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 54namespace cricket { 55 56enum { 57 MSG_VIDEOCAPTURESTATE = 1, 58}; 59 60using rtc::Bind; 61 62static const int kNotSetOutputVolume = -1; 63 64struct 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 72static DataEngineInterface* ConstructDataEngine() { 73#ifdef HAVE_SCTP 74 return new HybridDataEngine(new RtpDataEngine(), new SctpDataEngine()); 75#else 76 return new RtpDataEngine(); 77#endif 78} 79 80ChannelManager::ChannelManager(MediaEngineInterface* me, 81 DataEngineInterface* dme, 82 CaptureManager* cm, 83 rtc::Thread* worker_thread) { 84 Construct(me, dme, cm, worker_thread); 85} 86 87ChannelManager::ChannelManager(MediaEngineInterface* me, 88 rtc::Thread* worker_thread) { 89 Construct(me, 90 ConstructDataEngine(), 91 new CaptureManager(), 92 worker_thread); 93} 94 95void 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 114ChannelManager::~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 130bool 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 145void 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 156void ChannelManager::GetSupportedAudioRtpHeaderExtensions( 157 RtpHeaderExtensions* ext) const { 158 *ext = media_engine_->GetAudioCapabilities().header_extensions; 159} 160 161void 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 175void ChannelManager::GetSupportedVideoRtpHeaderExtensions( 176 RtpHeaderExtensions* ext) const { 177 *ext = media_engine_->GetVideoCapabilities().header_extensions; 178} 179 180void ChannelManager::GetSupportedDataCodecs( 181 std::vector<DataCodec>* codecs) const { 182 *codecs = data_media_engine_->data_codecs(); 183} 184 185bool 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 218bool ChannelManager::InitMediaEngine_w() { 219 ASSERT(worker_thread_ == rtc::Thread::Current()); 220 return (media_engine_->Init(worker_thread_)); 221} 222 223void 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 232void ChannelManager::DestructorDeletes_w() { 233 ASSERT(worker_thread_ == rtc::Thread::Current()); 234 media_engine_.reset(NULL); 235 capture_manager_.reset(NULL); 236} 237 238void 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 250VoiceChannel* 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 261VoiceChannel* 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 286void 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 294void 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 308VideoChannel* 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 319VideoChannel* 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 344void 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 352void 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 367DataChannel* 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 377DataChannel* 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 403void 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 411void 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 425bool 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 433bool 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 448std::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 457void 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. 469bool 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 476bool 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 486bool 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 493bool 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 503bool 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 510bool 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 517bool ChannelManager::IsScreencastRunning() const { 518 return initialized_ && worker_thread_->Invoke<bool>( 519 Bind(&ChannelManager::IsScreencastRunning_w, this)); 520} 521 522bool 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 532void 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 541void 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 553bool ChannelManager::StartAecDump(rtc::PlatformFile file) { 554 return worker_thread_->Invoke<bool>( 555 Bind(&MediaEngineInterface::StartAecDump, media_engine_.get(), file)); 556} 557 558void ChannelManager::StopAecDump() { 559 worker_thread_->Invoke<void>( 560 Bind(&MediaEngineInterface::StopAecDump, media_engine_.get())); 561} 562 563bool ChannelManager::StartRtcEventLog(rtc::PlatformFile file) { 564 return worker_thread_->Invoke<bool>( 565 Bind(&MediaEngineInterface::StartRtcEventLog, media_engine_.get(), file)); 566} 567 568void ChannelManager::StopRtcEventLog() { 569 worker_thread_->Invoke<void>( 570 Bind(&MediaEngineInterface::StopRtcEventLog, media_engine_.get())); 571} 572 573} // namespace cricket 574