mirror of
https://github.com/davedoesdev/streamana.git
synced 2025-10-05 13:36:50 +08:00
Use audio worklet for regular update events even with MediaRecorder
This commit is contained in:
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
54
site/hls.js
54
site/hls.js
@@ -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;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user