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

Implementers must not refuse to open sources set as default at the machine: "DOMException: Could not start audio source" is not in the specification #708

Closed
guest271314 opened this issue Aug 2, 2020 · 6 comments

Comments

@guest271314
Copy link

Chromium deliberately refuses to open a source which are monitor inputs at Linux per https://chromium.googlesource.com/chromium/src/+/4519c32f528e079f25cb2afc594ecf625f943782, see https://bugs.chromium.org/p/chromium/issues/detail?id=931749.

PulseAudio: Filter out unavailable inputs and refuse to open monitor inputs

which results in this code

navigator.mediaDevices.getUserMedia({audio: true})
.then(stream => {
  const recorder = new MediaRecorder(stream);
  recorder.ondataavailable = e => console.log(URL.createObjectURL(e.data));
  recorder.start();
  setTimeout(_ => recorder.stop(), 30000);
}).catch(console.error);

throwing this exception

DOMException: Could not start audio source

No such error is thrown at Nightly 80 and the device set as default, listed first in the UI when the same code is run.

The problem is such a DOMException is not described in the specification. Nor is restricting monitor sources set as default by the user intentionally at their machine.

The specification should not care which sources the user sets at OS level. If the user sets a default source for microphone at the OS then getUserMedia({audio: true}) should capture that source, not throw a DOMException with attached message claim "Could not start source", which is simply not true, as it is possible to dynamically set the source to a monitor after getUserMedia({audio: true}) is called using pavucontrol or pavucontrol-qt - which will result in the device that was claimed could not start being captured.

The solution is to state clearly that Implementers must not refuse to open sources set as default at OS. It is the users' prerogative which device they set as default source, not implementers, language such as

Implementers must not refuse to open sources set as default.

should suffice, for the ability cite the controlling specification at the above-listed bug report, indicating that behaviour is non-conformant with the specification, and must be modified to not restrict capture of the default source set by the user at their own machine.

@guest271314
Copy link
Author

If a user runs this line

$ pacmd "set-default-source $(pactl list | grep -A2 '^Source #' | grep 'Name: .*\.monitor$' | awk '{print $NF}' | tail -n1)"

at a shell, then the expected behaviour is for the source set to be captured at getUserMedia({audio: true}), and there is not reason in the specification why that should not be the expected behaviour and result.

@guest271314
Copy link
Author

This bug leads back to the sequence of events described at #703 (comment), specifically, the order should be enumerateDevices() permissions granted or not => getUserMedia() if permissions are granted, instead of getUserMedia() permissions granted or not => enumerateDevices() if granted - to avoid having to execute getUserMedia() twice to select one device intended to be selected

navigator.mediaDevices.getUserMedia({audio: true})
.then(async stream => {
  const [track] = stream.getTracks();
  const devices = await navigator.mediaDevices.enumerateDevices();
  console.log(devices);
  const {deviceId} = devices.find(({kind, label}) => kind === "audiooutput");
  track.stop();
  return navigator.mediaDevices.getUserMedia({audio:{deviceId:{exact: deviceId}}});
})
.then(stream => {
  console.log(stream.getTracks()[0]);
  // do stuff
})
.catch(console.error);

where even then the same code cannot be run at both Chromium and Nighly 80 because Nighly lists kind of the device as "audioinput" and label as "Monitor of Built-in Audio Analog Stereo" where Chromium 86 lists kind as audiooutput and label as "Default".

Preferably the devices should be able to be selected before capture of the device is started.

There should be consistency here.

@guest271314
Copy link
Author

According to PulseAudio/Examples monitor device is an input source

Set default input source

$ pacmd list-sources | grep -e 'index:' -e device.string -e 'name:'
  index: 0
    name: <input>
      device.string = "hw:2"
* index: 1
    name: <oss_input.dsp>
      device.string = "/dev/dsp"
  index: 2
    name: <alsa_output.pci-0000_04_01.0.analog-stereo.monitor>

For disambiguation in this specification are monitor devices audio input "audioinput" or audio output "audiooutput" source?

@jan-ivar
Copy link
Member

Unfortunately, I don't think specs have a lot of sway convincing vendors what to implement, only how to implement it.

While "User Agents are encouraged to default to using the user's primary or system default device", there is no requirement.

Which devices to expose is entirely up to the user agent.

If a browser exposes a non-functioning device in enumerateDevices that seems like a bug in that implementation, so I'm going to close this.

@Bug-Reaper
Copy link

Bug-Reaper commented Feb 29, 2024

@jan-ivar

Just for reference, the exposed monitor devices are 100% functional. These devices function exactly as intended and have practical application for music visualization and other exotic audio configurations.

While I agree specs are unlikely to force a vendor's hand, I want to acknowledge there are use-cases where these devices are the one's a user/developer intended to use.

The mistake that a virtual device is "non-functioning" seems earnest and with good intention. That said it is quite frustrating to learn the input device you configured is arbitrarily blacklisted by a vendor despite it's availability.

A user could disable monitor devices if they wanted on the system level. I'd imagine if we wanted to disable monitor devices by default it'd be better to take that upstream to the audio-libraries as opposed to have vendors go against spec b/c they do not commonly use the feature.

@guidou
Copy link
Contributor

guidou commented Mar 6, 2024

Just FYI, the reason Chrome doesn't expose monitor devices is not that they are virtual or non-functioning. In fact, Chrome exposes some virtual devices, like the "Communications" device on Windows, and "Default" devices on all platforms, which map to real microphones.

The reason Chrome doesn't expose monitor devices is that in our past experience they create a lot of confusion among users because they are not microphones. gUM in Chromium is designed (UI, audio processing, etc.) to support microphones.

So, this is not a bug in the spec. It would be a feature request for Chromium, which Chromium has no interest to implement at the moment.

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