atlas-iac/testing/probes/generate_mediarecorder_fixture.js

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;
});