Use audio worklet for regular update events even with MediaRecorder

This commit is contained in:
David Halls
2021-09-02 19:39:00 +01:00
parent ca851c3f18
commit d7766e2ee5
2 changed files with 29 additions and 27 deletions

View File

@@ -335,8 +335,6 @@ async function start() {
canvas_el.style.width = `${width}px`; canvas_el.style.width = `${width}px`;
canvas_el.style.height = `${height}px`; canvas_el.style.height = `${height}px`;
// TODO: // TODO:
// performance on mobile
// webcodecs performance on PC is less fps than MediaRecorder
// windows, iOS, find a mac to test // windows, iOS, find a mac to test
} }
} }

View File

@@ -37,9 +37,9 @@ export class HLS extends EventTarget {
console.warn(ex); console.warn(ex);
try { try {
// next try WebCodecs - this should work on Chrome including Android // next try WebCodecs - this should work on Chrome including Android
this.webcodecs(video_encoder_codec, await this.webcodecs(video_encoder_codec,
'opus' /*'pcm'*/, 'opus' /*'pcm'*/,
{ avc: { format: 'annexb' } }); { avc: { format: 'annexb' } });
console.log("Using WebCodecs"); console.log("Using WebCodecs");
} catch (ex) { } catch (ex) {
console.warn(ex); console.warn(ex);
@@ -53,6 +53,27 @@ export class HLS extends EventTarget {
this.started = true; this.started = true;
} }
async start_dummy_processor() {
// use a persistent audio generator to trigger updates to avoid setInterval throttling
const context = new AudioContext();
await context.audioWorklet.addModule('./dummy-worklet.js');
this.dummy_processor = new AudioWorkletNode(context, 'dummy-processor', {
processorOptions: {
update_rate: this.frame_rate
}
});
this.dummy_processor.onerror = onerror;
this.dummy_processor.onprocessorerror = onerror;
this.dummy_processor.port.onmessage = () => this.dispatchEvent(this.update_event);
this.dummy_processor.connect(context.destination);
}
stop_dummy_processor() {
this.dummy_processor.port.postMessage({ type: 'stop' });
this.dummy_processor.disconnect();
this.dummy_processor.context.suspend();
}
async media_recorder(mimeType) { async media_recorder(mimeType) {
const onerror = this.onerror.bind(this); const onerror = this.onerror.bind(this);
@@ -79,18 +100,7 @@ export class HLS extends EventTarget {
} }
}; };
// use a persistent audio generator to trigger updates to avoid setInterval throttling await this.start_dummy_processor();
const context = new AudioContext();
await context.audioWorklet.addModule('./dummy-worklet.js');
const dummy_processor = new AudioWorkletNode(context, 'dummy-processor', {
processorOptions: {
update_rate: this.frame_rate
}
});
dummy_processor.onerror = onerror;
dummy_processor.onprocessorerror = onerror;
dummy_processor.port.onmessage = () => this.dispatchEvent(this.update_event);
dummy_processor.connect(context.destination);
// start the ffmpeg worker // start the ffmpeg worker
this.receiver = new MuxReceiver(); this.receiver = new MuxReceiver();
@@ -134,9 +144,7 @@ export class HLS extends EventTarget {
if (recorder.state !== 'inactive') { if (recorder.state !== 'inactive') {
recorder.stop(); recorder.stop();
} }
dummy_processor.port.postMessage({ type: 'stop' }); this.stop_dummy_processor();
dummy_processor.disconnect();
context.suspend();
if ((msg.code === 'force-end') && !this.sending) { if ((msg.code === 'force-end') && !this.sending) {
msg.code = 0; msg.code = 0;
} }
@@ -146,7 +154,7 @@ export class HLS extends EventTarget {
}); });
} }
webcodecs(video_codec, audio_codec, video_config, audio_config) { async webcodecs(video_codec, audio_codec, video_config, audio_config) {
const onerror = this.onerror.bind(this); const onerror = this.onerror.bind(this);
const video_track = this.stream.getVideoTracks()[0]; const video_track = this.stream.getVideoTracks()[0];
@@ -157,7 +165,7 @@ export class HLS extends EventTarget {
const audio_readable = (new MediaStreamTrackProcessor(audio_track)).readable; const audio_readable = (new MediaStreamTrackProcessor(audio_track)).readable;
const audio_settings = audio_track.getSettings(); const audio_settings = audio_track.getSettings();
const update_limiter = new UpdateLimiter(this.frame_rate); await this.start_dummy_processor();
let num_exits = 0; let num_exits = 0;
@@ -177,11 +185,6 @@ export class HLS extends EventTarget {
break; break;
case 'audio-data': case 'audio-data':
if (update_limiter.check()) {
this.dispatchEvent(this.update_event);
}
// falls through
case 'video-data': case 'video-data':
this.worker.postMessage(msg, [msg.data]); this.worker.postMessage(msg, [msg.data]);
break; break;
@@ -244,6 +247,7 @@ export class HLS extends EventTarget {
this.worker = null; this.worker = null;
video_worker.terminate(); video_worker.terminate();
audio_worker.terminate(); audio_worker.terminate();
this.stop_dummy_processor();
if ((msg.code === 'force-end') && !this.sending) { if ((msg.code === 'force-end') && !this.sending) {
msg.code = 0; msg.code = 0;
} }