xref: /aosp_15_r20/external/webrtc/modules/audio_device/linux/audio_device_pulse_linux.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2012 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 "modules/audio_device/linux/audio_device_pulse_linux.h"
12 
13 #include <string.h>
14 
15 #include "modules/audio_device/linux/latebindingsymboltable_linux.h"
16 #include "rtc_base/checks.h"
17 #include "rtc_base/logging.h"
18 #include "rtc_base/platform_thread.h"
19 
GetPulseSymbolTable()20 WebRTCPulseSymbolTable* GetPulseSymbolTable() {
21   static WebRTCPulseSymbolTable* pulse_symbol_table =
22       new WebRTCPulseSymbolTable();
23   return pulse_symbol_table;
24 }
25 
26 // Accesses Pulse functions through our late-binding symbol table instead of
27 // directly. This way we don't have to link to libpulse, which means our binary
28 // will work on systems that don't have it.
29 #define LATE(sym)                                             \
30   LATESYM_GET(webrtc::adm_linux_pulse::PulseAudioSymbolTable, \
31               GetPulseSymbolTable(), sym)
32 
33 namespace webrtc {
34 
AudioDeviceLinuxPulse()35 AudioDeviceLinuxPulse::AudioDeviceLinuxPulse()
36     : _ptrAudioBuffer(NULL),
37       _inputDeviceIndex(0),
38       _outputDeviceIndex(0),
39       _inputDeviceIsSpecified(false),
40       _outputDeviceIsSpecified(false),
41       sample_rate_hz_(0),
42       _recChannels(1),
43       _playChannels(1),
44       _initialized(false),
45       _recording(false),
46       _playing(false),
47       _recIsInitialized(false),
48       _playIsInitialized(false),
49       _startRec(false),
50       _startPlay(false),
51       update_speaker_volume_at_startup_(false),
52       quit_(false),
53       _sndCardPlayDelay(0),
54       _writeErrors(0),
55       _deviceIndex(-1),
56       _numPlayDevices(0),
57       _numRecDevices(0),
58       _playDeviceName(NULL),
59       _recDeviceName(NULL),
60       _playDisplayDeviceName(NULL),
61       _recDisplayDeviceName(NULL),
62       _playBuffer(NULL),
63       _playbackBufferSize(0),
64       _playbackBufferUnused(0),
65       _tempBufferSpace(0),
66       _recBuffer(NULL),
67       _recordBufferSize(0),
68       _recordBufferUsed(0),
69       _tempSampleData(NULL),
70       _tempSampleDataSize(0),
71       _configuredLatencyPlay(0),
72       _configuredLatencyRec(0),
73       _paDeviceIndex(-1),
74       _paStateChanged(false),
75       _paMainloop(NULL),
76       _paMainloopApi(NULL),
77       _paContext(NULL),
78       _recStream(NULL),
79       _playStream(NULL),
80       _recStreamFlags(0),
81       _playStreamFlags(0) {
82   RTC_DLOG(LS_INFO) << __FUNCTION__ << " created";
83 
84   memset(_paServerVersion, 0, sizeof(_paServerVersion));
85   memset(&_playBufferAttr, 0, sizeof(_playBufferAttr));
86   memset(&_recBufferAttr, 0, sizeof(_recBufferAttr));
87   memset(_oldKeyState, 0, sizeof(_oldKeyState));
88 }
89 
~AudioDeviceLinuxPulse()90 AudioDeviceLinuxPulse::~AudioDeviceLinuxPulse() {
91   RTC_DLOG(LS_INFO) << __FUNCTION__ << " destroyed";
92   RTC_DCHECK(thread_checker_.IsCurrent());
93   Terminate();
94 
95   if (_recBuffer) {
96     delete[] _recBuffer;
97     _recBuffer = NULL;
98   }
99   if (_playBuffer) {
100     delete[] _playBuffer;
101     _playBuffer = NULL;
102   }
103   if (_playDeviceName) {
104     delete[] _playDeviceName;
105     _playDeviceName = NULL;
106   }
107   if (_recDeviceName) {
108     delete[] _recDeviceName;
109     _recDeviceName = NULL;
110   }
111 }
112 
AttachAudioBuffer(AudioDeviceBuffer * audioBuffer)113 void AudioDeviceLinuxPulse::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) {
114   RTC_DCHECK(thread_checker_.IsCurrent());
115 
116   _ptrAudioBuffer = audioBuffer;
117 
118   // Inform the AudioBuffer about default settings for this implementation.
119   // Set all values to zero here since the actual settings will be done by
120   // InitPlayout and InitRecording later.
121   _ptrAudioBuffer->SetRecordingSampleRate(0);
122   _ptrAudioBuffer->SetPlayoutSampleRate(0);
123   _ptrAudioBuffer->SetRecordingChannels(0);
124   _ptrAudioBuffer->SetPlayoutChannels(0);
125 }
126 
127 // ----------------------------------------------------------------------------
128 //  ActiveAudioLayer
129 // ----------------------------------------------------------------------------
130 
ActiveAudioLayer(AudioDeviceModule::AudioLayer & audioLayer) const131 int32_t AudioDeviceLinuxPulse::ActiveAudioLayer(
132     AudioDeviceModule::AudioLayer& audioLayer) const {
133   audioLayer = AudioDeviceModule::kLinuxPulseAudio;
134   return 0;
135 }
136 
Init()137 AudioDeviceGeneric::InitStatus AudioDeviceLinuxPulse::Init() {
138   RTC_DCHECK(thread_checker_.IsCurrent());
139   if (_initialized) {
140     return InitStatus::OK;
141   }
142 
143   // Initialize PulseAudio
144   if (InitPulseAudio() < 0) {
145     RTC_LOG(LS_ERROR) << "failed to initialize PulseAudio";
146     if (TerminatePulseAudio() < 0) {
147       RTC_LOG(LS_ERROR) << "failed to terminate PulseAudio";
148     }
149     return InitStatus::OTHER_ERROR;
150   }
151 
152 #if defined(WEBRTC_USE_X11)
153   // Get X display handle for typing detection
154   _XDisplay = XOpenDisplay(NULL);
155   if (!_XDisplay) {
156     RTC_LOG(LS_WARNING)
157         << "failed to open X display, typing detection will not work";
158   }
159 #endif
160 
161   // RECORDING
162   const auto attributes =
163       rtc::ThreadAttributes().SetPriority(rtc::ThreadPriority::kRealtime);
164   _ptrThreadRec = rtc::PlatformThread::SpawnJoinable(
165       [this] {
166         while (RecThreadProcess()) {
167         }
168       },
169       "webrtc_audio_module_rec_thread", attributes);
170 
171   // PLAYOUT
172   _ptrThreadPlay = rtc::PlatformThread::SpawnJoinable(
173       [this] {
174         while (PlayThreadProcess()) {
175         }
176       },
177       "webrtc_audio_module_play_thread", attributes);
178   _initialized = true;
179 
180   return InitStatus::OK;
181 }
182 
Terminate()183 int32_t AudioDeviceLinuxPulse::Terminate() {
184   RTC_DCHECK(thread_checker_.IsCurrent());
185   if (!_initialized) {
186     return 0;
187   }
188   {
189     MutexLock lock(&mutex_);
190     quit_ = true;
191   }
192   _mixerManager.Close();
193 
194   // RECORDING
195   _timeEventRec.Set();
196   _ptrThreadRec.Finalize();
197 
198   // PLAYOUT
199   _timeEventPlay.Set();
200   _ptrThreadPlay.Finalize();
201 
202   // Terminate PulseAudio
203   if (TerminatePulseAudio() < 0) {
204     RTC_LOG(LS_ERROR) << "failed to terminate PulseAudio";
205     return -1;
206   }
207 
208 #if defined(WEBRTC_USE_X11)
209   if (_XDisplay) {
210     XCloseDisplay(_XDisplay);
211     _XDisplay = NULL;
212   }
213 #endif
214 
215   _initialized = false;
216   _outputDeviceIsSpecified = false;
217   _inputDeviceIsSpecified = false;
218 
219   return 0;
220 }
221 
Initialized() const222 bool AudioDeviceLinuxPulse::Initialized() const {
223   RTC_DCHECK(thread_checker_.IsCurrent());
224   return (_initialized);
225 }
226 
InitSpeaker()227 int32_t AudioDeviceLinuxPulse::InitSpeaker() {
228   RTC_DCHECK(thread_checker_.IsCurrent());
229 
230   if (_playing) {
231     return -1;
232   }
233 
234   if (!_outputDeviceIsSpecified) {
235     return -1;
236   }
237 
238   // check if default device
239   if (_outputDeviceIndex == 0) {
240     uint16_t deviceIndex = 0;
241     GetDefaultDeviceInfo(false, NULL, deviceIndex);
242     _paDeviceIndex = deviceIndex;
243   } else {
244     // get the PA device index from
245     // the callback
246     _deviceIndex = _outputDeviceIndex;
247 
248     // get playout devices
249     PlayoutDevices();
250   }
251 
252   // the callback has now set the _paDeviceIndex to
253   // the PulseAudio index of the device
254   if (_mixerManager.OpenSpeaker(_paDeviceIndex) == -1) {
255     return -1;
256   }
257 
258   // clear _deviceIndex
259   _deviceIndex = -1;
260   _paDeviceIndex = -1;
261 
262   return 0;
263 }
264 
InitMicrophone()265 int32_t AudioDeviceLinuxPulse::InitMicrophone() {
266   RTC_DCHECK(thread_checker_.IsCurrent());
267   if (_recording) {
268     return -1;
269   }
270 
271   if (!_inputDeviceIsSpecified) {
272     return -1;
273   }
274 
275   // Check if default device
276   if (_inputDeviceIndex == 0) {
277     uint16_t deviceIndex = 0;
278     GetDefaultDeviceInfo(true, NULL, deviceIndex);
279     _paDeviceIndex = deviceIndex;
280   } else {
281     // Get the PA device index from
282     // the callback
283     _deviceIndex = _inputDeviceIndex;
284 
285     // get recording devices
286     RecordingDevices();
287   }
288 
289   // The callback has now set the _paDeviceIndex to
290   // the PulseAudio index of the device
291   if (_mixerManager.OpenMicrophone(_paDeviceIndex) == -1) {
292     return -1;
293   }
294 
295   // Clear _deviceIndex
296   _deviceIndex = -1;
297   _paDeviceIndex = -1;
298 
299   return 0;
300 }
301 
SpeakerIsInitialized() const302 bool AudioDeviceLinuxPulse::SpeakerIsInitialized() const {
303   RTC_DCHECK(thread_checker_.IsCurrent());
304   return (_mixerManager.SpeakerIsInitialized());
305 }
306 
MicrophoneIsInitialized() const307 bool AudioDeviceLinuxPulse::MicrophoneIsInitialized() const {
308   RTC_DCHECK(thread_checker_.IsCurrent());
309   return (_mixerManager.MicrophoneIsInitialized());
310 }
311 
SpeakerVolumeIsAvailable(bool & available)312 int32_t AudioDeviceLinuxPulse::SpeakerVolumeIsAvailable(bool& available) {
313   RTC_DCHECK(thread_checker_.IsCurrent());
314   bool wasInitialized = _mixerManager.SpeakerIsInitialized();
315 
316   // Make an attempt to open up the
317   // output mixer corresponding to the currently selected output device.
318   if (!wasInitialized && InitSpeaker() == -1) {
319     // If we end up here it means that the selected speaker has no volume
320     // control.
321     available = false;
322     return 0;
323   }
324 
325   // Given that InitSpeaker was successful, we know volume control exists.
326   available = true;
327 
328   // Close the initialized output mixer
329   if (!wasInitialized) {
330     _mixerManager.CloseSpeaker();
331   }
332 
333   return 0;
334 }
335 
SetSpeakerVolume(uint32_t volume)336 int32_t AudioDeviceLinuxPulse::SetSpeakerVolume(uint32_t volume) {
337   RTC_DCHECK(thread_checker_.IsCurrent());
338   if (!_playing) {
339     // Only update the volume if it's been set while we weren't playing.
340     update_speaker_volume_at_startup_ = true;
341   }
342   return (_mixerManager.SetSpeakerVolume(volume));
343 }
344 
SpeakerVolume(uint32_t & volume) const345 int32_t AudioDeviceLinuxPulse::SpeakerVolume(uint32_t& volume) const {
346   RTC_DCHECK(thread_checker_.IsCurrent());
347   uint32_t level(0);
348 
349   if (_mixerManager.SpeakerVolume(level) == -1) {
350     return -1;
351   }
352 
353   volume = level;
354 
355   return 0;
356 }
357 
MaxSpeakerVolume(uint32_t & maxVolume) const358 int32_t AudioDeviceLinuxPulse::MaxSpeakerVolume(uint32_t& maxVolume) const {
359   RTC_DCHECK(thread_checker_.IsCurrent());
360   uint32_t maxVol(0);
361 
362   if (_mixerManager.MaxSpeakerVolume(maxVol) == -1) {
363     return -1;
364   }
365 
366   maxVolume = maxVol;
367 
368   return 0;
369 }
370 
MinSpeakerVolume(uint32_t & minVolume) const371 int32_t AudioDeviceLinuxPulse::MinSpeakerVolume(uint32_t& minVolume) const {
372   RTC_DCHECK(thread_checker_.IsCurrent());
373   uint32_t minVol(0);
374 
375   if (_mixerManager.MinSpeakerVolume(minVol) == -1) {
376     return -1;
377   }
378 
379   minVolume = minVol;
380 
381   return 0;
382 }
383 
SpeakerMuteIsAvailable(bool & available)384 int32_t AudioDeviceLinuxPulse::SpeakerMuteIsAvailable(bool& available) {
385   RTC_DCHECK(thread_checker_.IsCurrent());
386   bool isAvailable(false);
387   bool wasInitialized = _mixerManager.SpeakerIsInitialized();
388 
389   // Make an attempt to open up the
390   // output mixer corresponding to the currently selected output device.
391   //
392   if (!wasInitialized && InitSpeaker() == -1) {
393     // If we end up here it means that the selected speaker has no volume
394     // control, hence it is safe to state that there is no mute control
395     // already at this stage.
396     available = false;
397     return 0;
398   }
399 
400   // Check if the selected speaker has a mute control
401   _mixerManager.SpeakerMuteIsAvailable(isAvailable);
402 
403   available = isAvailable;
404 
405   // Close the initialized output mixer
406   if (!wasInitialized) {
407     _mixerManager.CloseSpeaker();
408   }
409 
410   return 0;
411 }
412 
SetSpeakerMute(bool enable)413 int32_t AudioDeviceLinuxPulse::SetSpeakerMute(bool enable) {
414   RTC_DCHECK(thread_checker_.IsCurrent());
415   return (_mixerManager.SetSpeakerMute(enable));
416 }
417 
SpeakerMute(bool & enabled) const418 int32_t AudioDeviceLinuxPulse::SpeakerMute(bool& enabled) const {
419   RTC_DCHECK(thread_checker_.IsCurrent());
420   bool muted(0);
421   if (_mixerManager.SpeakerMute(muted) == -1) {
422     return -1;
423   }
424 
425   enabled = muted;
426   return 0;
427 }
428 
MicrophoneMuteIsAvailable(bool & available)429 int32_t AudioDeviceLinuxPulse::MicrophoneMuteIsAvailable(bool& available) {
430   RTC_DCHECK(thread_checker_.IsCurrent());
431   bool isAvailable(false);
432   bool wasInitialized = _mixerManager.MicrophoneIsInitialized();
433 
434   // Make an attempt to open up the
435   // input mixer corresponding to the currently selected input device.
436   //
437   if (!wasInitialized && InitMicrophone() == -1) {
438     // If we end up here it means that the selected microphone has no
439     // volume control, hence it is safe to state that there is no
440     // boost control already at this stage.
441     available = false;
442     return 0;
443   }
444 
445   // Check if the selected microphone has a mute control
446   //
447   _mixerManager.MicrophoneMuteIsAvailable(isAvailable);
448   available = isAvailable;
449 
450   // Close the initialized input mixer
451   //
452   if (!wasInitialized) {
453     _mixerManager.CloseMicrophone();
454   }
455 
456   return 0;
457 }
458 
SetMicrophoneMute(bool enable)459 int32_t AudioDeviceLinuxPulse::SetMicrophoneMute(bool enable) {
460   RTC_DCHECK(thread_checker_.IsCurrent());
461   return (_mixerManager.SetMicrophoneMute(enable));
462 }
463 
MicrophoneMute(bool & enabled) const464 int32_t AudioDeviceLinuxPulse::MicrophoneMute(bool& enabled) const {
465   RTC_DCHECK(thread_checker_.IsCurrent());
466   bool muted(0);
467   if (_mixerManager.MicrophoneMute(muted) == -1) {
468     return -1;
469   }
470 
471   enabled = muted;
472   return 0;
473 }
474 
StereoRecordingIsAvailable(bool & available)475 int32_t AudioDeviceLinuxPulse::StereoRecordingIsAvailable(bool& available) {
476   RTC_DCHECK(thread_checker_.IsCurrent());
477   if (_recChannels == 2 && _recording) {
478     available = true;
479     return 0;
480   }
481 
482   available = false;
483   bool wasInitialized = _mixerManager.MicrophoneIsInitialized();
484   int error = 0;
485 
486   if (!wasInitialized && InitMicrophone() == -1) {
487     // Cannot open the specified device
488     available = false;
489     return 0;
490   }
491 
492   // Check if the selected microphone can record stereo.
493   bool isAvailable(false);
494   error = _mixerManager.StereoRecordingIsAvailable(isAvailable);
495   if (!error)
496     available = isAvailable;
497 
498   // Close the initialized input mixer
499   if (!wasInitialized) {
500     _mixerManager.CloseMicrophone();
501   }
502 
503   return error;
504 }
505 
SetStereoRecording(bool enable)506 int32_t AudioDeviceLinuxPulse::SetStereoRecording(bool enable) {
507   RTC_DCHECK(thread_checker_.IsCurrent());
508   if (enable)
509     _recChannels = 2;
510   else
511     _recChannels = 1;
512 
513   return 0;
514 }
515 
StereoRecording(bool & enabled) const516 int32_t AudioDeviceLinuxPulse::StereoRecording(bool& enabled) const {
517   RTC_DCHECK(thread_checker_.IsCurrent());
518   if (_recChannels == 2)
519     enabled = true;
520   else
521     enabled = false;
522 
523   return 0;
524 }
525 
StereoPlayoutIsAvailable(bool & available)526 int32_t AudioDeviceLinuxPulse::StereoPlayoutIsAvailable(bool& available) {
527   RTC_DCHECK(thread_checker_.IsCurrent());
528   if (_playChannels == 2 && _playing) {
529     available = true;
530     return 0;
531   }
532 
533   available = false;
534   bool wasInitialized = _mixerManager.SpeakerIsInitialized();
535   int error = 0;
536 
537   if (!wasInitialized && InitSpeaker() == -1) {
538     // Cannot open the specified device.
539     return -1;
540   }
541 
542   // Check if the selected speaker can play stereo.
543   bool isAvailable(false);
544   error = _mixerManager.StereoPlayoutIsAvailable(isAvailable);
545   if (!error)
546     available = isAvailable;
547 
548   // Close the initialized input mixer
549   if (!wasInitialized) {
550     _mixerManager.CloseSpeaker();
551   }
552 
553   return error;
554 }
555 
SetStereoPlayout(bool enable)556 int32_t AudioDeviceLinuxPulse::SetStereoPlayout(bool enable) {
557   RTC_DCHECK(thread_checker_.IsCurrent());
558   if (enable)
559     _playChannels = 2;
560   else
561     _playChannels = 1;
562 
563   return 0;
564 }
565 
StereoPlayout(bool & enabled) const566 int32_t AudioDeviceLinuxPulse::StereoPlayout(bool& enabled) const {
567   RTC_DCHECK(thread_checker_.IsCurrent());
568   if (_playChannels == 2)
569     enabled = true;
570   else
571     enabled = false;
572 
573   return 0;
574 }
575 
MicrophoneVolumeIsAvailable(bool & available)576 int32_t AudioDeviceLinuxPulse::MicrophoneVolumeIsAvailable(bool& available) {
577   RTC_DCHECK(thread_checker_.IsCurrent());
578   bool wasInitialized = _mixerManager.MicrophoneIsInitialized();
579 
580   // Make an attempt to open up the
581   // input mixer corresponding to the currently selected output device.
582   if (!wasInitialized && InitMicrophone() == -1) {
583     // If we end up here it means that the selected microphone has no
584     // volume control.
585     available = false;
586     return 0;
587   }
588 
589   // Given that InitMicrophone was successful, we know that a volume control
590   // exists.
591   available = true;
592 
593   // Close the initialized input mixer
594   if (!wasInitialized) {
595     _mixerManager.CloseMicrophone();
596   }
597 
598   return 0;
599 }
600 
SetMicrophoneVolume(uint32_t volume)601 int32_t AudioDeviceLinuxPulse::SetMicrophoneVolume(uint32_t volume) {
602   return (_mixerManager.SetMicrophoneVolume(volume));
603 }
604 
MicrophoneVolume(uint32_t & volume) const605 int32_t AudioDeviceLinuxPulse::MicrophoneVolume(uint32_t& volume) const {
606   uint32_t level(0);
607 
608   if (_mixerManager.MicrophoneVolume(level) == -1) {
609     RTC_LOG(LS_WARNING) << "failed to retrieve current microphone level";
610     return -1;
611   }
612 
613   volume = level;
614 
615   return 0;
616 }
617 
MaxMicrophoneVolume(uint32_t & maxVolume) const618 int32_t AudioDeviceLinuxPulse::MaxMicrophoneVolume(uint32_t& maxVolume) const {
619   uint32_t maxVol(0);
620 
621   if (_mixerManager.MaxMicrophoneVolume(maxVol) == -1) {
622     return -1;
623   }
624 
625   maxVolume = maxVol;
626 
627   return 0;
628 }
629 
MinMicrophoneVolume(uint32_t & minVolume) const630 int32_t AudioDeviceLinuxPulse::MinMicrophoneVolume(uint32_t& minVolume) const {
631   uint32_t minVol(0);
632 
633   if (_mixerManager.MinMicrophoneVolume(minVol) == -1) {
634     return -1;
635   }
636 
637   minVolume = minVol;
638 
639   return 0;
640 }
641 
PlayoutDevices()642 int16_t AudioDeviceLinuxPulse::PlayoutDevices() {
643   PaLock();
644 
645   pa_operation* paOperation = NULL;
646   _numPlayDevices = 1;  // init to 1 to account for "default"
647 
648   // get the whole list of devices and update _numPlayDevices
649   paOperation =
650       LATE(pa_context_get_sink_info_list)(_paContext, PaSinkInfoCallback, this);
651 
652   WaitForOperationCompletion(paOperation);
653 
654   PaUnLock();
655 
656   return _numPlayDevices;
657 }
658 
SetPlayoutDevice(uint16_t index)659 int32_t AudioDeviceLinuxPulse::SetPlayoutDevice(uint16_t index) {
660   RTC_DCHECK(thread_checker_.IsCurrent());
661   if (_playIsInitialized) {
662     return -1;
663   }
664 
665   const uint16_t nDevices = PlayoutDevices();
666 
667   RTC_LOG(LS_VERBOSE) << "number of availiable output devices is " << nDevices;
668 
669   if (index > (nDevices - 1)) {
670     RTC_LOG(LS_ERROR) << "device index is out of range [0," << (nDevices - 1)
671                       << "]";
672     return -1;
673   }
674 
675   _outputDeviceIndex = index;
676   _outputDeviceIsSpecified = true;
677 
678   return 0;
679 }
680 
SetPlayoutDevice(AudioDeviceModule::WindowsDeviceType)681 int32_t AudioDeviceLinuxPulse::SetPlayoutDevice(
682     AudioDeviceModule::WindowsDeviceType /*device*/) {
683   RTC_LOG(LS_ERROR) << "WindowsDeviceType not supported";
684   return -1;
685 }
686 
PlayoutDeviceName(uint16_t index,char name[kAdmMaxDeviceNameSize],char guid[kAdmMaxGuidSize])687 int32_t AudioDeviceLinuxPulse::PlayoutDeviceName(
688     uint16_t index,
689     char name[kAdmMaxDeviceNameSize],
690     char guid[kAdmMaxGuidSize]) {
691   RTC_DCHECK(thread_checker_.IsCurrent());
692   const uint16_t nDevices = PlayoutDevices();
693 
694   if ((index > (nDevices - 1)) || (name == NULL)) {
695     return -1;
696   }
697 
698   memset(name, 0, kAdmMaxDeviceNameSize);
699 
700   if (guid != NULL) {
701     memset(guid, 0, kAdmMaxGuidSize);
702   }
703 
704   // Check if default device
705   if (index == 0) {
706     uint16_t deviceIndex = 0;
707     return GetDefaultDeviceInfo(false, name, deviceIndex);
708   }
709 
710   // Tell the callback that we want
711   // The name for this device
712   _playDisplayDeviceName = name;
713   _deviceIndex = index;
714 
715   // get playout devices
716   PlayoutDevices();
717 
718   // clear device name and index
719   _playDisplayDeviceName = NULL;
720   _deviceIndex = -1;
721 
722   return 0;
723 }
724 
RecordingDeviceName(uint16_t index,char name[kAdmMaxDeviceNameSize],char guid[kAdmMaxGuidSize])725 int32_t AudioDeviceLinuxPulse::RecordingDeviceName(
726     uint16_t index,
727     char name[kAdmMaxDeviceNameSize],
728     char guid[kAdmMaxGuidSize]) {
729   RTC_DCHECK(thread_checker_.IsCurrent());
730   const uint16_t nDevices(RecordingDevices());
731 
732   if ((index > (nDevices - 1)) || (name == NULL)) {
733     return -1;
734   }
735 
736   memset(name, 0, kAdmMaxDeviceNameSize);
737 
738   if (guid != NULL) {
739     memset(guid, 0, kAdmMaxGuidSize);
740   }
741 
742   // Check if default device
743   if (index == 0) {
744     uint16_t deviceIndex = 0;
745     return GetDefaultDeviceInfo(true, name, deviceIndex);
746   }
747 
748   // Tell the callback that we want
749   // the name for this device
750   _recDisplayDeviceName = name;
751   _deviceIndex = index;
752 
753   // Get recording devices
754   RecordingDevices();
755 
756   // Clear device name and index
757   _recDisplayDeviceName = NULL;
758   _deviceIndex = -1;
759 
760   return 0;
761 }
762 
RecordingDevices()763 int16_t AudioDeviceLinuxPulse::RecordingDevices() {
764   PaLock();
765 
766   pa_operation* paOperation = NULL;
767   _numRecDevices = 1;  // Init to 1 to account for "default"
768 
769   // Get the whole list of devices and update _numRecDevices
770   paOperation = LATE(pa_context_get_source_info_list)(
771       _paContext, PaSourceInfoCallback, this);
772 
773   WaitForOperationCompletion(paOperation);
774 
775   PaUnLock();
776 
777   return _numRecDevices;
778 }
779 
SetRecordingDevice(uint16_t index)780 int32_t AudioDeviceLinuxPulse::SetRecordingDevice(uint16_t index) {
781   RTC_DCHECK(thread_checker_.IsCurrent());
782   if (_recIsInitialized) {
783     return -1;
784   }
785 
786   const uint16_t nDevices(RecordingDevices());
787 
788   RTC_LOG(LS_VERBOSE) << "number of availiable input devices is " << nDevices;
789 
790   if (index > (nDevices - 1)) {
791     RTC_LOG(LS_ERROR) << "device index is out of range [0," << (nDevices - 1)
792                       << "]";
793     return -1;
794   }
795 
796   _inputDeviceIndex = index;
797   _inputDeviceIsSpecified = true;
798 
799   return 0;
800 }
801 
SetRecordingDevice(AudioDeviceModule::WindowsDeviceType)802 int32_t AudioDeviceLinuxPulse::SetRecordingDevice(
803     AudioDeviceModule::WindowsDeviceType /*device*/) {
804   RTC_LOG(LS_ERROR) << "WindowsDeviceType not supported";
805   return -1;
806 }
807 
PlayoutIsAvailable(bool & available)808 int32_t AudioDeviceLinuxPulse::PlayoutIsAvailable(bool& available) {
809   RTC_DCHECK(thread_checker_.IsCurrent());
810   available = false;
811 
812   // Try to initialize the playout side
813   int32_t res = InitPlayout();
814 
815   // Cancel effect of initialization
816   StopPlayout();
817 
818   if (res != -1) {
819     available = true;
820   }
821 
822   return res;
823 }
824 
RecordingIsAvailable(bool & available)825 int32_t AudioDeviceLinuxPulse::RecordingIsAvailable(bool& available) {
826   RTC_DCHECK(thread_checker_.IsCurrent());
827   available = false;
828 
829   // Try to initialize the playout side
830   int32_t res = InitRecording();
831 
832   // Cancel effect of initialization
833   StopRecording();
834 
835   if (res != -1) {
836     available = true;
837   }
838 
839   return res;
840 }
841 
InitPlayout()842 int32_t AudioDeviceLinuxPulse::InitPlayout() {
843   RTC_DCHECK(thread_checker_.IsCurrent());
844 
845   if (_playing) {
846     return -1;
847   }
848 
849   if (!_outputDeviceIsSpecified) {
850     return -1;
851   }
852 
853   if (_playIsInitialized) {
854     return 0;
855   }
856 
857   // Initialize the speaker (devices might have been added or removed)
858   if (InitSpeaker() == -1) {
859     RTC_LOG(LS_WARNING) << "InitSpeaker() failed";
860   }
861 
862   // Set the play sample specification
863   pa_sample_spec playSampleSpec;
864   playSampleSpec.channels = _playChannels;
865   playSampleSpec.format = PA_SAMPLE_S16LE;
866   playSampleSpec.rate = sample_rate_hz_;
867 
868   // Create a new play stream
869   {
870     MutexLock lock(&mutex_);
871     _playStream =
872         LATE(pa_stream_new)(_paContext, "playStream", &playSampleSpec, NULL);
873   }
874 
875   if (!_playStream) {
876     RTC_LOG(LS_ERROR) << "failed to create play stream, err="
877                       << LATE(pa_context_errno)(_paContext);
878     return -1;
879   }
880 
881   // Provide the playStream to the mixer
882   _mixerManager.SetPlayStream(_playStream);
883 
884   if (_ptrAudioBuffer) {
885     // Update audio buffer with the selected parameters
886     _ptrAudioBuffer->SetPlayoutSampleRate(sample_rate_hz_);
887     _ptrAudioBuffer->SetPlayoutChannels((uint8_t)_playChannels);
888   }
889 
890   RTC_LOG(LS_VERBOSE) << "stream state "
891                       << LATE(pa_stream_get_state)(_playStream);
892 
893   // Set stream flags
894   _playStreamFlags = (pa_stream_flags_t)(PA_STREAM_AUTO_TIMING_UPDATE |
895                                          PA_STREAM_INTERPOLATE_TIMING);
896 
897   if (_configuredLatencyPlay != WEBRTC_PA_NO_LATENCY_REQUIREMENTS) {
898     // If configuring a specific latency then we want to specify
899     // PA_STREAM_ADJUST_LATENCY to make the server adjust parameters
900     // automatically to reach that target latency. However, that flag
901     // doesn't exist in Ubuntu 8.04 and many people still use that,
902     // so we have to check the protocol version of libpulse.
903     if (LATE(pa_context_get_protocol_version)(_paContext) >=
904         WEBRTC_PA_ADJUST_LATENCY_PROTOCOL_VERSION) {
905       _playStreamFlags |= PA_STREAM_ADJUST_LATENCY;
906     }
907 
908     const pa_sample_spec* spec = LATE(pa_stream_get_sample_spec)(_playStream);
909     if (!spec) {
910       RTC_LOG(LS_ERROR) << "pa_stream_get_sample_spec()";
911       return -1;
912     }
913 
914     size_t bytesPerSec = LATE(pa_bytes_per_second)(spec);
915     uint32_t latency = bytesPerSec * WEBRTC_PA_PLAYBACK_LATENCY_MINIMUM_MSECS /
916                        WEBRTC_PA_MSECS_PER_SEC;
917 
918     // Set the play buffer attributes
919     _playBufferAttr.maxlength = latency;  // num bytes stored in the buffer
920     _playBufferAttr.tlength = latency;    // target fill level of play buffer
921     // minimum free num bytes before server request more data
922     _playBufferAttr.minreq = latency / WEBRTC_PA_PLAYBACK_REQUEST_FACTOR;
923     // prebuffer tlength before starting playout
924     _playBufferAttr.prebuf = _playBufferAttr.tlength - _playBufferAttr.minreq;
925 
926     _configuredLatencyPlay = latency;
927   }
928 
929   // num samples in bytes * num channels
930   _playbackBufferSize = sample_rate_hz_ / 100 * 2 * _playChannels;
931   _playbackBufferUnused = _playbackBufferSize;
932   _playBuffer = new int8_t[_playbackBufferSize];
933 
934   // Enable underflow callback
935   LATE(pa_stream_set_underflow_callback)
936   (_playStream, PaStreamUnderflowCallback, this);
937 
938   // Set the state callback function for the stream
939   LATE(pa_stream_set_state_callback)(_playStream, PaStreamStateCallback, this);
940 
941   // Mark playout side as initialized
942   {
943     MutexLock lock(&mutex_);
944     _playIsInitialized = true;
945     _sndCardPlayDelay = 0;
946   }
947 
948   return 0;
949 }
950 
InitRecording()951 int32_t AudioDeviceLinuxPulse::InitRecording() {
952   RTC_DCHECK(thread_checker_.IsCurrent());
953 
954   if (_recording) {
955     return -1;
956   }
957 
958   if (!_inputDeviceIsSpecified) {
959     return -1;
960   }
961 
962   if (_recIsInitialized) {
963     return 0;
964   }
965 
966   // Initialize the microphone (devices might have been added or removed)
967   if (InitMicrophone() == -1) {
968     RTC_LOG(LS_WARNING) << "InitMicrophone() failed";
969   }
970 
971   // Set the rec sample specification
972   pa_sample_spec recSampleSpec;
973   recSampleSpec.channels = _recChannels;
974   recSampleSpec.format = PA_SAMPLE_S16LE;
975   recSampleSpec.rate = sample_rate_hz_;
976 
977   // Create a new rec stream
978   _recStream =
979       LATE(pa_stream_new)(_paContext, "recStream", &recSampleSpec, NULL);
980   if (!_recStream) {
981     RTC_LOG(LS_ERROR) << "failed to create rec stream, err="
982                       << LATE(pa_context_errno)(_paContext);
983     return -1;
984   }
985 
986   // Provide the recStream to the mixer
987   _mixerManager.SetRecStream(_recStream);
988 
989   if (_ptrAudioBuffer) {
990     // Update audio buffer with the selected parameters
991     _ptrAudioBuffer->SetRecordingSampleRate(sample_rate_hz_);
992     _ptrAudioBuffer->SetRecordingChannels((uint8_t)_recChannels);
993   }
994 
995   if (_configuredLatencyRec != WEBRTC_PA_NO_LATENCY_REQUIREMENTS) {
996     _recStreamFlags = (pa_stream_flags_t)(PA_STREAM_AUTO_TIMING_UPDATE |
997                                           PA_STREAM_INTERPOLATE_TIMING);
998 
999     // If configuring a specific latency then we want to specify
1000     // PA_STREAM_ADJUST_LATENCY to make the server adjust parameters
1001     // automatically to reach that target latency. However, that flag
1002     // doesn't exist in Ubuntu 8.04 and many people still use that,
1003     //  so we have to check the protocol version of libpulse.
1004     if (LATE(pa_context_get_protocol_version)(_paContext) >=
1005         WEBRTC_PA_ADJUST_LATENCY_PROTOCOL_VERSION) {
1006       _recStreamFlags |= PA_STREAM_ADJUST_LATENCY;
1007     }
1008 
1009     const pa_sample_spec* spec = LATE(pa_stream_get_sample_spec)(_recStream);
1010     if (!spec) {
1011       RTC_LOG(LS_ERROR) << "pa_stream_get_sample_spec(rec)";
1012       return -1;
1013     }
1014 
1015     size_t bytesPerSec = LATE(pa_bytes_per_second)(spec);
1016     uint32_t latency = bytesPerSec * WEBRTC_PA_LOW_CAPTURE_LATENCY_MSECS /
1017                        WEBRTC_PA_MSECS_PER_SEC;
1018 
1019     // Set the rec buffer attributes
1020     // Note: fragsize specifies a maximum transfer size, not a minimum, so
1021     // it is not possible to force a high latency setting, only a low one.
1022     _recBufferAttr.fragsize = latency;  // size of fragment
1023     _recBufferAttr.maxlength =
1024         latency + bytesPerSec * WEBRTC_PA_CAPTURE_BUFFER_EXTRA_MSECS /
1025                       WEBRTC_PA_MSECS_PER_SEC;
1026 
1027     _configuredLatencyRec = latency;
1028   }
1029 
1030   _recordBufferSize = sample_rate_hz_ / 100 * 2 * _recChannels;
1031   _recordBufferUsed = 0;
1032   _recBuffer = new int8_t[_recordBufferSize];
1033 
1034   // Enable overflow callback
1035   LATE(pa_stream_set_overflow_callback)
1036   (_recStream, PaStreamOverflowCallback, this);
1037 
1038   // Set the state callback function for the stream
1039   LATE(pa_stream_set_state_callback)(_recStream, PaStreamStateCallback, this);
1040 
1041   // Mark recording side as initialized
1042   _recIsInitialized = true;
1043 
1044   return 0;
1045 }
1046 
StartRecording()1047 int32_t AudioDeviceLinuxPulse::StartRecording() {
1048   RTC_DCHECK(thread_checker_.IsCurrent());
1049   if (!_recIsInitialized) {
1050     return -1;
1051   }
1052 
1053   if (_recording) {
1054     return 0;
1055   }
1056 
1057   // Set state to ensure that the recording starts from the audio thread.
1058   _startRec = true;
1059 
1060   // The audio thread will signal when recording has started.
1061   _timeEventRec.Set();
1062   if (!_recStartEvent.Wait(TimeDelta::Seconds(10))) {
1063     {
1064       MutexLock lock(&mutex_);
1065       _startRec = false;
1066     }
1067     StopRecording();
1068     RTC_LOG(LS_ERROR) << "failed to activate recording";
1069     return -1;
1070   }
1071 
1072   {
1073     MutexLock lock(&mutex_);
1074     if (_recording) {
1075       // The recording state is set by the audio thread after recording
1076       // has started.
1077     } else {
1078       RTC_LOG(LS_ERROR) << "failed to activate recording";
1079       return -1;
1080     }
1081   }
1082 
1083   return 0;
1084 }
1085 
StopRecording()1086 int32_t AudioDeviceLinuxPulse::StopRecording() {
1087   RTC_DCHECK(thread_checker_.IsCurrent());
1088   MutexLock lock(&mutex_);
1089 
1090   if (!_recIsInitialized) {
1091     return 0;
1092   }
1093 
1094   if (_recStream == NULL) {
1095     return -1;
1096   }
1097 
1098   _recIsInitialized = false;
1099   _recording = false;
1100 
1101   RTC_LOG(LS_VERBOSE) << "stopping recording";
1102 
1103   // Stop Recording
1104   PaLock();
1105 
1106   DisableReadCallback();
1107   LATE(pa_stream_set_overflow_callback)(_recStream, NULL, NULL);
1108 
1109   // Unset this here so that we don't get a TERMINATED callback
1110   LATE(pa_stream_set_state_callback)(_recStream, NULL, NULL);
1111 
1112   if (LATE(pa_stream_get_state)(_recStream) != PA_STREAM_UNCONNECTED) {
1113     // Disconnect the stream
1114     if (LATE(pa_stream_disconnect)(_recStream) != PA_OK) {
1115       RTC_LOG(LS_ERROR) << "failed to disconnect rec stream, err="
1116                         << LATE(pa_context_errno)(_paContext);
1117       PaUnLock();
1118       return -1;
1119     }
1120 
1121     RTC_LOG(LS_VERBOSE) << "disconnected recording";
1122   }
1123 
1124   LATE(pa_stream_unref)(_recStream);
1125   _recStream = NULL;
1126 
1127   PaUnLock();
1128 
1129   // Provide the recStream to the mixer
1130   _mixerManager.SetRecStream(_recStream);
1131 
1132   if (_recBuffer) {
1133     delete[] _recBuffer;
1134     _recBuffer = NULL;
1135   }
1136 
1137   return 0;
1138 }
1139 
RecordingIsInitialized() const1140 bool AudioDeviceLinuxPulse::RecordingIsInitialized() const {
1141   RTC_DCHECK(thread_checker_.IsCurrent());
1142   return (_recIsInitialized);
1143 }
1144 
Recording() const1145 bool AudioDeviceLinuxPulse::Recording() const {
1146   RTC_DCHECK(thread_checker_.IsCurrent());
1147   return (_recording);
1148 }
1149 
PlayoutIsInitialized() const1150 bool AudioDeviceLinuxPulse::PlayoutIsInitialized() const {
1151   RTC_DCHECK(thread_checker_.IsCurrent());
1152   return (_playIsInitialized);
1153 }
1154 
StartPlayout()1155 int32_t AudioDeviceLinuxPulse::StartPlayout() {
1156   RTC_DCHECK(thread_checker_.IsCurrent());
1157 
1158   if (!_playIsInitialized) {
1159     return -1;
1160   }
1161 
1162   if (_playing) {
1163     return 0;
1164   }
1165 
1166   // Set state to ensure that playout starts from the audio thread.
1167   {
1168     MutexLock lock(&mutex_);
1169     _startPlay = true;
1170   }
1171 
1172   // Both `_startPlay` and `_playing` needs protction since they are also
1173   // accessed on the playout thread.
1174 
1175   // The audio thread will signal when playout has started.
1176   _timeEventPlay.Set();
1177   if (!_playStartEvent.Wait(TimeDelta::Seconds(10))) {
1178     {
1179       MutexLock lock(&mutex_);
1180       _startPlay = false;
1181     }
1182     StopPlayout();
1183     RTC_LOG(LS_ERROR) << "failed to activate playout";
1184     return -1;
1185   }
1186 
1187   {
1188     MutexLock lock(&mutex_);
1189     if (_playing) {
1190       // The playing state is set by the audio thread after playout
1191       // has started.
1192     } else {
1193       RTC_LOG(LS_ERROR) << "failed to activate playing";
1194       return -1;
1195     }
1196   }
1197 
1198   return 0;
1199 }
1200 
StopPlayout()1201 int32_t AudioDeviceLinuxPulse::StopPlayout() {
1202   RTC_DCHECK(thread_checker_.IsCurrent());
1203   MutexLock lock(&mutex_);
1204 
1205   if (!_playIsInitialized) {
1206     return 0;
1207   }
1208 
1209   if (_playStream == NULL) {
1210     return -1;
1211   }
1212 
1213   _playIsInitialized = false;
1214   _playing = false;
1215   _sndCardPlayDelay = 0;
1216 
1217   RTC_LOG(LS_VERBOSE) << "stopping playback";
1218 
1219   // Stop Playout
1220   PaLock();
1221 
1222   DisableWriteCallback();
1223   LATE(pa_stream_set_underflow_callback)(_playStream, NULL, NULL);
1224 
1225   // Unset this here so that we don't get a TERMINATED callback
1226   LATE(pa_stream_set_state_callback)(_playStream, NULL, NULL);
1227 
1228   if (LATE(pa_stream_get_state)(_playStream) != PA_STREAM_UNCONNECTED) {
1229     // Disconnect the stream
1230     if (LATE(pa_stream_disconnect)(_playStream) != PA_OK) {
1231       RTC_LOG(LS_ERROR) << "failed to disconnect play stream, err="
1232                         << LATE(pa_context_errno)(_paContext);
1233       PaUnLock();
1234       return -1;
1235     }
1236 
1237     RTC_LOG(LS_VERBOSE) << "disconnected playback";
1238   }
1239 
1240   LATE(pa_stream_unref)(_playStream);
1241   _playStream = NULL;
1242 
1243   PaUnLock();
1244 
1245   // Provide the playStream to the mixer
1246   _mixerManager.SetPlayStream(_playStream);
1247 
1248   if (_playBuffer) {
1249     delete[] _playBuffer;
1250     _playBuffer = NULL;
1251   }
1252 
1253   return 0;
1254 }
1255 
PlayoutDelay(uint16_t & delayMS) const1256 int32_t AudioDeviceLinuxPulse::PlayoutDelay(uint16_t& delayMS) const {
1257   MutexLock lock(&mutex_);
1258   delayMS = (uint16_t)_sndCardPlayDelay;
1259   return 0;
1260 }
1261 
Playing() const1262 bool AudioDeviceLinuxPulse::Playing() const {
1263   RTC_DCHECK(thread_checker_.IsCurrent());
1264   return (_playing);
1265 }
1266 
1267 // ============================================================================
1268 //                                 Private Methods
1269 // ============================================================================
1270 
PaContextStateCallback(pa_context * c,void * pThis)1271 void AudioDeviceLinuxPulse::PaContextStateCallback(pa_context* c, void* pThis) {
1272   static_cast<AudioDeviceLinuxPulse*>(pThis)->PaContextStateCallbackHandler(c);
1273 }
1274 
1275 // ----------------------------------------------------------------------------
1276 //  PaSinkInfoCallback
1277 // ----------------------------------------------------------------------------
1278 
PaSinkInfoCallback(pa_context *,const pa_sink_info * i,int eol,void * pThis)1279 void AudioDeviceLinuxPulse::PaSinkInfoCallback(pa_context* /*c*/,
1280                                                const pa_sink_info* i,
1281                                                int eol,
1282                                                void* pThis) {
1283   static_cast<AudioDeviceLinuxPulse*>(pThis)->PaSinkInfoCallbackHandler(i, eol);
1284 }
1285 
PaSourceInfoCallback(pa_context *,const pa_source_info * i,int eol,void * pThis)1286 void AudioDeviceLinuxPulse::PaSourceInfoCallback(pa_context* /*c*/,
1287                                                  const pa_source_info* i,
1288                                                  int eol,
1289                                                  void* pThis) {
1290   static_cast<AudioDeviceLinuxPulse*>(pThis)->PaSourceInfoCallbackHandler(i,
1291                                                                           eol);
1292 }
1293 
PaServerInfoCallback(pa_context *,const pa_server_info * i,void * pThis)1294 void AudioDeviceLinuxPulse::PaServerInfoCallback(pa_context* /*c*/,
1295                                                  const pa_server_info* i,
1296                                                  void* pThis) {
1297   static_cast<AudioDeviceLinuxPulse*>(pThis)->PaServerInfoCallbackHandler(i);
1298 }
1299 
PaStreamStateCallback(pa_stream * p,void * pThis)1300 void AudioDeviceLinuxPulse::PaStreamStateCallback(pa_stream* p, void* pThis) {
1301   static_cast<AudioDeviceLinuxPulse*>(pThis)->PaStreamStateCallbackHandler(p);
1302 }
1303 
PaContextStateCallbackHandler(pa_context * c)1304 void AudioDeviceLinuxPulse::PaContextStateCallbackHandler(pa_context* c) {
1305   RTC_LOG(LS_VERBOSE) << "context state cb";
1306 
1307   pa_context_state_t state = LATE(pa_context_get_state)(c);
1308   switch (state) {
1309     case PA_CONTEXT_UNCONNECTED:
1310       RTC_LOG(LS_VERBOSE) << "unconnected";
1311       break;
1312     case PA_CONTEXT_CONNECTING:
1313     case PA_CONTEXT_AUTHORIZING:
1314     case PA_CONTEXT_SETTING_NAME:
1315       RTC_LOG(LS_VERBOSE) << "no state";
1316       break;
1317     case PA_CONTEXT_FAILED:
1318     case PA_CONTEXT_TERMINATED:
1319       RTC_LOG(LS_VERBOSE) << "failed";
1320       _paStateChanged = true;
1321       LATE(pa_threaded_mainloop_signal)(_paMainloop, 0);
1322       break;
1323     case PA_CONTEXT_READY:
1324       RTC_LOG(LS_VERBOSE) << "ready";
1325       _paStateChanged = true;
1326       LATE(pa_threaded_mainloop_signal)(_paMainloop, 0);
1327       break;
1328   }
1329 }
1330 
PaSinkInfoCallbackHandler(const pa_sink_info * i,int eol)1331 void AudioDeviceLinuxPulse::PaSinkInfoCallbackHandler(const pa_sink_info* i,
1332                                                       int eol) {
1333   if (eol) {
1334     // Signal that we are done
1335     LATE(pa_threaded_mainloop_signal)(_paMainloop, 0);
1336     return;
1337   }
1338 
1339   if (_numPlayDevices == _deviceIndex) {
1340     // Convert the device index to the one of the sink
1341     _paDeviceIndex = i->index;
1342 
1343     if (_playDeviceName) {
1344       // Copy the sink name
1345       strncpy(_playDeviceName, i->name, kAdmMaxDeviceNameSize);
1346       _playDeviceName[kAdmMaxDeviceNameSize - 1] = '\0';
1347     }
1348     if (_playDisplayDeviceName) {
1349       // Copy the sink display name
1350       strncpy(_playDisplayDeviceName, i->description, kAdmMaxDeviceNameSize);
1351       _playDisplayDeviceName[kAdmMaxDeviceNameSize - 1] = '\0';
1352     }
1353   }
1354 
1355   _numPlayDevices++;
1356 }
1357 
PaSourceInfoCallbackHandler(const pa_source_info * i,int eol)1358 void AudioDeviceLinuxPulse::PaSourceInfoCallbackHandler(const pa_source_info* i,
1359                                                         int eol) {
1360   if (eol) {
1361     // Signal that we are done
1362     LATE(pa_threaded_mainloop_signal)(_paMainloop, 0);
1363     return;
1364   }
1365 
1366   // We don't want to list output devices
1367   if (i->monitor_of_sink == PA_INVALID_INDEX) {
1368     if (_numRecDevices == _deviceIndex) {
1369       // Convert the device index to the one of the source
1370       _paDeviceIndex = i->index;
1371 
1372       if (_recDeviceName) {
1373         // copy the source name
1374         strncpy(_recDeviceName, i->name, kAdmMaxDeviceNameSize);
1375         _recDeviceName[kAdmMaxDeviceNameSize - 1] = '\0';
1376       }
1377       if (_recDisplayDeviceName) {
1378         // Copy the source display name
1379         strncpy(_recDisplayDeviceName, i->description, kAdmMaxDeviceNameSize);
1380         _recDisplayDeviceName[kAdmMaxDeviceNameSize - 1] = '\0';
1381       }
1382     }
1383 
1384     _numRecDevices++;
1385   }
1386 }
1387 
PaServerInfoCallbackHandler(const pa_server_info * i)1388 void AudioDeviceLinuxPulse::PaServerInfoCallbackHandler(
1389     const pa_server_info* i) {
1390   // Use PA native sampling rate
1391   sample_rate_hz_ = i->sample_spec.rate;
1392 
1393   // Copy the PA server version
1394   strncpy(_paServerVersion, i->server_version, 31);
1395   _paServerVersion[31] = '\0';
1396 
1397   if (_recDisplayDeviceName) {
1398     // Copy the source name
1399     strncpy(_recDisplayDeviceName, i->default_source_name,
1400             kAdmMaxDeviceNameSize);
1401     _recDisplayDeviceName[kAdmMaxDeviceNameSize - 1] = '\0';
1402   }
1403 
1404   if (_playDisplayDeviceName) {
1405     // Copy the sink name
1406     strncpy(_playDisplayDeviceName, i->default_sink_name,
1407             kAdmMaxDeviceNameSize);
1408     _playDisplayDeviceName[kAdmMaxDeviceNameSize - 1] = '\0';
1409   }
1410 
1411   LATE(pa_threaded_mainloop_signal)(_paMainloop, 0);
1412 }
1413 
PaStreamStateCallbackHandler(pa_stream * p)1414 void AudioDeviceLinuxPulse::PaStreamStateCallbackHandler(pa_stream* p) {
1415   RTC_LOG(LS_VERBOSE) << "stream state cb";
1416 
1417   pa_stream_state_t state = LATE(pa_stream_get_state)(p);
1418   switch (state) {
1419     case PA_STREAM_UNCONNECTED:
1420       RTC_LOG(LS_VERBOSE) << "unconnected";
1421       break;
1422     case PA_STREAM_CREATING:
1423       RTC_LOG(LS_VERBOSE) << "creating";
1424       break;
1425     case PA_STREAM_FAILED:
1426     case PA_STREAM_TERMINATED:
1427       RTC_LOG(LS_VERBOSE) << "failed";
1428       break;
1429     case PA_STREAM_READY:
1430       RTC_LOG(LS_VERBOSE) << "ready";
1431       break;
1432   }
1433 
1434   LATE(pa_threaded_mainloop_signal)(_paMainloop, 0);
1435 }
1436 
CheckPulseAudioVersion()1437 int32_t AudioDeviceLinuxPulse::CheckPulseAudioVersion() {
1438   PaLock();
1439 
1440   pa_operation* paOperation = NULL;
1441 
1442   // get the server info and update deviceName
1443   paOperation =
1444       LATE(pa_context_get_server_info)(_paContext, PaServerInfoCallback, this);
1445 
1446   WaitForOperationCompletion(paOperation);
1447 
1448   PaUnLock();
1449 
1450   RTC_LOG(LS_VERBOSE) << "checking PulseAudio version: " << _paServerVersion;
1451 
1452   return 0;
1453 }
1454 
InitSamplingFrequency()1455 int32_t AudioDeviceLinuxPulse::InitSamplingFrequency() {
1456   PaLock();
1457 
1458   pa_operation* paOperation = NULL;
1459 
1460   // Get the server info and update sample_rate_hz_
1461   paOperation =
1462       LATE(pa_context_get_server_info)(_paContext, PaServerInfoCallback, this);
1463 
1464   WaitForOperationCompletion(paOperation);
1465 
1466   PaUnLock();
1467 
1468   return 0;
1469 }
1470 
GetDefaultDeviceInfo(bool recDevice,char * name,uint16_t & index)1471 int32_t AudioDeviceLinuxPulse::GetDefaultDeviceInfo(bool recDevice,
1472                                                     char* name,
1473                                                     uint16_t& index) {
1474   char tmpName[kAdmMaxDeviceNameSize] = {0};
1475   // subtract length of "default: "
1476   uint16_t nameLen = kAdmMaxDeviceNameSize - 9;
1477   char* pName = NULL;
1478 
1479   if (name) {
1480     // Add "default: "
1481     strcpy(name, "default: ");
1482     pName = &name[9];
1483   }
1484 
1485   // Tell the callback that we want
1486   // the name for this device
1487   if (recDevice) {
1488     _recDisplayDeviceName = tmpName;
1489   } else {
1490     _playDisplayDeviceName = tmpName;
1491   }
1492 
1493   // Set members
1494   _paDeviceIndex = -1;
1495   _deviceIndex = 0;
1496   _numPlayDevices = 0;
1497   _numRecDevices = 0;
1498 
1499   PaLock();
1500 
1501   pa_operation* paOperation = NULL;
1502 
1503   // Get the server info and update deviceName
1504   paOperation =
1505       LATE(pa_context_get_server_info)(_paContext, PaServerInfoCallback, this);
1506 
1507   WaitForOperationCompletion(paOperation);
1508 
1509   // Get the device index
1510   if (recDevice) {
1511     paOperation = LATE(pa_context_get_source_info_by_name)(
1512         _paContext, (char*)tmpName, PaSourceInfoCallback, this);
1513   } else {
1514     paOperation = LATE(pa_context_get_sink_info_by_name)(
1515         _paContext, (char*)tmpName, PaSinkInfoCallback, this);
1516   }
1517 
1518   WaitForOperationCompletion(paOperation);
1519 
1520   PaUnLock();
1521 
1522   // Set the index
1523   index = _paDeviceIndex;
1524 
1525   if (name) {
1526     // Copy to name string
1527     strncpy(pName, tmpName, nameLen);
1528   }
1529 
1530   // Clear members
1531   _playDisplayDeviceName = NULL;
1532   _recDisplayDeviceName = NULL;
1533   _paDeviceIndex = -1;
1534   _deviceIndex = -1;
1535   _numPlayDevices = 0;
1536   _numRecDevices = 0;
1537 
1538   return 0;
1539 }
1540 
InitPulseAudio()1541 int32_t AudioDeviceLinuxPulse::InitPulseAudio() {
1542   int retVal = 0;
1543 
1544   // Load libpulse
1545   if (!GetPulseSymbolTable()->Load()) {
1546     // Most likely the Pulse library and sound server are not installed on
1547     // this system
1548     RTC_LOG(LS_ERROR) << "failed to load symbol table";
1549     return -1;
1550   }
1551 
1552   // Create a mainloop API and connection to the default server
1553   // the mainloop is the internal asynchronous API event loop
1554   if (_paMainloop) {
1555     RTC_LOG(LS_ERROR) << "PA mainloop has already existed";
1556     return -1;
1557   }
1558   _paMainloop = LATE(pa_threaded_mainloop_new)();
1559   if (!_paMainloop) {
1560     RTC_LOG(LS_ERROR) << "could not create mainloop";
1561     return -1;
1562   }
1563 
1564   // Start the threaded main loop
1565   retVal = LATE(pa_threaded_mainloop_start)(_paMainloop);
1566   if (retVal != PA_OK) {
1567     RTC_LOG(LS_ERROR) << "failed to start main loop, error=" << retVal;
1568     return -1;
1569   }
1570 
1571   RTC_LOG(LS_VERBOSE) << "mainloop running!";
1572 
1573   PaLock();
1574 
1575   _paMainloopApi = LATE(pa_threaded_mainloop_get_api)(_paMainloop);
1576   if (!_paMainloopApi) {
1577     RTC_LOG(LS_ERROR) << "could not create mainloop API";
1578     PaUnLock();
1579     return -1;
1580   }
1581 
1582   // Create a new PulseAudio context
1583   if (_paContext) {
1584     RTC_LOG(LS_ERROR) << "PA context has already existed";
1585     PaUnLock();
1586     return -1;
1587   }
1588   _paContext = LATE(pa_context_new)(_paMainloopApi, "WEBRTC VoiceEngine");
1589 
1590   if (!_paContext) {
1591     RTC_LOG(LS_ERROR) << "could not create context";
1592     PaUnLock();
1593     return -1;
1594   }
1595 
1596   // Set state callback function
1597   LATE(pa_context_set_state_callback)(_paContext, PaContextStateCallback, this);
1598 
1599   // Connect the context to a server (default)
1600   _paStateChanged = false;
1601   retVal =
1602       LATE(pa_context_connect)(_paContext, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL);
1603 
1604   if (retVal != PA_OK) {
1605     RTC_LOG(LS_ERROR) << "failed to connect context, error=" << retVal;
1606     PaUnLock();
1607     return -1;
1608   }
1609 
1610   // Wait for state change
1611   while (!_paStateChanged) {
1612     LATE(pa_threaded_mainloop_wait)(_paMainloop);
1613   }
1614 
1615   // Now check to see what final state we reached.
1616   pa_context_state_t state = LATE(pa_context_get_state)(_paContext);
1617 
1618   if (state != PA_CONTEXT_READY) {
1619     if (state == PA_CONTEXT_FAILED) {
1620       RTC_LOG(LS_ERROR) << "failed to connect to PulseAudio sound server";
1621     } else if (state == PA_CONTEXT_TERMINATED) {
1622       RTC_LOG(LS_ERROR) << "PulseAudio connection terminated early";
1623     } else {
1624       // Shouldn't happen, because we only signal on one of those three
1625       // states
1626       RTC_LOG(LS_ERROR) << "unknown problem connecting to PulseAudio";
1627     }
1628     PaUnLock();
1629     return -1;
1630   }
1631 
1632   PaUnLock();
1633 
1634   // Give the objects to the mixer manager
1635   _mixerManager.SetPulseAudioObjects(_paMainloop, _paContext);
1636 
1637   // Check the version
1638   if (CheckPulseAudioVersion() < 0) {
1639     RTC_LOG(LS_ERROR) << "PulseAudio version " << _paServerVersion
1640                       << " not supported";
1641     return -1;
1642   }
1643 
1644   // Initialize sampling frequency
1645   if (InitSamplingFrequency() < 0 || sample_rate_hz_ == 0) {
1646     RTC_LOG(LS_ERROR) << "failed to initialize sampling frequency, set to "
1647                       << sample_rate_hz_ << " Hz";
1648     return -1;
1649   }
1650 
1651   return 0;
1652 }
1653 
TerminatePulseAudio()1654 int32_t AudioDeviceLinuxPulse::TerminatePulseAudio() {
1655   // Do nothing if the instance doesn't exist
1656   // likely GetPulseSymbolTable.Load() fails
1657   if (!_paMainloop) {
1658     return 0;
1659   }
1660 
1661   PaLock();
1662 
1663   // Disconnect the context
1664   if (_paContext) {
1665     LATE(pa_context_disconnect)(_paContext);
1666   }
1667 
1668   // Unreference the context
1669   if (_paContext) {
1670     LATE(pa_context_unref)(_paContext);
1671   }
1672 
1673   PaUnLock();
1674   _paContext = NULL;
1675 
1676   // Stop the threaded main loop
1677   if (_paMainloop) {
1678     LATE(pa_threaded_mainloop_stop)(_paMainloop);
1679   }
1680 
1681   // Free the mainloop
1682   if (_paMainloop) {
1683     LATE(pa_threaded_mainloop_free)(_paMainloop);
1684   }
1685 
1686   _paMainloop = NULL;
1687 
1688   RTC_LOG(LS_VERBOSE) << "PulseAudio terminated";
1689 
1690   return 0;
1691 }
1692 
PaLock()1693 void AudioDeviceLinuxPulse::PaLock() {
1694   LATE(pa_threaded_mainloop_lock)(_paMainloop);
1695 }
1696 
PaUnLock()1697 void AudioDeviceLinuxPulse::PaUnLock() {
1698   LATE(pa_threaded_mainloop_unlock)(_paMainloop);
1699 }
1700 
WaitForOperationCompletion(pa_operation * paOperation) const1701 void AudioDeviceLinuxPulse::WaitForOperationCompletion(
1702     pa_operation* paOperation) const {
1703   if (!paOperation) {
1704     RTC_LOG(LS_ERROR) << "paOperation NULL in WaitForOperationCompletion";
1705     return;
1706   }
1707 
1708   while (LATE(pa_operation_get_state)(paOperation) == PA_OPERATION_RUNNING) {
1709     LATE(pa_threaded_mainloop_wait)(_paMainloop);
1710   }
1711 
1712   LATE(pa_operation_unref)(paOperation);
1713 }
1714 
1715 // ============================================================================
1716 //                                  Thread Methods
1717 // ============================================================================
1718 
EnableWriteCallback()1719 void AudioDeviceLinuxPulse::EnableWriteCallback() {
1720   if (LATE(pa_stream_get_state)(_playStream) == PA_STREAM_READY) {
1721     // May already have available space. Must check.
1722     _tempBufferSpace = LATE(pa_stream_writable_size)(_playStream);
1723     if (_tempBufferSpace > 0) {
1724       // Yup, there is already space available, so if we register a
1725       // write callback then it will not receive any event. So dispatch
1726       // one ourself instead.
1727       _timeEventPlay.Set();
1728       return;
1729     }
1730   }
1731 
1732   LATE(pa_stream_set_write_callback)(_playStream, &PaStreamWriteCallback, this);
1733 }
1734 
DisableWriteCallback()1735 void AudioDeviceLinuxPulse::DisableWriteCallback() {
1736   LATE(pa_stream_set_write_callback)(_playStream, NULL, NULL);
1737 }
1738 
PaStreamWriteCallback(pa_stream *,size_t buffer_space,void * pThis)1739 void AudioDeviceLinuxPulse::PaStreamWriteCallback(pa_stream* /*unused*/,
1740                                                   size_t buffer_space,
1741                                                   void* pThis) {
1742   static_cast<AudioDeviceLinuxPulse*>(pThis)->PaStreamWriteCallbackHandler(
1743       buffer_space);
1744 }
1745 
PaStreamWriteCallbackHandler(size_t bufferSpace)1746 void AudioDeviceLinuxPulse::PaStreamWriteCallbackHandler(size_t bufferSpace) {
1747   _tempBufferSpace = bufferSpace;
1748 
1749   // Since we write the data asynchronously on a different thread, we have
1750   // to temporarily disable the write callback or else Pulse will call it
1751   // continuously until we write the data. We re-enable it below.
1752   DisableWriteCallback();
1753   _timeEventPlay.Set();
1754 }
1755 
PaStreamUnderflowCallback(pa_stream *,void * pThis)1756 void AudioDeviceLinuxPulse::PaStreamUnderflowCallback(pa_stream* /*unused*/,
1757                                                       void* pThis) {
1758   static_cast<AudioDeviceLinuxPulse*>(pThis)
1759       ->PaStreamUnderflowCallbackHandler();
1760 }
1761 
PaStreamUnderflowCallbackHandler()1762 void AudioDeviceLinuxPulse::PaStreamUnderflowCallbackHandler() {
1763   RTC_LOG(LS_WARNING) << "Playout underflow";
1764 
1765   if (_configuredLatencyPlay == WEBRTC_PA_NO_LATENCY_REQUIREMENTS) {
1766     // We didn't configure a pa_buffer_attr before, so switching to
1767     // one now would be questionable.
1768     return;
1769   }
1770 
1771   // Otherwise reconfigure the stream with a higher target latency.
1772 
1773   const pa_sample_spec* spec = LATE(pa_stream_get_sample_spec)(_playStream);
1774   if (!spec) {
1775     RTC_LOG(LS_ERROR) << "pa_stream_get_sample_spec()";
1776     return;
1777   }
1778 
1779   size_t bytesPerSec = LATE(pa_bytes_per_second)(spec);
1780   uint32_t newLatency =
1781       _configuredLatencyPlay + bytesPerSec *
1782                                    WEBRTC_PA_PLAYBACK_LATENCY_INCREMENT_MSECS /
1783                                    WEBRTC_PA_MSECS_PER_SEC;
1784 
1785   // Set the play buffer attributes
1786   _playBufferAttr.maxlength = newLatency;
1787   _playBufferAttr.tlength = newLatency;
1788   _playBufferAttr.minreq = newLatency / WEBRTC_PA_PLAYBACK_REQUEST_FACTOR;
1789   _playBufferAttr.prebuf = _playBufferAttr.tlength - _playBufferAttr.minreq;
1790 
1791   pa_operation* op = LATE(pa_stream_set_buffer_attr)(
1792       _playStream, &_playBufferAttr, NULL, NULL);
1793   if (!op) {
1794     RTC_LOG(LS_ERROR) << "pa_stream_set_buffer_attr()";
1795     return;
1796   }
1797 
1798   // Don't need to wait for this to complete.
1799   LATE(pa_operation_unref)(op);
1800 
1801   // Save the new latency in case we underflow again.
1802   _configuredLatencyPlay = newLatency;
1803 }
1804 
EnableReadCallback()1805 void AudioDeviceLinuxPulse::EnableReadCallback() {
1806   LATE(pa_stream_set_read_callback)(_recStream, &PaStreamReadCallback, this);
1807 }
1808 
DisableReadCallback()1809 void AudioDeviceLinuxPulse::DisableReadCallback() {
1810   LATE(pa_stream_set_read_callback)(_recStream, NULL, NULL);
1811 }
1812 
PaStreamReadCallback(pa_stream *,size_t,void * pThis)1813 void AudioDeviceLinuxPulse::PaStreamReadCallback(pa_stream* /*unused1*/,
1814                                                  size_t /*unused2*/,
1815                                                  void* pThis) {
1816   static_cast<AudioDeviceLinuxPulse*>(pThis)->PaStreamReadCallbackHandler();
1817 }
1818 
PaStreamReadCallbackHandler()1819 void AudioDeviceLinuxPulse::PaStreamReadCallbackHandler() {
1820   // We get the data pointer and size now in order to save one Lock/Unlock
1821   // in the worker thread.
1822   if (LATE(pa_stream_peek)(_recStream, &_tempSampleData,
1823                            &_tempSampleDataSize) != 0) {
1824     RTC_LOG(LS_ERROR) << "Can't read data!";
1825     return;
1826   }
1827 
1828   // Since we consume the data asynchronously on a different thread, we have
1829   // to temporarily disable the read callback or else Pulse will call it
1830   // continuously until we consume the data. We re-enable it below.
1831   DisableReadCallback();
1832   _timeEventRec.Set();
1833 }
1834 
PaStreamOverflowCallback(pa_stream *,void * pThis)1835 void AudioDeviceLinuxPulse::PaStreamOverflowCallback(pa_stream* /*unused*/,
1836                                                      void* pThis) {
1837   static_cast<AudioDeviceLinuxPulse*>(pThis)->PaStreamOverflowCallbackHandler();
1838 }
1839 
PaStreamOverflowCallbackHandler()1840 void AudioDeviceLinuxPulse::PaStreamOverflowCallbackHandler() {
1841   RTC_LOG(LS_WARNING) << "Recording overflow";
1842 }
1843 
LatencyUsecs(pa_stream * stream)1844 int32_t AudioDeviceLinuxPulse::LatencyUsecs(pa_stream* stream) {
1845   if (!WEBRTC_PA_REPORT_LATENCY) {
1846     return 0;
1847   }
1848 
1849   if (!stream) {
1850     return 0;
1851   }
1852 
1853   pa_usec_t latency;
1854   int negative;
1855   if (LATE(pa_stream_get_latency)(stream, &latency, &negative) != 0) {
1856     RTC_LOG(LS_ERROR) << "Can't query latency";
1857     // We'd rather continue playout/capture with an incorrect delay than
1858     // stop it altogether, so return a valid value.
1859     return 0;
1860   }
1861 
1862   if (negative) {
1863     RTC_LOG(LS_VERBOSE)
1864         << "warning: pa_stream_get_latency reported negative delay";
1865 
1866     // The delay can be negative for monitoring streams if the captured
1867     // samples haven't been played yet. In such a case, "latency"
1868     // contains the magnitude, so we must negate it to get the real value.
1869     int32_t tmpLatency = (int32_t)-latency;
1870     if (tmpLatency < 0) {
1871       // Make sure that we don't use a negative delay.
1872       tmpLatency = 0;
1873     }
1874 
1875     return tmpLatency;
1876   } else {
1877     return (int32_t)latency;
1878   }
1879 }
1880 
ReadRecordedData(const void * bufferData,size_t bufferSize)1881 int32_t AudioDeviceLinuxPulse::ReadRecordedData(const void* bufferData,
1882                                                 size_t bufferSize)
1883     RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_) {
1884   size_t size = bufferSize;
1885   uint32_t numRecSamples = _recordBufferSize / (2 * _recChannels);
1886 
1887   // Account for the peeked data and the used data.
1888   uint32_t recDelay =
1889       (uint32_t)((LatencyUsecs(_recStream) / 1000) +
1890                  10 * ((size + _recordBufferUsed) / _recordBufferSize));
1891 
1892   if (_playStream) {
1893     // Get the playout delay.
1894     _sndCardPlayDelay = (uint32_t)(LatencyUsecs(_playStream) / 1000);
1895   }
1896 
1897   if (_recordBufferUsed > 0) {
1898     // Have to copy to the buffer until it is full.
1899     size_t copy = _recordBufferSize - _recordBufferUsed;
1900     if (size < copy) {
1901       copy = size;
1902     }
1903 
1904     memcpy(&_recBuffer[_recordBufferUsed], bufferData, copy);
1905     _recordBufferUsed += copy;
1906     bufferData = static_cast<const char*>(bufferData) + copy;
1907     size -= copy;
1908 
1909     if (_recordBufferUsed != _recordBufferSize) {
1910       // Not enough data yet to pass to VoE.
1911       return 0;
1912     }
1913 
1914     // Provide data to VoiceEngine.
1915     if (ProcessRecordedData(_recBuffer, numRecSamples, recDelay) == -1) {
1916       // We have stopped recording.
1917       return -1;
1918     }
1919 
1920     _recordBufferUsed = 0;
1921   }
1922 
1923   // Now process full 10ms sample sets directly from the input.
1924   while (size >= _recordBufferSize) {
1925     // Provide data to VoiceEngine.
1926     if (ProcessRecordedData(static_cast<int8_t*>(const_cast<void*>(bufferData)),
1927                             numRecSamples, recDelay) == -1) {
1928       // We have stopped recording.
1929       return -1;
1930     }
1931 
1932     bufferData = static_cast<const char*>(bufferData) + _recordBufferSize;
1933     size -= _recordBufferSize;
1934 
1935     // We have consumed 10ms of data.
1936     recDelay -= 10;
1937   }
1938 
1939   // Now save any leftovers for later.
1940   if (size > 0) {
1941     memcpy(_recBuffer, bufferData, size);
1942     _recordBufferUsed = size;
1943   }
1944 
1945   return 0;
1946 }
1947 
ProcessRecordedData(int8_t * bufferData,uint32_t bufferSizeInSamples,uint32_t recDelay)1948 int32_t AudioDeviceLinuxPulse::ProcessRecordedData(int8_t* bufferData,
1949                                                    uint32_t bufferSizeInSamples,
1950                                                    uint32_t recDelay)
1951     RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_) {
1952   _ptrAudioBuffer->SetRecordedBuffer(bufferData, bufferSizeInSamples);
1953 
1954   // TODO(andrew): this is a temporary hack, to avoid non-causal far- and
1955   // near-end signals at the AEC for PulseAudio. I think the system delay is
1956   // being correctly calculated here, but for legacy reasons we add +10 ms
1957   // to the value in the AEC. The real fix will be part of a larger
1958   // investigation into managing system delay in the AEC.
1959   if (recDelay > 10)
1960     recDelay -= 10;
1961   else
1962     recDelay = 0;
1963   _ptrAudioBuffer->SetVQEData(_sndCardPlayDelay, recDelay);
1964   _ptrAudioBuffer->SetTypingStatus(KeyPressed());
1965   // Deliver recorded samples at specified sample rate,
1966   // mic level etc. to the observer using callback.
1967   UnLock();
1968   _ptrAudioBuffer->DeliverRecordedData();
1969   Lock();
1970 
1971   // We have been unlocked - check the flag again.
1972   if (!_recording) {
1973     return -1;
1974   }
1975 
1976   return 0;
1977 }
1978 
PlayThreadProcess()1979 bool AudioDeviceLinuxPulse::PlayThreadProcess() {
1980   if (!_timeEventPlay.Wait(TimeDelta::Seconds(1))) {
1981     return true;
1982   }
1983 
1984   MutexLock lock(&mutex_);
1985 
1986   if (quit_) {
1987     return false;
1988   }
1989 
1990   if (_startPlay) {
1991     RTC_LOG(LS_VERBOSE) << "_startPlay true, performing initial actions";
1992 
1993     _startPlay = false;
1994     _playDeviceName = NULL;
1995 
1996     // Set if not default device
1997     if (_outputDeviceIndex > 0) {
1998       // Get the playout device name
1999       _playDeviceName = new char[kAdmMaxDeviceNameSize];
2000       _deviceIndex = _outputDeviceIndex;
2001       PlayoutDevices();
2002     }
2003 
2004     // Start muted only supported on 0.9.11 and up
2005     if (LATE(pa_context_get_protocol_version)(_paContext) >=
2006         WEBRTC_PA_ADJUST_LATENCY_PROTOCOL_VERSION) {
2007       // Get the currently saved speaker mute status
2008       // and set the initial mute status accordingly
2009       bool enabled(false);
2010       _mixerManager.SpeakerMute(enabled);
2011       if (enabled) {
2012         _playStreamFlags |= PA_STREAM_START_MUTED;
2013       }
2014     }
2015 
2016     // Get the currently saved speaker volume
2017     uint32_t volume = 0;
2018     if (update_speaker_volume_at_startup_)
2019       _mixerManager.SpeakerVolume(volume);
2020 
2021     PaLock();
2022 
2023     // NULL gives PA the choice of startup volume.
2024     pa_cvolume* ptr_cvolume = NULL;
2025     if (update_speaker_volume_at_startup_) {
2026       pa_cvolume cVolumes;
2027       ptr_cvolume = &cVolumes;
2028 
2029       // Set the same volume for all channels
2030       const pa_sample_spec* spec = LATE(pa_stream_get_sample_spec)(_playStream);
2031       LATE(pa_cvolume_set)(&cVolumes, spec->channels, volume);
2032       update_speaker_volume_at_startup_ = false;
2033     }
2034 
2035     // Connect the stream to a sink
2036     if (LATE(pa_stream_connect_playback)(
2037             _playStream, _playDeviceName, &_playBufferAttr,
2038             (pa_stream_flags_t)_playStreamFlags, ptr_cvolume, NULL) != PA_OK) {
2039       RTC_LOG(LS_ERROR) << "failed to connect play stream, err="
2040                         << LATE(pa_context_errno)(_paContext);
2041     }
2042 
2043     RTC_LOG(LS_VERBOSE) << "play stream connected";
2044 
2045     // Wait for state change
2046     while (LATE(pa_stream_get_state)(_playStream) != PA_STREAM_READY) {
2047       LATE(pa_threaded_mainloop_wait)(_paMainloop);
2048     }
2049 
2050     RTC_LOG(LS_VERBOSE) << "play stream ready";
2051 
2052     // We can now handle write callbacks
2053     EnableWriteCallback();
2054 
2055     PaUnLock();
2056 
2057     // Clear device name
2058     if (_playDeviceName) {
2059       delete[] _playDeviceName;
2060       _playDeviceName = NULL;
2061     }
2062 
2063     _playing = true;
2064     _playStartEvent.Set();
2065 
2066     return true;
2067   }
2068 
2069   if (_playing) {
2070     if (!_recording) {
2071       // Update the playout delay
2072       _sndCardPlayDelay = (uint32_t)(LatencyUsecs(_playStream) / 1000);
2073     }
2074 
2075     if (_playbackBufferUnused < _playbackBufferSize) {
2076       size_t write = _playbackBufferSize - _playbackBufferUnused;
2077       if (_tempBufferSpace < write) {
2078         write = _tempBufferSpace;
2079       }
2080 
2081       PaLock();
2082       if (LATE(pa_stream_write)(
2083               _playStream, (void*)&_playBuffer[_playbackBufferUnused], write,
2084               NULL, (int64_t)0, PA_SEEK_RELATIVE) != PA_OK) {
2085         _writeErrors++;
2086         if (_writeErrors > 10) {
2087           RTC_LOG(LS_ERROR) << "Playout error: _writeErrors=" << _writeErrors
2088                             << ", error=" << LATE(pa_context_errno)(_paContext);
2089           _writeErrors = 0;
2090         }
2091       }
2092       PaUnLock();
2093 
2094       _playbackBufferUnused += write;
2095       _tempBufferSpace -= write;
2096     }
2097 
2098     uint32_t numPlaySamples = _playbackBufferSize / (2 * _playChannels);
2099     // Might have been reduced to zero by the above.
2100     if (_tempBufferSpace > 0) {
2101       // Ask for new PCM data to be played out using the
2102       // AudioDeviceBuffer ensure that this callback is executed
2103       // without taking the audio-thread lock.
2104       UnLock();
2105       RTC_LOG(LS_VERBOSE) << "requesting data";
2106       uint32_t nSamples = _ptrAudioBuffer->RequestPlayoutData(numPlaySamples);
2107       Lock();
2108 
2109       // We have been unlocked - check the flag again.
2110       if (!_playing) {
2111         return true;
2112       }
2113 
2114       nSamples = _ptrAudioBuffer->GetPlayoutData(_playBuffer);
2115       if (nSamples != numPlaySamples) {
2116         RTC_LOG(LS_ERROR) << "invalid number of output samples(" << nSamples
2117                           << ")";
2118       }
2119 
2120       size_t write = _playbackBufferSize;
2121       if (_tempBufferSpace < write) {
2122         write = _tempBufferSpace;
2123       }
2124 
2125       RTC_LOG(LS_VERBOSE) << "will write";
2126       PaLock();
2127       if (LATE(pa_stream_write)(_playStream, (void*)&_playBuffer[0], write,
2128                                 NULL, (int64_t)0, PA_SEEK_RELATIVE) != PA_OK) {
2129         _writeErrors++;
2130         if (_writeErrors > 10) {
2131           RTC_LOG(LS_ERROR) << "Playout error: _writeErrors=" << _writeErrors
2132                             << ", error=" << LATE(pa_context_errno)(_paContext);
2133           _writeErrors = 0;
2134         }
2135       }
2136       PaUnLock();
2137 
2138       _playbackBufferUnused = write;
2139     }
2140 
2141     _tempBufferSpace = 0;
2142     PaLock();
2143     EnableWriteCallback();
2144     PaUnLock();
2145 
2146   }  // _playing
2147 
2148   return true;
2149 }
2150 
RecThreadProcess()2151 bool AudioDeviceLinuxPulse::RecThreadProcess() {
2152   if (!_timeEventRec.Wait(TimeDelta::Seconds(1))) {
2153     return true;
2154   }
2155 
2156   MutexLock lock(&mutex_);
2157   if (quit_) {
2158     return false;
2159   }
2160   if (_startRec) {
2161     RTC_LOG(LS_VERBOSE) << "_startRec true, performing initial actions";
2162 
2163     _recDeviceName = NULL;
2164 
2165     // Set if not default device
2166     if (_inputDeviceIndex > 0) {
2167       // Get the recording device name
2168       _recDeviceName = new char[kAdmMaxDeviceNameSize];
2169       _deviceIndex = _inputDeviceIndex;
2170       RecordingDevices();
2171     }
2172 
2173     PaLock();
2174 
2175     RTC_LOG(LS_VERBOSE) << "connecting stream";
2176 
2177     // Connect the stream to a source
2178     if (LATE(pa_stream_connect_record)(
2179             _recStream, _recDeviceName, &_recBufferAttr,
2180             (pa_stream_flags_t)_recStreamFlags) != PA_OK) {
2181       RTC_LOG(LS_ERROR) << "failed to connect rec stream, err="
2182                         << LATE(pa_context_errno)(_paContext);
2183     }
2184 
2185     RTC_LOG(LS_VERBOSE) << "connected";
2186 
2187     // Wait for state change
2188     while (LATE(pa_stream_get_state)(_recStream) != PA_STREAM_READY) {
2189       LATE(pa_threaded_mainloop_wait)(_paMainloop);
2190     }
2191 
2192     RTC_LOG(LS_VERBOSE) << "done";
2193 
2194     // We can now handle read callbacks
2195     EnableReadCallback();
2196 
2197     PaUnLock();
2198 
2199     // Clear device name
2200     if (_recDeviceName) {
2201       delete[] _recDeviceName;
2202       _recDeviceName = NULL;
2203     }
2204 
2205     _startRec = false;
2206     _recording = true;
2207     _recStartEvent.Set();
2208 
2209     return true;
2210   }
2211 
2212   if (_recording) {
2213     // Read data and provide it to VoiceEngine
2214     if (ReadRecordedData(_tempSampleData, _tempSampleDataSize) == -1) {
2215       return true;
2216     }
2217 
2218     _tempSampleData = NULL;
2219     _tempSampleDataSize = 0;
2220 
2221     PaLock();
2222     while (true) {
2223       // Ack the last thing we read
2224       if (LATE(pa_stream_drop)(_recStream) != 0) {
2225         RTC_LOG(LS_WARNING)
2226             << "failed to drop, err=" << LATE(pa_context_errno)(_paContext);
2227       }
2228 
2229       if (LATE(pa_stream_readable_size)(_recStream) <= 0) {
2230         // Then that was all the data
2231         break;
2232       }
2233 
2234       // Else more data.
2235       const void* sampleData;
2236       size_t sampleDataSize;
2237 
2238       if (LATE(pa_stream_peek)(_recStream, &sampleData, &sampleDataSize) != 0) {
2239         RTC_LOG(LS_ERROR) << "RECORD_ERROR, error = "
2240                           << LATE(pa_context_errno)(_paContext);
2241         break;
2242       }
2243 
2244       // Drop lock for sigslot dispatch, which could take a while.
2245       PaUnLock();
2246       // Read data and provide it to VoiceEngine
2247       if (ReadRecordedData(sampleData, sampleDataSize) == -1) {
2248         return true;
2249       }
2250       PaLock();
2251 
2252       // Return to top of loop for the ack and the check for more data.
2253     }
2254 
2255     EnableReadCallback();
2256     PaUnLock();
2257 
2258   }  // _recording
2259 
2260   return true;
2261 }
2262 
KeyPressed() const2263 bool AudioDeviceLinuxPulse::KeyPressed() const {
2264 #if defined(WEBRTC_USE_X11)
2265   char szKey[32];
2266   unsigned int i = 0;
2267   char state = 0;
2268 
2269   if (!_XDisplay)
2270     return false;
2271 
2272   // Check key map status
2273   XQueryKeymap(_XDisplay, szKey);
2274 
2275   // A bit change in keymap means a key is pressed
2276   for (i = 0; i < sizeof(szKey); i++)
2277     state |= (szKey[i] ^ _oldKeyState[i]) & szKey[i];
2278 
2279   // Save old state
2280   memcpy((char*)_oldKeyState, (char*)szKey, sizeof(_oldKeyState));
2281   return (state != 0);
2282 #else
2283   return false;
2284 #endif
2285 }
2286 }  // namespace webrtc
2287