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
17namespace content {
18
19namespace {
20
21void 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.
55class RemoteMediaStreamTrackAdapter {
56 public:
57  RemoteMediaStreamTrackAdapter(webrtc::MediaStreamTrackInterface* webrtc_track,
58                                const blink::WebMediaStreamTrack& webkit_track)
59     : webrtc_track_(webrtc_track),
60       webkit_track_(webkit_track) {
61  }
62
63  virtual ~RemoteMediaStreamTrackAdapter() {
64  }
65
66  webrtc::MediaStreamTrackInterface* observed_track() {
67    return webrtc_track_.get();
68  }
69
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
79static 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.
94class 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
113RemoteAudioMediaStreamTrackAdapter::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
121RemoteAudioMediaStreamTrackAdapter::~RemoteAudioMediaStreamTrackAdapter() {
122  observed_track()->UnregisterObserver(this);
123}
124
125void 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
153RemoteMediaStreamImpl::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
195RemoteMediaStreamImpl::~RemoteMediaStreamImpl() {
196  webrtc_stream_->UnregisterObserver(this);
197}
198
199void 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