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