blob: 3461a9c10ac6c4bc956d649af99dd18663b3195d [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"
wu@webrtc.org9dba5252013-08-05 20:36:57 +000051#include "talk/session/media/srtpfilter.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000052
53namespace cricket {
54
55enum {
56 MSG_VIDEOCAPTURESTATE = 1,
57};
58
59using talk_base::Bind;
60
61static const int kNotSetOutputVolume = -1;
62
63struct CaptureStateParams : public talk_base::MessageData {
64 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)
80ChannelManager::ChannelManager(talk_base::Thread* worker_thread) {
81 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,
93 talk_base::Thread* worker_thread) {
94 Construct(me, dme, dm, cm, worker_thread);
95}
96
97ChannelManager::ChannelManager(MediaEngineInterface* me,
98 DeviceManagerInterface* dm,
99 talk_base::Thread* worker_thread) {
100 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,
111 talk_base::Thread* worker_thread) {
112 media_engine_.reset(me);
113 data_media_engine_.reset(dme);
114 device_manager_.reset(dm);
115 capture_manager_.reset(cm);
116 initialized_ = false;
117 main_thread_ = talk_base::Thread::Current();
118 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.org28e20752013-07-10 00:45:36 +0000123 audio_delay_offset_ = MediaEngineInterface::kDefaultAudioDelayOffset;
124 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);
fischman@webrtc.orge5063b12014-05-23 17:28:50 +0000220 ASSERT(worker_thread_->RunningForChannelManager());
221 // TODO(fischman): remove the if below (and
222 // Thread::RunningForChannelManager()) once the ASSERT above has stuck for a
223 // month (2014/06/22).
224 if (worker_thread_ && worker_thread_->RunningForChannelManager()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000225 if (media_engine_->Init(worker_thread_)) {
226 initialized_ = true;
227
228 // Now that we're initialized, apply any stored preferences. A preferred
229 // device might have been unplugged. In this case, we fallback to the
230 // default device but keep the user preferences. The preferences are
231 // changed only when the Javascript FE changes them.
232 const std::string preferred_audio_in_device = audio_in_device_;
233 const std::string preferred_audio_out_device = audio_out_device_;
234 const std::string preferred_camera_device = camera_device_;
235 Device device;
236 if (!device_manager_->GetAudioInputDevice(audio_in_device_, &device)) {
237 LOG(LS_WARNING) << "The preferred microphone '" << audio_in_device_
238 << "' is unavailable. Fall back to the default.";
239 audio_in_device_ = DeviceManagerInterface::kDefaultDeviceName;
240 }
241 if (!device_manager_->GetAudioOutputDevice(audio_out_device_, &device)) {
242 LOG(LS_WARNING) << "The preferred speaker '" << audio_out_device_
243 << "' is unavailable. Fall back to the default.";
244 audio_out_device_ = DeviceManagerInterface::kDefaultDeviceName;
245 }
246 if (!device_manager_->GetVideoCaptureDevice(camera_device_, &device)) {
247 if (!camera_device_.empty()) {
248 LOG(LS_WARNING) << "The preferred camera '" << camera_device_
249 << "' is unavailable. Fall back to the default.";
250 }
251 camera_device_ = DeviceManagerInterface::kDefaultDeviceName;
252 }
253
254 if (!SetAudioOptions(audio_in_device_, audio_out_device_,
255 audio_options_, audio_delay_offset_)) {
256 LOG(LS_WARNING) << "Failed to SetAudioOptions with"
257 << " microphone: " << audio_in_device_
258 << " speaker: " << audio_out_device_
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000259 << " options: " << audio_options_.ToString()
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000260 << " delay: " << audio_delay_offset_;
261 }
262
263 // If audio_output_volume_ has been set via SetOutputVolume(), set the
264 // audio output volume of the engine.
265 if (kNotSetOutputVolume != audio_output_volume_ &&
266 !SetOutputVolume(audio_output_volume_)) {
267 LOG(LS_WARNING) << "Failed to SetOutputVolume to "
268 << audio_output_volume_;
269 }
270 if (!SetCaptureDevice(camera_device_) && !camera_device_.empty()) {
271 LOG(LS_WARNING) << "Failed to SetCaptureDevice with camera: "
272 << camera_device_;
273 }
274
275 // Restore the user preferences.
276 audio_in_device_ = preferred_audio_in_device;
277 audio_out_device_ = preferred_audio_out_device;
278 camera_device_ = preferred_camera_device;
279
280 // Now apply the default video codec that has been set earlier.
281 if (default_video_encoder_config_.max_codec.id != 0) {
282 SetDefaultVideoEncoderConfig(default_video_encoder_config_);
283 }
284 // And the local renderer.
285 if (local_renderer_) {
286 SetLocalRenderer(local_renderer_);
287 }
288 }
289 }
290 return initialized_;
291}
292
293void ChannelManager::Terminate() {
294 ASSERT(initialized_);
295 if (!initialized_) {
296 return;
297 }
298 worker_thread_->Invoke<void>(Bind(&ChannelManager::Terminate_w, this));
299 media_engine_->Terminate();
300 initialized_ = false;
301}
302
303void ChannelManager::Terminate_w() {
304 ASSERT(worker_thread_ == talk_base::Thread::Current());
305 // Need to destroy the voice/video channels
306 while (!video_channels_.empty()) {
307 DestroyVideoChannel_w(video_channels_.back());
308 }
309 while (!voice_channels_.empty()) {
310 DestroyVoiceChannel_w(voice_channels_.back());
311 }
312 while (!soundclips_.empty()) {
313 DestroySoundclip_w(soundclips_.back());
314 }
315 if (!SetCaptureDevice_w(NULL)) {
316 LOG(LS_WARNING) << "failed to delete video capturer";
317 }
318}
319
320VoiceChannel* ChannelManager::CreateVoiceChannel(
321 BaseSession* session, const std::string& content_name, bool rtcp) {
322 return worker_thread_->Invoke<VoiceChannel*>(
323 Bind(&ChannelManager::CreateVoiceChannel_w, this,
324 session, content_name, rtcp));
325}
326
327VoiceChannel* ChannelManager::CreateVoiceChannel_w(
328 BaseSession* session, const std::string& content_name, bool rtcp) {
329 // This is ok to alloc from a thread other than the worker thread
330 ASSERT(initialized_);
331 VoiceMediaChannel* media_channel = media_engine_->CreateChannel();
332 if (media_channel == NULL)
333 return NULL;
334
335 VoiceChannel* voice_channel = new VoiceChannel(
336 worker_thread_, media_engine_.get(), media_channel,
337 session, content_name, rtcp);
338 if (!voice_channel->Init()) {
339 delete voice_channel;
340 return NULL;
341 }
342 voice_channels_.push_back(voice_channel);
343 return voice_channel;
344}
345
346void ChannelManager::DestroyVoiceChannel(VoiceChannel* voice_channel) {
347 if (voice_channel) {
348 worker_thread_->Invoke<void>(
349 Bind(&ChannelManager::DestroyVoiceChannel_w, this, voice_channel));
350 }
351}
352
353void ChannelManager::DestroyVoiceChannel_w(VoiceChannel* voice_channel) {
354 // Destroy voice channel.
355 ASSERT(initialized_);
356 VoiceChannels::iterator it = std::find(voice_channels_.begin(),
357 voice_channels_.end(), voice_channel);
358 ASSERT(it != voice_channels_.end());
359 if (it == voice_channels_.end())
360 return;
361
362 voice_channels_.erase(it);
363 delete voice_channel;
364}
365
366VideoChannel* ChannelManager::CreateVideoChannel(
367 BaseSession* session, const std::string& content_name, bool rtcp,
368 VoiceChannel* voice_channel) {
369 return worker_thread_->Invoke<VideoChannel*>(
370 Bind(&ChannelManager::CreateVideoChannel_w, this, session,
371 content_name, rtcp, voice_channel));
372}
373
374VideoChannel* ChannelManager::CreateVideoChannel_w(
375 BaseSession* session, const std::string& content_name, bool rtcp,
376 VoiceChannel* voice_channel) {
377 // This is ok to alloc from a thread other than the worker thread
378 ASSERT(initialized_);
379 VideoMediaChannel* media_channel =
380 // voice_channel can be NULL in case of NullVoiceEngine.
381 media_engine_->CreateVideoChannel(voice_channel ?
382 voice_channel->media_channel() : NULL);
383 if (media_channel == NULL)
384 return NULL;
385
386 VideoChannel* video_channel = new VideoChannel(
387 worker_thread_, media_engine_.get(), media_channel,
388 session, content_name, rtcp, voice_channel);
389 if (!video_channel->Init()) {
390 delete video_channel;
391 return NULL;
392 }
393 video_channels_.push_back(video_channel);
394 return video_channel;
395}
396
397void ChannelManager::DestroyVideoChannel(VideoChannel* video_channel) {
398 if (video_channel) {
399 worker_thread_->Invoke<void>(
400 Bind(&ChannelManager::DestroyVideoChannel_w, this, video_channel));
401 }
402}
403
404void ChannelManager::DestroyVideoChannel_w(VideoChannel* video_channel) {
405 // Destroy video channel.
406 ASSERT(initialized_);
407 VideoChannels::iterator it = std::find(video_channels_.begin(),
408 video_channels_.end(), video_channel);
409 ASSERT(it != video_channels_.end());
410 if (it == video_channels_.end())
411 return;
412
413 video_channels_.erase(it);
414 delete video_channel;
415}
416
417DataChannel* ChannelManager::CreateDataChannel(
418 BaseSession* session, const std::string& content_name,
419 bool rtcp, DataChannelType channel_type) {
420 return worker_thread_->Invoke<DataChannel*>(
421 Bind(&ChannelManager::CreateDataChannel_w, this, session, content_name,
422 rtcp, channel_type));
423}
424
425DataChannel* ChannelManager::CreateDataChannel_w(
426 BaseSession* session, const std::string& content_name,
427 bool rtcp, DataChannelType data_channel_type) {
428 // This is ok to alloc from a thread other than the worker thread.
429 ASSERT(initialized_);
430 DataMediaChannel* media_channel = data_media_engine_->CreateChannel(
431 data_channel_type);
432 if (!media_channel) {
433 LOG(LS_WARNING) << "Failed to create data channel of type "
434 << data_channel_type;
435 return NULL;
436 }
437
438 DataChannel* data_channel = new DataChannel(
439 worker_thread_, media_channel,
440 session, content_name, rtcp);
441 if (!data_channel->Init()) {
442 LOG(LS_WARNING) << "Failed to init data channel.";
443 delete data_channel;
444 return NULL;
445 }
446 data_channels_.push_back(data_channel);
447 return data_channel;
448}
449
450void ChannelManager::DestroyDataChannel(DataChannel* data_channel) {
451 if (data_channel) {
452 worker_thread_->Invoke<void>(
453 Bind(&ChannelManager::DestroyDataChannel_w, this, data_channel));
454 }
455}
456
457void ChannelManager::DestroyDataChannel_w(DataChannel* data_channel) {
458 // Destroy data channel.
459 ASSERT(initialized_);
460 DataChannels::iterator it = std::find(data_channels_.begin(),
461 data_channels_.end(), data_channel);
462 ASSERT(it != data_channels_.end());
463 if (it == data_channels_.end())
464 return;
465
466 data_channels_.erase(it);
467 delete data_channel;
468}
469
470Soundclip* ChannelManager::CreateSoundclip() {
471 return worker_thread_->Invoke<Soundclip*>(
472 Bind(&ChannelManager::CreateSoundclip_w, this));
473}
474
475Soundclip* ChannelManager::CreateSoundclip_w() {
476 ASSERT(initialized_);
477 ASSERT(worker_thread_ == talk_base::Thread::Current());
478
479 SoundclipMedia* soundclip_media = media_engine_->CreateSoundclip();
480 if (!soundclip_media) {
481 return NULL;
482 }
483
484 Soundclip* soundclip = new Soundclip(worker_thread_, soundclip_media);
485 soundclips_.push_back(soundclip);
486 return soundclip;
487}
488
489void ChannelManager::DestroySoundclip(Soundclip* soundclip) {
490 if (soundclip) {
491 worker_thread_->Invoke<void>(
492 Bind(&ChannelManager::DestroySoundclip_w, this, soundclip));
493 }
494}
495
496void ChannelManager::DestroySoundclip_w(Soundclip* soundclip) {
497 // Destroy soundclip.
498 ASSERT(initialized_);
499 Soundclips::iterator it = std::find(soundclips_.begin(),
500 soundclips_.end(), soundclip);
501 ASSERT(it != soundclips_.end());
502 if (it == soundclips_.end())
503 return;
504
505 soundclips_.erase(it);
506 delete soundclip;
507}
508
509bool ChannelManager::GetAudioOptions(std::string* in_name,
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000510 std::string* out_name,
511 AudioOptions* options) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000512 if (in_name)
513 *in_name = audio_in_device_;
514 if (out_name)
515 *out_name = audio_out_device_;
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000516 if (options)
517 *options = audio_options_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000518 return true;
519}
520
521bool ChannelManager::SetAudioOptions(const std::string& in_name,
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000522 const std::string& out_name,
523 const AudioOptions& options) {
524 return SetAudioOptions(in_name, out_name, options, audio_delay_offset_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000525}
526
527bool ChannelManager::SetAudioOptions(const std::string& in_name,
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000528 const std::string& out_name,
529 const AudioOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000530 int delay_offset) {
531 // Get device ids from DeviceManager.
532 Device in_dev, out_dev;
533 if (!device_manager_->GetAudioInputDevice(in_name, &in_dev)) {
534 LOG(LS_WARNING) << "Failed to GetAudioInputDevice: " << in_name;
535 return false;
536 }
537 if (!device_manager_->GetAudioOutputDevice(out_name, &out_dev)) {
538 LOG(LS_WARNING) << "Failed to GetAudioOutputDevice: " << out_name;
539 return false;
540 }
541
542 // If we're initialized, pass the settings to the media engine.
543 bool ret = true;
544 if (initialized_) {
545 ret = worker_thread_->Invoke<bool>(
546 Bind(&ChannelManager::SetAudioOptions_w, this,
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000547 options, delay_offset, &in_dev, &out_dev));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000548 }
549
550 // If all worked well, save the values for use in GetAudioOptions.
551 if (ret) {
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000552 audio_options_ = options;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000553 audio_in_device_ = in_name;
554 audio_out_device_ = out_name;
555 audio_delay_offset_ = delay_offset;
556 }
557 return ret;
558}
559
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000560bool ChannelManager::SetAudioOptions_w(
561 const AudioOptions& options, int delay_offset,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000562 const Device* in_dev, const Device* out_dev) {
563 ASSERT(worker_thread_ == talk_base::Thread::Current());
564 ASSERT(initialized_);
565
566 // Set audio options
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000567 bool ret = media_engine_->SetAudioOptions(options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000568
569 if (ret) {
570 ret = media_engine_->SetAudioDelayOffset(delay_offset);
571 }
572
573 // Set the audio devices
574 if (ret) {
575 ret = media_engine_->SetSoundDevices(in_dev, out_dev);
576 }
577
578 return ret;
579}
580
581bool ChannelManager::GetOutputVolume(int* level) {
582 if (!initialized_) {
583 return false;
584 }
585 return worker_thread_->Invoke<bool>(
586 Bind(&MediaEngineInterface::GetOutputVolume, media_engine_.get(), level));
587}
588
589bool ChannelManager::SetOutputVolume(int level) {
590 bool ret = level >= 0 && level <= 255;
591 if (initialized_) {
592 ret &= worker_thread_->Invoke<bool>(
593 Bind(&MediaEngineInterface::SetOutputVolume,
594 media_engine_.get(), level));
595 }
596
597 if (ret) {
598 audio_output_volume_ = level;
599 }
600
601 return ret;
602}
603
604bool ChannelManager::IsSameCapturer(const std::string& capturer_name,
605 VideoCapturer* capturer) {
606 if (capturer == NULL) {
607 return false;
608 }
609 Device device;
610 if (!device_manager_->GetVideoCaptureDevice(capturer_name, &device)) {
611 return false;
612 }
613 return capturer->GetId() == device.id;
614}
615
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000616bool ChannelManager::GetVideoCaptureDevice(Device* device) {
617 std::string device_name;
618 if (!GetCaptureDevice(&device_name)) {
619 return false;
620 }
621 return device_manager_->GetVideoCaptureDevice(device_name, device);
622}
623
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000624bool ChannelManager::GetCaptureDevice(std::string* cam_name) {
625 if (camera_device_.empty()) {
626 // Initialize camera_device_ with default.
627 Device device;
628 if (!device_manager_->GetVideoCaptureDevice(
629 DeviceManagerInterface::kDefaultDeviceName, &device)) {
630 LOG(LS_WARNING) << "Device manager can't find default camera: " <<
631 DeviceManagerInterface::kDefaultDeviceName;
632 return false;
633 }
634 camera_device_ = device.name;
635 }
636 *cam_name = camera_device_;
637 return true;
638}
639
640bool ChannelManager::SetCaptureDevice(const std::string& cam_name) {
641 Device device;
642 bool ret = true;
643 if (!device_manager_->GetVideoCaptureDevice(cam_name, &device)) {
644 if (!cam_name.empty()) {
645 LOG(LS_WARNING) << "Device manager can't find camera: " << cam_name;
646 }
647 ret = false;
648 }
649
650 // If we're running, tell the media engine about it.
651 if (initialized_ && ret) {
652 ret = worker_thread_->Invoke<bool>(
653 Bind(&ChannelManager::SetCaptureDevice_w, this, &device));
654 }
655
656 // If everything worked, retain the name of the selected camera.
657 if (ret) {
658 camera_device_ = device.name;
659 } else if (camera_device_.empty()) {
660 // When video option setting fails, we still want camera_device_ to be in a
661 // good state, so we initialize it with default if it's empty.
662 Device default_device;
663 if (!device_manager_->GetVideoCaptureDevice(
664 DeviceManagerInterface::kDefaultDeviceName, &default_device)) {
665 LOG(LS_WARNING) << "Device manager can't find default camera: " <<
666 DeviceManagerInterface::kDefaultDeviceName;
667 }
668 camera_device_ = default_device.name;
669 }
670
671 return ret;
672}
673
674VideoCapturer* ChannelManager::CreateVideoCapturer() {
675 Device device;
676 if (!device_manager_->GetVideoCaptureDevice(camera_device_, &device)) {
677 if (!camera_device_.empty()) {
678 LOG(LS_WARNING) << "Device manager can't find camera: " << camera_device_;
679 }
680 return NULL;
681 }
sergeyu@chromium.orga59696b2013-09-13 23:48:58 +0000682 VideoCapturer* capturer = device_manager_->CreateVideoCapturer(device);
683 if (capturer && default_video_encoder_config_.max_codec.id != 0) {
684 // For now, use the aspect ratio of the default_video_encoder_config_,
685 // which may be different than the native aspect ratio of the start
686 // format the camera may use.
687 capturer->UpdateAspectRatio(
688 default_video_encoder_config_.max_codec.width,
689 default_video_encoder_config_.max_codec.height);
690 }
691 return capturer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000692}
693
694bool ChannelManager::SetCaptureDevice_w(const Device* cam_device) {
695 ASSERT(worker_thread_ == talk_base::Thread::Current());
696 ASSERT(initialized_);
697
698 if (!cam_device) {
699 video_device_name_.clear();
700 return true;
701 }
702 video_device_name_ = cam_device->name;
703 return true;
704}
705
706bool ChannelManager::SetDefaultVideoEncoderConfig(const VideoEncoderConfig& c) {
707 bool ret = true;
708 if (initialized_) {
709 ret = worker_thread_->Invoke<bool>(
710 Bind(&MediaEngineInterface::SetDefaultVideoEncoderConfig,
711 media_engine_.get(), c));
712 }
713 if (ret) {
714 default_video_encoder_config_ = c;
715 }
716 return ret;
717}
718
719bool ChannelManager::SetLocalMonitor(bool enable) {
720 bool ret = initialized_ && worker_thread_->Invoke<bool>(
721 Bind(&MediaEngineInterface::SetLocalMonitor,
722 media_engine_.get(), enable));
723 if (ret) {
724 monitoring_ = enable;
725 }
726 return ret;
727}
728
729bool ChannelManager::SetLocalRenderer(VideoRenderer* renderer) {
730 bool ret = true;
731 if (initialized_) {
732 ret = worker_thread_->Invoke<bool>(
733 Bind(&MediaEngineInterface::SetLocalRenderer,
734 media_engine_.get(), renderer));
735 }
736 if (ret) {
737 local_renderer_ = renderer;
738 }
739 return ret;
740}
741
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000742void ChannelManager::SetVoiceLogging(int level, const char* filter) {
743 if (initialized_) {
744 worker_thread_->Invoke<void>(
745 Bind(&MediaEngineInterface::SetVoiceLogging,
746 media_engine_.get(), level, filter));
747 } else {
748 media_engine_->SetVoiceLogging(level, filter);
749 }
750}
751
752void ChannelManager::SetVideoLogging(int level, const char* filter) {
753 if (initialized_) {
754 worker_thread_->Invoke<void>(
755 Bind(&MediaEngineInterface::SetVideoLogging,
756 media_engine_.get(), level, filter));
757 } else {
758 media_engine_->SetVideoLogging(level, filter);
759 }
760}
761
762// TODO(janahan): For now pass this request through the mediaengine to the
763// voice and video engines to do the real work. Once the capturer refactoring
764// is done, we will access the capturer using the ssrc (similar to how the
765// renderer is accessed today) and register with it directly.
766bool ChannelManager::RegisterVideoProcessor(VideoCapturer* capturer,
767 VideoProcessor* processor) {
768 return initialized_ && worker_thread_->Invoke<bool>(
769 Bind(&ChannelManager::RegisterVideoProcessor_w, this,
770 capturer, processor));
771}
772
773bool ChannelManager::RegisterVideoProcessor_w(VideoCapturer* capturer,
774 VideoProcessor* processor) {
775 return capture_manager_->AddVideoProcessor(capturer, processor);
776}
777
778bool ChannelManager::UnregisterVideoProcessor(VideoCapturer* capturer,
779 VideoProcessor* processor) {
780 return initialized_ && worker_thread_->Invoke<bool>(
781 Bind(&ChannelManager::UnregisterVideoProcessor_w, this,
782 capturer, processor));
783}
784
785bool ChannelManager::UnregisterVideoProcessor_w(VideoCapturer* capturer,
786 VideoProcessor* processor) {
787 return capture_manager_->RemoveVideoProcessor(capturer, processor);
788}
789
790bool ChannelManager::RegisterVoiceProcessor(
791 uint32 ssrc,
792 VoiceProcessor* processor,
793 MediaProcessorDirection direction) {
794 return initialized_ && worker_thread_->Invoke<bool>(
795 Bind(&MediaEngineInterface::RegisterVoiceProcessor, media_engine_.get(),
796 ssrc, processor, direction));
797}
798
799bool ChannelManager::UnregisterVoiceProcessor(
800 uint32 ssrc,
801 VoiceProcessor* processor,
802 MediaProcessorDirection direction) {
803 return initialized_ && worker_thread_->Invoke<bool>(
804 Bind(&MediaEngineInterface::UnregisterVoiceProcessor,
805 media_engine_.get(), ssrc, processor, direction));
806}
807
808// The following are done in the new "CaptureManager" style that
809// all local video capturers, processors, and managers should move
810// to.
811// TODO(pthatcher): Add more of the CaptureManager interface.
812bool ChannelManager::StartVideoCapture(
813 VideoCapturer* capturer, const VideoFormat& video_format) {
814 return initialized_ && worker_thread_->Invoke<bool>(
815 Bind(&CaptureManager::StartVideoCapture,
816 capture_manager_.get(), capturer, video_format));
817}
818
819bool ChannelManager::MuteToBlackThenPause(
820 VideoCapturer* video_capturer, bool muted) {
821 if (!initialized_) {
822 return false;
823 }
824 worker_thread_->Invoke<void>(
825 Bind(&VideoCapturer::MuteToBlackThenPause, video_capturer, muted));
826 return true;
827}
828
829bool ChannelManager::StopVideoCapture(
830 VideoCapturer* capturer, const VideoFormat& video_format) {
831 return initialized_ && worker_thread_->Invoke<bool>(
832 Bind(&CaptureManager::StopVideoCapture,
833 capture_manager_.get(), capturer, video_format));
834}
835
836bool ChannelManager::RestartVideoCapture(
837 VideoCapturer* video_capturer,
838 const VideoFormat& previous_format,
839 const VideoFormat& desired_format,
840 CaptureManager::RestartOptions options) {
841 return initialized_ && worker_thread_->Invoke<bool>(
842 Bind(&CaptureManager::RestartVideoCapture, capture_manager_.get(),
843 video_capturer, previous_format, desired_format, options));
844}
845
846bool ChannelManager::AddVideoRenderer(
847 VideoCapturer* capturer, VideoRenderer* renderer) {
848 return initialized_ && worker_thread_->Invoke<bool>(
849 Bind(&CaptureManager::AddVideoRenderer,
850 capture_manager_.get(), capturer, renderer));
851}
852
853bool ChannelManager::RemoveVideoRenderer(
854 VideoCapturer* capturer, VideoRenderer* renderer) {
855 return initialized_ && worker_thread_->Invoke<bool>(
856 Bind(&CaptureManager::RemoveVideoRenderer,
857 capture_manager_.get(), capturer, renderer));
858}
859
860bool ChannelManager::IsScreencastRunning() const {
861 return initialized_ && worker_thread_->Invoke<bool>(
862 Bind(&ChannelManager::IsScreencastRunning_w, this));
863}
864
865bool ChannelManager::IsScreencastRunning_w() const {
866 VideoChannels::const_iterator it = video_channels_.begin();
867 for ( ; it != video_channels_.end(); ++it) {
868 if ((*it) && (*it)->IsScreencasting()) {
869 return true;
870 }
871 }
872 return false;
873}
874
875void ChannelManager::OnVideoCaptureStateChange(VideoCapturer* capturer,
876 CaptureState result) {
877 // TODO(whyuan): Check capturer and signal failure only for camera video, not
878 // screencast.
879 capturing_ = result == CS_RUNNING;
880 main_thread_->Post(this, MSG_VIDEOCAPTURESTATE,
881 new CaptureStateParams(capturer, result));
882}
883
884void ChannelManager::OnMessage(talk_base::Message* message) {
885 switch (message->message_id) {
886 case MSG_VIDEOCAPTURESTATE: {
887 CaptureStateParams* data =
888 static_cast<CaptureStateParams*>(message->pdata);
889 SignalVideoCaptureStateChange(data->capturer, data->state);
890 delete data;
891 break;
892 }
893 }
894}
895
896
897static void GetDeviceNames(const std::vector<Device>& devs,
898 std::vector<std::string>* names) {
899 names->clear();
900 for (size_t i = 0; i < devs.size(); ++i) {
901 names->push_back(devs[i].name);
902 }
903}
904
905bool ChannelManager::GetAudioInputDevices(std::vector<std::string>* names) {
906 names->clear();
907 std::vector<Device> devs;
908 bool ret = device_manager_->GetAudioInputDevices(&devs);
909 if (ret)
910 GetDeviceNames(devs, names);
911
912 return ret;
913}
914
915bool ChannelManager::GetAudioOutputDevices(std::vector<std::string>* names) {
916 names->clear();
917 std::vector<Device> devs;
918 bool ret = device_manager_->GetAudioOutputDevices(&devs);
919 if (ret)
920 GetDeviceNames(devs, names);
921
922 return ret;
923}
924
925bool ChannelManager::GetVideoCaptureDevices(std::vector<std::string>* names) {
926 names->clear();
927 std::vector<Device> devs;
928 bool ret = device_manager_->GetVideoCaptureDevices(&devs);
929 if (ret)
930 GetDeviceNames(devs, names);
931
932 return ret;
933}
934
935void ChannelManager::SetVideoCaptureDeviceMaxFormat(
936 const std::string& usb_id,
937 const VideoFormat& max_format) {
938 device_manager_->SetVideoCaptureDeviceMaxFormat(usb_id, max_format);
939}
940
941VideoFormat ChannelManager::GetStartCaptureFormat() {
942 return worker_thread_->Invoke<VideoFormat>(
943 Bind(&MediaEngineInterface::GetStartCaptureFormat, media_engine_.get()));
944}
945
wu@webrtc.orga8910d22014-01-23 22:12:45 +0000946bool ChannelManager::StartAecDump(talk_base::PlatformFile file) {
wu@webrtc.orga9890802013-12-13 00:21:03 +0000947 return worker_thread_->Invoke<bool>(
948 Bind(&MediaEngineInterface::StartAecDump, media_engine_.get(), file));
949}
950
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000951} // namespace cricket