Custom MediaStream
Я получаю необработанный звук float32 через веб-сокеты и хотел бы воспроизвести его в браузере. Из моего понимания мне нужно было бы использовать MediaStream API для этого. Однако я не могу найти способ создать MediaStream, к которому я могу добавить буферы данных.
Как правильно добиться этого?
Я пытаюсь что-то вроде этого:
var context = new AudioContext();
context.sampleRate = 48000;
var stream = null; // ????
var source = context.createMediaStreamSource(stream);
source.connect(context.destination);
source.start(0);
socket.onmessage = function (event) {
stream.appendBuffer(new Float32Array(event.data)); // ????
};
2 ответа
Вы должны использовать AudioBuffers для чтения звука из буферов из веб-сокета и воспроизведения его.
var context = new AudioContext();
var sampleRate = 48000;
var startAt = 0;
socket.onmessage = function (event) {
var floats = new Float32Array(event.data);
var source = context.createBufferSource();
var buffer = context.createBuffer(1, floats.length, sampleRate);
buffer.getChannelData(0).set(floats);
source.buffer = buffer;
source.connect(context.destination);
startAt = Math.max(context.currentTime, startAt);
source.start(startAt);
startAt += buffer.duration;
};
Это играет музыку из веб-сокета.
Чтобы преобразовать AudioBuffer в MediaStream, используйте AudioContext.createMediaStreamDestination()
, Подключите к нему BufferSource, чтобы создать собственный MediaStream на основе данных буфера.
var data = getSound(); // Float32Array;
var sampleRate = 48000;
var context = new AudioContext();
var streamDestination = context.createMediaStreamDestination();
var buffer = context.createBuffer(1, data.length, sampleRate);
var source = context.createBufferSource();
buffer.getChannelData(0).set(data);
source.buffer = buffer;
source.connect(streamDestination);
source.loop = true;
source.start();
var stream = streamDestination.stream;
Это читает аудио из массива данных и преобразует его в MediaStream.
Что касается декодирования, audioContext из объекта окна должен делать эту работу.
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
а потом
audioCtx.decodeAudioData(audioData, function(buffer) {
непосредственно в двоичном массиве.
Что касается связи, я бы предпочел использовать XMLHttpRequest (функция низкого уровня и старый) и использовать ответ напрямую.
Это очень хорошая функция, созданная ребятами из MDM (я обновил URL-адрес файла ogg, чтобы вы могли проверить его напрямую):
function getData() {
source = audioCtx.createBufferSource();
request = new XMLHttpRequest();
request.open('GET', 'https://raw.githubusercontent.com/mdn/webaudio-examples/master/decode-audio-data/viper.ogg', true);
request.responseType = 'arraybuffer';
request.onload = function() {
var audioData = request.response;
audioCtx.decodeAudioData(audioData, function(buffer) {
myBuffer = buffer;
songLength = buffer.duration;
source.buffer = myBuffer;
source.playbackRate.value = playbackControl.value;
source.connect(audioCtx.destination);
source.loop = true;
loopstartControl.setAttribute('max', Math.floor(songLength));
loopendControl.setAttribute('max', Math.floor(songLength));
},
function(e){"Error with decoding audio data" + e.error});
}
request.send();
}
полный исходный код здесь:
https://raw.githubusercontent.com/mdn/webaudio-examples/master/decode-audio-data/index.html