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 ¶ms) {
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 ¶ms) {
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 ¶ms,
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