1 /*
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/channelmanager.h"
29 
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33 
34 #include <algorithm>
35 
36 #include "talk/app/webrtc/mediacontroller.h"
37 #include "talk/media/base/capturemanager.h"
38 #include "talk/media/base/device.h"
39 #include "talk/media/base/hybriddataengine.h"
40 #include "talk/media/base/rtpdataengine.h"
41 #include "talk/media/base/videocapturer.h"
42 #ifdef HAVE_SCTP
43 #include "talk/media/sctp/sctpdataengine.h"
44 #endif
45 #include "talk/session/media/srtpfilter.h"
46 #include "webrtc/base/bind.h"
47 #include "webrtc/base/common.h"
48 #include "webrtc/base/logging.h"
49 #include "webrtc/base/sigslotrepeater.h"
50 #include "webrtc/base/stringencode.h"
51 #include "webrtc/base/stringutils.h"
52 #include "webrtc/base/trace_event.h"
53 
54 namespace cricket {
55 
56 enum {
57   MSG_VIDEOCAPTURESTATE = 1,
58 };
59 
60 using rtc::Bind;
61 
62 static const int kNotSetOutputVolume = -1;
63 
64 struct CaptureStateParams : public rtc::MessageData {
CaptureStateParamscricket::CaptureStateParams65   CaptureStateParams(cricket::VideoCapturer* c, cricket::CaptureState s)
66       : capturer(c),
67         state(s) {}
68   cricket::VideoCapturer* capturer;
69   cricket::CaptureState state;
70 };
71 
ConstructDataEngine()72 static DataEngineInterface* ConstructDataEngine() {
73 #ifdef HAVE_SCTP
74   return new HybridDataEngine(new RtpDataEngine(), new SctpDataEngine());
75 #else
76   return new RtpDataEngine();
77 #endif
78 }
79 
ChannelManager(MediaEngineInterface * me,DataEngineInterface * dme,CaptureManager * cm,rtc::Thread * worker_thread)80 ChannelManager::ChannelManager(MediaEngineInterface* me,
81                                DataEngineInterface* dme,
82                                CaptureManager* cm,
83                                rtc::Thread* worker_thread) {
84   Construct(me, dme, cm, worker_thread);
85 }
86 
ChannelManager(MediaEngineInterface * me,rtc::Thread * worker_thread)87 ChannelManager::ChannelManager(MediaEngineInterface* me,
88                                rtc::Thread* worker_thread) {
89   Construct(me,
90             ConstructDataEngine(),
91             new CaptureManager(),
92             worker_thread);
93 }
94 
Construct(MediaEngineInterface * me,DataEngineInterface * dme,CaptureManager * cm,rtc::Thread * worker_thread)95 void ChannelManager::Construct(MediaEngineInterface* me,
96                                DataEngineInterface* dme,
97                                CaptureManager* cm,
98                                rtc::Thread* worker_thread) {
99   media_engine_.reset(me);
100   data_media_engine_.reset(dme);
101   capture_manager_.reset(cm);
102   initialized_ = false;
103   main_thread_ = rtc::Thread::Current();
104   worker_thread_ = worker_thread;
105   audio_output_volume_ = kNotSetOutputVolume;
106   local_renderer_ = NULL;
107   capturing_ = false;
108   enable_rtx_ = false;
109 
110   capture_manager_->SignalCapturerStateChange.connect(
111       this, &ChannelManager::OnVideoCaptureStateChange);
112 }
113 
~ChannelManager()114 ChannelManager::~ChannelManager() {
115   if (initialized_) {
116     Terminate();
117     // If srtp is initialized (done by the Channel) then we must call
118     // srtp_shutdown to free all crypto kernel lists. But we need to make sure
119     // shutdown always called at the end, after channels are destroyed.
120     // ChannelManager d'tor is always called last, it's safe place to call
121     // shutdown.
122     ShutdownSrtp();
123   }
124   // Some deletes need to be on the worker thread for thread safe destruction,
125   // this includes the media engine and capture manager.
126   worker_thread_->Invoke<void>(Bind(
127       &ChannelManager::DestructorDeletes_w, this));
128 }
129 
SetVideoRtxEnabled(bool enable)130 bool ChannelManager::SetVideoRtxEnabled(bool enable) {
131   // To be safe, this call is only allowed before initialization. Apps like
132   // Flute only have a singleton ChannelManager and we don't want this flag to
133   // be toggled between calls or when there's concurrent calls. We expect apps
134   // to enable this at startup and retain that setting for the lifetime of the
135   // app.
136   if (!initialized_) {
137     enable_rtx_ = enable;
138     return true;
139   } else {
140     LOG(LS_WARNING) << "Cannot toggle rtx after initialization!";
141     return false;
142   }
143 }
144 
GetSupportedAudioCodecs(std::vector<AudioCodec> * codecs) const145 void ChannelManager::GetSupportedAudioCodecs(
146     std::vector<AudioCodec>* codecs) const {
147   codecs->clear();
148 
149   for (std::vector<AudioCodec>::const_iterator it =
150            media_engine_->audio_codecs().begin();
151       it != media_engine_->audio_codecs().end(); ++it) {
152     codecs->push_back(*it);
153   }
154 }
155 
GetSupportedAudioRtpHeaderExtensions(RtpHeaderExtensions * ext) const156 void ChannelManager::GetSupportedAudioRtpHeaderExtensions(
157     RtpHeaderExtensions* ext) const {
158   *ext = media_engine_->GetAudioCapabilities().header_extensions;
159 }
160 
GetSupportedVideoCodecs(std::vector<VideoCodec> * codecs) const161 void ChannelManager::GetSupportedVideoCodecs(
162     std::vector<VideoCodec>* codecs) const {
163   codecs->clear();
164 
165   std::vector<VideoCodec>::const_iterator it;
166   for (it = media_engine_->video_codecs().begin();
167       it != media_engine_->video_codecs().end(); ++it) {
168     if (!enable_rtx_ && _stricmp(kRtxCodecName, it->name.c_str()) == 0) {
169       continue;
170     }
171     codecs->push_back(*it);
172   }
173 }
174 
GetSupportedVideoRtpHeaderExtensions(RtpHeaderExtensions * ext) const175 void ChannelManager::GetSupportedVideoRtpHeaderExtensions(
176     RtpHeaderExtensions* ext) const {
177   *ext = media_engine_->GetVideoCapabilities().header_extensions;
178 }
179 
GetSupportedDataCodecs(std::vector<DataCodec> * codecs) const180 void ChannelManager::GetSupportedDataCodecs(
181     std::vector<DataCodec>* codecs) const {
182   *codecs = data_media_engine_->data_codecs();
183 }
184 
Init()185 bool ChannelManager::Init() {
186   ASSERT(!initialized_);
187   if (initialized_) {
188     return false;
189   }
190   ASSERT(worker_thread_ != NULL);
191   if (!worker_thread_) {
192     return false;
193   }
194   if (worker_thread_ != rtc::Thread::Current()) {
195     // Do not allow invoking calls to other threads on the worker thread.
196     worker_thread_->Invoke<bool>(rtc::Bind(
197         &rtc::Thread::SetAllowBlockingCalls, worker_thread_, false));
198   }
199 
200   initialized_ = worker_thread_->Invoke<bool>(Bind(
201       &ChannelManager::InitMediaEngine_w, this));
202   ASSERT(initialized_);
203   if (!initialized_) {
204     return false;
205   }
206 
207   // If audio_output_volume_ has been set via SetOutputVolume(), set the
208   // audio output volume of the engine.
209   if (kNotSetOutputVolume != audio_output_volume_ &&
210       !SetOutputVolume(audio_output_volume_)) {
211     LOG(LS_WARNING) << "Failed to SetOutputVolume to "
212                     << audio_output_volume_;
213   }
214 
215   return initialized_;
216 }
217 
InitMediaEngine_w()218 bool ChannelManager::InitMediaEngine_w() {
219   ASSERT(worker_thread_ == rtc::Thread::Current());
220   return (media_engine_->Init(worker_thread_));
221 }
222 
Terminate()223 void ChannelManager::Terminate() {
224   ASSERT(initialized_);
225   if (!initialized_) {
226     return;
227   }
228   worker_thread_->Invoke<void>(Bind(&ChannelManager::Terminate_w, this));
229   initialized_ = false;
230 }
231 
DestructorDeletes_w()232 void ChannelManager::DestructorDeletes_w() {
233   ASSERT(worker_thread_ == rtc::Thread::Current());
234   media_engine_.reset(NULL);
235   capture_manager_.reset(NULL);
236 }
237 
Terminate_w()238 void ChannelManager::Terminate_w() {
239   ASSERT(worker_thread_ == rtc::Thread::Current());
240   // Need to destroy the voice/video channels
241   while (!video_channels_.empty()) {
242     DestroyVideoChannel_w(video_channels_.back());
243   }
244   while (!voice_channels_.empty()) {
245     DestroyVoiceChannel_w(voice_channels_.back());
246   }
247   media_engine_->Terminate();
248 }
249 
CreateVoiceChannel(webrtc::MediaControllerInterface * media_controller,TransportController * transport_controller,const std::string & content_name,bool rtcp,const AudioOptions & options)250 VoiceChannel* ChannelManager::CreateVoiceChannel(
251     webrtc::MediaControllerInterface* media_controller,
252     TransportController* transport_controller,
253     const std::string& content_name,
254     bool rtcp,
255     const AudioOptions& options) {
256   return worker_thread_->Invoke<VoiceChannel*>(
257       Bind(&ChannelManager::CreateVoiceChannel_w, this, media_controller,
258            transport_controller, content_name, rtcp, options));
259 }
260 
CreateVoiceChannel_w(webrtc::MediaControllerInterface * media_controller,TransportController * transport_controller,const std::string & content_name,bool rtcp,const AudioOptions & options)261 VoiceChannel* ChannelManager::CreateVoiceChannel_w(
262     webrtc::MediaControllerInterface* media_controller,
263     TransportController* transport_controller,
264     const std::string& content_name,
265     bool rtcp,
266     const AudioOptions& options) {
267   ASSERT(initialized_);
268   ASSERT(worker_thread_ == rtc::Thread::Current());
269   ASSERT(nullptr != media_controller);
270   VoiceMediaChannel* media_channel =
271       media_engine_->CreateChannel(media_controller->call_w(), options);
272   if (!media_channel)
273     return nullptr;
274 
275   VoiceChannel* voice_channel =
276       new VoiceChannel(worker_thread_, media_engine_.get(), media_channel,
277                        transport_controller, content_name, rtcp);
278   if (!voice_channel->Init()) {
279     delete voice_channel;
280     return nullptr;
281   }
282   voice_channels_.push_back(voice_channel);
283   return voice_channel;
284 }
285 
DestroyVoiceChannel(VoiceChannel * voice_channel)286 void ChannelManager::DestroyVoiceChannel(VoiceChannel* voice_channel) {
287   TRACE_EVENT0("webrtc", "ChannelManager::DestroyVoiceChannel");
288   if (voice_channel) {
289     worker_thread_->Invoke<void>(
290         Bind(&ChannelManager::DestroyVoiceChannel_w, this, voice_channel));
291   }
292 }
293 
DestroyVoiceChannel_w(VoiceChannel * voice_channel)294 void ChannelManager::DestroyVoiceChannel_w(VoiceChannel* voice_channel) {
295   TRACE_EVENT0("webrtc", "ChannelManager::DestroyVoiceChannel_w");
296   // Destroy voice channel.
297   ASSERT(initialized_);
298   ASSERT(worker_thread_ == rtc::Thread::Current());
299   VoiceChannels::iterator it = std::find(voice_channels_.begin(),
300       voice_channels_.end(), voice_channel);
301   ASSERT(it != voice_channels_.end());
302   if (it == voice_channels_.end())
303     return;
304   voice_channels_.erase(it);
305   delete voice_channel;
306 }
307 
CreateVideoChannel(webrtc::MediaControllerInterface * media_controller,TransportController * transport_controller,const std::string & content_name,bool rtcp,const VideoOptions & options)308 VideoChannel* ChannelManager::CreateVideoChannel(
309     webrtc::MediaControllerInterface* media_controller,
310     TransportController* transport_controller,
311     const std::string& content_name,
312     bool rtcp,
313     const VideoOptions& options) {
314   return worker_thread_->Invoke<VideoChannel*>(
315       Bind(&ChannelManager::CreateVideoChannel_w, this, media_controller,
316            transport_controller, content_name, rtcp, options));
317 }
318 
CreateVideoChannel_w(webrtc::MediaControllerInterface * media_controller,TransportController * transport_controller,const std::string & content_name,bool rtcp,const VideoOptions & options)319 VideoChannel* ChannelManager::CreateVideoChannel_w(
320     webrtc::MediaControllerInterface* media_controller,
321     TransportController* transport_controller,
322     const std::string& content_name,
323     bool rtcp,
324     const VideoOptions& options) {
325   ASSERT(initialized_);
326   ASSERT(worker_thread_ == rtc::Thread::Current());
327   ASSERT(nullptr != media_controller);
328   VideoMediaChannel* media_channel =
329       media_engine_->CreateVideoChannel(media_controller->call_w(), options);
330   if (media_channel == NULL) {
331     return NULL;
332   }
333 
334   VideoChannel* video_channel = new VideoChannel(
335       worker_thread_, media_channel, transport_controller, content_name, rtcp);
336   if (!video_channel->Init()) {
337     delete video_channel;
338     return NULL;
339   }
340   video_channels_.push_back(video_channel);
341   return video_channel;
342 }
343 
DestroyVideoChannel(VideoChannel * video_channel)344 void ChannelManager::DestroyVideoChannel(VideoChannel* video_channel) {
345   TRACE_EVENT0("webrtc", "ChannelManager::DestroyVideoChannel");
346   if (video_channel) {
347     worker_thread_->Invoke<void>(
348         Bind(&ChannelManager::DestroyVideoChannel_w, this, video_channel));
349   }
350 }
351 
DestroyVideoChannel_w(VideoChannel * video_channel)352 void ChannelManager::DestroyVideoChannel_w(VideoChannel* video_channel) {
353   TRACE_EVENT0("webrtc", "ChannelManager::DestroyVideoChannel_w");
354   // Destroy video channel.
355   ASSERT(initialized_);
356   ASSERT(worker_thread_ == rtc::Thread::Current());
357   VideoChannels::iterator it = std::find(video_channels_.begin(),
358       video_channels_.end(), video_channel);
359   ASSERT(it != video_channels_.end());
360   if (it == video_channels_.end())
361     return;
362 
363   video_channels_.erase(it);
364   delete video_channel;
365 }
366 
CreateDataChannel(TransportController * transport_controller,const std::string & content_name,bool rtcp,DataChannelType channel_type)367 DataChannel* ChannelManager::CreateDataChannel(
368     TransportController* transport_controller,
369     const std::string& content_name,
370     bool rtcp,
371     DataChannelType channel_type) {
372   return worker_thread_->Invoke<DataChannel*>(
373       Bind(&ChannelManager::CreateDataChannel_w, this, transport_controller,
374            content_name, rtcp, channel_type));
375 }
376 
CreateDataChannel_w(TransportController * transport_controller,const std::string & content_name,bool rtcp,DataChannelType data_channel_type)377 DataChannel* ChannelManager::CreateDataChannel_w(
378     TransportController* transport_controller,
379     const std::string& content_name,
380     bool rtcp,
381     DataChannelType data_channel_type) {
382   // This is ok to alloc from a thread other than the worker thread.
383   ASSERT(initialized_);
384   DataMediaChannel* media_channel = data_media_engine_->CreateChannel(
385       data_channel_type);
386   if (!media_channel) {
387     LOG(LS_WARNING) << "Failed to create data channel of type "
388                     << data_channel_type;
389     return NULL;
390   }
391 
392   DataChannel* data_channel = new DataChannel(
393       worker_thread_, media_channel, transport_controller, content_name, rtcp);
394   if (!data_channel->Init()) {
395     LOG(LS_WARNING) << "Failed to init data channel.";
396     delete data_channel;
397     return NULL;
398   }
399   data_channels_.push_back(data_channel);
400   return data_channel;
401 }
402 
DestroyDataChannel(DataChannel * data_channel)403 void ChannelManager::DestroyDataChannel(DataChannel* data_channel) {
404   TRACE_EVENT0("webrtc", "ChannelManager::DestroyDataChannel");
405   if (data_channel) {
406     worker_thread_->Invoke<void>(
407         Bind(&ChannelManager::DestroyDataChannel_w, this, data_channel));
408   }
409 }
410 
DestroyDataChannel_w(DataChannel * data_channel)411 void ChannelManager::DestroyDataChannel_w(DataChannel* data_channel) {
412   TRACE_EVENT0("webrtc", "ChannelManager::DestroyDataChannel_w");
413   // Destroy data channel.
414   ASSERT(initialized_);
415   DataChannels::iterator it = std::find(data_channels_.begin(),
416       data_channels_.end(), data_channel);
417   ASSERT(it != data_channels_.end());
418   if (it == data_channels_.end())
419     return;
420 
421   data_channels_.erase(it);
422   delete data_channel;
423 }
424 
GetOutputVolume(int * level)425 bool ChannelManager::GetOutputVolume(int* level) {
426   if (!initialized_) {
427     return false;
428   }
429   return worker_thread_->Invoke<bool>(
430       Bind(&MediaEngineInterface::GetOutputVolume, media_engine_.get(), level));
431 }
432 
SetOutputVolume(int level)433 bool ChannelManager::SetOutputVolume(int level) {
434   bool ret = level >= 0 && level <= 255;
435   if (initialized_) {
436     ret &= worker_thread_->Invoke<bool>(
437         Bind(&MediaEngineInterface::SetOutputVolume,
438              media_engine_.get(), level));
439   }
440 
441   if (ret) {
442     audio_output_volume_ = level;
443   }
444 
445   return ret;
446 }
447 
GetSupportedFormats(VideoCapturer * capturer) const448 std::vector<cricket::VideoFormat> ChannelManager::GetSupportedFormats(
449     VideoCapturer* capturer) const {
450   ASSERT(capturer != NULL);
451   std::vector<VideoFormat> formats;
452   worker_thread_->Invoke<void>(rtc::Bind(&ChannelManager::GetSupportedFormats_w,
453                                          this, capturer, &formats));
454   return formats;
455 }
456 
GetSupportedFormats_w(VideoCapturer * capturer,std::vector<cricket::VideoFormat> * out_formats) const457 void ChannelManager::GetSupportedFormats_w(
458     VideoCapturer* capturer,
459     std::vector<cricket::VideoFormat>* out_formats) const {
460   const std::vector<VideoFormat>* formats = capturer->GetSupportedFormats();
461   if (formats != NULL)
462     *out_formats = *formats;
463 }
464 
465 // The following are done in the new "CaptureManager" style that
466 // all local video capturers, processors, and managers should move
467 // to.
468 // TODO(pthatcher): Add more of the CaptureManager interface.
StartVideoCapture(VideoCapturer * capturer,const VideoFormat & video_format)469 bool ChannelManager::StartVideoCapture(
470     VideoCapturer* capturer, const VideoFormat& video_format) {
471   return initialized_ && worker_thread_->Invoke<bool>(
472       Bind(&CaptureManager::StartVideoCapture,
473            capture_manager_.get(), capturer, video_format));
474 }
475 
MuteToBlackThenPause(VideoCapturer * video_capturer,bool muted)476 bool ChannelManager::MuteToBlackThenPause(
477     VideoCapturer* video_capturer, bool muted) {
478   if (!initialized_) {
479     return false;
480   }
481   worker_thread_->Invoke<void>(
482       Bind(&VideoCapturer::MuteToBlackThenPause, video_capturer, muted));
483   return true;
484 }
485 
StopVideoCapture(VideoCapturer * capturer,const VideoFormat & video_format)486 bool ChannelManager::StopVideoCapture(
487     VideoCapturer* capturer, const VideoFormat& video_format) {
488   return initialized_ && worker_thread_->Invoke<bool>(
489       Bind(&CaptureManager::StopVideoCapture,
490            capture_manager_.get(), capturer, video_format));
491 }
492 
RestartVideoCapture(VideoCapturer * video_capturer,const VideoFormat & previous_format,const VideoFormat & desired_format,CaptureManager::RestartOptions options)493 bool ChannelManager::RestartVideoCapture(
494     VideoCapturer* video_capturer,
495     const VideoFormat& previous_format,
496     const VideoFormat& desired_format,
497     CaptureManager::RestartOptions options) {
498   return initialized_ && worker_thread_->Invoke<bool>(
499       Bind(&CaptureManager::RestartVideoCapture, capture_manager_.get(),
500            video_capturer, previous_format, desired_format, options));
501 }
502 
AddVideoRenderer(VideoCapturer * capturer,VideoRenderer * renderer)503 bool ChannelManager::AddVideoRenderer(
504     VideoCapturer* capturer, VideoRenderer* renderer) {
505   return initialized_ && worker_thread_->Invoke<bool>(
506       Bind(&CaptureManager::AddVideoRenderer,
507            capture_manager_.get(), capturer, renderer));
508 }
509 
RemoveVideoRenderer(VideoCapturer * capturer,VideoRenderer * renderer)510 bool ChannelManager::RemoveVideoRenderer(
511     VideoCapturer* capturer, VideoRenderer* renderer) {
512   return initialized_ && worker_thread_->Invoke<bool>(
513       Bind(&CaptureManager::RemoveVideoRenderer,
514            capture_manager_.get(), capturer, renderer));
515 }
516 
IsScreencastRunning() const517 bool ChannelManager::IsScreencastRunning() const {
518   return initialized_ && worker_thread_->Invoke<bool>(
519       Bind(&ChannelManager::IsScreencastRunning_w, this));
520 }
521 
IsScreencastRunning_w() const522 bool ChannelManager::IsScreencastRunning_w() const {
523   VideoChannels::const_iterator it = video_channels_.begin();
524   for ( ; it != video_channels_.end(); ++it) {
525     if ((*it) && (*it)->IsScreencasting()) {
526       return true;
527     }
528   }
529   return false;
530 }
531 
OnVideoCaptureStateChange(VideoCapturer * capturer,CaptureState result)532 void ChannelManager::OnVideoCaptureStateChange(VideoCapturer* capturer,
533                                                CaptureState result) {
534   // TODO(whyuan): Check capturer and signal failure only for camera video, not
535   // screencast.
536   capturing_ = result == CS_RUNNING;
537   main_thread_->Post(this, MSG_VIDEOCAPTURESTATE,
538                      new CaptureStateParams(capturer, result));
539 }
540 
OnMessage(rtc::Message * message)541 void ChannelManager::OnMessage(rtc::Message* message) {
542   switch (message->message_id) {
543     case MSG_VIDEOCAPTURESTATE: {
544       CaptureStateParams* data =
545           static_cast<CaptureStateParams*>(message->pdata);
546       SignalVideoCaptureStateChange(data->capturer, data->state);
547       delete data;
548       break;
549     }
550   }
551 }
552 
StartAecDump(rtc::PlatformFile file)553 bool ChannelManager::StartAecDump(rtc::PlatformFile file) {
554   return worker_thread_->Invoke<bool>(
555       Bind(&MediaEngineInterface::StartAecDump, media_engine_.get(), file));
556 }
557 
StopAecDump()558 void ChannelManager::StopAecDump() {
559   worker_thread_->Invoke<void>(
560       Bind(&MediaEngineInterface::StopAecDump, media_engine_.get()));
561 }
562 
StartRtcEventLog(rtc::PlatformFile file)563 bool ChannelManager::StartRtcEventLog(rtc::PlatformFile file) {
564   return worker_thread_->Invoke<bool>(
565       Bind(&MediaEngineInterface::StartRtcEventLog, media_engine_.get(), file));
566 }
567 
StopRtcEventLog()568 void ChannelManager::StopRtcEventLog() {
569   worker_thread_->Invoke<void>(
570       Bind(&MediaEngineInterface::StopRtcEventLog, media_engine_.get()));
571 }
572 
573 }  // namespace cricket
574