commit 3f5d16c26e27ec58eda51483b368e9519213c911
parent acc5989a8cd4cdd29726fd441e5a3c852ae778ba
Author: Andreas Pehrson <apehrson@mozilla.com>
Date: Thu, 23 Oct 2025 14:11:18 +0000
Bug 1771789 - Deep-clone track sources for correct settings synchronously. r=jib
Differential Revision: https://phabricator.services.mozilla.com/D266386
Diffstat:
10 files changed, 98 insertions(+), 3 deletions(-)
diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp
@@ -1297,6 +1297,8 @@ nsresult LocalMediaDevice::Deallocate() {
already_AddRefed<LocalMediaDevice> LocalMediaDevice::Clone() const {
MOZ_ASSERT(NS_IsMainThread());
auto device = MakeRefPtr<LocalMediaDevice>(mRawDevice, mID, mGroupID, mName);
+ device->mSource =
+ mRawDevice->mEngine->CreateSourceFrom(mSource, device->mRawDevice);
#ifdef MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED
// The source is normally created on the MediaManager thread. But for cloning,
// it ends up being created on main thread. Make sure its owning event target
diff --git a/dom/media/webrtc/MediaEngine.h b/dom/media/webrtc/MediaEngine.h
@@ -50,6 +50,13 @@ class MediaEngine {
virtual RefPtr<MediaEngineSource> CreateSource(
const MediaDevice* aDevice) = 0;
+ /**
+ * Like CreateSource but in addition copies over capabilities and settings
+ * from another source.
+ */
+ virtual RefPtr<MediaEngineSource> CreateSourceFrom(
+ const MediaEngineSource* aSource, const MediaDevice* aDevice) = 0;
+
virtual MediaEventSource<void>& DeviceListChangeEvent() = 0;
/**
* Return true if devices returned from EnumerateDevices are emulated media
diff --git a/dom/media/webrtc/MediaEngineFake.cpp b/dom/media/webrtc/MediaEngineFake.cpp
@@ -86,6 +86,9 @@ class MediaEngineFakeVideoSource : public MediaEngineSource {
public:
MediaEngineFakeVideoSource();
+ static already_AddRefed<MediaEngineFakeVideoSource> CreateFrom(
+ const MediaEngineFakeVideoSource* aSource);
+
static nsString GetGroupId();
nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
@@ -143,6 +146,15 @@ MediaEngineFakeVideoSource::MediaEngineFakeVideoSource()
dom::GetEnumString(dom::VideoResizeModeEnum::None)));
}
+/*static*/ already_AddRefed<MediaEngineFakeVideoSource>
+MediaEngineFakeVideoSource::CreateFrom(
+ const MediaEngineFakeVideoSource* aSource) {
+ auto src = MakeRefPtr<MediaEngineFakeVideoSource>();
+ *static_cast<MediaTrackSettings*>(src->mSettings) = *aSource->mSettings;
+ src->mOpts = aSource->mOpts;
+ return src.forget();
+}
+
nsString MediaEngineFakeVideoSource::GetGroupId() {
return u"Fake Video Group"_ns;
}
@@ -616,4 +628,20 @@ RefPtr<MediaEngineSource> MediaEngineFake::CreateSource(
}
}
+RefPtr<MediaEngineSource> MediaEngineFake::CreateSourceFrom(
+ const MediaEngineSource* aSource, const MediaDevice* aMediaDevice) {
+ MOZ_ASSERT(aMediaDevice->mEngine == this);
+ switch (aMediaDevice->mMediaSource) {
+ case MediaSourceEnum::Camera:
+ return MediaEngineFakeVideoSource::CreateFrom(
+ static_cast<const MediaEngineFakeVideoSource*>(aSource));
+ case MediaSourceEnum::Microphone:
+ // No main thread members that need to be deep cloned.
+ return new MediaEngineFakeAudioSource();
+ default:
+ MOZ_ASSERT_UNREACHABLE("Unsupported source type");
+ return nullptr;
+ }
+}
+
} // namespace mozilla
diff --git a/dom/media/webrtc/MediaEngineFake.h b/dom/media/webrtc/MediaEngineFake.h
@@ -22,6 +22,8 @@ class MediaEngineFake : public MediaEngine {
nsTArray<RefPtr<MediaDevice>>*) override;
void Shutdown() override {}
RefPtr<MediaEngineSource> CreateSource(const MediaDevice* aDevice) override;
+ RefPtr<MediaEngineSource> CreateSourceFrom(
+ const MediaEngineSource* aSource, const MediaDevice* aDevice) override;
MediaEventSource<void>& DeviceListChangeEvent() override {
return mDeviceListChangeEvent;
diff --git a/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp b/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
@@ -203,6 +203,22 @@ MediaEngineRemoteVideoSource::MediaEngineRemoteVideoSource(
}
}
+/*static*/
+already_AddRefed<MediaEngineRemoteVideoSource>
+MediaEngineRemoteVideoSource::CreateFrom(
+ const MediaEngineRemoteVideoSource* aSource,
+ const MediaDevice* aMediaDevice) {
+ auto src = MakeRefPtr<MediaEngineRemoteVideoSource>(aMediaDevice);
+ *static_cast<MediaTrackSettings*>(src->mSettings) = *aSource->mSettings;
+ *static_cast<MediaTrackCapabilities*>(src->mTrackCapabilities) =
+ *aSource->mTrackCapabilities;
+ {
+ MutexAutoLock lock(aSource->mMutex);
+ src->mIncomingImageSize = aSource->mIncomingImageSize;
+ }
+ return src.forget();
+}
+
MediaEngineRemoteVideoSource::~MediaEngineRemoteVideoSource() {
mFirstFramePromiseHolder.RejectIfExists(NS_ERROR_ABORT, __func__);
}
@@ -283,8 +299,8 @@ nsresult MediaEngineRemoteVideoSource::Allocate(
.mCapabilityWidth = cw ? Some(cw) : Nothing(),
.mCapabilityHeight = ch ? Some(ch) : Nothing(),
.mCapEngine = mCapEngine,
- .mInputWidth = cw,
- .mInputHeight = ch,
+ .mInputWidth = cw ? cw : mIncomingImageSize.width,
+ .mInputHeight = ch ? ch : mIncomingImageSize.height,
.mRotation = 0,
};
framerate = input.mCanCropAndScale.valueOr(false)
diff --git a/dom/media/webrtc/MediaEngineRemoteVideoSource.h b/dom/media/webrtc/MediaEngineRemoteVideoSource.h
@@ -88,6 +88,10 @@ class MediaEngineRemoteVideoSource : public MediaEngineSource,
public:
explicit MediaEngineRemoteVideoSource(const MediaDevice* aMediaDevice);
+ static already_AddRefed<MediaEngineRemoteVideoSource> CreateFrom(
+ const MediaEngineRemoteVideoSource* aSource,
+ const MediaDevice* aMediaDevice);
+
// ExternalRenderer
/**
* Signals that the capture stream has ended
@@ -161,7 +165,7 @@ class MediaEngineRemoteVideoSource : public MediaEngineSource,
// mMutex protects certain members on 3 threads:
// MediaManager, Cameras IPC and MediaTrackGraph.
- Mutex mMutex MOZ_UNANNOTATED;
+ mutable Mutex mMutex MOZ_UNANNOTATED;
// Current state of this source.
// Set under mMutex on the owning thread. Accessed under one of the two.
diff --git a/dom/media/webrtc/MediaEngineWebRTC.cpp b/dom/media/webrtc/MediaEngineWebRTC.cpp
@@ -299,6 +299,25 @@ RefPtr<MediaEngineSource> MediaEngineWebRTC::CreateSource(
}
}
+RefPtr<MediaEngineSource> MediaEngineWebRTC::CreateSourceFrom(
+ const MediaEngineSource* aSource, const MediaDevice* aMediaDevice) {
+ MOZ_ASSERT(aMediaDevice->mEngine == this);
+ if (MediaEngineSource::IsVideo(aMediaDevice->mMediaSource)) {
+ return MediaEngineRemoteVideoSource::CreateFrom(
+ static_cast<const MediaEngineRemoteVideoSource*>(aSource),
+ aMediaDevice);
+ }
+ switch (aMediaDevice->mMediaSource) {
+ case MediaSourceEnum::Microphone:
+ return MediaEngineWebRTCMicrophoneSource::CreateFrom(
+ static_cast<const MediaEngineWebRTCMicrophoneSource*>(aSource),
+ aMediaDevice);
+ default:
+ MOZ_CRASH("Unsupported source type");
+ return nullptr;
+ }
+}
+
void MediaEngineWebRTC::Shutdown() {
AssertIsOnOwningThread();
mCameraListChangeListener.DisconnectIfExists();
diff --git a/dom/media/webrtc/MediaEngineWebRTC.h b/dom/media/webrtc/MediaEngineWebRTC.h
@@ -27,6 +27,8 @@ class MediaEngineWebRTC : public MediaEngine {
void EnumerateDevices(dom::MediaSourceEnum, MediaSinkEnum,
nsTArray<RefPtr<MediaDevice>>*) override;
RefPtr<MediaEngineSource> CreateSource(const MediaDevice* aDevice) override;
+ RefPtr<MediaEngineSource> CreateSourceFrom(const MediaEngineSource* aSource,
+ const MediaDevice*) override;
MediaEventSource<void>& DeviceListChangeEvent() override {
return mDeviceListChangeEvent;
diff --git a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
@@ -113,6 +113,17 @@ MediaEngineWebRTCMicrophoneSource::MediaEngineWebRTCMicrophoneSource(
}));
}
+/*static*/ already_AddRefed<MediaEngineWebRTCMicrophoneSource>
+MediaEngineWebRTCMicrophoneSource::CreateFrom(
+ const MediaEngineWebRTCMicrophoneSource* aSource,
+ const MediaDevice* aMediaDevice) {
+ auto src = MakeRefPtr<MediaEngineWebRTCMicrophoneSource>(aMediaDevice);
+ *static_cast<dom::MediaTrackSettings*>(src->mSettings) = *aSource->mSettings;
+ *static_cast<dom::MediaTrackCapabilities*>(src->mCapabilities) =
+ *aSource->mCapabilities;
+ return src.forget();
+}
+
nsresult MediaEngineWebRTCMicrophoneSource::EvaluateSettings(
const NormalizedConstraints& aConstraintsUpdate,
const MediaEnginePrefs& aInPrefs, MediaEnginePrefs* aOutPrefs,
diff --git a/dom/media/webrtc/MediaEngineWebRTCAudio.h b/dom/media/webrtc/MediaEngineWebRTCAudio.h
@@ -34,6 +34,10 @@ class MediaEngineWebRTCMicrophoneSource : public MediaEngineSource {
public:
explicit MediaEngineWebRTCMicrophoneSource(const MediaDevice* aMediaDevice);
+ static already_AddRefed<MediaEngineWebRTCMicrophoneSource> CreateFrom(
+ const MediaEngineWebRTCMicrophoneSource* aSource,
+ const MediaDevice* aMediaDevice);
+
nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
const MediaEnginePrefs& aPrefs, uint64_t aWindowID,
const char** aOutBadConstraint) override;