commit da6e8cb19129649b5ff85c2b59d798bdaeb20f85 parent 1346bd8346bccbccc64e48d89aeade48d27b9e2f Author: Jan-Ivar Bruaroey <jib@mozilla.com> Date: Wed, 8 Oct 2025 22:41:32 +0000 Bug 1975032 - Implement RTCEncodedVideoFrame and RTCEncodedAudioFrame copy constructors. r=bwc,webidl,smaug Differential Revision: https://phabricator.services.mozilla.com/D267706 Diffstat:
15 files changed, 95 insertions(+), 66 deletions(-)
diff --git a/dom/media/webrtc/jsapi/RTCEncodedAudioFrame.cpp b/dom/media/webrtc/jsapi/RTCEncodedAudioFrame.cpp @@ -104,6 +104,33 @@ JSObject* RTCEncodedAudioFrame::WrapObject(JSContext* aCx, return RTCEncodedAudioFrame_Binding::Wrap(aCx, this, aGivenProto); } +// https://w3c.github.io/webrtc-encoded-transform/#RTCEncodedAudioFrame-constructor +/* static */ +already_AddRefed<RTCEncodedAudioFrame> RTCEncodedAudioFrame::Constructor( + const GlobalObject& aGlobal, const RTCEncodedAudioFrame& aOriginalFrame, + const RTCEncodedAudioFrameOptions& aOptions, ErrorResult& aRv) { + nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports()); + if (!global) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + auto frame = MakeRefPtr<RTCEncodedAudioFrame>(global, aOriginalFrame.Clone()); + + if (aOptions.mMetadata.WasPassed()) { + const auto& src = aOptions.mMetadata.Value(); + auto& dst = frame->mMetadata; + + auto set_if = [](auto& dst, const auto& src) { + if (src.WasPassed()) dst.Value() = src.Value(); + }; + set_if(dst.mSynchronizationSource, src.mSynchronizationSource); + set_if(dst.mPayloadType, src.mPayloadType); + set_if(dst.mContributingSources, src.mContributingSources); + set_if(dst.mSequenceNumber, src.mSequenceNumber); + } + return frame.forget(); +} + RTCEncodedAudioFrameData RTCEncodedAudioFrameData::Clone() const { return RTCEncodedAudioFrameData{ {webrtc::CloneAudioFrame( diff --git a/dom/media/webrtc/jsapi/RTCEncodedAudioFrame.h b/dom/media/webrtc/jsapi/RTCEncodedAudioFrame.h @@ -15,6 +15,7 @@ namespace mozilla::dom { class StructuredCloneHolder; +struct RTCEncodedAudioFrameOptions; struct RTCEncodedAudioFrameData : RTCEncodedFrameState { RTCEncodedAudioFrameMetadata mMetadata; @@ -46,6 +47,10 @@ class RTCEncodedAudioFrame final : public RTCEncodedAudioFrameData, JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; + static already_AddRefed<RTCEncodedAudioFrame> Constructor( + const GlobalObject& aGlobal, const RTCEncodedAudioFrame& aOriginalFrame, + const RTCEncodedAudioFrameOptions& aOptions, ErrorResult& aRv); + nsIGlobalObject* GetParentObject() const; void GetMetadata(RTCEncodedAudioFrameMetadata& aMetadata) const; diff --git a/dom/media/webrtc/jsapi/RTCEncodedVideoFrame.cpp b/dom/media/webrtc/jsapi/RTCEncodedVideoFrame.cpp @@ -131,6 +131,39 @@ JSObject* RTCEncodedVideoFrame::WrapObject(JSContext* aCx, return RTCEncodedVideoFrame_Binding::Wrap(aCx, this, aGivenProto); } +// https://w3c.github.io/webrtc-encoded-transform/#RTCEncodedVideoFrame-constructor +/* static */ +already_AddRefed<RTCEncodedVideoFrame> RTCEncodedVideoFrame::Constructor( + const GlobalObject& aGlobal, const RTCEncodedVideoFrame& aOriginalFrame, + const RTCEncodedVideoFrameOptions& aOptions, ErrorResult& aRv) { + nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports()); + if (!global) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + auto frame = MakeRefPtr<RTCEncodedVideoFrame>(global, aOriginalFrame.Clone()); + + if (aOptions.mMetadata.WasPassed()) { + const auto& src = aOptions.mMetadata.Value(); + auto& dst = frame->mMetadata; + + auto set_if = [](auto& dst, const auto& src) { + if (src.WasPassed()) dst.Value() = src.Value(); + }; + set_if(dst.mFrameId, src.mFrameId); + set_if(dst.mDependencies, src.mDependencies); + set_if(dst.mWidth, src.mWidth); + set_if(dst.mHeight, src.mHeight); + set_if(dst.mSpatialIndex, src.mSpatialIndex); + set_if(dst.mTemporalIndex, src.mTemporalIndex); + set_if(dst.mSynchronizationSource, src.mSynchronizationSource); + set_if(dst.mPayloadType, src.mPayloadType); + set_if(dst.mContributingSources, src.mContributingSources); + set_if(dst.mTimestamp, src.mTimestamp); + } + return frame.forget(); +} + RTCEncodedVideoFrameData RTCEncodedVideoFrameData::Clone() const { return RTCEncodedVideoFrameData{ {webrtc::CloneVideoFrame( diff --git a/dom/media/webrtc/jsapi/RTCEncodedVideoFrame.h b/dom/media/webrtc/jsapi/RTCEncodedVideoFrame.h @@ -16,6 +16,7 @@ namespace mozilla::dom { class RTCRtpScriptTransformer; class StructuredCloneHolder; +struct RTCEncodedVideoFrameOptions; struct RTCEncodedVideoFrameData : RTCEncodedFrameState { RTCEncodedVideoFrameType mType; @@ -49,6 +50,10 @@ class RTCEncodedVideoFrame final : public RTCEncodedVideoFrameData, JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; + static already_AddRefed<RTCEncodedVideoFrame> Constructor( + const GlobalObject& aGlobal, const RTCEncodedVideoFrame& aOriginalFrame, + const RTCEncodedVideoFrameOptions& aOptions, ErrorResult& aRv); + nsIGlobalObject* GetParentObject() const; RTCEncodedVideoFrameType Type() const; diff --git a/dom/webidl/RTCEncodedAudioFrame.webidl b/dom/webidl/RTCEncodedAudioFrame.webidl @@ -14,12 +14,18 @@ dictionary RTCEncodedAudioFrameMetadata { short sequenceNumber; }; +dictionary RTCEncodedAudioFrameOptions { + RTCEncodedAudioFrameMetadata metadata; +}; + // [Serializable] is implemented without adding attribute here, // because we don't implement "full serialization" to disk. [Pref="media.peerconnection.enabled", Pref="media.peerconnection.scripttransform.enabled", Exposed=(Window,DedicatedWorker)] interface RTCEncodedAudioFrame { + [Throws] + constructor(RTCEncodedAudioFrame originalFrame, optional RTCEncodedAudioFrameOptions options = {}); readonly attribute unsigned long timestamp; attribute ArrayBuffer data; RTCEncodedAudioFrameMetadata getMetadata(); diff --git a/dom/webidl/RTCEncodedVideoFrame.webidl b/dom/webidl/RTCEncodedVideoFrame.webidl @@ -28,6 +28,10 @@ dictionary RTCEncodedVideoFrameMetadata { long long timestamp; // microseconds }; +dictionary RTCEncodedVideoFrameOptions { + RTCEncodedVideoFrameMetadata metadata; +}; + // New interfaces to define encoded video and audio frames. Will eventually // re-use or extend the equivalent defined in WebCodecs. // @@ -37,6 +41,8 @@ dictionary RTCEncodedVideoFrameMetadata { Pref="media.peerconnection.scripttransform.enabled", Exposed=(Window,DedicatedWorker)] interface RTCEncodedVideoFrame { + [Throws] + constructor(RTCEncodedVideoFrame originalFrame, optional RTCEncodedVideoFrameOptions options = {}); readonly attribute RTCEncodedVideoFrameType type; readonly attribute unsigned long timestamp; attribute ArrayBuffer data; diff --git a/testing/web-platform/meta/webrtc-encoded-transform/RTCRtpScriptTransform-bad-chunk.https.html.ini b/testing/web-platform/meta/webrtc-encoded-transform/RTCRtpScriptTransform-bad-chunk.https.html.ini @@ -1,3 +0,0 @@ -[RTCRtpScriptTransform-bad-chunk.https.html] - expected: - if (os == "mac") and debug: TIMEOUT diff --git a/testing/web-platform/meta/webrtc-encoded-transform/idlharness.https.window.js.ini b/testing/web-platform/meta/webrtc-encoded-transform/idlharness.https.window.js.ini @@ -82,21 +82,10 @@ bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1631263 expected: FAIL - [RTCEncodedVideoFrame interface object length] - expected: FAIL - - [RTCEncodedAudioFrame interface object length] - expected: FAIL - [idlharness.https.window.html?exclude=SFrameTransform.*] expected: if not sessionHistoryInParent and not debug: [OK, TIMEOUT] - [RTCEncodedVideoFrame interface object length] - expected: FAIL - - [RTCEncodedAudioFrame interface object length] - expected: FAIL [idlharness.https.window.html?include=SFrameTransform.*] diff --git a/testing/web-platform/meta/webrtc-encoded-transform/script-change-transform.https.html.ini b/testing/web-platform/meta/webrtc-encoded-transform/script-change-transform.https.html.ini @@ -1,11 +0,0 @@ -[script-change-transform.https.html] - bug: 1709960 - expected: - if (os == "win") and not debug and (processor == "x86"): [OK, TIMEOUT] - if (os == "android") and debug and sessionHistoryInParent: [OK, TIMEOUT] - if (os == "android") and not debug and not sessionHistoryInParent: [OK, TIMEOUT] - if (os == "linux") and not debug: [OK, CRASH] - [change sender transform] - bug: 1709960 - expected: - if (processor == "x86") and not debug: [PASS, TIMEOUT] diff --git a/testing/web-platform/meta/webrtc-encoded-transform/tentative/RTCEncodedAudioFrame-constructor.html.ini b/testing/web-platform/meta/webrtc-encoded-transform/tentative/RTCEncodedAudioFrame-constructor.html.ini @@ -1,15 +1,21 @@ [RTCEncodedAudioFrame-constructor.html] expected: if (os == "linux") and debug and fission: [TIMEOUT, ERROR] - TIMEOUT + if (os == "mac") and debug: [OK, TIMEOUT] [Constructing a new receiver audio frame explicitly using metadata from a previous frame works] - expected: TIMEOUT + expected: + if (os == "mac") and debug: [PASS, TIMEOUT] [Constructing a new sender audio frame explicitly using metadata from a previous frame works] - expected: NOTRUN + expected: + if (os == "mac") and debug: [PASS, NOTRUN] [Constructing a new receiver audio frame explicitly using metadata from a previous frame works, absCaptureTime extension enabled] - expected: NOTRUN + expected: + if (os == "mac") and debug: [FAIL, NOTRUN] + FAIL [Constructing a new sender audio frame explicitly using metadata from a previous frame works, absCaptureTime extension enabled] - expected: NOTRUN + expected: + if (os == "mac") and debug: [FAIL, NOTRUN] + FAIL diff --git a/testing/web-platform/meta/webrtc-encoded-transform/tentative/RTCEncodedAudioFrame-receive-cloned.https.html.ini b/testing/web-platform/meta/webrtc-encoded-transform/tentative/RTCEncodedAudioFrame-receive-cloned.https.html.ini @@ -1,5 +1,3 @@ [RTCEncodedAudioFrame-receive-cloned.https.html] - expected: - if (os == "mac") and debug: TIMEOUT [Cloning before sending works] expected: FAIL diff --git a/testing/web-platform/meta/webrtc-encoded-transform/tentative/RTCEncodedAudioFrame-serviceworker-failure.https.html.ini b/testing/web-platform/meta/webrtc-encoded-transform/tentative/RTCEncodedAudioFrame-serviceworker-failure.https.html.ini @@ -1,5 +1,3 @@ [RTCEncodedAudioFrame-serviceworker-failure.https.html] - expected: - if (os == "mac") and debug: TIMEOUT [RTCEncodedVideoFrame cannot cross agent clusters, service worker edition] expected: FAIL diff --git a/testing/web-platform/meta/webrtc-encoded-transform/tentative/RTCEncodedFrame-timestamps.html.ini b/testing/web-platform/meta/webrtc-encoded-transform/tentative/RTCEncodedFrame-timestamps.html.ini @@ -1,28 +1,7 @@ [RTCEncodedFrame-timestamps.html] - bug: 1709960 - expected: - if (os == "win") and debug and (processor == "x86_64"): [OK, TIMEOUT] - if (os == "win") and not debug and (processor == "x86"): [OK, TIMEOUT] - if (os == "mac") and debug: TIMEOUT - if (os == "mac") and not debug: [OK, TIMEOUT] [captureTime and senderCaptureTimeOffset present in audio receiver if extension is used] expected: FAIL [captureTime and senderCaptureTimeOffset present in video receiver if extension is used] expected: - if (os == "win") and debug and (processor == "x86_64"): [FAIL, NOTRUN] - if (os == "win") and not debug and (processor == "x86"): [FAIL, NOTRUN] - if os == "mac": [FAIL, NOTRUN] FAIL - - [captureTime and senderCaptureTimeOffset not present in video receiver if extension not used] - expected: - if (os == "win") and debug and (processor == "x86_64"): [PASS, NOTRUN] - if (os == "win") and not debug and (processor == "x86"): [PASS, NOTRUN] - if os == "mac": [PASS, NOTRUN] - - [captureTime and senderCaptureTimeOffset not present in audio receiver if extension not used] - expected: - if (os == "win") and debug and (processor == "x86_64"): [PASS, TIMEOUT] - if (os == "win") and not debug and (processor == "x86"): [PASS, TIMEOUT] - if os == "mac": [PASS, TIMEOUT] diff --git a/testing/web-platform/meta/webrtc-encoded-transform/tentative/RTCEncodedVideoFrame-clone.https.html.ini b/testing/web-platform/meta/webrtc-encoded-transform/tentative/RTCEncodedVideoFrame-clone.https.html.ini @@ -1,5 +1,3 @@ [RTCEncodedVideoFrame-clone.https.html] - expected: - if (os == "mac") and debug: TIMEOUT [Cloning before sending works] expected: FAIL diff --git a/testing/web-platform/meta/webrtc-encoded-transform/tentative/RTCEncodedVideoFrame-constructor.html.ini b/testing/web-platform/meta/webrtc-encoded-transform/tentative/RTCEncodedVideoFrame-constructor.html.ini @@ -1,13 +1,6 @@ [RTCEncodedVideoFrame-constructor.html] - expected: TIMEOUT - [Constructing a new receiver audio frame explicitly using metadata from an existing frame works] - expected: TIMEOUT - - [Constructing a new sender audio frame explicitly using metadata from an existing frame works] - expected: NOTRUN - [Constructing a new receiver audio frame explicitly using metadata from an existing frame works, absCaptureTime extension enabled] - expected: NOTRUN + expected: FAIL [Constructing a new sender audio frame explicitly using metadata from an existing frame works, absCaptureTime extension enabled] - expected: NOTRUN + expected: FAIL