| 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 |