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