如何使用Web音频API将PCM数据馈送到AudioContext?

huangapple go评论66阅读模式
英文:

How can I feed Audiocontext with pcm Data using Web Audio Api

问题

I have a function startPlayer() which creates a player with an audio context and a function feed(data) which is called when I receive a new audio chunk.

音频块:[采样率:48000],[字节长度:4096],[声道数:1]

I'm using a bufferSourceNode to play the audio chunk. However, I'm encountering an issue because it seems that the buffer property can only be set once, resulting in the following error:

Uncaught (in promise) DOMException: Failed to set the 'buffer' property on 'AudioBufferSourceNode': Cannot set the buffer to non-null after it has already been set to a non-null buffer
    at feed (http://127.0.0.1:5500/audio.js:112:21)

Maybe I should create a bufferSourceNode and connect it to audiocontext.destination every time feed(data) is called, but it seems like too much work.

以下是我的代码:

async function startPlayer() {
  playerAudioContext = new AudioContext();
  sourceNode = playerAudioContext.createBufferSource();
  sourceNode.connect(playerAudioContext.destination)
}

async function feed(pcmData) {
  const data = new DataView(pcmData)
  audioBuffer = playerAudioContext.createBuffer(1, data.byteLength / 2, playerAudioContext.sampleRate);
  const channelData = audioBuffer.getChannelData(0);
  for (let i = 0; i < data.byteLength; i += 2) {
    const sample = data.getInt16(i, true);
    channelData[i / 2] = sample / 32768;
  }

  // Set the buffer on the source node and start playing
  startTime = currentTime;
  const bufferDuration = audioBuffer.duration;
  sourceNode.buffer = audioBuffer;
  sourceNode.start(startTime);
  currentTime += bufferDuration;
}

也许有更好的方法将数据解析到channelData中,但我认为这不是问题所在。

英文:

I have a function startPlayer() which create a player with audiocontext and a function feed(data) which is called when I received a new audio chunk.

audio chunk: [sample rate: 48000], [bytelength: 4096], [channel number: 1]

I'm using a bufferSourceNode in order to play the chunk audio. But i'm only using one but the buffer seems to be settable only once because I got the following error:

Uncaught (in promise) DOMException: Failed to set the 'buffer' property on 'AudioBufferSourceNode': Cannot set buffer to non-null after it has been already been set to a non-null buffer
    at feed (http://127.0.0.1:5500/audio.js:112:21)

Maybe I should create a bufferSourceNode and connect it to audiocontext.destination every time feed(data) is called, but it seem too much.

Here my code:

async function startPlayer() {
  playerAudioContext = new AudioContext();
  sourceNode = playerAudioContext.createBufferSource();
  sourceNode.connect(playerAudioContext.destination)
}

async function feed(pcmData) {
  const data = new DataView(pcmData)
  audioBuffer = playerAudioContext.createBuffer(1, data.byteLength / 2, playerAudioContext.sampleRate);
  const channelData = audioBuffer.getChannelData(0);
  for (let i = 0; i < data.byteLength; i += 2) {
    const sample = data.getInt16(i, true);
    channelData[i / 2] = sample / 32768;
  }


  // Set the buffer on the source node and start playing
  startTime = currentTime;
  const bufferDuration = audioBuffer.duration;
  sourceNode.buffer = audioBuffer;
  sourceNode.start(startTime);
  currentTime += bufferDuration;
}

Yes maybe there is better solution for parsing the data into the channelData but I don't think that's a problem here.

答案1

得分: 1

你可以为每个新的音频块创建一个新的AudioBufferSourceNode

但正如你在下面的评论中提到的,这样频繁地创建并不是非常高效的。你也可以创建一个AudioWorkletProcessor,它可以从主线程接收音频数据并实时播放它。

可以使用常规的postMessage()调用来发送数据。但使用SharedArrayBuffer来代替会更加高效。

英文:

You can create a new AudioBufferSourceNode for each new chunk of audio.

But as you mentioned in your comment below it's not very efficient to do this that frequently. You can also create an AudioWorkletProcessor which receives the audio data from the main thread and plays it just in time.

It's possible to send the data with regular postMessage() calls. But doing it with a SharedArrayBuffer instead would be even more efficient.

huangapple
  • 本文由 发表于 2023年5月6日 23:17:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/76189653.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定