1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/renderer/media/remote_media_stream_impl.h"
6
7 #include <string>
8
9 #include "base/logging.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "content/renderer/media/media_stream.h"
12 #include "content/renderer/media/media_stream_video_track.h"
13 #include "content/renderer/media/webrtc/media_stream_remote_video_source.h"
14 #include "content/renderer/media/webrtc/peer_connection_dependency_factory.h"
15 #include "third_party/WebKit/public/platform/WebString.h"
16
17 namespace content {
18
19 namespace {
20
InitializeWebkitTrack(webrtc::MediaStreamTrackInterface * track,blink::WebMediaStreamTrack * webkit_track,blink::WebMediaStreamSource::Type type)21 void InitializeWebkitTrack(webrtc::MediaStreamTrackInterface* track,
22 blink::WebMediaStreamTrack* webkit_track,
23 blink::WebMediaStreamSource::Type type) {
24 blink::WebMediaStreamSource webkit_source;
25 blink::WebString webkit_track_id(base::UTF8ToUTF16(track->id()));
26
27 webkit_source.initialize(webkit_track_id, type, webkit_track_id);
28 webkit_track->initialize(webkit_track_id, webkit_source);
29
30 if (type == blink::WebMediaStreamSource::TypeVideo) {
31 MediaStreamRemoteVideoSource* video_source =
32 new MediaStreamRemoteVideoSource(
33 static_cast<webrtc::VideoTrackInterface*>(track));
34 webkit_source.setExtraData(video_source);
35 // Initial constraints must be provided to a MediaStreamVideoTrack. But
36 // no constraints are available initially on a remote video track.
37 blink::WebMediaConstraints constraints;
38 constraints.initialize();
39 webkit_track->setExtraData(
40 new MediaStreamVideoTrack(video_source, constraints,
41 MediaStreamVideoSource::ConstraintsCallback(),
42 track->enabled()));
43 } else {
44 DCHECK(type == blink::WebMediaStreamSource::TypeAudio);
45 content::PeerConnectionDependencyFactory::AddNativeAudioTrackToBlinkTrack(
46 track, *webkit_track, false);
47 }
48 }
49
50 } // namespace
51
52 // Base class used for mapping between webrtc and blink MediaStream tracks.
53 // An instance of a RemoteMediaStreamTrackAdapter is stored in
54 // RemoteMediaStreamImpl per remote audio and video track.
55 class RemoteMediaStreamTrackAdapter {
56 public:
RemoteMediaStreamTrackAdapter(webrtc::MediaStreamTrackInterface * webrtc_track,const blink::WebMediaStreamTrack & webkit_track)57 RemoteMediaStreamTrackAdapter(webrtc::MediaStreamTrackInterface* webrtc_track,
58 const blink::WebMediaStreamTrack& webkit_track)
59 : webrtc_track_(webrtc_track),
60 webkit_track_(webkit_track) {
61 }
62
~RemoteMediaStreamTrackAdapter()63 virtual ~RemoteMediaStreamTrackAdapter() {
64 }
65
observed_track()66 webrtc::MediaStreamTrackInterface* observed_track() {
67 return webrtc_track_.get();
68 }
69
webkit_track()70 const blink::WebMediaStreamTrack& webkit_track() { return webkit_track_; }
71
72 private:
73 scoped_refptr<webrtc::MediaStreamTrackInterface> webrtc_track_;
74 blink::WebMediaStreamTrack webkit_track_;
75
76 DISALLOW_COPY_AND_ASSIGN(RemoteMediaStreamTrackAdapter);
77 };
78
FindTrackObserver(webrtc::MediaStreamTrackInterface * track,const ScopedVector<content::RemoteMediaStreamTrackAdapter> & observers)79 static content::RemoteMediaStreamTrackAdapter* FindTrackObserver(
80 webrtc::MediaStreamTrackInterface* track,
81 const ScopedVector<content::RemoteMediaStreamTrackAdapter>& observers) {
82 ScopedVector<content::RemoteMediaStreamTrackAdapter>::const_iterator it =
83 observers.begin();
84 for (; it != observers.end(); ++it) {
85 if ((*it)->observed_track() == track)
86 return *it;
87 }
88 return NULL;
89 }
90
91 // RemoteAudioMediaStreamTrackAdapter is responsible for listening on state
92 // change notifications on a remote webrtc audio MediaStreamTracks and notify
93 // WebKit.
94 class RemoteAudioMediaStreamTrackAdapter
95 : public RemoteMediaStreamTrackAdapter,
96 public webrtc::ObserverInterface,
97 public base::NonThreadSafe {
98 public:
99 RemoteAudioMediaStreamTrackAdapter(
100 webrtc::MediaStreamTrackInterface* webrtc_track,
101 const blink::WebMediaStreamTrack& webkit_track);
102 virtual ~RemoteAudioMediaStreamTrackAdapter();
103
104 private:
105 // webrtc::ObserverInterface implementation.
106 virtual void OnChanged() OVERRIDE;
107
108 webrtc::MediaStreamTrackInterface::TrackState state_;
109
110 DISALLOW_COPY_AND_ASSIGN(RemoteAudioMediaStreamTrackAdapter);
111 };
112
RemoteAudioMediaStreamTrackAdapter(webrtc::MediaStreamTrackInterface * webrtc_track,const blink::WebMediaStreamTrack & webkit_track)113 RemoteAudioMediaStreamTrackAdapter::RemoteAudioMediaStreamTrackAdapter(
114 webrtc::MediaStreamTrackInterface* webrtc_track,
115 const blink::WebMediaStreamTrack& webkit_track)
116 : RemoteMediaStreamTrackAdapter(webrtc_track, webkit_track),
117 state_(observed_track()->state()) {
118 observed_track()->RegisterObserver(this);
119 }
120
~RemoteAudioMediaStreamTrackAdapter()121 RemoteAudioMediaStreamTrackAdapter::~RemoteAudioMediaStreamTrackAdapter() {
122 observed_track()->UnregisterObserver(this);
123 }
124
OnChanged()125 void RemoteAudioMediaStreamTrackAdapter::OnChanged() {
126 DCHECK(CalledOnValidThread());
127
128 webrtc::MediaStreamTrackInterface::TrackState state =
129 observed_track()->state();
130 if (state == state_)
131 return;
132
133 state_ = state;
134 switch (state) {
135 case webrtc::MediaStreamTrackInterface::kInitializing:
136 // Ignore the kInitializing state since there is no match in
137 // WebMediaStreamSource::ReadyState.
138 break;
139 case webrtc::MediaStreamTrackInterface::kLive:
140 webkit_track().source().setReadyState(
141 blink::WebMediaStreamSource::ReadyStateLive);
142 break;
143 case webrtc::MediaStreamTrackInterface::kEnded:
144 webkit_track().source().setReadyState(
145 blink::WebMediaStreamSource::ReadyStateEnded);
146 break;
147 default:
148 NOTREACHED();
149 break;
150 }
151 }
152
RemoteMediaStreamImpl(webrtc::MediaStreamInterface * webrtc_stream)153 RemoteMediaStreamImpl::RemoteMediaStreamImpl(
154 webrtc::MediaStreamInterface* webrtc_stream)
155 : webrtc_stream_(webrtc_stream) {
156 webrtc_stream_->RegisterObserver(this);
157
158 webrtc::AudioTrackVector webrtc_audio_tracks =
159 webrtc_stream_->GetAudioTracks();
160 blink::WebVector<blink::WebMediaStreamTrack> webkit_audio_tracks(
161 webrtc_audio_tracks.size());
162
163 // Initialize WebKit audio tracks.
164 size_t i = 0;
165 for (; i < webrtc_audio_tracks.size(); ++i) {
166 webrtc::AudioTrackInterface* audio_track = webrtc_audio_tracks[i];
167 DCHECK(audio_track);
168 InitializeWebkitTrack(audio_track, &webkit_audio_tracks[i],
169 blink::WebMediaStreamSource::TypeAudio);
170 audio_track_observers_.push_back(
171 new RemoteAudioMediaStreamTrackAdapter(audio_track,
172 webkit_audio_tracks[i]));
173 }
174
175 // Initialize WebKit video tracks.
176 webrtc::VideoTrackVector webrtc_video_tracks =
177 webrtc_stream_->GetVideoTracks();
178 blink::WebVector<blink::WebMediaStreamTrack> webkit_video_tracks(
179 webrtc_video_tracks.size());
180 for (i = 0; i < webrtc_video_tracks.size(); ++i) {
181 webrtc::VideoTrackInterface* video_track = webrtc_video_tracks[i];
182 DCHECK(video_track);
183 InitializeWebkitTrack(video_track, &webkit_video_tracks[i],
184 blink::WebMediaStreamSource::TypeVideo);
185 video_track_observers_.push_back(
186 new RemoteMediaStreamTrackAdapter(video_track,
187 webkit_video_tracks[i]));
188 }
189
190 webkit_stream_.initialize(base::UTF8ToUTF16(webrtc_stream->label()),
191 webkit_audio_tracks, webkit_video_tracks);
192 webkit_stream_.setExtraData(new MediaStream(webrtc_stream));
193 }
194
~RemoteMediaStreamImpl()195 RemoteMediaStreamImpl::~RemoteMediaStreamImpl() {
196 webrtc_stream_->UnregisterObserver(this);
197 }
198
OnChanged()199 void RemoteMediaStreamImpl::OnChanged() {
200 // Find removed audio tracks.
201 ScopedVector<RemoteMediaStreamTrackAdapter>::iterator audio_it =
202 audio_track_observers_.begin();
203 while (audio_it != audio_track_observers_.end()) {
204 std::string track_id = (*audio_it)->observed_track()->id();
205 if (webrtc_stream_->FindAudioTrack(track_id) == NULL) {
206 webkit_stream_.removeTrack((*audio_it)->webkit_track());
207 audio_it = audio_track_observers_.erase(audio_it);
208 } else {
209 ++audio_it;
210 }
211 }
212
213 // Find removed video tracks.
214 ScopedVector<RemoteMediaStreamTrackAdapter>::iterator video_it =
215 video_track_observers_.begin();
216 while (video_it != video_track_observers_.end()) {
217 std::string track_id = (*video_it)->observed_track()->id();
218 if (webrtc_stream_->FindVideoTrack(track_id) == NULL) {
219 webkit_stream_.removeTrack((*video_it)->webkit_track());
220 video_it = video_track_observers_.erase(video_it);
221 } else {
222 ++video_it;
223 }
224 }
225
226 // Find added audio tracks.
227 webrtc::AudioTrackVector webrtc_audio_tracks =
228 webrtc_stream_->GetAudioTracks();
229 for (webrtc::AudioTrackVector::iterator it = webrtc_audio_tracks.begin();
230 it != webrtc_audio_tracks.end(); ++it) {
231 if (!FindTrackObserver(*it, audio_track_observers_)) {
232 blink::WebMediaStreamTrack new_track;
233 InitializeWebkitTrack(*it, &new_track,
234 blink::WebMediaStreamSource::TypeAudio);
235 audio_track_observers_.push_back(
236 new RemoteAudioMediaStreamTrackAdapter(*it, new_track));
237 webkit_stream_.addTrack(new_track);
238 }
239 }
240
241 // Find added video tracks.
242 webrtc::VideoTrackVector webrtc_video_tracks =
243 webrtc_stream_->GetVideoTracks();
244 for (webrtc::VideoTrackVector::iterator it = webrtc_video_tracks.begin();
245 it != webrtc_video_tracks.end(); ++it) {
246 if (!FindTrackObserver(*it, video_track_observers_)) {
247 blink::WebMediaStreamTrack new_track;
248 InitializeWebkitTrack(*it, &new_track,
249 blink::WebMediaStreamSource::TypeVideo);
250 video_track_observers_.push_back(
251 new RemoteMediaStreamTrackAdapter(*it, new_track));
252 webkit_stream_.addTrack(new_track);
253 }
254 }
255 }
256
257 } // namespace content
258