let rs;
self.addEventListener('message', (event) => {
console.log(event.data);
rs = event.data;
});
self.addEventListener('install', (event) => {
console.log(event);
event.waitUntil(self.skipWaiting());
});
self.addEventListener('activate', (event) => {
console.log(event);
event.waitUntil(self.clients.claim());
});
self.addEventListener('fetch', async (event) => {
if (event.request.url.includes('stream')) {
console.log(rs);
event.respondWith(
new Response(rs, {
headers: { 'Content-Type': 'audio/webm;codecs=opus' },
})
);
console.log(rs);
}
});
<!DOCTYPE html>
<html>
<head>
<title>Test infinite Opus stream</title>
<style>
body *:not(script) {
display: block;
}
</style>
</head>
<body>
<p>Test infinite Opus stream</p>
<a
href="https://bugs.chromium.org/p/chromium/issues/detail?id=1161429"
target="_blank"
>Issue 1161429: FLAC and Opus Audio Streams Stop Playing</a
>
<h1>Click</h1>
<data></data>
<script>
const unregisterServiceWorkers = async (_) => {
const registrations = await navigator.serviceWorker.getRegistrations();
for (const registration of registrations) {
console.log(registration);
try {
await registration.unregister();
} catch (e) {
throw e;
}
}
return `ServiceWorker's unregistered`;
};
const mimeType = 'audio/webm;codecs=opus';
const output = document.querySelector('data');
document.querySelector('h1').onclick = async (e) => {
let ac, msd, osc, recorder, controller, readable, sw;
const disconnect = async () => {
console.log(e);
msd.disconnect();
msd.stream.getAudioTracks()[0].stop();
osc.disconnect();
await ac.close();
await unregisterServiceWorkers();
return;
};
try {
e.target.onclick = null;
console.log(await unregisterServiceWorkers());
sw = await navigator.serviceWorker.register('sw.js', {
scope: './',
});
console.log(sw);
await sw.ready;
let blobs = 0;
let bytes = 0;
ac = new AudioContext({
latencyHint: 1.0,
});
osc = new OscillatorNode(ac, { detune: -1000 });
osc.start();
msd = new MediaStreamAudioDestinationNode(ac, {
channelCount: 2,
});
osc.connect(msd);
const { stream } = msd;
const [track] = stream.getAudioTracks();
const audio = new Audio();
[
'loadedmetadata',
'loadeddata',
'canplay',
'canplaythrough',
'play',
'playing',
'pause',
'ended',
'stalled',
'waiting',
'durationchange',
'suspend',
'abort',
'emptied',
].forEach((event) =>
audio.addEventListener(event, (e) => {
console.log(e.type, audio.currentTime);
})
);
audio.controls = audio.autoplay = true;
document.body.appendChild(audio);
readable = new ReadableStream({
start(_) {
return (controller = _);
},
});
recorder = new MediaRecorder(stream, { mimeType });
recorder.ondataavailable = async ({ data }) => {
controller.enqueue(new Uint8Array(await data.arrayBuffer()));
++blobs;
bytes += data.size;
if (blobs % 100 === 0) {
console.log(`bytes:${bytes}, blobs:${blobs}`);
}
// output.textContent = `bytes:${bytes}, blobs:${blobs}`;
if (controller.desiredSize === -1 && !readable.locked) {
sw.active.postMessage(readable, [readable]);
audio.src = './stream';
console.log(controller, blobs, bytes);
if ('gc' in globalThis && typeof globalThis.gc === 'function') {
globalThis.gc();
}
}
};
recorder.start(0);
audio.onpause = async (e) => {
console.log(await diconnect());
};
} catch (e) {
console.error(e);
disconnect();
}
};
</script>
</body>
</html>