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