blob: ce8f473600025454c7a0d6cb2f611027bb9f076f [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
Steve Anton10542f22019-01-11 09:11:00 -080011#include "pc/channel_manager.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000012
Steve Anton36b29d12017-10-30 09:57:42 -070013#include <utility>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000014
Steve Anton64b626b2019-01-28 17:25:26 -080015#include "absl/algorithm/container.h"
Karl Wiberg918f50c2018-07-05 11:40:33 +020016#include "absl/memory/memory.h"
Niels Möller3c7d5992018-10-19 15:29:54 +020017#include "absl/strings/match.h"
Steve Anton10542f22019-01-11 09:11:00 -080018#include "media/base/media_constants.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "rtc_base/checks.h"
Yves Gerey3e707812018-11-28 16:47:49 +010020#include "rtc_base/location.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "rtc_base/logging.h"
Yves Gerey3e707812018-11-28 16:47:49 +010022#include "rtc_base/thread_checker.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "rtc_base/trace_event.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000024
25namespace cricket {
26
Steve Antonc9e15602017-11-06 15:40:09 -080027ChannelManager::ChannelManager(
28 std::unique_ptr<MediaEngineInterface> media_engine,
29 std::unique_ptr<DataEngineInterface> data_engine,
30 rtc::Thread* worker_thread,
31 rtc::Thread* network_thread)
32 : media_engine_(std::move(media_engine)),
33 data_engine_(std::move(data_engine)),
34 main_thread_(rtc::Thread::Current()),
35 worker_thread_(worker_thread),
36 network_thread_(network_thread) {
37 RTC_DCHECK(data_engine_);
38 RTC_DCHECK(worker_thread_);
39 RTC_DCHECK(network_thread_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +000040}
41
42ChannelManager::~ChannelManager() {
wu@webrtc.org9dba5252013-08-05 20:36:57 +000043 if (initialized_) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000044 Terminate();
wu@webrtc.org9dba5252013-08-05 20:36:57 +000045 }
perkjc11b1842016-03-07 17:34:13 -080046 // The media engine needs to be deleted on the worker thread for thread safe
47 // destruction,
Steve Antonc9e15602017-11-06 15:40:09 -080048 worker_thread_->Invoke<void>(RTC_FROM_HERE, [&] { media_engine_.reset(); });
henrike@webrtc.org28e20752013-07-10 00:45:36 +000049}
50
51bool ChannelManager::SetVideoRtxEnabled(bool enable) {
52 // To be safe, this call is only allowed before initialization. Apps like
53 // Flute only have a singleton ChannelManager and we don't want this flag to
54 // be toggled between calls or when there's concurrent calls. We expect apps
55 // to enable this at startup and retain that setting for the lifetime of the
56 // app.
57 if (!initialized_) {
58 enable_rtx_ = enable;
59 return true;
60 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +010061 RTC_LOG(LS_WARNING) << "Cannot toggle rtx after initialization!";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000062 return false;
63 }
64}
65
ossudedfd282016-06-14 07:12:39 -070066void ChannelManager::GetSupportedAudioSendCodecs(
henrike@webrtc.org28e20752013-07-10 00:45:36 +000067 std::vector<AudioCodec>* codecs) const {
zhihuang38ede132017-06-15 12:52:32 -070068 if (!media_engine_) {
69 return;
70 }
Sebastian Jansson6eb8a162018-11-16 11:29:55 +010071 *codecs = media_engine_->voice().send_codecs();
ossudedfd282016-06-14 07:12:39 -070072}
henrike@webrtc.org28e20752013-07-10 00:45:36 +000073
ossudedfd282016-06-14 07:12:39 -070074void ChannelManager::GetSupportedAudioReceiveCodecs(
75 std::vector<AudioCodec>* codecs) const {
zhihuang38ede132017-06-15 12:52:32 -070076 if (!media_engine_) {
77 return;
78 }
Sebastian Jansson6eb8a162018-11-16 11:29:55 +010079 *codecs = media_engine_->voice().recv_codecs();
henrike@webrtc.org28e20752013-07-10 00:45:36 +000080}
81
82void ChannelManager::GetSupportedAudioRtpHeaderExtensions(
83 RtpHeaderExtensions* ext) const {
zhihuang38ede132017-06-15 12:52:32 -070084 if (!media_engine_) {
85 return;
86 }
Sebastian Jansson6eb8a162018-11-16 11:29:55 +010087 *ext = media_engine_->voice().GetCapabilities().header_extensions;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000088}
89
magjed3cf8ece2016-11-10 03:36:53 -080090void ChannelManager::GetSupportedVideoCodecs(
91 std::vector<VideoCodec>* codecs) const {
zhihuang38ede132017-06-15 12:52:32 -070092 if (!media_engine_) {
93 return;
94 }
magjed3cf8ece2016-11-10 03:36:53 -080095 codecs->clear();
96
Mirko Bonadeif5ecb5f2020-01-13 08:12:47 +000097 std::vector<VideoCodec> video_codecs = media_engine_->video().codecs();
brandtrffc61182016-11-28 06:02:22 -080098 for (const auto& video_codec : video_codecs) {
99 if (!enable_rtx_ &&
Niels Möller3c7d5992018-10-19 15:29:54 +0200100 absl::EqualsIgnoreCase(kRtxCodecName, video_codec.name)) {
magjed3cf8ece2016-11-10 03:36:53 -0800101 continue;
102 }
brandtrffc61182016-11-28 06:02:22 -0800103 codecs->push_back(video_codec);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000104 }
105}
106
107void ChannelManager::GetSupportedVideoRtpHeaderExtensions(
108 RtpHeaderExtensions* ext) const {
zhihuang38ede132017-06-15 12:52:32 -0700109 if (!media_engine_) {
110 return;
111 }
Sebastian Jansson6eb8a162018-11-16 11:29:55 +0100112 *ext = media_engine_->video().GetCapabilities().header_extensions;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000113}
114
115void ChannelManager::GetSupportedDataCodecs(
116 std::vector<DataCodec>* codecs) const {
Steve Antonc9e15602017-11-06 15:40:09 -0800117 *codecs = data_engine_->data_codecs();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000118}
119
120bool ChannelManager::Init() {
nisseede5da42017-01-12 05:15:36 -0800121 RTC_DCHECK(!initialized_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000122 if (initialized_) {
123 return false;
124 }
Danil Chapovalov33b01f22016-05-11 19:55:27 +0200125 RTC_DCHECK(network_thread_);
126 RTC_DCHECK(worker_thread_);
127 if (!network_thread_->IsCurrent()) {
128 // Do not allow invoking calls to other threads on the network thread.
Steve Antonc9e15602017-11-06 15:40:09 -0800129 network_thread_->Invoke<void>(
Karl Wiberg32562252019-02-21 13:38:30 +0100130 RTC_FROM_HERE, [&] { network_thread_->DisallowBlockingCalls(); });
henrika@webrtc.org62f6e752015-02-11 08:38:35 +0000131 }
132
zhihuang38ede132017-06-15 12:52:32 -0700133 if (media_engine_) {
Steve Antonc9e15602017-11-06 15:40:09 -0800134 initialized_ = worker_thread_->Invoke<bool>(
135 RTC_FROM_HERE, [&] { return media_engine_->Init(); });
136 RTC_DCHECK(initialized_);
137 } else {
138 initialized_ = true;
zhihuang38ede132017-06-15 12:52:32 -0700139 }
Steve Antonc9e15602017-11-06 15:40:09 -0800140 return initialized_;
henrika@webrtc.org62f6e752015-02-11 08:38:35 +0000141}
142
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000143void ChannelManager::Terminate() {
nisseede5da42017-01-12 05:15:36 -0800144 RTC_DCHECK(initialized_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000145 if (!initialized_) {
146 return;
147 }
Steve Antonc9e15602017-11-06 15:40:09 -0800148 // Need to destroy the channels on the worker thread.
149 worker_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
150 video_channels_.clear();
151 voice_channels_.clear();
152 data_channels_.clear();
153 });
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000154 initialized_ = false;
155}
156
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000157VoiceChannel* ChannelManager::CreateVoiceChannel(
nisseeaabdf62017-05-05 02:23:02 -0700158 webrtc::Call* call,
159 const cricket::MediaConfig& media_config,
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800160 webrtc::RtpTransportInternal* rtp_transport,
Anton Sukhanov4f08faa2019-05-21 11:12:57 -0700161 const webrtc::MediaTransportConfig& media_transport_config,
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800162 rtc::Thread* signaling_thread,
163 const std::string& content_name,
164 bool srtp_required,
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700165 const webrtc::CryptoOptions& crypto_options,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800166 rtc::UniqueRandomIdGenerator* ssrc_generator,
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800167 const AudioOptions& options) {
168 if (!worker_thread_->IsCurrent()) {
169 return worker_thread_->Invoke<VoiceChannel*>(RTC_FROM_HERE, [&] {
Anton Sukhanov4f08faa2019-05-21 11:12:57 -0700170 return CreateVoiceChannel(call, media_config, rtp_transport,
171 media_transport_config, signaling_thread,
172 content_name, srtp_required, crypto_options,
173 ssrc_generator, options);
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800174 });
175 }
176
177 RTC_DCHECK_RUN_ON(worker_thread_);
178 RTC_DCHECK(initialized_);
179 RTC_DCHECK(call);
180 if (!media_engine_) {
181 return nullptr;
182 }
183
Sebastian Jansson6eb8a162018-11-16 11:29:55 +0100184 VoiceMediaChannel* media_channel = media_engine_->voice().CreateMediaChannel(
185 call, media_config, options, crypto_options);
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800186 if (!media_channel) {
187 return nullptr;
188 }
189
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200190 auto voice_channel = std::make_unique<VoiceChannel>(
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800191 worker_thread_, network_thread_, signaling_thread,
Karl Wiberg918f50c2018-07-05 11:40:33 +0200192 absl::WrapUnique(media_channel), content_name, srtp_required,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800193 crypto_options, ssrc_generator);
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800194
Anton Sukhanov4f08faa2019-05-21 11:12:57 -0700195 voice_channel->Init_w(rtp_transport, media_transport_config);
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800196
197 VoiceChannel* voice_channel_ptr = voice_channel.get();
198 voice_channels_.push_back(std::move(voice_channel));
199 return voice_channel_ptr;
200}
201
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200202void ChannelManager::DestroyVoiceChannel(VoiceChannel* voice_channel) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100203 TRACE_EVENT0("webrtc", "ChannelManager::DestroyVoiceChannel");
Steve Antonc9e15602017-11-06 15:40:09 -0800204 if (!voice_channel) {
205 return;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000206 }
Steve Antonc9e15602017-11-06 15:40:09 -0800207 if (!worker_thread_->IsCurrent()) {
208 worker_thread_->Invoke<void>(RTC_FROM_HERE,
209 [&] { DestroyVoiceChannel(voice_channel); });
210 return;
211 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000212
nisseede5da42017-01-12 05:15:36 -0800213 RTC_DCHECK(initialized_);
Steve Anton774115c2017-08-30 10:48:46 -0700214
Steve Anton64b626b2019-01-28 17:25:26 -0800215 auto it = absl::c_find_if(voice_channels_,
216 [&](const std::unique_ptr<VoiceChannel>& p) {
217 return p.get() == voice_channel;
218 });
nisseede5da42017-01-12 05:15:36 -0800219 RTC_DCHECK(it != voice_channels_.end());
Steve Antonc9e15602017-11-06 15:40:09 -0800220 if (it == voice_channels_.end()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000221 return;
Steve Antonc9e15602017-11-06 15:40:09 -0800222 }
223
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000224 voice_channels_.erase(it);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000225}
226
227VideoChannel* ChannelManager::CreateVideoChannel(
nisseeaabdf62017-05-05 02:23:02 -0700228 webrtc::Call* call,
229 const cricket::MediaConfig& media_config,
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800230 webrtc::RtpTransportInternal* rtp_transport,
Anton Sukhanov4f08faa2019-05-21 11:12:57 -0700231 const webrtc::MediaTransportConfig& media_transport_config,
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800232 rtc::Thread* signaling_thread,
233 const std::string& content_name,
234 bool srtp_required,
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700235 const webrtc::CryptoOptions& crypto_options,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800236 rtc::UniqueRandomIdGenerator* ssrc_generator,
Jonas Orelanda3aa9bd2019-04-17 07:38:40 +0200237 const VideoOptions& options,
238 webrtc::VideoBitrateAllocatorFactory* video_bitrate_allocator_factory) {
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800239 if (!worker_thread_->IsCurrent()) {
240 return worker_thread_->Invoke<VideoChannel*>(RTC_FROM_HERE, [&] {
Anton Sukhanov4f08faa2019-05-21 11:12:57 -0700241 return CreateVideoChannel(
242 call, media_config, rtp_transport, media_transport_config,
243 signaling_thread, content_name, srtp_required, crypto_options,
244 ssrc_generator, options, video_bitrate_allocator_factory);
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800245 });
246 }
247
248 RTC_DCHECK_RUN_ON(worker_thread_);
249 RTC_DCHECK(initialized_);
250 RTC_DCHECK(call);
251 if (!media_engine_) {
252 return nullptr;
253 }
254
Sebastian Jansson6eb8a162018-11-16 11:29:55 +0100255 VideoMediaChannel* media_channel = media_engine_->video().CreateMediaChannel(
Jonas Orelanda3aa9bd2019-04-17 07:38:40 +0200256 call, media_config, options, crypto_options,
257 video_bitrate_allocator_factory);
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800258 if (!media_channel) {
259 return nullptr;
260 }
261
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200262 auto video_channel = std::make_unique<VideoChannel>(
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800263 worker_thread_, network_thread_, signaling_thread,
Karl Wiberg918f50c2018-07-05 11:40:33 +0200264 absl::WrapUnique(media_channel), content_name, srtp_required,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800265 crypto_options, ssrc_generator);
Anton Sukhanov98a462c2018-10-17 13:15:42 -0700266
Anton Sukhanov4f08faa2019-05-21 11:12:57 -0700267 video_channel->Init_w(rtp_transport, media_transport_config);
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800268
269 VideoChannel* video_channel_ptr = video_channel.get();
270 video_channels_.push_back(std::move(video_channel));
271 return video_channel_ptr;
272}
273
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000274void ChannelManager::DestroyVideoChannel(VideoChannel* video_channel) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100275 TRACE_EVENT0("webrtc", "ChannelManager::DestroyVideoChannel");
Steve Antonc9e15602017-11-06 15:40:09 -0800276 if (!video_channel) {
277 return;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000278 }
Steve Antonc9e15602017-11-06 15:40:09 -0800279 if (!worker_thread_->IsCurrent()) {
280 worker_thread_->Invoke<void>(RTC_FROM_HERE,
281 [&] { DestroyVideoChannel(video_channel); });
282 return;
283 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000284
nisseede5da42017-01-12 05:15:36 -0800285 RTC_DCHECK(initialized_);
Steve Anton774115c2017-08-30 10:48:46 -0700286
Steve Anton64b626b2019-01-28 17:25:26 -0800287 auto it = absl::c_find_if(video_channels_,
288 [&](const std::unique_ptr<VideoChannel>& p) {
289 return p.get() == video_channel;
290 });
nisseede5da42017-01-12 05:15:36 -0800291 RTC_DCHECK(it != video_channels_.end());
Steve Antonc9e15602017-11-06 15:40:09 -0800292 if (it == video_channels_.end()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000293 return;
Steve Antonc9e15602017-11-06 15:40:09 -0800294 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000295
296 video_channels_.erase(it);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000297}
298
deadbeef953c2ce2017-01-09 14:53:41 -0800299RtpDataChannel* ChannelManager::CreateRtpDataChannel(
nisseeaabdf62017-05-05 02:23:02 -0700300 const cricket::MediaConfig& media_config,
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800301 webrtc::RtpTransportInternal* rtp_transport,
302 rtc::Thread* signaling_thread,
303 const std::string& content_name,
Zhi Huange830e682018-03-30 10:48:35 -0700304 bool srtp_required,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800305 const webrtc::CryptoOptions& crypto_options,
306 rtc::UniqueRandomIdGenerator* ssrc_generator) {
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800307 if (!worker_thread_->IsCurrent()) {
308 return worker_thread_->Invoke<RtpDataChannel*>(RTC_FROM_HERE, [&] {
309 return CreateRtpDataChannel(media_config, rtp_transport, signaling_thread,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800310 content_name, srtp_required, crypto_options,
311 ssrc_generator);
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800312 });
313 }
314
315 // This is ok to alloc from a thread other than the worker thread.
316 RTC_DCHECK(initialized_);
317 DataMediaChannel* media_channel = data_engine_->CreateChannel(media_config);
318 if (!media_channel) {
319 RTC_LOG(LS_WARNING) << "Failed to create RTP data channel.";
320 return nullptr;
321 }
322
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200323 auto data_channel = std::make_unique<RtpDataChannel>(
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800324 worker_thread_, network_thread_, signaling_thread,
Karl Wiberg918f50c2018-07-05 11:40:33 +0200325 absl::WrapUnique(media_channel), content_name, srtp_required,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800326 crypto_options, ssrc_generator);
Anton Sukhanov4f08faa2019-05-21 11:12:57 -0700327
328 // Media Transports are not supported with Rtp Data Channel.
329 data_channel->Init_w(rtp_transport, webrtc::MediaTransportConfig());
Zhi Huang2dfc42d2017-12-04 13:38:48 -0800330
331 RtpDataChannel* data_channel_ptr = data_channel.get();
332 data_channels_.push_back(std::move(data_channel));
333 return data_channel_ptr;
334}
335
deadbeef953c2ce2017-01-09 14:53:41 -0800336void ChannelManager::DestroyRtpDataChannel(RtpDataChannel* data_channel) {
337 TRACE_EVENT0("webrtc", "ChannelManager::DestroyRtpDataChannel");
Steve Antonc9e15602017-11-06 15:40:09 -0800338 if (!data_channel) {
339 return;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000340 }
Steve Antonc9e15602017-11-06 15:40:09 -0800341 if (!worker_thread_->IsCurrent()) {
342 worker_thread_->Invoke<void>(
343 RTC_FROM_HERE, [&] { return DestroyRtpDataChannel(data_channel); });
344 return;
345 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000346
nisseede5da42017-01-12 05:15:36 -0800347 RTC_DCHECK(initialized_);
Steve Anton774115c2017-08-30 10:48:46 -0700348
Steve Anton64b626b2019-01-28 17:25:26 -0800349 auto it = absl::c_find_if(data_channels_,
350 [&](const std::unique_ptr<RtpDataChannel>& p) {
351 return p.get() == data_channel;
352 });
nisseede5da42017-01-12 05:15:36 -0800353 RTC_DCHECK(it != data_channels_.end());
Steve Antonc9e15602017-11-06 15:40:09 -0800354 if (it == data_channels_.end()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000355 return;
Steve Antonc9e15602017-11-06 15:40:09 -0800356 }
Zhi Huang95e7dbb2018-03-29 00:08:03 +0000357
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000358 data_channels_.erase(it);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000359}
360
Niels Möllere8e4dc42019-06-11 14:04:16 +0200361bool ChannelManager::StartAecDump(webrtc::FileWrapper file,
ivocd66b44d2016-01-15 03:06:36 -0800362 int64_t max_size_bytes) {
Steve Antonc9e15602017-11-06 15:40:09 -0800363 return worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
Niels Möllere8e4dc42019-06-11 14:04:16 +0200364 return media_engine_->voice().StartAecDump(std::move(file), max_size_bytes);
Steve Antonc9e15602017-11-06 15:40:09 -0800365 });
wu@webrtc.orga9890802013-12-13 00:21:03 +0000366}
367
ivoc797ef122015-10-22 03:25:41 -0700368void ChannelManager::StopAecDump() {
Steve Antonc9e15602017-11-06 15:40:09 -0800369 worker_thread_->Invoke<void>(RTC_FROM_HERE,
Sebastian Jansson6eb8a162018-11-16 11:29:55 +0100370 [&] { media_engine_->voice().StopAecDump(); });
ivoc797ef122015-10-22 03:25:41 -0700371}
372
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000373} // namespace cricket