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_extra_data.h"
12#include "third_party/WebKit/public/platform/WebString.h"
13
14namespace content {
15
16// RemoteMediaStreamTrackObserver is responsible for listening on change
17// notification on a remote webrtc MediaStreamTrack and notify WebKit.
18class RemoteMediaStreamTrackObserver
19    : NON_EXPORTED_BASE(public webrtc::ObserverInterface),
20      NON_EXPORTED_BASE(public base::NonThreadSafe) {
21 public:
22  RemoteMediaStreamTrackObserver(
23      webrtc::MediaStreamTrackInterface* webrtc_track,
24      const WebKit::WebMediaStreamTrack& webkit_track);
25  virtual ~RemoteMediaStreamTrackObserver();
26
27  webrtc::MediaStreamTrackInterface* observered_track() {
28    return webrtc_track_.get();
29  }
30  const WebKit::WebMediaStreamTrack& webkit_track() { return webkit_track_; }
31
32 private:
33  // webrtc::ObserverInterface implementation.
34  virtual void OnChanged() OVERRIDE;
35
36  webrtc::MediaStreamTrackInterface::TrackState state_;
37  scoped_refptr<webrtc::MediaStreamTrackInterface> webrtc_track_;
38  WebKit::WebMediaStreamTrack webkit_track_;
39
40  DISALLOW_COPY_AND_ASSIGN(RemoteMediaStreamTrackObserver);
41};
42
43}  // namespace content
44
45namespace {
46
47void InitializeWebkitTrack(webrtc::MediaStreamTrackInterface* track,
48                           WebKit::WebMediaStreamTrack* webkit_track,
49                           WebKit::WebMediaStreamSource::Type type) {
50  WebKit::WebMediaStreamSource webkit_source;
51  WebKit::WebString webkit_track_id(UTF8ToUTF16(track->id()));
52
53  webkit_source.initialize(webkit_track_id, type, webkit_track_id);
54  webkit_track->initialize(webkit_track_id, webkit_source);
55}
56
57content::RemoteMediaStreamTrackObserver* FindTrackObserver(
58    webrtc::MediaStreamTrackInterface* track,
59    const ScopedVector<content::RemoteMediaStreamTrackObserver>& observers) {
60  ScopedVector<content::RemoteMediaStreamTrackObserver>::const_iterator it =
61      observers.begin();
62  for (; it != observers.end(); ++it) {
63    if ((*it)->observered_track() == track)
64      return *it;
65  }
66  return NULL;
67}
68
69} // namespace anonymous
70
71namespace content {
72
73RemoteMediaStreamTrackObserver::RemoteMediaStreamTrackObserver(
74    webrtc::MediaStreamTrackInterface* webrtc_track,
75    const WebKit::WebMediaStreamTrack& webkit_track)
76    : state_(webrtc_track->state()),
77      webrtc_track_(webrtc_track),
78      webkit_track_(webkit_track) {
79  webrtc_track->RegisterObserver(this);
80}
81
82RemoteMediaStreamTrackObserver::~RemoteMediaStreamTrackObserver() {
83  webrtc_track_->UnregisterObserver(this);
84}
85
86void RemoteMediaStreamTrackObserver::OnChanged() {
87  DCHECK(CalledOnValidThread());
88
89  webrtc::MediaStreamTrackInterface::TrackState state = webrtc_track_->state();
90  if (state == state_)
91    return;
92
93  state_ = state;
94  switch (state) {
95    case webrtc::MediaStreamTrackInterface::kInitializing:
96      // Ignore the kInitializing state since there is no match in
97      // WebMediaStreamSource::ReadyState.
98      break;
99    case webrtc::MediaStreamTrackInterface::kLive:
100      webkit_track_.source().setReadyState(
101          WebKit::WebMediaStreamSource::ReadyStateLive);
102      break;
103    case webrtc::MediaStreamTrackInterface::kEnded:
104      webkit_track_.source().setReadyState(
105          WebKit::WebMediaStreamSource::ReadyStateEnded);
106      break;
107    default:
108      NOTREACHED();
109      break;
110  }
111}
112
113RemoteMediaStreamImpl::RemoteMediaStreamImpl(
114    webrtc::MediaStreamInterface* webrtc_stream)
115    : webrtc_stream_(webrtc_stream) {
116  webrtc_stream_->RegisterObserver(this);
117
118  webrtc::AudioTrackVector webrtc_audio_tracks =
119      webrtc_stream_->GetAudioTracks();
120  WebKit::WebVector<WebKit::WebMediaStreamTrack> webkit_audio_tracks(
121      webrtc_audio_tracks.size());
122
123  // Initialize WebKit audio tracks.
124  size_t i = 0;
125  for (; i < webrtc_audio_tracks.size(); ++i) {
126    webrtc::AudioTrackInterface* audio_track = webrtc_audio_tracks[i];
127    DCHECK(audio_track);
128    InitializeWebkitTrack(audio_track,  &webkit_audio_tracks[i],
129                          WebKit::WebMediaStreamSource::TypeAudio);
130    audio_track_observers_.push_back(
131        new RemoteMediaStreamTrackObserver(audio_track,
132                                           webkit_audio_tracks[i]));
133  }
134
135  // Initialize WebKit video tracks.
136  webrtc::VideoTrackVector webrtc_video_tracks =
137        webrtc_stream_->GetVideoTracks();
138  WebKit::WebVector<WebKit::WebMediaStreamTrack> webkit_video_tracks(
139       webrtc_video_tracks.size());
140  for (i = 0; i < webrtc_video_tracks.size(); ++i) {
141    webrtc::VideoTrackInterface* video_track = webrtc_video_tracks[i];
142    DCHECK(video_track);
143    InitializeWebkitTrack(video_track,  &webkit_video_tracks[i],
144                          WebKit::WebMediaStreamSource::TypeVideo);
145    video_track_observers_.push_back(
146        new RemoteMediaStreamTrackObserver(video_track,
147                                           webkit_video_tracks[i]));
148  }
149
150  webkit_stream_.initialize(UTF8ToUTF16(webrtc_stream->label()),
151                            webkit_audio_tracks, webkit_video_tracks);
152  webkit_stream_.setExtraData(new MediaStreamExtraData(webrtc_stream, false));
153}
154
155RemoteMediaStreamImpl::~RemoteMediaStreamImpl() {
156  webrtc_stream_->UnregisterObserver(this);
157}
158
159void RemoteMediaStreamImpl::OnChanged() {
160  // Find removed audio tracks.
161  ScopedVector<RemoteMediaStreamTrackObserver>::iterator audio_it =
162      audio_track_observers_.begin();
163  while (audio_it != audio_track_observers_.end()) {
164    std::string track_id = (*audio_it)->observered_track()->id();
165    if (webrtc_stream_->FindAudioTrack(track_id) == NULL) {
166       webkit_stream_.removeTrack((*audio_it)->webkit_track());
167       audio_it = audio_track_observers_.erase(audio_it);
168    } else {
169      ++audio_it;
170    }
171  }
172
173  // Find removed video tracks.
174  ScopedVector<RemoteMediaStreamTrackObserver>::iterator video_it =
175      video_track_observers_.begin();
176  while (video_it != video_track_observers_.end()) {
177    std::string track_id = (*video_it)->observered_track()->id();
178    if (webrtc_stream_->FindVideoTrack(track_id) == NULL) {
179      webkit_stream_.removeTrack((*video_it)->webkit_track());
180      video_it = video_track_observers_.erase(video_it);
181    } else {
182      ++video_it;
183    }
184  }
185
186  // Find added audio tracks.
187  webrtc::AudioTrackVector webrtc_audio_tracks =
188      webrtc_stream_->GetAudioTracks();
189  for (webrtc::AudioTrackVector::iterator it = webrtc_audio_tracks.begin();
190       it != webrtc_audio_tracks.end(); ++it) {
191    if (!FindTrackObserver(*it, audio_track_observers_)) {
192      WebKit::WebMediaStreamTrack new_track;
193      InitializeWebkitTrack(*it, &new_track,
194                            WebKit::WebMediaStreamSource::TypeAudio);
195      audio_track_observers_.push_back(
196          new RemoteMediaStreamTrackObserver(*it, new_track));
197      webkit_stream_.addTrack(new_track);
198    }
199  }
200
201  // Find added video tracks.
202  webrtc::VideoTrackVector webrtc_video_tracks =
203      webrtc_stream_->GetVideoTracks();
204  for (webrtc::VideoTrackVector::iterator it = webrtc_video_tracks.begin();
205       it != webrtc_video_tracks.end(); ++it) {
206    if (!FindTrackObserver(*it, video_track_observers_)) {
207      WebKit::WebMediaStreamTrack new_track;
208      InitializeWebkitTrack(*it, &new_track,
209                            WebKit::WebMediaStreamSource::TypeVideo);
210      video_track_observers_.push_back(
211          new RemoteMediaStreamTrackObserver(*it, new_track));
212      webkit_stream_.addTrack(new_track);
213    }
214  }
215}
216
217}  // namespace content
218