Open Bug 1197047 Opened 9 years ago Updated 2 years ago

Switching between speaker and headphone output in Creative control panel breaks playback

Categories

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

defect

Tracking

()

People

(Reporter: kinetik, Assigned: kinetik)

References

()

Details

Using the Creative Sound Blaster Z custom control panel to switch between headphone and speaker output via the "Speakers/Headphones" tab causes playback to completely stop.

We handle device changes via an IMMNotificationClient listening for OnDefaultDeviceChanged, but in this situation the callback is never called.

We do get a larger number of OnPropertyValueChanged callbacks indicating various properties have changed - I couldn't find documentation or even search engine references for most of the properties, but we do get at least the following:

PKEY_AudioEndpoint_FullRangeSpeakers
PKEY_AudioEndpoint_PhysicalSpeakers
PKEY_AudioEngine_DeviceFormat

Note that PKEY_AudioEngine_DeviceFormat only occurs if the default device format for the headphones and speakers actually differs - in my case the speakers are stereo and the headphones appear as a 5.1 system.  If I set the default format of the speakers to 5.1, we never get a PKEY_AudioEngine_DeviceFormat change notification.

The values of PKEY_AudioEndpoint_FullRangeSpeakers and PKEY_AudioEndpoint_PhysicalSpeakers during the device change don't seem to be unique enough to use as a trigger for a device change (bearing in mind that I'm seeing 60+ OnPropertyValueChanged invocations for a single switch).

What ultimately breaks playback is that wasapi_stream_render_loop wakes up in the middle of the barrage of OnPropertyValueChanged calls to try to refill the stream, and GetCurrentPadding fails with AUDCLNT_E_RESOURCES_INVALIDATED (0x88890026), causing is_playing to be set to false in the GetCurrentPadding error handling.

The error AUDCLNT_E_RESOURCES_INVALIDATED appears in the OS headers but is otherwise completely undocumented in MSDN as far as I can find.  Presumably this could be treated the same way as AUDCLNT_E_DEVICE_INVALIDATED which we already handle and use to trigger a device change in some cases.

We might have better luck catching this type of device change by registering a listener with the IAudioSessionEvents interface, but I haven't experimented with this yet.
IAudioSessionEvents doesn't seem to give us anything useful (or at all) in this situation, unless I implemented support incorrectly during my quick experimentation.

Worth noting that Chrome doesn't handle this type of device switch either, but their playback continues (without audio) at least.  Other apps that I've tested are switching correctly in this case, e.g. IE11, Edge, iTunes, Groove, Windows Media Player, various games.
Treating AUDCLNT_E_RESOURCES_INVALIDATED from GetCurrentPadding as a trigger to switch devices somewhat works, but after switching back and forth multiple times there seem to be cases where wasapi_stream_render_loop isn't being woken up so we never switch devices.
(In reply to Matthew Gregan [:kinetik] from comment #1)
> IAudioSessionEvents doesn't seem to give us anything useful (or at all) in
> this situation, unless I implemented support incorrectly during my quick
> experimentation.

Looks like I was wrong about that - my initial experiment was too sloppy with the lifetimes of the related interfaces and the listener ended up being unregistered before it did anything useful.  With a cleaner attempt, we seem to get OnStateChanged(AudioSessionStateInactive) and OnStateChanged(AudioSessionStateActive), in addition to a OnSessionDisconnected(DisconnectReasonFormatChanged) if the format of the speakers and headphones differs.
Assignee: nobody → kinetik
Status: NEW → ASSIGNED
Component: Audio/Video: MediaStreamGraph → Audio/Video: cubeb
Rank: 28
Priority: -- → P2
Still relevant?
Flags: needinfo?(kinetik)
Yes.  Need to find time to fix this.
Flags: needinfo?(kinetik)
Mass change P2->P3 to align with new Mozilla triage process.
Priority: P2 → P3
Status: ASSIGNED → NEW
Severity: normal → S3
You need to log in before you can comment on or make changes to this bug.