Chromium Code Reviews| 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 d2027fd939e797db1171625fcf469f8466c2fd36..4ddae4ed06c76d8f9261d73d43ffe0be09239fb5 100644 | 
| --- a/content/renderer/media/media_stream_audio_source.cc | 
| +++ b/content/renderer/media/media_stream_audio_source.cc | 
| @@ -4,29 +4,29 @@ | 
| #include "content/renderer/media/media_stream_audio_source.h" | 
| -#include "content/renderer/media/webrtc_local_audio_track.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), | 
| +MediaStreamAudioSource::MediaStreamAudioSource(bool is_local_source) | 
| + : is_stopped_(false), | 
| + is_local_source_(is_local_source), | 
| weak_factory_(this) { | 
| - SetDeviceInfo(device_info); | 
| - SetStopCallback(stop_callback); | 
| + DVLOG(1) << "MediaStreamAudioSource::MediaStreamAudioSource(is a " | 
| + << (is_local_source_ ? "local" : "remote") << " source)"; | 
| } | 
| -MediaStreamAudioSource::MediaStreamAudioSource() | 
| - : render_frame_id_(-1), factory_(NULL), weak_factory_(this) { | 
| +MediaStreamAudioSource::~MediaStreamAudioSource() { | 
| + DCHECK(thread_checker_.CalledOnValidThread()); | 
| + DVLOG(1) << "MediaStreamAudioSource::~MediaStreamAudioSource()"; | 
| + DCHECK(is_stopped_) << "BUG: Subclass must ensure StopSource() is called."; | 
| 
 
o1ka
2016/03/30 15:00:57
Since this flag is supposed to be set by a child c
 
miu
2016/03/31 04:57:59
Fixed.  As described in a comment below, I reworke
 
 | 
| } | 
| -MediaStreamAudioSource::~MediaStreamAudioSource() {} | 
| - | 
| // static | 
| MediaStreamAudioSource* MediaStreamAudioSource::From( | 
| const blink::WebMediaStreamSource& source) { | 
| @@ -37,50 +37,122 @@ MediaStreamAudioSource* MediaStreamAudioSource::From( | 
| return static_cast<MediaStreamAudioSource*>(source.getExtraData()); | 
| } | 
| +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::From(track)) { | 
| + LOG(DFATAL) | 
| + << "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; | 
| +} | 
| + | 
| +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_) | 
| - audio_capturer_->Stop(); | 
| - if (webaudio_capturer_) | 
| - webaudio_capturer_->Stop(); | 
| + DCHECK(thread_checker_.CalledOnValidThread()); | 
| + DVLOG(1) << "MediaStreamAudioSource::DoStopSource()"; | 
| + if (is_stopped_) | 
| + return; | 
| + is_stopped_ = true; | 
| } | 
| -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; | 
| - } | 
| - } | 
| +bool MediaStreamAudioSource::EnsureSourceIsStarted() { | 
| + DCHECK(thread_checker_.CalledOnValidThread()); | 
| + DVLOG(1) << "MediaStreamAudioSource::EnsureSourceIsStarted()"; | 
| + if (is_stopped_) | 
| + return false; | 
| + return true; | 
| +} | 
| - factory_->CreateLocalAudioTrack(track); | 
| - callback.Run(this, MEDIA_DEVICE_OK, ""); | 
| +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::StopAudioDeliveryTo(MediaStreamAudioTrack* track) { | 
| - DCHECK(track); | 
| - if (audio_capturer_) { | 
| - // The cast here is safe because only WebRtcLocalAudioTracks are ever used | 
| - // with WebRtcAudioCapturer sources. | 
| - // | 
| - // TODO(miu): That said, this ugly cast won't be necessary after my | 
| - // soon-upcoming refactoring change. | 
| - audio_capturer_->RemoveTrack(static_cast<WebRtcLocalAudioTrack*>(track)); | 
| +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->Start(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()); | 
| } | 
| - if (webaudio_capturer_) { | 
| - // A separate source is created for each track, so just stop the source. | 
| - webaudio_capturer_->Stop(); | 
| + 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(); | 
| } | 
| + // TODO(miu): Is this the behavior we want? Perhaps sources should be | 
| + // explicitly closed, rather than auto-stop on the removal of the last track | 
| + // (behavior preserved from the defunct WebRtcAudioCapturer::RemoveTrack())? | 
| + if (!is_stopped_ && did_remove_last_track) | 
| + StopSource(); | 
| } | 
| } // namespace content |