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