Home | History | Annotate | Download | only in sound
      1 /*
      2  *  Copyright 2010 The WebRTC Project Authors. All rights reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #include "webrtc/sound/pulseaudiosoundsystem.h"
     12 
     13 #ifdef HAVE_LIBPULSE
     14 
     15 #include <algorithm>
     16 #include <string>
     17 
     18 #include "webrtc/base/arraysize.h"
     19 #include "webrtc/base/common.h"
     20 #include "webrtc/base/fileutils.h"  // for GetApplicationName()
     21 #include "webrtc/base/logging.h"
     22 #include "webrtc/base/timeutils.h"
     23 #include "webrtc/base/worker.h"
     24 #include "webrtc/sound/sounddevicelocator.h"
     25 #include "webrtc/sound/soundinputstreaminterface.h"
     26 #include "webrtc/sound/soundoutputstreaminterface.h"
     27 
     28 namespace rtc {
     29 
     30 // First PulseAudio protocol version that supports PA_STREAM_ADJUST_LATENCY.
     31 static const uint32_t kAdjustLatencyProtocolVersion = 13;
     32 
     33 // Lookup table from the rtc format enum in soundsysteminterface.h to
     34 // Pulse's enums.
     35 static const pa_sample_format_t kCricketFormatToPulseFormatTable[] = {
     36   // The order here must match the order in soundsysteminterface.h
     37   PA_SAMPLE_S16LE,
     38 };
     39 
     40 // Some timing constants for optimal operation. See
     41 // https://tango.0pointer.de/pipermail/pulseaudio-discuss/2008-January/001170.html
     42 // for a good explanation of some of the factors that go into this.
     43 
     44 // Playback.
     45 
     46 // For playback, there is a round-trip delay to fill the server-side playback
     47 // buffer, so setting too low of a latency is a buffer underflow risk. We will
     48 // automatically increase the latency if a buffer underflow does occur, but we
     49 // also enforce a sane minimum at start-up time. Anything lower would be
     50 // virtually guaranteed to underflow at least once, so there's no point in
     51 // allowing lower latencies.
     52 static const int kPlaybackLatencyMinimumMsecs = 20;
     53 // Every time a playback stream underflows, we will reconfigure it with target
     54 // latency that is greater by this amount.
     55 static const int kPlaybackLatencyIncrementMsecs = 20;
     56 // We also need to configure a suitable request size. Too small and we'd burn
     57 // CPU from the overhead of transfering small amounts of data at once. Too large
     58 // and the amount of data remaining in the buffer right before refilling it
     59 // would be a buffer underflow risk. We set it to half of the buffer size.
     60 static const int kPlaybackRequestFactor = 2;
     61 
     62 // Capture.
     63 
     64 // For capture, low latency is not a buffer overflow risk, but it makes us burn
     65 // CPU from the overhead of transfering small amounts of data at once, so we set
     66 // a recommended value that we use for the kLowLatency constant (but if the user
     67 // explicitly requests something lower then we will honour it).
     68 // 1ms takes about 6-7% CPU. 5ms takes about 5%. 10ms takes about 4.x%.
     69 static const int kLowCaptureLatencyMsecs = 10;
     70 // There is a round-trip delay to ack the data to the server, so the
     71 // server-side buffer needs extra space to prevent buffer overflow. 20ms is
     72 // sufficient, but there is no penalty to making it bigger, so we make it huge.
     73 // (750ms is libpulse's default value for the _total_ buffer size in the
     74 // kNoLatencyRequirements case.)
     75 static const int kCaptureBufferExtraMsecs = 750;
     76 
     77 static void FillPlaybackBufferAttr(int latency,
     78                                    pa_buffer_attr *attr) {
     79   attr->maxlength = latency;
     80   attr->tlength = latency;
     81   attr->minreq = latency / kPlaybackRequestFactor;
     82   attr->prebuf = attr->tlength - attr->minreq;
     83   LOG(LS_VERBOSE) << "Configuring latency = " << attr->tlength << ", minreq = "
     84                   << attr->minreq << ", minfill = " << attr->prebuf;
     85 }
     86 
     87 static pa_volume_t CricketVolumeToPulseVolume(int volume) {
     88   // PA's volume space goes from 0% at PA_VOLUME_MUTED (value 0) to 100% at
     89   // PA_VOLUME_NORM (value 0x10000). It can also go beyond 100% up to
     90   // PA_VOLUME_MAX (value UINT32_MAX-1), but using that is probably unwise.
     91   // We just linearly map the 0-255 scale of SoundSystemInterface onto
     92   // PA_VOLUME_MUTED-PA_VOLUME_NORM. If the programmer exceeds kMaxVolume then
     93   // they can access the over-100% features of PA.
     94   return PA_VOLUME_MUTED + (PA_VOLUME_NORM - PA_VOLUME_MUTED) *
     95       volume / SoundSystemInterface::kMaxVolume;
     96 }
     97 
     98 static int PulseVolumeToCricketVolume(pa_volume_t pa_volume) {
     99   return SoundSystemInterface::kMinVolume +
    100       (SoundSystemInterface::kMaxVolume - SoundSystemInterface::kMinVolume) *
    101       pa_volume / PA_VOLUME_NORM;
    102 }
    103 
    104 static pa_volume_t MaxChannelVolume(pa_cvolume *channel_volumes) {
    105   pa_volume_t pa_volume = PA_VOLUME_MUTED;  // Minimum possible value.
    106   for (int i = 0; i < channel_volumes->channels; ++i) {
    107     if (pa_volume < channel_volumes->values[i]) {
    108       pa_volume = channel_volumes->values[i];
    109     }
    110   }
    111   return pa_volume;
    112 }
    113 
    114 class PulseAudioDeviceLocator : public SoundDeviceLocator {
    115  public:
    116   PulseAudioDeviceLocator(const std::string &name,
    117                           const std::string &device_name)
    118       : SoundDeviceLocator(name, device_name) {
    119   }
    120 
    121   virtual SoundDeviceLocator *Copy() const {
    122     return new PulseAudioDeviceLocator(*this);
    123   }
    124 };
    125 
    126 // Functionality that is common to both PulseAudioInputStream and
    127 // PulseAudioOutputStream.
    128 class PulseAudioStream {
    129  public:
    130   PulseAudioStream(PulseAudioSoundSystem *pulse, pa_stream *stream, int flags)
    131       : pulse_(pulse), stream_(stream), flags_(flags) {
    132   }
    133 
    134   ~PulseAudioStream() {
    135     // Close() should have been called during the containing class's destructor.
    136     ASSERT(stream_ == NULL);
    137   }
    138 
    139   // Must be called with the lock held.
    140   bool Close() {
    141     if (!IsClosed()) {
    142       // Unset this here so that we don't get a TERMINATED callback.
    143       symbol_table()->pa_stream_set_state_callback()(stream_, NULL, NULL);
    144       if (symbol_table()->pa_stream_disconnect()(stream_) != 0) {
    145         LOG(LS_ERROR) << "Can't disconnect stream";
    146         // Continue and return true anyways.
    147       }
    148       symbol_table()->pa_stream_unref()(stream_);
    149       stream_ = NULL;
    150     }
    151     return true;
    152   }
    153 
    154   // Must be called with the lock held.
    155   int LatencyUsecs() {
    156     if (!(flags_ & SoundSystemInterface::FLAG_REPORT_LATENCY)) {
    157       return 0;
    158     }
    159 
    160     pa_usec_t latency;
    161     int negative;
    162     Lock();
    163     int re = symbol_table()->pa_stream_get_latency()(stream_, &latency,
    164         &negative);
    165     Unlock();
    166     if (re != 0) {
    167       LOG(LS_ERROR) << "Can't query latency";
    168       // We'd rather continue playout/capture with an incorrect delay than stop
    169       // it altogether, so return a valid value.
    170       return 0;
    171     }
    172     if (negative) {
    173       // The delay can be negative for monitoring streams if the captured
    174       // samples haven't been played yet. In such a case, "latency" contains the
    175       // magnitude, so we must negate it to get the real value.
    176       return -latency;
    177     } else {
    178       return latency;
    179     }
    180   }
    181 
    182   PulseAudioSoundSystem *pulse() {
    183     return pulse_;
    184   }
    185 
    186   PulseAudioSymbolTable *symbol_table() {
    187     return &pulse()->symbol_table_;
    188   }
    189 
    190   pa_stream *stream() {
    191     ASSERT(stream_ != NULL);
    192     return stream_;
    193   }
    194 
    195   bool IsClosed() {
    196     return stream_ == NULL;
    197   }
    198 
    199   void Lock() {
    200     pulse()->Lock();
    201   }
    202 
    203   void Unlock() {
    204     pulse()->Unlock();
    205   }
    206 
    207  private:
    208   PulseAudioSoundSystem *pulse_;
    209   pa_stream *stream_;
    210   int flags_;
    211 
    212   RTC_DISALLOW_COPY_AND_ASSIGN(PulseAudioStream);
    213 };
    214 
    215 // Implementation of an input stream. See soundinputstreaminterface.h regarding
    216 // thread-safety.
    217 class PulseAudioInputStream :
    218     public SoundInputStreamInterface,
    219     private rtc::Worker {
    220  public:
    221   PulseAudioInputStream(PulseAudioSoundSystem *pulse,
    222                         pa_stream *stream,
    223                         int flags)
    224       : stream_(pulse, stream, flags),
    225         temp_sample_data_(NULL),
    226         temp_sample_data_size_(0) {
    227     // This callback seems to never be issued, but let's set it anyways.
    228     symbol_table()->pa_stream_set_overflow_callback()(stream, &OverflowCallback,
    229         NULL);
    230   }
    231 
    232   virtual ~PulseAudioInputStream() {
    233     bool success = Close();
    234     // We need that to live.
    235     VERIFY(success);
    236   }
    237 
    238   virtual bool StartReading() {
    239     return StartWork();
    240   }
    241 
    242   virtual bool StopReading() {
    243     return StopWork();
    244   }
    245 
    246   virtual bool GetVolume(int *volume) {
    247     bool ret = false;
    248 
    249     Lock();
    250 
    251     // Unlike output streams, input streams have no concept of a stream volume,
    252     // only a device volume. So we have to retrieve the volume of the device
    253     // itself.
    254 
    255     pa_cvolume channel_volumes;
    256 
    257     GetVolumeCallbackData data;
    258     data.instance = this;
    259     data.channel_volumes = &channel_volumes;
    260 
    261     pa_operation *op = symbol_table()->pa_context_get_source_info_by_index()(
    262             stream_.pulse()->context_,
    263             symbol_table()->pa_stream_get_device_index()(stream_.stream()),
    264             &GetVolumeCallbackThunk,
    265             &data);
    266     if (!stream_.pulse()->FinishOperation(op)) {
    267       goto done;
    268     }
    269 
    270     if (data.channel_volumes) {
    271       // This pointer was never unset by the callback, so we must have received
    272       // an empty list of infos. This probably never happens, but we code for it
    273       // anyway.
    274       LOG(LS_ERROR) << "Did not receive GetVolumeCallback";
    275       goto done;
    276     }
    277 
    278     // We now have the volume for each channel. Each channel could have a
    279     // different volume if, e.g., the user went and changed the volumes in the
    280     // PA UI. To get a single volume for SoundSystemInterface we just take the
    281     // maximum. Ideally we'd do so with pa_cvolume_max, but it doesn't exist in
    282     // Hardy, so we do it manually.
    283     pa_volume_t pa_volume;
    284     pa_volume = MaxChannelVolume(&channel_volumes);
    285     // Now map onto the SoundSystemInterface range.
    286     *volume = PulseVolumeToCricketVolume(pa_volume);
    287 
    288     ret = true;
    289    done:
    290     Unlock();
    291     return ret;
    292   }
    293 
    294   virtual bool SetVolume(int volume) {
    295     bool ret = false;
    296     pa_volume_t pa_volume = CricketVolumeToPulseVolume(volume);
    297 
    298     Lock();
    299 
    300     // Unlike output streams, input streams have no concept of a stream volume,
    301     // only a device volume. So we have to change the volume of the device
    302     // itself.
    303 
    304     // The device may have a different number of channels than the stream and
    305     // their mapping may be different, so we don't want to use the channel count
    306     // from our sample spec. We could use PA_CHANNELS_MAX to cover our bases,
    307     // and the server allows that even if the device's channel count is lower,
    308     // but some buggy PA clients don't like that (the pavucontrol on Hardy dies
    309     // in an assert if the channel count is different). So instead we look up
    310     // the actual number of channels that the device has.
    311 
    312     uint8_t channels;
    313 
    314     GetSourceChannelCountCallbackData data;
    315     data.instance = this;
    316     data.channels = &channels;
    317 
    318     uint32_t device_index = symbol_table()->pa_stream_get_device_index()(
    319         stream_.stream());
    320 
    321     pa_operation *op = symbol_table()->pa_context_get_source_info_by_index()(
    322         stream_.pulse()->context_,
    323         device_index,
    324         &GetSourceChannelCountCallbackThunk,
    325         &data);
    326     if (!stream_.pulse()->FinishOperation(op)) {
    327       goto done;
    328     }
    329 
    330     if (data.channels) {
    331       // This pointer was never unset by the callback, so we must have received
    332       // an empty list of infos. This probably never happens, but we code for it
    333       // anyway.
    334       LOG(LS_ERROR) << "Did not receive GetSourceChannelCountCallback";
    335       goto done;
    336     }
    337 
    338     pa_cvolume channel_volumes;
    339     symbol_table()->pa_cvolume_set()(&channel_volumes, channels, pa_volume);
    340 
    341     op = symbol_table()->pa_context_set_source_volume_by_index()(
    342         stream_.pulse()->context_,
    343         device_index,
    344         &channel_volumes,
    345         // This callback merely logs errors.
    346         &SetVolumeCallback,
    347         NULL);
    348     if (!op) {
    349       LOG(LS_ERROR) << "pa_context_set_source_volume_by_index()";
    350       goto done;
    351     }
    352     // Don't need to wait for this to complete.
    353     symbol_table()->pa_operation_unref()(op);
    354 
    355     ret = true;
    356    done:
    357     Unlock();
    358     return ret;
    359   }
    360 
    361   virtual bool Close() {
    362     if (!StopReading()) {
    363       return false;
    364     }
    365     bool ret = true;
    366     if (!stream_.IsClosed()) {
    367       Lock();
    368       ret = stream_.Close();
    369       Unlock();
    370     }
    371     return ret;
    372   }
    373 
    374   virtual int LatencyUsecs() {
    375     return stream_.LatencyUsecs();
    376   }
    377 
    378  private:
    379   struct GetVolumeCallbackData {
    380     PulseAudioInputStream* instance;
    381     pa_cvolume* channel_volumes;
    382   };
    383 
    384   struct GetSourceChannelCountCallbackData {
    385     PulseAudioInputStream* instance;
    386     uint8_t* channels;
    387   };
    388 
    389   void Lock() {
    390     stream_.Lock();
    391   }
    392 
    393   void Unlock() {
    394     stream_.Unlock();
    395   }
    396 
    397   PulseAudioSymbolTable *symbol_table() {
    398     return stream_.symbol_table();
    399   }
    400 
    401   void EnableReadCallback() {
    402     symbol_table()->pa_stream_set_read_callback()(
    403          stream_.stream(),
    404          &ReadCallbackThunk,
    405          this);
    406   }
    407 
    408   void DisableReadCallback() {
    409     symbol_table()->pa_stream_set_read_callback()(
    410          stream_.stream(),
    411          NULL,
    412          NULL);
    413   }
    414 
    415   static void ReadCallbackThunk(pa_stream *unused1,
    416                                 size_t unused2,
    417                                 void *userdata) {
    418     PulseAudioInputStream *instance =
    419         static_cast<PulseAudioInputStream *>(userdata);
    420     instance->OnReadCallback();
    421   }
    422 
    423   void OnReadCallback() {
    424     // We get the data pointer and size now in order to save one Lock/Unlock
    425     // on OnMessage.
    426     if (symbol_table()->pa_stream_peek()(stream_.stream(),
    427                                          &temp_sample_data_,
    428                                          &temp_sample_data_size_) != 0) {
    429       LOG(LS_ERROR) << "Can't read data!";
    430       return;
    431     }
    432     // Since we consume the data asynchronously on a different thread, we have
    433     // to temporarily disable the read callback or else Pulse will call it
    434     // continuously until we consume the data. We re-enable it below.
    435     DisableReadCallback();
    436     HaveWork();
    437   }
    438 
    439   // Inherited from Worker.
    440   virtual void OnStart() {
    441     Lock();
    442     EnableReadCallback();
    443     Unlock();
    444   }
    445 
    446   // Inherited from Worker.
    447   virtual void OnHaveWork() {
    448     ASSERT(temp_sample_data_ && temp_sample_data_size_);
    449     SignalSamplesRead(temp_sample_data_,
    450                       temp_sample_data_size_,
    451                       this);
    452     temp_sample_data_ = NULL;
    453     temp_sample_data_size_ = 0;
    454 
    455     Lock();
    456     for (;;) {
    457       // Ack the last thing we read.
    458       if (symbol_table()->pa_stream_drop()(stream_.stream()) != 0) {
    459         LOG(LS_ERROR) << "Can't ack read data";
    460       }
    461 
    462       if (symbol_table()->pa_stream_readable_size()(stream_.stream()) <= 0) {
    463         // Then that was all the data.
    464         break;
    465       }
    466 
    467       // Else more data.
    468       const void *sample_data;
    469       size_t sample_data_size;
    470       if (symbol_table()->pa_stream_peek()(stream_.stream(),
    471                                            &sample_data,
    472                                            &sample_data_size) != 0) {
    473         LOG(LS_ERROR) << "Can't read data!";
    474         break;
    475       }
    476 
    477       // Drop lock for sigslot dispatch, which could take a while.
    478       Unlock();
    479       SignalSamplesRead(sample_data, sample_data_size, this);
    480       Lock();
    481 
    482       // Return to top of loop for the ack and the check for more data.
    483     }
    484     EnableReadCallback();
    485     Unlock();
    486   }
    487 
    488   // Inherited from Worker.
    489   virtual void OnStop() {
    490     Lock();
    491     DisableReadCallback();
    492     Unlock();
    493   }
    494 
    495   static void OverflowCallback(pa_stream *stream,
    496                                void *userdata) {
    497     LOG(LS_WARNING) << "Buffer overflow on capture stream " << stream;
    498   }
    499 
    500   static void GetVolumeCallbackThunk(pa_context *unused,
    501                                      const pa_source_info *info,
    502                                      int eol,
    503                                      void *userdata) {
    504     GetVolumeCallbackData *data =
    505         static_cast<GetVolumeCallbackData *>(userdata);
    506     data->instance->OnGetVolumeCallback(info, eol, &data->channel_volumes);
    507   }
    508 
    509   void OnGetVolumeCallback(const pa_source_info *info,
    510                            int eol,
    511                            pa_cvolume **channel_volumes) {
    512     if (eol) {
    513       // List is over. Wake GetVolume().
    514       stream_.pulse()->Signal();
    515       return;
    516     }
    517 
    518     if (*channel_volumes) {
    519       **channel_volumes = info->volume;
    520       // Unset the pointer so that we know that we have have already copied the
    521       // volume.
    522       *channel_volumes = NULL;
    523     } else {
    524       // We have received an additional callback after the first one, which
    525       // doesn't make sense for a single source. This probably never happens,
    526       // but we code for it anyway.
    527       LOG(LS_WARNING) << "Ignoring extra GetVolumeCallback";
    528     }
    529   }
    530 
    531   static void GetSourceChannelCountCallbackThunk(pa_context *unused,
    532                                                  const pa_source_info *info,
    533                                                  int eol,
    534                                                  void *userdata) {
    535     GetSourceChannelCountCallbackData *data =
    536         static_cast<GetSourceChannelCountCallbackData *>(userdata);
    537     data->instance->OnGetSourceChannelCountCallback(info, eol, &data->channels);
    538   }
    539 
    540   void OnGetSourceChannelCountCallback(const pa_source_info *info,
    541                                        int eol,
    542                                        uint8_t **channels) {
    543     if (eol) {
    544       // List is over. Wake SetVolume().
    545       stream_.pulse()->Signal();
    546       return;
    547     }
    548 
    549     if (*channels) {
    550       **channels = info->channel_map.channels;
    551       // Unset the pointer so that we know that we have have already copied the
    552       // channel count.
    553       *channels = NULL;
    554     } else {
    555       // We have received an additional callback after the first one, which
    556       // doesn't make sense for a single source. This probably never happens,
    557       // but we code for it anyway.
    558       LOG(LS_WARNING) << "Ignoring extra GetSourceChannelCountCallback";
    559     }
    560   }
    561 
    562   static void SetVolumeCallback(pa_context *unused1,
    563                                 int success,
    564                                 void *unused2) {
    565     if (!success) {
    566       LOG(LS_ERROR) << "Failed to change capture volume";
    567     }
    568   }
    569 
    570   PulseAudioStream stream_;
    571   // Temporary storage for passing data between threads.
    572   const void *temp_sample_data_;
    573   size_t temp_sample_data_size_;
    574 
    575   RTC_DISALLOW_COPY_AND_ASSIGN(PulseAudioInputStream);
    576 };
    577 
    578 // Implementation of an output stream. See soundoutputstreaminterface.h
    579 // regarding thread-safety.
    580 class PulseAudioOutputStream :
    581     public SoundOutputStreamInterface,
    582     private rtc::Worker {
    583  public:
    584   PulseAudioOutputStream(PulseAudioSoundSystem *pulse,
    585                          pa_stream *stream,
    586                          int flags,
    587                          int latency)
    588       : stream_(pulse, stream, flags),
    589         configured_latency_(latency),
    590         temp_buffer_space_(0) {
    591     symbol_table()->pa_stream_set_underflow_callback()(stream,
    592                                                        &UnderflowCallbackThunk,
    593                                                        this);
    594   }
    595 
    596   virtual ~PulseAudioOutputStream() {
    597     bool success = Close();
    598     // We need that to live.
    599     VERIFY(success);
    600   }
    601 
    602   virtual bool EnableBufferMonitoring() {
    603     return StartWork();
    604   }
    605 
    606   virtual bool DisableBufferMonitoring() {
    607     return StopWork();
    608   }
    609 
    610   virtual bool WriteSamples(const void *sample_data,
    611                             size_t size) {
    612     bool ret = true;
    613     Lock();
    614     if (symbol_table()->pa_stream_write()(stream_.stream(),
    615                                           sample_data,
    616                                           size,
    617                                           NULL,
    618                                           0,
    619                                           PA_SEEK_RELATIVE) != 0) {
    620       LOG(LS_ERROR) << "Unable to write";
    621       ret = false;
    622     }
    623     Unlock();
    624     return ret;
    625   }
    626 
    627   virtual bool GetVolume(int *volume) {
    628     bool ret = false;
    629 
    630     Lock();
    631 
    632     pa_cvolume channel_volumes;
    633 
    634     GetVolumeCallbackData data;
    635     data.instance = this;
    636     data.channel_volumes = &channel_volumes;
    637 
    638     pa_operation *op = symbol_table()->pa_context_get_sink_input_info()(
    639             stream_.pulse()->context_,
    640             symbol_table()->pa_stream_get_index()(stream_.stream()),
    641             &GetVolumeCallbackThunk,
    642             &data);
    643     if (!stream_.pulse()->FinishOperation(op)) {
    644       goto done;
    645     }
    646 
    647     if (data.channel_volumes) {
    648       // This pointer was never unset by the callback, so we must have received
    649       // an empty list of infos. This probably never happens, but we code for it
    650       // anyway.
    651       LOG(LS_ERROR) << "Did not receive GetVolumeCallback";
    652       goto done;
    653     }
    654 
    655     // We now have the volume for each channel. Each channel could have a
    656     // different volume if, e.g., the user went and changed the volumes in the
    657     // PA UI. To get a single volume for SoundSystemInterface we just take the
    658     // maximum. Ideally we'd do so with pa_cvolume_max, but it doesn't exist in
    659     // Hardy, so we do it manually.
    660     pa_volume_t pa_volume;
    661     pa_volume = MaxChannelVolume(&channel_volumes);
    662     // Now map onto the SoundSystemInterface range.
    663     *volume = PulseVolumeToCricketVolume(pa_volume);
    664 
    665     ret = true;
    666    done:
    667     Unlock();
    668     return ret;
    669   }
    670 
    671   virtual bool SetVolume(int volume) {
    672     bool ret = false;
    673     pa_volume_t pa_volume = CricketVolumeToPulseVolume(volume);
    674 
    675     Lock();
    676 
    677     const pa_sample_spec *spec = symbol_table()->pa_stream_get_sample_spec()(
    678         stream_.stream());
    679     if (!spec) {
    680       LOG(LS_ERROR) << "pa_stream_get_sample_spec()";
    681       goto done;
    682     }
    683 
    684     pa_cvolume channel_volumes;
    685     symbol_table()->pa_cvolume_set()(&channel_volumes, spec->channels,
    686         pa_volume);
    687 
    688     pa_operation *op;
    689     op = symbol_table()->pa_context_set_sink_input_volume()(
    690         stream_.pulse()->context_,
    691         symbol_table()->pa_stream_get_index()(stream_.stream()),
    692         &channel_volumes,
    693         // This callback merely logs errors.
    694         &SetVolumeCallback,
    695         NULL);
    696     if (!op) {
    697       LOG(LS_ERROR) << "pa_context_set_sink_input_volume()";
    698       goto done;
    699     }
    700     // Don't need to wait for this to complete.
    701     symbol_table()->pa_operation_unref()(op);
    702 
    703     ret = true;
    704    done:
    705     Unlock();
    706     return ret;
    707   }
    708 
    709   virtual bool Close() {
    710     if (!DisableBufferMonitoring()) {
    711       return false;
    712     }
    713     bool ret = true;
    714     if (!stream_.IsClosed()) {
    715       Lock();
    716       symbol_table()->pa_stream_set_underflow_callback()(stream_.stream(),
    717                                                          NULL,
    718                                                          NULL);
    719       ret = stream_.Close();
    720       Unlock();
    721     }
    722     return ret;
    723   }
    724 
    725   virtual int LatencyUsecs() {
    726     return stream_.LatencyUsecs();
    727   }
    728 
    729 #if 0
    730   // TODO(henrika): Versions 0.9.16 and later of Pulse have a new API for
    731   // zero-copy writes, but Hardy is not new enough to have that so we can't
    732   // rely on it. Perhaps auto-detect if it's present or not and use it if we
    733   // can?
    734 
    735   virtual bool GetWriteBuffer(void **buffer, size_t *size) {
    736     bool ret = true;
    737     Lock();
    738     if (symbol_table()->pa_stream_begin_write()(stream_.stream(), buffer, size)
    739             != 0) {
    740       LOG(LS_ERROR) << "Can't get write buffer";
    741       ret = false;
    742     }
    743     Unlock();
    744     return ret;
    745   }
    746 
    747   // Releases the caller's hold on the write buffer. "written" must be the
    748   // amount of data that was written.
    749   virtual bool ReleaseWriteBuffer(void *buffer, size_t written) {
    750     bool ret = true;
    751     Lock();
    752     if (written == 0) {
    753       if (symbol_table()->pa_stream_cancel_write()(stream_.stream()) != 0) {
    754         LOG(LS_ERROR) << "Can't cancel write";
    755         ret = false;
    756       }
    757     } else {
    758       if (symbol_table()->pa_stream_write()(stream_.stream(),
    759                                             buffer,
    760                                             written,
    761                                             NULL,
    762                                             0,
    763                                             PA_SEEK_RELATIVE) != 0) {
    764         LOG(LS_ERROR) << "Unable to write";
    765         ret = false;
    766       }
    767     }
    768     Unlock();
    769     return ret;
    770   }
    771 #endif
    772 
    773  private:
    774   struct GetVolumeCallbackData {
    775     PulseAudioOutputStream* instance;
    776     pa_cvolume* channel_volumes;
    777   };
    778 
    779   void Lock() {
    780     stream_.Lock();
    781   }
    782 
    783   void Unlock() {
    784     stream_.Unlock();
    785   }
    786 
    787   PulseAudioSymbolTable *symbol_table() {
    788     return stream_.symbol_table();
    789   }
    790 
    791   void EnableWriteCallback() {
    792     pa_stream_state_t state = symbol_table()->pa_stream_get_state()(
    793         stream_.stream());
    794     if (state == PA_STREAM_READY) {
    795       // May already have available space. Must check.
    796       temp_buffer_space_ = symbol_table()->pa_stream_writable_size()(
    797           stream_.stream());
    798       if (temp_buffer_space_ > 0) {
    799         // Yup, there is already space available, so if we register a write
    800         // callback then it will not receive any event. So dispatch one ourself
    801         // instead.
    802         HaveWork();
    803         return;
    804       }
    805     }
    806     symbol_table()->pa_stream_set_write_callback()(
    807          stream_.stream(),
    808          &WriteCallbackThunk,
    809          this);
    810   }
    811 
    812   void DisableWriteCallback() {
    813     symbol_table()->pa_stream_set_write_callback()(
    814          stream_.stream(),
    815          NULL,
    816          NULL);
    817   }
    818 
    819   static void WriteCallbackThunk(pa_stream *unused,
    820                                  size_t buffer_space,
    821                                  void *userdata) {
    822     PulseAudioOutputStream *instance =
    823         static_cast<PulseAudioOutputStream *>(userdata);
    824     instance->OnWriteCallback(buffer_space);
    825   }
    826 
    827   void OnWriteCallback(size_t buffer_space) {
    828     temp_buffer_space_ = buffer_space;
    829     // Since we write the data asynchronously on a different thread, we have
    830     // to temporarily disable the write callback or else Pulse will call it
    831     // continuously until we write the data. We re-enable it below.
    832     DisableWriteCallback();
    833     HaveWork();
    834   }
    835 
    836   // Inherited from Worker.
    837   virtual void OnStart() {
    838     Lock();
    839     EnableWriteCallback();
    840     Unlock();
    841   }
    842 
    843   // Inherited from Worker.
    844   virtual void OnHaveWork() {
    845     ASSERT(temp_buffer_space_ > 0);
    846 
    847     SignalBufferSpace(temp_buffer_space_, this);
    848 
    849     temp_buffer_space_ = 0;
    850     Lock();
    851     EnableWriteCallback();
    852     Unlock();
    853   }
    854 
    855   // Inherited from Worker.
    856   virtual void OnStop() {
    857     Lock();
    858     DisableWriteCallback();
    859     Unlock();
    860   }
    861 
    862   static void UnderflowCallbackThunk(pa_stream *unused,
    863                                      void *userdata) {
    864     PulseAudioOutputStream *instance =
    865         static_cast<PulseAudioOutputStream *>(userdata);
    866     instance->OnUnderflowCallback();
    867   }
    868 
    869   void OnUnderflowCallback() {
    870     LOG(LS_WARNING) << "Buffer underflow on playback stream "
    871                     << stream_.stream();
    872 
    873     if (configured_latency_ == SoundSystemInterface::kNoLatencyRequirements) {
    874       // We didn't configure a pa_buffer_attr before, so switching to one now
    875       // would be questionable.
    876       return;
    877     }
    878 
    879     // Otherwise reconfigure the stream with a higher target latency.
    880 
    881     const pa_sample_spec *spec = symbol_table()->pa_stream_get_sample_spec()(
    882         stream_.stream());
    883     if (!spec) {
    884       LOG(LS_ERROR) << "pa_stream_get_sample_spec()";
    885       return;
    886     }
    887 
    888     size_t bytes_per_sec = symbol_table()->pa_bytes_per_second()(spec);
    889 
    890     int new_latency = configured_latency_ +
    891         bytes_per_sec * kPlaybackLatencyIncrementMsecs /
    892         rtc::kNumMicrosecsPerSec;
    893 
    894     pa_buffer_attr new_attr = {0};
    895     FillPlaybackBufferAttr(new_latency, &new_attr);
    896 
    897     pa_operation *op = symbol_table()->pa_stream_set_buffer_attr()(
    898         stream_.stream(),
    899         &new_attr,
    900         // No callback.
    901         NULL,
    902         NULL);
    903     if (!op) {
    904       LOG(LS_ERROR) << "pa_stream_set_buffer_attr()";
    905       return;
    906     }
    907     // Don't need to wait for this to complete.
    908     symbol_table()->pa_operation_unref()(op);
    909 
    910     // Save the new latency in case we underflow again.
    911     configured_latency_ = new_latency;
    912   }
    913 
    914   static void GetVolumeCallbackThunk(pa_context *unused,
    915                                      const pa_sink_input_info *info,
    916                                      int eol,
    917                                      void *userdata) {
    918     GetVolumeCallbackData *data =
    919         static_cast<GetVolumeCallbackData *>(userdata);
    920     data->instance->OnGetVolumeCallback(info, eol, &data->channel_volumes);
    921   }
    922 
    923   void OnGetVolumeCallback(const pa_sink_input_info *info,
    924                            int eol,
    925                            pa_cvolume **channel_volumes) {
    926     if (eol) {
    927       // List is over. Wake GetVolume().
    928       stream_.pulse()->Signal();
    929       return;
    930     }
    931 
    932     if (*channel_volumes) {
    933       **channel_volumes = info->volume;
    934       // Unset the pointer so that we know that we have have already copied the
    935       // volume.
    936       *channel_volumes = NULL;
    937     } else {
    938       // We have received an additional callback after the first one, which
    939       // doesn't make sense for a single sink input. This probably never
    940       // happens, but we code for it anyway.
    941       LOG(LS_WARNING) << "Ignoring extra GetVolumeCallback";
    942     }
    943   }
    944 
    945   static void SetVolumeCallback(pa_context *unused1,
    946                                 int success,
    947                                 void *unused2) {
    948     if (!success) {
    949       LOG(LS_ERROR) << "Failed to change playback volume";
    950     }
    951   }
    952 
    953   PulseAudioStream stream_;
    954   int configured_latency_;
    955   // Temporary storage for passing data between threads.
    956   size_t temp_buffer_space_;
    957 
    958   RTC_DISALLOW_COPY_AND_ASSIGN(PulseAudioOutputStream);
    959 };
    960 
    961 PulseAudioSoundSystem::PulseAudioSoundSystem()
    962     : mainloop_(NULL), context_(NULL) {
    963 }
    964 
    965 PulseAudioSoundSystem::~PulseAudioSoundSystem() {
    966   Terminate();
    967 }
    968 
    969 bool PulseAudioSoundSystem::Init() {
    970   if (IsInitialized()) {
    971     return true;
    972   }
    973 
    974   // Load libpulse.
    975   if (!symbol_table_.Load()) {
    976     // Most likely the Pulse library and sound server are not installed on
    977     // this system.
    978     LOG(LS_WARNING) << "Failed to load symbol table";
    979     return false;
    980   }
    981 
    982   // Now create and start the Pulse event thread.
    983   mainloop_ = symbol_table_.pa_threaded_mainloop_new()();
    984   if (!mainloop_) {
    985     LOG(LS_ERROR) << "Can't create mainloop";
    986     goto fail0;
    987   }
    988 
    989   if (symbol_table_.pa_threaded_mainloop_start()(mainloop_) != 0) {
    990     LOG(LS_ERROR) << "Can't start mainloop";
    991     goto fail1;
    992   }
    993 
    994   Lock();
    995   context_ = CreateNewConnection();
    996   Unlock();
    997 
    998   if (!context_) {
    999     goto fail2;
   1000   }
   1001 
   1002   // Otherwise we're now ready!
   1003   return true;
   1004 
   1005  fail2:
   1006   symbol_table_.pa_threaded_mainloop_stop()(mainloop_);
   1007  fail1:
   1008   symbol_table_.pa_threaded_mainloop_free()(mainloop_);
   1009   mainloop_ = NULL;
   1010  fail0:
   1011   return false;
   1012 }
   1013 
   1014 void PulseAudioSoundSystem::Terminate() {
   1015   if (!IsInitialized()) {
   1016     return;
   1017   }
   1018 
   1019   Lock();
   1020   symbol_table_.pa_context_disconnect()(context_);
   1021   symbol_table_.pa_context_unref()(context_);
   1022   Unlock();
   1023   context_ = NULL;
   1024   symbol_table_.pa_threaded_mainloop_stop()(mainloop_);
   1025   symbol_table_.pa_threaded_mainloop_free()(mainloop_);
   1026   mainloop_ = NULL;
   1027 
   1028   // We do not unload the symbol table because we may need it again soon if
   1029   // Init() is called again.
   1030 }
   1031 
   1032 bool PulseAudioSoundSystem::EnumeratePlaybackDevices(
   1033     SoundDeviceLocatorList *devices) {
   1034   return EnumerateDevices<pa_sink_info>(
   1035       devices,
   1036       symbol_table_.pa_context_get_sink_info_list(),
   1037       &EnumeratePlaybackDevicesCallbackThunk);
   1038 }
   1039 
   1040 bool PulseAudioSoundSystem::EnumerateCaptureDevices(
   1041     SoundDeviceLocatorList *devices) {
   1042   return EnumerateDevices<pa_source_info>(
   1043       devices,
   1044       symbol_table_.pa_context_get_source_info_list(),
   1045       &EnumerateCaptureDevicesCallbackThunk);
   1046 }
   1047 
   1048 bool PulseAudioSoundSystem::GetDefaultPlaybackDevice(
   1049     SoundDeviceLocator **device) {
   1050   return GetDefaultDevice<&pa_server_info::default_sink_name>(device);
   1051 }
   1052 
   1053 bool PulseAudioSoundSystem::GetDefaultCaptureDevice(
   1054     SoundDeviceLocator **device) {
   1055   return GetDefaultDevice<&pa_server_info::default_source_name>(device);
   1056 }
   1057 
   1058 SoundOutputStreamInterface *PulseAudioSoundSystem::OpenPlaybackDevice(
   1059     const SoundDeviceLocator *device,
   1060     const OpenParams &params) {
   1061   return OpenDevice<SoundOutputStreamInterface>(
   1062       device,
   1063       params,
   1064       "Playback",
   1065       &PulseAudioSoundSystem::ConnectOutputStream);
   1066 }
   1067 
   1068 SoundInputStreamInterface *PulseAudioSoundSystem::OpenCaptureDevice(
   1069     const SoundDeviceLocator *device,
   1070     const OpenParams &params) {
   1071   return OpenDevice<SoundInputStreamInterface>(
   1072       device,
   1073       params,
   1074       "Capture",
   1075       &PulseAudioSoundSystem::ConnectInputStream);
   1076 }
   1077 
   1078 const char *PulseAudioSoundSystem::GetName() const {
   1079   return "PulseAudio";
   1080 }
   1081 
   1082 inline bool PulseAudioSoundSystem::IsInitialized() {
   1083   return mainloop_ != NULL;
   1084 }
   1085 
   1086 struct ConnectToPulseCallbackData {
   1087   PulseAudioSoundSystem *instance;
   1088   bool connect_done;
   1089 };
   1090 
   1091 void PulseAudioSoundSystem::ConnectToPulseCallbackThunk(
   1092     pa_context *context, void *userdata) {
   1093   ConnectToPulseCallbackData *data =
   1094       static_cast<ConnectToPulseCallbackData *>(userdata);
   1095   data->instance->OnConnectToPulseCallback(context, &data->connect_done);
   1096 }
   1097 
   1098 void PulseAudioSoundSystem::OnConnectToPulseCallback(
   1099     pa_context *context, bool *connect_done) {
   1100   pa_context_state_t state = symbol_table_.pa_context_get_state()(context);
   1101   if (state == PA_CONTEXT_READY ||
   1102       state == PA_CONTEXT_FAILED ||
   1103       state == PA_CONTEXT_TERMINATED) {
   1104     // Connection process has reached a terminal state. Wake ConnectToPulse().
   1105     *connect_done = true;
   1106     Signal();
   1107   }
   1108 }
   1109 
   1110 // Must be called with the lock held.
   1111 bool PulseAudioSoundSystem::ConnectToPulse(pa_context *context) {
   1112   bool ret = true;
   1113   ConnectToPulseCallbackData data;
   1114   // Have to put this up here to satisfy the compiler.
   1115   pa_context_state_t state;
   1116 
   1117   data.instance = this;
   1118   data.connect_done = false;
   1119 
   1120   symbol_table_.pa_context_set_state_callback()(context,
   1121                                                 &ConnectToPulseCallbackThunk,
   1122                                                 &data);
   1123 
   1124   // Connect to PulseAudio sound server.
   1125   if (symbol_table_.pa_context_connect()(
   1126           context,
   1127           NULL,          // Default server
   1128           PA_CONTEXT_NOAUTOSPAWN,
   1129           NULL) != 0) {  // No special fork handling needed
   1130     LOG(LS_ERROR) << "Can't start connection to PulseAudio sound server";
   1131     ret = false;
   1132     goto done;
   1133   }
   1134 
   1135   // Wait for the connection state machine to reach a terminal state.
   1136   do {
   1137     Wait();
   1138   } while (!data.connect_done);
   1139 
   1140   // Now check to see what final state we reached.
   1141   state = symbol_table_.pa_context_get_state()(context);
   1142 
   1143   if (state != PA_CONTEXT_READY) {
   1144     if (state == PA_CONTEXT_FAILED) {
   1145       LOG(LS_ERROR) << "Failed to connect to PulseAudio sound server";
   1146     } else if (state == PA_CONTEXT_TERMINATED) {
   1147       LOG(LS_ERROR) << "PulseAudio connection terminated early";
   1148     } else {
   1149       // Shouldn't happen, because we only signal on one of those three states.
   1150       LOG(LS_ERROR) << "Unknown problem connecting to PulseAudio";
   1151     }
   1152     ret = false;
   1153   }
   1154 
   1155  done:
   1156   // We unset our callback for safety just in case the state might somehow
   1157   // change later, because the pointer to "data" will be invalid after return
   1158   // from this function.
   1159   symbol_table_.pa_context_set_state_callback()(context, NULL, NULL);
   1160   return ret;
   1161 }
   1162 
   1163 // Must be called with the lock held.
   1164 pa_context *PulseAudioSoundSystem::CreateNewConnection() {
   1165   // Create connection context.
   1166   std::string app_name;
   1167   // TODO(henrika): Pulse etiquette says this name should be localized. Do
   1168   // we care?
   1169   rtc::Filesystem::GetApplicationName(&app_name);
   1170   pa_context *context = symbol_table_.pa_context_new()(
   1171       symbol_table_.pa_threaded_mainloop_get_api()(mainloop_),
   1172       app_name.c_str());
   1173   if (!context) {
   1174     LOG(LS_ERROR) << "Can't create context";
   1175     goto fail0;
   1176   }
   1177 
   1178   // Now connect.
   1179   if (!ConnectToPulse(context)) {
   1180     goto fail1;
   1181   }
   1182 
   1183   // Otherwise the connection succeeded and is ready.
   1184   return context;
   1185 
   1186  fail1:
   1187   symbol_table_.pa_context_unref()(context);
   1188  fail0:
   1189   return NULL;
   1190 }
   1191 
   1192 struct EnumerateDevicesCallbackData {
   1193   PulseAudioSoundSystem *instance;
   1194   SoundSystemInterface::SoundDeviceLocatorList *devices;
   1195 };
   1196 
   1197 void PulseAudioSoundSystem::EnumeratePlaybackDevicesCallbackThunk(
   1198     pa_context *unused,
   1199     const pa_sink_info *info,
   1200     int eol,
   1201     void *userdata) {
   1202   EnumerateDevicesCallbackData *data =
   1203       static_cast<EnumerateDevicesCallbackData *>(userdata);
   1204   data->instance->OnEnumeratePlaybackDevicesCallback(data->devices, info, eol);
   1205 }
   1206 
   1207 void PulseAudioSoundSystem::EnumerateCaptureDevicesCallbackThunk(
   1208     pa_context *unused,
   1209     const pa_source_info *info,
   1210     int eol,
   1211     void *userdata) {
   1212   EnumerateDevicesCallbackData *data =
   1213       static_cast<EnumerateDevicesCallbackData *>(userdata);
   1214   data->instance->OnEnumerateCaptureDevicesCallback(data->devices, info, eol);
   1215 }
   1216 
   1217 void PulseAudioSoundSystem::OnEnumeratePlaybackDevicesCallback(
   1218     SoundDeviceLocatorList *devices,
   1219     const pa_sink_info *info,
   1220     int eol) {
   1221   if (eol) {
   1222     // List is over. Wake EnumerateDevices().
   1223     Signal();
   1224     return;
   1225   }
   1226 
   1227   // Else this is the next device.
   1228   devices->push_back(
   1229       new PulseAudioDeviceLocator(info->description, info->name));
   1230 }
   1231 
   1232 void PulseAudioSoundSystem::OnEnumerateCaptureDevicesCallback(
   1233     SoundDeviceLocatorList *devices,
   1234     const pa_source_info *info,
   1235     int eol) {
   1236   if (eol) {
   1237     // List is over. Wake EnumerateDevices().
   1238     Signal();
   1239     return;
   1240   }
   1241 
   1242   if (info->monitor_of_sink != PA_INVALID_INDEX) {
   1243     // We don't want to list monitor sources, since they are almost certainly
   1244     // not what the user wants for voice conferencing.
   1245     return;
   1246   }
   1247 
   1248   // Else this is the next device.
   1249   devices->push_back(
   1250       new PulseAudioDeviceLocator(info->description, info->name));
   1251 }
   1252 
   1253 template <typename InfoStruct>
   1254 bool PulseAudioSoundSystem::EnumerateDevices(
   1255     SoundDeviceLocatorList *devices,
   1256     pa_operation *(*enumerate_fn)(
   1257         pa_context *c,
   1258         void (*callback_fn)(
   1259             pa_context *c,
   1260             const InfoStruct *i,
   1261             int eol,
   1262             void *userdata),
   1263         void *userdata),
   1264     void (*callback_fn)(
   1265         pa_context *c,
   1266         const InfoStruct *i,
   1267         int eol,
   1268         void *userdata)) {
   1269   ClearSoundDeviceLocatorList(devices);
   1270   if (!IsInitialized()) {
   1271     return false;
   1272   }
   1273 
   1274   EnumerateDevicesCallbackData data;
   1275   data.instance = this;
   1276   data.devices = devices;
   1277 
   1278   Lock();
   1279   pa_operation *op = (*enumerate_fn)(
   1280       context_,
   1281       callback_fn,
   1282       &data);
   1283   bool ret = FinishOperation(op);
   1284   Unlock();
   1285   return ret;
   1286 }
   1287 
   1288 struct GetDefaultDeviceCallbackData {
   1289   PulseAudioSoundSystem *instance;
   1290   SoundDeviceLocator **device;
   1291 };
   1292 
   1293 template <const char *(pa_server_info::*field)>
   1294 void PulseAudioSoundSystem::GetDefaultDeviceCallbackThunk(
   1295     pa_context *unused,
   1296     const pa_server_info *info,
   1297     void *userdata) {
   1298   GetDefaultDeviceCallbackData *data =
   1299       static_cast<GetDefaultDeviceCallbackData *>(userdata);
   1300   data->instance->OnGetDefaultDeviceCallback<field>(info, data->device);
   1301 }
   1302 
   1303 template <const char *(pa_server_info::*field)>
   1304 void PulseAudioSoundSystem::OnGetDefaultDeviceCallback(
   1305     const pa_server_info *info,
   1306     SoundDeviceLocator **device) {
   1307   if (info) {
   1308     const char *dev = info->*field;
   1309     if (dev) {
   1310       *device = new PulseAudioDeviceLocator("Default device", dev);
   1311     }
   1312   }
   1313   Signal();
   1314 }
   1315 
   1316 template <const char *(pa_server_info::*field)>
   1317 bool PulseAudioSoundSystem::GetDefaultDevice(SoundDeviceLocator **device) {
   1318   if (!IsInitialized()) {
   1319     return false;
   1320   }
   1321   bool ret;
   1322   *device = NULL;
   1323   GetDefaultDeviceCallbackData data;
   1324   data.instance = this;
   1325   data.device = device;
   1326   Lock();
   1327   pa_operation *op = symbol_table_.pa_context_get_server_info()(
   1328       context_,
   1329       &GetDefaultDeviceCallbackThunk<field>,
   1330       &data);
   1331   ret = FinishOperation(op);
   1332   Unlock();
   1333   return ret && (*device != NULL);
   1334 }
   1335 
   1336 void PulseAudioSoundSystem::StreamStateChangedCallbackThunk(
   1337     pa_stream *stream,
   1338     void *userdata) {
   1339   PulseAudioSoundSystem *instance =
   1340       static_cast<PulseAudioSoundSystem *>(userdata);
   1341   instance->OnStreamStateChangedCallback(stream);
   1342 }
   1343 
   1344 void PulseAudioSoundSystem::OnStreamStateChangedCallback(pa_stream *stream) {
   1345   pa_stream_state_t state = symbol_table_.pa_stream_get_state()(stream);
   1346   if (state == PA_STREAM_READY) {
   1347     LOG(LS_INFO) << "Pulse stream " << stream << " ready";
   1348   } else if (state == PA_STREAM_FAILED ||
   1349              state == PA_STREAM_TERMINATED ||
   1350              state == PA_STREAM_UNCONNECTED) {
   1351     LOG(LS_ERROR) << "Pulse stream " << stream << " failed to connect: "
   1352                   << LastError();
   1353   }
   1354 }
   1355 
   1356 template <typename StreamInterface>
   1357 StreamInterface *PulseAudioSoundSystem::OpenDevice(
   1358     const SoundDeviceLocator *device,
   1359     const OpenParams &params,
   1360     const char *stream_name,
   1361     StreamInterface *(PulseAudioSoundSystem::*connect_fn)(
   1362         pa_stream *stream,
   1363         const char *dev,
   1364         int flags,
   1365         pa_stream_flags_t pa_flags,
   1366         int latency,
   1367         const pa_sample_spec &spec)) {
   1368   if (!IsInitialized()) {
   1369     return NULL;
   1370   }
   1371 
   1372   const char *dev = static_cast<const PulseAudioDeviceLocator *>(device)->
   1373       device_name().c_str();
   1374 
   1375   StreamInterface *stream_interface = NULL;
   1376 
   1377   ASSERT(params.format < arraysize(kCricketFormatToPulseFormatTable));
   1378 
   1379   pa_sample_spec spec;
   1380   spec.format = kCricketFormatToPulseFormatTable[params.format];
   1381   spec.rate = params.freq;
   1382   spec.channels = params.channels;
   1383 
   1384   int pa_flags = 0;
   1385   if (params.flags & FLAG_REPORT_LATENCY) {
   1386     pa_flags |= PA_STREAM_INTERPOLATE_TIMING |
   1387                 PA_STREAM_AUTO_TIMING_UPDATE;
   1388   }
   1389 
   1390   if (params.latency != kNoLatencyRequirements) {
   1391     // If configuring a specific latency then we want to specify
   1392     // PA_STREAM_ADJUST_LATENCY to make the server adjust parameters
   1393     // automatically to reach that target latency. However, that flag doesn't
   1394     // exist in Ubuntu 8.04 and many people still use that, so we have to check
   1395     // the protocol version of libpulse.
   1396     if (symbol_table_.pa_context_get_protocol_version()(context_) >=
   1397         kAdjustLatencyProtocolVersion) {
   1398       pa_flags |= PA_STREAM_ADJUST_LATENCY;
   1399     }
   1400   }
   1401 
   1402   Lock();
   1403 
   1404   pa_stream *stream = symbol_table_.pa_stream_new()(context_, stream_name,
   1405       &spec, NULL);
   1406   if (!stream) {
   1407     LOG(LS_ERROR) << "Can't create pa_stream";
   1408     goto done;
   1409   }
   1410 
   1411   // Set a state callback to log errors.
   1412   symbol_table_.pa_stream_set_state_callback()(stream,
   1413                                                &StreamStateChangedCallbackThunk,
   1414                                                this);
   1415 
   1416   stream_interface = (this->*connect_fn)(
   1417       stream,
   1418       dev,
   1419       params.flags,
   1420       static_cast<pa_stream_flags_t>(pa_flags),
   1421       params.latency,
   1422       spec);
   1423   if (!stream_interface) {
   1424     LOG(LS_ERROR) << "Can't connect stream to " << dev;
   1425     symbol_table_.pa_stream_unref()(stream);
   1426   }
   1427 
   1428  done:
   1429   Unlock();
   1430   return stream_interface;
   1431 }
   1432 
   1433 // Must be called with the lock held.
   1434 SoundOutputStreamInterface *PulseAudioSoundSystem::ConnectOutputStream(
   1435     pa_stream *stream,
   1436     const char *dev,
   1437     int flags,
   1438     pa_stream_flags_t pa_flags,
   1439     int latency,
   1440     const pa_sample_spec &spec) {
   1441   pa_buffer_attr attr = {0};
   1442   pa_buffer_attr *pattr = NULL;
   1443   if (latency != kNoLatencyRequirements) {
   1444     // kLowLatency is 0, so we treat it the same as a request for zero latency.
   1445     ssize_t bytes_per_sec = symbol_table_.pa_bytes_per_second()(&spec);
   1446     latency = std::max(
   1447         latency, static_cast<int>(bytes_per_sec * kPlaybackLatencyMinimumMsecs /
   1448                                   rtc::kNumMicrosecsPerSec));
   1449     FillPlaybackBufferAttr(latency, &attr);
   1450     pattr = &attr;
   1451   }
   1452   if (symbol_table_.pa_stream_connect_playback()(
   1453           stream,
   1454           dev,
   1455           pattr,
   1456           pa_flags,
   1457           // Let server choose volume
   1458           NULL,
   1459           // Not synchronized to any other playout
   1460           NULL) != 0) {
   1461     return NULL;
   1462   }
   1463   return new PulseAudioOutputStream(this, stream, flags, latency);
   1464 }
   1465 
   1466 // Must be called with the lock held.
   1467 SoundInputStreamInterface *PulseAudioSoundSystem::ConnectInputStream(
   1468     pa_stream *stream,
   1469     const char *dev,
   1470     int flags,
   1471     pa_stream_flags_t pa_flags,
   1472     int latency,
   1473     const pa_sample_spec &spec) {
   1474   pa_buffer_attr attr = {0};
   1475   pa_buffer_attr *pattr = NULL;
   1476   if (latency != kNoLatencyRequirements) {
   1477     size_t bytes_per_sec = symbol_table_.pa_bytes_per_second()(&spec);
   1478     if (latency == kLowLatency) {
   1479       latency = bytes_per_sec * kLowCaptureLatencyMsecs /
   1480           rtc::kNumMicrosecsPerSec;
   1481     }
   1482     // Note: fragsize specifies a maximum transfer size, not a minimum, so it is
   1483     // not possible to force a high latency setting, only a low one.
   1484     attr.fragsize = latency;
   1485     attr.maxlength = latency + bytes_per_sec * kCaptureBufferExtraMsecs /
   1486         rtc::kNumMicrosecsPerSec;
   1487     LOG(LS_VERBOSE) << "Configuring latency = " << attr.fragsize
   1488                     << ", maxlength = " << attr.maxlength;
   1489     pattr = &attr;
   1490   }
   1491   if (symbol_table_.pa_stream_connect_record()(stream,
   1492                                                dev,
   1493                                                pattr,
   1494                                                pa_flags) != 0) {
   1495     return NULL;
   1496   }
   1497   return new PulseAudioInputStream(this, stream, flags);
   1498 }
   1499 
   1500 // Must be called with the lock held.
   1501 bool PulseAudioSoundSystem::FinishOperation(pa_operation *op) {
   1502   if (!op) {
   1503     LOG(LS_ERROR) << "Failed to start operation";
   1504     return false;
   1505   }
   1506 
   1507   do {
   1508     Wait();
   1509   } while (symbol_table_.pa_operation_get_state()(op) == PA_OPERATION_RUNNING);
   1510 
   1511   symbol_table_.pa_operation_unref()(op);
   1512 
   1513   return true;
   1514 }
   1515 
   1516 inline void PulseAudioSoundSystem::Lock() {
   1517   symbol_table_.pa_threaded_mainloop_lock()(mainloop_);
   1518 }
   1519 
   1520 inline void PulseAudioSoundSystem::Unlock() {
   1521   symbol_table_.pa_threaded_mainloop_unlock()(mainloop_);
   1522 }
   1523 
   1524 // Must be called with the lock held.
   1525 inline void PulseAudioSoundSystem::Wait() {
   1526   symbol_table_.pa_threaded_mainloop_wait()(mainloop_);
   1527 }
   1528 
   1529 // Must be called with the lock held.
   1530 inline void PulseAudioSoundSystem::Signal() {
   1531   symbol_table_.pa_threaded_mainloop_signal()(mainloop_, 0);
   1532 }
   1533 
   1534 // Must be called with the lock held.
   1535 const char *PulseAudioSoundSystem::LastError() {
   1536   return symbol_table_.pa_strerror()(symbol_table_.pa_context_errno()(
   1537       context_));
   1538 }
   1539 
   1540 }  // namespace rtc
   1541 
   1542 #endif  // HAVE_LIBPULSE
   1543