如何使用来自网络套接字的网络音频 API 流式传输音频块?
Posted
技术标签:
【中文标题】如何使用来自网络套接字的网络音频 API 流式传输音频块?【英文标题】:how to stream audio chunks using web audio API coming from web-socket? 【发布时间】:2016-12-27 14:07:59 【问题描述】:我正在通过服务器的 web-Socket 以块的形式流式传输音频数据
ws.on('message', function incoming(message)
var readStream = fs.createReadStream("angular/data/google.mp3",
'flags': 'r',
'highWaterMark': 128 * 1024
);
readStream.on('data', function(data)
ws.send(data);
);
readStream.on('end', function()
ws.send('end');
);
readStream.on('error', function(err)
console.log(err)
);
);
在客户端
var chunks = [];
var context = new AudioContext();
var soundSource;
var ws = new WebSocket(url);
ws.binaryType = "arraybuffer";
ws.onmessage = function(message)
if (message.data instanceof ArrayBuffer)
chunks.push(message.data)
else
createSoundSource(chunks);
;
function createSoundSource(audioData)
soundSource = context.createBufferSource();
for (var i=0; i < audioData.length;i++)
context.decodeAudioData(audioData[i], function(soundBuffer)
soundSource.buffer = soundBuffer;
soundSource.connect(context.destination);
soundSource.start(0);
);
但是第二次设置缓冲区soundSource.buffer = soundBuffer;
会报错
未捕获的 DOMException:无法在“AudioBufferSourceNode”上设置“缓冲区”属性:缓冲区已设置后无法设置
任何关于如何最好地使用update
Web Audio API 播放新音频数据的建议或见解将不胜感激。
【问题讨论】:
你搞清楚了吗? 【参考方案1】:AudioBufferSourceNode
上的缓冲区一旦设置就无法重置。这就像一劳永逸。每次要播放不同的缓冲区时,都必须创建一个新的AudioBufferSourceNode
才能继续播放。这些是非常轻量级的节点,因此即使创建大量节点也不必担心性能。
为了解决这个问题,您可以修改您的 createSoundSource
函数,以简单地为循环体内的每个块创建一个 AudioBufferSourceNode
,如下所示:
function createSoundSource(audioData)
for (var i=0; i < audioData.length;i++)
context.decodeAudioData(audioData[i], function(soundBuffer)
var soundSource = context.createBufferSource();
soundSource.buffer = soundBuffer;
soundSource.connect(context.destination);
soundSource.start(0);
);
我试图让代码风格尽可能接近原始,但现在是 2020 年,利用现代特性的函数实际上可能看起来像这样:
async function createSoundSource(audioData)
await Promise.all(
audioData.map(async (chunk) =>
const soundBuffer = await context.decodeAudioData(chunk);
const soundSource = context.createBufferSource();
soundSource.buffer = soundBuffer;
soundSource.connect(context.destination);
soundSource.start(0);
)
);
如果您想在新数据到达后立即停止旧节点(看起来您希望通过重置 .buffer
但我不确定),您必须存储它们并调用 disconnect
到了时候就全部上去。
【讨论】:
【参考方案2】:不是肯定的,但我认为你必须以不同的方式处理你的流式 websocket 缓冲区。也许websocket-streaming-audio 包源代码可以为您提供有关如何处理您的场景的更好线索。
【讨论】:
以上是关于如何使用来自网络套接字的网络音频 API 流式传输音频块?的主要内容,如果未能解决你的问题,请参考以下文章