blob: 0cf89ef011b42ee5e1c9f3b342a33a05e5652b58 [file] [log] [blame]
xians@google.com68efa212011-08-11 12:41:561/*
leozwang@webrtc.org28f39132012-03-01 18:01:482 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
xians@google.com68efa212011-08-11 12:41:563 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 04:47:3111#ifndef AUDIO_DEVICE_AUDIO_DEVICE_PULSE_LINUX_H_
12#define AUDIO_DEVICE_AUDIO_DEVICE_PULSE_LINUX_H_
xians@google.com68efa212011-08-11 12:41:5613
kwibergf01633e2016-02-24 13:00:3614#include <memory>
15
Artem Titovd15a5752021-02-10 13:31:2416#include "api/sequence_checker.h"
Yves Gerey988cc082018-10-23 10:03:0117#include "modules/audio_device/audio_device_buffer.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3118#include "modules/audio_device/audio_device_generic.h"
Yves Gerey988cc082018-10-23 10:03:0119#include "modules/audio_device/include/audio_device.h"
20#include "modules/audio_device/include/audio_device_defines.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3121#include "modules/audio_device/linux/audio_mixer_manager_pulse_linux.h"
Yves Gerey988cc082018-10-23 10:03:0122#include "modules/audio_device/linux/pulseaudiosymboltable_linux.h"
Niels Möller2c16cc62018-10-29 08:47:5123#include "rtc_base/event.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3124#include "rtc_base/platform_thread.h"
Markus Handell5f612822020-07-08 08:13:2025#include "rtc_base/synchronization/mutex.h"
Yves Gerey988cc082018-10-23 10:03:0126#include "rtc_base/thread_annotations.h"
xians@google.com68efa212011-08-11 12:41:5627
Yves Gereyee562d82018-08-08 14:39:4428#if defined(WEBRTC_USE_X11)
niklas.enbom@webrtc.orge2a80062013-05-14 21:33:1129#include <X11/Xlib.h>
Yves Gereyee562d82018-08-08 14:39:4430#endif
31
pbos@webrtc.org811269d2013-07-11 13:24:3832#include <pulse/pulseaudio.h>
Yves Gerey988cc082018-10-23 10:03:0133#include <stddef.h>
34#include <stdint.h>
xians@google.com68efa212011-08-11 12:41:5635
xians@google.com68efa212011-08-11 12:41:5636// We define this flag if it's missing from our headers, because we want to be
37// able to compile against old headers but still use PA_STREAM_ADJUST_LATENCY
38// if run against a recent version of the library.
39#ifndef PA_STREAM_ADJUST_LATENCY
40#define PA_STREAM_ADJUST_LATENCY 0x2000U
41#endif
42#ifndef PA_STREAM_START_MUTED
43#define PA_STREAM_START_MUTED 0x1000U
44#endif
45
46// Set this constant to 0 to disable latency reading
pbos@webrtc.org25509882013-04-09 10:30:3547const uint32_t WEBRTC_PA_REPORT_LATENCY = 1;
xians@google.com68efa212011-08-11 12:41:5648
49// Constants from implementation by Tristan Schmelcher [tschmelcher@google.com]
50
51// First PulseAudio protocol version that supports PA_STREAM_ADJUST_LATENCY.
pbos@webrtc.org25509882013-04-09 10:30:3552const uint32_t WEBRTC_PA_ADJUST_LATENCY_PROTOCOL_VERSION = 13;
xians@google.com68efa212011-08-11 12:41:5653
54// Some timing constants for optimal operation. See
55// https://tango.0pointer.de/pipermail/pulseaudio-discuss/2008-January/001170.html
56// for a good explanation of some of the factors that go into this.
57
58// Playback.
59
60// For playback, there is a round-trip delay to fill the server-side playback
61// buffer, so setting too low of a latency is a buffer underflow risk. We will
62// automatically increase the latency if a buffer underflow does occur, but we
63// also enforce a sane minimum at start-up time. Anything lower would be
64// virtually guaranteed to underflow at least once, so there's no point in
65// allowing lower latencies.
pbos@webrtc.org25509882013-04-09 10:30:3566const uint32_t WEBRTC_PA_PLAYBACK_LATENCY_MINIMUM_MSECS = 20;
xians@google.com68efa212011-08-11 12:41:5667
68// Every time a playback stream underflows, we will reconfigure it with target
69// latency that is greater by this amount.
pbos@webrtc.org25509882013-04-09 10:30:3570const uint32_t WEBRTC_PA_PLAYBACK_LATENCY_INCREMENT_MSECS = 20;
xians@google.com68efa212011-08-11 12:41:5671
72// We also need to configure a suitable request size. Too small and we'd burn
73// CPU from the overhead of transfering small amounts of data at once. Too large
74// and the amount of data remaining in the buffer right before refilling it
75// would be a buffer underflow risk. We set it to half of the buffer size.
pbos@webrtc.org25509882013-04-09 10:30:3576const uint32_t WEBRTC_PA_PLAYBACK_REQUEST_FACTOR = 2;
xians@google.com68efa212011-08-11 12:41:5677
78// Capture.
79
80// For capture, low latency is not a buffer overflow risk, but it makes us burn
81// CPU from the overhead of transfering small amounts of data at once, so we set
82// a recommended value that we use for the kLowLatency constant (but if the user
83// explicitly requests something lower then we will honour it).
84// 1ms takes about 6-7% CPU. 5ms takes about 5%. 10ms takes about 4.x%.
pbos@webrtc.org25509882013-04-09 10:30:3585const uint32_t WEBRTC_PA_LOW_CAPTURE_LATENCY_MSECS = 10;
xians@google.com68efa212011-08-11 12:41:5686
87// There is a round-trip delay to ack the data to the server, so the
88// server-side buffer needs extra space to prevent buffer overflow. 20ms is
89// sufficient, but there is no penalty to making it bigger, so we make it huge.
90// (750ms is libpulse's default value for the _total_ buffer size in the
91// kNoLatencyRequirements case.)
pbos@webrtc.org25509882013-04-09 10:30:3592const uint32_t WEBRTC_PA_CAPTURE_BUFFER_EXTRA_MSECS = 750;
xians@google.com68efa212011-08-11 12:41:5693
pbos@webrtc.org25509882013-04-09 10:30:3594const uint32_t WEBRTC_PA_MSECS_PER_SEC = 1000;
xians@google.com68efa212011-08-11 12:41:5695
96// Init _configuredLatencyRec/Play to this value to disable latency requirements
pbos@webrtc.org25509882013-04-09 10:30:3597const int32_t WEBRTC_PA_NO_LATENCY_REQUIREMENTS = -1;
xians@google.com68efa212011-08-11 12:41:5698
Yves Gerey665174f2018-06-19 13:03:0599// Set this const to 1 to account for peeked and used data in latency
100// calculation
pbos@webrtc.org25509882013-04-09 10:30:35101const uint32_t WEBRTC_PA_CAPTURE_BUFFER_LATENCY_ADJUSTMENT = 0;
xians@google.com68efa212011-08-11 12:41:56102
Mirko Bonadeie0c01b92018-09-14 07:52:46103typedef webrtc::adm_linux_pulse::PulseAudioSymbolTable WebRTCPulseSymbolTable;
104WebRTCPulseSymbolTable* GetPulseSymbolTable();
105
Yves Gerey665174f2018-06-19 13:03:05106namespace webrtc {
xians@google.com68efa212011-08-11 12:41:56107
Yves Gerey665174f2018-06-19 13:03:05108class AudioDeviceLinuxPulse : public AudioDeviceGeneric {
109 public:
110 AudioDeviceLinuxPulse();
111 virtual ~AudioDeviceLinuxPulse();
xians@google.com68efa212011-08-11 12:41:56112
Yves Gerey665174f2018-06-19 13:03:05113 // Retrieve the currently utilized audio layer
114 int32_t ActiveAudioLayer(
115 AudioDeviceModule::AudioLayer& audioLayer) const override;
xians@google.com68efa212011-08-11 12:41:56116
Yves Gerey665174f2018-06-19 13:03:05117 // Main initializaton and termination
118 InitStatus Init() override;
Markus Handell957318c2020-08-20 09:38:21119 int32_t Terminate() RTC_LOCKS_EXCLUDED(mutex_) override;
Yves Gerey665174f2018-06-19 13:03:05120 bool Initialized() const override;
xians@google.com68efa212011-08-11 12:41:56121
Yves Gerey665174f2018-06-19 13:03:05122 // Device enumeration
123 int16_t PlayoutDevices() override;
124 int16_t RecordingDevices() override;
125 int32_t PlayoutDeviceName(uint16_t index,
126 char name[kAdmMaxDeviceNameSize],
127 char guid[kAdmMaxGuidSize]) override;
128 int32_t RecordingDeviceName(uint16_t index,
kjellander@webrtc.org14665ff2015-03-04 12:58:35129 char name[kAdmMaxDeviceNameSize],
130 char guid[kAdmMaxGuidSize]) override;
xians@google.com68efa212011-08-11 12:41:56131
Yves Gerey665174f2018-06-19 13:03:05132 // Device selection
133 int32_t SetPlayoutDevice(uint16_t index) override;
134 int32_t SetPlayoutDevice(
135 AudioDeviceModule::WindowsDeviceType device) override;
136 int32_t SetRecordingDevice(uint16_t index) override;
137 int32_t SetRecordingDevice(
138 AudioDeviceModule::WindowsDeviceType device) override;
xians@google.com68efa212011-08-11 12:41:56139
Yves Gerey665174f2018-06-19 13:03:05140 // Audio transport initialization
141 int32_t PlayoutIsAvailable(bool& available) override;
Markus Handell957318c2020-08-20 09:38:21142 int32_t InitPlayout() RTC_LOCKS_EXCLUDED(mutex_) override;
Yves Gerey665174f2018-06-19 13:03:05143 bool PlayoutIsInitialized() const override;
144 int32_t RecordingIsAvailable(bool& available) override;
145 int32_t InitRecording() override;
146 bool RecordingIsInitialized() const override;
xians@google.com68efa212011-08-11 12:41:56147
Yves Gerey665174f2018-06-19 13:03:05148 // Audio transport control
Markus Handell957318c2020-08-20 09:38:21149 int32_t StartPlayout() RTC_LOCKS_EXCLUDED(mutex_) override;
150 int32_t StopPlayout() RTC_LOCKS_EXCLUDED(mutex_) override;
Yves Gerey665174f2018-06-19 13:03:05151 bool Playing() const override;
Markus Handell957318c2020-08-20 09:38:21152 int32_t StartRecording() RTC_LOCKS_EXCLUDED(mutex_) override;
153 int32_t StopRecording() RTC_LOCKS_EXCLUDED(mutex_) override;
Yves Gerey665174f2018-06-19 13:03:05154 bool Recording() const override;
xians@google.com68efa212011-08-11 12:41:56155
Yves Gerey665174f2018-06-19 13:03:05156 // Audio mixer initialization
157 int32_t InitSpeaker() override;
158 bool SpeakerIsInitialized() const override;
159 int32_t InitMicrophone() override;
160 bool MicrophoneIsInitialized() const override;
xians@google.com68efa212011-08-11 12:41:56161
Yves Gerey665174f2018-06-19 13:03:05162 // Speaker volume controls
163 int32_t SpeakerVolumeIsAvailable(bool& available) override;
164 int32_t SetSpeakerVolume(uint32_t volume) override;
165 int32_t SpeakerVolume(uint32_t& volume) const override;
166 int32_t MaxSpeakerVolume(uint32_t& maxVolume) const override;
167 int32_t MinSpeakerVolume(uint32_t& minVolume) const override;
xians@google.com68efa212011-08-11 12:41:56168
Yves Gerey665174f2018-06-19 13:03:05169 // Microphone volume controls
170 int32_t MicrophoneVolumeIsAvailable(bool& available) override;
171 int32_t SetMicrophoneVolume(uint32_t volume) override;
172 int32_t MicrophoneVolume(uint32_t& volume) const override;
173 int32_t MaxMicrophoneVolume(uint32_t& maxVolume) const override;
174 int32_t MinMicrophoneVolume(uint32_t& minVolume) const override;
xians@google.com68efa212011-08-11 12:41:56175
Yves Gerey665174f2018-06-19 13:03:05176 // Speaker mute control
177 int32_t SpeakerMuteIsAvailable(bool& available) override;
178 int32_t SetSpeakerMute(bool enable) override;
179 int32_t SpeakerMute(bool& enabled) const override;
xians@google.com68efa212011-08-11 12:41:56180
Yves Gerey665174f2018-06-19 13:03:05181 // Microphone mute control
182 int32_t MicrophoneMuteIsAvailable(bool& available) override;
183 int32_t SetMicrophoneMute(bool enable) override;
184 int32_t MicrophoneMute(bool& enabled) const override;
xians@google.com68efa212011-08-11 12:41:56185
Yves Gerey665174f2018-06-19 13:03:05186 // Stereo support
187 int32_t StereoPlayoutIsAvailable(bool& available) override;
188 int32_t SetStereoPlayout(bool enable) override;
189 int32_t StereoPlayout(bool& enabled) const override;
190 int32_t StereoRecordingIsAvailable(bool& available) override;
191 int32_t SetStereoRecording(bool enable) override;
192 int32_t StereoRecording(bool& enabled) const override;
xians@google.com68efa212011-08-11 12:41:56193
Yves Gerey665174f2018-06-19 13:03:05194 // Delay information and control
Markus Handell957318c2020-08-20 09:38:21195 int32_t PlayoutDelay(uint16_t& delayMS) const
196 RTC_LOCKS_EXCLUDED(mutex_) override;
xians@google.com68efa212011-08-11 12:41:56197
Yves Gerey665174f2018-06-19 13:03:05198 void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) override;
xians@google.com68efa212011-08-11 12:41:56199
Yves Gerey665174f2018-06-19 13:03:05200 private:
Markus Handell5f612822020-07-08 08:13:20201 void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION(mutex_) { mutex_.Lock(); }
202 void UnLock() RTC_UNLOCK_FUNCTION(mutex_) { mutex_.Unlock(); }
Yves Gerey665174f2018-06-19 13:03:05203 void WaitForOperationCompletion(pa_operation* paOperation) const;
204 void WaitForSuccess(pa_operation* paOperation) const;
xians@google.com68efa212011-08-11 12:41:56205
Yves Gerey665174f2018-06-19 13:03:05206 bool KeyPressed() const;
niklas.enbom@webrtc.orge2a80062013-05-14 21:33:11207
Yves Gerey665174f2018-06-19 13:03:05208 static void PaContextStateCallback(pa_context* c, void* pThis);
209 static void PaSinkInfoCallback(pa_context* c,
210 const pa_sink_info* i,
211 int eol,
212 void* pThis);
213 static void PaSourceInfoCallback(pa_context* c,
214 const pa_source_info* i,
215 int eol,
danilchap56359be2017-09-07 14:53:45216 void* pThis);
Yves Gerey665174f2018-06-19 13:03:05217 static void PaServerInfoCallback(pa_context* c,
218 const pa_server_info* i,
219 void* pThis);
220 static void PaStreamStateCallback(pa_stream* p, void* pThis);
221 void PaContextStateCallbackHandler(pa_context* c);
222 void PaSinkInfoCallbackHandler(const pa_sink_info* i, int eol);
223 void PaSourceInfoCallbackHandler(const pa_source_info* i, int eol);
224 void PaServerInfoCallbackHandler(const pa_server_info* i);
225 void PaStreamStateCallbackHandler(pa_stream* p);
xians@google.com68efa212011-08-11 12:41:56226
Yves Gerey665174f2018-06-19 13:03:05227 void EnableWriteCallback();
228 void DisableWriteCallback();
229 static void PaStreamWriteCallback(pa_stream* unused,
230 size_t buffer_space,
231 void* pThis);
232 void PaStreamWriteCallbackHandler(size_t buffer_space);
233 static void PaStreamUnderflowCallback(pa_stream* unused, void* pThis);
234 void PaStreamUnderflowCallbackHandler();
235 void EnableReadCallback();
236 void DisableReadCallback();
237 static void PaStreamReadCallback(pa_stream* unused1,
238 size_t unused2,
239 void* pThis);
240 void PaStreamReadCallbackHandler();
241 static void PaStreamOverflowCallback(pa_stream* unused, void* pThis);
242 void PaStreamOverflowCallbackHandler();
243 int32_t LatencyUsecs(pa_stream* stream);
244 int32_t ReadRecordedData(const void* bufferData, size_t bufferSize);
245 int32_t ProcessRecordedData(int8_t* bufferData,
246 uint32_t bufferSizeInSamples,
247 uint32_t recDelay);
xians@google.com68efa212011-08-11 12:41:56248
Yves Gerey665174f2018-06-19 13:03:05249 int32_t CheckPulseAudioVersion();
250 int32_t InitSamplingFrequency();
251 int32_t GetDefaultDeviceInfo(bool recDevice, char* name, uint16_t& index);
252 int32_t InitPulseAudio();
253 int32_t TerminatePulseAudio();
xians@google.com68efa212011-08-11 12:41:56254
Yves Gerey665174f2018-06-19 13:03:05255 void PaLock();
256 void PaUnLock();
xians@google.com68efa212011-08-11 12:41:56257
Niels Möller4731f002019-05-03 07:34:24258 static void RecThreadFunc(void*);
259 static void PlayThreadFunc(void*);
Markus Handell957318c2020-08-20 09:38:21260 bool RecThreadProcess() RTC_LOCKS_EXCLUDED(mutex_);
261 bool PlayThreadProcess() RTC_LOCKS_EXCLUDED(mutex_);
xians@google.com68efa212011-08-11 12:41:56262
Yves Gerey665174f2018-06-19 13:03:05263 AudioDeviceBuffer* _ptrAudioBuffer;
xians@google.com68efa212011-08-11 12:41:56264
Markus Handell5f612822020-07-08 08:13:20265 mutable Mutex mutex_;
Niels Möller2c16cc62018-10-29 08:47:51266 rtc::Event _timeEventRec;
267 rtc::Event _timeEventPlay;
268 rtc::Event _recStartEvent;
269 rtc::Event _playStartEvent;
xians@google.com68efa212011-08-11 12:41:56270
Markus Handellad5037b2021-05-07 13:02:36271 rtc::PlatformThread _ptrThreadPlay;
272 rtc::PlatformThread _ptrThreadRec;
xians@google.com68efa212011-08-11 12:41:56273
Yves Gerey665174f2018-06-19 13:03:05274 AudioMixerManagerLinuxPulse _mixerManager;
xians@google.com68efa212011-08-11 12:41:56275
Yves Gerey665174f2018-06-19 13:03:05276 uint16_t _inputDeviceIndex;
277 uint16_t _outputDeviceIndex;
278 bool _inputDeviceIsSpecified;
279 bool _outputDeviceIsSpecified;
xians@google.com68efa212011-08-11 12:41:56280
Yves Gerey665174f2018-06-19 13:03:05281 int sample_rate_hz_;
282 uint8_t _recChannels;
283 uint8_t _playChannels;
Brave Yao1a07a1e2015-05-21 04:42:40284
Yves Gerey665174f2018-06-19 13:03:05285 // Stores thread ID in constructor.
Artem Titovc8421c42021-02-02 09:57:19286 // We can then use RTC_DCHECK_RUN_ON(&worker_thread_checker_) to ensure that
Yves Gerey665174f2018-06-19 13:03:05287 // other methods are called from the same thread.
Sebastian Janssonc01367d2019-04-08 13:20:44288 // Currently only does RTC_DCHECK(thread_checker_.IsCurrent()).
Artem Titovc8421c42021-02-02 09:57:19289 SequenceChecker thread_checker_;
xians@google.com68efa212011-08-11 12:41:56290
Yves Gerey665174f2018-06-19 13:03:05291 bool _initialized;
292 bool _recording;
293 bool _playing;
294 bool _recIsInitialized;
295 bool _playIsInitialized;
296 bool _startRec;
Yves Gerey665174f2018-06-19 13:03:05297 bool _startPlay;
Yves Gerey665174f2018-06-19 13:03:05298 bool update_speaker_volume_at_startup_;
Markus Handell5f612822020-07-08 08:13:20299 bool quit_ RTC_GUARDED_BY(&mutex_);
xians@google.com68efa212011-08-11 12:41:56300
Markus Handell5f612822020-07-08 08:13:20301 uint32_t _sndCardPlayDelay RTC_GUARDED_BY(&mutex_);
xians@google.com68efa212011-08-11 12:41:56302
Yves Gerey665174f2018-06-19 13:03:05303 int32_t _writeErrors;
xians@google.com68efa212011-08-11 12:41:56304
Yves Gerey665174f2018-06-19 13:03:05305 uint16_t _deviceIndex;
306 int16_t _numPlayDevices;
307 int16_t _numRecDevices;
308 char* _playDeviceName;
309 char* _recDeviceName;
310 char* _playDisplayDeviceName;
311 char* _recDisplayDeviceName;
312 char _paServerVersion[32];
xians@google.com68efa212011-08-11 12:41:56313
Yves Gerey665174f2018-06-19 13:03:05314 int8_t* _playBuffer;
315 size_t _playbackBufferSize;
316 size_t _playbackBufferUnused;
317 size_t _tempBufferSpace;
318 int8_t* _recBuffer;
319 size_t _recordBufferSize;
320 size_t _recordBufferUsed;
321 const void* _tempSampleData;
322 size_t _tempSampleDataSize;
323 int32_t _configuredLatencyPlay;
324 int32_t _configuredLatencyRec;
xians@google.com68efa212011-08-11 12:41:56325
Yves Gerey665174f2018-06-19 13:03:05326 // PulseAudio
327 uint16_t _paDeviceIndex;
328 bool _paStateChanged;
xians@google.com68efa212011-08-11 12:41:56329
Yves Gerey665174f2018-06-19 13:03:05330 pa_threaded_mainloop* _paMainloop;
331 pa_mainloop_api* _paMainloopApi;
332 pa_context* _paContext;
niklas.enbom@webrtc.orge2a80062013-05-14 21:33:11333
Yves Gerey665174f2018-06-19 13:03:05334 pa_stream* _recStream;
335 pa_stream* _playStream;
336 uint32_t _recStreamFlags;
337 uint32_t _playStreamFlags;
338 pa_buffer_attr _playBufferAttr;
339 pa_buffer_attr _recBufferAttr;
340
341 char _oldKeyState[32];
Yves Gereyee562d82018-08-08 14:39:44342#if defined(WEBRTC_USE_X11)
Yves Gerey665174f2018-06-19 13:03:05343 Display* _XDisplay;
Yves Gereyee562d82018-08-08 14:39:44344#endif
xians@google.com68efa212011-08-11 12:41:56345};
346
Yves Gerey665174f2018-06-19 13:03:05347} // namespace webrtc
xians@google.com68efa212011-08-11 12:41:56348
349#endif // MODULES_AUDIO_DEVICE_MAIN_SOURCE_LINUX_AUDIO_DEVICE_PULSE_LINUX_H_