MediaDevices.getUserMedia
在将 Chromium Audio 工作组与媒体流(麦克风)一起使用时,我注意到频繁且可重复的丢失。这不是 100% 可重现的,但是当它们确实发生时,它们确实倾向于遵循模式:
(每次尝试的时间范围略有不同)
- 0:00 -> 0:00.2:没有收到样本。(能够重现 100% 的时间,但这感觉像是一个单独的问题,我现在不一定要追踪)
- 0:00.2 -> 0:00.5 : 收到样本
- 0:00.5 -> 0:00.6 :发生丢失,没有收到样本(能够重现约 20% 的时间)。
- 0:00.6 -> 0:30.0 : 收到样品
- 从现在开始每隔 30 秒,偶尔会发生辍学。往往在前 30 岁时最常发生。(前 30 年代标记我也可以复制大约 20% 的时间)。
这是一个说明行为的代码笔: https ://codepen.io/GJStevenson/pen/GRErPbm
const startRecordingButton = document.getElementById('startRecordingButton');
let mediaStreamSourceNode;
let isRecording = false;
let timer;
const workletString = `
const formatTimeString = s => {
const m = (s / 60).toFixed(2);
const h = (m / 60).toFixed(2);
const ms = Math.trunc(s * 1000) % 1000;
const ss = Math.trunc(s) % 60;
const mm = Math.trunc(m) % 60;
const hh = Math.trunc(h);
return hh + ":" + mm + ":" + ss + "." + ms;
};
class RecorderWorklet extends AudioWorkletProcessor {
constructor(options) {
super(options);
this.sampleRate = 0;
this.sampleCount = 0;
this.port.onmessage = event => {
if (event.data.message === 'init') {
this.sampleRate = event.data.sampleRate;
}
}
}
process(inputs) {
if (inputs.length > 0 && inputs[0].length > 0) {
this.sampleCount += inputs[0][0].length;
//console.debug(formatTimeString(this.sampleCount/this.sampleRate), ' : ', inputs[0][0]);
if (inputs[0][0].includes(0)) {
console.log('Dropped Samples at: ', formatTimeString(this.sampleCount/this.sampleRate), ' : ', ...inputs[0][0])
}
}
return true;
}
}
registerProcessor('recorder-worklet', RecorderWorklet);
`;
async function listAudioInputs() {
const devices = await navigator.mediaDevices.enumerateDevices();
return devices.filter((device) => device.kind === 'audioinput');
}
async function getDefaultInput(fallbackToFirstInput = true) {
const audioInputs = await listAudioInputs();
const defaultDevice = audioInputs.find((device) => device.deviceId === 'default');
if (defaultDevice) {
return defaultDevice;
}
return fallbackToFirstInput && audioInputs.length > 0 ? audioInputs[0] : undefined;
}
async function getAudioStream(device) {
const constraints = {
audio: {
deviceId: device.deviceId,
},
};
return navigator.mediaDevices.getUserMedia(constraints);
}
async function createRecordingPipeline(device) {
const stream = await getAudioStream(device);
const audioTracks = stream.getAudioTracks();
const sampleRate = audioTracks[0].getSettings().sampleRate;
console.log('Sample Rate: ', sampleRate);
const context = new AudioContext({ sampleRate, latencyHint: 'interactive' });
const blob = new Blob([workletString], { type: 'text/javascript' });
const workletUrl = URL.createObjectURL(blob);
await context.audioWorklet.addModule(workletUrl);
const workletNode = new AudioWorkletNode(context, 'recorder-worklet');
workletNode.port.postMessage({
message: 'init',
sampleRate: sampleRate
});
mediaStreamSourceNode = context.createMediaStreamSource(stream);
mediaStreamSourceNode.connect(workletNode)
.connect(context.destination);
}
function formatTimeString(s) {
const m = (s / 60).toFixed(2);
const h = (m / 60).toFixed(2);
const ms = Math.trunc(s * 1000) % 1000;
const ss = Math.trunc(s) % 60;
const mm = Math.trunc(m) % 60;
const hh = Math.trunc(h);
return hh + ":" + mm + ":" + ss + "." + ms;
};
async function startRecording() {
const device = await getDefaultInput();
await createRecordingPipeline(device);
let timeElapsed = 0;
timer = setInterval(() => {
timeElapsed++;
console.log('Time: ', formatTimeString(timeElapsed));
}, 1000);
startRecordingButton.innerText = "Stop Recording";
}
async function stopRecording() {
if (mediaStreamSourceNode) {
mediaStreamSourceNode.mediaStream.getAudioTracks().forEach(track => {
track.stop();
});
mediaStreamSourceNode.disconnect();
}
mediaStreamSourceNode = null;
clearInterval(timer);
startRecordingButton.innerText = "Start Recording";
}
async function toggleRecording() {
if (!isRecording) {
await startRecording();
} else {
await stopRecording();
}
isRecording = !isRecording;
}
<button onclick="toggleRecording()" id="startRecordingButton">Start Recording</button>
丢弃的样本在控制台中将如下所示:
关于问题可能是什么的任何想法?
编辑:运行 chrome://tracing 以捕获丢弃样本的跟踪。https://www.dropbox.com/s/veg1vgsg9nn03ty/trace_dropped-sample-trace.json.gz?dl=0。丢弃的样本发生在 ~.53s -> .61s