OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/renderer/media/media_stream_audio_source.h" | 5 #include "content/renderer/media/media_stream_audio_source.h" |
6 | 6 |
7 #include "content/renderer/render_frame_impl.h" | 7 #include <algorithm> |
| 8 |
| 9 #include "base/bind.h" |
| 10 #include "content/renderer/media/media_stream_audio_track.h" |
| 11 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h" |
| 12 #include "third_party/WebKit/public/platform/WebString.h" |
8 | 13 |
9 namespace content { | 14 namespace content { |
10 | 15 |
11 MediaStreamAudioSource::MediaStreamAudioSource( | 16 MediaStreamAudioSource::MediaStreamAudioSource(bool is_local_source) |
12 int render_frame_id, | 17 : is_stopped_(false), |
13 const StreamDeviceInfo& device_info, | 18 is_local_source_(is_local_source), |
14 const SourceStoppedCallback& stop_callback, | 19 weak_factory_(this) { |
15 PeerConnectionDependencyFactory* factory) | 20 DVLOG(1) << "MediaStreamAudioSource::MediaStreamAudioSource(is a " |
16 : render_frame_id_(render_frame_id), factory_(factory) { | 21 << (is_local_source_ ? "local" : "remote") << " source)"; |
17 SetDeviceInfo(device_info); | |
18 SetStopCallback(stop_callback); | |
19 } | 22 } |
20 | 23 |
21 MediaStreamAudioSource::MediaStreamAudioSource() | 24 MediaStreamAudioSource::~MediaStreamAudioSource() { |
22 : render_frame_id_(-1), factory_(NULL) { | 25 DCHECK(thread_checker_.CalledOnValidThread()); |
| 26 DVLOG(1) << "MediaStreamAudioSource::~MediaStreamAudioSource()"; |
| 27 if (!is_stopped_) |
| 28 StopSource(); |
| 29 DCHECK(is_stopped_); |
23 } | 30 } |
24 | 31 |
25 MediaStreamAudioSource::~MediaStreamAudioSource() {} | 32 // static |
| 33 MediaStreamAudioSource* MediaStreamAudioSource::Get( |
| 34 const blink::WebMediaStreamSource& source) { |
| 35 if (source.isNull() || |
| 36 source.type() != blink::WebMediaStreamSource::TypeAudio) { |
| 37 return nullptr; |
| 38 } |
| 39 return static_cast<MediaStreamAudioSource*>(source.extraData()); |
| 40 } |
| 41 |
| 42 bool MediaStreamAudioSource::ConnectToTrack( |
| 43 const blink::WebMediaStreamTrack& track) { |
| 44 DCHECK(thread_checker_.CalledOnValidThread()); |
| 45 DCHECK(!track.isNull()); |
| 46 |
| 47 // Sanity-check that there is not already a MediaStreamAudioTrack instance |
| 48 // associated with |track|. |
| 49 if (MediaStreamAudioTrack::Get(track)) { |
| 50 NOTREACHED() |
| 51 << "Attempting to connect another source to a WebMediaStreamTrack."; |
| 52 return false; |
| 53 } |
| 54 |
| 55 if (!EnsureSourceIsStarted()) |
| 56 return false; |
| 57 ConnectStartedSourceToTrack(track); |
| 58 return true; |
| 59 } |
| 60 |
| 61 media::AudioParameters MediaStreamAudioSource::GetAudioParameters() const { |
| 62 base::AutoLock auto_lock(lock_); |
| 63 return params_; |
| 64 } |
| 65 |
| 66 void* MediaStreamAudioSource::GetClassIdentifier() const { |
| 67 return nullptr; |
| 68 } |
| 69 |
| 70 void MediaStreamAudioSource::StartSourceForTesting() { |
| 71 CHECK(EnsureSourceIsStarted()); |
| 72 } |
| 73 |
| 74 scoped_ptr<MediaStreamAudioTrack> |
| 75 MediaStreamAudioSource::CreateMediaStreamAudioTrack(const std::string& id) { |
| 76 DCHECK(thread_checker_.CalledOnValidThread()); |
| 77 return make_scoped_ptr(new MediaStreamAudioTrack(is_local_source())); |
| 78 } |
26 | 79 |
27 void MediaStreamAudioSource::DoStopSource() { | 80 void MediaStreamAudioSource::DoStopSource() { |
28 if (audio_capturer_.get()) | 81 DCHECK(thread_checker_.CalledOnValidThread()); |
29 audio_capturer_->Stop(); | 82 DVLOG(1) << "MediaStreamAudioSource::DoStopSource()"; |
| 83 if (is_stopped_) |
| 84 return; |
| 85 is_stopped_ = true; |
30 } | 86 } |
31 | 87 |
32 void MediaStreamAudioSource::AddTrack( | 88 bool MediaStreamAudioSource::EnsureSourceIsStarted() { |
33 const blink::WebMediaStreamTrack& track, | 89 DCHECK(thread_checker_.CalledOnValidThread()); |
34 const blink::WebMediaConstraints& constraints, | 90 DVLOG(1) << "MediaStreamAudioSource::EnsureSourceIsStarted()"; |
35 const ConstraintsCallback& callback) { | 91 if (is_stopped_) |
36 // TODO(xians): Properly implement for audio sources. | 92 return false; |
37 if (!local_audio_source_.get()) { | 93 return true; |
38 if (!factory_->InitializeMediaStreamAudioSource(render_frame_id_, | 94 } |
39 constraints, this)) { | 95 |
40 // The source failed to start. | 96 void MediaStreamAudioSource::SetFormat(const media::AudioParameters& params) { |
41 // UserMediaClientImpl rely on the |stop_callback| to be triggered when | 97 // Note: May be called on any thread. |
42 // the last track is removed from the source. But in this case, the | 98 |
43 // source is is not even started. So we need to fail both adding the | 99 DCHECK(params.IsValid()); |
44 // track and trigger |stop_callback|. | 100 base::AutoLock auto_lock(lock_); |
45 callback.Run(this, MEDIA_DEVICE_TRACK_START_FAILURE, ""); | 101 DVLOG(1) << "MediaStreamAudioSource::SetFormat(" |
46 StopSource(); | 102 << params.AsHumanReadableString() << "), was previously set to {" |
47 return; | 103 << params_.AsHumanReadableString() << "}."; |
48 } | 104 if (params_.Equals(params)) |
| 105 return; |
| 106 params_ = params; |
| 107 for (MediaStreamAudioTrack* track : tracks_) |
| 108 track->SetFormat(params); |
| 109 } |
| 110 |
| 111 void MediaStreamAudioSource::DeliverDataToTracks( |
| 112 const media::AudioBus& audio_bus, |
| 113 base::TimeTicks reference_time) { |
| 114 // Note: May be called on any thread. |
| 115 |
| 116 base::AutoLock auto_lock(lock_); |
| 117 DCHECK(params_.IsValid()); |
| 118 for (MediaStreamAudioTrack* track : tracks_) |
| 119 track->DeliverDataToSinks(audio_bus, reference_time); |
| 120 } |
| 121 |
| 122 void MediaStreamAudioSource::ConnectStartedSourceToTrack( |
| 123 const blink::WebMediaStreamTrack& blink_track) { |
| 124 DCHECK(thread_checker_.CalledOnValidThread()); |
| 125 DCHECK(!is_stopped_); |
| 126 |
| 127 // Create a MediaStreamAudioTrack to deliver audio data directly from the |
| 128 // calls to Capture() to all its managed sinks. Pass ownership of it to the |
| 129 // WebMediaStreamTrack. |
| 130 scoped_ptr<MediaStreamAudioTrack> track = |
| 131 CreateMediaStreamAudioTrack(blink_track.id().utf8()); |
| 132 track->AddStopObserver( |
| 133 base::Bind(&MediaStreamAudioSource::StopAudioDeliveryTo, |
| 134 weak_factory_.GetWeakPtr(), |
| 135 track.get())); |
| 136 track->SetEnabled(blink_track.isEnabled()); |
| 137 { |
| 138 base::AutoLock auto_lock(lock_); |
| 139 if (params_.IsValid()) |
| 140 track->SetFormat(params_); |
| 141 tracks_.push_back(track.get()); |
| 142 } |
| 143 blink::WebMediaStreamTrack mutable_blink_track = blink_track; |
| 144 mutable_blink_track.setExtraData(track.release()); |
| 145 } |
| 146 |
| 147 void MediaStreamAudioSource::StopAudioDeliveryTo(MediaStreamAudioTrack* track) { |
| 148 DCHECK(thread_checker_.CalledOnValidThread()); |
| 149 |
| 150 // Remove |track| from the list of tracks, which will immediatly halt all |
| 151 // further audio data delivery. |
| 152 bool did_remove_last_track = false; |
| 153 { |
| 154 base::AutoLock auto_lock(lock_); |
| 155 const bool had_tracks = !tracks_.empty(); |
| 156 const auto it = std::find(tracks_.begin(), tracks_.end(), track); |
| 157 if (it != tracks_.end()) |
| 158 tracks_.erase(it); |
| 159 did_remove_last_track = had_tracks && tracks_.empty(); |
49 } | 160 } |
50 | 161 |
51 factory_->CreateLocalAudioTrack(track); | 162 // TODO(miu): Is this the right behavior? Perhaps sources should be |
52 callback.Run(this, MEDIA_DEVICE_OK, ""); | 163 // explicitly closed, rather than auto-stop on the removal of the last track? |
| 164 if (!is_stopped_ && did_remove_last_track) |
| 165 StopSource(); |
53 } | 166 } |
54 | 167 |
55 } // namespace content | 168 } // namespace content |
OLD | NEW |