blob: 6e6623cf2bd19bb136b19c293b9c114f8bda9f67 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellander65c7f672016-02-12 00:05:01 -08002 * Copyright 2004 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellander65c7f672016-02-12 00:05:01 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
kjellander@webrtc.org9b8df252016-02-12 06:47:59 +010011#include "webrtc/pc/channelmanager.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000012
13#ifdef HAVE_CONFIG_H
14#include <config.h>
15#endif
16
17#include <algorithm>
18
Henrik Kjellander15583c12016-02-10 10:53:12 +010019#include "webrtc/api/mediacontroller.h"
20#include "webrtc/base/bind.h"
21#include "webrtc/base/common.h"
22#include "webrtc/base/logging.h"
Henrik Kjellander15583c12016-02-10 10:53:12 +010023#include "webrtc/base/stringencode.h"
24#include "webrtc/base/stringutils.h"
25#include "webrtc/base/trace_event.h"
kjellandera96e2d72016-02-04 23:52:28 -080026#include "webrtc/media/base/device.h"
27#include "webrtc/media/base/hybriddataengine.h"
28#include "webrtc/media/base/rtpdataengine.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000029#ifdef HAVE_SCTP
kjellandera96e2d72016-02-04 23:52:28 -080030#include "webrtc/media/sctp/sctpdataengine.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000031#endif
kjellander@webrtc.org9b8df252016-02-12 06:47:59 +010032#include "webrtc/pc/srtpfilter.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000033
34namespace cricket {
35
henrike@webrtc.org28e20752013-07-10 00:45:36 +000036
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000037using rtc::Bind;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000038
39static const int kNotSetOutputVolume = -1;
40
henrike@webrtc.org28e20752013-07-10 00:45:36 +000041static DataEngineInterface* ConstructDataEngine() {
42#ifdef HAVE_SCTP
43 return new HybridDataEngine(new RtpDataEngine(), new SctpDataEngine());
44#else
45 return new RtpDataEngine();
46#endif
47}
48
henrike@webrtc.org28e20752013-07-10 00:45:36 +000049ChannelManager::ChannelManager(MediaEngineInterface* me,
50 DataEngineInterface* dme,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000051 rtc::Thread* worker_thread) {
perkjc11b1842016-03-07 17:34:13 -080052 Construct(me, dme, worker_thread);
henrike@webrtc.org28e20752013-07-10 00:45:36 +000053}
54
55ChannelManager::ChannelManager(MediaEngineInterface* me,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000056 rtc::Thread* worker_thread) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000057 Construct(me,
58 ConstructDataEngine(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000059 worker_thread);
60}
61
62void ChannelManager::Construct(MediaEngineInterface* me,
63 DataEngineInterface* dme,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000064 rtc::Thread* worker_thread) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000065 media_engine_.reset(me);
66 data_media_engine_.reset(dme);
henrike@webrtc.org28e20752013-07-10 00:45:36 +000067 initialized_ = false;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000068 main_thread_ = rtc::Thread::Current();
henrike@webrtc.org28e20752013-07-10 00:45:36 +000069 worker_thread_ = worker_thread;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000070 audio_output_volume_ = kNotSetOutputVolume;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000071 capturing_ = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000072 enable_rtx_ = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000073}
74
75ChannelManager::~ChannelManager() {
wu@webrtc.org9dba5252013-08-05 20:36:57 +000076 if (initialized_) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000077 Terminate();
wu@webrtc.org9dba5252013-08-05 20:36:57 +000078 // If srtp is initialized (done by the Channel) then we must call
79 // srtp_shutdown to free all crypto kernel lists. But we need to make sure
80 // shutdown always called at the end, after channels are destroyed.
81 // ChannelManager d'tor is always called last, it's safe place to call
82 // shutdown.
83 ShutdownSrtp();
84 }
perkjc11b1842016-03-07 17:34:13 -080085 // The media engine needs to be deleted on the worker thread for thread safe
86 // destruction,
henrika@webrtc.org62f6e752015-02-11 08:38:35 +000087 worker_thread_->Invoke<void>(Bind(
hbos@webrtc.org4aef5fe2015-02-25 10:09:05 +000088 &ChannelManager::DestructorDeletes_w, this));
henrike@webrtc.org28e20752013-07-10 00:45:36 +000089}
90
91bool ChannelManager::SetVideoRtxEnabled(bool enable) {
92 // To be safe, this call is only allowed before initialization. Apps like
93 // Flute only have a singleton ChannelManager and we don't want this flag to
94 // be toggled between calls or when there's concurrent calls. We expect apps
95 // to enable this at startup and retain that setting for the lifetime of the
96 // app.
97 if (!initialized_) {
98 enable_rtx_ = enable;
99 return true;
100 } else {
101 LOG(LS_WARNING) << "Cannot toggle rtx after initialization!";
102 return false;
103 }
104}
105
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000106void ChannelManager::GetSupportedAudioCodecs(
107 std::vector<AudioCodec>* codecs) const {
108 codecs->clear();
109
110 for (std::vector<AudioCodec>::const_iterator it =
111 media_engine_->audio_codecs().begin();
112 it != media_engine_->audio_codecs().end(); ++it) {
113 codecs->push_back(*it);
114 }
115}
116
117void ChannelManager::GetSupportedAudioRtpHeaderExtensions(
118 RtpHeaderExtensions* ext) const {
Stefan Holmer9d69c3f2015-12-07 10:45:43 +0100119 *ext = media_engine_->GetAudioCapabilities().header_extensions;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000120}
121
122void ChannelManager::GetSupportedVideoCodecs(
123 std::vector<VideoCodec>* codecs) const {
124 codecs->clear();
125
126 std::vector<VideoCodec>::const_iterator it;
127 for (it = media_engine_->video_codecs().begin();
128 it != media_engine_->video_codecs().end(); ++it) {
129 if (!enable_rtx_ && _stricmp(kRtxCodecName, it->name.c_str()) == 0) {
130 continue;
131 }
132 codecs->push_back(*it);
133 }
134}
135
136void ChannelManager::GetSupportedVideoRtpHeaderExtensions(
137 RtpHeaderExtensions* ext) const {
Stefan Holmer9d69c3f2015-12-07 10:45:43 +0100138 *ext = media_engine_->GetVideoCapabilities().header_extensions;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000139}
140
141void ChannelManager::GetSupportedDataCodecs(
142 std::vector<DataCodec>* codecs) const {
143 *codecs = data_media_engine_->data_codecs();
144}
145
146bool ChannelManager::Init() {
147 ASSERT(!initialized_);
148 if (initialized_) {
149 return false;
150 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000151 ASSERT(worker_thread_ != NULL);
henrika@webrtc.org62f6e752015-02-11 08:38:35 +0000152 if (!worker_thread_) {
153 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000154 }
henrika@webrtc.org62f6e752015-02-11 08:38:35 +0000155 if (worker_thread_ != rtc::Thread::Current()) {
156 // Do not allow invoking calls to other threads on the worker thread.
157 worker_thread_->Invoke<bool>(rtc::Bind(
158 &rtc::Thread::SetAllowBlockingCalls, worker_thread_, false));
159 }
160
161 initialized_ = worker_thread_->Invoke<bool>(Bind(
162 &ChannelManager::InitMediaEngine_w, this));
163 ASSERT(initialized_);
164 if (!initialized_) {
165 return false;
166 }
167
henrika@webrtc.org62f6e752015-02-11 08:38:35 +0000168 // If audio_output_volume_ has been set via SetOutputVolume(), set the
169 // audio output volume of the engine.
170 if (kNotSetOutputVolume != audio_output_volume_ &&
171 !SetOutputVolume(audio_output_volume_)) {
172 LOG(LS_WARNING) << "Failed to SetOutputVolume to "
173 << audio_output_volume_;
174 }
henrika@webrtc.org62f6e752015-02-11 08:38:35 +0000175
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000176 return initialized_;
177}
178
henrika@webrtc.org62f6e752015-02-11 08:38:35 +0000179bool ChannelManager::InitMediaEngine_w() {
180 ASSERT(worker_thread_ == rtc::Thread::Current());
181 return (media_engine_->Init(worker_thread_));
182}
183
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000184void ChannelManager::Terminate() {
185 ASSERT(initialized_);
186 if (!initialized_) {
187 return;
188 }
189 worker_thread_->Invoke<void>(Bind(&ChannelManager::Terminate_w, this));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000190 initialized_ = false;
191}
192
hbos@webrtc.org4aef5fe2015-02-25 10:09:05 +0000193void ChannelManager::DestructorDeletes_w() {
henrika@webrtc.org62f6e752015-02-11 08:38:35 +0000194 ASSERT(worker_thread_ == rtc::Thread::Current());
195 media_engine_.reset(NULL);
196}
197
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000198void ChannelManager::Terminate_w() {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000199 ASSERT(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000200 // Need to destroy the voice/video channels
201 while (!video_channels_.empty()) {
202 DestroyVideoChannel_w(video_channels_.back());
203 }
204 while (!voice_channels_.empty()) {
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200205 DestroyVoiceChannel_w(voice_channels_.back());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000206 }
henrika@webrtc.org62f6e752015-02-11 08:38:35 +0000207 media_engine_->Terminate();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000208}
209
210VoiceChannel* ChannelManager::CreateVoiceChannel(
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200211 webrtc::MediaControllerInterface* media_controller,
deadbeefcbecd352015-09-23 11:50:27 -0700212 TransportController* transport_controller,
Jelena Marusicc28a8962015-05-29 15:05:44 +0200213 const std::string& content_name,
214 bool rtcp,
215 const AudioOptions& options) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000216 return worker_thread_->Invoke<VoiceChannel*>(
deadbeefcbecd352015-09-23 11:50:27 -0700217 Bind(&ChannelManager::CreateVoiceChannel_w, this, media_controller,
218 transport_controller, content_name, rtcp, options));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000219}
220
221VoiceChannel* ChannelManager::CreateVoiceChannel_w(
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200222 webrtc::MediaControllerInterface* media_controller,
deadbeefcbecd352015-09-23 11:50:27 -0700223 TransportController* transport_controller,
Jelena Marusicc28a8962015-05-29 15:05:44 +0200224 const std::string& content_name,
225 bool rtcp,
226 const AudioOptions& options) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000227 ASSERT(initialized_);
Fredrik Solenberg4b60c732015-05-07 14:07:48 +0200228 ASSERT(worker_thread_ == rtc::Thread::Current());
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200229 ASSERT(nullptr != media_controller);
nisse51542be2016-02-12 02:27:06 -0800230 VoiceMediaChannel* media_channel = media_engine_->CreateChannel(
231 media_controller->call_w(), media_controller->config(), options);
Jelena Marusicc28a8962015-05-29 15:05:44 +0200232 if (!media_channel)
233 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000234
deadbeefcbecd352015-09-23 11:50:27 -0700235 VoiceChannel* voice_channel =
236 new VoiceChannel(worker_thread_, media_engine_.get(), media_channel,
237 transport_controller, content_name, rtcp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000238 if (!voice_channel->Init()) {
239 delete voice_channel;
Jelena Marusicc28a8962015-05-29 15:05:44 +0200240 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000241 }
242 voice_channels_.push_back(voice_channel);
243 return voice_channel;
244}
245
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200246void ChannelManager::DestroyVoiceChannel(VoiceChannel* voice_channel) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100247 TRACE_EVENT0("webrtc", "ChannelManager::DestroyVoiceChannel");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000248 if (voice_channel) {
249 worker_thread_->Invoke<void>(
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200250 Bind(&ChannelManager::DestroyVoiceChannel_w, this, voice_channel));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000251 }
252}
253
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200254void ChannelManager::DestroyVoiceChannel_w(VoiceChannel* voice_channel) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100255 TRACE_EVENT0("webrtc", "ChannelManager::DestroyVoiceChannel_w");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000256 // Destroy voice channel.
257 ASSERT(initialized_);
Fredrik Solenberg4b60c732015-05-07 14:07:48 +0200258 ASSERT(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000259 VoiceChannels::iterator it = std::find(voice_channels_.begin(),
260 voice_channels_.end(), voice_channel);
261 ASSERT(it != voice_channels_.end());
262 if (it == voice_channels_.end())
263 return;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000264 voice_channels_.erase(it);
265 delete voice_channel;
266}
267
268VideoChannel* ChannelManager::CreateVideoChannel(
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200269 webrtc::MediaControllerInterface* media_controller,
deadbeefcbecd352015-09-23 11:50:27 -0700270 TransportController* transport_controller,
buildbot@webrtc.org1ecbe452014-10-14 20:29:28 +0000271 const std::string& content_name,
272 bool rtcp,
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200273 const VideoOptions& options) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000274 return worker_thread_->Invoke<VideoChannel*>(
deadbeefcbecd352015-09-23 11:50:27 -0700275 Bind(&ChannelManager::CreateVideoChannel_w, this, media_controller,
276 transport_controller, content_name, rtcp, options));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000277}
278
279VideoChannel* ChannelManager::CreateVideoChannel_w(
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200280 webrtc::MediaControllerInterface* media_controller,
deadbeefcbecd352015-09-23 11:50:27 -0700281 TransportController* transport_controller,
buildbot@webrtc.org1ecbe452014-10-14 20:29:28 +0000282 const std::string& content_name,
283 bool rtcp,
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200284 const VideoOptions& options) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000285 ASSERT(initialized_);
Fredrik Solenberg4b60c732015-05-07 14:07:48 +0200286 ASSERT(worker_thread_ == rtc::Thread::Current());
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200287 ASSERT(nullptr != media_controller);
nisse51542be2016-02-12 02:27:06 -0800288 VideoMediaChannel* media_channel = media_engine_->CreateVideoChannel(
289 media_controller->call_w(), media_controller->config(), options);
deadbeefcbecd352015-09-23 11:50:27 -0700290 if (media_channel == NULL) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000291 return NULL;
deadbeefcbecd352015-09-23 11:50:27 -0700292 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000293
294 VideoChannel* video_channel = new VideoChannel(
deadbeefcbecd352015-09-23 11:50:27 -0700295 worker_thread_, media_channel, transport_controller, content_name, rtcp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000296 if (!video_channel->Init()) {
297 delete video_channel;
298 return NULL;
299 }
300 video_channels_.push_back(video_channel);
301 return video_channel;
302}
303
304void ChannelManager::DestroyVideoChannel(VideoChannel* video_channel) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100305 TRACE_EVENT0("webrtc", "ChannelManager::DestroyVideoChannel");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000306 if (video_channel) {
307 worker_thread_->Invoke<void>(
308 Bind(&ChannelManager::DestroyVideoChannel_w, this, video_channel));
309 }
310}
311
312void ChannelManager::DestroyVideoChannel_w(VideoChannel* video_channel) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100313 TRACE_EVENT0("webrtc", "ChannelManager::DestroyVideoChannel_w");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000314 // Destroy video channel.
315 ASSERT(initialized_);
Fredrik Solenberg4b60c732015-05-07 14:07:48 +0200316 ASSERT(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000317 VideoChannels::iterator it = std::find(video_channels_.begin(),
318 video_channels_.end(), video_channel);
319 ASSERT(it != video_channels_.end());
320 if (it == video_channels_.end())
321 return;
322
323 video_channels_.erase(it);
324 delete video_channel;
325}
326
327DataChannel* ChannelManager::CreateDataChannel(
deadbeefcbecd352015-09-23 11:50:27 -0700328 TransportController* transport_controller,
329 const std::string& content_name,
330 bool rtcp,
331 DataChannelType channel_type) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000332 return worker_thread_->Invoke<DataChannel*>(
deadbeefcbecd352015-09-23 11:50:27 -0700333 Bind(&ChannelManager::CreateDataChannel_w, this, transport_controller,
334 content_name, rtcp, channel_type));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000335}
336
337DataChannel* ChannelManager::CreateDataChannel_w(
deadbeefcbecd352015-09-23 11:50:27 -0700338 TransportController* transport_controller,
339 const std::string& content_name,
340 bool rtcp,
341 DataChannelType data_channel_type) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000342 // This is ok to alloc from a thread other than the worker thread.
343 ASSERT(initialized_);
344 DataMediaChannel* media_channel = data_media_engine_->CreateChannel(
345 data_channel_type);
346 if (!media_channel) {
347 LOG(LS_WARNING) << "Failed to create data channel of type "
348 << data_channel_type;
349 return NULL;
350 }
351
352 DataChannel* data_channel = new DataChannel(
deadbeefcbecd352015-09-23 11:50:27 -0700353 worker_thread_, media_channel, transport_controller, content_name, rtcp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000354 if (!data_channel->Init()) {
355 LOG(LS_WARNING) << "Failed to init data channel.";
356 delete data_channel;
357 return NULL;
358 }
359 data_channels_.push_back(data_channel);
360 return data_channel;
361}
362
363void ChannelManager::DestroyDataChannel(DataChannel* data_channel) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100364 TRACE_EVENT0("webrtc", "ChannelManager::DestroyDataChannel");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000365 if (data_channel) {
366 worker_thread_->Invoke<void>(
367 Bind(&ChannelManager::DestroyDataChannel_w, this, data_channel));
368 }
369}
370
371void ChannelManager::DestroyDataChannel_w(DataChannel* data_channel) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100372 TRACE_EVENT0("webrtc", "ChannelManager::DestroyDataChannel_w");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000373 // Destroy data channel.
374 ASSERT(initialized_);
375 DataChannels::iterator it = std::find(data_channels_.begin(),
376 data_channels_.end(), data_channel);
377 ASSERT(it != data_channels_.end());
378 if (it == data_channels_.end())
379 return;
380
381 data_channels_.erase(it);
382 delete data_channel;
383}
384
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000385bool ChannelManager::GetOutputVolume(int* level) {
386 if (!initialized_) {
387 return false;
388 }
389 return worker_thread_->Invoke<bool>(
390 Bind(&MediaEngineInterface::GetOutputVolume, media_engine_.get(), level));
391}
392
393bool ChannelManager::SetOutputVolume(int level) {
394 bool ret = level >= 0 && level <= 255;
395 if (initialized_) {
396 ret &= worker_thread_->Invoke<bool>(
397 Bind(&MediaEngineInterface::SetOutputVolume,
398 media_engine_.get(), level));
399 }
400
401 if (ret) {
402 audio_output_volume_ = level;
403 }
404
405 return ret;
406}
407
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000408
ivocd66b44d2016-01-15 03:06:36 -0800409bool ChannelManager::StartAecDump(rtc::PlatformFile file,
410 int64_t max_size_bytes) {
411 return worker_thread_->Invoke<bool>(Bind(&MediaEngineInterface::StartAecDump,
412 media_engine_.get(), file,
413 max_size_bytes));
wu@webrtc.orga9890802013-12-13 00:21:03 +0000414}
415
ivoc797ef122015-10-22 03:25:41 -0700416void ChannelManager::StopAecDump() {
417 worker_thread_->Invoke<void>(
418 Bind(&MediaEngineInterface::StopAecDump, media_engine_.get()));
419}
420
ivoc112a3d82015-10-16 02:22:18 -0700421bool ChannelManager::StartRtcEventLog(rtc::PlatformFile file) {
422 return worker_thread_->Invoke<bool>(
423 Bind(&MediaEngineInterface::StartRtcEventLog, media_engine_.get(), file));
424}
425
426void ChannelManager::StopRtcEventLog() {
427 worker_thread_->Invoke<void>(
428 Bind(&MediaEngineInterface::StopRtcEventLog, media_engine_.get()));
429}
430
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000431} // namespace cricket