tor-browser

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

RTCRtpTransceiver.cpp (50869B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "jsapi/RTCRtpTransceiver.h"
      6 
      7 #include <stdint.h>
      8 
      9 #include <algorithm>
     10 #include <set>
     11 #include <string>
     12 #include <tuple>
     13 #include <utility>
     14 #include <vector>
     15 
     16 #include "ErrorList.h"
     17 #include "MainThreadUtils.h"
     18 #include "MediaEventSource.h"
     19 #include "MediaTrackGraph.h"
     20 #include "MediaTransportHandler.h"
     21 #include "PeerConnectionImpl.h"
     22 #include "PrincipalHandle.h"
     23 #include "RTCDTMFSender.h"
     24 #include "RTCDtlsTransport.h"
     25 #include "RTCRtpReceiver.h"
     26 #include "RTCRtpSender.h"
     27 #include "RTCStatsIdGenerator.h"
     28 #include "RTCStatsReport.h"
     29 #include "RemoteTrackSource.h"
     30 #include "api/video_codecs/video_codec.h"
     31 #include "js/RootingAPI.h"
     32 #include "jsep/JsepCodecDescription.h"
     33 #include "jsep/JsepSession.h"
     34 #include "jsep/JsepTrack.h"
     35 #include "jsep/JsepTrackEncoding.h"
     36 #include "libwebrtcglue/AudioConduit.h"
     37 #include "libwebrtcglue/CodecConfig.h"
     38 #include "libwebrtcglue/FrameTransformerProxy.h"
     39 #include "libwebrtcglue/MediaConduitControl.h"
     40 #include "libwebrtcglue/MediaConduitInterface.h"
     41 #include "libwebrtcglue/RtpRtcpConfig.h"
     42 #include "libwebrtcglue/VideoConduit.h"
     43 #include "libwebrtcglue/WebrtcCallWrapper.h"
     44 #include "mozilla/AbstractThread.h"
     45 #include "mozilla/Assertions.h"
     46 #include "mozilla/ErrorResult.h"
     47 #include "mozilla/Maybe.h"
     48 #include "mozilla/MozPromise.h"
     49 #include "mozilla/Preferences.h"
     50 #include "mozilla/RefPtr.h"
     51 #include "mozilla/StateMirroring.h"
     52 #include "mozilla/UniquePtr.h"
     53 #include "mozilla/dom/Nullable.h"
     54 #include "mozilla/dom/Promise.h"
     55 #include "mozilla/dom/RTCRtpReceiverBinding.h"
     56 #include "mozilla/dom/RTCRtpSenderBinding.h"
     57 #include "mozilla/dom/RTCRtpTransceiverBinding.h"
     58 #include "mozilla/dom/RTCStatsReportBinding.h"
     59 #include "mozilla/fallible.h"
     60 #include "mozilla/mozalloc_oom.h"
     61 #include "nsCOMPtr.h"
     62 #include "nsContentUtils.h"
     63 #include "nsCycleCollectionParticipant.h"
     64 #include "nsDebug.h"
     65 #include "nsISerialEventTarget.h"
     66 #include "nsISupports.h"
     67 #include "nsProxyRelease.h"
     68 #include "nsString.h"
     69 #include "nsStringFwd.h"
     70 #include "nsTArray.h"
     71 #include "nsThreadUtils.h"
     72 #include "nsWrapperCache.h"
     73 #include "sdp/SdpAttribute.h"
     74 #include "sdp/SdpEnum.h"
     75 #include "sdp/SdpHelper.h"
     76 #include "sdp/SdpMediaSection.h"
     77 #include "systemservices/MediaUtils.h"
     78 #include "transport/logging.h"
     79 #include "transport/transportlayer.h"
     80 #include "transportbridge/MediaPipeline.h"
     81 #include "utils/PerformanceRecorder.h"
     82 
     83 namespace mozilla {
     84 
     85 using namespace dom;
     86 
     87 namespace {
     88 struct ConduitControlState : public AudioConduitControlInterface,
     89                             public VideoConduitControlInterface {
     90  ConduitControlState(RTCRtpTransceiver* aTransceiver, RTCRtpSender* aSender,
     91                      RTCRtpReceiver* aReceiver)
     92      : mTransceiver(new nsMainThreadPtrHolder<RTCRtpTransceiver>(
     93            "ConduitControlState::mTransceiver", aTransceiver, false)),
     94        mSender(new nsMainThreadPtrHolder<dom::RTCRtpSender>(
     95            "ConduitControlState::mSender", aSender, false)),
     96        mReceiver(new nsMainThreadPtrHolder<dom::RTCRtpReceiver>(
     97            "ConduitControlState::mReceiver", aReceiver, false)) {}
     98 
     99  const nsMainThreadPtrHandle<RTCRtpTransceiver> mTransceiver;
    100  const nsMainThreadPtrHandle<RTCRtpSender> mSender;
    101  const nsMainThreadPtrHandle<RTCRtpReceiver> mReceiver;
    102 
    103  // MediaConduitControlInterface
    104  Canonical<bool>& CanonicalReceiving() override {
    105    return mReceiver->CanonicalReceiving();
    106  }
    107  Canonical<bool>& CanonicalTransmitting() override {
    108    return mSender->CanonicalTransmitting();
    109  }
    110  Canonical<Ssrcs>& CanonicalLocalSsrcs() override {
    111    return mSender->CanonicalSsrcs();
    112  }
    113  Canonical<std::string>& CanonicalLocalCname() override {
    114    return mSender->CanonicalCname();
    115  }
    116  Canonical<std::string>& CanonicalMid() override {
    117    return mTransceiver->CanonicalMid();
    118  }
    119  Canonical<Ssrc>& CanonicalRemoteSsrc() override {
    120    return mReceiver->CanonicalSsrc();
    121  }
    122  Canonical<std::string>& CanonicalSyncGroup() override {
    123    return mTransceiver->CanonicalSyncGroup();
    124  }
    125  Canonical<RtpExtList>& CanonicalLocalRecvRtpExtensions() override {
    126    return mReceiver->CanonicalLocalRtpExtensions();
    127  }
    128  Canonical<RtpExtList>& CanonicalLocalSendRtpExtensions() override {
    129    return mSender->CanonicalLocalRtpExtensions();
    130  }
    131 
    132  // AudioConduitControlInterface
    133  Canonical<Maybe<AudioCodecConfig>>& CanonicalAudioSendCodec() override {
    134    return mSender->CanonicalAudioCodec();
    135  }
    136  Canonical<std::vector<AudioCodecConfig>>& CanonicalAudioRecvCodecs()
    137      override {
    138    return mReceiver->CanonicalAudioCodecs();
    139  }
    140  MediaEventSource<DtmfEvent>& OnDtmfEvent() override {
    141    return mSender->GetDtmf()->OnDtmfEvent();
    142  }
    143 
    144  // VideoConduitControlInterface
    145  Canonical<Ssrcs>& CanonicalLocalVideoRtxSsrcs() override {
    146    return mSender->CanonicalVideoRtxSsrcs();
    147  }
    148  Canonical<Ssrc>& CanonicalRemoteVideoRtxSsrc() override {
    149    return mReceiver->CanonicalVideoRtxSsrc();
    150  }
    151  Canonical<Maybe<VideoCodecConfig>>& CanonicalVideoSendCodec() override {
    152    return mSender->CanonicalVideoCodec();
    153  }
    154  Canonical<Maybe<RtpRtcpConfig>>& CanonicalVideoSendRtpRtcpConfig() override {
    155    return mSender->CanonicalVideoRtpRtcpConfig();
    156  }
    157  Canonical<std::vector<VideoCodecConfig>>& CanonicalVideoRecvCodecs()
    158      override {
    159    return mReceiver->CanonicalVideoCodecs();
    160  }
    161  Canonical<Maybe<RtpRtcpConfig>>& CanonicalVideoRecvRtpRtcpConfig() override {
    162    return mReceiver->CanonicalVideoRtpRtcpConfig();
    163  }
    164  Canonical<webrtc::VideoCodecMode>& CanonicalVideoCodecMode() override {
    165    return mSender->CanonicalVideoCodecMode();
    166  }
    167  Canonical<RefPtr<FrameTransformerProxy>>& CanonicalFrameTransformerProxySend()
    168      override {
    169    return mSender->CanonicalFrameTransformerProxy();
    170  }
    171  Canonical<RefPtr<FrameTransformerProxy>>& CanonicalFrameTransformerProxyRecv()
    172      override {
    173    return mReceiver->CanonicalFrameTransformerProxy();
    174  }
    175  Canonical<webrtc::DegradationPreference>&
    176  CanonicalVideoDegradationPreference() override {
    177    return mSender->CanonicalVideoDegradationPreference();
    178  }
    179 };
    180 }  // namespace
    181 
    182 MOZ_MTLOG_MODULE("RTCRtpTransceiver")
    183 
    184 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(RTCRtpTransceiver)
    185 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(RTCRtpTransceiver)
    186  tmp->Unlink();
    187  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
    188 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    189 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(RTCRtpTransceiver)
    190  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow, mPc, mSendTrack, mReceiver,
    191                                    mSender, mDtlsTransport,
    192                                    mLastStableDtlsTransport)
    193 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    194 
    195 NS_IMPL_CYCLE_COLLECTING_ADDREF(RTCRtpTransceiver)
    196 NS_IMPL_CYCLE_COLLECTING_RELEASE(RTCRtpTransceiver)
    197 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(RTCRtpTransceiver)
    198  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
    199  NS_INTERFACE_MAP_ENTRY(nsISupports)
    200 NS_INTERFACE_MAP_END
    201 
    202 #define INIT_CANONICAL(name, val)         \
    203  name(AbstractThread::MainThread(), val, \
    204       "RTCRtpTransceiver::" #name " (Canonical)")
    205 
    206 RTCRtpTransceiver::RTCRtpTransceiver(
    207    nsPIDOMWindowInner* aWindow, bool aPrivacyNeeded, PeerConnectionImpl* aPc,
    208    MediaTransportHandler* aTransportHandler, JsepSession* aJsepSession,
    209    const std::string& aTransceiverId, bool aIsVideo,
    210    nsISerialEventTarget* aStsThread, dom::MediaStreamTrack* aSendTrack,
    211    WebrtcCallWrapper* aCallWrapper, RTCStatsIdGenerator* aIdGenerator)
    212    : mWindow(aWindow),
    213      mPc(aPc),
    214      mTransportHandler(aTransportHandler),
    215      mTransceiverId(aTransceiverId),
    216      mJsepTransceiver(*aJsepSession->GetTransceiver(mTransceiverId)),
    217      mStsThread(aStsThread),
    218      mCallWrapper(aCallWrapper),
    219      mSendTrack(aSendTrack),
    220      mIdGenerator(aIdGenerator),
    221      mPrincipalPrivacy(aPrivacyNeeded ? PrincipalPrivacy::Private
    222                                       : PrincipalPrivacy::NonPrivate),
    223      mIsVideo(aIsVideo),
    224      INIT_CANONICAL(mMid, std::string()),
    225      INIT_CANONICAL(mSyncGroup, std::string()) {}
    226 
    227 #undef INIT_CANONICAL
    228 
    229 RTCRtpTransceiver::~RTCRtpTransceiver() = default;
    230 
    231 SdpDirectionAttribute::Direction ToSdpDirection(
    232    RTCRtpTransceiverDirection aDirection) {
    233  switch (aDirection) {
    234    case dom::RTCRtpTransceiverDirection::Sendrecv:
    235      return SdpDirectionAttribute::Direction::kSendrecv;
    236    case dom::RTCRtpTransceiverDirection::Sendonly:
    237      return SdpDirectionAttribute::Direction::kSendonly;
    238    case dom::RTCRtpTransceiverDirection::Recvonly:
    239      return SdpDirectionAttribute::Direction::kRecvonly;
    240    case dom::RTCRtpTransceiverDirection::Inactive:
    241    case dom::RTCRtpTransceiverDirection::Stopped:
    242      return SdpDirectionAttribute::Direction::kInactive;
    243  }
    244  MOZ_CRASH("Invalid transceiver direction!");
    245 }
    246 
    247 static uint32_t sRemoteSourceId = 0;
    248 
    249 // TODO(bug 1401592): Once we implement the sendEncodings stuff, there will
    250 // need to be validation code in here.
    251 void RTCRtpTransceiver::Init(const RTCRtpTransceiverInit& aInit,
    252                             ErrorResult& aRv) {
    253  TrackingId trackingId(TrackingId::Source::RTCRtpReceiver, sRemoteSourceId++,
    254                        TrackingId::TrackAcrossProcesses::Yes);
    255  if (IsVideo()) {
    256    InitVideo(trackingId);
    257  } else {
    258    InitAudio();
    259  }
    260 
    261  if (!IsValid()) {
    262    aRv = NS_ERROR_UNEXPECTED;
    263    return;
    264  }
    265 
    266  mReceiver = new RTCRtpReceiver(mWindow, mPrincipalPrivacy, mPc,
    267                                 mTransportHandler, mCallWrapper->mCallThread,
    268                                 mStsThread, mConduit, this, trackingId);
    269 
    270  mSender = new RTCRtpSender(mWindow, mPc, mTransportHandler,
    271                             mCallWrapper->mCallThread, mStsThread, mConduit,
    272                             mSendTrack, aInit.mSendEncodings, this);
    273 
    274  if (mConduit) {
    275    InitConduitControl();
    276  }
    277 
    278  mSender->SetStreamsImpl(aInit.mStreams);
    279  mDirection = aInit.mDirection;
    280 }
    281 
    282 void RTCRtpTransceiver::SetDtlsTransport(
    283    dom::RTCDtlsTransport* aDtlsTransport) {
    284  mDtlsTransport = aDtlsTransport;
    285 }
    286 
    287 void RTCRtpTransceiver::SaveStateForRollback() {
    288  mLastStableDtlsTransport = mDtlsTransport;
    289 }
    290 
    291 void RTCRtpTransceiver::RollbackToStableDtlsTransport() {
    292  mDtlsTransport = mLastStableDtlsTransport;
    293 }
    294 
    295 void RTCRtpTransceiver::InitAudio() {
    296  mConduit = AudioSessionConduit::Create(mCallWrapper, mStsThread);
    297 
    298  if (!mConduit) {
    299    MOZ_MTLOG(ML_ERROR, mPc->GetHandle()
    300                            << "[" << mMid.Ref() << "]: " << __FUNCTION__
    301                            << ": Failed to create AudioSessionConduit");
    302    // TODO(bug 1422897): We need a way to record this when it happens in the
    303    // wild.
    304  }
    305 }
    306 
    307 void RTCRtpTransceiver::InitVideo(const TrackingId& aRecvTrackingId) {
    308  VideoSessionConduit::Options options;
    309  options.mVideoLatencyTestEnable =
    310      Preferences::GetBool("media.video.test_latency", false);
    311  options.mMinBitrate = std::max(
    312      0,
    313      Preferences::GetInt("media.peerconnection.video.min_bitrate", 0) * 1000);
    314  options.mStartBitrate = std::max(
    315      0, Preferences::GetInt("media.peerconnection.video.start_bitrate", 0) *
    316             1000);
    317  options.mPrefMaxBitrate = std::max(
    318      0,
    319      Preferences::GetInt("media.peerconnection.video.max_bitrate", 0) * 1000);
    320  if (options.mMinBitrate != 0 &&
    321      options.mMinBitrate < kViEMinCodecBitrate_bps) {
    322    options.mMinBitrate = kViEMinCodecBitrate_bps;
    323  }
    324  if (options.mStartBitrate < options.mMinBitrate) {
    325    options.mStartBitrate = options.mMinBitrate;
    326  }
    327  if (options.mPrefMaxBitrate &&
    328      options.mStartBitrate > options.mPrefMaxBitrate) {
    329    options.mStartBitrate = options.mPrefMaxBitrate;
    330  }
    331  // XXX We'd love if this was a live param for testing adaptation/etc
    332  // in automation
    333  options.mMinBitrateEstimate =
    334      std::max(0, Preferences::GetInt(
    335                      "media.peerconnection.video.min_bitrate_estimate", 0) *
    336                      1000);
    337  options.mSpatialLayers = std::max(
    338      1, Preferences::GetInt("media.peerconnection.video.svc.spatial", 0));
    339  options.mTemporalLayers = std::max(
    340      1, Preferences::GetInt("media.peerconnection.video.svc.temporal", 0));
    341  options.mDenoising =
    342      Preferences::GetBool("media.peerconnection.video.denoising", false);
    343  options.mLockScaling =
    344      Preferences::GetBool("media.peerconnection.video.lock_scaling", false);
    345 
    346  mConduit =
    347      VideoSessionConduit::Create(mCallWrapper, mStsThread, std::move(options),
    348                                  mPc->GetHandle(), aRecvTrackingId);
    349 
    350  if (!mConduit) {
    351    MOZ_MTLOG(ML_ERROR, mPc->GetHandle()
    352                            << "[" << mMid.Ref() << "]: " << __FUNCTION__
    353                            << ": Failed to create VideoSessionConduit");
    354    // TODO(bug 1422897): We need a way to record this when it happens in the
    355    // wild.
    356  }
    357 }
    358 
    359 void RTCRtpTransceiver::InitConduitControl() {
    360  MOZ_ASSERT(NS_IsMainThread());
    361  MOZ_ASSERT(mConduit);
    362  ConduitControlState control(this, mSender, mReceiver);
    363  mConduit->AsVideoSessionConduit().apply(
    364      [&](auto aConduit) { aConduit->InitControl(&control); });
    365  mConduit->AsAudioSessionConduit().apply(
    366      [&](auto aConduit) { aConduit->InitControl(&control); });
    367 }
    368 
    369 void RTCRtpTransceiver::Close() {
    370  // Called via PCImpl::Close
    371  // Satisfies steps 7 and 9 of
    372  // https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-close
    373  // No events are fired for this.
    374  mShutdown = true;
    375  if (mDtlsTransport) {
    376    mDtlsTransport->UpdateStateNoEvent(TransportLayer::TS_CLOSED);
    377    // Might not be set if we're cycle-collecting
    378    if (mDtlsTransport->IceTransport()) {
    379      mDtlsTransport->IceTransport()->SetState(RTCIceTransportState::Closed);
    380    }
    381  }
    382  StopImpl();
    383 }
    384 
    385 void RTCRtpTransceiver::BreakCycles() {
    386  mSender->BreakCycles();
    387  mReceiver->BreakCycles();
    388  mWindow = nullptr;
    389  mSendTrack = nullptr;
    390  mSender = nullptr;
    391  mReceiver = nullptr;
    392  mDtlsTransport = nullptr;
    393  mLastStableDtlsTransport = nullptr;
    394  mPc = nullptr;
    395 }
    396 
    397 void RTCRtpTransceiver::Unlink() {
    398  if (mHandlingUnlink) {
    399    BreakCycles();
    400    mHandlingUnlink = false;
    401  } else if (mPc) {
    402    mPc->Close();
    403    mPc->BreakCycles();
    404  }
    405 }
    406 
    407 // TODO: Only called from one place in PeerConnectionImpl, synchronously, when
    408 // the JSEP engine has successfully completed an offer/answer exchange. This is
    409 // a bit squirrely, since identity validation happens asynchronously in
    410 // PeerConnection.sys.mjs. This probably needs to happen once all the "in
    411 // parallel" steps have succeeded, but before we queue the task for JS
    412 // observable state updates.
    413 nsresult RTCRtpTransceiver::UpdateTransport() {
    414  if (!mHasTransport) {
    415    return NS_OK;
    416  }
    417 
    418  mReceiver->UpdateTransport();
    419  mSender->UpdateTransport();
    420  return NS_OK;
    421 }
    422 
    423 nsresult RTCRtpTransceiver::UpdateConduit() {
    424  if (mStopped) {
    425    return NS_OK;
    426  }
    427 
    428  mReceiver->UpdateConduit();
    429  mSender->MaybeUpdateConduit();
    430 
    431  return NS_OK;
    432 }
    433 
    434 void RTCRtpTransceiver::UpdatePrincipalPrivacy(PrincipalPrivacy aPrivacy) {
    435  if (mPrincipalPrivacy == aPrivacy) {
    436    return;
    437  }
    438 
    439  mPrincipalPrivacy = aPrivacy;
    440  mReceiver->UpdatePrincipalPrivacy(mPrincipalPrivacy);
    441 }
    442 
    443 void RTCRtpTransceiver::ResetSync() { mSyncGroup = std::string(); }
    444 
    445 // TODO: Only called from one place in PeerConnectionImpl, synchronously, when
    446 // the JSEP engine has successfully completed an offer/answer exchange. This is
    447 // a bit squirrely, since identity validation happens asynchronously in
    448 // PeerConnection.sys.mjs. This probably needs to happen once all the "in
    449 // parallel" steps have succeeded, but before we queue the task for JS
    450 // observable state updates.
    451 nsresult RTCRtpTransceiver::SyncWithMatchingVideoConduits(
    452    nsTArray<RefPtr<RTCRtpTransceiver>>& transceivers) {
    453  if (mStopped) {
    454    return NS_OK;
    455  }
    456 
    457  if (IsVideo()) {
    458    MOZ_MTLOG(ML_ERROR, mPc->GetHandle()
    459                            << "[" << mMid.Ref() << "]: " << __FUNCTION__
    460                            << " called when transceiver is not "
    461                               "video! This should never happen.");
    462    MOZ_CRASH();
    463    return NS_ERROR_UNEXPECTED;
    464  }
    465 
    466  std::set<std::string> myReceiveStreamIds;
    467  myReceiveStreamIds.insert(mReceiver->GetStreamIds().begin(),
    468                            mReceiver->GetStreamIds().end());
    469 
    470  for (RefPtr<RTCRtpTransceiver>& transceiver : transceivers) {
    471    if (!transceiver->IsValid()) {
    472      continue;
    473    }
    474 
    475    if (!transceiver->IsVideo()) {
    476      // |this| is an audio transceiver, so we skip other audio transceivers
    477      continue;
    478    }
    479 
    480    // Maybe could make this more efficient by cacheing this set, but probably
    481    // not worth it.
    482    for (const std::string& streamId :
    483         transceiver->Receiver()->GetStreamIds()) {
    484      if (myReceiveStreamIds.count(streamId)) {
    485        // Ok, we have one video, one non-video - cross the streams!
    486        mSyncGroup = streamId;
    487        transceiver->mSyncGroup = streamId;
    488 
    489        MOZ_MTLOG(ML_DEBUG, mPc->GetHandle()
    490                                << "[" << mMid.Ref() << "]: " << __FUNCTION__
    491                                << " Syncing " << mConduit.get() << " to "
    492                                << transceiver->mConduit.get());
    493 
    494        // The sync code in call.cc only permits sync between audio stream and
    495        // one video stream. They take the first match, so there's no point in
    496        // continuing here. If we want to change the default, we should sort
    497        // video streams here and only call SetSyncGroup on the chosen stream.
    498        break;
    499      }
    500    }
    501  }
    502 
    503  return NS_OK;
    504 }
    505 
    506 bool RTCRtpTransceiver::ConduitHasPluginID(uint64_t aPluginID) {
    507  return mConduit && mConduit->HasCodecPluginID(aPluginID);
    508 }
    509 
    510 void RTCRtpTransceiver::SyncFromJsep(const JsepSession& aSession) {
    511  MOZ_MTLOG(ML_DEBUG, mPc->GetHandle()
    512                          << "[" << mMid.Ref() << "]: " << __FUNCTION__
    513                          << " Syncing from JSEP transceiver");
    514  if (mShutdown) {
    515    // Shutdown_m has already been called, probably due to pc.close(). Just
    516    // nod and smile.
    517    return;
    518  }
    519 
    520  mJsepTransceiver = *aSession.GetTransceiver(mTransceiverId);
    521 
    522  // Transceivers can stop due to sRD, so we need to check that
    523  if (!mStopped && mJsepTransceiver.IsStopped()) {
    524    MOZ_MTLOG(ML_DEBUG, mPc->GetHandle()
    525                            << "[" << mMid.Ref() << "]: " << __FUNCTION__
    526                            << " JSEP transceiver is stopped");
    527    StopImpl();
    528  }
    529 
    530  mReceiver->SyncFromJsep(mJsepTransceiver);
    531  mSender->SyncFromJsep(mJsepTransceiver);
    532 
    533  // mid from JSEP
    534  if (mJsepTransceiver.IsAssociated()) {
    535    mMid = mJsepTransceiver.GetMid();
    536  } else {
    537    mMid = std::string();
    538  }
    539 
    540  // currentDirection from JSEP, but not if "this transceiver has never been
    541  // represented in an offer/answer exchange"
    542  if (mJsepTransceiver.HasLevel() && mJsepTransceiver.IsNegotiated()) {
    543    if (mJsepTransceiver.mRecvTrack.GetActive()) {
    544      if (mJsepTransceiver.mSendTrack.GetActive()) {
    545        mCurrentDirection.SetValue(dom::RTCRtpTransceiverDirection::Sendrecv);
    546        mHasBeenUsedToSend = true;
    547      } else {
    548        mCurrentDirection.SetValue(dom::RTCRtpTransceiverDirection::Recvonly);
    549      }
    550    } else {
    551      if (mJsepTransceiver.mSendTrack.GetActive()) {
    552        mCurrentDirection.SetValue(dom::RTCRtpTransceiverDirection::Sendonly);
    553        mHasBeenUsedToSend = true;
    554      } else {
    555        mCurrentDirection.SetValue(dom::RTCRtpTransceiverDirection::Inactive);
    556      }
    557    }
    558  }
    559 
    560  mShouldRemove = mJsepTransceiver.IsRemoved();
    561  mHasTransport = !mStopped && mJsepTransceiver.mTransport.mComponents;
    562 }
    563 
    564 void RTCRtpTransceiver::SyncToJsep(JsepSession& aSession) const {
    565  MOZ_MTLOG(ML_DEBUG, mPc->GetHandle()
    566                          << "[" << mMid.Ref() << "]: " << __FUNCTION__
    567                          << " Syncing to JSEP transceiver");
    568 
    569  aSession.ApplyToTransceiver(
    570      mTransceiverId, [this, self = RefPtr<const RTCRtpTransceiver>(this)](
    571                          JsepTransceiver& aTransceiver) {
    572        mReceiver->SyncToJsep(aTransceiver);
    573        mSender->SyncToJsep(aTransceiver);
    574        aTransceiver.mJsDirection = ToSdpDirection(mDirection);
    575        if (mStopping || mStopped) {
    576          aTransceiver.Stop();
    577        }
    578      });
    579 }
    580 
    581 void RTCRtpTransceiver::GetKind(nsAString& aKind) const {
    582  // The transceiver kind of an RTCRtpTransceiver is defined by the kind of the
    583  // associated RTCRtpReceiver's MediaStreamTrack object.
    584  MOZ_ASSERT(mReceiver && mReceiver->Track());
    585  mReceiver->Track()->GetKind(aKind);
    586 }
    587 
    588 void RTCRtpTransceiver::GetMid(nsAString& aMid) const {
    589  if (!mMid.Ref().empty()) {
    590    aMid = NS_ConvertUTF8toUTF16(mMid.Ref());
    591  } else {
    592    aMid.SetIsVoid(true);
    593  }
    594 }
    595 
    596 std::string RTCRtpTransceiver::GetMidAscii() const {
    597  if (mMid.Ref().empty()) {
    598    return std::string();
    599  }
    600 
    601  return mMid.Ref();
    602 }
    603 
    604 void RTCRtpTransceiver::SetDirection(RTCRtpTransceiverDirection aDirection,
    605                                     ErrorResult& aRv) {
    606  // If transceiver.[[Stopping]] is true, throw an InvalidStateError.
    607  if (mStopping) {
    608    aRv.ThrowInvalidStateError("Transceiver is stopping/stopped!");
    609    return;
    610  }
    611 
    612  // If newDirection is equal to transceiver.[[Direction]], abort these steps.
    613  if (aDirection == mDirection) {
    614    return;
    615  }
    616 
    617  // If newDirection is equal to "stopped", throw a TypeError.
    618  if (aDirection == RTCRtpTransceiverDirection::Stopped) {
    619    aRv.ThrowTypeError("Cannot use \"stopped\" in setDirection!");
    620    return;
    621  }
    622 
    623  // Set transceiver.[[Direction]] to newDirection.
    624  SetDirectionInternal(aDirection);
    625 
    626  // Update the negotiation-needed flag for connection.
    627  mPc->UpdateNegotiationNeeded();
    628 }
    629 
    630 void RTCRtpTransceiver::SetDirectionInternal(
    631    RTCRtpTransceiverDirection aDirection) {
    632  // We do not update the direction on the JsepTransceiver until sync
    633  mDirection = aDirection;
    634 }
    635 
    636 bool RTCRtpTransceiver::ShouldRemove() const { return mShouldRemove; }
    637 
    638 bool RTCRtpTransceiver::CanSendDTMF() const {
    639  // Spec says: "If connection's RTCPeerConnectionState is not "connected"
    640  // return false." We don't support that right now. This is supposed to be
    641  // true once ICE is complete, and _all_ DTLS handshakes are also complete. We
    642  // don't really have access to the state of _all_ of our DTLS states either.
    643  // Our pipeline _does_ know whether SRTP/SRTCP is ready, which happens
    644  // immediately after our transport finishes DTLS (unless there was an error),
    645  // so this is pretty close.
    646  // TODO (bug 1265827): Base this on RTCPeerConnectionState instead.
    647  // TODO (bug 1623193): Tighten this up
    648  if (!IsSending() || !mSender->GetTrack() || Stopping()) {
    649    return false;
    650  }
    651 
    652  // Ok, it looks like the connection is up and sending. Did we negotiate
    653  // telephone-event?
    654  const JsepTrackNegotiatedDetails* details =
    655      mJsepTransceiver.mSendTrack.GetNegotiatedDetails();
    656  if (NS_WARN_IF(!details || !details->GetEncodingCount())) {
    657    // What?
    658    return false;
    659  }
    660 
    661  for (size_t i = 0; i < details->GetEncodingCount(); ++i) {
    662    const auto& encoding = details->GetEncoding(i);
    663    for (const auto& codec : encoding.GetCodecs()) {
    664      if (codec->mName == "telephone-event") {
    665        return true;
    666      }
    667    }
    668  }
    669 
    670  return false;
    671 }
    672 
    673 JSObject* RTCRtpTransceiver::WrapObject(JSContext* aCx,
    674                                        JS::Handle<JSObject*> aGivenProto) {
    675  return dom::RTCRtpTransceiver_Binding::Wrap(aCx, this, aGivenProto);
    676 }
    677 
    678 nsPIDOMWindowInner* RTCRtpTransceiver::GetParentObject() const {
    679  return mWindow;
    680 }
    681 
    682 static void JsepCodecDescToAudioCodecConfig(
    683    const JsepAudioCodecDescription& aCodec, Maybe<AudioCodecConfig>* aConfig) {
    684  uint16_t pt;
    685 
    686  // TODO(bug 1761272): Getting the pt for a JsepAudioCodecDescription should be
    687  // infallible.
    688  if (NS_WARN_IF(!aCodec.GetPtAsInt(&pt))) {
    689    MOZ_MTLOG(ML_ERROR, "Invalid payload type: " << aCodec.mDefaultPt);
    690    MOZ_ASSERT(false);
    691    return;
    692  }
    693 
    694  // libwebrtc crashes if we attempt to configure a mono recv codec
    695  bool sendMono = aCodec.mForceMono && aCodec.mDirection == sdp::kSend;
    696 
    697  *aConfig = Some(AudioCodecConfig(
    698      pt, aCodec.mName, static_cast<int>(aCodec.mClock),
    699      sendMono ? 1 : static_cast<int>(aCodec.mChannels), aCodec.mFECEnabled));
    700  (*aConfig)->mMaxPlaybackRate = static_cast<int>(aCodec.mMaxPlaybackRate);
    701  (*aConfig)->mDtmfEnabled = aCodec.mDtmfEnabled;
    702  (*aConfig)->mDTXEnabled = aCodec.mDTXEnabled;
    703  (*aConfig)->mMaxAverageBitrate = aCodec.mMaxAverageBitrate;
    704  (*aConfig)->mFrameSizeMs = aCodec.mFrameSizeMs;
    705  (*aConfig)->mMinFrameSizeMs = aCodec.mMinFrameSizeMs;
    706  (*aConfig)->mMaxFrameSizeMs = aCodec.mMaxFrameSizeMs;
    707  (*aConfig)->mCbrEnabled = aCodec.mCbrEnabled;
    708 }
    709 
    710 // TODO: This and the next function probably should move to JsepTransceiver
    711 Maybe<const std::vector<UniquePtr<JsepCodecDescription>>&>
    712 RTCRtpTransceiver::GetNegotiatedSendCodecs() const {
    713  if (!mJsepTransceiver.mSendTrack.GetActive()) {
    714    return Nothing();
    715  }
    716 
    717  const auto* details = mJsepTransceiver.mSendTrack.GetNegotiatedDetails();
    718  if (!details) {
    719    return Nothing();
    720  }
    721 
    722  if (details->GetEncodingCount() == 0) {
    723    return Nothing();
    724  }
    725 
    726  return SomeRef(details->GetEncoding(0).GetCodecs());
    727 }
    728 
    729 Maybe<const std::vector<UniquePtr<JsepCodecDescription>>&>
    730 RTCRtpTransceiver::GetNegotiatedRecvCodecs() const {
    731  if (!mJsepTransceiver.mRecvTrack.GetActive()) {
    732    return Nothing();
    733  }
    734 
    735  const auto* details = mJsepTransceiver.mRecvTrack.GetNegotiatedDetails();
    736  if (!details) {
    737    return Nothing();
    738  }
    739 
    740  if (details->GetEncodingCount() == 0) {
    741    return Nothing();
    742  }
    743 
    744  return SomeRef(details->GetEncoding(0).GetCodecs());
    745 }
    746 
    747 // TODO: Maybe move this someplace else?
    748 /*static*/
    749 void RTCRtpTransceiver::NegotiatedDetailsToAudioCodecConfigs(
    750    const JsepTrackNegotiatedDetails& aDetails,
    751    std::vector<AudioCodecConfig>* aConfigs) {
    752  Maybe<AudioCodecConfig> telephoneEvent;
    753 
    754  const std::decay_t<decltype(aDetails.GetEncoding(0).GetCodecs())> empty;
    755  const auto& codecs =
    756      aDetails.GetEncodingCount() ? aDetails.GetEncoding(0).GetCodecs() : empty;
    757  for (const auto& codec : codecs) {
    758    if (NS_WARN_IF(codec->Type() != SdpMediaSection::kAudio)) {
    759      MOZ_ASSERT(false, "Codec is not audio! This is a JSEP bug.");
    760      return;
    761    }
    762    Maybe<AudioCodecConfig> config;
    763    const JsepAudioCodecDescription& audio =
    764        static_cast<const JsepAudioCodecDescription&>(*codec);
    765    JsepCodecDescToAudioCodecConfig(audio, &config);
    766    if (config->mName == "telephone-event") {
    767      telephoneEvent = std::move(config);
    768    } else {
    769      aConfigs->push_back(std::move(*config));
    770    }
    771  }
    772 
    773  // Put telephone event at the back, because webrtc.org crashes if we don't
    774  // If we need to do even more sorting, we should use std::sort.
    775  if (telephoneEvent) {
    776    aConfigs->push_back(std::move(*telephoneEvent));
    777  }
    778 }
    779 
    780 auto RTCRtpTransceiver::GetActivePayloadTypes() const
    781    -> RefPtr<ActivePayloadTypesPromise> {
    782  if (!mConduit) {
    783    return ActivePayloadTypesPromise::CreateAndResolve(PayloadTypes(),
    784                                                       __func__);
    785  }
    786 
    787  if (!mCallWrapper) {
    788    return ActivePayloadTypesPromise::CreateAndResolve(PayloadTypes(),
    789                                                       __func__);
    790  }
    791 
    792  return InvokeAsync(mCallWrapper->mCallThread, __func__,
    793                     [conduit = mConduit]() {
    794                       PayloadTypes pts;
    795                       pts.mSendPayloadType = conduit->ActiveSendPayloadType();
    796                       pts.mRecvPayloadType = conduit->ActiveRecvPayloadType();
    797                       return ActivePayloadTypesPromise::CreateAndResolve(
    798                           std::move(pts), __func__);
    799                     });
    800 }
    801 
    802 static auto JsepCodecDescToVideoCodecConfig(
    803    const JsepVideoCodecDescription& aCodec) -> Maybe<VideoCodecConfig> {
    804  uint16_t pt;
    805 
    806  Maybe<VideoCodecConfig> config;
    807  // TODO(bug 1761272): Getting the pt for a JsepVideoCodecDescription should be
    808  // infallible.
    809  // Bug 1920249, yes please.
    810  if (NS_WARN_IF(!aCodec.GetPtAsInt(&pt))) {
    811    MOZ_MTLOG(ML_ERROR, "Invalid payload type: " << aCodec.mDefaultPt);
    812    MOZ_ASSERT(false);
    813    return Nothing();
    814  }
    815 
    816  UniquePtr<VideoCodecConfigH264> h264Config;
    817 
    818  if (aCodec.mName == "H264") {
    819    h264Config = MakeUnique<VideoCodecConfigH264>();
    820    size_t spropSize = sizeof(h264Config->sprop_parameter_sets);
    821    strncpy(h264Config->sprop_parameter_sets,
    822            aCodec.mSpropParameterSets.c_str(), spropSize);
    823    h264Config->sprop_parameter_sets[spropSize - 1] = '\0';
    824    h264Config->packetization_mode =
    825        static_cast<int>(aCodec.mPacketizationMode);
    826    h264Config->profile_level_id = static_cast<int>(aCodec.mProfileLevelId);
    827    h264Config->tias_bw = 0;  // TODO(bug 1403206)
    828    config = Some(VideoCodecConfig::CreateH264Config(pt, aCodec.mConstraints,
    829                                                     *h264Config));
    830  }
    831 
    832  if (aCodec.mName == "AV1") {
    833    config = Some(VideoCodecConfig::CreateAv1Config(pt, aCodec.mConstraints,
    834                                                    aCodec.mAv1Config));
    835  }
    836 
    837  if (config.isNothing()) {
    838    // TODO bug 1920249, let's just pass in the JsepCodecConfig
    839    config = Some(VideoCodecConfig(pt, aCodec.mName, aCodec.mConstraints));
    840  }
    841 
    842  config->mAckFbTypes = aCodec.mAckFbTypes;
    843  config->mNackFbTypes = aCodec.mNackFbTypes;
    844  config->mCcmFbTypes = aCodec.mCcmFbTypes;
    845  config->mRembFbSet = aCodec.RtcpFbRembIsSet();
    846  config->mFECFbSet = aCodec.mFECEnabled;
    847  config->mTransportCCFbSet = aCodec.RtcpFbTransportCCIsSet();
    848  if (aCodec.mFECEnabled) {
    849    uint16_t pt;
    850    if (SdpHelper::GetPtAsInt(aCodec.mREDPayloadType, &pt)) {
    851      config->mREDPayloadType = pt;
    852    }
    853    if (SdpHelper::GetPtAsInt(aCodec.mULPFECPayloadType, &pt)) {
    854      config->mULPFECPayloadType = pt;
    855    }
    856    if (SdpHelper::GetPtAsInt(aCodec.mREDRTXPayloadType, &pt)) {
    857      config->mREDRTXPayloadType = pt;
    858    }
    859  }
    860  if (aCodec.mRtxEnabled) {
    861    uint16_t pt;
    862    if (SdpHelper::GetPtAsInt(aCodec.mRtxPayloadType, &pt)) {
    863      config->mRTXPayloadType = pt;
    864    }
    865  }
    866  return config;
    867 }
    868 
    869 // TODO: Maybe move this someplace else?
    870 /*static*/
    871 void RTCRtpTransceiver::NegotiatedDetailsToVideoCodecConfigs(
    872    const JsepTrackNegotiatedDetails& aDetails,
    873    std::vector<VideoCodecConfig>* aConfigs) {
    874  const std::decay_t<decltype(aDetails.GetEncoding(0).GetCodecs())> empty;
    875  const auto& codecs =
    876      aDetails.GetEncodingCount() ? aDetails.GetEncoding(0).GetCodecs() : empty;
    877  for (const auto& codec : codecs) {
    878    if (NS_WARN_IF(codec->Type() != SdpMediaSection::kVideo)) {
    879      MOZ_ASSERT(false, "Codec is not video! This is a JSEP bug.");
    880      return;
    881    }
    882    const JsepVideoCodecDescription& video =
    883        static_cast<const JsepVideoCodecDescription&>(*codec);
    884 
    885    JsepCodecDescToVideoCodecConfig(video).apply([&](VideoCodecConfig config) {
    886      config.mTias = aDetails.GetTias();
    887      for (size_t i = 0; i < aDetails.GetEncodingCount(); ++i) {
    888        const JsepTrackEncoding& jsepEncoding(aDetails.GetEncoding(i));
    889        if (jsepEncoding.HasFormat(video.mDefaultPt)) {
    890          VideoCodecConfig::Encoding encoding;
    891          encoding.rid = jsepEncoding.mRid;
    892          config.mEncodings.push_back(encoding);
    893        }
    894      }
    895 
    896      aConfigs->push_back(std::move(config));
    897    });
    898  }
    899 }
    900 
    901 /* static */
    902 void RTCRtpTransceiver::ToDomRtpCodec(const JsepCodecDescription& aCodec,
    903                                      RTCRtpCodec* aDomCodec) {
    904  MOZ_ASSERT(aCodec.Type() == SdpMediaSection::kAudio ||
    905             aCodec.Type() == SdpMediaSection::kVideo);
    906  if (aCodec.Type() == SdpMediaSection::kAudio) {
    907    aDomCodec->mChannels.Construct(aCodec.mChannels);
    908  }
    909  aDomCodec->mClockRate = aCodec.mClock;
    910  std::string mimeType =
    911      aCodec.Type() == SdpMediaSection::kAudio ? "audio/" : "video/";
    912  mimeType += aCodec.mName;
    913  aDomCodec->mMimeType = NS_ConvertASCIItoUTF16(mimeType);
    914 
    915  if (aCodec.mSdpFmtpLine) {
    916    // The RTCRtpParameters.codecs case; just use what we parsed out of the SDP
    917    if (!aCodec.mSdpFmtpLine->empty()) {
    918      aDomCodec->mSdpFmtpLine.Construct(
    919          NS_ConvertASCIItoUTF16(aCodec.mSdpFmtpLine->c_str()));
    920    }
    921  } else {
    922    // The getCapabilities case; serialize what we would put in an offer.
    923    UniquePtr<SdpFmtpAttributeList::Parameters> params;
    924    aCodec.ApplyConfigToFmtp(params);
    925 
    926    if (params != nullptr) {
    927      std::ostringstream paramsString;
    928      params->Serialize(paramsString);
    929      if (!paramsString.str().empty()) {
    930        nsTString<char16_t> fmtp;
    931        fmtp.AssignASCII(paramsString.str());
    932        aDomCodec->mSdpFmtpLine.Construct(fmtp);
    933      }
    934    }
    935  }
    936 }
    937 
    938 /* static */
    939 void RTCRtpTransceiver::ToDomRtpCodecParameters(
    940    const JsepCodecDescription& aCodec,
    941    RTCRtpCodecParameters* aDomCodecParameters) {
    942  ToDomRtpCodec(aCodec, aDomCodecParameters);
    943  uint16_t pt;
    944  if (SdpHelper::GetPtAsInt(aCodec.mDefaultPt, &pt)) {
    945    aDomCodecParameters->mPayloadType = pt;
    946  }
    947 }
    948 
    949 /* static */
    950 void RTCRtpTransceiver::ToDomRtpCodecRtx(
    951    const JsepVideoCodecDescription& aCodec, RTCRtpCodec* aDomCodec) {
    952  MOZ_ASSERT(aCodec.Type() == SdpMediaSection::kVideo);
    953  aDomCodec->mClockRate = aCodec.mClock;
    954  aDomCodec->mMimeType = NS_ConvertASCIItoUTF16("video/rtx");
    955  std::ostringstream apt;
    956  apt << "apt=" << aCodec.mDefaultPt;
    957  aDomCodec->mSdpFmtpLine.Construct(NS_ConvertASCIItoUTF16(apt.str().c_str()));
    958 }
    959 
    960 /* static */
    961 void RTCRtpTransceiver::ToDomRtpCodecParametersRtx(
    962    const JsepVideoCodecDescription& aCodec,
    963    RTCRtpCodecParameters* aDomCodecParameters) {
    964  ToDomRtpCodecRtx(aCodec, aDomCodecParameters);
    965  uint16_t pt;
    966  if (SdpHelper::GetPtAsInt(aCodec.mRtxPayloadType, &pt)) {
    967    aDomCodecParameters->mPayloadType = pt;
    968  }
    969 }
    970 
    971 void RTCRtpTransceiver::Stop(ErrorResult& aRv) {
    972  if (mPc->IsClosed()) {
    973    aRv.ThrowInvalidStateError("Peer connection is closed");
    974    return;
    975  }
    976 
    977  if (mStopping) {
    978    return;
    979  }
    980 
    981  StopTransceiving();
    982  mPc->UpdateNegotiationNeeded();
    983 }
    984 
    985 void RTCRtpTransceiver::SetCodecPreferences(
    986    const nsTArray<RTCRtpCodec>& aCodecs, ErrorResult& aRv) {
    987  nsTArray<RTCRtpCodec> aCodecsFiltered;
    988  OverrideRtxPreference rtxOverride =
    989      OverrideRtxPreference::OverrideWithDisabled;
    990  ;
    991  bool useableCodecs = false;
    992 
    993  // kind = transciever's kind.
    994  nsAutoString kind;
    995  GetKind(kind);
    996 
    997  if (!aCodecs.IsEmpty()) {
    998    struct {
    999      bool Equals(const RTCRtpCodec& aA, const RTCRtpCodec& aB) const {
   1000        return ((aA.mMimeType.Equals(aB.mMimeType,
   1001                                     nsCaseInsensitiveStringComparator)) &&
   1002                (aA.mClockRate == aB.mClockRate) &&
   1003                (aA.mChannels == aB.mChannels) &&
   1004                (aA.mSdpFmtpLine == aB.mSdpFmtpLine));
   1005      }
   1006    } CodecComparator;
   1007 
   1008    // Remove any duplicate values in codecs, ensuring that the first occurrence
   1009    // of each value remains in place.
   1010    for (const auto& codec : aCodecs) {
   1011      if (!std::any_of(aCodecsFiltered.begin(), aCodecsFiltered.end(),
   1012                       [&codec, CodecComparator](RTCRtpCodec& alreadyInserted) {
   1013                         return CodecComparator.Equals(alreadyInserted, codec);
   1014                       })) {
   1015        aCodecsFiltered.AppendElement(codec);
   1016      }
   1017 
   1018      // Ensure a usable codec was supplied and if RTX is still preferred.
   1019      if (!useableCodecs && !codec.mMimeType.EqualsLiteral("video/ulpfec") &&
   1020          !codec.mMimeType.EqualsLiteral("video/red") &&
   1021          !codec.mMimeType.EqualsLiteral("video/rtx")) {
   1022        useableCodecs = true;
   1023      }
   1024      if (codec.mMimeType.EqualsLiteral("video/rtx")) {
   1025        rtxOverride = OverrideRtxPreference::OverrideWithEnabled;
   1026      }
   1027    }
   1028 
   1029    // If codecs are not in the codecCapabilities of receiver capabilities
   1030    // throw InvalidModificationError
   1031    dom::Nullable<dom::RTCRtpCapabilities> codecCapabilities;
   1032    PeerConnectionImpl::GetCapabilities(kind, codecCapabilities,
   1033                                        sdp::Direction::kRecv);
   1034 
   1035    for (const auto& codec : aCodecsFiltered) {
   1036      if (!std::any_of(codecCapabilities.Value().mCodecs.begin(),
   1037                       codecCapabilities.Value().mCodecs.end(),
   1038                       [&codec, CodecComparator](RTCRtpCodec& recvCap) {
   1039                         return CodecComparator.Equals(codec, recvCap);
   1040                       })) {
   1041        aRv.ThrowInvalidModificationError(
   1042            nsPrintfCString("Codec %s not in capabilities",
   1043                            NS_ConvertUTF16toUTF8(codec.mMimeType).get()));
   1044        return;
   1045      }
   1046    }
   1047 
   1048    // If only RTX, RED, or FEC codecs throw InvalidModificationError
   1049    if (!useableCodecs) {
   1050      aRv.ThrowInvalidModificationError("No useable codecs supplied");
   1051      return;
   1052    }
   1053  }
   1054  // If we passed an empty list, we should restore the default list, including
   1055  // RTX
   1056 
   1057  mPreferredCodecs.clear();
   1058  std::vector<UniquePtr<JsepCodecDescription>> defaultCodecs;
   1059 
   1060  if (kind.EqualsLiteral("video")) {
   1061    PeerConnectionImpl::GetDefaultVideoCodecs(defaultCodecs, rtxOverride);
   1062  } else if (kind.EqualsLiteral("audio")) {
   1063    PeerConnectionImpl::GetDefaultAudioCodecs(defaultCodecs);
   1064  }
   1065 
   1066  if (!aCodecsFiltered.IsEmpty()) {
   1067    mPreferredCodecsInUse = true;
   1068 
   1069    std::vector<std::pair<UniquePtr<JsepCodecDescription>, std::string>>
   1070        defaultCodecsAndParams;
   1071    for (auto& codec : defaultCodecs) {
   1072      UniquePtr<SdpFmtpAttributeList::Parameters> params;
   1073      codec->ApplyConfigToFmtp(params);
   1074      std::ostringstream paramsString;
   1075      if (params != nullptr) {
   1076        params->Serialize(paramsString);
   1077      }
   1078      defaultCodecsAndParams.emplace_back(std::move(codec), paramsString.str());
   1079    }
   1080 
   1081    // Take the array of RTCRtpCodec and convert it to a vector of
   1082    // JsepCodecDescription in order to pass to the receive track and populate
   1083    // codecs.
   1084    for (auto& inputCodec : aCodecsFiltered) {
   1085      auto mimeType = NS_ConvertUTF16toUTF8(inputCodec.mMimeType);
   1086      for (auto& [defaultCodec, precomputedParamsString] :
   1087           defaultCodecsAndParams) {
   1088        bool channelsMatch =
   1089            (!inputCodec.mChannels.WasPassed() && !defaultCodec->mChannels) ||
   1090            (inputCodec.mChannels.WasPassed() &&
   1091             (inputCodec.mChannels.Value() == defaultCodec->mChannels));
   1092        bool sdpFmtpLinesMatch =
   1093            (precomputedParamsString.empty() &&
   1094             !inputCodec.mSdpFmtpLine.WasPassed()) ||
   1095            ((!precomputedParamsString.empty() &&
   1096              inputCodec.mSdpFmtpLine.WasPassed()) &&
   1097             NS_ConvertUTF16toUTF8(inputCodec.mSdpFmtpLine.Value())
   1098                 .EqualsASCII(precomputedParamsString.c_str()));
   1099 
   1100        if ((mimeType.Find(defaultCodec->mName) != kNotFound) &&
   1101            (inputCodec.mClockRate == defaultCodec->mClock) && channelsMatch &&
   1102            sdpFmtpLinesMatch) {
   1103          mPreferredCodecs.emplace_back(defaultCodec->Clone());
   1104          break;
   1105        }
   1106      }
   1107    }
   1108  } else {
   1109    mPreferredCodecs.swap(defaultCodecs);
   1110    mPreferredCodecsInUse = false;
   1111  }
   1112 }
   1113 
   1114 void RTCRtpTransceiver::StopTransceiving() {
   1115  if (mStopping) {
   1116    MOZ_ASSERT(false);
   1117    return;
   1118  }
   1119  mStopping = true;
   1120  // This is the "Stop sending and receiving" algorithm from webrtc-pc
   1121  mSender->Stop();
   1122  mReceiver->Stop();
   1123  mDirection = RTCRtpTransceiverDirection::Inactive;
   1124 }
   1125 
   1126 void RTCRtpTransceiver::StopImpl() {
   1127  // This is the "stop the RTCRtpTransceiver" algorithm from webrtc-pc
   1128  if (!mStopping) {
   1129    StopTransceiving();
   1130  }
   1131 
   1132  if (mCallWrapper) {
   1133    auto conduit = std::move(mConduit);
   1134    (conduit ? conduit->Shutdown()
   1135             : GenericPromise::CreateAndResolve(true, __func__))
   1136        ->Then(GetMainThreadSerialEventTarget(), __func__,
   1137               [sender = mSender, receiver = mReceiver]() mutable {
   1138                 // Shutdown pipelines when conduits are guaranteed shut down,
   1139                 // so that all packets sent from conduits can be delivered.
   1140                 sender->Shutdown();
   1141                 receiver->Shutdown();
   1142               });
   1143    mCallWrapper = nullptr;
   1144  }
   1145  mStopped = true;
   1146  mCurrentDirection.SetNull();
   1147 
   1148  mSender->Stop();
   1149  mReceiver->Stop();
   1150 
   1151  mHasTransport = false;
   1152 
   1153  auto self = nsMainThreadPtrHandle<RTCRtpTransceiver>(
   1154      new nsMainThreadPtrHolder<RTCRtpTransceiver>(
   1155          "RTCRtpTransceiver::StopImpl::self", this, false));
   1156  mStsThread->Dispatch(NS_NewRunnableFunction(
   1157      __func__, [self] { self->mTransportHandler = nullptr; }));
   1158 }
   1159 
   1160 bool RTCRtpTransceiver::IsVideo() const { return mIsVideo; }
   1161 
   1162 bool RTCRtpTransceiver::IsSending() const {
   1163  return mCurrentDirection == Nullable(RTCRtpTransceiverDirection::Sendonly) ||
   1164         mCurrentDirection == Nullable(RTCRtpTransceiverDirection::Sendrecv);
   1165 }
   1166 
   1167 bool RTCRtpTransceiver::IsReceiving() const {
   1168  return mCurrentDirection == Nullable(RTCRtpTransceiverDirection::Recvonly) ||
   1169         mCurrentDirection == Nullable(RTCRtpTransceiverDirection::Sendrecv);
   1170 }
   1171 
   1172 void RTCRtpTransceiver::ChainToDomPromiseWithCodecStats(
   1173    nsTArray<RefPtr<RTCStatsPromise>> aStats,
   1174    const RefPtr<dom::Promise>& aDomPromise) {
   1175  nsTArray<RTCCodecStats> codecStats =
   1176      mPc->GetCodecStats(mPc->GetTimestampMaker().GetNow().ToDom());
   1177 
   1178  AutoTArray<
   1179      std::tuple<RTCRtpTransceiver*, RefPtr<RTCStatsPromise::AllPromiseType>>,
   1180      1>
   1181      statsPromises;
   1182  statsPromises.AppendElement(std::make_tuple(
   1183      this, RTCStatsPromise::All(GetMainThreadSerialEventTarget(), aStats)));
   1184 
   1185  ApplyCodecStats(std::move(codecStats), std::move(statsPromises))
   1186      ->Then(
   1187          GetMainThreadSerialEventTarget(), __func__,
   1188          [aDomPromise, window = mWindow,
   1189           idGen = mIdGenerator](UniquePtr<RTCStatsCollection> aStats) mutable {
   1190            // Rewrite ids and merge stats collections into the final report.
   1191            AutoTArray<UniquePtr<RTCStatsCollection>, 1> stats;
   1192            stats.AppendElement(std::move(aStats));
   1193 
   1194            RTCStatsCollection opaqueStats;
   1195            idGen->RewriteIds(std::move(stats), &opaqueStats);
   1196 
   1197            RefPtr<RTCStatsReport> report(new RTCStatsReport(window));
   1198            report->Incorporate(opaqueStats);
   1199 
   1200            aDomPromise->MaybeResolve(std::move(report));
   1201          },
   1202          [aDomPromise](nsresult aError) {
   1203            aDomPromise->MaybeReject(NS_ERROR_FAILURE);
   1204          });
   1205 }
   1206 
   1207 RefPtr<RTCStatsPromise> RTCRtpTransceiver::ApplyCodecStats(
   1208    nsTArray<RTCCodecStats> aCodecStats,
   1209    nsTArray<
   1210        std::tuple<RTCRtpTransceiver*, RefPtr<RTCStatsPromise::AllPromiseType>>>
   1211        aTransceiverStatsPromises) {
   1212  MOZ_ASSERT(NS_IsMainThread());
   1213  // The process here is roughly:
   1214  // - Gather all inputs to the codec filtering process, including:
   1215  //   - Each transceiver's transportIds
   1216  //   - Each transceiver's active payload types (resolved)
   1217  //   - Each transceiver's resolved stats
   1218  //
   1219  //   Waiting (async) for multiple promises of different types is not supported
   1220  //   by the MozPromise API (bug 1752318), so we are a bit finicky here. We
   1221  //   create media::Refcountables of the types we want to resolve, and let
   1222  //   these be shared across Then-functions through RefPtrs.
   1223  //
   1224  // - For each active payload type in a transceiver:
   1225  //   - Register the codec stats for this payload type and transport if we
   1226  //     haven't already done so
   1227  //   - If it was a send payload type, assign the codec stats id for this
   1228  //     payload type and transport to the transceiver's outbound-rtp and
   1229  //     remote-inbound-rtp stats as codecId
   1230  //   - If it was a recv payload type, assign the codec stats id for this
   1231  //     payload type and transport to the transceiver's inbound-rtp and
   1232  //     remote-outbound-rtp stats as codecId
   1233  //
   1234  // - Flatten all transceiver stats collections into one, and set the
   1235  //   registered codec stats on it
   1236 
   1237  // Wrap codec stats in a Refcountable<> to allow sharing across promise
   1238  // handlers.
   1239  auto codecStats = MakeRefPtr<media::Refcountable<nsTArray<RTCCodecStats>>>();
   1240  *codecStats = std::move(aCodecStats);
   1241 
   1242  struct IdComparator {
   1243    bool operator()(const RTCCodecStats& aA, const RTCCodecStats& aB) const {
   1244      return aA.mId.Value() < aB.mId.Value();
   1245    }
   1246  };
   1247 
   1248  // Stores distinct codec stats by id; to avoid dupes within a transport.
   1249  auto finalCodecStats =
   1250      MakeRefPtr<media::Refcountable<std::set<RTCCodecStats, IdComparator>>>();
   1251 
   1252  // All the transceiver rtp stream stats in a single array. These stats will,
   1253  // when resolved, contain codecIds.
   1254  nsTArray<RefPtr<RTCStatsPromise>> promises(
   1255      aTransceiverStatsPromises.Length());
   1256 
   1257  for (const auto& [transceiver, allPromise] : aTransceiverStatsPromises) {
   1258    // Per transceiver, gather up what we need to assign codecId to this
   1259    // transceiver's rtp stream stats. Register codec stats while we're at it.
   1260    auto payloadTypes =
   1261        MakeRefPtr<media::Refcountable<RTCRtpTransceiver::PayloadTypes>>();
   1262    promises.AppendElement(
   1263        transceiver->GetActivePayloadTypes()
   1264            ->Then(
   1265                GetMainThreadSerialEventTarget(), __func__,
   1266                [payloadTypes, allPromise = allPromise](
   1267                    RTCRtpTransceiver::PayloadTypes aPayloadTypes) {
   1268                  // Forward active payload types to the next Then-handler.
   1269                  *payloadTypes = std::move(aPayloadTypes);
   1270                  return allPromise;
   1271                },
   1272                [] {
   1273                  MOZ_CRASH("Unexpected reject");
   1274                  return RTCStatsPromise::AllPromiseType::CreateAndReject(
   1275                      NS_ERROR_UNEXPECTED, __func__);
   1276                })
   1277            ->Then(
   1278                GetMainThreadSerialEventTarget(), __func__,
   1279                [codecStats, finalCodecStats, payloadTypes,
   1280                 transportId =
   1281                     NS_ConvertASCIItoUTF16(transceiver->GetTransportId())](
   1282                    nsTArray<UniquePtr<RTCStatsCollection>>
   1283                        aTransceiverStats) mutable {
   1284                  // We have all the data we need to register codec stats and
   1285                  // assign codecIds for this transceiver's rtp stream stats.
   1286 
   1287                  auto report = MakeUnique<RTCStatsCollection>();
   1288                  FlattenStats(std::move(aTransceiverStats), report.get());
   1289 
   1290                  // Find the codec stats we are looking for, based on the
   1291                  // transportId and the active payload types.
   1292                  Maybe<RTCCodecStats&> sendCodec;
   1293                  Maybe<RTCCodecStats&> recvCodec;
   1294                  for (auto& codec : *codecStats) {
   1295                    if (payloadTypes->mSendPayloadType.isSome() ==
   1296                            sendCodec.isSome() &&
   1297                        payloadTypes->mRecvPayloadType.isSome() ==
   1298                            recvCodec.isSome()) {
   1299                      // We have found all the codec stats we were looking for.
   1300                      break;
   1301                    }
   1302                    if (codec.mTransportId != transportId) {
   1303                      continue;
   1304                    }
   1305                    if (payloadTypes->mSendPayloadType &&
   1306                        *payloadTypes->mSendPayloadType ==
   1307                            static_cast<int>(codec.mPayloadType) &&
   1308                        (!codec.mCodecType.WasPassed() ||
   1309                         codec.mCodecType.Value() == RTCCodecType::Encode)) {
   1310                      MOZ_ASSERT(!sendCodec,
   1311                                 "At most one send codec stat per transceiver");
   1312                      sendCodec = SomeRef(codec);
   1313                    }
   1314                    if (payloadTypes->mRecvPayloadType &&
   1315                        *payloadTypes->mRecvPayloadType ==
   1316                            static_cast<int>(codec.mPayloadType) &&
   1317                        (!codec.mCodecType.WasPassed() ||
   1318                         codec.mCodecType.Value() == RTCCodecType::Decode)) {
   1319                      MOZ_ASSERT(!recvCodec,
   1320                                 "At most one recv codec stat per transceiver");
   1321                      recvCodec = SomeRef(codec);
   1322                    }
   1323                  }
   1324 
   1325                  // Register and assign codecIds for the found codec stats.
   1326                  if (sendCodec) {
   1327                    finalCodecStats->insert(*sendCodec);
   1328                    for (auto& stat : report->mOutboundRtpStreamStats) {
   1329                      stat.mCodecId.Construct(sendCodec->mId.Value());
   1330                    }
   1331                    for (auto& stat : report->mRemoteInboundRtpStreamStats) {
   1332                      stat.mCodecId.Construct(sendCodec->mId.Value());
   1333                    }
   1334                  }
   1335                  if (recvCodec) {
   1336                    finalCodecStats->insert(*recvCodec);
   1337                    for (auto& stat : report->mInboundRtpStreamStats) {
   1338                      stat.mCodecId.Construct(recvCodec->mId.Value());
   1339                    }
   1340                    for (auto& stat : report->mRemoteOutboundRtpStreamStats) {
   1341                      stat.mCodecId.Construct(recvCodec->mId.Value());
   1342                    }
   1343                  }
   1344 
   1345                  return RTCStatsPromise::CreateAndResolve(std::move(report),
   1346                                                           __func__);
   1347                },
   1348                [] {
   1349                  MOZ_CRASH("Unexpected reject");
   1350                  return RTCStatsPromise::CreateAndReject(NS_ERROR_UNEXPECTED,
   1351                                                          __func__);
   1352                }));
   1353  }
   1354 
   1355  return RTCStatsPromise::All(GetMainThreadSerialEventTarget(), promises)
   1356      ->Then(
   1357          GetMainThreadSerialEventTarget(), __func__,
   1358          [finalCodecStats = std::move(finalCodecStats)](
   1359              nsTArray<UniquePtr<RTCStatsCollection>> aStats) mutable {
   1360            auto finalStats = MakeUnique<RTCStatsCollection>();
   1361            FlattenStats(std::move(aStats), finalStats.get());
   1362            MOZ_ASSERT(finalStats->mCodecStats.IsEmpty());
   1363            if (!finalStats->mCodecStats.SetCapacity(finalCodecStats->size(),
   1364                                                     fallible)) {
   1365              mozalloc_handle_oom(0);
   1366            }
   1367            while (!finalCodecStats->empty()) {
   1368              auto node = finalCodecStats->extract(finalCodecStats->begin());
   1369              if (!finalStats->mCodecStats.AppendElement(
   1370                      std::move(node.value()), fallible)) {
   1371                mozalloc_handle_oom(0);
   1372              }
   1373            }
   1374            return RTCStatsPromise::CreateAndResolve(std::move(finalStats),
   1375                                                     __func__);
   1376          },
   1377          [] {
   1378            MOZ_CRASH("Unexpected reject");
   1379            return RTCStatsPromise::CreateAndReject(NS_ERROR_UNEXPECTED,
   1380                                                    __func__);
   1381          });
   1382 }
   1383 
   1384 }  // namespace mozilla