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