mirror of
https://github.com/vector-im/element-call.git
synced 2026-10-13 23:35:51 +00:00
Prefer the browser default audio output when no output has been chosen
On browsers without a "default" pseudo-device (Firefox, Safari), the virtual default output entry was appended after the physical devices, so with no saved preference EC selected the first physical device and pinned every remote audio element to it with setSinkId. Pinned sinks are not re-routed by the browser: on Firefox/Linux a Bluetooth headset switching from A2DP to HFP when its microphone is opened (i.e. on unmute) destroys the pinned sink and all remote audio goes silent, with no error and no fallback (rageshake 17320). List the virtual default first so it is the fallback both when nothing was chosen and when the chosen output disappears, and stop labelling it with the first device's name since the browser default is not necessarily that device.
This commit is contained in:
@@ -257,14 +257,21 @@ export class AudioOutput implements MediaDevice<
|
||||
map((availableRaw) => {
|
||||
let available: Map<string, AudioOutputDeviceLabel> =
|
||||
buildDeviceMap(availableRaw);
|
||||
// Create a virtual default audio output for browsers that don't have one.
|
||||
// Its device ID must be the empty string because that's what setSinkId
|
||||
// recognizes.
|
||||
// Create a virtual default audio output for browsers that don't have one
|
||||
// (Firefox, Safari). Its device ID must be the empty string because
|
||||
// that's what setSinkId recognizes. It goes first so that it is the
|
||||
// fallback when no output has been explicitly chosen (or the chosen
|
||||
// one disappears), rather than pinning the first physical device
|
||||
// with setSinkId: pinned sinks are not re-routed by the browser, and
|
||||
// Firefox leaves the audio elements silent when a pinned sink goes
|
||||
// away (e.g. a Bluetooth headset switching profile when its
|
||||
// microphone is opened). We can't know which physical device the
|
||||
// browser default resolves to, so the entry carries no name.
|
||||
if (available.size && !available.has("") && !available.has("default"))
|
||||
available.set("", {
|
||||
type: "default",
|
||||
name: availableRaw[0]?.label || null,
|
||||
});
|
||||
available = new Map<string, AudioOutputDeviceLabel>([
|
||||
["", { type: "default", name: null }],
|
||||
...available,
|
||||
]);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const isSafari = !!(window as any).GestureEvent; // non standard api only found on Safari. https://developer.mozilla.org/en-US/docs/Web/API/GestureEvent#browser_compatibility
|
||||
if (isSafari) {
|
||||
|
||||
Reference in New Issue
Block a user