• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libjingle
3  * Copyright 2004--2007, 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/phone/channel.h"
29 
30 #include "talk/base/buffer.h"
31 #include "talk/base/byteorder.h"
32 #include "talk/base/common.h"
33 #include "talk/base/logging.h"
34 #include "talk/p2p/base/transportchannel.h"
35 #include "talk/session/phone/channelmanager.h"
36 #include "talk/session/phone/mediasessionclient.h"
37 #include "talk/session/phone/mediasink.h"
38 #include "talk/session/phone/rtcpmuxfilter.h"
39 
40 namespace cricket {
41 
42 struct PacketMessageData : public talk_base::MessageData {
43   talk_base::Buffer packet;
44 };
45 
46 struct VoiceChannelErrorMessageData : public talk_base::MessageData {
VoiceChannelErrorMessageDatacricket::VoiceChannelErrorMessageData47   VoiceChannelErrorMessageData(uint32 in_ssrc,
48                                VoiceMediaChannel::Error in_error)
49       : ssrc(in_ssrc),
50         error(in_error) {}
51   uint32 ssrc;
52   VoiceMediaChannel::Error error;
53 };
54 
55 struct VideoChannelErrorMessageData : public talk_base::MessageData {
VideoChannelErrorMessageDatacricket::VideoChannelErrorMessageData56   VideoChannelErrorMessageData(uint32 in_ssrc,
57                                VideoMediaChannel::Error in_error)
58       : ssrc(in_ssrc),
59         error(in_error) {}
60   uint32 ssrc;
61   VideoMediaChannel::Error error;
62 };
63 
PacketType(bool rtcp)64 static const char* PacketType(bool rtcp) {
65   return (!rtcp) ? "RTP" : "RTCP";
66 }
67 
ValidPacket(bool rtcp,const talk_base::Buffer * packet)68 static bool ValidPacket(bool rtcp, const talk_base::Buffer* packet) {
69   // Check the packet size. We could check the header too if needed.
70   return (packet &&
71       packet->length() >= (!rtcp ? kMinRtpPacketLen : kMinRtcpPacketLen) &&
72       packet->length() <= kMaxRtpPacketLen);
73 }
74 
GetRtpSeqNum(const talk_base::Buffer * packet)75 static uint16 GetRtpSeqNum(const talk_base::Buffer* packet) {
76   return (packet->length() >= kMinRtpPacketLen) ?
77        talk_base::GetBE16(packet->data() + 2) : 0;
78 }
79 
GetRtpSsrc(const talk_base::Buffer * packet)80 static uint32 GetRtpSsrc(const talk_base::Buffer* packet) {
81   return (packet->length() >= kMinRtpPacketLen) ?
82        talk_base::GetBE32(packet->data() + 8) : 0;
83 }
84 
GetRtcpType(const talk_base::Buffer * packet)85 static int GetRtcpType(const talk_base::Buffer* packet) {
86   return (packet->length() >= kMinRtcpPacketLen) ?
87        static_cast<int>(packet->data()[1]) : 0;
88 }
89 
BaseChannel(talk_base::Thread * thread,MediaEngine * media_engine,MediaChannel * media_channel,BaseSession * session,const std::string & content_name,TransportChannel * transport_channel)90 BaseChannel::BaseChannel(talk_base::Thread* thread, MediaEngine* media_engine,
91                          MediaChannel* media_channel, BaseSession* session,
92                          const std::string& content_name,
93                          TransportChannel* transport_channel)
94     : worker_thread_(thread),
95       media_engine_(media_engine),
96       session_(session),
97       media_channel_(media_channel),
98       received_media_sink_(NULL),
99       sent_media_sink_(NULL),
100       content_name_(content_name),
101       transport_channel_(transport_channel),
102       rtcp_transport_channel_(NULL),
103       enabled_(false),
104       writable_(false),
105       has_codec_(false),
106       muted_(false) {
107   ASSERT(worker_thread_ == talk_base::Thread::Current());
108   media_channel_->SetInterface(this);
109   transport_channel_->SignalWritableState.connect(
110       this, &BaseChannel::OnWritableState);
111   transport_channel_->SignalReadPacket.connect(
112       this, &BaseChannel::OnChannelRead);
113 
114   LOG(LS_INFO) << "Created channel";
115 
116   session->SignalState.connect(this, &BaseChannel::OnSessionState);
117 }
118 
~BaseChannel()119 BaseChannel::~BaseChannel() {
120   ASSERT(worker_thread_ == talk_base::Thread::Current());
121   StopConnectionMonitor();
122   FlushRtcpMessages();  // Send any outstanding RTCP packets.
123   Clear();  // eats any outstanding messages or packets
124   // We must destroy the media channel before the transport channel, otherwise
125   // the media channel may try to send on the dead transport channel. NULLing
126   // is not an effective strategy since the sends will come on another thread.
127   delete media_channel_;
128   set_rtcp_transport_channel(NULL);
129   if (transport_channel_ != NULL)
130     session_->DestroyChannel(content_name_, transport_channel_->name());
131   LOG(LS_INFO) << "Destroyed channel";
132 }
133 
Enable(bool enable)134 bool BaseChannel::Enable(bool enable) {
135   // Can be called from thread other than worker thread
136   Send(enable ? MSG_ENABLE : MSG_DISABLE);
137   return true;
138 }
139 
Mute(bool mute)140 bool BaseChannel::Mute(bool mute) {
141   // Can be called from thread other than worker thread
142   Send(mute ? MSG_MUTE : MSG_UNMUTE);
143   return true;
144 }
145 
RemoveStream(uint32 ssrc)146 bool BaseChannel::RemoveStream(uint32 ssrc) {
147   StreamMessageData data(ssrc, 0);
148   Send(MSG_REMOVESTREAM, &data);
149   return true;
150 }
151 
SetRtcpCName(const std::string & cname)152 bool BaseChannel::SetRtcpCName(const std::string& cname) {
153   SetRtcpCNameData data(cname);
154   Send(MSG_SETRTCPCNAME, &data);
155   return data.result;
156 }
157 
SetLocalContent(const MediaContentDescription * content,ContentAction action)158 bool BaseChannel::SetLocalContent(const MediaContentDescription* content,
159                                   ContentAction action) {
160   SetContentData data(content, action);
161   Send(MSG_SETLOCALCONTENT, &data);
162   return data.result;
163 }
164 
SetRemoteContent(const MediaContentDescription * content,ContentAction action)165 bool BaseChannel::SetRemoteContent(const MediaContentDescription* content,
166                                    ContentAction action) {
167   SetContentData data(content, action);
168   Send(MSG_SETREMOTECONTENT, &data);
169   return data.result;
170 }
171 
SetMaxSendBandwidth(int max_bandwidth)172 bool BaseChannel::SetMaxSendBandwidth(int max_bandwidth) {
173   SetBandwidthData data(max_bandwidth);
174   Send(MSG_SETMAXSENDBANDWIDTH, &data);
175   return data.result;
176 }
177 
StartConnectionMonitor(int cms)178 void BaseChannel::StartConnectionMonitor(int cms) {
179   socket_monitor_.reset(new SocketMonitor(transport_channel_,
180                                           worker_thread(),
181                                           talk_base::Thread::Current()));
182   socket_monitor_->SignalUpdate.connect(
183       this, &BaseChannel::OnConnectionMonitorUpdate);
184   socket_monitor_->Start(cms);
185 }
186 
StopConnectionMonitor()187 void BaseChannel::StopConnectionMonitor() {
188   if (socket_monitor_.get()) {
189     socket_monitor_->Stop();
190     socket_monitor_.reset();
191   }
192 }
193 
set_rtcp_transport_channel(TransportChannel * channel)194 void BaseChannel::set_rtcp_transport_channel(TransportChannel* channel) {
195   if (rtcp_transport_channel_ != channel) {
196     if (rtcp_transport_channel_) {
197       session_->DestroyChannel(content_name_, rtcp_transport_channel_->name());
198     }
199     rtcp_transport_channel_ = channel;
200     if (rtcp_transport_channel_) {
201       rtcp_transport_channel_->SignalWritableState.connect(
202           this, &BaseChannel::OnWritableState);
203       rtcp_transport_channel_->SignalReadPacket.connect(
204           this, &BaseChannel::OnChannelRead);
205     }
206   }
207 }
208 
SendPacket(talk_base::Buffer * packet)209 bool BaseChannel::SendPacket(talk_base::Buffer* packet) {
210   return SendPacket(false, packet);
211 }
212 
SendRtcp(talk_base::Buffer * packet)213 bool BaseChannel::SendRtcp(talk_base::Buffer* packet) {
214   return SendPacket(true, packet);
215 }
216 
SetOption(SocketType type,talk_base::Socket::Option opt,int value)217 int BaseChannel::SetOption(SocketType type, talk_base::Socket::Option opt,
218                            int value) {
219   switch (type) {
220     case ST_RTP: return transport_channel_->SetOption(opt, value);
221     case ST_RTCP: return rtcp_transport_channel_->SetOption(opt, value);
222     default: return -1;
223   }
224 }
225 
OnWritableState(TransportChannel * channel)226 void BaseChannel::OnWritableState(TransportChannel* channel) {
227   ASSERT(channel == transport_channel_ || channel == rtcp_transport_channel_);
228   if (transport_channel_->writable()
229       && (!rtcp_transport_channel_ || rtcp_transport_channel_->writable())) {
230     ChannelWritable_w();
231   } else {
232     ChannelNotWritable_w();
233   }
234 }
235 
OnChannelRead(TransportChannel * channel,const char * data,size_t len)236 void BaseChannel::OnChannelRead(TransportChannel* channel,
237                                 const char* data, size_t len) {
238   // OnChannelRead gets called from P2PSocket; now pass data to MediaEngine
239   ASSERT(worker_thread_ == talk_base::Thread::Current());
240 
241   talk_base::Buffer packet(data, len);
242   // When using RTCP multiplexing we might get RTCP packets on the RTP
243   // transport. We feed RTP traffic into the demuxer to determine if it is RTCP.
244   bool rtcp = (channel == rtcp_transport_channel_ ||
245                rtcp_mux_filter_.DemuxRtcp(packet.data(), packet.length()));
246   HandlePacket(rtcp, &packet);
247 }
248 
SendPacket(bool rtcp,talk_base::Buffer * packet)249 bool BaseChannel::SendPacket(bool rtcp, talk_base::Buffer* packet) {
250   // SendPacket gets called from MediaEngine, typically on an encoder thread.
251   // If the thread is not our worker thread, we will post to our worker
252   // so that the real work happens on our worker. This avoids us having to
253   // synchronize access to all the pieces of the send path, including
254   // SRTP and the inner workings of the transport channels.
255   // The only downside is that we can't return a proper failure code if
256   // needed. Since UDP is unreliable anyway, this should be a non-issue.
257   if (talk_base::Thread::Current() != worker_thread_) {
258     // Avoid a copy by transferring the ownership of the packet data.
259     int message_id = (!rtcp) ? MSG_RTPPACKET : MSG_RTCPPACKET;
260     PacketMessageData* data = new PacketMessageData;
261     packet->TransferTo(&data->packet);
262     worker_thread_->Post(this, message_id, data);
263     return true;
264   }
265 
266   // Make sure we have a place to send this packet before doing anything.
267   // (We might get RTCP packets that we don't intend to send.)
268   // If we've negotiated RTCP mux, send RTCP over the RTP transport.
269   TransportChannel* channel = (!rtcp || rtcp_mux_filter_.IsActive()) ?
270       transport_channel_ : rtcp_transport_channel_;
271   if (!channel) {
272     return false;
273   }
274 
275   // Protect ourselves against crazy data.
276   if (!ValidPacket(rtcp, packet)) {
277     LOG(LS_ERROR) << "Dropping outgoing " << content_name_ << " "
278                   << PacketType(rtcp) << " packet: wrong size="
279                   << packet->length();
280     return false;
281   }
282 
283   // Push the packet down to the media sink.
284   // Need to do this before protecting the packet.
285   {
286     talk_base::CritScope cs(&sink_critical_section_);
287     if (sent_media_sink_) {
288       if (!rtcp) {
289         sent_media_sink_->OnRtpPacket(packet->data(), packet->length());
290       } else {
291         sent_media_sink_->OnRtcpPacket(packet->data(), packet->length());
292       }
293     }
294   }
295 
296   // Protect if needed.
297   if (srtp_filter_.IsActive()) {
298     bool res;
299     char* data = packet->data();
300     int len = packet->length();
301     if (!rtcp) {
302       res = srtp_filter_.ProtectRtp(data, len, packet->capacity(), &len);
303       if (!res) {
304         LOG(LS_ERROR) << "Failed to protect " << content_name_
305                       << " RTP packet: size=" << len
306                       << ", seqnum=" << GetRtpSeqNum(packet)
307                       << ", SSRC=" << GetRtpSsrc(packet);
308         return false;
309       }
310     } else {
311       res = srtp_filter_.ProtectRtcp(data, len, packet->capacity(), &len);
312       if (!res) {
313         LOG(LS_ERROR) << "Failed to protect " << content_name_
314                      << " RTCP packet: size=" << len
315                       << ", type=" << GetRtcpType(packet);
316         return false;
317       }
318     }
319 
320     // Update the length of the packet now that we've added the auth tag.
321     packet->SetLength(len);
322   }
323 
324   // Bon voyage.
325   return (channel->SendPacket(packet->data(), packet->length())
326       == static_cast<int>(packet->length()));
327 }
328 
HandlePacket(bool rtcp,talk_base::Buffer * packet)329 void BaseChannel::HandlePacket(bool rtcp, talk_base::Buffer* packet) {
330   // Protect ourselvs against crazy data.
331   if (!ValidPacket(rtcp, packet)) {
332     LOG(LS_ERROR) << "Dropping incoming " << content_name_ << " "
333                   << PacketType(rtcp) << " packet: wrong size="
334                   << packet->length();
335     return;
336   }
337 
338   // Unprotect the packet, if needed.
339   if (srtp_filter_.IsActive()) {
340     char* data = packet->data();
341     int len = packet->length();
342     bool res;
343     if (!rtcp) {
344       res = srtp_filter_.UnprotectRtp(data, len, &len);
345       if (!res) {
346         LOG(LS_ERROR) << "Failed to unprotect " << content_name_
347                       << " RTP packet: size=" << len
348                       << ", seqnum=" << GetRtpSeqNum(packet)
349                       << ", SSRC=" << GetRtpSsrc(packet);
350         return;
351       }
352     } else {
353       res = srtp_filter_.UnprotectRtcp(data, len, &len);
354       if (!res) {
355         LOG(LS_ERROR) << "Failed to unprotect " << content_name_
356                       << " RTCP packet: size=" << len
357                       << ", type=" << GetRtcpType(packet);
358         return;
359       }
360     }
361 
362     packet->SetLength(len);
363   }
364 
365   // Push it down to the media channel.
366   if (!rtcp) {
367     media_channel_->OnPacketReceived(packet);
368   } else {
369     media_channel_->OnRtcpReceived(packet);
370   }
371 
372   // Push it down to the media sink.
373   {
374     talk_base::CritScope cs(&sink_critical_section_);
375     if (received_media_sink_) {
376       if (!rtcp) {
377         received_media_sink_->OnRtpPacket(packet->data(), packet->length());
378       } else {
379         received_media_sink_->OnRtcpPacket(packet->data(), packet->length());
380       }
381     }
382   }
383 }
384 
OnSessionState(BaseSession * session,BaseSession::State state)385 void BaseChannel::OnSessionState(BaseSession* session,
386                                  BaseSession::State state) {
387   const MediaContentDescription* content = NULL;
388   switch (state) {
389     case Session::STATE_SENTINITIATE:
390       content = GetFirstContent(session->local_description());
391       if (content && !SetLocalContent(content, CA_OFFER)) {
392         LOG(LS_ERROR) << "Failure in SetLocalContent with CA_OFFER";
393         session->SetError(BaseSession::ERROR_CONTENT);
394       }
395       break;
396     case Session::STATE_SENTACCEPT:
397       content = GetFirstContent(session->local_description());
398       if (content && !SetLocalContent(content, CA_ANSWER)) {
399         LOG(LS_ERROR) << "Failure in SetLocalContent with CA_ANSWER";
400         session->SetError(BaseSession::ERROR_CONTENT);
401       }
402       break;
403     case Session::STATE_RECEIVEDINITIATE:
404       content = GetFirstContent(session->remote_description());
405       if (content && !SetRemoteContent(content, CA_OFFER)) {
406         LOG(LS_ERROR) << "Failure in SetRemoteContent with CA_OFFER";
407         session->SetError(BaseSession::ERROR_CONTENT);
408       }
409       break;
410     case Session::STATE_RECEIVEDACCEPT:
411       content = GetFirstContent(session->remote_description());
412       if (content && !SetRemoteContent(content, CA_ANSWER)) {
413         LOG(LS_ERROR) << "Failure in SetRemoteContent with CA_ANSWER";
414         session->SetError(BaseSession::ERROR_CONTENT);
415       }
416       break;
417     default:
418       break;
419   }
420 }
421 
EnableMedia_w()422 void BaseChannel::EnableMedia_w() {
423   ASSERT(worker_thread_ == talk_base::Thread::Current());
424   if (enabled_)
425     return;
426 
427   LOG(LS_INFO) << "Channel enabled";
428   enabled_ = true;
429   ChangeState();
430 }
431 
DisableMedia_w()432 void BaseChannel::DisableMedia_w() {
433   ASSERT(worker_thread_ == talk_base::Thread::Current());
434   if (!enabled_)
435     return;
436 
437   LOG(LS_INFO) << "Channel disabled";
438   enabled_ = false;
439   ChangeState();
440 }
441 
MuteMedia_w()442 void BaseChannel::MuteMedia_w() {
443   ASSERT(worker_thread_ == talk_base::Thread::Current());
444   if (muted_)
445     return;
446 
447   if (media_channel()->Mute(true)) {
448     LOG(LS_INFO) << "Channel muted";
449     muted_ = true;
450   }
451 }
452 
UnmuteMedia_w()453 void BaseChannel::UnmuteMedia_w() {
454   ASSERT(worker_thread_ == talk_base::Thread::Current());
455   if (!muted_)
456     return;
457 
458   if (media_channel()->Mute(false)) {
459     LOG(LS_INFO) << "Channel unmuted";
460     muted_ = false;
461   }
462 }
463 
ChannelWritable_w()464 void BaseChannel::ChannelWritable_w() {
465   ASSERT(worker_thread_ == talk_base::Thread::Current());
466   if (writable_)
467     return;
468   LOG(LS_INFO) << "Channel socket writable ("
469                << transport_channel_->name().c_str() << ")";
470   writable_ = true;
471   ChangeState();
472 }
473 
ChannelNotWritable_w()474 void BaseChannel::ChannelNotWritable_w() {
475   ASSERT(worker_thread_ == talk_base::Thread::Current());
476   if (!writable_)
477     return;
478 
479   LOG(LS_INFO) << "Channel socket not writable ("
480                << transport_channel_->name().c_str() << ")";
481   writable_ = false;
482   ChangeState();
483 }
484 
485 // Sets the maximum video bandwidth for automatic bandwidth adjustment.
SetMaxSendBandwidth_w(int max_bandwidth)486 bool BaseChannel::SetMaxSendBandwidth_w(int max_bandwidth) {
487   return media_channel()->SetSendBandwidth(true, max_bandwidth);
488 }
489 
SetRtcpCName_w(const std::string & cname)490 bool BaseChannel::SetRtcpCName_w(const std::string& cname) {
491   return media_channel()->SetRtcpCName(cname);
492 }
493 
SetSrtp_w(const std::vector<CryptoParams> & cryptos,ContentAction action,ContentSource src)494 bool BaseChannel::SetSrtp_w(const std::vector<CryptoParams>& cryptos,
495                             ContentAction action, ContentSource src) {
496   bool ret;
497   if (action == CA_OFFER) {
498     ret = srtp_filter_.SetOffer(cryptos, src);
499   } else if (action == CA_ANSWER) {
500     ret = srtp_filter_.SetAnswer(cryptos, src);
501   } else {
502     // CA_UPDATE, no crypto params.
503     ret = true;
504   }
505   return ret;
506 }
507 
SetRtcpMux_w(bool enable,ContentAction action,ContentSource src)508 bool BaseChannel::SetRtcpMux_w(bool enable, ContentAction action,
509                                ContentSource src) {
510   bool ret;
511   if (action == CA_OFFER) {
512     ret = rtcp_mux_filter_.SetOffer(enable, src);
513   } else if (action == CA_ANSWER) {
514     ret = rtcp_mux_filter_.SetAnswer(enable, src);
515     if (ret && rtcp_mux_filter_.IsActive()) {
516       // We activated RTCP mux, close down the RTCP transport.
517       set_rtcp_transport_channel(NULL);
518       // If the RTP transport is already writable, then so are we.
519       if (transport_channel_->writable()) {
520         ChannelWritable_w();
521       }
522     }
523   } else {
524     // CA_UPDATE, no RTCP mux info.
525     ret = true;
526   }
527   return ret;
528 }
529 
OnMessage(talk_base::Message * pmsg)530 void BaseChannel::OnMessage(talk_base::Message *pmsg) {
531   switch (pmsg->message_id) {
532     case MSG_ENABLE:
533       EnableMedia_w();
534       break;
535     case MSG_DISABLE:
536       DisableMedia_w();
537       break;
538 
539     case MSG_MUTE:
540       MuteMedia_w();
541       break;
542     case MSG_UNMUTE:
543       UnmuteMedia_w();
544       break;
545 
546     case MSG_SETRTCPCNAME: {
547       SetRtcpCNameData* data = static_cast<SetRtcpCNameData*>(pmsg->pdata);
548       data->result = SetRtcpCName_w(data->cname);
549       break;
550     }
551 
552     case MSG_SETLOCALCONTENT: {
553       SetContentData* data = static_cast<SetContentData*>(pmsg->pdata);
554       data->result = SetLocalContent_w(data->content, data->action);
555       break;
556     }
557     case MSG_SETREMOTECONTENT: {
558       SetContentData* data = static_cast<SetContentData*>(pmsg->pdata);
559       data->result = SetRemoteContent_w(data->content, data->action);
560       break;
561     }
562 
563     case MSG_REMOVESTREAM: {
564       StreamMessageData* data = static_cast<StreamMessageData*>(pmsg->pdata);
565       RemoveStream_w(data->ssrc1);
566       break;
567     }
568 
569     case MSG_SETMAXSENDBANDWIDTH: {
570       SetBandwidthData* data = static_cast<SetBandwidthData*>(pmsg->pdata);
571       data->result = SetMaxSendBandwidth_w(data->value);
572       break;
573     }
574 
575     case MSG_RTPPACKET:
576     case MSG_RTCPPACKET: {
577       PacketMessageData* data = static_cast<PacketMessageData*>(pmsg->pdata);
578       SendPacket(pmsg->message_id == MSG_RTCPPACKET, &data->packet);
579       delete data;  // because it is Posted
580       break;
581     }
582   }
583 }
584 
Send(uint32 id,talk_base::MessageData * pdata)585 void BaseChannel::Send(uint32 id, talk_base::MessageData *pdata) {
586   worker_thread_->Send(this, id, pdata);
587 }
588 
Post(uint32 id,talk_base::MessageData * pdata)589 void BaseChannel::Post(uint32 id, talk_base::MessageData *pdata) {
590   worker_thread_->Post(this, id, pdata);
591 }
592 
PostDelayed(int cmsDelay,uint32 id,talk_base::MessageData * pdata)593 void BaseChannel::PostDelayed(int cmsDelay, uint32 id,
594                               talk_base::MessageData *pdata) {
595   worker_thread_->PostDelayed(cmsDelay, this, id, pdata);
596 }
597 
Clear(uint32 id,talk_base::MessageList * removed)598 void BaseChannel::Clear(uint32 id, talk_base::MessageList* removed) {
599   worker_thread_->Clear(this, id, removed);
600 }
601 
FlushRtcpMessages()602 void BaseChannel::FlushRtcpMessages() {
603   // Flush all remaining RTCP messages. This should only be called in
604   // destructor.
605   ASSERT(talk_base::Thread::Current() == worker_thread_);
606   talk_base::MessageList rtcp_messages;
607   Clear(MSG_RTCPPACKET, &rtcp_messages);
608   for (talk_base::MessageList::iterator it = rtcp_messages.begin();
609        it != rtcp_messages.end(); ++it) {
610     Send(MSG_RTCPPACKET, it->pdata);
611   }
612 }
613 
VoiceChannel(talk_base::Thread * thread,MediaEngine * media_engine,VoiceMediaChannel * media_channel,BaseSession * session,const std::string & content_name,bool rtcp)614 VoiceChannel::VoiceChannel(talk_base::Thread* thread,
615                            MediaEngine* media_engine,
616                            VoiceMediaChannel* media_channel,
617                            BaseSession* session,
618                            const std::string& content_name,
619                            bool rtcp)
620     : BaseChannel(thread, media_engine, media_channel, session, content_name,
621                   session->CreateChannel(content_name, "rtp")),
622       received_media_(false) {
623   if (rtcp) {
624     set_rtcp_transport_channel(session->CreateChannel(content_name, "rtcp"));
625   }
626   // Can't go in BaseChannel because certain session states will
627   // trigger pure virtual functions, such as GetFirstContent().
628   OnSessionState(session, session->state());
629 
630   media_channel->SignalMediaError.connect(
631       this, &VoiceChannel::OnVoiceChannelError);
632 }
633 
~VoiceChannel()634 VoiceChannel::~VoiceChannel() {
635   StopAudioMonitor();
636   StopMediaMonitor();
637   // this can't be done in the base class, since it calls a virtual
638   DisableMedia_w();
639 }
640 
AddStream(uint32 ssrc)641 bool VoiceChannel::AddStream(uint32 ssrc) {
642   StreamMessageData data(ssrc, 0);
643   Send(MSG_ADDSTREAM, &data);
644   return true;
645 }
646 
SetRingbackTone(const void * buf,int len)647 bool VoiceChannel::SetRingbackTone(const void* buf, int len) {
648   SetRingbackToneMessageData data(buf, len);
649   Send(MSG_SETRINGBACKTONE, &data);
650   return true;
651 }
652 
653 // TODO: Handle early media the right way. We should get an explicit
654 // ringing message telling us to start playing local ringback, which we cancel
655 // if any early media actually arrives. For now, we do the opposite, which is
656 // to wait 1 second for early media, and start playing local ringback if none
657 // arrives.
SetEarlyMedia(bool enable)658 void VoiceChannel::SetEarlyMedia(bool enable) {
659   if (enable) {
660     // Start the early media timeout
661     PostDelayed(kEarlyMediaTimeout, MSG_EARLYMEDIATIMEOUT);
662   } else {
663     // Stop the timeout if currently going.
664     Clear(MSG_EARLYMEDIATIMEOUT);
665   }
666 }
667 
PlayRingbackTone(bool play,bool loop)668 bool VoiceChannel::PlayRingbackTone(bool play, bool loop) {
669   PlayRingbackToneMessageData data(play, loop);
670   Send(MSG_PLAYRINGBACKTONE, &data);
671   return data.result;
672 }
673 
PressDTMF(int digit,bool playout)674 bool VoiceChannel::PressDTMF(int digit, bool playout) {
675   DtmfMessageData data(digit, playout);
676   Send(MSG_PRESSDTMF, &data);
677   return data.result;
678 }
679 
StartMediaMonitor(int cms)680 void VoiceChannel::StartMediaMonitor(int cms) {
681   media_monitor_.reset(new VoiceMediaMonitor(media_channel(), worker_thread(),
682       talk_base::Thread::Current()));
683   media_monitor_->SignalUpdate.connect(
684       this, &VoiceChannel::OnMediaMonitorUpdate);
685   media_monitor_->Start(cms);
686 }
687 
StopMediaMonitor()688 void VoiceChannel::StopMediaMonitor() {
689   if (media_monitor_.get()) {
690     media_monitor_->Stop();
691     media_monitor_->SignalUpdate.disconnect(this);
692     media_monitor_.reset();
693   }
694 }
695 
StartAudioMonitor(int cms)696 void VoiceChannel::StartAudioMonitor(int cms) {
697   audio_monitor_.reset(new AudioMonitor(this, talk_base::Thread::Current()));
698   audio_monitor_
699     ->SignalUpdate.connect(this, &VoiceChannel::OnAudioMonitorUpdate);
700   audio_monitor_->Start(cms);
701 }
702 
StopAudioMonitor()703 void VoiceChannel::StopAudioMonitor() {
704   if (audio_monitor_.get()) {
705     audio_monitor_->Stop();
706     audio_monitor_.reset();
707   }
708 }
709 
GetInputLevel_w()710 int VoiceChannel::GetInputLevel_w() {
711   return media_engine()->GetInputLevel();
712 }
713 
GetOutputLevel_w()714 int VoiceChannel::GetOutputLevel_w() {
715   return media_channel()->GetOutputLevel();
716 }
717 
GetActiveStreams_w(AudioInfo::StreamList * actives)718 void VoiceChannel::GetActiveStreams_w(AudioInfo::StreamList* actives) {
719   media_channel()->GetActiveStreams(actives);
720 }
721 
OnChannelRead(TransportChannel * channel,const char * data,size_t len)722 void VoiceChannel::OnChannelRead(TransportChannel* channel,
723                                  const char* data, size_t len) {
724   BaseChannel::OnChannelRead(channel, data, len);
725 
726   // Set a flag when we've received an RTP packet. If we're waiting for early
727   // media, this will disable the timeout.
728   // If we were playing out our local ringback, make sure it is stopped to
729   // prevent it from interfering with the incoming media.
730   if (!received_media_) {
731     if (!PlayRingbackTone_w(false, false)) {
732       LOG(LS_ERROR) << "Failed to stop ringback tone.";
733       SendLastMediaError();
734     }
735   }
736 }
737 
ChangeState()738 void VoiceChannel::ChangeState() {
739   // render incoming data if we are the active call
740   // we receive data on the default channel and multiplexed streams
741   bool recv = enabled();
742   if (!media_channel()->SetPlayout(recv)) {
743     SendLastMediaError();
744   }
745 
746   // send outgoing data if we are the active call, have the
747   // remote party's codec, and have a writable transport
748   // we only send data on the default channel
749   bool send = enabled() && has_codec() && writable();
750   SendFlags send_flag = send ? SEND_MICROPHONE : SEND_NOTHING;
751   if (!media_channel()->SetSend(send_flag)) {
752     LOG(LS_ERROR) << "Failed to SetSend " << send_flag << " on voice channel";
753     SendLastMediaError();
754   }
755 
756   LOG(LS_INFO) << "Changing voice state, recv=" << recv << " send=" << send;
757 }
758 
GetFirstContent(const SessionDescription * sdesc)759 const MediaContentDescription* VoiceChannel::GetFirstContent(
760     const SessionDescription* sdesc) {
761   const ContentInfo* cinfo = GetFirstAudioContent(sdesc);
762   if (cinfo == NULL)
763     return NULL;
764 
765   return static_cast<const MediaContentDescription*>(cinfo->description);
766 }
767 
SetLocalContent_w(const MediaContentDescription * content,ContentAction action)768 bool VoiceChannel::SetLocalContent_w(const MediaContentDescription* content,
769                                      ContentAction action) {
770   ASSERT(worker_thread() == talk_base::Thread::Current());
771   LOG(LS_INFO) << "Setting local voice description";
772 
773   const AudioContentDescription* audio =
774       static_cast<const AudioContentDescription*>(content);
775   ASSERT(audio != NULL);
776 
777   bool ret;
778   // set SRTP
779   ret = SetSrtp_w(audio->cryptos(), action, CS_LOCAL);
780   // set RTCP mux
781   if (ret) {
782     ret = SetRtcpMux_w(audio->rtcp_mux(), action, CS_LOCAL);
783   }
784   // set payload type and config for voice codecs
785   if (ret) {
786     ret = media_channel()->SetRecvCodecs(audio->codecs());
787   }
788   return ret;
789 }
790 
SetRemoteContent_w(const MediaContentDescription * content,ContentAction action)791 bool VoiceChannel::SetRemoteContent_w(const MediaContentDescription* content,
792                                       ContentAction action) {
793   ASSERT(worker_thread() == talk_base::Thread::Current());
794   LOG(LS_INFO) << "Setting remote voice description";
795 
796   const AudioContentDescription* audio =
797       static_cast<const AudioContentDescription*>(content);
798   ASSERT(audio != NULL);
799 
800   bool ret;
801   // set the sending SSRC, if the remote side gave us one
802   if (audio->ssrc_set()) {
803     media_channel()->SetSendSsrc(audio->ssrc());
804   }
805   // set SRTP
806   ret = SetSrtp_w(audio->cryptos(), action, CS_REMOTE);
807   // set RTCP mux
808   if (ret) {
809     ret = SetRtcpMux_w(audio->rtcp_mux(), action, CS_REMOTE);
810   }
811   // set codecs and payload types
812   if (ret) {
813     ret = media_channel()->SetSendCodecs(audio->codecs());
814   }
815 
816   int audio_options = 0;
817   if (audio->conference_mode()) {
818     audio_options |= OPT_CONFERENCE;
819   }
820   if (!media_channel()->SetOptions(audio_options)) {
821     // Log an error on failure, but don't abort the call.
822     LOG(LS_ERROR) << "Failed to set voice channel options";
823   }
824 
825   // update state
826   if (ret) {
827     set_has_codec(true);
828     ChangeState();
829   }
830   return ret;
831 }
832 
AddStream_w(uint32 ssrc)833 void VoiceChannel::AddStream_w(uint32 ssrc) {
834   ASSERT(worker_thread() == talk_base::Thread::Current());
835   media_channel()->AddStream(ssrc);
836 }
837 
RemoveStream_w(uint32 ssrc)838 void VoiceChannel::RemoveStream_w(uint32 ssrc) {
839   media_channel()->RemoveStream(ssrc);
840 }
841 
SetRingbackTone_w(const void * buf,int len)842 void VoiceChannel::SetRingbackTone_w(const void* buf, int len) {
843   ASSERT(worker_thread() == talk_base::Thread::Current());
844   media_channel()->SetRingbackTone(static_cast<const char*>(buf), len);
845 }
846 
PlayRingbackTone_w(bool play,bool loop)847 bool VoiceChannel::PlayRingbackTone_w(bool play, bool loop) {
848   ASSERT(worker_thread() == talk_base::Thread::Current());
849   if (play) {
850     LOG(LS_INFO) << "Playing ringback tone, loop=" << loop;
851   } else {
852     LOG(LS_INFO) << "Stopping ringback tone";
853   }
854   return media_channel()->PlayRingbackTone(play, loop);
855 }
856 
HandleEarlyMediaTimeout()857 void VoiceChannel::HandleEarlyMediaTimeout() {
858   // This occurs on the main thread, not the worker thread.
859   if (!received_media_) {
860     LOG(LS_INFO) << "No early media received before timeout";
861     SignalEarlyMediaTimeout(this);
862   }
863 }
864 
PressDTMF_w(int digit,bool playout)865 bool VoiceChannel::PressDTMF_w(int digit, bool playout) {
866   if (!enabled() || !writable()) {
867     return false;
868   }
869 
870   return media_channel()->PressDTMF(digit, playout);
871 }
872 
OnMessage(talk_base::Message * pmsg)873 void VoiceChannel::OnMessage(talk_base::Message *pmsg) {
874   switch (pmsg->message_id) {
875     case MSG_ADDSTREAM: {
876       StreamMessageData* data = static_cast<StreamMessageData*>(pmsg->pdata);
877       AddStream_w(data->ssrc1);
878       break;
879     }
880     case MSG_SETRINGBACKTONE: {
881       SetRingbackToneMessageData* data =
882           static_cast<SetRingbackToneMessageData*>(pmsg->pdata);
883       SetRingbackTone_w(data->buf, data->len);
884       break;
885     }
886     case MSG_PLAYRINGBACKTONE: {
887       PlayRingbackToneMessageData* data =
888           static_cast<PlayRingbackToneMessageData*>(pmsg->pdata);
889       data->result = PlayRingbackTone_w(data->play, data->loop);
890       break;
891     }
892     case MSG_EARLYMEDIATIMEOUT:
893       HandleEarlyMediaTimeout();
894       break;
895     case MSG_PRESSDTMF: {
896       DtmfMessageData* data = static_cast<DtmfMessageData*>(pmsg->pdata);
897       data->result = PressDTMF_w(data->digit, data->playout);
898       break;
899     }
900     case MSG_CHANNEL_ERROR: {
901       VoiceChannelErrorMessageData* data =
902           static_cast<VoiceChannelErrorMessageData*>(pmsg->pdata);
903       SignalMediaError(this, data->ssrc, data->error);
904       delete data;
905       break;
906     }
907 
908     default:
909       BaseChannel::OnMessage(pmsg);
910       break;
911   }
912 }
913 
OnConnectionMonitorUpdate(SocketMonitor * monitor,const std::vector<ConnectionInfo> & infos)914 void VoiceChannel::OnConnectionMonitorUpdate(
915     SocketMonitor* monitor, const std::vector<ConnectionInfo>& infos) {
916   SignalConnectionMonitor(this, infos);
917 }
918 
OnMediaMonitorUpdate(VoiceMediaChannel * media_channel,const VoiceMediaInfo & info)919 void VoiceChannel::OnMediaMonitorUpdate(
920     VoiceMediaChannel* media_channel, const VoiceMediaInfo& info) {
921   ASSERT(media_channel == this->media_channel());
922   SignalMediaMonitor(this, info);
923 }
924 
OnAudioMonitorUpdate(AudioMonitor * monitor,const AudioInfo & info)925 void VoiceChannel::OnAudioMonitorUpdate(AudioMonitor* monitor,
926                                         const AudioInfo& info) {
927   SignalAudioMonitor(this, info);
928 }
929 
OnVoiceChannelError(uint32 ssrc,VoiceMediaChannel::Error error)930 void VoiceChannel::OnVoiceChannelError(
931     uint32 ssrc, VoiceMediaChannel::Error error) {
932   VoiceChannelErrorMessageData *data = new VoiceChannelErrorMessageData(
933       ssrc, error);
934   signaling_thread()->Post(this, MSG_CHANNEL_ERROR, data);
935 }
936 
VideoChannel(talk_base::Thread * thread,MediaEngine * media_engine,VideoMediaChannel * media_channel,BaseSession * session,const std::string & content_name,bool rtcp,VoiceChannel * voice_channel)937 VideoChannel::VideoChannel(talk_base::Thread* thread,
938                            MediaEngine* media_engine,
939                            VideoMediaChannel* media_channel,
940                            BaseSession* session,
941                            const std::string& content_name,
942                            bool rtcp,
943                            VoiceChannel* voice_channel)
944     : BaseChannel(thread, media_engine, media_channel, session, content_name,
945                   session->CreateChannel(content_name, "video_rtp")),
946       voice_channel_(voice_channel), renderer_(NULL) {
947   if (rtcp) {
948     set_rtcp_transport_channel(
949         session->CreateChannel(content_name, "video_rtcp"));
950   }
951   // Can't go in BaseChannel because certain session states will
952   // trigger pure virtual functions, such as GetFirstContent()
953   OnSessionState(session, session->state());
954 
955   media_channel->SignalMediaError.connect(
956       this, &VideoChannel::OnVideoChannelError);
957 }
958 
SendLastMediaError()959 void VoiceChannel::SendLastMediaError() {
960   uint32 ssrc;
961   VoiceMediaChannel::Error error;
962   media_channel()->GetLastMediaError(&ssrc, &error);
963   SignalMediaError(this, ssrc, error);
964 }
965 
~VideoChannel()966 VideoChannel::~VideoChannel() {
967   StopMediaMonitor();
968   // this can't be done in the base class, since it calls a virtual
969   DisableMedia_w();
970 }
971 
AddStream(uint32 ssrc,uint32 voice_ssrc)972 bool VideoChannel::AddStream(uint32 ssrc, uint32 voice_ssrc) {
973   StreamMessageData data(ssrc, voice_ssrc);
974   Send(MSG_ADDSTREAM, &data);
975   return true;
976 }
977 
SetRenderer(uint32 ssrc,VideoRenderer * renderer)978 bool VideoChannel::SetRenderer(uint32 ssrc, VideoRenderer* renderer) {
979   RenderMessageData data(ssrc, renderer);
980   Send(MSG_SETRENDERER, &data);
981   return true;
982 }
983 
984 
985 
SendIntraFrame()986 bool VideoChannel::SendIntraFrame() {
987   Send(MSG_SENDINTRAFRAME);
988   return true;
989 }
RequestIntraFrame()990 bool VideoChannel::RequestIntraFrame() {
991   Send(MSG_REQUESTINTRAFRAME);
992   return true;
993 }
994 
ChangeState()995 void VideoChannel::ChangeState() {
996   // render incoming data if we are the active call
997   // we receive data on the default channel and multiplexed streams
998   bool recv = enabled();
999   if (!media_channel()->SetRender(recv)) {
1000     LOG(LS_ERROR) << "Failed to SetRender on video channel";
1001     // TODO: Report error back to server.
1002   }
1003 
1004   // send outgoing data if we are the active call, have the
1005   // remote party's codec, and have a writable transport
1006   // we only send data on the default channel
1007   bool send = enabled() && has_codec() && writable();
1008   if (!media_channel()->SetSend(send)) {
1009     LOG(LS_ERROR) << "Failed to SetSend on video channel";
1010     // TODO: Report error back to server.
1011   }
1012 
1013   LOG(LS_INFO) << "Changing video state, recv=" << recv << " send=" << send;
1014 }
1015 
StartMediaMonitor(int cms)1016 void VideoChannel::StartMediaMonitor(int cms) {
1017   media_monitor_.reset(new VideoMediaMonitor(media_channel(), worker_thread(),
1018       talk_base::Thread::Current()));
1019   media_monitor_->SignalUpdate.connect(
1020       this, &VideoChannel::OnMediaMonitorUpdate);
1021   media_monitor_->Start(cms);
1022 }
1023 
StopMediaMonitor()1024 void VideoChannel::StopMediaMonitor() {
1025   if (media_monitor_.get()) {
1026     media_monitor_->Stop();
1027     media_monitor_.reset();
1028   }
1029 }
1030 
GetFirstContent(const SessionDescription * sdesc)1031 const MediaContentDescription* VideoChannel::GetFirstContent(
1032     const SessionDescription* sdesc) {
1033   const ContentInfo* cinfo = GetFirstVideoContent(sdesc);
1034   if (cinfo == NULL)
1035     return NULL;
1036 
1037   return static_cast<const MediaContentDescription*>(cinfo->description);
1038 }
1039 
SetLocalContent_w(const MediaContentDescription * content,ContentAction action)1040 bool VideoChannel::SetLocalContent_w(const MediaContentDescription* content,
1041                                      ContentAction action) {
1042   ASSERT(worker_thread() == talk_base::Thread::Current());
1043   LOG(LS_INFO) << "Setting local video description";
1044 
1045   const VideoContentDescription* video =
1046       static_cast<const VideoContentDescription*>(content);
1047   ASSERT(video != NULL);
1048 
1049   bool ret;
1050   // set SRTP
1051   ret = SetSrtp_w(video->cryptos(), action, CS_LOCAL);
1052   // set RTCP mux
1053   if (ret) {
1054     ret = SetRtcpMux_w(video->rtcp_mux(), action, CS_LOCAL);
1055   }
1056   // set payload types and config for receiving video
1057   if (ret) {
1058     ret = media_channel()->SetRecvCodecs(video->codecs());
1059   }
1060   return ret;
1061 }
1062 
SetRemoteContent_w(const MediaContentDescription * content,ContentAction action)1063 bool VideoChannel::SetRemoteContent_w(const MediaContentDescription* content,
1064                                       ContentAction action) {
1065   ASSERT(worker_thread() == talk_base::Thread::Current());
1066   LOG(LS_INFO) << "Setting remote video description";
1067 
1068   const VideoContentDescription* video =
1069       static_cast<const VideoContentDescription*>(content);
1070   ASSERT(video != NULL);
1071 
1072   bool ret;
1073   // set the sending SSRC, if the remote side gave us one
1074   // TODO: remove this, since it's not needed.
1075   if (video->ssrc_set()) {
1076     media_channel()->SetSendSsrc(video->ssrc());
1077   }
1078   // set SRTP
1079   ret = SetSrtp_w(video->cryptos(), action, CS_REMOTE);
1080   // set RTCP mux
1081   if (ret) {
1082     ret = SetRtcpMux_w(video->rtcp_mux(), action, CS_REMOTE);
1083   }
1084   // Set video bandwidth parameters.
1085   if (ret) {
1086     int bandwidth_bps = video->bandwidth();
1087     bool auto_bandwidth = (bandwidth_bps == kAutoBandwidth);
1088     ret = media_channel()->SetSendBandwidth(auto_bandwidth, bandwidth_bps);
1089   }
1090   if (ret) {
1091     ret = media_channel()->SetSendCodecs(video->codecs());
1092   }
1093   media_channel()->SetRtpExtensionHeaders(!video->rtp_headers_disabled());
1094   if (ret) {
1095     set_has_codec(true);
1096     ChangeState();
1097   }
1098   return ret;
1099 }
1100 
AddStream_w(uint32 ssrc,uint32 voice_ssrc)1101 void VideoChannel::AddStream_w(uint32 ssrc, uint32 voice_ssrc) {
1102   media_channel()->AddStream(ssrc, voice_ssrc);
1103 }
1104 
RemoveStream_w(uint32 ssrc)1105 void VideoChannel::RemoveStream_w(uint32 ssrc) {
1106   media_channel()->RemoveStream(ssrc);
1107 }
1108 
SetRenderer_w(uint32 ssrc,VideoRenderer * renderer)1109 void VideoChannel::SetRenderer_w(uint32 ssrc, VideoRenderer* renderer) {
1110   media_channel()->SetRenderer(ssrc, renderer);
1111 }
1112 
1113 
OnMessage(talk_base::Message * pmsg)1114 void VideoChannel::OnMessage(talk_base::Message *pmsg) {
1115   switch (pmsg->message_id) {
1116     case MSG_ADDSTREAM: {
1117       StreamMessageData* data = static_cast<StreamMessageData*>(pmsg->pdata);
1118       AddStream_w(data->ssrc1, data->ssrc2);
1119       break;
1120     }
1121     case MSG_SETRENDERER: {
1122       RenderMessageData* data = static_cast<RenderMessageData*>(pmsg->pdata);
1123       SetRenderer_w(data->ssrc, data->renderer);
1124       break;
1125     }
1126     case MSG_SENDINTRAFRAME:
1127       SendIntraFrame_w();
1128       break;
1129     case MSG_REQUESTINTRAFRAME:
1130       RequestIntraFrame_w();
1131       break;
1132     case MSG_CHANNEL_ERROR: {
1133       const VideoChannelErrorMessageData* data =
1134           static_cast<VideoChannelErrorMessageData*>(pmsg->pdata);
1135       SignalMediaError(this, data->ssrc, data->error);
1136       delete data;
1137       break;
1138     }
1139     default:
1140       BaseChannel::OnMessage(pmsg);
1141       break;
1142   }
1143 }
1144 
OnConnectionMonitorUpdate(SocketMonitor * monitor,const std::vector<ConnectionInfo> & infos)1145 void VideoChannel::OnConnectionMonitorUpdate(
1146     SocketMonitor *monitor, const std::vector<ConnectionInfo> &infos) {
1147   SignalConnectionMonitor(this, infos);
1148 }
1149 
OnMediaMonitorUpdate(VideoMediaChannel * media_channel,const VideoMediaInfo & info)1150 void VideoChannel::OnMediaMonitorUpdate(
1151     VideoMediaChannel* media_channel, const VideoMediaInfo &info) {
1152   ASSERT(media_channel == this->media_channel());
1153   SignalMediaMonitor(this, info);
1154 }
1155 
1156 
OnVideoChannelError(uint32 ssrc,VideoMediaChannel::Error error)1157 void VideoChannel::OnVideoChannelError(uint32 ssrc,
1158                                        VideoMediaChannel::Error error) {
1159   VideoChannelErrorMessageData* data = new VideoChannelErrorMessageData(
1160       ssrc, error);
1161   signaling_thread()->Post(this, MSG_CHANNEL_ERROR, data);
1162 }
1163 
1164 }  // namespace cricket
1165