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
3 // found in the LICENSE file.
5 #include "media/audio/audio_output_resampler.h"
8 #include "base/bind_helpers.h"
9 #include "base/compiler_specific.h"
10 #include "base/metrics/histogram.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/time/time.h"
13 #include "build/build_config.h"
14 #include "media/audio/audio_io.h"
15 #include "media/audio/audio_output_dispatcher_impl.h"
16 #include "media/audio/audio_output_proxy.h"
17 #include "media/audio/sample_rates.h"
18 #include "media/base/audio_converter.h"
19 #include "media/base/limits.h"
23 class OnMoreDataConverter
24 : public AudioOutputStream::AudioSourceCallback,
25 public AudioConverter::InputCallback {
27 OnMoreDataConverter(const AudioParameters& input_params,
28 const AudioParameters& output_params);
29 virtual ~OnMoreDataConverter();
31 // AudioSourceCallback interface.
32 virtual int OnMoreData(AudioBus* dest,
33 AudioBuffersState buffers_state) OVERRIDE;
34 virtual int OnMoreIOData(AudioBus* source,
36 AudioBuffersState buffers_state) OVERRIDE;
37 virtual void OnError(AudioOutputStream* stream) OVERRIDE;
39 // Sets |source_callback_|. If this is not a new object, then Stop() must be
40 // called before Start().
41 void Start(AudioOutputStream::AudioSourceCallback* callback);
43 // Clears |source_callback_| and flushes the resampler.
46 bool started() { return source_callback_ != NULL; }
49 // AudioConverter::InputCallback implementation.
50 virtual double ProvideInput(AudioBus* audio_bus,
51 base::TimeDelta buffer_delay) OVERRIDE;
53 // Ratio of input bytes to output bytes used to correct playback delay with
54 // regard to buffering and resampling.
55 const double io_ratio_;
58 AudioOutputStream::AudioSourceCallback* source_callback_;
60 // Last AudioBuffersState object received via OnMoreData(), used to correct
61 // playback delay by ProvideInput() and passed on to |source_callback_|.
62 AudioBuffersState current_buffers_state_;
64 const int input_bytes_per_second_;
66 // Handles resampling, buffering, and channel mixing between input and output
68 AudioConverter audio_converter_;
70 DISALLOW_COPY_AND_ASSIGN(OnMoreDataConverter);
73 // Record UMA statistics for hardware output configuration.
74 static void RecordStats(const AudioParameters& output_params) {
75 UMA_HISTOGRAM_ENUMERATION(
76 "Media.HardwareAudioBitsPerChannel", output_params.bits_per_sample(),
77 limits::kMaxBitsPerSample);
78 UMA_HISTOGRAM_ENUMERATION(
79 "Media.HardwareAudioChannelLayout", output_params.channel_layout(),
81 UMA_HISTOGRAM_ENUMERATION(
82 "Media.HardwareAudioChannelCount", output_params.channels(),
83 limits::kMaxChannels);
85 AudioSampleRate asr = media::AsAudioSampleRate(output_params.sample_rate());
86 if (asr != kUnexpectedAudioSampleRate) {
87 UMA_HISTOGRAM_ENUMERATION(
88 "Media.HardwareAudioSamplesPerSecond", asr, kUnexpectedAudioSampleRate);
91 "Media.HardwareAudioSamplesPerSecondUnexpected",
92 output_params.sample_rate());
96 // Record UMA statistics for hardware output configuration after fallback.
97 static void RecordFallbackStats(const AudioParameters& output_params) {
98 UMA_HISTOGRAM_BOOLEAN("Media.FallbackToHighLatencyAudioPath", true);
99 UMA_HISTOGRAM_ENUMERATION(
100 "Media.FallbackHardwareAudioBitsPerChannel",
101 output_params.bits_per_sample(), limits::kMaxBitsPerSample);
102 UMA_HISTOGRAM_ENUMERATION(
103 "Media.FallbackHardwareAudioChannelLayout",
104 output_params.channel_layout(), CHANNEL_LAYOUT_MAX);
105 UMA_HISTOGRAM_ENUMERATION(
106 "Media.FallbackHardwareAudioChannelCount",
107 output_params.channels(), limits::kMaxChannels);
109 AudioSampleRate asr = media::AsAudioSampleRate(output_params.sample_rate());
110 if (asr != kUnexpectedAudioSampleRate) {
111 UMA_HISTOGRAM_ENUMERATION(
112 "Media.FallbackHardwareAudioSamplesPerSecond",
113 asr, kUnexpectedAudioSampleRate);
115 UMA_HISTOGRAM_COUNTS(
116 "Media.FallbackHardwareAudioSamplesPerSecondUnexpected",
117 output_params.sample_rate());
121 // Converts low latency based |output_params| into high latency appropriate
122 // output parameters in error situations.
123 void AudioOutputResampler::SetupFallbackParams() {
124 // Only Windows has a high latency output driver that is not the same as the low
127 // Choose AudioParameters appropriate for opening the device in high latency
128 // mode. |kMinLowLatencyFrameSize| is arbitrarily based on Pepper Flash's
129 // MAXIMUM frame size for low latency.
130 static const int kMinLowLatencyFrameSize = 2048;
131 const int frames_per_buffer =
132 std::max(params_.frames_per_buffer(), kMinLowLatencyFrameSize);
134 output_params_ = AudioParameters(
135 AudioParameters::AUDIO_PCM_LINEAR, params_.channel_layout(),
136 params_.sample_rate(), params_.bits_per_sample(),
143 AudioOutputResampler::AudioOutputResampler(AudioManager* audio_manager,
144 const AudioParameters& input_params,
145 const AudioParameters& output_params,
146 const std::string& output_device_id,
147 const base::TimeDelta& close_delay)
148 : AudioOutputDispatcher(audio_manager, input_params, output_device_id),
149 close_delay_(close_delay),
150 output_params_(output_params),
151 streams_opened_(false) {
152 DCHECK(input_params.IsValid());
153 DCHECK(output_params.IsValid());
154 DCHECK_EQ(output_params_.format(), AudioParameters::AUDIO_PCM_LOW_LATENCY);
156 // Record UMA statistics for the hardware configuration.
157 RecordStats(output_params);
162 AudioOutputResampler::~AudioOutputResampler() {
163 DCHECK(callbacks_.empty());
166 void AudioOutputResampler::Initialize() {
167 DCHECK(!streams_opened_);
168 DCHECK(callbacks_.empty());
169 dispatcher_ = new AudioOutputDispatcherImpl(
170 audio_manager_, output_params_, device_id_, close_delay_);
173 bool AudioOutputResampler::OpenStream() {
174 DCHECK(task_runner_->BelongsToCurrentThread());
176 if (dispatcher_->OpenStream()) {
177 // Only record the UMA statistic if we didn't fallback during construction
178 // and only for the first stream we open.
179 if (!streams_opened_ &&
180 output_params_.format() == AudioParameters::AUDIO_PCM_LOW_LATENCY) {
181 UMA_HISTOGRAM_BOOLEAN("Media.FallbackToHighLatencyAudioPath", false);
183 streams_opened_ = true;
187 // If we've already tried to open the stream in high latency mode or we've
188 // successfully opened a stream previously, there's nothing more to be done.
189 if (output_params_.format() != AudioParameters::AUDIO_PCM_LOW_LATENCY ||
190 streams_opened_ || !callbacks_.empty()) {
194 DCHECK_EQ(output_params_.format(), AudioParameters::AUDIO_PCM_LOW_LATENCY);
196 // Record UMA statistics about the hardware which triggered the failure so
197 // we can debug and triage later.
198 RecordFallbackStats(output_params_);
200 // Only Windows has a high latency output driver that is not the same as the
203 DLOG(ERROR) << "Unable to open audio device in low latency mode. Falling "
204 << "back to high latency audio output.";
206 SetupFallbackParams();
207 if (dispatcher_->OpenStream()) {
208 streams_opened_ = true;
213 DLOG(ERROR) << "Unable to open audio device in high latency mode. Falling "
214 << "back to fake audio output.";
216 // Finally fall back to a fake audio output device.
217 output_params_.Reset(
218 AudioParameters::AUDIO_FAKE, params_.channel_layout(),
219 params_.channels(), params_.input_channels(), params_.sample_rate(),
220 params_.bits_per_sample(), params_.frames_per_buffer());
222 if (dispatcher_->OpenStream()) {
223 streams_opened_ = true;
230 bool AudioOutputResampler::StartStream(
231 AudioOutputStream::AudioSourceCallback* callback,
232 AudioOutputProxy* stream_proxy) {
233 DCHECK(task_runner_->BelongsToCurrentThread());
235 OnMoreDataConverter* resampler_callback = NULL;
236 CallbackMap::iterator it = callbacks_.find(stream_proxy);
237 if (it == callbacks_.end()) {
238 resampler_callback = new OnMoreDataConverter(params_, output_params_);
239 callbacks_[stream_proxy] = resampler_callback;
241 resampler_callback = it->second;
244 resampler_callback->Start(callback);
245 bool result = dispatcher_->StartStream(resampler_callback, stream_proxy);
247 resampler_callback->Stop();
251 void AudioOutputResampler::StreamVolumeSet(AudioOutputProxy* stream_proxy,
253 DCHECK(task_runner_->BelongsToCurrentThread());
254 dispatcher_->StreamVolumeSet(stream_proxy, volume);
257 void AudioOutputResampler::StopStream(AudioOutputProxy* stream_proxy) {
258 DCHECK(task_runner_->BelongsToCurrentThread());
259 dispatcher_->StopStream(stream_proxy);
261 // Now that StopStream() has completed the underlying physical stream should
262 // be stopped and no longer calling OnMoreData(), making it safe to Stop() the
263 // OnMoreDataConverter.
264 CallbackMap::iterator it = callbacks_.find(stream_proxy);
265 if (it != callbacks_.end())
269 void AudioOutputResampler::CloseStream(AudioOutputProxy* stream_proxy) {
270 DCHECK(task_runner_->BelongsToCurrentThread());
271 dispatcher_->CloseStream(stream_proxy);
273 // We assume that StopStream() is always called prior to CloseStream(), so
274 // that it is safe to delete the OnMoreDataConverter here.
275 CallbackMap::iterator it = callbacks_.find(stream_proxy);
276 if (it != callbacks_.end()) {
278 callbacks_.erase(it);
282 void AudioOutputResampler::Shutdown() {
283 DCHECK(task_runner_->BelongsToCurrentThread());
285 // No AudioOutputProxy objects should hold a reference to us when we get
287 DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference";
289 dispatcher_->Shutdown();
290 DCHECK(callbacks_.empty());
293 void AudioOutputResampler::CloseStreamsForWedgeFix() {
294 DCHECK(task_runner_->BelongsToCurrentThread());
296 // Stop and close all active streams. Once all streams across all dispatchers
297 // have been closed the AudioManager will call RestartStreamsForWedgeFix().
298 for (CallbackMap::iterator it = callbacks_.begin(); it != callbacks_.end();
300 if (it->second->started())
301 dispatcher_->StopStream(it->first);
302 dispatcher_->CloseStream(it->first);
305 // Close all idle streams as well.
306 dispatcher_->CloseStreamsForWedgeFix();
309 void AudioOutputResampler::RestartStreamsForWedgeFix() {
310 DCHECK(task_runner_->BelongsToCurrentThread());
311 // By opening all streams first and then starting them one by one we ensure
312 // the dispatcher only opens streams for those which will actually be used.
313 for (CallbackMap::iterator it = callbacks_.begin(); it != callbacks_.end();
315 dispatcher_->OpenStream();
317 for (CallbackMap::iterator it = callbacks_.begin(); it != callbacks_.end();
319 if (it->second->started())
320 dispatcher_->StartStream(it->second, it->first);
324 OnMoreDataConverter::OnMoreDataConverter(const AudioParameters& input_params,
325 const AudioParameters& output_params)
326 : io_ratio_(static_cast<double>(input_params.GetBytesPerSecond()) /
327 output_params.GetBytesPerSecond()),
328 source_callback_(NULL),
329 input_bytes_per_second_(input_params.GetBytesPerSecond()),
330 audio_converter_(input_params, output_params, false) {}
332 OnMoreDataConverter::~OnMoreDataConverter() {
333 // Ensure Stop() has been called so we don't end up with an AudioOutputStream
334 // calling back into OnMoreData() after destruction.
335 CHECK(!source_callback_);
338 void OnMoreDataConverter::Start(
339 AudioOutputStream::AudioSourceCallback* callback) {
340 CHECK(!source_callback_);
341 source_callback_ = callback;
343 // While AudioConverter can handle multiple inputs, we're using it only with
344 // a single input currently. Eventually this may be the basis for a browser
346 audio_converter_.AddInput(this);
349 void OnMoreDataConverter::Stop() {
350 CHECK(source_callback_);
351 source_callback_ = NULL;
352 audio_converter_.RemoveInput(this);
355 int OnMoreDataConverter::OnMoreData(AudioBus* dest,
356 AudioBuffersState buffers_state) {
357 return OnMoreIOData(NULL, dest, buffers_state);
360 int OnMoreDataConverter::OnMoreIOData(AudioBus* source,
362 AudioBuffersState buffers_state) {
363 // Note: The input portion of OnMoreIOData() is not supported when a converter
364 // has been injected. Downstream clients prefer silence to potentially split
367 current_buffers_state_ = buffers_state;
368 audio_converter_.Convert(dest);
370 // Always return the full number of frames requested, ProvideInput()
371 // will pad with silence if it wasn't able to acquire enough data.
372 return dest->frames();
375 double OnMoreDataConverter::ProvideInput(AudioBus* dest,
376 base::TimeDelta buffer_delay) {
377 // Adjust playback delay to include |buffer_delay|.
378 // TODO(dalecurtis): Stop passing bytes around, it doesn't make sense since
379 // AudioBus is just float data. Use TimeDelta instead.
380 AudioBuffersState new_buffers_state;
381 new_buffers_state.pending_bytes =
382 io_ratio_ * (current_buffers_state_.total_bytes() +
383 buffer_delay.InSecondsF() * input_bytes_per_second_);
385 // Retrieve data from the original callback.
386 const int frames = source_callback_->OnMoreIOData(
387 NULL, dest, new_buffers_state);
389 // Zero any unfilled frames if anything was filled, otherwise we'll just
390 // return a volume of zero and let AudioConverter drop the output.
391 if (frames > 0 && frames < dest->frames())
392 dest->ZeroFramesPartial(frames, dest->frames() - frames);
393 return frames > 0 ? 1 : 0;
396 void OnMoreDataConverter::OnError(AudioOutputStream* stream) {
397 source_callback_->OnError(stream);