Home | History | Annotate | Download | only in base
      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 // AudioConverter implementation.  Uses MultiChannelSincResampler for resampling
      6 // audio, ChannelMixer for channel mixing, and AudioPullFifo for buffering.
      7 //
      8 // Delay estimates are provided to InputCallbacks based on the frame delay
      9 // information reported via the resampler and FIFO units.
     10 
     11 #include "media/base/audio_converter.h"
     12 
     13 #include <algorithm>
     14 
     15 #include "base/bind.h"
     16 #include "base/bind_helpers.h"
     17 #include "media/base/audio_bus.h"
     18 #include "media/base/audio_pull_fifo.h"
     19 #include "media/base/channel_mixer.h"
     20 #include "media/base/multi_channel_resampler.h"
     21 #include "media/base/vector_math.h"
     22 
     23 namespace media {
     24 
     25 AudioConverter::AudioConverter(const AudioParameters& input_params,
     26                                const AudioParameters& output_params,
     27                                bool disable_fifo)
     28     : downmix_early_(false),
     29       resampler_frame_delay_(0),
     30       input_channel_count_(input_params.channels()) {
     31   CHECK(input_params.IsValid());
     32   CHECK(output_params.IsValid());
     33 
     34   // Handle different input and output channel layouts.
     35   if (input_params.channel_layout() != output_params.channel_layout()) {
     36     DVLOG(1) << "Remixing channel layout from " << input_params.channel_layout()
     37              << " to " << output_params.channel_layout() << "; from "
     38              << input_params.channels() << " channels to "
     39              << output_params.channels() << " channels.";
     40     channel_mixer_.reset(new ChannelMixer(input_params, output_params));
     41 
     42     // Pare off data as early as we can for efficiency.
     43     downmix_early_ = input_params.channels() > output_params.channels();
     44     if (downmix_early_) {
     45       DVLOG(1) << "Remixing channel layout prior to resampling.";
     46       // |unmixed_audio_| will be allocated on the fly.
     47     } else {
     48       // Instead, if we're not downmixing early we need a temporary AudioBus
     49       // which matches the input channel count but uses the output frame size
     50       // since we'll mix into the AudioBus from the output stream.
     51       unmixed_audio_ = AudioBus::Create(
     52           input_params.channels(), output_params.frames_per_buffer());
     53     }
     54   }
     55 
     56   // Only resample if necessary since it's expensive.
     57   if (input_params.sample_rate() != output_params.sample_rate()) {
     58     DVLOG(1) << "Resampling from " << input_params.sample_rate() << " to "
     59              << output_params.sample_rate();
     60     const double io_sample_rate_ratio = input_params.sample_rate() /
     61         static_cast<double>(output_params.sample_rate());
     62     const int request_size = disable_fifo ? SincResampler::kDefaultRequestSize :
     63         input_params.frames_per_buffer();
     64     resampler_.reset(new MultiChannelResampler(
     65         downmix_early_ ? output_params.channels() :
     66             input_params.channels(),
     67         io_sample_rate_ratio, request_size, base::Bind(
     68             &AudioConverter::ProvideInput, base::Unretained(this))));
     69   }
     70 
     71   input_frame_duration_ = base::TimeDelta::FromMicroseconds(
     72       base::Time::kMicrosecondsPerSecond /
     73       static_cast<double>(input_params.sample_rate()));
     74   output_frame_duration_ = base::TimeDelta::FromMicroseconds(
     75       base::Time::kMicrosecondsPerSecond /
     76       static_cast<double>(output_params.sample_rate()));
     77 
     78   // The resampler can be configured to work with a specific request size, so a
     79   // FIFO is not necessary when resampling.
     80   if (disable_fifo || resampler_)
     81     return;
     82 
     83   // Since the output device may want a different buffer size than the caller
     84   // asked for, we need to use a FIFO to ensure that both sides read in chunk
     85   // sizes they're configured for.
     86   if (input_params.frames_per_buffer() != output_params.frames_per_buffer()) {
     87     DVLOG(1) << "Rebuffering from " << input_params.frames_per_buffer()
     88              << " to " << output_params.frames_per_buffer();
     89     audio_fifo_.reset(new AudioPullFifo(
     90         downmix_early_ ? output_params.channels() :
     91             input_params.channels(),
     92         input_params.frames_per_buffer(), base::Bind(
     93             &AudioConverter::SourceCallback,
     94             base::Unretained(this))));
     95   }
     96 }
     97 
     98 AudioConverter::~AudioConverter() {}
     99 
    100 void AudioConverter::AddInput(InputCallback* input) {
    101   // TODO(dalecurtis): Speculative CHECK for http://crbug.com/233026, should be
    102   // converted to a DCHECK once resolved.
    103   CHECK(std::find(transform_inputs_.begin(), transform_inputs_.end(), input) ==
    104         transform_inputs_.end());
    105   transform_inputs_.push_back(input);
    106 }
    107 
    108 void AudioConverter::RemoveInput(InputCallback* input) {
    109   DCHECK(std::find(transform_inputs_.begin(), transform_inputs_.end(), input) !=
    110          transform_inputs_.end());
    111   transform_inputs_.remove(input);
    112 
    113   if (transform_inputs_.empty())
    114     Reset();
    115 }
    116 
    117 void AudioConverter::Reset() {
    118   if (audio_fifo_)
    119     audio_fifo_->Clear();
    120   if (resampler_)
    121     resampler_->Flush();
    122 }
    123 
    124 void AudioConverter::ConvertWithDelay(const base::TimeDelta& initial_delay,
    125                                       AudioBus* dest) {
    126   initial_delay_ = initial_delay;
    127 
    128   if (transform_inputs_.empty()) {
    129     dest->Zero();
    130     return;
    131   }
    132 
    133   // Determine if channel mixing should be done and if it should be done before
    134   // or after resampling.  If it's possible to reduce the channel count prior to
    135   // resampling we can save a lot of processing time.  Vice versa, we don't want
    136   // to increase the channel count prior to resampling for the same reason.
    137   bool needs_mixing = channel_mixer_ && !downmix_early_;
    138   AudioBus* temp_dest = needs_mixing ? unmixed_audio_.get() : dest;
    139   DCHECK(temp_dest);
    140 
    141   // Figure out which method to call based on whether we're resampling and
    142   // rebuffering, just resampling, or just mixing.  We want to avoid any extra
    143   // steps when possible since we may be converting audio data in real time.
    144   if (!resampler_ && !audio_fifo_) {
    145     SourceCallback(0, temp_dest);
    146   } else {
    147     if (resampler_)
    148       resampler_->Resample(temp_dest->frames(), temp_dest);
    149     else
    150       ProvideInput(0, temp_dest);
    151   }
    152 
    153   // Finally upmix the channels if we didn't do so earlier.
    154   if (needs_mixing) {
    155     DCHECK_EQ(temp_dest->frames(), dest->frames());
    156     channel_mixer_->Transform(temp_dest, dest);
    157   }
    158 }
    159 
    160 void AudioConverter::Convert(AudioBus* dest) {
    161   ConvertWithDelay(base::TimeDelta::FromMilliseconds(0), dest);
    162 }
    163 
    164 void AudioConverter::SourceCallback(int fifo_frame_delay, AudioBus* dest) {
    165   bool needs_downmix = channel_mixer_ && downmix_early_;
    166 
    167   if (!mixer_input_audio_bus_ ||
    168       mixer_input_audio_bus_->frames() != dest->frames()) {
    169     mixer_input_audio_bus_ =
    170         AudioBus::Create(input_channel_count_, dest->frames());
    171   }
    172 
    173   if (needs_downmix &&
    174       (!unmixed_audio_ || unmixed_audio_->frames() != dest->frames())) {
    175     // If we're downmixing early we need a temporary AudioBus which matches
    176     // the the input channel count and input frame size since we're passing
    177     // |unmixed_audio_| directly to the |source_callback_|.
    178     unmixed_audio_ = AudioBus::Create(input_channel_count_, dest->frames());
    179   }
    180 
    181   AudioBus* temp_dest = needs_downmix ? unmixed_audio_.get() : dest;
    182 
    183   // Sanity check our inputs.
    184   DCHECK_EQ(temp_dest->frames(), mixer_input_audio_bus_->frames());
    185   DCHECK_EQ(temp_dest->channels(), mixer_input_audio_bus_->channels());
    186 
    187   // Calculate the buffer delay for this callback.
    188   base::TimeDelta buffer_delay = initial_delay_;
    189   if (resampler_) {
    190     buffer_delay += base::TimeDelta::FromMicroseconds(
    191         resampler_frame_delay_ * output_frame_duration_.InMicroseconds());
    192   }
    193   if (audio_fifo_) {
    194     buffer_delay += base::TimeDelta::FromMicroseconds(
    195         fifo_frame_delay * input_frame_duration_.InMicroseconds());
    196   }
    197 
    198   // Have each mixer render its data into an output buffer then mix the result.
    199   for (InputCallbackSet::iterator it = transform_inputs_.begin();
    200        it != transform_inputs_.end(); ++it) {
    201     InputCallback* input = *it;
    202 
    203     float volume = input->ProvideInput(
    204         mixer_input_audio_bus_.get(), buffer_delay);
    205 
    206     // Optimize the most common single input, full volume case.
    207     if (it == transform_inputs_.begin()) {
    208       if (volume == 1.0f) {
    209         mixer_input_audio_bus_->CopyTo(temp_dest);
    210       } else if (volume > 0) {
    211         for (int i = 0; i < mixer_input_audio_bus_->channels(); ++i) {
    212           vector_math::FMUL(
    213               mixer_input_audio_bus_->channel(i), volume,
    214               mixer_input_audio_bus_->frames(), temp_dest->channel(i));
    215         }
    216       } else {
    217         // Zero |temp_dest| otherwise, so we're mixing into a clean buffer.
    218         temp_dest->Zero();
    219       }
    220 
    221       continue;
    222     }
    223 
    224     // Volume adjust and mix each mixer input into |temp_dest| after rendering.
    225     if (volume > 0) {
    226       for (int i = 0; i < mixer_input_audio_bus_->channels(); ++i) {
    227         vector_math::FMAC(
    228             mixer_input_audio_bus_->channel(i), volume,
    229             mixer_input_audio_bus_->frames(), temp_dest->channel(i));
    230       }
    231     }
    232   }
    233 
    234   if (needs_downmix) {
    235     DCHECK_EQ(temp_dest->frames(), dest->frames());
    236     channel_mixer_->Transform(temp_dest, dest);
    237   }
    238 }
    239 
    240 void AudioConverter::ProvideInput(int resampler_frame_delay, AudioBus* dest) {
    241   resampler_frame_delay_ = resampler_frame_delay;
    242   if (audio_fifo_)
    243     audio_fifo_->Consume(dest, dest->frames());
    244   else
    245     SourceCallback(0, dest);
    246 }
    247 
    248 }  // namespace media
    249