| Index: content/renderer/media/media_stream_audio_source.cc
|
| diff --git a/content/renderer/media/media_stream_audio_source.cc b/content/renderer/media/media_stream_audio_source.cc
|
| index c643140e4dbdb6ef5d3d294477a3b7f3cb4cd785..660d14c79cc1dc80c2cd9080d937f7a9b4c15076 100644
|
| --- a/content/renderer/media/media_stream_audio_source.cc
|
| +++ b/content/renderer/media/media_stream_audio_source.cc
|
| @@ -4,52 +4,165 @@
|
|
|
| #include "content/renderer/media/media_stream_audio_source.h"
|
|
|
| -#include "content/renderer/render_frame_impl.h"
|
| +#include <algorithm>
|
| +
|
| +#include "base/bind.h"
|
| +#include "content/renderer/media/media_stream_audio_track.h"
|
| +#include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
|
| +#include "third_party/WebKit/public/platform/WebString.h"
|
|
|
| namespace content {
|
|
|
| -MediaStreamAudioSource::MediaStreamAudioSource(
|
| - int render_frame_id,
|
| - const StreamDeviceInfo& device_info,
|
| - const SourceStoppedCallback& stop_callback,
|
| - PeerConnectionDependencyFactory* factory)
|
| - : render_frame_id_(render_frame_id), factory_(factory) {
|
| - SetDeviceInfo(device_info);
|
| - SetStopCallback(stop_callback);
|
| +MediaStreamAudioSource::MediaStreamAudioSource(bool is_local_source)
|
| + : is_stopped_(false),
|
| + is_local_source_(is_local_source),
|
| + weak_factory_(this) {
|
| + DVLOG(1) << "MediaStreamAudioSource::MediaStreamAudioSource(is a "
|
| + << (is_local_source_ ? "local" : "remote") << " source)";
|
| +}
|
| +
|
| +MediaStreamAudioSource::~MediaStreamAudioSource() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DVLOG(1) << "MediaStreamAudioSource::~MediaStreamAudioSource()";
|
| + if (!is_stopped_)
|
| + StopSource();
|
| + DCHECK(is_stopped_);
|
| +}
|
| +
|
| +// static
|
| +MediaStreamAudioSource* MediaStreamAudioSource::Get(
|
| + const blink::WebMediaStreamSource& source) {
|
| + if (source.isNull() ||
|
| + source.type() != blink::WebMediaStreamSource::TypeAudio) {
|
| + return nullptr;
|
| + }
|
| + return static_cast<MediaStreamAudioSource*>(source.extraData());
|
| +}
|
| +
|
| +bool MediaStreamAudioSource::ConnectToTrack(
|
| + const blink::WebMediaStreamTrack& track) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK(!track.isNull());
|
| +
|
| + // Sanity-check that there is not already a MediaStreamAudioTrack instance
|
| + // associated with |track|.
|
| + if (MediaStreamAudioTrack::Get(track)) {
|
| + NOTREACHED()
|
| + << "Attempting to connect another source to a WebMediaStreamTrack.";
|
| + return false;
|
| + }
|
| +
|
| + if (!EnsureSourceIsStarted())
|
| + return false;
|
| + ConnectStartedSourceToTrack(track);
|
| + return true;
|
| +}
|
| +
|
| +media::AudioParameters MediaStreamAudioSource::GetAudioParameters() const {
|
| + base::AutoLock auto_lock(lock_);
|
| + return params_;
|
| +}
|
| +
|
| +void* MediaStreamAudioSource::GetClassIdentifier() const {
|
| + return nullptr;
|
| }
|
|
|
| -MediaStreamAudioSource::MediaStreamAudioSource()
|
| - : render_frame_id_(-1), factory_(NULL) {
|
| +void MediaStreamAudioSource::StartSourceForTesting() {
|
| + CHECK(EnsureSourceIsStarted());
|
| }
|
|
|
| -MediaStreamAudioSource::~MediaStreamAudioSource() {}
|
| +scoped_ptr<MediaStreamAudioTrack>
|
| +MediaStreamAudioSource::CreateMediaStreamAudioTrack(const std::string& id) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + return make_scoped_ptr(new MediaStreamAudioTrack(is_local_source()));
|
| +}
|
|
|
| void MediaStreamAudioSource::DoStopSource() {
|
| - if (audio_capturer_.get())
|
| - audio_capturer_->Stop();
|
| -}
|
| -
|
| -void MediaStreamAudioSource::AddTrack(
|
| - const blink::WebMediaStreamTrack& track,
|
| - const blink::WebMediaConstraints& constraints,
|
| - const ConstraintsCallback& callback) {
|
| - // TODO(xians): Properly implement for audio sources.
|
| - if (!local_audio_source_.get()) {
|
| - if (!factory_->InitializeMediaStreamAudioSource(render_frame_id_,
|
| - constraints, this)) {
|
| - // The source failed to start.
|
| - // UserMediaClientImpl rely on the |stop_callback| to be triggered when
|
| - // the last track is removed from the source. But in this case, the
|
| - // source is is not even started. So we need to fail both adding the
|
| - // track and trigger |stop_callback|.
|
| - callback.Run(this, MEDIA_DEVICE_TRACK_START_FAILURE, "");
|
| - StopSource();
|
| - return;
|
| - }
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DVLOG(1) << "MediaStreamAudioSource::DoStopSource()";
|
| + if (is_stopped_)
|
| + return;
|
| + is_stopped_ = true;
|
| +}
|
| +
|
| +bool MediaStreamAudioSource::EnsureSourceIsStarted() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DVLOG(1) << "MediaStreamAudioSource::EnsureSourceIsStarted()";
|
| + if (is_stopped_)
|
| + return false;
|
| + return true;
|
| +}
|
| +
|
| +void MediaStreamAudioSource::SetFormat(const media::AudioParameters& params) {
|
| + // Note: May be called on any thread.
|
| +
|
| + DCHECK(params.IsValid());
|
| + base::AutoLock auto_lock(lock_);
|
| + DVLOG(1) << "MediaStreamAudioSource::SetFormat("
|
| + << params.AsHumanReadableString() << "), was previously set to {"
|
| + << params_.AsHumanReadableString() << "}.";
|
| + if (params_.Equals(params))
|
| + return;
|
| + params_ = params;
|
| + for (MediaStreamAudioTrack* track : tracks_)
|
| + track->SetFormat(params);
|
| +}
|
| +
|
| +void MediaStreamAudioSource::DeliverDataToTracks(
|
| + const media::AudioBus& audio_bus,
|
| + base::TimeTicks reference_time) {
|
| + // Note: May be called on any thread.
|
| +
|
| + base::AutoLock auto_lock(lock_);
|
| + DCHECK(params_.IsValid());
|
| + for (MediaStreamAudioTrack* track : tracks_)
|
| + track->DeliverDataToSinks(audio_bus, reference_time);
|
| +}
|
| +
|
| +void MediaStreamAudioSource::ConnectStartedSourceToTrack(
|
| + const blink::WebMediaStreamTrack& blink_track) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK(!is_stopped_);
|
| +
|
| + // Create a MediaStreamAudioTrack to deliver audio data directly from the
|
| + // calls to Capture() to all its managed sinks. Pass ownership of it to the
|
| + // WebMediaStreamTrack.
|
| + scoped_ptr<MediaStreamAudioTrack> track =
|
| + CreateMediaStreamAudioTrack(blink_track.id().utf8());
|
| + track->AddStopObserver(
|
| + base::Bind(&MediaStreamAudioSource::StopAudioDeliveryTo,
|
| + weak_factory_.GetWeakPtr(),
|
| + track.get()));
|
| + track->SetEnabled(blink_track.isEnabled());
|
| + {
|
| + base::AutoLock auto_lock(lock_);
|
| + if (params_.IsValid())
|
| + track->SetFormat(params_);
|
| + tracks_.push_back(track.get());
|
| + }
|
| + blink::WebMediaStreamTrack mutable_blink_track = blink_track;
|
| + mutable_blink_track.setExtraData(track.release());
|
| +}
|
| +
|
| +void MediaStreamAudioSource::StopAudioDeliveryTo(MediaStreamAudioTrack* track) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + // Remove |track| from the list of tracks, which will immediatly halt all
|
| + // further audio data delivery.
|
| + bool did_remove_last_track = false;
|
| + {
|
| + base::AutoLock auto_lock(lock_);
|
| + const bool had_tracks = !tracks_.empty();
|
| + const auto it = std::find(tracks_.begin(), tracks_.end(), track);
|
| + if (it != tracks_.end())
|
| + tracks_.erase(it);
|
| + did_remove_last_track = had_tracks && tracks_.empty();
|
| }
|
|
|
| - factory_->CreateLocalAudioTrack(track);
|
| - callback.Run(this, MEDIA_DEVICE_OK, "");
|
| + // TODO(miu): Is this the right behavior? Perhaps sources should be
|
| + // explicitly closed, rather than auto-stop on the removal of the last track?
|
| + if (!is_stopped_ && did_remove_last_track)
|
| + StopSource();
|
| }
|
|
|
| } // namespace content
|
|
|