| /* |
| * libjingle |
| * Copyright 2004--2008, Google Inc. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * 3. The name of the author may not be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
| * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
| * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
| * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
| * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "talk/session/phone/channelmanager.h" |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| |
| #include <algorithm> |
| |
| #include "talk/base/common.h" |
| #include "talk/base/logging.h" |
| #include "talk/base/sigslotrepeater.h" |
| #include "talk/base/stringencode.h" |
| #include "talk/session/phone/soundclip.h" |
| |
| namespace cricket { |
| |
| enum { |
| MSG_CREATEVOICECHANNEL = 1, |
| MSG_DESTROYVOICECHANNEL = 2, |
| MSG_SETAUDIOOPTIONS = 3, |
| MSG_GETOUTPUTVOLUME = 4, |
| MSG_SETOUTPUTVOLUME = 5, |
| MSG_SETLOCALMONITOR = 6, |
| MSG_SETVOICELOGGING = 7, |
| MSG_CREATEVIDEOCHANNEL = 11, |
| MSG_DESTROYVIDEOCHANNEL = 12, |
| MSG_SETVIDEOOPTIONS = 13, |
| MSG_SETLOCALRENDERER = 14, |
| MSG_SETDEFAULTVIDEOENCODERCONFIG = 15, |
| MSG_SETVIDEOLOGGING = 16, |
| MSG_CREATESOUNDCLIP = 17, |
| MSG_DESTROYSOUNDCLIP = 18, |
| MSG_CAMERASTARTED = 19, |
| MSG_SETVIDEOCAPTURE = 20, |
| MSG_TERMINATE = 21, |
| MSG_REGISTERVIDEOPROCESSOR = 22, |
| MSG_UNREGISTERVIDEOPROCESSOR = 23, |
| MSG_REGISTERVOICEPROCESSOR = 24, |
| MSG_UNREGISTERVOICEPROCESSOR = 25, |
| MSG_SETVIDEOCAPTURER = 26, |
| }; |
| |
| struct CreationParams : public talk_base::MessageData { |
| CreationParams(BaseSession* session, const std::string& content_name, |
| bool rtcp, VoiceChannel* voice_channel) |
| : session(session), |
| content_name(content_name), |
| rtcp(rtcp), |
| voice_channel(voice_channel), |
| video_channel(NULL) {} |
| BaseSession* session; |
| std::string content_name; |
| bool rtcp; |
| VoiceChannel* voice_channel; |
| VideoChannel* video_channel; |
| }; |
| |
| struct AudioOptions : public talk_base::MessageData { |
| AudioOptions(int o, const Device* in, const Device* out) |
| : options(o), in_device(in), out_device(out) {} |
| int options; |
| const Device* in_device; |
| const Device* out_device; |
| bool result; |
| }; |
| |
| struct VolumeLevel : public talk_base::MessageData { |
| VolumeLevel() : level(-1), result(false) {} |
| explicit VolumeLevel(int l) : level(l), result(false) {} |
| int level; |
| bool result; |
| }; |
| |
| struct VideoOptions : public talk_base::MessageData { |
| explicit VideoOptions(const Device* d) : cam_device(d), result(false) {} |
| const Device* cam_device; |
| bool result; |
| }; |
| |
| struct DefaultVideoEncoderConfig : public talk_base::MessageData { |
| explicit DefaultVideoEncoderConfig(const VideoEncoderConfig& c) |
| : config(c), result(false) {} |
| VideoEncoderConfig config; |
| bool result; |
| }; |
| |
| struct LocalMonitor : public talk_base::MessageData { |
| explicit LocalMonitor(bool e) : enable(e), result(false) {} |
| bool enable; |
| bool result; |
| }; |
| |
| struct LocalRenderer : public talk_base::MessageData { |
| explicit LocalRenderer(VideoRenderer* r) : renderer(r), result(false) {} |
| VideoRenderer* renderer; |
| bool result; |
| }; |
| |
| struct Capturer : public talk_base::MessageData { |
| Capturer(VideoCapturer* c, uint32 s) |
| : capturer(c), |
| ssrc(s), |
| result(false) {} |
| VideoCapturer* capturer; |
| uint32 ssrc; |
| bool result; |
| }; |
| |
| struct LoggingOptions : public talk_base::MessageData { |
| explicit LoggingOptions(int lev, const char* f) : level(lev), filter(f) {} |
| int level; |
| std::string filter; |
| }; |
| |
| struct CaptureParams : public talk_base::MessageData { |
| explicit CaptureParams(bool c) : capture(c), result(CR_FAILURE) {} |
| bool capture; |
| CaptureResult result; |
| }; |
| |
| struct VideoProcessorParams : public talk_base::MessageData { |
| VideoProcessorParams(uint32 s, VideoProcessor* p) |
| : ssrc(s), processor(p), result(false) {} |
| uint32 ssrc; |
| VideoProcessor* processor; |
| bool result; |
| }; |
| |
| struct VoiceProcessorParams : public talk_base::MessageData { |
| VoiceProcessorParams(uint32 c, VoiceProcessor* p, MediaProcessorDirection d) |
| : ssrc(c), direction(d), processor(p), result(false) {} |
| uint32 ssrc; |
| MediaProcessorDirection direction; |
| VoiceProcessor* processor; |
| bool result; |
| }; |
| |
| ChannelManager::ChannelManager(talk_base::Thread* worker_thread) |
| : media_engine_(MediaEngineFactory::Create()), |
| device_manager_(cricket::DeviceManagerFactory::Create()), |
| initialized_(false), |
| main_thread_(talk_base::Thread::Current()), |
| worker_thread_(worker_thread), |
| audio_in_device_(DeviceManagerInterface::kDefaultDeviceName), |
| audio_out_device_(DeviceManagerInterface::kDefaultDeviceName), |
| audio_options_(MediaEngineInterface::DEFAULT_AUDIO_OPTIONS), |
| local_renderer_(NULL), |
| capturing_(false), |
| monitoring_(false) { |
| Construct(); |
| } |
| |
| ChannelManager::ChannelManager(MediaEngineInterface* me, |
| DeviceManagerInterface* dm, |
| talk_base::Thread* worker_thread) |
| : media_engine_(me), |
| device_manager_(dm), |
| initialized_(false), |
| main_thread_(talk_base::Thread::Current()), |
| worker_thread_(worker_thread), |
| audio_in_device_(DeviceManagerInterface::kDefaultDeviceName), |
| audio_out_device_(DeviceManagerInterface::kDefaultDeviceName), |
| audio_options_(MediaEngineInterface::DEFAULT_AUDIO_OPTIONS), |
| local_renderer_(NULL), |
| capturing_(false), |
| monitoring_(false) { |
| Construct(); |
| } |
| |
| void ChannelManager::Construct() { |
| // Init the device manager immediately, and set up our default video device. |
| SignalDevicesChange.repeat(device_manager_->SignalDevicesChange); |
| device_manager_->Init(); |
| // Set camera_device_ to the name of the default video capturer. |
| SetVideoOptions(DeviceManagerInterface::kDefaultDeviceName); |
| |
| // Camera is started asynchronously, request callbacks when startup |
| // completes to be able to forward them to the rendering manager. |
| media_engine_->SignalVideoCaptureResult.connect( |
| this, &ChannelManager::OnVideoCaptureResult); |
| } |
| |
| ChannelManager::~ChannelManager() { |
| if (initialized_) |
| Terminate(); |
| } |
| |
| int ChannelManager::GetCapabilities() { |
| return media_engine_->GetCapabilities() & device_manager_->GetCapabilities(); |
| } |
| |
| void ChannelManager::GetSupportedAudioCodecs( |
| std::vector<AudioCodec>* codecs) const { |
| codecs->clear(); |
| |
| for (std::vector<AudioCodec>::const_iterator it = |
| media_engine_->audio_codecs().begin(); |
| it != media_engine_->audio_codecs().end(); ++it) { |
| codecs->push_back(*it); |
| } |
| } |
| |
| void ChannelManager::GetSupportedVideoCodecs( |
| std::vector<VideoCodec>* codecs) const { |
| codecs->clear(); |
| |
| std::vector<VideoCodec>::const_iterator it; |
| for (it = media_engine_->video_codecs().begin(); |
| it != media_engine_->video_codecs().end(); ++it) { |
| codecs->push_back(*it); |
| } |
| } |
| |
| bool ChannelManager::Init() { |
| ASSERT(!initialized_); |
| if (initialized_) { |
| return false; |
| } |
| |
| ASSERT(worker_thread_ != NULL); |
| if (worker_thread_ && worker_thread_->started()) { |
| if (media_engine_->Init()) { |
| initialized_ = true; |
| |
| // Now that we're initialized, apply any stored preferences. A preferred |
| // device might have been unplugged. In this case, we fallback to the |
| // default device but keep the user preferences. The preferences are |
| // changed only when the Javascript FE changes them. |
| const std::string preferred_audio_in_device = audio_in_device_; |
| const std::string preferred_audio_out_device = audio_out_device_; |
| const std::string preferred_camera_device = camera_device_; |
| Device device; |
| if (!device_manager_->GetAudioInputDevice(audio_in_device_, &device)) { |
| LOG(LS_WARNING) << "The preferred microphone '" << audio_in_device_ |
| << "' is unavailable. Fall back to the default."; |
| audio_in_device_ = DeviceManagerInterface::kDefaultDeviceName; |
| } |
| if (!device_manager_->GetAudioOutputDevice(audio_out_device_, &device)) { |
| LOG(LS_WARNING) << "The preferred speaker '" << audio_out_device_ |
| << "' is unavailable. Fall back to the default."; |
| audio_out_device_ = DeviceManagerInterface::kDefaultDeviceName; |
| } |
| if (!device_manager_->GetVideoCaptureDevice(camera_device_, &device)) { |
| if (!camera_device_.empty()) { |
| LOG(LS_WARNING) << "The preferred camera '" << camera_device_ |
| << "' is unavailable. Fall back to the default."; |
| } |
| camera_device_ = DeviceManagerInterface::kDefaultDeviceName; |
| } |
| |
| if (!SetAudioOptions(audio_in_device_, audio_out_device_, |
| audio_options_)) { |
| LOG(LS_WARNING) << "Failed to SetAudioOptions with" |
| << " microphone: " << audio_in_device_ |
| << " speaker: " << audio_out_device_ |
| << " options: " << audio_options_; |
| } |
| if (!SetVideoOptions(camera_device_) && !camera_device_.empty()) { |
| LOG(LS_WARNING) << "Failed to SetVideoOptions with camera: " |
| << camera_device_; |
| } |
| |
| // Restore the user preferences. |
| audio_in_device_ = preferred_audio_in_device; |
| audio_out_device_ = preferred_audio_out_device; |
| camera_device_ = preferred_camera_device; |
| |
| // Now apply the default video codec that has been set earlier. |
| if (default_video_encoder_config_.max_codec.id != 0) { |
| SetDefaultVideoEncoderConfig(default_video_encoder_config_); |
| } |
| // And the local renderer. |
| if (local_renderer_) { |
| SetLocalRenderer(local_renderer_); |
| } |
| } |
| } |
| return initialized_; |
| } |
| |
| void ChannelManager::Terminate() { |
| ASSERT(initialized_); |
| if (!initialized_) { |
| return; |
| } |
| Send(MSG_TERMINATE, NULL); |
| media_engine_->Terminate(); |
| initialized_ = false; |
| } |
| |
| void ChannelManager::Terminate_w() { |
| ASSERT(worker_thread_ == talk_base::Thread::Current()); |
| // Need to destroy the voice/video channels |
| while (!video_channels_.empty()) { |
| DestroyVideoChannel_w(video_channels_.back()); |
| } |
| while (!voice_channels_.empty()) { |
| DestroyVoiceChannel_w(voice_channels_.back()); |
| } |
| while (!soundclips_.empty()) { |
| DestroySoundclip_w(soundclips_.back()); |
| } |
| } |
| |
| VoiceChannel* ChannelManager::CreateVoiceChannel( |
| BaseSession* session, const std::string& content_name, bool rtcp) { |
| CreationParams params(session, content_name, rtcp, NULL); |
| return (Send(MSG_CREATEVOICECHANNEL, ¶ms)) ? params.voice_channel : NULL; |
| } |
| |
| VoiceChannel* ChannelManager::CreateVoiceChannel_w( |
| BaseSession* session, const std::string& content_name, bool rtcp) { |
| // This is ok to alloc from a thread other than the worker thread |
| ASSERT(initialized_); |
| VoiceMediaChannel* media_channel = media_engine_->CreateChannel(); |
| if (media_channel == NULL) |
| return NULL; |
| |
| VoiceChannel* voice_channel = new VoiceChannel( |
| worker_thread_, media_engine_.get(), media_channel, |
| session, content_name, rtcp); |
| if (!voice_channel->Init()) { |
| delete voice_channel; |
| return NULL; |
| } |
| voice_channels_.push_back(voice_channel); |
| return voice_channel; |
| } |
| |
| void ChannelManager::DestroyVoiceChannel(VoiceChannel* voice_channel) { |
| if (voice_channel) { |
| talk_base::TypedMessageData<VoiceChannel *> data(voice_channel); |
| Send(MSG_DESTROYVOICECHANNEL, &data); |
| } |
| } |
| |
| void ChannelManager::DestroyVoiceChannel_w(VoiceChannel* voice_channel) { |
| // Destroy voice channel. |
| ASSERT(initialized_); |
| VoiceChannels::iterator it = std::find(voice_channels_.begin(), |
| voice_channels_.end(), voice_channel); |
| ASSERT(it != voice_channels_.end()); |
| if (it == voice_channels_.end()) |
| return; |
| |
| voice_channels_.erase(it); |
| delete voice_channel; |
| } |
| |
| VideoChannel* ChannelManager::CreateVideoChannel( |
| BaseSession* session, const std::string& content_name, bool rtcp, |
| VoiceChannel* voice_channel) { |
| CreationParams params(session, content_name, rtcp, voice_channel); |
| return (Send(MSG_CREATEVIDEOCHANNEL, ¶ms)) ? params.video_channel : NULL; |
| } |
| |
| VideoChannel* ChannelManager::CreateVideoChannel_w( |
| BaseSession* session, const std::string& content_name, bool rtcp, |
| VoiceChannel* voice_channel) { |
| // This is ok to alloc from a thread other than the worker thread |
| ASSERT(initialized_); |
| VideoMediaChannel* media_channel = |
| // voice_channel can be NULL in case of NullVoiceEngine. |
| media_engine_->CreateVideoChannel(voice_channel ? |
| voice_channel->media_channel() : NULL); |
| if (media_channel == NULL) |
| return NULL; |
| |
| VideoChannel* video_channel = new VideoChannel( |
| worker_thread_, media_engine_.get(), media_channel, |
| session, content_name, rtcp, voice_channel); |
| if (!video_channel->Init()) { |
| delete video_channel; |
| return NULL; |
| } |
| video_channels_.push_back(video_channel); |
| return video_channel; |
| } |
| |
| void ChannelManager::DestroyVideoChannel(VideoChannel* video_channel) { |
| if (video_channel) { |
| talk_base::TypedMessageData<VideoChannel *> data(video_channel); |
| Send(MSG_DESTROYVIDEOCHANNEL, &data); |
| } |
| } |
| |
| void ChannelManager::DestroyVideoChannel_w(VideoChannel *video_channel) { |
| // Destroy voice channel. |
| ASSERT(initialized_); |
| VideoChannels::iterator it = std::find(video_channels_.begin(), |
| video_channels_.end(), video_channel); |
| ASSERT(it != video_channels_.end()); |
| if (it == video_channels_.end()) |
| return; |
| |
| video_channels_.erase(it); |
| delete video_channel; |
| } |
| |
| Soundclip* ChannelManager::CreateSoundclip() { |
| talk_base::TypedMessageData<Soundclip*> data(NULL); |
| Send(MSG_CREATESOUNDCLIP, &data); |
| return data.data(); |
| } |
| |
| Soundclip* ChannelManager::CreateSoundclip_w() { |
| ASSERT(initialized_); |
| ASSERT(worker_thread_ == talk_base::Thread::Current()); |
| |
| SoundclipMedia* soundclip_media = media_engine_->CreateSoundclip(); |
| if (!soundclip_media) { |
| return NULL; |
| } |
| |
| Soundclip* soundclip = new Soundclip(worker_thread_, soundclip_media); |
| soundclips_.push_back(soundclip); |
| return soundclip; |
| } |
| |
| void ChannelManager::DestroySoundclip(Soundclip* soundclip) { |
| if (soundclip) { |
| talk_base::TypedMessageData<Soundclip*> data(soundclip); |
| Send(MSG_DESTROYSOUNDCLIP, &data); |
| } |
| } |
| |
| void ChannelManager::DestroySoundclip_w(Soundclip* soundclip) { |
| // Destroy soundclip. |
| ASSERT(initialized_); |
| Soundclips::iterator it = std::find(soundclips_.begin(), |
| soundclips_.end(), soundclip); |
| ASSERT(it != soundclips_.end()); |
| if (it == soundclips_.end()) |
| return; |
| |
| soundclips_.erase(it); |
| delete soundclip; |
| } |
| |
| bool ChannelManager::GetAudioOptions(std::string* in_name, |
| std::string* out_name, int* opts) { |
| *in_name = audio_in_device_; |
| *out_name = audio_out_device_; |
| *opts = audio_options_; |
| return true; |
| } |
| |
| bool ChannelManager::SetAudioOptions(const std::string& in_name, |
| const std::string& out_name, int opts) { |
| // Get device ids from DeviceManager. |
| Device in_dev, out_dev; |
| if (!device_manager_->GetAudioInputDevice(in_name, &in_dev)) { |
| LOG(LS_WARNING) << "Failed to GetAudioInputDevice: " << in_name; |
| return false; |
| } |
| if (!device_manager_->GetAudioOutputDevice(out_name, &out_dev)) { |
| LOG(LS_WARNING) << "Failed to GetAudioOutputDevice: " << out_name; |
| return false; |
| } |
| |
| // If we're initialized, pass the settings to the media engine. |
| bool ret = true; |
| if (initialized_) { |
| AudioOptions options(opts, &in_dev, &out_dev); |
| ret = (Send(MSG_SETAUDIOOPTIONS, &options) && options.result); |
| } |
| |
| // If all worked well, save the values for use in GetAudioOptions. |
| if (ret) { |
| audio_options_ = opts; |
| audio_in_device_ = in_name; |
| audio_out_device_ = out_name; |
| } |
| return ret; |
| } |
| |
| bool ChannelManager::SetAudioOptions_w(int opts, const Device* in_dev, |
| const Device* out_dev) { |
| ASSERT(worker_thread_ == talk_base::Thread::Current()); |
| ASSERT(initialized_); |
| |
| // Set audio options |
| bool ret = media_engine_->SetAudioOptions(opts); |
| |
| // Set the audio devices |
| if (ret) { |
| ret = media_engine_->SetSoundDevices(in_dev, out_dev); |
| } |
| |
| return ret; |
| } |
| |
| bool ChannelManager::GetOutputVolume(int* level) { |
| VolumeLevel volume; |
| if (!Send(MSG_GETOUTPUTVOLUME, &volume) || !volume.result) { |
| return false; |
| } |
| |
| *level = volume.level; |
| return true; |
| } |
| |
| bool ChannelManager::GetOutputVolume_w(int* level) { |
| ASSERT(worker_thread_ == talk_base::Thread::Current()); |
| ASSERT(initialized_); |
| return media_engine_->GetOutputVolume(level); |
| } |
| |
| bool ChannelManager::SetOutputVolume(int level) { |
| VolumeLevel volume(level); |
| return (Send(MSG_SETOUTPUTVOLUME, &volume) && volume.result); |
| } |
| |
| bool ChannelManager::SetOutputVolume_w(int level) { |
| ASSERT(worker_thread_ == talk_base::Thread::Current()); |
| ASSERT(initialized_); |
| return media_engine_->SetOutputVolume(level); |
| } |
| |
| bool ChannelManager::GetVideoOptions(std::string* cam_name) { |
| *cam_name = camera_device_; |
| return true; |
| } |
| |
| bool ChannelManager::SetVideoOptions(const std::string& cam_name) { |
| Device device; |
| if (!device_manager_->GetVideoCaptureDevice(cam_name, &device)) { |
| if (!cam_name.empty()) { |
| LOG(LS_WARNING) << "Device manager can't find camera: " << cam_name; |
| } |
| return false; |
| } |
| |
| // If we're running, tell the media engine about it. |
| bool ret = true; |
| if (initialized_) { |
| VideoOptions options(&device); |
| ret = (Send(MSG_SETVIDEOOPTIONS, &options) && options.result); |
| } |
| |
| // If everything worked, retain the name of the selected camera. |
| if (ret) { |
| camera_device_ = device.name; |
| } |
| return ret; |
| } |
| |
| bool ChannelManager::SetVideoOptions_w(const Device* cam_device) { |
| ASSERT(worker_thread_ == talk_base::Thread::Current()); |
| ASSERT(initialized_); |
| |
| // Set the video input device |
| return media_engine_->SetVideoCaptureDevice(cam_device); |
| } |
| |
| bool ChannelManager::SetDefaultVideoEncoderConfig(const VideoEncoderConfig& c) { |
| bool ret = true; |
| if (initialized_) { |
| DefaultVideoEncoderConfig config(c); |
| ret = Send(MSG_SETDEFAULTVIDEOENCODERCONFIG, &config) && config.result; |
| } |
| if (ret) { |
| default_video_encoder_config_ = c; |
| } |
| return ret; |
| } |
| |
| bool ChannelManager::SetDefaultVideoEncoderConfig_w( |
| const VideoEncoderConfig& c) { |
| ASSERT(worker_thread_ == talk_base::Thread::Current()); |
| ASSERT(initialized_); |
| return media_engine_->SetDefaultVideoEncoderConfig(c); |
| } |
| |
| bool ChannelManager::SetLocalMonitor(bool enable) { |
| LocalMonitor monitor(enable); |
| bool ret = Send(MSG_SETLOCALMONITOR, &monitor) && monitor.result; |
| if (ret) { |
| monitoring_ = enable; |
| } |
| return ret; |
| } |
| |
| bool ChannelManager::SetLocalMonitor_w(bool enable) { |
| ASSERT(worker_thread_ == talk_base::Thread::Current()); |
| ASSERT(initialized_); |
| return media_engine_->SetLocalMonitor(enable); |
| } |
| |
| bool ChannelManager::SetLocalRenderer(VideoRenderer* renderer) { |
| bool ret = true; |
| if (initialized_) { |
| LocalRenderer local(renderer); |
| ret = (Send(MSG_SETLOCALRENDERER, &local) && local.result); |
| } |
| if (ret) { |
| local_renderer_ = renderer; |
| } |
| return ret; |
| } |
| |
| bool ChannelManager::SetLocalRenderer_w(VideoRenderer* renderer) { |
| ASSERT(worker_thread_ == talk_base::Thread::Current()); |
| ASSERT(initialized_); |
| return media_engine_->SetLocalRenderer(renderer); |
| } |
| |
| bool ChannelManager::SetVideoCapturer(VideoCapturer* capturer, uint32 ssrc) { |
| bool ret = true; |
| if (initialized_) { |
| Capturer capture(capturer, ssrc); |
| ret = (Send(MSG_SETVIDEOCAPTURER, &capture) && capture.result); |
| } |
| return ret; |
| } |
| |
| bool ChannelManager::SetVideoCapturer_w(VideoCapturer* capturer, uint32 ssrc) { |
| ASSERT(worker_thread_ == talk_base::Thread::Current()); |
| ASSERT(initialized_); |
| return media_engine_->SetVideoCapturer(capturer, ssrc); |
| } |
| |
| CaptureResult ChannelManager::SetVideoCapture(bool capture) { |
| bool ret; |
| CaptureParams capture_params(capture); |
| ret = (Send(MSG_SETVIDEOCAPTURE, &capture_params) && |
| (capture_params.result != CR_FAILURE)); |
| if (ret) { |
| capturing_ = capture; |
| } |
| return capture_params.result; |
| } |
| |
| CaptureResult ChannelManager::SetVideoCapture_w(bool capture) { |
| ASSERT(worker_thread_ == talk_base::Thread::Current()); |
| ASSERT(initialized_); |
| return media_engine_->SetVideoCapture(capture); |
| } |
| |
| void ChannelManager::SetVoiceLogging(int level, const char* filter) { |
| SetMediaLogging(false, level, filter); |
| } |
| |
| void ChannelManager::SetVideoLogging(int level, const char* filter) { |
| SetMediaLogging(true, level, filter); |
| } |
| |
| void ChannelManager::SetMediaLogging(bool video, int level, |
| const char* filter) { |
| // Can be called before initialization; in this case, the worker function |
| // is simply called on the main thread. |
| if (initialized_) { |
| LoggingOptions options(level, filter); |
| Send((video) ? MSG_SETVIDEOLOGGING : MSG_SETVOICELOGGING, &options); |
| } else { |
| SetMediaLogging_w(video, level, filter); |
| } |
| } |
| |
| void ChannelManager::SetMediaLogging_w(bool video, int level, |
| const char* filter) { |
| // Can be called before initialization |
| ASSERT(worker_thread_ == talk_base::Thread::Current() || !initialized_); |
| if (video) { |
| media_engine_->SetVideoLogging(level, filter); |
| } else { |
| media_engine_->SetVoiceLogging(level, filter); |
| } |
| } |
| |
| // TODO: For now pass this request through the mediaengine to the |
| // voice and video engines to do the real work. Once the capturer refactoring |
| // is done, we will access the capturer using the ssrc (similar to how the |
| // renderer is accessed today) and register with it directly. |
| bool ChannelManager::RegisterVideoProcessor(uint32 ssrc, |
| VideoProcessor* processor) { |
| VideoProcessorParams processor_params(ssrc, processor); |
| return (Send(MSG_REGISTERVIDEOPROCESSOR, &processor_params) && |
| processor_params.result); |
| } |
| bool ChannelManager::RegisterVideoProcessor_w(uint32 ssrc, |
| VideoProcessor* processor) { |
| return media_engine_->RegisterVideoProcessor(processor); |
| } |
| |
| bool ChannelManager::UnregisterVideoProcessor(uint32 ssrc, |
| VideoProcessor* processor) { |
| VideoProcessorParams processor_params(ssrc, processor); |
| return (Send(MSG_UNREGISTERVIDEOPROCESSOR, &processor_params) && |
| processor_params.result); |
| } |
| bool ChannelManager::UnregisterVideoProcessor_w(uint32 ssrc, |
| VideoProcessor* processor) { |
| return media_engine_->UnregisterVideoProcessor(processor); |
| } |
| |
| bool ChannelManager::RegisterVoiceProcessor( |
| uint32 ssrc, |
| VoiceProcessor* processor, |
| MediaProcessorDirection direction) { |
| VoiceProcessorParams processor_params(ssrc, processor, direction); |
| return (Send(MSG_REGISTERVOICEPROCESSOR, &processor_params) && |
| processor_params.result); |
| } |
| bool ChannelManager::RegisterVoiceProcessor_w( |
| uint32 ssrc, |
| VoiceProcessor* processor, |
| MediaProcessorDirection direction) { |
| return media_engine_->RegisterVoiceProcessor(ssrc, processor, direction); |
| } |
| |
| bool ChannelManager::UnregisterVoiceProcessor( |
| uint32 ssrc, |
| VoiceProcessor* processor, |
| MediaProcessorDirection direction) { |
| VoiceProcessorParams processor_params(ssrc, processor, direction); |
| return (Send(MSG_UNREGISTERVOICEPROCESSOR, &processor_params) && |
| processor_params.result); |
| } |
| bool ChannelManager::UnregisterVoiceProcessor_w( |
| uint32 ssrc, |
| VoiceProcessor* processor, |
| MediaProcessorDirection direction) { |
| return media_engine_->UnregisterVoiceProcessor(ssrc, processor, direction); |
| } |
| |
| bool ChannelManager::Send(uint32 id, talk_base::MessageData* data) { |
| if (!worker_thread_ || !initialized_) return false; |
| worker_thread_->Send(this, id, data); |
| return true; |
| } |
| |
| void ChannelManager::OnVideoCaptureResult(VideoCapturer* capturer, |
| CaptureResult result) { |
| // TODO: Check capturer and signal failure only for camera video, not |
| // screencast. |
| capturing_ = result == CR_SUCCESS; |
| main_thread_->Post(this, MSG_CAMERASTARTED, |
| new talk_base::TypedMessageData<CaptureResult>(result)); |
| } |
| |
| void ChannelManager::OnMessage(talk_base::Message* message) { |
| talk_base::MessageData* data = message->pdata; |
| switch (message->message_id) { |
| case MSG_CREATEVOICECHANNEL: { |
| CreationParams* p = static_cast<CreationParams*>(data); |
| p->voice_channel = |
| CreateVoiceChannel_w(p->session, p->content_name, p->rtcp); |
| break; |
| } |
| case MSG_DESTROYVOICECHANNEL: { |
| VoiceChannel* p = static_cast<talk_base::TypedMessageData<VoiceChannel*>*> |
| (data)->data(); |
| DestroyVoiceChannel_w(p); |
| break; |
| } |
| case MSG_CREATEVIDEOCHANNEL: { |
| CreationParams* p = static_cast<CreationParams*>(data); |
| p->video_channel = CreateVideoChannel_w(p->session, p->content_name, |
| p->rtcp, p->voice_channel); |
| break; |
| } |
| case MSG_DESTROYVIDEOCHANNEL: { |
| VideoChannel* p = static_cast<talk_base::TypedMessageData<VideoChannel*>*> |
| (data)->data(); |
| DestroyVideoChannel_w(p); |
| break; |
| } |
| case MSG_CREATESOUNDCLIP: { |
| talk_base::TypedMessageData<Soundclip*> *p = |
| static_cast<talk_base::TypedMessageData<Soundclip*>*>(data); |
| p->data() = CreateSoundclip_w(); |
| break; |
| } |
| case MSG_DESTROYSOUNDCLIP: { |
| talk_base::TypedMessageData<Soundclip*> *p = |
| static_cast<talk_base::TypedMessageData<Soundclip*>*>(data); |
| DestroySoundclip_w(p->data()); |
| break; |
| } |
| case MSG_SETAUDIOOPTIONS: { |
| AudioOptions* p = static_cast<AudioOptions*>(data); |
| p->result = SetAudioOptions_w(p->options, |
| p->in_device, p->out_device); |
| break; |
| } |
| case MSG_GETOUTPUTVOLUME: { |
| VolumeLevel* p = static_cast<VolumeLevel*>(data); |
| p->result = GetOutputVolume_w(&p->level); |
| break; |
| } |
| case MSG_SETOUTPUTVOLUME: { |
| VolumeLevel* p = static_cast<VolumeLevel*>(data); |
| p->result = SetOutputVolume_w(p->level); |
| break; |
| } |
| case MSG_SETLOCALMONITOR: { |
| LocalMonitor* p = static_cast<LocalMonitor*>(data); |
| p->result = SetLocalMonitor_w(p->enable); |
| break; |
| } |
| case MSG_SETVIDEOOPTIONS: { |
| VideoOptions* p = static_cast<VideoOptions*>(data); |
| p->result = SetVideoOptions_w(p->cam_device); |
| break; |
| } |
| case MSG_SETDEFAULTVIDEOENCODERCONFIG: { |
| DefaultVideoEncoderConfig* p = |
| static_cast<DefaultVideoEncoderConfig*>(data); |
| p->result = SetDefaultVideoEncoderConfig_w(p->config); |
| break; |
| } |
| case MSG_SETLOCALRENDERER: { |
| LocalRenderer* p = static_cast<LocalRenderer*>(data); |
| p->result = SetLocalRenderer_w(p->renderer); |
| break; |
| } |
| case MSG_SETVIDEOCAPTURER: { |
| Capturer* p = static_cast<Capturer*>(data); |
| p->result = SetVideoCapturer_w(p->capturer, p->ssrc); |
| break; |
| } |
| case MSG_SETVIDEOCAPTURE: { |
| CaptureParams* p = static_cast<CaptureParams*>(data); |
| p->result = SetVideoCapture_w(p->capture); |
| break; |
| } |
| case MSG_SETVOICELOGGING: |
| case MSG_SETVIDEOLOGGING: { |
| LoggingOptions* p = static_cast<LoggingOptions*>(data); |
| bool video = (message->message_id == MSG_SETVIDEOLOGGING); |
| SetMediaLogging_w(video, p->level, p->filter.c_str()); |
| break; |
| } |
| case MSG_CAMERASTARTED: { |
| talk_base::TypedMessageData<CaptureResult>* data = |
| static_cast<talk_base::TypedMessageData<CaptureResult>*>( |
| message->pdata); |
| SignalVideoCaptureResult(data->data()); |
| delete data; |
| break; |
| } |
| case MSG_TERMINATE: { |
| Terminate_w(); |
| break; |
| } |
| case MSG_REGISTERVIDEOPROCESSOR: { |
| VideoProcessorParams* data = |
| static_cast<VideoProcessorParams*>(message->pdata); |
| data->result = RegisterVideoProcessor_w(data->ssrc, data->processor); |
| break; |
| } |
| case MSG_UNREGISTERVIDEOPROCESSOR: { |
| VideoProcessorParams* data = |
| static_cast<VideoProcessorParams*>(message->pdata); |
| data->result = UnregisterVideoProcessor_w(data->ssrc, data->processor); |
| break; |
| } |
| case MSG_REGISTERVOICEPROCESSOR: { |
| VoiceProcessorParams* data = |
| static_cast<VoiceProcessorParams*>(message->pdata); |
| data->result = RegisterVoiceProcessor_w(data->ssrc, |
| data->processor, |
| data->direction); |
| break; |
| } |
| case MSG_UNREGISTERVOICEPROCESSOR: { |
| VoiceProcessorParams* data = |
| static_cast<VoiceProcessorParams*>(message->pdata); |
| data->result = UnregisterVoiceProcessor_w(data->ssrc, |
| data->processor, |
| data->direction); |
| break; |
| } |
| } |
| } |
| |
| static void GetDeviceNames(const std::vector<Device>& devs, |
| std::vector<std::string>* names) { |
| names->clear(); |
| for (size_t i = 0; i < devs.size(); ++i) { |
| names->push_back(devs[i].name); |
| } |
| } |
| |
| bool ChannelManager::GetAudioInputDevices(std::vector<std::string>* names) { |
| names->clear(); |
| std::vector<Device> devs; |
| bool ret = device_manager_->GetAudioInputDevices(&devs); |
| if (ret) |
| GetDeviceNames(devs, names); |
| |
| return ret; |
| } |
| |
| bool ChannelManager::GetAudioOutputDevices(std::vector<std::string>* names) { |
| names->clear(); |
| std::vector<Device> devs; |
| bool ret = device_manager_->GetAudioOutputDevices(&devs); |
| if (ret) |
| GetDeviceNames(devs, names); |
| |
| return ret; |
| } |
| |
| bool ChannelManager::GetVideoCaptureDevices(std::vector<std::string>* names) { |
| names->clear(); |
| std::vector<Device> devs; |
| bool ret = device_manager_->GetVideoCaptureDevices(&devs); |
| if (ret) |
| GetDeviceNames(devs, names); |
| |
| return ret; |
| } |
| |
| } // namespace cricket |