Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / webrtc / modules / audio_device / linux / audio_device_pulse_linux.cc
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
21 webrtc_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
29 namespace webrtc
30 {
31
32 // ============================================================================
33 //                              Static Methods
34 // ============================================================================
35
36 AudioDeviceLinuxPulse::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
113 AudioDeviceLinuxPulse::~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
148 void 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
168 int32_t AudioDeviceLinuxPulse::ActiveAudioLayer(
169     AudioDeviceModule::AudioLayer& audioLayer) const
170 {
171     audioLayer = AudioDeviceModule::kLinuxPulseAudio;
172     return 0;
173 }
174
175 int32_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
264 int32_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
339 bool AudioDeviceLinuxPulse::Initialized() const
340 {
341     return (_initialized);
342 }
343
344 int32_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
389 int32_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
434 bool AudioDeviceLinuxPulse::SpeakerIsInitialized() const
435 {
436     return (_mixerManager.SpeakerIsInitialized());
437 }
438
439 bool AudioDeviceLinuxPulse::MicrophoneIsInitialized() const
440 {
441     return (_mixerManager.MicrophoneIsInitialized());
442 }
443
444 int32_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
471 int32_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
480 int32_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
495 int32_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
505 int32_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
515 int32_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
531 int32_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
547 int32_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
563 int32_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
595 int32_t AudioDeviceLinuxPulse::SetSpeakerMute(bool enable)
596 {
597
598     return (_mixerManager.SetSpeakerMute(enable));
599 }
600
601 int32_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
614 int32_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
647 int32_t AudioDeviceLinuxPulse::SetMicrophoneMute(bool enable)
648 {
649
650     return (_mixerManager.SetMicrophoneMute(enable));
651 }
652
653 int32_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
666 int32_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
697 int32_t AudioDeviceLinuxPulse::SetMicrophoneBoost(bool enable)
698 {
699
700     return (_mixerManager.SetMicrophoneBoost(enable));
701 }
702
703 int32_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
718 int32_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
752 int32_t AudioDeviceLinuxPulse::SetStereoRecording(bool enable)
753 {
754
755     if (enable)
756         _recChannels = 2;
757     else
758         _recChannels = 1;
759
760     return 0;
761 }
762
763 int32_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
774 int32_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
807 int32_t AudioDeviceLinuxPulse::SetStereoPlayout(bool enable)
808 {
809
810     if (enable)
811         _playChannels = 2;
812     else
813         _playChannels = 1;
814
815     return 0;
816 }
817
818 int32_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
829 int32_t AudioDeviceLinuxPulse::SetAGC(bool enable)
830 {
831
832     _AGC = enable;
833
834     return 0;
835 }
836
837 bool AudioDeviceLinuxPulse::AGC() const
838 {
839
840     return _AGC;
841 }
842
843 int32_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
872 int32_t AudioDeviceLinuxPulse::SetMicrophoneVolume(uint32_t volume)
873 {
874
875     return (_mixerManager.SetMicrophoneVolume(volume));
876 }
877
878 int32_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
896 int32_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
912 int32_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
928 int32_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
944 int16_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
964 int32_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
990 int32_t AudioDeviceLinuxPulse::SetPlayoutDevice(
991     AudioDeviceModule::WindowsDeviceType /*device*/)
992 {
993     WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
994                  "WindowsDeviceType not supported");
995     return -1;
996 }
997
998 int32_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
1040 int32_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
1082 int16_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
1102 int32_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
1128 int32_t AudioDeviceLinuxPulse::SetRecordingDevice(
1129     AudioDeviceModule::WindowsDeviceType /*device*/)
1130 {
1131     WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1132                  "WindowsDeviceType not supported");
1133     return -1;
1134 }
1135
1136 int32_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
1155 int32_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
1174 int32_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
1293 int32_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
1403 int32_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
1449 int32_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
1512 bool AudioDeviceLinuxPulse::RecordingIsInitialized() const
1513 {
1514     return (_recIsInitialized);
1515 }
1516
1517 bool AudioDeviceLinuxPulse::Recording() const
1518 {
1519     CriticalSectionScoped lock(&_critSect);
1520     return (_recording);
1521 }
1522
1523 bool AudioDeviceLinuxPulse::PlayoutIsInitialized() const
1524 {
1525     return (_playIsInitialized);
1526 }
1527
1528 int32_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
1576 int32_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
1641 int32_t AudioDeviceLinuxPulse::PlayoutDelay(uint16_t& delayMS) const
1642 {
1643     CriticalSectionScoped lock(&_critSect);
1644     delayMS = (uint16_t) _sndCardPlayDelay;
1645     return 0;
1646 }
1647
1648 int32_t AudioDeviceLinuxPulse::RecordingDelay(uint16_t& delayMS) const
1649 {
1650     CriticalSectionScoped lock(&_critSect);
1651     delayMS = (uint16_t) _sndCardRecDelay;
1652     return 0;
1653 }
1654
1655 bool AudioDeviceLinuxPulse::Playing() const
1656 {
1657     CriticalSectionScoped lock(&_critSect);
1658     return (_playing);
1659 }
1660
1661 int32_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
1679 int32_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
1690 int32_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
1698 bool AudioDeviceLinuxPulse::PlayoutWarning() const
1699 {
1700   CriticalSectionScoped lock(&_critSect);
1701   return (_playWarning > 0);
1702 }
1703
1704 bool AudioDeviceLinuxPulse::PlayoutError() const
1705 {
1706   CriticalSectionScoped lock(&_critSect);
1707   return (_playError > 0);
1708 }
1709
1710 bool AudioDeviceLinuxPulse::RecordingWarning() const
1711 {
1712   CriticalSectionScoped lock(&_critSect);
1713   return (_recWarning > 0);
1714 }
1715
1716 bool AudioDeviceLinuxPulse::RecordingError() const
1717 {
1718   CriticalSectionScoped lock(&_critSect);
1719   return (_recError > 0);
1720 }
1721
1722 void AudioDeviceLinuxPulse::ClearPlayoutWarning()
1723 {
1724   CriticalSectionScoped lock(&_critSect);
1725   _playWarning = 0;
1726 }
1727
1728 void AudioDeviceLinuxPulse::ClearPlayoutError()
1729 {
1730   CriticalSectionScoped lock(&_critSect);
1731   _playError = 0;
1732 }
1733
1734 void AudioDeviceLinuxPulse::ClearRecordingWarning()
1735 {
1736   CriticalSectionScoped lock(&_critSect);
1737   _recWarning = 0;
1738 }
1739
1740 void AudioDeviceLinuxPulse::ClearRecordingError()
1741 {
1742   CriticalSectionScoped lock(&_critSect);
1743   _recError = 0;
1744 }
1745
1746 // ============================================================================
1747 //                                 Private Methods
1748 // ============================================================================
1749
1750 void AudioDeviceLinuxPulse::PaContextStateCallback(pa_context *c, void *pThis)
1751 {
1752     static_cast<AudioDeviceLinuxPulse*> (pThis)->PaContextStateCallbackHandler(
1753         c);
1754 }
1755
1756 // ----------------------------------------------------------------------------
1757 //  PaSinkInfoCallback
1758 // ----------------------------------------------------------------------------
1759
1760 void 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
1768 void 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
1776 void AudioDeviceLinuxPulse::PaServerInfoCallback(pa_context */*c*/,
1777                                                  const pa_server_info *i,
1778                                                  void *pThis)
1779 {
1780     static_cast<AudioDeviceLinuxPulse*> (pThis)->PaServerInfoCallbackHandler(i);
1781 }
1782
1783 void AudioDeviceLinuxPulse::PaStreamStateCallback(pa_stream *p, void *pThis)
1784 {
1785     static_cast<AudioDeviceLinuxPulse*> (pThis)->PaStreamStateCallbackHandler(p);
1786 }
1787
1788 void 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
1822 void 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
1855 void 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
1893 void 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
1921 void 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
1951 int32_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
1971 int32_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
1988 int32_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
2070 int32_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
2211 int32_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
2256 void AudioDeviceLinuxPulse::PaLock()
2257 {
2258     LATE(pa_threaded_mainloop_lock)(_paMainloop);
2259 }
2260
2261 void AudioDeviceLinuxPulse::PaUnLock()
2262 {
2263     LATE(pa_threaded_mainloop_unlock)(_paMainloop);
2264 }
2265
2266 void 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
2288 void 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
2308 void AudioDeviceLinuxPulse::DisableWriteCallback()
2309 {
2310     LATE(pa_stream_set_write_callback)(_playStream, NULL, NULL);
2311 }
2312
2313 void 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
2321 void 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
2332 void AudioDeviceLinuxPulse::PaStreamUnderflowCallback(pa_stream */*unused*/,
2333                                                       void *pThis)
2334 {
2335     static_cast<AudioDeviceLinuxPulse*> (pThis)->PaStreamUnderflowCallbackHandler();
2336 }
2337
2338 void 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
2387 void AudioDeviceLinuxPulse::EnableReadCallback()
2388 {
2389     LATE(pa_stream_set_read_callback)(_recStream, &PaStreamReadCallback, this);
2390 }
2391
2392 void AudioDeviceLinuxPulse::DisableReadCallback()
2393 {
2394     LATE(pa_stream_set_read_callback)(_recStream, NULL, NULL);
2395 }
2396
2397 void AudioDeviceLinuxPulse::PaStreamReadCallback(pa_stream */*unused1*/,
2398                                                  size_t /*unused2*/,
2399                                                  void *pThis)
2400 {
2401     static_cast<AudioDeviceLinuxPulse*> (pThis)->PaStreamReadCallbackHandler();
2402 }
2403
2404 void 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
2423 void AudioDeviceLinuxPulse::PaStreamOverflowCallback(pa_stream */*unused*/,
2424                                                      void *pThis)
2425 {
2426     static_cast<AudioDeviceLinuxPulse*> (pThis)->PaStreamOverflowCallbackHandler();
2427 }
2428
2429 void AudioDeviceLinuxPulse::PaStreamOverflowCallbackHandler()
2430 {
2431     WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
2432                  "  Recording overflow");
2433 }
2434
2435 int32_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
2480 int32_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
2557 int32_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
2626 bool AudioDeviceLinuxPulse::PlayThreadFunc(void* pThis)
2627 {
2628     return (static_cast<AudioDeviceLinuxPulse*> (pThis)->PlayThreadProcess());
2629 }
2630
2631 bool AudioDeviceLinuxPulse::RecThreadFunc(void* pThis)
2632 {
2633     return (static_cast<AudioDeviceLinuxPulse*> (pThis)->RecThreadProcess());
2634 }
2635
2636 bool 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
2878 bool 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
3027 bool 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 }