| // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/renderer/media/remote_media_stream_impl.h" |
| |
| #include <string> |
| |
| #include "base/logging.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "content/renderer/media/media_stream.h" |
| #include "content/renderer/media/media_stream_video_track.h" |
| #include "content/renderer/media/webrtc/media_stream_remote_video_source.h" |
| #include "content/renderer/media/webrtc/peer_connection_dependency_factory.h" |
| #include "third_party/WebKit/public/platform/WebString.h" |
| |
| namespace content { |
| |
| namespace { |
| |
| void InitializeWebkitTrack(webrtc::MediaStreamTrackInterface* track, |
| blink::WebMediaStreamTrack* webkit_track, |
| blink::WebMediaStreamSource::Type type) { |
| blink::WebMediaStreamSource webkit_source; |
| blink::WebString webkit_track_id(base::UTF8ToUTF16(track->id())); |
| |
| webkit_source.initialize(webkit_track_id, type, webkit_track_id); |
| webkit_track->initialize(webkit_track_id, webkit_source); |
| |
| if (type == blink::WebMediaStreamSource::TypeVideo) { |
| MediaStreamRemoteVideoSource* video_source = |
| new MediaStreamRemoteVideoSource( |
| static_cast<webrtc::VideoTrackInterface*>(track)); |
| webkit_source.setExtraData(video_source); |
| // Initial constraints must be provided to a MediaStreamVideoTrack. But |
| // no constraints are available initially on a remote video track. |
| blink::WebMediaConstraints constraints; |
| constraints.initialize(); |
| webkit_track->setExtraData( |
| new MediaStreamVideoTrack(video_source, constraints, |
| MediaStreamVideoSource::ConstraintsCallback(), |
| track->enabled())); |
| } else { |
| DCHECK(type == blink::WebMediaStreamSource::TypeAudio); |
| content::PeerConnectionDependencyFactory::AddNativeAudioTrackToBlinkTrack( |
| track, *webkit_track, false); |
| } |
| } |
| |
| } // namespace |
| |
| // Base class used for mapping between webrtc and blink MediaStream tracks. |
| // An instance of a RemoteMediaStreamTrackAdapter is stored in |
| // RemoteMediaStreamImpl per remote audio and video track. |
| class RemoteMediaStreamTrackAdapter { |
| public: |
| RemoteMediaStreamTrackAdapter(webrtc::MediaStreamTrackInterface* webrtc_track, |
| const blink::WebMediaStreamTrack& webkit_track) |
| : webrtc_track_(webrtc_track), |
| webkit_track_(webkit_track) { |
| } |
| |
| virtual ~RemoteMediaStreamTrackAdapter() { |
| } |
| |
| webrtc::MediaStreamTrackInterface* observed_track() { |
| return webrtc_track_.get(); |
| } |
| |
| const blink::WebMediaStreamTrack& webkit_track() { return webkit_track_; } |
| |
| private: |
| scoped_refptr<webrtc::MediaStreamTrackInterface> webrtc_track_; |
| blink::WebMediaStreamTrack webkit_track_; |
| |
| DISALLOW_COPY_AND_ASSIGN(RemoteMediaStreamTrackAdapter); |
| }; |
| |
| static content::RemoteMediaStreamTrackAdapter* FindTrackObserver( |
| webrtc::MediaStreamTrackInterface* track, |
| const ScopedVector<content::RemoteMediaStreamTrackAdapter>& observers) { |
| ScopedVector<content::RemoteMediaStreamTrackAdapter>::const_iterator it = |
| observers.begin(); |
| for (; it != observers.end(); ++it) { |
| if ((*it)->observed_track() == track) |
| return *it; |
| } |
| return NULL; |
| } |
| |
| // RemoteAudioMediaStreamTrackAdapter is responsible for listening on state |
| // change notifications on a remote webrtc audio MediaStreamTracks and notify |
| // WebKit. |
| class RemoteAudioMediaStreamTrackAdapter |
| : public RemoteMediaStreamTrackAdapter, |
| public webrtc::ObserverInterface, |
| public base::NonThreadSafe { |
| public: |
| RemoteAudioMediaStreamTrackAdapter( |
| webrtc::MediaStreamTrackInterface* webrtc_track, |
| const blink::WebMediaStreamTrack& webkit_track); |
| virtual ~RemoteAudioMediaStreamTrackAdapter(); |
| |
| private: |
| // webrtc::ObserverInterface implementation. |
| virtual void OnChanged() OVERRIDE; |
| |
| webrtc::MediaStreamTrackInterface::TrackState state_; |
| |
| DISALLOW_COPY_AND_ASSIGN(RemoteAudioMediaStreamTrackAdapter); |
| }; |
| |
| RemoteAudioMediaStreamTrackAdapter::RemoteAudioMediaStreamTrackAdapter( |
| webrtc::MediaStreamTrackInterface* webrtc_track, |
| const blink::WebMediaStreamTrack& webkit_track) |
| : RemoteMediaStreamTrackAdapter(webrtc_track, webkit_track), |
| state_(observed_track()->state()) { |
| observed_track()->RegisterObserver(this); |
| } |
| |
| RemoteAudioMediaStreamTrackAdapter::~RemoteAudioMediaStreamTrackAdapter() { |
| observed_track()->UnregisterObserver(this); |
| } |
| |
| void RemoteAudioMediaStreamTrackAdapter::OnChanged() { |
| DCHECK(CalledOnValidThread()); |
| |
| webrtc::MediaStreamTrackInterface::TrackState state = |
| observed_track()->state(); |
| if (state == state_) |
| return; |
| |
| state_ = state; |
| switch (state) { |
| case webrtc::MediaStreamTrackInterface::kInitializing: |
| // Ignore the kInitializing state since there is no match in |
| // WebMediaStreamSource::ReadyState. |
| break; |
| case webrtc::MediaStreamTrackInterface::kLive: |
| webkit_track().source().setReadyState( |
| blink::WebMediaStreamSource::ReadyStateLive); |
| break; |
| case webrtc::MediaStreamTrackInterface::kEnded: |
| webkit_track().source().setReadyState( |
| blink::WebMediaStreamSource::ReadyStateEnded); |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| } |
| |
| RemoteMediaStreamImpl::RemoteMediaStreamImpl( |
| webrtc::MediaStreamInterface* webrtc_stream) |
| : webrtc_stream_(webrtc_stream) { |
| webrtc_stream_->RegisterObserver(this); |
| |
| webrtc::AudioTrackVector webrtc_audio_tracks = |
| webrtc_stream_->GetAudioTracks(); |
| blink::WebVector<blink::WebMediaStreamTrack> webkit_audio_tracks( |
| webrtc_audio_tracks.size()); |
| |
| // Initialize WebKit audio tracks. |
| size_t i = 0; |
| for (; i < webrtc_audio_tracks.size(); ++i) { |
| webrtc::AudioTrackInterface* audio_track = webrtc_audio_tracks[i]; |
| DCHECK(audio_track); |
| InitializeWebkitTrack(audio_track, &webkit_audio_tracks[i], |
| blink::WebMediaStreamSource::TypeAudio); |
| audio_track_observers_.push_back( |
| new RemoteAudioMediaStreamTrackAdapter(audio_track, |
| webkit_audio_tracks[i])); |
| } |
| |
| // Initialize WebKit video tracks. |
| webrtc::VideoTrackVector webrtc_video_tracks = |
| webrtc_stream_->GetVideoTracks(); |
| blink::WebVector<blink::WebMediaStreamTrack> webkit_video_tracks( |
| webrtc_video_tracks.size()); |
| for (i = 0; i < webrtc_video_tracks.size(); ++i) { |
| webrtc::VideoTrackInterface* video_track = webrtc_video_tracks[i]; |
| DCHECK(video_track); |
| InitializeWebkitTrack(video_track, &webkit_video_tracks[i], |
| blink::WebMediaStreamSource::TypeVideo); |
| video_track_observers_.push_back( |
| new RemoteMediaStreamTrackAdapter(video_track, |
| webkit_video_tracks[i])); |
| } |
| |
| webkit_stream_.initialize(base::UTF8ToUTF16(webrtc_stream->label()), |
| webkit_audio_tracks, webkit_video_tracks); |
| webkit_stream_.setExtraData(new MediaStream(webrtc_stream)); |
| } |
| |
| RemoteMediaStreamImpl::~RemoteMediaStreamImpl() { |
| webrtc_stream_->UnregisterObserver(this); |
| } |
| |
| void RemoteMediaStreamImpl::OnChanged() { |
| // Find removed audio tracks. |
| ScopedVector<RemoteMediaStreamTrackAdapter>::iterator audio_it = |
| audio_track_observers_.begin(); |
| while (audio_it != audio_track_observers_.end()) { |
| std::string track_id = (*audio_it)->observed_track()->id(); |
| if (webrtc_stream_->FindAudioTrack(track_id) == NULL) { |
| webkit_stream_.removeTrack((*audio_it)->webkit_track()); |
| audio_it = audio_track_observers_.erase(audio_it); |
| } else { |
| ++audio_it; |
| } |
| } |
| |
| // Find removed video tracks. |
| ScopedVector<RemoteMediaStreamTrackAdapter>::iterator video_it = |
| video_track_observers_.begin(); |
| while (video_it != video_track_observers_.end()) { |
| std::string track_id = (*video_it)->observed_track()->id(); |
| if (webrtc_stream_->FindVideoTrack(track_id) == NULL) { |
| webkit_stream_.removeTrack((*video_it)->webkit_track()); |
| video_it = video_track_observers_.erase(video_it); |
| } else { |
| ++video_it; |
| } |
| } |
| |
| // Find added audio tracks. |
| webrtc::AudioTrackVector webrtc_audio_tracks = |
| webrtc_stream_->GetAudioTracks(); |
| for (webrtc::AudioTrackVector::iterator it = webrtc_audio_tracks.begin(); |
| it != webrtc_audio_tracks.end(); ++it) { |
| if (!FindTrackObserver(*it, audio_track_observers_)) { |
| blink::WebMediaStreamTrack new_track; |
| InitializeWebkitTrack(*it, &new_track, |
| blink::WebMediaStreamSource::TypeAudio); |
| audio_track_observers_.push_back( |
| new RemoteAudioMediaStreamTrackAdapter(*it, new_track)); |
| webkit_stream_.addTrack(new_track); |
| } |
| } |
| |
| // Find added video tracks. |
| webrtc::VideoTrackVector webrtc_video_tracks = |
| webrtc_stream_->GetVideoTracks(); |
| for (webrtc::VideoTrackVector::iterator it = webrtc_video_tracks.begin(); |
| it != webrtc_video_tracks.end(); ++it) { |
| if (!FindTrackObserver(*it, video_track_observers_)) { |
| blink::WebMediaStreamTrack new_track; |
| InitializeWebkitTrack(*it, &new_track, |
| blink::WebMediaStreamSource::TypeVideo); |
| video_track_observers_.push_back( |
| new RemoteMediaStreamTrackAdapter(*it, new_track)); |
| webkit_stream_.addTrack(new_track); |
| } |
| } |
| } |
| |
| } // namespace content |