diff --git a/third_party_mods/libjingle/libjingle.gyp b/third_party_mods/libjingle/libjingle.gyp index bad09b5e63..42f34bb0f9 100644 --- a/third_party_mods/libjingle/libjingle.gyp +++ b/third_party_mods/libjingle/libjingle.gyp @@ -466,7 +466,7 @@ 'source/talk/session/phone/devicemanager.cc', 'source/talk/session/phone/devicemanager.h', 'source/talk/session/phone/filemediaengine.cc', - 'source/talk/session/phone/filemediaengine.h', + 'source/talk/session/phone/filemediaengine.h', 'source/talk/session/phone/mediachannel.h', 'source/talk/session/phone/mediaengine.cc', 'source/talk/session/phone/mediaengine.h', @@ -494,17 +494,9 @@ 'source/talk/session/tunnel/tunnelsessionclient.cc', 'source/talk/session/tunnel/tunnelsessionclient.h', ], - 'conditions': [ - ['OS=="win"', { - 'sources': [ - 'source/talk/session/phone/gdivideorenderer.cc', - 'source/talk/session/phone/gdivideorenderer.h', - ], - }], + 'conditions': [ ['OS=="linux"', { 'sources': [ - #'source/talk/session/phone/gtkvideorenderer.cc', - #'source/talk/session/phone/gtkvideorenderer.h', 'source/talk/session/phone/libudevsymboltable.cc', 'source/talk/session/phone/libudevsymboltable.h', 'source/talk/session/phone/v4llookup.cc', @@ -547,6 +539,8 @@ 'source/talk/app/voicemediaengine.h', 'source/talk/app/webrtc_json.cc', 'source/talk/app/webrtc_json.h', + 'source/talk/app/webrtcchannelmanager.cc', + 'source/talk/app/webrtcchannelmanager.h', 'source/talk/app/webrtcsession.cc', 'source/talk/app/webrtcsession.h', 'source/talk/app/webrtcsessionimpl.cc', @@ -562,8 +556,8 @@ ], },{ 'sources': [ - 'source/talk/app/p2p_transport_manager.cc', - 'source/talk/app/p2p_transport_manager.h', + 'source/talk/app/p2p_transport_manager.cc', + 'source/talk/app/p2p_transport_manager.h', ], }], ], diff --git a/third_party_mods/libjingle/source/talk/app/peerconnection.cc b/third_party_mods/libjingle/source/talk/app/peerconnection.cc index 87805c1808..4a1962f487 100644 --- a/third_party_mods/libjingle/source/talk/app/peerconnection.cc +++ b/third_party_mods/libjingle/source/talk/app/peerconnection.cc @@ -115,7 +115,7 @@ bool PeerConnection::Init() { cricket::PORTALLOCATOR_DISABLE_RELAY); // create channel manager - channel_manager_.reset(new cricket::ChannelManager(media_thread_.get())); + channel_manager_.reset(new WebRtcChannelManager(media_thread_.get())); //start the media thread media_thread_->SetPriority(talk_base::PRIORITY_HIGH); @@ -244,22 +244,24 @@ bool PeerConnection::SetAudioDevice(const std::string& wave_in_device, return channel_manager_->SetAudioOptions(wave_in_device, wave_out_device, opts); } -bool PeerConnection::SetLocalVideoRenderer(cricket::VideoRenderer* renderer) { - return channel_manager_->SetLocalRenderer(renderer); -} - -bool PeerConnection::SetVideoRenderer(const std::string& stream_id, - cricket::VideoRenderer* renderer) { - ASSERT(session_ != NULL); - return session_->SetVideoRenderer(stream_id, renderer); -} - bool PeerConnection::SetVideoRenderer(const std::string& stream_id, ExternalRenderer* external_renderer) { ASSERT(session_ != NULL); return session_->SetVideoRenderer(stream_id, external_renderer); } +bool PeerConnection::SetVideoRenderer(int channel_id, + void* window, + unsigned int zOrder, + float left, + float top, + float right, + float bottom) { + ASSERT(session_ != NULL); + return session_->SetVideoRenderer(channel_id, window, zOrder, left, top, + right, bottom); +} + bool PeerConnection::SetVideoCapture(const std::string& cam_device) { return channel_manager_->SetVideoOptions(cam_device); } diff --git a/third_party_mods/libjingle/source/talk/app/peerconnection.h b/third_party_mods/libjingle/source/talk/app/peerconnection.h index e39c88b1c1..9ab8da5c9a 100644 --- a/third_party_mods/libjingle/source/talk/app/peerconnection.h +++ b/third_party_mods/libjingle/source/talk/app/peerconnection.h @@ -10,7 +10,7 @@ #include "talk/base/thread.h" #include "talk/base/scoped_ptr.h" #include "talk/base/basicpacketsocketfactory.h" -#include "talk/session/phone/channelmanager.h" +#include "talk/app/webrtcchannelmanager.h" namespace Json { class Value; @@ -18,8 +18,6 @@ class Value; namespace cricket { class BasicPortAllocator; -class ChannelManager; -class VideoRenderer; } #ifdef PLATFORM_CHROMIUM @@ -78,13 +76,16 @@ class PeerConnection : public sigslot::has_slots<> { bool SetAudioDevice(const std::string& wave_in_device, const std::string& wave_out_device, int opts); // Set the video renderer - bool SetLocalVideoRenderer(cricket::VideoRenderer* renderer); - bool SetVideoRenderer(const std::string& stream_id, - cricket::VideoRenderer* renderer); - bool SetVideoRenderer(const std::string& stream_id, ExternalRenderer* external_renderer); - + // Set channel_id to -1 for the local preview + bool SetVideoRenderer(int channel_id, + void* window, + unsigned int zOrder, + float left, + float top, + float right, + float bottom); // Set video capture device // For Chromium the cam_device should use the capture session id. // For standalone app, cam_device is the camera name. It will try to @@ -119,7 +120,7 @@ class PeerConnection : public sigslot::has_slots<> { std::string config_; talk_base::scoped_ptr media_thread_; - talk_base::scoped_ptr channel_manager_; + talk_base::scoped_ptr channel_manager_; talk_base::scoped_ptr network_manager_; talk_base::scoped_ptr port_allocator_; talk_base::scoped_ptr socket_factory_; diff --git a/third_party_mods/libjingle/source/talk/app/session_test/session_test_main.cc b/third_party_mods/libjingle/source/talk/app/session_test/session_test_main.cc index e783bdfb77..99af54e720 100644 --- a/third_party_mods/libjingle/source/talk/app/session_test/session_test_main.cc +++ b/third_party_mods/libjingle/source/talk/app/session_test/session_test_main.cc @@ -20,7 +20,6 @@ #include "talk/app/peerconnection.h" #include "talk/app/session_test/main_wnd.h" #include "talk/base/logging.h" -#include "talk/session/phone/videorendererfactory.h" static const char kAudioLabel[] = "audio_label"; static const char kVideoLabel[] = "video_label"; @@ -218,7 +217,6 @@ class PeerConnectionClient : public sigslot::has_slots<> { } void OnConnect(talk_base::AsyncSocket* socket) { - ASSERT(!onconnect_data_.empty()); int sent = socket->Send(onconnect_data_.c_str(), onconnect_data_.length()); ASSERT(sent == onconnect_data_.length()); onconnect_data_.clear(); @@ -387,10 +385,8 @@ class PeerConnectionClient : public sigslot::has_slots<> { notification_data_.clear(); } - if (hanging_get_.GetState() == talk_base::Socket::CS_CLOSED && - state_ == CONNECTED) { + if (hanging_get_.GetState() == talk_base::Socket::CS_CLOSED) hanging_get_.Connect(server_address_); - } } // Parses a single line entry in the form ",," @@ -450,9 +446,7 @@ class PeerConnectionClient : public sigslot::has_slots<> { void OnClose(talk_base::AsyncSocket* socket, int err) { LOG(INFO) << __FUNCTION__; - socket->Close(); - if (err != WSAECONNREFUSED) { if (socket == &hanging_get_) { if (state_ == CONNECTED) { @@ -559,7 +553,6 @@ class ConnectionObserver void DeletePeerConnection() { peer_connection_.reset(); - handshake_ = NONE; } void StartCaptureDevice() { @@ -568,11 +561,8 @@ class ConnectionObserver main_wnd_->SwitchToStreamingUI(); if (peer_connection_->SetVideoCapture("")) { - if (!local_renderer_.get()) { - local_renderer_.reset( - cricket::VideoRendererFactory::CreateGuiVideoRenderer(176, 144)); - } - peer_connection_->SetLocalVideoRenderer(local_renderer_.get()); + peer_connection_->SetVideoRenderer(-1, main_wnd_->handle(), 0, + 0.7f, 0.7f, 0.95f, 0.95f); } else { ASSERT(false); } @@ -622,12 +612,8 @@ class ConnectionObserver video_channel_ = channel_id; waiting_for_video_ = false; LOG(INFO) << "Setting video renderer for channel: " << channel_id; - if (!remote_renderer_.get()) { - remote_renderer_.reset( - cricket::VideoRendererFactory::CreateGuiVideoRenderer(352, 288)); - } - bool ok = peer_connection_->SetVideoRenderer(stream_id, - remote_renderer_.get()); + bool ok = peer_connection_->SetVideoRenderer(channel_id, + main_wnd_->handle(), 1, 0.0f, 0.0f, 1.0f, 1.0f); ASSERT(ok); } else { ASSERT(audio_channel_ == -1); @@ -788,6 +774,7 @@ class ConnectionObserver LOG(INFO) << "PEER_CONNECTION_CLOSED"; DeletePeerConnection(); ::InvalidateRect(main_wnd_->handle(), NULL, TRUE); + handshake_ = NONE; waiting_for_audio_ = false; waiting_for_video_ = false; peer_id_ = -1; @@ -803,12 +790,7 @@ class ConnectionObserver DisconnectFromServer(); } } else if (msg == SEND_MESSAGE_TO_PEER) { - bool ok = client_->SendToPeer(peer_id_, - *reinterpret_cast(lp)); - if (!ok) { - LOG(LS_ERROR) << "SendToPeer failed"; - DisconnectFromServer(); - } + client_->SendToPeer(peer_id_, *reinterpret_cast(lp)); } else { ret = false; } @@ -826,8 +808,6 @@ class ConnectionObserver MainWnd* main_wnd_; int video_channel_; int audio_channel_; - scoped_ptr local_renderer_; - scoped_ptr remote_renderer_; }; int PASCAL wWinMain(HINSTANCE instance, HINSTANCE prev_instance, diff --git a/third_party_mods/libjingle/source/talk/app/videoengine.h b/third_party_mods/libjingle/source/talk/app/videoengine.h index 3b724bbfc0..aa7fb62208 100644 --- a/third_party_mods/libjingle/source/talk/app/videoengine.h +++ b/third_party_mods/libjingle/source/talk/app/videoengine.h @@ -31,7 +31,6 @@ #include "talk/base/common.h" #include "common_types.h" -#include "modules/interface/module_common_types.h" #include "video_engine/main/interface/vie_base.h" #include "video_engine/main/interface/vie_capture.h" #include "video_engine/main/interface/vie_codec.h" diff --git a/third_party_mods/libjingle/source/talk/app/videomediaengine.cc b/third_party_mods/libjingle/source/talk/app/videomediaengine.cc index 95387bf105..dd5bddea71 100644 --- a/third_party_mods/libjingle/source/talk/app/videomediaengine.cc +++ b/third_party_mods/libjingle/source/talk/app/videomediaengine.cc @@ -14,7 +14,6 @@ #include "talk/app/voicemediaengine.h" #include "modules/video_capture/main/interface/video_capture.h" -#include "vplib.h" #ifndef ARRAYSIZE #define ARRAYSIZE(a) (sizeof(a) / sizeof((a)[0])) @@ -26,213 +25,6 @@ static const int kDefaultLogSeverity = 3; static const int kStartVideoBitrate = 300; static const int kMaxVideoBitrate = 1000; -CricketWebRTCVideoFrame::CricketWebRTCVideoFrame() { -} - -CricketWebRTCVideoFrame::~CricketWebRTCVideoFrame() { - // TODO(ronghuawu): should the CricketWebRTCVideoFrame owns the buffer? - WebRtc_UWord8* newMemory = NULL; - WebRtc_UWord32 newLength = 0; - WebRtc_UWord32 newSize = 0; - video_frame_.Swap(newMemory, newLength, newSize); -} - -void CricketWebRTCVideoFrame::Attach(unsigned char* buffer, int bufferSize, - int w, int h) { - WebRtc_UWord8* newMemory = buffer; - WebRtc_UWord32 newLength = bufferSize; - WebRtc_UWord32 newSize = bufferSize; - video_frame_.Swap(newMemory, newLength, newSize); - video_frame_.SetWidth(w); - video_frame_.SetHeight(h); -} - -size_t CricketWebRTCVideoFrame::GetWidth() const { - return video_frame_.Width(); -} -size_t CricketWebRTCVideoFrame::GetHeight() const { - return video_frame_.Height(); -} - -const uint8* CricketWebRTCVideoFrame::GetYPlane() const { - WebRtc_UWord8* buffer = video_frame_.Buffer(); - return buffer; -} - -const uint8* CricketWebRTCVideoFrame::GetUPlane() const { - WebRtc_UWord8* buffer = video_frame_.Buffer(); - if (buffer) - buffer += (video_frame_.Width() * video_frame_.Height()); - return buffer; -} - -const uint8* CricketWebRTCVideoFrame::GetVPlane() const { - WebRtc_UWord8* buffer = video_frame_.Buffer(); - if (buffer) - buffer += (video_frame_.Width() * video_frame_.Height() * 5 / 4); - return buffer; -} - -uint8* CricketWebRTCVideoFrame::GetYPlane() { - WebRtc_UWord8* buffer = video_frame_.Buffer(); - return buffer; -} - -uint8* CricketWebRTCVideoFrame::GetUPlane() { - WebRtc_UWord8* buffer = video_frame_.Buffer(); - if (buffer) - buffer += (video_frame_.Width() * video_frame_.Height()); - return buffer; -} - -uint8* CricketWebRTCVideoFrame::GetVPlane() { - WebRtc_UWord8* buffer = video_frame_.Buffer(); - if (buffer) - buffer += (video_frame_.Width() * video_frame_.Height() * 3 / 2); - return buffer; -} - -cricket::VideoFrame* CricketWebRTCVideoFrame::Copy() const { - WebRtc_UWord8* buffer = video_frame_.Buffer(); - if (buffer) { - int new_buffer_size = video_frame_.Length(); - unsigned char* new_buffer = new unsigned char[new_buffer_size]; - memcpy(new_buffer, buffer, new_buffer_size); - CricketWebRTCVideoFrame* copy = new CricketWebRTCVideoFrame(); - copy->Attach(new_buffer, new_buffer_size, - video_frame_.Width(), video_frame_.Height()); - copy->SetTimeStamp(video_frame_.TimeStamp()); - copy->SetElapsedTime(elapsed_time_); - return copy; - } - return NULL; -} - -size_t CricketWebRTCVideoFrame::CopyToBuffer( - uint8* buffer, size_t size) const { - if (!video_frame_.Buffer()) { - return 0; - } - - size_t needed = video_frame_.Length(); - if (needed <= size) { - memcpy(buffer, video_frame_.Buffer(), needed); - } - return needed; -} - -size_t CricketWebRTCVideoFrame::ConvertToRgbBuffer(uint32 to_fourcc, - uint8* buffer, - size_t size, - size_t pitch_rgb) const { - if (!video_frame_.Buffer()) { - return 0; - } - - size_t width = video_frame_.Width(); - size_t height = video_frame_.Height(); - // See http://www.virtualdub.org/blog/pivot/entry.php?id=190 for a good - // explanation of pitch and why this is the amount of space we need. - size_t needed = pitch_rgb * (height - 1) + 4 * width; - - if (needed > size) { - LOG(LS_WARNING) << "RGB buffer is not large enough"; - return needed; - } - - VideoType outgoingVideoType = kUnknown; - switch (to_fourcc) { - case cricket::FOURCC_ARGB: - outgoingVideoType = kARGB; - break; - default: - LOG(LS_WARNING) << "RGB type not supported: " << to_fourcc; - break; - } - - if (outgoingVideoType != kUnknown) - ConvertFromI420(outgoingVideoType, video_frame_.Buffer(), - width, height, buffer); - - return needed; -} - -// TODO(ronghuawu): Implement StretchToPlanes -void CricketWebRTCVideoFrame::StretchToPlanes( - uint8* y, uint8* u, uint8* v, - int32 dst_pitch_y, int32 dst_pitch_u, int32 dst_pitch_v, - size_t width, size_t height, bool interpolate, bool crop) const { -} - -size_t CricketWebRTCVideoFrame::StretchToBuffer(size_t w, size_t h, - uint8* buffer, size_t size, - bool interpolate, - bool crop) const { - if (!video_frame_.Buffer()) { - return 0; - } - - size_t needed = video_frame_.Length(); - - if (needed <= size) { - uint8* bufy = buffer; - uint8* bufu = bufy + w * h; - uint8* bufv = bufu + ((w + 1) >> 1) * ((h + 1) >> 1); - StretchToPlanes(bufy, bufu, bufv, w, (w + 1) >> 1, (w + 1) >> 1, w, h, - interpolate, crop); - } - return needed; -} - -void CricketWebRTCVideoFrame::StretchToFrame(cricket::VideoFrame *target, - bool interpolate, bool crop) const { - if (!target) return; - - StretchToPlanes(target->GetYPlane(), - target->GetUPlane(), - target->GetVPlane(), - target->GetYPitch(), - target->GetUPitch(), - target->GetVPitch(), - target->GetWidth(), - target->GetHeight(), - interpolate, crop); - target->SetElapsedTime(GetElapsedTime()); - target->SetTimeStamp(GetTimeStamp()); -} - -cricket::VideoFrame* CricketWebRTCVideoFrame::Stretch(size_t w, size_t h, - bool interpolate, bool crop) const { - // TODO(ronghuawu): implement - CricketWebRTCVideoFrame* frame = new CricketWebRTCVideoFrame(); - return frame; -} - -CricketWebRTCVideoRenderer::CricketWebRTCVideoRenderer - (cricket::VideoRenderer* renderer) - :renderer_(renderer) { -} - -CricketWebRTCVideoRenderer::~CricketWebRTCVideoRenderer() { -} - -int CricketWebRTCVideoRenderer::FrameSizeChange(unsigned int width, - unsigned int height, - unsigned int numberOfStreams) { - ASSERT(renderer_ != NULL); - width_ = width; - height_ = height; - number_of_streams_ = numberOfStreams; - return renderer_->SetSize(width_, height_, 0) ? 0 : -1; -} - -int CricketWebRTCVideoRenderer::DeliverFrame(unsigned char* buffer, - int bufferSize) { - ASSERT(renderer_ != NULL); - video_frame_.Attach(buffer, bufferSize, width_, height_); - return renderer_->RenderFrame(&video_frame_) ? 0 : -1; -} - const RtcVideoEngine::VideoCodecPref RtcVideoEngine::kVideoCodecPrefs[] = { {"VP8", 104, 0}, {"H264", 105, 1} @@ -439,23 +231,29 @@ bool RtcVideoEngine::SetCaptureDevice(const cricket::Device* cam) { return (capture_id_ != -1); } -bool RtcVideoEngine::SetLocalRenderer(cricket::VideoRenderer* renderer) { - if (!local_renderer_.get()) { - local_renderer_.reset(new CricketWebRTCVideoRenderer(renderer)); - } else { - // Renderer already set - return true; - } - +bool RtcVideoEngine::SetVideoRenderer(int channel_id, + void* window, + unsigned int zOrder, + float left, + float top, + float right, + float bottom) { int ret; - ret = video_engine_->render()->AddRenderer(capture_id_, - kVideoI420, - local_renderer_.get()); - if (ret != 0) + if (channel_id == -1) + channel_id = capture_id_; + ret = video_engine_->render()->AddRenderer( + channel_id, window, zOrder, left, top, right, bottom); + if (ret !=0 ) return false; - ret = video_engine_->render()->StartRender(capture_id_); + ret = video_engine_->render()->StartRender(channel_id); + if (ret !=0 ) + return false; + return true; +} - return (ret == 0); +bool RtcVideoEngine::SetLocalRenderer(cricket::VideoRenderer* renderer) { + LOG(LS_WARNING) << "Not required call SetLocalRenderer for webrtc"; + return false; } cricket::CaptureResult RtcVideoEngine::SetCapture(bool capture) { @@ -767,22 +565,7 @@ bool RtcVideoMediaChannel::RemoveStream(uint32 ssrc) { bool RtcVideoMediaChannel::SetRenderer( uint32 ssrc, cricket::VideoRenderer* renderer) { - if (!remote_renderer_.get()) { - remote_renderer_.reset(new CricketWebRTCVideoRenderer(renderer)); - } else { - // Renderer already set - return true; - } - - int ret; - ret = engine_->video_engine()->render()->AddRenderer(video_channel_, - kVideoI420, - remote_renderer_.get()); - if (ret != 0) - return false; - ret = engine_->video_engine()->render()->StartRender(video_channel_); - - return (ret == 0); + return false; } bool RtcVideoMediaChannel::SetExternalRenderer(uint32 ssrc, void* renderer) @@ -792,11 +575,12 @@ bool RtcVideoMediaChannel::SetExternalRenderer(uint32 ssrc, void* renderer) video_channel_, kVideoI420, static_cast(renderer)); - if (ret != 0) + if (ret !=0 ) return false; ret = engine_->video_engine()->render()->StartRender(video_channel_); - - return (ret == 0); + if (ret !=0 ) + return false; + return true; } bool RtcVideoMediaChannel::GetStats(cricket::VideoMediaInfo* info) { diff --git a/third_party_mods/libjingle/source/talk/app/videomediaengine.h b/third_party_mods/libjingle/source/talk/app/videomediaengine.h index 4fdb629725..a5e9fcee2b 100644 --- a/third_party_mods/libjingle/source/talk/app/videomediaengine.h +++ b/third_party_mods/libjingle/source/talk/app/videomediaengine.h @@ -49,74 +49,6 @@ class RtcVideoMediaChannel; class RtcVoiceEngine; class ExternalRenderer; -// CricketWebRTCVideoFrame only supports I420 -class CricketWebRTCVideoFrame : public cricket::VideoFrame { - public: - CricketWebRTCVideoFrame(); - ~CricketWebRTCVideoFrame(); - - void Attach(unsigned char* buffer, int bufferSize, int w, int h); - - virtual size_t GetWidth() const; - virtual size_t GetHeight() const; - virtual const uint8* GetYPlane() const; - virtual const uint8* GetUPlane() const; - virtual const uint8* GetVPlane() const; - virtual uint8* GetYPlane(); - virtual uint8* GetUPlane(); - virtual uint8* GetVPlane(); - virtual int32 GetYPitch() const { return video_frame_.Width(); } - virtual int32 GetUPitch() const { return video_frame_.Width() / 2; } - virtual int32 GetVPitch() const { return video_frame_.Width() / 2; } - - virtual size_t GetPixelWidth() const { return 1; } - virtual size_t GetPixelHeight() const { return 1; } - virtual int64 GetElapsedTime() const { return elapsed_time_; } - virtual int64 GetTimeStamp() const { return video_frame_.TimeStamp(); } - virtual void SetElapsedTime(int64 elapsed_time) { - elapsed_time_ = elapsed_time; - } - virtual void SetTimeStamp(int64 time_stamp) { - video_frame_.SetTimeStamp(time_stamp); - } - - virtual VideoFrame* Copy() const; - virtual size_t CopyToBuffer(uint8* buffer, size_t size) const; - virtual size_t ConvertToRgbBuffer(uint32 to_fourcc, uint8* buffer, - size_t size, size_t pitch_rgb) const; - virtual void StretchToPlanes(uint8* y, uint8* u, uint8* v, - int32 pitchY, int32 pitchU, int32 pitchV, - size_t width, size_t height, - bool interpolate, bool crop) const; - virtual size_t StretchToBuffer(size_t w, size_t h, uint8* buffer, size_t size, - bool interpolate, bool crop) const; - virtual void StretchToFrame(VideoFrame* target, bool interpolate, - bool crop) const; - virtual VideoFrame* Stretch(size_t w, size_t h, bool interpolate, - bool crop) const; - - private: - webrtc::VideoFrame video_frame_; - int64 elapsed_time_; -}; - -class CricketWebRTCVideoRenderer : public ExternalRenderer { - public: - CricketWebRTCVideoRenderer(cricket::VideoRenderer* renderer); - - virtual int FrameSizeChange(unsigned int width, unsigned int height, - unsigned int numberOfStreams); - virtual int DeliverFrame(unsigned char* buffer, int bufferSize); - virtual ~CricketWebRTCVideoRenderer(); - - private: - cricket::VideoRenderer* renderer_; - CricketWebRTCVideoFrame video_frame_; - unsigned int width_; - unsigned int height_; - unsigned int number_of_streams_; -}; - class RtcVideoEngine : public ViEBaseObserver, public TraceCallback { public: RtcVideoEngine(); @@ -140,6 +72,13 @@ class RtcVideoEngine : public ViEBaseObserver, public TraceCallback { bool SetOptions(int options); //TODO - need to change this interface for webrtc bool SetCaptureDevice(const cricket::Device* device); + bool SetVideoRenderer(int channel_id, + void* window, + unsigned int zOrder, + float left, + float top, + float right, + float bottom); bool SetLocalRenderer(cricket::VideoRenderer* renderer); cricket::CaptureResult SetCapture(bool capture); const std::vector& codecs() const; @@ -194,7 +133,6 @@ class RtcVideoEngine : public ViEBaseObserver, public TraceCallback { cricket::VideoEncoderConfig default_encoder_config_; cricket::VideoCodec default_codec_; bool capture_started_; - talk_base::scoped_ptr local_renderer_; }; class RtcVideoMediaChannel: public cricket::VideoMediaChannel, @@ -250,7 +188,6 @@ class RtcVideoMediaChannel: public cricket::VideoMediaChannel, bool sending_; bool render_started_; webrtc::VideoCodec send_codec_; - talk_base::scoped_ptr remote_renderer_; }; } diff --git a/third_party_mods/libjingle/source/talk/app/webrtcchannelmanager.cc b/third_party_mods/libjingle/source/talk/app/webrtcchannelmanager.cc new file mode 100644 index 0000000000..8b624fd905 --- /dev/null +++ b/third_party_mods/libjingle/source/talk/app/webrtcchannelmanager.cc @@ -0,0 +1,137 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// Author: mallinath@google.com (Mallinath Bareddy) + +#include "talk/app/webrtcchannelmanager.h" + +namespace webrtc { + +struct VideoCaptureDeviceParams : public talk_base::MessageData { + VideoCaptureDeviceParams(const std::string& cam_device) + : cam_device(cam_device), + result(false) {} + const std::string cam_device; + bool result; +}; + +struct RenderParams : public talk_base::MessageData { + RenderParams(int channel_id, + void* window, + unsigned int zOrder, + float left, + float top, + float right, + float bottom) + :channel_id(channel_id) + ,window(window) + ,zOrder(zOrder) + ,left(left) + ,top(top) + ,right(right) + ,bottom(bottom) {} + + int channel_id; + void* window; + unsigned int zOrder; + float left; + float top; + float right; + float bottom; + bool result; +}; + +bool WebRtcChannelManager::Init() { + return MaybeInit(); +} + +cricket::VoiceChannel* WebRtcChannelManager::CreateVoiceChannel( + cricket::BaseSession* s, const std::string& content_name, bool rtcp) { + return (MaybeInit()) ? + ChannelManager::CreateVoiceChannel(s, content_name, rtcp) : NULL; +} + +cricket::VideoChannel* WebRtcChannelManager::CreateVideoChannel( + cricket::BaseSession* s, const std::string& content_name, bool rtcp, + cricket::VoiceChannel* vc) { + return (MaybeInit()) ? + ChannelManager::CreateVideoChannel(s, content_name, rtcp, vc) : NULL; + +} + +cricket::Soundclip* WebRtcChannelManager::CreateSoundclip() { + return (MaybeInit()) ? ChannelManager::CreateSoundclip() : NULL; +} +void WebRtcChannelManager::DestroyVoiceChannel(cricket::VoiceChannel* vc) { + ChannelManager::DestroyVoiceChannel(vc); + MaybeTerm(); +} +void WebRtcChannelManager::DestroyVideoChannel(cricket::VideoChannel* vc) { + ChannelManager::DestroyVideoChannel(vc); + MaybeTerm(); +} +void WebRtcChannelManager::DestroySoundclip(cricket::Soundclip* s) { + ChannelManager::DestroySoundclip(s); + MaybeTerm(); +} + +bool WebRtcChannelManager::MaybeInit() { + bool ret = initialized(); + if (!ret) { + ret = ChannelManager::Init(); + } + return ret; +} + +void WebRtcChannelManager::MaybeTerm() { + if (initialized() && !has_channels()) { + Terminate(); + } +} + +bool WebRtcChannelManager::SetVideoRenderer(int channel_id, + void* window, + unsigned int zOrder, + float left, + float top, + float right, + float bottom) { + if (MaybeInit()) { + RenderParams params(channel_id, window, zOrder, left, top, right, bottom); + return cricket::ChannelManager::Send(MSG_SETRTC_VIDEORENDERER, ¶ms); + } else { + return false; + } +} + +void WebRtcChannelManager::SetVideoRenderer_w(int channel_id, + void* window, + unsigned int zOrder, + float left, + float top, + float right, + float bottom) { + ASSERT(worker_thread() == talk_base::Thread::Current()); + ASSERT(initialized()); + media_engine()->SetVideoRenderer(channel_id, window, zOrder, left, top, right, bottom); +} + +void WebRtcChannelManager::OnMessage(talk_base::Message *message) { + talk_base::MessageData* data = message->pdata; + switch(message->message_id) { + case MSG_SETRTC_VIDEORENDERER: { + RenderParams* p = static_cast(data); + SetVideoRenderer_w(p->channel_id, + p->window, + p->zOrder, + p->left, + p->top, + p->right, + p->bottom); + break; + } + default: { + ChannelManager::OnMessage(message); + } + } +} + +} // namespace webrtc diff --git a/third_party_mods/libjingle/source/talk/app/webrtcchannelmanager.h b/third_party_mods/libjingle/source/talk/app/webrtcchannelmanager.h new file mode 100644 index 0000000000..b8f15a8eec --- /dev/null +++ b/third_party_mods/libjingle/source/talk/app/webrtcchannelmanager.h @@ -0,0 +1,68 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// Author: mallinath@google.com (Mallinath Bareddy) + + +#ifndef TALK_APP_WEBRTC_WEBRTCCHANNELMANAGER_H_ +#define TALK_APP_WEBRTC_WEBRTCCHANNELMANAGER_H_ + +#include "talk/session/phone/channelmanager.h" + +namespace webrtc { + +class AudioDeviceModule; + +enum { + MSG_SETRTC_VIDEORENDERER = 21, // Set internal video renderer +}; + +// WebRtcChannelManager automatically takes care of initialization and +// cricket::ChannelManager. Terminates when not needed + +class WebRtcChannelManager : public cricket::ChannelManager { + public: + WebRtcChannelManager(talk_base::Thread* worker_thread) + : ChannelManager(worker_thread) { + } + + WebRtcChannelManager(cricket::MediaEngine* me, cricket::DeviceManager* dm, + talk_base::Thread* worker_thread) + : ChannelManager(me, dm, worker_thread) { + } + + bool Init(); + cricket::VoiceChannel* CreateVoiceChannel( + cricket::BaseSession* s, const std::string& content_name, bool rtcp); + cricket::VideoChannel* CreateVideoChannel( + cricket::BaseSession* s, const std::string& content_name, bool rtcp, + cricket::VoiceChannel* vc); + cricket::Soundclip* CreateSoundclip(); + void DestroyVoiceChannel(cricket::VoiceChannel* vc); + void DestroyVideoChannel(cricket::VideoChannel* vc); + void DestroySoundclip(cricket::Soundclip* s); + + bool SetVideoRenderer(int channel_id, + void* window, + unsigned int zOrder, + float left, + float top, + float right, + float bottom); + + private: + bool MaybeInit(); + void MaybeTerm(); + void SetExternalAdm_w(AudioDeviceModule* external_adm); + void SetVideoRenderer_w(int channel_id, + void* window, + unsigned int zOrder, + float left, + float top, + float right, + float bottom); + void OnMessage(talk_base::Message *message); +}; + +} // namespace webrtc + + +#endif /* TALK_APP_WEBRTC_WEBRTCCHANNELMANAGER_H_ */ diff --git a/third_party_mods/libjingle/source/talk/app/webrtcsessionimpl.cc b/third_party_mods/libjingle/source/talk/app/webrtcsessionimpl.cc index f71f6aaae6..7c916c90ac 100644 --- a/third_party_mods/libjingle/source/talk/app/webrtcsessionimpl.cc +++ b/third_party_mods/libjingle/source/talk/app/webrtcsessionimpl.cc @@ -29,19 +29,20 @@ #include #include -#include "talk/app/pc_transport_impl.h" -#include "talk/app/peerconnection.h" -#include "talk/app/webrtc_json.h" #include "talk/base/common.h" #include "talk/base/json.h" #include "talk/base/scoped_ptr.h" #include "talk/p2p/base/constants.h" #include "talk/p2p/base/sessiondescription.h" #include "talk/p2p/base/p2ptransport.h" -#include "talk/session/phone/channel.h" -#include "talk/session/phone/channelmanager.h" #include "talk/session/phone/mediasessionclient.h" +#include "talk/session/phone/channel.h" #include "talk/session/phone/voicechannel.h" +#include "talk/session/phone/channelmanager.h" +#include "talk/app/webrtc_json.h" +#include "talk/app/webrtcchannelmanager.h" +#include "talk/app/peerconnection.h" +#include "talk/app/pc_transport_impl.h" using namespace cricket; @@ -54,7 +55,7 @@ enum { MSG_RTC_SETVIDEOCAPTURE = 4, MSG_RTC_CANDIDATETIMEOUT = 5, MSG_RTC_SETEXTERNALRENDERER = 6, - MSG_RTC_SETCRICKETRENDERER = 7, + MSG_RTC_SETRENDERER = 7, MSG_RTC_CHANNELENABLE = 8, MSG_RTC_SIGNALONWRITABLESTATE = 9, MSG_RTC_DESTROYVOICECHANNEL = 10, @@ -106,15 +107,29 @@ struct ExternalRenderParams : public talk_base::MessageData { bool result; }; -struct CricketRenderParams : public talk_base::MessageData { - CricketRenderParams(const std::string& stream_id, - cricket::VideoRenderer* renderer) - : stream_id(stream_id), - renderer(renderer), - result(false) {} +struct RenderParams : public talk_base::MessageData { + RenderParams(int channel_id, + void* window, + unsigned int zOrder, + float left, + float top, + float right, + float bottom) + :channel_id(channel_id) + ,window(window) + ,zOrder(zOrder) + ,left(left) + ,top(top) + ,right(right) + ,bottom(bottom) {} - const std::string stream_id; - cricket::VideoRenderer* renderer; + int channel_id; + void* window; + unsigned int zOrder; + float left; + float top; + float right; + float bottom; bool result; }; @@ -144,7 +159,7 @@ WebRTCSessionImpl::WebRTCSessionImpl( const std::string& id, const std::string& direction, cricket::PortAllocator* allocator, - cricket::ChannelManager* channelmgr, + WebRtcChannelManager* channelmgr, PeerConnection* connection, talk_base::Thread* signaling_thread) : WebRTCSession(id, direction, allocator, connection, signaling_thread), @@ -188,7 +203,7 @@ bool WebRTCSessionImpl::CreateVoiceChannel(const std::string& stream_id) { this, &WebRTCSessionImpl::OnVoiceChannelCreated); signaling_thread_->Post(this, MSG_RTC_CREATEAUDIOCHANNEL, - new CreateChannelParams(stream_id, true, NULL)); + new CreateChannelParams(stream_id, false, NULL)); return true; } @@ -240,7 +255,7 @@ bool WebRTCSessionImpl::CreateVideoChannel(const std::string& stream_id) { this, &WebRTCSessionImpl::OnVideoChannelCreated); signaling_thread_->Post(this, MSG_RTC_CREATEVIDEOCHANNEL, - new CreateChannelParams(stream_id, true, NULL)); + new CreateChannelParams(stream_id, false, NULL)); return true; } @@ -288,33 +303,6 @@ void WebRTCSessionImpl::OnVideoChannelCreated( } } -bool WebRTCSessionImpl::SetVideoRenderer(const std::string& stream_id, - cricket::VideoRenderer* renderer) { - if(signaling_thread_ != talk_base::Thread::Current()) { - signaling_thread_->Post(this, MSG_RTC_SETCRICKETRENDERER, - new CricketRenderParams(stream_id, renderer), - true); - return true; - } - - ASSERT(signaling_thread_ == talk_base::Thread::Current()); - - bool ret = false; - StreamMap::iterator iter; - for (iter = streams_.begin(); iter != streams_.end(); ++iter) { - StreamInfo* stream_info = (*iter); - if (stream_info->stream_id.compare(stream_id) == 0) { - ASSERT(stream_info->channel != NULL); - ASSERT(stream_info->video); - cricket::VideoChannel* channel = static_cast( - stream_info->channel); - ret = channel->SetRenderer(0, renderer); - break; - } - } - return ret; -} - bool WebRTCSessionImpl::SetVideoRenderer(const std::string& stream_id, ExternalRenderer* external_renderer) { if(signaling_thread_ != talk_base::Thread::Current()) { @@ -342,6 +330,30 @@ bool WebRTCSessionImpl::SetVideoRenderer(const std::string& stream_id, return ret; } +bool WebRTCSessionImpl::SetVideoRenderer(int channel_id, + void* window, + unsigned int zOrder, + float left, + float top, + float right, + float bottom) { + signaling_thread_->Post(this, MSG_RTC_SETRENDERER, + new RenderParams(channel_id, window, zOrder, left, top, right, bottom), + true); + return true; +} + +bool WebRTCSessionImpl::SetVideoRenderer_w(int channel_id, + void* window, + unsigned int zOrder, + float left, + float top, + float right, + float bottom) { + ASSERT(signaling_thread_ == talk_base::Thread::Current()); + return channel_manager_->SetVideoRenderer(channel_id, window, zOrder, left, top, right, bottom); +} + void WebRTCSessionImpl::OnMessage(talk_base::Message* message) { using talk_base::TypedMessageData; talk_base::MessageData* data = message->pdata; @@ -408,25 +420,31 @@ void WebRTCSessionImpl::OnMessage(talk_base::Message* message) { break; } case MSG_RTC_SETVIDEOCAPTURE : { - CaptureParams* p = reinterpret_cast(data); + CaptureParams* p = static_cast(data); p->result = SetVideoCapture_w(p->capture); delete p; break; } case MSG_RTC_SETEXTERNALRENDERER : { - ExternalRenderParams* p = reinterpret_cast(data); + ExternalRenderParams* p = static_cast (data); p->result = SetVideoRenderer(p->stream_id, p->external_renderer); delete p; break; } - case MSG_RTC_SETCRICKETRENDERER : { - CricketRenderParams* p = reinterpret_cast(data); - p->result = SetVideoRenderer(p->stream_id, p->renderer); + case MSG_RTC_SETRENDERER : { + RenderParams* p = static_cast (data); + p->result = SetVideoRenderer_w(p->channel_id, + p->window, + p->zOrder, + p->left, + p->top, + p->right, + p->bottom); delete p; break; } case MSG_RTC_CHANNELENABLE : { - ChannelEnableParams* p = reinterpret_cast(data); + ChannelEnableParams* p = static_cast (data); ChannelEnable_w(p->channel, p->enable); delete p; break; @@ -689,6 +707,8 @@ void WebRTCSessionImpl::DestroyChannel( break; } } + + ASSERT(found); } void WebRTCSessionImpl::DestroyVoiceChannel_w( diff --git a/third_party_mods/libjingle/source/talk/app/webrtcsessionimpl.h b/third_party_mods/libjingle/source/talk/app/webrtcsessionimpl.h index 95db057c16..20a141a4a6 100644 --- a/third_party_mods/libjingle/source/talk/app/webrtcsessionimpl.h +++ b/third_party_mods/libjingle/source/talk/app/webrtcsessionimpl.h @@ -79,6 +79,7 @@ typedef std::vector VideoCodecs; class ExternalRenderer; class PeerConnection; +class WebRtcChannelManager; class WebRTCSessionImpl: public WebRTCSession { @@ -87,7 +88,7 @@ class WebRTCSessionImpl: public WebRTCSession { WebRTCSessionImpl(const std::string& id, const std::string& direction, cricket::PortAllocator* allocator, - cricket::ChannelManager* channelmgr, + WebRtcChannelManager* channelmgr, PeerConnection* connection, talk_base::Thread* signaling_thread); @@ -129,11 +130,15 @@ class WebRTCSessionImpl: public WebRTCSession { void OnStateChange(P2PTransportClass::State state, cricket::TransportChannel* channel); void OnMessageReceived(const char* data, size_t data_size); - bool SetVideoRenderer(const std::string& stream_id, - cricket::VideoRenderer* renderer); bool SetVideoRenderer(const std::string& stream_id, ExternalRenderer* external_renderer); - + bool SetVideoRenderer(int channel_id, + void* window, + unsigned int zOrder, + float left, + float top, + float right, + float bottom); sigslot::signal2 SignalVideoChannel; sigslot::signal2 SignalVoiceChannel; sigslot::signal1 SignalOnRemoveStream; @@ -150,6 +155,13 @@ class WebRTCSessionImpl: public WebRTCSession { } private: + bool SetVideoRenderer_w(int channel_id, + void* window, + unsigned int zOrder, + float left, + float top, + float right, + float bottom); void ChannelEnable_w(cricket::BaseChannel* channel, bool enable); void OnVoiceChannelError(cricket::VoiceChannel* voice_channel, uint32 ssrc, @@ -220,7 +232,7 @@ class WebRTCSessionImpl: public WebRTCSession { void SendLocalDescription_w(); - cricket::ChannelManager* channel_manager_; + WebRtcChannelManager* channel_manager_; std::vector streams_; TransportChannelMap transport_channels_; bool all_writable_; diff --git a/third_party_mods/libjingle/source/talk/session/phone/channelmanager.cc b/third_party_mods/libjingle/source/talk/session/phone/channelmanager.cc new file mode 100644 index 0000000000..1c76f02537 --- /dev/null +++ b/third_party_mods/libjingle/source/talk/session/phone/channelmanager.cc @@ -0,0 +1,798 @@ +/* + * 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 +#endif + +#include + +#include "talk/base/common.h" +#include "talk/base/logging.h" +#include "talk/base/sigslotrepeater.h" +#include "talk/base/stringencode.h" +#include "talk/session/phone/mediaengine.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, +}; + +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 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; +}; + +ChannelManager::ChannelManager(talk_base::Thread* worker_thread) + : media_engine_(MediaEngine::Create()), + device_manager_(new DeviceManager()), + initialized_(false), + main_thread_(talk_base::Thread::Current()), + worker_thread_(worker_thread), + audio_in_device_(DeviceManager::kDefaultDeviceName), + audio_out_device_(DeviceManager::kDefaultDeviceName), + audio_options_(MediaEngine::DEFAULT_AUDIO_OPTIONS), + local_renderer_(NULL), + capturing_(false), + monitoring_(false) { + Construct(); +} + +ChannelManager::ChannelManager(MediaEngine* me, DeviceManager* 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_(DeviceManager::kDefaultDeviceName), + audio_out_device_(DeviceManager::kDefaultDeviceName), + audio_options_(MediaEngine::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(DeviceManager::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* codecs) const { + codecs->clear(); + + for (std::vector::const_iterator it = + media_engine_->audio_codecs().begin(); + it != media_engine_->audio_codecs().end(); ++it) { + codecs->push_back(*it); + } +} + +void ChannelManager::GetSupportedVideoCodecs( + std::vector* codecs) const { + codecs->clear(); + + std::vector::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_ = DeviceManager::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_ = DeviceManager::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_ = DeviceManager::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; + } + + // 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()); + } + + media_engine_->Terminate(); + initialized_ = false; +} + +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) { + talk_base::CritScope cs(&crit_); + + // 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); + voice_channels_.push_back(voice_channel); + return voice_channel; +} + +void ChannelManager::DestroyVoiceChannel(VoiceChannel* voice_channel) { + if (voice_channel) { + talk_base::TypedMessageData data(voice_channel); + Send(MSG_DESTROYVOICECHANNEL, &data); + } +} + +void ChannelManager::DestroyVoiceChannel_w(VoiceChannel* voice_channel) { + talk_base::CritScope cs(&crit_); + // 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) { + talk_base::CritScope cs(&crit_); + + // 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); + video_channels_.push_back(video_channel); + return video_channel; +} + +void ChannelManager::DestroyVideoChannel(VideoChannel* video_channel) { + if (video_channel) { + talk_base::TypedMessageData data(video_channel); + Send(MSG_DESTROYVIDEOCHANNEL, &data); + } +} + +void ChannelManager::DestroyVideoChannel_w(VideoChannel *video_channel) { + talk_base::CritScope cs(&crit_); + // Destroy voice channel. + ASSERT(initialized_); + VideoChannels::iterator it = std::find(video_channels_.begin(), + video_channels_.end(), video_channel); + if (it == video_channels_.end()) + return; + + video_channels_.erase(it); + delete video_channel; +} + +Soundclip* ChannelManager::CreateSoundclip() { + talk_base::TypedMessageData data(NULL); + Send(MSG_CREATESOUNDCLIP, &data); + return data.data(); +} + +Soundclip* ChannelManager::CreateSoundclip_w() { + talk_base::CritScope cs(&crit_); + + 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 data(soundclip); + Send(MSG_DESTROYSOUNDCLIP, &data); + } +} + +void ChannelManager::DestroySoundclip_w(Soundclip* soundclip) { + talk_base::CritScope cs(&crit_); + // 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) { + talk_base::CritScope cs(&crit_); + 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); +} + +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); + } +} + +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(CaptureResult result) { + capturing_ = result == CR_SUCCESS; + main_thread_->Post(this, MSG_CAMERASTARTED, + new talk_base::TypedMessageData(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(data); + p->voice_channel = + CreateVoiceChannel_w(p->session, p->content_name, p->rtcp); + break; + } + case MSG_DESTROYVOICECHANNEL: { + VoiceChannel* p = static_cast*> + (data)->data(); + DestroyVoiceChannel_w(p); + break; + } + case MSG_CREATEVIDEOCHANNEL: { + CreationParams* p = static_cast(data); + p->video_channel = CreateVideoChannel_w(p->session, p->content_name, + p->rtcp, p->voice_channel); + break; + } + case MSG_DESTROYVIDEOCHANNEL: { + VideoChannel* p = static_cast*> + (data)->data(); + DestroyVideoChannel_w(p); + break; + } + case MSG_CREATESOUNDCLIP: { + talk_base::TypedMessageData *p = + static_cast*>(data); + p->data() = CreateSoundclip_w(); + break; + } + case MSG_DESTROYSOUNDCLIP: { + talk_base::TypedMessageData *p = + static_cast*>(data); + DestroySoundclip_w(p->data()); + break; + } + case MSG_SETAUDIOOPTIONS: { + AudioOptions* p = static_cast(data); + p->result = SetAudioOptions_w(p->options, + p->in_device, p->out_device); + break; + } + case MSG_GETOUTPUTVOLUME: { + VolumeLevel* p = static_cast(data); + p->result = GetOutputVolume_w(&p->level); + break; + } + case MSG_SETOUTPUTVOLUME: { + VolumeLevel* p = static_cast(data); + p->result = SetOutputVolume_w(p->level); + break; + } + case MSG_SETLOCALMONITOR: { + LocalMonitor* p = static_cast(data); + p->result = SetLocalMonitor_w(p->enable); + break; + } + case MSG_SETVIDEOOPTIONS: { + VideoOptions* p = static_cast(data); + p->result = SetVideoOptions_w(p->cam_device); + break; + } + case MSG_SETDEFAULTVIDEOENCODERCONFIG: { + DefaultVideoEncoderConfig* p = + static_cast(data); + p->result = SetDefaultVideoEncoderConfig_w(p->config); + break; + } + case MSG_SETLOCALRENDERER: { + LocalRenderer* p = static_cast(data); + p->result = SetLocalRenderer_w(p->renderer); + break; + } + case MSG_SETVIDEOCAPTURE: { + CaptureParams* p = static_cast(data); + p->result = SetVideoCapture_w(p->capture); + break; + } + case MSG_SETVOICELOGGING: + case MSG_SETVIDEOLOGGING: { + LoggingOptions* p = static_cast(data); + bool video = (message->message_id == MSG_SETVIDEOLOGGING); + SetMediaLogging_w(video, p->level, p->filter.c_str()); + break; + } + case MSG_CAMERASTARTED: { + talk_base::TypedMessageData* data = + static_cast*>( + message->pdata); + SignalVideoCaptureResult(data->data()); + delete data; + break; + } + } +} + +static void GetDeviceNames(const std::vector& devs, + std::vector* names) { + names->clear(); + for (size_t i = 0; i < devs.size(); ++i) { + names->push_back(devs[i].name); + } +} + +bool ChannelManager::GetAudioInputDevices(std::vector* names) { + names->clear(); + std::vector devs; + bool ret = device_manager_->GetAudioInputDevices(&devs); + if (ret) + GetDeviceNames(devs, names); + + return ret; +} + +bool ChannelManager::GetAudioOutputDevices(std::vector* names) { + names->clear(); + std::vector devs; + bool ret = device_manager_->GetAudioOutputDevices(&devs); + if (ret) + GetDeviceNames(devs, names); + + return ret; +} + +bool ChannelManager::GetVideoCaptureDevices(std::vector* names) { + names->clear(); + std::vector devs; + bool ret = device_manager_->GetVideoCaptureDevices(&devs); + if (ret) + GetDeviceNames(devs, names); + + return ret; +} + +} // namespace cricket diff --git a/third_party_mods/libjingle/source/talk/session/phone/channelmanager.h b/third_party_mods/libjingle/source/talk/session/phone/channelmanager.h new file mode 100644 index 0000000000..bfdf5d5923 --- /dev/null +++ b/third_party_mods/libjingle/source/talk/session/phone/channelmanager.h @@ -0,0 +1,208 @@ +/* + * 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. + */ + +#ifndef TALK_SESSION_PHONE_CHANNELMANAGER_H_ +#define TALK_SESSION_PHONE_CHANNELMANAGER_H_ + +#include +#include + +#include "talk/base/criticalsection.h" +#include "talk/base/sigslotrepeater.h" +#include "talk/base/thread.h" +#include "talk/p2p/base/session.h" +#include "talk/session/phone/voicechannel.h" +#include "talk/session/phone/mediaengine.h" +#include "talk/session/phone/devicemanager.h" + +namespace cricket { + +class Soundclip; +class VoiceChannel; + +// ChannelManager allows the MediaEngine to run on a separate thread, and takes +// care of marshalling calls between threads. It also creates and keeps track of +// voice and video channels; by doing so, it can temporarily pause all the +// channels when a new audio or video device is chosen. The voice and video +// channels are stored in separate vectors, to easily allow operations on just +// voice or just video channels. +// ChannelManager also allows the application to discover what devices it has +// using device manager. +class ChannelManager : public talk_base::MessageHandler, + public sigslot::has_slots<> { + public: + // Creates the channel manager, and specifies the worker thread to use. + explicit ChannelManager(talk_base::Thread* worker); + // For testing purposes. Allows the media engine and dev manager to be mocks. + // The ChannelManager takes ownership of these objects. + ChannelManager(MediaEngine* me, DeviceManager* dm, talk_base::Thread* worker); + ~ChannelManager(); + + // Accessors for the worker thread, allowing it to be set after construction, + // but before Init. set_worker_thread will return false if called after Init. + talk_base::Thread* worker_thread() const { return worker_thread_; } + bool set_worker_thread(talk_base::Thread* thread) { + if (initialized_) return false; + worker_thread_ = thread; + return true; + } + + // Gets capabilities. Can be called prior to starting the media engine. + int GetCapabilities(); + + // Retrieves the list of supported audio & video codec types. + // Can be called before starting the media engine. + void GetSupportedAudioCodecs(std::vector* codecs) const; + void GetSupportedVideoCodecs(std::vector* codecs) const; + + // Indicates whether the media engine is started. + bool initialized() const { return initialized_; } + // Starts up the media engine. + bool Init(); + // TODO: Remove this temporary API once Flute is updated. + bool Init(talk_base::Thread* thread) { + return set_worker_thread(thread) && Init(); + } + // Shuts down the media engine. + void Terminate(); + + // The operations below all occur on the worker thread. + + // Creates a voice channel, to be associated with the specified session. + VoiceChannel* CreateVoiceChannel( + BaseSession* session, const std::string& content_name, bool rtcp); + // Destroys a voice channel created with the Create API. + void DestroyVoiceChannel(VoiceChannel* voice_channel); + // Creates a video channel, synced with the specified voice channel, and + // associated with the specified session. + VideoChannel* CreateVideoChannel( + BaseSession* session, const std::string& content_name, bool rtcp, + VoiceChannel* voice_channel); + // Destroys a video channel created with the Create API. + void DestroyVideoChannel(VideoChannel* video_channel); + + // Creates a soundclip. + Soundclip* CreateSoundclip(); + // Destroys a soundclip created with the Create API. + void DestroySoundclip(Soundclip* soundclip); + + // Indicates whether any channels exist. + bool has_channels() const { + return (!voice_channels_.empty() || !video_channels_.empty() || + !soundclips_.empty()); + } + + // Configures the audio and video devices. + bool GetAudioOptions(std::string* wave_in_device, + std::string* wave_out_device, int* opts); + bool SetAudioOptions(const std::string& wave_in_device, + const std::string& wave_out_device, int opts); + bool GetOutputVolume(int* level); + bool SetOutputVolume(int level); + bool GetVideoOptions(std::string* cam_device); + bool SetVideoOptions(const std::string& cam_device); + bool SetDefaultVideoEncoderConfig(const VideoEncoderConfig& config); + + // Starts/stops the local microphone and enables polling of the input level. + bool SetLocalMonitor(bool enable); + bool monitoring() const { return monitoring_; } + // Sets the local renderer where to renderer the local camera. + bool SetLocalRenderer(VideoRenderer* renderer); + // Starts and stops the local camera and renders it to the local renderer. + CaptureResult SetVideoCapture(bool capture); + bool capturing() const { return capturing_; } + + // Configures the logging output of the mediaengine(s). + void SetVoiceLogging(int level, const char* filter); + void SetVideoLogging(int level, const char* filter); + + // The operations below occur on the main thread. + + bool GetAudioInputDevices(std::vector* names); + bool GetAudioOutputDevices(std::vector* names); + bool GetVideoCaptureDevices(std::vector* names); + sigslot::repeater0<> SignalDevicesChange; + sigslot::signal1 SignalVideoCaptureResult; + + protected: + bool Send(uint32 id, talk_base::MessageData* pdata); + void OnMessage(talk_base::Message *message); + MediaEngine* media_engine() { return media_engine_.get(); } + + private: + typedef std::vector VoiceChannels; + typedef std::vector VideoChannels; + typedef std::vector Soundclips; + + void Construct(); + VoiceChannel* CreateVoiceChannel_w( + BaseSession* session, const std::string& content_name, bool rtcp); + void DestroyVoiceChannel_w(VoiceChannel* voice_channel); + VideoChannel* CreateVideoChannel_w( + BaseSession* session, const std::string& content_name, bool rtcp, + VoiceChannel* voice_channel); + void DestroyVideoChannel_w(VideoChannel* video_channel); + Soundclip* CreateSoundclip_w(); + void DestroySoundclip_w(Soundclip* soundclip); + bool SetAudioOptions_w(int opts, const Device* in_dev, + const Device* out_dev); + bool GetOutputVolume_w(int* level); + bool SetOutputVolume_w(int level); + bool SetLocalMonitor_w(bool enable); + bool SetVideoOptions_w(const Device* cam_device); + bool SetDefaultVideoEncoderConfig_w(const VideoEncoderConfig& config); + bool SetLocalRenderer_w(VideoRenderer* renderer); + CaptureResult SetVideoCapture_w(bool capture); + void SetMediaLogging(bool video, int level, const char* filter); + void SetMediaLogging_w(bool video, int level, const char* filter); + void OnVideoCaptureResult(CaptureResult result); + + talk_base::CriticalSection crit_; + talk_base::scoped_ptr media_engine_; + talk_base::scoped_ptr device_manager_; + bool initialized_; + talk_base::Thread* main_thread_; + talk_base::Thread* worker_thread_; + + VoiceChannels voice_channels_; + VideoChannels video_channels_; + Soundclips soundclips_; + + std::string audio_in_device_; + std::string audio_out_device_; + int audio_options_; + std::string camera_device_; + VideoEncoderConfig default_video_encoder_config_; + VideoRenderer* local_renderer_; + + bool capturing_; + bool monitoring_; +}; + +} // namespace cricket + +#endif // TALK_SESSION_PHONE_CHANNELMANAGER_H_ diff --git a/third_party_mods/libjingle/source/talk/session/phone/mediachannel.h b/third_party_mods/libjingle/source/talk/session/phone/mediachannel.h new file mode 100644 index 0000000000..7062761411 --- /dev/null +++ b/third_party_mods/libjingle/source/talk/session/phone/mediachannel.h @@ -0,0 +1,501 @@ +/* + * libjingle + * Copyright 2004--2010, 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. + */ + +#ifndef TALK_SESSION_PHONE_MEDIACHANNEL_H_ +#define TALK_SESSION_PHONE_MEDIACHANNEL_H_ + +#include +#include + +#include "talk/base/basictypes.h" +#include "talk/base/sigslot.h" +#include "talk/base/socket.h" +#include "talk/session/phone/codec.h" +// TODO: re-evaluate this include +#include "talk/session/phone/audiomonitor.h" + +namespace talk_base { +class Buffer; +} + +namespace flute { +class MagicCamVideoRenderer; +} + +namespace cricket { + +const int kMinRtpHeaderExtensionId = 1; +const int kMaxRtpHeaderExtensionId = 255; + +struct RtpHeaderExtension { + RtpHeaderExtension(const std::string& u, int i) : uri(u), id(i) {} + std::string uri; + int id; + // TODO: SendRecv direction; +}; + +enum VoiceMediaChannelOptions { + OPT_CONFERENCE = 0x10000, // tune the audio stream for conference mode + +}; + +enum VideoMediaChannelOptions { + OPT_INTERPOLATE = 0x10000 // Increase the output framerate by 2x by + // interpolating frames +}; + +class MediaChannel : public sigslot::has_slots<> { + public: + class NetworkInterface { + public: + enum SocketType { ST_RTP, ST_RTCP }; + virtual bool SendPacket(talk_base::Buffer* packet) = 0; + virtual bool SendRtcp(talk_base::Buffer* packet) = 0; + virtual int SetOption(SocketType type, talk_base::Socket::Option opt, + int option) = 0; + virtual ~NetworkInterface() {} + }; + + MediaChannel() : network_interface_(NULL) {} + virtual ~MediaChannel() {} + + // Gets/sets the abstract inteface class for sending RTP/RTCP data. + NetworkInterface *network_interface() { return network_interface_; } + virtual void SetInterface(NetworkInterface *iface) { + network_interface_ = iface; + } + + // Called when a RTP packet is received. + virtual void OnPacketReceived(talk_base::Buffer* packet) = 0; + // Called when a RTCP packet is received. + virtual void OnRtcpReceived(talk_base::Buffer* packet) = 0; + // Sets the SSRC to be used for outgoing data. + virtual void SetSendSsrc(uint32 id) = 0; + // Set the CNAME of RTCP + virtual bool SetRtcpCName(const std::string& cname) = 0; + // Mutes the channel. + virtual bool Mute(bool on) = 0; + + // Sets the RTP extension headers and IDs to use when sending RTP. + virtual bool SetRecvRtpHeaderExtensions( + const std::vector& extensions) = 0; + virtual bool SetSendRtpHeaderExtensions( + const std::vector& extensions) = 0; + // Sets the rate control to use when sending data. + virtual bool SetSendBandwidth(bool autobw, int bps) = 0; + // Sets the media options to use. + virtual bool SetOptions(int options) = 0; + // Gets the Rtc channel id + virtual int GetMediaChannelId() = 0; + + protected: + NetworkInterface *network_interface_; +}; + +enum SendFlags { + SEND_NOTHING, + SEND_RINGBACKTONE, + SEND_MICROPHONE +}; + +struct VoiceSenderInfo { + uint32 ssrc; + int bytes_sent; + int packets_sent; + int packets_lost; + float fraction_lost; + int ext_seqnum; + int rtt_ms; + int jitter_ms; + int audio_level; +}; + +struct VoiceReceiverInfo { + uint32 ssrc; + int bytes_rcvd; + int packets_rcvd; + int packets_lost; + float fraction_lost; + int ext_seqnum; + int jitter_ms; + int jitter_buffer_ms; + int jitter_buffer_preferred_ms; + int delay_estimate_ms; + int audio_level; +}; + +struct VideoSenderInfo { + uint32 ssrc; + int bytes_sent; + int packets_sent; + int packets_cached; + int packets_lost; + float fraction_lost; + int firs_rcvd; + int nacks_rcvd; + int rtt_ms; + int frame_width; + int frame_height; + int framerate_input; + int framerate_sent; + int nominal_bitrate; + int preferred_bitrate; +}; + +struct VideoReceiverInfo { + uint32 ssrc; + int bytes_rcvd; + // vector layer_bytes_rcvd; + int packets_rcvd; + int packets_lost; + int packets_concealed; + float fraction_lost; + int firs_sent; + int nacks_sent; + int frame_width; + int frame_height; + int framerate_rcvd; + int framerate_decoded; + int framerate_output; +}; + +struct BandwidthEstimationInfo { + int available_send_bandwidth; + int available_recv_bandwidth; + int target_enc_bitrate; + int actual_enc_bitrate; + int retransmit_bitrate; + int transmit_bitrate; + int bucket_delay; +}; + +struct VoiceMediaInfo { + void Clear() { + senders.clear(); + receivers.clear(); + } + std::vector senders; + std::vector receivers; +}; + +struct VideoMediaInfo { + void Clear() { + senders.clear(); + receivers.clear(); + bw_estimations.clear(); + } + std::vector senders; + std::vector receivers; + std::vector bw_estimations; +}; + +class VoiceMediaChannel : public MediaChannel { + public: + enum Error { + ERROR_NONE = 0, // No error. + ERROR_OTHER, // Other errors. + ERROR_REC_DEVICE_OPEN_FAILED = 100, // Could not open mic. + ERROR_REC_DEVICE_MUTED, // Mic was muted by OS. + ERROR_REC_DEVICE_SILENT, // No background noise picked up. + ERROR_REC_DEVICE_SATURATION, // Mic input is clipping. + ERROR_REC_DEVICE_REMOVED, // Mic was removed while active. + ERROR_REC_RUNTIME_ERROR, // Processing is encountering errors. + ERROR_REC_SRTP_ERROR, // Generic SRTP failure. + ERROR_REC_SRTP_AUTH_FAILED, // Failed to authenticate packets. + ERROR_REC_TYPING_NOISE_DETECTED, // Typing noise is detected. + ERROR_PLAY_DEVICE_OPEN_FAILED = 200, // Could not open playout. + ERROR_PLAY_DEVICE_MUTED, // Playout muted by OS. + ERROR_PLAY_DEVICE_REMOVED, // Playout removed while active. + ERROR_PLAY_RUNTIME_ERROR, // Errors in voice processing. + ERROR_PLAY_SRTP_ERROR, // Generic SRTP failure. + ERROR_PLAY_SRTP_AUTH_FAILED, // Failed to authenticate packets. + ERROR_PLAY_SRTP_REPLAY, // Packet replay detected. + }; + + VoiceMediaChannel() {} + virtual ~VoiceMediaChannel() {} + // Sets the codecs/payload types to be used for incoming media. + virtual bool SetRecvCodecs(const std::vector& codecs) = 0; + // Sets the codecs/payload types to be used for outgoing media. + virtual bool SetSendCodecs(const std::vector& codecs) = 0; + // Starts or stops playout of received audio. + virtual bool SetPlayout(bool playout) = 0; + // Starts or stops sending (and potentially capture) of local audio. + virtual bool SetSend(SendFlags flag) = 0; + // Adds a new receive-only stream with the specified SSRC. + virtual bool AddStream(uint32 ssrc) = 0; + // Removes a stream added with AddStream. + virtual bool RemoveStream(uint32 ssrc) = 0; + // Gets current energy levels for all incoming streams. + virtual bool GetActiveStreams(AudioInfo::StreamList* actives) = 0; + // Get the current energy level for the outgoing stream. + virtual int GetOutputLevel() = 0; + // Specifies a ringback tone to be played during call setup. + virtual bool SetRingbackTone(const char *buf, int len) = 0; + // Plays or stops the aforementioned ringback tone + virtual bool PlayRingbackTone(uint32 ssrc, bool play, bool loop) = 0; + // Sends a out-of-band DTMF signal using the specified event. + virtual bool PressDTMF(int event, bool playout) = 0; + // Gets quality stats for the channel. + virtual bool GetStats(VoiceMediaInfo* info) = 0; + // Gets last reported error for this media channel. + virtual void GetLastMediaError(uint32* ssrc, + VoiceMediaChannel::Error* error) { + ASSERT(error != NULL); + *error = ERROR_NONE; + } + // Signal errors from MediaChannel. Arguments are: + // ssrc(uint32), and error(VoiceMediaChannel::Error). + sigslot::signal2 SignalMediaError; +}; + +// Represents a YUV420 (a.k.a. I420) video frame. +class VideoFrame { + friend class flute::MagicCamVideoRenderer; + + public: + VideoFrame() : rendered_(false) {} + + virtual ~VideoFrame() {} + + virtual size_t GetWidth() const = 0; + virtual size_t GetHeight() const = 0; + virtual const uint8 *GetYPlane() const = 0; + virtual const uint8 *GetUPlane() const = 0; + virtual const uint8 *GetVPlane() const = 0; + virtual uint8 *GetYPlane() = 0; + virtual uint8 *GetUPlane() = 0; + virtual uint8 *GetVPlane() = 0; + virtual int32 GetYPitch() const = 0; + virtual int32 GetUPitch() const = 0; + virtual int32 GetVPitch() const = 0; + + // For retrieving the aspect ratio of each pixel. Usually this is 1x1, but + // the aspect_ratio_idc parameter of H.264 can specify non-square pixels. + virtual size_t GetPixelWidth() const = 0; + virtual size_t GetPixelHeight() const = 0; + + // TODO: Add a fourcc format here and probably combine VideoFrame + // with CapturedFrame. + virtual int64 GetElapsedTime() const = 0; + virtual int64 GetTimeStamp() const = 0; + virtual void SetElapsedTime(int64 elapsed_time) = 0; + virtual void SetTimeStamp(int64 time_stamp) = 0; + + // Make a copy of the frame. The frame buffer itself may not be copied, + // in which case both the current and new VideoFrame will share a single + // reference-counted frame buffer. + virtual VideoFrame *Copy() const = 0; + + // Writes the frame into the given frame buffer, provided that it is of + // sufficient size. Returns the frame's actual size, regardless of whether + // it was written or not (like snprintf). If there is insufficient space, + // nothing is written. + virtual size_t CopyToBuffer(uint8 *buffer, size_t size) const = 0; + + // Converts the I420 data to RGB of a certain type such as ARGB and ABGR. + // Returns the frame's actual size, regardless of whether it was written or + // not (like snprintf). Parameters size and pitch_rgb are in units of bytes. + // If there is insufficient space, nothing is written. + virtual size_t ConvertToRgbBuffer(uint32 to_fourcc, uint8 *buffer, + size_t size, size_t pitch_rgb) const = 0; + + // Writes the frame into the given planes, stretched to the given width and + // height. The parameter "interpolate" controls whether to interpolate or just + // take the nearest-point. The parameter "crop" controls whether to crop this + // frame to the aspect ratio of the given dimensions before stretching. + virtual void StretchToPlanes(uint8 *y, uint8 *u, uint8 *v, + int32 pitchY, int32 pitchU, int32 pitchV, + size_t width, size_t height, + bool interpolate, bool crop) const = 0; + + // Writes the frame into the given frame buffer, stretched to the given width + // and height, provided that it is of sufficient size. Returns the frame's + // actual size, regardless of whether it was written or not (like snprintf). + // If there is insufficient space, nothing is written. The parameter + // "interpolate" controls whether to interpolate or just take the + // nearest-point. The parameter "crop" controls whether to crop this frame to + // the aspect ratio of the given dimensions before stretching. + virtual size_t StretchToBuffer(size_t w, size_t h, uint8 *buffer, size_t size, + bool interpolate, bool crop) const = 0; + + // Writes the frame into the target VideoFrame, stretched to the size of that + // frame. The parameter "interpolate" controls whether to interpolate or just + // take the nearest-point. The parameter "crop" controls whether to crop this + // frame to the aspect ratio of the target frame before stretching. + virtual void StretchToFrame(VideoFrame *target, bool interpolate, + bool crop) const = 0; + + // Stretches the frame to the given size, creating a new VideoFrame object to + // hold it. The parameter "interpolate" controls whether to interpolate or + // just take the nearest-point. The parameter "crop" controls whether to crop + // this frame to the aspect ratio of the given dimensions before stretching. + virtual VideoFrame *Stretch(size_t w, size_t h, bool interpolate, + bool crop) const = 0; + + // Size of an I420 image of given dimensions when stored as a frame buffer. + static size_t SizeOf(size_t w, size_t h) { + return w * h + ((w + 1) / 2) * ((h + 1) / 2) * 2; + } + + protected: + // The frame needs to be rendered to magiccam only once. + // TODO: Remove this flag once magiccam rendering is fully replaced + // by client3d rendering. + mutable bool rendered_; +}; + +// Simple subclass for use in mocks. +class NullVideoFrame : public VideoFrame { + public: + virtual size_t GetWidth() const { return 0; } + virtual size_t GetHeight() const { return 0; } + virtual const uint8 *GetYPlane() const { return NULL; } + virtual const uint8 *GetUPlane() const { return NULL; } + virtual const uint8 *GetVPlane() const { return NULL; } + virtual uint8 *GetYPlane() { return NULL; } + virtual uint8 *GetUPlane() { return NULL; } + virtual uint8 *GetVPlane() { return NULL; } + virtual int32 GetYPitch() const { return 0; } + virtual int32 GetUPitch() const { return 0; } + virtual int32 GetVPitch() const { return 0; } + + virtual size_t GetPixelWidth() const { return 1; } + virtual size_t GetPixelHeight() const { return 1; } + virtual int64 GetElapsedTime() const { return 0; } + virtual int64 GetTimeStamp() const { return 0; } + virtual void SetElapsedTime(int64 elapsed_time) {} + virtual void SetTimeStamp(int64 time_stamp) {} + + virtual VideoFrame *Copy() const { + return NULL; + } + + virtual size_t CopyToBuffer(uint8 *buffer, size_t size) const { + return 0; + } + + virtual size_t ConvertToRgbBuffer(uint32 to_fourcc, uint8 *buffer, + size_t size, size_t pitch_rgb) const { + return 0; + } + + virtual void StretchToPlanes(uint8 *y, uint8 *u, uint8 *v, + int32 pitchY, int32 pitchU, int32 pitchV, + size_t width, size_t height, + bool interpolate, bool crop) const { + } + + virtual size_t StretchToBuffer(size_t w, size_t h, uint8 *buffer, size_t size, + bool interpolate, bool crop) const { + return 0; + } + + virtual void StretchToFrame(VideoFrame *target, bool interpolate, + bool crop) const { + } + + virtual VideoFrame *Stretch(size_t w, size_t h, bool interpolate, + bool crop) const { + return NULL; + } +}; + +// Abstract interface for rendering VideoFrames. +class VideoRenderer { + public: + virtual ~VideoRenderer() {} + // Called when the video has changed size. + virtual bool SetSize(int width, int height, int reserved) = 0; + // Called when a new frame is available for display. + virtual bool RenderFrame(const VideoFrame *frame) = 0; +}; + +// Simple implementation for use in tests. +class NullVideoRenderer : public VideoRenderer { + virtual bool SetSize(int width, int height, int reserved) { + return true; + } + // Called when a new frame is available for display. + virtual bool RenderFrame(const VideoFrame *frame) { + return true; + } +}; + +class VideoMediaChannel : public MediaChannel { + public: + enum Error { + ERROR_NONE = 0, // No error. + ERROR_OTHER, // Other errors. + ERROR_REC_DEVICE_OPEN_FAILED = 100, // Could not open camera. + ERROR_REC_DEVICE_NO_DEVICE, // No camera. + ERROR_REC_DEVICE_IN_USE, // Device is in already use. + ERROR_REC_DEVICE_REMOVED, // Device is removed. + ERROR_REC_SRTP_ERROR, // Generic sender SRTP failure. + ERROR_REC_SRTP_AUTH_FAILED, // Failed to authenticate packets. + ERROR_PLAY_SRTP_ERROR = 200, // Generic receiver SRTP failure. + ERROR_PLAY_SRTP_AUTH_FAILED, // Failed to authenticate packets. + ERROR_PLAY_SRTP_REPLAY, // Packet replay detected. + }; + + VideoMediaChannel() { renderer_ = NULL; } + virtual ~VideoMediaChannel() {} + // Sets the codecs/payload types to be used for incoming media. + virtual bool SetRecvCodecs(const std::vector &codecs) = 0; + // Sets the codecs/payload types to be used for outgoing media. + virtual bool SetSendCodecs(const std::vector &codecs) = 0; + // Starts or stops playout of received video. + virtual bool SetRender(bool render) = 0; + // Starts or stops transmission (and potentially capture) of local video. + virtual bool SetSend(bool send) = 0; + // Adds a new receive-only stream with the specified SSRC. + virtual bool AddStream(uint32 ssrc, uint32 voice_ssrc) = 0; + // Removes a stream added with AddStream. + virtual bool RemoveStream(uint32 ssrc) = 0; + // Sets the renderer object to be used for the specified stream. + // If SSRC is 0, the renderer is used for the 'default' stream. + virtual bool SetRenderer(uint32 ssrc, VideoRenderer* renderer) = 0; + // Sets the renderer object to be used for the specified stream. + // If SSRC is 0, the renderer is used for the 'default' stream. + virtual bool SetExternalRenderer(uint32 ssrc, void* renderer) = 0; + // Gets quality stats for the channel. + virtual bool GetStats(VideoMediaInfo* info) = 0; + + // Send an intra frame to the receivers. + virtual bool SendIntraFrame() = 0; + // Reuqest each of the remote senders to send an intra frame. + virtual bool RequestIntraFrame() = 0; + + sigslot::signal2 SignalMediaError; + + protected: + VideoRenderer *renderer_; +}; + +} // namespace cricket + +#endif // TALK_SESSION_PHONE_MEDIACHANNEL_H_ diff --git a/third_party_mods/libjingle/source/talk/session/phone/mediaengine.h b/third_party_mods/libjingle/source/talk/session/phone/mediaengine.h new file mode 100644 index 0000000000..05f0821c2f --- /dev/null +++ b/third_party_mods/libjingle/source/talk/session/phone/mediaengine.h @@ -0,0 +1,328 @@ +/* + * libjingle + * Copyright 2004--2007, 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. + */ + +#ifndef TALK_SESSION_PHONE_MEDIAENGINE_H_ +#define TALK_SESSION_PHONE_MEDIAENGINE_H_ + +#ifdef OSX +#include +#endif + +#include +#include + +#include "talk/base/sigslotrepeater.h" +#include "talk/session/phone/codec.h" +#include "talk/session/phone/devicemanager.h" +#include "talk/session/phone/mediachannel.h" +#include "talk/session/phone/videocommon.h" + +namespace cricket { + +// A class for playing out soundclips. +class SoundclipMedia { + public: + enum SoundclipFlags { + SF_LOOP = 1, + }; + + virtual ~SoundclipMedia() {} + + // Plays a sound out to the speakers with the given audio stream. The stream + // must be 16-bit little-endian 16 kHz PCM. If a stream is already playing + // on this SoundclipMedia, it is stopped. If clip is NULL, nothing is played. + // Returns whether it was successful. + virtual bool PlaySound(const char *clip, int len, int flags) = 0; +}; + +// MediaEngine is an abstraction of a media engine which can be subclassed +// to support different media componentry backends. It supports voice and +// video operations in the same class to facilitate proper synchronization +// between both media types. +class MediaEngine { + public: + // TODO: Move this to a global location (also used in DeviceManager) + // Capabilities of the media engine. + enum Capabilities { + AUDIO_RECV = 1 << 0, + AUDIO_SEND = 1 << 1, + VIDEO_RECV = 1 << 2, + VIDEO_SEND = 1 << 3, + }; + + // Bitmask flags for options that may be supported by the media engine + // implementation + enum AudioOptions { + ECHO_CANCELLATION = 1 << 0, + AUTO_GAIN_CONTROL = 1 << 1, + DEFAULT_AUDIO_OPTIONS = ECHO_CANCELLATION | AUTO_GAIN_CONTROL + }; + enum VideoOptions { + }; + + virtual ~MediaEngine() {} + static MediaEngine* Create(); + + // Initialization + // Starts the engine. + virtual bool Init() = 0; + // Shuts down the engine. + virtual void Terminate() = 0; + // Returns what the engine is capable of, as a set of Capabilities, above. + virtual int GetCapabilities() = 0; + + // MediaChannel creation + // Creates a voice media channel. Returns NULL on failure. + virtual VoiceMediaChannel *CreateChannel() = 0; + // Creates a video media channel, paired with the specified voice channel. + // Returns NULL on failure. + virtual VideoMediaChannel *CreateVideoChannel( + VoiceMediaChannel* voice_media_channel) = 0; + + // Creates a soundclip object for playing sounds on. Returns NULL on failure. + virtual SoundclipMedia *CreateSoundclip() = 0; + + // Configuration + // Sets global audio options. "options" are from AudioOptions, above. + virtual bool SetAudioOptions(int options) = 0; + // Sets global video options. "options" are from VideoOptions, above. + virtual bool SetVideoOptions(int options) = 0; + // Sets the default (maximum) codec/resolution and encoder option to capture + // and encode video. + virtual bool SetDefaultVideoEncoderConfig(const VideoEncoderConfig& config) + = 0; + + // Device selection + // TODO: Add method for selecting the soundclip device. + virtual bool SetSoundDevices(const Device* in_device, + const Device* out_device) = 0; + virtual bool SetVideoCaptureDevice(const Device* cam_device) = 0; + virtual bool SetVideoRenderer(int channel_id, + void* window, + unsigned int zOrder, + float left, + float top, + float right, + float bottom) = 0; + + // Device configuration + // Gets the current speaker volume, as a value between 0 and 255. + virtual bool GetOutputVolume(int* level) = 0; + // Sets the current speaker volume, as a value between 0 and 255. + virtual bool SetOutputVolume(int level) = 0; + + // Local monitoring + // Gets the current microphone level, as a value between 0 and 10. + virtual int GetInputLevel() = 0; + // Starts or stops the local microphone. Useful if local mic info is needed + // prior to a call being connected; the mic will be started automatically + // when a VoiceMediaChannel starts sending. + virtual bool SetLocalMonitor(bool enable) = 0; + // Installs a callback for raw frames from the local camera. + virtual bool SetLocalRenderer(VideoRenderer* renderer) = 0; + // Starts/stops local camera. + virtual CaptureResult SetVideoCapture(bool capture) = 0; + + virtual const std::vector& audio_codecs() = 0; + virtual const std::vector& video_codecs() = 0; + + // Logging control + virtual void SetVoiceLogging(int min_sev, const char* filter) = 0; + virtual void SetVideoLogging(int min_sev, const char* filter) = 0; + + sigslot::repeater1 SignalVideoCaptureResult; +}; + +// CompositeMediaEngine constructs a MediaEngine from separate +// voice and video engine classes. +template +class CompositeMediaEngine : public MediaEngine { + public: + CompositeMediaEngine() {} + virtual ~CompositeMediaEngine() {} + virtual bool Init() { + if (!voice_.Init()) + return false; + if (!video_.Init()) { + voice_.Terminate(); + return false; + } + SignalVideoCaptureResult.repeat(video_.SignalCaptureResult); + return true; + } + virtual void Terminate() { + video_.Terminate(); + voice_.Terminate(); + } + + virtual int GetCapabilities() { + return (voice_.GetCapabilities() | video_.GetCapabilities()); + } + virtual VoiceMediaChannel *CreateChannel() { + return voice_.CreateChannel(); + } + virtual VideoMediaChannel *CreateVideoChannel(VoiceMediaChannel* channel) { + return video_.CreateChannel(channel); + } + virtual SoundclipMedia *CreateSoundclip() { + return voice_.CreateSoundclip(); + } + + virtual bool SetAudioOptions(int o) { + return voice_.SetOptions(o); + } + virtual bool SetVideoOptions(int o) { + return video_.SetOptions(o); + } + virtual bool SetDefaultVideoEncoderConfig(const VideoEncoderConfig& config) { + return video_.SetDefaultEncoderConfig(config); + } + + virtual bool SetSoundDevices(const Device* in_device, + const Device* out_device) { + return voice_.SetDevices(in_device, out_device); + } + + virtual bool SetVideoCaptureDevice(const Device* cam_device) { + return video_.SetCaptureDevice(cam_device); + } + + virtual bool SetVideoRenderer(int channel_id, + void* window, + unsigned int zOrder, + float left, + float top, + float right, + float bottom) { + return video_.SetVideoRenderer(channel_id, + window, + zOrder, + left, + top, + right, + bottom); + } + + virtual bool GetOutputVolume(int* level) { + return voice_.GetOutputVolume(level); + } + + virtual bool SetOutputVolume(int level) { + return voice_.SetOutputVolume(level); + } + + virtual int GetInputLevel() { + return voice_.GetInputLevel(); + } + virtual bool SetLocalMonitor(bool enable) { + return voice_.SetLocalMonitor(enable); + } + virtual bool SetLocalRenderer(VideoRenderer* renderer) { + return video_.SetLocalRenderer(renderer); + } + virtual CaptureResult SetVideoCapture(bool capture) { + return video_.SetCapture(capture); + } + + virtual const std::vector& audio_codecs() { + return voice_.codecs(); + } + virtual const std::vector& video_codecs() { + return video_.codecs(); + } + + virtual void SetVoiceLogging(int min_sev, const char* filter) { + return voice_.SetLogging(min_sev, filter); + } + virtual void SetVideoLogging(int min_sev, const char* filter) { + return video_.SetLogging(min_sev, filter); + } + + protected: + VOICE voice_; + VIDEO video_; +}; + +// NullVoiceEngine can be used with CompositeMediaEngine in the case where only +// a video engine is desired. +class NullVoiceEngine { + public: + bool Init() { return true; } + void Terminate() {} + int GetCapabilities() { return 0; } + // If you need this to return an actual channel, use FakeMediaEngine instead. + VoiceMediaChannel* CreateChannel() { + return NULL; + } + SoundclipMedia* CreateSoundclip() { + return NULL; + } + bool SetOptions(int opts) { return true; } + bool SetDevices(const Device* in_device, const Device* out_device) { + return true; + } + bool GetOutputVolume(int* level) { *level = 0; return true; } + bool SetOutputVolume(int level) { return true; } + int GetInputLevel() { return 0; } + bool SetLocalMonitor(bool enable) { return true; } + const std::vector& codecs() { return codecs_; } + void SetLogging(int min_sev, const char* filter) {} + private: + std::vector codecs_; +}; + +// NullVideoEngine can be used with CompositeMediaEngine in the case where only +// a voice engine is desired. +class NullVideoEngine { + public: + bool Init() { return true; } + void Terminate() {} + int GetCapabilities() { return 0; } + // If you need this to return an actual channel, use FakeMediaEngine instead. + VideoMediaChannel* CreateChannel( + VoiceMediaChannel* voice_media_channel) { + return NULL; + } + bool SetOptions(int opts) { return true; } + bool SetDefaultEncoderConfig(const VideoEncoderConfig& config) { + return true; + } + bool SetCaptureDevice(const Device* cam_device) { return true; } + bool SetLocalRenderer(VideoRenderer* renderer) { return true; } + CaptureResult SetCapture(bool capture) { return CR_SUCCESS; } + const std::vector& codecs() { return codecs_; } + void SetLogging(int min_sev, const char* filter) {} + sigslot::signal1 SignalCaptureResult; + private: + std::vector codecs_; +}; + +typedef CompositeMediaEngine NullMediaEngine; + +} // namespace cricket + +#endif // TALK_SESSION_PHONE_MEDIAENGINE_H_