blob: c109d60388bb5fb37e4aaa856bbe6b048b292599 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2004 Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "talk/session/media/channelmanager.h"
29
30#ifdef HAVE_CONFIG_H
31#include <config.h>
32#endif
33
34#include <algorithm>
35
Fredrik Solenberg709ed672015-09-15 12:26:33 +020036#include "talk/app/webrtc/mediacontroller.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000037#include "talk/media/base/capturemanager.h"
38#include "talk/media/base/hybriddataengine.h"
39#include "talk/media/base/rtpdataengine.h"
40#include "talk/media/base/videocapturer.h"
henrike@webrtc.org723d6832013-07-12 16:04:50 +000041#include "talk/media/devices/devicemanager.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000042#ifdef HAVE_SCTP
43#include "talk/media/sctp/sctpdataengine.h"
44#endif
wu@webrtc.org9dba5252013-08-05 20:36:57 +000045#include "talk/session/media/srtpfilter.h"
buildbot@webrtc.org65b98d12014-08-07 22:09:08 +000046#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"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000052
53namespace cricket {
54
55enum {
56 MSG_VIDEOCAPTURESTATE = 1,
57};
58
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000059using rtc::Bind;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000060
61static const int kNotSetOutputVolume = -1;
62
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000063struct CaptureStateParams : public rtc::MessageData {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000064 CaptureStateParams(cricket::VideoCapturer* c, cricket::CaptureState s)
65 : capturer(c),
66 state(s) {}
67 cricket::VideoCapturer* capturer;
68 cricket::CaptureState state;
69};
70
71static DataEngineInterface* ConstructDataEngine() {
72#ifdef HAVE_SCTP
73 return new HybridDataEngine(new RtpDataEngine(), new SctpDataEngine());
74#else
75 return new RtpDataEngine();
76#endif
77}
78
henrike@webrtc.org28e20752013-07-10 00:45:36 +000079ChannelManager::ChannelManager(MediaEngineInterface* me,
80 DataEngineInterface* dme,
81 DeviceManagerInterface* dm,
82 CaptureManager* cm,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000083 rtc::Thread* worker_thread) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000084 Construct(me, dme, dm, cm, worker_thread);
85}
86
87ChannelManager::ChannelManager(MediaEngineInterface* me,
88 DeviceManagerInterface* dm,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000089 rtc::Thread* worker_thread) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000090 Construct(me,
91 ConstructDataEngine(),
92 dm,
93 new CaptureManager(),
94 worker_thread);
95}
96
97void ChannelManager::Construct(MediaEngineInterface* me,
98 DataEngineInterface* dme,
99 DeviceManagerInterface* dm,
100 CaptureManager* cm,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000101 rtc::Thread* worker_thread) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000102 media_engine_.reset(me);
103 data_media_engine_.reset(dme);
104 device_manager_.reset(dm);
105 capture_manager_.reset(cm);
106 initialized_ = false;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000107 main_thread_ = rtc::Thread::Current();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000108 worker_thread_ = worker_thread;
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000109 // Get the default audio options from the media engine.
110 audio_options_ = media_engine_->GetAudioOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000111 audio_in_device_ = DeviceManagerInterface::kDefaultDeviceName;
112 audio_out_device_ = DeviceManagerInterface::kDefaultDeviceName;
henrike@webrtc.org0481f152014-08-19 14:56:59 +0000113 audio_delay_offset_ = kDefaultAudioDelayOffset;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000114 audio_output_volume_ = kNotSetOutputVolume;
115 local_renderer_ = NULL;
116 capturing_ = false;
117 monitoring_ = false;
118 enable_rtx_ = false;
119
120 // Init the device manager immediately, and set up our default video device.
121 SignalDevicesChange.repeat(device_manager_->SignalDevicesChange);
122 device_manager_->Init();
123
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000124 capture_manager_->SignalCapturerStateChange.connect(
125 this, &ChannelManager::OnVideoCaptureStateChange);
126}
127
128ChannelManager::~ChannelManager() {
wu@webrtc.org9dba5252013-08-05 20:36:57 +0000129 if (initialized_) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000130 Terminate();
wu@webrtc.org9dba5252013-08-05 20:36:57 +0000131 // If srtp is initialized (done by the Channel) then we must call
132 // srtp_shutdown to free all crypto kernel lists. But we need to make sure
133 // shutdown always called at the end, after channels are destroyed.
134 // ChannelManager d'tor is always called last, it's safe place to call
135 // shutdown.
136 ShutdownSrtp();
137 }
hbos@webrtc.org4aef5fe2015-02-25 10:09:05 +0000138 // Some deletes need to be on the worker thread for thread safe destruction,
139 // this includes the media engine and capture manager.
henrika@webrtc.org62f6e752015-02-11 08:38:35 +0000140 worker_thread_->Invoke<void>(Bind(
hbos@webrtc.org4aef5fe2015-02-25 10:09:05 +0000141 &ChannelManager::DestructorDeletes_w, this));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000142}
143
144bool ChannelManager::SetVideoRtxEnabled(bool enable) {
145 // To be safe, this call is only allowed before initialization. Apps like
146 // Flute only have a singleton ChannelManager and we don't want this flag to
147 // be toggled between calls or when there's concurrent calls. We expect apps
148 // to enable this at startup and retain that setting for the lifetime of the
149 // app.
150 if (!initialized_) {
151 enable_rtx_ = enable;
152 return true;
153 } else {
154 LOG(LS_WARNING) << "Cannot toggle rtx after initialization!";
155 return false;
156 }
157}
158
159int ChannelManager::GetCapabilities() {
160 return media_engine_->GetCapabilities() & device_manager_->GetCapabilities();
161}
162
163void ChannelManager::GetSupportedAudioCodecs(
164 std::vector<AudioCodec>* codecs) const {
165 codecs->clear();
166
167 for (std::vector<AudioCodec>::const_iterator it =
168 media_engine_->audio_codecs().begin();
169 it != media_engine_->audio_codecs().end(); ++it) {
170 codecs->push_back(*it);
171 }
172}
173
174void ChannelManager::GetSupportedAudioRtpHeaderExtensions(
175 RtpHeaderExtensions* ext) const {
176 *ext = media_engine_->audio_rtp_header_extensions();
177}
178
179void ChannelManager::GetSupportedVideoCodecs(
180 std::vector<VideoCodec>* codecs) const {
181 codecs->clear();
182
183 std::vector<VideoCodec>::const_iterator it;
184 for (it = media_engine_->video_codecs().begin();
185 it != media_engine_->video_codecs().end(); ++it) {
186 if (!enable_rtx_ && _stricmp(kRtxCodecName, it->name.c_str()) == 0) {
187 continue;
188 }
189 codecs->push_back(*it);
190 }
191}
192
193void ChannelManager::GetSupportedVideoRtpHeaderExtensions(
194 RtpHeaderExtensions* ext) const {
195 *ext = media_engine_->video_rtp_header_extensions();
196}
197
198void ChannelManager::GetSupportedDataCodecs(
199 std::vector<DataCodec>* codecs) const {
200 *codecs = data_media_engine_->data_codecs();
201}
202
203bool ChannelManager::Init() {
204 ASSERT(!initialized_);
205 if (initialized_) {
206 return false;
207 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000208 ASSERT(worker_thread_ != NULL);
henrika@webrtc.org62f6e752015-02-11 08:38:35 +0000209 if (!worker_thread_) {
210 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000211 }
henrika@webrtc.org62f6e752015-02-11 08:38:35 +0000212 if (worker_thread_ != rtc::Thread::Current()) {
213 // Do not allow invoking calls to other threads on the worker thread.
214 worker_thread_->Invoke<bool>(rtc::Bind(
215 &rtc::Thread::SetAllowBlockingCalls, worker_thread_, false));
216 }
217
218 initialized_ = worker_thread_->Invoke<bool>(Bind(
219 &ChannelManager::InitMediaEngine_w, this));
220 ASSERT(initialized_);
221 if (!initialized_) {
222 return false;
223 }
224
225 // Now that we're initialized, apply any stored preferences. A preferred
226 // device might have been unplugged. In this case, we fallback to the
227 // default device but keep the user preferences. The preferences are
228 // changed only when the Javascript FE changes them.
229 const std::string preferred_audio_in_device = audio_in_device_;
230 const std::string preferred_audio_out_device = audio_out_device_;
231 const std::string preferred_camera_device = camera_device_;
232 Device device;
233 if (!device_manager_->GetAudioInputDevice(audio_in_device_, &device)) {
234 LOG(LS_WARNING) << "The preferred microphone '" << audio_in_device_
235 << "' is unavailable. Fall back to the default.";
236 audio_in_device_ = DeviceManagerInterface::kDefaultDeviceName;
237 }
238 if (!device_manager_->GetAudioOutputDevice(audio_out_device_, &device)) {
239 LOG(LS_WARNING) << "The preferred speaker '" << audio_out_device_
240 << "' is unavailable. Fall back to the default.";
241 audio_out_device_ = DeviceManagerInterface::kDefaultDeviceName;
242 }
243 if (!device_manager_->GetVideoCaptureDevice(camera_device_, &device)) {
244 if (!camera_device_.empty()) {
245 LOG(LS_WARNING) << "The preferred camera '" << camera_device_
246 << "' is unavailable. Fall back to the default.";
247 }
248 camera_device_ = DeviceManagerInterface::kDefaultDeviceName;
249 }
250
251 if (!SetAudioOptions(audio_in_device_, audio_out_device_,
252 audio_options_, audio_delay_offset_)) {
253 LOG(LS_WARNING) << "Failed to SetAudioOptions with"
254 << " microphone: " << audio_in_device_
255 << " speaker: " << audio_out_device_
256 << " options: " << audio_options_.ToString()
257 << " delay: " << audio_delay_offset_;
258 }
259
260 // If audio_output_volume_ has been set via SetOutputVolume(), set the
261 // audio output volume of the engine.
262 if (kNotSetOutputVolume != audio_output_volume_ &&
263 !SetOutputVolume(audio_output_volume_)) {
264 LOG(LS_WARNING) << "Failed to SetOutputVolume to "
265 << audio_output_volume_;
266 }
267 if (!SetCaptureDevice(camera_device_) && !camera_device_.empty()) {
268 LOG(LS_WARNING) << "Failed to SetCaptureDevice with camera: "
269 << camera_device_;
270 }
271
272 // Restore the user preferences.
273 audio_in_device_ = preferred_audio_in_device;
274 audio_out_device_ = preferred_audio_out_device;
275 camera_device_ = preferred_camera_device;
276
277 // Now apply the default video codec that has been set earlier.
278 if (default_video_encoder_config_.max_codec.id != 0) {
279 SetDefaultVideoEncoderConfig(default_video_encoder_config_);
280 }
281
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000282 return initialized_;
283}
284
henrika@webrtc.org62f6e752015-02-11 08:38:35 +0000285bool ChannelManager::InitMediaEngine_w() {
286 ASSERT(worker_thread_ == rtc::Thread::Current());
287 return (media_engine_->Init(worker_thread_));
288}
289
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000290void ChannelManager::Terminate() {
291 ASSERT(initialized_);
292 if (!initialized_) {
293 return;
294 }
295 worker_thread_->Invoke<void>(Bind(&ChannelManager::Terminate_w, this));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000296 initialized_ = false;
297}
298
hbos@webrtc.org4aef5fe2015-02-25 10:09:05 +0000299void ChannelManager::DestructorDeletes_w() {
henrika@webrtc.org62f6e752015-02-11 08:38:35 +0000300 ASSERT(worker_thread_ == rtc::Thread::Current());
301 media_engine_.reset(NULL);
hbos@webrtc.org4aef5fe2015-02-25 10:09:05 +0000302 capture_manager_.reset(NULL);
henrika@webrtc.org62f6e752015-02-11 08:38:35 +0000303}
304
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000305void ChannelManager::Terminate_w() {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000306 ASSERT(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000307 // Need to destroy the voice/video channels
308 while (!video_channels_.empty()) {
309 DestroyVideoChannel_w(video_channels_.back());
310 }
311 while (!voice_channels_.empty()) {
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200312 DestroyVoiceChannel_w(voice_channels_.back());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000313 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000314 if (!SetCaptureDevice_w(NULL)) {
315 LOG(LS_WARNING) << "failed to delete video capturer";
316 }
henrika@webrtc.org62f6e752015-02-11 08:38:35 +0000317 media_engine_->Terminate();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000318}
319
320VoiceChannel* ChannelManager::CreateVoiceChannel(
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200321 webrtc::MediaControllerInterface* media_controller,
Jelena Marusicc28a8962015-05-29 15:05:44 +0200322 BaseSession* session,
323 const std::string& content_name,
324 bool rtcp,
325 const AudioOptions& options) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000326 return worker_thread_->Invoke<VoiceChannel*>(
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200327 Bind(&ChannelManager::CreateVoiceChannel_w,
328 this,
329 media_controller,
330 session,
331 content_name,
332 rtcp,
333 options));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000334}
335
336VoiceChannel* ChannelManager::CreateVoiceChannel_w(
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200337 webrtc::MediaControllerInterface* media_controller,
Jelena Marusicc28a8962015-05-29 15:05:44 +0200338 BaseSession* session,
339 const std::string& content_name,
340 bool rtcp,
341 const AudioOptions& options) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000342 ASSERT(initialized_);
Fredrik Solenberg4b60c732015-05-07 14:07:48 +0200343 ASSERT(worker_thread_ == rtc::Thread::Current());
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200344 ASSERT(nullptr != media_controller);
345 VoiceMediaChannel* media_channel =
346 media_engine_->CreateChannel(media_controller->call_w(), options);
Jelena Marusicc28a8962015-05-29 15:05:44 +0200347 if (!media_channel)
348 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000349
350 VoiceChannel* voice_channel = new VoiceChannel(
351 worker_thread_, media_engine_.get(), media_channel,
352 session, content_name, rtcp);
353 if (!voice_channel->Init()) {
354 delete voice_channel;
Jelena Marusicc28a8962015-05-29 15:05:44 +0200355 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000356 }
357 voice_channels_.push_back(voice_channel);
358 return voice_channel;
359}
360
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200361void ChannelManager::DestroyVoiceChannel(VoiceChannel* voice_channel) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000362 if (voice_channel) {
363 worker_thread_->Invoke<void>(
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200364 Bind(&ChannelManager::DestroyVoiceChannel_w, this, voice_channel));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000365 }
366}
367
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200368void ChannelManager::DestroyVoiceChannel_w(VoiceChannel* voice_channel) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000369 // Destroy voice channel.
370 ASSERT(initialized_);
Fredrik Solenberg4b60c732015-05-07 14:07:48 +0200371 ASSERT(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000372 VoiceChannels::iterator it = std::find(voice_channels_.begin(),
373 voice_channels_.end(), voice_channel);
374 ASSERT(it != voice_channels_.end());
375 if (it == voice_channels_.end())
376 return;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000377 voice_channels_.erase(it);
378 delete voice_channel;
379}
380
381VideoChannel* ChannelManager::CreateVideoChannel(
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200382 webrtc::MediaControllerInterface* media_controller,
buildbot@webrtc.org1ecbe452014-10-14 20:29:28 +0000383 BaseSession* session,
384 const std::string& content_name,
385 bool rtcp,
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200386 const VideoOptions& options) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000387 return worker_thread_->Invoke<VideoChannel*>(
buildbot@webrtc.org1ecbe452014-10-14 20:29:28 +0000388 Bind(&ChannelManager::CreateVideoChannel_w,
389 this,
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200390 media_controller,
buildbot@webrtc.org1ecbe452014-10-14 20:29:28 +0000391 session,
392 content_name,
393 rtcp,
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200394 options));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000395}
396
397VideoChannel* ChannelManager::CreateVideoChannel_w(
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200398 webrtc::MediaControllerInterface* media_controller,
buildbot@webrtc.org1ecbe452014-10-14 20:29:28 +0000399 BaseSession* session,
400 const std::string& content_name,
401 bool rtcp,
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200402 const VideoOptions& options) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000403 ASSERT(initialized_);
Fredrik Solenberg4b60c732015-05-07 14:07:48 +0200404 ASSERT(worker_thread_ == rtc::Thread::Current());
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200405 ASSERT(nullptr != media_controller);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000406 VideoMediaChannel* media_channel =
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200407 media_engine_->CreateVideoChannel(media_controller->call_w(), options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000408 if (media_channel == NULL)
409 return NULL;
410
411 VideoChannel* video_channel = new VideoChannel(
Fredrik Solenberg0c022642015-08-05 12:25:22 +0200412 worker_thread_, media_channel,
Fredrik Solenberg7fb711f2015-04-22 15:30:51 +0200413 session, content_name, rtcp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000414 if (!video_channel->Init()) {
415 delete video_channel;
416 return NULL;
417 }
418 video_channels_.push_back(video_channel);
419 return video_channel;
420}
421
422void ChannelManager::DestroyVideoChannel(VideoChannel* video_channel) {
423 if (video_channel) {
424 worker_thread_->Invoke<void>(
425 Bind(&ChannelManager::DestroyVideoChannel_w, this, video_channel));
426 }
427}
428
429void ChannelManager::DestroyVideoChannel_w(VideoChannel* video_channel) {
430 // Destroy video channel.
431 ASSERT(initialized_);
Fredrik Solenberg4b60c732015-05-07 14:07:48 +0200432 ASSERT(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000433 VideoChannels::iterator it = std::find(video_channels_.begin(),
434 video_channels_.end(), video_channel);
435 ASSERT(it != video_channels_.end());
436 if (it == video_channels_.end())
437 return;
438
439 video_channels_.erase(it);
440 delete video_channel;
441}
442
443DataChannel* ChannelManager::CreateDataChannel(
444 BaseSession* session, const std::string& content_name,
445 bool rtcp, DataChannelType channel_type) {
446 return worker_thread_->Invoke<DataChannel*>(
447 Bind(&ChannelManager::CreateDataChannel_w, this, session, content_name,
448 rtcp, channel_type));
449}
450
451DataChannel* ChannelManager::CreateDataChannel_w(
452 BaseSession* session, const std::string& content_name,
453 bool rtcp, DataChannelType data_channel_type) {
454 // This is ok to alloc from a thread other than the worker thread.
455 ASSERT(initialized_);
456 DataMediaChannel* media_channel = data_media_engine_->CreateChannel(
457 data_channel_type);
458 if (!media_channel) {
459 LOG(LS_WARNING) << "Failed to create data channel of type "
460 << data_channel_type;
461 return NULL;
462 }
463
464 DataChannel* data_channel = new DataChannel(
465 worker_thread_, media_channel,
466 session, content_name, rtcp);
467 if (!data_channel->Init()) {
468 LOG(LS_WARNING) << "Failed to init data channel.";
469 delete data_channel;
470 return NULL;
471 }
472 data_channels_.push_back(data_channel);
473 return data_channel;
474}
475
476void ChannelManager::DestroyDataChannel(DataChannel* data_channel) {
477 if (data_channel) {
478 worker_thread_->Invoke<void>(
479 Bind(&ChannelManager::DestroyDataChannel_w, this, data_channel));
480 }
481}
482
483void ChannelManager::DestroyDataChannel_w(DataChannel* data_channel) {
484 // Destroy data channel.
485 ASSERT(initialized_);
486 DataChannels::iterator it = std::find(data_channels_.begin(),
487 data_channels_.end(), data_channel);
488 ASSERT(it != data_channels_.end());
489 if (it == data_channels_.end())
490 return;
491
492 data_channels_.erase(it);
493 delete data_channel;
494}
495
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000496bool ChannelManager::GetAudioOptions(std::string* in_name,
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000497 std::string* out_name,
498 AudioOptions* options) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000499 if (in_name)
500 *in_name = audio_in_device_;
501 if (out_name)
502 *out_name = audio_out_device_;
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000503 if (options)
504 *options = audio_options_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000505 return true;
506}
507
508bool ChannelManager::SetAudioOptions(const std::string& in_name,
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000509 const std::string& out_name,
510 const AudioOptions& options) {
511 return SetAudioOptions(in_name, out_name, options, audio_delay_offset_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000512}
513
514bool ChannelManager::SetAudioOptions(const std::string& in_name,
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000515 const std::string& out_name,
516 const AudioOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000517 int delay_offset) {
518 // Get device ids from DeviceManager.
519 Device in_dev, out_dev;
520 if (!device_manager_->GetAudioInputDevice(in_name, &in_dev)) {
521 LOG(LS_WARNING) << "Failed to GetAudioInputDevice: " << in_name;
522 return false;
523 }
524 if (!device_manager_->GetAudioOutputDevice(out_name, &out_dev)) {
525 LOG(LS_WARNING) << "Failed to GetAudioOutputDevice: " << out_name;
526 return false;
527 }
528
529 // If we're initialized, pass the settings to the media engine.
530 bool ret = true;
531 if (initialized_) {
532 ret = worker_thread_->Invoke<bool>(
533 Bind(&ChannelManager::SetAudioOptions_w, this,
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000534 options, delay_offset, &in_dev, &out_dev));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000535 }
536
537 // If all worked well, save the values for use in GetAudioOptions.
538 if (ret) {
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000539 audio_options_ = options;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000540 audio_in_device_ = in_name;
541 audio_out_device_ = out_name;
542 audio_delay_offset_ = delay_offset;
543 }
544 return ret;
545}
546
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000547bool ChannelManager::SetAudioOptions_w(
548 const AudioOptions& options, int delay_offset,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000549 const Device* in_dev, const Device* out_dev) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000550 ASSERT(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000551 ASSERT(initialized_);
552
553 // Set audio options
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000554 bool ret = media_engine_->SetAudioOptions(options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000555
556 if (ret) {
557 ret = media_engine_->SetAudioDelayOffset(delay_offset);
558 }
559
560 // Set the audio devices
561 if (ret) {
562 ret = media_engine_->SetSoundDevices(in_dev, out_dev);
563 }
564
565 return ret;
566}
567
568bool ChannelManager::GetOutputVolume(int* level) {
569 if (!initialized_) {
570 return false;
571 }
572 return worker_thread_->Invoke<bool>(
573 Bind(&MediaEngineInterface::GetOutputVolume, media_engine_.get(), level));
574}
575
576bool ChannelManager::SetOutputVolume(int level) {
577 bool ret = level >= 0 && level <= 255;
578 if (initialized_) {
579 ret &= worker_thread_->Invoke<bool>(
580 Bind(&MediaEngineInterface::SetOutputVolume,
581 media_engine_.get(), level));
582 }
583
584 if (ret) {
585 audio_output_volume_ = level;
586 }
587
588 return ret;
589}
590
591bool ChannelManager::IsSameCapturer(const std::string& capturer_name,
592 VideoCapturer* capturer) {
593 if (capturer == NULL) {
594 return false;
595 }
596 Device device;
597 if (!device_manager_->GetVideoCaptureDevice(capturer_name, &device)) {
598 return false;
599 }
600 return capturer->GetId() == device.id;
601}
602
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000603bool ChannelManager::GetVideoCaptureDevice(Device* device) {
604 std::string device_name;
605 if (!GetCaptureDevice(&device_name)) {
606 return false;
607 }
608 return device_manager_->GetVideoCaptureDevice(device_name, device);
609}
610
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000611bool ChannelManager::GetCaptureDevice(std::string* cam_name) {
612 if (camera_device_.empty()) {
613 // Initialize camera_device_ with default.
614 Device device;
615 if (!device_manager_->GetVideoCaptureDevice(
616 DeviceManagerInterface::kDefaultDeviceName, &device)) {
617 LOG(LS_WARNING) << "Device manager can't find default camera: " <<
618 DeviceManagerInterface::kDefaultDeviceName;
619 return false;
620 }
621 camera_device_ = device.name;
622 }
623 *cam_name = camera_device_;
624 return true;
625}
626
627bool ChannelManager::SetCaptureDevice(const std::string& cam_name) {
628 Device device;
629 bool ret = true;
630 if (!device_manager_->GetVideoCaptureDevice(cam_name, &device)) {
631 if (!cam_name.empty()) {
632 LOG(LS_WARNING) << "Device manager can't find camera: " << cam_name;
633 }
634 ret = false;
635 }
636
637 // If we're running, tell the media engine about it.
638 if (initialized_ && ret) {
639 ret = worker_thread_->Invoke<bool>(
640 Bind(&ChannelManager::SetCaptureDevice_w, this, &device));
641 }
642
643 // If everything worked, retain the name of the selected camera.
644 if (ret) {
645 camera_device_ = device.name;
646 } else if (camera_device_.empty()) {
647 // When video option setting fails, we still want camera_device_ to be in a
648 // good state, so we initialize it with default if it's empty.
649 Device default_device;
650 if (!device_manager_->GetVideoCaptureDevice(
651 DeviceManagerInterface::kDefaultDeviceName, &default_device)) {
652 LOG(LS_WARNING) << "Device manager can't find default camera: " <<
653 DeviceManagerInterface::kDefaultDeviceName;
654 }
655 camera_device_ = default_device.name;
656 }
657
658 return ret;
659}
660
661VideoCapturer* ChannelManager::CreateVideoCapturer() {
662 Device device;
663 if (!device_manager_->GetVideoCaptureDevice(camera_device_, &device)) {
664 if (!camera_device_.empty()) {
665 LOG(LS_WARNING) << "Device manager can't find camera: " << camera_device_;
666 }
667 return NULL;
668 }
sergeyu@chromium.orga59696b2013-09-13 23:48:58 +0000669 VideoCapturer* capturer = device_manager_->CreateVideoCapturer(device);
670 if (capturer && default_video_encoder_config_.max_codec.id != 0) {
671 // For now, use the aspect ratio of the default_video_encoder_config_,
672 // which may be different than the native aspect ratio of the start
673 // format the camera may use.
674 capturer->UpdateAspectRatio(
675 default_video_encoder_config_.max_codec.width,
676 default_video_encoder_config_.max_codec.height);
677 }
678 return capturer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000679}
680
buildbot@webrtc.org65b98d12014-08-07 22:09:08 +0000681VideoCapturer* ChannelManager::CreateScreenCapturer(
682 const ScreencastId& screenid) {
683 return device_manager_->CreateScreenCapturer(screenid);
684}
685
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000686bool ChannelManager::SetCaptureDevice_w(const Device* cam_device) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000687 ASSERT(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000688 ASSERT(initialized_);
689
690 if (!cam_device) {
691 video_device_name_.clear();
692 return true;
693 }
694 video_device_name_ = cam_device->name;
695 return true;
696}
697
698bool ChannelManager::SetDefaultVideoEncoderConfig(const VideoEncoderConfig& c) {
buildbot@webrtc.org992febb2014-09-05 16:39:08 +0000699 bool ret = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000700 if (initialized_) {
buildbot@webrtc.org992febb2014-09-05 16:39:08 +0000701 ret = worker_thread_->Invoke<bool>(
702 Bind(&MediaEngineInterface::SetDefaultVideoEncoderConfig,
703 media_engine_.get(), c));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000704 }
buildbot@webrtc.org992febb2014-09-05 16:39:08 +0000705 if (ret) {
706 default_video_encoder_config_ = c;
707 }
708 return ret;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000709}
710
711bool ChannelManager::SetLocalMonitor(bool enable) {
712 bool ret = initialized_ && worker_thread_->Invoke<bool>(
713 Bind(&MediaEngineInterface::SetLocalMonitor,
714 media_engine_.get(), enable));
715 if (ret) {
716 monitoring_ = enable;
717 }
718 return ret;
719}
720
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000721void ChannelManager::SetVoiceLogging(int level, const char* filter) {
722 if (initialized_) {
723 worker_thread_->Invoke<void>(
724 Bind(&MediaEngineInterface::SetVoiceLogging,
725 media_engine_.get(), level, filter));
726 } else {
727 media_engine_->SetVoiceLogging(level, filter);
728 }
729}
730
731void ChannelManager::SetVideoLogging(int level, const char* filter) {
732 if (initialized_) {
733 worker_thread_->Invoke<void>(
734 Bind(&MediaEngineInterface::SetVideoLogging,
735 media_engine_.get(), level, filter));
736 } else {
737 media_engine_->SetVideoLogging(level, filter);
738 }
739}
740
hbos@webrtc.org1e642632015-02-25 09:49:41 +0000741std::vector<cricket::VideoFormat> ChannelManager::GetSupportedFormats(
742 VideoCapturer* capturer) const {
743 ASSERT(capturer != NULL);
744 std::vector<VideoFormat> formats;
745 worker_thread_->Invoke<void>(rtc::Bind(&ChannelManager::GetSupportedFormats_w,
746 this, capturer, &formats));
747 return formats;
748}
749
750void ChannelManager::GetSupportedFormats_w(
751 VideoCapturer* capturer,
752 std::vector<cricket::VideoFormat>* out_formats) const {
753 const std::vector<VideoFormat>* formats = capturer->GetSupportedFormats();
754 if (formats != NULL)
755 *out_formats = *formats;
756}
757
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000758bool ChannelManager::RegisterVoiceProcessor(
759 uint32 ssrc,
760 VoiceProcessor* processor,
761 MediaProcessorDirection direction) {
762 return initialized_ && worker_thread_->Invoke<bool>(
763 Bind(&MediaEngineInterface::RegisterVoiceProcessor, media_engine_.get(),
764 ssrc, processor, direction));
765}
766
767bool ChannelManager::UnregisterVoiceProcessor(
768 uint32 ssrc,
769 VoiceProcessor* processor,
770 MediaProcessorDirection direction) {
771 return initialized_ && worker_thread_->Invoke<bool>(
772 Bind(&MediaEngineInterface::UnregisterVoiceProcessor,
773 media_engine_.get(), ssrc, processor, direction));
774}
775
776// The following are done in the new "CaptureManager" style that
777// all local video capturers, processors, and managers should move
778// to.
779// TODO(pthatcher): Add more of the CaptureManager interface.
780bool ChannelManager::StartVideoCapture(
781 VideoCapturer* capturer, const VideoFormat& video_format) {
782 return initialized_ && worker_thread_->Invoke<bool>(
783 Bind(&CaptureManager::StartVideoCapture,
784 capture_manager_.get(), capturer, video_format));
785}
786
787bool ChannelManager::MuteToBlackThenPause(
788 VideoCapturer* video_capturer, bool muted) {
789 if (!initialized_) {
790 return false;
791 }
792 worker_thread_->Invoke<void>(
793 Bind(&VideoCapturer::MuteToBlackThenPause, video_capturer, muted));
794 return true;
795}
796
797bool ChannelManager::StopVideoCapture(
798 VideoCapturer* capturer, const VideoFormat& video_format) {
799 return initialized_ && worker_thread_->Invoke<bool>(
800 Bind(&CaptureManager::StopVideoCapture,
801 capture_manager_.get(), capturer, video_format));
802}
803
804bool ChannelManager::RestartVideoCapture(
805 VideoCapturer* video_capturer,
806 const VideoFormat& previous_format,
807 const VideoFormat& desired_format,
808 CaptureManager::RestartOptions options) {
809 return initialized_ && worker_thread_->Invoke<bool>(
810 Bind(&CaptureManager::RestartVideoCapture, capture_manager_.get(),
811 video_capturer, previous_format, desired_format, options));
812}
813
814bool ChannelManager::AddVideoRenderer(
815 VideoCapturer* capturer, VideoRenderer* renderer) {
816 return initialized_ && worker_thread_->Invoke<bool>(
817 Bind(&CaptureManager::AddVideoRenderer,
818 capture_manager_.get(), capturer, renderer));
819}
820
821bool ChannelManager::RemoveVideoRenderer(
822 VideoCapturer* capturer, VideoRenderer* renderer) {
823 return initialized_ && worker_thread_->Invoke<bool>(
824 Bind(&CaptureManager::RemoveVideoRenderer,
825 capture_manager_.get(), capturer, renderer));
826}
827
828bool ChannelManager::IsScreencastRunning() const {
829 return initialized_ && worker_thread_->Invoke<bool>(
830 Bind(&ChannelManager::IsScreencastRunning_w, this));
831}
832
833bool ChannelManager::IsScreencastRunning_w() const {
834 VideoChannels::const_iterator it = video_channels_.begin();
835 for ( ; it != video_channels_.end(); ++it) {
836 if ((*it) && (*it)->IsScreencasting()) {
837 return true;
838 }
839 }
840 return false;
841}
842
843void ChannelManager::OnVideoCaptureStateChange(VideoCapturer* capturer,
844 CaptureState result) {
845 // TODO(whyuan): Check capturer and signal failure only for camera video, not
846 // screencast.
847 capturing_ = result == CS_RUNNING;
848 main_thread_->Post(this, MSG_VIDEOCAPTURESTATE,
849 new CaptureStateParams(capturer, result));
850}
851
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000852void ChannelManager::OnMessage(rtc::Message* message) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000853 switch (message->message_id) {
854 case MSG_VIDEOCAPTURESTATE: {
855 CaptureStateParams* data =
856 static_cast<CaptureStateParams*>(message->pdata);
857 SignalVideoCaptureStateChange(data->capturer, data->state);
858 delete data;
859 break;
860 }
861 }
862}
863
864
865static void GetDeviceNames(const std::vector<Device>& devs,
866 std::vector<std::string>* names) {
867 names->clear();
868 for (size_t i = 0; i < devs.size(); ++i) {
869 names->push_back(devs[i].name);
870 }
871}
872
873bool ChannelManager::GetAudioInputDevices(std::vector<std::string>* names) {
874 names->clear();
875 std::vector<Device> devs;
876 bool ret = device_manager_->GetAudioInputDevices(&devs);
877 if (ret)
878 GetDeviceNames(devs, names);
879
880 return ret;
881}
882
883bool ChannelManager::GetAudioOutputDevices(std::vector<std::string>* names) {
884 names->clear();
885 std::vector<Device> devs;
886 bool ret = device_manager_->GetAudioOutputDevices(&devs);
887 if (ret)
888 GetDeviceNames(devs, names);
889
890 return ret;
891}
892
893bool ChannelManager::GetVideoCaptureDevices(std::vector<std::string>* names) {
894 names->clear();
895 std::vector<Device> devs;
896 bool ret = device_manager_->GetVideoCaptureDevices(&devs);
897 if (ret)
898 GetDeviceNames(devs, names);
899
900 return ret;
901}
902
903void ChannelManager::SetVideoCaptureDeviceMaxFormat(
904 const std::string& usb_id,
905 const VideoFormat& max_format) {
906 device_manager_->SetVideoCaptureDeviceMaxFormat(usb_id, max_format);
907}
908
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000909bool ChannelManager::StartAecDump(rtc::PlatformFile file) {
wu@webrtc.orga9890802013-12-13 00:21:03 +0000910 return worker_thread_->Invoke<bool>(
911 Bind(&MediaEngineInterface::StartAecDump, media_engine_.get(), file));
912}
913
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000914} // namespace cricket