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 |