Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 53 #include "webrtc/video/send_delay_stats.h" | 53 #include "webrtc/video/send_delay_stats.h" |
| 54 #include "webrtc/video/stats_counter.h" | 54 #include "webrtc/video/stats_counter.h" |
| 55 #include "webrtc/video/video_receive_stream.h" | 55 #include "webrtc/video/video_receive_stream.h" |
| 56 #include "webrtc/video/video_send_stream.h" | 56 #include "webrtc/video/video_send_stream.h" |
| 57 #include "webrtc/video/vie_remb.h" | 57 #include "webrtc/video/vie_remb.h" |
| 58 | 58 |
| 59 namespace webrtc { | 59 namespace webrtc { |
| 60 | 60 |
| 61 const int Call::Config::kDefaultStartBitrateBps = 300000; | 61 const int Call::Config::kDefaultStartBitrateBps = 300000; |
| 62 | 62 |
| 63 namespace { | |
| 64 | |
| 65 // TODO(nisse): This really begs for a shared context struct. | |
| 66 bool UseSendSideBwe(const std::vector<RtpExtension>& extensions, | |
| 67 bool transport_cc) { | |
| 68 if (!transport_cc) | |
| 69 return false; | |
| 70 for (const auto& extension : extensions) { | |
| 71 if (extension.uri == RtpExtension::kTransportSequenceNumberUri) | |
| 72 return true; | |
| 73 } | |
| 74 return false; | |
| 75 } | |
| 76 | |
| 77 bool UseSendSideBwe(const VideoReceiveStream::Config& config) { | |
| 78 return UseSendSideBwe(config.rtp.extensions, config.rtp.transport_cc); | |
| 79 } | |
| 80 | |
| 81 bool UseSendSideBwe(const AudioReceiveStream::Config& config) { | |
| 82 return UseSendSideBwe(config.rtp.extensions, config.rtp.transport_cc); | |
| 83 } | |
| 84 | |
| 85 bool UseSendSideBwe(const FlexfecReceiveStream::Config& config) { | |
| 86 return UseSendSideBwe(config.rtp_header_extensions, config.transport_cc); | |
| 87 } | |
| 88 | |
| 89 } // namespace | |
| 90 | |
| 91 namespace internal { | 63 namespace internal { |
| 92 | 64 |
| 93 class Call : public webrtc::Call, | 65 class Call : public webrtc::Call, |
| 94 public PacketReceiver, | 66 public PacketReceiver, |
| 95 public RecoveredPacketReceiver, | 67 public RecoveredPacketReceiver, |
| 96 public CongestionController::Observer, | 68 public CongestionController::Observer, |
| 97 public BitrateAllocator::LimitObserver { | 69 public BitrateAllocator::LimitObserver { |
| 98 public: | 70 public: |
| 99 explicit Call(const Call::Config& config); | 71 explicit Call(const Call::Config& config); |
| 100 virtual ~Call(); | 72 virtual ~Call(); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 165 DeliveryStatus DeliverRtcp(MediaType media_type, const uint8_t* packet, | 137 DeliveryStatus DeliverRtcp(MediaType media_type, const uint8_t* packet, |
| 166 size_t length); | 138 size_t length); |
| 167 DeliveryStatus DeliverRtp(MediaType media_type, | 139 DeliveryStatus DeliverRtp(MediaType media_type, |
| 168 const uint8_t* packet, | 140 const uint8_t* packet, |
| 169 size_t length, | 141 size_t length, |
| 170 const PacketTime& packet_time); | 142 const PacketTime& packet_time); |
| 171 void ConfigureSync(const std::string& sync_group) | 143 void ConfigureSync(const std::string& sync_group) |
| 172 EXCLUSIVE_LOCKS_REQUIRED(receive_crit_); | 144 EXCLUSIVE_LOCKS_REQUIRED(receive_crit_); |
| 173 | 145 |
| 174 void NotifyBweOfReceivedPacket(const RtpPacketReceived& packet, | 146 void NotifyBweOfReceivedPacket(const RtpPacketReceived& packet, |
| 175 MediaType media_type) | 147 MediaType media_type, |
| 176 SHARED_LOCKS_REQUIRED(receive_crit_); | 148 bool use_send_side_bwe) |
| 177 | |
| 178 rtc::Optional<RtpPacketReceived> ParseRtpPacket(const uint8_t* packet, | |
| 179 size_t length, | |
| 180 const PacketTime& packet_time) | |
| 181 SHARED_LOCKS_REQUIRED(receive_crit_); | 149 SHARED_LOCKS_REQUIRED(receive_crit_); |
| 182 | 150 |
| 183 void UpdateSendHistograms() EXCLUSIVE_LOCKS_REQUIRED(&bitrate_crit_); | 151 void UpdateSendHistograms() EXCLUSIVE_LOCKS_REQUIRED(&bitrate_crit_); |
| 184 void UpdateReceiveHistograms(); | 152 void UpdateReceiveHistograms(); |
| 185 void UpdateHistograms(); | 153 void UpdateHistograms(); |
| 186 void UpdateAggregateNetworkState(); | 154 void UpdateAggregateNetworkState(); |
| 187 | 155 |
| 188 Clock* const clock_; | 156 Clock* const clock_; |
| 189 | 157 |
| 190 const int num_cpu_cores_; | 158 const int num_cpu_cores_; |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 211 // streams. | 179 // streams. |
| 212 std::multimap<uint32_t, FlexfecReceiveStreamImpl*> | 180 std::multimap<uint32_t, FlexfecReceiveStreamImpl*> |
| 213 flexfec_receive_ssrcs_media_ GUARDED_BY(receive_crit_); | 181 flexfec_receive_ssrcs_media_ GUARDED_BY(receive_crit_); |
| 214 std::map<uint32_t, FlexfecReceiveStreamImpl*> | 182 std::map<uint32_t, FlexfecReceiveStreamImpl*> |
| 215 flexfec_receive_ssrcs_protection_ GUARDED_BY(receive_crit_); | 183 flexfec_receive_ssrcs_protection_ GUARDED_BY(receive_crit_); |
| 216 std::set<FlexfecReceiveStreamImpl*> flexfec_receive_streams_ | 184 std::set<FlexfecReceiveStreamImpl*> flexfec_receive_streams_ |
| 217 GUARDED_BY(receive_crit_); | 185 GUARDED_BY(receive_crit_); |
| 218 std::map<std::string, AudioReceiveStream*> sync_stream_mapping_ | 186 std::map<std::string, AudioReceiveStream*> sync_stream_mapping_ |
| 219 GUARDED_BY(receive_crit_); | 187 GUARDED_BY(receive_crit_); |
| 220 | 188 |
| 221 // This extra map is used for receive processing which is | |
| 222 // independent of media type. | |
| 223 | |
| 224 // TODO(nisse): In the RTP transport refactoring, we should have a | |
| 225 // single mapping from ssrc to a more abstract receive stream, with | |
| 226 // accessor methods for all configuration we need at this level. | |
| 227 struct ReceiveRtpConfig { | |
| 228 ReceiveRtpConfig() = default; // Needed by std::map | |
| 229 ReceiveRtpConfig(const std::vector<RtpExtension>& extensions, | |
| 230 bool use_send_side_bwe) | |
| 231 : extensions(extensions), use_send_side_bwe(use_send_side_bwe) {} | |
| 232 | |
| 233 // Registered RTP header extensions for each stream. Note that RTP header | |
| 234 // extensions are negotiated per track ("m= line") in the SDP, but we have | |
| 235 // no notion of tracks at the Call level. We therefore store the RTP header | |
| 236 // extensions per SSRC instead, which leads to some storage overhead. | |
| 237 RtpHeaderExtensionMap extensions; | |
| 238 // Set if both RTP extension the RTCP feedback message needed for | |
| 239 // send side BWE are negotiated. | |
| 240 bool use_send_side_bwe = false; | |
| 241 }; | |
| 242 std::map<uint32_t, ReceiveRtpConfig> receive_rtp_config_ | |
| 243 GUARDED_BY(receive_crit_); | |
| 244 | |
| 245 std::unique_ptr<RWLockWrapper> send_crit_; | 189 std::unique_ptr<RWLockWrapper> send_crit_; |
| 246 // Audio and Video send streams are owned by the client that creates them. | 190 // Audio and Video send streams are owned by the client that creates them. |
| 247 std::map<uint32_t, AudioSendStream*> audio_send_ssrcs_ GUARDED_BY(send_crit_); | 191 std::map<uint32_t, AudioSendStream*> audio_send_ssrcs_ GUARDED_BY(send_crit_); |
| 248 std::map<uint32_t, VideoSendStream*> video_send_ssrcs_ GUARDED_BY(send_crit_); | 192 std::map<uint32_t, VideoSendStream*> video_send_ssrcs_ GUARDED_BY(send_crit_); |
| 249 std::set<VideoSendStream*> video_send_streams_ GUARDED_BY(send_crit_); | 193 std::set<VideoSendStream*> video_send_streams_ GUARDED_BY(send_crit_); |
| 250 | 194 |
| 251 VideoSendStream::RtpStateMap suspended_video_send_ssrcs_; | 195 VideoSendStream::RtpStateMap suspended_video_send_ssrcs_; |
| 252 webrtc::RtcEventLog* event_log_; | 196 webrtc::RtcEventLog* event_log_; |
| 253 | 197 |
| 254 // The following members are only accessed (exclusively) from one thread and | 198 // The following members are only accessed (exclusively) from one thread and |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 388 { | 332 { |
| 389 rtc::CritScope lock(&bitrate_crit_); | 333 rtc::CritScope lock(&bitrate_crit_); |
| 390 UpdateSendHistograms(); | 334 UpdateSendHistograms(); |
| 391 } | 335 } |
| 392 UpdateReceiveHistograms(); | 336 UpdateReceiveHistograms(); |
| 393 UpdateHistograms(); | 337 UpdateHistograms(); |
| 394 | 338 |
| 395 Trace::ReturnTrace(); | 339 Trace::ReturnTrace(); |
| 396 } | 340 } |
| 397 | 341 |
| 398 rtc::Optional<RtpPacketReceived> Call::ParseRtpPacket( | |
| 399 const uint8_t* packet, | |
| 400 size_t length, | |
| 401 const PacketTime& packet_time) { | |
| 402 RtpPacketReceived parsed_packet; | |
| 403 if (!parsed_packet.Parse(packet, length)) | |
| 404 return rtc::Optional<RtpPacketReceived>(); | |
| 405 | |
| 406 auto it = receive_rtp_config_.find(parsed_packet.Ssrc()); | |
| 407 if (it != receive_rtp_config_.end()) | |
| 408 parsed_packet.IdentifyExtensions(it->second.extensions); | |
| 409 | |
| 410 int64_t arrival_time_ms; | |
| 411 if (packet_time.timestamp != -1) { | |
| 412 arrival_time_ms = (packet_time.timestamp + 500) / 1000; | |
| 413 } else { | |
| 414 arrival_time_ms = clock_->TimeInMilliseconds(); | |
| 415 } | |
| 416 parsed_packet.set_arrival_time_ms(arrival_time_ms); | |
| 417 | |
| 418 return rtc::Optional<RtpPacketReceived>(std::move(parsed_packet)); | |
| 419 } | |
| 420 | |
| 421 void Call::UpdateHistograms() { | 342 void Call::UpdateHistograms() { |
| 422 RTC_HISTOGRAM_COUNTS_100000( | 343 RTC_HISTOGRAM_COUNTS_100000( |
| 423 "WebRTC.Call.LifetimeInSeconds", | 344 "WebRTC.Call.LifetimeInSeconds", |
| 424 (clock_->TimeInMilliseconds() - start_ms_) / 1000); | 345 (clock_->TimeInMilliseconds() - start_ms_) / 1000); |
| 425 } | 346 } |
| 426 | 347 |
| 427 void Call::UpdateSendHistograms() { | 348 void Call::UpdateSendHistograms() { |
| 428 if (first_packet_sent_ms_ == -1) | 349 if (first_packet_sent_ms_ == -1) |
| 429 return; | 350 return; |
| 430 int64_t elapsed_sec = | 351 int64_t elapsed_sec = |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 554 RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); | 475 RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); |
| 555 event_log_->LogAudioReceiveStreamConfig(config); | 476 event_log_->LogAudioReceiveStreamConfig(config); |
| 556 AudioReceiveStream* receive_stream = new AudioReceiveStream( | 477 AudioReceiveStream* receive_stream = new AudioReceiveStream( |
| 557 &packet_router_, config, | 478 &packet_router_, config, |
| 558 config_.audio_state, event_log_); | 479 config_.audio_state, event_log_); |
| 559 { | 480 { |
| 560 WriteLockScoped write_lock(*receive_crit_); | 481 WriteLockScoped write_lock(*receive_crit_); |
| 561 RTC_DCHECK(audio_receive_ssrcs_.find(config.rtp.remote_ssrc) == | 482 RTC_DCHECK(audio_receive_ssrcs_.find(config.rtp.remote_ssrc) == |
| 562 audio_receive_ssrcs_.end()); | 483 audio_receive_ssrcs_.end()); |
| 563 audio_receive_ssrcs_[config.rtp.remote_ssrc] = receive_stream; | 484 audio_receive_ssrcs_[config.rtp.remote_ssrc] = receive_stream; |
| 564 receive_rtp_config_[config.rtp.remote_ssrc] = | |
| 565 ReceiveRtpConfig(config.rtp.extensions, UseSendSideBwe(config)); | |
| 566 | 485 |
| 567 ConfigureSync(config.sync_group); | 486 ConfigureSync(config.sync_group); |
| 568 } | 487 } |
| 569 { | 488 { |
| 570 ReadLockScoped read_lock(*send_crit_); | 489 ReadLockScoped read_lock(*send_crit_); |
| 571 auto it = audio_send_ssrcs_.find(config.rtp.local_ssrc); | 490 auto it = audio_send_ssrcs_.find(config.rtp.local_ssrc); |
| 572 if (it != audio_send_ssrcs_.end()) { | 491 if (it != audio_send_ssrcs_.end()) { |
| 573 receive_stream->AssociateSendStream(it->second); | 492 receive_stream->AssociateSendStream(it->second); |
| 574 } | 493 } |
| 575 } | 494 } |
| 576 receive_stream->SignalNetworkState(audio_network_state_); | 495 receive_stream->SignalNetworkState(audio_network_state_); |
| 577 UpdateAggregateNetworkState(); | 496 UpdateAggregateNetworkState(); |
| 578 return receive_stream; | 497 return receive_stream; |
| 579 } | 498 } |
| 580 | 499 |
| 581 void Call::DestroyAudioReceiveStream( | 500 void Call::DestroyAudioReceiveStream( |
| 582 webrtc::AudioReceiveStream* receive_stream) { | 501 webrtc::AudioReceiveStream* receive_stream) { |
| 583 TRACE_EVENT0("webrtc", "Call::DestroyAudioReceiveStream"); | 502 TRACE_EVENT0("webrtc", "Call::DestroyAudioReceiveStream"); |
| 584 RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); | 503 RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); |
| 585 RTC_DCHECK(receive_stream != nullptr); | 504 RTC_DCHECK(receive_stream != nullptr); |
| 586 webrtc::internal::AudioReceiveStream* audio_receive_stream = | 505 webrtc::internal::AudioReceiveStream* audio_receive_stream = |
| 587 static_cast<webrtc::internal::AudioReceiveStream*>(receive_stream); | 506 static_cast<webrtc::internal::AudioReceiveStream*>(receive_stream); |
| 588 { | 507 { |
| 589 WriteLockScoped write_lock(*receive_crit_); | 508 WriteLockScoped write_lock(*receive_crit_); |
| 590 const AudioReceiveStream::Config& config = audio_receive_stream->config(); | 509 const AudioReceiveStream::Config& config = audio_receive_stream->config(); |
| 591 uint32_t ssrc = config.rtp.remote_ssrc; | 510 uint32_t ssrc = config.rtp.remote_ssrc; |
| 592 congestion_controller_->GetRemoteBitrateEstimator(UseSendSideBwe(config)) | 511 congestion_controller_->GetRemoteBitrateEstimator( |
| 512 audio_receive_stream->rtp_config().use_send_side_bwe) | |
| 593 ->RemoveStream(ssrc); | 513 ->RemoveStream(ssrc); |
| 594 size_t num_deleted = audio_receive_ssrcs_.erase(ssrc); | 514 size_t num_deleted = audio_receive_ssrcs_.erase(ssrc); |
| 595 RTC_DCHECK(num_deleted == 1); | 515 RTC_DCHECK(num_deleted == 1); |
| 596 const std::string& sync_group = audio_receive_stream->config().sync_group; | 516 const std::string& sync_group = audio_receive_stream->config().sync_group; |
| 597 const auto it = sync_stream_mapping_.find(sync_group); | 517 const auto it = sync_stream_mapping_.find(sync_group); |
| 598 if (it != sync_stream_mapping_.end() && | 518 if (it != sync_stream_mapping_.end() && |
| 599 it->second == audio_receive_stream) { | 519 it->second == audio_receive_stream) { |
| 600 sync_stream_mapping_.erase(it); | 520 sync_stream_mapping_.erase(it); |
| 601 ConfigureSync(sync_group); | 521 ConfigureSync(sync_group); |
| 602 } | 522 } |
| 603 receive_rtp_config_.erase(ssrc); | |
| 604 } | 523 } |
| 605 UpdateAggregateNetworkState(); | 524 UpdateAggregateNetworkState(); |
| 606 delete audio_receive_stream; | 525 delete audio_receive_stream; |
| 607 } | 526 } |
| 608 | 527 |
| 609 webrtc::VideoSendStream* Call::CreateVideoSendStream( | 528 webrtc::VideoSendStream* Call::CreateVideoSendStream( |
| 610 webrtc::VideoSendStream::Config config, | 529 webrtc::VideoSendStream::Config config, |
| 611 VideoEncoderConfig encoder_config) { | 530 VideoEncoderConfig encoder_config) { |
| 612 TRACE_EVENT0("webrtc", "Call::CreateVideoSendStream"); | 531 TRACE_EVENT0("webrtc", "Call::CreateVideoSendStream"); |
| 613 RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); | 532 RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 686 protected_by_flexfec = | 605 protected_by_flexfec = |
| 687 flexfec_receive_ssrcs_media_.find(configuration.rtp.remote_ssrc) != | 606 flexfec_receive_ssrcs_media_.find(configuration.rtp.remote_ssrc) != |
| 688 flexfec_receive_ssrcs_media_.end(); | 607 flexfec_receive_ssrcs_media_.end(); |
| 689 } | 608 } |
| 690 VideoReceiveStream* receive_stream = new VideoReceiveStream( | 609 VideoReceiveStream* receive_stream = new VideoReceiveStream( |
| 691 num_cpu_cores_, protected_by_flexfec, | 610 num_cpu_cores_, protected_by_flexfec, |
| 692 &packet_router_, std::move(configuration), module_process_thread_.get(), | 611 &packet_router_, std::move(configuration), module_process_thread_.get(), |
| 693 call_stats_.get(), &remb_); | 612 call_stats_.get(), &remb_); |
| 694 | 613 |
| 695 const webrtc::VideoReceiveStream::Config& config = receive_stream->config(); | 614 const webrtc::VideoReceiveStream::Config& config = receive_stream->config(); |
| 696 ReceiveRtpConfig receive_config(config.rtp.extensions, | |
| 697 UseSendSideBwe(config)); | |
| 698 { | 615 { |
| 699 WriteLockScoped write_lock(*receive_crit_); | 616 WriteLockScoped write_lock(*receive_crit_); |
| 700 RTC_DCHECK(video_receive_ssrcs_.find(config.rtp.remote_ssrc) == | 617 RTC_DCHECK(video_receive_ssrcs_.find(config.rtp.remote_ssrc) == |
| 701 video_receive_ssrcs_.end()); | 618 video_receive_ssrcs_.end()); |
| 702 video_receive_ssrcs_[config.rtp.remote_ssrc] = receive_stream; | 619 video_receive_ssrcs_[config.rtp.remote_ssrc] = receive_stream; |
| 703 if (config.rtp.rtx_ssrc) { | 620 if (config.rtp.rtx_ssrc) { |
| 704 video_receive_ssrcs_[config.rtp.rtx_ssrc] = receive_stream; | 621 video_receive_ssrcs_[config.rtp.rtx_ssrc] = receive_stream; |
| 705 // We record identical config for the rtx stream as for the main | |
| 706 // stream. Since the transport_cc negotiation is per payload | |
| 707 // type, we may get an incorrect value for the rtx stream, but | |
| 708 // that is unlikely to matter in practice. | |
| 709 receive_rtp_config_[config.rtp.rtx_ssrc] = receive_config; | |
| 710 } | 622 } |
| 711 receive_rtp_config_[config.rtp.remote_ssrc] = receive_config; | |
| 712 video_receive_streams_.insert(receive_stream); | 623 video_receive_streams_.insert(receive_stream); |
| 713 ConfigureSync(config.sync_group); | 624 ConfigureSync(config.sync_group); |
| 714 } | 625 } |
| 715 receive_stream->SignalNetworkState(video_network_state_); | 626 receive_stream->SignalNetworkState(video_network_state_); |
| 716 UpdateAggregateNetworkState(); | 627 UpdateAggregateNetworkState(); |
| 717 event_log_->LogVideoReceiveStreamConfig(config); | 628 event_log_->LogVideoReceiveStreamConfig(config); |
| 718 return receive_stream; | 629 return receive_stream; |
| 719 } | 630 } |
| 720 | 631 |
| 721 void Call::DestroyVideoReceiveStream( | 632 void Call::DestroyVideoReceiveStream( |
| 722 webrtc::VideoReceiveStream* receive_stream) { | 633 webrtc::VideoReceiveStream* receive_stream) { |
| 723 TRACE_EVENT0("webrtc", "Call::DestroyVideoReceiveStream"); | 634 TRACE_EVENT0("webrtc", "Call::DestroyVideoReceiveStream"); |
| 724 RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); | 635 RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); |
| 725 RTC_DCHECK(receive_stream != nullptr); | 636 RTC_DCHECK(receive_stream != nullptr); |
| 726 VideoReceiveStream* receive_stream_impl = nullptr; | 637 VideoReceiveStream* receive_stream_impl = nullptr; |
| 727 { | 638 { |
| 728 WriteLockScoped write_lock(*receive_crit_); | 639 WriteLockScoped write_lock(*receive_crit_); |
| 729 // Remove all ssrcs pointing to a receive stream. As RTX retransmits on a | 640 // Remove all ssrcs pointing to a receive stream. As RTX retransmits on a |
| 730 // separate SSRC there can be either one or two. | 641 // separate SSRC there can be either one or two. |
| 731 auto it = video_receive_ssrcs_.begin(); | 642 auto it = video_receive_ssrcs_.begin(); |
| 732 while (it != video_receive_ssrcs_.end()) { | 643 while (it != video_receive_ssrcs_.end()) { |
| 733 if (it->second == static_cast<VideoReceiveStream*>(receive_stream)) { | 644 if (it->second == static_cast<VideoReceiveStream*>(receive_stream)) { |
| 734 if (receive_stream_impl != nullptr) | 645 if (receive_stream_impl != nullptr) |
| 735 RTC_DCHECK(receive_stream_impl == it->second); | 646 RTC_DCHECK(receive_stream_impl == it->second); |
| 736 receive_stream_impl = it->second; | 647 receive_stream_impl = it->second; |
| 737 receive_rtp_config_.erase(it->first); | |
| 738 it = video_receive_ssrcs_.erase(it); | 648 it = video_receive_ssrcs_.erase(it); |
| 739 } else { | 649 } else { |
| 740 ++it; | 650 ++it; |
| 741 } | 651 } |
| 742 } | 652 } |
| 743 video_receive_streams_.erase(receive_stream_impl); | 653 video_receive_streams_.erase(receive_stream_impl); |
| 744 RTC_CHECK(receive_stream_impl != nullptr); | 654 RTC_CHECK(receive_stream_impl != nullptr); |
| 745 ConfigureSync(receive_stream_impl->config().sync_group); | 655 ConfigureSync(receive_stream_impl->config().sync_group); |
| 746 } | 656 } |
| 747 const VideoReceiveStream::Config& config = receive_stream_impl->config(); | 657 const VideoReceiveStream::Config& config = receive_stream_impl->config(); |
| 748 | 658 |
| 749 congestion_controller_->GetRemoteBitrateEstimator(UseSendSideBwe(config)) | 659 congestion_controller_->GetRemoteBitrateEstimator( |
| 660 receive_stream_impl->rtp_config().use_send_side_bwe) | |
| 750 ->RemoveStream(config.rtp.remote_ssrc); | 661 ->RemoveStream(config.rtp.remote_ssrc); |
| 751 | 662 |
| 752 UpdateAggregateNetworkState(); | 663 UpdateAggregateNetworkState(); |
| 753 delete receive_stream_impl; | 664 delete receive_stream_impl; |
| 754 } | 665 } |
| 755 | 666 |
| 756 FlexfecReceiveStream* Call::CreateFlexfecReceiveStream( | 667 FlexfecReceiveStream* Call::CreateFlexfecReceiveStream( |
| 757 const FlexfecReceiveStream::Config& config) { | 668 const FlexfecReceiveStream::Config& config) { |
| 758 TRACE_EVENT0("webrtc", "Call::CreateFlexfecReceiveStream"); | 669 TRACE_EVENT0("webrtc", "Call::CreateFlexfecReceiveStream"); |
| 759 RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); | 670 RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); |
| 760 | 671 |
| 761 RecoveredPacketReceiver* recovered_packet_receiver = this; | 672 RecoveredPacketReceiver* recovered_packet_receiver = this; |
| 762 FlexfecReceiveStreamImpl* receive_stream = new FlexfecReceiveStreamImpl( | 673 FlexfecReceiveStreamImpl* receive_stream = new FlexfecReceiveStreamImpl( |
| 763 config, recovered_packet_receiver, call_stats_->rtcp_rtt_stats(), | 674 config, recovered_packet_receiver, call_stats_->rtcp_rtt_stats(), |
| 764 module_process_thread_.get()); | 675 module_process_thread_.get()); |
| 765 | 676 |
| 766 { | 677 { |
| 767 WriteLockScoped write_lock(*receive_crit_); | 678 WriteLockScoped write_lock(*receive_crit_); |
| 768 | 679 |
| 769 RTC_DCHECK(flexfec_receive_streams_.find(receive_stream) == | 680 RTC_DCHECK(flexfec_receive_streams_.find(receive_stream) == |
| 770 flexfec_receive_streams_.end()); | 681 flexfec_receive_streams_.end()); |
| 771 flexfec_receive_streams_.insert(receive_stream); | 682 flexfec_receive_streams_.insert(receive_stream); |
| 772 | 683 |
| 773 for (auto ssrc : config.protected_media_ssrcs) | 684 for (auto ssrc : config.protected_media_ssrcs) |
| 774 flexfec_receive_ssrcs_media_.insert(std::make_pair(ssrc, receive_stream)); | 685 flexfec_receive_ssrcs_media_.insert(std::make_pair(ssrc, receive_stream)); |
| 775 | 686 |
| 776 RTC_DCHECK(flexfec_receive_ssrcs_protection_.find(config.remote_ssrc) == | 687 RTC_DCHECK(flexfec_receive_ssrcs_protection_.find(config.remote_ssrc) == |
| 777 flexfec_receive_ssrcs_protection_.end()); | 688 flexfec_receive_ssrcs_protection_.end()); |
| 778 flexfec_receive_ssrcs_protection_[config.remote_ssrc] = receive_stream; | 689 flexfec_receive_ssrcs_protection_[config.remote_ssrc] = receive_stream; |
| 779 | |
| 780 RTC_DCHECK(receive_rtp_config_.find(config.remote_ssrc) == | |
| 781 receive_rtp_config_.end()); | |
| 782 receive_rtp_config_[config.remote_ssrc] = | |
| 783 ReceiveRtpConfig(config.rtp_header_extensions, UseSendSideBwe(config)); | |
| 784 } | 690 } |
| 785 | 691 |
| 786 // TODO(brandtr): Store config in RtcEventLog here. | 692 // TODO(brandtr): Store config in RtcEventLog here. |
| 787 | 693 |
| 788 return receive_stream; | 694 return receive_stream; |
| 789 } | 695 } |
| 790 | 696 |
| 791 void Call::DestroyFlexfecReceiveStream(FlexfecReceiveStream* receive_stream) { | 697 void Call::DestroyFlexfecReceiveStream(FlexfecReceiveStream* receive_stream) { |
| 792 TRACE_EVENT0("webrtc", "Call::DestroyFlexfecReceiveStream"); | 698 TRACE_EVENT0("webrtc", "Call::DestroyFlexfecReceiveStream"); |
| 793 RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); | 699 RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); |
| 794 | 700 |
| 795 RTC_DCHECK(receive_stream != nullptr); | 701 RTC_DCHECK(receive_stream != nullptr); |
| 796 // There exist no other derived classes of FlexfecReceiveStream, | 702 // There exist no other derived classes of FlexfecReceiveStream, |
| 797 // so this downcast is safe. | 703 // so this downcast is safe. |
| 798 FlexfecReceiveStreamImpl* receive_stream_impl = | 704 FlexfecReceiveStreamImpl* receive_stream_impl = |
| 799 static_cast<FlexfecReceiveStreamImpl*>(receive_stream); | 705 static_cast<FlexfecReceiveStreamImpl*>(receive_stream); |
| 800 { | 706 { |
| 801 WriteLockScoped write_lock(*receive_crit_); | 707 WriteLockScoped write_lock(*receive_crit_); |
| 802 | 708 |
| 803 const FlexfecReceiveStream::Config& config = | 709 const FlexfecReceiveStream::Config& config = |
| 804 receive_stream_impl->GetConfig(); | 710 receive_stream_impl->GetConfig(); |
| 805 uint32_t ssrc = config.remote_ssrc; | 711 uint32_t ssrc = config.remote_ssrc; |
| 806 receive_rtp_config_.erase(ssrc); | |
| 807 | 712 |
| 808 // Remove all SSRCs pointing to the FlexfecReceiveStreamImpl to be | 713 // Remove all SSRCs pointing to the FlexfecReceiveStreamImpl to be |
| 809 // destroyed. | 714 // destroyed. |
| 810 auto prot_it = flexfec_receive_ssrcs_protection_.begin(); | 715 auto prot_it = flexfec_receive_ssrcs_protection_.begin(); |
| 811 while (prot_it != flexfec_receive_ssrcs_protection_.end()) { | 716 while (prot_it != flexfec_receive_ssrcs_protection_.end()) { |
| 812 if (prot_it->second == receive_stream_impl) | 717 if (prot_it->second == receive_stream_impl) |
| 813 prot_it = flexfec_receive_ssrcs_protection_.erase(prot_it); | 718 prot_it = flexfec_receive_ssrcs_protection_.erase(prot_it); |
| 814 else | 719 else |
| 815 ++prot_it; | 720 ++prot_it; |
| 816 } | 721 } |
| 817 auto media_it = flexfec_receive_ssrcs_media_.begin(); | 722 auto media_it = flexfec_receive_ssrcs_media_.begin(); |
| 818 while (media_it != flexfec_receive_ssrcs_media_.end()) { | 723 while (media_it != flexfec_receive_ssrcs_media_.end()) { |
| 819 if (media_it->second == receive_stream_impl) | 724 if (media_it->second == receive_stream_impl) |
| 820 media_it = flexfec_receive_ssrcs_media_.erase(media_it); | 725 media_it = flexfec_receive_ssrcs_media_.erase(media_it); |
| 821 else | 726 else |
| 822 ++media_it; | 727 ++media_it; |
| 823 } | 728 } |
| 824 | 729 |
| 825 congestion_controller_->GetRemoteBitrateEstimator(UseSendSideBwe(config)) | 730 congestion_controller_->GetRemoteBitrateEstimator( |
| 731 receive_stream_impl->rtp_config().use_send_side_bwe) | |
| 826 ->RemoveStream(ssrc); | 732 ->RemoveStream(ssrc); |
| 827 | 733 |
| 828 flexfec_receive_streams_.erase(receive_stream_impl); | 734 flexfec_receive_streams_.erase(receive_stream_impl); |
| 829 } | 735 } |
| 830 | 736 |
| 831 delete receive_stream_impl; | 737 delete receive_stream_impl; |
| 832 } | 738 } |
| 833 | 739 |
| 834 Call::Stats Call::GetStats() const { | 740 Call::Stats Call::GetStats() const { |
| 835 // TODO(solenberg): Some test cases in EndToEndTest use this from a different | 741 // TODO(solenberg): Some test cases in EndToEndTest use this from a different |
| (...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1173 | 1079 |
| 1174 return rtcp_delivered ? DELIVERY_OK : DELIVERY_PACKET_ERROR; | 1080 return rtcp_delivered ? DELIVERY_OK : DELIVERY_PACKET_ERROR; |
| 1175 } | 1081 } |
| 1176 | 1082 |
| 1177 PacketReceiver::DeliveryStatus Call::DeliverRtp(MediaType media_type, | 1083 PacketReceiver::DeliveryStatus Call::DeliverRtp(MediaType media_type, |
| 1178 const uint8_t* packet, | 1084 const uint8_t* packet, |
| 1179 size_t length, | 1085 size_t length, |
| 1180 const PacketTime& packet_time) { | 1086 const PacketTime& packet_time) { |
| 1181 TRACE_EVENT0("webrtc", "Call::DeliverRtp"); | 1087 TRACE_EVENT0("webrtc", "Call::DeliverRtp"); |
| 1182 | 1088 |
| 1089 RtpPacketReceived parsed_packet; | |
| 1090 if (!parsed_packet.Parse(packet, length)) | |
| 1091 return DELIVERY_PACKET_ERROR; | |
| 1092 uint32_t ssrc = parsed_packet.Ssrc(); | |
| 1093 | |
| 1183 ReadLockScoped read_lock(*receive_crit_); | 1094 ReadLockScoped read_lock(*receive_crit_); |
| 1184 // TODO(nisse): We should parse the RTP header only here, and pass | |
| 1185 // on parsed_packet to the receive streams. | |
| 1186 rtc::Optional<RtpPacketReceived> parsed_packet = | |
| 1187 ParseRtpPacket(packet, length, packet_time); | |
| 1188 | 1095 |
| 1189 if (!parsed_packet) | 1096 // Look up receiver, so we can parse extensions properly. |
| 1190 return DELIVERY_PACKET_ERROR; | 1097 RtpPacketReceiver* receiver = nullptr; |
| 1191 | 1098 bool pass_to_flexfec = false; |
| 1192 NotifyBweOfReceivedPacket(*parsed_packet, media_type); | |
| 1193 | |
| 1194 uint32_t ssrc = parsed_packet->Ssrc(); | |
| 1195 | 1099 |
| 1196 if (media_type == MediaType::ANY || media_type == MediaType::AUDIO) { | 1100 if (media_type == MediaType::ANY || media_type == MediaType::AUDIO) { |
| 1197 auto it = audio_receive_ssrcs_.find(ssrc); | 1101 auto it = audio_receive_ssrcs_.find(ssrc); |
| 1198 if (it != audio_receive_ssrcs_.end()) { | 1102 if (it != audio_receive_ssrcs_.end()) { |
| 1199 received_bytes_per_second_counter_.Add(static_cast<int>(length)); | 1103 received_bytes_per_second_counter_.Add(static_cast<int>(length)); |
| 1200 received_audio_bytes_per_second_counter_.Add(static_cast<int>(length)); | 1104 received_audio_bytes_per_second_counter_.Add(static_cast<int>(length)); |
| 1201 auto status = it->second->DeliverRtp(packet, length, packet_time) | 1105 receiver = it->second; |
| 1202 ? DELIVERY_OK | |
| 1203 : DELIVERY_PACKET_ERROR; | |
| 1204 if (status == DELIVERY_OK) | |
| 1205 event_log_->LogRtpHeader(kIncomingPacket, media_type, packet, length); | |
| 1206 return status; | |
| 1207 } | 1106 } |
| 1208 } | 1107 } |
| 1209 if (media_type == MediaType::ANY || media_type == MediaType::VIDEO) { | 1108 if (!receiver && |
| 1109 (media_type == MediaType::ANY || media_type == MediaType::VIDEO)) { | |
| 1210 auto it = video_receive_ssrcs_.find(ssrc); | 1110 auto it = video_receive_ssrcs_.find(ssrc); |
| 1211 if (it != video_receive_ssrcs_.end()) { | 1111 if (it != video_receive_ssrcs_.end()) { |
| 1212 received_bytes_per_second_counter_.Add(static_cast<int>(length)); | 1112 received_bytes_per_second_counter_.Add(static_cast<int>(length)); |
| 1213 received_video_bytes_per_second_counter_.Add(static_cast<int>(length)); | 1113 received_video_bytes_per_second_counter_.Add(static_cast<int>(length)); |
| 1214 // TODO(brandtr): Notify the BWE of received media packets here. | 1114 receiver = it->second; |
| 1215 auto status = it->second->DeliverRtp(packet, length, packet_time) | 1115 pass_to_flexfec = true; |
|
brandtr
2017/02/09 14:51:55
maybe_pass_to_flexfec
| |
| 1216 ? DELIVERY_OK | 1116 } else { |
| 1217 : DELIVERY_PACKET_ERROR; | 1117 auto it = flexfec_receive_ssrcs_protection_.find(ssrc); |
| 1218 // Deliver media packets to FlexFEC subsystem. RTP header extensions need | 1118 if (it != flexfec_receive_ssrcs_protection_.end()) { |
| 1219 // not be parsed, as FlexFEC is oblivious to the semantic meaning of the | 1119 receiver = it->second; |
| 1220 // packet contents beyond the 12 byte RTP base header. The BWE is fed | 1120 // TODO(nisse): Update received_bytes_per_second_counter_ ? |
|
brandtr
2017/02/09 14:51:55
Yes! This is an omission, the counters should be u
nisse-webrtc
2017/02/10 08:09:23
That's what you're fixing in
https://codereview.we
| |
| 1221 // information about these media packets from the regular media pipeline. | |
| 1222 if (parsed_packet) { | |
| 1223 auto it_bounds = flexfec_receive_ssrcs_media_.equal_range(ssrc); | |
| 1224 for (auto it = it_bounds.first; it != it_bounds.second; ++it) | |
| 1225 it->second->AddAndProcessReceivedPacket(*parsed_packet); | |
| 1226 } | |
| 1227 if (status == DELIVERY_OK) | |
| 1228 event_log_->LogRtpHeader(kIncomingPacket, media_type, packet, length); | |
| 1229 return status; | |
| 1230 } | |
| 1231 } | |
| 1232 if (media_type == MediaType::ANY || media_type == MediaType::VIDEO) { | |
| 1233 auto it = flexfec_receive_ssrcs_protection_.find(ssrc); | |
| 1234 if (it != flexfec_receive_ssrcs_protection_.end()) { | |
| 1235 if (parsed_packet) { | |
| 1236 auto status = it->second->AddAndProcessReceivedPacket(*parsed_packet) | |
| 1237 ? DELIVERY_OK | |
| 1238 : DELIVERY_PACKET_ERROR; | |
| 1239 if (status == DELIVERY_OK) | |
| 1240 event_log_->LogRtpHeader(kIncomingPacket, media_type, packet, length); | |
| 1241 return status; | |
| 1242 } | 1121 } |
| 1243 } | 1122 } |
| 1244 } | 1123 } |
| 1245 return DELIVERY_UNKNOWN_SSRC; | 1124 if (!receiver) |
| 1125 return DELIVERY_UNKNOWN_SSRC; | |
| 1126 | |
| 1127 parsed_packet.IdentifyExtensions(receiver->rtp_config().extensions); | |
| 1128 int64_t arrival_time_ms; | |
| 1129 if (packet_time.timestamp != -1) { | |
| 1130 arrival_time_ms = (packet_time.timestamp + 500) / 1000; | |
| 1131 } else { | |
| 1132 arrival_time_ms = clock_->TimeInMilliseconds(); | |
| 1133 } | |
| 1134 parsed_packet.set_arrival_time_ms(arrival_time_ms); | |
| 1135 | |
| 1136 NotifyBweOfReceivedPacket(parsed_packet, media_type, | |
| 1137 receiver->rtp_config().use_send_side_bwe); | |
| 1138 | |
| 1139 bool success = receiver->OnRtpPacket(parsed_packet); | |
| 1140 if (success) | |
| 1141 event_log_->LogRtpHeader(kIncomingPacket, media_type, packet, length); | |
| 1142 | |
| 1143 if (pass_to_flexfec) { | |
| 1144 // Deliver media packets to FlexFEC subsystem. RTP header extensions need | |
| 1145 // not be parsed, as FlexFEC is oblivious to the semantic meaning of the | |
| 1146 // packet contents beyond the 12 byte RTP base header. The BWE is fed | |
| 1147 // information about these media packets from the regular media pipeline. | |
| 1148 auto it_bounds = flexfec_receive_ssrcs_media_.equal_range(ssrc); | |
| 1149 for (auto it = it_bounds.first; it != it_bounds.second; ++it) | |
| 1150 it->second->OnRtpPacket(parsed_packet); | |
| 1151 } | |
| 1152 | |
| 1153 return success ? DELIVERY_OK : DELIVERY_PACKET_ERROR; | |
| 1246 } | 1154 } |
| 1247 | 1155 |
| 1248 PacketReceiver::DeliveryStatus Call::DeliverPacket( | 1156 PacketReceiver::DeliveryStatus Call::DeliverPacket( |
| 1249 MediaType media_type, | 1157 MediaType media_type, |
| 1250 const uint8_t* packet, | 1158 const uint8_t* packet, |
| 1251 size_t length, | 1159 size_t length, |
| 1252 const PacketTime& packet_time) { | 1160 const PacketTime& packet_time) { |
| 1253 // TODO(solenberg): Tests call this function on a network thread, libjingle | 1161 // TODO(solenberg): Tests call this function on a network thread, libjingle |
| 1254 // calls on the worker thread. We should move towards always using a network | 1162 // calls on the worker thread. We should move towards always using a network |
| 1255 // thread. Then this check can be enabled. | 1163 // thread. Then this check can be enabled. |
| 1256 // RTC_DCHECK(!configuration_thread_checker_.CalledOnValidThread()); | 1164 // RTC_DCHECK(!configuration_thread_checker_.CalledOnValidThread()); |
| 1257 if (RtpHeaderParser::IsRtcp(packet, length)) | 1165 if (RtpHeaderParser::IsRtcp(packet, length)) |
| 1258 return DeliverRtcp(media_type, packet, length); | 1166 return DeliverRtcp(media_type, packet, length); |
| 1259 | 1167 |
| 1260 return DeliverRtp(media_type, packet, length, packet_time); | 1168 return DeliverRtp(media_type, packet, length, packet_time); |
| 1261 } | 1169 } |
| 1262 | 1170 |
| 1263 // TODO(brandtr): Update this member function when we support protecting | 1171 // TODO(brandtr): Update this member function when we support protecting |
| 1264 // audio packets with FlexFEC. | 1172 // audio packets with FlexFEC. |
| 1265 bool Call::OnRecoveredPacket(const uint8_t* packet, size_t length) { | 1173 bool Call::OnRecoveredPacket(const uint8_t* packet, size_t length) { |
| 1266 uint32_t ssrc = ByteReader<uint32_t>::ReadBigEndian(&packet[8]); | 1174 uint32_t ssrc = ByteReader<uint32_t>::ReadBigEndian(&packet[8]); |
| 1267 ReadLockScoped read_lock(*receive_crit_); | 1175 ReadLockScoped read_lock(*receive_crit_); |
| 1268 auto it = video_receive_ssrcs_.find(ssrc); | 1176 auto it = video_receive_ssrcs_.find(ssrc); |
| 1269 if (it == video_receive_ssrcs_.end()) | 1177 if (it == video_receive_ssrcs_.end()) |
| 1270 return false; | 1178 return false; |
| 1271 return it->second->OnRecoveredPacket(packet, length); | 1179 return it->second->OnRecoveredPacket(packet, length); |
| 1272 } | 1180 } |
| 1273 | 1181 |
| 1274 void Call::NotifyBweOfReceivedPacket(const RtpPacketReceived& packet, | 1182 void Call::NotifyBweOfReceivedPacket(const RtpPacketReceived& packet, |
| 1275 MediaType media_type) { | 1183 MediaType media_type, |
| 1276 auto it = receive_rtp_config_.find(packet.Ssrc()); | 1184 bool use_send_side_bwe) { |
| 1277 bool use_send_side_bwe = | |
| 1278 (it != receive_rtp_config_.end()) && it->second.use_send_side_bwe; | |
| 1279 | |
| 1280 RTPHeader header; | 1185 RTPHeader header; |
| 1281 packet.GetHeader(&header); | 1186 packet.GetHeader(&header); |
| 1282 | 1187 |
| 1283 if (!use_send_side_bwe && header.extension.hasTransportSequenceNumber) { | 1188 if (!use_send_side_bwe && header.extension.hasTransportSequenceNumber) { |
| 1284 // Inconsistent configuration of send side BWE. Do nothing. | 1189 // Inconsistent configuration of send side BWE. Do nothing. |
| 1285 // TODO(nisse): Without this check, we may produce RTCP feedback | 1190 // TODO(nisse): Without this check, we may produce RTCP feedback |
| 1286 // packets even when not negotiated. But it would be cleaner to | 1191 // packets even when not negotiated. But it would be cleaner to |
| 1287 // move the check down to RTCPSender::SendFeedbackPacket, which | 1192 // move the check down to RTCPSender::SendFeedbackPacket, which |
| 1288 // would also help the PacketRouter to select an appropriate rtp | 1193 // would also help the PacketRouter to select an appropriate rtp |
| 1289 // module in the case that some, but not all, have RTCP feedback | 1194 // module in the case that some, but not all, have RTCP feedback |
| 1290 // enabled. | 1195 // enabled. |
| 1291 return; | 1196 return; |
| 1292 } | 1197 } |
| 1293 // For audio, we only support send side BWE. | 1198 // For audio, we only support send side BWE. |
| 1294 // TODO(nisse): Tests passes MediaType::ANY, see | 1199 // TODO(nisse): Tests passes MediaType::ANY, see |
| 1295 // FakeNetworkPipe::Process. We need to treat that as video. Tests | 1200 // FakeNetworkPipe::Process. We need to treat that as video. Tests |
| 1296 // should be fixed to use the same MediaType as the production code. | 1201 // should be fixed to use the same MediaType as the production code. |
| 1297 if (media_type != MediaType::AUDIO || | 1202 if (media_type != MediaType::AUDIO || |
| 1298 (use_send_side_bwe && header.extension.hasTransportSequenceNumber)) { | 1203 (use_send_side_bwe && header.extension.hasTransportSequenceNumber)) { |
| 1299 congestion_controller_->OnReceivedPacket( | 1204 congestion_controller_->OnReceivedPacket( |
| 1300 packet.arrival_time_ms(), packet.payload_size() + packet.padding_size(), | 1205 packet.arrival_time_ms(), packet.payload_size() + packet.padding_size(), |
| 1301 header); | 1206 header); |
| 1302 } | 1207 } |
| 1303 } | 1208 } |
| 1304 | 1209 |
| 1305 } // namespace internal | 1210 } // namespace internal |
| 1306 } // namespace webrtc | 1211 } // namespace webrtc |
| OLD | NEW |