Make a couple more operator bools explicit
[openal-soft.git] / alc / alc.cpp
blob4c8d0a6c4da1497f47216c9ebe9d21bfde7e8497
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include "version.h"
25 #ifdef _WIN32
26 #define WIN32_LEAN_AND_MEAN
27 #include <windows.h>
28 #endif
30 #include <algorithm>
31 #include <array>
32 #include <atomic>
33 #include <bitset>
34 #include <cassert>
35 #include <cctype>
36 #include <chrono>
37 #include <cinttypes>
38 #include <climits>
39 #include <cmath>
40 #include <csignal>
41 #include <cstdint>
42 #include <cstdio>
43 #include <cstdlib>
44 #include <cstring>
45 #include <functional>
46 #include <iterator>
47 #include <limits>
48 #include <memory>
49 #include <mutex>
50 #include <new>
51 #include <stddef.h>
52 #include <stdexcept>
53 #include <string>
54 #include <type_traits>
55 #include <utility>
57 #include "AL/al.h"
58 #include "AL/alc.h"
59 #include "AL/alext.h"
60 #include "AL/efx.h"
62 #include "al/auxeffectslot.h"
63 #include "al/buffer.h"
64 #include "al/effect.h"
65 #include "al/filter.h"
66 #include "al/listener.h"
67 #include "al/source.h"
68 #include "albit.h"
69 #include "albyte.h"
70 #include "alconfig.h"
71 #include "almalloc.h"
72 #include "alnumeric.h"
73 #include "aloptional.h"
74 #include "alspan.h"
75 #include "alstring.h"
76 #include "alu.h"
77 #include "atomic.h"
78 #include "context.h"
79 #include "core/ambidefs.h"
80 #include "core/bformatdec.h"
81 #include "core/bs2b.h"
82 #include "core/context.h"
83 #include "core/cpu_caps.h"
84 #include "core/devformat.h"
85 #include "core/device.h"
86 #include "core/effectslot.h"
87 #include "core/except.h"
88 #include "core/helpers.h"
89 #include "core/mastering.h"
90 #include "core/mixer/hrtfdefs.h"
91 #include "core/fpu_ctrl.h"
92 #include "core/front_stablizer.h"
93 #include "core/logging.h"
94 #include "core/uhjfilter.h"
95 #include "core/voice.h"
96 #include "core/voice_change.h"
97 #include "device.h"
98 #include "effects/base.h"
99 #include "inprogext.h"
100 #include "intrusive_ptr.h"
101 #include "opthelpers.h"
102 #include "strutils.h"
103 #include "threads.h"
104 #include "vector.h"
106 #include "backends/base.h"
107 #include "backends/null.h"
108 #include "backends/loopback.h"
109 #ifdef HAVE_PIPEWIRE
110 #include "backends/pipewire.h"
111 #endif
112 #ifdef HAVE_JACK
113 #include "backends/jack.h"
114 #endif
115 #ifdef HAVE_PULSEAUDIO
116 #include "backends/pulseaudio.h"
117 #endif
118 #ifdef HAVE_ALSA
119 #include "backends/alsa.h"
120 #endif
121 #ifdef HAVE_WASAPI
122 #include "backends/wasapi.h"
123 #endif
124 #ifdef HAVE_COREAUDIO
125 #include "backends/coreaudio.h"
126 #endif
127 #ifdef HAVE_OPENSL
128 #include "backends/opensl.h"
129 #endif
130 #ifdef HAVE_OBOE
131 #include "backends/oboe.h"
132 #endif
133 #ifdef HAVE_SOLARIS
134 #include "backends/solaris.h"
135 #endif
136 #ifdef HAVE_SNDIO
137 #include "backends/sndio.h"
138 #endif
139 #ifdef HAVE_OSS
140 #include "backends/oss.h"
141 #endif
142 #ifdef HAVE_DSOUND
143 #include "backends/dsound.h"
144 #endif
145 #ifdef HAVE_WINMM
146 #include "backends/winmm.h"
147 #endif
148 #ifdef HAVE_PORTAUDIO
149 #include "backends/portaudio.h"
150 #endif
151 #ifdef HAVE_SDL2
152 #include "backends/sdl2.h"
153 #endif
154 #ifdef HAVE_WAVE
155 #include "backends/wave.h"
156 #endif
158 #ifdef ALSOFT_EAX
159 #include "al/eax_globals.h"
160 #include "al/eax_x_ram.h"
161 #endif // ALSOFT_EAX
164 FILE *gLogFile{stderr};
165 #ifdef _DEBUG
166 LogLevel gLogLevel{LogLevel::Warning};
167 #else
168 LogLevel gLogLevel{LogLevel::Error};
169 #endif
171 /************************************************
172 * Library initialization
173 ************************************************/
174 #if defined(_WIN32) && !defined(AL_LIBTYPE_STATIC)
175 BOOL APIENTRY DllMain(HINSTANCE module, DWORD reason, LPVOID /*reserved*/)
177 switch(reason)
179 case DLL_PROCESS_ATTACH:
180 /* Pin the DLL so we won't get unloaded until the process terminates */
181 GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
182 reinterpret_cast<WCHAR*>(module), &module);
183 break;
185 return TRUE;
187 #endif
189 namespace {
191 using namespace std::placeholders;
192 using std::chrono::seconds;
193 using std::chrono::nanoseconds;
195 using voidp = void*;
196 using float2 = std::array<float,2>;
199 /************************************************
200 * Backends
201 ************************************************/
202 struct BackendInfo {
203 const char *name;
204 BackendFactory& (*getFactory)(void);
207 BackendInfo BackendList[] = {
208 #ifdef HAVE_PIPEWIRE
209 { "pipewire", PipeWireBackendFactory::getFactory },
210 #endif
211 #ifdef HAVE_PULSEAUDIO
212 { "pulse", PulseBackendFactory::getFactory },
213 #endif
214 #ifdef HAVE_WASAPI
215 { "wasapi", WasapiBackendFactory::getFactory },
216 #endif
217 #ifdef HAVE_COREAUDIO
218 { "core", CoreAudioBackendFactory::getFactory },
219 #endif
220 #ifdef HAVE_OBOE
221 { "oboe", OboeBackendFactory::getFactory },
222 #endif
223 #ifdef HAVE_OPENSL
224 { "opensl", OSLBackendFactory::getFactory },
225 #endif
226 #ifdef HAVE_SOLARIS
227 { "solaris", SolarisBackendFactory::getFactory },
228 #endif
229 #ifdef HAVE_SNDIO
230 { "sndio", SndIOBackendFactory::getFactory },
231 #endif
232 #ifdef HAVE_ALSA
233 { "alsa", AlsaBackendFactory::getFactory },
234 #endif
235 #ifdef HAVE_OSS
236 { "oss", OSSBackendFactory::getFactory },
237 #endif
238 #ifdef HAVE_JACK
239 { "jack", JackBackendFactory::getFactory },
240 #endif
241 #ifdef HAVE_DSOUND
242 { "dsound", DSoundBackendFactory::getFactory },
243 #endif
244 #ifdef HAVE_WINMM
245 { "winmm", WinMMBackendFactory::getFactory },
246 #endif
247 #ifdef HAVE_PORTAUDIO
248 { "port", PortBackendFactory::getFactory },
249 #endif
250 #ifdef HAVE_SDL2
251 { "sdl2", SDL2BackendFactory::getFactory },
252 #endif
254 { "null", NullBackendFactory::getFactory },
255 #ifdef HAVE_WAVE
256 { "wave", WaveBackendFactory::getFactory },
257 #endif
260 BackendFactory *PlaybackFactory{};
261 BackendFactory *CaptureFactory{};
264 /************************************************
265 * Functions, enums, and errors
266 ************************************************/
267 #define DECL(x) { #x, reinterpret_cast<void*>(x) }
268 const struct {
269 const char *funcName;
270 void *address;
271 } alcFunctions[] = {
272 DECL(alcCreateContext),
273 DECL(alcMakeContextCurrent),
274 DECL(alcProcessContext),
275 DECL(alcSuspendContext),
276 DECL(alcDestroyContext),
277 DECL(alcGetCurrentContext),
278 DECL(alcGetContextsDevice),
279 DECL(alcOpenDevice),
280 DECL(alcCloseDevice),
281 DECL(alcGetError),
282 DECL(alcIsExtensionPresent),
283 DECL(alcGetProcAddress),
284 DECL(alcGetEnumValue),
285 DECL(alcGetString),
286 DECL(alcGetIntegerv),
287 DECL(alcCaptureOpenDevice),
288 DECL(alcCaptureCloseDevice),
289 DECL(alcCaptureStart),
290 DECL(alcCaptureStop),
291 DECL(alcCaptureSamples),
293 DECL(alcSetThreadContext),
294 DECL(alcGetThreadContext),
296 DECL(alcLoopbackOpenDeviceSOFT),
297 DECL(alcIsRenderFormatSupportedSOFT),
298 DECL(alcRenderSamplesSOFT),
300 DECL(alcDevicePauseSOFT),
301 DECL(alcDeviceResumeSOFT),
303 DECL(alcGetStringiSOFT),
304 DECL(alcResetDeviceSOFT),
306 DECL(alcGetInteger64vSOFT),
308 DECL(alcReopenDeviceSOFT),
310 DECL(alEnable),
311 DECL(alDisable),
312 DECL(alIsEnabled),
313 DECL(alGetString),
314 DECL(alGetBooleanv),
315 DECL(alGetIntegerv),
316 DECL(alGetFloatv),
317 DECL(alGetDoublev),
318 DECL(alGetBoolean),
319 DECL(alGetInteger),
320 DECL(alGetFloat),
321 DECL(alGetDouble),
322 DECL(alGetError),
323 DECL(alIsExtensionPresent),
324 DECL(alGetProcAddress),
325 DECL(alGetEnumValue),
326 DECL(alListenerf),
327 DECL(alListener3f),
328 DECL(alListenerfv),
329 DECL(alListeneri),
330 DECL(alListener3i),
331 DECL(alListeneriv),
332 DECL(alGetListenerf),
333 DECL(alGetListener3f),
334 DECL(alGetListenerfv),
335 DECL(alGetListeneri),
336 DECL(alGetListener3i),
337 DECL(alGetListeneriv),
338 DECL(alGenSources),
339 DECL(alDeleteSources),
340 DECL(alIsSource),
341 DECL(alSourcef),
342 DECL(alSource3f),
343 DECL(alSourcefv),
344 DECL(alSourcei),
345 DECL(alSource3i),
346 DECL(alSourceiv),
347 DECL(alGetSourcef),
348 DECL(alGetSource3f),
349 DECL(alGetSourcefv),
350 DECL(alGetSourcei),
351 DECL(alGetSource3i),
352 DECL(alGetSourceiv),
353 DECL(alSourcePlayv),
354 DECL(alSourceStopv),
355 DECL(alSourceRewindv),
356 DECL(alSourcePausev),
357 DECL(alSourcePlay),
358 DECL(alSourceStop),
359 DECL(alSourceRewind),
360 DECL(alSourcePause),
361 DECL(alSourceQueueBuffers),
362 DECL(alSourceUnqueueBuffers),
363 DECL(alGenBuffers),
364 DECL(alDeleteBuffers),
365 DECL(alIsBuffer),
366 DECL(alBufferData),
367 DECL(alBufferf),
368 DECL(alBuffer3f),
369 DECL(alBufferfv),
370 DECL(alBufferi),
371 DECL(alBuffer3i),
372 DECL(alBufferiv),
373 DECL(alGetBufferf),
374 DECL(alGetBuffer3f),
375 DECL(alGetBufferfv),
376 DECL(alGetBufferi),
377 DECL(alGetBuffer3i),
378 DECL(alGetBufferiv),
379 DECL(alDopplerFactor),
380 DECL(alDopplerVelocity),
381 DECL(alSpeedOfSound),
382 DECL(alDistanceModel),
384 DECL(alGenFilters),
385 DECL(alDeleteFilters),
386 DECL(alIsFilter),
387 DECL(alFilteri),
388 DECL(alFilteriv),
389 DECL(alFilterf),
390 DECL(alFilterfv),
391 DECL(alGetFilteri),
392 DECL(alGetFilteriv),
393 DECL(alGetFilterf),
394 DECL(alGetFilterfv),
395 DECL(alGenEffects),
396 DECL(alDeleteEffects),
397 DECL(alIsEffect),
398 DECL(alEffecti),
399 DECL(alEffectiv),
400 DECL(alEffectf),
401 DECL(alEffectfv),
402 DECL(alGetEffecti),
403 DECL(alGetEffectiv),
404 DECL(alGetEffectf),
405 DECL(alGetEffectfv),
406 DECL(alGenAuxiliaryEffectSlots),
407 DECL(alDeleteAuxiliaryEffectSlots),
408 DECL(alIsAuxiliaryEffectSlot),
409 DECL(alAuxiliaryEffectSloti),
410 DECL(alAuxiliaryEffectSlotiv),
411 DECL(alAuxiliaryEffectSlotf),
412 DECL(alAuxiliaryEffectSlotfv),
413 DECL(alGetAuxiliaryEffectSloti),
414 DECL(alGetAuxiliaryEffectSlotiv),
415 DECL(alGetAuxiliaryEffectSlotf),
416 DECL(alGetAuxiliaryEffectSlotfv),
418 DECL(alDeferUpdatesSOFT),
419 DECL(alProcessUpdatesSOFT),
421 DECL(alSourcedSOFT),
422 DECL(alSource3dSOFT),
423 DECL(alSourcedvSOFT),
424 DECL(alGetSourcedSOFT),
425 DECL(alGetSource3dSOFT),
426 DECL(alGetSourcedvSOFT),
427 DECL(alSourcei64SOFT),
428 DECL(alSource3i64SOFT),
429 DECL(alSourcei64vSOFT),
430 DECL(alGetSourcei64SOFT),
431 DECL(alGetSource3i64SOFT),
432 DECL(alGetSourcei64vSOFT),
434 DECL(alGetStringiSOFT),
436 DECL(alBufferStorageSOFT),
437 DECL(alMapBufferSOFT),
438 DECL(alUnmapBufferSOFT),
439 DECL(alFlushMappedBufferSOFT),
441 DECL(alEventControlSOFT),
442 DECL(alEventCallbackSOFT),
443 DECL(alGetPointerSOFT),
444 DECL(alGetPointervSOFT),
446 DECL(alBufferCallbackSOFT),
447 DECL(alGetBufferPtrSOFT),
448 DECL(alGetBuffer3PtrSOFT),
449 DECL(alGetBufferPtrvSOFT),
451 DECL(alAuxiliaryEffectSlotPlaySOFT),
452 DECL(alAuxiliaryEffectSlotPlayvSOFT),
453 DECL(alAuxiliaryEffectSlotStopSOFT),
454 DECL(alAuxiliaryEffectSlotStopvSOFT),
455 #ifdef ALSOFT_EAX
456 }, eaxFunctions[] = {
457 DECL(EAXGet),
458 DECL(EAXSet),
459 DECL(EAXGetBufferMode),
460 DECL(EAXSetBufferMode),
461 #endif
463 #undef DECL
465 #define DECL(x) { #x, (x) }
466 constexpr struct {
467 const ALCchar *enumName;
468 ALCenum value;
469 } alcEnumerations[] = {
470 DECL(ALC_INVALID),
471 DECL(ALC_FALSE),
472 DECL(ALC_TRUE),
474 DECL(ALC_MAJOR_VERSION),
475 DECL(ALC_MINOR_VERSION),
476 DECL(ALC_ATTRIBUTES_SIZE),
477 DECL(ALC_ALL_ATTRIBUTES),
478 DECL(ALC_DEFAULT_DEVICE_SPECIFIER),
479 DECL(ALC_DEVICE_SPECIFIER),
480 DECL(ALC_ALL_DEVICES_SPECIFIER),
481 DECL(ALC_DEFAULT_ALL_DEVICES_SPECIFIER),
482 DECL(ALC_EXTENSIONS),
483 DECL(ALC_FREQUENCY),
484 DECL(ALC_REFRESH),
485 DECL(ALC_SYNC),
486 DECL(ALC_MONO_SOURCES),
487 DECL(ALC_STEREO_SOURCES),
488 DECL(ALC_CAPTURE_DEVICE_SPECIFIER),
489 DECL(ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER),
490 DECL(ALC_CAPTURE_SAMPLES),
491 DECL(ALC_CONNECTED),
493 DECL(ALC_EFX_MAJOR_VERSION),
494 DECL(ALC_EFX_MINOR_VERSION),
495 DECL(ALC_MAX_AUXILIARY_SENDS),
497 DECL(ALC_FORMAT_CHANNELS_SOFT),
498 DECL(ALC_FORMAT_TYPE_SOFT),
500 DECL(ALC_MONO_SOFT),
501 DECL(ALC_STEREO_SOFT),
502 DECL(ALC_QUAD_SOFT),
503 DECL(ALC_5POINT1_SOFT),
504 DECL(ALC_6POINT1_SOFT),
505 DECL(ALC_7POINT1_SOFT),
506 DECL(ALC_BFORMAT3D_SOFT),
508 DECL(ALC_BYTE_SOFT),
509 DECL(ALC_UNSIGNED_BYTE_SOFT),
510 DECL(ALC_SHORT_SOFT),
511 DECL(ALC_UNSIGNED_SHORT_SOFT),
512 DECL(ALC_INT_SOFT),
513 DECL(ALC_UNSIGNED_INT_SOFT),
514 DECL(ALC_FLOAT_SOFT),
516 DECL(ALC_HRTF_SOFT),
517 DECL(ALC_DONT_CARE_SOFT),
518 DECL(ALC_HRTF_STATUS_SOFT),
519 DECL(ALC_HRTF_DISABLED_SOFT),
520 DECL(ALC_HRTF_ENABLED_SOFT),
521 DECL(ALC_HRTF_DENIED_SOFT),
522 DECL(ALC_HRTF_REQUIRED_SOFT),
523 DECL(ALC_HRTF_HEADPHONES_DETECTED_SOFT),
524 DECL(ALC_HRTF_UNSUPPORTED_FORMAT_SOFT),
525 DECL(ALC_NUM_HRTF_SPECIFIERS_SOFT),
526 DECL(ALC_HRTF_SPECIFIER_SOFT),
527 DECL(ALC_HRTF_ID_SOFT),
529 DECL(ALC_AMBISONIC_LAYOUT_SOFT),
530 DECL(ALC_AMBISONIC_SCALING_SOFT),
531 DECL(ALC_AMBISONIC_ORDER_SOFT),
532 DECL(ALC_ACN_SOFT),
533 DECL(ALC_FUMA_SOFT),
534 DECL(ALC_N3D_SOFT),
535 DECL(ALC_SN3D_SOFT),
537 DECL(ALC_OUTPUT_LIMITER_SOFT),
539 DECL(ALC_OUTPUT_MODE_SOFT),
540 DECL(ALC_NORMAL_SOFT),
541 DECL(ALC_STEREO_UHJ_SOFT),
542 DECL(ALC_ANY_SOFT),
544 DECL(ALC_NO_ERROR),
545 DECL(ALC_INVALID_DEVICE),
546 DECL(ALC_INVALID_CONTEXT),
547 DECL(ALC_INVALID_ENUM),
548 DECL(ALC_INVALID_VALUE),
549 DECL(ALC_OUT_OF_MEMORY),
552 DECL(AL_INVALID),
553 DECL(AL_NONE),
554 DECL(AL_FALSE),
555 DECL(AL_TRUE),
557 DECL(AL_SOURCE_RELATIVE),
558 DECL(AL_CONE_INNER_ANGLE),
559 DECL(AL_CONE_OUTER_ANGLE),
560 DECL(AL_PITCH),
561 DECL(AL_POSITION),
562 DECL(AL_DIRECTION),
563 DECL(AL_VELOCITY),
564 DECL(AL_LOOPING),
565 DECL(AL_BUFFER),
566 DECL(AL_GAIN),
567 DECL(AL_MIN_GAIN),
568 DECL(AL_MAX_GAIN),
569 DECL(AL_ORIENTATION),
570 DECL(AL_REFERENCE_DISTANCE),
571 DECL(AL_ROLLOFF_FACTOR),
572 DECL(AL_CONE_OUTER_GAIN),
573 DECL(AL_MAX_DISTANCE),
574 DECL(AL_SEC_OFFSET),
575 DECL(AL_SAMPLE_OFFSET),
576 DECL(AL_BYTE_OFFSET),
577 DECL(AL_SOURCE_TYPE),
578 DECL(AL_STATIC),
579 DECL(AL_STREAMING),
580 DECL(AL_UNDETERMINED),
581 DECL(AL_METERS_PER_UNIT),
582 DECL(AL_LOOP_POINTS_SOFT),
583 DECL(AL_DIRECT_CHANNELS_SOFT),
585 DECL(AL_DIRECT_FILTER),
586 DECL(AL_AUXILIARY_SEND_FILTER),
587 DECL(AL_AIR_ABSORPTION_FACTOR),
588 DECL(AL_ROOM_ROLLOFF_FACTOR),
589 DECL(AL_CONE_OUTER_GAINHF),
590 DECL(AL_DIRECT_FILTER_GAINHF_AUTO),
591 DECL(AL_AUXILIARY_SEND_FILTER_GAIN_AUTO),
592 DECL(AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO),
594 DECL(AL_SOURCE_STATE),
595 DECL(AL_INITIAL),
596 DECL(AL_PLAYING),
597 DECL(AL_PAUSED),
598 DECL(AL_STOPPED),
600 DECL(AL_BUFFERS_QUEUED),
601 DECL(AL_BUFFERS_PROCESSED),
603 DECL(AL_FORMAT_MONO8),
604 DECL(AL_FORMAT_MONO16),
605 DECL(AL_FORMAT_MONO_FLOAT32),
606 DECL(AL_FORMAT_MONO_DOUBLE_EXT),
607 DECL(AL_FORMAT_STEREO8),
608 DECL(AL_FORMAT_STEREO16),
609 DECL(AL_FORMAT_STEREO_FLOAT32),
610 DECL(AL_FORMAT_STEREO_DOUBLE_EXT),
611 DECL(AL_FORMAT_MONO_IMA4),
612 DECL(AL_FORMAT_STEREO_IMA4),
613 DECL(AL_FORMAT_MONO_MSADPCM_SOFT),
614 DECL(AL_FORMAT_STEREO_MSADPCM_SOFT),
615 DECL(AL_FORMAT_QUAD8_LOKI),
616 DECL(AL_FORMAT_QUAD16_LOKI),
617 DECL(AL_FORMAT_QUAD8),
618 DECL(AL_FORMAT_QUAD16),
619 DECL(AL_FORMAT_QUAD32),
620 DECL(AL_FORMAT_51CHN8),
621 DECL(AL_FORMAT_51CHN16),
622 DECL(AL_FORMAT_51CHN32),
623 DECL(AL_FORMAT_61CHN8),
624 DECL(AL_FORMAT_61CHN16),
625 DECL(AL_FORMAT_61CHN32),
626 DECL(AL_FORMAT_71CHN8),
627 DECL(AL_FORMAT_71CHN16),
628 DECL(AL_FORMAT_71CHN32),
629 DECL(AL_FORMAT_REAR8),
630 DECL(AL_FORMAT_REAR16),
631 DECL(AL_FORMAT_REAR32),
632 DECL(AL_FORMAT_MONO_MULAW),
633 DECL(AL_FORMAT_MONO_MULAW_EXT),
634 DECL(AL_FORMAT_STEREO_MULAW),
635 DECL(AL_FORMAT_STEREO_MULAW_EXT),
636 DECL(AL_FORMAT_QUAD_MULAW),
637 DECL(AL_FORMAT_51CHN_MULAW),
638 DECL(AL_FORMAT_61CHN_MULAW),
639 DECL(AL_FORMAT_71CHN_MULAW),
640 DECL(AL_FORMAT_REAR_MULAW),
641 DECL(AL_FORMAT_MONO_ALAW_EXT),
642 DECL(AL_FORMAT_STEREO_ALAW_EXT),
644 DECL(AL_FORMAT_BFORMAT2D_8),
645 DECL(AL_FORMAT_BFORMAT2D_16),
646 DECL(AL_FORMAT_BFORMAT2D_FLOAT32),
647 DECL(AL_FORMAT_BFORMAT2D_MULAW),
648 DECL(AL_FORMAT_BFORMAT3D_8),
649 DECL(AL_FORMAT_BFORMAT3D_16),
650 DECL(AL_FORMAT_BFORMAT3D_FLOAT32),
651 DECL(AL_FORMAT_BFORMAT3D_MULAW),
653 DECL(AL_FREQUENCY),
654 DECL(AL_BITS),
655 DECL(AL_CHANNELS),
656 DECL(AL_SIZE),
657 DECL(AL_UNPACK_BLOCK_ALIGNMENT_SOFT),
658 DECL(AL_PACK_BLOCK_ALIGNMENT_SOFT),
660 DECL(AL_SOURCE_RADIUS),
662 DECL(AL_STEREO_ANGLES),
664 DECL(AL_UNUSED),
665 DECL(AL_PENDING),
666 DECL(AL_PROCESSED),
668 DECL(AL_NO_ERROR),
669 DECL(AL_INVALID_NAME),
670 DECL(AL_INVALID_ENUM),
671 DECL(AL_INVALID_VALUE),
672 DECL(AL_INVALID_OPERATION),
673 DECL(AL_OUT_OF_MEMORY),
675 DECL(AL_VENDOR),
676 DECL(AL_VERSION),
677 DECL(AL_RENDERER),
678 DECL(AL_EXTENSIONS),
680 DECL(AL_DOPPLER_FACTOR),
681 DECL(AL_DOPPLER_VELOCITY),
682 DECL(AL_DISTANCE_MODEL),
683 DECL(AL_SPEED_OF_SOUND),
684 DECL(AL_SOURCE_DISTANCE_MODEL),
685 DECL(AL_DEFERRED_UPDATES_SOFT),
686 DECL(AL_GAIN_LIMIT_SOFT),
688 DECL(AL_INVERSE_DISTANCE),
689 DECL(AL_INVERSE_DISTANCE_CLAMPED),
690 DECL(AL_LINEAR_DISTANCE),
691 DECL(AL_LINEAR_DISTANCE_CLAMPED),
692 DECL(AL_EXPONENT_DISTANCE),
693 DECL(AL_EXPONENT_DISTANCE_CLAMPED),
695 DECL(AL_FILTER_TYPE),
696 DECL(AL_FILTER_NULL),
697 DECL(AL_FILTER_LOWPASS),
698 DECL(AL_FILTER_HIGHPASS),
699 DECL(AL_FILTER_BANDPASS),
701 DECL(AL_LOWPASS_GAIN),
702 DECL(AL_LOWPASS_GAINHF),
704 DECL(AL_HIGHPASS_GAIN),
705 DECL(AL_HIGHPASS_GAINLF),
707 DECL(AL_BANDPASS_GAIN),
708 DECL(AL_BANDPASS_GAINHF),
709 DECL(AL_BANDPASS_GAINLF),
711 DECL(AL_EFFECT_TYPE),
712 DECL(AL_EFFECT_NULL),
713 DECL(AL_EFFECT_REVERB),
714 DECL(AL_EFFECT_EAXREVERB),
715 DECL(AL_EFFECT_CHORUS),
716 DECL(AL_EFFECT_DISTORTION),
717 DECL(AL_EFFECT_ECHO),
718 DECL(AL_EFFECT_FLANGER),
719 DECL(AL_EFFECT_PITCH_SHIFTER),
720 DECL(AL_EFFECT_FREQUENCY_SHIFTER),
721 DECL(AL_EFFECT_VOCAL_MORPHER),
722 DECL(AL_EFFECT_RING_MODULATOR),
723 DECL(AL_EFFECT_AUTOWAH),
724 DECL(AL_EFFECT_COMPRESSOR),
725 DECL(AL_EFFECT_EQUALIZER),
726 DECL(AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT),
727 DECL(AL_EFFECT_DEDICATED_DIALOGUE),
729 DECL(AL_EFFECTSLOT_EFFECT),
730 DECL(AL_EFFECTSLOT_GAIN),
731 DECL(AL_EFFECTSLOT_AUXILIARY_SEND_AUTO),
732 DECL(AL_EFFECTSLOT_NULL),
734 DECL(AL_EAXREVERB_DENSITY),
735 DECL(AL_EAXREVERB_DIFFUSION),
736 DECL(AL_EAXREVERB_GAIN),
737 DECL(AL_EAXREVERB_GAINHF),
738 DECL(AL_EAXREVERB_GAINLF),
739 DECL(AL_EAXREVERB_DECAY_TIME),
740 DECL(AL_EAXREVERB_DECAY_HFRATIO),
741 DECL(AL_EAXREVERB_DECAY_LFRATIO),
742 DECL(AL_EAXREVERB_REFLECTIONS_GAIN),
743 DECL(AL_EAXREVERB_REFLECTIONS_DELAY),
744 DECL(AL_EAXREVERB_REFLECTIONS_PAN),
745 DECL(AL_EAXREVERB_LATE_REVERB_GAIN),
746 DECL(AL_EAXREVERB_LATE_REVERB_DELAY),
747 DECL(AL_EAXREVERB_LATE_REVERB_PAN),
748 DECL(AL_EAXREVERB_ECHO_TIME),
749 DECL(AL_EAXREVERB_ECHO_DEPTH),
750 DECL(AL_EAXREVERB_MODULATION_TIME),
751 DECL(AL_EAXREVERB_MODULATION_DEPTH),
752 DECL(AL_EAXREVERB_AIR_ABSORPTION_GAINHF),
753 DECL(AL_EAXREVERB_HFREFERENCE),
754 DECL(AL_EAXREVERB_LFREFERENCE),
755 DECL(AL_EAXREVERB_ROOM_ROLLOFF_FACTOR),
756 DECL(AL_EAXREVERB_DECAY_HFLIMIT),
758 DECL(AL_REVERB_DENSITY),
759 DECL(AL_REVERB_DIFFUSION),
760 DECL(AL_REVERB_GAIN),
761 DECL(AL_REVERB_GAINHF),
762 DECL(AL_REVERB_DECAY_TIME),
763 DECL(AL_REVERB_DECAY_HFRATIO),
764 DECL(AL_REVERB_REFLECTIONS_GAIN),
765 DECL(AL_REVERB_REFLECTIONS_DELAY),
766 DECL(AL_REVERB_LATE_REVERB_GAIN),
767 DECL(AL_REVERB_LATE_REVERB_DELAY),
768 DECL(AL_REVERB_AIR_ABSORPTION_GAINHF),
769 DECL(AL_REVERB_ROOM_ROLLOFF_FACTOR),
770 DECL(AL_REVERB_DECAY_HFLIMIT),
772 DECL(AL_CHORUS_WAVEFORM),
773 DECL(AL_CHORUS_PHASE),
774 DECL(AL_CHORUS_RATE),
775 DECL(AL_CHORUS_DEPTH),
776 DECL(AL_CHORUS_FEEDBACK),
777 DECL(AL_CHORUS_DELAY),
779 DECL(AL_DISTORTION_EDGE),
780 DECL(AL_DISTORTION_GAIN),
781 DECL(AL_DISTORTION_LOWPASS_CUTOFF),
782 DECL(AL_DISTORTION_EQCENTER),
783 DECL(AL_DISTORTION_EQBANDWIDTH),
785 DECL(AL_ECHO_DELAY),
786 DECL(AL_ECHO_LRDELAY),
787 DECL(AL_ECHO_DAMPING),
788 DECL(AL_ECHO_FEEDBACK),
789 DECL(AL_ECHO_SPREAD),
791 DECL(AL_FLANGER_WAVEFORM),
792 DECL(AL_FLANGER_PHASE),
793 DECL(AL_FLANGER_RATE),
794 DECL(AL_FLANGER_DEPTH),
795 DECL(AL_FLANGER_FEEDBACK),
796 DECL(AL_FLANGER_DELAY),
798 DECL(AL_FREQUENCY_SHIFTER_FREQUENCY),
799 DECL(AL_FREQUENCY_SHIFTER_LEFT_DIRECTION),
800 DECL(AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION),
802 DECL(AL_RING_MODULATOR_FREQUENCY),
803 DECL(AL_RING_MODULATOR_HIGHPASS_CUTOFF),
804 DECL(AL_RING_MODULATOR_WAVEFORM),
806 DECL(AL_PITCH_SHIFTER_COARSE_TUNE),
807 DECL(AL_PITCH_SHIFTER_FINE_TUNE),
809 DECL(AL_COMPRESSOR_ONOFF),
811 DECL(AL_EQUALIZER_LOW_GAIN),
812 DECL(AL_EQUALIZER_LOW_CUTOFF),
813 DECL(AL_EQUALIZER_MID1_GAIN),
814 DECL(AL_EQUALIZER_MID1_CENTER),
815 DECL(AL_EQUALIZER_MID1_WIDTH),
816 DECL(AL_EQUALIZER_MID2_GAIN),
817 DECL(AL_EQUALIZER_MID2_CENTER),
818 DECL(AL_EQUALIZER_MID2_WIDTH),
819 DECL(AL_EQUALIZER_HIGH_GAIN),
820 DECL(AL_EQUALIZER_HIGH_CUTOFF),
822 DECL(AL_DEDICATED_GAIN),
824 DECL(AL_AUTOWAH_ATTACK_TIME),
825 DECL(AL_AUTOWAH_RELEASE_TIME),
826 DECL(AL_AUTOWAH_RESONANCE),
827 DECL(AL_AUTOWAH_PEAK_GAIN),
829 DECL(AL_VOCAL_MORPHER_PHONEMEA),
830 DECL(AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING),
831 DECL(AL_VOCAL_MORPHER_PHONEMEB),
832 DECL(AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING),
833 DECL(AL_VOCAL_MORPHER_WAVEFORM),
834 DECL(AL_VOCAL_MORPHER_RATE),
836 DECL(AL_EFFECTSLOT_TARGET_SOFT),
838 DECL(AL_NUM_RESAMPLERS_SOFT),
839 DECL(AL_DEFAULT_RESAMPLER_SOFT),
840 DECL(AL_SOURCE_RESAMPLER_SOFT),
841 DECL(AL_RESAMPLER_NAME_SOFT),
843 DECL(AL_SOURCE_SPATIALIZE_SOFT),
844 DECL(AL_AUTO_SOFT),
846 DECL(AL_MAP_READ_BIT_SOFT),
847 DECL(AL_MAP_WRITE_BIT_SOFT),
848 DECL(AL_MAP_PERSISTENT_BIT_SOFT),
849 DECL(AL_PRESERVE_DATA_BIT_SOFT),
851 DECL(AL_EVENT_CALLBACK_FUNCTION_SOFT),
852 DECL(AL_EVENT_CALLBACK_USER_PARAM_SOFT),
853 DECL(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT),
854 DECL(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT),
855 DECL(AL_EVENT_TYPE_DISCONNECTED_SOFT),
857 DECL(AL_DROP_UNMATCHED_SOFT),
858 DECL(AL_REMIX_UNMATCHED_SOFT),
860 DECL(AL_AMBISONIC_LAYOUT_SOFT),
861 DECL(AL_AMBISONIC_SCALING_SOFT),
862 DECL(AL_FUMA_SOFT),
863 DECL(AL_ACN_SOFT),
864 DECL(AL_SN3D_SOFT),
865 DECL(AL_N3D_SOFT),
867 DECL(AL_BUFFER_CALLBACK_FUNCTION_SOFT),
868 DECL(AL_BUFFER_CALLBACK_USER_PARAM_SOFT),
870 DECL(AL_UNPACK_AMBISONIC_ORDER_SOFT),
872 DECL(AL_EFFECT_CONVOLUTION_REVERB_SOFT),
873 DECL(AL_EFFECTSLOT_STATE_SOFT),
875 DECL(AL_FORMAT_UHJ2CHN8_SOFT),
876 DECL(AL_FORMAT_UHJ2CHN16_SOFT),
877 DECL(AL_FORMAT_UHJ2CHN_FLOAT32_SOFT),
878 DECL(AL_FORMAT_UHJ3CHN8_SOFT),
879 DECL(AL_FORMAT_UHJ3CHN16_SOFT),
880 DECL(AL_FORMAT_UHJ3CHN_FLOAT32_SOFT),
881 DECL(AL_FORMAT_UHJ4CHN8_SOFT),
882 DECL(AL_FORMAT_UHJ4CHN16_SOFT),
883 DECL(AL_FORMAT_UHJ4CHN_FLOAT32_SOFT),
884 DECL(AL_STEREO_MODE_SOFT),
885 DECL(AL_NORMAL_SOFT),
886 DECL(AL_SUPER_STEREO_SOFT),
887 DECL(AL_SUPER_STEREO_WIDTH_SOFT),
889 DECL(AL_STOP_SOURCES_ON_DISCONNECT_SOFT),
891 #ifdef ALSOFT_EAX
892 }, eaxEnumerations[] = {
893 DECL(AL_EAX_RAM_SIZE),
894 DECL(AL_EAX_RAM_FREE),
895 DECL(AL_STORAGE_AUTOMATIC),
896 DECL(AL_STORAGE_HARDWARE),
897 DECL(AL_STORAGE_ACCESSIBLE),
898 #endif // ALSOFT_EAX
900 #undef DECL
902 constexpr ALCchar alcNoError[] = "No Error";
903 constexpr ALCchar alcErrInvalidDevice[] = "Invalid Device";
904 constexpr ALCchar alcErrInvalidContext[] = "Invalid Context";
905 constexpr ALCchar alcErrInvalidEnum[] = "Invalid Enum";
906 constexpr ALCchar alcErrInvalidValue[] = "Invalid Value";
907 constexpr ALCchar alcErrOutOfMemory[] = "Out of Memory";
910 /************************************************
911 * Global variables
912 ************************************************/
914 /* Enumerated device names */
915 constexpr ALCchar alcDefaultName[] = "OpenAL Soft\0";
917 std::string alcAllDevicesList;
918 std::string alcCaptureDeviceList;
920 /* Default is always the first in the list */
921 std::string alcDefaultAllDevicesSpecifier;
922 std::string alcCaptureDefaultDeviceSpecifier;
924 std::atomic<ALCenum> LastNullDeviceError{ALC_NO_ERROR};
926 /* Flag to trap ALC device errors */
927 bool TrapALCError{false};
929 /* One-time configuration init control */
930 std::once_flag alc_config_once{};
932 /* Flag to specify if alcSuspendContext/alcProcessContext should defer/process
933 * updates.
935 bool SuspendDefers{true};
937 /* Initial seed for dithering. */
938 constexpr uint DitherRNGSeed{22222u};
941 /************************************************
942 * ALC information
943 ************************************************/
944 constexpr ALCchar alcNoDeviceExtList[] =
945 "ALC_ENUMERATE_ALL_EXT "
946 "ALC_ENUMERATION_EXT "
947 "ALC_EXT_CAPTURE "
948 "ALC_EXT_EFX "
949 "ALC_EXT_thread_local_context "
950 "ALC_SOFT_loopback "
951 "ALC_SOFT_loopback_bformat "
952 "ALC_SOFTX_reopen_device";
953 constexpr ALCchar alcExtensionList[] =
954 "ALC_ENUMERATE_ALL_EXT "
955 "ALC_ENUMERATION_EXT "
956 "ALC_EXT_CAPTURE "
957 "ALC_EXT_DEDICATED "
958 "ALC_EXT_disconnect "
959 "ALC_EXT_EFX "
960 "ALC_EXT_thread_local_context "
961 "ALC_SOFT_device_clock "
962 "ALC_SOFT_HRTF "
963 "ALC_SOFT_loopback "
964 "ALC_SOFT_loopback_bformat "
965 "ALC_SOFT_output_limiter "
966 "ALC_SOFTX_output_mode "
967 "ALC_SOFT_pause_device "
968 "ALC_SOFTX_reopen_device";
969 constexpr int alcMajorVersion{1};
970 constexpr int alcMinorVersion{1};
972 constexpr int alcEFXMajorVersion{1};
973 constexpr int alcEFXMinorVersion{0};
976 using DeviceRef = al::intrusive_ptr<ALCdevice>;
979 /************************************************
980 * Device lists
981 ************************************************/
982 al::vector<ALCdevice*> DeviceList;
983 al::vector<ALCcontext*> ContextList;
985 std::recursive_mutex ListLock;
988 void alc_initconfig(void)
990 if(auto loglevel = al::getenv("ALSOFT_LOGLEVEL"))
992 long lvl = strtol(loglevel->c_str(), nullptr, 0);
993 if(lvl >= static_cast<long>(LogLevel::Trace))
994 gLogLevel = LogLevel::Trace;
995 else if(lvl <= static_cast<long>(LogLevel::Disable))
996 gLogLevel = LogLevel::Disable;
997 else
998 gLogLevel = static_cast<LogLevel>(lvl);
1001 #ifdef _WIN32
1002 if(const auto logfile = al::getenv(L"ALSOFT_LOGFILE"))
1004 FILE *logf{_wfopen(logfile->c_str(), L"wt")};
1005 if(logf) gLogFile = logf;
1006 else
1008 auto u8name = wstr_to_utf8(logfile->c_str());
1009 ERR("Failed to open log file '%s'\n", u8name.c_str());
1012 #else
1013 if(const auto logfile = al::getenv("ALSOFT_LOGFILE"))
1015 FILE *logf{fopen(logfile->c_str(), "wt")};
1016 if(logf) gLogFile = logf;
1017 else ERR("Failed to open log file '%s'\n", logfile->c_str());
1019 #endif
1021 TRACE("Initializing library v%s-%s %s\n", ALSOFT_VERSION, ALSOFT_GIT_COMMIT_HASH,
1022 ALSOFT_GIT_BRANCH);
1024 std::string names;
1025 if(al::size(BackendList) < 1)
1026 names = "(none)";
1027 else
1029 const al::span<const BackendInfo> infos{BackendList};
1030 names = infos[0].name;
1031 for(const auto &backend : infos.subspan<1>())
1033 names += ", ";
1034 names += backend.name;
1037 TRACE("Supported backends: %s\n", names.c_str());
1039 ReadALConfig();
1041 if(auto suspendmode = al::getenv("__ALSOFT_SUSPEND_CONTEXT"))
1043 if(al::strcasecmp(suspendmode->c_str(), "ignore") == 0)
1045 SuspendDefers = false;
1046 TRACE("Selected context suspend behavior, \"ignore\"\n");
1048 else
1049 ERR("Unhandled context suspend behavior setting: \"%s\"\n", suspendmode->c_str());
1052 int capfilter{0};
1053 #if defined(HAVE_SSE4_1)
1054 capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3 | CPU_CAP_SSE4_1;
1055 #elif defined(HAVE_SSE3)
1056 capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3;
1057 #elif defined(HAVE_SSE2)
1058 capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2;
1059 #elif defined(HAVE_SSE)
1060 capfilter |= CPU_CAP_SSE;
1061 #endif
1062 #ifdef HAVE_NEON
1063 capfilter |= CPU_CAP_NEON;
1064 #endif
1065 if(auto cpuopt = ConfigValueStr(nullptr, nullptr, "disable-cpu-exts"))
1067 const char *str{cpuopt->c_str()};
1068 if(al::strcasecmp(str, "all") == 0)
1069 capfilter = 0;
1070 else
1072 const char *next = str;
1073 do {
1074 str = next;
1075 while(isspace(str[0]))
1076 str++;
1077 next = strchr(str, ',');
1079 if(!str[0] || str[0] == ',')
1080 continue;
1082 size_t len{next ? static_cast<size_t>(next-str) : strlen(str)};
1083 while(len > 0 && isspace(str[len-1]))
1084 len--;
1085 if(len == 3 && al::strncasecmp(str, "sse", len) == 0)
1086 capfilter &= ~CPU_CAP_SSE;
1087 else if(len == 4 && al::strncasecmp(str, "sse2", len) == 0)
1088 capfilter &= ~CPU_CAP_SSE2;
1089 else if(len == 4 && al::strncasecmp(str, "sse3", len) == 0)
1090 capfilter &= ~CPU_CAP_SSE3;
1091 else if(len == 6 && al::strncasecmp(str, "sse4.1", len) == 0)
1092 capfilter &= ~CPU_CAP_SSE4_1;
1093 else if(len == 4 && al::strncasecmp(str, "neon", len) == 0)
1094 capfilter &= ~CPU_CAP_NEON;
1095 else
1096 WARN("Invalid CPU extension \"%s\"\n", str);
1097 } while(next++);
1100 if(auto cpuopt = GetCPUInfo())
1102 if(!cpuopt->mVendor.empty() || !cpuopt->mName.empty())
1104 TRACE("Vendor ID: \"%s\"\n", cpuopt->mVendor.c_str());
1105 TRACE("Name: \"%s\"\n", cpuopt->mName.c_str());
1107 const int caps{cpuopt->mCaps};
1108 TRACE("Extensions:%s%s%s%s%s%s\n",
1109 ((capfilter&CPU_CAP_SSE) ? ((caps&CPU_CAP_SSE) ? " +SSE" : " -SSE") : ""),
1110 ((capfilter&CPU_CAP_SSE2) ? ((caps&CPU_CAP_SSE2) ? " +SSE2" : " -SSE2") : ""),
1111 ((capfilter&CPU_CAP_SSE3) ? ((caps&CPU_CAP_SSE3) ? " +SSE3" : " -SSE3") : ""),
1112 ((capfilter&CPU_CAP_SSE4_1) ? ((caps&CPU_CAP_SSE4_1) ? " +SSE4.1" : " -SSE4.1") : ""),
1113 ((capfilter&CPU_CAP_NEON) ? ((caps&CPU_CAP_NEON) ? " +NEON" : " -NEON") : ""),
1114 ((!capfilter) ? " -none-" : ""));
1115 CPUCapFlags = caps & capfilter;
1118 if(auto priopt = ConfigValueInt(nullptr, nullptr, "rt-prio"))
1119 RTPrioLevel = *priopt;
1120 if(auto limopt = ConfigValueBool(nullptr, nullptr, "rt-time-limit"))
1121 AllowRTTimeLimit = *limopt;
1123 aluInit();
1124 Voice::InitMixer(ConfigValueStr(nullptr, nullptr, "resampler"));
1126 auto traperr = al::getenv("ALSOFT_TRAP_ERROR");
1127 if(traperr && (al::strcasecmp(traperr->c_str(), "true") == 0
1128 || std::strtol(traperr->c_str(), nullptr, 0) == 1))
1130 TrapALError = true;
1131 TrapALCError = true;
1133 else
1135 traperr = al::getenv("ALSOFT_TRAP_AL_ERROR");
1136 if(traperr)
1137 TrapALError = al::strcasecmp(traperr->c_str(), "true") == 0
1138 || strtol(traperr->c_str(), nullptr, 0) == 1;
1139 else
1140 TrapALError = !!GetConfigValueBool(nullptr, nullptr, "trap-al-error", false);
1142 traperr = al::getenv("ALSOFT_TRAP_ALC_ERROR");
1143 if(traperr)
1144 TrapALCError = al::strcasecmp(traperr->c_str(), "true") == 0
1145 || strtol(traperr->c_str(), nullptr, 0) == 1;
1146 else
1147 TrapALCError = !!GetConfigValueBool(nullptr, nullptr, "trap-alc-error", false);
1150 if(auto boostopt = ConfigValueFloat(nullptr, "reverb", "boost"))
1152 const float valf{std::isfinite(*boostopt) ? clampf(*boostopt, -24.0f, 24.0f) : 0.0f};
1153 ReverbBoost *= std::pow(10.0f, valf / 20.0f);
1156 auto BackendListEnd = std::end(BackendList);
1157 auto devopt = al::getenv("ALSOFT_DRIVERS");
1158 if(devopt || (devopt=ConfigValueStr(nullptr, nullptr, "drivers")))
1160 auto backendlist_cur = std::begin(BackendList);
1162 bool endlist{true};
1163 const char *next{devopt->c_str()};
1164 do {
1165 const char *devs{next};
1166 while(isspace(devs[0]))
1167 devs++;
1168 next = strchr(devs, ',');
1170 const bool delitem{devs[0] == '-'};
1171 if(devs[0] == '-') devs++;
1173 if(!devs[0] || devs[0] == ',')
1175 endlist = false;
1176 continue;
1178 endlist = true;
1180 size_t len{next ? (static_cast<size_t>(next-devs)) : strlen(devs)};
1181 while(len > 0 && isspace(devs[len-1])) --len;
1182 #ifdef HAVE_WASAPI
1183 /* HACK: For backwards compatibility, convert backend references of
1184 * mmdevapi to wasapi. This should eventually be removed.
1186 if(len == 8 && strncmp(devs, "mmdevapi", len) == 0)
1188 devs = "wasapi";
1189 len = 6;
1191 #endif
1193 auto find_backend = [devs,len](const BackendInfo &backend) -> bool
1194 { return len == strlen(backend.name) && strncmp(backend.name, devs, len) == 0; };
1195 auto this_backend = std::find_if(std::begin(BackendList), BackendListEnd,
1196 find_backend);
1198 if(this_backend == BackendListEnd)
1199 continue;
1201 if(delitem)
1202 BackendListEnd = std::move(this_backend+1, BackendListEnd, this_backend);
1203 else
1204 backendlist_cur = std::rotate(backendlist_cur, this_backend, this_backend+1);
1205 } while(next++);
1207 if(endlist)
1208 BackendListEnd = backendlist_cur;
1211 auto init_backend = [](BackendInfo &backend) -> void
1213 if(PlaybackFactory && CaptureFactory)
1214 return;
1216 BackendFactory &factory = backend.getFactory();
1217 if(!factory.init())
1219 WARN("Failed to initialize backend \"%s\"\n", backend.name);
1220 return;
1223 TRACE("Initialized backend \"%s\"\n", backend.name);
1224 if(!PlaybackFactory && factory.querySupport(BackendType::Playback))
1226 PlaybackFactory = &factory;
1227 TRACE("Added \"%s\" for playback\n", backend.name);
1229 if(!CaptureFactory && factory.querySupport(BackendType::Capture))
1231 CaptureFactory = &factory;
1232 TRACE("Added \"%s\" for capture\n", backend.name);
1235 std::for_each(std::begin(BackendList), BackendListEnd, init_backend);
1237 LoopbackBackendFactory::getFactory().init();
1239 if(!PlaybackFactory)
1240 WARN("No playback backend available!\n");
1241 if(!CaptureFactory)
1242 WARN("No capture backend available!\n");
1244 if(auto exclopt = ConfigValueStr(nullptr, nullptr, "excludefx"))
1246 const char *next{exclopt->c_str()};
1247 do {
1248 const char *str{next};
1249 next = strchr(str, ',');
1251 if(!str[0] || next == str)
1252 continue;
1254 size_t len{next ? static_cast<size_t>(next-str) : strlen(str)};
1255 for(const EffectList &effectitem : gEffectList)
1257 if(len == strlen(effectitem.name) &&
1258 strncmp(effectitem.name, str, len) == 0)
1259 DisabledEffects[effectitem.type] = true;
1261 } while(next++);
1264 InitEffect(&ALCcontext::sDefaultEffect);
1265 auto defrevopt = al::getenv("ALSOFT_DEFAULT_REVERB");
1266 if(defrevopt || (defrevopt=ConfigValueStr(nullptr, nullptr, "default-reverb")))
1267 LoadReverbPreset(defrevopt->c_str(), &ALCcontext::sDefaultEffect);
1269 #ifdef ALSOFT_EAX
1271 constexpr auto eax_block_name = "eax";
1273 const auto eax_enable_opt = ConfigValueBool(nullptr, eax_block_name, "enable");
1275 if (eax_enable_opt)
1277 eax_g_is_enabled = *eax_enable_opt;
1279 if (!eax_g_is_enabled)
1281 TRACE("%s\n", "EAX disabled by a configuration.");
1284 else
1286 eax_g_is_enabled = true;
1288 if(eax_g_is_enabled && DisabledEffects[EAXREVERB_EFFECT])
1290 eax_g_is_enabled = false;
1291 TRACE("%s\n", "EAX disabled because EAXReverb is disabled.");
1294 #endif // ALSOFT_EAX
1296 #define DO_INITCONFIG() std::call_once(alc_config_once, [](){alc_initconfig();})
1299 /************************************************
1300 * Device enumeration
1301 ************************************************/
1302 void ProbeAllDevicesList()
1304 DO_INITCONFIG();
1306 std::lock_guard<std::recursive_mutex> _{ListLock};
1307 if(!PlaybackFactory)
1308 decltype(alcAllDevicesList){}.swap(alcAllDevicesList);
1309 else
1311 std::string names{PlaybackFactory->probe(BackendType::Playback)};
1312 if(names.empty()) names += '\0';
1313 names.swap(alcAllDevicesList);
1316 void ProbeCaptureDeviceList()
1318 DO_INITCONFIG();
1320 std::lock_guard<std::recursive_mutex> _{ListLock};
1321 if(!CaptureFactory)
1322 decltype(alcCaptureDeviceList){}.swap(alcCaptureDeviceList);
1323 else
1325 std::string names{CaptureFactory->probe(BackendType::Capture)};
1326 if(names.empty()) names += '\0';
1327 names.swap(alcCaptureDeviceList);
1332 struct DevFmtPair { DevFmtChannels chans; DevFmtType type; };
1333 al::optional<DevFmtPair> DecomposeDevFormat(ALenum format)
1335 static const struct {
1336 ALenum format;
1337 DevFmtChannels channels;
1338 DevFmtType type;
1339 } list[] = {
1340 { AL_FORMAT_MONO8, DevFmtMono, DevFmtUByte },
1341 { AL_FORMAT_MONO16, DevFmtMono, DevFmtShort },
1342 { AL_FORMAT_MONO_FLOAT32, DevFmtMono, DevFmtFloat },
1344 { AL_FORMAT_STEREO8, DevFmtStereo, DevFmtUByte },
1345 { AL_FORMAT_STEREO16, DevFmtStereo, DevFmtShort },
1346 { AL_FORMAT_STEREO_FLOAT32, DevFmtStereo, DevFmtFloat },
1348 { AL_FORMAT_QUAD8, DevFmtQuad, DevFmtUByte },
1349 { AL_FORMAT_QUAD16, DevFmtQuad, DevFmtShort },
1350 { AL_FORMAT_QUAD32, DevFmtQuad, DevFmtFloat },
1352 { AL_FORMAT_51CHN8, DevFmtX51, DevFmtUByte },
1353 { AL_FORMAT_51CHN16, DevFmtX51, DevFmtShort },
1354 { AL_FORMAT_51CHN32, DevFmtX51, DevFmtFloat },
1356 { AL_FORMAT_61CHN8, DevFmtX61, DevFmtUByte },
1357 { AL_FORMAT_61CHN16, DevFmtX61, DevFmtShort },
1358 { AL_FORMAT_61CHN32, DevFmtX61, DevFmtFloat },
1360 { AL_FORMAT_71CHN8, DevFmtX71, DevFmtUByte },
1361 { AL_FORMAT_71CHN16, DevFmtX71, DevFmtShort },
1362 { AL_FORMAT_71CHN32, DevFmtX71, DevFmtFloat },
1365 for(const auto &item : list)
1367 if(item.format == format)
1368 return al::make_optional(DevFmtPair{item.channels, item.type});
1371 return al::nullopt;
1374 al::optional<DevFmtType> DevFmtTypeFromEnum(ALCenum type)
1376 switch(type)
1378 case ALC_BYTE_SOFT: return al::make_optional(DevFmtByte);
1379 case ALC_UNSIGNED_BYTE_SOFT: return al::make_optional(DevFmtUByte);
1380 case ALC_SHORT_SOFT: return al::make_optional(DevFmtShort);
1381 case ALC_UNSIGNED_SHORT_SOFT: return al::make_optional(DevFmtUShort);
1382 case ALC_INT_SOFT: return al::make_optional(DevFmtInt);
1383 case ALC_UNSIGNED_INT_SOFT: return al::make_optional(DevFmtUInt);
1384 case ALC_FLOAT_SOFT: return al::make_optional(DevFmtFloat);
1386 WARN("Unsupported format type: 0x%04x\n", type);
1387 return al::nullopt;
1389 ALCenum EnumFromDevFmt(DevFmtType type)
1391 switch(type)
1393 case DevFmtByte: return ALC_BYTE_SOFT;
1394 case DevFmtUByte: return ALC_UNSIGNED_BYTE_SOFT;
1395 case DevFmtShort: return ALC_SHORT_SOFT;
1396 case DevFmtUShort: return ALC_UNSIGNED_SHORT_SOFT;
1397 case DevFmtInt: return ALC_INT_SOFT;
1398 case DevFmtUInt: return ALC_UNSIGNED_INT_SOFT;
1399 case DevFmtFloat: return ALC_FLOAT_SOFT;
1401 throw std::runtime_error{"Invalid DevFmtType: "+std::to_string(int(type))};
1404 al::optional<DevFmtChannels> DevFmtChannelsFromEnum(ALCenum channels)
1406 switch(channels)
1408 case ALC_MONO_SOFT: return al::make_optional(DevFmtMono);
1409 case ALC_STEREO_SOFT: return al::make_optional(DevFmtStereo);
1410 case ALC_QUAD_SOFT: return al::make_optional(DevFmtQuad);
1411 case ALC_5POINT1_SOFT: return al::make_optional(DevFmtX51);
1412 case ALC_6POINT1_SOFT: return al::make_optional(DevFmtX61);
1413 case ALC_7POINT1_SOFT: return al::make_optional(DevFmtX71);
1414 case ALC_BFORMAT3D_SOFT: return al::make_optional(DevFmtAmbi3D);
1416 WARN("Unsupported format channels: 0x%04x\n", channels);
1417 return al::nullopt;
1419 ALCenum EnumFromDevFmt(DevFmtChannels channels)
1421 switch(channels)
1423 case DevFmtMono: return ALC_MONO_SOFT;
1424 case DevFmtStereo: return ALC_STEREO_SOFT;
1425 case DevFmtQuad: return ALC_QUAD_SOFT;
1426 case DevFmtX51: return ALC_5POINT1_SOFT;
1427 case DevFmtX61: return ALC_6POINT1_SOFT;
1428 case DevFmtX71: return ALC_7POINT1_SOFT;
1429 case DevFmtAmbi3D: return ALC_BFORMAT3D_SOFT;
1431 throw std::runtime_error{"Invalid DevFmtChannels: "+std::to_string(int(channels))};
1434 al::optional<DevAmbiLayout> DevAmbiLayoutFromEnum(ALCenum layout)
1436 switch(layout)
1438 case ALC_FUMA_SOFT: return al::make_optional(DevAmbiLayout::FuMa);
1439 case ALC_ACN_SOFT: return al::make_optional(DevAmbiLayout::ACN);
1441 WARN("Unsupported ambisonic layout: 0x%04x\n", layout);
1442 return al::nullopt;
1444 ALCenum EnumFromDevAmbi(DevAmbiLayout layout)
1446 switch(layout)
1448 case DevAmbiLayout::FuMa: return ALC_FUMA_SOFT;
1449 case DevAmbiLayout::ACN: return ALC_ACN_SOFT;
1451 throw std::runtime_error{"Invalid DevAmbiLayout: "+std::to_string(int(layout))};
1454 al::optional<DevAmbiScaling> DevAmbiScalingFromEnum(ALCenum scaling)
1456 switch(scaling)
1458 case ALC_FUMA_SOFT: return al::make_optional(DevAmbiScaling::FuMa);
1459 case ALC_SN3D_SOFT: return al::make_optional(DevAmbiScaling::SN3D);
1460 case ALC_N3D_SOFT: return al::make_optional(DevAmbiScaling::N3D);
1462 WARN("Unsupported ambisonic scaling: 0x%04x\n", scaling);
1463 return al::nullopt;
1465 ALCenum EnumFromDevAmbi(DevAmbiScaling scaling)
1467 switch(scaling)
1469 case DevAmbiScaling::FuMa: return ALC_FUMA_SOFT;
1470 case DevAmbiScaling::SN3D: return ALC_SN3D_SOFT;
1471 case DevAmbiScaling::N3D: return ALC_N3D_SOFT;
1473 throw std::runtime_error{"Invalid DevAmbiScaling: "+std::to_string(int(scaling))};
1477 /* Downmixing channel arrays, to map the given format's missing channels to
1478 * existing ones. Based on Wine's DSound downmix values, which are based on
1479 * PulseAudio's.
1481 const std::array<InputRemixMap,6> StereoDownmix{{
1482 { FrontCenter, {{{FrontLeft, 0.5f}, {FrontRight, 0.5f}}} },
1483 { SideLeft, {{{FrontLeft, 1.0f/9.0f}, {FrontRight, 0.0f}}} },
1484 { SideRight, {{{FrontLeft, 0.0f}, {FrontRight, 1.0f/9.0f}}} },
1485 { BackLeft, {{{FrontLeft, 1.0f/9.0f}, {FrontRight, 0.0f}}} },
1486 { BackRight, {{{FrontLeft, 0.0f}, {FrontRight, 1.0f/9.0f}}} },
1487 { BackCenter, {{{FrontLeft, 0.5f/9.0f}, {FrontRight, 0.5f/9.0f}}} },
1489 const std::array<InputRemixMap,4> QuadDownmix{{
1490 { FrontCenter, {{{FrontLeft, 0.5f}, {FrontRight, 0.5f}}} },
1491 { SideLeft, {{{FrontLeft, 0.5f}, {BackLeft, 0.5f}}} },
1492 { SideRight, {{{FrontRight, 0.5f}, {BackRight, 0.5f}}} },
1493 { BackCenter, {{{BackLeft, 0.5f}, {BackRight, 0.5f}}} },
1495 const std::array<InputRemixMap,3> X51Downmix{{
1496 { BackLeft, {{{SideLeft, 1.0f}, {SideRight, 0.0f}}} },
1497 { BackRight, {{{SideLeft, 0.0f}, {SideRight, 1.0f}}} },
1498 { BackCenter, {{{SideLeft, 0.5f}, {SideRight, 0.5f}}} },
1500 const std::array<InputRemixMap,2> X61Downmix{{
1501 { BackLeft, {{{BackCenter, 0.5f}, {SideLeft, 0.5f}}} },
1502 { BackRight, {{{BackCenter, 0.5f}, {SideRight, 0.5f}}} },
1504 const std::array<InputRemixMap,1> X71Downmix{{
1505 { BackCenter, {{{BackLeft, 0.5f}, {BackRight, 0.5f}}} },
1509 /** Stores the latest ALC device error. */
1510 void alcSetError(ALCdevice *device, ALCenum errorCode)
1512 WARN("Error generated on device %p, code 0x%04x\n", voidp{device}, errorCode);
1513 if(TrapALCError)
1515 #ifdef _WIN32
1516 /* DebugBreak() will cause an exception if there is no debugger */
1517 if(IsDebuggerPresent())
1518 DebugBreak();
1519 #elif defined(SIGTRAP)
1520 raise(SIGTRAP);
1521 #endif
1524 if(device)
1525 device->LastError.store(errorCode);
1526 else
1527 LastNullDeviceError.store(errorCode);
1531 std::unique_ptr<Compressor> CreateDeviceLimiter(const ALCdevice *device, const float threshold)
1533 constexpr bool AutoKnee{true};
1534 constexpr bool AutoAttack{true};
1535 constexpr bool AutoRelease{true};
1536 constexpr bool AutoPostGain{true};
1537 constexpr bool AutoDeclip{true};
1538 constexpr float LookAheadTime{0.001f};
1539 constexpr float HoldTime{0.002f};
1540 constexpr float PreGainDb{0.0f};
1541 constexpr float PostGainDb{0.0f};
1542 constexpr float Ratio{std::numeric_limits<float>::infinity()};
1543 constexpr float KneeDb{0.0f};
1544 constexpr float AttackTime{0.02f};
1545 constexpr float ReleaseTime{0.2f};
1547 return Compressor::Create(device->RealOut.Buffer.size(), static_cast<float>(device->Frequency),
1548 AutoKnee, AutoAttack, AutoRelease, AutoPostGain, AutoDeclip, LookAheadTime, HoldTime,
1549 PreGainDb, PostGainDb, threshold, Ratio, KneeDb, AttackTime, ReleaseTime);
1553 * Updates the device's base clock time with however many samples have been
1554 * done. This is used so frequency changes on the device don't cause the time
1555 * to jump forward or back. Must not be called while the device is running/
1556 * mixing.
1558 static inline void UpdateClockBase(ALCdevice *device)
1560 IncrementRef(device->MixCount);
1561 device->ClockBase += nanoseconds{seconds{device->SamplesDone}} / device->Frequency;
1562 device->SamplesDone = 0;
1563 IncrementRef(device->MixCount);
1567 * Updates device parameters according to the attribute list (caller is
1568 * responsible for holding the list lock).
1570 ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
1572 if((!attrList || !attrList[0]) && device->Type == DeviceType::Loopback)
1574 WARN("Missing attributes for loopback device\n");
1575 return ALC_INVALID_VALUE;
1578 al::optional<StereoEncoding> stereomode{};
1579 al::optional<bool> optlimit{};
1580 int hrtf_id{-1};
1582 // Check for attributes
1583 if(attrList && attrList[0])
1585 uint numMono{device->NumMonoSources};
1586 uint numStereo{device->NumStereoSources};
1587 uint numSends{device->NumAuxSends};
1589 al::optional<DevFmtChannels> optchans;
1590 al::optional<DevFmtType> opttype;
1591 al::optional<DevAmbiLayout> optlayout;
1592 al::optional<DevAmbiScaling> optscale;
1593 al::optional<bool> opthrtf;
1595 uint aorder{0u};
1596 uint freq{0u};
1598 #define TRACE_ATTR(a, v) TRACE("%s = %d\n", #a, v)
1599 size_t attrIdx{0};
1600 while(attrList[attrIdx])
1602 switch(attrList[attrIdx])
1604 case ALC_FORMAT_CHANNELS_SOFT:
1605 TRACE_ATTR(ALC_FORMAT_CHANNELS_SOFT, attrList[attrIdx + 1]);
1606 optchans = DevFmtChannelsFromEnum(attrList[attrIdx + 1]);
1607 break;
1609 case ALC_FORMAT_TYPE_SOFT:
1610 TRACE_ATTR(ALC_FORMAT_TYPE_SOFT, attrList[attrIdx + 1]);
1611 opttype = DevFmtTypeFromEnum(attrList[attrIdx + 1]);
1612 break;
1614 case ALC_FREQUENCY:
1615 freq = static_cast<uint>(attrList[attrIdx + 1]);
1616 TRACE_ATTR(ALC_FREQUENCY, freq);
1617 break;
1619 case ALC_AMBISONIC_LAYOUT_SOFT:
1620 TRACE_ATTR(ALC_AMBISONIC_LAYOUT_SOFT, attrList[attrIdx + 1]);
1621 optlayout = DevAmbiLayoutFromEnum(attrList[attrIdx + 1]);
1622 break;
1624 case ALC_AMBISONIC_SCALING_SOFT:
1625 TRACE_ATTR(ALC_AMBISONIC_SCALING_SOFT, attrList[attrIdx + 1]);
1626 optscale = DevAmbiScalingFromEnum(attrList[attrIdx + 1]);
1627 break;
1629 case ALC_AMBISONIC_ORDER_SOFT:
1630 aorder = static_cast<uint>(attrList[attrIdx + 1]);
1631 TRACE_ATTR(ALC_AMBISONIC_ORDER_SOFT, aorder);
1632 break;
1634 case ALC_MONO_SOURCES:
1635 numMono = static_cast<uint>(attrList[attrIdx + 1]);
1636 TRACE_ATTR(ALC_MONO_SOURCES, numMono);
1637 if(numMono > INT_MAX) numMono = 0;
1638 break;
1640 case ALC_STEREO_SOURCES:
1641 numStereo = static_cast<uint>(attrList[attrIdx + 1]);
1642 TRACE_ATTR(ALC_STEREO_SOURCES, numStereo);
1643 if(numStereo > INT_MAX) numStereo = 0;
1644 break;
1646 case ALC_MAX_AUXILIARY_SENDS:
1647 numSends = static_cast<uint>(attrList[attrIdx + 1]);
1648 TRACE_ATTR(ALC_MAX_AUXILIARY_SENDS, numSends);
1649 if(numSends > INT_MAX) numSends = 0;
1650 else numSends = minu(numSends, MAX_SENDS);
1651 break;
1653 case ALC_HRTF_SOFT:
1654 TRACE_ATTR(ALC_HRTF_SOFT, attrList[attrIdx + 1]);
1655 if(attrList[attrIdx + 1] == ALC_FALSE)
1656 opthrtf = false;
1657 else if(attrList[attrIdx + 1] == ALC_TRUE)
1658 opthrtf = true;
1659 else if(attrList[attrIdx + 1] == ALC_DONT_CARE_SOFT)
1660 opthrtf = al::nullopt;
1661 break;
1663 case ALC_HRTF_ID_SOFT:
1664 hrtf_id = attrList[attrIdx + 1];
1665 TRACE_ATTR(ALC_HRTF_ID_SOFT, hrtf_id);
1666 break;
1668 case ALC_OUTPUT_LIMITER_SOFT:
1669 TRACE_ATTR(ALC_OUTPUT_LIMITER_SOFT, attrList[attrIdx + 1]);
1670 if(attrList[attrIdx + 1] == ALC_FALSE)
1671 optlimit = false;
1672 else if(attrList[attrIdx + 1] == ALC_TRUE)
1673 optlimit = true;
1674 else if(attrList[attrIdx + 1] == ALC_DONT_CARE_SOFT)
1675 optlimit = al::nullopt;
1676 break;
1678 case ALC_OUTPUT_MODE_SOFT:
1679 TRACE_ATTR(ALC_HRTF_SOFT, attrList[attrIdx + 1]);
1680 if(attrList[attrIdx + 1] == ALC_HRTF_SOFT)
1681 stereomode = StereoEncoding::Hrtf;
1682 else if(attrList[attrIdx + 1] == ALC_STEREO_UHJ_SOFT)
1683 stereomode = StereoEncoding::Uhj;
1684 else if(attrList[attrIdx + 1] == ALC_NORMAL_SOFT)
1685 stereomode = StereoEncoding::Normal;
1686 else if(attrList[attrIdx + 1] == ALC_ANY_SOFT)
1687 stereomode = al::nullopt;
1688 break;
1690 default:
1691 TRACE("0x%04X = %d (0x%x)\n", attrList[attrIdx],
1692 attrList[attrIdx + 1], attrList[attrIdx + 1]);
1693 break;
1696 attrIdx += 2;
1698 #undef TRACE_ATTR
1700 const bool loopback{device->Type == DeviceType::Loopback};
1701 if(loopback)
1703 if(!optchans || !opttype)
1704 return ALC_INVALID_VALUE;
1705 if(freq < MIN_OUTPUT_RATE || freq > MAX_OUTPUT_RATE)
1706 return ALC_INVALID_VALUE;
1707 if(*optchans == DevFmtAmbi3D)
1709 if(!optlayout || !optscale)
1710 return ALC_INVALID_VALUE;
1711 if(aorder < 1 || aorder > MaxAmbiOrder)
1712 return ALC_INVALID_VALUE;
1713 if((*optlayout == DevAmbiLayout::FuMa || *optscale == DevAmbiScaling::FuMa)
1714 && aorder > 3)
1715 return ALC_INVALID_VALUE;
1719 /* If a context is already running on the device, stop playback so the
1720 * device attributes can be updated.
1722 if(device->Flags.test(DeviceRunning))
1723 device->Backend->stop();
1724 device->Flags.reset(DeviceRunning);
1726 UpdateClockBase(device);
1728 if(!stereomode && opthrtf)
1729 stereomode = *opthrtf ? StereoEncoding::Hrtf : StereoEncoding::Normal;
1731 if(loopback)
1733 device->Frequency = freq;
1734 device->FmtChans = *optchans;
1735 device->FmtType = *opttype;
1736 if(device->FmtChans == DevFmtAmbi3D)
1738 device->mAmbiOrder = aorder;
1739 device->mAmbiLayout = *optlayout;
1740 device->mAmbiScale = *optscale;
1743 else
1745 device->BufferSize = DEFAULT_UPDATE_SIZE * DEFAULT_NUM_UPDATES;
1746 device->UpdateSize = DEFAULT_UPDATE_SIZE;
1747 device->Frequency = DEFAULT_OUTPUT_RATE;
1749 freq = device->configValue<uint>(nullptr, "frequency").value_or(freq);
1750 if(freq < 1)
1751 device->Flags.reset(FrequencyRequest);
1752 else
1754 freq = clampu(freq, MIN_OUTPUT_RATE, MAX_OUTPUT_RATE);
1756 const double scale{static_cast<double>(freq) / device->Frequency};
1757 device->UpdateSize = static_cast<uint>(device->UpdateSize*scale + 0.5);
1758 device->BufferSize = static_cast<uint>(device->BufferSize*scale + 0.5);
1760 device->Frequency = freq;
1761 device->Flags.set(FrequencyRequest);
1764 if(auto persizeopt = device->configValue<uint>(nullptr, "period_size"))
1765 device->UpdateSize = clampu(*persizeopt, 64, 8192);
1767 if(auto peropt = device->configValue<uint>(nullptr, "periods"))
1768 device->BufferSize = device->UpdateSize * clampu(*peropt, 2, 16);
1769 else
1770 device->BufferSize = maxu(device->BufferSize, device->UpdateSize*2);
1773 if(numMono > INT_MAX-numStereo)
1774 numMono = INT_MAX-numStereo;
1775 numMono += numStereo;
1776 if(auto srcsopt = device->configValue<uint>(nullptr, "sources"))
1778 if(*srcsopt <= 0) numMono = 256;
1779 else numMono = *srcsopt;
1781 else
1782 numMono = maxu(numMono, 256);
1783 numStereo = minu(numStereo, numMono);
1784 numMono -= numStereo;
1785 device->SourcesMax = numMono + numStereo;
1787 device->NumMonoSources = numMono;
1788 device->NumStereoSources = numStereo;
1790 if(auto sendsopt = device->configValue<int>(nullptr, "sends"))
1791 device->NumAuxSends = minu(numSends,
1792 static_cast<uint>(clampi(*sendsopt, 0, MAX_SENDS)));
1793 else
1794 device->NumAuxSends = numSends;
1797 if(device->Flags.test(DeviceRunning))
1798 return ALC_NO_ERROR;
1800 device->AvgSpeakerDist = 0.0f;
1801 device->mNFCtrlFilter = NfcFilter{};
1802 device->mUhjEncoder = nullptr;
1803 device->AmbiDecoder = nullptr;
1804 device->Bs2b = nullptr;
1805 device->PostProcess = nullptr;
1807 device->Limiter = nullptr;
1808 device->ChannelDelays = nullptr;
1810 std::fill(std::begin(device->HrtfAccumData), std::end(device->HrtfAccumData), float2{});
1812 device->Dry.AmbiMap.fill(BFChannelConfig{});
1813 device->Dry.Buffer = {};
1814 std::fill(std::begin(device->NumChannelsPerOrder), std::end(device->NumChannelsPerOrder), 0u);
1815 device->RealOut.RemixMap = {};
1816 device->RealOut.ChannelIndex.fill(INVALID_CHANNEL_INDEX);
1817 device->RealOut.Buffer = {};
1818 device->MixBuffer.clear();
1819 device->MixBuffer.shrink_to_fit();
1821 UpdateClockBase(device);
1822 device->FixedLatency = nanoseconds::zero();
1824 device->DitherDepth = 0.0f;
1825 device->DitherSeed = DitherRNGSeed;
1827 /*************************************************************************
1828 * Update device format request if HRTF or UHJ is requested
1830 device->mHrtfStatus = ALC_HRTF_DISABLED_SOFT;
1831 if(device->Type != DeviceType::Loopback)
1833 if(auto hrtfopt = device->configValue<std::string>(nullptr, "hrtf"))
1835 const char *hrtf{hrtfopt->c_str()};
1836 if(al::strcasecmp(hrtf, "true") == 0)
1837 stereomode = StereoEncoding::Hrtf;
1838 else if(al::strcasecmp(hrtf, "false") == 0)
1840 if(!stereomode || *stereomode == StereoEncoding::Hrtf)
1841 stereomode = StereoEncoding::Normal;
1843 else if(al::strcasecmp(hrtf, "auto") != 0)
1844 ERR("Unexpected hrtf value: %s\n", hrtf);
1847 /* If the app or user wants HRTF or UHJ, try to set stereo playback. */
1848 if(stereomode && *stereomode != StereoEncoding::Normal)
1850 device->FmtChans = DevFmtStereo;
1851 device->Flags.set(ChannelsRequest);
1855 TRACE("Pre-reset: %s%s, %s%s, %s%uhz, %u / %u buffer\n",
1856 device->Flags.test(ChannelsRequest)?"*":"", DevFmtChannelsString(device->FmtChans),
1857 device->Flags.test(SampleTypeRequest)?"*":"", DevFmtTypeString(device->FmtType),
1858 device->Flags.test(FrequencyRequest)?"*":"", device->Frequency,
1859 device->UpdateSize, device->BufferSize);
1861 const uint oldFreq{device->Frequency};
1862 const DevFmtChannels oldChans{device->FmtChans};
1863 const DevFmtType oldType{device->FmtType};
1864 try {
1865 auto backend = device->Backend.get();
1866 if(!backend->reset())
1867 throw al::backend_exception{al::backend_error::DeviceError, "Device reset failure"};
1869 catch(std::exception &e) {
1870 ERR("Device error: %s\n", e.what());
1871 device->handleDisconnect("%s", e.what());
1872 return ALC_INVALID_DEVICE;
1875 if(device->FmtChans != oldChans && device->Flags.test(ChannelsRequest))
1877 ERR("Failed to set %s, got %s instead\n", DevFmtChannelsString(oldChans),
1878 DevFmtChannelsString(device->FmtChans));
1879 device->Flags.reset(ChannelsRequest);
1881 if(device->FmtType != oldType && device->Flags.test(SampleTypeRequest))
1883 ERR("Failed to set %s, got %s instead\n", DevFmtTypeString(oldType),
1884 DevFmtTypeString(device->FmtType));
1885 device->Flags.reset(SampleTypeRequest);
1887 if(device->Frequency != oldFreq && device->Flags.test(FrequencyRequest))
1889 WARN("Failed to set %uhz, got %uhz instead\n", oldFreq, device->Frequency);
1890 device->Flags.reset(FrequencyRequest);
1893 TRACE("Post-reset: %s, %s, %uhz, %u / %u buffer\n",
1894 DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType),
1895 device->Frequency, device->UpdateSize, device->BufferSize);
1897 if(device->Type != DeviceType::Loopback)
1899 if(auto modeopt = device->configValue<std::string>(nullptr, "stereo-mode"))
1901 const char *mode{modeopt->c_str()};
1902 if(al::strcasecmp(mode, "headphones") == 0)
1903 device->Flags.set(DirectEar);
1904 else if(al::strcasecmp(mode, "speakers") == 0)
1905 device->Flags.reset(DirectEar);
1906 else if(al::strcasecmp(mode, "auto") != 0)
1907 ERR("Unexpected stereo-mode: %s\n", mode);
1910 if(auto encopt = device->configValue<std::string>(nullptr, "stereo-encoding"))
1912 const char *mode{encopt->c_str()};
1913 if(al::strcasecmp(mode, "panpot") == 0)
1914 stereomode = al::make_optional(StereoEncoding::Normal);
1915 else if(al::strcasecmp(mode, "uhj") == 0)
1916 stereomode = al::make_optional(StereoEncoding::Uhj);
1917 else if(al::strcasecmp(mode, "hrtf") == 0)
1918 stereomode = al::make_optional(StereoEncoding::Hrtf);
1919 else
1920 ERR("Unexpected stereo-encoding: %s\n", mode);
1924 aluInitRenderer(device, hrtf_id, stereomode);
1926 TRACE("Max sources: %d (%d + %d), effect slots: %d, sends: %d\n",
1927 device->SourcesMax, device->NumMonoSources, device->NumStereoSources,
1928 device->AuxiliaryEffectSlotMax, device->NumAuxSends);
1930 switch(device->FmtChans)
1932 case DevFmtMono: break;
1933 case DevFmtStereo:
1934 if(!device->mUhjEncoder)
1935 device->RealOut.RemixMap = StereoDownmix;
1936 break;
1937 case DevFmtQuad: device->RealOut.RemixMap = QuadDownmix; break;
1938 case DevFmtX51: device->RealOut.RemixMap = X51Downmix; break;
1939 case DevFmtX61: device->RealOut.RemixMap = X61Downmix; break;
1940 case DevFmtX71: device->RealOut.RemixMap = X71Downmix; break;
1941 case DevFmtAmbi3D: break;
1944 nanoseconds::rep sample_delay{0};
1945 if(device->mUhjEncoder)
1946 sample_delay += UhjEncoder::sFilterDelay;
1947 if(device->mHrtfState)
1948 sample_delay += HrtfDirectDelay;
1949 if(auto *ambidec = device->AmbiDecoder.get())
1951 if(ambidec->hasStablizer())
1952 sample_delay += FrontStablizer::DelayLength;
1955 if(device->getConfigValueBool(nullptr, "dither", 1))
1957 int depth{device->configValue<int>(nullptr, "dither-depth").value_or(0)};
1958 if(depth <= 0)
1960 switch(device->FmtType)
1962 case DevFmtByte:
1963 case DevFmtUByte:
1964 depth = 8;
1965 break;
1966 case DevFmtShort:
1967 case DevFmtUShort:
1968 depth = 16;
1969 break;
1970 case DevFmtInt:
1971 case DevFmtUInt:
1972 case DevFmtFloat:
1973 break;
1977 if(depth > 0)
1979 depth = clampi(depth, 2, 24);
1980 device->DitherDepth = std::pow(2.0f, static_cast<float>(depth-1));
1983 if(!(device->DitherDepth > 0.0f))
1984 TRACE("Dithering disabled\n");
1985 else
1986 TRACE("Dithering enabled (%d-bit, %g)\n", float2int(std::log2(device->DitherDepth)+0.5f)+1,
1987 device->DitherDepth);
1989 if(auto limopt = device->configValue<bool>(nullptr, "output-limiter"))
1990 optlimit = limopt;
1992 /* If the gain limiter is unset, use the limiter for integer-based output
1993 * (where samples must be clamped), and don't for floating-point (which can
1994 * take unclamped samples).
1996 if(!optlimit)
1998 switch(device->FmtType)
2000 case DevFmtByte:
2001 case DevFmtUByte:
2002 case DevFmtShort:
2003 case DevFmtUShort:
2004 case DevFmtInt:
2005 case DevFmtUInt:
2006 optlimit = true;
2007 break;
2008 case DevFmtFloat:
2009 break;
2012 if(optlimit.value_or(false) == false)
2013 TRACE("Output limiter disabled\n");
2014 else
2016 float thrshld{1.0f};
2017 switch(device->FmtType)
2019 case DevFmtByte:
2020 case DevFmtUByte:
2021 thrshld = 127.0f / 128.0f;
2022 break;
2023 case DevFmtShort:
2024 case DevFmtUShort:
2025 thrshld = 32767.0f / 32768.0f;
2026 break;
2027 case DevFmtInt:
2028 case DevFmtUInt:
2029 case DevFmtFloat:
2030 break;
2032 if(device->DitherDepth > 0.0f)
2033 thrshld -= 1.0f / device->DitherDepth;
2035 const float thrshld_dB{std::log10(thrshld) * 20.0f};
2036 auto limiter = CreateDeviceLimiter(device, thrshld_dB);
2038 sample_delay += limiter->getLookAhead();
2039 device->Limiter = std::move(limiter);
2040 TRACE("Output limiter enabled, %.4fdB limit\n", thrshld_dB);
2043 /* Convert the sample delay from samples to nanosamples to nanoseconds. */
2044 device->FixedLatency += nanoseconds{seconds{sample_delay}} / device->Frequency;
2045 TRACE("Fixed device latency: %" PRId64 "ns\n", int64_t{device->FixedLatency.count()});
2047 FPUCtl mixer_mode{};
2048 for(ContextBase *ctxbase : *device->mContexts.load())
2050 auto *context = static_cast<ALCcontext*>(ctxbase);
2052 auto GetEffectBuffer = [](ALbuffer *buffer) noexcept -> EffectState::Buffer
2054 if(!buffer) return EffectState::Buffer{};
2055 return EffectState::Buffer{buffer, buffer->mData};
2057 std::unique_lock<std::mutex> proplock{context->mPropLock};
2058 std::unique_lock<std::mutex> slotlock{context->mEffectSlotLock};
2060 /* Clear out unused wet buffers. */
2061 auto buffer_not_in_use = [](WetBufferPtr &wetbuffer) noexcept -> bool
2062 { return !wetbuffer->mInUse; };
2063 auto wetbuffer_iter = std::remove_if(context->mWetBuffers.begin(),
2064 context->mWetBuffers.end(), buffer_not_in_use);
2065 context->mWetBuffers.erase(wetbuffer_iter, context->mWetBuffers.end());
2067 if(ALeffectslot *slot{context->mDefaultSlot.get()})
2069 aluInitEffectPanning(&slot->mSlot, context);
2071 EffectState *state{slot->Effect.State.get()};
2072 state->mOutTarget = device->Dry.Buffer;
2073 state->deviceUpdate(device, GetEffectBuffer(slot->Buffer));
2074 slot->updateProps(context);
2077 if(EffectSlotArray *curarray{context->mActiveAuxSlots.load(std::memory_order_relaxed)})
2078 std::fill_n(curarray->end(), curarray->size(), nullptr);
2079 for(auto &sublist : context->mEffectSlotList)
2081 uint64_t usemask{~sublist.FreeMask};
2082 while(usemask)
2084 const int idx{al::countr_zero(usemask)};
2085 ALeffectslot *slot{sublist.EffectSlots + idx};
2086 usemask &= ~(1_u64 << idx);
2088 aluInitEffectPanning(&slot->mSlot, context);
2090 EffectState *state{slot->Effect.State.get()};
2091 state->mOutTarget = device->Dry.Buffer;
2092 state->deviceUpdate(device, GetEffectBuffer(slot->Buffer));
2093 slot->updateProps(context);
2096 slotlock.unlock();
2098 const uint num_sends{device->NumAuxSends};
2099 std::unique_lock<std::mutex> srclock{context->mSourceLock};
2100 for(auto &sublist : context->mSourceList)
2102 uint64_t usemask{~sublist.FreeMask};
2103 while(usemask)
2105 const int idx{al::countr_zero(usemask)};
2106 ALsource *source{sublist.Sources + idx};
2107 usemask &= ~(1_u64 << idx);
2109 auto clear_send = [](ALsource::SendData &send) -> void
2111 if(send.Slot)
2112 DecrementRef(send.Slot->ref);
2113 send.Slot = nullptr;
2114 send.Gain = 1.0f;
2115 send.GainHF = 1.0f;
2116 send.HFReference = LOWPASSFREQREF;
2117 send.GainLF = 1.0f;
2118 send.LFReference = HIGHPASSFREQREF;
2120 auto send_begin = source->Send.begin() + static_cast<ptrdiff_t>(num_sends);
2121 std::for_each(send_begin, source->Send.end(), clear_send);
2123 source->mPropsDirty = true;
2127 auto voicelist = context->getVoicesSpan();
2128 for(Voice *voice : voicelist)
2130 /* Clear extraneous property set sends. */
2131 std::fill(std::begin(voice->mProps.Send)+num_sends, std::end(voice->mProps.Send),
2132 VoiceProps::SendData{});
2134 std::fill(voice->mSend.begin()+num_sends, voice->mSend.end(), Voice::TargetData{});
2135 for(auto &chandata : voice->mChans)
2137 std::fill(chandata.mWetParams.begin()+num_sends, chandata.mWetParams.end(),
2138 SendParams{});
2141 if(VoicePropsItem *props{voice->mUpdate.exchange(nullptr, std::memory_order_relaxed)})
2142 AtomicReplaceHead(context->mFreeVoiceProps, props);
2144 /* Force the voice to stopped if it was stopping. */
2145 Voice::State vstate{Voice::Stopping};
2146 voice->mPlayState.compare_exchange_strong(vstate, Voice::Stopped,
2147 std::memory_order_acquire, std::memory_order_acquire);
2148 if(voice->mSourceID.load(std::memory_order_relaxed) == 0u)
2149 continue;
2151 voice->prepare(device);
2153 /* Clear all voice props to let them get allocated again. */
2154 context->mVoicePropClusters.clear();
2155 context->mFreeVoiceProps.store(nullptr, std::memory_order_relaxed);
2156 srclock.unlock();
2158 context->mPropsDirty = false;
2159 UpdateContextProps(context);
2160 UpdateAllSourceProps(context);
2162 mixer_mode.leave();
2164 if(!device->Flags.test(DevicePaused))
2166 try {
2167 auto backend = device->Backend.get();
2168 backend->start();
2169 device->Flags.set(DeviceRunning);
2171 catch(al::backend_exception& e) {
2172 ERR("%s\n", e.what());
2173 device->handleDisconnect("%s", e.what());
2174 return ALC_INVALID_DEVICE;
2176 TRACE("Post-start: %s, %s, %uhz, %u / %u buffer\n",
2177 DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType),
2178 device->Frequency, device->UpdateSize, device->BufferSize);
2181 return ALC_NO_ERROR;
2185 * Updates device parameters as above, and also first clears the disconnected
2186 * status, if set.
2188 bool ResetDeviceParams(ALCdevice *device, const int *attrList)
2190 /* If the device was disconnected, reset it since we're opened anew. */
2191 if UNLIKELY(!device->Connected.load(std::memory_order_relaxed))
2193 /* Make sure disconnection is finished before continuing on. */
2194 device->waitForMix();
2196 for(ContextBase *ctxbase : *device->mContexts.load(std::memory_order_acquire))
2198 auto *ctx = static_cast<ALCcontext*>(ctxbase);
2199 if(!ctx->mStopVoicesOnDisconnect.load(std::memory_order_acquire))
2200 continue;
2202 /* Clear any pending voice changes and reallocate voices to get a
2203 * clean restart.
2205 std::lock_guard<std::mutex> __{ctx->mSourceLock};
2206 auto *vchg = ctx->mCurrentVoiceChange.load(std::memory_order_acquire);
2207 while(auto *next = vchg->mNext.load(std::memory_order_acquire))
2208 vchg = next;
2209 ctx->mCurrentVoiceChange.store(vchg, std::memory_order_release);
2211 ctx->mVoicePropClusters.clear();
2212 ctx->mFreeVoiceProps.store(nullptr, std::memory_order_relaxed);
2214 ctx->mVoiceClusters.clear();
2215 ctx->allocVoices(std::max<size_t>(256,
2216 ctx->mActiveVoiceCount.load(std::memory_order_relaxed)));
2219 device->Connected.store(true);
2222 ALCenum err{UpdateDeviceParams(device, attrList)};
2223 if LIKELY(err == ALC_NO_ERROR) return ALC_TRUE;
2225 alcSetError(device, err);
2226 return ALC_FALSE;
2230 /** Checks if the device handle is valid, and returns a new reference if so. */
2231 DeviceRef VerifyDevice(ALCdevice *device)
2233 std::lock_guard<std::recursive_mutex> _{ListLock};
2234 auto iter = std::lower_bound(DeviceList.begin(), DeviceList.end(), device);
2235 if(iter != DeviceList.end() && *iter == device)
2237 (*iter)->add_ref();
2238 return DeviceRef{*iter};
2240 return nullptr;
2245 * Checks if the given context is valid, returning a new reference to it if so.
2247 ContextRef VerifyContext(ALCcontext *context)
2249 std::lock_guard<std::recursive_mutex> _{ListLock};
2250 auto iter = std::lower_bound(ContextList.begin(), ContextList.end(), context);
2251 if(iter != ContextList.end() && *iter == context)
2253 (*iter)->add_ref();
2254 return ContextRef{*iter};
2256 return nullptr;
2259 } // namespace
2261 /** Returns a new reference to the currently active context for this thread. */
2262 ContextRef GetContextRef(void)
2264 ALCcontext *context{ALCcontext::getThreadContext()};
2265 if(context)
2266 context->add_ref();
2267 else
2269 std::lock_guard<std::recursive_mutex> _{ListLock};
2270 context = ALCcontext::sGlobalContext.load(std::memory_order_acquire);
2271 if(context) context->add_ref();
2273 return ContextRef{context};
2277 /************************************************
2278 * Standard ALC functions
2279 ************************************************/
2281 ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device)
2282 START_API_FUNC
2284 DeviceRef dev{VerifyDevice(device)};
2285 if(dev) return dev->LastError.exchange(ALC_NO_ERROR);
2286 return LastNullDeviceError.exchange(ALC_NO_ERROR);
2288 END_API_FUNC
2291 ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context)
2292 START_API_FUNC
2294 if(!SuspendDefers)
2295 return;
2297 ContextRef ctx{VerifyContext(context)};
2298 if(!ctx)
2299 alcSetError(nullptr, ALC_INVALID_CONTEXT);
2300 else
2302 std::lock_guard<std::mutex> _{ctx->mPropLock};
2303 ctx->deferUpdates();
2306 END_API_FUNC
2308 ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context)
2309 START_API_FUNC
2311 if(!SuspendDefers)
2312 return;
2314 ContextRef ctx{VerifyContext(context)};
2315 if(!ctx)
2316 alcSetError(nullptr, ALC_INVALID_CONTEXT);
2317 else
2319 std::lock_guard<std::mutex> _{ctx->mPropLock};
2320 ctx->processUpdates();
2323 END_API_FUNC
2326 ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum param)
2327 START_API_FUNC
2329 const ALCchar *value{nullptr};
2331 switch(param)
2333 case ALC_NO_ERROR:
2334 value = alcNoError;
2335 break;
2337 case ALC_INVALID_ENUM:
2338 value = alcErrInvalidEnum;
2339 break;
2341 case ALC_INVALID_VALUE:
2342 value = alcErrInvalidValue;
2343 break;
2345 case ALC_INVALID_DEVICE:
2346 value = alcErrInvalidDevice;
2347 break;
2349 case ALC_INVALID_CONTEXT:
2350 value = alcErrInvalidContext;
2351 break;
2353 case ALC_OUT_OF_MEMORY:
2354 value = alcErrOutOfMemory;
2355 break;
2357 case ALC_DEVICE_SPECIFIER:
2358 value = alcDefaultName;
2359 break;
2361 case ALC_ALL_DEVICES_SPECIFIER:
2362 if(DeviceRef dev{VerifyDevice(Device)})
2364 if(dev->Type == DeviceType::Capture)
2365 alcSetError(dev.get(), ALC_INVALID_ENUM);
2366 else if(dev->Type == DeviceType::Loopback)
2367 value = alcDefaultName;
2368 else
2370 std::lock_guard<std::mutex> _{dev->StateLock};
2371 value = dev->DeviceName.c_str();
2374 else
2376 ProbeAllDevicesList();
2377 value = alcAllDevicesList.c_str();
2379 break;
2381 case ALC_CAPTURE_DEVICE_SPECIFIER:
2382 if(DeviceRef dev{VerifyDevice(Device)})
2384 if(dev->Type != DeviceType::Capture)
2385 alcSetError(dev.get(), ALC_INVALID_ENUM);
2386 else
2388 std::lock_guard<std::mutex> _{dev->StateLock};
2389 value = dev->DeviceName.c_str();
2392 else
2394 ProbeCaptureDeviceList();
2395 value = alcCaptureDeviceList.c_str();
2397 break;
2399 /* Default devices are always first in the list */
2400 case ALC_DEFAULT_DEVICE_SPECIFIER:
2401 value = alcDefaultName;
2402 break;
2404 case ALC_DEFAULT_ALL_DEVICES_SPECIFIER:
2405 if(alcAllDevicesList.empty())
2406 ProbeAllDevicesList();
2408 /* Copy first entry as default. */
2409 alcDefaultAllDevicesSpecifier = alcAllDevicesList.c_str();
2410 value = alcDefaultAllDevicesSpecifier.c_str();
2411 break;
2413 case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER:
2414 if(alcCaptureDeviceList.empty())
2415 ProbeCaptureDeviceList();
2417 /* Copy first entry as default. */
2418 alcCaptureDefaultDeviceSpecifier = alcCaptureDeviceList.c_str();
2419 value = alcCaptureDefaultDeviceSpecifier.c_str();
2420 break;
2422 case ALC_EXTENSIONS:
2423 if(VerifyDevice(Device))
2424 value = alcExtensionList;
2425 else
2426 value = alcNoDeviceExtList;
2427 break;
2429 case ALC_HRTF_SPECIFIER_SOFT:
2430 if(DeviceRef dev{VerifyDevice(Device)})
2432 std::lock_guard<std::mutex> _{dev->StateLock};
2433 value = (dev->mHrtf ? dev->mHrtfName.c_str() : "");
2435 else
2436 alcSetError(nullptr, ALC_INVALID_DEVICE);
2437 break;
2439 default:
2440 alcSetError(VerifyDevice(Device).get(), ALC_INVALID_ENUM);
2441 break;
2444 return value;
2446 END_API_FUNC
2449 static size_t GetIntegerv(ALCdevice *device, ALCenum param, const al::span<int> values)
2451 size_t i;
2453 if(values.empty())
2455 alcSetError(device, ALC_INVALID_VALUE);
2456 return 0;
2459 if(!device)
2461 switch(param)
2463 case ALC_MAJOR_VERSION:
2464 values[0] = alcMajorVersion;
2465 return 1;
2466 case ALC_MINOR_VERSION:
2467 values[0] = alcMinorVersion;
2468 return 1;
2470 case ALC_EFX_MAJOR_VERSION:
2471 values[0] = alcEFXMajorVersion;
2472 return 1;
2473 case ALC_EFX_MINOR_VERSION:
2474 values[0] = alcEFXMinorVersion;
2475 return 1;
2476 case ALC_MAX_AUXILIARY_SENDS:
2477 values[0] = MAX_SENDS;
2478 return 1;
2480 case ALC_ATTRIBUTES_SIZE:
2481 case ALC_ALL_ATTRIBUTES:
2482 case ALC_FREQUENCY:
2483 case ALC_REFRESH:
2484 case ALC_SYNC:
2485 case ALC_MONO_SOURCES:
2486 case ALC_STEREO_SOURCES:
2487 case ALC_CAPTURE_SAMPLES:
2488 case ALC_FORMAT_CHANNELS_SOFT:
2489 case ALC_FORMAT_TYPE_SOFT:
2490 case ALC_AMBISONIC_LAYOUT_SOFT:
2491 case ALC_AMBISONIC_SCALING_SOFT:
2492 case ALC_AMBISONIC_ORDER_SOFT:
2493 case ALC_MAX_AMBISONIC_ORDER_SOFT:
2494 alcSetError(nullptr, ALC_INVALID_DEVICE);
2495 return 0;
2497 default:
2498 alcSetError(nullptr, ALC_INVALID_ENUM);
2500 return 0;
2503 std::lock_guard<std::mutex> _{device->StateLock};
2504 if(device->Type == DeviceType::Capture)
2506 constexpr int MaxCaptureAttributes{9};
2507 switch(param)
2509 case ALC_ATTRIBUTES_SIZE:
2510 values[0] = MaxCaptureAttributes;
2511 return 1;
2512 case ALC_ALL_ATTRIBUTES:
2513 i = 0;
2514 if(values.size() < MaxCaptureAttributes)
2515 alcSetError(device, ALC_INVALID_VALUE);
2516 else
2518 values[i++] = ALC_MAJOR_VERSION;
2519 values[i++] = alcMajorVersion;
2520 values[i++] = ALC_MINOR_VERSION;
2521 values[i++] = alcMinorVersion;
2522 values[i++] = ALC_CAPTURE_SAMPLES;
2523 values[i++] = static_cast<int>(device->Backend->availableSamples());
2524 values[i++] = ALC_CONNECTED;
2525 values[i++] = device->Connected.load(std::memory_order_relaxed);
2526 values[i++] = 0;
2527 assert(i == MaxCaptureAttributes);
2529 return i;
2531 case ALC_MAJOR_VERSION:
2532 values[0] = alcMajorVersion;
2533 return 1;
2534 case ALC_MINOR_VERSION:
2535 values[0] = alcMinorVersion;
2536 return 1;
2538 case ALC_CAPTURE_SAMPLES:
2539 values[0] = static_cast<int>(device->Backend->availableSamples());
2540 return 1;
2542 case ALC_CONNECTED:
2543 values[0] = device->Connected.load(std::memory_order_acquire);
2544 return 1;
2546 default:
2547 alcSetError(device, ALC_INVALID_ENUM);
2549 return 0;
2552 /* render device */
2553 auto NumAttrsForDevice = [](ALCdevice *aldev) noexcept
2555 if(aldev->Type == DeviceType::Loopback && aldev->FmtChans == DevFmtAmbi3D)
2556 return 35;
2557 return 29;
2559 switch(param)
2561 case ALC_ATTRIBUTES_SIZE:
2562 values[0] = NumAttrsForDevice(device);
2563 return 1;
2565 case ALC_ALL_ATTRIBUTES:
2566 i = 0;
2567 if(values.size() < static_cast<size_t>(NumAttrsForDevice(device)))
2568 alcSetError(device, ALC_INVALID_VALUE);
2569 else
2571 values[i++] = ALC_MAJOR_VERSION;
2572 values[i++] = alcMajorVersion;
2573 values[i++] = ALC_MINOR_VERSION;
2574 values[i++] = alcMinorVersion;
2575 values[i++] = ALC_EFX_MAJOR_VERSION;
2576 values[i++] = alcEFXMajorVersion;
2577 values[i++] = ALC_EFX_MINOR_VERSION;
2578 values[i++] = alcEFXMinorVersion;
2580 values[i++] = ALC_FREQUENCY;
2581 values[i++] = static_cast<int>(device->Frequency);
2582 if(device->Type != DeviceType::Loopback)
2584 values[i++] = ALC_REFRESH;
2585 values[i++] = static_cast<int>(device->Frequency / device->UpdateSize);
2587 values[i++] = ALC_SYNC;
2588 values[i++] = ALC_FALSE;
2590 else
2592 if(device->FmtChans == DevFmtAmbi3D)
2594 values[i++] = ALC_AMBISONIC_LAYOUT_SOFT;
2595 values[i++] = EnumFromDevAmbi(device->mAmbiLayout);
2597 values[i++] = ALC_AMBISONIC_SCALING_SOFT;
2598 values[i++] = EnumFromDevAmbi(device->mAmbiScale);
2600 values[i++] = ALC_AMBISONIC_ORDER_SOFT;
2601 values[i++] = static_cast<int>(device->mAmbiOrder);
2604 values[i++] = ALC_FORMAT_CHANNELS_SOFT;
2605 values[i++] = EnumFromDevFmt(device->FmtChans);
2607 values[i++] = ALC_FORMAT_TYPE_SOFT;
2608 values[i++] = EnumFromDevFmt(device->FmtType);
2611 values[i++] = ALC_MONO_SOURCES;
2612 values[i++] = static_cast<int>(device->NumMonoSources);
2614 values[i++] = ALC_STEREO_SOURCES;
2615 values[i++] = static_cast<int>(device->NumStereoSources);
2617 values[i++] = ALC_MAX_AUXILIARY_SENDS;
2618 values[i++] = static_cast<int>(device->NumAuxSends);
2620 values[i++] = ALC_HRTF_SOFT;
2621 values[i++] = (device->mHrtf ? ALC_TRUE : ALC_FALSE);
2623 values[i++] = ALC_HRTF_STATUS_SOFT;
2624 values[i++] = device->mHrtfStatus;
2626 values[i++] = ALC_OUTPUT_LIMITER_SOFT;
2627 values[i++] = device->Limiter ? ALC_TRUE : ALC_FALSE;
2629 values[i++] = ALC_MAX_AMBISONIC_ORDER_SOFT;
2630 values[i++] = MaxAmbiOrder;
2632 values[i++] = 0;
2634 return i;
2636 case ALC_MAJOR_VERSION:
2637 values[0] = alcMajorVersion;
2638 return 1;
2640 case ALC_MINOR_VERSION:
2641 values[0] = alcMinorVersion;
2642 return 1;
2644 case ALC_EFX_MAJOR_VERSION:
2645 values[0] = alcEFXMajorVersion;
2646 return 1;
2648 case ALC_EFX_MINOR_VERSION:
2649 values[0] = alcEFXMinorVersion;
2650 return 1;
2652 case ALC_FREQUENCY:
2653 values[0] = static_cast<int>(device->Frequency);
2654 return 1;
2656 case ALC_REFRESH:
2657 if(device->Type == DeviceType::Loopback)
2659 alcSetError(device, ALC_INVALID_DEVICE);
2660 return 0;
2662 values[0] = static_cast<int>(device->Frequency / device->UpdateSize);
2663 return 1;
2665 case ALC_SYNC:
2666 if(device->Type == DeviceType::Loopback)
2668 alcSetError(device, ALC_INVALID_DEVICE);
2669 return 0;
2671 values[0] = ALC_FALSE;
2672 return 1;
2674 case ALC_FORMAT_CHANNELS_SOFT:
2675 if(device->Type != DeviceType::Loopback)
2677 alcSetError(device, ALC_INVALID_DEVICE);
2678 return 0;
2680 values[0] = EnumFromDevFmt(device->FmtChans);
2681 return 1;
2683 case ALC_FORMAT_TYPE_SOFT:
2684 if(device->Type != DeviceType::Loopback)
2686 alcSetError(device, ALC_INVALID_DEVICE);
2687 return 0;
2689 values[0] = EnumFromDevFmt(device->FmtType);
2690 return 1;
2692 case ALC_AMBISONIC_LAYOUT_SOFT:
2693 if(device->Type != DeviceType::Loopback || device->FmtChans != DevFmtAmbi3D)
2695 alcSetError(device, ALC_INVALID_DEVICE);
2696 return 0;
2698 values[0] = EnumFromDevAmbi(device->mAmbiLayout);
2699 return 1;
2701 case ALC_AMBISONIC_SCALING_SOFT:
2702 if(device->Type != DeviceType::Loopback || device->FmtChans != DevFmtAmbi3D)
2704 alcSetError(device, ALC_INVALID_DEVICE);
2705 return 0;
2707 values[0] = EnumFromDevAmbi(device->mAmbiScale);
2708 return 1;
2710 case ALC_AMBISONIC_ORDER_SOFT:
2711 if(device->Type != DeviceType::Loopback || device->FmtChans != DevFmtAmbi3D)
2713 alcSetError(device, ALC_INVALID_DEVICE);
2714 return 0;
2716 values[0] = static_cast<int>(device->mAmbiOrder);
2717 return 1;
2719 case ALC_MONO_SOURCES:
2720 values[0] = static_cast<int>(device->NumMonoSources);
2721 return 1;
2723 case ALC_STEREO_SOURCES:
2724 values[0] = static_cast<int>(device->NumStereoSources);
2725 return 1;
2727 case ALC_MAX_AUXILIARY_SENDS:
2728 values[0] = static_cast<int>(device->NumAuxSends);
2729 return 1;
2731 case ALC_CONNECTED:
2732 values[0] = device->Connected.load(std::memory_order_acquire);
2733 return 1;
2735 case ALC_HRTF_SOFT:
2736 values[0] = (device->mHrtf ? ALC_TRUE : ALC_FALSE);
2737 return 1;
2739 case ALC_HRTF_STATUS_SOFT:
2740 values[0] = device->mHrtfStatus;
2741 return 1;
2743 case ALC_NUM_HRTF_SPECIFIERS_SOFT:
2744 device->enumerateHrtfs();
2745 values[0] = static_cast<int>(minz(device->mHrtfList.size(),
2746 std::numeric_limits<int>::max()));
2747 return 1;
2749 case ALC_OUTPUT_LIMITER_SOFT:
2750 values[0] = device->Limiter ? ALC_TRUE : ALC_FALSE;
2751 return 1;
2753 case ALC_MAX_AMBISONIC_ORDER_SOFT:
2754 values[0] = MaxAmbiOrder;
2755 return 1;
2757 case ALC_OUTPUT_MODE_SOFT:
2758 if(device->mHrtf)
2759 values[0] = ALC_HRTF_SOFT;
2760 else if(device->mUhjEncoder)
2761 values[0] = ALC_STEREO_UHJ_SOFT;
2762 else
2763 values[0] = ALC_NORMAL_SOFT;
2764 return 1;
2766 default:
2767 alcSetError(device, ALC_INVALID_ENUM);
2769 return 0;
2772 ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values)
2773 START_API_FUNC
2775 DeviceRef dev{VerifyDevice(device)};
2776 if(size <= 0 || values == nullptr)
2777 alcSetError(dev.get(), ALC_INVALID_VALUE);
2778 else
2779 GetIntegerv(dev.get(), param, {values, static_cast<uint>(size)});
2781 END_API_FUNC
2783 ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, ALCsizei size, ALCint64SOFT *values)
2784 START_API_FUNC
2786 DeviceRef dev{VerifyDevice(device)};
2787 if(size <= 0 || values == nullptr)
2789 alcSetError(dev.get(), ALC_INVALID_VALUE);
2790 return;
2792 if(!dev || dev->Type == DeviceType::Capture)
2794 auto ivals = al::vector<int>(static_cast<uint>(size));
2795 if(size_t got{GetIntegerv(dev.get(), pname, ivals)})
2796 std::copy_n(ivals.begin(), got, values);
2797 return;
2799 /* render device */
2800 auto NumAttrsForDevice = [](ALCdevice *aldev) noexcept
2802 if(aldev->Type == DeviceType::Loopback && aldev->FmtChans == DevFmtAmbi3D)
2803 return 39;
2804 return 33;
2806 std::lock_guard<std::mutex> _{dev->StateLock};
2807 switch(pname)
2809 case ALC_ATTRIBUTES_SIZE:
2810 *values = NumAttrsForDevice(dev.get());
2811 break;
2813 case ALC_ALL_ATTRIBUTES:
2814 if(size < NumAttrsForDevice(dev.get()))
2815 alcSetError(dev.get(), ALC_INVALID_VALUE);
2816 else
2818 size_t i{0};
2819 values[i++] = ALC_FREQUENCY;
2820 values[i++] = dev->Frequency;
2822 if(dev->Type != DeviceType::Loopback)
2824 values[i++] = ALC_REFRESH;
2825 values[i++] = dev->Frequency / dev->UpdateSize;
2827 values[i++] = ALC_SYNC;
2828 values[i++] = ALC_FALSE;
2830 else
2832 values[i++] = ALC_FORMAT_CHANNELS_SOFT;
2833 values[i++] = EnumFromDevFmt(dev->FmtChans);
2835 values[i++] = ALC_FORMAT_TYPE_SOFT;
2836 values[i++] = EnumFromDevFmt(dev->FmtType);
2838 if(dev->FmtChans == DevFmtAmbi3D)
2840 values[i++] = ALC_AMBISONIC_LAYOUT_SOFT;
2841 values[i++] = EnumFromDevAmbi(dev->mAmbiLayout);
2843 values[i++] = ALC_AMBISONIC_SCALING_SOFT;
2844 values[i++] = EnumFromDevAmbi(dev->mAmbiScale);
2846 values[i++] = ALC_AMBISONIC_ORDER_SOFT;
2847 values[i++] = dev->mAmbiOrder;
2851 values[i++] = ALC_MONO_SOURCES;
2852 values[i++] = dev->NumMonoSources;
2854 values[i++] = ALC_STEREO_SOURCES;
2855 values[i++] = dev->NumStereoSources;
2857 values[i++] = ALC_MAX_AUXILIARY_SENDS;
2858 values[i++] = dev->NumAuxSends;
2860 values[i++] = ALC_HRTF_SOFT;
2861 values[i++] = (dev->mHrtf ? ALC_TRUE : ALC_FALSE);
2863 values[i++] = ALC_HRTF_STATUS_SOFT;
2864 values[i++] = dev->mHrtfStatus;
2866 values[i++] = ALC_OUTPUT_LIMITER_SOFT;
2867 values[i++] = dev->Limiter ? ALC_TRUE : ALC_FALSE;
2869 ClockLatency clock{GetClockLatency(dev.get(), dev->Backend.get())};
2870 values[i++] = ALC_DEVICE_CLOCK_SOFT;
2871 values[i++] = clock.ClockTime.count();
2873 values[i++] = ALC_DEVICE_LATENCY_SOFT;
2874 values[i++] = clock.Latency.count();
2876 values[i++] = 0;
2878 break;
2880 case ALC_DEVICE_CLOCK_SOFT:
2882 uint samplecount, refcount;
2883 nanoseconds basecount;
2884 do {
2885 refcount = dev->waitForMix();
2886 basecount = dev->ClockBase;
2887 samplecount = dev->SamplesDone;
2888 } while(refcount != ReadRef(dev->MixCount));
2889 basecount += nanoseconds{seconds{samplecount}} / dev->Frequency;
2890 *values = basecount.count();
2892 break;
2894 case ALC_DEVICE_LATENCY_SOFT:
2895 *values = GetClockLatency(dev.get(), dev->Backend.get()).Latency.count();
2896 break;
2898 case ALC_DEVICE_CLOCK_LATENCY_SOFT:
2899 if(size < 2)
2900 alcSetError(dev.get(), ALC_INVALID_VALUE);
2901 else
2903 ClockLatency clock{GetClockLatency(dev.get(), dev->Backend.get())};
2904 values[0] = clock.ClockTime.count();
2905 values[1] = clock.Latency.count();
2907 break;
2909 default:
2910 auto ivals = al::vector<int>(static_cast<uint>(size));
2911 if(size_t got{GetIntegerv(dev.get(), pname, ivals)})
2912 std::copy_n(ivals.begin(), got, values);
2913 break;
2916 END_API_FUNC
2919 ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extName)
2920 START_API_FUNC
2922 DeviceRef dev{VerifyDevice(device)};
2923 if(!extName)
2924 alcSetError(dev.get(), ALC_INVALID_VALUE);
2925 else
2927 size_t len = strlen(extName);
2928 const char *ptr = (dev ? alcExtensionList : alcNoDeviceExtList);
2929 while(ptr && *ptr)
2931 if(al::strncasecmp(ptr, extName, len) == 0 && (ptr[len] == '\0' || isspace(ptr[len])))
2932 return ALC_TRUE;
2934 if((ptr=strchr(ptr, ' ')) != nullptr)
2936 do {
2937 ++ptr;
2938 } while(isspace(*ptr));
2942 return ALC_FALSE;
2944 END_API_FUNC
2947 ALC_API ALCvoid* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcName)
2948 START_API_FUNC
2950 if(!funcName)
2952 DeviceRef dev{VerifyDevice(device)};
2953 alcSetError(dev.get(), ALC_INVALID_VALUE);
2954 return nullptr;
2956 #ifdef ALSOFT_EAX
2957 if(eax_g_is_enabled)
2959 for(const auto &func : eaxFunctions)
2961 if(strcmp(func.funcName, funcName) == 0)
2962 return func.address;
2965 #endif
2966 for(const auto &func : alcFunctions)
2968 if(strcmp(func.funcName, funcName) == 0)
2969 return func.address;
2971 return nullptr;
2973 END_API_FUNC
2976 ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumName)
2977 START_API_FUNC
2979 if(!enumName)
2981 DeviceRef dev{VerifyDevice(device)};
2982 alcSetError(dev.get(), ALC_INVALID_VALUE);
2983 return 0;
2985 #ifdef ALSOFT_EAX
2986 if(eax_g_is_enabled)
2988 for(const auto &enm : eaxEnumerations)
2990 if(strcmp(enm.enumName, enumName) == 0)
2991 return enm.value;
2994 #endif
2995 for(const auto &enm : alcEnumerations)
2997 if(strcmp(enm.enumName, enumName) == 0)
2998 return enm.value;
3001 return 0;
3003 END_API_FUNC
3006 ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrList)
3007 START_API_FUNC
3009 /* Explicitly hold the list lock while taking the StateLock in case the
3010 * device is asynchronously destroyed, to ensure this new context is
3011 * properly cleaned up after being made.
3013 std::unique_lock<std::recursive_mutex> listlock{ListLock};
3014 DeviceRef dev{VerifyDevice(device)};
3015 if(!dev || dev->Type == DeviceType::Capture || !dev->Connected.load(std::memory_order_relaxed))
3017 listlock.unlock();
3018 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3019 return nullptr;
3021 std::unique_lock<std::mutex> statelock{dev->StateLock};
3022 listlock.unlock();
3024 dev->LastError.store(ALC_NO_ERROR);
3026 ALCenum err{UpdateDeviceParams(dev.get(), attrList)};
3027 if(err != ALC_NO_ERROR)
3029 alcSetError(dev.get(), err);
3030 return nullptr;
3033 ContextRef context{new ALCcontext{dev}};
3034 context->init();
3036 if(auto volopt = dev->configValue<float>(nullptr, "volume-adjust"))
3038 const float valf{*volopt};
3039 if(!std::isfinite(valf))
3040 ERR("volume-adjust must be finite: %f\n", valf);
3041 else
3043 const float db{clampf(valf, -24.0f, 24.0f)};
3044 if(db != valf)
3045 WARN("volume-adjust clamped: %f, range: +/-%f\n", valf, 24.0f);
3046 context->mGainBoost = std::pow(10.0f, db/20.0f);
3047 TRACE("volume-adjust gain: %f\n", context->mGainBoost);
3052 using ContextArray = al::FlexArray<ContextBase*>;
3054 /* Allocate a new context array, which holds 1 more than the current/
3055 * old array.
3057 auto *oldarray = device->mContexts.load();
3058 const size_t newcount{oldarray->size()+1};
3059 std::unique_ptr<ContextArray> newarray{ContextArray::Create(newcount)};
3061 /* Copy the current/old context handles to the new array, appending the
3062 * new context.
3064 auto iter = std::copy(oldarray->begin(), oldarray->end(), newarray->begin());
3065 *iter = context.get();
3067 /* Store the new context array in the device. Wait for any current mix
3068 * to finish before deleting the old array.
3070 dev->mContexts.store(newarray.release());
3071 if(oldarray != &DeviceBase::sEmptyContextArray)
3073 dev->waitForMix();
3074 delete oldarray;
3077 statelock.unlock();
3080 std::lock_guard<std::recursive_mutex> _{ListLock};
3081 auto iter = std::lower_bound(ContextList.cbegin(), ContextList.cend(), context.get());
3082 ContextList.emplace(iter, context.get());
3085 if(ALeffectslot *slot{context->mDefaultSlot.get()})
3087 ALenum sloterr{slot->initEffect(ALCcontext::sDefaultEffect.type,
3088 ALCcontext::sDefaultEffect.Props, context.get())};
3089 if(sloterr == AL_NO_ERROR)
3090 slot->updateProps(context.get());
3091 else
3092 ERR("Failed to initialize the default effect\n");
3095 TRACE("Created context %p\n", voidp{context.get()});
3096 return context.release();
3098 END_API_FUNC
3100 ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context)
3101 START_API_FUNC
3103 std::unique_lock<std::recursive_mutex> listlock{ListLock};
3104 auto iter = std::lower_bound(ContextList.begin(), ContextList.end(), context);
3105 if(iter == ContextList.end() || *iter != context)
3107 listlock.unlock();
3108 alcSetError(nullptr, ALC_INVALID_CONTEXT);
3109 return;
3112 /* Hold a reference to this context so it remains valid until the ListLock
3113 * is released.
3115 ContextRef ctx{*iter};
3116 ContextList.erase(iter);
3118 ALCdevice *Device{ctx->mALDevice.get()};
3120 std::lock_guard<std::mutex> _{Device->StateLock};
3121 if(!ctx->deinit() && Device->Flags.test(DeviceRunning))
3123 Device->Backend->stop();
3124 Device->Flags.reset(DeviceRunning);
3127 END_API_FUNC
3130 ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void)
3131 START_API_FUNC
3133 ALCcontext *Context{ALCcontext::getThreadContext()};
3134 if(!Context) Context = ALCcontext::sGlobalContext.load();
3135 return Context;
3137 END_API_FUNC
3139 /** Returns the currently active thread-local context. */
3140 ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void)
3141 START_API_FUNC
3142 { return ALCcontext::getThreadContext(); }
3143 END_API_FUNC
3145 ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context)
3146 START_API_FUNC
3148 /* context must be valid or nullptr */
3149 ContextRef ctx;
3150 if(context)
3152 ctx = VerifyContext(context);
3153 if(!ctx)
3155 alcSetError(nullptr, ALC_INVALID_CONTEXT);
3156 return ALC_FALSE;
3159 /* Release this reference (if any) to store it in the GlobalContext
3160 * pointer. Take ownership of the reference (if any) that was previously
3161 * stored there.
3163 ctx = ContextRef{ALCcontext::sGlobalContext.exchange(ctx.release())};
3165 /* Reset (decrement) the previous global reference by replacing it with the
3166 * thread-local context. Take ownership of the thread-local context
3167 * reference (if any), clearing the storage to null.
3169 ctx = ContextRef{ALCcontext::getThreadContext()};
3170 if(ctx) ALCcontext::setThreadContext(nullptr);
3171 /* Reset (decrement) the previous thread-local reference. */
3173 return ALC_TRUE;
3175 END_API_FUNC
3177 /** Makes the given context the active context for the current thread. */
3178 ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context)
3179 START_API_FUNC
3181 /* context must be valid or nullptr */
3182 ContextRef ctx;
3183 if(context)
3185 ctx = VerifyContext(context);
3186 if(!ctx)
3188 alcSetError(nullptr, ALC_INVALID_CONTEXT);
3189 return ALC_FALSE;
3192 /* context's reference count is already incremented */
3193 ContextRef old{ALCcontext::getThreadContext()};
3194 ALCcontext::setThreadContext(ctx.release());
3196 return ALC_TRUE;
3198 END_API_FUNC
3201 ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *Context)
3202 START_API_FUNC
3204 ContextRef ctx{VerifyContext(Context)};
3205 if(!ctx)
3207 alcSetError(nullptr, ALC_INVALID_CONTEXT);
3208 return nullptr;
3210 return ctx->mALDevice.get();
3212 END_API_FUNC
3215 ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
3216 START_API_FUNC
3218 DO_INITCONFIG();
3220 if(!PlaybackFactory)
3222 alcSetError(nullptr, ALC_INVALID_VALUE);
3223 return nullptr;
3226 if(deviceName)
3228 if(!deviceName[0] || al::strcasecmp(deviceName, alcDefaultName) == 0
3229 #ifdef _WIN32
3230 /* Some old Windows apps hardcode these expecting OpenAL to use a
3231 * specific audio API, even when they're not enumerated. Creative's
3232 * router effectively ignores them too.
3234 || al::strcasecmp(deviceName, "DirectSound3D") == 0
3235 || al::strcasecmp(deviceName, "DirectSound") == 0
3236 || al::strcasecmp(deviceName, "MMSYSTEM") == 0
3237 #endif
3238 /* Some old Linux apps hardcode configuration strings that were
3239 * supported by the OpenAL SI. We can't really do anything useful
3240 * with them, so just ignore.
3242 || (deviceName[0] == '\'' && deviceName[1] == '(')
3243 || al::strcasecmp(deviceName, "openal-soft") == 0)
3244 deviceName = nullptr;
3247 DeviceRef device{new ALCdevice{DeviceType::Playback}};
3249 /* Set output format */
3250 device->FmtChans = DevFmtChannelsDefault;
3251 device->FmtType = DevFmtTypeDefault;
3252 device->Frequency = DEFAULT_OUTPUT_RATE;
3253 device->UpdateSize = DEFAULT_UPDATE_SIZE;
3254 device->BufferSize = DEFAULT_UPDATE_SIZE * DEFAULT_NUM_UPDATES;
3256 device->SourcesMax = 256;
3257 device->AuxiliaryEffectSlotMax = 64;
3258 device->NumAuxSends = DEFAULT_SENDS;
3260 #ifdef ALSOFT_EAX
3261 if (eax_g_is_enabled)
3263 device->NumAuxSends = EAX_MAX_FXSLOTS;
3265 #endif // ALSOFT_EAX
3267 try {
3268 auto backend = PlaybackFactory->createBackend(device.get(), BackendType::Playback);
3269 std::lock_guard<std::recursive_mutex> _{ListLock};
3270 backend->open(deviceName);
3271 device->Backend = std::move(backend);
3273 catch(al::backend_exception &e) {
3274 WARN("Failed to open playback device: %s\n", e.what());
3275 alcSetError(nullptr, (e.errorCode() == al::backend_error::OutOfMemory)
3276 ? ALC_OUT_OF_MEMORY : ALC_INVALID_VALUE);
3277 return nullptr;
3280 if(auto chanopt = device->configValue<std::string>(nullptr, "channels"))
3282 static const struct ChannelMap {
3283 const char name[16];
3284 DevFmtChannels chans;
3285 uint order;
3286 } chanlist[] = {
3287 { "mono", DevFmtMono, 0 },
3288 { "stereo", DevFmtStereo, 0 },
3289 { "quad", DevFmtQuad, 0 },
3290 { "surround51", DevFmtX51, 0 },
3291 { "surround61", DevFmtX61, 0 },
3292 { "surround71", DevFmtX71, 0 },
3293 { "surround51rear", DevFmtX51, 0 },
3294 { "ambi1", DevFmtAmbi3D, 1 },
3295 { "ambi2", DevFmtAmbi3D, 2 },
3296 { "ambi3", DevFmtAmbi3D, 3 },
3299 const ALCchar *fmt{chanopt->c_str()};
3300 auto iter = std::find_if(std::begin(chanlist), std::end(chanlist),
3301 [fmt](const ChannelMap &entry) -> bool
3302 { return al::strcasecmp(entry.name, fmt) == 0; }
3304 if(iter == std::end(chanlist))
3305 ERR("Unsupported channels: %s\n", fmt);
3306 else
3308 device->FmtChans = iter->chans;
3309 device->mAmbiOrder = iter->order;
3310 device->Flags.set(ChannelsRequest);
3313 if(auto typeopt = device->configValue<std::string>(nullptr, "sample-type"))
3315 static const struct TypeMap {
3316 const char name[16];
3317 DevFmtType type;
3318 } typelist[] = {
3319 { "int8", DevFmtByte },
3320 { "uint8", DevFmtUByte },
3321 { "int16", DevFmtShort },
3322 { "uint16", DevFmtUShort },
3323 { "int32", DevFmtInt },
3324 { "uint32", DevFmtUInt },
3325 { "float32", DevFmtFloat },
3328 const ALCchar *fmt{typeopt->c_str()};
3329 auto iter = std::find_if(std::begin(typelist), std::end(typelist),
3330 [fmt](const TypeMap &entry) -> bool
3331 { return al::strcasecmp(entry.name, fmt) == 0; }
3333 if(iter == std::end(typelist))
3334 ERR("Unsupported sample-type: %s\n", fmt);
3335 else
3337 device->FmtType = iter->type;
3338 device->Flags.set(SampleTypeRequest);
3342 if(uint freq{device->configValue<uint>(nullptr, "frequency").value_or(0u)})
3344 if(freq < MIN_OUTPUT_RATE || freq > MAX_OUTPUT_RATE)
3346 const uint newfreq{clampu(freq, MIN_OUTPUT_RATE, MAX_OUTPUT_RATE)};
3347 ERR("%uhz request clamped to %uhz\n", freq, newfreq);
3348 freq = newfreq;
3350 const double scale{static_cast<double>(freq) / device->Frequency};
3351 device->UpdateSize = static_cast<uint>(device->UpdateSize*scale + 0.5);
3352 device->BufferSize = static_cast<uint>(device->BufferSize*scale + 0.5);
3353 device->Frequency = freq;
3354 device->Flags.set(FrequencyRequest);
3357 if(auto persizeopt = device->configValue<uint>(nullptr, "period_size"))
3358 device->UpdateSize = clampu(*persizeopt, 64, 8192);
3360 if(auto peropt = device->configValue<uint>(nullptr, "periods"))
3361 device->BufferSize = device->UpdateSize * clampu(*peropt, 2, 16);
3362 else
3363 device->BufferSize = maxu(device->BufferSize, device->UpdateSize*2);
3365 if(auto srcsmax = device->configValue<uint>(nullptr, "sources").value_or(0))
3366 device->SourcesMax = srcsmax;
3368 if(auto slotsmax = device->configValue<uint>(nullptr, "slots").value_or(0))
3369 device->AuxiliaryEffectSlotMax = minu(slotsmax, INT_MAX);
3371 if(auto sendsopt = device->configValue<int>(nullptr, "sends"))
3372 device->NumAuxSends = minu(DEFAULT_SENDS,
3373 static_cast<uint>(clampi(*sendsopt, 0, MAX_SENDS)));
3375 device->NumStereoSources = 1;
3376 device->NumMonoSources = device->SourcesMax - device->NumStereoSources;
3378 if(auto ambiopt = device->configValue<std::string>(nullptr, "ambi-format"))
3380 const ALCchar *fmt{ambiopt->c_str()};
3381 if(al::strcasecmp(fmt, "fuma") == 0)
3383 if(device->mAmbiOrder > 3)
3384 ERR("FuMa is incompatible with %d%s order ambisonics (up to third-order only)\n",
3385 device->mAmbiOrder,
3386 (((device->mAmbiOrder%100)/10) == 1) ? "th" :
3387 ((device->mAmbiOrder%10) == 1) ? "st" :
3388 ((device->mAmbiOrder%10) == 2) ? "nd" :
3389 ((device->mAmbiOrder%10) == 3) ? "rd" : "th");
3390 else
3392 device->mAmbiLayout = DevAmbiLayout::FuMa;
3393 device->mAmbiScale = DevAmbiScaling::FuMa;
3396 else if(al::strcasecmp(fmt, "acn+fuma") == 0)
3398 if(device->mAmbiOrder > 3)
3399 ERR("FuMa is incompatible with %d%s order ambisonics (up to third-order only)\n",
3400 device->mAmbiOrder,
3401 (((device->mAmbiOrder%100)/10) == 1) ? "th" :
3402 ((device->mAmbiOrder%10) == 1) ? "st" :
3403 ((device->mAmbiOrder%10) == 2) ? "nd" :
3404 ((device->mAmbiOrder%10) == 3) ? "rd" : "th");
3405 else
3407 device->mAmbiLayout = DevAmbiLayout::ACN;
3408 device->mAmbiScale = DevAmbiScaling::FuMa;
3411 else if(al::strcasecmp(fmt, "ambix") == 0 || al::strcasecmp(fmt, "acn+sn3d") == 0)
3413 device->mAmbiLayout = DevAmbiLayout::ACN;
3414 device->mAmbiScale = DevAmbiScaling::SN3D;
3416 else if(al::strcasecmp(fmt, "acn+n3d") == 0)
3418 device->mAmbiLayout = DevAmbiLayout::ACN;
3419 device->mAmbiScale = DevAmbiScaling::N3D;
3421 else
3422 ERR("Unsupported ambi-format: %s\n", fmt);
3426 std::lock_guard<std::recursive_mutex> _{ListLock};
3427 auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get());
3428 DeviceList.emplace(iter, device.get());
3431 TRACE("Created device %p, \"%s\"\n", voidp{device.get()}, device->DeviceName.c_str());
3432 return device.release();
3434 END_API_FUNC
3436 ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device)
3437 START_API_FUNC
3439 std::unique_lock<std::recursive_mutex> listlock{ListLock};
3440 auto iter = std::lower_bound(DeviceList.begin(), DeviceList.end(), device);
3441 if(iter == DeviceList.end() || *iter != device)
3443 alcSetError(nullptr, ALC_INVALID_DEVICE);
3444 return ALC_FALSE;
3446 if((*iter)->Type == DeviceType::Capture)
3448 alcSetError(*iter, ALC_INVALID_DEVICE);
3449 return ALC_FALSE;
3452 /* Erase the device, and any remaining contexts left on it, from their
3453 * respective lists.
3455 DeviceRef dev{*iter};
3456 DeviceList.erase(iter);
3458 std::unique_lock<std::mutex> statelock{dev->StateLock};
3459 al::vector<ContextRef> orphanctxs;
3460 for(ContextBase *ctx : *dev->mContexts.load())
3462 auto ctxiter = std::lower_bound(ContextList.begin(), ContextList.end(), ctx);
3463 if(ctxiter != ContextList.end() && *ctxiter == ctx)
3465 orphanctxs.emplace_back(ContextRef{*ctxiter});
3466 ContextList.erase(ctxiter);
3469 listlock.unlock();
3471 for(ContextRef &context : orphanctxs)
3473 WARN("Releasing orphaned context %p\n", voidp{context.get()});
3474 context->deinit();
3476 orphanctxs.clear();
3478 if(dev->Flags.test(DeviceRunning))
3479 dev->Backend->stop();
3480 dev->Flags.reset(DeviceRunning);
3482 return ALC_TRUE;
3484 END_API_FUNC
3487 /************************************************
3488 * ALC capture functions
3489 ************************************************/
3490 ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei samples)
3491 START_API_FUNC
3493 DO_INITCONFIG();
3495 if(!CaptureFactory)
3497 alcSetError(nullptr, ALC_INVALID_VALUE);
3498 return nullptr;
3501 if(samples <= 0)
3503 alcSetError(nullptr, ALC_INVALID_VALUE);
3504 return nullptr;
3507 if(deviceName)
3509 if(!deviceName[0] || al::strcasecmp(deviceName, alcDefaultName) == 0
3510 || al::strcasecmp(deviceName, "openal-soft") == 0)
3511 deviceName = nullptr;
3514 DeviceRef device{new ALCdevice{DeviceType::Capture}};
3516 auto decompfmt = DecomposeDevFormat(format);
3517 if(!decompfmt)
3519 alcSetError(nullptr, ALC_INVALID_ENUM);
3520 return nullptr;
3523 device->Frequency = frequency;
3524 device->FmtChans = decompfmt->chans;
3525 device->FmtType = decompfmt->type;
3526 device->Flags.set(FrequencyRequest);
3527 device->Flags.set(ChannelsRequest);
3528 device->Flags.set(SampleTypeRequest);
3530 device->UpdateSize = static_cast<uint>(samples);
3531 device->BufferSize = static_cast<uint>(samples);
3533 try {
3534 TRACE("Capture format: %s, %s, %uhz, %u / %u buffer\n",
3535 DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType),
3536 device->Frequency, device->UpdateSize, device->BufferSize);
3538 auto backend = CaptureFactory->createBackend(device.get(), BackendType::Capture);
3539 std::lock_guard<std::recursive_mutex> _{ListLock};
3540 backend->open(deviceName);
3541 device->Backend = std::move(backend);
3543 catch(al::backend_exception &e) {
3544 WARN("Failed to open capture device: %s\n", e.what());
3545 alcSetError(nullptr, (e.errorCode() == al::backend_error::OutOfMemory)
3546 ? ALC_OUT_OF_MEMORY : ALC_INVALID_VALUE);
3547 return nullptr;
3551 std::lock_guard<std::recursive_mutex> _{ListLock};
3552 auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get());
3553 DeviceList.emplace(iter, device.get());
3556 TRACE("Created capture device %p, \"%s\"\n", voidp{device.get()}, device->DeviceName.c_str());
3557 return device.release();
3559 END_API_FUNC
3561 ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device)
3562 START_API_FUNC
3564 std::unique_lock<std::recursive_mutex> listlock{ListLock};
3565 auto iter = std::lower_bound(DeviceList.begin(), DeviceList.end(), device);
3566 if(iter == DeviceList.end() || *iter != device)
3568 alcSetError(nullptr, ALC_INVALID_DEVICE);
3569 return ALC_FALSE;
3571 if((*iter)->Type != DeviceType::Capture)
3573 alcSetError(*iter, ALC_INVALID_DEVICE);
3574 return ALC_FALSE;
3577 DeviceRef dev{*iter};
3578 DeviceList.erase(iter);
3579 listlock.unlock();
3581 std::lock_guard<std::mutex> _{dev->StateLock};
3582 if(dev->Flags.test(DeviceRunning))
3583 dev->Backend->stop();
3584 dev->Flags.reset(DeviceRunning);
3586 return ALC_TRUE;
3588 END_API_FUNC
3590 ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device)
3591 START_API_FUNC
3593 DeviceRef dev{VerifyDevice(device)};
3594 if(!dev || dev->Type != DeviceType::Capture)
3596 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3597 return;
3600 std::lock_guard<std::mutex> _{dev->StateLock};
3601 if(!dev->Connected.load(std::memory_order_acquire))
3602 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3603 else if(!dev->Flags.test(DeviceRunning))
3605 try {
3606 auto backend = dev->Backend.get();
3607 backend->start();
3608 dev->Flags.set(DeviceRunning);
3610 catch(al::backend_exception& e) {
3611 ERR("%s\n", e.what());
3612 dev->handleDisconnect("%s", e.what());
3613 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3617 END_API_FUNC
3619 ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device)
3620 START_API_FUNC
3622 DeviceRef dev{VerifyDevice(device)};
3623 if(!dev || dev->Type != DeviceType::Capture)
3624 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3625 else
3627 std::lock_guard<std::mutex> _{dev->StateLock};
3628 if(dev->Flags.test(DeviceRunning))
3629 dev->Backend->stop();
3630 dev->Flags.reset(DeviceRunning);
3633 END_API_FUNC
3635 ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples)
3636 START_API_FUNC
3638 DeviceRef dev{VerifyDevice(device)};
3639 if(!dev || dev->Type != DeviceType::Capture)
3641 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3642 return;
3645 if(samples < 0 || (samples > 0 && buffer == nullptr))
3647 alcSetError(dev.get(), ALC_INVALID_VALUE);
3648 return;
3650 if(samples < 1)
3651 return;
3653 std::lock_guard<std::mutex> _{dev->StateLock};
3654 BackendBase *backend{dev->Backend.get()};
3656 const auto usamples = static_cast<uint>(samples);
3657 if(usamples > backend->availableSamples())
3659 alcSetError(dev.get(), ALC_INVALID_VALUE);
3660 return;
3663 backend->captureSamples(static_cast<al::byte*>(buffer), usamples);
3665 END_API_FUNC
3668 /************************************************
3669 * ALC loopback functions
3670 ************************************************/
3672 /** Open a loopback device, for manual rendering. */
3673 ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName)
3674 START_API_FUNC
3676 DO_INITCONFIG();
3678 /* Make sure the device name, if specified, is us. */
3679 if(deviceName && strcmp(deviceName, alcDefaultName) != 0)
3681 alcSetError(nullptr, ALC_INVALID_VALUE);
3682 return nullptr;
3685 DeviceRef device{new ALCdevice{DeviceType::Loopback}};
3687 device->SourcesMax = 256;
3688 device->AuxiliaryEffectSlotMax = 64;
3689 device->NumAuxSends = DEFAULT_SENDS;
3691 //Set output format
3692 device->BufferSize = 0;
3693 device->UpdateSize = 0;
3695 device->Frequency = DEFAULT_OUTPUT_RATE;
3696 device->FmtChans = DevFmtChannelsDefault;
3697 device->FmtType = DevFmtTypeDefault;
3699 if(auto srcsmax = ConfigValueUInt(nullptr, nullptr, "sources").value_or(0))
3700 device->SourcesMax = srcsmax;
3702 if(auto slotsmax = ConfigValueUInt(nullptr, nullptr, "slots").value_or(0))
3703 device->AuxiliaryEffectSlotMax = minu(slotsmax, INT_MAX);
3705 if(auto sendsopt = ConfigValueInt(nullptr, nullptr, "sends"))
3706 device->NumAuxSends = minu(DEFAULT_SENDS,
3707 static_cast<uint>(clampi(*sendsopt, 0, MAX_SENDS)));
3709 device->NumStereoSources = 1;
3710 device->NumMonoSources = device->SourcesMax - device->NumStereoSources;
3712 try {
3713 auto backend = LoopbackBackendFactory::getFactory().createBackend(device.get(),
3714 BackendType::Playback);
3715 backend->open("Loopback");
3716 device->Backend = std::move(backend);
3718 catch(al::backend_exception &e) {
3719 WARN("Failed to open loopback device: %s\n", e.what());
3720 alcSetError(nullptr, (e.errorCode() == al::backend_error::OutOfMemory)
3721 ? ALC_OUT_OF_MEMORY : ALC_INVALID_VALUE);
3722 return nullptr;
3726 std::lock_guard<std::recursive_mutex> _{ListLock};
3727 auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get());
3728 DeviceList.emplace(iter, device.get());
3731 TRACE("Created loopback device %p\n", voidp{device.get()});
3732 return device.release();
3734 END_API_FUNC
3737 * Determines if the loopback device supports the given format for rendering.
3739 ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type)
3740 START_API_FUNC
3742 DeviceRef dev{VerifyDevice(device)};
3743 if(!dev || dev->Type != DeviceType::Loopback)
3744 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3745 else if(freq <= 0)
3746 alcSetError(dev.get(), ALC_INVALID_VALUE);
3747 else
3749 if(DevFmtTypeFromEnum(type).has_value() && DevFmtChannelsFromEnum(channels).has_value()
3750 && freq >= MIN_OUTPUT_RATE && freq <= MAX_OUTPUT_RATE)
3751 return ALC_TRUE;
3754 return ALC_FALSE;
3756 END_API_FUNC
3759 * Renders some samples into a buffer, using the format last set by the
3760 * attributes given to alcCreateContext.
3762 FORCE_ALIGN ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples)
3763 START_API_FUNC
3765 if(!device || device->Type != DeviceType::Loopback)
3766 alcSetError(device, ALC_INVALID_DEVICE);
3767 else if(samples < 0 || (samples > 0 && buffer == nullptr))
3768 alcSetError(device, ALC_INVALID_VALUE);
3769 else
3770 device->renderSamples(buffer, static_cast<uint>(samples), device->channelsFromFmt());
3772 END_API_FUNC
3775 /************************************************
3776 * ALC DSP pause/resume functions
3777 ************************************************/
3779 /** Pause the DSP to stop audio processing. */
3780 ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device)
3781 START_API_FUNC
3783 DeviceRef dev{VerifyDevice(device)};
3784 if(!dev || dev->Type != DeviceType::Playback)
3785 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3786 else
3788 std::lock_guard<std::mutex> _{dev->StateLock};
3789 if(dev->Flags.test(DeviceRunning))
3790 dev->Backend->stop();
3791 dev->Flags.reset(DeviceRunning);
3792 dev->Flags.set(DevicePaused);
3795 END_API_FUNC
3797 /** Resume the DSP to restart audio processing. */
3798 ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device)
3799 START_API_FUNC
3801 DeviceRef dev{VerifyDevice(device)};
3802 if(!dev || dev->Type != DeviceType::Playback)
3804 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3805 return;
3808 std::lock_guard<std::mutex> _{dev->StateLock};
3809 if(!dev->Flags.test(DevicePaused))
3810 return;
3811 dev->Flags.reset(DevicePaused);
3812 if(dev->mContexts.load()->empty())
3813 return;
3815 try {
3816 auto backend = dev->Backend.get();
3817 backend->start();
3818 dev->Flags.set(DeviceRunning);
3820 catch(al::backend_exception& e) {
3821 ERR("%s\n", e.what());
3822 dev->handleDisconnect("%s", e.what());
3823 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3824 return;
3826 TRACE("Post-resume: %s, %s, %uhz, %u / %u buffer\n",
3827 DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType),
3828 device->Frequency, device->UpdateSize, device->BufferSize);
3830 END_API_FUNC
3833 /************************************************
3834 * ALC HRTF functions
3835 ************************************************/
3837 /** Gets a string parameter at the given index. */
3838 ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index)
3839 START_API_FUNC
3841 DeviceRef dev{VerifyDevice(device)};
3842 if(!dev || dev->Type == DeviceType::Capture)
3843 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3844 else switch(paramName)
3846 case ALC_HRTF_SPECIFIER_SOFT:
3847 if(index >= 0 && static_cast<uint>(index) < dev->mHrtfList.size())
3848 return dev->mHrtfList[static_cast<uint>(index)].c_str();
3849 alcSetError(dev.get(), ALC_INVALID_VALUE);
3850 break;
3852 default:
3853 alcSetError(dev.get(), ALC_INVALID_ENUM);
3854 break;
3857 return nullptr;
3859 END_API_FUNC
3861 /** Resets the given device output, using the specified attribute list. */
3862 ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs)
3863 START_API_FUNC
3865 std::unique_lock<std::recursive_mutex> listlock{ListLock};
3866 DeviceRef dev{VerifyDevice(device)};
3867 if(!dev || dev->Type == DeviceType::Capture)
3869 listlock.unlock();
3870 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3871 return ALC_FALSE;
3873 std::lock_guard<std::mutex> _{dev->StateLock};
3874 listlock.unlock();
3876 /* Force the backend to stop mixing first since we're resetting. Also reset
3877 * the connected state so lost devices can attempt recover.
3879 if(dev->Flags.test(DeviceRunning))
3880 dev->Backend->stop();
3881 dev->Flags.reset(DeviceRunning);
3883 return ResetDeviceParams(dev.get(), attribs) ? ALC_TRUE : ALC_FALSE;
3885 END_API_FUNC
3888 /************************************************
3889 * ALC device reopen functions
3890 ************************************************/
3892 /** Reopens the given device output, using the specified name and attribute list. */
3893 FORCE_ALIGN ALCboolean ALC_APIENTRY alcReopenDeviceSOFT(ALCdevice *device,
3894 const ALCchar *deviceName, const ALCint *attribs)
3895 START_API_FUNC
3897 if(deviceName)
3899 if(!deviceName[0] || al::strcasecmp(deviceName, alcDefaultName) == 0)
3900 deviceName = nullptr;
3903 std::unique_lock<std::recursive_mutex> listlock{ListLock};
3904 DeviceRef dev{VerifyDevice(device)};
3905 if(!dev || dev->Type != DeviceType::Playback)
3907 listlock.unlock();
3908 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3909 return ALC_FALSE;
3911 std::lock_guard<std::mutex> _{dev->StateLock};
3913 /* Force the backend to stop mixing first since we're reopening. */
3914 if(dev->Flags.test(DeviceRunning))
3916 auto backend = dev->Backend.get();
3917 backend->stop();
3918 dev->Flags.reset(DeviceRunning);
3921 BackendPtr newbackend;
3922 try {
3923 newbackend = PlaybackFactory->createBackend(dev.get(), BackendType::Playback);
3924 newbackend->open(deviceName);
3926 catch(al::backend_exception &e) {
3927 listlock.unlock();
3928 newbackend = nullptr;
3930 WARN("Failed to reopen playback device: %s\n", e.what());
3931 alcSetError(dev.get(), (e.errorCode() == al::backend_error::OutOfMemory)
3932 ? ALC_OUT_OF_MEMORY : ALC_INVALID_VALUE);
3934 /* If the device is connected, not paused, and has contexts, ensure it
3935 * continues playing.
3937 if(dev->Connected.load(std::memory_order_relaxed) && !dev->Flags.test(DevicePaused)
3938 && !dev->mContexts.load(std::memory_order_relaxed)->empty())
3940 try {
3941 auto backend = dev->Backend.get();
3942 backend->start();
3943 dev->Flags.set(DeviceRunning);
3945 catch(al::backend_exception &be) {
3946 ERR("%s\n", be.what());
3947 dev->handleDisconnect("%s", be.what());
3950 return ALC_FALSE;
3952 listlock.unlock();
3953 dev->Backend = std::move(newbackend);
3954 TRACE("Reopened device %p, \"%s\"\n", voidp{dev.get()}, dev->DeviceName.c_str());
3956 /* Always return true even if resetting fails. It shouldn't fail, but this
3957 * is primarily to avoid confusion by the app seeing the function return
3958 * false while the device is on the new output anyway. We could try to
3959 * restore the old backend if this fails, but the configuration would be
3960 * changed with the new backend and would need to be reset again with the
3961 * old one, and the provided attributes may not be appropriate or desirable
3962 * for the old device.
3964 * In this way, we essentially act as if the function succeeded, but
3965 * immediately disconnects following it.
3967 ResetDeviceParams(dev.get(), attribs);
3968 return ALC_TRUE;
3970 END_API_FUNC