Home | History | Annotate | Download | only in cras
      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/cras/cras_unified.h"
      6 
      7 #include "base/logging.h"
      8 #include "media/audio/cras/audio_manager_cras.h"
      9 
     10 namespace media {
     11 
     12 // Overview of operation:
     13 // 1) An object of CrasUnifiedStream is created by the AudioManager
     14 // factory: audio_man->MakeAudioStream().
     15 // 2) Next some thread will call Open(), at that point a client is created and
     16 // configured for the correct format and sample rate.
     17 // 3) Then Start(source) is called and a stream is added to the CRAS client
     18 // which will create its own thread that periodically calls the source for more
     19 // data as buffers are being consumed.
     20 // 4) When finished Stop() is called, which is handled by stopping the stream.
     21 // 5) Finally Close() is called. It cleans up and notifies the audio manager,
     22 // which likely will destroy this object.
     23 //
     24 // For output-only streams, a unified stream is created with 0 input channels.
     25 //
     26 // Simplified data flow for unified streams:
     27 //
     28 //   +-------------+                  +------------------+
     29 //   | CRAS Server |                  | Chrome Client    |
     30 //   +------+------+    Add Stream    +---------+--------+
     31 //          |<----------------------------------|
     32 //          |                                   |
     33 //          |  buffer_frames captured to shm    |
     34 //          |---------------------------------->|
     35 //          |                                   |  UnifiedCallback()
     36 //          |                                   |  ReadWriteAudio()
     37 //          |                                   |
     38 //          |  buffer_frames written to shm     |
     39 //          |<----------------------------------|
     40 //          |                                   |
     41 //         ...  Repeats for each block.        ...
     42 //          |                                   |
     43 //          |                                   |
     44 //          |  Remove stream                    |
     45 //          |<----------------------------------|
     46 //          |                                   |
     47 //
     48 // Simplified data flow for output only streams:
     49 //
     50 //   +-------------+                  +------------------+
     51 //   | CRAS Server |                  | Chrome Client    |
     52 //   +------+------+    Add Stream    +---------+--------+
     53 //          |<----------------------------------|
     54 //          |                                   |
     55 //          | Near out of samples, request more |
     56 //          |---------------------------------->|
     57 //          |                                   |  UnifiedCallback()
     58 //          |                                   |  WriteAudio()
     59 //          |                                   |
     60 //          |  buffer_frames written to shm     |
     61 //          |<----------------------------------|
     62 //          |                                   |
     63 //         ...  Repeats for each block.        ...
     64 //          |                                   |
     65 //          |                                   |
     66 //          |  Remove stream                    |
     67 //          |<----------------------------------|
     68 //          |                                   |
     69 //
     70 // For Unified streams the Chrome client is notified whenever buffer_frames have
     71 // been captured.  For Output streams the client is notified a few milliseconds
     72 // before the hardware buffer underruns and fills the buffer with another block
     73 // of audio.
     74 
     75 CrasUnifiedStream::CrasUnifiedStream(const AudioParameters& params,
     76                                      AudioManagerCras* manager)
     77     : client_(NULL),
     78       stream_id_(0),
     79       params_(params),
     80       bytes_per_frame_(0),
     81       is_playing_(false),
     82       volume_(1.0),
     83       manager_(manager),
     84       source_callback_(NULL),
     85       stream_direction_(CRAS_STREAM_OUTPUT) {
     86   DCHECK(manager_);
     87   DCHECK(params_.channels()  > 0);
     88 
     89   // Must have at least one input or output.  If there are both they must be the
     90   // same.
     91   int input_channels = params_.input_channels();
     92 
     93   if (input_channels) {
     94     // A unified stream for input and output.
     95     DCHECK(params_.channels() == input_channels);
     96     stream_direction_ = CRAS_STREAM_UNIFIED;
     97     input_bus_ = AudioBus::Create(input_channels,
     98                                   params_.frames_per_buffer());
     99   }
    100 
    101   output_bus_ = AudioBus::Create(params);
    102 }
    103 
    104 CrasUnifiedStream::~CrasUnifiedStream() {
    105   DCHECK(!is_playing_);
    106 }
    107 
    108 bool CrasUnifiedStream::Open() {
    109   // Sanity check input values.
    110   if (params_.sample_rate() <= 0) {
    111     LOG(WARNING) << "Unsupported audio frequency.";
    112     return false;
    113   }
    114 
    115   if (AudioManagerCras::BitsToFormat(params_.bits_per_sample()) ==
    116       SND_PCM_FORMAT_UNKNOWN) {
    117     LOG(WARNING) << "Unsupported pcm format";
    118     return false;
    119   }
    120 
    121   // Create the client and connect to the CRAS server.
    122   if (cras_client_create(&client_)) {
    123     LOG(WARNING) << "Couldn't create CRAS client.\n";
    124     client_ = NULL;
    125     return false;
    126   }
    127 
    128   if (cras_client_connect(client_)) {
    129     LOG(WARNING) << "Couldn't connect CRAS client.\n";
    130     cras_client_destroy(client_);
    131     client_ = NULL;
    132     return false;
    133   }
    134 
    135   // Then start running the client.
    136   if (cras_client_run_thread(client_)) {
    137     LOG(WARNING) << "Couldn't run CRAS client.\n";
    138     cras_client_destroy(client_);
    139     client_ = NULL;
    140     return false;
    141   }
    142 
    143   return true;
    144 }
    145 
    146 void CrasUnifiedStream::Close() {
    147   if (client_) {
    148     cras_client_stop(client_);
    149     cras_client_destroy(client_);
    150     client_ = NULL;
    151   }
    152 
    153   // Signal to the manager that we're closed and can be removed.
    154   // Should be last call in the method as it deletes "this".
    155   manager_->ReleaseOutputStream(this);
    156 }
    157 
    158 void CrasUnifiedStream::Start(AudioSourceCallback* callback) {
    159   CHECK(callback);
    160 
    161   // Channel map to CRAS_CHANNEL, values in the same order of
    162   // corresponding source in Chromium defined Channels.
    163   static const int kChannelMap[] = {
    164     CRAS_CH_FL,
    165     CRAS_CH_FR,
    166     CRAS_CH_FC,
    167     CRAS_CH_LFE,
    168     CRAS_CH_RL,
    169     CRAS_CH_RR,
    170     CRAS_CH_FLC,
    171     CRAS_CH_FRC,
    172     CRAS_CH_RC,
    173     CRAS_CH_SL,
    174     CRAS_CH_SR
    175   };
    176 
    177   source_callback_ = callback;
    178 
    179   // Only start if we can enter the playing state.
    180   if (is_playing_)
    181     return;
    182 
    183   // Prepare |audio_format| and |stream_params| for the stream we
    184   // will create.
    185   cras_audio_format* audio_format = cras_audio_format_create(
    186       AudioManagerCras::BitsToFormat(params_.bits_per_sample()),
    187       params_.sample_rate(),
    188       params_.channels());
    189   if (!audio_format) {
    190     LOG(WARNING) << "Error setting up audio parameters.";
    191     callback->OnError(this);
    192     return;
    193   }
    194 
    195   // Initialize channel layout to all -1 to indicate that none of
    196   // the channels is set in the layout.
    197   int8 layout[CRAS_CH_MAX] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
    198 
    199   // Converts to CRAS defined channels. ChannelOrder will return -1
    200   // for channels that does not present in params_.channel_layout().
    201   for (size_t i = 0; i < arraysize(kChannelMap); ++i)
    202     layout[kChannelMap[i]] = ChannelOrder(params_.channel_layout(),
    203                                           static_cast<Channels>(i));
    204 
    205   if (cras_audio_format_set_channel_layout(audio_format, layout)) {
    206     LOG(WARNING) << "Error setting channel layout.";
    207     callback->OnError(this);
    208     return;
    209   }
    210 
    211   cras_stream_params* stream_params = cras_client_unified_params_create(
    212       stream_direction_,
    213       params_.frames_per_buffer(),
    214       CRAS_STREAM_TYPE_DEFAULT,
    215       0,
    216       this,
    217       CrasUnifiedStream::UnifiedCallback,
    218       CrasUnifiedStream::StreamError,
    219       audio_format);
    220   if (!stream_params) {
    221     LOG(WARNING) << "Error setting up stream parameters.";
    222     callback->OnError(this);
    223     cras_audio_format_destroy(audio_format);
    224     return;
    225   }
    226 
    227   // Before starting the stream, save the number of bytes in a frame for use in
    228   // the callback.
    229   bytes_per_frame_ = cras_client_format_bytes_per_frame(audio_format);
    230 
    231   // Adding the stream will start the audio callbacks requesting data.
    232   if (cras_client_add_stream(client_, &stream_id_, stream_params) < 0) {
    233     LOG(WARNING) << "Failed to add the stream";
    234     callback->OnError(this);
    235     cras_audio_format_destroy(audio_format);
    236     cras_client_stream_params_destroy(stream_params);
    237     return;
    238   }
    239 
    240   // Set initial volume.
    241   cras_client_set_stream_volume(client_, stream_id_, volume_);
    242 
    243   // Done with config params.
    244   cras_audio_format_destroy(audio_format);
    245   cras_client_stream_params_destroy(stream_params);
    246 
    247   is_playing_ = true;
    248 }
    249 
    250 void CrasUnifiedStream::Stop() {
    251   if (!client_)
    252     return;
    253 
    254   // Removing the stream from the client stops audio.
    255   cras_client_rm_stream(client_, stream_id_);
    256 
    257   is_playing_ = false;
    258 }
    259 
    260 void CrasUnifiedStream::SetVolume(double volume) {
    261   if (!client_)
    262     return;
    263   volume_ = static_cast<float>(volume);
    264   cras_client_set_stream_volume(client_, stream_id_, volume_);
    265 }
    266 
    267 void CrasUnifiedStream::GetVolume(double* volume) {
    268   *volume = volume_;
    269 }
    270 
    271 uint32 CrasUnifiedStream::GetBytesLatency(
    272     const struct timespec& latency_ts) {
    273   uint32 latency_usec;
    274 
    275   // Treat negative latency (if we are too slow to render) as 0.
    276   if (latency_ts.tv_sec < 0 || latency_ts.tv_nsec < 0) {
    277     latency_usec = 0;
    278   } else {
    279     latency_usec = (latency_ts.tv_sec * base::Time::kMicrosecondsPerSecond) +
    280         latency_ts.tv_nsec / base::Time::kNanosecondsPerMicrosecond;
    281   }
    282 
    283   double frames_latency =
    284       latency_usec * params_.sample_rate() / base::Time::kMicrosecondsPerSecond;
    285 
    286   return static_cast<unsigned int>(frames_latency * bytes_per_frame_);
    287 }
    288 
    289 // Static callback asking for samples.
    290 int CrasUnifiedStream::UnifiedCallback(cras_client* client,
    291                                        cras_stream_id_t stream_id,
    292                                        uint8* input_samples,
    293                                        uint8* output_samples,
    294                                        unsigned int frames,
    295                                        const timespec* input_ts,
    296                                        const timespec* output_ts,
    297                                        void* arg) {
    298   CrasUnifiedStream* me = static_cast<CrasUnifiedStream*>(arg);
    299   return me->DispatchCallback(frames,
    300                               input_samples,
    301                               output_samples,
    302                               input_ts,
    303                               output_ts);
    304 }
    305 
    306 // Static callback for stream errors.
    307 int CrasUnifiedStream::StreamError(cras_client* client,
    308                                    cras_stream_id_t stream_id,
    309                                    int err,
    310                                    void* arg) {
    311   CrasUnifiedStream* me = static_cast<CrasUnifiedStream*>(arg);
    312   me->NotifyStreamError(err);
    313   return 0;
    314 }
    315 
    316 // Calls the appropriate rendering function for this type of stream.
    317 uint32 CrasUnifiedStream::DispatchCallback(size_t frames,
    318                                            uint8* input_samples,
    319                                            uint8* output_samples,
    320                                            const timespec* input_ts,
    321                                            const timespec* output_ts) {
    322   switch (stream_direction_) {
    323     case CRAS_STREAM_OUTPUT:
    324       return WriteAudio(frames, output_samples, output_ts);
    325     case CRAS_STREAM_INPUT:
    326       NOTREACHED() << "CrasUnifiedStream doesn't support input streams.";
    327       return 0;
    328     case CRAS_STREAM_UNIFIED:
    329       return ReadWriteAudio(frames, input_samples, output_samples,
    330                             input_ts, output_ts);
    331     default:
    332       break;
    333   }
    334 
    335   return 0;
    336 }
    337 
    338 // Note these are run from a real time thread, so don't waste cycles here.
    339 uint32 CrasUnifiedStream::ReadWriteAudio(size_t frames,
    340                                          uint8* input_samples,
    341                                          uint8* output_samples,
    342                                          const timespec* input_ts,
    343                                          const timespec* output_ts) {
    344   DCHECK_EQ(frames, static_cast<size_t>(output_bus_->frames()));
    345   DCHECK(source_callback_);
    346 
    347   uint32 bytes_per_sample = bytes_per_frame_ / params_.channels();
    348   input_bus_->FromInterleaved(input_samples, frames, bytes_per_sample);
    349 
    350   // Determine latency and pass that on to the source.  We have the capture time
    351   // of the first input sample and the playback time of the next audio sample
    352   // passed from the audio server, add them together for total latency.
    353   uint32 total_delay_bytes;
    354   timespec latency_ts  = {0, 0};
    355   cras_client_calc_capture_latency(input_ts, &latency_ts);
    356   total_delay_bytes = GetBytesLatency(latency_ts);
    357   cras_client_calc_playback_latency(output_ts, &latency_ts);
    358   total_delay_bytes += GetBytesLatency(latency_ts);
    359 
    360   int frames_filled = source_callback_->OnMoreData(
    361       output_bus_.get(),
    362       AudioBuffersState(0, total_delay_bytes));
    363 
    364   output_bus_->ToInterleaved(frames_filled, bytes_per_sample, output_samples);
    365 
    366   return frames_filled;
    367 }
    368 
    369 uint32 CrasUnifiedStream::WriteAudio(size_t frames,
    370                                      uint8* buffer,
    371                                      const timespec* sample_ts) {
    372   DCHECK_EQ(frames, static_cast<size_t>(output_bus_->frames()));
    373 
    374   // Determine latency and pass that on to the source.
    375   timespec latency_ts  = {0, 0};
    376   cras_client_calc_playback_latency(sample_ts, &latency_ts);
    377 
    378   int frames_filled = source_callback_->OnMoreData(
    379       output_bus_.get(), AudioBuffersState(0, GetBytesLatency(latency_ts)));
    380 
    381   // Note: If this ever changes to output raw float the data must be clipped and
    382   // sanitized since it may come from an untrusted source such as NaCl.
    383   output_bus_->ToInterleaved(
    384       frames_filled, bytes_per_frame_ / params_.channels(), buffer);
    385 
    386   return frames_filled;
    387 }
    388 
    389 void CrasUnifiedStream::NotifyStreamError(int err) {
    390   // This will remove the stream from the client.
    391   if (source_callback_)
    392     source_callback_->OnError(this);
    393 }
    394 
    395 }  // namespace media
    396