Home | History | Annotate | Download | only in media
      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/app/webrtc/mediacontroller.h"
     37 #include "talk/media/base/capturemanager.h"
     38 #include "talk/media/base/device.h"
     39 #include "talk/media/base/hybriddataengine.h"
     40 #include "talk/media/base/rtpdataengine.h"
     41 #include "talk/media/base/videocapturer.h"
     42 #ifdef HAVE_SCTP
     43 #include "talk/media/sctp/sctpdataengine.h"
     44 #endif
     45 #include "talk/session/media/srtpfilter.h"
     46 #include "webrtc/base/bind.h"
     47 #include "webrtc/base/common.h"
     48 #include "webrtc/base/logging.h"
     49 #include "webrtc/base/sigslotrepeater.h"
     50 #include "webrtc/base/stringencode.h"
     51 #include "webrtc/base/stringutils.h"
     52 #include "webrtc/base/trace_event.h"
     53 
     54 namespace cricket {
     55 
     56 enum {
     57   MSG_VIDEOCAPTURESTATE = 1,
     58 };
     59 
     60 using rtc::Bind;
     61 
     62 static const int kNotSetOutputVolume = -1;
     63 
     64 struct CaptureStateParams : public rtc::MessageData {
     65   CaptureStateParams(cricket::VideoCapturer* c, cricket::CaptureState s)
     66       : capturer(c),
     67         state(s) {}
     68   cricket::VideoCapturer* capturer;
     69   cricket::CaptureState state;
     70 };
     71 
     72 static DataEngineInterface* ConstructDataEngine() {
     73 #ifdef HAVE_SCTP
     74   return new HybridDataEngine(new RtpDataEngine(), new SctpDataEngine());
     75 #else
     76   return new RtpDataEngine();
     77 #endif
     78 }
     79 
     80 ChannelManager::ChannelManager(MediaEngineInterface* me,
     81                                DataEngineInterface* dme,
     82                                CaptureManager* cm,
     83                                rtc::Thread* worker_thread) {
     84   Construct(me, dme, cm, worker_thread);
     85 }
     86 
     87 ChannelManager::ChannelManager(MediaEngineInterface* me,
     88                                rtc::Thread* worker_thread) {
     89   Construct(me,
     90             ConstructDataEngine(),
     91             new CaptureManager(),
     92             worker_thread);
     93 }
     94 
     95 void ChannelManager::Construct(MediaEngineInterface* me,
     96                                DataEngineInterface* dme,
     97                                CaptureManager* cm,
     98                                rtc::Thread* worker_thread) {
     99   media_engine_.reset(me);
    100   data_media_engine_.reset(dme);
    101   capture_manager_.reset(cm);
    102   initialized_ = false;
    103   main_thread_ = rtc::Thread::Current();
    104   worker_thread_ = worker_thread;
    105   audio_output_volume_ = kNotSetOutputVolume;
    106   local_renderer_ = NULL;
    107   capturing_ = false;
    108   enable_rtx_ = false;
    109 
    110   capture_manager_->SignalCapturerStateChange.connect(
    111       this, &ChannelManager::OnVideoCaptureStateChange);
    112 }
    113 
    114 ChannelManager::~ChannelManager() {
    115   if (initialized_) {
    116     Terminate();
    117     // If srtp is initialized (done by the Channel) then we must call
    118     // srtp_shutdown to free all crypto kernel lists. But we need to make sure
    119     // shutdown always called at the end, after channels are destroyed.
    120     // ChannelManager d'tor is always called last, it's safe place to call
    121     // shutdown.
    122     ShutdownSrtp();
    123   }
    124   // Some deletes need to be on the worker thread for thread safe destruction,
    125   // this includes the media engine and capture manager.
    126   worker_thread_->Invoke<void>(Bind(
    127       &ChannelManager::DestructorDeletes_w, this));
    128 }
    129 
    130 bool ChannelManager::SetVideoRtxEnabled(bool enable) {
    131   // To be safe, this call is only allowed before initialization. Apps like
    132   // Flute only have a singleton ChannelManager and we don't want this flag to
    133   // be toggled between calls or when there's concurrent calls. We expect apps
    134   // to enable this at startup and retain that setting for the lifetime of the
    135   // app.
    136   if (!initialized_) {
    137     enable_rtx_ = enable;
    138     return true;
    139   } else {
    140     LOG(LS_WARNING) << "Cannot toggle rtx after initialization!";
    141     return false;
    142   }
    143 }
    144 
    145 void ChannelManager::GetSupportedAudioCodecs(
    146     std::vector<AudioCodec>* codecs) const {
    147   codecs->clear();
    148 
    149   for (std::vector<AudioCodec>::const_iterator it =
    150            media_engine_->audio_codecs().begin();
    151       it != media_engine_->audio_codecs().end(); ++it) {
    152     codecs->push_back(*it);
    153   }
    154 }
    155 
    156 void ChannelManager::GetSupportedAudioRtpHeaderExtensions(
    157     RtpHeaderExtensions* ext) const {
    158   *ext = media_engine_->GetAudioCapabilities().header_extensions;
    159 }
    160 
    161 void ChannelManager::GetSupportedVideoCodecs(
    162     std::vector<VideoCodec>* codecs) const {
    163   codecs->clear();
    164 
    165   std::vector<VideoCodec>::const_iterator it;
    166   for (it = media_engine_->video_codecs().begin();
    167       it != media_engine_->video_codecs().end(); ++it) {
    168     if (!enable_rtx_ && _stricmp(kRtxCodecName, it->name.c_str()) == 0) {
    169       continue;
    170     }
    171     codecs->push_back(*it);
    172   }
    173 }
    174 
    175 void ChannelManager::GetSupportedVideoRtpHeaderExtensions(
    176     RtpHeaderExtensions* ext) const {
    177   *ext = media_engine_->GetVideoCapabilities().header_extensions;
    178 }
    179 
    180 void ChannelManager::GetSupportedDataCodecs(
    181     std::vector<DataCodec>* codecs) const {
    182   *codecs = data_media_engine_->data_codecs();
    183 }
    184 
    185 bool ChannelManager::Init() {
    186   ASSERT(!initialized_);
    187   if (initialized_) {
    188     return false;
    189   }
    190   ASSERT(worker_thread_ != NULL);
    191   if (!worker_thread_) {
    192     return false;
    193   }
    194   if (worker_thread_ != rtc::Thread::Current()) {
    195     // Do not allow invoking calls to other threads on the worker thread.
    196     worker_thread_->Invoke<bool>(rtc::Bind(
    197         &rtc::Thread::SetAllowBlockingCalls, worker_thread_, false));
    198   }
    199 
    200   initialized_ = worker_thread_->Invoke<bool>(Bind(
    201       &ChannelManager::InitMediaEngine_w, this));
    202   ASSERT(initialized_);
    203   if (!initialized_) {
    204     return false;
    205   }
    206 
    207   // If audio_output_volume_ has been set via SetOutputVolume(), set the
    208   // audio output volume of the engine.
    209   if (kNotSetOutputVolume != audio_output_volume_ &&
    210       !SetOutputVolume(audio_output_volume_)) {
    211     LOG(LS_WARNING) << "Failed to SetOutputVolume to "
    212                     << audio_output_volume_;
    213   }
    214 
    215   return initialized_;
    216 }
    217 
    218 bool ChannelManager::InitMediaEngine_w() {
    219   ASSERT(worker_thread_ == rtc::Thread::Current());
    220   return (media_engine_->Init(worker_thread_));
    221 }
    222 
    223 void ChannelManager::Terminate() {
    224   ASSERT(initialized_);
    225   if (!initialized_) {
    226     return;
    227   }
    228   worker_thread_->Invoke<void>(Bind(&ChannelManager::Terminate_w, this));
    229   initialized_ = false;
    230 }
    231 
    232 void ChannelManager::DestructorDeletes_w() {
    233   ASSERT(worker_thread_ == rtc::Thread::Current());
    234   media_engine_.reset(NULL);
    235   capture_manager_.reset(NULL);
    236 }
    237 
    238 void ChannelManager::Terminate_w() {
    239   ASSERT(worker_thread_ == rtc::Thread::Current());
    240   // Need to destroy the voice/video channels
    241   while (!video_channels_.empty()) {
    242     DestroyVideoChannel_w(video_channels_.back());
    243   }
    244   while (!voice_channels_.empty()) {
    245     DestroyVoiceChannel_w(voice_channels_.back());
    246   }
    247   media_engine_->Terminate();
    248 }
    249 
    250 VoiceChannel* ChannelManager::CreateVoiceChannel(
    251     webrtc::MediaControllerInterface* media_controller,
    252     TransportController* transport_controller,
    253     const std::string& content_name,
    254     bool rtcp,
    255     const AudioOptions& options) {
    256   return worker_thread_->Invoke<VoiceChannel*>(
    257       Bind(&ChannelManager::CreateVoiceChannel_w, this, media_controller,
    258            transport_controller, content_name, rtcp, options));
    259 }
    260 
    261 VoiceChannel* ChannelManager::CreateVoiceChannel_w(
    262     webrtc::MediaControllerInterface* media_controller,
    263     TransportController* transport_controller,
    264     const std::string& content_name,
    265     bool rtcp,
    266     const AudioOptions& options) {
    267   ASSERT(initialized_);
    268   ASSERT(worker_thread_ == rtc::Thread::Current());
    269   ASSERT(nullptr != media_controller);
    270   VoiceMediaChannel* media_channel =
    271       media_engine_->CreateChannel(media_controller->call_w(), options);
    272   if (!media_channel)
    273     return nullptr;
    274 
    275   VoiceChannel* voice_channel =
    276       new VoiceChannel(worker_thread_, media_engine_.get(), media_channel,
    277                        transport_controller, content_name, rtcp);
    278   if (!voice_channel->Init()) {
    279     delete voice_channel;
    280     return nullptr;
    281   }
    282   voice_channels_.push_back(voice_channel);
    283   return voice_channel;
    284 }
    285 
    286 void ChannelManager::DestroyVoiceChannel(VoiceChannel* voice_channel) {
    287   TRACE_EVENT0("webrtc", "ChannelManager::DestroyVoiceChannel");
    288   if (voice_channel) {
    289     worker_thread_->Invoke<void>(
    290         Bind(&ChannelManager::DestroyVoiceChannel_w, this, voice_channel));
    291   }
    292 }
    293 
    294 void ChannelManager::DestroyVoiceChannel_w(VoiceChannel* voice_channel) {
    295   TRACE_EVENT0("webrtc", "ChannelManager::DestroyVoiceChannel_w");
    296   // Destroy voice channel.
    297   ASSERT(initialized_);
    298   ASSERT(worker_thread_ == rtc::Thread::Current());
    299   VoiceChannels::iterator it = std::find(voice_channels_.begin(),
    300       voice_channels_.end(), voice_channel);
    301   ASSERT(it != voice_channels_.end());
    302   if (it == voice_channels_.end())
    303     return;
    304   voice_channels_.erase(it);
    305   delete voice_channel;
    306 }
    307 
    308 VideoChannel* ChannelManager::CreateVideoChannel(
    309     webrtc::MediaControllerInterface* media_controller,
    310     TransportController* transport_controller,
    311     const std::string& content_name,
    312     bool rtcp,
    313     const VideoOptions& options) {
    314   return worker_thread_->Invoke<VideoChannel*>(
    315       Bind(&ChannelManager::CreateVideoChannel_w, this, media_controller,
    316            transport_controller, content_name, rtcp, options));
    317 }
    318 
    319 VideoChannel* ChannelManager::CreateVideoChannel_w(
    320     webrtc::MediaControllerInterface* media_controller,
    321     TransportController* transport_controller,
    322     const std::string& content_name,
    323     bool rtcp,
    324     const VideoOptions& options) {
    325   ASSERT(initialized_);
    326   ASSERT(worker_thread_ == rtc::Thread::Current());
    327   ASSERT(nullptr != media_controller);
    328   VideoMediaChannel* media_channel =
    329       media_engine_->CreateVideoChannel(media_controller->call_w(), options);
    330   if (media_channel == NULL) {
    331     return NULL;
    332   }
    333 
    334   VideoChannel* video_channel = new VideoChannel(
    335       worker_thread_, media_channel, transport_controller, content_name, rtcp);
    336   if (!video_channel->Init()) {
    337     delete video_channel;
    338     return NULL;
    339   }
    340   video_channels_.push_back(video_channel);
    341   return video_channel;
    342 }
    343 
    344 void ChannelManager::DestroyVideoChannel(VideoChannel* video_channel) {
    345   TRACE_EVENT0("webrtc", "ChannelManager::DestroyVideoChannel");
    346   if (video_channel) {
    347     worker_thread_->Invoke<void>(
    348         Bind(&ChannelManager::DestroyVideoChannel_w, this, video_channel));
    349   }
    350 }
    351 
    352 void ChannelManager::DestroyVideoChannel_w(VideoChannel* video_channel) {
    353   TRACE_EVENT0("webrtc", "ChannelManager::DestroyVideoChannel_w");
    354   // Destroy video channel.
    355   ASSERT(initialized_);
    356   ASSERT(worker_thread_ == rtc::Thread::Current());
    357   VideoChannels::iterator it = std::find(video_channels_.begin(),
    358       video_channels_.end(), video_channel);
    359   ASSERT(it != video_channels_.end());
    360   if (it == video_channels_.end())
    361     return;
    362 
    363   video_channels_.erase(it);
    364   delete video_channel;
    365 }
    366 
    367 DataChannel* ChannelManager::CreateDataChannel(
    368     TransportController* transport_controller,
    369     const std::string& content_name,
    370     bool rtcp,
    371     DataChannelType channel_type) {
    372   return worker_thread_->Invoke<DataChannel*>(
    373       Bind(&ChannelManager::CreateDataChannel_w, this, transport_controller,
    374            content_name, rtcp, channel_type));
    375 }
    376 
    377 DataChannel* ChannelManager::CreateDataChannel_w(
    378     TransportController* transport_controller,
    379     const std::string& content_name,
    380     bool rtcp,
    381     DataChannelType data_channel_type) {
    382   // This is ok to alloc from a thread other than the worker thread.
    383   ASSERT(initialized_);
    384   DataMediaChannel* media_channel = data_media_engine_->CreateChannel(
    385       data_channel_type);
    386   if (!media_channel) {
    387     LOG(LS_WARNING) << "Failed to create data channel of type "
    388                     << data_channel_type;
    389     return NULL;
    390   }
    391 
    392   DataChannel* data_channel = new DataChannel(
    393       worker_thread_, media_channel, transport_controller, content_name, rtcp);
    394   if (!data_channel->Init()) {
    395     LOG(LS_WARNING) << "Failed to init data channel.";
    396     delete data_channel;
    397     return NULL;
    398   }
    399   data_channels_.push_back(data_channel);
    400   return data_channel;
    401 }
    402 
    403 void ChannelManager::DestroyDataChannel(DataChannel* data_channel) {
    404   TRACE_EVENT0("webrtc", "ChannelManager::DestroyDataChannel");
    405   if (data_channel) {
    406     worker_thread_->Invoke<void>(
    407         Bind(&ChannelManager::DestroyDataChannel_w, this, data_channel));
    408   }
    409 }
    410 
    411 void ChannelManager::DestroyDataChannel_w(DataChannel* data_channel) {
    412   TRACE_EVENT0("webrtc", "ChannelManager::DestroyDataChannel_w");
    413   // Destroy data channel.
    414   ASSERT(initialized_);
    415   DataChannels::iterator it = std::find(data_channels_.begin(),
    416       data_channels_.end(), data_channel);
    417   ASSERT(it != data_channels_.end());
    418   if (it == data_channels_.end())
    419     return;
    420 
    421   data_channels_.erase(it);
    422   delete data_channel;
    423 }
    424 
    425 bool ChannelManager::GetOutputVolume(int* level) {
    426   if (!initialized_) {
    427     return false;
    428   }
    429   return worker_thread_->Invoke<bool>(
    430       Bind(&MediaEngineInterface::GetOutputVolume, media_engine_.get(), level));
    431 }
    432 
    433 bool ChannelManager::SetOutputVolume(int level) {
    434   bool ret = level >= 0 && level <= 255;
    435   if (initialized_) {
    436     ret &= worker_thread_->Invoke<bool>(
    437         Bind(&MediaEngineInterface::SetOutputVolume,
    438              media_engine_.get(), level));
    439   }
    440 
    441   if (ret) {
    442     audio_output_volume_ = level;
    443   }
    444 
    445   return ret;
    446 }
    447 
    448 std::vector<cricket::VideoFormat> ChannelManager::GetSupportedFormats(
    449     VideoCapturer* capturer) const {
    450   ASSERT(capturer != NULL);
    451   std::vector<VideoFormat> formats;
    452   worker_thread_->Invoke<void>(rtc::Bind(&ChannelManager::GetSupportedFormats_w,
    453                                          this, capturer, &formats));
    454   return formats;
    455 }
    456 
    457 void ChannelManager::GetSupportedFormats_w(
    458     VideoCapturer* capturer,
    459     std::vector<cricket::VideoFormat>* out_formats) const {
    460   const std::vector<VideoFormat>* formats = capturer->GetSupportedFormats();
    461   if (formats != NULL)
    462     *out_formats = *formats;
    463 }
    464 
    465 // The following are done in the new "CaptureManager" style that
    466 // all local video capturers, processors, and managers should move
    467 // to.
    468 // TODO(pthatcher): Add more of the CaptureManager interface.
    469 bool ChannelManager::StartVideoCapture(
    470     VideoCapturer* capturer, const VideoFormat& video_format) {
    471   return initialized_ && worker_thread_->Invoke<bool>(
    472       Bind(&CaptureManager::StartVideoCapture,
    473            capture_manager_.get(), capturer, video_format));
    474 }
    475 
    476 bool ChannelManager::MuteToBlackThenPause(
    477     VideoCapturer* video_capturer, bool muted) {
    478   if (!initialized_) {
    479     return false;
    480   }
    481   worker_thread_->Invoke<void>(
    482       Bind(&VideoCapturer::MuteToBlackThenPause, video_capturer, muted));
    483   return true;
    484 }
    485 
    486 bool ChannelManager::StopVideoCapture(
    487     VideoCapturer* capturer, const VideoFormat& video_format) {
    488   return initialized_ && worker_thread_->Invoke<bool>(
    489       Bind(&CaptureManager::StopVideoCapture,
    490            capture_manager_.get(), capturer, video_format));
    491 }
    492 
    493 bool ChannelManager::RestartVideoCapture(
    494     VideoCapturer* video_capturer,
    495     const VideoFormat& previous_format,
    496     const VideoFormat& desired_format,
    497     CaptureManager::RestartOptions options) {
    498   return initialized_ && worker_thread_->Invoke<bool>(
    499       Bind(&CaptureManager::RestartVideoCapture, capture_manager_.get(),
    500            video_capturer, previous_format, desired_format, options));
    501 }
    502 
    503 bool ChannelManager::AddVideoRenderer(
    504     VideoCapturer* capturer, VideoRenderer* renderer) {
    505   return initialized_ && worker_thread_->Invoke<bool>(
    506       Bind(&CaptureManager::AddVideoRenderer,
    507            capture_manager_.get(), capturer, renderer));
    508 }
    509 
    510 bool ChannelManager::RemoveVideoRenderer(
    511     VideoCapturer* capturer, VideoRenderer* renderer) {
    512   return initialized_ && worker_thread_->Invoke<bool>(
    513       Bind(&CaptureManager::RemoveVideoRenderer,
    514            capture_manager_.get(), capturer, renderer));
    515 }
    516 
    517 bool ChannelManager::IsScreencastRunning() const {
    518   return initialized_ && worker_thread_->Invoke<bool>(
    519       Bind(&ChannelManager::IsScreencastRunning_w, this));
    520 }
    521 
    522 bool ChannelManager::IsScreencastRunning_w() const {
    523   VideoChannels::const_iterator it = video_channels_.begin();
    524   for ( ; it != video_channels_.end(); ++it) {
    525     if ((*it) && (*it)->IsScreencasting()) {
    526       return true;
    527     }
    528   }
    529   return false;
    530 }
    531 
    532 void ChannelManager::OnVideoCaptureStateChange(VideoCapturer* capturer,
    533                                                CaptureState result) {
    534   // TODO(whyuan): Check capturer and signal failure only for camera video, not
    535   // screencast.
    536   capturing_ = result == CS_RUNNING;
    537   main_thread_->Post(this, MSG_VIDEOCAPTURESTATE,
    538                      new CaptureStateParams(capturer, result));
    539 }
    540 
    541 void ChannelManager::OnMessage(rtc::Message* message) {
    542   switch (message->message_id) {
    543     case MSG_VIDEOCAPTURESTATE: {
    544       CaptureStateParams* data =
    545           static_cast<CaptureStateParams*>(message->pdata);
    546       SignalVideoCaptureStateChange(data->capturer, data->state);
    547       delete data;
    548       break;
    549     }
    550   }
    551 }
    552 
    553 bool ChannelManager::StartAecDump(rtc::PlatformFile file) {
    554   return worker_thread_->Invoke<bool>(
    555       Bind(&MediaEngineInterface::StartAecDump, media_engine_.get(), file));
    556 }
    557 
    558 void ChannelManager::StopAecDump() {
    559   worker_thread_->Invoke<void>(
    560       Bind(&MediaEngineInterface::StopAecDump, media_engine_.get()));
    561 }
    562 
    563 bool ChannelManager::StartRtcEventLog(rtc::PlatformFile file) {
    564   return worker_thread_->Invoke<bool>(
    565       Bind(&MediaEngineInterface::StartRtcEventLog, media_engine_.get(), file));
    566 }
    567 
    568 void ChannelManager::StopRtcEventLog() {
    569   worker_thread_->Invoke<void>(
    570       Bind(&MediaEngineInterface::StopRtcEventLog, media_engine_.get()));
    571 }
    572 
    573 }  // namespace cricket
    574