blob: d2421310ef85bef455da7a25d7ca08e70e0e4e71 [file] [log] [blame]
// 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