13

I want to input WAV or MP3 into puppeteer as a microphone, however while in headless the application is muted, so I was wondering if there was a way to get input directly into the browser.

I am also wondering if it's possible to get a feed of audio from the browser while in headless, and/or record the audio and place it in a folder.

david elepen
  • 131
  • 1
  • 3
  • Sorry, it's not definitely clear from the question — but what is the task? Why use puppeteer if you just want to record audio from a microphone? – Vaviloff Sep 24 '18 at 10:15
  • See also: https://stackoverflow.com/q/48264537/247696 – Flimm Sep 20 '19 at 13:47
  • Also see this one: https://stackoverflow.com/questions/52095416/how-can-i-correctly-provide-a-mock-webcam-video-to-chrome/52188760 – Flimm Sep 20 '19 at 14:32

4 Answers4

14

I ended up using this solution. First, I enabled some options for Chromium:

const browser = await puppeteer.launch({
  args: [
    '--use-fake-ui-for-media-stream',
  ],
  ignoreDefaultArgs: ['--mute-audio'],
});

Remember to close Chromium if it is open already.

I created an <audio> element with the src set to the file that I wanted to input. I also overrode navigator.mediaDevices.getUserMedia, so that it returns a Promise with the same stream as the audio file, rather than from the microphone.

const page = await browser.newPage();
await page.goto('http://example.com', {waitUntil: 'load'});
await page.evaluate(() => {
  var audio = document.createElement("audio");
  audio.setAttribute("src", "http://example.com/example.mp3");
  audio.setAttribute("crossorigin", "anonymous");
  audio.setAttribute("controls", "");
  audio.onplay = function() {
    var stream = audio.captureStream();
    navigator.mediaDevices.getUserMedia = async function() {
       return stream;
    };
  });
  document.querySelector("body").appendChild(audio);
});

Now whenever the website's code calls navigator.mediaDevices.getUserMedia, it will get the audio stream from the file. (You need to make sure the audio is playing first.)

Flimm
  • 136,138
  • 45
  • 251
  • 267
4

User Flimm's second answer was on the ball. Not sure why it did not work for him. Adding the answer here for others, as I do not have sufficient reputation to comment on his answer.

const browser = await puppeteer.launch({ headless: true,
  args: [
    '--use-fake-ui-for-media-stream',
    '--use-fake-device-for-media-stream',
    '--use-file-for-fake-audio-capture=C:\\Users\\Username\\Desktop\\newtest.wav',
  ],

One possible reason might be that in Windows, the slashes need to be doubled as I've done here.

The --use-fake-device-for-media-stream also needs to be enabled for this to work.

The wav file should be 44.1 kHz, 16-bit. This sample one worked for me.

Flimm
  • 136,138
  • 45
  • 251
  • 267
regstuff
  • 83
  • 7
2

Not sure what you mean by inputting as a microphone, but you can enable audio in headless mode. This should work:

const browser = await puppeteer.launch({
   ignoreDefaultArgs: ['--mute-audio']
});
  • Also, you might be interested in this option: `puppeteer.launch({args: [ '--use-fake-ui-for-media-stream' ]})` – Flimm Sep 20 '19 at 13:48
1

In theory, to load the file example.wav and use it as if it were microphone input, this should work:

const browser = await puppeteer.launch({
  args: [
    '--use-fake-ui-for-media-stream',
    '--use-fake-device-for-media-stream',
    '--use-file-for-fake-audio-capture=/path/example.wav',
    '--allow-file-access',
  ],
  ignoreDefaultArgs: ['--mute-audio'],
});

I was told that you need to make sure that Chrome has been closed before running the script, and that the .wav file needs to be 41khz and 16-bit.

However, I could not get it to work :(

Flimm
  • 136,138
  • 45
  • 251
  • 267