commit b632604cf8b8f3fe769ddf1cf82f02627b29b915
parent a6fe17852ae81dec0d634665abac2de42d93cec0
Author: Karl Tomlinson <karlt+@karlt.net>
Date: Wed, 17 Dec 2025 12:38:42 +0000
Bug 2005992 Switch MediaTrackGraph drivers only in CheckDriver() r=padenot
This coalesces changes and consolidates logic in one place.
DeviceInputTrack is an AUDIO track and so CloseAudioInputImpl() never switched
to a SystemClockDriver, until CheckDriver() reconsidered on the next iteration.
This covered over the omission of mPendingResumeOperations logic in the choice
of driver.
Differential Revision: https://phabricator.services.mozilla.com/D276412
Diffstat:
3 files changed, 54 insertions(+), 119 deletions(-)
diff --git a/dom/media/GraphDriver.h b/dom/media/GraphDriver.h
@@ -631,11 +631,13 @@ class AudioCallbackDriver final : public GraphDriver,
return this;
}
- uint32_t OutputChannelCount() { return mOutputChannelCount; }
+ uint32_t OutputChannelCount() const { return mOutputChannelCount; }
- uint32_t InputChannelCount() { return mInputChannelCount; }
+ uint32_t InputChannelCount() const { return mInputChannelCount; }
- AudioInputType InputDevicePreference() {
+ CubebUtils::AudioDeviceID InputDeviceID() const { return mInputDeviceID; }
+
+ AudioInputType InputDevicePreference() const {
if (mInputDevicePreference == CUBEB_DEVICE_PREF_VOICE) {
return AudioInputType::Voice;
}
diff --git a/dom/media/MediaTrackGraph.cpp b/dom/media/MediaTrackGraph.cpp
@@ -400,8 +400,7 @@ bool MediaTrackGraphImpl::AudioTrackPresent() {
void MediaTrackGraphImpl::CheckDriver() {
MOZ_ASSERT(OnGraphThread());
// An offline graph has only one driver.
- // Otherwise, if a switch is already pending, let that happen.
- if (!mRealtime || Switching()) {
+ if (!mRealtime) {
return;
}
@@ -449,13 +448,16 @@ void MediaTrackGraphImpl::CheckDriver() {
return;
}
- // Check if this graph should switch to a different number of output channels.
- // Generally, a driver switch is explicitly made by an event (e.g., setting
+ // Check if a new driver is required for a configuration change. Generally,
+ // a driver switch is explicitly triggered by an event (e.g., setting
// the AudioDestinationNode channelCount), but if an HTMLMediaElement is
// directly playing back via another HTMLMediaElement, the number of channels
// of the media determines how many channels to output, and it can change
// dynamically.
- if (primaryOutputChannelCount != audioCallbackDriver->OutputChannelCount()) {
+ if (primaryOutputChannelCount != audioCallbackDriver->OutputChannelCount() ||
+ inputDevice != audioCallbackDriver->InputDeviceID() ||
+ inputChannelCount != audioCallbackDriver->InputChannelCount() ||
+ inputPreference != audioCallbackDriver->InputDevicePreference()) {
AudioCallbackDriver* driver = new AudioCallbackDriver(
this, CurrentDriver(), mSampleRate, primaryOutputChannelCount,
inputChannelCount, PrimaryOutputDeviceID(), inputDevice,
@@ -768,28 +770,19 @@ void MediaTrackGraphImpl::OpenAudioInputImpl(DeviceInputTrack* aTrack) {
mDeviceInputTrackManagerGraphThread.Add(aTrack);
if (aTrack->AsNativeInputTrack()) {
- // Switch Drivers since we're adding input (to input-only or full-duplex)
- AudioCallbackDriver* driver = new AudioCallbackDriver(
- this, CurrentDriver(), mSampleRate, PrimaryOutputChannelCount(),
- AudioInputChannelCount(aTrack->mDeviceId), PrimaryOutputDeviceID(),
- aTrack->mDeviceId, AudioInputDevicePreference(aTrack->mDeviceId),
- Some(aTrack->UpdateRequestedProcessingParams()));
- LOG(LogLevel::Debug,
- ("%p OpenAudioInputImpl: starting new AudioCallbackDriver(input) %p",
- this, driver));
- SwitchAtNextIteration(driver);
- } else {
- NonNativeInputTrack* nonNative = aTrack->AsNonNativeInputTrack();
- MOZ_ASSERT(nonNative);
- // Start non-native input right away.
- nonNative->StartAudio(MakeRefPtr<AudioInputSource>(
- MakeRefPtr<AudioInputSourceListener>(nonNative),
- nonNative->GenerateSourceId(), nonNative->mDeviceId,
- AudioInputChannelCount(nonNative->mDeviceId),
- AudioInputDevicePreference(nonNative->mDeviceId) ==
- AudioInputType::Voice,
- nonNative->mPrincipalHandle, nonNative->mSampleRate, GraphRate()));
+ // CheckDriver() will check for changes, after all control messages are
+ // processed.
+ return;
}
+ NonNativeInputTrack* nonNative = aTrack->AsNonNativeInputTrack();
+ MOZ_ASSERT(nonNative);
+ // Start non-native input right away.
+ nonNative->StartAudio(MakeRefPtr<AudioInputSource>(
+ MakeRefPtr<AudioInputSourceListener>(nonNative),
+ nonNative->GenerateSourceId(), nonNative->mDeviceId,
+ AudioInputChannelCount(nonNative->mDeviceId),
+ AudioInputDevicePreference(nonNative->mDeviceId) == AudioInputType::Voice,
+ nonNative->mPrincipalHandle, nonNative->mSampleRate, GraphRate()));
}
void MediaTrackGraphImpl::OpenAudioInput(DeviceInputTrack* aTrack) {
@@ -832,30 +825,8 @@ void MediaTrackGraphImpl::CloseAudioInputImpl(DeviceInputTrack* aTrack) {
MOZ_ASSERT(aTrack->AsNativeInputTrack());
mDeviceInputTrackManagerGraphThread.Remove(aTrack);
-
- // Switch Drivers since we're adding or removing an input (to nothing/system
- // or output only)
- bool audioTrackPresent = AudioTrackPresent();
-
- GraphDriver* driver;
- if (audioTrackPresent) {
- // We still have audio output
- LOG(LogLevel::Debug,
- ("%p: CloseInput: output present (AudioCallback)", this));
-
- driver = new AudioCallbackDriver(
- this, CurrentDriver(), mSampleRate, PrimaryOutputChannelCount(),
- AudioInputChannelCount(aTrack->mDeviceId), PrimaryOutputDeviceID(),
- nullptr, AudioInputDevicePreference(aTrack->mDeviceId),
- Some(aTrack->UpdateRequestedProcessingParams()));
- SwitchAtNextIteration(driver);
- } else if (CurrentDriver()->AsAudioCallbackDriver()) {
- LOG(LogLevel::Debug,
- ("%p: CloseInput: no output present (SystemClockCallback)", this));
-
- driver = new SystemClockDriver(this, CurrentDriver(), mSampleRate);
- SwitchAtNextIteration(driver);
- } // else SystemClockDriver->SystemClockDriver, no switch
+ // CheckDriver() will check for changes, after all control messages are
+ // processed.
}
void MediaTrackGraphImpl::UnregisterAllAudioOutputs(MediaTrack* aTrack) {
@@ -1083,79 +1054,39 @@ void MediaTrackGraphImpl::ReevaluateInputDevice(CubebUtils::AudioDeviceID aID) {
("%p: No DeviceInputTrack for this device. Ignore", this));
return;
}
-
- bool needToSwitch = false;
-
- if (NonNativeInputTrack* nonNative = track->AsNonNativeInputTrack()) {
- if (nonNative->NumberOfChannels() != AudioInputChannelCount(aID)) {
- LOG(LogLevel::Debug,
- ("%p: %u-channel non-native input device %p (track %p) is "
- "re-configured to %d-channel",
- this, nonNative->NumberOfChannels(), aID, track,
- AudioInputChannelCount(aID)));
- needToSwitch = true;
- }
- if (nonNative->DevicePreference() != AudioInputDevicePreference(aID)) {
- LOG(LogLevel::Debug,
- ("%p: %s-type non-native input device %p (track %p) is re-configured "
- "to %s-type",
- this, GetAudioInputTypeString(nonNative->DevicePreference()), aID,
- track, GetAudioInputTypeString(AudioInputDevicePreference(aID))));
- needToSwitch = true;
- }
-
- if (needToSwitch) {
- nonNative->StopAudio();
- nonNative->StartAudio(MakeRefPtr<AudioInputSource>(
- MakeRefPtr<AudioInputSourceListener>(nonNative),
- nonNative->GenerateSourceId(), aID, AudioInputChannelCount(aID),
- AudioInputDevicePreference(aID) == AudioInputType::Voice,
- nonNative->mPrincipalHandle, nonNative->mSampleRate, GraphRate()));
- }
-
+ if (track->AsNativeInputTrack()) {
+ // CheckDriver() will check for changes, after all control messages are
+ // processed.
return;
}
+ bool needToSwitch = false;
- MOZ_ASSERT(track->AsNativeInputTrack());
-
- if (AudioCallbackDriver* audioCallbackDriver =
- CurrentDriver()->AsAudioCallbackDriver()) {
- if (audioCallbackDriver->InputChannelCount() !=
- AudioInputChannelCount(aID)) {
- LOG(LogLevel::Debug,
- ("%p: ReevaluateInputDevice: %u-channel AudioCallbackDriver %p is "
- "re-configured to %d-channel",
- this, audioCallbackDriver->InputChannelCount(), audioCallbackDriver,
- AudioInputChannelCount(aID)));
- needToSwitch = true;
- }
- if (audioCallbackDriver->InputDevicePreference() !=
- AudioInputDevicePreference(aID)) {
- LOG(LogLevel::Debug,
- ("%p: ReevaluateInputDevice: %s-type AudioCallbackDriver %p is "
- "re-configured to %s-type",
- this,
- GetAudioInputTypeString(
- audioCallbackDriver->InputDevicePreference()),
- audioCallbackDriver,
- GetAudioInputTypeString(AudioInputDevicePreference(aID))));
- needToSwitch = true;
- }
- } else if (Switching() && NextDriver()->AsAudioCallbackDriver()) {
- // We're already in the process of switching to a audio callback driver,
- // which will happen at the next iteration.
- // However, maybe it's not the correct number of channels. Re-query the
- // correct channel amount at this time.
+ NonNativeInputTrack* nonNative = track->AsNonNativeInputTrack();
+ MOZ_ASSERT(nonNative);
+ if (nonNative->NumberOfChannels() != AudioInputChannelCount(aID)) {
+ LOG(LogLevel::Debug,
+ ("%p: %u-channel non-native input device %p (track %p) is "
+ "re-configured to %d-channel",
+ this, nonNative->NumberOfChannels(), aID, track,
+ AudioInputChannelCount(aID)));
+ needToSwitch = true;
+ }
+ if (nonNative->DevicePreference() != AudioInputDevicePreference(aID)) {
+ LOG(LogLevel::Debug,
+ ("%p: %s-type non-native input device %p (track %p) is re-configured "
+ "to %s-type",
+ this, GetAudioInputTypeString(nonNative->DevicePreference()), aID,
+ track, GetAudioInputTypeString(AudioInputDevicePreference(aID))));
needToSwitch = true;
}
if (needToSwitch) {
- AudioCallbackDriver* newDriver = new AudioCallbackDriver(
- this, CurrentDriver(), mSampleRate, PrimaryOutputChannelCount(),
- AudioInputChannelCount(aID), PrimaryOutputDeviceID(), aID,
- AudioInputDevicePreference(aID),
- Some(track->UpdateRequestedProcessingParams()));
- SwitchAtNextIteration(newDriver);
+ nonNative->StopAudio();
+ nonNative->StartAudio(MakeRefPtr<AudioInputSource>(
+ MakeRefPtr<AudioInputSourceListener>(nonNative),
+ nonNative->GenerateSourceId(), aID, AudioInputChannelCount(aID),
+ AudioInputDevicePreference(aID) == AudioInputType::Voice,
+ nonNative->mPrincipalHandle, nonNative->mSampleRate, GraphRate()));
}
}
diff --git a/dom/media/gtest/TestAudioTrackGraph.cpp b/dom/media/gtest/TestAudioTrackGraph.cpp
@@ -2960,6 +2960,8 @@ TEST(TestAudioTrackGraph, PlatformProcessing)
// Switch driver.
EXPECT_CALL(*listener, RequestedInputChannelCount).WillRepeatedly(Return(2));
+ // ReevaluateInputDevice() is not required for the native input, but is
+ // called anyway.
DispatchFunction([&] {
track->QueueControlMessageWithNoShutdown(
[&] { graph->ReevaluateInputDevice(device); });