tor-browser

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

RTCEncodedAudioFrame.cpp (7950B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
      6 
      7 #include "jsapi/RTCEncodedAudioFrame.h"
      8 
      9 #include <stdint.h>
     10 
     11 #include <memory>
     12 #include <utility>
     13 
     14 #include "api/frame_transformer_factory.h"
     15 #include "api/frame_transformer_interface.h"
     16 #include "js/RootingAPI.h"
     17 #include "jsapi/RTCEncodedFrameBase.h"
     18 #include "jsapi/RTCRtpScriptTransform.h"
     19 #include "mozilla/HoldDropJSObjects.h"
     20 #include "mozilla/RefPtr.h"
     21 #include "mozilla/dom/RTCEncodedAudioFrameBinding.h"
     22 #include "mozilla/dom/RTCRtpScriptTransformer.h"
     23 #include "mozilla/dom/StructuredCloneHolder.h"
     24 #include "mozilla/dom/StructuredCloneTags.h"
     25 #include "mozilla/fallible.h"
     26 #include "nsContentUtils.h"
     27 #include "nsCycleCollectionParticipant.h"
     28 #include "nsIGlobalObject.h"
     29 #include "nsISupports.h"
     30 #include "nsWrapperCache.h"
     31 
     32 namespace mozilla::dom {
     33 
     34 NS_IMPL_CYCLE_COLLECTION_CLASS(RTCEncodedAudioFrame)
     35 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(RTCEncodedAudioFrame,
     36                                                RTCEncodedFrameBase)
     37  NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
     38  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
     39 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     40 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(RTCEncodedAudioFrame,
     41                                                  RTCEncodedFrameBase)
     42  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
     43 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     44 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(RTCEncodedAudioFrame,
     45                                               RTCEncodedFrameBase)
     46  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
     47 NS_IMPL_CYCLE_COLLECTION_TRACE_END
     48 NS_IMPL_ADDREF_INHERITED(RTCEncodedAudioFrame, RTCEncodedFrameBase)
     49 NS_IMPL_RELEASE_INHERITED(RTCEncodedAudioFrame, RTCEncodedFrameBase)
     50 
     51 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(RTCEncodedAudioFrame)
     52  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     53 NS_INTERFACE_MAP_END_INHERITING(RTCEncodedFrameBase)
     54 
     55 RTCEncodedAudioFrame::RTCEncodedAudioFrame(
     56    nsIGlobalObject* aGlobal,
     57    std::unique_ptr<webrtc::TransformableFrameInterface> aFrame,
     58    uint64_t aCounter, RTCRtpScriptTransformer* aOwner)
     59    : RTCEncodedAudioFrameData{RTCEncodedFrameState{std::move(aFrame), aCounter,
     60                                                    /*timestamp*/ 0}},
     61      RTCEncodedFrameBase(aGlobal, static_cast<RTCEncodedFrameState&>(*this)),
     62      mOwner(aOwner) {
     63  mMetadata.mSynchronizationSource.Construct(mFrame->GetSsrc());
     64  mMetadata.mPayloadType.Construct(mFrame->GetPayloadType());
     65  const auto& audioFrame(
     66      static_cast<webrtc::TransformableAudioFrameInterface&>(*mFrame));
     67  mMetadata.mContributingSources.Construct();
     68  for (const auto csrc : audioFrame.GetContributingSources()) {
     69    (void)mMetadata.mContributingSources.Value().AppendElement(csrc, fallible);
     70  }
     71  if (const auto optionalSeqNum = audioFrame.SequenceNumber()) {
     72    mMetadata.mSequenceNumber.Construct(*optionalSeqNum);
     73  }
     74 
     75  // Base class needs this, but can't do it itself because of an assertion in
     76  // the cycle-collector.
     77  mozilla::HoldJSObjects(this);
     78 }
     79 
     80 RTCEncodedAudioFrame::RTCEncodedAudioFrame(nsIGlobalObject* aGlobal,
     81                                           RTCEncodedAudioFrameData&& aData)
     82    : RTCEncodedAudioFrameData{RTCEncodedFrameState{std::move(aData.mFrame),
     83                                                    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 
     93 RTCEncodedAudioFrame::~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)
     97  // Base class needs this, but can't do it itself because of an assertion in
     98  // the cycle-collector.
     99  mozilla::DropJSObjects(this);
    100 }
    101 
    102 JSObject* RTCEncodedAudioFrame::WrapObject(JSContext* aCx,
    103                                           JS::Handle<JSObject*> aGivenProto) {
    104  return RTCEncodedAudioFrame_Binding::Wrap(aCx, this, aGivenProto);
    105 }
    106 
    107 // https://w3c.github.io/webrtc-encoded-transform/#RTCEncodedAudioFrame-constructor
    108 /* static */
    109 already_AddRefed<RTCEncodedAudioFrame> RTCEncodedAudioFrame::Constructor(
    110    const GlobalObject& aGlobal, const RTCEncodedAudioFrame& aOriginalFrame,
    111    const RTCEncodedAudioFrameOptions& aOptions, ErrorResult& aRv) {
    112  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
    113  if (!global) {
    114    aRv.Throw(NS_ERROR_FAILURE);
    115    return nullptr;
    116  }
    117  auto frame = MakeRefPtr<RTCEncodedAudioFrame>(global, aOriginalFrame.Clone());
    118 
    119  if (aOptions.mMetadata.WasPassed()) {
    120    const auto& src = aOptions.mMetadata.Value();
    121    auto& dst = frame->mMetadata;
    122 
    123    auto set_if = [](auto& dst, const auto& src) {
    124      if (src.WasPassed()) dst.Value() = src.Value();
    125    };
    126    set_if(dst.mSynchronizationSource, src.mSynchronizationSource);
    127    set_if(dst.mPayloadType, src.mPayloadType);
    128    set_if(dst.mContributingSources, src.mContributingSources);
    129    set_if(dst.mSequenceNumber, src.mSequenceNumber);
    130  }
    131  return frame.forget();
    132 }
    133 
    134 RTCEncodedAudioFrameData RTCEncodedAudioFrameData::Clone() const {
    135  return RTCEncodedAudioFrameData{
    136      RTCEncodedFrameState{webrtc::CloneAudioFrame(
    137          static_cast<webrtc::TransformableAudioFrameInterface*>(
    138              mFrame.get()))},
    139      RTCEncodedAudioFrameMetadata(mMetadata)};
    140 }
    141 
    142 nsIGlobalObject* RTCEncodedAudioFrame::GetParentObject() const {
    143  return mGlobal;
    144 }
    145 
    146 void RTCEncodedAudioFrame::GetMetadata(
    147    RTCEncodedAudioFrameMetadata& aMetadata) const {
    148  aMetadata = mMetadata;
    149 }
    150 
    151 bool RTCEncodedAudioFrame::CheckOwner(RTCRtpScriptTransformer* aOwner) const {
    152  return aOwner == mOwner;
    153 }
    154 
    155 // https://www.w3.org/TR/webrtc-encoded-transform/#RTCEncodedAudioFrame-serialization
    156 /* static */
    157 JSObject* RTCEncodedAudioFrame::ReadStructuredClone(
    158    JSContext* aCx, nsIGlobalObject* aGlobal, JSStructuredCloneReader* aReader,
    159    RTCEncodedAudioFrameData& aData) {
    160  JS::Rooted<JS::Value> value(aCx, JS::NullValue());
    161  // To avoid a rooting hazard error from returning a raw JSObject* before
    162  // running the RefPtr destructor, RefPtr needs to be destructed before
    163  // returning the raw JSObject*, which is why the RefPtr<RTCEncodedAudioFrame>
    164  // is created in the scope below. Otherwise, the static analysis infers the
    165  // RefPtr cannot be safely destructed while the unrooted return JSObject* is
    166  // on the stack.
    167  {
    168    auto frame = MakeRefPtr<RTCEncodedAudioFrame>(aGlobal, std::move(aData));
    169    if (!GetOrCreateDOMReflector(aCx, frame, &value) || !value.isObject()) {
    170      return nullptr;
    171    }
    172  }
    173  return value.toObjectOrNull();
    174 }
    175 
    176 bool RTCEncodedAudioFrame::WriteStructuredClone(
    177    JSStructuredCloneWriter* aWriter, StructuredCloneHolder* aHolder) const {
    178  AssertIsOnOwningThread();
    179 
    180  // Indexing the chunk and send the index to the receiver.
    181  const uint32_t index =
    182      static_cast<uint32_t>(aHolder->RtcEncodedAudioFrames().Length());
    183  // The serialization is limited to the same process scope so it's ok to
    184  // hand over a (copy of a) webrtc internal object here.
    185  //
    186  // TODO: optimize later once encoded source API materializes
    187  // .AppendElement(aHolder->IsTransferred(mData) ? Take() : Clone())
    188  aHolder->RtcEncodedAudioFrames().AppendElement(Clone());
    189  return !NS_WARN_IF(
    190      !JS_WriteUint32Pair(aWriter, SCTAG_DOM_RTCENCODEDAUDIOFRAME, index));
    191 }
    192 
    193 }  // namespace mozilla::dom