diff --git a/site/example.js b/site/example.js index 892509c..6449e76 100644 --- a/site/example.js +++ b/site/example.js @@ -335,8 +335,6 @@ async function start() { canvas_el.style.width = `${width}px`; canvas_el.style.height = `${height}px`; // TODO: - // performance on mobile - // webcodecs performance on PC is less fps than MediaRecorder // windows, iOS, find a mac to test } } diff --git a/site/hls.js b/site/hls.js index 5d5d30c..86ced16 100644 --- a/site/hls.js +++ b/site/hls.js @@ -37,9 +37,9 @@ export class HLS extends EventTarget { console.warn(ex); try { // next try WebCodecs - this should work on Chrome including Android - this.webcodecs(video_encoder_codec, - 'opus' /*'pcm'*/, - { avc: { format: 'annexb' } }); + await this.webcodecs(video_encoder_codec, + 'opus' /*'pcm'*/, + { avc: { format: 'annexb' } }); console.log("Using WebCodecs"); } catch (ex) { console.warn(ex); @@ -53,6 +53,27 @@ export class HLS extends EventTarget { 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) { 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 - 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); + await this.start_dummy_processor(); // start the ffmpeg worker this.receiver = new MuxReceiver(); @@ -134,9 +144,7 @@ export class HLS extends EventTarget { if (recorder.state !== 'inactive') { recorder.stop(); } - dummy_processor.port.postMessage({ type: 'stop' }); - dummy_processor.disconnect(); - context.suspend(); + this.stop_dummy_processor(); if ((msg.code === 'force-end') && !this.sending) { 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 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_settings = audio_track.getSettings(); - const update_limiter = new UpdateLimiter(this.frame_rate); + await this.start_dummy_processor(); let num_exits = 0; @@ -177,11 +185,6 @@ export class HLS extends EventTarget { break; case 'audio-data': - if (update_limiter.check()) { - this.dispatchEvent(this.update_event); - } - // falls through - case 'video-data': this.worker.postMessage(msg, [msg.data]); break; @@ -244,6 +247,7 @@ export class HLS extends EventTarget { this.worker = null; video_worker.terminate(); audio_worker.terminate(); + this.stop_dummy_processor(); if ((msg.code === 'force-end') && !this.sending) { msg.code = 0; }