Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / libjingle / source / talk / sound / pulseaudiosoundsystem.cc
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/sound/sounddevicelocator.h"
33 #include "talk/sound/soundinputstreaminterface.h"
34 #include "talk/sound/soundoutputstreaminterface.h"
35 #include "webrtc/base/common.h"
36 #include "webrtc/base/fileutils.h"  // for GetApplicationName()
37 #include "webrtc/base/logging.h"
38 #include "webrtc/base/timeutils.h"
39 #include "webrtc/base/worker.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 rtc::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 rtc::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         rtc::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   rtc::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 = rtc::_max(
1462         latency,
1463         static_cast<int>(
1464             bytes_per_sec * kPlaybackLatencyMinimumMsecs /
1465             rtc::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           rtc::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         rtc::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