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