OLD | NEW |
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" |
11 #include "base/message_loop.h" | 11 #include "base/message_loop.h" |
12 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
13 #include "base/time.h" | 13 #include "base/time.h" |
| 14 #include "build/build_config.h" |
14 #include "media/audio/audio_io.h" | 15 #include "media/audio/audio_io.h" |
15 #include "media/audio/audio_output_dispatcher_impl.h" | 16 #include "media/audio/audio_output_dispatcher_impl.h" |
16 #include "media/audio/audio_output_proxy.h" | 17 #include "media/audio/audio_output_proxy.h" |
17 #include "media/audio/audio_util.h" | 18 #include "media/audio/audio_util.h" |
18 #include "media/audio/sample_rates.h" | 19 #include "media/audio/sample_rates.h" |
19 #include "media/base/audio_pull_fifo.h" | 20 #include "media/base/audio_pull_fifo.h" |
20 #include "media/base/channel_mixer.h" | 21 #include "media/base/channel_mixer.h" |
21 #include "media/base/limits.h" | 22 #include "media/base/limits.h" |
22 #include "media/base/media_switches.h" | 23 #include "media/base/media_switches.h" |
23 #include "media/base/multi_channel_resampler.h" | 24 #include "media/base/multi_channel_resampler.h" |
24 | 25 |
| 26 #if defined(OS_WIN) |
| 27 #include "media/audio/win/core_audio_util_win.h" |
| 28 #endif |
| 29 |
25 namespace media { | 30 namespace media { |
26 | 31 |
27 class OnMoreDataResampler : public AudioOutputStream::AudioSourceCallback { | 32 class OnMoreDataResampler : public AudioOutputStream::AudioSourceCallback { |
28 public: | 33 public: |
29 OnMoreDataResampler(double io_ratio, | 34 OnMoreDataResampler(double io_ratio, |
30 const AudioParameters& input_params, | 35 const AudioParameters& input_params, |
31 const AudioParameters& output_params); | 36 const AudioParameters& output_params); |
32 virtual ~OnMoreDataResampler(); | 37 virtual ~OnMoreDataResampler(); |
33 | 38 |
34 // AudioSourceCallback interface. | 39 // AudioSourceCallback interface. |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
88 scoped_ptr<ChannelMixer> channel_mixer_; | 93 scoped_ptr<ChannelMixer> channel_mixer_; |
89 scoped_ptr<AudioBus> unmixed_audio_; | 94 scoped_ptr<AudioBus> unmixed_audio_; |
90 | 95 |
91 int output_bytes_per_frame_; | 96 int output_bytes_per_frame_; |
92 int input_bytes_per_frame_; | 97 int input_bytes_per_frame_; |
93 | 98 |
94 // Since resampling is expensive, figure out if we should downmix channels | 99 // Since resampling is expensive, figure out if we should downmix channels |
95 // before resampling. | 100 // before resampling. |
96 bool downmix_early_; | 101 bool downmix_early_; |
97 | 102 |
98 DISALLOW_COPY_AND_ASSIGN(OnMoreDataResampler); | 103 // If we're using WaveOut on Windows' we always have to wait for DataReady() |
| 104 // before calling |source_callback_|. |
| 105 bool waveout_wait_hack_; |
| 106 |
| 107 DISALLOW_COPY_AND_ASSIGN(OnMoreDataConverter); |
99 }; | 108 }; |
100 | 109 |
101 // Record UMA statistics for hardware output configuration. | 110 // Record UMA statistics for hardware output configuration. |
102 static void RecordStats(const AudioParameters& output_params) { | 111 static void RecordStats(const AudioParameters& output_params) { |
103 UMA_HISTOGRAM_ENUMERATION( | 112 UMA_HISTOGRAM_ENUMERATION( |
104 "Media.HardwareAudioBitsPerChannel", output_params.bits_per_sample(), | 113 "Media.HardwareAudioBitsPerChannel", output_params.bits_per_sample(), |
105 limits::kMaxBitsPerSample); | 114 limits::kMaxBitsPerSample); |
106 UMA_HISTOGRAM_ENUMERATION( | 115 UMA_HISTOGRAM_ENUMERATION( |
107 "Media.HardwareAudioChannelLayout", output_params.channel_layout(), | 116 "Media.HardwareAudioChannelLayout", output_params.channel_layout(), |
108 CHANNEL_LAYOUT_MAX); | 117 CHANNEL_LAYOUT_MAX); |
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
330 } | 339 } |
331 | 340 |
332 OnMoreDataResampler::OnMoreDataResampler( | 341 OnMoreDataResampler::OnMoreDataResampler( |
333 double io_ratio, const AudioParameters& input_params, | 342 double io_ratio, const AudioParameters& input_params, |
334 const AudioParameters& output_params) | 343 const AudioParameters& output_params) |
335 : io_ratio_(io_ratio), | 344 : io_ratio_(io_ratio), |
336 source_callback_(NULL), | 345 source_callback_(NULL), |
337 outstanding_audio_bytes_(0), | 346 outstanding_audio_bytes_(0), |
338 output_bytes_per_frame_(output_params.GetBytesPerFrame()), | 347 output_bytes_per_frame_(output_params.GetBytesPerFrame()), |
339 input_bytes_per_frame_(input_params.GetBytesPerFrame()), | 348 input_bytes_per_frame_(input_params.GetBytesPerFrame()), |
340 downmix_early_(false) { | 349 downmix_early_(false), |
| 350 waveout_wait_hack_(false) { |
341 // Handle different input and output channel layouts. | 351 // Handle different input and output channel layouts. |
342 if (input_params.channel_layout() != output_params.channel_layout()) { | 352 if (input_params.channel_layout() != output_params.channel_layout()) { |
343 DVLOG(1) << "Remixing channel layout from " << input_params.channel_layout() | 353 DVLOG(1) << "Remixing channel layout from " << input_params.channel_layout() |
344 << " to " << output_params.channel_layout() << "; from " | 354 << " to " << output_params.channel_layout() << "; from " |
345 << input_params.channels() << " channels to " | 355 << input_params.channels() << " channels to " |
346 << output_params.channels() << " channels."; | 356 << output_params.channels() << " channels."; |
347 channel_mixer_.reset(new ChannelMixer( | 357 channel_mixer_.reset(new ChannelMixer( |
348 input_params.channel_layout(), output_params.channel_layout())); | 358 input_params.channel_layout(), output_params.channel_layout())); |
349 | 359 |
350 // Pare off data as early as we can for efficiency. | 360 // Pare off data as early as we can for efficiency. |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
384 input_params.frames_per_buffer() != output_params.frames_per_buffer()) { | 394 input_params.frames_per_buffer() != output_params.frames_per_buffer()) { |
385 DVLOG(1) << "Rebuffering from " << input_params.frames_per_buffer() | 395 DVLOG(1) << "Rebuffering from " << input_params.frames_per_buffer() |
386 << " to " << output_params.frames_per_buffer(); | 396 << " to " << output_params.frames_per_buffer(); |
387 audio_fifo_.reset(new AudioPullFifo( | 397 audio_fifo_.reset(new AudioPullFifo( |
388 downmix_early_ ? output_params.channels() : | 398 downmix_early_ ? output_params.channels() : |
389 input_params.channels(), | 399 input_params.channels(), |
390 input_params.frames_per_buffer(), base::Bind( | 400 input_params.frames_per_buffer(), base::Bind( |
391 &OnMoreDataResampler::SourceCallback_Locked, | 401 &OnMoreDataResampler::SourceCallback_Locked, |
392 base::Unretained(this)))); | 402 base::Unretained(this)))); |
393 } | 403 } |
| 404 |
| 405 // TODO(dalecurtis): We should require all render side clients to use a |
| 406 // buffer size that's a multiple of the hardware buffer size scaled by the |
| 407 // request_sample_rate / hw_sample_rate. Doing so ensures each hardware |
| 408 // request for audio data results in only a single render side callback and |
| 409 // would allow us to remove this hack. See http://crbug.com/162207. |
| 410 #if defined(OS_WIN) |
| 411 waveout_wait_hack_ = |
| 412 output_params.format() == AudioParameters::AUDIO_PCM_LINEAR || |
| 413 !CoreAudioUtil::IsSupported(); |
| 414 #endif |
394 } | 415 } |
395 | 416 |
396 OnMoreDataResampler::~OnMoreDataResampler() {} | 417 OnMoreDataResampler::~OnMoreDataResampler() {} |
397 | 418 |
398 void OnMoreDataResampler::Start( | 419 void OnMoreDataResampler::Start( |
399 AudioOutputStream::AudioSourceCallback* callback) { | 420 AudioOutputStream::AudioSourceCallback* callback) { |
400 base::AutoLock auto_lock(source_lock_); | 421 base::AutoLock auto_lock(source_lock_); |
401 DCHECK(!source_callback_); | 422 DCHECK(!source_callback_); |
402 source_callback_ = callback; | 423 source_callback_ = callback; |
403 } | 424 } |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
475 // Adjust playback delay to include the state of the internal buffers used by | 496 // Adjust playback delay to include the state of the internal buffers used by |
476 // the resampler and/or the FIFO. Since the sample rate and bits per channel | 497 // the resampler and/or the FIFO. Since the sample rate and bits per channel |
477 // may be different, we need to scale this value appropriately. | 498 // may be different, we need to scale this value appropriately. |
478 AudioBuffersState new_buffers_state; | 499 AudioBuffersState new_buffers_state; |
479 new_buffers_state.pending_bytes = io_ratio_ * | 500 new_buffers_state.pending_bytes = io_ratio_ * |
480 (current_buffers_state_.total_bytes() + outstanding_audio_bytes_); | 501 (current_buffers_state_.total_bytes() + outstanding_audio_bytes_); |
481 | 502 |
482 bool needs_downmix = channel_mixer_ && downmix_early_; | 503 bool needs_downmix = channel_mixer_ && downmix_early_; |
483 AudioBus* temp_dest = needs_downmix ? unmixed_audio_.get() : dest; | 504 AudioBus* temp_dest = needs_downmix ? unmixed_audio_.get() : dest; |
484 | 505 |
| 506 if (waveout_wait_hack_) |
| 507 source_callback_->WaitTillDataReady(); |
| 508 |
485 // Retrieve data from the original callback. Zero any unfilled frames. | 509 // Retrieve data from the original callback. Zero any unfilled frames. |
486 int frames = source_callback_->OnMoreIOData( | 510 int frames = source_callback_->OnMoreIOData( |
487 source, temp_dest, new_buffers_state); | 511 source, temp_dest, new_buffers_state); |
488 if (frames < temp_dest->frames()) | 512 if (frames < temp_dest->frames()) |
489 temp_dest->ZeroFramesPartial(frames, temp_dest->frames() - frames); | 513 temp_dest->ZeroFramesPartial(frames, temp_dest->frames() - frames); |
490 | 514 |
491 // Scale the number of frames we got back in terms of input bytes to output | 515 // Scale the number of frames we got back in terms of input bytes to output |
492 // bytes accordingly. | 516 // bytes accordingly. |
493 outstanding_audio_bytes_ += | 517 outstanding_audio_bytes_ += |
494 (temp_dest->frames() * input_bytes_per_frame_) / io_ratio_; | 518 (temp_dest->frames() * input_bytes_per_frame_) / io_ratio_; |
(...skipping 14 matching lines...) Expand all Loading... |
509 source_callback_->OnError(stream, code); | 533 source_callback_->OnError(stream, code); |
510 } | 534 } |
511 | 535 |
512 void OnMoreDataResampler::WaitTillDataReady() { | 536 void OnMoreDataResampler::WaitTillDataReady() { |
513 base::AutoLock auto_lock(source_lock_); | 537 base::AutoLock auto_lock(source_lock_); |
514 if (source_callback_ && !outstanding_audio_bytes_) | 538 if (source_callback_ && !outstanding_audio_bytes_) |
515 source_callback_->WaitTillDataReady(); | 539 source_callback_->WaitTillDataReady(); |
516 } | 540 } |
517 | 541 |
518 } // namespace media | 542 } // namespace media |
OLD | NEW |