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