1 /*
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"
46 #include "talk/media/devices/devicemanager.h"
47 #ifdef HAVE_SCTP
48 #include "talk/media/sctp/sctpdataengine.h"
49 #endif
50 #include "talk/session/media/soundclip.h"
51 #include "talk/session/media/srtpfilter.h"
52
53 namespace cricket {
54
55 enum {
56 MSG_VIDEOCAPTURESTATE = 1,
57 };
58
59 using talk_base::Bind;
60
61 static const int kNotSetOutputVolume = -1;
62
63 struct CaptureStateParams : public talk_base::MessageData {
CaptureStateParamscricket::CaptureStateParams64 CaptureStateParams(cricket::VideoCapturer* c, cricket::CaptureState s)
65 : capturer(c),
66 state(s) {}
67 cricket::VideoCapturer* capturer;
68 cricket::CaptureState state;
69 };
70
ConstructDataEngine()71 static 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)
ChannelManager(talk_base::Thread * worker_thread)80 ChannelManager::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
ChannelManager(MediaEngineInterface * me,DataEngineInterface * dme,DeviceManagerInterface * dm,CaptureManager * cm,talk_base::Thread * worker_thread)89 ChannelManager::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
ChannelManager(MediaEngineInterface * me,DeviceManagerInterface * dm,talk_base::Thread * worker_thread)97 ChannelManager::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
Construct(MediaEngineInterface * me,DataEngineInterface * dme,DeviceManagerInterface * dm,CaptureManager * cm,talk_base::Thread * worker_thread)107 void 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;
119 // Get the default audio options from the media engine.
120 audio_options_ = media_engine_->GetAudioOptions();
121 audio_in_device_ = DeviceManagerInterface::kDefaultDeviceName;
122 audio_out_device_ = DeviceManagerInterface::kDefaultDeviceName;
123 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
~ChannelManager()142 ChannelManager::~ChannelManager() {
143 if (initialized_) {
144 Terminate();
145 // 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 }
152 }
153
SetVideoRtxEnabled(bool enable)154 bool 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
GetCapabilities()169 int ChannelManager::GetCapabilities() {
170 return media_engine_->GetCapabilities() & device_manager_->GetCapabilities();
171 }
172
GetSupportedAudioCodecs(std::vector<AudioCodec> * codecs) const173 void 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
GetSupportedAudioRtpHeaderExtensions(RtpHeaderExtensions * ext) const184 void ChannelManager::GetSupportedAudioRtpHeaderExtensions(
185 RtpHeaderExtensions* ext) const {
186 *ext = media_engine_->audio_rtp_header_extensions();
187 }
188
GetSupportedVideoCodecs(std::vector<VideoCodec> * codecs) const189 void 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
GetSupportedVideoRtpHeaderExtensions(RtpHeaderExtensions * ext) const203 void ChannelManager::GetSupportedVideoRtpHeaderExtensions(
204 RtpHeaderExtensions* ext) const {
205 *ext = media_engine_->video_rtp_header_extensions();
206 }
207
GetSupportedDataCodecs(std::vector<DataCodec> * codecs) const208 void ChannelManager::GetSupportedDataCodecs(
209 std::vector<DataCodec>* codecs) const {
210 *codecs = data_media_engine_->data_codecs();
211 }
212
Init()213 bool ChannelManager::Init() {
214 ASSERT(!initialized_);
215 if (initialized_) {
216 return false;
217 }
218
219 ASSERT(worker_thread_ != NULL);
220 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()) {
225 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_
259 << " options: " << audio_options_.ToString()
260 << " 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
Terminate()293 void 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
Terminate_w()303 void 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
CreateVoiceChannel(BaseSession * session,const std::string & content_name,bool rtcp)320 VoiceChannel* 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
CreateVoiceChannel_w(BaseSession * session,const std::string & content_name,bool rtcp)327 VoiceChannel* 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
DestroyVoiceChannel(VoiceChannel * voice_channel)346 void 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
DestroyVoiceChannel_w(VoiceChannel * voice_channel)353 void 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
CreateVideoChannel(BaseSession * session,const std::string & content_name,bool rtcp,VoiceChannel * voice_channel)366 VideoChannel* 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
CreateVideoChannel_w(BaseSession * session,const std::string & content_name,bool rtcp,VoiceChannel * voice_channel)374 VideoChannel* 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
DestroyVideoChannel(VideoChannel * video_channel)397 void 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
DestroyVideoChannel_w(VideoChannel * video_channel)404 void 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
CreateDataChannel(BaseSession * session,const std::string & content_name,bool rtcp,DataChannelType channel_type)417 DataChannel* 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
CreateDataChannel_w(BaseSession * session,const std::string & content_name,bool rtcp,DataChannelType data_channel_type)425 DataChannel* 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
DestroyDataChannel(DataChannel * data_channel)450 void 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
DestroyDataChannel_w(DataChannel * data_channel)457 void 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
CreateSoundclip()470 Soundclip* ChannelManager::CreateSoundclip() {
471 return worker_thread_->Invoke<Soundclip*>(
472 Bind(&ChannelManager::CreateSoundclip_w, this));
473 }
474
CreateSoundclip_w()475 Soundclip* 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
DestroySoundclip(Soundclip * soundclip)489 void ChannelManager::DestroySoundclip(Soundclip* soundclip) {
490 if (soundclip) {
491 worker_thread_->Invoke<void>(
492 Bind(&ChannelManager::DestroySoundclip_w, this, soundclip));
493 }
494 }
495
DestroySoundclip_w(Soundclip * soundclip)496 void 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
GetAudioOptions(std::string * in_name,std::string * out_name,AudioOptions * options)509 bool ChannelManager::GetAudioOptions(std::string* in_name,
510 std::string* out_name,
511 AudioOptions* options) {
512 if (in_name)
513 *in_name = audio_in_device_;
514 if (out_name)
515 *out_name = audio_out_device_;
516 if (options)
517 *options = audio_options_;
518 return true;
519 }
520
SetAudioOptions(const std::string & in_name,const std::string & out_name,const AudioOptions & options)521 bool ChannelManager::SetAudioOptions(const std::string& in_name,
522 const std::string& out_name,
523 const AudioOptions& options) {
524 return SetAudioOptions(in_name, out_name, options, audio_delay_offset_);
525 }
526
SetAudioOptions(const std::string & in_name,const std::string & out_name,const AudioOptions & options,int delay_offset)527 bool ChannelManager::SetAudioOptions(const std::string& in_name,
528 const std::string& out_name,
529 const AudioOptions& options,
530 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,
547 options, delay_offset, &in_dev, &out_dev));
548 }
549
550 // If all worked well, save the values for use in GetAudioOptions.
551 if (ret) {
552 audio_options_ = options;
553 audio_in_device_ = in_name;
554 audio_out_device_ = out_name;
555 audio_delay_offset_ = delay_offset;
556 }
557 return ret;
558 }
559
SetAudioOptions_w(const AudioOptions & options,int delay_offset,const Device * in_dev,const Device * out_dev)560 bool ChannelManager::SetAudioOptions_w(
561 const AudioOptions& options, int delay_offset,
562 const Device* in_dev, const Device* out_dev) {
563 ASSERT(worker_thread_ == talk_base::Thread::Current());
564 ASSERT(initialized_);
565
566 // Set audio options
567 bool ret = media_engine_->SetAudioOptions(options);
568
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
581 // Sets Engine-specific audio options according to enabled experiments.
SetEngineAudioOptions(const AudioOptions & options)582 bool ChannelManager::SetEngineAudioOptions(const AudioOptions& options) {
583 // If we're initialized, pass the settings to the media engine.
584 bool ret = false;
585 if (initialized_) {
586 ret = worker_thread_->Invoke<bool>(
587 Bind(&ChannelManager::SetEngineAudioOptions_w, this, options));
588 }
589
590 // If all worked well, save the audio options.
591 if (ret) {
592 audio_options_ = options;
593 }
594 return ret;
595 }
596
SetEngineAudioOptions_w(const AudioOptions & options)597 bool ChannelManager::SetEngineAudioOptions_w(const AudioOptions& options) {
598 ASSERT(worker_thread_ == talk_base::Thread::Current());
599 ASSERT(initialized_);
600
601 return media_engine_->SetAudioOptions(options);
602 }
603
GetOutputVolume(int * level)604 bool ChannelManager::GetOutputVolume(int* level) {
605 if (!initialized_) {
606 return false;
607 }
608 return worker_thread_->Invoke<bool>(
609 Bind(&MediaEngineInterface::GetOutputVolume, media_engine_.get(), level));
610 }
611
SetOutputVolume(int level)612 bool ChannelManager::SetOutputVolume(int level) {
613 bool ret = level >= 0 && level <= 255;
614 if (initialized_) {
615 ret &= worker_thread_->Invoke<bool>(
616 Bind(&MediaEngineInterface::SetOutputVolume,
617 media_engine_.get(), level));
618 }
619
620 if (ret) {
621 audio_output_volume_ = level;
622 }
623
624 return ret;
625 }
626
IsSameCapturer(const std::string & capturer_name,VideoCapturer * capturer)627 bool ChannelManager::IsSameCapturer(const std::string& capturer_name,
628 VideoCapturer* capturer) {
629 if (capturer == NULL) {
630 return false;
631 }
632 Device device;
633 if (!device_manager_->GetVideoCaptureDevice(capturer_name, &device)) {
634 return false;
635 }
636 return capturer->GetId() == device.id;
637 }
638
GetVideoCaptureDevice(Device * device)639 bool ChannelManager::GetVideoCaptureDevice(Device* device) {
640 std::string device_name;
641 if (!GetCaptureDevice(&device_name)) {
642 return false;
643 }
644 return device_manager_->GetVideoCaptureDevice(device_name, device);
645 }
646
GetCaptureDevice(std::string * cam_name)647 bool ChannelManager::GetCaptureDevice(std::string* cam_name) {
648 if (camera_device_.empty()) {
649 // Initialize camera_device_ with default.
650 Device device;
651 if (!device_manager_->GetVideoCaptureDevice(
652 DeviceManagerInterface::kDefaultDeviceName, &device)) {
653 LOG(LS_WARNING) << "Device manager can't find default camera: " <<
654 DeviceManagerInterface::kDefaultDeviceName;
655 return false;
656 }
657 camera_device_ = device.name;
658 }
659 *cam_name = camera_device_;
660 return true;
661 }
662
SetCaptureDevice(const std::string & cam_name)663 bool ChannelManager::SetCaptureDevice(const std::string& cam_name) {
664 Device device;
665 bool ret = true;
666 if (!device_manager_->GetVideoCaptureDevice(cam_name, &device)) {
667 if (!cam_name.empty()) {
668 LOG(LS_WARNING) << "Device manager can't find camera: " << cam_name;
669 }
670 ret = false;
671 }
672
673 // If we're running, tell the media engine about it.
674 if (initialized_ && ret) {
675 ret = worker_thread_->Invoke<bool>(
676 Bind(&ChannelManager::SetCaptureDevice_w, this, &device));
677 }
678
679 // If everything worked, retain the name of the selected camera.
680 if (ret) {
681 camera_device_ = device.name;
682 } else if (camera_device_.empty()) {
683 // When video option setting fails, we still want camera_device_ to be in a
684 // good state, so we initialize it with default if it's empty.
685 Device default_device;
686 if (!device_manager_->GetVideoCaptureDevice(
687 DeviceManagerInterface::kDefaultDeviceName, &default_device)) {
688 LOG(LS_WARNING) << "Device manager can't find default camera: " <<
689 DeviceManagerInterface::kDefaultDeviceName;
690 }
691 camera_device_ = default_device.name;
692 }
693
694 return ret;
695 }
696
CreateVideoCapturer()697 VideoCapturer* ChannelManager::CreateVideoCapturer() {
698 Device device;
699 if (!device_manager_->GetVideoCaptureDevice(camera_device_, &device)) {
700 if (!camera_device_.empty()) {
701 LOG(LS_WARNING) << "Device manager can't find camera: " << camera_device_;
702 }
703 return NULL;
704 }
705 VideoCapturer* capturer = device_manager_->CreateVideoCapturer(device);
706 if (capturer && default_video_encoder_config_.max_codec.id != 0) {
707 // For now, use the aspect ratio of the default_video_encoder_config_,
708 // which may be different than the native aspect ratio of the start
709 // format the camera may use.
710 capturer->UpdateAspectRatio(
711 default_video_encoder_config_.max_codec.width,
712 default_video_encoder_config_.max_codec.height);
713 }
714 return capturer;
715 }
716
SetCaptureDevice_w(const Device * cam_device)717 bool ChannelManager::SetCaptureDevice_w(const Device* cam_device) {
718 ASSERT(worker_thread_ == talk_base::Thread::Current());
719 ASSERT(initialized_);
720
721 if (!cam_device) {
722 video_device_name_.clear();
723 return true;
724 }
725 video_device_name_ = cam_device->name;
726 return true;
727 }
728
SetDefaultVideoEncoderConfig(const VideoEncoderConfig & c)729 bool ChannelManager::SetDefaultVideoEncoderConfig(const VideoEncoderConfig& c) {
730 bool ret = true;
731 if (initialized_) {
732 ret = worker_thread_->Invoke<bool>(
733 Bind(&MediaEngineInterface::SetDefaultVideoEncoderConfig,
734 media_engine_.get(), c));
735 }
736 if (ret) {
737 default_video_encoder_config_ = c;
738 }
739 return ret;
740 }
741
SetLocalMonitor(bool enable)742 bool ChannelManager::SetLocalMonitor(bool enable) {
743 bool ret = initialized_ && worker_thread_->Invoke<bool>(
744 Bind(&MediaEngineInterface::SetLocalMonitor,
745 media_engine_.get(), enable));
746 if (ret) {
747 monitoring_ = enable;
748 }
749 return ret;
750 }
751
SetLocalRenderer(VideoRenderer * renderer)752 bool ChannelManager::SetLocalRenderer(VideoRenderer* renderer) {
753 bool ret = true;
754 if (initialized_) {
755 ret = worker_thread_->Invoke<bool>(
756 Bind(&MediaEngineInterface::SetLocalRenderer,
757 media_engine_.get(), renderer));
758 }
759 if (ret) {
760 local_renderer_ = renderer;
761 }
762 return ret;
763 }
764
SetVoiceLogging(int level,const char * filter)765 void ChannelManager::SetVoiceLogging(int level, const char* filter) {
766 if (initialized_) {
767 worker_thread_->Invoke<void>(
768 Bind(&MediaEngineInterface::SetVoiceLogging,
769 media_engine_.get(), level, filter));
770 } else {
771 media_engine_->SetVoiceLogging(level, filter);
772 }
773 }
774
SetVideoLogging(int level,const char * filter)775 void ChannelManager::SetVideoLogging(int level, const char* filter) {
776 if (initialized_) {
777 worker_thread_->Invoke<void>(
778 Bind(&MediaEngineInterface::SetVideoLogging,
779 media_engine_.get(), level, filter));
780 } else {
781 media_engine_->SetVideoLogging(level, filter);
782 }
783 }
784
785 // TODO(janahan): For now pass this request through the mediaengine to the
786 // voice and video engines to do the real work. Once the capturer refactoring
787 // is done, we will access the capturer using the ssrc (similar to how the
788 // renderer is accessed today) and register with it directly.
RegisterVideoProcessor(VideoCapturer * capturer,VideoProcessor * processor)789 bool ChannelManager::RegisterVideoProcessor(VideoCapturer* capturer,
790 VideoProcessor* processor) {
791 return initialized_ && worker_thread_->Invoke<bool>(
792 Bind(&ChannelManager::RegisterVideoProcessor_w, this,
793 capturer, processor));
794 }
795
RegisterVideoProcessor_w(VideoCapturer * capturer,VideoProcessor * processor)796 bool ChannelManager::RegisterVideoProcessor_w(VideoCapturer* capturer,
797 VideoProcessor* processor) {
798 return capture_manager_->AddVideoProcessor(capturer, processor);
799 }
800
UnregisterVideoProcessor(VideoCapturer * capturer,VideoProcessor * processor)801 bool ChannelManager::UnregisterVideoProcessor(VideoCapturer* capturer,
802 VideoProcessor* processor) {
803 return initialized_ && worker_thread_->Invoke<bool>(
804 Bind(&ChannelManager::UnregisterVideoProcessor_w, this,
805 capturer, processor));
806 }
807
UnregisterVideoProcessor_w(VideoCapturer * capturer,VideoProcessor * processor)808 bool ChannelManager::UnregisterVideoProcessor_w(VideoCapturer* capturer,
809 VideoProcessor* processor) {
810 return capture_manager_->RemoveVideoProcessor(capturer, processor);
811 }
812
RegisterVoiceProcessor(uint32 ssrc,VoiceProcessor * processor,MediaProcessorDirection direction)813 bool ChannelManager::RegisterVoiceProcessor(
814 uint32 ssrc,
815 VoiceProcessor* processor,
816 MediaProcessorDirection direction) {
817 return initialized_ && worker_thread_->Invoke<bool>(
818 Bind(&MediaEngineInterface::RegisterVoiceProcessor, media_engine_.get(),
819 ssrc, processor, direction));
820 }
821
UnregisterVoiceProcessor(uint32 ssrc,VoiceProcessor * processor,MediaProcessorDirection direction)822 bool ChannelManager::UnregisterVoiceProcessor(
823 uint32 ssrc,
824 VoiceProcessor* processor,
825 MediaProcessorDirection direction) {
826 return initialized_ && worker_thread_->Invoke<bool>(
827 Bind(&MediaEngineInterface::UnregisterVoiceProcessor,
828 media_engine_.get(), ssrc, processor, direction));
829 }
830
831 // The following are done in the new "CaptureManager" style that
832 // all local video capturers, processors, and managers should move
833 // to.
834 // TODO(pthatcher): Add more of the CaptureManager interface.
StartVideoCapture(VideoCapturer * capturer,const VideoFormat & video_format)835 bool ChannelManager::StartVideoCapture(
836 VideoCapturer* capturer, const VideoFormat& video_format) {
837 return initialized_ && worker_thread_->Invoke<bool>(
838 Bind(&CaptureManager::StartVideoCapture,
839 capture_manager_.get(), capturer, video_format));
840 }
841
MuteToBlackThenPause(VideoCapturer * video_capturer,bool muted)842 bool ChannelManager::MuteToBlackThenPause(
843 VideoCapturer* video_capturer, bool muted) {
844 if (!initialized_) {
845 return false;
846 }
847 worker_thread_->Invoke<void>(
848 Bind(&VideoCapturer::MuteToBlackThenPause, video_capturer, muted));
849 return true;
850 }
851
StopVideoCapture(VideoCapturer * capturer,const VideoFormat & video_format)852 bool ChannelManager::StopVideoCapture(
853 VideoCapturer* capturer, const VideoFormat& video_format) {
854 return initialized_ && worker_thread_->Invoke<bool>(
855 Bind(&CaptureManager::StopVideoCapture,
856 capture_manager_.get(), capturer, video_format));
857 }
858
RestartVideoCapture(VideoCapturer * video_capturer,const VideoFormat & previous_format,const VideoFormat & desired_format,CaptureManager::RestartOptions options)859 bool ChannelManager::RestartVideoCapture(
860 VideoCapturer* video_capturer,
861 const VideoFormat& previous_format,
862 const VideoFormat& desired_format,
863 CaptureManager::RestartOptions options) {
864 return initialized_ && worker_thread_->Invoke<bool>(
865 Bind(&CaptureManager::RestartVideoCapture, capture_manager_.get(),
866 video_capturer, previous_format, desired_format, options));
867 }
868
AddVideoRenderer(VideoCapturer * capturer,VideoRenderer * renderer)869 bool ChannelManager::AddVideoRenderer(
870 VideoCapturer* capturer, VideoRenderer* renderer) {
871 return initialized_ && worker_thread_->Invoke<bool>(
872 Bind(&CaptureManager::AddVideoRenderer,
873 capture_manager_.get(), capturer, renderer));
874 }
875
RemoveVideoRenderer(VideoCapturer * capturer,VideoRenderer * renderer)876 bool ChannelManager::RemoveVideoRenderer(
877 VideoCapturer* capturer, VideoRenderer* renderer) {
878 return initialized_ && worker_thread_->Invoke<bool>(
879 Bind(&CaptureManager::RemoveVideoRenderer,
880 capture_manager_.get(), capturer, renderer));
881 }
882
IsScreencastRunning() const883 bool ChannelManager::IsScreencastRunning() const {
884 return initialized_ && worker_thread_->Invoke<bool>(
885 Bind(&ChannelManager::IsScreencastRunning_w, this));
886 }
887
IsScreencastRunning_w() const888 bool ChannelManager::IsScreencastRunning_w() const {
889 VideoChannels::const_iterator it = video_channels_.begin();
890 for ( ; it != video_channels_.end(); ++it) {
891 if ((*it) && (*it)->IsScreencasting()) {
892 return true;
893 }
894 }
895 return false;
896 }
897
OnVideoCaptureStateChange(VideoCapturer * capturer,CaptureState result)898 void ChannelManager::OnVideoCaptureStateChange(VideoCapturer* capturer,
899 CaptureState result) {
900 // TODO(whyuan): Check capturer and signal failure only for camera video, not
901 // screencast.
902 capturing_ = result == CS_RUNNING;
903 main_thread_->Post(this, MSG_VIDEOCAPTURESTATE,
904 new CaptureStateParams(capturer, result));
905 }
906
OnMessage(talk_base::Message * message)907 void ChannelManager::OnMessage(talk_base::Message* message) {
908 switch (message->message_id) {
909 case MSG_VIDEOCAPTURESTATE: {
910 CaptureStateParams* data =
911 static_cast<CaptureStateParams*>(message->pdata);
912 SignalVideoCaptureStateChange(data->capturer, data->state);
913 delete data;
914 break;
915 }
916 }
917 }
918
919
GetDeviceNames(const std::vector<Device> & devs,std::vector<std::string> * names)920 static void GetDeviceNames(const std::vector<Device>& devs,
921 std::vector<std::string>* names) {
922 names->clear();
923 for (size_t i = 0; i < devs.size(); ++i) {
924 names->push_back(devs[i].name);
925 }
926 }
927
GetAudioInputDevices(std::vector<std::string> * names)928 bool ChannelManager::GetAudioInputDevices(std::vector<std::string>* names) {
929 names->clear();
930 std::vector<Device> devs;
931 bool ret = device_manager_->GetAudioInputDevices(&devs);
932 if (ret)
933 GetDeviceNames(devs, names);
934
935 return ret;
936 }
937
GetAudioOutputDevices(std::vector<std::string> * names)938 bool ChannelManager::GetAudioOutputDevices(std::vector<std::string>* names) {
939 names->clear();
940 std::vector<Device> devs;
941 bool ret = device_manager_->GetAudioOutputDevices(&devs);
942 if (ret)
943 GetDeviceNames(devs, names);
944
945 return ret;
946 }
947
GetVideoCaptureDevices(std::vector<std::string> * names)948 bool ChannelManager::GetVideoCaptureDevices(std::vector<std::string>* names) {
949 names->clear();
950 std::vector<Device> devs;
951 bool ret = device_manager_->GetVideoCaptureDevices(&devs);
952 if (ret)
953 GetDeviceNames(devs, names);
954
955 return ret;
956 }
957
SetVideoCaptureDeviceMaxFormat(const std::string & usb_id,const VideoFormat & max_format)958 void ChannelManager::SetVideoCaptureDeviceMaxFormat(
959 const std::string& usb_id,
960 const VideoFormat& max_format) {
961 device_manager_->SetVideoCaptureDeviceMaxFormat(usb_id, max_format);
962 }
963
GetStartCaptureFormat()964 VideoFormat ChannelManager::GetStartCaptureFormat() {
965 return worker_thread_->Invoke<VideoFormat>(
966 Bind(&MediaEngineInterface::GetStartCaptureFormat, media_engine_.get()));
967 }
968
StartAecDump(talk_base::PlatformFile file)969 bool ChannelManager::StartAecDump(talk_base::PlatformFile file) {
970 return worker_thread_->Invoke<bool>(
971 Bind(&MediaEngineInterface::StartAecDump, media_engine_.get(), file));
972 }
973
974 } // namespace cricket
975