18045010223
7 天以前 afe371d39a054b2f2a9e5875b945584eec8a8141
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
<html>
    <head>
        <title>Chunked Audio Test</title>
    </head>
    <body>
        <button>Play</button>
    </body>
</html>
<!--<script src="//cdn.bootcss.com/jquery/3.4.1/jquery.min.js" type="text/javascript"></script>-->
<script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
<script type="text/javascript">
 
    var streamOffset = 0;
    var Base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('');
    var CharIdxArray = { };
    for (var i = 0; i < Base64Chars.length; i++) CharIdxArray[Base64Chars[i]] = i;
 
    window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.msAudioContext;
    var audioContext = new AudioContext();
    var segments = [];
    var ended = true;
 
    function playNextSegment()
    {
        if (segments.length > 0 && ended)
        {
            ended = false;
            var audioBufferSouceNode = audioContext.createBufferSource();
            audioBufferSouceNode.onended = function()
            {
                // playNextSegment();
                ended = true;
                console.log('play ended...');
            }
            audioBufferSouceNode.buffer = segments.shift();
            audioBufferSouceNode.connect(audioContext.destination);
            audioBufferSouceNode.start(0);
        }
    }
 
    $(document).ready(function()
    {
        var decodeCallback = function(buffer)
        {
            segments.push(buffer);
        };
 
        $('button').click(function()
        {
            var xhr = new XMLHttpRequest();
            xhr.open('GET', '/audio/' + location.hash.substring(1), true);
            xhr.onprogress = function()
            {
                var audioData = xhr.responseText;
                while (true)
                {
                    var audio = base64Decode(audioData);
                    if (audio == null) break;
                    console.log('decoded: ' + audio.length);
                    audioContext.decodeAudioData(audio.buffer, decodeCallback);
                }
            }
            xhr.send();
        });
 
        setInterval(playNextSegment, 50);
    });
 
    function base64Decode(text)
    {
        var i, k = 0, l;
        if (text.length < streamOffset + 8) return null;
        var blockLength = parseInt(text.substring(streamOffset, streamOffset + 8), 16);
        console.log('block: ' + blockLength);
        if (text.length < streamOffset + 8 + blockLength) return null;
 
        var audioBuffer = new Uint8Array(new ArrayBuffer(2048), 0);
        for (i = streamOffset + 8, l = text.length; i < l && k < blockLength; )
        {
            var a = CharIdxArray[text.charAt(i + 0)];
            var b = CharIdxArray[text.charAt(i + 1)];
            var c = CharIdxArray[text.charAt(i + 2)];
            var d = CharIdxArray[text.charAt(i + 3)];
 
            var b1 = ((a << 2) | (b >> 4)) & 0xff;
            var b2 = ((b << 4) | (c >> 2)) & 0xff;
            var b3 = ((c << 6) | (d)) & 0xff;
 
            audioBuffer[k++] = b1;
            audioBuffer[k++] = b2;
            audioBuffer[k++] = b3;
 
            i += 4;
        }
        streamOffset += blockLength + 8;
 
        /*
        var hex = [];
        for (i = 0; i < k && i < 32; i++)
        {
            var ch = (audioBuffer[i] & 0xff).toString(16).toUpperCase();
            hex.push(ch.length == 1 ? '0' + ch : ch);
            hex.push(' ');
            if (i % 4 == 3) hex.push("   ");
            if (i % 16 == 15) hex.push("\n");
        }
        console.log(hex.join(''));
        */
 
        return audioBuffer.subarray(k);
    }
 
</script>