1 // This file is part of Desktop App Toolkit,
2 // a set of libraries for developing nice desktop applications.
3 //
4 // For license and copyright information please follow this link:
5 // https://github.com/desktop-app/legal/blob/master/LEGAL
6 //
7 #include "webrtc/details/webrtc_openal_adm.h"
8 
9 #include "base/timer.h"
10 #include "base/invoke_queued.h"
11 #include <crl/crl_semaphore.h>
12 
13 #undef emit
14 #undef slots
15 #undef signals
16 
17 #include "rtc_base/logging.h"
18 #include "rtc_base/thread.h"
19 #include <QtCore/QPointer>
20 #include <QtCore/QThread>
21 
22 #ifdef WEBRTC_WIN
23 #include "webrtc/win/webrtc_loopback_adm_win.h"
24 #endif // WEBRTC_WIN
25 
26 namespace Webrtc::details {
27 namespace {
28 
29 constexpr auto kRecordingFrequency = 48000;
30 constexpr auto kPlayoutFrequency = 48000;
31 constexpr auto kRecordingChannels = 1;
32 constexpr auto kBufferSizeMs = crl::time(10);
33 constexpr auto kPlayoutPart = (kPlayoutFrequency * kBufferSizeMs + 999)
34 	/ 1000;
35 constexpr auto kRecordingPart = (kRecordingFrequency * kBufferSizeMs + 999)
36 	/ 1000;
37 constexpr auto kRecordingBufferSize = kRecordingPart * sizeof(int16_t)
38 	* kRecordingChannels;
39 constexpr auto kRestartAfterEmptyData = 50; // Half a second with no data.
40 constexpr auto kProcessInterval = crl::time(10);
41 
42 constexpr auto kBuffersFullCount = 7;
43 constexpr auto kBuffersKeepReadyCount = 5;
44 
45 constexpr auto kDefaultRecordingLatency = crl::time(20);
46 constexpr auto kDefaultPlayoutLatency = crl::time(20);
47 constexpr auto kQueryExactTimeEach = 20;
48 
49 constexpr auto kALMaxValues = 6;
50 auto kAL_EVENT_CALLBACK_FUNCTION_SOFT = ALenum();
51 auto kAL_EVENT_CALLBACK_USER_PARAM_SOFT = ALenum();
52 auto kAL_EVENT_TYPE_BUFFER_COMPLETED_SOFT = ALenum();
53 auto kAL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT = ALenum();
54 auto kAL_EVENT_TYPE_DISCONNECTED_SOFT = ALenum();
55 auto kAL_SAMPLE_OFFSET_CLOCK_SOFT = ALenum();
56 auto kAL_SAMPLE_OFFSET_CLOCK_EXACT_SOFT = ALenum();
57 
58 auto kALC_DEVICE_LATENCY_SOFT = ALenum();
59 
60 using AL_INT64_TYPE = std::int64_t;
61 
62 using ALEVENTPROCSOFT = void(*)(
63 	ALenum eventType,
64 	ALuint object,
65 	ALuint param,
66 	ALsizei length,
67 	const ALchar *message,
68 	void *userParam);
69 using ALEVENTCALLBACKSOFT = void(*)(
70 	ALEVENTPROCSOFT callback,
71 	void *userParam);
72 using ALCSETTHREADCONTEXT = ALCboolean(*)(ALCcontext *context);
73 using ALGETSOURCEI64VSOFT = void(*)(
74 	ALuint source,
75 	ALenum param,
76 	AL_INT64_TYPE *values);
77 using ALCGETINTEGER64VSOFT = void(*)(
78 	ALCdevice *device,
79 	ALCenum pname,
80 	ALsizei size,
81 	AL_INT64_TYPE *values);
82 
83 ALEVENTCALLBACKSOFT alEventCallbackSOFT/* = nullptr*/;
84 ALCSETTHREADCONTEXT alcSetThreadContext/* = nullptr*/;
85 ALGETSOURCEI64VSOFT alGetSourcei64vSOFT/* = nullptr*/;
86 ALCGETINTEGER64VSOFT alcGetInteger64vSOFT/* = nullptr*/;
87 
Failed(ALCdevice * device)88 [[nodiscard]] bool Failed(ALCdevice *device) {
89 	if (auto code = alcGetError(device); code != ALC_NO_ERROR) {
90 		RTC_LOG(LS_ERROR)
91 			<< "OpenAL Error "
92 			<< code
93 			<< ": "
94 			<< (const char *)alcGetString(device, code);
95 		return true;
96 	}
97 	return false;
98 }
99 
100 template <typename Callback>
EnumerateDevices(ALCenum specifier,Callback && callback)101 void EnumerateDevices(ALCenum specifier, Callback &&callback) {
102 	auto devices = alcGetString(nullptr, specifier);
103 	Assert(devices != nullptr);
104 	while (*devices != 0) {
105 		callback(devices);
106 		while (*devices != 0) {
107 			++devices;
108 		}
109 		++devices;
110 	}
111 }
112 
DevicesCount(ALCenum specifier)113 [[nodiscard]] int DevicesCount(ALCenum specifier) {
114 	auto result = 0;
115 	EnumerateDevices(specifier, [&](const char *device) {
116 		++result;
117 	});
118 	return result;
119 }
120 
DeviceName(ALCenum specifier,int index,std::string * name,std::string * guid)121 [[nodiscard]] int DeviceName(
122 		ALCenum specifier,
123 		int index,
124 		std::string *name,
125 		std::string *guid) {
126 	EnumerateDevices(specifier, [&](const char *device) {
127 		if (index < 0) {
128 			return;
129 		} else if (index > 0) {
130 			--index;
131 			return;
132 		}
133 
134 		auto string = std::string(device);
135 		if (name) {
136 			if (guid) {
137 				*guid = string;
138 			}
139 			const auto prefix = std::string("OpenAL Soft on ");
140 			if (string.rfind(prefix, 0) == 0) {
141 				string = string.substr(prefix.size());
142 			}
143 			*name = std::move(string);
144 		} else if (guid) {
145 			*guid = std::move(string);
146 		}
147 		index = -1;
148 	});
149 	return (index > 0) ? -1 : 0;
150 }
151 
SetStringToArray(const std::string & string,char * array,int size)152 void SetStringToArray(const std::string &string, char *array, int size) {
153 	const auto length = std::min(int(string.size()), size - 1);
154 	if (length > 0) {
155 		memcpy(array, string.data(), length);
156 	}
157 	array[length] = 0;
158 }
159 
DeviceName(ALCenum specifier,int index,char name[webrtc::kAdmMaxDeviceNameSize],char guid[webrtc::kAdmMaxGuidSize])160 [[nodiscard]] int DeviceName(
161 		ALCenum specifier,
162 		int index,
163 		char name[webrtc::kAdmMaxDeviceNameSize],
164 		char guid[webrtc::kAdmMaxGuidSize]) {
165 	auto sname = std::string();
166 	auto sguid = std::string();
167 	const auto result = DeviceName(specifier, index, &sname, &sguid);
168 	if (result) {
169 		return result;
170 	}
171 	SetStringToArray(sname, name, webrtc::kAdmMaxDeviceNameSize);
172 	SetStringToArray(sguid, guid, webrtc::kAdmMaxGuidSize);
173 	return 0;
174 }
175 
ComputeDefaultDeviceId(ALCenum specifier)176 [[nodiscard]] std::string ComputeDefaultDeviceId(ALCenum specifier) {
177 	const auto device = alcGetString(nullptr, specifier);
178 	return device ? std::string(device) : std::string();
179 }
180 
181 } // namespace
182 
183 struct AudioDeviceOpenAL::Data {
DataWebrtc::details::AudioDeviceOpenAL::Data184 	Data() : timer(&thread) {
185 		context.moveToThread(&thread);
186 	}
187 
188 	QThread thread;
189 	QObject context;
190 	base::Timer timer;
191 
192 	QByteArray recordedSamples;
193 	int emptyRecordingData = 0;
194 	bool recording = false;
195 
196 	QByteArray playoutSamples;
197 	ALuint source = 0;
198 	int queuedBuffersCount = 0;
199 	std::array<ALuint, kBuffersFullCount> buffers = { { 0 } };
200 	std::array<bool, kBuffersFullCount> queuedBuffers = { { false } };
201 	int64_t exactDeviceTimeCounter = 0;
202 	int64_t lastExactDeviceTime = 0;
203 	crl::time lastExactDeviceTimeWhen = 0;
204 	bool playing = false;
205 };
206 
207 template <typename Callback>
sync(Callback && callback)208 std::invoke_result_t<Callback> AudioDeviceOpenAL::sync(Callback &&callback) {
209 	Expects(_data != nullptr);
210 
211 	using Result = std::invoke_result_t<Callback>;
212 
213 	crl::semaphore semaphore;
214 	if constexpr (std::is_same_v<Result, void>) {
215 		InvokeQueued(&_data->context, [&] {
216 			callback();
217 			semaphore.release();
218 		});
219 		semaphore.acquire();
220 	} else {
221 		auto result = Result();
222 		InvokeQueued(&_data->context, [&] {
223 			result = callback();
224 			semaphore.release();
225 		});
226 		semaphore.acquire();
227 		return result;
228 	}
229 }
230 
AudioDeviceOpenAL(webrtc::TaskQueueFactory * taskQueueFactory)231 AudioDeviceOpenAL::AudioDeviceOpenAL(
232 	webrtc::TaskQueueFactory *taskQueueFactory)
233 : _audioDeviceBuffer(taskQueueFactory) {
234 	_audioDeviceBuffer.SetRecordingSampleRate(kRecordingFrequency);
235 	_audioDeviceBuffer.SetRecordingChannels(kRecordingChannels);
236 }
237 
~AudioDeviceOpenAL()238 AudioDeviceOpenAL::~AudioDeviceOpenAL() {
239 	Terminate();
240 }
241 
ActiveAudioLayer(AudioLayer * audioLayer) const242 int32_t AudioDeviceOpenAL::ActiveAudioLayer(AudioLayer *audioLayer) const {
243 	*audioLayer = kPlatformDefaultAudio;
244 	return 0;
245 }
246 
RegisterAudioCallback(webrtc::AudioTransport * audioCallback)247 int32_t AudioDeviceOpenAL::RegisterAudioCallback(
248 		webrtc::AudioTransport *audioCallback) {
249 	return _audioDeviceBuffer.RegisterAudioCallback(audioCallback);
250 }
251 
Init()252 int32_t AudioDeviceOpenAL::Init() {
253 	if (_initialized) {
254 		return 0;
255 	}
256 	alcSetThreadContext = (ALCSETTHREADCONTEXT)alcGetProcAddress(
257 		nullptr,
258 		"alcSetThreadContext");
259 	if (!alcSetThreadContext) {
260 		return -1;
261 	}
262 	alEventCallbackSOFT = (ALEVENTCALLBACKSOFT)alcGetProcAddress(
263 		nullptr,
264 		"alEventCallbackSOFT");
265 
266 	alGetSourcei64vSOFT = (ALGETSOURCEI64VSOFT)alcGetProcAddress(
267 		nullptr,
268 		"alGetSourcei64vSOFT");
269 
270 	alcGetInteger64vSOFT = (ALCGETINTEGER64VSOFT)alcGetProcAddress(
271 		nullptr,
272 		"alcGetInteger64vSOFT");
273 
274 #define RESOLVE_ENUM(ENUM) k##ENUM = alcGetEnumValue(nullptr, #ENUM)
275 	RESOLVE_ENUM(AL_EVENT_CALLBACK_FUNCTION_SOFT);
276 	RESOLVE_ENUM(AL_EVENT_CALLBACK_FUNCTION_SOFT);
277 	RESOLVE_ENUM(AL_EVENT_CALLBACK_USER_PARAM_SOFT);
278 	RESOLVE_ENUM(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT);
279 	RESOLVE_ENUM(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT);
280 	RESOLVE_ENUM(AL_EVENT_TYPE_DISCONNECTED_SOFT);
281 	RESOLVE_ENUM(AL_SAMPLE_OFFSET_CLOCK_SOFT);
282 	RESOLVE_ENUM(AL_SAMPLE_OFFSET_CLOCK_EXACT_SOFT);
283 	RESOLVE_ENUM(ALC_DEVICE_LATENCY_SOFT);
284 #undef RESOLVE_ENUM
285 
286 	_initialized = true;
287 	return 0;
288 }
289 
Terminate()290 int32_t AudioDeviceOpenAL::Terminate() {
291 	StopRecording();
292 	StopPlayout();
293 	_initialized = false;
294 
295 	Ensures(!_data);
296 	return 0;
297 }
298 
Initialized() const299 bool AudioDeviceOpenAL::Initialized() const {
300 	return _initialized;
301 }
302 
InitSpeaker()303 int32_t AudioDeviceOpenAL::InitSpeaker() {
304 	_speakerInitialized = true;
305 	return 0;
306 }
307 
InitMicrophone()308 int32_t AudioDeviceOpenAL::InitMicrophone() {
309 	_microphoneInitialized = true;
310 	return 0;
311 }
312 
SpeakerIsInitialized() const313 bool AudioDeviceOpenAL::SpeakerIsInitialized() const {
314 	return _speakerInitialized;
315 }
316 
MicrophoneIsInitialized() const317 bool AudioDeviceOpenAL::MicrophoneIsInitialized() const {
318 	return _microphoneInitialized;
319 }
320 
SpeakerVolumeIsAvailable(bool * available)321 int32_t AudioDeviceOpenAL::SpeakerVolumeIsAvailable(bool *available) {
322 	if (available) {
323 		*available = false;
324 	}
325 	return 0;
326 }
327 
SetSpeakerVolume(uint32_t volume)328 int32_t AudioDeviceOpenAL::SetSpeakerVolume(uint32_t volume) {
329 	return -1;
330 }
331 
SpeakerVolume(uint32_t * volume) const332 int32_t AudioDeviceOpenAL::SpeakerVolume(uint32_t *volume) const {
333 	return -1;
334 }
335 
MaxSpeakerVolume(uint32_t * maxVolume) const336 int32_t AudioDeviceOpenAL::MaxSpeakerVolume(uint32_t *maxVolume) const {
337 	return -1;
338 }
339 
MinSpeakerVolume(uint32_t * minVolume) const340 int32_t AudioDeviceOpenAL::MinSpeakerVolume(uint32_t *minVolume) const {
341 	return -1;
342 }
343 
SpeakerMuteIsAvailable(bool * available)344 int32_t AudioDeviceOpenAL::SpeakerMuteIsAvailable(bool *available) {
345 	if (available) {
346 		*available = false;
347 	}
348 	return 0;
349 }
350 
SetSpeakerMute(bool enable)351 int32_t AudioDeviceOpenAL::SetSpeakerMute(bool enable) {
352 	return -1;
353 }
354 
SpeakerMute(bool * enabled) const355 int32_t AudioDeviceOpenAL::SpeakerMute(bool *enabled) const {
356 	if (enabled) {
357 		*enabled = false;
358 	}
359 	return 0;
360 }
361 
MicrophoneMuteIsAvailable(bool * available)362 int32_t AudioDeviceOpenAL::MicrophoneMuteIsAvailable(bool *available) {
363 	if (available) {
364 		*available = false;
365 	}
366 	return 0;
367 }
368 
SetMicrophoneMute(bool enable)369 int32_t AudioDeviceOpenAL::SetMicrophoneMute(bool enable) {
370 	return -1;
371 }
372 
MicrophoneMute(bool * enabled) const373 int32_t AudioDeviceOpenAL::MicrophoneMute(bool *enabled) const {
374 	if (enabled) {
375 		*enabled = false;
376 	}
377 	return 0;
378 }
379 
StereoRecordingIsAvailable(bool * available) const380 int32_t AudioDeviceOpenAL::StereoRecordingIsAvailable(
381 		bool *available) const {
382 	if (available) {
383 		*available = false;
384 	}
385 	return 0;
386 }
387 
SetStereoRecording(bool enable)388 int32_t AudioDeviceOpenAL::SetStereoRecording(bool enable) {
389 	return -1;
390 }
391 
StereoRecording(bool * enabled) const392 int32_t AudioDeviceOpenAL::StereoRecording(bool *enabled) const {
393 	if (enabled) {
394 		*enabled = false;
395 	}
396 	return 0;
397 }
398 
StereoPlayoutIsAvailable(bool * available) const399 int32_t AudioDeviceOpenAL::StereoPlayoutIsAvailable(bool *available) const {
400 	if (available) {
401 		*available = true;
402 	}
403 	return 0;
404 }
405 
SetStereoPlayout(bool enable)406 int32_t AudioDeviceOpenAL::SetStereoPlayout(bool enable) {
407 	if (Playing()) {
408 		return -1;
409 	}
410 	_playoutChannels = enable ? 2 : 1;
411 	return 0;
412 }
413 
StereoPlayout(bool * enabled) const414 int32_t AudioDeviceOpenAL::StereoPlayout(bool *enabled) const {
415 	if (enabled) {
416 		*enabled = (_playoutChannels == 2);
417 	}
418 	return 0;
419 }
420 
MicrophoneVolumeIsAvailable(bool * available)421 int32_t AudioDeviceOpenAL::MicrophoneVolumeIsAvailable(
422 		bool *available) {
423 	if (available) {
424 		*available = false;
425 	}
426 	return 0;
427 }
428 
SetMicrophoneVolume(uint32_t volume)429 int32_t AudioDeviceOpenAL::SetMicrophoneVolume(uint32_t volume) {
430 	return -1;
431 }
432 
MicrophoneVolume(uint32_t * volume) const433 int32_t AudioDeviceOpenAL::MicrophoneVolume(uint32_t *volume) const {
434 	return -1;
435 }
436 
MaxMicrophoneVolume(uint32_t * maxVolume) const437 int32_t AudioDeviceOpenAL::MaxMicrophoneVolume(uint32_t *maxVolume) const {
438 	return -1;
439 }
440 
MinMicrophoneVolume(uint32_t * minVolume) const441 int32_t AudioDeviceOpenAL::MinMicrophoneVolume(uint32_t *minVolume) const {
442 	return -1;
443 }
444 
PlayoutDevices()445 int16_t AudioDeviceOpenAL::PlayoutDevices() {
446 	return DevicesCount(ALC_ALL_DEVICES_SPECIFIER);
447 }
448 
SetPlayoutDevice(uint16_t index)449 int32_t AudioDeviceOpenAL::SetPlayoutDevice(uint16_t index) {
450 	const auto result = DeviceName(
451 		ALC_ALL_DEVICES_SPECIFIER,
452 		index,
453 		nullptr,
454 		&_playoutDeviceId);
455 	return result ? result : restartPlayout();
456 }
457 
SetPlayoutDevice(WindowsDeviceType)458 int32_t AudioDeviceOpenAL::SetPlayoutDevice(WindowsDeviceType /*device*/) {
459 	_playoutDeviceId = ComputeDefaultDeviceId(ALC_DEFAULT_DEVICE_SPECIFIER);
460 	return _playoutDeviceId.empty() ? -1 : restartPlayout();
461 }
462 
PlayoutDeviceName(uint16_t index,char name[webrtc::kAdmMaxDeviceNameSize],char guid[webrtc::kAdmMaxGuidSize])463 int32_t AudioDeviceOpenAL::PlayoutDeviceName(
464 		uint16_t index,
465 		char name[webrtc::kAdmMaxDeviceNameSize],
466 		char guid[webrtc::kAdmMaxGuidSize]) {
467 	return DeviceName(ALC_ALL_DEVICES_SPECIFIER, index, name, guid);
468 }
469 
RecordingDeviceName(uint16_t index,char name[webrtc::kAdmMaxDeviceNameSize],char guid[webrtc::kAdmMaxGuidSize])470 int32_t AudioDeviceOpenAL::RecordingDeviceName(
471 		uint16_t index,
472 		char name[webrtc::kAdmMaxDeviceNameSize],
473 		char guid[webrtc::kAdmMaxGuidSize]) {
474 	return DeviceName(ALC_CAPTURE_DEVICE_SPECIFIER, index, name, guid);
475 }
476 
RecordingDevices()477 int16_t AudioDeviceOpenAL::RecordingDevices() {
478 	return DevicesCount(ALC_CAPTURE_DEVICE_SPECIFIER);
479 }
480 
SetRecordingDevice(uint16_t index)481 int32_t AudioDeviceOpenAL::SetRecordingDevice(uint16_t index) {
482 	const auto result = DeviceName(
483 		ALC_CAPTURE_DEVICE_SPECIFIER,
484 		index,
485 		nullptr,
486 		&_recordingDeviceId);
487 	return result ? result : restartRecording();
488 }
489 
SetRecordingDevice(WindowsDeviceType)490 int32_t AudioDeviceOpenAL::SetRecordingDevice(WindowsDeviceType /*device*/) {
491 	_recordingDeviceId = ComputeDefaultDeviceId(
492 		ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
493 	return _recordingDeviceId.empty() ? -1 : restartRecording();
494 }
495 
PlayoutIsAvailable(bool * available)496 int32_t AudioDeviceOpenAL::PlayoutIsAvailable(bool *available) {
497 	if (available) {
498 		*available = true;
499 	}
500 	return 0;
501 }
502 
RecordingIsAvailable(bool * available)503 int32_t AudioDeviceOpenAL::RecordingIsAvailable(bool *available) {
504 	if (available) {
505 		*available = true;
506 	}
507 	return 0;
508 }
509 
InitPlayout()510 int32_t AudioDeviceOpenAL::InitPlayout() {
511 	if (!_initialized) {
512 		return -1;
513 	} else if (_playoutInitialized) {
514 		return 0;
515 	}
516 	_playoutInitialized = true;
517 	ensureThreadStarted();
518 	openPlayoutDevice();
519 	return 0;
520 }
521 
openRecordingDevice()522 void AudioDeviceOpenAL::openRecordingDevice() {
523 	if (_recordingDevice || _recordingFailed) {
524 		return;
525 	}
526 	_recordingDevice = alcCaptureOpenDevice(
527 		_recordingDeviceId.empty() ? nullptr : _recordingDeviceId.c_str(),
528 		kRecordingFrequency,
529 		AL_FORMAT_MONO16,
530 		kRecordingFrequency / 4);
531 	if (!_recordingDevice) {
532 		RTC_LOG(LS_ERROR)
533 			<< "OpenAL Capture Device open failed, deviceID: '"
534 			<< _recordingDeviceId
535 			<< "'";
536 		_recordingFailed = true;
537 		return;
538 	}
539 	// This does not work for capture devices :(
540 	//_context = alcCreateContext(_device, nullptr);
541 	//	alEventCallbackSOFT([](
542 	//			ALenum eventType,
543 	//			ALuint object,
544 	//			ALuint param,
545 	//			ALsizei length,
546 	//			const ALchar *message,
547 	//			void *that) {
548 	//		static_cast<AudioInputOpenAL*>(that)->handleEvent(
549 	//			eventType,
550 	//			object,
551 	//			param,
552 	//			length,
553 	//			message);
554 	//	}, this);
555 }
556 
openPlayoutDevice()557 void AudioDeviceOpenAL::openPlayoutDevice() {
558 	if (_playoutDevice || _playoutFailed) {
559 		return;
560 	}
561 	_playoutDevice = alcOpenDevice(
562 		_playoutDeviceId.empty() ? nullptr : _playoutDeviceId.c_str());
563 	if (!_playoutDevice) {
564 		RTC_LOG(LS_ERROR)
565 			<< "OpenAL Device open failed, deviceID: '"
566 			<< _playoutDeviceId
567 			<< "'";
568 		_playoutFailed = true;
569 		return;
570 	}
571 	_playoutContext = alcCreateContext(_playoutDevice, nullptr);
572 	if (!_playoutContext) {
573 		RTC_LOG(LS_ERROR) << "OpenAL Context create failed.";
574 		_playoutFailed = true;
575 		closePlayoutDevice();
576 		return;
577 	}
578 	sync([&] {
579 		alcSetThreadContext(_playoutContext);
580 		if (alEventCallbackSOFT) {
581 			alEventCallbackSOFT([](
582 					ALenum eventType,
583 					ALuint object,
584 					ALuint param,
585 					ALsizei length,
586 					const ALchar *message,
587 					void *that) {
588 				static_cast<AudioDeviceOpenAL*>(that)->handleEvent(
589 					eventType,
590 					object,
591 					param,
592 					length,
593 					message);
594 			}, this);
595 		}
596 	});
597 }
598 
handleEvent(ALenum eventType,ALuint object,ALuint param,ALsizei length,const ALchar * message)599 void AudioDeviceOpenAL::handleEvent(
600 		ALenum eventType,
601 		ALuint object,
602 		ALuint param,
603 		ALsizei length,
604 		const ALchar *message) {
605 	if (eventType == kAL_EVENT_TYPE_DISCONNECTED_SOFT && _thread) {
606 		const auto weak = QPointer<QObject>(&_data->context);
607 		_thread->PostTask(RTC_FROM_HERE, [=] {
608 			if (weak) {
609 				restartRecording();
610 			}
611 		});
612 	}
613 }
614 
InitRecording()615 int32_t AudioDeviceOpenAL::InitRecording() {
616 	if (!_initialized) {
617 		return -1;
618 	} else if (_recordingInitialized) {
619 		return 0;
620 	}
621 	_recordingInitialized = true;
622 	ensureThreadStarted();
623 	openRecordingDevice();
624 	_audioDeviceBuffer.SetRecordingSampleRate(kRecordingFrequency);
625 	_audioDeviceBuffer.SetRecordingChannels(kRecordingChannels);
626 	return 0;
627 }
628 
ensureThreadStarted()629 void AudioDeviceOpenAL::ensureThreadStarted() {
630 	if (_data) {
631 		return;
632 	}
633 	_thread = rtc::Thread::Current();
634 	if (_thread && !_thread->IsOwned()) {
635 		_thread->UnwrapCurrent();
636 		_thread = nullptr;
637 	}
638 	//	Assert(_thread != nullptr);
639 	//	Assert(_thread->IsOwned());
640 
641 	_data = std::make_unique<Data>();
642 	_data->timer.setCallback([=] { processData(); });
643 	_data->thread.setObjectName("Webrtc OpenAL Thread");
644 	_data->thread.start(QThread::TimeCriticalPriority);
645 }
646 
processData()647 void AudioDeviceOpenAL::processData() {
648 	Expects(_data != nullptr);
649 
650 	if (_data->playing && !_playoutFailed) {
651 		processPlayoutData();
652 	}
653 	if (_data->recording && !_recordingFailed) {
654 		processRecordingData();
655 	}
656 }
657 
processRecordedPart(bool firstInCycle)658 bool AudioDeviceOpenAL::processRecordedPart(bool firstInCycle) {
659 	auto samples = ALint();
660 	alcGetIntegerv(_recordingDevice, ALC_CAPTURE_SAMPLES, 1, &samples);
661 	if (Failed(_recordingDevice)) {
662 		restartRecordingQueued();
663 		return false;
664 	}
665 	if (samples <= 0) {
666 		if (firstInCycle) {
667 			++_data->emptyRecordingData;
668 			if (_data->emptyRecordingData == kRestartAfterEmptyData) {
669 				restartRecordingQueued();
670 			}
671 		}
672 		return false;
673 	} else if (samples < kRecordingPart) {
674 		// Not enough data for 10ms.
675 		return false;
676 	}
677 
678 	_recordingLatency = queryRecordingLatencyMs();
679 	//RTC_LOG(LS_ERROR) << "RECORDING LATENCY: " << _recordingLatency << "ms";
680 
681 	_data->emptyRecordingData = 0;
682 	if (_data->recordedSamples.size() < kRecordingBufferSize) {
683 		_data->recordedSamples.resize(kRecordingBufferSize);
684 	}
685 	alcCaptureSamples(
686 		_recordingDevice,
687 		_data->recordedSamples.data(),
688 		kRecordingPart);
689 	if (Failed(_recordingDevice)) {
690 		restartRecordingQueued();
691 		return false;
692 	}
693 	_audioDeviceBuffer.SetRecordedBuffer(
694 		_data->recordedSamples.data(),
695 		kRecordingPart);
696 	_audioDeviceBuffer.SetVQEData(_playoutLatency, _recordingLatency);
697 	_audioDeviceBuffer.DeliverRecordedData();
698 	return true;
699 }
700 
processRecordingData()701 void AudioDeviceOpenAL::processRecordingData() {
702 	for (auto first = true; processRecordedPart(first); first = false) {
703 	}
704 }
705 
clearProcessedBuffer()706 bool AudioDeviceOpenAL::clearProcessedBuffer() {
707 	Expects(_data != nullptr);
708 
709 	auto processed = ALint(0);
710 	alGetSourcei(_data->source, AL_BUFFERS_PROCESSED, &processed);
711 	if (processed < 1) {
712 		return false;
713 	}
714 	auto buffer = ALuint(0);
715 	alSourceUnqueueBuffers(_data->source, 1, &buffer);
716 	for (auto i = 0; i != int(_data->buffers.size()); ++i) {
717 		if (_data->buffers[i] == buffer) {
718 			_data->queuedBuffers[i] = false;
719 			--_data->queuedBuffersCount;
720 			return true;
721 		}
722 	}
723 	Unexpected("Processed buffer not found.");
724 }
725 
unqueueAllBuffers()726 void AudioDeviceOpenAL::unqueueAllBuffers() {
727 	alSourcei(_data->source, AL_BUFFER, AL_NONE);
728 	ranges::fill(_data->queuedBuffers, false);
729 	_data->queuedBuffersCount = 0;
730 }
731 
clearProcessedBuffers()732 void AudioDeviceOpenAL::clearProcessedBuffers() {
733 	while (true) {
734 		if (!clearProcessedBuffer()) {
735 			break;
736 		}
737 	}
738 }
739 
queryRecordingLatencyMs()740 crl::time AudioDeviceOpenAL::queryRecordingLatencyMs() {
741 #ifdef WEBRTC_WIN
742 	if (kALC_DEVICE_LATENCY_SOFT
743 		&& kAL_SAMPLE_OFFSET_CLOCK_EXACT_SOFT) { // Check patched build.
744 		auto latency = AL_INT64_TYPE();
745 		alcGetInteger64vSOFT(
746 			_recordingDevice,
747 			kALC_DEVICE_LATENCY_SOFT,
748 			1,
749 			&latency);
750 		return latency / 1'000'000;
751 	}
752 #endif // WEBRTC_WIN
753 	return kDefaultRecordingLatency;
754 }
755 
countExactQueuedMsForLatency(crl::time now,bool playing)756 crl::time AudioDeviceOpenAL::countExactQueuedMsForLatency(
757 		crl::time now,
758 		bool playing) {
759 	auto values = std::array<AL_INT64_TYPE, kALMaxValues>{};
760 	auto &sampleOffset = values[0];
761 	auto &clockTime = values[1];
762 	auto &exactDeviceTime = values[2];
763 	const auto countExact = alGetSourcei64vSOFT
764 		&& kAL_SAMPLE_OFFSET_CLOCK_SOFT
765 		&& kAL_SAMPLE_OFFSET_CLOCK_EXACT_SOFT;
766 	if (countExact) {
767 		if (!_data->lastExactDeviceTimeWhen
768 			|| !(++_data->exactDeviceTimeCounter % kQueryExactTimeEach)) {
769 			alGetSourcei64vSOFT(
770 				_data->source,
771 				kAL_SAMPLE_OFFSET_CLOCK_EXACT_SOFT,
772 				values.data());
773 			_data->lastExactDeviceTime = exactDeviceTime;
774 			_data->lastExactDeviceTimeWhen = now;
775 		} else {
776 			alGetSourcei64vSOFT(
777 				_data->source,
778 				kAL_SAMPLE_OFFSET_CLOCK_SOFT,
779 				values.data());
780 
781 			// The exactDeviceTime is in nanoseconds.
782 			exactDeviceTime = _data->lastExactDeviceTime
783 				+ (now - _data->lastExactDeviceTimeWhen) * 1'000'000;
784 		}
785 	} else {
786 		auto offset = ALint(0);
787 		alGetSourcei(_data->source, AL_SAMPLE_OFFSET, &offset);
788 		sampleOffset = (AL_INT64_TYPE(offset) << 32);
789 	}
790 
791 	const auto queuedSamples = (AL_INT64_TYPE(
792 		_data->queuedBuffersCount * kPlayoutPart) << 32);
793 	const auto processedInOpenAL = playing ? sampleOffset : queuedSamples;
794 	const auto secondsQueuedInDevice = std::max(
795 		clockTime - exactDeviceTime,
796 		AL_INT64_TYPE(0)
797 	) / 1'000'000'000.;
798 	const auto secondsQueuedInOpenAL
799 		= (double((queuedSamples - processedInOpenAL) >> (32 - 10))
800 			/ double(kPlayoutFrequency * (1 << 10)));
801 
802 	const auto queuedTotal = crl::time(base::SafeRound(
803 		(secondsQueuedInDevice + secondsQueuedInOpenAL) * 1'000));
804 
805 	return countExact
806 		? queuedTotal
807 		: std::max(queuedTotal, kDefaultPlayoutLatency);
808 }
809 
processPlayoutData()810 void AudioDeviceOpenAL::processPlayoutData() {
811 	Expects(_data != nullptr);
812 
813 	const auto playing = [&] {
814 		auto state = ALint(AL_INITIAL);
815 		alGetSourcei(_data->source, AL_SOURCE_STATE, &state);
816 		return (state == AL_PLAYING);
817 	};
818 	const auto wasPlaying = playing();
819 
820 	if (wasPlaying) {
821 		clearProcessedBuffers();
822 	} else {
823 		unqueueAllBuffers();
824 	}
825 
826 	const auto wereQueued = _data->queuedBuffers;
827 	while (_data->queuedBuffersCount < kBuffersKeepReadyCount) {
828 		const auto available = _audioDeviceBuffer.RequestPlayoutData(
829 			kPlayoutPart);
830 		if (available == kPlayoutPart) {
831 			_audioDeviceBuffer.GetPlayoutData(_data->playoutSamples.data());
832 		} else {
833 			//ranges::fill(_data->playoutSamples, 0);
834 			break;
835 		}
836 		const auto now = crl::now();
837 		_playoutLatency = countExactQueuedMsForLatency(now, wasPlaying);
838 		//RTC_LOG(LS_ERROR) << "PLAYOUT LATENCY: " << _playoutLatency << "ms";
839 
840 		const auto i = ranges::find(_data->queuedBuffers, false);
841 		Assert(i != end(_data->queuedBuffers));
842 		const auto index = int(i - begin(_data->queuedBuffers));
843 		alBufferData(
844 			_data->buffers[index],
845 			(_playoutChannels == 2) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16,
846 			_data->playoutSamples.data(),
847 			_data->playoutSamples.size(),
848 			kPlayoutFrequency);
849 
850 #ifdef WEBRTC_WIN
851 		if (IsLoopbackCaptureActive() && _playoutChannels == 2) {
852 			LoopbackCapturePushFarEnd(
853 				now + _playoutLatency,
854 				_data->playoutSamples,
855 				kPlayoutFrequency,
856 				_playoutChannels);
857 		}
858 #endif // WEBRTC_WIN
859 
860 		_data->queuedBuffers[index] = true;
861 		++_data->queuedBuffersCount;
862 		if (wasPlaying) {
863 			alSourceQueueBuffers(
864 				_data->source,
865 				1,
866 				_data->buffers.data() + index);
867 		}
868 	}
869 	if (!_data->queuedBuffersCount) {
870 		return;
871 	}
872 	if (!playing()) {
873 		if (wasPlaying) {
874 			// While we were queueing buffers the source stopped.
875 			// Now we can't unqueue only old buffers, so we unqueue all
876 			// of them and then re-queue the ones we queued right now.
877 			unqueueAllBuffers();
878 			for (auto i = 0; i != int(_data->buffers.size()); ++i) {
879 				if (!wereQueued[i] && _data->queuedBuffers[i]) {
880 					alSourceQueueBuffers(
881 						_data->source,
882 						1,
883 						_data->buffers.data() + i);
884 				}
885 			}
886 		} else {
887 			// We were not playing and had no buffers,
888 			// so queue them all at once.
889 			alSourceQueueBuffers(
890 				_data->source,
891 				_data->queuedBuffersCount,
892 				_data->buffers.data());
893 		}
894 		alSourcePlay(_data->source);
895 	}
896 
897 	if (Failed(_playoutDevice)) {
898 		_playoutFailed = true;
899 	}
900 }
901 
StartRecording()902 int32_t AudioDeviceOpenAL::StartRecording() {
903 	if (!_recordingInitialized) {
904 		return -1;
905 	} else if (_data && _data->recording) {
906 		return 0;
907 	}
908 	if (_recordingFailed) {
909 		_recordingFailed = false;
910 		openRecordingDevice();
911 	}
912 	_audioDeviceBuffer.StartRecording();
913 	startCaptureOnThread();
914 	return 0;
915 }
916 
startCaptureOnThread()917 void AudioDeviceOpenAL::startCaptureOnThread() {
918 	Expects(_data != nullptr);
919 
920 	sync([&] {
921 		_data->recording = true;
922 		if (_recordingFailed) {
923 			return;
924 		}
925 		alcCaptureStart(_recordingDevice);
926 		if (Failed(_recordingDevice)) {
927 			_recordingFailed = true;
928 			return;
929 		}
930 		if (!_data->timer.isActive()) {
931 			_data->timer.callEach(kProcessInterval);
932 		}
933 	});
934 	if (_recordingFailed) {
935 		closeRecordingDevice();
936 	}
937 }
938 
stopCaptureOnThread()939 void AudioDeviceOpenAL::stopCaptureOnThread() {
940 	Expects(_data != nullptr);
941 
942 	if (!_data->recording) {
943 		return;
944 	}
945 	sync([&] {
946 		_data->recording = false;
947 		if (_recordingFailed) {
948 			return;
949 		}
950 		if (!_data->playing) {
951 			_data->timer.cancel();
952 		}
953 		if (_recordingDevice) {
954 			alcCaptureStop(_recordingDevice);
955 		}
956 	});
957 }
958 
startPlayingOnThread()959 void AudioDeviceOpenAL::startPlayingOnThread() {
960 	Expects(_data != nullptr);
961 
962 	sync([&] {
963 		_data->playing = true;
964 		if (_playoutFailed) {
965 			return;
966 		}
967 		ALuint source = 0;
968 		alGenSources(1, &source);
969 		if (source) {
970 			alSourcef(source, AL_PITCH, 1.f);
971 			alSource3f(source, AL_POSITION, 0, 0, 0);
972 			alSource3f(source, AL_VELOCITY, 0, 0, 0);
973 			alSourcei(source, AL_LOOPING, 0);
974 			alSourcei(source, AL_SOURCE_RELATIVE, 1);
975 			alSourcei(source, AL_ROLLOFF_FACTOR, 0);
976 			if (alIsExtensionPresent("AL_SOFT_direct_channels_remix")) {
977 				alSourcei(source, alGetEnumValue("AL_DIRECT_CHANNELS_SOFT"), 2);
978 			}
979 			_data->source = source;
980 			alGenBuffers(_data->buffers.size(), _data->buffers.data());
981 
982 			_data->exactDeviceTimeCounter = 0;
983 			_data->lastExactDeviceTime = 0;
984 			_data->lastExactDeviceTimeWhen = 0;
985 
986 			const auto bufferSize = kPlayoutPart * sizeof(int16_t)
987 				* _playoutChannels;
988 
989 			_data->playoutSamples = QByteArray(bufferSize, 0);
990 			//for (auto i = 0; i != kBuffersKeepReadyCount; ++i) {
991 			//	alBufferData(
992 			//		_data->buffers[i],
993 			//		AL_FORMAT_STEREO16,
994 			//		_data->playoutSamples.data(),
995 			//		_data->playoutSamples.size(),
996 			//		kPlayoutFrequency);
997 			//	_data->queuedBuffers[i] = true;
998 			//}
999 			//_data->queuedBuffersCount = kBuffersKeepReadyCount;
1000 			//alSourceQueueBuffers(
1001 			//	source,
1002 			//	kBuffersKeepReadyCount,
1003 			//	_data->buffers.data());
1004 			//alSourcePlay(source);
1005 
1006 			if (!_data->timer.isActive()) {
1007 				_data->timer.callEach(kProcessInterval);
1008 			}
1009 		}
1010 	});
1011 }
1012 
stopPlayingOnThread()1013 void AudioDeviceOpenAL::stopPlayingOnThread() {
1014 	Expects(_data != nullptr);
1015 
1016 	sync([&] {
1017 		const auto guard = gsl::finally([&] {
1018 			if (alEventCallbackSOFT) {
1019 				alEventCallbackSOFT(nullptr, nullptr);
1020 			}
1021 			alcSetThreadContext(nullptr);
1022 		});
1023 		if (!_data->playing) {
1024 			return;
1025 		}
1026 		_data->playing = false;
1027 		if (_playoutFailed) {
1028 			return;
1029 		}
1030 		if (!_data->recording) {
1031 			_data->timer.cancel();
1032 		}
1033 		if (_data->source) {
1034 			alSourceStop(_data->source);
1035 			unqueueAllBuffers();
1036 			alDeleteBuffers(_data->buffers.size(), _data->buffers.data());
1037 			alDeleteSources(1, &_data->source);
1038 			_data->source = 0;
1039 			ranges::fill(_data->buffers, ALuint(0));
1040 		}
1041 	});
1042 }
1043 
StopRecording()1044 int32_t AudioDeviceOpenAL::StopRecording() {
1045 	if (_data) {
1046 		stopCaptureOnThread();
1047 		_audioDeviceBuffer.StopRecording();
1048 		if (!_data->playing) {
1049 			_data->thread.quit();
1050 			_data->thread.wait();
1051 			_data = nullptr;
1052 		}
1053 	}
1054 	closeRecordingDevice();
1055 	_recordingInitialized = false;
1056 	return 0;
1057 }
1058 
restartRecordingQueued()1059 void AudioDeviceOpenAL::restartRecordingQueued() {
1060 	Expects(_data != nullptr);
1061 
1062 	if (!_thread) {
1063 		// We support auto-restarting only when started from rtc::Thread.
1064 		return;
1065 	}
1066 	const auto weak = QPointer<QObject>(&_data->context);
1067 	_thread->PostTask(RTC_FROM_HERE, [=] {
1068 		if (weak) {
1069 			restartRecording();
1070 			InvokeQueued(&_data->context, [=] {
1071 				_data->emptyRecordingData = 0;
1072 			});
1073 		}
1074 	});
1075 }
1076 
restartRecording()1077 int AudioDeviceOpenAL::restartRecording() {
1078 	if (!_data || !_data->recording) {
1079 		return 0;
1080 	}
1081 	stopCaptureOnThread();
1082 	closeRecordingDevice();
1083 	if (!validateRecordingDeviceId()) {
1084 		sync([&] {
1085 			_data->recording = true;
1086 			_recordingFailed = true;
1087 		});
1088 		return 0;
1089 	}
1090 	_recordingFailed = false;
1091 	openRecordingDevice();
1092 	startCaptureOnThread();
1093 	return 0;
1094 }
1095 
restartPlayoutQueued()1096 void AudioDeviceOpenAL::restartPlayoutQueued() {
1097 	Expects(_data != nullptr);
1098 
1099 	if (!_thread) {
1100 		// We support auto-restarting only when started from rtc::Thread.
1101 		return;
1102 	}
1103 	const auto weak = QPointer<QObject>(&_data->context);
1104 	_thread->PostTask(RTC_FROM_HERE, [=] {
1105 		if (weak) {
1106 			restartPlayout();
1107 		}
1108 	});
1109 }
1110 
restartPlayout()1111 int AudioDeviceOpenAL::restartPlayout() {
1112 	if (!_data || !_data->playing) {
1113 		return 0;
1114 	}
1115 	stopPlayingOnThread();
1116 	closePlayoutDevice();
1117 	if (!validatePlayoutDeviceId()) {
1118 		sync([&] {
1119 			_data->playing = true;
1120 			_playoutFailed = true;
1121 		});
1122 		return 0;
1123 	}
1124 	_playoutFailed = false;
1125 	openPlayoutDevice();
1126 	startPlayingOnThread();
1127 	return 0;
1128 }
1129 
closeRecordingDevice()1130 void AudioDeviceOpenAL::closeRecordingDevice() {
1131 	//if (_context) {
1132 	//	alcDestroyContext(_context);
1133 	//	_context = nullptr;
1134 	//}
1135 	if (_recordingDevice) {
1136 		alcCaptureCloseDevice(_recordingDevice);
1137 		_recordingDevice = nullptr;
1138 	}
1139 }
1140 
closePlayoutDevice()1141 void AudioDeviceOpenAL::closePlayoutDevice() {
1142 	if (_playoutContext) {
1143 		alcDestroyContext(_playoutContext);
1144 		_playoutContext = nullptr;
1145 	}
1146 	if (_playoutDevice) {
1147 		alcCloseDevice(_playoutDevice);
1148 		_playoutDevice = nullptr;
1149 	}
1150 }
1151 
validateRecordingDeviceId()1152 bool AudioDeviceOpenAL::validateRecordingDeviceId() {
1153 	auto valid = false;
1154 	EnumerateDevices(ALC_CAPTURE_DEVICE_SPECIFIER, [&](const char *device) {
1155 		if (!valid && _recordingDeviceId == std::string(device)) {
1156 			valid = true;
1157 		}
1158 	});
1159 	if (valid) {
1160 		return true;
1161 	}
1162 	const auto defaultDeviceId = ComputeDefaultDeviceId(
1163 		ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
1164 	if (!defaultDeviceId.empty()) {
1165 		_recordingDeviceId = defaultDeviceId;
1166 		return true;
1167 	}
1168 	RTC_LOG(LS_ERROR) << "Could not find any OpenAL Capture devices.";
1169 	return false;
1170 }
1171 
validatePlayoutDeviceId()1172 bool AudioDeviceOpenAL::validatePlayoutDeviceId() {
1173 	auto valid = false;
1174 	EnumerateDevices(ALC_ALL_DEVICES_SPECIFIER, [&](const char *device) {
1175 		if (!valid && _playoutDeviceId == std::string(device)) {
1176 			valid = true;
1177 		}
1178 	});
1179 	if (valid) {
1180 		return true;
1181 	}
1182 	const auto defaultDeviceId = ComputeDefaultDeviceId(
1183 		ALC_DEFAULT_DEVICE_SPECIFIER);
1184 	if (!defaultDeviceId.empty()) {
1185 		_playoutDeviceId = defaultDeviceId;
1186 		return true;
1187 	}
1188 	RTC_LOG(LS_ERROR) << "Could not find any OpenAL devices.";
1189 	return false;
1190 }
1191 
RecordingIsInitialized() const1192 bool AudioDeviceOpenAL::RecordingIsInitialized() const {
1193 	return _recordingInitialized;
1194 }
1195 
Recording() const1196 bool AudioDeviceOpenAL::Recording() const {
1197 	return _data && _data->recording;
1198 }
1199 
PlayoutIsInitialized() const1200 bool AudioDeviceOpenAL::PlayoutIsInitialized() const {
1201 	return _playoutInitialized;
1202 }
1203 
StartPlayout()1204 int32_t AudioDeviceOpenAL::StartPlayout() {
1205 	if (!_playoutInitialized) {
1206 		return -1;
1207 	} else if (Playing()) {
1208 		return 0;
1209 	}
1210 	if (_playoutFailed) {
1211 		_playoutFailed = false;
1212 		openPlayoutDevice();
1213 	}
1214 	_audioDeviceBuffer.SetPlayoutSampleRate(kPlayoutFrequency);
1215 	_audioDeviceBuffer.SetPlayoutChannels(_playoutChannels);
1216 	_audioDeviceBuffer.StartPlayout();
1217 	startPlayingOnThread();
1218 	return 0;
1219 }
1220 
StopPlayout()1221 int32_t AudioDeviceOpenAL::StopPlayout() {
1222 	if (_data) {
1223 		stopPlayingOnThread();
1224 		_audioDeviceBuffer.StopPlayout();
1225 		if (!_data->recording) {
1226 			_data->thread.quit();
1227 			_data->thread.wait();
1228 			_data = nullptr;
1229 		}
1230 	}
1231 	closePlayoutDevice();
1232 	_playoutInitialized = false;
1233 	return 0;
1234 }
1235 
PlayoutDelay(uint16_t * delayMS) const1236 int32_t AudioDeviceOpenAL::PlayoutDelay(uint16_t *delayMS) const {
1237 	if (delayMS) {
1238 		*delayMS = 0;
1239 	}
1240 	return 0;
1241 }
1242 
BuiltInAECIsAvailable() const1243 bool AudioDeviceOpenAL::BuiltInAECIsAvailable() const {
1244 	return false;
1245 }
1246 
BuiltInAGCIsAvailable() const1247 bool AudioDeviceOpenAL::BuiltInAGCIsAvailable() const {
1248 	return false;
1249 }
1250 
BuiltInNSIsAvailable() const1251 bool AudioDeviceOpenAL::BuiltInNSIsAvailable() const {
1252 	return false;
1253 }
1254 
EnableBuiltInAEC(bool enable)1255 int32_t AudioDeviceOpenAL::EnableBuiltInAEC(bool enable) {
1256 	return enable ? -1 : 0;
1257 }
1258 
EnableBuiltInAGC(bool enable)1259 int32_t AudioDeviceOpenAL::EnableBuiltInAGC(bool enable) {
1260 	return enable ? -1 : 0;
1261 }
1262 
EnableBuiltInNS(bool enable)1263 int32_t AudioDeviceOpenAL::EnableBuiltInNS(bool enable) {
1264 	return enable ? -1 : 0;
1265 }
1266 
Playing() const1267 bool AudioDeviceOpenAL::Playing() const {
1268 	return _data && _data->playing;
1269 }
1270 
1271 } // namespace Webrtc::details
1272