tor-browser

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

commit 1c2b6611749e93687e0fdf03b58ed5acc81ad7ad
parent 8487ac8adf09e14bfbe7d26a93590464ac505402
Author: Andrew Osmond <aosmond@gmail.com>
Date:   Wed, 10 Dec 2025 15:57:39 +0000

Bug 2005092 - Wait for RemoteMediaDataEncoderChild::Construct to resolve before handling Init. r=media-playback-reviewers,karlt

Init cannot be handled before Construct has completed. For synchronously
created encoders, Init may get called first, but in that case, we just
need to cache the request until we resolve a promise from Construct.
This race is possible because we defer Construct until the encoding
process promise resolves (it may still be launching). Simply checking
the promise like we did before was insufficient because the Init call
might win the race against the process launch as well.

This patch makes it so that we never send the Init message until the
response has been received for the Construct message.

Differential Revision: https://phabricator.services.mozilla.com/D275700

Diffstat:
Mdom/media/ipc/PRemoteEncoder.ipdl | 2++
Mdom/media/ipc/RemoteMediaDataEncoderChild.cpp | 9++++++++-
Mdom/media/ipc/RemoteMediaDataEncoderChild.h | 1+
3 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/dom/media/ipc/PRemoteEncoder.ipdl b/dom/media/ipc/PRemoteEncoder.ipdl @@ -60,8 +60,10 @@ async protocol PRemoteEncoder { manager PRemoteMediaManager; parent: + // Construct must be the first message sent. async Construct() returns (MediaResult result); + // Init must only be called after Construct has returned successfully. async Init() returns (EncodeInitResultIPDL result); async Encode(EncodedInputIPDL data) returns (EncodeResultIPDL result); diff --git a/dom/media/ipc/RemoteMediaDataEncoderChild.cpp b/dom/media/ipc/RemoteMediaDataEncoderChild.cpp @@ -83,6 +83,7 @@ RemoteMediaDataEncoderChild::Construct() { [self = RefPtr{this}](MediaResult aResult) { LOGD("[{}] Construct resolved code={}", fmt::ptr(self.get()), aResult.Description()); + self->mHasConstructed = true; self->mConstructPromise.Resolve(self, __func__); if (!self->mInitPromise.IsEmpty()) { self->DoSendInit(); @@ -101,6 +102,8 @@ RemoteMediaDataEncoderChild::Construct() { } void RemoteMediaDataEncoderChild::DoSendInit() { + MOZ_ASSERT(mHasConstructed); + LOGD("[{}] Init send", fmt::ptr(this)); SendInit()->Then( mThread, __func__, @@ -143,7 +146,11 @@ RefPtr<MediaDataEncoder::InitPromise> RemoteMediaDataEncoderChild::Init() { // create promise and wait for that first. This can happen if the owner // created the encoder via RemoteEncoderModule's CreateAudioEncoder or // CreateVideoEncoder instead of AsyncCreateEncoder. - if (self->mConstructPromise.IsEmpty()) { + // + // mConstructPromise might not have been created yet either because we + // may have delayed dispatching related to the process launching. + // mHasConstructed will be set when the construct IPDL call returns. + if (self->mHasConstructed) { self->DoSendInit(); } else { LOGD("[{}] Init deferred, still constructing", fmt::ptr(self.get())); diff --git a/dom/media/ipc/RemoteMediaDataEncoderChild.h b/dom/media/ipc/RemoteMediaDataEncoderChild.h @@ -67,6 +67,7 @@ class RemoteMediaDataEncoderChild final const nsCOMPtr<nsISerialEventTarget> mThread; const RemoteMediaIn mLocation; bool mRemoteCrashed = false; + bool mHasConstructed = false; MozPromiseHolder<PlatformEncoderModule::CreateEncoderPromise> mConstructPromise;