| /* |
| * libjingle |
| * Copyright 2011, 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/app/webrtc/mediastreamproxy.h" |
| #include "talk/base/refcount.h" |
| #include "talk/base/scoped_ref_ptr.h" |
| |
| namespace { |
| |
| enum { |
| MSG_SET_TRACKLIST_IMPLEMENTATION = 1, |
| MSG_REGISTER_OBSERVER, |
| MSG_UNREGISTER_OBSERVER, |
| MSG_LABEL, |
| MSG_ADD_AUDIO_TRACK, |
| MSG_ADD_VIDEO_TRACK, |
| MSG_READY_STATE, |
| MSG_COUNT, |
| MSG_AT |
| }; |
| |
| typedef talk_base::TypedMessageData<std::string*> LabelMessageData; |
| typedef talk_base::TypedMessageData<size_t> SizeTMessageData; |
| typedef talk_base::TypedMessageData<webrtc::ObserverInterface*> |
| ObserverMessageData; |
| typedef talk_base::TypedMessageData<webrtc::MediaStreamInterface::ReadyState> |
| ReadyStateMessageData; |
| |
| template<typename T> |
| class MediaStreamTrackMessageData : public talk_base::MessageData { |
| public: |
| explicit MediaStreamTrackMessageData(T* track) |
| : track_(track), |
| result_(false) { |
| } |
| |
| talk_base::scoped_refptr<T> track_; |
| bool result_; |
| }; |
| |
| typedef MediaStreamTrackMessageData<webrtc::AudioTrackInterface> |
| AudioTrackMsgData; |
| typedef MediaStreamTrackMessageData<webrtc::VideoTrackInterface> |
| VideoTrackMsgData; |
| |
| template <class TrackType> |
| class MediaStreamTrackAtMessageData : public talk_base::MessageData { |
| public: |
| explicit MediaStreamTrackAtMessageData(size_t index) |
| : index_(index) { |
| } |
| |
| size_t index_; |
| talk_base::scoped_refptr<TrackType> track_; |
| }; |
| |
| class MediaStreamTrackListsMessageData : public talk_base::MessageData { |
| public: |
| talk_base::scoped_refptr<webrtc::AudioTracks> audio_tracks_; |
| talk_base::scoped_refptr<webrtc::VideoTracks> video_tracks_; |
| }; |
| |
| } // namespace anonymous |
| |
| namespace webrtc { |
| |
| talk_base::scoped_refptr<MediaStreamProxy> MediaStreamProxy::Create( |
| const std::string& label, |
| talk_base::Thread* signaling_thread) { |
| ASSERT(signaling_thread != NULL); |
| talk_base::RefCountedObject<MediaStreamProxy>* stream = |
| new talk_base::RefCountedObject<MediaStreamProxy>( |
| label, signaling_thread, |
| reinterpret_cast<LocalMediaStreamInterface*>(NULL)); |
| return stream; |
| } |
| |
| talk_base::scoped_refptr<MediaStreamProxy> MediaStreamProxy::Create( |
| const std::string& label, |
| talk_base::Thread* signaling_thread, |
| LocalMediaStreamInterface* media_stream_impl) { |
| ASSERT(signaling_thread != NULL); |
| ASSERT(media_stream_impl != NULL); |
| talk_base::RefCountedObject<MediaStreamProxy>* stream = |
| new talk_base::RefCountedObject<MediaStreamProxy>(label, signaling_thread, |
| media_stream_impl); |
| return stream; |
| } |
| |
| MediaStreamProxy::MediaStreamProxy(const std::string& label, |
| talk_base::Thread* signaling_thread, |
| LocalMediaStreamInterface* media_stream_impl) |
| : signaling_thread_(signaling_thread), |
| media_stream_impl_(media_stream_impl), |
| audio_tracks_(new talk_base::RefCountedObject< |
| MediaStreamTrackListProxy<AudioTrackInterface> >( |
| signaling_thread_)), |
| video_tracks_(new talk_base::RefCountedObject< |
| MediaStreamTrackListProxy<VideoTrackInterface> >( |
| signaling_thread_)) { |
| if (media_stream_impl_ == NULL) { |
| media_stream_impl_ = MediaStream::Create(label); |
| } |
| |
| MediaStreamTrackListsMessageData tracklists; |
| Send(MSG_SET_TRACKLIST_IMPLEMENTATION, &tracklists); |
| audio_tracks_->SetImplementation(tracklists.audio_tracks_); |
| video_tracks_->SetImplementation(tracklists.video_tracks_); |
| } |
| |
| std::string MediaStreamProxy::label() const { |
| if (!signaling_thread_->IsCurrent()) { |
| std::string label; |
| LabelMessageData msg(&label); |
| Send(MSG_LABEL, &msg); |
| return label; |
| } |
| return media_stream_impl_->label(); |
| } |
| |
| MediaStreamInterface::ReadyState MediaStreamProxy::ready_state() { |
| if (!signaling_thread_->IsCurrent()) { |
| ReadyStateMessageData msg(MediaStreamInterface::kInitializing); |
| Send(MSG_READY_STATE, &msg); |
| return msg.data(); |
| } |
| return media_stream_impl_->ready_state(); |
| } |
| |
| void MediaStreamProxy::set_ready_state( |
| MediaStreamInterface::ReadyState new_state) { |
| if (!signaling_thread_->IsCurrent()) { |
| // State should only be allowed to be changed from the signaling thread. |
| ASSERT(!"Not Allowed!"); |
| return; |
| } |
| media_stream_impl_->set_ready_state(new_state); |
| } |
| |
| bool MediaStreamProxy::AddTrack(AudioTrackInterface* track) { |
| if (!signaling_thread_->IsCurrent()) { |
| AudioTrackMsgData msg(track); |
| Send(MSG_ADD_AUDIO_TRACK, &msg); |
| return msg.result_; |
| } |
| return media_stream_impl_->AddTrack(track); |
| } |
| |
| bool MediaStreamProxy::AddTrack(VideoTrackInterface* track) { |
| if (!signaling_thread_->IsCurrent()) { |
| VideoTrackMsgData msg(track); |
| Send(MSG_ADD_VIDEO_TRACK, &msg); |
| return msg.result_; |
| } |
| return media_stream_impl_->AddTrack(track); |
| } |
| |
| void MediaStreamProxy::RegisterObserver(ObserverInterface* observer) { |
| if (!signaling_thread_->IsCurrent()) { |
| ObserverMessageData msg(observer); |
| Send(MSG_REGISTER_OBSERVER, &msg); |
| return; |
| } |
| media_stream_impl_->RegisterObserver(observer); |
| } |
| |
| void MediaStreamProxy::UnregisterObserver(ObserverInterface* observer) { |
| if (!signaling_thread_->IsCurrent()) { |
| ObserverMessageData msg(observer); |
| Send(MSG_UNREGISTER_OBSERVER, &msg); |
| return; |
| } |
| media_stream_impl_->UnregisterObserver(observer); |
| } |
| |
| void MediaStreamProxy::Send(uint32 id, talk_base::MessageData* data) const { |
| signaling_thread_->Send(const_cast<MediaStreamProxy*>(this), id, |
| data); |
| } |
| |
| // Implement MessageHandler |
| void MediaStreamProxy::OnMessage(talk_base::Message* msg) { |
| talk_base::MessageData* data = msg->pdata; |
| switch (msg->message_id) { |
| case MSG_SET_TRACKLIST_IMPLEMENTATION: { |
| MediaStreamTrackListsMessageData* lists = |
| static_cast<MediaStreamTrackListsMessageData*>(data); |
| lists->audio_tracks_ = media_stream_impl_->audio_tracks(); |
| lists->video_tracks_ = media_stream_impl_->video_tracks(); |
| break; |
| } |
| case MSG_REGISTER_OBSERVER: { |
| ObserverMessageData* observer = static_cast<ObserverMessageData*>(data); |
| media_stream_impl_->RegisterObserver(observer->data()); |
| break; |
| } |
| case MSG_UNREGISTER_OBSERVER: { |
| ObserverMessageData* observer = static_cast<ObserverMessageData*>(data); |
| media_stream_impl_->UnregisterObserver(observer->data()); |
| break; |
| } |
| case MSG_LABEL: { |
| LabelMessageData * label = static_cast<LabelMessageData*>(data); |
| *(label->data()) = media_stream_impl_->label(); |
| break; |
| } |
| case MSG_ADD_AUDIO_TRACK: { |
| AudioTrackMsgData * track = |
| static_cast<AudioTrackMsgData *>(data); |
| track->result_ = media_stream_impl_->AddTrack(track->track_.get()); |
| break; |
| } |
| case MSG_ADD_VIDEO_TRACK: { |
| VideoTrackMsgData * track = |
| static_cast<VideoTrackMsgData *>(data); |
| track->result_ = media_stream_impl_->AddTrack(track->track_.get()); |
| break; |
| } |
| case MSG_READY_STATE: { |
| ReadyStateMessageData* state = static_cast<ReadyStateMessageData*>(data); |
| state->data() = media_stream_impl_->ready_state(); |
| break; |
| } |
| default: |
| ASSERT(!"Not Implemented!"); |
| break; |
| } |
| } |
| |
| template <class T> |
| MediaStreamProxy::MediaStreamTrackListProxy<T>::MediaStreamTrackListProxy( |
| talk_base::Thread* signaling_thread) |
| : signaling_thread_(signaling_thread) { |
| } |
| |
| template <class T> |
| void MediaStreamProxy::MediaStreamTrackListProxy<T>::SetImplementation( |
| MediaStreamTrackListInterface<T>* track_list) { |
| track_list_ = track_list; |
| } |
| |
| template <class T> |
| size_t MediaStreamProxy::MediaStreamTrackListProxy<T>::count() { |
| if (!signaling_thread_->IsCurrent()) { |
| SizeTMessageData msg(0u); |
| Send(MSG_COUNT, &msg); |
| return msg.data(); |
| } |
| return track_list_->count(); |
| } |
| |
| template <class T> |
| T* MediaStreamProxy::MediaStreamTrackListProxy<T>::at( |
| size_t index) { |
| if (!signaling_thread_->IsCurrent()) { |
| MediaStreamTrackAtMessageData<T> msg(index); |
| Send(MSG_AT, &msg); |
| return msg.track_; |
| } |
| return track_list_->at(index); |
| } |
| |
| template <class T> |
| void MediaStreamProxy::MediaStreamTrackListProxy<T>::Send( |
| uint32 id, talk_base::MessageData* data) const { |
| signaling_thread_->Send( |
| const_cast<MediaStreamProxy::MediaStreamTrackListProxy<T>*>( |
| this), id, data); |
| } |
| |
| // Implement MessageHandler |
| template <class T> |
| void MediaStreamProxy::MediaStreamTrackListProxy<T>::OnMessage( |
| talk_base::Message* msg) { |
| talk_base::MessageData* data = msg->pdata; |
| switch (msg->message_id) { |
| case MSG_COUNT: { |
| SizeTMessageData* count = static_cast<SizeTMessageData*>(data); |
| count->data() = track_list_->count(); |
| break; |
| } |
| case MSG_AT: { |
| MediaStreamTrackAtMessageData<T>* track = |
| static_cast<MediaStreamTrackAtMessageData<T>*>(data); |
| track->track_ = track_list_->at(track->index_); |
| break; |
| } |
| default: |
| ASSERT(!"Not Implemented!"); |
| break; |
| } |
| } |
| |
| } // namespace webrtc |