Home | History | Annotate | Download | only in phone
      1 /*
      2  * libjingle
      3  * Copyright 2004--2008, 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/phone/channelmanager.h"
     29 
     30 #ifdef HAVE_CONFIG_H
     31 #include <config.h>
     32 #endif
     33 
     34 #include <algorithm>
     35 
     36 #include "talk/base/common.h"
     37 #include "talk/base/logging.h"
     38 #include "talk/base/sigslotrepeater.h"
     39 #include "talk/base/stringencode.h"
     40 #include "talk/session/phone/mediaengine.h"
     41 #include "talk/session/phone/soundclip.h"
     42 
     43 namespace cricket {
     44 
     45 enum {
     46   MSG_CREATEVOICECHANNEL = 1,
     47   MSG_DESTROYVOICECHANNEL = 2,
     48   MSG_SETAUDIOOPTIONS = 3,
     49   MSG_SETOUTPUTVOLUME = 4,
     50   MSG_SETLOCALMONITOR = 5,
     51   MSG_SETVOICELOGGING = 6,
     52   MSG_CREATEVIDEOCHANNEL = 11,
     53   MSG_DESTROYVIDEOCHANNEL = 12,
     54   MSG_SETVIDEOOPTIONS = 13,
     55   MSG_SETLOCALRENDERER = 14,
     56   MSG_SETDEFAULTVIDEOENCODERCONFIG = 15,
     57   MSG_SETVIDEOLOGGING = 16,
     58   MSG_CREATESOUNDCLIP = 17,
     59   MSG_DESTROYSOUNDCLIP = 18,
     60   MSG_CAMERASTARTED = 19,
     61   MSG_SETVIDEOCAPTURE = 20,
     62 };
     63 
     64 struct CreationParams : public talk_base::MessageData {
     65   CreationParams(BaseSession* session, const std::string& content_name,
     66                  bool rtcp, VoiceChannel* voice_channel)
     67       : session(session),
     68         content_name(content_name),
     69         rtcp(rtcp),
     70         voice_channel(voice_channel),
     71         video_channel(NULL) {}
     72   BaseSession* session;
     73   std::string content_name;
     74   bool rtcp;
     75   VoiceChannel* voice_channel;
     76   VideoChannel* video_channel;
     77 };
     78 
     79 struct AudioOptions : public talk_base::MessageData {
     80   AudioOptions(int o, const Device* in, const Device* out)
     81       : options(o), in_device(in), out_device(out) {}
     82   int options;
     83   const Device* in_device;
     84   const Device* out_device;
     85   bool result;
     86 };
     87 
     88 struct VolumeLevel : public talk_base::MessageData {
     89   explicit VolumeLevel(int l) : level(l), result(false) {}
     90   int level;
     91   bool result;
     92 };
     93 
     94 struct VideoOptions : public talk_base::MessageData {
     95   explicit VideoOptions(const Device* d) : cam_device(d), result(false) {}
     96   const Device* cam_device;
     97   bool result;
     98 };
     99 
    100 struct DefaultVideoEncoderConfig : public talk_base::MessageData {
    101   explicit DefaultVideoEncoderConfig(const VideoEncoderConfig& c)
    102       : config(c), result(false) {}
    103   VideoEncoderConfig config;
    104   bool result;
    105 };
    106 
    107 struct LocalMonitor : public talk_base::MessageData {
    108   explicit LocalMonitor(bool e) : enable(e), result(false) {}
    109   bool enable;
    110   bool result;
    111 };
    112 
    113 struct LocalRenderer : public talk_base::MessageData {
    114   explicit LocalRenderer(VideoRenderer* r) : renderer(r), result(false) {}
    115   VideoRenderer* renderer;
    116   bool result;
    117 };
    118 
    119 struct LoggingOptions : public talk_base::MessageData {
    120   explicit LoggingOptions(int lev, const char* f) : level(lev), filter(f) {}
    121   int level;
    122   std::string filter;
    123 };
    124 
    125 struct CaptureParams : public talk_base::MessageData {
    126   explicit CaptureParams(bool c) : capture(c), result(CR_FAILURE) {}
    127 
    128   bool capture;
    129   CaptureResult result;
    130 };
    131 
    132 ChannelManager::ChannelManager(talk_base::Thread* worker_thread)
    133     : media_engine_(MediaEngine::Create()),
    134       device_manager_(new DeviceManager()),
    135       initialized_(false),
    136       main_thread_(talk_base::Thread::Current()),
    137       worker_thread_(worker_thread),
    138       audio_in_device_(DeviceManager::kDefaultDeviceName),
    139       audio_out_device_(DeviceManager::kDefaultDeviceName),
    140       audio_options_(MediaEngine::DEFAULT_AUDIO_OPTIONS),
    141       local_renderer_(NULL),
    142       capturing_(false),
    143       monitoring_(false) {
    144   Construct();
    145 }
    146 
    147 ChannelManager::ChannelManager(MediaEngine* me, DeviceManager* dm,
    148                                talk_base::Thread* worker_thread)
    149     : media_engine_(me),
    150       device_manager_(dm),
    151       initialized_(false),
    152       main_thread_(talk_base::Thread::Current()),
    153       worker_thread_(worker_thread),
    154       audio_in_device_(DeviceManager::kDefaultDeviceName),
    155       audio_out_device_(DeviceManager::kDefaultDeviceName),
    156       audio_options_(MediaEngine::DEFAULT_AUDIO_OPTIONS),
    157       local_renderer_(NULL),
    158       capturing_(false),
    159       monitoring_(false) {
    160   Construct();
    161 }
    162 
    163 void ChannelManager::Construct() {
    164   // Init the device manager immediately, and set up our default video device.
    165   SignalDevicesChange.repeat(device_manager_->SignalDevicesChange);
    166   device_manager_->Init();
    167   // Set camera_device_ to the name of the default video capturer.
    168   SetVideoOptions(DeviceManager::kDefaultDeviceName);
    169 
    170   // Camera is started asynchronously, request callbacks when startup
    171   // completes to be able to forward them to the rendering manager.
    172   media_engine_->SignalVideoCaptureResult.connect(
    173       this, &ChannelManager::OnVideoCaptureResult);
    174 }
    175 
    176 ChannelManager::~ChannelManager() {
    177   if (initialized_)
    178     Terminate();
    179 }
    180 
    181 int ChannelManager::GetCapabilities() {
    182   return media_engine_->GetCapabilities() & device_manager_->GetCapabilities();
    183 }
    184 
    185 void ChannelManager::GetSupportedAudioCodecs(
    186     std::vector<AudioCodec>* codecs) const {
    187   codecs->clear();
    188 
    189   for (std::vector<AudioCodec>::const_iterator it =
    190            media_engine_->audio_codecs().begin();
    191       it != media_engine_->audio_codecs().end(); ++it) {
    192     codecs->push_back(*it);
    193   }
    194 }
    195 
    196 void ChannelManager::GetSupportedVideoCodecs(
    197     std::vector<VideoCodec>* codecs) const {
    198   codecs->clear();
    199 
    200   std::vector<VideoCodec>::const_iterator it;
    201   for (it = media_engine_->video_codecs().begin();
    202       it != media_engine_->video_codecs().end(); ++it) {
    203     codecs->push_back(*it);
    204   }
    205 }
    206 
    207 bool ChannelManager::Init() {
    208   ASSERT(!initialized_);
    209   if (initialized_) {
    210     return false;
    211   }
    212 
    213   ASSERT(worker_thread_ != NULL);
    214   if (worker_thread_ && worker_thread_->started()) {
    215     if (media_engine_->Init()) {
    216       initialized_ = true;
    217 
    218       // Now that we're initialized, apply any stored preferences. A preferred
    219       // device might have been unplugged. In this case, we fallback to the
    220       // default device but keep the user preferences. The preferences are
    221       // changed only when the Javascript FE changes them.
    222       const std::string preferred_audio_in_device = audio_in_device_;
    223       const std::string preferred_audio_out_device = audio_out_device_;
    224       const std::string preferred_camera_device = camera_device_;
    225       Device device;
    226       if (!device_manager_->GetAudioInputDevice(audio_in_device_, &device)) {
    227         LOG(LS_WARNING) << "The preferred microphone '" << audio_in_device_
    228                         << "' is unavailable. Fall back to the default.";
    229         audio_in_device_ = DeviceManager::kDefaultDeviceName;
    230       }
    231       if (!device_manager_->GetAudioOutputDevice(audio_out_device_, &device)) {
    232         LOG(LS_WARNING) << "The preferred speaker '" << audio_out_device_
    233                         << "' is unavailable. Fall back to the default.";
    234         audio_out_device_ = DeviceManager::kDefaultDeviceName;
    235       }
    236       if (!device_manager_->GetVideoCaptureDevice(camera_device_, &device)) {
    237         LOG(LS_WARNING) << "The preferred camera '" << camera_device_
    238                         << "' is unavailable. Fall back to the default.";
    239         camera_device_ = DeviceManager::kDefaultDeviceName;
    240       }
    241 
    242       if (!SetAudioOptions(audio_in_device_, audio_out_device_,
    243                            audio_options_)) {
    244         LOG(LS_WARNING) << "Failed to SetAudioOptions with"
    245                         << " microphone: " << audio_in_device_
    246                         << " speaker: " << audio_out_device_
    247                         << " options: " << audio_options_;
    248       }
    249       if (!SetVideoOptions(camera_device_)) {
    250         LOG(LS_WARNING) << "Failed to SetVideoOptions with camera: "
    251                         << camera_device_;
    252       }
    253 
    254       // Restore the user preferences.
    255       audio_in_device_ = preferred_audio_in_device;
    256       audio_out_device_ = preferred_audio_out_device;
    257       camera_device_ = preferred_camera_device;
    258 
    259       // Now apply the default video codec that has been set earlier.
    260       if (default_video_encoder_config_.max_codec.id != 0) {
    261         SetDefaultVideoEncoderConfig(default_video_encoder_config_);
    262       }
    263       // And the local renderer.
    264       if (local_renderer_) {
    265         SetLocalRenderer(local_renderer_);
    266       }
    267     }
    268   }
    269   return initialized_;
    270 }
    271 
    272 void ChannelManager::Terminate() {
    273   ASSERT(initialized_);
    274   if (!initialized_) {
    275     return;
    276   }
    277 
    278   // Need to destroy the voice/video channels
    279   while (!video_channels_.empty()) {
    280     DestroyVideoChannel_w(video_channels_.back());
    281   }
    282   while (!voice_channels_.empty()) {
    283     DestroyVoiceChannel_w(voice_channels_.back());
    284   }
    285   while (!soundclips_.empty()) {
    286     DestroySoundclip_w(soundclips_.back());
    287   }
    288 
    289   media_engine_->Terminate();
    290   initialized_ = false;
    291 }
    292 
    293 VoiceChannel* ChannelManager::CreateVoiceChannel(
    294     BaseSession* session, const std::string& content_name, bool rtcp) {
    295   CreationParams params(session, content_name, rtcp, NULL);
    296   return (Send(MSG_CREATEVOICECHANNEL, &params)) ? params.voice_channel : NULL;
    297 }
    298 
    299 VoiceChannel* ChannelManager::CreateVoiceChannel_w(
    300     BaseSession* session, const std::string& content_name, bool rtcp) {
    301   talk_base::CritScope cs(&crit_);
    302 
    303   // This is ok to alloc from a thread other than the worker thread
    304   ASSERT(initialized_);
    305   VoiceMediaChannel* media_channel = media_engine_->CreateChannel();
    306   if (media_channel == NULL)
    307     return NULL;
    308 
    309   VoiceChannel* voice_channel = new VoiceChannel(
    310       worker_thread_, media_engine_.get(), media_channel,
    311       session, content_name, rtcp);
    312   voice_channels_.push_back(voice_channel);
    313   return voice_channel;
    314 }
    315 
    316 void ChannelManager::DestroyVoiceChannel(VoiceChannel* voice_channel) {
    317   if (voice_channel) {
    318     talk_base::TypedMessageData<VoiceChannel *> data(voice_channel);
    319     Send(MSG_DESTROYVOICECHANNEL, &data);
    320   }
    321 }
    322 
    323 void ChannelManager::DestroyVoiceChannel_w(VoiceChannel* voice_channel) {
    324   talk_base::CritScope cs(&crit_);
    325   // Destroy voice channel.
    326   ASSERT(initialized_);
    327   VoiceChannels::iterator it = std::find(voice_channels_.begin(),
    328       voice_channels_.end(), voice_channel);
    329   ASSERT(it != voice_channels_.end());
    330   if (it == voice_channels_.end())
    331     return;
    332 
    333   voice_channels_.erase(it);
    334   delete voice_channel;
    335 }
    336 
    337 VideoChannel* ChannelManager::CreateVideoChannel(
    338     BaseSession* session, const std::string& content_name, bool rtcp,
    339     VoiceChannel* voice_channel) {
    340   CreationParams params(session, content_name, rtcp, voice_channel);
    341   return (Send(MSG_CREATEVIDEOCHANNEL, &params)) ? params.video_channel : NULL;
    342 }
    343 
    344 VideoChannel* ChannelManager::CreateVideoChannel_w(
    345     BaseSession* session, const std::string& content_name, bool rtcp,
    346     VoiceChannel* voice_channel) {
    347   talk_base::CritScope cs(&crit_);
    348 
    349   // This is ok to alloc from a thread other than the worker thread
    350   ASSERT(initialized_);
    351   VideoMediaChannel* media_channel =
    352       // voice_channel can be NULL in case of NullVoiceEngine.
    353       media_engine_->CreateVideoChannel(voice_channel ?
    354           voice_channel->media_channel() : NULL);
    355   if (media_channel == NULL)
    356     return NULL;
    357 
    358   VideoChannel* video_channel = new VideoChannel(
    359       worker_thread_, media_engine_.get(), media_channel,
    360       session, content_name, rtcp, voice_channel);
    361   video_channels_.push_back(video_channel);
    362   return video_channel;
    363 }
    364 
    365 void ChannelManager::DestroyVideoChannel(VideoChannel* video_channel) {
    366   if (video_channel) {
    367     talk_base::TypedMessageData<VideoChannel *> data(video_channel);
    368     Send(MSG_DESTROYVIDEOCHANNEL, &data);
    369   }
    370 }
    371 
    372 void ChannelManager::DestroyVideoChannel_w(VideoChannel *video_channel) {
    373   talk_base::CritScope cs(&crit_);
    374   // Destroy voice channel.
    375   ASSERT(initialized_);
    376   VideoChannels::iterator it = std::find(video_channels_.begin(),
    377       video_channels_.end(), video_channel);
    378   ASSERT(it != video_channels_.end());
    379   if (it == video_channels_.end())
    380     return;
    381 
    382   video_channels_.erase(it);
    383   delete video_channel;
    384 }
    385 
    386 Soundclip* ChannelManager::CreateSoundclip() {
    387   talk_base::TypedMessageData<Soundclip*> data(NULL);
    388   Send(MSG_CREATESOUNDCLIP, &data);
    389   return data.data();
    390 }
    391 
    392 Soundclip* ChannelManager::CreateSoundclip_w() {
    393   talk_base::CritScope cs(&crit_);
    394 
    395   ASSERT(initialized_);
    396   ASSERT(worker_thread_ == talk_base::Thread::Current());
    397 
    398   SoundclipMedia* soundclip_media = media_engine_->CreateSoundclip();
    399   if (!soundclip_media) {
    400     return NULL;
    401   }
    402 
    403   Soundclip* soundclip = new Soundclip(worker_thread_, soundclip_media);
    404   soundclips_.push_back(soundclip);
    405   return soundclip;
    406 }
    407 
    408 void ChannelManager::DestroySoundclip(Soundclip* soundclip) {
    409   if (soundclip) {
    410     talk_base::TypedMessageData<Soundclip*> data(soundclip);
    411     Send(MSG_DESTROYSOUNDCLIP, &data);
    412   }
    413 }
    414 
    415 void ChannelManager::DestroySoundclip_w(Soundclip* soundclip) {
    416   talk_base::CritScope cs(&crit_);
    417   // Destroy soundclip.
    418   ASSERT(initialized_);
    419   Soundclips::iterator it = std::find(soundclips_.begin(),
    420       soundclips_.end(), soundclip);
    421   ASSERT(it != soundclips_.end());
    422   if (it == soundclips_.end())
    423     return;
    424 
    425   soundclips_.erase(it);
    426   delete soundclip;
    427 }
    428 
    429 bool ChannelManager::GetAudioOptions(std::string* in_name,
    430                                      std::string* out_name, int* opts) {
    431   *in_name = audio_in_device_;
    432   *out_name = audio_out_device_;
    433   *opts = audio_options_;
    434   return true;
    435 }
    436 
    437 bool ChannelManager::SetAudioOptions(const std::string& in_name,
    438                                      const std::string& out_name, int opts) {
    439   // Get device ids from DeviceManager.
    440   Device in_dev, out_dev;
    441   if (!device_manager_->GetAudioInputDevice(in_name, &in_dev) ||
    442       !device_manager_->GetAudioOutputDevice(out_name, &out_dev)) {
    443     LOG(LS_WARNING) << "Device manager can't find selected device";
    444     return false;
    445   }
    446 
    447   // If we're initialized, pass the settings to the media engine.
    448   bool ret = true;
    449   if (initialized_) {
    450     AudioOptions options(opts, &in_dev, &out_dev);
    451     ret = (Send(MSG_SETAUDIOOPTIONS, &options) && options.result);
    452   }
    453 
    454   // If all worked well, save the values for use in GetAudioOptions.
    455   if (ret) {
    456     audio_options_ = opts;
    457     audio_in_device_ = in_name;
    458     audio_out_device_ = out_name;
    459   }
    460   return ret;
    461 }
    462 
    463 bool ChannelManager::SetAudioOptions_w(int opts, const Device* in_dev,
    464     const Device* out_dev) {
    465   ASSERT(worker_thread_ == talk_base::Thread::Current());
    466   ASSERT(initialized_);
    467 
    468   // Set audio options
    469   bool ret = media_engine_->SetAudioOptions(opts);
    470 
    471   // Set the audio devices
    472   if (ret) {
    473     talk_base::CritScope cs(&crit_);
    474     ret = media_engine_->SetSoundDevices(in_dev, out_dev);
    475   }
    476 
    477   return ret;
    478 }
    479 
    480 bool ChannelManager::SetOutputVolume(int level) {
    481   VolumeLevel volume(level);
    482   return (Send(MSG_SETOUTPUTVOLUME, &volume) && volume.result);
    483 }
    484 
    485 bool ChannelManager::SetOutputVolume_w(int level) {
    486   ASSERT(worker_thread_ == talk_base::Thread::Current());
    487   ASSERT(initialized_);
    488   return media_engine_->SetOutputVolume(level);
    489 }
    490 
    491 bool ChannelManager::GetVideoOptions(std::string* cam_name) {
    492   *cam_name = camera_device_;
    493   return true;
    494 }
    495 
    496 bool ChannelManager::SetVideoOptions(const std::string& cam_name) {
    497   Device device;
    498   if (!device_manager_->GetVideoCaptureDevice(cam_name, &device)) {
    499     LOG(LS_WARNING) << "Device manager can't find camera: " << cam_name;
    500     return false;
    501   }
    502 
    503   // If we're running, tell the media engine about it.
    504   bool ret = true;
    505   if (initialized_) {
    506     VideoOptions options(&device);
    507     ret = (Send(MSG_SETVIDEOOPTIONS, &options) && options.result);
    508   }
    509 
    510   // If everything worked, retain the name of the selected camera.
    511   if (ret) {
    512     camera_device_ = device.name;
    513   }
    514   return ret;
    515 }
    516 
    517 bool ChannelManager::SetVideoOptions_w(const Device* cam_device) {
    518   ASSERT(worker_thread_ == talk_base::Thread::Current());
    519   ASSERT(initialized_);
    520 
    521   // Set the video input device
    522   return media_engine_->SetVideoCaptureDevice(cam_device);
    523 }
    524 
    525 bool ChannelManager::SetDefaultVideoEncoderConfig(const VideoEncoderConfig& c) {
    526   bool ret = true;
    527   if (initialized_) {
    528     DefaultVideoEncoderConfig config(c);
    529     ret = Send(MSG_SETDEFAULTVIDEOENCODERCONFIG, &config) && config.result;
    530   }
    531   if (ret) {
    532     default_video_encoder_config_ = c;
    533   }
    534   return ret;
    535 }
    536 
    537 bool ChannelManager::SetDefaultVideoEncoderConfig_w(
    538     const VideoEncoderConfig& c) {
    539   ASSERT(worker_thread_ == talk_base::Thread::Current());
    540   ASSERT(initialized_);
    541   return media_engine_->SetDefaultVideoEncoderConfig(c);
    542 }
    543 
    544 bool ChannelManager::SetLocalMonitor(bool enable) {
    545   LocalMonitor monitor(enable);
    546   bool ret = Send(MSG_SETLOCALMONITOR, &monitor) && monitor.result;
    547   if (ret) {
    548     monitoring_ = enable;
    549   }
    550   return ret;
    551 }
    552 
    553 bool ChannelManager::SetLocalMonitor_w(bool enable) {
    554   ASSERT(worker_thread_ == talk_base::Thread::Current());
    555   ASSERT(initialized_);
    556   return media_engine_->SetLocalMonitor(enable);
    557 }
    558 
    559 bool ChannelManager::SetLocalRenderer(VideoRenderer* renderer) {
    560   bool ret = true;
    561   if (initialized_) {
    562     LocalRenderer local(renderer);
    563     ret = (Send(MSG_SETLOCALRENDERER, &local) && local.result);
    564   }
    565   if (ret) {
    566     local_renderer_ = renderer;
    567   }
    568   return ret;
    569 }
    570 
    571 bool ChannelManager::SetLocalRenderer_w(VideoRenderer* renderer) {
    572   ASSERT(worker_thread_ == talk_base::Thread::Current());
    573   ASSERT(initialized_);
    574   return media_engine_->SetLocalRenderer(renderer);
    575 }
    576 
    577 CaptureResult ChannelManager::SetVideoCapture(bool capture) {
    578   bool ret;
    579   CaptureParams capture_params(capture);
    580   ret = (Send(MSG_SETVIDEOCAPTURE, &capture_params) &&
    581          (capture_params.result != CR_FAILURE));
    582   if (ret) {
    583     capturing_ = capture;
    584   }
    585   return capture_params.result;
    586 }
    587 
    588 CaptureResult ChannelManager::SetVideoCapture_w(bool capture) {
    589   ASSERT(worker_thread_ == talk_base::Thread::Current());
    590   ASSERT(initialized_);
    591   return media_engine_->SetVideoCapture(capture);
    592 }
    593 
    594 void ChannelManager::SetVoiceLogging(int level, const char* filter) {
    595   SetMediaLogging(false, level, filter);
    596 }
    597 
    598 void ChannelManager::SetVideoLogging(int level, const char* filter) {
    599   SetMediaLogging(true, level, filter);
    600 }
    601 
    602 void ChannelManager::SetMediaLogging(bool video, int level,
    603                                      const char* filter) {
    604   // Can be called before initialization; in this case, the worker function
    605   // is simply called on the main thread.
    606   if (initialized_) {
    607     LoggingOptions options(level, filter);
    608     Send((video) ? MSG_SETVIDEOLOGGING : MSG_SETVOICELOGGING, &options);
    609   } else {
    610     SetMediaLogging_w(video, level, filter);
    611   }
    612 }
    613 
    614 void ChannelManager::SetMediaLogging_w(bool video, int level,
    615                                        const char* filter) {
    616   // Can be called before initialization
    617   ASSERT(worker_thread_ == talk_base::Thread::Current() || !initialized_);
    618   if (video) {
    619     media_engine_->SetVideoLogging(level, filter);
    620   } else {
    621     media_engine_->SetVoiceLogging(level, filter);
    622   }
    623 }
    624 
    625 bool ChannelManager::Send(uint32 id, talk_base::MessageData* data) {
    626   if (!worker_thread_ || !initialized_) return false;
    627   worker_thread_->Send(this, id, data);
    628   return true;
    629 }
    630 
    631 void ChannelManager::OnVideoCaptureResult(CaptureResult result) {
    632   capturing_ = result == CR_SUCCESS;
    633   main_thread_->Post(this, MSG_CAMERASTARTED,
    634                      new talk_base::TypedMessageData<CaptureResult>(result));
    635 }
    636 
    637 void ChannelManager::OnMessage(talk_base::Message* message) {
    638   talk_base::MessageData* data = message->pdata;
    639   switch (message->message_id) {
    640     case MSG_CREATEVOICECHANNEL: {
    641       CreationParams* p = static_cast<CreationParams*>(data);
    642       p->voice_channel =
    643           CreateVoiceChannel_w(p->session, p->content_name, p->rtcp);
    644       break;
    645     }
    646     case MSG_DESTROYVOICECHANNEL: {
    647       VoiceChannel* p = static_cast<talk_base::TypedMessageData<VoiceChannel*>*>
    648           (data)->data();
    649       DestroyVoiceChannel_w(p);
    650       break;
    651     }
    652     case MSG_CREATEVIDEOCHANNEL: {
    653       CreationParams* p = static_cast<CreationParams*>(data);
    654       p->video_channel = CreateVideoChannel_w(p->session, p->content_name,
    655                                               p->rtcp, p->voice_channel);
    656       break;
    657     }
    658     case MSG_DESTROYVIDEOCHANNEL: {
    659       VideoChannel* p = static_cast<talk_base::TypedMessageData<VideoChannel*>*>
    660           (data)->data();
    661       DestroyVideoChannel_w(p);
    662       break;
    663     }
    664     case MSG_CREATESOUNDCLIP: {
    665       talk_base::TypedMessageData<Soundclip*> *p =
    666           static_cast<talk_base::TypedMessageData<Soundclip*>*>(data);
    667       p->data() = CreateSoundclip_w();
    668       break;
    669     }
    670     case MSG_DESTROYSOUNDCLIP: {
    671       talk_base::TypedMessageData<Soundclip*> *p =
    672           static_cast<talk_base::TypedMessageData<Soundclip*>*>(data);
    673       DestroySoundclip_w(p->data());
    674       break;
    675     }
    676     case MSG_SETAUDIOOPTIONS: {
    677       AudioOptions* p = static_cast<AudioOptions*>(data);
    678       p->result = SetAudioOptions_w(p->options,
    679                                     p->in_device, p->out_device);
    680       break;
    681     }
    682     case MSG_SETOUTPUTVOLUME: {
    683       VolumeLevel* p = static_cast<VolumeLevel*>(data);
    684       p->result = SetOutputVolume_w(p->level);
    685       break;
    686     }
    687     case MSG_SETLOCALMONITOR: {
    688       LocalMonitor* p = static_cast<LocalMonitor*>(data);
    689       p->result = SetLocalMonitor_w(p->enable);
    690       break;
    691     }
    692     case MSG_SETVIDEOOPTIONS: {
    693       VideoOptions* p = static_cast<VideoOptions*>(data);
    694       p->result = SetVideoOptions_w(p->cam_device);
    695       break;
    696     }
    697     case MSG_SETDEFAULTVIDEOENCODERCONFIG: {
    698       DefaultVideoEncoderConfig* p =
    699           static_cast<DefaultVideoEncoderConfig*>(data);
    700       p->result = SetDefaultVideoEncoderConfig_w(p->config);
    701       break;
    702     }
    703     case MSG_SETLOCALRENDERER: {
    704       LocalRenderer* p = static_cast<LocalRenderer*>(data);
    705       p->result = SetLocalRenderer_w(p->renderer);
    706       break;
    707     }
    708     case MSG_SETVIDEOCAPTURE: {
    709       CaptureParams* p = static_cast<CaptureParams*>(data);
    710       p->result = SetVideoCapture_w(p->capture);
    711       break;
    712     }
    713     case MSG_SETVOICELOGGING:
    714     case MSG_SETVIDEOLOGGING: {
    715       LoggingOptions* p = static_cast<LoggingOptions*>(data);
    716       bool video = (message->message_id == MSG_SETVIDEOLOGGING);
    717       SetMediaLogging_w(video, p->level, p->filter.c_str());
    718       break;
    719     }
    720     case MSG_CAMERASTARTED: {
    721       talk_base::TypedMessageData<CaptureResult>* data =
    722           static_cast<talk_base::TypedMessageData<CaptureResult>*>(
    723               message->pdata);
    724       SignalVideoCaptureResult(data->data());
    725       delete data;
    726       break;
    727     }
    728   }
    729 }
    730 
    731 static void GetDeviceNames(const std::vector<Device>& devs,
    732                            std::vector<std::string>* names) {
    733   names->clear();
    734   for (size_t i = 0; i < devs.size(); ++i) {
    735     names->push_back(devs[i].name);
    736   }
    737 }
    738 
    739 bool ChannelManager::GetAudioInputDevices(std::vector<std::string>* names) {
    740   names->clear();
    741   std::vector<Device> devs;
    742   bool ret = device_manager_->GetAudioInputDevices(&devs);
    743   if (ret)
    744     GetDeviceNames(devs, names);
    745 
    746   return ret;
    747 }
    748 
    749 bool ChannelManager::GetAudioOutputDevices(std::vector<std::string>* names) {
    750   names->clear();
    751   std::vector<Device> devs;
    752   bool ret = device_manager_->GetAudioOutputDevices(&devs);
    753   if (ret)
    754     GetDeviceNames(devs, names);
    755 
    756   return ret;
    757 }
    758 
    759 bool ChannelManager::GetVideoCaptureDevices(std::vector<std::string>* names) {
    760   names->clear();
    761   std::vector<Device> devs;
    762   bool ret = device_manager_->GetVideoCaptureDevices(&devs);
    763   if (ret)
    764     GetDeviceNames(devs, names);
    765 
    766   return ret;
    767 }
    768 
    769 }  // namespace cricket
    770