blob: b507d4be1786047296fe239d5543c21be9183934 [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
henrike@webrtc.org28e20752013-07-10 00:45:36 +000036#include "talk/media/base/capturemanager.h"
37#include "talk/media/base/hybriddataengine.h"
38#include "talk/media/base/rtpdataengine.h"
39#include "talk/media/base/videocapturer.h"
henrike@webrtc.org723d6832013-07-12 16:04:50 +000040#include "talk/media/devices/devicemanager.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000041#ifdef HAVE_SCTP
42#include "talk/media/sctp/sctpdataengine.h"
43#endif
44#include "talk/session/media/soundclip.h"
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
79#if !defined(DISABLE_MEDIA_ENGINE_FACTORY)
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000080ChannelManager::ChannelManager(rtc::Thread* worker_thread) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000081 Construct(MediaEngineFactory::Create(),
82 ConstructDataEngine(),
83 cricket::DeviceManagerFactory::Create(),
84 new CaptureManager(),
85 worker_thread);
86}
87#endif
88
89ChannelManager::ChannelManager(MediaEngineInterface* me,
90 DataEngineInterface* dme,
91 DeviceManagerInterface* dm,
92 CaptureManager* cm,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000093 rtc::Thread* worker_thread) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000094 Construct(me, dme, dm, cm, worker_thread);
95}
96
97ChannelManager::ChannelManager(MediaEngineInterface* me,
98 DeviceManagerInterface* dm,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000099 rtc::Thread* worker_thread) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000100 Construct(me,
101 ConstructDataEngine(),
102 dm,
103 new CaptureManager(),
104 worker_thread);
105}
106
107void ChannelManager::Construct(MediaEngineInterface* me,
108 DataEngineInterface* dme,
109 DeviceManagerInterface* dm,
110 CaptureManager* cm,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000111 rtc::Thread* worker_thread) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000112 media_engine_.reset(me);
113 data_media_engine_.reset(dme);
114 device_manager_.reset(dm);
115 capture_manager_.reset(cm);
116 initialized_ = false;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000117 main_thread_ = rtc::Thread::Current();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000118 worker_thread_ = worker_thread;
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000119 // Get the default audio options from the media engine.
120 audio_options_ = media_engine_->GetAudioOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000121 audio_in_device_ = DeviceManagerInterface::kDefaultDeviceName;
122 audio_out_device_ = DeviceManagerInterface::kDefaultDeviceName;
henrike@webrtc.org0481f152014-08-19 14:56:59 +0000123 audio_delay_offset_ = kDefaultAudioDelayOffset;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000124 audio_output_volume_ = kNotSetOutputVolume;
125 local_renderer_ = NULL;
126 capturing_ = false;
127 monitoring_ = false;
128 enable_rtx_ = false;
129
130 // Init the device manager immediately, and set up our default video device.
131 SignalDevicesChange.repeat(device_manager_->SignalDevicesChange);
132 device_manager_->Init();
133
134 // Camera is started asynchronously, request callbacks when startup
135 // completes to be able to forward them to the rendering manager.
136 media_engine_->SignalVideoCaptureStateChange().connect(
137 this, &ChannelManager::OnVideoCaptureStateChange);
138 capture_manager_->SignalCapturerStateChange.connect(
139 this, &ChannelManager::OnVideoCaptureStateChange);
140}
141
142ChannelManager::~ChannelManager() {
wu@webrtc.org9dba5252013-08-05 20:36:57 +0000143 if (initialized_) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000144 Terminate();
wu@webrtc.org9dba5252013-08-05 20:36:57 +0000145 // If srtp is initialized (done by the Channel) then we must call
146 // srtp_shutdown to free all crypto kernel lists. But we need to make sure
147 // shutdown always called at the end, after channels are destroyed.
148 // ChannelManager d'tor is always called last, it's safe place to call
149 // shutdown.
150 ShutdownSrtp();
151 }
henrika@webrtc.org62f6e752015-02-11 08:38:35 +0000152 // Always delete the media engine on the worker thread to match how it was
153 // created.
154 worker_thread_->Invoke<void>(Bind(
155 &ChannelManager::DeleteMediaEngine_w, this));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000156}
157
158bool ChannelManager::SetVideoRtxEnabled(bool enable) {
159 // To be safe, this call is only allowed before initialization. Apps like
160 // Flute only have a singleton ChannelManager and we don't want this flag to
161 // be toggled between calls or when there's concurrent calls. We expect apps
162 // to enable this at startup and retain that setting for the lifetime of the
163 // app.
164 if (!initialized_) {
165 enable_rtx_ = enable;
166 return true;
167 } else {
168 LOG(LS_WARNING) << "Cannot toggle rtx after initialization!";
169 return false;
170 }
171}
172
173int ChannelManager::GetCapabilities() {
174 return media_engine_->GetCapabilities() & device_manager_->GetCapabilities();
175}
176
177void ChannelManager::GetSupportedAudioCodecs(
178 std::vector<AudioCodec>* codecs) const {
179 codecs->clear();
180
181 for (std::vector<AudioCodec>::const_iterator it =
182 media_engine_->audio_codecs().begin();
183 it != media_engine_->audio_codecs().end(); ++it) {
184 codecs->push_back(*it);
185 }
186}
187
188void ChannelManager::GetSupportedAudioRtpHeaderExtensions(
189 RtpHeaderExtensions* ext) const {
190 *ext = media_engine_->audio_rtp_header_extensions();
191}
192
193void ChannelManager::GetSupportedVideoCodecs(
194 std::vector<VideoCodec>* codecs) const {
195 codecs->clear();
196
197 std::vector<VideoCodec>::const_iterator it;
198 for (it = media_engine_->video_codecs().begin();
199 it != media_engine_->video_codecs().end(); ++it) {
200 if (!enable_rtx_ && _stricmp(kRtxCodecName, it->name.c_str()) == 0) {
201 continue;
202 }
203 codecs->push_back(*it);
204 }
205}
206
207void ChannelManager::GetSupportedVideoRtpHeaderExtensions(
208 RtpHeaderExtensions* ext) const {
209 *ext = media_engine_->video_rtp_header_extensions();
210}
211
212void ChannelManager::GetSupportedDataCodecs(
213 std::vector<DataCodec>* codecs) const {
214 *codecs = data_media_engine_->data_codecs();
215}
216
217bool ChannelManager::Init() {
218 ASSERT(!initialized_);
219 if (initialized_) {
220 return false;
221 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000222 ASSERT(worker_thread_ != NULL);
henrika@webrtc.org62f6e752015-02-11 08:38:35 +0000223 if (!worker_thread_) {
224 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000225 }
henrika@webrtc.org62f6e752015-02-11 08:38:35 +0000226 if (worker_thread_ != rtc::Thread::Current()) {
227 // Do not allow invoking calls to other threads on the worker thread.
228 worker_thread_->Invoke<bool>(rtc::Bind(
229 &rtc::Thread::SetAllowBlockingCalls, worker_thread_, false));
230 }
231
232 initialized_ = worker_thread_->Invoke<bool>(Bind(
233 &ChannelManager::InitMediaEngine_w, this));
234 ASSERT(initialized_);
235 if (!initialized_) {
236 return false;
237 }
238
239 // Now that we're initialized, apply any stored preferences. A preferred
240 // device might have been unplugged. In this case, we fallback to the
241 // default device but keep the user preferences. The preferences are
242 // changed only when the Javascript FE changes them.
243 const std::string preferred_audio_in_device = audio_in_device_;
244 const std::string preferred_audio_out_device = audio_out_device_;
245 const std::string preferred_camera_device = camera_device_;
246 Device device;
247 if (!device_manager_->GetAudioInputDevice(audio_in_device_, &device)) {
248 LOG(LS_WARNING) << "The preferred microphone '" << audio_in_device_
249 << "' is unavailable. Fall back to the default.";
250 audio_in_device_ = DeviceManagerInterface::kDefaultDeviceName;
251 }
252 if (!device_manager_->GetAudioOutputDevice(audio_out_device_, &device)) {
253 LOG(LS_WARNING) << "The preferred speaker '" << audio_out_device_
254 << "' is unavailable. Fall back to the default.";
255 audio_out_device_ = DeviceManagerInterface::kDefaultDeviceName;
256 }
257 if (!device_manager_->GetVideoCaptureDevice(camera_device_, &device)) {
258 if (!camera_device_.empty()) {
259 LOG(LS_WARNING) << "The preferred camera '" << camera_device_
260 << "' is unavailable. Fall back to the default.";
261 }
262 camera_device_ = DeviceManagerInterface::kDefaultDeviceName;
263 }
264
265 if (!SetAudioOptions(audio_in_device_, audio_out_device_,
266 audio_options_, audio_delay_offset_)) {
267 LOG(LS_WARNING) << "Failed to SetAudioOptions with"
268 << " microphone: " << audio_in_device_
269 << " speaker: " << audio_out_device_
270 << " options: " << audio_options_.ToString()
271 << " delay: " << audio_delay_offset_;
272 }
273
274 // If audio_output_volume_ has been set via SetOutputVolume(), set the
275 // audio output volume of the engine.
276 if (kNotSetOutputVolume != audio_output_volume_ &&
277 !SetOutputVolume(audio_output_volume_)) {
278 LOG(LS_WARNING) << "Failed to SetOutputVolume to "
279 << audio_output_volume_;
280 }
281 if (!SetCaptureDevice(camera_device_) && !camera_device_.empty()) {
282 LOG(LS_WARNING) << "Failed to SetCaptureDevice with camera: "
283 << camera_device_;
284 }
285
286 // Restore the user preferences.
287 audio_in_device_ = preferred_audio_in_device;
288 audio_out_device_ = preferred_audio_out_device;
289 camera_device_ = preferred_camera_device;
290
291 // Now apply the default video codec that has been set earlier.
292 if (default_video_encoder_config_.max_codec.id != 0) {
293 SetDefaultVideoEncoderConfig(default_video_encoder_config_);
294 }
295
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000296 return initialized_;
297}
298
henrika@webrtc.org62f6e752015-02-11 08:38:35 +0000299bool ChannelManager::InitMediaEngine_w() {
300 ASSERT(worker_thread_ == rtc::Thread::Current());
301 return (media_engine_->Init(worker_thread_));
302}
303
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000304void ChannelManager::Terminate() {
305 ASSERT(initialized_);
306 if (!initialized_) {
307 return;
308 }
309 worker_thread_->Invoke<void>(Bind(&ChannelManager::Terminate_w, this));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000310 initialized_ = false;
311}
312
henrika@webrtc.org62f6e752015-02-11 08:38:35 +0000313void ChannelManager::DeleteMediaEngine_w() {
314 ASSERT(worker_thread_ == rtc::Thread::Current());
315 media_engine_.reset(NULL);
316}
317
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000318void ChannelManager::Terminate_w() {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000319 ASSERT(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000320 // Need to destroy the voice/video channels
321 while (!video_channels_.empty()) {
322 DestroyVideoChannel_w(video_channels_.back());
323 }
324 while (!voice_channels_.empty()) {
325 DestroyVoiceChannel_w(voice_channels_.back());
326 }
327 while (!soundclips_.empty()) {
328 DestroySoundclip_w(soundclips_.back());
329 }
330 if (!SetCaptureDevice_w(NULL)) {
331 LOG(LS_WARNING) << "failed to delete video capturer";
332 }
henrika@webrtc.org62f6e752015-02-11 08:38:35 +0000333 media_engine_->Terminate();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000334}
335
336VoiceChannel* ChannelManager::CreateVoiceChannel(
337 BaseSession* session, const std::string& content_name, bool rtcp) {
338 return worker_thread_->Invoke<VoiceChannel*>(
339 Bind(&ChannelManager::CreateVoiceChannel_w, this,
340 session, content_name, rtcp));
341}
342
343VoiceChannel* ChannelManager::CreateVoiceChannel_w(
344 BaseSession* session, const std::string& content_name, bool rtcp) {
345 // This is ok to alloc from a thread other than the worker thread
346 ASSERT(initialized_);
347 VoiceMediaChannel* media_channel = media_engine_->CreateChannel();
348 if (media_channel == NULL)
349 return NULL;
350
351 VoiceChannel* voice_channel = new VoiceChannel(
352 worker_thread_, media_engine_.get(), media_channel,
353 session, content_name, rtcp);
354 if (!voice_channel->Init()) {
355 delete voice_channel;
356 return NULL;
357 }
358 voice_channels_.push_back(voice_channel);
359 return voice_channel;
360}
361
362void ChannelManager::DestroyVoiceChannel(VoiceChannel* voice_channel) {
363 if (voice_channel) {
364 worker_thread_->Invoke<void>(
365 Bind(&ChannelManager::DestroyVoiceChannel_w, this, voice_channel));
366 }
367}
368
369void ChannelManager::DestroyVoiceChannel_w(VoiceChannel* voice_channel) {
370 // Destroy voice channel.
371 ASSERT(initialized_);
372 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;
377
378 voice_channels_.erase(it);
379 delete voice_channel;
380}
381
382VideoChannel* ChannelManager::CreateVideoChannel(
buildbot@webrtc.org1ecbe452014-10-14 20:29:28 +0000383 BaseSession* session,
384 const std::string& content_name,
385 bool rtcp,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000386 VoiceChannel* voice_channel) {
387 return worker_thread_->Invoke<VideoChannel*>(
buildbot@webrtc.org1ecbe452014-10-14 20:29:28 +0000388 Bind(&ChannelManager::CreateVideoChannel_w,
389 this,
390 session,
391 content_name,
392 rtcp,
393 VideoOptions(),
394 voice_channel));
395}
396
397VideoChannel* ChannelManager::CreateVideoChannel(
398 BaseSession* session,
399 const std::string& content_name,
400 bool rtcp,
401 const VideoOptions& options,
402 VoiceChannel* voice_channel) {
403 return worker_thread_->Invoke<VideoChannel*>(
404 Bind(&ChannelManager::CreateVideoChannel_w,
405 this,
406 session,
407 content_name,
408 rtcp,
409 options,
410 voice_channel));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000411}
412
413VideoChannel* ChannelManager::CreateVideoChannel_w(
buildbot@webrtc.org1ecbe452014-10-14 20:29:28 +0000414 BaseSession* session,
415 const std::string& content_name,
416 bool rtcp,
417 const VideoOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000418 VoiceChannel* voice_channel) {
419 // This is ok to alloc from a thread other than the worker thread
420 ASSERT(initialized_);
421 VideoMediaChannel* media_channel =
422 // voice_channel can be NULL in case of NullVoiceEngine.
buildbot@webrtc.org1ecbe452014-10-14 20:29:28 +0000423 media_engine_->CreateVideoChannel(
424 options, voice_channel ? voice_channel->media_channel() : NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000425 if (media_channel == NULL)
426 return NULL;
427
428 VideoChannel* video_channel = new VideoChannel(
429 worker_thread_, media_engine_.get(), media_channel,
430 session, content_name, rtcp, voice_channel);
431 if (!video_channel->Init()) {
432 delete video_channel;
433 return NULL;
434 }
435 video_channels_.push_back(video_channel);
436 return video_channel;
437}
438
439void ChannelManager::DestroyVideoChannel(VideoChannel* video_channel) {
440 if (video_channel) {
441 worker_thread_->Invoke<void>(
442 Bind(&ChannelManager::DestroyVideoChannel_w, this, video_channel));
443 }
444}
445
446void ChannelManager::DestroyVideoChannel_w(VideoChannel* video_channel) {
447 // Destroy video channel.
448 ASSERT(initialized_);
449 VideoChannels::iterator it = std::find(video_channels_.begin(),
450 video_channels_.end(), video_channel);
451 ASSERT(it != video_channels_.end());
452 if (it == video_channels_.end())
453 return;
454
455 video_channels_.erase(it);
456 delete video_channel;
457}
458
459DataChannel* ChannelManager::CreateDataChannel(
460 BaseSession* session, const std::string& content_name,
461 bool rtcp, DataChannelType channel_type) {
462 return worker_thread_->Invoke<DataChannel*>(
463 Bind(&ChannelManager::CreateDataChannel_w, this, session, content_name,
464 rtcp, channel_type));
465}
466
467DataChannel* ChannelManager::CreateDataChannel_w(
468 BaseSession* session, const std::string& content_name,
469 bool rtcp, DataChannelType data_channel_type) {
470 // This is ok to alloc from a thread other than the worker thread.
471 ASSERT(initialized_);
472 DataMediaChannel* media_channel = data_media_engine_->CreateChannel(
473 data_channel_type);
474 if (!media_channel) {
475 LOG(LS_WARNING) << "Failed to create data channel of type "
476 << data_channel_type;
477 return NULL;
478 }
479
480 DataChannel* data_channel = new DataChannel(
481 worker_thread_, media_channel,
482 session, content_name, rtcp);
483 if (!data_channel->Init()) {
484 LOG(LS_WARNING) << "Failed to init data channel.";
485 delete data_channel;
486 return NULL;
487 }
488 data_channels_.push_back(data_channel);
489 return data_channel;
490}
491
492void ChannelManager::DestroyDataChannel(DataChannel* data_channel) {
493 if (data_channel) {
494 worker_thread_->Invoke<void>(
495 Bind(&ChannelManager::DestroyDataChannel_w, this, data_channel));
496 }
497}
498
499void ChannelManager::DestroyDataChannel_w(DataChannel* data_channel) {
500 // Destroy data channel.
501 ASSERT(initialized_);
502 DataChannels::iterator it = std::find(data_channels_.begin(),
503 data_channels_.end(), data_channel);
504 ASSERT(it != data_channels_.end());
505 if (it == data_channels_.end())
506 return;
507
508 data_channels_.erase(it);
509 delete data_channel;
510}
511
512Soundclip* ChannelManager::CreateSoundclip() {
513 return worker_thread_->Invoke<Soundclip*>(
514 Bind(&ChannelManager::CreateSoundclip_w, this));
515}
516
517Soundclip* ChannelManager::CreateSoundclip_w() {
518 ASSERT(initialized_);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000519 ASSERT(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000520
521 SoundclipMedia* soundclip_media = media_engine_->CreateSoundclip();
522 if (!soundclip_media) {
523 return NULL;
524 }
525
526 Soundclip* soundclip = new Soundclip(worker_thread_, soundclip_media);
527 soundclips_.push_back(soundclip);
528 return soundclip;
529}
530
531void ChannelManager::DestroySoundclip(Soundclip* soundclip) {
532 if (soundclip) {
533 worker_thread_->Invoke<void>(
534 Bind(&ChannelManager::DestroySoundclip_w, this, soundclip));
535 }
536}
537
538void ChannelManager::DestroySoundclip_w(Soundclip* soundclip) {
539 // Destroy soundclip.
540 ASSERT(initialized_);
541 Soundclips::iterator it = std::find(soundclips_.begin(),
542 soundclips_.end(), soundclip);
543 ASSERT(it != soundclips_.end());
544 if (it == soundclips_.end())
545 return;
546
547 soundclips_.erase(it);
548 delete soundclip;
549}
550
551bool ChannelManager::GetAudioOptions(std::string* in_name,
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000552 std::string* out_name,
553 AudioOptions* options) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000554 if (in_name)
555 *in_name = audio_in_device_;
556 if (out_name)
557 *out_name = audio_out_device_;
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000558 if (options)
559 *options = audio_options_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000560 return true;
561}
562
563bool ChannelManager::SetAudioOptions(const std::string& in_name,
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000564 const std::string& out_name,
565 const AudioOptions& options) {
566 return SetAudioOptions(in_name, out_name, options, audio_delay_offset_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000567}
568
569bool ChannelManager::SetAudioOptions(const std::string& in_name,
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000570 const std::string& out_name,
571 const AudioOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000572 int delay_offset) {
573 // Get device ids from DeviceManager.
574 Device in_dev, out_dev;
575 if (!device_manager_->GetAudioInputDevice(in_name, &in_dev)) {
576 LOG(LS_WARNING) << "Failed to GetAudioInputDevice: " << in_name;
577 return false;
578 }
579 if (!device_manager_->GetAudioOutputDevice(out_name, &out_dev)) {
580 LOG(LS_WARNING) << "Failed to GetAudioOutputDevice: " << out_name;
581 return false;
582 }
583
584 // If we're initialized, pass the settings to the media engine.
585 bool ret = true;
586 if (initialized_) {
587 ret = worker_thread_->Invoke<bool>(
588 Bind(&ChannelManager::SetAudioOptions_w, this,
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000589 options, delay_offset, &in_dev, &out_dev));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000590 }
591
592 // If all worked well, save the values for use in GetAudioOptions.
593 if (ret) {
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000594 audio_options_ = options;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000595 audio_in_device_ = in_name;
596 audio_out_device_ = out_name;
597 audio_delay_offset_ = delay_offset;
598 }
599 return ret;
600}
601
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000602bool ChannelManager::SetAudioOptions_w(
603 const AudioOptions& options, int delay_offset,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000604 const Device* in_dev, const Device* out_dev) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000605 ASSERT(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000606 ASSERT(initialized_);
607
608 // Set audio options
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000609 bool ret = media_engine_->SetAudioOptions(options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000610
611 if (ret) {
612 ret = media_engine_->SetAudioDelayOffset(delay_offset);
613 }
614
615 // Set the audio devices
616 if (ret) {
617 ret = media_engine_->SetSoundDevices(in_dev, out_dev);
618 }
619
620 return ret;
621}
622
buildbot@webrtc.org88d9fa62014-06-16 14:11:32 +0000623// Sets Engine-specific audio options according to enabled experiments.
624bool ChannelManager::SetEngineAudioOptions(const AudioOptions& options) {
625 // If we're initialized, pass the settings to the media engine.
626 bool ret = false;
627 if (initialized_) {
628 ret = worker_thread_->Invoke<bool>(
629 Bind(&ChannelManager::SetEngineAudioOptions_w, this, options));
630 }
631
632 // If all worked well, save the audio options.
633 if (ret) {
634 audio_options_ = options;
635 }
636 return ret;
637}
638
639bool ChannelManager::SetEngineAudioOptions_w(const AudioOptions& options) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000640 ASSERT(worker_thread_ == rtc::Thread::Current());
buildbot@webrtc.org88d9fa62014-06-16 14:11:32 +0000641 ASSERT(initialized_);
642
643 return media_engine_->SetAudioOptions(options);
644}
645
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000646bool ChannelManager::GetOutputVolume(int* level) {
647 if (!initialized_) {
648 return false;
649 }
650 return worker_thread_->Invoke<bool>(
651 Bind(&MediaEngineInterface::GetOutputVolume, media_engine_.get(), level));
652}
653
654bool ChannelManager::SetOutputVolume(int level) {
655 bool ret = level >= 0 && level <= 255;
656 if (initialized_) {
657 ret &= worker_thread_->Invoke<bool>(
658 Bind(&MediaEngineInterface::SetOutputVolume,
659 media_engine_.get(), level));
660 }
661
662 if (ret) {
663 audio_output_volume_ = level;
664 }
665
666 return ret;
667}
668
669bool ChannelManager::IsSameCapturer(const std::string& capturer_name,
670 VideoCapturer* capturer) {
671 if (capturer == NULL) {
672 return false;
673 }
674 Device device;
675 if (!device_manager_->GetVideoCaptureDevice(capturer_name, &device)) {
676 return false;
677 }
678 return capturer->GetId() == device.id;
679}
680
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000681bool ChannelManager::GetVideoCaptureDevice(Device* device) {
682 std::string device_name;
683 if (!GetCaptureDevice(&device_name)) {
684 return false;
685 }
686 return device_manager_->GetVideoCaptureDevice(device_name, device);
687}
688
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000689bool ChannelManager::GetCaptureDevice(std::string* cam_name) {
690 if (camera_device_.empty()) {
691 // Initialize camera_device_ with default.
692 Device device;
693 if (!device_manager_->GetVideoCaptureDevice(
694 DeviceManagerInterface::kDefaultDeviceName, &device)) {
695 LOG(LS_WARNING) << "Device manager can't find default camera: " <<
696 DeviceManagerInterface::kDefaultDeviceName;
697 return false;
698 }
699 camera_device_ = device.name;
700 }
701 *cam_name = camera_device_;
702 return true;
703}
704
705bool ChannelManager::SetCaptureDevice(const std::string& cam_name) {
706 Device device;
707 bool ret = true;
708 if (!device_manager_->GetVideoCaptureDevice(cam_name, &device)) {
709 if (!cam_name.empty()) {
710 LOG(LS_WARNING) << "Device manager can't find camera: " << cam_name;
711 }
712 ret = false;
713 }
714
715 // If we're running, tell the media engine about it.
716 if (initialized_ && ret) {
717 ret = worker_thread_->Invoke<bool>(
718 Bind(&ChannelManager::SetCaptureDevice_w, this, &device));
719 }
720
721 // If everything worked, retain the name of the selected camera.
722 if (ret) {
723 camera_device_ = device.name;
724 } else if (camera_device_.empty()) {
725 // When video option setting fails, we still want camera_device_ to be in a
726 // good state, so we initialize it with default if it's empty.
727 Device default_device;
728 if (!device_manager_->GetVideoCaptureDevice(
729 DeviceManagerInterface::kDefaultDeviceName, &default_device)) {
730 LOG(LS_WARNING) << "Device manager can't find default camera: " <<
731 DeviceManagerInterface::kDefaultDeviceName;
732 }
733 camera_device_ = default_device.name;
734 }
735
736 return ret;
737}
738
739VideoCapturer* ChannelManager::CreateVideoCapturer() {
740 Device device;
741 if (!device_manager_->GetVideoCaptureDevice(camera_device_, &device)) {
742 if (!camera_device_.empty()) {
743 LOG(LS_WARNING) << "Device manager can't find camera: " << camera_device_;
744 }
745 return NULL;
746 }
sergeyu@chromium.orga59696b2013-09-13 23:48:58 +0000747 VideoCapturer* capturer = device_manager_->CreateVideoCapturer(device);
748 if (capturer && default_video_encoder_config_.max_codec.id != 0) {
749 // For now, use the aspect ratio of the default_video_encoder_config_,
750 // which may be different than the native aspect ratio of the start
751 // format the camera may use.
752 capturer->UpdateAspectRatio(
753 default_video_encoder_config_.max_codec.width,
754 default_video_encoder_config_.max_codec.height);
755 }
756 return capturer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000757}
758
buildbot@webrtc.org65b98d12014-08-07 22:09:08 +0000759VideoCapturer* ChannelManager::CreateScreenCapturer(
760 const ScreencastId& screenid) {
761 return device_manager_->CreateScreenCapturer(screenid);
762}
763
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000764bool ChannelManager::SetCaptureDevice_w(const Device* cam_device) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000765 ASSERT(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000766 ASSERT(initialized_);
767
768 if (!cam_device) {
769 video_device_name_.clear();
770 return true;
771 }
772 video_device_name_ = cam_device->name;
773 return true;
774}
775
776bool ChannelManager::SetDefaultVideoEncoderConfig(const VideoEncoderConfig& c) {
buildbot@webrtc.org992febb2014-09-05 16:39:08 +0000777 bool ret = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000778 if (initialized_) {
buildbot@webrtc.org992febb2014-09-05 16:39:08 +0000779 ret = worker_thread_->Invoke<bool>(
780 Bind(&MediaEngineInterface::SetDefaultVideoEncoderConfig,
781 media_engine_.get(), c));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000782 }
buildbot@webrtc.org992febb2014-09-05 16:39:08 +0000783 if (ret) {
784 default_video_encoder_config_ = c;
785 }
786 return ret;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000787}
788
789bool ChannelManager::SetLocalMonitor(bool enable) {
790 bool ret = initialized_ && worker_thread_->Invoke<bool>(
791 Bind(&MediaEngineInterface::SetLocalMonitor,
792 media_engine_.get(), enable));
793 if (ret) {
794 monitoring_ = enable;
795 }
796 return ret;
797}
798
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000799void ChannelManager::SetVoiceLogging(int level, const char* filter) {
800 if (initialized_) {
801 worker_thread_->Invoke<void>(
802 Bind(&MediaEngineInterface::SetVoiceLogging,
803 media_engine_.get(), level, filter));
804 } else {
805 media_engine_->SetVoiceLogging(level, filter);
806 }
807}
808
809void ChannelManager::SetVideoLogging(int level, const char* filter) {
810 if (initialized_) {
811 worker_thread_->Invoke<void>(
812 Bind(&MediaEngineInterface::SetVideoLogging,
813 media_engine_.get(), level, filter));
814 } else {
815 media_engine_->SetVideoLogging(level, filter);
816 }
817}
818
hbos@webrtc.org1e642632015-02-25 09:49:41 +0000819std::vector<cricket::VideoFormat> ChannelManager::GetSupportedFormats(
820 VideoCapturer* capturer) const {
821 ASSERT(capturer != NULL);
822 std::vector<VideoFormat> formats;
823 worker_thread_->Invoke<void>(rtc::Bind(&ChannelManager::GetSupportedFormats_w,
824 this, capturer, &formats));
825 return formats;
826}
827
828void ChannelManager::GetSupportedFormats_w(
829 VideoCapturer* capturer,
830 std::vector<cricket::VideoFormat>* out_formats) const {
831 const std::vector<VideoFormat>* formats = capturer->GetSupportedFormats();
832 if (formats != NULL)
833 *out_formats = *formats;
834}
835
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000836// TODO(janahan): For now pass this request through the mediaengine to the
837// voice and video engines to do the real work. Once the capturer refactoring
838// is done, we will access the capturer using the ssrc (similar to how the
839// renderer is accessed today) and register with it directly.
840bool ChannelManager::RegisterVideoProcessor(VideoCapturer* capturer,
841 VideoProcessor* processor) {
842 return initialized_ && worker_thread_->Invoke<bool>(
843 Bind(&ChannelManager::RegisterVideoProcessor_w, this,
844 capturer, processor));
845}
846
847bool ChannelManager::RegisterVideoProcessor_w(VideoCapturer* capturer,
848 VideoProcessor* processor) {
849 return capture_manager_->AddVideoProcessor(capturer, processor);
850}
851
852bool ChannelManager::UnregisterVideoProcessor(VideoCapturer* capturer,
853 VideoProcessor* processor) {
854 return initialized_ && worker_thread_->Invoke<bool>(
855 Bind(&ChannelManager::UnregisterVideoProcessor_w, this,
856 capturer, processor));
857}
858
859bool ChannelManager::UnregisterVideoProcessor_w(VideoCapturer* capturer,
860 VideoProcessor* processor) {
861 return capture_manager_->RemoveVideoProcessor(capturer, processor);
862}
863
864bool ChannelManager::RegisterVoiceProcessor(
865 uint32 ssrc,
866 VoiceProcessor* processor,
867 MediaProcessorDirection direction) {
868 return initialized_ && worker_thread_->Invoke<bool>(
869 Bind(&MediaEngineInterface::RegisterVoiceProcessor, media_engine_.get(),
870 ssrc, processor, direction));
871}
872
873bool ChannelManager::UnregisterVoiceProcessor(
874 uint32 ssrc,
875 VoiceProcessor* processor,
876 MediaProcessorDirection direction) {
877 return initialized_ && worker_thread_->Invoke<bool>(
878 Bind(&MediaEngineInterface::UnregisterVoiceProcessor,
879 media_engine_.get(), ssrc, processor, direction));
880}
881
882// The following are done in the new "CaptureManager" style that
883// all local video capturers, processors, and managers should move
884// to.
885// TODO(pthatcher): Add more of the CaptureManager interface.
886bool ChannelManager::StartVideoCapture(
887 VideoCapturer* capturer, const VideoFormat& video_format) {
888 return initialized_ && worker_thread_->Invoke<bool>(
889 Bind(&CaptureManager::StartVideoCapture,
890 capture_manager_.get(), capturer, video_format));
891}
892
893bool ChannelManager::MuteToBlackThenPause(
894 VideoCapturer* video_capturer, bool muted) {
895 if (!initialized_) {
896 return false;
897 }
898 worker_thread_->Invoke<void>(
899 Bind(&VideoCapturer::MuteToBlackThenPause, video_capturer, muted));
900 return true;
901}
902
903bool ChannelManager::StopVideoCapture(
904 VideoCapturer* capturer, const VideoFormat& video_format) {
905 return initialized_ && worker_thread_->Invoke<bool>(
906 Bind(&CaptureManager::StopVideoCapture,
907 capture_manager_.get(), capturer, video_format));
908}
909
910bool ChannelManager::RestartVideoCapture(
911 VideoCapturer* video_capturer,
912 const VideoFormat& previous_format,
913 const VideoFormat& desired_format,
914 CaptureManager::RestartOptions options) {
915 return initialized_ && worker_thread_->Invoke<bool>(
916 Bind(&CaptureManager::RestartVideoCapture, capture_manager_.get(),
917 video_capturer, previous_format, desired_format, options));
918}
919
920bool ChannelManager::AddVideoRenderer(
921 VideoCapturer* capturer, VideoRenderer* renderer) {
922 return initialized_ && worker_thread_->Invoke<bool>(
923 Bind(&CaptureManager::AddVideoRenderer,
924 capture_manager_.get(), capturer, renderer));
925}
926
927bool ChannelManager::RemoveVideoRenderer(
928 VideoCapturer* capturer, VideoRenderer* renderer) {
929 return initialized_ && worker_thread_->Invoke<bool>(
930 Bind(&CaptureManager::RemoveVideoRenderer,
931 capture_manager_.get(), capturer, renderer));
932}
933
934bool ChannelManager::IsScreencastRunning() const {
935 return initialized_ && worker_thread_->Invoke<bool>(
936 Bind(&ChannelManager::IsScreencastRunning_w, this));
937}
938
939bool ChannelManager::IsScreencastRunning_w() const {
940 VideoChannels::const_iterator it = video_channels_.begin();
941 for ( ; it != video_channels_.end(); ++it) {
942 if ((*it) && (*it)->IsScreencasting()) {
943 return true;
944 }
945 }
946 return false;
947}
948
949void ChannelManager::OnVideoCaptureStateChange(VideoCapturer* capturer,
950 CaptureState result) {
951 // TODO(whyuan): Check capturer and signal failure only for camera video, not
952 // screencast.
953 capturing_ = result == CS_RUNNING;
954 main_thread_->Post(this, MSG_VIDEOCAPTURESTATE,
955 new CaptureStateParams(capturer, result));
956}
957
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000958void ChannelManager::OnMessage(rtc::Message* message) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000959 switch (message->message_id) {
960 case MSG_VIDEOCAPTURESTATE: {
961 CaptureStateParams* data =
962 static_cast<CaptureStateParams*>(message->pdata);
963 SignalVideoCaptureStateChange(data->capturer, data->state);
964 delete data;
965 break;
966 }
967 }
968}
969
970
971static void GetDeviceNames(const std::vector<Device>& devs,
972 std::vector<std::string>* names) {
973 names->clear();
974 for (size_t i = 0; i < devs.size(); ++i) {
975 names->push_back(devs[i].name);
976 }
977}
978
979bool ChannelManager::GetAudioInputDevices(std::vector<std::string>* names) {
980 names->clear();
981 std::vector<Device> devs;
982 bool ret = device_manager_->GetAudioInputDevices(&devs);
983 if (ret)
984 GetDeviceNames(devs, names);
985
986 return ret;
987}
988
989bool ChannelManager::GetAudioOutputDevices(std::vector<std::string>* names) {
990 names->clear();
991 std::vector<Device> devs;
992 bool ret = device_manager_->GetAudioOutputDevices(&devs);
993 if (ret)
994 GetDeviceNames(devs, names);
995
996 return ret;
997}
998
999bool ChannelManager::GetVideoCaptureDevices(std::vector<std::string>* names) {
1000 names->clear();
1001 std::vector<Device> devs;
1002 bool ret = device_manager_->GetVideoCaptureDevices(&devs);
1003 if (ret)
1004 GetDeviceNames(devs, names);
1005
1006 return ret;
1007}
1008
1009void ChannelManager::SetVideoCaptureDeviceMaxFormat(
1010 const std::string& usb_id,
1011 const VideoFormat& max_format) {
1012 device_manager_->SetVideoCaptureDeviceMaxFormat(usb_id, max_format);
1013}
1014
buildbot@webrtc.org992febb2014-09-05 16:39:08 +00001015VideoFormat ChannelManager::GetStartCaptureFormat() {
1016 return worker_thread_->Invoke<VideoFormat>(
1017 Bind(&MediaEngineInterface::GetStartCaptureFormat, media_engine_.get()));
1018}
1019
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001020bool ChannelManager::StartAecDump(rtc::PlatformFile file) {
wu@webrtc.orga9890802013-12-13 00:21:03 +00001021 return worker_thread_->Invoke<bool>(
1022 Bind(&MediaEngineInterface::StartAecDump, media_engine_.get(), file));
1023}
1024
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001025} // namespace cricket