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