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

Side by Side Diff: media/audio/audio_output_resampler.cc

Issue 10958020: Don't fallback if we've successfully opened a stream previously. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Revert double-stop() change. Created 8 years, 3 months 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/audio/audio_output_resampler.h" 5 #include "media/audio/audio_output_resampler.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h" 8 #include "base/bind_helpers.h"
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/compiler_specific.h" 10 #include "base/compiler_specific.h"
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
167 frames_per_buffer); 167 frames_per_buffer);
168 } 168 }
169 169
170 AudioOutputResampler::AudioOutputResampler(AudioManager* audio_manager, 170 AudioOutputResampler::AudioOutputResampler(AudioManager* audio_manager,
171 const AudioParameters& input_params, 171 const AudioParameters& input_params,
172 const AudioParameters& output_params, 172 const AudioParameters& output_params,
173 const base::TimeDelta& close_delay) 173 const base::TimeDelta& close_delay)
174 : AudioOutputDispatcher(audio_manager, input_params), 174 : AudioOutputDispatcher(audio_manager, input_params),
175 io_ratio_(1), 175 io_ratio_(1),
176 close_delay_(close_delay), 176 close_delay_(close_delay),
177 output_params_(output_params) { 177 output_params_(output_params),
178 streams_opened_(false) {
178 DCHECK_EQ(output_params_.format(), AudioParameters::AUDIO_PCM_LOW_LATENCY); 179 DCHECK_EQ(output_params_.format(), AudioParameters::AUDIO_PCM_LOW_LATENCY);
179 180
180 // Record UMA statistics for the hardware configuration. 181 // Record UMA statistics for the hardware configuration.
181 RecordStats(output_params); 182 RecordStats(output_params);
182 183
183 // Immediately fallback if we're given invalid output parameters. This may 184 // Immediately fallback if we're given invalid output parameters. This may
184 // happen if the OS provided us junk values for the hardware configuration. 185 // happen if the OS provided us junk values for the hardware configuration.
185 if (!output_params_.IsValid()) { 186 if (!output_params_.IsValid()) {
186 LOG(ERROR) << "Invalid audio output parameters received; using fallback " 187 LOG(ERROR) << "Invalid audio output parameters received; using fallback "
187 << "path. Channels: " << output_params_.channels() << ", " 188 << "path. Channels: " << output_params_.channels() << ", "
188 << "Sample Rate: " << output_params_.sample_rate() << ", " 189 << "Sample Rate: " << output_params_.sample_rate() << ", "
189 << "Bits Per Sample: " << output_params_.bits_per_sample() 190 << "Bits Per Sample: " << output_params_.bits_per_sample()
190 << ", Frames Per Buffer: " << output_params_.frames_per_buffer(); 191 << ", Frames Per Buffer: " << output_params_.frames_per_buffer();
191 // Record UMA statistics about the hardware which triggered the failure so 192 // Record UMA statistics about the hardware which triggered the failure so
192 // we can debug and triage later. 193 // we can debug and triage later.
193 RecordFallbackStats(output_params); 194 RecordFallbackStats(output_params);
194 output_params_ = SetupFallbackParams(input_params, output_params); 195 output_params_ = SetupFallbackParams(input_params, output_params);
195 } 196 }
196 197
197 Initialize(); 198 Initialize();
198 } 199 }
199 200
200 AudioOutputResampler::~AudioOutputResampler() {} 201 AudioOutputResampler::~AudioOutputResampler() {
202 DCHECK(callbacks_.empty());
203 }
201 204
202 void AudioOutputResampler::Initialize() { 205 void AudioOutputResampler::Initialize() {
203 io_ratio_ = 1; 206 io_ratio_ = 1;
204 207
205 // TODO(dalecurtis): Add channel remixing. http://crbug.com/138762 208 // TODO(dalecurtis): Add channel remixing. http://crbug.com/138762
206 DCHECK_EQ(params_.channels(), output_params_.channels()); 209 DCHECK_EQ(params_.channels(), output_params_.channels());
207 // Only resample or rebuffer if the input parameters don't match the output 210 // Only resample or rebuffer if the input parameters don't match the output
208 // parameters to avoid any unnecessary work. 211 // parameters to avoid any unnecessary work.
209 if (params_.channels() != output_params_.channels() || 212 if (params_.channels() != output_params_.channels() ||
210 params_.sample_rate() != output_params_.sample_rate() || 213 params_.sample_rate() != output_params_.sample_rate() ||
(...skipping 19 matching lines...) Expand all
230 DVLOG(1) << "Input and output params are the same; in pass-through mode."; 233 DVLOG(1) << "Input and output params are the same; in pass-through mode.";
231 } 234 }
232 235
233 // TODO(dalecurtis): All this code should be merged into AudioOutputMixer once 236 // TODO(dalecurtis): All this code should be merged into AudioOutputMixer once
234 // we've stabilized the issues there. 237 // we've stabilized the issues there.
235 dispatcher_ = new AudioOutputDispatcherImpl( 238 dispatcher_ = new AudioOutputDispatcherImpl(
236 audio_manager_, output_params_, close_delay_); 239 audio_manager_, output_params_, close_delay_);
237 } 240 }
238 241
239 bool AudioOutputResampler::OpenStream() { 242 bool AudioOutputResampler::OpenStream() {
243 DCHECK_EQ(MessageLoop::current(), message_loop_);
244
240 if (dispatcher_->OpenStream()) { 245 if (dispatcher_->OpenStream()) {
scherkus (not reviewing) 2012/09/21 01:24:18 I'm not a fan of the implicit stateness in this cl
DaleCurtis 2012/09/21 02:57:27 I'm not sure it's any more readable, but I've uplo
246 streams_opened_ = true;
241 // Only record the UMA statistic if we didn't fallback during construction. 247 // Only record the UMA statistic if we didn't fallback during construction.
242 if (output_params_.format() == AudioParameters::AUDIO_PCM_LOW_LATENCY) 248 if (output_params_.format() == AudioParameters::AUDIO_PCM_LOW_LATENCY)
243 UMA_HISTOGRAM_BOOLEAN("Media.FallbackToHighLatencyAudioPath", false); 249 UMA_HISTOGRAM_BOOLEAN("Media.FallbackToHighLatencyAudioPath", false);
244 return true; 250 return true;
245 } 251 }
246 252
247 // If we've already tried to open the stream in high latency mode, there's 253 // If we've already tried to open the stream in high latency mode or we've
248 // nothing more to be done. 254 // successfully opened a stream previously, there's nothing more to be done.
249 if (output_params_.format() == AudioParameters::AUDIO_PCM_LINEAR) 255 if (output_params_.format() == AudioParameters::AUDIO_PCM_LINEAR ||
256 streams_opened_ || !callbacks_.empty()) {
250 return false; 257 return false;
258 }
259
260 DCHECK(!streams_opened_);
261 DCHECK(callbacks_.empty());
251 262
252 if (CommandLine::ForCurrentProcess()->HasSwitch( 263 if (CommandLine::ForCurrentProcess()->HasSwitch(
253 switches::kDisableAudioFallback)) { 264 switches::kDisableAudioFallback)) {
254 LOG(ERROR) << "Open failed and automatic fallback to high latency audio " 265 LOG(ERROR) << "Open failed and automatic fallback to high latency audio "
255 << "path is disabled, aborting."; 266 << "path is disabled, aborting.";
256 return false; 267 return false;
257 } 268 }
258 269
259 // TODO(dalecurtis): Is it better to recreate the whole |dispatcher_| ? See
260 // http://crbug.com/149815
261 dispatcher_->CloseStream(NULL);
262
263 DLOG(ERROR) << "Unable to open audio device in low latency mode. Falling " 270 DLOG(ERROR) << "Unable to open audio device in low latency mode. Falling "
264 << "back to high latency audio output."; 271 << "back to high latency audio output.";
265 272
266 // Record UMA statistics about the hardware which triggered the failure so 273 // Record UMA statistics about the hardware which triggered the failure so
267 // we can debug and triage later. 274 // we can debug and triage later.
268 RecordFallbackStats(output_params_); 275 RecordFallbackStats(output_params_);
269 output_params_ = SetupFallbackParams(params_, output_params_); 276 output_params_ = SetupFallbackParams(params_, output_params_);
270 Initialize(); 277 Initialize();
271 278
272 // Retry, if this fails, there's nothing left to do but report the error back. 279 // Retry, if this fails, there's nothing left to do but report the error back.
273 return dispatcher_->OpenStream(); 280 return dispatcher_->OpenStream();
274 } 281 }
275 282
276 bool AudioOutputResampler::StartStream( 283 bool AudioOutputResampler::StartStream(
277 AudioOutputStream::AudioSourceCallback* callback, 284 AudioOutputStream::AudioSourceCallback* callback,
278 AudioOutputProxy* stream_proxy) { 285 AudioOutputProxy* stream_proxy) {
286 DCHECK_EQ(MessageLoop::current(), message_loop_);
287
279 OnMoreDataResampler* resampler_callback = NULL; 288 OnMoreDataResampler* resampler_callback = NULL;
280 { 289 CallbackMap::iterator it = callbacks_.find(stream_proxy);
281 base::AutoLock auto_lock(callbacks_lock_); 290 if (it == callbacks_.end()) {
282 CallbackMap::iterator it = callbacks_.find(stream_proxy); 291 resampler_callback = new OnMoreDataResampler(
283 if (it == callbacks_.end()) { 292 io_ratio_, params_, output_params_);
284 resampler_callback = new OnMoreDataResampler( 293 callbacks_[stream_proxy] = resampler_callback;
285 io_ratio_, params_, output_params_); 294 } else {
286 callbacks_[stream_proxy] = resampler_callback; 295 resampler_callback = it->second;
287 } else {
288 resampler_callback = it->second;
289 }
290 resampler_callback->Start(callback);
291 } 296 }
297 resampler_callback->Start(callback);
292 return dispatcher_->StartStream(resampler_callback, stream_proxy); 298 return dispatcher_->StartStream(resampler_callback, stream_proxy);
293 } 299 }
294 300
295 void AudioOutputResampler::StreamVolumeSet(AudioOutputProxy* stream_proxy, 301 void AudioOutputResampler::StreamVolumeSet(AudioOutputProxy* stream_proxy,
296 double volume) { 302 double volume) {
303 DCHECK_EQ(MessageLoop::current(), message_loop_);
297 dispatcher_->StreamVolumeSet(stream_proxy, volume); 304 dispatcher_->StreamVolumeSet(stream_proxy, volume);
298 } 305 }
299 306
300 void AudioOutputResampler::StopStream(AudioOutputProxy* stream_proxy) { 307 void AudioOutputResampler::StopStream(AudioOutputProxy* stream_proxy) {
308 DCHECK_EQ(MessageLoop::current(), message_loop_);
301 dispatcher_->StopStream(stream_proxy); 309 dispatcher_->StopStream(stream_proxy);
302 310
303 // Now that StopStream() has completed the underlying physical stream should 311 // Now that StopStream() has completed the underlying physical stream should
304 // be stopped and no longer calling OnMoreData(), making it safe to Stop() the 312 // be stopped and no longer calling OnMoreData(), making it safe to Stop() the
305 // OnMoreDataResampler. 313 // OnMoreDataResampler.
306 { 314 CallbackMap::iterator it = callbacks_.find(stream_proxy);
307 base::AutoLock auto_lock(callbacks_lock_); 315 if (it != callbacks_.end())
308 CallbackMap::iterator it = callbacks_.find(stream_proxy); 316 it->second->Stop();
309 if (it != callbacks_.end())
310 it->second->Stop();
311 }
312 } 317 }
313 318
314 void AudioOutputResampler::CloseStream(AudioOutputProxy* stream_proxy) { 319 void AudioOutputResampler::CloseStream(AudioOutputProxy* stream_proxy) {
scherkus (not reviewing) 2012/09/21 01:24:18 to confirm.. we never have to reset streams_opened
DaleCurtis 2012/09/21 02:57:27 Nope, especially since AudioOutputDispatcherImpl m
315 // Force StopStream() before CloseStream(). 320 DCHECK_EQ(MessageLoop::current(), message_loop_);
316 // TODO(dalecurtis): This shouldn't be necessary, but somewhere in the chain
317 // CloseStream() is occurring without a StopStream() which causes the callback
318 // provided by OnMoreDataResampler to go away before the output stream is
319 // ready. http://crbug.com/150619
320 StopStream(stream_proxy);
321 dispatcher_->CloseStream(stream_proxy); 321 dispatcher_->CloseStream(stream_proxy);
322 322
323 // We assume that StopStream() is always called prior to CloseStream(), so 323 // We assume that StopStream() is always called prior to CloseStream(), so
324 // that it is safe to delete the OnMoreDataResampler here. 324 // that it is safe to delete the OnMoreDataResampler here.
325 { 325 CallbackMap::iterator it = callbacks_.find(stream_proxy);
326 base::AutoLock auto_lock(callbacks_lock_); 326 if (it != callbacks_.end()) {
327 CallbackMap::iterator it = callbacks_.find(stream_proxy); 327 delete it->second;
328 if (it != callbacks_.end()) { 328 callbacks_.erase(it);
329 delete it->second;
330 callbacks_.erase(it);
331 }
332 } 329 }
333 } 330 }
334 331
335 void AudioOutputResampler::Shutdown() { 332 void AudioOutputResampler::Shutdown() {
333 DCHECK_EQ(MessageLoop::current(), message_loop_);
334
335 // No AudioOutputProxy objects should hold a reference to us when we get
336 // to this stage.
337 DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference";
scherkus (not reviewing) 2012/09/21 01:24:18 did this end up firing?
DaleCurtis 2012/09/21 02:57:27 During testing when I messed up the AOP/AOC state
338
336 dispatcher_->Shutdown(); 339 dispatcher_->Shutdown();
337 DCHECK(callbacks_.empty()); 340 DCHECK(callbacks_.empty());
338 } 341 }
339 342
340 OnMoreDataResampler::OnMoreDataResampler( 343 OnMoreDataResampler::OnMoreDataResampler(
341 double io_ratio, const AudioParameters& input_params, 344 double io_ratio, const AudioParameters& input_params,
342 const AudioParameters& output_params) 345 const AudioParameters& output_params)
343 : io_ratio_(io_ratio), 346 : io_ratio_(io_ratio),
344 source_callback_(NULL), 347 source_callback_(NULL),
345 outstanding_audio_bytes_(0), 348 outstanding_audio_bytes_(0),
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
470 source_callback_->OnError(stream, code); 473 source_callback_->OnError(stream, code);
471 } 474 }
472 475
473 void OnMoreDataResampler::WaitTillDataReady() { 476 void OnMoreDataResampler::WaitTillDataReady() {
474 base::AutoLock auto_lock(source_lock_); 477 base::AutoLock auto_lock(source_lock_);
475 if (source_callback_ && !outstanding_audio_bytes_) 478 if (source_callback_ && !outstanding_audio_bytes_)
476 source_callback_->WaitTillDataReady(); 479 source_callback_->WaitTillDataReady();
477 } 480 }
478 481
479 } // namespace media 482 } // namespace media
OLDNEW
« media/audio/audio_output_proxy_unittest.cc ('K') | « media/audio/audio_output_resampler.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698