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 "webrtc/modules/audio_device/audio_device_config.h"
14#include "webrtc/modules/audio_device/audio_device_utility.h"
15#include "webrtc/modules/audio_device/linux/audio_device_pulse_linux.h"
16
17#include "webrtc/system_wrappers/interface/event_wrapper.h"
18#include "webrtc/system_wrappers/interface/thread_wrapper.h"
19#include "webrtc/system_wrappers/interface/trace.h"
20
21webrtc_adm_linux_pulse::PulseAudioSymbolTable PaSymbolTable;
22
23// Accesses Pulse functions through our late-binding symbol table instead of
24// directly. This way we don't have to link to libpulse, which means our binary
25// will work on systems that don't have it.
26#define LATE(sym) \
27  LATESYM_GET(webrtc_adm_linux_pulse::PulseAudioSymbolTable, &PaSymbolTable, sym)
28
29namespace webrtc
30{
31
32// ============================================================================
33//                              Static Methods
34// ============================================================================
35
36AudioDeviceLinuxPulse::AudioDeviceLinuxPulse(const int32_t id) :
37    _ptrAudioBuffer(NULL),
38    _critSect(*CriticalSectionWrapper::CreateCriticalSection()),
39    _timeEventRec(*EventWrapper::Create()),
40    _timeEventPlay(*EventWrapper::Create()),
41    _recStartEvent(*EventWrapper::Create()),
42    _playStartEvent(*EventWrapper::Create()),
43    _ptrThreadPlay(NULL),
44    _ptrThreadRec(NULL),
45    _recThreadID(0),
46    _playThreadID(0),
47    _id(id),
48    _mixerManager(id),
49    _inputDeviceIndex(0),
50    _outputDeviceIndex(0),
51    _inputDeviceIsSpecified(false),
52    _outputDeviceIsSpecified(false),
53    sample_rate_hz_(0),
54    _recChannels(1),
55    _playChannels(1),
56    _playBufType(AudioDeviceModule::kFixedBufferSize),
57    _initialized(false),
58    _recording(false),
59    _playing(false),
60    _recIsInitialized(false),
61    _playIsInitialized(false),
62    _startRec(false),
63    _stopRec(false),
64    _startPlay(false),
65    _stopPlay(false),
66    _AGC(false),
67    update_speaker_volume_at_startup_(false),
68    _playBufDelayFixed(20),
69    _sndCardPlayDelay(0),
70    _sndCardRecDelay(0),
71    _writeErrors(0),
72    _playWarning(0),
73    _playError(0),
74    _recWarning(0),
75    _recError(0),
76    _deviceIndex(-1),
77    _numPlayDevices(0),
78    _numRecDevices(0),
79    _playDeviceName(NULL),
80    _recDeviceName(NULL),
81    _playDisplayDeviceName(NULL),
82    _recDisplayDeviceName(NULL),
83    _playBuffer(NULL),
84    _playbackBufferSize(0),
85    _playbackBufferUnused(0),
86    _tempBufferSpace(0),
87    _recBuffer(NULL),
88    _recordBufferSize(0),
89    _recordBufferUsed(0),
90    _tempSampleData(NULL),
91    _tempSampleDataSize(0),
92    _configuredLatencyPlay(0),
93    _configuredLatencyRec(0),
94    _paDeviceIndex(-1),
95    _paStateChanged(false),
96    _paMainloop(NULL),
97    _paMainloopApi(NULL),
98    _paContext(NULL),
99    _recStream(NULL),
100    _playStream(NULL),
101    _recStreamFlags(0),
102    _playStreamFlags(0)
103{
104    WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, id,
105                 "%s created", __FUNCTION__);
106
107    memset(_paServerVersion, 0, sizeof(_paServerVersion));
108    memset(&_playBufferAttr, 0, sizeof(_playBufferAttr));
109    memset(&_recBufferAttr, 0, sizeof(_recBufferAttr));
110    memset(_oldKeyState, 0, sizeof(_oldKeyState));
111}
112
113AudioDeviceLinuxPulse::~AudioDeviceLinuxPulse()
114{
115    WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id,
116                 "%s destroyed", __FUNCTION__);
117
118    Terminate();
119
120    if (_recBuffer)
121    {
122        delete [] _recBuffer;
123        _recBuffer = NULL;
124    }
125    if (_playBuffer)
126    {
127        delete [] _playBuffer;
128        _playBuffer = NULL;
129    }
130    if (_playDeviceName)
131    {
132        delete [] _playDeviceName;
133        _playDeviceName = NULL;
134    }
135    if (_recDeviceName)
136    {
137        delete [] _recDeviceName;
138        _recDeviceName = NULL;
139    }
140
141    delete &_recStartEvent;
142    delete &_playStartEvent;
143    delete &_timeEventRec;
144    delete &_timeEventPlay;
145    delete &_critSect;
146}
147
148void AudioDeviceLinuxPulse::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer)
149{
150
151    CriticalSectionScoped lock(&_critSect);
152
153    _ptrAudioBuffer = audioBuffer;
154
155    // Inform the AudioBuffer about default settings for this implementation.
156    // Set all values to zero here since the actual settings will be done by
157    // InitPlayout and InitRecording later.
158    _ptrAudioBuffer->SetRecordingSampleRate(0);
159    _ptrAudioBuffer->SetPlayoutSampleRate(0);
160    _ptrAudioBuffer->SetRecordingChannels(0);
161    _ptrAudioBuffer->SetPlayoutChannels(0);
162}
163
164// ----------------------------------------------------------------------------
165//  ActiveAudioLayer
166// ----------------------------------------------------------------------------
167
168int32_t AudioDeviceLinuxPulse::ActiveAudioLayer(
169    AudioDeviceModule::AudioLayer& audioLayer) const
170{
171    audioLayer = AudioDeviceModule::kLinuxPulseAudio;
172    return 0;
173}
174
175int32_t AudioDeviceLinuxPulse::Init()
176{
177
178    CriticalSectionScoped lock(&_critSect);
179
180    if (_initialized)
181    {
182        return 0;
183    }
184
185    // Initialize PulseAudio
186    if (InitPulseAudio() < 0)
187    {
188        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
189                     "  failed to initialize PulseAudio");
190
191        if (TerminatePulseAudio() < 0)
192        {
193            WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
194                         "  failed to terminate PulseAudio");
195        }
196
197        return -1;
198    }
199
200    _playWarning = 0;
201    _playError = 0;
202    _recWarning = 0;
203    _recError = 0;
204
205    //Get X display handle for typing detection
206    _XDisplay = XOpenDisplay(NULL);
207    if (!_XDisplay)
208    {
209        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
210          "  failed to open X display, typing detection will not work");
211    }
212
213    // RECORDING
214    const char* threadName = "webrtc_audio_module_rec_thread";
215    _ptrThreadRec = ThreadWrapper::CreateThread(RecThreadFunc, this,
216                                                kRealtimePriority, threadName);
217    if (_ptrThreadRec == NULL)
218    {
219        WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id,
220                     "  failed to create the rec audio thread");
221        return -1;
222    }
223
224    unsigned int threadID(0);
225    if (!_ptrThreadRec->Start(threadID))
226    {
227        WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id,
228                     "  failed to start the rec audio thread");
229
230        delete _ptrThreadRec;
231        _ptrThreadRec = NULL;
232        return -1;
233    }
234    _recThreadID = threadID;
235
236    // PLAYOUT
237    threadName = "webrtc_audio_module_play_thread";
238    _ptrThreadPlay = ThreadWrapper::CreateThread(PlayThreadFunc, this,
239                                                 kRealtimePriority, threadName);
240    if (_ptrThreadPlay == NULL)
241    {
242        WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id,
243                     "  failed to create the play audio thread");
244        return -1;
245    }
246
247    threadID = 0;
248    if (!_ptrThreadPlay->Start(threadID))
249    {
250        WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id,
251                     "  failed to start the play audio thread");
252
253        delete _ptrThreadPlay;
254        _ptrThreadPlay = NULL;
255        return -1;
256    }
257    _playThreadID = threadID;
258
259    _initialized = true;
260
261    return 0;
262}
263
264int32_t AudioDeviceLinuxPulse::Terminate()
265{
266
267    if (!_initialized)
268    {
269        return 0;
270    }
271
272    Lock();
273
274    _mixerManager.Close();
275
276    // RECORDING
277    if (_ptrThreadRec)
278    {
279        ThreadWrapper* tmpThread = _ptrThreadRec;
280        _ptrThreadRec = NULL;
281        UnLock();
282
283        tmpThread->SetNotAlive();
284        _timeEventRec.Set();
285        if (tmpThread->Stop())
286        {
287            delete tmpThread;
288        } else
289        {
290            WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
291                         "  failed to close down the rec audio thread");
292        }
293        // Lock again since we need to protect _ptrThreadPlay.
294        Lock();
295    }
296
297    // PLAYOUT
298    if (_ptrThreadPlay)
299    {
300        ThreadWrapper* tmpThread = _ptrThreadPlay;
301        _ptrThreadPlay = NULL;
302        _critSect.Leave();
303
304        tmpThread->SetNotAlive();
305        _timeEventPlay.Set();
306        if (tmpThread->Stop())
307        {
308            delete tmpThread;
309        } else
310        {
311            WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
312                         "  failed to close down the play audio thread");
313        }
314    } else {
315      UnLock();
316    }
317
318    // Terminate PulseAudio
319    if (TerminatePulseAudio() < 0)
320    {
321        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
322                     "  failed to terminate PulseAudio");
323        return -1;
324    }
325
326    if (_XDisplay)
327    {
328      XCloseDisplay(_XDisplay);
329      _XDisplay = NULL;
330    }
331
332    _initialized = false;
333    _outputDeviceIsSpecified = false;
334    _inputDeviceIsSpecified = false;
335
336    return 0;
337}
338
339bool AudioDeviceLinuxPulse::Initialized() const
340{
341    return (_initialized);
342}
343
344int32_t AudioDeviceLinuxPulse::InitSpeaker()
345{
346
347    CriticalSectionScoped lock(&_critSect);
348
349    if (_playing)
350    {
351        return -1;
352    }
353
354    if (!_outputDeviceIsSpecified)
355    {
356        return -1;
357    }
358
359    // check if default device
360    if (_outputDeviceIndex == 0)
361    {
362        uint16_t deviceIndex = 0;
363        GetDefaultDeviceInfo(false, NULL, deviceIndex);
364        _paDeviceIndex = deviceIndex;
365    } else
366    {
367        // get the PA device index from
368        // the callback
369        _deviceIndex = _outputDeviceIndex;
370
371        // get playout devices
372        PlayoutDevices();
373    }
374
375    // the callback has now set the _paDeviceIndex to
376    // the PulseAudio index of the device
377    if (_mixerManager.OpenSpeaker(_paDeviceIndex) == -1)
378    {
379        return -1;
380    }
381
382    // clear _deviceIndex
383    _deviceIndex = -1;
384    _paDeviceIndex = -1;
385
386    return 0;
387}
388
389int32_t AudioDeviceLinuxPulse::InitMicrophone()
390{
391
392    CriticalSectionScoped lock(&_critSect);
393
394    if (_recording)
395    {
396        return -1;
397    }
398
399    if (!_inputDeviceIsSpecified)
400    {
401        return -1;
402    }
403
404    // Check if default device
405    if (_inputDeviceIndex == 0)
406    {
407        uint16_t deviceIndex = 0;
408        GetDefaultDeviceInfo(true, NULL, deviceIndex);
409        _paDeviceIndex = deviceIndex;
410    } else
411    {
412        // Get the PA device index from
413        // the callback
414        _deviceIndex = _inputDeviceIndex;
415
416        // get recording devices
417        RecordingDevices();
418    }
419
420    // The callback has now set the _paDeviceIndex to
421    // the PulseAudio index of the device
422    if (_mixerManager.OpenMicrophone(_paDeviceIndex) == -1)
423    {
424        return -1;
425    }
426
427    // Clear _deviceIndex
428    _deviceIndex = -1;
429    _paDeviceIndex = -1;
430
431    return 0;
432}
433
434bool AudioDeviceLinuxPulse::SpeakerIsInitialized() const
435{
436    return (_mixerManager.SpeakerIsInitialized());
437}
438
439bool AudioDeviceLinuxPulse::MicrophoneIsInitialized() const
440{
441    return (_mixerManager.MicrophoneIsInitialized());
442}
443
444int32_t AudioDeviceLinuxPulse::SpeakerVolumeIsAvailable(bool& available)
445{
446
447    bool wasInitialized = _mixerManager.SpeakerIsInitialized();
448
449    // Make an attempt to open up the
450    // output mixer corresponding to the currently selected output device.
451    if (!wasInitialized && InitSpeaker() == -1)
452    {
453        // If we end up here it means that the selected speaker has no volume
454        // control.
455        available = false;
456        return 0;
457    }
458
459    // Given that InitSpeaker was successful, we know that a volume control exists
460    available = true;
461
462    // Close the initialized output mixer
463    if (!wasInitialized)
464    {
465        _mixerManager.CloseSpeaker();
466    }
467
468    return 0;
469}
470
471int32_t AudioDeviceLinuxPulse::SetSpeakerVolume(uint32_t volume)
472{
473    if (!_playing) {
474      // Only update the volume if it's been set while we weren't playing.
475      update_speaker_volume_at_startup_ = true;
476    }
477    return (_mixerManager.SetSpeakerVolume(volume));
478}
479
480int32_t AudioDeviceLinuxPulse::SpeakerVolume(uint32_t& volume) const
481{
482
483    uint32_t level(0);
484
485    if (_mixerManager.SpeakerVolume(level) == -1)
486    {
487        return -1;
488    }
489
490    volume = level;
491
492    return 0;
493}
494
495int32_t AudioDeviceLinuxPulse::SetWaveOutVolume(
496    uint16_t volumeLeft,
497    uint16_t volumeRight)
498{
499
500    WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
501                 "  API call not supported on this platform");
502    return -1;
503}
504
505int32_t AudioDeviceLinuxPulse::WaveOutVolume(
506    uint16_t& /*volumeLeft*/,
507    uint16_t& /*volumeRight*/) const
508{
509
510    WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
511                 "  API call not supported on this platform");
512    return -1;
513}
514
515int32_t AudioDeviceLinuxPulse::MaxSpeakerVolume(
516    uint32_t& maxVolume) const
517{
518
519    uint32_t maxVol(0);
520
521    if (_mixerManager.MaxSpeakerVolume(maxVol) == -1)
522    {
523        return -1;
524    }
525
526    maxVolume = maxVol;
527
528    return 0;
529}
530
531int32_t AudioDeviceLinuxPulse::MinSpeakerVolume(
532    uint32_t& minVolume) const
533{
534
535    uint32_t minVol(0);
536
537    if (_mixerManager.MinSpeakerVolume(minVol) == -1)
538    {
539        return -1;
540    }
541
542    minVolume = minVol;
543
544    return 0;
545}
546
547int32_t AudioDeviceLinuxPulse::SpeakerVolumeStepSize(
548    uint16_t& stepSize) const
549{
550
551    uint16_t delta(0);
552
553    if (_mixerManager.SpeakerVolumeStepSize(delta) == -1)
554    {
555        return -1;
556    }
557
558    stepSize = delta;
559
560    return 0;
561}
562
563int32_t AudioDeviceLinuxPulse::SpeakerMuteIsAvailable(bool& available)
564{
565
566    bool isAvailable(false);
567    bool wasInitialized = _mixerManager.SpeakerIsInitialized();
568
569    // Make an attempt to open up the
570    // output mixer corresponding to the currently selected output device.
571    //
572    if (!wasInitialized && InitSpeaker() == -1)
573    {
574        // If we end up here it means that the selected speaker has no volume
575        // control, hence it is safe to state that there is no mute control
576        // already at this stage.
577        available = false;
578        return 0;
579    }
580
581    // Check if the selected speaker has a mute control
582    _mixerManager.SpeakerMuteIsAvailable(isAvailable);
583
584    available = isAvailable;
585
586    // Close the initialized output mixer
587    if (!wasInitialized)
588    {
589        _mixerManager.CloseSpeaker();
590    }
591
592    return 0;
593}
594
595int32_t AudioDeviceLinuxPulse::SetSpeakerMute(bool enable)
596{
597
598    return (_mixerManager.SetSpeakerMute(enable));
599}
600
601int32_t AudioDeviceLinuxPulse::SpeakerMute(bool& enabled) const
602{
603
604    bool muted(0);
605    if (_mixerManager.SpeakerMute(muted) == -1)
606    {
607        return -1;
608    }
609
610    enabled = muted;
611    return 0;
612}
613
614int32_t AudioDeviceLinuxPulse::MicrophoneMuteIsAvailable(bool& available)
615{
616
617    bool isAvailable(false);
618    bool wasInitialized = _mixerManager.MicrophoneIsInitialized();
619
620    // Make an attempt to open up the
621    // input mixer corresponding to the currently selected input device.
622    //
623    if (!wasInitialized && InitMicrophone() == -1)
624    {
625        // If we end up here it means that the selected microphone has no volume
626        // control, hence it is safe to state that there is no boost control
627        // already at this stage.
628        available = false;
629        return 0;
630    }
631
632    // Check if the selected microphone has a mute control
633    //
634    _mixerManager.MicrophoneMuteIsAvailable(isAvailable);
635    available = isAvailable;
636
637    // Close the initialized input mixer
638    //
639    if (!wasInitialized)
640    {
641        _mixerManager.CloseMicrophone();
642    }
643
644    return 0;
645}
646
647int32_t AudioDeviceLinuxPulse::SetMicrophoneMute(bool enable)
648{
649
650    return (_mixerManager.SetMicrophoneMute(enable));
651}
652
653int32_t AudioDeviceLinuxPulse::MicrophoneMute(bool& enabled) const
654{
655
656    bool muted(0);
657    if (_mixerManager.MicrophoneMute(muted) == -1)
658    {
659        return -1;
660    }
661
662    enabled = muted;
663    return 0;
664}
665
666int32_t AudioDeviceLinuxPulse::MicrophoneBoostIsAvailable(bool& available)
667{
668
669    bool isAvailable(false);
670    bool wasInitialized = _mixerManager.MicrophoneIsInitialized();
671
672    // Enumerate all avaliable microphone and make an attempt to open up the
673    // input mixer corresponding to the currently selected input device.
674    //
675    if (!wasInitialized && InitMicrophone() == -1)
676    {
677        // If we end up here it means that the selected microphone has no volume
678        // control, hence it is safe to state that there is no boost control
679        // already at this stage.
680        available = false;
681        return 0;
682    }
683
684    // Check if the selected microphone has a boost control
685    _mixerManager.MicrophoneBoostIsAvailable(isAvailable);
686    available = isAvailable;
687
688    // Close the initialized input mixer
689    if (!wasInitialized)
690    {
691        _mixerManager.CloseMicrophone();
692    }
693
694    return 0;
695}
696
697int32_t AudioDeviceLinuxPulse::SetMicrophoneBoost(bool enable)
698{
699
700    return (_mixerManager.SetMicrophoneBoost(enable));
701}
702
703int32_t AudioDeviceLinuxPulse::MicrophoneBoost(bool& enabled) const
704{
705
706    bool onOff(0);
707
708    if (_mixerManager.MicrophoneBoost(onOff) == -1)
709    {
710        return -1;
711    }
712
713    enabled = onOff;
714
715    return 0;
716}
717
718int32_t AudioDeviceLinuxPulse::StereoRecordingIsAvailable(bool& available)
719{
720
721    if (_recChannels == 2 && _recording) {
722      available = true;
723      return 0;
724    }
725
726    available = false;
727    bool wasInitialized = _mixerManager.MicrophoneIsInitialized();
728    int error = 0;
729
730    if (!wasInitialized && InitMicrophone() == -1)
731    {
732        // Cannot open the specified device
733        available = false;
734        return 0;
735    }
736
737    // Check if the selected microphone can record stereo.
738    bool isAvailable(false);
739    error = _mixerManager.StereoRecordingIsAvailable(isAvailable);
740    if (!error)
741      available = isAvailable;
742
743    // Close the initialized input mixer
744    if (!wasInitialized)
745    {
746        _mixerManager.CloseMicrophone();
747    }
748
749    return error;
750}
751
752int32_t AudioDeviceLinuxPulse::SetStereoRecording(bool enable)
753{
754
755    if (enable)
756        _recChannels = 2;
757    else
758        _recChannels = 1;
759
760    return 0;
761}
762
763int32_t AudioDeviceLinuxPulse::StereoRecording(bool& enabled) const
764{
765
766    if (_recChannels == 2)
767        enabled = true;
768    else
769        enabled = false;
770
771    return 0;
772}
773
774int32_t AudioDeviceLinuxPulse::StereoPlayoutIsAvailable(bool& available)
775{
776
777    if (_playChannels == 2 && _playing) {
778      available = true;
779      return 0;
780    }
781
782    available = false;
783    bool wasInitialized = _mixerManager.SpeakerIsInitialized();
784    int error = 0;
785
786    if (!wasInitialized && InitSpeaker() == -1)
787    {
788        // Cannot open the specified device.
789        return -1;
790    }
791
792    // Check if the selected speaker can play stereo.
793    bool isAvailable(false);
794    error = _mixerManager.StereoPlayoutIsAvailable(isAvailable);
795    if (!error)
796      available = isAvailable;
797
798    // Close the initialized input mixer
799    if (!wasInitialized)
800    {
801        _mixerManager.CloseSpeaker();
802    }
803
804    return error;
805}
806
807int32_t AudioDeviceLinuxPulse::SetStereoPlayout(bool enable)
808{
809
810    if (enable)
811        _playChannels = 2;
812    else
813        _playChannels = 1;
814
815    return 0;
816}
817
818int32_t AudioDeviceLinuxPulse::StereoPlayout(bool& enabled) const
819{
820
821    if (_playChannels == 2)
822        enabled = true;
823    else
824        enabled = false;
825
826    return 0;
827}
828
829int32_t AudioDeviceLinuxPulse::SetAGC(bool enable)
830{
831
832    _AGC = enable;
833
834    return 0;
835}
836
837bool AudioDeviceLinuxPulse::AGC() const
838{
839
840    return _AGC;
841}
842
843int32_t AudioDeviceLinuxPulse::MicrophoneVolumeIsAvailable(
844    bool& available)
845{
846
847    bool wasInitialized = _mixerManager.MicrophoneIsInitialized();
848
849    // Make an attempt to open up the
850    // input mixer corresponding to the currently selected output device.
851    if (!wasInitialized && InitMicrophone() == -1)
852    {
853        // If we end up here it means that the selected microphone has no volume
854        // control.
855        available = false;
856        return 0;
857    }
858
859    // Given that InitMicrophone was successful, we know that a volume control
860    // exists
861    available = true;
862
863    // Close the initialized input mixer
864    if (!wasInitialized)
865    {
866        _mixerManager.CloseMicrophone();
867    }
868
869    return 0;
870}
871
872int32_t AudioDeviceLinuxPulse::SetMicrophoneVolume(uint32_t volume)
873{
874
875    return (_mixerManager.SetMicrophoneVolume(volume));
876}
877
878int32_t AudioDeviceLinuxPulse::MicrophoneVolume(
879    uint32_t& volume) const
880{
881
882    uint32_t level(0);
883
884    if (_mixerManager.MicrophoneVolume(level) == -1)
885    {
886        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
887                     "  failed to retrive current microphone level");
888        return -1;
889    }
890
891    volume = level;
892
893    return 0;
894}
895
896int32_t AudioDeviceLinuxPulse::MaxMicrophoneVolume(
897    uint32_t& maxVolume) const
898{
899
900    uint32_t maxVol(0);
901
902    if (_mixerManager.MaxMicrophoneVolume(maxVol) == -1)
903    {
904        return -1;
905    }
906
907    maxVolume = maxVol;
908
909    return 0;
910}
911
912int32_t AudioDeviceLinuxPulse::MinMicrophoneVolume(
913    uint32_t& minVolume) const
914{
915
916    uint32_t minVol(0);
917
918    if (_mixerManager.MinMicrophoneVolume(minVol) == -1)
919    {
920        return -1;
921    }
922
923    minVolume = minVol;
924
925    return 0;
926}
927
928int32_t AudioDeviceLinuxPulse::MicrophoneVolumeStepSize(
929    uint16_t& stepSize) const
930{
931
932    uint16_t delta(0);
933
934    if (_mixerManager.MicrophoneVolumeStepSize(delta) == -1)
935    {
936        return -1;
937    }
938
939    stepSize = delta;
940
941    return 0;
942}
943
944int16_t AudioDeviceLinuxPulse::PlayoutDevices()
945{
946
947    PaLock();
948
949    pa_operation* paOperation = NULL;
950    _numPlayDevices = 1; // init to 1 to account for "default"
951
952    // get the whole list of devices and update _numPlayDevices
953    paOperation = LATE(pa_context_get_sink_info_list)(_paContext,
954                                                      PaSinkInfoCallback,
955                                                      this);
956
957    WaitForOperationCompletion(paOperation);
958
959    PaUnLock();
960
961    return _numPlayDevices;
962}
963
964int32_t AudioDeviceLinuxPulse::SetPlayoutDevice(uint16_t index)
965{
966
967    if (_playIsInitialized)
968    {
969        return -1;
970    }
971
972    const uint16_t nDevices = PlayoutDevices();
973
974    WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
975                 "  number of availiable output devices is %u", nDevices);
976
977    if (index > (nDevices - 1))
978    {
979        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
980                     "  device index is out of range [0,%u]", (nDevices - 1));
981        return -1;
982    }
983
984    _outputDeviceIndex = index;
985    _outputDeviceIsSpecified = true;
986
987    return 0;
988}
989
990int32_t AudioDeviceLinuxPulse::SetPlayoutDevice(
991    AudioDeviceModule::WindowsDeviceType /*device*/)
992{
993    WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
994                 "WindowsDeviceType not supported");
995    return -1;
996}
997
998int32_t AudioDeviceLinuxPulse::PlayoutDeviceName(
999    uint16_t index,
1000    char name[kAdmMaxDeviceNameSize],
1001    char guid[kAdmMaxGuidSize])
1002{
1003
1004    const uint16_t nDevices = PlayoutDevices();
1005
1006    if ((index > (nDevices - 1)) || (name == NULL))
1007    {
1008        return -1;
1009    }
1010
1011    memset(name, 0, kAdmMaxDeviceNameSize);
1012
1013    if (guid != NULL)
1014    {
1015        memset(guid, 0, kAdmMaxGuidSize);
1016    }
1017
1018    // Check if default device
1019    if (index == 0)
1020    {
1021        uint16_t deviceIndex = 0;
1022        return GetDefaultDeviceInfo(false, name, deviceIndex);
1023    }
1024
1025    // Tell the callback that we want
1026    // The name for this device
1027    _playDisplayDeviceName = name;
1028    _deviceIndex = index;
1029
1030    // get playout devices
1031    PlayoutDevices();
1032
1033    // clear device name and index
1034    _playDisplayDeviceName = NULL;
1035    _deviceIndex = -1;
1036
1037    return 0;
1038}
1039
1040int32_t AudioDeviceLinuxPulse::RecordingDeviceName(
1041    uint16_t index,
1042    char name[kAdmMaxDeviceNameSize],
1043    char guid[kAdmMaxGuidSize])
1044{
1045
1046    const uint16_t nDevices(RecordingDevices());
1047
1048    if ((index > (nDevices - 1)) || (name == NULL))
1049    {
1050        return -1;
1051    }
1052
1053    memset(name, 0, kAdmMaxDeviceNameSize);
1054
1055    if (guid != NULL)
1056    {
1057        memset(guid, 0, kAdmMaxGuidSize);
1058    }
1059
1060    // Check if default device
1061    if (index == 0)
1062    {
1063        uint16_t deviceIndex = 0;
1064        return GetDefaultDeviceInfo(true, name, deviceIndex);
1065    }
1066
1067    // Tell the callback that we want
1068    // the name for this device
1069    _recDisplayDeviceName = name;
1070    _deviceIndex = index;
1071
1072    // Get recording devices
1073    RecordingDevices();
1074
1075    // Clear device name and index
1076    _recDisplayDeviceName = NULL;
1077    _deviceIndex = -1;
1078
1079    return 0;
1080}
1081
1082int16_t AudioDeviceLinuxPulse::RecordingDevices()
1083{
1084
1085    PaLock();
1086
1087    pa_operation* paOperation = NULL;
1088    _numRecDevices = 1; // Init to 1 to account for "default"
1089
1090    // Get the whole list of devices and update _numRecDevices
1091    paOperation = LATE(pa_context_get_source_info_list)(_paContext,
1092                                                        PaSourceInfoCallback,
1093                                                        this);
1094
1095    WaitForOperationCompletion(paOperation);
1096
1097    PaUnLock();
1098
1099    return _numRecDevices;
1100}
1101
1102int32_t AudioDeviceLinuxPulse::SetRecordingDevice(uint16_t index)
1103{
1104
1105    if (_recIsInitialized)
1106    {
1107        return -1;
1108    }
1109
1110    const uint16_t nDevices(RecordingDevices());
1111
1112    WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
1113                 "  number of availiable input devices is %u", nDevices);
1114
1115    if (index > (nDevices - 1))
1116    {
1117        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1118                     "  device index is out of range [0,%u]", (nDevices - 1));
1119        return -1;
1120    }
1121
1122    _inputDeviceIndex = index;
1123    _inputDeviceIsSpecified = true;
1124
1125    return 0;
1126}
1127
1128int32_t AudioDeviceLinuxPulse::SetRecordingDevice(
1129    AudioDeviceModule::WindowsDeviceType /*device*/)
1130{
1131    WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1132                 "WindowsDeviceType not supported");
1133    return -1;
1134}
1135
1136int32_t AudioDeviceLinuxPulse::PlayoutIsAvailable(bool& available)
1137{
1138
1139    available = false;
1140
1141    // Try to initialize the playout side
1142    int32_t res = InitPlayout();
1143
1144    // Cancel effect of initialization
1145    StopPlayout();
1146
1147    if (res != -1)
1148    {
1149        available = true;
1150    }
1151
1152    return res;
1153}
1154
1155int32_t AudioDeviceLinuxPulse::RecordingIsAvailable(bool& available)
1156{
1157
1158    available = false;
1159
1160    // Try to initialize the playout side
1161    int32_t res = InitRecording();
1162
1163    // Cancel effect of initialization
1164    StopRecording();
1165
1166    if (res != -1)
1167    {
1168        available = true;
1169    }
1170
1171    return res;
1172}
1173
1174int32_t AudioDeviceLinuxPulse::InitPlayout()
1175{
1176
1177    CriticalSectionScoped lock(&_critSect);
1178
1179    if (_playing)
1180    {
1181        return -1;
1182    }
1183
1184    if (!_outputDeviceIsSpecified)
1185    {
1186        return -1;
1187    }
1188
1189    if (_playIsInitialized)
1190    {
1191        return 0;
1192    }
1193
1194    // Initialize the speaker (devices might have been added or removed)
1195    if (InitSpeaker() == -1)
1196    {
1197        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
1198                     "  InitSpeaker() failed");
1199    }
1200
1201    // Set the play sample specification
1202    pa_sample_spec playSampleSpec;
1203    playSampleSpec.channels = _playChannels;
1204    playSampleSpec.format = PA_SAMPLE_S16LE;
1205    playSampleSpec.rate = sample_rate_hz_;
1206
1207    // Create a new play stream
1208    _playStream = LATE(pa_stream_new)(_paContext, "playStream",
1209                                      &playSampleSpec, NULL);
1210
1211    if (!_playStream)
1212    {
1213        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1214                     "  failed to create play stream, err=%d",
1215                     LATE(pa_context_errno)(_paContext));
1216        return -1;
1217    }
1218
1219    // Provide the playStream to the mixer
1220    _mixerManager.SetPlayStream(_playStream);
1221
1222    if (_ptrAudioBuffer)
1223    {
1224        // Update audio buffer with the selected parameters
1225        _ptrAudioBuffer->SetPlayoutSampleRate(sample_rate_hz_);
1226        _ptrAudioBuffer->SetPlayoutChannels((uint8_t) _playChannels);
1227    }
1228
1229    WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
1230                 "  stream state %d\n", LATE(pa_stream_get_state)(_playStream));
1231
1232    // Set stream flags
1233    _playStreamFlags = (pa_stream_flags_t) (PA_STREAM_AUTO_TIMING_UPDATE
1234        | PA_STREAM_INTERPOLATE_TIMING);
1235
1236    if (_configuredLatencyPlay != WEBRTC_PA_NO_LATENCY_REQUIREMENTS)
1237    {
1238        // If configuring a specific latency then we want to specify
1239        // PA_STREAM_ADJUST_LATENCY to make the server adjust parameters
1240        // automatically to reach that target latency. However, that flag doesn't
1241        // exist in Ubuntu 8.04 and many people still use that, so we have to check
1242        // the protocol version of libpulse.
1243        if (LATE(pa_context_get_protocol_version)(_paContext)
1244            >= WEBRTC_PA_ADJUST_LATENCY_PROTOCOL_VERSION)
1245        {
1246            _playStreamFlags |= PA_STREAM_ADJUST_LATENCY;
1247        }
1248
1249        const pa_sample_spec *spec =
1250            LATE(pa_stream_get_sample_spec)(_playStream);
1251        if (!spec)
1252        {
1253            WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1254                         "  pa_stream_get_sample_spec()");
1255            return -1;
1256        }
1257
1258        size_t bytesPerSec = LATE(pa_bytes_per_second)(spec);
1259        uint32_t latency = bytesPerSec
1260            * WEBRTC_PA_PLAYBACK_LATENCY_MINIMUM_MSECS / WEBRTC_PA_MSECS_PER_SEC;
1261
1262        // Set the play buffer attributes
1263        _playBufferAttr.maxlength = latency; // num bytes stored in the buffer
1264        _playBufferAttr.tlength = latency; // target fill level of play buffer
1265        // minimum free num bytes before server request more data
1266        _playBufferAttr.minreq = latency / WEBRTC_PA_PLAYBACK_REQUEST_FACTOR;
1267        _playBufferAttr.prebuf = _playBufferAttr.tlength
1268            - _playBufferAttr.minreq; // prebuffer tlength before starting playout
1269
1270        _configuredLatencyPlay = latency;
1271    }
1272
1273    // num samples in bytes * num channels
1274    _playbackBufferSize = sample_rate_hz_ / 100 * 2 * _playChannels;
1275    _playbackBufferUnused = _playbackBufferSize;
1276    _playBuffer = new int8_t[_playbackBufferSize];
1277
1278    // Enable underflow callback
1279    LATE(pa_stream_set_underflow_callback)(_playStream,
1280                                           PaStreamUnderflowCallback, this);
1281
1282    // Set the state callback function for the stream
1283    LATE(pa_stream_set_state_callback)(_playStream, PaStreamStateCallback, this);
1284
1285    // Mark playout side as initialized
1286    _playIsInitialized = true;
1287    _sndCardPlayDelay = 0;
1288    _sndCardRecDelay = 0;
1289
1290    return 0;
1291}
1292
1293int32_t AudioDeviceLinuxPulse::InitRecording()
1294{
1295
1296    CriticalSectionScoped lock(&_critSect);
1297
1298    if (_recording)
1299    {
1300        return -1;
1301    }
1302
1303    if (!_inputDeviceIsSpecified)
1304    {
1305        return -1;
1306    }
1307
1308    if (_recIsInitialized)
1309    {
1310        return 0;
1311    }
1312
1313    // Initialize the microphone (devices might have been added or removed)
1314    if (InitMicrophone() == -1)
1315    {
1316        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
1317                     "  InitMicrophone() failed");
1318    }
1319
1320    // Set the rec sample specification
1321    pa_sample_spec recSampleSpec;
1322    recSampleSpec.channels = _recChannels;
1323    recSampleSpec.format = PA_SAMPLE_S16LE;
1324    recSampleSpec.rate = sample_rate_hz_;
1325
1326    // Create a new rec stream
1327    _recStream = LATE(pa_stream_new)(_paContext, "recStream", &recSampleSpec,
1328                                     NULL);
1329    if (!_recStream)
1330    {
1331        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1332                     "  failed to create rec stream, err=%d",
1333                     LATE(pa_context_errno)(_paContext));
1334        return -1;
1335    }
1336
1337    // Provide the recStream to the mixer
1338    _mixerManager.SetRecStream(_recStream);
1339
1340    if (_ptrAudioBuffer)
1341    {
1342        // Update audio buffer with the selected parameters
1343        _ptrAudioBuffer->SetRecordingSampleRate(sample_rate_hz_);
1344        _ptrAudioBuffer->SetRecordingChannels((uint8_t) _recChannels);
1345    }
1346
1347    if (_configuredLatencyRec != WEBRTC_PA_NO_LATENCY_REQUIREMENTS)
1348    {
1349        _recStreamFlags = (pa_stream_flags_t) (PA_STREAM_AUTO_TIMING_UPDATE
1350            | PA_STREAM_INTERPOLATE_TIMING);
1351
1352        // If configuring a specific latency then we want to specify
1353        // PA_STREAM_ADJUST_LATENCY to make the server adjust parameters
1354        // automatically to reach that target latency. However, that flag doesn't
1355        // exist in Ubuntu 8.04 and many people still use that, so we have to check
1356        // the protocol version of libpulse.
1357        if (LATE(pa_context_get_protocol_version)(_paContext)
1358            >= WEBRTC_PA_ADJUST_LATENCY_PROTOCOL_VERSION)
1359        {
1360            _recStreamFlags |= PA_STREAM_ADJUST_LATENCY;
1361        }
1362
1363        const pa_sample_spec *spec =
1364            LATE(pa_stream_get_sample_spec)(_recStream);
1365        if (!spec)
1366        {
1367            WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1368                         "  pa_stream_get_sample_spec(rec)");
1369            return -1;
1370        }
1371
1372        size_t bytesPerSec = LATE(pa_bytes_per_second)(spec);
1373        uint32_t latency = bytesPerSec
1374            * WEBRTC_PA_LOW_CAPTURE_LATENCY_MSECS / WEBRTC_PA_MSECS_PER_SEC;
1375
1376        // Set the rec buffer attributes
1377        // Note: fragsize specifies a maximum transfer size, not a minimum, so
1378        // it is not possible to force a high latency setting, only a low one.
1379        _recBufferAttr.fragsize = latency; // size of fragment
1380        _recBufferAttr.maxlength = latency + bytesPerSec
1381            * WEBRTC_PA_CAPTURE_BUFFER_EXTRA_MSECS / WEBRTC_PA_MSECS_PER_SEC;
1382
1383        _configuredLatencyRec = latency;
1384    }
1385
1386    _recordBufferSize = sample_rate_hz_ / 100 * 2 * _recChannels;
1387    _recordBufferUsed = 0;
1388    _recBuffer = new int8_t[_recordBufferSize];
1389
1390    // Enable overflow callback
1391    LATE(pa_stream_set_overflow_callback)(_recStream, PaStreamOverflowCallback,
1392                                          this);
1393
1394    // Set the state callback function for the stream
1395    LATE(pa_stream_set_state_callback)(_recStream, PaStreamStateCallback, this);
1396
1397    // Mark recording side as initialized
1398    _recIsInitialized = true;
1399
1400    return 0;
1401}
1402
1403int32_t AudioDeviceLinuxPulse::StartRecording()
1404{
1405
1406    if (!_recIsInitialized)
1407    {
1408        return -1;
1409    }
1410
1411    if (_recording)
1412    {
1413        return 0;
1414    }
1415
1416    // set state to ensure that the recording starts from the audio thread
1417    _startRec = true;
1418
1419    // the audio thread will signal when recording has started
1420    _timeEventRec.Set();
1421    if (kEventTimeout == _recStartEvent.Wait(10000))
1422    {
1423        {
1424            CriticalSectionScoped lock(&_critSect);
1425            _startRec = false;
1426        }
1427        StopRecording();
1428        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1429                     "  failed to activate recording");
1430        return -1;
1431    }
1432
1433    {
1434        CriticalSectionScoped lock(&_critSect);
1435        if (_recording)
1436        {
1437            // the recording state is set by the audio thread after recording has started
1438        } else
1439        {
1440            WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1441                         "  failed to activate recording");
1442            return -1;
1443        }
1444    }
1445
1446    return 0;
1447}
1448
1449int32_t AudioDeviceLinuxPulse::StopRecording()
1450{
1451
1452    CriticalSectionScoped lock(&_critSect);
1453
1454    if (!_recIsInitialized)
1455    {
1456        return 0;
1457    }
1458
1459    if (_recStream == NULL)
1460    {
1461        return -1;
1462    }
1463
1464    _recIsInitialized = false;
1465    _recording = false;
1466
1467    WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
1468                 "  stopping recording");
1469
1470    // Stop Recording
1471    PaLock();
1472
1473    DisableReadCallback();
1474    LATE(pa_stream_set_overflow_callback)(_recStream, NULL, NULL);
1475
1476    // Unset this here so that we don't get a TERMINATED callback
1477    LATE(pa_stream_set_state_callback)(_recStream, NULL, NULL);
1478
1479    if (LATE(pa_stream_get_state)(_recStream) != PA_STREAM_UNCONNECTED)
1480    {
1481        // Disconnect the stream
1482        if (LATE(pa_stream_disconnect)(_recStream) != PA_OK)
1483        {
1484            WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1485                         "  failed to disconnect rec stream, err=%d\n",
1486                         LATE(pa_context_errno)(_paContext));
1487            PaUnLock();
1488            return -1;
1489        }
1490
1491        WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
1492                     "  disconnected recording");
1493    }
1494
1495    LATE(pa_stream_unref)(_recStream);
1496    _recStream = NULL;
1497
1498    PaUnLock();
1499
1500    // Provide the recStream to the mixer
1501    _mixerManager.SetRecStream(_recStream);
1502
1503    if (_recBuffer)
1504    {
1505        delete [] _recBuffer;
1506        _recBuffer = NULL;
1507    }
1508
1509    return 0;
1510}
1511
1512bool AudioDeviceLinuxPulse::RecordingIsInitialized() const
1513{
1514    return (_recIsInitialized);
1515}
1516
1517bool AudioDeviceLinuxPulse::Recording() const
1518{
1519    CriticalSectionScoped lock(&_critSect);
1520    return (_recording);
1521}
1522
1523bool AudioDeviceLinuxPulse::PlayoutIsInitialized() const
1524{
1525    return (_playIsInitialized);
1526}
1527
1528int32_t AudioDeviceLinuxPulse::StartPlayout()
1529{
1530    if (!_playIsInitialized)
1531    {
1532        return -1;
1533    }
1534
1535    if (_playing)
1536    {
1537        return 0;
1538    }
1539
1540    // set state to ensure that playout starts from the audio thread
1541    _startPlay = true;
1542
1543    // Both |_startPlay| and |_playing| needs protction since they are also
1544    // accessed on the playout thread.
1545
1546    // the audio thread will signal when playout has started
1547    _timeEventPlay.Set();
1548    if (kEventTimeout == _playStartEvent.Wait(10000))
1549    {
1550        {
1551            CriticalSectionScoped lock(&_critSect);
1552            _startPlay = false;
1553        }
1554        StopPlayout();
1555        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1556                     "  failed to activate playout");
1557        return -1;
1558    }
1559
1560    {
1561        CriticalSectionScoped lock(&_critSect);
1562        if (_playing)
1563        {
1564            // the playing state is set by the audio thread after playout has started
1565        } else
1566        {
1567            WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1568                         "  failed to activate playing");
1569            return -1;
1570        }
1571    }
1572
1573    return 0;
1574}
1575
1576int32_t AudioDeviceLinuxPulse::StopPlayout()
1577{
1578
1579    CriticalSectionScoped lock(&_critSect);
1580
1581    if (!_playIsInitialized)
1582    {
1583        return 0;
1584    }
1585
1586    if (_playStream == NULL)
1587    {
1588        return -1;
1589    }
1590
1591    _playIsInitialized = false;
1592    _playing = false;
1593    _sndCardPlayDelay = 0;
1594    _sndCardRecDelay = 0;
1595
1596    WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
1597                 "  stopping playback");
1598
1599    // Stop Playout
1600    PaLock();
1601
1602    DisableWriteCallback();
1603    LATE(pa_stream_set_underflow_callback)(_playStream, NULL, NULL);
1604
1605    // Unset this here so that we don't get a TERMINATED callback
1606    LATE(pa_stream_set_state_callback)(_playStream, NULL, NULL);
1607
1608    if (LATE(pa_stream_get_state)(_playStream) != PA_STREAM_UNCONNECTED)
1609    {
1610        // Disconnect the stream
1611        if (LATE(pa_stream_disconnect)(_playStream) != PA_OK)
1612        {
1613            WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1614                         "  failed to disconnect play stream, err=%d",
1615                         LATE(pa_context_errno)(_paContext));
1616            PaUnLock();
1617            return -1;
1618        }
1619
1620        WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
1621                     "  disconnected playback");
1622    }
1623
1624    LATE(pa_stream_unref)(_playStream);
1625    _playStream = NULL;
1626
1627    PaUnLock();
1628
1629    // Provide the playStream to the mixer
1630    _mixerManager.SetPlayStream(_playStream);
1631
1632    if (_playBuffer)
1633    {
1634        delete [] _playBuffer;
1635        _playBuffer = NULL;
1636    }
1637
1638    return 0;
1639}
1640
1641int32_t AudioDeviceLinuxPulse::PlayoutDelay(uint16_t& delayMS) const
1642{
1643    CriticalSectionScoped lock(&_critSect);
1644    delayMS = (uint16_t) _sndCardPlayDelay;
1645    return 0;
1646}
1647
1648int32_t AudioDeviceLinuxPulse::RecordingDelay(uint16_t& delayMS) const
1649{
1650    CriticalSectionScoped lock(&_critSect);
1651    delayMS = (uint16_t) _sndCardRecDelay;
1652    return 0;
1653}
1654
1655bool AudioDeviceLinuxPulse::Playing() const
1656{
1657    CriticalSectionScoped lock(&_critSect);
1658    return (_playing);
1659}
1660
1661int32_t AudioDeviceLinuxPulse::SetPlayoutBuffer(
1662    const AudioDeviceModule::BufferType type,
1663    uint16_t sizeMS)
1664{
1665
1666    if (type != AudioDeviceModule::kFixedBufferSize)
1667    {
1668        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1669                     " Adaptive buffer size not supported on this platform");
1670        return -1;
1671    }
1672
1673    _playBufType = type;
1674    _playBufDelayFixed = sizeMS;
1675
1676    return 0;
1677}
1678
1679int32_t AudioDeviceLinuxPulse::PlayoutBuffer(
1680    AudioDeviceModule::BufferType& type,
1681    uint16_t& sizeMS) const
1682{
1683
1684    type = _playBufType;
1685    sizeMS = _playBufDelayFixed;
1686
1687    return 0;
1688}
1689
1690int32_t AudioDeviceLinuxPulse::CPULoad(uint16_t& /*load*/) const
1691{
1692
1693    WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
1694                 "  API call not supported on this platform");
1695    return -1;
1696}
1697
1698bool AudioDeviceLinuxPulse::PlayoutWarning() const
1699{
1700  CriticalSectionScoped lock(&_critSect);
1701  return (_playWarning > 0);
1702}
1703
1704bool AudioDeviceLinuxPulse::PlayoutError() const
1705{
1706  CriticalSectionScoped lock(&_critSect);
1707  return (_playError > 0);
1708}
1709
1710bool AudioDeviceLinuxPulse::RecordingWarning() const
1711{
1712  CriticalSectionScoped lock(&_critSect);
1713  return (_recWarning > 0);
1714}
1715
1716bool AudioDeviceLinuxPulse::RecordingError() const
1717{
1718  CriticalSectionScoped lock(&_critSect);
1719  return (_recError > 0);
1720}
1721
1722void AudioDeviceLinuxPulse::ClearPlayoutWarning()
1723{
1724  CriticalSectionScoped lock(&_critSect);
1725  _playWarning = 0;
1726}
1727
1728void AudioDeviceLinuxPulse::ClearPlayoutError()
1729{
1730  CriticalSectionScoped lock(&_critSect);
1731  _playError = 0;
1732}
1733
1734void AudioDeviceLinuxPulse::ClearRecordingWarning()
1735{
1736  CriticalSectionScoped lock(&_critSect);
1737  _recWarning = 0;
1738}
1739
1740void AudioDeviceLinuxPulse::ClearRecordingError()
1741{
1742  CriticalSectionScoped lock(&_critSect);
1743  _recError = 0;
1744}
1745
1746// ============================================================================
1747//                                 Private Methods
1748// ============================================================================
1749
1750void AudioDeviceLinuxPulse::PaContextStateCallback(pa_context *c, void *pThis)
1751{
1752    static_cast<AudioDeviceLinuxPulse*> (pThis)->PaContextStateCallbackHandler(
1753        c);
1754}
1755
1756// ----------------------------------------------------------------------------
1757//  PaSinkInfoCallback
1758// ----------------------------------------------------------------------------
1759
1760void AudioDeviceLinuxPulse::PaSinkInfoCallback(pa_context */*c*/,
1761                                               const pa_sink_info *i, int eol,
1762                                               void *pThis)
1763{
1764    static_cast<AudioDeviceLinuxPulse*> (pThis)->PaSinkInfoCallbackHandler(
1765        i, eol);
1766}
1767
1768void AudioDeviceLinuxPulse::PaSourceInfoCallback(pa_context */*c*/,
1769                                                 const pa_source_info *i,
1770                                                 int eol, void *pThis)
1771{
1772    static_cast<AudioDeviceLinuxPulse*> (pThis)->PaSourceInfoCallbackHandler(
1773        i, eol);
1774}
1775
1776void AudioDeviceLinuxPulse::PaServerInfoCallback(pa_context */*c*/,
1777                                                 const pa_server_info *i,
1778                                                 void *pThis)
1779{
1780    static_cast<AudioDeviceLinuxPulse*> (pThis)->PaServerInfoCallbackHandler(i);
1781}
1782
1783void AudioDeviceLinuxPulse::PaStreamStateCallback(pa_stream *p, void *pThis)
1784{
1785    static_cast<AudioDeviceLinuxPulse*> (pThis)->PaStreamStateCallbackHandler(p);
1786}
1787
1788void AudioDeviceLinuxPulse::PaContextStateCallbackHandler(pa_context *c)
1789{
1790    WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
1791                 "  context state cb");
1792
1793    pa_context_state_t state = LATE(pa_context_get_state)(c);
1794    switch (state)
1795    {
1796        case PA_CONTEXT_UNCONNECTED:
1797            WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
1798                         "  unconnected");
1799            break;
1800        case PA_CONTEXT_CONNECTING:
1801        case PA_CONTEXT_AUTHORIZING:
1802        case PA_CONTEXT_SETTING_NAME:
1803            WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
1804                         "  no state");
1805            break;
1806        case PA_CONTEXT_FAILED:
1807        case PA_CONTEXT_TERMINATED:
1808            WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
1809                         "  failed");
1810            _paStateChanged = true;
1811            LATE(pa_threaded_mainloop_signal)(_paMainloop, 0);
1812            break;
1813        case PA_CONTEXT_READY:
1814            WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
1815                         "  ready");
1816            _paStateChanged = true;
1817            LATE(pa_threaded_mainloop_signal)(_paMainloop, 0);
1818            break;
1819    }
1820}
1821
1822void AudioDeviceLinuxPulse::PaSinkInfoCallbackHandler(const pa_sink_info *i,
1823                                                      int eol)
1824{
1825    if (eol)
1826    {
1827        // Signal that we are done
1828        LATE(pa_threaded_mainloop_signal)(_paMainloop, 0);
1829        return;
1830    }
1831
1832    if (_numPlayDevices == _deviceIndex)
1833    {
1834        // Convert the device index to the one of the sink
1835        _paDeviceIndex = i->index;
1836
1837        if (_playDeviceName)
1838        {
1839            // Copy the sink name
1840            strncpy(_playDeviceName, i->name, kAdmMaxDeviceNameSize);
1841            _playDeviceName[kAdmMaxDeviceNameSize - 1] = '\0';
1842        }
1843        if (_playDisplayDeviceName)
1844        {
1845            // Copy the sink display name
1846            strncpy(_playDisplayDeviceName, i->description,
1847                    kAdmMaxDeviceNameSize);
1848            _playDisplayDeviceName[kAdmMaxDeviceNameSize - 1] = '\0';
1849        }
1850    }
1851
1852    _numPlayDevices++;
1853}
1854
1855void AudioDeviceLinuxPulse::PaSourceInfoCallbackHandler(
1856    const pa_source_info *i,
1857    int eol)
1858{
1859    if (eol)
1860    {
1861        // Signal that we are done
1862        LATE(pa_threaded_mainloop_signal)(_paMainloop, 0);
1863        return;
1864    }
1865
1866    // We don't want to list output devices
1867     if (i->monitor_of_sink == PA_INVALID_INDEX)
1868    {
1869        if (_numRecDevices == _deviceIndex)
1870        {
1871            // Convert the device index to the one of the source
1872            _paDeviceIndex = i->index;
1873
1874            if (_recDeviceName)
1875            {
1876                // copy the source name
1877                strncpy(_recDeviceName, i->name, kAdmMaxDeviceNameSize);
1878                _recDeviceName[kAdmMaxDeviceNameSize - 1] = '\0';
1879            }
1880            if (_recDisplayDeviceName)
1881            {
1882                // Copy the source display name
1883                strncpy(_recDisplayDeviceName, i->description,
1884                        kAdmMaxDeviceNameSize);
1885                _recDisplayDeviceName[kAdmMaxDeviceNameSize - 1] = '\0';
1886            }
1887        }
1888
1889        _numRecDevices++;
1890    }
1891}
1892
1893void AudioDeviceLinuxPulse::PaServerInfoCallbackHandler(const pa_server_info *i)
1894{
1895    // Use PA native sampling rate
1896    sample_rate_hz_ = i->sample_spec.rate;
1897
1898    // Copy the PA server version
1899    strncpy(_paServerVersion, i->server_version, 31);
1900    _paServerVersion[31] = '\0';
1901
1902    if (_recDisplayDeviceName)
1903    {
1904        // Copy the source name
1905        strncpy(_recDisplayDeviceName, i->default_source_name,
1906                kAdmMaxDeviceNameSize);
1907        _recDisplayDeviceName[kAdmMaxDeviceNameSize - 1] = '\0';
1908    }
1909
1910    if (_playDisplayDeviceName)
1911    {
1912        // Copy the sink name
1913        strncpy(_playDisplayDeviceName, i->default_sink_name,
1914                kAdmMaxDeviceNameSize);
1915        _playDisplayDeviceName[kAdmMaxDeviceNameSize - 1] = '\0';
1916    }
1917
1918    LATE(pa_threaded_mainloop_signal)(_paMainloop, 0);
1919}
1920
1921void AudioDeviceLinuxPulse::PaStreamStateCallbackHandler(pa_stream *p)
1922{
1923    WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
1924                 "  stream state cb");
1925
1926    pa_stream_state_t state = LATE(pa_stream_get_state)(p);
1927    switch (state)
1928    {
1929        case PA_STREAM_UNCONNECTED:
1930            WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
1931                         "  unconnected");
1932            break;
1933        case PA_STREAM_CREATING:
1934            WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
1935                         "  creating");
1936            break;
1937        case PA_STREAM_FAILED:
1938        case PA_STREAM_TERMINATED:
1939            WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
1940                         "  failed");
1941            break;
1942        case PA_STREAM_READY:
1943            WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
1944                         "  ready");
1945            break;
1946    }
1947
1948    LATE(pa_threaded_mainloop_signal)(_paMainloop, 0);
1949}
1950
1951int32_t AudioDeviceLinuxPulse::CheckPulseAudioVersion()
1952{
1953    PaLock();
1954
1955    pa_operation* paOperation = NULL;
1956
1957    // get the server info and update deviceName
1958    paOperation = LATE(pa_context_get_server_info)(_paContext,
1959                                                   PaServerInfoCallback, this);
1960
1961    WaitForOperationCompletion(paOperation);
1962
1963    PaUnLock();
1964
1965    WEBRTC_TRACE(kTraceStateInfo, kTraceAudioDevice, -1,
1966                 "  checking PulseAudio version: %s", _paServerVersion);
1967
1968    return 0;
1969}
1970
1971int32_t AudioDeviceLinuxPulse::InitSamplingFrequency()
1972{
1973    PaLock();
1974
1975    pa_operation* paOperation = NULL;
1976
1977    // Get the server info and update sample_rate_hz_
1978    paOperation = LATE(pa_context_get_server_info)(_paContext,
1979                                                   PaServerInfoCallback, this);
1980
1981    WaitForOperationCompletion(paOperation);
1982
1983    PaUnLock();
1984
1985    return 0;
1986}
1987
1988int32_t AudioDeviceLinuxPulse::GetDefaultDeviceInfo(bool recDevice,
1989                                                    char* name,
1990                                                    uint16_t& index)
1991{
1992    char tmpName[kAdmMaxDeviceNameSize] = {0};
1993    // subtract length of "default: "
1994    uint16_t nameLen = kAdmMaxDeviceNameSize - 9;
1995    char* pName = NULL;
1996
1997    if (name)
1998    {
1999        // Add "default: "
2000        strcpy(name, "default: ");
2001        pName = &name[9];
2002    }
2003
2004    // Tell the callback that we want
2005    // the name for this device
2006    if (recDevice)
2007    {
2008        _recDisplayDeviceName = tmpName;
2009    } else
2010    {
2011        _playDisplayDeviceName = tmpName;
2012    }
2013
2014    // Set members
2015    _paDeviceIndex = -1;
2016    _deviceIndex = 0;
2017    _numPlayDevices = 0;
2018    _numRecDevices = 0;
2019
2020    PaLock();
2021
2022    pa_operation* paOperation = NULL;
2023
2024    // Get the server info and update deviceName
2025    paOperation = LATE(pa_context_get_server_info)(_paContext,
2026                                                   PaServerInfoCallback, this);
2027
2028    WaitForOperationCompletion(paOperation);
2029
2030    // Get the device index
2031    if (recDevice)
2032    {
2033        paOperation
2034            = LATE(pa_context_get_source_info_by_name)(_paContext,
2035                                                       (char *) tmpName,
2036                                                       PaSourceInfoCallback,
2037                                                       this);
2038    } else
2039    {
2040        paOperation
2041            = LATE(pa_context_get_sink_info_by_name)(_paContext,
2042                                                     (char *) tmpName,
2043                                                     PaSinkInfoCallback, this);
2044    }
2045
2046    WaitForOperationCompletion(paOperation);
2047
2048    PaUnLock();
2049
2050    // Set the index
2051    index = _paDeviceIndex;
2052
2053    if (name)
2054    {
2055        // Copy to name string
2056        strncpy(pName, tmpName, nameLen);
2057    }
2058
2059    // Clear members
2060    _playDisplayDeviceName = NULL;
2061    _recDisplayDeviceName = NULL;
2062    _paDeviceIndex = -1;
2063    _deviceIndex = -1;
2064    _numPlayDevices = 0;
2065    _numRecDevices = 0;
2066
2067    return 0;
2068}
2069
2070int32_t AudioDeviceLinuxPulse::InitPulseAudio()
2071{
2072    int retVal = 0;
2073
2074    // Load libpulse
2075    if (!PaSymbolTable.Load())
2076    {
2077        // Most likely the Pulse library and sound server are not installed on
2078        // this system
2079        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
2080                     "  failed to load symbol table");
2081        return -1;
2082    }
2083
2084    // Create a mainloop API and connection to the default server
2085    // the mainloop is the internal asynchronous API event loop
2086    if (_paMainloop) {
2087        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
2088                     "  PA mainloop has already existed");
2089        return -1;
2090    }
2091    _paMainloop = LATE(pa_threaded_mainloop_new)();
2092    if (!_paMainloop)
2093    {
2094        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
2095                     "  could not create mainloop");
2096        return -1;
2097    }
2098
2099    // Start the threaded main loop
2100    retVal = LATE(pa_threaded_mainloop_start)(_paMainloop);
2101    if (retVal != PA_OK)
2102    {
2103        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
2104                     "  failed to start main loop, error=%d", retVal);
2105        return -1;
2106    }
2107
2108    WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
2109                 "  mainloop running!");
2110
2111    PaLock();
2112
2113    _paMainloopApi = LATE(pa_threaded_mainloop_get_api)(_paMainloop);
2114    if (!_paMainloopApi)
2115    {
2116        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
2117                     "  could not create mainloop API");
2118        PaUnLock();
2119        return -1;
2120    }
2121
2122    // Create a new PulseAudio context
2123    if (_paContext){
2124        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
2125                     "  PA context has already existed");
2126        PaUnLock();
2127        return -1;
2128    }
2129    _paContext = LATE(pa_context_new)(_paMainloopApi, "WEBRTC VoiceEngine");
2130
2131    if (!_paContext)
2132    {
2133        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
2134                     "  could not create context");
2135        PaUnLock();
2136        return -1;
2137    }
2138
2139    // Set state callback function
2140    LATE(pa_context_set_state_callback)(_paContext, PaContextStateCallback,
2141                                        this);
2142
2143    // Connect the context to a server (default)
2144    _paStateChanged = false;
2145    retVal = LATE(pa_context_connect)(_paContext, NULL, PA_CONTEXT_NOAUTOSPAWN,
2146                                      NULL);
2147
2148    if (retVal != PA_OK)
2149    {
2150        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
2151                     "  failed to connect context, error=%d", retVal);
2152        PaUnLock();
2153        return -1;
2154    }
2155
2156    // Wait for state change
2157    while (!_paStateChanged)
2158    {
2159        LATE(pa_threaded_mainloop_wait)(_paMainloop);
2160    }
2161
2162    // Now check to see what final state we reached.
2163    pa_context_state_t state = LATE(pa_context_get_state)(_paContext);
2164
2165    if (state != PA_CONTEXT_READY)
2166    {
2167        if (state == PA_CONTEXT_FAILED)
2168        {
2169            WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
2170                         "  failed to connect to PulseAudio sound server");
2171        } else if (state == PA_CONTEXT_TERMINATED)
2172        {
2173            WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
2174                         "  PulseAudio connection terminated early");
2175        } else
2176        {
2177            // Shouldn't happen, because we only signal on one of those three
2178            // states
2179            WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
2180                         "  unknown problem connecting to PulseAudio");
2181        }
2182        PaUnLock();
2183        return -1;
2184    }
2185
2186    PaUnLock();
2187
2188    // Give the objects to the mixer manager
2189    _mixerManager.SetPulseAudioObjects(_paMainloop, _paContext);
2190
2191    // Check the version
2192    if (CheckPulseAudioVersion() < 0)
2193    {
2194        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
2195                     "  PulseAudio version %s not supported", _paServerVersion);
2196        return -1;
2197    }
2198
2199    // Initialize sampling frequency
2200    if (InitSamplingFrequency() < 0 || sample_rate_hz_ == 0)
2201    {
2202        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
2203                     "  failed to initialize sampling frequency, set to %d Hz",
2204                     sample_rate_hz_);
2205        return -1;
2206    }
2207
2208    return 0;
2209}
2210
2211int32_t AudioDeviceLinuxPulse::TerminatePulseAudio()
2212{
2213    // Do nothing if the instance doesn't exist
2214    // likely PaSymbolTable.Load() fails
2215    if (!_paMainloop) {
2216        return 0;
2217    }
2218
2219    PaLock();
2220
2221    // Disconnect the context
2222    if (_paContext)
2223    {
2224        LATE(pa_context_disconnect)(_paContext);
2225    }
2226
2227    // Unreference the context
2228    if (_paContext)
2229    {
2230        LATE(pa_context_unref)(_paContext);
2231    }
2232
2233    PaUnLock();
2234    _paContext = NULL;
2235
2236    // Stop the threaded main loop
2237    if (_paMainloop)
2238    {
2239        LATE(pa_threaded_mainloop_stop)(_paMainloop);
2240    }
2241
2242    // Free the mainloop
2243    if (_paMainloop)
2244    {
2245        LATE(pa_threaded_mainloop_free)(_paMainloop);
2246    }
2247
2248    _paMainloop = NULL;
2249
2250    WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
2251                 "  PulseAudio terminated");
2252
2253    return 0;
2254}
2255
2256void AudioDeviceLinuxPulse::PaLock()
2257{
2258    LATE(pa_threaded_mainloop_lock)(_paMainloop);
2259}
2260
2261void AudioDeviceLinuxPulse::PaUnLock()
2262{
2263    LATE(pa_threaded_mainloop_unlock)(_paMainloop);
2264}
2265
2266void AudioDeviceLinuxPulse::WaitForOperationCompletion(
2267    pa_operation* paOperation) const
2268{
2269    if (!paOperation)
2270    {
2271        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
2272                     "paOperation NULL in WaitForOperationCompletion");
2273        return;
2274    }
2275
2276    while (LATE(pa_operation_get_state)(paOperation) == PA_OPERATION_RUNNING)
2277    {
2278        LATE(pa_threaded_mainloop_wait)(_paMainloop);
2279    }
2280
2281    LATE(pa_operation_unref)(paOperation);
2282}
2283
2284// ============================================================================
2285//                                  Thread Methods
2286// ============================================================================
2287
2288void AudioDeviceLinuxPulse::EnableWriteCallback()
2289{
2290    if (LATE(pa_stream_get_state)(_playStream) == PA_STREAM_READY)
2291    {
2292        // May already have available space. Must check.
2293        _tempBufferSpace = LATE(pa_stream_writable_size)(_playStream);
2294        if (_tempBufferSpace > 0)
2295        {
2296            // Yup, there is already space available, so if we register a write
2297            // callback then it will not receive any event. So dispatch one ourself
2298            // instead
2299            _timeEventPlay.Set();
2300            return;
2301        }
2302    }
2303
2304    LATE(pa_stream_set_write_callback)(_playStream, &PaStreamWriteCallback,
2305                                       this);
2306}
2307
2308void AudioDeviceLinuxPulse::DisableWriteCallback()
2309{
2310    LATE(pa_stream_set_write_callback)(_playStream, NULL, NULL);
2311}
2312
2313void AudioDeviceLinuxPulse::PaStreamWriteCallback(pa_stream */*unused*/,
2314                                                  size_t buffer_space,
2315                                                  void *pThis)
2316{
2317    static_cast<AudioDeviceLinuxPulse*> (pThis)->PaStreamWriteCallbackHandler(
2318        buffer_space);
2319}
2320
2321void AudioDeviceLinuxPulse::PaStreamWriteCallbackHandler(size_t bufferSpace)
2322{
2323    _tempBufferSpace = bufferSpace;
2324
2325    // Since we write the data asynchronously on a different thread, we have
2326    // to temporarily disable the write callback or else Pulse will call it
2327    // continuously until we write the data. We re-enable it below.
2328    DisableWriteCallback();
2329    _timeEventPlay.Set();
2330}
2331
2332void AudioDeviceLinuxPulse::PaStreamUnderflowCallback(pa_stream */*unused*/,
2333                                                      void *pThis)
2334{
2335    static_cast<AudioDeviceLinuxPulse*> (pThis)->PaStreamUnderflowCallbackHandler();
2336}
2337
2338void AudioDeviceLinuxPulse::PaStreamUnderflowCallbackHandler()
2339{
2340    WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
2341                 "  Playout underflow");
2342
2343    if (_configuredLatencyPlay == WEBRTC_PA_NO_LATENCY_REQUIREMENTS)
2344    {
2345        // We didn't configure a pa_buffer_attr before, so switching to one now
2346        // would be questionable.
2347        return;
2348    }
2349
2350    // Otherwise reconfigure the stream with a higher target latency.
2351
2352    const pa_sample_spec *spec = LATE(pa_stream_get_sample_spec)(_playStream);
2353    if (!spec)
2354    {
2355        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
2356                     "  pa_stream_get_sample_spec()");
2357        return;
2358    }
2359
2360    size_t bytesPerSec = LATE(pa_bytes_per_second)(spec);
2361    uint32_t newLatency = _configuredLatencyPlay + bytesPerSec
2362        * WEBRTC_PA_PLAYBACK_LATENCY_INCREMENT_MSECS / WEBRTC_PA_MSECS_PER_SEC;
2363
2364    // Set the play buffer attributes
2365    _playBufferAttr.maxlength = newLatency;
2366    _playBufferAttr.tlength = newLatency;
2367    _playBufferAttr.minreq = newLatency / WEBRTC_PA_PLAYBACK_REQUEST_FACTOR;
2368    _playBufferAttr.prebuf = _playBufferAttr.tlength - _playBufferAttr.minreq;
2369
2370    pa_operation *op = LATE(pa_stream_set_buffer_attr)(_playStream,
2371                                                       &_playBufferAttr, NULL,
2372                                                       NULL);
2373    if (!op)
2374    {
2375        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
2376                     "  pa_stream_set_buffer_attr()");
2377        return;
2378    }
2379
2380    // Don't need to wait for this to complete.
2381    LATE(pa_operation_unref)(op);
2382
2383    // Save the new latency in case we underflow again.
2384    _configuredLatencyPlay = newLatency;
2385}
2386
2387void AudioDeviceLinuxPulse::EnableReadCallback()
2388{
2389    LATE(pa_stream_set_read_callback)(_recStream, &PaStreamReadCallback, this);
2390}
2391
2392void AudioDeviceLinuxPulse::DisableReadCallback()
2393{
2394    LATE(pa_stream_set_read_callback)(_recStream, NULL, NULL);
2395}
2396
2397void AudioDeviceLinuxPulse::PaStreamReadCallback(pa_stream */*unused1*/,
2398                                                 size_t /*unused2*/,
2399                                                 void *pThis)
2400{
2401    static_cast<AudioDeviceLinuxPulse*> (pThis)->PaStreamReadCallbackHandler();
2402}
2403
2404void AudioDeviceLinuxPulse::PaStreamReadCallbackHandler()
2405{
2406    // We get the data pointer and size now in order to save one Lock/Unlock
2407    // in the worker thread
2408    if (LATE(pa_stream_peek)(_recStream, &_tempSampleData, &_tempSampleDataSize)
2409        != 0)
2410    {
2411        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
2412                     "  Can't read data!");
2413        return;
2414    }
2415
2416    // Since we consume the data asynchronously on a different thread, we have
2417    // to temporarily disable the read callback or else Pulse will call it
2418    // continuously until we consume the data. We re-enable it below
2419    DisableReadCallback();
2420    _timeEventRec.Set();
2421}
2422
2423void AudioDeviceLinuxPulse::PaStreamOverflowCallback(pa_stream */*unused*/,
2424                                                     void *pThis)
2425{
2426    static_cast<AudioDeviceLinuxPulse*> (pThis)->PaStreamOverflowCallbackHandler();
2427}
2428
2429void AudioDeviceLinuxPulse::PaStreamOverflowCallbackHandler()
2430{
2431    WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
2432                 "  Recording overflow");
2433}
2434
2435int32_t AudioDeviceLinuxPulse::LatencyUsecs(pa_stream *stream)
2436{
2437    if (!WEBRTC_PA_REPORT_LATENCY)
2438    {
2439        return 0;
2440    }
2441
2442    if (!stream)
2443    {
2444        return 0;
2445    }
2446
2447    pa_usec_t latency;
2448    int negative;
2449    if (LATE(pa_stream_get_latency)(stream, &latency, &negative) != 0)
2450    {
2451        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
2452                     "  Can't query latency");
2453        // We'd rather continue playout/capture with an incorrect delay than stop
2454        // it altogether, so return a valid value.
2455        return 0;
2456    }
2457
2458    if (negative)
2459    {
2460        WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
2461                     "  warning: pa_stream_get_latency reported negative delay");
2462
2463        // The delay can be negative for monitoring streams if the captured
2464        // samples haven't been played yet. In such a case, "latency" contains the
2465        // magnitude, so we must negate it to get the real value.
2466        int32_t tmpLatency = (int32_t) -latency;
2467        if (tmpLatency < 0)
2468        {
2469            // Make sure that we don't use a negative delay
2470            tmpLatency = 0;
2471        }
2472
2473        return tmpLatency;
2474    } else
2475    {
2476        return (int32_t) latency;
2477    }
2478}
2479
2480int32_t AudioDeviceLinuxPulse::ReadRecordedData(const void* bufferData,
2481                                                size_t bufferSize)
2482{
2483    size_t size = bufferSize;
2484    uint32_t numRecSamples = _recordBufferSize / (2 * _recChannels);
2485
2486    // Account for the peeked data and the used data
2487    uint32_t recDelay = (uint32_t) ((LatencyUsecs(_recStream)
2488        / 1000) + 10 * ((size + _recordBufferUsed) / _recordBufferSize));
2489
2490    _sndCardRecDelay = recDelay;
2491
2492    if (_playStream)
2493    {
2494        // Get the playout delay
2495        _sndCardPlayDelay = (uint32_t) (LatencyUsecs(_playStream) / 1000);
2496    }
2497
2498    if (_recordBufferUsed > 0)
2499    {
2500        // Have to copy to the buffer until it is full
2501        size_t copy = _recordBufferSize - _recordBufferUsed;
2502        if (size < copy)
2503        {
2504            copy = size;
2505        }
2506
2507        memcpy(&_recBuffer[_recordBufferUsed], bufferData, copy);
2508        _recordBufferUsed += copy;
2509        bufferData = static_cast<const char *> (bufferData) + copy;
2510        size -= copy;
2511
2512        if (_recordBufferUsed != _recordBufferSize)
2513        {
2514            // Not enough data yet to pass to VoE
2515            return 0;
2516        }
2517
2518        // Provide data to VoiceEngine
2519        if (ProcessRecordedData(_recBuffer, numRecSamples, recDelay) == -1)
2520        {
2521            // We have stopped recording
2522            return -1;
2523        }
2524
2525        _recordBufferUsed = 0;
2526    }
2527
2528    // Now process full 10ms sample sets directly from the input
2529    while (size >= _recordBufferSize)
2530    {
2531        // Provide data to VoiceEngine
2532        if (ProcessRecordedData(
2533            static_cast<int8_t *> (const_cast<void *> (bufferData)),
2534            numRecSamples, recDelay) == -1)
2535        {
2536            // We have stopped recording
2537            return -1;
2538        }
2539
2540        bufferData = static_cast<const char *> (bufferData) + _recordBufferSize;
2541        size -= _recordBufferSize;
2542
2543        // We have consumed 10ms of data
2544        recDelay -= 10;
2545    }
2546
2547    // Now save any leftovers for later.
2548    if (size > 0)
2549    {
2550        memcpy(_recBuffer, bufferData, size);
2551        _recordBufferUsed = size;
2552    }
2553
2554    return 0;
2555}
2556
2557int32_t AudioDeviceLinuxPulse::ProcessRecordedData(
2558    int8_t *bufferData,
2559    uint32_t bufferSizeInSamples,
2560    uint32_t recDelay) EXCLUSIVE_LOCKS_REQUIRED(_critSect)
2561{
2562    uint32_t currentMicLevel(0);
2563    uint32_t newMicLevel(0);
2564
2565    _ptrAudioBuffer->SetRecordedBuffer(bufferData, bufferSizeInSamples);
2566
2567    if (AGC())
2568    {
2569        // Store current mic level in the audio buffer if AGC is enabled
2570        if (MicrophoneVolume(currentMicLevel) == 0)
2571        {
2572            // This call does not affect the actual microphone volume
2573            _ptrAudioBuffer->SetCurrentMicLevel(currentMicLevel);
2574        }
2575    }
2576
2577    const uint32_t clockDrift(0);
2578    // TODO(andrew): this is a temporary hack, to avoid non-causal far- and
2579    // near-end signals at the AEC for PulseAudio. I think the system delay is
2580    // being correctly calculated here, but for legacy reasons we add +10 ms to
2581    // the value in the AEC. The real fix will be part of a larger investigation
2582    // into managing system delay in the AEC.
2583    if (recDelay > 10)
2584        recDelay -= 10;
2585    else
2586        recDelay = 0;
2587    _ptrAudioBuffer->SetVQEData(_sndCardPlayDelay, recDelay, clockDrift);
2588    _ptrAudioBuffer->SetTypingStatus(KeyPressed());
2589    // Deliver recorded samples at specified sample rate,
2590    // mic level etc. to the observer using callback
2591    UnLock();
2592    _ptrAudioBuffer->DeliverRecordedData();
2593    Lock();
2594
2595    // We have been unlocked - check the flag again
2596    if (!_recording)
2597    {
2598        return -1;
2599    }
2600
2601    if (AGC())
2602    {
2603        newMicLevel = _ptrAudioBuffer->NewMicLevel();
2604        if (newMicLevel != 0)
2605        {
2606            // The VQE will only deliver non-zero microphone levels when a
2607            // change is needed.
2608            // Set this new mic level (received from the observer as return
2609            // value in the callback).
2610            WEBRTC_TRACE(kTraceStream, kTraceAudioDevice, _id,
2611                         "  AGC change of volume: old=%u => new=%u",
2612                         currentMicLevel, newMicLevel);
2613            if (SetMicrophoneVolume(newMicLevel) == -1)
2614            {
2615                WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice,
2616                             _id,
2617                             "  the required modification of the microphone "
2618                             "volume failed");
2619            }
2620        }
2621    }
2622
2623    return 0;
2624}
2625
2626bool AudioDeviceLinuxPulse::PlayThreadFunc(void* pThis)
2627{
2628    return (static_cast<AudioDeviceLinuxPulse*> (pThis)->PlayThreadProcess());
2629}
2630
2631bool AudioDeviceLinuxPulse::RecThreadFunc(void* pThis)
2632{
2633    return (static_cast<AudioDeviceLinuxPulse*> (pThis)->RecThreadProcess());
2634}
2635
2636bool AudioDeviceLinuxPulse::PlayThreadProcess()
2637{
2638    switch (_timeEventPlay.Wait(1000))
2639    {
2640        case kEventSignaled:
2641            _timeEventPlay.Reset();
2642            break;
2643        case kEventError:
2644            WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
2645                         "EventWrapper::Wait() failed");
2646            return true;
2647        case kEventTimeout:
2648            return true;
2649    }
2650
2651    Lock();
2652
2653    if (_startPlay)
2654    {
2655        WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
2656                     "_startPlay true, performing initial actions");
2657
2658        _startPlay = false;
2659        _playDeviceName = NULL;
2660
2661        // Set if not default device
2662        if (_outputDeviceIndex > 0)
2663        {
2664            // Get the playout device name
2665            _playDeviceName = new char[kAdmMaxDeviceNameSize];
2666            _deviceIndex = _outputDeviceIndex;
2667            PlayoutDevices();
2668        }
2669
2670        // Start muted only supported on 0.9.11 and up
2671        if (LATE(pa_context_get_protocol_version)(_paContext)
2672            >= WEBRTC_PA_ADJUST_LATENCY_PROTOCOL_VERSION)
2673        {
2674            // Get the currently saved speaker mute status
2675            // and set the initial mute status accordingly
2676            bool enabled(false);
2677            _mixerManager.SpeakerMute(enabled);
2678            if (enabled)
2679            {
2680                _playStreamFlags |= PA_STREAM_START_MUTED;
2681            }
2682        }
2683
2684        // Get the currently saved speaker volume
2685        uint32_t volume = 0;
2686        if (update_speaker_volume_at_startup_)
2687          _mixerManager.SpeakerVolume(volume);
2688
2689        PaLock();
2690
2691        // NULL gives PA the choice of startup volume.
2692        pa_cvolume* ptr_cvolume = NULL;
2693        if (update_speaker_volume_at_startup_) {
2694          pa_cvolume cVolumes;
2695          ptr_cvolume = &cVolumes;
2696
2697          // Set the same volume for all channels
2698          const pa_sample_spec *spec =
2699              LATE(pa_stream_get_sample_spec)(_playStream);
2700          LATE(pa_cvolume_set)(&cVolumes, spec->channels, volume);
2701          update_speaker_volume_at_startup_ = false;
2702        }
2703
2704        // Connect the stream to a sink
2705        if (LATE(pa_stream_connect_playback)(
2706            _playStream,
2707            _playDeviceName,
2708            &_playBufferAttr,
2709            (pa_stream_flags_t) _playStreamFlags,
2710            ptr_cvolume, NULL) != PA_OK)
2711        {
2712            WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
2713                         "  failed to connect play stream, err=%d",
2714                         LATE(pa_context_errno)(_paContext));
2715        }
2716
2717        WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
2718                     "  play stream connected");
2719
2720        // Wait for state change
2721        while (LATE(pa_stream_get_state)(_playStream) != PA_STREAM_READY)
2722        {
2723            LATE(pa_threaded_mainloop_wait)(_paMainloop);
2724        }
2725
2726        WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
2727                     "  play stream ready");
2728
2729        // We can now handle write callbacks
2730        EnableWriteCallback();
2731
2732        PaUnLock();
2733
2734        // Clear device name
2735        if (_playDeviceName)
2736        {
2737            delete [] _playDeviceName;
2738            _playDeviceName = NULL;
2739        }
2740
2741        _playing = true;
2742        _playStartEvent.Set();
2743
2744        UnLock();
2745        return true;
2746    }
2747
2748    if (_playing)
2749    {
2750        if (!_recording)
2751        {
2752            // Update the playout delay
2753            _sndCardPlayDelay = (uint32_t) (LatencyUsecs(_playStream)
2754                / 1000);
2755        }
2756
2757        if (_playbackBufferUnused < _playbackBufferSize)
2758        {
2759
2760            size_t write = _playbackBufferSize - _playbackBufferUnused;
2761            if (_tempBufferSpace < write)
2762            {
2763                write = _tempBufferSpace;
2764            }
2765
2766            PaLock();
2767            if (LATE(pa_stream_write)(
2768                                      _playStream,
2769                                      (void *) &_playBuffer[_playbackBufferUnused],
2770                                      write, NULL, (int64_t) 0,
2771                                      PA_SEEK_RELATIVE) != PA_OK)
2772            {
2773                _writeErrors++;
2774                if (_writeErrors > 10)
2775                {
2776                    if (_playError == 1)
2777                    {
2778                        WEBRTC_TRACE(kTraceWarning,
2779                                     kTraceUtility, _id,
2780                                     "  pending playout error exists");
2781                    }
2782                    _playError = 1; // Triggers callback from module process thread
2783                    WEBRTC_TRACE(
2784                                 kTraceError,
2785                                 kTraceUtility,
2786                                 _id,
2787                                 "  kPlayoutError message posted: "
2788                                 "_writeErrors=%u, error=%d",
2789                                 _writeErrors,
2790                                 LATE(pa_context_errno)(_paContext));
2791                    _writeErrors = 0;
2792                }
2793            }
2794            PaUnLock();
2795
2796            _playbackBufferUnused += write;
2797            _tempBufferSpace -= write;
2798        }
2799
2800        uint32_t numPlaySamples = _playbackBufferSize / (2 * _playChannels);
2801        if (_tempBufferSpace > 0) // Might have been reduced to zero by the above
2802        {
2803            // Ask for new PCM data to be played out using the AudioDeviceBuffer
2804            // ensure that this callback is executed without taking the
2805            // audio-thread lock
2806            UnLock();
2807            WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
2808                         "  requesting data");
2809            uint32_t nSamples =
2810                _ptrAudioBuffer->RequestPlayoutData(numPlaySamples);
2811            Lock();
2812
2813            // We have been unlocked - check the flag again
2814            if (!_playing)
2815            {
2816                UnLock();
2817                return true;
2818            }
2819
2820            nSamples = _ptrAudioBuffer->GetPlayoutData(_playBuffer);
2821            if (nSamples != numPlaySamples)
2822            {
2823                WEBRTC_TRACE(kTraceError, kTraceAudioDevice,
2824                             _id, "  invalid number of output samples(%d)",
2825                             nSamples);
2826            }
2827
2828            size_t write = _playbackBufferSize;
2829            if (_tempBufferSpace < write)
2830            {
2831                write = _tempBufferSpace;
2832            }
2833
2834            WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
2835                         "  will write");
2836            PaLock();
2837            if (LATE(pa_stream_write)(_playStream, (void *) &_playBuffer[0],
2838                                      write, NULL, (int64_t) 0,
2839                                      PA_SEEK_RELATIVE) != PA_OK)
2840            {
2841                _writeErrors++;
2842                if (_writeErrors > 10)
2843                {
2844                    if (_playError == 1)
2845                    {
2846                        WEBRTC_TRACE(kTraceWarning,
2847                                     kTraceUtility, _id,
2848                                     "  pending playout error exists");
2849                    }
2850                    _playError = 1; // triggers callback from module process thread
2851                    WEBRTC_TRACE(
2852                                 kTraceError,
2853                                 kTraceUtility,
2854                                 _id,
2855                                 "  kPlayoutError message posted: "
2856                                 "_writeErrors=%u, error=%d",
2857                                 _writeErrors,
2858                                 LATE(pa_context_errno)(_paContext));
2859                    _writeErrors = 0;
2860                }
2861            }
2862            PaUnLock();
2863
2864            _playbackBufferUnused = write;
2865        }
2866
2867        _tempBufferSpace = 0;
2868        PaLock();
2869        EnableWriteCallback();
2870        PaUnLock();
2871
2872    }  // _playing
2873
2874    UnLock();
2875    return true;
2876}
2877
2878bool AudioDeviceLinuxPulse::RecThreadProcess()
2879{
2880    switch (_timeEventRec.Wait(1000))
2881    {
2882        case kEventSignaled:
2883            _timeEventRec.Reset();
2884            break;
2885        case kEventError:
2886            WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
2887                         "EventWrapper::Wait() failed");
2888            return true;
2889        case kEventTimeout:
2890            return true;
2891    }
2892
2893    Lock();
2894
2895    if (_startRec)
2896    {
2897        WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
2898                     "_startRec true, performing initial actions");
2899
2900        _recDeviceName = NULL;
2901
2902        // Set if not default device
2903        if (_inputDeviceIndex > 0)
2904        {
2905            // Get the recording device name
2906            _recDeviceName = new char[kAdmMaxDeviceNameSize];
2907            _deviceIndex = _inputDeviceIndex;
2908            RecordingDevices();
2909        }
2910
2911        PaLock();
2912
2913        WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
2914                     "  connecting stream");
2915
2916        // Connect the stream to a source
2917        if (LATE(pa_stream_connect_record)(_recStream, _recDeviceName,
2918                                           &_recBufferAttr,
2919                                           (pa_stream_flags_t) _recStreamFlags)
2920            != PA_OK)
2921        {
2922            WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
2923                         "  failed to connect rec stream, err=%d",
2924                         LATE(pa_context_errno)(_paContext));
2925        }
2926
2927        WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
2928                     "  connected");
2929
2930        // Wait for state change
2931        while (LATE(pa_stream_get_state)(_recStream) != PA_STREAM_READY)
2932        {
2933            LATE(pa_threaded_mainloop_wait)(_paMainloop);
2934        }
2935
2936        WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
2937                     "  done");
2938
2939        // We can now handle read callbacks
2940        EnableReadCallback();
2941
2942        PaUnLock();
2943
2944        // Clear device name
2945        if (_recDeviceName)
2946        {
2947            delete [] _recDeviceName;
2948            _recDeviceName = NULL;
2949        }
2950
2951        _startRec = false;
2952        _recording = true;
2953        _recStartEvent.Set();
2954
2955        UnLock();
2956        return true;
2957    }
2958
2959    if (_recording)
2960    {
2961        // Read data and provide it to VoiceEngine
2962        if (ReadRecordedData(_tempSampleData, _tempSampleDataSize) == -1)
2963        {
2964            UnLock();
2965            return true;
2966        }
2967
2968        _tempSampleData = NULL;
2969        _tempSampleDataSize = 0;
2970
2971        PaLock();
2972        while (true)
2973        {
2974            // Ack the last thing we read
2975            if (LATE(pa_stream_drop)(_recStream) != 0)
2976            {
2977                WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice,
2978                             _id, "  failed to drop, err=%d\n",
2979                             LATE(pa_context_errno)(_paContext));
2980            }
2981
2982            if (LATE(pa_stream_readable_size)(_recStream) <= 0)
2983            {
2984                // Then that was all the data
2985                break;
2986            }
2987
2988            // Else more data.
2989            const void *sampleData;
2990            size_t sampleDataSize;
2991
2992            if (LATE(pa_stream_peek)(_recStream, &sampleData, &sampleDataSize)
2993                != 0)
2994            {
2995                _recError = 1; // triggers callback from module process thread
2996                WEBRTC_TRACE(kTraceError, kTraceAudioDevice,
2997                             _id, "  RECORD_ERROR message posted, error = %d",
2998                             LATE(pa_context_errno)(_paContext));
2999                break;
3000            }
3001
3002            _sndCardRecDelay = (uint32_t) (LatencyUsecs(_recStream)
3003                / 1000);
3004
3005            // Drop lock for sigslot dispatch, which could take a while.
3006            PaUnLock();
3007            // Read data and provide it to VoiceEngine
3008            if (ReadRecordedData(sampleData, sampleDataSize) == -1)
3009            {
3010                UnLock();
3011                return true;
3012            }
3013            PaLock();
3014
3015            // Return to top of loop for the ack and the check for more data.
3016        }
3017
3018        EnableReadCallback();
3019        PaUnLock();
3020
3021    }  // _recording
3022
3023    UnLock();
3024    return true;
3025}
3026
3027bool AudioDeviceLinuxPulse::KeyPressed() const{
3028
3029  char szKey[32];
3030  unsigned int i = 0;
3031  char state = 0;
3032
3033  if (!_XDisplay)
3034    return false;
3035
3036  // Check key map status
3037  XQueryKeymap(_XDisplay, szKey);
3038
3039  // A bit change in keymap means a key is pressed
3040  for (i = 0; i < sizeof(szKey); i++)
3041    state |= (szKey[i] ^ _oldKeyState[i]) & szKey[i];
3042
3043  // Save old state
3044  memcpy((char*)_oldKeyState, (char*)szKey, sizeof(_oldKeyState));
3045  return (state != 0);
3046}
3047}
3048