tor-browser

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

RTCRtpReceiver.cpp (46411B)


      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 "RTCRtpReceiver.h"
      6 
      7 #include <stdint.h>
      8 
      9 #include <set>
     10 #include <string>
     11 #include <vector>
     12 
     13 #include "ErrorList.h"
     14 #include "MainThreadUtils.h"
     15 #include "MediaSegment.h"
     16 #include "MediaTrackGraph.h"
     17 #include "MediaTransportHandler.h"
     18 #include "PeerConnectionImpl.h"
     19 #include "PerformanceRecorder.h"
     20 #include "PrincipalHandle.h"
     21 #include "RTCRtpTransceiver.h"
     22 #include "RTCStatsReport.h"
     23 #include "RemoteTrackSource.h"
     24 #include "api/rtp_parameters.h"
     25 #include "api/units/time_delta.h"
     26 #include "api/units/timestamp.h"
     27 #include "call/audio_receive_stream.h"
     28 #include "call/call.h"
     29 #include "call/video_receive_stream.h"
     30 #include "js/RootingAPI.h"
     31 #include "jsep/JsepTransceiver.h"
     32 #include "libwebrtcglue/MediaConduitControl.h"
     33 #include "libwebrtcglue/MediaConduitInterface.h"
     34 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
     35 #include "mozilla/AbstractThread.h"
     36 #include "mozilla/AlreadyAddRefed.h"
     37 #include "mozilla/Assertions.h"
     38 #include "mozilla/ErrorResult.h"
     39 #include "mozilla/Logging.h"
     40 #include "mozilla/Maybe.h"
     41 #include "mozilla/MozPromise.h"
     42 #include "mozilla/NullPrincipal.h"
     43 #include "mozilla/Preferences.h"
     44 #include "mozilla/RefPtr.h"
     45 #include "mozilla/StateMirroring.h"
     46 #include "mozilla/StateWatching.h"
     47 #include "mozilla/UniquePtr.h"
     48 #include "mozilla/dom/AudioStreamTrack.h"
     49 #include "mozilla/dom/Document.h"
     50 #include "mozilla/dom/MediaStreamTrack.h"
     51 #include "mozilla/dom/Nullable.h"
     52 #include "mozilla/dom/Promise.h"
     53 #include "mozilla/dom/RTCRtpCapabilitiesBinding.h"
     54 #include "mozilla/dom/RTCRtpReceiverBinding.h"
     55 #include "mozilla/dom/RTCRtpScriptTransform.h"
     56 #include "mozilla/dom/RTCRtpSourcesBinding.h"
     57 #include "mozilla/dom/RTCStatsReportBinding.h"
     58 #include "mozilla/dom/VideoStreamTrack.h"
     59 #include "mozilla/fallible.h"
     60 #include "mozilla/mozalloc_oom.h"
     61 #include "nsCOMPtr.h"
     62 #include "nsCycleCollectionParticipant.h"
     63 #include "nsDOMNavigationTiming.h"
     64 #include "nsDebug.h"
     65 #include "nsIPrincipal.h"
     66 #include "nsIScriptObjectPrincipal.h"
     67 #include "nsISupports.h"
     68 #include "nsLiteralString.h"
     69 #include "nsPIDOMWindow.h"
     70 #include "nsStringFwd.h"
     71 #include "nsTArray.h"
     72 #include "nsThreadUtils.h"
     73 #include "nsWrapperCache.h"
     74 #include "sdp/SdpAttribute.h"
     75 #include "sdp/SdpEnum.h"
     76 #include "system_wrappers/include/clock.h"
     77 #include "transportbridge/MediaPipeline.h"
     78 
     79 namespace mozilla::dom {
     80 
     81 LazyLogModule gReceiverLog("RTCRtpReceiver");
     82 
     83 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(RTCRtpReceiver)
     84 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(RTCRtpReceiver)
     85  tmp->Unlink();
     86  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
     87 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     88 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(RTCRtpReceiver)
     89  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow, mPc, mTransceiver, mTransform,
     90                                    mTrack, mTrackSource)
     91 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     92 
     93 NS_IMPL_CYCLE_COLLECTING_ADDREF(RTCRtpReceiver)
     94 NS_IMPL_CYCLE_COLLECTING_RELEASE(RTCRtpReceiver)
     95 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(RTCRtpReceiver)
     96  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     97  NS_INTERFACE_MAP_ENTRY(nsISupports)
     98 NS_INTERFACE_MAP_END
     99 
    100 static PrincipalHandle GetPrincipalHandle(nsPIDOMWindowInner* aWindow,
    101                                          PrincipalPrivacy aPrivacy) {
    102  // Set the principal used for creating the tracks. This makes the track
    103  // data (audio/video samples) accessible to the receiving page. We're
    104  // only certain that privacy hasn't been requested if we're connected.
    105  nsCOMPtr<nsIScriptObjectPrincipal> winPrincipal = do_QueryInterface(aWindow);
    106  RefPtr<nsIPrincipal> principal = winPrincipal->GetPrincipal();
    107  if (NS_WARN_IF(!principal)) {
    108    principal = NullPrincipal::CreateWithoutOriginAttributes();
    109  } else if (aPrivacy == PrincipalPrivacy::Private) {
    110    principal = NullPrincipal::CreateWithInheritedAttributes(principal);
    111  }
    112  return MakePrincipalHandle(principal);
    113 }
    114 
    115 #define INIT_CANONICAL(name, val)         \
    116  name(AbstractThread::MainThread(), val, \
    117       "RTCRtpReceiver::" #name " (Canonical)")
    118 #define INIT_MIRROR(name, val) \
    119  name(AbstractThread::MainThread(), val, "RTCRtpReceiver::" #name " (Mirror)")
    120 
    121 RTCRtpReceiver::RTCRtpReceiver(
    122    nsPIDOMWindowInner* aWindow, PrincipalPrivacy aPrivacy,
    123    PeerConnectionImpl* aPc, MediaTransportHandler* aTransportHandler,
    124    AbstractThread* aCallThread, nsISerialEventTarget* aStsThread,
    125    MediaSessionConduit* aConduit, RTCRtpTransceiver* aTransceiver,
    126    const TrackingId& aTrackingId)
    127    : mWatchManager(this, AbstractThread::MainThread()),
    128      mWindow(aWindow),
    129      mPc(aPc),
    130      mCallThread(aCallThread),
    131      mStsThread(aStsThread),
    132      mTransportHandler(aTransportHandler),
    133      mTransceiver(aTransceiver),
    134      INIT_CANONICAL(mSsrc, 0),
    135      INIT_CANONICAL(mVideoRtxSsrc, 0),
    136      INIT_CANONICAL(mLocalRtpExtensions, RtpExtList()),
    137      INIT_CANONICAL(mAudioCodecs, std::vector<AudioCodecConfig>()),
    138      INIT_CANONICAL(mVideoCodecs, std::vector<VideoCodecConfig>()),
    139      INIT_CANONICAL(mVideoRtpRtcpConfig, Nothing()),
    140      INIT_CANONICAL(mReceiving, false),
    141      INIT_CANONICAL(mFrameTransformerProxy, nullptr),
    142      INIT_MIRROR(mReceivingSize, {}) {
    143  PrincipalHandle principalHandle = GetPrincipalHandle(aWindow, aPrivacy);
    144  const bool isAudio = aConduit->type() == MediaSessionConduit::AUDIO;
    145 
    146  MediaTrackGraph* graph = MediaTrackGraph::GetInstance(
    147      isAudio ? MediaTrackGraph::AUDIO_THREAD_DRIVER
    148              : MediaTrackGraph::SYSTEM_THREAD_DRIVER,
    149      aWindow, MediaTrackGraph::REQUEST_DEFAULT_SAMPLE_RATE,
    150      MediaTrackGraph::DEFAULT_OUTPUT_DEVICE);
    151 
    152  if (isAudio) {
    153    auto* source = graph->CreateSourceTrack(MediaSegment::AUDIO);
    154    mTrackSource = MakeAndAddRef<RemoteTrackSource>(
    155        source, this, principalHandle, u"remote audio"_ns, aTrackingId);
    156    mTrack = MakeAndAddRef<AudioStreamTrack>(aWindow, source, mTrackSource);
    157    mPipeline = MakeAndAddRef<MediaPipelineReceiveAudio>(
    158        mPc->GetHandle(), aTransportHandler, aCallThread, mStsThread.get(),
    159        *aConduit->AsAudioSessionConduit(), mTrackSource->Stream(), aTrackingId,
    160        principalHandle, aPrivacy);
    161  } else {
    162    auto* source = graph->CreateSourceTrack(MediaSegment::VIDEO);
    163    mTrackSource = MakeAndAddRef<RemoteTrackSource>(
    164        source, this, principalHandle, u"remote video"_ns, aTrackingId);
    165    mTrack = MakeAndAddRef<VideoStreamTrack>(aWindow, source, mTrackSource);
    166    mPipeline = MakeAndAddRef<MediaPipelineReceiveVideo>(
    167        mPc->GetHandle(), aTransportHandler, aCallThread, mStsThread.get(),
    168        *aConduit->AsVideoSessionConduit(), mTrackSource->Stream(), aTrackingId,
    169        principalHandle, aPrivacy);
    170    mReceivingSize.Connect(
    171        aConduit->AsVideoSessionConduit().ref()->CanonicalReceivingSize());
    172  }
    173 
    174  mPipeline->InitControl(this);
    175 
    176  // Spec says remote tracks start out muted.
    177  mTrackSource->SetMuted(true);
    178 
    179  // Until Bug 1232234 is fixed, we'll get extra RTCP BYES during renegotiation,
    180  // so we'll disable muting on RTCP BYE and timeout for now.
    181  if (Preferences::GetBool("media.peerconnection.mute_on_bye_or_timeout",
    182                           false)) {
    183    mRtcpByeListener = aConduit->RtcpByeEvent().Connect(
    184        GetMainThreadSerialEventTarget(), this, &RTCRtpReceiver::OnRtcpBye);
    185    mRtcpTimeoutListener = aConduit->RtcpTimeoutEvent().Connect(
    186        GetMainThreadSerialEventTarget(), this, &RTCRtpReceiver::OnRtcpTimeout);
    187  }
    188 
    189  mWatchManager.Watch(mReceiveTrackMute,
    190                      &RTCRtpReceiver::UpdateReceiveTrackMute);
    191 
    192  mParameters.mCodecs.Construct();
    193 }
    194 
    195 #undef INIT_MIRROR
    196 #undef INIT_CANONICAL
    197 
    198 RTCRtpReceiver::~RTCRtpReceiver() { MOZ_ASSERT(!mPipeline); }
    199 
    200 JSObject* RTCRtpReceiver::WrapObject(JSContext* aCx,
    201                                     JS::Handle<JSObject*> aGivenProto) {
    202  return RTCRtpReceiver_Binding::Wrap(aCx, this, aGivenProto);
    203 }
    204 
    205 RTCDtlsTransport* RTCRtpReceiver::GetTransport() const {
    206  if (!mTransceiver) {
    207    return nullptr;
    208  }
    209  return mTransceiver->GetDtlsTransport();
    210 }
    211 
    212 void RTCRtpReceiver::GetCapabilities(
    213    const GlobalObject&, const nsAString& aKind,
    214    Nullable<dom::RTCRtpCapabilities>& aResult) {
    215  PeerConnectionImpl::GetCapabilities(aKind, aResult, sdp::Direction::kRecv);
    216 }
    217 
    218 void RTCRtpReceiver::GetParameters(RTCRtpReceiveParameters& aParameters) const {
    219  aParameters = mParameters;
    220 }
    221 
    222 already_AddRefed<Promise> RTCRtpReceiver::GetStats(ErrorResult& aError) {
    223  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mWindow);
    224  RefPtr<Promise> promise = Promise::Create(global, aError);
    225  if (NS_WARN_IF(aError.Failed())) {
    226    return nullptr;
    227  }
    228 
    229  if (NS_WARN_IF(!mTransceiver)) {
    230    // TODO(bug 1056433): When we stop nulling this out when the PC is closed
    231    // (or when the transceiver is stopped), we can remove this code. We
    232    // resolve instead of reject in order to make this eventual change in
    233    // behavior a little smaller.
    234    promise->MaybeResolve(new RTCStatsReport(mWindow));
    235    return promise.forget();
    236  }
    237 
    238  mTransceiver->ChainToDomPromiseWithCodecStats(GetStatsInternal(), promise);
    239  return promise.forget();
    240 }
    241 
    242 nsTArray<RefPtr<RTCStatsPromise>> RTCRtpReceiver::GetStatsInternal(
    243    bool aSkipIceStats) {
    244  MOZ_ASSERT(NS_IsMainThread());
    245  nsTArray<RefPtr<RTCStatsPromise>> promises(3);
    246 
    247  if (!mPipeline) {
    248    return promises;
    249  }
    250 
    251  if (!mHaveStartedReceiving) {
    252    return promises;
    253  }
    254 
    255  nsString recvTrackId;
    256  MOZ_ASSERT(mTrack);
    257  if (mTrack) {
    258    mTrack->GetId(recvTrackId);
    259  }
    260 
    261  std::string mid = mTransceiver->GetMidAscii();
    262 
    263  {
    264    // Add bandwidth estimation stats
    265    promises.AppendElement(InvokeAsync(
    266        mCallThread, __func__,
    267        [conduit = mPipeline->mConduit, recvTrackId]() mutable {
    268          auto report = MakeUnique<dom::RTCStatsCollection>();
    269          const Maybe<webrtc::Call::Stats> stats = conduit->GetCallStats();
    270          stats.apply([&](const auto& aStats) {
    271            dom::RTCBandwidthEstimationInternal bw;
    272            bw.mTrackIdentifier = recvTrackId;
    273            bw.mSendBandwidthBps.Construct(aStats.send_bandwidth_bps / 8);
    274            bw.mMaxPaddingBps.Construct(aStats.max_padding_bitrate_bps / 8);
    275            bw.mReceiveBandwidthBps.Construct(aStats.recv_bandwidth_bps / 8);
    276            bw.mPacerDelayMs.Construct(aStats.pacer_delay_ms);
    277            if (aStats.rtt_ms >= 0) {
    278              bw.mRttMs.Construct(aStats.rtt_ms);
    279            }
    280            if (!report->mBandwidthEstimations.AppendElement(std::move(bw),
    281                                                             fallible)) {
    282              mozalloc_handle_oom(0);
    283            }
    284          });
    285          return RTCStatsPromise::CreateAndResolve(std::move(report), __func__);
    286        }));
    287  }
    288 
    289  promises.AppendElement(
    290      InvokeAsync(
    291          mCallThread, __func__,
    292          [pipeline = mPipeline, recvTrackId, mid = std::move(mid)] {
    293            auto report = MakeUnique<dom::RTCStatsCollection>();
    294            auto asAudio = pipeline->mConduit->AsAudioSessionConduit();
    295            auto asVideo = pipeline->mConduit->AsVideoSessionConduit();
    296 
    297            nsString kind = asVideo.isNothing() ? u"audio"_ns : u"video"_ns;
    298            nsString idstr = kind + u"_"_ns;
    299            idstr.AppendInt(static_cast<uint32_t>(pipeline->Level()));
    300 
    301            Maybe<uint32_t> ssrc = pipeline->mConduit->GetRemoteSSRC();
    302 
    303            // Add frame history
    304            asVideo.apply([&](const auto& conduit) {
    305              if (conduit->AddFrameHistory(&report->mVideoFrameHistories)) {
    306                auto& history = report->mVideoFrameHistories.LastElement();
    307                history.mTrackIdentifier = recvTrackId;
    308              }
    309            });
    310 
    311            // TODO(@@NG):ssrcs handle Conduits having multiple stats at the
    312            // same level.
    313            // This is pending spec work.
    314            // Gather pipeline stats.
    315            nsString localId = u"inbound_rtp_"_ns + idstr;
    316            nsString remoteId;
    317 
    318            auto constructCommonRemoteOutboundRtpStats =
    319                [&](RTCRemoteOutboundRtpStreamStats& aRemote,
    320                    const DOMHighResTimeStamp& aTimestamp) {
    321                  remoteId = u"inbound_rtcp_"_ns + idstr;
    322                  aRemote.mTimestamp.Construct(aTimestamp);
    323                  aRemote.mId.Construct(remoteId);
    324                  aRemote.mType.Construct(RTCStatsType::Remote_outbound_rtp);
    325                  ssrc.apply([&](uint32_t aSsrc) { aRemote.mSsrc = aSsrc; });
    326                  aRemote.mKind = kind;
    327                  aRemote.mMediaType.Construct(
    328                      kind);  // mediaType is the old name for kind.
    329                  aRemote.mLocalId.Construct(localId);
    330                };
    331 
    332            auto constructCommonInboundRtpStats =
    333                [&](RTCInboundRtpStreamStats& aLocal) {
    334                  aLocal.mTrackIdentifier = recvTrackId;
    335                  if (mid != "") {
    336                    aLocal.mMid.Construct(NS_ConvertUTF8toUTF16(mid).get());
    337                  }
    338                  aLocal.mTimestamp.Construct(
    339                      pipeline->GetTimestampMaker().GetNow().ToDom());
    340                  aLocal.mId.Construct(localId);
    341                  aLocal.mType.Construct(RTCStatsType::Inbound_rtp);
    342                  ssrc.apply([&](uint32_t aSsrc) { aLocal.mSsrc = aSsrc; });
    343                  aLocal.mKind = kind;
    344                  aLocal.mMediaType.Construct(
    345                      kind);  // mediaType is the old name for kind.
    346                  if (remoteId.Length()) {
    347                    aLocal.mRemoteId.Construct(remoteId);
    348                  }
    349                };
    350 
    351            asAudio.apply([&](auto& aConduit) {
    352              Maybe<webrtc::AudioReceiveStreamInterface::Stats> audioStats =
    353                  aConduit->GetReceiverStats();
    354              if (audioStats.isNothing()) {
    355                return;
    356              }
    357 
    358              if (!audioStats->last_packet_received.has_value()) {
    359                // By spec: "The lifetime of all RTP monitored objects starts
    360                // when the RTP stream is first used: When the first RTP packet
    361                // is sent or received on the SSRC it represents"
    362                return;
    363              }
    364 
    365              // First, fill in remote stat with rtcp sender data, if present.
    366              if (audioStats->last_sender_report_utc_timestamp) {
    367                RTCRemoteOutboundRtpStreamStats remote;
    368                constructCommonRemoteOutboundRtpStats(
    369                    remote,
    370                    RTCStatsTimestamp::FromNtp(
    371                        aConduit->GetTimestampMaker(),
    372                        /*webrtc::Timestamp::Millis(*/
    373                        *audioStats->last_sender_report_utc_timestamp +
    374                            webrtc::TimeDelta::Seconds(webrtc::kNtpJan1970))
    375                        .ToDom());
    376                remote.mPacketsSent.Construct(
    377                    audioStats->sender_reports_packets_sent);
    378                remote.mBytesSent.Construct(
    379                    audioStats->sender_reports_bytes_sent);
    380                remote.mRemoteTimestamp.Construct(
    381                    audioStats->last_sender_report_remote_utc_timestamp
    382                        ->ms<double>());
    383                if (!report->mRemoteOutboundRtpStreamStats.AppendElement(
    384                        std::move(remote), fallible)) {
    385                  mozalloc_handle_oom(0);
    386                }
    387              }
    388 
    389              // Then, fill in local side (with cross-link to remote only if
    390              // present)
    391              RTCInboundRtpStreamStats local;
    392              constructCommonInboundRtpStats(local);
    393              local.mJitter.Construct(audioStats->jitter_ms / 1000.0);
    394              local.mPacketsLost.Construct(audioStats->packets_lost);
    395              local.mPacketsReceived.Construct(audioStats->packets_received);
    396              local.mPacketsDiscarded.Construct(audioStats->packets_discarded);
    397              local.mBytesReceived.Construct(
    398                  audioStats->payload_bytes_received);
    399              if (audioStats->estimated_playout_ntp_timestamp_ms) {
    400                local.mEstimatedPlayoutTimestamp.Construct(
    401                    RTCStatsTimestamp::FromNtp(
    402                        aConduit->GetTimestampMaker(),
    403                        webrtc::Timestamp::Millis(
    404                            *audioStats->estimated_playout_ntp_timestamp_ms))
    405                        .ToDom());
    406              }
    407              local.mJitterBufferDelay.Construct(
    408                  audioStats->jitter_buffer_delay_seconds);
    409              local.mJitterBufferTargetDelay.Construct(
    410                  audioStats->jitter_buffer_target_delay_seconds);
    411              local.mJitterBufferEmittedCount.Construct(
    412                  audioStats->jitter_buffer_emitted_count);
    413              local.mJitterBufferMinimumDelay.Construct(
    414                  audioStats->jitter_buffer_minimum_delay_seconds);
    415              local.mTotalSamplesReceived.Construct(
    416                  audioStats->total_samples_received);
    417              local.mConcealedSamples.Construct(audioStats->concealed_samples);
    418              local.mSilentConcealedSamples.Construct(
    419                  audioStats->silent_concealed_samples);
    420              if (audioStats->last_packet_received.has_value()) {
    421                local.mLastPacketReceivedTimestamp.Construct(
    422                    RTCStatsTimestamp::FromNtp(
    423                        aConduit->GetTimestampMaker(),
    424                        webrtc::Timestamp::Millis(
    425                            audioStats->last_packet_received->ms()) +
    426                            webrtc::TimeDelta::Seconds(webrtc::kNtpJan1970))
    427                        .ToDom());
    428              }
    429              local.mHeaderBytesReceived.Construct(
    430                  audioStats->header_and_padding_bytes_received);
    431              local.mFecPacketsReceived.Construct(
    432                  audioStats->fec_packets_received);
    433              local.mFecPacketsDiscarded.Construct(
    434                  audioStats->fec_packets_discarded);
    435              local.mConcealmentEvents.Construct(
    436                  audioStats->concealment_events);
    437 
    438              local.mInsertedSamplesForDeceleration.Construct(
    439                  audioStats->inserted_samples_for_deceleration);
    440              local.mRemovedSamplesForAcceleration.Construct(
    441                  audioStats->removed_samples_for_acceleration);
    442              if (audioStats->audio_level >= 0 &&
    443                  audioStats->audio_level <= 32767) {
    444                local.mAudioLevel.Construct(audioStats->audio_level / 32767.0);
    445              }
    446              local.mTotalAudioEnergy.Construct(
    447                  audioStats->total_output_energy);
    448              local.mTotalSamplesDuration.Construct(
    449                  audioStats->total_output_duration);
    450 
    451              if (!report->mInboundRtpStreamStats.AppendElement(
    452                      std::move(local), fallible)) {
    453                mozalloc_handle_oom(0);
    454              }
    455            });
    456 
    457            asVideo.apply([&](auto& aConduit) {
    458              Maybe<webrtc::VideoReceiveStreamInterface::Stats> videoStats =
    459                  aConduit->GetReceiverStats();
    460              if (videoStats.isNothing()) {
    461                return;
    462              }
    463 
    464              if (!videoStats->rtp_stats.last_packet_received.has_value()) {
    465                // By spec: "The lifetime of all RTP monitored objects starts
    466                // when the RTP stream is first used: When the first RTP packet
    467                // is sent or received on the SSRC it represents"
    468                return;
    469              }
    470 
    471              // First, fill in remote stat with rtcp sender data, if present.
    472              if (videoStats->rtcp_sender_ntp_timestamp_ms) {
    473                RTCRemoteOutboundRtpStreamStats remote;
    474                constructCommonRemoteOutboundRtpStats(
    475                    remote, RTCStatsTimestamp::FromNtp(
    476                                aConduit->GetTimestampMaker(),
    477                                webrtc::Timestamp::Millis(
    478                                    videoStats->rtcp_sender_ntp_timestamp_ms))
    479                                .ToDom());
    480                remote.mPacketsSent.Construct(
    481                    videoStats->rtcp_sender_packets_sent);
    482                remote.mBytesSent.Construct(
    483                    videoStats->rtcp_sender_octets_sent);
    484                remote.mRemoteTimestamp.Construct(
    485                    (webrtc::TimeDelta::Millis(
    486                         videoStats->rtcp_sender_remote_ntp_timestamp_ms) -
    487                     webrtc::TimeDelta::Seconds(webrtc::kNtpJan1970))
    488                        .ms());
    489                if (!report->mRemoteOutboundRtpStreamStats.AppendElement(
    490                        std::move(remote), fallible)) {
    491                  mozalloc_handle_oom(0);
    492                }
    493              }
    494 
    495              // Then, fill in local side (with cross-link to remote only if
    496              // present)
    497              RTCInboundRtpStreamStats local;
    498              constructCommonInboundRtpStats(local);
    499              local.mJitter.Construct(
    500                  static_cast<double>(videoStats->rtp_stats.jitter) /
    501                  webrtc::kVideoPayloadTypeFrequency);
    502              local.mPacketsLost.Construct(videoStats->rtp_stats.packets_lost);
    503              local.mPacketsReceived.Construct(
    504                  videoStats->rtp_stats.packet_counter.packets);
    505              local.mPacketsDiscarded.Construct(videoStats->packets_discarded);
    506              local.mDiscardedPackets.Construct(videoStats->packets_discarded);
    507              local.mBytesReceived.Construct(
    508                  videoStats->rtp_stats.packet_counter.payload_bytes);
    509 
    510              // Fill in packet type statistics
    511              local.mNackCount.Construct(
    512                  videoStats->rtcp_packet_type_counts.nack_packets);
    513              local.mFirCount.Construct(
    514                  videoStats->rtcp_packet_type_counts.fir_packets);
    515              local.mPliCount.Construct(
    516                  videoStats->rtcp_packet_type_counts.pli_packets);
    517 
    518              // Lastly, fill in video decoder stats
    519              local.mFramesDecoded.Construct(videoStats->frames_decoded);
    520              local.mKeyFramesDecoded.Construct(
    521                  videoStats->frame_counts.key_frames);
    522 
    523              local.mFramesPerSecond.Construct(videoStats->decode_frame_rate);
    524              local.mFrameWidth.Construct(videoStats->width);
    525              local.mFrameHeight.Construct(videoStats->height);
    526              // XXX: key_frames + delta_frames may undercount frames because
    527              // they were dropped in FrameBuffer::InsertFrame. (bug 1766553)
    528              local.mFramesReceived.Construct(
    529                  videoStats->frame_counts.key_frames +
    530                  videoStats->frame_counts.delta_frames);
    531              local.mJitterBufferDelay.Construct(
    532                  videoStats->jitter_buffer_delay.seconds<double>());
    533              local.mJitterBufferTargetDelay.Construct(
    534                  videoStats->jitter_buffer_target_delay.seconds<double>());
    535              local.mJitterBufferEmittedCount.Construct(
    536                  videoStats->jitter_buffer_emitted_count);
    537              local.mJitterBufferMinimumDelay.Construct(
    538                  videoStats->jitter_buffer_minimum_delay.seconds<double>());
    539 
    540              if (videoStats->qp_sum) {
    541                local.mQpSum.Construct(videoStats->qp_sum.value());
    542              }
    543              local.mTotalDecodeTime.Construct(
    544                  double(videoStats->total_decode_time.ms()) / 1000);
    545              local.mTotalInterFrameDelay.Construct(
    546                  videoStats->total_inter_frame_delay);
    547              local.mTotalSquaredInterFrameDelay.Construct(
    548                  videoStats->total_squared_inter_frame_delay);
    549              local.mPauseCount.Construct(videoStats->pause_count);
    550              local.mTotalPausesDuration.Construct(
    551                  double(videoStats->total_pauses_duration_ms) / 1000.0);
    552              local.mFreezeCount.Construct(videoStats->freeze_count);
    553              local.mTotalFreezesDuration.Construct(
    554                  double(videoStats->total_freezes_duration_ms) / 1000.0);
    555 
    556              if (videoStats->rtp_stats.last_packet_received.has_value()) {
    557                local.mLastPacketReceivedTimestamp.Construct(
    558                    RTCStatsTimestamp::FromNtp(
    559                        aConduit->GetTimestampMaker(),
    560                        webrtc::Timestamp::Millis(
    561                            videoStats->rtp_stats.last_packet_received->ms()) +
    562                            webrtc::TimeDelta::Seconds(webrtc::kNtpJan1970))
    563                        .ToDom());
    564              }
    565              local.mHeaderBytesReceived.Construct(
    566                  videoStats->rtp_stats.packet_counter.header_bytes +
    567                  videoStats->rtp_stats.packet_counter.padding_bytes);
    568              local.mTotalProcessingDelay.Construct(
    569                  videoStats->total_processing_delay.seconds<double>());
    570              local.mFramesAssembledFromMultiplePackets.Construct(
    571                  videoStats->frames_assembled_from_multiple_packets);
    572              local.mTotalAssemblyTime.Construct(
    573                  videoStats->total_assembly_time.seconds<double>());
    574              // For audio this is a Timestamp, but for video it is an int64_t
    575              if (videoStats->estimated_playout_ntp_timestamp_ms.value_or(0)) {
    576                local.mEstimatedPlayoutTimestamp.Construct(
    577                    RTCStatsTimestamp::FromNtp(
    578                        aConduit->GetTimestampMaker(),
    579                        webrtc::Timestamp::Millis(
    580                            *videoStats->estimated_playout_ntp_timestamp_ms))
    581                        .ToDom());
    582              }
    583              // Not including frames dropped in the rendering pipe, which
    584              // is not of webrtc's concern anyway?!
    585              local.mFramesDropped.Construct(videoStats->frames_dropped);
    586              if (!report->mInboundRtpStreamStats.AppendElement(
    587                      std::move(local), fallible)) {
    588                mozalloc_handle_oom(0);
    589              }
    590              // We need to first support the corruption detection RTP header
    591              // extension before we can add these stats.
    592              // if (videoStats->corruption_score_sum.has_value()) {
    593              //   local.mTotalCorruptionProbability.Construct(
    594              //     videoStats->corruption_score_sum.value());
    595              // }
    596              // if (videoStats->corruption_score_squared_sum.has_value()) {
    597              //   local.mTotalSquaredCorruptionProbability.Construct(
    598              //     videoStats->corruption_score_squared_sum.value());
    599              // }
    600              // local.mCorruptionMeasurements.Construct(
    601              //   videoStats->corruption_score_count);
    602            });
    603            return RTCStatsPromise::CreateAndResolve(std::move(report),
    604                                                     __func__);
    605          })
    606          ->Then(
    607              mStsThread, __func__,
    608              [pipeline = mPipeline](UniquePtr<RTCStatsCollection> aReport) {
    609                // Fill in Contributing Source statistics
    610                if (!aReport->mInboundRtpStreamStats.IsEmpty() &&
    611                    aReport->mInboundRtpStreamStats[0].mId.WasPassed()) {
    612                  pipeline->GetContributingSourceStats(
    613                      aReport->mInboundRtpStreamStats[0].mId.Value(),
    614                      aReport->mRtpContributingSourceStats);
    615                }
    616                return RTCStatsPromise::CreateAndResolve(std::move(aReport),
    617                                                         __func__);
    618              },
    619              [] {
    620                MOZ_CRASH("Unexpected reject");
    621                return RTCStatsPromise::CreateAndReject(NS_ERROR_UNEXPECTED,
    622                                                        __func__);
    623              }));
    624 
    625  if (!aSkipIceStats && GetJsepTransceiver().mTransport.mComponents) {
    626    promises.AppendElement(mTransportHandler->GetIceStats(
    627        GetJsepTransceiver().mTransport.mTransportId,
    628        mPipeline->GetTimestampMaker().GetNow().ToDom()));
    629  }
    630 
    631  return promises;
    632 }
    633 
    634 void RTCRtpReceiver::SetJitterBufferTarget(
    635    const Nullable<DOMHighResTimeStamp>& aTargetMs, ErrorResult& aError) {
    636  // Spec says jitter buffer target cannot be negative or larger than 4000
    637  // milliseconds and to throw RangeError if it is. If an invalid value is
    638  // received we return early to preserve the current JitterBufferTarget
    639  // internal slot and jitter buffer values.
    640  if (mPipeline && mPipeline->mConduit) {
    641    if (!aTargetMs.IsNull() &&
    642        (aTargetMs.Value() < 0.0 || aTargetMs.Value() > 4000.0)) {
    643      aError.ThrowRangeError<MSG_VALUE_OUT_OF_RANGE>("jitterBufferTarget");
    644      return;
    645    }
    646 
    647    mJitterBufferTarget.reset();
    648 
    649    if (!aTargetMs.IsNull()) {
    650      mJitterBufferTarget = Some(aTargetMs.Value());
    651    }
    652    // If aJitterBufferTarget is null then we are resetting the jitter buffer so
    653    // pass the default target of 0.0.
    654    mPipeline->mConduit->SetJitterBufferTarget(
    655        mJitterBufferTarget.valueOr(0.0));
    656  }
    657 }
    658 
    659 void RTCRtpReceiver::GetContributingSources(
    660    nsTArray<RTCRtpContributingSource>& aSources) {
    661  // Duplicate code...
    662  if (mPipeline && mPipeline->mConduit) {
    663    nsTArray<dom::RTCRtpSourceEntry> sources;
    664    mPipeline->mConduit->GetRtpSources(sources);
    665    sources.RemoveElementsBy([](const dom::RTCRtpSourceEntry& aEntry) {
    666      return aEntry.mSourceType != dom::RTCRtpSourceEntryType::Contributing;
    667    });
    668    aSources.ReplaceElementsAt(0, aSources.Length(), sources.Elements(),
    669                               sources.Length());
    670  }
    671 }
    672 
    673 void RTCRtpReceiver::GetSynchronizationSources(
    674    nsTArray<dom::RTCRtpSynchronizationSource>& aSources) {
    675  // Duplicate code...
    676  if (mPipeline && mPipeline->mConduit) {
    677    nsTArray<dom::RTCRtpSourceEntry> sources;
    678    mPipeline->mConduit->GetRtpSources(sources);
    679    sources.RemoveElementsBy([](const dom::RTCRtpSourceEntry& aEntry) {
    680      return aEntry.mSourceType != dom::RTCRtpSourceEntryType::Synchronization;
    681    });
    682    aSources.ReplaceElementsAt(0, aSources.Length(), sources.Elements(),
    683                               sources.Length());
    684  }
    685 }
    686 
    687 nsPIDOMWindowInner* RTCRtpReceiver::GetParentObject() const { return mWindow; }
    688 
    689 void RTCRtpReceiver::Shutdown() {
    690  MOZ_ASSERT(NS_IsMainThread());
    691  mWatchManager.Shutdown();
    692  if (mPipeline) {
    693    mPipeline->Shutdown();
    694    mPipeline = nullptr;
    695  }
    696  if (mTrackSource) {
    697    mTrackSource->Destroy();
    698  }
    699  mCallThread = nullptr;
    700  mReceivingSize.DisconnectIfConnected();
    701  mRtcpByeListener.DisconnectIfExists();
    702  mRtcpTimeoutListener.DisconnectIfExists();
    703  mUnmuteListener.DisconnectIfExists();
    704  if (mTransform) {
    705    mTransform->GetProxy().SetReceiver(nullptr);
    706  }
    707 }
    708 
    709 void RTCRtpReceiver::BreakCycles() {
    710  mWindow = nullptr;
    711  mPc = nullptr;
    712  mTrack = nullptr;
    713  mTrackSource = nullptr;
    714 }
    715 
    716 void RTCRtpReceiver::Unlink() {
    717  if (mTransceiver) {
    718    mTransceiver->Unlink();
    719  }
    720 }
    721 
    722 void RTCRtpReceiver::UpdateTransport() {
    723  MOZ_ASSERT(NS_IsMainThread());
    724  if (!mHaveSetupTransport && GetJsepTransceiver().HasLevel()) {
    725    mPipeline->SetLevel(GetJsepTransceiver().GetLevel());
    726    mHaveSetupTransport = true;
    727  }
    728 
    729  UniquePtr<MediaPipelineFilter> filter;
    730  bool signalingStable =
    731      (mPc->GetSignalingState() == RTCSignalingState::Stable);
    732 
    733  auto const& details = GetJsepTransceiver().mRecvTrack.GetNegotiatedDetails();
    734  std::vector<webrtc::RtpExtension> extmaps;
    735  if (GetJsepTransceiver().HasBundleLevel()) {
    736    if (details) {
    737      details->ForEachRTPHeaderExtension(
    738          [&extmaps](const SdpExtmapAttributeList::Extmap& extmap) {
    739            extmaps.emplace_back(extmap.extensionname, extmap.entry);
    740          });
    741    }
    742 
    743    filter = MakeUnique<MediaPipelineFilter>(extmaps);
    744 
    745    // Add remote SSRCs so we can distinguish which RTP packets actually
    746    // belong to this pipeline (also RTCP sender reports).
    747    for (uint32_t ssrc : GetJsepTransceiver().mRecvTrack.GetSsrcs()) {
    748      filter->AddRemoteSSRC(ssrc);
    749    }
    750    for (uint32_t ssrc : GetJsepTransceiver().mRecvTrack.GetRtxSsrcs()) {
    751      filter->AddRemoteSSRC(ssrc);
    752    }
    753    auto mid = Maybe<std::string>();
    754    if (GetMid() != "") {
    755      mid = Some(GetMid());
    756    }
    757    filter->SetRemoteMediaStreamId(mid);
    758 
    759    // Add unique payload types as a last-ditch fallback
    760    auto uniquePts =
    761        GetJsepTransceiver().mRecvTrack.GetUniqueReceivePayloadTypes();
    762    for (auto uniquePt : uniquePts) {
    763      filter->AddUniqueReceivePT(uniquePt);
    764    }
    765 
    766    // Add duplicate payload types
    767    auto duplicatePts =
    768        GetJsepTransceiver().mRecvTrack.GetOtherReceivePayloadTypes();
    769 
    770    for (auto duplicatePt : duplicatePts) {
    771      filter->AddOtherReceivePT(duplicatePt);
    772    }
    773  }
    774 
    775  if (signalingStable || filter) {
    776    mPipeline->UpdateTransport_m(GetJsepTransceiver().mTransport.mTransportId,
    777                                 std::move(filter), signalingStable);
    778  }
    779 }
    780 
    781 void RTCRtpReceiver::UpdateConduit() {
    782  if (mPipeline->mConduit->type() == MediaSessionConduit::VIDEO) {
    783    UpdateVideoConduit();
    784  } else {
    785    UpdateAudioConduit();
    786  }
    787 
    788  if ((mReceiving = mTransceiver->IsReceiving())) {
    789    mHaveStartedReceiving = true;
    790  }
    791 }
    792 
    793 void RTCRtpReceiver::UpdateVideoConduit() {
    794  RefPtr<VideoSessionConduit> conduit =
    795      *mPipeline->mConduit->AsVideoSessionConduit();
    796 
    797  // NOTE(pkerr) - this is new behavior. Needed because the
    798  // CreateVideoReceiveStream method of the Call API will assert (in debug)
    799  // and fail if a value is not provided for the remote_ssrc that will be used
    800  // by the far-end sender.
    801  if (!GetJsepTransceiver().mRecvTrack.GetSsrcs().empty()) {
    802    MOZ_LOG(gReceiverLog, LogLevel::Debug,
    803            ("%s[%s]: %s Setting remote SSRC %u", mPc->GetHandle().c_str(),
    804             GetMid().c_str(), __FUNCTION__,
    805             GetJsepTransceiver().mRecvTrack.GetSsrcs().front()));
    806    uint32_t rtxSsrc =
    807        GetJsepTransceiver().mRecvTrack.GetRtxSsrcs().empty()
    808            ? 0
    809            : GetJsepTransceiver().mRecvTrack.GetRtxSsrcs().front();
    810    mSsrc = GetJsepTransceiver().mRecvTrack.GetSsrcs().front();
    811    mVideoRtxSsrc = rtxSsrc;
    812 
    813    // TODO (bug 1423041) once we pay attention to receiving MID's in RTP
    814    // packets (see bug 1405495) we could make this depending on the presence of
    815    // MID in the RTP packets instead of relying on the signaling.
    816    // In any case, do not disable SSRC changes if no SSRCs were negotiated
    817    if (GetJsepTransceiver().HasBundleLevel() &&
    818        (!GetJsepTransceiver().mRecvTrack.GetNegotiatedDetails() ||
    819         !GetJsepTransceiver().mRecvTrack.GetNegotiatedDetails()->GetExt(
    820             webrtc::RtpExtension::kMidUri))) {
    821      mCallThread->Dispatch(
    822          NewRunnableMethod("VideoSessionConduit::DisableSsrcChanges", conduit,
    823                            &VideoSessionConduit::DisableSsrcChanges));
    824    }
    825  }
    826 
    827  if (GetJsepTransceiver().mRecvTrack.GetNegotiatedDetails() &&
    828      GetJsepTransceiver().mRecvTrack.GetActive()) {
    829    const auto& details(
    830        *GetJsepTransceiver().mRecvTrack.GetNegotiatedDetails());
    831 
    832    {
    833      std::vector<webrtc::RtpExtension> extmaps;
    834      // @@NG read extmap from track
    835      details.ForEachRTPHeaderExtension(
    836          [&extmaps](const SdpExtmapAttributeList::Extmap& extmap) {
    837            extmaps.emplace_back(extmap.extensionname, extmap.entry);
    838          });
    839      mLocalRtpExtensions = extmaps;
    840    }
    841 
    842    std::vector<VideoCodecConfig> configs;
    843    RTCRtpTransceiver::NegotiatedDetailsToVideoCodecConfigs(details, &configs);
    844    if (configs.empty()) {
    845      // TODO: Are we supposed to plumb this error back to JS? This does not
    846      // seem like a failure to set an answer, it just means that codec
    847      // negotiation failed. For now, we're just doing the same thing we do
    848      // if negotiation as a whole failed.
    849      MOZ_LOG(gReceiverLog, LogLevel::Error,
    850              ("%s[%s]: %s  No video codecs were negotiated (recv).",
    851               mPc->GetHandle().c_str(), GetMid().c_str(), __FUNCTION__));
    852      return;
    853    }
    854 
    855    mVideoCodecs = configs;
    856    mVideoRtpRtcpConfig = Some(details.GetRtpRtcpConfig());
    857  }
    858 }
    859 
    860 void RTCRtpReceiver::UpdateAudioConduit() {
    861  RefPtr<AudioSessionConduit> conduit =
    862      *mPipeline->mConduit->AsAudioSessionConduit();
    863 
    864  if (!GetJsepTransceiver().mRecvTrack.GetSsrcs().empty()) {
    865    MOZ_LOG(gReceiverLog, LogLevel::Debug,
    866            ("%s[%s]: %s Setting remote SSRC %u", mPc->GetHandle().c_str(),
    867             GetMid().c_str(), __FUNCTION__,
    868             GetJsepTransceiver().mRecvTrack.GetSsrcs().front()));
    869    mSsrc = GetJsepTransceiver().mRecvTrack.GetSsrcs().front();
    870 
    871    // TODO (bug 1423041) once we pay attention to receiving MID's in RTP
    872    // packets (see bug 1405495) we could make this depending on the presence of
    873    // MID in the RTP packets instead of relying on the signaling.
    874    // In any case, do not disable SSRC changes if no SSRCs were negotiated
    875    if (GetJsepTransceiver().HasBundleLevel() &&
    876        (!GetJsepTransceiver().mRecvTrack.GetNegotiatedDetails() ||
    877         !GetJsepTransceiver().mRecvTrack.GetNegotiatedDetails()->GetExt(
    878             webrtc::RtpExtension::kMidUri))) {
    879      mCallThread->Dispatch(
    880          NewRunnableMethod("AudioSessionConduit::DisableSsrcChanges", conduit,
    881                            &AudioSessionConduit::DisableSsrcChanges));
    882    }
    883  }
    884 
    885  if (GetJsepTransceiver().mRecvTrack.GetNegotiatedDetails() &&
    886      GetJsepTransceiver().mRecvTrack.GetActive()) {
    887    const auto& details(
    888        *GetJsepTransceiver().mRecvTrack.GetNegotiatedDetails());
    889    std::vector<AudioCodecConfig> configs;
    890    RTCRtpTransceiver::NegotiatedDetailsToAudioCodecConfigs(details, &configs);
    891    if (configs.empty()) {
    892      // TODO: Are we supposed to plumb this error back to JS? This does not
    893      // seem like a failure to set an answer, it just means that codec
    894      // negotiation failed. For now, we're just doing the same thing we do
    895      // if negotiation as a whole failed.
    896      MOZ_LOG(gReceiverLog, LogLevel::Error,
    897              ("%s[%s]: %s No audio codecs were negotiated (recv)",
    898               mPc->GetHandle().c_str(), GetMid().c_str(), __FUNCTION__));
    899      return;
    900    }
    901 
    902    // Ensure conduit knows about extensions prior to creating streams
    903    {
    904      std::vector<webrtc::RtpExtension> extmaps;
    905      // @@NG read extmap from track
    906      details.ForEachRTPHeaderExtension(
    907          [&extmaps](const SdpExtmapAttributeList::Extmap& extmap) {
    908            extmaps.emplace_back(extmap.extensionname, extmap.entry);
    909          });
    910      mLocalRtpExtensions = extmaps;
    911    }
    912 
    913    mAudioCodecs = configs;
    914  }
    915 }
    916 
    917 void RTCRtpReceiver::Stop() {
    918  MOZ_ASSERT(mTransceiver->Stopped() || mTransceiver->Stopping());
    919  mReceiving = false;
    920  GetMainThreadSerialEventTarget()->Dispatch(NS_NewRunnableFunction(
    921      __func__, [trackSource = mTrackSource] { trackSource->ForceEnded(); }));
    922 }
    923 
    924 bool RTCRtpReceiver::HasTrack(const dom::MediaStreamTrack* aTrack) const {
    925  return !aTrack || (mTrack == aTrack);
    926 }
    927 
    928 void RTCRtpReceiver::SyncFromJsep(const JsepTransceiver& aJsepTransceiver) {
    929  if (!mPipeline) {
    930    return;
    931  }
    932 
    933  if (GetJsepTransceiver().mRecvTrack.GetNegotiatedDetails()) {
    934    const auto& details(
    935        *GetJsepTransceiver().mRecvTrack.GetNegotiatedDetails());
    936    mParameters.mCodecs.Reset();
    937    mParameters.mCodecs.Construct();
    938    if (details.GetEncodingCount()) {
    939      for (const auto& jsepCodec : details.GetEncoding(0).GetCodecs()) {
    940        if (!jsepCodec->mEnabled ||
    941            !jsepCodec->DirectionSupported(sdp::kRecv)) {
    942          // This codec is disabled or receiving it is unsupported.
    943          continue;
    944        }
    945        RTCRtpCodecParameters codec;
    946        RTCRtpTransceiver::ToDomRtpCodecParameters(*jsepCodec, &codec);
    947        (void)mParameters.mCodecs.Value().AppendElement(codec, fallible);
    948        if (jsepCodec->Type() == SdpMediaSection::kVideo) {
    949          const JsepVideoCodecDescription& videoJsepCodec =
    950              static_cast<JsepVideoCodecDescription&>(*jsepCodec);
    951          if (videoJsepCodec.mRtxEnabled) {
    952            RTCRtpCodecParameters rtx;
    953            RTCRtpTransceiver::ToDomRtpCodecParametersRtx(videoJsepCodec, &rtx);
    954            (void)mParameters.mCodecs.Value().AppendElement(rtx, fallible);
    955          }
    956        }
    957      }
    958    }
    959  }
    960 
    961  // Spec says we set [[Receptive]] to true on sLD(sendrecv/recvonly), and to
    962  // false on sRD(recvonly/inactive), sLD(sendonly/inactive), or when stop()
    963  // is called.
    964  bool wasReceptive = mReceptive;
    965  mReceptive = aJsepTransceiver.mRecvTrack.GetReceptive();
    966  if (!wasReceptive && mReceptive) {
    967    mUnmuteListener = mPipeline->mConduit->RtpPacketEvent().Connect(
    968        GetMainThreadSerialEventTarget(), this, &RTCRtpReceiver::OnRtpPacket);
    969  } else if (wasReceptive && !mReceptive) {
    970    mUnmuteListener.DisconnectIfExists();
    971  }
    972 }
    973 
    974 void RTCRtpReceiver::SyncToJsep(JsepTransceiver& aJsepTransceiver) const {
    975  if (!mTransceiver->GetPreferredCodecs().empty()) {
    976    aJsepTransceiver.mRecvTrack.PopulateCodecs(
    977        mTransceiver->GetPreferredCodecs(),
    978        mTransceiver->GetPreferredCodecsInUse());
    979  }
    980 }
    981 
    982 void RTCRtpReceiver::UpdateStreams(StreamAssociationChanges* aChanges) {
    983  // We don't sort and use set_difference, because we need to report the
    984  // added/removed streams in the order that they appear in the SDP.
    985  std::set<std::string> newIds(
    986      GetJsepTransceiver().mRecvTrack.GetStreamIds().begin(),
    987      GetJsepTransceiver().mRecvTrack.GetStreamIds().end());
    988  MOZ_ASSERT(GetJsepTransceiver().mRecvTrack.GetRemoteSetSendBit() ||
    989             newIds.empty());
    990  bool needsTrackEvent = false;
    991  for (const auto& id : mStreamIds) {
    992    if (!newIds.count(id)) {
    993      aChanges->mStreamAssociationsRemoved.push_back({mTrack, id});
    994    }
    995  }
    996 
    997  std::set<std::string> oldIds(mStreamIds.begin(), mStreamIds.end());
    998  for (const auto& id : GetJsepTransceiver().mRecvTrack.GetStreamIds()) {
    999    if (!oldIds.count(id)) {
   1000      needsTrackEvent = true;
   1001      aChanges->mStreamAssociationsAdded.push_back({mTrack, id});
   1002    }
   1003  }
   1004 
   1005  mStreamIds = GetJsepTransceiver().mRecvTrack.GetStreamIds();
   1006 
   1007  if (mRemoteSetSendBit !=
   1008      GetJsepTransceiver().mRecvTrack.GetRemoteSetSendBit()) {
   1009    mRemoteSetSendBit = GetJsepTransceiver().mRecvTrack.GetRemoteSetSendBit();
   1010    if (mRemoteSetSendBit) {
   1011      needsTrackEvent = true;
   1012    } else {
   1013      aChanges->mReceiversToMute.push_back(this);
   1014    }
   1015  }
   1016 
   1017  if (needsTrackEvent) {
   1018    aChanges->mTrackEvents.push_back({this, mStreamIds});
   1019  }
   1020 }
   1021 
   1022 void RTCRtpReceiver::UpdatePrincipalPrivacy(PrincipalPrivacy aPrivacy) {
   1023  if (!mPipeline) {
   1024    return;
   1025  }
   1026 
   1027  if (aPrivacy != PrincipalPrivacy::Private) {
   1028    return;
   1029  }
   1030 
   1031  mPipeline->SetPrivatePrincipal(GetPrincipalHandle(mWindow, aPrivacy));
   1032 }
   1033 
   1034 // test-only: adds fake CSRCs and audio data
   1035 void RTCRtpReceiver::MozInsertAudioLevelForContributingSource(
   1036    const uint32_t aSource, const DOMHighResTimeStamp aTimestamp,
   1037    const uint32_t aRtpTimestamp, const bool aHasLevel, const uint8_t aLevel) {
   1038  if (!mPipeline || mPipeline->IsVideo() || !mPipeline->mConduit) {
   1039    return;
   1040  }
   1041  mPipeline->mConduit->InsertAudioLevelForContributingSource(
   1042      aSource, aTimestamp, aRtpTimestamp, aHasLevel, aLevel);
   1043 }
   1044 
   1045 void RTCRtpReceiver::OnRtcpBye() { mReceiveTrackMute = true; }
   1046 
   1047 void RTCRtpReceiver::OnRtcpTimeout() { mReceiveTrackMute = true; }
   1048 
   1049 void RTCRtpReceiver::SetTrackMuteFromRemoteSdp() {
   1050  MOZ_ASSERT(!mReceptive,
   1051             "PeerConnectionImpl should have blocked unmute events prior to "
   1052             "firing mute");
   1053  mReceiveTrackMute = true;
   1054  // Set the mute state (and fire the mute event) synchronously. Unmute is
   1055  // handled asynchronously after receiving RTP packets.
   1056  UpdateReceiveTrackMute();
   1057  MOZ_ASSERT(mTrack->Muted(), "Muted state was indeed set synchronously");
   1058 }
   1059 
   1060 void RTCRtpReceiver::OnRtpPacket() {
   1061  MOZ_ASSERT(mReceptive, "We should not be registered unless this is set!");
   1062  // We should be registered since we're currently getting a callback.
   1063  mUnmuteListener.Disconnect();
   1064  if (mReceptive) {
   1065    mReceiveTrackMute = false;
   1066  }
   1067 }
   1068 
   1069 void RTCRtpReceiver::UpdateReceiveTrackMute() {
   1070  if (!mTrack) {
   1071    return;
   1072  }
   1073  if (!mTrackSource) {
   1074    return;
   1075  }
   1076  // This sets the muted state for mTrack and all its clones.
   1077  // Idempotent -- only reacts to changes.
   1078  mTrackSource->SetMuted(mReceiveTrackMute);
   1079 }
   1080 
   1081 std::string RTCRtpReceiver::GetMid() const {
   1082  return mTransceiver->GetMidAscii();
   1083 }
   1084 
   1085 JsepTransceiver& RTCRtpReceiver::GetJsepTransceiver() {
   1086  MOZ_ASSERT(mTransceiver);
   1087  return mTransceiver->GetJsepTransceiver();
   1088 }
   1089 
   1090 const JsepTransceiver& RTCRtpReceiver::GetJsepTransceiver() const {
   1091  MOZ_ASSERT(mTransceiver);
   1092  return mTransceiver->GetJsepTransceiver();
   1093 }
   1094 
   1095 void RTCRtpReceiver::SetTransform(RTCRtpScriptTransform* aTransform,
   1096                                  ErrorResult& aError) {
   1097  if (aTransform == mTransform.get()) {
   1098    // Ok... smile and nod
   1099    // TODO: Depending on spec, this might throw
   1100    // https://github.com/w3c/webrtc-encoded-transform/issues/189
   1101    return;
   1102  }
   1103 
   1104  if (aTransform && aTransform->IsClaimed()) {
   1105    aError.ThrowInvalidStateError("transform has already been used elsewhere");
   1106    return;
   1107  }
   1108 
   1109  if (aTransform) {
   1110    mFrameTransformerProxy = &aTransform->GetProxy();
   1111  } else {
   1112    mFrameTransformerProxy = nullptr;
   1113  }
   1114 
   1115  if (mTransform) {
   1116    mTransform->GetProxy().SetReceiver(nullptr);
   1117  }
   1118 
   1119  mTransform = const_cast<RTCRtpScriptTransform*>(aTransform);
   1120 
   1121  if (mTransform) {
   1122    mTransform->GetProxy().SetReceiver(this);
   1123    mTransform->SetClaimed();
   1124  }
   1125 }
   1126 
   1127 void RTCRtpReceiver::RequestKeyFrame() {
   1128  if (!mTransform || !mPipeline) {
   1129    return;
   1130  }
   1131 
   1132  mPipeline->mConduit->AsVideoSessionConduit().apply([&](const auto& conduit) {
   1133    conduit->RequestKeyFrame(&mTransform->GetProxy());
   1134  });
   1135 }
   1136 
   1137 const RTCStatsTimestampMaker* RTCRtpReceiver::GetTimestampMaker() const {
   1138  if (!mPc) {
   1139    return nullptr;
   1140  }
   1141  return &mPc->GetTimestampMaker();
   1142 }
   1143 
   1144 Maybe<gfx::IntSize> RTCRtpReceiver::ReceivingSize() const {
   1145  MOZ_ASSERT(NS_IsMainThread());
   1146  MOZ_ASSERT_IF(mPipeline,
   1147                mPipeline->mConduit->type() == MediaSessionConduit::VIDEO);
   1148  return mReceivingSize.Ref();
   1149 }
   1150 
   1151 }  // namespace mozilla::dom
   1152 
   1153 #undef LOGTAG