Home | History | Annotate | Download | only in cras
      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/cras/cras_input.h"
      6 
      7 #include <math.h>
      8 
      9 #include "base/basictypes.h"
     10 #include "base/logging.h"
     11 #include "base/time/time.h"
     12 #include "media/audio/audio_manager.h"
     13 #include "media/audio/cras/audio_manager_cras.h"
     14 
     15 namespace media {
     16 
     17 CrasInputStream::CrasInputStream(const AudioParameters& params,
     18                                  AudioManagerCras* manager,
     19                                  const std::string& device_id)
     20     : audio_manager_(manager),
     21       bytes_per_frame_(0),
     22       callback_(NULL),
     23       client_(NULL),
     24       params_(params),
     25       started_(false),
     26       stream_id_(0),
     27       stream_direction_(device_id == AudioManagerBase::kLoopbackInputDeviceId ?
     28                             CRAS_STREAM_POST_MIX_PRE_DSP : CRAS_STREAM_INPUT) {
     29   DCHECK(audio_manager_);
     30   audio_bus_ = AudioBus::Create(params_);
     31 }
     32 
     33 CrasInputStream::~CrasInputStream() {
     34   DCHECK(!client_);
     35 }
     36 
     37 bool CrasInputStream::Open() {
     38   if (client_) {
     39     NOTREACHED() << "CrasInputStream already open";
     40     return false;  // Already open.
     41   }
     42 
     43   // Sanity check input values.
     44   if (params_.sample_rate() <= 0) {
     45     DLOG(WARNING) << "Unsupported audio frequency.";
     46     return false;
     47   }
     48 
     49   if (AudioParameters::AUDIO_PCM_LINEAR != params_.format() &&
     50       AudioParameters::AUDIO_PCM_LOW_LATENCY != params_.format()) {
     51     DLOG(WARNING) << "Unsupported audio format.";
     52     return false;
     53   }
     54 
     55   snd_pcm_format_t pcm_format =
     56       AudioManagerCras::BitsToFormat(params_.bits_per_sample());
     57   if (pcm_format == SND_PCM_FORMAT_UNKNOWN) {
     58     DLOG(WARNING) << "Unsupported bits/sample: " << params_.bits_per_sample();
     59     return false;
     60   }
     61 
     62   // Create the client and connect to the CRAS server.
     63   if (cras_client_create(&client_) < 0) {
     64     DLOG(WARNING) << "Couldn't create CRAS client.\n";
     65     client_ = NULL;
     66     return false;
     67   }
     68 
     69   if (cras_client_connect(client_)) {
     70     DLOG(WARNING) << "Couldn't connect CRAS client.\n";
     71     cras_client_destroy(client_);
     72     client_ = NULL;
     73     return false;
     74   }
     75 
     76   // Then start running the client.
     77   if (cras_client_run_thread(client_)) {
     78     DLOG(WARNING) << "Couldn't run CRAS client.\n";
     79     cras_client_destroy(client_);
     80     client_ = NULL;
     81     return false;
     82   }
     83 
     84   return true;
     85 }
     86 
     87 void CrasInputStream::Close() {
     88   Stop();
     89 
     90   if (client_) {
     91     cras_client_stop(client_);
     92     cras_client_destroy(client_);
     93     client_ = NULL;
     94   }
     95 
     96   // Signal to the manager that we're closed and can be removed.
     97   // Should be last call in the method as it deletes "this".
     98   audio_manager_->ReleaseInputStream(this);
     99 }
    100 
    101 void CrasInputStream::Start(AudioInputCallback* callback) {
    102   DCHECK(client_);
    103   DCHECK(callback);
    104 
    105   // Channel map to CRAS_CHANNEL, values in the same order of
    106   // corresponding source in Chromium defined Channels.
    107   static const int kChannelMap[] = {
    108     CRAS_CH_FL,
    109     CRAS_CH_FR,
    110     CRAS_CH_FC,
    111     CRAS_CH_LFE,
    112     CRAS_CH_RL,
    113     CRAS_CH_RR,
    114     CRAS_CH_FLC,
    115     CRAS_CH_FRC,
    116     CRAS_CH_RC,
    117     CRAS_CH_SL,
    118     CRAS_CH_SR
    119   };
    120   COMPILE_ASSERT(arraysize(kChannelMap) == CHANNELS_MAX + 1,
    121                  channel_map_size_do_not_match);
    122 
    123   // If already playing, stop before re-starting.
    124   if (started_)
    125     return;
    126 
    127   StartAgc();
    128 
    129   callback_ = callback;
    130 
    131   // Prepare |audio_format| and |stream_params| for the stream we
    132   // will create.
    133   cras_audio_format* audio_format = cras_audio_format_create(
    134       AudioManagerCras::BitsToFormat(params_.bits_per_sample()),
    135       params_.sample_rate(),
    136       params_.channels());
    137   if (!audio_format) {
    138     DLOG(WARNING) << "Error setting up audio parameters.";
    139     callback_->OnError(this);
    140     callback_ = NULL;
    141     return;
    142   }
    143 
    144   // Initialize channel layout to all -1 to indicate that none of
    145   // the channels is set in the layout.
    146   int8 layout[CRAS_CH_MAX];
    147   for (size_t i = 0; i < arraysize(layout); ++i)
    148     layout[i] = -1;
    149 
    150   // Converts to CRAS defined channels. ChannelOrder will return -1
    151   // for channels that are not present in params_.channel_layout().
    152   for (size_t i = 0; i < arraysize(kChannelMap); ++i) {
    153     layout[kChannelMap[i]] = ChannelOrder(params_.channel_layout(),
    154                                           static_cast<Channels>(i));
    155   }
    156   if (cras_audio_format_set_channel_layout(audio_format, layout) != 0) {
    157     DLOG(WARNING) << "Error setting channel layout.";
    158     callback->OnError(this);
    159     return;
    160   }
    161 
    162   unsigned int frames_per_packet = params_.frames_per_buffer();
    163   cras_stream_params* stream_params = cras_client_stream_params_create(
    164       stream_direction_,
    165       frames_per_packet,  // Total latency.
    166       frames_per_packet,  // Call back when this many ready.
    167       frames_per_packet,  // Minimum Callback level ignored for capture streams.
    168       CRAS_STREAM_TYPE_DEFAULT,
    169       0,  // Unused flags.
    170       this,
    171       CrasInputStream::SamplesReady,
    172       CrasInputStream::StreamError,
    173       audio_format);
    174   if (!stream_params) {
    175     DLOG(WARNING) << "Error setting up stream parameters.";
    176     callback_->OnError(this);
    177     callback_ = NULL;
    178     cras_audio_format_destroy(audio_format);
    179     return;
    180   }
    181 
    182   // Before starting the stream, save the number of bytes in a frame for use in
    183   // the callback.
    184   bytes_per_frame_ = cras_client_format_bytes_per_frame(audio_format);
    185 
    186   // Adding the stream will start the audio callbacks.
    187   if (cras_client_add_stream(client_, &stream_id_, stream_params)) {
    188     DLOG(WARNING) << "Failed to add the stream.";
    189     callback_->OnError(this);
    190     callback_ = NULL;
    191   }
    192 
    193   // Done with config params.
    194   cras_audio_format_destroy(audio_format);
    195   cras_client_stream_params_destroy(stream_params);
    196 
    197   started_ = true;
    198 }
    199 
    200 void CrasInputStream::Stop() {
    201   DCHECK(client_);
    202 
    203   if (!callback_ || !started_)
    204     return;
    205 
    206   StopAgc();
    207 
    208   // Removing the stream from the client stops audio.
    209   cras_client_rm_stream(client_, stream_id_);
    210 
    211   started_ = false;
    212   callback_ = NULL;
    213 }
    214 
    215 // Static callback asking for samples.  Run on high priority thread.
    216 int CrasInputStream::SamplesReady(cras_client* client,
    217                                   cras_stream_id_t stream_id,
    218                                   uint8* samples,
    219                                   size_t frames,
    220                                   const timespec* sample_ts,
    221                                   void* arg) {
    222   CrasInputStream* me = static_cast<CrasInputStream*>(arg);
    223   me->ReadAudio(frames, samples, sample_ts);
    224   return frames;
    225 }
    226 
    227 // Static callback for stream errors.
    228 int CrasInputStream::StreamError(cras_client* client,
    229                                  cras_stream_id_t stream_id,
    230                                  int err,
    231                                  void* arg) {
    232   CrasInputStream* me = static_cast<CrasInputStream*>(arg);
    233   me->NotifyStreamError(err);
    234   return 0;
    235 }
    236 
    237 void CrasInputStream::ReadAudio(size_t frames,
    238                                 uint8* buffer,
    239                                 const timespec* sample_ts) {
    240   DCHECK(callback_);
    241 
    242   timespec latency_ts = {0, 0};
    243 
    244   // Determine latency and pass that on to the sink.  sample_ts is the wall time
    245   // indicating when the first sample in the buffer was captured.  Convert that
    246   // to latency in bytes.
    247   cras_client_calc_capture_latency(sample_ts, &latency_ts);
    248   double latency_usec =
    249       latency_ts.tv_sec * base::Time::kMicrosecondsPerSecond +
    250       latency_ts.tv_nsec / base::Time::kNanosecondsPerMicrosecond;
    251   double frames_latency =
    252       latency_usec * params_.sample_rate() / base::Time::kMicrosecondsPerSecond;
    253   unsigned int bytes_latency =
    254       static_cast<unsigned int>(frames_latency * bytes_per_frame_);
    255 
    256   // Update the AGC volume level once every second. Note that, |volume| is
    257   // also updated each time SetVolume() is called through IPC by the
    258   // render-side AGC.
    259   double normalized_volume = 0.0;
    260   GetAgcVolume(&normalized_volume);
    261 
    262   audio_bus_->FromInterleaved(
    263       buffer, audio_bus_->frames(), params_.bits_per_sample() / 8);
    264   callback_->OnData(this, audio_bus_.get(), bytes_latency, normalized_volume);
    265 }
    266 
    267 void CrasInputStream::NotifyStreamError(int err) {
    268   if (callback_)
    269     callback_->OnError(this);
    270 }
    271 
    272 double CrasInputStream::GetMaxVolume() {
    273   DCHECK(client_);
    274 
    275   // Capture gain is returned as dB * 100 (150 => 1.5dBFS).  Convert the dB
    276   // value to a ratio before returning.
    277   double dB = cras_client_get_system_max_capture_gain(client_) / 100.0;
    278   return GetVolumeRatioFromDecibels(dB);
    279 }
    280 
    281 void CrasInputStream::SetVolume(double volume) {
    282   DCHECK(client_);
    283 
    284   // Convert from the passed volume ratio, to dB * 100.
    285   double dB = GetDecibelsFromVolumeRatio(volume);
    286   cras_client_set_system_capture_gain(client_, static_cast<long>(dB * 100.0));
    287 
    288   // Update the AGC volume level based on the last setting above. Note that,
    289   // the volume-level resolution is not infinite and it is therefore not
    290   // possible to assume that the volume provided as input parameter can be
    291   // used directly. Instead, a new query to the audio hardware is required.
    292   // This method does nothing if AGC is disabled.
    293   UpdateAgcVolume();
    294 }
    295 
    296 double CrasInputStream::GetVolume() {
    297   if (!client_)
    298     return 0.0;
    299 
    300   long dB = cras_client_get_system_capture_gain(client_) / 100.0;
    301   return GetVolumeRatioFromDecibels(dB);
    302 }
    303 
    304 bool CrasInputStream::IsMuted() {
    305   return false;
    306 }
    307 
    308 double CrasInputStream::GetVolumeRatioFromDecibels(double dB) const {
    309   return pow(10, dB / 20.0);
    310 }
    311 
    312 double CrasInputStream::GetDecibelsFromVolumeRatio(double volume_ratio) const {
    313   return 20 * log10(volume_ratio);
    314 }
    315 
    316 }  // namespace media
    317