blob: b47676e271af6f9efb298cc324d1fb9c0553a4ea [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2004 Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "talk/session/media/channel.h"
29
buildbot@webrtc.org5b1ebac2014-08-07 17:18:00 +000030#include "talk/media/base/constants.h"
31#include "talk/media/base/rtputils.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000032#include "webrtc/p2p/base/transportchannel.h"
buildbot@webrtc.org5b1ebac2014-08-07 17:18:00 +000033#include "talk/session/media/channelmanager.h"
buildbot@webrtc.org5b1ebac2014-08-07 17:18:00 +000034#include "talk/session/media/typingmonitor.h"
buildbot@webrtc.org65b98d12014-08-07 22:09:08 +000035#include "webrtc/base/bind.h"
36#include "webrtc/base/buffer.h"
37#include "webrtc/base/byteorder.h"
38#include "webrtc/base/common.h"
39#include "webrtc/base/dscp.h"
40#include "webrtc/base/logging.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000041
42namespace cricket {
43
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000044using rtc::Bind;
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +000045
henrike@webrtc.org28e20752013-07-10 00:45:36 +000046enum {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +000047 MSG_EARLYMEDIATIMEOUT = 1,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000048 MSG_SCREENCASTWINDOWEVENT,
49 MSG_RTPPACKET,
50 MSG_RTCPPACKET,
51 MSG_CHANNEL_ERROR,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000052 MSG_READYTOSENDDATA,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000053 MSG_DATARECEIVED,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000054 MSG_FIRSTPACKETRECEIVED,
buildbot@webrtc.org1d66be22014-05-29 22:54:24 +000055 MSG_STREAMCLOSEDREMOTELY,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000056};
57
58// Value specified in RFC 5764.
59static const char kDtlsSrtpExporterLabel[] = "EXTRACTOR-dtls_srtp";
60
61static const int kAgcMinus10db = -10;
62
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +000063static void SetSessionError(BaseSession* session, BaseSession::Error error,
64 const std::string& error_desc) {
65 session->SetError(error, error_desc);
66}
67
68static void SafeSetError(const std::string& message, std::string* error_desc) {
69 if (error_desc) {
70 *error_desc = message;
71 }
72}
73
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000074struct PacketMessageData : public rtc::MessageData {
75 rtc::Buffer packet;
76 rtc::DiffServCodePoint dscp;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000077};
78
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000079struct ScreencastEventMessageData : public rtc::MessageData {
80 ScreencastEventMessageData(uint32 s, rtc::WindowEvent we)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000081 : ssrc(s),
82 event(we) {
83 }
84 uint32 ssrc;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000085 rtc::WindowEvent event;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000086};
87
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000088struct VoiceChannelErrorMessageData : public rtc::MessageData {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000089 VoiceChannelErrorMessageData(uint32 in_ssrc,
90 VoiceMediaChannel::Error in_error)
91 : ssrc(in_ssrc),
92 error(in_error) {
93 }
94 uint32 ssrc;
95 VoiceMediaChannel::Error error;
96};
97
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000098struct VideoChannelErrorMessageData : public rtc::MessageData {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000099 VideoChannelErrorMessageData(uint32 in_ssrc,
100 VideoMediaChannel::Error in_error)
101 : ssrc(in_ssrc),
102 error(in_error) {
103 }
104 uint32 ssrc;
105 VideoMediaChannel::Error error;
106};
107
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000108struct DataChannelErrorMessageData : public rtc::MessageData {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000109 DataChannelErrorMessageData(uint32 in_ssrc,
110 DataMediaChannel::Error in_error)
111 : ssrc(in_ssrc),
112 error(in_error) {}
113 uint32 ssrc;
114 DataMediaChannel::Error error;
115};
116
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000117
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000118struct VideoChannel::ScreencastDetailsData {
119 explicit ScreencastDetailsData(uint32 s)
wu@webrtc.orgcadf9042013-08-30 21:24:16 +0000120 : ssrc(s), fps(0), screencast_max_pixels(0) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000121 }
122 uint32 ssrc;
wu@webrtc.orgcadf9042013-08-30 21:24:16 +0000123 int fps;
124 int screencast_max_pixels;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000125};
126
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000127static const char* PacketType(bool rtcp) {
128 return (!rtcp) ? "RTP" : "RTCP";
129}
130
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000131static bool ValidPacket(bool rtcp, const rtc::Buffer* packet) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000132 // Check the packet size. We could check the header too if needed.
133 return (packet &&
134 packet->length() >= (!rtcp ? kMinRtpPacketLen : kMinRtcpPacketLen) &&
135 packet->length() <= kMaxRtpPacketLen);
136}
137
138static bool IsReceiveContentDirection(MediaContentDirection direction) {
139 return direction == MD_SENDRECV || direction == MD_RECVONLY;
140}
141
142static bool IsSendContentDirection(MediaContentDirection direction) {
143 return direction == MD_SENDRECV || direction == MD_SENDONLY;
144}
145
146static const MediaContentDescription* GetContentDescription(
147 const ContentInfo* cinfo) {
148 if (cinfo == NULL)
149 return NULL;
150 return static_cast<const MediaContentDescription*>(cinfo->description);
151}
152
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000153BaseChannel::BaseChannel(rtc::Thread* thread,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000154 MediaEngineInterface* media_engine,
155 MediaChannel* media_channel, BaseSession* session,
156 const std::string& content_name, bool rtcp)
157 : worker_thread_(thread),
158 media_engine_(media_engine),
159 session_(session),
160 media_channel_(media_channel),
161 content_name_(content_name),
162 rtcp_(rtcp),
163 transport_channel_(NULL),
164 rtcp_transport_channel_(NULL),
165 enabled_(false),
166 writable_(false),
167 rtp_ready_to_send_(false),
168 rtcp_ready_to_send_(false),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000169 was_ever_writable_(false),
170 local_content_direction_(MD_INACTIVE),
171 remote_content_direction_(MD_INACTIVE),
172 has_received_packet_(false),
173 dtls_keyed_(false),
henrike@webrtc.orgd43aa9d2014-02-21 23:43:24 +0000174 secure_required_(false),
175 rtp_abs_sendtime_extn_id_(-1) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000176 ASSERT(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000177 LOG(LS_INFO) << "Created channel for " << content_name;
178}
179
180BaseChannel::~BaseChannel() {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000181 ASSERT(worker_thread_ == rtc::Thread::Current());
wu@webrtc.org78187522013-10-07 23:32:02 +0000182 Deinit();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000183 StopConnectionMonitor();
184 FlushRtcpMessages(); // Send any outstanding RTCP packets.
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000185 worker_thread_->Clear(this); // eats any outstanding messages or packets
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000186 // We must destroy the media channel before the transport channel, otherwise
187 // the media channel may try to send on the dead transport channel. NULLing
188 // is not an effective strategy since the sends will come on another thread.
189 delete media_channel_;
190 set_rtcp_transport_channel(NULL);
191 if (transport_channel_ != NULL)
192 session_->DestroyChannel(content_name_, transport_channel_->component());
193 LOG(LS_INFO) << "Destroyed channel";
194}
195
196bool BaseChannel::Init(TransportChannel* transport_channel,
197 TransportChannel* rtcp_transport_channel) {
198 if (transport_channel == NULL) {
199 return false;
200 }
201 if (rtcp() && rtcp_transport_channel == NULL) {
202 return false;
203 }
204 transport_channel_ = transport_channel;
205
206 if (!SetDtlsSrtpCiphers(transport_channel_, false)) {
207 return false;
208 }
209
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000210 transport_channel_->SignalWritableState.connect(
211 this, &BaseChannel::OnWritableState);
212 transport_channel_->SignalReadPacket.connect(
213 this, &BaseChannel::OnChannelRead);
214 transport_channel_->SignalReadyToSend.connect(
215 this, &BaseChannel::OnReadyToSend);
216
217 session_->SignalNewLocalDescription.connect(
218 this, &BaseChannel::OnNewLocalDescription);
219 session_->SignalNewRemoteDescription.connect(
220 this, &BaseChannel::OnNewRemoteDescription);
221
222 set_rtcp_transport_channel(rtcp_transport_channel);
wu@webrtc.orgde305012013-10-31 15:40:38 +0000223 // Both RTP and RTCP channels are set, we can call SetInterface on
224 // media channel and it can set network options.
225 media_channel_->SetInterface(this);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000226 return true;
227}
228
wu@webrtc.org78187522013-10-07 23:32:02 +0000229void BaseChannel::Deinit() {
230 media_channel_->SetInterface(NULL);
231}
232
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000233bool BaseChannel::Enable(bool enable) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000234 worker_thread_->Invoke<void>(Bind(
235 enable ? &BaseChannel::EnableMedia_w : &BaseChannel::DisableMedia_w,
236 this));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000237 return true;
238}
239
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000240bool BaseChannel::MuteStream(uint32 ssrc, bool mute) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000241 return InvokeOnWorker(Bind(&BaseChannel::MuteStream_w, this, ssrc, mute));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000242}
243
244bool BaseChannel::IsStreamMuted(uint32 ssrc) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000245 return InvokeOnWorker(Bind(&BaseChannel::IsStreamMuted_w, this, ssrc));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000246}
247
248bool BaseChannel::AddRecvStream(const StreamParams& sp) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000249 return InvokeOnWorker(Bind(&BaseChannel::AddRecvStream_w, this, sp));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000250}
251
252bool BaseChannel::RemoveRecvStream(uint32 ssrc) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000253 return InvokeOnWorker(Bind(&BaseChannel::RemoveRecvStream_w, this, ssrc));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000254}
255
wu@webrtc.orgcadf9042013-08-30 21:24:16 +0000256bool BaseChannel::AddSendStream(const StreamParams& sp) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000257 return InvokeOnWorker(
258 Bind(&MediaChannel::AddSendStream, media_channel(), sp));
wu@webrtc.orgcadf9042013-08-30 21:24:16 +0000259}
260
261bool BaseChannel::RemoveSendStream(uint32 ssrc) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000262 return InvokeOnWorker(
263 Bind(&MediaChannel::RemoveSendStream, media_channel(), ssrc));
wu@webrtc.orgcadf9042013-08-30 21:24:16 +0000264}
265
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000266bool BaseChannel::SetLocalContent(const MediaContentDescription* content,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000267 ContentAction action,
268 std::string* error_desc) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000269 return InvokeOnWorker(Bind(&BaseChannel::SetLocalContent_w,
270 this, content, action, error_desc));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000271}
272
273bool BaseChannel::SetRemoteContent(const MediaContentDescription* content,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000274 ContentAction action,
275 std::string* error_desc) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000276 return InvokeOnWorker(Bind(&BaseChannel::SetRemoteContent_w,
277 this, content, action, error_desc));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000278}
279
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000280void BaseChannel::StartConnectionMonitor(int cms) {
281 socket_monitor_.reset(new SocketMonitor(transport_channel_,
282 worker_thread(),
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000283 rtc::Thread::Current()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000284 socket_monitor_->SignalUpdate.connect(
285 this, &BaseChannel::OnConnectionMonitorUpdate);
286 socket_monitor_->Start(cms);
287}
288
289void BaseChannel::StopConnectionMonitor() {
290 if (socket_monitor_) {
291 socket_monitor_->Stop();
292 socket_monitor_.reset();
293 }
294}
295
296void BaseChannel::set_rtcp_transport_channel(TransportChannel* channel) {
297 if (rtcp_transport_channel_ != channel) {
298 if (rtcp_transport_channel_) {
299 session_->DestroyChannel(
300 content_name_, rtcp_transport_channel_->component());
301 }
302 rtcp_transport_channel_ = channel;
303 if (rtcp_transport_channel_) {
304 // TODO(juberti): Propagate this error code
305 VERIFY(SetDtlsSrtpCiphers(rtcp_transport_channel_, true));
306 rtcp_transport_channel_->SignalWritableState.connect(
307 this, &BaseChannel::OnWritableState);
308 rtcp_transport_channel_->SignalReadPacket.connect(
309 this, &BaseChannel::OnChannelRead);
310 rtcp_transport_channel_->SignalReadyToSend.connect(
311 this, &BaseChannel::OnReadyToSend);
312 }
313 }
314}
315
316bool BaseChannel::IsReadyToReceive() const {
317 // Receive data if we are enabled and have local content,
318 return enabled() && IsReceiveContentDirection(local_content_direction_);
319}
320
321bool BaseChannel::IsReadyToSend() const {
322 // Send outgoing data if we are enabled, have local and remote content,
323 // and we have had some form of connectivity.
324 return enabled() &&
325 IsReceiveContentDirection(remote_content_direction_) &&
326 IsSendContentDirection(local_content_direction_) &&
327 was_ever_writable();
328}
329
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000330bool BaseChannel::SendPacket(rtc::Buffer* packet,
331 rtc::DiffServCodePoint dscp) {
mallinath@webrtc.org1112c302013-09-23 20:34:45 +0000332 return SendPacket(false, packet, dscp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000333}
334
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000335bool BaseChannel::SendRtcp(rtc::Buffer* packet,
336 rtc::DiffServCodePoint dscp) {
mallinath@webrtc.org1112c302013-09-23 20:34:45 +0000337 return SendPacket(true, packet, dscp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000338}
339
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000340int BaseChannel::SetOption(SocketType type, rtc::Socket::Option opt,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000341 int value) {
wu@webrtc.org9caf2762013-12-11 18:25:07 +0000342 TransportChannel* channel = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000343 switch (type) {
wu@webrtc.org9caf2762013-12-11 18:25:07 +0000344 case ST_RTP:
345 channel = transport_channel_;
346 break;
347 case ST_RTCP:
348 channel = rtcp_transport_channel_;
349 break;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000350 }
wu@webrtc.org9caf2762013-12-11 18:25:07 +0000351 return channel ? channel->SetOption(opt, value) : -1;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000352}
353
354void BaseChannel::OnWritableState(TransportChannel* channel) {
355 ASSERT(channel == transport_channel_ || channel == rtcp_transport_channel_);
356 if (transport_channel_->writable()
357 && (!rtcp_transport_channel_ || rtcp_transport_channel_->writable())) {
358 ChannelWritable_w();
359 } else {
360 ChannelNotWritable_w();
361 }
362}
363
364void BaseChannel::OnChannelRead(TransportChannel* channel,
wu@webrtc.orga9890802013-12-13 00:21:03 +0000365 const char* data, size_t len,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000366 const rtc::PacketTime& packet_time,
wu@webrtc.orga9890802013-12-13 00:21:03 +0000367 int flags) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000368 // OnChannelRead gets called from P2PSocket; now pass data to MediaEngine
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000369 ASSERT(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000370
371 // When using RTCP multiplexing we might get RTCP packets on the RTP
372 // transport. We feed RTP traffic into the demuxer to determine if it is RTCP.
373 bool rtcp = PacketIsRtcp(channel, data, len);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000374 rtc::Buffer packet(data, len);
wu@webrtc.orga9890802013-12-13 00:21:03 +0000375 HandlePacket(rtcp, &packet, packet_time);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000376}
377
378void BaseChannel::OnReadyToSend(TransportChannel* channel) {
379 SetReadyToSend(channel, true);
380}
381
382void BaseChannel::SetReadyToSend(TransportChannel* channel, bool ready) {
383 ASSERT(channel == transport_channel_ || channel == rtcp_transport_channel_);
384 if (channel == transport_channel_) {
385 rtp_ready_to_send_ = ready;
386 }
387 if (channel == rtcp_transport_channel_) {
388 rtcp_ready_to_send_ = ready;
389 }
390
391 if (!ready) {
392 // Notify the MediaChannel when either rtp or rtcp channel can't send.
393 media_channel_->OnReadyToSend(false);
394 } else if (rtp_ready_to_send_ &&
395 // In the case of rtcp mux |rtcp_transport_channel_| will be null.
396 (rtcp_ready_to_send_ || !rtcp_transport_channel_)) {
397 // Notify the MediaChannel when both rtp and rtcp channel can send.
398 media_channel_->OnReadyToSend(true);
399 }
400}
401
402bool BaseChannel::PacketIsRtcp(const TransportChannel* channel,
403 const char* data, size_t len) {
404 return (channel == rtcp_transport_channel_ ||
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000405 rtcp_mux_filter_.DemuxRtcp(data, static_cast<int>(len)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000406}
407
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000408bool BaseChannel::SendPacket(bool rtcp, rtc::Buffer* packet,
409 rtc::DiffServCodePoint dscp) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000410 // SendPacket gets called from MediaEngine, typically on an encoder thread.
411 // If the thread is not our worker thread, we will post to our worker
412 // so that the real work happens on our worker. This avoids us having to
413 // synchronize access to all the pieces of the send path, including
414 // SRTP and the inner workings of the transport channels.
415 // The only downside is that we can't return a proper failure code if
416 // needed. Since UDP is unreliable anyway, this should be a non-issue.
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000417 if (rtc::Thread::Current() != worker_thread_) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000418 // Avoid a copy by transferring the ownership of the packet data.
419 int message_id = (!rtcp) ? MSG_RTPPACKET : MSG_RTCPPACKET;
420 PacketMessageData* data = new PacketMessageData;
421 packet->TransferTo(&data->packet);
mallinath@webrtc.org1112c302013-09-23 20:34:45 +0000422 data->dscp = dscp;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000423 worker_thread_->Post(this, message_id, data);
424 return true;
425 }
426
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.
431 TransportChannel* channel = (!rtcp || rtcp_mux_filter_.IsActive()) ?
432 transport_channel_ : rtcp_transport_channel_;
wu@webrtc.org97077a32013-10-25 21:18:33 +0000433 if (!channel || !channel->writable()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000434 return false;
435 }
436
437 // Protect ourselves against crazy data.
438 if (!ValidPacket(rtcp, packet)) {
439 LOG(LS_ERROR) << "Dropping outgoing " << content_name_ << " "
440 << PacketType(rtcp) << " packet: wrong size="
441 << packet->length();
442 return false;
443 }
444
445 // Signal to the media sink before protecting the packet.
446 {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000447 rtc::CritScope cs(&signal_send_packet_cs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000448 SignalSendPacketPreCrypto(packet->data(), packet->length(), rtcp);
449 }
450
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000451 rtc::PacketOptions options(dscp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000452 // Protect if needed.
453 if (srtp_filter_.IsActive()) {
454 bool res;
455 char* data = packet->data();
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000456 int len = static_cast<int>(packet->length());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000457 if (!rtcp) {
henrike@webrtc.orgd43aa9d2014-02-21 23:43:24 +0000458 // If ENABLE_EXTERNAL_AUTH flag is on then packet authentication is not done
459 // inside libsrtp for a RTP packet. A external HMAC module will be writing
460 // a fake HMAC value. This is ONLY done for a RTP packet.
461 // Socket layer will update rtp sendtime extension header if present in
462 // packet with current time before updating the HMAC.
463#if !defined(ENABLE_EXTERNAL_AUTH)
464 res = srtp_filter_.ProtectRtp(
465 data, len, static_cast<int>(packet->capacity()), &len);
466#else
henrike@webrtc.org05376342014-03-10 15:53:12 +0000467 options.packet_time_params.rtp_sendtime_extension_id =
468 rtp_abs_sendtime_extn_id_;
henrike@webrtc.orgd43aa9d2014-02-21 23:43:24 +0000469 res = srtp_filter_.ProtectRtp(
470 data, len, static_cast<int>(packet->capacity()), &len,
471 &options.packet_time_params.srtp_packet_index);
472 // If protection succeeds, let's get auth params from srtp.
473 if (res) {
474 uint8* auth_key = NULL;
475 int key_len;
476 res = srtp_filter_.GetRtpAuthParams(
477 &auth_key, &key_len, &options.packet_time_params.srtp_auth_tag_len);
478 if (res) {
479 options.packet_time_params.srtp_auth_key.resize(key_len);
480 options.packet_time_params.srtp_auth_key.assign(auth_key,
481 auth_key + key_len);
482 }
483 }
484#endif
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000485 if (!res) {
486 int seq_num = -1;
487 uint32 ssrc = 0;
488 GetRtpSeqNum(data, len, &seq_num);
489 GetRtpSsrc(data, len, &ssrc);
490 LOG(LS_ERROR) << "Failed to protect " << content_name_
491 << " RTP packet: size=" << len
492 << ", seqnum=" << seq_num << ", SSRC=" << ssrc;
493 return false;
494 }
495 } else {
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000496 res = srtp_filter_.ProtectRtcp(data, len,
497 static_cast<int>(packet->capacity()),
498 &len);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000499 if (!res) {
500 int type = -1;
501 GetRtcpType(data, len, &type);
502 LOG(LS_ERROR) << "Failed to protect " << content_name_
503 << " RTCP packet: size=" << len << ", type=" << type;
504 return false;
505 }
506 }
507
508 // Update the length of the packet now that we've added the auth tag.
509 packet->SetLength(len);
510 } else if (secure_required_) {
511 // This is a double check for something that supposedly can't happen.
512 LOG(LS_ERROR) << "Can't send outgoing " << PacketType(rtcp)
513 << " packet when SRTP is inactive and crypto is required";
514
515 ASSERT(false);
516 return false;
517 }
518
519 // Signal to the media sink after protecting the packet.
520 {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000521 rtc::CritScope cs(&signal_send_packet_cs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000522 SignalSendPacketPostCrypto(packet->data(), packet->length(), rtcp);
523 }
524
525 // Bon voyage.
mallinath@webrtc.org385857d2014-02-14 00:56:12 +0000526 int ret = channel->SendPacket(packet->data(), packet->length(), options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000527 (secure() && secure_dtls()) ? PF_SRTP_BYPASS : 0);
528 if (ret != static_cast<int>(packet->length())) {
529 if (channel->GetError() == EWOULDBLOCK) {
530 LOG(LS_WARNING) << "Got EWOULDBLOCK from socket.";
531 SetReadyToSend(channel, false);
532 }
533 return false;
534 }
535 return true;
536}
537
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000538bool BaseChannel::WantsPacket(bool rtcp, rtc::Buffer* packet) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000539 // Protect ourselves against crazy data.
540 if (!ValidPacket(rtcp, packet)) {
541 LOG(LS_ERROR) << "Dropping incoming " << content_name_ << " "
542 << PacketType(rtcp) << " packet: wrong size="
543 << packet->length();
544 return false;
545 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000546
buildbot@webrtc.org5ee0f052014-05-05 20:18:08 +0000547 // Bundle filter handles both rtp and rtcp packets.
548 return bundle_filter_.DemuxPacket(packet->data(), packet->length(), rtcp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000549}
550
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000551void BaseChannel::HandlePacket(bool rtcp, rtc::Buffer* packet,
552 const rtc::PacketTime& packet_time) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000553 if (!WantsPacket(rtcp, packet)) {
554 return;
555 }
556
honghaiz@google.coma67ca1a2015-01-28 19:48:33 +0000557 // We are only interested in the first rtp packet because that
558 // indicates the media has started flowing.
559 if (!has_received_packet_ && !rtcp) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000560 has_received_packet_ = true;
561 signaling_thread()->Post(this, MSG_FIRSTPACKETRECEIVED);
562 }
563
564 // Signal to the media sink before unprotecting the packet.
565 {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000566 rtc::CritScope cs(&signal_recv_packet_cs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000567 SignalRecvPacketPostCrypto(packet->data(), packet->length(), rtcp);
568 }
569
570 // Unprotect the packet, if needed.
571 if (srtp_filter_.IsActive()) {
572 char* data = packet->data();
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000573 int len = static_cast<int>(packet->length());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000574 bool res;
575 if (!rtcp) {
576 res = srtp_filter_.UnprotectRtp(data, len, &len);
577 if (!res) {
578 int seq_num = -1;
579 uint32 ssrc = 0;
580 GetRtpSeqNum(data, len, &seq_num);
581 GetRtpSsrc(data, len, &ssrc);
582 LOG(LS_ERROR) << "Failed to unprotect " << content_name_
583 << " RTP packet: size=" << len
584 << ", seqnum=" << seq_num << ", SSRC=" << ssrc;
585 return;
586 }
587 } else {
588 res = srtp_filter_.UnprotectRtcp(data, len, &len);
589 if (!res) {
590 int type = -1;
591 GetRtcpType(data, len, &type);
592 LOG(LS_ERROR) << "Failed to unprotect " << content_name_
593 << " RTCP packet: size=" << len << ", type=" << type;
594 return;
595 }
596 }
597
598 packet->SetLength(len);
599 } else if (secure_required_) {
600 // Our session description indicates that SRTP is required, but we got a
601 // packet before our SRTP filter is active. This means either that
602 // a) we got SRTP packets before we received the SDES keys, in which case
603 // we can't decrypt it anyway, or
604 // b) we got SRTP packets before DTLS completed on both the RTP and RTCP
605 // channels, so we haven't yet extracted keys, even if DTLS did complete
606 // on the channel that the packets are being sent on. It's really good
607 // practice to wait for both RTP and RTCP to be good to go before sending
608 // media, to prevent weird failure modes, so it's fine for us to just eat
609 // packets here. This is all sidestepped if RTCP mux is used anyway.
610 LOG(LS_WARNING) << "Can't process incoming " << PacketType(rtcp)
611 << " packet when SRTP is inactive and crypto is required";
612 return;
613 }
614
615 // Signal to the media sink after unprotecting the packet.
616 {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000617 rtc::CritScope cs(&signal_recv_packet_cs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000618 SignalRecvPacketPreCrypto(packet->data(), packet->length(), rtcp);
619 }
620
621 // Push it down to the media channel.
622 if (!rtcp) {
wu@webrtc.orga9890802013-12-13 00:21:03 +0000623 media_channel_->OnPacketReceived(packet, packet_time);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000624 } else {
wu@webrtc.orga9890802013-12-13 00:21:03 +0000625 media_channel_->OnRtcpReceived(packet, packet_time);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000626 }
627}
628
629void BaseChannel::OnNewLocalDescription(
630 BaseSession* session, ContentAction action) {
631 const ContentInfo* content_info =
632 GetFirstContent(session->local_description());
633 const MediaContentDescription* content_desc =
634 GetContentDescription(content_info);
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000635 std::string error_desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000636 if (content_desc && content_info && !content_info->rejected &&
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000637 !SetLocalContent(content_desc, action, &error_desc)) {
638 SetSessionError(session_, BaseSession::ERROR_CONTENT, error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000639 LOG(LS_ERROR) << "Failure in SetLocalContent with action " << action;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000640 }
641}
642
643void BaseChannel::OnNewRemoteDescription(
644 BaseSession* session, ContentAction action) {
645 const ContentInfo* content_info =
646 GetFirstContent(session->remote_description());
647 const MediaContentDescription* content_desc =
648 GetContentDescription(content_info);
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000649 std::string error_desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000650 if (content_desc && content_info && !content_info->rejected &&
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000651 !SetRemoteContent(content_desc, action, &error_desc)) {
652 SetSessionError(session_, BaseSession::ERROR_CONTENT, error_desc);
653 LOG(LS_ERROR) << "Failure in SetRemoteContent with action " << action;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000654 }
655}
656
657void BaseChannel::EnableMedia_w() {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000658 ASSERT(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000659 if (enabled_)
660 return;
661
662 LOG(LS_INFO) << "Channel enabled";
663 enabled_ = true;
664 ChangeState();
665}
666
667void BaseChannel::DisableMedia_w() {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000668 ASSERT(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000669 if (!enabled_)
670 return;
671
672 LOG(LS_INFO) << "Channel disabled";
673 enabled_ = false;
674 ChangeState();
675}
676
677bool BaseChannel::MuteStream_w(uint32 ssrc, bool mute) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000678 ASSERT(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000679 bool ret = media_channel()->MuteStream(ssrc, mute);
680 if (ret) {
681 if (mute)
682 muted_streams_.insert(ssrc);
683 else
684 muted_streams_.erase(ssrc);
685 }
686 return ret;
687}
688
689bool BaseChannel::IsStreamMuted_w(uint32 ssrc) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000690 ASSERT(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000691 return muted_streams_.find(ssrc) != muted_streams_.end();
692}
693
694void BaseChannel::ChannelWritable_w() {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000695 ASSERT(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000696 if (writable_)
697 return;
698
699 LOG(LS_INFO) << "Channel socket writable ("
700 << transport_channel_->content_name() << ", "
701 << transport_channel_->component() << ")"
702 << (was_ever_writable_ ? "" : " for the first time");
703
704 std::vector<ConnectionInfo> infos;
705 transport_channel_->GetStats(&infos);
706 for (std::vector<ConnectionInfo>::const_iterator it = infos.begin();
707 it != infos.end(); ++it) {
708 if (it->best_connection) {
709 LOG(LS_INFO) << "Using " << it->local_candidate.ToSensitiveString()
710 << "->" << it->remote_candidate.ToSensitiveString();
711 break;
712 }
713 }
714
715 // If we're doing DTLS-SRTP, now is the time.
716 if (!was_ever_writable_ && ShouldSetupDtlsSrtp()) {
717 if (!SetupDtlsSrtp(false)) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000718 const std::string error_desc =
719 "Couldn't set up DTLS-SRTP on RTP channel.";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000720 // Sent synchronously.
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000721 signaling_thread()->Invoke<void>(Bind(
722 &SetSessionError,
723 session_,
724 BaseSession::ERROR_TRANSPORT,
725 error_desc));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000726 return;
727 }
728
729 if (rtcp_transport_channel_) {
730 if (!SetupDtlsSrtp(true)) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000731 const std::string error_desc =
732 "Couldn't set up DTLS-SRTP on RTCP channel";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000733 // Sent synchronously.
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000734 signaling_thread()->Invoke<void>(Bind(
735 &SetSessionError,
736 session_,
737 BaseSession::ERROR_TRANSPORT,
738 error_desc));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000739 return;
740 }
741 }
742 }
743
744 was_ever_writable_ = true;
745 writable_ = true;
746 ChangeState();
747}
748
749bool BaseChannel::SetDtlsSrtpCiphers(TransportChannel *tc, bool rtcp) {
750 std::vector<std::string> ciphers;
751 // We always use the default SRTP ciphers for RTCP, but we may use different
752 // ciphers for RTP depending on the media type.
753 if (!rtcp) {
754 GetSrtpCiphers(&ciphers);
755 } else {
756 GetSupportedDefaultCryptoSuites(&ciphers);
757 }
758 return tc->SetSrtpCiphers(ciphers);
759}
760
761bool BaseChannel::ShouldSetupDtlsSrtp() const {
762 return true;
763}
764
765// This function returns true if either DTLS-SRTP is not in use
766// *or* DTLS-SRTP is successfully set up.
767bool BaseChannel::SetupDtlsSrtp(bool rtcp_channel) {
768 bool ret = false;
769
770 TransportChannel *channel = rtcp_channel ?
771 rtcp_transport_channel_ : transport_channel_;
772
773 // No DTLS
774 if (!channel->IsDtlsActive())
775 return true;
776
777 std::string selected_cipher;
778
779 if (!channel->GetSrtpCipher(&selected_cipher)) {
780 LOG(LS_ERROR) << "No DTLS-SRTP selected cipher";
781 return false;
782 }
783
784 LOG(LS_INFO) << "Installing keys from DTLS-SRTP on "
785 << content_name() << " "
786 << PacketType(rtcp_channel);
787
788 // OK, we're now doing DTLS (RFC 5764)
789 std::vector<unsigned char> dtls_buffer(SRTP_MASTER_KEY_KEY_LEN * 2 +
790 SRTP_MASTER_KEY_SALT_LEN * 2);
791
792 // RFC 5705 exporter using the RFC 5764 parameters
793 if (!channel->ExportKeyingMaterial(
794 kDtlsSrtpExporterLabel,
795 NULL, 0, false,
796 &dtls_buffer[0], dtls_buffer.size())) {
797 LOG(LS_WARNING) << "DTLS-SRTP key export failed";
798 ASSERT(false); // This should never happen
799 return false;
800 }
801
802 // Sync up the keys with the DTLS-SRTP interface
803 std::vector<unsigned char> client_write_key(SRTP_MASTER_KEY_KEY_LEN +
804 SRTP_MASTER_KEY_SALT_LEN);
805 std::vector<unsigned char> server_write_key(SRTP_MASTER_KEY_KEY_LEN +
806 SRTP_MASTER_KEY_SALT_LEN);
807 size_t offset = 0;
808 memcpy(&client_write_key[0], &dtls_buffer[offset],
809 SRTP_MASTER_KEY_KEY_LEN);
810 offset += SRTP_MASTER_KEY_KEY_LEN;
811 memcpy(&server_write_key[0], &dtls_buffer[offset],
812 SRTP_MASTER_KEY_KEY_LEN);
813 offset += SRTP_MASTER_KEY_KEY_LEN;
814 memcpy(&client_write_key[SRTP_MASTER_KEY_KEY_LEN],
815 &dtls_buffer[offset], SRTP_MASTER_KEY_SALT_LEN);
816 offset += SRTP_MASTER_KEY_SALT_LEN;
817 memcpy(&server_write_key[SRTP_MASTER_KEY_KEY_LEN],
818 &dtls_buffer[offset], SRTP_MASTER_KEY_SALT_LEN);
819
820 std::vector<unsigned char> *send_key, *recv_key;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000821 rtc::SSLRole role;
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000822 if (!channel->GetSslRole(&role)) {
823 LOG(LS_WARNING) << "GetSslRole failed";
824 return false;
825 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000826
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000827 if (role == rtc::SSL_SERVER) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000828 send_key = &server_write_key;
829 recv_key = &client_write_key;
830 } else {
831 send_key = &client_write_key;
832 recv_key = &server_write_key;
833 }
834
835 if (rtcp_channel) {
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000836 ret = srtp_filter_.SetRtcpParams(
837 selected_cipher,
838 &(*send_key)[0],
839 static_cast<int>(send_key->size()),
840 selected_cipher,
841 &(*recv_key)[0],
842 static_cast<int>(recv_key->size()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000843 } else {
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000844 ret = srtp_filter_.SetRtpParams(
845 selected_cipher,
846 &(*send_key)[0],
847 static_cast<int>(send_key->size()),
848 selected_cipher,
849 &(*recv_key)[0],
850 static_cast<int>(recv_key->size()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000851 }
852
853 if (!ret)
854 LOG(LS_WARNING) << "DTLS-SRTP key installation failed";
855 else
856 dtls_keyed_ = true;
857
858 return ret;
859}
860
861void BaseChannel::ChannelNotWritable_w() {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000862 ASSERT(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000863 if (!writable_)
864 return;
865
866 LOG(LS_INFO) << "Channel socket not writable ("
867 << transport_channel_->content_name() << ", "
868 << transport_channel_->component() << ")";
869 writable_ = false;
870 ChangeState();
871}
872
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000873// |dtls| will be set to true if DTLS is active for transport channel and
874// crypto is empty.
875bool BaseChannel::CheckSrtpConfig(const std::vector<CryptoParams>& cryptos,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000876 bool* dtls,
877 std::string* error_desc) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000878 *dtls = transport_channel_->IsDtlsActive();
879 if (*dtls && !cryptos.empty()) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000880 SafeSetError("Cryptos must be empty when DTLS is active.",
881 error_desc);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000882 return false;
883 }
884 return true;
885}
886
buildbot@webrtc.org75ce9202014-06-20 12:30:24 +0000887bool BaseChannel::SetRecvRtpHeaderExtensions_w(
888 const MediaContentDescription* content,
889 MediaChannel* media_channel,
890 std::string* error_desc) {
891 if (content->rtp_header_extensions_set()) {
892 if (!media_channel->SetRecvRtpHeaderExtensions(
893 content->rtp_header_extensions())) {
894 std::ostringstream desc;
895 desc << "Failed to set receive rtp header extensions for "
896 << MediaTypeToString(content->type()) << " content.";
897 SafeSetError(desc.str(), error_desc);
898 return false;
899 }
900 }
901 return true;
902}
903
904bool BaseChannel::SetSendRtpHeaderExtensions_w(
905 const MediaContentDescription* content,
906 MediaChannel* media_channel,
907 std::string* error_desc) {
908 if (content->rtp_header_extensions_set()) {
909 if (!media_channel->SetSendRtpHeaderExtensions(
910 content->rtp_header_extensions())) {
911 std::ostringstream desc;
912 desc << "Failed to set send rtp header extensions for "
913 << MediaTypeToString(content->type()) << " content.";
914 SafeSetError(desc.str(), error_desc);
915 return false;
916 } else {
917 MaybeCacheRtpAbsSendTimeHeaderExtension(content->rtp_header_extensions());
918 }
919 }
920 return true;
921}
922
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000923bool BaseChannel::SetSrtp_w(const std::vector<CryptoParams>& cryptos,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000924 ContentAction action,
925 ContentSource src,
926 std::string* error_desc) {
927 if (action == CA_UPDATE) {
928 // no crypto params.
929 return true;
930 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000931 bool ret = false;
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000932 bool dtls = false;
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000933 ret = CheckSrtpConfig(cryptos, &dtls, error_desc);
934 if (!ret) {
935 return false;
936 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000937 switch (action) {
938 case CA_OFFER:
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000939 // If DTLS is already active on the channel, we could be renegotiating
940 // here. We don't update the srtp filter.
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000941 if (!dtls) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000942 ret = srtp_filter_.SetOffer(cryptos, src);
943 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000944 break;
945 case CA_PRANSWER:
946 // If we're doing DTLS-SRTP, we don't want to update the filter
947 // with an answer, because we already have SRTP parameters.
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000948 if (!dtls) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000949 ret = srtp_filter_.SetProvisionalAnswer(cryptos, src);
950 }
951 break;
952 case CA_ANSWER:
953 // If we're doing DTLS-SRTP, we don't want to update the filter
954 // with an answer, because we already have SRTP parameters.
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000955 if (!dtls) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000956 ret = srtp_filter_.SetAnswer(cryptos, src);
957 }
958 break;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000959 default:
960 break;
961 }
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000962 if (!ret) {
963 SafeSetError("Failed to setup SRTP filter.", error_desc);
964 return false;
965 }
966 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000967}
968
969bool BaseChannel::SetRtcpMux_w(bool enable, ContentAction action,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000970 ContentSource src,
971 std::string* error_desc) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000972 bool ret = false;
973 switch (action) {
974 case CA_OFFER:
975 ret = rtcp_mux_filter_.SetOffer(enable, src);
976 break;
977 case CA_PRANSWER:
978 ret = rtcp_mux_filter_.SetProvisionalAnswer(enable, src);
979 break;
980 case CA_ANSWER:
981 ret = rtcp_mux_filter_.SetAnswer(enable, src);
982 if (ret && rtcp_mux_filter_.IsActive()) {
983 // We activated RTCP mux, close down the RTCP transport.
984 set_rtcp_transport_channel(NULL);
985 }
986 break;
987 case CA_UPDATE:
988 // No RTCP mux info.
989 ret = true;
990 default:
991 break;
992 }
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000993 if (!ret) {
994 SafeSetError("Failed to setup RTCP mux filter.", error_desc);
995 return false;
996 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000997 // |rtcp_mux_filter_| can be active if |action| is CA_PRANSWER or
998 // CA_ANSWER, but we only want to tear down the RTCP transport channel if we
999 // received a final answer.
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001000 if (rtcp_mux_filter_.IsActive()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001001 // If the RTP transport is already writable, then so are we.
1002 if (transport_channel_->writable()) {
1003 ChannelWritable_w();
1004 }
1005 }
1006
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001007 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001008}
1009
1010bool BaseChannel::AddRecvStream_w(const StreamParams& sp) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001011 ASSERT(worker_thread() == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001012 if (!media_channel()->AddRecvStream(sp))
1013 return false;
1014
buildbot@webrtc.org5ee0f052014-05-05 20:18:08 +00001015 return bundle_filter_.AddStream(sp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001016}
1017
1018bool BaseChannel::RemoveRecvStream_w(uint32 ssrc) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001019 ASSERT(worker_thread() == rtc::Thread::Current());
buildbot@webrtc.org5ee0f052014-05-05 20:18:08 +00001020 bundle_filter_.RemoveStream(ssrc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001021 return media_channel()->RemoveRecvStream(ssrc);
1022}
1023
1024bool BaseChannel::UpdateLocalStreams_w(const std::vector<StreamParams>& streams,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001025 ContentAction action,
1026 std::string* error_desc) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001027 if (!VERIFY(action == CA_OFFER || action == CA_ANSWER ||
1028 action == CA_PRANSWER || action == CA_UPDATE))
1029 return false;
1030
1031 // If this is an update, streams only contain streams that have changed.
1032 if (action == CA_UPDATE) {
1033 for (StreamParamsVec::const_iterator it = streams.begin();
1034 it != streams.end(); ++it) {
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +00001035 const StreamParams* existing_stream =
1036 GetStreamByIds(local_streams_, it->groupid, it->id);
1037 if (!existing_stream && it->has_ssrcs()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001038 if (media_channel()->AddSendStream(*it)) {
1039 local_streams_.push_back(*it);
1040 LOG(LS_INFO) << "Add send stream ssrc: " << it->first_ssrc();
1041 } else {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001042 std::ostringstream desc;
1043 desc << "Failed to add send stream ssrc: " << it->first_ssrc();
1044 SafeSetError(desc.str(), error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001045 return false;
1046 }
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +00001047 } else if (existing_stream && !it->has_ssrcs()) {
1048 if (!media_channel()->RemoveSendStream(existing_stream->first_ssrc())) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001049 std::ostringstream desc;
1050 desc << "Failed to remove send stream with ssrc "
1051 << it->first_ssrc() << ".";
1052 SafeSetError(desc.str(), error_desc);
1053 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001054 }
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +00001055 RemoveStreamBySsrc(&local_streams_, existing_stream->first_ssrc());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001056 } else {
1057 LOG(LS_WARNING) << "Ignore unsupported stream update";
1058 }
1059 }
1060 return true;
1061 }
1062 // Else streams are all the streams we want to send.
1063
1064 // Check for streams that have been removed.
1065 bool ret = true;
1066 for (StreamParamsVec::const_iterator it = local_streams_.begin();
1067 it != local_streams_.end(); ++it) {
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +00001068 if (!GetStreamBySsrc(streams, it->first_ssrc())) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001069 if (!media_channel()->RemoveSendStream(it->first_ssrc())) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001070 std::ostringstream desc;
1071 desc << "Failed to remove send stream with ssrc "
1072 << it->first_ssrc() << ".";
1073 SafeSetError(desc.str(), error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001074 ret = false;
1075 }
1076 }
1077 }
1078 // Check for new streams.
1079 for (StreamParamsVec::const_iterator it = streams.begin();
1080 it != streams.end(); ++it) {
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +00001081 if (!GetStreamBySsrc(local_streams_, it->first_ssrc())) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001082 if (media_channel()->AddSendStream(*it)) {
1083 LOG(LS_INFO) << "Add send ssrc: " << it->ssrcs[0];
1084 } else {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001085 std::ostringstream desc;
1086 desc << "Failed to add send stream ssrc: " << it->first_ssrc();
1087 SafeSetError(desc.str(), error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001088 ret = false;
1089 }
1090 }
1091 }
1092 local_streams_ = streams;
1093 return ret;
1094}
1095
1096bool BaseChannel::UpdateRemoteStreams_w(
1097 const std::vector<StreamParams>& streams,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001098 ContentAction action,
1099 std::string* error_desc) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001100 if (!VERIFY(action == CA_OFFER || action == CA_ANSWER ||
1101 action == CA_PRANSWER || action == CA_UPDATE))
1102 return false;
1103
1104 // If this is an update, streams only contain streams that have changed.
1105 if (action == CA_UPDATE) {
1106 for (StreamParamsVec::const_iterator it = streams.begin();
1107 it != streams.end(); ++it) {
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +00001108 const StreamParams* existing_stream =
1109 GetStreamByIds(remote_streams_, it->groupid, it->id);
1110 if (!existing_stream && it->has_ssrcs()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001111 if (AddRecvStream_w(*it)) {
1112 remote_streams_.push_back(*it);
1113 LOG(LS_INFO) << "Add remote stream ssrc: " << it->first_ssrc();
1114 } else {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001115 std::ostringstream desc;
1116 desc << "Failed to add remote stream ssrc: " << it->first_ssrc();
1117 SafeSetError(desc.str(), error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001118 return false;
1119 }
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +00001120 } else if (existing_stream && !it->has_ssrcs()) {
1121 if (!RemoveRecvStream_w(existing_stream->first_ssrc())) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001122 std::ostringstream desc;
1123 desc << "Failed to remove remote stream with ssrc "
1124 << it->first_ssrc() << ".";
1125 SafeSetError(desc.str(), error_desc);
1126 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001127 }
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +00001128 RemoveStreamBySsrc(&remote_streams_, existing_stream->first_ssrc());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001129 } else {
1130 LOG(LS_WARNING) << "Ignore unsupported stream update."
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +00001131 << " Stream exists? " << (existing_stream != nullptr)
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001132 << " new stream = " << it->ToString();
1133 }
1134 }
1135 return true;
1136 }
1137 // Else streams are all the streams we want to receive.
1138
1139 // Check for streams that have been removed.
1140 bool ret = true;
1141 for (StreamParamsVec::const_iterator it = remote_streams_.begin();
1142 it != remote_streams_.end(); ++it) {
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +00001143 if (!GetStreamBySsrc(streams, it->first_ssrc())) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001144 if (!RemoveRecvStream_w(it->first_ssrc())) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001145 std::ostringstream desc;
1146 desc << "Failed to remove remote stream with ssrc "
1147 << it->first_ssrc() << ".";
1148 SafeSetError(desc.str(), error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001149 ret = false;
1150 }
1151 }
1152 }
1153 // Check for new streams.
1154 for (StreamParamsVec::const_iterator it = streams.begin();
1155 it != streams.end(); ++it) {
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +00001156 if (!GetStreamBySsrc(remote_streams_, it->first_ssrc())) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001157 if (AddRecvStream_w(*it)) {
1158 LOG(LS_INFO) << "Add remote ssrc: " << it->ssrcs[0];
1159 } else {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001160 std::ostringstream desc;
1161 desc << "Failed to add remote stream ssrc: " << it->first_ssrc();
1162 SafeSetError(desc.str(), error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001163 ret = false;
1164 }
1165 }
1166 }
1167 remote_streams_ = streams;
1168 return ret;
1169}
1170
1171bool BaseChannel::SetBaseLocalContent_w(const MediaContentDescription* content,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001172 ContentAction action,
1173 std::string* error_desc) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001174 // Cache secure_required_ for belt and suspenders check on SendPacket
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +00001175 secure_required_ = content->crypto_required() != CT_NONE;
buildbot@webrtc.org75ce9202014-06-20 12:30:24 +00001176 // Set local RTP header extensions.
1177 bool ret = SetRecvRtpHeaderExtensions_w(content, media_channel(), error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001178 // Set local SRTP parameters (what we will encrypt with).
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001179 ret &= SetSrtp_w(content->cryptos(), action, CS_LOCAL, error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001180 // Set local RTCP mux parameters.
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001181 ret &= SetRtcpMux_w(content->rtcp_mux(), action, CS_LOCAL, error_desc);
buildbot@webrtc.org75ce9202014-06-20 12:30:24 +00001182
1183 // Call UpdateLocalStreams_w last to make sure as many settings as possible
1184 // are already set when creating streams.
1185 ret &= UpdateLocalStreams_w(content->streams(), action, error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001186 set_local_content_direction(content->direction());
1187 return ret;
1188}
1189
1190bool BaseChannel::SetBaseRemoteContent_w(const MediaContentDescription* content,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001191 ContentAction action,
1192 std::string* error_desc) {
buildbot@webrtc.org75ce9202014-06-20 12:30:24 +00001193 // Set remote RTP header extensions.
1194 bool ret = SetSendRtpHeaderExtensions_w(content, media_channel(), error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001195 // Set remote SRTP parameters (what the other side will encrypt with).
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001196 ret &= SetSrtp_w(content->cryptos(), action, CS_REMOTE, error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001197 // Set remote RTCP mux parameters.
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001198 ret &= SetRtcpMux_w(content->rtcp_mux(), action, CS_REMOTE, error_desc);
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001199 if (!media_channel()->SetMaxSendBandwidth(content->bandwidth())) {
1200 std::ostringstream desc;
1201 desc << "Failed to set max send bandwidth for "
1202 << MediaTypeToString(content->type()) << " content.";
1203 SafeSetError(desc.str(), error_desc);
1204 ret = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001205 }
buildbot@webrtc.org75ce9202014-06-20 12:30:24 +00001206
1207 // Call UpdateRemoteStreams_w last to make sure as many settings as possible
1208 // are already set when creating streams.
1209 ret &= UpdateRemoteStreams_w(content->streams(), action, error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001210 set_remote_content_direction(content->direction());
1211 return ret;
1212}
1213
henrike@webrtc.orgd43aa9d2014-02-21 23:43:24 +00001214void BaseChannel::MaybeCacheRtpAbsSendTimeHeaderExtension(
1215 const std::vector<RtpHeaderExtension>& extensions) {
1216 const RtpHeaderExtension* send_time_extension =
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001217 FindHeaderExtension(extensions, kRtpAbsoluteSenderTimeHeaderExtension);
henrike@webrtc.orgd43aa9d2014-02-21 23:43:24 +00001218 rtp_abs_sendtime_extn_id_ =
1219 send_time_extension ? send_time_extension->id : -1;
1220}
1221
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001222void BaseChannel::OnMessage(rtc::Message *pmsg) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001223 switch (pmsg->message_id) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001224 case MSG_RTPPACKET:
1225 case MSG_RTCPPACKET: {
1226 PacketMessageData* data = static_cast<PacketMessageData*>(pmsg->pdata);
mallinath@webrtc.org1112c302013-09-23 20:34:45 +00001227 SendPacket(pmsg->message_id == MSG_RTCPPACKET, &data->packet, data->dscp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001228 delete data; // because it is Posted
1229 break;
1230 }
1231 case MSG_FIRSTPACKETRECEIVED: {
1232 SignalFirstPacketReceived(this);
1233 break;
1234 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001235 }
1236}
1237
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001238void BaseChannel::FlushRtcpMessages() {
1239 // Flush all remaining RTCP messages. This should only be called in
1240 // destructor.
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001241 ASSERT(rtc::Thread::Current() == worker_thread_);
1242 rtc::MessageList rtcp_messages;
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001243 worker_thread_->Clear(this, MSG_RTCPPACKET, &rtcp_messages);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001244 for (rtc::MessageList::iterator it = rtcp_messages.begin();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001245 it != rtcp_messages.end(); ++it) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001246 worker_thread_->Send(this, MSG_RTCPPACKET, it->pdata);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001247 }
1248}
1249
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001250VoiceChannel::VoiceChannel(rtc::Thread* thread,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001251 MediaEngineInterface* media_engine,
1252 VoiceMediaChannel* media_channel,
1253 BaseSession* session,
1254 const std::string& content_name,
1255 bool rtcp)
1256 : BaseChannel(thread, media_engine, media_channel, session, content_name,
1257 rtcp),
1258 received_media_(false) {
1259}
1260
1261VoiceChannel::~VoiceChannel() {
1262 StopAudioMonitor();
1263 StopMediaMonitor();
1264 // this can't be done in the base class, since it calls a virtual
1265 DisableMedia_w();
wu@webrtc.org78187522013-10-07 23:32:02 +00001266 Deinit();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001267}
1268
1269bool VoiceChannel::Init() {
1270 TransportChannel* rtcp_channel = rtcp() ? session()->CreateChannel(
1271 content_name(), "rtcp", ICE_CANDIDATE_COMPONENT_RTCP) : NULL;
1272 if (!BaseChannel::Init(session()->CreateChannel(
1273 content_name(), "rtp", ICE_CANDIDATE_COMPONENT_RTP),
1274 rtcp_channel)) {
1275 return false;
1276 }
1277 media_channel()->SignalMediaError.connect(
1278 this, &VoiceChannel::OnVoiceChannelError);
1279 srtp_filter()->SignalSrtpError.connect(
1280 this, &VoiceChannel::OnSrtpError);
1281 return true;
1282}
1283
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001284bool VoiceChannel::SetRemoteRenderer(uint32 ssrc, AudioRenderer* renderer) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001285 return InvokeOnWorker(Bind(&VoiceMediaChannel::SetRemoteRenderer,
1286 media_channel(), ssrc, renderer));
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001287}
1288
1289bool VoiceChannel::SetLocalRenderer(uint32 ssrc, AudioRenderer* renderer) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001290 return InvokeOnWorker(Bind(&VoiceMediaChannel::SetLocalRenderer,
1291 media_channel(), ssrc, renderer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001292}
1293
1294bool VoiceChannel::SetRingbackTone(const void* buf, int len) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001295 return InvokeOnWorker(Bind(&VoiceChannel::SetRingbackTone_w, this, buf, len));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001296}
1297
1298// TODO(juberti): Handle early media the right way. We should get an explicit
1299// ringing message telling us to start playing local ringback, which we cancel
1300// if any early media actually arrives. For now, we do the opposite, which is
1301// to wait 1 second for early media, and start playing local ringback if none
1302// arrives.
1303void VoiceChannel::SetEarlyMedia(bool enable) {
1304 if (enable) {
1305 // Start the early media timeout
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001306 worker_thread()->PostDelayed(kEarlyMediaTimeout, this,
1307 MSG_EARLYMEDIATIMEOUT);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001308 } else {
1309 // Stop the timeout if currently going.
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001310 worker_thread()->Clear(this, MSG_EARLYMEDIATIMEOUT);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001311 }
1312}
1313
1314bool VoiceChannel::PlayRingbackTone(uint32 ssrc, bool play, bool loop) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001315 return InvokeOnWorker(Bind(&VoiceChannel::PlayRingbackTone_w,
1316 this, ssrc, play, loop));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001317}
1318
1319bool VoiceChannel::PressDTMF(int digit, bool playout) {
1320 int flags = DF_SEND;
1321 if (playout) {
1322 flags |= DF_PLAY;
1323 }
1324 int duration_ms = 160;
1325 return InsertDtmf(0, digit, duration_ms, flags);
1326}
1327
1328bool VoiceChannel::CanInsertDtmf() {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001329 return InvokeOnWorker(Bind(&VoiceMediaChannel::CanInsertDtmf,
1330 media_channel()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001331}
1332
1333bool VoiceChannel::InsertDtmf(uint32 ssrc, int event_code, int duration,
1334 int flags) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001335 return InvokeOnWorker(Bind(&VoiceChannel::InsertDtmf_w, this,
1336 ssrc, event_code, duration, flags));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001337}
1338
1339bool VoiceChannel::SetOutputScaling(uint32 ssrc, double left, double right) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001340 return InvokeOnWorker(Bind(&VoiceMediaChannel::SetOutputScaling,
1341 media_channel(), ssrc, left, right));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001342}
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001343
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001344bool VoiceChannel::GetStats(VoiceMediaInfo* stats) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001345 return InvokeOnWorker(Bind(&VoiceMediaChannel::GetStats,
1346 media_channel(), stats));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001347}
1348
1349void VoiceChannel::StartMediaMonitor(int cms) {
1350 media_monitor_.reset(new VoiceMediaMonitor(media_channel(), worker_thread(),
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001351 rtc::Thread::Current()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001352 media_monitor_->SignalUpdate.connect(
1353 this, &VoiceChannel::OnMediaMonitorUpdate);
1354 media_monitor_->Start(cms);
1355}
1356
1357void VoiceChannel::StopMediaMonitor() {
1358 if (media_monitor_) {
1359 media_monitor_->Stop();
1360 media_monitor_->SignalUpdate.disconnect(this);
1361 media_monitor_.reset();
1362 }
1363}
1364
1365void VoiceChannel::StartAudioMonitor(int cms) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001366 audio_monitor_.reset(new AudioMonitor(this, rtc::Thread::Current()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001367 audio_monitor_
1368 ->SignalUpdate.connect(this, &VoiceChannel::OnAudioMonitorUpdate);
1369 audio_monitor_->Start(cms);
1370}
1371
1372void VoiceChannel::StopAudioMonitor() {
1373 if (audio_monitor_) {
1374 audio_monitor_->Stop();
1375 audio_monitor_.reset();
1376 }
1377}
1378
1379bool VoiceChannel::IsAudioMonitorRunning() const {
1380 return (audio_monitor_.get() != NULL);
1381}
1382
1383void VoiceChannel::StartTypingMonitor(const TypingMonitorOptions& settings) {
1384 typing_monitor_.reset(new TypingMonitor(this, worker_thread(), settings));
1385 SignalAutoMuted.repeat(typing_monitor_->SignalMuted);
1386}
1387
1388void VoiceChannel::StopTypingMonitor() {
1389 typing_monitor_.reset();
1390}
1391
1392bool VoiceChannel::IsTypingMonitorRunning() const {
1393 return typing_monitor_;
1394}
1395
1396bool VoiceChannel::MuteStream_w(uint32 ssrc, bool mute) {
1397 bool ret = BaseChannel::MuteStream_w(ssrc, mute);
1398 if (typing_monitor_ && mute)
1399 typing_monitor_->OnChannelMuted();
1400 return ret;
1401}
1402
1403int VoiceChannel::GetInputLevel_w() {
1404 return media_engine()->GetInputLevel();
1405}
1406
1407int VoiceChannel::GetOutputLevel_w() {
1408 return media_channel()->GetOutputLevel();
1409}
1410
1411void VoiceChannel::GetActiveStreams_w(AudioInfo::StreamList* actives) {
1412 media_channel()->GetActiveStreams(actives);
1413}
1414
1415void VoiceChannel::OnChannelRead(TransportChannel* channel,
wu@webrtc.orga9890802013-12-13 00:21:03 +00001416 const char* data, size_t len,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001417 const rtc::PacketTime& packet_time,
wu@webrtc.orga9890802013-12-13 00:21:03 +00001418 int flags) {
1419 BaseChannel::OnChannelRead(channel, data, len, packet_time, flags);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001420
1421 // Set a flag when we've received an RTP packet. If we're waiting for early
1422 // media, this will disable the timeout.
1423 if (!received_media_ && !PacketIsRtcp(channel, data, len)) {
1424 received_media_ = true;
1425 }
1426}
1427
1428void VoiceChannel::ChangeState() {
1429 // Render incoming data if we're the active call, and we have the local
1430 // content. We receive data on the default channel and multiplexed streams.
1431 bool recv = IsReadyToReceive();
1432 if (!media_channel()->SetPlayout(recv)) {
1433 SendLastMediaError();
1434 }
1435
1436 // Send outgoing data if we're the active call, we have the remote content,
1437 // and we have had some form of connectivity.
1438 bool send = IsReadyToSend();
1439 SendFlags send_flag = send ? SEND_MICROPHONE : SEND_NOTHING;
1440 if (!media_channel()->SetSend(send_flag)) {
1441 LOG(LS_ERROR) << "Failed to SetSend " << send_flag << " on voice channel";
1442 SendLastMediaError();
1443 }
1444
1445 LOG(LS_INFO) << "Changing voice state, recv=" << recv << " send=" << send;
1446}
1447
1448const ContentInfo* VoiceChannel::GetFirstContent(
1449 const SessionDescription* sdesc) {
1450 return GetFirstAudioContent(sdesc);
1451}
1452
1453bool VoiceChannel::SetLocalContent_w(const MediaContentDescription* content,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001454 ContentAction action,
1455 std::string* error_desc) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001456 ASSERT(worker_thread() == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001457 LOG(LS_INFO) << "Setting local voice description";
1458
1459 const AudioContentDescription* audio =
1460 static_cast<const AudioContentDescription*>(content);
1461 ASSERT(audio != NULL);
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001462 if (!audio) {
1463 SafeSetError("Can't find audio content in local description.", error_desc);
1464 return false;
1465 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001466
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001467 bool ret = SetBaseLocalContent_w(content, action, error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001468 // Set local audio codecs (what we want to receive).
1469 // TODO(whyuan): Change action != CA_UPDATE to !audio->partial() when partial
1470 // is set properly.
1471 if (action != CA_UPDATE || audio->has_codecs()) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001472 if (!media_channel()->SetRecvCodecs(audio->codecs())) {
1473 SafeSetError("Failed to set audio receive codecs.", error_desc);
1474 ret = false;
1475 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001476 }
1477
1478 // If everything worked, see if we can start receiving.
1479 if (ret) {
buildbot@webrtc.org5ee0f052014-05-05 20:18:08 +00001480 std::vector<AudioCodec>::const_iterator it = audio->codecs().begin();
1481 for (; it != audio->codecs().end(); ++it) {
1482 bundle_filter()->AddPayloadType(it->id);
1483 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001484 ChangeState();
1485 } else {
1486 LOG(LS_WARNING) << "Failed to set local voice description";
1487 }
1488 return ret;
1489}
1490
1491bool VoiceChannel::SetRemoteContent_w(const MediaContentDescription* content,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001492 ContentAction action,
1493 std::string* error_desc) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001494 ASSERT(worker_thread() == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001495 LOG(LS_INFO) << "Setting remote voice description";
1496
1497 const AudioContentDescription* audio =
1498 static_cast<const AudioContentDescription*>(content);
1499 ASSERT(audio != NULL);
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001500 if (!audio) {
1501 SafeSetError("Can't find audio content in remote description.", error_desc);
1502 return false;
1503 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001504
1505 bool ret = true;
1506 // Set remote video codecs (what the other side wants to receive).
1507 if (action != CA_UPDATE || audio->has_codecs()) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001508 if (!media_channel()->SetSendCodecs(audio->codecs())) {
1509 SafeSetError("Failed to set audio send codecs.", error_desc);
1510 ret = false;
1511 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001512 }
1513
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001514 ret &= SetBaseRemoteContent_w(content, action, error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001515
1516 if (action != CA_UPDATE) {
1517 // Tweak our audio processing settings, if needed.
1518 AudioOptions audio_options;
1519 if (!media_channel()->GetOptions(&audio_options)) {
1520 LOG(LS_WARNING) << "Can not set audio options from on remote content.";
1521 } else {
1522 if (audio->conference_mode()) {
1523 audio_options.conference_mode.Set(true);
1524 }
1525 if (audio->agc_minus_10db()) {
1526 audio_options.adjust_agc_delta.Set(kAgcMinus10db);
1527 }
1528 if (!media_channel()->SetOptions(audio_options)) {
1529 // Log an error on failure, but don't abort the call.
1530 LOG(LS_ERROR) << "Failed to set voice channel options";
1531 }
1532 }
1533 }
1534
1535 // If everything worked, see if we can start sending.
1536 if (ret) {
1537 ChangeState();
1538 } else {
1539 LOG(LS_WARNING) << "Failed to set remote voice description";
1540 }
1541 return ret;
1542}
1543
1544bool VoiceChannel::SetRingbackTone_w(const void* buf, int len) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001545 ASSERT(worker_thread() == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001546 return media_channel()->SetRingbackTone(static_cast<const char*>(buf), len);
1547}
1548
1549bool VoiceChannel::PlayRingbackTone_w(uint32 ssrc, bool play, bool loop) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001550 ASSERT(worker_thread() == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001551 if (play) {
1552 LOG(LS_INFO) << "Playing ringback tone, loop=" << loop;
1553 } else {
1554 LOG(LS_INFO) << "Stopping ringback tone";
1555 }
1556 return media_channel()->PlayRingbackTone(ssrc, play, loop);
1557}
1558
1559void VoiceChannel::HandleEarlyMediaTimeout() {
1560 // This occurs on the main thread, not the worker thread.
1561 if (!received_media_) {
1562 LOG(LS_INFO) << "No early media received before timeout";
1563 SignalEarlyMediaTimeout(this);
1564 }
1565}
1566
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001567bool VoiceChannel::InsertDtmf_w(uint32 ssrc, int event, int duration,
1568 int flags) {
1569 if (!enabled()) {
1570 return false;
1571 }
1572
1573 return media_channel()->InsertDtmf(ssrc, event, duration, flags);
1574}
1575
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001576bool VoiceChannel::SetChannelOptions(const AudioOptions& options) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001577 return InvokeOnWorker(Bind(&VoiceMediaChannel::SetOptions,
1578 media_channel(), options));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001579}
1580
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001581void VoiceChannel::OnMessage(rtc::Message *pmsg) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001582 switch (pmsg->message_id) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001583 case MSG_EARLYMEDIATIMEOUT:
1584 HandleEarlyMediaTimeout();
1585 break;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001586 case MSG_CHANNEL_ERROR: {
1587 VoiceChannelErrorMessageData* data =
1588 static_cast<VoiceChannelErrorMessageData*>(pmsg->pdata);
1589 SignalMediaError(this, data->ssrc, data->error);
1590 delete data;
1591 break;
1592 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001593 default:
1594 BaseChannel::OnMessage(pmsg);
1595 break;
1596 }
1597}
1598
1599void VoiceChannel::OnConnectionMonitorUpdate(
1600 SocketMonitor* monitor, const std::vector<ConnectionInfo>& infos) {
1601 SignalConnectionMonitor(this, infos);
1602}
1603
1604void VoiceChannel::OnMediaMonitorUpdate(
1605 VoiceMediaChannel* media_channel, const VoiceMediaInfo& info) {
1606 ASSERT(media_channel == this->media_channel());
1607 SignalMediaMonitor(this, info);
1608}
1609
1610void VoiceChannel::OnAudioMonitorUpdate(AudioMonitor* monitor,
1611 const AudioInfo& info) {
1612 SignalAudioMonitor(this, info);
1613}
1614
1615void VoiceChannel::OnVoiceChannelError(
1616 uint32 ssrc, VoiceMediaChannel::Error err) {
1617 VoiceChannelErrorMessageData* data = new VoiceChannelErrorMessageData(
1618 ssrc, err);
1619 signaling_thread()->Post(this, MSG_CHANNEL_ERROR, data);
1620}
1621
1622void VoiceChannel::OnSrtpError(uint32 ssrc, SrtpFilter::Mode mode,
1623 SrtpFilter::Error error) {
1624 switch (error) {
1625 case SrtpFilter::ERROR_FAIL:
1626 OnVoiceChannelError(ssrc, (mode == SrtpFilter::PROTECT) ?
1627 VoiceMediaChannel::ERROR_REC_SRTP_ERROR :
1628 VoiceMediaChannel::ERROR_PLAY_SRTP_ERROR);
1629 break;
1630 case SrtpFilter::ERROR_AUTH:
1631 OnVoiceChannelError(ssrc, (mode == SrtpFilter::PROTECT) ?
1632 VoiceMediaChannel::ERROR_REC_SRTP_AUTH_FAILED :
1633 VoiceMediaChannel::ERROR_PLAY_SRTP_AUTH_FAILED);
1634 break;
1635 case SrtpFilter::ERROR_REPLAY:
1636 // Only receving channel should have this error.
1637 ASSERT(mode == SrtpFilter::UNPROTECT);
1638 OnVoiceChannelError(ssrc, VoiceMediaChannel::ERROR_PLAY_SRTP_REPLAY);
1639 break;
1640 default:
1641 break;
1642 }
1643}
1644
1645void VoiceChannel::GetSrtpCiphers(std::vector<std::string>* ciphers) const {
1646 GetSupportedAudioCryptoSuites(ciphers);
1647}
1648
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001649VideoChannel::VideoChannel(rtc::Thread* thread,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001650 MediaEngineInterface* media_engine,
1651 VideoMediaChannel* media_channel,
1652 BaseSession* session,
1653 const std::string& content_name,
1654 bool rtcp,
1655 VoiceChannel* voice_channel)
1656 : BaseChannel(thread, media_engine, media_channel, session, content_name,
1657 rtcp),
1658 voice_channel_(voice_channel),
1659 renderer_(NULL),
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001660 previous_we_(rtc::WE_CLOSE) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001661}
1662
1663bool VideoChannel::Init() {
1664 TransportChannel* rtcp_channel = rtcp() ? session()->CreateChannel(
1665 content_name(), "video_rtcp", ICE_CANDIDATE_COMPONENT_RTCP) : NULL;
1666 if (!BaseChannel::Init(session()->CreateChannel(
1667 content_name(), "video_rtp", ICE_CANDIDATE_COMPONENT_RTP),
1668 rtcp_channel)) {
1669 return false;
1670 }
1671 media_channel()->SignalMediaError.connect(
1672 this, &VideoChannel::OnVideoChannelError);
1673 srtp_filter()->SignalSrtpError.connect(
1674 this, &VideoChannel::OnSrtpError);
1675 return true;
1676}
1677
1678void VoiceChannel::SendLastMediaError() {
1679 uint32 ssrc;
1680 VoiceMediaChannel::Error error;
1681 media_channel()->GetLastMediaError(&ssrc, &error);
1682 SignalMediaError(this, ssrc, error);
1683}
1684
1685VideoChannel::~VideoChannel() {
1686 std::vector<uint32> screencast_ssrcs;
1687 ScreencastMap::iterator iter;
1688 while (!screencast_capturers_.empty()) {
1689 if (!RemoveScreencast(screencast_capturers_.begin()->first)) {
1690 LOG(LS_ERROR) << "Unable to delete screencast with ssrc "
1691 << screencast_capturers_.begin()->first;
1692 ASSERT(false);
1693 break;
1694 }
1695 }
1696
1697 StopMediaMonitor();
1698 // this can't be done in the base class, since it calls a virtual
1699 DisableMedia_w();
wu@webrtc.org78187522013-10-07 23:32:02 +00001700
1701 Deinit();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001702}
1703
1704bool VideoChannel::SetRenderer(uint32 ssrc, VideoRenderer* renderer) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001705 worker_thread()->Invoke<void>(Bind(
1706 &VideoMediaChannel::SetRenderer, media_channel(), ssrc, renderer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001707 return true;
1708}
1709
1710bool VideoChannel::ApplyViewRequest(const ViewRequest& request) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001711 return InvokeOnWorker(Bind(&VideoChannel::ApplyViewRequest_w, this, request));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001712}
1713
buildbot@webrtc.org65b98d12014-08-07 22:09:08 +00001714bool VideoChannel::AddScreencast(uint32 ssrc, VideoCapturer* capturer) {
1715 return worker_thread()->Invoke<bool>(Bind(
1716 &VideoChannel::AddScreencast_w, this, ssrc, capturer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001717}
1718
1719bool VideoChannel::SetCapturer(uint32 ssrc, VideoCapturer* capturer) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001720 return InvokeOnWorker(Bind(&VideoMediaChannel::SetCapturer,
1721 media_channel(), ssrc, capturer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001722}
1723
1724bool VideoChannel::RemoveScreencast(uint32 ssrc) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001725 return InvokeOnWorker(Bind(&VideoChannel::RemoveScreencast_w, this, ssrc));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001726}
1727
1728bool VideoChannel::IsScreencasting() {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001729 return InvokeOnWorker(Bind(&VideoChannel::IsScreencasting_w, this));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001730}
1731
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001732int VideoChannel::GetScreencastFps(uint32 ssrc) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001733 ScreencastDetailsData data(ssrc);
1734 worker_thread()->Invoke<void>(Bind(
1735 &VideoChannel::GetScreencastDetails_w, this, &data));
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001736 return data.fps;
1737}
1738
1739int VideoChannel::GetScreencastMaxPixels(uint32 ssrc) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001740 ScreencastDetailsData data(ssrc);
1741 worker_thread()->Invoke<void>(Bind(
1742 &VideoChannel::GetScreencastDetails_w, this, &data));
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001743 return data.screencast_max_pixels;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001744}
1745
1746bool VideoChannel::SendIntraFrame() {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001747 worker_thread()->Invoke<void>(Bind(
1748 &VideoMediaChannel::SendIntraFrame, media_channel()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001749 return true;
1750}
1751
1752bool VideoChannel::RequestIntraFrame() {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001753 worker_thread()->Invoke<void>(Bind(
1754 &VideoMediaChannel::RequestIntraFrame, media_channel()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001755 return true;
1756}
1757
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001758void VideoChannel::ChangeState() {
1759 // Render incoming data if we're the active call, and we have the local
1760 // content. We receive data on the default channel and multiplexed streams.
1761 bool recv = IsReadyToReceive();
1762 if (!media_channel()->SetRender(recv)) {
1763 LOG(LS_ERROR) << "Failed to SetRender on video channel";
1764 // TODO(gangji): Report error back to server.
1765 }
1766
1767 // Send outgoing data if we're the active call, we have the remote content,
1768 // and we have had some form of connectivity.
1769 bool send = IsReadyToSend();
1770 if (!media_channel()->SetSend(send)) {
1771 LOG(LS_ERROR) << "Failed to SetSend on video channel";
1772 // TODO(gangji): Report error back to server.
1773 }
1774
1775 LOG(LS_INFO) << "Changing video state, recv=" << recv << " send=" << send;
1776}
1777
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +00001778bool VideoChannel::GetStats(
1779 const StatsOptions& options, VideoMediaInfo* stats) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001780 return InvokeOnWorker(Bind(&VideoMediaChannel::GetStats,
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +00001781 media_channel(), options, stats));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001782}
1783
1784void VideoChannel::StartMediaMonitor(int cms) {
1785 media_monitor_.reset(new VideoMediaMonitor(media_channel(), worker_thread(),
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001786 rtc::Thread::Current()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001787 media_monitor_->SignalUpdate.connect(
1788 this, &VideoChannel::OnMediaMonitorUpdate);
1789 media_monitor_->Start(cms);
1790}
1791
1792void VideoChannel::StopMediaMonitor() {
1793 if (media_monitor_) {
1794 media_monitor_->Stop();
1795 media_monitor_.reset();
1796 }
1797}
1798
1799const ContentInfo* VideoChannel::GetFirstContent(
1800 const SessionDescription* sdesc) {
1801 return GetFirstVideoContent(sdesc);
1802}
1803
1804bool VideoChannel::SetLocalContent_w(const MediaContentDescription* content,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001805 ContentAction action,
1806 std::string* error_desc) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001807 ASSERT(worker_thread() == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001808 LOG(LS_INFO) << "Setting local video description";
1809
1810 const VideoContentDescription* video =
1811 static_cast<const VideoContentDescription*>(content);
1812 ASSERT(video != NULL);
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001813 if (!video) {
1814 SafeSetError("Can't find video content in local description.", error_desc);
1815 return false;
1816 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001817
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001818 bool ret = SetBaseLocalContent_w(content, action, error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001819 // Set local video codecs (what we want to receive).
1820 if (action != CA_UPDATE || video->has_codecs()) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001821 if (!media_channel()->SetRecvCodecs(video->codecs())) {
1822 SafeSetError("Failed to set video receive codecs.", error_desc);
1823 ret = false;
1824 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001825 }
1826
1827 if (action != CA_UPDATE) {
1828 VideoOptions video_options;
1829 media_channel()->GetOptions(&video_options);
1830 video_options.buffered_mode_latency.Set(video->buffered_mode_latency());
1831
1832 if (!media_channel()->SetOptions(video_options)) {
1833 // Log an error on failure, but don't abort the call.
1834 LOG(LS_ERROR) << "Failed to set video channel options";
1835 }
1836 }
1837
1838 // If everything worked, see if we can start receiving.
1839 if (ret) {
buildbot@webrtc.org5ee0f052014-05-05 20:18:08 +00001840 std::vector<VideoCodec>::const_iterator it = video->codecs().begin();
1841 for (; it != video->codecs().end(); ++it) {
1842 bundle_filter()->AddPayloadType(it->id);
1843 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001844 ChangeState();
1845 } else {
1846 LOG(LS_WARNING) << "Failed to set local video description";
1847 }
1848 return ret;
1849}
1850
1851bool VideoChannel::SetRemoteContent_w(const MediaContentDescription* content,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001852 ContentAction action,
1853 std::string* error_desc) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001854 ASSERT(worker_thread() == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001855 LOG(LS_INFO) << "Setting remote video description";
1856
1857 const VideoContentDescription* video =
1858 static_cast<const VideoContentDescription*>(content);
1859 ASSERT(video != NULL);
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001860 if (!video) {
1861 SafeSetError("Can't find video content in remote description.", error_desc);
1862 return false;
1863 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001864
1865 bool ret = true;
1866 // Set remote video codecs (what the other side wants to receive).
1867 if (action != CA_UPDATE || video->has_codecs()) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001868 if (!media_channel()->SetSendCodecs(video->codecs())) {
1869 SafeSetError("Failed to set video send codecs.", error_desc);
1870 ret = false;
1871 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001872 }
1873
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001874 ret &= SetBaseRemoteContent_w(content, action, error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001875
1876 if (action != CA_UPDATE) {
1877 // Tweak our video processing settings, if needed.
1878 VideoOptions video_options;
1879 media_channel()->GetOptions(&video_options);
wu@webrtc.org9caf2762013-12-11 18:25:07 +00001880 if (video->conference_mode()) {
1881 video_options.conference_mode.Set(true);
1882 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001883 video_options.buffered_mode_latency.Set(video->buffered_mode_latency());
1884
1885 if (!media_channel()->SetOptions(video_options)) {
1886 // Log an error on failure, but don't abort the call.
1887 LOG(LS_ERROR) << "Failed to set video channel options";
1888 }
1889 }
1890
1891 // If everything worked, see if we can start sending.
1892 if (ret) {
1893 ChangeState();
1894 } else {
1895 LOG(LS_WARNING) << "Failed to set remote video description";
1896 }
1897 return ret;
1898}
1899
1900bool VideoChannel::ApplyViewRequest_w(const ViewRequest& request) {
1901 bool ret = true;
1902 // Set the send format for each of the local streams. If the view request
1903 // does not contain a local stream, set its send format to 0x0, which will
1904 // drop all frames.
1905 for (std::vector<StreamParams>::const_iterator it = local_streams().begin();
1906 it != local_streams().end(); ++it) {
1907 VideoFormat format(0, 0, 0, cricket::FOURCC_I420);
1908 StaticVideoViews::const_iterator view;
1909 for (view = request.static_video_views.begin();
1910 view != request.static_video_views.end(); ++view) {
1911 if (view->selector.Matches(*it)) {
1912 format.width = view->width;
1913 format.height = view->height;
1914 format.interval = cricket::VideoFormat::FpsToInterval(view->framerate);
1915 break;
1916 }
1917 }
1918
1919 ret &= media_channel()->SetSendStreamFormat(it->first_ssrc(), format);
1920 }
1921
1922 // Check if the view request has invalid streams.
1923 for (StaticVideoViews::const_iterator it = request.static_video_views.begin();
1924 it != request.static_video_views.end(); ++it) {
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +00001925 if (!GetStream(local_streams(), it->selector)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001926 LOG(LS_WARNING) << "View request for ("
1927 << it->selector.ssrc << ", '"
1928 << it->selector.groupid << "', '"
1929 << it->selector.streamid << "'"
1930 << ") is not in the local streams.";
1931 }
1932 }
1933
1934 return ret;
1935}
1936
buildbot@webrtc.org65b98d12014-08-07 22:09:08 +00001937bool VideoChannel::AddScreencast_w(uint32 ssrc, VideoCapturer* capturer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001938 if (screencast_capturers_.find(ssrc) != screencast_capturers_.end()) {
buildbot@webrtc.org65b98d12014-08-07 22:09:08 +00001939 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001940 }
buildbot@webrtc.org65b98d12014-08-07 22:09:08 +00001941 capturer->SignalStateChange.connect(this, &VideoChannel::OnStateChange);
1942 screencast_capturers_[ssrc] = capturer;
1943 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001944}
1945
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001946bool VideoChannel::RemoveScreencast_w(uint32 ssrc) {
1947 ScreencastMap::iterator iter = screencast_capturers_.find(ssrc);
1948 if (iter == screencast_capturers_.end()) {
1949 return false;
1950 }
1951 // Clean up VideoCapturer.
1952 delete iter->second;
1953 screencast_capturers_.erase(iter);
1954 return true;
1955}
1956
1957bool VideoChannel::IsScreencasting_w() const {
1958 return !screencast_capturers_.empty();
1959}
1960
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001961void VideoChannel::GetScreencastDetails_w(
1962 ScreencastDetailsData* data) const {
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001963 ScreencastMap::const_iterator iter = screencast_capturers_.find(data->ssrc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001964 if (iter == screencast_capturers_.end()) {
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001965 return;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001966 }
1967 VideoCapturer* capturer = iter->second;
1968 const VideoFormat* video_format = capturer->GetCaptureFormat();
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001969 data->fps = VideoFormat::IntervalToFps(video_format->interval);
1970 data->screencast_max_pixels = capturer->screencast_max_pixels();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001971}
1972
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001973void VideoChannel::OnScreencastWindowEvent_s(uint32 ssrc,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001974 rtc::WindowEvent we) {
1975 ASSERT(signaling_thread() == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001976 SignalScreencastWindowEvent(ssrc, we);
1977}
1978
1979bool VideoChannel::SetChannelOptions(const VideoOptions &options) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00001980 return InvokeOnWorker(Bind(&VideoMediaChannel::SetOptions,
1981 media_channel(), options));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001982}
1983
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001984void VideoChannel::OnMessage(rtc::Message *pmsg) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001985 switch (pmsg->message_id) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001986 case MSG_SCREENCASTWINDOWEVENT: {
1987 const ScreencastEventMessageData* data =
1988 static_cast<ScreencastEventMessageData*>(pmsg->pdata);
1989 OnScreencastWindowEvent_s(data->ssrc, data->event);
1990 delete data;
1991 break;
1992 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001993 case MSG_CHANNEL_ERROR: {
1994 const VideoChannelErrorMessageData* data =
1995 static_cast<VideoChannelErrorMessageData*>(pmsg->pdata);
1996 SignalMediaError(this, data->ssrc, data->error);
1997 delete data;
1998 break;
1999 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002000 default:
2001 BaseChannel::OnMessage(pmsg);
2002 break;
2003 }
2004}
2005
2006void VideoChannel::OnConnectionMonitorUpdate(
2007 SocketMonitor *monitor, const std::vector<ConnectionInfo> &infos) {
2008 SignalConnectionMonitor(this, infos);
2009}
2010
2011// TODO(pthatcher): Look into removing duplicate code between
2012// audio, video, and data, perhaps by using templates.
2013void VideoChannel::OnMediaMonitorUpdate(
2014 VideoMediaChannel* media_channel, const VideoMediaInfo &info) {
2015 ASSERT(media_channel == this->media_channel());
2016 SignalMediaMonitor(this, info);
2017}
2018
2019void VideoChannel::OnScreencastWindowEvent(uint32 ssrc,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002020 rtc::WindowEvent event) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002021 ScreencastEventMessageData* pdata =
2022 new ScreencastEventMessageData(ssrc, event);
2023 signaling_thread()->Post(this, MSG_SCREENCASTWINDOWEVENT, pdata);
2024}
2025
2026void VideoChannel::OnStateChange(VideoCapturer* capturer, CaptureState ev) {
2027 // Map capturer events to window events. In the future we may want to simply
2028 // pass these events up directly.
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002029 rtc::WindowEvent we;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002030 if (ev == CS_STOPPED) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002031 we = rtc::WE_CLOSE;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002032 } else if (ev == CS_PAUSED) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002033 we = rtc::WE_MINIMIZE;
2034 } else if (ev == CS_RUNNING && previous_we_ == rtc::WE_MINIMIZE) {
2035 we = rtc::WE_RESTORE;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002036 } else {
2037 return;
2038 }
2039 previous_we_ = we;
2040
2041 uint32 ssrc = 0;
2042 if (!GetLocalSsrc(capturer, &ssrc)) {
2043 return;
2044 }
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00002045
2046 OnScreencastWindowEvent(ssrc, we);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002047}
2048
2049bool VideoChannel::GetLocalSsrc(const VideoCapturer* capturer, uint32* ssrc) {
2050 *ssrc = 0;
2051 for (ScreencastMap::iterator iter = screencast_capturers_.begin();
2052 iter != screencast_capturers_.end(); ++iter) {
2053 if (iter->second == capturer) {
2054 *ssrc = iter->first;
2055 return true;
2056 }
2057 }
2058 return false;
2059}
2060
2061void VideoChannel::OnVideoChannelError(uint32 ssrc,
2062 VideoMediaChannel::Error error) {
2063 VideoChannelErrorMessageData* data = new VideoChannelErrorMessageData(
2064 ssrc, error);
2065 signaling_thread()->Post(this, MSG_CHANNEL_ERROR, data);
2066}
2067
2068void VideoChannel::OnSrtpError(uint32 ssrc, SrtpFilter::Mode mode,
2069 SrtpFilter::Error error) {
2070 switch (error) {
2071 case SrtpFilter::ERROR_FAIL:
2072 OnVideoChannelError(ssrc, (mode == SrtpFilter::PROTECT) ?
2073 VideoMediaChannel::ERROR_REC_SRTP_ERROR :
2074 VideoMediaChannel::ERROR_PLAY_SRTP_ERROR);
2075 break;
2076 case SrtpFilter::ERROR_AUTH:
2077 OnVideoChannelError(ssrc, (mode == SrtpFilter::PROTECT) ?
2078 VideoMediaChannel::ERROR_REC_SRTP_AUTH_FAILED :
2079 VideoMediaChannel::ERROR_PLAY_SRTP_AUTH_FAILED);
2080 break;
2081 case SrtpFilter::ERROR_REPLAY:
2082 // Only receving channel should have this error.
2083 ASSERT(mode == SrtpFilter::UNPROTECT);
2084 // TODO(gangji): Turn on the signaling of replay error once we have
2085 // switched to the new mechanism for doing video retransmissions.
2086 // OnVideoChannelError(ssrc, VideoMediaChannel::ERROR_PLAY_SRTP_REPLAY);
2087 break;
2088 default:
2089 break;
2090 }
2091}
2092
2093
2094void VideoChannel::GetSrtpCiphers(std::vector<std::string>* ciphers) const {
2095 GetSupportedVideoCryptoSuites(ciphers);
2096}
2097
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002098DataChannel::DataChannel(rtc::Thread* thread,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002099 DataMediaChannel* media_channel,
2100 BaseSession* session,
2101 const std::string& content_name,
2102 bool rtcp)
2103 // MediaEngine is NULL
2104 : BaseChannel(thread, NULL, media_channel, session, content_name, rtcp),
wu@webrtc.org07a6fbe2013-11-04 18:41:34 +00002105 data_channel_type_(cricket::DCT_NONE),
2106 ready_to_send_data_(false) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002107}
2108
2109DataChannel::~DataChannel() {
2110 StopMediaMonitor();
2111 // this can't be done in the base class, since it calls a virtual
2112 DisableMedia_w();
wu@webrtc.org78187522013-10-07 23:32:02 +00002113
2114 Deinit();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002115}
2116
2117bool DataChannel::Init() {
2118 TransportChannel* rtcp_channel = rtcp() ? session()->CreateChannel(
2119 content_name(), "data_rtcp", ICE_CANDIDATE_COMPONENT_RTCP) : NULL;
2120 if (!BaseChannel::Init(session()->CreateChannel(
2121 content_name(), "data_rtp", ICE_CANDIDATE_COMPONENT_RTP),
2122 rtcp_channel)) {
2123 return false;
2124 }
2125 media_channel()->SignalDataReceived.connect(
2126 this, &DataChannel::OnDataReceived);
2127 media_channel()->SignalMediaError.connect(
2128 this, &DataChannel::OnDataChannelError);
wu@webrtc.orgd64719d2013-08-01 00:00:07 +00002129 media_channel()->SignalReadyToSend.connect(
2130 this, &DataChannel::OnDataChannelReadyToSend);
buildbot@webrtc.org1d66be22014-05-29 22:54:24 +00002131 media_channel()->SignalStreamClosedRemotely.connect(
2132 this, &DataChannel::OnStreamClosedRemotely);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002133 srtp_filter()->SignalSrtpError.connect(
2134 this, &DataChannel::OnSrtpError);
2135 return true;
2136}
2137
2138bool DataChannel::SendData(const SendDataParams& params,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002139 const rtc::Buffer& payload,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002140 SendDataResult* result) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00002141 return InvokeOnWorker(Bind(&DataMediaChannel::SendData,
2142 media_channel(), params, payload, result));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002143}
2144
2145const ContentInfo* DataChannel::GetFirstContent(
2146 const SessionDescription* sdesc) {
2147 return GetFirstDataContent(sdesc);
2148}
2149
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002150bool DataChannel::WantsPacket(bool rtcp, rtc::Buffer* packet) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002151 if (data_channel_type_ == DCT_SCTP) {
2152 // TODO(pthatcher): Do this in a more robust way by checking for
2153 // SCTP or DTLS.
buildbot@webrtc.org1ef789d2014-06-19 23:54:12 +00002154 return !IsRtpPacket(packet->data(), packet->length());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002155 } else if (data_channel_type_ == DCT_RTP) {
2156 return BaseChannel::WantsPacket(rtcp, packet);
2157 }
2158 return false;
2159}
2160
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00002161bool DataChannel::SetDataChannelType(DataChannelType new_data_channel_type,
2162 std::string* error_desc) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002163 // It hasn't been set before, so set it now.
2164 if (data_channel_type_ == DCT_NONE) {
2165 data_channel_type_ = new_data_channel_type;
2166 return true;
2167 }
2168
2169 // It's been set before, but doesn't match. That's bad.
2170 if (data_channel_type_ != new_data_channel_type) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00002171 std::ostringstream desc;
2172 desc << "Data channel type mismatch."
2173 << " Expected " << data_channel_type_
2174 << " Got " << new_data_channel_type;
2175 SafeSetError(desc.str(), error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002176 return false;
2177 }
2178
2179 // It's hasn't changed. Nothing to do.
2180 return true;
2181}
2182
2183bool DataChannel::SetDataChannelTypeFromContent(
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00002184 const DataContentDescription* content,
2185 std::string* error_desc) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002186 bool is_sctp = ((content->protocol() == kMediaProtocolSctp) ||
2187 (content->protocol() == kMediaProtocolDtlsSctp));
2188 DataChannelType data_channel_type = is_sctp ? DCT_SCTP : DCT_RTP;
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00002189 return SetDataChannelType(data_channel_type, error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002190}
2191
2192bool DataChannel::SetLocalContent_w(const MediaContentDescription* content,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00002193 ContentAction action,
2194 std::string* error_desc) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002195 ASSERT(worker_thread() == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002196 LOG(LS_INFO) << "Setting local data description";
2197
2198 const DataContentDescription* data =
2199 static_cast<const DataContentDescription*>(content);
2200 ASSERT(data != NULL);
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00002201 if (!data) {
2202 SafeSetError("Can't find data content in local description.", error_desc);
2203 return false;
2204 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002205
2206 bool ret = false;
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00002207 if (!SetDataChannelTypeFromContent(data, error_desc)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002208 return false;
2209 }
2210
2211 if (data_channel_type_ == DCT_SCTP) {
2212 // SCTP data channels don't need the rest of the stuff.
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00002213 ret = UpdateLocalStreams_w(data->streams(), action, error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002214 if (ret) {
2215 set_local_content_direction(content->direction());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002216 // As in SetRemoteContent_w, make sure we set the local SCTP port
2217 // number as specified in our DataContentDescription.
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00002218 if (!media_channel()->SetRecvCodecs(data->codecs())) {
2219 SafeSetError("Failed to set data receive codecs.", error_desc);
2220 ret = false;
2221 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002222 }
2223 } else {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00002224 ret = SetBaseLocalContent_w(content, action, error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002225 if (action != CA_UPDATE || data->has_codecs()) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00002226 if (!media_channel()->SetRecvCodecs(data->codecs())) {
2227 SafeSetError("Failed to set data receive codecs.", error_desc);
2228 ret = false;
2229 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002230 }
2231 }
2232
2233 // If everything worked, see if we can start receiving.
2234 if (ret) {
buildbot@webrtc.org5ee0f052014-05-05 20:18:08 +00002235 std::vector<DataCodec>::const_iterator it = data->codecs().begin();
2236 for (; it != data->codecs().end(); ++it) {
2237 bundle_filter()->AddPayloadType(it->id);
2238 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002239 ChangeState();
2240 } else {
2241 LOG(LS_WARNING) << "Failed to set local data description";
2242 }
2243 return ret;
2244}
2245
2246bool DataChannel::SetRemoteContent_w(const MediaContentDescription* content,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00002247 ContentAction action,
2248 std::string* error_desc) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002249 ASSERT(worker_thread() == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002250
2251 const DataContentDescription* data =
2252 static_cast<const DataContentDescription*>(content);
2253 ASSERT(data != NULL);
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00002254 if (!data) {
2255 SafeSetError("Can't find data content in remote description.", error_desc);
2256 return false;
2257 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002258
2259 bool ret = true;
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00002260 if (!SetDataChannelTypeFromContent(data, error_desc)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002261 return false;
2262 }
2263
2264 if (data_channel_type_ == DCT_SCTP) {
2265 LOG(LS_INFO) << "Setting SCTP remote data description";
2266 // SCTP data channels don't need the rest of the stuff.
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00002267 ret = UpdateRemoteStreams_w(content->streams(), action, error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002268 if (ret) {
2269 set_remote_content_direction(content->direction());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002270 // We send the SCTP port number (not to be confused with the underlying
2271 // UDP port number) as a codec parameter. Make sure it gets there.
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00002272 if (!media_channel()->SetSendCodecs(data->codecs())) {
2273 SafeSetError("Failed to set data send codecs.", error_desc);
2274 ret = false;
2275 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002276 }
2277 } else {
2278 // If the remote data doesn't have codecs and isn't an update, it
2279 // must be empty, so ignore it.
2280 if (action != CA_UPDATE && !data->has_codecs()) {
2281 return true;
2282 }
2283 LOG(LS_INFO) << "Setting remote data description";
2284
2285 // Set remote video codecs (what the other side wants to receive).
2286 if (action != CA_UPDATE || data->has_codecs()) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00002287 if (!media_channel()->SetSendCodecs(data->codecs())) {
2288 SafeSetError("Failed to set data send codecs.", error_desc);
2289 ret = false;
2290 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002291 }
2292
2293 if (ret) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00002294 ret &= SetBaseRemoteContent_w(content, action, error_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002295 }
2296
2297 if (action != CA_UPDATE) {
2298 int bandwidth_bps = data->bandwidth();
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00002299 if (!media_channel()->SetMaxSendBandwidth(bandwidth_bps)) {
2300 std::ostringstream desc;
2301 desc << "Failed to set max send bandwidth for data content.";
2302 SafeSetError(desc.str(), error_desc);
2303 ret = false;
2304 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002305 }
2306 }
2307
2308 // If everything worked, see if we can start sending.
2309 if (ret) {
2310 ChangeState();
2311 } else {
2312 LOG(LS_WARNING) << "Failed to set remote data description";
2313 }
2314 return ret;
2315}
2316
2317void DataChannel::ChangeState() {
2318 // Render incoming data if we're the active call, and we have the local
2319 // content. We receive data on the default channel and multiplexed streams.
2320 bool recv = IsReadyToReceive();
2321 if (!media_channel()->SetReceive(recv)) {
2322 LOG(LS_ERROR) << "Failed to SetReceive on data channel";
2323 }
2324
2325 // Send outgoing data if we're the active call, we have the remote content,
2326 // and we have had some form of connectivity.
2327 bool send = IsReadyToSend();
2328 if (!media_channel()->SetSend(send)) {
2329 LOG(LS_ERROR) << "Failed to SetSend on data channel";
2330 }
2331
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +00002332 // Trigger SignalReadyToSendData asynchronously.
2333 OnDataChannelReadyToSend(send);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002334
2335 LOG(LS_INFO) << "Changing data state, recv=" << recv << " send=" << send;
2336}
2337
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002338void DataChannel::OnMessage(rtc::Message *pmsg) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002339 switch (pmsg->message_id) {
2340 case MSG_READYTOSENDDATA: {
wu@webrtc.orgd64719d2013-08-01 00:00:07 +00002341 DataChannelReadyToSendMessageData* data =
2342 static_cast<DataChannelReadyToSendMessageData*>(pmsg->pdata);
wu@webrtc.org07a6fbe2013-11-04 18:41:34 +00002343 ready_to_send_data_ = data->data();
2344 SignalReadyToSendData(ready_to_send_data_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002345 delete data;
2346 break;
2347 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002348 case MSG_DATARECEIVED: {
2349 DataReceivedMessageData* data =
2350 static_cast<DataReceivedMessageData*>(pmsg->pdata);
2351 SignalDataReceived(this, data->params, data->payload);
2352 delete data;
2353 break;
2354 }
2355 case MSG_CHANNEL_ERROR: {
2356 const DataChannelErrorMessageData* data =
2357 static_cast<DataChannelErrorMessageData*>(pmsg->pdata);
2358 SignalMediaError(this, data->ssrc, data->error);
2359 delete data;
2360 break;
2361 }
buildbot@webrtc.org1d66be22014-05-29 22:54:24 +00002362 case MSG_STREAMCLOSEDREMOTELY: {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002363 rtc::TypedMessageData<uint32>* data =
2364 static_cast<rtc::TypedMessageData<uint32>*>(pmsg->pdata);
buildbot@webrtc.org1d66be22014-05-29 22:54:24 +00002365 SignalStreamClosedRemotely(data->data());
2366 delete data;
2367 break;
2368 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002369 default:
2370 BaseChannel::OnMessage(pmsg);
2371 break;
2372 }
2373}
2374
2375void DataChannel::OnConnectionMonitorUpdate(
2376 SocketMonitor* monitor, const std::vector<ConnectionInfo>& infos) {
2377 SignalConnectionMonitor(this, infos);
2378}
2379
2380void DataChannel::StartMediaMonitor(int cms) {
2381 media_monitor_.reset(new DataMediaMonitor(media_channel(), worker_thread(),
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002382 rtc::Thread::Current()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002383 media_monitor_->SignalUpdate.connect(
2384 this, &DataChannel::OnMediaMonitorUpdate);
2385 media_monitor_->Start(cms);
2386}
2387
2388void DataChannel::StopMediaMonitor() {
2389 if (media_monitor_) {
2390 media_monitor_->Stop();
2391 media_monitor_->SignalUpdate.disconnect(this);
2392 media_monitor_.reset();
2393 }
2394}
2395
2396void DataChannel::OnMediaMonitorUpdate(
2397 DataMediaChannel* media_channel, const DataMediaInfo& info) {
2398 ASSERT(media_channel == this->media_channel());
2399 SignalMediaMonitor(this, info);
2400}
2401
2402void DataChannel::OnDataReceived(
2403 const ReceiveDataParams& params, const char* data, size_t len) {
2404 DataReceivedMessageData* msg = new DataReceivedMessageData(
2405 params, data, len);
2406 signaling_thread()->Post(this, MSG_DATARECEIVED, msg);
2407}
2408
2409void DataChannel::OnDataChannelError(
2410 uint32 ssrc, DataMediaChannel::Error err) {
2411 DataChannelErrorMessageData* data = new DataChannelErrorMessageData(
2412 ssrc, err);
2413 signaling_thread()->Post(this, MSG_CHANNEL_ERROR, data);
2414}
2415
wu@webrtc.orgd64719d2013-08-01 00:00:07 +00002416void DataChannel::OnDataChannelReadyToSend(bool writable) {
2417 // This is usded for congestion control to indicate that the stream is ready
2418 // to send by the MediaChannel, as opposed to OnReadyToSend, which indicates
2419 // that the transport channel is ready.
2420 signaling_thread()->Post(this, MSG_READYTOSENDDATA,
2421 new DataChannelReadyToSendMessageData(writable));
2422}
2423
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002424void DataChannel::OnSrtpError(uint32 ssrc, SrtpFilter::Mode mode,
2425 SrtpFilter::Error error) {
2426 switch (error) {
2427 case SrtpFilter::ERROR_FAIL:
2428 OnDataChannelError(ssrc, (mode == SrtpFilter::PROTECT) ?
2429 DataMediaChannel::ERROR_SEND_SRTP_ERROR :
2430 DataMediaChannel::ERROR_RECV_SRTP_ERROR);
2431 break;
2432 case SrtpFilter::ERROR_AUTH:
2433 OnDataChannelError(ssrc, (mode == SrtpFilter::PROTECT) ?
2434 DataMediaChannel::ERROR_SEND_SRTP_AUTH_FAILED :
2435 DataMediaChannel::ERROR_RECV_SRTP_AUTH_FAILED);
2436 break;
2437 case SrtpFilter::ERROR_REPLAY:
2438 // Only receving channel should have this error.
2439 ASSERT(mode == SrtpFilter::UNPROTECT);
2440 OnDataChannelError(ssrc, DataMediaChannel::ERROR_RECV_SRTP_REPLAY);
2441 break;
2442 default:
2443 break;
2444 }
2445}
2446
2447void DataChannel::GetSrtpCiphers(std::vector<std::string>* ciphers) const {
2448 GetSupportedDataCryptoSuites(ciphers);
2449}
2450
2451bool DataChannel::ShouldSetupDtlsSrtp() const {
2452 return (data_channel_type_ == DCT_RTP);
2453}
2454
buildbot@webrtc.org1d66be22014-05-29 22:54:24 +00002455void DataChannel::OnStreamClosedRemotely(uint32 sid) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002456 rtc::TypedMessageData<uint32>* message =
2457 new rtc::TypedMessageData<uint32>(sid);
buildbot@webrtc.org1d66be22014-05-29 22:54:24 +00002458 signaling_thread()->Post(this, MSG_STREAMCLOSEDREMOTELY, message);
2459}
2460
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002461} // namespace cricket