Home | History | Annotate | Download | only in alsa
      1 // Copyright 2013 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/alsa/alsa_input.h"
      6 
      7 #include "base/basictypes.h"
      8 #include "base/bind.h"
      9 #include "base/logging.h"
     10 #include "base/message_loop/message_loop.h"
     11 #include "base/time/time.h"
     12 #include "media/audio/alsa/alsa_output.h"
     13 #include "media/audio/alsa/alsa_util.h"
     14 #include "media/audio/alsa/alsa_wrapper.h"
     15 #include "media/audio/alsa/audio_manager_alsa.h"
     16 #include "media/audio/audio_manager.h"
     17 
     18 namespace media {
     19 
     20 static const int kNumPacketsInRingBuffer = 3;
     21 
     22 static const char kDefaultDevice1[] = "default";
     23 static const char kDefaultDevice2[] = "plug:default";
     24 
     25 const char AlsaPcmInputStream::kAutoSelectDevice[] = "";
     26 
     27 AlsaPcmInputStream::AlsaPcmInputStream(AudioManagerBase* audio_manager,
     28                                        const std::string& device_name,
     29                                        const AudioParameters& params,
     30                                        AlsaWrapper* wrapper)
     31     : audio_manager_(audio_manager),
     32       device_name_(device_name),
     33       params_(params),
     34       bytes_per_buffer_(params.frames_per_buffer() *
     35                         (params.channels() * params.bits_per_sample()) /
     36                         8),
     37       wrapper_(wrapper),
     38       buffer_duration_(base::TimeDelta::FromMicroseconds(
     39           params.frames_per_buffer() * base::Time::kMicrosecondsPerSecond /
     40           static_cast<float>(params.sample_rate()))),
     41       callback_(NULL),
     42       device_handle_(NULL),
     43       mixer_handle_(NULL),
     44       mixer_element_handle_(NULL),
     45       read_callback_behind_schedule_(false),
     46       audio_bus_(AudioBus::Create(params)),
     47       weak_factory_(this) {
     48 }
     49 
     50 AlsaPcmInputStream::~AlsaPcmInputStream() {}
     51 
     52 bool AlsaPcmInputStream::Open() {
     53   if (device_handle_)
     54     return false;  // Already open.
     55 
     56   snd_pcm_format_t pcm_format = alsa_util::BitsToFormat(
     57       params_.bits_per_sample());
     58   if (pcm_format == SND_PCM_FORMAT_UNKNOWN) {
     59     LOG(WARNING) << "Unsupported bits per sample: "
     60                  << params_.bits_per_sample();
     61     return false;
     62   }
     63 
     64   uint32 latency_us =
     65       buffer_duration_.InMicroseconds() * kNumPacketsInRingBuffer;
     66 
     67   // Use the same minimum required latency as output.
     68   latency_us = std::max(latency_us, AlsaPcmOutputStream::kMinLatencyMicros);
     69 
     70   if (device_name_ == kAutoSelectDevice) {
     71     const char* device_names[] = { kDefaultDevice1, kDefaultDevice2 };
     72     for (size_t i = 0; i < arraysize(device_names); ++i) {
     73       device_handle_ = alsa_util::OpenCaptureDevice(
     74           wrapper_, device_names[i], params_.channels(),
     75           params_.sample_rate(), pcm_format, latency_us);
     76 
     77       if (device_handle_) {
     78         device_name_ = device_names[i];
     79         break;
     80       }
     81     }
     82   } else {
     83     device_handle_ = alsa_util::OpenCaptureDevice(wrapper_,
     84                                                   device_name_.c_str(),
     85                                                   params_.channels(),
     86                                                   params_.sample_rate(),
     87                                                   pcm_format, latency_us);
     88   }
     89 
     90   if (device_handle_) {
     91     audio_buffer_.reset(new uint8[bytes_per_buffer_]);
     92 
     93     // Open the microphone mixer.
     94     mixer_handle_ = alsa_util::OpenMixer(wrapper_, device_name_);
     95     if (mixer_handle_) {
     96       mixer_element_handle_ = alsa_util::LoadCaptureMixerElement(
     97           wrapper_, mixer_handle_);
     98     }
     99   }
    100 
    101   return device_handle_ != NULL;
    102 }
    103 
    104 void AlsaPcmInputStream::Start(AudioInputCallback* callback) {
    105   DCHECK(!callback_ && callback);
    106   callback_ = callback;
    107   StartAgc();
    108   int error = wrapper_->PcmPrepare(device_handle_);
    109   if (error < 0) {
    110     HandleError("PcmPrepare", error);
    111   } else {
    112     error = wrapper_->PcmStart(device_handle_);
    113     if (error < 0)
    114       HandleError("PcmStart", error);
    115   }
    116 
    117   if (error < 0) {
    118     callback_ = NULL;
    119   } else {
    120     // We start reading data half |buffer_duration_| later than when the
    121     // buffer might have got filled, to accommodate some delays in the audio
    122     // driver. This could also give us a smooth read sequence going forward.
    123     base::TimeDelta delay = buffer_duration_ + buffer_duration_ / 2;
    124     next_read_time_ = base::TimeTicks::Now() + delay;
    125     base::MessageLoop::current()->PostDelayedTask(
    126         FROM_HERE,
    127         base::Bind(&AlsaPcmInputStream::ReadAudio, weak_factory_.GetWeakPtr()),
    128         delay);
    129   }
    130 }
    131 
    132 bool AlsaPcmInputStream::Recover(int original_error) {
    133   int error = wrapper_->PcmRecover(device_handle_, original_error, 1);
    134   if (error < 0) {
    135     // Docs say snd_pcm_recover returns the original error if it is not one
    136     // of the recoverable ones, so this log message will probably contain the
    137     // same error twice.
    138     LOG(WARNING) << "Unable to recover from \""
    139                  << wrapper_->StrError(original_error) << "\": "
    140                  << wrapper_->StrError(error);
    141     return false;
    142   }
    143 
    144   if (original_error == -EPIPE) {  // Buffer underrun/overrun.
    145     // For capture streams we have to repeat the explicit start() to get
    146     // data flowing again.
    147     error = wrapper_->PcmStart(device_handle_);
    148     if (error < 0) {
    149       HandleError("PcmStart", error);
    150       return false;
    151     }
    152   }
    153 
    154   return true;
    155 }
    156 
    157 snd_pcm_sframes_t AlsaPcmInputStream::GetCurrentDelay() {
    158   snd_pcm_sframes_t delay = -1;
    159 
    160   int error = wrapper_->PcmDelay(device_handle_, &delay);
    161   if (error < 0)
    162     Recover(error);
    163 
    164   // snd_pcm_delay() may not work in the beginning of the stream. In this case
    165   // return delay of data we know currently is in the ALSA's buffer.
    166   if (delay < 0)
    167     delay = wrapper_->PcmAvailUpdate(device_handle_);
    168 
    169   return delay;
    170 }
    171 
    172 void AlsaPcmInputStream::ReadAudio() {
    173   DCHECK(callback_);
    174 
    175   snd_pcm_sframes_t frames = wrapper_->PcmAvailUpdate(device_handle_);
    176   if (frames < 0) {  // Potentially recoverable error?
    177     LOG(WARNING) << "PcmAvailUpdate(): " << wrapper_->StrError(frames);
    178     Recover(frames);
    179   }
    180 
    181   if (frames < params_.frames_per_buffer()) {
    182     // Not enough data yet or error happened. In both cases wait for a very
    183     // small duration before checking again.
    184     // Even Though read callback was behind schedule, there is no data, so
    185     // reset the next_read_time_.
    186     if (read_callback_behind_schedule_) {
    187       next_read_time_ = base::TimeTicks::Now();
    188       read_callback_behind_schedule_ = false;
    189     }
    190 
    191     base::TimeDelta next_check_time = buffer_duration_ / 2;
    192     base::MessageLoop::current()->PostDelayedTask(
    193         FROM_HERE,
    194         base::Bind(&AlsaPcmInputStream::ReadAudio, weak_factory_.GetWeakPtr()),
    195         next_check_time);
    196     return;
    197   }
    198 
    199   int num_buffers = frames / params_.frames_per_buffer();
    200   uint32 hardware_delay_bytes =
    201       static_cast<uint32>(GetCurrentDelay() * params_.GetBytesPerFrame());
    202   double normalized_volume = 0.0;
    203 
    204   // Update the AGC volume level once every second. Note that, |volume| is
    205   // also updated each time SetVolume() is called through IPC by the
    206   // render-side AGC.
    207   GetAgcVolume(&normalized_volume);
    208 
    209   while (num_buffers--) {
    210     int frames_read = wrapper_->PcmReadi(device_handle_, audio_buffer_.get(),
    211                                          params_.frames_per_buffer());
    212     if (frames_read == params_.frames_per_buffer()) {
    213       audio_bus_->FromInterleaved(audio_buffer_.get(),
    214                                   audio_bus_->frames(),
    215                                   params_.bits_per_sample() / 8);
    216       callback_->OnData(
    217           this, audio_bus_.get(), hardware_delay_bytes, normalized_volume);
    218     } else {
    219       LOG(WARNING) << "PcmReadi returning less than expected frames: "
    220                    << frames_read << " vs. " << params_.frames_per_buffer()
    221                    << ". Dropping this buffer.";
    222     }
    223   }
    224 
    225   next_read_time_ += buffer_duration_;
    226   base::TimeDelta delay = next_read_time_ - base::TimeTicks::Now();
    227   if (delay < base::TimeDelta()) {
    228     DVLOG(1) << "Audio read callback behind schedule by "
    229              << (buffer_duration_ - delay).InMicroseconds()
    230              << " (us).";
    231     // Read callback is behind schedule. Assuming there is data pending in
    232     // the soundcard, invoke the read callback immediate in order to catch up.
    233     read_callback_behind_schedule_ = true;
    234     delay = base::TimeDelta();
    235   }
    236 
    237   base::MessageLoop::current()->PostDelayedTask(
    238       FROM_HERE,
    239       base::Bind(&AlsaPcmInputStream::ReadAudio, weak_factory_.GetWeakPtr()),
    240       delay);
    241 }
    242 
    243 void AlsaPcmInputStream::Stop() {
    244   if (!device_handle_ || !callback_)
    245     return;
    246 
    247   StopAgc();
    248 
    249   weak_factory_.InvalidateWeakPtrs();  // Cancel the next scheduled read.
    250   int error = wrapper_->PcmDrop(device_handle_);
    251   if (error < 0)
    252     HandleError("PcmDrop", error);
    253 
    254   callback_ = NULL;
    255 }
    256 
    257 void AlsaPcmInputStream::Close() {
    258   if (device_handle_) {
    259     weak_factory_.InvalidateWeakPtrs();  // Cancel the next scheduled read.
    260     int error = alsa_util::CloseDevice(wrapper_, device_handle_);
    261     if (error < 0)
    262       HandleError("PcmClose", error);
    263 
    264     if (mixer_handle_)
    265       alsa_util::CloseMixer(wrapper_, mixer_handle_, device_name_);
    266 
    267     audio_buffer_.reset();
    268     device_handle_ = NULL;
    269     mixer_handle_ = NULL;
    270     mixer_element_handle_ = NULL;
    271   }
    272 
    273   audio_manager_->ReleaseInputStream(this);
    274 }
    275 
    276 double AlsaPcmInputStream::GetMaxVolume() {
    277   if (!mixer_handle_ || !mixer_element_handle_) {
    278     DLOG(WARNING) << "GetMaxVolume is not supported for " << device_name_;
    279     return 0.0;
    280   }
    281 
    282   if (!wrapper_->MixerSelemHasCaptureVolume(mixer_element_handle_)) {
    283     DLOG(WARNING) << "Unsupported microphone volume for " << device_name_;
    284     return 0.0;
    285   }
    286 
    287   long min = 0;
    288   long max = 0;
    289   if (wrapper_->MixerSelemGetCaptureVolumeRange(mixer_element_handle_,
    290                                                 &min,
    291                                                 &max)) {
    292     DLOG(WARNING) << "Unsupported max microphone volume for " << device_name_;
    293     return 0.0;
    294   }
    295   DCHECK(min == 0);
    296   DCHECK(max > 0);
    297 
    298   return static_cast<double>(max);
    299 }
    300 
    301 void AlsaPcmInputStream::SetVolume(double volume) {
    302   if (!mixer_handle_ || !mixer_element_handle_) {
    303     DLOG(WARNING) << "SetVolume is not supported for " << device_name_;
    304     return;
    305   }
    306 
    307   int error = wrapper_->MixerSelemSetCaptureVolumeAll(
    308       mixer_element_handle_, static_cast<long>(volume));
    309   if (error < 0) {
    310     DLOG(WARNING) << "Unable to set volume for " << device_name_;
    311   }
    312 
    313   // Update the AGC volume level based on the last setting above. Note that,
    314   // the volume-level resolution is not infinite and it is therefore not
    315   // possible to assume that the volume provided as input parameter can be
    316   // used directly. Instead, a new query to the audio hardware is required.
    317   // This method does nothing if AGC is disabled.
    318   UpdateAgcVolume();
    319 }
    320 
    321 double AlsaPcmInputStream::GetVolume() {
    322   if (!mixer_handle_ || !mixer_element_handle_) {
    323     DLOG(WARNING) << "GetVolume is not supported for " << device_name_;
    324     return 0.0;
    325   }
    326 
    327   long current_volume = 0;
    328   int error = wrapper_->MixerSelemGetCaptureVolume(
    329       mixer_element_handle_, static_cast<snd_mixer_selem_channel_id_t>(0),
    330       &current_volume);
    331   if (error < 0) {
    332     DLOG(WARNING) << "Unable to get volume for " << device_name_;
    333     return 0.0;
    334   }
    335 
    336   return static_cast<double>(current_volume);
    337 }
    338 
    339 void AlsaPcmInputStream::HandleError(const char* method, int error) {
    340   LOG(WARNING) << method << ": " << wrapper_->StrError(error);
    341   callback_->OnError(this);
    342 }
    343 
    344 }  // namespace media
    345