Handle 3D7.1 as a separate channel configuration
[openal-soft.git] / alc / alc.cpp
blob686b794e3d3dfc4d4e8d7c79c6b20668503c3e20
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_ANY_SOFT),
541 DECL(ALC_STEREO_BASIC_SOFT),
542 DECL(ALC_STEREO_UHJ_SOFT),
543 DECL(ALC_STEREO_HRTF_SOFT),
544 DECL(ALC_SURROUND_5_1_SOFT),
545 DECL(ALC_SURROUND_6_1_SOFT),
546 DECL(ALC_SURROUND_7_1_SOFT),
548 DECL(ALC_NO_ERROR),
549 DECL(ALC_INVALID_DEVICE),
550 DECL(ALC_INVALID_CONTEXT),
551 DECL(ALC_INVALID_ENUM),
552 DECL(ALC_INVALID_VALUE),
553 DECL(ALC_OUT_OF_MEMORY),
556 DECL(AL_INVALID),
557 DECL(AL_NONE),
558 DECL(AL_FALSE),
559 DECL(AL_TRUE),
561 DECL(AL_SOURCE_RELATIVE),
562 DECL(AL_CONE_INNER_ANGLE),
563 DECL(AL_CONE_OUTER_ANGLE),
564 DECL(AL_PITCH),
565 DECL(AL_POSITION),
566 DECL(AL_DIRECTION),
567 DECL(AL_VELOCITY),
568 DECL(AL_LOOPING),
569 DECL(AL_BUFFER),
570 DECL(AL_GAIN),
571 DECL(AL_MIN_GAIN),
572 DECL(AL_MAX_GAIN),
573 DECL(AL_ORIENTATION),
574 DECL(AL_REFERENCE_DISTANCE),
575 DECL(AL_ROLLOFF_FACTOR),
576 DECL(AL_CONE_OUTER_GAIN),
577 DECL(AL_MAX_DISTANCE),
578 DECL(AL_SEC_OFFSET),
579 DECL(AL_SAMPLE_OFFSET),
580 DECL(AL_BYTE_OFFSET),
581 DECL(AL_SOURCE_TYPE),
582 DECL(AL_STATIC),
583 DECL(AL_STREAMING),
584 DECL(AL_UNDETERMINED),
585 DECL(AL_METERS_PER_UNIT),
586 DECL(AL_LOOP_POINTS_SOFT),
587 DECL(AL_DIRECT_CHANNELS_SOFT),
589 DECL(AL_DIRECT_FILTER),
590 DECL(AL_AUXILIARY_SEND_FILTER),
591 DECL(AL_AIR_ABSORPTION_FACTOR),
592 DECL(AL_ROOM_ROLLOFF_FACTOR),
593 DECL(AL_CONE_OUTER_GAINHF),
594 DECL(AL_DIRECT_FILTER_GAINHF_AUTO),
595 DECL(AL_AUXILIARY_SEND_FILTER_GAIN_AUTO),
596 DECL(AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO),
598 DECL(AL_SOURCE_STATE),
599 DECL(AL_INITIAL),
600 DECL(AL_PLAYING),
601 DECL(AL_PAUSED),
602 DECL(AL_STOPPED),
604 DECL(AL_BUFFERS_QUEUED),
605 DECL(AL_BUFFERS_PROCESSED),
607 DECL(AL_FORMAT_MONO8),
608 DECL(AL_FORMAT_MONO16),
609 DECL(AL_FORMAT_MONO_FLOAT32),
610 DECL(AL_FORMAT_MONO_DOUBLE_EXT),
611 DECL(AL_FORMAT_STEREO8),
612 DECL(AL_FORMAT_STEREO16),
613 DECL(AL_FORMAT_STEREO_FLOAT32),
614 DECL(AL_FORMAT_STEREO_DOUBLE_EXT),
615 DECL(AL_FORMAT_MONO_IMA4),
616 DECL(AL_FORMAT_STEREO_IMA4),
617 DECL(AL_FORMAT_MONO_MSADPCM_SOFT),
618 DECL(AL_FORMAT_STEREO_MSADPCM_SOFT),
619 DECL(AL_FORMAT_QUAD8_LOKI),
620 DECL(AL_FORMAT_QUAD16_LOKI),
621 DECL(AL_FORMAT_QUAD8),
622 DECL(AL_FORMAT_QUAD16),
623 DECL(AL_FORMAT_QUAD32),
624 DECL(AL_FORMAT_51CHN8),
625 DECL(AL_FORMAT_51CHN16),
626 DECL(AL_FORMAT_51CHN32),
627 DECL(AL_FORMAT_61CHN8),
628 DECL(AL_FORMAT_61CHN16),
629 DECL(AL_FORMAT_61CHN32),
630 DECL(AL_FORMAT_71CHN8),
631 DECL(AL_FORMAT_71CHN16),
632 DECL(AL_FORMAT_71CHN32),
633 DECL(AL_FORMAT_REAR8),
634 DECL(AL_FORMAT_REAR16),
635 DECL(AL_FORMAT_REAR32),
636 DECL(AL_FORMAT_MONO_MULAW),
637 DECL(AL_FORMAT_MONO_MULAW_EXT),
638 DECL(AL_FORMAT_STEREO_MULAW),
639 DECL(AL_FORMAT_STEREO_MULAW_EXT),
640 DECL(AL_FORMAT_QUAD_MULAW),
641 DECL(AL_FORMAT_51CHN_MULAW),
642 DECL(AL_FORMAT_61CHN_MULAW),
643 DECL(AL_FORMAT_71CHN_MULAW),
644 DECL(AL_FORMAT_REAR_MULAW),
645 DECL(AL_FORMAT_MONO_ALAW_EXT),
646 DECL(AL_FORMAT_STEREO_ALAW_EXT),
648 DECL(AL_FORMAT_BFORMAT2D_8),
649 DECL(AL_FORMAT_BFORMAT2D_16),
650 DECL(AL_FORMAT_BFORMAT2D_FLOAT32),
651 DECL(AL_FORMAT_BFORMAT2D_MULAW),
652 DECL(AL_FORMAT_BFORMAT3D_8),
653 DECL(AL_FORMAT_BFORMAT3D_16),
654 DECL(AL_FORMAT_BFORMAT3D_FLOAT32),
655 DECL(AL_FORMAT_BFORMAT3D_MULAW),
657 DECL(AL_FREQUENCY),
658 DECL(AL_BITS),
659 DECL(AL_CHANNELS),
660 DECL(AL_SIZE),
661 DECL(AL_UNPACK_BLOCK_ALIGNMENT_SOFT),
662 DECL(AL_PACK_BLOCK_ALIGNMENT_SOFT),
664 DECL(AL_SOURCE_RADIUS),
666 DECL(AL_STEREO_ANGLES),
668 DECL(AL_UNUSED),
669 DECL(AL_PENDING),
670 DECL(AL_PROCESSED),
672 DECL(AL_NO_ERROR),
673 DECL(AL_INVALID_NAME),
674 DECL(AL_INVALID_ENUM),
675 DECL(AL_INVALID_VALUE),
676 DECL(AL_INVALID_OPERATION),
677 DECL(AL_OUT_OF_MEMORY),
679 DECL(AL_VENDOR),
680 DECL(AL_VERSION),
681 DECL(AL_RENDERER),
682 DECL(AL_EXTENSIONS),
684 DECL(AL_DOPPLER_FACTOR),
685 DECL(AL_DOPPLER_VELOCITY),
686 DECL(AL_DISTANCE_MODEL),
687 DECL(AL_SPEED_OF_SOUND),
688 DECL(AL_SOURCE_DISTANCE_MODEL),
689 DECL(AL_DEFERRED_UPDATES_SOFT),
690 DECL(AL_GAIN_LIMIT_SOFT),
692 DECL(AL_INVERSE_DISTANCE),
693 DECL(AL_INVERSE_DISTANCE_CLAMPED),
694 DECL(AL_LINEAR_DISTANCE),
695 DECL(AL_LINEAR_DISTANCE_CLAMPED),
696 DECL(AL_EXPONENT_DISTANCE),
697 DECL(AL_EXPONENT_DISTANCE_CLAMPED),
699 DECL(AL_FILTER_TYPE),
700 DECL(AL_FILTER_NULL),
701 DECL(AL_FILTER_LOWPASS),
702 DECL(AL_FILTER_HIGHPASS),
703 DECL(AL_FILTER_BANDPASS),
705 DECL(AL_LOWPASS_GAIN),
706 DECL(AL_LOWPASS_GAINHF),
708 DECL(AL_HIGHPASS_GAIN),
709 DECL(AL_HIGHPASS_GAINLF),
711 DECL(AL_BANDPASS_GAIN),
712 DECL(AL_BANDPASS_GAINHF),
713 DECL(AL_BANDPASS_GAINLF),
715 DECL(AL_EFFECT_TYPE),
716 DECL(AL_EFFECT_NULL),
717 DECL(AL_EFFECT_REVERB),
718 DECL(AL_EFFECT_EAXREVERB),
719 DECL(AL_EFFECT_CHORUS),
720 DECL(AL_EFFECT_DISTORTION),
721 DECL(AL_EFFECT_ECHO),
722 DECL(AL_EFFECT_FLANGER),
723 DECL(AL_EFFECT_PITCH_SHIFTER),
724 DECL(AL_EFFECT_FREQUENCY_SHIFTER),
725 DECL(AL_EFFECT_VOCAL_MORPHER),
726 DECL(AL_EFFECT_RING_MODULATOR),
727 DECL(AL_EFFECT_AUTOWAH),
728 DECL(AL_EFFECT_COMPRESSOR),
729 DECL(AL_EFFECT_EQUALIZER),
730 DECL(AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT),
731 DECL(AL_EFFECT_DEDICATED_DIALOGUE),
733 DECL(AL_EFFECTSLOT_EFFECT),
734 DECL(AL_EFFECTSLOT_GAIN),
735 DECL(AL_EFFECTSLOT_AUXILIARY_SEND_AUTO),
736 DECL(AL_EFFECTSLOT_NULL),
738 DECL(AL_EAXREVERB_DENSITY),
739 DECL(AL_EAXREVERB_DIFFUSION),
740 DECL(AL_EAXREVERB_GAIN),
741 DECL(AL_EAXREVERB_GAINHF),
742 DECL(AL_EAXREVERB_GAINLF),
743 DECL(AL_EAXREVERB_DECAY_TIME),
744 DECL(AL_EAXREVERB_DECAY_HFRATIO),
745 DECL(AL_EAXREVERB_DECAY_LFRATIO),
746 DECL(AL_EAXREVERB_REFLECTIONS_GAIN),
747 DECL(AL_EAXREVERB_REFLECTIONS_DELAY),
748 DECL(AL_EAXREVERB_REFLECTIONS_PAN),
749 DECL(AL_EAXREVERB_LATE_REVERB_GAIN),
750 DECL(AL_EAXREVERB_LATE_REVERB_DELAY),
751 DECL(AL_EAXREVERB_LATE_REVERB_PAN),
752 DECL(AL_EAXREVERB_ECHO_TIME),
753 DECL(AL_EAXREVERB_ECHO_DEPTH),
754 DECL(AL_EAXREVERB_MODULATION_TIME),
755 DECL(AL_EAXREVERB_MODULATION_DEPTH),
756 DECL(AL_EAXREVERB_AIR_ABSORPTION_GAINHF),
757 DECL(AL_EAXREVERB_HFREFERENCE),
758 DECL(AL_EAXREVERB_LFREFERENCE),
759 DECL(AL_EAXREVERB_ROOM_ROLLOFF_FACTOR),
760 DECL(AL_EAXREVERB_DECAY_HFLIMIT),
762 DECL(AL_REVERB_DENSITY),
763 DECL(AL_REVERB_DIFFUSION),
764 DECL(AL_REVERB_GAIN),
765 DECL(AL_REVERB_GAINHF),
766 DECL(AL_REVERB_DECAY_TIME),
767 DECL(AL_REVERB_DECAY_HFRATIO),
768 DECL(AL_REVERB_REFLECTIONS_GAIN),
769 DECL(AL_REVERB_REFLECTIONS_DELAY),
770 DECL(AL_REVERB_LATE_REVERB_GAIN),
771 DECL(AL_REVERB_LATE_REVERB_DELAY),
772 DECL(AL_REVERB_AIR_ABSORPTION_GAINHF),
773 DECL(AL_REVERB_ROOM_ROLLOFF_FACTOR),
774 DECL(AL_REVERB_DECAY_HFLIMIT),
776 DECL(AL_CHORUS_WAVEFORM),
777 DECL(AL_CHORUS_PHASE),
778 DECL(AL_CHORUS_RATE),
779 DECL(AL_CHORUS_DEPTH),
780 DECL(AL_CHORUS_FEEDBACK),
781 DECL(AL_CHORUS_DELAY),
783 DECL(AL_DISTORTION_EDGE),
784 DECL(AL_DISTORTION_GAIN),
785 DECL(AL_DISTORTION_LOWPASS_CUTOFF),
786 DECL(AL_DISTORTION_EQCENTER),
787 DECL(AL_DISTORTION_EQBANDWIDTH),
789 DECL(AL_ECHO_DELAY),
790 DECL(AL_ECHO_LRDELAY),
791 DECL(AL_ECHO_DAMPING),
792 DECL(AL_ECHO_FEEDBACK),
793 DECL(AL_ECHO_SPREAD),
795 DECL(AL_FLANGER_WAVEFORM),
796 DECL(AL_FLANGER_PHASE),
797 DECL(AL_FLANGER_RATE),
798 DECL(AL_FLANGER_DEPTH),
799 DECL(AL_FLANGER_FEEDBACK),
800 DECL(AL_FLANGER_DELAY),
802 DECL(AL_FREQUENCY_SHIFTER_FREQUENCY),
803 DECL(AL_FREQUENCY_SHIFTER_LEFT_DIRECTION),
804 DECL(AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION),
806 DECL(AL_RING_MODULATOR_FREQUENCY),
807 DECL(AL_RING_MODULATOR_HIGHPASS_CUTOFF),
808 DECL(AL_RING_MODULATOR_WAVEFORM),
810 DECL(AL_PITCH_SHIFTER_COARSE_TUNE),
811 DECL(AL_PITCH_SHIFTER_FINE_TUNE),
813 DECL(AL_COMPRESSOR_ONOFF),
815 DECL(AL_EQUALIZER_LOW_GAIN),
816 DECL(AL_EQUALIZER_LOW_CUTOFF),
817 DECL(AL_EQUALIZER_MID1_GAIN),
818 DECL(AL_EQUALIZER_MID1_CENTER),
819 DECL(AL_EQUALIZER_MID1_WIDTH),
820 DECL(AL_EQUALIZER_MID2_GAIN),
821 DECL(AL_EQUALIZER_MID2_CENTER),
822 DECL(AL_EQUALIZER_MID2_WIDTH),
823 DECL(AL_EQUALIZER_HIGH_GAIN),
824 DECL(AL_EQUALIZER_HIGH_CUTOFF),
826 DECL(AL_DEDICATED_GAIN),
828 DECL(AL_AUTOWAH_ATTACK_TIME),
829 DECL(AL_AUTOWAH_RELEASE_TIME),
830 DECL(AL_AUTOWAH_RESONANCE),
831 DECL(AL_AUTOWAH_PEAK_GAIN),
833 DECL(AL_VOCAL_MORPHER_PHONEMEA),
834 DECL(AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING),
835 DECL(AL_VOCAL_MORPHER_PHONEMEB),
836 DECL(AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING),
837 DECL(AL_VOCAL_MORPHER_WAVEFORM),
838 DECL(AL_VOCAL_MORPHER_RATE),
840 DECL(AL_EFFECTSLOT_TARGET_SOFT),
842 DECL(AL_NUM_RESAMPLERS_SOFT),
843 DECL(AL_DEFAULT_RESAMPLER_SOFT),
844 DECL(AL_SOURCE_RESAMPLER_SOFT),
845 DECL(AL_RESAMPLER_NAME_SOFT),
847 DECL(AL_SOURCE_SPATIALIZE_SOFT),
848 DECL(AL_AUTO_SOFT),
850 DECL(AL_MAP_READ_BIT_SOFT),
851 DECL(AL_MAP_WRITE_BIT_SOFT),
852 DECL(AL_MAP_PERSISTENT_BIT_SOFT),
853 DECL(AL_PRESERVE_DATA_BIT_SOFT),
855 DECL(AL_EVENT_CALLBACK_FUNCTION_SOFT),
856 DECL(AL_EVENT_CALLBACK_USER_PARAM_SOFT),
857 DECL(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT),
858 DECL(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT),
859 DECL(AL_EVENT_TYPE_DISCONNECTED_SOFT),
861 DECL(AL_DROP_UNMATCHED_SOFT),
862 DECL(AL_REMIX_UNMATCHED_SOFT),
864 DECL(AL_AMBISONIC_LAYOUT_SOFT),
865 DECL(AL_AMBISONIC_SCALING_SOFT),
866 DECL(AL_FUMA_SOFT),
867 DECL(AL_ACN_SOFT),
868 DECL(AL_SN3D_SOFT),
869 DECL(AL_N3D_SOFT),
871 DECL(AL_BUFFER_CALLBACK_FUNCTION_SOFT),
872 DECL(AL_BUFFER_CALLBACK_USER_PARAM_SOFT),
874 DECL(AL_UNPACK_AMBISONIC_ORDER_SOFT),
876 DECL(AL_EFFECT_CONVOLUTION_REVERB_SOFT),
877 DECL(AL_EFFECTSLOT_STATE_SOFT),
879 DECL(AL_FORMAT_UHJ2CHN8_SOFT),
880 DECL(AL_FORMAT_UHJ2CHN16_SOFT),
881 DECL(AL_FORMAT_UHJ2CHN_FLOAT32_SOFT),
882 DECL(AL_FORMAT_UHJ3CHN8_SOFT),
883 DECL(AL_FORMAT_UHJ3CHN16_SOFT),
884 DECL(AL_FORMAT_UHJ3CHN_FLOAT32_SOFT),
885 DECL(AL_FORMAT_UHJ4CHN8_SOFT),
886 DECL(AL_FORMAT_UHJ4CHN16_SOFT),
887 DECL(AL_FORMAT_UHJ4CHN_FLOAT32_SOFT),
888 DECL(AL_STEREO_MODE_SOFT),
889 DECL(AL_NORMAL_SOFT),
890 DECL(AL_SUPER_STEREO_SOFT),
891 DECL(AL_SUPER_STEREO_WIDTH_SOFT),
893 DECL(AL_STOP_SOURCES_ON_DISCONNECT_SOFT),
895 #ifdef ALSOFT_EAX
896 }, eaxEnumerations[] = {
897 DECL(AL_EAX_RAM_SIZE),
898 DECL(AL_EAX_RAM_FREE),
899 DECL(AL_STORAGE_AUTOMATIC),
900 DECL(AL_STORAGE_HARDWARE),
901 DECL(AL_STORAGE_ACCESSIBLE),
902 #endif // ALSOFT_EAX
904 #undef DECL
906 constexpr ALCchar alcNoError[] = "No Error";
907 constexpr ALCchar alcErrInvalidDevice[] = "Invalid Device";
908 constexpr ALCchar alcErrInvalidContext[] = "Invalid Context";
909 constexpr ALCchar alcErrInvalidEnum[] = "Invalid Enum";
910 constexpr ALCchar alcErrInvalidValue[] = "Invalid Value";
911 constexpr ALCchar alcErrOutOfMemory[] = "Out of Memory";
914 /************************************************
915 * Global variables
916 ************************************************/
918 /* Enumerated device names */
919 constexpr ALCchar alcDefaultName[] = "OpenAL Soft\0";
921 std::string alcAllDevicesList;
922 std::string alcCaptureDeviceList;
924 /* Default is always the first in the list */
925 std::string alcDefaultAllDevicesSpecifier;
926 std::string alcCaptureDefaultDeviceSpecifier;
928 std::atomic<ALCenum> LastNullDeviceError{ALC_NO_ERROR};
930 /* Flag to trap ALC device errors */
931 bool TrapALCError{false};
933 /* One-time configuration init control */
934 std::once_flag alc_config_once{};
936 /* Flag to specify if alcSuspendContext/alcProcessContext should defer/process
937 * updates.
939 bool SuspendDefers{true};
941 /* Initial seed for dithering. */
942 constexpr uint DitherRNGSeed{22222u};
945 /************************************************
946 * ALC information
947 ************************************************/
948 constexpr ALCchar alcNoDeviceExtList[] =
949 "ALC_ENUMERATE_ALL_EXT "
950 "ALC_ENUMERATION_EXT "
951 "ALC_EXT_CAPTURE "
952 "ALC_EXT_EFX "
953 "ALC_EXT_thread_local_context "
954 "ALC_SOFT_loopback "
955 "ALC_SOFT_loopback_bformat "
956 "ALC_SOFT_reopen_device";
957 constexpr ALCchar alcExtensionList[] =
958 "ALC_ENUMERATE_ALL_EXT "
959 "ALC_ENUMERATION_EXT "
960 "ALC_EXT_CAPTURE "
961 "ALC_EXT_DEDICATED "
962 "ALC_EXT_disconnect "
963 "ALC_EXT_EFX "
964 "ALC_EXT_thread_local_context "
965 "ALC_SOFT_device_clock "
966 "ALC_SOFT_HRTF "
967 "ALC_SOFT_loopback "
968 "ALC_SOFT_loopback_bformat "
969 "ALC_SOFT_output_limiter "
970 "ALC_SOFT_output_mode "
971 "ALC_SOFT_pause_device "
972 "ALC_SOFT_reopen_device";
973 constexpr int alcMajorVersion{1};
974 constexpr int alcMinorVersion{1};
976 constexpr int alcEFXMajorVersion{1};
977 constexpr int alcEFXMinorVersion{0};
980 using DeviceRef = al::intrusive_ptr<ALCdevice>;
983 /************************************************
984 * Device lists
985 ************************************************/
986 al::vector<ALCdevice*> DeviceList;
987 al::vector<ALCcontext*> ContextList;
989 std::recursive_mutex ListLock;
992 void alc_initconfig(void)
994 if(auto loglevel = al::getenv("ALSOFT_LOGLEVEL"))
996 long lvl = strtol(loglevel->c_str(), nullptr, 0);
997 if(lvl >= static_cast<long>(LogLevel::Trace))
998 gLogLevel = LogLevel::Trace;
999 else if(lvl <= static_cast<long>(LogLevel::Disable))
1000 gLogLevel = LogLevel::Disable;
1001 else
1002 gLogLevel = static_cast<LogLevel>(lvl);
1005 #ifdef _WIN32
1006 if(const auto logfile = al::getenv(L"ALSOFT_LOGFILE"))
1008 FILE *logf{_wfopen(logfile->c_str(), L"wt")};
1009 if(logf) gLogFile = logf;
1010 else
1012 auto u8name = wstr_to_utf8(logfile->c_str());
1013 ERR("Failed to open log file '%s'\n", u8name.c_str());
1016 #else
1017 if(const auto logfile = al::getenv("ALSOFT_LOGFILE"))
1019 FILE *logf{fopen(logfile->c_str(), "wt")};
1020 if(logf) gLogFile = logf;
1021 else ERR("Failed to open log file '%s'\n", logfile->c_str());
1023 #endif
1025 TRACE("Initializing library v%s-%s %s\n", ALSOFT_VERSION, ALSOFT_GIT_COMMIT_HASH,
1026 ALSOFT_GIT_BRANCH);
1028 std::string names;
1029 if(al::size(BackendList) < 1)
1030 names = "(none)";
1031 else
1033 const al::span<const BackendInfo> infos{BackendList};
1034 names = infos[0].name;
1035 for(const auto &backend : infos.subspan<1>())
1037 names += ", ";
1038 names += backend.name;
1041 TRACE("Supported backends: %s\n", names.c_str());
1043 ReadALConfig();
1045 if(auto suspendmode = al::getenv("__ALSOFT_SUSPEND_CONTEXT"))
1047 if(al::strcasecmp(suspendmode->c_str(), "ignore") == 0)
1049 SuspendDefers = false;
1050 TRACE("Selected context suspend behavior, \"ignore\"\n");
1052 else
1053 ERR("Unhandled context suspend behavior setting: \"%s\"\n", suspendmode->c_str());
1056 int capfilter{0};
1057 #if defined(HAVE_SSE4_1)
1058 capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3 | CPU_CAP_SSE4_1;
1059 #elif defined(HAVE_SSE3)
1060 capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3;
1061 #elif defined(HAVE_SSE2)
1062 capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2;
1063 #elif defined(HAVE_SSE)
1064 capfilter |= CPU_CAP_SSE;
1065 #endif
1066 #ifdef HAVE_NEON
1067 capfilter |= CPU_CAP_NEON;
1068 #endif
1069 if(auto cpuopt = ConfigValueStr(nullptr, nullptr, "disable-cpu-exts"))
1071 const char *str{cpuopt->c_str()};
1072 if(al::strcasecmp(str, "all") == 0)
1073 capfilter = 0;
1074 else
1076 const char *next = str;
1077 do {
1078 str = next;
1079 while(isspace(str[0]))
1080 str++;
1081 next = strchr(str, ',');
1083 if(!str[0] || str[0] == ',')
1084 continue;
1086 size_t len{next ? static_cast<size_t>(next-str) : strlen(str)};
1087 while(len > 0 && isspace(str[len-1]))
1088 len--;
1089 if(len == 3 && al::strncasecmp(str, "sse", len) == 0)
1090 capfilter &= ~CPU_CAP_SSE;
1091 else if(len == 4 && al::strncasecmp(str, "sse2", len) == 0)
1092 capfilter &= ~CPU_CAP_SSE2;
1093 else if(len == 4 && al::strncasecmp(str, "sse3", len) == 0)
1094 capfilter &= ~CPU_CAP_SSE3;
1095 else if(len == 6 && al::strncasecmp(str, "sse4.1", len) == 0)
1096 capfilter &= ~CPU_CAP_SSE4_1;
1097 else if(len == 4 && al::strncasecmp(str, "neon", len) == 0)
1098 capfilter &= ~CPU_CAP_NEON;
1099 else
1100 WARN("Invalid CPU extension \"%s\"\n", str);
1101 } while(next++);
1104 if(auto cpuopt = GetCPUInfo())
1106 if(!cpuopt->mVendor.empty() || !cpuopt->mName.empty())
1108 TRACE("Vendor ID: \"%s\"\n", cpuopt->mVendor.c_str());
1109 TRACE("Name: \"%s\"\n", cpuopt->mName.c_str());
1111 const int caps{cpuopt->mCaps};
1112 TRACE("Extensions:%s%s%s%s%s%s\n",
1113 ((capfilter&CPU_CAP_SSE) ? ((caps&CPU_CAP_SSE) ? " +SSE" : " -SSE") : ""),
1114 ((capfilter&CPU_CAP_SSE2) ? ((caps&CPU_CAP_SSE2) ? " +SSE2" : " -SSE2") : ""),
1115 ((capfilter&CPU_CAP_SSE3) ? ((caps&CPU_CAP_SSE3) ? " +SSE3" : " -SSE3") : ""),
1116 ((capfilter&CPU_CAP_SSE4_1) ? ((caps&CPU_CAP_SSE4_1) ? " +SSE4.1" : " -SSE4.1") : ""),
1117 ((capfilter&CPU_CAP_NEON) ? ((caps&CPU_CAP_NEON) ? " +NEON" : " -NEON") : ""),
1118 ((!capfilter) ? " -none-" : ""));
1119 CPUCapFlags = caps & capfilter;
1122 if(auto priopt = ConfigValueInt(nullptr, nullptr, "rt-prio"))
1123 RTPrioLevel = *priopt;
1124 if(auto limopt = ConfigValueBool(nullptr, nullptr, "rt-time-limit"))
1125 AllowRTTimeLimit = *limopt;
1127 CompatFlagBitset compatflags{};
1128 auto checkflag = [](const char *envname, const char *optname) -> bool
1130 if(auto optval = al::getenv(envname))
1132 if(al::strcasecmp(optval->c_str(), "true") == 0
1133 || strtol(optval->c_str(), nullptr, 0) == 1)
1134 return true;
1135 return false;
1137 return GetConfigValueBool(nullptr, "game_compat", optname, false);
1139 compatflags.set(CompatFlags::ReverseX, checkflag("__ALSOFT_REVERSE_X", "reverse-x"));
1140 compatflags.set(CompatFlags::ReverseY, checkflag("__ALSOFT_REVERSE_Y", "reverse-y"));
1141 compatflags.set(CompatFlags::ReverseZ, checkflag("__ALSOFT_REVERSE_Z", "reverse-z"));
1143 aluInit(compatflags);
1144 Voice::InitMixer(ConfigValueStr(nullptr, nullptr, "resampler"));
1146 auto traperr = al::getenv("ALSOFT_TRAP_ERROR");
1147 if(traperr && (al::strcasecmp(traperr->c_str(), "true") == 0
1148 || std::strtol(traperr->c_str(), nullptr, 0) == 1))
1150 TrapALError = true;
1151 TrapALCError = true;
1153 else
1155 traperr = al::getenv("ALSOFT_TRAP_AL_ERROR");
1156 if(traperr)
1157 TrapALError = al::strcasecmp(traperr->c_str(), "true") == 0
1158 || strtol(traperr->c_str(), nullptr, 0) == 1;
1159 else
1160 TrapALError = !!GetConfigValueBool(nullptr, nullptr, "trap-al-error", false);
1162 traperr = al::getenv("ALSOFT_TRAP_ALC_ERROR");
1163 if(traperr)
1164 TrapALCError = al::strcasecmp(traperr->c_str(), "true") == 0
1165 || strtol(traperr->c_str(), nullptr, 0) == 1;
1166 else
1167 TrapALCError = !!GetConfigValueBool(nullptr, nullptr, "trap-alc-error", false);
1170 if(auto boostopt = ConfigValueFloat(nullptr, "reverb", "boost"))
1172 const float valf{std::isfinite(*boostopt) ? clampf(*boostopt, -24.0f, 24.0f) : 0.0f};
1173 ReverbBoost *= std::pow(10.0f, valf / 20.0f);
1176 auto BackendListEnd = std::end(BackendList);
1177 auto devopt = al::getenv("ALSOFT_DRIVERS");
1178 if(devopt || (devopt=ConfigValueStr(nullptr, nullptr, "drivers")))
1180 auto backendlist_cur = std::begin(BackendList);
1182 bool endlist{true};
1183 const char *next{devopt->c_str()};
1184 do {
1185 const char *devs{next};
1186 while(isspace(devs[0]))
1187 devs++;
1188 next = strchr(devs, ',');
1190 const bool delitem{devs[0] == '-'};
1191 if(devs[0] == '-') devs++;
1193 if(!devs[0] || devs[0] == ',')
1195 endlist = false;
1196 continue;
1198 endlist = true;
1200 size_t len{next ? (static_cast<size_t>(next-devs)) : strlen(devs)};
1201 while(len > 0 && isspace(devs[len-1])) --len;
1202 #ifdef HAVE_WASAPI
1203 /* HACK: For backwards compatibility, convert backend references of
1204 * mmdevapi to wasapi. This should eventually be removed.
1206 if(len == 8 && strncmp(devs, "mmdevapi", len) == 0)
1208 devs = "wasapi";
1209 len = 6;
1211 #endif
1213 auto find_backend = [devs,len](const BackendInfo &backend) -> bool
1214 { return len == strlen(backend.name) && strncmp(backend.name, devs, len) == 0; };
1215 auto this_backend = std::find_if(std::begin(BackendList), BackendListEnd,
1216 find_backend);
1218 if(this_backend == BackendListEnd)
1219 continue;
1221 if(delitem)
1222 BackendListEnd = std::move(this_backend+1, BackendListEnd, this_backend);
1223 else
1224 backendlist_cur = std::rotate(backendlist_cur, this_backend, this_backend+1);
1225 } while(next++);
1227 if(endlist)
1228 BackendListEnd = backendlist_cur;
1231 auto init_backend = [](BackendInfo &backend) -> void
1233 if(PlaybackFactory && CaptureFactory)
1234 return;
1236 BackendFactory &factory = backend.getFactory();
1237 if(!factory.init())
1239 WARN("Failed to initialize backend \"%s\"\n", backend.name);
1240 return;
1243 TRACE("Initialized backend \"%s\"\n", backend.name);
1244 if(!PlaybackFactory && factory.querySupport(BackendType::Playback))
1246 PlaybackFactory = &factory;
1247 TRACE("Added \"%s\" for playback\n", backend.name);
1249 if(!CaptureFactory && factory.querySupport(BackendType::Capture))
1251 CaptureFactory = &factory;
1252 TRACE("Added \"%s\" for capture\n", backend.name);
1255 std::for_each(std::begin(BackendList), BackendListEnd, init_backend);
1257 LoopbackBackendFactory::getFactory().init();
1259 if(!PlaybackFactory)
1260 WARN("No playback backend available!\n");
1261 if(!CaptureFactory)
1262 WARN("No capture backend available!\n");
1264 if(auto exclopt = ConfigValueStr(nullptr, nullptr, "excludefx"))
1266 const char *next{exclopt->c_str()};
1267 do {
1268 const char *str{next};
1269 next = strchr(str, ',');
1271 if(!str[0] || next == str)
1272 continue;
1274 size_t len{next ? static_cast<size_t>(next-str) : strlen(str)};
1275 for(const EffectList &effectitem : gEffectList)
1277 if(len == strlen(effectitem.name) &&
1278 strncmp(effectitem.name, str, len) == 0)
1279 DisabledEffects[effectitem.type] = true;
1281 } while(next++);
1284 InitEffect(&ALCcontext::sDefaultEffect);
1285 auto defrevopt = al::getenv("ALSOFT_DEFAULT_REVERB");
1286 if(defrevopt || (defrevopt=ConfigValueStr(nullptr, nullptr, "default-reverb")))
1287 LoadReverbPreset(defrevopt->c_str(), &ALCcontext::sDefaultEffect);
1289 #ifdef ALSOFT_EAX
1291 static constexpr char eax_block_name[] = "eax";
1293 if(const auto eax_enable_opt = ConfigValueBool(nullptr, eax_block_name, "enable"))
1295 eax_g_is_enabled = *eax_enable_opt;
1296 if(!eax_g_is_enabled)
1297 TRACE("%s\n", "EAX disabled by a configuration.");
1299 else
1300 eax_g_is_enabled = true;
1302 if(eax_g_is_enabled && DisabledEffects[EAXREVERB_EFFECT])
1304 eax_g_is_enabled = false;
1305 TRACE("%s\n", "EAX disabled because EAXReverb is disabled.");
1308 #endif // ALSOFT_EAX
1310 #define DO_INITCONFIG() std::call_once(alc_config_once, [](){alc_initconfig();})
1313 /************************************************
1314 * Device enumeration
1315 ************************************************/
1316 void ProbeAllDevicesList()
1318 DO_INITCONFIG();
1320 std::lock_guard<std::recursive_mutex> _{ListLock};
1321 if(!PlaybackFactory)
1322 decltype(alcAllDevicesList){}.swap(alcAllDevicesList);
1323 else
1325 std::string names{PlaybackFactory->probe(BackendType::Playback)};
1326 if(names.empty()) names += '\0';
1327 names.swap(alcAllDevicesList);
1330 void ProbeCaptureDeviceList()
1332 DO_INITCONFIG();
1334 std::lock_guard<std::recursive_mutex> _{ListLock};
1335 if(!CaptureFactory)
1336 decltype(alcCaptureDeviceList){}.swap(alcCaptureDeviceList);
1337 else
1339 std::string names{CaptureFactory->probe(BackendType::Capture)};
1340 if(names.empty()) names += '\0';
1341 names.swap(alcCaptureDeviceList);
1346 struct DevFmtPair { DevFmtChannels chans; DevFmtType type; };
1347 al::optional<DevFmtPair> DecomposeDevFormat(ALenum format)
1349 static const struct {
1350 ALenum format;
1351 DevFmtChannels channels;
1352 DevFmtType type;
1353 } list[] = {
1354 { AL_FORMAT_MONO8, DevFmtMono, DevFmtUByte },
1355 { AL_FORMAT_MONO16, DevFmtMono, DevFmtShort },
1356 { AL_FORMAT_MONO_FLOAT32, DevFmtMono, DevFmtFloat },
1358 { AL_FORMAT_STEREO8, DevFmtStereo, DevFmtUByte },
1359 { AL_FORMAT_STEREO16, DevFmtStereo, DevFmtShort },
1360 { AL_FORMAT_STEREO_FLOAT32, DevFmtStereo, DevFmtFloat },
1362 { AL_FORMAT_QUAD8, DevFmtQuad, DevFmtUByte },
1363 { AL_FORMAT_QUAD16, DevFmtQuad, DevFmtShort },
1364 { AL_FORMAT_QUAD32, DevFmtQuad, DevFmtFloat },
1366 { AL_FORMAT_51CHN8, DevFmtX51, DevFmtUByte },
1367 { AL_FORMAT_51CHN16, DevFmtX51, DevFmtShort },
1368 { AL_FORMAT_51CHN32, DevFmtX51, DevFmtFloat },
1370 { AL_FORMAT_61CHN8, DevFmtX61, DevFmtUByte },
1371 { AL_FORMAT_61CHN16, DevFmtX61, DevFmtShort },
1372 { AL_FORMAT_61CHN32, DevFmtX61, DevFmtFloat },
1374 { AL_FORMAT_71CHN8, DevFmtX71, DevFmtUByte },
1375 { AL_FORMAT_71CHN16, DevFmtX71, DevFmtShort },
1376 { AL_FORMAT_71CHN32, DevFmtX71, DevFmtFloat },
1379 for(const auto &item : list)
1381 if(item.format == format)
1382 return al::make_optional(DevFmtPair{item.channels, item.type});
1385 return al::nullopt;
1388 al::optional<DevFmtType> DevFmtTypeFromEnum(ALCenum type)
1390 switch(type)
1392 case ALC_BYTE_SOFT: return al::make_optional(DevFmtByte);
1393 case ALC_UNSIGNED_BYTE_SOFT: return al::make_optional(DevFmtUByte);
1394 case ALC_SHORT_SOFT: return al::make_optional(DevFmtShort);
1395 case ALC_UNSIGNED_SHORT_SOFT: return al::make_optional(DevFmtUShort);
1396 case ALC_INT_SOFT: return al::make_optional(DevFmtInt);
1397 case ALC_UNSIGNED_INT_SOFT: return al::make_optional(DevFmtUInt);
1398 case ALC_FLOAT_SOFT: return al::make_optional(DevFmtFloat);
1400 WARN("Unsupported format type: 0x%04x\n", type);
1401 return al::nullopt;
1403 ALCenum EnumFromDevFmt(DevFmtType type)
1405 switch(type)
1407 case DevFmtByte: return ALC_BYTE_SOFT;
1408 case DevFmtUByte: return ALC_UNSIGNED_BYTE_SOFT;
1409 case DevFmtShort: return ALC_SHORT_SOFT;
1410 case DevFmtUShort: return ALC_UNSIGNED_SHORT_SOFT;
1411 case DevFmtInt: return ALC_INT_SOFT;
1412 case DevFmtUInt: return ALC_UNSIGNED_INT_SOFT;
1413 case DevFmtFloat: return ALC_FLOAT_SOFT;
1415 throw std::runtime_error{"Invalid DevFmtType: "+std::to_string(int(type))};
1418 al::optional<DevFmtChannels> DevFmtChannelsFromEnum(ALCenum channels)
1420 switch(channels)
1422 case ALC_MONO_SOFT: return al::make_optional(DevFmtMono);
1423 case ALC_STEREO_SOFT: return al::make_optional(DevFmtStereo);
1424 case ALC_QUAD_SOFT: return al::make_optional(DevFmtQuad);
1425 case ALC_5POINT1_SOFT: return al::make_optional(DevFmtX51);
1426 case ALC_6POINT1_SOFT: return al::make_optional(DevFmtX61);
1427 case ALC_7POINT1_SOFT: return al::make_optional(DevFmtX71);
1428 case ALC_BFORMAT3D_SOFT: return al::make_optional(DevFmtAmbi3D);
1430 WARN("Unsupported format channels: 0x%04x\n", channels);
1431 return al::nullopt;
1433 ALCenum EnumFromDevFmt(DevFmtChannels channels)
1435 switch(channels)
1437 case DevFmtMono: return ALC_MONO_SOFT;
1438 case DevFmtStereo: return ALC_STEREO_SOFT;
1439 case DevFmtQuad: return ALC_QUAD_SOFT;
1440 case DevFmtX51: return ALC_5POINT1_SOFT;
1441 case DevFmtX61: return ALC_6POINT1_SOFT;
1442 case DevFmtX71: return ALC_7POINT1_SOFT;
1443 case DevFmtAmbi3D: return ALC_BFORMAT3D_SOFT;
1444 /* FIXME: Shouldn't happen. */
1445 case DevFmtX3D71: break;
1447 throw std::runtime_error{"Invalid DevFmtChannels: "+std::to_string(int(channels))};
1450 al::optional<DevAmbiLayout> DevAmbiLayoutFromEnum(ALCenum layout)
1452 switch(layout)
1454 case ALC_FUMA_SOFT: return al::make_optional(DevAmbiLayout::FuMa);
1455 case ALC_ACN_SOFT: return al::make_optional(DevAmbiLayout::ACN);
1457 WARN("Unsupported ambisonic layout: 0x%04x\n", layout);
1458 return al::nullopt;
1460 ALCenum EnumFromDevAmbi(DevAmbiLayout layout)
1462 switch(layout)
1464 case DevAmbiLayout::FuMa: return ALC_FUMA_SOFT;
1465 case DevAmbiLayout::ACN: return ALC_ACN_SOFT;
1467 throw std::runtime_error{"Invalid DevAmbiLayout: "+std::to_string(int(layout))};
1470 al::optional<DevAmbiScaling> DevAmbiScalingFromEnum(ALCenum scaling)
1472 switch(scaling)
1474 case ALC_FUMA_SOFT: return al::make_optional(DevAmbiScaling::FuMa);
1475 case ALC_SN3D_SOFT: return al::make_optional(DevAmbiScaling::SN3D);
1476 case ALC_N3D_SOFT: return al::make_optional(DevAmbiScaling::N3D);
1478 WARN("Unsupported ambisonic scaling: 0x%04x\n", scaling);
1479 return al::nullopt;
1481 ALCenum EnumFromDevAmbi(DevAmbiScaling scaling)
1483 switch(scaling)
1485 case DevAmbiScaling::FuMa: return ALC_FUMA_SOFT;
1486 case DevAmbiScaling::SN3D: return ALC_SN3D_SOFT;
1487 case DevAmbiScaling::N3D: return ALC_N3D_SOFT;
1489 throw std::runtime_error{"Invalid DevAmbiScaling: "+std::to_string(int(scaling))};
1493 /* Downmixing channel arrays, to map the given format's missing channels to
1494 * existing ones. Based on Wine's DSound downmix values, which are based on
1495 * PulseAudio's.
1497 const std::array<InputRemixMap,6> StereoDownmix{{
1498 { FrontCenter, {{{FrontLeft, 0.5f}, {FrontRight, 0.5f}}} },
1499 { SideLeft, {{{FrontLeft, 1.0f/9.0f}, {FrontRight, 0.0f}}} },
1500 { SideRight, {{{FrontLeft, 0.0f}, {FrontRight, 1.0f/9.0f}}} },
1501 { BackLeft, {{{FrontLeft, 1.0f/9.0f}, {FrontRight, 0.0f}}} },
1502 { BackRight, {{{FrontLeft, 0.0f}, {FrontRight, 1.0f/9.0f}}} },
1503 { BackCenter, {{{FrontLeft, 0.5f/9.0f}, {FrontRight, 0.5f/9.0f}}} },
1505 const std::array<InputRemixMap,4> QuadDownmix{{
1506 { FrontCenter, {{{FrontLeft, 0.5f}, {FrontRight, 0.5f}}} },
1507 { SideLeft, {{{FrontLeft, 0.5f}, {BackLeft, 0.5f}}} },
1508 { SideRight, {{{FrontRight, 0.5f}, {BackRight, 0.5f}}} },
1509 { BackCenter, {{{BackLeft, 0.5f}, {BackRight, 0.5f}}} },
1511 const std::array<InputRemixMap,3> X51Downmix{{
1512 { BackLeft, {{{SideLeft, 1.0f}, {SideRight, 0.0f}}} },
1513 { BackRight, {{{SideLeft, 0.0f}, {SideRight, 1.0f}}} },
1514 { BackCenter, {{{SideLeft, 0.5f}, {SideRight, 0.5f}}} },
1516 const std::array<InputRemixMap,2> X61Downmix{{
1517 { BackLeft, {{{BackCenter, 0.5f}, {SideLeft, 0.5f}}} },
1518 { BackRight, {{{BackCenter, 0.5f}, {SideRight, 0.5f}}} },
1520 const std::array<InputRemixMap,1> X71Downmix{{
1521 { BackCenter, {{{BackLeft, 0.5f}, {BackRight, 0.5f}}} },
1525 /** Stores the latest ALC device error. */
1526 void alcSetError(ALCdevice *device, ALCenum errorCode)
1528 WARN("Error generated on device %p, code 0x%04x\n", voidp{device}, errorCode);
1529 if(TrapALCError)
1531 #ifdef _WIN32
1532 /* DebugBreak() will cause an exception if there is no debugger */
1533 if(IsDebuggerPresent())
1534 DebugBreak();
1535 #elif defined(SIGTRAP)
1536 raise(SIGTRAP);
1537 #endif
1540 if(device)
1541 device->LastError.store(errorCode);
1542 else
1543 LastNullDeviceError.store(errorCode);
1547 std::unique_ptr<Compressor> CreateDeviceLimiter(const ALCdevice *device, const float threshold)
1549 static constexpr bool AutoKnee{true};
1550 static constexpr bool AutoAttack{true};
1551 static constexpr bool AutoRelease{true};
1552 static constexpr bool AutoPostGain{true};
1553 static constexpr bool AutoDeclip{true};
1554 static constexpr float LookAheadTime{0.001f};
1555 static constexpr float HoldTime{0.002f};
1556 static constexpr float PreGainDb{0.0f};
1557 static constexpr float PostGainDb{0.0f};
1558 static constexpr float Ratio{std::numeric_limits<float>::infinity()};
1559 static constexpr float KneeDb{0.0f};
1560 static constexpr float AttackTime{0.02f};
1561 static constexpr float ReleaseTime{0.2f};
1563 return Compressor::Create(device->RealOut.Buffer.size(), static_cast<float>(device->Frequency),
1564 AutoKnee, AutoAttack, AutoRelease, AutoPostGain, AutoDeclip, LookAheadTime, HoldTime,
1565 PreGainDb, PostGainDb, threshold, Ratio, KneeDb, AttackTime, ReleaseTime);
1569 * Updates the device's base clock time with however many samples have been
1570 * done. This is used so frequency changes on the device don't cause the time
1571 * to jump forward or back. Must not be called while the device is running/
1572 * mixing.
1574 static inline void UpdateClockBase(ALCdevice *device)
1576 IncrementRef(device->MixCount);
1577 device->ClockBase += nanoseconds{seconds{device->SamplesDone}} / device->Frequency;
1578 device->SamplesDone = 0;
1579 IncrementRef(device->MixCount);
1583 * Updates device parameters according to the attribute list (caller is
1584 * responsible for holding the list lock).
1586 ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
1588 if((!attrList || !attrList[0]) && device->Type == DeviceType::Loopback)
1590 WARN("Missing attributes for loopback device\n");
1591 return ALC_INVALID_VALUE;
1594 al::optional<StereoEncoding> stereomode{};
1595 al::optional<bool> optlimit{};
1596 int hrtf_id{-1};
1598 // Check for attributes
1599 if(attrList && attrList[0])
1601 uint numMono{device->NumMonoSources};
1602 uint numStereo{device->NumStereoSources};
1603 uint numSends{device->NumAuxSends};
1605 al::optional<DevFmtChannels> optchans;
1606 al::optional<DevFmtType> opttype;
1607 al::optional<DevAmbiLayout> optlayout;
1608 al::optional<DevAmbiScaling> optscale;
1609 al::optional<bool> opthrtf;
1611 ALenum outmode{ALC_ANY_SOFT};
1612 uint aorder{0u};
1613 uint freq{0u};
1615 #define ATTRIBUTE(a) a: TRACE("%s = %d\n", #a, attrList[attrIdx + 1]);
1616 size_t attrIdx{0};
1617 while(attrList[attrIdx])
1619 switch(attrList[attrIdx])
1621 case ATTRIBUTE(ALC_FORMAT_CHANNELS_SOFT)
1622 optchans = DevFmtChannelsFromEnum(attrList[attrIdx + 1]);
1623 break;
1625 case ATTRIBUTE(ALC_FORMAT_TYPE_SOFT)
1626 opttype = DevFmtTypeFromEnum(attrList[attrIdx + 1]);
1627 break;
1629 case ATTRIBUTE(ALC_FREQUENCY)
1630 freq = static_cast<uint>(attrList[attrIdx + 1]);
1631 break;
1633 case ATTRIBUTE(ALC_AMBISONIC_LAYOUT_SOFT)
1634 optlayout = DevAmbiLayoutFromEnum(attrList[attrIdx + 1]);
1635 break;
1637 case ATTRIBUTE(ALC_AMBISONIC_SCALING_SOFT)
1638 optscale = DevAmbiScalingFromEnum(attrList[attrIdx + 1]);
1639 break;
1641 case ATTRIBUTE(ALC_AMBISONIC_ORDER_SOFT)
1642 aorder = static_cast<uint>(attrList[attrIdx + 1]);
1643 break;
1645 case ATTRIBUTE(ALC_MONO_SOURCES)
1646 numMono = static_cast<uint>(attrList[attrIdx + 1]);
1647 if(numMono > INT_MAX) numMono = 0;
1648 break;
1650 case ATTRIBUTE(ALC_STEREO_SOURCES)
1651 numStereo = static_cast<uint>(attrList[attrIdx + 1]);
1652 if(numStereo > INT_MAX) numStereo = 0;
1653 break;
1655 case ATTRIBUTE(ALC_MAX_AUXILIARY_SENDS)
1656 numSends = static_cast<uint>(attrList[attrIdx + 1]);
1657 if(numSends > INT_MAX) numSends = 0;
1658 else numSends = minu(numSends, MAX_SENDS);
1659 break;
1661 case ATTRIBUTE(ALC_HRTF_SOFT)
1662 if(attrList[attrIdx + 1] == ALC_FALSE)
1663 opthrtf = false;
1664 else if(attrList[attrIdx + 1] == ALC_TRUE)
1665 opthrtf = true;
1666 else if(attrList[attrIdx + 1] == ALC_DONT_CARE_SOFT)
1667 opthrtf = al::nullopt;
1668 break;
1670 case ATTRIBUTE(ALC_HRTF_ID_SOFT)
1671 hrtf_id = attrList[attrIdx + 1];
1672 break;
1674 case ATTRIBUTE(ALC_OUTPUT_LIMITER_SOFT)
1675 if(attrList[attrIdx + 1] == ALC_FALSE)
1676 optlimit = false;
1677 else if(attrList[attrIdx + 1] == ALC_TRUE)
1678 optlimit = true;
1679 else if(attrList[attrIdx + 1] == ALC_DONT_CARE_SOFT)
1680 optlimit = al::nullopt;
1681 break;
1683 case ATTRIBUTE(ALC_OUTPUT_MODE_SOFT)
1684 outmode = attrList[attrIdx + 1];
1685 break;
1687 default:
1688 TRACE("0x%04X = %d (0x%x)\n", attrList[attrIdx],
1689 attrList[attrIdx + 1], attrList[attrIdx + 1]);
1690 break;
1693 attrIdx += 2;
1695 #undef ATTRIBUTE
1697 const bool loopback{device->Type == DeviceType::Loopback};
1698 if(loopback)
1700 if(!optchans || !opttype)
1701 return ALC_INVALID_VALUE;
1702 if(freq < MIN_OUTPUT_RATE || freq > MAX_OUTPUT_RATE)
1703 return ALC_INVALID_VALUE;
1704 if(*optchans == DevFmtAmbi3D)
1706 if(!optlayout || !optscale)
1707 return ALC_INVALID_VALUE;
1708 if(aorder < 1 || aorder > MaxAmbiOrder)
1709 return ALC_INVALID_VALUE;
1710 if((*optlayout == DevAmbiLayout::FuMa || *optscale == DevAmbiScaling::FuMa)
1711 && aorder > 3)
1712 return ALC_INVALID_VALUE;
1716 /* If a context is already running on the device, stop playback so the
1717 * device attributes can be updated.
1719 if(device->Flags.test(DeviceRunning))
1720 device->Backend->stop();
1721 device->Flags.reset(DeviceRunning);
1723 UpdateClockBase(device);
1725 /* Calculate the max number of sources, and split them between the mono
1726 * and stereo count given the requested number of stereo sources.
1728 if(auto srcsopt = device->configValue<uint>(nullptr, "sources"))
1730 if(*srcsopt <= 0) numMono = 256;
1731 else numMono = *srcsopt;
1733 else
1735 if(numMono > INT_MAX-numStereo)
1736 numMono = INT_MAX-numStereo;
1737 numMono = maxu(numMono+numStereo, 256);
1739 numStereo = minu(numStereo, numMono);
1740 numMono -= numStereo;
1741 device->SourcesMax = numMono + numStereo;
1742 device->NumMonoSources = numMono;
1743 device->NumStereoSources = numStereo;
1745 if(auto sendsopt = device->configValue<int>(nullptr, "sends"))
1746 numSends = minu(numSends, static_cast<uint>(clampi(*sendsopt, 0, MAX_SENDS)));
1747 device->NumAuxSends = numSends;
1749 if(loopback)
1751 device->Frequency = freq;
1752 device->FmtChans = *optchans;
1753 device->FmtType = *opttype;
1754 if(device->FmtChans == DevFmtAmbi3D)
1756 device->mAmbiOrder = aorder;
1757 device->mAmbiLayout = *optlayout;
1758 device->mAmbiScale = *optscale;
1760 else if(device->FmtChans == DevFmtStereo)
1762 if(opthrtf)
1763 stereomode = *opthrtf ? StereoEncoding::Hrtf : StereoEncoding::Default;
1765 if(outmode == ALC_STEREO_BASIC_SOFT)
1766 stereomode = StereoEncoding::Basic;
1767 else if(outmode == ALC_STEREO_UHJ_SOFT)
1768 stereomode = StereoEncoding::Uhj;
1769 else if(outmode == ALC_STEREO_HRTF_SOFT)
1770 stereomode = StereoEncoding::Hrtf;
1772 device->Flags.set(FrequencyRequest).set(ChannelsRequest).set(SampleTypeRequest);
1774 else
1776 device->Flags.reset(FrequencyRequest).reset(ChannelsRequest).reset(SampleTypeRequest);
1777 device->FmtType = DevFmtTypeDefault;
1778 device->FmtChans = DevFmtChannelsDefault;
1779 device->mAmbiOrder = 0;
1780 device->BufferSize = DEFAULT_UPDATE_SIZE * DEFAULT_NUM_UPDATES;
1781 device->UpdateSize = DEFAULT_UPDATE_SIZE;
1782 device->Frequency = DEFAULT_OUTPUT_RATE;
1784 freq = device->configValue<uint>(nullptr, "frequency").value_or(freq);
1785 if(freq > 0)
1787 freq = clampu(freq, MIN_OUTPUT_RATE, MAX_OUTPUT_RATE);
1789 const double scale{static_cast<double>(freq) / device->Frequency};
1790 device->UpdateSize = static_cast<uint>(device->UpdateSize*scale + 0.5);
1791 device->BufferSize = static_cast<uint>(device->BufferSize*scale + 0.5);
1793 device->Frequency = freq;
1794 device->Flags.set(FrequencyRequest);
1797 auto set_device_mode = [device](DevFmtChannels chans) noexcept
1799 device->FmtChans = chans;
1800 device->Flags.set(ChannelsRequest);
1802 if(opthrtf)
1804 if(*opthrtf)
1806 set_device_mode(DevFmtStereo);
1807 stereomode = StereoEncoding::Hrtf;
1809 else
1810 stereomode = StereoEncoding::Default;
1813 using OutputMode = ALCdevice::OutputMode;
1814 switch(OutputMode(outmode))
1816 case OutputMode::Any: break;
1817 case OutputMode::Mono: set_device_mode(DevFmtMono); break;
1818 case OutputMode::Stereo: set_device_mode(DevFmtStereo); break;
1819 case OutputMode::StereoBasic:
1820 set_device_mode(DevFmtStereo);
1821 stereomode = StereoEncoding::Basic;
1822 break;
1823 case OutputMode::Uhj2:
1824 set_device_mode(DevFmtStereo);
1825 stereomode = StereoEncoding::Uhj;
1826 break;
1827 case OutputMode::Hrtf:
1828 set_device_mode(DevFmtStereo);
1829 stereomode = StereoEncoding::Hrtf;
1830 break;
1831 case OutputMode::Quad: set_device_mode(DevFmtQuad); break;
1832 case OutputMode::X51: set_device_mode(DevFmtX51); break;
1833 case OutputMode::X61: set_device_mode(DevFmtX61); break;
1834 case OutputMode::X71: set_device_mode(DevFmtX71); break;
1839 if(device->Flags.test(DeviceRunning))
1840 return ALC_NO_ERROR;
1842 device->AvgSpeakerDist = 0.0f;
1843 device->mNFCtrlFilter = NfcFilter{};
1844 device->mUhjEncoder = nullptr;
1845 device->AmbiDecoder = nullptr;
1846 device->Bs2b = nullptr;
1847 device->PostProcess = nullptr;
1849 device->Limiter = nullptr;
1850 device->ChannelDelays = nullptr;
1852 std::fill(std::begin(device->HrtfAccumData), std::end(device->HrtfAccumData), float2{});
1854 device->Dry.AmbiMap.fill(BFChannelConfig{});
1855 device->Dry.Buffer = {};
1856 std::fill(std::begin(device->NumChannelsPerOrder), std::end(device->NumChannelsPerOrder), 0u);
1857 device->RealOut.RemixMap = {};
1858 device->RealOut.ChannelIndex.fill(INVALID_CHANNEL_INDEX);
1859 device->RealOut.Buffer = {};
1860 device->MixBuffer.clear();
1861 device->MixBuffer.shrink_to_fit();
1863 UpdateClockBase(device);
1864 device->FixedLatency = nanoseconds::zero();
1866 device->DitherDepth = 0.0f;
1867 device->DitherSeed = DitherRNGSeed;
1869 device->mHrtfStatus = ALC_HRTF_DISABLED_SOFT;
1871 /*************************************************************************
1872 * Update device format request from the user configuration
1874 if(device->Type != DeviceType::Loopback)
1876 if(auto typeopt = device->configValue<std::string>(nullptr, "sample-type"))
1878 static constexpr struct TypeMap {
1879 const char name[8];
1880 DevFmtType type;
1881 } typelist[] = {
1882 { "int8", DevFmtByte },
1883 { "uint8", DevFmtUByte },
1884 { "int16", DevFmtShort },
1885 { "uint16", DevFmtUShort },
1886 { "int32", DevFmtInt },
1887 { "uint32", DevFmtUInt },
1888 { "float32", DevFmtFloat },
1891 const ALCchar *fmt{typeopt->c_str()};
1892 auto iter = std::find_if(std::begin(typelist), std::end(typelist),
1893 [fmt](const TypeMap &entry) -> bool
1894 { return al::strcasecmp(entry.name, fmt) == 0; });
1895 if(iter == std::end(typelist))
1896 ERR("Unsupported sample-type: %s\n", fmt);
1897 else
1899 device->FmtType = iter->type;
1900 device->Flags.set(SampleTypeRequest);
1903 if(auto chanopt = device->configValue<std::string>(nullptr, "channels"))
1905 static constexpr struct ChannelMap {
1906 const char name[16];
1907 DevFmtChannels chans;
1908 uint8_t order;
1909 } chanlist[] = {
1910 { "mono", DevFmtMono, 0 },
1911 { "stereo", DevFmtStereo, 0 },
1912 { "quad", DevFmtQuad, 0 },
1913 { "surround51", DevFmtX51, 0 },
1914 { "surround61", DevFmtX61, 0 },
1915 { "surround71", DevFmtX71, 0 },
1916 { "surround3d71", DevFmtX3D71, 0 },
1917 { "surround51rear", DevFmtX51, 0 },
1918 { "ambi1", DevFmtAmbi3D, 1 },
1919 { "ambi2", DevFmtAmbi3D, 2 },
1920 { "ambi3", DevFmtAmbi3D, 3 },
1923 const ALCchar *fmt{chanopt->c_str()};
1924 auto iter = std::find_if(std::begin(chanlist), std::end(chanlist),
1925 [fmt](const ChannelMap &entry) -> bool
1926 { return al::strcasecmp(entry.name, fmt) == 0; });
1927 if(iter == std::end(chanlist))
1928 ERR("Unsupported channels: %s\n", fmt);
1929 else
1931 device->FmtChans = iter->chans;
1932 device->mAmbiOrder = iter->order;
1933 device->Flags.set(ChannelsRequest);
1936 if(auto ambiopt = device->configValue<std::string>(nullptr, "ambi-format"))
1938 const ALCchar *fmt{ambiopt->c_str()};
1939 if(al::strcasecmp(fmt, "fuma") == 0)
1941 if(device->mAmbiOrder > 3)
1942 ERR("FuMa is incompatible with %d%s order ambisonics (up to 3rd order only)\n",
1943 device->mAmbiOrder,
1944 (((device->mAmbiOrder%100)/10) == 1) ? "th" :
1945 ((device->mAmbiOrder%10) == 1) ? "st" :
1946 ((device->mAmbiOrder%10) == 2) ? "nd" :
1947 ((device->mAmbiOrder%10) == 3) ? "rd" : "th");
1948 else
1950 device->mAmbiLayout = DevAmbiLayout::FuMa;
1951 device->mAmbiScale = DevAmbiScaling::FuMa;
1954 else if(al::strcasecmp(fmt, "acn+fuma") == 0)
1956 if(device->mAmbiOrder > 3)
1957 ERR("FuMa is incompatible with %d%s order ambisonics (up to 3rd order only)\n",
1958 device->mAmbiOrder,
1959 (((device->mAmbiOrder%100)/10) == 1) ? "th" :
1960 ((device->mAmbiOrder%10) == 1) ? "st" :
1961 ((device->mAmbiOrder%10) == 2) ? "nd" :
1962 ((device->mAmbiOrder%10) == 3) ? "rd" : "th");
1963 else
1965 device->mAmbiLayout = DevAmbiLayout::ACN;
1966 device->mAmbiScale = DevAmbiScaling::FuMa;
1969 else if(al::strcasecmp(fmt, "ambix") == 0 || al::strcasecmp(fmt, "acn+sn3d") == 0)
1971 device->mAmbiLayout = DevAmbiLayout::ACN;
1972 device->mAmbiScale = DevAmbiScaling::SN3D;
1974 else if(al::strcasecmp(fmt, "acn+n3d") == 0)
1976 device->mAmbiLayout = DevAmbiLayout::ACN;
1977 device->mAmbiScale = DevAmbiScaling::N3D;
1979 else
1980 ERR("Unsupported ambi-format: %s\n", fmt);
1983 if(auto persizeopt = device->configValue<uint>(nullptr, "period_size"))
1984 device->UpdateSize = clampu(*persizeopt, 64, 8192);
1986 if(auto peropt = device->configValue<uint>(nullptr, "periods"))
1987 device->BufferSize = device->UpdateSize * clampu(*peropt, 2, 16);
1988 else
1989 device->BufferSize = maxu(device->BufferSize, device->UpdateSize*2);
1991 if(auto hrtfopt = device->configValue<std::string>(nullptr, "hrtf"))
1993 const char *hrtf{hrtfopt->c_str()};
1994 if(al::strcasecmp(hrtf, "true") == 0)
1996 stereomode = StereoEncoding::Hrtf;
1997 device->FmtChans = DevFmtStereo;
1998 device->Flags.set(ChannelsRequest);
2000 else if(al::strcasecmp(hrtf, "false") == 0)
2002 if(!stereomode || *stereomode == StereoEncoding::Hrtf)
2003 stereomode = StereoEncoding::Default;
2005 else if(al::strcasecmp(hrtf, "auto") != 0)
2006 ERR("Unexpected hrtf value: %s\n", hrtf);
2010 TRACE("Pre-reset: %s%s, %s%s, %s%uhz, %u / %u buffer\n",
2011 device->Flags.test(ChannelsRequest)?"*":"", DevFmtChannelsString(device->FmtChans),
2012 device->Flags.test(SampleTypeRequest)?"*":"", DevFmtTypeString(device->FmtType),
2013 device->Flags.test(FrequencyRequest)?"*":"", device->Frequency,
2014 device->UpdateSize, device->BufferSize);
2016 const uint oldFreq{device->Frequency};
2017 const DevFmtChannels oldChans{device->FmtChans};
2018 const DevFmtType oldType{device->FmtType};
2019 try {
2020 auto backend = device->Backend.get();
2021 if(!backend->reset())
2022 throw al::backend_exception{al::backend_error::DeviceError, "Device reset failure"};
2024 catch(std::exception &e) {
2025 ERR("Device error: %s\n", e.what());
2026 device->handleDisconnect("%s", e.what());
2027 return ALC_INVALID_DEVICE;
2030 if(device->FmtChans != oldChans && device->Flags.test(ChannelsRequest))
2032 ERR("Failed to set %s, got %s instead\n", DevFmtChannelsString(oldChans),
2033 DevFmtChannelsString(device->FmtChans));
2034 device->Flags.reset(ChannelsRequest);
2036 if(device->FmtType != oldType && device->Flags.test(SampleTypeRequest))
2038 ERR("Failed to set %s, got %s instead\n", DevFmtTypeString(oldType),
2039 DevFmtTypeString(device->FmtType));
2040 device->Flags.reset(SampleTypeRequest);
2042 if(device->Frequency != oldFreq && device->Flags.test(FrequencyRequest))
2044 WARN("Failed to set %uhz, got %uhz instead\n", oldFreq, device->Frequency);
2045 device->Flags.reset(FrequencyRequest);
2048 TRACE("Post-reset: %s, %s, %uhz, %u / %u buffer\n",
2049 DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType),
2050 device->Frequency, device->UpdateSize, device->BufferSize);
2052 if(device->Type != DeviceType::Loopback)
2054 if(auto modeopt = device->configValue<std::string>(nullptr, "stereo-mode"))
2056 const char *mode{modeopt->c_str()};
2057 if(al::strcasecmp(mode, "headphones") == 0)
2058 device->Flags.set(DirectEar);
2059 else if(al::strcasecmp(mode, "speakers") == 0)
2060 device->Flags.reset(DirectEar);
2061 else if(al::strcasecmp(mode, "auto") != 0)
2062 ERR("Unexpected stereo-mode: %s\n", mode);
2065 if(auto encopt = device->configValue<std::string>(nullptr, "stereo-encoding"))
2067 const char *mode{encopt->c_str()};
2068 if(al::strcasecmp(mode, "panpot") == 0)
2069 stereomode = al::make_optional(StereoEncoding::Basic);
2070 else if(al::strcasecmp(mode, "uhj") == 0)
2071 stereomode = al::make_optional(StereoEncoding::Uhj);
2072 else if(al::strcasecmp(mode, "hrtf") == 0)
2073 stereomode = al::make_optional(StereoEncoding::Hrtf);
2074 else
2075 ERR("Unexpected stereo-encoding: %s\n", mode);
2079 aluInitRenderer(device, hrtf_id, stereomode);
2081 TRACE("Max sources: %d (%d + %d), effect slots: %d, sends: %d\n",
2082 device->SourcesMax, device->NumMonoSources, device->NumStereoSources,
2083 device->AuxiliaryEffectSlotMax, device->NumAuxSends);
2085 switch(device->FmtChans)
2087 case DevFmtMono: break;
2088 case DevFmtStereo:
2089 if(!device->mUhjEncoder)
2090 device->RealOut.RemixMap = StereoDownmix;
2091 break;
2092 case DevFmtQuad: device->RealOut.RemixMap = QuadDownmix; break;
2093 case DevFmtX51: device->RealOut.RemixMap = X51Downmix; break;
2094 case DevFmtX61: device->RealOut.RemixMap = X61Downmix; break;
2095 case DevFmtX71: device->RealOut.RemixMap = X71Downmix; break;
2096 case DevFmtX3D71: device->RealOut.RemixMap = X51Downmix; break;
2097 case DevFmtAmbi3D: break;
2100 nanoseconds::rep sample_delay{0};
2101 if(device->mUhjEncoder)
2102 sample_delay += UhjEncoder::sFilterDelay;
2103 if(auto *ambidec = device->AmbiDecoder.get())
2105 if(ambidec->hasStablizer())
2106 sample_delay += FrontStablizer::DelayLength;
2109 if(device->getConfigValueBool(nullptr, "dither", true))
2111 int depth{device->configValue<int>(nullptr, "dither-depth").value_or(0)};
2112 if(depth <= 0)
2114 switch(device->FmtType)
2116 case DevFmtByte:
2117 case DevFmtUByte:
2118 depth = 8;
2119 break;
2120 case DevFmtShort:
2121 case DevFmtUShort:
2122 depth = 16;
2123 break;
2124 case DevFmtInt:
2125 case DevFmtUInt:
2126 case DevFmtFloat:
2127 break;
2131 if(depth > 0)
2133 depth = clampi(depth, 2, 24);
2134 device->DitherDepth = std::pow(2.0f, static_cast<float>(depth-1));
2137 if(!(device->DitherDepth > 0.0f))
2138 TRACE("Dithering disabled\n");
2139 else
2140 TRACE("Dithering enabled (%d-bit, %g)\n", float2int(std::log2(device->DitherDepth)+0.5f)+1,
2141 device->DitherDepth);
2143 if(auto limopt = device->configValue<bool>(nullptr, "output-limiter"))
2144 optlimit = limopt;
2146 /* If the gain limiter is unset, use the limiter for integer-based output
2147 * (where samples must be clamped), and don't for floating-point (which can
2148 * take unclamped samples).
2150 if(!optlimit)
2152 switch(device->FmtType)
2154 case DevFmtByte:
2155 case DevFmtUByte:
2156 case DevFmtShort:
2157 case DevFmtUShort:
2158 case DevFmtInt:
2159 case DevFmtUInt:
2160 optlimit = true;
2161 break;
2162 case DevFmtFloat:
2163 break;
2166 if(optlimit.value_or(false) == false)
2167 TRACE("Output limiter disabled\n");
2168 else
2170 float thrshld{1.0f};
2171 switch(device->FmtType)
2173 case DevFmtByte:
2174 case DevFmtUByte:
2175 thrshld = 127.0f / 128.0f;
2176 break;
2177 case DevFmtShort:
2178 case DevFmtUShort:
2179 thrshld = 32767.0f / 32768.0f;
2180 break;
2181 case DevFmtInt:
2182 case DevFmtUInt:
2183 case DevFmtFloat:
2184 break;
2186 if(device->DitherDepth > 0.0f)
2187 thrshld -= 1.0f / device->DitherDepth;
2189 const float thrshld_dB{std::log10(thrshld) * 20.0f};
2190 auto limiter = CreateDeviceLimiter(device, thrshld_dB);
2192 sample_delay += limiter->getLookAhead();
2193 device->Limiter = std::move(limiter);
2194 TRACE("Output limiter enabled, %.4fdB limit\n", thrshld_dB);
2197 /* Convert the sample delay from samples to nanosamples to nanoseconds. */
2198 device->FixedLatency += nanoseconds{seconds{sample_delay}} / device->Frequency;
2199 TRACE("Fixed device latency: %" PRId64 "ns\n", int64_t{device->FixedLatency.count()});
2201 FPUCtl mixer_mode{};
2202 for(ContextBase *ctxbase : *device->mContexts.load())
2204 auto *context = static_cast<ALCcontext*>(ctxbase);
2206 auto GetEffectBuffer = [](ALbuffer *buffer) noexcept -> EffectState::Buffer
2208 if(!buffer) return EffectState::Buffer{};
2209 return EffectState::Buffer{buffer, buffer->mData};
2211 std::unique_lock<std::mutex> proplock{context->mPropLock};
2212 std::unique_lock<std::mutex> slotlock{context->mEffectSlotLock};
2214 /* Clear out unused wet buffers. */
2215 auto buffer_not_in_use = [](WetBufferPtr &wetbuffer) noexcept -> bool
2216 { return !wetbuffer->mInUse; };
2217 auto wetbuffer_iter = std::remove_if(context->mWetBuffers.begin(),
2218 context->mWetBuffers.end(), buffer_not_in_use);
2219 context->mWetBuffers.erase(wetbuffer_iter, context->mWetBuffers.end());
2221 if(ALeffectslot *slot{context->mDefaultSlot.get()})
2223 aluInitEffectPanning(&slot->mSlot, context);
2225 EffectState *state{slot->Effect.State.get()};
2226 state->mOutTarget = device->Dry.Buffer;
2227 state->deviceUpdate(device, GetEffectBuffer(slot->Buffer));
2228 slot->updateProps(context);
2231 if(EffectSlotArray *curarray{context->mActiveAuxSlots.load(std::memory_order_relaxed)})
2232 std::fill_n(curarray->end(), curarray->size(), nullptr);
2233 for(auto &sublist : context->mEffectSlotList)
2235 uint64_t usemask{~sublist.FreeMask};
2236 while(usemask)
2238 const int idx{al::countr_zero(usemask)};
2239 ALeffectslot *slot{sublist.EffectSlots + idx};
2240 usemask &= ~(1_u64 << idx);
2242 aluInitEffectPanning(&slot->mSlot, context);
2244 EffectState *state{slot->Effect.State.get()};
2245 state->mOutTarget = device->Dry.Buffer;
2246 state->deviceUpdate(device, GetEffectBuffer(slot->Buffer));
2247 slot->updateProps(context);
2250 slotlock.unlock();
2252 const uint num_sends{device->NumAuxSends};
2253 std::unique_lock<std::mutex> srclock{context->mSourceLock};
2254 for(auto &sublist : context->mSourceList)
2256 uint64_t usemask{~sublist.FreeMask};
2257 while(usemask)
2259 const int idx{al::countr_zero(usemask)};
2260 ALsource *source{sublist.Sources + idx};
2261 usemask &= ~(1_u64 << idx);
2263 auto clear_send = [](ALsource::SendData &send) -> void
2265 if(send.Slot)
2266 DecrementRef(send.Slot->ref);
2267 send.Slot = nullptr;
2268 send.Gain = 1.0f;
2269 send.GainHF = 1.0f;
2270 send.HFReference = LOWPASSFREQREF;
2271 send.GainLF = 1.0f;
2272 send.LFReference = HIGHPASSFREQREF;
2274 auto send_begin = source->Send.begin() + static_cast<ptrdiff_t>(num_sends);
2275 std::for_each(send_begin, source->Send.end(), clear_send);
2277 source->mPropsDirty = true;
2281 auto voicelist = context->getVoicesSpan();
2282 for(Voice *voice : voicelist)
2284 /* Clear extraneous property set sends. */
2285 std::fill(std::begin(voice->mProps.Send)+num_sends, std::end(voice->mProps.Send),
2286 VoiceProps::SendData{});
2288 std::fill(voice->mSend.begin()+num_sends, voice->mSend.end(), Voice::TargetData{});
2289 for(auto &chandata : voice->mChans)
2291 std::fill(chandata.mWetParams.begin()+num_sends, chandata.mWetParams.end(),
2292 SendParams{});
2295 if(VoicePropsItem *props{voice->mUpdate.exchange(nullptr, std::memory_order_relaxed)})
2296 AtomicReplaceHead(context->mFreeVoiceProps, props);
2298 /* Force the voice to stopped if it was stopping. */
2299 Voice::State vstate{Voice::Stopping};
2300 voice->mPlayState.compare_exchange_strong(vstate, Voice::Stopped,
2301 std::memory_order_acquire, std::memory_order_acquire);
2302 if(voice->mSourceID.load(std::memory_order_relaxed) == 0u)
2303 continue;
2305 voice->prepare(device);
2307 /* Clear all voice props to let them get allocated again. */
2308 context->mVoicePropClusters.clear();
2309 context->mFreeVoiceProps.store(nullptr, std::memory_order_relaxed);
2310 srclock.unlock();
2312 context->mPropsDirty = false;
2313 UpdateContextProps(context);
2314 UpdateAllSourceProps(context);
2316 mixer_mode.leave();
2318 if(!device->Flags.test(DevicePaused))
2320 try {
2321 auto backend = device->Backend.get();
2322 backend->start();
2323 device->Flags.set(DeviceRunning);
2325 catch(al::backend_exception& e) {
2326 ERR("%s\n", e.what());
2327 device->handleDisconnect("%s", e.what());
2328 return ALC_INVALID_DEVICE;
2330 TRACE("Post-start: %s, %s, %uhz, %u / %u buffer\n",
2331 DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType),
2332 device->Frequency, device->UpdateSize, device->BufferSize);
2335 return ALC_NO_ERROR;
2339 * Updates device parameters as above, and also first clears the disconnected
2340 * status, if set.
2342 bool ResetDeviceParams(ALCdevice *device, const int *attrList)
2344 /* If the device was disconnected, reset it since we're opened anew. */
2345 if UNLIKELY(!device->Connected.load(std::memory_order_relaxed))
2347 /* Make sure disconnection is finished before continuing on. */
2348 device->waitForMix();
2350 for(ContextBase *ctxbase : *device->mContexts.load(std::memory_order_acquire))
2352 auto *ctx = static_cast<ALCcontext*>(ctxbase);
2353 if(!ctx->mStopVoicesOnDisconnect.load(std::memory_order_acquire))
2354 continue;
2356 /* Clear any pending voice changes and reallocate voices to get a
2357 * clean restart.
2359 std::lock_guard<std::mutex> __{ctx->mSourceLock};
2360 auto *vchg = ctx->mCurrentVoiceChange.load(std::memory_order_acquire);
2361 while(auto *next = vchg->mNext.load(std::memory_order_acquire))
2362 vchg = next;
2363 ctx->mCurrentVoiceChange.store(vchg, std::memory_order_release);
2365 ctx->mVoicePropClusters.clear();
2366 ctx->mFreeVoiceProps.store(nullptr, std::memory_order_relaxed);
2368 ctx->mVoiceClusters.clear();
2369 ctx->allocVoices(std::max<size_t>(256,
2370 ctx->mActiveVoiceCount.load(std::memory_order_relaxed)));
2373 device->Connected.store(true);
2376 ALCenum err{UpdateDeviceParams(device, attrList)};
2377 if LIKELY(err == ALC_NO_ERROR) return ALC_TRUE;
2379 alcSetError(device, err);
2380 return ALC_FALSE;
2384 /** Checks if the device handle is valid, and returns a new reference if so. */
2385 DeviceRef VerifyDevice(ALCdevice *device)
2387 std::lock_guard<std::recursive_mutex> _{ListLock};
2388 auto iter = std::lower_bound(DeviceList.begin(), DeviceList.end(), device);
2389 if(iter != DeviceList.end() && *iter == device)
2391 (*iter)->add_ref();
2392 return DeviceRef{*iter};
2394 return nullptr;
2399 * Checks if the given context is valid, returning a new reference to it if so.
2401 ContextRef VerifyContext(ALCcontext *context)
2403 std::lock_guard<std::recursive_mutex> _{ListLock};
2404 auto iter = std::lower_bound(ContextList.begin(), ContextList.end(), context);
2405 if(iter != ContextList.end() && *iter == context)
2407 (*iter)->add_ref();
2408 return ContextRef{*iter};
2410 return nullptr;
2413 } // namespace
2415 /** Returns a new reference to the currently active context for this thread. */
2416 ContextRef GetContextRef(void)
2418 ALCcontext *context{ALCcontext::getThreadContext()};
2419 if(context)
2420 context->add_ref();
2421 else
2423 std::lock_guard<std::recursive_mutex> _{ListLock};
2424 context = ALCcontext::sGlobalContext.load(std::memory_order_acquire);
2425 if(context) context->add_ref();
2427 return ContextRef{context};
2431 /************************************************
2432 * Standard ALC functions
2433 ************************************************/
2435 ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device)
2436 START_API_FUNC
2438 DeviceRef dev{VerifyDevice(device)};
2439 if(dev) return dev->LastError.exchange(ALC_NO_ERROR);
2440 return LastNullDeviceError.exchange(ALC_NO_ERROR);
2442 END_API_FUNC
2445 ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context)
2446 START_API_FUNC
2448 if(!SuspendDefers)
2449 return;
2451 ContextRef ctx{VerifyContext(context)};
2452 if(!ctx)
2453 alcSetError(nullptr, ALC_INVALID_CONTEXT);
2454 else
2456 std::lock_guard<std::mutex> _{ctx->mPropLock};
2457 ctx->deferUpdates();
2460 END_API_FUNC
2462 ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context)
2463 START_API_FUNC
2465 if(!SuspendDefers)
2466 return;
2468 ContextRef ctx{VerifyContext(context)};
2469 if(!ctx)
2470 alcSetError(nullptr, ALC_INVALID_CONTEXT);
2471 else
2473 std::lock_guard<std::mutex> _{ctx->mPropLock};
2474 ctx->processUpdates();
2477 END_API_FUNC
2480 ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum param)
2481 START_API_FUNC
2483 const ALCchar *value{nullptr};
2485 switch(param)
2487 case ALC_NO_ERROR:
2488 value = alcNoError;
2489 break;
2491 case ALC_INVALID_ENUM:
2492 value = alcErrInvalidEnum;
2493 break;
2495 case ALC_INVALID_VALUE:
2496 value = alcErrInvalidValue;
2497 break;
2499 case ALC_INVALID_DEVICE:
2500 value = alcErrInvalidDevice;
2501 break;
2503 case ALC_INVALID_CONTEXT:
2504 value = alcErrInvalidContext;
2505 break;
2507 case ALC_OUT_OF_MEMORY:
2508 value = alcErrOutOfMemory;
2509 break;
2511 case ALC_DEVICE_SPECIFIER:
2512 value = alcDefaultName;
2513 break;
2515 case ALC_ALL_DEVICES_SPECIFIER:
2516 if(DeviceRef dev{VerifyDevice(Device)})
2518 if(dev->Type == DeviceType::Capture)
2519 alcSetError(dev.get(), ALC_INVALID_ENUM);
2520 else if(dev->Type == DeviceType::Loopback)
2521 value = alcDefaultName;
2522 else
2524 std::lock_guard<std::mutex> _{dev->StateLock};
2525 value = dev->DeviceName.c_str();
2528 else
2530 ProbeAllDevicesList();
2531 value = alcAllDevicesList.c_str();
2533 break;
2535 case ALC_CAPTURE_DEVICE_SPECIFIER:
2536 if(DeviceRef dev{VerifyDevice(Device)})
2538 if(dev->Type != DeviceType::Capture)
2539 alcSetError(dev.get(), ALC_INVALID_ENUM);
2540 else
2542 std::lock_guard<std::mutex> _{dev->StateLock};
2543 value = dev->DeviceName.c_str();
2546 else
2548 ProbeCaptureDeviceList();
2549 value = alcCaptureDeviceList.c_str();
2551 break;
2553 /* Default devices are always first in the list */
2554 case ALC_DEFAULT_DEVICE_SPECIFIER:
2555 value = alcDefaultName;
2556 break;
2558 case ALC_DEFAULT_ALL_DEVICES_SPECIFIER:
2559 if(alcAllDevicesList.empty())
2560 ProbeAllDevicesList();
2562 /* Copy first entry as default. */
2563 alcDefaultAllDevicesSpecifier = alcAllDevicesList.c_str();
2564 value = alcDefaultAllDevicesSpecifier.c_str();
2565 break;
2567 case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER:
2568 if(alcCaptureDeviceList.empty())
2569 ProbeCaptureDeviceList();
2571 /* Copy first entry as default. */
2572 alcCaptureDefaultDeviceSpecifier = alcCaptureDeviceList.c_str();
2573 value = alcCaptureDefaultDeviceSpecifier.c_str();
2574 break;
2576 case ALC_EXTENSIONS:
2577 if(VerifyDevice(Device))
2578 value = alcExtensionList;
2579 else
2580 value = alcNoDeviceExtList;
2581 break;
2583 case ALC_HRTF_SPECIFIER_SOFT:
2584 if(DeviceRef dev{VerifyDevice(Device)})
2586 std::lock_guard<std::mutex> _{dev->StateLock};
2587 value = (dev->mHrtf ? dev->mHrtfName.c_str() : "");
2589 else
2590 alcSetError(nullptr, ALC_INVALID_DEVICE);
2591 break;
2593 default:
2594 alcSetError(VerifyDevice(Device).get(), ALC_INVALID_ENUM);
2595 break;
2598 return value;
2600 END_API_FUNC
2603 static size_t GetIntegerv(ALCdevice *device, ALCenum param, const al::span<int> values)
2605 size_t i;
2607 if(values.empty())
2609 alcSetError(device, ALC_INVALID_VALUE);
2610 return 0;
2613 if(!device)
2615 switch(param)
2617 case ALC_MAJOR_VERSION:
2618 values[0] = alcMajorVersion;
2619 return 1;
2620 case ALC_MINOR_VERSION:
2621 values[0] = alcMinorVersion;
2622 return 1;
2624 case ALC_EFX_MAJOR_VERSION:
2625 values[0] = alcEFXMajorVersion;
2626 return 1;
2627 case ALC_EFX_MINOR_VERSION:
2628 values[0] = alcEFXMinorVersion;
2629 return 1;
2630 case ALC_MAX_AUXILIARY_SENDS:
2631 values[0] = MAX_SENDS;
2632 return 1;
2634 case ALC_ATTRIBUTES_SIZE:
2635 case ALC_ALL_ATTRIBUTES:
2636 case ALC_FREQUENCY:
2637 case ALC_REFRESH:
2638 case ALC_SYNC:
2639 case ALC_MONO_SOURCES:
2640 case ALC_STEREO_SOURCES:
2641 case ALC_CAPTURE_SAMPLES:
2642 case ALC_FORMAT_CHANNELS_SOFT:
2643 case ALC_FORMAT_TYPE_SOFT:
2644 case ALC_AMBISONIC_LAYOUT_SOFT:
2645 case ALC_AMBISONIC_SCALING_SOFT:
2646 case ALC_AMBISONIC_ORDER_SOFT:
2647 case ALC_MAX_AMBISONIC_ORDER_SOFT:
2648 alcSetError(nullptr, ALC_INVALID_DEVICE);
2649 return 0;
2651 default:
2652 alcSetError(nullptr, ALC_INVALID_ENUM);
2654 return 0;
2657 std::lock_guard<std::mutex> _{device->StateLock};
2658 if(device->Type == DeviceType::Capture)
2660 static constexpr int MaxCaptureAttributes{9};
2661 switch(param)
2663 case ALC_ATTRIBUTES_SIZE:
2664 values[0] = MaxCaptureAttributes;
2665 return 1;
2666 case ALC_ALL_ATTRIBUTES:
2667 i = 0;
2668 if(values.size() < MaxCaptureAttributes)
2669 alcSetError(device, ALC_INVALID_VALUE);
2670 else
2672 values[i++] = ALC_MAJOR_VERSION;
2673 values[i++] = alcMajorVersion;
2674 values[i++] = ALC_MINOR_VERSION;
2675 values[i++] = alcMinorVersion;
2676 values[i++] = ALC_CAPTURE_SAMPLES;
2677 values[i++] = static_cast<int>(device->Backend->availableSamples());
2678 values[i++] = ALC_CONNECTED;
2679 values[i++] = device->Connected.load(std::memory_order_relaxed);
2680 values[i++] = 0;
2681 assert(i == MaxCaptureAttributes);
2683 return i;
2685 case ALC_MAJOR_VERSION:
2686 values[0] = alcMajorVersion;
2687 return 1;
2688 case ALC_MINOR_VERSION:
2689 values[0] = alcMinorVersion;
2690 return 1;
2692 case ALC_CAPTURE_SAMPLES:
2693 values[0] = static_cast<int>(device->Backend->availableSamples());
2694 return 1;
2696 case ALC_CONNECTED:
2697 values[0] = device->Connected.load(std::memory_order_acquire);
2698 return 1;
2700 default:
2701 alcSetError(device, ALC_INVALID_ENUM);
2703 return 0;
2706 /* render device */
2707 auto NumAttrsForDevice = [](ALCdevice *aldev) noexcept
2709 if(aldev->Type == DeviceType::Loopback && aldev->FmtChans == DevFmtAmbi3D)
2710 return 37;
2711 return 31;
2713 switch(param)
2715 case ALC_ATTRIBUTES_SIZE:
2716 values[0] = NumAttrsForDevice(device);
2717 return 1;
2719 case ALC_ALL_ATTRIBUTES:
2720 i = 0;
2721 if(values.size() < static_cast<size_t>(NumAttrsForDevice(device)))
2722 alcSetError(device, ALC_INVALID_VALUE);
2723 else
2725 values[i++] = ALC_MAJOR_VERSION;
2726 values[i++] = alcMajorVersion;
2727 values[i++] = ALC_MINOR_VERSION;
2728 values[i++] = alcMinorVersion;
2729 values[i++] = ALC_EFX_MAJOR_VERSION;
2730 values[i++] = alcEFXMajorVersion;
2731 values[i++] = ALC_EFX_MINOR_VERSION;
2732 values[i++] = alcEFXMinorVersion;
2734 values[i++] = ALC_FREQUENCY;
2735 values[i++] = static_cast<int>(device->Frequency);
2736 if(device->Type != DeviceType::Loopback)
2738 values[i++] = ALC_REFRESH;
2739 values[i++] = static_cast<int>(device->Frequency / device->UpdateSize);
2741 values[i++] = ALC_SYNC;
2742 values[i++] = ALC_FALSE;
2744 else
2746 if(device->FmtChans == DevFmtAmbi3D)
2748 values[i++] = ALC_AMBISONIC_LAYOUT_SOFT;
2749 values[i++] = EnumFromDevAmbi(device->mAmbiLayout);
2751 values[i++] = ALC_AMBISONIC_SCALING_SOFT;
2752 values[i++] = EnumFromDevAmbi(device->mAmbiScale);
2754 values[i++] = ALC_AMBISONIC_ORDER_SOFT;
2755 values[i++] = static_cast<int>(device->mAmbiOrder);
2758 values[i++] = ALC_FORMAT_CHANNELS_SOFT;
2759 values[i++] = EnumFromDevFmt(device->FmtChans);
2761 values[i++] = ALC_FORMAT_TYPE_SOFT;
2762 values[i++] = EnumFromDevFmt(device->FmtType);
2765 values[i++] = ALC_MONO_SOURCES;
2766 values[i++] = static_cast<int>(device->NumMonoSources);
2768 values[i++] = ALC_STEREO_SOURCES;
2769 values[i++] = static_cast<int>(device->NumStereoSources);
2771 values[i++] = ALC_MAX_AUXILIARY_SENDS;
2772 values[i++] = static_cast<int>(device->NumAuxSends);
2774 values[i++] = ALC_HRTF_SOFT;
2775 values[i++] = (device->mHrtf ? ALC_TRUE : ALC_FALSE);
2777 values[i++] = ALC_HRTF_STATUS_SOFT;
2778 values[i++] = device->mHrtfStatus;
2780 values[i++] = ALC_OUTPUT_LIMITER_SOFT;
2781 values[i++] = device->Limiter ? ALC_TRUE : ALC_FALSE;
2783 values[i++] = ALC_MAX_AMBISONIC_ORDER_SOFT;
2784 values[i++] = MaxAmbiOrder;
2786 values[i++] = ALC_OUTPUT_MODE_SOFT;
2787 values[i++] = static_cast<ALCenum>(device->getOutputMode1());
2789 values[i++] = 0;
2791 return i;
2793 case ALC_MAJOR_VERSION:
2794 values[0] = alcMajorVersion;
2795 return 1;
2797 case ALC_MINOR_VERSION:
2798 values[0] = alcMinorVersion;
2799 return 1;
2801 case ALC_EFX_MAJOR_VERSION:
2802 values[0] = alcEFXMajorVersion;
2803 return 1;
2805 case ALC_EFX_MINOR_VERSION:
2806 values[0] = alcEFXMinorVersion;
2807 return 1;
2809 case ALC_FREQUENCY:
2810 values[0] = static_cast<int>(device->Frequency);
2811 return 1;
2813 case ALC_REFRESH:
2814 if(device->Type == DeviceType::Loopback)
2816 alcSetError(device, ALC_INVALID_DEVICE);
2817 return 0;
2819 values[0] = static_cast<int>(device->Frequency / device->UpdateSize);
2820 return 1;
2822 case ALC_SYNC:
2823 if(device->Type == DeviceType::Loopback)
2825 alcSetError(device, ALC_INVALID_DEVICE);
2826 return 0;
2828 values[0] = ALC_FALSE;
2829 return 1;
2831 case ALC_FORMAT_CHANNELS_SOFT:
2832 if(device->Type != DeviceType::Loopback)
2834 alcSetError(device, ALC_INVALID_DEVICE);
2835 return 0;
2837 values[0] = EnumFromDevFmt(device->FmtChans);
2838 return 1;
2840 case ALC_FORMAT_TYPE_SOFT:
2841 if(device->Type != DeviceType::Loopback)
2843 alcSetError(device, ALC_INVALID_DEVICE);
2844 return 0;
2846 values[0] = EnumFromDevFmt(device->FmtType);
2847 return 1;
2849 case ALC_AMBISONIC_LAYOUT_SOFT:
2850 if(device->Type != DeviceType::Loopback || device->FmtChans != DevFmtAmbi3D)
2852 alcSetError(device, ALC_INVALID_DEVICE);
2853 return 0;
2855 values[0] = EnumFromDevAmbi(device->mAmbiLayout);
2856 return 1;
2858 case ALC_AMBISONIC_SCALING_SOFT:
2859 if(device->Type != DeviceType::Loopback || device->FmtChans != DevFmtAmbi3D)
2861 alcSetError(device, ALC_INVALID_DEVICE);
2862 return 0;
2864 values[0] = EnumFromDevAmbi(device->mAmbiScale);
2865 return 1;
2867 case ALC_AMBISONIC_ORDER_SOFT:
2868 if(device->Type != DeviceType::Loopback || device->FmtChans != DevFmtAmbi3D)
2870 alcSetError(device, ALC_INVALID_DEVICE);
2871 return 0;
2873 values[0] = static_cast<int>(device->mAmbiOrder);
2874 return 1;
2876 case ALC_MONO_SOURCES:
2877 values[0] = static_cast<int>(device->NumMonoSources);
2878 return 1;
2880 case ALC_STEREO_SOURCES:
2881 values[0] = static_cast<int>(device->NumStereoSources);
2882 return 1;
2884 case ALC_MAX_AUXILIARY_SENDS:
2885 values[0] = static_cast<int>(device->NumAuxSends);
2886 return 1;
2888 case ALC_CONNECTED:
2889 values[0] = device->Connected.load(std::memory_order_acquire);
2890 return 1;
2892 case ALC_HRTF_SOFT:
2893 values[0] = (device->mHrtf ? ALC_TRUE : ALC_FALSE);
2894 return 1;
2896 case ALC_HRTF_STATUS_SOFT:
2897 values[0] = device->mHrtfStatus;
2898 return 1;
2900 case ALC_NUM_HRTF_SPECIFIERS_SOFT:
2901 device->enumerateHrtfs();
2902 values[0] = static_cast<int>(minz(device->mHrtfList.size(),
2903 std::numeric_limits<int>::max()));
2904 return 1;
2906 case ALC_OUTPUT_LIMITER_SOFT:
2907 values[0] = device->Limiter ? ALC_TRUE : ALC_FALSE;
2908 return 1;
2910 case ALC_MAX_AMBISONIC_ORDER_SOFT:
2911 values[0] = MaxAmbiOrder;
2912 return 1;
2914 case ALC_OUTPUT_MODE_SOFT:
2915 values[0] = static_cast<ALCenum>(device->getOutputMode1());
2916 return 1;
2918 default:
2919 alcSetError(device, ALC_INVALID_ENUM);
2921 return 0;
2924 ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values)
2925 START_API_FUNC
2927 DeviceRef dev{VerifyDevice(device)};
2928 if(size <= 0 || values == nullptr)
2929 alcSetError(dev.get(), ALC_INVALID_VALUE);
2930 else
2931 GetIntegerv(dev.get(), param, {values, static_cast<uint>(size)});
2933 END_API_FUNC
2935 ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, ALCsizei size, ALCint64SOFT *values)
2936 START_API_FUNC
2938 DeviceRef dev{VerifyDevice(device)};
2939 if(size <= 0 || values == nullptr)
2941 alcSetError(dev.get(), ALC_INVALID_VALUE);
2942 return;
2944 if(!dev || dev->Type == DeviceType::Capture)
2946 auto ivals = al::vector<int>(static_cast<uint>(size));
2947 if(size_t got{GetIntegerv(dev.get(), pname, ivals)})
2948 std::copy_n(ivals.begin(), got, values);
2949 return;
2951 /* render device */
2952 auto NumAttrsForDevice = [](ALCdevice *aldev) noexcept
2954 if(aldev->Type == DeviceType::Loopback && aldev->FmtChans == DevFmtAmbi3D)
2955 return 41;
2956 return 35;
2958 std::lock_guard<std::mutex> _{dev->StateLock};
2959 switch(pname)
2961 case ALC_ATTRIBUTES_SIZE:
2962 *values = NumAttrsForDevice(dev.get());
2963 break;
2965 case ALC_ALL_ATTRIBUTES:
2966 if(size < NumAttrsForDevice(dev.get()))
2967 alcSetError(dev.get(), ALC_INVALID_VALUE);
2968 else
2970 size_t i{0};
2971 values[i++] = ALC_FREQUENCY;
2972 values[i++] = dev->Frequency;
2974 if(dev->Type != DeviceType::Loopback)
2976 values[i++] = ALC_REFRESH;
2977 values[i++] = dev->Frequency / dev->UpdateSize;
2979 values[i++] = ALC_SYNC;
2980 values[i++] = ALC_FALSE;
2982 else
2984 values[i++] = ALC_FORMAT_CHANNELS_SOFT;
2985 values[i++] = EnumFromDevFmt(dev->FmtChans);
2987 values[i++] = ALC_FORMAT_TYPE_SOFT;
2988 values[i++] = EnumFromDevFmt(dev->FmtType);
2990 if(dev->FmtChans == DevFmtAmbi3D)
2992 values[i++] = ALC_AMBISONIC_LAYOUT_SOFT;
2993 values[i++] = EnumFromDevAmbi(dev->mAmbiLayout);
2995 values[i++] = ALC_AMBISONIC_SCALING_SOFT;
2996 values[i++] = EnumFromDevAmbi(dev->mAmbiScale);
2998 values[i++] = ALC_AMBISONIC_ORDER_SOFT;
2999 values[i++] = dev->mAmbiOrder;
3003 values[i++] = ALC_MONO_SOURCES;
3004 values[i++] = dev->NumMonoSources;
3006 values[i++] = ALC_STEREO_SOURCES;
3007 values[i++] = dev->NumStereoSources;
3009 values[i++] = ALC_MAX_AUXILIARY_SENDS;
3010 values[i++] = dev->NumAuxSends;
3012 values[i++] = ALC_HRTF_SOFT;
3013 values[i++] = (dev->mHrtf ? ALC_TRUE : ALC_FALSE);
3015 values[i++] = ALC_HRTF_STATUS_SOFT;
3016 values[i++] = dev->mHrtfStatus;
3018 values[i++] = ALC_OUTPUT_LIMITER_SOFT;
3019 values[i++] = dev->Limiter ? ALC_TRUE : ALC_FALSE;
3021 ClockLatency clock{GetClockLatency(dev.get(), dev->Backend.get())};
3022 values[i++] = ALC_DEVICE_CLOCK_SOFT;
3023 values[i++] = clock.ClockTime.count();
3025 values[i++] = ALC_DEVICE_LATENCY_SOFT;
3026 values[i++] = clock.Latency.count();
3028 values[i++] = ALC_OUTPUT_MODE_SOFT;
3029 values[i++] = static_cast<ALCenum>(device->getOutputMode1());
3031 values[i++] = 0;
3033 break;
3035 case ALC_DEVICE_CLOCK_SOFT:
3037 uint samplecount, refcount;
3038 nanoseconds basecount;
3039 do {
3040 refcount = dev->waitForMix();
3041 basecount = dev->ClockBase;
3042 samplecount = dev->SamplesDone;
3043 } while(refcount != ReadRef(dev->MixCount));
3044 basecount += nanoseconds{seconds{samplecount}} / dev->Frequency;
3045 *values = basecount.count();
3047 break;
3049 case ALC_DEVICE_LATENCY_SOFT:
3050 *values = GetClockLatency(dev.get(), dev->Backend.get()).Latency.count();
3051 break;
3053 case ALC_DEVICE_CLOCK_LATENCY_SOFT:
3054 if(size < 2)
3055 alcSetError(dev.get(), ALC_INVALID_VALUE);
3056 else
3058 ClockLatency clock{GetClockLatency(dev.get(), dev->Backend.get())};
3059 values[0] = clock.ClockTime.count();
3060 values[1] = clock.Latency.count();
3062 break;
3064 default:
3065 auto ivals = al::vector<int>(static_cast<uint>(size));
3066 if(size_t got{GetIntegerv(dev.get(), pname, ivals)})
3067 std::copy_n(ivals.begin(), got, values);
3068 break;
3071 END_API_FUNC
3074 ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extName)
3075 START_API_FUNC
3077 DeviceRef dev{VerifyDevice(device)};
3078 if(!extName)
3079 alcSetError(dev.get(), ALC_INVALID_VALUE);
3080 else
3082 size_t len = strlen(extName);
3083 const char *ptr = (dev ? alcExtensionList : alcNoDeviceExtList);
3084 while(ptr && *ptr)
3086 if(al::strncasecmp(ptr, extName, len) == 0 && (ptr[len] == '\0' || isspace(ptr[len])))
3087 return ALC_TRUE;
3089 if((ptr=strchr(ptr, ' ')) != nullptr)
3091 do {
3092 ++ptr;
3093 } while(isspace(*ptr));
3097 return ALC_FALSE;
3099 END_API_FUNC
3102 ALC_API ALCvoid* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcName)
3103 START_API_FUNC
3105 if(!funcName)
3107 DeviceRef dev{VerifyDevice(device)};
3108 alcSetError(dev.get(), ALC_INVALID_VALUE);
3109 return nullptr;
3111 #ifdef ALSOFT_EAX
3112 if(eax_g_is_enabled)
3114 for(const auto &func : eaxFunctions)
3116 if(strcmp(func.funcName, funcName) == 0)
3117 return func.address;
3120 #endif
3121 for(const auto &func : alcFunctions)
3123 if(strcmp(func.funcName, funcName) == 0)
3124 return func.address;
3126 return nullptr;
3128 END_API_FUNC
3131 ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumName)
3132 START_API_FUNC
3134 if(!enumName)
3136 DeviceRef dev{VerifyDevice(device)};
3137 alcSetError(dev.get(), ALC_INVALID_VALUE);
3138 return 0;
3140 #ifdef ALSOFT_EAX
3141 if(eax_g_is_enabled)
3143 for(const auto &enm : eaxEnumerations)
3145 if(strcmp(enm.enumName, enumName) == 0)
3146 return enm.value;
3149 #endif
3150 for(const auto &enm : alcEnumerations)
3152 if(strcmp(enm.enumName, enumName) == 0)
3153 return enm.value;
3156 return 0;
3158 END_API_FUNC
3161 ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrList)
3162 START_API_FUNC
3164 /* Explicitly hold the list lock while taking the StateLock in case the
3165 * device is asynchronously destroyed, to ensure this new context is
3166 * properly cleaned up after being made.
3168 std::unique_lock<std::recursive_mutex> listlock{ListLock};
3169 DeviceRef dev{VerifyDevice(device)};
3170 if(!dev || dev->Type == DeviceType::Capture || !dev->Connected.load(std::memory_order_relaxed))
3172 listlock.unlock();
3173 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3174 return nullptr;
3176 std::unique_lock<std::mutex> statelock{dev->StateLock};
3177 listlock.unlock();
3179 dev->LastError.store(ALC_NO_ERROR);
3181 ALCenum err{UpdateDeviceParams(dev.get(), attrList)};
3182 if(err != ALC_NO_ERROR)
3184 alcSetError(dev.get(), err);
3185 return nullptr;
3188 ContextRef context{new ALCcontext{dev}};
3189 context->init();
3191 if(auto volopt = dev->configValue<float>(nullptr, "volume-adjust"))
3193 const float valf{*volopt};
3194 if(!std::isfinite(valf))
3195 ERR("volume-adjust must be finite: %f\n", valf);
3196 else
3198 const float db{clampf(valf, -24.0f, 24.0f)};
3199 if(db != valf)
3200 WARN("volume-adjust clamped: %f, range: +/-%f\n", valf, 24.0f);
3201 context->mGainBoost = std::pow(10.0f, db/20.0f);
3202 TRACE("volume-adjust gain: %f\n", context->mGainBoost);
3207 using ContextArray = al::FlexArray<ContextBase*>;
3209 /* Allocate a new context array, which holds 1 more than the current/
3210 * old array.
3212 auto *oldarray = device->mContexts.load();
3213 const size_t newcount{oldarray->size()+1};
3214 std::unique_ptr<ContextArray> newarray{ContextArray::Create(newcount)};
3216 /* Copy the current/old context handles to the new array, appending the
3217 * new context.
3219 auto iter = std::copy(oldarray->begin(), oldarray->end(), newarray->begin());
3220 *iter = context.get();
3222 /* Store the new context array in the device. Wait for any current mix
3223 * to finish before deleting the old array.
3225 dev->mContexts.store(newarray.release());
3226 if(oldarray != &DeviceBase::sEmptyContextArray)
3228 dev->waitForMix();
3229 delete oldarray;
3232 statelock.unlock();
3235 std::lock_guard<std::recursive_mutex> _{ListLock};
3236 auto iter = std::lower_bound(ContextList.cbegin(), ContextList.cend(), context.get());
3237 ContextList.emplace(iter, context.get());
3240 if(ALeffectslot *slot{context->mDefaultSlot.get()})
3242 ALenum sloterr{slot->initEffect(ALCcontext::sDefaultEffect.type,
3243 ALCcontext::sDefaultEffect.Props, context.get())};
3244 if(sloterr == AL_NO_ERROR)
3245 slot->updateProps(context.get());
3246 else
3247 ERR("Failed to initialize the default effect\n");
3250 TRACE("Created context %p\n", voidp{context.get()});
3251 return context.release();
3253 END_API_FUNC
3255 ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context)
3256 START_API_FUNC
3258 std::unique_lock<std::recursive_mutex> listlock{ListLock};
3259 auto iter = std::lower_bound(ContextList.begin(), ContextList.end(), context);
3260 if(iter == ContextList.end() || *iter != context)
3262 listlock.unlock();
3263 alcSetError(nullptr, ALC_INVALID_CONTEXT);
3264 return;
3267 /* Hold a reference to this context so it remains valid until the ListLock
3268 * is released.
3270 ContextRef ctx{*iter};
3271 ContextList.erase(iter);
3273 ALCdevice *Device{ctx->mALDevice.get()};
3275 std::lock_guard<std::mutex> _{Device->StateLock};
3276 if(!ctx->deinit() && Device->Flags.test(DeviceRunning))
3278 Device->Backend->stop();
3279 Device->Flags.reset(DeviceRunning);
3282 END_API_FUNC
3285 ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void)
3286 START_API_FUNC
3288 ALCcontext *Context{ALCcontext::getThreadContext()};
3289 if(!Context) Context = ALCcontext::sGlobalContext.load();
3290 return Context;
3292 END_API_FUNC
3294 /** Returns the currently active thread-local context. */
3295 ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void)
3296 START_API_FUNC
3297 { return ALCcontext::getThreadContext(); }
3298 END_API_FUNC
3300 ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context)
3301 START_API_FUNC
3303 /* context must be valid or nullptr */
3304 ContextRef ctx;
3305 if(context)
3307 ctx = VerifyContext(context);
3308 if(!ctx)
3310 alcSetError(nullptr, ALC_INVALID_CONTEXT);
3311 return ALC_FALSE;
3314 /* Release this reference (if any) to store it in the GlobalContext
3315 * pointer. Take ownership of the reference (if any) that was previously
3316 * stored there.
3318 ctx = ContextRef{ALCcontext::sGlobalContext.exchange(ctx.release())};
3320 /* Reset (decrement) the previous global reference by replacing it with the
3321 * thread-local context. Take ownership of the thread-local context
3322 * reference (if any), clearing the storage to null.
3324 ctx = ContextRef{ALCcontext::getThreadContext()};
3325 if(ctx) ALCcontext::setThreadContext(nullptr);
3326 /* Reset (decrement) the previous thread-local reference. */
3328 return ALC_TRUE;
3330 END_API_FUNC
3332 /** Makes the given context the active context for the current thread. */
3333 ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context)
3334 START_API_FUNC
3336 /* context must be valid or nullptr */
3337 ContextRef ctx;
3338 if(context)
3340 ctx = VerifyContext(context);
3341 if(!ctx)
3343 alcSetError(nullptr, ALC_INVALID_CONTEXT);
3344 return ALC_FALSE;
3347 /* context's reference count is already incremented */
3348 ContextRef old{ALCcontext::getThreadContext()};
3349 ALCcontext::setThreadContext(ctx.release());
3351 return ALC_TRUE;
3353 END_API_FUNC
3356 ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *Context)
3357 START_API_FUNC
3359 ContextRef ctx{VerifyContext(Context)};
3360 if(!ctx)
3362 alcSetError(nullptr, ALC_INVALID_CONTEXT);
3363 return nullptr;
3365 return ctx->mALDevice.get();
3367 END_API_FUNC
3370 ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
3371 START_API_FUNC
3373 DO_INITCONFIG();
3375 if(!PlaybackFactory)
3377 alcSetError(nullptr, ALC_INVALID_VALUE);
3378 return nullptr;
3381 if(deviceName)
3383 if(!deviceName[0] || al::strcasecmp(deviceName, alcDefaultName) == 0
3384 #ifdef _WIN32
3385 /* Some old Windows apps hardcode these expecting OpenAL to use a
3386 * specific audio API, even when they're not enumerated. Creative's
3387 * router effectively ignores them too.
3389 || al::strcasecmp(deviceName, "DirectSound3D") == 0
3390 || al::strcasecmp(deviceName, "DirectSound") == 0
3391 || al::strcasecmp(deviceName, "MMSYSTEM") == 0
3392 #endif
3393 /* Some old Linux apps hardcode configuration strings that were
3394 * supported by the OpenAL SI. We can't really do anything useful
3395 * with them, so just ignore.
3397 || (deviceName[0] == '\'' && deviceName[1] == '(')
3398 || al::strcasecmp(deviceName, "openal-soft") == 0)
3399 deviceName = nullptr;
3402 DeviceRef device{new ALCdevice{DeviceType::Playback}};
3404 /* Set output format */
3405 device->FmtChans = DevFmtChannelsDefault;
3406 device->FmtType = DevFmtTypeDefault;
3407 device->Frequency = DEFAULT_OUTPUT_RATE;
3408 device->UpdateSize = DEFAULT_UPDATE_SIZE;
3409 device->BufferSize = DEFAULT_UPDATE_SIZE * DEFAULT_NUM_UPDATES;
3411 device->SourcesMax = 256;
3412 device->AuxiliaryEffectSlotMax = 64;
3413 device->NumAuxSends = DEFAULT_SENDS;
3414 #ifdef ALSOFT_EAX
3415 if(eax_g_is_enabled)
3416 device->NumAuxSends = EAX_MAX_FXSLOTS;
3417 #endif // ALSOFT_EAX
3419 try {
3420 auto backend = PlaybackFactory->createBackend(device.get(), BackendType::Playback);
3421 std::lock_guard<std::recursive_mutex> _{ListLock};
3422 backend->open(deviceName);
3423 device->Backend = std::move(backend);
3425 catch(al::backend_exception &e) {
3426 WARN("Failed to open playback device: %s\n", e.what());
3427 alcSetError(nullptr, (e.errorCode() == al::backend_error::OutOfMemory)
3428 ? ALC_OUT_OF_MEMORY : ALC_INVALID_VALUE);
3429 return nullptr;
3432 if(uint freq{device->configValue<uint>(nullptr, "frequency").value_or(0u)})
3434 if(freq < MIN_OUTPUT_RATE || freq > MAX_OUTPUT_RATE)
3436 const uint newfreq{clampu(freq, MIN_OUTPUT_RATE, MAX_OUTPUT_RATE)};
3437 ERR("%uhz request clamped to %uhz\n", freq, newfreq);
3438 freq = newfreq;
3440 const double scale{static_cast<double>(freq) / device->Frequency};
3441 device->UpdateSize = static_cast<uint>(device->UpdateSize*scale + 0.5);
3442 device->BufferSize = static_cast<uint>(device->BufferSize*scale + 0.5);
3443 device->Frequency = freq;
3444 device->Flags.set(FrequencyRequest);
3447 if(auto srcsmax = device->configValue<uint>(nullptr, "sources").value_or(0))
3448 device->SourcesMax = srcsmax;
3450 if(auto slotsmax = device->configValue<uint>(nullptr, "slots").value_or(0))
3451 device->AuxiliaryEffectSlotMax = minu(slotsmax, INT_MAX);
3453 if(auto sendsopt = device->configValue<int>(nullptr, "sends"))
3454 device->NumAuxSends = minu(DEFAULT_SENDS,
3455 static_cast<uint>(clampi(*sendsopt, 0, MAX_SENDS)));
3457 device->NumStereoSources = 1;
3458 device->NumMonoSources = device->SourcesMax - device->NumStereoSources;
3461 std::lock_guard<std::recursive_mutex> _{ListLock};
3462 auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get());
3463 DeviceList.emplace(iter, device.get());
3466 TRACE("Created device %p, \"%s\"\n", voidp{device.get()}, device->DeviceName.c_str());
3467 return device.release();
3469 END_API_FUNC
3471 ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device)
3472 START_API_FUNC
3474 std::unique_lock<std::recursive_mutex> listlock{ListLock};
3475 auto iter = std::lower_bound(DeviceList.begin(), DeviceList.end(), device);
3476 if(iter == DeviceList.end() || *iter != device)
3478 alcSetError(nullptr, ALC_INVALID_DEVICE);
3479 return ALC_FALSE;
3481 if((*iter)->Type == DeviceType::Capture)
3483 alcSetError(*iter, ALC_INVALID_DEVICE);
3484 return ALC_FALSE;
3487 /* Erase the device, and any remaining contexts left on it, from their
3488 * respective lists.
3490 DeviceRef dev{*iter};
3491 DeviceList.erase(iter);
3493 std::unique_lock<std::mutex> statelock{dev->StateLock};
3494 al::vector<ContextRef> orphanctxs;
3495 for(ContextBase *ctx : *dev->mContexts.load())
3497 auto ctxiter = std::lower_bound(ContextList.begin(), ContextList.end(), ctx);
3498 if(ctxiter != ContextList.end() && *ctxiter == ctx)
3500 orphanctxs.emplace_back(ContextRef{*ctxiter});
3501 ContextList.erase(ctxiter);
3504 listlock.unlock();
3506 for(ContextRef &context : orphanctxs)
3508 WARN("Releasing orphaned context %p\n", voidp{context.get()});
3509 context->deinit();
3511 orphanctxs.clear();
3513 if(dev->Flags.test(DeviceRunning))
3514 dev->Backend->stop();
3515 dev->Flags.reset(DeviceRunning);
3517 return ALC_TRUE;
3519 END_API_FUNC
3522 /************************************************
3523 * ALC capture functions
3524 ************************************************/
3525 ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei samples)
3526 START_API_FUNC
3528 DO_INITCONFIG();
3530 if(!CaptureFactory)
3532 alcSetError(nullptr, ALC_INVALID_VALUE);
3533 return nullptr;
3536 if(samples <= 0)
3538 alcSetError(nullptr, ALC_INVALID_VALUE);
3539 return nullptr;
3542 if(deviceName)
3544 if(!deviceName[0] || al::strcasecmp(deviceName, alcDefaultName) == 0
3545 || al::strcasecmp(deviceName, "openal-soft") == 0)
3546 deviceName = nullptr;
3549 DeviceRef device{new ALCdevice{DeviceType::Capture}};
3551 auto decompfmt = DecomposeDevFormat(format);
3552 if(!decompfmt)
3554 alcSetError(nullptr, ALC_INVALID_ENUM);
3555 return nullptr;
3558 device->Frequency = frequency;
3559 device->FmtChans = decompfmt->chans;
3560 device->FmtType = decompfmt->type;
3561 device->Flags.set(FrequencyRequest);
3562 device->Flags.set(ChannelsRequest);
3563 device->Flags.set(SampleTypeRequest);
3565 device->UpdateSize = static_cast<uint>(samples);
3566 device->BufferSize = static_cast<uint>(samples);
3568 try {
3569 TRACE("Capture format: %s, %s, %uhz, %u / %u buffer\n",
3570 DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType),
3571 device->Frequency, device->UpdateSize, device->BufferSize);
3573 auto backend = CaptureFactory->createBackend(device.get(), BackendType::Capture);
3574 std::lock_guard<std::recursive_mutex> _{ListLock};
3575 backend->open(deviceName);
3576 device->Backend = std::move(backend);
3578 catch(al::backend_exception &e) {
3579 WARN("Failed to open capture device: %s\n", e.what());
3580 alcSetError(nullptr, (e.errorCode() == al::backend_error::OutOfMemory)
3581 ? ALC_OUT_OF_MEMORY : ALC_INVALID_VALUE);
3582 return nullptr;
3586 std::lock_guard<std::recursive_mutex> _{ListLock};
3587 auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get());
3588 DeviceList.emplace(iter, device.get());
3591 TRACE("Created capture device %p, \"%s\"\n", voidp{device.get()}, device->DeviceName.c_str());
3592 return device.release();
3594 END_API_FUNC
3596 ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device)
3597 START_API_FUNC
3599 std::unique_lock<std::recursive_mutex> listlock{ListLock};
3600 auto iter = std::lower_bound(DeviceList.begin(), DeviceList.end(), device);
3601 if(iter == DeviceList.end() || *iter != device)
3603 alcSetError(nullptr, ALC_INVALID_DEVICE);
3604 return ALC_FALSE;
3606 if((*iter)->Type != DeviceType::Capture)
3608 alcSetError(*iter, ALC_INVALID_DEVICE);
3609 return ALC_FALSE;
3612 DeviceRef dev{*iter};
3613 DeviceList.erase(iter);
3614 listlock.unlock();
3616 std::lock_guard<std::mutex> _{dev->StateLock};
3617 if(dev->Flags.test(DeviceRunning))
3618 dev->Backend->stop();
3619 dev->Flags.reset(DeviceRunning);
3621 return ALC_TRUE;
3623 END_API_FUNC
3625 ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device)
3626 START_API_FUNC
3628 DeviceRef dev{VerifyDevice(device)};
3629 if(!dev || dev->Type != DeviceType::Capture)
3631 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3632 return;
3635 std::lock_guard<std::mutex> _{dev->StateLock};
3636 if(!dev->Connected.load(std::memory_order_acquire))
3637 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3638 else if(!dev->Flags.test(DeviceRunning))
3640 try {
3641 auto backend = dev->Backend.get();
3642 backend->start();
3643 dev->Flags.set(DeviceRunning);
3645 catch(al::backend_exception& e) {
3646 ERR("%s\n", e.what());
3647 dev->handleDisconnect("%s", e.what());
3648 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3652 END_API_FUNC
3654 ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device)
3655 START_API_FUNC
3657 DeviceRef dev{VerifyDevice(device)};
3658 if(!dev || dev->Type != DeviceType::Capture)
3659 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3660 else
3662 std::lock_guard<std::mutex> _{dev->StateLock};
3663 if(dev->Flags.test(DeviceRunning))
3664 dev->Backend->stop();
3665 dev->Flags.reset(DeviceRunning);
3668 END_API_FUNC
3670 ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples)
3671 START_API_FUNC
3673 DeviceRef dev{VerifyDevice(device)};
3674 if(!dev || dev->Type != DeviceType::Capture)
3676 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3677 return;
3680 if(samples < 0 || (samples > 0 && buffer == nullptr))
3682 alcSetError(dev.get(), ALC_INVALID_VALUE);
3683 return;
3685 if(samples < 1)
3686 return;
3688 std::lock_guard<std::mutex> _{dev->StateLock};
3689 BackendBase *backend{dev->Backend.get()};
3691 const auto usamples = static_cast<uint>(samples);
3692 if(usamples > backend->availableSamples())
3694 alcSetError(dev.get(), ALC_INVALID_VALUE);
3695 return;
3698 backend->captureSamples(static_cast<al::byte*>(buffer), usamples);
3700 END_API_FUNC
3703 /************************************************
3704 * ALC loopback functions
3705 ************************************************/
3707 /** Open a loopback device, for manual rendering. */
3708 ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName)
3709 START_API_FUNC
3711 DO_INITCONFIG();
3713 /* Make sure the device name, if specified, is us. */
3714 if(deviceName && strcmp(deviceName, alcDefaultName) != 0)
3716 alcSetError(nullptr, ALC_INVALID_VALUE);
3717 return nullptr;
3720 DeviceRef device{new ALCdevice{DeviceType::Loopback}};
3722 device->SourcesMax = 256;
3723 device->AuxiliaryEffectSlotMax = 64;
3724 device->NumAuxSends = DEFAULT_SENDS;
3726 //Set output format
3727 device->BufferSize = 0;
3728 device->UpdateSize = 0;
3730 device->Frequency = DEFAULT_OUTPUT_RATE;
3731 device->FmtChans = DevFmtChannelsDefault;
3732 device->FmtType = DevFmtTypeDefault;
3734 if(auto srcsmax = ConfigValueUInt(nullptr, nullptr, "sources").value_or(0))
3735 device->SourcesMax = srcsmax;
3737 if(auto slotsmax = ConfigValueUInt(nullptr, nullptr, "slots").value_or(0))
3738 device->AuxiliaryEffectSlotMax = minu(slotsmax, INT_MAX);
3740 if(auto sendsopt = ConfigValueInt(nullptr, nullptr, "sends"))
3741 device->NumAuxSends = minu(DEFAULT_SENDS,
3742 static_cast<uint>(clampi(*sendsopt, 0, MAX_SENDS)));
3744 device->NumStereoSources = 1;
3745 device->NumMonoSources = device->SourcesMax - device->NumStereoSources;
3747 try {
3748 auto backend = LoopbackBackendFactory::getFactory().createBackend(device.get(),
3749 BackendType::Playback);
3750 backend->open("Loopback");
3751 device->Backend = std::move(backend);
3753 catch(al::backend_exception &e) {
3754 WARN("Failed to open loopback device: %s\n", e.what());
3755 alcSetError(nullptr, (e.errorCode() == al::backend_error::OutOfMemory)
3756 ? ALC_OUT_OF_MEMORY : ALC_INVALID_VALUE);
3757 return nullptr;
3761 std::lock_guard<std::recursive_mutex> _{ListLock};
3762 auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get());
3763 DeviceList.emplace(iter, device.get());
3766 TRACE("Created loopback device %p\n", voidp{device.get()});
3767 return device.release();
3769 END_API_FUNC
3772 * Determines if the loopback device supports the given format for rendering.
3774 ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type)
3775 START_API_FUNC
3777 DeviceRef dev{VerifyDevice(device)};
3778 if(!dev || dev->Type != DeviceType::Loopback)
3779 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3780 else if(freq <= 0)
3781 alcSetError(dev.get(), ALC_INVALID_VALUE);
3782 else
3784 if(DevFmtTypeFromEnum(type).has_value() && DevFmtChannelsFromEnum(channels).has_value()
3785 && freq >= MIN_OUTPUT_RATE && freq <= MAX_OUTPUT_RATE)
3786 return ALC_TRUE;
3789 return ALC_FALSE;
3791 END_API_FUNC
3794 * Renders some samples into a buffer, using the format last set by the
3795 * attributes given to alcCreateContext.
3797 FORCE_ALIGN ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples)
3798 START_API_FUNC
3800 if(!device || device->Type != DeviceType::Loopback)
3801 alcSetError(device, ALC_INVALID_DEVICE);
3802 else if(samples < 0 || (samples > 0 && buffer == nullptr))
3803 alcSetError(device, ALC_INVALID_VALUE);
3804 else
3805 device->renderSamples(buffer, static_cast<uint>(samples), device->channelsFromFmt());
3807 END_API_FUNC
3810 /************************************************
3811 * ALC DSP pause/resume functions
3812 ************************************************/
3814 /** Pause the DSP to stop audio processing. */
3815 ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device)
3816 START_API_FUNC
3818 DeviceRef dev{VerifyDevice(device)};
3819 if(!dev || dev->Type != DeviceType::Playback)
3820 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3821 else
3823 std::lock_guard<std::mutex> _{dev->StateLock};
3824 if(dev->Flags.test(DeviceRunning))
3825 dev->Backend->stop();
3826 dev->Flags.reset(DeviceRunning);
3827 dev->Flags.set(DevicePaused);
3830 END_API_FUNC
3832 /** Resume the DSP to restart audio processing. */
3833 ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device)
3834 START_API_FUNC
3836 DeviceRef dev{VerifyDevice(device)};
3837 if(!dev || dev->Type != DeviceType::Playback)
3839 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3840 return;
3843 std::lock_guard<std::mutex> _{dev->StateLock};
3844 if(!dev->Flags.test(DevicePaused))
3845 return;
3846 dev->Flags.reset(DevicePaused);
3847 if(dev->mContexts.load()->empty())
3848 return;
3850 try {
3851 auto backend = dev->Backend.get();
3852 backend->start();
3853 dev->Flags.set(DeviceRunning);
3855 catch(al::backend_exception& e) {
3856 ERR("%s\n", e.what());
3857 dev->handleDisconnect("%s", e.what());
3858 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3859 return;
3861 TRACE("Post-resume: %s, %s, %uhz, %u / %u buffer\n",
3862 DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType),
3863 device->Frequency, device->UpdateSize, device->BufferSize);
3865 END_API_FUNC
3868 /************************************************
3869 * ALC HRTF functions
3870 ************************************************/
3872 /** Gets a string parameter at the given index. */
3873 ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index)
3874 START_API_FUNC
3876 DeviceRef dev{VerifyDevice(device)};
3877 if(!dev || dev->Type == DeviceType::Capture)
3878 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3879 else switch(paramName)
3881 case ALC_HRTF_SPECIFIER_SOFT:
3882 if(index >= 0 && static_cast<uint>(index) < dev->mHrtfList.size())
3883 return dev->mHrtfList[static_cast<uint>(index)].c_str();
3884 alcSetError(dev.get(), ALC_INVALID_VALUE);
3885 break;
3887 default:
3888 alcSetError(dev.get(), ALC_INVALID_ENUM);
3889 break;
3892 return nullptr;
3894 END_API_FUNC
3896 /** Resets the given device output, using the specified attribute list. */
3897 ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs)
3898 START_API_FUNC
3900 std::unique_lock<std::recursive_mutex> listlock{ListLock};
3901 DeviceRef dev{VerifyDevice(device)};
3902 if(!dev || dev->Type == DeviceType::Capture)
3904 listlock.unlock();
3905 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3906 return ALC_FALSE;
3908 std::lock_guard<std::mutex> _{dev->StateLock};
3909 listlock.unlock();
3911 /* Force the backend to stop mixing first since we're resetting. Also reset
3912 * the connected state so lost devices can attempt recover.
3914 if(dev->Flags.test(DeviceRunning))
3915 dev->Backend->stop();
3916 dev->Flags.reset(DeviceRunning);
3918 return ResetDeviceParams(dev.get(), attribs) ? ALC_TRUE : ALC_FALSE;
3920 END_API_FUNC
3923 /************************************************
3924 * ALC device reopen functions
3925 ************************************************/
3927 /** Reopens the given device output, using the specified name and attribute list. */
3928 FORCE_ALIGN ALCboolean ALC_APIENTRY alcReopenDeviceSOFT(ALCdevice *device,
3929 const ALCchar *deviceName, const ALCint *attribs)
3930 START_API_FUNC
3932 if(deviceName)
3934 if(!deviceName[0] || al::strcasecmp(deviceName, alcDefaultName) == 0)
3935 deviceName = nullptr;
3938 std::unique_lock<std::recursive_mutex> listlock{ListLock};
3939 DeviceRef dev{VerifyDevice(device)};
3940 if(!dev || dev->Type != DeviceType::Playback)
3942 listlock.unlock();
3943 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3944 return ALC_FALSE;
3946 std::lock_guard<std::mutex> _{dev->StateLock};
3948 /* Force the backend to stop mixing first since we're reopening. */
3949 if(dev->Flags.test(DeviceRunning))
3951 auto backend = dev->Backend.get();
3952 backend->stop();
3953 dev->Flags.reset(DeviceRunning);
3956 BackendPtr newbackend;
3957 try {
3958 newbackend = PlaybackFactory->createBackend(dev.get(), BackendType::Playback);
3959 newbackend->open(deviceName);
3961 catch(al::backend_exception &e) {
3962 listlock.unlock();
3963 newbackend = nullptr;
3965 WARN("Failed to reopen playback device: %s\n", e.what());
3966 alcSetError(dev.get(), (e.errorCode() == al::backend_error::OutOfMemory)
3967 ? ALC_OUT_OF_MEMORY : ALC_INVALID_VALUE);
3969 /* If the device is connected, not paused, and has contexts, ensure it
3970 * continues playing.
3972 if(dev->Connected.load(std::memory_order_relaxed) && !dev->Flags.test(DevicePaused)
3973 && !dev->mContexts.load(std::memory_order_relaxed)->empty())
3975 try {
3976 auto backend = dev->Backend.get();
3977 backend->start();
3978 dev->Flags.set(DeviceRunning);
3980 catch(al::backend_exception &be) {
3981 ERR("%s\n", be.what());
3982 dev->handleDisconnect("%s", be.what());
3985 return ALC_FALSE;
3987 listlock.unlock();
3988 dev->Backend = std::move(newbackend);
3989 TRACE("Reopened device %p, \"%s\"\n", voidp{dev.get()}, dev->DeviceName.c_str());
3991 /* Always return true even if resetting fails. It shouldn't fail, but this
3992 * is primarily to avoid confusion by the app seeing the function return
3993 * false while the device is on the new output anyway. We could try to
3994 * restore the old backend if this fails, but the configuration would be
3995 * changed with the new backend and would need to be reset again with the
3996 * old one, and the provided attributes may not be appropriate or desirable
3997 * for the old device.
3999 * In this way, we essentially act as if the function succeeded, but
4000 * immediately disconnects following it.
4002 ResetDeviceParams(dev.get(), attribs);
4003 return ALC_TRUE;
4005 END_API_FUNC