Open Bug 2073800 Opened 21 days ago Updated 3 days ago

macOS: while a microphone is open, all page audio is delivered to the input device's own output channels (aggregate device lists the input device first)

Categories

(Core :: Audio/Video: cubeb, defect)

Firefox 155
defect

Tracking

()

Tracking Status
firefox-esr115 --- unaffected
firefox-esr153 --- affected
firefox157 --- wontfix
firefox158 --- wontfix
firefox159 --- fix-optional

People

(Reporter: zamalloachion.diego, Assigned: padenot, NeedInfo)

References

(Regression)

Details

(Keywords: regression)

Attachments

(4 files)

Steps to reproduce:

Needs macOS with a default input device that also has output channels (a USB microphone with a headphone jack, a USB headset, an audio interface) and a different default output device. Here: input = Samson G-Track Pro (USB, 2 in / 2 out), output = the Mac's built-in headphone jack ("External Headphones"), both at 48 kHz. Firefox 155.0.1, macOS 26.5.1, Apple M2 Pro.

  1. Open the attached repro.html and press Start tone. A 330 Hz tone plays on the default output device.
  2. Press Open microphone. It calls getUserMedia with echoCancellation, noiseSuppression and autoGainControl all false, so the VoiceProcessingIO path is not taken.
  3. Press Close microphone.

Actual results:

Playback goes silent on the default output device for as long as the microphone is open, and returns when the track is stopped. (Heard with a real page that plays Web Audio while pitch-tracking the microphone; the attached minimal page produces the identical re-routing in the cubeb log below.) Nothing is reported to the page: the AudioContext stays running and currentTime keeps advancing. The MediaStream does not have to be connected to the AudioContext (the attached page never connects it); any same-rate AudioContext in the window is affected because it shares the graph.

Analysis

When input and output devices differ, cubeb-coreaudio-rs builds a private aggregate device and re-opens the output side on it. Two changes from 2024 combine badly:

  • f8df86f "On aggregate devices put the input device first" fixes input channel selection, but sub-device order also decides output stream order, so the input device's own output channels become channels 1-2 of the aggregate.
  • 6d84f46 "Route to the stereo pair even when having an input" (vendored in bug 1903315, see also bug 1903283): a stereo stream now sets kAudioUnitProperty_AudioChannelLayout = Stereo on the AUHAL and skips the mixer. On the aggregate the stereo pair is channels 1-2, i.e. the input device's outputs. (Inferred from the stream order below; not confirmed by ear on the USB device's own jack.)

The comment above the output format set-up still describes the old order ("the data recorded by the input device's output channels will be appended at the end"), and nothing sets kAudioDevicePropertyPreferredChannelsForStereo or a channel map on the aggregate.

Evidence (further attachments to follow):

  • cubeb-log-firefox-155.txt (MOZ_LOG=cubeb:4, stream set-up lines only): output opens on device 106 with 2 channels [FrontLeft, FrontRight]; on getUserMedia, "Add devices input 113 and output 106 into an aggregate device 176", then the output side re-opens on 176 with 4 channels, layout [FrontLeft, FrontRight, Discrete, Discrete], no "setting up remixer" line and no AudioChannelLayout error; on track.stop() the aggregate is destroyed and output returns to device 106 with 2 channels.
  • aggregate-probe.swift builds the same private aggregate with both orders and prints its output streams. Input-first gives stream 1 (channels 1-2, "Front Left/Right") = the USB microphone's headphone output and stream 2 (channels 3-4) = the built-in headphone jack, with preferred stereo pair [1, 2]. Output-first puts the built-in jack on channels 1-2.

Possible fixes

Offset the output onto the output device's channels within the aggregate (a kAudioOutputUnitProperty_ChannelMap, or setting the aggregate's preferred stereo pair to [n+1, n+2] where n is the input device's output channel count) before taking the stereo-pair shortcut; the mixer path needs the same offset, since the layout it sees labels the input device's channels Front Left/Right.

Workaround for web pages

Create the playback AudioContext with a sampleRate different from the native one. It then lives in its own MediaTrackGraph with an output-only stream that is never moved onto the aggregate (verified in the cubeb log). A second AudioContext at the native rate does not help.

Expected results:

Playback stays on the default output device while a microphone on another device is open. Chrome on the same machine is unaffected (it opens independent input and output units).

The severity field is not set for this bug.
:karlt, could you have a look please?

For more information, please visit BugBot documentation.

Flags: needinfo?(karlt)
Flags: needinfo?(karlt)
Keywords: regression
Regressed by: 1903315

:padenot, since you are the author of the regressor, bug 1903315, could you take a look? Also, could you set the severity field?

For more information, please visit BugBot documentation.

Flags: needinfo?(padenot)

Taking.

Assignee: nobody → padenot
Status: UNCONFIRMED → NEW
Ever confirmed: true
Flags: needinfo?(padenot)

Set release status flags based on info from the regressing bug 1903315

The severity field is not set for this bug.
:karlt, could you have a look please?

For more information, please visit BugBot documentation.

Flags: needinfo?(karlt)
Flags: needinfo?(karlt)

The severity field is not set for this bug.
:karlt, could you have a look please?

For more information, please visit BugBot documentation.

Flags: needinfo?(karlt)
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: