blob: 8ceb148b3920771960ed254463601b32e562c700 [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;
buildbot@webrtc.orgbb2d6582014-06-20 14:58:56 +0000123 audio_delay_offset_ = MediaEngineInterface::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 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000152}
153
154bool ChannelManager::SetVideoRtxEnabled(bool enable) {
155 // To be safe, this call is only allowed before initialization. Apps like
156 // Flute only have a singleton ChannelManager and we don't want this flag to
157 // be toggled between calls or when there's concurrent calls. We expect apps
158 // to enable this at startup and retain that setting for the lifetime of the
159 // app.
160 if (!initialized_) {
161 enable_rtx_ = enable;
162 return true;
163 } else {
164 LOG(LS_WARNING) << "Cannot toggle rtx after initialization!";
165 return false;
166 }
167}
168
169int ChannelManager::GetCapabilities() {
170 return media_engine_->GetCapabilities() & device_manager_->GetCapabilities();
171}
172
173void ChannelManager::GetSupportedAudioCodecs(
174 std::vector<AudioCodec>* codecs) const {
175 codecs->clear();
176
177 for (std::vector<AudioCodec>::const_iterator it =
178 media_engine_->audio_codecs().begin();
179 it != media_engine_->audio_codecs().end(); ++it) {
180 codecs->push_back(*it);
181 }
182}
183
184void ChannelManager::GetSupportedAudioRtpHeaderExtensions(
185 RtpHeaderExtensions* ext) const {
186 *ext = media_engine_->audio_rtp_header_extensions();
187}
188
189void ChannelManager::GetSupportedVideoCodecs(
190 std::vector<VideoCodec>* codecs) const {
191 codecs->clear();
192
193 std::vector<VideoCodec>::const_iterator it;
194 for (it = media_engine_->video_codecs().begin();
195 it != media_engine_->video_codecs().end(); ++it) {
196 if (!enable_rtx_ && _stricmp(kRtxCodecName, it->name.c_str()) == 0) {
197 continue;
198 }
199 codecs->push_back(*it);
200 }
201}
202
203void ChannelManager::GetSupportedVideoRtpHeaderExtensions(
204 RtpHeaderExtensions* ext) const {
205 *ext = media_engine_->video_rtp_header_extensions();
206}
207
208void ChannelManager::GetSupportedDataCodecs(
209 std::vector<DataCodec>* codecs) const {
210 *codecs = data_media_engine_->data_codecs();
211}
212
213bool ChannelManager::Init() {
214 ASSERT(!initialized_);
215 if (initialized_) {
216 return false;
217 }
218
219 ASSERT(worker_thread_ != NULL);
tkchin@webrtc.org42fe4352014-07-15 17:52:43 +0000220 if (worker_thread_) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000221 if (media_engine_->Init(worker_thread_)) {
222 initialized_ = true;
223
224 // Now that we're initialized, apply any stored preferences. A preferred
225 // device might have been unplugged. In this case, we fallback to the
226 // default device but keep the user preferences. The preferences are
227 // changed only when the Javascript FE changes them.
228 const std::string preferred_audio_in_device = audio_in_device_;
229 const std::string preferred_audio_out_device = audio_out_device_;
230 const std::string preferred_camera_device = camera_device_;
231 Device device;
232 if (!device_manager_->GetAudioInputDevice(audio_in_device_, &device)) {
233 LOG(LS_WARNING) << "The preferred microphone '" << audio_in_device_
234 << "' is unavailable. Fall back to the default.";
235 audio_in_device_ = DeviceManagerInterface::kDefaultDeviceName;
236 }
237 if (!device_manager_->GetAudioOutputDevice(audio_out_device_, &device)) {
238 LOG(LS_WARNING) << "The preferred speaker '" << audio_out_device_
239 << "' is unavailable. Fall back to the default.";
240 audio_out_device_ = DeviceManagerInterface::kDefaultDeviceName;
241 }
242 if (!device_manager_->GetVideoCaptureDevice(camera_device_, &device)) {
243 if (!camera_device_.empty()) {
244 LOG(LS_WARNING) << "The preferred camera '" << camera_device_
245 << "' is unavailable. Fall back to the default.";
246 }
247 camera_device_ = DeviceManagerInterface::kDefaultDeviceName;
248 }
249
250 if (!SetAudioOptions(audio_in_device_, audio_out_device_,
251 audio_options_, audio_delay_offset_)) {
252 LOG(LS_WARNING) << "Failed to SetAudioOptions with"
253 << " microphone: " << audio_in_device_
254 << " speaker: " << audio_out_device_
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000255 << " options: " << audio_options_.ToString()
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000256 << " delay: " << audio_delay_offset_;
257 }
258
259 // If audio_output_volume_ has been set via SetOutputVolume(), set the
260 // audio output volume of the engine.
261 if (kNotSetOutputVolume != audio_output_volume_ &&
262 !SetOutputVolume(audio_output_volume_)) {
263 LOG(LS_WARNING) << "Failed to SetOutputVolume to "
264 << audio_output_volume_;
265 }
266 if (!SetCaptureDevice(camera_device_) && !camera_device_.empty()) {
267 LOG(LS_WARNING) << "Failed to SetCaptureDevice with camera: "
268 << camera_device_;
269 }
270
271 // Restore the user preferences.
272 audio_in_device_ = preferred_audio_in_device;
273 audio_out_device_ = preferred_audio_out_device;
274 camera_device_ = preferred_camera_device;
275
276 // Now apply the default video codec that has been set earlier.
277 if (default_video_encoder_config_.max_codec.id != 0) {
278 SetDefaultVideoEncoderConfig(default_video_encoder_config_);
279 }
280 // And the local renderer.
281 if (local_renderer_) {
282 SetLocalRenderer(local_renderer_);
283 }
284 }
285 }
286 return initialized_;
287}
288
289void ChannelManager::Terminate() {
290 ASSERT(initialized_);
291 if (!initialized_) {
292 return;
293 }
294 worker_thread_->Invoke<void>(Bind(&ChannelManager::Terminate_w, this));
295 media_engine_->Terminate();
296 initialized_ = false;
297}
298
299void ChannelManager::Terminate_w() {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000300 ASSERT(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000301 // Need to destroy the voice/video channels
302 while (!video_channels_.empty()) {
303 DestroyVideoChannel_w(video_channels_.back());
304 }
305 while (!voice_channels_.empty()) {
306 DestroyVoiceChannel_w(voice_channels_.back());
307 }
308 while (!soundclips_.empty()) {
309 DestroySoundclip_w(soundclips_.back());
310 }
311 if (!SetCaptureDevice_w(NULL)) {
312 LOG(LS_WARNING) << "failed to delete video capturer";
313 }
314}
315
316VoiceChannel* ChannelManager::CreateVoiceChannel(
317 BaseSession* session, const std::string& content_name, bool rtcp) {
318 return worker_thread_->Invoke<VoiceChannel*>(
319 Bind(&ChannelManager::CreateVoiceChannel_w, this,
320 session, content_name, rtcp));
321}
322
323VoiceChannel* ChannelManager::CreateVoiceChannel_w(
324 BaseSession* session, const std::string& content_name, bool rtcp) {
325 // This is ok to alloc from a thread other than the worker thread
326 ASSERT(initialized_);
327 VoiceMediaChannel* media_channel = media_engine_->CreateChannel();
328 if (media_channel == NULL)
329 return NULL;
330
331 VoiceChannel* voice_channel = new VoiceChannel(
332 worker_thread_, media_engine_.get(), media_channel,
333 session, content_name, rtcp);
334 if (!voice_channel->Init()) {
335 delete voice_channel;
336 return NULL;
337 }
338 voice_channels_.push_back(voice_channel);
339 return voice_channel;
340}
341
342void ChannelManager::DestroyVoiceChannel(VoiceChannel* voice_channel) {
343 if (voice_channel) {
344 worker_thread_->Invoke<void>(
345 Bind(&ChannelManager::DestroyVoiceChannel_w, this, voice_channel));
346 }
347}
348
349void ChannelManager::DestroyVoiceChannel_w(VoiceChannel* voice_channel) {
350 // Destroy voice channel.
351 ASSERT(initialized_);
352 VoiceChannels::iterator it = std::find(voice_channels_.begin(),
353 voice_channels_.end(), voice_channel);
354 ASSERT(it != voice_channels_.end());
355 if (it == voice_channels_.end())
356 return;
357
358 voice_channels_.erase(it);
359 delete voice_channel;
360}
361
362VideoChannel* ChannelManager::CreateVideoChannel(
363 BaseSession* session, const std::string& content_name, bool rtcp,
364 VoiceChannel* voice_channel) {
365 return worker_thread_->Invoke<VideoChannel*>(
366 Bind(&ChannelManager::CreateVideoChannel_w, this, session,
367 content_name, rtcp, voice_channel));
368}
369
370VideoChannel* ChannelManager::CreateVideoChannel_w(
371 BaseSession* session, const std::string& content_name, bool rtcp,
372 VoiceChannel* voice_channel) {
373 // This is ok to alloc from a thread other than the worker thread
374 ASSERT(initialized_);
375 VideoMediaChannel* media_channel =
376 // voice_channel can be NULL in case of NullVoiceEngine.
377 media_engine_->CreateVideoChannel(voice_channel ?
378 voice_channel->media_channel() : NULL);
379 if (media_channel == NULL)
380 return NULL;
381
382 VideoChannel* video_channel = new VideoChannel(
383 worker_thread_, media_engine_.get(), media_channel,
384 session, content_name, rtcp, voice_channel);
385 if (!video_channel->Init()) {
386 delete video_channel;
387 return NULL;
388 }
389 video_channels_.push_back(video_channel);
390 return video_channel;
391}
392
393void ChannelManager::DestroyVideoChannel(VideoChannel* video_channel) {
394 if (video_channel) {
395 worker_thread_->Invoke<void>(
396 Bind(&ChannelManager::DestroyVideoChannel_w, this, video_channel));
397 }
398}
399
400void ChannelManager::DestroyVideoChannel_w(VideoChannel* video_channel) {
401 // Destroy video channel.
402 ASSERT(initialized_);
403 VideoChannels::iterator it = std::find(video_channels_.begin(),
404 video_channels_.end(), video_channel);
405 ASSERT(it != video_channels_.end());
406 if (it == video_channels_.end())
407 return;
408
409 video_channels_.erase(it);
410 delete video_channel;
411}
412
413DataChannel* ChannelManager::CreateDataChannel(
414 BaseSession* session, const std::string& content_name,
415 bool rtcp, DataChannelType channel_type) {
416 return worker_thread_->Invoke<DataChannel*>(
417 Bind(&ChannelManager::CreateDataChannel_w, this, session, content_name,
418 rtcp, channel_type));
419}
420
421DataChannel* ChannelManager::CreateDataChannel_w(
422 BaseSession* session, const std::string& content_name,
423 bool rtcp, DataChannelType data_channel_type) {
424 // This is ok to alloc from a thread other than the worker thread.
425 ASSERT(initialized_);
426 DataMediaChannel* media_channel = data_media_engine_->CreateChannel(
427 data_channel_type);
428 if (!media_channel) {
429 LOG(LS_WARNING) << "Failed to create data channel of type "
430 << data_channel_type;
431 return NULL;
432 }
433
434 DataChannel* data_channel = new DataChannel(
435 worker_thread_, media_channel,
436 session, content_name, rtcp);
437 if (!data_channel->Init()) {
438 LOG(LS_WARNING) << "Failed to init data channel.";
439 delete data_channel;
440 return NULL;
441 }
442 data_channels_.push_back(data_channel);
443 return data_channel;
444}
445
446void ChannelManager::DestroyDataChannel(DataChannel* data_channel) {
447 if (data_channel) {
448 worker_thread_->Invoke<void>(
449 Bind(&ChannelManager::DestroyDataChannel_w, this, data_channel));
450 }
451}
452
453void ChannelManager::DestroyDataChannel_w(DataChannel* data_channel) {
454 // Destroy data channel.
455 ASSERT(initialized_);
456 DataChannels::iterator it = std::find(data_channels_.begin(),
457 data_channels_.end(), data_channel);
458 ASSERT(it != data_channels_.end());
459 if (it == data_channels_.end())
460 return;
461
462 data_channels_.erase(it);
463 delete data_channel;
464}
465
466Soundclip* ChannelManager::CreateSoundclip() {
467 return worker_thread_->Invoke<Soundclip*>(
468 Bind(&ChannelManager::CreateSoundclip_w, this));
469}
470
471Soundclip* ChannelManager::CreateSoundclip_w() {
472 ASSERT(initialized_);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000473 ASSERT(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000474
475 SoundclipMedia* soundclip_media = media_engine_->CreateSoundclip();
476 if (!soundclip_media) {
477 return NULL;
478 }
479
480 Soundclip* soundclip = new Soundclip(worker_thread_, soundclip_media);
481 soundclips_.push_back(soundclip);
482 return soundclip;
483}
484
485void ChannelManager::DestroySoundclip(Soundclip* soundclip) {
486 if (soundclip) {
487 worker_thread_->Invoke<void>(
488 Bind(&ChannelManager::DestroySoundclip_w, this, soundclip));
489 }
490}
491
492void ChannelManager::DestroySoundclip_w(Soundclip* soundclip) {
493 // Destroy soundclip.
494 ASSERT(initialized_);
495 Soundclips::iterator it = std::find(soundclips_.begin(),
496 soundclips_.end(), soundclip);
497 ASSERT(it != soundclips_.end());
498 if (it == soundclips_.end())
499 return;
500
501 soundclips_.erase(it);
502 delete soundclip;
503}
504
505bool ChannelManager::GetAudioOptions(std::string* in_name,
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000506 std::string* out_name,
507 AudioOptions* options) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000508 if (in_name)
509 *in_name = audio_in_device_;
510 if (out_name)
511 *out_name = audio_out_device_;
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000512 if (options)
513 *options = audio_options_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000514 return true;
515}
516
517bool ChannelManager::SetAudioOptions(const std::string& in_name,
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000518 const std::string& out_name,
519 const AudioOptions& options) {
520 return SetAudioOptions(in_name, out_name, options, audio_delay_offset_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000521}
522
523bool ChannelManager::SetAudioOptions(const std::string& in_name,
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000524 const std::string& out_name,
525 const AudioOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000526 int delay_offset) {
527 // Get device ids from DeviceManager.
528 Device in_dev, out_dev;
529 if (!device_manager_->GetAudioInputDevice(in_name, &in_dev)) {
530 LOG(LS_WARNING) << "Failed to GetAudioInputDevice: " << in_name;
531 return false;
532 }
533 if (!device_manager_->GetAudioOutputDevice(out_name, &out_dev)) {
534 LOG(LS_WARNING) << "Failed to GetAudioOutputDevice: " << out_name;
535 return false;
536 }
537
538 // If we're initialized, pass the settings to the media engine.
539 bool ret = true;
540 if (initialized_) {
541 ret = worker_thread_->Invoke<bool>(
542 Bind(&ChannelManager::SetAudioOptions_w, this,
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000543 options, delay_offset, &in_dev, &out_dev));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000544 }
545
546 // If all worked well, save the values for use in GetAudioOptions.
547 if (ret) {
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000548 audio_options_ = options;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000549 audio_in_device_ = in_name;
550 audio_out_device_ = out_name;
551 audio_delay_offset_ = delay_offset;
552 }
553 return ret;
554}
555
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000556bool ChannelManager::SetAudioOptions_w(
557 const AudioOptions& options, int delay_offset,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000558 const Device* in_dev, const Device* out_dev) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000559 ASSERT(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000560 ASSERT(initialized_);
561
562 // Set audio options
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000563 bool ret = media_engine_->SetAudioOptions(options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000564
565 if (ret) {
566 ret = media_engine_->SetAudioDelayOffset(delay_offset);
567 }
568
569 // Set the audio devices
570 if (ret) {
571 ret = media_engine_->SetSoundDevices(in_dev, out_dev);
572 }
573
574 return ret;
575}
576
buildbot@webrtc.org88d9fa62014-06-16 14:11:32 +0000577// Sets Engine-specific audio options according to enabled experiments.
578bool ChannelManager::SetEngineAudioOptions(const AudioOptions& options) {
579 // If we're initialized, pass the settings to the media engine.
580 bool ret = false;
581 if (initialized_) {
582 ret = worker_thread_->Invoke<bool>(
583 Bind(&ChannelManager::SetEngineAudioOptions_w, this, options));
584 }
585
586 // If all worked well, save the audio options.
587 if (ret) {
588 audio_options_ = options;
589 }
590 return ret;
591}
592
593bool ChannelManager::SetEngineAudioOptions_w(const AudioOptions& options) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000594 ASSERT(worker_thread_ == rtc::Thread::Current());
buildbot@webrtc.org88d9fa62014-06-16 14:11:32 +0000595 ASSERT(initialized_);
596
597 return media_engine_->SetAudioOptions(options);
598}
599
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000600bool ChannelManager::GetOutputVolume(int* level) {
601 if (!initialized_) {
602 return false;
603 }
604 return worker_thread_->Invoke<bool>(
605 Bind(&MediaEngineInterface::GetOutputVolume, media_engine_.get(), level));
606}
607
608bool ChannelManager::SetOutputVolume(int level) {
609 bool ret = level >= 0 && level <= 255;
610 if (initialized_) {
611 ret &= worker_thread_->Invoke<bool>(
612 Bind(&MediaEngineInterface::SetOutputVolume,
613 media_engine_.get(), level));
614 }
615
616 if (ret) {
617 audio_output_volume_ = level;
618 }
619
620 return ret;
621}
622
623bool ChannelManager::IsSameCapturer(const std::string& capturer_name,
624 VideoCapturer* capturer) {
625 if (capturer == NULL) {
626 return false;
627 }
628 Device device;
629 if (!device_manager_->GetVideoCaptureDevice(capturer_name, &device)) {
630 return false;
631 }
632 return capturer->GetId() == device.id;
633}
634
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000635bool ChannelManager::GetVideoCaptureDevice(Device* device) {
636 std::string device_name;
637 if (!GetCaptureDevice(&device_name)) {
638 return false;
639 }
640 return device_manager_->GetVideoCaptureDevice(device_name, device);
641}
642
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000643bool ChannelManager::GetCaptureDevice(std::string* cam_name) {
644 if (camera_device_.empty()) {
645 // Initialize camera_device_ with default.
646 Device device;
647 if (!device_manager_->GetVideoCaptureDevice(
648 DeviceManagerInterface::kDefaultDeviceName, &device)) {
649 LOG(LS_WARNING) << "Device manager can't find default camera: " <<
650 DeviceManagerInterface::kDefaultDeviceName;
651 return false;
652 }
653 camera_device_ = device.name;
654 }
655 *cam_name = camera_device_;
656 return true;
657}
658
659bool ChannelManager::SetCaptureDevice(const std::string& cam_name) {
660 Device device;
661 bool ret = true;
662 if (!device_manager_->GetVideoCaptureDevice(cam_name, &device)) {
663 if (!cam_name.empty()) {
664 LOG(LS_WARNING) << "Device manager can't find camera: " << cam_name;
665 }
666 ret = false;
667 }
668
669 // If we're running, tell the media engine about it.
670 if (initialized_ && ret) {
671 ret = worker_thread_->Invoke<bool>(
672 Bind(&ChannelManager::SetCaptureDevice_w, this, &device));
673 }
674
675 // If everything worked, retain the name of the selected camera.
676 if (ret) {
677 camera_device_ = device.name;
678 } else if (camera_device_.empty()) {
679 // When video option setting fails, we still want camera_device_ to be in a
680 // good state, so we initialize it with default if it's empty.
681 Device default_device;
682 if (!device_manager_->GetVideoCaptureDevice(
683 DeviceManagerInterface::kDefaultDeviceName, &default_device)) {
684 LOG(LS_WARNING) << "Device manager can't find default camera: " <<
685 DeviceManagerInterface::kDefaultDeviceName;
686 }
687 camera_device_ = default_device.name;
688 }
689
690 return ret;
691}
692
693VideoCapturer* ChannelManager::CreateVideoCapturer() {
694 Device device;
695 if (!device_manager_->GetVideoCaptureDevice(camera_device_, &device)) {
696 if (!camera_device_.empty()) {
697 LOG(LS_WARNING) << "Device manager can't find camera: " << camera_device_;
698 }
699 return NULL;
700 }
sergeyu@chromium.orga59696b2013-09-13 23:48:58 +0000701 VideoCapturer* capturer = device_manager_->CreateVideoCapturer(device);
702 if (capturer && default_video_encoder_config_.max_codec.id != 0) {
703 // For now, use the aspect ratio of the default_video_encoder_config_,
704 // which may be different than the native aspect ratio of the start
705 // format the camera may use.
706 capturer->UpdateAspectRatio(
707 default_video_encoder_config_.max_codec.width,
708 default_video_encoder_config_.max_codec.height);
709 }
710 return capturer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000711}
712
buildbot@webrtc.org65b98d12014-08-07 22:09:08 +0000713VideoCapturer* ChannelManager::CreateScreenCapturer(
714 const ScreencastId& screenid) {
715 return device_manager_->CreateScreenCapturer(screenid);
716}
717
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000718bool ChannelManager::SetCaptureDevice_w(const Device* cam_device) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000719 ASSERT(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000720 ASSERT(initialized_);
721
722 if (!cam_device) {
723 video_device_name_.clear();
724 return true;
725 }
726 video_device_name_ = cam_device->name;
727 return true;
728}
729
730bool ChannelManager::SetDefaultVideoEncoderConfig(const VideoEncoderConfig& c) {
731 bool ret = true;
732 if (initialized_) {
733 ret = worker_thread_->Invoke<bool>(
734 Bind(&MediaEngineInterface::SetDefaultVideoEncoderConfig,
735 media_engine_.get(), c));
736 }
737 if (ret) {
738 default_video_encoder_config_ = c;
739 }
740 return ret;
741}
742
743bool ChannelManager::SetLocalMonitor(bool enable) {
744 bool ret = initialized_ && worker_thread_->Invoke<bool>(
745 Bind(&MediaEngineInterface::SetLocalMonitor,
746 media_engine_.get(), enable));
747 if (ret) {
748 monitoring_ = enable;
749 }
750 return ret;
751}
752
753bool ChannelManager::SetLocalRenderer(VideoRenderer* renderer) {
754 bool ret = true;
755 if (initialized_) {
756 ret = worker_thread_->Invoke<bool>(
757 Bind(&MediaEngineInterface::SetLocalRenderer,
758 media_engine_.get(), renderer));
759 }
760 if (ret) {
761 local_renderer_ = renderer;
762 }
763 return ret;
764}
765
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000766void ChannelManager::SetVoiceLogging(int level, const char* filter) {
767 if (initialized_) {
768 worker_thread_->Invoke<void>(
769 Bind(&MediaEngineInterface::SetVoiceLogging,
770 media_engine_.get(), level, filter));
771 } else {
772 media_engine_->SetVoiceLogging(level, filter);
773 }
774}
775
776void ChannelManager::SetVideoLogging(int level, const char* filter) {
777 if (initialized_) {
778 worker_thread_->Invoke<void>(
779 Bind(&MediaEngineInterface::SetVideoLogging,
780 media_engine_.get(), level, filter));
781 } else {
782 media_engine_->SetVideoLogging(level, filter);
783 }
784}
785
786// TODO(janahan): For now pass this request through the mediaengine to the
787// voice and video engines to do the real work. Once the capturer refactoring
788// is done, we will access the capturer using the ssrc (similar to how the
789// renderer is accessed today) and register with it directly.
790bool ChannelManager::RegisterVideoProcessor(VideoCapturer* capturer,
791 VideoProcessor* processor) {
792 return initialized_ && worker_thread_->Invoke<bool>(
793 Bind(&ChannelManager::RegisterVideoProcessor_w, this,
794 capturer, processor));
795}
796
797bool ChannelManager::RegisterVideoProcessor_w(VideoCapturer* capturer,
798 VideoProcessor* processor) {
799 return capture_manager_->AddVideoProcessor(capturer, processor);
800}
801
802bool ChannelManager::UnregisterVideoProcessor(VideoCapturer* capturer,
803 VideoProcessor* processor) {
804 return initialized_ && worker_thread_->Invoke<bool>(
805 Bind(&ChannelManager::UnregisterVideoProcessor_w, this,
806 capturer, processor));
807}
808
809bool ChannelManager::UnregisterVideoProcessor_w(VideoCapturer* capturer,
810 VideoProcessor* processor) {
811 return capture_manager_->RemoveVideoProcessor(capturer, processor);
812}
813
814bool ChannelManager::RegisterVoiceProcessor(
815 uint32 ssrc,
816 VoiceProcessor* processor,
817 MediaProcessorDirection direction) {
818 return initialized_ && worker_thread_->Invoke<bool>(
819 Bind(&MediaEngineInterface::RegisterVoiceProcessor, media_engine_.get(),
820 ssrc, processor, direction));
821}
822
823bool ChannelManager::UnregisterVoiceProcessor(
824 uint32 ssrc,
825 VoiceProcessor* processor,
826 MediaProcessorDirection direction) {
827 return initialized_ && worker_thread_->Invoke<bool>(
828 Bind(&MediaEngineInterface::UnregisterVoiceProcessor,
829 media_engine_.get(), ssrc, processor, direction));
830}
831
832// The following are done in the new "CaptureManager" style that
833// all local video capturers, processors, and managers should move
834// to.
835// TODO(pthatcher): Add more of the CaptureManager interface.
836bool ChannelManager::StartVideoCapture(
837 VideoCapturer* capturer, const VideoFormat& video_format) {
838 return initialized_ && worker_thread_->Invoke<bool>(
839 Bind(&CaptureManager::StartVideoCapture,
840 capture_manager_.get(), capturer, video_format));
841}
842
843bool ChannelManager::MuteToBlackThenPause(
844 VideoCapturer* video_capturer, bool muted) {
845 if (!initialized_) {
846 return false;
847 }
848 worker_thread_->Invoke<void>(
849 Bind(&VideoCapturer::MuteToBlackThenPause, video_capturer, muted));
850 return true;
851}
852
853bool ChannelManager::StopVideoCapture(
854 VideoCapturer* capturer, const VideoFormat& video_format) {
855 return initialized_ && worker_thread_->Invoke<bool>(
856 Bind(&CaptureManager::StopVideoCapture,
857 capture_manager_.get(), capturer, video_format));
858}
859
860bool ChannelManager::RestartVideoCapture(
861 VideoCapturer* video_capturer,
862 const VideoFormat& previous_format,
863 const VideoFormat& desired_format,
864 CaptureManager::RestartOptions options) {
865 return initialized_ && worker_thread_->Invoke<bool>(
866 Bind(&CaptureManager::RestartVideoCapture, capture_manager_.get(),
867 video_capturer, previous_format, desired_format, options));
868}
869
870bool ChannelManager::AddVideoRenderer(
871 VideoCapturer* capturer, VideoRenderer* renderer) {
872 return initialized_ && worker_thread_->Invoke<bool>(
873 Bind(&CaptureManager::AddVideoRenderer,
874 capture_manager_.get(), capturer, renderer));
875}
876
877bool ChannelManager::RemoveVideoRenderer(
878 VideoCapturer* capturer, VideoRenderer* renderer) {
879 return initialized_ && worker_thread_->Invoke<bool>(
880 Bind(&CaptureManager::RemoveVideoRenderer,
881 capture_manager_.get(), capturer, renderer));
882}
883
884bool ChannelManager::IsScreencastRunning() const {
885 return initialized_ && worker_thread_->Invoke<bool>(
886 Bind(&ChannelManager::IsScreencastRunning_w, this));
887}
888
889bool ChannelManager::IsScreencastRunning_w() const {
890 VideoChannels::const_iterator it = video_channels_.begin();
891 for ( ; it != video_channels_.end(); ++it) {
892 if ((*it) && (*it)->IsScreencasting()) {
893 return true;
894 }
895 }
896 return false;
897}
898
899void ChannelManager::OnVideoCaptureStateChange(VideoCapturer* capturer,
900 CaptureState result) {
901 // TODO(whyuan): Check capturer and signal failure only for camera video, not
902 // screencast.
903 capturing_ = result == CS_RUNNING;
904 main_thread_->Post(this, MSG_VIDEOCAPTURESTATE,
905 new CaptureStateParams(capturer, result));
906}
907
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000908void ChannelManager::OnMessage(rtc::Message* message) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000909 switch (message->message_id) {
910 case MSG_VIDEOCAPTURESTATE: {
911 CaptureStateParams* data =
912 static_cast<CaptureStateParams*>(message->pdata);
913 SignalVideoCaptureStateChange(data->capturer, data->state);
914 delete data;
915 break;
916 }
917 }
918}
919
920
921static void GetDeviceNames(const std::vector<Device>& devs,
922 std::vector<std::string>* names) {
923 names->clear();
924 for (size_t i = 0; i < devs.size(); ++i) {
925 names->push_back(devs[i].name);
926 }
927}
928
929bool ChannelManager::GetAudioInputDevices(std::vector<std::string>* names) {
930 names->clear();
931 std::vector<Device> devs;
932 bool ret = device_manager_->GetAudioInputDevices(&devs);
933 if (ret)
934 GetDeviceNames(devs, names);
935
936 return ret;
937}
938
939bool ChannelManager::GetAudioOutputDevices(std::vector<std::string>* names) {
940 names->clear();
941 std::vector<Device> devs;
942 bool ret = device_manager_->GetAudioOutputDevices(&devs);
943 if (ret)
944 GetDeviceNames(devs, names);
945
946 return ret;
947}
948
949bool ChannelManager::GetVideoCaptureDevices(std::vector<std::string>* names) {
950 names->clear();
951 std::vector<Device> devs;
952 bool ret = device_manager_->GetVideoCaptureDevices(&devs);
953 if (ret)
954 GetDeviceNames(devs, names);
955
956 return ret;
957}
958
959void ChannelManager::SetVideoCaptureDeviceMaxFormat(
960 const std::string& usb_id,
961 const VideoFormat& max_format) {
962 device_manager_->SetVideoCaptureDeviceMaxFormat(usb_id, max_format);
963}
964
965VideoFormat ChannelManager::GetStartCaptureFormat() {
966 return worker_thread_->Invoke<VideoFormat>(
967 Bind(&MediaEngineInterface::GetStartCaptureFormat, media_engine_.get()));
968}
969
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000970bool ChannelManager::StartAecDump(rtc::PlatformFile file) {
wu@webrtc.orga9890802013-12-13 00:21:03 +0000971 return worker_thread_->Invoke<bool>(
972 Bind(&MediaEngineInterface::StartAecDump, media_engine_.get(), file));
973}
974
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000975} // namespace cricket