我正在尝试记录用户(通过麦克风)对某些音频内容的响应,以便我可以精确地分析用户对该音频的响应的客户端计时。理想情况下,我会沿同一时间线录制两条轨道:(1)用户的麦克风流; (2)用户听到的音频流。
我没有使用Web Audio API的经验,但是使用以前的一些SO解答,我得出了以下解决方案:我将音频源(source
)和麦克风源(stream
)连接到一个单一流(combinedStream
),将其馈送到MediaRecorder
。
我的问题:
这会记录一条单音轨(即,音频和麦克风信号必须使用后处理进行分离)。是否可以将它们记录为两个轨道?例如粗略地作为立体声信号的两个通道?
我不清楚这是否是对延迟最敏感的方法,也许是与流连接相关的开销,还是与客户端的实际音频播放相关的未捕获的延迟?任何建议都将不胜感激-当前,音频源和播放之间存在约10-20ms的延迟(通过查看音频流和通过扬声器播放的音频之间的延迟来粗略衡量,就像从麦克风流上拾取的那样)。
我对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);
};
...
答案 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>
答案 1 :(得分:0)
MediaRecorder似乎没有执行此操作,至少not in Chromium。
MediaSourceExtensions确实允许控制Matroska文件内部多个曲目的播放。 webm是Matroska的子集。当前版本的webm standard不允许有多个轨道。但是MSE可以播放它们。
可以想象,您可以使用两个MediaRecorder,然后使用ebml代码编写代码来破解这两个Matroska容器,然后将它们组合成一个具有多个轨道的输出Matroska数据流。那是一项不平凡的编程任务。