Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(767)

Side by Side Diff: media/blink/webaudiosourceprovider_impl.cc

Issue 2533443002: fallback to null sink in WebAudioSourceProvider::Initialize() + UMA stats for device status (Closed)
Patch Set: content unittest fix Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698