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.
5 #include "content/renderer/media/remote_media_stream_impl.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "content/renderer/media/media_stream.h"
15 #include "content/renderer/media/media_stream_track.h"
16 #include "content/renderer/media/media_stream_video_track.h"
17 #include "content/renderer/media/webrtc/media_stream_remote_video_source.h"
18 #include "content/renderer/media/webrtc/peer_connection_dependency_factory.h"
19 #include "third_party/WebKit/public/platform/WebString.h"
24 template <typename WebRtcTrackVector, typename AdapterType>
25 void CreateAdaptersForTracks(
26 const WebRtcTrackVector& tracks,
27 std::vector<scoped_refptr<AdapterType>>* observers,
28 const scoped_refptr<base::SingleThreadTaskRunner>& main_thread) {
29 for (auto& track : tracks)
30 observers->push_back(new AdapterType(main_thread, track));
33 template<typename VectorType>
34 bool IsTrackInVector(const VectorType& v, const std::string& id) {
35 for (const auto& t : v) {
43 // TODO(tommi): Move this class to a separate set of files.
44 class RemoteMediaStreamAudioTrack : public MediaStreamTrack {
46 RemoteMediaStreamAudioTrack(
47 const scoped_refptr<webrtc::AudioTrackInterface>& track,
48 const scoped_refptr<base::SingleThreadTaskRunner>& signaling_thread)
49 : MediaStreamTrack(false), track_(track),
50 signaling_thread_(signaling_thread) {
53 ~RemoteMediaStreamAudioTrack() override {}
56 void SetEnabled(bool enabled) override {
57 track_->set_enabled(enabled);
60 void Stop() override {
61 // Stop means that a track should be stopped permanently. But
62 // since there is no proper way of doing that on a remote track, we can
63 // at least disable the track. Blink will not call down to the content layer
64 // after a track has been stopped.
69 const scoped_refptr<webrtc::AudioTrackInterface> track_;
70 const scoped_refptr<base::SingleThreadTaskRunner> signaling_thread_;
73 // Base class used for mapping between webrtc and blink MediaStream tracks.
74 // An instance of a RemoteMediaStreamTrackAdapter is stored in
75 // RemoteMediaStreamImpl per remote audio and video track.
76 template<typename WebRtcMediaStreamTrackType>
77 class RemoteMediaStreamTrackAdapter
78 : public base::RefCountedThreadSafe<
79 RemoteMediaStreamTrackAdapter<WebRtcMediaStreamTrackType>> {
81 RemoteMediaStreamTrackAdapter(
82 const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
83 WebRtcMediaStreamTrackType* webrtc_track)
84 : main_thread_(main_thread), webrtc_track_(webrtc_track),
85 id_(webrtc_track->id()) {
88 const scoped_refptr<WebRtcMediaStreamTrackType>& observed_track() {
92 blink::WebMediaStreamTrack* webkit_track() {
93 DCHECK(main_thread_->BelongsToCurrentThread());
94 DCHECK(!webkit_track_.isNull());
95 return &webkit_track_;
98 const std::string& id() const { return id_; }
100 bool initialized() const {
101 DCHECK(main_thread_->BelongsToCurrentThread());
102 return !webkit_track_.isNull();
106 DCHECK(main_thread_->BelongsToCurrentThread());
107 DCHECK(!initialized());
108 webkit_initialize_.Run();
109 webkit_initialize_.Reset();
110 DCHECK(initialized());
114 friend class base::RefCountedThreadSafe<
115 RemoteMediaStreamTrackAdapter<WebRtcMediaStreamTrackType>>;
117 virtual ~RemoteMediaStreamTrackAdapter() {
118 DCHECK(main_thread_->BelongsToCurrentThread());
121 void InitializeWebkitTrack(blink::WebMediaStreamSource::Type type) {
122 DCHECK(main_thread_->BelongsToCurrentThread());
123 DCHECK(webkit_track_.isNull());
125 blink::WebString webkit_track_id(base::UTF8ToUTF16(id_));
126 blink::WebMediaStreamSource webkit_source;
127 webkit_source.initialize(webkit_track_id, type, webkit_track_id);
128 webkit_track_.initialize(webkit_track_id, webkit_source);
129 DCHECK(!webkit_track_.isNull());
132 const scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
133 // This callback will be run when Initialize() is called and then freed.
134 // The callback is used by derived classes to bind objects that need to be
135 // instantiated and initialized on the signaling thread but then moved to
136 // and used on the main thread when initializing the webkit object(s).
137 base::Callback<void()> webkit_initialize_;
140 const scoped_refptr<WebRtcMediaStreamTrackType> webrtc_track_;
141 blink::WebMediaStreamTrack webkit_track_;
142 // const copy of the webrtc track id that allows us to check it from both the
143 // main and signaling threads without incurring a synchronous thread hop.
144 const std::string id_;
146 DISALLOW_COPY_AND_ASSIGN(RemoteMediaStreamTrackAdapter);
149 class RemoteVideoTrackAdapter
150 : public RemoteMediaStreamTrackAdapter<webrtc::VideoTrackInterface> {
152 // Called on the signaling thread
153 RemoteVideoTrackAdapter(
154 const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
155 webrtc::VideoTrackInterface* webrtc_track)
156 : RemoteMediaStreamTrackAdapter(main_thread, webrtc_track) {
157 source_observer_ = new MediaStreamRemoteVideoSource::Observer(main_thread,
158 observed_track().get());
159 // Here, we use base::Unretained() to avoid a circular reference.
160 webkit_initialize_ = base::Bind(
161 &RemoteVideoTrackAdapter::InitializeWebkitVideoTrack,
162 base::Unretained(this), observed_track()->enabled());
166 ~RemoteVideoTrackAdapter() override {
167 // If the source_observer_ is valid at this point, then that means we
168 // haven't been initialized and we need to unregister the observer before
169 // it gets automatically deleted. We can't unregister from the destructor
170 // of the observer because at that point, the refcount will be 0 and we
171 // could receive an event during that time which would attempt to increment
172 // the refcount while we're running the dtor on this thread...
173 if (source_observer_.get()) {
174 DCHECK(!initialized());
175 source_observer_->Unregister();
178 // TODO(tommi): There's got to be a smarter way of solving this.
179 // We should probably separate the implementation of the observer itself
180 // and the ownerof the weakptr to the main thread's implementation of
185 void InitializeWebkitVideoTrack(bool enabled) {
186 DCHECK(main_thread_->BelongsToCurrentThread());
187 scoped_ptr<MediaStreamRemoteVideoSource> video_source(
188 new MediaStreamRemoteVideoSource(source_observer_));
189 // Now that we're being initialized, we do not want to unregister the
190 // observer in the dtor. This will be done when the source goes out of
191 // scope. A source can be shared by more than one tracks (e.g via cloning)
192 // so we must not unregister an observer that belongs to a live source.
193 source_observer_ = nullptr;
194 InitializeWebkitTrack(blink::WebMediaStreamSource::TypeVideo);
195 webkit_track()->source().setExtraData(video_source.get());
196 // Initial constraints must be provided to a MediaStreamVideoTrack. But
197 // no constraints are available initially on a remote video track.
198 blink::WebMediaConstraints constraints;
199 constraints.initialize();
200 MediaStreamVideoTrack* media_stream_track =
201 new MediaStreamVideoTrack(video_source.release(), constraints,
202 MediaStreamVideoSource::ConstraintsCallback(), enabled);
203 webkit_track()->setExtraData(media_stream_track);
206 // We hold on to the source observer in case we don't get initialized and
207 // need to unregister it in the dtor.
208 // TODO(tommi): There has to be a more elegant solution.
209 scoped_refptr<MediaStreamRemoteVideoSource::Observer> source_observer_;
212 // RemoteAudioTrackAdapter is responsible for listening on state
213 // change notifications on a remote webrtc audio MediaStreamTracks and notify
215 class RemoteAudioTrackAdapter
216 : public RemoteMediaStreamTrackAdapter<webrtc::AudioTrackInterface>,
217 public webrtc::ObserverInterface {
219 RemoteAudioTrackAdapter(
220 const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
221 webrtc::AudioTrackInterface* webrtc_track);
226 ~RemoteAudioTrackAdapter() override;
229 void InitializeWebkitAudioTrack(
230 scoped_ptr<RemoteMediaStreamAudioTrack> media_stream_track);
232 // webrtc::ObserverInterface implementation.
233 void OnChanged() override;
235 void OnChangedOnMainThread(
236 webrtc::MediaStreamTrackInterface::TrackState state);
242 webrtc::MediaStreamTrackInterface::TrackState state_;
244 DISALLOW_COPY_AND_ASSIGN(RemoteAudioTrackAdapter);
247 // Called on the signaling thread.
248 RemoteAudioTrackAdapter::RemoteAudioTrackAdapter(
249 const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
250 webrtc::AudioTrackInterface* webrtc_track)
251 : RemoteMediaStreamTrackAdapter(main_thread, webrtc_track),
253 unregistered_(false),
255 state_(observed_track()->state()) {
256 observed_track()->RegisterObserver(this);
257 scoped_ptr<RemoteMediaStreamAudioTrack> media_stream_track(
258 new RemoteMediaStreamAudioTrack(observed_track().get(),
259 base::ThreadTaskRunnerHandle::Get()));
260 // Here, we use base::Unretained() to avoid a circular reference.
261 webkit_initialize_ = base::Bind(
262 &RemoteAudioTrackAdapter::InitializeWebkitAudioTrack,
263 base::Unretained(this), base::Passed(&media_stream_track));
266 RemoteAudioTrackAdapter::~RemoteAudioTrackAdapter() {
268 DCHECK(unregistered_);
272 void RemoteAudioTrackAdapter::Unregister() {
274 DCHECK(!unregistered_);
275 unregistered_ = true;
277 observed_track()->UnregisterObserver(this);
280 void RemoteAudioTrackAdapter::InitializeWebkitAudioTrack(
281 scoped_ptr<RemoteMediaStreamAudioTrack> media_stream_track) {
282 InitializeWebkitTrack(blink::WebMediaStreamSource::TypeAudio);
283 webkit_track()->setExtraData(media_stream_track.release());
286 void RemoteAudioTrackAdapter::OnChanged() {
287 main_thread_->PostTask(FROM_HERE,
288 base::Bind(&RemoteAudioTrackAdapter::OnChangedOnMainThread,
289 this, observed_track()->state()));
292 void RemoteAudioTrackAdapter::OnChangedOnMainThread(
293 webrtc::MediaStreamTrackInterface::TrackState state) {
294 DCHECK(main_thread_->BelongsToCurrentThread());
296 if (state == state_ || !initialized())
302 case webrtc::MediaStreamTrackInterface::kInitializing:
303 // Ignore the kInitializing state since there is no match in
304 // WebMediaStreamSource::ReadyState.
306 case webrtc::MediaStreamTrackInterface::kLive:
307 webkit_track()->source().setReadyState(
308 blink::WebMediaStreamSource::ReadyStateLive);
310 case webrtc::MediaStreamTrackInterface::kEnded:
311 webkit_track()->source().setReadyState(
312 blink::WebMediaStreamSource::ReadyStateEnded);
320 RemoteMediaStreamImpl::Observer::Observer(
321 const base::WeakPtr<RemoteMediaStreamImpl>& media_stream,
322 const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
323 webrtc::MediaStreamInterface* webrtc_stream)
324 : media_stream_(media_stream),
325 main_thread_(main_thread),
326 webrtc_stream_(webrtc_stream) {
327 webrtc_stream_->RegisterObserver(this);
330 RemoteMediaStreamImpl::Observer::~Observer() {
331 DCHECK(!webrtc_stream_.get()) << "Unregister hasn't been called";
334 void RemoteMediaStreamImpl::Observer::InitializeOnMainThread(
335 const std::string& label) {
336 DCHECK(main_thread_->BelongsToCurrentThread());
338 media_stream_->InitializeOnMainThread(label);
341 void RemoteMediaStreamImpl::Observer::Unregister() {
342 DCHECK(main_thread_->BelongsToCurrentThread());
343 webrtc_stream_->UnregisterObserver(this);
344 // Since we're guaranteed to not get further notifications, it's safe to
345 // release the webrtc_stream_ here.
346 webrtc_stream_ = nullptr;
349 void RemoteMediaStreamImpl::Observer::OnChanged() {
350 scoped_ptr<RemoteAudioTrackAdapters> audio(new RemoteAudioTrackAdapters());
351 scoped_ptr<RemoteVideoTrackAdapters> video(new RemoteVideoTrackAdapters());
353 CreateAdaptersForTracks(
354 webrtc_stream_->GetAudioTracks(), audio.get(), main_thread_);
355 CreateAdaptersForTracks(
356 webrtc_stream_->GetVideoTracks(), video.get(), main_thread_);
358 main_thread_->PostTask(FROM_HERE,
359 base::Bind(&RemoteMediaStreamImpl::Observer::OnChangedOnMainThread,
360 this, base::Passed(&audio), base::Passed(&video)));
363 void RemoteMediaStreamImpl::Observer::OnChangedOnMainThread(
364 scoped_ptr<RemoteAudioTrackAdapters> audio_tracks,
365 scoped_ptr<RemoteVideoTrackAdapters> video_tracks) {
366 DCHECK(main_thread_->BelongsToCurrentThread());
368 media_stream_->OnChanged(audio_tracks.Pass(), video_tracks.Pass());
371 // Called on the signaling thread.
372 RemoteMediaStreamImpl::RemoteMediaStreamImpl(
373 const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
374 webrtc::MediaStreamInterface* webrtc_stream)
375 : signaling_thread_(base::ThreadTaskRunnerHandle::Get()),
377 observer_(new RemoteMediaStreamImpl::Observer(weak_factory_.GetWeakPtr(),
378 main_thread, webrtc_stream)) {
379 CreateAdaptersForTracks(webrtc_stream->GetAudioTracks(),
380 &audio_track_observers_, main_thread);
381 CreateAdaptersForTracks(webrtc_stream->GetVideoTracks(),
382 &video_track_observers_, main_thread);
384 main_thread->PostTask(FROM_HERE,
385 base::Bind(&RemoteMediaStreamImpl::Observer::InitializeOnMainThread,
386 observer_, webrtc_stream->label()));
389 RemoteMediaStreamImpl::~RemoteMediaStreamImpl() {
390 DCHECK(observer_->main_thread()->BelongsToCurrentThread());
391 for (auto& track : audio_track_observers_)
393 observer_->Unregister();
396 void RemoteMediaStreamImpl::InitializeOnMainThread(const std::string& label) {
397 DCHECK(observer_->main_thread()->BelongsToCurrentThread());
398 blink::WebVector<blink::WebMediaStreamTrack> webkit_audio_tracks(
399 audio_track_observers_.size());
400 for (size_t i = 0; i < audio_track_observers_.size(); ++i) {
401 audio_track_observers_[i]->Initialize();
402 webkit_audio_tracks[i] = *audio_track_observers_[i]->webkit_track();
405 blink::WebVector<blink::WebMediaStreamTrack> webkit_video_tracks(
406 video_track_observers_.size());
407 for (size_t i = 0; i < video_track_observers_.size(); ++i) {
408 video_track_observers_[i]->Initialize();
409 webkit_video_tracks[i] = *video_track_observers_[i]->webkit_track();
412 webkit_stream_.initialize(base::UTF8ToUTF16(label),
413 webkit_audio_tracks, webkit_video_tracks);
414 webkit_stream_.setExtraData(new MediaStream(observer_->stream().get()));
417 void RemoteMediaStreamImpl::OnChanged(
418 scoped_ptr<RemoteAudioTrackAdapters> audio_tracks,
419 scoped_ptr<RemoteVideoTrackAdapters> video_tracks) {
420 // Find removed tracks.
421 auto audio_it = audio_track_observers_.begin();
422 while (audio_it != audio_track_observers_.end()) {
423 if (!IsTrackInVector(*audio_tracks.get(), (*audio_it)->id())) {
424 (*audio_it)->Unregister();
425 webkit_stream_.removeTrack(*(*audio_it)->webkit_track());
426 audio_it = audio_track_observers_.erase(audio_it);
432 auto video_it = video_track_observers_.begin();
433 while (video_it != video_track_observers_.end()) {
434 if (!IsTrackInVector(*video_tracks.get(), (*video_it)->id())) {
435 webkit_stream_.removeTrack(*(*video_it)->webkit_track());
436 video_it = video_track_observers_.erase(video_it);
442 // Find added tracks.
443 for (auto& track : *audio_tracks.get()) {
444 if (!IsTrackInVector(audio_track_observers_, track->id())) {
446 audio_track_observers_.push_back(track);
447 webkit_stream_.addTrack(*track->webkit_track());
448 // Set the track to null to avoid unregistering it below now that it's
449 // been associated with a media stream.
454 // Find added video tracks.
455 for (const auto& track : *video_tracks.get()) {
456 if (!IsTrackInVector(video_track_observers_, track->id())) {
458 video_track_observers_.push_back(track);
459 webkit_stream_.addTrack(*track->webkit_track());
463 // Unregister all the audio track observers that were not used.
464 // We need to do this before destruction since the observers can't unregister
465 // from within the dtor due to a race.
466 for (auto& track : *audio_tracks.get()) {
472 } // namespace content