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