1111#include < memory>
1212#include < utility>
1313
14+ #include " api/frame_transformer_factory.h"
1415#include " api/frame_transformer_interface.h"
1516#include " js/RootingAPI.h"
1617#include " jsapi/RTCEncodedFrameBase.h"
2021#include " mozilla/Unused.h"
2122#include " mozilla/dom/RTCEncodedAudioFrameBinding.h"
2223#include " mozilla/dom/RTCRtpScriptTransformer.h"
24+ #include " mozilla/dom/StructuredCloneHolder.h"
25+ #include " mozilla/dom/StructuredCloneTags.h"
2326#include " mozilla/fallible.h"
2427#include " nsContentUtils.h"
2528#include " nsCycleCollectionParticipant.h"
2932
3033namespace mozilla ::dom {
3134
32- NS_IMPL_CYCLE_COLLECTION_INHERITED (RTCEncodedAudioFrame, RTCEncodedFrameBase,
33- mOwner )
35+ NS_IMPL_CYCLE_COLLECTION_CLASS (RTCEncodedAudioFrame)
36+ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED (RTCEncodedAudioFrame,
37+ RTCEncodedFrameBase)
38+ NS_IMPL_CYCLE_COLLECTION_UNLINK (mOwner )
39+ NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
40+ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
41+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED (RTCEncodedAudioFrame,
42+ RTCEncodedFrameBase)
43+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE (mOwner )
44+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
45+ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED (RTCEncodedAudioFrame,
46+ RTCEncodedFrameBase)
47+ NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
48+ NS_IMPL_CYCLE_COLLECTION_TRACE_END
3449NS_IMPL_ADDREF_INHERITED (RTCEncodedAudioFrame, RTCEncodedFrameBase)
3550NS_IMPL_RELEASE_INHERITED (RTCEncodedAudioFrame, RTCEncodedFrameBase)
3651
@@ -48,7 +63,7 @@ RTCEncodedAudioFrame::RTCEncodedAudioFrame(
4863 mMetadata .mSynchronizationSource .Construct (mFrame ->GetSsrc ());
4964 mMetadata .mPayloadType .Construct (mFrame ->GetPayloadType ());
5065 const auto & audioFrame (
51- static_cast <webrtc::TransformableAudioFrameInterface&>(*mState . mFrame ));
66+ static_cast <webrtc::TransformableAudioFrameInterface&>(*mFrame ));
5267 mMetadata .mContributingSources .Construct ();
5368 for (const auto csrc : audioFrame.GetContributingSources ()) {
5469 Unused << mMetadata .mContributingSources .Value ().AppendElement (csrc,
@@ -63,7 +78,22 @@ RTCEncodedAudioFrame::RTCEncodedAudioFrame(
6378 mozilla::HoldJSObjects (this );
6479}
6580
81+ RTCEncodedAudioFrame::RTCEncodedAudioFrame (nsIGlobalObject* aGlobal,
82+ RTCEncodedAudioFrameData&& aData)
83+ : RTCEncodedAudioFrameData{{std::move (aData.mFrame ), aData.mCounter ,
84+ aData.mTimestamp },
85+ std::move (aData.mMetadata )},
86+ RTCEncodedFrameBase (aGlobal, static_cast <RTCEncodedFrameState&>(*this )),
87+ mOwner (nullptr ) {
88+ // Base class needs this, but can't do it itself because of an assertion in
89+ // the cycle-collector.
90+ mozilla::HoldJSObjects (this );
91+ }
92+
6693RTCEncodedAudioFrame::~RTCEncodedAudioFrame () {
94+ // Clear JS::Heap<> members before unregistering as a script holder,
95+ // so their destructors don't barrier against a finalized JS object.
96+ mData = nullptr ; // from RTCEncodedFrameBase (protected)
6797 // Base class needs this, but can't do it itself because of an assertion in
6898 // the cycle-collector.
6999 mozilla::DropJSObjects (this );
@@ -74,6 +104,14 @@ JSObject* RTCEncodedAudioFrame::WrapObject(JSContext* aCx,
74104 return RTCEncodedAudioFrame_Binding::Wrap (aCx, this , aGivenProto);
75105}
76106
107+ RTCEncodedAudioFrameData RTCEncodedAudioFrameData::Clone () const {
108+ return RTCEncodedAudioFrameData{
109+ {webrtc::CloneAudioFrame (
110+ static_cast <webrtc::TransformableAudioFrameInterface*>(
111+ mFrame .get ()))},
112+ RTCEncodedAudioFrameMetadata (mMetadata )};
113+ }
114+
77115nsIGlobalObject* RTCEncodedAudioFrame::GetParentObject () const {
78116 return mGlobal ;
79117}
@@ -89,17 +127,40 @@ bool RTCEncodedAudioFrame::CheckOwner(RTCRtpScriptTransformer* aOwner) const {
89127
90128// https://www.w3.org/TR/webrtc-encoded-transform/#RTCEncodedAudioFrame-serialization
91129/* static */
92- already_AddRefed<RTCEncodedAudioFrame>
93- RTCEncodedAudioFrame::ReadStructuredClone (JSContext* aCx,
94- nsIGlobalObject* aGlobal,
95- JSStructuredCloneReader* aReader) {
96- // TBD implementation to follow in followup patch
97- return nullptr ;
130+ JSObject* RTCEncodedAudioFrame::ReadStructuredClone (
131+ JSContext* aCx, nsIGlobalObject* aGlobal, JSStructuredCloneReader* aReader,
132+ RTCEncodedAudioFrameData& aData) {
133+ JS::Rooted<JS::Value> value (aCx, JS::NullValue ());
134+ // To avoid a rooting hazard error from returning a raw JSObject* before
135+ // running the RefPtr destructor, RefPtr needs to be destructed before
136+ // returning the raw JSObject*, which is why the RefPtr<RTCEncodedAudioFrame>
137+ // is created in the scope below. Otherwise, the static analysis infers the
138+ // RefPtr cannot be safely destructed while the unrooted return JSObject* is
139+ // on the stack.
140+ {
141+ auto frame = MakeRefPtr<RTCEncodedAudioFrame>(aGlobal, std::move (aData));
142+ if (!GetOrCreateDOMReflector (aCx, frame, &value) || !value.isObject ()) {
143+ return nullptr ;
144+ }
145+ }
146+ return value.toObjectOrNull ();
98147}
99148
100149bool RTCEncodedAudioFrame::WriteStructuredClone (
101- JSContext* aCx, JSStructuredCloneWriter* aWriter) const {
102- return false ;
150+ JSStructuredCloneWriter* aWriter, StructuredCloneHolder* aHolder) const {
151+ AssertIsOnOwningThread ();
152+
153+ // Indexing the chunk and send the index to the receiver.
154+ const uint32_t index =
155+ static_cast <uint32_t >(aHolder->RtcEncodedAudioFrames ().Length ());
156+ // The serialization is limited to the same process scope so it's ok to
157+ // hand over a (copy of a) webrtc internal object here.
158+ //
159+ // TODO: optimize later once encoded source API materializes
160+ // .AppendElement(aHolder->IsTransferred(mData) ? Take() : Clone())
161+ aHolder->RtcEncodedAudioFrames ().AppendElement (Clone ());
162+ return !NS_WARN_IF(
163+ !JS_WriteUint32Pair (aWriter, SCTAG_DOM_RTCENCODEDAUDIOFRAME, index));
103164}
104165
105166} // namespace mozilla::dom
0 commit comments