blob: 82de7de3812d0694a2b12d93a8da27ec35b70e87 [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
jbauch5869f502017-06-29 12:31:36 -070011#include <iterator>
kwiberg0eb15ed2015-12-17 03:04:15 -080012#include <utility>
13
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020014#include "pc/channel.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000015
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"
Steve Anton10542f22019-01-11 09:11:00 -080019#include "media/base/media_constants.h"
20#include "media/base/rtp_utils.h"
Zhi Huang365381f2018-04-13 16:44:34 -070021#include "modules/rtp_rtcp/source/rtp_packet_received.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "rtc_base/bind.h"
Steve Anton10542f22019-01-11 09:11:00 -080023#include "rtc_base/byte_order.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080025#include "rtc_base/copy_on_write_buffer.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020026#include "rtc_base/dscp.h"
27#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080028#include "rtc_base/network_route.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020029#include "rtc_base/strings/string_builder.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020030#include "rtc_base/trace_event.h"
Steve Anton10542f22019-01-11 09:11:00 -080031#include "p2p/base/packet_transport_internal.h"
32#include "pc/channel_manager.h"
33#include "pc/rtp_media_utils.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000034
35namespace cricket {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000036using rtc::Bind;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080037using rtc::UniqueRandomIdGenerator;
Steve Anton3828c062017-12-06 10:34:51 -080038using webrtc::SdpType;
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +000039
deadbeef2d110be2016-01-13 12:00:26 -080040namespace {
Danil Chapovalov33b01f22016-05-11 19:55:27 +020041
42struct SendPacketMessageData : public rtc::MessageData {
43 rtc::CopyOnWriteBuffer packet;
44 rtc::PacketOptions options;
45};
46
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080047// Finds a stream based on target's Primary SSRC or RIDs.
48// This struct is used in BaseChannel::UpdateLocalStreams_w.
49struct StreamFinder {
50 explicit StreamFinder(const StreamParams* target) : target_(target) {
51 RTC_DCHECK(target);
52 }
53
54 bool operator()(const StreamParams& sp) const {
55 if (target_->has_ssrcs() && sp.has_ssrcs()) {
56 return sp.has_ssrc(target_->first_ssrc());
57 }
58
59 if (!target_->has_rids() && !sp.has_rids()) {
60 return false;
61 }
62
63 const std::vector<RidDescription>& target_rids = target_->rids();
64 const std::vector<RidDescription>& source_rids = sp.rids();
65 if (source_rids.size() != target_rids.size()) {
66 return false;
67 }
68
69 // Check that all RIDs match.
70 return std::equal(source_rids.begin(), source_rids.end(),
71 target_rids.begin(),
72 [](const RidDescription& lhs, const RidDescription& rhs) {
73 return lhs.rid == rhs.rid;
74 });
75 }
76
77 const StreamParams* target_;
78};
79
deadbeef2d110be2016-01-13 12:00:26 -080080} // namespace
81
henrike@webrtc.org28e20752013-07-10 00:45:36 +000082enum {
Steve Anton0807d152018-03-05 11:23:09 -080083 MSG_SEND_RTP_PACKET = 1,
Danil Chapovalov33b01f22016-05-11 19:55:27 +020084 MSG_SEND_RTCP_PACKET,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000085 MSG_READYTOSENDDATA,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000086 MSG_DATARECEIVED,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000087 MSG_FIRSTPACKETRECEIVED,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000088};
89
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +000090static void SafeSetError(const std::string& message, std::string* error_desc) {
91 if (error_desc) {
92 *error_desc = message;
93 }
94}
95
Peter Thatcherc2ee2c82015-08-07 16:05:34 -070096template <class Codec>
97void RtpParametersFromMediaDescription(
98 const MediaContentDescriptionImpl<Codec>* desc,
jbauch5869f502017-06-29 12:31:36 -070099 const RtpHeaderExtensions& extensions,
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700100 RtpParameters<Codec>* params) {
101 // TODO(pthatcher): Remove this once we're sure no one will give us
Zhi Huang801b8682017-11-15 11:36:43 -0800102 // a description without codecs. Currently the ORTC implementation is relying
103 // on this.
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700104 if (desc->has_codecs()) {
105 params->codecs = desc->codecs();
106 }
107 // TODO(pthatcher): See if we really need
108 // rtp_header_extensions_set() and remove it if we don't.
109 if (desc->rtp_header_extensions_set()) {
jbauch5869f502017-06-29 12:31:36 -0700110 params->extensions = extensions;
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700111 }
deadbeef13871492015-12-09 12:37:51 -0800112 params->rtcp.reduced_size = desc->rtcp_reduced_size();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700113}
114
nisse05103312016-03-16 02:22:50 -0700115template <class Codec>
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700116void RtpSendParametersFromMediaDescription(
117 const MediaContentDescriptionImpl<Codec>* desc,
jbauch5869f502017-06-29 12:31:36 -0700118 const RtpHeaderExtensions& extensions,
nisse05103312016-03-16 02:22:50 -0700119 RtpSendParameters<Codec>* send_params) {
jbauch5869f502017-06-29 12:31:36 -0700120 RtpParametersFromMediaDescription(desc, extensions, send_params);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700121 send_params->max_bandwidth_bps = desc->bandwidth();
Johannes Kron9190b822018-10-29 11:22:05 +0100122 send_params->extmap_allow_mixed = desc->extmap_allow_mixed();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700123}
124
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200125BaseChannel::BaseChannel(rtc::Thread* worker_thread,
126 rtc::Thread* network_thread,
zhihuangf5b251b2017-01-12 19:37:48 -0800127 rtc::Thread* signaling_thread,
Steve Anton8699a322017-11-06 15:53:33 -0800128 std::unique_ptr<MediaChannel> media_channel,
deadbeefcbecd352015-09-23 11:50:27 -0700129 const std::string& content_name,
Zhi Huange830e682018-03-30 10:48:35 -0700130 bool srtp_required,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800131 webrtc::CryptoOptions crypto_options,
132 UniqueRandomIdGenerator* ssrc_generator)
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200133 : worker_thread_(worker_thread),
134 network_thread_(network_thread),
zhihuangf5b251b2017-01-12 19:37:48 -0800135 signaling_thread_(signaling_thread),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000136 content_name_(content_name),
deadbeef7af91dd2016-12-13 11:29:11 -0800137 srtp_required_(srtp_required),
Zhi Huange830e682018-03-30 10:48:35 -0700138 crypto_options_(crypto_options),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800139 media_channel_(std::move(media_channel)),
140 ssrc_generator_(ssrc_generator) {
Steve Anton8699a322017-11-06 15:53:33 -0800141 RTC_DCHECK_RUN_ON(worker_thread_);
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800142 RTC_DCHECK(ssrc_generator_);
Zhi Huang365381f2018-04-13 16:44:34 -0700143 demuxer_criteria_.mid = content_name;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100144 RTC_LOG(LS_INFO) << "Created channel for " << content_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000145}
146
147BaseChannel::~BaseChannel() {
Peter Boströmca8b4042016-03-08 14:24:13 -0800148 TRACE_EVENT0("webrtc", "BaseChannel::~BaseChannel");
Steve Anton8699a322017-11-06 15:53:33 -0800149 RTC_DCHECK_RUN_ON(worker_thread_);
Piotr (Peter) Slatala179a3922018-11-16 09:57:58 -0800150
151 if (media_transport_) {
Niels Möllerfe6e50f2019-02-05 17:32:57 +0100152 media_transport_->RemoveNetworkChangeCallback(this);
Piotr (Peter) Slatala179a3922018-11-16 09:57:58 -0800153 }
154
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200155 // Eats any outstanding messages or packets.
156 worker_thread_->Clear(&invoker_);
157 worker_thread_->Clear(this);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000158 // We must destroy the media channel before the transport channel, otherwise
159 // the media channel may try to send on the dead transport channel. NULLing
160 // is not an effective strategy since the sends will come on another thread.
Steve Anton8699a322017-11-06 15:53:33 -0800161 media_channel_.reset();
Mirko Bonadei675513b2017-11-09 11:09:25 +0100162 RTC_LOG(LS_INFO) << "Destroyed channel: " << content_name_;
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200163}
164
Zhi Huang365381f2018-04-13 16:44:34 -0700165bool BaseChannel::ConnectToRtpTransport() {
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800166 RTC_DCHECK(rtp_transport_);
Zhi Huang365381f2018-04-13 16:44:34 -0700167 if (!RegisterRtpDemuxerSink()) {
168 return false;
169 }
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800170 rtp_transport_->SignalReadyToSend.connect(
171 this, &BaseChannel::OnTransportReadyToSend);
Zhi Huang365381f2018-04-13 16:44:34 -0700172 rtp_transport_->SignalRtcpPacketReceived.connect(
173 this, &BaseChannel::OnRtcpPacketReceived);
Piotr (Peter) Slatala179a3922018-11-16 09:57:58 -0800174
175 // If media transport is used, it's responsible for providing network
176 // route changed callbacks.
177 if (!media_transport_) {
178 rtp_transport_->SignalNetworkRouteChanged.connect(
179 this, &BaseChannel::OnNetworkRouteChanged);
180 }
181 // TODO(bugs.webrtc.org/9719): Media transport should also be used to provide
182 // 'writable' state here.
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800183 rtp_transport_->SignalWritableState.connect(this,
184 &BaseChannel::OnWritableState);
185 rtp_transport_->SignalSentPacket.connect(this,
186 &BaseChannel::SignalSentPacket_n);
Zhi Huang365381f2018-04-13 16:44:34 -0700187 return true;
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800188}
Danil Chapovalovdae07ba2016-05-14 01:43:50 +0200189
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800190void BaseChannel::DisconnectFromRtpTransport() {
191 RTC_DCHECK(rtp_transport_);
Zhi Huang365381f2018-04-13 16:44:34 -0700192 rtp_transport_->UnregisterRtpDemuxerSink(this);
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800193 rtp_transport_->SignalReadyToSend.disconnect(this);
Zhi Huang365381f2018-04-13 16:44:34 -0700194 rtp_transport_->SignalRtcpPacketReceived.disconnect(this);
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800195 rtp_transport_->SignalNetworkRouteChanged.disconnect(this);
196 rtp_transport_->SignalWritableState.disconnect(this);
197 rtp_transport_->SignalSentPacket.disconnect(this);
Danil Chapovalovdae07ba2016-05-14 01:43:50 +0200198}
199
Anton Sukhanov98a462c2018-10-17 13:15:42 -0700200void BaseChannel::Init_w(webrtc::RtpTransportInternal* rtp_transport,
201 webrtc::MediaTransportInterface* media_transport) {
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800202 RTC_DCHECK_RUN_ON(worker_thread_);
Piotr (Peter) Slatala179a3922018-11-16 09:57:58 -0800203 media_transport_ = media_transport;
204
Zhi Huang365381f2018-04-13 16:44:34 -0700205 network_thread_->Invoke<void>(
206 RTC_FROM_HERE, [this, rtp_transport] { SetRtpTransport(rtp_transport); });
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800207
208 // Both RTP and RTCP channels should be set, we can call SetInterface on
209 // the media channel and it can set network options.
Anton Sukhanov98a462c2018-10-17 13:15:42 -0700210 media_channel_->SetInterface(this, media_transport);
Piotr (Peter) Slatala179a3922018-11-16 09:57:58 -0800211
212 RTC_LOG(LS_INFO) << "BaseChannel::Init_w, media_transport="
213 << (media_transport_ != nullptr);
214 if (media_transport_) {
Niels Möllerfe6e50f2019-02-05 17:32:57 +0100215 media_transport_->AddNetworkChangeCallback(this);
Piotr (Peter) Slatala179a3922018-11-16 09:57:58 -0800216 }
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200217}
218
wu@webrtc.org78187522013-10-07 23:32:02 +0000219void BaseChannel::Deinit() {
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200220 RTC_DCHECK(worker_thread_->IsCurrent());
Anton Sukhanov98a462c2018-10-17 13:15:42 -0700221 media_channel_->SetInterface(/*iface=*/nullptr,
222 /*media_transport=*/nullptr);
Danil Chapovalovdae07ba2016-05-14 01:43:50 +0200223 // Packets arrive on the network thread, processing packets calls virtual
224 // functions, so need to stop this process in Deinit that is called in
225 // derived classes destructor.
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800226 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
Zhi Huang95e7dbb2018-03-29 00:08:03 +0000227 FlushRtcpMessages_n();
Zhi Huang27f3bf52018-03-26 21:37:23 -0700228
Zhi Huange830e682018-03-30 10:48:35 -0700229 if (rtp_transport_) {
230 DisconnectFromRtpTransport();
Zhi Huang95e7dbb2018-03-29 00:08:03 +0000231 }
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800232 // Clear pending read packets/messages.
233 network_thread_->Clear(&invoker_);
234 network_thread_->Clear(this);
235 });
wu@webrtc.org78187522013-10-07 23:32:02 +0000236}
237
Zhi Huang365381f2018-04-13 16:44:34 -0700238bool BaseChannel::SetRtpTransport(webrtc::RtpTransportInternal* rtp_transport) {
239 if (rtp_transport == rtp_transport_) {
240 return true;
241 }
242
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800243 if (!network_thread_->IsCurrent()) {
Zhi Huang365381f2018-04-13 16:44:34 -0700244 return network_thread_->Invoke<bool>(RTC_FROM_HERE, [this, rtp_transport] {
245 return SetRtpTransport(rtp_transport);
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800246 });
247 }
Zhi Huang95e7dbb2018-03-29 00:08:03 +0000248
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800249 if (rtp_transport_) {
250 DisconnectFromRtpTransport();
251 }
Zhi Huange830e682018-03-30 10:48:35 -0700252
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800253 rtp_transport_ = rtp_transport;
Zhi Huange830e682018-03-30 10:48:35 -0700254 if (rtp_transport_) {
255 RTC_DCHECK(rtp_transport_->rtp_packet_transport());
256 transport_name_ = rtp_transport_->rtp_packet_transport()->transport_name();
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800257
Zhi Huang365381f2018-04-13 16:44:34 -0700258 if (!ConnectToRtpTransport()) {
259 RTC_LOG(LS_ERROR) << "Failed to connect to the new RtpTransport.";
260 return false;
261 }
Zhi Huange830e682018-03-30 10:48:35 -0700262 OnTransportReadyToSend(rtp_transport_->IsReadyToSend());
263 UpdateWritableState_n();
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800264
Zhi Huange830e682018-03-30 10:48:35 -0700265 // Set the cached socket options.
266 for (const auto& pair : socket_options_) {
267 rtp_transport_->rtp_packet_transport()->SetOption(pair.first,
268 pair.second);
269 }
270 if (rtp_transport_->rtcp_packet_transport()) {
271 for (const auto& pair : rtcp_socket_options_) {
272 rtp_transport_->rtp_packet_transport()->SetOption(pair.first,
273 pair.second);
274 }
275 }
guoweis46383312015-12-17 16:45:59 -0800276 }
Zhi Huang365381f2018-04-13 16:44:34 -0700277 return true;
pthatcher@webrtc.org6ad507a2015-03-16 20:19:12 +0000278}
279
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000280bool BaseChannel::Enable(bool enable) {
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700281 worker_thread_->Invoke<void>(
282 RTC_FROM_HERE,
283 Bind(enable ? &BaseChannel::EnableMedia_w : &BaseChannel::DisableMedia_w,
284 this));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000285 return true;
286}
287
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000288bool BaseChannel::SetLocalContent(const MediaContentDescription* content,
Steve Anton3828c062017-12-06 10:34:51 -0800289 SdpType type,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000290 std::string* error_desc) {
Peter Boström9f45a452015-12-08 13:25:57 +0100291 TRACE_EVENT0("webrtc", "BaseChannel::SetLocalContent");
stefanf79ade12017-06-02 06:44:03 -0700292 return InvokeOnWorker<bool>(
293 RTC_FROM_HERE,
Steve Anton3828c062017-12-06 10:34:51 -0800294 Bind(&BaseChannel::SetLocalContent_w, this, content, type, error_desc));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000295}
296
297bool BaseChannel::SetRemoteContent(const MediaContentDescription* content,
Steve Anton3828c062017-12-06 10:34:51 -0800298 SdpType type,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000299 std::string* error_desc) {
Peter Boström9f45a452015-12-08 13:25:57 +0100300 TRACE_EVENT0("webrtc", "BaseChannel::SetRemoteContent");
stefanf79ade12017-06-02 06:44:03 -0700301 return InvokeOnWorker<bool>(
Steve Anton3828c062017-12-06 10:34:51 -0800302 RTC_FROM_HERE,
303 Bind(&BaseChannel::SetRemoteContent_w, this, content, type, error_desc));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000304}
305
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700306bool BaseChannel::IsReadyToReceiveMedia_w() const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000307 // Receive data if we are enabled and have local content,
Steve Anton4e70a722017-11-28 14:57:10 -0800308 return enabled() &&
309 webrtc::RtpTransceiverDirectionHasRecv(local_content_direction_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000310}
311
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700312bool BaseChannel::IsReadyToSendMedia_w() const {
313 // Need to access some state updated on the network thread.
314 return network_thread_->Invoke<bool>(
315 RTC_FROM_HERE, Bind(&BaseChannel::IsReadyToSendMedia_n, this));
316}
317
318bool BaseChannel::IsReadyToSendMedia_n() const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000319 // Send outgoing data if we are enabled, have local and remote content,
320 // and we have had some form of connectivity.
Steve Anton4e70a722017-11-28 14:57:10 -0800321 return enabled() &&
322 webrtc::RtpTransceiverDirectionHasRecv(remote_content_direction_) &&
323 webrtc::RtpTransceiverDirectionHasSend(local_content_direction_) &&
Zhi Huang365381f2018-04-13 16:44:34 -0700324 was_ever_writable();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000325}
326
jbaucheec21bd2016-03-20 06:15:43 -0700327bool BaseChannel::SendPacket(rtc::CopyOnWriteBuffer* packet,
stefanc1aeaf02015-10-15 07:26:07 -0700328 const rtc::PacketOptions& options) {
329 return SendPacket(false, packet, options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000330}
331
jbaucheec21bd2016-03-20 06:15:43 -0700332bool BaseChannel::SendRtcp(rtc::CopyOnWriteBuffer* packet,
stefanc1aeaf02015-10-15 07:26:07 -0700333 const rtc::PacketOptions& options) {
334 return SendPacket(true, packet, options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000335}
336
Yves Gerey665174f2018-06-19 15:03:05 +0200337int BaseChannel::SetOption(SocketType type,
338 rtc::Socket::Option opt,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000339 int value) {
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200340 return network_thread_->Invoke<int>(
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700341 RTC_FROM_HERE, Bind(&BaseChannel::SetOption_n, this, type, opt, value));
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200342}
343
344int BaseChannel::SetOption_n(SocketType type,
345 rtc::Socket::Option opt,
346 int value) {
347 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange830e682018-03-30 10:48:35 -0700348 RTC_DCHECK(rtp_transport_);
deadbeef5bd5ca32017-02-10 11:31:50 -0800349 rtc::PacketTransportInternal* transport = nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000350 switch (type) {
wu@webrtc.org9caf2762013-12-11 18:25:07 +0000351 case ST_RTP:
zsteine8ab5432017-07-12 11:48:11 -0700352 transport = rtp_transport_->rtp_packet_transport();
deadbeefcbecd352015-09-23 11:50:27 -0700353 socket_options_.push_back(
354 std::pair<rtc::Socket::Option, int>(opt, value));
wu@webrtc.org9caf2762013-12-11 18:25:07 +0000355 break;
356 case ST_RTCP:
zsteine8ab5432017-07-12 11:48:11 -0700357 transport = rtp_transport_->rtcp_packet_transport();
deadbeefcbecd352015-09-23 11:50:27 -0700358 rtcp_socket_options_.push_back(
359 std::pair<rtc::Socket::Option, int>(opt, value));
wu@webrtc.org9caf2762013-12-11 18:25:07 +0000360 break;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000361 }
deadbeeff5346592017-01-24 21:51:21 -0800362 return transport ? transport->SetOption(opt, value) : -1;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000363}
364
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800365void BaseChannel::OnWritableState(bool writable) {
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200366 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800367 if (writable) {
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800368 ChannelWritable_n();
369 } else {
370 ChannelNotWritable_n();
Guo-wei Shieh1218d7a2015-12-05 09:59:56 -0800371 }
372}
373
Zhi Huang942bc2e2017-11-13 13:26:07 -0800374void BaseChannel::OnNetworkRouteChanged(
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200375 absl::optional<rtc::NetworkRoute> network_route) {
Piotr (Peter) Slatala179a3922018-11-16 09:57:58 -0800376 RTC_LOG(LS_INFO) << "Network route was changed.";
377
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200378 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huang942bc2e2017-11-13 13:26:07 -0800379 rtc::NetworkRoute new_route;
380 if (network_route) {
Zhi Huang942bc2e2017-11-13 13:26:07 -0800381 new_route = *(network_route);
Zhi Huang8c316c12017-11-13 21:13:45 +0000382 }
Zhi Huang942bc2e2017-11-13 13:26:07 -0800383 // Note: When the RTCP-muxing is not enabled, RTCP transport and RTP transport
384 // use the same transport name and MediaChannel::OnNetworkRouteChanged cannot
385 // work correctly. Intentionally leave it broken to simplify the code and
386 // encourage the users to stop using non-muxing RTCP.
Steve Anton8699a322017-11-06 15:53:33 -0800387 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, worker_thread_, [=] {
Zhi Huang942bc2e2017-11-13 13:26:07 -0800388 media_channel_->OnNetworkRouteChanged(transport_name_, new_route);
Steve Anton8699a322017-11-06 15:53:33 -0800389 });
Honghai Zhangcc411c02016-03-29 17:27:21 -0700390}
391
zstein56162b92017-04-24 16:54:35 -0700392void BaseChannel::OnTransportReadyToSend(bool ready) {
Steve Anton8699a322017-11-06 15:53:33 -0800393 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, worker_thread_,
394 [=] { media_channel_->OnReadyToSend(ready); });
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000395}
396
stefanc1aeaf02015-10-15 07:26:07 -0700397bool BaseChannel::SendPacket(bool rtcp,
jbaucheec21bd2016-03-20 06:15:43 -0700398 rtc::CopyOnWriteBuffer* packet,
stefanc1aeaf02015-10-15 07:26:07 -0700399 const rtc::PacketOptions& options) {
Amit Hilbuchedd20542019-03-18 12:33:43 -0700400 // Until all the code is migrated to use RtpPacketType instead of bool.
401 RtpPacketType packet_type = rtcp ? RtpPacketType::kRtcp : RtpPacketType::kRtp;
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200402 // SendPacket gets called from MediaEngine, on a pacer or an encoder thread.
403 // If the thread is not our network thread, we will post to our network
404 // so that the real work happens on our network. This avoids us having to
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000405 // synchronize access to all the pieces of the send path, including
406 // SRTP and the inner workings of the transport channels.
407 // The only downside is that we can't return a proper failure code if
408 // needed. Since UDP is unreliable anyway, this should be a non-issue.
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200409 if (!network_thread_->IsCurrent()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000410 // Avoid a copy by transferring the ownership of the packet data.
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200411 int message_id = rtcp ? MSG_SEND_RTCP_PACKET : MSG_SEND_RTP_PACKET;
412 SendPacketMessageData* data = new SendPacketMessageData;
kwiberg0eb15ed2015-12-17 03:04:15 -0800413 data->packet = std::move(*packet);
stefanc1aeaf02015-10-15 07:26:07 -0700414 data->options = options;
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700415 network_thread_->Post(RTC_FROM_HERE, this, message_id, data);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000416 return true;
417 }
Zhi Huange830e682018-03-30 10:48:35 -0700418
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200419 TRACE_EVENT0("webrtc", "BaseChannel::SendPacket");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000420
421 // Now that we are on the correct thread, ensure we have a place to send this
422 // packet before doing anything. (We might get RTCP packets that we don't
423 // intend to send.) If we've negotiated RTCP mux, send RTCP over the RTP
424 // transport.
Zhi Huange830e682018-03-30 10:48:35 -0700425 if (!rtp_transport_ || !rtp_transport_->IsWritable(rtcp)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000426 return false;
427 }
428
429 // Protect ourselves against crazy data.
Amit Hilbuchedd20542019-03-18 12:33:43 -0700430 if (!IsValidRtpPacketSize(packet_type, packet->size())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100431 RTC_LOG(LS_ERROR) << "Dropping outgoing " << content_name_ << " "
Amit Hilbuchedd20542019-03-18 12:33:43 -0700432 << RtpPacketTypeToString(packet_type)
Mirko Bonadei675513b2017-11-09 11:09:25 +0100433 << " packet: wrong size=" << packet->size();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000434 return false;
435 }
436
Zhi Huangcf990f52017-09-22 12:12:30 -0700437 if (!srtp_active()) {
438 if (srtp_required_) {
439 // The audio/video engines may attempt to send RTCP packets as soon as the
440 // streams are created, so don't treat this as an error for RTCP.
441 // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=6809
442 if (rtcp) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000443 return false;
444 }
Zhi Huangcf990f52017-09-22 12:12:30 -0700445 // However, there shouldn't be any RTP packets sent before SRTP is set up
446 // (and SetSend(true) is called).
Mirko Bonadei675513b2017-11-09 11:09:25 +0100447 RTC_LOG(LS_ERROR)
448 << "Can't send outgoing RTP packet when SRTP is inactive"
449 << " and crypto is required";
Zhi Huangcf990f52017-09-22 12:12:30 -0700450 RTC_NOTREACHED();
deadbeef8f425f92016-12-01 12:26:27 -0800451 return false;
452 }
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800453
454 std::string packet_type = rtcp ? "RTCP" : "RTP";
455 RTC_LOG(LS_WARNING) << "Sending an " << packet_type
456 << " packet without encryption.";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000457 }
Zhi Huange830e682018-03-30 10:48:35 -0700458
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000459 // Bon voyage.
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800460 return rtcp ? rtp_transport_->SendRtcpPacket(packet, options, PF_SRTP_BYPASS)
461 : rtp_transport_->SendRtpPacket(packet, options, PF_SRTP_BYPASS);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000462}
463
Zhi Huang365381f2018-04-13 16:44:34 -0700464void BaseChannel::OnRtpPacket(const webrtc::RtpPacketReceived& parsed_packet) {
Niels Möller29e13fd2018-12-17 12:35:30 +0100465 // Take packet time from the |parsed_packet|.
466 // RtpPacketReceived.arrival_time_ms = (timestamp_us + 500) / 1000;
Niels Möllere6933812018-11-05 13:01:41 +0100467 int64_t timestamp_us = -1;
Zhi Huang365381f2018-04-13 16:44:34 -0700468 if (parsed_packet.arrival_time_ms() > 0) {
Niels Möllere6933812018-11-05 13:01:41 +0100469 timestamp_us = parsed_packet.arrival_time_ms() * 1000;
Zhi Huang365381f2018-04-13 16:44:34 -0700470 }
Zhi Huang365381f2018-04-13 16:44:34 -0700471
Niels Möllere6933812018-11-05 13:01:41 +0100472 OnPacketReceived(/*rtcp=*/false, parsed_packet.Buffer(), timestamp_us);
Zhi Huang365381f2018-04-13 16:44:34 -0700473}
474
475void BaseChannel::UpdateRtpHeaderExtensionMap(
476 const RtpHeaderExtensions& header_extensions) {
477 RTC_DCHECK(rtp_transport_);
478 // Update the header extension map on network thread in case there is data
479 // race.
480 // TODO(zhihuang): Add an rtc::ThreadChecker make sure to RtpTransport won't
481 // be accessed from different threads.
482 //
483 // NOTE: This doesn't take the BUNDLE case in account meaning the RTP header
484 // extension maps are not merged when BUNDLE is enabled. This is fine because
485 // the ID for MID should be consistent among all the RTP transports.
486 network_thread_->Invoke<void>(RTC_FROM_HERE, [this, &header_extensions] {
487 rtp_transport_->UpdateRtpHeaderExtensionMap(header_extensions);
488 });
489}
490
491bool BaseChannel::RegisterRtpDemuxerSink() {
492 RTC_DCHECK(rtp_transport_);
493 return network_thread_->Invoke<bool>(RTC_FROM_HERE, [this] {
494 return rtp_transport_->RegisterRtpDemuxerSink(demuxer_criteria_, this);
495 });
496}
497
498void BaseChannel::OnRtcpPacketReceived(rtc::CopyOnWriteBuffer* packet,
Niels Möllere6933812018-11-05 13:01:41 +0100499 int64_t packet_time_us) {
500 OnPacketReceived(/*rtcp=*/true, *packet, packet_time_us);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000501}
502
zstein3dcf0e92017-06-01 13:22:42 -0700503void BaseChannel::OnPacketReceived(bool rtcp,
Zhi Huang365381f2018-04-13 16:44:34 -0700504 const rtc::CopyOnWriteBuffer& packet,
Niels Möllere6933812018-11-05 13:01:41 +0100505 int64_t packet_time_us) {
honghaiz@google.coma67ca1a2015-01-28 19:48:33 +0000506 if (!has_received_packet_ && !rtcp) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000507 has_received_packet_ = true;
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700508 signaling_thread()->Post(RTC_FROM_HERE, this, MSG_FIRSTPACKETRECEIVED);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000509 }
510
Zhi Huangcf990f52017-09-22 12:12:30 -0700511 if (!srtp_active() && srtp_required_) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000512 // Our session description indicates that SRTP is required, but we got a
513 // packet before our SRTP filter is active. This means either that
514 // a) we got SRTP packets before we received the SDES keys, in which case
515 // we can't decrypt it anyway, or
516 // b) we got SRTP packets before DTLS completed on both the RTP and RTCP
zhihuangb2cdd932017-01-19 16:54:25 -0800517 // transports, so we haven't yet extracted keys, even if DTLS did
518 // complete on the transport that the packets are being sent on. It's
519 // really good practice to wait for both RTP and RTCP to be good to go
520 // before sending media, to prevent weird failure modes, so it's fine
521 // for us to just eat packets here. This is all sidestepped if RTCP mux
522 // is used anyway.
Mirko Bonadei675513b2017-11-09 11:09:25 +0100523 RTC_LOG(LS_WARNING)
Amit Hilbuchedd20542019-03-18 12:33:43 -0700524 << "Can't process incoming "
525 << RtpPacketTypeToString(rtcp ? RtpPacketType::kRtcp
526 : RtpPacketType::kRtp)
Mirko Bonadei675513b2017-11-09 11:09:25 +0100527 << " packet when SRTP is inactive and crypto is required";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000528 return;
529 }
530
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200531 invoker_.AsyncInvoke<void>(
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700532 RTC_FROM_HERE, worker_thread_,
Niels Möllere6933812018-11-05 13:01:41 +0100533 Bind(&BaseChannel::ProcessPacket, this, rtcp, packet, packet_time_us));
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200534}
535
zstein3dcf0e92017-06-01 13:22:42 -0700536void BaseChannel::ProcessPacket(bool rtcp,
537 const rtc::CopyOnWriteBuffer& packet,
Niels Möllere6933812018-11-05 13:01:41 +0100538 int64_t packet_time_us) {
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200539 RTC_DCHECK(worker_thread_->IsCurrent());
zstein3dcf0e92017-06-01 13:22:42 -0700540
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200541 if (rtcp) {
Amit Hilbuche7a5f7b2019-03-12 11:10:27 -0700542 media_channel_->OnRtcpReceived(packet, packet_time_us);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000543 } else {
Amit Hilbuche7a5f7b2019-03-12 11:10:27 -0700544 media_channel_->OnPacketReceived(packet, packet_time_us);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000545 }
546}
547
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000548void BaseChannel::EnableMedia_w() {
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700549 RTC_DCHECK(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000550 if (enabled_)
551 return;
552
Mirko Bonadei675513b2017-11-09 11:09:25 +0100553 RTC_LOG(LS_INFO) << "Channel enabled";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000554 enabled_ = true;
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700555 UpdateMediaSendRecvState_w();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000556}
557
558void BaseChannel::DisableMedia_w() {
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700559 RTC_DCHECK(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000560 if (!enabled_)
561 return;
562
Mirko Bonadei675513b2017-11-09 11:09:25 +0100563 RTC_LOG(LS_INFO) << "Channel disabled";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000564 enabled_ = false;
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700565 UpdateMediaSendRecvState_w();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000566}
567
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200568void BaseChannel::UpdateWritableState_n() {
Zhi Huange830e682018-03-30 10:48:35 -0700569 if (rtp_transport_->IsWritable(/*rtcp=*/true) &&
570 rtp_transport_->IsWritable(/*rtcp=*/false)) {
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200571 ChannelWritable_n();
deadbeefcbecd352015-09-23 11:50:27 -0700572 } else {
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200573 ChannelNotWritable_n();
deadbeefcbecd352015-09-23 11:50:27 -0700574 }
575}
576
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200577void BaseChannel::ChannelWritable_n() {
578 RTC_DCHECK(network_thread_->IsCurrent());
Guo-wei Shieh1218d7a2015-12-05 09:59:56 -0800579 if (writable_) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000580 return;
Guo-wei Shieh1218d7a2015-12-05 09:59:56 -0800581 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000582
Mirko Bonadei675513b2017-11-09 11:09:25 +0100583 RTC_LOG(LS_INFO) << "Channel writable (" << content_name_ << ")"
584 << (was_ever_writable_ ? "" : " for the first time");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000585
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000586 was_ever_writable_ = true;
587 writable_ = true;
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700588 UpdateMediaSendRecvState();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000589}
590
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200591void BaseChannel::ChannelNotWritable_n() {
592 RTC_DCHECK(network_thread_->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000593 if (!writable_)
594 return;
595
Mirko Bonadei675513b2017-11-09 11:09:25 +0100596 RTC_LOG(LS_INFO) << "Channel not writable (" << content_name_ << ")";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000597 writable_ = false;
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700598 UpdateMediaSendRecvState();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000599}
600
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000601bool BaseChannel::AddRecvStream_w(const StreamParams& sp) {
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700602 RTC_DCHECK(worker_thread() == rtc::Thread::Current());
pbos482b12e2015-11-16 10:19:58 -0800603 return media_channel()->AddRecvStream(sp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000604}
605
Peter Boström0c4e06b2015-10-07 12:23:21 +0200606bool BaseChannel::RemoveRecvStream_w(uint32_t ssrc) {
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700607 RTC_DCHECK(worker_thread() == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000608 return media_channel()->RemoveRecvStream(ssrc);
609}
610
611bool BaseChannel::UpdateLocalStreams_w(const std::vector<StreamParams>& streams,
Steve Anton3828c062017-12-06 10:34:51 -0800612 SdpType type,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000613 std::string* error_desc) {
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800614 // In the case of RIDs (where SSRCs are not negotiated), this method will
615 // generate an SSRC for each layer in StreamParams. That representation will
616 // be stored internally in |local_streams_|.
617 // In subsequent offers, the same stream can appear in |streams| again
618 // (without the SSRCs), so it should be looked up using RIDs (if available)
619 // and then by primary SSRC.
620 // In both scenarios, it is safe to assume that the media channel will be
621 // created with a StreamParams object with SSRCs. However, it is not safe to
622 // assume that |local_streams_| will always have SSRCs as there are scenarios
623 // in which niether SSRCs or RIDs are negotiated.
624
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000625 // Check for streams that have been removed.
626 bool ret = true;
Steve Anton5f8b5fd2018-12-27 16:58:10 -0800627 for (const StreamParams& old_stream : local_streams_) {
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800628 if (!old_stream.has_ssrcs() ||
629 GetStream(streams, StreamFinder(&old_stream))) {
630 continue;
631 }
632 if (!media_channel()->RemoveSendStream(old_stream.first_ssrc())) {
633 rtc::StringBuilder desc;
634 desc << "Failed to remove send stream with ssrc "
635 << old_stream.first_ssrc() << ".";
636 SafeSetError(desc.str(), error_desc);
637 ret = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000638 }
639 }
640 // Check for new streams.
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800641 std::vector<StreamParams> all_streams;
642 for (const StreamParams& stream : streams) {
643 StreamParams* existing = GetStream(local_streams_, StreamFinder(&stream));
644 if (existing) {
645 // Parameters cannot change for an existing stream.
646 all_streams.push_back(*existing);
647 continue;
648 }
649
650 all_streams.push_back(stream);
651 StreamParams& new_stream = all_streams.back();
652
653 if (!new_stream.has_ssrcs() && !new_stream.has_rids()) {
654 continue;
655 }
656
657 RTC_DCHECK(new_stream.has_ssrcs() || new_stream.has_rids());
658 if (new_stream.has_ssrcs() && new_stream.has_rids()) {
659 rtc::StringBuilder desc;
660 desc << "Failed to add send stream: " << new_stream.first_ssrc()
661 << ". Stream has both SSRCs and RIDs.";
662 SafeSetError(desc.str(), error_desc);
663 ret = false;
664 continue;
665 }
666
667 // At this point we use the legacy simulcast group in StreamParams to
668 // indicate that we want multiple layers to the media channel.
669 if (!new_stream.has_ssrcs()) {
670 // TODO(bugs.webrtc.org/10250): Indicate if flex is desired here.
671 new_stream.GenerateSsrcs(new_stream.rids().size(), /* rtx = */ true,
672 /* flex_fec = */ false, ssrc_generator_);
673 }
674
675 if (media_channel()->AddSendStream(new_stream)) {
676 RTC_LOG(LS_INFO) << "Add send stream ssrc: " << new_stream.ssrcs[0];
677 } else {
678 rtc::StringBuilder desc;
679 desc << "Failed to add send stream ssrc: " << new_stream.first_ssrc();
680 SafeSetError(desc.str(), error_desc);
681 ret = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000682 }
683 }
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800684 local_streams_ = all_streams;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000685 return ret;
686}
687
688bool BaseChannel::UpdateRemoteStreams_w(
689 const std::vector<StreamParams>& streams,
Steve Anton3828c062017-12-06 10:34:51 -0800690 SdpType type,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000691 std::string* error_desc) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000692 // Check for streams that have been removed.
693 bool ret = true;
Steve Anton5f8b5fd2018-12-27 16:58:10 -0800694 for (const StreamParams& old_stream : remote_streams_) {
Seth Hampson5897a6e2018-04-03 11:16:33 -0700695 // If we no longer have an unsignaled stream, we would like to remove
696 // the unsignaled stream params that are cached.
Steve Anton5f8b5fd2018-12-27 16:58:10 -0800697 if ((!old_stream.has_ssrcs() && !HasStreamWithNoSsrcs(streams)) ||
698 !GetStreamBySsrc(streams, old_stream.first_ssrc())) {
699 if (RemoveRecvStream_w(old_stream.first_ssrc())) {
700 RTC_LOG(LS_INFO) << "Remove remote ssrc: " << old_stream.first_ssrc();
Zhi Huang365381f2018-04-13 16:44:34 -0700701 } else {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200702 rtc::StringBuilder desc;
Steve Anton5f8b5fd2018-12-27 16:58:10 -0800703 desc << "Failed to remove remote stream with ssrc "
704 << old_stream.first_ssrc() << ".";
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000705 SafeSetError(desc.str(), error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000706 ret = false;
707 }
708 }
709 }
Zhi Huang365381f2018-04-13 16:44:34 -0700710 demuxer_criteria_.ssrcs.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000711 // Check for new streams.
Steve Anton5f8b5fd2018-12-27 16:58:10 -0800712 for (const StreamParams& new_stream : streams) {
Seth Hampson5897a6e2018-04-03 11:16:33 -0700713 // We allow a StreamParams with an empty list of SSRCs, in which case the
714 // MediaChannel will cache the parameters and use them for any unsignaled
715 // stream received later.
Steve Anton5f8b5fd2018-12-27 16:58:10 -0800716 if ((!new_stream.has_ssrcs() && !HasStreamWithNoSsrcs(remote_streams_)) ||
717 !GetStreamBySsrc(remote_streams_, new_stream.first_ssrc())) {
718 if (AddRecvStream_w(new_stream)) {
719 RTC_LOG(LS_INFO) << "Add remote ssrc: " << new_stream.first_ssrc();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000720 } else {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200721 rtc::StringBuilder desc;
Steve Anton5f8b5fd2018-12-27 16:58:10 -0800722 desc << "Failed to add remote stream ssrc: " << new_stream.first_ssrc();
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000723 SafeSetError(desc.str(), error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000724 ret = false;
725 }
726 }
Zhi Huang365381f2018-04-13 16:44:34 -0700727 // Update the receiving SSRCs.
Steve Anton5f8b5fd2018-12-27 16:58:10 -0800728 demuxer_criteria_.ssrcs.insert(new_stream.ssrcs.begin(),
729 new_stream.ssrcs.end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000730 }
Zhi Huang365381f2018-04-13 16:44:34 -0700731 // Re-register the sink to update the receiving ssrcs.
732 RegisterRtpDemuxerSink();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000733 remote_streams_ = streams;
734 return ret;
735}
736
jbauch5869f502017-06-29 12:31:36 -0700737RtpHeaderExtensions BaseChannel::GetFilteredRtpHeaderExtensions(
738 const RtpHeaderExtensions& extensions) {
Zhi Huange830e682018-03-30 10:48:35 -0700739 RTC_DCHECK(rtp_transport_);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700740 if (crypto_options_.srtp.enable_encrypted_rtp_header_extensions) {
jbauch5869f502017-06-29 12:31:36 -0700741 RtpHeaderExtensions filtered;
Steve Anton64b626b2019-01-28 17:25:26 -0800742 absl::c_copy_if(extensions, std::back_inserter(filtered),
743 [](const webrtc::RtpExtension& extension) {
744 return !extension.encrypt;
745 });
jbauch5869f502017-06-29 12:31:36 -0700746 return filtered;
747 }
748
749 return webrtc::RtpExtension::FilterDuplicateNonEncrypted(extensions);
750}
751
Yves Gerey665174f2018-06-19 15:03:05 +0200752void BaseChannel::OnMessage(rtc::Message* pmsg) {
Peter Boström6f28cf02015-12-07 23:17:15 +0100753 TRACE_EVENT0("webrtc", "BaseChannel::OnMessage");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000754 switch (pmsg->message_id) {
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200755 case MSG_SEND_RTP_PACKET:
756 case MSG_SEND_RTCP_PACKET: {
757 RTC_DCHECK(network_thread_->IsCurrent());
758 SendPacketMessageData* data =
759 static_cast<SendPacketMessageData*>(pmsg->pdata);
760 bool rtcp = pmsg->message_id == MSG_SEND_RTCP_PACKET;
761 SendPacket(rtcp, &data->packet, data->options);
762 delete data;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000763 break;
764 }
765 case MSG_FIRSTPACKETRECEIVED: {
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800766 SignalFirstPacketReceived_(this);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000767 break;
768 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000769 }
770}
771
zstein3dcf0e92017-06-01 13:22:42 -0700772void BaseChannel::AddHandledPayloadType(int payload_type) {
Zhi Huang365381f2018-04-13 16:44:34 -0700773 demuxer_criteria_.payload_types.insert(static_cast<uint8_t>(payload_type));
zstein3dcf0e92017-06-01 13:22:42 -0700774}
775
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200776void BaseChannel::FlushRtcpMessages_n() {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000777 // Flush all remaining RTCP messages. This should only be called in
778 // destructor.
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200779 RTC_DCHECK(network_thread_->IsCurrent());
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000780 rtc::MessageList rtcp_messages;
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200781 network_thread_->Clear(this, MSG_SEND_RTCP_PACKET, &rtcp_messages);
782 for (const auto& message : rtcp_messages) {
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700783 network_thread_->Send(RTC_FROM_HERE, this, MSG_SEND_RTCP_PACKET,
784 message.pdata);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000785 }
786}
787
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800788void BaseChannel::SignalSentPacket_n(const rtc::SentPacket& sent_packet) {
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200789 RTC_DCHECK(network_thread_->IsCurrent());
790 invoker_.AsyncInvoke<void>(
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700791 RTC_FROM_HERE, worker_thread_,
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200792 rtc::Bind(&BaseChannel::SignalSentPacket_w, this, sent_packet));
793}
794
795void BaseChannel::SignalSentPacket_w(const rtc::SentPacket& sent_packet) {
796 RTC_DCHECK(worker_thread_->IsCurrent());
797 SignalSentPacket(sent_packet);
798}
799
800VoiceChannel::VoiceChannel(rtc::Thread* worker_thread,
801 rtc::Thread* network_thread,
zhihuangf5b251b2017-01-12 19:37:48 -0800802 rtc::Thread* signaling_thread,
Steve Anton8699a322017-11-06 15:53:33 -0800803 std::unique_ptr<VoiceMediaChannel> media_channel,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000804 const std::string& content_name,
Zhi Huange830e682018-03-30 10:48:35 -0700805 bool srtp_required,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800806 webrtc::CryptoOptions crypto_options,
807 UniqueRandomIdGenerator* ssrc_generator)
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200808 : BaseChannel(worker_thread,
809 network_thread,
zhihuangf5b251b2017-01-12 19:37:48 -0800810 signaling_thread,
Steve Anton8699a322017-11-06 15:53:33 -0800811 std::move(media_channel),
deadbeefcbecd352015-09-23 11:50:27 -0700812 content_name,
Zhi Huange830e682018-03-30 10:48:35 -0700813 srtp_required,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800814 crypto_options,
815 ssrc_generator) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000816
817VoiceChannel::~VoiceChannel() {
Piotr (Peter) Slatala309aafe2019-01-15 14:24:34 -0800818 if (media_transport()) {
819 media_transport()->SetFirstAudioPacketReceivedObserver(nullptr);
820 }
Peter Boströmca8b4042016-03-08 14:24:13 -0800821 TRACE_EVENT0("webrtc", "VoiceChannel::~VoiceChannel");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000822 // this can't be done in the base class, since it calls a virtual
823 DisableMedia_w();
Zhi Huang0ffe03d2018-03-30 13:17:42 -0700824 Deinit();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000825}
826
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700827void BaseChannel::UpdateMediaSendRecvState() {
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200828 RTC_DCHECK(network_thread_->IsCurrent());
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700829 invoker_.AsyncInvoke<void>(
830 RTC_FROM_HERE, worker_thread_,
831 Bind(&BaseChannel::UpdateMediaSendRecvState_w, this));
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200832}
833
Piotr (Peter) Slatala179a3922018-11-16 09:57:58 -0800834void BaseChannel::OnNetworkRouteChanged(
835 const rtc::NetworkRoute& network_route) {
836 OnNetworkRouteChanged(absl::make_optional(network_route));
837}
838
Piotr (Peter) Slatala309aafe2019-01-15 14:24:34 -0800839void VoiceChannel::Init_w(webrtc::RtpTransportInternal* rtp_transport,
840 webrtc::MediaTransportInterface* media_transport) {
841 BaseChannel::Init_w(rtp_transport, media_transport);
842 if (BaseChannel::media_transport()) {
843 this->media_transport()->SetFirstAudioPacketReceivedObserver(this);
844 }
845}
846
847void VoiceChannel::OnFirstAudioPacketReceived(int64_t channel_id) {
848 has_received_packet_ = true;
849 signaling_thread()->Post(RTC_FROM_HERE, this, MSG_FIRSTPACKETRECEIVED);
850}
851
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700852void VoiceChannel::UpdateMediaSendRecvState_w() {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000853 // Render incoming data if we're the active call, and we have the local
854 // content. We receive data on the default channel and multiplexed streams.
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700855 bool recv = IsReadyToReceiveMedia_w();
solenberg5b14b422015-10-01 04:10:31 -0700856 media_channel()->SetPlayout(recv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000857
858 // Send outgoing data if we're the active call, we have the remote content,
859 // and we have had some form of connectivity.
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700860 bool send = IsReadyToSendMedia_w();
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800861 media_channel()->SetSend(send);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000862
Mirko Bonadei675513b2017-11-09 11:09:25 +0100863 RTC_LOG(LS_INFO) << "Changing voice state, recv=" << recv << " send=" << send;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000864}
865
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000866bool VoiceChannel::SetLocalContent_w(const MediaContentDescription* content,
Steve Anton3828c062017-12-06 10:34:51 -0800867 SdpType type,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000868 std::string* error_desc) {
Peter Boström9f45a452015-12-08 13:25:57 +0100869 TRACE_EVENT0("webrtc", "VoiceChannel::SetLocalContent_w");
Steve Antonb1c1de12017-12-21 15:14:30 -0800870 RTC_DCHECK_RUN_ON(worker_thread());
Mirko Bonadei675513b2017-11-09 11:09:25 +0100871 RTC_LOG(LS_INFO) << "Setting local voice description";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000872
Steve Antonb1c1de12017-12-21 15:14:30 -0800873 RTC_DCHECK(content);
874 if (!content) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000875 SafeSetError("Can't find audio content in local description.", error_desc);
876 return false;
877 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000878
Steve Antonb1c1de12017-12-21 15:14:30 -0800879 const AudioContentDescription* audio = content->as_audio();
880
jbauch5869f502017-06-29 12:31:36 -0700881 RtpHeaderExtensions rtp_header_extensions =
882 GetFilteredRtpHeaderExtensions(audio->rtp_header_extensions());
Zhi Huang365381f2018-04-13 16:44:34 -0700883 UpdateRtpHeaderExtensionMap(rtp_header_extensions);
Johannes Kron9190b822018-10-29 11:22:05 +0100884 media_channel()->SetExtmapAllowMixed(audio->extmap_allow_mixed());
jbauch5869f502017-06-29 12:31:36 -0700885
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700886 AudioRecvParameters recv_params = last_recv_params_;
jbauch5869f502017-06-29 12:31:36 -0700887 RtpParametersFromMediaDescription(audio, rtp_header_extensions, &recv_params);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700888 if (!media_channel()->SetRecvParameters(recv_params)) {
Peter Thatcherbfab5cb2015-08-20 17:40:24 -0700889 SafeSetError("Failed to set local audio description recv parameters.",
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700890 error_desc);
891 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000892 }
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700893 for (const AudioCodec& codec : audio->codecs()) {
zstein3dcf0e92017-06-01 13:22:42 -0700894 AddHandledPayloadType(codec.id);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700895 }
Zhi Huang365381f2018-04-13 16:44:34 -0700896 // Need to re-register the sink to update the handled payload.
897 if (!RegisterRtpDemuxerSink()) {
898 RTC_LOG(LS_ERROR) << "Failed to set up audio demuxing.";
899 return false;
900 }
901
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700902 last_recv_params_ = recv_params;
903
904 // TODO(pthatcher): Move local streams into AudioSendParameters, and
905 // only give it to the media channel once we have a remote
906 // description too (without a remote description, we won't be able
907 // to send them anyway).
Steve Anton3828c062017-12-06 10:34:51 -0800908 if (!UpdateLocalStreams_w(audio->streams(), type, error_desc)) {
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700909 SafeSetError("Failed to set local audio description streams.", error_desc);
910 return false;
911 }
912
913 set_local_content_direction(content->direction());
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700914 UpdateMediaSendRecvState_w();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700915 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000916}
917
918bool VoiceChannel::SetRemoteContent_w(const MediaContentDescription* content,
Steve Anton3828c062017-12-06 10:34:51 -0800919 SdpType type,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000920 std::string* error_desc) {
Peter Boström9f45a452015-12-08 13:25:57 +0100921 TRACE_EVENT0("webrtc", "VoiceChannel::SetRemoteContent_w");
Steve Antonb1c1de12017-12-21 15:14:30 -0800922 RTC_DCHECK_RUN_ON(worker_thread());
Mirko Bonadei675513b2017-11-09 11:09:25 +0100923 RTC_LOG(LS_INFO) << "Setting remote voice description";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000924
Steve Antonb1c1de12017-12-21 15:14:30 -0800925 RTC_DCHECK(content);
926 if (!content) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000927 SafeSetError("Can't find audio content in remote description.", error_desc);
928 return false;
929 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000930
Steve Antonb1c1de12017-12-21 15:14:30 -0800931 const AudioContentDescription* audio = content->as_audio();
932
jbauch5869f502017-06-29 12:31:36 -0700933 RtpHeaderExtensions rtp_header_extensions =
934 GetFilteredRtpHeaderExtensions(audio->rtp_header_extensions());
935
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700936 AudioSendParameters send_params = last_send_params_;
jbauch5869f502017-06-29 12:31:36 -0700937 RtpSendParametersFromMediaDescription(audio, rtp_header_extensions,
Yves Gerey665174f2018-06-19 15:03:05 +0200938 &send_params);
Steve Antonbb50ce52018-03-26 10:24:32 -0700939 send_params.mid = content_name();
skvladdc1c62c2016-03-16 19:07:43 -0700940
941 bool parameters_applied = media_channel()->SetSendParameters(send_params);
942 if (!parameters_applied) {
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700943 SafeSetError("Failed to set remote audio description send parameters.",
944 error_desc);
945 return false;
946 }
947 last_send_params_ = send_params;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000948
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700949 // TODO(pthatcher): Move remote streams into AudioRecvParameters,
950 // and only give it to the media channel once we have a local
951 // description too (without a local description, we won't be able to
952 // recv them anyway).
Steve Anton3828c062017-12-06 10:34:51 -0800953 if (!UpdateRemoteStreams_w(audio->streams(), type, error_desc)) {
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700954 SafeSetError("Failed to set remote audio description streams.", error_desc);
955 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000956 }
957
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700958 set_remote_content_direction(content->direction());
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700959 UpdateMediaSendRecvState_w();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700960 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000961}
962
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200963VideoChannel::VideoChannel(rtc::Thread* worker_thread,
964 rtc::Thread* network_thread,
zhihuangf5b251b2017-01-12 19:37:48 -0800965 rtc::Thread* signaling_thread,
Steve Anton8699a322017-11-06 15:53:33 -0800966 std::unique_ptr<VideoMediaChannel> media_channel,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000967 const std::string& content_name,
Zhi Huange830e682018-03-30 10:48:35 -0700968 bool srtp_required,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800969 webrtc::CryptoOptions crypto_options,
970 UniqueRandomIdGenerator* ssrc_generator)
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200971 : BaseChannel(worker_thread,
972 network_thread,
zhihuangf5b251b2017-01-12 19:37:48 -0800973 signaling_thread,
Steve Anton8699a322017-11-06 15:53:33 -0800974 std::move(media_channel),
deadbeefcbecd352015-09-23 11:50:27 -0700975 content_name,
Zhi Huange830e682018-03-30 10:48:35 -0700976 srtp_required,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800977 crypto_options,
978 ssrc_generator) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000979
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000980VideoChannel::~VideoChannel() {
Peter Boströmca8b4042016-03-08 14:24:13 -0800981 TRACE_EVENT0("webrtc", "VideoChannel::~VideoChannel");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000982 // this can't be done in the base class, since it calls a virtual
983 DisableMedia_w();
Zhi Huang0ffe03d2018-03-30 13:17:42 -0700984 Deinit();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000985}
986
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700987void VideoChannel::UpdateMediaSendRecvState_w() {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000988 // Send outgoing data if we're the active call, we have the remote content,
989 // and we have had some form of connectivity.
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700990 bool send = IsReadyToSendMedia_w();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000991 if (!media_channel()->SetSend(send)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100992 RTC_LOG(LS_ERROR) << "Failed to SetSend on video channel";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000993 // TODO(gangji): Report error back to server.
994 }
995
Mirko Bonadei675513b2017-11-09 11:09:25 +0100996 RTC_LOG(LS_INFO) << "Changing video state, send=" << send;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000997}
998
stefanf79ade12017-06-02 06:44:03 -0700999void VideoChannel::FillBitrateInfo(BandwidthEstimationInfo* bwe_info) {
1000 InvokeOnWorker<void>(RTC_FROM_HERE, Bind(&VideoMediaChannel::FillBitrateInfo,
1001 media_channel(), bwe_info));
1002}
1003
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001004bool VideoChannel::SetLocalContent_w(const MediaContentDescription* content,
Steve Anton3828c062017-12-06 10:34:51 -08001005 SdpType type,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001006 std::string* error_desc) {
Peter Boström9f45a452015-12-08 13:25:57 +01001007 TRACE_EVENT0("webrtc", "VideoChannel::SetLocalContent_w");
Steve Antonb1c1de12017-12-21 15:14:30 -08001008 RTC_DCHECK_RUN_ON(worker_thread());
Mirko Bonadei675513b2017-11-09 11:09:25 +01001009 RTC_LOG(LS_INFO) << "Setting local video description";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001010
Steve Antonb1c1de12017-12-21 15:14:30 -08001011 RTC_DCHECK(content);
1012 if (!content) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001013 SafeSetError("Can't find video content in local description.", error_desc);
1014 return false;
1015 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001016
Steve Antonb1c1de12017-12-21 15:14:30 -08001017 const VideoContentDescription* video = content->as_video();
1018
jbauch5869f502017-06-29 12:31:36 -07001019 RtpHeaderExtensions rtp_header_extensions =
1020 GetFilteredRtpHeaderExtensions(video->rtp_header_extensions());
Zhi Huang365381f2018-04-13 16:44:34 -07001021 UpdateRtpHeaderExtensionMap(rtp_header_extensions);
Johannes Kron9190b822018-10-29 11:22:05 +01001022 media_channel()->SetExtmapAllowMixed(video->extmap_allow_mixed());
jbauch5869f502017-06-29 12:31:36 -07001023
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001024 VideoRecvParameters recv_params = last_recv_params_;
jbauch5869f502017-06-29 12:31:36 -07001025 RtpParametersFromMediaDescription(video, rtp_header_extensions, &recv_params);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001026 if (!media_channel()->SetRecvParameters(recv_params)) {
1027 SafeSetError("Failed to set local video description recv parameters.",
1028 error_desc);
1029 return false;
1030 }
1031 for (const VideoCodec& codec : video->codecs()) {
zstein3dcf0e92017-06-01 13:22:42 -07001032 AddHandledPayloadType(codec.id);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001033 }
Zhi Huang365381f2018-04-13 16:44:34 -07001034 // Need to re-register the sink to update the handled payload.
1035 if (!RegisterRtpDemuxerSink()) {
1036 RTC_LOG(LS_ERROR) << "Failed to set up video demuxing.";
1037 return false;
1038 }
1039
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001040 last_recv_params_ = recv_params;
1041
1042 // TODO(pthatcher): Move local streams into VideoSendParameters, and
1043 // only give it to the media channel once we have a remote
1044 // description too (without a remote description, we won't be able
1045 // to send them anyway).
Steve Anton3828c062017-12-06 10:34:51 -08001046 if (!UpdateLocalStreams_w(video->streams(), type, error_desc)) {
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001047 SafeSetError("Failed to set local video description streams.", error_desc);
1048 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001049 }
1050
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001051 set_local_content_direction(content->direction());
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -07001052 UpdateMediaSendRecvState_w();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001053 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001054}
1055
1056bool VideoChannel::SetRemoteContent_w(const MediaContentDescription* content,
Steve Anton3828c062017-12-06 10:34:51 -08001057 SdpType type,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001058 std::string* error_desc) {
Peter Boström9f45a452015-12-08 13:25:57 +01001059 TRACE_EVENT0("webrtc", "VideoChannel::SetRemoteContent_w");
Steve Antonb1c1de12017-12-21 15:14:30 -08001060 RTC_DCHECK_RUN_ON(worker_thread());
Mirko Bonadei675513b2017-11-09 11:09:25 +01001061 RTC_LOG(LS_INFO) << "Setting remote video description";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001062
Steve Antonb1c1de12017-12-21 15:14:30 -08001063 RTC_DCHECK(content);
1064 if (!content) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001065 SafeSetError("Can't find video content in remote description.", error_desc);
1066 return false;
1067 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001068
Steve Antonb1c1de12017-12-21 15:14:30 -08001069 const VideoContentDescription* video = content->as_video();
1070
jbauch5869f502017-06-29 12:31:36 -07001071 RtpHeaderExtensions rtp_header_extensions =
1072 GetFilteredRtpHeaderExtensions(video->rtp_header_extensions());
1073
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001074 VideoSendParameters send_params = last_send_params_;
jbauch5869f502017-06-29 12:31:36 -07001075 RtpSendParametersFromMediaDescription(video, rtp_header_extensions,
Yves Gerey665174f2018-06-19 15:03:05 +02001076 &send_params);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001077 if (video->conference_mode()) {
nisse4b4dc862016-02-17 05:25:36 -08001078 send_params.conference_mode = true;
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001079 }
Steve Antonbb50ce52018-03-26 10:24:32 -07001080 send_params.mid = content_name();
skvladdc1c62c2016-03-16 19:07:43 -07001081
1082 bool parameters_applied = media_channel()->SetSendParameters(send_params);
1083
1084 if (!parameters_applied) {
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001085 SafeSetError("Failed to set remote video description send parameters.",
1086 error_desc);
1087 return false;
1088 }
1089 last_send_params_ = send_params;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001090
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001091 // TODO(pthatcher): Move remote streams into VideoRecvParameters,
1092 // and only give it to the media channel once we have a local
1093 // description too (without a local description, we won't be able to
1094 // recv them anyway).
Steve Anton3828c062017-12-06 10:34:51 -08001095 if (!UpdateRemoteStreams_w(video->streams(), type, error_desc)) {
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001096 SafeSetError("Failed to set remote video description streams.", error_desc);
1097 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001098 }
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001099 set_remote_content_direction(content->direction());
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -07001100 UpdateMediaSendRecvState_w();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001101 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001102}
1103
deadbeef953c2ce2017-01-09 14:53:41 -08001104RtpDataChannel::RtpDataChannel(rtc::Thread* worker_thread,
1105 rtc::Thread* network_thread,
zhihuangf5b251b2017-01-12 19:37:48 -08001106 rtc::Thread* signaling_thread,
Steve Anton8699a322017-11-06 15:53:33 -08001107 std::unique_ptr<DataMediaChannel> media_channel,
deadbeef953c2ce2017-01-09 14:53:41 -08001108 const std::string& content_name,
Zhi Huange830e682018-03-30 10:48:35 -07001109 bool srtp_required,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001110 webrtc::CryptoOptions crypto_options,
1111 UniqueRandomIdGenerator* ssrc_generator)
Danil Chapovalov33b01f22016-05-11 19:55:27 +02001112 : BaseChannel(worker_thread,
1113 network_thread,
zhihuangf5b251b2017-01-12 19:37:48 -08001114 signaling_thread,
Steve Anton8699a322017-11-06 15:53:33 -08001115 std::move(media_channel),
deadbeefcbecd352015-09-23 11:50:27 -07001116 content_name,
Zhi Huange830e682018-03-30 10:48:35 -07001117 srtp_required,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001118 crypto_options,
1119 ssrc_generator) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001120
deadbeef953c2ce2017-01-09 14:53:41 -08001121RtpDataChannel::~RtpDataChannel() {
1122 TRACE_EVENT0("webrtc", "RtpDataChannel::~RtpDataChannel");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001123 // this can't be done in the base class, since it calls a virtual
1124 DisableMedia_w();
Zhi Huang0ffe03d2018-03-30 13:17:42 -07001125 Deinit();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001126}
1127
Piotr (Peter) Slatala309aafe2019-01-15 14:24:34 -08001128void RtpDataChannel::Init_w(webrtc::RtpTransportInternal* rtp_transport,
1129 webrtc::MediaTransportInterface* media_transport) {
Anton Sukhanov98a462c2018-10-17 13:15:42 -07001130 BaseChannel::Init_w(rtp_transport, /*media_transport=*/nullptr);
Zhi Huang2dfc42d2017-12-04 13:38:48 -08001131 media_channel()->SignalDataReceived.connect(this,
1132 &RtpDataChannel::OnDataReceived);
1133 media_channel()->SignalReadyToSend.connect(
1134 this, &RtpDataChannel::OnDataChannelReadyToSend);
1135}
1136
deadbeef953c2ce2017-01-09 14:53:41 -08001137bool RtpDataChannel::SendData(const SendDataParams& params,
1138 const rtc::CopyOnWriteBuffer& payload,
1139 SendDataResult* result) {
stefanf79ade12017-06-02 06:44:03 -07001140 return InvokeOnWorker<bool>(
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -07001141 RTC_FROM_HERE, Bind(&DataMediaChannel::SendData, media_channel(), params,
1142 payload, result));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001143}
1144
deadbeef953c2ce2017-01-09 14:53:41 -08001145bool RtpDataChannel::CheckDataChannelTypeFromContent(
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001146 const RtpDataContentDescription* content,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001147 std::string* error_desc) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001148 bool is_sctp = ((content->protocol() == kMediaProtocolSctp) ||
1149 (content->protocol() == kMediaProtocolDtlsSctp));
deadbeef953c2ce2017-01-09 14:53:41 -08001150 // It's been set before, but doesn't match. That's bad.
1151 if (is_sctp) {
1152 SafeSetError("Data channel type mismatch. Expected RTP, got SCTP.",
1153 error_desc);
1154 return false;
1155 }
1156 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001157}
1158
deadbeef953c2ce2017-01-09 14:53:41 -08001159bool RtpDataChannel::SetLocalContent_w(const MediaContentDescription* content,
Steve Anton3828c062017-12-06 10:34:51 -08001160 SdpType type,
deadbeef953c2ce2017-01-09 14:53:41 -08001161 std::string* error_desc) {
1162 TRACE_EVENT0("webrtc", "RtpDataChannel::SetLocalContent_w");
Steve Antonb1c1de12017-12-21 15:14:30 -08001163 RTC_DCHECK_RUN_ON(worker_thread());
Mirko Bonadei675513b2017-11-09 11:09:25 +01001164 RTC_LOG(LS_INFO) << "Setting local data description";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001165
Steve Antonb1c1de12017-12-21 15:14:30 -08001166 RTC_DCHECK(content);
1167 if (!content) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001168 SafeSetError("Can't find data content in local description.", error_desc);
1169 return false;
1170 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001171
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001172 const RtpDataContentDescription* data = content->as_rtp_data();
Steve Antonb1c1de12017-12-21 15:14:30 -08001173
deadbeef953c2ce2017-01-09 14:53:41 -08001174 if (!CheckDataChannelTypeFromContent(data, error_desc)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001175 return false;
1176 }
1177
jbauch5869f502017-06-29 12:31:36 -07001178 RtpHeaderExtensions rtp_header_extensions =
1179 GetFilteredRtpHeaderExtensions(data->rtp_header_extensions());
1180
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001181 DataRecvParameters recv_params = last_recv_params_;
jbauch5869f502017-06-29 12:31:36 -07001182 RtpParametersFromMediaDescription(data, rtp_header_extensions, &recv_params);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001183 if (!media_channel()->SetRecvParameters(recv_params)) {
1184 SafeSetError("Failed to set remote data description recv parameters.",
1185 error_desc);
1186 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001187 }
deadbeef953c2ce2017-01-09 14:53:41 -08001188 for (const DataCodec& codec : data->codecs()) {
zstein3dcf0e92017-06-01 13:22:42 -07001189 AddHandledPayloadType(codec.id);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001190 }
Zhi Huang365381f2018-04-13 16:44:34 -07001191 // Need to re-register the sink to update the handled payload.
1192 if (!RegisterRtpDemuxerSink()) {
1193 RTC_LOG(LS_ERROR) << "Failed to set up data demuxing.";
1194 return false;
1195 }
1196
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001197 last_recv_params_ = recv_params;
1198
1199 // TODO(pthatcher): Move local streams into DataSendParameters, and
1200 // only give it to the media channel once we have a remote
1201 // description too (without a remote description, we won't be able
1202 // to send them anyway).
Steve Anton3828c062017-12-06 10:34:51 -08001203 if (!UpdateLocalStreams_w(data->streams(), type, error_desc)) {
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001204 SafeSetError("Failed to set local data description streams.", error_desc);
1205 return false;
1206 }
1207
1208 set_local_content_direction(content->direction());
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -07001209 UpdateMediaSendRecvState_w();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001210 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001211}
1212
deadbeef953c2ce2017-01-09 14:53:41 -08001213bool RtpDataChannel::SetRemoteContent_w(const MediaContentDescription* content,
Steve Anton3828c062017-12-06 10:34:51 -08001214 SdpType type,
deadbeef953c2ce2017-01-09 14:53:41 -08001215 std::string* error_desc) {
1216 TRACE_EVENT0("webrtc", "RtpDataChannel::SetRemoteContent_w");
Steve Antonb1c1de12017-12-21 15:14:30 -08001217 RTC_DCHECK_RUN_ON(worker_thread());
1218 RTC_LOG(LS_INFO) << "Setting remote data description";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001219
Steve Antonb1c1de12017-12-21 15:14:30 -08001220 RTC_DCHECK(content);
1221 if (!content) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001222 SafeSetError("Can't find data content in remote description.", error_desc);
1223 return false;
1224 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001225
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001226 const RtpDataContentDescription* data = content->as_rtp_data();
1227
1228 if (!data) {
1229 RTC_LOG(LS_INFO) << "Accepting and ignoring non-RTP content description";
1230 return true;
1231 }
Steve Antonb1c1de12017-12-21 15:14:30 -08001232
Zhi Huang801b8682017-11-15 11:36:43 -08001233 // If the remote data doesn't have codecs, it must be empty, so ignore it.
1234 if (!data->has_codecs()) {
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001235 return true;
1236 }
1237
deadbeef953c2ce2017-01-09 14:53:41 -08001238 if (!CheckDataChannelTypeFromContent(data, error_desc)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001239 return false;
1240 }
1241
jbauch5869f502017-06-29 12:31:36 -07001242 RtpHeaderExtensions rtp_header_extensions =
1243 GetFilteredRtpHeaderExtensions(data->rtp_header_extensions());
1244
Mirko Bonadei675513b2017-11-09 11:09:25 +01001245 RTC_LOG(LS_INFO) << "Setting remote data description";
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001246 DataSendParameters send_params = last_send_params_;
jbauch5869f502017-06-29 12:31:36 -07001247 RtpSendParametersFromMediaDescription<DataCodec>(data, rtp_header_extensions,
Yves Gerey665174f2018-06-19 15:03:05 +02001248 &send_params);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001249 if (!media_channel()->SetSendParameters(send_params)) {
1250 SafeSetError("Failed to set remote data description send parameters.",
1251 error_desc);
1252 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001253 }
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001254 last_send_params_ = send_params;
1255
1256 // TODO(pthatcher): Move remote streams into DataRecvParameters,
1257 // and only give it to the media channel once we have a local
1258 // description too (without a local description, we won't be able to
1259 // recv them anyway).
Steve Anton3828c062017-12-06 10:34:51 -08001260 if (!UpdateRemoteStreams_w(data->streams(), type, error_desc)) {
Yves Gerey665174f2018-06-19 15:03:05 +02001261 SafeSetError("Failed to set remote data description streams.", error_desc);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001262 return false;
1263 }
1264
1265 set_remote_content_direction(content->direction());
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -07001266 UpdateMediaSendRecvState_w();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001267 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001268}
1269
deadbeef953c2ce2017-01-09 14:53:41 -08001270void RtpDataChannel::UpdateMediaSendRecvState_w() {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001271 // Render incoming data if we're the active call, and we have the local
1272 // content. We receive data on the default channel and multiplexed streams.
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -07001273 bool recv = IsReadyToReceiveMedia_w();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001274 if (!media_channel()->SetReceive(recv)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001275 RTC_LOG(LS_ERROR) << "Failed to SetReceive on data channel";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001276 }
1277
1278 // Send outgoing data if we're the active call, we have the remote content,
1279 // and we have had some form of connectivity.
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -07001280 bool send = IsReadyToSendMedia_w();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001281 if (!media_channel()->SetSend(send)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001282 RTC_LOG(LS_ERROR) << "Failed to SetSend on data channel";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001283 }
1284
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001285 // Trigger SignalReadyToSendData asynchronously.
1286 OnDataChannelReadyToSend(send);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001287
Mirko Bonadei675513b2017-11-09 11:09:25 +01001288 RTC_LOG(LS_INFO) << "Changing data state, recv=" << recv << " send=" << send;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001289}
1290
deadbeef953c2ce2017-01-09 14:53:41 -08001291void RtpDataChannel::OnMessage(rtc::Message* pmsg) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001292 switch (pmsg->message_id) {
1293 case MSG_READYTOSENDDATA: {
wu@webrtc.orgd64719d2013-08-01 00:00:07 +00001294 DataChannelReadyToSendMessageData* data =
1295 static_cast<DataChannelReadyToSendMessageData*>(pmsg->pdata);
wu@webrtc.org07a6fbe2013-11-04 18:41:34 +00001296 ready_to_send_data_ = data->data();
1297 SignalReadyToSendData(ready_to_send_data_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001298 delete data;
1299 break;
1300 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001301 case MSG_DATARECEIVED: {
1302 DataReceivedMessageData* data =
1303 static_cast<DataReceivedMessageData*>(pmsg->pdata);
deadbeef953c2ce2017-01-09 14:53:41 -08001304 SignalDataReceived(data->params, data->payload);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001305 delete data;
1306 break;
1307 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001308 default:
1309 BaseChannel::OnMessage(pmsg);
1310 break;
1311 }
1312}
1313
deadbeef953c2ce2017-01-09 14:53:41 -08001314void RtpDataChannel::OnDataReceived(const ReceiveDataParams& params,
1315 const char* data,
1316 size_t len) {
Yves Gerey665174f2018-06-19 15:03:05 +02001317 DataReceivedMessageData* msg = new DataReceivedMessageData(params, data, len);
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -07001318 signaling_thread()->Post(RTC_FROM_HERE, this, MSG_DATARECEIVED, msg);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001319}
1320
deadbeef953c2ce2017-01-09 14:53:41 -08001321void RtpDataChannel::OnDataChannelReadyToSend(bool writable) {
wu@webrtc.orgd64719d2013-08-01 00:00:07 +00001322 // This is usded for congestion control to indicate that the stream is ready
1323 // to send by the MediaChannel, as opposed to OnReadyToSend, which indicates
1324 // that the transport channel is ready.
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -07001325 signaling_thread()->Post(RTC_FROM_HERE, this, MSG_READYTOSENDDATA,
wu@webrtc.orgd64719d2013-08-01 00:00:07 +00001326 new DataChannelReadyToSendMessageData(writable));
1327}
1328
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001329} // namespace cricket