blob: 285291fb45e938db4fd50e43004448cf029e25a7 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellander65c7f672016-02-12 00:05:01 -08002 * Copyright 2004 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellander65c7f672016-02-12 00:05:01 -08004 * 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
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
Anton Sukhanov4f08faa2019-05-21 11:12:57 -070011#include "pc/channel.h"
12
jbauch5869f502017-06-29 12:31:36 -070013#include <iterator>
kwiberg0eb15ed2015-12-17 03:04:15 -080014#include <utility>
15
Steve Anton64b626b2019-01-28 17:25:26 -080016#include "absl/algorithm/container.h"
Karl Wiberg918f50c2018-07-05 11:40:33 +020017#include "absl/memory/memory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "api/call/audio_sink.h"
Niels Möller65f17ca2019-09-12 13:59:36 +020019#include "api/transport/media/media_transport_config.h"
Steve Anton10542f22019-01-11 09:11:00 -080020#include "media/base/media_constants.h"
21#include "media/base/rtp_utils.h"
Zhi Huang365381f2018-04-13 16:44:34 -070022#include "modules/rtp_rtcp/source/rtp_packet_received.h"
Anton Sukhanov4f08faa2019-05-21 11:12:57 -070023#include "p2p/base/packet_transport_internal.h"
24#include "pc/channel_manager.h"
25#include "pc/rtp_media_utils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020026#include "rtc_base/bind.h"
Steve Anton10542f22019-01-11 09:11:00 -080027#include "rtc_base/byte_order.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020028#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080029#include "rtc_base/copy_on_write_buffer.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020030#include "rtc_base/dscp.h"
31#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080032#include "rtc_base/network_route.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020033#include "rtc_base/strings/string_builder.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020034#include "rtc_base/trace_event.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000035
36namespace cricket {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000037using rtc::Bind;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080038using rtc::UniqueRandomIdGenerator;
Steve Anton3828c062017-12-06 10:34:51 -080039using webrtc::SdpType;
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +000040
deadbeef2d110be2016-01-13 12:00:26 -080041namespace {
Danil Chapovalov33b01f22016-05-11 19:55:27 +020042
43struct SendPacketMessageData : public rtc::MessageData {
44 rtc::CopyOnWriteBuffer packet;
45 rtc::PacketOptions options;
46};
47
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080048// Finds a stream based on target's Primary SSRC or RIDs.
49// This struct is used in BaseChannel::UpdateLocalStreams_w.
50struct StreamFinder {
51 explicit StreamFinder(const StreamParams* target) : target_(target) {
52 RTC_DCHECK(target);
53 }
54
55 bool operator()(const StreamParams& sp) const {
56 if (target_->has_ssrcs() && sp.has_ssrcs()) {
57 return sp.has_ssrc(target_->first_ssrc());
58 }
59
60 if (!target_->has_rids() && !sp.has_rids()) {
61 return false;
62 }
63
64 const std::vector<RidDescription>& target_rids = target_->rids();
65 const std::vector<RidDescription>& source_rids = sp.rids();
66 if (source_rids.size() != target_rids.size()) {
67 return false;
68 }
69
70 // Check that all RIDs match.
71 return std::equal(source_rids.begin(), source_rids.end(),
72 target_rids.begin(),
73 [](const RidDescription& lhs, const RidDescription& rhs) {
74 return lhs.rid == rhs.rid;
75 });
76 }
77
78 const StreamParams* target_;
79};
80
deadbeef2d110be2016-01-13 12:00:26 -080081} // namespace
82
henrike@webrtc.org28e20752013-07-10 00:45:36 +000083enum {
Steve Anton0807d152018-03-05 11:23:09 -080084 MSG_SEND_RTP_PACKET = 1,
Danil Chapovalov33b01f22016-05-11 19:55:27 +020085 MSG_SEND_RTCP_PACKET,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000086 MSG_READYTOSENDDATA,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000087 MSG_DATARECEIVED,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000088 MSG_FIRSTPACKETRECEIVED,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000089};
90
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +000091static void SafeSetError(const std::string& message, std::string* error_desc) {
92 if (error_desc) {
93 *error_desc = message;
94 }
95}
96
Peter Thatcherc2ee2c82015-08-07 16:05:34 -070097template <class Codec>
98void RtpParametersFromMediaDescription(
99 const MediaContentDescriptionImpl<Codec>* desc,
jbauch5869f502017-06-29 12:31:36 -0700100 const RtpHeaderExtensions& extensions,
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700101 RtpParameters<Codec>* params) {
102 // TODO(pthatcher): Remove this once we're sure no one will give us
Zhi Huang801b8682017-11-15 11:36:43 -0800103 // a description without codecs. Currently the ORTC implementation is relying
104 // on this.
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700105 if (desc->has_codecs()) {
Artem Titov65639342019-08-02 08:27:51 +0000106 params->codecs = desc->codecs();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700107 }
108 // TODO(pthatcher): See if we really need
109 // rtp_header_extensions_set() and remove it if we don't.
110 if (desc->rtp_header_extensions_set()) {
jbauch5869f502017-06-29 12:31:36 -0700111 params->extensions = extensions;
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700112 }
deadbeef13871492015-12-09 12:37:51 -0800113 params->rtcp.reduced_size = desc->rtcp_reduced_size();
Sebastian Janssone1795f42019-07-24 11:38:03 +0200114 params->rtcp.remote_estimate = desc->remote_estimate();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700115}
116
nisse05103312016-03-16 02:22:50 -0700117template <class Codec>
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700118void RtpSendParametersFromMediaDescription(
119 const MediaContentDescriptionImpl<Codec>* desc,
jbauch5869f502017-06-29 12:31:36 -0700120 const RtpHeaderExtensions& extensions,
nisse05103312016-03-16 02:22:50 -0700121 RtpSendParameters<Codec>* send_params) {
jbauch5869f502017-06-29 12:31:36 -0700122 RtpParametersFromMediaDescription(desc, extensions, send_params);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700123 send_params->max_bandwidth_bps = desc->bandwidth();
Johannes Kron9190b822018-10-29 11:22:05 +0100124 send_params->extmap_allow_mixed = desc->extmap_allow_mixed();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700125}
126
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200127BaseChannel::BaseChannel(rtc::Thread* worker_thread,
128 rtc::Thread* network_thread,
zhihuangf5b251b2017-01-12 19:37:48 -0800129 rtc::Thread* signaling_thread,
Steve Anton8699a322017-11-06 15:53:33 -0800130 std::unique_ptr<MediaChannel> media_channel,
deadbeefcbecd352015-09-23 11:50:27 -0700131 const std::string& content_name,
Zhi Huange830e682018-03-30 10:48:35 -0700132 bool srtp_required,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800133 webrtc::CryptoOptions crypto_options,
134 UniqueRandomIdGenerator* ssrc_generator)
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200135 : worker_thread_(worker_thread),
136 network_thread_(network_thread),
zhihuangf5b251b2017-01-12 19:37:48 -0800137 signaling_thread_(signaling_thread),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000138 content_name_(content_name),
deadbeef7af91dd2016-12-13 11:29:11 -0800139 srtp_required_(srtp_required),
Zhi Huange830e682018-03-30 10:48:35 -0700140 crypto_options_(crypto_options),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800141 media_channel_(std::move(media_channel)),
142 ssrc_generator_(ssrc_generator) {
Steve Anton8699a322017-11-06 15:53:33 -0800143 RTC_DCHECK_RUN_ON(worker_thread_);
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800144 RTC_DCHECK(ssrc_generator_);
Zhi Huang365381f2018-04-13 16:44:34 -0700145 demuxer_criteria_.mid = content_name;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100146 RTC_LOG(LS_INFO) << "Created channel for " << content_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000147}
148
149BaseChannel::~BaseChannel() {
Peter Boströmca8b4042016-03-08 14:24:13 -0800150 TRACE_EVENT0("webrtc", "BaseChannel::~BaseChannel");
Steve Anton8699a322017-11-06 15:53:33 -0800151 RTC_DCHECK_RUN_ON(worker_thread_);
Piotr (Peter) Slatala179a3922018-11-16 09:57:58 -0800152
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200153 // Eats any outstanding messages or packets.
154 worker_thread_->Clear(&invoker_);
155 worker_thread_->Clear(this);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000156 // We must destroy the media channel before the transport channel, otherwise
157 // the media channel may try to send on the dead transport channel. NULLing
158 // is not an effective strategy since the sends will come on another thread.
Steve Anton8699a322017-11-06 15:53:33 -0800159 media_channel_.reset();
Mirko Bonadei675513b2017-11-09 11:09:25 +0100160 RTC_LOG(LS_INFO) << "Destroyed channel: " << content_name_;
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200161}
162
Zhi Huang365381f2018-04-13 16:44:34 -0700163bool BaseChannel::ConnectToRtpTransport() {
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800164 RTC_DCHECK(rtp_transport_);
Zhi Huang365381f2018-04-13 16:44:34 -0700165 if (!RegisterRtpDemuxerSink()) {
166 return false;
167 }
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800168 rtp_transport_->SignalReadyToSend.connect(
169 this, &BaseChannel::OnTransportReadyToSend);
Bjorn A Mellem7a9a0922019-11-26 09:19:40 -0800170 rtp_transport_->SignalNetworkRouteChanged.connect(
171 this, &BaseChannel::OnNetworkRouteChanged);
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800172 rtp_transport_->SignalWritableState.connect(this,
173 &BaseChannel::OnWritableState);
174 rtp_transport_->SignalSentPacket.connect(this,
175 &BaseChannel::SignalSentPacket_n);
Zhi Huang365381f2018-04-13 16:44:34 -0700176 return true;
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800177}
Danil Chapovalovdae07ba2016-05-14 01:43:50 +0200178
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800179void BaseChannel::DisconnectFromRtpTransport() {
180 RTC_DCHECK(rtp_transport_);
Zhi Huang365381f2018-04-13 16:44:34 -0700181 rtp_transport_->UnregisterRtpDemuxerSink(this);
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800182 rtp_transport_->SignalReadyToSend.disconnect(this);
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800183 rtp_transport_->SignalNetworkRouteChanged.disconnect(this);
184 rtp_transport_->SignalWritableState.disconnect(this);
185 rtp_transport_->SignalSentPacket.disconnect(this);
Danil Chapovalovdae07ba2016-05-14 01:43:50 +0200186}
187
Anton Sukhanov4f08faa2019-05-21 11:12:57 -0700188void BaseChannel::Init_w(
189 webrtc::RtpTransportInternal* rtp_transport,
190 const webrtc::MediaTransportConfig& media_transport_config) {
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800191 RTC_DCHECK_RUN_ON(worker_thread_);
Anton Sukhanov4f08faa2019-05-21 11:12:57 -0700192 media_transport_config_ = media_transport_config;
Piotr (Peter) Slatala179a3922018-11-16 09:57:58 -0800193
Zhi Huang365381f2018-04-13 16:44:34 -0700194 network_thread_->Invoke<void>(
195 RTC_FROM_HERE, [this, rtp_transport] { SetRtpTransport(rtp_transport); });
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800196
197 // Both RTP and RTCP channels should be set, we can call SetInterface on
198 // the media channel and it can set network options.
Anton Sukhanov4f08faa2019-05-21 11:12:57 -0700199 media_channel_->SetInterface(this, media_transport_config);
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200200}
201
wu@webrtc.org78187522013-10-07 23:32:02 +0000202void BaseChannel::Deinit() {
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200203 RTC_DCHECK(worker_thread_->IsCurrent());
Anton Sukhanov98a462c2018-10-17 13:15:42 -0700204 media_channel_->SetInterface(/*iface=*/nullptr,
Anton Sukhanov4f08faa2019-05-21 11:12:57 -0700205 webrtc::MediaTransportConfig());
Danil Chapovalovdae07ba2016-05-14 01:43:50 +0200206 // Packets arrive on the network thread, processing packets calls virtual
207 // functions, so need to stop this process in Deinit that is called in
208 // derived classes destructor.
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800209 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
Zhi Huang95e7dbb2018-03-29 00:08:03 +0000210 FlushRtcpMessages_n();
Zhi Huang27f3bf52018-03-26 21:37:23 -0700211
Zhi Huange830e682018-03-30 10:48:35 -0700212 if (rtp_transport_) {
213 DisconnectFromRtpTransport();
Zhi Huang95e7dbb2018-03-29 00:08:03 +0000214 }
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800215 // Clear pending read packets/messages.
216 network_thread_->Clear(&invoker_);
217 network_thread_->Clear(this);
218 });
wu@webrtc.org78187522013-10-07 23:32:02 +0000219}
220
Zhi Huang365381f2018-04-13 16:44:34 -0700221bool BaseChannel::SetRtpTransport(webrtc::RtpTransportInternal* rtp_transport) {
222 if (rtp_transport == rtp_transport_) {
223 return true;
224 }
225
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800226 if (!network_thread_->IsCurrent()) {
Zhi Huang365381f2018-04-13 16:44:34 -0700227 return network_thread_->Invoke<bool>(RTC_FROM_HERE, [this, rtp_transport] {
228 return SetRtpTransport(rtp_transport);
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800229 });
230 }
Zhi Huang95e7dbb2018-03-29 00:08:03 +0000231
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800232 if (rtp_transport_) {
233 DisconnectFromRtpTransport();
234 }
Zhi Huange830e682018-03-30 10:48:35 -0700235
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800236 rtp_transport_ = rtp_transport;
Zhi Huange830e682018-03-30 10:48:35 -0700237 if (rtp_transport_) {
Bjorn A Mellem3a1b9272019-05-24 16:13:08 -0700238 transport_name_ = rtp_transport_->transport_name();
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800239
Zhi Huang365381f2018-04-13 16:44:34 -0700240 if (!ConnectToRtpTransport()) {
241 RTC_LOG(LS_ERROR) << "Failed to connect to the new RtpTransport.";
242 return false;
243 }
Zhi Huange830e682018-03-30 10:48:35 -0700244 OnTransportReadyToSend(rtp_transport_->IsReadyToSend());
245 UpdateWritableState_n();
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800246
Zhi Huange830e682018-03-30 10:48:35 -0700247 // Set the cached socket options.
248 for (const auto& pair : socket_options_) {
Bjorn A Mellem3a1b9272019-05-24 16:13:08 -0700249 rtp_transport_->SetRtpOption(pair.first, pair.second);
Zhi Huange830e682018-03-30 10:48:35 -0700250 }
Bjorn A Mellem3a1b9272019-05-24 16:13:08 -0700251 if (!rtp_transport_->rtcp_mux_enabled()) {
Zhi Huange830e682018-03-30 10:48:35 -0700252 for (const auto& pair : rtcp_socket_options_) {
Bjorn A Mellem3a1b9272019-05-24 16:13:08 -0700253 rtp_transport_->SetRtcpOption(pair.first, pair.second);
Zhi Huange830e682018-03-30 10:48:35 -0700254 }
255 }
guoweis46383312015-12-17 16:45:59 -0800256 }
Zhi Huang365381f2018-04-13 16:44:34 -0700257 return true;
pthatcher@webrtc.org6ad507a2015-03-16 20:19:12 +0000258}
259
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000260bool BaseChannel::Enable(bool enable) {
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700261 worker_thread_->Invoke<void>(
262 RTC_FROM_HERE,
263 Bind(enable ? &BaseChannel::EnableMedia_w : &BaseChannel::DisableMedia_w,
264 this));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000265 return true;
266}
267
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000268bool BaseChannel::SetLocalContent(const MediaContentDescription* content,
Steve Anton3828c062017-12-06 10:34:51 -0800269 SdpType type,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000270 std::string* error_desc) {
Peter Boström9f45a452015-12-08 13:25:57 +0100271 TRACE_EVENT0("webrtc", "BaseChannel::SetLocalContent");
stefanf79ade12017-06-02 06:44:03 -0700272 return InvokeOnWorker<bool>(
273 RTC_FROM_HERE,
Steve Anton3828c062017-12-06 10:34:51 -0800274 Bind(&BaseChannel::SetLocalContent_w, this, content, type, error_desc));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000275}
276
277bool BaseChannel::SetRemoteContent(const MediaContentDescription* content,
Steve Anton3828c062017-12-06 10:34:51 -0800278 SdpType type,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000279 std::string* error_desc) {
Peter Boström9f45a452015-12-08 13:25:57 +0100280 TRACE_EVENT0("webrtc", "BaseChannel::SetRemoteContent");
stefanf79ade12017-06-02 06:44:03 -0700281 return InvokeOnWorker<bool>(
Steve Anton3828c062017-12-06 10:34:51 -0800282 RTC_FROM_HERE,
283 Bind(&BaseChannel::SetRemoteContent_w, this, content, type, error_desc));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000284}
285
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700286bool BaseChannel::IsReadyToReceiveMedia_w() const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000287 // Receive data if we are enabled and have local content,
Steve Anton4e70a722017-11-28 14:57:10 -0800288 return enabled() &&
289 webrtc::RtpTransceiverDirectionHasRecv(local_content_direction_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000290}
291
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700292bool BaseChannel::IsReadyToSendMedia_w() const {
293 // Need to access some state updated on the network thread.
294 return network_thread_->Invoke<bool>(
295 RTC_FROM_HERE, Bind(&BaseChannel::IsReadyToSendMedia_n, this));
296}
297
298bool BaseChannel::IsReadyToSendMedia_n() const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000299 // Send outgoing data if we are enabled, have local and remote content,
300 // and we have had some form of connectivity.
Steve Anton4e70a722017-11-28 14:57:10 -0800301 return enabled() &&
302 webrtc::RtpTransceiverDirectionHasRecv(remote_content_direction_) &&
303 webrtc::RtpTransceiverDirectionHasSend(local_content_direction_) &&
Zhi Huang365381f2018-04-13 16:44:34 -0700304 was_ever_writable();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000305}
306
jbaucheec21bd2016-03-20 06:15:43 -0700307bool BaseChannel::SendPacket(rtc::CopyOnWriteBuffer* packet,
stefanc1aeaf02015-10-15 07:26:07 -0700308 const rtc::PacketOptions& options) {
309 return SendPacket(false, packet, options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000310}
311
jbaucheec21bd2016-03-20 06:15:43 -0700312bool BaseChannel::SendRtcp(rtc::CopyOnWriteBuffer* packet,
stefanc1aeaf02015-10-15 07:26:07 -0700313 const rtc::PacketOptions& options) {
314 return SendPacket(true, packet, options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000315}
316
Yves Gerey665174f2018-06-19 15:03:05 +0200317int BaseChannel::SetOption(SocketType type,
318 rtc::Socket::Option opt,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000319 int value) {
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200320 return network_thread_->Invoke<int>(
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700321 RTC_FROM_HERE, Bind(&BaseChannel::SetOption_n, this, type, opt, value));
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200322}
323
324int BaseChannel::SetOption_n(SocketType type,
325 rtc::Socket::Option opt,
326 int value) {
327 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange830e682018-03-30 10:48:35 -0700328 RTC_DCHECK(rtp_transport_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000329 switch (type) {
wu@webrtc.org9caf2762013-12-11 18:25:07 +0000330 case ST_RTP:
deadbeefcbecd352015-09-23 11:50:27 -0700331 socket_options_.push_back(
332 std::pair<rtc::Socket::Option, int>(opt, value));
Bjorn A Mellem3a1b9272019-05-24 16:13:08 -0700333 return rtp_transport_->SetRtpOption(opt, value);
wu@webrtc.org9caf2762013-12-11 18:25:07 +0000334 case ST_RTCP:
deadbeefcbecd352015-09-23 11:50:27 -0700335 rtcp_socket_options_.push_back(
336 std::pair<rtc::Socket::Option, int>(opt, value));
Bjorn A Mellem3a1b9272019-05-24 16:13:08 -0700337 return rtp_transport_->SetRtcpOption(opt, value);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000338 }
Bjorn A Mellem3a1b9272019-05-24 16:13:08 -0700339 return -1;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000340}
341
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800342void BaseChannel::OnWritableState(bool writable) {
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200343 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800344 if (writable) {
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800345 ChannelWritable_n();
346 } else {
347 ChannelNotWritable_n();
Guo-wei Shieh1218d7a2015-12-05 09:59:56 -0800348 }
349}
350
Zhi Huang942bc2e2017-11-13 13:26:07 -0800351void BaseChannel::OnNetworkRouteChanged(
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200352 absl::optional<rtc::NetworkRoute> network_route) {
Piotr (Peter) Slatala179a3922018-11-16 09:57:58 -0800353 RTC_LOG(LS_INFO) << "Network route was changed.";
354
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200355 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huang942bc2e2017-11-13 13:26:07 -0800356 rtc::NetworkRoute new_route;
357 if (network_route) {
Zhi Huang942bc2e2017-11-13 13:26:07 -0800358 new_route = *(network_route);
Zhi Huang8c316c12017-11-13 21:13:45 +0000359 }
Zhi Huang942bc2e2017-11-13 13:26:07 -0800360 // Note: When the RTCP-muxing is not enabled, RTCP transport and RTP transport
361 // use the same transport name and MediaChannel::OnNetworkRouteChanged cannot
362 // work correctly. Intentionally leave it broken to simplify the code and
363 // encourage the users to stop using non-muxing RTCP.
Steve Anton8699a322017-11-06 15:53:33 -0800364 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, worker_thread_, [=] {
Zhi Huang942bc2e2017-11-13 13:26:07 -0800365 media_channel_->OnNetworkRouteChanged(transport_name_, new_route);
Steve Anton8699a322017-11-06 15:53:33 -0800366 });
Honghai Zhangcc411c02016-03-29 17:27:21 -0700367}
368
zstein56162b92017-04-24 16:54:35 -0700369void BaseChannel::OnTransportReadyToSend(bool ready) {
Steve Anton8699a322017-11-06 15:53:33 -0800370 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, worker_thread_,
371 [=] { media_channel_->OnReadyToSend(ready); });
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000372}
373
stefanc1aeaf02015-10-15 07:26:07 -0700374bool BaseChannel::SendPacket(bool rtcp,
jbaucheec21bd2016-03-20 06:15:43 -0700375 rtc::CopyOnWriteBuffer* packet,
stefanc1aeaf02015-10-15 07:26:07 -0700376 const rtc::PacketOptions& options) {
Amit Hilbuchedd20542019-03-18 12:33:43 -0700377 // Until all the code is migrated to use RtpPacketType instead of bool.
378 RtpPacketType packet_type = rtcp ? RtpPacketType::kRtcp : RtpPacketType::kRtp;
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200379 // SendPacket gets called from MediaEngine, on a pacer or an encoder thread.
380 // If the thread is not our network thread, we will post to our network
381 // so that the real work happens on our network. This avoids us having to
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000382 // synchronize access to all the pieces of the send path, including
383 // SRTP and the inner workings of the transport channels.
384 // The only downside is that we can't return a proper failure code if
385 // needed. Since UDP is unreliable anyway, this should be a non-issue.
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200386 if (!network_thread_->IsCurrent()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000387 // Avoid a copy by transferring the ownership of the packet data.
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200388 int message_id = rtcp ? MSG_SEND_RTCP_PACKET : MSG_SEND_RTP_PACKET;
389 SendPacketMessageData* data = new SendPacketMessageData;
kwiberg0eb15ed2015-12-17 03:04:15 -0800390 data->packet = std::move(*packet);
stefanc1aeaf02015-10-15 07:26:07 -0700391 data->options = options;
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700392 network_thread_->Post(RTC_FROM_HERE, this, message_id, data);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000393 return true;
394 }
Zhi Huange830e682018-03-30 10:48:35 -0700395
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200396 TRACE_EVENT0("webrtc", "BaseChannel::SendPacket");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000397
398 // Now that we are on the correct thread, ensure we have a place to send this
399 // packet before doing anything. (We might get RTCP packets that we don't
400 // intend to send.) If we've negotiated RTCP mux, send RTCP over the RTP
401 // transport.
Zhi Huange830e682018-03-30 10:48:35 -0700402 if (!rtp_transport_ || !rtp_transport_->IsWritable(rtcp)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000403 return false;
404 }
405
406 // Protect ourselves against crazy data.
Amit Hilbuchedd20542019-03-18 12:33:43 -0700407 if (!IsValidRtpPacketSize(packet_type, packet->size())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100408 RTC_LOG(LS_ERROR) << "Dropping outgoing " << content_name_ << " "
Amit Hilbuchedd20542019-03-18 12:33:43 -0700409 << RtpPacketTypeToString(packet_type)
Mirko Bonadei675513b2017-11-09 11:09:25 +0100410 << " packet: wrong size=" << packet->size();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000411 return false;
412 }
413
Zhi Huangcf990f52017-09-22 12:12:30 -0700414 if (!srtp_active()) {
415 if (srtp_required_) {
416 // The audio/video engines may attempt to send RTCP packets as soon as the
417 // streams are created, so don't treat this as an error for RTCP.
418 // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=6809
419 if (rtcp) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000420 return false;
421 }
Zhi Huangcf990f52017-09-22 12:12:30 -0700422 // However, there shouldn't be any RTP packets sent before SRTP is set up
423 // (and SetSend(true) is called).
Mirko Bonadei675513b2017-11-09 11:09:25 +0100424 RTC_LOG(LS_ERROR)
425 << "Can't send outgoing RTP packet when SRTP is inactive"
426 << " and crypto is required";
Zhi Huangcf990f52017-09-22 12:12:30 -0700427 RTC_NOTREACHED();
deadbeef8f425f92016-12-01 12:26:27 -0800428 return false;
429 }
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800430
431 std::string packet_type = rtcp ? "RTCP" : "RTP";
432 RTC_LOG(LS_WARNING) << "Sending an " << packet_type
433 << " packet without encryption.";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000434 }
Zhi Huange830e682018-03-30 10:48:35 -0700435
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000436 // Bon voyage.
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800437 return rtcp ? rtp_transport_->SendRtcpPacket(packet, options, PF_SRTP_BYPASS)
438 : rtp_transport_->SendRtpPacket(packet, options, PF_SRTP_BYPASS);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000439}
440
Zhi Huang365381f2018-04-13 16:44:34 -0700441void BaseChannel::OnRtpPacket(const webrtc::RtpPacketReceived& parsed_packet) {
Niels Möller29e13fd2018-12-17 12:35:30 +0100442 // Take packet time from the |parsed_packet|.
443 // RtpPacketReceived.arrival_time_ms = (timestamp_us + 500) / 1000;
Sebastian Jansson1b83a9e2019-09-18 18:22:12 +0200444 int64_t packet_time_us = -1;
Zhi Huang365381f2018-04-13 16:44:34 -0700445 if (parsed_packet.arrival_time_ms() > 0) {
Sebastian Jansson1b83a9e2019-09-18 18:22:12 +0200446 packet_time_us = parsed_packet.arrival_time_ms() * 1000;
Zhi Huang365381f2018-04-13 16:44:34 -0700447 }
Zhi Huang365381f2018-04-13 16:44:34 -0700448
Sebastian Jansson1b83a9e2019-09-18 18:22:12 +0200449 if (!has_received_packet_) {
450 has_received_packet_ = true;
451 signaling_thread()->Post(RTC_FROM_HERE, this, MSG_FIRSTPACKETRECEIVED);
452 }
453
454 if (!srtp_active() && srtp_required_) {
455 // Our session description indicates that SRTP is required, but we got a
456 // packet before our SRTP filter is active. This means either that
457 // a) we got SRTP packets before we received the SDES keys, in which case
458 // we can't decrypt it anyway, or
459 // b) we got SRTP packets before DTLS completed on both the RTP and RTCP
460 // transports, so we haven't yet extracted keys, even if DTLS did
461 // complete on the transport that the packets are being sent on. It's
462 // really good practice to wait for both RTP and RTCP to be good to go
463 // before sending media, to prevent weird failure modes, so it's fine
464 // for us to just eat packets here. This is all sidestepped if RTCP mux
465 // is used anyway.
466 RTC_LOG(LS_WARNING) << "Can't process incoming RTP packet when "
467 "SRTP is inactive and crypto is required";
468 return;
469 }
470
471 auto packet_buffer = parsed_packet.Buffer();
472
473 invoker_.AsyncInvoke<void>(
474 RTC_FROM_HERE, worker_thread_, [this, packet_buffer, packet_time_us] {
475 RTC_DCHECK(worker_thread_->IsCurrent());
476 media_channel_->OnPacketReceived(packet_buffer, packet_time_us);
477 });
Zhi Huang365381f2018-04-13 16:44:34 -0700478}
479
480void BaseChannel::UpdateRtpHeaderExtensionMap(
481 const RtpHeaderExtensions& header_extensions) {
482 RTC_DCHECK(rtp_transport_);
483 // Update the header extension map on network thread in case there is data
484 // race.
485 // TODO(zhihuang): Add an rtc::ThreadChecker make sure to RtpTransport won't
486 // be accessed from different threads.
487 //
488 // NOTE: This doesn't take the BUNDLE case in account meaning the RTP header
489 // extension maps are not merged when BUNDLE is enabled. This is fine because
490 // the ID for MID should be consistent among all the RTP transports.
491 network_thread_->Invoke<void>(RTC_FROM_HERE, [this, &header_extensions] {
492 rtp_transport_->UpdateRtpHeaderExtensionMap(header_extensions);
493 });
494}
495
496bool BaseChannel::RegisterRtpDemuxerSink() {
497 RTC_DCHECK(rtp_transport_);
498 return network_thread_->Invoke<bool>(RTC_FROM_HERE, [this] {
499 return rtp_transport_->RegisterRtpDemuxerSink(demuxer_criteria_, this);
500 });
501}
502
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000503void BaseChannel::EnableMedia_w() {
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700504 RTC_DCHECK(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000505 if (enabled_)
506 return;
507
Mirko Bonadei675513b2017-11-09 11:09:25 +0100508 RTC_LOG(LS_INFO) << "Channel enabled";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000509 enabled_ = true;
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700510 UpdateMediaSendRecvState_w();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000511}
512
513void BaseChannel::DisableMedia_w() {
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700514 RTC_DCHECK(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000515 if (!enabled_)
516 return;
517
Mirko Bonadei675513b2017-11-09 11:09:25 +0100518 RTC_LOG(LS_INFO) << "Channel disabled";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000519 enabled_ = false;
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700520 UpdateMediaSendRecvState_w();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000521}
522
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200523void BaseChannel::UpdateWritableState_n() {
Zhi Huange830e682018-03-30 10:48:35 -0700524 if (rtp_transport_->IsWritable(/*rtcp=*/true) &&
525 rtp_transport_->IsWritable(/*rtcp=*/false)) {
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200526 ChannelWritable_n();
deadbeefcbecd352015-09-23 11:50:27 -0700527 } else {
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200528 ChannelNotWritable_n();
deadbeefcbecd352015-09-23 11:50:27 -0700529 }
530}
531
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200532void BaseChannel::ChannelWritable_n() {
533 RTC_DCHECK(network_thread_->IsCurrent());
Guo-wei Shieh1218d7a2015-12-05 09:59:56 -0800534 if (writable_) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000535 return;
Guo-wei Shieh1218d7a2015-12-05 09:59:56 -0800536 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000537
Mirko Bonadei675513b2017-11-09 11:09:25 +0100538 RTC_LOG(LS_INFO) << "Channel writable (" << content_name_ << ")"
539 << (was_ever_writable_ ? "" : " for the first time");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000540
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000541 was_ever_writable_ = true;
542 writable_ = true;
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700543 UpdateMediaSendRecvState();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000544}
545
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200546void BaseChannel::ChannelNotWritable_n() {
547 RTC_DCHECK(network_thread_->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000548 if (!writable_)
549 return;
550
Mirko Bonadei675513b2017-11-09 11:09:25 +0100551 RTC_LOG(LS_INFO) << "Channel not writable (" << content_name_ << ")";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000552 writable_ = false;
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700553 UpdateMediaSendRecvState();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000554}
555
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000556bool BaseChannel::AddRecvStream_w(const StreamParams& sp) {
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700557 RTC_DCHECK(worker_thread() == rtc::Thread::Current());
pbos482b12e2015-11-16 10:19:58 -0800558 return media_channel()->AddRecvStream(sp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000559}
560
Peter Boström0c4e06b2015-10-07 12:23:21 +0200561bool BaseChannel::RemoveRecvStream_w(uint32_t ssrc) {
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700562 RTC_DCHECK(worker_thread() == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000563 return media_channel()->RemoveRecvStream(ssrc);
564}
565
Saurav Dasff27da52019-09-20 11:05:30 -0700566void BaseChannel::ResetUnsignaledRecvStream_w() {
567 RTC_DCHECK(worker_thread() == rtc::Thread::Current());
568 media_channel()->ResetUnsignaledRecvStream();
569}
570
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000571bool BaseChannel::UpdateLocalStreams_w(const std::vector<StreamParams>& streams,
Steve Anton3828c062017-12-06 10:34:51 -0800572 SdpType type,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000573 std::string* error_desc) {
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800574 // In the case of RIDs (where SSRCs are not negotiated), this method will
575 // generate an SSRC for each layer in StreamParams. That representation will
576 // be stored internally in |local_streams_|.
577 // In subsequent offers, the same stream can appear in |streams| again
578 // (without the SSRCs), so it should be looked up using RIDs (if available)
579 // and then by primary SSRC.
580 // In both scenarios, it is safe to assume that the media channel will be
581 // created with a StreamParams object with SSRCs. However, it is not safe to
582 // assume that |local_streams_| will always have SSRCs as there are scenarios
583 // in which niether SSRCs or RIDs are negotiated.
584
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000585 // Check for streams that have been removed.
586 bool ret = true;
Steve Anton5f8b5fd2018-12-27 16:58:10 -0800587 for (const StreamParams& old_stream : local_streams_) {
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800588 if (!old_stream.has_ssrcs() ||
589 GetStream(streams, StreamFinder(&old_stream))) {
590 continue;
591 }
592 if (!media_channel()->RemoveSendStream(old_stream.first_ssrc())) {
593 rtc::StringBuilder desc;
594 desc << "Failed to remove send stream with ssrc "
595 << old_stream.first_ssrc() << ".";
596 SafeSetError(desc.str(), error_desc);
597 ret = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000598 }
599 }
600 // Check for new streams.
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800601 std::vector<StreamParams> all_streams;
602 for (const StreamParams& stream : streams) {
603 StreamParams* existing = GetStream(local_streams_, StreamFinder(&stream));
604 if (existing) {
605 // Parameters cannot change for an existing stream.
606 all_streams.push_back(*existing);
607 continue;
608 }
609
610 all_streams.push_back(stream);
611 StreamParams& new_stream = all_streams.back();
612
613 if (!new_stream.has_ssrcs() && !new_stream.has_rids()) {
614 continue;
615 }
616
617 RTC_DCHECK(new_stream.has_ssrcs() || new_stream.has_rids());
618 if (new_stream.has_ssrcs() && new_stream.has_rids()) {
619 rtc::StringBuilder desc;
620 desc << "Failed to add send stream: " << new_stream.first_ssrc()
621 << ". Stream has both SSRCs and RIDs.";
622 SafeSetError(desc.str(), error_desc);
623 ret = false;
624 continue;
625 }
626
627 // At this point we use the legacy simulcast group in StreamParams to
628 // indicate that we want multiple layers to the media channel.
629 if (!new_stream.has_ssrcs()) {
630 // TODO(bugs.webrtc.org/10250): Indicate if flex is desired here.
631 new_stream.GenerateSsrcs(new_stream.rids().size(), /* rtx = */ true,
632 /* flex_fec = */ false, ssrc_generator_);
633 }
634
635 if (media_channel()->AddSendStream(new_stream)) {
636 RTC_LOG(LS_INFO) << "Add send stream ssrc: " << new_stream.ssrcs[0];
637 } else {
638 rtc::StringBuilder desc;
639 desc << "Failed to add send stream ssrc: " << new_stream.first_ssrc();
640 SafeSetError(desc.str(), error_desc);
641 ret = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000642 }
643 }
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800644 local_streams_ = all_streams;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000645 return ret;
646}
647
648bool BaseChannel::UpdateRemoteStreams_w(
649 const std::vector<StreamParams>& streams,
Steve Anton3828c062017-12-06 10:34:51 -0800650 SdpType type,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000651 std::string* error_desc) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000652 // Check for streams that have been removed.
653 bool ret = true;
Steve Anton5f8b5fd2018-12-27 16:58:10 -0800654 for (const StreamParams& old_stream : remote_streams_) {
Seth Hampson5897a6e2018-04-03 11:16:33 -0700655 // If we no longer have an unsignaled stream, we would like to remove
656 // the unsignaled stream params that are cached.
Saurav Dasff27da52019-09-20 11:05:30 -0700657 if (!old_stream.has_ssrcs() && !HasStreamWithNoSsrcs(streams)) {
658 ResetUnsignaledRecvStream_w();
659 RTC_LOG(LS_INFO) << "Reset unsignaled remote stream.";
660 } else if (old_stream.has_ssrcs() &&
661 !GetStreamBySsrc(streams, old_stream.first_ssrc())) {
Steve Anton5f8b5fd2018-12-27 16:58:10 -0800662 if (RemoveRecvStream_w(old_stream.first_ssrc())) {
663 RTC_LOG(LS_INFO) << "Remove remote ssrc: " << old_stream.first_ssrc();
Zhi Huang365381f2018-04-13 16:44:34 -0700664 } else {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200665 rtc::StringBuilder desc;
Steve Anton5f8b5fd2018-12-27 16:58:10 -0800666 desc << "Failed to remove remote stream with ssrc "
667 << old_stream.first_ssrc() << ".";
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000668 SafeSetError(desc.str(), error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000669 ret = false;
670 }
671 }
672 }
Zhi Huang365381f2018-04-13 16:44:34 -0700673 demuxer_criteria_.ssrcs.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000674 // Check for new streams.
Steve Anton5f8b5fd2018-12-27 16:58:10 -0800675 for (const StreamParams& new_stream : streams) {
Seth Hampson5897a6e2018-04-03 11:16:33 -0700676 // We allow a StreamParams with an empty list of SSRCs, in which case the
677 // MediaChannel will cache the parameters and use them for any unsignaled
678 // stream received later.
Steve Anton5f8b5fd2018-12-27 16:58:10 -0800679 if ((!new_stream.has_ssrcs() && !HasStreamWithNoSsrcs(remote_streams_)) ||
680 !GetStreamBySsrc(remote_streams_, new_stream.first_ssrc())) {
681 if (AddRecvStream_w(new_stream)) {
Saurav Dasff27da52019-09-20 11:05:30 -0700682 RTC_LOG(LS_INFO) << "Add remote ssrc: "
683 << (new_stream.has_ssrcs()
684 ? std::to_string(new_stream.first_ssrc())
685 : "unsignaled");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000686 } else {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200687 rtc::StringBuilder desc;
Saurav Dasff27da52019-09-20 11:05:30 -0700688 desc << "Failed to add remote stream ssrc: "
689 << (new_stream.has_ssrcs()
690 ? std::to_string(new_stream.first_ssrc())
691 : "unsignaled");
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000692 SafeSetError(desc.str(), error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000693 ret = false;
694 }
695 }
Zhi Huang365381f2018-04-13 16:44:34 -0700696 // Update the receiving SSRCs.
Steve Anton5f8b5fd2018-12-27 16:58:10 -0800697 demuxer_criteria_.ssrcs.insert(new_stream.ssrcs.begin(),
698 new_stream.ssrcs.end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000699 }
Zhi Huang365381f2018-04-13 16:44:34 -0700700 // Re-register the sink to update the receiving ssrcs.
701 RegisterRtpDemuxerSink();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000702 remote_streams_ = streams;
703 return ret;
704}
705
jbauch5869f502017-06-29 12:31:36 -0700706RtpHeaderExtensions BaseChannel::GetFilteredRtpHeaderExtensions(
707 const RtpHeaderExtensions& extensions) {
Zhi Huange830e682018-03-30 10:48:35 -0700708 RTC_DCHECK(rtp_transport_);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700709 if (crypto_options_.srtp.enable_encrypted_rtp_header_extensions) {
jbauch5869f502017-06-29 12:31:36 -0700710 RtpHeaderExtensions filtered;
Steve Anton64b626b2019-01-28 17:25:26 -0800711 absl::c_copy_if(extensions, std::back_inserter(filtered),
712 [](const webrtc::RtpExtension& extension) {
713 return !extension.encrypt;
714 });
jbauch5869f502017-06-29 12:31:36 -0700715 return filtered;
716 }
717
718 return webrtc::RtpExtension::FilterDuplicateNonEncrypted(extensions);
719}
720
Yves Gerey665174f2018-06-19 15:03:05 +0200721void BaseChannel::OnMessage(rtc::Message* pmsg) {
Peter Boström6f28cf02015-12-07 23:17:15 +0100722 TRACE_EVENT0("webrtc", "BaseChannel::OnMessage");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000723 switch (pmsg->message_id) {
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200724 case MSG_SEND_RTP_PACKET:
725 case MSG_SEND_RTCP_PACKET: {
726 RTC_DCHECK(network_thread_->IsCurrent());
727 SendPacketMessageData* data =
728 static_cast<SendPacketMessageData*>(pmsg->pdata);
729 bool rtcp = pmsg->message_id == MSG_SEND_RTCP_PACKET;
730 SendPacket(rtcp, &data->packet, data->options);
731 delete data;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000732 break;
733 }
734 case MSG_FIRSTPACKETRECEIVED: {
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800735 SignalFirstPacketReceived_(this);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000736 break;
737 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000738 }
739}
740
zstein3dcf0e92017-06-01 13:22:42 -0700741void BaseChannel::AddHandledPayloadType(int payload_type) {
Zhi Huang365381f2018-04-13 16:44:34 -0700742 demuxer_criteria_.payload_types.insert(static_cast<uint8_t>(payload_type));
zstein3dcf0e92017-06-01 13:22:42 -0700743}
744
Steve Antonbe2e5f72019-09-06 16:26:02 -0700745void BaseChannel::ClearHandledPayloadTypes() {
746 demuxer_criteria_.payload_types.clear();
747}
748
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200749void BaseChannel::FlushRtcpMessages_n() {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000750 // Flush all remaining RTCP messages. This should only be called in
751 // destructor.
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200752 RTC_DCHECK(network_thread_->IsCurrent());
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000753 rtc::MessageList rtcp_messages;
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200754 network_thread_->Clear(this, MSG_SEND_RTCP_PACKET, &rtcp_messages);
755 for (const auto& message : rtcp_messages) {
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700756 network_thread_->Send(RTC_FROM_HERE, this, MSG_SEND_RTCP_PACKET,
757 message.pdata);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000758 }
759}
760
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800761void BaseChannel::SignalSentPacket_n(const rtc::SentPacket& sent_packet) {
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200762 RTC_DCHECK(network_thread_->IsCurrent());
Sebastian Jansson01be33b2019-09-12 17:39:18 +0200763 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, worker_thread_,
764 [this, sent_packet] {
765 RTC_DCHECK(worker_thread_->IsCurrent());
766 SignalSentPacket(sent_packet);
767 });
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200768}
769
770VoiceChannel::VoiceChannel(rtc::Thread* worker_thread,
771 rtc::Thread* network_thread,
zhihuangf5b251b2017-01-12 19:37:48 -0800772 rtc::Thread* signaling_thread,
Steve Anton8699a322017-11-06 15:53:33 -0800773 std::unique_ptr<VoiceMediaChannel> media_channel,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000774 const std::string& content_name,
Zhi Huange830e682018-03-30 10:48:35 -0700775 bool srtp_required,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800776 webrtc::CryptoOptions crypto_options,
777 UniqueRandomIdGenerator* ssrc_generator)
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200778 : BaseChannel(worker_thread,
779 network_thread,
zhihuangf5b251b2017-01-12 19:37:48 -0800780 signaling_thread,
Steve Anton8699a322017-11-06 15:53:33 -0800781 std::move(media_channel),
deadbeefcbecd352015-09-23 11:50:27 -0700782 content_name,
Zhi Huange830e682018-03-30 10:48:35 -0700783 srtp_required,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800784 crypto_options,
785 ssrc_generator) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000786
787VoiceChannel::~VoiceChannel() {
Peter Boströmca8b4042016-03-08 14:24:13 -0800788 TRACE_EVENT0("webrtc", "VoiceChannel::~VoiceChannel");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000789 // this can't be done in the base class, since it calls a virtual
790 DisableMedia_w();
Zhi Huang0ffe03d2018-03-30 13:17:42 -0700791 Deinit();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000792}
793
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700794void BaseChannel::UpdateMediaSendRecvState() {
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200795 RTC_DCHECK(network_thread_->IsCurrent());
Sebastian Jansson01be33b2019-09-12 17:39:18 +0200796 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, worker_thread_,
797 [this] { UpdateMediaSendRecvState_w(); });
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200798}
799
Anton Sukhanov4f08faa2019-05-21 11:12:57 -0700800void VoiceChannel::Init_w(
801 webrtc::RtpTransportInternal* rtp_transport,
802 const webrtc::MediaTransportConfig& media_transport_config) {
803 BaseChannel::Init_w(rtp_transport, media_transport_config);
Piotr (Peter) Slatala309aafe2019-01-15 14:24:34 -0800804}
805
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700806void VoiceChannel::UpdateMediaSendRecvState_w() {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000807 // Render incoming data if we're the active call, and we have the local
808 // content. We receive data on the default channel and multiplexed streams.
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700809 bool recv = IsReadyToReceiveMedia_w();
solenberg5b14b422015-10-01 04:10:31 -0700810 media_channel()->SetPlayout(recv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000811
812 // Send outgoing data if we're the active call, we have the remote content,
813 // and we have had some form of connectivity.
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700814 bool send = IsReadyToSendMedia_w();
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800815 media_channel()->SetSend(send);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000816
Mirko Bonadei675513b2017-11-09 11:09:25 +0100817 RTC_LOG(LS_INFO) << "Changing voice state, recv=" << recv << " send=" << send;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000818}
819
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000820bool VoiceChannel::SetLocalContent_w(const MediaContentDescription* content,
Steve Anton3828c062017-12-06 10:34:51 -0800821 SdpType type,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000822 std::string* error_desc) {
Peter Boström9f45a452015-12-08 13:25:57 +0100823 TRACE_EVENT0("webrtc", "VoiceChannel::SetLocalContent_w");
Steve Antonb1c1de12017-12-21 15:14:30 -0800824 RTC_DCHECK_RUN_ON(worker_thread());
Mirko Bonadei675513b2017-11-09 11:09:25 +0100825 RTC_LOG(LS_INFO) << "Setting local voice description";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000826
Steve Antonb1c1de12017-12-21 15:14:30 -0800827 RTC_DCHECK(content);
828 if (!content) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000829 SafeSetError("Can't find audio content in local description.", error_desc);
830 return false;
831 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000832
Steve Antonb1c1de12017-12-21 15:14:30 -0800833 const AudioContentDescription* audio = content->as_audio();
834
jbauch5869f502017-06-29 12:31:36 -0700835 RtpHeaderExtensions rtp_header_extensions =
836 GetFilteredRtpHeaderExtensions(audio->rtp_header_extensions());
Zhi Huang365381f2018-04-13 16:44:34 -0700837 UpdateRtpHeaderExtensionMap(rtp_header_extensions);
Johannes Kron9190b822018-10-29 11:22:05 +0100838 media_channel()->SetExtmapAllowMixed(audio->extmap_allow_mixed());
jbauch5869f502017-06-29 12:31:36 -0700839
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700840 AudioRecvParameters recv_params = last_recv_params_;
jbauch5869f502017-06-29 12:31:36 -0700841 RtpParametersFromMediaDescription(audio, rtp_header_extensions, &recv_params);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700842 if (!media_channel()->SetRecvParameters(recv_params)) {
Peter Thatcherbfab5cb2015-08-20 17:40:24 -0700843 SafeSetError("Failed to set local audio description recv parameters.",
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700844 error_desc);
845 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000846 }
Steve Antonbe2e5f72019-09-06 16:26:02 -0700847
848 if (webrtc::RtpTransceiverDirectionHasRecv(audio->direction())) {
849 for (const AudioCodec& codec : audio->codecs()) {
850 AddHandledPayloadType(codec.id);
851 }
852 // Need to re-register the sink to update the handled payload.
853 if (!RegisterRtpDemuxerSink()) {
854 RTC_LOG(LS_ERROR) << "Failed to set up audio demuxing.";
855 return false;
856 }
Zhi Huang365381f2018-04-13 16:44:34 -0700857 }
858
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700859 last_recv_params_ = recv_params;
860
861 // TODO(pthatcher): Move local streams into AudioSendParameters, and
862 // only give it to the media channel once we have a remote
863 // description too (without a remote description, we won't be able
864 // to send them anyway).
Steve Anton3828c062017-12-06 10:34:51 -0800865 if (!UpdateLocalStreams_w(audio->streams(), type, error_desc)) {
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700866 SafeSetError("Failed to set local audio description streams.", error_desc);
867 return false;
868 }
869
870 set_local_content_direction(content->direction());
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700871 UpdateMediaSendRecvState_w();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700872 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000873}
874
875bool VoiceChannel::SetRemoteContent_w(const MediaContentDescription* content,
Steve Anton3828c062017-12-06 10:34:51 -0800876 SdpType type,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000877 std::string* error_desc) {
Peter Boström9f45a452015-12-08 13:25:57 +0100878 TRACE_EVENT0("webrtc", "VoiceChannel::SetRemoteContent_w");
Steve Antonb1c1de12017-12-21 15:14:30 -0800879 RTC_DCHECK_RUN_ON(worker_thread());
Mirko Bonadei675513b2017-11-09 11:09:25 +0100880 RTC_LOG(LS_INFO) << "Setting remote voice description";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000881
Steve Antonb1c1de12017-12-21 15:14:30 -0800882 RTC_DCHECK(content);
883 if (!content) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000884 SafeSetError("Can't find audio content in remote description.", error_desc);
885 return false;
886 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000887
Steve Antonb1c1de12017-12-21 15:14:30 -0800888 const AudioContentDescription* audio = content->as_audio();
889
jbauch5869f502017-06-29 12:31:36 -0700890 RtpHeaderExtensions rtp_header_extensions =
891 GetFilteredRtpHeaderExtensions(audio->rtp_header_extensions());
892
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700893 AudioSendParameters send_params = last_send_params_;
jbauch5869f502017-06-29 12:31:36 -0700894 RtpSendParametersFromMediaDescription(audio, rtp_header_extensions,
Yves Gerey665174f2018-06-19 15:03:05 +0200895 &send_params);
Steve Antonbb50ce52018-03-26 10:24:32 -0700896 send_params.mid = content_name();
skvladdc1c62c2016-03-16 19:07:43 -0700897
898 bool parameters_applied = media_channel()->SetSendParameters(send_params);
899 if (!parameters_applied) {
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700900 SafeSetError("Failed to set remote audio description send parameters.",
901 error_desc);
902 return false;
903 }
904 last_send_params_ = send_params;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000905
Steve Antonbe2e5f72019-09-06 16:26:02 -0700906 if (!webrtc::RtpTransceiverDirectionHasSend(content->direction())) {
907 RTC_DLOG(LS_VERBOSE) << "SetRemoteContent_w: remote side will not send - "
908 "disable payload type demuxing";
909 ClearHandledPayloadTypes();
910 if (!RegisterRtpDemuxerSink()) {
911 RTC_LOG(LS_ERROR) << "Failed to update audio demuxing.";
912 return false;
913 }
914 }
915
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700916 // TODO(pthatcher): Move remote streams into AudioRecvParameters,
917 // and only give it to the media channel once we have a local
918 // description too (without a local description, we won't be able to
919 // recv them anyway).
Steve Anton3828c062017-12-06 10:34:51 -0800920 if (!UpdateRemoteStreams_w(audio->streams(), type, error_desc)) {
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700921 SafeSetError("Failed to set remote audio description streams.", error_desc);
922 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000923 }
924
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700925 set_remote_content_direction(content->direction());
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700926 UpdateMediaSendRecvState_w();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700927 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000928}
929
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200930VideoChannel::VideoChannel(rtc::Thread* worker_thread,
931 rtc::Thread* network_thread,
zhihuangf5b251b2017-01-12 19:37:48 -0800932 rtc::Thread* signaling_thread,
Steve Anton8699a322017-11-06 15:53:33 -0800933 std::unique_ptr<VideoMediaChannel> media_channel,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000934 const std::string& content_name,
Zhi Huange830e682018-03-30 10:48:35 -0700935 bool srtp_required,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800936 webrtc::CryptoOptions crypto_options,
937 UniqueRandomIdGenerator* ssrc_generator)
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200938 : BaseChannel(worker_thread,
939 network_thread,
zhihuangf5b251b2017-01-12 19:37:48 -0800940 signaling_thread,
Steve Anton8699a322017-11-06 15:53:33 -0800941 std::move(media_channel),
deadbeefcbecd352015-09-23 11:50:27 -0700942 content_name,
Zhi Huange830e682018-03-30 10:48:35 -0700943 srtp_required,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800944 crypto_options,
945 ssrc_generator) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000946
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000947VideoChannel::~VideoChannel() {
Peter Boströmca8b4042016-03-08 14:24:13 -0800948 TRACE_EVENT0("webrtc", "VideoChannel::~VideoChannel");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000949 // this can't be done in the base class, since it calls a virtual
950 DisableMedia_w();
Zhi Huang0ffe03d2018-03-30 13:17:42 -0700951 Deinit();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000952}
953
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700954void VideoChannel::UpdateMediaSendRecvState_w() {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000955 // Send outgoing data if we're the active call, we have the remote content,
956 // and we have had some form of connectivity.
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700957 bool send = IsReadyToSendMedia_w();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000958 if (!media_channel()->SetSend(send)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100959 RTC_LOG(LS_ERROR) << "Failed to SetSend on video channel";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000960 // TODO(gangji): Report error back to server.
961 }
962
Mirko Bonadei675513b2017-11-09 11:09:25 +0100963 RTC_LOG(LS_INFO) << "Changing video state, send=" << send;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000964}
965
stefanf79ade12017-06-02 06:44:03 -0700966void VideoChannel::FillBitrateInfo(BandwidthEstimationInfo* bwe_info) {
967 InvokeOnWorker<void>(RTC_FROM_HERE, Bind(&VideoMediaChannel::FillBitrateInfo,
968 media_channel(), bwe_info));
969}
970
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000971bool VideoChannel::SetLocalContent_w(const MediaContentDescription* content,
Steve Anton3828c062017-12-06 10:34:51 -0800972 SdpType type,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000973 std::string* error_desc) {
Peter Boström9f45a452015-12-08 13:25:57 +0100974 TRACE_EVENT0("webrtc", "VideoChannel::SetLocalContent_w");
Steve Antonb1c1de12017-12-21 15:14:30 -0800975 RTC_DCHECK_RUN_ON(worker_thread());
Mirko Bonadei675513b2017-11-09 11:09:25 +0100976 RTC_LOG(LS_INFO) << "Setting local video description";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000977
Steve Antonb1c1de12017-12-21 15:14:30 -0800978 RTC_DCHECK(content);
979 if (!content) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000980 SafeSetError("Can't find video content in local description.", error_desc);
981 return false;
982 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000983
Steve Antonb1c1de12017-12-21 15:14:30 -0800984 const VideoContentDescription* video = content->as_video();
985
jbauch5869f502017-06-29 12:31:36 -0700986 RtpHeaderExtensions rtp_header_extensions =
987 GetFilteredRtpHeaderExtensions(video->rtp_header_extensions());
Zhi Huang365381f2018-04-13 16:44:34 -0700988 UpdateRtpHeaderExtensionMap(rtp_header_extensions);
Johannes Kron9190b822018-10-29 11:22:05 +0100989 media_channel()->SetExtmapAllowMixed(video->extmap_allow_mixed());
jbauch5869f502017-06-29 12:31:36 -0700990
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700991 VideoRecvParameters recv_params = last_recv_params_;
jbauch5869f502017-06-29 12:31:36 -0700992 RtpParametersFromMediaDescription(video, rtp_header_extensions, &recv_params);
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200993
994 VideoSendParameters send_params = last_send_params_;
995 bool needs_send_params_update = false;
996 if (type == SdpType::kAnswer || type == SdpType::kPrAnswer) {
997 for (auto& send_codec : send_params.codecs) {
998 auto* recv_codec = FindMatchingCodec(recv_params.codecs, send_codec);
999 if (recv_codec) {
1000 if (!recv_codec->packetization && send_codec.packetization) {
1001 send_codec.packetization.reset();
1002 needs_send_params_update = true;
1003 } else if (recv_codec->packetization != send_codec.packetization) {
1004 SafeSetError(
1005 "Failed to set local answer due to invalid codec packetization.",
1006 error_desc);
1007 return false;
1008 }
1009 }
1010 }
1011 }
1012
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001013 if (!media_channel()->SetRecvParameters(recv_params)) {
1014 SafeSetError("Failed to set local video description recv parameters.",
1015 error_desc);
1016 return false;
1017 }
Steve Antonbe2e5f72019-09-06 16:26:02 -07001018
1019 if (webrtc::RtpTransceiverDirectionHasRecv(video->direction())) {
1020 for (const VideoCodec& codec : video->codecs()) {
1021 AddHandledPayloadType(codec.id);
1022 }
1023 // Need to re-register the sink to update the handled payload.
1024 if (!RegisterRtpDemuxerSink()) {
1025 RTC_LOG(LS_ERROR) << "Failed to set up video demuxing.";
1026 return false;
1027 }
Zhi Huang365381f2018-04-13 16:44:34 -07001028 }
1029
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001030 last_recv_params_ = recv_params;
1031
Mirta Dvornicic479a3c02019-06-04 15:38:50 +02001032 if (needs_send_params_update) {
1033 if (!media_channel()->SetSendParameters(send_params)) {
1034 SafeSetError("Failed to set send parameters.", error_desc);
1035 return false;
1036 }
1037 last_send_params_ = send_params;
1038 }
1039
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001040 // TODO(pthatcher): Move local streams into VideoSendParameters, and
1041 // only give it to the media channel once we have a remote
1042 // description too (without a remote description, we won't be able
1043 // to send them anyway).
Steve Anton3828c062017-12-06 10:34:51 -08001044 if (!UpdateLocalStreams_w(video->streams(), type, error_desc)) {
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001045 SafeSetError("Failed to set local video description streams.", error_desc);
1046 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001047 }
1048
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001049 set_local_content_direction(content->direction());
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -07001050 UpdateMediaSendRecvState_w();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001051 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001052}
1053
1054bool VideoChannel::SetRemoteContent_w(const MediaContentDescription* content,
Steve Anton3828c062017-12-06 10:34:51 -08001055 SdpType type,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001056 std::string* error_desc) {
Peter Boström9f45a452015-12-08 13:25:57 +01001057 TRACE_EVENT0("webrtc", "VideoChannel::SetRemoteContent_w");
Steve Antonb1c1de12017-12-21 15:14:30 -08001058 RTC_DCHECK_RUN_ON(worker_thread());
Mirko Bonadei675513b2017-11-09 11:09:25 +01001059 RTC_LOG(LS_INFO) << "Setting remote video description";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001060
Steve Antonb1c1de12017-12-21 15:14:30 -08001061 RTC_DCHECK(content);
1062 if (!content) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001063 SafeSetError("Can't find video content in remote description.", error_desc);
1064 return false;
1065 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001066
Steve Antonb1c1de12017-12-21 15:14:30 -08001067 const VideoContentDescription* video = content->as_video();
1068
jbauch5869f502017-06-29 12:31:36 -07001069 RtpHeaderExtensions rtp_header_extensions =
1070 GetFilteredRtpHeaderExtensions(video->rtp_header_extensions());
1071
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001072 VideoSendParameters send_params = last_send_params_;
jbauch5869f502017-06-29 12:31:36 -07001073 RtpSendParametersFromMediaDescription(video, rtp_header_extensions,
Yves Gerey665174f2018-06-19 15:03:05 +02001074 &send_params);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001075 if (video->conference_mode()) {
nisse4b4dc862016-02-17 05:25:36 -08001076 send_params.conference_mode = true;
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001077 }
Steve Antonbb50ce52018-03-26 10:24:32 -07001078 send_params.mid = content_name();
skvladdc1c62c2016-03-16 19:07:43 -07001079
Mirta Dvornicic479a3c02019-06-04 15:38:50 +02001080 VideoRecvParameters recv_params = last_recv_params_;
1081 bool needs_recv_params_update = false;
1082 if (type == SdpType::kAnswer || type == SdpType::kPrAnswer) {
1083 for (auto& recv_codec : recv_params.codecs) {
1084 auto* send_codec = FindMatchingCodec(send_params.codecs, recv_codec);
1085 if (send_codec) {
1086 if (!send_codec->packetization && recv_codec.packetization) {
1087 recv_codec.packetization.reset();
1088 needs_recv_params_update = true;
1089 } else if (send_codec->packetization != recv_codec.packetization) {
1090 SafeSetError(
1091 "Failed to set remote answer due to invalid codec packetization.",
1092 error_desc);
1093 return false;
1094 }
1095 }
1096 }
1097 }
skvladdc1c62c2016-03-16 19:07:43 -07001098
Mirta Dvornicic479a3c02019-06-04 15:38:50 +02001099 if (!media_channel()->SetSendParameters(send_params)) {
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001100 SafeSetError("Failed to set remote video description send parameters.",
1101 error_desc);
1102 return false;
1103 }
1104 last_send_params_ = send_params;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001105
Mirta Dvornicic479a3c02019-06-04 15:38:50 +02001106 if (needs_recv_params_update) {
1107 if (!media_channel()->SetRecvParameters(recv_params)) {
1108 SafeSetError("Failed to set recv parameters.", error_desc);
1109 return false;
1110 }
1111 last_recv_params_ = recv_params;
1112 }
1113
Steve Antonbe2e5f72019-09-06 16:26:02 -07001114 if (!webrtc::RtpTransceiverDirectionHasSend(content->direction())) {
1115 RTC_DLOG(LS_VERBOSE) << "SetRemoteContent_w: remote side will not send - "
1116 "disable payload type demuxing";
1117 ClearHandledPayloadTypes();
1118 if (!RegisterRtpDemuxerSink()) {
1119 RTC_LOG(LS_ERROR) << "Failed to update video demuxing.";
1120 return false;
1121 }
1122 }
1123
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001124 // TODO(pthatcher): Move remote streams into VideoRecvParameters,
1125 // and only give it to the media channel once we have a local
1126 // description too (without a local description, we won't be able to
1127 // recv them anyway).
Steve Anton3828c062017-12-06 10:34:51 -08001128 if (!UpdateRemoteStreams_w(video->streams(), type, error_desc)) {
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001129 SafeSetError("Failed to set remote video description streams.", error_desc);
1130 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001131 }
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001132 set_remote_content_direction(content->direction());
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -07001133 UpdateMediaSendRecvState_w();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001134 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001135}
1136
deadbeef953c2ce2017-01-09 14:53:41 -08001137RtpDataChannel::RtpDataChannel(rtc::Thread* worker_thread,
1138 rtc::Thread* network_thread,
zhihuangf5b251b2017-01-12 19:37:48 -08001139 rtc::Thread* signaling_thread,
Steve Anton8699a322017-11-06 15:53:33 -08001140 std::unique_ptr<DataMediaChannel> media_channel,
deadbeef953c2ce2017-01-09 14:53:41 -08001141 const std::string& content_name,
Zhi Huange830e682018-03-30 10:48:35 -07001142 bool srtp_required,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001143 webrtc::CryptoOptions crypto_options,
1144 UniqueRandomIdGenerator* ssrc_generator)
Danil Chapovalov33b01f22016-05-11 19:55:27 +02001145 : BaseChannel(worker_thread,
1146 network_thread,
zhihuangf5b251b2017-01-12 19:37:48 -08001147 signaling_thread,
Steve Anton8699a322017-11-06 15:53:33 -08001148 std::move(media_channel),
deadbeefcbecd352015-09-23 11:50:27 -07001149 content_name,
Zhi Huange830e682018-03-30 10:48:35 -07001150 srtp_required,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001151 crypto_options,
1152 ssrc_generator) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001153
deadbeef953c2ce2017-01-09 14:53:41 -08001154RtpDataChannel::~RtpDataChannel() {
1155 TRACE_EVENT0("webrtc", "RtpDataChannel::~RtpDataChannel");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001156 // this can't be done in the base class, since it calls a virtual
1157 DisableMedia_w();
Zhi Huang0ffe03d2018-03-30 13:17:42 -07001158 Deinit();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001159}
1160
Anton Sukhanov4f08faa2019-05-21 11:12:57 -07001161void RtpDataChannel::Init_w(
1162 webrtc::RtpTransportInternal* rtp_transport,
1163 const webrtc::MediaTransportConfig& media_transport_config) {
1164 BaseChannel::Init_w(rtp_transport, media_transport_config);
Zhi Huang2dfc42d2017-12-04 13:38:48 -08001165 media_channel()->SignalDataReceived.connect(this,
1166 &RtpDataChannel::OnDataReceived);
1167 media_channel()->SignalReadyToSend.connect(
1168 this, &RtpDataChannel::OnDataChannelReadyToSend);
1169}
1170
deadbeef953c2ce2017-01-09 14:53:41 -08001171bool RtpDataChannel::SendData(const SendDataParams& params,
1172 const rtc::CopyOnWriteBuffer& payload,
1173 SendDataResult* result) {
stefanf79ade12017-06-02 06:44:03 -07001174 return InvokeOnWorker<bool>(
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -07001175 RTC_FROM_HERE, Bind(&DataMediaChannel::SendData, media_channel(), params,
1176 payload, result));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001177}
1178
deadbeef953c2ce2017-01-09 14:53:41 -08001179bool RtpDataChannel::CheckDataChannelTypeFromContent(
Harald Alvestrand755187f2019-12-05 13:43:34 +01001180 const MediaContentDescription* content,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001181 std::string* error_desc) {
Harald Alvestrand755187f2019-12-05 13:43:34 +01001182 if (!content->as_rtp_data()) {
1183 if (content->as_sctp()) {
1184 SafeSetError("Data channel type mismatch. Expected RTP, got SCTP.",
1185 error_desc);
1186 } else {
1187 SafeSetError("Data channel is not RTP or SCTP.", error_desc);
1188 }
deadbeef953c2ce2017-01-09 14:53:41 -08001189 return false;
1190 }
1191 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001192}
1193
deadbeef953c2ce2017-01-09 14:53:41 -08001194bool RtpDataChannel::SetLocalContent_w(const MediaContentDescription* content,
Steve Anton3828c062017-12-06 10:34:51 -08001195 SdpType type,
deadbeef953c2ce2017-01-09 14:53:41 -08001196 std::string* error_desc) {
1197 TRACE_EVENT0("webrtc", "RtpDataChannel::SetLocalContent_w");
Steve Antonb1c1de12017-12-21 15:14:30 -08001198 RTC_DCHECK_RUN_ON(worker_thread());
Mirko Bonadei675513b2017-11-09 11:09:25 +01001199 RTC_LOG(LS_INFO) << "Setting local data description";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001200
Steve Antonb1c1de12017-12-21 15:14:30 -08001201 RTC_DCHECK(content);
1202 if (!content) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001203 SafeSetError("Can't find data content in local description.", error_desc);
1204 return false;
1205 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001206
Harald Alvestrand755187f2019-12-05 13:43:34 +01001207 if (!CheckDataChannelTypeFromContent(content, error_desc)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001208 return false;
1209 }
Harald Alvestrand755187f2019-12-05 13:43:34 +01001210 const RtpDataContentDescription* data = content->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001211
jbauch5869f502017-06-29 12:31:36 -07001212 RtpHeaderExtensions rtp_header_extensions =
1213 GetFilteredRtpHeaderExtensions(data->rtp_header_extensions());
1214
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001215 DataRecvParameters recv_params = last_recv_params_;
jbauch5869f502017-06-29 12:31:36 -07001216 RtpParametersFromMediaDescription(data, rtp_header_extensions, &recv_params);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001217 if (!media_channel()->SetRecvParameters(recv_params)) {
1218 SafeSetError("Failed to set remote data description recv parameters.",
1219 error_desc);
1220 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001221 }
deadbeef953c2ce2017-01-09 14:53:41 -08001222 for (const DataCodec& codec : data->codecs()) {
zstein3dcf0e92017-06-01 13:22:42 -07001223 AddHandledPayloadType(codec.id);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001224 }
Zhi Huang365381f2018-04-13 16:44:34 -07001225 // Need to re-register the sink to update the handled payload.
1226 if (!RegisterRtpDemuxerSink()) {
1227 RTC_LOG(LS_ERROR) << "Failed to set up data demuxing.";
1228 return false;
1229 }
1230
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001231 last_recv_params_ = recv_params;
1232
1233 // TODO(pthatcher): Move local streams into DataSendParameters, and
1234 // only give it to the media channel once we have a remote
1235 // description too (without a remote description, we won't be able
1236 // to send them anyway).
Steve Anton3828c062017-12-06 10:34:51 -08001237 if (!UpdateLocalStreams_w(data->streams(), type, error_desc)) {
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001238 SafeSetError("Failed to set local data description streams.", error_desc);
1239 return false;
1240 }
1241
1242 set_local_content_direction(content->direction());
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -07001243 UpdateMediaSendRecvState_w();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001244 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001245}
1246
deadbeef953c2ce2017-01-09 14:53:41 -08001247bool RtpDataChannel::SetRemoteContent_w(const MediaContentDescription* content,
Steve Anton3828c062017-12-06 10:34:51 -08001248 SdpType type,
deadbeef953c2ce2017-01-09 14:53:41 -08001249 std::string* error_desc) {
1250 TRACE_EVENT0("webrtc", "RtpDataChannel::SetRemoteContent_w");
Steve Antonb1c1de12017-12-21 15:14:30 -08001251 RTC_DCHECK_RUN_ON(worker_thread());
1252 RTC_LOG(LS_INFO) << "Setting remote data description";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001253
Steve Antonb1c1de12017-12-21 15:14:30 -08001254 RTC_DCHECK(content);
1255 if (!content) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001256 SafeSetError("Can't find data content in remote description.", error_desc);
1257 return false;
1258 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001259
Harald Alvestrand755187f2019-12-05 13:43:34 +01001260 if (!CheckDataChannelTypeFromContent(content, error_desc)) {
1261 return false;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001262 }
Steve Antonb1c1de12017-12-21 15:14:30 -08001263
Harald Alvestrand755187f2019-12-05 13:43:34 +01001264 const RtpDataContentDescription* data = content->as_rtp_data();
1265
Zhi Huang801b8682017-11-15 11:36:43 -08001266 // If the remote data doesn't have codecs, it must be empty, so ignore it.
1267 if (!data->has_codecs()) {
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001268 return true;
1269 }
1270
jbauch5869f502017-06-29 12:31:36 -07001271 RtpHeaderExtensions rtp_header_extensions =
1272 GetFilteredRtpHeaderExtensions(data->rtp_header_extensions());
1273
Mirko Bonadei675513b2017-11-09 11:09:25 +01001274 RTC_LOG(LS_INFO) << "Setting remote data description";
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001275 DataSendParameters send_params = last_send_params_;
jbauch5869f502017-06-29 12:31:36 -07001276 RtpSendParametersFromMediaDescription<DataCodec>(data, rtp_header_extensions,
Yves Gerey665174f2018-06-19 15:03:05 +02001277 &send_params);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001278 if (!media_channel()->SetSendParameters(send_params)) {
1279 SafeSetError("Failed to set remote data description send parameters.",
1280 error_desc);
1281 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001282 }
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001283 last_send_params_ = send_params;
1284
1285 // TODO(pthatcher): Move remote streams into DataRecvParameters,
1286 // and only give it to the media channel once we have a local
1287 // description too (without a local description, we won't be able to
1288 // recv them anyway).
Steve Anton3828c062017-12-06 10:34:51 -08001289 if (!UpdateRemoteStreams_w(data->streams(), type, error_desc)) {
Yves Gerey665174f2018-06-19 15:03:05 +02001290 SafeSetError("Failed to set remote data description streams.", error_desc);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001291 return false;
1292 }
1293
1294 set_remote_content_direction(content->direction());
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -07001295 UpdateMediaSendRecvState_w();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001296 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001297}
1298
deadbeef953c2ce2017-01-09 14:53:41 -08001299void RtpDataChannel::UpdateMediaSendRecvState_w() {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001300 // Render incoming data if we're the active call, and we have the local
1301 // content. We receive data on the default channel and multiplexed streams.
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -07001302 bool recv = IsReadyToReceiveMedia_w();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001303 if (!media_channel()->SetReceive(recv)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001304 RTC_LOG(LS_ERROR) << "Failed to SetReceive on data channel";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001305 }
1306
1307 // Send outgoing data if we're the active call, we have the remote content,
1308 // and we have had some form of connectivity.
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -07001309 bool send = IsReadyToSendMedia_w();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001310 if (!media_channel()->SetSend(send)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001311 RTC_LOG(LS_ERROR) << "Failed to SetSend on data channel";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001312 }
1313
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001314 // Trigger SignalReadyToSendData asynchronously.
1315 OnDataChannelReadyToSend(send);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001316
Mirko Bonadei675513b2017-11-09 11:09:25 +01001317 RTC_LOG(LS_INFO) << "Changing data state, recv=" << recv << " send=" << send;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001318}
1319
deadbeef953c2ce2017-01-09 14:53:41 -08001320void RtpDataChannel::OnMessage(rtc::Message* pmsg) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001321 switch (pmsg->message_id) {
1322 case MSG_READYTOSENDDATA: {
wu@webrtc.orgd64719d2013-08-01 00:00:07 +00001323 DataChannelReadyToSendMessageData* data =
1324 static_cast<DataChannelReadyToSendMessageData*>(pmsg->pdata);
wu@webrtc.org07a6fbe2013-11-04 18:41:34 +00001325 ready_to_send_data_ = data->data();
1326 SignalReadyToSendData(ready_to_send_data_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001327 delete data;
1328 break;
1329 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001330 case MSG_DATARECEIVED: {
1331 DataReceivedMessageData* data =
1332 static_cast<DataReceivedMessageData*>(pmsg->pdata);
deadbeef953c2ce2017-01-09 14:53:41 -08001333 SignalDataReceived(data->params, data->payload);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001334 delete data;
1335 break;
1336 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001337 default:
1338 BaseChannel::OnMessage(pmsg);
1339 break;
1340 }
1341}
1342
deadbeef953c2ce2017-01-09 14:53:41 -08001343void RtpDataChannel::OnDataReceived(const ReceiveDataParams& params,
1344 const char* data,
1345 size_t len) {
Yves Gerey665174f2018-06-19 15:03:05 +02001346 DataReceivedMessageData* msg = new DataReceivedMessageData(params, data, len);
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -07001347 signaling_thread()->Post(RTC_FROM_HERE, this, MSG_DATARECEIVED, msg);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001348}
1349
deadbeef953c2ce2017-01-09 14:53:41 -08001350void RtpDataChannel::OnDataChannelReadyToSend(bool writable) {
wu@webrtc.orgd64719d2013-08-01 00:00:07 +00001351 // This is usded for congestion control to indicate that the stream is ready
1352 // to send by the MediaChannel, as opposed to OnReadyToSend, which indicates
1353 // that the transport channel is ready.
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -07001354 signaling_thread()->Post(RTC_FROM_HERE, this, MSG_READYTOSENDDATA,
wu@webrtc.orgd64719d2013-08-01 00:00:07 +00001355 new DataChannelReadyToSendMessageData(writable));
1356}
1357
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001358} // namespace cricket