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
26 #define WIN32_LEAN_AND_MEAN
54 #include <type_traits>
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"
72 #include "alnumeric.h"
73 #include "aloptional.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"
98 #include "effects/base.h"
99 #include "inprogext.h"
100 #include "intrusive_ptr.h"
101 #include "opthelpers.h"
102 #include "strutils.h"
106 #include "backends/base.h"
107 #include "backends/null.h"
108 #include "backends/loopback.h"
110 #include "backends/pipewire.h"
113 #include "backends/jack.h"
115 #ifdef HAVE_PULSEAUDIO
116 #include "backends/pulseaudio.h"
119 #include "backends/alsa.h"
122 #include "backends/wasapi.h"
124 #ifdef HAVE_COREAUDIO
125 #include "backends/coreaudio.h"
128 #include "backends/opensl.h"
131 #include "backends/oboe.h"
134 #include "backends/solaris.h"
137 #include "backends/sndio.h"
140 #include "backends/oss.h"
143 #include "backends/dsound.h"
146 #include "backends/winmm.h"
148 #ifdef HAVE_PORTAUDIO
149 #include "backends/portaudio.h"
152 #include "backends/sdl2.h"
155 #include "backends/wave.h"
159 #include "al/eax/globals.h"
160 #include "al/eax/x_ram.h"
164 FILE *gLogFile{stderr};
166 LogLevel gLogLevel{LogLevel::Warning};
168 LogLevel gLogLevel{LogLevel::Error};
171 /************************************************
172 * Library initialization
173 ************************************************/
174 #if defined(_WIN32) && !defined(AL_LIBTYPE_STATIC)
175 BOOL APIENTRY DllMain(HINSTANCE module, DWORD reason, LPVOID /*reserved*/)
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);
191 using namespace std::placeholders;
192 using std::chrono::seconds;
193 using std::chrono::nanoseconds;
196 using float2 = std::array<float,2>;
199 /************************************************
201 ************************************************/
204 BackendFactory& (*getFactory)(void);
207 BackendInfo BackendList[] = {
209 { "pipewire", PipeWireBackendFactory::getFactory },
211 #ifdef HAVE_PULSEAUDIO
212 { "pulse", PulseBackendFactory::getFactory },
215 { "wasapi", WasapiBackendFactory::getFactory },
217 #ifdef HAVE_COREAUDIO
218 { "core", CoreAudioBackendFactory::getFactory },
221 { "oboe", OboeBackendFactory::getFactory },
224 { "opensl", OSLBackendFactory::getFactory },
227 { "alsa", AlsaBackendFactory::getFactory },
230 { "solaris", SolarisBackendFactory::getFactory },
233 { "sndio", SndIOBackendFactory::getFactory },
236 { "oss", OSSBackendFactory::getFactory },
239 { "jack", JackBackendFactory::getFactory },
242 { "dsound", DSoundBackendFactory::getFactory },
245 { "winmm", WinMMBackendFactory::getFactory },
247 #ifdef HAVE_PORTAUDIO
248 { "port", PortBackendFactory::getFactory },
251 { "sdl2", SDL2BackendFactory::getFactory },
254 { "null", NullBackendFactory::getFactory },
256 { "wave", WaveBackendFactory::getFactory },
260 BackendFactory *PlaybackFactory{};
261 BackendFactory *CaptureFactory{};
264 /************************************************
265 * Functions, enums, and errors
266 ************************************************/
267 #define DECL(x) { #x, reinterpret_cast<void*>(x) }
269 const char *funcName;
272 DECL(alcCreateContext),
273 DECL(alcMakeContextCurrent),
274 DECL(alcProcessContext),
275 DECL(alcSuspendContext),
276 DECL(alcDestroyContext),
277 DECL(alcGetCurrentContext),
278 DECL(alcGetContextsDevice),
280 DECL(alcCloseDevice),
282 DECL(alcIsExtensionPresent),
283 DECL(alcGetProcAddress),
284 DECL(alcGetEnumValue),
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),
323 DECL(alIsExtensionPresent),
324 DECL(alGetProcAddress),
325 DECL(alGetEnumValue),
332 DECL(alGetListenerf),
333 DECL(alGetListener3f),
334 DECL(alGetListenerfv),
335 DECL(alGetListeneri),
336 DECL(alGetListener3i),
337 DECL(alGetListeneriv),
339 DECL(alDeleteSources),
355 DECL(alSourceRewindv),
356 DECL(alSourcePausev),
359 DECL(alSourceRewind),
361 DECL(alSourceQueueBuffers),
362 DECL(alSourceUnqueueBuffers),
364 DECL(alDeleteBuffers),
379 DECL(alDopplerFactor),
380 DECL(alDopplerVelocity),
381 DECL(alSpeedOfSound),
382 DECL(alDistanceModel),
385 DECL(alDeleteFilters),
396 DECL(alDeleteEffects),
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),
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),
456 DECL(alSourcePlayAtTimeSOFT),
457 DECL(alSourcePlayAtTimevSOFT),
459 DECL(alBufferSubDataSOFT),
461 DECL(alBufferDataStatic),
463 }, eaxFunctions[] = {
466 DECL(EAXGetBufferMode),
467 DECL(EAXSetBufferMode),
472 #define DECL(x) { #x, (x) }
474 const ALCchar *enumName;
476 } alcEnumerations[] = {
481 DECL(ALC_MAJOR_VERSION),
482 DECL(ALC_MINOR_VERSION),
483 DECL(ALC_ATTRIBUTES_SIZE),
484 DECL(ALC_ALL_ATTRIBUTES),
485 DECL(ALC_DEFAULT_DEVICE_SPECIFIER),
486 DECL(ALC_DEVICE_SPECIFIER),
487 DECL(ALC_ALL_DEVICES_SPECIFIER),
488 DECL(ALC_DEFAULT_ALL_DEVICES_SPECIFIER),
489 DECL(ALC_EXTENSIONS),
493 DECL(ALC_MONO_SOURCES),
494 DECL(ALC_STEREO_SOURCES),
495 DECL(ALC_CAPTURE_DEVICE_SPECIFIER),
496 DECL(ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER),
497 DECL(ALC_CAPTURE_SAMPLES),
500 DECL(ALC_EFX_MAJOR_VERSION),
501 DECL(ALC_EFX_MINOR_VERSION),
502 DECL(ALC_MAX_AUXILIARY_SENDS),
504 DECL(ALC_FORMAT_CHANNELS_SOFT),
505 DECL(ALC_FORMAT_TYPE_SOFT),
508 DECL(ALC_STEREO_SOFT),
510 DECL(ALC_5POINT1_SOFT),
511 DECL(ALC_6POINT1_SOFT),
512 DECL(ALC_7POINT1_SOFT),
513 DECL(ALC_BFORMAT3D_SOFT),
516 DECL(ALC_UNSIGNED_BYTE_SOFT),
517 DECL(ALC_SHORT_SOFT),
518 DECL(ALC_UNSIGNED_SHORT_SOFT),
520 DECL(ALC_UNSIGNED_INT_SOFT),
521 DECL(ALC_FLOAT_SOFT),
524 DECL(ALC_DONT_CARE_SOFT),
525 DECL(ALC_HRTF_STATUS_SOFT),
526 DECL(ALC_HRTF_DISABLED_SOFT),
527 DECL(ALC_HRTF_ENABLED_SOFT),
528 DECL(ALC_HRTF_DENIED_SOFT),
529 DECL(ALC_HRTF_REQUIRED_SOFT),
530 DECL(ALC_HRTF_HEADPHONES_DETECTED_SOFT),
531 DECL(ALC_HRTF_UNSUPPORTED_FORMAT_SOFT),
532 DECL(ALC_NUM_HRTF_SPECIFIERS_SOFT),
533 DECL(ALC_HRTF_SPECIFIER_SOFT),
534 DECL(ALC_HRTF_ID_SOFT),
536 DECL(ALC_AMBISONIC_LAYOUT_SOFT),
537 DECL(ALC_AMBISONIC_SCALING_SOFT),
538 DECL(ALC_AMBISONIC_ORDER_SOFT),
544 DECL(ALC_OUTPUT_LIMITER_SOFT),
546 DECL(ALC_DEVICE_CLOCK_SOFT),
547 DECL(ALC_DEVICE_LATENCY_SOFT),
548 DECL(ALC_DEVICE_CLOCK_LATENCY_SOFT),
549 DECL(AL_SAMPLE_OFFSET_CLOCK_SOFT),
550 DECL(AL_SEC_OFFSET_CLOCK_SOFT),
552 DECL(ALC_OUTPUT_MODE_SOFT),
554 DECL(ALC_STEREO_BASIC_SOFT),
555 DECL(ALC_STEREO_UHJ_SOFT),
556 DECL(ALC_STEREO_HRTF_SOFT),
557 DECL(ALC_SURROUND_5_1_SOFT),
558 DECL(ALC_SURROUND_6_1_SOFT),
559 DECL(ALC_SURROUND_7_1_SOFT),
562 DECL(ALC_INVALID_DEVICE),
563 DECL(ALC_INVALID_CONTEXT),
564 DECL(ALC_INVALID_ENUM),
565 DECL(ALC_INVALID_VALUE),
566 DECL(ALC_OUT_OF_MEMORY),
574 DECL(AL_SOURCE_RELATIVE),
575 DECL(AL_CONE_INNER_ANGLE),
576 DECL(AL_CONE_OUTER_ANGLE),
586 DECL(AL_ORIENTATION),
587 DECL(AL_REFERENCE_DISTANCE),
588 DECL(AL_ROLLOFF_FACTOR),
589 DECL(AL_CONE_OUTER_GAIN),
590 DECL(AL_MAX_DISTANCE),
592 DECL(AL_SAMPLE_OFFSET),
593 DECL(AL_BYTE_OFFSET),
594 DECL(AL_SOURCE_TYPE),
597 DECL(AL_UNDETERMINED),
598 DECL(AL_METERS_PER_UNIT),
599 DECL(AL_LOOP_POINTS_SOFT),
600 DECL(AL_DIRECT_CHANNELS_SOFT),
602 DECL(AL_DIRECT_FILTER),
603 DECL(AL_AUXILIARY_SEND_FILTER),
604 DECL(AL_AIR_ABSORPTION_FACTOR),
605 DECL(AL_ROOM_ROLLOFF_FACTOR),
606 DECL(AL_CONE_OUTER_GAINHF),
607 DECL(AL_DIRECT_FILTER_GAINHF_AUTO),
608 DECL(AL_AUXILIARY_SEND_FILTER_GAIN_AUTO),
609 DECL(AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO),
611 DECL(AL_SOURCE_STATE),
617 DECL(AL_BUFFERS_QUEUED),
618 DECL(AL_BUFFERS_PROCESSED),
620 DECL(AL_FORMAT_MONO8),
621 DECL(AL_FORMAT_MONO16),
622 DECL(AL_FORMAT_MONO_FLOAT32),
623 DECL(AL_FORMAT_MONO_DOUBLE_EXT),
624 DECL(AL_FORMAT_STEREO8),
625 DECL(AL_FORMAT_STEREO16),
626 DECL(AL_FORMAT_STEREO_FLOAT32),
627 DECL(AL_FORMAT_STEREO_DOUBLE_EXT),
628 DECL(AL_FORMAT_MONO_IMA4),
629 DECL(AL_FORMAT_STEREO_IMA4),
630 DECL(AL_FORMAT_MONO_MSADPCM_SOFT),
631 DECL(AL_FORMAT_STEREO_MSADPCM_SOFT),
632 DECL(AL_FORMAT_QUAD8_LOKI),
633 DECL(AL_FORMAT_QUAD16_LOKI),
634 DECL(AL_FORMAT_QUAD8),
635 DECL(AL_FORMAT_QUAD16),
636 DECL(AL_FORMAT_QUAD32),
637 DECL(AL_FORMAT_51CHN8),
638 DECL(AL_FORMAT_51CHN16),
639 DECL(AL_FORMAT_51CHN32),
640 DECL(AL_FORMAT_61CHN8),
641 DECL(AL_FORMAT_61CHN16),
642 DECL(AL_FORMAT_61CHN32),
643 DECL(AL_FORMAT_71CHN8),
644 DECL(AL_FORMAT_71CHN16),
645 DECL(AL_FORMAT_71CHN32),
646 DECL(AL_FORMAT_REAR8),
647 DECL(AL_FORMAT_REAR16),
648 DECL(AL_FORMAT_REAR32),
649 DECL(AL_FORMAT_MONO_MULAW),
650 DECL(AL_FORMAT_MONO_MULAW_EXT),
651 DECL(AL_FORMAT_STEREO_MULAW),
652 DECL(AL_FORMAT_STEREO_MULAW_EXT),
653 DECL(AL_FORMAT_QUAD_MULAW),
654 DECL(AL_FORMAT_51CHN_MULAW),
655 DECL(AL_FORMAT_61CHN_MULAW),
656 DECL(AL_FORMAT_71CHN_MULAW),
657 DECL(AL_FORMAT_REAR_MULAW),
658 DECL(AL_FORMAT_MONO_ALAW_EXT),
659 DECL(AL_FORMAT_STEREO_ALAW_EXT),
661 DECL(AL_FORMAT_BFORMAT2D_8),
662 DECL(AL_FORMAT_BFORMAT2D_16),
663 DECL(AL_FORMAT_BFORMAT2D_FLOAT32),
664 DECL(AL_FORMAT_BFORMAT2D_MULAW),
665 DECL(AL_FORMAT_BFORMAT3D_8),
666 DECL(AL_FORMAT_BFORMAT3D_16),
667 DECL(AL_FORMAT_BFORMAT3D_FLOAT32),
668 DECL(AL_FORMAT_BFORMAT3D_MULAW),
674 DECL(AL_UNPACK_BLOCK_ALIGNMENT_SOFT),
675 DECL(AL_PACK_BLOCK_ALIGNMENT_SOFT),
677 DECL(AL_SOURCE_RADIUS),
679 DECL(AL_SAMPLE_OFFSET_LATENCY_SOFT),
680 DECL(AL_SEC_OFFSET_LATENCY_SOFT),
682 DECL(AL_STEREO_ANGLES),
689 DECL(AL_INVALID_NAME),
690 DECL(AL_INVALID_ENUM),
691 DECL(AL_INVALID_VALUE),
692 DECL(AL_INVALID_OPERATION),
693 DECL(AL_OUT_OF_MEMORY),
700 DECL(AL_DOPPLER_FACTOR),
701 DECL(AL_DOPPLER_VELOCITY),
702 DECL(AL_DISTANCE_MODEL),
703 DECL(AL_SPEED_OF_SOUND),
704 DECL(AL_SOURCE_DISTANCE_MODEL),
705 DECL(AL_DEFERRED_UPDATES_SOFT),
706 DECL(AL_GAIN_LIMIT_SOFT),
708 DECL(AL_INVERSE_DISTANCE),
709 DECL(AL_INVERSE_DISTANCE_CLAMPED),
710 DECL(AL_LINEAR_DISTANCE),
711 DECL(AL_LINEAR_DISTANCE_CLAMPED),
712 DECL(AL_EXPONENT_DISTANCE),
713 DECL(AL_EXPONENT_DISTANCE_CLAMPED),
715 DECL(AL_FILTER_TYPE),
716 DECL(AL_FILTER_NULL),
717 DECL(AL_FILTER_LOWPASS),
718 DECL(AL_FILTER_HIGHPASS),
719 DECL(AL_FILTER_BANDPASS),
721 DECL(AL_LOWPASS_GAIN),
722 DECL(AL_LOWPASS_GAINHF),
724 DECL(AL_HIGHPASS_GAIN),
725 DECL(AL_HIGHPASS_GAINLF),
727 DECL(AL_BANDPASS_GAIN),
728 DECL(AL_BANDPASS_GAINHF),
729 DECL(AL_BANDPASS_GAINLF),
731 DECL(AL_EFFECT_TYPE),
732 DECL(AL_EFFECT_NULL),
733 DECL(AL_EFFECT_REVERB),
734 DECL(AL_EFFECT_EAXREVERB),
735 DECL(AL_EFFECT_CHORUS),
736 DECL(AL_EFFECT_DISTORTION),
737 DECL(AL_EFFECT_ECHO),
738 DECL(AL_EFFECT_FLANGER),
739 DECL(AL_EFFECT_PITCH_SHIFTER),
740 DECL(AL_EFFECT_FREQUENCY_SHIFTER),
741 DECL(AL_EFFECT_VOCAL_MORPHER),
742 DECL(AL_EFFECT_RING_MODULATOR),
743 DECL(AL_EFFECT_AUTOWAH),
744 DECL(AL_EFFECT_COMPRESSOR),
745 DECL(AL_EFFECT_EQUALIZER),
746 DECL(AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT),
747 DECL(AL_EFFECT_DEDICATED_DIALOGUE),
749 DECL(AL_EFFECTSLOT_EFFECT),
750 DECL(AL_EFFECTSLOT_GAIN),
751 DECL(AL_EFFECTSLOT_AUXILIARY_SEND_AUTO),
752 DECL(AL_EFFECTSLOT_NULL),
754 DECL(AL_EAXREVERB_DENSITY),
755 DECL(AL_EAXREVERB_DIFFUSION),
756 DECL(AL_EAXREVERB_GAIN),
757 DECL(AL_EAXREVERB_GAINHF),
758 DECL(AL_EAXREVERB_GAINLF),
759 DECL(AL_EAXREVERB_DECAY_TIME),
760 DECL(AL_EAXREVERB_DECAY_HFRATIO),
761 DECL(AL_EAXREVERB_DECAY_LFRATIO),
762 DECL(AL_EAXREVERB_REFLECTIONS_GAIN),
763 DECL(AL_EAXREVERB_REFLECTIONS_DELAY),
764 DECL(AL_EAXREVERB_REFLECTIONS_PAN),
765 DECL(AL_EAXREVERB_LATE_REVERB_GAIN),
766 DECL(AL_EAXREVERB_LATE_REVERB_DELAY),
767 DECL(AL_EAXREVERB_LATE_REVERB_PAN),
768 DECL(AL_EAXREVERB_ECHO_TIME),
769 DECL(AL_EAXREVERB_ECHO_DEPTH),
770 DECL(AL_EAXREVERB_MODULATION_TIME),
771 DECL(AL_EAXREVERB_MODULATION_DEPTH),
772 DECL(AL_EAXREVERB_AIR_ABSORPTION_GAINHF),
773 DECL(AL_EAXREVERB_HFREFERENCE),
774 DECL(AL_EAXREVERB_LFREFERENCE),
775 DECL(AL_EAXREVERB_ROOM_ROLLOFF_FACTOR),
776 DECL(AL_EAXREVERB_DECAY_HFLIMIT),
778 DECL(AL_REVERB_DENSITY),
779 DECL(AL_REVERB_DIFFUSION),
780 DECL(AL_REVERB_GAIN),
781 DECL(AL_REVERB_GAINHF),
782 DECL(AL_REVERB_DECAY_TIME),
783 DECL(AL_REVERB_DECAY_HFRATIO),
784 DECL(AL_REVERB_REFLECTIONS_GAIN),
785 DECL(AL_REVERB_REFLECTIONS_DELAY),
786 DECL(AL_REVERB_LATE_REVERB_GAIN),
787 DECL(AL_REVERB_LATE_REVERB_DELAY),
788 DECL(AL_REVERB_AIR_ABSORPTION_GAINHF),
789 DECL(AL_REVERB_ROOM_ROLLOFF_FACTOR),
790 DECL(AL_REVERB_DECAY_HFLIMIT),
792 DECL(AL_CHORUS_WAVEFORM),
793 DECL(AL_CHORUS_PHASE),
794 DECL(AL_CHORUS_RATE),
795 DECL(AL_CHORUS_DEPTH),
796 DECL(AL_CHORUS_FEEDBACK),
797 DECL(AL_CHORUS_DELAY),
799 DECL(AL_DISTORTION_EDGE),
800 DECL(AL_DISTORTION_GAIN),
801 DECL(AL_DISTORTION_LOWPASS_CUTOFF),
802 DECL(AL_DISTORTION_EQCENTER),
803 DECL(AL_DISTORTION_EQBANDWIDTH),
806 DECL(AL_ECHO_LRDELAY),
807 DECL(AL_ECHO_DAMPING),
808 DECL(AL_ECHO_FEEDBACK),
809 DECL(AL_ECHO_SPREAD),
811 DECL(AL_FLANGER_WAVEFORM),
812 DECL(AL_FLANGER_PHASE),
813 DECL(AL_FLANGER_RATE),
814 DECL(AL_FLANGER_DEPTH),
815 DECL(AL_FLANGER_FEEDBACK),
816 DECL(AL_FLANGER_DELAY),
818 DECL(AL_FREQUENCY_SHIFTER_FREQUENCY),
819 DECL(AL_FREQUENCY_SHIFTER_LEFT_DIRECTION),
820 DECL(AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION),
822 DECL(AL_RING_MODULATOR_FREQUENCY),
823 DECL(AL_RING_MODULATOR_HIGHPASS_CUTOFF),
824 DECL(AL_RING_MODULATOR_WAVEFORM),
826 DECL(AL_PITCH_SHIFTER_COARSE_TUNE),
827 DECL(AL_PITCH_SHIFTER_FINE_TUNE),
829 DECL(AL_COMPRESSOR_ONOFF),
831 DECL(AL_EQUALIZER_LOW_GAIN),
832 DECL(AL_EQUALIZER_LOW_CUTOFF),
833 DECL(AL_EQUALIZER_MID1_GAIN),
834 DECL(AL_EQUALIZER_MID1_CENTER),
835 DECL(AL_EQUALIZER_MID1_WIDTH),
836 DECL(AL_EQUALIZER_MID2_GAIN),
837 DECL(AL_EQUALIZER_MID2_CENTER),
838 DECL(AL_EQUALIZER_MID2_WIDTH),
839 DECL(AL_EQUALIZER_HIGH_GAIN),
840 DECL(AL_EQUALIZER_HIGH_CUTOFF),
842 DECL(AL_DEDICATED_GAIN),
844 DECL(AL_AUTOWAH_ATTACK_TIME),
845 DECL(AL_AUTOWAH_RELEASE_TIME),
846 DECL(AL_AUTOWAH_RESONANCE),
847 DECL(AL_AUTOWAH_PEAK_GAIN),
849 DECL(AL_VOCAL_MORPHER_PHONEMEA),
850 DECL(AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING),
851 DECL(AL_VOCAL_MORPHER_PHONEMEB),
852 DECL(AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING),
853 DECL(AL_VOCAL_MORPHER_WAVEFORM),
854 DECL(AL_VOCAL_MORPHER_RATE),
856 DECL(AL_EFFECTSLOT_TARGET_SOFT),
858 DECL(AL_NUM_RESAMPLERS_SOFT),
859 DECL(AL_DEFAULT_RESAMPLER_SOFT),
860 DECL(AL_SOURCE_RESAMPLER_SOFT),
861 DECL(AL_RESAMPLER_NAME_SOFT),
863 DECL(AL_SOURCE_SPATIALIZE_SOFT),
866 DECL(AL_MAP_READ_BIT_SOFT),
867 DECL(AL_MAP_WRITE_BIT_SOFT),
868 DECL(AL_MAP_PERSISTENT_BIT_SOFT),
869 DECL(AL_PRESERVE_DATA_BIT_SOFT),
871 DECL(AL_EVENT_CALLBACK_FUNCTION_SOFT),
872 DECL(AL_EVENT_CALLBACK_USER_PARAM_SOFT),
873 DECL(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT),
874 DECL(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT),
875 DECL(AL_EVENT_TYPE_DISCONNECTED_SOFT),
877 DECL(AL_DROP_UNMATCHED_SOFT),
878 DECL(AL_REMIX_UNMATCHED_SOFT),
880 DECL(AL_AMBISONIC_LAYOUT_SOFT),
881 DECL(AL_AMBISONIC_SCALING_SOFT),
887 DECL(AL_BUFFER_CALLBACK_FUNCTION_SOFT),
888 DECL(AL_BUFFER_CALLBACK_USER_PARAM_SOFT),
890 DECL(AL_UNPACK_AMBISONIC_ORDER_SOFT),
892 DECL(AL_EFFECT_CONVOLUTION_REVERB_SOFT),
893 DECL(AL_EFFECTSLOT_STATE_SOFT),
895 DECL(AL_FORMAT_UHJ2CHN8_SOFT),
896 DECL(AL_FORMAT_UHJ2CHN16_SOFT),
897 DECL(AL_FORMAT_UHJ2CHN_FLOAT32_SOFT),
898 DECL(AL_FORMAT_UHJ3CHN8_SOFT),
899 DECL(AL_FORMAT_UHJ3CHN16_SOFT),
900 DECL(AL_FORMAT_UHJ3CHN_FLOAT32_SOFT),
901 DECL(AL_FORMAT_UHJ4CHN8_SOFT),
902 DECL(AL_FORMAT_UHJ4CHN16_SOFT),
903 DECL(AL_FORMAT_UHJ4CHN_FLOAT32_SOFT),
904 DECL(AL_STEREO_MODE_SOFT),
905 DECL(AL_NORMAL_SOFT),
906 DECL(AL_SUPER_STEREO_SOFT),
907 DECL(AL_SUPER_STEREO_WIDTH_SOFT),
909 DECL(AL_FORMAT_UHJ2CHN_MULAW_SOFT),
910 DECL(AL_FORMAT_UHJ2CHN_ALAW_SOFT),
911 DECL(AL_FORMAT_UHJ2CHN_IMA4_SOFT),
912 DECL(AL_FORMAT_UHJ2CHN_MSADPCM_SOFT),
913 DECL(AL_FORMAT_UHJ3CHN_MULAW_SOFT),
914 DECL(AL_FORMAT_UHJ3CHN_ALAW_SOFT),
915 DECL(AL_FORMAT_UHJ4CHN_MULAW_SOFT),
916 DECL(AL_FORMAT_UHJ4CHN_ALAW_SOFT),
918 DECL(AL_STOP_SOURCES_ON_DISCONNECT_SOFT),
921 }, eaxEnumerations[] = {
922 DECL(AL_EAX_RAM_SIZE),
923 DECL(AL_EAX_RAM_FREE),
924 DECL(AL_STORAGE_AUTOMATIC),
925 DECL(AL_STORAGE_HARDWARE),
926 DECL(AL_STORAGE_ACCESSIBLE),
931 constexpr ALCchar alcNoError[] = "No Error";
932 constexpr ALCchar alcErrInvalidDevice[] = "Invalid Device";
933 constexpr ALCchar alcErrInvalidContext[] = "Invalid Context";
934 constexpr ALCchar alcErrInvalidEnum[] = "Invalid Enum";
935 constexpr ALCchar alcErrInvalidValue[] = "Invalid Value";
936 constexpr ALCchar alcErrOutOfMemory[] = "Out of Memory";
939 /************************************************
941 ************************************************/
943 /* Enumerated device names */
944 constexpr ALCchar alcDefaultName[] = "OpenAL Soft\0";
946 std::string alcAllDevicesList;
947 std::string alcCaptureDeviceList;
949 /* Default is always the first in the list */
950 std::string alcDefaultAllDevicesSpecifier;
951 std::string alcCaptureDefaultDeviceSpecifier;
953 std::atomic<ALCenum> LastNullDeviceError{ALC_NO_ERROR};
955 /* Flag to trap ALC device errors */
956 bool TrapALCError{false};
958 /* One-time configuration init control */
959 std::once_flag alc_config_once{};
961 /* Flag to specify if alcSuspendContext/alcProcessContext should defer/process
964 bool SuspendDefers{true};
966 /* Initial seed for dithering. */
967 constexpr uint DitherRNGSeed{22222u};
970 /************************************************
972 ************************************************/
973 constexpr ALCchar alcNoDeviceExtList[] =
974 "ALC_ENUMERATE_ALL_EXT "
975 "ALC_ENUMERATION_EXT "
978 "ALC_EXT_thread_local_context "
980 "ALC_SOFT_loopback_bformat "
981 "ALC_SOFT_reopen_device";
982 constexpr ALCchar alcExtensionList[] =
983 "ALC_ENUMERATE_ALL_EXT "
984 "ALC_ENUMERATION_EXT "
987 "ALC_EXT_disconnect "
989 "ALC_EXT_thread_local_context "
990 "ALC_SOFT_device_clock "
993 "ALC_SOFT_loopback_bformat "
994 "ALC_SOFT_output_limiter "
995 "ALC_SOFT_output_mode "
996 "ALC_SOFT_pause_device "
997 "ALC_SOFT_reopen_device";
998 constexpr int alcMajorVersion{1};
999 constexpr int alcMinorVersion{1};
1001 constexpr int alcEFXMajorVersion{1};
1002 constexpr int alcEFXMinorVersion{0};
1005 using DeviceRef = al::intrusive_ptr<ALCdevice>;
1008 /************************************************
1010 ************************************************/
1011 al::vector<ALCdevice*> DeviceList;
1012 al::vector<ALCcontext*> ContextList;
1014 std::recursive_mutex ListLock;
1017 void alc_initconfig(void)
1019 if(auto loglevel = al::getenv("ALSOFT_LOGLEVEL"))
1021 long lvl = strtol(loglevel->c_str(), nullptr, 0);
1022 if(lvl >= static_cast<long>(LogLevel::Trace))
1023 gLogLevel = LogLevel::Trace;
1024 else if(lvl <= static_cast<long>(LogLevel::Disable))
1025 gLogLevel = LogLevel::Disable;
1027 gLogLevel = static_cast<LogLevel>(lvl);
1031 if(const auto logfile = al::getenv(L"ALSOFT_LOGFILE"))
1033 FILE *logf{_wfopen(logfile->c_str(), L"wt")};
1034 if(logf) gLogFile = logf;
1037 auto u8name = wstr_to_utf8(logfile->c_str());
1038 ERR("Failed to open log file '%s'\n", u8name.c_str());
1042 if(const auto logfile = al::getenv("ALSOFT_LOGFILE"))
1044 FILE *logf{fopen(logfile->c_str(), "wt")};
1045 if(logf) gLogFile = logf;
1046 else ERR("Failed to open log file '%s'\n", logfile->c_str());
1050 TRACE("Initializing library v%s-%s %s\n", ALSOFT_VERSION, ALSOFT_GIT_COMMIT_HASH,
1054 if(al::size(BackendList) < 1)
1058 const al::span<const BackendInfo> infos{BackendList};
1059 names = infos[0].name;
1060 for(const auto &backend : infos.subspan<1>())
1063 names += backend.name;
1066 TRACE("Supported backends: %s\n", names.c_str());
1070 if(auto suspendmode = al::getenv("__ALSOFT_SUSPEND_CONTEXT"))
1072 if(al::strcasecmp(suspendmode->c_str(), "ignore") == 0)
1074 SuspendDefers = false;
1075 TRACE("Selected context suspend behavior, \"ignore\"\n");
1078 ERR("Unhandled context suspend behavior setting: \"%s\"\n", suspendmode->c_str());
1082 #if defined(HAVE_SSE4_1)
1083 capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3 | CPU_CAP_SSE4_1;
1084 #elif defined(HAVE_SSE3)
1085 capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3;
1086 #elif defined(HAVE_SSE2)
1087 capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2;
1088 #elif defined(HAVE_SSE)
1089 capfilter |= CPU_CAP_SSE;
1092 capfilter |= CPU_CAP_NEON;
1094 if(auto cpuopt = ConfigValueStr(nullptr, nullptr, "disable-cpu-exts"))
1096 const char *str{cpuopt->c_str()};
1097 if(al::strcasecmp(str, "all") == 0)
1101 const char *next = str;
1104 while(isspace(str[0]))
1106 next = strchr(str, ',');
1108 if(!str[0] || str[0] == ',')
1111 size_t len{next ? static_cast<size_t>(next-str) : strlen(str)};
1112 while(len > 0 && isspace(str[len-1]))
1114 if(len == 3 && al::strncasecmp(str, "sse", len) == 0)
1115 capfilter &= ~CPU_CAP_SSE;
1116 else if(len == 4 && al::strncasecmp(str, "sse2", len) == 0)
1117 capfilter &= ~CPU_CAP_SSE2;
1118 else if(len == 4 && al::strncasecmp(str, "sse3", len) == 0)
1119 capfilter &= ~CPU_CAP_SSE3;
1120 else if(len == 6 && al::strncasecmp(str, "sse4.1", len) == 0)
1121 capfilter &= ~CPU_CAP_SSE4_1;
1122 else if(len == 4 && al::strncasecmp(str, "neon", len) == 0)
1123 capfilter &= ~CPU_CAP_NEON;
1125 WARN("Invalid CPU extension \"%s\"\n", str);
1129 if(auto cpuopt = GetCPUInfo())
1131 if(!cpuopt->mVendor.empty() || !cpuopt->mName.empty())
1133 TRACE("Vendor ID: \"%s\"\n", cpuopt->mVendor.c_str());
1134 TRACE("Name: \"%s\"\n", cpuopt->mName.c_str());
1136 const int caps{cpuopt->mCaps};
1137 TRACE("Extensions:%s%s%s%s%s%s\n",
1138 ((capfilter&CPU_CAP_SSE) ? ((caps&CPU_CAP_SSE) ? " +SSE" : " -SSE") : ""),
1139 ((capfilter&CPU_CAP_SSE2) ? ((caps&CPU_CAP_SSE2) ? " +SSE2" : " -SSE2") : ""),
1140 ((capfilter&CPU_CAP_SSE3) ? ((caps&CPU_CAP_SSE3) ? " +SSE3" : " -SSE3") : ""),
1141 ((capfilter&CPU_CAP_SSE4_1) ? ((caps&CPU_CAP_SSE4_1) ? " +SSE4.1" : " -SSE4.1") : ""),
1142 ((capfilter&CPU_CAP_NEON) ? ((caps&CPU_CAP_NEON) ? " +NEON" : " -NEON") : ""),
1143 ((!capfilter) ? " -none-" : ""));
1144 CPUCapFlags = caps & capfilter;
1147 if(auto priopt = ConfigValueInt(nullptr, nullptr, "rt-prio"))
1148 RTPrioLevel = *priopt;
1149 if(auto limopt = ConfigValueBool(nullptr, nullptr, "rt-time-limit"))
1150 AllowRTTimeLimit = *limopt;
1153 CompatFlagBitset compatflags{};
1154 auto checkflag = [](const char *envname, const char *optname) -> bool
1156 if(auto optval = al::getenv(envname))
1158 if(al::strcasecmp(optval->c_str(), "true") == 0
1159 || strtol(optval->c_str(), nullptr, 0) == 1)
1163 return GetConfigValueBool(nullptr, "game_compat", optname, false);
1165 sBufferSubDataCompat = checkflag("__ALSOFT_ENABLE_SUB_DATA_EXT", "enable-sub-data-ext");
1166 compatflags.set(CompatFlags::ReverseX, checkflag("__ALSOFT_REVERSE_X", "reverse-x"));
1167 compatflags.set(CompatFlags::ReverseY, checkflag("__ALSOFT_REVERSE_Y", "reverse-y"));
1168 compatflags.set(CompatFlags::ReverseZ, checkflag("__ALSOFT_REVERSE_Z", "reverse-z"));
1170 aluInit(compatflags, ConfigValueFloat(nullptr, "game_compat", "nfc-scale").value_or(1.0f));
1172 Voice::InitMixer(ConfigValueStr(nullptr, nullptr, "resampler"));
1174 auto uhjfiltopt = ConfigValueStr(nullptr, "uhj", "decode-filter");
1177 if((uhjfiltopt = ConfigValueStr(nullptr, "uhj", "filter")))
1178 WARN("uhj/filter is deprecated, please use uhj/decode-filter\n");
1182 if(al::strcasecmp(uhjfiltopt->c_str(), "fir256") == 0)
1183 UhjDecodeQuality = UhjQualityType::FIR256;
1184 else if(al::strcasecmp(uhjfiltopt->c_str(), "fir512") == 0)
1185 UhjDecodeQuality = UhjQualityType::FIR512;
1186 else if(al::strcasecmp(uhjfiltopt->c_str(), "iir") == 0)
1187 UhjDecodeQuality = UhjQualityType::IIR;
1189 WARN("Unsupported uhj/decode-filter: %s\n", uhjfiltopt->c_str());
1191 if((uhjfiltopt = ConfigValueStr(nullptr, "uhj", "encode-filter")))
1193 if(al::strcasecmp(uhjfiltopt->c_str(), "fir256") == 0)
1194 UhjEncodeQuality = UhjQualityType::FIR256;
1195 else if(al::strcasecmp(uhjfiltopt->c_str(), "fir512") == 0)
1196 UhjEncodeQuality = UhjQualityType::FIR512;
1197 else if(al::strcasecmp(uhjfiltopt->c_str(), "iir") == 0)
1198 UhjEncodeQuality = UhjQualityType::IIR;
1200 WARN("Unsupported uhj/encode-filter: %s\n", uhjfiltopt->c_str());
1203 auto traperr = al::getenv("ALSOFT_TRAP_ERROR");
1204 if(traperr && (al::strcasecmp(traperr->c_str(), "true") == 0
1205 || std::strtol(traperr->c_str(), nullptr, 0) == 1))
1208 TrapALCError = true;
1212 traperr = al::getenv("ALSOFT_TRAP_AL_ERROR");
1214 TrapALError = al::strcasecmp(traperr->c_str(), "true") == 0
1215 || strtol(traperr->c_str(), nullptr, 0) == 1;
1217 TrapALError = !!GetConfigValueBool(nullptr, nullptr, "trap-al-error", false);
1219 traperr = al::getenv("ALSOFT_TRAP_ALC_ERROR");
1221 TrapALCError = al::strcasecmp(traperr->c_str(), "true") == 0
1222 || strtol(traperr->c_str(), nullptr, 0) == 1;
1224 TrapALCError = !!GetConfigValueBool(nullptr, nullptr, "trap-alc-error", false);
1227 if(auto boostopt = ConfigValueFloat(nullptr, "reverb", "boost"))
1229 const float valf{std::isfinite(*boostopt) ? clampf(*boostopt, -24.0f, 24.0f) : 0.0f};
1230 ReverbBoost *= std::pow(10.0f, valf / 20.0f);
1233 auto BackendListEnd = std::end(BackendList);
1234 auto devopt = al::getenv("ALSOFT_DRIVERS");
1235 if(devopt || (devopt=ConfigValueStr(nullptr, nullptr, "drivers")))
1237 auto backendlist_cur = std::begin(BackendList);
1240 const char *next{devopt->c_str()};
1242 const char *devs{next};
1243 while(isspace(devs[0]))
1245 next = strchr(devs, ',');
1247 const bool delitem{devs[0] == '-'};
1248 if(devs[0] == '-') devs++;
1250 if(!devs[0] || devs[0] == ',')
1257 size_t len{next ? (static_cast<size_t>(next-devs)) : strlen(devs)};
1258 while(len > 0 && isspace(devs[len-1])) --len;
1260 /* HACK: For backwards compatibility, convert backend references of
1261 * mmdevapi to wasapi. This should eventually be removed.
1263 if(len == 8 && strncmp(devs, "mmdevapi", len) == 0)
1270 auto find_backend = [devs,len](const BackendInfo &backend) -> bool
1271 { return len == strlen(backend.name) && strncmp(backend.name, devs, len) == 0; };
1272 auto this_backend = std::find_if(std::begin(BackendList), BackendListEnd,
1275 if(this_backend == BackendListEnd)
1279 BackendListEnd = std::move(this_backend+1, BackendListEnd, this_backend);
1281 backendlist_cur = std::rotate(backendlist_cur, this_backend, this_backend+1);
1285 BackendListEnd = backendlist_cur;
1288 auto init_backend = [](BackendInfo &backend) -> void
1290 if(PlaybackFactory && CaptureFactory)
1293 BackendFactory &factory = backend.getFactory();
1296 WARN("Failed to initialize backend \"%s\"\n", backend.name);
1300 TRACE("Initialized backend \"%s\"\n", backend.name);
1301 if(!PlaybackFactory && factory.querySupport(BackendType::Playback))
1303 PlaybackFactory = &factory;
1304 TRACE("Added \"%s\" for playback\n", backend.name);
1306 if(!CaptureFactory && factory.querySupport(BackendType::Capture))
1308 CaptureFactory = &factory;
1309 TRACE("Added \"%s\" for capture\n", backend.name);
1312 std::for_each(std::begin(BackendList), BackendListEnd, init_backend);
1314 LoopbackBackendFactory::getFactory().init();
1316 if(!PlaybackFactory)
1317 WARN("No playback backend available!\n");
1319 WARN("No capture backend available!\n");
1321 if(auto exclopt = ConfigValueStr(nullptr, nullptr, "excludefx"))
1323 const char *next{exclopt->c_str()};
1325 const char *str{next};
1326 next = strchr(str, ',');
1328 if(!str[0] || next == str)
1331 size_t len{next ? static_cast<size_t>(next-str) : strlen(str)};
1332 for(const EffectList &effectitem : gEffectList)
1334 if(len == strlen(effectitem.name) &&
1335 strncmp(effectitem.name, str, len) == 0)
1336 DisabledEffects[effectitem.type] = true;
1341 InitEffect(&ALCcontext::sDefaultEffect);
1342 auto defrevopt = al::getenv("ALSOFT_DEFAULT_REVERB");
1343 if(defrevopt || (defrevopt=ConfigValueStr(nullptr, nullptr, "default-reverb")))
1344 LoadReverbPreset(defrevopt->c_str(), &ALCcontext::sDefaultEffect);
1348 static constexpr char eax_block_name[] = "eax";
1350 if(const auto eax_enable_opt = ConfigValueBool(nullptr, eax_block_name, "enable"))
1352 eax_g_is_enabled = *eax_enable_opt;
1353 if(!eax_g_is_enabled)
1354 TRACE("%s\n", "EAX disabled by a configuration.");
1357 eax_g_is_enabled = true;
1359 if((DisabledEffects[EAXREVERB_EFFECT] || DisabledEffects[CHORUS_EFFECT])
1360 && eax_g_is_enabled)
1362 eax_g_is_enabled = false;
1363 TRACE("EAX disabled because %s disabled.\n",
1364 (DisabledEffects[EAXREVERB_EFFECT] && DisabledEffects[CHORUS_EFFECT])
1365 ? "EAXReverb and Chorus are" :
1366 DisabledEffects[EAXREVERB_EFFECT] ? "EAXReverb is" :
1367 DisabledEffects[CHORUS_EFFECT] ? "Chorus is" : "");
1370 #endif // ALSOFT_EAX
1372 inline void InitConfig()
1373 { std::call_once(alc_config_once, [](){alc_initconfig();}); }
1376 /************************************************
1377 * Device enumeration
1378 ************************************************/
1379 void ProbeAllDevicesList()
1383 std::lock_guard<std::recursive_mutex> _{ListLock};
1384 if(!PlaybackFactory)
1385 decltype(alcAllDevicesList){}.swap(alcAllDevicesList);
1388 std::string names{PlaybackFactory->probe(BackendType::Playback)};
1389 if(names.empty()) names += '\0';
1390 names.swap(alcAllDevicesList);
1393 void ProbeCaptureDeviceList()
1397 std::lock_guard<std::recursive_mutex> _{ListLock};
1399 decltype(alcCaptureDeviceList){}.swap(alcCaptureDeviceList);
1402 std::string names{CaptureFactory->probe(BackendType::Capture)};
1403 if(names.empty()) names += '\0';
1404 names.swap(alcCaptureDeviceList);
1409 struct DevFmtPair { DevFmtChannels chans; DevFmtType type; };
1410 al::optional<DevFmtPair> DecomposeDevFormat(ALenum format)
1412 static const struct {
1414 DevFmtChannels channels;
1417 { AL_FORMAT_MONO8, DevFmtMono, DevFmtUByte },
1418 { AL_FORMAT_MONO16, DevFmtMono, DevFmtShort },
1419 { AL_FORMAT_MONO_FLOAT32, DevFmtMono, DevFmtFloat },
1421 { AL_FORMAT_STEREO8, DevFmtStereo, DevFmtUByte },
1422 { AL_FORMAT_STEREO16, DevFmtStereo, DevFmtShort },
1423 { AL_FORMAT_STEREO_FLOAT32, DevFmtStereo, DevFmtFloat },
1425 { AL_FORMAT_QUAD8, DevFmtQuad, DevFmtUByte },
1426 { AL_FORMAT_QUAD16, DevFmtQuad, DevFmtShort },
1427 { AL_FORMAT_QUAD32, DevFmtQuad, DevFmtFloat },
1429 { AL_FORMAT_51CHN8, DevFmtX51, DevFmtUByte },
1430 { AL_FORMAT_51CHN16, DevFmtX51, DevFmtShort },
1431 { AL_FORMAT_51CHN32, DevFmtX51, DevFmtFloat },
1433 { AL_FORMAT_61CHN8, DevFmtX61, DevFmtUByte },
1434 { AL_FORMAT_61CHN16, DevFmtX61, DevFmtShort },
1435 { AL_FORMAT_61CHN32, DevFmtX61, DevFmtFloat },
1437 { AL_FORMAT_71CHN8, DevFmtX71, DevFmtUByte },
1438 { AL_FORMAT_71CHN16, DevFmtX71, DevFmtShort },
1439 { AL_FORMAT_71CHN32, DevFmtX71, DevFmtFloat },
1442 for(const auto &item : list)
1444 if(item.format == format)
1445 return al::make_optional<DevFmtPair>({item.channels, item.type});
1451 al::optional<DevFmtType> DevFmtTypeFromEnum(ALCenum type)
1455 case ALC_BYTE_SOFT: return DevFmtByte;
1456 case ALC_UNSIGNED_BYTE_SOFT: return DevFmtUByte;
1457 case ALC_SHORT_SOFT: return DevFmtShort;
1458 case ALC_UNSIGNED_SHORT_SOFT: return DevFmtUShort;
1459 case ALC_INT_SOFT: return DevFmtInt;
1460 case ALC_UNSIGNED_INT_SOFT: return DevFmtUInt;
1461 case ALC_FLOAT_SOFT: return DevFmtFloat;
1463 WARN("Unsupported format type: 0x%04x\n", type);
1466 ALCenum EnumFromDevFmt(DevFmtType type)
1470 case DevFmtByte: return ALC_BYTE_SOFT;
1471 case DevFmtUByte: return ALC_UNSIGNED_BYTE_SOFT;
1472 case DevFmtShort: return ALC_SHORT_SOFT;
1473 case DevFmtUShort: return ALC_UNSIGNED_SHORT_SOFT;
1474 case DevFmtInt: return ALC_INT_SOFT;
1475 case DevFmtUInt: return ALC_UNSIGNED_INT_SOFT;
1476 case DevFmtFloat: return ALC_FLOAT_SOFT;
1478 throw std::runtime_error{"Invalid DevFmtType: "+std::to_string(int(type))};
1481 al::optional<DevFmtChannels> DevFmtChannelsFromEnum(ALCenum channels)
1485 case ALC_MONO_SOFT: return DevFmtMono;
1486 case ALC_STEREO_SOFT: return DevFmtStereo;
1487 case ALC_QUAD_SOFT: return DevFmtQuad;
1488 case ALC_5POINT1_SOFT: return DevFmtX51;
1489 case ALC_6POINT1_SOFT: return DevFmtX61;
1490 case ALC_7POINT1_SOFT: return DevFmtX71;
1491 case ALC_BFORMAT3D_SOFT: return DevFmtAmbi3D;
1493 WARN("Unsupported format channels: 0x%04x\n", channels);
1496 ALCenum EnumFromDevFmt(DevFmtChannels channels)
1500 case DevFmtMono: return ALC_MONO_SOFT;
1501 case DevFmtStereo: return ALC_STEREO_SOFT;
1502 case DevFmtQuad: return ALC_QUAD_SOFT;
1503 case DevFmtX51: return ALC_5POINT1_SOFT;
1504 case DevFmtX61: return ALC_6POINT1_SOFT;
1505 case DevFmtX71: return ALC_7POINT1_SOFT;
1506 case DevFmtAmbi3D: return ALC_BFORMAT3D_SOFT;
1507 /* FIXME: Shouldn't happen. */
1509 case DevFmtX3D71: break;
1511 throw std::runtime_error{"Invalid DevFmtChannels: "+std::to_string(int(channels))};
1514 al::optional<DevAmbiLayout> DevAmbiLayoutFromEnum(ALCenum layout)
1518 case ALC_FUMA_SOFT: return DevAmbiLayout::FuMa;
1519 case ALC_ACN_SOFT: return DevAmbiLayout::ACN;
1521 WARN("Unsupported ambisonic layout: 0x%04x\n", layout);
1524 ALCenum EnumFromDevAmbi(DevAmbiLayout layout)
1528 case DevAmbiLayout::FuMa: return ALC_FUMA_SOFT;
1529 case DevAmbiLayout::ACN: return ALC_ACN_SOFT;
1531 throw std::runtime_error{"Invalid DevAmbiLayout: "+std::to_string(int(layout))};
1534 al::optional<DevAmbiScaling> DevAmbiScalingFromEnum(ALCenum scaling)
1538 case ALC_FUMA_SOFT: return DevAmbiScaling::FuMa;
1539 case ALC_SN3D_SOFT: return DevAmbiScaling::SN3D;
1540 case ALC_N3D_SOFT: return DevAmbiScaling::N3D;
1542 WARN("Unsupported ambisonic scaling: 0x%04x\n", scaling);
1545 ALCenum EnumFromDevAmbi(DevAmbiScaling scaling)
1549 case DevAmbiScaling::FuMa: return ALC_FUMA_SOFT;
1550 case DevAmbiScaling::SN3D: return ALC_SN3D_SOFT;
1551 case DevAmbiScaling::N3D: return ALC_N3D_SOFT;
1553 throw std::runtime_error{"Invalid DevAmbiScaling: "+std::to_string(int(scaling))};
1557 /* Downmixing channel arrays, to map the given format's missing channels to
1558 * existing ones. Based on Wine's DSound downmix values, which are based on
1561 constexpr std::array<InputRemixMap::TargetMix,2> FrontStereoSplit{{
1562 {FrontLeft, 0.5f}, {FrontRight, 0.5f}
1564 constexpr std::array<InputRemixMap::TargetMix,1> FrontLeft9{{
1565 {FrontLeft, 1.0f/9.0f}
1567 constexpr std::array<InputRemixMap::TargetMix,1> FrontRight9{{
1568 {FrontRight, 1.0f/9.0f}
1570 constexpr std::array<InputRemixMap::TargetMix,2> BackMonoToFrontSplit{{
1571 {FrontLeft, 0.5f/9.0f}, {FrontRight, 0.5f/9.0f}
1573 constexpr std::array<InputRemixMap::TargetMix,2> LeftStereoSplit{{
1574 {FrontLeft, 0.5f}, {BackLeft, 0.5f}
1576 constexpr std::array<InputRemixMap::TargetMix,2> RightStereoSplit{{
1577 {FrontRight, 0.5f}, {BackRight, 0.5f}
1579 constexpr std::array<InputRemixMap::TargetMix,2> BackStereoSplit{{
1580 {BackLeft, 0.5f}, {BackRight, 0.5f}
1582 constexpr std::array<InputRemixMap::TargetMix,2> SideStereoSplit{{
1583 {SideLeft, 0.5f}, {SideRight, 0.5f}
1585 constexpr std::array<InputRemixMap::TargetMix,1> ToSideLeft{{
1588 constexpr std::array<InputRemixMap::TargetMix,1> ToSideRight{{
1591 constexpr std::array<InputRemixMap::TargetMix,2> BackLeftSplit{{
1592 {SideLeft, 0.5f}, {BackCenter, 0.5f}
1594 constexpr std::array<InputRemixMap::TargetMix,2> BackRightSplit{{
1595 {SideRight, 0.5f}, {BackCenter, 0.5f}
1598 const std::array<InputRemixMap,6> StereoDownmix{{
1599 { FrontCenter, FrontStereoSplit },
1600 { SideLeft, FrontLeft9 },
1601 { SideRight, FrontRight9 },
1602 { BackLeft, FrontLeft9 },
1603 { BackRight, FrontRight9 },
1604 { BackCenter, BackMonoToFrontSplit },
1606 const std::array<InputRemixMap,4> QuadDownmix{{
1607 { FrontCenter, FrontStereoSplit },
1608 { SideLeft, LeftStereoSplit },
1609 { SideRight, RightStereoSplit },
1610 { BackCenter, BackStereoSplit },
1612 const std::array<InputRemixMap,3> X51Downmix{{
1613 { BackLeft, ToSideLeft },
1614 { BackRight, ToSideRight },
1615 { BackCenter, SideStereoSplit },
1617 const std::array<InputRemixMap,2> X61Downmix{{
1618 { BackLeft, BackLeftSplit },
1619 { BackRight, BackRightSplit },
1621 const std::array<InputRemixMap,1> X71Downmix{{
1622 { BackCenter, BackStereoSplit },
1626 /** Stores the latest ALC device error. */
1627 void alcSetError(ALCdevice *device, ALCenum errorCode)
1629 WARN("Error generated on device %p, code 0x%04x\n", voidp{device}, errorCode);
1633 /* DebugBreak() will cause an exception if there is no debugger */
1634 if(IsDebuggerPresent())
1636 #elif defined(SIGTRAP)
1642 device->LastError.store(errorCode);
1644 LastNullDeviceError.store(errorCode);
1648 std::unique_ptr<Compressor> CreateDeviceLimiter(const ALCdevice *device, const float threshold)
1650 static constexpr bool AutoKnee{true};
1651 static constexpr bool AutoAttack{true};
1652 static constexpr bool AutoRelease{true};
1653 static constexpr bool AutoPostGain{true};
1654 static constexpr bool AutoDeclip{true};
1655 static constexpr float LookAheadTime{0.001f};
1656 static constexpr float HoldTime{0.002f};
1657 static constexpr float PreGainDb{0.0f};
1658 static constexpr float PostGainDb{0.0f};
1659 static constexpr float Ratio{std::numeric_limits<float>::infinity()};
1660 static constexpr float KneeDb{0.0f};
1661 static constexpr float AttackTime{0.02f};
1662 static constexpr float ReleaseTime{0.2f};
1664 return Compressor::Create(device->RealOut.Buffer.size(), static_cast<float>(device->Frequency),
1665 AutoKnee, AutoAttack, AutoRelease, AutoPostGain, AutoDeclip, LookAheadTime, HoldTime,
1666 PreGainDb, PostGainDb, threshold, Ratio, KneeDb, AttackTime, ReleaseTime);
1670 * Updates the device's base clock time with however many samples have been
1671 * done. This is used so frequency changes on the device don't cause the time
1672 * to jump forward or back. Must not be called while the device is running/
1675 inline void UpdateClockBase(ALCdevice *device)
1677 IncrementRef(device->MixCount);
1678 device->ClockBase += nanoseconds{seconds{device->SamplesDone}} / device->Frequency;
1679 device->SamplesDone = 0;
1680 IncrementRef(device->MixCount);
1684 * Updates device parameters according to the attribute list (caller is
1685 * responsible for holding the list lock).
1687 ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList)
1689 if((!attrList || !attrList[0]) && device->Type == DeviceType::Loopback)
1691 WARN("Missing attributes for loopback device\n");
1692 return ALC_INVALID_VALUE;
1695 uint numMono{device->NumMonoSources};
1696 uint numStereo{device->NumStereoSources};
1697 uint numSends{device->NumAuxSends};
1698 al::optional<StereoEncoding> stereomode;
1699 al::optional<bool> optlimit;
1700 al::optional<uint> optsrate;
1701 al::optional<DevFmtChannels> optchans;
1702 al::optional<DevFmtType> opttype;
1703 al::optional<DevAmbiLayout> optlayout;
1704 al::optional<DevAmbiScaling> optscale;
1705 uint period_size{DEFAULT_UPDATE_SIZE};
1706 uint buffer_size{DEFAULT_UPDATE_SIZE * DEFAULT_NUM_UPDATES};
1710 if(device->Type != DeviceType::Loopback)
1712 /* Get default settings from the user configuration */
1714 if(auto freqopt = device->configValue<uint>(nullptr, "frequency"))
1716 optsrate = clampu(*freqopt, MIN_OUTPUT_RATE, MAX_OUTPUT_RATE);
1718 const double scale{static_cast<double>(*optsrate) / DEFAULT_OUTPUT_RATE};
1719 period_size = static_cast<uint>(period_size*scale + 0.5);
1722 if(auto persizeopt = device->configValue<uint>(nullptr, "period_size"))
1723 period_size = clampu(*persizeopt, 64, 8192);
1724 if(auto numperopt = device->configValue<uint>(nullptr, "periods"))
1725 buffer_size = clampu(*numperopt, 2, 16) * period_size;
1727 buffer_size = period_size * DEFAULT_NUM_UPDATES;
1729 if(auto typeopt = device->configValue<std::string>(nullptr, "sample-type"))
1731 static constexpr struct TypeMap {
1735 { "int8", DevFmtByte },
1736 { "uint8", DevFmtUByte },
1737 { "int16", DevFmtShort },
1738 { "uint16", DevFmtUShort },
1739 { "int32", DevFmtInt },
1740 { "uint32", DevFmtUInt },
1741 { "float32", DevFmtFloat },
1744 const ALCchar *fmt{typeopt->c_str()};
1745 auto iter = std::find_if(std::begin(typelist), std::end(typelist),
1746 [fmt](const TypeMap &entry) -> bool
1747 { return al::strcasecmp(entry.name, fmt) == 0; });
1748 if(iter == std::end(typelist))
1749 ERR("Unsupported sample-type: %s\n", fmt);
1751 opttype = iter->type;
1753 if(auto chanopt = device->configValue<std::string>(nullptr, "channels"))
1755 static constexpr struct ChannelMap {
1756 const char name[16];
1757 DevFmtChannels chans;
1760 { "mono", DevFmtMono, 0 },
1761 { "stereo", DevFmtStereo, 0 },
1762 { "quad", DevFmtQuad, 0 },
1763 { "surround51", DevFmtX51, 0 },
1764 { "surround61", DevFmtX61, 0 },
1765 { "surround71", DevFmtX71, 0 },
1766 { "surround714", DevFmtX714, 0 },
1767 { "surround3d71", DevFmtX3D71, 0 },
1768 { "surround51rear", DevFmtX51, 0 },
1769 { "ambi1", DevFmtAmbi3D, 1 },
1770 { "ambi2", DevFmtAmbi3D, 2 },
1771 { "ambi3", DevFmtAmbi3D, 3 },
1774 const ALCchar *fmt{chanopt->c_str()};
1775 auto iter = std::find_if(std::begin(chanlist), std::end(chanlist),
1776 [fmt](const ChannelMap &entry) -> bool
1777 { return al::strcasecmp(entry.name, fmt) == 0; });
1778 if(iter == std::end(chanlist))
1779 ERR("Unsupported channels: %s\n", fmt);
1782 optchans = iter->chans;
1783 aorder = iter->order;
1786 if(auto ambiopt = device->configValue<std::string>(nullptr, "ambi-format"))
1788 const ALCchar *fmt{ambiopt->c_str()};
1789 if(al::strcasecmp(fmt, "fuma") == 0)
1791 optlayout = DevAmbiLayout::FuMa;
1792 optscale = DevAmbiScaling::FuMa;
1794 else if(al::strcasecmp(fmt, "acn+fuma") == 0)
1796 optlayout = DevAmbiLayout::ACN;
1797 optscale = DevAmbiScaling::FuMa;
1799 else if(al::strcasecmp(fmt, "ambix") == 0 || al::strcasecmp(fmt, "acn+sn3d") == 0)
1801 optlayout = DevAmbiLayout::ACN;
1802 optscale = DevAmbiScaling::SN3D;
1804 else if(al::strcasecmp(fmt, "acn+n3d") == 0)
1806 optlayout = DevAmbiLayout::ACN;
1807 optscale = DevAmbiScaling::N3D;
1810 ERR("Unsupported ambi-format: %s\n", fmt);
1813 if(auto hrtfopt = device->configValue<std::string>(nullptr, "hrtf"))
1815 WARN("general/hrtf is deprecated, please use stereo-encoding instead\n");
1817 const char *hrtf{hrtfopt->c_str()};
1818 if(al::strcasecmp(hrtf, "true") == 0)
1819 stereomode = StereoEncoding::Hrtf;
1820 else if(al::strcasecmp(hrtf, "false") == 0)
1822 if(!stereomode || *stereomode == StereoEncoding::Hrtf)
1823 stereomode = StereoEncoding::Default;
1825 else if(al::strcasecmp(hrtf, "auto") != 0)
1826 ERR("Unexpected hrtf value: %s\n", hrtf);
1830 if(auto encopt = device->configValue<std::string>(nullptr, "stereo-encoding"))
1832 const char *mode{encopt->c_str()};
1833 if(al::strcasecmp(mode, "basic") == 0 || al::strcasecmp(mode, "panpot") == 0)
1834 stereomode = StereoEncoding::Basic;
1835 else if(al::strcasecmp(mode, "uhj") == 0)
1836 stereomode = StereoEncoding::Uhj;
1837 else if(al::strcasecmp(mode, "hrtf") == 0)
1838 stereomode = StereoEncoding::Hrtf;
1840 ERR("Unexpected stereo-encoding: %s\n", mode);
1843 // Check for app-specified attributes
1844 if(attrList && attrList[0])
1846 ALenum outmode{ALC_ANY_SOFT};
1847 al::optional<bool> opthrtf;
1850 #define ATTRIBUTE(a) a: TRACE("%s = %d\n", #a, attrList[attrIdx + 1]);
1852 while(attrList[attrIdx])
1854 switch(attrList[attrIdx])
1856 case ATTRIBUTE(ALC_FORMAT_CHANNELS_SOFT)
1857 if(device->Type == DeviceType::Loopback)
1858 optchans = DevFmtChannelsFromEnum(attrList[attrIdx + 1]);
1861 case ATTRIBUTE(ALC_FORMAT_TYPE_SOFT)
1862 if(device->Type == DeviceType::Loopback)
1863 opttype = DevFmtTypeFromEnum(attrList[attrIdx + 1]);
1866 case ATTRIBUTE(ALC_FREQUENCY)
1867 freqAttr = attrList[attrIdx + 1];
1870 case ATTRIBUTE(ALC_AMBISONIC_LAYOUT_SOFT)
1871 if(device->Type == DeviceType::Loopback)
1872 optlayout = DevAmbiLayoutFromEnum(attrList[attrIdx + 1]);
1875 case ATTRIBUTE(ALC_AMBISONIC_SCALING_SOFT)
1876 if(device->Type == DeviceType::Loopback)
1877 optscale = DevAmbiScalingFromEnum(attrList[attrIdx + 1]);
1880 case ATTRIBUTE(ALC_AMBISONIC_ORDER_SOFT)
1881 if(device->Type == DeviceType::Loopback)
1882 aorder = static_cast<uint>(attrList[attrIdx + 1]);
1885 case ATTRIBUTE(ALC_MONO_SOURCES)
1886 numMono = static_cast<uint>(attrList[attrIdx + 1]);
1887 if(numMono > INT_MAX) numMono = 0;
1890 case ATTRIBUTE(ALC_STEREO_SOURCES)
1891 numStereo = static_cast<uint>(attrList[attrIdx + 1]);
1892 if(numStereo > INT_MAX) numStereo = 0;
1895 case ATTRIBUTE(ALC_MAX_AUXILIARY_SENDS)
1896 numSends = static_cast<uint>(attrList[attrIdx + 1]);
1897 if(numSends > INT_MAX) numSends = 0;
1898 else numSends = minu(numSends, MAX_SENDS);
1901 case ATTRIBUTE(ALC_HRTF_SOFT)
1902 if(attrList[attrIdx + 1] == ALC_FALSE)
1904 else if(attrList[attrIdx + 1] == ALC_TRUE)
1906 else if(attrList[attrIdx + 1] == ALC_DONT_CARE_SOFT)
1907 opthrtf = al::nullopt;
1910 case ATTRIBUTE(ALC_HRTF_ID_SOFT)
1911 hrtf_id = attrList[attrIdx + 1];
1914 case ATTRIBUTE(ALC_OUTPUT_LIMITER_SOFT)
1915 if(attrList[attrIdx + 1] == ALC_FALSE)
1917 else if(attrList[attrIdx + 1] == ALC_TRUE)
1919 else if(attrList[attrIdx + 1] == ALC_DONT_CARE_SOFT)
1920 optlimit = al::nullopt;
1923 case ATTRIBUTE(ALC_OUTPUT_MODE_SOFT)
1924 outmode = attrList[attrIdx + 1];
1928 TRACE("0x%04X = %d (0x%x)\n", attrList[attrIdx],
1929 attrList[attrIdx + 1], attrList[attrIdx + 1]);
1937 if(device->Type == DeviceType::Loopback)
1939 if(!optchans || !opttype)
1940 return ALC_INVALID_VALUE;
1941 if(freqAttr < MIN_OUTPUT_RATE || freqAttr > MAX_OUTPUT_RATE)
1942 return ALC_INVALID_VALUE;
1943 if(*optchans == DevFmtAmbi3D)
1945 if(!optlayout || !optscale)
1946 return ALC_INVALID_VALUE;
1947 if(aorder < 1 || aorder > MaxAmbiOrder)
1948 return ALC_INVALID_VALUE;
1949 if((*optlayout == DevAmbiLayout::FuMa || *optscale == DevAmbiScaling::FuMa)
1951 return ALC_INVALID_VALUE;
1953 else if(*optchans == DevFmtStereo)
1958 stereomode = StereoEncoding::Hrtf;
1961 if(stereomode.value_or(StereoEncoding::Hrtf) == StereoEncoding::Hrtf)
1962 stereomode = StereoEncoding::Default;
1966 if(outmode == ALC_STEREO_BASIC_SOFT)
1967 stereomode = StereoEncoding::Basic;
1968 else if(outmode == ALC_STEREO_UHJ_SOFT)
1969 stereomode = StereoEncoding::Uhj;
1970 else if(outmode == ALC_STEREO_HRTF_SOFT)
1971 stereomode = StereoEncoding::Hrtf;
1974 optsrate = static_cast<uint>(freqAttr);
1981 stereomode = StereoEncoding::Hrtf;
1984 if(stereomode.value_or(StereoEncoding::Hrtf) == StereoEncoding::Hrtf)
1985 stereomode = StereoEncoding::Default;
1989 if(outmode != ALC_ANY_SOFT)
1991 using OutputMode = ALCdevice::OutputMode;
1992 switch(OutputMode(outmode))
1994 case OutputMode::Any: break;
1995 case OutputMode::Mono: optchans = DevFmtMono; break;
1996 case OutputMode::Stereo: optchans = DevFmtStereo; break;
1997 case OutputMode::StereoBasic:
1998 optchans = DevFmtStereo;
1999 stereomode = StereoEncoding::Basic;
2001 case OutputMode::Uhj2:
2002 optchans = DevFmtStereo;
2003 stereomode = StereoEncoding::Uhj;
2005 case OutputMode::Hrtf:
2006 optchans = DevFmtStereo;
2007 stereomode = StereoEncoding::Hrtf;
2009 case OutputMode::Quad: optchans = DevFmtQuad; break;
2010 case OutputMode::X51: optchans = DevFmtX51; break;
2011 case OutputMode::X61: optchans = DevFmtX61; break;
2012 case OutputMode::X71: optchans = DevFmtX71; break;
2018 uint oldrate = optsrate.value_or(DEFAULT_OUTPUT_RATE);
2019 freqAttr = clampi(freqAttr, MIN_OUTPUT_RATE, MAX_OUTPUT_RATE);
2021 const double scale{static_cast<double>(freqAttr) / oldrate};
2022 period_size = static_cast<uint>(period_size*scale + 0.5);
2023 buffer_size = static_cast<uint>(buffer_size*scale + 0.5);
2024 optsrate = static_cast<uint>(freqAttr);
2028 /* If a context is already running on the device, stop playback so the
2029 * device attributes can be updated.
2031 if(device->Flags.test(DeviceRunning))
2032 device->Backend->stop();
2033 device->Flags.reset(DeviceRunning);
2035 UpdateClockBase(device);
2038 if(device->Flags.test(DeviceRunning))
2039 return ALC_NO_ERROR;
2041 device->AvgSpeakerDist = 0.0f;
2042 device->mNFCtrlFilter = NfcFilter{};
2043 device->mUhjEncoder = nullptr;
2044 device->AmbiDecoder = nullptr;
2045 device->Bs2b = nullptr;
2046 device->PostProcess = nullptr;
2048 device->Limiter = nullptr;
2049 device->ChannelDelays = nullptr;
2051 std::fill(std::begin(device->HrtfAccumData), std::end(device->HrtfAccumData), float2{});
2053 device->Dry.AmbiMap.fill(BFChannelConfig{});
2054 device->Dry.Buffer = {};
2055 std::fill(std::begin(device->NumChannelsPerOrder), std::end(device->NumChannelsPerOrder), 0u);
2056 device->RealOut.RemixMap = {};
2057 device->RealOut.ChannelIndex.fill(InvalidChannelIndex);
2058 device->RealOut.Buffer = {};
2059 device->MixBuffer.clear();
2060 device->MixBuffer.shrink_to_fit();
2062 UpdateClockBase(device);
2063 device->FixedLatency = nanoseconds::zero();
2065 device->DitherDepth = 0.0f;
2066 device->DitherSeed = DitherRNGSeed;
2068 device->mHrtfStatus = ALC_HRTF_DISABLED_SOFT;
2070 /*************************************************************************
2071 * Update device format request
2074 if(device->Type == DeviceType::Loopback)
2076 device->Frequency = *optsrate;
2077 device->FmtChans = *optchans;
2078 device->FmtType = *opttype;
2079 if(device->FmtChans == DevFmtAmbi3D)
2081 device->mAmbiOrder = aorder;
2082 device->mAmbiLayout = *optlayout;
2083 device->mAmbiScale = *optscale;
2085 device->Flags.set(FrequencyRequest).set(ChannelsRequest).set(SampleTypeRequest);
2089 device->FmtType = opttype.value_or(DevFmtTypeDefault);
2090 device->FmtChans = optchans.value_or(DevFmtChannelsDefault);
2091 device->mAmbiOrder = 0;
2092 device->BufferSize = buffer_size;
2093 device->UpdateSize = period_size;
2094 device->Frequency = optsrate.value_or(DEFAULT_OUTPUT_RATE);
2095 device->Flags.set(FrequencyRequest, optsrate.has_value())
2096 .set(ChannelsRequest, optchans.has_value())
2097 .set(SampleTypeRequest, opttype.has_value());
2099 if(device->FmtChans == DevFmtAmbi3D)
2101 device->mAmbiOrder = clampu(aorder, 1, MaxAmbiOrder);
2102 device->mAmbiLayout = optlayout.value_or(DevAmbiLayout::Default);
2103 device->mAmbiScale = optscale.value_or(DevAmbiScaling::Default);
2104 if(device->mAmbiOrder > 3
2105 && (device->mAmbiLayout == DevAmbiLayout::FuMa
2106 || device->mAmbiScale == DevAmbiScaling::FuMa))
2108 ERR("FuMa is incompatible with %d%s order ambisonics (up to 3rd order only)\n",
2110 (((device->mAmbiOrder%100)/10) == 1) ? "th" :
2111 ((device->mAmbiOrder%10) == 1) ? "st" :
2112 ((device->mAmbiOrder%10) == 2) ? "nd" :
2113 ((device->mAmbiOrder%10) == 3) ? "rd" : "th");
2114 device->mAmbiOrder = 3;
2119 TRACE("Pre-reset: %s%s, %s%s, %s%uhz, %u / %u buffer\n",
2120 device->Flags.test(ChannelsRequest)?"*":"", DevFmtChannelsString(device->FmtChans),
2121 device->Flags.test(SampleTypeRequest)?"*":"", DevFmtTypeString(device->FmtType),
2122 device->Flags.test(FrequencyRequest)?"*":"", device->Frequency,
2123 device->UpdateSize, device->BufferSize);
2125 const uint oldFreq{device->Frequency};
2126 const DevFmtChannels oldChans{device->FmtChans};
2127 const DevFmtType oldType{device->FmtType};
2129 auto backend = device->Backend.get();
2130 if(!backend->reset())
2131 throw al::backend_exception{al::backend_error::DeviceError, "Device reset failure"};
2133 catch(std::exception &e) {
2134 ERR("Device error: %s\n", e.what());
2135 device->handleDisconnect("%s", e.what());
2136 return ALC_INVALID_DEVICE;
2139 if(device->FmtChans != oldChans && device->Flags.test(ChannelsRequest))
2141 ERR("Failed to set %s, got %s instead\n", DevFmtChannelsString(oldChans),
2142 DevFmtChannelsString(device->FmtChans));
2143 device->Flags.reset(ChannelsRequest);
2145 if(device->FmtType != oldType && device->Flags.test(SampleTypeRequest))
2147 ERR("Failed to set %s, got %s instead\n", DevFmtTypeString(oldType),
2148 DevFmtTypeString(device->FmtType));
2149 device->Flags.reset(SampleTypeRequest);
2151 if(device->Frequency != oldFreq && device->Flags.test(FrequencyRequest))
2153 WARN("Failed to set %uhz, got %uhz instead\n", oldFreq, device->Frequency);
2154 device->Flags.reset(FrequencyRequest);
2157 TRACE("Post-reset: %s, %s, %uhz, %u / %u buffer\n",
2158 DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType),
2159 device->Frequency, device->UpdateSize, device->BufferSize);
2161 if(device->Type != DeviceType::Loopback)
2163 if(auto modeopt = device->configValue<std::string>(nullptr, "stereo-mode"))
2165 const char *mode{modeopt->c_str()};
2166 if(al::strcasecmp(mode, "headphones") == 0)
2167 device->Flags.set(DirectEar);
2168 else if(al::strcasecmp(mode, "speakers") == 0)
2169 device->Flags.reset(DirectEar);
2170 else if(al::strcasecmp(mode, "auto") != 0)
2171 ERR("Unexpected stereo-mode: %s\n", mode);
2175 aluInitRenderer(device, hrtf_id, stereomode);
2177 /* Calculate the max number of sources, and split them between the mono and
2178 * stereo count given the requested number of stereo sources.
2180 if(auto srcsopt = device->configValue<uint>(nullptr, "sources"))
2182 if(*srcsopt <= 0) numMono = 256;
2183 else numMono = maxu(*srcsopt, 16);
2187 numMono = minu(numMono, INT_MAX-numStereo);
2188 numMono = maxu(numMono+numStereo, 256);
2190 numStereo = minu(numStereo, numMono);
2191 numMono -= numStereo;
2192 device->SourcesMax = numMono + numStereo;
2193 device->NumMonoSources = numMono;
2194 device->NumStereoSources = numStereo;
2196 if(auto sendsopt = device->configValue<int>(nullptr, "sends"))
2197 numSends = minu(numSends, static_cast<uint>(clampi(*sendsopt, 0, MAX_SENDS)));
2198 device->NumAuxSends = numSends;
2200 TRACE("Max sources: %d (%d + %d), effect slots: %d, sends: %d\n",
2201 device->SourcesMax, device->NumMonoSources, device->NumStereoSources,
2202 device->AuxiliaryEffectSlotMax, device->NumAuxSends);
2204 switch(device->FmtChans)
2206 case DevFmtMono: break;
2208 if(!device->mUhjEncoder)
2209 device->RealOut.RemixMap = StereoDownmix;
2211 case DevFmtQuad: device->RealOut.RemixMap = QuadDownmix; break;
2212 case DevFmtX51: device->RealOut.RemixMap = X51Downmix; break;
2213 case DevFmtX61: device->RealOut.RemixMap = X61Downmix; break;
2214 case DevFmtX71: device->RealOut.RemixMap = X71Downmix; break;
2215 case DevFmtX714: device->RealOut.RemixMap = X71Downmix; break;
2216 case DevFmtX3D71: device->RealOut.RemixMap = X51Downmix; break;
2217 case DevFmtAmbi3D: break;
2220 nanoseconds::rep sample_delay{0};
2221 if(auto *encoder{device->mUhjEncoder.get()})
2222 sample_delay += encoder->getDelay();
2224 if(device->getConfigValueBool(nullptr, "dither", true))
2226 int depth{device->configValue<int>(nullptr, "dither-depth").value_or(0)};
2229 switch(device->FmtType)
2248 depth = clampi(depth, 2, 24);
2249 device->DitherDepth = std::pow(2.0f, static_cast<float>(depth-1));
2252 if(!(device->DitherDepth > 0.0f))
2253 TRACE("Dithering disabled\n");
2255 TRACE("Dithering enabled (%d-bit, %g)\n", float2int(std::log2(device->DitherDepth)+0.5f)+1,
2256 device->DitherDepth);
2259 optlimit = device->configValue<bool>(nullptr, "output-limiter");
2261 /* If the gain limiter is unset, use the limiter for integer-based output
2262 * (where samples must be clamped), and don't for floating-point (which can
2263 * take unclamped samples).
2267 switch(device->FmtType)
2281 if(optlimit.value_or(false) == false)
2282 TRACE("Output limiter disabled\n");
2285 float thrshld{1.0f};
2286 switch(device->FmtType)
2290 thrshld = 127.0f / 128.0f;
2294 thrshld = 32767.0f / 32768.0f;
2301 if(device->DitherDepth > 0.0f)
2302 thrshld -= 1.0f / device->DitherDepth;
2304 const float thrshld_dB{std::log10(thrshld) * 20.0f};
2305 auto limiter = CreateDeviceLimiter(device, thrshld_dB);
2307 sample_delay += limiter->getLookAhead();
2308 device->Limiter = std::move(limiter);
2309 TRACE("Output limiter enabled, %.4fdB limit\n", thrshld_dB);
2312 /* Convert the sample delay from samples to nanosamples to nanoseconds. */
2313 device->FixedLatency += nanoseconds{seconds{sample_delay}} / device->Frequency;
2314 TRACE("Fixed device latency: %" PRId64 "ns\n", int64_t{device->FixedLatency.count()});
2316 FPUCtl mixer_mode{};
2317 for(ContextBase *ctxbase : *device->mContexts.load())
2319 auto *context = static_cast<ALCcontext*>(ctxbase);
2321 std::unique_lock<std::mutex> proplock{context->mPropLock};
2322 std::unique_lock<std::mutex> slotlock{context->mEffectSlotLock};
2324 /* Clear out unused effect slot clusters. */
2325 auto slot_cluster_not_in_use = [](ContextBase::EffectSlotCluster &cluster)
2327 for(size_t i{0};i < ContextBase::EffectSlotClusterSize;++i)
2329 if(cluster[i].InUse)
2334 auto slotcluster_iter = std::remove_if(context->mEffectSlotClusters.begin(),
2335 context->mEffectSlotClusters.end(), slot_cluster_not_in_use);
2336 context->mEffectSlotClusters.erase(slotcluster_iter, context->mEffectSlotClusters.end());
2338 /* Free all wet buffers. Any in use will be reallocated with an updated
2339 * configuration in aluInitEffectPanning.
2341 for(auto&& slots : context->mEffectSlotClusters)
2343 for(size_t i{0};i < ContextBase::EffectSlotClusterSize;++i)
2345 slots[i].mWetBuffer.clear();
2346 slots[i].mWetBuffer.shrink_to_fit();
2347 slots[i].Wet.Buffer = {};
2351 if(ALeffectslot *slot{context->mDefaultSlot.get()})
2353 aluInitEffectPanning(slot->mSlot, context);
2355 EffectState *state{slot->Effect.State.get()};
2356 state->mOutTarget = device->Dry.Buffer;
2357 state->deviceUpdate(device, slot->Buffer);
2358 slot->updateProps(context);
2361 if(EffectSlotArray *curarray{context->mActiveAuxSlots.load(std::memory_order_relaxed)})
2362 std::fill_n(curarray->end(), curarray->size(), nullptr);
2363 for(auto &sublist : context->mEffectSlotList)
2365 uint64_t usemask{~sublist.FreeMask};
2368 const int idx{al::countr_zero(usemask)};
2369 ALeffectslot *slot{sublist.EffectSlots + idx};
2370 usemask &= ~(1_u64 << idx);
2372 aluInitEffectPanning(slot->mSlot, context);
2374 EffectState *state{slot->Effect.State.get()};
2375 state->mOutTarget = device->Dry.Buffer;
2376 state->deviceUpdate(device, slot->Buffer);
2377 slot->updateProps(context);
2382 const uint num_sends{device->NumAuxSends};
2383 std::unique_lock<std::mutex> srclock{context->mSourceLock};
2384 for(auto &sublist : context->mSourceList)
2386 uint64_t usemask{~sublist.FreeMask};
2389 const int idx{al::countr_zero(usemask)};
2390 ALsource *source{sublist.Sources + idx};
2391 usemask &= ~(1_u64 << idx);
2393 auto clear_send = [](ALsource::SendData &send) -> void
2396 DecrementRef(send.Slot->ref);
2397 send.Slot = nullptr;
2400 send.HFReference = LOWPASSFREQREF;
2402 send.LFReference = HIGHPASSFREQREF;
2404 auto send_begin = source->Send.begin() + static_cast<ptrdiff_t>(num_sends);
2405 std::for_each(send_begin, source->Send.end(), clear_send);
2407 source->mPropsDirty = true;
2411 auto voicelist = context->getVoicesSpan();
2412 for(Voice *voice : voicelist)
2414 /* Clear extraneous property set sends. */
2415 std::fill(std::begin(voice->mProps.Send)+num_sends, std::end(voice->mProps.Send),
2416 VoiceProps::SendData{});
2418 std::fill(voice->mSend.begin()+num_sends, voice->mSend.end(), Voice::TargetData{});
2419 for(auto &chandata : voice->mChans)
2421 std::fill(chandata.mWetParams.begin()+num_sends, chandata.mWetParams.end(),
2425 if(VoicePropsItem *props{voice->mUpdate.exchange(nullptr, std::memory_order_relaxed)})
2426 AtomicReplaceHead(context->mFreeVoiceProps, props);
2428 /* Force the voice to stopped if it was stopping. */
2429 Voice::State vstate{Voice::Stopping};
2430 voice->mPlayState.compare_exchange_strong(vstate, Voice::Stopped,
2431 std::memory_order_acquire, std::memory_order_acquire);
2432 if(voice->mSourceID.load(std::memory_order_relaxed) == 0u)
2435 voice->prepare(device);
2437 /* Clear all voice props to let them get allocated again. */
2438 context->mVoicePropClusters.clear();
2439 context->mFreeVoiceProps.store(nullptr, std::memory_order_relaxed);
2442 context->mPropsDirty = false;
2443 UpdateContextProps(context);
2444 UpdateAllSourceProps(context);
2448 if(!device->Flags.test(DevicePaused))
2451 auto backend = device->Backend.get();
2453 device->Flags.set(DeviceRunning);
2455 catch(al::backend_exception& e) {
2456 ERR("%s\n", e.what());
2457 device->handleDisconnect("%s", e.what());
2458 return ALC_INVALID_DEVICE;
2460 TRACE("Post-start: %s, %s, %uhz, %u / %u buffer\n",
2461 DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType),
2462 device->Frequency, device->UpdateSize, device->BufferSize);
2465 return ALC_NO_ERROR;
2469 * Updates device parameters as above, and also first clears the disconnected
2472 bool ResetDeviceParams(ALCdevice *device, const int *attrList)
2474 /* If the device was disconnected, reset it since we're opened anew. */
2475 if(!device->Connected.load(std::memory_order_relaxed)) UNLIKELY
2477 /* Make sure disconnection is finished before continuing on. */
2478 device->waitForMix();
2480 for(ContextBase *ctxbase : *device->mContexts.load(std::memory_order_acquire))
2482 auto *ctx = static_cast<ALCcontext*>(ctxbase);
2483 if(!ctx->mStopVoicesOnDisconnect.load(std::memory_order_acquire))
2486 /* Clear any pending voice changes and reallocate voices to get a
2489 std::lock_guard<std::mutex> __{ctx->mSourceLock};
2490 auto *vchg = ctx->mCurrentVoiceChange.load(std::memory_order_acquire);
2491 while(auto *next = vchg->mNext.load(std::memory_order_acquire))
2493 ctx->mCurrentVoiceChange.store(vchg, std::memory_order_release);
2495 ctx->mVoicePropClusters.clear();
2496 ctx->mFreeVoiceProps.store(nullptr, std::memory_order_relaxed);
2498 ctx->mVoiceClusters.clear();
2499 ctx->allocVoices(std::max<size_t>(256,
2500 ctx->mActiveVoiceCount.load(std::memory_order_relaxed)));
2503 device->Connected.store(true);
2506 ALCenum err{UpdateDeviceParams(device, attrList)};
2507 if(err == ALC_NO_ERROR) LIKELY return ALC_TRUE;
2509 alcSetError(device, err);
2514 /** Checks if the device handle is valid, and returns a new reference if so. */
2515 DeviceRef VerifyDevice(ALCdevice *device)
2517 std::lock_guard<std::recursive_mutex> _{ListLock};
2518 auto iter = std::lower_bound(DeviceList.begin(), DeviceList.end(), device);
2519 if(iter != DeviceList.end() && *iter == device)
2522 return DeviceRef{*iter};
2529 * Checks if the given context is valid, returning a new reference to it if so.
2531 ContextRef VerifyContext(ALCcontext *context)
2533 std::lock_guard<std::recursive_mutex> _{ListLock};
2534 auto iter = std::lower_bound(ContextList.begin(), ContextList.end(), context);
2535 if(iter != ContextList.end() && *iter == context)
2538 return ContextRef{*iter};
2545 /** Returns a new reference to the currently active context for this thread. */
2546 ContextRef GetContextRef(void)
2548 ALCcontext *context{ALCcontext::getThreadContext()};
2553 while(ALCcontext::sGlobalContextLock.exchange(true, std::memory_order_acquire)) {
2554 /* Wait to make sure another thread isn't trying to change the
2555 * current context and bring its refcount to 0.
2558 context = ALCcontext::sGlobalContext.load(std::memory_order_acquire);
2559 if(context) LIKELY context->add_ref();
2560 ALCcontext::sGlobalContextLock.store(false, std::memory_order_release);
2562 return ContextRef{context};
2566 /************************************************
2567 * Standard ALC functions
2568 ************************************************/
2570 ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device)
2573 DeviceRef dev{VerifyDevice(device)};
2574 if(dev) return dev->LastError.exchange(ALC_NO_ERROR);
2575 return LastNullDeviceError.exchange(ALC_NO_ERROR);
2580 ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context)
2586 ContextRef ctx{VerifyContext(context)};
2588 alcSetError(nullptr, ALC_INVALID_CONTEXT);
2591 std::lock_guard<std::mutex> _{ctx->mPropLock};
2592 ctx->deferUpdates();
2597 ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context)
2603 ContextRef ctx{VerifyContext(context)};
2605 alcSetError(nullptr, ALC_INVALID_CONTEXT);
2608 std::lock_guard<std::mutex> _{ctx->mPropLock};
2609 ctx->processUpdates();
2615 ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum param)
2618 const ALCchar *value{nullptr};
2626 case ALC_INVALID_ENUM:
2627 value = alcErrInvalidEnum;
2630 case ALC_INVALID_VALUE:
2631 value = alcErrInvalidValue;
2634 case ALC_INVALID_DEVICE:
2635 value = alcErrInvalidDevice;
2638 case ALC_INVALID_CONTEXT:
2639 value = alcErrInvalidContext;
2642 case ALC_OUT_OF_MEMORY:
2643 value = alcErrOutOfMemory;
2646 case ALC_DEVICE_SPECIFIER:
2647 value = alcDefaultName;
2650 case ALC_ALL_DEVICES_SPECIFIER:
2651 if(DeviceRef dev{VerifyDevice(Device)})
2653 if(dev->Type == DeviceType::Capture)
2654 alcSetError(dev.get(), ALC_INVALID_ENUM);
2655 else if(dev->Type == DeviceType::Loopback)
2656 value = alcDefaultName;
2659 std::lock_guard<std::mutex> _{dev->StateLock};
2660 value = dev->DeviceName.c_str();
2665 ProbeAllDevicesList();
2666 value = alcAllDevicesList.c_str();
2670 case ALC_CAPTURE_DEVICE_SPECIFIER:
2671 if(DeviceRef dev{VerifyDevice(Device)})
2673 if(dev->Type != DeviceType::Capture)
2674 alcSetError(dev.get(), ALC_INVALID_ENUM);
2677 std::lock_guard<std::mutex> _{dev->StateLock};
2678 value = dev->DeviceName.c_str();
2683 ProbeCaptureDeviceList();
2684 value = alcCaptureDeviceList.c_str();
2688 /* Default devices are always first in the list */
2689 case ALC_DEFAULT_DEVICE_SPECIFIER:
2690 value = alcDefaultName;
2693 case ALC_DEFAULT_ALL_DEVICES_SPECIFIER:
2694 if(alcAllDevicesList.empty())
2695 ProbeAllDevicesList();
2697 /* Copy first entry as default. */
2698 alcDefaultAllDevicesSpecifier = alcAllDevicesList.c_str();
2699 value = alcDefaultAllDevicesSpecifier.c_str();
2702 case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER:
2703 if(alcCaptureDeviceList.empty())
2704 ProbeCaptureDeviceList();
2706 /* Copy first entry as default. */
2707 alcCaptureDefaultDeviceSpecifier = alcCaptureDeviceList.c_str();
2708 value = alcCaptureDefaultDeviceSpecifier.c_str();
2711 case ALC_EXTENSIONS:
2712 if(VerifyDevice(Device))
2713 value = alcExtensionList;
2715 value = alcNoDeviceExtList;
2718 case ALC_HRTF_SPECIFIER_SOFT:
2719 if(DeviceRef dev{VerifyDevice(Device)})
2721 std::lock_guard<std::mutex> _{dev->StateLock};
2722 value = (dev->mHrtf ? dev->mHrtfName.c_str() : "");
2725 alcSetError(nullptr, ALC_INVALID_DEVICE);
2729 alcSetError(VerifyDevice(Device).get(), ALC_INVALID_ENUM);
2738 static size_t GetIntegerv(ALCdevice *device, ALCenum param, const al::span<int> values)
2744 alcSetError(device, ALC_INVALID_VALUE);
2752 case ALC_MAJOR_VERSION:
2753 values[0] = alcMajorVersion;
2755 case ALC_MINOR_VERSION:
2756 values[0] = alcMinorVersion;
2759 case ALC_EFX_MAJOR_VERSION:
2760 values[0] = alcEFXMajorVersion;
2762 case ALC_EFX_MINOR_VERSION:
2763 values[0] = alcEFXMinorVersion;
2765 case ALC_MAX_AUXILIARY_SENDS:
2766 values[0] = MAX_SENDS;
2769 case ALC_ATTRIBUTES_SIZE:
2770 case ALC_ALL_ATTRIBUTES:
2774 case ALC_MONO_SOURCES:
2775 case ALC_STEREO_SOURCES:
2776 case ALC_CAPTURE_SAMPLES:
2777 case ALC_FORMAT_CHANNELS_SOFT:
2778 case ALC_FORMAT_TYPE_SOFT:
2779 case ALC_AMBISONIC_LAYOUT_SOFT:
2780 case ALC_AMBISONIC_SCALING_SOFT:
2781 case ALC_AMBISONIC_ORDER_SOFT:
2782 case ALC_MAX_AMBISONIC_ORDER_SOFT:
2783 alcSetError(nullptr, ALC_INVALID_DEVICE);
2787 alcSetError(nullptr, ALC_INVALID_ENUM);
2792 std::lock_guard<std::mutex> _{device->StateLock};
2793 if(device->Type == DeviceType::Capture)
2795 static constexpr int MaxCaptureAttributes{9};
2798 case ALC_ATTRIBUTES_SIZE:
2799 values[0] = MaxCaptureAttributes;
2801 case ALC_ALL_ATTRIBUTES:
2803 if(values.size() < MaxCaptureAttributes)
2804 alcSetError(device, ALC_INVALID_VALUE);
2807 values[i++] = ALC_MAJOR_VERSION;
2808 values[i++] = alcMajorVersion;
2809 values[i++] = ALC_MINOR_VERSION;
2810 values[i++] = alcMinorVersion;
2811 values[i++] = ALC_CAPTURE_SAMPLES;
2812 values[i++] = static_cast<int>(device->Backend->availableSamples());
2813 values[i++] = ALC_CONNECTED;
2814 values[i++] = device->Connected.load(std::memory_order_relaxed);
2816 assert(i == MaxCaptureAttributes);
2820 case ALC_MAJOR_VERSION:
2821 values[0] = alcMajorVersion;
2823 case ALC_MINOR_VERSION:
2824 values[0] = alcMinorVersion;
2827 case ALC_CAPTURE_SAMPLES:
2828 values[0] = static_cast<int>(device->Backend->availableSamples());
2832 values[0] = device->Connected.load(std::memory_order_acquire);
2836 alcSetError(device, ALC_INVALID_ENUM);
2842 auto NumAttrsForDevice = [](ALCdevice *aldev) noexcept
2844 if(aldev->Type == DeviceType::Loopback && aldev->FmtChans == DevFmtAmbi3D)
2850 case ALC_ATTRIBUTES_SIZE:
2851 values[0] = NumAttrsForDevice(device);
2854 case ALC_ALL_ATTRIBUTES:
2856 if(values.size() < static_cast<size_t>(NumAttrsForDevice(device)))
2857 alcSetError(device, ALC_INVALID_VALUE);
2860 values[i++] = ALC_MAJOR_VERSION;
2861 values[i++] = alcMajorVersion;
2862 values[i++] = ALC_MINOR_VERSION;
2863 values[i++] = alcMinorVersion;
2864 values[i++] = ALC_EFX_MAJOR_VERSION;
2865 values[i++] = alcEFXMajorVersion;
2866 values[i++] = ALC_EFX_MINOR_VERSION;
2867 values[i++] = alcEFXMinorVersion;
2869 values[i++] = ALC_FREQUENCY;
2870 values[i++] = static_cast<int>(device->Frequency);
2871 if(device->Type != DeviceType::Loopback)
2873 values[i++] = ALC_REFRESH;
2874 values[i++] = static_cast<int>(device->Frequency / device->UpdateSize);
2876 values[i++] = ALC_SYNC;
2877 values[i++] = ALC_FALSE;
2881 if(device->FmtChans == DevFmtAmbi3D)
2883 values[i++] = ALC_AMBISONIC_LAYOUT_SOFT;
2884 values[i++] = EnumFromDevAmbi(device->mAmbiLayout);
2886 values[i++] = ALC_AMBISONIC_SCALING_SOFT;
2887 values[i++] = EnumFromDevAmbi(device->mAmbiScale);
2889 values[i++] = ALC_AMBISONIC_ORDER_SOFT;
2890 values[i++] = static_cast<int>(device->mAmbiOrder);
2893 values[i++] = ALC_FORMAT_CHANNELS_SOFT;
2894 values[i++] = EnumFromDevFmt(device->FmtChans);
2896 values[i++] = ALC_FORMAT_TYPE_SOFT;
2897 values[i++] = EnumFromDevFmt(device->FmtType);
2900 values[i++] = ALC_MONO_SOURCES;
2901 values[i++] = static_cast<int>(device->NumMonoSources);
2903 values[i++] = ALC_STEREO_SOURCES;
2904 values[i++] = static_cast<int>(device->NumStereoSources);
2906 values[i++] = ALC_MAX_AUXILIARY_SENDS;
2907 values[i++] = static_cast<int>(device->NumAuxSends);
2909 values[i++] = ALC_HRTF_SOFT;
2910 values[i++] = (device->mHrtf ? ALC_TRUE : ALC_FALSE);
2912 values[i++] = ALC_HRTF_STATUS_SOFT;
2913 values[i++] = device->mHrtfStatus;
2915 values[i++] = ALC_OUTPUT_LIMITER_SOFT;
2916 values[i++] = device->Limiter ? ALC_TRUE : ALC_FALSE;
2918 values[i++] = ALC_MAX_AMBISONIC_ORDER_SOFT;
2919 values[i++] = MaxAmbiOrder;
2921 values[i++] = ALC_OUTPUT_MODE_SOFT;
2922 values[i++] = static_cast<ALCenum>(device->getOutputMode1());
2928 case ALC_MAJOR_VERSION:
2929 values[0] = alcMajorVersion;
2932 case ALC_MINOR_VERSION:
2933 values[0] = alcMinorVersion;
2936 case ALC_EFX_MAJOR_VERSION:
2937 values[0] = alcEFXMajorVersion;
2940 case ALC_EFX_MINOR_VERSION:
2941 values[0] = alcEFXMinorVersion;
2945 values[0] = static_cast<int>(device->Frequency);
2949 if(device->Type == DeviceType::Loopback)
2951 alcSetError(device, ALC_INVALID_DEVICE);
2954 values[0] = static_cast<int>(device->Frequency / device->UpdateSize);
2958 if(device->Type == DeviceType::Loopback)
2960 alcSetError(device, ALC_INVALID_DEVICE);
2963 values[0] = ALC_FALSE;
2966 case ALC_FORMAT_CHANNELS_SOFT:
2967 if(device->Type != DeviceType::Loopback)
2969 alcSetError(device, ALC_INVALID_DEVICE);
2972 values[0] = EnumFromDevFmt(device->FmtChans);
2975 case ALC_FORMAT_TYPE_SOFT:
2976 if(device->Type != DeviceType::Loopback)
2978 alcSetError(device, ALC_INVALID_DEVICE);
2981 values[0] = EnumFromDevFmt(device->FmtType);
2984 case ALC_AMBISONIC_LAYOUT_SOFT:
2985 if(device->Type != DeviceType::Loopback || device->FmtChans != DevFmtAmbi3D)
2987 alcSetError(device, ALC_INVALID_DEVICE);
2990 values[0] = EnumFromDevAmbi(device->mAmbiLayout);
2993 case ALC_AMBISONIC_SCALING_SOFT:
2994 if(device->Type != DeviceType::Loopback || device->FmtChans != DevFmtAmbi3D)
2996 alcSetError(device, ALC_INVALID_DEVICE);
2999 values[0] = EnumFromDevAmbi(device->mAmbiScale);
3002 case ALC_AMBISONIC_ORDER_SOFT:
3003 if(device->Type != DeviceType::Loopback || device->FmtChans != DevFmtAmbi3D)
3005 alcSetError(device, ALC_INVALID_DEVICE);
3008 values[0] = static_cast<int>(device->mAmbiOrder);
3011 case ALC_MONO_SOURCES:
3012 values[0] = static_cast<int>(device->NumMonoSources);
3015 case ALC_STEREO_SOURCES:
3016 values[0] = static_cast<int>(device->NumStereoSources);
3019 case ALC_MAX_AUXILIARY_SENDS:
3020 values[0] = static_cast<int>(device->NumAuxSends);
3024 values[0] = device->Connected.load(std::memory_order_acquire);
3028 values[0] = (device->mHrtf ? ALC_TRUE : ALC_FALSE);
3031 case ALC_HRTF_STATUS_SOFT:
3032 values[0] = device->mHrtfStatus;
3035 case ALC_NUM_HRTF_SPECIFIERS_SOFT:
3036 device->enumerateHrtfs();
3037 values[0] = static_cast<int>(minz(device->mHrtfList.size(),
3038 std::numeric_limits<int>::max()));
3041 case ALC_OUTPUT_LIMITER_SOFT:
3042 values[0] = device->Limiter ? ALC_TRUE : ALC_FALSE;
3045 case ALC_MAX_AMBISONIC_ORDER_SOFT:
3046 values[0] = MaxAmbiOrder;
3049 case ALC_OUTPUT_MODE_SOFT:
3050 values[0] = static_cast<ALCenum>(device->getOutputMode1());
3054 alcSetError(device, ALC_INVALID_ENUM);
3059 ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values)
3062 DeviceRef dev{VerifyDevice(device)};
3063 if(size <= 0 || values == nullptr)
3064 alcSetError(dev.get(), ALC_INVALID_VALUE);
3066 GetIntegerv(dev.get(), param, {values, static_cast<uint>(size)});
3070 ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, ALCsizei size, ALCint64SOFT *values)
3073 DeviceRef dev{VerifyDevice(device)};
3074 if(size <= 0 || values == nullptr)
3076 alcSetError(dev.get(), ALC_INVALID_VALUE);
3079 if(!dev || dev->Type == DeviceType::Capture)
3081 auto ivals = al::vector<int>(static_cast<uint>(size));
3082 if(size_t got{GetIntegerv(dev.get(), pname, ivals)})
3083 std::copy_n(ivals.begin(), got, values);
3087 auto NumAttrsForDevice = [](ALCdevice *aldev) noexcept
3089 if(aldev->Type == DeviceType::Loopback && aldev->FmtChans == DevFmtAmbi3D)
3093 std::lock_guard<std::mutex> _{dev->StateLock};
3096 case ALC_ATTRIBUTES_SIZE:
3097 *values = NumAttrsForDevice(dev.get());
3100 case ALC_ALL_ATTRIBUTES:
3101 if(size < NumAttrsForDevice(dev.get()))
3102 alcSetError(dev.get(), ALC_INVALID_VALUE);
3106 values[i++] = ALC_FREQUENCY;
3107 values[i++] = dev->Frequency;
3109 if(dev->Type != DeviceType::Loopback)
3111 values[i++] = ALC_REFRESH;
3112 values[i++] = dev->Frequency / dev->UpdateSize;
3114 values[i++] = ALC_SYNC;
3115 values[i++] = ALC_FALSE;
3119 values[i++] = ALC_FORMAT_CHANNELS_SOFT;
3120 values[i++] = EnumFromDevFmt(dev->FmtChans);
3122 values[i++] = ALC_FORMAT_TYPE_SOFT;
3123 values[i++] = EnumFromDevFmt(dev->FmtType);
3125 if(dev->FmtChans == DevFmtAmbi3D)
3127 values[i++] = ALC_AMBISONIC_LAYOUT_SOFT;
3128 values[i++] = EnumFromDevAmbi(dev->mAmbiLayout);
3130 values[i++] = ALC_AMBISONIC_SCALING_SOFT;
3131 values[i++] = EnumFromDevAmbi(dev->mAmbiScale);
3133 values[i++] = ALC_AMBISONIC_ORDER_SOFT;
3134 values[i++] = dev->mAmbiOrder;
3138 values[i++] = ALC_MONO_SOURCES;
3139 values[i++] = dev->NumMonoSources;
3141 values[i++] = ALC_STEREO_SOURCES;
3142 values[i++] = dev->NumStereoSources;
3144 values[i++] = ALC_MAX_AUXILIARY_SENDS;
3145 values[i++] = dev->NumAuxSends;
3147 values[i++] = ALC_HRTF_SOFT;
3148 values[i++] = (dev->mHrtf ? ALC_TRUE : ALC_FALSE);
3150 values[i++] = ALC_HRTF_STATUS_SOFT;
3151 values[i++] = dev->mHrtfStatus;
3153 values[i++] = ALC_OUTPUT_LIMITER_SOFT;
3154 values[i++] = dev->Limiter ? ALC_TRUE : ALC_FALSE;
3156 ClockLatency clock{GetClockLatency(dev.get(), dev->Backend.get())};
3157 values[i++] = ALC_DEVICE_CLOCK_SOFT;
3158 values[i++] = clock.ClockTime.count();
3160 values[i++] = ALC_DEVICE_LATENCY_SOFT;
3161 values[i++] = clock.Latency.count();
3163 values[i++] = ALC_OUTPUT_MODE_SOFT;
3164 values[i++] = static_cast<ALCenum>(device->getOutputMode1());
3170 case ALC_DEVICE_CLOCK_SOFT:
3172 uint samplecount, refcount;
3173 nanoseconds basecount;
3175 refcount = dev->waitForMix();
3176 basecount = dev->ClockBase;
3177 samplecount = dev->SamplesDone;
3178 } while(refcount != ReadRef(dev->MixCount));
3179 basecount += nanoseconds{seconds{samplecount}} / dev->Frequency;
3180 *values = basecount.count();
3184 case ALC_DEVICE_LATENCY_SOFT:
3185 *values = GetClockLatency(dev.get(), dev->Backend.get()).Latency.count();
3188 case ALC_DEVICE_CLOCK_LATENCY_SOFT:
3190 alcSetError(dev.get(), ALC_INVALID_VALUE);
3193 ClockLatency clock{GetClockLatency(dev.get(), dev->Backend.get())};
3194 values[0] = clock.ClockTime.count();
3195 values[1] = clock.Latency.count();
3200 auto ivals = al::vector<int>(static_cast<uint>(size));
3201 if(size_t got{GetIntegerv(dev.get(), pname, ivals)})
3202 std::copy_n(ivals.begin(), got, values);
3209 ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extName)
3212 DeviceRef dev{VerifyDevice(device)};
3214 alcSetError(dev.get(), ALC_INVALID_VALUE);
3217 size_t len = strlen(extName);
3218 const char *ptr = (dev ? alcExtensionList : alcNoDeviceExtList);
3221 if(al::strncasecmp(ptr, extName, len) == 0 && (ptr[len] == '\0' || isspace(ptr[len])))
3224 if((ptr=strchr(ptr, ' ')) != nullptr)
3228 } while(isspace(*ptr));
3237 ALC_API ALCvoid* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcName)
3242 DeviceRef dev{VerifyDevice(device)};
3243 alcSetError(dev.get(), ALC_INVALID_VALUE);
3247 if(eax_g_is_enabled)
3249 for(const auto &func : eaxFunctions)
3251 if(strcmp(func.funcName, funcName) == 0)
3252 return func.address;
3256 for(const auto &func : alcFunctions)
3258 if(strcmp(func.funcName, funcName) == 0)
3259 return func.address;
3266 ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumName)
3271 DeviceRef dev{VerifyDevice(device)};
3272 alcSetError(dev.get(), ALC_INVALID_VALUE);
3276 if(eax_g_is_enabled)
3278 for(const auto &enm : eaxEnumerations)
3280 if(strcmp(enm.enumName, enumName) == 0)
3285 for(const auto &enm : alcEnumerations)
3287 if(strcmp(enm.enumName, enumName) == 0)
3296 ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrList)
3299 /* Explicitly hold the list lock while taking the StateLock in case the
3300 * device is asynchronously destroyed, to ensure this new context is
3301 * properly cleaned up after being made.
3303 std::unique_lock<std::recursive_mutex> listlock{ListLock};
3304 DeviceRef dev{VerifyDevice(device)};
3305 if(!dev || dev->Type == DeviceType::Capture || !dev->Connected.load(std::memory_order_relaxed))
3308 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3311 std::unique_lock<std::mutex> statelock{dev->StateLock};
3314 dev->LastError.store(ALC_NO_ERROR);
3316 ALCenum err{UpdateDeviceParams(dev.get(), attrList)};
3317 if(err != ALC_NO_ERROR)
3319 alcSetError(dev.get(), err);
3323 ContextRef context{new ALCcontext{dev}};
3326 if(auto volopt = dev->configValue<float>(nullptr, "volume-adjust"))
3328 const float valf{*volopt};
3329 if(!std::isfinite(valf))
3330 ERR("volume-adjust must be finite: %f\n", valf);
3333 const float db{clampf(valf, -24.0f, 24.0f)};
3335 WARN("volume-adjust clamped: %f, range: +/-%f\n", valf, 24.0f);
3336 context->mGainBoost = std::pow(10.0f, db/20.0f);
3337 TRACE("volume-adjust gain: %f\n", context->mGainBoost);
3342 using ContextArray = al::FlexArray<ContextBase*>;
3344 /* Allocate a new context array, which holds 1 more than the current/
3347 auto *oldarray = device->mContexts.load();
3348 const size_t newcount{oldarray->size()+1};
3349 std::unique_ptr<ContextArray> newarray{ContextArray::Create(newcount)};
3351 /* Copy the current/old context handles to the new array, appending the
3354 auto iter = std::copy(oldarray->begin(), oldarray->end(), newarray->begin());
3355 *iter = context.get();
3357 /* Store the new context array in the device. Wait for any current mix
3358 * to finish before deleting the old array.
3360 dev->mContexts.store(newarray.release());
3361 if(oldarray != &DeviceBase::sEmptyContextArray)
3370 std::lock_guard<std::recursive_mutex> _{ListLock};
3371 auto iter = std::lower_bound(ContextList.cbegin(), ContextList.cend(), context.get());
3372 ContextList.emplace(iter, context.get());
3375 if(ALeffectslot *slot{context->mDefaultSlot.get()})
3377 ALenum sloterr{slot->initEffect(ALCcontext::sDefaultEffect.type,
3378 ALCcontext::sDefaultEffect.Props, context.get())};
3379 if(sloterr == AL_NO_ERROR)
3380 slot->updateProps(context.get());
3382 ERR("Failed to initialize the default effect\n");
3385 TRACE("Created context %p\n", voidp{context.get()});
3386 return context.release();
3390 ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context)
3393 std::unique_lock<std::recursive_mutex> listlock{ListLock};
3394 auto iter = std::lower_bound(ContextList.begin(), ContextList.end(), context);
3395 if(iter == ContextList.end() || *iter != context)
3398 alcSetError(nullptr, ALC_INVALID_CONTEXT);
3402 /* Hold a reference to this context so it remains valid until the ListLock
3405 ContextRef ctx{*iter};
3406 ContextList.erase(iter);
3408 ALCdevice *Device{ctx->mALDevice.get()};
3410 std::lock_guard<std::mutex> _{Device->StateLock};
3411 if(!ctx->deinit() && Device->Flags.test(DeviceRunning))
3413 Device->Backend->stop();
3414 Device->Flags.reset(DeviceRunning);
3420 ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void)
3423 ALCcontext *Context{ALCcontext::getThreadContext()};
3424 if(!Context) Context = ALCcontext::sGlobalContext.load();
3429 /** Returns the currently active thread-local context. */
3430 ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void)
3432 { return ALCcontext::getThreadContext(); }
3435 ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context)
3438 /* context must be valid or nullptr */
3442 ctx = VerifyContext(context);
3445 alcSetError(nullptr, ALC_INVALID_CONTEXT);
3449 /* Release this reference (if any) to store it in the GlobalContext
3450 * pointer. Take ownership of the reference (if any) that was previously
3451 * stored there, and let the reference go.
3453 while(ALCcontext::sGlobalContextLock.exchange(true, std::memory_order_acquire)) {
3454 /* Wait to make sure another thread isn't getting or trying to change
3455 * the current context as its refcount is decremented.
3458 ContextRef{ALCcontext::sGlobalContext.exchange(ctx.release())};
3459 ALCcontext::sGlobalContextLock.store(false, std::memory_order_release);
3461 /* Take ownership of the thread-local context reference (if any), clearing
3462 * the storage to null.
3464 ctx = ContextRef{ALCcontext::getThreadContext()};
3465 if(ctx) ALCcontext::setThreadContext(nullptr);
3466 /* Reset (decrement) the previous thread-local reference. */
3472 /** Makes the given context the active context for the current thread. */
3473 ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context)
3476 /* context must be valid or nullptr */
3480 ctx = VerifyContext(context);
3483 alcSetError(nullptr, ALC_INVALID_CONTEXT);
3487 /* context's reference count is already incremented */
3488 ContextRef old{ALCcontext::getThreadContext()};
3489 ALCcontext::setThreadContext(ctx.release());
3496 ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *Context)
3499 ContextRef ctx{VerifyContext(Context)};
3502 alcSetError(nullptr, ALC_INVALID_CONTEXT);
3505 return ctx->mALDevice.get();
3510 ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
3515 if(!PlaybackFactory)
3517 alcSetError(nullptr, ALC_INVALID_VALUE);
3523 TRACE("Opening playback device \"%s\"\n", deviceName);
3524 if(!deviceName[0] || al::strcasecmp(deviceName, alcDefaultName) == 0
3526 /* Some old Windows apps hardcode these expecting OpenAL to use a
3527 * specific audio API, even when they're not enumerated. Creative's
3528 * router effectively ignores them too.
3530 || al::strcasecmp(deviceName, "DirectSound3D") == 0
3531 || al::strcasecmp(deviceName, "DirectSound") == 0
3532 || al::strcasecmp(deviceName, "MMSYSTEM") == 0
3534 /* Some old Linux apps hardcode configuration strings that were
3535 * supported by the OpenAL SI. We can't really do anything useful
3536 * with them, so just ignore.
3538 || (deviceName[0] == '\'' && deviceName[1] == '(')
3539 || al::strcasecmp(deviceName, "openal-soft") == 0)
3540 deviceName = nullptr;
3543 TRACE("Opening default playback device\n");
3545 const uint DefaultSends{
3547 eax_g_is_enabled ? uint{EAX_MAX_FXSLOTS} :
3548 #endif // ALSOFT_EAX
3552 DeviceRef device{new ALCdevice{DeviceType::Playback}};
3554 /* Set output format */
3555 device->FmtChans = DevFmtChannelsDefault;
3556 device->FmtType = DevFmtTypeDefault;
3557 device->Frequency = DEFAULT_OUTPUT_RATE;
3558 device->UpdateSize = DEFAULT_UPDATE_SIZE;
3559 device->BufferSize = DEFAULT_UPDATE_SIZE * DEFAULT_NUM_UPDATES;
3561 device->SourcesMax = 256;
3562 device->NumStereoSources = 1;
3563 device->NumMonoSources = device->SourcesMax - device->NumStereoSources;
3564 device->AuxiliaryEffectSlotMax = 64;
3565 device->NumAuxSends = DefaultSends;
3568 auto backend = PlaybackFactory->createBackend(device.get(), BackendType::Playback);
3569 std::lock_guard<std::recursive_mutex> _{ListLock};
3570 backend->open(deviceName);
3571 device->Backend = std::move(backend);
3573 catch(al::backend_exception &e) {
3574 WARN("Failed to open playback device: %s\n", e.what());
3575 alcSetError(nullptr, (e.errorCode() == al::backend_error::OutOfMemory)
3576 ? ALC_OUT_OF_MEMORY : ALC_INVALID_VALUE);
3581 std::lock_guard<std::recursive_mutex> _{ListLock};
3582 auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get());
3583 DeviceList.emplace(iter, device.get());
3586 TRACE("Created device %p, \"%s\"\n", voidp{device.get()}, device->DeviceName.c_str());
3587 return device.release();
3591 ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device)
3594 std::unique_lock<std::recursive_mutex> listlock{ListLock};
3595 auto iter = std::lower_bound(DeviceList.begin(), DeviceList.end(), device);
3596 if(iter == DeviceList.end() || *iter != device)
3598 alcSetError(nullptr, ALC_INVALID_DEVICE);
3601 if((*iter)->Type == DeviceType::Capture)
3603 alcSetError(*iter, ALC_INVALID_DEVICE);
3607 /* Erase the device, and any remaining contexts left on it, from their
3610 DeviceRef dev{*iter};
3611 DeviceList.erase(iter);
3613 std::unique_lock<std::mutex> statelock{dev->StateLock};
3614 al::vector<ContextRef> orphanctxs;
3615 for(ContextBase *ctx : *dev->mContexts.load())
3617 auto ctxiter = std::lower_bound(ContextList.begin(), ContextList.end(), ctx);
3618 if(ctxiter != ContextList.end() && *ctxiter == ctx)
3620 orphanctxs.emplace_back(ContextRef{*ctxiter});
3621 ContextList.erase(ctxiter);
3626 for(ContextRef &context : orphanctxs)
3628 WARN("Releasing orphaned context %p\n", voidp{context.get()});
3633 if(dev->Flags.test(DeviceRunning))
3634 dev->Backend->stop();
3635 dev->Flags.reset(DeviceRunning);
3642 /************************************************
3643 * ALC capture functions
3644 ************************************************/
3645 ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei samples)
3652 alcSetError(nullptr, ALC_INVALID_VALUE);
3658 alcSetError(nullptr, ALC_INVALID_VALUE);
3664 TRACE("Opening capture device \"%s\"\n", deviceName);
3665 if(!deviceName[0] || al::strcasecmp(deviceName, alcDefaultName) == 0
3666 || al::strcasecmp(deviceName, "openal-soft") == 0)
3667 deviceName = nullptr;
3670 TRACE("Opening default capture device\n");
3672 DeviceRef device{new ALCdevice{DeviceType::Capture}};
3674 auto decompfmt = DecomposeDevFormat(format);
3677 alcSetError(nullptr, ALC_INVALID_ENUM);
3681 device->Frequency = frequency;
3682 device->FmtChans = decompfmt->chans;
3683 device->FmtType = decompfmt->type;
3684 device->Flags.set(FrequencyRequest);
3685 device->Flags.set(ChannelsRequest);
3686 device->Flags.set(SampleTypeRequest);
3688 device->UpdateSize = static_cast<uint>(samples);
3689 device->BufferSize = static_cast<uint>(samples);
3692 TRACE("Capture format: %s, %s, %uhz, %u / %u buffer\n",
3693 DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType),
3694 device->Frequency, device->UpdateSize, device->BufferSize);
3696 auto backend = CaptureFactory->createBackend(device.get(), BackendType::Capture);
3697 std::lock_guard<std::recursive_mutex> _{ListLock};
3698 backend->open(deviceName);
3699 device->Backend = std::move(backend);
3701 catch(al::backend_exception &e) {
3702 WARN("Failed to open capture device: %s\n", e.what());
3703 alcSetError(nullptr, (e.errorCode() == al::backend_error::OutOfMemory)
3704 ? ALC_OUT_OF_MEMORY : ALC_INVALID_VALUE);
3709 std::lock_guard<std::recursive_mutex> _{ListLock};
3710 auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get());
3711 DeviceList.emplace(iter, device.get());
3714 TRACE("Created capture device %p, \"%s\"\n", voidp{device.get()}, device->DeviceName.c_str());
3715 return device.release();
3719 ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device)
3722 std::unique_lock<std::recursive_mutex> listlock{ListLock};
3723 auto iter = std::lower_bound(DeviceList.begin(), DeviceList.end(), device);
3724 if(iter == DeviceList.end() || *iter != device)
3726 alcSetError(nullptr, ALC_INVALID_DEVICE);
3729 if((*iter)->Type != DeviceType::Capture)
3731 alcSetError(*iter, ALC_INVALID_DEVICE);
3735 DeviceRef dev{*iter};
3736 DeviceList.erase(iter);
3739 std::lock_guard<std::mutex> _{dev->StateLock};
3740 if(dev->Flags.test(DeviceRunning))
3741 dev->Backend->stop();
3742 dev->Flags.reset(DeviceRunning);
3748 ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device)
3751 DeviceRef dev{VerifyDevice(device)};
3752 if(!dev || dev->Type != DeviceType::Capture)
3754 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3758 std::lock_guard<std::mutex> _{dev->StateLock};
3759 if(!dev->Connected.load(std::memory_order_acquire))
3760 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3761 else if(!dev->Flags.test(DeviceRunning))
3764 auto backend = dev->Backend.get();
3766 dev->Flags.set(DeviceRunning);
3768 catch(al::backend_exception& e) {
3769 ERR("%s\n", e.what());
3770 dev->handleDisconnect("%s", e.what());
3771 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3777 ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device)
3780 DeviceRef dev{VerifyDevice(device)};
3781 if(!dev || dev->Type != DeviceType::Capture)
3782 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3785 std::lock_guard<std::mutex> _{dev->StateLock};
3786 if(dev->Flags.test(DeviceRunning))
3787 dev->Backend->stop();
3788 dev->Flags.reset(DeviceRunning);
3793 ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples)
3796 DeviceRef dev{VerifyDevice(device)};
3797 if(!dev || dev->Type != DeviceType::Capture)
3799 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3803 if(samples < 0 || (samples > 0 && buffer == nullptr))
3805 alcSetError(dev.get(), ALC_INVALID_VALUE);
3811 std::lock_guard<std::mutex> _{dev->StateLock};
3812 BackendBase *backend{dev->Backend.get()};
3814 const auto usamples = static_cast<uint>(samples);
3815 if(usamples > backend->availableSamples())
3817 alcSetError(dev.get(), ALC_INVALID_VALUE);
3821 backend->captureSamples(static_cast<al::byte*>(buffer), usamples);
3826 /************************************************
3827 * ALC loopback functions
3828 ************************************************/
3830 /** Open a loopback device, for manual rendering. */
3831 ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName)
3836 /* Make sure the device name, if specified, is us. */
3837 if(deviceName && strcmp(deviceName, alcDefaultName) != 0)
3839 alcSetError(nullptr, ALC_INVALID_VALUE);
3843 const uint DefaultSends{
3845 eax_g_is_enabled ? uint{EAX_MAX_FXSLOTS} :
3846 #endif // ALSOFT_EAX
3850 DeviceRef device{new ALCdevice{DeviceType::Loopback}};
3852 device->SourcesMax = 256;
3853 device->AuxiliaryEffectSlotMax = 64;
3854 device->NumAuxSends = DefaultSends;
3857 device->BufferSize = 0;
3858 device->UpdateSize = 0;
3860 device->Frequency = DEFAULT_OUTPUT_RATE;
3861 device->FmtChans = DevFmtChannelsDefault;
3862 device->FmtType = DevFmtTypeDefault;
3864 device->NumStereoSources = 1;
3865 device->NumMonoSources = device->SourcesMax - device->NumStereoSources;
3868 auto backend = LoopbackBackendFactory::getFactory().createBackend(device.get(),
3869 BackendType::Playback);
3870 backend->open("Loopback");
3871 device->Backend = std::move(backend);
3873 catch(al::backend_exception &e) {
3874 WARN("Failed to open loopback device: %s\n", e.what());
3875 alcSetError(nullptr, (e.errorCode() == al::backend_error::OutOfMemory)
3876 ? ALC_OUT_OF_MEMORY : ALC_INVALID_VALUE);
3881 std::lock_guard<std::recursive_mutex> _{ListLock};
3882 auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get());
3883 DeviceList.emplace(iter, device.get());
3886 TRACE("Created loopback device %p\n", voidp{device.get()});
3887 return device.release();
3892 * Determines if the loopback device supports the given format for rendering.
3894 ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type)
3897 DeviceRef dev{VerifyDevice(device)};
3898 if(!dev || dev->Type != DeviceType::Loopback)
3899 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3901 alcSetError(dev.get(), ALC_INVALID_VALUE);
3904 if(DevFmtTypeFromEnum(type).has_value() && DevFmtChannelsFromEnum(channels).has_value()
3905 && freq >= MIN_OUTPUT_RATE && freq <= MAX_OUTPUT_RATE)
3914 * Renders some samples into a buffer, using the format last set by the
3915 * attributes given to alcCreateContext.
3917 FORCE_ALIGN ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples)
3920 if(!device || device->Type != DeviceType::Loopback)
3921 alcSetError(device, ALC_INVALID_DEVICE);
3922 else if(samples < 0 || (samples > 0 && buffer == nullptr))
3923 alcSetError(device, ALC_INVALID_VALUE);
3925 device->renderSamples(buffer, static_cast<uint>(samples), device->channelsFromFmt());
3930 /************************************************
3931 * ALC DSP pause/resume functions
3932 ************************************************/
3934 /** Pause the DSP to stop audio processing. */
3935 ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device)
3938 DeviceRef dev{VerifyDevice(device)};
3939 if(!dev || dev->Type != DeviceType::Playback)
3940 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3943 std::lock_guard<std::mutex> _{dev->StateLock};
3944 if(dev->Flags.test(DeviceRunning))
3945 dev->Backend->stop();
3946 dev->Flags.reset(DeviceRunning);
3947 dev->Flags.set(DevicePaused);
3952 /** Resume the DSP to restart audio processing. */
3953 ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device)
3956 DeviceRef dev{VerifyDevice(device)};
3957 if(!dev || dev->Type != DeviceType::Playback)
3959 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3963 std::lock_guard<std::mutex> _{dev->StateLock};
3964 if(!dev->Flags.test(DevicePaused))
3966 dev->Flags.reset(DevicePaused);
3967 if(dev->mContexts.load()->empty())
3971 auto backend = dev->Backend.get();
3973 dev->Flags.set(DeviceRunning);
3975 catch(al::backend_exception& e) {
3976 ERR("%s\n", e.what());
3977 dev->handleDisconnect("%s", e.what());
3978 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3981 TRACE("Post-resume: %s, %s, %uhz, %u / %u buffer\n",
3982 DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType),
3983 device->Frequency, device->UpdateSize, device->BufferSize);
3988 /************************************************
3989 * ALC HRTF functions
3990 ************************************************/
3992 /** Gets a string parameter at the given index. */
3993 ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index)
3996 DeviceRef dev{VerifyDevice(device)};
3997 if(!dev || dev->Type == DeviceType::Capture)
3998 alcSetError(dev.get(), ALC_INVALID_DEVICE);
3999 else switch(paramName)
4001 case ALC_HRTF_SPECIFIER_SOFT:
4002 if(index >= 0 && static_cast<uint>(index) < dev->mHrtfList.size())
4003 return dev->mHrtfList[static_cast<uint>(index)].c_str();
4004 alcSetError(dev.get(), ALC_INVALID_VALUE);
4008 alcSetError(dev.get(), ALC_INVALID_ENUM);
4016 /** Resets the given device output, using the specified attribute list. */
4017 ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs)
4020 std::unique_lock<std::recursive_mutex> listlock{ListLock};
4021 DeviceRef dev{VerifyDevice(device)};
4022 if(!dev || dev->Type == DeviceType::Capture)
4025 alcSetError(dev.get(), ALC_INVALID_DEVICE);
4028 std::lock_guard<std::mutex> _{dev->StateLock};
4031 /* Force the backend to stop mixing first since we're resetting. Also reset
4032 * the connected state so lost devices can attempt recover.
4034 if(dev->Flags.test(DeviceRunning))
4035 dev->Backend->stop();
4036 dev->Flags.reset(DeviceRunning);
4038 return ResetDeviceParams(dev.get(), attribs) ? ALC_TRUE : ALC_FALSE;
4043 /************************************************
4044 * ALC device reopen functions
4045 ************************************************/
4047 /** Reopens the given device output, using the specified name and attribute list. */
4048 FORCE_ALIGN ALCboolean ALC_APIENTRY alcReopenDeviceSOFT(ALCdevice *device,
4049 const ALCchar *deviceName, const ALCint *attribs)
4054 if(!deviceName[0] || al::strcasecmp(deviceName, alcDefaultName) == 0)
4055 deviceName = nullptr;
4058 std::unique_lock<std::recursive_mutex> listlock{ListLock};
4059 DeviceRef dev{VerifyDevice(device)};
4060 if(!dev || dev->Type != DeviceType::Playback)
4063 alcSetError(dev.get(), ALC_INVALID_DEVICE);
4066 std::lock_guard<std::mutex> _{dev->StateLock};
4068 /* Force the backend to stop mixing first since we're reopening. */
4069 if(dev->Flags.test(DeviceRunning))
4071 auto backend = dev->Backend.get();
4073 dev->Flags.reset(DeviceRunning);
4076 BackendPtr newbackend;
4078 newbackend = PlaybackFactory->createBackend(dev.get(), BackendType::Playback);
4079 newbackend->open(deviceName);
4081 catch(al::backend_exception &e) {
4083 newbackend = nullptr;
4085 WARN("Failed to reopen playback device: %s\n", e.what());
4086 alcSetError(dev.get(), (e.errorCode() == al::backend_error::OutOfMemory)
4087 ? ALC_OUT_OF_MEMORY : ALC_INVALID_VALUE);
4089 /* If the device is connected, not paused, and has contexts, ensure it
4090 * continues playing.
4092 if(dev->Connected.load(std::memory_order_relaxed) && !dev->Flags.test(DevicePaused)
4093 && !dev->mContexts.load(std::memory_order_relaxed)->empty())
4096 auto backend = dev->Backend.get();
4098 dev->Flags.set(DeviceRunning);
4100 catch(al::backend_exception &be) {
4101 ERR("%s\n", be.what());
4102 dev->handleDisconnect("%s", be.what());
4108 dev->Backend = std::move(newbackend);
4109 TRACE("Reopened device %p, \"%s\"\n", voidp{dev.get()}, dev->DeviceName.c_str());
4111 /* Always return true even if resetting fails. It shouldn't fail, but this
4112 * is primarily to avoid confusion by the app seeing the function return
4113 * false while the device is on the new output anyway. We could try to
4114 * restore the old backend if this fails, but the configuration would be
4115 * changed with the new backend and would need to be reset again with the
4116 * old one, and the provided attributes may not be appropriate or desirable
4117 * for the old device.
4119 * In this way, we essentially act as if the function succeeded, but
4120 * immediately disconnects following it.
4122 ResetDeviceParams(dev.get(), attribs);