commit 760ee59dea28fcf55dbde503fea440ac0408d805
parent 55ca6273e38657bc692c3a901f7a437847826151
Author: Andreas Pehrson <apehrson@mozilla.com>
Date: Tue, 14 Oct 2025 18:35:41 +0000
Bug 1771789 - Add DeviceState::mAllocated to avoid Stop and Deallocate of non-allocated sources. r=jib
This is needed because MediaEngineSource::Stop/Deallocate are not idempotent,
and cloning allocates async *after* creating DeviceState, unlike getUserMedia.
Differential Revision: https://phabricator.services.mozilla.com/D266383
Diffstat:
1 file changed, 22 insertions(+), 10 deletions(-)
diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp
@@ -211,6 +211,11 @@ struct DeviceState {
MOZ_ASSERT(mTrackSource);
}
+ // true if we have allocated mDevice. When not allocated, we may not stop or
+ // deallocate.
+ // MainThread only.
+ bool mAllocated = false;
+
// true if we have stopped mDevice, this is a terminal state.
// MainThread only.
bool mStopped = false;
@@ -390,7 +395,8 @@ class DeviceListener : public SupportsWeakPtr {
* Marks this listener as active and creates the internal device state.
*/
void Activate(RefPtr<LocalMediaDevice> aDevice,
- RefPtr<LocalTrackSource> aTrackSource, bool aStartMuted);
+ RefPtr<LocalTrackSource> aTrackSource, bool aStartMuted,
+ bool aIsAllocated);
/**
* Posts a task to initialize and start the associated device.
@@ -572,7 +578,7 @@ class GetUserMediaWindowListener {
*/
void Activate(RefPtr<DeviceListener> aListener,
RefPtr<LocalMediaDevice> aDevice,
- RefPtr<LocalTrackSource> aTrackSource) {
+ RefPtr<LocalTrackSource> aTrackSource, bool aIsAllocated) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aListener);
MOZ_ASSERT(!aListener->Activated());
@@ -590,7 +596,8 @@ class GetUserMediaWindowListener {
}
mInactiveListeners.RemoveElement(aListener);
- aListener->Activate(std::move(aDevice), std::move(aTrackSource), muted);
+ aListener->Activate(std::move(aDevice), std::move(aTrackSource), muted,
+ aIsAllocated);
mActiveListeners.AppendElement(std::move(aListener));
}
@@ -1775,11 +1782,13 @@ void GetUserMediaStreamTask::PrepareDOMStream() {
// is freed when the page is invalidated (on navigation or close).
if (mAudioDeviceListener) {
mWindowListener->Activate(mAudioDeviceListener, mAudioDevice,
- std::move(audioTrackSource));
+ std::move(audioTrackSource),
+ /*aIsAllocated=*/true);
}
if (mVideoDeviceListener) {
mWindowListener->Activate(mVideoDeviceListener, mVideoDevice,
- std::move(videoTrackSource));
+ std::move(videoTrackSource),
+ /*aIsAllocated=*/true);
}
// Dispatch to the media thread to ask it to start the sources, because that
@@ -4264,7 +4273,7 @@ void DeviceListener::Register(GetUserMediaWindowListener* aListener) {
void DeviceListener::Activate(RefPtr<LocalMediaDevice> aDevice,
RefPtr<LocalTrackSource> aTrackSource,
- bool aStartMuted) {
+ bool aStartMuted, bool aIsAllocated) {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread");
LOG("DeviceListener %p activating %s device %p", this,
@@ -4290,6 +4299,7 @@ void DeviceListener::Activate(RefPtr<LocalMediaDevice> aDevice,
mDeviceState = MakeUnique<DeviceState>(
std::move(aDevice), std::move(aTrackSource), offWhileDisabled);
mDeviceState->mDeviceMuted = aStartMuted;
+ mDeviceState->mAllocated = aIsAllocated;
if (aStartMuted) {
mDeviceState->mTrackSource->Mute();
}
@@ -4404,10 +4414,12 @@ void DeviceListener::Stop() {
mDeviceState->mTrackSource->Stop();
- MediaManager::Dispatch(NewTaskFrom([device = mDeviceState->mDevice]() {
- device->Stop();
- device->Deallocate();
- }));
+ if (mDeviceState->mAllocated) {
+ MediaManager::Dispatch(NewTaskFrom([device = mDeviceState->mDevice]() {
+ device->Stop();
+ device->Deallocate();
+ }));
+ }
mWindowListener->ChromeAffectingStateChanged();
}