1b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org/*
2b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *
4b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  Use of this source code is governed by a BSD-style license
5b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  that can be found in the LICENSE file in the root of the source
6b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  tree. An additional intellectual property rights grant can be found
7b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  in the file PATENTS.  All contributing project authors may
8b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
9b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org */
10b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
113f45c2e0ac4cb280f941efa3a3476895795e3dd6pbos@webrtc.org#include <assert.h>
12b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
13bc669ace8f09d73e95f923253ecdadd366f9b7f1pbos@webrtc.org#include "webrtc/modules/audio_device/audio_device_config.h"
14bc669ace8f09d73e95f923253ecdadd366f9b7f1pbos@webrtc.org#include "webrtc/modules/audio_device/audio_device_utility.h"
15bc669ace8f09d73e95f923253ecdadd366f9b7f1pbos@webrtc.org#include "webrtc/modules/audio_device/linux/audio_device_alsa_linux.h"
16b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
17bc669ace8f09d73e95f923253ecdadd366f9b7f1pbos@webrtc.org#include "webrtc/system_wrappers/interface/event_wrapper.h"
18bc669ace8f09d73e95f923253ecdadd366f9b7f1pbos@webrtc.org#include "webrtc/system_wrappers/interface/sleep.h"
19bc669ace8f09d73e95f923253ecdadd366f9b7f1pbos@webrtc.org#include "webrtc/system_wrappers/interface/thread_wrapper.h"
20bc669ace8f09d73e95f923253ecdadd366f9b7f1pbos@webrtc.org#include "webrtc/system_wrappers/interface/trace.h"
21b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
22b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgwebrtc_adm_linux_alsa::AlsaSymbolTable AlsaSymbolTable;
23b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
24b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Accesses ALSA functions through our late-binding symbol table instead of
25b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// directly. This way we don't have to link to libasound, which means our binary
26b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// will work on systems that don't have it.
27b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#define LATE(sym) \
28b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  LATESYM_GET(webrtc_adm_linux_alsa::AlsaSymbolTable, &AlsaSymbolTable, sym)
29b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
30b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Redefine these here to be able to do late-binding
31b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#undef snd_ctl_card_info_alloca
32b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#define snd_ctl_card_info_alloca(ptr) \
33b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        do { *ptr = (snd_ctl_card_info_t *) \
34b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            __builtin_alloca (LATE(snd_ctl_card_info_sizeof)()); \
35b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            memset(*ptr, 0, LATE(snd_ctl_card_info_sizeof)()); } while (0)
36b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
37b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#undef snd_pcm_info_alloca
38b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#define snd_pcm_info_alloca(pInfo) \
39b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org       do { *pInfo = (snd_pcm_info_t *) \
40b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org       __builtin_alloca (LATE(snd_pcm_info_sizeof)()); \
41b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org       memset(*pInfo, 0, LATE(snd_pcm_info_sizeof)()); } while (0)
42b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
43b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// snd_lib_error_handler_t
44b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid WebrtcAlsaErrorHandler(const char *file,
45b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                          int line,
46b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                          const char *function,
47b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                          int err,
48b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                          const char *fmt,...){};
49b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
50b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgnamespace webrtc
51b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
52b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgstatic const unsigned int ALSA_PLAYOUT_FREQ = 48000;
53b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgstatic const unsigned int ALSA_PLAYOUT_CH = 2;
54b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgstatic const unsigned int ALSA_PLAYOUT_LATENCY = 40*1000; // in us
55b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgstatic const unsigned int ALSA_CAPTURE_FREQ = 48000;
56b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgstatic const unsigned int ALSA_CAPTURE_CH = 2;
57b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgstatic const unsigned int ALSA_CAPTURE_LATENCY = 40*1000; // in us
58b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgstatic const unsigned int ALSA_CAPTURE_WAIT_TIMEOUT = 5; // in ms
59b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
60b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#define FUNC_GET_NUM_OF_DEVICE 0
61b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#define FUNC_GET_DEVICE_NAME 1
62b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#define FUNC_GET_DEVICE_NAME_FOR_AN_ENUM 2
63b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
6464a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgAudioDeviceLinuxALSA::AudioDeviceLinuxALSA(const int32_t id) :
65b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _ptrAudioBuffer(NULL),
66b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _critSect(*CriticalSectionWrapper::CreateCriticalSection()),
67b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _ptrThreadRec(NULL),
68b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _ptrThreadPlay(NULL),
69b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _recThreadID(0),
70b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playThreadID(0),
71b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _id(id),
72b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _mixerManager(id),
73b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _inputDeviceIndex(0),
74b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _outputDeviceIndex(0),
75b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _inputDeviceIsSpecified(false),
76b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _outputDeviceIsSpecified(false),
77b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _handleRecord(NULL),
78b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _handlePlayout(NULL),
79b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _recordingBuffersizeInFrame(0),
80b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _recordingPeriodSizeInFrame(0),
81b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playoutBufferSizeInFrame(0),
82b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playoutPeriodSizeInFrame(0),
83b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _recordingBufferSizeIn10MS(0),
84b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playoutBufferSizeIn10MS(0),
85b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _recordingFramesIn10MS(0),
86b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playoutFramesIn10MS(0),
87b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _recordingFreq(ALSA_CAPTURE_FREQ),
88b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playoutFreq(ALSA_PLAYOUT_FREQ),
89b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _recChannels(ALSA_CAPTURE_CH),
90b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playChannels(ALSA_PLAYOUT_CH),
91b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _recordingBuffer(NULL),
92b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playoutBuffer(NULL),
93b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _recordingFramesLeft(0),
94b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playoutFramesLeft(0),
95b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playBufType(AudioDeviceModule::kFixedBufferSize),
96b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _initialized(false),
97b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _recording(false),
98b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playing(false),
99b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _recIsInitialized(false),
100b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playIsInitialized(false),
101b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _AGC(false),
102b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _recordingDelay(0),
103b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playoutDelay(0),
104b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playWarning(0),
105b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playError(0),
106b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _recWarning(0),
107b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _recError(0),
108b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playBufDelay(80),
109b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playBufDelayFixed(80)
110b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
11132b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org    memset(_oldKeyState, 0, sizeof(_oldKeyState));
112b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, id,
113b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "%s created", __FUNCTION__);
114b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
115b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
116b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// ----------------------------------------------------------------------------
117b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//  AudioDeviceLinuxALSA - dtor
118b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// ----------------------------------------------------------------------------
119b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
120b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgAudioDeviceLinuxALSA::~AudioDeviceLinuxALSA()
121b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
122b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id,
123b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "%s destroyed", __FUNCTION__);
1249e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org
125b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    Terminate();
126b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
127b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Clean up the recording buffer and playout buffer.
128b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_recordingBuffer)
129b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
130b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        delete [] _recordingBuffer;
131b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _recordingBuffer = NULL;
132b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
133b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_playoutBuffer)
134b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
135b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        delete [] _playoutBuffer;
136b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _playoutBuffer = NULL;
137b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
138b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    delete &_critSect;
139b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
140b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
141b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid AudioDeviceLinuxALSA::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer)
142b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
143b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
144b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped lock(&_critSect);
145b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
146b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _ptrAudioBuffer = audioBuffer;
147b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
148b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Inform the AudioBuffer about default settings for this implementation.
149b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Set all values to zero here since the actual settings will be done by
150b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // InitPlayout and InitRecording later.
151b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _ptrAudioBuffer->SetRecordingSampleRate(0);
152b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _ptrAudioBuffer->SetPlayoutSampleRate(0);
153b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _ptrAudioBuffer->SetRecordingChannels(0);
154b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _ptrAudioBuffer->SetPlayoutChannels(0);
155b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
156b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
15764a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::ActiveAudioLayer(
158b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    AudioDeviceModule::AudioLayer& audioLayer) const
159b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
160b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    audioLayer = AudioDeviceModule::kLinuxAlsaAudio;
161b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
162b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
163b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
16464a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::Init()
165b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
166b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
167b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped lock(&_critSect);
168b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
169b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Load libasound
170b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!AlsaSymbolTable.Load())
171b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
172b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Alsa is not installed on
173b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // this system
174b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
175b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                   "  failed to load symbol table");
176b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
177b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
178b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
179b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_initialized)
180b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
181b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
182b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
18346b817d939765bef587c575720c18764e3b03fd4fbarchard@google.com#if defined(USE_X11)
18432b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org    //Get X display handle for typing detection
18532b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org    _XDisplay = XOpenDisplay(NULL);
18632b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org    if (!_XDisplay)
18732b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org    {
18832b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
18932b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org          "  failed to open X display, typing detection will not work");
19032b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org    }
19146b817d939765bef587c575720c18764e3b03fd4fbarchard@google.com#endif
192b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playWarning = 0;
193b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playError = 0;
194b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _recWarning = 0;
195b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _recError = 0;
196b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
197b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _initialized = true;
198b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
199b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
200b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
201b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
20264a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::Terminate()
203b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
204b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
205b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_initialized)
206b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
207b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
208b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
209b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
210b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped lock(&_critSect);
211b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
212b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _mixerManager.Close();
213b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
214b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // RECORDING
215b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_ptrThreadRec)
216b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
217b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        ThreadWrapper* tmpThread = _ptrThreadRec;
218b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _ptrThreadRec = NULL;
219b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _critSect.Leave();
220b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
221b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        tmpThread->SetNotAlive();
222b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
223b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (tmpThread->Stop())
224b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
225b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            delete tmpThread;
226b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
227b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        else
228b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
229b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
230b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         "  failed to close down the rec audio thread");
231b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
232b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
233b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _critSect.Enter();
234b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
235b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
236b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // PLAYOUT
237b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_ptrThreadPlay)
238b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
239b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        ThreadWrapper* tmpThread = _ptrThreadPlay;
240b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _ptrThreadPlay = NULL;
241b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _critSect.Leave();
242b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
243b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        tmpThread->SetNotAlive();
244b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
245b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (tmpThread->Stop())
246b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
247b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            delete tmpThread;
248b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
249b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        else
250b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
251b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
252b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         "  failed to close down the play audio thread");
253b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
254b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
255b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _critSect.Enter();
256b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
25746b817d939765bef587c575720c18764e3b03fd4fbarchard@google.com#if defined(USE_X11)
25832b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org    if (_XDisplay)
25932b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org    {
26032b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org      XCloseDisplay(_XDisplay);
26132b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org      _XDisplay = NULL;
26232b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org    }
26346b817d939765bef587c575720c18764e3b03fd4fbarchard@google.com#endif
264b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _initialized = false;
265b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _outputDeviceIsSpecified = false;
266b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _inputDeviceIsSpecified = false;
267b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
268b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
269b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
270b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
271b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceLinuxALSA::Initialized() const
272b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
273b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return (_initialized);
274b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
275b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
27664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::InitSpeaker()
277b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
278b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
279b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped lock(&_critSect);
280b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
281b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_playing)
282b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
283b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
284b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
285b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
286b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    char devName[kAdmMaxDeviceNameSize] = {0};
287b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    GetDevicesInfo(2, true, _outputDeviceIndex, devName, kAdmMaxDeviceNameSize);
288b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return _mixerManager.OpenSpeaker(devName);
289b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
290b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
29164a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::InitMicrophone()
292b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
293b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
294b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped lock(&_critSect);
295b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
296b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_recording)
297b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
298b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
299b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
300b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
301b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    char devName[kAdmMaxDeviceNameSize] = {0};
302b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    GetDevicesInfo(2, false, _inputDeviceIndex, devName, kAdmMaxDeviceNameSize);
303b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return _mixerManager.OpenMicrophone(devName);
304b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
305b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
306b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceLinuxALSA::SpeakerIsInitialized() const
307b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
308b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return (_mixerManager.SpeakerIsInitialized());
309b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
310b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
311b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceLinuxALSA::MicrophoneIsInitialized() const
312b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
313b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return (_mixerManager.MicrophoneIsInitialized());
314b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
315b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
31664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::SpeakerVolumeIsAvailable(bool& available)
317b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
318b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
319b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    bool wasInitialized = _mixerManager.SpeakerIsInitialized();
320b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
321b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Make an attempt to open up the
322b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // output mixer corresponding to the currently selected output device.
323b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!wasInitialized && InitSpeaker() == -1)
324b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
325b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // If we end up here it means that the selected speaker has no volume
326b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // control.
327b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        available = false;
328b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
329b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
330b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
331b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Given that InitSpeaker was successful, we know that a volume control
332b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // exists
333b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    available = true;
334b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
335b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Close the initialized output mixer
336b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!wasInitialized)
337b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
338b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _mixerManager.CloseSpeaker();
339b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
340b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
341b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
342b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
343b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
34464a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::SetSpeakerVolume(uint32_t volume)
345b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
346b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
347b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return (_mixerManager.SetSpeakerVolume(volume));
348b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
349b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
35064a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::SpeakerVolume(uint32_t& volume) const
351b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
352b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
35364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    uint32_t level(0);
354b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
355b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_mixerManager.SpeakerVolume(level) == -1)
356b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
357b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
358b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
359b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
360b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    volume = level;
3619e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org
362b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
363b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
364b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
365b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
36664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::SetWaveOutVolume(uint16_t volumeLeft,
36764a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org                                               uint16_t volumeRight)
368b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
369b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
370b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
371b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "  API call not supported on this platform");
372b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return -1;
373b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
374b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
37564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::WaveOutVolume(
37664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    uint16_t& /*volumeLeft*/,
37764a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    uint16_t& /*volumeRight*/) const
378b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
379b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
380b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
381b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "  API call not supported on this platform");
382b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return -1;
383b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
384b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
38564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::MaxSpeakerVolume(
38664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    uint32_t& maxVolume) const
387b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
388b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
38964a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    uint32_t maxVol(0);
390b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
391b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_mixerManager.MaxSpeakerVolume(maxVol) == -1)
392b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
393b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
394b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
395b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
396b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    maxVolume = maxVol;
3979e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org
398b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
399b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
400b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
40164a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::MinSpeakerVolume(
40264a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    uint32_t& minVolume) const
403b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
404b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
40564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    uint32_t minVol(0);
406b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
407b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_mixerManager.MinSpeakerVolume(minVol) == -1)
408b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
409b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
410b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
411b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
412b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    minVolume = minVol;
4139e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org
414b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
415b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
416b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
41764a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::SpeakerVolumeStepSize(
41864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    uint16_t& stepSize) const
419b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
420b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
4219e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org    uint16_t delta(0);
4229e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org
423b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_mixerManager.SpeakerVolumeStepSize(delta) == -1)
424b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
425b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
426b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
427b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
428b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    stepSize = delta;
429b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
430b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
431b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
432b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
43364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::SpeakerMuteIsAvailable(bool& available)
434b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
435b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
436b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    bool isAvailable(false);
437b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    bool wasInitialized = _mixerManager.SpeakerIsInitialized();
438b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
439b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Make an attempt to open up the
440b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // output mixer corresponding to the currently selected output device.
441b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //
442b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!wasInitialized && InitSpeaker() == -1)
443b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
444b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // If we end up here it means that the selected speaker has no volume
445b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // control, hence it is safe to state that there is no mute control
446b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // already at this stage.
447b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        available = false;
448b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
449b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
450b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
451b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Check if the selected speaker has a mute control
452b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _mixerManager.SpeakerMuteIsAvailable(isAvailable);
453b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
454b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    available = isAvailable;
455b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
456b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Close the initialized output mixer
457b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!wasInitialized)
458b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
459b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _mixerManager.CloseSpeaker();
460b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
461b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
462b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
463b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
464b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
46564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::SetSpeakerMute(bool enable)
466b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
467b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return (_mixerManager.SetSpeakerMute(enable));
468b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
469b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
47064a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::SpeakerMute(bool& enabled) const
471b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
472b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
4739e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org    bool muted(0);
4749e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org
475b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_mixerManager.SpeakerMute(muted) == -1)
476b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
477b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
478b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
479b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
480b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    enabled = muted;
4819e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org
482b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
483b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
484b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
48564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::MicrophoneMuteIsAvailable(bool& available)
486b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
487b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
488b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    bool isAvailable(false);
489b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    bool wasInitialized = _mixerManager.MicrophoneIsInitialized();
490b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
491b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Make an attempt to open up the
492b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // input mixer corresponding to the currently selected input device.
493b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //
494b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!wasInitialized && InitMicrophone() == -1)
495b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
496b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // If we end up here it means that the selected microphone has no volume
497b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // control, hence it is safe to state that there is no mute control
498b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // already at this stage.
499b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        available = false;
500b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
501b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
502b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
503b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Check if the selected microphone has a mute control
504b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //
505b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _mixerManager.MicrophoneMuteIsAvailable(isAvailable);
506b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    available = isAvailable;
507b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
508b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Close the initialized input mixer
509b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //
510b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!wasInitialized)
511b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
512b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _mixerManager.CloseMicrophone();
513b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
514b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
515b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
516b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
517b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
51864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::SetMicrophoneMute(bool enable)
519b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
520b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return (_mixerManager.SetMicrophoneMute(enable));
521b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
522b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
523b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// ----------------------------------------------------------------------------
524b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//  MicrophoneMute
525b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// ----------------------------------------------------------------------------
526b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
52764a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::MicrophoneMute(bool& enabled) const
528b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
529b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
5309e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org    bool muted(0);
5319e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org
532b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_mixerManager.MicrophoneMute(muted) == -1)
533b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
534b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
535b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
536b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
537b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    enabled = muted;
538b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
539b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
540b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
54164a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::MicrophoneBoostIsAvailable(bool& available)
542b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
5439e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org
544b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    bool isAvailable(false);
545b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    bool wasInitialized = _mixerManager.MicrophoneIsInitialized();
546b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
547b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Enumerate all avaliable microphone and make an attempt to open up the
548b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // input mixer corresponding to the currently selected input device.
549b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //
550b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!wasInitialized && InitMicrophone() == -1)
551b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
552b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // If we end up here it means that the selected microphone has no volume
553b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // control, hence it is safe to state that there is no boost control
554b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // already at this stage.
555b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        available = false;
556b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
557b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
558b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
559b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Check if the selected microphone has a boost control
560b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _mixerManager.MicrophoneBoostIsAvailable(isAvailable);
561b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    available = isAvailable;
562b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
563b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Close the initialized input mixer
564b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!wasInitialized)
565b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
566b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _mixerManager.CloseMicrophone();
567b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
568b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
569b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
570b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
571b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
57264a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::SetMicrophoneBoost(bool enable)
573b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
574b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
575b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return (_mixerManager.SetMicrophoneBoost(enable));
576b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
577b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
57864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::MicrophoneBoost(bool& enabled) const
579b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
580b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
5819e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org    bool onOff(0);
5829e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org
583b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_mixerManager.MicrophoneBoost(onOff) == -1)
584b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
585b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
586b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
587b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
588b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    enabled = onOff;
5899e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org
590b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
591b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
592b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
59364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::StereoRecordingIsAvailable(bool& available)
594b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
595b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
596b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped lock(&_critSect);
597b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
598b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // If we already have initialized in stereo it's obviously available
599b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_recIsInitialized && (2 == _recChannels))
600b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
601b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        available = true;
602b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
603b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
604b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
605b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Save rec states and the number of rec channels
606b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    bool recIsInitialized = _recIsInitialized;
607b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    bool recording = _recording;
608b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int recChannels = _recChannels;
609b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
610b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    available = false;
6119e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org
612b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Stop/uninitialize recording if initialized (and possibly started)
613b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_recIsInitialized)
614b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
615b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        StopRecording();
616b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
617b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
618b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Try init in stereo;
619b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _recChannels = 2;
620b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (InitRecording() == 0)
621b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
622b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        available = true;
623b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
624b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
625b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Stop/uninitialize recording
626b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    StopRecording();
627b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
628b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Recover previous states
629b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _recChannels = recChannels;
630b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (recIsInitialized)
631b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
632b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        InitRecording();
633b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
634b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (recording)
635b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
636b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        StartRecording();
637b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
638b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
639b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
640b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
641b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
64264a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::SetStereoRecording(bool enable)
643b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
644b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
645b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (enable)
646b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _recChannels = 2;
647b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    else
648b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _recChannels = 1;
649b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
650b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
651b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
652b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
65364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::StereoRecording(bool& enabled) const
654b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
655b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
656b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_recChannels == 2)
657b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        enabled = true;
658b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    else
659b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        enabled = false;
660b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
661b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
662b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
663b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
66464a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::StereoPlayoutIsAvailable(bool& available)
665b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
666b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
667b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped lock(&_critSect);
668b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
669b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // If we already have initialized in stereo it's obviously available
670b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_playIsInitialized && (2 == _playChannels))
671b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
672b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        available = true;
673b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
674b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
675b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
676b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Save rec states and the number of rec channels
677b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    bool playIsInitialized = _playIsInitialized;
678b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    bool playing = _playing;
679b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int playChannels = _playChannels;
680b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
681b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    available = false;
6829e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org
683b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Stop/uninitialize recording if initialized (and possibly started)
684b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_playIsInitialized)
685b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
686b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        StopPlayout();
687b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
688b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
689b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Try init in stereo;
690b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playChannels = 2;
691b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (InitPlayout() == 0)
692b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
693b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        available = true;
694b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
695b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
696b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Stop/uninitialize recording
697b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    StopPlayout();
698b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
699b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Recover previous states
700b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playChannels = playChannels;
701b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (playIsInitialized)
702b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
703b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        InitPlayout();
704b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
705b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (playing)
706b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
707b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        StartPlayout();
708b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
709b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
710b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
711b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
712b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
71364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::SetStereoPlayout(bool enable)
714b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
715b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
716b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (enable)
717b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _playChannels = 2;
718b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    else
719b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _playChannels = 1;
720b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
721b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
722b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
723b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
72464a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::StereoPlayout(bool& enabled) const
725b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
726b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
727b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_playChannels == 2)
728b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        enabled = true;
729b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    else
730b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        enabled = false;
731b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
732b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
733b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
734b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
73564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::SetAGC(bool enable)
736b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
737b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
738b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _AGC = enable;
739b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
740b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
741b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
742b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
743b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceLinuxALSA::AGC() const
744b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
745b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
746b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return _AGC;
747b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
748b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
74964a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::MicrophoneVolumeIsAvailable(bool& available)
750b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
751b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
752b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    bool wasInitialized = _mixerManager.MicrophoneIsInitialized();
753b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
754b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Make an attempt to open up the
755b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // input mixer corresponding to the currently selected output device.
756b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!wasInitialized && InitMicrophone() == -1)
757b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
758b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // If we end up here it means that the selected microphone has no volume
759b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // control.
760b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        available = false;
761b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
762b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
763b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
764b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Given that InitMicrophone was successful, we know that a volume control
765b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // exists
766b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    available = true;
767b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
768b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Close the initialized input mixer
769b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!wasInitialized)
770b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
771b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _mixerManager.CloseMicrophone();
772b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
773b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
774b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
775b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
776b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
77764a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::SetMicrophoneVolume(uint32_t volume)
778b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
779b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
780b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return (_mixerManager.SetMicrophoneVolume(volume));
7819e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org
782b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
783b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
784b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
78564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::MicrophoneVolume(uint32_t& volume) const
786b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
787b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
78864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    uint32_t level(0);
789b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
790b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_mixerManager.MicrophoneVolume(level) == -1)
791b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
792b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
793b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  failed to retrive current microphone level");
794b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
795b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
796b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
797b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    volume = level;
7989e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org
799b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
800b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
801b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
80264a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::MaxMicrophoneVolume(
80364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    uint32_t& maxVolume) const
804b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
805b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
80664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    uint32_t maxVol(0);
807b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
808b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_mixerManager.MaxMicrophoneVolume(maxVol) == -1)
809b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
810b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
811b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
812b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
813b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    maxVolume = maxVol;
814b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
815b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
816b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
817b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
81864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::MinMicrophoneVolume(
81964a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    uint32_t& minVolume) const
820b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
821b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
82264a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    uint32_t minVol(0);
823b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
824b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_mixerManager.MinMicrophoneVolume(minVol) == -1)
825b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
826b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
827b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
828b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
829b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    minVolume = minVol;
830b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
831b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
832b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
833b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
83464a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::MicrophoneVolumeStepSize(
83564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    uint16_t& stepSize) const
836b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
837b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
8389e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org    uint16_t delta(0);
8399e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org
840b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_mixerManager.MicrophoneVolumeStepSize(delta) == -1)
841b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
842b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
843b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
844b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
845b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    stepSize = delta;
846b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
847b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
848b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
849b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
85064a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint16_t AudioDeviceLinuxALSA::PlayoutDevices()
851b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
852b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
85364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    return (int16_t)GetDevicesInfo(0, true);
854b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
855b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
85664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::SetPlayoutDevice(uint16_t index)
857b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
858b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
859b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_playIsInitialized)
860b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
861b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
862b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
863b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
86464a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    uint32_t nDevices = GetDevicesInfo(0, true);
865b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
866b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "  number of availiable audio output devices is %u", nDevices);
867b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
868b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (index > (nDevices-1))
869b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
870b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
871b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  device index is out of range [0,%u]", (nDevices-1));
872b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
873b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
874b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
875b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _outputDeviceIndex = index;
876b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _outputDeviceIsSpecified = true;
877b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
878b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
879b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
880b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
88164a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::SetPlayoutDevice(
882b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    AudioDeviceModule::WindowsDeviceType /*device*/)
883b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
884b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
885b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "WindowsDeviceType not supported");
886b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return -1;
887b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
888b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
88964a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::PlayoutDeviceName(
89064a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    uint16_t index,
891b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    char name[kAdmMaxDeviceNameSize],
892b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    char guid[kAdmMaxGuidSize])
893b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
894b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
89564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    const uint16_t nDevices(PlayoutDevices());
896b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
897b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if ((index > (nDevices-1)) || (name == NULL))
898b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
899b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
900b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
901b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
902b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    memset(name, 0, kAdmMaxDeviceNameSize);
903b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
904b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (guid != NULL)
905b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
906b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        memset(guid, 0, kAdmMaxGuidSize);
907b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
908b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
909b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return GetDevicesInfo(1, true, index, name, kAdmMaxDeviceNameSize);
910b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
911b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
91264a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::RecordingDeviceName(
91364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    uint16_t index,
914b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    char name[kAdmMaxDeviceNameSize],
915b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    char guid[kAdmMaxGuidSize])
916b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
917b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
91864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    const uint16_t nDevices(RecordingDevices());
919b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
920b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if ((index > (nDevices-1)) || (name == NULL))
921b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
922b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
923b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
924b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
925b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    memset(name, 0, kAdmMaxDeviceNameSize);
926b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
927b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (guid != NULL)
928b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
929b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        memset(guid, 0, kAdmMaxGuidSize);
930b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
9319e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org
932b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return GetDevicesInfo(1, false, index, name, kAdmMaxDeviceNameSize);
933b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
934b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
93564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint16_t AudioDeviceLinuxALSA::RecordingDevices()
936b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
937b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
93864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    return (int16_t)GetDevicesInfo(0, false);
939b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
940b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
94164a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::SetRecordingDevice(uint16_t index)
942b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
943b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
944b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_recIsInitialized)
945b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
946b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
947b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
948b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
94964a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    uint32_t nDevices = GetDevicesInfo(0, false);
950b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
951b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "  number of availiable audio input devices is %u", nDevices);
952b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
953b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (index > (nDevices-1))
954b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
955b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
956b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  device index is out of range [0,%u]", (nDevices-1));
957b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
958b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
959b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
960b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _inputDeviceIndex = index;
961b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _inputDeviceIsSpecified = true;
962b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
963b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
964b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
965b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
966b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// ----------------------------------------------------------------------------
967b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//  SetRecordingDevice II (II)
968b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// ----------------------------------------------------------------------------
969b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
97064a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::SetRecordingDevice(
971b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    AudioDeviceModule::WindowsDeviceType /*device*/)
972b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
973b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
974b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "WindowsDeviceType not supported");
975b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return -1;
976b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
977b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
97864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::PlayoutIsAvailable(bool& available)
979b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
9809e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org
981b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    available = false;
982b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
983b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Try to initialize the playout side with mono
984b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Assumes that user set num channels after calling this function
985b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playChannels = 1;
98664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    int32_t res = InitPlayout();
987b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
988b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Cancel effect of initialization
989b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    StopPlayout();
990b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
991b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (res != -1)
992b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
993b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        available = true;
994b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
995b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    else
996b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
997b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // It may be possible to play out in stereo
998b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        res = StereoPlayoutIsAvailable(available);
999b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (available)
1000b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
1001b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Then set channels to 2 so InitPlayout doesn't fail
1002b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _playChannels = 2;
1003b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
1004b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
10059e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org
1006b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return res;
1007b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1008b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
100964a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::RecordingIsAvailable(bool& available)
1010b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
10119e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org
1012b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    available = false;
1013b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1014b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Try to initialize the recording side with mono
1015b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Assumes that user set num channels after calling this function
1016b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _recChannels = 1;
101764a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    int32_t res = InitRecording();
1018b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1019b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Cancel effect of initialization
1020b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    StopRecording();
1021b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1022b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (res != -1)
1023b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1024b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        available = true;
1025b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1026b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    else
1027b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1028b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // It may be possible to record in stereo
1029b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        res = StereoRecordingIsAvailable(available);
1030b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (available)
1031b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
1032b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Then set channels to 2 so InitPlayout doesn't fail
1033b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _recChannels = 2;
1034b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
1035b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
10369e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org
1037b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return res;
1038b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1039b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
104064a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::InitPlayout()
1041b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
1042b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1043b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int errVal = 0;
1044b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1045b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped lock(&_critSect);
1046b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_playing)
1047b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1048b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
1049b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1050b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1051b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_outputDeviceIsSpecified)
1052b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1053b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
1054b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1055b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1056b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_playIsInitialized)
1057b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1058b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
1059b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1060b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Initialize the speaker (devices might have been added or removed)
1061b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (InitSpeaker() == -1)
1062b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1063b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
1064b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  InitSpeaker() failed");
1065b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1066b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1067b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Start by closing any existing wave-output devices
1068b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //
1069b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_handlePlayout != NULL)
1070b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1071b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        LATE(snd_pcm_close)(_handlePlayout);
1072b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _handlePlayout = NULL;
1073b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _playIsInitialized = false;
1074b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (errVal < 0)
1075b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
1076b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1077b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         "  Error closing current playout sound device, error:"
1078b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         " %s", LATE(snd_strerror)(errVal));
1079b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
1080b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1081b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1082b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Open PCM device for playout
1083b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    char deviceName[kAdmMaxDeviceNameSize] = {0};
1084b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    GetDevicesInfo(2, true, _outputDeviceIndex, deviceName,
1085b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                   kAdmMaxDeviceNameSize);
1086b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1087b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
1088b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "  InitPlayout open (%s)", deviceName);
1089b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1090b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    errVal = LATE(snd_pcm_open)
1091b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 (&_handlePlayout,
1092b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                  deviceName,
1093b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                  SND_PCM_STREAM_PLAYBACK,
1094b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                  SND_PCM_NONBLOCK);
1095b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1096b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (errVal == -EBUSY) // Device busy - try some more!
1097b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1098b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        for (int i=0; i < 5; i++)
1099b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
1100b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            SleepMs(1000);
1101b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            errVal = LATE(snd_pcm_open)
1102b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         (&_handlePlayout,
1103b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                          deviceName,
1104b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                          SND_PCM_STREAM_PLAYBACK,
1105b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                          SND_PCM_NONBLOCK);
1106b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (errVal == 0)
1107b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
1108b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                break;
1109b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
1110b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
1111b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1112b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (errVal < 0)
1113b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1114b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1115b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "     unable to open playback device: %s (%d)",
1116b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     LATE(snd_strerror)(errVal),
1117b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     errVal);
1118b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _handlePlayout = NULL;
1119b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
1120b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1121b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1122b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playoutFramesIn10MS = _playoutFreq/100;
1123b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if ((errVal = LATE(snd_pcm_set_params)( _handlePlayout,
1124d7e904161d5c59c61cbf094b16bca6e79ada713aandrew@webrtc.org#if defined(WEBRTC_ARCH_BIG_ENDIAN)
1125b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        SND_PCM_FORMAT_S16_BE,
1126b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#else
1127b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        SND_PCM_FORMAT_S16_LE, //format
1128b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#endif
1129b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        SND_PCM_ACCESS_RW_INTERLEAVED, //access
1130b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _playChannels, //channels
1131b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _playoutFreq, //rate
1132b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        1, //soft_resample
1133b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        ALSA_PLAYOUT_LATENCY //40*1000 //latency required overall latency in us
1134b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    )) < 0)
1135b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {   /* 0.5sec */
1136b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _playoutFramesIn10MS = 0;
1137b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1138b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "     unable to set playback device: %s (%d)",
1139b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     LATE(snd_strerror)(errVal),
1140b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     errVal);
1141b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        ErrorRecovery(errVal, _handlePlayout);
1142b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        errVal = LATE(snd_pcm_close)(_handlePlayout);
1143b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _handlePlayout = NULL;
1144b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
1145b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1146b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1147b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    errVal = LATE(snd_pcm_get_params)(_handlePlayout,
1148b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        &_playoutBufferSizeInFrame, &_playoutPeriodSizeInFrame);
1149b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (errVal < 0)
1150b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1151b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1152b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "    snd_pcm_get_params %s",
1153b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     LATE(snd_strerror)(errVal),
1154b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     errVal);
1155b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _playoutBufferSizeInFrame = 0;
1156b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _playoutPeriodSizeInFrame = 0;
1157b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1158b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    else {
1159b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
1160b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "    playout snd_pcm_get_params "
1161b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "buffer_size:%d period_size :%d",
1162b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     _playoutBufferSizeInFrame, _playoutPeriodSizeInFrame);
1163b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1164b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1165b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_ptrAudioBuffer)
1166b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1167b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Update webrtc audio buffer with the selected parameters
1168b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _ptrAudioBuffer->SetPlayoutSampleRate(_playoutFreq);
1169b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _ptrAudioBuffer->SetPlayoutChannels(_playChannels);
1170b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1171b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1172b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Set play buffer size
1173b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playoutBufferSizeIn10MS = LATE(snd_pcm_frames_to_bytes)(
1174b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _handlePlayout, _playoutFramesIn10MS);
1175b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1176b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Init varaibles used for play
1177b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playWarning = 0;
1178b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playError = 0;
1179b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1180b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_handlePlayout != NULL)
1181b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1182b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _playIsInitialized = true;
1183b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
1184b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1185b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    else
1186b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1187b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
1188b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1189b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1190b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
1191b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1192b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
119364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::InitRecording()
1194b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
1195b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1196b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int errVal = 0;
1197b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1198b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped lock(&_critSect);
1199b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1200b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_recording)
1201b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1202b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
1203b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1204b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1205b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_inputDeviceIsSpecified)
1206b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1207b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
1208b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1209b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1210b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_recIsInitialized)
1211b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1212b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
1213b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1214b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1215b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Initialize the microphone (devices might have been added or removed)
1216b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (InitMicrophone() == -1)
1217b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1218b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
1219b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                   "  InitMicrophone() failed");
1220b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1221b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1222b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Start by closing any existing pcm-input devices
1223b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //
1224b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_handleRecord != NULL)
1225b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1226b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        int errVal = LATE(snd_pcm_close)(_handleRecord);
1227b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _handleRecord = NULL;
1228b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _recIsInitialized = false;
1229b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (errVal < 0)
1230b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
1231b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1232b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         "     Error closing current recording sound device,"
1233b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         " error: %s",
1234b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         LATE(snd_strerror)(errVal));
1235b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
1236b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1237b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1238b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Open PCM device for recording
1239b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // The corresponding settings for playout are made after the record settings
1240b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    char deviceName[kAdmMaxDeviceNameSize] = {0};
1241b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    GetDevicesInfo(2, false, _inputDeviceIndex, deviceName,
1242b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                   kAdmMaxDeviceNameSize);
1243b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1244b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
1245b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "InitRecording open (%s)", deviceName);
1246b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    errVal = LATE(snd_pcm_open)
1247b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 (&_handleRecord,
1248b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                  deviceName,
1249b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                  SND_PCM_STREAM_CAPTURE,
1250b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                  SND_PCM_NONBLOCK);
1251b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1252b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Available modes: 0 = blocking, SND_PCM_NONBLOCK, SND_PCM_ASYNC
1253b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (errVal == -EBUSY) // Device busy - try some more!
1254b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1255b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        for (int i=0; i < 5; i++)
1256b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
1257b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            SleepMs(1000);
1258b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            errVal = LATE(snd_pcm_open)
1259b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         (&_handleRecord,
1260b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                          deviceName,
1261b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                          SND_PCM_STREAM_CAPTURE,
1262b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                          SND_PCM_NONBLOCK);
1263b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (errVal == 0)
1264b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
1265b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                break;
1266b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
1267b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
1268b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1269b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (errVal < 0)
1270b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1271b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1272b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "    unable to open record device: %s",
1273b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     LATE(snd_strerror)(errVal));
1274b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _handleRecord = NULL;
1275b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
1276b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1277b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1278b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _recordingFramesIn10MS = _recordingFreq/100;
1279b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if ((errVal = LATE(snd_pcm_set_params)(_handleRecord,
1280d7e904161d5c59c61cbf094b16bca6e79ada713aandrew@webrtc.org#if defined(WEBRTC_ARCH_BIG_ENDIAN)
1281b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        SND_PCM_FORMAT_S16_BE, //format
1282b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#else
1283b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        SND_PCM_FORMAT_S16_LE, //format
1284b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#endif
1285b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        SND_PCM_ACCESS_RW_INTERLEAVED, //access
1286b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _recChannels, //channels
1287b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _recordingFreq, //rate
1288b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        1, //soft_resample
1289b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        ALSA_CAPTURE_LATENCY //latency in us
1290b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    )) < 0)
1291b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1292b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org         // Fall back to another mode then.
1293b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org         if (_recChannels == 1)
1294b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org           _recChannels = 2;
1295b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org         else
1296b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org           _recChannels = 1;
1297b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1298b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org         if ((errVal = LATE(snd_pcm_set_params)(_handleRecord,
1299d7e904161d5c59c61cbf094b16bca6e79ada713aandrew@webrtc.org#if defined(WEBRTC_ARCH_BIG_ENDIAN)
1300b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org             SND_PCM_FORMAT_S16_BE, //format
1301b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#else
1302b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org             SND_PCM_FORMAT_S16_LE, //format
1303b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#endif
1304b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org             SND_PCM_ACCESS_RW_INTERLEAVED, //access
1305b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org             _recChannels, //channels
1306b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org             _recordingFreq, //rate
1307b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org             1, //soft_resample
1308b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org             ALSA_CAPTURE_LATENCY //latency in us
1309b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org         )) < 0)
1310b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org         {
1311b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org             _recordingFramesIn10MS = 0;
1312b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1313b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                          "    unable to set record settings: %s (%d)",
1314b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                          LATE(snd_strerror)(errVal), errVal);
1315b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org             ErrorRecovery(errVal, _handleRecord);
1316b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org             errVal = LATE(snd_pcm_close)(_handleRecord);
1317b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org             _handleRecord = NULL;
1318b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org             return -1;
1319b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org         }
1320b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1321b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1322b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    errVal = LATE(snd_pcm_get_params)(_handleRecord,
1323b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        &_recordingBuffersizeInFrame, &_recordingPeriodSizeInFrame);
1324b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (errVal < 0)
1325b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1326b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1327b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "    snd_pcm_get_params %s",
1328b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     LATE(snd_strerror)(errVal), errVal);
1329b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _recordingBuffersizeInFrame = 0;
1330b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _recordingPeriodSizeInFrame = 0;
1331b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1332b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    else {
1333b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
1334b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "    capture snd_pcm_get_params "
1335b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "buffer_size:%d period_size:%d",
1336b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     _recordingBuffersizeInFrame, _recordingPeriodSizeInFrame);
1337b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1338b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1339b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_ptrAudioBuffer)
1340b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1341b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Update webrtc audio buffer with the selected parameters
1342b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _ptrAudioBuffer->SetRecordingSampleRate(_recordingFreq);
1343b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _ptrAudioBuffer->SetRecordingChannels(_recChannels);
1344b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1345b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1346b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Set rec buffer size and create buffer
1347b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _recordingBufferSizeIn10MS = LATE(snd_pcm_frames_to_bytes)(
1348b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _handleRecord, _recordingFramesIn10MS);
1349b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1350b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_handleRecord != NULL)
1351b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1352b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Mark recording side as initialized
1353b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _recIsInitialized = true;
1354b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
1355b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1356b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    else
1357b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1358b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
1359b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1360b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1361b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
1362b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1363b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
136464a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::StartRecording()
1365b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
1366b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1367b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_recIsInitialized)
1368b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1369b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
1370b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1371b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1372b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_recording)
1373b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1374b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
1375b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1376b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1377b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _recording = true;
1378b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1379b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int errVal = 0;
1380b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _recordingFramesLeft = _recordingFramesIn10MS;
1381b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1382b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Make sure we only create the buffer once.
1383b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_recordingBuffer)
138464a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org        _recordingBuffer = new int8_t[_recordingBufferSizeIn10MS];
1385b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_recordingBuffer)
1386b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1387b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id,
1388b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "   failed to alloc recording buffer");
1389b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _recording = false;
1390b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
1391b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1392b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // RECORDING
1393b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    const char* threadName = "webrtc_audio_module_capture_thread";
1394b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _ptrThreadRec = ThreadWrapper::CreateThread(RecThreadFunc,
1395b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                this,
1396b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                kRealtimePriority,
1397b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                threadName);
1398b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_ptrThreadRec == NULL)
1399b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1400b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id,
1401b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  failed to create the rec audio thread");
1402b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _recording = false;
1403b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        delete [] _recordingBuffer;
1404b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _recordingBuffer = NULL;
1405b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
1406b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1407b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1408b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    unsigned int threadID(0);
1409b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_ptrThreadRec->Start(threadID))
1410b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1411b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id,
1412b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  failed to start the rec audio thread");
1413b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _recording = false;
1414b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        delete _ptrThreadRec;
1415b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _ptrThreadRec = NULL;
1416b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        delete [] _recordingBuffer;
1417b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _recordingBuffer = NULL;
1418b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
1419b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1420b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _recThreadID = threadID;
1421b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1422b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    errVal = LATE(snd_pcm_prepare)(_handleRecord);
1423b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (errVal < 0)
1424b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1425b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1426b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "     capture snd_pcm_prepare failed (%s)\n",
1427b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     LATE(snd_strerror)(errVal));
1428b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // just log error
1429b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // if snd_pcm_open fails will return -1
1430b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1431b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1432b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    errVal = LATE(snd_pcm_start)(_handleRecord);
1433b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (errVal < 0)
1434b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1435b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1436b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "     capture snd_pcm_start err: %s",
1437b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     LATE(snd_strerror)(errVal));
1438b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        errVal = LATE(snd_pcm_start)(_handleRecord);
1439b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (errVal < 0)
1440b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
1441b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1442b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         "     capture snd_pcm_start 2nd try err: %s",
1443b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         LATE(snd_strerror)(errVal));
1444b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            StopRecording();
1445b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return -1;
1446b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
1447b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1448b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1449b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
1450b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1451b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
145264a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::StopRecording()
1453b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
1454b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1455b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1456b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      CriticalSectionScoped lock(&_critSect);
1457b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1458b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      if (!_recIsInitialized)
1459b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      {
1460b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          return 0;
1461b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      }
1462b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1463b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      if (_handleRecord == NULL)
1464b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      {
1465b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          return -1;
1466b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      }
1467b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1468b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      // Make sure we don't start recording (it's asynchronous).
1469b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _recIsInitialized = false;
1470b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _recording = false;
1471b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1472b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1473b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_ptrThreadRec && !_ptrThreadRec->Stop())
1474b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1475b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1476b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "    failed to stop the rec audio thread");
1477b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
1478b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1479b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    else {
1480b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        delete _ptrThreadRec;
1481b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _ptrThreadRec = NULL;
1482b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1483b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1484b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped lock(&_critSect);
1485b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _recordingFramesLeft = 0;
1486b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_recordingBuffer)
1487b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1488b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        delete [] _recordingBuffer;
1489b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _recordingBuffer = NULL;
1490b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1491b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1492b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Stop and close pcm recording device.
1493b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int errVal = LATE(snd_pcm_drop)(_handleRecord);
1494b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (errVal < 0)
1495b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1496b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1497b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "     Error stop recording: %s",
1498b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     LATE(snd_strerror)(errVal));
1499b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
1500b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1501b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1502b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    errVal = LATE(snd_pcm_close)(_handleRecord);
1503b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (errVal < 0)
1504b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1505b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1506b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "     Error closing record sound device, error: %s",
1507b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     LATE(snd_strerror)(errVal));
1508b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
1509b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1510b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1511b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Check if we have muted and unmute if so.
1512b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    bool muteEnabled = false;
1513b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    MicrophoneMute(muteEnabled);
1514b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (muteEnabled)
1515b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1516b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        SetMicrophoneMute(false);
1517b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1518b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1519b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // set the pcm input handle to NULL
1520b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _handleRecord = NULL;
1521b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
1522b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1523b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1524b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceLinuxALSA::RecordingIsInitialized() const
1525b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
1526b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return (_recIsInitialized);
1527b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1528b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1529b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceLinuxALSA::Recording() const
1530b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
1531b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return (_recording);
1532b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1533b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1534b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceLinuxALSA::PlayoutIsInitialized() const
1535b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
1536b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return (_playIsInitialized);
1537b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1538b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
153964a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::StartPlayout()
1540b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
1541b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_playIsInitialized)
1542b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1543b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
1544b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1545b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1546b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_playing)
1547b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1548b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
1549b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1550b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1551b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playing = true;
1552b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1553b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playoutFramesLeft = 0;
1554b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_playoutBuffer)
155564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org        _playoutBuffer = new int8_t[_playoutBufferSizeIn10MS];
1556b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_playoutBuffer)
1557b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1558b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1559b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                   "    failed to alloc playout buf");
1560b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _playing = false;
1561b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      return -1;
1562b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1563b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1564b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // PLAYOUT
1565b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    const char* threadName = "webrtc_audio_module_play_thread";
1566b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _ptrThreadPlay =  ThreadWrapper::CreateThread(PlayThreadFunc,
1567b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                  this,
1568b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                  kRealtimePriority,
1569b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                  threadName);
1570b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_ptrThreadPlay == NULL)
1571b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1572b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id,
1573b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "    failed to create the play audio thread");
1574b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _playing = false;
1575b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        delete [] _playoutBuffer;
1576b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _playoutBuffer = NULL;
1577b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
1578b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1579b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1580b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    unsigned int threadID(0);
1581b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_ptrThreadPlay->Start(threadID))
1582b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1583b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id,
1584b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  failed to start the play audio thread");
1585b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _playing = false;
1586b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        delete _ptrThreadPlay;
1587b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _ptrThreadPlay = NULL;
1588b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        delete [] _playoutBuffer;
1589b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _playoutBuffer = NULL;
1590b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
1591b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1592b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playThreadID = threadID;
1593b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1594b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int errVal = LATE(snd_pcm_prepare)(_handlePlayout);
1595b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (errVal < 0)
1596b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1597b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id,
1598b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "     playout snd_pcm_prepare failed (%s)\n",
1599b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     LATE(snd_strerror)(errVal));
1600b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // just log error
1601b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // if snd_pcm_open fails will return -1
1602b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1603b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1604b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
1605b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1606b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
160764a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::StopPlayout()
1608b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
1609b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1610b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1611b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        CriticalSectionScoped lock(&_critSect);
1612b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1613b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (!_playIsInitialized)
1614b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
1615b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return 0;
1616b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
1617b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1618b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (_handlePlayout == NULL)
1619b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
1620b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return -1;
1621b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
1622b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1623b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _playing = false;
1624b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1625b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1626b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // stop playout thread first
1627b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_ptrThreadPlay && !_ptrThreadPlay->Stop())
1628b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1629b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1630b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  failed to stop the play audio thread");
1631b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
1632b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1633b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    else {
1634b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        delete _ptrThreadPlay;
1635b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _ptrThreadPlay = NULL;
1636b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1637b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1638b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped lock(&_critSect);
1639b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1640b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playoutFramesLeft = 0;
1641b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    delete [] _playoutBuffer;
1642b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playoutBuffer = NULL;
1643b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1644b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // stop and close pcm playout device
1645b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int errVal = LATE(snd_pcm_drop)(_handlePlayout);
1646b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (errVal < 0)
1647b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1648b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1649b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "    Error stop playing: %s",
1650b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     LATE(snd_strerror)(errVal));
1651b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1652b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1653b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    errVal = LATE(snd_pcm_close)(_handlePlayout);
1654b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org     if (errVal < 0)
1655b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1656b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                      "    Error closing playout sound device, error: %s",
1657b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                      LATE(snd_strerror)(errVal));
1658b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1659b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org     // set the pcm input handle to NULL
1660b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org     _playIsInitialized = false;
1661b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org     _handlePlayout = NULL;
1662b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
1663b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                  "  handle_playout is now set to NULL");
1664b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1665b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org     return 0;
1666b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1667b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
166864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::PlayoutDelay(uint16_t& delayMS) const
1669b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
167064a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    delayMS = (uint16_t)_playoutDelay * 1000 / _playoutFreq;
1671b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
1672b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1673b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
167464a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::RecordingDelay(uint16_t& delayMS) const
1675b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
1676b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Adding 10ms adjusted value to the record delay due to 10ms buffering.
167764a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    delayMS = (uint16_t)(10 + _recordingDelay * 1000 / _recordingFreq);
1678b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
1679b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1680b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1681b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceLinuxALSA::Playing() const
1682b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
1683b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return (_playing);
1684b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1685b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// ----------------------------------------------------------------------------
1686b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//  SetPlayoutBuffer
1687b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// ----------------------------------------------------------------------------
1688b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
168964a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::SetPlayoutBuffer(
1690b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    const AudioDeviceModule::BufferType type,
169164a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    uint16_t sizeMS)
1692b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
1693b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playBufType = type;
1694b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (type == AudioDeviceModule::kFixedBufferSize)
1695b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1696b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _playBufDelayFixed = sizeMS;
1697b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1698b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
1699b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1700b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
170164a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::PlayoutBuffer(
1702b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    AudioDeviceModule::BufferType& type,
170364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    uint16_t& sizeMS) const
1704b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
1705b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    type = _playBufType;
1706b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (type == AudioDeviceModule::kFixedBufferSize)
1707b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
17089e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org        sizeMS = _playBufDelayFixed;
1709b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1710b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    else
1711b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
17129e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org        sizeMS = _playBufDelay;
1713b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1714b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1715b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
1716b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1717b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
171864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::CPULoad(uint16_t& load) const
1719b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
1720b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1721b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
1722b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org               "  API call not supported on this platform");
1723b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return -1;
1724b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1725b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1726b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceLinuxALSA::PlayoutWarning() const
1727b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
17289e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org    CriticalSectionScoped lock(&_critSect);
1729b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return (_playWarning > 0);
1730b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1731b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1732b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceLinuxALSA::PlayoutError() const
1733b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
17349e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org    CriticalSectionScoped lock(&_critSect);
1735b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return (_playError > 0);
1736b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1737b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1738b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceLinuxALSA::RecordingWarning() const
1739b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
17409e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org    CriticalSectionScoped lock(&_critSect);
1741b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return (_recWarning > 0);
1742b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1743b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1744b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceLinuxALSA::RecordingError() const
1745b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
17469e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org    CriticalSectionScoped lock(&_critSect);
1747b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return (_recError > 0);
1748b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1749b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1750b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid AudioDeviceLinuxALSA::ClearPlayoutWarning()
1751b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
17529e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org    CriticalSectionScoped lock(&_critSect);
1753b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playWarning = 0;
1754b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1755b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1756b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid AudioDeviceLinuxALSA::ClearPlayoutError()
1757b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
17589e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org    CriticalSectionScoped lock(&_critSect);
1759b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _playError = 0;
1760b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1761b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1762b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid AudioDeviceLinuxALSA::ClearRecordingWarning()
1763b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
17649e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org    CriticalSectionScoped lock(&_critSect);
1765b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _recWarning = 0;
1766b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1767b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1768b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid AudioDeviceLinuxALSA::ClearRecordingError()
1769b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
17709e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org    CriticalSectionScoped lock(&_critSect);
1771b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _recError = 0;
1772b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1773b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1774b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// ============================================================================
1775b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//                                 Private Methods
1776b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// ============================================================================
1777b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
177864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::GetDevicesInfo(
177964a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    const int32_t function,
1780b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    const bool playback,
178164a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    const int32_t enumDeviceNo,
1782b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    char* enumDeviceName,
178364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    const int32_t ednLen) const
1784b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
17859e035d2ce2a35ae6db3ac47131821056cda31eaewu@webrtc.org
1786b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Device enumeration based on libjingle implementation
1787b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // by Tristan Schmelcher at Google Inc.
1788b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1789b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    const char *type = playback ? "Output" : "Input";
1790b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // dmix and dsnoop are only for playback and capture, respectively, but ALSA
1791b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // stupidly includes them in both lists.
1792b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    const char *ignorePrefix = playback ? "dsnoop:" : "dmix:" ;
1793b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // (ALSA lists many more "devices" of questionable interest, but we show them
1794b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // just in case the weird devices may actually be desirable for some
1795b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // users/systems.)
1796b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1797b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int err;
1798b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int enumCount(0);
1799b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    bool keepSearching(true);
1800b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1801b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // From Chromium issue 95797
1802b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Loop through the sound cards to get Alsa device hints.
1803b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Don't use snd_device_name_hint(-1,..) since there is a access violation
1804b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // inside this ALSA API with libasound.so.2.0.0.
1805b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int card = -1;
1806b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    while (!(LATE(snd_card_next)(&card)) && (card >= 0) && keepSearching) {
1807b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        void **hints;
1808b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        err = LATE(snd_device_name_hint)(card, "pcm", &hints);
1809b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (err != 0)
1810b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
1811b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1812b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         "GetDevicesInfo - device name hint error: %s",
1813b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         LATE(snd_strerror)(err));
1814b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return -1;
1815b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
1816b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1817b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        enumCount++; // default is 0
1818b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if ((function == FUNC_GET_DEVICE_NAME ||
1819b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            function == FUNC_GET_DEVICE_NAME_FOR_AN_ENUM) && enumDeviceNo == 0)
1820b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
1821b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            strcpy(enumDeviceName, "default");
1822b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1823b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            err = LATE(snd_device_name_free_hint)(hints);
1824b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (err != 0)
1825b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
1826b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1827b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                             "GetDevicesInfo - device name free hint error: %s",
1828b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                             LATE(snd_strerror)(err));
1829b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
1830b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1831b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return 0;
1832b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
1833b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1834b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        for (void **list = hints; *list != NULL; ++list)
1835b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
1836b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            char *actualType = LATE(snd_device_name_get_hint)(*list, "IOID");
1837b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (actualType)
1838b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {   // NULL means it's both.
1839b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                bool wrongType = (strcmp(actualType, type) != 0);
1840b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                free(actualType);
1841b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                if (wrongType)
1842b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                {
1843b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    // Wrong type of device (i.e., input vs. output).
1844b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    continue;
1845b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                }
1846b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
1847b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1848b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            char *name = LATE(snd_device_name_get_hint)(*list, "NAME");
1849b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (!name)
1850b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
1851b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1852b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                             "Device has no name");
1853b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                // Skip it.
1854b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                continue;
1855b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
1856b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1857b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Now check if we actually want to show this device.
1858b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (strcmp(name, "default") != 0 &&
1859b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                strcmp(name, "null") != 0 &&
1860b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                strcmp(name, "pulse") != 0 &&
1861b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                strncmp(name, ignorePrefix, strlen(ignorePrefix)) != 0)
1862b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
1863b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                // Yes, we do.
1864b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                char *desc = LATE(snd_device_name_get_hint)(*list, "DESC");
1865b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                if (!desc)
1866b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                {
1867b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    // Virtual devices don't necessarily have descriptions.
1868b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    // Use their names instead.
1869b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    desc = name;
1870b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                }
1871b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1872b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                if (FUNC_GET_NUM_OF_DEVICE == function)
1873b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                {
1874b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
1875b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                 "    Enum device %d - %s", enumCount, name);
1876b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1877b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                }
1878b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                if ((FUNC_GET_DEVICE_NAME == function) &&
1879b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    (enumDeviceNo == enumCount))
1880b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                {
1881b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    // We have found the enum device, copy the name to buffer.
1882b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    strncpy(enumDeviceName, desc, ednLen);
1883b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    enumDeviceName[ednLen-1] = '\0';
1884b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    keepSearching = false;
1885b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    // Replace '\n' with '-'.
1886b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    char * pret = strchr(enumDeviceName, '\n'/*0xa*/); //LF
1887b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    if (pret)
1888b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        *pret = '-';
1889b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                }
1890b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                if ((FUNC_GET_DEVICE_NAME_FOR_AN_ENUM == function) &&
1891b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    (enumDeviceNo == enumCount))
1892b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                {
1893b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    // We have found the enum device, copy the name to buffer.
1894b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    strncpy(enumDeviceName, name, ednLen);
1895b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    enumDeviceName[ednLen-1] = '\0';
1896b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    keepSearching = false;
1897b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                }
1898b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1899b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                if (keepSearching)
1900b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    ++enumCount;
1901b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1902b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                if (desc != name)
1903b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    free(desc);
1904b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
1905b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1906b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            free(name);
1907b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1908b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (!keepSearching)
1909b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                break;
1910b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
1911b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1912b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        err = LATE(snd_device_name_free_hint)(hints);
1913b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (err != 0)
1914b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
1915b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1916b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         "GetDevicesInfo - device name free hint error: %s",
1917b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         LATE(snd_strerror)(err));
1918b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Continue and return true anyway, since we did get the whole list.
1919b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
1920b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1921b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1922b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (FUNC_GET_NUM_OF_DEVICE == function)
1923b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1924b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (enumCount == 1) // only default?
1925b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            enumCount = 0;
1926b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return enumCount; // Normal return point for function 0
1927b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1928b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1929b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (keepSearching)
1930b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1931b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // If we get here for function 1 and 2, we didn't find the specified
1932b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // enum device.
1933b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1934b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "GetDevicesInfo - Could not find device name or numbers");
1935b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
1936b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1937b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1938b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
1939b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1940b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
194164a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::InputSanityCheckAfterUnlockedPeriod() const
1942b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
1943b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_handleRecord == NULL)
1944b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1945b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1946b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  input state has been modified during unlocked period");
1947b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
1948b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1949b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
1950b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1951b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
195264a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::OutputSanityCheckAfterUnlockedPeriod() const
1953b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
1954b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_handlePlayout == NULL)
1955b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1956b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1957b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  output state has been modified during unlocked period");
1958b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
1959b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1960b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
1961b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1962b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
196364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceLinuxALSA::ErrorRecovery(int32_t error,
196464a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org                                            snd_pcm_t* deviceHandle)
1965b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
1966b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int st = LATE(snd_pcm_state)(deviceHandle);
1967b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
1968b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org               "Trying to recover from error: %s (%d) (state %d)",
1969b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org               (LATE(snd_pcm_stream)(deviceHandle) == SND_PCM_STREAM_CAPTURE) ?
1970b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                   "capture" : "playout", LATE(snd_strerror)(error), error, st);
1971b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1972b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // It is recommended to use snd_pcm_recover for all errors. If that function
1973b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // cannot handle the error, the input error code will be returned, otherwise
1974b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // 0 is returned. From snd_pcm_recover API doc: "This functions handles
1975b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // -EINTR (4) (interrupted system call), -EPIPE (32) (playout overrun or
1976b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // capture underrun) and -ESTRPIPE (86) (stream is suspended) error codes
1977b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // trying to prepare given stream for next I/O."
1978b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1979b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    /** Open */
1980b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //    SND_PCM_STATE_OPEN = 0,
1981b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    /** Setup installed */
1982b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //    SND_PCM_STATE_SETUP,
1983b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    /** Ready to start */
1984b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //    SND_PCM_STATE_PREPARED,
1985b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    /** Running */
1986b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //    SND_PCM_STATE_RUNNING,
1987b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    /** Stopped: underrun (playback) or overrun (capture) detected */
1988b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //    SND_PCM_STATE_XRUN,= 4
1989b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    /** Draining: running (playback) or stopped (capture) */
1990b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //    SND_PCM_STATE_DRAINING,
1991b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    /** Paused */
1992b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //    SND_PCM_STATE_PAUSED,
1993b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    /** Hardware is suspended */
1994b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //    SND_PCM_STATE_SUSPENDED,
1995b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //  ** Hardware is disconnected */
1996b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //    SND_PCM_STATE_DISCONNECTED,
1997b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //    SND_PCM_STATE_LAST = SND_PCM_STATE_DISCONNECTED
1998b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1999b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // snd_pcm_recover isn't available in older alsa, e.g. on the FC4 machine
2000b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // in Sthlm lab.
2001b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2002b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int res = LATE(snd_pcm_recover)(deviceHandle, error, 1);
2003b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (0 == res)
2004b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
2005b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
2006b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                   "    Recovery - snd_pcm_recover OK");
2007b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2008b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if ((error == -EPIPE || error == -ESTRPIPE) && // Buf underrun/overrun.
2009b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _recording &&
2010b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            LATE(snd_pcm_stream)(deviceHandle) == SND_PCM_STREAM_CAPTURE)
2011b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
2012b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // For capture streams we also have to repeat the explicit start()
2013b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // to get data flowing again.
2014b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            int err = LATE(snd_pcm_start)(deviceHandle);
2015b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (err != 0)
2016b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
2017b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
2018b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                             "  Recovery - snd_pcm_start error: %u", err);
2019b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                return -1;
2020b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
2021b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
2022b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2023b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if ((error == -EPIPE || error == -ESTRPIPE) &&  // Buf underrun/overrun.
2024b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _playing &&
2025b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            LATE(snd_pcm_stream)(deviceHandle) == SND_PCM_STREAM_PLAYBACK)
2026b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
2027b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // For capture streams we also have to repeat the explicit start() to get
2028b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // data flowing again.
2029b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            int err = LATE(snd_pcm_start)(deviceHandle);
2030b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (err != 0)
2031b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
2032b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org              WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
2033b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                       "    Recovery - snd_pcm_start error: %s",
2034b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                       LATE(snd_strerror)(err));
2035b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org              return -1;
2036b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
2037b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
2038b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2039b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -EPIPE == error ? 1 : 0;
2040b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
2041b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    else {
2042b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
2043b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  Unrecoverable alsa stream error: %d", res);
2044b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
2045b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2046b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return res;
2047b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
2048b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2049b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// ============================================================================
2050b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//                                  Thread Methods
2051b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// ============================================================================
2052b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2053b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceLinuxALSA::PlayThreadFunc(void* pThis)
2054b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
2055b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return (static_cast<AudioDeviceLinuxALSA*>(pThis)->PlayThreadProcess());
2056b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
2057b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2058b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceLinuxALSA::RecThreadFunc(void* pThis)
2059b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
2060b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return (static_cast<AudioDeviceLinuxALSA*>(pThis)->RecThreadProcess());
2061b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
2062b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2063b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceLinuxALSA::PlayThreadProcess()
2064b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
2065b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if(!_playing)
2066b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return false;
2067b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2068b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int err;
2069b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    snd_pcm_sframes_t frames;
2070b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    snd_pcm_sframes_t avail_frames;
2071b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2072b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    Lock();
2073b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //return a positive number of frames ready otherwise a negative error code
2074b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    avail_frames = LATE(snd_pcm_avail_update)(_handlePlayout);
2075b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (avail_frames < 0)
2076b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
2077b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
2078b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                   "playout snd_pcm_avail_update error: %s",
2079b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                   LATE(snd_strerror)(avail_frames));
2080b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        ErrorRecovery(avail_frames, _handlePlayout);
2081b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        UnLock();
2082b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return true;
2083b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
2084b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    else if (avail_frames == 0)
2085b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
2086b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        UnLock();
2087b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2088b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        //maximum tixe in milliseconds to wait, a negative value means infinity
2089b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        err = LATE(snd_pcm_wait)(_handlePlayout, 2);
2090b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (err == 0)
2091b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        { //timeout occured
2092b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceStream, kTraceAudioDevice, _id,
2093b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         "playout snd_pcm_wait timeout");
2094b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
2095b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2096b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return true;
2097b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
2098b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2099b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_playoutFramesLeft <= 0)
2100b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
2101b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        UnLock();
2102b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _ptrAudioBuffer->RequestPlayoutData(_playoutFramesIn10MS);
2103b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        Lock();
2104b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2105b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _playoutFramesLeft = _ptrAudioBuffer->GetPlayoutData(_playoutBuffer);
2106b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        assert(_playoutFramesLeft == _playoutFramesIn10MS);
2107b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
2108b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
210964a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    if (static_cast<uint32_t>(avail_frames) > _playoutFramesLeft)
2110b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        avail_frames = _playoutFramesLeft;
2111b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2112b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int size = LATE(snd_pcm_frames_to_bytes)(_handlePlayout,
2113b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _playoutFramesLeft);
2114b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    frames = LATE(snd_pcm_writei)(
2115b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _handlePlayout,
2116b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        &_playoutBuffer[_playoutBufferSizeIn10MS - size],
2117b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        avail_frames);
2118b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2119b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (frames < 0)
2120b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
2121b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceStream, kTraceAudioDevice, _id,
2122b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "playout snd_pcm_writei error: %s",
2123b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     LATE(snd_strerror)(frames));
2124b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _playoutFramesLeft = 0;
2125b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        ErrorRecovery(frames, _handlePlayout);
2126b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        UnLock();
2127b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return true;
2128b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
2129b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    else {
2130b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        assert(frames==avail_frames);
2131b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _playoutFramesLeft -= frames;
2132b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
2133b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2134b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    UnLock();
2135b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return true;
2136b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
2137b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2138b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceLinuxALSA::RecThreadProcess()
2139b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
2140b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_recording)
2141b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return false;
2142b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2143b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int err;
2144b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    snd_pcm_sframes_t frames;
2145b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    snd_pcm_sframes_t avail_frames;
214664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    int8_t buffer[_recordingBufferSizeIn10MS];
2147b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2148b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    Lock();
2149b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2150b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //return a positive number of frames ready otherwise a negative error code
2151b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    avail_frames = LATE(snd_pcm_avail_update)(_handleRecord);
2152b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (avail_frames < 0)
2153b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
2154b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
2155b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "capture snd_pcm_avail_update error: %s",
2156b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     LATE(snd_strerror)(avail_frames));
2157b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        ErrorRecovery(avail_frames, _handleRecord);
2158b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        UnLock();
2159b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return true;
2160b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
2161b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    else if (avail_frames == 0)
2162b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    { // no frame is available now
2163b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        UnLock();
2164b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2165b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        //maximum time in milliseconds to wait, a negative value means infinity
2166b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        err = LATE(snd_pcm_wait)(_handleRecord,
2167b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            ALSA_CAPTURE_WAIT_TIMEOUT);
2168b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (err == 0) //timeout occured
2169b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceStream, kTraceAudioDevice, _id,
2170b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         "capture snd_pcm_wait timeout");
2171b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2172b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return true;
2173b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
2174b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
217564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org    if (static_cast<uint32_t>(avail_frames) > _recordingFramesLeft)
2176b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        avail_frames = _recordingFramesLeft;
2177b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2178b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    frames = LATE(snd_pcm_readi)(_handleRecord,
2179b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        buffer, avail_frames); // frames to be written
2180b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (frames < 0)
2181b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
2182b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
2183b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "capture snd_pcm_readi error: %s",
2184b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     LATE(snd_strerror)(frames));
2185b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        ErrorRecovery(frames, _handleRecord);
2186b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        UnLock();
2187b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return true;
2188b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
2189b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    else if (frames > 0)
2190b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
2191b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        assert(frames == avail_frames);
2192b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2193b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        int left_size = LATE(snd_pcm_frames_to_bytes)(_handleRecord,
2194b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _recordingFramesLeft);
2195b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        int size = LATE(snd_pcm_frames_to_bytes)(_handleRecord, frames);
2196b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2197b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        memcpy(&_recordingBuffer[_recordingBufferSizeIn10MS - left_size],
2198b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org               buffer, size);
2199b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _recordingFramesLeft -= frames;
2200b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2201b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (!_recordingFramesLeft)
2202b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        { // buf is full
2203b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _recordingFramesLeft = _recordingFramesIn10MS;
2204b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2205b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // store the recorded buffer (no action will be taken if the
2206b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // #recorded samples is not a full buffer)
2207b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _ptrAudioBuffer->SetRecordedBuffer(_recordingBuffer,
2208b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                               _recordingFramesIn10MS);
2209b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
221064a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org            uint32_t currentMicLevel = 0;
221164a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org            uint32_t newMicLevel = 0;
2212b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2213b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (AGC())
2214b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
2215b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                // store current mic level in the audio buffer if AGC is enabled
2216b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                if (MicrophoneVolume(currentMicLevel) == 0)
2217b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                {
2218b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    if (currentMicLevel == 0xffffffff)
2219b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        currentMicLevel = 100;
2220b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    // this call does not affect the actual microphone volume
2221b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    _ptrAudioBuffer->SetCurrentMicLevel(currentMicLevel);
2222b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                }
2223b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
2224b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2225b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // calculate delay
2226b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _playoutDelay = 0;
2227b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _recordingDelay = 0;
2228b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (_handlePlayout)
2229b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
2230b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                err = LATE(snd_pcm_delay)(_handlePlayout,
2231b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    &_playoutDelay); // returned delay in frames
2232b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                if (err < 0)
2233b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                {
2234b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    // TODO(xians): Shall we call ErrorRecovery() here?
2235b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    _playoutDelay = 0;
2236b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
2237b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                 "playout snd_pcm_delay: %s",
2238b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                 LATE(snd_strerror)(err));
2239b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                }
2240b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
2241b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2242b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            err = LATE(snd_pcm_delay)(_handleRecord,
2243b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                &_recordingDelay); // returned delay in frames
2244b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (err < 0)
2245b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
2246b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                // TODO(xians): Shall we call ErrorRecovery() here?
2247b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                _recordingDelay = 0;
2248b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
2249b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                             "capture snd_pcm_delay: %s",
2250b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                             LATE(snd_strerror)(err));
2251b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
2252b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2253b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org           // TODO(xians): Shall we add 10ms buffer delay to the record delay?
2254b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _ptrAudioBuffer->SetVQEData(
2255b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                _playoutDelay * 1000 / _playoutFreq,
2256b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                _recordingDelay * 1000 / _recordingFreq, 0);
2257b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
225832b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org            _ptrAudioBuffer->SetTypingStatus(KeyPressed());
225932b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org
2260b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Deliver recorded samples at specified sample rate, mic level etc.
2261b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // to the observer using callback.
2262b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            UnLock();
2263b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _ptrAudioBuffer->DeliverRecordedData();
2264b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            Lock();
2265b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2266b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (AGC())
2267b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
2268b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                newMicLevel = _ptrAudioBuffer->NewMicLevel();
2269b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                if (newMicLevel != 0)
2270b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                {
2271b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    // The VQE will only deliver non-zero microphone levels when a
2272b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    // change is needed. Set this new mic level (received from the
2273b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    // observer as return value in the callback).
2274b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    if (SetMicrophoneVolume(newMicLevel) == -1)
2275b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
2276b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                     "  the required modification of the "
2277b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                     "microphone volume failed");
2278b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                }
2279b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
2280b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
2281b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
2282b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2283b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    UnLock();
2284b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return true;
2285b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
2286b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
228732b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org
228832b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.orgbool AudioDeviceLinuxALSA::KeyPressed() const{
228946b817d939765bef587c575720c18764e3b03fd4fbarchard@google.com#if defined(USE_X11)
229032b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org  char szKey[32];
229132b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org  unsigned int i = 0;
229232b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org  char state = 0;
229332b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org
229432b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org  if (!_XDisplay)
229532b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org    return false;
229632b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org
229732b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org  // Check key map status
229832b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org  XQueryKeymap(_XDisplay, szKey);
229932b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org
230032b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org  // A bit change in keymap means a key is pressed
230132b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org  for (i = 0; i < sizeof(szKey); i++)
230232b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org    state |= (szKey[i] ^ _oldKeyState[i]) & szKey[i];
230332b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org
230432b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org  // Save old state
230532b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org  memcpy((char*)_oldKeyState, (char*)szKey, sizeof(_oldKeyState));
230632b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org  return (state != 0);
230746b817d939765bef587c575720c18764e3b03fd4fbarchard@google.com#else
230846b817d939765bef587c575720c18764e3b03fd4fbarchard@google.com  return false;
230946b817d939765bef587c575720c18764e3b03fd4fbarchard@google.com#endif
231032b4e2f2d38cb8fe7ca95ea0ab65ba4769ffa230niklas.enbom@webrtc.org}
2311b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}  // namespace webrtc
2312