Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2004 The WebRTC project authors. All Rights Reserved. | 2 * Copyright 2004 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 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 111 return direction == MD_SENDRECV || direction == MD_SENDONLY; | 111 return direction == MD_SENDRECV || direction == MD_SENDONLY; |
| 112 } | 112 } |
| 113 | 113 |
| 114 static const MediaContentDescription* GetContentDescription( | 114 static const MediaContentDescription* GetContentDescription( |
| 115 const ContentInfo* cinfo) { | 115 const ContentInfo* cinfo) { |
| 116 if (cinfo == NULL) | 116 if (cinfo == NULL) |
| 117 return NULL; | 117 return NULL; |
| 118 return static_cast<const MediaContentDescription*>(cinfo->description); | 118 return static_cast<const MediaContentDescription*>(cinfo->description); |
| 119 } | 119 } |
| 120 | 120 |
| 121 static bool IsInsecureRtp(const std::string& protocol) { | |
| 122 return protocol == "RTP/AVPF" || protocol == "RTP/AVP"; | |
|
Taylor Brandstetter
2017/08/26 02:40:38
Looking elsewhere, it looks like we typically use
Zhi Huang
2017/08/29 18:40:34
Removed.
| |
| 123 } | |
| 124 | |
| 121 template <class Codec> | 125 template <class Codec> |
| 122 void RtpParametersFromMediaDescription( | 126 void RtpParametersFromMediaDescription( |
| 123 const MediaContentDescriptionImpl<Codec>* desc, | 127 const MediaContentDescriptionImpl<Codec>* desc, |
| 124 const RtpHeaderExtensions& extensions, | 128 const RtpHeaderExtensions& extensions, |
| 125 RtpParameters<Codec>* params) { | 129 RtpParameters<Codec>* params) { |
| 126 // TODO(pthatcher): Remove this once we're sure no one will give us | 130 // TODO(pthatcher): Remove this once we're sure no one will give us |
| 127 // a description without codecs (currently a CA_UPDATE with just | 131 // a description without codecs (currently a CA_UPDATE with just |
| 128 // streams can). | 132 // streams can). |
| 129 if (desc->has_codecs()) { | 133 if (desc->has_codecs()) { |
| 130 params->codecs = desc->codecs(); | 134 params->codecs = desc->codecs(); |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 151 rtc::Thread* signaling_thread, | 155 rtc::Thread* signaling_thread, |
| 152 MediaChannel* media_channel, | 156 MediaChannel* media_channel, |
| 153 const std::string& content_name, | 157 const std::string& content_name, |
| 154 bool rtcp_mux_required, | 158 bool rtcp_mux_required, |
| 155 bool srtp_required) | 159 bool srtp_required) |
| 156 : worker_thread_(worker_thread), | 160 : worker_thread_(worker_thread), |
| 157 network_thread_(network_thread), | 161 network_thread_(network_thread), |
| 158 signaling_thread_(signaling_thread), | 162 signaling_thread_(signaling_thread), |
| 159 content_name_(content_name), | 163 content_name_(content_name), |
| 160 rtcp_mux_required_(rtcp_mux_required), | 164 rtcp_mux_required_(rtcp_mux_required), |
| 161 rtp_transport_( | |
| 162 srtp_required | |
| 163 ? rtc::WrapUnique<webrtc::RtpTransportInternal>( | |
| 164 new webrtc::SrtpTransport(rtcp_mux_required, content_name)) | |
| 165 : rtc::MakeUnique<webrtc::RtpTransport>(rtcp_mux_required)), | |
| 166 srtp_required_(srtp_required), | 165 srtp_required_(srtp_required), |
| 167 media_channel_(media_channel), | 166 media_channel_(media_channel), |
| 168 selected_candidate_pair_(nullptr) { | 167 selected_candidate_pair_(nullptr) { |
| 169 RTC_DCHECK(worker_thread_ == rtc::Thread::Current()); | 168 RTC_DCHECK(worker_thread_ == rtc::Thread::Current()); |
| 169 // Always create an SrtpTransport for |rtp_transport_|. If insecure protocol | |
| 170 // is used, |srtp_transport_| will be set to nullptr and |rtp_transport_| will | |
| 171 // act as a plain RtpTransport. | |
| 172 // TODO(zhihuang): Move the transport creation to the TransportController. | |
| 173 auto transport = | |
| 174 rtc::MakeUnique<webrtc::SrtpTransport>(rtcp_mux_required, content_name); | |
| 175 srtp_transport_ = transport.get(); | |
| 176 rtp_transport_ = std::move(transport); | |
| 170 #if defined(ENABLE_EXTERNAL_AUTH) | 177 #if defined(ENABLE_EXTERNAL_AUTH) |
| 171 srtp_filter_.EnableExternalAuth(); | 178 srtp_transport_->EnableExternalAuth(); |
| 172 #endif | 179 #endif |
| 173 rtp_transport_->SignalReadyToSend.connect( | 180 rtp_transport_->SignalReadyToSend.connect( |
| 174 this, &BaseChannel::OnTransportReadyToSend); | 181 this, &BaseChannel::OnTransportReadyToSend); |
| 175 // TODO(zstein): RtpTransport::SignalPacketReceived will probably be replaced | 182 // TODO(zstein): RtpTransport::SignalPacketReceived will probably be replaced |
| 176 // with a callback interface later so that the demuxer can select which | 183 // with a callback interface later so that the demuxer can select which |
| 177 // channel to signal. | 184 // channel to signal. |
| 178 rtp_transport_->SignalPacketReceived.connect(this, | 185 rtp_transport_->SignalPacketReceived.connect(this, |
| 179 &BaseChannel::OnPacketReceived); | 186 &BaseChannel::OnPacketReceived); |
| 180 LOG(LS_INFO) << "Created channel for " << content_name; | 187 LOG(LS_INFO) << "Created channel for " << content_name; |
| 181 } | 188 } |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 314 return; | 321 return; |
| 315 } | 322 } |
| 316 | 323 |
| 317 // When using DTLS-SRTP, we must reset the SrtpFilter every time the transport | 324 // When using DTLS-SRTP, we must reset the SrtpFilter every time the transport |
| 318 // changes and wait until the DTLS handshake is complete to set the newly | 325 // changes and wait until the DTLS handshake is complete to set the newly |
| 319 // negotiated parameters. | 326 // negotiated parameters. |
| 320 if (ShouldSetupDtlsSrtp_n()) { | 327 if (ShouldSetupDtlsSrtp_n()) { |
| 321 // Set |writable_| to false such that UpdateWritableState_w can set up | 328 // Set |writable_| to false such that UpdateWritableState_w can set up |
| 322 // DTLS-SRTP when |writable_| becomes true again. | 329 // DTLS-SRTP when |writable_| becomes true again. |
| 323 writable_ = false; | 330 writable_ = false; |
| 324 srtp_filter_.ResetParams(); | 331 dtls_active_ = false; |
| 332 if (srtp_transport_) { | |
| 333 srtp_transport_->ResetParams(); | |
| 334 } | |
| 325 } | 335 } |
| 326 | 336 |
| 327 // If this BaseChannel doesn't require RTCP mux and we haven't fully | 337 // If this BaseChannel doesn't require RTCP mux and we haven't fully |
| 328 // negotiated RTCP mux, we need an RTCP transport. | 338 // negotiated RTCP mux, we need an RTCP transport. |
| 329 if (rtcp_packet_transport) { | 339 if (rtcp_packet_transport) { |
| 330 LOG(LS_INFO) << "Setting RTCP Transport for " << content_name() << " on " | 340 LOG(LS_INFO) << "Setting RTCP Transport for " << content_name() << " on " |
| 331 << debug_name << " transport " << rtcp_packet_transport; | 341 << debug_name << " transport " << rtcp_packet_transport; |
| 332 SetTransport_n(true, rtcp_dtls_transport, rtcp_packet_transport); | 342 SetTransport_n(true, rtcp_dtls_transport, rtcp_packet_transport); |
| 333 } | 343 } |
| 334 | 344 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 370 rtp_transport_->SetRtpPacketTransport(new_packet_transport); | 380 rtp_transport_->SetRtpPacketTransport(new_packet_transport); |
| 371 } | 381 } |
| 372 old_dtls_transport = new_dtls_transport; | 382 old_dtls_transport = new_dtls_transport; |
| 373 | 383 |
| 374 // If there's no new transport, we're done after disconnecting from old one. | 384 // If there's no new transport, we're done after disconnecting from old one. |
| 375 if (!new_packet_transport) { | 385 if (!new_packet_transport) { |
| 376 return; | 386 return; |
| 377 } | 387 } |
| 378 | 388 |
| 379 if (rtcp && new_dtls_transport) { | 389 if (rtcp && new_dtls_transport) { |
| 380 RTC_CHECK(!(ShouldSetupDtlsSrtp_n() && srtp_filter_.IsActive())) | 390 RTC_CHECK(!(ShouldSetupDtlsSrtp_n() && secure())) |
| 381 << "Setting RTCP for DTLS/SRTP after SrtpFilter is active " | 391 << "Setting RTCP for DTLS/SRTP after the channel is secure " |
| 382 << "should never happen."; | 392 << "should never happen."; |
| 383 } | 393 } |
| 384 | 394 |
| 385 if (new_dtls_transport) { | 395 if (new_dtls_transport) { |
| 386 ConnectToDtlsTransport(new_dtls_transport); | 396 ConnectToDtlsTransport(new_dtls_transport); |
| 387 } else { | 397 } else { |
| 388 ConnectToPacketTransport(new_packet_transport); | 398 ConnectToPacketTransport(new_packet_transport); |
| 389 } | 399 } |
| 390 auto& socket_options = rtcp ? rtcp_socket_options_ : socket_options_; | 400 auto& socket_options = rtcp ? rtcp_socket_options_ : socket_options_; |
| 391 for (const auto& pair : socket_options) { | 401 for (const auto& pair : socket_options) { |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 522 // Need to access some state updated on the network thread. | 532 // Need to access some state updated on the network thread. |
| 523 return network_thread_->Invoke<bool>( | 533 return network_thread_->Invoke<bool>( |
| 524 RTC_FROM_HERE, Bind(&BaseChannel::IsReadyToSendMedia_n, this)); | 534 RTC_FROM_HERE, Bind(&BaseChannel::IsReadyToSendMedia_n, this)); |
| 525 } | 535 } |
| 526 | 536 |
| 527 bool BaseChannel::IsReadyToSendMedia_n() const { | 537 bool BaseChannel::IsReadyToSendMedia_n() const { |
| 528 // Send outgoing data if we are enabled, have local and remote content, | 538 // Send outgoing data if we are enabled, have local and remote content, |
| 529 // and we have had some form of connectivity. | 539 // and we have had some form of connectivity. |
| 530 return enabled() && IsReceiveContentDirection(remote_content_direction_) && | 540 return enabled() && IsReceiveContentDirection(remote_content_direction_) && |
| 531 IsSendContentDirection(local_content_direction_) && | 541 IsSendContentDirection(local_content_direction_) && |
| 532 was_ever_writable() && | 542 was_ever_writable() && (secure() || !ShouldSetupDtlsSrtp_n()); |
| 533 (srtp_filter_.IsActive() || !ShouldSetupDtlsSrtp_n()); | |
| 534 } | 543 } |
| 535 | 544 |
| 536 bool BaseChannel::SendPacket(rtc::CopyOnWriteBuffer* packet, | 545 bool BaseChannel::SendPacket(rtc::CopyOnWriteBuffer* packet, |
| 537 const rtc::PacketOptions& options) { | 546 const rtc::PacketOptions& options) { |
| 538 return SendPacket(false, packet, options); | 547 return SendPacket(false, packet, options); |
| 539 } | 548 } |
| 540 | 549 |
| 541 bool BaseChannel::SendRtcp(rtc::CopyOnWriteBuffer* packet, | 550 bool BaseChannel::SendRtcp(rtc::CopyOnWriteBuffer* packet, |
| 542 const rtc::PacketOptions& options) { | 551 const rtc::PacketOptions& options) { |
| 543 return SendPacket(true, packet, options); | 552 return SendPacket(true, packet, options); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 581 if (!ShouldSetupDtlsSrtp_n()) { | 590 if (!ShouldSetupDtlsSrtp_n()) { |
| 582 return; | 591 return; |
| 583 } | 592 } |
| 584 | 593 |
| 585 // Reset the srtp filter if it's not the CONNECTED state. For the CONNECTED | 594 // Reset the srtp filter if it's not the CONNECTED state. For the CONNECTED |
| 586 // state, setting up DTLS-SRTP context is deferred to ChannelWritable_w to | 595 // state, setting up DTLS-SRTP context is deferred to ChannelWritable_w to |
| 587 // cover other scenarios like the whole transport is writable (not just this | 596 // cover other scenarios like the whole transport is writable (not just this |
| 588 // TransportChannel) or when TransportChannel is attached after DTLS is | 597 // TransportChannel) or when TransportChannel is attached after DTLS is |
| 589 // negotiated. | 598 // negotiated. |
| 590 if (state != DTLS_TRANSPORT_CONNECTED) { | 599 if (state != DTLS_TRANSPORT_CONNECTED) { |
| 591 srtp_filter_.ResetParams(); | 600 dtls_active_ = false; |
| 601 if (srtp_transport_) { | |
| 602 srtp_transport_->ResetParams(); | |
| 603 } | |
| 592 } | 604 } |
| 593 } | 605 } |
| 594 | 606 |
| 595 void BaseChannel::OnSelectedCandidatePairChanged( | 607 void BaseChannel::OnSelectedCandidatePairChanged( |
| 596 IceTransportInternal* ice_transport, | 608 IceTransportInternal* ice_transport, |
| 597 CandidatePairInterface* selected_candidate_pair, | 609 CandidatePairInterface* selected_candidate_pair, |
| 598 int last_sent_packet_id, | 610 int last_sent_packet_id, |
| 599 bool ready_to_send) { | 611 bool ready_to_send) { |
| 600 RTC_DCHECK((rtp_dtls_transport_ && | 612 RTC_DCHECK((rtp_dtls_transport_ && |
| 601 ice_transport == rtp_dtls_transport_->ice_transport()) || | 613 ice_transport == rtp_dtls_transport_->ice_transport()) || |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 655 } | 667 } |
| 656 | 668 |
| 657 // Protect ourselves against crazy data. | 669 // Protect ourselves against crazy data. |
| 658 if (!ValidPacket(rtcp, packet)) { | 670 if (!ValidPacket(rtcp, packet)) { |
| 659 LOG(LS_ERROR) << "Dropping outgoing " << content_name_ << " " | 671 LOG(LS_ERROR) << "Dropping outgoing " << content_name_ << " " |
| 660 << RtpRtcpStringLiteral(rtcp) | 672 << RtpRtcpStringLiteral(rtcp) |
| 661 << " packet: wrong size=" << packet->size(); | 673 << " packet: wrong size=" << packet->size(); |
| 662 return false; | 674 return false; |
| 663 } | 675 } |
| 664 | 676 |
| 665 rtc::PacketOptions updated_options; | 677 if (!secure() && srtp_required_) { |
| 666 updated_options = options; | |
| 667 // Protect if needed. | |
| 668 if (srtp_filter_.IsActive()) { | |
| 669 TRACE_EVENT0("webrtc", "SRTP Encode"); | |
| 670 bool res; | |
| 671 uint8_t* data = packet->data(); | |
| 672 int len = static_cast<int>(packet->size()); | |
| 673 if (!rtcp) { | |
| 674 // If ENABLE_EXTERNAL_AUTH flag is on then packet authentication is not done | |
| 675 // inside libsrtp for a RTP packet. A external HMAC module will be writing | |
| 676 // a fake HMAC value. This is ONLY done for a RTP packet. | |
| 677 // Socket layer will update rtp sendtime extension header if present in | |
| 678 // packet with current time before updating the HMAC. | |
| 679 #if !defined(ENABLE_EXTERNAL_AUTH) | |
| 680 res = srtp_filter_.ProtectRtp( | |
| 681 data, len, static_cast<int>(packet->capacity()), &len); | |
| 682 #else | |
| 683 if (!srtp_filter_.IsExternalAuthActive()) { | |
| 684 res = srtp_filter_.ProtectRtp( | |
| 685 data, len, static_cast<int>(packet->capacity()), &len); | |
| 686 } else { | |
| 687 updated_options.packet_time_params.rtp_sendtime_extension_id = | |
| 688 rtp_abs_sendtime_extn_id_; | |
| 689 res = srtp_filter_.ProtectRtp( | |
| 690 data, len, static_cast<int>(packet->capacity()), &len, | |
| 691 &updated_options.packet_time_params.srtp_packet_index); | |
| 692 // If protection succeeds, let's get auth params from srtp. | |
| 693 if (res) { | |
| 694 uint8_t* auth_key = NULL; | |
| 695 int key_len; | |
| 696 res = srtp_filter_.GetRtpAuthParams( | |
| 697 &auth_key, &key_len, | |
| 698 &updated_options.packet_time_params.srtp_auth_tag_len); | |
| 699 if (res) { | |
| 700 updated_options.packet_time_params.srtp_auth_key.resize(key_len); | |
| 701 updated_options.packet_time_params.srtp_auth_key.assign( | |
| 702 auth_key, auth_key + key_len); | |
| 703 } | |
| 704 } | |
| 705 } | |
| 706 #endif | |
| 707 if (!res) { | |
| 708 int seq_num = -1; | |
| 709 uint32_t ssrc = 0; | |
| 710 GetRtpSeqNum(data, len, &seq_num); | |
| 711 GetRtpSsrc(data, len, &ssrc); | |
| 712 LOG(LS_ERROR) << "Failed to protect " << content_name_ | |
| 713 << " RTP packet: size=" << len | |
| 714 << ", seqnum=" << seq_num << ", SSRC=" << ssrc; | |
| 715 return false; | |
| 716 } | |
| 717 } else { | |
| 718 res = srtp_filter_.ProtectRtcp(data, len, | |
| 719 static_cast<int>(packet->capacity()), | |
| 720 &len); | |
| 721 if (!res) { | |
| 722 int type = -1; | |
| 723 GetRtcpType(data, len, &type); | |
| 724 LOG(LS_ERROR) << "Failed to protect " << content_name_ | |
| 725 << " RTCP packet: size=" << len << ", type=" << type; | |
| 726 return false; | |
| 727 } | |
| 728 } | |
| 729 | |
| 730 // Update the length of the packet now that we've added the auth tag. | |
| 731 packet->SetSize(len); | |
| 732 } else if (srtp_required_) { | |
| 733 // The audio/video engines may attempt to send RTCP packets as soon as the | 678 // The audio/video engines may attempt to send RTCP packets as soon as the |
| 734 // streams are created, so don't treat this as an error for RTCP. | 679 // streams are created, so don't treat this as an error for RTCP. |
| 735 // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=6809 | 680 // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=6809 |
| 736 if (rtcp) { | 681 if (rtcp) { |
| 737 return false; | 682 return false; |
| 738 } | 683 } |
| 739 // However, there shouldn't be any RTP packets sent before SRTP is set up | 684 // However, there shouldn't be any RTP packets sent before SRTP is set up |
| 740 // (and SetSend(true) is called). | 685 // (and SetSend(true) is called). |
| 741 LOG(LS_ERROR) << "Can't send outgoing RTP packet when SRTP is inactive" | 686 LOG(LS_ERROR) << "Can't send outgoing RTP packet when SRTP is inactive" |
| 742 << " and crypto is required"; | 687 << " and crypto is required"; |
| 743 RTC_NOTREACHED(); | 688 RTC_NOTREACHED(); |
| 744 return false; | 689 return false; |
| 745 } | 690 } |
| 746 | 691 |
| 692 if (secure()) { | |
|
pthatcher
2017/08/28 21:42:56
I think making the shorter path the early return w
Zhi Huang
2017/08/29 18:40:34
Done.
| |
| 693 RTC_DCHECK(srtp_transport_); | |
| 694 RTC_DCHECK(srtp_transport_->IsActive()); | |
| 695 // Bon voyage. | |
| 696 int flags = secure_dtls() ? PF_SRTP_BYPASS : PF_NORMAL; | |
| 697 return srtp_transport_->SendPacket(rtcp, packet, options, flags); | |
|
pthatcher
2017/08/28 21:42:56
I don't think it should be the responsibility of t
Zhi Huang
2017/08/29 18:40:34
SrtpTransport doesn't interact with DtlsTransport
| |
| 698 } | |
| 699 | |
| 747 // Bon voyage. | 700 // Bon voyage. |
| 748 int flags = (secure() && secure_dtls()) ? PF_SRTP_BYPASS : PF_NORMAL; | 701 return rtp_transport_->SendPacket(rtcp, packet, options, PF_NORMAL); |
|
pthatcher
2017/08/28 21:42:56
And similarly here, it would make sense to call Se
Zhi Huang
2017/08/29 18:40:34
Done.
| |
| 749 return rtp_transport_->SendPacket(rtcp, packet, updated_options, flags); | |
| 750 } | 702 } |
| 751 | 703 |
| 752 bool BaseChannel::HandlesPayloadType(int packet_type) const { | 704 bool BaseChannel::HandlesPayloadType(int packet_type) const { |
| 753 return rtp_transport_->HandlesPayloadType(packet_type); | 705 return rtp_transport_->HandlesPayloadType(packet_type); |
| 754 } | 706 } |
| 755 | 707 |
| 756 void BaseChannel::OnPacketReceived(bool rtcp, | 708 void BaseChannel::OnPacketReceived(bool rtcp, |
| 757 rtc::CopyOnWriteBuffer* packet, | 709 rtc::CopyOnWriteBuffer* packet, |
| 758 const rtc::PacketTime& packet_time) { | 710 const rtc::PacketTime& packet_time) { |
| 759 if (!has_received_packet_ && !rtcp) { | 711 if (!has_received_packet_ && !rtcp) { |
| 760 has_received_packet_ = true; | 712 has_received_packet_ = true; |
| 761 signaling_thread()->Post(RTC_FROM_HERE, this, MSG_FIRSTPACKETRECEIVED); | 713 signaling_thread()->Post(RTC_FROM_HERE, this, MSG_FIRSTPACKETRECEIVED); |
| 762 } | 714 } |
| 763 | 715 |
| 764 // Unprotect the packet, if needed. | 716 if (!secure() && srtp_required_) { |
| 765 if (srtp_filter_.IsActive()) { | |
| 766 TRACE_EVENT0("webrtc", "SRTP Decode"); | |
| 767 char* data = packet->data<char>(); | |
| 768 int len = static_cast<int>(packet->size()); | |
| 769 bool res; | |
| 770 if (!rtcp) { | |
| 771 res = srtp_filter_.UnprotectRtp(data, len, &len); | |
| 772 if (!res) { | |
| 773 int seq_num = -1; | |
| 774 uint32_t ssrc = 0; | |
| 775 GetRtpSeqNum(data, len, &seq_num); | |
| 776 GetRtpSsrc(data, len, &ssrc); | |
| 777 LOG(LS_ERROR) << "Failed to unprotect " << content_name_ | |
| 778 << " RTP packet: size=" << len << ", seqnum=" << seq_num | |
| 779 << ", SSRC=" << ssrc; | |
| 780 return; | |
| 781 } | |
| 782 } else { | |
| 783 res = srtp_filter_.UnprotectRtcp(data, len, &len); | |
| 784 if (!res) { | |
| 785 int type = -1; | |
| 786 GetRtcpType(data, len, &type); | |
| 787 LOG(LS_ERROR) << "Failed to unprotect " << content_name_ | |
| 788 << " RTCP packet: size=" << len << ", type=" << type; | |
| 789 return; | |
| 790 } | |
| 791 } | |
| 792 | |
| 793 packet->SetSize(len); | |
| 794 } else if (srtp_required_) { | |
| 795 // Our session description indicates that SRTP is required, but we got a | 717 // Our session description indicates that SRTP is required, but we got a |
| 796 // packet before our SRTP filter is active. This means either that | 718 // packet before our SRTP filter is active. This means either that |
| 797 // a) we got SRTP packets before we received the SDES keys, in which case | 719 // a) we got SRTP packets before we received the SDES keys, in which case |
| 798 // we can't decrypt it anyway, or | 720 // we can't decrypt it anyway, or |
| 799 // b) we got SRTP packets before DTLS completed on both the RTP and RTCP | 721 // b) we got SRTP packets before DTLS completed on both the RTP and RTCP |
| 800 // transports, so we haven't yet extracted keys, even if DTLS did | 722 // transports, so we haven't yet extracted keys, even if DTLS did |
| 801 // complete on the transport that the packets are being sent on. It's | 723 // complete on the transport that the packets are being sent on. It's |
| 802 // really good practice to wait for both RTP and RTCP to be good to go | 724 // really good practice to wait for both RTP and RTCP to be good to go |
| 803 // before sending media, to prevent weird failure modes, so it's fine | 725 // before sending media, to prevent weird failure modes, so it's fine |
| 804 // for us to just eat packets here. This is all sidestepped if RTCP mux | 726 // for us to just eat packets here. This is all sidestepped if RTCP mux |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 827 media_channel_->OnPacketReceived(&data, packet_time); | 749 media_channel_->OnPacketReceived(&data, packet_time); |
| 828 } | 750 } |
| 829 } | 751 } |
| 830 | 752 |
| 831 bool BaseChannel::PushdownLocalDescription( | 753 bool BaseChannel::PushdownLocalDescription( |
| 832 const SessionDescription* local_desc, ContentAction action, | 754 const SessionDescription* local_desc, ContentAction action, |
| 833 std::string* error_desc) { | 755 std::string* error_desc) { |
| 834 const ContentInfo* content_info = GetFirstContent(local_desc); | 756 const ContentInfo* content_info = GetFirstContent(local_desc); |
| 835 const MediaContentDescription* content_desc = | 757 const MediaContentDescription* content_desc = |
| 836 GetContentDescription(content_info); | 758 GetContentDescription(content_info); |
| 759 if (IsInsecureRtp(content_desc->protocol())) { | |
| 760 RTC_DCHECK(!srtp_required_); | |
|
Taylor Brandstetter
2017/08/26 02:40:38
This should be an error rather than a DCHECK since
Zhi Huang
2017/08/29 18:40:34
I'll remove these for now.
| |
| 761 srtp_transport_ = nullptr; | |
|
Taylor Brandstetter
2017/08/26 02:40:39
This unsets the srtp_transport_ pointer, but rtp_t
Zhi Huang
2017/08/29 18:40:33
Done.
| |
| 762 } | |
| 837 if (content_desc && content_info && !content_info->rejected && | 763 if (content_desc && content_info && !content_info->rejected && |
| 838 !SetLocalContent(content_desc, action, error_desc)) { | 764 !SetLocalContent(content_desc, action, error_desc)) { |
| 839 LOG(LS_ERROR) << "Failure in SetLocalContent with action " << action; | 765 LOG(LS_ERROR) << "Failure in SetLocalContent with action " << action; |
| 840 return false; | 766 return false; |
| 841 } | 767 } |
| 842 return true; | 768 return true; |
| 843 } | 769 } |
| 844 | 770 |
| 845 bool BaseChannel::PushdownRemoteDescription( | 771 bool BaseChannel::PushdownRemoteDescription( |
| 846 const SessionDescription* remote_desc, ContentAction action, | 772 const SessionDescription* remote_desc, ContentAction action, |
| 847 std::string* error_desc) { | 773 std::string* error_desc) { |
| 848 const ContentInfo* content_info = GetFirstContent(remote_desc); | 774 const ContentInfo* content_info = GetFirstContent(remote_desc); |
| 849 const MediaContentDescription* content_desc = | 775 const MediaContentDescription* content_desc = |
| 850 GetContentDescription(content_info); | 776 GetContentDescription(content_info); |
| 777 if (IsInsecureRtp(content_desc->protocol())) { | |
| 778 RTC_DCHECK(!srtp_required_); | |
| 779 srtp_transport_ = nullptr; | |
| 780 } | |
| 851 if (content_desc && content_info && !content_info->rejected && | 781 if (content_desc && content_info && !content_info->rejected && |
| 852 !SetRemoteContent(content_desc, action, error_desc)) { | 782 !SetRemoteContent(content_desc, action, error_desc)) { |
| 853 LOG(LS_ERROR) << "Failure in SetRemoteContent with action " << action; | 783 LOG(LS_ERROR) << "Failure in SetRemoteContent with action " << action; |
| 854 return false; | 784 return false; |
| 855 } | 785 } |
| 856 return true; | 786 return true; |
| 857 } | 787 } |
| 858 | 788 |
| 859 void BaseChannel::EnableMedia_w() { | 789 void BaseChannel::EnableMedia_w() { |
| 860 RTC_DCHECK(worker_thread_ == rtc::Thread::Current()); | 790 RTC_DCHECK(worker_thread_ == rtc::Thread::Current()); |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 988 } | 918 } |
| 989 | 919 |
| 990 if (role == rtc::SSL_SERVER) { | 920 if (role == rtc::SSL_SERVER) { |
| 991 send_key = &server_write_key; | 921 send_key = &server_write_key; |
| 992 recv_key = &client_write_key; | 922 recv_key = &client_write_key; |
| 993 } else { | 923 } else { |
| 994 send_key = &client_write_key; | 924 send_key = &client_write_key; |
| 995 recv_key = &server_write_key; | 925 recv_key = &server_write_key; |
| 996 } | 926 } |
| 997 | 927 |
| 998 if (!srtp_filter_.IsActive()) { | 928 if (!secure_dtls()) { |
| 999 if (rtcp) { | 929 if (rtcp) { |
| 1000 ret = srtp_filter_.SetRtcpParams(selected_crypto_suite, &(*send_key)[0], | 930 RTC_DCHECK(srtp_transport_); |
| 1001 static_cast<int>(send_key->size()), | 931 ret = srtp_transport_->SetRtcpParams( |
| 1002 selected_crypto_suite, &(*recv_key)[0], | 932 selected_crypto_suite, &(*send_key)[0], |
| 1003 static_cast<int>(recv_key->size())); | 933 static_cast<int>(send_key->size()), selected_crypto_suite, |
| 934 &(*recv_key)[0], static_cast<int>(recv_key->size())); | |
| 1004 } else { | 935 } else { |
| 1005 ret = srtp_filter_.SetRtpParams(selected_crypto_suite, &(*send_key)[0], | 936 RTC_DCHECK(srtp_transport_); |
| 1006 static_cast<int>(send_key->size()), | 937 ret = srtp_transport_->SetRtpParams( |
| 1007 selected_crypto_suite, &(*recv_key)[0], | 938 selected_crypto_suite, &(*send_key)[0], |
| 1008 static_cast<int>(recv_key->size())); | 939 static_cast<int>(send_key->size()), selected_crypto_suite, |
| 940 &(*recv_key)[0], static_cast<int>(recv_key->size())); | |
| 941 dtls_active_ = ret; | |
| 1009 } | 942 } |
| 1010 } else { | 943 } else { |
| 1011 if (rtcp) { | 944 if (rtcp) { |
| 1012 // RTCP doesn't need to be updated because UpdateRtpParams is only used | 945 // RTCP doesn't need to be updated because UpdateRtpParams is only used |
| 1013 // to update the set of encrypted RTP header extension IDs. | 946 // to update the set of encrypted RTP header extension IDs. |
| 1014 ret = true; | 947 ret = true; |
| 1015 } else { | 948 } else { |
| 1016 ret = srtp_filter_.UpdateRtpParams( | 949 RTC_DCHECK(srtp_transport_); |
| 1017 selected_crypto_suite, | 950 ret = srtp_transport_->UpdateRtpParams( |
| 1018 &(*send_key)[0], static_cast<int>(send_key->size()), | 951 selected_crypto_suite, &(*send_key)[0], |
| 1019 selected_crypto_suite, | 952 static_cast<int>(send_key->size()), selected_crypto_suite, |
| 1020 &(*recv_key)[0], static_cast<int>(recv_key->size())); | 953 &(*recv_key)[0], static_cast<int>(recv_key->size())); |
| 1021 } | 954 } |
| 1022 } | 955 } |
|
pthatcher
2017/08/28 21:42:56
If this is only used for changing the header exten
Zhi Huang
2017/08/29 18:40:34
SetEncryptedHeaderExtensionIds just stores the upd
| |
| 1023 | 956 |
| 1024 if (!ret) { | 957 if (!ret) { |
| 1025 LOG(LS_WARNING) << "DTLS-SRTP key installation failed"; | 958 LOG(LS_WARNING) << "DTLS-SRTP key installation failed"; |
| 1026 } else { | 959 } else { |
| 1027 dtls_keyed_ = true; | |
| 1028 UpdateTransportOverhead(); | 960 UpdateTransportOverhead(); |
| 1029 } | 961 } |
| 1030 return ret; | 962 return ret; |
| 1031 } | 963 } |
| 1032 | 964 |
| 1033 void BaseChannel::MaybeSetupDtlsSrtp_n() { | 965 void BaseChannel::MaybeSetupDtlsSrtp_n() { |
| 1034 if (srtp_filter_.IsActive()) { | 966 if (secure_dtls()) { |
| 1035 return; | 967 return; |
| 1036 } | 968 } |
| 1037 | 969 |
| 1038 if (!ShouldSetupDtlsSrtp_n()) { | 970 if (!ShouldSetupDtlsSrtp_n()) { |
| 1039 return; | 971 return; |
| 1040 } | 972 } |
| 1041 | 973 |
| 1042 if (!SetupDtlsSrtp_n(false)) { | 974 if (!SetupDtlsSrtp_n(false)) { |
| 1043 SignalDtlsSrtpSetupFailure_n(false); | 975 SignalDtlsSrtpSetupFailure_n(false); |
| 1044 return; | 976 return; |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1131 if (action == CA_UPDATE) { | 1063 if (action == CA_UPDATE) { |
| 1132 // no crypto params. | 1064 // no crypto params. |
| 1133 return true; | 1065 return true; |
| 1134 } | 1066 } |
| 1135 bool ret = false; | 1067 bool ret = false; |
| 1136 bool dtls = false; | 1068 bool dtls = false; |
| 1137 ret = CheckSrtpConfig_n(cryptos, &dtls, error_desc); | 1069 ret = CheckSrtpConfig_n(cryptos, &dtls, error_desc); |
| 1138 if (!ret) { | 1070 if (!ret) { |
| 1139 return false; | 1071 return false; |
| 1140 } | 1072 } |
| 1141 srtp_filter_.SetEncryptedHeaderExtensionIds(src, encrypted_extension_ids); | 1073 |
| 1074 if (!srtp_transport_) { | |
| 1075 LOG(LS_WARNING) << "Setting SRTP without an SrtpTransport."; | |
|
Taylor Brandstetter
2017/08/26 02:40:38
It looks like this warning message would be logged
Zhi Huang
2017/08/29 18:40:34
Acknowledged.
| |
| 1076 return true; | |
| 1077 } | |
| 1078 | |
| 1079 srtp_transport_->SetEncryptedHeaderExtensionIds(src, encrypted_extension_ids); | |
| 1142 switch (action) { | 1080 switch (action) { |
| 1143 case CA_OFFER: | 1081 case CA_OFFER: |
| 1144 // If DTLS is already active on the channel, we could be renegotiating | 1082 // If DTLS is already active on the channel, we could be renegotiating |
| 1145 // here. We don't update the srtp filter. | 1083 // here. We don't update the srtp filter. |
| 1146 if (!dtls) { | 1084 if (!dtls) { |
| 1147 ret = srtp_filter_.SetOffer(cryptos, src); | 1085 ret = srtp_filter_.SetOffer(cryptos, src); |
| 1148 } | 1086 } |
| 1149 break; | 1087 break; |
| 1150 case CA_PRANSWER: | 1088 case CA_PRANSWER: |
| 1151 // If we're doing DTLS-SRTP, we don't want to update the filter | 1089 // If we're doing DTLS-SRTP, we don't want to update the filter |
| 1152 // with an answer, because we already have SRTP parameters. | 1090 // with an answer, because we already have SRTP parameters. |
| 1153 if (!dtls) { | 1091 if (!dtls) { |
| 1154 ret = srtp_filter_.SetProvisionalAnswer(cryptos, src); | 1092 ret = srtp_filter_.SetProvisionalAnswer(cryptos, src); |
| 1155 } | 1093 } |
| 1156 break; | 1094 break; |
| 1157 case CA_ANSWER: | 1095 case CA_ANSWER: |
| 1158 // If we're doing DTLS-SRTP, we don't want to update the filter | 1096 // If we're doing DTLS-SRTP, we don't want to update the filter |
| 1159 // with an answer, because we already have SRTP parameters. | 1097 // with an answer, because we already have SRTP parameters. |
| 1160 if (!dtls) { | 1098 if (!dtls) { |
| 1161 ret = srtp_filter_.SetAnswer(cryptos, src); | 1099 ret = srtp_filter_.SetAnswer(cryptos, src); |
| 1162 } | 1100 } |
| 1163 break; | 1101 break; |
| 1164 default: | 1102 default: |
| 1165 break; | 1103 break; |
| 1166 } | 1104 } |
| 1105 | |
| 1106 // If setting an SDES answer succeeded, apply the negotiated parameters | |
| 1107 // to the SRTP transport. | |
| 1108 if ((action == CA_PRANSWER || action == CA_ANSWER) && !dtls && ret) { | |
| 1109 if (srtp_filter_.send_cipher_suite() && srtp_filter_.recv_cipher_suite()) { | |
| 1110 auto send_key = srtp_filter_.send_key(); | |
| 1111 auto recv_key = srtp_filter_.recv_key(); | |
| 1112 ret = srtp_transport_->SetRtpParams( | |
| 1113 *(srtp_filter_.send_cipher_suite()), &(*send_key)[0], | |
| 1114 static_cast<int>(send_key->size()), | |
| 1115 *(srtp_filter_.recv_cipher_suite()), &(*recv_key)[0], | |
| 1116 static_cast<int>(recv_key->size())); | |
| 1117 } else { | |
| 1118 LOG(LS_INFO) << "No crypto keys are provided for SDES."; | |
|
Taylor Brandstetter
2017/08/26 02:40:38
Is it even possible to hit this point? Won't "srtp
Zhi Huang
2017/08/29 18:40:34
If we still support upgrading rtp_transport to srt
| |
| 1119 if (action == CA_ANSWER) { | |
| 1120 // Explicitly reset the |srtp_transport_| if no crypto param is | |
| 1121 // provided in the answer. No need to call |ResetParams()| for | |
| 1122 // |srtp_filter_| because it resets the params inside |SetAnswer|. | |
| 1123 srtp_transport_->ResetParams(); | |
| 1124 } | |
| 1125 } | |
| 1126 } | |
| 1127 | |
| 1167 // Only update SRTP filter if using DTLS. SDES is handled internally | 1128 // Only update SRTP filter if using DTLS. SDES is handled internally |
| 1168 // by the SRTP filter. | 1129 // by the SRTP filter. |
| 1169 // TODO(jbauch): Only update if encrypted extension ids have changed. | 1130 // TODO(jbauch): Only update if encrypted extension ids have changed. |
| 1170 if (ret && dtls_keyed_ && rtp_dtls_transport_ && | 1131 if (ret && secure_dtls() && rtp_dtls_transport_ && |
| 1171 rtp_dtls_transport_->dtls_state() == DTLS_TRANSPORT_CONNECTED) { | 1132 rtp_dtls_transport_->dtls_state() == DTLS_TRANSPORT_CONNECTED) { |
| 1172 bool rtcp = false; | 1133 bool rtcp = false; |
| 1173 ret = SetupDtlsSrtp_n(rtcp); | 1134 ret = SetupDtlsSrtp_n(rtcp); |
| 1174 } | 1135 } |
| 1175 if (!ret) { | 1136 if (!ret) { |
| 1176 SafeSetError("Failed to setup SRTP filter.", error_desc); | 1137 SafeSetError("Failed to setup SRTP filter.", error_desc); |
| 1177 return false; | 1138 return false; |
| 1178 } | 1139 } |
| 1179 return true; | 1140 return true; |
| 1180 } | 1141 } |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 1204 break; | 1165 break; |
| 1205 case CA_ANSWER: | 1166 case CA_ANSWER: |
| 1206 ret = rtcp_mux_filter_.SetAnswer(enable, src); | 1167 ret = rtcp_mux_filter_.SetAnswer(enable, src); |
| 1207 if (ret && rtcp_mux_filter_.IsActive()) { | 1168 if (ret && rtcp_mux_filter_.IsActive()) { |
| 1208 // We permanently activated RTCP muxing; signal that we no longer need | 1169 // We permanently activated RTCP muxing; signal that we no longer need |
| 1209 // the RTCP transport. | 1170 // the RTCP transport. |
| 1210 std::string debug_name = | 1171 std::string debug_name = |
| 1211 transport_name_.empty() | 1172 transport_name_.empty() |
| 1212 ? rtp_transport_->rtp_packet_transport()->debug_name() | 1173 ? rtp_transport_->rtp_packet_transport()->debug_name() |
| 1213 : transport_name_; | 1174 : transport_name_; |
| 1214 ; | |
| 1215 LOG(LS_INFO) << "Enabling rtcp-mux for " << content_name() | 1175 LOG(LS_INFO) << "Enabling rtcp-mux for " << content_name() |
| 1216 << "; no longer need RTCP transport for " << debug_name; | 1176 << "; no longer need RTCP transport for " << debug_name; |
| 1217 if (rtp_transport_->rtcp_packet_transport()) { | 1177 if (rtp_transport_->rtcp_packet_transport()) { |
| 1218 SetTransport_n(true, nullptr, nullptr); | 1178 SetTransport_n(true, nullptr, nullptr); |
| 1219 SignalRtcpMuxFullyActive(transport_name_); | 1179 SignalRtcpMuxFullyActive(transport_name_); |
| 1220 } | 1180 } |
| 1221 UpdateWritableState_n(); | 1181 UpdateWritableState_n(); |
| 1222 } | 1182 } |
| 1223 break; | 1183 break; |
| 1224 case CA_UPDATE: | 1184 case CA_UPDATE: |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1433 send_time_extension ? send_time_extension->id : -1; | 1393 send_time_extension ? send_time_extension->id : -1; |
| 1434 invoker_.AsyncInvoke<void>( | 1394 invoker_.AsyncInvoke<void>( |
| 1435 RTC_FROM_HERE, network_thread_, | 1395 RTC_FROM_HERE, network_thread_, |
| 1436 Bind(&BaseChannel::CacheRtpAbsSendTimeHeaderExtension_n, this, | 1396 Bind(&BaseChannel::CacheRtpAbsSendTimeHeaderExtension_n, this, |
| 1437 rtp_abs_sendtime_extn_id)); | 1397 rtp_abs_sendtime_extn_id)); |
| 1438 #endif | 1398 #endif |
| 1439 } | 1399 } |
| 1440 | 1400 |
| 1441 void BaseChannel::CacheRtpAbsSendTimeHeaderExtension_n( | 1401 void BaseChannel::CacheRtpAbsSendTimeHeaderExtension_n( |
| 1442 int rtp_abs_sendtime_extn_id) { | 1402 int rtp_abs_sendtime_extn_id) { |
| 1443 rtp_abs_sendtime_extn_id_ = rtp_abs_sendtime_extn_id; | 1403 RTC_DCHECK(srtp_transport_); |
| 1404 srtp_transport_->CacheRtpAbsSendTimeHeaderExtension(rtp_abs_sendtime_extn_id); | |
| 1444 } | 1405 } |
| 1445 | 1406 |
| 1446 void BaseChannel::OnMessage(rtc::Message *pmsg) { | 1407 void BaseChannel::OnMessage(rtc::Message *pmsg) { |
| 1447 TRACE_EVENT0("webrtc", "BaseChannel::OnMessage"); | 1408 TRACE_EVENT0("webrtc", "BaseChannel::OnMessage"); |
| 1448 switch (pmsg->message_id) { | 1409 switch (pmsg->message_id) { |
| 1449 case MSG_SEND_RTP_PACKET: | 1410 case MSG_SEND_RTP_PACKET: |
| 1450 case MSG_SEND_RTCP_PACKET: { | 1411 case MSG_SEND_RTCP_PACKET: { |
| 1451 RTC_DCHECK(network_thread_->IsCurrent()); | 1412 RTC_DCHECK(network_thread_->IsCurrent()); |
| 1452 SendPacketMessageData* data = | 1413 SendPacketMessageData* data = |
| 1453 static_cast<SendPacketMessageData*>(pmsg->pdata); | 1414 static_cast<SendPacketMessageData*>(pmsg->pdata); |
| (...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1717 : kIpv6Overhaed; | 1678 : kIpv6Overhaed; |
| 1718 | 1679 |
| 1719 constexpr int kUdpOverhaed = 8; | 1680 constexpr int kUdpOverhaed = 8; |
| 1720 constexpr int kTcpOverhaed = 20; | 1681 constexpr int kTcpOverhaed = 20; |
| 1721 transport_overhead_per_packet += | 1682 transport_overhead_per_packet += |
| 1722 selected_candidate_pair_->local_candidate().protocol() == | 1683 selected_candidate_pair_->local_candidate().protocol() == |
| 1723 TCP_PROTOCOL_NAME | 1684 TCP_PROTOCOL_NAME |
| 1724 ? kTcpOverhaed | 1685 ? kTcpOverhaed |
| 1725 : kUdpOverhaed; | 1686 : kUdpOverhaed; |
| 1726 | 1687 |
| 1727 if (secure()) { | 1688 if (secure_sdes()) { |
| 1728 int srtp_overhead = 0; | 1689 int srtp_overhead = 0; |
| 1729 if (srtp_filter_.GetSrtpOverhead(&srtp_overhead)) | 1690 if (srtp_transport_->GetSrtpOverhead(&srtp_overhead)) |
| 1730 transport_overhead_per_packet += srtp_overhead; | 1691 transport_overhead_per_packet += srtp_overhead; |
| 1731 } | 1692 } |
| 1732 | 1693 |
| 1733 return transport_overhead_per_packet; | 1694 return transport_overhead_per_packet; |
| 1734 } | 1695 } |
| 1735 | 1696 |
| 1736 void BaseChannel::UpdateTransportOverhead() { | 1697 void BaseChannel::UpdateTransportOverhead() { |
| 1737 int transport_overhead_per_packet = GetTransportOverheadPerPacket(); | 1698 int transport_overhead_per_packet = GetTransportOverheadPerPacket(); |
| 1738 if (transport_overhead_per_packet) | 1699 if (transport_overhead_per_packet) |
| 1739 invoker_.AsyncInvoke<void>( | 1700 invoker_.AsyncInvoke<void>( |
| (...skipping 714 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2454 | 2415 |
| 2455 void RtpDataChannel::OnDataChannelReadyToSend(bool writable) { | 2416 void RtpDataChannel::OnDataChannelReadyToSend(bool writable) { |
| 2456 // This is usded for congestion control to indicate that the stream is ready | 2417 // This is usded for congestion control to indicate that the stream is ready |
| 2457 // to send by the MediaChannel, as opposed to OnReadyToSend, which indicates | 2418 // to send by the MediaChannel, as opposed to OnReadyToSend, which indicates |
| 2458 // that the transport channel is ready. | 2419 // that the transport channel is ready. |
| 2459 signaling_thread()->Post(RTC_FROM_HERE, this, MSG_READYTOSENDDATA, | 2420 signaling_thread()->Post(RTC_FROM_HERE, this, MSG_READYTOSENDDATA, |
| 2460 new DataChannelReadyToSendMessageData(writable)); | 2421 new DataChannelReadyToSendMessageData(writable)); |
| 2461 } | 2422 } |
| 2462 | 2423 |
| 2463 } // namespace cricket | 2424 } // namespace cricket |
| OLD | NEW |