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 { "solaris", SolarisBackendFactory::getFactory
},
230 { "sndio", SndIOBackendFactory::getFactory
},
233 { "alsa", AlsaBackendFactory::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 }, eaxFunctions
[] = {
459 DECL(EAXGetBufferMode
),
460 DECL(EAXSetBufferMode
),
465 #define DECL(x) { #x, (x) }
467 const ALCchar
*enumName
;
469 } alcEnumerations
[] = {
474 DECL(ALC_MAJOR_VERSION
),
475 DECL(ALC_MINOR_VERSION
),
476 DECL(ALC_ATTRIBUTES_SIZE
),
477 DECL(ALC_ALL_ATTRIBUTES
),
478 DECL(ALC_DEFAULT_DEVICE_SPECIFIER
),
479 DECL(ALC_DEVICE_SPECIFIER
),
480 DECL(ALC_ALL_DEVICES_SPECIFIER
),
481 DECL(ALC_DEFAULT_ALL_DEVICES_SPECIFIER
),
482 DECL(ALC_EXTENSIONS
),
486 DECL(ALC_MONO_SOURCES
),
487 DECL(ALC_STEREO_SOURCES
),
488 DECL(ALC_CAPTURE_DEVICE_SPECIFIER
),
489 DECL(ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER
),
490 DECL(ALC_CAPTURE_SAMPLES
),
493 DECL(ALC_EFX_MAJOR_VERSION
),
494 DECL(ALC_EFX_MINOR_VERSION
),
495 DECL(ALC_MAX_AUXILIARY_SENDS
),
497 DECL(ALC_FORMAT_CHANNELS_SOFT
),
498 DECL(ALC_FORMAT_TYPE_SOFT
),
501 DECL(ALC_STEREO_SOFT
),
503 DECL(ALC_5POINT1_SOFT
),
504 DECL(ALC_6POINT1_SOFT
),
505 DECL(ALC_7POINT1_SOFT
),
506 DECL(ALC_BFORMAT3D_SOFT
),
509 DECL(ALC_UNSIGNED_BYTE_SOFT
),
510 DECL(ALC_SHORT_SOFT
),
511 DECL(ALC_UNSIGNED_SHORT_SOFT
),
513 DECL(ALC_UNSIGNED_INT_SOFT
),
514 DECL(ALC_FLOAT_SOFT
),
517 DECL(ALC_DONT_CARE_SOFT
),
518 DECL(ALC_HRTF_STATUS_SOFT
),
519 DECL(ALC_HRTF_DISABLED_SOFT
),
520 DECL(ALC_HRTF_ENABLED_SOFT
),
521 DECL(ALC_HRTF_DENIED_SOFT
),
522 DECL(ALC_HRTF_REQUIRED_SOFT
),
523 DECL(ALC_HRTF_HEADPHONES_DETECTED_SOFT
),
524 DECL(ALC_HRTF_UNSUPPORTED_FORMAT_SOFT
),
525 DECL(ALC_NUM_HRTF_SPECIFIERS_SOFT
),
526 DECL(ALC_HRTF_SPECIFIER_SOFT
),
527 DECL(ALC_HRTF_ID_SOFT
),
529 DECL(ALC_AMBISONIC_LAYOUT_SOFT
),
530 DECL(ALC_AMBISONIC_SCALING_SOFT
),
531 DECL(ALC_AMBISONIC_ORDER_SOFT
),
537 DECL(ALC_OUTPUT_LIMITER_SOFT
),
539 DECL(ALC_OUTPUT_MODE_SOFT
),
540 DECL(ALC_NORMAL_SOFT
),
541 DECL(ALC_STEREO_UHJ_SOFT
),
545 DECL(ALC_INVALID_DEVICE
),
546 DECL(ALC_INVALID_CONTEXT
),
547 DECL(ALC_INVALID_ENUM
),
548 DECL(ALC_INVALID_VALUE
),
549 DECL(ALC_OUT_OF_MEMORY
),
557 DECL(AL_SOURCE_RELATIVE
),
558 DECL(AL_CONE_INNER_ANGLE
),
559 DECL(AL_CONE_OUTER_ANGLE
),
569 DECL(AL_ORIENTATION
),
570 DECL(AL_REFERENCE_DISTANCE
),
571 DECL(AL_ROLLOFF_FACTOR
),
572 DECL(AL_CONE_OUTER_GAIN
),
573 DECL(AL_MAX_DISTANCE
),
575 DECL(AL_SAMPLE_OFFSET
),
576 DECL(AL_BYTE_OFFSET
),
577 DECL(AL_SOURCE_TYPE
),
580 DECL(AL_UNDETERMINED
),
581 DECL(AL_METERS_PER_UNIT
),
582 DECL(AL_LOOP_POINTS_SOFT
),
583 DECL(AL_DIRECT_CHANNELS_SOFT
),
585 DECL(AL_DIRECT_FILTER
),
586 DECL(AL_AUXILIARY_SEND_FILTER
),
587 DECL(AL_AIR_ABSORPTION_FACTOR
),
588 DECL(AL_ROOM_ROLLOFF_FACTOR
),
589 DECL(AL_CONE_OUTER_GAINHF
),
590 DECL(AL_DIRECT_FILTER_GAINHF_AUTO
),
591 DECL(AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
),
592 DECL(AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
),
594 DECL(AL_SOURCE_STATE
),
600 DECL(AL_BUFFERS_QUEUED
),
601 DECL(AL_BUFFERS_PROCESSED
),
603 DECL(AL_FORMAT_MONO8
),
604 DECL(AL_FORMAT_MONO16
),
605 DECL(AL_FORMAT_MONO_FLOAT32
),
606 DECL(AL_FORMAT_MONO_DOUBLE_EXT
),
607 DECL(AL_FORMAT_STEREO8
),
608 DECL(AL_FORMAT_STEREO16
),
609 DECL(AL_FORMAT_STEREO_FLOAT32
),
610 DECL(AL_FORMAT_STEREO_DOUBLE_EXT
),
611 DECL(AL_FORMAT_MONO_IMA4
),
612 DECL(AL_FORMAT_STEREO_IMA4
),
613 DECL(AL_FORMAT_MONO_MSADPCM_SOFT
),
614 DECL(AL_FORMAT_STEREO_MSADPCM_SOFT
),
615 DECL(AL_FORMAT_QUAD8_LOKI
),
616 DECL(AL_FORMAT_QUAD16_LOKI
),
617 DECL(AL_FORMAT_QUAD8
),
618 DECL(AL_FORMAT_QUAD16
),
619 DECL(AL_FORMAT_QUAD32
),
620 DECL(AL_FORMAT_51CHN8
),
621 DECL(AL_FORMAT_51CHN16
),
622 DECL(AL_FORMAT_51CHN32
),
623 DECL(AL_FORMAT_61CHN8
),
624 DECL(AL_FORMAT_61CHN16
),
625 DECL(AL_FORMAT_61CHN32
),
626 DECL(AL_FORMAT_71CHN8
),
627 DECL(AL_FORMAT_71CHN16
),
628 DECL(AL_FORMAT_71CHN32
),
629 DECL(AL_FORMAT_REAR8
),
630 DECL(AL_FORMAT_REAR16
),
631 DECL(AL_FORMAT_REAR32
),
632 DECL(AL_FORMAT_MONO_MULAW
),
633 DECL(AL_FORMAT_MONO_MULAW_EXT
),
634 DECL(AL_FORMAT_STEREO_MULAW
),
635 DECL(AL_FORMAT_STEREO_MULAW_EXT
),
636 DECL(AL_FORMAT_QUAD_MULAW
),
637 DECL(AL_FORMAT_51CHN_MULAW
),
638 DECL(AL_FORMAT_61CHN_MULAW
),
639 DECL(AL_FORMAT_71CHN_MULAW
),
640 DECL(AL_FORMAT_REAR_MULAW
),
641 DECL(AL_FORMAT_MONO_ALAW_EXT
),
642 DECL(AL_FORMAT_STEREO_ALAW_EXT
),
644 DECL(AL_FORMAT_BFORMAT2D_8
),
645 DECL(AL_FORMAT_BFORMAT2D_16
),
646 DECL(AL_FORMAT_BFORMAT2D_FLOAT32
),
647 DECL(AL_FORMAT_BFORMAT2D_MULAW
),
648 DECL(AL_FORMAT_BFORMAT3D_8
),
649 DECL(AL_FORMAT_BFORMAT3D_16
),
650 DECL(AL_FORMAT_BFORMAT3D_FLOAT32
),
651 DECL(AL_FORMAT_BFORMAT3D_MULAW
),
657 DECL(AL_UNPACK_BLOCK_ALIGNMENT_SOFT
),
658 DECL(AL_PACK_BLOCK_ALIGNMENT_SOFT
),
660 DECL(AL_SOURCE_RADIUS
),
662 DECL(AL_STEREO_ANGLES
),
669 DECL(AL_INVALID_NAME
),
670 DECL(AL_INVALID_ENUM
),
671 DECL(AL_INVALID_VALUE
),
672 DECL(AL_INVALID_OPERATION
),
673 DECL(AL_OUT_OF_MEMORY
),
680 DECL(AL_DOPPLER_FACTOR
),
681 DECL(AL_DOPPLER_VELOCITY
),
682 DECL(AL_DISTANCE_MODEL
),
683 DECL(AL_SPEED_OF_SOUND
),
684 DECL(AL_SOURCE_DISTANCE_MODEL
),
685 DECL(AL_DEFERRED_UPDATES_SOFT
),
686 DECL(AL_GAIN_LIMIT_SOFT
),
688 DECL(AL_INVERSE_DISTANCE
),
689 DECL(AL_INVERSE_DISTANCE_CLAMPED
),
690 DECL(AL_LINEAR_DISTANCE
),
691 DECL(AL_LINEAR_DISTANCE_CLAMPED
),
692 DECL(AL_EXPONENT_DISTANCE
),
693 DECL(AL_EXPONENT_DISTANCE_CLAMPED
),
695 DECL(AL_FILTER_TYPE
),
696 DECL(AL_FILTER_NULL
),
697 DECL(AL_FILTER_LOWPASS
),
698 DECL(AL_FILTER_HIGHPASS
),
699 DECL(AL_FILTER_BANDPASS
),
701 DECL(AL_LOWPASS_GAIN
),
702 DECL(AL_LOWPASS_GAINHF
),
704 DECL(AL_HIGHPASS_GAIN
),
705 DECL(AL_HIGHPASS_GAINLF
),
707 DECL(AL_BANDPASS_GAIN
),
708 DECL(AL_BANDPASS_GAINHF
),
709 DECL(AL_BANDPASS_GAINLF
),
711 DECL(AL_EFFECT_TYPE
),
712 DECL(AL_EFFECT_NULL
),
713 DECL(AL_EFFECT_REVERB
),
714 DECL(AL_EFFECT_EAXREVERB
),
715 DECL(AL_EFFECT_CHORUS
),
716 DECL(AL_EFFECT_DISTORTION
),
717 DECL(AL_EFFECT_ECHO
),
718 DECL(AL_EFFECT_FLANGER
),
719 DECL(AL_EFFECT_PITCH_SHIFTER
),
720 DECL(AL_EFFECT_FREQUENCY_SHIFTER
),
721 DECL(AL_EFFECT_VOCAL_MORPHER
),
722 DECL(AL_EFFECT_RING_MODULATOR
),
723 DECL(AL_EFFECT_AUTOWAH
),
724 DECL(AL_EFFECT_COMPRESSOR
),
725 DECL(AL_EFFECT_EQUALIZER
),
726 DECL(AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT
),
727 DECL(AL_EFFECT_DEDICATED_DIALOGUE
),
729 DECL(AL_EFFECTSLOT_EFFECT
),
730 DECL(AL_EFFECTSLOT_GAIN
),
731 DECL(AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
),
732 DECL(AL_EFFECTSLOT_NULL
),
734 DECL(AL_EAXREVERB_DENSITY
),
735 DECL(AL_EAXREVERB_DIFFUSION
),
736 DECL(AL_EAXREVERB_GAIN
),
737 DECL(AL_EAXREVERB_GAINHF
),
738 DECL(AL_EAXREVERB_GAINLF
),
739 DECL(AL_EAXREVERB_DECAY_TIME
),
740 DECL(AL_EAXREVERB_DECAY_HFRATIO
),
741 DECL(AL_EAXREVERB_DECAY_LFRATIO
),
742 DECL(AL_EAXREVERB_REFLECTIONS_GAIN
),
743 DECL(AL_EAXREVERB_REFLECTIONS_DELAY
),
744 DECL(AL_EAXREVERB_REFLECTIONS_PAN
),
745 DECL(AL_EAXREVERB_LATE_REVERB_GAIN
),
746 DECL(AL_EAXREVERB_LATE_REVERB_DELAY
),
747 DECL(AL_EAXREVERB_LATE_REVERB_PAN
),
748 DECL(AL_EAXREVERB_ECHO_TIME
),
749 DECL(AL_EAXREVERB_ECHO_DEPTH
),
750 DECL(AL_EAXREVERB_MODULATION_TIME
),
751 DECL(AL_EAXREVERB_MODULATION_DEPTH
),
752 DECL(AL_EAXREVERB_AIR_ABSORPTION_GAINHF
),
753 DECL(AL_EAXREVERB_HFREFERENCE
),
754 DECL(AL_EAXREVERB_LFREFERENCE
),
755 DECL(AL_EAXREVERB_ROOM_ROLLOFF_FACTOR
),
756 DECL(AL_EAXREVERB_DECAY_HFLIMIT
),
758 DECL(AL_REVERB_DENSITY
),
759 DECL(AL_REVERB_DIFFUSION
),
760 DECL(AL_REVERB_GAIN
),
761 DECL(AL_REVERB_GAINHF
),
762 DECL(AL_REVERB_DECAY_TIME
),
763 DECL(AL_REVERB_DECAY_HFRATIO
),
764 DECL(AL_REVERB_REFLECTIONS_GAIN
),
765 DECL(AL_REVERB_REFLECTIONS_DELAY
),
766 DECL(AL_REVERB_LATE_REVERB_GAIN
),
767 DECL(AL_REVERB_LATE_REVERB_DELAY
),
768 DECL(AL_REVERB_AIR_ABSORPTION_GAINHF
),
769 DECL(AL_REVERB_ROOM_ROLLOFF_FACTOR
),
770 DECL(AL_REVERB_DECAY_HFLIMIT
),
772 DECL(AL_CHORUS_WAVEFORM
),
773 DECL(AL_CHORUS_PHASE
),
774 DECL(AL_CHORUS_RATE
),
775 DECL(AL_CHORUS_DEPTH
),
776 DECL(AL_CHORUS_FEEDBACK
),
777 DECL(AL_CHORUS_DELAY
),
779 DECL(AL_DISTORTION_EDGE
),
780 DECL(AL_DISTORTION_GAIN
),
781 DECL(AL_DISTORTION_LOWPASS_CUTOFF
),
782 DECL(AL_DISTORTION_EQCENTER
),
783 DECL(AL_DISTORTION_EQBANDWIDTH
),
786 DECL(AL_ECHO_LRDELAY
),
787 DECL(AL_ECHO_DAMPING
),
788 DECL(AL_ECHO_FEEDBACK
),
789 DECL(AL_ECHO_SPREAD
),
791 DECL(AL_FLANGER_WAVEFORM
),
792 DECL(AL_FLANGER_PHASE
),
793 DECL(AL_FLANGER_RATE
),
794 DECL(AL_FLANGER_DEPTH
),
795 DECL(AL_FLANGER_FEEDBACK
),
796 DECL(AL_FLANGER_DELAY
),
798 DECL(AL_FREQUENCY_SHIFTER_FREQUENCY
),
799 DECL(AL_FREQUENCY_SHIFTER_LEFT_DIRECTION
),
800 DECL(AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION
),
802 DECL(AL_RING_MODULATOR_FREQUENCY
),
803 DECL(AL_RING_MODULATOR_HIGHPASS_CUTOFF
),
804 DECL(AL_RING_MODULATOR_WAVEFORM
),
806 DECL(AL_PITCH_SHIFTER_COARSE_TUNE
),
807 DECL(AL_PITCH_SHIFTER_FINE_TUNE
),
809 DECL(AL_COMPRESSOR_ONOFF
),
811 DECL(AL_EQUALIZER_LOW_GAIN
),
812 DECL(AL_EQUALIZER_LOW_CUTOFF
),
813 DECL(AL_EQUALIZER_MID1_GAIN
),
814 DECL(AL_EQUALIZER_MID1_CENTER
),
815 DECL(AL_EQUALIZER_MID1_WIDTH
),
816 DECL(AL_EQUALIZER_MID2_GAIN
),
817 DECL(AL_EQUALIZER_MID2_CENTER
),
818 DECL(AL_EQUALIZER_MID2_WIDTH
),
819 DECL(AL_EQUALIZER_HIGH_GAIN
),
820 DECL(AL_EQUALIZER_HIGH_CUTOFF
),
822 DECL(AL_DEDICATED_GAIN
),
824 DECL(AL_AUTOWAH_ATTACK_TIME
),
825 DECL(AL_AUTOWAH_RELEASE_TIME
),
826 DECL(AL_AUTOWAH_RESONANCE
),
827 DECL(AL_AUTOWAH_PEAK_GAIN
),
829 DECL(AL_VOCAL_MORPHER_PHONEMEA
),
830 DECL(AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING
),
831 DECL(AL_VOCAL_MORPHER_PHONEMEB
),
832 DECL(AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING
),
833 DECL(AL_VOCAL_MORPHER_WAVEFORM
),
834 DECL(AL_VOCAL_MORPHER_RATE
),
836 DECL(AL_EFFECTSLOT_TARGET_SOFT
),
838 DECL(AL_NUM_RESAMPLERS_SOFT
),
839 DECL(AL_DEFAULT_RESAMPLER_SOFT
),
840 DECL(AL_SOURCE_RESAMPLER_SOFT
),
841 DECL(AL_RESAMPLER_NAME_SOFT
),
843 DECL(AL_SOURCE_SPATIALIZE_SOFT
),
846 DECL(AL_MAP_READ_BIT_SOFT
),
847 DECL(AL_MAP_WRITE_BIT_SOFT
),
848 DECL(AL_MAP_PERSISTENT_BIT_SOFT
),
849 DECL(AL_PRESERVE_DATA_BIT_SOFT
),
851 DECL(AL_EVENT_CALLBACK_FUNCTION_SOFT
),
852 DECL(AL_EVENT_CALLBACK_USER_PARAM_SOFT
),
853 DECL(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT
),
854 DECL(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT
),
855 DECL(AL_EVENT_TYPE_DISCONNECTED_SOFT
),
857 DECL(AL_DROP_UNMATCHED_SOFT
),
858 DECL(AL_REMIX_UNMATCHED_SOFT
),
860 DECL(AL_AMBISONIC_LAYOUT_SOFT
),
861 DECL(AL_AMBISONIC_SCALING_SOFT
),
867 DECL(AL_BUFFER_CALLBACK_FUNCTION_SOFT
),
868 DECL(AL_BUFFER_CALLBACK_USER_PARAM_SOFT
),
870 DECL(AL_UNPACK_AMBISONIC_ORDER_SOFT
),
872 DECL(AL_EFFECT_CONVOLUTION_REVERB_SOFT
),
873 DECL(AL_EFFECTSLOT_STATE_SOFT
),
875 DECL(AL_FORMAT_UHJ2CHN8_SOFT
),
876 DECL(AL_FORMAT_UHJ2CHN16_SOFT
),
877 DECL(AL_FORMAT_UHJ2CHN_FLOAT32_SOFT
),
878 DECL(AL_FORMAT_UHJ3CHN8_SOFT
),
879 DECL(AL_FORMAT_UHJ3CHN16_SOFT
),
880 DECL(AL_FORMAT_UHJ3CHN_FLOAT32_SOFT
),
881 DECL(AL_FORMAT_UHJ4CHN8_SOFT
),
882 DECL(AL_FORMAT_UHJ4CHN16_SOFT
),
883 DECL(AL_FORMAT_UHJ4CHN_FLOAT32_SOFT
),
884 DECL(AL_STEREO_MODE_SOFT
),
885 DECL(AL_NORMAL_SOFT
),
886 DECL(AL_SUPER_STEREO_SOFT
),
887 DECL(AL_SUPER_STEREO_WIDTH_SOFT
),
889 DECL(AL_STOP_SOURCES_ON_DISCONNECT_SOFT
),
892 }, eaxEnumerations
[] = {
893 DECL(AL_EAX_RAM_SIZE
),
894 DECL(AL_EAX_RAM_FREE
),
895 DECL(AL_STORAGE_AUTOMATIC
),
896 DECL(AL_STORAGE_HARDWARE
),
897 DECL(AL_STORAGE_ACCESSIBLE
),
902 constexpr ALCchar alcNoError
[] = "No Error";
903 constexpr ALCchar alcErrInvalidDevice
[] = "Invalid Device";
904 constexpr ALCchar alcErrInvalidContext
[] = "Invalid Context";
905 constexpr ALCchar alcErrInvalidEnum
[] = "Invalid Enum";
906 constexpr ALCchar alcErrInvalidValue
[] = "Invalid Value";
907 constexpr ALCchar alcErrOutOfMemory
[] = "Out of Memory";
910 /************************************************
912 ************************************************/
914 /* Enumerated device names */
915 constexpr ALCchar alcDefaultName
[] = "OpenAL Soft\0";
917 std::string alcAllDevicesList
;
918 std::string alcCaptureDeviceList
;
920 /* Default is always the first in the list */
921 std::string alcDefaultAllDevicesSpecifier
;
922 std::string alcCaptureDefaultDeviceSpecifier
;
924 std::atomic
<ALCenum
> LastNullDeviceError
{ALC_NO_ERROR
};
926 /* Flag to trap ALC device errors */
927 bool TrapALCError
{false};
929 /* One-time configuration init control */
930 std::once_flag alc_config_once
{};
932 /* Flag to specify if alcSuspendContext/alcProcessContext should defer/process
935 bool SuspendDefers
{true};
937 /* Initial seed for dithering. */
938 constexpr uint DitherRNGSeed
{22222u};
941 /************************************************
943 ************************************************/
944 constexpr ALCchar alcNoDeviceExtList
[] =
945 "ALC_ENUMERATE_ALL_EXT "
946 "ALC_ENUMERATION_EXT "
949 "ALC_EXT_thread_local_context "
951 "ALC_SOFT_loopback_bformat "
952 "ALC_SOFTX_reopen_device";
953 constexpr ALCchar alcExtensionList
[] =
954 "ALC_ENUMERATE_ALL_EXT "
955 "ALC_ENUMERATION_EXT "
958 "ALC_EXT_disconnect "
960 "ALC_EXT_thread_local_context "
961 "ALC_SOFT_device_clock "
964 "ALC_SOFT_loopback_bformat "
965 "ALC_SOFT_output_limiter "
966 "ALC_SOFTX_output_mode "
967 "ALC_SOFT_pause_device "
968 "ALC_SOFTX_reopen_device";
969 constexpr int alcMajorVersion
{1};
970 constexpr int alcMinorVersion
{1};
972 constexpr int alcEFXMajorVersion
{1};
973 constexpr int alcEFXMinorVersion
{0};
976 using DeviceRef
= al::intrusive_ptr
<ALCdevice
>;
979 /************************************************
981 ************************************************/
982 al::vector
<ALCdevice
*> DeviceList
;
983 al::vector
<ALCcontext
*> ContextList
;
985 std::recursive_mutex ListLock
;
988 void alc_initconfig(void)
990 if(auto loglevel
= al::getenv("ALSOFT_LOGLEVEL"))
992 long lvl
= strtol(loglevel
->c_str(), nullptr, 0);
993 if(lvl
>= static_cast<long>(LogLevel::Trace
))
994 gLogLevel
= LogLevel::Trace
;
995 else if(lvl
<= static_cast<long>(LogLevel::Disable
))
996 gLogLevel
= LogLevel::Disable
;
998 gLogLevel
= static_cast<LogLevel
>(lvl
);
1002 if(const auto logfile
= al::getenv(L
"ALSOFT_LOGFILE"))
1004 FILE *logf
{_wfopen(logfile
->c_str(), L
"wt")};
1005 if(logf
) gLogFile
= logf
;
1008 auto u8name
= wstr_to_utf8(logfile
->c_str());
1009 ERR("Failed to open log file '%s'\n", u8name
.c_str());
1013 if(const auto logfile
= al::getenv("ALSOFT_LOGFILE"))
1015 FILE *logf
{fopen(logfile
->c_str(), "wt")};
1016 if(logf
) gLogFile
= logf
;
1017 else ERR("Failed to open log file '%s'\n", logfile
->c_str());
1021 TRACE("Initializing library v%s-%s %s\n", ALSOFT_VERSION
, ALSOFT_GIT_COMMIT_HASH
,
1025 if(al::size(BackendList
) < 1)
1029 const al::span
<const BackendInfo
> infos
{BackendList
};
1030 names
= infos
[0].name
;
1031 for(const auto &backend
: infos
.subspan
<1>())
1034 names
+= backend
.name
;
1037 TRACE("Supported backends: %s\n", names
.c_str());
1041 if(auto suspendmode
= al::getenv("__ALSOFT_SUSPEND_CONTEXT"))
1043 if(al::strcasecmp(suspendmode
->c_str(), "ignore") == 0)
1045 SuspendDefers
= false;
1046 TRACE("Selected context suspend behavior, \"ignore\"\n");
1049 ERR("Unhandled context suspend behavior setting: \"%s\"\n", suspendmode
->c_str());
1053 #if defined(HAVE_SSE4_1)
1054 capfilter
|= CPU_CAP_SSE
| CPU_CAP_SSE2
| CPU_CAP_SSE3
| CPU_CAP_SSE4_1
;
1055 #elif defined(HAVE_SSE3)
1056 capfilter
|= CPU_CAP_SSE
| CPU_CAP_SSE2
| CPU_CAP_SSE3
;
1057 #elif defined(HAVE_SSE2)
1058 capfilter
|= CPU_CAP_SSE
| CPU_CAP_SSE2
;
1059 #elif defined(HAVE_SSE)
1060 capfilter
|= CPU_CAP_SSE
;
1063 capfilter
|= CPU_CAP_NEON
;
1065 if(auto cpuopt
= ConfigValueStr(nullptr, nullptr, "disable-cpu-exts"))
1067 const char *str
{cpuopt
->c_str()};
1068 if(al::strcasecmp(str
, "all") == 0)
1072 const char *next
= str
;
1075 while(isspace(str
[0]))
1077 next
= strchr(str
, ',');
1079 if(!str
[0] || str
[0] == ',')
1082 size_t len
{next
? static_cast<size_t>(next
-str
) : strlen(str
)};
1083 while(len
> 0 && isspace(str
[len
-1]))
1085 if(len
== 3 && al::strncasecmp(str
, "sse", len
) == 0)
1086 capfilter
&= ~CPU_CAP_SSE
;
1087 else if(len
== 4 && al::strncasecmp(str
, "sse2", len
) == 0)
1088 capfilter
&= ~CPU_CAP_SSE2
;
1089 else if(len
== 4 && al::strncasecmp(str
, "sse3", len
) == 0)
1090 capfilter
&= ~CPU_CAP_SSE3
;
1091 else if(len
== 6 && al::strncasecmp(str
, "sse4.1", len
) == 0)
1092 capfilter
&= ~CPU_CAP_SSE4_1
;
1093 else if(len
== 4 && al::strncasecmp(str
, "neon", len
) == 0)
1094 capfilter
&= ~CPU_CAP_NEON
;
1096 WARN("Invalid CPU extension \"%s\"\n", str
);
1100 if(auto cpuopt
= GetCPUInfo())
1102 if(!cpuopt
->mVendor
.empty() || !cpuopt
->mName
.empty())
1104 TRACE("Vendor ID: \"%s\"\n", cpuopt
->mVendor
.c_str());
1105 TRACE("Name: \"%s\"\n", cpuopt
->mName
.c_str());
1107 const int caps
{cpuopt
->mCaps
};
1108 TRACE("Extensions:%s%s%s%s%s%s\n",
1109 ((capfilter
&CPU_CAP_SSE
) ? ((caps
&CPU_CAP_SSE
) ? " +SSE" : " -SSE") : ""),
1110 ((capfilter
&CPU_CAP_SSE2
) ? ((caps
&CPU_CAP_SSE2
) ? " +SSE2" : " -SSE2") : ""),
1111 ((capfilter
&CPU_CAP_SSE3
) ? ((caps
&CPU_CAP_SSE3
) ? " +SSE3" : " -SSE3") : ""),
1112 ((capfilter
&CPU_CAP_SSE4_1
) ? ((caps
&CPU_CAP_SSE4_1
) ? " +SSE4.1" : " -SSE4.1") : ""),
1113 ((capfilter
&CPU_CAP_NEON
) ? ((caps
&CPU_CAP_NEON
) ? " +NEON" : " -NEON") : ""),
1114 ((!capfilter
) ? " -none-" : ""));
1115 CPUCapFlags
= caps
& capfilter
;
1118 if(auto priopt
= ConfigValueInt(nullptr, nullptr, "rt-prio"))
1119 RTPrioLevel
= *priopt
;
1120 if(auto limopt
= ConfigValueBool(nullptr, nullptr, "rt-time-limit"))
1121 AllowRTTimeLimit
= *limopt
;
1124 Voice::InitMixer(ConfigValueStr(nullptr, nullptr, "resampler"));
1126 auto traperr
= al::getenv("ALSOFT_TRAP_ERROR");
1127 if(traperr
&& (al::strcasecmp(traperr
->c_str(), "true") == 0
1128 || std::strtol(traperr
->c_str(), nullptr, 0) == 1))
1131 TrapALCError
= true;
1135 traperr
= al::getenv("ALSOFT_TRAP_AL_ERROR");
1137 TrapALError
= al::strcasecmp(traperr
->c_str(), "true") == 0
1138 || strtol(traperr
->c_str(), nullptr, 0) == 1;
1140 TrapALError
= !!GetConfigValueBool(nullptr, nullptr, "trap-al-error", false);
1142 traperr
= al::getenv("ALSOFT_TRAP_ALC_ERROR");
1144 TrapALCError
= al::strcasecmp(traperr
->c_str(), "true") == 0
1145 || strtol(traperr
->c_str(), nullptr, 0) == 1;
1147 TrapALCError
= !!GetConfigValueBool(nullptr, nullptr, "trap-alc-error", false);
1150 if(auto boostopt
= ConfigValueFloat(nullptr, "reverb", "boost"))
1152 const float valf
{std::isfinite(*boostopt
) ? clampf(*boostopt
, -24.0f
, 24.0f
) : 0.0f
};
1153 ReverbBoost
*= std::pow(10.0f
, valf
/ 20.0f
);
1156 auto BackendListEnd
= std::end(BackendList
);
1157 auto devopt
= al::getenv("ALSOFT_DRIVERS");
1158 if(devopt
|| (devopt
=ConfigValueStr(nullptr, nullptr, "drivers")))
1160 auto backendlist_cur
= std::begin(BackendList
);
1163 const char *next
{devopt
->c_str()};
1165 const char *devs
{next
};
1166 while(isspace(devs
[0]))
1168 next
= strchr(devs
, ',');
1170 const bool delitem
{devs
[0] == '-'};
1171 if(devs
[0] == '-') devs
++;
1173 if(!devs
[0] || devs
[0] == ',')
1180 size_t len
{next
? (static_cast<size_t>(next
-devs
)) : strlen(devs
)};
1181 while(len
> 0 && isspace(devs
[len
-1])) --len
;
1183 /* HACK: For backwards compatibility, convert backend references of
1184 * mmdevapi to wasapi. This should eventually be removed.
1186 if(len
== 8 && strncmp(devs
, "mmdevapi", len
) == 0)
1193 auto find_backend
= [devs
,len
](const BackendInfo
&backend
) -> bool
1194 { return len
== strlen(backend
.name
) && strncmp(backend
.name
, devs
, len
) == 0; };
1195 auto this_backend
= std::find_if(std::begin(BackendList
), BackendListEnd
,
1198 if(this_backend
== BackendListEnd
)
1202 BackendListEnd
= std::move(this_backend
+1, BackendListEnd
, this_backend
);
1204 backendlist_cur
= std::rotate(backendlist_cur
, this_backend
, this_backend
+1);
1208 BackendListEnd
= backendlist_cur
;
1211 auto init_backend
= [](BackendInfo
&backend
) -> void
1213 if(PlaybackFactory
&& CaptureFactory
)
1216 BackendFactory
&factory
= backend
.getFactory();
1219 WARN("Failed to initialize backend \"%s\"\n", backend
.name
);
1223 TRACE("Initialized backend \"%s\"\n", backend
.name
);
1224 if(!PlaybackFactory
&& factory
.querySupport(BackendType::Playback
))
1226 PlaybackFactory
= &factory
;
1227 TRACE("Added \"%s\" for playback\n", backend
.name
);
1229 if(!CaptureFactory
&& factory
.querySupport(BackendType::Capture
))
1231 CaptureFactory
= &factory
;
1232 TRACE("Added \"%s\" for capture\n", backend
.name
);
1235 std::for_each(std::begin(BackendList
), BackendListEnd
, init_backend
);
1237 LoopbackBackendFactory::getFactory().init();
1239 if(!PlaybackFactory
)
1240 WARN("No playback backend available!\n");
1242 WARN("No capture backend available!\n");
1244 if(auto exclopt
= ConfigValueStr(nullptr, nullptr, "excludefx"))
1246 const char *next
{exclopt
->c_str()};
1248 const char *str
{next
};
1249 next
= strchr(str
, ',');
1251 if(!str
[0] || next
== str
)
1254 size_t len
{next
? static_cast<size_t>(next
-str
) : strlen(str
)};
1255 for(const EffectList
&effectitem
: gEffectList
)
1257 if(len
== strlen(effectitem
.name
) &&
1258 strncmp(effectitem
.name
, str
, len
) == 0)
1259 DisabledEffects
[effectitem
.type
] = true;
1264 InitEffect(&ALCcontext::sDefaultEffect
);
1265 auto defrevopt
= al::getenv("ALSOFT_DEFAULT_REVERB");
1266 if(defrevopt
|| (defrevopt
=ConfigValueStr(nullptr, nullptr, "default-reverb")))
1267 LoadReverbPreset(defrevopt
->c_str(), &ALCcontext::sDefaultEffect
);
1271 constexpr auto eax_block_name
= "eax";
1273 const auto eax_enable_opt
= ConfigValueBool(nullptr, eax_block_name
, "enable");
1277 eax_g_is_enabled
= *eax_enable_opt
;
1279 if (!eax_g_is_enabled
)
1281 TRACE("%s\n", "EAX disabled by a configuration.");
1286 eax_g_is_enabled
= true;
1288 if(eax_g_is_enabled
&& DisabledEffects
[EAXREVERB_EFFECT
])
1290 eax_g_is_enabled
= false;
1291 TRACE("%s\n", "EAX disabled because EAXReverb is disabled.");
1294 #endif // ALSOFT_EAX
1296 #define DO_INITCONFIG() std::call_once(alc_config_once, [](){alc_initconfig();})
1299 /************************************************
1300 * Device enumeration
1301 ************************************************/
1302 void ProbeAllDevicesList()
1306 std::lock_guard
<std::recursive_mutex
> _
{ListLock
};
1307 if(!PlaybackFactory
)
1308 decltype(alcAllDevicesList
){}.swap(alcAllDevicesList
);
1311 std::string names
{PlaybackFactory
->probe(BackendType::Playback
)};
1312 if(names
.empty()) names
+= '\0';
1313 names
.swap(alcAllDevicesList
);
1316 void ProbeCaptureDeviceList()
1320 std::lock_guard
<std::recursive_mutex
> _
{ListLock
};
1322 decltype(alcCaptureDeviceList
){}.swap(alcCaptureDeviceList
);
1325 std::string names
{CaptureFactory
->probe(BackendType::Capture
)};
1326 if(names
.empty()) names
+= '\0';
1327 names
.swap(alcCaptureDeviceList
);
1332 struct DevFmtPair
{ DevFmtChannels chans
; DevFmtType type
; };
1333 al::optional
<DevFmtPair
> DecomposeDevFormat(ALenum format
)
1335 static const struct {
1337 DevFmtChannels channels
;
1340 { AL_FORMAT_MONO8
, DevFmtMono
, DevFmtUByte
},
1341 { AL_FORMAT_MONO16
, DevFmtMono
, DevFmtShort
},
1342 { AL_FORMAT_MONO_FLOAT32
, DevFmtMono
, DevFmtFloat
},
1344 { AL_FORMAT_STEREO8
, DevFmtStereo
, DevFmtUByte
},
1345 { AL_FORMAT_STEREO16
, DevFmtStereo
, DevFmtShort
},
1346 { AL_FORMAT_STEREO_FLOAT32
, DevFmtStereo
, DevFmtFloat
},
1348 { AL_FORMAT_QUAD8
, DevFmtQuad
, DevFmtUByte
},
1349 { AL_FORMAT_QUAD16
, DevFmtQuad
, DevFmtShort
},
1350 { AL_FORMAT_QUAD32
, DevFmtQuad
, DevFmtFloat
},
1352 { AL_FORMAT_51CHN8
, DevFmtX51
, DevFmtUByte
},
1353 { AL_FORMAT_51CHN16
, DevFmtX51
, DevFmtShort
},
1354 { AL_FORMAT_51CHN32
, DevFmtX51
, DevFmtFloat
},
1356 { AL_FORMAT_61CHN8
, DevFmtX61
, DevFmtUByte
},
1357 { AL_FORMAT_61CHN16
, DevFmtX61
, DevFmtShort
},
1358 { AL_FORMAT_61CHN32
, DevFmtX61
, DevFmtFloat
},
1360 { AL_FORMAT_71CHN8
, DevFmtX71
, DevFmtUByte
},
1361 { AL_FORMAT_71CHN16
, DevFmtX71
, DevFmtShort
},
1362 { AL_FORMAT_71CHN32
, DevFmtX71
, DevFmtFloat
},
1365 for(const auto &item
: list
)
1367 if(item
.format
== format
)
1368 return al::make_optional(DevFmtPair
{item
.channels
, item
.type
});
1374 al::optional
<DevFmtType
> DevFmtTypeFromEnum(ALCenum type
)
1378 case ALC_BYTE_SOFT
: return al::make_optional(DevFmtByte
);
1379 case ALC_UNSIGNED_BYTE_SOFT
: return al::make_optional(DevFmtUByte
);
1380 case ALC_SHORT_SOFT
: return al::make_optional(DevFmtShort
);
1381 case ALC_UNSIGNED_SHORT_SOFT
: return al::make_optional(DevFmtUShort
);
1382 case ALC_INT_SOFT
: return al::make_optional(DevFmtInt
);
1383 case ALC_UNSIGNED_INT_SOFT
: return al::make_optional(DevFmtUInt
);
1384 case ALC_FLOAT_SOFT
: return al::make_optional(DevFmtFloat
);
1386 WARN("Unsupported format type: 0x%04x\n", type
);
1389 ALCenum
EnumFromDevFmt(DevFmtType type
)
1393 case DevFmtByte
: return ALC_BYTE_SOFT
;
1394 case DevFmtUByte
: return ALC_UNSIGNED_BYTE_SOFT
;
1395 case DevFmtShort
: return ALC_SHORT_SOFT
;
1396 case DevFmtUShort
: return ALC_UNSIGNED_SHORT_SOFT
;
1397 case DevFmtInt
: return ALC_INT_SOFT
;
1398 case DevFmtUInt
: return ALC_UNSIGNED_INT_SOFT
;
1399 case DevFmtFloat
: return ALC_FLOAT_SOFT
;
1401 throw std::runtime_error
{"Invalid DevFmtType: "+std::to_string(int(type
))};
1404 al::optional
<DevFmtChannels
> DevFmtChannelsFromEnum(ALCenum channels
)
1408 case ALC_MONO_SOFT
: return al::make_optional(DevFmtMono
);
1409 case ALC_STEREO_SOFT
: return al::make_optional(DevFmtStereo
);
1410 case ALC_QUAD_SOFT
: return al::make_optional(DevFmtQuad
);
1411 case ALC_5POINT1_SOFT
: return al::make_optional(DevFmtX51
);
1412 case ALC_6POINT1_SOFT
: return al::make_optional(DevFmtX61
);
1413 case ALC_7POINT1_SOFT
: return al::make_optional(DevFmtX71
);
1414 case ALC_BFORMAT3D_SOFT
: return al::make_optional(DevFmtAmbi3D
);
1416 WARN("Unsupported format channels: 0x%04x\n", channels
);
1419 ALCenum
EnumFromDevFmt(DevFmtChannels channels
)
1423 case DevFmtMono
: return ALC_MONO_SOFT
;
1424 case DevFmtStereo
: return ALC_STEREO_SOFT
;
1425 case DevFmtQuad
: return ALC_QUAD_SOFT
;
1426 case DevFmtX51
: return ALC_5POINT1_SOFT
;
1427 case DevFmtX61
: return ALC_6POINT1_SOFT
;
1428 case DevFmtX71
: return ALC_7POINT1_SOFT
;
1429 case DevFmtAmbi3D
: return ALC_BFORMAT3D_SOFT
;
1431 throw std::runtime_error
{"Invalid DevFmtChannels: "+std::to_string(int(channels
))};
1434 al::optional
<DevAmbiLayout
> DevAmbiLayoutFromEnum(ALCenum layout
)
1438 case ALC_FUMA_SOFT
: return al::make_optional(DevAmbiLayout::FuMa
);
1439 case ALC_ACN_SOFT
: return al::make_optional(DevAmbiLayout::ACN
);
1441 WARN("Unsupported ambisonic layout: 0x%04x\n", layout
);
1444 ALCenum
EnumFromDevAmbi(DevAmbiLayout layout
)
1448 case DevAmbiLayout::FuMa
: return ALC_FUMA_SOFT
;
1449 case DevAmbiLayout::ACN
: return ALC_ACN_SOFT
;
1451 throw std::runtime_error
{"Invalid DevAmbiLayout: "+std::to_string(int(layout
))};
1454 al::optional
<DevAmbiScaling
> DevAmbiScalingFromEnum(ALCenum scaling
)
1458 case ALC_FUMA_SOFT
: return al::make_optional(DevAmbiScaling::FuMa
);
1459 case ALC_SN3D_SOFT
: return al::make_optional(DevAmbiScaling::SN3D
);
1460 case ALC_N3D_SOFT
: return al::make_optional(DevAmbiScaling::N3D
);
1462 WARN("Unsupported ambisonic scaling: 0x%04x\n", scaling
);
1465 ALCenum
EnumFromDevAmbi(DevAmbiScaling scaling
)
1469 case DevAmbiScaling::FuMa
: return ALC_FUMA_SOFT
;
1470 case DevAmbiScaling::SN3D
: return ALC_SN3D_SOFT
;
1471 case DevAmbiScaling::N3D
: return ALC_N3D_SOFT
;
1473 throw std::runtime_error
{"Invalid DevAmbiScaling: "+std::to_string(int(scaling
))};
1477 /* Downmixing channel arrays, to map the given format's missing channels to
1478 * existing ones. Based on Wine's DSound downmix values, which are based on
1481 const std::array
<InputRemixMap
,6> StereoDownmix
{{
1482 { FrontCenter
, {{{FrontLeft
, 0.5f
}, {FrontRight
, 0.5f
}}} },
1483 { SideLeft
, {{{FrontLeft
, 1.0f
/9.0f
}, {FrontRight
, 0.0f
}}} },
1484 { SideRight
, {{{FrontLeft
, 0.0f
}, {FrontRight
, 1.0f
/9.0f
}}} },
1485 { BackLeft
, {{{FrontLeft
, 1.0f
/9.0f
}, {FrontRight
, 0.0f
}}} },
1486 { BackRight
, {{{FrontLeft
, 0.0f
}, {FrontRight
, 1.0f
/9.0f
}}} },
1487 { BackCenter
, {{{FrontLeft
, 0.5f
/9.0f
}, {FrontRight
, 0.5f
/9.0f
}}} },
1489 const std::array
<InputRemixMap
,4> QuadDownmix
{{
1490 { FrontCenter
, {{{FrontLeft
, 0.5f
}, {FrontRight
, 0.5f
}}} },
1491 { SideLeft
, {{{FrontLeft
, 0.5f
}, {BackLeft
, 0.5f
}}} },
1492 { SideRight
, {{{FrontRight
, 0.5f
}, {BackRight
, 0.5f
}}} },
1493 { BackCenter
, {{{BackLeft
, 0.5f
}, {BackRight
, 0.5f
}}} },
1495 const std::array
<InputRemixMap
,3> X51Downmix
{{
1496 { BackLeft
, {{{SideLeft
, 1.0f
}, {SideRight
, 0.0f
}}} },
1497 { BackRight
, {{{SideLeft
, 0.0f
}, {SideRight
, 1.0f
}}} },
1498 { BackCenter
, {{{SideLeft
, 0.5f
}, {SideRight
, 0.5f
}}} },
1500 const std::array
<InputRemixMap
,2> X61Downmix
{{
1501 { BackLeft
, {{{BackCenter
, 0.5f
}, {SideLeft
, 0.5f
}}} },
1502 { BackRight
, {{{BackCenter
, 0.5f
}, {SideRight
, 0.5f
}}} },
1504 const std::array
<InputRemixMap
,1> X71Downmix
{{
1505 { BackCenter
, {{{BackLeft
, 0.5f
}, {BackRight
, 0.5f
}}} },
1509 /** Stores the latest ALC device error. */
1510 void alcSetError(ALCdevice
*device
, ALCenum errorCode
)
1512 WARN("Error generated on device %p, code 0x%04x\n", voidp
{device
}, errorCode
);
1516 /* DebugBreak() will cause an exception if there is no debugger */
1517 if(IsDebuggerPresent())
1519 #elif defined(SIGTRAP)
1525 device
->LastError
.store(errorCode
);
1527 LastNullDeviceError
.store(errorCode
);
1531 std::unique_ptr
<Compressor
> CreateDeviceLimiter(const ALCdevice
*device
, const float threshold
)
1533 constexpr bool AutoKnee
{true};
1534 constexpr bool AutoAttack
{true};
1535 constexpr bool AutoRelease
{true};
1536 constexpr bool AutoPostGain
{true};
1537 constexpr bool AutoDeclip
{true};
1538 constexpr float LookAheadTime
{0.001f
};
1539 constexpr float HoldTime
{0.002f
};
1540 constexpr float PreGainDb
{0.0f
};
1541 constexpr float PostGainDb
{0.0f
};
1542 constexpr float Ratio
{std::numeric_limits
<float>::infinity()};
1543 constexpr float KneeDb
{0.0f
};
1544 constexpr float AttackTime
{0.02f
};
1545 constexpr float ReleaseTime
{0.2f
};
1547 return Compressor::Create(device
->RealOut
.Buffer
.size(), static_cast<float>(device
->Frequency
),
1548 AutoKnee
, AutoAttack
, AutoRelease
, AutoPostGain
, AutoDeclip
, LookAheadTime
, HoldTime
,
1549 PreGainDb
, PostGainDb
, threshold
, Ratio
, KneeDb
, AttackTime
, ReleaseTime
);
1553 * Updates the device's base clock time with however many samples have been
1554 * done. This is used so frequency changes on the device don't cause the time
1555 * to jump forward or back. Must not be called while the device is running/
1558 static inline void UpdateClockBase(ALCdevice
*device
)
1560 IncrementRef(device
->MixCount
);
1561 device
->ClockBase
+= nanoseconds
{seconds
{device
->SamplesDone
}} / device
->Frequency
;
1562 device
->SamplesDone
= 0;
1563 IncrementRef(device
->MixCount
);
1567 * Updates device parameters according to the attribute list (caller is
1568 * responsible for holding the list lock).
1570 ALCenum
UpdateDeviceParams(ALCdevice
*device
, const int *attrList
)
1572 if((!attrList
|| !attrList
[0]) && device
->Type
== DeviceType::Loopback
)
1574 WARN("Missing attributes for loopback device\n");
1575 return ALC_INVALID_VALUE
;
1578 al::optional
<StereoEncoding
> stereomode
{};
1579 al::optional
<bool> optlimit
{};
1582 // Check for attributes
1583 if(attrList
&& attrList
[0])
1585 uint numMono
{device
->NumMonoSources
};
1586 uint numStereo
{device
->NumStereoSources
};
1587 uint numSends
{device
->NumAuxSends
};
1589 al::optional
<DevFmtChannels
> optchans
;
1590 al::optional
<DevFmtType
> opttype
;
1591 al::optional
<DevAmbiLayout
> optlayout
;
1592 al::optional
<DevAmbiScaling
> optscale
;
1593 al::optional
<bool> opthrtf
;
1598 #define TRACE_ATTR(a, v) TRACE("%s = %d\n", #a, v)
1600 while(attrList
[attrIdx
])
1602 switch(attrList
[attrIdx
])
1604 case ALC_FORMAT_CHANNELS_SOFT
:
1605 TRACE_ATTR(ALC_FORMAT_CHANNELS_SOFT
, attrList
[attrIdx
+ 1]);
1606 optchans
= DevFmtChannelsFromEnum(attrList
[attrIdx
+ 1]);
1609 case ALC_FORMAT_TYPE_SOFT
:
1610 TRACE_ATTR(ALC_FORMAT_TYPE_SOFT
, attrList
[attrIdx
+ 1]);
1611 opttype
= DevFmtTypeFromEnum(attrList
[attrIdx
+ 1]);
1615 freq
= static_cast<uint
>(attrList
[attrIdx
+ 1]);
1616 TRACE_ATTR(ALC_FREQUENCY
, freq
);
1619 case ALC_AMBISONIC_LAYOUT_SOFT
:
1620 TRACE_ATTR(ALC_AMBISONIC_LAYOUT_SOFT
, attrList
[attrIdx
+ 1]);
1621 optlayout
= DevAmbiLayoutFromEnum(attrList
[attrIdx
+ 1]);
1624 case ALC_AMBISONIC_SCALING_SOFT
:
1625 TRACE_ATTR(ALC_AMBISONIC_SCALING_SOFT
, attrList
[attrIdx
+ 1]);
1626 optscale
= DevAmbiScalingFromEnum(attrList
[attrIdx
+ 1]);
1629 case ALC_AMBISONIC_ORDER_SOFT
:
1630 aorder
= static_cast<uint
>(attrList
[attrIdx
+ 1]);
1631 TRACE_ATTR(ALC_AMBISONIC_ORDER_SOFT
, aorder
);
1634 case ALC_MONO_SOURCES
:
1635 numMono
= static_cast<uint
>(attrList
[attrIdx
+ 1]);
1636 TRACE_ATTR(ALC_MONO_SOURCES
, numMono
);
1637 if(numMono
> INT_MAX
) numMono
= 0;
1640 case ALC_STEREO_SOURCES
:
1641 numStereo
= static_cast<uint
>(attrList
[attrIdx
+ 1]);
1642 TRACE_ATTR(ALC_STEREO_SOURCES
, numStereo
);
1643 if(numStereo
> INT_MAX
) numStereo
= 0;
1646 case ALC_MAX_AUXILIARY_SENDS
:
1647 numSends
= static_cast<uint
>(attrList
[attrIdx
+ 1]);
1648 TRACE_ATTR(ALC_MAX_AUXILIARY_SENDS
, numSends
);
1649 if(numSends
> INT_MAX
) numSends
= 0;
1650 else numSends
= minu(numSends
, MAX_SENDS
);
1654 TRACE_ATTR(ALC_HRTF_SOFT
, attrList
[attrIdx
+ 1]);
1655 if(attrList
[attrIdx
+ 1] == ALC_FALSE
)
1657 else if(attrList
[attrIdx
+ 1] == ALC_TRUE
)
1659 else if(attrList
[attrIdx
+ 1] == ALC_DONT_CARE_SOFT
)
1660 opthrtf
= al::nullopt
;
1663 case ALC_HRTF_ID_SOFT
:
1664 hrtf_id
= attrList
[attrIdx
+ 1];
1665 TRACE_ATTR(ALC_HRTF_ID_SOFT
, hrtf_id
);
1668 case ALC_OUTPUT_LIMITER_SOFT
:
1669 TRACE_ATTR(ALC_OUTPUT_LIMITER_SOFT
, attrList
[attrIdx
+ 1]);
1670 if(attrList
[attrIdx
+ 1] == ALC_FALSE
)
1672 else if(attrList
[attrIdx
+ 1] == ALC_TRUE
)
1674 else if(attrList
[attrIdx
+ 1] == ALC_DONT_CARE_SOFT
)
1675 optlimit
= al::nullopt
;
1678 case ALC_OUTPUT_MODE_SOFT
:
1679 TRACE_ATTR(ALC_HRTF_SOFT
, attrList
[attrIdx
+ 1]);
1680 if(attrList
[attrIdx
+ 1] == ALC_HRTF_SOFT
)
1681 stereomode
= StereoEncoding::Hrtf
;
1682 else if(attrList
[attrIdx
+ 1] == ALC_STEREO_UHJ_SOFT
)
1683 stereomode
= StereoEncoding::Uhj
;
1684 else if(attrList
[attrIdx
+ 1] == ALC_NORMAL_SOFT
)
1685 stereomode
= StereoEncoding::Normal
;
1686 else if(attrList
[attrIdx
+ 1] == ALC_ANY_SOFT
)
1687 stereomode
= al::nullopt
;
1691 TRACE("0x%04X = %d (0x%x)\n", attrList
[attrIdx
],
1692 attrList
[attrIdx
+ 1], attrList
[attrIdx
+ 1]);
1700 const bool loopback
{device
->Type
== DeviceType::Loopback
};
1703 if(!optchans
|| !opttype
)
1704 return ALC_INVALID_VALUE
;
1705 if(freq
< MIN_OUTPUT_RATE
|| freq
> MAX_OUTPUT_RATE
)
1706 return ALC_INVALID_VALUE
;
1707 if(*optchans
== DevFmtAmbi3D
)
1709 if(!optlayout
|| !optscale
)
1710 return ALC_INVALID_VALUE
;
1711 if(aorder
< 1 || aorder
> MaxAmbiOrder
)
1712 return ALC_INVALID_VALUE
;
1713 if((*optlayout
== DevAmbiLayout::FuMa
|| *optscale
== DevAmbiScaling::FuMa
)
1715 return ALC_INVALID_VALUE
;
1719 /* If a context is already running on the device, stop playback so the
1720 * device attributes can be updated.
1722 if(device
->Flags
.test(DeviceRunning
))
1723 device
->Backend
->stop();
1724 device
->Flags
.reset(DeviceRunning
);
1726 UpdateClockBase(device
);
1728 if(!stereomode
&& opthrtf
)
1729 stereomode
= *opthrtf
? StereoEncoding::Hrtf
: StereoEncoding::Normal
;
1733 device
->Frequency
= freq
;
1734 device
->FmtChans
= *optchans
;
1735 device
->FmtType
= *opttype
;
1736 if(device
->FmtChans
== DevFmtAmbi3D
)
1738 device
->mAmbiOrder
= aorder
;
1739 device
->mAmbiLayout
= *optlayout
;
1740 device
->mAmbiScale
= *optscale
;
1745 device
->BufferSize
= DEFAULT_UPDATE_SIZE
* DEFAULT_NUM_UPDATES
;
1746 device
->UpdateSize
= DEFAULT_UPDATE_SIZE
;
1747 device
->Frequency
= DEFAULT_OUTPUT_RATE
;
1749 freq
= device
->configValue
<uint
>(nullptr, "frequency").value_or(freq
);
1751 device
->Flags
.reset(FrequencyRequest
);
1754 freq
= clampu(freq
, MIN_OUTPUT_RATE
, MAX_OUTPUT_RATE
);
1756 const double scale
{static_cast<double>(freq
) / device
->Frequency
};
1757 device
->UpdateSize
= static_cast<uint
>(device
->UpdateSize
*scale
+ 0.5);
1758 device
->BufferSize
= static_cast<uint
>(device
->BufferSize
*scale
+ 0.5);
1760 device
->Frequency
= freq
;
1761 device
->Flags
.set(FrequencyRequest
);
1764 if(auto persizeopt
= device
->configValue
<uint
>(nullptr, "period_size"))
1765 device
->UpdateSize
= clampu(*persizeopt
, 64, 8192);
1767 if(auto peropt
= device
->configValue
<uint
>(nullptr, "periods"))
1768 device
->BufferSize
= device
->UpdateSize
* clampu(*peropt
, 2, 16);
1770 device
->BufferSize
= maxu(device
->BufferSize
, device
->UpdateSize
*2);
1773 if(numMono
> INT_MAX
-numStereo
)
1774 numMono
= INT_MAX
-numStereo
;
1775 numMono
+= numStereo
;
1776 if(auto srcsopt
= device
->configValue
<uint
>(nullptr, "sources"))
1778 if(*srcsopt
<= 0) numMono
= 256;
1779 else numMono
= *srcsopt
;
1782 numMono
= maxu(numMono
, 256);
1783 numStereo
= minu(numStereo
, numMono
);
1784 numMono
-= numStereo
;
1785 device
->SourcesMax
= numMono
+ numStereo
;
1787 device
->NumMonoSources
= numMono
;
1788 device
->NumStereoSources
= numStereo
;
1790 if(auto sendsopt
= device
->configValue
<int>(nullptr, "sends"))
1791 device
->NumAuxSends
= minu(numSends
,
1792 static_cast<uint
>(clampi(*sendsopt
, 0, MAX_SENDS
)));
1794 device
->NumAuxSends
= numSends
;
1797 if(device
->Flags
.test(DeviceRunning
))
1798 return ALC_NO_ERROR
;
1800 device
->AvgSpeakerDist
= 0.0f
;
1801 device
->mNFCtrlFilter
= NfcFilter
{};
1802 device
->mUhjEncoder
= nullptr;
1803 device
->AmbiDecoder
= nullptr;
1804 device
->Bs2b
= nullptr;
1805 device
->PostProcess
= nullptr;
1807 device
->Limiter
= nullptr;
1808 device
->ChannelDelays
= nullptr;
1810 std::fill(std::begin(device
->HrtfAccumData
), std::end(device
->HrtfAccumData
), float2
{});
1812 device
->Dry
.AmbiMap
.fill(BFChannelConfig
{});
1813 device
->Dry
.Buffer
= {};
1814 std::fill(std::begin(device
->NumChannelsPerOrder
), std::end(device
->NumChannelsPerOrder
), 0u);
1815 device
->RealOut
.RemixMap
= {};
1816 device
->RealOut
.ChannelIndex
.fill(INVALID_CHANNEL_INDEX
);
1817 device
->RealOut
.Buffer
= {};
1818 device
->MixBuffer
.clear();
1819 device
->MixBuffer
.shrink_to_fit();
1821 UpdateClockBase(device
);
1822 device
->FixedLatency
= nanoseconds::zero();
1824 device
->DitherDepth
= 0.0f
;
1825 device
->DitherSeed
= DitherRNGSeed
;
1827 /*************************************************************************
1828 * Update device format request if HRTF or UHJ is requested
1830 device
->mHrtfStatus
= ALC_HRTF_DISABLED_SOFT
;
1831 if(device
->Type
!= DeviceType::Loopback
)
1833 if(auto hrtfopt
= device
->configValue
<std::string
>(nullptr, "hrtf"))
1835 const char *hrtf
{hrtfopt
->c_str()};
1836 if(al::strcasecmp(hrtf
, "true") == 0)
1837 stereomode
= StereoEncoding::Hrtf
;
1838 else if(al::strcasecmp(hrtf
, "false") == 0)
1840 if(!stereomode
|| *stereomode
== StereoEncoding::Hrtf
)
1841 stereomode
= StereoEncoding::Normal
;
1843 else if(al::strcasecmp(hrtf
, "auto") != 0)
1844 ERR("Unexpected hrtf value: %s\n", hrtf
);
1847 /* If the app or user wants HRTF or UHJ, try to set stereo playback. */
1848 if(stereomode
&& *stereomode
!= StereoEncoding::Normal
)
1850 device
->FmtChans
= DevFmtStereo
;
1851 device
->Flags
.set(ChannelsRequest
);
1855 TRACE("Pre-reset: %s%s, %s%s, %s%uhz, %u / %u buffer\n",
1856 device
->Flags
.test(ChannelsRequest
)?"*":"", DevFmtChannelsString(device
->FmtChans
),
1857 device
->Flags
.test(SampleTypeRequest
)?"*":"", DevFmtTypeString(device
->FmtType
),
1858 device
->Flags
.test(FrequencyRequest
)?"*":"", device
->Frequency
,
1859 device
->UpdateSize
, device
->BufferSize
);
1861 const uint oldFreq
{device
->Frequency
};
1862 const DevFmtChannels oldChans
{device
->FmtChans
};
1863 const DevFmtType oldType
{device
->FmtType
};
1865 auto backend
= device
->Backend
.get();
1866 if(!backend
->reset())
1867 throw al::backend_exception
{al::backend_error::DeviceError
, "Device reset failure"};
1869 catch(std::exception
&e
) {
1870 ERR("Device error: %s\n", e
.what());
1871 device
->handleDisconnect("%s", e
.what());
1872 return ALC_INVALID_DEVICE
;
1875 if(device
->FmtChans
!= oldChans
&& device
->Flags
.test(ChannelsRequest
))
1877 ERR("Failed to set %s, got %s instead\n", DevFmtChannelsString(oldChans
),
1878 DevFmtChannelsString(device
->FmtChans
));
1879 device
->Flags
.reset(ChannelsRequest
);
1881 if(device
->FmtType
!= oldType
&& device
->Flags
.test(SampleTypeRequest
))
1883 ERR("Failed to set %s, got %s instead\n", DevFmtTypeString(oldType
),
1884 DevFmtTypeString(device
->FmtType
));
1885 device
->Flags
.reset(SampleTypeRequest
);
1887 if(device
->Frequency
!= oldFreq
&& device
->Flags
.test(FrequencyRequest
))
1889 WARN("Failed to set %uhz, got %uhz instead\n", oldFreq
, device
->Frequency
);
1890 device
->Flags
.reset(FrequencyRequest
);
1893 TRACE("Post-reset: %s, %s, %uhz, %u / %u buffer\n",
1894 DevFmtChannelsString(device
->FmtChans
), DevFmtTypeString(device
->FmtType
),
1895 device
->Frequency
, device
->UpdateSize
, device
->BufferSize
);
1897 if(device
->Type
!= DeviceType::Loopback
)
1899 if(auto modeopt
= device
->configValue
<std::string
>(nullptr, "stereo-mode"))
1901 const char *mode
{modeopt
->c_str()};
1902 if(al::strcasecmp(mode
, "headphones") == 0)
1903 device
->Flags
.set(DirectEar
);
1904 else if(al::strcasecmp(mode
, "speakers") == 0)
1905 device
->Flags
.reset(DirectEar
);
1906 else if(al::strcasecmp(mode
, "auto") != 0)
1907 ERR("Unexpected stereo-mode: %s\n", mode
);
1910 if(auto encopt
= device
->configValue
<std::string
>(nullptr, "stereo-encoding"))
1912 const char *mode
{encopt
->c_str()};
1913 if(al::strcasecmp(mode
, "panpot") == 0)
1914 stereomode
= al::make_optional(StereoEncoding::Normal
);
1915 else if(al::strcasecmp(mode
, "uhj") == 0)
1916 stereomode
= al::make_optional(StereoEncoding::Uhj
);
1917 else if(al::strcasecmp(mode
, "hrtf") == 0)
1918 stereomode
= al::make_optional(StereoEncoding::Hrtf
);
1920 ERR("Unexpected stereo-encoding: %s\n", mode
);
1924 aluInitRenderer(device
, hrtf_id
, stereomode
);
1926 TRACE("Max sources: %d (%d + %d), effect slots: %d, sends: %d\n",
1927 device
->SourcesMax
, device
->NumMonoSources
, device
->NumStereoSources
,
1928 device
->AuxiliaryEffectSlotMax
, device
->NumAuxSends
);
1930 switch(device
->FmtChans
)
1932 case DevFmtMono
: break;
1934 if(!device
->mUhjEncoder
)
1935 device
->RealOut
.RemixMap
= StereoDownmix
;
1937 case DevFmtQuad
: device
->RealOut
.RemixMap
= QuadDownmix
; break;
1938 case DevFmtX51
: device
->RealOut
.RemixMap
= X51Downmix
; break;
1939 case DevFmtX61
: device
->RealOut
.RemixMap
= X61Downmix
; break;
1940 case DevFmtX71
: device
->RealOut
.RemixMap
= X71Downmix
; break;
1941 case DevFmtAmbi3D
: break;
1944 nanoseconds::rep sample_delay
{0};
1945 if(device
->mUhjEncoder
)
1946 sample_delay
+= UhjEncoder::sFilterDelay
;
1947 if(device
->mHrtfState
)
1948 sample_delay
+= HrtfDirectDelay
;
1949 if(auto *ambidec
= device
->AmbiDecoder
.get())
1951 if(ambidec
->hasStablizer())
1952 sample_delay
+= FrontStablizer::DelayLength
;
1955 if(device
->getConfigValueBool(nullptr, "dither", 1))
1957 int depth
{device
->configValue
<int>(nullptr, "dither-depth").value_or(0)};
1960 switch(device
->FmtType
)
1979 depth
= clampi(depth
, 2, 24);
1980 device
->DitherDepth
= std::pow(2.0f
, static_cast<float>(depth
-1));
1983 if(!(device
->DitherDepth
> 0.0f
))
1984 TRACE("Dithering disabled\n");
1986 TRACE("Dithering enabled (%d-bit, %g)\n", float2int(std::log2(device
->DitherDepth
)+0.5f
)+1,
1987 device
->DitherDepth
);
1989 if(auto limopt
= device
->configValue
<bool>(nullptr, "output-limiter"))
1992 /* If the gain limiter is unset, use the limiter for integer-based output
1993 * (where samples must be clamped), and don't for floating-point (which can
1994 * take unclamped samples).
1998 switch(device
->FmtType
)
2012 if(optlimit
.value_or(false) == false)
2013 TRACE("Output limiter disabled\n");
2016 float thrshld
{1.0f
};
2017 switch(device
->FmtType
)
2021 thrshld
= 127.0f
/ 128.0f
;
2025 thrshld
= 32767.0f
/ 32768.0f
;
2032 if(device
->DitherDepth
> 0.0f
)
2033 thrshld
-= 1.0f
/ device
->DitherDepth
;
2035 const float thrshld_dB
{std::log10(thrshld
) * 20.0f
};
2036 auto limiter
= CreateDeviceLimiter(device
, thrshld_dB
);
2038 sample_delay
+= limiter
->getLookAhead();
2039 device
->Limiter
= std::move(limiter
);
2040 TRACE("Output limiter enabled, %.4fdB limit\n", thrshld_dB
);
2043 /* Convert the sample delay from samples to nanosamples to nanoseconds. */
2044 device
->FixedLatency
+= nanoseconds
{seconds
{sample_delay
}} / device
->Frequency
;
2045 TRACE("Fixed device latency: %" PRId64
"ns\n", int64_t{device
->FixedLatency
.count()});
2047 FPUCtl mixer_mode
{};
2048 for(ContextBase
*ctxbase
: *device
->mContexts
.load())
2050 auto *context
= static_cast<ALCcontext
*>(ctxbase
);
2052 auto GetEffectBuffer
= [](ALbuffer
*buffer
) noexcept
-> EffectState::Buffer
2054 if(!buffer
) return EffectState::Buffer
{};
2055 return EffectState::Buffer
{buffer
, buffer
->mData
};
2057 std::unique_lock
<std::mutex
> proplock
{context
->mPropLock
};
2058 std::unique_lock
<std::mutex
> slotlock
{context
->mEffectSlotLock
};
2060 /* Clear out unused wet buffers. */
2061 auto buffer_not_in_use
= [](WetBufferPtr
&wetbuffer
) noexcept
-> bool
2062 { return !wetbuffer
->mInUse
; };
2063 auto wetbuffer_iter
= std::remove_if(context
->mWetBuffers
.begin(),
2064 context
->mWetBuffers
.end(), buffer_not_in_use
);
2065 context
->mWetBuffers
.erase(wetbuffer_iter
, context
->mWetBuffers
.end());
2067 if(ALeffectslot
*slot
{context
->mDefaultSlot
.get()})
2069 aluInitEffectPanning(&slot
->mSlot
, context
);
2071 EffectState
*state
{slot
->Effect
.State
.get()};
2072 state
->mOutTarget
= device
->Dry
.Buffer
;
2073 state
->deviceUpdate(device
, GetEffectBuffer(slot
->Buffer
));
2074 slot
->updateProps(context
);
2077 if(EffectSlotArray
*curarray
{context
->mActiveAuxSlots
.load(std::memory_order_relaxed
)})
2078 std::fill_n(curarray
->end(), curarray
->size(), nullptr);
2079 for(auto &sublist
: context
->mEffectSlotList
)
2081 uint64_t usemask
{~sublist
.FreeMask
};
2084 const int idx
{al::countr_zero(usemask
)};
2085 ALeffectslot
*slot
{sublist
.EffectSlots
+ idx
};
2086 usemask
&= ~(1_u64
<< idx
);
2088 aluInitEffectPanning(&slot
->mSlot
, context
);
2090 EffectState
*state
{slot
->Effect
.State
.get()};
2091 state
->mOutTarget
= device
->Dry
.Buffer
;
2092 state
->deviceUpdate(device
, GetEffectBuffer(slot
->Buffer
));
2093 slot
->updateProps(context
);
2098 const uint num_sends
{device
->NumAuxSends
};
2099 std::unique_lock
<std::mutex
> srclock
{context
->mSourceLock
};
2100 for(auto &sublist
: context
->mSourceList
)
2102 uint64_t usemask
{~sublist
.FreeMask
};
2105 const int idx
{al::countr_zero(usemask
)};
2106 ALsource
*source
{sublist
.Sources
+ idx
};
2107 usemask
&= ~(1_u64
<< idx
);
2109 auto clear_send
= [](ALsource::SendData
&send
) -> void
2112 DecrementRef(send
.Slot
->ref
);
2113 send
.Slot
= nullptr;
2116 send
.HFReference
= LOWPASSFREQREF
;
2118 send
.LFReference
= HIGHPASSFREQREF
;
2120 auto send_begin
= source
->Send
.begin() + static_cast<ptrdiff_t>(num_sends
);
2121 std::for_each(send_begin
, source
->Send
.end(), clear_send
);
2123 source
->mPropsDirty
= true;
2127 auto voicelist
= context
->getVoicesSpan();
2128 for(Voice
*voice
: voicelist
)
2130 /* Clear extraneous property set sends. */
2131 std::fill(std::begin(voice
->mProps
.Send
)+num_sends
, std::end(voice
->mProps
.Send
),
2132 VoiceProps::SendData
{});
2134 std::fill(voice
->mSend
.begin()+num_sends
, voice
->mSend
.end(), Voice::TargetData
{});
2135 for(auto &chandata
: voice
->mChans
)
2137 std::fill(chandata
.mWetParams
.begin()+num_sends
, chandata
.mWetParams
.end(),
2141 if(VoicePropsItem
*props
{voice
->mUpdate
.exchange(nullptr, std::memory_order_relaxed
)})
2142 AtomicReplaceHead(context
->mFreeVoiceProps
, props
);
2144 /* Force the voice to stopped if it was stopping. */
2145 Voice::State vstate
{Voice::Stopping
};
2146 voice
->mPlayState
.compare_exchange_strong(vstate
, Voice::Stopped
,
2147 std::memory_order_acquire
, std::memory_order_acquire
);
2148 if(voice
->mSourceID
.load(std::memory_order_relaxed
) == 0u)
2151 voice
->prepare(device
);
2153 /* Clear all voice props to let them get allocated again. */
2154 context
->mVoicePropClusters
.clear();
2155 context
->mFreeVoiceProps
.store(nullptr, std::memory_order_relaxed
);
2158 context
->mPropsDirty
= false;
2159 UpdateContextProps(context
);
2160 UpdateAllSourceProps(context
);
2164 if(!device
->Flags
.test(DevicePaused
))
2167 auto backend
= device
->Backend
.get();
2169 device
->Flags
.set(DeviceRunning
);
2171 catch(al::backend_exception
& e
) {
2172 ERR("%s\n", e
.what());
2173 device
->handleDisconnect("%s", e
.what());
2174 return ALC_INVALID_DEVICE
;
2176 TRACE("Post-start: %s, %s, %uhz, %u / %u buffer\n",
2177 DevFmtChannelsString(device
->FmtChans
), DevFmtTypeString(device
->FmtType
),
2178 device
->Frequency
, device
->UpdateSize
, device
->BufferSize
);
2181 return ALC_NO_ERROR
;
2185 * Updates device parameters as above, and also first clears the disconnected
2188 bool ResetDeviceParams(ALCdevice
*device
, const int *attrList
)
2190 /* If the device was disconnected, reset it since we're opened anew. */
2191 if UNLIKELY(!device
->Connected
.load(std::memory_order_relaxed
))
2193 /* Make sure disconnection is finished before continuing on. */
2194 device
->waitForMix();
2196 for(ContextBase
*ctxbase
: *device
->mContexts
.load(std::memory_order_acquire
))
2198 auto *ctx
= static_cast<ALCcontext
*>(ctxbase
);
2199 if(!ctx
->mStopVoicesOnDisconnect
.load(std::memory_order_acquire
))
2202 /* Clear any pending voice changes and reallocate voices to get a
2205 std::lock_guard
<std::mutex
> __
{ctx
->mSourceLock
};
2206 auto *vchg
= ctx
->mCurrentVoiceChange
.load(std::memory_order_acquire
);
2207 while(auto *next
= vchg
->mNext
.load(std::memory_order_acquire
))
2209 ctx
->mCurrentVoiceChange
.store(vchg
, std::memory_order_release
);
2211 ctx
->mVoicePropClusters
.clear();
2212 ctx
->mFreeVoiceProps
.store(nullptr, std::memory_order_relaxed
);
2214 ctx
->mVoiceClusters
.clear();
2215 ctx
->allocVoices(std::max
<size_t>(256,
2216 ctx
->mActiveVoiceCount
.load(std::memory_order_relaxed
)));
2219 device
->Connected
.store(true);
2222 ALCenum err
{UpdateDeviceParams(device
, attrList
)};
2223 if LIKELY(err
== ALC_NO_ERROR
) return ALC_TRUE
;
2225 alcSetError(device
, err
);
2230 /** Checks if the device handle is valid, and returns a new reference if so. */
2231 DeviceRef
VerifyDevice(ALCdevice
*device
)
2233 std::lock_guard
<std::recursive_mutex
> _
{ListLock
};
2234 auto iter
= std::lower_bound(DeviceList
.begin(), DeviceList
.end(), device
);
2235 if(iter
!= DeviceList
.end() && *iter
== device
)
2238 return DeviceRef
{*iter
};
2245 * Checks if the given context is valid, returning a new reference to it if so.
2247 ContextRef
VerifyContext(ALCcontext
*context
)
2249 std::lock_guard
<std::recursive_mutex
> _
{ListLock
};
2250 auto iter
= std::lower_bound(ContextList
.begin(), ContextList
.end(), context
);
2251 if(iter
!= ContextList
.end() && *iter
== context
)
2254 return ContextRef
{*iter
};
2261 /** Returns a new reference to the currently active context for this thread. */
2262 ContextRef
GetContextRef(void)
2264 ALCcontext
*context
{ALCcontext::getThreadContext()};
2269 std::lock_guard
<std::recursive_mutex
> _
{ListLock
};
2270 context
= ALCcontext::sGlobalContext
.load(std::memory_order_acquire
);
2271 if(context
) context
->add_ref();
2273 return ContextRef
{context
};
2277 /************************************************
2278 * Standard ALC functions
2279 ************************************************/
2281 ALC_API ALCenum ALC_APIENTRY
alcGetError(ALCdevice
*device
)
2284 DeviceRef dev
{VerifyDevice(device
)};
2285 if(dev
) return dev
->LastError
.exchange(ALC_NO_ERROR
);
2286 return LastNullDeviceError
.exchange(ALC_NO_ERROR
);
2291 ALC_API
void ALC_APIENTRY
alcSuspendContext(ALCcontext
*context
)
2297 ContextRef ctx
{VerifyContext(context
)};
2299 alcSetError(nullptr, ALC_INVALID_CONTEXT
);
2302 std::lock_guard
<std::mutex
> _
{ctx
->mPropLock
};
2303 ctx
->deferUpdates();
2308 ALC_API
void ALC_APIENTRY
alcProcessContext(ALCcontext
*context
)
2314 ContextRef ctx
{VerifyContext(context
)};
2316 alcSetError(nullptr, ALC_INVALID_CONTEXT
);
2319 std::lock_guard
<std::mutex
> _
{ctx
->mPropLock
};
2320 ctx
->processUpdates();
2326 ALC_API
const ALCchar
* ALC_APIENTRY
alcGetString(ALCdevice
*Device
, ALCenum param
)
2329 const ALCchar
*value
{nullptr};
2337 case ALC_INVALID_ENUM
:
2338 value
= alcErrInvalidEnum
;
2341 case ALC_INVALID_VALUE
:
2342 value
= alcErrInvalidValue
;
2345 case ALC_INVALID_DEVICE
:
2346 value
= alcErrInvalidDevice
;
2349 case ALC_INVALID_CONTEXT
:
2350 value
= alcErrInvalidContext
;
2353 case ALC_OUT_OF_MEMORY
:
2354 value
= alcErrOutOfMemory
;
2357 case ALC_DEVICE_SPECIFIER
:
2358 value
= alcDefaultName
;
2361 case ALC_ALL_DEVICES_SPECIFIER
:
2362 if(DeviceRef dev
{VerifyDevice(Device
)})
2364 if(dev
->Type
== DeviceType::Capture
)
2365 alcSetError(dev
.get(), ALC_INVALID_ENUM
);
2366 else if(dev
->Type
== DeviceType::Loopback
)
2367 value
= alcDefaultName
;
2370 std::lock_guard
<std::mutex
> _
{dev
->StateLock
};
2371 value
= dev
->DeviceName
.c_str();
2376 ProbeAllDevicesList();
2377 value
= alcAllDevicesList
.c_str();
2381 case ALC_CAPTURE_DEVICE_SPECIFIER
:
2382 if(DeviceRef dev
{VerifyDevice(Device
)})
2384 if(dev
->Type
!= DeviceType::Capture
)
2385 alcSetError(dev
.get(), ALC_INVALID_ENUM
);
2388 std::lock_guard
<std::mutex
> _
{dev
->StateLock
};
2389 value
= dev
->DeviceName
.c_str();
2394 ProbeCaptureDeviceList();
2395 value
= alcCaptureDeviceList
.c_str();
2399 /* Default devices are always first in the list */
2400 case ALC_DEFAULT_DEVICE_SPECIFIER
:
2401 value
= alcDefaultName
;
2404 case ALC_DEFAULT_ALL_DEVICES_SPECIFIER
:
2405 if(alcAllDevicesList
.empty())
2406 ProbeAllDevicesList();
2408 /* Copy first entry as default. */
2409 alcDefaultAllDevicesSpecifier
= alcAllDevicesList
.c_str();
2410 value
= alcDefaultAllDevicesSpecifier
.c_str();
2413 case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER
:
2414 if(alcCaptureDeviceList
.empty())
2415 ProbeCaptureDeviceList();
2417 /* Copy first entry as default. */
2418 alcCaptureDefaultDeviceSpecifier
= alcCaptureDeviceList
.c_str();
2419 value
= alcCaptureDefaultDeviceSpecifier
.c_str();
2422 case ALC_EXTENSIONS
:
2423 if(VerifyDevice(Device
))
2424 value
= alcExtensionList
;
2426 value
= alcNoDeviceExtList
;
2429 case ALC_HRTF_SPECIFIER_SOFT
:
2430 if(DeviceRef dev
{VerifyDevice(Device
)})
2432 std::lock_guard
<std::mutex
> _
{dev
->StateLock
};
2433 value
= (dev
->mHrtf
? dev
->mHrtfName
.c_str() : "");
2436 alcSetError(nullptr, ALC_INVALID_DEVICE
);
2440 alcSetError(VerifyDevice(Device
).get(), ALC_INVALID_ENUM
);
2449 static size_t GetIntegerv(ALCdevice
*device
, ALCenum param
, const al::span
<int> values
)
2455 alcSetError(device
, ALC_INVALID_VALUE
);
2463 case ALC_MAJOR_VERSION
:
2464 values
[0] = alcMajorVersion
;
2466 case ALC_MINOR_VERSION
:
2467 values
[0] = alcMinorVersion
;
2470 case ALC_EFX_MAJOR_VERSION
:
2471 values
[0] = alcEFXMajorVersion
;
2473 case ALC_EFX_MINOR_VERSION
:
2474 values
[0] = alcEFXMinorVersion
;
2476 case ALC_MAX_AUXILIARY_SENDS
:
2477 values
[0] = MAX_SENDS
;
2480 case ALC_ATTRIBUTES_SIZE
:
2481 case ALC_ALL_ATTRIBUTES
:
2485 case ALC_MONO_SOURCES
:
2486 case ALC_STEREO_SOURCES
:
2487 case ALC_CAPTURE_SAMPLES
:
2488 case ALC_FORMAT_CHANNELS_SOFT
:
2489 case ALC_FORMAT_TYPE_SOFT
:
2490 case ALC_AMBISONIC_LAYOUT_SOFT
:
2491 case ALC_AMBISONIC_SCALING_SOFT
:
2492 case ALC_AMBISONIC_ORDER_SOFT
:
2493 case ALC_MAX_AMBISONIC_ORDER_SOFT
:
2494 alcSetError(nullptr, ALC_INVALID_DEVICE
);
2498 alcSetError(nullptr, ALC_INVALID_ENUM
);
2503 std::lock_guard
<std::mutex
> _
{device
->StateLock
};
2504 if(device
->Type
== DeviceType::Capture
)
2506 constexpr int MaxCaptureAttributes
{9};
2509 case ALC_ATTRIBUTES_SIZE
:
2510 values
[0] = MaxCaptureAttributes
;
2512 case ALC_ALL_ATTRIBUTES
:
2514 if(values
.size() < MaxCaptureAttributes
)
2515 alcSetError(device
, ALC_INVALID_VALUE
);
2518 values
[i
++] = ALC_MAJOR_VERSION
;
2519 values
[i
++] = alcMajorVersion
;
2520 values
[i
++] = ALC_MINOR_VERSION
;
2521 values
[i
++] = alcMinorVersion
;
2522 values
[i
++] = ALC_CAPTURE_SAMPLES
;
2523 values
[i
++] = static_cast<int>(device
->Backend
->availableSamples());
2524 values
[i
++] = ALC_CONNECTED
;
2525 values
[i
++] = device
->Connected
.load(std::memory_order_relaxed
);
2527 assert(i
== MaxCaptureAttributes
);
2531 case ALC_MAJOR_VERSION
:
2532 values
[0] = alcMajorVersion
;
2534 case ALC_MINOR_VERSION
:
2535 values
[0] = alcMinorVersion
;
2538 case ALC_CAPTURE_SAMPLES
:
2539 values
[0] = static_cast<int>(device
->Backend
->availableSamples());
2543 values
[0] = device
->Connected
.load(std::memory_order_acquire
);
2547 alcSetError(device
, ALC_INVALID_ENUM
);
2553 auto NumAttrsForDevice
= [](ALCdevice
*aldev
) noexcept
2555 if(aldev
->Type
== DeviceType::Loopback
&& aldev
->FmtChans
== DevFmtAmbi3D
)
2561 case ALC_ATTRIBUTES_SIZE
:
2562 values
[0] = NumAttrsForDevice(device
);
2565 case ALC_ALL_ATTRIBUTES
:
2567 if(values
.size() < static_cast<size_t>(NumAttrsForDevice(device
)))
2568 alcSetError(device
, ALC_INVALID_VALUE
);
2571 values
[i
++] = ALC_MAJOR_VERSION
;
2572 values
[i
++] = alcMajorVersion
;
2573 values
[i
++] = ALC_MINOR_VERSION
;
2574 values
[i
++] = alcMinorVersion
;
2575 values
[i
++] = ALC_EFX_MAJOR_VERSION
;
2576 values
[i
++] = alcEFXMajorVersion
;
2577 values
[i
++] = ALC_EFX_MINOR_VERSION
;
2578 values
[i
++] = alcEFXMinorVersion
;
2580 values
[i
++] = ALC_FREQUENCY
;
2581 values
[i
++] = static_cast<int>(device
->Frequency
);
2582 if(device
->Type
!= DeviceType::Loopback
)
2584 values
[i
++] = ALC_REFRESH
;
2585 values
[i
++] = static_cast<int>(device
->Frequency
/ device
->UpdateSize
);
2587 values
[i
++] = ALC_SYNC
;
2588 values
[i
++] = ALC_FALSE
;
2592 if(device
->FmtChans
== DevFmtAmbi3D
)
2594 values
[i
++] = ALC_AMBISONIC_LAYOUT_SOFT
;
2595 values
[i
++] = EnumFromDevAmbi(device
->mAmbiLayout
);
2597 values
[i
++] = ALC_AMBISONIC_SCALING_SOFT
;
2598 values
[i
++] = EnumFromDevAmbi(device
->mAmbiScale
);
2600 values
[i
++] = ALC_AMBISONIC_ORDER_SOFT
;
2601 values
[i
++] = static_cast<int>(device
->mAmbiOrder
);
2604 values
[i
++] = ALC_FORMAT_CHANNELS_SOFT
;
2605 values
[i
++] = EnumFromDevFmt(device
->FmtChans
);
2607 values
[i
++] = ALC_FORMAT_TYPE_SOFT
;
2608 values
[i
++] = EnumFromDevFmt(device
->FmtType
);
2611 values
[i
++] = ALC_MONO_SOURCES
;
2612 values
[i
++] = static_cast<int>(device
->NumMonoSources
);
2614 values
[i
++] = ALC_STEREO_SOURCES
;
2615 values
[i
++] = static_cast<int>(device
->NumStereoSources
);
2617 values
[i
++] = ALC_MAX_AUXILIARY_SENDS
;
2618 values
[i
++] = static_cast<int>(device
->NumAuxSends
);
2620 values
[i
++] = ALC_HRTF_SOFT
;
2621 values
[i
++] = (device
->mHrtf
? ALC_TRUE
: ALC_FALSE
);
2623 values
[i
++] = ALC_HRTF_STATUS_SOFT
;
2624 values
[i
++] = device
->mHrtfStatus
;
2626 values
[i
++] = ALC_OUTPUT_LIMITER_SOFT
;
2627 values
[i
++] = device
->Limiter
? ALC_TRUE
: ALC_FALSE
;
2629 values
[i
++] = ALC_MAX_AMBISONIC_ORDER_SOFT
;
2630 values
[i
++] = MaxAmbiOrder
;
2636 case ALC_MAJOR_VERSION
:
2637 values
[0] = alcMajorVersion
;
2640 case ALC_MINOR_VERSION
:
2641 values
[0] = alcMinorVersion
;
2644 case ALC_EFX_MAJOR_VERSION
:
2645 values
[0] = alcEFXMajorVersion
;
2648 case ALC_EFX_MINOR_VERSION
:
2649 values
[0] = alcEFXMinorVersion
;
2653 values
[0] = static_cast<int>(device
->Frequency
);
2657 if(device
->Type
== DeviceType::Loopback
)
2659 alcSetError(device
, ALC_INVALID_DEVICE
);
2662 values
[0] = static_cast<int>(device
->Frequency
/ device
->UpdateSize
);
2666 if(device
->Type
== DeviceType::Loopback
)
2668 alcSetError(device
, ALC_INVALID_DEVICE
);
2671 values
[0] = ALC_FALSE
;
2674 case ALC_FORMAT_CHANNELS_SOFT
:
2675 if(device
->Type
!= DeviceType::Loopback
)
2677 alcSetError(device
, ALC_INVALID_DEVICE
);
2680 values
[0] = EnumFromDevFmt(device
->FmtChans
);
2683 case ALC_FORMAT_TYPE_SOFT
:
2684 if(device
->Type
!= DeviceType::Loopback
)
2686 alcSetError(device
, ALC_INVALID_DEVICE
);
2689 values
[0] = EnumFromDevFmt(device
->FmtType
);
2692 case ALC_AMBISONIC_LAYOUT_SOFT
:
2693 if(device
->Type
!= DeviceType::Loopback
|| device
->FmtChans
!= DevFmtAmbi3D
)
2695 alcSetError(device
, ALC_INVALID_DEVICE
);
2698 values
[0] = EnumFromDevAmbi(device
->mAmbiLayout
);
2701 case ALC_AMBISONIC_SCALING_SOFT
:
2702 if(device
->Type
!= DeviceType::Loopback
|| device
->FmtChans
!= DevFmtAmbi3D
)
2704 alcSetError(device
, ALC_INVALID_DEVICE
);
2707 values
[0] = EnumFromDevAmbi(device
->mAmbiScale
);
2710 case ALC_AMBISONIC_ORDER_SOFT
:
2711 if(device
->Type
!= DeviceType::Loopback
|| device
->FmtChans
!= DevFmtAmbi3D
)
2713 alcSetError(device
, ALC_INVALID_DEVICE
);
2716 values
[0] = static_cast<int>(device
->mAmbiOrder
);
2719 case ALC_MONO_SOURCES
:
2720 values
[0] = static_cast<int>(device
->NumMonoSources
);
2723 case ALC_STEREO_SOURCES
:
2724 values
[0] = static_cast<int>(device
->NumStereoSources
);
2727 case ALC_MAX_AUXILIARY_SENDS
:
2728 values
[0] = static_cast<int>(device
->NumAuxSends
);
2732 values
[0] = device
->Connected
.load(std::memory_order_acquire
);
2736 values
[0] = (device
->mHrtf
? ALC_TRUE
: ALC_FALSE
);
2739 case ALC_HRTF_STATUS_SOFT
:
2740 values
[0] = device
->mHrtfStatus
;
2743 case ALC_NUM_HRTF_SPECIFIERS_SOFT
:
2744 device
->enumerateHrtfs();
2745 values
[0] = static_cast<int>(minz(device
->mHrtfList
.size(),
2746 std::numeric_limits
<int>::max()));
2749 case ALC_OUTPUT_LIMITER_SOFT
:
2750 values
[0] = device
->Limiter
? ALC_TRUE
: ALC_FALSE
;
2753 case ALC_MAX_AMBISONIC_ORDER_SOFT
:
2754 values
[0] = MaxAmbiOrder
;
2757 case ALC_OUTPUT_MODE_SOFT
:
2759 values
[0] = ALC_HRTF_SOFT
;
2760 else if(device
->mUhjEncoder
)
2761 values
[0] = ALC_STEREO_UHJ_SOFT
;
2763 values
[0] = ALC_NORMAL_SOFT
;
2767 alcSetError(device
, ALC_INVALID_ENUM
);
2772 ALC_API
void ALC_APIENTRY
alcGetIntegerv(ALCdevice
*device
, ALCenum param
, ALCsizei size
, ALCint
*values
)
2775 DeviceRef dev
{VerifyDevice(device
)};
2776 if(size
<= 0 || values
== nullptr)
2777 alcSetError(dev
.get(), ALC_INVALID_VALUE
);
2779 GetIntegerv(dev
.get(), param
, {values
, static_cast<uint
>(size
)});
2783 ALC_API
void ALC_APIENTRY
alcGetInteger64vSOFT(ALCdevice
*device
, ALCenum pname
, ALCsizei size
, ALCint64SOFT
*values
)
2786 DeviceRef dev
{VerifyDevice(device
)};
2787 if(size
<= 0 || values
== nullptr)
2789 alcSetError(dev
.get(), ALC_INVALID_VALUE
);
2792 if(!dev
|| dev
->Type
== DeviceType::Capture
)
2794 auto ivals
= al::vector
<int>(static_cast<uint
>(size
));
2795 if(size_t got
{GetIntegerv(dev
.get(), pname
, ivals
)})
2796 std::copy_n(ivals
.begin(), got
, values
);
2800 auto NumAttrsForDevice
= [](ALCdevice
*aldev
) noexcept
2802 if(aldev
->Type
== DeviceType::Loopback
&& aldev
->FmtChans
== DevFmtAmbi3D
)
2806 std::lock_guard
<std::mutex
> _
{dev
->StateLock
};
2809 case ALC_ATTRIBUTES_SIZE
:
2810 *values
= NumAttrsForDevice(dev
.get());
2813 case ALC_ALL_ATTRIBUTES
:
2814 if(size
< NumAttrsForDevice(dev
.get()))
2815 alcSetError(dev
.get(), ALC_INVALID_VALUE
);
2819 values
[i
++] = ALC_FREQUENCY
;
2820 values
[i
++] = dev
->Frequency
;
2822 if(dev
->Type
!= DeviceType::Loopback
)
2824 values
[i
++] = ALC_REFRESH
;
2825 values
[i
++] = dev
->Frequency
/ dev
->UpdateSize
;
2827 values
[i
++] = ALC_SYNC
;
2828 values
[i
++] = ALC_FALSE
;
2832 values
[i
++] = ALC_FORMAT_CHANNELS_SOFT
;
2833 values
[i
++] = EnumFromDevFmt(dev
->FmtChans
);
2835 values
[i
++] = ALC_FORMAT_TYPE_SOFT
;
2836 values
[i
++] = EnumFromDevFmt(dev
->FmtType
);
2838 if(dev
->FmtChans
== DevFmtAmbi3D
)
2840 values
[i
++] = ALC_AMBISONIC_LAYOUT_SOFT
;
2841 values
[i
++] = EnumFromDevAmbi(dev
->mAmbiLayout
);
2843 values
[i
++] = ALC_AMBISONIC_SCALING_SOFT
;
2844 values
[i
++] = EnumFromDevAmbi(dev
->mAmbiScale
);
2846 values
[i
++] = ALC_AMBISONIC_ORDER_SOFT
;
2847 values
[i
++] = dev
->mAmbiOrder
;
2851 values
[i
++] = ALC_MONO_SOURCES
;
2852 values
[i
++] = dev
->NumMonoSources
;
2854 values
[i
++] = ALC_STEREO_SOURCES
;
2855 values
[i
++] = dev
->NumStereoSources
;
2857 values
[i
++] = ALC_MAX_AUXILIARY_SENDS
;
2858 values
[i
++] = dev
->NumAuxSends
;
2860 values
[i
++] = ALC_HRTF_SOFT
;
2861 values
[i
++] = (dev
->mHrtf
? ALC_TRUE
: ALC_FALSE
);
2863 values
[i
++] = ALC_HRTF_STATUS_SOFT
;
2864 values
[i
++] = dev
->mHrtfStatus
;
2866 values
[i
++] = ALC_OUTPUT_LIMITER_SOFT
;
2867 values
[i
++] = dev
->Limiter
? ALC_TRUE
: ALC_FALSE
;
2869 ClockLatency clock
{GetClockLatency(dev
.get(), dev
->Backend
.get())};
2870 values
[i
++] = ALC_DEVICE_CLOCK_SOFT
;
2871 values
[i
++] = clock
.ClockTime
.count();
2873 values
[i
++] = ALC_DEVICE_LATENCY_SOFT
;
2874 values
[i
++] = clock
.Latency
.count();
2880 case ALC_DEVICE_CLOCK_SOFT
:
2882 uint samplecount
, refcount
;
2883 nanoseconds basecount
;
2885 refcount
= dev
->waitForMix();
2886 basecount
= dev
->ClockBase
;
2887 samplecount
= dev
->SamplesDone
;
2888 } while(refcount
!= ReadRef(dev
->MixCount
));
2889 basecount
+= nanoseconds
{seconds
{samplecount
}} / dev
->Frequency
;
2890 *values
= basecount
.count();
2894 case ALC_DEVICE_LATENCY_SOFT
:
2895 *values
= GetClockLatency(dev
.get(), dev
->Backend
.get()).Latency
.count();
2898 case ALC_DEVICE_CLOCK_LATENCY_SOFT
:
2900 alcSetError(dev
.get(), ALC_INVALID_VALUE
);
2903 ClockLatency clock
{GetClockLatency(dev
.get(), dev
->Backend
.get())};
2904 values
[0] = clock
.ClockTime
.count();
2905 values
[1] = clock
.Latency
.count();
2910 auto ivals
= al::vector
<int>(static_cast<uint
>(size
));
2911 if(size_t got
{GetIntegerv(dev
.get(), pname
, ivals
)})
2912 std::copy_n(ivals
.begin(), got
, values
);
2919 ALC_API ALCboolean ALC_APIENTRY
alcIsExtensionPresent(ALCdevice
*device
, const ALCchar
*extName
)
2922 DeviceRef dev
{VerifyDevice(device
)};
2924 alcSetError(dev
.get(), ALC_INVALID_VALUE
);
2927 size_t len
= strlen(extName
);
2928 const char *ptr
= (dev
? alcExtensionList
: alcNoDeviceExtList
);
2931 if(al::strncasecmp(ptr
, extName
, len
) == 0 && (ptr
[len
] == '\0' || isspace(ptr
[len
])))
2934 if((ptr
=strchr(ptr
, ' ')) != nullptr)
2938 } while(isspace(*ptr
));
2947 ALC_API ALCvoid
* ALC_APIENTRY
alcGetProcAddress(ALCdevice
*device
, const ALCchar
*funcName
)
2952 DeviceRef dev
{VerifyDevice(device
)};
2953 alcSetError(dev
.get(), ALC_INVALID_VALUE
);
2957 if(eax_g_is_enabled
)
2959 for(const auto &func
: eaxFunctions
)
2961 if(strcmp(func
.funcName
, funcName
) == 0)
2962 return func
.address
;
2966 for(const auto &func
: alcFunctions
)
2968 if(strcmp(func
.funcName
, funcName
) == 0)
2969 return func
.address
;
2976 ALC_API ALCenum ALC_APIENTRY
alcGetEnumValue(ALCdevice
*device
, const ALCchar
*enumName
)
2981 DeviceRef dev
{VerifyDevice(device
)};
2982 alcSetError(dev
.get(), ALC_INVALID_VALUE
);
2986 if(eax_g_is_enabled
)
2988 for(const auto &enm
: eaxEnumerations
)
2990 if(strcmp(enm
.enumName
, enumName
) == 0)
2995 for(const auto &enm
: alcEnumerations
)
2997 if(strcmp(enm
.enumName
, enumName
) == 0)
3006 ALC_API ALCcontext
* ALC_APIENTRY
alcCreateContext(ALCdevice
*device
, const ALCint
*attrList
)
3009 /* Explicitly hold the list lock while taking the StateLock in case the
3010 * device is asynchronously destroyed, to ensure this new context is
3011 * properly cleaned up after being made.
3013 std::unique_lock
<std::recursive_mutex
> listlock
{ListLock
};
3014 DeviceRef dev
{VerifyDevice(device
)};
3015 if(!dev
|| dev
->Type
== DeviceType::Capture
|| !dev
->Connected
.load(std::memory_order_relaxed
))
3018 alcSetError(dev
.get(), ALC_INVALID_DEVICE
);
3021 std::unique_lock
<std::mutex
> statelock
{dev
->StateLock
};
3024 dev
->LastError
.store(ALC_NO_ERROR
);
3026 ALCenum err
{UpdateDeviceParams(dev
.get(), attrList
)};
3027 if(err
!= ALC_NO_ERROR
)
3029 alcSetError(dev
.get(), err
);
3033 ContextRef context
{new ALCcontext
{dev
}};
3036 if(auto volopt
= dev
->configValue
<float>(nullptr, "volume-adjust"))
3038 const float valf
{*volopt
};
3039 if(!std::isfinite(valf
))
3040 ERR("volume-adjust must be finite: %f\n", valf
);
3043 const float db
{clampf(valf
, -24.0f
, 24.0f
)};
3045 WARN("volume-adjust clamped: %f, range: +/-%f\n", valf
, 24.0f
);
3046 context
->mGainBoost
= std::pow(10.0f
, db
/20.0f
);
3047 TRACE("volume-adjust gain: %f\n", context
->mGainBoost
);
3052 using ContextArray
= al::FlexArray
<ContextBase
*>;
3054 /* Allocate a new context array, which holds 1 more than the current/
3057 auto *oldarray
= device
->mContexts
.load();
3058 const size_t newcount
{oldarray
->size()+1};
3059 std::unique_ptr
<ContextArray
> newarray
{ContextArray::Create(newcount
)};
3061 /* Copy the current/old context handles to the new array, appending the
3064 auto iter
= std::copy(oldarray
->begin(), oldarray
->end(), newarray
->begin());
3065 *iter
= context
.get();
3067 /* Store the new context array in the device. Wait for any current mix
3068 * to finish before deleting the old array.
3070 dev
->mContexts
.store(newarray
.release());
3071 if(oldarray
!= &DeviceBase::sEmptyContextArray
)
3080 std::lock_guard
<std::recursive_mutex
> _
{ListLock
};
3081 auto iter
= std::lower_bound(ContextList
.cbegin(), ContextList
.cend(), context
.get());
3082 ContextList
.emplace(iter
, context
.get());
3085 if(ALeffectslot
*slot
{context
->mDefaultSlot
.get()})
3087 ALenum sloterr
{slot
->initEffect(ALCcontext::sDefaultEffect
.type
,
3088 ALCcontext::sDefaultEffect
.Props
, context
.get())};
3089 if(sloterr
== AL_NO_ERROR
)
3090 slot
->updateProps(context
.get());
3092 ERR("Failed to initialize the default effect\n");
3095 TRACE("Created context %p\n", voidp
{context
.get()});
3096 return context
.release();
3100 ALC_API
void ALC_APIENTRY
alcDestroyContext(ALCcontext
*context
)
3103 std::unique_lock
<std::recursive_mutex
> listlock
{ListLock
};
3104 auto iter
= std::lower_bound(ContextList
.begin(), ContextList
.end(), context
);
3105 if(iter
== ContextList
.end() || *iter
!= context
)
3108 alcSetError(nullptr, ALC_INVALID_CONTEXT
);
3112 /* Hold a reference to this context so it remains valid until the ListLock
3115 ContextRef ctx
{*iter
};
3116 ContextList
.erase(iter
);
3118 ALCdevice
*Device
{ctx
->mALDevice
.get()};
3120 std::lock_guard
<std::mutex
> _
{Device
->StateLock
};
3121 if(!ctx
->deinit() && Device
->Flags
.test(DeviceRunning
))
3123 Device
->Backend
->stop();
3124 Device
->Flags
.reset(DeviceRunning
);
3130 ALC_API ALCcontext
* ALC_APIENTRY
alcGetCurrentContext(void)
3133 ALCcontext
*Context
{ALCcontext::getThreadContext()};
3134 if(!Context
) Context
= ALCcontext::sGlobalContext
.load();
3139 /** Returns the currently active thread-local context. */
3140 ALC_API ALCcontext
* ALC_APIENTRY
alcGetThreadContext(void)
3142 { return ALCcontext::getThreadContext(); }
3145 ALC_API ALCboolean ALC_APIENTRY
alcMakeContextCurrent(ALCcontext
*context
)
3148 /* context must be valid or nullptr */
3152 ctx
= VerifyContext(context
);
3155 alcSetError(nullptr, ALC_INVALID_CONTEXT
);
3159 /* Release this reference (if any) to store it in the GlobalContext
3160 * pointer. Take ownership of the reference (if any) that was previously
3163 ctx
= ContextRef
{ALCcontext::sGlobalContext
.exchange(ctx
.release())};
3165 /* Reset (decrement) the previous global reference by replacing it with the
3166 * thread-local context. Take ownership of the thread-local context
3167 * reference (if any), clearing the storage to null.
3169 ctx
= ContextRef
{ALCcontext::getThreadContext()};
3170 if(ctx
) ALCcontext::setThreadContext(nullptr);
3171 /* Reset (decrement) the previous thread-local reference. */
3177 /** Makes the given context the active context for the current thread. */
3178 ALC_API ALCboolean ALC_APIENTRY
alcSetThreadContext(ALCcontext
*context
)
3181 /* context must be valid or nullptr */
3185 ctx
= VerifyContext(context
);
3188 alcSetError(nullptr, ALC_INVALID_CONTEXT
);
3192 /* context's reference count is already incremented */
3193 ContextRef old
{ALCcontext::getThreadContext()};
3194 ALCcontext::setThreadContext(ctx
.release());
3201 ALC_API ALCdevice
* ALC_APIENTRY
alcGetContextsDevice(ALCcontext
*Context
)
3204 ContextRef ctx
{VerifyContext(Context
)};
3207 alcSetError(nullptr, ALC_INVALID_CONTEXT
);
3210 return ctx
->mALDevice
.get();
3215 ALC_API ALCdevice
* ALC_APIENTRY
alcOpenDevice(const ALCchar
*deviceName
)
3220 if(!PlaybackFactory
)
3222 alcSetError(nullptr, ALC_INVALID_VALUE
);
3228 if(!deviceName
[0] || al::strcasecmp(deviceName
, alcDefaultName
) == 0
3230 /* Some old Windows apps hardcode these expecting OpenAL to use a
3231 * specific audio API, even when they're not enumerated. Creative's
3232 * router effectively ignores them too.
3234 || al::strcasecmp(deviceName
, "DirectSound3D") == 0
3235 || al::strcasecmp(deviceName
, "DirectSound") == 0
3236 || al::strcasecmp(deviceName
, "MMSYSTEM") == 0
3238 /* Some old Linux apps hardcode configuration strings that were
3239 * supported by the OpenAL SI. We can't really do anything useful
3240 * with them, so just ignore.
3242 || (deviceName
[0] == '\'' && deviceName
[1] == '(')
3243 || al::strcasecmp(deviceName
, "openal-soft") == 0)
3244 deviceName
= nullptr;
3247 DeviceRef device
{new ALCdevice
{DeviceType::Playback
}};
3249 /* Set output format */
3250 device
->FmtChans
= DevFmtChannelsDefault
;
3251 device
->FmtType
= DevFmtTypeDefault
;
3252 device
->Frequency
= DEFAULT_OUTPUT_RATE
;
3253 device
->UpdateSize
= DEFAULT_UPDATE_SIZE
;
3254 device
->BufferSize
= DEFAULT_UPDATE_SIZE
* DEFAULT_NUM_UPDATES
;
3256 device
->SourcesMax
= 256;
3257 device
->AuxiliaryEffectSlotMax
= 64;
3258 device
->NumAuxSends
= DEFAULT_SENDS
;
3261 if (eax_g_is_enabled
)
3263 device
->NumAuxSends
= EAX_MAX_FXSLOTS
;
3265 #endif // ALSOFT_EAX
3268 auto backend
= PlaybackFactory
->createBackend(device
.get(), BackendType::Playback
);
3269 std::lock_guard
<std::recursive_mutex
> _
{ListLock
};
3270 backend
->open(deviceName
);
3271 device
->Backend
= std::move(backend
);
3273 catch(al::backend_exception
&e
) {
3274 WARN("Failed to open playback device: %s\n", e
.what());
3275 alcSetError(nullptr, (e
.errorCode() == al::backend_error::OutOfMemory
)
3276 ? ALC_OUT_OF_MEMORY
: ALC_INVALID_VALUE
);
3280 if(auto chanopt
= device
->configValue
<std::string
>(nullptr, "channels"))
3282 static const struct ChannelMap
{
3283 const char name
[16];
3284 DevFmtChannels chans
;
3287 { "mono", DevFmtMono
, 0 },
3288 { "stereo", DevFmtStereo
, 0 },
3289 { "quad", DevFmtQuad
, 0 },
3290 { "surround51", DevFmtX51
, 0 },
3291 { "surround61", DevFmtX61
, 0 },
3292 { "surround71", DevFmtX71
, 0 },
3293 { "surround51rear", DevFmtX51
, 0 },
3294 { "ambi1", DevFmtAmbi3D
, 1 },
3295 { "ambi2", DevFmtAmbi3D
, 2 },
3296 { "ambi3", DevFmtAmbi3D
, 3 },
3299 const ALCchar
*fmt
{chanopt
->c_str()};
3300 auto iter
= std::find_if(std::begin(chanlist
), std::end(chanlist
),
3301 [fmt
](const ChannelMap
&entry
) -> bool
3302 { return al::strcasecmp(entry
.name
, fmt
) == 0; }
3304 if(iter
== std::end(chanlist
))
3305 ERR("Unsupported channels: %s\n", fmt
);
3308 device
->FmtChans
= iter
->chans
;
3309 device
->mAmbiOrder
= iter
->order
;
3310 device
->Flags
.set(ChannelsRequest
);
3313 if(auto typeopt
= device
->configValue
<std::string
>(nullptr, "sample-type"))
3315 static const struct TypeMap
{
3316 const char name
[16];
3319 { "int8", DevFmtByte
},
3320 { "uint8", DevFmtUByte
},
3321 { "int16", DevFmtShort
},
3322 { "uint16", DevFmtUShort
},
3323 { "int32", DevFmtInt
},
3324 { "uint32", DevFmtUInt
},
3325 { "float32", DevFmtFloat
},
3328 const ALCchar
*fmt
{typeopt
->c_str()};
3329 auto iter
= std::find_if(std::begin(typelist
), std::end(typelist
),
3330 [fmt
](const TypeMap
&entry
) -> bool
3331 { return al::strcasecmp(entry
.name
, fmt
) == 0; }
3333 if(iter
== std::end(typelist
))
3334 ERR("Unsupported sample-type: %s\n", fmt
);
3337 device
->FmtType
= iter
->type
;
3338 device
->Flags
.set(SampleTypeRequest
);
3342 if(uint freq
{device
->configValue
<uint
>(nullptr, "frequency").value_or(0u)})
3344 if(freq
< MIN_OUTPUT_RATE
|| freq
> MAX_OUTPUT_RATE
)
3346 const uint newfreq
{clampu(freq
, MIN_OUTPUT_RATE
, MAX_OUTPUT_RATE
)};
3347 ERR("%uhz request clamped to %uhz\n", freq
, newfreq
);
3350 const double scale
{static_cast<double>(freq
) / device
->Frequency
};
3351 device
->UpdateSize
= static_cast<uint
>(device
->UpdateSize
*scale
+ 0.5);
3352 device
->BufferSize
= static_cast<uint
>(device
->BufferSize
*scale
+ 0.5);
3353 device
->Frequency
= freq
;
3354 device
->Flags
.set(FrequencyRequest
);
3357 if(auto persizeopt
= device
->configValue
<uint
>(nullptr, "period_size"))
3358 device
->UpdateSize
= clampu(*persizeopt
, 64, 8192);
3360 if(auto peropt
= device
->configValue
<uint
>(nullptr, "periods"))
3361 device
->BufferSize
= device
->UpdateSize
* clampu(*peropt
, 2, 16);
3363 device
->BufferSize
= maxu(device
->BufferSize
, device
->UpdateSize
*2);
3365 if(auto srcsmax
= device
->configValue
<uint
>(nullptr, "sources").value_or(0))
3366 device
->SourcesMax
= srcsmax
;
3368 if(auto slotsmax
= device
->configValue
<uint
>(nullptr, "slots").value_or(0))
3369 device
->AuxiliaryEffectSlotMax
= minu(slotsmax
, INT_MAX
);
3371 if(auto sendsopt
= device
->configValue
<int>(nullptr, "sends"))
3372 device
->NumAuxSends
= minu(DEFAULT_SENDS
,
3373 static_cast<uint
>(clampi(*sendsopt
, 0, MAX_SENDS
)));
3375 device
->NumStereoSources
= 1;
3376 device
->NumMonoSources
= device
->SourcesMax
- device
->NumStereoSources
;
3378 if(auto ambiopt
= device
->configValue
<std::string
>(nullptr, "ambi-format"))
3380 const ALCchar
*fmt
{ambiopt
->c_str()};
3381 if(al::strcasecmp(fmt
, "fuma") == 0)
3383 if(device
->mAmbiOrder
> 3)
3384 ERR("FuMa is incompatible with %d%s order ambisonics (up to third-order only)\n",
3386 (((device
->mAmbiOrder
%100)/10) == 1) ? "th" :
3387 ((device
->mAmbiOrder
%10) == 1) ? "st" :
3388 ((device
->mAmbiOrder
%10) == 2) ? "nd" :
3389 ((device
->mAmbiOrder
%10) == 3) ? "rd" : "th");
3392 device
->mAmbiLayout
= DevAmbiLayout::FuMa
;
3393 device
->mAmbiScale
= DevAmbiScaling::FuMa
;
3396 else if(al::strcasecmp(fmt
, "acn+fuma") == 0)
3398 if(device
->mAmbiOrder
> 3)
3399 ERR("FuMa is incompatible with %d%s order ambisonics (up to third-order only)\n",
3401 (((device
->mAmbiOrder
%100)/10) == 1) ? "th" :
3402 ((device
->mAmbiOrder
%10) == 1) ? "st" :
3403 ((device
->mAmbiOrder
%10) == 2) ? "nd" :
3404 ((device
->mAmbiOrder
%10) == 3) ? "rd" : "th");
3407 device
->mAmbiLayout
= DevAmbiLayout::ACN
;
3408 device
->mAmbiScale
= DevAmbiScaling::FuMa
;
3411 else if(al::strcasecmp(fmt
, "ambix") == 0 || al::strcasecmp(fmt
, "acn+sn3d") == 0)
3413 device
->mAmbiLayout
= DevAmbiLayout::ACN
;
3414 device
->mAmbiScale
= DevAmbiScaling::SN3D
;
3416 else if(al::strcasecmp(fmt
, "acn+n3d") == 0)
3418 device
->mAmbiLayout
= DevAmbiLayout::ACN
;
3419 device
->mAmbiScale
= DevAmbiScaling::N3D
;
3422 ERR("Unsupported ambi-format: %s\n", fmt
);
3426 std::lock_guard
<std::recursive_mutex
> _
{ListLock
};
3427 auto iter
= std::lower_bound(DeviceList
.cbegin(), DeviceList
.cend(), device
.get());
3428 DeviceList
.emplace(iter
, device
.get());
3431 TRACE("Created device %p, \"%s\"\n", voidp
{device
.get()}, device
->DeviceName
.c_str());
3432 return device
.release();
3436 ALC_API ALCboolean ALC_APIENTRY
alcCloseDevice(ALCdevice
*device
)
3439 std::unique_lock
<std::recursive_mutex
> listlock
{ListLock
};
3440 auto iter
= std::lower_bound(DeviceList
.begin(), DeviceList
.end(), device
);
3441 if(iter
== DeviceList
.end() || *iter
!= device
)
3443 alcSetError(nullptr, ALC_INVALID_DEVICE
);
3446 if((*iter
)->Type
== DeviceType::Capture
)
3448 alcSetError(*iter
, ALC_INVALID_DEVICE
);
3452 /* Erase the device, and any remaining contexts left on it, from their
3455 DeviceRef dev
{*iter
};
3456 DeviceList
.erase(iter
);
3458 std::unique_lock
<std::mutex
> statelock
{dev
->StateLock
};
3459 al::vector
<ContextRef
> orphanctxs
;
3460 for(ContextBase
*ctx
: *dev
->mContexts
.load())
3462 auto ctxiter
= std::lower_bound(ContextList
.begin(), ContextList
.end(), ctx
);
3463 if(ctxiter
!= ContextList
.end() && *ctxiter
== ctx
)
3465 orphanctxs
.emplace_back(ContextRef
{*ctxiter
});
3466 ContextList
.erase(ctxiter
);
3471 for(ContextRef
&context
: orphanctxs
)
3473 WARN("Releasing orphaned context %p\n", voidp
{context
.get()});
3478 if(dev
->Flags
.test(DeviceRunning
))
3479 dev
->Backend
->stop();
3480 dev
->Flags
.reset(DeviceRunning
);
3487 /************************************************
3488 * ALC capture functions
3489 ************************************************/
3490 ALC_API ALCdevice
* ALC_APIENTRY
alcCaptureOpenDevice(const ALCchar
*deviceName
, ALCuint frequency
, ALCenum format
, ALCsizei samples
)
3497 alcSetError(nullptr, ALC_INVALID_VALUE
);
3503 alcSetError(nullptr, ALC_INVALID_VALUE
);
3509 if(!deviceName
[0] || al::strcasecmp(deviceName
, alcDefaultName
) == 0
3510 || al::strcasecmp(deviceName
, "openal-soft") == 0)
3511 deviceName
= nullptr;
3514 DeviceRef device
{new ALCdevice
{DeviceType::Capture
}};
3516 auto decompfmt
= DecomposeDevFormat(format
);
3519 alcSetError(nullptr, ALC_INVALID_ENUM
);
3523 device
->Frequency
= frequency
;
3524 device
->FmtChans
= decompfmt
->chans
;
3525 device
->FmtType
= decompfmt
->type
;
3526 device
->Flags
.set(FrequencyRequest
);
3527 device
->Flags
.set(ChannelsRequest
);
3528 device
->Flags
.set(SampleTypeRequest
);
3530 device
->UpdateSize
= static_cast<uint
>(samples
);
3531 device
->BufferSize
= static_cast<uint
>(samples
);
3534 TRACE("Capture format: %s, %s, %uhz, %u / %u buffer\n",
3535 DevFmtChannelsString(device
->FmtChans
), DevFmtTypeString(device
->FmtType
),
3536 device
->Frequency
, device
->UpdateSize
, device
->BufferSize
);
3538 auto backend
= CaptureFactory
->createBackend(device
.get(), BackendType::Capture
);
3539 std::lock_guard
<std::recursive_mutex
> _
{ListLock
};
3540 backend
->open(deviceName
);
3541 device
->Backend
= std::move(backend
);
3543 catch(al::backend_exception
&e
) {
3544 WARN("Failed to open capture device: %s\n", e
.what());
3545 alcSetError(nullptr, (e
.errorCode() == al::backend_error::OutOfMemory
)
3546 ? ALC_OUT_OF_MEMORY
: ALC_INVALID_VALUE
);
3551 std::lock_guard
<std::recursive_mutex
> _
{ListLock
};
3552 auto iter
= std::lower_bound(DeviceList
.cbegin(), DeviceList
.cend(), device
.get());
3553 DeviceList
.emplace(iter
, device
.get());
3556 TRACE("Created capture device %p, \"%s\"\n", voidp
{device
.get()}, device
->DeviceName
.c_str());
3557 return device
.release();
3561 ALC_API ALCboolean ALC_APIENTRY
alcCaptureCloseDevice(ALCdevice
*device
)
3564 std::unique_lock
<std::recursive_mutex
> listlock
{ListLock
};
3565 auto iter
= std::lower_bound(DeviceList
.begin(), DeviceList
.end(), device
);
3566 if(iter
== DeviceList
.end() || *iter
!= device
)
3568 alcSetError(nullptr, ALC_INVALID_DEVICE
);
3571 if((*iter
)->Type
!= DeviceType::Capture
)
3573 alcSetError(*iter
, ALC_INVALID_DEVICE
);
3577 DeviceRef dev
{*iter
};
3578 DeviceList
.erase(iter
);
3581 std::lock_guard
<std::mutex
> _
{dev
->StateLock
};
3582 if(dev
->Flags
.test(DeviceRunning
))
3583 dev
->Backend
->stop();
3584 dev
->Flags
.reset(DeviceRunning
);
3590 ALC_API
void ALC_APIENTRY
alcCaptureStart(ALCdevice
*device
)
3593 DeviceRef dev
{VerifyDevice(device
)};
3594 if(!dev
|| dev
->Type
!= DeviceType::Capture
)
3596 alcSetError(dev
.get(), ALC_INVALID_DEVICE
);
3600 std::lock_guard
<std::mutex
> _
{dev
->StateLock
};
3601 if(!dev
->Connected
.load(std::memory_order_acquire
))
3602 alcSetError(dev
.get(), ALC_INVALID_DEVICE
);
3603 else if(!dev
->Flags
.test(DeviceRunning
))
3606 auto backend
= dev
->Backend
.get();
3608 dev
->Flags
.set(DeviceRunning
);
3610 catch(al::backend_exception
& e
) {
3611 ERR("%s\n", e
.what());
3612 dev
->handleDisconnect("%s", e
.what());
3613 alcSetError(dev
.get(), ALC_INVALID_DEVICE
);
3619 ALC_API
void ALC_APIENTRY
alcCaptureStop(ALCdevice
*device
)
3622 DeviceRef dev
{VerifyDevice(device
)};
3623 if(!dev
|| dev
->Type
!= DeviceType::Capture
)
3624 alcSetError(dev
.get(), ALC_INVALID_DEVICE
);
3627 std::lock_guard
<std::mutex
> _
{dev
->StateLock
};
3628 if(dev
->Flags
.test(DeviceRunning
))
3629 dev
->Backend
->stop();
3630 dev
->Flags
.reset(DeviceRunning
);
3635 ALC_API
void ALC_APIENTRY
alcCaptureSamples(ALCdevice
*device
, ALCvoid
*buffer
, ALCsizei samples
)
3638 DeviceRef dev
{VerifyDevice(device
)};
3639 if(!dev
|| dev
->Type
!= DeviceType::Capture
)
3641 alcSetError(dev
.get(), ALC_INVALID_DEVICE
);
3645 if(samples
< 0 || (samples
> 0 && buffer
== nullptr))
3647 alcSetError(dev
.get(), ALC_INVALID_VALUE
);
3653 std::lock_guard
<std::mutex
> _
{dev
->StateLock
};
3654 BackendBase
*backend
{dev
->Backend
.get()};
3656 const auto usamples
= static_cast<uint
>(samples
);
3657 if(usamples
> backend
->availableSamples())
3659 alcSetError(dev
.get(), ALC_INVALID_VALUE
);
3663 backend
->captureSamples(static_cast<al::byte
*>(buffer
), usamples
);
3668 /************************************************
3669 * ALC loopback functions
3670 ************************************************/
3672 /** Open a loopback device, for manual rendering. */
3673 ALC_API ALCdevice
* ALC_APIENTRY
alcLoopbackOpenDeviceSOFT(const ALCchar
*deviceName
)
3678 /* Make sure the device name, if specified, is us. */
3679 if(deviceName
&& strcmp(deviceName
, alcDefaultName
) != 0)
3681 alcSetError(nullptr, ALC_INVALID_VALUE
);
3685 DeviceRef device
{new ALCdevice
{DeviceType::Loopback
}};
3687 device
->SourcesMax
= 256;
3688 device
->AuxiliaryEffectSlotMax
= 64;
3689 device
->NumAuxSends
= DEFAULT_SENDS
;
3692 device
->BufferSize
= 0;
3693 device
->UpdateSize
= 0;
3695 device
->Frequency
= DEFAULT_OUTPUT_RATE
;
3696 device
->FmtChans
= DevFmtChannelsDefault
;
3697 device
->FmtType
= DevFmtTypeDefault
;
3699 if(auto srcsmax
= ConfigValueUInt(nullptr, nullptr, "sources").value_or(0))
3700 device
->SourcesMax
= srcsmax
;
3702 if(auto slotsmax
= ConfigValueUInt(nullptr, nullptr, "slots").value_or(0))
3703 device
->AuxiliaryEffectSlotMax
= minu(slotsmax
, INT_MAX
);
3705 if(auto sendsopt
= ConfigValueInt(nullptr, nullptr, "sends"))
3706 device
->NumAuxSends
= minu(DEFAULT_SENDS
,
3707 static_cast<uint
>(clampi(*sendsopt
, 0, MAX_SENDS
)));
3709 device
->NumStereoSources
= 1;
3710 device
->NumMonoSources
= device
->SourcesMax
- device
->NumStereoSources
;
3713 auto backend
= LoopbackBackendFactory::getFactory().createBackend(device
.get(),
3714 BackendType::Playback
);
3715 backend
->open("Loopback");
3716 device
->Backend
= std::move(backend
);
3718 catch(al::backend_exception
&e
) {
3719 WARN("Failed to open loopback device: %s\n", e
.what());
3720 alcSetError(nullptr, (e
.errorCode() == al::backend_error::OutOfMemory
)
3721 ? ALC_OUT_OF_MEMORY
: ALC_INVALID_VALUE
);
3726 std::lock_guard
<std::recursive_mutex
> _
{ListLock
};
3727 auto iter
= std::lower_bound(DeviceList
.cbegin(), DeviceList
.cend(), device
.get());
3728 DeviceList
.emplace(iter
, device
.get());
3731 TRACE("Created loopback device %p\n", voidp
{device
.get()});
3732 return device
.release();
3737 * Determines if the loopback device supports the given format for rendering.
3739 ALC_API ALCboolean ALC_APIENTRY
alcIsRenderFormatSupportedSOFT(ALCdevice
*device
, ALCsizei freq
, ALCenum channels
, ALCenum type
)
3742 DeviceRef dev
{VerifyDevice(device
)};
3743 if(!dev
|| dev
->Type
!= DeviceType::Loopback
)
3744 alcSetError(dev
.get(), ALC_INVALID_DEVICE
);
3746 alcSetError(dev
.get(), ALC_INVALID_VALUE
);
3749 if(DevFmtTypeFromEnum(type
).has_value() && DevFmtChannelsFromEnum(channels
).has_value()
3750 && freq
>= MIN_OUTPUT_RATE
&& freq
<= MAX_OUTPUT_RATE
)
3759 * Renders some samples into a buffer, using the format last set by the
3760 * attributes given to alcCreateContext.
3762 FORCE_ALIGN ALC_API
void ALC_APIENTRY
alcRenderSamplesSOFT(ALCdevice
*device
, ALCvoid
*buffer
, ALCsizei samples
)
3765 if(!device
|| device
->Type
!= DeviceType::Loopback
)
3766 alcSetError(device
, ALC_INVALID_DEVICE
);
3767 else if(samples
< 0 || (samples
> 0 && buffer
== nullptr))
3768 alcSetError(device
, ALC_INVALID_VALUE
);
3770 device
->renderSamples(buffer
, static_cast<uint
>(samples
), device
->channelsFromFmt());
3775 /************************************************
3776 * ALC DSP pause/resume functions
3777 ************************************************/
3779 /** Pause the DSP to stop audio processing. */
3780 ALC_API
void ALC_APIENTRY
alcDevicePauseSOFT(ALCdevice
*device
)
3783 DeviceRef dev
{VerifyDevice(device
)};
3784 if(!dev
|| dev
->Type
!= DeviceType::Playback
)
3785 alcSetError(dev
.get(), ALC_INVALID_DEVICE
);
3788 std::lock_guard
<std::mutex
> _
{dev
->StateLock
};
3789 if(dev
->Flags
.test(DeviceRunning
))
3790 dev
->Backend
->stop();
3791 dev
->Flags
.reset(DeviceRunning
);
3792 dev
->Flags
.set(DevicePaused
);
3797 /** Resume the DSP to restart audio processing. */
3798 ALC_API
void ALC_APIENTRY
alcDeviceResumeSOFT(ALCdevice
*device
)
3801 DeviceRef dev
{VerifyDevice(device
)};
3802 if(!dev
|| dev
->Type
!= DeviceType::Playback
)
3804 alcSetError(dev
.get(), ALC_INVALID_DEVICE
);
3808 std::lock_guard
<std::mutex
> _
{dev
->StateLock
};
3809 if(!dev
->Flags
.test(DevicePaused
))
3811 dev
->Flags
.reset(DevicePaused
);
3812 if(dev
->mContexts
.load()->empty())
3816 auto backend
= dev
->Backend
.get();
3818 dev
->Flags
.set(DeviceRunning
);
3820 catch(al::backend_exception
& e
) {
3821 ERR("%s\n", e
.what());
3822 dev
->handleDisconnect("%s", e
.what());
3823 alcSetError(dev
.get(), ALC_INVALID_DEVICE
);
3826 TRACE("Post-resume: %s, %s, %uhz, %u / %u buffer\n",
3827 DevFmtChannelsString(device
->FmtChans
), DevFmtTypeString(device
->FmtType
),
3828 device
->Frequency
, device
->UpdateSize
, device
->BufferSize
);
3833 /************************************************
3834 * ALC HRTF functions
3835 ************************************************/
3837 /** Gets a string parameter at the given index. */
3838 ALC_API
const ALCchar
* ALC_APIENTRY
alcGetStringiSOFT(ALCdevice
*device
, ALCenum paramName
, ALCsizei index
)
3841 DeviceRef dev
{VerifyDevice(device
)};
3842 if(!dev
|| dev
->Type
== DeviceType::Capture
)
3843 alcSetError(dev
.get(), ALC_INVALID_DEVICE
);
3844 else switch(paramName
)
3846 case ALC_HRTF_SPECIFIER_SOFT
:
3847 if(index
>= 0 && static_cast<uint
>(index
) < dev
->mHrtfList
.size())
3848 return dev
->mHrtfList
[static_cast<uint
>(index
)].c_str();
3849 alcSetError(dev
.get(), ALC_INVALID_VALUE
);
3853 alcSetError(dev
.get(), ALC_INVALID_ENUM
);
3861 /** Resets the given device output, using the specified attribute list. */
3862 ALC_API ALCboolean ALC_APIENTRY
alcResetDeviceSOFT(ALCdevice
*device
, const ALCint
*attribs
)
3865 std::unique_lock
<std::recursive_mutex
> listlock
{ListLock
};
3866 DeviceRef dev
{VerifyDevice(device
)};
3867 if(!dev
|| dev
->Type
== DeviceType::Capture
)
3870 alcSetError(dev
.get(), ALC_INVALID_DEVICE
);
3873 std::lock_guard
<std::mutex
> _
{dev
->StateLock
};
3876 /* Force the backend to stop mixing first since we're resetting. Also reset
3877 * the connected state so lost devices can attempt recover.
3879 if(dev
->Flags
.test(DeviceRunning
))
3880 dev
->Backend
->stop();
3881 dev
->Flags
.reset(DeviceRunning
);
3883 return ResetDeviceParams(dev
.get(), attribs
) ? ALC_TRUE
: ALC_FALSE
;
3888 /************************************************
3889 * ALC device reopen functions
3890 ************************************************/
3892 /** Reopens the given device output, using the specified name and attribute list. */
3893 FORCE_ALIGN ALCboolean ALC_APIENTRY
alcReopenDeviceSOFT(ALCdevice
*device
,
3894 const ALCchar
*deviceName
, const ALCint
*attribs
)
3899 if(!deviceName
[0] || al::strcasecmp(deviceName
, alcDefaultName
) == 0)
3900 deviceName
= nullptr;
3903 std::unique_lock
<std::recursive_mutex
> listlock
{ListLock
};
3904 DeviceRef dev
{VerifyDevice(device
)};
3905 if(!dev
|| dev
->Type
!= DeviceType::Playback
)
3908 alcSetError(dev
.get(), ALC_INVALID_DEVICE
);
3911 std::lock_guard
<std::mutex
> _
{dev
->StateLock
};
3913 /* Force the backend to stop mixing first since we're reopening. */
3914 if(dev
->Flags
.test(DeviceRunning
))
3916 auto backend
= dev
->Backend
.get();
3918 dev
->Flags
.reset(DeviceRunning
);
3921 BackendPtr newbackend
;
3923 newbackend
= PlaybackFactory
->createBackend(dev
.get(), BackendType::Playback
);
3924 newbackend
->open(deviceName
);
3926 catch(al::backend_exception
&e
) {
3928 newbackend
= nullptr;
3930 WARN("Failed to reopen playback device: %s\n", e
.what());
3931 alcSetError(dev
.get(), (e
.errorCode() == al::backend_error::OutOfMemory
)
3932 ? ALC_OUT_OF_MEMORY
: ALC_INVALID_VALUE
);
3934 /* If the device is connected, not paused, and has contexts, ensure it
3935 * continues playing.
3937 if(dev
->Connected
.load(std::memory_order_relaxed
) && !dev
->Flags
.test(DevicePaused
)
3938 && !dev
->mContexts
.load(std::memory_order_relaxed
)->empty())
3941 auto backend
= dev
->Backend
.get();
3943 dev
->Flags
.set(DeviceRunning
);
3945 catch(al::backend_exception
&be
) {
3946 ERR("%s\n", be
.what());
3947 dev
->handleDisconnect("%s", be
.what());
3953 dev
->Backend
= std::move(newbackend
);
3954 TRACE("Reopened device %p, \"%s\"\n", voidp
{dev
.get()}, dev
->DeviceName
.c_str());
3956 /* Always return true even if resetting fails. It shouldn't fail, but this
3957 * is primarily to avoid confusion by the app seeing the function return
3958 * false while the device is on the new output anyway. We could try to
3959 * restore the old backend if this fails, but the configuration would be
3960 * changed with the new backend and would need to be reset again with the
3961 * old one, and the provided attributes may not be appropriate or desirable
3962 * for the old device.
3964 * In this way, we essentially act as if the function succeeded, but
3965 * immediately disconnects following it.
3967 ResetDeviceParams(dev
.get(), attribs
);