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

Setting the audio output for a whole context or page #87

Open
youennf opened this issue Nov 28, 2019 · 7 comments
Open

Setting the audio output for a whole context or page #87

youennf opened this issue Nov 28, 2019 · 7 comments

Comments

@youennf
Copy link
Contributor

youennf commented Nov 28, 2019

Currently, we are only able to control individual HTMLMediaElement audio output with setSinkId.
We probably need to add something to WebAudio as well.

In most cases, it seems that pages will want to output all their audio to a single device.
Adding such an API to do so would be convenient and would complement setSinkId which would be used to override this default value.

Something at navigator.mediaDevices level might make sense.

@youennf youennf changed the title Setting the output for a whole context Setting the audio output for a whole context or page Nov 28, 2019
@youennf
Copy link
Contributor Author

youennf commented Nov 28, 2019

This somehow relates to #63.
With this new API, an iframe could be able to update the page audio output if it were allowed to do so by feature policy.

@fippo
Copy link

fippo commented Dec 1, 2019

In most cases, it seems that pages will want to output all their audio to a single device.

Actually no. You might want to have the "ring" sound to go to the speaker (so you hear it if you are not at your desk) while during the call you want to have sound going to your headset. Arguably you might want in-call notification sounds to go to your headset too then.

@youennf
Copy link
Contributor Author

youennf commented Dec 2, 2019

If the user is not interacting/interested in the web application, the application is probably not in a position to select the proper means to request user interest. For instance, you might want the device to vibrate instead of playing a ring tone if the device is in vibration mode, but you probably do not want to let the application know you are in vibration mode.
This API does not seem to be a good fit for this use case, which is closer to existing notification API use cases.

On the other hand, if the web application knows the user is interacting with the page, like in the middle of a phone call, it seems natural to use the same speaker device.

I agree though that there are use cases for multi speaker setup cases (hence why HTMLMediaElement.setSinkId is good to have too). These use cases might not be as common, hence why it might be useful to have a page-wide version.

@jan-ivar
Copy link
Member

We probably need to add something to WebAudio as well.

Web audio seems easy enough to work around. Instead of:

audioNode.connect(audioContext.destination);

you'd do

const dest = audioContext.createMediaStreamDestination();
element.srcObject = dest.stream;
audioNode.connect(dest);

Not sure about audio worklet though.

In most cases, it seems that pages will want to output all their audio to a single device.

The workaround is to collect all elements and set them:

async function setAllElements(sinkId) {
  const elements = [...doc.getElementsByTagName("audio"),
                    ...doc.getElementsByTagName("video")];
  await Promise.all(elements.map(element => element.setSinkId(sinkId)));
}

@youennf
Copy link
Contributor Author

youennf commented May 20, 2020

This is not working for third-party iframes.
For WebAudio, this seems a rather convoluted solution.
At least in Safari, this is most probably less efficient and would probably add some latency.

@jan-ivar
Copy link
Member

jan-ivar commented May 20, 2020

This is not working for third-party iframes.

@youennf I'm confused. It should work fine for the JS inside the iframe. Or do you want #63?

If so, should we close one of the issues as a dup?

@elibarzilay
Copy link

I got here while trying to get this to work now in chrome, and if something like a whole page default can simplify how changing a device is done now, it would be very nice. I'm really just playing around, so take it with a sack of salt, but OTOH there's generally a lot of confusion on the interwebs.

The thing that tripped me is that if you createMediaElementSource an audio element (in my case since I want to monitor it for a visualization of a player), then it's no longer playing until you manually connect that stream to ctx.destination, but AFAICT this is currently (in chrome, at least) always playing the default device. So to get the monitor to work the only way I found was to create a second Audio, set its srcObject to a fresh createMediaStreamDestination()'s stream, and then use setSinkId on that audio. That's much more than @jan-ivar's loop suggests, and would be nice to simplify. (But maybe I'm confusion too.)

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