blob: 049e9506ce5dab383b1aba6b6cba377383f16461 [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 <algorithm>
12#include <iterator>
kwiberg0eb15ed2015-12-17 03:04:15 -080013#include <utility>
14
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "pc/channel.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000016
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"
Patrik Höglund42805f32018-01-18 19:15:38 +000031// Adding 'nogncheck' to disable the gn include headers check to support modular
32// WebRTC build targets.
Steve Anton10542f22019-01-11 09:11:00 -080033#include "media/engine/webrtc_voice_engine.h" // nogncheck
34#include "p2p/base/packet_transport_internal.h"
35#include "pc/channel_manager.h"
36#include "pc/rtp_media_utils.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000037
38namespace cricket {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000039using rtc::Bind;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080040using rtc::UniqueRandomIdGenerator;
Steve Anton3828c062017-12-06 10:34:51 -080041using webrtc::SdpType;
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +000042
deadbeef2d110be2016-01-13 12:00:26 -080043namespace {
Danil Chapovalov33b01f22016-05-11 19:55:27 +020044
45struct SendPacketMessageData : public rtc::MessageData {
46 rtc::CopyOnWriteBuffer packet;
47 rtc::PacketOptions options;
48};
49
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080050// Finds a stream based on target's Primary SSRC or RIDs.
51// This struct is used in BaseChannel::UpdateLocalStreams_w.
52struct StreamFinder {
53 explicit StreamFinder(const StreamParams* target) : target_(target) {
54 RTC_DCHECK(target);
55 }
56
57 bool operator()(const StreamParams& sp) const {
58 if (target_->has_ssrcs() && sp.has_ssrcs()) {
59 return sp.has_ssrc(target_->first_ssrc());
60 }
61
62 if (!target_->has_rids() && !sp.has_rids()) {
63 return false;
64 }
65
66 const std::vector<RidDescription>& target_rids = target_->rids();
67 const std::vector<RidDescription>& source_rids = sp.rids();
68 if (source_rids.size() != target_rids.size()) {
69 return false;
70 }
71
72 // Check that all RIDs match.
73 return std::equal(source_rids.begin(), source_rids.end(),
74 target_rids.begin(),
75 [](const RidDescription& lhs, const RidDescription& rhs) {
76 return lhs.rid == rhs.rid;
77 });
78 }
79
80 const StreamParams* target_;
81};
82
deadbeef2d110be2016-01-13 12:00:26 -080083} // namespace
84
henrike@webrtc.org28e20752013-07-10 00:45:36 +000085enum {
Steve Anton0807d152018-03-05 11:23:09 -080086 MSG_SEND_RTP_PACKET = 1,
Danil Chapovalov33b01f22016-05-11 19:55:27 +020087 MSG_SEND_RTCP_PACKET,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000088 MSG_READYTOSENDDATA,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000089 MSG_DATARECEIVED,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000090 MSG_FIRSTPACKETRECEIVED,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000091};
92
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +000093static void SafeSetError(const std::string& message, std::string* error_desc) {
94 if (error_desc) {
95 *error_desc = message;
96 }
97}
98
jbaucheec21bd2016-03-20 06:15:43 -070099static bool ValidPacket(bool rtcp, const rtc::CopyOnWriteBuffer* packet) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000100 // Check the packet size. We could check the header too if needed.
zstein3dcf0e92017-06-01 13:22:42 -0700101 return packet && IsValidRtpRtcpPacketSize(rtcp, packet->size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000102}
103
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700104template <class Codec>
105void RtpParametersFromMediaDescription(
106 const MediaContentDescriptionImpl<Codec>* desc,
jbauch5869f502017-06-29 12:31:36 -0700107 const RtpHeaderExtensions& extensions,
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700108 RtpParameters<Codec>* params) {
109 // TODO(pthatcher): Remove this once we're sure no one will give us
Zhi Huang801b8682017-11-15 11:36:43 -0800110 // a description without codecs. Currently the ORTC implementation is relying
111 // on this.
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700112 if (desc->has_codecs()) {
113 params->codecs = desc->codecs();
114 }
115 // TODO(pthatcher): See if we really need
116 // rtp_header_extensions_set() and remove it if we don't.
117 if (desc->rtp_header_extensions_set()) {
jbauch5869f502017-06-29 12:31:36 -0700118 params->extensions = extensions;
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700119 }
deadbeef13871492015-12-09 12:37:51 -0800120 params->rtcp.reduced_size = desc->rtcp_reduced_size();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700121}
122
nisse05103312016-03-16 02:22:50 -0700123template <class Codec>
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700124void RtpSendParametersFromMediaDescription(
125 const MediaContentDescriptionImpl<Codec>* desc,
jbauch5869f502017-06-29 12:31:36 -0700126 const RtpHeaderExtensions& extensions,
nisse05103312016-03-16 02:22:50 -0700127 RtpSendParameters<Codec>* send_params) {
jbauch5869f502017-06-29 12:31:36 -0700128 RtpParametersFromMediaDescription(desc, extensions, send_params);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700129 send_params->max_bandwidth_bps = desc->bandwidth();
Johannes Kron9190b822018-10-29 11:22:05 +0100130 send_params->extmap_allow_mixed = desc->extmap_allow_mixed();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700131}
132
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200133BaseChannel::BaseChannel(rtc::Thread* worker_thread,
134 rtc::Thread* network_thread,
zhihuangf5b251b2017-01-12 19:37:48 -0800135 rtc::Thread* signaling_thread,
Steve Anton8699a322017-11-06 15:53:33 -0800136 std::unique_ptr<MediaChannel> media_channel,
deadbeefcbecd352015-09-23 11:50:27 -0700137 const std::string& content_name,
Zhi Huange830e682018-03-30 10:48:35 -0700138 bool srtp_required,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800139 webrtc::CryptoOptions crypto_options,
140 UniqueRandomIdGenerator* ssrc_generator)
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200141 : worker_thread_(worker_thread),
142 network_thread_(network_thread),
zhihuangf5b251b2017-01-12 19:37:48 -0800143 signaling_thread_(signaling_thread),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000144 content_name_(content_name),
deadbeef7af91dd2016-12-13 11:29:11 -0800145 srtp_required_(srtp_required),
Zhi Huange830e682018-03-30 10:48:35 -0700146 crypto_options_(crypto_options),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800147 media_channel_(std::move(media_channel)),
148 ssrc_generator_(ssrc_generator) {
Steve Anton8699a322017-11-06 15:53:33 -0800149 RTC_DCHECK_RUN_ON(worker_thread_);
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800150 RTC_DCHECK(ssrc_generator_);
Zhi Huang365381f2018-04-13 16:44:34 -0700151 demuxer_criteria_.mid = content_name;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100152 RTC_LOG(LS_INFO) << "Created channel for " << content_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000153}
154
155BaseChannel::~BaseChannel() {
Peter Boströmca8b4042016-03-08 14:24:13 -0800156 TRACE_EVENT0("webrtc", "BaseChannel::~BaseChannel");
Steve Anton8699a322017-11-06 15:53:33 -0800157 RTC_DCHECK_RUN_ON(worker_thread_);
Piotr (Peter) Slatala179a3922018-11-16 09:57:58 -0800158
159 if (media_transport_) {
160 media_transport_->SetNetworkChangeCallback(nullptr);
161 }
162
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200163 // Eats any outstanding messages or packets.
164 worker_thread_->Clear(&invoker_);
165 worker_thread_->Clear(this);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000166 // We must destroy the media channel before the transport channel, otherwise
167 // the media channel may try to send on the dead transport channel. NULLing
168 // is not an effective strategy since the sends will come on another thread.
Steve Anton8699a322017-11-06 15:53:33 -0800169 media_channel_.reset();
Mirko Bonadei675513b2017-11-09 11:09:25 +0100170 RTC_LOG(LS_INFO) << "Destroyed channel: " << content_name_;
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200171}
172
Zhi Huang365381f2018-04-13 16:44:34 -0700173bool BaseChannel::ConnectToRtpTransport() {
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800174 RTC_DCHECK(rtp_transport_);
Zhi Huang365381f2018-04-13 16:44:34 -0700175 if (!RegisterRtpDemuxerSink()) {
176 return false;
177 }
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800178 rtp_transport_->SignalReadyToSend.connect(
179 this, &BaseChannel::OnTransportReadyToSend);
Zhi Huang365381f2018-04-13 16:44:34 -0700180 rtp_transport_->SignalRtcpPacketReceived.connect(
181 this, &BaseChannel::OnRtcpPacketReceived);
Piotr (Peter) Slatala179a3922018-11-16 09:57:58 -0800182
183 // If media transport is used, it's responsible for providing network
184 // route changed callbacks.
185 if (!media_transport_) {
186 rtp_transport_->SignalNetworkRouteChanged.connect(
187 this, &BaseChannel::OnNetworkRouteChanged);
188 }
189 // TODO(bugs.webrtc.org/9719): Media transport should also be used to provide
190 // 'writable' state here.
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800191 rtp_transport_->SignalWritableState.connect(this,
192 &BaseChannel::OnWritableState);
193 rtp_transport_->SignalSentPacket.connect(this,
194 &BaseChannel::SignalSentPacket_n);
Zhi Huang365381f2018-04-13 16:44:34 -0700195 return true;
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800196}
Danil Chapovalovdae07ba2016-05-14 01:43:50 +0200197
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800198void BaseChannel::DisconnectFromRtpTransport() {
199 RTC_DCHECK(rtp_transport_);
Zhi Huang365381f2018-04-13 16:44:34 -0700200 rtp_transport_->UnregisterRtpDemuxerSink(this);
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800201 rtp_transport_->SignalReadyToSend.disconnect(this);
Zhi Huang365381f2018-04-13 16:44:34 -0700202 rtp_transport_->SignalRtcpPacketReceived.disconnect(this);
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800203 rtp_transport_->SignalNetworkRouteChanged.disconnect(this);
204 rtp_transport_->SignalWritableState.disconnect(this);
205 rtp_transport_->SignalSentPacket.disconnect(this);
Danil Chapovalovdae07ba2016-05-14 01:43:50 +0200206}
207
Anton Sukhanov98a462c2018-10-17 13:15:42 -0700208void BaseChannel::Init_w(webrtc::RtpTransportInternal* rtp_transport,
209 webrtc::MediaTransportInterface* media_transport) {
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800210 RTC_DCHECK_RUN_ON(worker_thread_);
Piotr (Peter) Slatala179a3922018-11-16 09:57:58 -0800211 media_transport_ = media_transport;
212
Zhi Huang365381f2018-04-13 16:44:34 -0700213 network_thread_->Invoke<void>(
214 RTC_FROM_HERE, [this, rtp_transport] { SetRtpTransport(rtp_transport); });
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800215
216 // Both RTP and RTCP channels should be set, we can call SetInterface on
217 // the media channel and it can set network options.
Anton Sukhanov98a462c2018-10-17 13:15:42 -0700218 media_channel_->SetInterface(this, media_transport);
Piotr (Peter) Slatala179a3922018-11-16 09:57:58 -0800219
220 RTC_LOG(LS_INFO) << "BaseChannel::Init_w, media_transport="
221 << (media_transport_ != nullptr);
222 if (media_transport_) {
223 media_transport_->SetNetworkChangeCallback(this);
224 }
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200225}
226
wu@webrtc.org78187522013-10-07 23:32:02 +0000227void BaseChannel::Deinit() {
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200228 RTC_DCHECK(worker_thread_->IsCurrent());
Anton Sukhanov98a462c2018-10-17 13:15:42 -0700229 media_channel_->SetInterface(/*iface=*/nullptr,
230 /*media_transport=*/nullptr);
Danil Chapovalovdae07ba2016-05-14 01:43:50 +0200231 // Packets arrive on the network thread, processing packets calls virtual
232 // functions, so need to stop this process in Deinit that is called in
233 // derived classes destructor.
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800234 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
Zhi Huang95e7dbb2018-03-29 00:08:03 +0000235 FlushRtcpMessages_n();
Zhi Huang27f3bf52018-03-26 21:37:23 -0700236
Zhi Huange830e682018-03-30 10:48:35 -0700237 if (rtp_transport_) {
238 DisconnectFromRtpTransport();
Zhi Huang95e7dbb2018-03-29 00:08:03 +0000239 }
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800240 // Clear pending read packets/messages.
241 network_thread_->Clear(&invoker_);
242 network_thread_->Clear(this);
243 });
wu@webrtc.org78187522013-10-07 23:32:02 +0000244}
245
Zhi Huang365381f2018-04-13 16:44:34 -0700246bool BaseChannel::SetRtpTransport(webrtc::RtpTransportInternal* rtp_transport) {
247 if (rtp_transport == rtp_transport_) {
248 return true;
249 }
250
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800251 if (!network_thread_->IsCurrent()) {
Zhi Huang365381f2018-04-13 16:44:34 -0700252 return network_thread_->Invoke<bool>(RTC_FROM_HERE, [this, rtp_transport] {
253 return SetRtpTransport(rtp_transport);
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800254 });
255 }
Zhi Huang95e7dbb2018-03-29 00:08:03 +0000256
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800257 if (rtp_transport_) {
258 DisconnectFromRtpTransport();
259 }
Zhi Huange830e682018-03-30 10:48:35 -0700260
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800261 rtp_transport_ = rtp_transport;
Zhi Huange830e682018-03-30 10:48:35 -0700262 if (rtp_transport_) {
263 RTC_DCHECK(rtp_transport_->rtp_packet_transport());
264 transport_name_ = rtp_transport_->rtp_packet_transport()->transport_name();
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800265
Zhi Huang365381f2018-04-13 16:44:34 -0700266 if (!ConnectToRtpTransport()) {
267 RTC_LOG(LS_ERROR) << "Failed to connect to the new RtpTransport.";
268 return false;
269 }
Zhi Huange830e682018-03-30 10:48:35 -0700270 OnTransportReadyToSend(rtp_transport_->IsReadyToSend());
271 UpdateWritableState_n();
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800272
Zhi Huange830e682018-03-30 10:48:35 -0700273 // Set the cached socket options.
274 for (const auto& pair : socket_options_) {
275 rtp_transport_->rtp_packet_transport()->SetOption(pair.first,
276 pair.second);
277 }
278 if (rtp_transport_->rtcp_packet_transport()) {
279 for (const auto& pair : rtcp_socket_options_) {
280 rtp_transport_->rtp_packet_transport()->SetOption(pair.first,
281 pair.second);
282 }
283 }
guoweis46383312015-12-17 16:45:59 -0800284 }
Zhi Huang365381f2018-04-13 16:44:34 -0700285 return true;
pthatcher@webrtc.org6ad507a2015-03-16 20:19:12 +0000286}
287
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000288bool BaseChannel::Enable(bool enable) {
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700289 worker_thread_->Invoke<void>(
290 RTC_FROM_HERE,
291 Bind(enable ? &BaseChannel::EnableMedia_w : &BaseChannel::DisableMedia_w,
292 this));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000293 return true;
294}
295
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000296bool BaseChannel::SetLocalContent(const MediaContentDescription* content,
Steve Anton3828c062017-12-06 10:34:51 -0800297 SdpType type,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000298 std::string* error_desc) {
Peter Boström9f45a452015-12-08 13:25:57 +0100299 TRACE_EVENT0("webrtc", "BaseChannel::SetLocalContent");
stefanf79ade12017-06-02 06:44:03 -0700300 return InvokeOnWorker<bool>(
301 RTC_FROM_HERE,
Steve Anton3828c062017-12-06 10:34:51 -0800302 Bind(&BaseChannel::SetLocalContent_w, this, content, type, error_desc));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000303}
304
305bool BaseChannel::SetRemoteContent(const MediaContentDescription* content,
Steve Anton3828c062017-12-06 10:34:51 -0800306 SdpType type,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000307 std::string* error_desc) {
Peter Boström9f45a452015-12-08 13:25:57 +0100308 TRACE_EVENT0("webrtc", "BaseChannel::SetRemoteContent");
stefanf79ade12017-06-02 06:44:03 -0700309 return InvokeOnWorker<bool>(
Steve Anton3828c062017-12-06 10:34:51 -0800310 RTC_FROM_HERE,
311 Bind(&BaseChannel::SetRemoteContent_w, this, content, type, error_desc));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000312}
313
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700314bool BaseChannel::IsReadyToReceiveMedia_w() const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000315 // Receive data if we are enabled and have local content,
Steve Anton4e70a722017-11-28 14:57:10 -0800316 return enabled() &&
317 webrtc::RtpTransceiverDirectionHasRecv(local_content_direction_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000318}
319
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700320bool BaseChannel::IsReadyToSendMedia_w() const {
321 // Need to access some state updated on the network thread.
322 return network_thread_->Invoke<bool>(
323 RTC_FROM_HERE, Bind(&BaseChannel::IsReadyToSendMedia_n, this));
324}
325
326bool BaseChannel::IsReadyToSendMedia_n() const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000327 // Send outgoing data if we are enabled, have local and remote content,
328 // and we have had some form of connectivity.
Steve Anton4e70a722017-11-28 14:57:10 -0800329 return enabled() &&
330 webrtc::RtpTransceiverDirectionHasRecv(remote_content_direction_) &&
331 webrtc::RtpTransceiverDirectionHasSend(local_content_direction_) &&
Zhi Huang365381f2018-04-13 16:44:34 -0700332 was_ever_writable();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000333}
334
jbaucheec21bd2016-03-20 06:15:43 -0700335bool BaseChannel::SendPacket(rtc::CopyOnWriteBuffer* packet,
stefanc1aeaf02015-10-15 07:26:07 -0700336 const rtc::PacketOptions& options) {
337 return SendPacket(false, packet, options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000338}
339
jbaucheec21bd2016-03-20 06:15:43 -0700340bool BaseChannel::SendRtcp(rtc::CopyOnWriteBuffer* packet,
stefanc1aeaf02015-10-15 07:26:07 -0700341 const rtc::PacketOptions& options) {
342 return SendPacket(true, packet, options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000343}
344
Yves Gerey665174f2018-06-19 15:03:05 +0200345int BaseChannel::SetOption(SocketType type,
346 rtc::Socket::Option opt,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000347 int value) {
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200348 return network_thread_->Invoke<int>(
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700349 RTC_FROM_HERE, Bind(&BaseChannel::SetOption_n, this, type, opt, value));
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200350}
351
352int BaseChannel::SetOption_n(SocketType type,
353 rtc::Socket::Option opt,
354 int value) {
355 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange830e682018-03-30 10:48:35 -0700356 RTC_DCHECK(rtp_transport_);
deadbeef5bd5ca32017-02-10 11:31:50 -0800357 rtc::PacketTransportInternal* transport = nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000358 switch (type) {
wu@webrtc.org9caf2762013-12-11 18:25:07 +0000359 case ST_RTP:
zsteine8ab5432017-07-12 11:48:11 -0700360 transport = rtp_transport_->rtp_packet_transport();
deadbeefcbecd352015-09-23 11:50:27 -0700361 socket_options_.push_back(
362 std::pair<rtc::Socket::Option, int>(opt, value));
wu@webrtc.org9caf2762013-12-11 18:25:07 +0000363 break;
364 case ST_RTCP:
zsteine8ab5432017-07-12 11:48:11 -0700365 transport = rtp_transport_->rtcp_packet_transport();
deadbeefcbecd352015-09-23 11:50:27 -0700366 rtcp_socket_options_.push_back(
367 std::pair<rtc::Socket::Option, int>(opt, value));
wu@webrtc.org9caf2762013-12-11 18:25:07 +0000368 break;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000369 }
deadbeeff5346592017-01-24 21:51:21 -0800370 return transport ? transport->SetOption(opt, value) : -1;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000371}
372
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800373void BaseChannel::OnWritableState(bool writable) {
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200374 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800375 if (writable) {
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800376 ChannelWritable_n();
377 } else {
378 ChannelNotWritable_n();
Guo-wei Shieh1218d7a2015-12-05 09:59:56 -0800379 }
380}
381
Zhi Huang942bc2e2017-11-13 13:26:07 -0800382void BaseChannel::OnNetworkRouteChanged(
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200383 absl::optional<rtc::NetworkRoute> network_route) {
Piotr (Peter) Slatala179a3922018-11-16 09:57:58 -0800384 RTC_LOG(LS_INFO) << "Network route was changed.";
385
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200386 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huang942bc2e2017-11-13 13:26:07 -0800387 rtc::NetworkRoute new_route;
388 if (network_route) {
Zhi Huang942bc2e2017-11-13 13:26:07 -0800389 new_route = *(network_route);
Zhi Huang8c316c12017-11-13 21:13:45 +0000390 }
Zhi Huang942bc2e2017-11-13 13:26:07 -0800391 // Note: When the RTCP-muxing is not enabled, RTCP transport and RTP transport
392 // use the same transport name and MediaChannel::OnNetworkRouteChanged cannot
393 // work correctly. Intentionally leave it broken to simplify the code and
394 // encourage the users to stop using non-muxing RTCP.
Steve Anton8699a322017-11-06 15:53:33 -0800395 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, worker_thread_, [=] {
Zhi Huang942bc2e2017-11-13 13:26:07 -0800396 media_channel_->OnNetworkRouteChanged(transport_name_, new_route);
Steve Anton8699a322017-11-06 15:53:33 -0800397 });
Honghai Zhangcc411c02016-03-29 17:27:21 -0700398}
399
zstein56162b92017-04-24 16:54:35 -0700400void BaseChannel::OnTransportReadyToSend(bool ready) {
Steve Anton8699a322017-11-06 15:53:33 -0800401 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, worker_thread_,
402 [=] { media_channel_->OnReadyToSend(ready); });
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000403}
404
stefanc1aeaf02015-10-15 07:26:07 -0700405bool BaseChannel::SendPacket(bool rtcp,
jbaucheec21bd2016-03-20 06:15:43 -0700406 rtc::CopyOnWriteBuffer* packet,
stefanc1aeaf02015-10-15 07:26:07 -0700407 const rtc::PacketOptions& options) {
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200408 // SendPacket gets called from MediaEngine, on a pacer or an encoder thread.
409 // If the thread is not our network thread, we will post to our network
410 // so that the real work happens on our network. This avoids us having to
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000411 // synchronize access to all the pieces of the send path, including
412 // SRTP and the inner workings of the transport channels.
413 // The only downside is that we can't return a proper failure code if
414 // needed. Since UDP is unreliable anyway, this should be a non-issue.
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200415 if (!network_thread_->IsCurrent()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000416 // Avoid a copy by transferring the ownership of the packet data.
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200417 int message_id = rtcp ? MSG_SEND_RTCP_PACKET : MSG_SEND_RTP_PACKET;
418 SendPacketMessageData* data = new SendPacketMessageData;
kwiberg0eb15ed2015-12-17 03:04:15 -0800419 data->packet = std::move(*packet);
stefanc1aeaf02015-10-15 07:26:07 -0700420 data->options = options;
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700421 network_thread_->Post(RTC_FROM_HERE, this, message_id, data);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000422 return true;
423 }
Zhi Huange830e682018-03-30 10:48:35 -0700424
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200425 TRACE_EVENT0("webrtc", "BaseChannel::SendPacket");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000426
427 // Now that we are on the correct thread, ensure we have a place to send this
428 // packet before doing anything. (We might get RTCP packets that we don't
429 // intend to send.) If we've negotiated RTCP mux, send RTCP over the RTP
430 // transport.
Zhi Huange830e682018-03-30 10:48:35 -0700431 if (!rtp_transport_ || !rtp_transport_->IsWritable(rtcp)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000432 return false;
433 }
434
435 // Protect ourselves against crazy data.
436 if (!ValidPacket(rtcp, packet)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100437 RTC_LOG(LS_ERROR) << "Dropping outgoing " << content_name_ << " "
438 << RtpRtcpStringLiteral(rtcp)
439 << " packet: wrong size=" << packet->size();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000440 return false;
441 }
442
Zhi Huangcf990f52017-09-22 12:12:30 -0700443 if (!srtp_active()) {
444 if (srtp_required_) {
445 // The audio/video engines may attempt to send RTCP packets as soon as the
446 // streams are created, so don't treat this as an error for RTCP.
447 // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=6809
448 if (rtcp) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000449 return false;
450 }
Zhi Huangcf990f52017-09-22 12:12:30 -0700451 // However, there shouldn't be any RTP packets sent before SRTP is set up
452 // (and SetSend(true) is called).
Mirko Bonadei675513b2017-11-09 11:09:25 +0100453 RTC_LOG(LS_ERROR)
454 << "Can't send outgoing RTP packet when SRTP is inactive"
455 << " and crypto is required";
Zhi Huangcf990f52017-09-22 12:12:30 -0700456 RTC_NOTREACHED();
deadbeef8f425f92016-12-01 12:26:27 -0800457 return false;
458 }
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800459
460 std::string packet_type = rtcp ? "RTCP" : "RTP";
461 RTC_LOG(LS_WARNING) << "Sending an " << packet_type
462 << " packet without encryption.";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000463 }
Zhi Huange830e682018-03-30 10:48:35 -0700464
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000465 // Bon voyage.
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800466 return rtcp ? rtp_transport_->SendRtcpPacket(packet, options, PF_SRTP_BYPASS)
467 : rtp_transport_->SendRtpPacket(packet, options, PF_SRTP_BYPASS);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000468}
469
Zhi Huang365381f2018-04-13 16:44:34 -0700470void BaseChannel::OnRtpPacket(const webrtc::RtpPacketReceived& parsed_packet) {
Niels Möller29e13fd2018-12-17 12:35:30 +0100471 // Take packet time from the |parsed_packet|.
472 // RtpPacketReceived.arrival_time_ms = (timestamp_us + 500) / 1000;
Niels Möllere6933812018-11-05 13:01:41 +0100473 int64_t timestamp_us = -1;
Zhi Huang365381f2018-04-13 16:44:34 -0700474 if (parsed_packet.arrival_time_ms() > 0) {
Niels Möllere6933812018-11-05 13:01:41 +0100475 timestamp_us = parsed_packet.arrival_time_ms() * 1000;
Zhi Huang365381f2018-04-13 16:44:34 -0700476 }
Zhi Huang365381f2018-04-13 16:44:34 -0700477
Niels Möllere6933812018-11-05 13:01:41 +0100478 OnPacketReceived(/*rtcp=*/false, parsed_packet.Buffer(), timestamp_us);
Zhi Huang365381f2018-04-13 16:44:34 -0700479}
480
481void BaseChannel::UpdateRtpHeaderExtensionMap(
482 const RtpHeaderExtensions& header_extensions) {
483 RTC_DCHECK(rtp_transport_);
484 // Update the header extension map on network thread in case there is data
485 // race.
486 // TODO(zhihuang): Add an rtc::ThreadChecker make sure to RtpTransport won't
487 // be accessed from different threads.
488 //
489 // NOTE: This doesn't take the BUNDLE case in account meaning the RTP header
490 // extension maps are not merged when BUNDLE is enabled. This is fine because
491 // the ID for MID should be consistent among all the RTP transports.
492 network_thread_->Invoke<void>(RTC_FROM_HERE, [this, &header_extensions] {
493 rtp_transport_->UpdateRtpHeaderExtensionMap(header_extensions);
494 });
495}
496
497bool BaseChannel::RegisterRtpDemuxerSink() {
498 RTC_DCHECK(rtp_transport_);
499 return network_thread_->Invoke<bool>(RTC_FROM_HERE, [this] {
500 return rtp_transport_->RegisterRtpDemuxerSink(demuxer_criteria_, this);
501 });
502}
503
504void BaseChannel::OnRtcpPacketReceived(rtc::CopyOnWriteBuffer* packet,
Niels Möllere6933812018-11-05 13:01:41 +0100505 int64_t packet_time_us) {
506 OnPacketReceived(/*rtcp=*/true, *packet, packet_time_us);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000507}
508
zstein3dcf0e92017-06-01 13:22:42 -0700509void BaseChannel::OnPacketReceived(bool rtcp,
Zhi Huang365381f2018-04-13 16:44:34 -0700510 const rtc::CopyOnWriteBuffer& packet,
Niels Möllere6933812018-11-05 13:01:41 +0100511 int64_t packet_time_us) {
honghaiz@google.coma67ca1a2015-01-28 19:48:33 +0000512 if (!has_received_packet_ && !rtcp) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000513 has_received_packet_ = true;
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700514 signaling_thread()->Post(RTC_FROM_HERE, this, MSG_FIRSTPACKETRECEIVED);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000515 }
516
Zhi Huangcf990f52017-09-22 12:12:30 -0700517 if (!srtp_active() && srtp_required_) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000518 // Our session description indicates that SRTP is required, but we got a
519 // packet before our SRTP filter is active. This means either that
520 // a) we got SRTP packets before we received the SDES keys, in which case
521 // we can't decrypt it anyway, or
522 // b) we got SRTP packets before DTLS completed on both the RTP and RTCP
zhihuangb2cdd932017-01-19 16:54:25 -0800523 // transports, so we haven't yet extracted keys, even if DTLS did
524 // complete on the transport that the packets are being sent on. It's
525 // really good practice to wait for both RTP and RTCP to be good to go
526 // before sending media, to prevent weird failure modes, so it's fine
527 // for us to just eat packets here. This is all sidestepped if RTCP mux
528 // is used anyway.
Mirko Bonadei675513b2017-11-09 11:09:25 +0100529 RTC_LOG(LS_WARNING)
530 << "Can't process incoming " << RtpRtcpStringLiteral(rtcp)
531 << " packet when SRTP is inactive and crypto is required";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000532 return;
533 }
534
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200535 invoker_.AsyncInvoke<void>(
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700536 RTC_FROM_HERE, worker_thread_,
Niels Möllere6933812018-11-05 13:01:41 +0100537 Bind(&BaseChannel::ProcessPacket, this, rtcp, packet, packet_time_us));
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200538}
539
zstein3dcf0e92017-06-01 13:22:42 -0700540void BaseChannel::ProcessPacket(bool rtcp,
541 const rtc::CopyOnWriteBuffer& packet,
Niels Möllere6933812018-11-05 13:01:41 +0100542 int64_t packet_time_us) {
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200543 RTC_DCHECK(worker_thread_->IsCurrent());
zstein3dcf0e92017-06-01 13:22:42 -0700544
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200545 // Need to copy variable because OnRtcpReceived/OnPacketReceived
546 // requires non-const pointer to buffer. This doesn't memcpy the actual data.
547 rtc::CopyOnWriteBuffer data(packet);
548 if (rtcp) {
Niels Möllere6933812018-11-05 13:01:41 +0100549 media_channel_->OnRtcpReceived(&data, packet_time_us);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000550 } else {
Niels Möllere6933812018-11-05 13:01:41 +0100551 media_channel_->OnPacketReceived(&data, packet_time_us);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000552 }
553}
554
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000555void BaseChannel::EnableMedia_w() {
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700556 RTC_DCHECK(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000557 if (enabled_)
558 return;
559
Mirko Bonadei675513b2017-11-09 11:09:25 +0100560 RTC_LOG(LS_INFO) << "Channel enabled";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000561 enabled_ = true;
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700562 UpdateMediaSendRecvState_w();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000563}
564
565void BaseChannel::DisableMedia_w() {
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700566 RTC_DCHECK(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000567 if (!enabled_)
568 return;
569
Mirko Bonadei675513b2017-11-09 11:09:25 +0100570 RTC_LOG(LS_INFO) << "Channel disabled";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000571 enabled_ = false;
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700572 UpdateMediaSendRecvState_w();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000573}
574
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200575void BaseChannel::UpdateWritableState_n() {
Zhi Huange830e682018-03-30 10:48:35 -0700576 if (rtp_transport_->IsWritable(/*rtcp=*/true) &&
577 rtp_transport_->IsWritable(/*rtcp=*/false)) {
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200578 ChannelWritable_n();
deadbeefcbecd352015-09-23 11:50:27 -0700579 } else {
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200580 ChannelNotWritable_n();
deadbeefcbecd352015-09-23 11:50:27 -0700581 }
582}
583
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200584void BaseChannel::ChannelWritable_n() {
585 RTC_DCHECK(network_thread_->IsCurrent());
Guo-wei Shieh1218d7a2015-12-05 09:59:56 -0800586 if (writable_) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000587 return;
Guo-wei Shieh1218d7a2015-12-05 09:59:56 -0800588 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000589
Mirko Bonadei675513b2017-11-09 11:09:25 +0100590 RTC_LOG(LS_INFO) << "Channel writable (" << content_name_ << ")"
591 << (was_ever_writable_ ? "" : " for the first time");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000592
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000593 was_ever_writable_ = true;
594 writable_ = true;
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700595 UpdateMediaSendRecvState();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000596}
597
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200598void BaseChannel::ChannelNotWritable_n() {
599 RTC_DCHECK(network_thread_->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000600 if (!writable_)
601 return;
602
Mirko Bonadei675513b2017-11-09 11:09:25 +0100603 RTC_LOG(LS_INFO) << "Channel not writable (" << content_name_ << ")";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000604 writable_ = false;
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700605 UpdateMediaSendRecvState();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000606}
607
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000608bool BaseChannel::AddRecvStream_w(const StreamParams& sp) {
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700609 RTC_DCHECK(worker_thread() == rtc::Thread::Current());
pbos482b12e2015-11-16 10:19:58 -0800610 return media_channel()->AddRecvStream(sp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000611}
612
Peter Boström0c4e06b2015-10-07 12:23:21 +0200613bool BaseChannel::RemoveRecvStream_w(uint32_t ssrc) {
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700614 RTC_DCHECK(worker_thread() == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000615 return media_channel()->RemoveRecvStream(ssrc);
616}
617
618bool BaseChannel::UpdateLocalStreams_w(const std::vector<StreamParams>& streams,
Steve Anton3828c062017-12-06 10:34:51 -0800619 SdpType type,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000620 std::string* error_desc) {
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800621 // In the case of RIDs (where SSRCs are not negotiated), this method will
622 // generate an SSRC for each layer in StreamParams. That representation will
623 // be stored internally in |local_streams_|.
624 // In subsequent offers, the same stream can appear in |streams| again
625 // (without the SSRCs), so it should be looked up using RIDs (if available)
626 // and then by primary SSRC.
627 // In both scenarios, it is safe to assume that the media channel will be
628 // created with a StreamParams object with SSRCs. However, it is not safe to
629 // assume that |local_streams_| will always have SSRCs as there are scenarios
630 // in which niether SSRCs or RIDs are negotiated.
631
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000632 // Check for streams that have been removed.
633 bool ret = true;
Steve Anton5f8b5fd2018-12-27 16:58:10 -0800634 for (const StreamParams& old_stream : local_streams_) {
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800635 if (!old_stream.has_ssrcs() ||
636 GetStream(streams, StreamFinder(&old_stream))) {
637 continue;
638 }
639 if (!media_channel()->RemoveSendStream(old_stream.first_ssrc())) {
640 rtc::StringBuilder desc;
641 desc << "Failed to remove send stream with ssrc "
642 << old_stream.first_ssrc() << ".";
643 SafeSetError(desc.str(), error_desc);
644 ret = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000645 }
646 }
647 // Check for new streams.
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800648 std::vector<StreamParams> all_streams;
649 for (const StreamParams& stream : streams) {
650 StreamParams* existing = GetStream(local_streams_, StreamFinder(&stream));
651 if (existing) {
652 // Parameters cannot change for an existing stream.
653 all_streams.push_back(*existing);
654 continue;
655 }
656
657 all_streams.push_back(stream);
658 StreamParams& new_stream = all_streams.back();
659
660 if (!new_stream.has_ssrcs() && !new_stream.has_rids()) {
661 continue;
662 }
663
664 RTC_DCHECK(new_stream.has_ssrcs() || new_stream.has_rids());
665 if (new_stream.has_ssrcs() && new_stream.has_rids()) {
666 rtc::StringBuilder desc;
667 desc << "Failed to add send stream: " << new_stream.first_ssrc()
668 << ". Stream has both SSRCs and RIDs.";
669 SafeSetError(desc.str(), error_desc);
670 ret = false;
671 continue;
672 }
673
674 // At this point we use the legacy simulcast group in StreamParams to
675 // indicate that we want multiple layers to the media channel.
676 if (!new_stream.has_ssrcs()) {
677 // TODO(bugs.webrtc.org/10250): Indicate if flex is desired here.
678 new_stream.GenerateSsrcs(new_stream.rids().size(), /* rtx = */ true,
679 /* flex_fec = */ false, ssrc_generator_);
680 }
681
682 if (media_channel()->AddSendStream(new_stream)) {
683 RTC_LOG(LS_INFO) << "Add send stream ssrc: " << new_stream.ssrcs[0];
684 } else {
685 rtc::StringBuilder desc;
686 desc << "Failed to add send stream ssrc: " << new_stream.first_ssrc();
687 SafeSetError(desc.str(), error_desc);
688 ret = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000689 }
690 }
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800691 local_streams_ = all_streams;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000692 return ret;
693}
694
695bool BaseChannel::UpdateRemoteStreams_w(
696 const std::vector<StreamParams>& streams,
Steve Anton3828c062017-12-06 10:34:51 -0800697 SdpType type,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000698 std::string* error_desc) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000699 // Check for streams that have been removed.
700 bool ret = true;
Steve Anton5f8b5fd2018-12-27 16:58:10 -0800701 for (const StreamParams& old_stream : remote_streams_) {
Seth Hampson5897a6e2018-04-03 11:16:33 -0700702 // If we no longer have an unsignaled stream, we would like to remove
703 // the unsignaled stream params that are cached.
Steve Anton5f8b5fd2018-12-27 16:58:10 -0800704 if ((!old_stream.has_ssrcs() && !HasStreamWithNoSsrcs(streams)) ||
705 !GetStreamBySsrc(streams, old_stream.first_ssrc())) {
706 if (RemoveRecvStream_w(old_stream.first_ssrc())) {
707 RTC_LOG(LS_INFO) << "Remove remote ssrc: " << old_stream.first_ssrc();
Zhi Huang365381f2018-04-13 16:44:34 -0700708 } else {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200709 rtc::StringBuilder desc;
Steve Anton5f8b5fd2018-12-27 16:58:10 -0800710 desc << "Failed to remove remote stream with ssrc "
711 << old_stream.first_ssrc() << ".";
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000712 SafeSetError(desc.str(), error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000713 ret = false;
714 }
715 }
716 }
Zhi Huang365381f2018-04-13 16:44:34 -0700717 demuxer_criteria_.ssrcs.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000718 // Check for new streams.
Steve Anton5f8b5fd2018-12-27 16:58:10 -0800719 for (const StreamParams& new_stream : streams) {
Seth Hampson5897a6e2018-04-03 11:16:33 -0700720 // We allow a StreamParams with an empty list of SSRCs, in which case the
721 // MediaChannel will cache the parameters and use them for any unsignaled
722 // stream received later.
Steve Anton5f8b5fd2018-12-27 16:58:10 -0800723 if ((!new_stream.has_ssrcs() && !HasStreamWithNoSsrcs(remote_streams_)) ||
724 !GetStreamBySsrc(remote_streams_, new_stream.first_ssrc())) {
725 if (AddRecvStream_w(new_stream)) {
726 RTC_LOG(LS_INFO) << "Add remote ssrc: " << new_stream.first_ssrc();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000727 } else {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200728 rtc::StringBuilder desc;
Steve Anton5f8b5fd2018-12-27 16:58:10 -0800729 desc << "Failed to add remote stream ssrc: " << new_stream.first_ssrc();
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000730 SafeSetError(desc.str(), error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000731 ret = false;
732 }
733 }
Zhi Huang365381f2018-04-13 16:44:34 -0700734 // Update the receiving SSRCs.
Steve Anton5f8b5fd2018-12-27 16:58:10 -0800735 demuxer_criteria_.ssrcs.insert(new_stream.ssrcs.begin(),
736 new_stream.ssrcs.end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000737 }
Zhi Huang365381f2018-04-13 16:44:34 -0700738 // Re-register the sink to update the receiving ssrcs.
739 RegisterRtpDemuxerSink();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000740 remote_streams_ = streams;
741 return ret;
742}
743
jbauch5869f502017-06-29 12:31:36 -0700744RtpHeaderExtensions BaseChannel::GetFilteredRtpHeaderExtensions(
745 const RtpHeaderExtensions& extensions) {
Zhi Huange830e682018-03-30 10:48:35 -0700746 RTC_DCHECK(rtp_transport_);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700747 if (crypto_options_.srtp.enable_encrypted_rtp_header_extensions) {
jbauch5869f502017-06-29 12:31:36 -0700748 RtpHeaderExtensions filtered;
749 auto pred = [](const webrtc::RtpExtension& extension) {
Yves Gerey665174f2018-06-19 15:03:05 +0200750 return !extension.encrypt;
jbauch5869f502017-06-29 12:31:36 -0700751 };
752 std::copy_if(extensions.begin(), extensions.end(),
Yves Gerey665174f2018-06-19 15:03:05 +0200753 std::back_inserter(filtered), pred);
jbauch5869f502017-06-29 12:31:36 -0700754 return filtered;
755 }
756
757 return webrtc::RtpExtension::FilterDuplicateNonEncrypted(extensions);
758}
759
Yves Gerey665174f2018-06-19 15:03:05 +0200760void BaseChannel::OnMessage(rtc::Message* pmsg) {
Peter Boström6f28cf02015-12-07 23:17:15 +0100761 TRACE_EVENT0("webrtc", "BaseChannel::OnMessage");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000762 switch (pmsg->message_id) {
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200763 case MSG_SEND_RTP_PACKET:
764 case MSG_SEND_RTCP_PACKET: {
765 RTC_DCHECK(network_thread_->IsCurrent());
766 SendPacketMessageData* data =
767 static_cast<SendPacketMessageData*>(pmsg->pdata);
768 bool rtcp = pmsg->message_id == MSG_SEND_RTCP_PACKET;
769 SendPacket(rtcp, &data->packet, data->options);
770 delete data;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000771 break;
772 }
773 case MSG_FIRSTPACKETRECEIVED: {
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800774 SignalFirstPacketReceived_(this);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000775 break;
776 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000777 }
778}
779
zstein3dcf0e92017-06-01 13:22:42 -0700780void BaseChannel::AddHandledPayloadType(int payload_type) {
Zhi Huang365381f2018-04-13 16:44:34 -0700781 demuxer_criteria_.payload_types.insert(static_cast<uint8_t>(payload_type));
zstein3dcf0e92017-06-01 13:22:42 -0700782}
783
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200784void BaseChannel::FlushRtcpMessages_n() {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000785 // Flush all remaining RTCP messages. This should only be called in
786 // destructor.
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200787 RTC_DCHECK(network_thread_->IsCurrent());
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000788 rtc::MessageList rtcp_messages;
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200789 network_thread_->Clear(this, MSG_SEND_RTCP_PACKET, &rtcp_messages);
790 for (const auto& message : rtcp_messages) {
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700791 network_thread_->Send(RTC_FROM_HERE, this, MSG_SEND_RTCP_PACKET,
792 message.pdata);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000793 }
794}
795
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800796void BaseChannel::SignalSentPacket_n(const rtc::SentPacket& sent_packet) {
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200797 RTC_DCHECK(network_thread_->IsCurrent());
798 invoker_.AsyncInvoke<void>(
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700799 RTC_FROM_HERE, worker_thread_,
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200800 rtc::Bind(&BaseChannel::SignalSentPacket_w, this, sent_packet));
801}
802
803void BaseChannel::SignalSentPacket_w(const rtc::SentPacket& sent_packet) {
804 RTC_DCHECK(worker_thread_->IsCurrent());
805 SignalSentPacket(sent_packet);
806}
807
808VoiceChannel::VoiceChannel(rtc::Thread* worker_thread,
809 rtc::Thread* network_thread,
zhihuangf5b251b2017-01-12 19:37:48 -0800810 rtc::Thread* signaling_thread,
Steve Anton8699a322017-11-06 15:53:33 -0800811 std::unique_ptr<VoiceMediaChannel> media_channel,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000812 const std::string& content_name,
Zhi Huange830e682018-03-30 10:48:35 -0700813 bool srtp_required,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800814 webrtc::CryptoOptions crypto_options,
815 UniqueRandomIdGenerator* ssrc_generator)
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200816 : BaseChannel(worker_thread,
817 network_thread,
zhihuangf5b251b2017-01-12 19:37:48 -0800818 signaling_thread,
Steve Anton8699a322017-11-06 15:53:33 -0800819 std::move(media_channel),
deadbeefcbecd352015-09-23 11:50:27 -0700820 content_name,
Zhi Huange830e682018-03-30 10:48:35 -0700821 srtp_required,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800822 crypto_options,
823 ssrc_generator) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000824
825VoiceChannel::~VoiceChannel() {
Piotr (Peter) Slatala309aafe2019-01-15 14:24:34 -0800826 if (media_transport()) {
827 media_transport()->SetFirstAudioPacketReceivedObserver(nullptr);
828 }
Peter Boströmca8b4042016-03-08 14:24:13 -0800829 TRACE_EVENT0("webrtc", "VoiceChannel::~VoiceChannel");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000830 // this can't be done in the base class, since it calls a virtual
831 DisableMedia_w();
Zhi Huang0ffe03d2018-03-30 13:17:42 -0700832 Deinit();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000833}
834
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700835void BaseChannel::UpdateMediaSendRecvState() {
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200836 RTC_DCHECK(network_thread_->IsCurrent());
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700837 invoker_.AsyncInvoke<void>(
838 RTC_FROM_HERE, worker_thread_,
839 Bind(&BaseChannel::UpdateMediaSendRecvState_w, this));
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200840}
841
Piotr (Peter) Slatala179a3922018-11-16 09:57:58 -0800842void BaseChannel::OnNetworkRouteChanged(
843 const rtc::NetworkRoute& network_route) {
844 OnNetworkRouteChanged(absl::make_optional(network_route));
845}
846
Piotr (Peter) Slatala309aafe2019-01-15 14:24:34 -0800847void VoiceChannel::Init_w(webrtc::RtpTransportInternal* rtp_transport,
848 webrtc::MediaTransportInterface* media_transport) {
849 BaseChannel::Init_w(rtp_transport, media_transport);
850 if (BaseChannel::media_transport()) {
851 this->media_transport()->SetFirstAudioPacketReceivedObserver(this);
852 }
853}
854
855void VoiceChannel::OnFirstAudioPacketReceived(int64_t channel_id) {
856 has_received_packet_ = true;
857 signaling_thread()->Post(RTC_FROM_HERE, this, MSG_FIRSTPACKETRECEIVED);
858}
859
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700860void VoiceChannel::UpdateMediaSendRecvState_w() {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000861 // Render incoming data if we're the active call, and we have the local
862 // content. We receive data on the default channel and multiplexed streams.
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700863 bool recv = IsReadyToReceiveMedia_w();
solenberg5b14b422015-10-01 04:10:31 -0700864 media_channel()->SetPlayout(recv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000865
866 // Send outgoing data if we're the active call, we have the remote content,
867 // and we have had some form of connectivity.
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700868 bool send = IsReadyToSendMedia_w();
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800869 media_channel()->SetSend(send);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000870
Mirko Bonadei675513b2017-11-09 11:09:25 +0100871 RTC_LOG(LS_INFO) << "Changing voice state, recv=" << recv << " send=" << send;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000872}
873
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000874bool VoiceChannel::SetLocalContent_w(const MediaContentDescription* content,
Steve Anton3828c062017-12-06 10:34:51 -0800875 SdpType type,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000876 std::string* error_desc) {
Peter Boström9f45a452015-12-08 13:25:57 +0100877 TRACE_EVENT0("webrtc", "VoiceChannel::SetLocalContent_w");
Steve Antonb1c1de12017-12-21 15:14:30 -0800878 RTC_DCHECK_RUN_ON(worker_thread());
Mirko Bonadei675513b2017-11-09 11:09:25 +0100879 RTC_LOG(LS_INFO) << "Setting local voice description";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000880
Steve Antonb1c1de12017-12-21 15:14:30 -0800881 RTC_DCHECK(content);
882 if (!content) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000883 SafeSetError("Can't find audio content in local description.", error_desc);
884 return false;
885 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000886
Steve Antonb1c1de12017-12-21 15:14:30 -0800887 const AudioContentDescription* audio = content->as_audio();
888
jbauch5869f502017-06-29 12:31:36 -0700889 RtpHeaderExtensions rtp_header_extensions =
890 GetFilteredRtpHeaderExtensions(audio->rtp_header_extensions());
Zhi Huang365381f2018-04-13 16:44:34 -0700891 UpdateRtpHeaderExtensionMap(rtp_header_extensions);
Johannes Kron9190b822018-10-29 11:22:05 +0100892 media_channel()->SetExtmapAllowMixed(audio->extmap_allow_mixed());
jbauch5869f502017-06-29 12:31:36 -0700893
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700894 AudioRecvParameters recv_params = last_recv_params_;
jbauch5869f502017-06-29 12:31:36 -0700895 RtpParametersFromMediaDescription(audio, rtp_header_extensions, &recv_params);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700896 if (!media_channel()->SetRecvParameters(recv_params)) {
Peter Thatcherbfab5cb2015-08-20 17:40:24 -0700897 SafeSetError("Failed to set local audio description recv parameters.",
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700898 error_desc);
899 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000900 }
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700901 for (const AudioCodec& codec : audio->codecs()) {
zstein3dcf0e92017-06-01 13:22:42 -0700902 AddHandledPayloadType(codec.id);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700903 }
Zhi Huang365381f2018-04-13 16:44:34 -0700904 // Need to re-register the sink to update the handled payload.
905 if (!RegisterRtpDemuxerSink()) {
906 RTC_LOG(LS_ERROR) << "Failed to set up audio demuxing.";
907 return false;
908 }
909
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700910 last_recv_params_ = recv_params;
911
912 // TODO(pthatcher): Move local streams into AudioSendParameters, and
913 // only give it to the media channel once we have a remote
914 // description too (without a remote description, we won't be able
915 // to send them anyway).
Steve Anton3828c062017-12-06 10:34:51 -0800916 if (!UpdateLocalStreams_w(audio->streams(), type, error_desc)) {
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700917 SafeSetError("Failed to set local audio description streams.", error_desc);
918 return false;
919 }
920
921 set_local_content_direction(content->direction());
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700922 UpdateMediaSendRecvState_w();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700923 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000924}
925
926bool VoiceChannel::SetRemoteContent_w(const MediaContentDescription* content,
Steve Anton3828c062017-12-06 10:34:51 -0800927 SdpType type,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000928 std::string* error_desc) {
Peter Boström9f45a452015-12-08 13:25:57 +0100929 TRACE_EVENT0("webrtc", "VoiceChannel::SetRemoteContent_w");
Steve Antonb1c1de12017-12-21 15:14:30 -0800930 RTC_DCHECK_RUN_ON(worker_thread());
Mirko Bonadei675513b2017-11-09 11:09:25 +0100931 RTC_LOG(LS_INFO) << "Setting remote voice description";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000932
Steve Antonb1c1de12017-12-21 15:14:30 -0800933 RTC_DCHECK(content);
934 if (!content) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000935 SafeSetError("Can't find audio content in remote description.", error_desc);
936 return false;
937 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000938
Steve Antonb1c1de12017-12-21 15:14:30 -0800939 const AudioContentDescription* audio = content->as_audio();
940
jbauch5869f502017-06-29 12:31:36 -0700941 RtpHeaderExtensions rtp_header_extensions =
942 GetFilteredRtpHeaderExtensions(audio->rtp_header_extensions());
943
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700944 AudioSendParameters send_params = last_send_params_;
jbauch5869f502017-06-29 12:31:36 -0700945 RtpSendParametersFromMediaDescription(audio, rtp_header_extensions,
Yves Gerey665174f2018-06-19 15:03:05 +0200946 &send_params);
Steve Antonbb50ce52018-03-26 10:24:32 -0700947 send_params.mid = content_name();
skvladdc1c62c2016-03-16 19:07:43 -0700948
949 bool parameters_applied = media_channel()->SetSendParameters(send_params);
950 if (!parameters_applied) {
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700951 SafeSetError("Failed to set remote audio description send parameters.",
952 error_desc);
953 return false;
954 }
955 last_send_params_ = send_params;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000956
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700957 // TODO(pthatcher): Move remote streams into AudioRecvParameters,
958 // and only give it to the media channel once we have a local
959 // description too (without a local description, we won't be able to
960 // recv them anyway).
Steve Anton3828c062017-12-06 10:34:51 -0800961 if (!UpdateRemoteStreams_w(audio->streams(), type, error_desc)) {
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700962 SafeSetError("Failed to set remote audio description streams.", error_desc);
963 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000964 }
965
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700966 set_remote_content_direction(content->direction());
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700967 UpdateMediaSendRecvState_w();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700968 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000969}
970
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200971VideoChannel::VideoChannel(rtc::Thread* worker_thread,
972 rtc::Thread* network_thread,
zhihuangf5b251b2017-01-12 19:37:48 -0800973 rtc::Thread* signaling_thread,
Steve Anton8699a322017-11-06 15:53:33 -0800974 std::unique_ptr<VideoMediaChannel> media_channel,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000975 const std::string& content_name,
Zhi Huange830e682018-03-30 10:48:35 -0700976 bool srtp_required,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800977 webrtc::CryptoOptions crypto_options,
978 UniqueRandomIdGenerator* ssrc_generator)
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200979 : BaseChannel(worker_thread,
980 network_thread,
zhihuangf5b251b2017-01-12 19:37:48 -0800981 signaling_thread,
Steve Anton8699a322017-11-06 15:53:33 -0800982 std::move(media_channel),
deadbeefcbecd352015-09-23 11:50:27 -0700983 content_name,
Zhi Huange830e682018-03-30 10:48:35 -0700984 srtp_required,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800985 crypto_options,
986 ssrc_generator) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000987
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000988VideoChannel::~VideoChannel() {
Peter Boströmca8b4042016-03-08 14:24:13 -0800989 TRACE_EVENT0("webrtc", "VideoChannel::~VideoChannel");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000990 // this can't be done in the base class, since it calls a virtual
991 DisableMedia_w();
Zhi Huang0ffe03d2018-03-30 13:17:42 -0700992 Deinit();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000993}
994
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700995void VideoChannel::UpdateMediaSendRecvState_w() {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000996 // Send outgoing data if we're the active call, we have the remote content,
997 // and we have had some form of connectivity.
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -0700998 bool send = IsReadyToSendMedia_w();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000999 if (!media_channel()->SetSend(send)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001000 RTC_LOG(LS_ERROR) << "Failed to SetSend on video channel";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001001 // TODO(gangji): Report error back to server.
1002 }
1003
Mirko Bonadei675513b2017-11-09 11:09:25 +01001004 RTC_LOG(LS_INFO) << "Changing video state, send=" << send;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001005}
1006
stefanf79ade12017-06-02 06:44:03 -07001007void VideoChannel::FillBitrateInfo(BandwidthEstimationInfo* bwe_info) {
1008 InvokeOnWorker<void>(RTC_FROM_HERE, Bind(&VideoMediaChannel::FillBitrateInfo,
1009 media_channel(), bwe_info));
1010}
1011
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001012bool VideoChannel::SetLocalContent_w(const MediaContentDescription* content,
Steve Anton3828c062017-12-06 10:34:51 -08001013 SdpType type,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001014 std::string* error_desc) {
Peter Boström9f45a452015-12-08 13:25:57 +01001015 TRACE_EVENT0("webrtc", "VideoChannel::SetLocalContent_w");
Steve Antonb1c1de12017-12-21 15:14:30 -08001016 RTC_DCHECK_RUN_ON(worker_thread());
Mirko Bonadei675513b2017-11-09 11:09:25 +01001017 RTC_LOG(LS_INFO) << "Setting local video description";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001018
Steve Antonb1c1de12017-12-21 15:14:30 -08001019 RTC_DCHECK(content);
1020 if (!content) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001021 SafeSetError("Can't find video content in local description.", error_desc);
1022 return false;
1023 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001024
Steve Antonb1c1de12017-12-21 15:14:30 -08001025 const VideoContentDescription* video = content->as_video();
1026
jbauch5869f502017-06-29 12:31:36 -07001027 RtpHeaderExtensions rtp_header_extensions =
1028 GetFilteredRtpHeaderExtensions(video->rtp_header_extensions());
Zhi Huang365381f2018-04-13 16:44:34 -07001029 UpdateRtpHeaderExtensionMap(rtp_header_extensions);
Johannes Kron9190b822018-10-29 11:22:05 +01001030 media_channel()->SetExtmapAllowMixed(video->extmap_allow_mixed());
jbauch5869f502017-06-29 12:31:36 -07001031
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001032 VideoRecvParameters recv_params = last_recv_params_;
jbauch5869f502017-06-29 12:31:36 -07001033 RtpParametersFromMediaDescription(video, rtp_header_extensions, &recv_params);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001034 if (!media_channel()->SetRecvParameters(recv_params)) {
1035 SafeSetError("Failed to set local video description recv parameters.",
1036 error_desc);
1037 return false;
1038 }
1039 for (const VideoCodec& codec : video->codecs()) {
zstein3dcf0e92017-06-01 13:22:42 -07001040 AddHandledPayloadType(codec.id);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001041 }
Zhi Huang365381f2018-04-13 16:44:34 -07001042 // Need to re-register the sink to update the handled payload.
1043 if (!RegisterRtpDemuxerSink()) {
1044 RTC_LOG(LS_ERROR) << "Failed to set up video demuxing.";
1045 return false;
1046 }
1047
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001048 last_recv_params_ = recv_params;
1049
1050 // TODO(pthatcher): Move local streams into VideoSendParameters, and
1051 // only give it to the media channel once we have a remote
1052 // description too (without a remote description, we won't be able
1053 // to send them anyway).
Steve Anton3828c062017-12-06 10:34:51 -08001054 if (!UpdateLocalStreams_w(video->streams(), type, error_desc)) {
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001055 SafeSetError("Failed to set local video description streams.", error_desc);
1056 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001057 }
1058
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001059 set_local_content_direction(content->direction());
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -07001060 UpdateMediaSendRecvState_w();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001061 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001062}
1063
1064bool VideoChannel::SetRemoteContent_w(const MediaContentDescription* content,
Steve Anton3828c062017-12-06 10:34:51 -08001065 SdpType type,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001066 std::string* error_desc) {
Peter Boström9f45a452015-12-08 13:25:57 +01001067 TRACE_EVENT0("webrtc", "VideoChannel::SetRemoteContent_w");
Steve Antonb1c1de12017-12-21 15:14:30 -08001068 RTC_DCHECK_RUN_ON(worker_thread());
Mirko Bonadei675513b2017-11-09 11:09:25 +01001069 RTC_LOG(LS_INFO) << "Setting remote video description";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001070
Steve Antonb1c1de12017-12-21 15:14:30 -08001071 RTC_DCHECK(content);
1072 if (!content) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001073 SafeSetError("Can't find video content in remote description.", error_desc);
1074 return false;
1075 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001076
Steve Antonb1c1de12017-12-21 15:14:30 -08001077 const VideoContentDescription* video = content->as_video();
1078
jbauch5869f502017-06-29 12:31:36 -07001079 RtpHeaderExtensions rtp_header_extensions =
1080 GetFilteredRtpHeaderExtensions(video->rtp_header_extensions());
1081
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001082 VideoSendParameters send_params = last_send_params_;
jbauch5869f502017-06-29 12:31:36 -07001083 RtpSendParametersFromMediaDescription(video, rtp_header_extensions,
Yves Gerey665174f2018-06-19 15:03:05 +02001084 &send_params);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001085 if (video->conference_mode()) {
nisse4b4dc862016-02-17 05:25:36 -08001086 send_params.conference_mode = true;
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001087 }
Steve Antonbb50ce52018-03-26 10:24:32 -07001088 send_params.mid = content_name();
skvladdc1c62c2016-03-16 19:07:43 -07001089
1090 bool parameters_applied = media_channel()->SetSendParameters(send_params);
1091
1092 if (!parameters_applied) {
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001093 SafeSetError("Failed to set remote video description send parameters.",
1094 error_desc);
1095 return false;
1096 }
1097 last_send_params_ = send_params;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001098
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001099 // TODO(pthatcher): Move remote streams into VideoRecvParameters,
1100 // and only give it to the media channel once we have a local
1101 // description too (without a local description, we won't be able to
1102 // recv them anyway).
Steve Anton3828c062017-12-06 10:34:51 -08001103 if (!UpdateRemoteStreams_w(video->streams(), type, error_desc)) {
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001104 SafeSetError("Failed to set remote video description streams.", error_desc);
1105 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001106 }
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001107 set_remote_content_direction(content->direction());
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -07001108 UpdateMediaSendRecvState_w();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001109 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001110}
1111
deadbeef953c2ce2017-01-09 14:53:41 -08001112RtpDataChannel::RtpDataChannel(rtc::Thread* worker_thread,
1113 rtc::Thread* network_thread,
zhihuangf5b251b2017-01-12 19:37:48 -08001114 rtc::Thread* signaling_thread,
Steve Anton8699a322017-11-06 15:53:33 -08001115 std::unique_ptr<DataMediaChannel> media_channel,
deadbeef953c2ce2017-01-09 14:53:41 -08001116 const std::string& content_name,
Zhi Huange830e682018-03-30 10:48:35 -07001117 bool srtp_required,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001118 webrtc::CryptoOptions crypto_options,
1119 UniqueRandomIdGenerator* ssrc_generator)
Danil Chapovalov33b01f22016-05-11 19:55:27 +02001120 : BaseChannel(worker_thread,
1121 network_thread,
zhihuangf5b251b2017-01-12 19:37:48 -08001122 signaling_thread,
Steve Anton8699a322017-11-06 15:53:33 -08001123 std::move(media_channel),
deadbeefcbecd352015-09-23 11:50:27 -07001124 content_name,
Zhi Huange830e682018-03-30 10:48:35 -07001125 srtp_required,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001126 crypto_options,
1127 ssrc_generator) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001128
deadbeef953c2ce2017-01-09 14:53:41 -08001129RtpDataChannel::~RtpDataChannel() {
1130 TRACE_EVENT0("webrtc", "RtpDataChannel::~RtpDataChannel");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001131 // this can't be done in the base class, since it calls a virtual
1132 DisableMedia_w();
Zhi Huang0ffe03d2018-03-30 13:17:42 -07001133 Deinit();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001134}
1135
Piotr (Peter) Slatala309aafe2019-01-15 14:24:34 -08001136void RtpDataChannel::Init_w(webrtc::RtpTransportInternal* rtp_transport,
1137 webrtc::MediaTransportInterface* media_transport) {
Anton Sukhanov98a462c2018-10-17 13:15:42 -07001138 BaseChannel::Init_w(rtp_transport, /*media_transport=*/nullptr);
Zhi Huang2dfc42d2017-12-04 13:38:48 -08001139 media_channel()->SignalDataReceived.connect(this,
1140 &RtpDataChannel::OnDataReceived);
1141 media_channel()->SignalReadyToSend.connect(
1142 this, &RtpDataChannel::OnDataChannelReadyToSend);
1143}
1144
deadbeef953c2ce2017-01-09 14:53:41 -08001145bool RtpDataChannel::SendData(const SendDataParams& params,
1146 const rtc::CopyOnWriteBuffer& payload,
1147 SendDataResult* result) {
stefanf79ade12017-06-02 06:44:03 -07001148 return InvokeOnWorker<bool>(
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -07001149 RTC_FROM_HERE, Bind(&DataMediaChannel::SendData, media_channel(), params,
1150 payload, result));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001151}
1152
deadbeef953c2ce2017-01-09 14:53:41 -08001153bool RtpDataChannel::CheckDataChannelTypeFromContent(
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001154 const DataContentDescription* content,
1155 std::string* error_desc) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001156 bool is_sctp = ((content->protocol() == kMediaProtocolSctp) ||
1157 (content->protocol() == kMediaProtocolDtlsSctp));
deadbeef953c2ce2017-01-09 14:53:41 -08001158 // It's been set before, but doesn't match. That's bad.
1159 if (is_sctp) {
1160 SafeSetError("Data channel type mismatch. Expected RTP, got SCTP.",
1161 error_desc);
1162 return false;
1163 }
1164 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001165}
1166
deadbeef953c2ce2017-01-09 14:53:41 -08001167bool RtpDataChannel::SetLocalContent_w(const MediaContentDescription* content,
Steve Anton3828c062017-12-06 10:34:51 -08001168 SdpType type,
deadbeef953c2ce2017-01-09 14:53:41 -08001169 std::string* error_desc) {
1170 TRACE_EVENT0("webrtc", "RtpDataChannel::SetLocalContent_w");
Steve Antonb1c1de12017-12-21 15:14:30 -08001171 RTC_DCHECK_RUN_ON(worker_thread());
Mirko Bonadei675513b2017-11-09 11:09:25 +01001172 RTC_LOG(LS_INFO) << "Setting local data description";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001173
Steve Antonb1c1de12017-12-21 15:14:30 -08001174 RTC_DCHECK(content);
1175 if (!content) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001176 SafeSetError("Can't find data content in local description.", error_desc);
1177 return false;
1178 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001179
Steve Antonb1c1de12017-12-21 15:14:30 -08001180 const DataContentDescription* data = content->as_data();
1181
deadbeef953c2ce2017-01-09 14:53:41 -08001182 if (!CheckDataChannelTypeFromContent(data, error_desc)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001183 return false;
1184 }
1185
jbauch5869f502017-06-29 12:31:36 -07001186 RtpHeaderExtensions rtp_header_extensions =
1187 GetFilteredRtpHeaderExtensions(data->rtp_header_extensions());
1188
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001189 DataRecvParameters recv_params = last_recv_params_;
jbauch5869f502017-06-29 12:31:36 -07001190 RtpParametersFromMediaDescription(data, rtp_header_extensions, &recv_params);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001191 if (!media_channel()->SetRecvParameters(recv_params)) {
1192 SafeSetError("Failed to set remote data description recv parameters.",
1193 error_desc);
1194 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001195 }
deadbeef953c2ce2017-01-09 14:53:41 -08001196 for (const DataCodec& codec : data->codecs()) {
zstein3dcf0e92017-06-01 13:22:42 -07001197 AddHandledPayloadType(codec.id);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001198 }
Zhi Huang365381f2018-04-13 16:44:34 -07001199 // Need to re-register the sink to update the handled payload.
1200 if (!RegisterRtpDemuxerSink()) {
1201 RTC_LOG(LS_ERROR) << "Failed to set up data demuxing.";
1202 return false;
1203 }
1204
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001205 last_recv_params_ = recv_params;
1206
1207 // TODO(pthatcher): Move local streams into DataSendParameters, and
1208 // only give it to the media channel once we have a remote
1209 // description too (without a remote description, we won't be able
1210 // to send them anyway).
Steve Anton3828c062017-12-06 10:34:51 -08001211 if (!UpdateLocalStreams_w(data->streams(), type, error_desc)) {
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001212 SafeSetError("Failed to set local data description streams.", error_desc);
1213 return false;
1214 }
1215
1216 set_local_content_direction(content->direction());
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -07001217 UpdateMediaSendRecvState_w();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001218 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001219}
1220
deadbeef953c2ce2017-01-09 14:53:41 -08001221bool RtpDataChannel::SetRemoteContent_w(const MediaContentDescription* content,
Steve Anton3828c062017-12-06 10:34:51 -08001222 SdpType type,
deadbeef953c2ce2017-01-09 14:53:41 -08001223 std::string* error_desc) {
1224 TRACE_EVENT0("webrtc", "RtpDataChannel::SetRemoteContent_w");
Steve Antonb1c1de12017-12-21 15:14:30 -08001225 RTC_DCHECK_RUN_ON(worker_thread());
1226 RTC_LOG(LS_INFO) << "Setting remote data description";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001227
Steve Antonb1c1de12017-12-21 15:14:30 -08001228 RTC_DCHECK(content);
1229 if (!content) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001230 SafeSetError("Can't find data content in remote description.", error_desc);
1231 return false;
1232 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001233
Steve Antonb1c1de12017-12-21 15:14:30 -08001234 const DataContentDescription* data = content->as_data();
1235
Zhi Huang801b8682017-11-15 11:36:43 -08001236 // If the remote data doesn't have codecs, it must be empty, so ignore it.
1237 if (!data->has_codecs()) {
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001238 return true;
1239 }
1240
deadbeef953c2ce2017-01-09 14:53:41 -08001241 if (!CheckDataChannelTypeFromContent(data, error_desc)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001242 return false;
1243 }
1244
jbauch5869f502017-06-29 12:31:36 -07001245 RtpHeaderExtensions rtp_header_extensions =
1246 GetFilteredRtpHeaderExtensions(data->rtp_header_extensions());
1247
Mirko Bonadei675513b2017-11-09 11:09:25 +01001248 RTC_LOG(LS_INFO) << "Setting remote data description";
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001249 DataSendParameters send_params = last_send_params_;
jbauch5869f502017-06-29 12:31:36 -07001250 RtpSendParametersFromMediaDescription<DataCodec>(data, rtp_header_extensions,
Yves Gerey665174f2018-06-19 15:03:05 +02001251 &send_params);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001252 if (!media_channel()->SetSendParameters(send_params)) {
1253 SafeSetError("Failed to set remote data description send parameters.",
1254 error_desc);
1255 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001256 }
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001257 last_send_params_ = send_params;
1258
1259 // TODO(pthatcher): Move remote streams into DataRecvParameters,
1260 // and only give it to the media channel once we have a local
1261 // description too (without a local description, we won't be able to
1262 // recv them anyway).
Steve Anton3828c062017-12-06 10:34:51 -08001263 if (!UpdateRemoteStreams_w(data->streams(), type, error_desc)) {
Yves Gerey665174f2018-06-19 15:03:05 +02001264 SafeSetError("Failed to set remote data description streams.", error_desc);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001265 return false;
1266 }
1267
1268 set_remote_content_direction(content->direction());
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -07001269 UpdateMediaSendRecvState_w();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001270 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001271}
1272
deadbeef953c2ce2017-01-09 14:53:41 -08001273void RtpDataChannel::UpdateMediaSendRecvState_w() {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001274 // Render incoming data if we're the active call, and we have the local
1275 // content. We receive data on the default channel and multiplexed streams.
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -07001276 bool recv = IsReadyToReceiveMedia_w();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001277 if (!media_channel()->SetReceive(recv)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001278 RTC_LOG(LS_ERROR) << "Failed to SetReceive on data channel";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001279 }
1280
1281 // Send outgoing data if we're the active call, we have the remote content,
1282 // and we have had some form of connectivity.
Taylor Brandstetterbad33bf2016-08-25 13:31:14 -07001283 bool send = IsReadyToSendMedia_w();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001284 if (!media_channel()->SetSend(send)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001285 RTC_LOG(LS_ERROR) << "Failed to SetSend on data channel";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001286 }
1287
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001288 // Trigger SignalReadyToSendData asynchronously.
1289 OnDataChannelReadyToSend(send);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001290
Mirko Bonadei675513b2017-11-09 11:09:25 +01001291 RTC_LOG(LS_INFO) << "Changing data state, recv=" << recv << " send=" << send;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001292}
1293
deadbeef953c2ce2017-01-09 14:53:41 -08001294void RtpDataChannel::OnMessage(rtc::Message* pmsg) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001295 switch (pmsg->message_id) {
1296 case MSG_READYTOSENDDATA: {
wu@webrtc.orgd64719d2013-08-01 00:00:07 +00001297 DataChannelReadyToSendMessageData* data =
1298 static_cast<DataChannelReadyToSendMessageData*>(pmsg->pdata);
wu@webrtc.org07a6fbe2013-11-04 18:41:34 +00001299 ready_to_send_data_ = data->data();
1300 SignalReadyToSendData(ready_to_send_data_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001301 delete data;
1302 break;
1303 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001304 case MSG_DATARECEIVED: {
1305 DataReceivedMessageData* data =
1306 static_cast<DataReceivedMessageData*>(pmsg->pdata);
deadbeef953c2ce2017-01-09 14:53:41 -08001307 SignalDataReceived(data->params, data->payload);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001308 delete data;
1309 break;
1310 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001311 default:
1312 BaseChannel::OnMessage(pmsg);
1313 break;
1314 }
1315}
1316
deadbeef953c2ce2017-01-09 14:53:41 -08001317void RtpDataChannel::OnDataReceived(const ReceiveDataParams& params,
1318 const char* data,
1319 size_t len) {
Yves Gerey665174f2018-06-19 15:03:05 +02001320 DataReceivedMessageData* msg = new DataReceivedMessageData(params, data, len);
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -07001321 signaling_thread()->Post(RTC_FROM_HERE, this, MSG_DATARECEIVED, msg);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001322}
1323
deadbeef953c2ce2017-01-09 14:53:41 -08001324void RtpDataChannel::OnDataChannelReadyToSend(bool writable) {
wu@webrtc.orgd64719d2013-08-01 00:00:07 +00001325 // This is usded for congestion control to indicate that the stream is ready
1326 // to send by the MediaChannel, as opposed to OnReadyToSend, which indicates
1327 // that the transport channel is ready.
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -07001328 signaling_thread()->Post(RTC_FROM_HERE, this, MSG_READYTOSENDDATA,
wu@webrtc.orgd64719d2013-08-01 00:00:07 +00001329 new DataChannelReadyToSendMessageData(writable));
1330}
1331
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001332} // namespace cricket