Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

getUserMedia with microphone fails #4160

Closed
jaypan opened this issue May 8, 2019 · 13 comments
Closed

getUserMedia with microphone fails #4160

jaypan opened this issue May 8, 2019 · 13 comments

Comments

@jaypan
Copy link

jaypan commented May 8, 2019

Bug

Requests to access the user's microphone using getUserMedia() fail and crash Cypress test.

Current behavior:

I have a web application which allows users to do voice recordings in their browser. Getting access to the microphone is done through the following

var constraints = {
  audio: true,
  video: false
};

navigator.mediaDevices
  .getUserMedia(constraints)
  .then(recordAudio);

Cypress fails this test due to the call .getUserMedia() with the error:

Uncaught TypeError: Cannot read property 'getUserMedia' of undefined

I have seen that some work has been done with webcams, but I'm not finding anything for microphones.

Desired behavior:

I would like this to not fail, so that I can test the application.

Steps to reproduce:

index.html:

<!DOCTYPE html>
<html>
  <head>
    <script>
      window.onload = function() {
        var constraints = {
          audio: true,
          video: false
        };

        navigator.mediaDevices.getUserMedia(constraints);
      };
    </script>
  </head>
  <body>
    <p>Hello World</p>
  </body>
</html>

Test:

cy.visit("/index.html");

Versions

macOS Mojave
Cypress 3.2.0

@jaypan jaypan changed the title getUserMedia with microphone getUserMedia with microphone fails May 8, 2019
@flotwig
Copy link
Contributor

flotwig commented May 14, 2019

You can follow the same basic procedure as @jennifer-shehane's comment on the webcam issue (#2704), but instead of using --use-file-for-fake-video-capture, you can use --use-file-for-fake-audio-capture:

In cypress/plugins/index.js:

module.exports = (on, config) => {
  on('before:browser:launch', (browser = {}, args) => {
    // args.push('--use-fake-device-for-media-stream')
    if (browser.name === 'chrome') {
      args.push('--use-fake-ui-for-media-stream')
      args.push('--use-fake-device-for-media-stream')
      args.push('--use-file-for-fake-audio-capture=cypress/fixtures/your_sound.wav')
    }
    
    return args
  })
}

@jaypan
Copy link
Author

jaypan commented May 14, 2019

Thanks, playing with that now.

@jennifer-shehane
Copy link
Member

@jaypan Great, please let us know how it works as we haven't manually tested this. I'd love to add a working example to our docs.

@cypress-bot cypress-bot bot added the stage: awaiting response Potential fix was proposed; awaiting response label May 14, 2019
@jaypan
Copy link
Author

jaypan commented May 23, 2019

Sorry it's taken me a while to get back to this.

Unfortunately, it's not working for me. I've added this to cypress/plugins/index.js:

module.exports = function (on, config) {
  "use strict";

  on('before:browser:launch', function (browser = {}, args) {

    if (browser.name === 'chrome') {
      args.push('--use-fake-ui-for-media-stream');
      args.push('--use-fake-device-for-media-stream');
      args.push('--use-file-for-fake-audio-capture=cypress/fixtures/audio/test.mp');
    }

    return args;
  });
};

I'm still getting the same error:

Uncaught TypeError: Cannot read property 'getUserMedia' of undefined

This error originated from your application code, not from Cypress.

Logging the args being sent to the browser, I see this:

[ '--test-type',
  '--ignore-certificate-errors',
  '--start-maximized',
  '--silent-debugger-extension-api',
  '--no-default-browser-check',
  '--no-first-run',
  '--noerrdialogs',
  '--enable-fixed-layout',
  '--disable-popup-blocking',
  '--disable-password-generation',
  '--disable-save-password-bubble',
  '--disable-single-click-autofill',
  '--disable-prompt-on-repos',
  '--disable-background-timer-throttling',
  '--disable-renderer-backgrounding',
  '--disable-renderer-throttling',
  '--disable-restore-session-state',
  '--disable-translate',
  '--disable-new-profile-management',
  '--disable-new-avatar-menu',
  '--allow-insecure-localhost',
  '--reduce-security-for-testing',
  '--enable-automation',
  '--disable-infobars',
  '--disable-device-discovery-notifications',
  '--autoplay-policy=no-user-gesture-required',
  '--disable-site-isolation-trials',
  '--metrics-recording-only',
  '--disable-prompt-on-repost',
  '--disable-hang-monitor',
  '--disable-sync',
  '--disable-web-resources',
  '--safebrowsing-disable-auto-update',
  '--safebrowsing-disable-download-protection',
  '--disable-client-side-phishing-detection',
  '--disable-component-update',
  '--disable-default-apps',
  '--use-fake-ui-for-media-stream',
  '--use-fake-device-for-media-stream',
  '--proxy-server=http://localhost:51989',
  '--proxy-bypass-list=<-loopback>',
  '--use-fake-ui-for-media-stream',
  '--use-fake-device-for-media-stream',
  '--use-file-for-fake-audio-capture=cypress/fixtures/audio/test.mp3' ]

Note that the file cypress/fixtures/audio/test.mp3 does exist. I've also tried the paths:

  • fixtures/audio/test.mp3
  • audio/test.mp3

As well as all combinations with a leading slash. I've shut down the test runner (the browser GUI) in between each change to make sure that the args are picked up during browser launch, and can confirm that they are, but that the error still occurs.

@flotwig
Copy link
Contributor

flotwig commented May 23, 2019

Have you tried using a .wav file? A .mp3 won't work, according to the docs for --use-file-for-fake-audio-capture:

Play a .wav file as the microphone. Note that for WebRTC calls we'll treat the bits as if they came from the microphone, which means you should disable audio processing (lest your audio file will play back distorted). The input file is converted to suit Chrome's audio buses if necessary, so most sane .wav files should work. You can pass either to play the file looping or %noloop to stop after playing the file to completion. ↪

@jaypan
Copy link
Author

jaypan commented May 23, 2019

I was just digging through the docs and found that myself. I tried a .wav file, but it also results in the same error.

I also tried removing the line to --use-file-for-fake-audio-capture altogether, as it seems from the comment below like it should create a file by default, but that also still throws the same error.

// This class acts as a fake audio input stream. The default is to generate a
// beeping sound unless --use-file-for-fake-audio-capture=<file> is specified,
// in which case the indicated .wav file will be read and played into the
// stream.

@flotwig
Copy link
Contributor

flotwig commented May 23, 2019

Hmm, that's strange. I'm using Cypress 3.3.0 with Chromium 73 on Linux and it works fine for me, even without --use-file-for-fake-audio-capture:

<!DOCTYPE html>
<html>
  <head>
    <script>
      window.onload = function() {
        var constraints = {
          audio: true,
          video: false
        };

        navigator.mediaDevices.getUserMedia(constraints)
        .then(stream => {
          console.log(stream)
        })
      };
    </script>
  </head>
  <body>
    <p>Hello World</p>
  </body>
</html>

image

What version of Chrome are you using?

@jaypan
Copy link
Author

jaypan commented May 23, 2019

Chrome 74.
Exact html doc as you (I copy/pasted), and I get this:

Screen Shot 2019-05-24 at 0 03 23

@flotwig
Copy link
Contributor

flotwig commented May 23, 2019

Well, as soon as I use Chrome 74, I get the same error.... maybe some behavior changed between 73 and 74 w.r.t. how these command line args are handled.

@jaypan
Copy link
Author

jaypan commented May 23, 2019

Oh, well that's a pain. Thanks for your help, much appreciated.

@jaypan
Copy link
Author

jaypan commented Jun 1, 2019

Guys, I've just realized I was overlooking the problem altogether. I've been developing in Firefox - where my code works fine. Cypress of course runs in Chrome, not Firefox. I finally took the time to look open it in Chrome - and sure enough it wasn't working in the browser, hence it was a problem with my application, and not in Cypress. I think the biggest indicator of this was probably Cypress telling me from the start that it was a problem in my application and not in Cypress :)

The actual problem is that Chrome blocks getUserMedia() in a non-HTTPS context. This is probably documented somewhere, but I figured it out through a guess and a test. When calling getUserMedia() in a non-HTTPS context, Chrome fails without even prompting the user to give permission to use the microphone, hence the error.

So I can comfortably say that this works (but the underlying application must be in HTTPS to work in Chrome):

module.exports = function (on, config) {
  "use strict";

  on('before:browser:launch', function (browser = {}, args) {

    if (browser.name === 'chrome') {
      args.push('--use-fake-ui-for-media-stream');
      args.push('--use-fake-device-for-media-stream');
      args.push('--use-file-for-fake-audio-capture=cypress/fixtures/test.mp3');
    }

    return args;
  });
};

I'll note that as can be seen from the code above, the code works with an .mp3 file as well, and does not require a .wav file, even though the underlying documentation would seem to indicated it does.

@jennifer-shehane jennifer-shehane removed the stage: awaiting response Potential fix was proposed; awaiting response label Jun 3, 2019
@jennifer-shehane
Copy link
Member

@jaypan Great to hear you were able to get it to work!

@ziadasem
Copy link

ziadasem commented Sep 5, 2019

this error is due to chrome and other browsers block microphone access to not https sites
so try to install SSL
you can get your free one from here
https://www.sslforfree.com/
and follow the tutorial

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants