Basicly, I'm trying to build and play audio data from bytes, that comes from WS sockets.
Detailed:
I have simple WS server written in Django-Channels, that on connect returns me splitted audio file in blob object with 6144 bytes of each chunk. Next, I want to decode this blob data and turn it into sound:
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var source;
var play = document.querySelector('#play');
var audioQueue = []
const chatSocket = new WebSocket(
'ws://'
+ window.location.host
+ 'audio-stream-test'
+ '/'
);
chatSocket.onmessage = function(e) {
e.data.arrayBuffer().then(buffer => {
audioCtx.decodeAudioData(buffer, (x)=>{
source = audioCtx.createBufferSource();
source.buffer = x;
source.connect(audioCtx.destination);
source.loop = false;
audioQueue.push(source)
})
})
}
After WS sent all the data, it closes on server side. The last thing is to play queued buffers from audioQueue
array:
play.onclick = function() {
var playOffset;
for (let [bufferCount, buffer] of audioQueue.entries()) {
if (bufferCount == 0) {
playOffset = 0
} else {
playOffset = audioQueue[bufferCount-1].buffer.duration
}
buffer.start(when=playOffset)
}
}
Want to clarify about this line: playOffset = audioQueue[bufferCount-1].buffer.duration
. I think, i'm writed it right because I want to play new buffer at the end of old (already played) one.
For me, as server-side developer, it seems like it should work fine.
But, the main problem is: all buffers from audioQueue
array is played at once. IDK what I'm doing wrong. Hoping for youre help :)
You need to start each AudioBufferSourceNode
in relation to the currentTime
of the AudioContext
.
play.onclick = function() {
audioQueue.reduce((startTime, audioBufferSourceNode) => {
audioBufferSourceNode.start(startTime);
return startTime + audioBufferSourceNode.buffer.duration;
}, audioContext.currentTime);
};
The code above will loop through all nodes in the audioQueue
. It computes the startTime
for each AudioBufferSourceNode
by accumulating the durations of the previous nodes based on the currentTime
of the AudioContext
.