将音频和麦克风流同时录制为不同的MediaRecorder音轨

时间:2020-11-12 18:25:23

标签: javascript html html5-audio web-audio-api getusermedia

我正在尝试记录用户(通过麦克风)对某些音频内容的响应,以便我可以精确地分析用户对该音频的响应的客户端计时。理想情况下,我会沿同一时间线录制两条轨道:(1)用户的麦克风流; (2)用户听到的音频流。

我没有使用Web Audio API的经验,但是使用以前的一些SO解答,我得出了以下解决方案:我将音频源(source)和麦克风源(stream)连接到一个单一流(combinedStream),将其馈送到MediaRecorder

我的问题:

  1. 这会记录一条音轨(即,音频和麦克风信号必须使用后处理进行分离)。是否可以将它们记录为两个轨道?例如粗略地作为立体声信号的两个通道?

  2. 我不清楚这是否是对延迟最敏感的方法,也许是与流连接相关的开销,还是与客户端的实际音频播放相关的未捕获的延迟?任何建议都将不胜感激-当前,音频源和播放之间存在约10-20ms的延迟(通过查看音频流和通过扬声器播放的音频之间的延迟来粗略衡量,就像从麦克风流上拾取的那样)。

  3. 我对HTML5音频了解不多,但是也许有更好的解决方案?

谢谢!

      ...

      // Audio for playback
      var source = context.createBufferSource();
      source.buffer = ...
      source.connect(context.destination);

      // Merge audio source with microphone stream
      const mediaStreamDestination = audioContext.createMediaStreamDestination();
      const sourceMic = jsPsych.pluginAPI.audioContext().createMediaStreamSource(stream);
      sourceMic.connect(mediaStreamDestination);
      source.connect(mediaStreamDestination);
      let combinedStream = new MediaStream([...mediaStreamDestination.stream.getAudioTracks()]);
      
      // Media recorder
      mediaRecorder = new MediaRecorder(combinedStream);
      mediaRecorder.ondataavailable = function(event) {
        chunks.push(event.data);
      };

      ...

2 个答案:

答案 0 :(得分:1)

要在两个不同的通道上录制两个不同的音频源(例如,立体声文件中的左右),可以使用ChannelMergerNode

基本上与您的设置相同,除了连接两个信号源时,您可以通过connect( destination, input_channel, output_channel )方法设置输出通道:

使用两个振荡器:

onclick = ()=>{
  onclick = null;
  const ctx = new AudioContext();
  const osc1 = ctx.createOscillator();
  const osc2 = ctx.createOscillator();
  osc1.frequency.value = 300;
  osc1.start(0);
  osc2.start(0);

  const merger = ctx.createChannelMerger();
  const dest = ctx.createMediaStreamDestination();
  merger.connect( dest );

  osc1.connect( merger, 0, 0 );
  osc2.connect( merger, 0, 1 );

  // for nodes to output sound in Chrome
  // they need to be connected to the destination
  // ...
  const mute = ctx.createGain();
  mute.gain.value = 0;
  mute.connect( ctx.destination );
  osc1.connect( mute );
  osc2.connect( mute );

  const chunks = [];
  const rec = new MediaRecorder( dest.stream );
  rec.ondataavailable = e => chunks.push(e.data)
  rec.onstop = e => {
    output.src = URL.createObjectURL( new Blob( chunks ) );
  };
  rec.start();
  setTimeout( () => rec.stop(), 5000 );
  log.remove();
};
<p id="log">click to start recording of 5s sample</p>
<audio id="output" controls></audio>

And as a fiddle using gUM

答案 1 :(得分:0)

MediaRecorder似乎没有执行此操作,至少not in Chromium

MediaSourceExtensions确实允许控制Matroska文件内部多个曲目的播放。 webm是Matroska的子集。当前版本的webm standard不允许有多个轨道。但是MSE可以播放它们。

可以想象,您可以使用两个MediaRecorder,然后使用ebml代码编写代码来破解这两个Matroska容器,然后将它们组合成一个具有多个轨道的输出Matroska数据流。那是一项不平凡的编程任务。

相关问题