-
Notifications
You must be signed in to change notification settings - Fork 168
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
Access to a different output device: AudioContext.setSinkId() #2400
Comments
http://w3c.github.io/mediacapture-output/#h-webaudio-extensions Just to keep the reference here. The spec enumerates several options for implementation with pros/cons. |
Missing is any information about characteristics of output devices (channels, etc., etc.) - this is a getUserMedia issue, but essential to solve |
This is currently in Media Capture Task Force's court; we are monitoring their progress. |
I don't think MCTF is just gonna fix our problem, though - and we need to provide a constructor that takes a different device. |
@cwilso If MCTF provides a way to obtain a MediaStream for some desired device (which is what we asked for, and their updated API seems well on the way to giving it to us) then doesn't AudioContext::createMediaStreamDestination() provide a way to use that device as a destination? |
Sure. But that would absolutely be a HORRIBLE way to connect - because you want the AudioContext to run at the rate and clock of the device, not at some arbitrary other clock and have to be coerced to that device. MediaStream device in/out implies a potential for clock conversion. |
@cwilso Thanks for explaining - I had not been aware of that very significant point (I wonder if others were?). Perhaps something as simple as a class method on AudioContext would fill the bill, e.g. Do you have a specific proposal in mind for us to discuss on Thursday? |
Yes, it's what I gave Justin to put in the MCTF spec: 3.1.1 Constructor argument
By requiring the sink ID to be set at construction time, this simplifies the implementation, since the output sample rate is fixed. |
I see now, it's in the document that @hoch referenced above. Sorry for the thrash here. Yup, that all looks great. |
So... apart from MCTF needing to approve, is there a reason this is not just "Ready for Editing"? |
@cwilso So that I can make sure MCTF is focusing on the right stuff: exactly what elements of the Audio Output API other than the Web Audio extensions must exist for V1, from your point of view? Since a sinkId is just a deviceID from enumerateDevices() (which itself is not part of the Audio Output API), do we really need to make the whole Audio Output API proposal a dependency for V1 Web Audio? |
I think we (Web Audio) are responsible for making sure AO API and WA API work together to define bedrock (e.g. audio device access, audio bits access a la issue #359) vs. layers on top of that bedrock (e.g. biquadfilter). If we don't work through and make sense of these architectural layers now, it will never make sense. |
Just to confirm: you are saying we shouldn't implement the constructor until the whole AO API is accepted by MCTF? |
No, that's not quite what I'm saying. I'm saying we shouldn't ship until the model for how access to devices - bedrock - works. We should be able to work through and prove how is built on top of Web Audio, which is built on top of direct device access alongside getUserMedia (which provides device enumeration). The Audio Output API is actually a semantic layer on top of an implementation - we just need to prove that we could implement that (through device enumeration from gUM and redirecting of AudioContexts). |
OK -- can you walk us through this on tomorrow's call? Let's discuss what "prove" means, in particular. |
Sure On Wed, May 13, 2015 at 9:21 AM, Joe Berkovitz [email protected]
|
This issue is Ready for Editing w/r/t the AudioContext constructor as described Audio Output API proposal. However we need to still wait for MCTF response re the ability to enumerate devices with an awareness of sample rate, latency, number of channels, etc. |
We should also ask MCTF about Permissions API with respect to acquiring permission to access or enumerate devices. |
Is there any work around to get this functionality with AudioContext? With appropriate flags enabled, I'm able to get the list of audio devices via navigator.mediaDevices.enumerateDevices(), but I'm at a loss on how to set the output to a given device id. It would be a super useful feature. |
I found a workaround, but I'm not sure how well it works yet. There seems to be pops and glitches with a single sine oscillator. Basically the Audio element has a setSinkId for setting the appropriate output device. With the audio element setup to send to the appropriate output, you can stream from the audiocontext to the audio element by creating a mediaStreamDestination, and passing it's stream property to the audio element. e.g.
Not sure how well this will work when dealing with several oscillators, effects, etc yet, but appears to be somewhat functional when appropriate flags are set. UPDATE: I plugged this behavior into my synthesizer. |
Btw, the permission dialog is: "site wants to use your microphone" which is not going to get accepted if the user is went to e.g. "output device settings" section of an app. Something should probably be done about that so that app that simply wants to enable the user to choose between audio output devices can do so without having to deal with creepy microphone permissions. |
You can get the |
I cannot imagine a use case where the label wouldnt be needed, other than malicous ones. —Reply to this email directly or view it on GitHub. |
|
Its unacceptable to present that to a normal user who will just think the app is cheap/unfinished. —Reply to this email directly or view it on GitHub. |
We are talking about audio people, right (didn't they invent Seriously, though. What are you suggesting? That output device labels be in the clear? |
I implied there should be separate permission for seeing audio output labels, not "wants to use your microphone" which is creepy as hell when the app has no reason for it. Applications that play sound are not for "audio people only". Even if they were, that doesnt change the feeling of low quality and cheapness when an app cannot even get your devices right while all other apps can. On Jan 31, 2016 21:25, jan-ivar [email protected] wrote:We are talking about audio people, right (didn't they invent output 1 and output 2)? Seriously, though. What are you suggesting? That output device labels be in the clear? —Reply to this email directly or view it on GitHub. |
More details on a solution that doesn't seem clean or practical: setSinkId((DOMString or AudioContextOptions) sinkId); Where dictionary AudioContextOptions {
(AudioContextLatencyCategory or double) latencyHint = "interactive";
float sampleRate;
(DOMString or AudioContextSinkOptions) sinkId;
};
dictionary AudioContextSinkOptions {
bool useSilentSink;
} With this way, we can change the latency hint and the sample rate when we change the sink. |
Could the following be expressed in WebIDL? new AudioContext() // uses the default device since sinkId is not defined
new AudioContext({ sinkId: null }) // uses no output device since sinkId is set to null
// or
const audioContext = new AudioContext();
audioContext.setSinkId(null);
new AudioContext({ sinkId: 'abcd' }) // uses the device with the sinkId called 'abcd'
// or
const audioContext = new AudioContext();
audioContext.setSinkId('abcd'); If I recall correctly any member of a dictionary is nullable by default. In that case it would just be a dictionary in WebIDL. dictionary AudioContextOptions {
DOMString sinkId;
} Another option could be to use new AudioContext({ sinkId: false })
// or
const audioContext = new AudioContext();
audioContext.setSinkId(false); I'm not sure though if it is possible to define a union of a DOMString with a boolean in WebIDL. |
Using I don't have a strong opinion, but the |
Have you all considered putting this functionality on |
There's 1:1 association between AudioContext and AudioDestinationNode. Having multiple AudioDestinationNodes is an idea, but I am not sure we want to pursue. Multiple devices mean that the system needs to handle sample rate and callback buffer differences across them. Also - the multi-routing is already possible with multiple instances of MediaStreamAudioDestinationNode -(MediaStream)-> AudioElement. You'll lose sample-accurate synchronization between devices, but that's expected without device aggregation and an intermedia layer. |
This idea also was proposed from Chrome engineers: audioContext.setSinkId("default");
audioContext.setSinkId("device-unique-id");
audioContext.setSinkId("silent"); No complicated types, just plain DOMStrings. This is easy and sensible, but IIUC there's no precedences in Web Audio API. We've been using enums for this purpose. |
To recap, here are two proposals for configurability: A. Using dictionary AudioContextOptions {
...
(DOMString or AudioSinkOptions) sinkId;
};
dictionary AudioSinkOptions {
bool useSilentSink;
}
// example
audioContext.setSinkId("");
audioContext.setSinkId("5b79a953d8fb279...");
audioContext.setSinkId({useSilentSink: true}); B. Using plain strings: dictionary AudioContextOptions {
...
DOMString sinkId;
};
// example
audioContext.setSinkId("");
audioContext.setSinkId("5b79a953d8fb279...");
audioContext.setSinkId("silent"); |
Is it a guarantee that no device (sink) will ever have an ID of |
See examples if typical IDs over here: This is what I get from my MacbookPro + Chrome:
So I would say no and yes:
|
This comment was marked as off-topic.
This comment was marked as off-topic.
The identifier is generated by the browser, it cannot be controlled by authors. It's different than the device name. |
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
As @padenot mentioned above, the |
Update from discussing with @hoch at TPAC, this is what we're currently thinking: enum AudioSinkType {
"default",
"none",
};
dict AudioSinkOptions {
AudioSinkType type;
};
partial interface AudioContext {
Promise<undefined> setSinkId(AudioSinkOptions or DOMString);
}
|
This comment was marked as off-topic.
This comment was marked as off-topic.
A slight update and one more discussion topic: enum AudioSinkType {
"none"
};
dict AudioSinkOptions {
AudioSinkType type;
};
partial interface AudioContext {
Promise<undefined> setSinkId(AudioSinkOptions or DOMString);
}
Question: what would be the value of |
We agreed upon the enum AudioSinkType {
"none"
};
dict AudioSinkOptions {
AudioSinkType type;
};
partial interface AudioContext {
readonly attribute (DOMString or AudioSinkOptions) sinkId;
Promise<undefined> setSinkId(DOMString or AudioSinkOptions);
} |
This comment was marked as off-topic.
This comment was marked as off-topic.
hoch, would this generally mean that after a successful setSinkId we should get exactly the same argument back when we call sinkId? guest271314, I think you are describing using PulseAudio commands to make a microphone / other input device appear as an output device, then setting that output device as the system default output device. I don't think this is the usual configuration, so if someone has set up their system that way it may be that they have a reason to and the browser should respect that. Are you concerned with the meaning of "default audio output device" in the spec? Would it make more sense to say something like the "system-reported" default audio output device? It seems to me that if the user configures their system to have a particular default output audio device, then that is the "real" default audio output device (even if it happens to be a microphone, /dev/null, etc.). There isn't anything special that would make one audio device the natural default for a particular system. Or am I misunderstanding your concern? |
Based on the algorithm, the internal slot changes only when the transition is successful. So: await context.setSinkId('some-id'); // if this was successful
console.log(context.sinkId); // then this should be 'some-id' |
Should be able to specify different audio devices, using media device selectors.
The text was updated successfully, but these errors were encountered: