OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "media/blink/webaudiosourceprovider_impl.h" | 5 #include "media/blink/webaudiosourceprovider_impl.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/callback_helpers.h" | 10 #include "base/callback_helpers.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/macros.h" | 12 #include "base/macros.h" |
13 #include "base/memory/ptr_util.h" | 13 #include "base/memory/ptr_util.h" |
14 #include "base/metrics/histogram_macros.h" | |
15 #include "base/single_thread_task_runner.h" | |
16 #include "media/audio/null_audio_sink.h" | |
14 #include "media/base/audio_timestamp_helper.h" | 17 #include "media/base/audio_timestamp_helper.h" |
15 #include "media/base/bind_to_current_loop.h" | 18 #include "media/base/bind_to_current_loop.h" |
19 #include "media/base/media_log.h" | |
16 #include "third_party/WebKit/public/platform/WebAudioSourceProviderClient.h" | 20 #include "third_party/WebKit/public/platform/WebAudioSourceProviderClient.h" |
17 | 21 |
18 using blink::WebVector; | 22 using blink::WebVector; |
19 | 23 |
20 namespace media { | 24 namespace media { |
21 | 25 |
22 namespace { | 26 namespace { |
23 | 27 |
24 // Simple helper class for Try() locks. Lock is Try()'d on construction and | 28 // Simple helper class for Try() locks. Lock is Try()'d on construction and |
25 // must be checked via the locked() attribute. If acquisition was successful | 29 // must be checked via the locked() attribute. If acquisition was successful |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
87 AudioRendererSink::RenderCallback* renderer_; | 91 AudioRendererSink::RenderCallback* renderer_; |
88 int channels_; | 92 int channels_; |
89 int sample_rate_; | 93 int sample_rate_; |
90 | 94 |
91 CopyAudioCB copy_audio_bus_callback_; | 95 CopyAudioCB copy_audio_bus_callback_; |
92 | 96 |
93 DISALLOW_COPY_AND_ASSIGN(TeeFilter); | 97 DISALLOW_COPY_AND_ASSIGN(TeeFilter); |
94 }; | 98 }; |
95 | 99 |
96 WebAudioSourceProviderImpl::WebAudioSourceProviderImpl( | 100 WebAudioSourceProviderImpl::WebAudioSourceProviderImpl( |
97 const scoped_refptr<SwitchableAudioRendererSink>& sink) | 101 const scoped_refptr<SwitchableAudioRendererSink>& sink, |
102 scoped_refptr<MediaLog> media_log) | |
98 : volume_(1.0), | 103 : volume_(1.0), |
99 state_(kStopped), | 104 state_(kStopped), |
100 client_(nullptr), | 105 client_(nullptr), |
101 sink_(sink), | 106 sink_(sink), |
102 tee_filter_(new TeeFilter()), | 107 tee_filter_(new TeeFilter()), |
108 media_log_(media_log), | |
dcheng
2016/12/02 18:25:03
Nit: std::move()
o1ka
2016/12/05 09:54:13
Done.
| |
103 weak_factory_(this) {} | 109 weak_factory_(this) {} |
104 | 110 |
105 WebAudioSourceProviderImpl::~WebAudioSourceProviderImpl() { | 111 WebAudioSourceProviderImpl::~WebAudioSourceProviderImpl() { |
106 } | 112 } |
107 | 113 |
108 void WebAudioSourceProviderImpl::setClient( | 114 void WebAudioSourceProviderImpl::setClient( |
109 blink::WebAudioSourceProviderClient* client) { | 115 blink::WebAudioSourceProviderClient* client) { |
110 // Skip taking the lock if unnecessary. This function is the only setter for | 116 // Skip taking the lock if unnecessary. This function is the only setter for |
111 // |client_| so it's safe to check |client_| outside of the lock. | 117 // |client_| so it's safe to check |client_| outside of the lock. |
112 if (client_ == client) | 118 if (client_ == client) |
113 return; | 119 return; |
114 | 120 |
115 base::AutoLock auto_lock(sink_lock_); | 121 base::AutoLock auto_lock(sink_lock_); |
116 if (client) { | 122 if (client) { |
117 // Detach the audio renderer from normal playback. | 123 // Detach the audio renderer from normal playback. |
118 sink_->Stop(); | 124 if (sink_) |
125 sink_->Stop(); | |
119 | 126 |
120 // The client will now take control by calling provideInput() periodically. | 127 // The client will now take control by calling provideInput() periodically. |
121 client_ = client; | 128 client_ = client; |
122 | 129 |
123 set_format_cb_ = BindToCurrentLoop(base::Bind( | 130 set_format_cb_ = BindToCurrentLoop(base::Bind( |
124 &WebAudioSourceProviderImpl::OnSetFormat, weak_factory_.GetWeakPtr())); | 131 &WebAudioSourceProviderImpl::OnSetFormat, weak_factory_.GetWeakPtr())); |
125 | 132 |
126 // If |tee_filter_| is Initialize()d - then run |set_format_cb_| to send | 133 // If |tee_filter_| is Initialize()d - then run |set_format_cb_| to send |
127 // |client_| the current format info. Otherwise |set_format_cb_| will get | 134 // |client_| the current format info. Otherwise |set_format_cb_| will get |
128 // called when Initialize() is called. Note: Always using |set_format_cb_| | 135 // called when Initialize() is called. Note: Always using |set_format_cb_| |
129 // ensures we have the same locking order when calling into |client_|. | 136 // ensures we have the same locking order when calling into |client_|. |
130 if (tee_filter_->IsInitialized()) | 137 if (tee_filter_->IsInitialized()) |
131 base::ResetAndReturn(&set_format_cb_).Run(); | 138 base::ResetAndReturn(&set_format_cb_).Run(); |
132 return; | 139 return; |
133 } | 140 } |
134 | 141 |
135 // Restore normal playback. | 142 // Restore normal playback. |
136 client_ = nullptr; | 143 client_ = nullptr; |
137 sink_->SetVolume(volume_); | 144 if (sink_) { |
138 if (state_ >= kStarted) | 145 sink_->SetVolume(volume_); |
139 sink_->Start(); | 146 if (state_ >= kStarted) |
140 if (state_ >= kPlaying) | 147 sink_->Start(); |
141 sink_->Play(); | 148 if (state_ >= kPlaying) |
149 sink_->Play(); | |
150 } | |
142 } | 151 } |
143 | 152 |
144 void WebAudioSourceProviderImpl::provideInput( | 153 void WebAudioSourceProviderImpl::provideInput( |
145 const WebVector<float*>& audio_data, size_t number_of_frames) { | 154 const WebVector<float*>& audio_data, size_t number_of_frames) { |
146 if (!bus_wrapper_ || | 155 if (!bus_wrapper_ || |
147 static_cast<size_t>(bus_wrapper_->channels()) != audio_data.size()) { | 156 static_cast<size_t>(bus_wrapper_->channels()) != audio_data.size()) { |
148 bus_wrapper_ = AudioBus::CreateWrapper(static_cast<int>(audio_data.size())); | 157 bus_wrapper_ = AudioBus::CreateWrapper(static_cast<int>(audio_data.size())); |
149 } | 158 } |
150 | 159 |
151 const int incoming_number_of_frames = static_cast<int>(number_of_frames); | 160 const int incoming_number_of_frames = static_cast<int>(number_of_frames); |
(...skipping 18 matching lines...) Expand all Loading... | |
170 bus_wrapper_->ZeroFramesPartial(frames, incoming_number_of_frames - frames); | 179 bus_wrapper_->ZeroFramesPartial(frames, incoming_number_of_frames - frames); |
171 | 180 |
172 bus_wrapper_->Scale(volume_); | 181 bus_wrapper_->Scale(volume_); |
173 } | 182 } |
174 | 183 |
175 void WebAudioSourceProviderImpl::Initialize(const AudioParameters& params, | 184 void WebAudioSourceProviderImpl::Initialize(const AudioParameters& params, |
176 RenderCallback* renderer) { | 185 RenderCallback* renderer) { |
177 base::AutoLock auto_lock(sink_lock_); | 186 base::AutoLock auto_lock(sink_lock_); |
178 DCHECK_EQ(state_, kStopped); | 187 DCHECK_EQ(state_, kStopped); |
179 | 188 |
189 OutputDeviceStatus device_status = | |
190 sink_ ? sink_->GetOutputDeviceInfo().device_status() | |
191 : OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND; | |
192 | |
193 UMA_HISTOGRAM_ENUMERATION("Media.WebMediaPlayer.SinkStatus", device_status, | |
DaleCurtis
2016/12/02 18:28:56
WebAudioSourceProvider?
o1ka
2016/12/05 09:54:13
Done.
| |
194 OUTPUT_DEVICE_STATUS_MAX + 1); | |
195 | |
196 if (device_status != OUTPUT_DEVICE_STATUS_OK) { | |
197 // Since null sink is always OK, we will fall back to it once and forever. | |
198 if (sink_) | |
199 sink_->Stop(); | |
200 sink_ = CreateFallbackSink(); | |
201 MEDIA_LOG(ERROR, media_log_) | |
202 << "Output device error, falling back to null sink"; | |
203 } | |
204 | |
180 tee_filter_->Initialize(renderer, params.channels(), params.sample_rate()); | 205 tee_filter_->Initialize(renderer, params.channels(), params.sample_rate()); |
181 | 206 |
182 sink_->Initialize(params, tee_filter_.get()); | 207 sink_->Initialize(params, tee_filter_.get()); |
183 | 208 |
184 if (!set_format_cb_.is_null()) | 209 if (!set_format_cb_.is_null()) |
185 base::ResetAndReturn(&set_format_cb_).Run(); | 210 base::ResetAndReturn(&set_format_cb_).Run(); |
186 } | 211 } |
187 | 212 |
188 void WebAudioSourceProviderImpl::Start() { | 213 void WebAudioSourceProviderImpl::Start() { |
189 base::AutoLock auto_lock(sink_lock_); | 214 base::AutoLock auto_lock(sink_lock_); |
(...skipping 23 matching lines...) Expand all Loading... | |
213 base::AutoLock auto_lock(sink_lock_); | 238 base::AutoLock auto_lock(sink_lock_); |
214 DCHECK(state_ == kPlaying || state_ == kStarted); | 239 DCHECK(state_ == kPlaying || state_ == kStarted); |
215 state_ = kStarted; | 240 state_ = kStarted; |
216 if (!client_) | 241 if (!client_) |
217 sink_->Pause(); | 242 sink_->Pause(); |
218 } | 243 } |
219 | 244 |
220 bool WebAudioSourceProviderImpl::SetVolume(double volume) { | 245 bool WebAudioSourceProviderImpl::SetVolume(double volume) { |
221 base::AutoLock auto_lock(sink_lock_); | 246 base::AutoLock auto_lock(sink_lock_); |
222 volume_ = volume; | 247 volume_ = volume; |
223 if (!client_) | 248 if (!client_ && sink_) |
224 sink_->SetVolume(volume); | 249 sink_->SetVolume(volume); |
225 return true; | 250 return true; |
226 } | 251 } |
227 | 252 |
228 media::OutputDeviceInfo WebAudioSourceProviderImpl::GetOutputDeviceInfo() { | 253 OutputDeviceInfo WebAudioSourceProviderImpl::GetOutputDeviceInfo() { |
229 base::AutoLock auto_lock(sink_lock_); | 254 base::AutoLock auto_lock(sink_lock_); |
230 return sink_->GetOutputDeviceInfo(); | 255 return sink_ ? sink_->GetOutputDeviceInfo() |
256 : OutputDeviceInfo(OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND); | |
231 } | 257 } |
232 | 258 |
233 bool WebAudioSourceProviderImpl::CurrentThreadIsRenderingThread() { | 259 bool WebAudioSourceProviderImpl::CurrentThreadIsRenderingThread() { |
234 NOTIMPLEMENTED(); | 260 NOTIMPLEMENTED(); |
235 return false; | 261 return false; |
236 } | 262 } |
237 | 263 |
238 void WebAudioSourceProviderImpl::SwitchOutputDevice( | 264 void WebAudioSourceProviderImpl::SwitchOutputDevice( |
239 const std::string& device_id, | 265 const std::string& device_id, |
240 const url::Origin& security_origin, | 266 const url::Origin& security_origin, |
241 const OutputDeviceStatusCB& callback) { | 267 const OutputDeviceStatusCB& callback) { |
242 base::AutoLock auto_lock(sink_lock_); | 268 base::AutoLock auto_lock(sink_lock_); |
243 if (client_) | 269 if (client_ || !sink_) |
244 callback.Run(media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL); | 270 callback.Run(OUTPUT_DEVICE_STATUS_ERROR_INTERNAL); |
245 else | 271 else |
246 sink_->SwitchOutputDevice(device_id, security_origin, callback); | 272 sink_->SwitchOutputDevice(device_id, security_origin, callback); |
247 } | 273 } |
248 | 274 |
249 void WebAudioSourceProviderImpl::SetCopyAudioCallback( | 275 void WebAudioSourceProviderImpl::SetCopyAudioCallback( |
250 const CopyAudioCB& callback) { | 276 const CopyAudioCB& callback) { |
251 DCHECK(!callback.is_null()); | 277 DCHECK(!callback.is_null()); |
252 | 278 |
253 // Use |sink_lock_| to protect |tee_filter_| too since they go in lockstep. | 279 // Use |sink_lock_| to protect |tee_filter_| too since they go in lockstep. |
254 base::AutoLock auto_lock(sink_lock_); | 280 base::AutoLock auto_lock(sink_lock_); |
(...skipping 14 matching lines...) Expand all Loading... | |
269 | 295 |
270 void WebAudioSourceProviderImpl::OnSetFormat() { | 296 void WebAudioSourceProviderImpl::OnSetFormat() { |
271 base::AutoLock auto_lock(sink_lock_); | 297 base::AutoLock auto_lock(sink_lock_); |
272 if (!client_) | 298 if (!client_) |
273 return; | 299 return; |
274 | 300 |
275 // Inform Blink about the audio stream format. | 301 // Inform Blink about the audio stream format. |
276 client_->setFormat(tee_filter_->channels(), tee_filter_->sample_rate()); | 302 client_->setFormat(tee_filter_->channels(), tee_filter_->sample_rate()); |
277 } | 303 } |
278 | 304 |
305 scoped_refptr<SwitchableAudioRendererSink> | |
306 WebAudioSourceProviderImpl::CreateFallbackSink() { | |
307 // Assuming it is called on media thread. | |
308 return new NullAudioSink(base::ThreadTaskRunnerHandle::Get()); | |
309 } | |
310 | |
279 int WebAudioSourceProviderImpl::TeeFilter::Render( | 311 int WebAudioSourceProviderImpl::TeeFilter::Render( |
280 base::TimeDelta delay, | 312 base::TimeDelta delay, |
281 base::TimeTicks delay_timestamp, | 313 base::TimeTicks delay_timestamp, |
282 int prior_frames_skipped, | 314 int prior_frames_skipped, |
283 AudioBus* audio_bus) { | 315 AudioBus* audio_bus) { |
284 DCHECK(IsInitialized()); | 316 DCHECK(IsInitialized()); |
285 | 317 |
286 const int num_rendered_frames = renderer_->Render( | 318 const int num_rendered_frames = renderer_->Render( |
287 delay, delay_timestamp, prior_frames_skipped, audio_bus); | 319 delay, delay_timestamp, prior_frames_skipped, audio_bus); |
288 | 320 |
289 if (!copy_audio_bus_callback_.is_null()) { | 321 if (!copy_audio_bus_callback_.is_null()) { |
290 const int64_t frames_delayed = | 322 const int64_t frames_delayed = |
291 AudioTimestampHelper::TimeToFrames(delay, sample_rate_); | 323 AudioTimestampHelper::TimeToFrames(delay, sample_rate_); |
292 std::unique_ptr<AudioBus> bus_copy = | 324 std::unique_ptr<AudioBus> bus_copy = |
293 AudioBus::Create(audio_bus->channels(), audio_bus->frames()); | 325 AudioBus::Create(audio_bus->channels(), audio_bus->frames()); |
294 audio_bus->CopyTo(bus_copy.get()); | 326 audio_bus->CopyTo(bus_copy.get()); |
295 copy_audio_bus_callback_.Run(std::move(bus_copy), frames_delayed, | 327 copy_audio_bus_callback_.Run(std::move(bus_copy), frames_delayed, |
296 sample_rate_); | 328 sample_rate_); |
297 } | 329 } |
298 | 330 |
299 return num_rendered_frames; | 331 return num_rendered_frames; |
300 } | 332 } |
301 | 333 |
302 void WebAudioSourceProviderImpl::TeeFilter::OnRenderError() { | 334 void WebAudioSourceProviderImpl::TeeFilter::OnRenderError() { |
303 DCHECK(IsInitialized()); | 335 DCHECK(IsInitialized()); |
304 renderer_->OnRenderError(); | 336 renderer_->OnRenderError(); |
305 } | 337 } |
306 | 338 |
307 } // namespace media | 339 } // namespace media |
OLD | NEW |