audio_output_resampler.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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.
4
5#include "media/audio/audio_output_resampler.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/compiler_specific.h"
10#include "base/message_loop.h"
11#include "base/metrics/histogram.h"
12#include "base/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/audio_util.h"
18#include "media/audio/sample_rates.h"
19#include "media/base/audio_converter.h"
20#include "media/base/limits.h"
21
22namespace media {
23
24class OnMoreDataConverter
25    : public AudioOutputStream::AudioSourceCallback,
26      public AudioConverter::InputCallback {
27 public:
28  OnMoreDataConverter(const AudioParameters& input_params,
29                      const AudioParameters& output_params);
30  virtual ~OnMoreDataConverter();
31
32  // AudioSourceCallback interface.
33  virtual int OnMoreData(AudioBus* dest,
34                         AudioBuffersState buffers_state) OVERRIDE;
35  virtual int OnMoreIOData(AudioBus* source,
36                           AudioBus* dest,
37                           AudioBuffersState buffers_state) OVERRIDE;
38  virtual void OnError(AudioOutputStream* stream) OVERRIDE;
39  virtual void WaitTillDataReady() OVERRIDE;
40
41  // Sets |source_callback_|.  If this is not a new object, then Stop() must be
42  // called before Start().
43  void Start(AudioOutputStream::AudioSourceCallback* callback);
44
45  // Clears |source_callback_| and flushes the resampler.
46  void Stop();
47
48 private:
49  // AudioConverter::InputCallback implementation.
50  virtual double ProvideInput(AudioBus* audio_bus,
51                              base::TimeDelta buffer_delay) OVERRIDE;
52
53  // Ratio of input bytes to output bytes used to correct playback delay with
54  // regard to buffering and resampling.
55  double io_ratio_;
56
57  // Source callback and associated lock.
58  base::Lock source_lock_;
59  AudioOutputStream::AudioSourceCallback* source_callback_;
60
61  // |source| passed to OnMoreIOData() which should be passed downstream.
62  AudioBus* source_bus_;
63
64  // Last AudioBuffersState object received via OnMoreData(), used to correct
65  // playback delay by ProvideInput() and passed on to |source_callback_|.
66  AudioBuffersState current_buffers_state_;
67
68  const int input_bytes_per_second_;
69
70  // Handles resampling, buffering, and channel mixing between input and output
71  // parameters.
72  AudioConverter audio_converter_;
73
74  DISALLOW_COPY_AND_ASSIGN(OnMoreDataConverter);
75};
76
77// Record UMA statistics for hardware output configuration.
78static void RecordStats(const AudioParameters& output_params) {
79  UMA_HISTOGRAM_ENUMERATION(
80      "Media.HardwareAudioBitsPerChannel", output_params.bits_per_sample(),
81      limits::kMaxBitsPerSample);
82  UMA_HISTOGRAM_ENUMERATION(
83      "Media.HardwareAudioChannelLayout", output_params.channel_layout(),
84      CHANNEL_LAYOUT_MAX);
85  UMA_HISTOGRAM_ENUMERATION(
86      "Media.HardwareAudioChannelCount", output_params.channels(),
87      limits::kMaxChannels);
88
89  AudioSampleRate asr = media::AsAudioSampleRate(output_params.sample_rate());
90  if (asr != kUnexpectedAudioSampleRate) {
91    UMA_HISTOGRAM_ENUMERATION(
92        "Media.HardwareAudioSamplesPerSecond", asr, kUnexpectedAudioSampleRate);
93  } else {
94    UMA_HISTOGRAM_COUNTS(
95        "Media.HardwareAudioSamplesPerSecondUnexpected",
96        output_params.sample_rate());
97  }
98}
99
100// Record UMA statistics for hardware output configuration after fallback.
101static void RecordFallbackStats(const AudioParameters& output_params) {
102  UMA_HISTOGRAM_BOOLEAN("Media.FallbackToHighLatencyAudioPath", true);
103  UMA_HISTOGRAM_ENUMERATION(
104      "Media.FallbackHardwareAudioBitsPerChannel",
105      output_params.bits_per_sample(), limits::kMaxBitsPerSample);
106  UMA_HISTOGRAM_ENUMERATION(
107      "Media.FallbackHardwareAudioChannelLayout",
108      output_params.channel_layout(), CHANNEL_LAYOUT_MAX);
109  UMA_HISTOGRAM_ENUMERATION(
110      "Media.FallbackHardwareAudioChannelCount",
111      output_params.channels(), limits::kMaxChannels);
112
113  AudioSampleRate asr = media::AsAudioSampleRate(output_params.sample_rate());
114  if (asr != kUnexpectedAudioSampleRate) {
115    UMA_HISTOGRAM_ENUMERATION(
116        "Media.FallbackHardwareAudioSamplesPerSecond",
117        asr, kUnexpectedAudioSampleRate);
118  } else {
119    UMA_HISTOGRAM_COUNTS(
120        "Media.FallbackHardwareAudioSamplesPerSecondUnexpected",
121        output_params.sample_rate());
122  }
123}
124
125// Only Windows has a high latency output driver that is not the same as the low
126// latency path.
127#if defined(OS_WIN)
128// Converts low latency based |output_params| into high latency appropriate
129// output parameters in error situations.
130static AudioParameters SetupFallbackParams(
131    const AudioParameters& input_params, const AudioParameters& output_params) {
132  // Choose AudioParameters appropriate for opening the device in high latency
133  // mode.  |kMinLowLatencyFrameSize| is arbitrarily based on Pepper Flash's
134  // MAXIMUM frame size for low latency.
135  static const int kMinLowLatencyFrameSize = 2048;
136  int frames_per_buffer = std::min(
137      std::max(input_params.frames_per_buffer(), kMinLowLatencyFrameSize),
138      static_cast<int>(
139          GetHighLatencyOutputBufferSize(input_params.sample_rate())));
140
141  return AudioParameters(
142      AudioParameters::AUDIO_PCM_LINEAR, input_params.channel_layout(),
143      input_params.sample_rate(), input_params.bits_per_sample(),
144      frames_per_buffer);
145}
146#endif
147
148AudioOutputResampler::AudioOutputResampler(AudioManager* audio_manager,
149                                           const AudioParameters& input_params,
150                                           const AudioParameters& output_params,
151                                           const base::TimeDelta& close_delay)
152    : AudioOutputDispatcher(audio_manager, input_params),
153      close_delay_(close_delay),
154      output_params_(output_params),
155      streams_opened_(false) {
156  DCHECK(input_params.IsValid());
157  DCHECK(output_params.IsValid());
158  DCHECK_EQ(output_params_.format(), AudioParameters::AUDIO_PCM_LOW_LATENCY);
159
160  // Record UMA statistics for the hardware configuration.
161  RecordStats(output_params);
162
163  Initialize();
164}
165
166AudioOutputResampler::~AudioOutputResampler() {
167  DCHECK(callbacks_.empty());
168}
169
170void AudioOutputResampler::Initialize() {
171  DCHECK(!streams_opened_);
172  DCHECK(callbacks_.empty());
173  dispatcher_ = new AudioOutputDispatcherImpl(
174      audio_manager_, output_params_, close_delay_);
175}
176
177bool AudioOutputResampler::OpenStream() {
178  DCHECK_EQ(base::MessageLoop::current(), message_loop_);
179
180  if (dispatcher_->OpenStream()) {
181    // Only record the UMA statistic if we didn't fallback during construction
182    // and only for the first stream we open.
183    if (!streams_opened_ &&
184        output_params_.format() == AudioParameters::AUDIO_PCM_LOW_LATENCY) {
185      UMA_HISTOGRAM_BOOLEAN("Media.FallbackToHighLatencyAudioPath", false);
186    }
187    streams_opened_ = true;
188    return true;
189  }
190
191  // If we've already tried to open the stream in high latency mode or we've
192  // successfully opened a stream previously, there's nothing more to be done.
193  if (output_params_.format() != AudioParameters::AUDIO_PCM_LOW_LATENCY ||
194      streams_opened_ || !callbacks_.empty()) {
195    return false;
196  }
197
198  DCHECK_EQ(output_params_.format(), AudioParameters::AUDIO_PCM_LOW_LATENCY);
199
200  // Record UMA statistics about the hardware which triggered the failure so
201  // we can debug and triage later.
202  RecordFallbackStats(output_params_);
203
204  // Only Windows has a high latency output driver that is not the same as the
205  // low latency path.
206#if defined(OS_WIN)
207  DLOG(ERROR) << "Unable to open audio device in low latency mode.  Falling "
208              << "back to high latency audio output.";
209
210  output_params_ = SetupFallbackParams(params_, output_params_);
211  Initialize();
212  if (dispatcher_->OpenStream()) {
213    streams_opened_ = true;
214    return true;
215  }
216#endif
217
218  DLOG(ERROR) << "Unable to open audio device in high latency mode.  Falling "
219              << "back to fake audio output.";
220
221  // Finally fall back to a fake audio output device.
222  output_params_.Reset(
223      AudioParameters::AUDIO_FAKE, params_.channel_layout(),
224      params_.channels(), params_.input_channels(), params_.sample_rate(),
225      params_.bits_per_sample(), params_.frames_per_buffer());
226  Initialize();
227  if (dispatcher_->OpenStream()) {
228    streams_opened_ = true;
229    return true;
230  }
231
232  return false;
233}
234
235bool AudioOutputResampler::StartStream(
236    AudioOutputStream::AudioSourceCallback* callback,
237    AudioOutputProxy* stream_proxy) {
238  DCHECK_EQ(base::MessageLoop::current(), message_loop_);
239
240  OnMoreDataConverter* resampler_callback = NULL;
241  CallbackMap::iterator it = callbacks_.find(stream_proxy);
242  if (it == callbacks_.end()) {
243    resampler_callback = new OnMoreDataConverter(params_, output_params_);
244    callbacks_[stream_proxy] = resampler_callback;
245  } else {
246    resampler_callback = it->second;
247  }
248
249  resampler_callback->Start(callback);
250  bool result = dispatcher_->StartStream(resampler_callback, stream_proxy);
251  if (!result)
252    resampler_callback->Stop();
253  return result;
254}
255
256void AudioOutputResampler::StreamVolumeSet(AudioOutputProxy* stream_proxy,
257                                           double volume) {
258  DCHECK_EQ(base::MessageLoop::current(), message_loop_);
259  dispatcher_->StreamVolumeSet(stream_proxy, volume);
260}
261
262void AudioOutputResampler::StopStream(AudioOutputProxy* stream_proxy) {
263  DCHECK_EQ(base::MessageLoop::current(), message_loop_);
264  dispatcher_->StopStream(stream_proxy);
265
266  // Now that StopStream() has completed the underlying physical stream should
267  // be stopped and no longer calling OnMoreData(), making it safe to Stop() the
268  // OnMoreDataConverter.
269  CallbackMap::iterator it = callbacks_.find(stream_proxy);
270  if (it != callbacks_.end())
271    it->second->Stop();
272}
273
274void AudioOutputResampler::CloseStream(AudioOutputProxy* stream_proxy) {
275  DCHECK_EQ(base::MessageLoop::current(), message_loop_);
276  dispatcher_->CloseStream(stream_proxy);
277
278  // We assume that StopStream() is always called prior to CloseStream(), so
279  // that it is safe to delete the OnMoreDataConverter here.
280  CallbackMap::iterator it = callbacks_.find(stream_proxy);
281  if (it != callbacks_.end()) {
282    delete it->second;
283    callbacks_.erase(it);
284  }
285}
286
287void AudioOutputResampler::Shutdown() {
288  DCHECK_EQ(base::MessageLoop::current(), message_loop_);
289
290  // No AudioOutputProxy objects should hold a reference to us when we get
291  // to this stage.
292  DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference";
293
294  dispatcher_->Shutdown();
295  DCHECK(callbacks_.empty());
296}
297
298OnMoreDataConverter::OnMoreDataConverter(const AudioParameters& input_params,
299                                         const AudioParameters& output_params)
300    : source_callback_(NULL),
301      source_bus_(NULL),
302      input_bytes_per_second_(input_params.GetBytesPerSecond()),
303      audio_converter_(input_params, output_params, false) {
304  io_ratio_ =
305      static_cast<double>(input_params.GetBytesPerSecond()) /
306      output_params.GetBytesPerSecond();
307}
308
309OnMoreDataConverter::~OnMoreDataConverter() {
310  // Ensure Stop() has been called so we don't end up with an AudioOutputStream
311  // calling back into OnMoreData() after destruction.
312  CHECK(!source_callback_);
313}
314
315void OnMoreDataConverter::Start(
316    AudioOutputStream::AudioSourceCallback* callback) {
317  base::AutoLock auto_lock(source_lock_);
318  CHECK(!source_callback_);
319  source_callback_ = callback;
320
321  // While AudioConverter can handle multiple inputs, we're using it only with
322  // a single input currently.  Eventually this may be the basis for a browser
323  // side mixer.
324  audio_converter_.AddInput(this);
325}
326
327void OnMoreDataConverter::Stop() {
328  base::AutoLock auto_lock(source_lock_);
329  CHECK(source_callback_);
330  source_callback_ = NULL;
331  audio_converter_.RemoveInput(this);
332}
333
334int OnMoreDataConverter::OnMoreData(AudioBus* dest,
335                                    AudioBuffersState buffers_state) {
336  return OnMoreIOData(NULL, dest, buffers_state);
337}
338
339int OnMoreDataConverter::OnMoreIOData(AudioBus* source,
340                                      AudioBus* dest,
341                                      AudioBuffersState buffers_state) {
342  base::AutoLock auto_lock(source_lock_);
343  // While we waited for |source_lock_| the callback might have been cleared.
344  if (!source_callback_) {
345    dest->Zero();
346    return dest->frames();
347  }
348
349  source_bus_ = source;
350  current_buffers_state_ = buffers_state;
351  audio_converter_.Convert(dest);
352
353  // Always return the full number of frames requested, ProvideInput_Locked()
354  // will pad with silence if it wasn't able to acquire enough data.
355  return dest->frames();
356}
357
358double OnMoreDataConverter::ProvideInput(AudioBus* dest,
359                                         base::TimeDelta buffer_delay) {
360  source_lock_.AssertAcquired();
361
362  // Adjust playback delay to include |buffer_delay|.
363  // TODO(dalecurtis): Stop passing bytes around, it doesn't make sense since
364  // AudioBus is just float data.  Use TimeDelta instead.
365  AudioBuffersState new_buffers_state;
366  new_buffers_state.pending_bytes =
367      io_ratio_ * (current_buffers_state_.total_bytes() +
368                   buffer_delay.InSecondsF() * input_bytes_per_second_);
369
370  // Retrieve data from the original callback.
371  int frames = source_callback_->OnMoreIOData(
372      source_bus_, dest, new_buffers_state);
373
374  // |source_bus_| should only be provided once.
375  // TODO(dalecurtis, crogers): This is not a complete fix.  If ProvideInput()
376  // is called multiple times, we need to do something more clever here.
377  source_bus_ = NULL;
378
379  // Zero any unfilled frames if anything was filled, otherwise we'll just
380  // return a volume of zero and let AudioConverter drop the output.
381  if (frames > 0 && frames < dest->frames())
382    dest->ZeroFramesPartial(frames, dest->frames() - frames);
383
384  // TODO(dalecurtis): Return the correct volume here.
385  return frames > 0 ? 1 : 0;
386}
387
388void OnMoreDataConverter::OnError(AudioOutputStream* stream) {
389  base::AutoLock auto_lock(source_lock_);
390  if (source_callback_)
391    source_callback_->OnError(stream);
392}
393
394void OnMoreDataConverter::WaitTillDataReady() {
395  base::AutoLock auto_lock(source_lock_);
396  if (source_callback_)
397    source_callback_->WaitTillDataReady();
398}
399
400}  // namespace media
401