This script is used by Puppeteer tests to be able to mock a browser's MediaStreams API allowing you to play multiple audio files.
The script is necessary as the Chrome flag --use-file-for-fake-audio-capture will only allow one audio file to be chosen, and you have no control over when it will be played.
await webRtcFrame.evaluate(mockMediaDevicesScript);
webRtcFrame.evaluate(() => window.mockMediaDevice.playAudio(/* URL */));
Read my blog article Automated tests using Genesys Cloud's WebRTC softphone to see how I am using this.
Bundle the TypeScript into a JS file
npx esbuild ./index.ts --bundle --outfile=mocked_media_stream.bundle.js --platform=browser --target=es6 --minifyIf you don't want to build it yourself then I've done it for you into the mocked_media_stream.bundle.js listed in this Gist.
Run the HTTP server that will be used to expose the audio files
This solution replaces the MediaStreams within a particular page. This means we will need to pass the audio you want to play over this stream to that page.
Ideally our Puppeteer script would just pass the byte array of the audio into the page, but alas the array will be too big. So this is the workaround. By hosting the audio files locally we can save them to a file and then pass the URL to the page instead. The page will then download the file (see step 5 below) and pass the byte array to the mocked Media Devices playAudio function.
npx http-server audio-files -p 8080 --corsUpdate your Puppeteer Script
// 1. Read in the JS bundled above
const mockMediaDevicesScript = readFileSync("./dist/bundle.js", "utf8");
// 2. Get IFrame for WebRTC phone
const webRtcFrame = await browser.waitForTarget((page) =>
page.url().includes("/crm/webrtc.html"),
);
// 3. Run the script within the WebRTC frame to replace the MediaStream API
await webRtcFrame.evaluate(mockMediaDevicesScript);
// 4. Run a JavaScript function within the IFrame when you want to play an audio file against the MediaStream
webRtcFrame.evaluate((fileNameIn) => {
window.mockMediaDevice.playAudio(fileNameIn);
}, `http://localhost:8080/${filename}`);The recommendation for overriding Web APIs is using the Page.evaluateOnNewDocument()
method, however for some reason this doesn't work for navigator.mediaDevices. It is as if it is being overridden at
a later time by the --use-fake-device-for-media-stream flag.