tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit e9c93d7376355ef4b3bbee0d846b0ee4e06083c7
parent 69a9ae6a6e4074b4c8417d5f806b3889f70597b8
Author: Andreas Pehrson <apehrson@mozilla.com>
Date:   Thu, 23 Oct 2025 14:11:16 +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:
Mdom/media/MediaManager.cpp | 32++++++++++++++++++++++----------
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(); }