85 lines
2.9 KiB
JavaScript
85 lines
2.9 KiB
JavaScript
'use strict';
|
|
|
|
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
const { chromium } = require('playwright');
|
|
|
|
async function main() {
|
|
const outputPath = process.argv[2];
|
|
if (!outputPath) throw new Error('usage: node generate_mediarecorder_fixture.js OUTPUT.json');
|
|
|
|
const browser = await chromium.launch({
|
|
headless: true,
|
|
args: ['--autoplay-policy=no-user-gesture-required'],
|
|
});
|
|
try {
|
|
const page = await browser.newPage();
|
|
const fixture = await page.evaluate(async () => {
|
|
const mimeType = 'audio/webm;codecs=opus';
|
|
if (!MediaRecorder.isTypeSupported(mimeType)) {
|
|
throw new Error(`${mimeType} is not supported by this Chromium build`);
|
|
}
|
|
|
|
const context = new AudioContext({sampleRate: 48000});
|
|
const destination = context.createMediaStreamDestination();
|
|
const oscillator = context.createOscillator();
|
|
const gain = context.createGain();
|
|
oscillator.frequency.value = 440;
|
|
gain.gain.value = 0;
|
|
oscillator.connect(gain).connect(destination);
|
|
oscillator.start();
|
|
|
|
const chunks = [];
|
|
const recorder = new MediaRecorder(destination.stream, {mimeType});
|
|
recorder.ondataavailable = event => {
|
|
if (event.data && event.data.size) chunks.push(event.data);
|
|
};
|
|
const stopped = new Promise(resolve => { recorder.onstop = resolve; });
|
|
const delay = milliseconds => new Promise(resolve => setTimeout(resolve, milliseconds));
|
|
|
|
recorder.start(250);
|
|
await delay(1400);
|
|
gain.gain.setValueAtTime(0.35, context.currentTime);
|
|
await delay(900);
|
|
gain.gain.setValueAtTime(0, context.currentTime);
|
|
await delay(500);
|
|
recorder.stop();
|
|
await stopped;
|
|
|
|
oscillator.stop();
|
|
await context.close();
|
|
const encoded = [];
|
|
for (const chunk of chunks) {
|
|
const bytes = new Uint8Array(await chunk.arrayBuffer());
|
|
let binary = '';
|
|
for (let index = 0; index < bytes.length; index += 0x8000) {
|
|
binary += String.fromCharCode(...bytes.subarray(index, index + 0x8000));
|
|
}
|
|
encoded.push(btoa(binary));
|
|
}
|
|
return {
|
|
mime_type: recorder.mimeType,
|
|
timeslice_ms: 250,
|
|
pre_speech_chunk_count: 5,
|
|
chunks_base64: encoded,
|
|
};
|
|
});
|
|
const chunks = fixture.chunks_base64.map(value => Buffer.from(value, 'base64'));
|
|
const payloadPath = outputPath.replace(/\.json$/i, '.webm');
|
|
fixture.chunk_sizes = chunks.map(chunk => chunk.length);
|
|
fixture.payload_file = path.basename(payloadPath);
|
|
delete fixture.chunks_base64;
|
|
fixture.browser = await browser.version();
|
|
fixture.generator = 'testing/probes/generate_mediarecorder_fixture.js';
|
|
fs.writeFileSync(payloadPath, Buffer.concat(chunks));
|
|
fs.writeFileSync(outputPath, `${JSON.stringify(fixture, null, 2)}\n`);
|
|
} finally {
|
|
await browser.close();
|
|
}
|
|
}
|
|
|
|
main().catch(error => {
|
|
console.error(error.stack || error);
|
|
process.exitCode = 1;
|
|
});
|