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 }, eaxFunctions
[] = {
462 DECL(EAXGetBufferMode
),
463 DECL(EAXSetBufferMode
),
468 #define DECL(x) { #x, (x) }
470 const ALCchar
*enumName
;
472 } alcEnumerations
[] = {
477 DECL(ALC_MAJOR_VERSION
),
478 DECL(ALC_MINOR_VERSION
),
479 DECL(ALC_ATTRIBUTES_SIZE
),
480 DECL(ALC_ALL_ATTRIBUTES
),
481 DECL(ALC_DEFAULT_DEVICE_SPECIFIER
),
482 DECL(ALC_DEVICE_SPECIFIER
),
483 DECL(ALC_ALL_DEVICES_SPECIFIER
),
484 DECL(ALC_DEFAULT_ALL_DEVICES_SPECIFIER
),
485 DECL(ALC_EXTENSIONS
),
489 DECL(ALC_MONO_SOURCES
),
490 DECL(ALC_STEREO_SOURCES
),
491 DECL(ALC_CAPTURE_DEVICE_SPECIFIER
),
492 DECL(ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER
),
493 DECL(ALC_CAPTURE_SAMPLES
),
496 DECL(ALC_EFX_MAJOR_VERSION
),
497 DECL(ALC_EFX_MINOR_VERSION
),
498 DECL(ALC_MAX_AUXILIARY_SENDS
),
500 DECL(ALC_FORMAT_CHANNELS_SOFT
),
501 DECL(ALC_FORMAT_TYPE_SOFT
),
504 DECL(ALC_STEREO_SOFT
),
506 DECL(ALC_5POINT1_SOFT
),
507 DECL(ALC_6POINT1_SOFT
),
508 DECL(ALC_7POINT1_SOFT
),
509 DECL(ALC_BFORMAT3D_SOFT
),
512 DECL(ALC_UNSIGNED_BYTE_SOFT
),
513 DECL(ALC_SHORT_SOFT
),
514 DECL(ALC_UNSIGNED_SHORT_SOFT
),
516 DECL(ALC_UNSIGNED_INT_SOFT
),
517 DECL(ALC_FLOAT_SOFT
),
520 DECL(ALC_DONT_CARE_SOFT
),
521 DECL(ALC_HRTF_STATUS_SOFT
),
522 DECL(ALC_HRTF_DISABLED_SOFT
),
523 DECL(ALC_HRTF_ENABLED_SOFT
),
524 DECL(ALC_HRTF_DENIED_SOFT
),
525 DECL(ALC_HRTF_REQUIRED_SOFT
),
526 DECL(ALC_HRTF_HEADPHONES_DETECTED_SOFT
),
527 DECL(ALC_HRTF_UNSUPPORTED_FORMAT_SOFT
),
528 DECL(ALC_NUM_HRTF_SPECIFIERS_SOFT
),
529 DECL(ALC_HRTF_SPECIFIER_SOFT
),
530 DECL(ALC_HRTF_ID_SOFT
),
532 DECL(ALC_AMBISONIC_LAYOUT_SOFT
),
533 DECL(ALC_AMBISONIC_SCALING_SOFT
),
534 DECL(ALC_AMBISONIC_ORDER_SOFT
),
540 DECL(ALC_OUTPUT_LIMITER_SOFT
),
542 DECL(ALC_DEVICE_CLOCK_SOFT
),
543 DECL(ALC_DEVICE_LATENCY_SOFT
),
544 DECL(ALC_DEVICE_CLOCK_LATENCY_SOFT
),
545 DECL(AL_SAMPLE_OFFSET_CLOCK_SOFT
),
546 DECL(AL_SEC_OFFSET_CLOCK_SOFT
),
548 DECL(ALC_OUTPUT_MODE_SOFT
),
550 DECL(ALC_STEREO_BASIC_SOFT
),
551 DECL(ALC_STEREO_UHJ_SOFT
),
552 DECL(ALC_STEREO_HRTF_SOFT
),
553 DECL(ALC_SURROUND_5_1_SOFT
),
554 DECL(ALC_SURROUND_6_1_SOFT
),
555 DECL(ALC_SURROUND_7_1_SOFT
),
558 DECL(ALC_INVALID_DEVICE
),
559 DECL(ALC_INVALID_CONTEXT
),
560 DECL(ALC_INVALID_ENUM
),
561 DECL(ALC_INVALID_VALUE
),
562 DECL(ALC_OUT_OF_MEMORY
),
570 DECL(AL_SOURCE_RELATIVE
),
571 DECL(AL_CONE_INNER_ANGLE
),
572 DECL(AL_CONE_OUTER_ANGLE
),
582 DECL(AL_ORIENTATION
),
583 DECL(AL_REFERENCE_DISTANCE
),
584 DECL(AL_ROLLOFF_FACTOR
),
585 DECL(AL_CONE_OUTER_GAIN
),
586 DECL(AL_MAX_DISTANCE
),
588 DECL(AL_SAMPLE_OFFSET
),
589 DECL(AL_BYTE_OFFSET
),
590 DECL(AL_SOURCE_TYPE
),
593 DECL(AL_UNDETERMINED
),
594 DECL(AL_METERS_PER_UNIT
),
595 DECL(AL_LOOP_POINTS_SOFT
),
596 DECL(AL_DIRECT_CHANNELS_SOFT
),
598 DECL(AL_DIRECT_FILTER
),
599 DECL(AL_AUXILIARY_SEND_FILTER
),
600 DECL(AL_AIR_ABSORPTION_FACTOR
),
601 DECL(AL_ROOM_ROLLOFF_FACTOR
),
602 DECL(AL_CONE_OUTER_GAINHF
),
603 DECL(AL_DIRECT_FILTER_GAINHF_AUTO
),
604 DECL(AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
),
605 DECL(AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
),
607 DECL(AL_SOURCE_STATE
),
613 DECL(AL_BUFFERS_QUEUED
),
614 DECL(AL_BUFFERS_PROCESSED
),
616 DECL(AL_FORMAT_MONO8
),
617 DECL(AL_FORMAT_MONO16
),
618 DECL(AL_FORMAT_MONO_FLOAT32
),
619 DECL(AL_FORMAT_MONO_DOUBLE_EXT
),
620 DECL(AL_FORMAT_STEREO8
),
621 DECL(AL_FORMAT_STEREO16
),
622 DECL(AL_FORMAT_STEREO_FLOAT32
),
623 DECL(AL_FORMAT_STEREO_DOUBLE_EXT
),
624 DECL(AL_FORMAT_MONO_IMA4
),
625 DECL(AL_FORMAT_STEREO_IMA4
),
626 DECL(AL_FORMAT_MONO_MSADPCM_SOFT
),
627 DECL(AL_FORMAT_STEREO_MSADPCM_SOFT
),
628 DECL(AL_FORMAT_QUAD8_LOKI
),
629 DECL(AL_FORMAT_QUAD16_LOKI
),
630 DECL(AL_FORMAT_QUAD8
),
631 DECL(AL_FORMAT_QUAD16
),
632 DECL(AL_FORMAT_QUAD32
),
633 DECL(AL_FORMAT_51CHN8
),
634 DECL(AL_FORMAT_51CHN16
),
635 DECL(AL_FORMAT_51CHN32
),
636 DECL(AL_FORMAT_61CHN8
),
637 DECL(AL_FORMAT_61CHN16
),
638 DECL(AL_FORMAT_61CHN32
),
639 DECL(AL_FORMAT_71CHN8
),
640 DECL(AL_FORMAT_71CHN16
),
641 DECL(AL_FORMAT_71CHN32
),
642 DECL(AL_FORMAT_REAR8
),
643 DECL(AL_FORMAT_REAR16
),
644 DECL(AL_FORMAT_REAR32
),
645 DECL(AL_FORMAT_MONO_MULAW
),
646 DECL(AL_FORMAT_MONO_MULAW_EXT
),
647 DECL(AL_FORMAT_STEREO_MULAW
),
648 DECL(AL_FORMAT_STEREO_MULAW_EXT
),
649 DECL(AL_FORMAT_QUAD_MULAW
),
650 DECL(AL_FORMAT_51CHN_MULAW
),
651 DECL(AL_FORMAT_61CHN_MULAW
),
652 DECL(AL_FORMAT_71CHN_MULAW
),
653 DECL(AL_FORMAT_REAR_MULAW
),
654 DECL(AL_FORMAT_MONO_ALAW_EXT
),
655 DECL(AL_FORMAT_STEREO_ALAW_EXT
),
657 DECL(AL_FORMAT_BFORMAT2D_8
),
658 DECL(AL_FORMAT_BFORMAT2D_16
),
659 DECL(AL_FORMAT_BFORMAT2D_FLOAT32
),
660 DECL(AL_FORMAT_BFORMAT2D_MULAW
),
661 DECL(AL_FORMAT_BFORMAT3D_8
),
662 DECL(AL_FORMAT_BFORMAT3D_16
),
663 DECL(AL_FORMAT_BFORMAT3D_FLOAT32
),
664 DECL(AL_FORMAT_BFORMAT3D_MULAW
),
670 DECL(AL_UNPACK_BLOCK_ALIGNMENT_SOFT
),
671 DECL(AL_PACK_BLOCK_ALIGNMENT_SOFT
),
673 DECL(AL_SOURCE_RADIUS
),
675 DECL(AL_SAMPLE_OFFSET_LATENCY_SOFT
),
676 DECL(AL_SEC_OFFSET_LATENCY_SOFT
),
678 DECL(AL_STEREO_ANGLES
),
685 DECL(AL_INVALID_NAME
),
686 DECL(AL_INVALID_ENUM
),
687 DECL(AL_INVALID_VALUE
),
688 DECL(AL_INVALID_OPERATION
),
689 DECL(AL_OUT_OF_MEMORY
),
696 DECL(AL_DOPPLER_FACTOR
),
697 DECL(AL_DOPPLER_VELOCITY
),
698 DECL(AL_DISTANCE_MODEL
),
699 DECL(AL_SPEED_OF_SOUND
),
700 DECL(AL_SOURCE_DISTANCE_MODEL
),
701 DECL(AL_DEFERRED_UPDATES_SOFT
),
702 DECL(AL_GAIN_LIMIT_SOFT
),
704 DECL(AL_INVERSE_DISTANCE
),
705 DECL(AL_INVERSE_DISTANCE_CLAMPED
),
706 DECL(AL_LINEAR_DISTANCE
),
707 DECL(AL_LINEAR_DISTANCE_CLAMPED
),
708 DECL(AL_EXPONENT_DISTANCE
),
709 DECL(AL_EXPONENT_DISTANCE_CLAMPED
),
711 DECL(AL_FILTER_TYPE
),
712 DECL(AL_FILTER_NULL
),
713 DECL(AL_FILTER_LOWPASS
),
714 DECL(AL_FILTER_HIGHPASS
),
715 DECL(AL_FILTER_BANDPASS
),
717 DECL(AL_LOWPASS_GAIN
),
718 DECL(AL_LOWPASS_GAINHF
),
720 DECL(AL_HIGHPASS_GAIN
),
721 DECL(AL_HIGHPASS_GAINLF
),
723 DECL(AL_BANDPASS_GAIN
),
724 DECL(AL_BANDPASS_GAINHF
),
725 DECL(AL_BANDPASS_GAINLF
),
727 DECL(AL_EFFECT_TYPE
),
728 DECL(AL_EFFECT_NULL
),
729 DECL(AL_EFFECT_REVERB
),
730 DECL(AL_EFFECT_EAXREVERB
),
731 DECL(AL_EFFECT_CHORUS
),
732 DECL(AL_EFFECT_DISTORTION
),
733 DECL(AL_EFFECT_ECHO
),
734 DECL(AL_EFFECT_FLANGER
),
735 DECL(AL_EFFECT_PITCH_SHIFTER
),
736 DECL(AL_EFFECT_FREQUENCY_SHIFTER
),
737 DECL(AL_EFFECT_VOCAL_MORPHER
),
738 DECL(AL_EFFECT_RING_MODULATOR
),
739 DECL(AL_EFFECT_AUTOWAH
),
740 DECL(AL_EFFECT_COMPRESSOR
),
741 DECL(AL_EFFECT_EQUALIZER
),
742 DECL(AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT
),
743 DECL(AL_EFFECT_DEDICATED_DIALOGUE
),
745 DECL(AL_EFFECTSLOT_EFFECT
),
746 DECL(AL_EFFECTSLOT_GAIN
),
747 DECL(AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
),
748 DECL(AL_EFFECTSLOT_NULL
),
750 DECL(AL_EAXREVERB_DENSITY
),
751 DECL(AL_EAXREVERB_DIFFUSION
),
752 DECL(AL_EAXREVERB_GAIN
),
753 DECL(AL_EAXREVERB_GAINHF
),
754 DECL(AL_EAXREVERB_GAINLF
),
755 DECL(AL_EAXREVERB_DECAY_TIME
),
756 DECL(AL_EAXREVERB_DECAY_HFRATIO
),
757 DECL(AL_EAXREVERB_DECAY_LFRATIO
),
758 DECL(AL_EAXREVERB_REFLECTIONS_GAIN
),
759 DECL(AL_EAXREVERB_REFLECTIONS_DELAY
),
760 DECL(AL_EAXREVERB_REFLECTIONS_PAN
),
761 DECL(AL_EAXREVERB_LATE_REVERB_GAIN
),
762 DECL(AL_EAXREVERB_LATE_REVERB_DELAY
),
763 DECL(AL_EAXREVERB_LATE_REVERB_PAN
),
764 DECL(AL_EAXREVERB_ECHO_TIME
),
765 DECL(AL_EAXREVERB_ECHO_DEPTH
),
766 DECL(AL_EAXREVERB_MODULATION_TIME
),
767 DECL(AL_EAXREVERB_MODULATION_DEPTH
),
768 DECL(AL_EAXREVERB_AIR_ABSORPTION_GAINHF
),
769 DECL(AL_EAXREVERB_HFREFERENCE
),
770 DECL(AL_EAXREVERB_LFREFERENCE
),
771 DECL(AL_EAXREVERB_ROOM_ROLLOFF_FACTOR
),
772 DECL(AL_EAXREVERB_DECAY_HFLIMIT
),
774 DECL(AL_REVERB_DENSITY
),
775 DECL(AL_REVERB_DIFFUSION
),
776 DECL(AL_REVERB_GAIN
),
777 DECL(AL_REVERB_GAINHF
),
778 DECL(AL_REVERB_DECAY_TIME
),
779 DECL(AL_REVERB_DECAY_HFRATIO
),
780 DECL(AL_REVERB_REFLECTIONS_GAIN
),
781 DECL(AL_REVERB_REFLECTIONS_DELAY
),
782 DECL(AL_REVERB_LATE_REVERB_GAIN
),
783 DECL(AL_REVERB_LATE_REVERB_DELAY
),
784 DECL(AL_REVERB_AIR_ABSORPTION_GAINHF
),
785 DECL(AL_REVERB_ROOM_ROLLOFF_FACTOR
),
786 DECL(AL_REVERB_DECAY_HFLIMIT
),
788 DECL(AL_CHORUS_WAVEFORM
),
789 DECL(AL_CHORUS_PHASE
),
790 DECL(AL_CHORUS_RATE
),
791 DECL(AL_CHORUS_DEPTH
),
792 DECL(AL_CHORUS_FEEDBACK
),
793 DECL(AL_CHORUS_DELAY
),
795 DECL(AL_DISTORTION_EDGE
),
796 DECL(AL_DISTORTION_GAIN
),
797 DECL(AL_DISTORTION_LOWPASS_CUTOFF
),
798 DECL(AL_DISTORTION_EQCENTER
),
799 DECL(AL_DISTORTION_EQBANDWIDTH
),
802 DECL(AL_ECHO_LRDELAY
),
803 DECL(AL_ECHO_DAMPING
),
804 DECL(AL_ECHO_FEEDBACK
),
805 DECL(AL_ECHO_SPREAD
),
807 DECL(AL_FLANGER_WAVEFORM
),
808 DECL(AL_FLANGER_PHASE
),
809 DECL(AL_FLANGER_RATE
),
810 DECL(AL_FLANGER_DEPTH
),
811 DECL(AL_FLANGER_FEEDBACK
),
812 DECL(AL_FLANGER_DELAY
),
814 DECL(AL_FREQUENCY_SHIFTER_FREQUENCY
),
815 DECL(AL_FREQUENCY_SHIFTER_LEFT_DIRECTION
),
816 DECL(AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION
),
818 DECL(AL_RING_MODULATOR_FREQUENCY
),
819 DECL(AL_RING_MODULATOR_HIGHPASS_CUTOFF
),
820 DECL(AL_RING_MODULATOR_WAVEFORM
),
822 DECL(AL_PITCH_SHIFTER_COARSE_TUNE
),
823 DECL(AL_PITCH_SHIFTER_FINE_TUNE
),
825 DECL(AL_COMPRESSOR_ONOFF
),
827 DECL(AL_EQUALIZER_LOW_GAIN
),
828 DECL(AL_EQUALIZER_LOW_CUTOFF
),
829 DECL(AL_EQUALIZER_MID1_GAIN
),
830 DECL(AL_EQUALIZER_MID1_CENTER
),
831 DECL(AL_EQUALIZER_MID1_WIDTH
),
832 DECL(AL_EQUALIZER_MID2_GAIN
),
833 DECL(AL_EQUALIZER_MID2_CENTER
),
834 DECL(AL_EQUALIZER_MID2_WIDTH
),
835 DECL(AL_EQUALIZER_HIGH_GAIN
),
836 DECL(AL_EQUALIZER_HIGH_CUTOFF
),
838 DECL(AL_DEDICATED_GAIN
),
840 DECL(AL_AUTOWAH_ATTACK_TIME
),
841 DECL(AL_AUTOWAH_RELEASE_TIME
),
842 DECL(AL_AUTOWAH_RESONANCE
),
843 DECL(AL_AUTOWAH_PEAK_GAIN
),
845 DECL(AL_VOCAL_MORPHER_PHONEMEA
),
846 DECL(AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING
),
847 DECL(AL_VOCAL_MORPHER_PHONEMEB
),
848 DECL(AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING
),
849 DECL(AL_VOCAL_MORPHER_WAVEFORM
),
850 DECL(AL_VOCAL_MORPHER_RATE
),
852 DECL(AL_EFFECTSLOT_TARGET_SOFT
),
854 DECL(AL_NUM_RESAMPLERS_SOFT
),
855 DECL(AL_DEFAULT_RESAMPLER_SOFT
),
856 DECL(AL_SOURCE_RESAMPLER_SOFT
),
857 DECL(AL_RESAMPLER_NAME_SOFT
),
859 DECL(AL_SOURCE_SPATIALIZE_SOFT
),
862 DECL(AL_MAP_READ_BIT_SOFT
),
863 DECL(AL_MAP_WRITE_BIT_SOFT
),
864 DECL(AL_MAP_PERSISTENT_BIT_SOFT
),
865 DECL(AL_PRESERVE_DATA_BIT_SOFT
),
867 DECL(AL_EVENT_CALLBACK_FUNCTION_SOFT
),
868 DECL(AL_EVENT_CALLBACK_USER_PARAM_SOFT
),
869 DECL(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT
),
870 DECL(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT
),
871 DECL(AL_EVENT_TYPE_DISCONNECTED_SOFT
),
873 DECL(AL_DROP_UNMATCHED_SOFT
),
874 DECL(AL_REMIX_UNMATCHED_SOFT
),
876 DECL(AL_AMBISONIC_LAYOUT_SOFT
),
877 DECL(AL_AMBISONIC_SCALING_SOFT
),
883 DECL(AL_BUFFER_CALLBACK_FUNCTION_SOFT
),
884 DECL(AL_BUFFER_CALLBACK_USER_PARAM_SOFT
),
886 DECL(AL_UNPACK_AMBISONIC_ORDER_SOFT
),
888 DECL(AL_EFFECT_CONVOLUTION_REVERB_SOFT
),
889 DECL(AL_EFFECTSLOT_STATE_SOFT
),
891 DECL(AL_FORMAT_UHJ2CHN8_SOFT
),
892 DECL(AL_FORMAT_UHJ2CHN16_SOFT
),
893 DECL(AL_FORMAT_UHJ2CHN_FLOAT32_SOFT
),
894 DECL(AL_FORMAT_UHJ3CHN8_SOFT
),
895 DECL(AL_FORMAT_UHJ3CHN16_SOFT
),
896 DECL(AL_FORMAT_UHJ3CHN_FLOAT32_SOFT
),
897 DECL(AL_FORMAT_UHJ4CHN8_SOFT
),
898 DECL(AL_FORMAT_UHJ4CHN16_SOFT
),
899 DECL(AL_FORMAT_UHJ4CHN_FLOAT32_SOFT
),
900 DECL(AL_STEREO_MODE_SOFT
),
901 DECL(AL_NORMAL_SOFT
),
902 DECL(AL_SUPER_STEREO_SOFT
),
903 DECL(AL_SUPER_STEREO_WIDTH_SOFT
),
905 DECL(AL_STOP_SOURCES_ON_DISCONNECT_SOFT
),
908 }, eaxEnumerations
[] = {
909 DECL(AL_EAX_RAM_SIZE
),
910 DECL(AL_EAX_RAM_FREE
),
911 DECL(AL_STORAGE_AUTOMATIC
),
912 DECL(AL_STORAGE_HARDWARE
),
913 DECL(AL_STORAGE_ACCESSIBLE
),
918 constexpr ALCchar alcNoError
[] = "No Error";
919 constexpr ALCchar alcErrInvalidDevice
[] = "Invalid Device";
920 constexpr ALCchar alcErrInvalidContext
[] = "Invalid Context";
921 constexpr ALCchar alcErrInvalidEnum
[] = "Invalid Enum";
922 constexpr ALCchar alcErrInvalidValue
[] = "Invalid Value";
923 constexpr ALCchar alcErrOutOfMemory
[] = "Out of Memory";
926 /************************************************
928 ************************************************/
930 /* Enumerated device names */
931 constexpr ALCchar alcDefaultName
[] = "OpenAL Soft\0";
933 std::string alcAllDevicesList
;
934 std::string alcCaptureDeviceList
;
936 /* Default is always the first in the list */
937 std::string alcDefaultAllDevicesSpecifier
;
938 std::string alcCaptureDefaultDeviceSpecifier
;
940 std::atomic
<ALCenum
> LastNullDeviceError
{ALC_NO_ERROR
};
942 /* Flag to trap ALC device errors */
943 bool TrapALCError
{false};
945 /* One-time configuration init control */
946 std::once_flag alc_config_once
{};
948 /* Flag to specify if alcSuspendContext/alcProcessContext should defer/process
951 bool SuspendDefers
{true};
953 /* Initial seed for dithering. */
954 constexpr uint DitherRNGSeed
{22222u};
957 /************************************************
959 ************************************************/
960 constexpr ALCchar alcNoDeviceExtList
[] =
961 "ALC_ENUMERATE_ALL_EXT "
962 "ALC_ENUMERATION_EXT "
965 "ALC_EXT_thread_local_context "
967 "ALC_SOFT_loopback_bformat "
968 "ALC_SOFT_reopen_device";
969 constexpr ALCchar alcExtensionList
[] =
970 "ALC_ENUMERATE_ALL_EXT "
971 "ALC_ENUMERATION_EXT "
974 "ALC_EXT_disconnect "
976 "ALC_EXT_thread_local_context "
977 "ALC_SOFT_device_clock "
980 "ALC_SOFT_loopback_bformat "
981 "ALC_SOFT_output_limiter "
982 "ALC_SOFT_output_mode "
983 "ALC_SOFT_pause_device "
984 "ALC_SOFT_reopen_device";
985 constexpr int alcMajorVersion
{1};
986 constexpr int alcMinorVersion
{1};
988 constexpr int alcEFXMajorVersion
{1};
989 constexpr int alcEFXMinorVersion
{0};
992 using DeviceRef
= al::intrusive_ptr
<ALCdevice
>;
995 /************************************************
997 ************************************************/
998 al::vector
<ALCdevice
*> DeviceList
;
999 al::vector
<ALCcontext
*> ContextList
;
1001 std::recursive_mutex ListLock
;
1004 void alc_initconfig(void)
1006 if(auto loglevel
= al::getenv("ALSOFT_LOGLEVEL"))
1008 long lvl
= strtol(loglevel
->c_str(), nullptr, 0);
1009 if(lvl
>= static_cast<long>(LogLevel::Trace
))
1010 gLogLevel
= LogLevel::Trace
;
1011 else if(lvl
<= static_cast<long>(LogLevel::Disable
))
1012 gLogLevel
= LogLevel::Disable
;
1014 gLogLevel
= static_cast<LogLevel
>(lvl
);
1018 if(const auto logfile
= al::getenv(L
"ALSOFT_LOGFILE"))
1020 FILE *logf
{_wfopen(logfile
->c_str(), L
"wt")};
1021 if(logf
) gLogFile
= logf
;
1024 auto u8name
= wstr_to_utf8(logfile
->c_str());
1025 ERR("Failed to open log file '%s'\n", u8name
.c_str());
1029 if(const auto logfile
= al::getenv("ALSOFT_LOGFILE"))
1031 FILE *logf
{fopen(logfile
->c_str(), "wt")};
1032 if(logf
) gLogFile
= logf
;
1033 else ERR("Failed to open log file '%s'\n", logfile
->c_str());
1037 TRACE("Initializing library v%s-%s %s\n", ALSOFT_VERSION
, ALSOFT_GIT_COMMIT_HASH
,
1041 if(al::size(BackendList
) < 1)
1045 const al::span
<const BackendInfo
> infos
{BackendList
};
1046 names
= infos
[0].name
;
1047 for(const auto &backend
: infos
.subspan
<1>())
1050 names
+= backend
.name
;
1053 TRACE("Supported backends: %s\n", names
.c_str());
1057 if(auto suspendmode
= al::getenv("__ALSOFT_SUSPEND_CONTEXT"))
1059 if(al::strcasecmp(suspendmode
->c_str(), "ignore") == 0)
1061 SuspendDefers
= false;
1062 TRACE("Selected context suspend behavior, \"ignore\"\n");
1065 ERR("Unhandled context suspend behavior setting: \"%s\"\n", suspendmode
->c_str());
1069 #if defined(HAVE_SSE4_1)
1070 capfilter
|= CPU_CAP_SSE
| CPU_CAP_SSE2
| CPU_CAP_SSE3
| CPU_CAP_SSE4_1
;
1071 #elif defined(HAVE_SSE3)
1072 capfilter
|= CPU_CAP_SSE
| CPU_CAP_SSE2
| CPU_CAP_SSE3
;
1073 #elif defined(HAVE_SSE2)
1074 capfilter
|= CPU_CAP_SSE
| CPU_CAP_SSE2
;
1075 #elif defined(HAVE_SSE)
1076 capfilter
|= CPU_CAP_SSE
;
1079 capfilter
|= CPU_CAP_NEON
;
1081 if(auto cpuopt
= ConfigValueStr(nullptr, nullptr, "disable-cpu-exts"))
1083 const char *str
{cpuopt
->c_str()};
1084 if(al::strcasecmp(str
, "all") == 0)
1088 const char *next
= str
;
1091 while(isspace(str
[0]))
1093 next
= strchr(str
, ',');
1095 if(!str
[0] || str
[0] == ',')
1098 size_t len
{next
? static_cast<size_t>(next
-str
) : strlen(str
)};
1099 while(len
> 0 && isspace(str
[len
-1]))
1101 if(len
== 3 && al::strncasecmp(str
, "sse", len
) == 0)
1102 capfilter
&= ~CPU_CAP_SSE
;
1103 else if(len
== 4 && al::strncasecmp(str
, "sse2", len
) == 0)
1104 capfilter
&= ~CPU_CAP_SSE2
;
1105 else if(len
== 4 && al::strncasecmp(str
, "sse3", len
) == 0)
1106 capfilter
&= ~CPU_CAP_SSE3
;
1107 else if(len
== 6 && al::strncasecmp(str
, "sse4.1", len
) == 0)
1108 capfilter
&= ~CPU_CAP_SSE4_1
;
1109 else if(len
== 4 && al::strncasecmp(str
, "neon", len
) == 0)
1110 capfilter
&= ~CPU_CAP_NEON
;
1112 WARN("Invalid CPU extension \"%s\"\n", str
);
1116 if(auto cpuopt
= GetCPUInfo())
1118 if(!cpuopt
->mVendor
.empty() || !cpuopt
->mName
.empty())
1120 TRACE("Vendor ID: \"%s\"\n", cpuopt
->mVendor
.c_str());
1121 TRACE("Name: \"%s\"\n", cpuopt
->mName
.c_str());
1123 const int caps
{cpuopt
->mCaps
};
1124 TRACE("Extensions:%s%s%s%s%s%s\n",
1125 ((capfilter
&CPU_CAP_SSE
) ? ((caps
&CPU_CAP_SSE
) ? " +SSE" : " -SSE") : ""),
1126 ((capfilter
&CPU_CAP_SSE2
) ? ((caps
&CPU_CAP_SSE2
) ? " +SSE2" : " -SSE2") : ""),
1127 ((capfilter
&CPU_CAP_SSE3
) ? ((caps
&CPU_CAP_SSE3
) ? " +SSE3" : " -SSE3") : ""),
1128 ((capfilter
&CPU_CAP_SSE4_1
) ? ((caps
&CPU_CAP_SSE4_1
) ? " +SSE4.1" : " -SSE4.1") : ""),
1129 ((capfilter
&CPU_CAP_NEON
) ? ((caps
&CPU_CAP_NEON
) ? " +NEON" : " -NEON") : ""),
1130 ((!capfilter
) ? " -none-" : ""));
1131 CPUCapFlags
= caps
& capfilter
;
1134 if(auto priopt
= ConfigValueInt(nullptr, nullptr, "rt-prio"))
1135 RTPrioLevel
= *priopt
;
1136 if(auto limopt
= ConfigValueBool(nullptr, nullptr, "rt-time-limit"))
1137 AllowRTTimeLimit
= *limopt
;
1140 CompatFlagBitset compatflags
{};
1141 auto checkflag
= [](const char *envname
, const char *optname
) -> bool
1143 if(auto optval
= al::getenv(envname
))
1145 if(al::strcasecmp(optval
->c_str(), "true") == 0
1146 || strtol(optval
->c_str(), nullptr, 0) == 1)
1150 return GetConfigValueBool(nullptr, "game_compat", optname
, false);
1152 compatflags
.set(CompatFlags::ReverseX
, checkflag("__ALSOFT_REVERSE_X", "reverse-x"));
1153 compatflags
.set(CompatFlags::ReverseY
, checkflag("__ALSOFT_REVERSE_Y", "reverse-y"));
1154 compatflags
.set(CompatFlags::ReverseZ
, checkflag("__ALSOFT_REVERSE_Z", "reverse-z"));
1156 aluInit(compatflags
, ConfigValueFloat(nullptr, "game_compat", "nfc-scale").value_or(1.0f
));
1158 Voice::InitMixer(ConfigValueStr(nullptr, nullptr, "resampler"));
1160 auto uhjfiltopt
= ConfigValueStr(nullptr, "uhj", "decode-filter");
1163 if((uhjfiltopt
= ConfigValueStr(nullptr, "uhj", "filter")))
1164 WARN("uhj/filter is deprecated, please use uhj/decode-filter\n");
1168 if(al::strcasecmp(uhjfiltopt
->c_str(), "fir256") == 0)
1169 UhjDecodeQuality
= UhjQualityType::FIR256
;
1170 else if(al::strcasecmp(uhjfiltopt
->c_str(), "fir512") == 0)
1171 UhjDecodeQuality
= UhjQualityType::FIR512
;
1172 else if(al::strcasecmp(uhjfiltopt
->c_str(), "iir") == 0)
1173 UhjDecodeQuality
= UhjQualityType::IIR
;
1175 WARN("Unsupported uhj/decode-filter: %s\n", uhjfiltopt
->c_str());
1177 if((uhjfiltopt
= ConfigValueStr(nullptr, "uhj", "encode-filter")))
1179 if(al::strcasecmp(uhjfiltopt
->c_str(), "fir256") == 0)
1180 UhjEncodeQuality
= UhjQualityType::FIR256
;
1181 else if(al::strcasecmp(uhjfiltopt
->c_str(), "fir512") == 0)
1182 UhjEncodeQuality
= UhjQualityType::FIR512
;
1183 else if(al::strcasecmp(uhjfiltopt
->c_str(), "iir") == 0)
1184 UhjEncodeQuality
= UhjQualityType::IIR
;
1186 WARN("Unsupported uhj/encode-filter: %s\n", uhjfiltopt
->c_str());
1189 auto traperr
= al::getenv("ALSOFT_TRAP_ERROR");
1190 if(traperr
&& (al::strcasecmp(traperr
->c_str(), "true") == 0
1191 || std::strtol(traperr
->c_str(), nullptr, 0) == 1))
1194 TrapALCError
= true;
1198 traperr
= al::getenv("ALSOFT_TRAP_AL_ERROR");
1200 TrapALError
= al::strcasecmp(traperr
->c_str(), "true") == 0
1201 || strtol(traperr
->c_str(), nullptr, 0) == 1;
1203 TrapALError
= !!GetConfigValueBool(nullptr, nullptr, "trap-al-error", false);
1205 traperr
= al::getenv("ALSOFT_TRAP_ALC_ERROR");
1207 TrapALCError
= al::strcasecmp(traperr
->c_str(), "true") == 0
1208 || strtol(traperr
->c_str(), nullptr, 0) == 1;
1210 TrapALCError
= !!GetConfigValueBool(nullptr, nullptr, "trap-alc-error", false);
1213 if(auto boostopt
= ConfigValueFloat(nullptr, "reverb", "boost"))
1215 const float valf
{std::isfinite(*boostopt
) ? clampf(*boostopt
, -24.0f
, 24.0f
) : 0.0f
};
1216 ReverbBoost
*= std::pow(10.0f
, valf
/ 20.0f
);
1219 auto BackendListEnd
= std::end(BackendList
);
1220 auto devopt
= al::getenv("ALSOFT_DRIVERS");
1221 if(devopt
|| (devopt
=ConfigValueStr(nullptr, nullptr, "drivers")))
1223 auto backendlist_cur
= std::begin(BackendList
);
1226 const char *next
{devopt
->c_str()};
1228 const char *devs
{next
};
1229 while(isspace(devs
[0]))
1231 next
= strchr(devs
, ',');
1233 const bool delitem
{devs
[0] == '-'};
1234 if(devs
[0] == '-') devs
++;
1236 if(!devs
[0] || devs
[0] == ',')
1243 size_t len
{next
? (static_cast<size_t>(next
-devs
)) : strlen(devs
)};
1244 while(len
> 0 && isspace(devs
[len
-1])) --len
;
1246 /* HACK: For backwards compatibility, convert backend references of
1247 * mmdevapi to wasapi. This should eventually be removed.
1249 if(len
== 8 && strncmp(devs
, "mmdevapi", len
) == 0)
1256 auto find_backend
= [devs
,len
](const BackendInfo
&backend
) -> bool
1257 { return len
== strlen(backend
.name
) && strncmp(backend
.name
, devs
, len
) == 0; };
1258 auto this_backend
= std::find_if(std::begin(BackendList
), BackendListEnd
,
1261 if(this_backend
== BackendListEnd
)
1265 BackendListEnd
= std::move(this_backend
+1, BackendListEnd
, this_backend
);
1267 backendlist_cur
= std::rotate(backendlist_cur
, this_backend
, this_backend
+1);
1271 BackendListEnd
= backendlist_cur
;
1274 auto init_backend
= [](BackendInfo
&backend
) -> void
1276 if(PlaybackFactory
&& CaptureFactory
)
1279 BackendFactory
&factory
= backend
.getFactory();
1282 WARN("Failed to initialize backend \"%s\"\n", backend
.name
);
1286 TRACE("Initialized backend \"%s\"\n", backend
.name
);
1287 if(!PlaybackFactory
&& factory
.querySupport(BackendType::Playback
))
1289 PlaybackFactory
= &factory
;
1290 TRACE("Added \"%s\" for playback\n", backend
.name
);
1292 if(!CaptureFactory
&& factory
.querySupport(BackendType::Capture
))
1294 CaptureFactory
= &factory
;
1295 TRACE("Added \"%s\" for capture\n", backend
.name
);
1298 std::for_each(std::begin(BackendList
), BackendListEnd
, init_backend
);
1300 LoopbackBackendFactory::getFactory().init();
1302 if(!PlaybackFactory
)
1303 WARN("No playback backend available!\n");
1305 WARN("No capture backend available!\n");
1307 if(auto exclopt
= ConfigValueStr(nullptr, nullptr, "excludefx"))
1309 const char *next
{exclopt
->c_str()};
1311 const char *str
{next
};
1312 next
= strchr(str
, ',');
1314 if(!str
[0] || next
== str
)
1317 size_t len
{next
? static_cast<size_t>(next
-str
) : strlen(str
)};
1318 for(const EffectList
&effectitem
: gEffectList
)
1320 if(len
== strlen(effectitem
.name
) &&
1321 strncmp(effectitem
.name
, str
, len
) == 0)
1322 DisabledEffects
[effectitem
.type
] = true;
1327 InitEffect(&ALCcontext::sDefaultEffect
);
1328 auto defrevopt
= al::getenv("ALSOFT_DEFAULT_REVERB");
1329 if(defrevopt
|| (defrevopt
=ConfigValueStr(nullptr, nullptr, "default-reverb")))
1330 LoadReverbPreset(defrevopt
->c_str(), &ALCcontext::sDefaultEffect
);
1334 static constexpr char eax_block_name
[] = "eax";
1336 if(const auto eax_enable_opt
= ConfigValueBool(nullptr, eax_block_name
, "enable"))
1338 eax_g_is_enabled
= *eax_enable_opt
;
1339 if(!eax_g_is_enabled
)
1340 TRACE("%s\n", "EAX disabled by a configuration.");
1343 eax_g_is_enabled
= true;
1345 if((DisabledEffects
[EAXREVERB_EFFECT
] || DisabledEffects
[CHORUS_EFFECT
])
1346 && eax_g_is_enabled
)
1348 eax_g_is_enabled
= false;
1349 TRACE("EAX disabled because %s disabled.\n",
1350 (DisabledEffects
[EAXREVERB_EFFECT
] && DisabledEffects
[CHORUS_EFFECT
])
1351 ? "EAXReverb and Chorus are" :
1352 DisabledEffects
[EAXREVERB_EFFECT
] ? "EAXReverb is" :
1353 DisabledEffects
[CHORUS_EFFECT
] ? "Chorus is" : "");
1356 #endif // ALSOFT_EAX
1358 inline void InitConfig()
1359 { std::call_once(alc_config_once
, [](){alc_initconfig();}); }
1362 /************************************************
1363 * Device enumeration
1364 ************************************************/
1365 void ProbeAllDevicesList()
1369 std::lock_guard
<std::recursive_mutex
> _
{ListLock
};
1370 if(!PlaybackFactory
)
1371 decltype(alcAllDevicesList
){}.swap(alcAllDevicesList
);
1374 std::string names
{PlaybackFactory
->probe(BackendType::Playback
)};
1375 if(names
.empty()) names
+= '\0';
1376 names
.swap(alcAllDevicesList
);
1379 void ProbeCaptureDeviceList()
1383 std::lock_guard
<std::recursive_mutex
> _
{ListLock
};
1385 decltype(alcCaptureDeviceList
){}.swap(alcCaptureDeviceList
);
1388 std::string names
{CaptureFactory
->probe(BackendType::Capture
)};
1389 if(names
.empty()) names
+= '\0';
1390 names
.swap(alcCaptureDeviceList
);
1395 struct DevFmtPair
{ DevFmtChannels chans
; DevFmtType type
; };
1396 al::optional
<DevFmtPair
> DecomposeDevFormat(ALenum format
)
1398 static const struct {
1400 DevFmtChannels channels
;
1403 { AL_FORMAT_MONO8
, DevFmtMono
, DevFmtUByte
},
1404 { AL_FORMAT_MONO16
, DevFmtMono
, DevFmtShort
},
1405 { AL_FORMAT_MONO_FLOAT32
, DevFmtMono
, DevFmtFloat
},
1407 { AL_FORMAT_STEREO8
, DevFmtStereo
, DevFmtUByte
},
1408 { AL_FORMAT_STEREO16
, DevFmtStereo
, DevFmtShort
},
1409 { AL_FORMAT_STEREO_FLOAT32
, DevFmtStereo
, DevFmtFloat
},
1411 { AL_FORMAT_QUAD8
, DevFmtQuad
, DevFmtUByte
},
1412 { AL_FORMAT_QUAD16
, DevFmtQuad
, DevFmtShort
},
1413 { AL_FORMAT_QUAD32
, DevFmtQuad
, DevFmtFloat
},
1415 { AL_FORMAT_51CHN8
, DevFmtX51
, DevFmtUByte
},
1416 { AL_FORMAT_51CHN16
, DevFmtX51
, DevFmtShort
},
1417 { AL_FORMAT_51CHN32
, DevFmtX51
, DevFmtFloat
},
1419 { AL_FORMAT_61CHN8
, DevFmtX61
, DevFmtUByte
},
1420 { AL_FORMAT_61CHN16
, DevFmtX61
, DevFmtShort
},
1421 { AL_FORMAT_61CHN32
, DevFmtX61
, DevFmtFloat
},
1423 { AL_FORMAT_71CHN8
, DevFmtX71
, DevFmtUByte
},
1424 { AL_FORMAT_71CHN16
, DevFmtX71
, DevFmtShort
},
1425 { AL_FORMAT_71CHN32
, DevFmtX71
, DevFmtFloat
},
1428 for(const auto &item
: list
)
1430 if(item
.format
== format
)
1431 return al::make_optional(DevFmtPair
{item
.channels
, item
.type
});
1437 al::optional
<DevFmtType
> DevFmtTypeFromEnum(ALCenum type
)
1441 case ALC_BYTE_SOFT
: return al::make_optional(DevFmtByte
);
1442 case ALC_UNSIGNED_BYTE_SOFT
: return al::make_optional(DevFmtUByte
);
1443 case ALC_SHORT_SOFT
: return al::make_optional(DevFmtShort
);
1444 case ALC_UNSIGNED_SHORT_SOFT
: return al::make_optional(DevFmtUShort
);
1445 case ALC_INT_SOFT
: return al::make_optional(DevFmtInt
);
1446 case ALC_UNSIGNED_INT_SOFT
: return al::make_optional(DevFmtUInt
);
1447 case ALC_FLOAT_SOFT
: return al::make_optional(DevFmtFloat
);
1449 WARN("Unsupported format type: 0x%04x\n", type
);
1452 ALCenum
EnumFromDevFmt(DevFmtType type
)
1456 case DevFmtByte
: return ALC_BYTE_SOFT
;
1457 case DevFmtUByte
: return ALC_UNSIGNED_BYTE_SOFT
;
1458 case DevFmtShort
: return ALC_SHORT_SOFT
;
1459 case DevFmtUShort
: return ALC_UNSIGNED_SHORT_SOFT
;
1460 case DevFmtInt
: return ALC_INT_SOFT
;
1461 case DevFmtUInt
: return ALC_UNSIGNED_INT_SOFT
;
1462 case DevFmtFloat
: return ALC_FLOAT_SOFT
;
1464 throw std::runtime_error
{"Invalid DevFmtType: "+std::to_string(int(type
))};
1467 al::optional
<DevFmtChannels
> DevFmtChannelsFromEnum(ALCenum channels
)
1471 case ALC_MONO_SOFT
: return al::make_optional(DevFmtMono
);
1472 case ALC_STEREO_SOFT
: return al::make_optional(DevFmtStereo
);
1473 case ALC_QUAD_SOFT
: return al::make_optional(DevFmtQuad
);
1474 case ALC_5POINT1_SOFT
: return al::make_optional(DevFmtX51
);
1475 case ALC_6POINT1_SOFT
: return al::make_optional(DevFmtX61
);
1476 case ALC_7POINT1_SOFT
: return al::make_optional(DevFmtX71
);
1477 case ALC_BFORMAT3D_SOFT
: return al::make_optional(DevFmtAmbi3D
);
1479 WARN("Unsupported format channels: 0x%04x\n", channels
);
1482 ALCenum
EnumFromDevFmt(DevFmtChannels channels
)
1486 case DevFmtMono
: return ALC_MONO_SOFT
;
1487 case DevFmtStereo
: return ALC_STEREO_SOFT
;
1488 case DevFmtQuad
: return ALC_QUAD_SOFT
;
1489 case DevFmtX51
: return ALC_5POINT1_SOFT
;
1490 case DevFmtX61
: return ALC_6POINT1_SOFT
;
1491 case DevFmtX71
: return ALC_7POINT1_SOFT
;
1492 case DevFmtAmbi3D
: return ALC_BFORMAT3D_SOFT
;
1493 /* FIXME: Shouldn't happen. */
1495 case DevFmtX3D71
: break;
1497 throw std::runtime_error
{"Invalid DevFmtChannels: "+std::to_string(int(channels
))};
1500 al::optional
<DevAmbiLayout
> DevAmbiLayoutFromEnum(ALCenum layout
)
1504 case ALC_FUMA_SOFT
: return al::make_optional(DevAmbiLayout::FuMa
);
1505 case ALC_ACN_SOFT
: return al::make_optional(DevAmbiLayout::ACN
);
1507 WARN("Unsupported ambisonic layout: 0x%04x\n", layout
);
1510 ALCenum
EnumFromDevAmbi(DevAmbiLayout layout
)
1514 case DevAmbiLayout::FuMa
: return ALC_FUMA_SOFT
;
1515 case DevAmbiLayout::ACN
: return ALC_ACN_SOFT
;
1517 throw std::runtime_error
{"Invalid DevAmbiLayout: "+std::to_string(int(layout
))};
1520 al::optional
<DevAmbiScaling
> DevAmbiScalingFromEnum(ALCenum scaling
)
1524 case ALC_FUMA_SOFT
: return al::make_optional(DevAmbiScaling::FuMa
);
1525 case ALC_SN3D_SOFT
: return al::make_optional(DevAmbiScaling::SN3D
);
1526 case ALC_N3D_SOFT
: return al::make_optional(DevAmbiScaling::N3D
);
1528 WARN("Unsupported ambisonic scaling: 0x%04x\n", scaling
);
1531 ALCenum
EnumFromDevAmbi(DevAmbiScaling scaling
)
1535 case DevAmbiScaling::FuMa
: return ALC_FUMA_SOFT
;
1536 case DevAmbiScaling::SN3D
: return ALC_SN3D_SOFT
;
1537 case DevAmbiScaling::N3D
: return ALC_N3D_SOFT
;
1539 throw std::runtime_error
{"Invalid DevAmbiScaling: "+std::to_string(int(scaling
))};
1543 /* Downmixing channel arrays, to map the given format's missing channels to
1544 * existing ones. Based on Wine's DSound downmix values, which are based on
1547 const std::array
<InputRemixMap
,6> StereoDownmix
{{
1548 { FrontCenter
, {{{FrontLeft
, 0.5f
}, {FrontRight
, 0.5f
}}} },
1549 { SideLeft
, {{{FrontLeft
, 1.0f
/9.0f
}}} },
1550 { SideRight
, {{{FrontRight
, 1.0f
/9.0f
}}} },
1551 { BackLeft
, {{{FrontLeft
, 1.0f
/9.0f
}}} },
1552 { BackRight
, {{{FrontRight
, 1.0f
/9.0f
}}} },
1553 { BackCenter
, {{{FrontLeft
, 0.5f
/9.0f
}, {FrontRight
, 0.5f
/9.0f
}}} },
1555 const std::array
<InputRemixMap
,4> QuadDownmix
{{
1556 { FrontCenter
, {{{FrontLeft
, 0.5f
}, {FrontRight
, 0.5f
}}} },
1557 { SideLeft
, {{{FrontLeft
, 0.5f
}, {BackLeft
, 0.5f
}}} },
1558 { SideRight
, {{{FrontRight
, 0.5f
}, {BackRight
, 0.5f
}}} },
1559 { BackCenter
, {{{BackLeft
, 0.5f
}, {BackRight
, 0.5f
}}} },
1561 const std::array
<InputRemixMap
,3> X51Downmix
{{
1562 { BackLeft
, {{{SideLeft
, 1.0f
}}} },
1563 { BackRight
, {{{SideRight
, 1.0f
}}} },
1564 { BackCenter
, {{{SideLeft
, 0.5f
}, {SideRight
, 0.5f
}}} },
1566 const std::array
<InputRemixMap
,2> X61Downmix
{{
1567 { BackLeft
, {{{BackCenter
, 0.5f
}, {SideLeft
, 0.5f
}}} },
1568 { BackRight
, {{{BackCenter
, 0.5f
}, {SideRight
, 0.5f
}}} },
1570 const std::array
<InputRemixMap
,1> X71Downmix
{{
1571 { BackCenter
, {{{BackLeft
, 0.5f
}, {BackRight
, 0.5f
}}} },
1575 /** Stores the latest ALC device error. */
1576 void alcSetError(ALCdevice
*device
, ALCenum errorCode
)
1578 WARN("Error generated on device %p, code 0x%04x\n", voidp
{device
}, errorCode
);
1582 /* DebugBreak() will cause an exception if there is no debugger */
1583 if(IsDebuggerPresent())
1585 #elif defined(SIGTRAP)
1591 device
->LastError
.store(errorCode
);
1593 LastNullDeviceError
.store(errorCode
);
1597 std::unique_ptr
<Compressor
> CreateDeviceLimiter(const ALCdevice
*device
, const float threshold
)
1599 static constexpr bool AutoKnee
{true};
1600 static constexpr bool AutoAttack
{true};
1601 static constexpr bool AutoRelease
{true};
1602 static constexpr bool AutoPostGain
{true};
1603 static constexpr bool AutoDeclip
{true};
1604 static constexpr float LookAheadTime
{0.001f
};
1605 static constexpr float HoldTime
{0.002f
};
1606 static constexpr float PreGainDb
{0.0f
};
1607 static constexpr float PostGainDb
{0.0f
};
1608 static constexpr float Ratio
{std::numeric_limits
<float>::infinity()};
1609 static constexpr float KneeDb
{0.0f
};
1610 static constexpr float AttackTime
{0.02f
};
1611 static constexpr float ReleaseTime
{0.2f
};
1613 return Compressor::Create(device
->RealOut
.Buffer
.size(), static_cast<float>(device
->Frequency
),
1614 AutoKnee
, AutoAttack
, AutoRelease
, AutoPostGain
, AutoDeclip
, LookAheadTime
, HoldTime
,
1615 PreGainDb
, PostGainDb
, threshold
, Ratio
, KneeDb
, AttackTime
, ReleaseTime
);
1619 * Updates the device's base clock time with however many samples have been
1620 * done. This is used so frequency changes on the device don't cause the time
1621 * to jump forward or back. Must not be called while the device is running/
1624 static inline void UpdateClockBase(ALCdevice
*device
)
1626 IncrementRef(device
->MixCount
);
1627 device
->ClockBase
+= nanoseconds
{seconds
{device
->SamplesDone
}} / device
->Frequency
;
1628 device
->SamplesDone
= 0;
1629 IncrementRef(device
->MixCount
);
1633 * Updates device parameters according to the attribute list (caller is
1634 * responsible for holding the list lock).
1636 ALCenum
UpdateDeviceParams(ALCdevice
*device
, const int *attrList
)
1638 if((!attrList
|| !attrList
[0]) && device
->Type
== DeviceType::Loopback
)
1640 WARN("Missing attributes for loopback device\n");
1641 return ALC_INVALID_VALUE
;
1644 uint numMono
{device
->NumMonoSources
};
1645 uint numStereo
{device
->NumStereoSources
};
1646 uint numSends
{device
->NumAuxSends
};
1647 al::optional
<StereoEncoding
> stereomode
;
1648 al::optional
<bool> optlimit
;
1649 al::optional
<uint
> optsrate
;
1650 al::optional
<DevFmtChannels
> optchans
;
1651 al::optional
<DevFmtType
> opttype
;
1652 al::optional
<DevAmbiLayout
> optlayout
;
1653 al::optional
<DevAmbiScaling
> optscale
;
1654 uint period_size
{DEFAULT_UPDATE_SIZE
};
1655 uint buffer_size
{DEFAULT_UPDATE_SIZE
* DEFAULT_NUM_UPDATES
};
1659 if(device
->Type
!= DeviceType::Loopback
)
1661 /* Get default settings from the user configuration */
1663 if(auto freqopt
= device
->configValue
<uint
>(nullptr, "frequency"))
1665 optsrate
= clampu(*freqopt
, MIN_OUTPUT_RATE
, MAX_OUTPUT_RATE
);
1667 const double scale
{static_cast<double>(*optsrate
) / DEFAULT_OUTPUT_RATE
};
1668 period_size
= static_cast<uint
>(period_size
*scale
+ 0.5);
1669 buffer_size
= static_cast<uint
>(buffer_size
*scale
+ 0.5);
1672 if(auto persizeopt
= device
->configValue
<uint
>(nullptr, "period_size"))
1673 period_size
= clampu(*persizeopt
, 64, 8192);
1674 if(auto numperopt
= device
->configValue
<uint
>(nullptr, "periods"))
1675 buffer_size
= clampu(*numperopt
, 2, 16) * period_size
;
1677 buffer_size
= period_size
* DEFAULT_NUM_UPDATES
;
1679 if(auto typeopt
= device
->configValue
<std::string
>(nullptr, "sample-type"))
1681 static constexpr struct TypeMap
{
1685 { "int8", DevFmtByte
},
1686 { "uint8", DevFmtUByte
},
1687 { "int16", DevFmtShort
},
1688 { "uint16", DevFmtUShort
},
1689 { "int32", DevFmtInt
},
1690 { "uint32", DevFmtUInt
},
1691 { "float32", DevFmtFloat
},
1694 const ALCchar
*fmt
{typeopt
->c_str()};
1695 auto iter
= std::find_if(std::begin(typelist
), std::end(typelist
),
1696 [fmt
](const TypeMap
&entry
) -> bool
1697 { return al::strcasecmp(entry
.name
, fmt
) == 0; });
1698 if(iter
== std::end(typelist
))
1699 ERR("Unsupported sample-type: %s\n", fmt
);
1701 opttype
= iter
->type
;
1703 if(auto chanopt
= device
->configValue
<std::string
>(nullptr, "channels"))
1705 static constexpr struct ChannelMap
{
1706 const char name
[16];
1707 DevFmtChannels chans
;
1710 { "mono", DevFmtMono
, 0 },
1711 { "stereo", DevFmtStereo
, 0 },
1712 { "quad", DevFmtQuad
, 0 },
1713 { "surround51", DevFmtX51
, 0 },
1714 { "surround61", DevFmtX61
, 0 },
1715 { "surround71", DevFmtX71
, 0 },
1716 { "surround714", DevFmtX714
, 0 },
1717 { "surround3d71", DevFmtX3D71
, 0 },
1718 { "surround51rear", DevFmtX51
, 0 },
1719 { "ambi1", DevFmtAmbi3D
, 1 },
1720 { "ambi2", DevFmtAmbi3D
, 2 },
1721 { "ambi3", DevFmtAmbi3D
, 3 },
1724 const ALCchar
*fmt
{chanopt
->c_str()};
1725 auto iter
= std::find_if(std::begin(chanlist
), std::end(chanlist
),
1726 [fmt
](const ChannelMap
&entry
) -> bool
1727 { return al::strcasecmp(entry
.name
, fmt
) == 0; });
1728 if(iter
== std::end(chanlist
))
1729 ERR("Unsupported channels: %s\n", fmt
);
1732 optchans
= iter
->chans
;
1733 aorder
= iter
->order
;
1736 if(auto ambiopt
= device
->configValue
<std::string
>(nullptr, "ambi-format"))
1738 const ALCchar
*fmt
{ambiopt
->c_str()};
1739 if(al::strcasecmp(fmt
, "fuma") == 0)
1741 optlayout
= DevAmbiLayout::FuMa
;
1742 optscale
= DevAmbiScaling::FuMa
;
1744 else if(al::strcasecmp(fmt
, "acn+fuma") == 0)
1746 optlayout
= DevAmbiLayout::ACN
;
1747 optscale
= DevAmbiScaling::FuMa
;
1749 else if(al::strcasecmp(fmt
, "ambix") == 0 || al::strcasecmp(fmt
, "acn+sn3d") == 0)
1751 optlayout
= DevAmbiLayout::ACN
;
1752 optscale
= DevAmbiScaling::SN3D
;
1754 else if(al::strcasecmp(fmt
, "acn+n3d") == 0)
1756 optlayout
= DevAmbiLayout::ACN
;
1757 optscale
= DevAmbiScaling::N3D
;
1760 ERR("Unsupported ambi-format: %s\n", fmt
);
1763 if(auto hrtfopt
= device
->configValue
<std::string
>(nullptr, "hrtf"))
1765 WARN("general/hrtf is deprecated, please use stereo-encoding instead\n");
1767 const char *hrtf
{hrtfopt
->c_str()};
1768 if(al::strcasecmp(hrtf
, "true") == 0)
1769 stereomode
= StereoEncoding::Hrtf
;
1770 else if(al::strcasecmp(hrtf
, "false") == 0)
1772 if(!stereomode
|| *stereomode
== StereoEncoding::Hrtf
)
1773 stereomode
= StereoEncoding::Default
;
1775 else if(al::strcasecmp(hrtf
, "auto") != 0)
1776 ERR("Unexpected hrtf value: %s\n", hrtf
);
1780 if(auto encopt
= device
->configValue
<std::string
>(nullptr, "stereo-encoding"))
1782 const char *mode
{encopt
->c_str()};
1783 if(al::strcasecmp(mode
, "basic") == 0 || al::strcasecmp(mode
, "panpot") == 0)
1784 stereomode
= StereoEncoding::Basic
;
1785 else if(al::strcasecmp(mode
, "uhj") == 0)
1786 stereomode
= StereoEncoding::Uhj
;
1787 else if(al::strcasecmp(mode
, "hrtf") == 0)
1788 stereomode
= StereoEncoding::Hrtf
;
1790 ERR("Unexpected stereo-encoding: %s\n", mode
);
1793 // Check for app-specified attributes
1794 if(attrList
&& attrList
[0])
1796 ALenum outmode
{ALC_ANY_SOFT
};
1797 al::optional
<bool> opthrtf
;
1800 #define ATTRIBUTE(a) a: TRACE("%s = %d\n", #a, attrList[attrIdx + 1]);
1802 while(attrList
[attrIdx
])
1804 switch(attrList
[attrIdx
])
1806 case ATTRIBUTE(ALC_FORMAT_CHANNELS_SOFT
)
1807 if(device
->Type
== DeviceType::Loopback
)
1808 optchans
= DevFmtChannelsFromEnum(attrList
[attrIdx
+ 1]);
1811 case ATTRIBUTE(ALC_FORMAT_TYPE_SOFT
)
1812 if(device
->Type
== DeviceType::Loopback
)
1813 opttype
= DevFmtTypeFromEnum(attrList
[attrIdx
+ 1]);
1816 case ATTRIBUTE(ALC_FREQUENCY
)
1817 freqAttr
= attrList
[attrIdx
+ 1];
1820 case ATTRIBUTE(ALC_AMBISONIC_LAYOUT_SOFT
)
1821 if(device
->Type
== DeviceType::Loopback
)
1822 optlayout
= DevAmbiLayoutFromEnum(attrList
[attrIdx
+ 1]);
1825 case ATTRIBUTE(ALC_AMBISONIC_SCALING_SOFT
)
1826 if(device
->Type
== DeviceType::Loopback
)
1827 optscale
= DevAmbiScalingFromEnum(attrList
[attrIdx
+ 1]);
1830 case ATTRIBUTE(ALC_AMBISONIC_ORDER_SOFT
)
1831 if(device
->Type
== DeviceType::Loopback
)
1832 aorder
= static_cast<uint
>(attrList
[attrIdx
+ 1]);
1835 case ATTRIBUTE(ALC_MONO_SOURCES
)
1836 numMono
= static_cast<uint
>(attrList
[attrIdx
+ 1]);
1837 if(numMono
> INT_MAX
) numMono
= 0;
1840 case ATTRIBUTE(ALC_STEREO_SOURCES
)
1841 numStereo
= static_cast<uint
>(attrList
[attrIdx
+ 1]);
1842 if(numStereo
> INT_MAX
) numStereo
= 0;
1845 case ATTRIBUTE(ALC_MAX_AUXILIARY_SENDS
)
1846 numSends
= static_cast<uint
>(attrList
[attrIdx
+ 1]);
1847 if(numSends
> INT_MAX
) numSends
= 0;
1848 else numSends
= minu(numSends
, MAX_SENDS
);
1851 case ATTRIBUTE(ALC_HRTF_SOFT
)
1852 if(attrList
[attrIdx
+ 1] == ALC_FALSE
)
1854 else if(attrList
[attrIdx
+ 1] == ALC_TRUE
)
1856 else if(attrList
[attrIdx
+ 1] == ALC_DONT_CARE_SOFT
)
1857 opthrtf
= al::nullopt
;
1860 case ATTRIBUTE(ALC_HRTF_ID_SOFT
)
1861 hrtf_id
= attrList
[attrIdx
+ 1];
1864 case ATTRIBUTE(ALC_OUTPUT_LIMITER_SOFT
)
1865 if(attrList
[attrIdx
+ 1] == ALC_FALSE
)
1867 else if(attrList
[attrIdx
+ 1] == ALC_TRUE
)
1869 else if(attrList
[attrIdx
+ 1] == ALC_DONT_CARE_SOFT
)
1870 optlimit
= al::nullopt
;
1873 case ATTRIBUTE(ALC_OUTPUT_MODE_SOFT
)
1874 outmode
= attrList
[attrIdx
+ 1];
1878 TRACE("0x%04X = %d (0x%x)\n", attrList
[attrIdx
],
1879 attrList
[attrIdx
+ 1], attrList
[attrIdx
+ 1]);
1887 if(device
->Type
== DeviceType::Loopback
)
1889 if(!optchans
|| !opttype
)
1890 return ALC_INVALID_VALUE
;
1891 if(freqAttr
< MIN_OUTPUT_RATE
|| freqAttr
> MAX_OUTPUT_RATE
)
1892 return ALC_INVALID_VALUE
;
1893 if(*optchans
== DevFmtAmbi3D
)
1895 if(!optlayout
|| !optscale
)
1896 return ALC_INVALID_VALUE
;
1897 if(aorder
< 1 || aorder
> MaxAmbiOrder
)
1898 return ALC_INVALID_VALUE
;
1899 if((*optlayout
== DevAmbiLayout::FuMa
|| *optscale
== DevAmbiScaling::FuMa
)
1901 return ALC_INVALID_VALUE
;
1903 else if(*optchans
== DevFmtStereo
)
1908 stereomode
= StereoEncoding::Hrtf
;
1911 if(stereomode
.value_or(StereoEncoding::Hrtf
) == StereoEncoding::Hrtf
)
1912 stereomode
= StereoEncoding::Default
;
1916 if(outmode
== ALC_STEREO_BASIC_SOFT
)
1917 stereomode
= StereoEncoding::Basic
;
1918 else if(outmode
== ALC_STEREO_UHJ_SOFT
)
1919 stereomode
= StereoEncoding::Uhj
;
1920 else if(outmode
== ALC_STEREO_HRTF_SOFT
)
1921 stereomode
= StereoEncoding::Hrtf
;
1924 optsrate
= static_cast<uint
>(freqAttr
);
1931 stereomode
= StereoEncoding::Hrtf
;
1934 if(stereomode
.value_or(StereoEncoding::Hrtf
) == StereoEncoding::Hrtf
)
1935 stereomode
= StereoEncoding::Default
;
1939 if(outmode
!= ALC_ANY_SOFT
)
1941 using OutputMode
= ALCdevice::OutputMode
;
1942 switch(OutputMode(outmode
))
1944 case OutputMode::Any
: break;
1945 case OutputMode::Mono
: optchans
= DevFmtMono
; break;
1946 case OutputMode::Stereo
: optchans
= DevFmtStereo
; break;
1947 case OutputMode::StereoBasic
:
1948 optchans
= DevFmtStereo
;
1949 stereomode
= StereoEncoding::Basic
;
1951 case OutputMode::Uhj2
:
1952 optchans
= DevFmtStereo
;
1953 stereomode
= StereoEncoding::Uhj
;
1955 case OutputMode::Hrtf
:
1956 optchans
= DevFmtStereo
;
1957 stereomode
= StereoEncoding::Hrtf
;
1959 case OutputMode::Quad
: optchans
= DevFmtQuad
; break;
1960 case OutputMode::X51
: optchans
= DevFmtX51
; break;
1961 case OutputMode::X61
: optchans
= DevFmtX61
; break;
1962 case OutputMode::X71
: optchans
= DevFmtX71
; break;
1968 uint oldrate
= optsrate
.value_or(DEFAULT_OUTPUT_RATE
);
1969 freqAttr
= clampi(freqAttr
, MIN_OUTPUT_RATE
, MAX_OUTPUT_RATE
);
1971 const double scale
{static_cast<double>(freqAttr
) / oldrate
};
1972 period_size
= static_cast<uint
>(period_size
*scale
+ 0.5);
1973 buffer_size
= static_cast<uint
>(buffer_size
*scale
+ 0.5);
1974 optsrate
= static_cast<uint
>(freqAttr
);
1978 /* If a context is already running on the device, stop playback so the
1979 * device attributes can be updated.
1981 if(device
->Flags
.test(DeviceRunning
))
1982 device
->Backend
->stop();
1983 device
->Flags
.reset(DeviceRunning
);
1985 UpdateClockBase(device
);
1988 if(device
->Flags
.test(DeviceRunning
))
1989 return ALC_NO_ERROR
;
1991 device
->AvgSpeakerDist
= 0.0f
;
1992 device
->mNFCtrlFilter
= NfcFilter
{};
1993 device
->mUhjEncoder
= nullptr;
1994 device
->AmbiDecoder
= nullptr;
1995 device
->Bs2b
= nullptr;
1996 device
->PostProcess
= nullptr;
1998 device
->Limiter
= nullptr;
1999 device
->ChannelDelays
= nullptr;
2001 std::fill(std::begin(device
->HrtfAccumData
), std::end(device
->HrtfAccumData
), float2
{});
2003 device
->Dry
.AmbiMap
.fill(BFChannelConfig
{});
2004 device
->Dry
.Buffer
= {};
2005 std::fill(std::begin(device
->NumChannelsPerOrder
), std::end(device
->NumChannelsPerOrder
), 0u);
2006 device
->RealOut
.RemixMap
= {};
2007 device
->RealOut
.ChannelIndex
.fill(INVALID_CHANNEL_INDEX
);
2008 device
->RealOut
.Buffer
= {};
2009 device
->MixBuffer
.clear();
2010 device
->MixBuffer
.shrink_to_fit();
2012 UpdateClockBase(device
);
2013 device
->FixedLatency
= nanoseconds::zero();
2015 device
->DitherDepth
= 0.0f
;
2016 device
->DitherSeed
= DitherRNGSeed
;
2018 device
->mHrtfStatus
= ALC_HRTF_DISABLED_SOFT
;
2020 /*************************************************************************
2021 * Update device format request
2024 if(device
->Type
== DeviceType::Loopback
)
2026 device
->Frequency
= *optsrate
;
2027 device
->FmtChans
= *optchans
;
2028 device
->FmtType
= *opttype
;
2029 if(device
->FmtChans
== DevFmtAmbi3D
)
2031 device
->mAmbiOrder
= aorder
;
2032 device
->mAmbiLayout
= *optlayout
;
2033 device
->mAmbiScale
= *optscale
;
2035 device
->Flags
.set(FrequencyRequest
).set(ChannelsRequest
).set(SampleTypeRequest
);
2039 device
->FmtType
= opttype
.value_or(DevFmtTypeDefault
);
2040 device
->FmtChans
= optchans
.value_or(DevFmtChannelsDefault
);
2041 device
->mAmbiOrder
= 0;
2042 device
->BufferSize
= buffer_size
;
2043 device
->UpdateSize
= period_size
;
2044 device
->Frequency
= optsrate
.value_or(DEFAULT_OUTPUT_RATE
);
2045 device
->Flags
.set(FrequencyRequest
, optsrate
.has_value())
2046 .set(ChannelsRequest
, optchans
.has_value())
2047 .set(SampleTypeRequest
, opttype
.has_value());
2049 if(device
->FmtChans
== DevFmtAmbi3D
)
2051 device
->mAmbiOrder
= clampu(aorder
, 1, MaxAmbiOrder
);
2052 device
->mAmbiLayout
= optlayout
.value_or(DevAmbiLayout::Default
);
2053 device
->mAmbiScale
= optscale
.value_or(DevAmbiScaling::Default
);
2054 if(device
->mAmbiOrder
> 3
2055 && (device
->mAmbiLayout
== DevAmbiLayout::FuMa
2056 || device
->mAmbiScale
== DevAmbiScaling::FuMa
))
2058 ERR("FuMa is incompatible with %d%s order ambisonics (up to 3rd order only)\n",
2060 (((device
->mAmbiOrder
%100)/10) == 1) ? "th" :
2061 ((device
->mAmbiOrder
%10) == 1) ? "st" :
2062 ((device
->mAmbiOrder
%10) == 2) ? "nd" :
2063 ((device
->mAmbiOrder
%10) == 3) ? "rd" : "th");
2064 device
->mAmbiOrder
= 3;
2069 TRACE("Pre-reset: %s%s, %s%s, %s%uhz, %u / %u buffer\n",
2070 device
->Flags
.test(ChannelsRequest
)?"*":"", DevFmtChannelsString(device
->FmtChans
),
2071 device
->Flags
.test(SampleTypeRequest
)?"*":"", DevFmtTypeString(device
->FmtType
),
2072 device
->Flags
.test(FrequencyRequest
)?"*":"", device
->Frequency
,
2073 device
->UpdateSize
, device
->BufferSize
);
2075 const uint oldFreq
{device
->Frequency
};
2076 const DevFmtChannels oldChans
{device
->FmtChans
};
2077 const DevFmtType oldType
{device
->FmtType
};
2079 auto backend
= device
->Backend
.get();
2080 if(!backend
->reset())
2081 throw al::backend_exception
{al::backend_error::DeviceError
, "Device reset failure"};
2083 catch(std::exception
&e
) {
2084 ERR("Device error: %s\n", e
.what());
2085 device
->handleDisconnect("%s", e
.what());
2086 return ALC_INVALID_DEVICE
;
2089 if(device
->FmtChans
!= oldChans
&& device
->Flags
.test(ChannelsRequest
))
2091 ERR("Failed to set %s, got %s instead\n", DevFmtChannelsString(oldChans
),
2092 DevFmtChannelsString(device
->FmtChans
));
2093 device
->Flags
.reset(ChannelsRequest
);
2095 if(device
->FmtType
!= oldType
&& device
->Flags
.test(SampleTypeRequest
))
2097 ERR("Failed to set %s, got %s instead\n", DevFmtTypeString(oldType
),
2098 DevFmtTypeString(device
->FmtType
));
2099 device
->Flags
.reset(SampleTypeRequest
);
2101 if(device
->Frequency
!= oldFreq
&& device
->Flags
.test(FrequencyRequest
))
2103 WARN("Failed to set %uhz, got %uhz instead\n", oldFreq
, device
->Frequency
);
2104 device
->Flags
.reset(FrequencyRequest
);
2107 TRACE("Post-reset: %s, %s, %uhz, %u / %u buffer\n",
2108 DevFmtChannelsString(device
->FmtChans
), DevFmtTypeString(device
->FmtType
),
2109 device
->Frequency
, device
->UpdateSize
, device
->BufferSize
);
2111 if(device
->Type
!= DeviceType::Loopback
)
2113 if(auto modeopt
= device
->configValue
<std::string
>(nullptr, "stereo-mode"))
2115 const char *mode
{modeopt
->c_str()};
2116 if(al::strcasecmp(mode
, "headphones") == 0)
2117 device
->Flags
.set(DirectEar
);
2118 else if(al::strcasecmp(mode
, "speakers") == 0)
2119 device
->Flags
.reset(DirectEar
);
2120 else if(al::strcasecmp(mode
, "auto") != 0)
2121 ERR("Unexpected stereo-mode: %s\n", mode
);
2125 aluInitRenderer(device
, hrtf_id
, stereomode
);
2127 /* Calculate the max number of sources, and split them between the mono and
2128 * stereo count given the requested number of stereo sources.
2130 if(auto srcsopt
= device
->configValue
<uint
>(nullptr, "sources"))
2132 if(*srcsopt
<= 0) numMono
= 256;
2133 else numMono
= maxu(*srcsopt
, 16);
2137 numMono
= minu(numMono
, INT_MAX
-numStereo
);
2138 numMono
= maxu(numMono
+numStereo
, 256);
2140 numStereo
= minu(numStereo
, numMono
);
2141 numMono
-= numStereo
;
2142 device
->SourcesMax
= numMono
+ numStereo
;
2143 device
->NumMonoSources
= numMono
;
2144 device
->NumStereoSources
= numStereo
;
2146 if(auto sendsopt
= device
->configValue
<int>(nullptr, "sends"))
2147 numSends
= minu(numSends
, static_cast<uint
>(clampi(*sendsopt
, 0, MAX_SENDS
)));
2148 device
->NumAuxSends
= numSends
;
2150 TRACE("Max sources: %d (%d + %d), effect slots: %d, sends: %d\n",
2151 device
->SourcesMax
, device
->NumMonoSources
, device
->NumStereoSources
,
2152 device
->AuxiliaryEffectSlotMax
, device
->NumAuxSends
);
2154 switch(device
->FmtChans
)
2156 case DevFmtMono
: break;
2158 if(!device
->mUhjEncoder
)
2159 device
->RealOut
.RemixMap
= StereoDownmix
;
2161 case DevFmtQuad
: device
->RealOut
.RemixMap
= QuadDownmix
; break;
2162 case DevFmtX51
: device
->RealOut
.RemixMap
= X51Downmix
; break;
2163 case DevFmtX61
: device
->RealOut
.RemixMap
= X61Downmix
; break;
2164 case DevFmtX71
: device
->RealOut
.RemixMap
= X71Downmix
; break;
2165 case DevFmtX714
: device
->RealOut
.RemixMap
= X71Downmix
; break;
2166 case DevFmtX3D71
: device
->RealOut
.RemixMap
= X51Downmix
; break;
2167 case DevFmtAmbi3D
: break;
2170 nanoseconds::rep sample_delay
{0};
2171 if(auto *encoder
{device
->mUhjEncoder
.get()})
2172 sample_delay
+= encoder
->getDelay();
2174 if(device
->getConfigValueBool(nullptr, "dither", true))
2176 int depth
{device
->configValue
<int>(nullptr, "dither-depth").value_or(0)};
2179 switch(device
->FmtType
)
2198 depth
= clampi(depth
, 2, 24);
2199 device
->DitherDepth
= std::pow(2.0f
, static_cast<float>(depth
-1));
2202 if(!(device
->DitherDepth
> 0.0f
))
2203 TRACE("Dithering disabled\n");
2205 TRACE("Dithering enabled (%d-bit, %g)\n", float2int(std::log2(device
->DitherDepth
)+0.5f
)+1,
2206 device
->DitherDepth
);
2209 optlimit
= device
->configValue
<bool>(nullptr, "output-limiter");
2211 /* If the gain limiter is unset, use the limiter for integer-based output
2212 * (where samples must be clamped), and don't for floating-point (which can
2213 * take unclamped samples).
2217 switch(device
->FmtType
)
2231 if(optlimit
.value_or(false) == false)
2232 TRACE("Output limiter disabled\n");
2235 float thrshld
{1.0f
};
2236 switch(device
->FmtType
)
2240 thrshld
= 127.0f
/ 128.0f
;
2244 thrshld
= 32767.0f
/ 32768.0f
;
2251 if(device
->DitherDepth
> 0.0f
)
2252 thrshld
-= 1.0f
/ device
->DitherDepth
;
2254 const float thrshld_dB
{std::log10(thrshld
) * 20.0f
};
2255 auto limiter
= CreateDeviceLimiter(device
, thrshld_dB
);
2257 sample_delay
+= limiter
->getLookAhead();
2258 device
->Limiter
= std::move(limiter
);
2259 TRACE("Output limiter enabled, %.4fdB limit\n", thrshld_dB
);
2262 /* Convert the sample delay from samples to nanosamples to nanoseconds. */
2263 device
->FixedLatency
+= nanoseconds
{seconds
{sample_delay
}} / device
->Frequency
;
2264 TRACE("Fixed device latency: %" PRId64
"ns\n", int64_t{device
->FixedLatency
.count()});
2266 FPUCtl mixer_mode
{};
2267 for(ContextBase
*ctxbase
: *device
->mContexts
.load())
2269 auto *context
= static_cast<ALCcontext
*>(ctxbase
);
2271 auto GetEffectBuffer
= [](ALbuffer
*buffer
) noexcept
-> EffectState::Buffer
2273 if(!buffer
) return EffectState::Buffer
{};
2274 return EffectState::Buffer
{buffer
, buffer
->mData
};
2276 std::unique_lock
<std::mutex
> proplock
{context
->mPropLock
};
2277 std::unique_lock
<std::mutex
> slotlock
{context
->mEffectSlotLock
};
2279 /* Clear out unused effect slot clusters. */
2280 auto slot_cluster_not_in_use
= [](ContextBase::EffectSlotCluster
&cluster
)
2282 for(size_t i
{0};i
< ContextBase::EffectSlotClusterSize
;++i
)
2284 if(cluster
[i
].InUse
)
2289 auto slotcluster_iter
= std::remove_if(context
->mEffectSlotClusters
.begin(),
2290 context
->mEffectSlotClusters
.end(), slot_cluster_not_in_use
);
2291 context
->mEffectSlotClusters
.erase(slotcluster_iter
, context
->mEffectSlotClusters
.end());
2293 /* Free all wet buffers. Any in use will be reallocated with an updated
2294 * configuration in aluInitEffectPanning.
2296 for(auto&& slots
: context
->mEffectSlotClusters
)
2298 for(size_t i
{0};i
< ContextBase::EffectSlotClusterSize
;++i
)
2300 slots
[i
].mWetBuffer
.clear();
2301 slots
[i
].mWetBuffer
.shrink_to_fit();
2302 slots
[i
].Wet
.Buffer
= {};
2306 if(ALeffectslot
*slot
{context
->mDefaultSlot
.get()})
2308 aluInitEffectPanning(slot
->mSlot
, context
);
2310 EffectState
*state
{slot
->Effect
.State
.get()};
2311 state
->mOutTarget
= device
->Dry
.Buffer
;
2312 state
->deviceUpdate(device
, GetEffectBuffer(slot
->Buffer
));
2313 slot
->updateProps(context
);
2316 if(EffectSlotArray
*curarray
{context
->mActiveAuxSlots
.load(std::memory_order_relaxed
)})
2317 std::fill_n(curarray
->end(), curarray
->size(), nullptr);
2318 for(auto &sublist
: context
->mEffectSlotList
)
2320 uint64_t usemask
{~sublist
.FreeMask
};
2323 const int idx
{al::countr_zero(usemask
)};
2324 ALeffectslot
*slot
{sublist
.EffectSlots
+ idx
};
2325 usemask
&= ~(1_u64
<< idx
);
2327 aluInitEffectPanning(slot
->mSlot
, context
);
2329 EffectState
*state
{slot
->Effect
.State
.get()};
2330 state
->mOutTarget
= device
->Dry
.Buffer
;
2331 state
->deviceUpdate(device
, GetEffectBuffer(slot
->Buffer
));
2332 slot
->updateProps(context
);
2337 const uint num_sends
{device
->NumAuxSends
};
2338 std::unique_lock
<std::mutex
> srclock
{context
->mSourceLock
};
2339 for(auto &sublist
: context
->mSourceList
)
2341 uint64_t usemask
{~sublist
.FreeMask
};
2344 const int idx
{al::countr_zero(usemask
)};
2345 ALsource
*source
{sublist
.Sources
+ idx
};
2346 usemask
&= ~(1_u64
<< idx
);
2348 auto clear_send
= [](ALsource::SendData
&send
) -> void
2351 DecrementRef(send
.Slot
->ref
);
2352 send
.Slot
= nullptr;
2355 send
.HFReference
= LOWPASSFREQREF
;
2357 send
.LFReference
= HIGHPASSFREQREF
;
2359 auto send_begin
= source
->Send
.begin() + static_cast<ptrdiff_t>(num_sends
);
2360 std::for_each(send_begin
, source
->Send
.end(), clear_send
);
2362 source
->mPropsDirty
= true;
2366 auto voicelist
= context
->getVoicesSpan();
2367 for(Voice
*voice
: voicelist
)
2369 /* Clear extraneous property set sends. */
2370 std::fill(std::begin(voice
->mProps
.Send
)+num_sends
, std::end(voice
->mProps
.Send
),
2371 VoiceProps::SendData
{});
2373 std::fill(voice
->mSend
.begin()+num_sends
, voice
->mSend
.end(), Voice::TargetData
{});
2374 for(auto &chandata
: voice
->mChans
)
2376 std::fill(chandata
.mWetParams
.begin()+num_sends
, chandata
.mWetParams
.end(),
2380 if(VoicePropsItem
*props
{voice
->mUpdate
.exchange(nullptr, std::memory_order_relaxed
)})
2381 AtomicReplaceHead(context
->mFreeVoiceProps
, props
);
2383 /* Force the voice to stopped if it was stopping. */
2384 Voice::State vstate
{Voice::Stopping
};
2385 voice
->mPlayState
.compare_exchange_strong(vstate
, Voice::Stopped
,
2386 std::memory_order_acquire
, std::memory_order_acquire
);
2387 if(voice
->mSourceID
.load(std::memory_order_relaxed
) == 0u)
2390 voice
->prepare(device
);
2392 /* Clear all voice props to let them get allocated again. */
2393 context
->mVoicePropClusters
.clear();
2394 context
->mFreeVoiceProps
.store(nullptr, std::memory_order_relaxed
);
2397 context
->mPropsDirty
= false;
2398 UpdateContextProps(context
);
2399 UpdateAllSourceProps(context
);
2403 if(!device
->Flags
.test(DevicePaused
))
2406 auto backend
= device
->Backend
.get();
2408 device
->Flags
.set(DeviceRunning
);
2410 catch(al::backend_exception
& e
) {
2411 ERR("%s\n", e
.what());
2412 device
->handleDisconnect("%s", e
.what());
2413 return ALC_INVALID_DEVICE
;
2415 TRACE("Post-start: %s, %s, %uhz, %u / %u buffer\n",
2416 DevFmtChannelsString(device
->FmtChans
), DevFmtTypeString(device
->FmtType
),
2417 device
->Frequency
, device
->UpdateSize
, device
->BufferSize
);
2420 return ALC_NO_ERROR
;
2424 * Updates device parameters as above, and also first clears the disconnected
2427 bool ResetDeviceParams(ALCdevice
*device
, const int *attrList
)
2429 /* If the device was disconnected, reset it since we're opened anew. */
2430 if(!device
->Connected
.load(std::memory_order_relaxed
)) [[unlikely
]]
2432 /* Make sure disconnection is finished before continuing on. */
2433 device
->waitForMix();
2435 for(ContextBase
*ctxbase
: *device
->mContexts
.load(std::memory_order_acquire
))
2437 auto *ctx
= static_cast<ALCcontext
*>(ctxbase
);
2438 if(!ctx
->mStopVoicesOnDisconnect
.load(std::memory_order_acquire
))
2441 /* Clear any pending voice changes and reallocate voices to get a
2444 std::lock_guard
<std::mutex
> __
{ctx
->mSourceLock
};
2445 auto *vchg
= ctx
->mCurrentVoiceChange
.load(std::memory_order_acquire
);
2446 while(auto *next
= vchg
->mNext
.load(std::memory_order_acquire
))
2448 ctx
->mCurrentVoiceChange
.store(vchg
, std::memory_order_release
);
2450 ctx
->mVoicePropClusters
.clear();
2451 ctx
->mFreeVoiceProps
.store(nullptr, std::memory_order_relaxed
);
2453 ctx
->mVoiceClusters
.clear();
2454 ctx
->allocVoices(std::max
<size_t>(256,
2455 ctx
->mActiveVoiceCount
.load(std::memory_order_relaxed
)));
2458 device
->Connected
.store(true);
2461 ALCenum err
{UpdateDeviceParams(device
, attrList
)};
2462 if(err
== ALC_NO_ERROR
) [[likely
]] return ALC_TRUE
;
2464 alcSetError(device
, err
);
2469 /** Checks if the device handle is valid, and returns a new reference if so. */
2470 DeviceRef
VerifyDevice(ALCdevice
*device
)
2472 std::lock_guard
<std::recursive_mutex
> _
{ListLock
};
2473 auto iter
= std::lower_bound(DeviceList
.begin(), DeviceList
.end(), device
);
2474 if(iter
!= DeviceList
.end() && *iter
== device
)
2477 return DeviceRef
{*iter
};
2484 * Checks if the given context is valid, returning a new reference to it if so.
2486 ContextRef
VerifyContext(ALCcontext
*context
)
2488 std::lock_guard
<std::recursive_mutex
> _
{ListLock
};
2489 auto iter
= std::lower_bound(ContextList
.begin(), ContextList
.end(), context
);
2490 if(iter
!= ContextList
.end() && *iter
== context
)
2493 return ContextRef
{*iter
};
2500 /** Returns a new reference to the currently active context for this thread. */
2501 ContextRef
GetContextRef(void)
2503 ALCcontext
*context
{ALCcontext::getThreadContext()};
2508 while(ALCcontext::sGlobalContextLock
.exchange(true, std::memory_order_acquire
)) {
2509 /* Wait to make sure another thread isn't trying to change the
2510 * current context and bring its refcount to 0.
2513 context
= ALCcontext::sGlobalContext
.load(std::memory_order_acquire
);
2514 if(context
) [[likely
]] context
->add_ref();
2515 ALCcontext::sGlobalContextLock
.store(false, std::memory_order_release
);
2517 return ContextRef
{context
};
2521 /************************************************
2522 * Standard ALC functions
2523 ************************************************/
2525 ALC_API ALCenum ALC_APIENTRY
alcGetError(ALCdevice
*device
)
2528 DeviceRef dev
{VerifyDevice(device
)};
2529 if(dev
) return dev
->LastError
.exchange(ALC_NO_ERROR
);
2530 return LastNullDeviceError
.exchange(ALC_NO_ERROR
);
2535 ALC_API
void ALC_APIENTRY
alcSuspendContext(ALCcontext
*context
)
2541 ContextRef ctx
{VerifyContext(context
)};
2543 alcSetError(nullptr, ALC_INVALID_CONTEXT
);
2546 std::lock_guard
<std::mutex
> _
{ctx
->mPropLock
};
2547 ctx
->deferUpdates();
2552 ALC_API
void ALC_APIENTRY
alcProcessContext(ALCcontext
*context
)
2558 ContextRef ctx
{VerifyContext(context
)};
2560 alcSetError(nullptr, ALC_INVALID_CONTEXT
);
2563 std::lock_guard
<std::mutex
> _
{ctx
->mPropLock
};
2564 ctx
->processUpdates();
2570 ALC_API
const ALCchar
* ALC_APIENTRY
alcGetString(ALCdevice
*Device
, ALCenum param
)
2573 const ALCchar
*value
{nullptr};
2581 case ALC_INVALID_ENUM
:
2582 value
= alcErrInvalidEnum
;
2585 case ALC_INVALID_VALUE
:
2586 value
= alcErrInvalidValue
;
2589 case ALC_INVALID_DEVICE
:
2590 value
= alcErrInvalidDevice
;
2593 case ALC_INVALID_CONTEXT
:
2594 value
= alcErrInvalidContext
;
2597 case ALC_OUT_OF_MEMORY
:
2598 value
= alcErrOutOfMemory
;
2601 case ALC_DEVICE_SPECIFIER
:
2602 value
= alcDefaultName
;
2605 case ALC_ALL_DEVICES_SPECIFIER
:
2606 if(DeviceRef dev
{VerifyDevice(Device
)})
2608 if(dev
->Type
== DeviceType::Capture
)
2609 alcSetError(dev
.get(), ALC_INVALID_ENUM
);
2610 else if(dev
->Type
== DeviceType::Loopback
)
2611 value
= alcDefaultName
;
2614 std::lock_guard
<std::mutex
> _
{dev
->StateLock
};
2615 value
= dev
->DeviceName
.c_str();
2620 ProbeAllDevicesList();
2621 value
= alcAllDevicesList
.c_str();
2625 case ALC_CAPTURE_DEVICE_SPECIFIER
:
2626 if(DeviceRef dev
{VerifyDevice(Device
)})
2628 if(dev
->Type
!= DeviceType::Capture
)
2629 alcSetError(dev
.get(), ALC_INVALID_ENUM
);
2632 std::lock_guard
<std::mutex
> _
{dev
->StateLock
};
2633 value
= dev
->DeviceName
.c_str();
2638 ProbeCaptureDeviceList();
2639 value
= alcCaptureDeviceList
.c_str();
2643 /* Default devices are always first in the list */
2644 case ALC_DEFAULT_DEVICE_SPECIFIER
:
2645 value
= alcDefaultName
;
2648 case ALC_DEFAULT_ALL_DEVICES_SPECIFIER
:
2649 if(alcAllDevicesList
.empty())
2650 ProbeAllDevicesList();
2652 /* Copy first entry as default. */
2653 alcDefaultAllDevicesSpecifier
= alcAllDevicesList
.c_str();
2654 value
= alcDefaultAllDevicesSpecifier
.c_str();
2657 case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER
:
2658 if(alcCaptureDeviceList
.empty())
2659 ProbeCaptureDeviceList();
2661 /* Copy first entry as default. */
2662 alcCaptureDefaultDeviceSpecifier
= alcCaptureDeviceList
.c_str();
2663 value
= alcCaptureDefaultDeviceSpecifier
.c_str();
2666 case ALC_EXTENSIONS
:
2667 if(VerifyDevice(Device
))
2668 value
= alcExtensionList
;
2670 value
= alcNoDeviceExtList
;
2673 case ALC_HRTF_SPECIFIER_SOFT
:
2674 if(DeviceRef dev
{VerifyDevice(Device
)})
2676 std::lock_guard
<std::mutex
> _
{dev
->StateLock
};
2677 value
= (dev
->mHrtf
? dev
->mHrtfName
.c_str() : "");
2680 alcSetError(nullptr, ALC_INVALID_DEVICE
);
2684 alcSetError(VerifyDevice(Device
).get(), ALC_INVALID_ENUM
);
2693 static size_t GetIntegerv(ALCdevice
*device
, ALCenum param
, const al::span
<int> values
)
2699 alcSetError(device
, ALC_INVALID_VALUE
);
2707 case ALC_MAJOR_VERSION
:
2708 values
[0] = alcMajorVersion
;
2710 case ALC_MINOR_VERSION
:
2711 values
[0] = alcMinorVersion
;
2714 case ALC_EFX_MAJOR_VERSION
:
2715 values
[0] = alcEFXMajorVersion
;
2717 case ALC_EFX_MINOR_VERSION
:
2718 values
[0] = alcEFXMinorVersion
;
2720 case ALC_MAX_AUXILIARY_SENDS
:
2721 values
[0] = MAX_SENDS
;
2724 case ALC_ATTRIBUTES_SIZE
:
2725 case ALC_ALL_ATTRIBUTES
:
2729 case ALC_MONO_SOURCES
:
2730 case ALC_STEREO_SOURCES
:
2731 case ALC_CAPTURE_SAMPLES
:
2732 case ALC_FORMAT_CHANNELS_SOFT
:
2733 case ALC_FORMAT_TYPE_SOFT
:
2734 case ALC_AMBISONIC_LAYOUT_SOFT
:
2735 case ALC_AMBISONIC_SCALING_SOFT
:
2736 case ALC_AMBISONIC_ORDER_SOFT
:
2737 case ALC_MAX_AMBISONIC_ORDER_SOFT
:
2738 alcSetError(nullptr, ALC_INVALID_DEVICE
);
2742 alcSetError(nullptr, ALC_INVALID_ENUM
);
2747 std::lock_guard
<std::mutex
> _
{device
->StateLock
};
2748 if(device
->Type
== DeviceType::Capture
)
2750 static constexpr int MaxCaptureAttributes
{9};
2753 case ALC_ATTRIBUTES_SIZE
:
2754 values
[0] = MaxCaptureAttributes
;
2756 case ALC_ALL_ATTRIBUTES
:
2758 if(values
.size() < MaxCaptureAttributes
)
2759 alcSetError(device
, ALC_INVALID_VALUE
);
2762 values
[i
++] = ALC_MAJOR_VERSION
;
2763 values
[i
++] = alcMajorVersion
;
2764 values
[i
++] = ALC_MINOR_VERSION
;
2765 values
[i
++] = alcMinorVersion
;
2766 values
[i
++] = ALC_CAPTURE_SAMPLES
;
2767 values
[i
++] = static_cast<int>(device
->Backend
->availableSamples());
2768 values
[i
++] = ALC_CONNECTED
;
2769 values
[i
++] = device
->Connected
.load(std::memory_order_relaxed
);
2771 assert(i
== MaxCaptureAttributes
);
2775 case ALC_MAJOR_VERSION
:
2776 values
[0] = alcMajorVersion
;
2778 case ALC_MINOR_VERSION
:
2779 values
[0] = alcMinorVersion
;
2782 case ALC_CAPTURE_SAMPLES
:
2783 values
[0] = static_cast<int>(device
->Backend
->availableSamples());
2787 values
[0] = device
->Connected
.load(std::memory_order_acquire
);
2791 alcSetError(device
, ALC_INVALID_ENUM
);
2797 auto NumAttrsForDevice
= [](ALCdevice
*aldev
) noexcept
2799 if(aldev
->Type
== DeviceType::Loopback
&& aldev
->FmtChans
== DevFmtAmbi3D
)
2805 case ALC_ATTRIBUTES_SIZE
:
2806 values
[0] = NumAttrsForDevice(device
);
2809 case ALC_ALL_ATTRIBUTES
:
2811 if(values
.size() < static_cast<size_t>(NumAttrsForDevice(device
)))
2812 alcSetError(device
, ALC_INVALID_VALUE
);
2815 values
[i
++] = ALC_MAJOR_VERSION
;
2816 values
[i
++] = alcMajorVersion
;
2817 values
[i
++] = ALC_MINOR_VERSION
;
2818 values
[i
++] = alcMinorVersion
;
2819 values
[i
++] = ALC_EFX_MAJOR_VERSION
;
2820 values
[i
++] = alcEFXMajorVersion
;
2821 values
[i
++] = ALC_EFX_MINOR_VERSION
;
2822 values
[i
++] = alcEFXMinorVersion
;
2824 values
[i
++] = ALC_FREQUENCY
;
2825 values
[i
++] = static_cast<int>(device
->Frequency
);
2826 if(device
->Type
!= DeviceType::Loopback
)
2828 values
[i
++] = ALC_REFRESH
;
2829 values
[i
++] = static_cast<int>(device
->Frequency
/ device
->UpdateSize
);
2831 values
[i
++] = ALC_SYNC
;
2832 values
[i
++] = ALC_FALSE
;
2836 if(device
->FmtChans
== DevFmtAmbi3D
)
2838 values
[i
++] = ALC_AMBISONIC_LAYOUT_SOFT
;
2839 values
[i
++] = EnumFromDevAmbi(device
->mAmbiLayout
);
2841 values
[i
++] = ALC_AMBISONIC_SCALING_SOFT
;
2842 values
[i
++] = EnumFromDevAmbi(device
->mAmbiScale
);
2844 values
[i
++] = ALC_AMBISONIC_ORDER_SOFT
;
2845 values
[i
++] = static_cast<int>(device
->mAmbiOrder
);
2848 values
[i
++] = ALC_FORMAT_CHANNELS_SOFT
;
2849 values
[i
++] = EnumFromDevFmt(device
->FmtChans
);
2851 values
[i
++] = ALC_FORMAT_TYPE_SOFT
;
2852 values
[i
++] = EnumFromDevFmt(device
->FmtType
);
2855 values
[i
++] = ALC_MONO_SOURCES
;
2856 values
[i
++] = static_cast<int>(device
->NumMonoSources
);
2858 values
[i
++] = ALC_STEREO_SOURCES
;
2859 values
[i
++] = static_cast<int>(device
->NumStereoSources
);
2861 values
[i
++] = ALC_MAX_AUXILIARY_SENDS
;
2862 values
[i
++] = static_cast<int>(device
->NumAuxSends
);
2864 values
[i
++] = ALC_HRTF_SOFT
;
2865 values
[i
++] = (device
->mHrtf
? ALC_TRUE
: ALC_FALSE
);
2867 values
[i
++] = ALC_HRTF_STATUS_SOFT
;
2868 values
[i
++] = device
->mHrtfStatus
;
2870 values
[i
++] = ALC_OUTPUT_LIMITER_SOFT
;
2871 values
[i
++] = device
->Limiter
? ALC_TRUE
: ALC_FALSE
;
2873 values
[i
++] = ALC_MAX_AMBISONIC_ORDER_SOFT
;
2874 values
[i
++] = MaxAmbiOrder
;
2876 values
[i
++] = ALC_OUTPUT_MODE_SOFT
;
2877 values
[i
++] = static_cast<ALCenum
>(device
->getOutputMode1());
2883 case ALC_MAJOR_VERSION
:
2884 values
[0] = alcMajorVersion
;
2887 case ALC_MINOR_VERSION
:
2888 values
[0] = alcMinorVersion
;
2891 case ALC_EFX_MAJOR_VERSION
:
2892 values
[0] = alcEFXMajorVersion
;
2895 case ALC_EFX_MINOR_VERSION
:
2896 values
[0] = alcEFXMinorVersion
;
2900 values
[0] = static_cast<int>(device
->Frequency
);
2904 if(device
->Type
== DeviceType::Loopback
)
2906 alcSetError(device
, ALC_INVALID_DEVICE
);
2909 values
[0] = static_cast<int>(device
->Frequency
/ device
->UpdateSize
);
2913 if(device
->Type
== DeviceType::Loopback
)
2915 alcSetError(device
, ALC_INVALID_DEVICE
);
2918 values
[0] = ALC_FALSE
;
2921 case ALC_FORMAT_CHANNELS_SOFT
:
2922 if(device
->Type
!= DeviceType::Loopback
)
2924 alcSetError(device
, ALC_INVALID_DEVICE
);
2927 values
[0] = EnumFromDevFmt(device
->FmtChans
);
2930 case ALC_FORMAT_TYPE_SOFT
:
2931 if(device
->Type
!= DeviceType::Loopback
)
2933 alcSetError(device
, ALC_INVALID_DEVICE
);
2936 values
[0] = EnumFromDevFmt(device
->FmtType
);
2939 case ALC_AMBISONIC_LAYOUT_SOFT
:
2940 if(device
->Type
!= DeviceType::Loopback
|| device
->FmtChans
!= DevFmtAmbi3D
)
2942 alcSetError(device
, ALC_INVALID_DEVICE
);
2945 values
[0] = EnumFromDevAmbi(device
->mAmbiLayout
);
2948 case ALC_AMBISONIC_SCALING_SOFT
:
2949 if(device
->Type
!= DeviceType::Loopback
|| device
->FmtChans
!= DevFmtAmbi3D
)
2951 alcSetError(device
, ALC_INVALID_DEVICE
);
2954 values
[0] = EnumFromDevAmbi(device
->mAmbiScale
);
2957 case ALC_AMBISONIC_ORDER_SOFT
:
2958 if(device
->Type
!= DeviceType::Loopback
|| device
->FmtChans
!= DevFmtAmbi3D
)
2960 alcSetError(device
, ALC_INVALID_DEVICE
);
2963 values
[0] = static_cast<int>(device
->mAmbiOrder
);
2966 case ALC_MONO_SOURCES
:
2967 values
[0] = static_cast<int>(device
->NumMonoSources
);
2970 case ALC_STEREO_SOURCES
:
2971 values
[0] = static_cast<int>(device
->NumStereoSources
);
2974 case ALC_MAX_AUXILIARY_SENDS
:
2975 values
[0] = static_cast<int>(device
->NumAuxSends
);
2979 values
[0] = device
->Connected
.load(std::memory_order_acquire
);
2983 values
[0] = (device
->mHrtf
? ALC_TRUE
: ALC_FALSE
);
2986 case ALC_HRTF_STATUS_SOFT
:
2987 values
[0] = device
->mHrtfStatus
;
2990 case ALC_NUM_HRTF_SPECIFIERS_SOFT
:
2991 device
->enumerateHrtfs();
2992 values
[0] = static_cast<int>(minz(device
->mHrtfList
.size(),
2993 std::numeric_limits
<int>::max()));
2996 case ALC_OUTPUT_LIMITER_SOFT
:
2997 values
[0] = device
->Limiter
? ALC_TRUE
: ALC_FALSE
;
3000 case ALC_MAX_AMBISONIC_ORDER_SOFT
:
3001 values
[0] = MaxAmbiOrder
;
3004 case ALC_OUTPUT_MODE_SOFT
:
3005 values
[0] = static_cast<ALCenum
>(device
->getOutputMode1());
3009 alcSetError(device
, ALC_INVALID_ENUM
);
3014 ALC_API
void ALC_APIENTRY
alcGetIntegerv(ALCdevice
*device
, ALCenum param
, ALCsizei size
, ALCint
*values
)
3017 DeviceRef dev
{VerifyDevice(device
)};
3018 if(size
<= 0 || values
== nullptr)
3019 alcSetError(dev
.get(), ALC_INVALID_VALUE
);
3021 GetIntegerv(dev
.get(), param
, {values
, static_cast<uint
>(size
)});
3025 ALC_API
void ALC_APIENTRY
alcGetInteger64vSOFT(ALCdevice
*device
, ALCenum pname
, ALCsizei size
, ALCint64SOFT
*values
)
3028 DeviceRef dev
{VerifyDevice(device
)};
3029 if(size
<= 0 || values
== nullptr)
3031 alcSetError(dev
.get(), ALC_INVALID_VALUE
);
3034 if(!dev
|| dev
->Type
== DeviceType::Capture
)
3036 auto ivals
= al::vector
<int>(static_cast<uint
>(size
));
3037 if(size_t got
{GetIntegerv(dev
.get(), pname
, ivals
)})
3038 std::copy_n(ivals
.begin(), got
, values
);
3042 auto NumAttrsForDevice
= [](ALCdevice
*aldev
) noexcept
3044 if(aldev
->Type
== DeviceType::Loopback
&& aldev
->FmtChans
== DevFmtAmbi3D
)
3048 std::lock_guard
<std::mutex
> _
{dev
->StateLock
};
3051 case ALC_ATTRIBUTES_SIZE
:
3052 *values
= NumAttrsForDevice(dev
.get());
3055 case ALC_ALL_ATTRIBUTES
:
3056 if(size
< NumAttrsForDevice(dev
.get()))
3057 alcSetError(dev
.get(), ALC_INVALID_VALUE
);
3061 values
[i
++] = ALC_FREQUENCY
;
3062 values
[i
++] = dev
->Frequency
;
3064 if(dev
->Type
!= DeviceType::Loopback
)
3066 values
[i
++] = ALC_REFRESH
;
3067 values
[i
++] = dev
->Frequency
/ dev
->UpdateSize
;
3069 values
[i
++] = ALC_SYNC
;
3070 values
[i
++] = ALC_FALSE
;
3074 values
[i
++] = ALC_FORMAT_CHANNELS_SOFT
;
3075 values
[i
++] = EnumFromDevFmt(dev
->FmtChans
);
3077 values
[i
++] = ALC_FORMAT_TYPE_SOFT
;
3078 values
[i
++] = EnumFromDevFmt(dev
->FmtType
);
3080 if(dev
->FmtChans
== DevFmtAmbi3D
)
3082 values
[i
++] = ALC_AMBISONIC_LAYOUT_SOFT
;
3083 values
[i
++] = EnumFromDevAmbi(dev
->mAmbiLayout
);
3085 values
[i
++] = ALC_AMBISONIC_SCALING_SOFT
;
3086 values
[i
++] = EnumFromDevAmbi(dev
->mAmbiScale
);
3088 values
[i
++] = ALC_AMBISONIC_ORDER_SOFT
;
3089 values
[i
++] = dev
->mAmbiOrder
;
3093 values
[i
++] = ALC_MONO_SOURCES
;
3094 values
[i
++] = dev
->NumMonoSources
;
3096 values
[i
++] = ALC_STEREO_SOURCES
;
3097 values
[i
++] = dev
->NumStereoSources
;
3099 values
[i
++] = ALC_MAX_AUXILIARY_SENDS
;
3100 values
[i
++] = dev
->NumAuxSends
;
3102 values
[i
++] = ALC_HRTF_SOFT
;
3103 values
[i
++] = (dev
->mHrtf
? ALC_TRUE
: ALC_FALSE
);
3105 values
[i
++] = ALC_HRTF_STATUS_SOFT
;
3106 values
[i
++] = dev
->mHrtfStatus
;
3108 values
[i
++] = ALC_OUTPUT_LIMITER_SOFT
;
3109 values
[i
++] = dev
->Limiter
? ALC_TRUE
: ALC_FALSE
;
3111 ClockLatency clock
{GetClockLatency(dev
.get(), dev
->Backend
.get())};
3112 values
[i
++] = ALC_DEVICE_CLOCK_SOFT
;
3113 values
[i
++] = clock
.ClockTime
.count();
3115 values
[i
++] = ALC_DEVICE_LATENCY_SOFT
;
3116 values
[i
++] = clock
.Latency
.count();
3118 values
[i
++] = ALC_OUTPUT_MODE_SOFT
;
3119 values
[i
++] = static_cast<ALCenum
>(device
->getOutputMode1());
3125 case ALC_DEVICE_CLOCK_SOFT
:
3127 uint samplecount
, refcount
;
3128 nanoseconds basecount
;
3130 refcount
= dev
->waitForMix();
3131 basecount
= dev
->ClockBase
;
3132 samplecount
= dev
->SamplesDone
;
3133 } while(refcount
!= ReadRef(dev
->MixCount
));
3134 basecount
+= nanoseconds
{seconds
{samplecount
}} / dev
->Frequency
;
3135 *values
= basecount
.count();
3139 case ALC_DEVICE_LATENCY_SOFT
:
3140 *values
= GetClockLatency(dev
.get(), dev
->Backend
.get()).Latency
.count();
3143 case ALC_DEVICE_CLOCK_LATENCY_SOFT
:
3145 alcSetError(dev
.get(), ALC_INVALID_VALUE
);
3148 ClockLatency clock
{GetClockLatency(dev
.get(), dev
->Backend
.get())};
3149 values
[0] = clock
.ClockTime
.count();
3150 values
[1] = clock
.Latency
.count();
3155 auto ivals
= al::vector
<int>(static_cast<uint
>(size
));
3156 if(size_t got
{GetIntegerv(dev
.get(), pname
, ivals
)})
3157 std::copy_n(ivals
.begin(), got
, values
);
3164 ALC_API ALCboolean ALC_APIENTRY
alcIsExtensionPresent(ALCdevice
*device
, const ALCchar
*extName
)
3167 DeviceRef dev
{VerifyDevice(device
)};
3169 alcSetError(dev
.get(), ALC_INVALID_VALUE
);
3172 size_t len
= strlen(extName
);
3173 const char *ptr
= (dev
? alcExtensionList
: alcNoDeviceExtList
);
3176 if(al::strncasecmp(ptr
, extName
, len
) == 0 && (ptr
[len
] == '\0' || isspace(ptr
[len
])))
3179 if((ptr
=strchr(ptr
, ' ')) != nullptr)
3183 } while(isspace(*ptr
));
3192 ALC_API ALCvoid
* ALC_APIENTRY
alcGetProcAddress(ALCdevice
*device
, const ALCchar
*funcName
)
3197 DeviceRef dev
{VerifyDevice(device
)};
3198 alcSetError(dev
.get(), ALC_INVALID_VALUE
);
3202 if(eax_g_is_enabled
)
3204 for(const auto &func
: eaxFunctions
)
3206 if(strcmp(func
.funcName
, funcName
) == 0)
3207 return func
.address
;
3211 for(const auto &func
: alcFunctions
)
3213 if(strcmp(func
.funcName
, funcName
) == 0)
3214 return func
.address
;
3221 ALC_API ALCenum ALC_APIENTRY
alcGetEnumValue(ALCdevice
*device
, const ALCchar
*enumName
)
3226 DeviceRef dev
{VerifyDevice(device
)};
3227 alcSetError(dev
.get(), ALC_INVALID_VALUE
);
3231 if(eax_g_is_enabled
)
3233 for(const auto &enm
: eaxEnumerations
)
3235 if(strcmp(enm
.enumName
, enumName
) == 0)
3240 for(const auto &enm
: alcEnumerations
)
3242 if(strcmp(enm
.enumName
, enumName
) == 0)
3251 ALC_API ALCcontext
* ALC_APIENTRY
alcCreateContext(ALCdevice
*device
, const ALCint
*attrList
)
3254 /* Explicitly hold the list lock while taking the StateLock in case the
3255 * device is asynchronously destroyed, to ensure this new context is
3256 * properly cleaned up after being made.
3258 std::unique_lock
<std::recursive_mutex
> listlock
{ListLock
};
3259 DeviceRef dev
{VerifyDevice(device
)};
3260 if(!dev
|| dev
->Type
== DeviceType::Capture
|| !dev
->Connected
.load(std::memory_order_relaxed
))
3263 alcSetError(dev
.get(), ALC_INVALID_DEVICE
);
3266 std::unique_lock
<std::mutex
> statelock
{dev
->StateLock
};
3269 dev
->LastError
.store(ALC_NO_ERROR
);
3271 ALCenum err
{UpdateDeviceParams(dev
.get(), attrList
)};
3272 if(err
!= ALC_NO_ERROR
)
3274 alcSetError(dev
.get(), err
);
3278 ContextRef context
{new ALCcontext
{dev
}};
3281 if(auto volopt
= dev
->configValue
<float>(nullptr, "volume-adjust"))
3283 const float valf
{*volopt
};
3284 if(!std::isfinite(valf
))
3285 ERR("volume-adjust must be finite: %f\n", valf
);
3288 const float db
{clampf(valf
, -24.0f
, 24.0f
)};
3290 WARN("volume-adjust clamped: %f, range: +/-%f\n", valf
, 24.0f
);
3291 context
->mGainBoost
= std::pow(10.0f
, db
/20.0f
);
3292 TRACE("volume-adjust gain: %f\n", context
->mGainBoost
);
3297 using ContextArray
= al::FlexArray
<ContextBase
*>;
3299 /* Allocate a new context array, which holds 1 more than the current/
3302 auto *oldarray
= device
->mContexts
.load();
3303 const size_t newcount
{oldarray
->size()+1};
3304 std::unique_ptr
<ContextArray
> newarray
{ContextArray::Create(newcount
)};
3306 /* Copy the current/old context handles to the new array, appending the
3309 auto iter
= std::copy(oldarray
->begin(), oldarray
->end(), newarray
->begin());
3310 *iter
= context
.get();
3312 /* Store the new context array in the device. Wait for any current mix
3313 * to finish before deleting the old array.
3315 dev
->mContexts
.store(newarray
.release());
3316 if(oldarray
!= &DeviceBase::sEmptyContextArray
)
3325 std::lock_guard
<std::recursive_mutex
> _
{ListLock
};
3326 auto iter
= std::lower_bound(ContextList
.cbegin(), ContextList
.cend(), context
.get());
3327 ContextList
.emplace(iter
, context
.get());
3330 if(ALeffectslot
*slot
{context
->mDefaultSlot
.get()})
3332 ALenum sloterr
{slot
->initEffect(ALCcontext::sDefaultEffect
.type
,
3333 ALCcontext::sDefaultEffect
.Props
, context
.get())};
3334 if(sloterr
== AL_NO_ERROR
)
3335 slot
->updateProps(context
.get());
3337 ERR("Failed to initialize the default effect\n");
3340 TRACE("Created context %p\n", voidp
{context
.get()});
3341 return context
.release();
3345 ALC_API
void ALC_APIENTRY
alcDestroyContext(ALCcontext
*context
)
3348 std::unique_lock
<std::recursive_mutex
> listlock
{ListLock
};
3349 auto iter
= std::lower_bound(ContextList
.begin(), ContextList
.end(), context
);
3350 if(iter
== ContextList
.end() || *iter
!= context
)
3353 alcSetError(nullptr, ALC_INVALID_CONTEXT
);
3357 /* Hold a reference to this context so it remains valid until the ListLock
3360 ContextRef ctx
{*iter
};
3361 ContextList
.erase(iter
);
3363 ALCdevice
*Device
{ctx
->mALDevice
.get()};
3365 std::lock_guard
<std::mutex
> _
{Device
->StateLock
};
3366 if(!ctx
->deinit() && Device
->Flags
.test(DeviceRunning
))
3368 Device
->Backend
->stop();
3369 Device
->Flags
.reset(DeviceRunning
);
3375 ALC_API ALCcontext
* ALC_APIENTRY
alcGetCurrentContext(void)
3378 ALCcontext
*Context
{ALCcontext::getThreadContext()};
3379 if(!Context
) Context
= ALCcontext::sGlobalContext
.load();
3384 /** Returns the currently active thread-local context. */
3385 ALC_API ALCcontext
* ALC_APIENTRY
alcGetThreadContext(void)
3387 { return ALCcontext::getThreadContext(); }
3390 ALC_API ALCboolean ALC_APIENTRY
alcMakeContextCurrent(ALCcontext
*context
)
3393 /* context must be valid or nullptr */
3397 ctx
= VerifyContext(context
);
3400 alcSetError(nullptr, ALC_INVALID_CONTEXT
);
3404 /* Release this reference (if any) to store it in the GlobalContext
3405 * pointer. Take ownership of the reference (if any) that was previously
3406 * stored there, and let the reference go.
3408 while(ALCcontext::sGlobalContextLock
.exchange(true, std::memory_order_acquire
)) {
3409 /* Wait to make sure another thread isn't getting or trying to change
3410 * the current context as its refcount is decremented.
3413 ContextRef
{ALCcontext::sGlobalContext
.exchange(ctx
.release())};
3414 ALCcontext::sGlobalContextLock
.store(false, std::memory_order_release
);
3416 /* Take ownership of the thread-local context reference (if any), clearing
3417 * the storage to null.
3419 ctx
= ContextRef
{ALCcontext::getThreadContext()};
3420 if(ctx
) ALCcontext::setThreadContext(nullptr);
3421 /* Reset (decrement) the previous thread-local reference. */
3427 /** Makes the given context the active context for the current thread. */
3428 ALC_API ALCboolean ALC_APIENTRY
alcSetThreadContext(ALCcontext
*context
)
3431 /* context must be valid or nullptr */
3435 ctx
= VerifyContext(context
);
3438 alcSetError(nullptr, ALC_INVALID_CONTEXT
);
3442 /* context's reference count is already incremented */
3443 ContextRef old
{ALCcontext::getThreadContext()};
3444 ALCcontext::setThreadContext(ctx
.release());
3451 ALC_API ALCdevice
* ALC_APIENTRY
alcGetContextsDevice(ALCcontext
*Context
)
3454 ContextRef ctx
{VerifyContext(Context
)};
3457 alcSetError(nullptr, ALC_INVALID_CONTEXT
);
3460 return ctx
->mALDevice
.get();
3465 ALC_API ALCdevice
* ALC_APIENTRY
alcOpenDevice(const ALCchar
*deviceName
)
3470 if(!PlaybackFactory
)
3472 alcSetError(nullptr, ALC_INVALID_VALUE
);
3478 TRACE("Opening playback device \"%s\"\n", deviceName
);
3479 if(!deviceName
[0] || al::strcasecmp(deviceName
, alcDefaultName
) == 0
3481 /* Some old Windows apps hardcode these expecting OpenAL to use a
3482 * specific audio API, even when they're not enumerated. Creative's
3483 * router effectively ignores them too.
3485 || al::strcasecmp(deviceName
, "DirectSound3D") == 0
3486 || al::strcasecmp(deviceName
, "DirectSound") == 0
3487 || al::strcasecmp(deviceName
, "MMSYSTEM") == 0
3489 /* Some old Linux apps hardcode configuration strings that were
3490 * supported by the OpenAL SI. We can't really do anything useful
3491 * with them, so just ignore.
3493 || (deviceName
[0] == '\'' && deviceName
[1] == '(')
3494 || al::strcasecmp(deviceName
, "openal-soft") == 0)
3495 deviceName
= nullptr;
3498 TRACE("Opening default playback device\n");
3500 const uint DefaultSends
{
3502 eax_g_is_enabled
? uint
{EAX_MAX_FXSLOTS
} :
3503 #endif // ALSOFT_EAX
3507 DeviceRef device
{new ALCdevice
{DeviceType::Playback
}};
3509 /* Set output format */
3510 device
->FmtChans
= DevFmtChannelsDefault
;
3511 device
->FmtType
= DevFmtTypeDefault
;
3512 device
->Frequency
= DEFAULT_OUTPUT_RATE
;
3513 device
->UpdateSize
= DEFAULT_UPDATE_SIZE
;
3514 device
->BufferSize
= DEFAULT_UPDATE_SIZE
* DEFAULT_NUM_UPDATES
;
3516 device
->SourcesMax
= 256;
3517 device
->NumStereoSources
= 1;
3518 device
->NumMonoSources
= device
->SourcesMax
- device
->NumStereoSources
;
3519 device
->AuxiliaryEffectSlotMax
= 64;
3520 device
->NumAuxSends
= DefaultSends
;
3523 auto backend
= PlaybackFactory
->createBackend(device
.get(), BackendType::Playback
);
3524 std::lock_guard
<std::recursive_mutex
> _
{ListLock
};
3525 backend
->open(deviceName
);
3526 device
->Backend
= std::move(backend
);
3528 catch(al::backend_exception
&e
) {
3529 WARN("Failed to open playback device: %s\n", e
.what());
3530 alcSetError(nullptr, (e
.errorCode() == al::backend_error::OutOfMemory
)
3531 ? ALC_OUT_OF_MEMORY
: ALC_INVALID_VALUE
);
3536 std::lock_guard
<std::recursive_mutex
> _
{ListLock
};
3537 auto iter
= std::lower_bound(DeviceList
.cbegin(), DeviceList
.cend(), device
.get());
3538 DeviceList
.emplace(iter
, device
.get());
3541 TRACE("Created device %p, \"%s\"\n", voidp
{device
.get()}, device
->DeviceName
.c_str());
3542 return device
.release();
3546 ALC_API ALCboolean ALC_APIENTRY
alcCloseDevice(ALCdevice
*device
)
3549 std::unique_lock
<std::recursive_mutex
> listlock
{ListLock
};
3550 auto iter
= std::lower_bound(DeviceList
.begin(), DeviceList
.end(), device
);
3551 if(iter
== DeviceList
.end() || *iter
!= device
)
3553 alcSetError(nullptr, ALC_INVALID_DEVICE
);
3556 if((*iter
)->Type
== DeviceType::Capture
)
3558 alcSetError(*iter
, ALC_INVALID_DEVICE
);
3562 /* Erase the device, and any remaining contexts left on it, from their
3565 DeviceRef dev
{*iter
};
3566 DeviceList
.erase(iter
);
3568 std::unique_lock
<std::mutex
> statelock
{dev
->StateLock
};
3569 al::vector
<ContextRef
> orphanctxs
;
3570 for(ContextBase
*ctx
: *dev
->mContexts
.load())
3572 auto ctxiter
= std::lower_bound(ContextList
.begin(), ContextList
.end(), ctx
);
3573 if(ctxiter
!= ContextList
.end() && *ctxiter
== ctx
)
3575 orphanctxs
.emplace_back(ContextRef
{*ctxiter
});
3576 ContextList
.erase(ctxiter
);
3581 for(ContextRef
&context
: orphanctxs
)
3583 WARN("Releasing orphaned context %p\n", voidp
{context
.get()});
3588 if(dev
->Flags
.test(DeviceRunning
))
3589 dev
->Backend
->stop();
3590 dev
->Flags
.reset(DeviceRunning
);
3597 /************************************************
3598 * ALC capture functions
3599 ************************************************/
3600 ALC_API ALCdevice
* ALC_APIENTRY
alcCaptureOpenDevice(const ALCchar
*deviceName
, ALCuint frequency
, ALCenum format
, ALCsizei samples
)
3607 alcSetError(nullptr, ALC_INVALID_VALUE
);
3613 alcSetError(nullptr, ALC_INVALID_VALUE
);
3619 TRACE("Opening capture device \"%s\"\n", deviceName
);
3620 if(!deviceName
[0] || al::strcasecmp(deviceName
, alcDefaultName
) == 0
3621 || al::strcasecmp(deviceName
, "openal-soft") == 0)
3622 deviceName
= nullptr;
3625 TRACE("Opening default capture device\n");
3627 DeviceRef device
{new ALCdevice
{DeviceType::Capture
}};
3629 auto decompfmt
= DecomposeDevFormat(format
);
3632 alcSetError(nullptr, ALC_INVALID_ENUM
);
3636 device
->Frequency
= frequency
;
3637 device
->FmtChans
= decompfmt
->chans
;
3638 device
->FmtType
= decompfmt
->type
;
3639 device
->Flags
.set(FrequencyRequest
);
3640 device
->Flags
.set(ChannelsRequest
);
3641 device
->Flags
.set(SampleTypeRequest
);
3643 device
->UpdateSize
= static_cast<uint
>(samples
);
3644 device
->BufferSize
= static_cast<uint
>(samples
);
3647 TRACE("Capture format: %s, %s, %uhz, %u / %u buffer\n",
3648 DevFmtChannelsString(device
->FmtChans
), DevFmtTypeString(device
->FmtType
),
3649 device
->Frequency
, device
->UpdateSize
, device
->BufferSize
);
3651 auto backend
= CaptureFactory
->createBackend(device
.get(), BackendType::Capture
);
3652 std::lock_guard
<std::recursive_mutex
> _
{ListLock
};
3653 backend
->open(deviceName
);
3654 device
->Backend
= std::move(backend
);
3656 catch(al::backend_exception
&e
) {
3657 WARN("Failed to open capture device: %s\n", e
.what());
3658 alcSetError(nullptr, (e
.errorCode() == al::backend_error::OutOfMemory
)
3659 ? ALC_OUT_OF_MEMORY
: ALC_INVALID_VALUE
);
3664 std::lock_guard
<std::recursive_mutex
> _
{ListLock
};
3665 auto iter
= std::lower_bound(DeviceList
.cbegin(), DeviceList
.cend(), device
.get());
3666 DeviceList
.emplace(iter
, device
.get());
3669 TRACE("Created capture device %p, \"%s\"\n", voidp
{device
.get()}, device
->DeviceName
.c_str());
3670 return device
.release();
3674 ALC_API ALCboolean ALC_APIENTRY
alcCaptureCloseDevice(ALCdevice
*device
)
3677 std::unique_lock
<std::recursive_mutex
> listlock
{ListLock
};
3678 auto iter
= std::lower_bound(DeviceList
.begin(), DeviceList
.end(), device
);
3679 if(iter
== DeviceList
.end() || *iter
!= device
)
3681 alcSetError(nullptr, ALC_INVALID_DEVICE
);
3684 if((*iter
)->Type
!= DeviceType::Capture
)
3686 alcSetError(*iter
, ALC_INVALID_DEVICE
);
3690 DeviceRef dev
{*iter
};
3691 DeviceList
.erase(iter
);
3694 std::lock_guard
<std::mutex
> _
{dev
->StateLock
};
3695 if(dev
->Flags
.test(DeviceRunning
))
3696 dev
->Backend
->stop();
3697 dev
->Flags
.reset(DeviceRunning
);
3703 ALC_API
void ALC_APIENTRY
alcCaptureStart(ALCdevice
*device
)
3706 DeviceRef dev
{VerifyDevice(device
)};
3707 if(!dev
|| dev
->Type
!= DeviceType::Capture
)
3709 alcSetError(dev
.get(), ALC_INVALID_DEVICE
);
3713 std::lock_guard
<std::mutex
> _
{dev
->StateLock
};
3714 if(!dev
->Connected
.load(std::memory_order_acquire
))
3715 alcSetError(dev
.get(), ALC_INVALID_DEVICE
);
3716 else if(!dev
->Flags
.test(DeviceRunning
))
3719 auto backend
= dev
->Backend
.get();
3721 dev
->Flags
.set(DeviceRunning
);
3723 catch(al::backend_exception
& e
) {
3724 ERR("%s\n", e
.what());
3725 dev
->handleDisconnect("%s", e
.what());
3726 alcSetError(dev
.get(), ALC_INVALID_DEVICE
);
3732 ALC_API
void ALC_APIENTRY
alcCaptureStop(ALCdevice
*device
)
3735 DeviceRef dev
{VerifyDevice(device
)};
3736 if(!dev
|| dev
->Type
!= DeviceType::Capture
)
3737 alcSetError(dev
.get(), ALC_INVALID_DEVICE
);
3740 std::lock_guard
<std::mutex
> _
{dev
->StateLock
};
3741 if(dev
->Flags
.test(DeviceRunning
))
3742 dev
->Backend
->stop();
3743 dev
->Flags
.reset(DeviceRunning
);
3748 ALC_API
void ALC_APIENTRY
alcCaptureSamples(ALCdevice
*device
, ALCvoid
*buffer
, ALCsizei samples
)
3751 DeviceRef dev
{VerifyDevice(device
)};
3752 if(!dev
|| dev
->Type
!= DeviceType::Capture
)
3754 alcSetError(dev
.get(), ALC_INVALID_DEVICE
);
3758 if(samples
< 0 || (samples
> 0 && buffer
== nullptr))
3760 alcSetError(dev
.get(), ALC_INVALID_VALUE
);
3766 std::lock_guard
<std::mutex
> _
{dev
->StateLock
};
3767 BackendBase
*backend
{dev
->Backend
.get()};
3769 const auto usamples
= static_cast<uint
>(samples
);
3770 if(usamples
> backend
->availableSamples())
3772 alcSetError(dev
.get(), ALC_INVALID_VALUE
);
3776 backend
->captureSamples(static_cast<al::byte
*>(buffer
), usamples
);
3781 /************************************************
3782 * ALC loopback functions
3783 ************************************************/
3785 /** Open a loopback device, for manual rendering. */
3786 ALC_API ALCdevice
* ALC_APIENTRY
alcLoopbackOpenDeviceSOFT(const ALCchar
*deviceName
)
3791 /* Make sure the device name, if specified, is us. */
3792 if(deviceName
&& strcmp(deviceName
, alcDefaultName
) != 0)
3794 alcSetError(nullptr, ALC_INVALID_VALUE
);
3798 const uint DefaultSends
{
3800 eax_g_is_enabled
? uint
{EAX_MAX_FXSLOTS
} :
3801 #endif // ALSOFT_EAX
3805 DeviceRef device
{new ALCdevice
{DeviceType::Loopback
}};
3807 device
->SourcesMax
= 256;
3808 device
->AuxiliaryEffectSlotMax
= 64;
3809 device
->NumAuxSends
= DefaultSends
;
3812 device
->BufferSize
= 0;
3813 device
->UpdateSize
= 0;
3815 device
->Frequency
= DEFAULT_OUTPUT_RATE
;
3816 device
->FmtChans
= DevFmtChannelsDefault
;
3817 device
->FmtType
= DevFmtTypeDefault
;
3819 device
->NumStereoSources
= 1;
3820 device
->NumMonoSources
= device
->SourcesMax
- device
->NumStereoSources
;
3823 auto backend
= LoopbackBackendFactory::getFactory().createBackend(device
.get(),
3824 BackendType::Playback
);
3825 backend
->open("Loopback");
3826 device
->Backend
= std::move(backend
);
3828 catch(al::backend_exception
&e
) {
3829 WARN("Failed to open loopback device: %s\n", e
.what());
3830 alcSetError(nullptr, (e
.errorCode() == al::backend_error::OutOfMemory
)
3831 ? ALC_OUT_OF_MEMORY
: ALC_INVALID_VALUE
);
3836 std::lock_guard
<std::recursive_mutex
> _
{ListLock
};
3837 auto iter
= std::lower_bound(DeviceList
.cbegin(), DeviceList
.cend(), device
.get());
3838 DeviceList
.emplace(iter
, device
.get());
3841 TRACE("Created loopback device %p\n", voidp
{device
.get()});
3842 return device
.release();
3847 * Determines if the loopback device supports the given format for rendering.
3849 ALC_API ALCboolean ALC_APIENTRY
alcIsRenderFormatSupportedSOFT(ALCdevice
*device
, ALCsizei freq
, ALCenum channels
, ALCenum type
)
3852 DeviceRef dev
{VerifyDevice(device
)};
3853 if(!dev
|| dev
->Type
!= DeviceType::Loopback
)
3854 alcSetError(dev
.get(), ALC_INVALID_DEVICE
);
3856 alcSetError(dev
.get(), ALC_INVALID_VALUE
);
3859 if(DevFmtTypeFromEnum(type
).has_value() && DevFmtChannelsFromEnum(channels
).has_value()
3860 && freq
>= MIN_OUTPUT_RATE
&& freq
<= MAX_OUTPUT_RATE
)
3869 * Renders some samples into a buffer, using the format last set by the
3870 * attributes given to alcCreateContext.
3872 FORCE_ALIGN ALC_API
void ALC_APIENTRY
alcRenderSamplesSOFT(ALCdevice
*device
, ALCvoid
*buffer
, ALCsizei samples
)
3875 if(!device
|| device
->Type
!= DeviceType::Loopback
)
3876 alcSetError(device
, ALC_INVALID_DEVICE
);
3877 else if(samples
< 0 || (samples
> 0 && buffer
== nullptr))
3878 alcSetError(device
, ALC_INVALID_VALUE
);
3880 device
->renderSamples(buffer
, static_cast<uint
>(samples
), device
->channelsFromFmt());
3885 /************************************************
3886 * ALC DSP pause/resume functions
3887 ************************************************/
3889 /** Pause the DSP to stop audio processing. */
3890 ALC_API
void ALC_APIENTRY
alcDevicePauseSOFT(ALCdevice
*device
)
3893 DeviceRef dev
{VerifyDevice(device
)};
3894 if(!dev
|| dev
->Type
!= DeviceType::Playback
)
3895 alcSetError(dev
.get(), ALC_INVALID_DEVICE
);
3898 std::lock_guard
<std::mutex
> _
{dev
->StateLock
};
3899 if(dev
->Flags
.test(DeviceRunning
))
3900 dev
->Backend
->stop();
3901 dev
->Flags
.reset(DeviceRunning
);
3902 dev
->Flags
.set(DevicePaused
);
3907 /** Resume the DSP to restart audio processing. */
3908 ALC_API
void ALC_APIENTRY
alcDeviceResumeSOFT(ALCdevice
*device
)
3911 DeviceRef dev
{VerifyDevice(device
)};
3912 if(!dev
|| dev
->Type
!= DeviceType::Playback
)
3914 alcSetError(dev
.get(), ALC_INVALID_DEVICE
);
3918 std::lock_guard
<std::mutex
> _
{dev
->StateLock
};
3919 if(!dev
->Flags
.test(DevicePaused
))
3921 dev
->Flags
.reset(DevicePaused
);
3922 if(dev
->mContexts
.load()->empty())
3926 auto backend
= dev
->Backend
.get();
3928 dev
->Flags
.set(DeviceRunning
);
3930 catch(al::backend_exception
& e
) {
3931 ERR("%s\n", e
.what());
3932 dev
->handleDisconnect("%s", e
.what());
3933 alcSetError(dev
.get(), ALC_INVALID_DEVICE
);
3936 TRACE("Post-resume: %s, %s, %uhz, %u / %u buffer\n",
3937 DevFmtChannelsString(device
->FmtChans
), DevFmtTypeString(device
->FmtType
),
3938 device
->Frequency
, device
->UpdateSize
, device
->BufferSize
);
3943 /************************************************
3944 * ALC HRTF functions
3945 ************************************************/
3947 /** Gets a string parameter at the given index. */
3948 ALC_API
const ALCchar
* ALC_APIENTRY
alcGetStringiSOFT(ALCdevice
*device
, ALCenum paramName
, ALCsizei index
)
3951 DeviceRef dev
{VerifyDevice(device
)};
3952 if(!dev
|| dev
->Type
== DeviceType::Capture
)
3953 alcSetError(dev
.get(), ALC_INVALID_DEVICE
);
3954 else switch(paramName
)
3956 case ALC_HRTF_SPECIFIER_SOFT
:
3957 if(index
>= 0 && static_cast<uint
>(index
) < dev
->mHrtfList
.size())
3958 return dev
->mHrtfList
[static_cast<uint
>(index
)].c_str();
3959 alcSetError(dev
.get(), ALC_INVALID_VALUE
);
3963 alcSetError(dev
.get(), ALC_INVALID_ENUM
);
3971 /** Resets the given device output, using the specified attribute list. */
3972 ALC_API ALCboolean ALC_APIENTRY
alcResetDeviceSOFT(ALCdevice
*device
, const ALCint
*attribs
)
3975 std::unique_lock
<std::recursive_mutex
> listlock
{ListLock
};
3976 DeviceRef dev
{VerifyDevice(device
)};
3977 if(!dev
|| dev
->Type
== DeviceType::Capture
)
3980 alcSetError(dev
.get(), ALC_INVALID_DEVICE
);
3983 std::lock_guard
<std::mutex
> _
{dev
->StateLock
};
3986 /* Force the backend to stop mixing first since we're resetting. Also reset
3987 * the connected state so lost devices can attempt recover.
3989 if(dev
->Flags
.test(DeviceRunning
))
3990 dev
->Backend
->stop();
3991 dev
->Flags
.reset(DeviceRunning
);
3993 return ResetDeviceParams(dev
.get(), attribs
) ? ALC_TRUE
: ALC_FALSE
;
3998 /************************************************
3999 * ALC device reopen functions
4000 ************************************************/
4002 /** Reopens the given device output, using the specified name and attribute list. */
4003 FORCE_ALIGN ALCboolean ALC_APIENTRY
alcReopenDeviceSOFT(ALCdevice
*device
,
4004 const ALCchar
*deviceName
, const ALCint
*attribs
)
4009 if(!deviceName
[0] || al::strcasecmp(deviceName
, alcDefaultName
) == 0)
4010 deviceName
= nullptr;
4013 std::unique_lock
<std::recursive_mutex
> listlock
{ListLock
};
4014 DeviceRef dev
{VerifyDevice(device
)};
4015 if(!dev
|| dev
->Type
!= DeviceType::Playback
)
4018 alcSetError(dev
.get(), ALC_INVALID_DEVICE
);
4021 std::lock_guard
<std::mutex
> _
{dev
->StateLock
};
4023 /* Force the backend to stop mixing first since we're reopening. */
4024 if(dev
->Flags
.test(DeviceRunning
))
4026 auto backend
= dev
->Backend
.get();
4028 dev
->Flags
.reset(DeviceRunning
);
4031 BackendPtr newbackend
;
4033 newbackend
= PlaybackFactory
->createBackend(dev
.get(), BackendType::Playback
);
4034 newbackend
->open(deviceName
);
4036 catch(al::backend_exception
&e
) {
4038 newbackend
= nullptr;
4040 WARN("Failed to reopen playback device: %s\n", e
.what());
4041 alcSetError(dev
.get(), (e
.errorCode() == al::backend_error::OutOfMemory
)
4042 ? ALC_OUT_OF_MEMORY
: ALC_INVALID_VALUE
);
4044 /* If the device is connected, not paused, and has contexts, ensure it
4045 * continues playing.
4047 if(dev
->Connected
.load(std::memory_order_relaxed
) && !dev
->Flags
.test(DevicePaused
)
4048 && !dev
->mContexts
.load(std::memory_order_relaxed
)->empty())
4051 auto backend
= dev
->Backend
.get();
4053 dev
->Flags
.set(DeviceRunning
);
4055 catch(al::backend_exception
&be
) {
4056 ERR("%s\n", be
.what());
4057 dev
->handleDisconnect("%s", be
.what());
4063 dev
->Backend
= std::move(newbackend
);
4064 TRACE("Reopened device %p, \"%s\"\n", voidp
{dev
.get()}, dev
->DeviceName
.c_str());
4066 /* Always return true even if resetting fails. It shouldn't fail, but this
4067 * is primarily to avoid confusion by the app seeing the function return
4068 * false while the device is on the new output anyway. We could try to
4069 * restore the old backend if this fails, but the configuration would be
4070 * changed with the new backend and would need to be reset again with the
4071 * old one, and the provided attributes may not be appropriate or desirable
4072 * for the old device.
4074 * In this way, we essentially act as if the function succeeded, but
4075 * immediately disconnects following it.
4077 ResetDeviceParams(dev
.get(), attribs
);