blob: 88e7f79af243477891768e2ed48e5658598b1a82 [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
36#include "talk/base/bind.h"
37#include "talk/base/common.h"
38#include "talk/base/logging.h"
39#include "talk/base/sigslotrepeater.h"
40#include "talk/base/stringencode.h"
41#include "talk/base/stringutils.h"
42#include "talk/media/base/capturemanager.h"
43#include "talk/media/base/hybriddataengine.h"
44#include "talk/media/base/rtpdataengine.h"
45#include "talk/media/base/videocapturer.h"
henrike@webrtc.org723d6832013-07-12 16:04:50 +000046#include "talk/media/devices/devicemanager.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000047#ifdef HAVE_SCTP
48#include "talk/media/sctp/sctpdataengine.h"
49#endif
50#include "talk/session/media/soundclip.h"
51
52namespace cricket {
53
54enum {
55 MSG_VIDEOCAPTURESTATE = 1,
56};
57
58using talk_base::Bind;
59
60static const int kNotSetOutputVolume = -1;
61
62struct CaptureStateParams : public talk_base::MessageData {
63 CaptureStateParams(cricket::VideoCapturer* c, cricket::CaptureState s)
64 : capturer(c),
65 state(s) {}
66 cricket::VideoCapturer* capturer;
67 cricket::CaptureState state;
68};
69
70static DataEngineInterface* ConstructDataEngine() {
71#ifdef HAVE_SCTP
72 return new HybridDataEngine(new RtpDataEngine(), new SctpDataEngine());
73#else
74 return new RtpDataEngine();
75#endif
76}
77
78#if !defined(DISABLE_MEDIA_ENGINE_FACTORY)
79ChannelManager::ChannelManager(talk_base::Thread* worker_thread) {
80 Construct(MediaEngineFactory::Create(),
81 ConstructDataEngine(),
82 cricket::DeviceManagerFactory::Create(),
83 new CaptureManager(),
84 worker_thread);
85}
86#endif
87
88ChannelManager::ChannelManager(MediaEngineInterface* me,
89 DataEngineInterface* dme,
90 DeviceManagerInterface* dm,
91 CaptureManager* cm,
92 talk_base::Thread* worker_thread) {
93 Construct(me, dme, dm, cm, worker_thread);
94}
95
96ChannelManager::ChannelManager(MediaEngineInterface* me,
97 DeviceManagerInterface* dm,
98 talk_base::Thread* worker_thread) {
99 Construct(me,
100 ConstructDataEngine(),
101 dm,
102 new CaptureManager(),
103 worker_thread);
104}
105
106void ChannelManager::Construct(MediaEngineInterface* me,
107 DataEngineInterface* dme,
108 DeviceManagerInterface* dm,
109 CaptureManager* cm,
110 talk_base::Thread* worker_thread) {
111 media_engine_.reset(me);
112 data_media_engine_.reset(dme);
113 device_manager_.reset(dm);
114 capture_manager_.reset(cm);
115 initialized_ = false;
116 main_thread_ = talk_base::Thread::Current();
117 worker_thread_ = worker_thread;
118 audio_in_device_ = DeviceManagerInterface::kDefaultDeviceName;
119 audio_out_device_ = DeviceManagerInterface::kDefaultDeviceName;
120 audio_options_ = MediaEngineInterface::DEFAULT_AUDIO_OPTIONS;
121 audio_delay_offset_ = MediaEngineInterface::kDefaultAudioDelayOffset;
122 audio_output_volume_ = kNotSetOutputVolume;
123 local_renderer_ = NULL;
124 capturing_ = false;
125 monitoring_ = false;
126 enable_rtx_ = false;
127
128 // Init the device manager immediately, and set up our default video device.
129 SignalDevicesChange.repeat(device_manager_->SignalDevicesChange);
130 device_manager_->Init();
131
132 // Camera is started asynchronously, request callbacks when startup
133 // completes to be able to forward them to the rendering manager.
134 media_engine_->SignalVideoCaptureStateChange().connect(
135 this, &ChannelManager::OnVideoCaptureStateChange);
136 capture_manager_->SignalCapturerStateChange.connect(
137 this, &ChannelManager::OnVideoCaptureStateChange);
138}
139
140ChannelManager::~ChannelManager() {
141 if (initialized_)
142 Terminate();
143}
144
145bool ChannelManager::SetVideoRtxEnabled(bool enable) {
146 // To be safe, this call is only allowed before initialization. Apps like
147 // Flute only have a singleton ChannelManager and we don't want this flag to
148 // be toggled between calls or when there's concurrent calls. We expect apps
149 // to enable this at startup and retain that setting for the lifetime of the
150 // app.
151 if (!initialized_) {
152 enable_rtx_ = enable;
153 return true;
154 } else {
155 LOG(LS_WARNING) << "Cannot toggle rtx after initialization!";
156 return false;
157 }
158}
159
160int ChannelManager::GetCapabilities() {
161 return media_engine_->GetCapabilities() & device_manager_->GetCapabilities();
162}
163
164void ChannelManager::GetSupportedAudioCodecs(
165 std::vector<AudioCodec>* codecs) const {
166 codecs->clear();
167
168 for (std::vector<AudioCodec>::const_iterator it =
169 media_engine_->audio_codecs().begin();
170 it != media_engine_->audio_codecs().end(); ++it) {
171 codecs->push_back(*it);
172 }
173}
174
175void ChannelManager::GetSupportedAudioRtpHeaderExtensions(
176 RtpHeaderExtensions* ext) const {
177 *ext = media_engine_->audio_rtp_header_extensions();
178}
179
180void ChannelManager::GetSupportedVideoCodecs(
181 std::vector<VideoCodec>* codecs) const {
182 codecs->clear();
183
184 std::vector<VideoCodec>::const_iterator it;
185 for (it = media_engine_->video_codecs().begin();
186 it != media_engine_->video_codecs().end(); ++it) {
187 if (!enable_rtx_ && _stricmp(kRtxCodecName, it->name.c_str()) == 0) {
188 continue;
189 }
190 codecs->push_back(*it);
191 }
192}
193
194void ChannelManager::GetSupportedVideoRtpHeaderExtensions(
195 RtpHeaderExtensions* ext) const {
196 *ext = media_engine_->video_rtp_header_extensions();
197}
198
199void ChannelManager::GetSupportedDataCodecs(
200 std::vector<DataCodec>* codecs) const {
201 *codecs = data_media_engine_->data_codecs();
202}
203
204bool ChannelManager::Init() {
205 ASSERT(!initialized_);
206 if (initialized_) {
207 return false;
208 }
209
210 ASSERT(worker_thread_ != NULL);
211 if (worker_thread_ && worker_thread_->started()) {
212 if (media_engine_->Init(worker_thread_)) {
213 initialized_ = true;
214
215 // Now that we're initialized, apply any stored preferences. A preferred
216 // device might have been unplugged. In this case, we fallback to the
217 // default device but keep the user preferences. The preferences are
218 // changed only when the Javascript FE changes them.
219 const std::string preferred_audio_in_device = audio_in_device_;
220 const std::string preferred_audio_out_device = audio_out_device_;
221 const std::string preferred_camera_device = camera_device_;
222 Device device;
223 if (!device_manager_->GetAudioInputDevice(audio_in_device_, &device)) {
224 LOG(LS_WARNING) << "The preferred microphone '" << audio_in_device_
225 << "' is unavailable. Fall back to the default.";
226 audio_in_device_ = DeviceManagerInterface::kDefaultDeviceName;
227 }
228 if (!device_manager_->GetAudioOutputDevice(audio_out_device_, &device)) {
229 LOG(LS_WARNING) << "The preferred speaker '" << audio_out_device_
230 << "' is unavailable. Fall back to the default.";
231 audio_out_device_ = DeviceManagerInterface::kDefaultDeviceName;
232 }
233 if (!device_manager_->GetVideoCaptureDevice(camera_device_, &device)) {
234 if (!camera_device_.empty()) {
235 LOG(LS_WARNING) << "The preferred camera '" << camera_device_
236 << "' is unavailable. Fall back to the default.";
237 }
238 camera_device_ = DeviceManagerInterface::kDefaultDeviceName;
239 }
240
241 if (!SetAudioOptions(audio_in_device_, audio_out_device_,
242 audio_options_, audio_delay_offset_)) {
243 LOG(LS_WARNING) << "Failed to SetAudioOptions with"
244 << " microphone: " << audio_in_device_
245 << " speaker: " << audio_out_device_
246 << " options: " << audio_options_
247 << " delay: " << audio_delay_offset_;
248 }
249
250 // If audio_output_volume_ has been set via SetOutputVolume(), set the
251 // audio output volume of the engine.
252 if (kNotSetOutputVolume != audio_output_volume_ &&
253 !SetOutputVolume(audio_output_volume_)) {
254 LOG(LS_WARNING) << "Failed to SetOutputVolume to "
255 << audio_output_volume_;
256 }
257 if (!SetCaptureDevice(camera_device_) && !camera_device_.empty()) {
258 LOG(LS_WARNING) << "Failed to SetCaptureDevice with camera: "
259 << camera_device_;
260 }
261
262 // Restore the user preferences.
263 audio_in_device_ = preferred_audio_in_device;
264 audio_out_device_ = preferred_audio_out_device;
265 camera_device_ = preferred_camera_device;
266
267 // Now apply the default video codec that has been set earlier.
268 if (default_video_encoder_config_.max_codec.id != 0) {
269 SetDefaultVideoEncoderConfig(default_video_encoder_config_);
270 }
271 // And the local renderer.
272 if (local_renderer_) {
273 SetLocalRenderer(local_renderer_);
274 }
275 }
276 }
277 return initialized_;
278}
279
280void ChannelManager::Terminate() {
281 ASSERT(initialized_);
282 if (!initialized_) {
283 return;
284 }
285 worker_thread_->Invoke<void>(Bind(&ChannelManager::Terminate_w, this));
286 media_engine_->Terminate();
287 initialized_ = false;
288}
289
290void ChannelManager::Terminate_w() {
291 ASSERT(worker_thread_ == talk_base::Thread::Current());
292 // Need to destroy the voice/video channels
293 while (!video_channels_.empty()) {
294 DestroyVideoChannel_w(video_channels_.back());
295 }
296 while (!voice_channels_.empty()) {
297 DestroyVoiceChannel_w(voice_channels_.back());
298 }
299 while (!soundclips_.empty()) {
300 DestroySoundclip_w(soundclips_.back());
301 }
302 if (!SetCaptureDevice_w(NULL)) {
303 LOG(LS_WARNING) << "failed to delete video capturer";
304 }
305}
306
307VoiceChannel* ChannelManager::CreateVoiceChannel(
308 BaseSession* session, const std::string& content_name, bool rtcp) {
309 return worker_thread_->Invoke<VoiceChannel*>(
310 Bind(&ChannelManager::CreateVoiceChannel_w, this,
311 session, content_name, rtcp));
312}
313
314VoiceChannel* ChannelManager::CreateVoiceChannel_w(
315 BaseSession* session, const std::string& content_name, bool rtcp) {
316 // This is ok to alloc from a thread other than the worker thread
317 ASSERT(initialized_);
318 VoiceMediaChannel* media_channel = media_engine_->CreateChannel();
319 if (media_channel == NULL)
320 return NULL;
321
322 VoiceChannel* voice_channel = new VoiceChannel(
323 worker_thread_, media_engine_.get(), media_channel,
324 session, content_name, rtcp);
325 if (!voice_channel->Init()) {
326 delete voice_channel;
327 return NULL;
328 }
329 voice_channels_.push_back(voice_channel);
330 return voice_channel;
331}
332
333void ChannelManager::DestroyVoiceChannel(VoiceChannel* voice_channel) {
334 if (voice_channel) {
335 worker_thread_->Invoke<void>(
336 Bind(&ChannelManager::DestroyVoiceChannel_w, this, voice_channel));
337 }
338}
339
340void ChannelManager::DestroyVoiceChannel_w(VoiceChannel* voice_channel) {
341 // Destroy voice channel.
342 ASSERT(initialized_);
343 VoiceChannels::iterator it = std::find(voice_channels_.begin(),
344 voice_channels_.end(), voice_channel);
345 ASSERT(it != voice_channels_.end());
346 if (it == voice_channels_.end())
347 return;
348
349 voice_channels_.erase(it);
350 delete voice_channel;
351}
352
353VideoChannel* ChannelManager::CreateVideoChannel(
354 BaseSession* session, const std::string& content_name, bool rtcp,
355 VoiceChannel* voice_channel) {
356 return worker_thread_->Invoke<VideoChannel*>(
357 Bind(&ChannelManager::CreateVideoChannel_w, this, session,
358 content_name, rtcp, voice_channel));
359}
360
361VideoChannel* ChannelManager::CreateVideoChannel_w(
362 BaseSession* session, const std::string& content_name, bool rtcp,
363 VoiceChannel* voice_channel) {
364 // This is ok to alloc from a thread other than the worker thread
365 ASSERT(initialized_);
366 VideoMediaChannel* media_channel =
367 // voice_channel can be NULL in case of NullVoiceEngine.
368 media_engine_->CreateVideoChannel(voice_channel ?
369 voice_channel->media_channel() : NULL);
370 if (media_channel == NULL)
371 return NULL;
372
373 VideoChannel* video_channel = new VideoChannel(
374 worker_thread_, media_engine_.get(), media_channel,
375 session, content_name, rtcp, voice_channel);
376 if (!video_channel->Init()) {
377 delete video_channel;
378 return NULL;
379 }
380 video_channels_.push_back(video_channel);
381 return video_channel;
382}
383
384void ChannelManager::DestroyVideoChannel(VideoChannel* video_channel) {
385 if (video_channel) {
386 worker_thread_->Invoke<void>(
387 Bind(&ChannelManager::DestroyVideoChannel_w, this, video_channel));
388 }
389}
390
391void ChannelManager::DestroyVideoChannel_w(VideoChannel* video_channel) {
392 // Destroy video channel.
393 ASSERT(initialized_);
394 VideoChannels::iterator it = std::find(video_channels_.begin(),
395 video_channels_.end(), video_channel);
396 ASSERT(it != video_channels_.end());
397 if (it == video_channels_.end())
398 return;
399
400 video_channels_.erase(it);
401 delete video_channel;
402}
403
404DataChannel* ChannelManager::CreateDataChannel(
405 BaseSession* session, const std::string& content_name,
406 bool rtcp, DataChannelType channel_type) {
407 return worker_thread_->Invoke<DataChannel*>(
408 Bind(&ChannelManager::CreateDataChannel_w, this, session, content_name,
409 rtcp, channel_type));
410}
411
412DataChannel* ChannelManager::CreateDataChannel_w(
413 BaseSession* session, const std::string& content_name,
414 bool rtcp, DataChannelType data_channel_type) {
415 // This is ok to alloc from a thread other than the worker thread.
416 ASSERT(initialized_);
417 DataMediaChannel* media_channel = data_media_engine_->CreateChannel(
418 data_channel_type);
419 if (!media_channel) {
420 LOG(LS_WARNING) << "Failed to create data channel of type "
421 << data_channel_type;
422 return NULL;
423 }
424
425 DataChannel* data_channel = new DataChannel(
426 worker_thread_, media_channel,
427 session, content_name, rtcp);
428 if (!data_channel->Init()) {
429 LOG(LS_WARNING) << "Failed to init data channel.";
430 delete data_channel;
431 return NULL;
432 }
433 data_channels_.push_back(data_channel);
434 return data_channel;
435}
436
437void ChannelManager::DestroyDataChannel(DataChannel* data_channel) {
438 if (data_channel) {
439 worker_thread_->Invoke<void>(
440 Bind(&ChannelManager::DestroyDataChannel_w, this, data_channel));
441 }
442}
443
444void ChannelManager::DestroyDataChannel_w(DataChannel* data_channel) {
445 // Destroy data channel.
446 ASSERT(initialized_);
447 DataChannels::iterator it = std::find(data_channels_.begin(),
448 data_channels_.end(), data_channel);
449 ASSERT(it != data_channels_.end());
450 if (it == data_channels_.end())
451 return;
452
453 data_channels_.erase(it);
454 delete data_channel;
455}
456
457Soundclip* ChannelManager::CreateSoundclip() {
458 return worker_thread_->Invoke<Soundclip*>(
459 Bind(&ChannelManager::CreateSoundclip_w, this));
460}
461
462Soundclip* ChannelManager::CreateSoundclip_w() {
463 ASSERT(initialized_);
464 ASSERT(worker_thread_ == talk_base::Thread::Current());
465
466 SoundclipMedia* soundclip_media = media_engine_->CreateSoundclip();
467 if (!soundclip_media) {
468 return NULL;
469 }
470
471 Soundclip* soundclip = new Soundclip(worker_thread_, soundclip_media);
472 soundclips_.push_back(soundclip);
473 return soundclip;
474}
475
476void ChannelManager::DestroySoundclip(Soundclip* soundclip) {
477 if (soundclip) {
478 worker_thread_->Invoke<void>(
479 Bind(&ChannelManager::DestroySoundclip_w, this, soundclip));
480 }
481}
482
483void ChannelManager::DestroySoundclip_w(Soundclip* soundclip) {
484 // Destroy soundclip.
485 ASSERT(initialized_);
486 Soundclips::iterator it = std::find(soundclips_.begin(),
487 soundclips_.end(), soundclip);
488 ASSERT(it != soundclips_.end());
489 if (it == soundclips_.end())
490 return;
491
492 soundclips_.erase(it);
493 delete soundclip;
494}
495
496bool ChannelManager::GetAudioOptions(std::string* in_name,
497 std::string* out_name, int* opts) {
498 if (in_name)
499 *in_name = audio_in_device_;
500 if (out_name)
501 *out_name = audio_out_device_;
502 if (opts)
503 *opts = audio_options_;
504 return true;
505}
506
507bool ChannelManager::SetAudioOptions(const std::string& in_name,
508 const std::string& out_name, int opts) {
509 return SetAudioOptions(in_name, out_name, opts, audio_delay_offset_);
510}
511
512bool ChannelManager::SetAudioOptions(const std::string& in_name,
513 const std::string& out_name, int opts,
514 int delay_offset) {
515 // Get device ids from DeviceManager.
516 Device in_dev, out_dev;
517 if (!device_manager_->GetAudioInputDevice(in_name, &in_dev)) {
518 LOG(LS_WARNING) << "Failed to GetAudioInputDevice: " << in_name;
519 return false;
520 }
521 if (!device_manager_->GetAudioOutputDevice(out_name, &out_dev)) {
522 LOG(LS_WARNING) << "Failed to GetAudioOutputDevice: " << out_name;
523 return false;
524 }
525
526 // If we're initialized, pass the settings to the media engine.
527 bool ret = true;
528 if (initialized_) {
529 ret = worker_thread_->Invoke<bool>(
530 Bind(&ChannelManager::SetAudioOptions_w, this,
531 opts, delay_offset, &in_dev, &out_dev));
532 }
533
534 // If all worked well, save the values for use in GetAudioOptions.
535 if (ret) {
536 audio_options_ = opts;
537 audio_in_device_ = in_name;
538 audio_out_device_ = out_name;
539 audio_delay_offset_ = delay_offset;
540 }
541 return ret;
542}
543
544bool ChannelManager::SetAudioOptions_w(int opts, int delay_offset,
545 const Device* in_dev, const Device* out_dev) {
546 ASSERT(worker_thread_ == talk_base::Thread::Current());
547 ASSERT(initialized_);
548
549 // Set audio options
550 bool ret = media_engine_->SetAudioOptions(opts);
551
552 if (ret) {
553 ret = media_engine_->SetAudioDelayOffset(delay_offset);
554 }
555
556 // Set the audio devices
557 if (ret) {
558 ret = media_engine_->SetSoundDevices(in_dev, out_dev);
559 }
560
561 return ret;
562}
563
564bool ChannelManager::GetOutputVolume(int* level) {
565 if (!initialized_) {
566 return false;
567 }
568 return worker_thread_->Invoke<bool>(
569 Bind(&MediaEngineInterface::GetOutputVolume, media_engine_.get(), level));
570}
571
572bool ChannelManager::SetOutputVolume(int level) {
573 bool ret = level >= 0 && level <= 255;
574 if (initialized_) {
575 ret &= worker_thread_->Invoke<bool>(
576 Bind(&MediaEngineInterface::SetOutputVolume,
577 media_engine_.get(), level));
578 }
579
580 if (ret) {
581 audio_output_volume_ = level;
582 }
583
584 return ret;
585}
586
587bool ChannelManager::IsSameCapturer(const std::string& capturer_name,
588 VideoCapturer* capturer) {
589 if (capturer == NULL) {
590 return false;
591 }
592 Device device;
593 if (!device_manager_->GetVideoCaptureDevice(capturer_name, &device)) {
594 return false;
595 }
596 return capturer->GetId() == device.id;
597}
598
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000599bool ChannelManager::GetVideoCaptureDevice(Device* device) {
600 std::string device_name;
601 if (!GetCaptureDevice(&device_name)) {
602 return false;
603 }
604 return device_manager_->GetVideoCaptureDevice(device_name, device);
605}
606
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000607bool ChannelManager::GetCaptureDevice(std::string* cam_name) {
608 if (camera_device_.empty()) {
609 // Initialize camera_device_ with default.
610 Device device;
611 if (!device_manager_->GetVideoCaptureDevice(
612 DeviceManagerInterface::kDefaultDeviceName, &device)) {
613 LOG(LS_WARNING) << "Device manager can't find default camera: " <<
614 DeviceManagerInterface::kDefaultDeviceName;
615 return false;
616 }
617 camera_device_ = device.name;
618 }
619 *cam_name = camera_device_;
620 return true;
621}
622
623bool ChannelManager::SetCaptureDevice(const std::string& cam_name) {
624 Device device;
625 bool ret = true;
626 if (!device_manager_->GetVideoCaptureDevice(cam_name, &device)) {
627 if (!cam_name.empty()) {
628 LOG(LS_WARNING) << "Device manager can't find camera: " << cam_name;
629 }
630 ret = false;
631 }
632
633 // If we're running, tell the media engine about it.
634 if (initialized_ && ret) {
635 ret = worker_thread_->Invoke<bool>(
636 Bind(&ChannelManager::SetCaptureDevice_w, this, &device));
637 }
638
639 // If everything worked, retain the name of the selected camera.
640 if (ret) {
641 camera_device_ = device.name;
642 } else if (camera_device_.empty()) {
643 // When video option setting fails, we still want camera_device_ to be in a
644 // good state, so we initialize it with default if it's empty.
645 Device default_device;
646 if (!device_manager_->GetVideoCaptureDevice(
647 DeviceManagerInterface::kDefaultDeviceName, &default_device)) {
648 LOG(LS_WARNING) << "Device manager can't find default camera: " <<
649 DeviceManagerInterface::kDefaultDeviceName;
650 }
651 camera_device_ = default_device.name;
652 }
653
654 return ret;
655}
656
657VideoCapturer* ChannelManager::CreateVideoCapturer() {
658 Device device;
659 if (!device_manager_->GetVideoCaptureDevice(camera_device_, &device)) {
660 if (!camera_device_.empty()) {
661 LOG(LS_WARNING) << "Device manager can't find camera: " << camera_device_;
662 }
663 return NULL;
664 }
665 return device_manager_->CreateVideoCapturer(device);
666}
667
668bool ChannelManager::SetCaptureDevice_w(const Device* cam_device) {
669 ASSERT(worker_thread_ == talk_base::Thread::Current());
670 ASSERT(initialized_);
671
672 if (!cam_device) {
673 video_device_name_.clear();
674 return true;
675 }
676 video_device_name_ = cam_device->name;
677 return true;
678}
679
680bool ChannelManager::SetDefaultVideoEncoderConfig(const VideoEncoderConfig& c) {
681 bool ret = true;
682 if (initialized_) {
683 ret = worker_thread_->Invoke<bool>(
684 Bind(&MediaEngineInterface::SetDefaultVideoEncoderConfig,
685 media_engine_.get(), c));
686 }
687 if (ret) {
688 default_video_encoder_config_ = c;
689 }
690 return ret;
691}
692
693bool ChannelManager::SetLocalMonitor(bool enable) {
694 bool ret = initialized_ && worker_thread_->Invoke<bool>(
695 Bind(&MediaEngineInterface::SetLocalMonitor,
696 media_engine_.get(), enable));
697 if (ret) {
698 monitoring_ = enable;
699 }
700 return ret;
701}
702
703bool ChannelManager::SetLocalRenderer(VideoRenderer* renderer) {
704 bool ret = true;
705 if (initialized_) {
706 ret = worker_thread_->Invoke<bool>(
707 Bind(&MediaEngineInterface::SetLocalRenderer,
708 media_engine_.get(), renderer));
709 }
710 if (ret) {
711 local_renderer_ = renderer;
712 }
713 return ret;
714}
715
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000716void ChannelManager::SetVoiceLogging(int level, const char* filter) {
717 if (initialized_) {
718 worker_thread_->Invoke<void>(
719 Bind(&MediaEngineInterface::SetVoiceLogging,
720 media_engine_.get(), level, filter));
721 } else {
722 media_engine_->SetVoiceLogging(level, filter);
723 }
724}
725
726void ChannelManager::SetVideoLogging(int level, const char* filter) {
727 if (initialized_) {
728 worker_thread_->Invoke<void>(
729 Bind(&MediaEngineInterface::SetVideoLogging,
730 media_engine_.get(), level, filter));
731 } else {
732 media_engine_->SetVideoLogging(level, filter);
733 }
734}
735
736// TODO(janahan): For now pass this request through the mediaengine to the
737// voice and video engines to do the real work. Once the capturer refactoring
738// is done, we will access the capturer using the ssrc (similar to how the
739// renderer is accessed today) and register with it directly.
740bool ChannelManager::RegisterVideoProcessor(VideoCapturer* capturer,
741 VideoProcessor* processor) {
742 return initialized_ && worker_thread_->Invoke<bool>(
743 Bind(&ChannelManager::RegisterVideoProcessor_w, this,
744 capturer, processor));
745}
746
747bool ChannelManager::RegisterVideoProcessor_w(VideoCapturer* capturer,
748 VideoProcessor* processor) {
749 return capture_manager_->AddVideoProcessor(capturer, processor);
750}
751
752bool ChannelManager::UnregisterVideoProcessor(VideoCapturer* capturer,
753 VideoProcessor* processor) {
754 return initialized_ && worker_thread_->Invoke<bool>(
755 Bind(&ChannelManager::UnregisterVideoProcessor_w, this,
756 capturer, processor));
757}
758
759bool ChannelManager::UnregisterVideoProcessor_w(VideoCapturer* capturer,
760 VideoProcessor* processor) {
761 return capture_manager_->RemoveVideoProcessor(capturer, processor);
762}
763
764bool ChannelManager::RegisterVoiceProcessor(
765 uint32 ssrc,
766 VoiceProcessor* processor,
767 MediaProcessorDirection direction) {
768 return initialized_ && worker_thread_->Invoke<bool>(
769 Bind(&MediaEngineInterface::RegisterVoiceProcessor, media_engine_.get(),
770 ssrc, processor, direction));
771}
772
773bool ChannelManager::UnregisterVoiceProcessor(
774 uint32 ssrc,
775 VoiceProcessor* processor,
776 MediaProcessorDirection direction) {
777 return initialized_ && worker_thread_->Invoke<bool>(
778 Bind(&MediaEngineInterface::UnregisterVoiceProcessor,
779 media_engine_.get(), ssrc, processor, direction));
780}
781
782// The following are done in the new "CaptureManager" style that
783// all local video capturers, processors, and managers should move
784// to.
785// TODO(pthatcher): Add more of the CaptureManager interface.
786bool ChannelManager::StartVideoCapture(
787 VideoCapturer* capturer, const VideoFormat& video_format) {
788 return initialized_ && worker_thread_->Invoke<bool>(
789 Bind(&CaptureManager::StartVideoCapture,
790 capture_manager_.get(), capturer, video_format));
791}
792
793bool ChannelManager::MuteToBlackThenPause(
794 VideoCapturer* video_capturer, bool muted) {
795 if (!initialized_) {
796 return false;
797 }
798 worker_thread_->Invoke<void>(
799 Bind(&VideoCapturer::MuteToBlackThenPause, video_capturer, muted));
800 return true;
801}
802
803bool ChannelManager::StopVideoCapture(
804 VideoCapturer* capturer, const VideoFormat& video_format) {
805 return initialized_ && worker_thread_->Invoke<bool>(
806 Bind(&CaptureManager::StopVideoCapture,
807 capture_manager_.get(), capturer, video_format));
808}
809
810bool ChannelManager::RestartVideoCapture(
811 VideoCapturer* video_capturer,
812 const VideoFormat& previous_format,
813 const VideoFormat& desired_format,
814 CaptureManager::RestartOptions options) {
815 return initialized_ && worker_thread_->Invoke<bool>(
816 Bind(&CaptureManager::RestartVideoCapture, capture_manager_.get(),
817 video_capturer, previous_format, desired_format, options));
818}
819
820bool ChannelManager::AddVideoRenderer(
821 VideoCapturer* capturer, VideoRenderer* renderer) {
822 return initialized_ && worker_thread_->Invoke<bool>(
823 Bind(&CaptureManager::AddVideoRenderer,
824 capture_manager_.get(), capturer, renderer));
825}
826
827bool ChannelManager::RemoveVideoRenderer(
828 VideoCapturer* capturer, VideoRenderer* renderer) {
829 return initialized_ && worker_thread_->Invoke<bool>(
830 Bind(&CaptureManager::RemoveVideoRenderer,
831 capture_manager_.get(), capturer, renderer));
832}
833
834bool ChannelManager::IsScreencastRunning() const {
835 return initialized_ && worker_thread_->Invoke<bool>(
836 Bind(&ChannelManager::IsScreencastRunning_w, this));
837}
838
839bool ChannelManager::IsScreencastRunning_w() const {
840 VideoChannels::const_iterator it = video_channels_.begin();
841 for ( ; it != video_channels_.end(); ++it) {
842 if ((*it) && (*it)->IsScreencasting()) {
843 return true;
844 }
845 }
846 return false;
847}
848
849void ChannelManager::OnVideoCaptureStateChange(VideoCapturer* capturer,
850 CaptureState result) {
851 // TODO(whyuan): Check capturer and signal failure only for camera video, not
852 // screencast.
853 capturing_ = result == CS_RUNNING;
854 main_thread_->Post(this, MSG_VIDEOCAPTURESTATE,
855 new CaptureStateParams(capturer, result));
856}
857
858void ChannelManager::OnMessage(talk_base::Message* message) {
859 switch (message->message_id) {
860 case MSG_VIDEOCAPTURESTATE: {
861 CaptureStateParams* data =
862 static_cast<CaptureStateParams*>(message->pdata);
863 SignalVideoCaptureStateChange(data->capturer, data->state);
864 delete data;
865 break;
866 }
867 }
868}
869
870
871static void GetDeviceNames(const std::vector<Device>& devs,
872 std::vector<std::string>* names) {
873 names->clear();
874 for (size_t i = 0; i < devs.size(); ++i) {
875 names->push_back(devs[i].name);
876 }
877}
878
879bool ChannelManager::GetAudioInputDevices(std::vector<std::string>* names) {
880 names->clear();
881 std::vector<Device> devs;
882 bool ret = device_manager_->GetAudioInputDevices(&devs);
883 if (ret)
884 GetDeviceNames(devs, names);
885
886 return ret;
887}
888
889bool ChannelManager::GetAudioOutputDevices(std::vector<std::string>* names) {
890 names->clear();
891 std::vector<Device> devs;
892 bool ret = device_manager_->GetAudioOutputDevices(&devs);
893 if (ret)
894 GetDeviceNames(devs, names);
895
896 return ret;
897}
898
899bool ChannelManager::GetVideoCaptureDevices(std::vector<std::string>* names) {
900 names->clear();
901 std::vector<Device> devs;
902 bool ret = device_manager_->GetVideoCaptureDevices(&devs);
903 if (ret)
904 GetDeviceNames(devs, names);
905
906 return ret;
907}
908
909void ChannelManager::SetVideoCaptureDeviceMaxFormat(
910 const std::string& usb_id,
911 const VideoFormat& max_format) {
912 device_manager_->SetVideoCaptureDeviceMaxFormat(usb_id, max_format);
913}
914
915VideoFormat ChannelManager::GetStartCaptureFormat() {
916 return worker_thread_->Invoke<VideoFormat>(
917 Bind(&MediaEngineInterface::GetStartCaptureFormat, media_engine_.get()));
918}
919
920} // namespace cricket