From 75f3e34951f165a523825472dc22bfc557277a00 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 24 Apr 2023 11:05:21 -0700 Subject: Try to detect headphones with CoreAudio --- alc/backends/coreaudio.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'alc/backends') diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index 8b0e75fd..86f58637 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -388,6 +388,24 @@ void CoreAudioPlayback::open(const char *name) if(!devname.empty()) mDevice->DeviceName = std::move(devname); else mDevice->DeviceName = "Unknown Device Name"; } + + if(audioDevice != kAudioDeviceUnknown) + { + UInt32 type{}; + err = GetDevProperty(audioDevice, kAudioDevicePropertyTransportType, false, + kAudioObjectPropertyElementMaster, sizeof(type), &type); + if(err != noErr) + ERR("Failed to get audio device type: %u\n", err); + else + { + static constexpr UInt32 HeadphoneType{('h'<<24u) | ('d'<<16u) | ('p'<<8u) | 'n'}; + TRACE("Got device type '%c%c%c%c'\n", static_cast((type>>24)&0xff), + static_cast((type>>16)&0xff), static_cast((type>>8)&0xff), + static_cast(type&0xff)); + mDevice->Flags.set(DirectEar, (type == HeadphoneType)); + } + } + #else mDevice->DeviceName = name; #endif -- cgit v1.2.3 From aefc514ef6d1ab94ec595f5042dcbb3107f77dc9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 25 Apr 2023 00:46:41 -0700 Subject: Check the correct device property to detect headphones --- alc/backends/coreaudio.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index 86f58637..6a8003d2 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -41,6 +41,7 @@ #include #include +#include namespace { @@ -392,17 +393,16 @@ void CoreAudioPlayback::open(const char *name) if(audioDevice != kAudioDeviceUnknown) { UInt32 type{}; - err = GetDevProperty(audioDevice, kAudioDevicePropertyTransportType, false, + err = GetDevProperty(audioDevice, kAudioDevicePropertyDataSource, false, kAudioObjectPropertyElementMaster, sizeof(type), &type); if(err != noErr) ERR("Failed to get audio device type: %u\n", err); else { - static constexpr UInt32 HeadphoneType{('h'<<24u) | ('d'<<16u) | ('p'<<8u) | 'n'}; TRACE("Got device type '%c%c%c%c'\n", static_cast((type>>24)&0xff), static_cast((type>>16)&0xff), static_cast((type>>8)&0xff), static_cast(type&0xff)); - mDevice->Flags.set(DirectEar, (type == HeadphoneType)); + mDevice->Flags.set(DirectEar, (type == kIOAudioOutputPortSubTypeHeadphones)); } } -- cgit v1.2.3 From e3d5c9f69cba4db2b5d4c0512a1132a83d3ce5d4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 26 Apr 2023 17:33:41 -0700 Subject: Print CoreAudio errors as FourCC codes when possible --- alc/backends/coreaudio.cpp | 101 ++++++++++++++++++++++++++------------------- 1 file changed, 58 insertions(+), 43 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index 6a8003d2..d11bcf6f 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -55,6 +55,27 @@ namespace { constexpr auto OutputElement = 0; constexpr auto InputElement = 1; +struct FourCCPrinter { + char mString[sizeof(UInt32) + 1]{}; + + constexpr FourCCPrinter(UInt32 code) noexcept + { + for(size_t i{0};i < sizeof(UInt32);++i) + { + const auto ch = static_cast(code & 0xff); + /* If this breaks early it'll leave the first byte null, to get + * read as a 0-length string. + */ + if(ch <= 0x1f || ch >= 0x7f) + break; + mString[sizeof(UInt32)-1-i] = ch; + code >>= 8; + } + } + + constexpr const char *c_str() const noexcept { return mString; } +}; + #if CAN_ENUMERATE struct DeviceEntry { AudioDeviceID mId; @@ -148,7 +169,8 @@ UInt32 GetDeviceChannelCount(AudioDeviceID devId, bool isCapture) &propSize); if(err) { - ERR("kAudioDevicePropertyStreamConfiguration size query failed: %u\n", err); + ERR("kAudioDevicePropertyStreamConfiguration size query failed: '%s' (%u)\n", + FourCCPrinter{err}.c_str(), err); return 0; } @@ -159,7 +181,8 @@ UInt32 GetDeviceChannelCount(AudioDeviceID devId, bool isCapture) buflist); if(err) { - ERR("kAudioDevicePropertyStreamConfiguration query failed: %u\n", err); + ERR("kAudioDevicePropertyStreamConfiguration query failed: '%s' (%u)\n", + FourCCPrinter{err}.c_str(), err); return 0; } @@ -183,7 +206,7 @@ void EnumerateDevices(std::vector &list, bool isCapture) auto devIds = std::vector(propSize/sizeof(AudioDeviceID), kAudioDeviceUnknown); if(auto err = GetHwProperty(kAudioHardwarePropertyDevices, propSize, devIds.data())) { - ERR("Failed to get device list: %u\n", err); + ERR("Failed to get device list: '%s' (%u)\n", FourCCPrinter{err}.c_str(), err); return; } @@ -261,13 +284,6 @@ struct CoreAudioPlayback final : public BackendBase { OSStatus MixerProc(AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) noexcept; - static OSStatus MixerProcC(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, - const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, - AudioBufferList *ioData) noexcept - { - return static_cast(inRefCon)->MixerProc(ioActionFlags, inTimeStamp, - inBusNumber, inNumberFrames, ioData); - } void open(const char *name) override; bool reset() override; @@ -352,7 +368,7 @@ void CoreAudioPlayback::open(const char *name) OSStatus err{AudioComponentInstanceNew(comp, &audioUnit)}; if(err != noErr) throw al::backend_exception{al::backend_error::NoDevice, - "Could not create component instance: %u", err}; + "Could not create component instance: '%s' (%u)", FourCCPrinter{err}.c_str(), err}; #if CAN_ENUMERATE if(audioDevice != kAudioDeviceUnknown) @@ -363,7 +379,7 @@ void CoreAudioPlayback::open(const char *name) err = AudioUnitInitialize(audioUnit); if(err != noErr) throw al::backend_exception{al::backend_error::DeviceError, - "Could not initialize audio unit: %u", err}; + "Could not initialize audio unit: '%s' (%u)", FourCCPrinter{err}.c_str(), err}; /* WARNING: I don't know if "valid" audio unit values are guaranteed to be * non-0. If not, this logic is broken. @@ -399,9 +415,7 @@ void CoreAudioPlayback::open(const char *name) ERR("Failed to get audio device type: %u\n", err); else { - TRACE("Got device type '%c%c%c%c'\n", static_cast((type>>24)&0xff), - static_cast((type>>16)&0xff), static_cast((type>>8)&0xff), - static_cast(type&0xff)); + TRACE("Got device type '%s'\n", FourCCPrinter{type}.c_str()); mDevice->Flags.set(DirectEar, (type == kIOAudioOutputPortSubTypeHeadphones)); } } @@ -415,7 +429,7 @@ bool CoreAudioPlayback::reset() { OSStatus err{AudioUnitUninitialize(mAudioUnit)}; if(err != noErr) - ERR("-- AudioUnitUninitialize failed.\n"); + ERR("AudioUnitUninitialize failed: '%s' (%u)\n", FourCCPrinter{err}.c_str(), err); /* retrieve default output unit's properties (output side) */ AudioStreamBasicDescription streamFormat{}; @@ -424,7 +438,8 @@ bool CoreAudioPlayback::reset() OutputElement, &streamFormat, &size); if(err != noErr || size != sizeof(streamFormat)) { - ERR("AudioUnitGetProperty failed\n"); + ERR("AudioUnitGetProperty(StreamFormat) failed: '%s' (%u)\n", FourCCPrinter{err}.c_str(), + err); return false; } @@ -491,7 +506,8 @@ bool CoreAudioPlayback::reset() OutputElement, &streamFormat, sizeof(streamFormat)); if(err != noErr) { - ERR("AudioUnitSetProperty failed\n"); + ERR("AudioUnitSetProperty(StreamFormat) failed: '%s' (%u)\n", FourCCPrinter{err}.c_str(), + err); return false; } @@ -500,14 +516,16 @@ bool CoreAudioPlayback::reset() /* setup callback */ mFrameSize = mDevice->frameSizeFromFmt(); AURenderCallbackStruct input{}; - input.inputProc = CoreAudioPlayback::MixerProcC; + input.inputProc = [](void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) noexcept + { return static_cast(inRefCon)->MixerProc(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData); }; input.inputProcRefCon = this; err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, OutputElement, &input, sizeof(AURenderCallbackStruct)); if(err != noErr) { - ERR("AudioUnitSetProperty failed\n"); + ERR("AudioUnitSetProperty(SetRenderCallback) failed: '%s' (%u)\n", + FourCCPrinter{err}.c_str(), err); return false; } @@ -515,7 +533,7 @@ bool CoreAudioPlayback::reset() err = AudioUnitInitialize(mAudioUnit); if(err != noErr) { - ERR("AudioUnitInitialize failed\n"); + ERR("AudioUnitInitialize failed: '%s' (%u)\n", FourCCPrinter{err}.c_str(), err); return false; } @@ -527,14 +545,14 @@ void CoreAudioPlayback::start() const OSStatus err{AudioOutputUnitStart(mAudioUnit)}; if(err != noErr) throw al::backend_exception{al::backend_error::DeviceError, - "AudioOutputUnitStart failed: %d", err}; + "AudioOutputUnitStart failed: '%s' (%u)", FourCCPrinter{err}.c_str(), err}; } void CoreAudioPlayback::stop() { OSStatus err{AudioOutputUnitStop(mAudioUnit)}; if(err != noErr) - ERR("AudioOutputUnitStop failed\n"); + ERR("AudioOutputUnitStop failed: '%s' (%u)\n", FourCCPrinter{err}.c_str(), err); } @@ -545,13 +563,6 @@ struct CoreAudioCapture final : public BackendBase { OSStatus RecordProc(AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) noexcept; - static OSStatus RecordProcC(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, - const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, - AudioBufferList *ioData) noexcept - { - return static_cast(inRefCon)->RecordProc(ioActionFlags, inTimeStamp, - inBusNumber, inNumberFrames, ioData); - } void open(const char *name) override; void start() override; @@ -599,7 +610,7 @@ OSStatus CoreAudioCapture::RecordProc(AudioUnitRenderActionFlags *ioActionFlags, inNumberFrames, &audiobuf.list)}; if(err != noErr) { - ERR("AudioUnitRender capture error: %d\n", err); + ERR("AudioUnitRender capture error: '%s' (%u)\n", FourCCPrinter{err}.c_str(), err); return err; } @@ -658,7 +669,7 @@ void CoreAudioCapture::open(const char *name) OSStatus err{AudioComponentInstanceNew(comp, &mAudioUnit)}; if(err != noErr) throw al::backend_exception{al::backend_error::NoDevice, - "Could not create component instance: %u", err}; + "Could not create component instance: '%s' (%u)", FourCCPrinter{err}.c_str(), err}; // Turn off AudioUnit output UInt32 enableIO{0}; @@ -666,7 +677,8 @@ void CoreAudioCapture::open(const char *name) kAudioUnitScope_Output, OutputElement, &enableIO, sizeof(enableIO)); if(err != noErr) throw al::backend_exception{al::backend_error::DeviceError, - "Could not disable audio unit output property: %u", err}; + "Could not disable audio unit output property: '%s' (%u)", FourCCPrinter{err}.c_str(), + err}; // Turn on AudioUnit input enableIO = 1; @@ -674,7 +686,8 @@ void CoreAudioCapture::open(const char *name) kAudioUnitScope_Input, InputElement, &enableIO, sizeof(enableIO)); if(err != noErr) throw al::backend_exception{al::backend_error::DeviceError, - "Could not enable audio unit input property: %u", err}; + "Could not enable audio unit input property: '%s' (%u)", FourCCPrinter{err}.c_str(), + err}; #if CAN_ENUMERATE if(audioDevice != kAudioDeviceUnknown) @@ -684,14 +697,15 @@ void CoreAudioCapture::open(const char *name) // set capture callback AURenderCallbackStruct input{}; - input.inputProc = CoreAudioCapture::RecordProcC; + input.inputProc = [](void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) noexcept + { return static_cast(inRefCon)->RecordProc(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData); }; input.inputProcRefCon = this; err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, InputElement, &input, sizeof(AURenderCallbackStruct)); if(err != noErr) throw al::backend_exception{al::backend_error::DeviceError, - "Could not set capture callback: %u", err}; + "Could not set capture callback: '%s' (%u)", FourCCPrinter{err}.c_str(), err}; // Disable buffer allocation for capture UInt32 flag{0}; @@ -699,13 +713,14 @@ void CoreAudioCapture::open(const char *name) kAudioUnitScope_Output, InputElement, &flag, sizeof(flag)); if(err != noErr) throw al::backend_exception{al::backend_error::DeviceError, - "Could not disable buffer allocation property: %u", err}; + "Could not disable buffer allocation property: '%s' (%u)", FourCCPrinter{err}.c_str(), + err}; // Initialize the device err = AudioUnitInitialize(mAudioUnit); if(err != noErr) throw al::backend_exception{al::backend_error::DeviceError, - "Could not initialize audio unit: %u", err}; + "Could not initialize audio unit: '%s' (%u)", FourCCPrinter{err}.c_str(), err}; // Get the hardware format AudioStreamBasicDescription hardwareFormat{}; @@ -714,7 +729,7 @@ void CoreAudioCapture::open(const char *name) InputElement, &hardwareFormat, &propertySize); if(err != noErr || propertySize != sizeof(hardwareFormat)) throw al::backend_exception{al::backend_error::DeviceError, - "Could not get input format: %u", err}; + "Could not get input format: '%s' (%u)", FourCCPrinter{err}.c_str(), err}; // Set up the requested format description AudioStreamBasicDescription requestedFormat{}; @@ -795,7 +810,7 @@ void CoreAudioCapture::open(const char *name) InputElement, &outputFormat, sizeof(outputFormat)); if(err != noErr) throw al::backend_exception{al::backend_error::DeviceError, - "Could not set input format: %u", err}; + "Could not set input format: '%s' (%u)", FourCCPrinter{err}.c_str(), err}; /* Calculate the minimum AudioUnit output format frame count for the pre- * conversion ring buffer. Ensure at least 100ms for the total buffer. @@ -814,7 +829,7 @@ void CoreAudioCapture::open(const char *name) kAudioUnitScope_Global, OutputElement, &outputFrameCount, &propertySize); if(err != noErr || propertySize != sizeof(outputFrameCount)) throw al::backend_exception{al::backend_error::DeviceError, - "Could not get input frame count: %u", err}; + "Could not get input frame count: '%s' (%u)", FourCCPrinter{err}.c_str(), err}; mCaptureData.resize(outputFrameCount * mFrameSize); @@ -852,14 +867,14 @@ void CoreAudioCapture::start() OSStatus err{AudioOutputUnitStart(mAudioUnit)}; if(err != noErr) throw al::backend_exception{al::backend_error::DeviceError, - "AudioOutputUnitStart failed: %d", err}; + "AudioOutputUnitStart failed: '%s' (%u)", FourCCPrinter{err}.c_str(), err}; } void CoreAudioCapture::stop() { OSStatus err{AudioOutputUnitStop(mAudioUnit)}; if(err != noErr) - ERR("AudioOutputUnitStop failed\n"); + ERR("AudioOutputUnitStop failed: '%s' (%u)\n", FourCCPrinter{err}.c_str(), err); } void CoreAudioCapture::captureSamples(al::byte *buffer, uint samples) -- cgit v1.2.3 From ac143e1236319ea087388ff48a178930c0dbaf47 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 26 Apr 2023 17:40:18 -0700 Subject: Handle signed int values holding FourCC codes --- alc/backends/coreaudio.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'alc/backends') diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index d11bcf6f..ae220d7a 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -72,6 +72,7 @@ struct FourCCPrinter { code >>= 8; } } + constexpr FourCCPrinter(int code) noexcept : FourCCPrinter{static_cast(code)} { } constexpr const char *c_str() const noexcept { return mString; } }; -- cgit v1.2.3 From 7cda37a67c8f147536c53f0073df9a9e61d40587 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 4 May 2023 08:03:40 -0700 Subject: Replace al::optional with std::optional --- CMakeLists.txt | 1 - al/buffer.cpp | 20 ++++++++++---------- al/debug.cpp | 14 +++++++------- al/eax/fx_slot_index.h | 7 +++---- al/effects/chorus.cpp | 6 +++--- al/effects/fshifter.cpp | 6 +++--- al/effects/modulator.cpp | 6 +++--- al/effects/vmorpher.cpp | 10 +++++----- al/source.cpp | 30 +++++++++++++++--------------- al/state.cpp | 6 +++--- alc/alc.cpp | 44 ++++++++++++++++++++++---------------------- alc/alconfig.cpp | 22 +++++++++++----------- alc/alconfig.h | 12 ++++++------ alc/alu.cpp | 1 + alc/alu.h | 5 ++--- alc/backends/alsa.cpp | 1 - alc/backends/base.cpp | 1 - alc/backends/oss.cpp | 1 - alc/backends/pipewire.cpp | 8 ++++---- alc/backends/pulseaudio.cpp | 6 +++--- alc/device.h | 13 +++++++------ alc/panning.cpp | 4 ++-- common/aloptional.h | 17 ----------------- common/strutils.cpp | 8 ++++---- common/strutils.h | 7 +++---- core/ambdec.cpp | 8 ++++---- core/ambdec.h | 4 ++-- core/cpu_caps.cpp | 4 ++-- core/cpu_caps.h | 5 ++--- core/helpers.cpp | 8 ++++---- core/hrtf.cpp | 4 ++-- core/hrtf.h | 4 ++-- core/voice.cpp | 4 ++-- core/voice.h | 4 ++-- utils/makemhr/loaddef.cpp | 5 ++--- utils/makemhr/loadsofa.cpp | 4 ++-- 36 files changed, 143 insertions(+), 167 deletions(-) delete mode 100644 common/aloptional.h (limited to 'alc/backends') diff --git a/CMakeLists.txt b/CMakeLists.txt index 764b4590..07377ddb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -599,7 +599,6 @@ set(COMMON_OBJS common/almalloc.h common/alnumbers.h common/alnumeric.h - common/aloptional.h common/alspan.h common/alstring.cpp common/alstring.h diff --git a/al/buffer.cpp b/al/buffer.cpp index b89ad5af..4f0bcf8c 100644 --- a/al/buffer.cpp +++ b/al/buffer.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -49,7 +50,6 @@ #include "alc/inprogext.h" #include "almalloc.h" #include "alnumeric.h" -#include "aloptional.h" #include "atomic.h" #include "core/except.h" #include "core/logging.h" @@ -64,14 +64,14 @@ namespace { -al::optional AmbiLayoutFromEnum(ALenum layout) +std::optional AmbiLayoutFromEnum(ALenum layout) { switch(layout) { case AL_FUMA_SOFT: return AmbiLayout::FuMa; case AL_ACN_SOFT: return AmbiLayout::ACN; } - return al::nullopt; + return std::nullopt; } ALenum EnumFromAmbiLayout(AmbiLayout layout) { @@ -83,7 +83,7 @@ ALenum EnumFromAmbiLayout(AmbiLayout layout) throw std::runtime_error{"Invalid AmbiLayout: "+std::to_string(int(layout))}; } -al::optional AmbiScalingFromEnum(ALenum scale) +std::optional AmbiScalingFromEnum(ALenum scale) { switch(scale) { @@ -91,7 +91,7 @@ al::optional AmbiScalingFromEnum(ALenum scale) case AL_SN3D_SOFT: return AmbiScaling::SN3D; case AL_N3D_SOFT: return AmbiScaling::N3D; } - return al::nullopt; + return std::nullopt; } ALenum EnumFromAmbiScaling(AmbiScaling scale) { @@ -106,7 +106,7 @@ ALenum EnumFromAmbiScaling(AmbiScaling scale) } #ifdef ALSOFT_EAX -al::optional EaxStorageFromEnum(ALenum scale) +std::optional EaxStorageFromEnum(ALenum scale) { switch(scale) { @@ -114,7 +114,7 @@ al::optional EaxStorageFromEnum(ALenum scale) case AL_STORAGE_ACCESSIBLE: return EaxStorage::Accessible; case AL_STORAGE_HARDWARE: return EaxStorage::Hardware; } - return al::nullopt; + return std::nullopt; } ALenum EnumFromEaxStorage(EaxStorage storage) { @@ -536,7 +536,7 @@ void PrepareUserPtr(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, struct DecompResult { FmtChannels channels; FmtType type; }; -al::optional DecomposeUserFormat(ALenum format) +std::optional DecomposeUserFormat(ALenum format) { struct FormatMap { ALenum format; @@ -624,9 +624,9 @@ al::optional DecomposeUserFormat(ALenum format) for(const auto &fmt : UserFmtList) { if(fmt.format == format) - return al::make_optional({fmt.channels, fmt.type}); + return DecompResult{fmt.channels, fmt.type}; } - return al::nullopt; + return std::nullopt; } } // namespace diff --git a/al/debug.cpp b/al/debug.cpp index 786fcd1f..3df85d62 100644 --- a/al/debug.cpp +++ b/al/debug.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -15,7 +16,6 @@ #include "alc/context.h" #include "alc/inprogext.h" -#include "aloptional.h" #include "alspan.h" #include "core/logging.h" #include "opthelpers.h" @@ -35,7 +35,7 @@ constexpr auto make_array() { return make_array(std::make_integer_sequence{}); } -constexpr al::optional GetDebugSource(ALenum source) noexcept +constexpr std::optional GetDebugSource(ALenum source) noexcept { switch(source) { @@ -45,10 +45,10 @@ constexpr al::optional GetDebugSource(ALenum source) noexcept case AL_DEBUG_SOURCE_APPLICATION_EXT: return DebugSource::Application; case AL_DEBUG_SOURCE_OTHER_EXT: return DebugSource::Other; } - return al::nullopt; + return std::nullopt; } -constexpr al::optional GetDebugType(ALenum type) noexcept +constexpr std::optional GetDebugType(ALenum type) noexcept { switch(type) { @@ -62,10 +62,10 @@ constexpr al::optional GetDebugType(ALenum type) noexcept case AL_DEBUG_TYPE_POP_GROUP_EXT: return DebugType::PopGroup; case AL_DEBUG_TYPE_OTHER_EXT: return DebugType::Other; } - return al::nullopt; + return std::nullopt; } -constexpr al::optional GetDebugSeverity(ALenum severity) noexcept +constexpr std::optional GetDebugSeverity(ALenum severity) noexcept { switch(severity) { @@ -74,7 +74,7 @@ constexpr al::optional GetDebugSeverity(ALenum severity) noexcept case AL_DEBUG_SEVERITY_LOW_EXT: return DebugSeverity::Low; case AL_DEBUG_SEVERITY_NOTIFICATION_EXT: return DebugSeverity::Notification; } - return al::nullopt; + return std::nullopt; } diff --git a/al/eax/fx_slot_index.h b/al/eax/fx_slot_index.h index 63dba037..9f350d9b 100644 --- a/al/eax/fx_slot_index.h +++ b/al/eax/fx_slot_index.h @@ -3,17 +3,16 @@ #include +#include -#include "aloptional.h" #include "api.h" using EaxFxSlotIndexValue = std::size_t; -class EaxFxSlotIndex : public al::optional -{ +class EaxFxSlotIndex : public std::optional { public: - using al::optional::optional; + using std::optional::optional; EaxFxSlotIndex& operator=(const EaxFxSlotIndexValue &value) { set(value); return *this; } EaxFxSlotIndex& operator=(const GUID &guid) { set(guid); return *this; } diff --git a/al/effects/chorus.cpp b/al/effects/chorus.cpp index 305259a4..2e0c23dd 100644 --- a/al/effects/chorus.cpp +++ b/al/effects/chorus.cpp @@ -1,13 +1,13 @@ #include "config.h" +#include #include #include "AL/al.h" #include "AL/efx.h" #include "alc/effects/base.h" -#include "aloptional.h" #include "core/logging.h" #include "effects.h" @@ -27,14 +27,14 @@ static_assert(FlangerMaxDelay >= AL_FLANGER_MAX_DELAY, "Flanger max delay too sm static_assert(AL_CHORUS_WAVEFORM_SINUSOID == AL_FLANGER_WAVEFORM_SINUSOID, "Chorus/Flanger waveform value mismatch"); static_assert(AL_CHORUS_WAVEFORM_TRIANGLE == AL_FLANGER_WAVEFORM_TRIANGLE, "Chorus/Flanger waveform value mismatch"); -inline al::optional WaveformFromEnum(ALenum type) +inline std::optional WaveformFromEnum(ALenum type) { switch(type) { case AL_CHORUS_WAVEFORM_SINUSOID: return ChorusWaveform::Sinusoid; case AL_CHORUS_WAVEFORM_TRIANGLE: return ChorusWaveform::Triangle; } - return al::nullopt; + return std::nullopt; } inline ALenum EnumFromWaveform(ChorusWaveform type) { diff --git a/al/effects/fshifter.cpp b/al/effects/fshifter.cpp index 949db203..54e71408 100644 --- a/al/effects/fshifter.cpp +++ b/al/effects/fshifter.cpp @@ -1,13 +1,13 @@ #include "config.h" +#include #include #include "AL/al.h" #include "AL/efx.h" #include "alc/effects/base.h" -#include "aloptional.h" #include "effects.h" #ifdef ALSOFT_EAX @@ -20,7 +20,7 @@ namespace { -al::optional DirectionFromEmum(ALenum value) +std::optional DirectionFromEmum(ALenum value) { switch(value) { @@ -28,7 +28,7 @@ al::optional DirectionFromEmum(ALenum value) case AL_FREQUENCY_SHIFTER_DIRECTION_UP: return FShifterDirection::Up; case AL_FREQUENCY_SHIFTER_DIRECTION_OFF: return FShifterDirection::Off; } - return al::nullopt; + return std::nullopt; } ALenum EnumFromDirection(FShifterDirection dir) { diff --git a/al/effects/modulator.cpp b/al/effects/modulator.cpp index 5f37d08f..228fe084 100644 --- a/al/effects/modulator.cpp +++ b/al/effects/modulator.cpp @@ -1,13 +1,13 @@ #include "config.h" +#include #include #include "AL/al.h" #include "AL/efx.h" #include "alc/effects/base.h" -#include "aloptional.h" #include "effects.h" #ifdef ALSOFT_EAX @@ -20,7 +20,7 @@ namespace { -al::optional WaveformFromEmum(ALenum value) +std::optional WaveformFromEmum(ALenum value) { switch(value) { @@ -28,7 +28,7 @@ al::optional WaveformFromEmum(ALenum value) case AL_RING_MODULATOR_SAWTOOTH: return ModulatorWaveform::Sawtooth; case AL_RING_MODULATOR_SQUARE: return ModulatorWaveform::Square; } - return al::nullopt; + return std::nullopt; } ALenum EnumFromWaveform(ModulatorWaveform type) { diff --git a/al/effects/vmorpher.cpp b/al/effects/vmorpher.cpp index 21ea3680..6268ea7f 100644 --- a/al/effects/vmorpher.cpp +++ b/al/effects/vmorpher.cpp @@ -1,13 +1,13 @@ #include "config.h" +#include #include #include "AL/al.h" #include "AL/efx.h" #include "alc/effects/base.h" -#include "aloptional.h" #include "effects.h" #ifdef ALSOFT_EAX @@ -20,7 +20,7 @@ namespace { -al::optional PhenomeFromEnum(ALenum val) +std::optional PhenomeFromEnum(ALenum val) { #define HANDLE_PHENOME(x) case AL_VOCAL_MORPHER_PHONEME_ ## x: \ return VMorpherPhenome::x @@ -57,7 +57,7 @@ al::optional PhenomeFromEnum(ALenum val) HANDLE_PHENOME(V); HANDLE_PHENOME(Z); } - return al::nullopt; + return std::nullopt; #undef HANDLE_PHENOME } ALenum EnumFromPhenome(VMorpherPhenome phenome) @@ -100,7 +100,7 @@ ALenum EnumFromPhenome(VMorpherPhenome phenome) #undef HANDLE_PHENOME } -al::optional WaveformFromEmum(ALenum value) +std::optional WaveformFromEmum(ALenum value) { switch(value) { @@ -108,7 +108,7 @@ al::optional WaveformFromEmum(ALenum value) case AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE: return VMorpherWaveform::Triangle; case AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH: return VMorpherWaveform::Sawtooth; } - return al::nullopt; + return std::nullopt; } ALenum EnumFromWaveform(VMorpherWaveform type) { diff --git a/al/source.cpp b/al/source.cpp index f51c3bca..2b0540b4 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -55,7 +56,6 @@ #include "alc/inprogext.h" #include "almalloc.h" #include "alnumeric.h" -#include "aloptional.h" #include "alspan.h" #include "atomic.h" #include "auxeffectslot.h" @@ -395,8 +395,8 @@ struct VoicePos { * using the givem offset type and offset. If the offset is out of range, * returns an empty optional. */ -al::optional GetSampleOffset(al::deque &BufferList, ALenum OffsetType, - double Offset) +std::optional GetSampleOffset(al::deque &BufferList, + ALenum OffsetType, double Offset) { /* Find the first valid Buffer in the Queue */ const ALbuffer *BufferFmt{nullptr}; @@ -406,7 +406,7 @@ al::optional GetSampleOffset(al::deque &BufferList, if(BufferFmt) break; } if(!BufferFmt) UNLIKELY - return al::nullopt; + return std::nullopt; /* Get sample frame offset */ int64_t offset{}; @@ -452,12 +452,12 @@ al::optional GetSampleOffset(al::deque &BufferList, if(offset < 0) { if(offset < std::numeric_limits::min()) - return al::nullopt; + return std::nullopt; return VoicePos{static_cast(offset), frac, &BufferList.front()}; } if(BufferFmt->mCallback) - return al::nullopt; + return std::nullopt; int64_t totalBufferLen{0}; for(auto &item : BufferList) @@ -473,7 +473,7 @@ al::optional GetSampleOffset(al::deque &BufferList, } /* Offset is out of range of the queue */ - return al::nullopt; + return std::nullopt; } @@ -798,7 +798,7 @@ inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) noexcept } -al::optional StereoModeFromEnum(ALenum mode) +std::optional StereoModeFromEnum(ALenum mode) { switch(mode) { @@ -806,7 +806,7 @@ al::optional StereoModeFromEnum(ALenum mode) case AL_SUPER_STEREO_SOFT: return SourceStereo::Enhanced; } WARN("Unsupported stereo mode: 0x%04x\n", mode); - return al::nullopt; + return std::nullopt; } ALenum EnumFromStereoMode(SourceStereo mode) { @@ -818,7 +818,7 @@ ALenum EnumFromStereoMode(SourceStereo mode) throw std::runtime_error{"Invalid SourceStereo: "+std::to_string(int(mode))}; } -al::optional SpatializeModeFromEnum(ALenum mode) +std::optional SpatializeModeFromEnum(ALenum mode) { switch(mode) { @@ -827,7 +827,7 @@ al::optional SpatializeModeFromEnum(ALenum mode) case AL_AUTO_SOFT: return SpatializeMode::Auto; } WARN("Unsupported spatialize mode: 0x%04x\n", mode); - return al::nullopt; + return std::nullopt; } ALenum EnumFromSpatializeMode(SpatializeMode mode) { @@ -840,7 +840,7 @@ ALenum EnumFromSpatializeMode(SpatializeMode mode) throw std::runtime_error{"Invalid SpatializeMode: "+std::to_string(int(mode))}; } -al::optional DirectModeFromEnum(ALenum mode) +std::optional DirectModeFromEnum(ALenum mode) { switch(mode) { @@ -849,7 +849,7 @@ al::optional DirectModeFromEnum(ALenum mode) case AL_REMIX_UNMATCHED_SOFT: return DirectMode::RemixMismatch; } WARN("Unsupported direct mode: 0x%04x\n", mode); - return al::nullopt; + return std::nullopt; } ALenum EnumFromDirectMode(DirectMode mode) { @@ -862,7 +862,7 @@ ALenum EnumFromDirectMode(DirectMode mode) throw std::runtime_error{"Invalid DirectMode: "+std::to_string(int(mode))}; } -al::optional DistanceModelFromALenum(ALenum model) +std::optional DistanceModelFromALenum(ALenum model) { switch(model) { @@ -874,7 +874,7 @@ al::optional DistanceModelFromALenum(ALenum model) case AL_EXPONENT_DISTANCE: return DistanceModel::Exponent; case AL_EXPONENT_DISTANCE_CLAMPED: return DistanceModel::ExponentClamped; } - return al::nullopt; + return std::nullopt; } ALenum ALenumFromDistanceModel(DistanceModel model) { diff --git a/al/state.cpp b/al/state.cpp index efc6398d..77b104a4 100644 --- a/al/state.cpp +++ b/al/state.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -38,7 +39,6 @@ #include "alc/context.h" #include "alc/inprogext.h" #include "alnumeric.h" -#include "aloptional.h" #include "atomic.h" #include "core/context.h" #include "core/except.h" @@ -107,7 +107,7 @@ const ALchar *GetResamplerName(const Resampler rtype) throw std::runtime_error{"Unexpected resampler index"}; } -al::optional DistanceModelFromALenum(ALenum model) +std::optional DistanceModelFromALenum(ALenum model) { switch(model) { @@ -119,7 +119,7 @@ al::optional DistanceModelFromALenum(ALenum model) case AL_EXPONENT_DISTANCE: return DistanceModel::Exponent; case AL_EXPONENT_DISTANCE_CLAMPED: return DistanceModel::ExponentClamped; } - return al::nullopt; + return std::nullopt; } ALenum ALenumFromDistanceModel(DistanceModel model) { diff --git a/alc/alc.cpp b/alc/alc.cpp index 8932a084..2da5c5db 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -71,7 +72,6 @@ #include "alconfig.h" #include "almalloc.h" #include "alnumeric.h" -#include "aloptional.h" #include "alspan.h" #include "alstring.h" #include "alu.h" @@ -1443,7 +1443,7 @@ void ProbeCaptureDeviceList() struct DevFmtPair { DevFmtChannels chans; DevFmtType type; }; -al::optional DecomposeDevFormat(ALenum format) +std::optional DecomposeDevFormat(ALenum format) { static const struct { ALenum format; @@ -1478,13 +1478,13 @@ al::optional DecomposeDevFormat(ALenum format) for(const auto &item : list) { if(item.format == format) - return al::make_optional({item.channels, item.type}); + return DevFmtPair{item.channels, item.type}; } - return al::nullopt; + return std::nullopt; } -al::optional DevFmtTypeFromEnum(ALCenum type) +std::optional DevFmtTypeFromEnum(ALCenum type) { switch(type) { @@ -1497,7 +1497,7 @@ al::optional DevFmtTypeFromEnum(ALCenum type) case ALC_FLOAT_SOFT: return DevFmtFloat; } WARN("Unsupported format type: 0x%04x\n", type); - return al::nullopt; + return std::nullopt; } ALCenum EnumFromDevFmt(DevFmtType type) { @@ -1514,7 +1514,7 @@ ALCenum EnumFromDevFmt(DevFmtType type) throw std::runtime_error{"Invalid DevFmtType: "+std::to_string(int(type))}; } -al::optional DevFmtChannelsFromEnum(ALCenum channels) +std::optional DevFmtChannelsFromEnum(ALCenum channels) { switch(channels) { @@ -1527,7 +1527,7 @@ al::optional DevFmtChannelsFromEnum(ALCenum channels) case ALC_BFORMAT3D_SOFT: return DevFmtAmbi3D; } WARN("Unsupported format channels: 0x%04x\n", channels); - return al::nullopt; + return std::nullopt; } ALCenum EnumFromDevFmt(DevFmtChannels channels) { @@ -1547,7 +1547,7 @@ ALCenum EnumFromDevFmt(DevFmtChannels channels) throw std::runtime_error{"Invalid DevFmtChannels: "+std::to_string(int(channels))}; } -al::optional DevAmbiLayoutFromEnum(ALCenum layout) +std::optional DevAmbiLayoutFromEnum(ALCenum layout) { switch(layout) { @@ -1555,7 +1555,7 @@ al::optional DevAmbiLayoutFromEnum(ALCenum layout) case ALC_ACN_SOFT: return DevAmbiLayout::ACN; } WARN("Unsupported ambisonic layout: 0x%04x\n", layout); - return al::nullopt; + return std::nullopt; } ALCenum EnumFromDevAmbi(DevAmbiLayout layout) { @@ -1567,7 +1567,7 @@ ALCenum EnumFromDevAmbi(DevAmbiLayout layout) throw std::runtime_error{"Invalid DevAmbiLayout: "+std::to_string(int(layout))}; } -al::optional DevAmbiScalingFromEnum(ALCenum scaling) +std::optional DevAmbiScalingFromEnum(ALCenum scaling) { switch(scaling) { @@ -1576,7 +1576,7 @@ al::optional DevAmbiScalingFromEnum(ALCenum scaling) case ALC_N3D_SOFT: return DevAmbiScaling::N3D; } WARN("Unsupported ambisonic scaling: 0x%04x\n", scaling); - return al::nullopt; + return std::nullopt; } ALCenum EnumFromDevAmbi(DevAmbiScaling scaling) { @@ -1731,13 +1731,13 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList) uint numMono{device->NumMonoSources}; uint numStereo{device->NumStereoSources}; uint numSends{device->NumAuxSends}; - al::optional stereomode; - al::optional optlimit; - al::optional optsrate; - al::optional optchans; - al::optional opttype; - al::optional optlayout; - al::optional optscale; + std::optional stereomode; + std::optional optlimit; + std::optional optsrate; + std::optional optchans; + std::optional opttype; + std::optional optlayout; + std::optional optscale; uint period_size{DEFAULT_UPDATE_SIZE}; uint buffer_size{DEFAULT_UPDATE_SIZE * DEFAULT_NUM_UPDATES}; int hrtf_id{-1}; @@ -1880,7 +1880,7 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList) if(attrList && attrList[0]) { ALenum outmode{ALC_ANY_SOFT}; - al::optional opthrtf; + std::optional opthrtf; int freqAttr{}; #define ATTRIBUTE(a) a: TRACE("%s = %d\n", #a, attrList[attrIdx + 1]); @@ -1940,7 +1940,7 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList) else if(attrList[attrIdx + 1] == ALC_TRUE) opthrtf = true; else if(attrList[attrIdx + 1] == ALC_DONT_CARE_SOFT) - opthrtf = al::nullopt; + opthrtf = std::nullopt; break; case ATTRIBUTE(ALC_HRTF_ID_SOFT) @@ -1953,7 +1953,7 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList) else if(attrList[attrIdx + 1] == ALC_TRUE) optlimit = true; else if(attrList[attrIdx + 1] == ALC_DONT_CARE_SOFT) - optlimit = al::nullopt; + optlimit = std::nullopt; break; case ATTRIBUTE(ALC_OUTPUT_MODE_SOFT) diff --git a/alc/alconfig.cpp b/alc/alconfig.cpp index b0544b89..56cad9e0 100644 --- a/alc/alconfig.cpp +++ b/alc/alconfig.cpp @@ -52,7 +52,7 @@ struct ConfigEntry { std::string key; std::string value; }; -al::vector ConfOpts; +std::vector ConfOpts; std::string &lstrip(std::string &line) @@ -483,40 +483,40 @@ void ReadALConfig() } #endif -al::optional ConfigValueStr(const char *devName, const char *blockName, const char *keyName) +std::optional ConfigValueStr(const char *devName, const char *blockName, const char *keyName) { if(const char *val{GetConfigValue(devName, blockName, keyName)}) return val; - return al::nullopt; + return std::nullopt; } -al::optional ConfigValueInt(const char *devName, const char *blockName, const char *keyName) +std::optional ConfigValueInt(const char *devName, const char *blockName, const char *keyName) { if(const char *val{GetConfigValue(devName, blockName, keyName)}) return static_cast(std::strtol(val, nullptr, 0)); - return al::nullopt; + return std::nullopt; } -al::optional ConfigValueUInt(const char *devName, const char *blockName, const char *keyName) +std::optional ConfigValueUInt(const char *devName, const char *blockName, const char *keyName) { if(const char *val{GetConfigValue(devName, blockName, keyName)}) return static_cast(std::strtoul(val, nullptr, 0)); - return al::nullopt; + return std::nullopt; } -al::optional ConfigValueFloat(const char *devName, const char *blockName, const char *keyName) +std::optional ConfigValueFloat(const char *devName, const char *blockName, const char *keyName) { if(const char *val{GetConfigValue(devName, blockName, keyName)}) return std::strtof(val, nullptr); - return al::nullopt; + return std::nullopt; } -al::optional ConfigValueBool(const char *devName, const char *blockName, const char *keyName) +std::optional ConfigValueBool(const char *devName, const char *blockName, const char *keyName) { if(const char *val{GetConfigValue(devName, blockName, keyName)}) return al::strcasecmp(val, "on") == 0 || al::strcasecmp(val, "yes") == 0 || al::strcasecmp(val, "true")==0 || atoi(val) != 0; - return al::nullopt; + return std::nullopt; } bool GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, bool def) diff --git a/alc/alconfig.h b/alc/alconfig.h index df2830cc..1eb44405 100644 --- a/alc/alconfig.h +++ b/alc/alconfig.h @@ -1,18 +1,18 @@ #ifndef ALCONFIG_H #define ALCONFIG_H +#include #include -#include "aloptional.h" void ReadALConfig(); bool GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, bool def); -al::optional ConfigValueStr(const char *devName, const char *blockName, const char *keyName); -al::optional ConfigValueInt(const char *devName, const char *blockName, const char *keyName); -al::optional ConfigValueUInt(const char *devName, const char *blockName, const char *keyName); -al::optional ConfigValueFloat(const char *devName, const char *blockName, const char *keyName); -al::optional ConfigValueBool(const char *devName, const char *blockName, const char *keyName); +std::optional ConfigValueStr(const char *devName, const char *blockName, const char *keyName); +std::optional ConfigValueInt(const char *devName, const char *blockName, const char *keyName); +std::optional ConfigValueUInt(const char *devName, const char *blockName, const char *keyName); +std::optional ConfigValueFloat(const char *devName, const char *blockName, const char *keyName); +std::optional ConfigValueBool(const char *devName, const char *blockName, const char *keyName); #endif /* ALCONFIG_H */ diff --git a/alc/alu.cpp b/alc/alu.cpp index e9ad68b1..fc22febb 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include diff --git a/alc/alu.h b/alc/alu.h index 67fd09e5..253940cf 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -2,8 +2,7 @@ #define ALU_H #include - -#include "aloptional.h" +#include struct ALCcontext; struct ALCdevice; @@ -31,7 +30,7 @@ void aluInit(CompatFlagBitset flags, const float nfcscale); * Set up the appropriate panning method and mixing method given the device * properties. */ -void aluInitRenderer(ALCdevice *device, int hrtf_id, al::optional stereomode); +void aluInitRenderer(ALCdevice *device, int hrtf_id, std::optional stereomode); void aluInitEffectPanning(EffectSlot *slot, ALCcontext *context); diff --git a/alc/backends/alsa.cpp b/alc/backends/alsa.cpp index d620a83c..01021868 100644 --- a/alc/backends/alsa.cpp +++ b/alc/backends/alsa.cpp @@ -39,7 +39,6 @@ #include "alc/alconfig.h" #include "almalloc.h" #include "alnumeric.h" -#include "aloptional.h" #include "core/device.h" #include "core/helpers.h" #include "core/logging.h" diff --git a/alc/backends/base.cpp b/alc/backends/base.cpp index e5ad8494..45254c47 100644 --- a/alc/backends/base.cpp +++ b/alc/backends/base.cpp @@ -14,7 +14,6 @@ #include "albit.h" #include "core/logging.h" -#include "aloptional.h" #endif #include "atomic.h" diff --git a/alc/backends/oss.cpp b/alc/backends/oss.cpp index 6d4fa261..f76024f4 100644 --- a/alc/backends/oss.cpp +++ b/alc/backends/oss.cpp @@ -45,7 +45,6 @@ #include "alc/alconfig.h" #include "almalloc.h" #include "alnumeric.h" -#include "aloptional.h" #include "core/device.h" #include "core/helpers.h" #include "core/logging.h" diff --git a/alc/backends/pipewire.cpp b/alc/backends/pipewire.cpp index c6569a74..d3c8e77e 100644 --- a/alc/backends/pipewire.cpp +++ b/alc/backends/pipewire.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -40,7 +41,6 @@ #include "alc/alconfig.h" #include "almalloc.h" #include "alnumeric.h" -#include "aloptional.h" #include "alspan.h" #include "alstring.h" #include "core/devformat.h" @@ -304,12 +304,12 @@ al::span> get_array_span(const spa_pod *pod) } template -al::optional> get_value(const spa_pod *value) +std::optional> get_value(const spa_pod *value) { Pod_t val{}; if(PodInfo::get_value(value, &val) == 0) return val; - return al::nullopt; + return std::nullopt; } /* Internally, PipeWire types "inherit" from each other, but this is hidden @@ -997,7 +997,7 @@ int MetadataProxy::propertyCallback(uint32_t id, const char *key, const char *ty auto get_json_string = [](spa_json *iter) { - al::optional str; + std::optional str; const char *val{}; int len{spa_json_next(iter, &val)}; diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index 4b0e316f..6f706c7f 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -41,7 +42,6 @@ #include "alc/alconfig.h" #include "almalloc.h" #include "alnumeric.h" -#include "aloptional.h" #include "alspan.h" #include "core/devformat.h" #include "core/device.h" @@ -615,7 +615,7 @@ struct PulsePlayback final : public BackendBase { PulseMainloop mMainloop; - al::optional mDeviceName{al::nullopt}; + std::optional mDeviceName{std::nullopt}; bool mIs51Rear{false}; pa_buffer_attr mAttr; @@ -1042,7 +1042,7 @@ struct PulseCapture final : public BackendBase { PulseMainloop mMainloop; - al::optional mDeviceName{al::nullopt}; + std::optional mDeviceName{std::nullopt}; al::span mCapBuffer; size_t mHoleLength{0}; diff --git a/alc/device.h b/alc/device.h index ef50f53e..d5e82ce3 100644 --- a/alc/device.h +++ b/alc/device.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -141,25 +142,25 @@ struct ALCdevice : public al::intrusive_ref, DeviceBase { { return GetConfigValueBool(DeviceName.c_str(), block, key, def); } template - inline al::optional configValue(const char *block, const char *key) = delete; + inline std::optional configValue(const char *block, const char *key) = delete; DEF_NEWDEL(ALCdevice) }; template<> -inline al::optional ALCdevice::configValue(const char *block, const char *key) +inline std::optional ALCdevice::configValue(const char *block, const char *key) { return ConfigValueStr(DeviceName.c_str(), block, key); } template<> -inline al::optional ALCdevice::configValue(const char *block, const char *key) +inline std::optional ALCdevice::configValue(const char *block, const char *key) { return ConfigValueInt(DeviceName.c_str(), block, key); } template<> -inline al::optional ALCdevice::configValue(const char *block, const char *key) +inline std::optional ALCdevice::configValue(const char *block, const char *key) { return ConfigValueUInt(DeviceName.c_str(), block, key); } template<> -inline al::optional ALCdevice::configValue(const char *block, const char *key) +inline std::optional ALCdevice::configValue(const char *block, const char *key) { return ConfigValueFloat(DeviceName.c_str(), block, key); } template<> -inline al::optional ALCdevice::configValue(const char *block, const char *key) +inline std::optional ALCdevice::configValue(const char *block, const char *key) { return ConfigValueBool(DeviceName.c_str(), block, key); } #endif diff --git a/alc/panning.cpp b/alc/panning.cpp index d118f99c..a3d639fc 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include "AL/al.h" @@ -45,7 +46,6 @@ #include "almalloc.h" #include "alnumbers.h" #include "alnumeric.h" -#include "aloptional.h" #include "alspan.h" #include "alstring.h" #include "alu.h" @@ -933,7 +933,7 @@ void InitUhjPanning(ALCdevice *device) } // namespace -void aluInitRenderer(ALCdevice *device, int hrtf_id, al::optional stereomode) +void aluInitRenderer(ALCdevice *device, int hrtf_id, std::optional stereomode) { /* Hold the HRTF the device last used, in case it's used again. */ HrtfStorePtr old_hrtf{std::move(device->mHrtf)}; diff --git a/common/aloptional.h b/common/aloptional.h deleted file mode 100644 index 45b0cf8a..00000000 --- a/common/aloptional.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef AL_OPTIONAL_H -#define AL_OPTIONAL_H - -#include - -namespace al { - -constexpr auto nullopt = std::nullopt; - -template -using optional = std::optional; - -using std::make_optional; - -} // namespace al - -#endif /* AL_OPTIONAL_H */ diff --git a/common/strutils.cpp b/common/strutils.cpp index d0418eff..b221b6ec 100644 --- a/common/strutils.cpp +++ b/common/strutils.cpp @@ -43,21 +43,21 @@ std::wstring utf8_to_wstr(const char *str) namespace al { -al::optional getenv(const char *envname) +std::optional getenv(const char *envname) { const char *str{std::getenv(envname)}; if(str && str[0] != '\0') return str; - return al::nullopt; + return std::nullopt; } #ifdef _WIN32 -al::optional getenv(const WCHAR *envname) +std::optional getenv(const WCHAR *envname) { const WCHAR *str{_wgetenv(envname)}; if(str && str[0] != L'\0') return str; - return al::nullopt; + return std::nullopt; } #endif diff --git a/common/strutils.h b/common/strutils.h index 0c7a0e22..67f057a7 100644 --- a/common/strutils.h +++ b/common/strutils.h @@ -1,10 +1,9 @@ #ifndef AL_STRUTILS_H #define AL_STRUTILS_H +#include #include -#include "aloptional.h" - #ifdef _WIN32 #include @@ -14,9 +13,9 @@ std::wstring utf8_to_wstr(const char *str); namespace al { -al::optional getenv(const char *envname); +std::optional getenv(const char *envname); #ifdef _WIN32 -al::optional getenv(const wchar_t *envname); +std::optional getenv(const wchar_t *envname); #endif } // namespace al diff --git a/core/ambdec.cpp b/core/ambdec.cpp index 8ca182c4..a056e63f 100644 --- a/core/ambdec.cpp +++ b/core/ambdec.cpp @@ -47,9 +47,9 @@ enum class ReaderScope { #else [[gnu::format(printf,2,3)]] #endif -al::optional make_error(size_t linenum, const char *fmt, ...) +std::optional make_error(size_t linenum, const char *fmt, ...) { - al::optional ret; + std::optional ret; auto &str = ret.emplace(); str.resize(256); @@ -77,7 +77,7 @@ al::optional make_error(size_t linenum, const char *fmt, ...) AmbDecConf::~AmbDecConf() = default; -al::optional AmbDecConf::load(const char *fname) noexcept +std::optional AmbDecConf::load(const char *fname) noexcept { al::ifstream f{fname}; if(!f.is_open()) @@ -291,7 +291,7 @@ al::optional AmbDecConf::load(const char *fname) noexcept if(CoeffScale == AmbDecScale::Unset) return make_error(linenum, "No coefficient scaling defined"); - return al::nullopt; + return std::nullopt; } else return make_error(linenum, "Unexpected command: %s", command.c_str()); diff --git a/core/ambdec.h b/core/ambdec.h index 7f739781..19f68697 100644 --- a/core/ambdec.h +++ b/core/ambdec.h @@ -3,9 +3,9 @@ #include #include +#include #include -#include "aloptional.h" #include "core/ambidefs.h" /* Helpers to read .ambdec configuration files. */ @@ -49,7 +49,7 @@ struct AmbDecConf { ~AmbDecConf(); - al::optional load(const char *fname) noexcept; + std::optional load(const char *fname) noexcept; }; #endif /* CORE_AMBDEC_H */ diff --git a/core/cpu_caps.cpp b/core/cpu_caps.cpp index 165edb24..1a064cf4 100644 --- a/core/cpu_caps.cpp +++ b/core/cpu_caps.cpp @@ -51,14 +51,14 @@ inline std::array get_cpuid(unsigned int f) } // namespace -al::optional GetCPUInfo() +std::optional GetCPUInfo() { CPUInfo ret; #ifdef CAN_GET_CPUID auto cpuregs = get_cpuid(0); if(cpuregs[0] == 0) - return al::nullopt; + return std::nullopt; const reg_type maxfunc{cpuregs[0]}; diff --git a/core/cpu_caps.h b/core/cpu_caps.h index ffd671d0..0826a49b 100644 --- a/core/cpu_caps.h +++ b/core/cpu_caps.h @@ -1,10 +1,9 @@ #ifndef CORE_CPU_CAPS_H #define CORE_CPU_CAPS_H +#include #include -#include "aloptional.h" - extern int CPUCapFlags; enum { @@ -21,6 +20,6 @@ struct CPUInfo { int mCaps{0}; }; -al::optional GetCPUInfo(); +std::optional GetCPUInfo(); #endif /* CORE_CPU_CAPS_H */ diff --git a/core/helpers.cpp b/core/helpers.cpp index 71ddbc23..58cc74e5 100644 --- a/core/helpers.cpp +++ b/core/helpers.cpp @@ -9,15 +9,15 @@ #include #include #include -#include #include +#include +#include #include #include #include "almalloc.h" #include "alfstream.h" #include "alnumeric.h" -#include "aloptional.h" #include "alspan.h" #include "alstring.h" #include "logging.h" @@ -38,7 +38,7 @@ bool AllowRTTimeLimit{true}; const PathNamePair &GetProcBinary() { - static al::optional procbin; + static std::optional procbin; if(procbin) return *procbin; auto fullpath = std::vector(256); @@ -209,7 +209,7 @@ void SetRTPriority(void) const PathNamePair &GetProcBinary() { - static al::optional procbin; + static std::optional procbin; if(procbin) return *procbin; std::vector pathname; diff --git a/core/hrtf.cpp b/core/hrtf.cpp index cdafe93c..c54d96d1 100644 --- a/core/hrtf.cpp +++ b/core/hrtf.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -25,7 +26,6 @@ #include "almalloc.h" #include "alnumbers.h" #include "alnumeric.h" -#include "aloptional.h" #include "alspan.h" #include "ambidefs.h" #include "filters/splitter.h" @@ -1221,7 +1221,7 @@ al::span GetResource(int name) } // namespace -al::vector EnumerateHrtf(al::optional pathopt) +al::vector EnumerateHrtf(std::optional pathopt) { std::lock_guard _{EnumeratedHrtfLock}; EnumeratedHrtfs.clear(); diff --git a/core/hrtf.h b/core/hrtf.h index eb18682a..7215711b 100644 --- a/core/hrtf.h +++ b/core/hrtf.h @@ -4,10 +4,10 @@ #include #include #include +#include #include #include "almalloc.h" -#include "aloptional.h" #include "alspan.h" #include "atomic.h" #include "ambidefs.h" @@ -83,7 +83,7 @@ struct DirectHrtfState { }; -al::vector EnumerateHrtf(al::optional pathopt); +al::vector EnumerateHrtf(std::optional pathopt); HrtfStorePtr GetLoadedHrtf(const std::string &name, const uint devrate); #endif /* CORE_HRTF_H */ diff --git a/core/voice.cpp b/core/voice.cpp index 6a747f85..090b10a3 100644 --- a/core/voice.cpp +++ b/core/voice.cpp @@ -12,13 +12,13 @@ #include #include #include +#include #include #include #include #include "albyte.h" #include "alnumeric.h" -#include "aloptional.h" #include "alspan.h" #include "alstring.h" #include "ambidefs.h" @@ -129,7 +129,7 @@ inline HrtfMixerBlendFunc SelectHrtfBlendMixer() } // namespace -void Voice::InitMixer(al::optional resampler) +void Voice::InitMixer(std::optional resampler) { if(resampler) { diff --git a/core/voice.h b/core/voice.h index 57ee7b01..9d74ff6b 100644 --- a/core/voice.h +++ b/core/voice.h @@ -6,12 +6,12 @@ #include #include #include +#include #include #include #include "albyte.h" #include "almalloc.h" -#include "aloptional.h" #include "alspan.h" #include "bufferline.h" #include "buffer_storage.h" @@ -270,7 +270,7 @@ struct Voice { void prepare(DeviceBase *device); - static void InitMixer(al::optional resampler); + static void InitMixer(std::optional resampler); DEF_NEWDEL(Voice) }; diff --git a/utils/makemhr/loaddef.cpp b/utils/makemhr/loaddef.cpp index e8092363..84fbb48b 100644 --- a/utils/makemhr/loaddef.cpp +++ b/utils/makemhr/loaddef.cpp @@ -33,11 +33,10 @@ #include #include #include -#include +#include #include #include "alfstream.h" -#include "aloptional.h" #include "alspan.h" #include "alstring.h" #include "makemhr.h" @@ -1755,7 +1754,7 @@ static int ProcessSources(TokenReaderT *tr, HrirDataT *hData, const uint outRate PPhaseResampler onsetResampler; onsetResampler.init(hData->mIrRate, OnsetRateMultiple*hData->mIrRate); - al::optional resampler; + std::optional resampler; if(outRate && outRate != hData->mIrRate) resampler.emplace().init(hData->mIrRate, outRate); const double rateScale{outRate ? static_cast(outRate) / hData->mIrRate : 1.0}; diff --git a/utils/makemhr/loadsofa.cpp b/utils/makemhr/loadsofa.cpp index dcb0a35e..9e661839 100644 --- a/utils/makemhr/loadsofa.cpp +++ b/utils/makemhr/loadsofa.cpp @@ -33,11 +33,11 @@ #include #include #include +#include #include #include #include -#include "aloptional.h" #include "alspan.h" #include "makemhr.h" #include "polyphase_resampler.h" @@ -265,7 +265,7 @@ static bool LoadResponses(MYSOFA_HRTF *sofaHrtf, HrirDataT *hData, const DelayTy double *hrirs = hData->mHrirsBase.data(); std::unique_ptr restmp; - al::optional resampler; + std::optional resampler; if(outRate && outRate != hData->mIrRate) { resampler.emplace().init(hData->mIrRate, outRate); -- cgit v1.2.3 From 3d2e586636f765eb2fccebb757305295d7b2c954 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 4 May 2023 08:33:43 -0700 Subject: Update ComPtr and use an out_ptr() function --- alc/backends/dsound.cpp | 15 ++++---- alc/backends/wasapi.cpp | 67 ++++++++++++++-------------------- common/comptr.h | 95 +++++++++++++++++++++++++++++++++++-------------- 3 files changed, 101 insertions(+), 76 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/dsound.cpp b/alc/backends/dsound.cpp index f549c0fe..51dc36f6 100644 --- a/alc/backends/dsound.cpp +++ b/alc/backends/dsound.cpp @@ -347,7 +347,7 @@ void DSoundPlayback::open(const char *name) //DirectSound Init code ComPtr ds; if(SUCCEEDED(hr)) - hr = DirectSoundCreate(guid, ds.getPtr(), nullptr); + hr = DirectSoundCreate(guid, al::out_ptr(ds), nullptr); if(SUCCEEDED(hr)) hr = ds->SetCooperativeLevel(GetForegroundWindow(), DSSCL_PRIORITY); if(FAILED(hr)) @@ -460,7 +460,7 @@ retry_open: DSBUFFERDESC DSBDescription{}; DSBDescription.dwSize = sizeof(DSBDescription); DSBDescription.dwFlags = DSBCAPS_PRIMARYBUFFER; - hr = mDS->CreateSoundBuffer(&DSBDescription, mPrimaryBuffer.getPtr(), nullptr); + hr = mDS->CreateSoundBuffer(&DSBDescription, al::out_ptr(mPrimaryBuffer), nullptr); } if(SUCCEEDED(hr)) hr = mPrimaryBuffer->SetFormat(&OutputType.Format); @@ -480,7 +480,7 @@ retry_open: DSBDescription.dwBufferBytes = mDevice->BufferSize * OutputType.Format.nBlockAlign; DSBDescription.lpwfxFormat = &OutputType.Format; - hr = mDS->CreateSoundBuffer(&DSBDescription, mBuffer.getPtr(), nullptr); + hr = mDS->CreateSoundBuffer(&DSBDescription, al::out_ptr(mBuffer), nullptr); if(FAILED(hr) && mDevice->FmtType == DevFmtFloat) { mDevice->FmtType = DevFmtShort; @@ -490,12 +490,9 @@ retry_open: if(SUCCEEDED(hr)) { - void *ptr; - hr = mBuffer->QueryInterface(IID_IDirectSoundNotify, &ptr); + hr = mBuffer->QueryInterface(IID_IDirectSoundNotify, al::out_ptr(mNotifies)); if(SUCCEEDED(hr)) { - mNotifies = ComPtr{static_cast(ptr)}; - uint num_updates{mDevice->BufferSize / mDevice->UpdateSize}; assert(num_updates <= MAX_UPDATES); @@ -679,9 +676,9 @@ void DSoundCapture::open(const char *name) DSCBDescription.lpwfxFormat = &InputType.Format; //DirectSoundCapture Init code - hr = DirectSoundCaptureCreate(guid, mDSC.getPtr(), nullptr); + hr = DirectSoundCaptureCreate(guid, al::out_ptr(mDSC), nullptr); if(SUCCEEDED(hr)) - mDSC->CreateCaptureBuffer(&DSCBDescription, mDSCbuffer.getPtr(), nullptr); + mDSC->CreateCaptureBuffer(&DSCBDescription, al::out_ptr(mDSCbuffer), nullptr); if(SUCCEEDED(hr)) mRing = RingBuffer::Create(mDevice->BufferSize, InputType.Format.nBlockAlign, false); diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index e834eef4..e66656ce 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -199,7 +199,7 @@ NameGUIDPair get_device_name_and_guid(IMMDevice *device) std::string name, guid; ComPtr ps; - HRESULT hr = device->OpenPropertyStore(STGM_READ, ps.getPtr()); + HRESULT hr = device->OpenPropertyStore(STGM_READ, al::out_ptr(ps)); if(FAILED(hr)) { WARN("OpenPropertyStore failed: 0x%08lx\n", hr); @@ -242,7 +242,7 @@ NameGUIDPair get_device_name_and_guid(IMMDevice *device) EndpointFormFactor get_device_formfactor(IMMDevice *device) { ComPtr ps; - HRESULT hr{device->OpenPropertyStore(STGM_READ, ps.getPtr())}; + HRESULT hr{device->OpenPropertyStore(STGM_READ, al::out_ptr(ps))}; if(FAILED(hr)) { WARN("OpenPropertyStore failed: 0x%08lx\n", hr); @@ -306,7 +306,7 @@ void probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, al::vector{}.swap(list); ComPtr coll; - HRESULT hr{devenum->EnumAudioEndpoints(flowdir, DEVICE_STATE_ACTIVE, coll.getPtr())}; + HRESULT hr{devenum->EnumAudioEndpoints(flowdir, DEVICE_STATE_ACTIVE, al::out_ptr(coll))}; if(FAILED(hr)) { ERR("Failed to enumerate audio endpoints: 0x%08lx\n", hr); @@ -319,7 +319,7 @@ void probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, al::vector device; - hr = devenum->GetDefaultAudioEndpoint(flowdir, eMultimedia, device.getPtr()); + hr = devenum->GetDefaultAudioEndpoint(flowdir, eMultimedia, al::out_ptr(device)); if(SUCCEEDED(hr)) { if(WCHAR *devid{get_device_id(device.get())}) @@ -327,12 +327,12 @@ void probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, al::vectorItem(i, device.getPtr()); + device = nullptr; + hr = coll->Item(i, al::out_ptr(device)); if(FAILED(hr)) continue; if(WCHAR *devid{get_device_id(device.get())}) @@ -340,7 +340,6 @@ void probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, al::vector *promise) case MsgType::EnumeratePlayback: case MsgType::EnumerateCapture: { - void *ptr{}; + ComPtr devenum; hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, - IID_IMMDeviceEnumerator, &ptr); + IID_IMMDeviceEnumerator, al::out_ptr(devenum)); if(FAILED(hr)) msg.mPromise.set_value(hr); else { - ComPtr devenum{static_cast(ptr)}; - if(msg.mType == MsgType::EnumeratePlayback) probe_devices(devenum.get(), eRender, PlaybackDevices); else if(msg.mType == MsgType::EnumerateCapture) @@ -841,17 +838,16 @@ HRESULT WasapiPlayback::openProxy(const char *name) devid = iter->devid.c_str(); } - void *ptr; + ComPtr enumerator; ComPtr mmdev; HRESULT hr{CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, - IID_IMMDeviceEnumerator, &ptr)}; + IID_IMMDeviceEnumerator, al::out_ptr(enumerator))}; if(SUCCEEDED(hr)) { - ComPtr enumerator{static_cast(ptr)}; if(!devid) - hr = enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, mmdev.getPtr()); + hr = enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, al::out_ptr(mmdev)); else - hr = enumerator->GetDevice(devid, mmdev.getPtr()); + hr = enumerator->GetDevice(devid, al::out_ptr(mmdev)); } if(FAILED(hr)) { @@ -886,14 +882,13 @@ HRESULT WasapiPlayback::resetProxy() { mClient = nullptr; - void *ptr; - HRESULT hr{mMMDev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr)}; + HRESULT hr{mMMDev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, + al::out_ptr(mClient))}; if(FAILED(hr)) { ERR("Failed to reactivate audio client: 0x%08lx\n", hr); return hr; } - mClient = ComPtr{static_cast(ptr)}; WAVEFORMATEX *wfx; hr = mClient->GetMixFormat(&wfx); @@ -1242,11 +1237,9 @@ HRESULT WasapiPlayback::startProxy() return hr; } - void *ptr; - hr = mClient->GetService(IID_IAudioRenderClient, &ptr); + hr = mClient->GetService(IID_IAudioRenderClient, al::out_ptr(mRender)); if(SUCCEEDED(hr)) { - mRender = ComPtr{static_cast(ptr)}; try { mKillNow.store(false, std::memory_order_release); mThread = std::thread{std::mem_fn(&WasapiPlayback::mixerProc), this}; @@ -1516,16 +1509,15 @@ HRESULT WasapiCapture::openProxy(const char *name) devid = iter->devid.c_str(); } - void *ptr; + ComPtr enumerator; HRESULT hr{CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, - IID_IMMDeviceEnumerator, &ptr)}; + IID_IMMDeviceEnumerator, al::out_ptr(enumerator))}; if(SUCCEEDED(hr)) { - ComPtr enumerator{static_cast(ptr)}; if(!devid) - hr = enumerator->GetDefaultAudioEndpoint(eCapture, eMultimedia, mMMDev.getPtr()); + hr = enumerator->GetDefaultAudioEndpoint(eCapture, eMultimedia, al::out_ptr(mMMDev)); else - hr = enumerator->GetDevice(devid, mMMDev.getPtr()); + hr = enumerator->GetDevice(devid, al::out_ptr(mMMDev)); } if(FAILED(hr)) { @@ -1550,14 +1542,13 @@ HRESULT WasapiCapture::resetProxy() { mClient = nullptr; - void *ptr; - HRESULT hr{mMMDev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr)}; + HRESULT hr{mMMDev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, + al::out_ptr(mClient))}; if(FAILED(hr)) { ERR("Failed to reactivate audio client: 0x%08lx\n", hr); return hr; } - mClient = ComPtr{static_cast(ptr)}; WAVEFORMATEX *wfx; hr = mClient->GetMixFormat(&wfx); @@ -1849,11 +1840,9 @@ HRESULT WasapiCapture::startProxy() return hr; } - void *ptr; - hr = mClient->GetService(IID_IAudioCaptureClient, &ptr); + hr = mClient->GetService(IID_IAudioCaptureClient, al::out_ptr(mCapture)); if(SUCCEEDED(hr)) { - mCapture = ComPtr{static_cast(ptr)}; try { mKillNow.store(false, std::memory_order_release); mThread = std::thread{std::mem_fn(&WasapiCapture::recordProc), this}; @@ -1916,19 +1905,15 @@ bool WasapiBackendFactory::init() return hr; } - void *ptr{}; + ComPtr enumerator; hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, - IID_IMMDeviceEnumerator, &ptr); + IID_IMMDeviceEnumerator, al::out_ptr(enumerator)); if(FAILED(hr)) - { WARN("Failed to create IMMDeviceEnumerator instance: 0x%08lx\n", hr); - CoUninitialize(); - return hr; - } - static_cast(ptr)->Release(); + enumerator = nullptr; CoUninitialize(); - return S_OK; + return hr; }); InitResult = res.get(); diff --git a/common/comptr.h b/common/comptr.h index cdc6dec0..5a733ea2 100644 --- a/common/comptr.h +++ b/common/comptr.h @@ -2,49 +2,46 @@ #define COMMON_COMPTR_H #include +#include +#include #include - -#include "opthelpers.h" - +#include template -class ComPtr { - T *mPtr{nullptr}; +struct ComPtr { + using element_type = T; + + static constexpr bool RefIsNoexcept{noexcept(std::declval().AddRef()) + && noexcept(std::declval().Release())}; -public: ComPtr() noexcept = default; - ComPtr(const ComPtr &rhs) : mPtr{rhs.mPtr} { if(mPtr) mPtr->AddRef(); } + ComPtr(const ComPtr &rhs) noexcept(RefIsNoexcept) : mPtr{rhs.mPtr} + { if(mPtr) mPtr->AddRef(); } ComPtr(ComPtr&& rhs) noexcept : mPtr{rhs.mPtr} { rhs.mPtr = nullptr; } ComPtr(std::nullptr_t) noexcept { } explicit ComPtr(T *ptr) noexcept : mPtr{ptr} { } ~ComPtr() { if(mPtr) mPtr->Release(); } - ComPtr& operator=(const ComPtr &rhs) + ComPtr& operator=(const ComPtr &rhs) noexcept(RefIsNoexcept) { - if(!rhs.mPtr) + if constexpr(RefIsNoexcept) { - if(mPtr) - mPtr->Release(); - mPtr = nullptr; + if(rhs.mPtr) rhs.mPtr->AddRef(); + if(mPtr) mPtr->Release(); + mPtr = rhs.mPtr; + return *this; } else { - rhs.mPtr->AddRef(); - try { - if(mPtr) - mPtr->Release(); - mPtr = rhs.mPtr; - } - catch(...) { - rhs.mPtr->Release(); - throw; - } + ComPtr tmp{rhs}; + if(mPtr) mPtr->Release(); + mPtr = tmp.release(); + return *this; } - return *this; } - ComPtr& operator=(ComPtr&& rhs) + ComPtr& operator=(ComPtr&& rhs) noexcept(RefIsNoexcept) { - if(&rhs != this) LIKELY + if(&rhs != this) { if(mPtr) mPtr->Release(); mPtr = std::exchange(rhs.mPtr, nullptr); @@ -52,17 +49,63 @@ public: return *this; } + void reset(T *ptr=nullptr) noexcept(RefIsNoexcept) + { + if(mPtr) mPtr->Release(); + mPtr = ptr; + } + explicit operator bool() const noexcept { return mPtr != nullptr; } T& operator*() const noexcept { return *mPtr; } T* operator->() const noexcept { return mPtr; } T* get() const noexcept { return mPtr; } - T** getPtr() noexcept { return &mPtr; } T* release() noexcept { return std::exchange(mPtr, nullptr); } void swap(ComPtr &rhs) noexcept { std::swap(mPtr, rhs.mPtr); } void swap(ComPtr&& rhs) noexcept { std::swap(mPtr, rhs.mPtr); } + +private: + T *mPtr{nullptr}; }; + +namespace al { + +template +class out_ptr_t { + static_assert(!std::is_same_v); + + SP &mRes; + std::variant mPtr{}; + +public: + out_ptr_t(SP &res) : mRes{res} { } + ~out_ptr_t() + { + auto set_res = [this](auto &ptr) + { mRes.reset(static_cast(ptr)); }; + std::visit(set_res, mPtr); + } + out_ptr_t(const out_ptr_t&) = delete; + + out_ptr_t& operator=(const out_ptr_t&) = delete; + + operator PT*() noexcept + { return &std::get(mPtr); } + + operator void**() noexcept + { return &mPtr.template emplace(); } +}; + +template +auto out_ptr(SP &res) +{ + using ptype = typename SP::element_type*; + return out_ptr_t{res}; +} + +} // namespace al + #endif -- cgit v1.2.3 From 6e0a0a2692a4303d6410c24bf83e09ca47ac6759 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 4 May 2023 09:16:59 -0700 Subject: Make and use a bit_cast function Instead of reinterpret_casting between incompatible types --- al/buffer.cpp | 2 +- al/state.cpp | 5 +++-- alc/alc.cpp | 2 +- alc/alconfig.cpp | 3 ++- alc/backends/alsa.cpp | 3 ++- alc/backends/dsound.cpp | 3 ++- alc/backends/jack.cpp | 5 +++-- alc/backends/pipewire.cpp | 9 +++++---- alc/backends/portaudio.cpp | 3 ++- alc/backends/pulseaudio.cpp | 3 ++- alc/backends/wasapi.cpp | 4 ++-- common/albit.h | 11 +++++++++++ common/dynload.cpp | 3 ++- core/dbus_wrap.cpp | 3 ++- 14 files changed, 40 insertions(+), 19 deletions(-) (limited to 'alc/backends') diff --git a/al/buffer.cpp b/al/buffer.cpp index 4f0bcf8c..ad74a7f7 100644 --- a/al/buffer.cpp +++ b/al/buffer.cpp @@ -1463,7 +1463,7 @@ START_API_FUNC else switch(param) { case AL_BUFFER_CALLBACK_FUNCTION_SOFT: - *value = reinterpret_cast(albuf->mCallback); + *value = al::bit_cast(albuf->mCallback); break; case AL_BUFFER_CALLBACK_USER_PARAM_SOFT: *value = albuf->mUserData; diff --git a/al/state.cpp b/al/state.cpp index 77b104a4..fb3186c7 100644 --- a/al/state.cpp +++ b/al/state.cpp @@ -35,6 +35,7 @@ #include "AL/alext.h" #include "al/debug.h" +#include "albit.h" #include "alc/alu.h" #include "alc/context.h" #include "alc/inprogext.h" @@ -516,7 +517,7 @@ START_API_FUNC switch(pname) { case AL_EVENT_CALLBACK_FUNCTION_SOFT: - *values = reinterpret_cast(context->mEventCb); + *values = al::bit_cast(context->mEventCb); break; case AL_EVENT_CALLBACK_USER_PARAM_SOFT: @@ -524,7 +525,7 @@ START_API_FUNC break; case AL_DEBUG_CALLBACK_FUNCTION_EXT: - *values = reinterpret_cast(context->mDebugCb); + *values = al::bit_cast(context->mDebugCb); break; case AL_DEBUG_CALLBACK_USER_PARAM_EXT: diff --git a/alc/alc.cpp b/alc/alc.cpp index 2da5c5db..149223f4 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -180,7 +180,7 @@ BOOL APIENTRY DllMain(HINSTANCE module, DWORD reason, LPVOID /*reserved*/) case DLL_PROCESS_ATTACH: /* Pin the DLL so we won't get unloaded until the process terminates */ GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, - reinterpret_cast(module), &module); + al::bit_cast(module), &module); break; } return TRUE; diff --git a/alc/alconfig.cpp b/alc/alconfig.cpp index 56cad9e0..ceb7d97b 100644 --- a/alc/alconfig.cpp +++ b/alc/alconfig.cpp @@ -38,6 +38,7 @@ #include #include +#include "albit.h" #include "alfstream.h" #include "alstring.h" #include "core/helpers.h" @@ -418,7 +419,7 @@ void ReadALConfig() if((configURL=CFBundleCopyResourceURL(mainBundle, CFSTR(".alsoftrc"), CFSTR(""), nullptr)) && CFURLGetFileSystemRepresentation(configURL, true, fileName, sizeof(fileName))) { - f = al::ifstream{reinterpret_cast(fileName)}; + f = al::ifstream{al::bit_cast(fileName)}; if(f.is_open()) LoadConfigFromFile(f); } diff --git a/alc/backends/alsa.cpp b/alc/backends/alsa.cpp index 01021868..b162f84e 100644 --- a/alc/backends/alsa.cpp +++ b/alc/backends/alsa.cpp @@ -35,6 +35,7 @@ #include #include +#include "albit.h" #include "albyte.h" #include "alc/alconfig.h" #include "almalloc.h" @@ -1204,7 +1205,7 @@ bool AlsaBackendFactory::init() error = false; #define LOAD_FUNC(f) do { \ - p##f = reinterpret_cast(GetSymbol(alsa_handle, #f)); \ + p##f = al::bit_cast(GetSymbol(alsa_handle, #f)); \ if(p##f == nullptr) { \ error = true; \ missing_funcs += "\n" #f; \ diff --git a/alc/backends/dsound.cpp b/alc/backends/dsound.cpp index 51dc36f6..8b967c95 100644 --- a/alc/backends/dsound.cpp +++ b/alc/backends/dsound.cpp @@ -44,6 +44,7 @@ #include #include +#include "albit.h" #include "alnumeric.h" #include "comptr.h" #include "core/device.h" @@ -778,7 +779,7 @@ bool DSoundBackendFactory::init() } #define LOAD_FUNC(f) do { \ - p##f = reinterpret_cast(GetSymbol(ds_handle, #f)); \ + p##f = al::bit_cast(GetSymbol(ds_handle, #f)); \ if(!p##f) \ { \ CloseLib(ds_handle); \ diff --git a/alc/backends/jack.cpp b/alc/backends/jack.cpp index 791002ca..dbc2b038 100644 --- a/alc/backends/jack.cpp +++ b/alc/backends/jack.cpp @@ -31,6 +31,7 @@ #include #include +#include "albit.h" #include "alc/alconfig.h" #include "alnumeric.h" #include "core/device.h" @@ -126,7 +127,7 @@ bool jack_load() error = false; #define LOAD_FUNC(f) do { \ - p##f = reinterpret_cast(GetSymbol(jack_handle, #f)); \ + p##f = al::bit_cast(GetSymbol(jack_handle, #f)); \ if(p##f == nullptr) { \ error = true; \ missing_funcs += "\n" #f; \ @@ -135,7 +136,7 @@ bool jack_load() JACK_FUNCS(LOAD_FUNC); #undef LOAD_FUNC /* Optional symbols. These don't exist in all versions of JACK. */ -#define LOAD_SYM(f) p##f = reinterpret_cast(GetSymbol(jack_handle, #f)) +#define LOAD_SYM(f) p##f = al::bit_cast(GetSymbol(jack_handle, #f)) LOAD_SYM(jack_error_callback); #undef LOAD_SYM diff --git a/alc/backends/pipewire.cpp b/alc/backends/pipewire.cpp index d3c8e77e..5b1596aa 100644 --- a/alc/backends/pipewire.cpp +++ b/alc/backends/pipewire.cpp @@ -37,6 +37,7 @@ #include #include +#include "albit.h" #include "albyte.h" #include "alc/alconfig.h" #include "almalloc.h" @@ -210,7 +211,7 @@ bool pwire_load() } #define LOAD_FUNC(f) do { \ - p##f = reinterpret_cast(GetSymbol(pwire_handle, #f)); \ + p##f = al::bit_cast(GetSymbol(pwire_handle, #f)); \ if(p##f == nullptr) missing_funcs += "\n" #f; \ } while(0); PWIRE_FUNCS(LOAD_FUNC) @@ -328,11 +329,11 @@ To as(From) noexcept = delete; * - pw_metadata */ template<> -pw_proxy* as(pw_registry *reg) noexcept { return reinterpret_cast(reg); } +pw_proxy* as(pw_registry *reg) noexcept { return al::bit_cast(reg); } template<> -pw_proxy* as(pw_node *node) noexcept { return reinterpret_cast(node); } +pw_proxy* as(pw_node *node) noexcept { return al::bit_cast(node); } template<> -pw_proxy* as(pw_metadata *mdata) noexcept { return reinterpret_cast(mdata); } +pw_proxy* as(pw_metadata *mdata) noexcept { return al::bit_cast(mdata); } struct PwContextDeleter { diff --git a/alc/backends/portaudio.cpp b/alc/backends/portaudio.cpp index 9c94587d..d652d4cd 100644 --- a/alc/backends/portaudio.cpp +++ b/alc/backends/portaudio.cpp @@ -26,6 +26,7 @@ #include #include +#include "albit.h" #include "alc/alconfig.h" #include "alnumeric.h" #include "core/device.h" @@ -376,7 +377,7 @@ bool PortBackendFactory::init() return false; #define LOAD_FUNC(f) do { \ - p##f = reinterpret_cast(GetSymbol(pa_handle, #f)); \ + p##f = al::bit_cast(GetSymbol(pa_handle, #f)); \ if(p##f == nullptr) \ { \ CloseLib(pa_handle); \ diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index 6f706c7f..6e8bfe1b 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -38,6 +38,7 @@ #include #include +#include "albit.h" #include "albyte.h" #include "alc/alconfig.h" #include "almalloc.h" @@ -1381,7 +1382,7 @@ bool PulseBackendFactory::init() } #define LOAD_FUNC(x) do { \ - p##x = reinterpret_cast(GetSymbol(pulse_handle, #x)); \ + p##x = al::bit_cast(GetSymbol(pulse_handle, #x)); \ if(!(p##x)) { \ ret = false; \ missing_funcs += "\n" #x; \ diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index e66656ce..ea6ecbe0 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -207,7 +207,7 @@ NameGUIDPair get_device_name_and_guid(IMMDevice *device) } PropVariant pvprop; - hr = ps->GetValue(reinterpret_cast(DEVPKEY_Device_FriendlyName), pvprop.get()); + hr = ps->GetValue(al::bit_cast(DEVPKEY_Device_FriendlyName), pvprop.get()); if(FAILED(hr)) { WARN("GetValue Device_FriendlyName failed: 0x%08lx\n", hr); @@ -222,7 +222,7 @@ NameGUIDPair get_device_name_and_guid(IMMDevice *device) } pvprop.clear(); - hr = ps->GetValue(reinterpret_cast(PKEY_AudioEndpoint_GUID), pvprop.get()); + hr = ps->GetValue(al::bit_cast(PKEY_AudioEndpoint_GUID), pvprop.get()); if(FAILED(hr)) { WARN("GetValue AudioEndpoint_GUID failed: 0x%08lx\n", hr); diff --git a/common/albit.h b/common/albit.h index ad596208..a563a4e7 100644 --- a/common/albit.h +++ b/common/albit.h @@ -2,6 +2,7 @@ #define AL_BIT_H #include +#include #include #include #if !defined(__GNUC__) && (defined(_WIN32) || defined(_WIN64)) @@ -10,6 +11,16 @@ namespace al { +template +std::enable_if_t + && std::is_trivially_copyable_v, +To> bit_cast(const From &src) noexcept +{ + union { char c; To dst; } u; + std::memcpy(&u.dst, &src, sizeof(To)); + return u.dst; +} + #ifdef __BYTE_ORDER__ enum class endian { little = __ORDER_LITTLE_ENDIAN__, diff --git a/common/dynload.cpp b/common/dynload.cpp index f1c2a7eb..86c36e00 100644 --- a/common/dynload.cpp +++ b/common/dynload.cpp @@ -3,6 +3,7 @@ #include "dynload.h" +#include "albit.h" #include "strutils.h" #ifdef _WIN32 @@ -17,7 +18,7 @@ void *LoadLib(const char *name) void CloseLib(void *handle) { FreeLibrary(static_cast(handle)); } void *GetSymbol(void *handle, const char *name) -{ return reinterpret_cast(GetProcAddress(static_cast(handle), name)); } +{ return al::bit_cast(GetProcAddress(static_cast(handle), name)); } #elif defined(HAVE_DLFCN_H) diff --git a/core/dbus_wrap.cpp b/core/dbus_wrap.cpp index 7f221706..eaddce9f 100644 --- a/core/dbus_wrap.cpp +++ b/core/dbus_wrap.cpp @@ -8,6 +8,7 @@ #include #include +#include "albit.h" #include "logging.h" @@ -21,7 +22,7 @@ void PrepareDBus() static constexpr char libname[] = "libdbus-1.so.3"; auto load_func = [](auto &f, const char *name) -> void - { f = reinterpret_cast>(GetSymbol(dbus_handle, name)); }; + { f = al::bit_cast>(GetSymbol(dbus_handle, name)); }; #define LOAD_FUNC(x) do { \ load_func(p##x, #x); \ if(!p##x) \ -- cgit v1.2.3 From 7cbf3ba2e2bab5c3aecb001e1d387c89309dbec4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 4 May 2023 11:39:13 -0700 Subject: Use std::byte instead of a custom al::byte --- CMakeLists.txt | 1 - al/buffer.cpp | 14 ++++---- al/buffer.h | 4 +-- al/event.cpp | 1 - alc/alc.cpp | 4 +-- alc/backends/alsa.cpp | 15 ++++---- alc/backends/base.cpp | 2 +- alc/backends/base.h | 4 +-- alc/backends/coreaudio.cpp | 6 ++-- alc/backends/dsound.cpp | 4 +-- alc/backends/oboe.cpp | 4 +-- alc/backends/opensl.cpp | 6 ++-- alc/backends/oss.cpp | 9 +++-- alc/backends/pipewire.cpp | 10 +++--- alc/backends/portaudio.cpp | 4 +-- alc/backends/pulseaudio.cpp | 15 ++++---- alc/backends/sndio.cpp | 16 ++++----- alc/backends/solaris.cpp | 7 ++-- alc/backends/wasapi.cpp | 4 +-- alc/backends/wave.cpp | 3 +- alc/backends/winmm.cpp | 4 +-- alc/effects/convolution.cpp | 3 +- common/albyte.h | 17 --------- common/ringbuffer.cpp | 85 ++++++++++++++++++++++----------------------- common/ringbuffer.h | 39 ++++++++++----------- core/buffer_storage.h | 4 +-- core/converter.cpp | 10 +++--- core/effects/base.h | 1 - core/fmt_traits.h | 20 +++++------ core/hrtf.cpp | 6 ++-- core/voice.cpp | 35 +++++++++---------- core/voice.h | 5 ++- utils/uhjdecoder.cpp | 53 ++++++++++++++-------------- 33 files changed, 191 insertions(+), 224 deletions(-) delete mode 100644 common/albyte.h (limited to 'alc/backends') diff --git a/CMakeLists.txt b/CMakeLists.txt index 07377ddb..fe46a688 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -589,7 +589,6 @@ check_symbol_exists(getopt unistd.h HAVE_GETOPT) # router, and certain tools and examples. set(COMMON_OBJS common/albit.h - common/albyte.h common/alcomplex.cpp common/alcomplex.h common/aldeque.h diff --git a/al/buffer.cpp b/al/buffer.cpp index ad74a7f7..1a042f46 100644 --- a/al/buffer.cpp +++ b/al/buffer.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -44,7 +45,6 @@ #include "AL/alext.h" #include "albit.h" -#include "albyte.h" #include "alc/context.h" #include "alc/device.h" #include "alc/inprogext.h" @@ -277,7 +277,7 @@ ALuint SanitizeAlignment(FmtType type, ALuint align) /** Loads the specified data into the buffer, using the specified format. */ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, ALuint size, - const FmtChannels DstChannels, const FmtType DstType, const al::byte *SrcData, + const FmtChannels DstChannels, const FmtType DstType, const std::byte *SrcData, ALbitfieldSOFT access) { if(ReadRef(ALBuf->ref) != 0 || ALBuf->MappedAccess != 0) UNLIKELY @@ -343,7 +343,7 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, ALuint size, */ if(newsize != ALBuf->mDataStorage.size()) { - auto newdata = al::vector(newsize, al::byte{}); + auto newdata = al::vector(newsize, std::byte{}); if((access&AL_PRESERVE_DATA_BIT_SOFT)) { const size_t tocopy{minz(newdata.size(), ALBuf->mDataStorage.size())}; @@ -437,7 +437,7 @@ void PrepareCallback(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, /** Prepares the buffer to use caller-specified storage. */ void PrepareUserPtr(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, - const FmtChannels DstChannels, const FmtType DstType, al::byte *sdata, const ALuint sdatalen) + const FmtChannels DstChannels, const FmtType DstType, std::byte *sdata, const ALuint sdatalen) { if(ReadRef(ALBuf->ref) != 0 || ALBuf->MappedAccess != 0) UNLIKELY return context->setError(AL_INVALID_OPERATION, "Modifying storage for in-use buffer %u", @@ -506,7 +506,7 @@ void PrepareUserPtr(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, #endif decltype(ALBuf->mDataStorage){}.swap(ALBuf->mDataStorage); - ALBuf->mData = {static_cast(sdata), sdatalen}; + ALBuf->mData = {static_cast(sdata), sdatalen}; #ifdef ALSOFT_EAX eax_x_ram_clear(*context->mALDevice, *ALBuf); @@ -767,7 +767,7 @@ START_API_FUNC else { LoadData(context.get(), albuf, freq, static_cast(size), usrfmt->channels, - usrfmt->type, static_cast(data), flags); + usrfmt->type, static_cast(data), flags); } } } @@ -796,7 +796,7 @@ START_API_FUNC return context->setError(AL_INVALID_ENUM, "Invalid format 0x%04x", format); PrepareUserPtr(context.get(), albuf, freq, usrfmt->channels, usrfmt->type, - static_cast(data), static_cast(size)); + static_cast(data), static_cast(size)); } END_API_FUNC diff --git a/al/buffer.h b/al/buffer.h index 64ebe1f3..3df1fa4c 100644 --- a/al/buffer.h +++ b/al/buffer.h @@ -2,10 +2,10 @@ #define AL_BUFFER_H #include +#include #include "AL/al.h" -#include "albyte.h" #include "alc/inprogext.h" #include "almalloc.h" #include "atomic.h" @@ -26,7 +26,7 @@ enum class EaxStorage : uint8_t { struct ALbuffer : public BufferStorage { ALbitfieldSOFT Access{0u}; - al::vector mDataStorage; + al::vector mDataStorage; ALuint OriginalSize{0}; diff --git a/al/event.cpp b/al/event.cpp index 1bc39d1e..acb4958a 100644 --- a/al/event.cpp +++ b/al/event.cpp @@ -17,7 +17,6 @@ #include "AL/al.h" #include "AL/alc.h" -#include "albyte.h" #include "alc/context.h" #include "alc/effects/base.h" #include "alc/inprogext.h" diff --git a/alc/alc.cpp b/alc/alc.cpp index 149223f4..d226b39d 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -68,7 +69,6 @@ #include "al/listener.h" #include "al/source.h" #include "albit.h" -#include "albyte.h" #include "alconfig.h" #include "almalloc.h" #include "alnumeric.h" @@ -3883,7 +3883,7 @@ START_API_FUNC return; } - backend->captureSamples(static_cast(buffer), usamples); + backend->captureSamples(static_cast(buffer), usamples); } END_API_FUNC diff --git a/alc/backends/alsa.cpp b/alc/backends/alsa.cpp index b162f84e..74713590 100644 --- a/alc/backends/alsa.cpp +++ b/alc/backends/alsa.cpp @@ -36,7 +36,6 @@ #include #include "albit.h" -#include "albyte.h" #include "alc/alconfig.h" #include "almalloc.h" #include "alnumeric.h" @@ -439,7 +438,7 @@ struct AlsaPlayback final : public BackendBase { std::mutex mMutex; uint mFrameStep{}; - al::vector mBuffer; + al::vector mBuffer; std::atomic mKillNow{true}; std::thread mThread; @@ -585,7 +584,7 @@ int AlsaPlayback::mixerNoMMapProc() continue; } - al::byte *WritePtr{mBuffer.data()}; + std::byte *WritePtr{mBuffer.data()}; avail = snd_pcm_bytes_to_frames(mPcmHandle, static_cast(mBuffer.size())); std::lock_guard _{mMutex}; mDevice->renderSamples(WritePtr, static_cast(avail), mFrameStep); @@ -874,13 +873,13 @@ struct AlsaCapture final : public BackendBase { void open(const char *name) override; void start() override; void stop() override; - void captureSamples(al::byte *buffer, uint samples) override; + void captureSamples(std::byte *buffer, uint samples) override; uint availableSamples() override; ClockLatency getClockLatency() override; snd_pcm_t *mPcmHandle{nullptr}; - al::vector mBuffer; + al::vector mBuffer; bool mDoCapture{false}; RingBufferPtr mRing{nullptr}; @@ -1024,7 +1023,7 @@ void AlsaCapture::stop() /* The ring buffer implicitly captures when checking availability. * Direct access needs to explicitly capture it into temp storage. */ - auto temp = al::vector( + auto temp = al::vector( static_cast(snd_pcm_frames_to_bytes(mPcmHandle, avail))); captureSamples(temp.data(), avail); mBuffer = std::move(temp); @@ -1035,7 +1034,7 @@ void AlsaCapture::stop() mDoCapture = false; } -void AlsaCapture::captureSamples(al::byte *buffer, uint samples) +void AlsaCapture::captureSamples(std::byte *buffer, uint samples) { if(mRing) { @@ -1093,7 +1092,7 @@ void AlsaCapture::captureSamples(al::byte *buffer, uint samples) } if(samples > 0) std::fill_n(buffer, snd_pcm_frames_to_bytes(mPcmHandle, samples), - al::byte((mDevice->FmtType == DevFmtUByte) ? 0x80 : 0)); + std::byte((mDevice->FmtType == DevFmtUByte) ? 0x80 : 0)); } uint AlsaCapture::availableSamples() diff --git a/alc/backends/base.cpp b/alc/backends/base.cpp index 45254c47..ab3ad028 100644 --- a/alc/backends/base.cpp +++ b/alc/backends/base.cpp @@ -37,7 +37,7 @@ backend_exception::~backend_exception() = default; bool BackendBase::reset() { throw al::backend_exception{al::backend_error::DeviceError, "Invalid BackendBase call"}; } -void BackendBase::captureSamples(al::byte*, uint) +void BackendBase::captureSamples(std::byte*, uint) { } uint BackendBase::availableSamples() diff --git a/alc/backends/base.h b/alc/backends/base.h index b6b3d922..07b430e0 100644 --- a/alc/backends/base.h +++ b/alc/backends/base.h @@ -3,11 +3,11 @@ #include #include +#include #include #include #include -#include "albyte.h" #include "core/device.h" #include "core/except.h" @@ -26,7 +26,7 @@ struct BackendBase { virtual void start() = 0; virtual void stop() = 0; - virtual void captureSamples(al::byte *buffer, uint samples); + virtual void captureSamples(std::byte *buffer, uint samples); virtual uint availableSamples(); virtual ClockLatency getClockLatency(); diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index ae220d7a..19a1f753 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -568,7 +568,7 @@ struct CoreAudioCapture final : public BackendBase { void open(const char *name) override; void start() override; void stop() override; - void captureSamples(al::byte *buffer, uint samples) override; + void captureSamples(std::byte *buffer, uint samples) override; uint availableSamples() override; AudioUnit mAudioUnit{0}; @@ -598,7 +598,7 @@ OSStatus CoreAudioCapture::RecordProc(AudioUnitRenderActionFlags *ioActionFlags, AudioBufferList*) noexcept { union { - al::byte _[maxz(sizeof(AudioBufferList), offsetof(AudioBufferList, mBuffers[1]))]; + std::byte _[maxz(sizeof(AudioBufferList), offsetof(AudioBufferList, mBuffers[1]))]; AudioBufferList list; } audiobuf{}; @@ -878,7 +878,7 @@ void CoreAudioCapture::stop() ERR("AudioOutputUnitStop failed: '%s' (%u)\n", FourCCPrinter{err}.c_str(), err); } -void CoreAudioCapture::captureSamples(al::byte *buffer, uint samples) +void CoreAudioCapture::captureSamples(std::byte *buffer, uint samples) { if(!mConverter) { diff --git a/alc/backends/dsound.cpp b/alc/backends/dsound.cpp index 8b967c95..05117781 100644 --- a/alc/backends/dsound.cpp +++ b/alc/backends/dsound.cpp @@ -551,7 +551,7 @@ struct DSoundCapture final : public BackendBase { void open(const char *name) override; void start() override; void stop() override; - void captureSamples(al::byte *buffer, uint samples) override; + void captureSamples(std::byte *buffer, uint samples) override; uint availableSamples() override; ComPtr mDSC; @@ -717,7 +717,7 @@ void DSoundCapture::stop() } } -void DSoundCapture::captureSamples(al::byte *buffer, uint samples) +void DSoundCapture::captureSamples(std::byte *buffer, uint samples) { mRing->read(buffer, samples); } uint DSoundCapture::availableSamples() diff --git a/alc/backends/oboe.cpp b/alc/backends/oboe.cpp index 461f5a6a..4c47190e 100644 --- a/alc/backends/oboe.cpp +++ b/alc/backends/oboe.cpp @@ -215,7 +215,7 @@ struct OboeCapture final : public BackendBase, public oboe::AudioStreamCallback void open(const char *name) override; void start() override; void stop() override; - void captureSamples(al::byte *buffer, uint samples) override; + void captureSamples(std::byte *buffer, uint samples) override; uint availableSamples() override; }; @@ -322,7 +322,7 @@ void OboeCapture::stop() uint OboeCapture::availableSamples() { return static_cast(mRing->readSpace()); } -void OboeCapture::captureSamples(al::byte *buffer, uint samples) +void OboeCapture::captureSamples(std::byte *buffer, uint samples) { mRing->read(buffer, samples); } } // namespace diff --git a/alc/backends/opensl.cpp b/alc/backends/opensl.cpp index f5b98fb8..0c2936b2 100644 --- a/alc/backends/opensl.cpp +++ b/alc/backends/opensl.cpp @@ -648,7 +648,7 @@ struct OpenSLCapture final : public BackendBase { void open(const char *name) override; void start() override; void stop() override; - void captureSamples(al::byte *buffer, uint samples) override; + void captureSamples(std::byte *buffer, uint samples) override; uint availableSamples() override; /* engine interfaces */ @@ -819,7 +819,7 @@ void OpenSLCapture::open(const char* name) if(SL_RESULT_SUCCESS == result) { const uint chunk_size{mDevice->UpdateSize * mFrameSize}; - const auto silence = (mDevice->FmtType == DevFmtUByte) ? al::byte{0x80} : al::byte{0}; + const auto silence = (mDevice->FmtType == DevFmtUByte) ? std::byte{0x80} : std::byte{0}; auto data = mRing->getWriteVector(); std::fill_n(data.first.buf, data.first.len*chunk_size, silence); @@ -883,7 +883,7 @@ void OpenSLCapture::stop() } } -void OpenSLCapture::captureSamples(al::byte *buffer, uint samples) +void OpenSLCapture::captureSamples(std::byte *buffer, uint samples) { const uint update_size{mDevice->UpdateSize}; const uint chunk_size{update_size * mFrameSize}; diff --git a/alc/backends/oss.cpp b/alc/backends/oss.cpp index f76024f4..9e247be1 100644 --- a/alc/backends/oss.cpp +++ b/alc/backends/oss.cpp @@ -41,7 +41,6 @@ #include #include -#include "albyte.h" #include "alc/alconfig.h" #include "almalloc.h" #include "alnumeric.h" @@ -237,7 +236,7 @@ struct OSSPlayback final : public BackendBase { int mFd{-1}; - al::vector mMixData; + al::vector mMixData; std::atomic mKillNow{true}; std::thread mThread; @@ -283,7 +282,7 @@ int OSSPlayback::mixerProc() continue; } - al::byte *write_ptr{mMixData.data()}; + std::byte *write_ptr{mMixData.data()}; size_t to_write{mMixData.size()}; mDevice->renderSamples(write_ptr, static_cast(to_write/frame_size), frame_step); while(to_write > 0 && !mKillNow.load(std::memory_order_acquire)) @@ -449,7 +448,7 @@ struct OSScapture final : public BackendBase { void open(const char *name) override; void start() override; void stop() override; - void captureSamples(al::byte *buffer, uint samples) override; + void captureSamples(std::byte *buffer, uint samples) override; uint availableSamples() override; int mFd{-1}; @@ -619,7 +618,7 @@ void OSScapture::stop() ERR("Error resetting device: %s\n", strerror(errno)); } -void OSScapture::captureSamples(al::byte *buffer, uint samples) +void OSScapture::captureSamples(std::byte *buffer, uint samples) { mRing->read(buffer, samples); } uint OSScapture::availableSamples() diff --git a/alc/backends/pipewire.cpp b/alc/backends/pipewire.cpp index 5b1596aa..3f372a4a 100644 --- a/alc/backends/pipewire.cpp +++ b/alc/backends/pipewire.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -38,7 +39,6 @@ #include #include "albit.h" -#include "albyte.h" #include "alc/alconfig.h" #include "almalloc.h" #include "alnumeric.h" @@ -1528,7 +1528,7 @@ bool PipeWirePlayback::reset() * magic value. */ constexpr uint32_t pod_buffer_size{1024}; - auto pod_buffer = std::make_unique(pod_buffer_size); + auto pod_buffer = std::make_unique(pod_buffer_size); spa_pod_builder b{make_pod_builder(pod_buffer.get(), pod_buffer_size)}; const spa_pod *params{spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &info)}; @@ -1793,7 +1793,7 @@ class PipeWireCapture final : public BackendBase { void open(const char *name) override; void start() override; void stop() override; - void captureSamples(al::byte *buffer, uint samples) override; + void captureSamples(std::byte *buffer, uint samples) override; uint availableSamples() override; uint64_t mTargetId{PwIdAny}; @@ -1954,7 +1954,7 @@ void PipeWireCapture::open(const char *name) spa_audio_info_raw info{make_spa_info(mDevice, is51rear, UseDevType)}; constexpr uint32_t pod_buffer_size{1024}; - auto pod_buffer = std::make_unique(pod_buffer_size); + auto pod_buffer = std::make_unique(pod_buffer_size); spa_pod_builder b{make_pod_builder(pod_buffer.get(), pod_buffer_size)}; const spa_pod *params[]{spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &info)}; @@ -2055,7 +2055,7 @@ void PipeWireCapture::stop() uint PipeWireCapture::availableSamples() { return static_cast(mRing->readSpace()); } -void PipeWireCapture::captureSamples(al::byte *buffer, uint samples) +void PipeWireCapture::captureSamples(std::byte *buffer, uint samples) { mRing->read(buffer, samples); } } // namespace diff --git a/alc/backends/portaudio.cpp b/alc/backends/portaudio.cpp index d652d4cd..2551f448 100644 --- a/alc/backends/portaudio.cpp +++ b/alc/backends/portaudio.cpp @@ -248,7 +248,7 @@ struct PortCapture final : public BackendBase { void open(const char *name) override; void start() override; void stop() override; - void captureSamples(al::byte *buffer, uint samples) override; + void captureSamples(std::byte *buffer, uint samples) override; uint availableSamples() override; PaStream *mStream{nullptr}; @@ -349,7 +349,7 @@ void PortCapture::stop() uint PortCapture::availableSamples() { return static_cast(mRing->readSpace()); } -void PortCapture::captureSamples(al::byte *buffer, uint samples) +void PortCapture::captureSamples(std::byte *buffer, uint samples) { mRing->read(buffer, samples); } } // namespace diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index 6e8bfe1b..e5696817 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -39,7 +39,6 @@ #include #include "albit.h" -#include "albyte.h" #include "alc/alconfig.h" #include "almalloc.h" #include "alnumeric.h" @@ -1037,7 +1036,7 @@ struct PulseCapture final : public BackendBase { void open(const char *name) override; void start() override; void stop() override; - void captureSamples(al::byte *buffer, uint samples) override; + void captureSamples(std::byte *buffer, uint samples) override; uint availableSamples() override; ClockLatency getClockLatency() override; @@ -1045,12 +1044,12 @@ struct PulseCapture final : public BackendBase { std::optional mDeviceName{std::nullopt}; - al::span mCapBuffer; + al::span mCapBuffer; size_t mHoleLength{0}; size_t mPacketLength{0}; uint mLastReadable{0u}; - al::byte mSilentVal{}; + std::byte mSilentVal{}; pa_buffer_attr mAttr{}; pa_sample_spec mSpec{}; @@ -1159,7 +1158,7 @@ void PulseCapture::open(const char *name) switch(mDevice->FmtType) { case DevFmtUByte: - mSilentVal = al::byte(0x80); + mSilentVal = std::byte(0x80); mSpec.format = PA_SAMPLE_U8; break; case DevFmtShort: @@ -1231,9 +1230,9 @@ void PulseCapture::stop() plock.waitForOperation(op); } -void PulseCapture::captureSamples(al::byte *buffer, uint samples) +void PulseCapture::captureSamples(std::byte *buffer, uint samples) { - al::span dstbuf{buffer, samples * pa_frame_size(&mSpec)}; + al::span dstbuf{buffer, samples * pa_frame_size(&mSpec)}; /* Capture is done in fragment-sized chunks, so we loop until we get all * that's available. @@ -1291,7 +1290,7 @@ void PulseCapture::captureSamples(al::byte *buffer, uint samples) if(!capbuf) UNLIKELY mHoleLength = caplen; else - mCapBuffer = {static_cast(capbuf), caplen}; + mCapBuffer = {static_cast(capbuf), caplen}; mPacketLength = caplen; } if(!dstbuf.empty()) diff --git a/alc/backends/sndio.cpp b/alc/backends/sndio.cpp index 077e77f2..2040dd3a 100644 --- a/alc/backends/sndio.cpp +++ b/alc/backends/sndio.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include "alnumeric.h" #include "core/device.h" @@ -36,7 +37,6 @@ #include "core/logging.h" #include "ringbuffer.h" #include "threads.h" -#include "vector.h" #include @@ -65,7 +65,7 @@ struct SndioPlayback final : public BackendBase { sio_hdl *mSndHandle{nullptr}; uint mFrameStep{}; - al::vector mBuffer; + std::vector mBuffer; std::atomic mKillNow{true}; std::thread mThread; @@ -91,7 +91,7 @@ int SndioPlayback::mixerProc() while(!mKillNow.load(std::memory_order_acquire) && mDevice->Connected.load(std::memory_order_acquire)) { - al::span buffer{mBuffer}; + al::span buffer{mBuffer}; mDevice->renderSamples(buffer.data(), static_cast(buffer.size() / frameSize), frameStep); @@ -231,9 +231,9 @@ retry_params: mBuffer.resize(mDevice->UpdateSize * par.pchan*par.bps); if(par.sig == 1) - std::fill(mBuffer.begin(), mBuffer.end(), al::byte{}); + std::fill(mBuffer.begin(), mBuffer.end(), std::byte{}); else if(par.bits == 8) - std::fill_n(mBuffer.data(), mBuffer.size(), al::byte(0x80)); + std::fill_n(mBuffer.data(), mBuffer.size(), std::byte(0x80)); else if(par.bits == 16) std::fill_n(reinterpret_cast(mBuffer.data()), mBuffer.size()/2, 0x8000); else if(par.bits == 32) @@ -283,7 +283,7 @@ struct SndioCapture final : public BackendBase { void open(const char *name) override; void start() override; void stop() override; - void captureSamples(al::byte *buffer, uint samples) override; + void captureSamples(std::byte *buffer, uint samples) override; uint availableSamples() override; sio_hdl *mSndHandle{nullptr}; @@ -349,7 +349,7 @@ int SndioCapture::recordProc() continue; auto data = mRing->getWriteVector(); - al::span buffer{data.first.buf, data.first.len*frameSize}; + al::span buffer{data.first.buf, data.first.len*frameSize}; while(!buffer.empty()) { size_t got{sio_read(mSndHandle, buffer.data(), buffer.size())}; @@ -496,7 +496,7 @@ void SndioCapture::stop() ERR("Error stopping device\n"); } -void SndioCapture::captureSamples(al::byte *buffer, uint samples) +void SndioCapture::captureSamples(std::byte *buffer, uint samples) { mRing->read(buffer, samples); } uint SndioCapture::availableSamples() diff --git a/alc/backends/solaris.cpp b/alc/backends/solaris.cpp index 791609ce..4eeeafac 100644 --- a/alc/backends/solaris.cpp +++ b/alc/backends/solaris.cpp @@ -39,7 +39,6 @@ #include #include -#include "albyte.h" #include "alc/alconfig.h" #include "core/device.h" #include "core/helpers.h" @@ -71,7 +70,7 @@ struct SolarisBackend final : public BackendBase { int mFd{-1}; uint mFrameStep{}; - al::vector mBuffer; + al::vector mBuffer; std::atomic mKillNow{true}; std::thread mThread; @@ -116,7 +115,7 @@ int SolarisBackend::mixerProc() continue; } - al::byte *write_ptr{mBuffer.data()}; + std::byte *write_ptr{mBuffer.data()}; size_t to_write{mBuffer.size()}; mDevice->renderSamples(write_ptr, static_cast(to_write/frame_size), frame_step); while(to_write > 0 && !mKillNow.load(std::memory_order_acquire)) @@ -231,7 +230,7 @@ bool SolarisBackend::reset() setDefaultChannelOrder(); mBuffer.resize(mDevice->UpdateSize * size_t{frame_size}); - std::fill(mBuffer.begin(), mBuffer.end(), al::byte{}); + std::fill(mBuffer.begin(), mBuffer.end(), std::byte{}); return true; } diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index ea6ecbe0..16576733 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -1309,7 +1309,7 @@ struct WasapiCapture final : public BackendBase, WasapiProxy { void stop() override; void stopProxy() override; - void captureSamples(al::byte *buffer, uint samples) override; + void captureSamples(std::byte *buffer, uint samples) override; uint availableSamples() override; HRESULT mOpenStatus{E_FAIL}; @@ -1881,7 +1881,7 @@ void WasapiCapture::stopProxy() } -void WasapiCapture::captureSamples(al::byte *buffer, uint samples) +void WasapiCapture::captureSamples(std::byte *buffer, uint samples) { mRing->read(buffer, samples); } uint WasapiCapture::availableSamples() diff --git a/alc/backends/wave.cpp b/alc/backends/wave.cpp index 1b40640c..f8302f1e 100644 --- a/alc/backends/wave.cpp +++ b/alc/backends/wave.cpp @@ -34,7 +34,6 @@ #include #include "albit.h" -#include "albyte.h" #include "alc/alconfig.h" #include "almalloc.h" #include "alnumeric.h" @@ -105,7 +104,7 @@ struct WaveBackend final : public BackendBase { FILE *mFile{nullptr}; long mDataStart{-1}; - al::vector mBuffer; + al::vector mBuffer; std::atomic mKillNow{true}; std::thread mThread; diff --git a/alc/backends/winmm.cpp b/alc/backends/winmm.cpp index 38e1193f..135b59df 100644 --- a/alc/backends/winmm.cpp +++ b/alc/backends/winmm.cpp @@ -372,7 +372,7 @@ struct WinMMCapture final : public BackendBase { void open(const char *name) override; void start() override; void stop() override; - void captureSamples(al::byte *buffer, uint samples) override; + void captureSamples(std::byte *buffer, uint samples) override; uint availableSamples() override; std::atomic mReadable{0u}; @@ -571,7 +571,7 @@ void WinMMCapture::stop() mIdx = 0; } -void WinMMCapture::captureSamples(al::byte *buffer, uint samples) +void WinMMCapture::captureSamples(std::byte *buffer, uint samples) { mRing->read(buffer, samples); } uint WinMMCapture::availableSamples() diff --git a/alc/effects/convolution.cpp b/alc/effects/convolution.cpp index 7f36c415..4ca31246 100644 --- a/alc/effects/convolution.cpp +++ b/alc/effects/convolution.cpp @@ -17,7 +17,6 @@ #include #endif -#include "albyte.h" #include "alcomplex.h" #include "almalloc.h" #include "alnumbers.h" @@ -72,7 +71,7 @@ namespace { */ -void LoadSamples(float *RESTRICT dst, const al::byte *src, const size_t srcstep, FmtType srctype, +void LoadSamples(float *RESTRICT dst, const std::byte *src, const size_t srcstep, FmtType srctype, const size_t samples) noexcept { #define HANDLE_FMT(T) case T: al::LoadSampleArray(dst, src, srcstep, samples); break diff --git a/common/albyte.h b/common/albyte.h deleted file mode 100644 index be586869..00000000 --- a/common/albyte.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef AL_BYTE_H -#define AL_BYTE_H - -#include -#include -#include -#include - -using uint = unsigned int; - -namespace al { - -using byte = unsigned char; - -} // namespace al - -#endif /* AL_BYTE_H */ diff --git a/common/ringbuffer.cpp b/common/ringbuffer.cpp index 0aec1d49..af1f3669 100644 --- a/common/ringbuffer.cpp +++ b/common/ringbuffer.cpp @@ -29,9 +29,9 @@ #include "almalloc.h" -RingBufferPtr RingBuffer::Create(size_t sz, size_t elem_sz, int limit_writes) +RingBufferPtr RingBuffer::Create(std::size_t sz, std::size_t elem_sz, int limit_writes) { - size_t power_of_two{0u}; + std::size_t power_of_two{0u}; if(sz > 0) { power_of_two = sz; @@ -40,15 +40,14 @@ RingBufferPtr RingBuffer::Create(size_t sz, size_t elem_sz, int limit_writes) power_of_two |= power_of_two>>4; power_of_two |= power_of_two>>8; power_of_two |= power_of_two>>16; -#if SIZE_MAX > UINT_MAX - power_of_two |= power_of_two>>32; -#endif + if constexpr(SIZE_MAX > UINT_MAX) + power_of_two |= power_of_two>>32; } ++power_of_two; - if(power_of_two <= sz || power_of_two > std::numeric_limits::max()/elem_sz) + if(power_of_two <= sz || power_of_two > std::numeric_limits::max()/elem_sz) throw std::overflow_error{"Ring buffer size overflow"}; - const size_t bufbytes{power_of_two * elem_sz}; + const std::size_t bufbytes{power_of_two * elem_sz}; RingBufferPtr rb{new(FamCount(bufbytes)) RingBuffer{bufbytes}}; rb->mWriteSize = limit_writes ? sz : (power_of_two-1); rb->mSizeMask = power_of_two - 1; @@ -61,20 +60,20 @@ void RingBuffer::reset() noexcept { mWritePtr.store(0, std::memory_order_relaxed); mReadPtr.store(0, std::memory_order_relaxed); - std::fill_n(mBuffer.begin(), (mSizeMask+1)*mElemSize, al::byte{}); + std::fill_n(mBuffer.begin(), (mSizeMask+1)*mElemSize, std::byte{}); } -size_t RingBuffer::read(void *dest, size_t cnt) noexcept +std::size_t RingBuffer::read(void *dest, std::size_t cnt) noexcept { - const size_t free_cnt{readSpace()}; + const std::size_t free_cnt{readSpace()}; if(free_cnt == 0) return 0; - const size_t to_read{std::min(cnt, free_cnt)}; - size_t read_ptr{mReadPtr.load(std::memory_order_relaxed) & mSizeMask}; + const std::size_t to_read{std::min(cnt, free_cnt)}; + std::size_t read_ptr{mReadPtr.load(std::memory_order_relaxed) & mSizeMask}; - size_t n1, n2; - const size_t cnt2{read_ptr + to_read}; + std::size_t n1, n2; + const std::size_t cnt2{read_ptr + to_read}; if(cnt2 > mSizeMask+1) { n1 = mSizeMask+1 - read_ptr; @@ -87,7 +86,7 @@ size_t RingBuffer::read(void *dest, size_t cnt) noexcept } auto outiter = std::copy_n(mBuffer.begin() + read_ptr*mElemSize, n1*mElemSize, - static_cast(dest)); + static_cast(dest)); read_ptr += n1; if(n2 > 0) { @@ -98,16 +97,16 @@ size_t RingBuffer::read(void *dest, size_t cnt) noexcept return to_read; } -size_t RingBuffer::peek(void *dest, size_t cnt) const noexcept +std::size_t RingBuffer::peek(void *dest, std::size_t cnt) const noexcept { - const size_t free_cnt{readSpace()}; + const std::size_t free_cnt{readSpace()}; if(free_cnt == 0) return 0; - const size_t to_read{std::min(cnt, free_cnt)}; - size_t read_ptr{mReadPtr.load(std::memory_order_relaxed) & mSizeMask}; + const std::size_t to_read{std::min(cnt, free_cnt)}; + std::size_t read_ptr{mReadPtr.load(std::memory_order_relaxed) & mSizeMask}; - size_t n1, n2; - const size_t cnt2{read_ptr + to_read}; + std::size_t n1, n2; + const std::size_t cnt2{read_ptr + to_read}; if(cnt2 > mSizeMask+1) { n1 = mSizeMask+1 - read_ptr; @@ -120,22 +119,22 @@ size_t RingBuffer::peek(void *dest, size_t cnt) const noexcept } auto outiter = std::copy_n(mBuffer.begin() + read_ptr*mElemSize, n1*mElemSize, - static_cast(dest)); + static_cast(dest)); if(n2 > 0) std::copy_n(mBuffer.begin(), n2*mElemSize, outiter); return to_read; } -size_t RingBuffer::write(const void *src, size_t cnt) noexcept +std::size_t RingBuffer::write(const void *src, std::size_t cnt) noexcept { - const size_t free_cnt{writeSpace()}; + const std::size_t free_cnt{writeSpace()}; if(free_cnt == 0) return 0; - const size_t to_write{std::min(cnt, free_cnt)}; - size_t write_ptr{mWritePtr.load(std::memory_order_relaxed) & mSizeMask}; + const std::size_t to_write{std::min(cnt, free_cnt)}; + std::size_t write_ptr{mWritePtr.load(std::memory_order_relaxed) & mSizeMask}; - size_t n1, n2; - const size_t cnt2{write_ptr + to_write}; + std::size_t n1, n2; + const std::size_t cnt2{write_ptr + to_write}; if(cnt2 > mSizeMask+1) { n1 = mSizeMask+1 - write_ptr; @@ -147,7 +146,7 @@ size_t RingBuffer::write(const void *src, size_t cnt) noexcept n2 = 0; } - auto srcbytes = static_cast(src); + auto srcbytes = static_cast(src); std::copy_n(srcbytes, n1*mElemSize, mBuffer.begin() + write_ptr*mElemSize); write_ptr += n1; if(n2 > 0) @@ -164,26 +163,26 @@ auto RingBuffer::getReadVector() const noexcept -> DataPair { DataPair ret; - size_t w{mWritePtr.load(std::memory_order_acquire)}; - size_t r{mReadPtr.load(std::memory_order_acquire)}; + std::size_t w{mWritePtr.load(std::memory_order_acquire)}; + std::size_t r{mReadPtr.load(std::memory_order_acquire)}; w &= mSizeMask; r &= mSizeMask; - const size_t free_cnt{(w-r) & mSizeMask}; + const std::size_t free_cnt{(w-r) & mSizeMask}; - const size_t cnt2{r + free_cnt}; + const std::size_t cnt2{r + free_cnt}; if(cnt2 > mSizeMask+1) { /* Two part vector: the rest of the buffer after the current read ptr, * plus some from the start of the buffer. */ - ret.first.buf = const_cast(mBuffer.data() + r*mElemSize); + ret.first.buf = const_cast(mBuffer.data() + r*mElemSize); ret.first.len = mSizeMask+1 - r; - ret.second.buf = const_cast(mBuffer.data()); + ret.second.buf = const_cast(mBuffer.data()); ret.second.len = cnt2 & mSizeMask; } else { /* Single part vector: just the rest of the buffer */ - ret.first.buf = const_cast(mBuffer.data() + r*mElemSize); + ret.first.buf = const_cast(mBuffer.data() + r*mElemSize); ret.first.len = free_cnt; ret.second.buf = nullptr; ret.second.len = 0; @@ -196,25 +195,25 @@ auto RingBuffer::getWriteVector() const noexcept -> DataPair { DataPair ret; - size_t w{mWritePtr.load(std::memory_order_acquire)}; - size_t r{mReadPtr.load(std::memory_order_acquire) + mWriteSize - mSizeMask}; + std::size_t w{mWritePtr.load(std::memory_order_acquire)}; + std::size_t r{mReadPtr.load(std::memory_order_acquire) + mWriteSize - mSizeMask}; w &= mSizeMask; r &= mSizeMask; - const size_t free_cnt{(r-w-1) & mSizeMask}; + const std::size_t free_cnt{(r-w-1) & mSizeMask}; - const size_t cnt2{w + free_cnt}; + const std::size_t cnt2{w + free_cnt}; if(cnt2 > mSizeMask+1) { /* Two part vector: the rest of the buffer after the current write ptr, * plus some from the start of the buffer. */ - ret.first.buf = const_cast(mBuffer.data() + w*mElemSize); + ret.first.buf = const_cast(mBuffer.data() + w*mElemSize); ret.first.len = mSizeMask+1 - w; - ret.second.buf = const_cast(mBuffer.data()); + ret.second.buf = const_cast(mBuffer.data()); ret.second.len = cnt2 & mSizeMask; } else { - ret.first.buf = const_cast(mBuffer.data() + w*mElemSize); + ret.first.buf = const_cast(mBuffer.data() + w*mElemSize); ret.first.len = free_cnt; ret.second.buf = nullptr; ret.second.len = 0; diff --git a/common/ringbuffer.h b/common/ringbuffer.h index 2a3797b0..8c65c3af 100644 --- a/common/ringbuffer.h +++ b/common/ringbuffer.h @@ -2,11 +2,10 @@ #define RINGBUFFER_H #include +#include #include -#include #include -#include "albyte.h" #include "almalloc.h" @@ -18,23 +17,23 @@ struct RingBuffer { private: - std::atomic mWritePtr{0u}; - std::atomic mReadPtr{0u}; - size_t mWriteSize{0u}; - size_t mSizeMask{0u}; - size_t mElemSize{0u}; + std::atomic mWritePtr{0u}; + std::atomic mReadPtr{0u}; + std::size_t mWriteSize{0u}; + std::size_t mSizeMask{0u}; + std::size_t mElemSize{0u}; - al::FlexArray mBuffer; + al::FlexArray mBuffer; public: struct Data { - al::byte *buf; - size_t len; + std::byte *buf; + std::size_t len; }; using DataPair = std::pair; - RingBuffer(const size_t count) : mBuffer{count} { } + RingBuffer(const std::size_t count) : mBuffer{count} { } /** Reset the read and write pointers to zero. This is not thread safe. */ void reset() noexcept; @@ -56,7 +55,7 @@ public: * Return the number of elements available for reading. This is the number * of elements in front of the read pointer and behind the write pointer. */ - size_t readSpace() const noexcept + std::size_t readSpace() const noexcept { const size_t w{mWritePtr.load(std::memory_order_acquire)}; const size_t r{mReadPtr.load(std::memory_order_acquire)}; @@ -67,14 +66,14 @@ public: * The copying data reader. Copy at most `cnt' elements into `dest'. * Returns the actual number of elements copied. */ - size_t read(void *dest, size_t cnt) noexcept; + std::size_t read(void *dest, std::size_t cnt) noexcept; /** * The copying data reader w/o read pointer advance. Copy at most `cnt' * elements into `dest'. Returns the actual number of elements copied. */ - size_t peek(void *dest, size_t cnt) const noexcept; + std::size_t peek(void *dest, std::size_t cnt) const noexcept; /** Advance the read pointer `cnt' places. */ - void readAdvance(size_t cnt) noexcept + void readAdvance(std::size_t cnt) noexcept { mReadPtr.fetch_add(cnt, std::memory_order_acq_rel); } @@ -82,7 +81,7 @@ public: * Return the number of elements available for writing. This is the number * of elements in front of the write pointer and behind the read pointer. */ - size_t writeSpace() const noexcept + std::size_t writeSpace() const noexcept { const size_t w{mWritePtr.load(std::memory_order_acquire)}; const size_t r{mReadPtr.load(std::memory_order_acquire) + mWriteSize - mSizeMask}; @@ -93,12 +92,12 @@ public: * The copying data writer. Copy at most `cnt' elements from `src'. Returns * the actual number of elements copied. */ - size_t write(const void *src, size_t cnt) noexcept; + std::size_t write(const void *src, std::size_t cnt) noexcept; /** Advance the write pointer `cnt' places. */ - void writeAdvance(size_t cnt) noexcept + void writeAdvance(std::size_t cnt) noexcept { mWritePtr.fetch_add(cnt, std::memory_order_acq_rel); } - size_t getElemSize() const noexcept { return mElemSize; } + std::size_t getElemSize() const noexcept { return mElemSize; } /** * Create a new ringbuffer to hold at least `sz' elements of `elem_sz' @@ -106,7 +105,7 @@ public: * (even if it is already a power of two, to ensure the requested amount * can be written). */ - static std::unique_ptr Create(size_t sz, size_t elem_sz, int limit_writes); + static std::unique_ptr Create(std::size_t sz, std::size_t elem_sz, int limit_writes); DEF_FAM_NEWDEL(RingBuffer, mBuffer) }; diff --git a/core/buffer_storage.h b/core/buffer_storage.h index 282d5b53..d8ab0b67 100644 --- a/core/buffer_storage.h +++ b/core/buffer_storage.h @@ -2,8 +2,8 @@ #define CORE_BUFFER_STORAGE_H #include +#include -#include "albyte.h" #include "alnumeric.h" #include "alspan.h" #include "ambidefs.h" @@ -85,7 +85,7 @@ struct BufferStorage { CallbackType mCallback{nullptr}; void *mUserData{nullptr}; - al::span mData; + al::span mData; uint mSampleRate{0u}; FmtChannels mChannels{FmtMono}; diff --git a/core/converter.cpp b/core/converter.cpp index a5141448..b3994d3f 100644 --- a/core/converter.cpp +++ b/core/converter.cpp @@ -6,12 +6,12 @@ #include #include #include +#include #include #include #include #include "albit.h" -#include "albyte.h" #include "alnumeric.h" #include "fpu_ctrl.h" @@ -219,7 +219,7 @@ uint SampleConverter::convert(const void **src, uint *srcframes, void *dst, uint const uint SrcFrameSize{static_cast(mChan.size()) * mSrcTypeSize}; const uint DstFrameSize{static_cast(mChan.size()) * mDstTypeSize}; const uint increment{mIncrement}; - auto SamplesIn = static_cast(*src); + auto SamplesIn = static_cast(*src); uint NumSrcSamples{*srcframes}; FPUCtl mixer_mode{}; @@ -265,8 +265,8 @@ uint SampleConverter::convert(const void **src, uint *srcframes, void *dst, uint for(size_t chan{0u};chan < mChan.size();chan++) { - const al::byte *SrcSamples{SamplesIn + mSrcTypeSize*chan}; - al::byte *DstSamples = static_cast(dst) + mDstTypeSize*chan; + const std::byte *SrcSamples{SamplesIn + mSrcTypeSize*chan}; + std::byte *DstSamples = static_cast(dst) + mDstTypeSize*chan; /* Load the previous samples into the source data first, then the * new samples from the input buffer. @@ -299,7 +299,7 @@ uint SampleConverter::convert(const void **src, uint *srcframes, void *dst, uint SamplesIn += SrcFrameSize*srcread; NumSrcSamples -= srcread; - dst = static_cast(dst) + DstFrameSize*DstSize; + dst = static_cast(dst) + DstFrameSize*DstSize; pos += DstSize; } diff --git a/core/effects/base.h b/core/effects/base.h index 4ee19f37..b02d33b7 100644 --- a/core/effects/base.h +++ b/core/effects/base.h @@ -3,7 +3,6 @@ #include -#include "albyte.h" #include "almalloc.h" #include "alspan.h" #include "atomic.h" diff --git a/core/fmt_traits.h b/core/fmt_traits.h index f797f836..1879c81b 100644 --- a/core/fmt_traits.h +++ b/core/fmt_traits.h @@ -1,10 +1,9 @@ #ifndef CORE_FMT_TRAITS_H #define CORE_FMT_TRAITS_H -#include +#include #include -#include "albyte.h" #include "buffer_storage.h" @@ -22,36 +21,35 @@ struct FmtTypeTraits { using Type = uint8_t; template - static constexpr inline OutT to(const Type val) noexcept - { return val*OutT{1.0/128.0} - OutT{1.0}; } + static constexpr OutT to(const Type val) noexcept { return val*OutT{1.0/128.0} - OutT{1.0}; } }; template<> struct FmtTypeTraits { using Type = int16_t; template - static constexpr inline OutT to(const Type val) noexcept { return val*OutT{1.0/32768.0}; } + static constexpr OutT to(const Type val) noexcept { return val*OutT{1.0/32768.0}; } }; template<> struct FmtTypeTraits { using Type = float; template - static constexpr inline OutT to(const Type val) noexcept { return val; } + static constexpr OutT to(const Type val) noexcept { return val; } }; template<> struct FmtTypeTraits { using Type = double; template - static constexpr inline OutT to(const Type val) noexcept { return static_cast(val); } + static constexpr OutT to(const Type val) noexcept { return static_cast(val); } }; template<> struct FmtTypeTraits { using Type = uint8_t; template - static constexpr inline OutT to(const Type val) noexcept + static constexpr OutT to(const Type val) noexcept { return muLawDecompressionTable[val] * OutT{1.0/32768.0}; } }; template<> @@ -59,14 +57,14 @@ struct FmtTypeTraits { using Type = uint8_t; template - static constexpr inline OutT to(const Type val) noexcept + static constexpr OutT to(const Type val) noexcept { return aLawDecompressionTable[val] * OutT{1.0/32768.0}; } }; template -inline void LoadSampleArray(DstT *RESTRICT dst, const al::byte *src, const size_t srcstep, - const size_t samples) noexcept +inline void LoadSampleArray(DstT *RESTRICT dst, const std::byte *src, const std::size_t srcstep, + const std::size_t samples) noexcept { using TypeTraits = FmtTypeTraits; using SampleType = typename TypeTraits::Type; diff --git a/core/hrtf.cpp b/core/hrtf.cpp index c54d96d1..1d9bc368 100644 --- a/core/hrtf.cpp +++ b/core/hrtf.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -21,7 +22,6 @@ #include #include "albit.h" -#include "albyte.h" #include "alfstream.h" #include "almalloc.h" #include "alnumbers.h" @@ -492,10 +492,10 @@ T> readle(std::istream &data) static_assert(num_bits <= sizeof(T)*8, "num_bits is too large for the type"); T ret{}; - al::byte b[sizeof(T)]{}; + std::byte b[sizeof(T)]{}; if(!data.read(reinterpret_cast(b), num_bits/8)) return static_cast(EOF); - std::reverse_copy(std::begin(b), std::end(b), reinterpret_cast(&ret)); + std::reverse_copy(std::begin(b), std::end(b), reinterpret_cast(&ret)); return fixsign(ret); } diff --git a/core/voice.cpp b/core/voice.cpp index 090b10a3..cbf84c2a 100644 --- a/core/voice.cpp +++ b/core/voice.cpp @@ -17,7 +17,6 @@ #include #include -#include "albyte.h" #include "alnumeric.h" #include "alspan.h" #include "alstring.h" @@ -264,7 +263,7 @@ const float *DoFilters(BiquadFilter &lpfilter, BiquadFilter &hpfilter, float *ds template -inline void LoadSamples(float *RESTRICT dstSamples, const al::byte *src, const size_t srcChan, +inline void LoadSamples(float *RESTRICT dstSamples, const std::byte *src, const size_t srcChan, const size_t srcOffset, const size_t srcStep, const size_t /*samplesPerBlock*/, const size_t samplesToLoad) noexcept { @@ -275,7 +274,7 @@ inline void LoadSamples(float *RESTRICT dstSamples, const al::byte *src, const s } template<> -inline void LoadSamples(float *RESTRICT dstSamples, const al::byte *src, +inline void LoadSamples(float *RESTRICT dstSamples, const std::byte *src, const size_t srcChan, const size_t srcOffset, const size_t srcStep, const size_t samplesPerBlock, const size_t samplesToLoad) noexcept { @@ -293,8 +292,8 @@ inline void LoadSamples(float *RESTRICT dstSamples, const al::byte *src /* Each IMA4 block starts with a signed 16-bit sample, and a signed * 16-bit table index. The table index needs to be clamped. */ - int sample{src[srcChan*4] | (src[srcChan*4 + 1] << 8)}; - int index{src[srcChan*4 + 2] | (src[srcChan*4 + 3] << 8)}; + int sample{int(src[srcChan*4]) | (int(src[srcChan*4 + 1]) << 8)}; + int index{int(src[srcChan*4 + 2]) | (int(src[srcChan*4 + 3]) << 8)}; sample = (sample^0x8000) - 32768; index = clampi((index^0x8000) - 32768, 0, MaxStepIndex); @@ -326,7 +325,7 @@ inline void LoadSamples(float *RESTRICT dstSamples, const al::byte *src * always be less than the block size). They need to be decoded despite * being ignored for proper state on the remaining samples. */ - const al::byte *nibbleData{src + (srcStep+srcChan)*4}; + const std::byte *nibbleData{src + (srcStep+srcChan)*4}; size_t nibbleOffset{0}; const size_t startOffset{skip + 1}; for(;skip;--skip) @@ -336,7 +335,7 @@ inline void LoadSamples(float *RESTRICT dstSamples, const al::byte *src const size_t byteOffset{wordOffset*srcStep + ((nibbleOffset>>1)&3u)}; ++nibbleOffset; - std::ignore = decode_sample((nibbleData[byteOffset]>>byteShift) & 15u); + std::ignore = decode_sample(uint(nibbleData[byteOffset]>>byteShift) & 15u); } /* Second, decode the rest of the block and write to the output, until @@ -350,7 +349,7 @@ inline void LoadSamples(float *RESTRICT dstSamples, const al::byte *src const size_t byteOffset{wordOffset*srcStep + ((nibbleOffset>>1)&3u)}; ++nibbleOffset; - const int result{decode_sample((nibbleData[byteOffset]>>byteShift) & 15u)}; + const int result{decode_sample(uint(nibbleData[byteOffset]>>byteShift) & 15u)}; dstSamples[wrote++] = static_cast(result) / 32768.0f; } if(wrote == samplesToLoad) @@ -361,7 +360,7 @@ inline void LoadSamples(float *RESTRICT dstSamples, const al::byte *src } template<> -inline void LoadSamples(float *RESTRICT dstSamples, const al::byte *src, +inline void LoadSamples(float *RESTRICT dstSamples, const std::byte *src, const size_t srcChan, const size_t srcOffset, const size_t srcStep, const size_t samplesPerBlock, const size_t samplesToLoad) noexcept { @@ -378,16 +377,16 @@ inline void LoadSamples(float *RESTRICT dstSamples, const al::byte * * nibble sample value. This is followed by the two initial 16-bit * sample history values. */ - const al::byte *input{src}; - const uint8_t blockpred{std::min(input[srcChan], uint8_t{6})}; + const std::byte *input{src}; + const uint8_t blockpred{std::min(uint8_t(input[srcChan]), uint8_t{6})}; input += srcStep; - int delta{input[2*srcChan + 0] | (input[2*srcChan + 1] << 8)}; + int delta{int(input[2*srcChan + 0]) | (int(input[2*srcChan + 1]) << 8)}; input += srcStep*2; int sampleHistory[2]{}; - sampleHistory[0] = input[2*srcChan + 0] | (input[2*srcChan + 1]<<8); + sampleHistory[0] = int(input[2*srcChan + 0]) | (int(input[2*srcChan + 1])<<8); input += srcStep*2; - sampleHistory[1] = input[2*srcChan + 0] | (input[2*srcChan + 1]<<8); + sampleHistory[1] = int(input[2*srcChan + 0]) | (int(input[2*srcChan + 1])<<8); input += srcStep*2; const auto coeffs = al::as_span(MSADPCMAdaptionCoeff[blockpred]); @@ -440,7 +439,7 @@ inline void LoadSamples(float *RESTRICT dstSamples, const al::byte * const size_t byteShift{((nibbleOffset&1)^1) * 4}; nibbleOffset += srcStep; - std::ignore = decode_sample((input[byteOffset]>>byteShift) & 15); + std::ignore = decode_sample(int(input[byteOffset]>>byteShift) & 15); } /* Now decode the rest of the block, until the end of the block or the @@ -453,7 +452,7 @@ inline void LoadSamples(float *RESTRICT dstSamples, const al::byte * const size_t byteShift{((nibbleOffset&1)^1) * 4}; nibbleOffset += srcStep; - const int sample{decode_sample((input[byteOffset]>>byteShift) & 15)}; + const int sample{decode_sample(int(input[byteOffset]>>byteShift) & 15)}; dstSamples[wrote++] = static_cast(sample) / 32768.0f; } if(wrote == samplesToLoad) @@ -463,7 +462,7 @@ inline void LoadSamples(float *RESTRICT dstSamples, const al::byte * } while(true); } -void LoadSamples(float *dstSamples, const al::byte *src, const size_t srcChan, +void LoadSamples(float *dstSamples, const std::byte *src, const size_t srcChan, const size_t srcOffset, const FmtType srcType, const size_t srcStep, const size_t samplesPerBlock, const size_t samplesToLoad) noexcept { @@ -1102,7 +1101,7 @@ void Voice::mix(const State vstate, ContextBase *Context, const nanoseconds devi { const size_t byteOffset{blocksDone*mBytesPerBlock}; const size_t byteEnd{mNumCallbackBlocks*mBytesPerBlock}; - al::byte *data{BufferListItem->mSamples}; + std::byte *data{BufferListItem->mSamples}; std::copy(data+byteOffset, data+byteEnd, data); mNumCallbackBlocks -= blocksDone; mCallbackBlockBase += blocksDone; diff --git a/core/voice.h b/core/voice.h index 9d74ff6b..a599eda8 100644 --- a/core/voice.h +++ b/core/voice.h @@ -5,12 +5,11 @@ #include #include #include +#include #include #include -#include #include -#include "albyte.h" #include "almalloc.h" #include "alspan.h" #include "bufferline.h" @@ -100,7 +99,7 @@ struct VoiceBufferItem { uint mLoopStart{0u}; uint mLoopEnd{0u}; - al::byte *mSamples{nullptr}; + std::byte *mSamples{nullptr}; }; diff --git a/utils/uhjdecoder.cpp b/utils/uhjdecoder.cpp index 6d992e30..c7efa376 100644 --- a/utils/uhjdecoder.cpp +++ b/utils/uhjdecoder.cpp @@ -26,15 +26,14 @@ #include #include +#include #include #include -#include #include #include #include #include "albit.h" -#include "albyte.h" #include "alcomplex.h" #include "almalloc.h" #include "alnumbers.h" @@ -64,7 +63,7 @@ using ushort = unsigned short; using uint = unsigned int; using complex_d = std::complex; -using byte4 = std::array; +using byte4 = std::array; constexpr ubyte SUBTYPE_BFORMAT_FLOAT[]{ @@ -113,7 +112,7 @@ using FloatBufferSpan = al::span; struct UhjDecoder { - constexpr static size_t sFilterDelay{1024}; + constexpr static std::size_t sFilterDelay{1024}; alignas(16) std::array mS{}; alignas(16) std::array mD{}; @@ -126,10 +125,10 @@ struct UhjDecoder { alignas(16) std::array mTemp{}; - void decode(const float *RESTRICT InSamples, const size_t InChannels, - const al::span OutSamples, const size_t SamplesToDo); + void decode(const float *RESTRICT InSamples, const std::size_t InChannels, + const al::span OutSamples, const std::size_t SamplesToDo); void decode2(const float *RESTRICT InSamples, const al::span OutSamples, - const size_t SamplesToDo); + const std::size_t SamplesToDo); DEF_NEWDEL(UhjDecoder) }; @@ -210,8 +209,8 @@ const PhaseShifterT PShift{}; * * Not halving produces a result matching the original input. */ -void UhjDecoder::decode(const float *RESTRICT InSamples, const size_t InChannels, - const al::span OutSamples, const size_t SamplesToDo) +void UhjDecoder::decode(const float *RESTRICT InSamples, const std::size_t InChannels, + const al::span OutSamples, const std::size_t SamplesToDo) { ASSUME(SamplesToDo > 0); @@ -224,23 +223,23 @@ void UhjDecoder::decode(const float *RESTRICT InSamples, const size_t InChannels */ /* S = Left + Right */ - for(size_t i{0};i < SamplesToDo;++i) + for(std::size_t i{0};i < SamplesToDo;++i) mS[sFilterDelay+i] = InSamples[i*InChannels + 0] + InSamples[i*InChannels + 1]; /* D = Left - Right */ - for(size_t i{0};i < SamplesToDo;++i) + for(std::size_t i{0};i < SamplesToDo;++i) mD[sFilterDelay+i] = InSamples[i*InChannels + 0] - InSamples[i*InChannels + 1]; if(InChannels > 2) { /* T */ - for(size_t i{0};i < SamplesToDo;++i) + for(std::size_t i{0};i < SamplesToDo;++i) mT[sFilterDelay+i] = InSamples[i*InChannels + 2]; } if(InChannels > 3) { /* Q */ - for(size_t i{0};i < SamplesToDo;++i) + for(std::size_t i{0};i < SamplesToDo;++i) mQ[sFilterDelay+i] = InSamples[i*InChannels + 3]; } @@ -251,7 +250,7 @@ void UhjDecoder::decode(const float *RESTRICT InSamples, const size_t InChannels std::copy_n(mTemp.cbegin()+SamplesToDo, mDTHistory.size(), mDTHistory.begin()); PShift.process({xoutput, SamplesToDo}, mTemp.data()); - for(size_t i{0};i < SamplesToDo;++i) + for(std::size_t i{0};i < SamplesToDo;++i) { /* W = 0.981532*S + 0.197484*j(0.828331*D + 0.767820*T) */ woutput[i] = 0.981532f*mS[i] + 0.197484f*xoutput[i]; @@ -265,7 +264,7 @@ void UhjDecoder::decode(const float *RESTRICT InSamples, const size_t InChannels std::copy_n(mTemp.cbegin()+SamplesToDo, mSHistory.size(), mSHistory.begin()); PShift.process({youtput, SamplesToDo}, mTemp.data()); - for(size_t i{0};i < SamplesToDo;++i) + for(std::size_t i{0};i < SamplesToDo;++i) { /* Y = 0.795968*D - 0.676392*T + j(0.186633*S) */ youtput[i] = 0.795968f*mD[i] - 0.676392f*mT[i] + 0.186633f*youtput[i]; @@ -275,7 +274,7 @@ void UhjDecoder::decode(const float *RESTRICT InSamples, const size_t InChannels { float *zoutput{OutSamples[3].data()}; /* Z = 1.023332*Q */ - for(size_t i{0};i < SamplesToDo;++i) + for(std::size_t i{0};i < SamplesToDo;++i) zoutput[i] = 1.023332f*mQ[i]; } @@ -305,7 +304,7 @@ void UhjDecoder::decode(const float *RESTRICT InSamples, const size_t InChannels * halving here is merely a -6dB reduction in output, but it's still incorrect. */ void UhjDecoder::decode2(const float *RESTRICT InSamples, - const al::span OutSamples, const size_t SamplesToDo) + const al::span OutSamples, const std::size_t SamplesToDo) { ASSUME(SamplesToDo > 0); @@ -314,11 +313,11 @@ void UhjDecoder::decode2(const float *RESTRICT InSamples, float *youtput{OutSamples[2].data()}; /* S = Left + Right */ - for(size_t i{0};i < SamplesToDo;++i) + for(std::size_t i{0};i < SamplesToDo;++i) mS[sFilterDelay+i] = InSamples[i*2 + 0] + InSamples[i*2 + 1]; /* D = Left - Right */ - for(size_t i{0};i < SamplesToDo;++i) + for(std::size_t i{0};i < SamplesToDo;++i) mD[sFilterDelay+i] = InSamples[i*2 + 0] - InSamples[i*2 + 1]; /* Precompute j*D and store in xoutput. */ @@ -327,7 +326,7 @@ void UhjDecoder::decode2(const float *RESTRICT InSamples, std::copy_n(mTemp.cbegin()+SamplesToDo, mDTHistory.size(), mDTHistory.begin()); PShift.process({xoutput, SamplesToDo}, mTemp.data()); - for(size_t i{0};i < SamplesToDo;++i) + for(std::size_t i{0};i < SamplesToDo;++i) { /* W = 0.981530*S + j*0.163585*D */ woutput[i] = 0.981530f*mS[i] + 0.163585f*xoutput[i]; @@ -341,7 +340,7 @@ void UhjDecoder::decode2(const float *RESTRICT InSamples, std::copy_n(mTemp.cbegin()+SamplesToDo, mSHistory.size(), mSHistory.begin()); PShift.process({youtput, SamplesToDo}, mTemp.data()); - for(size_t i{0};i < SamplesToDo;++i) + for(std::size_t i{0};i < SamplesToDo;++i) { /* Y = 0.762956*D + j*0.384230*S */ youtput[i] = 0.762956f*mD[i] + 0.384230f*youtput[i]; @@ -368,7 +367,7 @@ int main(int argc, char **argv) return 1; } - size_t num_files{0}, num_decoded{0}; + std::size_t num_files{0}, num_decoded{0}; bool use_general{true}; for(int fidx{1};fidx < argc;++fidx) { @@ -473,7 +472,7 @@ int main(int argc, char **argv) * be fed through the decoder after reaching the end of the input file * to ensure none of the original input is lost. */ - size_t LeadIn{UhjDecoder::sFilterDelay}; + std::size_t LeadIn{UhjDecoder::sFilterDelay}; sf_count_t LeadOut{UhjDecoder::sFilterDelay}; while(LeadOut > 0) { @@ -487,7 +486,7 @@ int main(int argc, char **argv) LeadOut -= remaining; } - auto got = static_cast(sgot); + auto got = static_cast(sgot); if(ininfo.channels > 2 || use_general) decoder->decode(inmem.get(), static_cast(ininfo.channels), decmem, got); else @@ -499,16 +498,16 @@ int main(int argc, char **argv) } got -= LeadIn; - for(size_t i{0};i < got;++i) + for(std::size_t i{0};i < got;++i) { /* Attenuate by -3dB for FuMa output levels. */ constexpr auto inv_sqrt2 = static_cast(1.0/al::numbers::sqrt2); - for(size_t j{0};j < outchans;++j) + for(std::size_t j{0};j < outchans;++j) outmem[i*outchans + j] = f32AsLEBytes(decmem[j][LeadIn+i] * inv_sqrt2); } LeadIn = 0; - size_t wrote{fwrite(outmem.get(), sizeof(byte4)*outchans, got, outfile.get())}; + std::size_t wrote{fwrite(outmem.get(), sizeof(byte4)*outchans, got, outfile.get())}; if(wrote < got) { fprintf(stderr, "Error writing wave data: %s (%d)\n", strerror(errno), errno); -- cgit v1.2.3 From 95b0c59adef778b30dfbe68af70b92d55801fd89 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 4 May 2023 12:26:57 -0700 Subject: Avoid defining separate wrapper functions --- alc/backends/pipewire.cpp | 48 ++++++++++++++++------------------------------- 1 file changed, 16 insertions(+), 32 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/pipewire.cpp b/alc/backends/pipewire.cpp index 3f372a4a..9fccf58d 100644 --- a/alc/backends/pipewire.cpp +++ b/alc/backends/pipewire.cpp @@ -815,8 +815,10 @@ struct NodeProxy { { pw_node_events ret{}; ret.version = PW_VERSION_NODE_EVENTS; - ret.info = &NodeProxy::infoCallbackC; - ret.param = &NodeProxy::paramCallbackC; + ret.info = [](void *object, const pw_node_info *info) + { static_cast(object)->infoCallback(info); }; + ret.param = [](void *object, int seq, uint32_t id, uint32_t index, uint32_t next, const spa_pod *param) + { static_cast(object)->paramCallback(seq, id, index, next, param); }; return ret; } @@ -842,13 +844,8 @@ struct NodeProxy { void infoCallback(const pw_node_info *info); - static void infoCallbackC(void *object, const pw_node_info *info) - { static_cast(object)->infoCallback(info); } void paramCallback(int seq, uint32_t id, uint32_t index, uint32_t next, const spa_pod *param); - static void paramCallbackC(void *object, int seq, uint32_t id, uint32_t index, uint32_t next, - const spa_pod *param) - { static_cast(object)->paramCallback(seq, id, index, next, param); } }; void NodeProxy::infoCallback(const pw_node_info *info) @@ -939,7 +936,8 @@ struct MetadataProxy { { pw_metadata_events ret{}; ret.version = PW_VERSION_METADATA_EVENTS; - ret.property = &MetadataProxy::propertyCallbackC; + ret.property = [](void *object, uint32_t id, const char *key, const char *type, const char *value) + { return static_cast(object)->propertyCallback(id, key, type, value); }; return ret; } @@ -957,11 +955,7 @@ struct MetadataProxy { ~MetadataProxy() { spa_hook_remove(&mListener); } - int propertyCallback(uint32_t id, const char *key, const char *type, const char *value); - static int propertyCallbackC(void *object, uint32_t id, const char *key, const char *type, - const char *value) - { return static_cast(object)->propertyCallback(id, key, type, value); } }; int MetadataProxy::propertyCallback(uint32_t id, const char *key, const char *type, @@ -1277,17 +1271,8 @@ spa_audio_info_raw make_spa_info(DeviceBase *device, bool is51rear, use_f32p_e u class PipeWirePlayback final : public BackendBase { void stateChangedCallback(pw_stream_state old, pw_stream_state state, const char *error); - static void stateChangedCallbackC(void *data, pw_stream_state old, pw_stream_state state, - const char *error) - { static_cast(data)->stateChangedCallback(old, state, error); } - void ioChangedCallback(uint32_t id, void *area, uint32_t size); - static void ioChangedCallbackC(void *data, uint32_t id, void *area, uint32_t size) - { static_cast(data)->ioChangedCallback(id, area, size); } - void outputCallback(); - static void outputCallbackC(void *data) - { static_cast(data)->outputCallback(); } void open(const char *name) override; bool reset() override; @@ -1310,9 +1295,12 @@ class PipeWirePlayback final : public BackendBase { { pw_stream_events ret{}; ret.version = PW_VERSION_STREAM_EVENTS; - ret.state_changed = &PipeWirePlayback::stateChangedCallbackC; - ret.io_changed = &PipeWirePlayback::ioChangedCallbackC; - ret.process = &PipeWirePlayback::outputCallbackC; + ret.state_changed = [](void *data, pw_stream_state old, pw_stream_state state, const char *error) + { static_cast(data)->stateChangedCallback(old, state, error); }; + ret.io_changed = [](void *data, uint32_t id, void *area, uint32_t size) + { static_cast(data)->ioChangedCallback(id, area, size); }; + ret.process = [](void *data) + { static_cast(data)->outputCallback(); }; return ret; } @@ -1782,13 +1770,7 @@ ClockLatency PipeWirePlayback::getClockLatency() class PipeWireCapture final : public BackendBase { void stateChangedCallback(pw_stream_state old, pw_stream_state state, const char *error); - static void stateChangedCallbackC(void *data, pw_stream_state old, pw_stream_state state, - const char *error) - { static_cast(data)->stateChangedCallback(old, state, error); } - void inputCallback(); - static void inputCallbackC(void *data) - { static_cast(data)->inputCallback(); } void open(const char *name) override; void start() override; @@ -1809,8 +1791,10 @@ class PipeWireCapture final : public BackendBase { { pw_stream_events ret{}; ret.version = PW_VERSION_STREAM_EVENTS; - ret.state_changed = &PipeWireCapture::stateChangedCallbackC; - ret.process = &PipeWireCapture::inputCallbackC; + ret.state_changed = [](void *data, pw_stream_state old, pw_stream_state state, const char *error) + { static_cast(data)->stateChangedCallback(old, state, error); }; + ret.process = [](void *data) + { static_cast(data)->inputCallback(); }; return ret; } -- cgit v1.2.3 From c14ca5f3aa6da354440a60656062f6bc68d6fca6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 4 May 2023 18:42:27 -0700 Subject: Remove custom stuff for standard --- alc/alc.cpp | 2 +- alc/backends/jack.cpp | 2 +- alc/backends/pipewire.cpp | 4 +-- alc/backends/wasapi.cpp | 4 +-- alc/panning.cpp | 10 +++---- common/alcomplex.cpp | 2 +- common/alnumbers.h | 16 +++++------ common/alspan.h | 69 +++++++++++++++-------------------------------- core/ambdec.cpp | 2 +- core/voice.cpp | 2 +- 10 files changed, 44 insertions(+), 69 deletions(-) (limited to 'alc/backends') diff --git a/alc/alc.cpp b/alc/alc.cpp index d226b39d..290cc3d1 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -1093,7 +1093,7 @@ void alc_initconfig(void) ALSOFT_GIT_BRANCH); { std::string names; - if(al::size(BackendList) < 1) + if(std::size(BackendList) < 1) names = "(none)"; else { diff --git a/alc/backends/jack.cpp b/alc/backends/jack.cpp index dbc2b038..7e1e8fc7 100644 --- a/alc/backends/jack.cpp +++ b/alc/backends/jack.cpp @@ -587,7 +587,7 @@ void JackPlayback::start() throw al::backend_exception{al::backend_error::DeviceError, "No playback ports found"}; } - for(size_t i{0};i < al::size(mPort) && mPort[i];++i) + for(size_t i{0};i < std::size(mPort) && mPort[i];++i) { if(!pnames[i]) { diff --git a/alc/backends/pipewire.cpp b/alc/backends/pipewire.cpp index 9fccf58d..dc52a44d 100644 --- a/alc/backends/pipewire.cpp +++ b/alc/backends/pipewire.cpp @@ -800,7 +800,7 @@ void DeviceNode::parseChannelCount(const spa_pod *value) noexcept constexpr char MonitorPrefix[]{"Monitor of "}; -constexpr auto MonitorPrefixLen = al::size(MonitorPrefix) - 1; +constexpr auto MonitorPrefixLen = std::size(MonitorPrefix) - 1; constexpr char AudioSinkClass[]{"Audio/Sink"}; constexpr char AudioSourceClass[]{"Audio/Source"}; constexpr char AudioSourceVirtualClass[]{"Audio/Source/Virtual"}; @@ -837,7 +837,7 @@ struct NodeProxy { * format, which is what we're interested in). */ uint32_t fmtids[]{SPA_PARAM_EnumFormat}; - ppw_node_subscribe_params(mNode.get(), al::data(fmtids), al::size(fmtids)); + ppw_node_subscribe_params(mNode.get(), std::data(fmtids), std::size(fmtids)); } ~NodeProxy() { spa_hook_remove(&mListener); } diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 16576733..97f0a291 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -125,7 +125,7 @@ constexpr DWORD X71Mask{MaskFromTopBits(X7DOT1)}; constexpr DWORD X714Mask{MaskFromTopBits(X7DOT1DOT4)}; constexpr char DevNameHead[] = "OpenAL Soft on "; -constexpr size_t DevNameHeadLen{al::size(DevNameHead) - 1}; +constexpr size_t DevNameHeadLen{std::size(DevNameHead) - 1}; /* Scales the given reftime value, rounding the result. */ @@ -142,7 +142,7 @@ class GuidPrinter { public: GuidPrinter(const GUID &guid) { - std::snprintf(mMsg, al::size(mMsg), "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + std::snprintf(mMsg, std::size(mMsg), "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", DWORD{guid.Data1}, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]); } diff --git a/alc/panning.cpp b/alc/panning.cpp index a3d639fc..60ce7ca4 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -346,10 +346,10 @@ DecoderView MakeDecoderView(ALCdevice *device, const AmbDecConf *conf, } std::copy_n(std::begin(conf->HFOrderGain), - std::min(al::size(conf->HFOrderGain), al::size(decoder.mOrderGain)), + std::min(std::size(conf->HFOrderGain), std::size(decoder.mOrderGain)), std::begin(decoder.mOrderGain)); std::copy_n(std::begin(conf->LFOrderGain), - std::min(al::size(conf->LFOrderGain), al::size(decoder.mOrderGainLF)), + std::min(std::size(conf->LFOrderGain), std::size(decoder.mOrderGainLF)), std::begin(decoder.mOrderGainLF)); const auto num_coeffs = decoder.mIs3D ? AmbiChannelsFromOrder(decoder.mOrder) @@ -818,9 +818,9 @@ void InitHrtfPanning(ALCdevice *device) /*RMS 8.340921354e-01f, 7.182670250e-01f, 5.107426573e-01f, 2.541870634e-01f*/ }; - static_assert(al::size(AmbiPoints1O) == al::size(AmbiMatrix1O), "First-Order Ambisonic HRTF mismatch"); - static_assert(al::size(AmbiPoints2O) == al::size(AmbiMatrix2O), "Second-Order Ambisonic HRTF mismatch"); - static_assert(al::size(AmbiPoints3O) == al::size(AmbiMatrix3O), "Third-Order Ambisonic HRTF mismatch"); + static_assert(std::size(AmbiPoints1O) == std::size(AmbiMatrix1O), "First-Order Ambisonic HRTF mismatch"); + static_assert(std::size(AmbiPoints2O) == std::size(AmbiMatrix2O), "Second-Order Ambisonic HRTF mismatch"); + static_assert(std::size(AmbiPoints3O) == std::size(AmbiMatrix3O), "Third-Order Ambisonic HRTF mismatch"); /* A 700hz crossover frequency provides tighter sound imaging at the sweet * spot with ambisonic decoding, as the distance between the ears is closer diff --git a/common/alcomplex.cpp b/common/alcomplex.cpp index 4420a1bb..a1ca822d 100644 --- a/common/alcomplex.cpp +++ b/common/alcomplex.cpp @@ -58,7 +58,7 @@ struct BitReverser { ++ret_i; } } - assert(ret_i == al::size(mData)); + assert(ret_i == std::size(mData)); } }; diff --git a/common/alnumbers.h b/common/alnumbers.h index 37a55410..800b1f2a 100644 --- a/common/alnumbers.h +++ b/common/alnumbers.h @@ -13,21 +13,21 @@ namespace detail_ { } // detail_ template -static constexpr auto pi_v = detail_::as_fp(3.141592653589793238462643383279502884L); +constexpr auto pi_v = detail_::as_fp(3.141592653589793238462643383279502884L); template -static constexpr auto inv_pi_v = detail_::as_fp(0.318309886183790671537767526745028724L); +constexpr auto inv_pi_v = detail_::as_fp(0.318309886183790671537767526745028724L); template -static constexpr auto sqrt2_v = detail_::as_fp(1.414213562373095048801688724209698079L); +constexpr auto sqrt2_v = detail_::as_fp(1.414213562373095048801688724209698079L); template -static constexpr auto sqrt3_v = detail_::as_fp(1.732050807568877293527446341505872367L); +constexpr auto sqrt3_v = detail_::as_fp(1.732050807568877293527446341505872367L); -static constexpr auto pi = pi_v; -static constexpr auto inv_pi = inv_pi_v; -static constexpr auto sqrt2 = sqrt2_v; -static constexpr auto sqrt3 = sqrt3_v; +constexpr auto pi = pi_v; +constexpr auto inv_pi = inv_pi_v; +constexpr auto sqrt2 = sqrt2_v; +constexpr auto sqrt3 = sqrt3_v; } // namespace numbers diff --git a/common/alspan.h b/common/alspan.h index 1d6cdfe5..42b3e057 100644 --- a/common/alspan.h +++ b/common/alspan.h @@ -12,41 +12,12 @@ namespace al { -template -constexpr auto size(const T &cont) noexcept(noexcept(cont.size())) -> decltype(cont.size()) -{ return cont.size(); } - -template -constexpr size_t size(const T (&)[N]) noexcept -{ return N; } - - -template -constexpr auto data(T &cont) noexcept(noexcept(cont.data())) -> decltype(cont.data()) -{ return cont.data(); } - -template -constexpr auto data(const T &cont) noexcept(noexcept(cont.data())) -> decltype(cont.data()) -{ return cont.data(); } - -template -constexpr T* data(T (&arr)[N]) noexcept -{ return arr; } - -template -constexpr const T* data(std::initializer_list list) noexcept -{ return list.begin(); } - - constexpr size_t dynamic_extent{static_cast(-1)}; template class span; namespace detail_ { - template - using void_t = void; - template struct is_span_ : std::false_type { }; template @@ -65,7 +36,7 @@ namespace detail_ { constexpr bool has_size_and_data = false; template constexpr bool has_size_and_data())), decltype(al::data(std::declval()))>> + std::void_t())),decltype(std::data(std::declval()))>> = true; template @@ -74,7 +45,7 @@ namespace detail_ { template constexpr bool is_valid_container = !is_span_v && !is_std_array_v && !std::is_array::value && has_size_and_data - && is_array_compatible()))>,T>; + && is_array_compatible()))>,T>; } // namespace detail_ #define REQUIRES(...) std::enable_if_t<(__VA_ARGS__),bool> = true @@ -107,25 +78,27 @@ public: constexpr explicit span(U first, V) : mData{to_address(first)} { } constexpr span(type_identity_t (&arr)[E]) noexcept - : span{al::data(arr), al::size(arr)} + : span{std::data(arr), std::size(arr)} + { } + constexpr span(std::array &arr) noexcept + : span{std::data(arr), std::size(arr)} { } - constexpr span(std::array &arr) noexcept : span{al::data(arr), al::size(arr)} { } template::value)> constexpr span(const std::array &arr) noexcept - : span{al::data(arr), al::size(arr)} + : span{std::data(arr), std::size(arr)} { } template)> - constexpr explicit span(U&& cont) : span{al::data(cont), al::size(cont)} { } + constexpr explicit span(U&& cont) : span{std::data(cont), std::size(cont)} { } template::value && detail_::is_array_compatible && N == dynamic_extent)> constexpr explicit span(const span &span_) noexcept - : span{al::data(span_), al::size(span_)} + : span{std::data(span_), std::size(span_)} { } template::value && detail_::is_array_compatible && N == extent)> - constexpr span(const span &span_) noexcept : span{al::data(span_), al::size(span_)} { } + constexpr span(const span &span_) noexcept : span{std::data(span_), std::size(span_)} { } constexpr span(const span&) noexcept = default; constexpr span& operator=(const span &rhs) noexcept = default; @@ -224,21 +197,23 @@ public: template constexpr span(type_identity_t (&arr)[N]) noexcept - : span{al::data(arr), al::size(arr)} + : span{std::data(arr), std::size(arr)} { } template - constexpr span(std::array &arr) noexcept : span{al::data(arr), al::size(arr)} { } + constexpr span(std::array &arr) noexcept + : span{std::data(arr), std::size(arr)} + { } template::value)> constexpr span(const std::array &arr) noexcept - : span{al::data(arr), al::size(arr)} + : span{std::data(arr), std::size(arr)} { } template)> - constexpr span(U&& cont) : span{al::data(cont), al::size(cont)} { } + constexpr span(U&& cont) : span{std::data(cont), std::size(cont)} { } template::value || extent != N) && detail_::is_array_compatible)> - constexpr span(const span &span_) noexcept : span{al::data(span_), al::size(span_)} { } + constexpr span(const span &span_) noexcept : span{std::data(span_), std::size(span_)} { } constexpr span(const span&) noexcept = default; constexpr span& operator=(const span &rhs) noexcept = default; @@ -330,19 +305,19 @@ constexpr auto as_span(T ptr, U count_or_end) return span{ptr, count_or_end}; } template -constexpr auto as_span(T (&arr)[N]) noexcept { return span{al::data(arr), al::size(arr)}; } +constexpr auto as_span(T (&arr)[N]) noexcept { return span{std::data(arr), std::size(arr)}; } template constexpr auto as_span(std::array &arr) noexcept -{ return span{al::data(arr), al::size(arr)}; } +{ return span{std::data(arr), std::size(arr)}; } template constexpr auto as_span(const std::array &arr) noexcept -{ return span,N>{al::data(arr), al::size(arr)}; } +{ return span,N>{std::data(arr), std::size(arr)}; } template && !detail_::is_std_array_v && !std::is_array::value && detail_::has_size_and_data)> constexpr auto as_span(U&& cont) { - using value_type = std::remove_pointer_t()))>; - return span{al::data(cont), al::size(cont)}; + using value_type = std::remove_pointer_t()))>; + return span{std::data(cont), std::size(cont)}; } template constexpr auto as_span(span span_) noexcept { return span_; } diff --git a/core/ambdec.cpp b/core/ambdec.cpp index a056e63f..f98e1098 100644 --- a/core/ambdec.cpp +++ b/core/ambdec.cpp @@ -139,7 +139,7 @@ std::optional AmbDecConf::load(const char *fname) noexcept { --toread; istr >> value; - if(curgain < al::size(gains)) + if(curgain < std::size(gains)) gains[curgain++] = value; } } diff --git a/core/voice.cpp b/core/voice.cpp index cbf84c2a..db6b6d27 100644 --- a/core/voice.cpp +++ b/core/voice.cpp @@ -288,7 +288,7 @@ inline void LoadSamples(float *RESTRICT dstSamples, const std::byte *sr /* NOTE: This could probably be optimized better. */ size_t wrote{0}; do { - static constexpr int MaxStepIndex{static_cast(al::size(IMAStep_size)) - 1}; + static constexpr int MaxStepIndex{static_cast(std::size(IMAStep_size)) - 1}; /* Each IMA4 block starts with a signed 16-bit sample, and a signed * 16-bit table index. The table index needs to be clamped. */ -- cgit v1.2.3 From bfe766cd574985465fe1a9f4cffa388ca9ca1f9b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 May 2023 13:37:50 -0700 Subject: Use some more standard functions --- al/auxeffectslot.cpp | 10 +++---- al/buffer.cpp | 4 +-- al/effect.cpp | 4 +-- al/effects/reverb.cpp | 24 ++++++++-------- al/event.cpp | 2 +- al/filter.cpp | 4 +-- al/source.cpp | 8 +++--- alc/backends/pipewire.cpp | 12 ++++---- common/almalloc.h | 71 ++--------------------------------------------- common/alnumeric.h | 6 ---- core/context.cpp | 6 ++-- core/mastering.cpp | 4 +-- utils/uhjencoder.cpp | 6 ++-- 13 files changed, 44 insertions(+), 117 deletions(-) (limited to 'alc/backends') diff --git a/al/auxeffectslot.cpp b/al/auxeffectslot.cpp index 571eb717..c69990fe 100644 --- a/al/auxeffectslot.cpp +++ b/al/auxeffectslot.cpp @@ -165,7 +165,7 @@ void AddActiveEffectSlots(const al::span auxslots, ALCcontext *co curarray = context->mActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); context->mDevice->waitForMix(); - al::destroy_n(curarray->end(), curarray->size()); + std::destroy_n(curarray->end(), curarray->size()); delete curarray; } @@ -204,7 +204,7 @@ void RemoveActiveEffectSlots(const al::span auxslots, ALCcontext curarray = context->mActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); context->mDevice->waitForMix(); - al::destroy_n(curarray->end(), curarray->size()); + std::destroy_n(curarray->end(), curarray->size()); delete curarray; } @@ -289,7 +289,7 @@ void FreeEffectSlot(ALCcontext *context, ALeffectslot *slot) const size_t lidx{id >> 6}; const ALuint slidx{id & 0x3f}; - al::destroy_at(slot); + std::destroy_at(slot); context->mEffectSlotList[lidx].FreeMask |= 1_u64 << slidx; context->mNumEffectSlots--; @@ -1030,7 +1030,7 @@ EffectSlotSubList::~EffectSlotSubList() while(usemask) { const int idx{al::countr_zero(usemask)}; - al::destroy_at(EffectSlots+idx); + std::destroy_at(EffectSlots+idx); usemask &= ~(1_u64 << idx); } FreeMask = ~usemask; @@ -1275,7 +1275,7 @@ void ALeffectslot::eax_fx_slot_load_effect(int version, ALenum altype) void ALeffectslot::eax_fx_slot_set_volume() { - const auto volume = clamp(eax_.lVolume, EAXFXSLOT_MINVOLUME, EAXFXSLOT_MAXVOLUME); + const auto volume = std::clamp(eax_.lVolume, EAXFXSLOT_MINVOLUME, EAXFXSLOT_MAXVOLUME); const auto gain = level_mb_to_gain(static_cast(volume)); eax_set_efx_slot_gain(gain); } diff --git a/al/buffer.cpp b/al/buffer.cpp index 1a042f46..371e586c 100644 --- a/al/buffer.cpp +++ b/al/buffer.cpp @@ -222,7 +222,7 @@ void FreeBuffer(ALCdevice *device, ALbuffer *buffer) const size_t lidx{id >> 6}; const ALuint slidx{id & 0x3f}; - al::destroy_at(buffer); + std::destroy_at(buffer); device->BufferList[lidx].FreeMask |= 1_u64 << slidx; } @@ -1533,7 +1533,7 @@ BufferSubList::~BufferSubList() while(usemask) { const int idx{al::countr_zero(usemask)}; - al::destroy_at(Buffers+idx); + std::destroy_at(Buffers+idx); usemask &= ~(1_u64 << idx); } FreeMask = ~usemask; diff --git a/al/effect.cpp b/al/effect.cpp index 28f5e967..3d91139a 100644 --- a/al/effect.cpp +++ b/al/effect.cpp @@ -210,7 +210,7 @@ void FreeEffect(ALCdevice *device, ALeffect *effect) const size_t lidx{id >> 6}; const ALuint slidx{id & 0x3f}; - al::destroy_at(effect); + std::destroy_at(effect); device->EffectList[lidx].FreeMask |= 1_u64 << slidx; } @@ -555,7 +555,7 @@ EffectSubList::~EffectSubList() while(usemask) { const int idx{al::countr_zero(usemask)}; - al::destroy_at(Effects+idx); + std::destroy_at(Effects+idx); usemask &= ~(1_u64 << idx); } FreeMask = ~usemask; diff --git a/al/effects/reverb.cpp b/al/effects/reverb.cpp index 440d7b4e..d93602cd 100644 --- a/al/effects/reverb.cpp +++ b/al/effects/reverb.cpp @@ -945,7 +945,7 @@ struct EnvironmentSizeDeferrer2 { if ((props.dwFlags & EAX2LISTENERFLAGS_DECAYTIMESCALE) != 0) { - props.flDecayTime = clamp( + props.flDecayTime = std::clamp( props.flDecayTime * scale, EAXREVERB_MINDECAYTIME, EAXREVERB_MAXDECAYTIME); @@ -954,7 +954,7 @@ struct EnvironmentSizeDeferrer2 { if ((props.dwFlags & EAX2LISTENERFLAGS_REFLECTIONSSCALE) != 0 && (props.dwFlags & EAX2LISTENERFLAGS_REFLECTIONSDELAYSCALE) != 0) { - props.lReflections = clamp( + props.lReflections = std::clamp( props.lReflections - static_cast(gain_to_level_mb(scale)), EAXREVERB_MINREFLECTIONS, EAXREVERB_MAXREFLECTIONS); @@ -962,7 +962,7 @@ struct EnvironmentSizeDeferrer2 { if ((props.dwFlags & EAX2LISTENERFLAGS_REFLECTIONSDELAYSCALE) != 0) { - props.flReflectionsDelay = clamp( + props.flReflectionsDelay = std::clamp( props.flReflectionsDelay * scale, EAXREVERB_MINREFLECTIONSDELAY, EAXREVERB_MAXREFLECTIONSDELAY); @@ -972,7 +972,7 @@ struct EnvironmentSizeDeferrer2 { { const auto log_scalar = ((props.dwFlags & EAXREVERBFLAGS_DECAYTIMESCALE) != 0) ? 2'000.0F : 3'000.0F; - props.lReverb = clamp( + props.lReverb = std::clamp( props.lReverb - static_cast(std::log10(scale) * log_scalar), EAXREVERB_MINREVERB, EAXREVERB_MAXREVERB); @@ -980,7 +980,7 @@ struct EnvironmentSizeDeferrer2 { if ((props.dwFlags & EAX2LISTENERFLAGS_REVERBDELAYSCALE) != 0) { - props.flReverbDelay = clamp( + props.flReverbDelay = std::clamp( props.flReverbDelay * scale, EAXREVERB_MINREVERBDELAY, EAXREVERB_MAXREVERBDELAY); @@ -1015,7 +1015,7 @@ struct EnvironmentSizeDeferrer3 { if ((props.ulFlags & EAXREVERBFLAGS_DECAYTIMESCALE) != 0) { - props.flDecayTime = clamp( + props.flDecayTime = std::clamp( props.flDecayTime * scale, EAXREVERB_MINDECAYTIME, EAXREVERB_MAXDECAYTIME); @@ -1024,7 +1024,7 @@ struct EnvironmentSizeDeferrer3 { if ((props.ulFlags & EAXREVERBFLAGS_REFLECTIONSSCALE) != 0 && (props.ulFlags & EAXREVERBFLAGS_REFLECTIONSDELAYSCALE) != 0) { - props.lReflections = clamp( + props.lReflections = std::clamp( props.lReflections - static_cast(gain_to_level_mb(scale)), EAXREVERB_MINREFLECTIONS, EAXREVERB_MAXREFLECTIONS); @@ -1032,7 +1032,7 @@ struct EnvironmentSizeDeferrer3 { if ((props.ulFlags & EAXREVERBFLAGS_REFLECTIONSDELAYSCALE) != 0) { - props.flReflectionsDelay = clamp( + props.flReflectionsDelay = std::clamp( props.flReflectionsDelay * scale, EAXREVERB_MINREFLECTIONSDELAY, EAXREVERB_MAXREFLECTIONSDELAY); @@ -1041,7 +1041,7 @@ struct EnvironmentSizeDeferrer3 { if ((props.ulFlags & EAXREVERBFLAGS_REVERBSCALE) != 0) { const auto log_scalar = ((props.ulFlags & EAXREVERBFLAGS_DECAYTIMESCALE) != 0) ? 2'000.0F : 3'000.0F; - props.lReverb = clamp( + props.lReverb = std::clamp( props.lReverb - static_cast(std::log10(scale) * log_scalar), EAXREVERB_MINREVERB, EAXREVERB_MAXREVERB); @@ -1049,7 +1049,7 @@ struct EnvironmentSizeDeferrer3 { if ((props.ulFlags & EAXREVERBFLAGS_REVERBDELAYSCALE) != 0) { - props.flReverbDelay = clamp( + props.flReverbDelay = std::clamp( props.flReverbDelay * scale, EAXREVERB_MINREVERBDELAY, EAXREVERB_MAXREVERBDELAY); @@ -1057,7 +1057,7 @@ struct EnvironmentSizeDeferrer3 { if ((props.ulFlags & EAXREVERBFLAGS_ECHOTIMESCALE) != 0) { - props.flEchoTime = clamp( + props.flEchoTime = std::clamp( props.flEchoTime * scale, EAXREVERB_MINECHOTIME, EAXREVERB_MAXECHOTIME); @@ -1065,7 +1065,7 @@ struct EnvironmentSizeDeferrer3 { if ((props.ulFlags & EAXREVERBFLAGS_MODULATIONTIMESCALE) != 0) { - props.flModulationTime = clamp( + props.flModulationTime = std::clamp( props.flModulationTime * scale, EAXREVERB_MINMODULATIONTIME, EAXREVERB_MAXMODULATIONTIME); diff --git a/al/event.cpp b/al/event.cpp index acb4958a..33e28412 100644 --- a/al/event.cpp +++ b/al/event.cpp @@ -50,7 +50,7 @@ static int EventThread(ALCcontext *context) evt_data.len -= 1; AsyncEvent evt{*evt_ptr}; - al::destroy_at(evt_ptr); + std::destroy_at(evt_ptr); ring->readAdvance(1); quitnow = evt.EnumType == AsyncEvent::KillThread; diff --git a/al/filter.cpp b/al/filter.cpp index c5d1b2a1..0fd8eaa8 100644 --- a/al/filter.cpp +++ b/al/filter.cpp @@ -380,7 +380,7 @@ void FreeFilter(ALCdevice *device, ALfilter *filter) const size_t lidx{id >> 6}; const ALuint slidx{id & 0x3f}; - al::destroy_at(filter); + std::destroy_at(filter); device->FilterList[lidx].FreeMask |= 1_u64 << slidx; } @@ -716,7 +716,7 @@ FilterSubList::~FilterSubList() while(usemask) { const int idx{al::countr_zero(usemask)}; - al::destroy_at(Filters+idx); + std::destroy_at(Filters+idx); usemask &= ~(1_u64 << idx); } FreeMask = ~usemask; diff --git a/al/source.cpp b/al/source.cpp index 2b0540b4..b8feb0c3 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -738,7 +738,7 @@ void FreeSource(ALCcontext *context, ALsource *source) SendVoiceChanges(context, vchg); } - al::destroy_at(source); + std::destroy_at(source); context->mSourceList[lidx].FreeMask |= 1_u64 << slidx; context->mNumSources--; @@ -4041,7 +4041,7 @@ SourceSubList::~SourceSubList() { const int idx{al::countr_zero(usemask)}; usemask &= ~(1_u64 << idx); - al::destroy_at(Sources+idx); + std::destroy_at(Sources+idx); } FreeMask = ~usemask; al_free(Sources); @@ -4257,7 +4257,7 @@ void ALsource::eax1_translate(const Eax1Props& src, Eax5Props& dst) noexcept else { dst.source.ulFlags &= ~EAXSOURCEFLAGS_ROOMAUTO; - dst.sends[0].lSend = clamp(static_cast(gain_to_level_mb(src.fMix)), + dst.sends[0].lSend = std::clamp(static_cast(gain_to_level_mb(src.fMix)), EAXSOURCE_MINSEND, EAXSOURCE_MAXSEND); } } @@ -4492,7 +4492,7 @@ void ALsource::eax_update_room_filters() void ALsource::eax_set_efx_outer_gain_hf() { - OuterGainHF = clamp( + OuterGainHF = std::clamp( level_mb_to_gain(static_cast(mEax.source.lOutsideVolumeHF)), AL_MIN_CONE_OUTER_GAINHF, AL_MAX_CONE_OUTER_GAINHF); diff --git a/alc/backends/pipewire.cpp b/alc/backends/pipewire.cpp index dc52a44d..bb7fc2f2 100644 --- a/alc/backends/pipewire.cpp +++ b/alc/backends/pipewire.cpp @@ -1085,9 +1085,9 @@ EventManager::~EventManager() if(mLoop) mLoop.stop(); for(NodeProxy *node : mNodeList) - al::destroy_at(node); + std::destroy_at(node); if(mDefaultMetadata) - al::destroy_at(mDefaultMetadata); + std::destroy_at(mDefaultMetadata); } void EventManager::kill() @@ -1095,10 +1095,10 @@ void EventManager::kill() if(mLoop) mLoop.stop(); for(NodeProxy *node : mNodeList) - al::destroy_at(node); + std::destroy_at(node); mNodeList.clear(); if(mDefaultMetadata) - al::destroy_at(mDefaultMetadata); + std::destroy_at(mDefaultMetadata); mDefaultMetadata = nullptr; mRegistry = nullptr; @@ -1191,7 +1191,7 @@ void EventManager::removeCallback(uint32_t id) { if(node->mId != id) return false; - al::destroy_at(node); + std::destroy_at(node); return true; }; auto node_end = std::remove_if(mNodeList.begin(), mNodeList.end(), clear_node); @@ -1199,7 +1199,7 @@ void EventManager::removeCallback(uint32_t id) if(mDefaultMetadata && mDefaultMetadata->mId == id) { - al::destroy_at(mDefaultMetadata); + std::destroy_at(mDefaultMetadata); mDefaultMetadata = nullptr; } } diff --git a/common/almalloc.h b/common/almalloc.h index a795fc3b..bd2e085b 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -125,71 +125,6 @@ constexpr T* construct_at(T *ptr, Args&& ...args) noexcept(std::is_nothrow_constructible::value) { return ::new(static_cast(ptr)) T{std::forward(args)...}; } -/* At least VS 2015 complains that 'ptr' is unused when the given type's - * destructor is trivial (a no-op). So disable that warning for this call. - */ -DIAGNOSTIC_PUSH -msc_pragma(warning(disable : 4100)) -template -constexpr std::enable_if_t::value> -destroy_at(T *ptr) noexcept(std::is_nothrow_destructible::value) -{ ptr->~T(); } -DIAGNOSTIC_POP -template -constexpr std::enable_if_t::value> -destroy_at(T *ptr) noexcept(std::is_nothrow_destructible>::value) -{ - for(auto &elem : *ptr) - al::destroy_at(std::addressof(elem)); -} - -template -constexpr void destroy(T first, T end) noexcept(noexcept(al::destroy_at(std::addressof(*first)))) -{ - while(first != end) - { - al::destroy_at(std::addressof(*first)); - ++first; - } -} - -template -constexpr std::enable_if_t::value,T> -destroy_n(T first, N count) noexcept(noexcept(al::destroy_at(std::addressof(*first)))) -{ - if(count != 0) - { - do { - al::destroy_at(std::addressof(*first)); - ++first; - } while(--count); - } - return first; -} - - -template -inline std::enable_if_t::value, -T> uninitialized_default_construct_n(T first, N count) -{ - using ValueT = typename std::iterator_traits::value_type; - T current{first}; - if(count != 0) - { - try { - do { - ::new(static_cast(std::addressof(*current))) ValueT; - ++current; - } while(--count); - } - catch(...) { - al::destroy(first, current); - throw; - } - } - return current; -} - /* Storage for flexible array data. This is trivially destructible if type T is * trivially destructible. @@ -209,7 +144,7 @@ struct FlexArrayStorage { } FlexArrayStorage(size_t size) : mSize{size} - { al::uninitialized_default_construct_n(mArray, mSize); } + { std::uninitialized_default_construct_n(mArray, mSize); } ~FlexArrayStorage() = default; FlexArrayStorage(const FlexArrayStorage&) = delete; @@ -231,8 +166,8 @@ struct FlexArrayStorage { } FlexArrayStorage(size_t size) : mSize{size} - { al::uninitialized_default_construct_n(mArray, mSize); } - ~FlexArrayStorage() { al::destroy_n(mArray, mSize); } + { std::uninitialized_default_construct_n(mArray, mSize); } + ~FlexArrayStorage() { std::destroy_n(mArray, mSize); } FlexArrayStorage(const FlexArrayStorage&) = delete; FlexArrayStorage& operator=(const FlexArrayStorage&) = delete; diff --git a/common/alnumeric.h b/common/alnumeric.h index d6919e40..8220d3e5 100644 --- a/common/alnumeric.h +++ b/common/alnumeric.h @@ -283,12 +283,6 @@ inline float fast_roundf(float f) noexcept } -template -constexpr const T& clamp(const T& value, const T& min_value, const T& max_value) noexcept -{ - return std::min(std::max(value, min_value), max_value); -} - // Converts level (mB) to gain. inline float level_mb_to_gain(float x) { diff --git a/core/context.cpp b/core/context.cpp index d68d8327..d94daf16 100644 --- a/core/context.cpp +++ b/core/context.cpp @@ -51,7 +51,7 @@ ContextBase::~ContextBase() if(EffectSlotArray *curarray{mActiveAuxSlots.exchange(nullptr, std::memory_order_relaxed)}) { - al::destroy_n(curarray->end(), curarray->size()); + std::destroy_n(curarray->end(), curarray->size()); delete curarray; } @@ -63,12 +63,12 @@ ContextBase::~ContextBase() auto evt_vec = mAsyncEvents->getReadVector(); if(evt_vec.first.len > 0) { - al::destroy_n(reinterpret_cast(evt_vec.first.buf), evt_vec.first.len); + std::destroy_n(reinterpret_cast(evt_vec.first.buf), evt_vec.first.len); count += evt_vec.first.len; } if(evt_vec.second.len > 0) { - al::destroy_n(reinterpret_cast(evt_vec.second.buf), evt_vec.second.len); + std::destroy_n(reinterpret_cast(evt_vec.second.buf), evt_vec.second.len); count += evt_vec.second.len; } if(count > 0) diff --git a/core/mastering.cpp b/core/mastering.cpp index 97a4008e..4445719b 100644 --- a/core/mastering.cpp +++ b/core/mastering.cpp @@ -382,10 +382,10 @@ std::unique_ptr Compressor::Create(const size_t NumChans, const floa Compressor::~Compressor() { if(mHold) - al::destroy_at(mHold); + std::destroy_at(mHold); mHold = nullptr; if(mDelay) - al::destroy_n(mDelay, mNumChans); + std::destroy_n(mDelay, mNumChans); mDelay = nullptr; } diff --git a/utils/uhjencoder.cpp b/utils/uhjencoder.cpp index 34698993..c381d1b9 100644 --- a/utils/uhjencoder.cpp +++ b/utils/uhjencoder.cpp @@ -502,11 +502,9 @@ int main(int argc, char **argv) got -= LeadIn; for(size_t c{0};c < uhjchans;++c) { - constexpr float max_val{8388607.0f / 8388608.0f}; - auto clamp = [](float v, float mn, float mx) noexcept - { return std::min(std::max(v, mn), mx); }; + static constexpr float max_val{8388607.0f / 8388608.0f}; for(size_t i{0};i < got;++i) - outmem[i*uhjchans + c] = clamp(encmem[c][LeadIn+i], -1.0f, max_val); + outmem[i*uhjchans + c] = std::clamp(encmem[c][LeadIn+i], -1.0f, max_val); } LeadIn = 0; -- cgit v1.2.3 From 72f02418e505a192c0cc7b27cd7b3aa28a7a03ec Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 12 May 2023 16:01:06 -0700 Subject: Clean up some more includes --- alc/backends/alsa.cpp | 1 + alc/backends/coreaudio.cpp | 8 ++++---- alc/backends/dsound.cpp | 14 +++++++------- alc/backends/jack.cpp | 4 ++-- alc/backends/oboe.cpp | 1 + alc/backends/opensl.cpp | 3 ++- alc/backends/oss.cpp | 2 -- alc/backends/winmm.cpp | 4 ++-- core/context.cpp | 3 +++ core/context.h | 13 +++++-------- core/device.h | 4 +--- 11 files changed, 28 insertions(+), 29 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/alsa.cpp b/alc/backends/alsa.cpp index 74713590..c1690867 100644 --- a/alc/backends/alsa.cpp +++ b/alc/backends/alsa.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index 19a1f753..c2a79815 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -22,17 +22,17 @@ #include "coreaudio.h" +#include #include +#include +#include #include #include #include +#include #include #include -#include -#include -#include - #include "alnumeric.h" #include "core/converter.h" #include "core/device.h" diff --git a/alc/backends/dsound.cpp b/alc/backends/dsound.cpp index 05117781..ffcd8430 100644 --- a/alc/backends/dsound.cpp +++ b/alc/backends/dsound.cpp @@ -25,10 +25,6 @@ #define WIN32_LEAN_AND_MEAN #include -#include -#include -#include - #include #include #ifndef _WAVEFORMATEXTENSIBLE_ @@ -36,13 +32,17 @@ #include #endif +#include #include #include -#include +#include +#include +#include +#include +#include #include +#include #include -#include -#include #include "albit.h" #include "alnumeric.h" diff --git a/alc/backends/jack.cpp b/alc/backends/jack.cpp index 7e1e8fc7..b12edf9f 100644 --- a/alc/backends/jack.cpp +++ b/alc/backends/jack.cpp @@ -22,12 +22,12 @@ #include "jack.h" +#include #include #include #include #include - -#include +#include #include #include diff --git a/alc/backends/oboe.cpp b/alc/backends/oboe.cpp index 4c47190e..c74b0180 100644 --- a/alc/backends/oboe.cpp +++ b/alc/backends/oboe.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include "alnumeric.h" diff --git a/alc/backends/opensl.cpp b/alc/backends/opensl.cpp index 0c2936b2..c9053816 100644 --- a/alc/backends/opensl.cpp +++ b/alc/backends/opensl.cpp @@ -26,9 +26,10 @@ #include #include -#include #include #include +#include +#include #include #include diff --git a/alc/backends/oss.cpp b/alc/backends/oss.cpp index 9e247be1..1fdee701 100644 --- a/alc/backends/oss.cpp +++ b/alc/backends/oss.cpp @@ -31,12 +31,10 @@ #include #include #include -#include #include #include #include #include -#include #include #include #include diff --git a/alc/backends/winmm.cpp b/alc/backends/winmm.cpp index 135b59df..edb875a0 100644 --- a/alc/backends/winmm.cpp +++ b/alc/backends/winmm.cpp @@ -55,8 +55,8 @@ namespace { #define DEVNAME_HEAD "OpenAL Soft on " -al::vector PlaybackDevices; -al::vector CaptureDevices; +std::vector PlaybackDevices; +std::vector CaptureDevices; bool checkName(const al::vector &list, const std::string &name) { return std::find(list.cbegin(), list.cend(), name) != list.cend(); } diff --git a/core/context.cpp b/core/context.cpp index d94daf16..145ce349 100644 --- a/core/context.cpp +++ b/core/context.cpp @@ -2,7 +2,10 @@ #include "config.h" #include +#include #include +#include +#include #include "async_event.h" #include "context.h" diff --git a/core/context.h b/core/context.h index 4febd38d..629e67a5 100644 --- a/core/context.h +++ b/core/context.h @@ -7,16 +7,15 @@ #include #include #include +#include #include "almalloc.h" #include "alspan.h" #include "async_event.h" #include "atomic.h" -#include "bufferline.h" #include "opthelpers.h" #include "threads.h" #include "vecmat.h" -#include "vector.h" struct DeviceBase; struct EffectSlot; @@ -26,8 +25,6 @@ struct Voice; struct VoiceChange; struct VoicePropsItem; -using uint = unsigned int; - constexpr float SpeedOfSoundMetersPerSec{343.3f}; @@ -147,20 +144,20 @@ struct ContextBase { * in clusters that are stored in a vector for easy automatic cleanup. */ using VoiceChangeCluster = std::unique_ptr; - al::vector mVoiceChangeClusters; + std::vector mVoiceChangeClusters; using VoiceCluster = std::unique_ptr; - al::vector mVoiceClusters; + std::vector mVoiceClusters; using VoicePropsCluster = std::unique_ptr; - al::vector mVoicePropClusters; + std::vector mVoicePropClusters; static constexpr size_t EffectSlotClusterSize{4}; EffectSlot *getEffectSlot(); using EffectSlotCluster = std::unique_ptr; - al::vector mEffectSlotClusters; + std::vector mEffectSlotClusters; ContextBase(DeviceBase *device); diff --git a/core/device.h b/core/device.h index bc180582..33cdfe89 100644 --- a/core/device.h +++ b/core/device.h @@ -1,14 +1,12 @@ #ifndef CORE_DEVICE_H #define CORE_DEVICE_H -#include - #include #include #include #include #include -#include +#include #include #include -- cgit v1.2.3 From e7ea579ca5f3c0da6cfe80ec9a7295bca60198aa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 12 May 2023 18:02:12 -0700 Subject: Avoid using al::vector unnecessarily --- al/auxeffectslot.cpp | 8 +++---- al/buffer.cpp | 5 +++-- al/effect.cpp | 4 ++-- al/error.cpp | 4 ++-- al/filter.cpp | 4 ++-- al/source.cpp | 13 ++++++------ alc/alc.cpp | 12 +++++------ alc/backends/alsa.cpp | 16 +++++++------- alc/backends/coreaudio.cpp | 4 ++-- alc/backends/dsound.cpp | 9 ++++---- alc/backends/jack.cpp | 5 +++-- alc/backends/oss.cpp | 14 ++++++------ alc/backends/pulseaudio.cpp | 6 +++--- alc/backends/solaris.cpp | 4 ++-- alc/backends/wasapi.cpp | 18 ++++++++-------- alc/backends/wave.cpp | 4 ++-- alc/backends/winmm.cpp | 2 +- alc/context.h | 6 +++--- alc/device.h | 10 ++++----- alc/effects/chorus.cpp | 4 ++-- alc/effects/echo.cpp | 6 +++--- alc/panning.cpp | 3 ++- core/bformatdec.h | 4 ++-- core/hrtf.cpp | 52 ++++++++++++++++++++++----------------------- core/hrtf.h | 4 ++-- core/logging.cpp | 4 ++-- 26 files changed, 115 insertions(+), 110 deletions(-) (limited to 'alc/backends') diff --git a/al/auxeffectslot.cpp b/al/auxeffectslot.cpp index c69990fe..3a3222b8 100644 --- a/al/auxeffectslot.cpp +++ b/al/auxeffectslot.cpp @@ -341,7 +341,7 @@ START_API_FUNC } else { - al::vector ids; + std::vector ids; ALsizei count{n}; ids.reserve(static_cast(count)); do { @@ -383,7 +383,7 @@ START_API_FUNC } else { - auto slots = al::vector(static_cast(n)); + auto slots = std::vector(static_cast(n)); for(size_t i{0};i < slots.size();++i) { ALeffectslot *slot{LookupEffectSlot(context.get(), effectslots[i])}; @@ -466,7 +466,7 @@ START_API_FUNC context->setError(AL_INVALID_VALUE, "Playing %d effect slots", n); if(n <= 0) UNLIKELY return; - auto slots = al::vector(static_cast(n)); + auto slots = std::vector(static_cast(n)); std::lock_guard _{context->mEffectSlotLock}; for(size_t i{0};i < slots.size();++i) { @@ -520,7 +520,7 @@ START_API_FUNC context->setError(AL_INVALID_VALUE, "Stopping %d effect slots", n); if(n <= 0) UNLIKELY return; - auto slots = al::vector(static_cast(n)); + auto slots = std::vector(static_cast(n)); std::lock_guard _{context->mEffectSlotLock}; for(size_t i{0};i < slots.size();++i) { diff --git a/al/buffer.cpp b/al/buffer.cpp index 1f008c8e..bfc10906 100644 --- a/al/buffer.cpp +++ b/al/buffer.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include "AL/al.h" #include "AL/alc.h" @@ -345,7 +346,7 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, ALuint size, */ if(newsize != ALBuf->mDataStorage.size()) { - auto newdata = al::vector(newsize, std::byte{}); + auto newdata = decltype(ALBuf->mDataStorage)(newsize, std::byte{}); if((access&AL_PRESERVE_DATA_BIT_SOFT)) { const size_t tocopy{minz(newdata.size(), ALBuf->mDataStorage.size())}; @@ -663,7 +664,7 @@ START_API_FUNC /* Store the allocated buffer IDs in a separate local list, to avoid * modifying the user storage in case of failure. */ - al::vector ids; + std::vector ids; ids.reserve(static_cast(n)); do { ALbuffer *buffer{AllocBuffer(device)}; diff --git a/al/effect.cpp b/al/effect.cpp index 3d91139a..3ca7c37e 100644 --- a/al/effect.cpp +++ b/al/effect.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include "AL/al.h" #include "AL/alc.h" @@ -49,7 +50,6 @@ #include "core/except.h" #include "core/logging.h" #include "opthelpers.h" -#include "vector.h" #ifdef ALSOFT_EAX #include @@ -259,7 +259,7 @@ START_API_FUNC /* Store the allocated buffer IDs in a separate local list, to avoid * modifying the user storage in case of failure. */ - al::vector ids; + std::vector ids; ids.reserve(static_cast(n)); do { ALeffect *effect{AllocEffect(device)}; diff --git a/al/error.cpp b/al/error.cpp index 39fd9f0a..b0607d66 100644 --- a/al/error.cpp +++ b/al/error.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include "AL/al.h" #include "AL/alc.h" @@ -41,14 +42,13 @@ #include "core/except.h" #include "core/logging.h" #include "opthelpers.h" -#include "vector.h" bool TrapALError{false}; void ALCcontext::setError(ALenum errorCode, const char *msg, ...) { - auto message = al::vector(256); + auto message = std::vector(256); va_list args, args2; va_start(args, msg); diff --git a/al/filter.cpp b/al/filter.cpp index 0fd8eaa8..11d71179 100644 --- a/al/filter.cpp +++ b/al/filter.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include "AL/al.h" #include "AL/alc.h" @@ -43,7 +44,6 @@ #include "alnumeric.h" #include "core/except.h" #include "opthelpers.h" -#include "vector.h" namespace { @@ -430,7 +430,7 @@ START_API_FUNC /* Store the allocated buffer IDs in a separate local list, to avoid * modifying the user storage in case of failure. */ - al::vector ids; + std::vector ids; ids.reserve(static_cast(n)); do { ALfilter *filter{AllocFilter(device)}; diff --git a/al/source.cpp b/al/source.cpp index efe65332..1bfd5a94 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include "AL/al.h" #include "AL/alc.h" @@ -2659,7 +2660,7 @@ START_API_FUNC } else { - al::vector ids; + std::vector ids; ids.reserve(static_cast(n)); do { ALsource *source{AllocSource(context.get())}; @@ -3223,7 +3224,7 @@ START_API_FUNC context->setError(AL_INVALID_VALUE, "Playing %d sources", n); if(n <= 0) UNLIKELY return; - al::vector extra_sources; + std::vector extra_sources; std::array source_storage; al::span srchandles; if(static_cast(n) <= source_storage.size()) LIKELY @@ -3261,7 +3262,7 @@ START_API_FUNC if(start_time < 0) UNLIKELY return context->setError(AL_INVALID_VALUE, "Invalid time point %" PRId64, start_time); - al::vector extra_sources; + std::vector extra_sources; std::array source_storage; al::span srchandles; if(static_cast(n) <= source_storage.size()) LIKELY @@ -3301,7 +3302,7 @@ START_API_FUNC context->setError(AL_INVALID_VALUE, "Pausing %d sources", n); if(n <= 0) UNLIKELY return; - al::vector extra_sources; + std::vector extra_sources; std::array source_storage; al::span srchandles; if(static_cast(n) <= source_storage.size()) LIKELY @@ -3377,7 +3378,7 @@ START_API_FUNC context->setError(AL_INVALID_VALUE, "Stopping %d sources", n); if(n <= 0) UNLIKELY return; - al::vector extra_sources; + std::vector extra_sources; std::array source_storage; al::span srchandles; if(static_cast(n) <= source_storage.size()) LIKELY @@ -3440,7 +3441,7 @@ START_API_FUNC context->setError(AL_INVALID_VALUE, "Rewinding %d sources", n); if(n <= 0) UNLIKELY return; - al::vector extra_sources; + std::vector extra_sources; std::array source_storage; al::span srchandles; if(static_cast(n) <= source_storage.size()) LIKELY diff --git a/alc/alc.cpp b/alc/alc.cpp index 290cc3d1..9fedee0b 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -55,6 +55,7 @@ #include #include #include +#include #include "AL/al.h" #include "AL/alc.h" @@ -102,7 +103,6 @@ #include "opthelpers.h" #include "strutils.h" #include "threads.h" -#include "vector.h" #include "backends/base.h" #include "backends/null.h" @@ -1050,8 +1050,8 @@ using DeviceRef = al::intrusive_ptr; /************************************************ * Device lists ************************************************/ -al::vector DeviceList; -al::vector ContextList; +std::vector DeviceList; +std::vector ContextList; std::recursive_mutex ListLock; @@ -3130,7 +3130,7 @@ START_API_FUNC } if(!dev || dev->Type == DeviceType::Capture) { - auto ivals = al::vector(static_cast(size)); + auto ivals = std::vector(static_cast(size)); if(size_t got{GetIntegerv(dev.get(), pname, ivals)}) std::copy_n(ivals.begin(), got, values); return; @@ -3249,7 +3249,7 @@ START_API_FUNC break; default: - auto ivals = al::vector(static_cast(size)); + auto ivals = std::vector(static_cast(size)); if(size_t got{GetIntegerv(dev.get(), pname, ivals)}) std::copy_n(ivals.begin(), got, values); break; @@ -3676,7 +3676,7 @@ START_API_FUNC DeviceList.erase(iter); std::unique_lock statelock{dev->StateLock}; - al::vector orphanctxs; + std::vector orphanctxs; for(ContextBase *ctx : *dev->mContexts.load()) { auto ctxiter = std::lower_bound(ContextList.begin(), ContextList.end(), ctx); diff --git a/alc/backends/alsa.cpp b/alc/backends/alsa.cpp index c1690867..ce368f5e 100644 --- a/alc/backends/alsa.cpp +++ b/alc/backends/alsa.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include "albit.h" #include "alc/alconfig.h" @@ -46,7 +47,6 @@ #include "dynload.h" #include "ringbuffer.h" #include "threads.h" -#include "vector.h" #include @@ -248,8 +248,8 @@ struct DevMap { { } }; -al::vector PlaybackDevices; -al::vector CaptureDevices; +std::vector PlaybackDevices; +std::vector CaptureDevices; const char *prefix_name(snd_pcm_stream_t stream) @@ -258,9 +258,9 @@ const char *prefix_name(snd_pcm_stream_t stream) return (stream==SND_PCM_STREAM_PLAYBACK) ? "device-prefix" : "capture-prefix"; } -al::vector probe_devices(snd_pcm_stream_t stream) +std::vector probe_devices(snd_pcm_stream_t stream) { - al::vector devlist; + std::vector devlist; snd_ctl_card_info_t *info; snd_ctl_card_info_malloc(&info); @@ -439,7 +439,7 @@ struct AlsaPlayback final : public BackendBase { std::mutex mMutex; uint mFrameStep{}; - al::vector mBuffer; + std::vector mBuffer; std::atomic mKillNow{true}; std::thread mThread; @@ -880,7 +880,7 @@ struct AlsaCapture final : public BackendBase { snd_pcm_t *mPcmHandle{nullptr}; - al::vector mBuffer; + std::vector mBuffer; bool mDoCapture{false}; RingBufferPtr mRing{nullptr}; @@ -1024,7 +1024,7 @@ void AlsaCapture::stop() /* The ring buffer implicitly captures when checking availability. * Direct access needs to explicitly capture it into temp storage. */ - auto temp = al::vector( + auto temp = std::vector( static_cast(snd_pcm_frames_to_bytes(mPcmHandle, avail))); captureSamples(temp.data(), avail); mBuffer = std::move(temp); diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index c2a79815..521f085d 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -25,13 +25,13 @@ #include #include #include -#include #include #include #include #include #include #include +#include #include "alnumeric.h" #include "core/converter.h" @@ -578,7 +578,7 @@ struct CoreAudioCapture final : public BackendBase { SampleConverterPtr mConverter; - al::vector mCaptureData; + std::vector mCaptureData; RingBufferPtr mRing{nullptr}; diff --git a/alc/backends/dsound.cpp b/alc/backends/dsound.cpp index ffcd8430..5fc8a1c7 100644 --- a/alc/backends/dsound.cpp +++ b/alc/backends/dsound.cpp @@ -46,6 +46,7 @@ #include "albit.h" #include "alnumeric.h" +#include "alspan.h" #include "comptr.h" #include "core/device.h" #include "core/helpers.h" @@ -130,10 +131,10 @@ struct DevMap { { } }; -al::vector PlaybackDevices; -al::vector CaptureDevices; +std::vector PlaybackDevices; +std::vector CaptureDevices; -bool checkName(const al::vector &list, const std::string &name) +bool checkName(const al::span list, const std::string &name) { auto match_name = [&name](const DevMap &entry) -> bool { return entry.name == name; }; @@ -145,7 +146,7 @@ BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHAR*, voi if(!guid) return TRUE; - auto& devices = *static_cast*>(data); + auto& devices = *static_cast*>(data); const std::string basename{DEVNAME_HEAD + wstr_to_utf8(desc)}; int count{1}; diff --git a/alc/backends/jack.cpp b/alc/backends/jack.cpp index b12edf9f..9e023e21 100644 --- a/alc/backends/jack.cpp +++ b/alc/backends/jack.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include "albit.h" #include "alc/alconfig.h" @@ -168,10 +169,10 @@ struct DeviceEntry { { } }; -al::vector PlaybackList; +std::vector PlaybackList; -void EnumerateDevices(jack_client_t *client, al::vector &list) +void EnumerateDevices(jack_client_t *client, std::vector &list) { std::remove_reference_t{}.swap(list); diff --git a/alc/backends/oss.cpp b/alc/backends/oss.cpp index 1fdee701..dc18c4c3 100644 --- a/alc/backends/oss.cpp +++ b/alc/backends/oss.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include "alc/alconfig.h" #include "almalloc.h" @@ -47,7 +48,6 @@ #include "core/logging.h" #include "ringbuffer.h" #include "threads.h" -#include "vector.h" #include @@ -88,22 +88,22 @@ struct DevMap { std::string device_name; }; -al::vector PlaybackDevices; -al::vector CaptureDevices; +std::vector PlaybackDevices; +std::vector CaptureDevices; #ifdef ALC_OSS_COMPAT #define DSP_CAP_OUTPUT 0x00020000 #define DSP_CAP_INPUT 0x00010000 -void ALCossListPopulate(al::vector &devlist, int type) +void ALCossListPopulate(std::vector &devlist, int type) { devlist.emplace_back(DevMap{DefaultName, (type==DSP_CAP_INPUT) ? DefaultCapture : DefaultPlayback}); } #else -void ALCossListAppend(al::vector &list, al::span handle, al::span path) +void ALCossListAppend(std::vector &list, al::span handle, al::span path) { #ifdef ALC_OSS_DEVNODE_TRUC for(size_t i{0};i < path.size();++i) @@ -148,7 +148,7 @@ void ALCossListAppend(al::vector &list, al::span handle, al: TRACE("Got device \"%s\", \"%s\"\n", entry.name.c_str(), entry.device_name.c_str()); } -void ALCossListPopulate(al::vector &devlist, int type_flag) +void ALCossListPopulate(std::vector &devlist, int type_flag) { int fd{open("/dev/mixer", O_RDONLY)}; if(fd < 0) @@ -234,7 +234,7 @@ struct OSSPlayback final : public BackendBase { int mFd{-1}; - al::vector mMixData; + std::vector mMixData; std::atomic mKillNow{true}; std::thread mThread; diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index e5696817..d2883f5c 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include "albit.h" #include "alc/alconfig.h" @@ -49,7 +50,6 @@ #include "dynload.h" #include "opthelpers.h" #include "strutils.h" -#include "vector.h" #include @@ -282,8 +282,8 @@ bool checkName(const al::span list, const std::string &name) return std::find_if(list.cbegin(), list.cend(), match_name) != list.cend(); } -al::vector PlaybackDevices; -al::vector CaptureDevices; +std::vector PlaybackDevices; +std::vector CaptureDevices; /* Global flags and properties */ diff --git a/alc/backends/solaris.cpp b/alc/backends/solaris.cpp index 4eeeafac..ae87e7eb 100644 --- a/alc/backends/solaris.cpp +++ b/alc/backends/solaris.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -44,7 +45,6 @@ #include "core/helpers.h" #include "core/logging.h" #include "threads.h" -#include "vector.h" #include @@ -70,7 +70,7 @@ struct SolarisBackend final : public BackendBase { int mFd{-1}; uint mFrameStep{}; - al::vector mBuffer; + std::vector mBuffer; std::atomic mKillNow{true}; std::thread mThread; diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 97f0a291..d4ad38e2 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -59,6 +59,7 @@ #include "albit.h" #include "alc/alconfig.h" #include "alnumeric.h" +#include "alspan.h" #include "comptr.h" #include "core/converter.h" #include "core/device.h" @@ -180,15 +181,14 @@ struct DevMap { { } }; -bool checkName(const al::vector &list, const std::string &name) +bool checkName(const al::span list, const std::string &name) { - auto match_name = [&name](const DevMap &entry) -> bool - { return entry.name == name; }; + auto match_name = [&name](const DevMap &entry) -> bool { return entry.name == name; }; return std::find_if(list.cbegin(), list.cend(), match_name) != list.cend(); } -al::vector PlaybackDevices; -al::vector CaptureDevices; +std::vector PlaybackDevices; +std::vector CaptureDevices; using NameGUIDPair = std::pair; @@ -262,7 +262,7 @@ EndpointFormFactor get_device_formfactor(IMMDevice *device) } -void add_device(IMMDevice *device, const WCHAR *devid, al::vector &list) +void add_device(IMMDevice *device, const WCHAR *devid, std::vector &list) { for(auto &entry : list) { @@ -301,9 +301,9 @@ WCHAR *get_device_id(IMMDevice *device) return devid; } -void probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, al::vector &list) +void probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, std::vector &list) { - al::vector{}.swap(list); + std::vector{}.swap(list); ComPtr coll; HRESULT hr{devenum->EnumAudioEndpoints(flowdir, DEVICE_STATE_ACTIVE, al::out_ptr(coll))}; @@ -1355,7 +1355,7 @@ FORCE_ALIGN int WasapiCapture::recordProc() althrd_setname(RECORD_THREAD_NAME); - al::vector samples; + std::vector samples; while(!mKillNow.load(std::memory_order_relaxed)) { UINT32 avail; diff --git a/alc/backends/wave.cpp b/alc/backends/wave.cpp index f8302f1e..1ee2fe51 100644 --- a/alc/backends/wave.cpp +++ b/alc/backends/wave.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include "albit.h" #include "alc/alconfig.h" @@ -43,7 +44,6 @@ #include "opthelpers.h" #include "strutils.h" #include "threads.h" -#include "vector.h" namespace { @@ -104,7 +104,7 @@ struct WaveBackend final : public BackendBase { FILE *mFile{nullptr}; long mDataStart{-1}; - al::vector mBuffer; + std::vector mBuffer; std::atomic mKillNow{true}; std::thread mThread; diff --git a/alc/backends/winmm.cpp b/alc/backends/winmm.cpp index edb875a0..0345fe10 100644 --- a/alc/backends/winmm.cpp +++ b/alc/backends/winmm.cpp @@ -58,7 +58,7 @@ namespace { std::vector PlaybackDevices; std::vector CaptureDevices; -bool checkName(const al::vector &list, const std::string &name) +bool checkName(const std::vector &list, const std::string &name) { return std::find(list.cbegin(), list.cend(), name) != list.cend(); } void ProbePlaybackDevices(void) diff --git a/alc/context.h b/alc/context.h index acbb3788..779be113 100644 --- a/alc/context.h +++ b/alc/context.h @@ -9,6 +9,7 @@ #include #include #include +#include #include "AL/al.h" #include "AL/alc.h" @@ -21,7 +22,6 @@ #include "core/context.h" #include "inprogext.h" #include "intrusive_ptr.h" -#include "vector.h" #ifdef ALSOFT_EAX #include "al/eax/call.h" @@ -132,11 +132,11 @@ struct ALCcontext : public al::intrusive_ref, ContextBase { ALlistener mListener{}; - al::vector mSourceList; + std::vector mSourceList; ALuint mNumSources{0}; std::mutex mSourceLock; - al::vector mEffectSlotList; + std::vector mEffectSlotList; ALuint mNumEffectSlots{0u}; std::mutex mEffectSlotLock; diff --git a/alc/device.h b/alc/device.h index d5e82ce3..1274e287 100644 --- a/alc/device.h +++ b/alc/device.h @@ -8,6 +8,7 @@ #include #include #include +#include #include "AL/alc.h" #include "AL/alext.h" @@ -18,7 +19,6 @@ #include "core/device.h" #include "inprogext.h" #include "intrusive_ptr.h" -#include "vector.h" #ifdef ALSOFT_EAX #include "al/eax/x_ram.h" @@ -95,7 +95,7 @@ struct ALCdevice : public al::intrusive_ref, DeviceBase { uint AuxiliaryEffectSlotMax{}; std::string mHrtfName; - al::vector mHrtfList; + std::vector mHrtfList; ALCenum mHrtfStatus{ALC_FALSE}; enum class OutputMode1 : ALCenum { @@ -118,15 +118,15 @@ struct ALCdevice : public al::intrusive_ref, DeviceBase { // Map of Buffers for this device std::mutex BufferLock; - al::vector BufferList; + std::vector BufferList; // Map of Effects for this device std::mutex EffectLock; - al::vector EffectList; + std::vector EffectList; // Map of Filters for this device std::mutex FilterLock; - al::vector FilterList; + std::vector FilterList; #ifdef ALSOFT_EAX ALuint eax_x_ram_free_size{eax_x_ram_max_size}; diff --git a/alc/effects/chorus.cpp b/alc/effects/chorus.cpp index 10ccf9f6..7c281aa5 100644 --- a/alc/effects/chorus.cpp +++ b/alc/effects/chorus.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include "alc/effects/base.h" #include "almalloc.h" @@ -41,7 +42,6 @@ #include "core/resampler_limits.h" #include "intrusive_ptr.h" #include "opthelpers.h" -#include "vector.h" namespace { @@ -49,7 +49,7 @@ namespace { using uint = unsigned int; struct ChorusState final : public EffectState { - al::vector mDelayBuffer; + std::vector mDelayBuffer; uint mOffset{0}; uint mLfoOffset{0}; diff --git a/alc/effects/echo.cpp b/alc/effects/echo.cpp index a69529dc..7824c246 100644 --- a/alc/effects/echo.cpp +++ b/alc/effects/echo.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include "alc/effects/base.h" #include "almalloc.h" @@ -39,7 +40,6 @@ #include "core/mixer.h" #include "intrusive_ptr.h" #include "opthelpers.h" -#include "vector.h" namespace { @@ -49,7 +49,7 @@ using uint = unsigned int; constexpr float LowpassFreqRef{5000.0f}; struct EchoState final : public EffectState { - al::vector mSampleBuffer; + std::vector mSampleBuffer; // The echo is two tap. The delay is the number of samples from before the // current offset @@ -87,7 +87,7 @@ void EchoState::deviceUpdate(const DeviceBase *Device, const BufferStorage*) const uint maxlen{NextPowerOf2(float2uint(EchoMaxDelay*frequency + 0.5f) + float2uint(EchoMaxLRDelay*frequency + 0.5f))}; if(maxlen != mSampleBuffer.size()) - al::vector(maxlen).swap(mSampleBuffer); + decltype(mSampleBuffer)(maxlen).swap(mSampleBuffer); std::fill(mSampleBuffer.begin(), mSampleBuffer.end(), 0.0f); for(auto &e : mGains) diff --git a/alc/panning.cpp b/alc/panning.cpp index 60ce7ca4..6fc955ee 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include "AL/al.h" #include "AL/alc.h" @@ -628,7 +629,7 @@ void InitPanning(ALCdevice *device, const bool hqdec=false, const bool stablize= const size_t ambicount{decoder.mIs3D ? AmbiChannelsFromOrder(decoder.mOrder) : Ambi2DChannelsFromOrder(decoder.mOrder)}; const bool dual_band{hqdec && !decoder.mCoeffsLF.empty()}; - al::vector chancoeffs, chancoeffslf; + std::vector chancoeffs, chancoeffslf; for(size_t i{0u};i < decoder.mChannels.size();++i) { const uint idx{device->channelIdxByName(decoder.mChannels[i])}; diff --git a/core/bformatdec.h b/core/bformatdec.h index 7a27a5a4..42024bd9 100644 --- a/core/bformatdec.h +++ b/core/bformatdec.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "almalloc.h" #include "alspan.h" @@ -11,7 +12,6 @@ #include "bufferline.h" #include "devformat.h" #include "filters/splitter.h" -#include "vector.h" struct FrontStablizer; @@ -43,7 +43,7 @@ class BFormatDec { * only be used in a standard layout struct, and a std::unique_ptr member * (mStablizer) causes GCC and Clang to warn it's not. */ - al::vector mChannelDec; + std::vector mChannelDec; public: BFormatDec(const size_t inchans, const al::span coeffs, diff --git a/core/hrtf.cpp b/core/hrtf.cpp index 607e3d3d..7d11ee19 100644 --- a/core/hrtf.cpp +++ b/core/hrtf.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "albit.h" #include "alfstream.h" @@ -34,7 +35,6 @@ #include "mixer/hrtfdefs.h" #include "opthelpers.h" #include "polyphase_resampler.h" -#include "vector.h" namespace { @@ -98,10 +98,10 @@ constexpr char magicMarker03[8]{'M','i','n','P','H','R','0','3'}; constexpr auto PassthruCoeff = static_cast(1.0/al::numbers::sqrt2); std::mutex LoadedHrtfLock; -al::vector LoadedHrtfs; +std::vector LoadedHrtfs; std::mutex EnumeratedHrtfLock; -al::vector EnumeratedHrtfs; +std::vector EnumeratedHrtfs; class databuf final : public std::streambuf { @@ -295,7 +295,7 @@ void DirectHrtfState::build(const HrtfStore *Hrtf, const uint irSize, const bool } uint min_delay{HrtfHistoryLength*HrirDelayFracOne}, max_delay{0}; - al::vector impres; impres.reserve(AmbiPoints.size()); + std::vector impres; impres.reserve(AmbiPoints.size()); auto calc_res = [Hrtf,&max_delay,&min_delay](const AngularPoint &pt) -> ImpulseResponse { auto &field = Hrtf->mFields[0]; @@ -331,7 +331,7 @@ void DirectHrtfState::build(const HrtfStore *Hrtf, const uint irSize, const bool TRACE("Min delay: %.2f, max delay: %.2f, FIR length: %u\n", min_delay/double{HrirDelayFracOne}, max_delay/double{HrirDelayFracOne}, irSize); - auto tmpres = al::vector>(mChannels.size()); + auto tmpres = std::vector>(mChannels.size()); max_delay = 0; for(size_t c{0u};c < AmbiPoints.size();++c) { @@ -529,7 +529,7 @@ std::unique_ptr LoadHrtf00(std::istream &data, const char *filename) return nullptr; } - auto elevs = al::vector(evCount); + auto elevs = std::vector(evCount); for(auto &elev : elevs) elev.irOffset = readle(data); if(!data || data.eof()) @@ -571,8 +571,8 @@ std::unique_ptr LoadHrtf00(std::istream &data, const char *filename) return nullptr; } - auto coeffs = al::vector(irCount, HrirArray{}); - auto delays = al::vector(irCount); + auto coeffs = std::vector(irCount, HrirArray{}); + auto delays = std::vector(irCount); for(auto &hrir : coeffs) { for(auto &val : al::span{hrir.data(), irSize}) @@ -626,7 +626,7 @@ std::unique_ptr LoadHrtf01(std::istream &data, const char *filename) return nullptr; } - auto elevs = al::vector(evCount); + auto elevs = std::vector(evCount); for(auto &elev : elevs) elev.azCount = readle(data); if(!data || data.eof()) @@ -649,8 +649,8 @@ std::unique_ptr LoadHrtf01(std::istream &data, const char *filename) elevs[i].irOffset = static_cast(elevs[i-1].irOffset + elevs[i-1].azCount); const ushort irCount{static_cast(elevs.back().irOffset + elevs.back().azCount)}; - auto coeffs = al::vector(irCount, HrirArray{}); - auto delays = al::vector(irCount); + auto coeffs = std::vector(irCount, HrirArray{}); + auto delays = std::vector(irCount); for(auto &hrir : coeffs) { for(auto &val : al::span{hrir.data(), irSize}) @@ -722,8 +722,8 @@ std::unique_ptr LoadHrtf02(std::istream &data, const char *filename) return nullptr; } - auto fields = al::vector(fdCount); - auto elevs = al::vector{}; + auto fields = std::vector(fdCount); + auto elevs = std::vector{}; for(size_t f{0};f < fdCount;f++) { const ushort distance{readle(data)}; @@ -787,8 +787,8 @@ std::unique_ptr LoadHrtf02(std::istream &data, const char *filename) }); const auto irTotal = static_cast(elevs.back().azCount + elevs.back().irOffset); - auto coeffs = al::vector(irTotal, HrirArray{}); - auto delays = al::vector(irTotal); + auto coeffs = std::vector(irTotal, HrirArray{}); + auto delays = std::vector(irTotal); if(channelType == ChanType_LeftOnly) { if(sampleType == SampleType_S16) @@ -881,10 +881,10 @@ std::unique_ptr LoadHrtf02(std::istream &data, const char *filename) if(fdCount > 1) { - auto fields_ = al::vector(fields.size()); - auto elevs_ = al::vector(elevs.size()); - auto coeffs_ = al::vector(coeffs.size()); - auto delays_ = al::vector(delays.size()); + auto fields_ = std::vector(fields.size()); + auto elevs_ = std::vector(elevs.size()); + auto coeffs_ = std::vector(coeffs.size()); + auto delays_ = std::vector(delays.size()); /* Simple reverse for the per-field elements. */ std::reverse_copy(fields.cbegin(), fields.cend(), fields_.begin()); @@ -983,8 +983,8 @@ std::unique_ptr LoadHrtf03(std::istream &data, const char *filename) return nullptr; } - auto fields = al::vector(fdCount); - auto elevs = al::vector{}; + auto fields = std::vector(fdCount); + auto elevs = std::vector{}; for(size_t f{0};f < fdCount;f++) { const ushort distance{readle(data)}; @@ -1048,8 +1048,8 @@ std::unique_ptr LoadHrtf03(std::istream &data, const char *filename) }); const auto irTotal = static_cast(elevs.back().azCount + elevs.back().irOffset); - auto coeffs = al::vector(irTotal, HrirArray{}); - auto delays = al::vector(irTotal); + auto coeffs = std::vector(irTotal, HrirArray{}); + auto delays = std::vector(irTotal); if(channelType == ChanType_LeftOnly) { for(auto &hrir : coeffs) @@ -1221,7 +1221,7 @@ al::span GetResource(int name) } // namespace -al::vector EnumerateHrtf(std::optional pathopt) +std::vector EnumerateHrtf(std::optional pathopt) { std::lock_guard _{EnumeratedHrtfLock}; EnumeratedHrtfs.clear(); @@ -1270,7 +1270,7 @@ al::vector EnumerateHrtf(std::optional pathopt) AddBuiltInEntry("Built-In HRTF", IDR_DEFAULT_HRTF_MHR); } - al::vector list; + std::vector list; list.reserve(EnumeratedHrtfs.size()); for(auto &entry : EnumeratedHrtfs) list.emplace_back(entry.mDispName); @@ -1394,7 +1394,7 @@ HrtfStorePtr GetLoadedHrtf(const std::string &name, const uint devrate) /* Scale the delays for the new sample rate. */ float max_delay{0.0f}; - auto new_delays = al::vector(irCount); + auto new_delays = std::vector(irCount); const float rate_scale{static_cast(devrate)/static_cast(hrtf->mSampleRate)}; for(size_t i{0};i < irCount;++i) { diff --git a/core/hrtf.h b/core/hrtf.h index 7215711b..5e6e09a8 100644 --- a/core/hrtf.h +++ b/core/hrtf.h @@ -6,6 +6,7 @@ #include #include #include +#include #include "almalloc.h" #include "alspan.h" @@ -14,7 +15,6 @@ #include "bufferline.h" #include "mixer/hrtfdefs.h" #include "intrusive_ptr.h" -#include "vector.h" struct HrtfStore { @@ -83,7 +83,7 @@ struct DirectHrtfState { }; -al::vector EnumerateHrtf(std::optional pathopt); +std::vector EnumerateHrtf(std::optional pathopt); HrtfStorePtr GetLoadedHrtf(const std::string &name, const uint devrate); #endif /* CORE_HRTF_H */ diff --git a/core/logging.cpp b/core/logging.cpp index 8e0116ea..34385cf4 100644 --- a/core/logging.cpp +++ b/core/logging.cpp @@ -6,10 +6,10 @@ #include #include #include +#include #include "alspan.h" #include "strutils.h" -#include "vector.h" #if defined(_WIN32) @@ -34,7 +34,7 @@ void al_print(LogLevel level, FILE *logfile, const char *fmt, ...) case LogLevel::Trace: prefix = al::span{"[ALSOFT] (II) "}.first<14>(); break; } - al::vector dynmsg; + std::vector dynmsg; std::array stcmsg{}; char *str{stcmsg.data()}; -- cgit v1.2.3 From 68908eebbec50ed8f4343f93fd8cd52427ea7ca8 Mon Sep 17 00:00:00 2001 From: "Deal(一线灵)" Date: Fri, 26 May 2023 00:23:24 +0800 Subject: Improve oboe backend (#848) * Improve oboe backend This change should handle handphone call event properly and fix crash at stop (because the mStream was disconnected by system when handphone call income) * Invoke mDevice->handleDisconnect when AAudio stream disconnected --- alc/backends/oboe.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'alc/backends') diff --git a/alc/backends/oboe.cpp b/alc/backends/oboe.cpp index c74b0180..01d6fb85 100644 --- a/alc/backends/oboe.cpp +++ b/alc/backends/oboe.cpp @@ -5,7 +5,6 @@ #include #include -#include #include #include "alnumeric.h" @@ -29,6 +28,8 @@ struct OboePlayback final : public BackendBase, public oboe::AudioStreamCallback oboe::DataCallbackResult onAudioReady(oboe::AudioStream *oboeStream, void *audioData, int32_t numFrames) override; + void onErrorAfterClose(oboe::AudioStream* /* audioStream */, oboe::Result /* error */) override; + void open(const char *name) override; bool reset() override; void start() override; @@ -47,6 +48,13 @@ oboe::DataCallbackResult OboePlayback::onAudioReady(oboe::AudioStream *oboeStrea return oboe::DataCallbackResult::Continue; } +void OboePlayback::onErrorAfterClose(oboe::AudioStream* audioStream, oboe::Result error) +{ + if (error == oboe::Result::ErrorDisconnected) { + mDevice->handleDisconnect("Oboe AudioStream was disconnected: %s", oboe::convertToText(error)); + } + TRACE("Error was %s", oboe::convertToText(error)); +} void OboePlayback::open(const char *name) { -- cgit v1.2.3 From 453677bc983a5c17a6d4426e845114bb7be9b770 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 25 May 2023 23:00:10 -0700 Subject: Don't throw when failing to stop Oboe playback --- alc/backends/oboe.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/oboe.cpp b/alc/backends/oboe.cpp index 01d6fb85..a0d806c8 100644 --- a/alc/backends/oboe.cpp +++ b/alc/backends/oboe.cpp @@ -206,8 +206,7 @@ void OboePlayback::stop() { oboe::Result result{mStream->stop()}; if(result != oboe::Result::OK) - throw al::backend_exception{al::backend_error::DeviceError, "Failed to stop stream: %s", - oboe::convertToText(result)}; + ERR("Failed to stop stream: %s\n", oboe::convertToText(result)); } -- cgit v1.2.3 From 2e75909ce90027267775d53e997d4936d6ef31a5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 30 May 2023 13:45:53 -0700 Subject: Don't throw when failing to stop Oboe capture --- alc/backends/oboe.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/oboe.cpp b/alc/backends/oboe.cpp index a0d806c8..cc44b867 100644 --- a/alc/backends/oboe.cpp +++ b/alc/backends/oboe.cpp @@ -323,8 +323,7 @@ void OboeCapture::stop() { const oboe::Result result{mStream->stop()}; if(result != oboe::Result::OK) - throw al::backend_exception{al::backend_error::DeviceError, "Failed to stop stream: %s", - oboe::convertToText(result)}; + ERR("Failed to stop stream: %s\n", oboe::convertToText(result)); } uint OboeCapture::availableSamples() -- cgit v1.2.3 From 3caadcf616074c6bedcd45e8af2854379f08e275 Mon Sep 17 00:00:00 2001 From: "Deal(一线灵)" Date: Wed, 31 May 2023 15:24:11 +0800 Subject: Improve wasapi backend UWP support (#853) * Improve wasapi, support uwp build * Fix compile errors * [UWP] Support ReadALConfig from app roaming * [UWP] Post disconnect event when default device changed * [UWP] Fix appveyor ci * [WIN32] Default device change notification support * Fix warnings * Add event to notify the app when the default device changes - Event type: AL_EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT=0x19A7 - Event callback parameters: void _onALSoftEvent(ALenum eventType, ALuint object, // dataFlow: 0(render), 1(capture) ALuint param, // 0 ALsizei length, // 0 const ALchar* message, // Default device changed: void* userParam); * Fix warnings * Fire default device changed event in mixerProc thread * Fix compile warning * [UWP] Improve cmake * Revert changes * Notify default device change by system event callback * Revert insignificant change * Remove duplicate call --- .github/workflows/ci.yml | 10 + CMakeLists.txt | 84 ++++-- alc/alconfig.cpp | 10 +- alc/backends/wasapi.cpp | 689 +++++++++++++++++++++++++++++++++++------------ config.h.in | 3 + core/async_event.h | 1 - core/helpers.cpp | 25 +- core/uiddefs.cpp | 2 +- router/router.cpp | 4 +- 9 files changed, 620 insertions(+), 208 deletions(-) (limited to 'alc/backends') diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a94c760..5309e1f4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,6 +50,16 @@ jobs: -DALSOFT_REQUIRE_WASAPI=ON", build_type: "Debug" } + - { + name: "Win64-UWP", + os: windows-latest, + cmake_opts: "-A x64 \ + -DCMAKE_SYSTEM_NAME=WindowsStore \ + \"-DCMAKE_SYSTEM_VERSION=10.0\" \ + -DALSOFT_BUILD_ROUTER=ON \ + -DALSOFT_REQUIRE_WASAPI=ON", + build_type: "Release" + } - { name: "macOS-Release", os: macos-latest, diff --git a/CMakeLists.txt b/CMakeLists.txt index 8df4be2a..02bf81b4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,8 @@ if(CMAKE_SYSTEM_NAME STREQUAL "iOS") FORCE) endif() endif() +elseif(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") + set(ALSOFT_UWP TRUE) endif() set(CMAKE_C_VISIBILITY_PRESET hidden) @@ -148,6 +150,8 @@ set(CPP_DEFS ) # C pre-processor, not C++ set(INC_PATHS ) set(C_FLAGS ) set(LINKER_FLAGS ) +set(LINKER_FLAGS_DEBUG ) +set(LINKER_FLAGS_RELEASE ) set(EXTRA_LIBS ) if(WIN32) @@ -1010,37 +1014,39 @@ endif() # Check Windows-only backends if(WIN32) - # Check MMSystem backend - option(ALSOFT_BACKEND_WINMM "Enable Windows Multimedia backend" ON) - option(ALSOFT_REQUIRE_WINMM "Require Windows Multimedia backend" OFF) - if(ALSOFT_BACKEND_WINMM) - set(HAVE_WINMM 1) - set(BACKENDS "${BACKENDS} WinMM,") - set(ALC_OBJS ${ALC_OBJS} alc/backends/winmm.cpp alc/backends/winmm.h) - # There doesn't seem to be good way to search for winmm.lib for MSVC. - # find_library doesn't find it without being told to look in a specific - # place in the WindowsSDK, but it links anyway. If there ends up being - # Windows targets without this, another means to detect it is needed. - set(EXTRA_LIBS winmm ${EXTRA_LIBS}) - endif() - - # Check DSound backend - option(ALSOFT_BACKEND_DSOUND "Enable DirectSound backend" ON) - option(ALSOFT_REQUIRE_DSOUND "Require DirectSound backend" OFF) - if(ALSOFT_BACKEND_DSOUND) - check_include_file(dsound.h HAVE_DSOUND_H) - if(DXSDK_DIR) - find_path(DSOUND_INCLUDE_DIR NAMES "dsound.h" - PATHS "${DXSDK_DIR}" PATH_SUFFIXES include - DOC "The DirectSound include directory") + if (NOT ALSOFT_UWP) + # Check MMSystem backend + option(ALSOFT_BACKEND_WINMM "Enable Windows Multimedia backend" ON) + option(ALSOFT_REQUIRE_WINMM "Require Windows Multimedia backend" OFF) + if(ALSOFT_BACKEND_WINMM) + set(HAVE_WINMM 1) + set(BACKENDS "${BACKENDS} WinMM,") + set(ALC_OBJS ${ALC_OBJS} alc/backends/winmm.cpp alc/backends/winmm.h) + # There doesn't seem to be good way to search for winmm.lib for MSVC. + # find_library doesn't find it without being told to look in a specific + # place in the WindowsSDK, but it links anyway. If there ends up being + # Windows targets without this, another means to detect it is needed. + set(EXTRA_LIBS winmm ${EXTRA_LIBS}) endif() - if(HAVE_DSOUND_H OR DSOUND_INCLUDE_DIR) - set(HAVE_DSOUND 1) - set(BACKENDS "${BACKENDS} DirectSound,") - set(ALC_OBJS ${ALC_OBJS} alc/backends/dsound.cpp alc/backends/dsound.h) - if(NOT HAVE_DSOUND_H) - set(INC_PATHS ${INC_PATHS} ${DSOUND_INCLUDE_DIR}) + # Check DSound backend + option(ALSOFT_BACKEND_DSOUND "Enable DirectSound backend" ON) + option(ALSOFT_REQUIRE_DSOUND "Require DirectSound backend" OFF) + if(ALSOFT_BACKEND_DSOUND) + check_include_file(dsound.h HAVE_DSOUND_H) + if(DXSDK_DIR) + find_path(DSOUND_INCLUDE_DIR NAMES "dsound.h" + PATHS "${DXSDK_DIR}" PATH_SUFFIXES include + DOC "The DirectSound include directory") + endif() + if(HAVE_DSOUND_H OR DSOUND_INCLUDE_DIR) + set(HAVE_DSOUND 1) + set(BACKENDS "${BACKENDS} DirectSound,") + set(ALC_OBJS ${ALC_OBJS} alc/backends/dsound.cpp alc/backends/dsound.h) + + if(NOT HAVE_DSOUND_H) + set(INC_PATHS ${INC_PATHS} ${DSOUND_INCLUDE_DIR}) + endif() endif() endif() endif() @@ -1054,8 +1060,19 @@ if(WIN32) set(HAVE_WASAPI 1) set(BACKENDS "${BACKENDS} WASAPI,") set(ALC_OBJS ${ALC_OBJS} alc/backends/wasapi.cpp alc/backends/wasapi.h) + if(ALSOFT_UWP) + set_source_files_properties(alc/backends/wasapi.cpp alc/alconfig.cpp PROPERTIES COMPILE_FLAGS /ZW) + endif() endif() endif() + + # Setup properly link flags for UWP + if(ALSOFT_UWP AND HAVE_WASAPI) + # Add compile and link flags required C++/CX + set(C_FLAGS "/Zc:twoPhase-" ${C_FLAGS}) + set(LINKER_FLAGS_DEBUG "/nodefaultlib:vccorlibd /nodefaultlib:msvcrtd vccorlibd.lib msvcrtd.lib ${LINKER_FLAGS_DEBUG}") + set(LINKER_FLAGS_RELEASE "/nodefaultlib:vccorlib /nodefaultlib:msvcrt vccorlib.lib msvcrt.lib ${LINKER_FLAGS_RELEASE}") + endif() endif() if(ALSOFT_REQUIRE_WINMM AND NOT HAVE_WINMM) message(FATAL_ERROR "Failed to enabled required WinMM backend") @@ -1399,6 +1416,15 @@ else() endif() target_link_libraries(${IMPL_TARGET} PRIVATE common ${LINKER_FLAGS} ${EXTRA_LIBS} ${MATH_LIB}) + if (WIN32) + set_target_properties(${IMPL_TARGET} PROPERTIES + LINK_FLAGS_DEBUG "${LINKER_FLAGS_DEBUG}" + LINK_FLAGS_RELEASE "${LINKER_FLAGS_RELEASE}" + LINK_FLAGS_MINSIZEREL "${LINKER_FLAGS_RELEASE}" + LINK_FLAGS_RELWITHDEBINFO "${LINKER_FLAGS_RELEASE}" + ) + endif() + if(NOT WIN32 AND NOT APPLE) # FIXME: This doesn't put a dependency on the version script. Changing # the version script will not cause a relink as it should. diff --git a/alc/alconfig.cpp b/alc/alconfig.cpp index 56cad9e0..3c9a9777 100644 --- a/alc/alconfig.cpp +++ b/alc/alconfig.cpp @@ -329,9 +329,14 @@ const char *GetConfigValue(const char *devName, const char *blockName, const cha #ifdef _WIN32 void ReadALConfig() { - WCHAR buffer[MAX_PATH]; - if(SHGetSpecialFolderPathW(nullptr, buffer, CSIDL_APPDATA, FALSE) != FALSE) { +#if !defined(ALSOFT_UWP) + WCHAR buffer[MAX_PATH]; + if (!SHGetSpecialFolderPathW(nullptr, buffer, CSIDL_APPDATA, FALSE)) + return; +#else + auto buffer = Windows::Storage::ApplicationData::Current->RoamingFolder->Path->Data(); +#endif std::string filepath{wstr_to_utf8(buffer)}; filepath += "\\alsoft.ini"; @@ -341,6 +346,7 @@ void ReadALConfig() LoadConfigFromFile(f); } + std::string ppath{GetProcBinary().path}; if(!ppath.empty()) { diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index d4ad38e2..c8c03e8a 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -58,6 +58,7 @@ #include "albit.h" #include "alc/alconfig.h" +#include "alc/events.h" #include "alnumeric.h" #include "alspan.h" #include "comptr.h" @@ -69,6 +70,14 @@ #include "strutils.h" #include "threads.h" +#if defined(ALSOFT_UWP) +#include +using namespace Platform; +using namespace Windows::Foundation; +using namespace Windows::Media::Devices; +using namespace Windows::Devices::Enumeration; +using namespace Windows::Media::Devices; +#endif /* Some headers seem to define these as macros for __uuidof, which is annoying * since some headers don't declare them at all. Hopefully the ifdef is enough @@ -80,11 +89,11 @@ DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x #ifndef KSDATAFORMAT_SUBTYPE_IEEE_FLOAT DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); #endif - +#if !defined(ALSOFT_UWP) DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14); DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0); DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23,0xe0, 0xc0,0xff,0xee,0x7f,0x0e, 4 ); - +#endif namespace { @@ -190,159 +199,504 @@ bool checkName(const al::span list, const std::string &name) std::vector PlaybackDevices; std::vector CaptureDevices; - -using NameGUIDPair = std::pair; -NameGUIDPair get_device_name_and_guid(IMMDevice *device) +#if defined(ALSOFT_UWP) +enum EDataFlow { - static constexpr char UnknownName[]{"Unknown Device Name"}; - static constexpr char UnknownGuid[]{"Unknown Device GUID"}; - std::string name, guid; + eRender = 0, + eCapture = (eRender + 1), + eAll = (eCapture + 1), + EDataFlow_enum_count = (eAll + 1) +}; +#endif - ComPtr ps; - HRESULT hr = device->OpenPropertyStore(STGM_READ, al::out_ptr(ps)); - if(FAILED(hr)) +#if defined(ALSOFT_UWP) +struct DeviceHandle +{ + DeviceHandle& operator=(std::nullptr_t) { - WARN("OpenPropertyStore failed: 0x%08lx\n", hr); - return std::make_pair(UnknownName, UnknownGuid); + value = nullptr; + return *this; } + DeviceInformation^ value{nullptr}; +}; +using EventRegistrationToken = Windows::Foundation::EventRegistrationToken; +#else +using DeviceHandle = ComPtr; +using EventRegistrationToken = void*; +#endif - PropVariant pvprop; - hr = ps->GetValue(al::bit_cast(DEVPKEY_Device_FriendlyName), pvprop.get()); - if(FAILED(hr)) - { - WARN("GetValue Device_FriendlyName failed: 0x%08lx\n", hr); - name += UnknownName; +#if defined(ALSOFT_UWP) +struct DeviceHelper final : public IActivateAudioInterfaceCompletionHandler +#else +struct DeviceHelper final : public IMMNotificationClient +#endif +{ +public: + DeviceHelper() + { +#if defined(ALSOFT_UWP) + mActiveClientEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); +#else + HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, + al::out_ptr(mEnumerator)); + if (SUCCEEDED(hr)) + mEnumerator->RegisterEndpointNotificationCallback(this); + else + WARN("Failed to create IMMDeviceEnumerator instance: 0x%08lx\n", hr); +#endif } - else if(pvprop->vt == VT_LPWSTR) - name += wstr_to_utf8(pvprop->pwszVal); - else + ~DeviceHelper() { - WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvprop->vt); - name += UnknownName; +#if defined(ALSOFT_UWP) + if (mActiveClientEvent != nullptr) + CloseHandle(mActiveClientEvent); + mActiveClientEvent = nullptr; +#else + if (mEnumerator) + mEnumerator->UnregisterEndpointNotificationCallback(this); + mEnumerator = nullptr; +#endif } - pvprop.clear(); - hr = ps->GetValue(al::bit_cast(PKEY_AudioEndpoint_GUID), pvprop.get()); - if(FAILED(hr)) + /** -------------------------- IUnkonwn ----------------------------- */ + LONG mRefCount{1}; + ULONG STDMETHODCALLTYPE AddRef() override { return InterlockedIncrement(&mRefCount); } + + ULONG STDMETHODCALLTYPE Release() override { - WARN("GetValue AudioEndpoint_GUID failed: 0x%08lx\n", hr); - guid = UnknownGuid; + ULONG ulRef = InterlockedDecrement(&mRefCount); + if (0 == ulRef) + { + delete this; + } + return ulRef; } - else if(pvprop->vt == VT_LPWSTR) - guid = wstr_to_utf8(pvprop->pwszVal); - else + + HRESULT STDMETHODCALLTYPE QueryInterface(const IID& IId, void** UnknownPtrPtr) override { - WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvprop->vt); - guid = UnknownGuid; - } + // Three rules of QueryInterface: + // https://docs.microsoft.com/en-us/windows/win32/com/rules-for-implementing-queryinterface + // 1. Objects must have identity. + // 2. The set of interfaces on an object instance must be static. + // 3. It must be possible to query successfully for any interface on an object from any other interface. - return std::make_pair(std::move(name), std::move(guid)); -} + // If ppvObject(the address) is nullptr, then this method returns E_POINTER. + if (!UnknownPtrPtr) + { + return E_POINTER; + } -EndpointFormFactor get_device_formfactor(IMMDevice *device) -{ - ComPtr ps; - HRESULT hr{device->OpenPropertyStore(STGM_READ, al::out_ptr(ps))}; - if(FAILED(hr)) - { - WARN("OpenPropertyStore failed: 0x%08lx\n", hr); - return UnknownFormFactor; + // https://docs.microsoft.com/en-us/windows/win32/com/implementing-reference-counting + // Whenever a client calls a method(or API function), such as QueryInterface, that returns a new interface + // pointer, the method being called is responsible for incrementing the reference count through the returned + // pointer. For example, when a client first creates an object, it receives an interface pointer to an object + // that, from the client's point of view, has a reference count of one. If the client then calls AddRef on the + // interface pointer, the reference count becomes two. The client must call Release twice on the interface + // pointer to drop all of its references to the object. +#if defined(ALSOFT_UWP) + if (IId == __uuidof(IActivateAudioInterfaceCompletionHandler)) + { + *UnknownPtrPtr = (IActivateAudioInterfaceCompletionHandler*)(this); + AddRef(); + return S_OK; + } +#else + if (IId == __uuidof(IMMNotificationClient)) + { + *UnknownPtrPtr = (IMMNotificationClient*)(this); + AddRef(); + return S_OK; + } +#endif + else if (IId == __uuidof(IAgileObject) || IId == __uuidof(IUnknown)) + { + *UnknownPtrPtr = (IUnknown*)(this); + AddRef(); + return S_OK; + } + + // This method returns S_OK if the interface is supported, and E_NOINTERFACE otherwise. + *UnknownPtrPtr = nullptr; + return E_NOINTERFACE; } - EndpointFormFactor formfactor{UnknownFormFactor}; - PropVariant pvform; - hr = ps->GetValue(PKEY_AudioEndpoint_FormFactor, pvform.get()); - if(FAILED(hr)) - WARN("GetValue AudioEndpoint_FormFactor failed: 0x%08lx\n", hr); - else if(pvform->vt == VT_UI4) - formfactor = static_cast(pvform->ulVal); - else if(pvform->vt != VT_EMPTY) - WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvform->vt); - return formfactor; -} +#if defined(ALSOFT_UWP) + /** ----------------------- IActivateAudioInterfaceCompletionHandler ------------ */ + HRESULT ActivateCompleted(IActivateAudioInterfaceAsyncOperation* operation) override + { + HRESULT hrActivateResult = S_OK; + IUnknown* punkAudioInterface = nullptr; + HRESULT hr = operation->GetActivateResult(&hrActivateResult, &punkAudioInterface); + // Check for a successful activation result + if (SUCCEEDED(hr) && SUCCEEDED(hrActivateResult)) + { + if (mPPV) + { + // Get the pointer for the Audio Client + IAudioClient3* audioClient; + punkAudioInterface->QueryInterface(IID_PPV_ARGS(&audioClient)); + *mPPV = audioClient; + } + } -void add_device(IMMDevice *device, const WCHAR *devid, std::vector &list) -{ - for(auto &entry : list) + SetEvent(mActiveClientEvent); + + // Need to return S_OK + return S_OK; + } +#else + /** ----------------------- IMMNotificationClient ------------ */ + STDMETHOD(OnDeviceStateChanged(LPCWSTR /*pwstrDeviceId*/, DWORD /*dwNewState*/)) override { return S_OK; } + STDMETHOD(OnDeviceAdded(LPCWSTR /*pwstrDeviceId*/)) override { return S_OK; } + STDMETHOD(OnDeviceRemoved(LPCWSTR /*pwstrDeviceId*/)) override { return S_OK; } + STDMETHOD(OnPropertyValueChanged(LPCWSTR /*pwstrDeviceId*/, const PROPERTYKEY /*key*/)) override { return S_OK; } + STDMETHOD(OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDefaultDeviceId)) override { - if(entry.devid == devid) - return; + if (role == eMultimedia && (flow == eRender || flow == eCapture)) + { + std::lock_guard lck(mDefaultChangeHandlersMtx); + for (auto& handlerItem : mDefaultChangeHandlers) + { + if (handlerItem.second.first == flow) + handlerItem.second.second(pwstrDefaultDeviceId); + } + } + return S_OK; } +#endif - auto name_guid = get_device_name_and_guid(device); + /** -------------------------- DeviceHelper ----------------------------- */ + HRESULT OpenDevice(LPCWSTR devid, EDataFlow flow, DeviceHandle& device) + { +#if !defined(ALSOFT_UWP) + HRESULT hr = E_POINTER; + if (mEnumerator) + { + if (!devid) + hr = mEnumerator->GetDefaultAudioEndpoint(flow, eMultimedia, al::out_ptr(device)); + else + hr = mEnumerator->GetDevice(devid, al::out_ptr(device)); + } + if (FAILED(hr)) + { + return hr; + } +#else + const auto deviceRole = Windows::Media::Devices::AudioDeviceRole::Default; + Platform::String^ devIfPath = + !devid ? (flow == eRender ? MediaDevice::GetDefaultAudioRenderId(deviceRole) : MediaDevice::GetDefaultAudioCaptureId(deviceRole)) + : ref new Platform::String(devid); + + Concurrency::task createDeviceOp( + DeviceInformation::CreateFromIdAsync(devIfPath, nullptr, DeviceInformationKind::DeviceInterface)); + auto status = createDeviceOp.then([&](DeviceInformation^ deviceInfo) { + device.value = deviceInfo; + }).wait(); + if (status != Concurrency::task_status::completed) + { + return E_NOINTERFACE; + } +#endif + return S_OK; + } - int count{1}; - std::string newname{name_guid.first}; - while(checkName(list, newname)) + HRESULT ActivateAudioClient(_In_ DeviceHandle& device, + void** ppv) { - newname = name_guid.first; - newname += " #"; - newname += std::to_string(++count); +#if !defined(ALSOFT_UWP) + HRESULT hr{device->Activate(__uuidof(IAudioClient3), CLSCTX_INPROC_SERVER, nullptr, ppv)}; +#else + HRESULT hr{ActivateAudioInterface(device.value->Id->Data(), + __uuidof(IAudioClient3), nullptr, ppv)}; +#endif + return hr; } - list.emplace_back(std::move(newname), std::move(name_guid.second), devid); - const DevMap &newentry = list.back(); - TRACE("Got device \"%s\", \"%s\", \"%ls\"\n", newentry.name.c_str(), - newentry.endpoint_guid.c_str(), newentry.devid.c_str()); -} + HRESULT probe_devices(EDataFlow flowdir, std::vector& list) + { + std::vector{}.swap(list); -WCHAR *get_device_id(IMMDevice *device) -{ - WCHAR *devid; +#if !defined(ALSOFT_UWP) + ComPtr coll; + HRESULT hr{mEnumerator->EnumAudioEndpoints(flowdir, DEVICE_STATE_ACTIVE, al::out_ptr(coll))}; + if (FAILED(hr)) + { + ERR("Failed to enumerate audio endpoints: 0x%08lx\n", hr); + return hr; + } - const HRESULT hr{device->GetId(&devid)}; - if(FAILED(hr)) - { - ERR("Failed to get device id: %lx\n", hr); - return nullptr; - } + UINT count{0}; + hr = coll->GetCount(&count); + if (SUCCEEDED(hr) && count > 0) + list.reserve(count); - return devid; -} + ComPtr device; + hr = mEnumerator->GetDefaultAudioEndpoint(flowdir, eMultimedia, al::out_ptr(device)); + if (SUCCEEDED(hr)) + { + if (WCHAR * devid{get_device_id(device.get())}) + { + add_device(device, devid, list); + CoTaskMemFree(devid); + } + device = nullptr; + } -void probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, std::vector &list) -{ - std::vector{}.swap(list); + for (UINT i{0}; i < count; ++i) + { + hr = coll->Item(i, al::out_ptr(device)); + if (FAILED(hr)) + continue; - ComPtr coll; - HRESULT hr{devenum->EnumAudioEndpoints(flowdir, DEVICE_STATE_ACTIVE, al::out_ptr(coll))}; - if(FAILED(hr)) - { - ERR("Failed to enumerate audio endpoints: 0x%08lx\n", hr); - return; + if (WCHAR * devid{get_device_id(device.get())}) + { + add_device(device, devid, list); + CoTaskMemFree(devid); + } + device = nullptr; + } + + return S_OK; +#else + const auto deviceRole = Windows::Media::Devices::AudioDeviceRole::Default; + auto DefaultAudioId = flowdir == eRender ? MediaDevice::GetDefaultAudioRenderId(deviceRole) + : MediaDevice::GetDefaultAudioCaptureId(deviceRole); + Concurrency::task createDefaultOp(DeviceInformation::CreateFromIdAsync(DefaultAudioId, nullptr, DeviceInformationKind::DeviceInterface)); + auto task_status = createDefaultOp + .then([this, &list](DeviceInformation ^ deviceInfo) { + if (deviceInfo) + add_device(DeviceHandle{deviceInfo}, deviceInfo->Id->Data(), list); + }).wait(); + if (task_status != Concurrency::task_group_status::completed) + return E_FAIL; + + // Get the string identifier of the audio renderer + auto AudioSelector = flowdir == eRender ? MediaDevice::GetAudioRenderSelector() : MediaDevice::GetAudioCaptureSelector(); + + // Setup the asynchronous callback + Concurrency::task enumOperation( + DeviceInformation::FindAllAsync(AudioSelector, /*PropertyList*/nullptr, DeviceInformationKind::DeviceInterface)); + task_status = enumOperation + .then([this, &list](DeviceInformationCollection ^ DeviceInfoCollection) { + if (DeviceInfoCollection) + { + try + { + auto deviceCount = DeviceInfoCollection->Size; + for (unsigned int i = 0; i < deviceCount; ++i) + { + DeviceInformation ^ deviceInfo = DeviceInfoCollection->GetAt(i); + if (deviceInfo) + add_device(DeviceHandle{deviceInfo}, deviceInfo->Id->Data(), list); + } + } + catch (Platform::Exception ^ e) + { + } + } + }).wait(); + + return task_status == Concurrency::task_group_status::completed ? S_OK : E_FAIL; +#endif } - UINT count{0}; - hr = coll->GetCount(&count); - if(SUCCEEDED(hr) && count > 0) - list.reserve(count); + using NameGUIDPair = std::pair; + static NameGUIDPair get_device_name_and_guid(const DeviceHandle& device) + { +#if !defined(ALSOFT_UWP) + static constexpr char UnknownName[]{"Unknown Device Name"}; + static constexpr char UnknownGuid[]{"Unknown Device GUID"}; + std::string name, guid; - ComPtr device; - hr = devenum->GetDefaultAudioEndpoint(flowdir, eMultimedia, al::out_ptr(device)); - if(SUCCEEDED(hr)) + ComPtr ps; + HRESULT hr = device->OpenPropertyStore(STGM_READ, al::out_ptr(ps)); + if (FAILED(hr)) + { + WARN("OpenPropertyStore failed: 0x%08lx\n", hr); + return std::make_pair(UnknownName, UnknownGuid); + } + + PropVariant pvprop; + hr = ps->GetValue(al::bit_cast(DEVPKEY_Device_FriendlyName), pvprop.get()); + if (FAILED(hr)) + { + WARN("GetValue Device_FriendlyName failed: 0x%08lx\n", hr); + name += UnknownName; + } + else if (pvprop->vt == VT_LPWSTR) + name += wstr_to_utf8(pvprop->pwszVal); + else + { + WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvprop->vt); + name += UnknownName; + } + + pvprop.clear(); + hr = ps->GetValue(al::bit_cast(PKEY_AudioEndpoint_GUID), pvprop.get()); + if (FAILED(hr)) + { + WARN("GetValue AudioEndpoint_GUID failed: 0x%08lx\n", hr); + guid = UnknownGuid; + } + else if (pvprop->vt == VT_LPWSTR) + guid = wstr_to_utf8(pvprop->pwszVal); + else + { + WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvprop->vt); + guid = UnknownGuid; + } + +#else + auto devInfo = device.value; + std::string name = wstr_to_utf8(devInfo->Name->Data()); + std::string guid; + // devInfo->Id is DeviceInterfacePath: \\?\SWD#MMDEVAPI#{0.0.0.00000000}.{a21c17a0-fc1d-405e-ab5a-b513422b57d1}#{e6327cad-dcec-4949-ae8a-991e976a79d2} + Platform::String ^ devIfPath = devInfo->Id; + auto wcsDevIfPath = devIfPath->Data(); + auto devIdStart = wcsstr(wcsDevIfPath, L"}."); + if (devIdStart) + { + devIdStart += 2; // L"}." + auto devIdStartEnd = wcschr(devIdStart, L'#'); + if (devIdStartEnd) + { + std::wstring wDevId{devIdStart, static_cast(devIdStartEnd - devIdStart)}; + guid = wstr_to_utf8(wDevId.c_str()); + std::transform(guid.begin(), guid.end(), guid.begin(), [](char ch) { return static_cast(std::toupper(ch)); }); + } + } +#endif + return std::make_pair(std::move(name), std::move(guid)); + } + + static void add_device(const DeviceHandle& device, const WCHAR* devid, std::vector& list) { - if(WCHAR *devid{get_device_id(device.get())}) + for (auto& entry : list) { - add_device(device.get(), devid, list); - CoTaskMemFree(devid); + if (entry.devid == devid) + return; } + + auto name_guid = get_device_name_and_guid(device); + int count{1}; + std::string newname{name_guid.first}; + while (checkName(list, newname)) + { + newname = name_guid.first; + newname += " #"; + newname += std::to_string(++count); + } + list.emplace_back(std::move(newname), std::move(name_guid.second), devid); + const DevMap& newentry = list.back(); + + TRACE("Got device \"%s\", \"%s\", \"%ls\"\n", newentry.name.c_str(), newentry.endpoint_guid.c_str(), + newentry.devid.c_str()); } - for(UINT i{0};i < count;++i) +#if !defined(ALSOFT_UWP) + static WCHAR* get_device_id(IMMDevice* device) { - device = nullptr; - hr = coll->Item(i, al::out_ptr(device)); - if(FAILED(hr)) continue; + WCHAR* devid; - if(WCHAR *devid{get_device_id(device.get())}) + const HRESULT hr{device->GetId(&devid)}; + if (FAILED(hr)) { - add_device(device.get(), devid, list); - CoTaskMemFree(devid); + ERR("Failed to get device id: %lx\n", hr); + return nullptr; } + + return devid; } -} + static EndpointFormFactor get_device_formfactor(IMMDevice* device) + { + ComPtr ps; + HRESULT hr{device->OpenPropertyStore(STGM_READ, al::out_ptr(ps))}; + if (FAILED(hr)) + { + WARN("OpenPropertyStore failed: 0x%08lx\n", hr); + return UnknownFormFactor; + } + + EndpointFormFactor formfactor{UnknownFormFactor}; + PropVariant pvform; + hr = ps->GetValue(PKEY_AudioEndpoint_FormFactor, pvform.get()); + if (FAILED(hr)) + WARN("GetValue AudioEndpoint_FormFactor failed: 0x%08lx\n", hr); + else if (pvform->vt == VT_UI4) + formfactor = static_cast(pvform->ulVal); + else if (pvform->vt != VT_EMPTY) + WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvform->vt); + return formfactor; + } +#endif + + template + EventRegistrationToken RegisterDefaultChangeHandler(EDataFlow flow, void* target, _Fty&& cb) + { +#if defined(ALSOFT_UWP) + (void)target; + if (flow == eRender) + return MediaDevice::DefaultAudioRenderDeviceChanged += + ref new TypedEventHandler( + [this, cb](Platform::Object ^ sender, DefaultAudioRenderDeviceChangedEventArgs ^ args) { + if (args->Role == AudioDeviceRole::Default) + cb(args->Id->Data()); + }); + else + return MediaDevice::DefaultAudioCaptureDeviceChanged += + ref new TypedEventHandler( + [this, cb](Platform::Object ^ sender, DefaultAudioCaptureDeviceChangedEventArgs ^ args) { + if (args->Role == AudioDeviceRole::Default) + cb(args->Id->Data()); + }); +#else + std::lock_guard lck(mDefaultChangeHandlersMtx); + if (mDefaultChangeHandlers.emplace(target, std::make_pair(flow, cb)).second) + return target; + return nullptr; +#endif + } + + void UnregisterDefaultChangeHandler(EventRegistrationToken handler) + { +#if defined(ALSOFT_UWP) + MediaDevice::DefaultAudioRenderDeviceChanged -= handler; +#else + std::lock_guard lck(mDefaultChangeHandlersMtx); + mDefaultChangeHandlers.erase(handler); +#endif + } +private: +#if defined(ALSOFT_UWP) + HRESULT ActivateAudioInterface(_In_ LPCWSTR deviceInterfacePath, + _In_ REFIID riid, + _In_opt_ PROPVARIANT* activationParams, + void** ppv) + { + IActivateAudioInterfaceAsyncOperation* asyncOp{nullptr}; + mPPV = ppv; + HRESULT hr = ActivateAudioInterfaceAsync(deviceInterfacePath, riid, activationParams, this, &asyncOp); + if (FAILED(hr)) + return hr; + if (asyncOp) + asyncOp->Release(); + + DWORD res{WaitForSingleObjectEx(mActiveClientEvent, 2000, FALSE)}; + if (res != WAIT_OBJECT_0) + ERR("WaitForSingleObjectEx error: 0x%lx\n", res); + return res; + } + + HANDLE mActiveClientEvent{nullptr}; + void** mPPV{nullptr}; +#else + ComPtr mEnumerator{nullptr}; + std::mutex mDefaultChangeHandlersMtx; + std::unordered_map>> mDefaultChangeHandlers; +#endif +}; bool MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *in) { @@ -473,6 +827,8 @@ struct WasapiProxy { static std::mutex sThreadLock; static size_t sInitCount; + static ComPtr sDeviceHelper; + std::future pushMessage(MsgType type, const char *param=nullptr) { std::promise promise; @@ -544,6 +900,7 @@ std::deque WasapiProxy::mMsgQueue; std::mutex WasapiProxy::mMsgQueueLock; std::condition_variable WasapiProxy::mMsgQueueCond; std::mutex WasapiProxy::sThreadLock; +ComPtr WasapiProxy::sDeviceHelper; size_t WasapiProxy::sInitCount{0}; int WasapiProxy::messageHandler(std::promise *promise) @@ -560,6 +917,8 @@ int WasapiProxy::messageHandler(std::promise *promise) promise->set_value(S_OK); promise = nullptr; + sDeviceHelper.reset(new DeviceHelper()); + TRACE("Starting message loop\n"); while(Msg msg{popMessage()}) { @@ -597,19 +956,12 @@ int WasapiProxy::messageHandler(std::promise *promise) case MsgType::EnumeratePlayback: case MsgType::EnumerateCapture: { - ComPtr devenum; - hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, - IID_IMMDeviceEnumerator, al::out_ptr(devenum)); - if(FAILED(hr)) - msg.mPromise.set_value(hr); - else - { - if(msg.mType == MsgType::EnumeratePlayback) - probe_devices(devenum.get(), eRender, PlaybackDevices); - else if(msg.mType == MsgType::EnumerateCapture) - probe_devices(devenum.get(), eCapture, CaptureDevices); - msg.mPromise.set_value(S_OK); - } + if (msg.mType == MsgType::EnumeratePlayback) + msg.mPromise.set_value(sDeviceHelper->probe_devices(eRender, PlaybackDevices)); + else if (msg.mType == MsgType::EnumerateCapture) + msg.mPromise.set_value(sDeviceHelper->probe_devices(eCapture, CaptureDevices)); + else + msg.mPromise.set_value(E_FAIL); continue; } @@ -625,7 +977,6 @@ int WasapiProxy::messageHandler(std::promise *promise) return 0; } - struct WasapiPlayback final : public BackendBase, WasapiProxy { WasapiPlayback(DeviceBase *device) noexcept : BackendBase{device} { } ~WasapiPlayback() override; @@ -646,7 +997,7 @@ struct WasapiPlayback final : public BackendBase, WasapiProxy { ClockLatency getClockLatency() override; HRESULT mOpenStatus{E_FAIL}; - ComPtr mMMDev{nullptr}; + DeviceHandle mMMDev{nullptr}; ComPtr mClient{nullptr}; ComPtr mRender{nullptr}; HANDLE mNotifyEvent{nullptr}; @@ -664,6 +1015,9 @@ struct WasapiPlayback final : public BackendBase, WasapiProxy { std::atomic mKillNow{true}; std::thread mThread; + std::string mDefaultDeviceId; + EventRegistrationToken mDefaultChangeHandler{}; + DEF_NEWDEL(WasapiPlayback) }; @@ -838,33 +1192,29 @@ HRESULT WasapiPlayback::openProxy(const char *name) devid = iter->devid.c_str(); } - ComPtr enumerator; - ComPtr mmdev; - HRESULT hr{CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, - IID_IMMDeviceEnumerator, al::out_ptr(enumerator))}; - if(SUCCEEDED(hr)) - { - if(!devid) - hr = enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, al::out_ptr(mmdev)); - else - hr = enumerator->GetDevice(devid, al::out_ptr(mmdev)); - } - if(FAILED(hr)) + HRESULT hr{sDeviceHelper->OpenDevice(devid, eRender, mMMDev)}; + if (FAILED(hr)) { - WARN("Failed to open device \"%s\"\n", name?name:"(default)"); + WARN("Failed to open device \"%s\"\n", name ? name : "(default)"); return hr; } - mClient = nullptr; - mMMDev = std::move(mmdev); - if(name) mDevice->DeviceName = std::string{DevNameHead} + name; - else mDevice->DeviceName = DevNameHead + get_device_name_and_guid(mMMDev.get()).first; + if (name) + mDevice->DeviceName = std::string{DevNameHead} + name; + else + mDevice->DeviceName = DevNameHead + DeviceHelper::get_device_name_and_guid(mMMDev).first; - return hr; + mDefaultChangeHandler = sDeviceHelper->RegisterDefaultChangeHandler(eRender, this, [this](LPCWSTR devid) { + mDefaultDeviceId = wstr_to_utf8(devid); + alc::Event(alc::EventType::DefaultDeviceChanged, (ALCdevice*)mDevice, mDefaultDeviceId); + }); + + return S_OK; } void WasapiPlayback::closeProxy() { + sDeviceHelper->UnregisterDefaultChangeHandler(mDefaultChangeHandler); mClient = nullptr; mMMDev = nullptr; } @@ -881,9 +1231,7 @@ bool WasapiPlayback::reset() HRESULT WasapiPlayback::resetProxy() { mClient = nullptr; - - HRESULT hr{mMMDev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, - al::out_ptr(mClient))}; + HRESULT hr{sDeviceHelper->ActivateAudioClient(mMMDev, al::out_ptr(mClient))}; if(FAILED(hr)) { ERR("Failed to reactivate audio client: 0x%08lx\n", hr); @@ -1154,9 +1502,12 @@ HRESULT WasapiPlayback::resetProxy() } mFormat = OutputType; - const EndpointFormFactor formfactor{get_device_formfactor(mMMDev.get())}; +#if !defined(ALSOFT_UWP) + const EndpointFormFactor formfactor{DeviceHelper::get_device_formfactor(mMMDev.get())}; mDevice->Flags.set(DirectEar, (formfactor == Headphones || formfactor == Headset)); - +#else + mDevice->Flags.set(DirectEar, false); +#endif setDefaultWFXChannelOrder(); hr = mClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, @@ -1313,7 +1664,7 @@ struct WasapiCapture final : public BackendBase, WasapiProxy { uint availableSamples() override; HRESULT mOpenStatus{E_FAIL}; - ComPtr mMMDev{nullptr}; + DeviceHandle mMMDev{nullptr}; ComPtr mClient{nullptr}; ComPtr mCapture{nullptr}; HANDLE mNotifyEvent{nullptr}; @@ -1325,6 +1676,9 @@ struct WasapiCapture final : public BackendBase, WasapiProxy { std::atomic mKillNow{true}; std::thread mThread; + std::string mDefaultDeviceId; + EventRegistrationToken mDefaultChangeHandler{}; + DEF_NEWDEL(WasapiCapture) }; @@ -1509,31 +1863,28 @@ HRESULT WasapiCapture::openProxy(const char *name) devid = iter->devid.c_str(); } - ComPtr enumerator; - HRESULT hr{CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, - IID_IMMDeviceEnumerator, al::out_ptr(enumerator))}; - if(SUCCEEDED(hr)) - { - if(!devid) - hr = enumerator->GetDefaultAudioEndpoint(eCapture, eMultimedia, al::out_ptr(mMMDev)); - else - hr = enumerator->GetDevice(devid, al::out_ptr(mMMDev)); - } - if(FAILED(hr)) + HRESULT hr{sDeviceHelper->OpenDevice(devid, eCapture, mMMDev)}; + if (FAILED(hr)) { - WARN("Failed to open device \"%s\"\n", name?name:"(default)"); + WARN("Failed to open device \"%s\"\n", name ? name : "(default)"); return hr; } - mClient = nullptr; - if(name) mDevice->DeviceName = std::string{DevNameHead} + name; - else mDevice->DeviceName = DevNameHead + get_device_name_and_guid(mMMDev.get()).first; + if (name) + mDevice->DeviceName = std::string{ DevNameHead } + name; + else + mDevice->DeviceName = DevNameHead + DeviceHelper::get_device_name_and_guid(mMMDev).first; - return hr; + mDefaultChangeHandler = sDeviceHelper->RegisterDefaultChangeHandler(eCapture, this, [this](LPCWSTR devid) { + mDefaultDeviceId = wstr_to_utf8(devid); + alc::Event(alc::EventType::DefaultDeviceChanged, (ALCdevice*)mDevice, mDefaultDeviceId); + }); + return S_OK; } void WasapiCapture::closeProxy() { + sDeviceHelper->UnregisterDefaultChangeHandler(mDefaultChangeHandler); mClient = nullptr; mMMDev = nullptr; } @@ -1542,8 +1893,7 @@ HRESULT WasapiCapture::resetProxy() { mClient = nullptr; - HRESULT hr{mMMDev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, - al::out_ptr(mClient))}; + HRESULT hr{sDeviceHelper->ActivateAudioClient(mMMDev, al::out_ptr(mClient))}; if(FAILED(hr)) { ERR("Failed to reactivate audio client: 0x%08lx\n", hr); @@ -1904,13 +2254,14 @@ bool WasapiBackendFactory::init() WARN("Failed to initialize COM: 0x%08lx\n", hr); return hr; } - +#if !defined(ALSOFT_UWP) ComPtr enumerator; hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, al::out_ptr(enumerator)); if(FAILED(hr)) WARN("Failed to create IMMDeviceEnumerator instance: 0x%08lx\n", hr); enumerator = nullptr; +#endif CoUninitialize(); return hr; diff --git a/config.h.in b/config.h.in index 477d8c77..d1cf0395 100644 --- a/config.h.in +++ b/config.h.in @@ -117,3 +117,6 @@ /* Define the installation data directory */ #cmakedefine ALSOFT_INSTALL_DATADIR "@ALSOFT_INSTALL_DATADIR@" + +/* Define whether build alsoft for winuwp */ +#cmakedefine ALSOFT_UWP diff --git a/core/async_event.h b/core/async_event.h index c049fa02..f1ca0c7b 100644 --- a/core/async_event.h +++ b/core/async_event.h @@ -15,7 +15,6 @@ enum class AsyncEnableBits : uint8_t { SourceState, BufferCompleted, Disconnected, - Count }; diff --git a/core/helpers.cpp b/core/helpers.cpp index 58cc74e5..f9de25cf 100644 --- a/core/helpers.cpp +++ b/core/helpers.cpp @@ -3,6 +3,11 @@ #include "helpers.h" +#if defined(_WIN32) +#define WIN32_LEAN_AND_MEAN +#include +#endif + #include #include #include @@ -40,7 +45,7 @@ const PathNamePair &GetProcBinary() { static std::optional procbin; if(procbin) return *procbin; - +#if !defined(ALSOFT_UWP) auto fullpath = std::vector(256); DWORD len{GetModuleFileNameW(nullptr, fullpath.data(), static_cast(fullpath.size()))}; while(len == fullpath.size()) @@ -58,7 +63,16 @@ const PathNamePair &GetProcBinary() fullpath.resize(len); if(fullpath.back() != 0) fullpath.push_back(0); - +#else + auto exePath = __wargv[0]; + if (!exePath) + { + ERR("Failed to get process name: error %lu\n", GetLastError()); + procbin.emplace(); + return *procbin; + } + std::vector fullpath{exePath, exePath + wcslen(exePath) + 1}; +#endif std::replace(fullpath.begin(), fullpath.end(), '/', '\\'); auto sep = std::find(fullpath.rbegin()+1, fullpath.rend(), '\\'); if(sep != fullpath.rend()) @@ -84,7 +98,7 @@ void DirectorySearch(const char *path, const char *ext, std::vector std::wstring wpath{utf8_to_wstr(pathstr.c_str())}; WIN32_FIND_DATAW fdata; - HANDLE hdl{FindFirstFileW(wpath.c_str(), &fdata)}; + HANDLE hdl{FindFirstFileExW(wpath.c_str(), FindExInfoStandard, &fdata, FindExSearchNameMatch, NULL, 0)}; if(hdl == INVALID_HANDLE_VALUE) return; const auto base = results->size(); @@ -97,7 +111,6 @@ void DirectorySearch(const char *path, const char *ext, std::vector str += wstr_to_utf8(fdata.cFileName); } while(FindNextFileW(hdl, &fdata)); FindClose(hdl); - const al::span newlist{results->data()+base, results->size()-base}; std::sort(newlist.begin(), newlist.end()); for(const auto &name : newlist) @@ -149,6 +162,7 @@ std::vector SearchDataFiles(const char *ext, const char *subdir) std::replace(path.begin(), path.end(), '/', '\\'); DirectorySearch(path.c_str(), ext, &results); +#if !defined(ALSOFT_UWP) /* Search the local and global data dirs. */ static const int ids[2]{ CSIDL_APPDATA, CSIDL_COMMON_APPDATA }; for(int id : ids) @@ -165,17 +179,20 @@ std::vector SearchDataFiles(const char *ext, const char *subdir) DirectorySearch(path.c_str(), ext, &results); } +#endif return results; } void SetRTPriority(void) { +#if !defined(ALSOFT_UWP) if(RTPrioLevel > 0) { if(!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL)) ERR("Failed to set priority level for thread\n"); } +#endif } #else diff --git a/core/uiddefs.cpp b/core/uiddefs.cpp index 244c01a5..833150f5 100644 --- a/core/uiddefs.cpp +++ b/core/uiddefs.cpp @@ -24,7 +24,7 @@ DEFINE_GUID(IID_IAudioClient, 0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1,0x78, 0xc DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7,0xbf, 0xad,0xdc,0xa7,0xc2,0x60,0xe2); DEFINE_GUID(IID_IAudioCaptureClient, 0xc8adbd64, 0xe71e, 0x48a0, 0xa4,0xde, 0x18,0x5c,0x39,0x5c,0xd3,0x17); -#ifdef HAVE_WASAPI +#if defined(HAVE_WASAPI) && !defined(ALSOFT_UWP) #include #include #include diff --git a/router/router.cpp b/router/router.cpp index 3c891053..18ecf9b4 100644 --- a/router/router.cpp +++ b/router/router.cpp @@ -334,7 +334,7 @@ void LoadDriverList(void) TRACE("Got DLL path %ls\n", dll_path); GetCurrentDirectoryW(MAX_PATH, cwd_path); - len = lstrlenW(cwd_path); + len = wcslen(cwd_path); if(len > 0 && (cwd_path[len-1] == '\\' || cwd_path[len-1] == '/')) cwd_path[len-1] = '\0'; TRACE("Got current working directory %ls\n", cwd_path); @@ -343,7 +343,7 @@ void LoadDriverList(void) TRACE("Got proc path %ls\n", proc_path); GetSystemDirectoryW(sys_path, MAX_PATH); - len = lstrlenW(sys_path); + len = wcslen(sys_path); if(len > 0 && (sys_path[len-1] == '\\' || sys_path[len-1] == '/')) sys_path[len-1] = '\0'; TRACE("Got system path %ls\n", sys_path); -- cgit v1.2.3 From 23f90b854a51eeaf6f70383beeef42944b675ce0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 May 2023 01:35:35 -0700 Subject: Don't register per-device default change handlers It's global state with a global callback. No need to associate it with each open device. --- alc/backends/wasapi.cpp | 211 +++++++++++++++++++----------------------------- 1 file changed, 83 insertions(+), 128 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index c8c03e8a..a11f8ae9 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -228,7 +228,7 @@ using EventRegistrationToken = void*; #if defined(ALSOFT_UWP) struct DeviceHelper final : public IActivateAudioInterfaceCompletionHandler #else -struct DeviceHelper final : public IMMNotificationClient +struct DeviceHelper final : private IMMNotificationClient #endif { public: @@ -236,10 +236,29 @@ public: { #if defined(ALSOFT_UWP) mActiveClientEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); + + auto cb = [](const WCHAR *devid) + { + const std::string msg{"Default device changed: "+wstr_to_utf8(devid)}; + alc::Event(alc::EventType::DefaultDeviceChanged, msg); + }; + + mRenderDeviceChangedToken = MediaDevice::DefaultAudioRenderDeviceChanged += + ref new TypedEventHandler( + [this,cb](Platform::Object ^ sender, DefaultAudioRenderDeviceChangedEventArgs ^ args) { + if (args->Role == AudioDeviceRole::Default) + cb(args->Id->Data()); + }); + mCaptureDeviceChangedToken = MediaDevice::DefaultAudioCaptureDeviceChanged += + ref new TypedEventHandler( + [this,cb](Platform::Object ^ sender, DefaultAudioCaptureDeviceChangedEventArgs ^ args) { + if (args->Role == AudioDeviceRole::Default) + cb(args->Id->Data()); + }); #else - HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, - al::out_ptr(mEnumerator)); - if (SUCCEEDED(hr)) + HRESULT hr{CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, + IID_IMMDeviceEnumerator, al::out_ptr(mEnumerator))}; + if(SUCCEEDED(hr)) mEnumerator->RegisterEndpointNotificationCallback(this); else WARN("Failed to create IMMDeviceEnumerator instance: 0x%08lx\n", hr); @@ -248,31 +267,31 @@ public: ~DeviceHelper() { #if defined(ALSOFT_UWP) - if (mActiveClientEvent != nullptr) + MediaDevice::DefaultAudioRenderDeviceChanged -= mRenderDeviceChangedToken; + MediaDevice::DefaultAudioCaptureDeviceChanged -= mCaptureDeviceChangedToken; + + if(mActiveClientEvent != nullptr) CloseHandle(mActiveClientEvent); mActiveClientEvent = nullptr; #else - if (mEnumerator) + if(mEnumerator) mEnumerator->UnregisterEndpointNotificationCallback(this); mEnumerator = nullptr; #endif } /** -------------------------- IUnkonwn ----------------------------- */ - LONG mRefCount{1}; - ULONG STDMETHODCALLTYPE AddRef() override { return InterlockedIncrement(&mRefCount); } + std::atomic mRefCount{1}; + STDMETHODIMP_(ULONG) AddRef() noexcept override { return mRefCount.fetch_add(1u) + 1u; } - ULONG STDMETHODCALLTYPE Release() override + STDMETHODIMP_(ULONG) Release() noexcept override { - ULONG ulRef = InterlockedDecrement(&mRefCount); - if (0 == ulRef) - { - delete this; - } - return ulRef; + auto ret = mRefCount.fetch_sub(1u) - 1u; + if(!ret) delete this; + return ret; } - HRESULT STDMETHODCALLTYPE QueryInterface(const IID& IId, void** UnknownPtrPtr) override + STDMETHODIMP QueryInterface(const IID& IId, void **UnknownPtrPtr) noexcept override { // Three rules of QueryInterface: // https://docs.microsoft.com/en-us/windows/win32/com/rules-for-implementing-queryinterface @@ -281,10 +300,8 @@ public: // 3. It must be possible to query successfully for any interface on an object from any other interface. // If ppvObject(the address) is nullptr, then this method returns E_POINTER. - if (!UnknownPtrPtr) - { + if(!UnknownPtrPtr) return E_POINTER; - } // https://docs.microsoft.com/en-us/windows/win32/com/implementing-reference-counting // Whenever a client calls a method(or API function), such as QueryInterface, that returns a new interface @@ -294,23 +311,23 @@ public: // interface pointer, the reference count becomes two. The client must call Release twice on the interface // pointer to drop all of its references to the object. #if defined(ALSOFT_UWP) - if (IId == __uuidof(IActivateAudioInterfaceCompletionHandler)) + if(IId == __uuidof(IActivateAudioInterfaceCompletionHandler)) { - *UnknownPtrPtr = (IActivateAudioInterfaceCompletionHandler*)(this); + *UnknownPtrPtr = static_cast(this); AddRef(); return S_OK; } #else - if (IId == __uuidof(IMMNotificationClient)) + if(IId == __uuidof(IMMNotificationClient)) { - *UnknownPtrPtr = (IMMNotificationClient*)(this); + *UnknownPtrPtr = static_cast(this); AddRef(); return S_OK; } #endif - else if (IId == __uuidof(IAgileObject) || IId == __uuidof(IUnknown)) + else if(IId == __uuidof(IAgileObject) || IId == __uuidof(IUnknown)) { - *UnknownPtrPtr = (IUnknown*)(this); + *UnknownPtrPtr = static_cast(this); AddRef(); return S_OK; } @@ -347,20 +364,16 @@ public: } #else /** ----------------------- IMMNotificationClient ------------ */ - STDMETHOD(OnDeviceStateChanged(LPCWSTR /*pwstrDeviceId*/, DWORD /*dwNewState*/)) override { return S_OK; } - STDMETHOD(OnDeviceAdded(LPCWSTR /*pwstrDeviceId*/)) override { return S_OK; } - STDMETHOD(OnDeviceRemoved(LPCWSTR /*pwstrDeviceId*/)) override { return S_OK; } - STDMETHOD(OnPropertyValueChanged(LPCWSTR /*pwstrDeviceId*/, const PROPERTYKEY /*key*/)) override { return S_OK; } - STDMETHOD(OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDefaultDeviceId)) override + STDMETHODIMP OnDeviceStateChanged(LPCWSTR /*pwstrDeviceId*/, DWORD /*dwNewState*/) noexcept override { return S_OK; } + STDMETHODIMP OnDeviceAdded(LPCWSTR /*pwstrDeviceId*/) noexcept override { return S_OK; } + STDMETHODIMP OnDeviceRemoved(LPCWSTR /*pwstrDeviceId*/) noexcept override { return S_OK; } + STDMETHODIMP OnPropertyValueChanged(LPCWSTR /*pwstrDeviceId*/, const PROPERTYKEY /*key*/) noexcept override { return S_OK; } + STDMETHODIMP OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDefaultDeviceId) noexcept override { - if (role == eMultimedia && (flow == eRender || flow == eCapture)) + if(role == eMultimedia && (flow == eRender || flow == eCapture)) { - std::lock_guard lck(mDefaultChangeHandlersMtx); - for (auto& handlerItem : mDefaultChangeHandlers) - { - if (handlerItem.second.first == flow) - handlerItem.second.second(pwstrDefaultDeviceId); - } + const std::string msg{"Default device changed: "+wstr_to_utf8(pwstrDefaultDeviceId)}; + alc::Event(alc::EventType::DefaultDeviceChanged, msg); } return S_OK; } @@ -370,18 +383,15 @@ public: HRESULT OpenDevice(LPCWSTR devid, EDataFlow flow, DeviceHandle& device) { #if !defined(ALSOFT_UWP) - HRESULT hr = E_POINTER; - if (mEnumerator) + HRESULT hr{E_POINTER}; + if(mEnumerator) { if (!devid) hr = mEnumerator->GetDefaultAudioEndpoint(flow, eMultimedia, al::out_ptr(device)); else hr = mEnumerator->GetDevice(devid, al::out_ptr(device)); } - if (FAILED(hr)) - { - return hr; - } + return hr; #else const auto deviceRole = Windows::Media::Devices::AudioDeviceRole::Default; Platform::String^ devIfPath = @@ -397,18 +407,17 @@ public: { return E_NOINTERFACE; } -#endif return S_OK; +#endif } - HRESULT ActivateAudioClient(_In_ DeviceHandle& device, - void** ppv) + HRESULT ActivateAudioClient(_In_ DeviceHandle& device, void **ppv) { #if !defined(ALSOFT_UWP) HRESULT hr{device->Activate(__uuidof(IAudioClient3), CLSCTX_INPROC_SERVER, nullptr, ppv)}; #else - HRESULT hr{ActivateAudioInterface(device.value->Id->Data(), - __uuidof(IAudioClient3), nullptr, ppv)}; + HRESULT hr{ActivateAudioInterface(device.value->Id->Data(), __uuidof(IAudioClient3), + nullptr, ppv)}; #endif return hr; } @@ -419,8 +428,9 @@ public: #if !defined(ALSOFT_UWP) ComPtr coll; - HRESULT hr{mEnumerator->EnumAudioEndpoints(flowdir, DEVICE_STATE_ACTIVE, al::out_ptr(coll))}; - if (FAILED(hr)) + HRESULT hr{mEnumerator->EnumAudioEndpoints(flowdir, DEVICE_STATE_ACTIVE, + al::out_ptr(coll))}; + if(FAILED(hr)) { ERR("Failed to enumerate audio endpoints: 0x%08lx\n", hr); return hr; @@ -428,14 +438,14 @@ public: UINT count{0}; hr = coll->GetCount(&count); - if (SUCCEEDED(hr) && count > 0) + if(SUCCEEDED(hr) && count > 0) list.reserve(count); ComPtr device; hr = mEnumerator->GetDefaultAudioEndpoint(flowdir, eMultimedia, al::out_ptr(device)); - if (SUCCEEDED(hr)) + if(SUCCEEDED(hr)) { - if (WCHAR * devid{get_device_id(device.get())}) + if(WCHAR *devid{get_device_id(device.get())}) { add_device(device, devid, list); CoTaskMemFree(devid); @@ -443,13 +453,13 @@ public: device = nullptr; } - for (UINT i{0}; i < count; ++i) + for(UINT i{0};i < count;++i) { hr = coll->Item(i, al::out_ptr(device)); - if (FAILED(hr)) + if(FAILED(hr)) continue; - if (WCHAR * devid{get_device_id(device.get())}) + if(WCHAR *devid{get_device_id(device.get())}) { add_device(device, devid, list); CoTaskMemFree(devid); @@ -595,12 +605,12 @@ public: } #if !defined(ALSOFT_UWP) - static WCHAR* get_device_id(IMMDevice* device) + static WCHAR *get_device_id(IMMDevice* device) { - WCHAR* devid; + WCHAR *devid; const HRESULT hr{device->GetId(&devid)}; - if (FAILED(hr)) + if(FAILED(hr)) { ERR("Failed to get device id: %lx\n", hr); return nullptr; @@ -612,7 +622,7 @@ public: { ComPtr ps; HRESULT hr{device->OpenPropertyStore(STGM_READ, al::out_ptr(ps))}; - if (FAILED(hr)) + if(FAILED(hr)) { WARN("OpenPropertyStore failed: 0x%08lx\n", hr); return UnknownFormFactor; @@ -621,52 +631,16 @@ public: EndpointFormFactor formfactor{UnknownFormFactor}; PropVariant pvform; hr = ps->GetValue(PKEY_AudioEndpoint_FormFactor, pvform.get()); - if (FAILED(hr)) + if(FAILED(hr)) WARN("GetValue AudioEndpoint_FormFactor failed: 0x%08lx\n", hr); - else if (pvform->vt == VT_UI4) + else if(pvform->vt == VT_UI4) formfactor = static_cast(pvform->ulVal); - else if (pvform->vt != VT_EMPTY) + else if(pvform->vt != VT_EMPTY) WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvform->vt); return formfactor; } #endif - template - EventRegistrationToken RegisterDefaultChangeHandler(EDataFlow flow, void* target, _Fty&& cb) - { -#if defined(ALSOFT_UWP) - (void)target; - if (flow == eRender) - return MediaDevice::DefaultAudioRenderDeviceChanged += - ref new TypedEventHandler( - [this, cb](Platform::Object ^ sender, DefaultAudioRenderDeviceChangedEventArgs ^ args) { - if (args->Role == AudioDeviceRole::Default) - cb(args->Id->Data()); - }); - else - return MediaDevice::DefaultAudioCaptureDeviceChanged += - ref new TypedEventHandler( - [this, cb](Platform::Object ^ sender, DefaultAudioCaptureDeviceChangedEventArgs ^ args) { - if (args->Role == AudioDeviceRole::Default) - cb(args->Id->Data()); - }); -#else - std::lock_guard lck(mDefaultChangeHandlersMtx); - if (mDefaultChangeHandlers.emplace(target, std::make_pair(flow, cb)).second) - return target; - return nullptr; -#endif - } - - void UnregisterDefaultChangeHandler(EventRegistrationToken handler) - { -#if defined(ALSOFT_UWP) - MediaDevice::DefaultAudioRenderDeviceChanged -= handler; -#else - std::lock_guard lck(mDefaultChangeHandlersMtx); - mDefaultChangeHandlers.erase(handler); -#endif - } private: #if defined(ALSOFT_UWP) HRESULT ActivateAudioInterface(_In_ LPCWSTR deviceInterfacePath, @@ -677,24 +651,24 @@ private: IActivateAudioInterfaceAsyncOperation* asyncOp{nullptr}; mPPV = ppv; HRESULT hr = ActivateAudioInterfaceAsync(deviceInterfacePath, riid, activationParams, this, &asyncOp); - if (FAILED(hr)) + if(FAILED(hr)) return hr; - if (asyncOp) + if(asyncOp) asyncOp->Release(); DWORD res{WaitForSingleObjectEx(mActiveClientEvent, 2000, FALSE)}; - if (res != WAIT_OBJECT_0) + if(res != WAIT_OBJECT_0) ERR("WaitForSingleObjectEx error: 0x%lx\n", res); return res; } HANDLE mActiveClientEvent{nullptr}; void** mPPV{nullptr}; + + EventRegistrationToken mRenderDeviceChangedToken; + EventRegistrationToken mCaptureDeviceChangedToken; #else ComPtr mEnumerator{nullptr}; - - std::mutex mDefaultChangeHandlersMtx; - std::unordered_map>> mDefaultChangeHandlers; #endif }; @@ -917,7 +891,7 @@ int WasapiProxy::messageHandler(std::promise *promise) promise->set_value(S_OK); promise = nullptr; - sDeviceHelper.reset(new DeviceHelper()); + sDeviceHelper.reset(new DeviceHelper{}); TRACE("Starting message loop\n"); while(Msg msg{popMessage()}) @@ -955,15 +929,13 @@ int WasapiProxy::messageHandler(std::promise *promise) case MsgType::EnumeratePlayback: case MsgType::EnumerateCapture: - { - if (msg.mType == MsgType::EnumeratePlayback) + if(msg.mType == MsgType::EnumeratePlayback) msg.mPromise.set_value(sDeviceHelper->probe_devices(eRender, PlaybackDevices)); - else if (msg.mType == MsgType::EnumerateCapture) + else if(msg.mType == MsgType::EnumerateCapture) msg.mPromise.set_value(sDeviceHelper->probe_devices(eCapture, CaptureDevices)); else msg.mPromise.set_value(E_FAIL); - continue; - } + continue; case MsgType::QuitThread: break; @@ -1015,9 +987,6 @@ struct WasapiPlayback final : public BackendBase, WasapiProxy { std::atomic mKillNow{true}; std::thread mThread; - std::string mDefaultDeviceId; - EventRegistrationToken mDefaultChangeHandler{}; - DEF_NEWDEL(WasapiPlayback) }; @@ -1204,17 +1173,11 @@ HRESULT WasapiPlayback::openProxy(const char *name) else mDevice->DeviceName = DevNameHead + DeviceHelper::get_device_name_and_guid(mMMDev).first; - mDefaultChangeHandler = sDeviceHelper->RegisterDefaultChangeHandler(eRender, this, [this](LPCWSTR devid) { - mDefaultDeviceId = wstr_to_utf8(devid); - alc::Event(alc::EventType::DefaultDeviceChanged, (ALCdevice*)mDevice, mDefaultDeviceId); - }); - return S_OK; } void WasapiPlayback::closeProxy() { - sDeviceHelper->UnregisterDefaultChangeHandler(mDefaultChangeHandler); mClient = nullptr; mMMDev = nullptr; } @@ -1676,9 +1639,6 @@ struct WasapiCapture final : public BackendBase, WasapiProxy { std::atomic mKillNow{true}; std::thread mThread; - std::string mDefaultDeviceId; - EventRegistrationToken mDefaultChangeHandler{}; - DEF_NEWDEL(WasapiCapture) }; @@ -1875,16 +1835,11 @@ HRESULT WasapiCapture::openProxy(const char *name) else mDevice->DeviceName = DevNameHead + DeviceHelper::get_device_name_and_guid(mMMDev).first; - mDefaultChangeHandler = sDeviceHelper->RegisterDefaultChangeHandler(eCapture, this, [this](LPCWSTR devid) { - mDefaultDeviceId = wstr_to_utf8(devid); - alc::Event(alc::EventType::DefaultDeviceChanged, (ALCdevice*)mDevice, mDefaultDeviceId); - }); return S_OK; } void WasapiCapture::closeProxy() { - sDeviceHelper->UnregisterDefaultChangeHandler(mDefaultChangeHandler); mClient = nullptr; mMMDev = nullptr; } -- cgit v1.2.3 From 1a583b016a7b5e22f370e2f425722e3dc240a7dd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 May 2023 02:15:43 -0700 Subject: Initialize the WASAPI device helper earlier --- CMakeLists.txt | 13 ++++++++----- alc/backends/wasapi.cpp | 5 +++-- 2 files changed, 11 insertions(+), 7 deletions(-) (limited to 'alc/backends') diff --git a/CMakeLists.txt b/CMakeLists.txt index 02bf81b4..ae21a83e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1061,11 +1061,11 @@ if(WIN32) set(BACKENDS "${BACKENDS} WASAPI,") set(ALC_OBJS ${ALC_OBJS} alc/backends/wasapi.cpp alc/backends/wasapi.h) if(ALSOFT_UWP) - set_source_files_properties(alc/backends/wasapi.cpp alc/alconfig.cpp PROPERTIES COMPILE_FLAGS /ZW) + set_source_files_properties(alc/backends/wasapi.cpp alc/alconfig.cpp PROPERTIES COMPILE_FLAGS /ZW) endif() endif() endif() - + # Setup properly link flags for UWP if(ALSOFT_UWP AND HAVE_WASAPI) # Add compile and link flags required C++/CX @@ -1416,8 +1416,8 @@ else() endif() target_link_libraries(${IMPL_TARGET} PRIVATE common ${LINKER_FLAGS} ${EXTRA_LIBS} ${MATH_LIB}) - if (WIN32) - set_target_properties(${IMPL_TARGET} PROPERTIES + if(ALSOFT_UWP AND HAVE_WASAPI) + set_target_properties(${IMPL_TARGET} PROPERTIES LINK_FLAGS_DEBUG "${LINKER_FLAGS_DEBUG}" LINK_FLAGS_RELEASE "${LINKER_FLAGS_RELEASE}" LINK_FLAGS_MINSIZEREL "${LINKER_FLAGS_RELEASE}" @@ -1538,7 +1538,10 @@ if(FPMATH_SET) message(STATUS "Building with SSE${FPMATH_SET} codegen") message(STATUS "") endif() - +if(ALSOFT_UWP) + message(STATUS "Building with UWP support") + message(STATUS "") +endif() if(ALSOFT_EAX) message(STATUS "Building with legacy EAX extension support") message(STATUS "") diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index a11f8ae9..ccdc54e7 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -891,8 +891,6 @@ int WasapiProxy::messageHandler(std::promise *promise) promise->set_value(S_OK); promise = nullptr; - sDeviceHelper.reset(new DeviceHelper{}); - TRACE("Starting message loop\n"); while(Msg msg{popMessage()}) { @@ -2217,6 +2215,9 @@ bool WasapiBackendFactory::init() WARN("Failed to create IMMDeviceEnumerator instance: 0x%08lx\n", hr); enumerator = nullptr; #endif + if(SUCCEEDED(hr)) + WasapiProxy::sDeviceHelper.reset(new DeviceHelper{}); + CoUninitialize(); return hr; -- cgit v1.2.3 From b93c425126de67bef30f9ee9cc112d4278c04954 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 May 2023 04:05:44 -0700 Subject: Report device change events from PipeWire --- alc/backends/pipewire.cpp | 125 +++++++++++++++++++++++++++++++++------------- 1 file changed, 91 insertions(+), 34 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/pipewire.cpp b/alc/backends/pipewire.cpp index bb7fc2f2..30dc7a87 100644 --- a/alc/backends/pipewire.cpp +++ b/alc/backends/pipewire.cpp @@ -40,6 +40,7 @@ #include "albit.h" #include "alc/alconfig.h" +#include "alc/events.h" #include "almalloc.h" #include "alnumeric.h" #include "alspan.h" @@ -472,16 +473,19 @@ struct EventManager { auto lock() const { return mLoop.lock(); } auto unlock() const { return mLoop.unlock(); } + inline bool initIsDone(std::memory_order m=std::memory_order_seq_cst) noexcept + { return mInitDone.load(m); } + /** * Waits for initialization to finish. The event manager must *NOT* be * locked when calling this. */ void waitForInit() { - if(!mInitDone.load(std::memory_order_acquire)) UNLIKELY + if(!initIsDone(std::memory_order_acquire)) UNLIKELY { MainloopUniqueLock plock{mLoop}; - plock.wait([this](){ return mInitDone.load(std::memory_order_acquire); }); + plock.wait([this](){ return initIsDone(std::memory_order_acquire); }); } } @@ -497,7 +501,7 @@ struct EventManager { plock.wait([this,&has_audio]() { has_audio = mHasAudio.load(std::memory_order_acquire); - return has_audio || mInitDone.load(std::memory_order_acquire); + return has_audio || initIsDone(std::memory_order_acquire); }); return has_audio; } @@ -507,38 +511,34 @@ struct EventManager { /* If initialization isn't done, update the sequence ID so it won't * complete until after currently scheduled events. */ - if(!mInitDone.load(std::memory_order_relaxed)) + if(!initIsDone(std::memory_order_relaxed)) mInitSeq = ppw_core_sync(mCore.get(), PW_ID_CORE, mInitSeq); } void addCallback(uint32_t id, uint32_t permissions, const char *type, uint32_t version, - const spa_dict *props); - static void addCallbackC(void *object, uint32_t id, uint32_t permissions, const char *type, - uint32_t version, const spa_dict *props) - { static_cast(object)->addCallback(id, permissions, type, version, props); } + const spa_dict *props) noexcept; - void removeCallback(uint32_t id); - static void removeCallbackC(void *object, uint32_t id) - { static_cast(object)->removeCallback(id); } + void removeCallback(uint32_t id) noexcept; static constexpr pw_registry_events CreateRegistryEvents() { pw_registry_events ret{}; ret.version = PW_VERSION_REGISTRY_EVENTS; - ret.global = &EventManager::addCallbackC; - ret.global_remove = &EventManager::removeCallbackC; + ret.global = [](void *object, uint32_t id, uint32_t permissions, const char *type, uint32_t version, const spa_dict *props) noexcept + { static_cast(object)->addCallback(id, permissions, type, version, props); }; + ret.global_remove = [](void *object, uint32_t id) noexcept + { static_cast(object)->removeCallback(id); }; return ret; } - void coreCallback(uint32_t id, int seq); - static void coreCallbackC(void *object, uint32_t id, int seq) - { static_cast(object)->coreCallback(id, seq); } + void coreCallback(uint32_t id, int seq) noexcept; static constexpr pw_core_events CreateCoreEvents() { pw_core_events ret{}; ret.version = PW_VERSION_CORE_EVENTS; - ret.done = &EventManager::coreCallbackC; + ret.done = [](void *object, uint32_t id, int seq) noexcept + { static_cast(object)->coreCallback(id, seq); }; return ret; } }; @@ -571,6 +571,7 @@ struct DeviceNode { static std::vector sList; static DeviceNode &Add(uint32_t id); static DeviceNode *Find(uint32_t id); + static DeviceNode *FindByDevName(std::string_view devname); static void Remove(uint32_t id); static std::vector &GetList() noexcept { return sList; } @@ -619,6 +620,17 @@ DeviceNode *DeviceNode::Find(uint32_t id) return nullptr; } +DeviceNode *DeviceNode::FindByDevName(std::string_view devname) +{ + auto match_id = [devname](DeviceNode &n) noexcept -> bool + { return n.mDevName == devname; }; + + auto match = std::find_if(sList.begin(), sList.end(), match_id); + if(match != sList.end()) return al::to_address(match); + + return nullptr; +} + void DeviceNode::Remove(uint32_t id) { auto match_id = [id](DeviceNode &n) noexcept -> bool @@ -626,6 +638,11 @@ void DeviceNode::Remove(uint32_t id) if(n.mId != id) return false; TRACE("Removing device \"%s\"\n", n.mDevName.c_str()); + if(gEventHandler.initIsDone(std::memory_order_relaxed)) + { + const std::string msg{"Device removed: "+n.mName}; + alc::Event(alc::EventType::DeviceRemoved, msg); + } return true; }; @@ -815,9 +832,9 @@ struct NodeProxy { { pw_node_events ret{}; ret.version = PW_VERSION_NODE_EVENTS; - ret.info = [](void *object, const pw_node_info *info) + ret.info = [](void *object, const pw_node_info *info) noexcept { static_cast(object)->infoCallback(info); }; - ret.param = [](void *object, int seq, uint32_t id, uint32_t index, uint32_t next, const spa_pod *param) + ret.param = [](void *object, int seq, uint32_t id, uint32_t index, uint32_t next, const spa_pod *param) noexcept { static_cast(object)->paramCallback(seq, id, index, next, param); }; return ret; } @@ -843,12 +860,12 @@ struct NodeProxy { { spa_hook_remove(&mListener); } - void infoCallback(const pw_node_info *info); + void infoCallback(const pw_node_info *info) noexcept; - void paramCallback(int seq, uint32_t id, uint32_t index, uint32_t next, const spa_pod *param); + void paramCallback(int seq, uint32_t id, uint32_t index, uint32_t next, const spa_pod *param) noexcept; }; -void NodeProxy::infoCallback(const pw_node_info *info) +void NodeProxy::infoCallback(const pw_node_info *info) noexcept { /* We only care about property changes here (media class, name/desc). * Format changes will automatically invoke the param callback. @@ -896,15 +913,31 @@ void NodeProxy::infoCallback(const pw_node_info *info) } #endif + std::string name; + if(nodeName && *nodeName) name = nodeName; + else name = "PipeWire node #"+std::to_string(info->id); + const char *form_factor{spa_dict_lookup(info->props, PW_KEY_DEVICE_FORM_FACTOR)}; TRACE("Got %s device \"%s\"%s%s%s\n", AsString(ntype), devName ? devName : "(nil)", form_factor?" (":"", form_factor?form_factor:"", form_factor?")":""); - TRACE(" \"%s\" = ID %" PRIu64 "\n", nodeName ? nodeName : "(nil)", serial_id); + TRACE(" \"%s\" = ID %" PRIu64 "\n", name.c_str(), serial_id); DeviceNode &node = DeviceNode::Add(info->id); node.mSerial = serial_id; - if(nodeName && *nodeName) node.mName = nodeName; - else node.mName = "PipeWire node #"+std::to_string(info->id); + if(node.mName != name) + { + if(gEventHandler.mInitDone.load(std::memory_order_relaxed)) + { + if(!node.mName.empty()) + { + const std::string msg{"Device removed: "+node.mName}; + alc::Event(alc::EventType::DeviceRemoved, msg); + } + const std::string msg{"Device added: "+name}; + alc::Event(alc::EventType::DeviceAdded, msg); + } + node.mName = std::move(name); + } node.mDevName = devName ? devName : ""; node.mType = ntype; node.mIsHeadphones = form_factor && (al::strcasecmp(form_factor, "headphones") == 0 @@ -912,7 +945,7 @@ void NodeProxy::infoCallback(const pw_node_info *info) } } -void NodeProxy::paramCallback(int, uint32_t id, uint32_t, uint32_t, const spa_pod *param) +void NodeProxy::paramCallback(int, uint32_t id, uint32_t, uint32_t, const spa_pod *param) noexcept { if(id == SPA_PARAM_EnumFormat) { @@ -936,7 +969,7 @@ struct MetadataProxy { { pw_metadata_events ret{}; ret.version = PW_VERSION_METADATA_EVENTS; - ret.property = [](void *object, uint32_t id, const char *key, const char *type, const char *value) + ret.property = [](void *object, uint32_t id, const char *key, const char *type, const char *value) noexcept { return static_cast(object)->propertyCallback(id, key, type, value); }; return ret; } @@ -955,11 +988,11 @@ struct MetadataProxy { ~MetadataProxy() { spa_hook_remove(&mListener); } - int propertyCallback(uint32_t id, const char *key, const char *type, const char *value); + int propertyCallback(uint32_t id, const char *key, const char *type, const char *value) noexcept; }; int MetadataProxy::propertyCallback(uint32_t id, const char *key, const char *type, - const char *value) + const char *value) noexcept { if(id != PW_ID_CORE) return 0; @@ -1015,9 +1048,33 @@ int MetadataProxy::propertyCallback(uint32_t id, const char *key, const char *ty TRACE("Got default %s device \"%s\"\n", isCapture ? "capture" : "playback", propValue->c_str()); if(!isCapture) - DefaultSinkDevice = std::move(*propValue); + { + if(DefaultSinkDevice != *propValue) + { + if(gEventHandler.mInitDone.load(std::memory_order_relaxed)) + { + auto entry = DeviceNode::FindByDevName(*propValue); + const std::string msg{"Default playback device changed: "+ + (entry ? entry->mName : std::string{})}; + alc::Event(alc::EventType::DefaultDeviceChanged, msg); + } + DefaultSinkDevice = std::move(*propValue); + } + } else - DefaultSourceDevice = std::move(*propValue); + { + if(DefaultSourceDevice != *propValue) + { + if(gEventHandler.mInitDone.load(std::memory_order_relaxed)) + { + auto entry = DeviceNode::FindByDevName(*propValue); + const std::string msg{"Default capture device changed: "+ + (entry ? entry->mName : std::string{})}; + alc::Event(alc::EventType::DefaultDeviceChanged, msg); + } + DefaultSourceDevice = std::move(*propValue); + } + } } else { @@ -1108,7 +1165,7 @@ void EventManager::kill() } void EventManager::addCallback(uint32_t id, uint32_t, const char *type, uint32_t version, - const spa_dict *props) + const spa_dict *props) noexcept { /* We're only interested in interface nodes. */ if(std::strcmp(type, PW_TYPE_INTERFACE_Node) == 0) @@ -1183,7 +1240,7 @@ void EventManager::addCallback(uint32_t id, uint32_t, const char *type, uint32_t } } -void EventManager::removeCallback(uint32_t id) +void EventManager::removeCallback(uint32_t id) noexcept { DeviceNode::Remove(id); @@ -1204,7 +1261,7 @@ void EventManager::removeCallback(uint32_t id) } } -void EventManager::coreCallback(uint32_t id, int seq) +void EventManager::coreCallback(uint32_t id, int seq) noexcept { if(id == PW_ID_CORE && seq == mInitSeq) { -- cgit v1.2.3 From 456e1e828235a721bfab6930fe0c0157fd0d8277 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 May 2023 16:12:49 -0700 Subject: Include IOAudioTypes.h only when needed --- alc/backends/coreaudio.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index 521f085d..13665a4c 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -41,17 +41,16 @@ #include #include -#include - - -namespace { #if TARGET_OS_IOS || TARGET_OS_TV #define CAN_ENUMERATE 0 #else +#include #define CAN_ENUMERATE 1 #endif +namespace { + constexpr auto OutputElement = 0; constexpr auto InputElement = 1; -- cgit v1.2.3 From 5f88fe54a06fda76cf16c2dec1d242cdb5e4a8ae Mon Sep 17 00:00:00 2001 From: "Deal(一线灵)" Date: Thu, 1 Jun 2023 21:30:03 +0800 Subject: Report device change events from CoreAudio (#856) * Report device change events from CoreAudio * Fix compile error * Use optional * Use optional, no unique_ptr --- alc/backends/coreaudio.cpp | 51 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) (limited to 'alc/backends') diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index 13665a4c..a9419e3d 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -32,12 +32,14 @@ #include #include #include +#include #include "alnumeric.h" #include "core/converter.h" #include "core/device.h" #include "core/logging.h" #include "ringbuffer.h" +#include "alc/events.h" #include #include @@ -271,6 +273,47 @@ void EnumerateDevices(std::vector &list, bool isCapture) newdevs.swap(list); } +struct DeviceHelper +{ +public: + DeviceHelper() + { + AudioObjectPropertyAddress addr = {kAudioHardwarePropertyDefaultOutputDevice, + kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain}; + OSStatus status = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &addr, DeviceListenerProc, nil); + if (status != noErr) + ERR("AudioObjectAddPropertyListener fail: %d", status); + } + ~DeviceHelper() + { + AudioObjectPropertyAddress addr = {kAudioHardwarePropertyDefaultOutputDevice, + kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain}; + OSStatus status = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &addr, DeviceListenerProc, nil); + if (status != noErr) + ERR("AudioObjectRemovePropertyListener fail: %d", status); + } + + static OSStatus DeviceListenerProc(AudioObjectID /*inObjectID*/, + UInt32 inNumberAddresses, + const AudioObjectPropertyAddress *inAddresses, + void* /*inClientData*/) + { + for (UInt32 i = 0; i < inNumberAddresses; ++i) + { + switch (inAddresses[i].mSelector) + { + case kAudioHardwarePropertyDefaultOutputDevice: + case kAudioHardwarePropertyDefaultSystemOutputDevice: + case kAudioHardwarePropertyDefaultInputDevice: + alc::Event(alc::EventType::DefaultDeviceChanged, "Default device changed: "+std::to_string(inAddresses[i].mSelector)); + break; + } + } + } +}; + +static std::optional sDeviceHelper; + #else static constexpr char ca_device[] = "CoreAudio Default"; @@ -915,7 +958,13 @@ BackendFactory &CoreAudioBackendFactory::getFactory() return factory; } -bool CoreAudioBackendFactory::init() { return true; } +bool CoreAudioBackendFactory::init() +{ +#if CAN_ENUMERATE + sDeviceHelper.emplace(); +#endif + return true; +} bool CoreAudioBackendFactory::querySupport(BackendType type) { return type == BackendType::Playback || type == BackendType::Capture; } -- cgit v1.2.3 From b5323af956dab2c27153568ef82facda33fff25a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 May 2023 17:15:53 -0700 Subject: Add a comment explaining the DeviceAdded logic for PipeWire --- alc/backends/pipewire.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'alc/backends') diff --git a/alc/backends/pipewire.cpp b/alc/backends/pipewire.cpp index 30dc7a87..fad64f01 100644 --- a/alc/backends/pipewire.cpp +++ b/alc/backends/pipewire.cpp @@ -924,9 +924,18 @@ void NodeProxy::infoCallback(const pw_node_info *info) noexcept DeviceNode &node = DeviceNode::Add(info->id); node.mSerial = serial_id; + /* This method is called both to notify about a new sink/source node, + * and update properties for the node. It's unclear what properties can + * change for an existing node without being removed first, so err on + * the side of caution: send a DeviceAdded event when the name differs, + * and send a DeviceRemoved event if it had a name that's being + * replaced. + * + * This is overkill if the name or devname can't change. + */ if(node.mName != name) { - if(gEventHandler.mInitDone.load(std::memory_order_relaxed)) + if(gEventHandler.initIsDone(std::memory_order_relaxed)) { if(!node.mName.empty()) { -- cgit v1.2.3 From f8d8a1a3900fd51dc3bffb91f88c7725982a7ccc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 May 2023 19:03:24 -0700 Subject: Add a context to PulseMainloop --- alc/backends/pulseaudio.cpp | 148 +++++++++++++++++++------------------------- 1 file changed, 64 insertions(+), 84 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index d2883f5c..7554b467 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -291,13 +291,14 @@ pa_context_flags_t pulse_ctx_flags; class PulseMainloop { pa_threaded_mainloop *mLoop{}; + pa_context *mContext{}; public: PulseMainloop() = default; PulseMainloop(const PulseMainloop&) = delete; PulseMainloop(PulseMainloop&& rhs) noexcept : mLoop{rhs.mLoop} { rhs.mLoop = nullptr; } explicit PulseMainloop(pa_threaded_mainloop *loop) noexcept : mLoop{loop} { } - ~PulseMainloop() { if(mLoop) pa_threaded_mainloop_free(mLoop); } + ~PulseMainloop(); PulseMainloop& operator=(const PulseMainloop&) = delete; PulseMainloop& operator=(PulseMainloop&& rhs) noexcept @@ -316,6 +317,7 @@ public: auto stop() const { return pa_threaded_mainloop_stop(mLoop); } auto getApi() const { return pa_threaded_mainloop_get_api(mLoop); } + auto getContext() const noexcept { return mContext; } auto lock() const { return pa_threaded_mainloop_lock(mLoop); } auto unlock() const { return pa_threaded_mainloop_unlock(mLoop); } @@ -329,7 +331,7 @@ public: static void streamSuccessCallbackC(pa_stream *stream, int success, void *pdata) noexcept { static_cast(pdata)->streamSuccessCallback(stream, success); } - void close(pa_context *context, pa_stream *stream=nullptr); + void close(pa_stream *stream=nullptr); void deviceSinkCallback(pa_context*, const pa_sink_info *info, int eol) noexcept @@ -434,31 +436,46 @@ struct MainloopUniqueLock : public std::unique_lock { mutex()->signal(); } - pa_context *connectContext(); - pa_stream *connectStream(const char *device_name, pa_context *context, pa_stream_flags_t flags, + void connectContext(); + pa_stream *connectStream(const char *device_name, pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec, pa_channel_map *chanmap, BackendType type); }; using MainloopLockGuard = std::lock_guard; +PulseMainloop::~PulseMainloop() +{ + if(mContext) + { + MainloopUniqueLock _{*this}; + pa_context_disconnect(mContext); + pa_context_unref(mContext); + } + if(mLoop) + pa_threaded_mainloop_free(mLoop); +} -pa_context *MainloopUniqueLock::connectContext() + +void MainloopUniqueLock::connectContext() { - pa_context *context{pa_context_new(mutex()->getApi(), nullptr)}; - if(!context) throw al::backend_exception{al::backend_error::OutOfMemory, + if(mutex()->mContext) + return; + + mutex()->mContext = pa_context_new(mutex()->getApi(), nullptr); + if(!mutex()->mContext) throw al::backend_exception{al::backend_error::OutOfMemory, "pa_context_new() failed"}; - pa_context_set_state_callback(context, [](pa_context *ctx, void *pdata) noexcept + pa_context_set_state_callback(mutex()->mContext, [](pa_context *ctx, void *pdata) noexcept { return static_cast(pdata)->contextStateCallback(ctx); }, this); int err; - if((err=pa_context_connect(context, nullptr, pulse_ctx_flags, nullptr)) >= 0) + if((err=pa_context_connect(mutex()->mContext, nullptr, pulse_ctx_flags, nullptr)) >= 0) { pa_context_state_t state; - while((state=pa_context_get_state(context)) != PA_CONTEXT_READY) + while((state=pa_context_get_state(mutex()->mContext)) != PA_CONTEXT_READY) { if(!PA_CONTEXT_IS_GOOD(state)) { - err = pa_context_errno(context); + err = pa_context_errno(mutex()->mContext); if(err > 0) err = -err; break; } @@ -466,27 +483,25 @@ pa_context *MainloopUniqueLock::connectContext() wait(); } } - pa_context_set_state_callback(context, nullptr, nullptr); + pa_context_set_state_callback(mutex()->mContext, nullptr, nullptr); if(err < 0) { - pa_context_unref(context); + pa_context_unref(mutex()->mContext); + mutex()->mContext = nullptr; throw al::backend_exception{al::backend_error::DeviceError, "Context did not connect (%s)", pa_strerror(err)}; } - - return context; } -pa_stream *MainloopUniqueLock::connectStream(const char *device_name, pa_context *context, - pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec, pa_channel_map *chanmap, - BackendType type) +pa_stream *MainloopUniqueLock::connectStream(const char *device_name, pa_stream_flags_t flags, + pa_buffer_attr *attr, pa_sample_spec *spec, pa_channel_map *chanmap, BackendType type) { const char *stream_id{(type==BackendType::Playback) ? "Playback Stream" : "Capture Stream"}; - pa_stream *stream{pa_stream_new(context, stream_id, spec, chanmap)}; + pa_stream *stream{pa_stream_new(mutex()->mContext, stream_id, spec, chanmap)}; if(!stream) throw al::backend_exception{al::backend_error::OutOfMemory, "pa_stream_new() failed (%s)", - pa_strerror(pa_context_errno(context))}; + pa_strerror(pa_context_errno(mutex()->mContext))}; pa_stream_set_state_callback(stream, [](pa_stream *strm, void *pdata) noexcept { return static_cast(pdata)->streamStateCallback(strm); }, this); @@ -506,7 +521,7 @@ pa_stream *MainloopUniqueLock::connectStream(const char *device_name, pa_context { if(!PA_STREAM_IS_GOOD(state)) { - err = pa_context_errno(context); + err = pa_context_errno(mutex()->mContext); pa_stream_unref(stream); throw al::backend_exception{al::backend_error::DeviceError, "%s did not get ready (%s)", stream_id, pa_strerror(err)}; @@ -519,75 +534,57 @@ pa_stream *MainloopUniqueLock::connectStream(const char *device_name, pa_context return stream; } -void PulseMainloop::close(pa_context *context, pa_stream *stream) +void PulseMainloop::close(pa_stream *stream) { - MainloopUniqueLock _{*this}; - if(stream) - { - pa_stream_set_state_callback(stream, nullptr, nullptr); - pa_stream_set_moved_callback(stream, nullptr, nullptr); - pa_stream_set_write_callback(stream, nullptr, nullptr); - pa_stream_set_buffer_attr_callback(stream, nullptr, nullptr); - pa_stream_disconnect(stream); - pa_stream_unref(stream); - } + if(!stream) + return; - pa_context_disconnect(context); - pa_context_unref(context); + MainloopUniqueLock _{*this}; + pa_stream_set_state_callback(stream, nullptr, nullptr); + pa_stream_set_moved_callback(stream, nullptr, nullptr); + pa_stream_set_write_callback(stream, nullptr, nullptr); + pa_stream_set_buffer_attr_callback(stream, nullptr, nullptr); + pa_stream_disconnect(stream); + pa_stream_unref(stream); } void PulseMainloop::probePlaybackDevices() { - pa_context *context{}; - PlaybackDevices.clear(); try { MainloopUniqueLock plock{*this}; auto sink_callback = [](pa_context *ctx, const pa_sink_info *info, int eol, void *pdata) noexcept { return static_cast(pdata)->deviceSinkCallback(ctx, info, eol); }; - context = plock.connectContext(); - pa_operation *op{pa_context_get_sink_info_by_name(context, nullptr, sink_callback, this)}; + pa_operation *op{pa_context_get_sink_info_by_name(mContext, nullptr, sink_callback, this)}; plock.waitForOperation(op); - op = pa_context_get_sink_info_list(context, sink_callback, this); + op = pa_context_get_sink_info_list(mContext, sink_callback, this); plock.waitForOperation(op); - - pa_context_disconnect(context); - pa_context_unref(context); - context = nullptr; } catch(std::exception &e) { ERR("Error enumerating devices: %s\n", e.what()); - if(context) close(context); } } void PulseMainloop::probeCaptureDevices() { - pa_context *context{}; - CaptureDevices.clear(); try { MainloopUniqueLock plock{*this}; auto src_callback = [](pa_context *ctx, const pa_source_info *info, int eol, void *pdata) noexcept { return static_cast(pdata)->deviceSourceCallback(ctx, info, eol); }; - context = plock.connectContext(); - pa_operation *op{pa_context_get_source_info_by_name(context, nullptr, src_callback, this)}; + pa_operation *op{pa_context_get_source_info_by_name(mContext, nullptr, src_callback, + this)}; plock.waitForOperation(op); - op = pa_context_get_source_info_list(context, src_callback, this); + op = pa_context_get_source_info_list(mContext, src_callback, this); plock.waitForOperation(op); - - pa_context_disconnect(context); - pa_context_unref(context); - context = nullptr; } catch(std::exception &e) { ERR("Error enumerating devices: %s\n", e.what()); - if(context) close(context); } } @@ -622,7 +619,6 @@ struct PulsePlayback final : public BackendBase { pa_sample_spec mSpec; pa_stream *mStream{nullptr}; - pa_context *mContext{nullptr}; uint mFrameSize{0u}; @@ -630,14 +626,7 @@ struct PulsePlayback final : public BackendBase { }; PulsePlayback::~PulsePlayback() -{ - if(!mContext) - return; - - mMainloop.close(mContext, mStream); - mContext = nullptr; - mStream = nullptr; -} +{ if(mStream) mMainloop.close(mStream); } void PulsePlayback::bufferAttrCallback(pa_stream *stream) noexcept @@ -772,7 +761,7 @@ void PulsePlayback::open(const char *name) } MainloopUniqueLock plock{mMainloop}; - mContext = plock.connectContext(); + plock.connectContext(); pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | PA_STREAM_FIX_CHANNELS}; @@ -790,7 +779,7 @@ void PulsePlayback::open(const char *name) if(defname) pulse_name = defname->c_str(); } TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); - mStream = plock.connectStream(pulse_name, mContext, flags, nullptr, &spec, nullptr, + mStream = plock.connectStream(pulse_name, flags, nullptr, &spec, nullptr, BackendType::Playback); pa_stream_set_moved_callback(mStream, [](pa_stream *stream, void *pdata) noexcept @@ -803,7 +792,7 @@ void PulsePlayback::open(const char *name) { auto name_callback = [](pa_context *context, const pa_sink_info *info, int eol, void *pdata) noexcept { return static_cast(pdata)->sinkNameCallback(context, info, eol); }; - pa_operation *op{pa_context_get_sink_info_by_name(mContext, + pa_operation *op{pa_context_get_sink_info_by_name(mMainloop.getContext(), pa_stream_get_device_name(mStream), name_callback, this)}; plock.waitForOperation(op); } @@ -829,7 +818,8 @@ bool PulsePlayback::reset() auto info_callback = [](pa_context *context, const pa_sink_info *info, int eol, void *pdata) noexcept { return static_cast(pdata)->sinkInfoCallback(context, info, eol); }; - pa_operation *op{pa_context_get_sink_info_by_name(mContext, deviceName, info_callback, this)}; + pa_operation *op{pa_context_get_sink_info_by_name(mMainloop.getContext(), deviceName, + info_callback, this)}; plock.waitForOperation(op); pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_INTERPOLATE_TIMING | @@ -916,7 +906,7 @@ bool PulsePlayback::reset() mAttr.minreq = mDevice->UpdateSize * frame_size; mAttr.fragsize = ~0u; - mStream = plock.connectStream(deviceName, mContext, flags, &mAttr, &mSpec, &chanmap, + mStream = plock.connectStream(deviceName, flags, &mAttr, &mSpec, &chanmap, BackendType::Playback); pa_stream_set_state_callback(mStream, [](pa_stream *stream, void *pdata) noexcept @@ -1055,20 +1045,12 @@ struct PulseCapture final : public BackendBase { pa_sample_spec mSpec{}; pa_stream *mStream{nullptr}; - pa_context *mContext{nullptr}; DEF_NEWDEL(PulseCapture) }; PulseCapture::~PulseCapture() -{ - if(!mContext) - return; - - mMainloop.close(mContext, mStream); - mContext = nullptr; - mStream = nullptr; -} +{ if(mStream) mMainloop.close(mStream); } void PulseCapture::streamStateCallback(pa_stream *stream) noexcept @@ -1122,7 +1104,7 @@ void PulseCapture::open(const char *name) } MainloopUniqueLock plock{mMainloop}; - mContext = plock.connectContext(); + plock.connectContext(); pa_channel_map chanmap{}; switch(mDevice->FmtChans) @@ -1194,7 +1176,7 @@ void PulseCapture::open(const char *name) flags |= PA_STREAM_DONT_MOVE; TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); - mStream = plock.connectStream(pulse_name, mContext, flags, &mAttr, &mSpec, &chanmap, + mStream = plock.connectStream(pulse_name, flags, &mAttr, &mSpec, &chanmap, BackendType::Capture); pa_stream_set_moved_callback(mStream, [](pa_stream *stream, void *pdata) noexcept @@ -1208,7 +1190,7 @@ void PulseCapture::open(const char *name) { auto name_callback = [](pa_context *context, const pa_source_info *info, int eol, void *pdata) noexcept { return static_cast(pdata)->sourceNameCallback(context, info, eol); }; - pa_operation *op{pa_context_get_source_info_by_name(mContext, + pa_operation *op{pa_context_get_source_info_by_name(mMainloop.getContext(), pa_stream_get_device_name(mStream), name_callback, this)}; plock.waitForOperation(op); } @@ -1281,7 +1263,7 @@ void PulseCapture::captureSamples(std::byte *buffer, uint samples) if(pa_stream_peek(mStream, &capbuf, &caplen) < 0) UNLIKELY { mDevice->handleDisconnect("Failed retrieving capture samples: %s", - pa_strerror(pa_context_errno(mContext))); + pa_strerror(pa_context_errno(mMainloop.getContext()))); break; } plock.unlock(); @@ -1412,9 +1394,7 @@ bool PulseBackendFactory::init() } MainloopUniqueLock plock{gGlobalMainloop}; - pa_context *context{plock.connectContext()}; - pa_context_disconnect(context); - pa_context_unref(context); + plock.connectContext(); return true; } catch(...) { -- cgit v1.2.3 From 360fdcbc721644e7b07aab7cbea4fc11bfa144d8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 May 2023 20:55:16 -0700 Subject: Handle device added/removed events with PulseAudio --- alc/backends/pulseaudio.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'alc/backends') diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index 7554b467..16a2450f 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -41,6 +41,7 @@ #include "albit.h" #include "alc/alconfig.h" +#include "alc/events.h" #include "almalloc.h" #include "alnumeric.h" #include "alspan.h" @@ -65,6 +66,8 @@ using uint = unsigned int; MAGIC(pa_context_get_state); \ MAGIC(pa_context_disconnect); \ MAGIC(pa_context_set_state_callback); \ + MAGIC(pa_context_set_subscribe_callback); \ + MAGIC(pa_context_subscribe); \ MAGIC(pa_context_errno); \ MAGIC(pa_context_connect); \ MAGIC(pa_context_get_server_info); \ @@ -136,6 +139,8 @@ PULSE_FUNCS(MAKE_FUNC) #define pa_context_get_state ppa_context_get_state #define pa_context_disconnect ppa_context_disconnect #define pa_context_set_state_callback ppa_context_set_state_callback +#define pa_context_set_subscribe_callback ppa_context_set_subscribe_callback +#define pa_context_subscribe ppa_context_subscribe #define pa_context_errno ppa_context_errno #define pa_context_connect ppa_context_connect #define pa_context_get_server_info ppa_context_get_server_info @@ -270,6 +275,9 @@ constexpr pa_context_flags_t& operator|=(pa_context_flags_t &lhs, pa_context_fla return lhs; } +constexpr pa_subscription_mask_t operator|(pa_subscription_mask_t lhs, pa_subscription_mask_t rhs) +{ return pa_subscription_mask_t(lhs | al::to_underlying(rhs)); } + struct DevMap { std::string name; @@ -422,6 +430,39 @@ struct MainloopUniqueLock : public std::unique_lock { } + void setEventHandler() + { + pa_operation *op{pa_context_subscribe(mutex()->mContext, + PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE, + [](pa_context*, int, void *pdata) noexcept + { static_cast(pdata)->signal(); }, + mutex())}; + waitForOperation(op); + + /* Watch for device added/removed events. + * + * TODO: Also track the "default" device, in as much as PulseAudio has + * the concept of a default device (whatever device is opened when not + * specifying a specific sink or source name). There doesn't seem to be + * an event for this. + */ + auto handler = [](pa_context*, pa_subscription_event_type_t t, uint32_t, void*) noexcept + { + const auto eventFacility = (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK); + if(eventFacility == PA_SUBSCRIPTION_EVENT_SINK + || eventFacility == PA_SUBSCRIPTION_EVENT_SOURCE) + { + const auto eventType = (t & PA_SUBSCRIPTION_EVENT_TYPE_MASK); + if(eventType == PA_SUBSCRIPTION_EVENT_NEW) + alc::Event(alc::EventType::DeviceAdded, "Device added"); + else if(eventType == PA_SUBSCRIPTION_EVENT_REMOVE) + alc::Event(alc::EventType::DeviceRemoved, "Device removed"); + } + }; + pa_context_set_subscribe_callback(mutex()->mContext, handler, nullptr); + } + + void contextStateCallback(pa_context *context) noexcept { pa_context_state_t state{pa_context_get_state(context)}; @@ -1395,6 +1436,7 @@ bool PulseBackendFactory::init() MainloopUniqueLock plock{gGlobalMainloop}; plock.connectContext(); + plock.setEventHandler(); return true; } catch(...) { -- cgit v1.2.3 From edc20c87d3cd37608e8fa50556d718cd32755f3d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 May 2023 22:11:15 -0700 Subject: Specify the device type for the event callback --- alc/backends/coreaudio.cpp | 28 ++++++++++++++-------------- alc/backends/pipewire.cpp | 22 +++++++++++++++++----- alc/backends/pulseaudio.cpp | 6 ++++-- alc/backends/wasapi.cpp | 38 +++++++++++++++++++++++++++++--------- alc/events.cpp | 10 +++++----- alc/events.h | 11 ++++++++--- alc/inprogext.h | 16 +++++++++------- 7 files changed, 86 insertions(+), 45 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index a9419e3d..1e8423b7 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -273,39 +273,39 @@ void EnumerateDevices(std::vector &list, bool isCapture) newdevs.swap(list); } -struct DeviceHelper -{ -public: +struct DeviceHelper { DeviceHelper() { - AudioObjectPropertyAddress addr = {kAudioHardwarePropertyDefaultOutputDevice, - kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain}; + AudioObjectPropertyAddress addr{kAudioHardwarePropertyDefaultOutputDevice, + kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain}; OSStatus status = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &addr, DeviceListenerProc, nil); if (status != noErr) ERR("AudioObjectAddPropertyListener fail: %d", status); } ~DeviceHelper() { - AudioObjectPropertyAddress addr = {kAudioHardwarePropertyDefaultOutputDevice, - kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain}; + AudioObjectPropertyAddress addr{kAudioHardwarePropertyDefaultOutputDevice, + kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain}; OSStatus status = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &addr, DeviceListenerProc, nil); if (status != noErr) ERR("AudioObjectRemovePropertyListener fail: %d", status); } - static OSStatus DeviceListenerProc(AudioObjectID /*inObjectID*/, - UInt32 inNumberAddresses, - const AudioObjectPropertyAddress *inAddresses, - void* /*inClientData*/) + static OSStatus DeviceListenerProc(AudioObjectID /*inObjectID*/, UInt32 inNumberAddresses, + const AudioObjectPropertyAddress *inAddresses, void* /*inClientData*/) { - for (UInt32 i = 0; i < inNumberAddresses; ++i) + for(UInt32 i = 0; i < inNumberAddresses; ++i) { - switch (inAddresses[i].mSelector) + switch(inAddresses[i].mSelector) { case kAudioHardwarePropertyDefaultOutputDevice: case kAudioHardwarePropertyDefaultSystemOutputDevice: + alc::Event(alc::EventType::DefaultDeviceChanged, alc::DeviceType::Playback, + "Default playback device changed: "+std::to_string(inAddresses[i].mSelector)); + break; case kAudioHardwarePropertyDefaultInputDevice: - alc::Event(alc::EventType::DefaultDeviceChanged, "Default device changed: "+std::to_string(inAddresses[i].mSelector)); + alc::Event(alc::EventType::DefaultDeviceChanged, alc::DeviceType::Capture, + "Default capture device changed: "+std::to_string(inAddresses[i].mSelector)); break; } } diff --git a/alc/backends/pipewire.cpp b/alc/backends/pipewire.cpp index fad64f01..2bee4d7d 100644 --- a/alc/backends/pipewire.cpp +++ b/alc/backends/pipewire.cpp @@ -578,6 +578,16 @@ struct DeviceNode { void parseSampleRate(const spa_pod *value) noexcept; void parsePositions(const spa_pod *value) noexcept; void parseChannelCount(const spa_pod *value) noexcept; + + void callEvent(alc::EventType type, std::string_view message) + { + /* Source nodes aren't recognized for playback, only Sink and Duplex + * nodes are. All node types are recognized for capture. + */ + if(mType != NodeType::Source) + alc::Event(type, alc::DeviceType::Playback, message); + alc::Event(type, alc::DeviceType::Capture, message); + } }; std::vector DeviceNode::sList; std::string DefaultSinkDevice; @@ -641,7 +651,7 @@ void DeviceNode::Remove(uint32_t id) if(gEventHandler.initIsDone(std::memory_order_relaxed)) { const std::string msg{"Device removed: "+n.mName}; - alc::Event(alc::EventType::DeviceRemoved, msg); + n.callEvent(alc::EventType::DeviceRemoved, msg); } return true; }; @@ -940,10 +950,10 @@ void NodeProxy::infoCallback(const pw_node_info *info) noexcept if(!node.mName.empty()) { const std::string msg{"Device removed: "+node.mName}; - alc::Event(alc::EventType::DeviceRemoved, msg); + node.callEvent(alc::EventType::DeviceRemoved, msg); } const std::string msg{"Device added: "+name}; - alc::Event(alc::EventType::DeviceAdded, msg); + node.callEvent(alc::EventType::DeviceAdded, msg); } node.mName = std::move(name); } @@ -1065,7 +1075,8 @@ int MetadataProxy::propertyCallback(uint32_t id, const char *key, const char *ty auto entry = DeviceNode::FindByDevName(*propValue); const std::string msg{"Default playback device changed: "+ (entry ? entry->mName : std::string{})}; - alc::Event(alc::EventType::DefaultDeviceChanged, msg); + alc::Event(alc::EventType::DefaultDeviceChanged, alc::DeviceType::Playback, + msg); } DefaultSinkDevice = std::move(*propValue); } @@ -1079,7 +1090,8 @@ int MetadataProxy::propertyCallback(uint32_t id, const char *key, const char *ty auto entry = DeviceNode::FindByDevName(*propValue); const std::string msg{"Default capture device changed: "+ (entry ? entry->mName : std::string{})}; - alc::Event(alc::EventType::DefaultDeviceChanged, msg); + alc::Event(alc::EventType::DefaultDeviceChanged, alc::DeviceType::Capture, + msg); } DefaultSourceDevice = std::move(*propValue); } diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index 16a2450f..8c6cc4d3 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -452,11 +452,13 @@ struct MainloopUniqueLock : public std::unique_lock { if(eventFacility == PA_SUBSCRIPTION_EVENT_SINK || eventFacility == PA_SUBSCRIPTION_EVENT_SOURCE) { + const auto deviceType = (eventFacility == PA_SUBSCRIPTION_EVENT_SINK) + ? alc::DeviceType::Playback : alc::DeviceType::Capture; const auto eventType = (t & PA_SUBSCRIPTION_EVENT_TYPE_MASK); if(eventType == PA_SUBSCRIPTION_EVENT_NEW) - alc::Event(alc::EventType::DeviceAdded, "Device added"); + alc::Event(alc::EventType::DeviceAdded, deviceType, "Device added"); else if(eventType == PA_SUBSCRIPTION_EVENT_REMOVE) - alc::Event(alc::EventType::DeviceRemoved, "Device removed"); + alc::Event(alc::EventType::DeviceRemoved, deviceType, "Device removed"); } }; pa_context_set_subscribe_callback(mutex()->mContext, handler, nullptr); diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index ccdc54e7..32a4334d 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -237,23 +237,33 @@ public: #if defined(ALSOFT_UWP) mActiveClientEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); - auto cb = [](const WCHAR *devid) + auto cb = [](alc::DeviceType type, const WCHAR *devid) { const std::string msg{"Default device changed: "+wstr_to_utf8(devid)}; - alc::Event(alc::EventType::DefaultDeviceChanged, msg); + alc::Event(alc::EventType::DefaultDeviceChanged, type, msg); }; mRenderDeviceChangedToken = MediaDevice::DefaultAudioRenderDeviceChanged += ref new TypedEventHandler( [this,cb](Platform::Object ^ sender, DefaultAudioRenderDeviceChangedEventArgs ^ args) { - if (args->Role == AudioDeviceRole::Default) - cb(args->Id->Data()); + if(args->Role == AudioDeviceRole::Default) + { + const std::string msg{"Default playback device changed: "+ + wstr_to_utf8(args->Id->Data())}; + alc::Event(alc::EventType::DefaultDeviceChanged, alc::DeviceType::Playback, + msg); + } }); mCaptureDeviceChangedToken = MediaDevice::DefaultAudioCaptureDeviceChanged += ref new TypedEventHandler( [this,cb](Platform::Object ^ sender, DefaultAudioCaptureDeviceChangedEventArgs ^ args) { - if (args->Role == AudioDeviceRole::Default) - cb(args->Id->Data()); + if(args->Role == AudioDeviceRole::Default) + { + const std::string msg{"Default capture device changed: "+ + wstr_to_utf8(args->Id->Data())}; + alc::Event(alc::EventType::DefaultDeviceChanged, alc::DeviceType::Capture, + msg); + } }); #else HRESULT hr{CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, @@ -370,10 +380,20 @@ public: STDMETHODIMP OnPropertyValueChanged(LPCWSTR /*pwstrDeviceId*/, const PROPERTYKEY /*key*/) noexcept override { return S_OK; } STDMETHODIMP OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDefaultDeviceId) noexcept override { - if(role == eMultimedia && (flow == eRender || flow == eCapture)) + if(role != eMultimedia) + return S_OK; + + if(flow == eRender) + { + const std::string msg{"Default playback device changed: "+ + wstr_to_utf8(pwstrDefaultDeviceId)}; + alc::Event(alc::EventType::DefaultDeviceChanged, alc::DeviceType::Playback, msg); + } + else if(flow == eCapture) { - const std::string msg{"Default device changed: "+wstr_to_utf8(pwstrDefaultDeviceId)}; - alc::Event(alc::EventType::DefaultDeviceChanged, msg); + const std::string msg{"Default capture device changed: "+ + wstr_to_utf8(pwstrDefaultDeviceId)}; + alc::Event(alc::EventType::DefaultDeviceChanged, alc::DeviceType::Capture, msg); } return S_OK; } diff --git a/alc/events.cpp b/alc/events.cpp index 3c9c59ee..b5b65cb1 100644 --- a/alc/events.cpp +++ b/alc/events.cpp @@ -40,17 +40,17 @@ ALCenum EnumFromEventType(const alc::EventType type) namespace alc { -void Event(EventType eventType, ALCdevice *device, std::string_view message) noexcept +void Event(EventType eventType, DeviceType deviceType, ALCdevice *device, std::string_view message) noexcept { auto eventlock = std::unique_lock{EventMutex}; if(EventCallback && EventsEnabled.test(al::to_underlying(eventType))) - EventCallback(EnumFromEventType(eventType), device, + EventCallback(EnumFromEventType(eventType), al::to_underlying(deviceType), device, static_cast(message.length()), message.data(), EventUserPtr); } } // namespace alc -FORCE_ALIGN ALCboolean ALC_APIENTRY alcEventControlSOFT(ALCsizei count, const ALCenum *types, +FORCE_ALIGN ALCboolean ALC_APIENTRY alcEventControlSOFT(ALCsizei count, const ALCenum *events, ALCboolean enable) noexcept { if(enable != ALC_FALSE && enable != ALC_TRUE) @@ -65,14 +65,14 @@ FORCE_ALIGN ALCboolean ALC_APIENTRY alcEventControlSOFT(ALCsizei count, const AL } if(count == 0) return ALC_TRUE; - if(!types) + if(!events) { alcSetError(nullptr, ALC_INVALID_VALUE); return ALC_FALSE; } std::bitset eventSet{0}; - for(ALCenum type : al::span{types, static_cast(count)}) + for(ALCenum type : al::span{events, static_cast(count)}) { auto etype = GetEventType(type); if(!etype) diff --git a/alc/events.h b/alc/events.h index 3b22a4c4..ddb3808a 100644 --- a/alc/events.h +++ b/alc/events.h @@ -19,6 +19,11 @@ enum class EventType : uint8_t { Count }; +enum class DeviceType : ALCenum { + Playback = ALC_PLAYBACK_DEVICE_SOFT, + Capture = ALC_CAPTURE_DEVICE_SOFT, +}; + inline std::bitset EventsEnabled{0}; inline std::mutex EventMutex; @@ -26,10 +31,10 @@ inline std::mutex EventMutex; inline ALCEVENTPROCTYPESOFT EventCallback{}; inline void *EventUserPtr{}; -void Event(alc::EventType eventType, ALCdevice *device, std::string_view message) noexcept; +void Event(EventType eventType, DeviceType deviceType, ALCdevice *device, std::string_view message) noexcept; -inline void Event(alc::EventType eventType, std::string_view message) noexcept -{ Event(eventType, nullptr, message); } +inline void Event(EventType eventType, DeviceType deviceType, std::string_view message) noexcept +{ Event(eventType, deviceType, nullptr, message); } } // namespace alc diff --git a/alc/inprogext.h b/alc/inprogext.h index 7cf49868..65e34ea4 100644 --- a/alc/inprogext.h +++ b/alc/inprogext.h @@ -445,15 +445,17 @@ ALenum AL_APIENTRY EAXGetBufferModeDirect(ALCcontext *context, ALuint buffer, AL #ifndef ALC_SOFT_system_events #define ALC_SOFT_system_events -#define ALC_EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT 0x19CF -#define ALC_EVENT_TYPE_DEVICE_ADDED_SOFT 0x19D0 -#define ALC_EVENT_TYPE_DEVICE_REMOVED_SOFT 0x19D1 -typedef void (ALC_APIENTRY*ALCEVENTPROCTYPESOFT)(ALCenum eventType, ALCdevice *device, - ALCsizei length, const ALCchar *message, void *userParam) ALC_API_NOEXCEPT17; -typedef ALCboolean (ALC_APIENTRY*LPALCEVENTCONTROLSOFT)(ALCsizei count, const ALCenum *types, ALCboolean enable) ALC_API_NOEXCEPT17; +#define ALC_PLAYBACK_DEVICE_SOFT 0x19CF +#define ALC_CAPTURE_DEVICE_SOFT 0x19D0 +#define ALC_EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT 0x19D1 +#define ALC_EVENT_TYPE_DEVICE_ADDED_SOFT 0x19D2 +#define ALC_EVENT_TYPE_DEVICE_REMOVED_SOFT 0x19D3 +typedef void (ALC_APIENTRY*ALCEVENTPROCTYPESOFT)(ALCenum eventType, ALCenum deviceType, + ALCdevice *device, ALCsizei length, const ALCchar *message, void *userParam) ALC_API_NOEXCEPT17; +typedef ALCboolean (ALC_APIENTRY*LPALCEVENTCONTROLSOFT)(ALCsizei count, const ALCenum *events, ALCboolean enable) ALC_API_NOEXCEPT17; typedef void (ALC_APIENTRY*LPALCEVENTCALLBACKSOFT)(ALCEVENTPROCTYPESOFT callback, void *userParam) ALC_API_NOEXCEPT17; #ifdef AL_ALEXT_PROTOTYPES -ALCboolean ALC_APIENTRY alcEventControlSOFT(ALCsizei count, const ALCenum *types, ALCboolean enable) ALC_API_NOEXCEPT; +ALCboolean ALC_APIENTRY alcEventControlSOFT(ALCsizei count, const ALCenum *events, ALCboolean enable) ALC_API_NOEXCEPT; void ALC_APIENTRY alcEventCallbackSOFT(ALCEVENTPROCTYPESOFT callback, void *userParam) ALC_API_NOEXCEPT; #endif #endif -- cgit v1.2.3 From c200eb73a7cf47dbd1a4a3785be471adfb3513d8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Jun 2023 17:31:31 -0700 Subject: Move althrd_setname to its own source --- CMakeLists.txt | 2 ++ alc/backends/alsa.cpp | 2 +- alc/backends/dsound.cpp | 2 +- alc/backends/jack.cpp | 1 + alc/backends/null.cpp | 4 +-- alc/backends/opensl.cpp | 1 + alc/backends/oss.cpp | 2 +- alc/backends/sndio.cpp | 2 +- alc/backends/solaris.cpp | 2 +- alc/backends/wasapi.cpp | 2 +- alc/backends/wave.cpp | 2 +- alc/backends/winmm.cpp | 1 + common/althrd_setname.cpp | 76 +++++++++++++++++++++++++++++++++++++++++++++++ common/althrd_setname.h | 6 ++++ common/threads.cpp | 66 ---------------------------------------- common/threads.h | 2 -- 16 files changed, 96 insertions(+), 77 deletions(-) create mode 100644 common/althrd_setname.cpp create mode 100644 common/althrd_setname.h (limited to 'alc/backends') diff --git a/CMakeLists.txt b/CMakeLists.txt index e4d3776d..63a213c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -621,6 +621,8 @@ set(COMMON_OBJS common/alspan.h common/alstring.cpp common/alstring.h + common/althrd_setname.cpp + common/althrd_setname.h common/altraits.h common/atomic.h common/comptr.h diff --git a/alc/backends/alsa.cpp b/alc/backends/alsa.cpp index ce368f5e..83eef183 100644 --- a/alc/backends/alsa.cpp +++ b/alc/backends/alsa.cpp @@ -41,12 +41,12 @@ #include "alc/alconfig.h" #include "almalloc.h" #include "alnumeric.h" +#include "althrd_setname.h" #include "core/device.h" #include "core/helpers.h" #include "core/logging.h" #include "dynload.h" #include "ringbuffer.h" -#include "threads.h" #include diff --git a/alc/backends/dsound.cpp b/alc/backends/dsound.cpp index 5fc8a1c7..54fac898 100644 --- a/alc/backends/dsound.cpp +++ b/alc/backends/dsound.cpp @@ -47,6 +47,7 @@ #include "albit.h" #include "alnumeric.h" #include "alspan.h" +#include "althrd_setname.h" #include "comptr.h" #include "core/device.h" #include "core/helpers.h" @@ -54,7 +55,6 @@ #include "dynload.h" #include "ringbuffer.h" #include "strutils.h" -#include "threads.h" /* MinGW-w64 needs this for some unknown reason now. */ using LPCWAVEFORMATEX = const WAVEFORMATEX*; diff --git a/alc/backends/jack.cpp b/alc/backends/jack.cpp index 9e023e21..b8325b05 100644 --- a/alc/backends/jack.cpp +++ b/alc/backends/jack.cpp @@ -35,6 +35,7 @@ #include "albit.h" #include "alc/alconfig.h" #include "alnumeric.h" +#include "althrd_setname.h" #include "core/device.h" #include "core/helpers.h" #include "core/logging.h" diff --git a/alc/backends/null.cpp b/alc/backends/null.cpp index 5a8fc255..73420ad3 100644 --- a/alc/backends/null.cpp +++ b/alc/backends/null.cpp @@ -30,10 +30,10 @@ #include #include -#include "core/device.h" +#include "althrd_setname.h" #include "almalloc.h" +#include "core/device.h" #include "core/helpers.h" -#include "threads.h" namespace { diff --git a/alc/backends/opensl.cpp b/alc/backends/opensl.cpp index c9053816..a3b70791 100644 --- a/alc/backends/opensl.cpp +++ b/alc/backends/opensl.cpp @@ -35,6 +35,7 @@ #include "albit.h" #include "alnumeric.h" +#include "althrd_setname.h" #include "core/device.h" #include "core/helpers.h" #include "core/logging.h" diff --git a/alc/backends/oss.cpp b/alc/backends/oss.cpp index dc18c4c3..554ccc24 100644 --- a/alc/backends/oss.cpp +++ b/alc/backends/oss.cpp @@ -43,11 +43,11 @@ #include "alc/alconfig.h" #include "almalloc.h" #include "alnumeric.h" +#include "althrd_setname.h" #include "core/device.h" #include "core/helpers.h" #include "core/logging.h" #include "ringbuffer.h" -#include "threads.h" #include diff --git a/alc/backends/sndio.cpp b/alc/backends/sndio.cpp index 2040dd3a..84c54c62 100644 --- a/alc/backends/sndio.cpp +++ b/alc/backends/sndio.cpp @@ -32,11 +32,11 @@ #include #include "alnumeric.h" +#include "althrd_setname.h" #include "core/device.h" #include "core/helpers.h" #include "core/logging.h" #include "ringbuffer.h" -#include "threads.h" #include diff --git a/alc/backends/solaris.cpp b/alc/backends/solaris.cpp index ae87e7eb..15dcc98f 100644 --- a/alc/backends/solaris.cpp +++ b/alc/backends/solaris.cpp @@ -41,10 +41,10 @@ #include #include "alc/alconfig.h" +#include "althrd_setname.h" #include "core/device.h" #include "core/helpers.h" #include "core/logging.h" -#include "threads.h" #include diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 32a4334d..2b88aa96 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -61,6 +61,7 @@ #include "alc/events.h" #include "alnumeric.h" #include "alspan.h" +#include "althrd_setname.h" #include "comptr.h" #include "core/converter.h" #include "core/device.h" @@ -68,7 +69,6 @@ #include "core/logging.h" #include "ringbuffer.h" #include "strutils.h" -#include "threads.h" #if defined(ALSOFT_UWP) #include diff --git a/alc/backends/wave.cpp b/alc/backends/wave.cpp index 1ee2fe51..40592ee7 100644 --- a/alc/backends/wave.cpp +++ b/alc/backends/wave.cpp @@ -38,12 +38,12 @@ #include "alc/alconfig.h" #include "almalloc.h" #include "alnumeric.h" +#include "althrd_setname.h" #include "core/device.h" #include "core/helpers.h" #include "core/logging.h" #include "opthelpers.h" #include "strutils.h" -#include "threads.h" namespace { diff --git a/alc/backends/winmm.cpp b/alc/backends/winmm.cpp index 0345fe10..fa5bf22a 100644 --- a/alc/backends/winmm.cpp +++ b/alc/backends/winmm.cpp @@ -39,6 +39,7 @@ #include #include "alnumeric.h" +#include "althrd_setname.h" #include "core/device.h" #include "core/helpers.h" #include "core/logging.h" diff --git a/common/althrd_setname.cpp b/common/althrd_setname.cpp new file mode 100644 index 00000000..22d33092 --- /dev/null +++ b/common/althrd_setname.cpp @@ -0,0 +1,76 @@ + +#include "config.h" + +#include "althrd_setname.h" + + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include + +void althrd_setname(const char *name [[maybe_unused]]) +{ +#if defined(_MSC_VER) && !defined(_M_ARM) + +#define MS_VC_EXCEPTION 0x406D1388 +#pragma pack(push,8) + struct { + DWORD dwType; // Must be 0x1000. + LPCSTR szName; // Pointer to name (in user addr space). + DWORD dwThreadID; // Thread ID (-1=caller thread). + DWORD dwFlags; // Reserved for future use, must be zero. + } info; +#pragma pack(pop) + info.dwType = 0x1000; + info.szName = name; + info.dwThreadID = ~DWORD{0}; + info.dwFlags = 0; + + /* FIXME: How to do this on MinGW? */ + __try { + RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info); + } + __except(EXCEPTION_CONTINUE_EXECUTION) { + } +#undef MS_VC_EXCEPTION +#endif +} + +#else + +#include +#ifdef HAVE_PTHREAD_NP_H +#include +#endif + +namespace { + +using setname_t1 = int(*)(const char*); +using setname_t2 = int(*)(pthread_t, const char*); +using setname_t3 = void(*)(pthread_t, const char*); +using setname_t4 = int(*)(pthread_t, const char*, void*); + +[[maybe_unused]] void setname_caller(setname_t1 func, const char *name) +{ func(name); } + +[[maybe_unused]] void setname_caller(setname_t2 func, const char *name) +{ func(pthread_self(), name); } + +[[maybe_unused]] void setname_caller(setname_t3 func, const char *name) +{ func(pthread_self(), name); } + +[[maybe_unused]] void setname_caller(setname_t4 func, const char *name) +{ func(pthread_self(), "%s", static_cast(const_cast(name))); } + +} // namespace + +void althrd_setname(const char *name [[maybe_unused]]) +{ +#if defined(HAVE_PTHREAD_SET_NAME_NP) + setname_caller(pthread_set_name_np, name); +#elif defined(HAVE_PTHREAD_SETNAME_NP) + setname_caller(pthread_setname_np, name); +#endif +} + +#endif diff --git a/common/althrd_setname.h b/common/althrd_setname.h new file mode 100644 index 00000000..0e22c0a9 --- /dev/null +++ b/common/althrd_setname.h @@ -0,0 +1,6 @@ +#ifndef COMMON_ALTHRD_SETNAME_H +#define COMMON_ALTHRD_SETNAME_H + +void althrd_setname(const char *name); + +#endif /* COMMON_ALTHRD_SETNAME_H */ diff --git a/common/threads.cpp b/common/threads.cpp index c1d9e8b0..c176f5af 100644 --- a/common/threads.cpp +++ b/common/threads.cpp @@ -32,37 +32,6 @@ #include -void althrd_setname(const char *name) -{ -#if defined(_MSC_VER) && !defined(_M_ARM) - -#define MS_VC_EXCEPTION 0x406D1388 -#pragma pack(push,8) - struct { - DWORD dwType; // Must be 0x1000. - LPCSTR szName; // Pointer to name (in user addr space). - DWORD dwThreadID; // Thread ID (-1=caller thread). - DWORD dwFlags; // Reserved for future use, must be zero. - } info; -#pragma pack(pop) - info.dwType = 0x1000; - info.szName = name; - info.dwThreadID = ~DWORD{0}; - info.dwFlags = 0; - - __try { - RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info); - } - __except(EXCEPTION_CONTINUE_EXECUTION) { - } -#undef MS_VC_EXCEPTION - -#else - - (void)name; -#endif -} - namespace al { semaphore::semaphore(unsigned int initial) @@ -93,41 +62,6 @@ bool semaphore::try_wait() noexcept #else -#include -#ifdef HAVE_PTHREAD_NP_H -#include -#endif - -namespace { - -using setname_t1 = int(*)(const char*); -using setname_t2 = int(*)(pthread_t, const char*); -using setname_t3 = void(*)(pthread_t, const char*); -using setname_t4 = int(*)(pthread_t, const char*, void*); - -[[maybe_unused]] void setname_caller(setname_t1 func, const char *name) -{ func(name); } - -[[maybe_unused]] void setname_caller(setname_t2 func, const char *name) -{ func(pthread_self(), name); } - -[[maybe_unused]] void setname_caller(setname_t3 func, const char *name) -{ func(pthread_self(), name); } - -[[maybe_unused]] void setname_caller(setname_t4 func, const char *name) -{ func(pthread_self(), "%s", static_cast(const_cast(name))); } - -} // namespace - -void althrd_setname(const char *name [[maybe_unused]]) -{ -#if defined(HAVE_PTHREAD_SET_NAME_NP) - setname_caller(pthread_set_name_np, name); -#elif defined(HAVE_PTHREAD_SETNAME_NP) - setname_caller(pthread_setname_np, name); -#endif -} - /* Do not try using libdispatch on systems where it is absent. */ #if defined(AL_APPLE_HAVE_DISPATCH) diff --git a/common/threads.h b/common/threads.h index 1ef037bb..703d50d4 100644 --- a/common/threads.h +++ b/common/threads.h @@ -14,8 +14,6 @@ #include #endif -void althrd_setname(const char *name); - namespace al { class semaphore { -- cgit v1.2.3 From 2b7ab0b75086f3d73a7ffe9bc05a80e5d9c625f5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Jun 2023 18:16:17 -0700 Subject: Rename threads.cpp/h to alsem.cpp/h --- CMakeLists.txt | 4 +- al/debug.cpp | 1 - al/event.cpp | 1 - al/source.cpp | 1 - alc/alc.cpp | 1 - alc/alu.cpp | 1 - alc/backends/jack.cpp | 2 +- alc/backends/opensl.cpp | 2 +- alc/backends/winmm.cpp | 2 +- alc/context.cpp | 1 - alc/events.cpp | 1 - common/alsem.cpp | 126 ++++++++++++++++++++++++++++++++++++++++++++++++ common/alsem.h | 43 +++++++++++++++++ common/threads.cpp | 125 ----------------------------------------------- common/threads.h | 43 ----------------- core/context.h | 2 +- 16 files changed, 175 insertions(+), 181 deletions(-) create mode 100644 common/alsem.cpp create mode 100644 common/alsem.h delete mode 100644 common/threads.cpp delete mode 100644 common/threads.h (limited to 'alc/backends') diff --git a/CMakeLists.txt b/CMakeLists.txt index 63a213c9..c73dee55 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -618,6 +618,8 @@ set(COMMON_OBJS common/almalloc.h common/alnumbers.h common/alnumeric.h + common/alsem.cpp + common/alsem.h common/alspan.h common/alstring.cpp common/alstring.h @@ -638,8 +640,6 @@ set(COMMON_OBJS common/ringbuffer.h common/strutils.cpp common/strutils.h - common/threads.cpp - common/threads.h common/vecmat.h common/vector.h) diff --git a/al/debug.cpp b/al/debug.cpp index 56705c65..af67859a 100644 --- a/al/debug.cpp +++ b/al/debug.cpp @@ -20,7 +20,6 @@ #include "core/logging.h" #include "direct_defs.h" #include "opthelpers.h" -#include "threads.h" namespace { diff --git a/al/event.cpp b/al/event.cpp index a5b5fdc5..ef58f86d 100644 --- a/al/event.cpp +++ b/al/event.cpp @@ -30,7 +30,6 @@ #include "direct_defs.h" #include "opthelpers.h" #include "ringbuffer.h" -#include "threads.h" namespace { diff --git a/al/source.cpp b/al/source.cpp index 8dbbbcd8..8f4d4d48 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -73,7 +73,6 @@ #include "filter.h" #include "opthelpers.h" #include "ringbuffer.h" -#include "threads.h" #ifdef ALSOFT_EAX #include diff --git a/alc/alc.cpp b/alc/alc.cpp index 128b3d7e..48fa19ec 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -103,7 +103,6 @@ #include "intrusive_ptr.h" #include "opthelpers.h" #include "strutils.h" -#include "threads.h" #include "backends/base.h" #include "backends/null.h" diff --git a/alc/alu.cpp b/alc/alu.cpp index c43da639..0130f280 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -77,7 +77,6 @@ #include "opthelpers.h" #include "ringbuffer.h" #include "strutils.h" -#include "threads.h" #include "vecmat.h" #include "vector.h" diff --git a/alc/backends/jack.cpp b/alc/backends/jack.cpp index b8325b05..66fc0877 100644 --- a/alc/backends/jack.cpp +++ b/alc/backends/jack.cpp @@ -35,13 +35,13 @@ #include "albit.h" #include "alc/alconfig.h" #include "alnumeric.h" +#include "alsem.h" #include "althrd_setname.h" #include "core/device.h" #include "core/helpers.h" #include "core/logging.h" #include "dynload.h" #include "ringbuffer.h" -#include "threads.h" #include #include diff --git a/alc/backends/opensl.cpp b/alc/backends/opensl.cpp index a3b70791..2a161056 100644 --- a/alc/backends/opensl.cpp +++ b/alc/backends/opensl.cpp @@ -35,13 +35,13 @@ #include "albit.h" #include "alnumeric.h" +#include "alsem.h" #include "althrd_setname.h" #include "core/device.h" #include "core/helpers.h" #include "core/logging.h" #include "opthelpers.h" #include "ringbuffer.h" -#include "threads.h" #include #include diff --git a/alc/backends/winmm.cpp b/alc/backends/winmm.cpp index fa5bf22a..661585cd 100644 --- a/alc/backends/winmm.cpp +++ b/alc/backends/winmm.cpp @@ -39,13 +39,13 @@ #include #include "alnumeric.h" +#include "alsem.h" #include "althrd_setname.h" #include "core/device.h" #include "core/helpers.h" #include "core/logging.h" #include "ringbuffer.h" #include "strutils.h" -#include "threads.h" #ifndef WAVE_FORMAT_IEEE_FLOAT #define WAVE_FORMAT_IEEE_FLOAT 0x0003 diff --git a/alc/context.cpp b/alc/context.cpp index bcd72f92..142ad50c 100644 --- a/alc/context.cpp +++ b/alc/context.cpp @@ -33,7 +33,6 @@ #include "core/voice_change.h" #include "device.h" #include "ringbuffer.h" -#include "threads.h" #include "vecmat.h" #ifdef ALSOFT_EAX diff --git a/alc/events.cpp b/alc/events.cpp index b5b65cb1..b14b1a8d 100644 --- a/alc/events.cpp +++ b/alc/events.cpp @@ -6,7 +6,6 @@ #include #include "alspan.h" -#include "common/threads.h" #include "core/logging.h" #include "device.h" diff --git a/common/alsem.cpp b/common/alsem.cpp new file mode 100644 index 00000000..6a92b35c --- /dev/null +++ b/common/alsem.cpp @@ -0,0 +1,126 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2007 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "alsem.h" + +#include + +#include "opthelpers.h" + + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include + +#include + +namespace al { + +semaphore::semaphore(unsigned int initial) +{ + if(initial > static_cast(std::numeric_limits::max())) + throw std::system_error(std::make_error_code(std::errc::value_too_large)); + mSem = CreateSemaphore(nullptr, initial, std::numeric_limits::max(), nullptr); + if(mSem == nullptr) + throw std::system_error(std::make_error_code(std::errc::resource_unavailable_try_again)); +} + +semaphore::~semaphore() +{ CloseHandle(mSem); } + +void semaphore::post() +{ + if(!ReleaseSemaphore(static_cast(mSem), 1, nullptr)) + throw std::system_error(std::make_error_code(std::errc::value_too_large)); +} + +void semaphore::wait() noexcept +{ WaitForSingleObject(static_cast(mSem), INFINITE); } + +bool semaphore::try_wait() noexcept +{ return WaitForSingleObject(static_cast(mSem), 0) == WAIT_OBJECT_0; } + +} // namespace al + +#else + +/* Do not try using libdispatch on systems where it is absent. */ +#if defined(AL_APPLE_HAVE_DISPATCH) + +namespace al { + +semaphore::semaphore(unsigned int initial) +{ + mSem = dispatch_semaphore_create(initial); + if(!mSem) + throw std::system_error(std::make_error_code(std::errc::resource_unavailable_try_again)); +} + +semaphore::~semaphore() +{ dispatch_release(mSem); } + +void semaphore::post() +{ dispatch_semaphore_signal(mSem); } + +void semaphore::wait() noexcept +{ dispatch_semaphore_wait(mSem, DISPATCH_TIME_FOREVER); } + +bool semaphore::try_wait() noexcept +{ return dispatch_semaphore_wait(mSem, DISPATCH_TIME_NOW) == 0; } + +} // namespace al + +#else /* !__APPLE__ */ + +#include + +namespace al { + +semaphore::semaphore(unsigned int initial) +{ + if(sem_init(&mSem, 0, initial) != 0) + throw std::system_error(std::make_error_code(std::errc::resource_unavailable_try_again)); +} + +semaphore::~semaphore() +{ sem_destroy(&mSem); } + +void semaphore::post() +{ + if(sem_post(&mSem) != 0) + throw std::system_error(std::make_error_code(std::errc::value_too_large)); +} + +void semaphore::wait() noexcept +{ + while(sem_wait(&mSem) == -1 && errno == EINTR) { + } +} + +bool semaphore::try_wait() noexcept +{ return sem_trywait(&mSem) == 0; } + +} // namespace al + +#endif /* __APPLE__ */ + +#endif /* _WIN32 */ diff --git a/common/alsem.h b/common/alsem.h new file mode 100644 index 00000000..9f72d1c6 --- /dev/null +++ b/common/alsem.h @@ -0,0 +1,43 @@ +#ifndef COMMON_ALSEM_H +#define COMMON_ALSEM_H + +#if defined(__APPLE__) +#include +#include +#if (((MAC_OS_X_VERSION_MIN_REQUIRED > 1050) && !defined(__ppc__)) || TARGET_OS_IOS || TARGET_OS_TV) +#include +#define AL_APPLE_HAVE_DISPATCH 1 +#else +#include /* Fallback option for Apple without a working libdispatch */ +#endif +#elif !defined(_WIN32) +#include +#endif + +namespace al { + +class semaphore { +#ifdef _WIN32 + using native_type = void*; +#elif defined(AL_APPLE_HAVE_DISPATCH) + using native_type = dispatch_semaphore_t; +#else + using native_type = sem_t; +#endif + native_type mSem; + +public: + semaphore(unsigned int initial=0); + semaphore(const semaphore&) = delete; + ~semaphore(); + + semaphore& operator=(const semaphore&) = delete; + + void post(); + void wait() noexcept; + bool try_wait() noexcept; +}; + +} // namespace al + +#endif /* COMMON_ALSEM_H */ diff --git a/common/threads.cpp b/common/threads.cpp deleted file mode 100644 index c176f5af..00000000 --- a/common/threads.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 1999-2007 by authors. - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "opthelpers.h" -#include "threads.h" - -#include - - -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include - -#include - -namespace al { - -semaphore::semaphore(unsigned int initial) -{ - if(initial > static_cast(std::numeric_limits::max())) - throw std::system_error(std::make_error_code(std::errc::value_too_large)); - mSem = CreateSemaphore(nullptr, initial, std::numeric_limits::max(), nullptr); - if(mSem == nullptr) - throw std::system_error(std::make_error_code(std::errc::resource_unavailable_try_again)); -} - -semaphore::~semaphore() -{ CloseHandle(mSem); } - -void semaphore::post() -{ - if(!ReleaseSemaphore(static_cast(mSem), 1, nullptr)) - throw std::system_error(std::make_error_code(std::errc::value_too_large)); -} - -void semaphore::wait() noexcept -{ WaitForSingleObject(static_cast(mSem), INFINITE); } - -bool semaphore::try_wait() noexcept -{ return WaitForSingleObject(static_cast(mSem), 0) == WAIT_OBJECT_0; } - -} // namespace al - -#else - -/* Do not try using libdispatch on systems where it is absent. */ -#if defined(AL_APPLE_HAVE_DISPATCH) - -namespace al { - -semaphore::semaphore(unsigned int initial) -{ - mSem = dispatch_semaphore_create(initial); - if(!mSem) - throw std::system_error(std::make_error_code(std::errc::resource_unavailable_try_again)); -} - -semaphore::~semaphore() -{ dispatch_release(mSem); } - -void semaphore::post() -{ dispatch_semaphore_signal(mSem); } - -void semaphore::wait() noexcept -{ dispatch_semaphore_wait(mSem, DISPATCH_TIME_FOREVER); } - -bool semaphore::try_wait() noexcept -{ return dispatch_semaphore_wait(mSem, DISPATCH_TIME_NOW) == 0; } - -} // namespace al - -#else /* !__APPLE__ */ - -#include - -namespace al { - -semaphore::semaphore(unsigned int initial) -{ - if(sem_init(&mSem, 0, initial) != 0) - throw std::system_error(std::make_error_code(std::errc::resource_unavailable_try_again)); -} - -semaphore::~semaphore() -{ sem_destroy(&mSem); } - -void semaphore::post() -{ - if(sem_post(&mSem) != 0) - throw std::system_error(std::make_error_code(std::errc::value_too_large)); -} - -void semaphore::wait() noexcept -{ - while(sem_wait(&mSem) == -1 && errno == EINTR) { - } -} - -bool semaphore::try_wait() noexcept -{ return sem_trywait(&mSem) == 0; } - -} // namespace al - -#endif /* __APPLE__ */ - -#endif /* _WIN32 */ diff --git a/common/threads.h b/common/threads.h deleted file mode 100644 index 703d50d4..00000000 --- a/common/threads.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef AL_THREADS_H -#define AL_THREADS_H - -#if defined(__APPLE__) -#include -#include -#if (((MAC_OS_X_VERSION_MIN_REQUIRED > 1050) && !defined(__ppc__)) || TARGET_OS_IOS || TARGET_OS_TV) -#include -#define AL_APPLE_HAVE_DISPATCH 1 -#else -#include /* Fallback option for Apple without a working libdispatch */ -#endif -#elif !defined(_WIN32) -#include -#endif - -namespace al { - -class semaphore { -#ifdef _WIN32 - using native_type = void*; -#elif defined(AL_APPLE_HAVE_DISPATCH) - using native_type = dispatch_semaphore_t; -#else - using native_type = sem_t; -#endif - native_type mSem; - -public: - semaphore(unsigned int initial=0); - semaphore(const semaphore&) = delete; - ~semaphore(); - - semaphore& operator=(const semaphore&) = delete; - - void post(); - void wait() noexcept; - bool try_wait() noexcept; -}; - -} // namespace al - -#endif /* AL_THREADS_H */ diff --git a/core/context.h b/core/context.h index 629e67a5..ccb7dd3b 100644 --- a/core/context.h +++ b/core/context.h @@ -10,11 +10,11 @@ #include #include "almalloc.h" +#include "alsem.h" #include "alspan.h" #include "async_event.h" #include "atomic.h" #include "opthelpers.h" -#include "threads.h" #include "vecmat.h" struct DeviceBase; -- cgit v1.2.3 From 6752d5516c8b30fe7db559c7f3a1423705d2a4fd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Jun 2023 19:05:57 -0700 Subject: Use cinttypes instead of inttypes.h in C++ --- al/source.cpp | 2 +- alc/backends/coreaudio.cpp | 2 +- alc/backends/sndio.cpp | 2 +- utils/uhjencoder.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'alc/backends') diff --git a/al/source.cpp b/al/source.cpp index 8f4d4d48..7e425d43 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -27,11 +27,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index 1e8423b7..c2888e42 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -22,8 +22,8 @@ #include "coreaudio.h" +#include #include -#include #include #include #include diff --git a/alc/backends/sndio.cpp b/alc/backends/sndio.cpp index 84c54c62..89eee941 100644 --- a/alc/backends/sndio.cpp +++ b/alc/backends/sndio.cpp @@ -22,8 +22,8 @@ #include "sndio.h" +#include #include -#include #include #include #include diff --git a/utils/uhjencoder.cpp b/utils/uhjencoder.cpp index c381d1b9..91e4dbd0 100644 --- a/utils/uhjencoder.cpp +++ b/utils/uhjencoder.cpp @@ -25,8 +25,8 @@ #include "config.h" #include +#include #include -#include #include #include #include -- cgit v1.2.3 From 75cbbd0c02be29e2cd6a5b735306158d21765e38 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Jun 2023 22:33:50 -0700 Subject: Remove an unused lambda --- alc/backends/wasapi.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 2b88aa96..a554d1b4 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -237,15 +237,9 @@ public: #if defined(ALSOFT_UWP) mActiveClientEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); - auto cb = [](alc::DeviceType type, const WCHAR *devid) - { - const std::string msg{"Default device changed: "+wstr_to_utf8(devid)}; - alc::Event(alc::EventType::DefaultDeviceChanged, type, msg); - }; - mRenderDeviceChangedToken = MediaDevice::DefaultAudioRenderDeviceChanged += ref new TypedEventHandler( - [this,cb](Platform::Object ^ sender, DefaultAudioRenderDeviceChangedEventArgs ^ args) { + [this](Platform::Object ^ sender, DefaultAudioRenderDeviceChangedEventArgs ^ args) { if(args->Role == AudioDeviceRole::Default) { const std::string msg{"Default playback device changed: "+ @@ -256,7 +250,7 @@ public: }); mCaptureDeviceChangedToken = MediaDevice::DefaultAudioCaptureDeviceChanged += ref new TypedEventHandler( - [this,cb](Platform::Object ^ sender, DefaultAudioCaptureDeviceChangedEventArgs ^ args) { + [this](Platform::Object ^ sender, DefaultAudioCaptureDeviceChangedEventArgs ^ args) { if(args->Role == AudioDeviceRole::Default) { const std::string msg{"Default capture device changed: "+ -- cgit v1.2.3 From d769041916df4efb48fd212683dc9842decc10f1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 2 Jun 2023 19:12:48 -0700 Subject: Start the WASAPI COM thread when initializing the backend COM doesn't make this easy. We want to be able to get device change notifications without an open device, but we need an IMMDeviceEnumerator object to register the notification client, which requires COM to be initialized. COM must then stay initialized while we have the IMMDeviceEnumerator object, which we can't assume for the calling thread so it has to be done in the COM thread. Consequently, the COM thread must stay alive and can't quit while the DLL is loaded if we want to get those notifications without an open device, and as there's no reliable way to make the thread quit during DLL unload, the DLL must stay pinned until process exit. --- alc/backends/wasapi.cpp | 163 +++++++++++------------------------------------- 1 file changed, 38 insertions(+), 125 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index a554d1b4..333c0dc7 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -222,7 +222,6 @@ struct DeviceHandle using EventRegistrationToken = Windows::Foundation::EventRegistrationToken; #else using DeviceHandle = ComPtr; -using EventRegistrationToken = void*; #endif #if defined(ALSOFT_UWP) @@ -231,7 +230,6 @@ struct DeviceHelper final : public IActivateAudioInterfaceCompletionHandler struct DeviceHelper final : private IMMNotificationClient #endif { -public: DeviceHelper() { #if defined(ALSOFT_UWP) @@ -259,13 +257,6 @@ public: msg); } }); -#else - HRESULT hr{CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, - IID_IMMDeviceEnumerator, al::out_ptr(mEnumerator))}; - if(SUCCEEDED(hr)) - mEnumerator->RegisterEndpointNotificationCallback(this); - else - WARN("Failed to create IMMDeviceEnumerator instance: 0x%08lx\n", hr); #endif } ~DeviceHelper() @@ -287,13 +278,7 @@ public: /** -------------------------- IUnkonwn ----------------------------- */ std::atomic mRefCount{1}; STDMETHODIMP_(ULONG) AddRef() noexcept override { return mRefCount.fetch_add(1u) + 1u; } - - STDMETHODIMP_(ULONG) Release() noexcept override - { - auto ret = mRefCount.fetch_sub(1u) - 1u; - if(!ret) delete this; - return ret; - } + STDMETHODIMP_(ULONG) Release() noexcept override { return mRefCount.fetch_sub(1u) - 1u; } STDMETHODIMP QueryInterface(const IID& IId, void **UnknownPtrPtr) noexcept override { @@ -394,7 +379,22 @@ public: #endif /** -------------------------- DeviceHelper ----------------------------- */ - HRESULT OpenDevice(LPCWSTR devid, EDataFlow flow, DeviceHandle& device) + HRESULT init() + { +#if !defined(ALSOFT_UWP) + HRESULT hr{CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, + IID_IMMDeviceEnumerator, al::out_ptr(mEnumerator))}; + if(SUCCEEDED(hr)) + mEnumerator->RegisterEndpointNotificationCallback(this); + else + WARN("Failed to create IMMDeviceEnumerator instance: 0x%08lx\n", hr); + return hr; +#else + return S_OK; +#endif + } + + HRESULT openDevice(LPCWSTR devid, EDataFlow flow, DeviceHandle& device) { #if !defined(ALSOFT_UWP) HRESULT hr{E_POINTER}; @@ -425,7 +425,7 @@ public: #endif } - HRESULT ActivateAudioClient(_In_ DeviceHandle& device, void **ppv) + static HRESULT ActivateAudioClient(_In_ DeviceHandle& device, void **ppv) { #if !defined(ALSOFT_UWP) HRESULT hr{device->Activate(__uuidof(IAudioClient3), CLSCTX_INPROC_SERVER, nullptr, ppv)}; @@ -570,7 +570,6 @@ public: WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvprop->vt); guid = UnknownGuid; } - #else auto devInfo = device.value; std::string name = wstr_to_utf8(devInfo->Name->Data()); @@ -798,7 +797,7 @@ struct WasapiProxy { virtual HRESULT resetProxy() = 0; virtual HRESULT startProxy() = 0; - virtual void stopProxy() = 0; + virtual void stopProxy() = 0; struct Msg { MsgType mType; @@ -808,14 +807,11 @@ struct WasapiProxy { explicit operator bool() const noexcept { return mType != MsgType::QuitThread; } }; - static std::thread sThread; static std::deque mMsgQueue; static std::mutex mMsgQueueLock; static std::condition_variable mMsgQueueCond; - static std::mutex sThreadLock; - static size_t sInitCount; - static ComPtr sDeviceHelper; + static std::optional sDeviceHelper; std::future pushMessage(MsgType type, const char *param=nullptr) { @@ -851,45 +847,11 @@ struct WasapiProxy { } static int messageHandler(std::promise *promise); - - static HRESULT InitThread() - { - std::lock_guard _{sThreadLock}; - HRESULT res{S_OK}; - if(!sThread.joinable()) - { - std::promise promise; - auto future = promise.get_future(); - - sThread = std::thread{&WasapiProxy::messageHandler, &promise}; - res = future.get(); - if(FAILED(res)) - { - sThread.join(); - return res; - } - } - ++sInitCount; - return res; - } - - static void DeinitThread() - { - std::lock_guard _{sThreadLock}; - if(!--sInitCount && sThread.joinable()) - { - pushMessageStatic(MsgType::QuitThread); - sThread.join(); - } - } }; -std::thread WasapiProxy::sThread; std::deque WasapiProxy::mMsgQueue; std::mutex WasapiProxy::mMsgQueueLock; std::condition_variable WasapiProxy::mMsgQueueCond; -std::mutex WasapiProxy::sThreadLock; -ComPtr WasapiProxy::sDeviceHelper; -size_t WasapiProxy::sInitCount{0}; +std::optional WasapiProxy::sDeviceHelper; int WasapiProxy::messageHandler(std::promise *promise) { @@ -902,8 +864,12 @@ int WasapiProxy::messageHandler(std::promise *promise) promise->set_value(hr); return 0; } - promise->set_value(S_OK); + + hr = sDeviceHelper.emplace().init(); + promise->set_value(hr); promise = nullptr; + if(FAILED(hr)) + goto skip_loop; TRACE("Starting message loop\n"); while(Msg msg{popMessage()}) @@ -956,6 +922,9 @@ int WasapiProxy::messageHandler(std::promise *promise) msg.mPromise.set_value(E_FAIL); } TRACE("Message loop finished\n"); + +skip_loop: + sDeviceHelper.reset(); CoUninitialize(); return 0; @@ -1005,10 +974,7 @@ struct WasapiPlayback final : public BackendBase, WasapiProxy { WasapiPlayback::~WasapiPlayback() { if(SUCCEEDED(mOpenStatus)) - { pushMessage(MsgType::CloseDevice).wait(); - DeinitThread(); - } mOpenStatus = E_FAIL; if(mNotifyEvent != nullptr) @@ -1121,13 +1087,6 @@ void WasapiPlayback::open(const char *name) "Failed to create notify events"}; } - HRESULT hr{InitThread()}; - if(FAILED(hr)) - { - throw al::backend_exception{al::backend_error::DeviceError, - "Failed to init COM thread: 0x%08lx", hr}; - } - if(name) { if(PlaybackDevices.empty()) @@ -1142,11 +1101,8 @@ void WasapiPlayback::open(const char *name) mOpenStatus = pushMessage(MsgType::OpenDevice, name).get(); if(FAILED(mOpenStatus)) - { - DeinitThread(); throw al::backend_exception{al::backend_error::DeviceError, "Device init failed: 0x%08lx", mOpenStatus}; - } } HRESULT WasapiPlayback::openProxy(const char *name) @@ -1173,14 +1129,14 @@ HRESULT WasapiPlayback::openProxy(const char *name) devid = iter->devid.c_str(); } - HRESULT hr{sDeviceHelper->OpenDevice(devid, eRender, mMMDev)}; - if (FAILED(hr)) + HRESULT hr{sDeviceHelper->openDevice(devid, eRender, mMMDev)}; + if(FAILED(hr)) { WARN("Failed to open device \"%s\"\n", name ? name : "(default)"); return hr; } mClient = nullptr; - if (name) + if(name) mDevice->DeviceName = std::string{DevNameHead} + name; else mDevice->DeviceName = DevNameHead + DeviceHelper::get_device_name_and_guid(mMMDev).first; @@ -1657,10 +1613,7 @@ struct WasapiCapture final : public BackendBase, WasapiProxy { WasapiCapture::~WasapiCapture() { if(SUCCEEDED(mOpenStatus)) - { pushMessage(MsgType::CloseDevice).wait(); - DeinitThread(); - } mOpenStatus = E_FAIL; if(mNotifyEvent != nullptr) @@ -1775,13 +1728,6 @@ void WasapiCapture::open(const char *name) "Failed to create notify events"}; } - HRESULT hr{InitThread()}; - if(FAILED(hr)) - { - throw al::backend_exception{al::backend_error::DeviceError, - "Failed to init COM thread: 0x%08lx", hr}; - } - if(name) { if(CaptureDevices.empty()) @@ -1796,13 +1742,10 @@ void WasapiCapture::open(const char *name) mOpenStatus = pushMessage(MsgType::OpenDevice, name).get(); if(FAILED(mOpenStatus)) - { - DeinitThread(); throw al::backend_exception{al::backend_error::DeviceError, "Device init failed: 0x%08lx", mOpenStatus}; - } - hr = pushMessage(MsgType::ResetDevice).get(); + HRESULT hr{pushMessage(MsgType::ResetDevice).get()}; if(FAILED(hr)) { if(hr == E_OUTOFMEMORY) @@ -1835,7 +1778,7 @@ HRESULT WasapiCapture::openProxy(const char *name) devid = iter->devid.c_str(); } - HRESULT hr{sDeviceHelper->OpenDevice(devid, eCapture, mMMDev)}; + HRESULT hr{sDeviceHelper->openDevice(devid, eCapture, mMMDev)}; if (FAILED(hr)) { WARN("Failed to open device \"%s\"\n", name ? name : "(default)"); @@ -2210,34 +2153,13 @@ uint WasapiCapture::availableSamples() bool WasapiBackendFactory::init() { static HRESULT InitResult{E_FAIL}; - if(FAILED(InitResult)) try { - auto res = std::async(std::launch::async, []() -> HRESULT - { - HRESULT hr{CoInitializeEx(nullptr, COINIT_MULTITHREADED)}; - if(FAILED(hr)) - { - WARN("Failed to initialize COM: 0x%08lx\n", hr); - return hr; - } -#if !defined(ALSOFT_UWP) - ComPtr enumerator; - hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, - IID_IMMDeviceEnumerator, al::out_ptr(enumerator)); - if(FAILED(hr)) - WARN("Failed to create IMMDeviceEnumerator instance: 0x%08lx\n", hr); - enumerator = nullptr; -#endif - if(SUCCEEDED(hr)) - WasapiProxy::sDeviceHelper.reset(new DeviceHelper{}); - - CoUninitialize(); - - return hr; - }); + std::promise promise; + auto future = promise.get_future(); - InitResult = res.get(); + std::thread{&WasapiProxy::messageHandler, &promise}.detach(); + InitResult = future.get(); } catch(...) { } @@ -2250,16 +2172,7 @@ bool WasapiBackendFactory::querySupport(BackendType type) std::string WasapiBackendFactory::probe(BackendType type) { - struct ProxyControl { - HRESULT mResult{}; - ProxyControl() { mResult = WasapiProxy::InitThread(); } - ~ProxyControl() { if(SUCCEEDED(mResult)) WasapiProxy::DeinitThread(); } - }; - ProxyControl proxy; - std::string outnames; - if(FAILED(proxy.mResult)) - return outnames; switch(type) { -- cgit v1.2.3 From cb7d5bc6d719c9114982e64c39caf2db7add9c58 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 2 Jun 2023 19:33:21 -0700 Subject: Fix comment typo --- alc/backends/wasapi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 333c0dc7..4e67f7dd 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -275,7 +275,7 @@ struct DeviceHelper final : private IMMNotificationClient #endif } - /** -------------------------- IUnkonwn ----------------------------- */ + /** -------------------------- IUnknown ----------------------------- */ std::atomic mRefCount{1}; STDMETHODIMP_(ULONG) AddRef() noexcept override { return mRefCount.fetch_add(1u) + 1u; } STDMETHODIMP_(ULONG) Release() noexcept override { return mRefCount.fetch_sub(1u) - 1u; } -- cgit v1.2.3 From e7dafb65d73d2caf70a45776c5ffde9e38de4701 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 2 Jun 2023 19:50:03 -0700 Subject: Fix UWP builds --- alc/backends/wasapi.cpp | 46 ++++++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 26 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 4e67f7dd..66400681 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -425,16 +425,29 @@ struct DeviceHelper final : private IMMNotificationClient #endif } - static HRESULT ActivateAudioClient(_In_ DeviceHandle& device, void **ppv) - { #if !defined(ALSOFT_UWP) - HRESULT hr{device->Activate(__uuidof(IAudioClient3), CLSCTX_INPROC_SERVER, nullptr, ppv)}; + static HRESULT ActivateAudioClient(_In_ DeviceHandle& device, void **ppv) + { return device->Activate(__uuidof(IAudioClient3), CLSCTX_INPROC_SERVER, nullptr, ppv); } #else - HRESULT hr{ActivateAudioInterface(device.value->Id->Data(), __uuidof(IAudioClient3), - nullptr, ppv)}; -#endif - return hr; + HRESULT ActivateAudioClient(_In_ DeviceHandle& device, void **ppv) + { + ComPtr asyncOp; + mPPV = ppv; + HRESULT hr{ActivateAudioInterfaceAsync(deviceInterfacePath, riid, activationParams, this, + al::out_ptr(asyncOp))}; + if(FAILED(hr)) + return hr; + asyncOp = nullptr; + + DWORD res{WaitForSingleObjectEx(mActiveClientEvent, 2000, FALSE)}; + if(res != WAIT_OBJECT_0) + { + ERR("WaitForSingleObjectEx error: 0x%lx\n", res); + return E_FAIL; + } + return S_OK; } +#endif HRESULT probe_devices(EDataFlow flowdir, std::vector& list) { @@ -656,25 +669,6 @@ struct DeviceHelper final : private IMMNotificationClient private: #if defined(ALSOFT_UWP) - HRESULT ActivateAudioInterface(_In_ LPCWSTR deviceInterfacePath, - _In_ REFIID riid, - _In_opt_ PROPVARIANT* activationParams, - void** ppv) - { - IActivateAudioInterfaceAsyncOperation* asyncOp{nullptr}; - mPPV = ppv; - HRESULT hr = ActivateAudioInterfaceAsync(deviceInterfacePath, riid, activationParams, this, &asyncOp); - if(FAILED(hr)) - return hr; - if(asyncOp) - asyncOp->Release(); - - DWORD res{WaitForSingleObjectEx(mActiveClientEvent, 2000, FALSE)}; - if(res != WAIT_OBJECT_0) - ERR("WaitForSingleObjectEx error: 0x%lx\n", res); - return res; - } - HANDLE mActiveClientEvent{nullptr}; void** mPPV{nullptr}; -- cgit v1.2.3 From 4c9906284e2b47f79ebbacb6098ac7f619f2fc0f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 2 Jun 2023 20:23:52 -0700 Subject: Try again to fix UWP builds --- alc/backends/wasapi.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 66400681..155f0413 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -433,8 +433,8 @@ struct DeviceHelper final : private IMMNotificationClient { ComPtr asyncOp; mPPV = ppv; - HRESULT hr{ActivateAudioInterfaceAsync(deviceInterfacePath, riid, activationParams, this, - al::out_ptr(asyncOp))}; + HRESULT hr{ActivateAudioInterfaceAsync(device.value->Id->Data(), __uuidof(IAudioClient3), + nullptr, this, al::out_ptr(asyncOp))}; if(FAILED(hr)) return hr; asyncOp = nullptr; -- cgit v1.2.3 From 045a4ff1448d1b8069ccc20d0f38edcbffbb8321 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 3 Jun 2023 21:26:05 -0700 Subject: Use the correct IID for the interface we use --- alc/backends/wasapi.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 155f0413..391976c8 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -426,15 +426,15 @@ struct DeviceHelper final : private IMMNotificationClient } #if !defined(ALSOFT_UWP) - static HRESULT ActivateAudioClient(_In_ DeviceHandle& device, void **ppv) - { return device->Activate(__uuidof(IAudioClient3), CLSCTX_INPROC_SERVER, nullptr, ppv); } + static HRESULT activateAudioClient(_In_ DeviceHandle& device, REFIID iid, void **ppv) + { return device->Activate(iid, CLSCTX_INPROC_SERVER, nullptr, ppv); } #else - HRESULT ActivateAudioClient(_In_ DeviceHandle& device, void **ppv) + HRESULT activateAudioClient(_In_ DeviceHandle& device, _In_ REFIID iid, void **ppv) { ComPtr asyncOp; mPPV = ppv; - HRESULT hr{ActivateAudioInterfaceAsync(device.value->Id->Data(), __uuidof(IAudioClient3), - nullptr, this, al::out_ptr(asyncOp))}; + HRESULT hr{ActivateAudioInterfaceAsync(device.value->Id->Data(), iid, nullptr, this, + al::out_ptr(asyncOp))}; if(FAILED(hr)) return hr; asyncOp = nullptr; @@ -1156,7 +1156,8 @@ bool WasapiPlayback::reset() HRESULT WasapiPlayback::resetProxy() { mClient = nullptr; - HRESULT hr{sDeviceHelper->ActivateAudioClient(mMMDev, al::out_ptr(mClient))}; + HRESULT hr{sDeviceHelper->activateAudioClient(mMMDev, __uuidof(IAudioClient), + al::out_ptr(mClient))}; if(FAILED(hr)) { ERR("Failed to reactivate audio client: 0x%08lx\n", hr); @@ -1797,7 +1798,8 @@ HRESULT WasapiCapture::resetProxy() { mClient = nullptr; - HRESULT hr{sDeviceHelper->ActivateAudioClient(mMMDev, al::out_ptr(mClient))}; + HRESULT hr{sDeviceHelper->activateAudioClient(mMMDev, __uuidof(IAudioClient), + al::out_ptr(mClient))}; if(FAILED(hr)) { ERR("Failed to reactivate audio client: 0x%08lx\n", hr); -- cgit v1.2.3 From 589602c931790dde97b189c809cb1051f9cc25b8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 4 Jun 2023 02:45:39 -0700 Subject: Better protect the WASAPI device list with a mutex --- alc/backends/wasapi.cpp | 130 ++++++++++++++++++++++++++++++------------------ 1 file changed, 82 insertions(+), 48 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 391976c8..a294105b 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -196,8 +196,27 @@ bool checkName(const al::span list, const std::string &name) return std::find_if(list.cbegin(), list.cend(), match_name) != list.cend(); } -std::vector PlaybackDevices; -std::vector CaptureDevices; + +struct DeviceList { + auto lock() noexcept(noexcept(mMutex.lock())) { return mMutex.lock(); } + auto unlock() noexcept(noexcept(mMutex.unlock())) { return mMutex.unlock(); } + +private: + std::mutex mMutex; + std::vector mPlayback; + std::vector mCapture; + + friend struct DeviceListLock; +}; +struct DeviceListLock : public std::unique_lock { + using std::unique_lock::unique_lock; + + auto& getPlaybackList() noexcept(noexcept(mutex())) { return mutex()->mPlayback; } + auto& getCaptureList() noexcept(noexcept(mutex())) { return mutex()->mCapture; } +}; + +DeviceList gDeviceList; + #if defined(ALSOFT_UWP) enum EDataFlow @@ -394,33 +413,34 @@ struct DeviceHelper final : private IMMNotificationClient #endif } - HRESULT openDevice(LPCWSTR devid, EDataFlow flow, DeviceHandle& device) + HRESULT openDevice(std::wstring_view devid, EDataFlow flow, DeviceHandle& device) { #if !defined(ALSOFT_UWP) HRESULT hr{E_POINTER}; if(mEnumerator) { - if (!devid) + if(devid.empty()) hr = mEnumerator->GetDefaultAudioEndpoint(flow, eMultimedia, al::out_ptr(device)); else - hr = mEnumerator->GetDevice(devid, al::out_ptr(device)); + hr = mEnumerator->GetDevice(devid.data(), al::out_ptr(device)); } return hr; #else const auto deviceRole = Windows::Media::Devices::AudioDeviceRole::Default; - Platform::String^ devIfPath = - !devid ? (flow == eRender ? MediaDevice::GetDefaultAudioRenderId(deviceRole) : MediaDevice::GetDefaultAudioCaptureId(deviceRole)) - : ref new Platform::String(devid); + Platform::String^ devIfPath = + devid.empty() ? (flow == eRender ? MediaDevice::GetDefaultAudioRenderId(deviceRole) : MediaDevice::GetDefaultAudioCaptureId(deviceRole)) + : ref new Platform::String(devid.data()); - Concurrency::task createDeviceOp( - DeviceInformation::CreateFromIdAsync(devIfPath, nullptr, DeviceInformationKind::DeviceInterface)); - auto status = createDeviceOp.then([&](DeviceInformation^ deviceInfo) { + Concurrency::task createDeviceOp( + DeviceInformation::CreateFromIdAsync(devIfPath, nullptr, DeviceInformationKind::DeviceInterface)); + auto status = createDeviceOp.then([&](DeviceInformation^ deviceInfo) + { device.value = deviceInfo; - }).wait(); - if (status != Concurrency::task_status::completed) - { - return E_NOINTERFACE; - } + }).wait(); + if(status != Concurrency::task_status::completed) + { + return E_NOINTERFACE; + } return S_OK; #endif } @@ -902,9 +922,11 @@ int WasapiProxy::messageHandler(std::promise *promise) case MsgType::EnumeratePlayback: case MsgType::EnumerateCapture: if(msg.mType == MsgType::EnumeratePlayback) - msg.mPromise.set_value(sDeviceHelper->probe_devices(eRender, PlaybackDevices)); + msg.mPromise.set_value(sDeviceHelper->probe_devices(eRender, + DeviceListLock{gDeviceList}.getPlaybackList())); else if(msg.mType == MsgType::EnumerateCapture) - msg.mPromise.set_value(sDeviceHelper->probe_devices(eCapture, CaptureDevices)); + msg.mPromise.set_value(sDeviceHelper->probe_devices(eCapture, + DeviceListLock{gDeviceList}.getCaptureList())); else msg.mPromise.set_value(E_FAIL); continue; @@ -1083,7 +1105,7 @@ void WasapiPlayback::open(const char *name) if(name) { - if(PlaybackDevices.empty()) + if(DeviceListLock{gDeviceList}.getPlaybackList().empty()) pushMessage(MsgType::EnumeratePlayback); if(std::strncmp(name, DevNameHead, DevNameHeadLen) == 0) { @@ -1101,37 +1123,40 @@ void WasapiPlayback::open(const char *name) HRESULT WasapiPlayback::openProxy(const char *name) { - const wchar_t *devid{nullptr}; + std::string devname; + std::wstring devid; if(name) { - auto iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), + auto devlock = DeviceListLock{gDeviceList}; + auto list = al::span{devlock.getPlaybackList()}; + auto iter = std::find_if(list.cbegin(), list.cend(), [name](const DevMap &entry) -> bool { return entry.name == name || entry.endpoint_guid == name; }); - if(iter == PlaybackDevices.cend()) + if(iter == list.cend()) { const std::wstring wname{utf8_to_wstr(name)}; - iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), + iter = std::find_if(list.cbegin(), list.cend(), [&wname](const DevMap &entry) -> bool { return entry.devid == wname; }); } - if(iter == PlaybackDevices.cend()) + if(iter == list.cend()) { WARN("Failed to find device name matching \"%s\"\n", name); return E_FAIL; } - name = iter->name.c_str(); - devid = iter->devid.c_str(); + devname = iter->name; + devid = iter->devid; } HRESULT hr{sDeviceHelper->openDevice(devid, eRender, mMMDev)}; if(FAILED(hr)) { - WARN("Failed to open device \"%s\"\n", name ? name : "(default)"); + WARN("Failed to open device \"%s\"\n", devname.empty() ? "(default)" : devname.c_str()); return hr; } mClient = nullptr; - if(name) - mDevice->DeviceName = std::string{DevNameHead} + name; + if(!devname.empty()) + mDevice->DeviceName = DevNameHead + std::move(devname); else mDevice->DeviceName = DevNameHead + DeviceHelper::get_device_name_and_guid(mMMDev).first; @@ -1725,7 +1750,7 @@ void WasapiCapture::open(const char *name) if(name) { - if(CaptureDevices.empty()) + if(DeviceListLock{gDeviceList}.getCaptureList().empty()) pushMessage(MsgType::EnumerateCapture); if(std::strncmp(name, DevNameHead, DevNameHeadLen) == 0) { @@ -1751,37 +1776,40 @@ void WasapiCapture::open(const char *name) HRESULT WasapiCapture::openProxy(const char *name) { - const wchar_t *devid{nullptr}; + std::string devname; + std::wstring devid; if(name) { - auto iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), + auto devlock = DeviceListLock{gDeviceList}; + auto devlist = al::span{devlock.getCaptureList()}; + auto iter = std::find_if(devlist.cbegin(), devlist.cend(), [name](const DevMap &entry) -> bool { return entry.name == name || entry.endpoint_guid == name; }); - if(iter == CaptureDevices.cend()) + if(iter == devlist.cend()) { const std::wstring wname{utf8_to_wstr(name)}; - iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), + iter = std::find_if(devlist.cbegin(), devlist.cend(), [&wname](const DevMap &entry) -> bool { return entry.devid == wname; }); } - if(iter == CaptureDevices.cend()) + if(iter == devlist.cend()) { WARN("Failed to find device name matching \"%s\"\n", name); return E_FAIL; } - name = iter->name.c_str(); - devid = iter->devid.c_str(); + devname = iter->name; + devid = iter->devid; } HRESULT hr{sDeviceHelper->openDevice(devid, eCapture, mMMDev)}; - if (FAILED(hr)) + if(FAILED(hr)) { - WARN("Failed to open device \"%s\"\n", name ? name : "(default)"); + WARN("Failed to open device \"%s\"\n", devname.empty() ? "(default)" : devname.c_str()); return hr; } mClient = nullptr; - if (name) - mDevice->DeviceName = std::string{ DevNameHead } + name; + if(!devname.empty()) + mDevice->DeviceName = DevNameHead + std::move(devname); else mDevice->DeviceName = DevNameHead + DeviceHelper::get_device_name_and_guid(mMMDev).first; @@ -2174,19 +2202,25 @@ std::string WasapiBackendFactory::probe(BackendType type) { case BackendType::Playback: WasapiProxy::pushMessageStatic(MsgType::EnumeratePlayback).wait(); - for(const DevMap &entry : PlaybackDevices) { - /* +1 to also append the null char (to ensure a null-separated list - * and double-null terminated list). - */ - outnames.append(DevNameHead).append(entry.name.c_str(), entry.name.length()+1); + auto devlock = DeviceListLock{gDeviceList}; + for(const DevMap &entry : devlock.getPlaybackList()) + { + /* +1 to also append the null char (to ensure a null-separated + * list and double-null terminated list). + */ + outnames.append(DevNameHead).append(entry.name.c_str(), entry.name.length()+1); + } } break; case BackendType::Capture: WasapiProxy::pushMessageStatic(MsgType::EnumerateCapture).wait(); - for(const DevMap &entry : CaptureDevices) - outnames.append(DevNameHead).append(entry.name.c_str(), entry.name.length()+1); + { + auto devlock = DeviceListLock{gDeviceList}; + for(const DevMap &entry : devlock.getCaptureList()) + outnames.append(DevNameHead).append(entry.name.c_str(), entry.name.length()+1); + } break; } -- cgit v1.2.3 From de01990260223aaef5ca9b66051e58d17133e3b1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 5 Jun 2023 07:43:06 -0700 Subject: Handle device added/removed events with WASAPI Non-UWP only for now. The device list is managed dynamically now so it doesn't need to be probed for each enumeration query. --- alc/backends/wasapi.cpp | 271 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 181 insertions(+), 90 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index a294105b..c0c33ffa 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -188,7 +188,10 @@ struct DevMap { , endpoint_guid{std::forward(guid_)} , devid{std::forward(devid_)} { } + /* To prevent GCC from complaining it doesn't want to inline this. */ + ~DevMap(); }; +DevMap::~DevMap() = default; bool checkName(const al::span list, const std::string &name) { @@ -205,22 +208,28 @@ private: std::mutex mMutex; std::vector mPlayback; std::vector mCapture; + std::wstring mPlaybackDefaultId; + std::wstring mCaptureDefaultId; friend struct DeviceListLock; }; struct DeviceListLock : public std::unique_lock { using std::unique_lock::unique_lock; - auto& getPlaybackList() noexcept(noexcept(mutex())) { return mutex()->mPlayback; } - auto& getCaptureList() noexcept(noexcept(mutex())) { return mutex()->mCapture; } + auto& getPlaybackList() const noexcept { return mutex()->mPlayback; } + auto& getCaptureList() const noexcept { return mutex()->mCapture; } + + void setPlaybackDefaultId(std::wstring_view devid) const { mutex()->mPlaybackDefaultId = devid; } + std::wstring_view getPlaybackDefaultId() const noexcept { return mutex()->mPlaybackDefaultId; } + void setCaptureDefaultId(std::wstring_view devid) const { mutex()->mCaptureDefaultId = devid; } + std::wstring_view getCaptureDefaultId() const noexcept { return mutex()->mCaptureDefaultId; } }; DeviceList gDeviceList; #if defined(ALSOFT_UWP) -enum EDataFlow -{ +enum EDataFlow { eRender = 0, eCapture = (eRender + 1), eAll = (eCapture + 1), @@ -229,8 +238,7 @@ enum EDataFlow #endif #if defined(ALSOFT_UWP) -struct DeviceHandle -{ +struct DeviceHandle { DeviceHandle& operator=(std::nullptr_t) { value = nullptr; @@ -252,6 +260,9 @@ struct DeviceHelper final : private IMMNotificationClient DeviceHelper() { #if defined(ALSOFT_UWP) + /* TODO: UWP also needs to watch for device added/removed events and + * dynamically add/remove devices from the lists. + */ mActiveClientEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); mRenderDeviceChangedToken = MediaDevice::DefaultAudioRenderDeviceChanged += @@ -373,8 +384,16 @@ struct DeviceHelper final : private IMMNotificationClient #else /** ----------------------- IMMNotificationClient ------------ */ STDMETHODIMP OnDeviceStateChanged(LPCWSTR /*pwstrDeviceId*/, DWORD /*dwNewState*/) noexcept override { return S_OK; } - STDMETHODIMP OnDeviceAdded(LPCWSTR /*pwstrDeviceId*/) noexcept override { return S_OK; } - STDMETHODIMP OnDeviceRemoved(LPCWSTR /*pwstrDeviceId*/) noexcept override { return S_OK; } + STDMETHODIMP OnDeviceAdded(LPCWSTR pwstrDeviceId) noexcept override + { + add_device(pwstrDeviceId); + return S_OK; + } + STDMETHODIMP OnDeviceRemoved(LPCWSTR pwstrDeviceId) noexcept override + { + remove_device(pwstrDeviceId); + return S_OK; + } STDMETHODIMP OnPropertyValueChanged(LPCWSTR /*pwstrDeviceId*/, const PROPERTYKEY /*key*/) noexcept override { return S_OK; } STDMETHODIMP OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDefaultDeviceId) noexcept override { @@ -383,12 +402,14 @@ struct DeviceHelper final : private IMMNotificationClient if(flow == eRender) { + DeviceListLock{gDeviceList}.setPlaybackDefaultId(pwstrDefaultDeviceId); const std::string msg{"Default playback device changed: "+ wstr_to_utf8(pwstrDefaultDeviceId)}; alc::Event(alc::EventType::DefaultDeviceChanged, alc::DeviceType::Playback, msg); } else if(flow == eCapture) { + DeviceListLock{gDeviceList}.setCaptureDefaultId(pwstrDefaultDeviceId); const std::string msg{"Default capture device changed: "+ wstr_to_utf8(pwstrDefaultDeviceId)}; alc::Event(alc::EventType::DefaultDeviceChanged, alc::DeviceType::Capture, msg); @@ -469,8 +490,9 @@ struct DeviceHelper final : private IMMNotificationClient } #endif - HRESULT probe_devices(EDataFlow flowdir, std::vector& list) + std::wstring probe_devices(EDataFlow flowdir, std::vector& list) { + std::wstring defaultId; std::vector{}.swap(list); #if !defined(ALSOFT_UWP) @@ -480,7 +502,7 @@ struct DeviceHelper final : private IMMNotificationClient if(FAILED(hr)) { ERR("Failed to enumerate audio endpoints: 0x%08lx\n", hr); - return hr; + return defaultId; } UINT count{0}; @@ -494,7 +516,7 @@ struct DeviceHelper final : private IMMNotificationClient { if(WCHAR *devid{get_device_id(device.get())}) { - add_device(device, devid, list); + defaultId = devid; CoTaskMemFree(devid); } device = nullptr; @@ -514,19 +536,19 @@ struct DeviceHelper final : private IMMNotificationClient device = nullptr; } - return S_OK; + return defaultId; #else const auto deviceRole = Windows::Media::Devices::AudioDeviceRole::Default; auto DefaultAudioId = flowdir == eRender ? MediaDevice::GetDefaultAudioRenderId(deviceRole) : MediaDevice::GetDefaultAudioCaptureId(deviceRole); Concurrency::task createDefaultOp(DeviceInformation::CreateFromIdAsync(DefaultAudioId, nullptr, DeviceInformationKind::DeviceInterface)); - auto task_status = createDefaultOp - .then([this, &list](DeviceInformation ^ deviceInfo) { - if (deviceInfo) - add_device(DeviceHandle{deviceInfo}, deviceInfo->Id->Data(), list); + auto task_status = createDefaultOp.then([&defaultId](DeviceInformation ^ deviceInfo) + { + if(deviceInfo) + defaultId = deviceInfo->Id->Data(); }).wait(); - if (task_status != Concurrency::task_group_status::completed) - return E_FAIL; + if(task_status != Concurrency::task_group_status::completed) + return; // Get the string identifier of the audio renderer auto AudioSelector = flowdir == eRender ? MediaDevice::GetAudioRenderSelector() : MediaDevice::GetAudioCaptureSelector(); @@ -534,32 +556,28 @@ struct DeviceHelper final : private IMMNotificationClient // Setup the asynchronous callback Concurrency::task enumOperation( DeviceInformation::FindAllAsync(AudioSelector, /*PropertyList*/nullptr, DeviceInformationKind::DeviceInterface)); - task_status = enumOperation - .then([this, &list](DeviceInformationCollection ^ DeviceInfoCollection) { - if (DeviceInfoCollection) + task_status = enumOperation.then([this,&list](DeviceInformationCollection ^ DeviceInfoCollection) + { + if(DeviceInfoCollection) { - try - { + try { auto deviceCount = DeviceInfoCollection->Size; - for (unsigned int i = 0; i < deviceCount; ++i) + for(unsigned int i{0};i < deviceCount;++i) { DeviceInformation ^ deviceInfo = DeviceInfoCollection->GetAt(i); - if (deviceInfo) + if(deviceInfo) add_device(DeviceHandle{deviceInfo}, deviceInfo->Id->Data(), list); } } - catch (Platform::Exception ^ e) - { + catch (Platform::Exception ^ e) { } } }).wait(); - - return task_status == Concurrency::task_group_status::completed ? S_OK : E_FAIL; #endif } using NameGUIDPair = std::pair; - static NameGUIDPair get_device_name_and_guid(const DeviceHandle& device) + static NameGUIDPair get_device_name_and_guid(const DeviceHandle &device) { #if !defined(ALSOFT_UWP) static constexpr char UnknownName[]{"Unknown Device Name"}; @@ -568,7 +586,7 @@ struct DeviceHelper final : private IMMNotificationClient ComPtr ps; HRESULT hr = device->OpenPropertyStore(STGM_READ, al::out_ptr(ps)); - if (FAILED(hr)) + if(FAILED(hr)) { WARN("OpenPropertyStore failed: 0x%08lx\n", hr); return std::make_pair(UnknownName, UnknownGuid); @@ -576,31 +594,31 @@ struct DeviceHelper final : private IMMNotificationClient PropVariant pvprop; hr = ps->GetValue(al::bit_cast(DEVPKEY_Device_FriendlyName), pvprop.get()); - if (FAILED(hr)) + if(FAILED(hr)) { WARN("GetValue Device_FriendlyName failed: 0x%08lx\n", hr); - name += UnknownName; + name = UnknownName; } - else if (pvprop->vt == VT_LPWSTR) - name += wstr_to_utf8(pvprop->pwszVal); + else if(pvprop->vt == VT_LPWSTR) + name = wstr_to_utf8(pvprop->pwszVal); else { - WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvprop->vt); - name += UnknownName; + WARN("Unexpected Device_FriendlyName PROPVARIANT type: 0x%04x\n", pvprop->vt); + name = UnknownName; } pvprop.clear(); hr = ps->GetValue(al::bit_cast(PKEY_AudioEndpoint_GUID), pvprop.get()); - if (FAILED(hr)) + if(FAILED(hr)) { WARN("GetValue AudioEndpoint_GUID failed: 0x%08lx\n", hr); guid = UnknownGuid; } - else if (pvprop->vt == VT_LPWSTR) + else if(pvprop->vt == VT_LPWSTR) guid = wstr_to_utf8(pvprop->pwszVal); else { - WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvprop->vt); + WARN("Unexpected AudioEndpoint_GUID PROPVARIANT type: 0x%04x\n", pvprop->vt); guid = UnknownGuid; } #else @@ -611,11 +629,11 @@ struct DeviceHelper final : private IMMNotificationClient Platform::String ^ devIfPath = devInfo->Id; auto wcsDevIfPath = devIfPath->Data(); auto devIdStart = wcsstr(wcsDevIfPath, L"}."); - if (devIdStart) + if(devIdStart) { devIdStart += 2; // L"}." auto devIdStartEnd = wcschr(devIdStart, L'#'); - if (devIdStartEnd) + if(devIdStartEnd) { std::wstring wDevId{devIdStart, static_cast(devIdStartEnd - devIdStart)}; guid = wstr_to_utf8(wDevId.c_str()); @@ -626,18 +644,18 @@ struct DeviceHelper final : private IMMNotificationClient return std::make_pair(std::move(name), std::move(guid)); } - static void add_device(const DeviceHandle& device, const WCHAR* devid, std::vector& list) + static void add_device(const DeviceHandle &device, const WCHAR *devid, std::vector &list) { - for (auto& entry : list) + for(auto &entry : list) { - if (entry.devid == devid) + if(entry.devid == devid) return; } auto name_guid = get_device_name_and_guid(device); int count{1}; std::string newname{name_guid.first}; - while (checkName(list, newname)) + while(checkName(list, newname)) { newname = name_guid.first; newname += " #"; @@ -651,6 +669,83 @@ struct DeviceHelper final : private IMMNotificationClient } #if !defined(ALSOFT_UWP) + void add_device(std::wstring_view devid) + { + ComPtr device; + HRESULT hr{mEnumerator->GetDevice(devid.data(), al::out_ptr(device))}; + if(FAILED(hr)) + { + ERR("Failed to get device: 0x%08lx\n", hr); + return; + } + + ComPtr endpoint; + hr = device->QueryInterface(__uuidof(IMMEndpoint), al::out_ptr(endpoint)); + if(FAILED(hr)) + { + ERR("Failed to get device endpoint: 0x%08lx\n", hr); + return; + } + + EDataFlow flowdir{}; + hr = endpoint->GetDataFlow(&flowdir); + if(FAILED(hr)) + { + ERR("Failed to get endpoint data flow: 0x%08lx\n", hr); + return; + } + + auto devlock = DeviceListLock{gDeviceList}; + auto &list = (flowdir==eRender) ? devlock.getPlaybackList() : devlock.getCaptureList(); + auto devtype = (flowdir==eRender) ? alc::DeviceType::Playback:alc::DeviceType::Capture; + + /* Ensure the ID doesn't already exist. */ + auto iter = std::find_if(list.begin(), list.end(), + [devid](const DevMap &entry) noexcept { return devid == entry.devid; }); + if(iter != list.end()) return; + + auto name_guid = get_device_name_and_guid(device); + int count{1}; + std::string newname{name_guid.first}; + while(checkName(list, newname)) + { + newname = name_guid.first; + newname += " #"; + newname += std::to_string(++count); + } + list.emplace_back(std::move(newname), std::move(name_guid.second), devid); + const DevMap &newentry = list.back(); + + TRACE("Added device \"%s\", \"%s\", \"%ls\"\n", newentry.name.c_str(), + newentry.endpoint_guid.c_str(), newentry.devid.c_str()); + + std::string msg{"Device added: "+newentry.name}; + alc::Event(alc::EventType::DeviceAdded, devtype, msg); + } + + void remove_device(std::wstring_view devid) + { + auto devlock = DeviceListLock{gDeviceList}; + for(auto flowdir : std::array{eRender, eCapture}) + { + auto &list = (flowdir==eRender) ? devlock.getPlaybackList() : devlock.getCaptureList(); + auto devtype = (flowdir==eRender)?alc::DeviceType::Playback : alc::DeviceType::Capture; + + /* Find the ID in the list to remove. */ + auto iter = std::find_if(list.begin(), list.end(), + [devid](const DevMap &entry) noexcept { return devid == entry.devid; }); + if(iter == list.end()) continue; + + TRACE("Removing device \"%s\", \"%s\", \"%ls\"\n", iter->name.c_str(), + iter->endpoint_guid.c_str(), iter->devid.c_str()); + + std::string msg{"Device removed: "+std::move(iter->name)}; + list.erase(iter); + + alc::Event(alc::EventType::DeviceRemoved, devtype, msg); + } + } + static WCHAR *get_device_id(IMMDevice* device) { WCHAR *devid; @@ -784,21 +879,17 @@ enum class MsgType { StartDevice, StopDevice, CloseDevice, - EnumeratePlayback, - EnumerateCapture, Count, QuitThread = Count }; -constexpr char MessageStr[static_cast(MsgType::Count)][20]{ +constexpr char MessageStr[static_cast(MsgType::Count)][16]{ "Open Device", "Reset Device", "Start Device", "Stop Device", "Close Device", - "Enumerate Playback", - "Enumerate Capture" }; @@ -885,6 +976,14 @@ int WasapiProxy::messageHandler(std::promise *promise) if(FAILED(hr)) goto skip_loop; + { + auto devlock = DeviceListLock{gDeviceList}; + auto defaultId = sDeviceHelper->probe_devices(eRender, devlock.getPlaybackList()); + if(!defaultId.empty()) devlock.setPlaybackDefaultId(defaultId); + defaultId = sDeviceHelper->probe_devices(eCapture, devlock.getCaptureList()); + if(!defaultId.empty()) devlock.setCaptureDefaultId(defaultId); + } + TRACE("Starting message loop\n"); while(Msg msg{popMessage()}) { @@ -919,18 +1018,6 @@ int WasapiProxy::messageHandler(std::promise *promise) msg.mPromise.set_value(S_OK); continue; - case MsgType::EnumeratePlayback: - case MsgType::EnumerateCapture: - if(msg.mType == MsgType::EnumeratePlayback) - msg.mPromise.set_value(sDeviceHelper->probe_devices(eRender, - DeviceListLock{gDeviceList}.getPlaybackList())); - else if(msg.mType == MsgType::EnumerateCapture) - msg.mPromise.set_value(sDeviceHelper->probe_devices(eCapture, - DeviceListLock{gDeviceList}.getCaptureList())); - else - msg.mPromise.set_value(E_FAIL); - continue; - case MsgType::QuitThread: break; } @@ -1103,16 +1190,11 @@ void WasapiPlayback::open(const char *name) "Failed to create notify events"}; } - if(name) + if(name && std::strncmp(name, DevNameHead, DevNameHeadLen) == 0) { - if(DeviceListLock{gDeviceList}.getPlaybackList().empty()) - pushMessage(MsgType::EnumeratePlayback); - if(std::strncmp(name, DevNameHead, DevNameHeadLen) == 0) - { - name += DevNameHeadLen; - if(*name == '\0') - name = nullptr; - } + name += DevNameHeadLen; + if(*name == '\0') + name = nullptr; } mOpenStatus = pushMessage(MsgType::OpenDevice, name).get(); @@ -1748,16 +1830,11 @@ void WasapiCapture::open(const char *name) "Failed to create notify events"}; } - if(name) + if(name && std::strncmp(name, DevNameHead, DevNameHeadLen) == 0) { - if(DeviceListLock{gDeviceList}.getCaptureList().empty()) - pushMessage(MsgType::EnumerateCapture); - if(std::strncmp(name, DevNameHead, DevNameHeadLen) == 0) - { - name += DevNameHeadLen; - if(*name == '\0') - name = nullptr; - } + name += DevNameHeadLen; + if(*name == '\0') + name = nullptr; } mOpenStatus = pushMessage(MsgType::OpenDevice, name).get(); @@ -2198,28 +2275,42 @@ std::string WasapiBackendFactory::probe(BackendType type) { std::string outnames; + auto devlock = DeviceListLock{gDeviceList}; switch(type) { case BackendType::Playback: - WasapiProxy::pushMessageStatic(MsgType::EnumeratePlayback).wait(); { - auto devlock = DeviceListLock{gDeviceList}; + auto defaultId = devlock.getPlaybackDefaultId(); for(const DevMap &entry : devlock.getPlaybackList()) { - /* +1 to also append the null char (to ensure a null-separated - * list and double-null terminated list). - */ - outnames.append(DevNameHead).append(entry.name.c_str(), entry.name.length()+1); + if(entry.devid != defaultId) + { + /* +1 to also append the null char (to ensure a null- + * separated list and double-null terminated list). + */ + outnames.append(DevNameHead).append(entry.name.c_str(), entry.name.length()+1); + continue; + } + /* Default device goes first. */ + std::string name{DevNameHead + entry.name}; + outnames.insert(0, name.c_str(), name.length()+1); } } break; case BackendType::Capture: - WasapiProxy::pushMessageStatic(MsgType::EnumerateCapture).wait(); { - auto devlock = DeviceListLock{gDeviceList}; + auto defaultId = devlock.getCaptureDefaultId(); for(const DevMap &entry : devlock.getCaptureList()) - outnames.append(DevNameHead).append(entry.name.c_str(), entry.name.length()+1); + { + if(entry.devid != defaultId) + { + outnames.append(DevNameHead).append(entry.name.c_str(), entry.name.length()+1); + continue; + } + std::string name{DevNameHead + entry.name}; + outnames.insert(0, name.c_str(), name.length()+1); + } } break; } -- cgit v1.2.3 From 399853fa3456fa1cf21426f0a2f8f39390124c64 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 5 Jun 2023 08:16:48 -0700 Subject: Fix return value for UWP builds --- alc/backends/wasapi.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index c0c33ffa..653c9098 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -535,8 +535,6 @@ struct DeviceHelper final : private IMMNotificationClient } device = nullptr; } - - return defaultId; #else const auto deviceRole = Windows::Media::Devices::AudioDeviceRole::Default; auto DefaultAudioId = flowdir == eRender ? MediaDevice::GetDefaultAudioRenderId(deviceRole) @@ -548,7 +546,7 @@ struct DeviceHelper final : private IMMNotificationClient defaultId = deviceInfo->Id->Data(); }).wait(); if(task_status != Concurrency::task_group_status::completed) - return; + return defaultId; // Get the string identifier of the audio renderer auto AudioSelector = flowdir == eRender ? MediaDevice::GetAudioRenderSelector() : MediaDevice::GetAudioCaptureSelector(); @@ -574,6 +572,8 @@ struct DeviceHelper final : private IMMNotificationClient } }).wait(); #endif + + return defaultId; } using NameGUIDPair = std::pair; -- cgit v1.2.3 From 5c143f8faa791cf563b2e7d11139c0f41bcb6cbc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 5 Jun 2023 19:42:34 -0700 Subject: Avoid explicit definitions of some IIDs --- alc/backends/wasapi.cpp | 6 +++--- core/uiddefs.cpp | 4 ---- 2 files changed, 3 insertions(+), 7 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 653c9098..b07cb62a 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -423,7 +423,7 @@ struct DeviceHelper final : private IMMNotificationClient { #if !defined(ALSOFT_UWP) HRESULT hr{CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, - IID_IMMDeviceEnumerator, al::out_ptr(mEnumerator))}; + __uuidof(IMMDeviceEnumerator), al::out_ptr(mEnumerator))}; if(SUCCEEDED(hr)) mEnumerator->RegisterEndpointNotificationCallback(this); else @@ -1621,7 +1621,7 @@ HRESULT WasapiPlayback::startProxy() return hr; } - hr = mClient->GetService(IID_IAudioRenderClient, al::out_ptr(mRender)); + hr = mClient->GetService(__uuidof(IAudioRenderClient), al::out_ptr(mRender)); if(SUCCEEDED(hr)) { try { @@ -2201,7 +2201,7 @@ HRESULT WasapiCapture::startProxy() return hr; } - hr = mClient->GetService(IID_IAudioCaptureClient, al::out_ptr(mCapture)); + hr = mClient->GetService(__uuidof(IAudioCaptureClient), al::out_ptr(mCapture)); if(SUCCEEDED(hr)) { try { diff --git a/core/uiddefs.cpp b/core/uiddefs.cpp index 833150f5..9471bba5 100644 --- a/core/uiddefs.cpp +++ b/core/uiddefs.cpp @@ -19,10 +19,6 @@ DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80,0x DEFINE_GUID(IID_IDirectSoundNotify, 0xb0210783, 0x89cd, 0x11d0, 0xaf,0x08, 0x00,0xa0,0xc9,0x25,0xcd,0x16); DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xbcde0395, 0xe52f, 0x467c, 0x8e,0x3d, 0xc4,0x57,0x92,0x91,0x69,0x2e); -DEFINE_GUID(IID_IMMDeviceEnumerator, 0xa95664d2, 0x9614, 0x4f35, 0xa7,0x46, 0xde,0x8d,0xb6,0x36,0x17,0xe6); -DEFINE_GUID(IID_IAudioClient, 0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1,0x78, 0xc2,0xf5,0x68,0xa7,0x03,0xb2); -DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7,0xbf, 0xad,0xdc,0xa7,0xc2,0x60,0xe2); -DEFINE_GUID(IID_IAudioCaptureClient, 0xc8adbd64, 0xe71e, 0x48a0, 0xa4,0xde, 0x18,0x5c,0x39,0x5c,0xd3,0x17); #if defined(HAVE_WASAPI) && !defined(ALSOFT_UWP) #include -- cgit v1.2.3 From 79bdc1c0a25289c21746283cab56d149b266c7ad Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 6 Jun 2023 02:44:42 -0700 Subject: Directly inline a couple functions --- alc/backends/wasapi.cpp | 363 +++++++++++++++++++++++------------------------- 1 file changed, 174 insertions(+), 189 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index b07cb62a..40255dc9 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -251,6 +251,99 @@ using EventRegistrationToken = Windows::Foundation::EventRegistrationToken; using DeviceHandle = ComPtr; #endif + +using NameGUIDPair = std::pair; +static NameGUIDPair GetDeviceNameAndGuid(const DeviceHandle &device) +{ + static constexpr char UnknownName[]{"Unknown Device Name"}; + static constexpr char UnknownGuid[]{"Unknown Device GUID"}; +#if !defined(ALSOFT_UWP) + std::string name, guid; + + ComPtr ps; + HRESULT hr = device->OpenPropertyStore(STGM_READ, al::out_ptr(ps)); + if(FAILED(hr)) + { + WARN("OpenPropertyStore failed: 0x%08lx\n", hr); + return std::make_pair(UnknownName, UnknownGuid); + } + + PropVariant pvprop; + hr = ps->GetValue(al::bit_cast(DEVPKEY_Device_FriendlyName), pvprop.get()); + if(FAILED(hr)) + { + WARN("GetValue Device_FriendlyName failed: 0x%08lx\n", hr); + name = UnknownName; + } + else if(pvprop->vt == VT_LPWSTR) + name = wstr_to_utf8(pvprop->pwszVal); + else + { + WARN("Unexpected Device_FriendlyName PROPVARIANT type: 0x%04x\n", pvprop->vt); + name = UnknownName; + } + + pvprop.clear(); + hr = ps->GetValue(al::bit_cast(PKEY_AudioEndpoint_GUID), pvprop.get()); + if(FAILED(hr)) + { + WARN("GetValue AudioEndpoint_GUID failed: 0x%08lx\n", hr); + guid = UnknownGuid; + } + else if(pvprop->vt == VT_LPWSTR) + guid = wstr_to_utf8(pvprop->pwszVal); + else + { + WARN("Unexpected AudioEndpoint_GUID PROPVARIANT type: 0x%04x\n", pvprop->vt); + guid = UnknownGuid; + } +#else + auto devInfo = device.value; + std::string name{wstr_to_utf8(devInfo->Name->Data())}; + std::string guid; + // devInfo->Id is DeviceInterfacePath: \\?\SWD#MMDEVAPI#{0.0.0.00000000}.{a21c17a0-fc1d-405e-ab5a-b513422b57d1}#{e6327cad-dcec-4949-ae8a-991e976a79d2} + Platform::String ^ devIfPath = devInfo->Id; + if(auto devIdStart = wcsstr(devIfPath->Data(), L"}.")) + { + devIdStart += 2; // L"}." + if(auto devIdStartEnd = wcschr(devIdStart, L'#')) + { + std::wstring wDevId{devIdStart, static_cast(devIdStartEnd - devIdStart)}; + guid = wstr_to_utf8(wDevId.c_str()); + std::transform(guid.begin(), guid.end(), guid.begin(), + [](char ch) { return static_cast(std::toupper(ch)); }); + } + } + if(name.empty()) name = UnknownName; + if(guid.empty()) guid = UnknownGuid; +#endif + return std::make_pair(std::move(name), std::move(guid)); +} +#if !defined(ALSOFT_UWP) +EndpointFormFactor GetDeviceFormfactor(IMMDevice *device) +{ + ComPtr ps; + HRESULT hr{device->OpenPropertyStore(STGM_READ, al::out_ptr(ps))}; + if(FAILED(hr)) + { + WARN("OpenPropertyStore failed: 0x%08lx\n", hr); + return UnknownFormFactor; + } + + EndpointFormFactor formfactor{UnknownFormFactor}; + PropVariant pvform; + hr = ps->GetValue(PKEY_AudioEndpoint_FormFactor, pvform.get()); + if(FAILED(hr)) + WARN("GetValue AudioEndpoint_FormFactor failed: 0x%08lx\n", hr); + else if(pvform->vt == VT_UI4) + formfactor = static_cast(pvform->ulVal); + else if(pvform->vt != VT_EMPTY) + WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvform->vt); + return formfactor; +} +#endif + + #if defined(ALSOFT_UWP) struct DeviceHelper final : public IActivateAudioInterfaceCompletionHandler #else @@ -384,17 +477,74 @@ struct DeviceHelper final : private IMMNotificationClient #else /** ----------------------- IMMNotificationClient ------------ */ STDMETHODIMP OnDeviceStateChanged(LPCWSTR /*pwstrDeviceId*/, DWORD /*dwNewState*/) noexcept override { return S_OK; } + STDMETHODIMP OnDeviceAdded(LPCWSTR pwstrDeviceId) noexcept override { - add_device(pwstrDeviceId); + ComPtr device; + HRESULT hr{mEnumerator->GetDevice(pwstrDeviceId, al::out_ptr(device))}; + if(FAILED(hr)) + { + ERR("Failed to get device: 0x%08lx\n", hr); + return S_OK; + } + + ComPtr endpoint; + hr = device->QueryInterface(__uuidof(IMMEndpoint), al::out_ptr(endpoint)); + if(FAILED(hr)) + { + ERR("Failed to get device endpoint: 0x%08lx\n", hr); + return S_OK; + } + + EDataFlow flowdir{}; + hr = endpoint->GetDataFlow(&flowdir); + if(FAILED(hr)) + { + ERR("Failed to get endpoint data flow: 0x%08lx\n", hr); + return S_OK; + } + + auto devlock = DeviceListLock{gDeviceList}; + auto &list = (flowdir==eRender) ? devlock.getPlaybackList() : devlock.getCaptureList(); + + if(AddDevice(device, pwstrDeviceId, list)) + { + const auto devtype = (flowdir==eRender) ? alc::DeviceType::Playback + : alc::DeviceType::Capture; + const std::string msg{"Device added: "+list.back().name}; + alc::Event(alc::EventType::DeviceAdded, devtype, msg); + } + return S_OK; } + STDMETHODIMP OnDeviceRemoved(LPCWSTR pwstrDeviceId) noexcept override { - remove_device(pwstrDeviceId); + auto devlock = DeviceListLock{gDeviceList}; + for(auto flowdir : std::array{eRender, eCapture}) + { + auto &list = (flowdir==eRender) ? devlock.getPlaybackList() : devlock.getCaptureList(); + auto devtype = (flowdir==eRender)?alc::DeviceType::Playback : alc::DeviceType::Capture; + + /* Find the ID in the list to remove. */ + auto iter = std::find_if(list.begin(), list.end(), + [pwstrDeviceId](const DevMap &entry) noexcept + { return pwstrDeviceId == entry.devid; }); + if(iter == list.end()) continue; + + TRACE("Removing device \"%s\", \"%s\", \"%ls\"\n", iter->name.c_str(), + iter->endpoint_guid.c_str(), iter->devid.c_str()); + + std::string msg{"Device removed: "+std::move(iter->name)}; + list.erase(iter); + + alc::Event(alc::EventType::DeviceRemoved, devtype, msg); + } return S_OK; } + STDMETHODIMP OnPropertyValueChanged(LPCWSTR /*pwstrDeviceId*/, const PROPERTYKEY /*key*/) noexcept override { return S_OK; } + STDMETHODIMP OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDefaultDeviceId) noexcept override { if(role != eMultimedia) @@ -437,7 +587,7 @@ struct DeviceHelper final : private IMMNotificationClient HRESULT openDevice(std::wstring_view devid, EDataFlow flow, DeviceHandle& device) { #if !defined(ALSOFT_UWP) - HRESULT hr{E_POINTER}; + HRESULT hr{E_FAIL}; if(mEnumerator) { if(devid.empty()) @@ -490,7 +640,7 @@ struct DeviceHelper final : private IMMNotificationClient } #endif - std::wstring probe_devices(EDataFlow flowdir, std::vector& list) + std::wstring probeDevices(EDataFlow flowdir, std::vector &list) { std::wstring defaultId; std::vector{}.swap(list); @@ -514,7 +664,7 @@ struct DeviceHelper final : private IMMNotificationClient hr = mEnumerator->GetDefaultAudioEndpoint(flowdir, eMultimedia, al::out_ptr(device)); if(SUCCEEDED(hr)) { - if(WCHAR *devid{get_device_id(device.get())}) + if(WCHAR *devid{GetDeviceId(device.get())}) { defaultId = devid; CoTaskMemFree(devid); @@ -528,9 +678,9 @@ struct DeviceHelper final : private IMMNotificationClient if(FAILED(hr)) continue; - if(WCHAR *devid{get_device_id(device.get())}) + if(WCHAR *devid{GetDeviceId(device.get())}) { - add_device(device, devid, list); + std::ignore = AddDevice(device, devid, list); CoTaskMemFree(devid); } device = nullptr; @@ -564,7 +714,8 @@ struct DeviceHelper final : private IMMNotificationClient { DeviceInformation ^ deviceInfo = DeviceInfoCollection->GetAt(i); if(deviceInfo) - add_device(DeviceHandle{deviceInfo}, deviceInfo->Id->Data(), list); + std::ignore = AddDevice(DeviceHandle{deviceInfo}, + deviceInfo->Id->Data(), list); } } catch (Platform::Exception ^ e) { @@ -576,135 +727,16 @@ struct DeviceHelper final : private IMMNotificationClient return defaultId; } - using NameGUIDPair = std::pair; - static NameGUIDPair get_device_name_and_guid(const DeviceHandle &device) - { -#if !defined(ALSOFT_UWP) - static constexpr char UnknownName[]{"Unknown Device Name"}; - static constexpr char UnknownGuid[]{"Unknown Device GUID"}; - std::string name, guid; - - ComPtr ps; - HRESULT hr = device->OpenPropertyStore(STGM_READ, al::out_ptr(ps)); - if(FAILED(hr)) - { - WARN("OpenPropertyStore failed: 0x%08lx\n", hr); - return std::make_pair(UnknownName, UnknownGuid); - } - - PropVariant pvprop; - hr = ps->GetValue(al::bit_cast(DEVPKEY_Device_FriendlyName), pvprop.get()); - if(FAILED(hr)) - { - WARN("GetValue Device_FriendlyName failed: 0x%08lx\n", hr); - name = UnknownName; - } - else if(pvprop->vt == VT_LPWSTR) - name = wstr_to_utf8(pvprop->pwszVal); - else - { - WARN("Unexpected Device_FriendlyName PROPVARIANT type: 0x%04x\n", pvprop->vt); - name = UnknownName; - } - - pvprop.clear(); - hr = ps->GetValue(al::bit_cast(PKEY_AudioEndpoint_GUID), pvprop.get()); - if(FAILED(hr)) - { - WARN("GetValue AudioEndpoint_GUID failed: 0x%08lx\n", hr); - guid = UnknownGuid; - } - else if(pvprop->vt == VT_LPWSTR) - guid = wstr_to_utf8(pvprop->pwszVal); - else - { - WARN("Unexpected AudioEndpoint_GUID PROPVARIANT type: 0x%04x\n", pvprop->vt); - guid = UnknownGuid; - } -#else - auto devInfo = device.value; - std::string name = wstr_to_utf8(devInfo->Name->Data()); - std::string guid; - // devInfo->Id is DeviceInterfacePath: \\?\SWD#MMDEVAPI#{0.0.0.00000000}.{a21c17a0-fc1d-405e-ab5a-b513422b57d1}#{e6327cad-dcec-4949-ae8a-991e976a79d2} - Platform::String ^ devIfPath = devInfo->Id; - auto wcsDevIfPath = devIfPath->Data(); - auto devIdStart = wcsstr(wcsDevIfPath, L"}."); - if(devIdStart) - { - devIdStart += 2; // L"}." - auto devIdStartEnd = wcschr(devIdStart, L'#'); - if(devIdStartEnd) - { - std::wstring wDevId{devIdStart, static_cast(devIdStartEnd - devIdStart)}; - guid = wstr_to_utf8(wDevId.c_str()); - std::transform(guid.begin(), guid.end(), guid.begin(), [](char ch) { return static_cast(std::toupper(ch)); }); - } - } -#endif - return std::make_pair(std::move(name), std::move(guid)); - } - - static void add_device(const DeviceHandle &device, const WCHAR *devid, std::vector &list) +private: + static bool AddDevice(const DeviceHandle &device, const WCHAR *devid, std::vector &list) { for(auto &entry : list) { if(entry.devid == devid) - return; - } - - auto name_guid = get_device_name_and_guid(device); - int count{1}; - std::string newname{name_guid.first}; - while(checkName(list, newname)) - { - newname = name_guid.first; - newname += " #"; - newname += std::to_string(++count); - } - list.emplace_back(std::move(newname), std::move(name_guid.second), devid); - const DevMap& newentry = list.back(); - - TRACE("Got device \"%s\", \"%s\", \"%ls\"\n", newentry.name.c_str(), newentry.endpoint_guid.c_str(), - newentry.devid.c_str()); - } - -#if !defined(ALSOFT_UWP) - void add_device(std::wstring_view devid) - { - ComPtr device; - HRESULT hr{mEnumerator->GetDevice(devid.data(), al::out_ptr(device))}; - if(FAILED(hr)) - { - ERR("Failed to get device: 0x%08lx\n", hr); - return; - } - - ComPtr endpoint; - hr = device->QueryInterface(__uuidof(IMMEndpoint), al::out_ptr(endpoint)); - if(FAILED(hr)) - { - ERR("Failed to get device endpoint: 0x%08lx\n", hr); - return; - } - - EDataFlow flowdir{}; - hr = endpoint->GetDataFlow(&flowdir); - if(FAILED(hr)) - { - ERR("Failed to get endpoint data flow: 0x%08lx\n", hr); - return; + return false; } - auto devlock = DeviceListLock{gDeviceList}; - auto &list = (flowdir==eRender) ? devlock.getPlaybackList() : devlock.getCaptureList(); - auto devtype = (flowdir==eRender) ? alc::DeviceType::Playback:alc::DeviceType::Capture; - - /* Ensure the ID doesn't already exist. */ - auto iter = std::find_if(list.begin(), list.end(), - [devid](const DevMap &entry) noexcept { return devid == entry.devid; }); - if(iter != list.end()) return; - - auto name_guid = get_device_name_and_guid(device); + auto name_guid = GetDeviceNameAndGuid(device); int count{1}; std::string newname{name_guid.first}; while(checkName(list, newname)) @@ -716,37 +748,13 @@ struct DeviceHelper final : private IMMNotificationClient list.emplace_back(std::move(newname), std::move(name_guid.second), devid); const DevMap &newentry = list.back(); - TRACE("Added device \"%s\", \"%s\", \"%ls\"\n", newentry.name.c_str(), + TRACE("Got device \"%s\", \"%s\", \"%ls\"\n", newentry.name.c_str(), newentry.endpoint_guid.c_str(), newentry.devid.c_str()); - - std::string msg{"Device added: "+newentry.name}; - alc::Event(alc::EventType::DeviceAdded, devtype, msg); - } - - void remove_device(std::wstring_view devid) - { - auto devlock = DeviceListLock{gDeviceList}; - for(auto flowdir : std::array{eRender, eCapture}) - { - auto &list = (flowdir==eRender) ? devlock.getPlaybackList() : devlock.getCaptureList(); - auto devtype = (flowdir==eRender)?alc::DeviceType::Playback : alc::DeviceType::Capture; - - /* Find the ID in the list to remove. */ - auto iter = std::find_if(list.begin(), list.end(), - [devid](const DevMap &entry) noexcept { return devid == entry.devid; }); - if(iter == list.end()) continue; - - TRACE("Removing device \"%s\", \"%s\", \"%ls\"\n", iter->name.c_str(), - iter->endpoint_guid.c_str(), iter->devid.c_str()); - - std::string msg{"Device removed: "+std::move(iter->name)}; - list.erase(iter); - - alc::Event(alc::EventType::DeviceRemoved, devtype, msg); - } + return true; } - static WCHAR *get_device_id(IMMDevice* device) +#if !defined(ALSOFT_UWP) + static WCHAR *GetDeviceId(IMMDevice *device) { WCHAR *devid; @@ -759,38 +767,15 @@ struct DeviceHelper final : private IMMNotificationClient return devid; } - static EndpointFormFactor get_device_formfactor(IMMDevice* device) - { - ComPtr ps; - HRESULT hr{device->OpenPropertyStore(STGM_READ, al::out_ptr(ps))}; - if(FAILED(hr)) - { - WARN("OpenPropertyStore failed: 0x%08lx\n", hr); - return UnknownFormFactor; - } + ComPtr mEnumerator{nullptr}; - EndpointFormFactor formfactor{UnknownFormFactor}; - PropVariant pvform; - hr = ps->GetValue(PKEY_AudioEndpoint_FormFactor, pvform.get()); - if(FAILED(hr)) - WARN("GetValue AudioEndpoint_FormFactor failed: 0x%08lx\n", hr); - else if(pvform->vt == VT_UI4) - formfactor = static_cast(pvform->ulVal); - else if(pvform->vt != VT_EMPTY) - WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvform->vt); - return formfactor; - } -#endif +#else -private: -#if defined(ALSOFT_UWP) HANDLE mActiveClientEvent{nullptr}; void** mPPV{nullptr}; EventRegistrationToken mRenderDeviceChangedToken; EventRegistrationToken mCaptureDeviceChangedToken; -#else - ComPtr mEnumerator{nullptr}; #endif }; @@ -978,9 +963,9 @@ int WasapiProxy::messageHandler(std::promise *promise) { auto devlock = DeviceListLock{gDeviceList}; - auto defaultId = sDeviceHelper->probe_devices(eRender, devlock.getPlaybackList()); + auto defaultId = sDeviceHelper->probeDevices(eRender, devlock.getPlaybackList()); if(!defaultId.empty()) devlock.setPlaybackDefaultId(defaultId); - defaultId = sDeviceHelper->probe_devices(eCapture, devlock.getCaptureList()); + defaultId = sDeviceHelper->probeDevices(eCapture, devlock.getCaptureList()); if(!defaultId.empty()) devlock.setCaptureDefaultId(defaultId); } @@ -1240,7 +1225,7 @@ HRESULT WasapiPlayback::openProxy(const char *name) if(!devname.empty()) mDevice->DeviceName = DevNameHead + std::move(devname); else - mDevice->DeviceName = DevNameHead + DeviceHelper::get_device_name_and_guid(mMMDev).first; + mDevice->DeviceName = DevNameHead + GetDeviceNameAndGuid(mMMDev).first; return S_OK; } @@ -1536,7 +1521,7 @@ HRESULT WasapiPlayback::resetProxy() mFormat = OutputType; #if !defined(ALSOFT_UWP) - const EndpointFormFactor formfactor{DeviceHelper::get_device_formfactor(mMMDev.get())}; + const EndpointFormFactor formfactor{GetDeviceFormfactor(mMMDev.get())}; mDevice->Flags.set(DirectEar, (formfactor == Headphones || formfactor == Headset)); #else mDevice->Flags.set(DirectEar, false); @@ -1888,7 +1873,7 @@ HRESULT WasapiCapture::openProxy(const char *name) if(!devname.empty()) mDevice->DeviceName = DevNameHead + std::move(devname); else - mDevice->DeviceName = DevNameHead + DeviceHelper::get_device_name_and_guid(mMMDev).first; + mDevice->DeviceName = DevNameHead + GetDeviceNameAndGuid(mMMDev).first; return S_OK; } -- cgit v1.2.3 From 642baebaa2920c92b750246c599f1d381d3f284b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 6 Jun 2023 02:56:06 -0700 Subject: Remove a seemingly unnecessary C++/CLI wrapper --- alc/backends/wasapi.cpp | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 40255dc9..816a2ae1 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -238,17 +238,10 @@ enum EDataFlow { #endif #if defined(ALSOFT_UWP) -struct DeviceHandle { - DeviceHandle& operator=(std::nullptr_t) - { - value = nullptr; - return *this; - } - DeviceInformation^ value{nullptr}; -}; +using DeviceHandle = DeviceInformation^; using EventRegistrationToken = Windows::Foundation::EventRegistrationToken; #else -using DeviceHandle = ComPtr; +using DeviceHandle = ComPtr; #endif @@ -298,11 +291,10 @@ static NameGUIDPair GetDeviceNameAndGuid(const DeviceHandle &device) guid = UnknownGuid; } #else - auto devInfo = device.value; - std::string name{wstr_to_utf8(devInfo->Name->Data())}; + std::string name{wstr_to_utf8(device->Name->Data())}; std::string guid; - // devInfo->Id is DeviceInterfacePath: \\?\SWD#MMDEVAPI#{0.0.0.00000000}.{a21c17a0-fc1d-405e-ab5a-b513422b57d1}#{e6327cad-dcec-4949-ae8a-991e976a79d2} - Platform::String ^ devIfPath = devInfo->Id; + // device->Id is DeviceInterfacePath: \\?\SWD#MMDEVAPI#{0.0.0.00000000}.{a21c17a0-fc1d-405e-ab5a-b513422b57d1}#{e6327cad-dcec-4949-ae8a-991e976a79d2} + Platform::String^ devIfPath = device->Id; if(auto devIdStart = wcsstr(devIfPath->Data(), L"}.")) { devIdStart += 2; // L"}." @@ -606,7 +598,7 @@ struct DeviceHelper final : private IMMNotificationClient DeviceInformation::CreateFromIdAsync(devIfPath, nullptr, DeviceInformationKind::DeviceInterface)); auto status = createDeviceOp.then([&](DeviceInformation^ deviceInfo) { - device.value = deviceInfo; + device = deviceInfo; }).wait(); if(status != Concurrency::task_status::completed) { @@ -624,7 +616,7 @@ struct DeviceHelper final : private IMMNotificationClient { ComPtr asyncOp; mPPV = ppv; - HRESULT hr{ActivateAudioInterfaceAsync(device.value->Id->Data(), iid, nullptr, this, + HRESULT hr{ActivateAudioInterfaceAsync(device->Id->Data(), iid, nullptr, this, al::out_ptr(asyncOp))}; if(FAILED(hr)) return hr; @@ -712,10 +704,9 @@ struct DeviceHelper final : private IMMNotificationClient auto deviceCount = DeviceInfoCollection->Size; for(unsigned int i{0};i < deviceCount;++i) { - DeviceInformation ^ deviceInfo = DeviceInfoCollection->GetAt(i); + DeviceInformation^ deviceInfo = DeviceInfoCollection->GetAt(i); if(deviceInfo) - std::ignore = AddDevice(DeviceHandle{deviceInfo}, - deviceInfo->Id->Data(), list); + std::ignore = AddDevice(deviceInfo, deviceInfo->Id->Data(), list); } } catch (Platform::Exception ^ e) { -- cgit v1.2.3 From 3d9900476ec49b2994b7163a451a69560d498306 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 7 Jun 2023 01:44:02 -0700 Subject: Get the correct audio client interface with UWP --- alc/backends/wasapi.cpp | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 816a2ae1..b68a59e2 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -443,24 +443,8 @@ struct DeviceHelper final : private IMMNotificationClient #if defined(ALSOFT_UWP) /** ----------------------- IActivateAudioInterfaceCompletionHandler ------------ */ - HRESULT ActivateCompleted(IActivateAudioInterfaceAsyncOperation* operation) override + HRESULT ActivateCompleted(IActivateAudioInterfaceAsyncOperation*) override { - HRESULT hrActivateResult = S_OK; - IUnknown* punkAudioInterface = nullptr; - - HRESULT hr = operation->GetActivateResult(&hrActivateResult, &punkAudioInterface); - // Check for a successful activation result - if (SUCCEEDED(hr) && SUCCEEDED(hrActivateResult)) - { - if (mPPV) - { - // Get the pointer for the Audio Client - IAudioClient3* audioClient; - punkAudioInterface->QueryInterface(IID_PPV_ARGS(&audioClient)); - *mPPV = audioClient; - } - } - SetEvent(mActiveClientEvent); // Need to return S_OK @@ -609,26 +593,35 @@ struct DeviceHelper final : private IMMNotificationClient } #if !defined(ALSOFT_UWP) - static HRESULT activateAudioClient(_In_ DeviceHandle& device, REFIID iid, void **ppv) + static HRESULT activateAudioClient(_In_ DeviceHandle &device, REFIID iid, void **ppv) { return device->Activate(iid, CLSCTX_INPROC_SERVER, nullptr, ppv); } #else - HRESULT activateAudioClient(_In_ DeviceHandle& device, _In_ REFIID iid, void **ppv) + HRESULT activateAudioClient(_In_ DeviceHandle &device, _In_ REFIID iid, void **ppv) { ComPtr asyncOp; - mPPV = ppv; HRESULT hr{ActivateAudioInterfaceAsync(device->Id->Data(), iid, nullptr, this, al::out_ptr(asyncOp))}; if(FAILED(hr)) return hr; - asyncOp = nullptr; - DWORD res{WaitForSingleObjectEx(mActiveClientEvent, 2000, FALSE)}; + /* I don't like waiting for INFINITE time, but the activate operation + * can take an indefinite amount of time since it can require user + * input. + */ + DWORD res{WaitForSingleObjectEx(mActiveClientEvent, INFINITE, FALSE)}; if(res != WAIT_OBJECT_0) { ERR("WaitForSingleObjectEx error: 0x%lx\n", res); return E_FAIL; } - return S_OK; + + HRESULT hrActivateRes{E_FAIL}; + ComPtr punkAudioIface; + hr = asyncOp->GetActivateResult(&hrActivateRes, al::out_ptr(punkAudioIface)); + if(SUCCEEDED(hr)) hr = hrActivateRes; + if(FAILED(hr)) return hr; + + return punkAudioIface->QueryInterface(iid, ppv); } #endif @@ -763,7 +756,6 @@ private: #else HANDLE mActiveClientEvent{nullptr}; - void** mPPV{nullptr}; EventRegistrationToken mRenderDeviceChangedToken; EventRegistrationToken mCaptureDeviceChangedToken; -- cgit v1.2.3 From 2da9d168b6bee32376889a394e11981a4515d041 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 27 Jun 2023 05:53:35 -0700 Subject: Set the correct dev format when autodetecting 7.1.4 in WASAPI --- alc/backends/wasapi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index b68a59e2..c5282fcb 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -1272,7 +1272,7 @@ HRESULT WasapiPlayback::resetProxy() const uint32_t chancount{OutputType.Format.nChannels}; const DWORD chanmask{OutputType.dwChannelMask}; if(chancount >= 12 && (chanmask&X714Mask) == X7DOT1DOT4) - mDevice->FmtChans = DevFmtX71; + mDevice->FmtChans = DevFmtX714; else if(chancount >= 8 && (chanmask&X71Mask) == X7DOT1) mDevice->FmtChans = DevFmtX71; else if(chancount >= 7 && (chanmask&X61Mask) == X6DOT1) -- cgit v1.2.3 From e714c8fbca7bc4a03be308d43d6d6cd5e57914bc Mon Sep 17 00:00:00 2001 From: "Deal(一线灵)" Date: Wed, 28 Jun 2023 16:10:49 +0800 Subject: [UWP] Fix crash when probe capture device fail (#868) * [UWP] Fix crash when probe capture device fail * [UWP] Also check openDevice to avoid crash --- alc/backends/wasapi.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index c5282fcb..dccbeba2 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -577,7 +577,8 @@ struct DeviceHelper final : private IMMNotificationClient Platform::String^ devIfPath = devid.empty() ? (flow == eRender ? MediaDevice::GetDefaultAudioRenderId(deviceRole) : MediaDevice::GetDefaultAudioCaptureId(deviceRole)) : ref new Platform::String(devid.data()); - + if (!devIfPath) + return E_POINTER; Concurrency::task createDeviceOp( DeviceInformation::CreateFromIdAsync(devIfPath, nullptr, DeviceInformationKind::DeviceInterface)); auto status = createDeviceOp.then([&](DeviceInformation^ deviceInfo) @@ -674,6 +675,8 @@ struct DeviceHelper final : private IMMNotificationClient const auto deviceRole = Windows::Media::Devices::AudioDeviceRole::Default; auto DefaultAudioId = flowdir == eRender ? MediaDevice::GetDefaultAudioRenderId(deviceRole) : MediaDevice::GetDefaultAudioCaptureId(deviceRole); + if (!DefaultAudioId) + return defaultId; Concurrency::task createDefaultOp(DeviceInformation::CreateFromIdAsync(DefaultAudioId, nullptr, DeviceInformationKind::DeviceInterface)); auto task_status = createDefaultOp.then([&defaultId](DeviceInformation ^ deviceInfo) { -- cgit v1.2.3 From 0cad3f7391959d1ad83f948df37db608e3f0e72c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 29 Jun 2023 02:37:08 -0700 Subject: Specify a callback using a lambda --- alc/backends/sdl2.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/sdl2.cpp b/alc/backends/sdl2.cpp index a4a5a9ac..e1e40e27 100644 --- a/alc/backends/sdl2.cpp +++ b/alc/backends/sdl2.cpp @@ -53,8 +53,6 @@ struct Sdl2Backend final : public BackendBase { ~Sdl2Backend() override; void audioCallback(Uint8 *stream, int len) noexcept; - static void audioCallbackC(void *ptr, Uint8 *stream, int len) noexcept - { static_cast(ptr)->audioCallback(stream, len); } void open(const char *name) override; bool reset() override; @@ -103,7 +101,8 @@ void Sdl2Backend::open(const char *name) } want.channels = (mDevice->FmtChans == DevFmtMono) ? 1 : 2; want.samples = static_cast(minu(mDevice->UpdateSize, 8192)); - want.callback = &Sdl2Backend::audioCallbackC; + want.callback = [](void *ptr, Uint8 *stream, int len) noexcept + { return static_cast(ptr)->audioCallback(stream, len); }; want.userdata = this; /* Passing nullptr to SDL_OpenAudioDevice opens a default, which isn't -- cgit v1.2.3 From 830a8d7e13be369ecc61d6938da3ee8a47c461a3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 4 Jul 2023 11:31:33 -0700 Subject: Fix a comment typo --- alc/backends/opensl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'alc/backends') diff --git a/alc/backends/opensl.cpp b/alc/backends/opensl.cpp index 2a161056..58e78459 100644 --- a/alc/backends/opensl.cpp +++ b/alc/backends/opensl.cpp @@ -934,7 +934,7 @@ void OpenSLCapture::captureSamples(std::byte *buffer, uint samples) return; /* For each buffer chunk that was fully read, queue another writable buffer - * chunk to keep the OpenSL queue full. This is rather convulated, as a + * chunk to keep the OpenSL queue full. This is rather convoluted, as a * result of the ring buffer holding more elements than are writable at a * given time. The end of the write vector increments when the read pointer * advances, which will "expose" a previously unwritable element. So for -- cgit v1.2.3 From e6e6a1c003ec2d80b5b11f8479ad95a4826bff89 Mon Sep 17 00:00:00 2001 From: Dirk Stolle Date: Wed, 5 Jul 2023 01:48:52 +0200 Subject: Fix some typos (#872) --- CMakeLists.txt | 4 ++-- al/buffer.cpp | 2 +- al/eax/api.h | 2 +- al/source.cpp | 6 +++--- alc/alu.cpp | 2 +- alc/backends/pipewire.cpp | 2 +- alc/backends/sndio.cpp | 2 +- alc/backends/winmm.cpp | 4 ++-- alc/effects/reverb.cpp | 4 ++-- core/filters/nfc.h | 2 +- core/helpers.cpp | 2 +- docs/ambisonics.txt | 4 ++-- examples/alconvolve.c | 4 ++-- examples/alhrtf.c | 2 +- examples/allatency.c | 2 +- examples/alloopback.c | 2 +- examples/almultireverb.c | 6 +++--- examples/alplay.c | 2 +- examples/alreverb.c | 4 ++-- examples/altonegen.c | 2 +- 20 files changed, 30 insertions(+), 30 deletions(-) (limited to 'alc/backends') diff --git a/CMakeLists.txt b/CMakeLists.txt index af25a96c..f458f3e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -171,7 +171,7 @@ elseif(APPLE) endif() -# QNX's gcc do not uses /usr/include and /usr/lib pathes by default +# QNX's gcc do not uses /usr/include and /usr/lib paths by default if("${CMAKE_C_PLATFORM_ID}" STREQUAL "QNX") set(INC_PATHS ${INC_PATHS} /usr/include) set(LINKER_FLAGS ${LINKER_FLAGS} -L/usr/lib) @@ -539,7 +539,7 @@ if(HAVE_LIBRT) set(RT_LIB rt) endif() -# Check for the dlopen API (for dynamicly loading backend libs) +# Check for the dlopen API (for dynamically loading backend libs) if(ALSOFT_DLOPEN) check_include_file(dlfcn.h HAVE_DLFCN_H) check_library_exists(dl dlopen "" HAVE_LIBDL) diff --git a/al/buffer.cpp b/al/buffer.cpp index edca56ad..01f61793 100644 --- a/al/buffer.cpp +++ b/al/buffer.cpp @@ -873,7 +873,7 @@ FORCE_ALIGN void AL_APIENTRY alFlushMappedBufferDirectSOFT(ALCcontext *context, else { /* FIXME: Need to use some method of double-buffering for the mixer and - * app to hold separate memory, which can be safely transfered + * app to hold separate memory, which can be safely transferred * asynchronously. Currently we just say the app shouldn't write where * OpenAL's reading, and hope for the best... */ diff --git a/al/eax/api.h b/al/eax/api.h index 8795d833..18d93ef8 100644 --- a/al/eax/api.h +++ b/al/eax/api.h @@ -614,7 +614,7 @@ struct EAX30SOURCEPROPERTIES { float flOcclusionLFRatio; // occlusion low-frequency level re. main control float flOcclusionRoomRatio; // relative occlusion control for room effect float flOcclusionDirectRatio; // relative occlusion control for direct path - long lExclusion; // main exlusion control (attenuation at high frequencies) + long lExclusion; // main exclusion control (attenuation at high frequencies) float flExclusionLFRatio; // exclusion low-frequency level re. main control long lOutsideVolumeHF; // outside sound cone level at high frequencies float flDopplerFactor; // like DS3D flDopplerFactor but per source diff --git a/al/source.cpp b/al/source.cpp index 7e425d43..adea9715 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -434,7 +434,7 @@ struct VoicePos { * GetSampleOffset * * Retrieves the voice position, fixed-point fraction, and bufferlist item - * using the givem offset type and offset. If the offset is out of range, + * using the given offset type and offset. If the offset is out of range, * returns an empty optional. */ std::optional GetSampleOffset(al::deque &BufferList, @@ -3870,7 +3870,7 @@ void ALsource::eax2_translate(const Eax2Props& src, Eax5Props& dst) noexcept dst.source.ulFlags = src.dwFlags; dst.source.flMacroFXFactor = EAXSOURCE_DEFAULTMACROFXFACTOR; - // Set everyting else to defaults. + // Set everything else to defaults. // eax5_set_sends_defaults(dst.sends); eax5_set_active_fx_slots_defaults(dst.active_fx_slots); @@ -3884,7 +3884,7 @@ void ALsource::eax3_translate(const Eax3Props& src, Eax5Props& dst) noexcept static_cast(dst.source) = src; dst.source.flMacroFXFactor = EAXSOURCE_DEFAULTMACROFXFACTOR; - // Set everyting else to defaults. + // Set everything else to defaults. // eax5_set_sends_defaults(dst.sends); eax5_set_active_fx_slots_defaults(dst.active_fx_slots); diff --git a/alc/alu.cpp b/alc/alu.cpp index 5dfb4fae..8a4df3d4 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -1853,7 +1853,7 @@ void ProcessContexts(DeviceBase *device, const uint SamplesToDo) const EffectSlotArray &auxslots = *ctx->mActiveAuxSlots.load(std::memory_order_acquire); const al::span voices{ctx->getVoicesSpanAcquired()}; - /* Process pending propery updates for objects on the context. */ + /* Process pending property updates for objects on the context. */ ProcessParamUpdates(ctx, auxslots, voices); /* Clear auxiliary effect slot mixing buffers. */ diff --git a/alc/backends/pipewire.cpp b/alc/backends/pipewire.cpp index 2bee4d7d..aac67ba2 100644 --- a/alc/backends/pipewire.cpp +++ b/alc/backends/pipewire.cpp @@ -1836,7 +1836,7 @@ ClockLatency PipeWirePlayback::getClockLatency() delay -= monoclock - nanoseconds{ptime.now}; /* Return the mixer time and delay. Clamp the delay to no less than 0, - * incase timer drift got that severe. + * in case timer drift got that severe. */ ClockLatency ret{}; ret.ClockTime = mixtime; diff --git a/alc/backends/sndio.cpp b/alc/backends/sndio.cpp index 89eee941..8daa928c 100644 --- a/alc/backends/sndio.cpp +++ b/alc/backends/sndio.cpp @@ -436,7 +436,7 @@ void SndioCapture::open(const char *name) if(!sio_setpar(mSndHandle, &par) || !sio_getpar(mSndHandle, &par)) throw al::backend_exception{al::backend_error::DeviceError, - "Failed to set device praameters"}; + "Failed to set device parameters"}; if(par.bps > 1 && par.le != SIO_LE_NATIVE) throw al::backend_exception{al::backend_error::DeviceError, diff --git a/alc/backends/winmm.cpp b/alc/backends/winmm.cpp index 661585cd..c22f1c4d 100644 --- a/alc/backends/winmm.cpp +++ b/alc/backends/winmm.cpp @@ -167,7 +167,7 @@ WinMMPlayback::~WinMMPlayback() /* WinMMPlayback::waveOutProc * - * Posts a message to 'WinMMPlayback::mixerProc' everytime a WaveOut Buffer is + * Posts a message to 'WinMMPlayback::mixerProc' every time a WaveOut Buffer is * completed and returns to the application (for more data) */ void CALLBACK WinMMPlayback::waveOutProc(HWAVEOUT, UINT msg, DWORD_PTR, DWORD_PTR) noexcept @@ -406,7 +406,7 @@ WinMMCapture::~WinMMCapture() /* WinMMCapture::waveInProc * - * Posts a message to 'WinMMCapture::captureProc' everytime a WaveIn Buffer is + * Posts a message to 'WinMMCapture::captureProc' every time a WaveIn Buffer is * completed and returns to the application (with more data). */ void CALLBACK WinMMCapture::waveInProc(HWAVEIN, UINT msg, DWORD_PTR, DWORD_PTR) noexcept diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index 3875bedb..330c404d 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -643,8 +643,8 @@ inline float CalcDelayLengthMult(float density) */ void ReverbState::allocLines(const float frequency) { - /* All delay line lengths are calculated to accomodate the full range of - * lengths given their respective paramters. + /* All delay line lengths are calculated to accommodate the full range of + * lengths given their respective parameters. */ size_t totalSamples{0u}; diff --git a/core/filters/nfc.h b/core/filters/nfc.h index 33f67a5f..4b8e68b5 100644 --- a/core/filters/nfc.h +++ b/core/filters/nfc.h @@ -39,7 +39,7 @@ public: * w1 = speed_of_sound / (control_distance * sample_rate); * * Generally speaking, the control distance should be approximately the - * average speaker distance, or based on the reference delay if outputing + * average speaker distance, or based on the reference delay if outputting * NFC-HOA. It must not be negative, 0, or infinite. The source distance * should not be too small relative to the control distance. */ diff --git a/core/helpers.cpp b/core/helpers.cpp index 2eccc50f..0d36048c 100644 --- a/core/helpers.cpp +++ b/core/helpers.cpp @@ -23,7 +23,7 @@ #include "strutils.h" -/* Mixing thread piority level */ +/* Mixing thread priority level */ int RTPrioLevel{1}; /* Allow reducing the process's RTTime limit for RTKit. */ diff --git a/docs/ambisonics.txt b/docs/ambisonics.txt index b1b111d6..7798c8f9 100644 --- a/docs/ambisonics.txt +++ b/docs/ambisonics.txt @@ -12,7 +12,7 @@ What Is It? Originally developed in the 1970s by Michael Gerzon and a team others, Ambisonics was created as a means of recording and playing back 3D sound. -Taking advantage of the way sound waves propogate, it is possible to record a +Taking advantage of the way sound waves propagate, it is possible to record a fully 3D soundfield using as few as 4 channels (or even just 3, if you don't mind dropping down to 2 dimensions like many surround sound systems are). This representation is called B-Format. It was designed to handle audio independent @@ -63,7 +63,7 @@ remain correct over a larger area around the center of the speakers. In addition, Ambisonics can encode the near-field effect of sounds, effectively capturing the sound distance. The near-field effect is a subtle low-frequency boost as a result of wave-front curvature, and properly compensating for this -occuring with the output speakers (as well as emulating it with a synthesized +occurring with the output speakers (as well as emulating it with a synthesized soundfield) can create an improved sense of distance for sounds that move near or far. diff --git a/examples/alconvolve.c b/examples/alconvolve.c index 93fd2eb4..94b978b5 100644 --- a/examples/alconvolve.c +++ b/examples/alconvolve.c @@ -292,7 +292,7 @@ static ALuint CreateEffect(void) alGenEffects(1, &effect); alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_CONVOLUTION_REVERB_SOFT); - /* Check if an error occured, and clean up if so. */ + /* Check if an error occurred, and clean up if so. */ err = alGetError(); if(err != AL_NO_ERROR) { @@ -391,7 +391,7 @@ static ALuint LoadSound(const char *filename) free(membuf); sf_close(sndfile); - /* Check if an error occured, and clean up if so. */ + /* Check if an error occurred, and clean up if so. */ err = alGetError(); if(err != AL_NO_ERROR) { diff --git a/examples/alhrtf.c b/examples/alhrtf.c index d878870e..7ea1b99e 100644 --- a/examples/alhrtf.c +++ b/examples/alhrtf.c @@ -121,7 +121,7 @@ static ALuint LoadSound(const char *filename) free(membuf); sf_close(sndfile); - /* Check if an error occured, and clean up if so. */ + /* Check if an error occurred, and clean up if so. */ err = alGetError(); if(err != AL_NO_ERROR) { diff --git a/examples/allatency.c b/examples/allatency.c index ab4a4ebc..01f4eb69 100644 --- a/examples/allatency.c +++ b/examples/allatency.c @@ -124,7 +124,7 @@ static ALuint LoadSound(const char *filename) free(membuf); sf_close(sndfile); - /* Check if an error occured, and clean up if so. */ + /* Check if an error occurred, and clean up if so. */ err = alGetError(); if(err != AL_NO_ERROR) { diff --git a/examples/alloopback.c b/examples/alloopback.c index 56cd420f..964a0cdb 100644 --- a/examples/alloopback.c +++ b/examples/alloopback.c @@ -118,7 +118,7 @@ static ALuint CreateSineWave(void) alGenBuffers(1, &buffer); alBufferData(buffer, AL_FORMAT_MONO16, data, sizeof(data), 44100); - /* Check if an error occured, and clean up if so. */ + /* Check if an error occurred, and clean up if so. */ err = alGetError(); if(err != AL_NO_ERROR) { diff --git a/examples/almultireverb.c b/examples/almultireverb.c index a77cc59e..dcb76c87 100644 --- a/examples/almultireverb.c +++ b/examples/almultireverb.c @@ -137,7 +137,7 @@ static int LoadEffect(ALuint effect, const EFXEAXREVERBPROPERTIES *reverb) alEffectf(effect, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, reverb->flRoomRolloffFactor); alEffecti(effect, AL_EAXREVERB_DECAY_HFLIMIT, reverb->iDecayHFLimit); - /* Check if an error occured, and return failure if so. */ + /* Check if an error occurred, and return failure if so. */ if((err=alGetError()) != AL_NO_ERROR) { fprintf(stderr, "Error setting up reverb: %s\n", alGetString(err)); @@ -210,7 +210,7 @@ static ALuint LoadSound(const char *filename) free(membuf); sf_close(sndfile); - /* Check if an error occured, and clean up if so. */ + /* Check if an error occurred, and clean up if so. */ err = alGetError(); if(err != AL_NO_ERROR) { @@ -493,7 +493,7 @@ int main(int argc, char **argv) } if(argc < 1) { - fprintf(stderr, "No filename spacified.\n"); + fprintf(stderr, "No filename specified.\n"); CloseAL(); return 1; } diff --git a/examples/alplay.c b/examples/alplay.c index 4291cb47..1eabcccd 100644 --- a/examples/alplay.c +++ b/examples/alplay.c @@ -266,7 +266,7 @@ static ALuint LoadSound(const char *filename) free(membuf); sf_close(sndfile); - /* Check if an error occured, and clean up if so. */ + /* Check if an error occurred, and clean up if so. */ err = alGetError(); if(err != AL_NO_ERROR) { diff --git a/examples/alreverb.c b/examples/alreverb.c index 11a3ac6b..ff49db25 100644 --- a/examples/alreverb.c +++ b/examples/alreverb.c @@ -132,7 +132,7 @@ static ALuint LoadEffect(const EFXEAXREVERBPROPERTIES *reverb) alEffecti(effect, AL_REVERB_DECAY_HFLIMIT, reverb->iDecayHFLimit); } - /* Check if an error occured, and clean up if so. */ + /* Check if an error occurred, and clean up if so. */ err = alGetError(); if(err != AL_NO_ERROR) { @@ -219,7 +219,7 @@ static ALuint LoadSound(const char *filename) free(membuf); sf_close(sndfile); - /* Check if an error occured, and clean up if so. */ + /* Check if an error occurred, and clean up if so. */ err = alGetError(); if(err != AL_NO_ERROR) { diff --git a/examples/altonegen.c b/examples/altonegen.c index 75db2d6b..a1daa66f 100644 --- a/examples/altonegen.c +++ b/examples/altonegen.c @@ -156,7 +156,7 @@ static ALuint CreateWave(enum WaveType type, ALuint freq, ALuint srate, ALfloat alBufferData(buffer, AL_FORMAT_MONO_FLOAT32, data, (ALsizei)data_size, (ALsizei)srate); free(data); - /* Check if an error occured, and clean up if so. */ + /* Check if an error occurred, and clean up if so. */ err = alGetError(); if(err != AL_NO_ERROR) { -- cgit v1.2.3 From 05f9ce8b978239cebecef1a60f0d451a118fa3df Mon Sep 17 00:00:00 2001 From: captainurist <73941350+captainurist@users.noreply.github.com> Date: Sat, 8 Jul 2023 01:29:45 +0800 Subject: Return noErr from DeviceListenerProc (#875) --- alc/backends/coreaudio.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'alc/backends') diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index c2888e42..12c667ac 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -309,6 +309,7 @@ struct DeviceHelper { break; } } + return noErr; } }; -- cgit v1.2.3 From e90ea548bfcf2fb0eeab484fabfbf508077d1217 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 20 Jul 2023 00:54:48 -0700 Subject: Make C callback functions noexcept --- alc/backends/pipewire.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/pipewire.cpp b/alc/backends/pipewire.cpp index aac67ba2..fec2e800 100644 --- a/alc/backends/pipewire.cpp +++ b/alc/backends/pipewire.cpp @@ -1348,9 +1348,9 @@ spa_audio_info_raw make_spa_info(DeviceBase *device, bool is51rear, use_f32p_e u } class PipeWirePlayback final : public BackendBase { - void stateChangedCallback(pw_stream_state old, pw_stream_state state, const char *error); - void ioChangedCallback(uint32_t id, void *area, uint32_t size); - void outputCallback(); + void stateChangedCallback(pw_stream_state old, pw_stream_state state, const char *error) noexcept; + void ioChangedCallback(uint32_t id, void *area, uint32_t size) noexcept; + void outputCallback() noexcept; void open(const char *name) override; bool reset() override; @@ -1373,11 +1373,11 @@ class PipeWirePlayback final : public BackendBase { { pw_stream_events ret{}; ret.version = PW_VERSION_STREAM_EVENTS; - ret.state_changed = [](void *data, pw_stream_state old, pw_stream_state state, const char *error) + ret.state_changed = [](void *data, pw_stream_state old, pw_stream_state state, const char *error) noexcept { static_cast(data)->stateChangedCallback(old, state, error); }; - ret.io_changed = [](void *data, uint32_t id, void *area, uint32_t size) + ret.io_changed = [](void *data, uint32_t id, void *area, uint32_t size) noexcept { static_cast(data)->ioChangedCallback(id, area, size); }; - ret.process = [](void *data) + ret.process = [](void *data) noexcept { static_cast(data)->outputCallback(); }; return ret; } @@ -1394,10 +1394,10 @@ public: }; -void PipeWirePlayback::stateChangedCallback(pw_stream_state, pw_stream_state, const char*) +void PipeWirePlayback::stateChangedCallback(pw_stream_state, pw_stream_state, const char*) noexcept { mLoop.signal(false); } -void PipeWirePlayback::ioChangedCallback(uint32_t id, void *area, uint32_t size) +void PipeWirePlayback::ioChangedCallback(uint32_t id, void *area, uint32_t size) noexcept { switch(id) { @@ -1408,7 +1408,7 @@ void PipeWirePlayback::ioChangedCallback(uint32_t id, void *area, uint32_t size) } } -void PipeWirePlayback::outputCallback() +void PipeWirePlayback::outputCallback() noexcept { pw_buffer *pw_buf{pw_stream_dequeue_buffer(mStream.get())}; if(!pw_buf) UNLIKELY return; @@ -1847,8 +1847,8 @@ ClockLatency PipeWirePlayback::getClockLatency() class PipeWireCapture final : public BackendBase { - void stateChangedCallback(pw_stream_state old, pw_stream_state state, const char *error); - void inputCallback(); + void stateChangedCallback(pw_stream_state old, pw_stream_state state, const char *error) noexcept; + void inputCallback() noexcept; void open(const char *name) override; void start() override; @@ -1869,9 +1869,9 @@ class PipeWireCapture final : public BackendBase { { pw_stream_events ret{}; ret.version = PW_VERSION_STREAM_EVENTS; - ret.state_changed = [](void *data, pw_stream_state old, pw_stream_state state, const char *error) + ret.state_changed = [](void *data, pw_stream_state old, pw_stream_state state, const char *error) noexcept { static_cast(data)->stateChangedCallback(old, state, error); }; - ret.process = [](void *data) + ret.process = [](void *data) noexcept { static_cast(data)->inputCallback(); }; return ret; } @@ -1884,10 +1884,10 @@ public: }; -void PipeWireCapture::stateChangedCallback(pw_stream_state, pw_stream_state, const char*) +void PipeWireCapture::stateChangedCallback(pw_stream_state, pw_stream_state, const char*) noexcept { mLoop.signal(false); } -void PipeWireCapture::inputCallback() +void PipeWireCapture::inputCallback() noexcept { pw_buffer *pw_buf{pw_stream_dequeue_buffer(mStream.get())}; if(!pw_buf) UNLIKELY return; -- cgit v1.2.3 From b9de83c3e191858ac6b572d145bec5f9f2515543 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 20 Jul 2023 02:30:08 -0700 Subject: Use a lambda to forward a C callback --- alc/backends/opensl.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/opensl.cpp b/alc/backends/opensl.cpp index 58e78459..35c57d77 100644 --- a/alc/backends/opensl.cpp +++ b/alc/backends/opensl.cpp @@ -161,8 +161,6 @@ struct OpenSLPlayback final : public BackendBase { ~OpenSLPlayback() override; void process(SLAndroidSimpleBufferQueueItf bq) noexcept; - static void processC(SLAndroidSimpleBufferQueueItf bq, void *context) noexcept - { static_cast(context)->process(bq); } int mixerProc(); @@ -566,7 +564,9 @@ void OpenSLPlayback::start() PrintErr(result, "bufferQueue->GetInterface"); if(SL_RESULT_SUCCESS == result) { - result = VCALL(bufferQueue,RegisterCallback)(&OpenSLPlayback::processC, this); + result = VCALL(bufferQueue,RegisterCallback)( + [](SLAndroidSimpleBufferQueueItf bq, void *context) noexcept + { static_cast(context)->process(bq); }, this); PrintErr(result, "bufferQueue->RegisterCallback"); } if(SL_RESULT_SUCCESS != result) @@ -644,8 +644,6 @@ struct OpenSLCapture final : public BackendBase { ~OpenSLCapture() override; void process(SLAndroidSimpleBufferQueueItf bq) noexcept; - static void processC(SLAndroidSimpleBufferQueueItf bq, void *context) noexcept - { static_cast(context)->process(bq); } void open(const char *name) override; void start() override; @@ -815,7 +813,9 @@ void OpenSLCapture::open(const char* name) } if(SL_RESULT_SUCCESS == result) { - result = VCALL(bufferQueue,RegisterCallback)(&OpenSLCapture::processC, this); + result = VCALL(bufferQueue,RegisterCallback)( + [](SLAndroidSimpleBufferQueueItf bq, void *context) noexcept + { static_cast(context)->process(bq); }, this); PrintErr(result, "bufferQueue->RegisterCallback"); } if(SL_RESULT_SUCCESS == result) -- cgit v1.2.3 From 199a75f17ac564983a4bc8fb70715107b1f99126 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 4 Aug 2023 04:59:42 -0700 Subject: Don't use pipewire user data storage for native proxy objects --- alc/backends/pipewire.cpp | 193 ++++++++++++++++++++-------------------------- 1 file changed, 83 insertions(+), 110 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/pipewire.cpp b/alc/backends/pipewire.cpp index fec2e800..902d6374 100644 --- a/alc/backends/pipewire.cpp +++ b/alc/backends/pipewire.cpp @@ -435,8 +435,75 @@ using MainloopLockGuard = std::lock_guard; * devices provided by the server. */ -struct NodeProxy; -struct MetadataProxy; +/* A generic PipeWire node proxy object used to track changes to sink and + * source nodes. + */ +struct NodeProxy { + static constexpr pw_node_events CreateNodeEvents() + { + pw_node_events ret{}; + ret.version = PW_VERSION_NODE_EVENTS; + ret.info = [](void *object, const pw_node_info *info) noexcept + { static_cast(object)->infoCallback(info); }; + ret.param = [](void *object, int seq, uint32_t id, uint32_t index, uint32_t next, const spa_pod *param) noexcept + { static_cast(object)->paramCallback(seq, id, index, next, param); }; + return ret; + } + + uint32_t mId{}; + + PwNodePtr mNode{}; + spa_hook mListener{}; + + NodeProxy(uint32_t id, PwNodePtr node) + : mId{id}, mNode{std::move(node)} + { + static constexpr pw_node_events nodeEvents{CreateNodeEvents()}; + ppw_node_add_listener(mNode.get(), &mListener, &nodeEvents, this); + + /* Track changes to the enumerable formats (indicates the default + * format, which is what we're interested in). + */ + uint32_t fmtids[]{SPA_PARAM_EnumFormat}; + ppw_node_subscribe_params(mNode.get(), std::data(fmtids), std::size(fmtids)); + } + ~NodeProxy() + { spa_hook_remove(&mListener); } + + + void infoCallback(const pw_node_info *info) noexcept; + + void paramCallback(int seq, uint32_t id, uint32_t index, uint32_t next, const spa_pod *param) noexcept; +}; + +/* A metadata proxy object used to query the default sink and source. */ +struct MetadataProxy { + static constexpr pw_metadata_events CreateMetadataEvents() + { + pw_metadata_events ret{}; + ret.version = PW_VERSION_METADATA_EVENTS; + ret.property = [](void *object, uint32_t id, const char *key, const char *type, const char *value) noexcept + { return static_cast(object)->propertyCallback(id, key, type, value); }; + return ret; + } + + uint32_t mId{}; + + PwMetadataPtr mMetadata{}; + spa_hook mListener{}; + + MetadataProxy(uint32_t id, PwMetadataPtr mdata) + : mId{id}, mMetadata{std::move(mdata)} + { + static constexpr pw_metadata_events metadataEvents{CreateMetadataEvents()}; + ppw_metadata_add_listener(mMetadata.get(), &mListener, &metadataEvents, this); + } + ~MetadataProxy() + { spa_hook_remove(&mListener); } + + int propertyCallback(uint32_t id, const char *key, const char *type, const char *value) noexcept; +}; + /* The global thread watching for global events. This particular class responds * to objects being added to or removed from the registry. @@ -452,8 +519,8 @@ struct EventManager { /* A list of proxy objects watching for events about changes to objects in * the registry. */ - std::vector mNodeList; - MetadataProxy *mDefaultMetadata{nullptr}; + std::vector> mNodeList; + std::optional mDefaultMetadata; /* Initialization handling. When init() is called, mInitSeq is set to a * SequenceID that marks the end of populating the registry. As objects of @@ -465,8 +532,9 @@ struct EventManager { std::atomic mHasAudio{false}; int mInitSeq{}; + ~EventManager() { if(mLoop) mLoop.stop(); } + bool init(); - ~EventManager(); void kill(); @@ -573,7 +641,7 @@ struct DeviceNode { static DeviceNode *Find(uint32_t id); static DeviceNode *FindByDevName(std::string_view devname); static void Remove(uint32_t id); - static std::vector &GetList() noexcept { return sList; } + static auto GetList() noexcept { return al::span{sList}; } void parseSampleRate(const spa_pod *value) noexcept; void parsePositions(const spa_pod *value) noexcept; @@ -613,8 +681,7 @@ DeviceNode &DeviceNode::Add(uint32_t id) auto match = std::find_if(sList.begin(), sList.end(), match_id); if(match != sList.end()) return *match; - sList.emplace_back(); - auto &n = sList.back(); + auto &n = sList.emplace_back(); n.mId = id; return n; } @@ -834,47 +901,6 @@ constexpr char AudioSourceVirtualClass[]{"Audio/Source/Virtual"}; constexpr char AudioDuplexClass[]{"Audio/Duplex"}; constexpr char StreamClass[]{"Stream/"}; -/* A generic PipeWire node proxy object used to track changes to sink and - * source nodes. - */ -struct NodeProxy { - static constexpr pw_node_events CreateNodeEvents() - { - pw_node_events ret{}; - ret.version = PW_VERSION_NODE_EVENTS; - ret.info = [](void *object, const pw_node_info *info) noexcept - { static_cast(object)->infoCallback(info); }; - ret.param = [](void *object, int seq, uint32_t id, uint32_t index, uint32_t next, const spa_pod *param) noexcept - { static_cast(object)->paramCallback(seq, id, index, next, param); }; - return ret; - } - - uint32_t mId{}; - - PwNodePtr mNode{}; - spa_hook mListener{}; - - NodeProxy(uint32_t id, PwNodePtr node) - : mId{id}, mNode{std::move(node)} - { - static constexpr pw_node_events nodeEvents{CreateNodeEvents()}; - ppw_node_add_listener(mNode.get(), &mListener, &nodeEvents, this); - - /* Track changes to the enumerable formats (indicates the default - * format, which is what we're interested in). - */ - uint32_t fmtids[]{SPA_PARAM_EnumFormat}; - ppw_node_subscribe_params(mNode.get(), std::data(fmtids), std::size(fmtids)); - } - ~NodeProxy() - { spa_hook_remove(&mListener); } - - - void infoCallback(const pw_node_info *info) noexcept; - - void paramCallback(int seq, uint32_t id, uint32_t index, uint32_t next, const spa_pod *param) noexcept; -}; - void NodeProxy::infoCallback(const pw_node_info *info) noexcept { /* We only care about property changes here (media class, name/desc). @@ -982,34 +1008,6 @@ void NodeProxy::paramCallback(int, uint32_t id, uint32_t, uint32_t, const spa_po } -/* A metadata proxy object used to query the default sink and source. */ -struct MetadataProxy { - static constexpr pw_metadata_events CreateMetadataEvents() - { - pw_metadata_events ret{}; - ret.version = PW_VERSION_METADATA_EVENTS; - ret.property = [](void *object, uint32_t id, const char *key, const char *type, const char *value) noexcept - { return static_cast(object)->propertyCallback(id, key, type, value); }; - return ret; - } - - uint32_t mId{}; - - PwMetadataPtr mMetadata{}; - spa_hook mListener{}; - - MetadataProxy(uint32_t id, PwMetadataPtr mdata) - : mId{id}, mMetadata{std::move(mdata)} - { - static constexpr pw_metadata_events metadataEvents{CreateMetadataEvents()}; - ppw_metadata_add_listener(mMetadata.get(), &mListener, &metadataEvents, this); - } - ~MetadataProxy() - { spa_hook_remove(&mListener); } - - int propertyCallback(uint32_t id, const char *key, const char *type, const char *value) noexcept; -}; - int MetadataProxy::propertyCallback(uint32_t id, const char *key, const char *type, const char *value) noexcept { @@ -1158,26 +1156,12 @@ bool EventManager::init() return true; } -EventManager::~EventManager() -{ - if(mLoop) mLoop.stop(); - - for(NodeProxy *node : mNodeList) - std::destroy_at(node); - if(mDefaultMetadata) - std::destroy_at(mDefaultMetadata); -} - void EventManager::kill() { if(mLoop) mLoop.stop(); - for(NodeProxy *node : mNodeList) - std::destroy_at(node); + mDefaultMetadata.reset(); mNodeList.clear(); - if(mDefaultMetadata) - std::destroy_at(mDefaultMetadata); - mDefaultMetadata = nullptr; mRegistry = nullptr; mCore = nullptr; @@ -1209,7 +1193,7 @@ void EventManager::addCallback(uint32_t id, uint32_t, const char *type, uint32_t /* Create the proxy object. */ auto node = PwNodePtr{static_cast(pw_registry_bind(mRegistry.get(), id, type, - version, sizeof(NodeProxy)))}; + version, 0))}; if(!node) { ERR("Failed to create node proxy object (errno: %d)\n", errno); @@ -1219,8 +1203,7 @@ void EventManager::addCallback(uint32_t id, uint32_t, const char *type, uint32_t /* Initialize the NodeProxy to hold the node object, add it to the * active node list, and update the sync point. */ - auto *proxy = static_cast(pw_proxy_get_user_data(as(node.get()))); - mNodeList.emplace_back(al::construct_at(proxy, id, std::move(node))); + mNodeList.emplace_back(std::make_unique(id, std::move(node))); syncInit(); /* Signal any waiters that we have found a source or sink for audio @@ -1247,16 +1230,14 @@ void EventManager::addCallback(uint32_t id, uint32_t, const char *type, uint32_t } auto mdata = PwMetadataPtr{static_cast(pw_registry_bind(mRegistry.get(), id, - type, version, sizeof(MetadataProxy)))}; + type, version, 0))}; if(!mdata) { ERR("Failed to create metadata proxy object (errno: %d)\n", errno); return; } - auto *proxy = static_cast( - pw_proxy_get_user_data(as(mdata.get()))); - mDefaultMetadata = al::construct_at(proxy, id, std::move(mdata)); + mDefaultMetadata.emplace(id, std::move(mdata)); syncInit(); } } @@ -1265,21 +1246,13 @@ void EventManager::removeCallback(uint32_t id) noexcept { DeviceNode::Remove(id); - auto clear_node = [id](NodeProxy *node) noexcept - { - if(node->mId != id) - return false; - std::destroy_at(node); - return true; - }; + auto clear_node = [id](std::unique_ptr &node) noexcept + { return node->mId == id; }; auto node_end = std::remove_if(mNodeList.begin(), mNodeList.end(), clear_node); mNodeList.erase(node_end, mNodeList.end()); if(mDefaultMetadata && mDefaultMetadata->mId == id) - { - std::destroy_at(mDefaultMetadata); - mDefaultMetadata = nullptr; - } + mDefaultMetadata.reset(); } void EventManager::coreCallback(uint32_t id, int seq) noexcept -- cgit v1.2.3 From 9296af5566afea4ba4cb78b374ef3ee0bf9bc04b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Aug 2023 18:49:42 -0700 Subject: Use a string_view for the backend open method --- alc/alc.cpp | 41 ++++++++++++++++++++++++++++++----- alc/backends/alsa.cpp | 16 +++++++------- alc/backends/base.h | 3 ++- alc/backends/coreaudio.cpp | 36 +++++++++++++++--------------- alc/backends/dsound.cpp | 22 ++++++++++--------- alc/backends/jack.cpp | 18 +++++++-------- alc/backends/loopback.cpp | 4 ++-- alc/backends/null.cpp | 12 +++++----- alc/backends/oboe.cpp | 24 ++++++++++---------- alc/backends/opensl.cpp | 24 ++++++++++---------- alc/backends/oss.cpp | 16 +++++++------- alc/backends/pipewire.cpp | 21 +++++++++--------- alc/backends/portaudio.cpp | 24 ++++++++++---------- alc/backends/pulseaudio.cpp | 16 +++++++------- alc/backends/sdl2.cpp | 27 +++++++++++++++++------ alc/backends/sndio.cpp | 24 ++++++++++---------- alc/backends/solaris.cpp | 12 +++++----- alc/backends/wasapi.cpp | 53 +++++++++++++++++++++++---------------------- alc/backends/wave.cpp | 14 ++++++------ alc/backends/winmm.cpp | 20 ++++++++--------- common/strutils.cpp | 17 ++++++++------- common/strutils.h | 5 +++-- 22 files changed, 249 insertions(+), 200 deletions(-) (limited to 'alc/backends') diff --git a/alc/alc.cpp b/alc/alc.cpp index 82f3ec4b..45a55793 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -2905,9 +2905,26 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) noexcep device->NumAuxSends = DefaultSends; try { + /* We need to ensure the device name isn't too long. The string_view is + * printed using the "%.*s" formatter, which uses an int for the + * precision/length. It wouldn't be a significant problem if larger + * values simply printed fewer characters due to truncation, but + * negative values are ignored, treating it like a normal null- + * terminated string, and string_views don't need to be null- + * terminated. + * + * Other than the annoyance of checking, this shouldn't be a problem. + * Two billion bytes is enough for a device name. + */ + const std::string_view devname{deviceName ? deviceName : ""}; + if(devname.length() >= std::numeric_limits::max()) + throw al::backend_exception{al::backend_error::NoDevice, + "Device name too long (%zu >= %d)", devname.length(), + std::numeric_limits::max()}; + auto backend = PlaybackFactory->createBackend(device.get(), BackendType::Playback); std::lock_guard _{ListLock}; - backend->open(deviceName); + backend->open(devname); device->Backend = std::move(backend); } catch(al::backend_exception &e) { @@ -3024,14 +3041,20 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, device->UpdateSize = static_cast(samples); device->BufferSize = static_cast(samples); + TRACE("Capture format: %s, %s, %uhz, %u / %u buffer\n", DevFmtChannelsString(device->FmtChans), + DevFmtTypeString(device->FmtType), device->Frequency, device->UpdateSize, + device->BufferSize); + try { - TRACE("Capture format: %s, %s, %uhz, %u / %u buffer\n", - DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), - device->Frequency, device->UpdateSize, device->BufferSize); + const std::string_view devname{deviceName ? deviceName : ""}; + if(devname.length() >= std::numeric_limits::max()) + throw al::backend_exception{al::backend_error::NoDevice, + "Device name too long (%zu >= %d)", devname.length(), + std::numeric_limits::max()}; auto backend = CaptureFactory->createBackend(device.get(), BackendType::Capture); std::lock_guard _{ListLock}; - backend->open(deviceName); + backend->open(devname); device->Backend = std::move(backend); } catch(al::backend_exception &e) { @@ -3393,8 +3416,14 @@ FORCE_ALIGN ALCboolean ALC_APIENTRY alcReopenDeviceSOFT(ALCdevice *device, BackendPtr newbackend; try { + const std::string_view devname{deviceName ? deviceName : ""}; + if(devname.length() >= std::numeric_limits::max()) + throw al::backend_exception{al::backend_error::NoDevice, + "Device name too long (%zu >= %d)", devname.length(), + std::numeric_limits::max()}; + newbackend = PlaybackFactory->createBackend(dev.get(), BackendType::Playback); - newbackend->open(deviceName); + newbackend->open(devname); } catch(al::backend_exception &e) { listlock.unlock(); diff --git a/alc/backends/alsa.cpp b/alc/backends/alsa.cpp index 83eef183..0d9ff30d 100644 --- a/alc/backends/alsa.cpp +++ b/alc/backends/alsa.cpp @@ -427,7 +427,7 @@ struct AlsaPlayback final : public BackendBase { int mixerProc(); int mixerNoMMapProc(); - void open(const char *name) override; + void open(std::string_view name) override; bool reset() override; void start() override; void stop() override; @@ -626,10 +626,10 @@ int AlsaPlayback::mixerNoMMapProc() } -void AlsaPlayback::open(const char *name) +void AlsaPlayback::open(std::string_view name) { std::string driver{"default"}; - if(name) + if(!name.empty()) { if(PlaybackDevices.empty()) PlaybackDevices = probe_devices(SND_PCM_STREAM_PLAYBACK); @@ -638,7 +638,7 @@ void AlsaPlayback::open(const char *name) [name](const DevMap &entry) -> bool { return entry.name == name; }); if(iter == PlaybackDevices.cend()) throw al::backend_exception{al::backend_error::NoDevice, - "Device name \"%s\" not found", name}; + "Device name \"%.*s\" not found", static_cast(name.length()), name.data()}; driver = iter->device_name; } else @@ -871,7 +871,7 @@ struct AlsaCapture final : public BackendBase { AlsaCapture(DeviceBase *device) noexcept : BackendBase{device} { } ~AlsaCapture() override; - void open(const char *name) override; + void open(std::string_view name) override; void start() override; void stop() override; void captureSamples(std::byte *buffer, uint samples) override; @@ -898,10 +898,10 @@ AlsaCapture::~AlsaCapture() } -void AlsaCapture::open(const char *name) +void AlsaCapture::open(std::string_view name) { std::string driver{"default"}; - if(name) + if(!name.empty()) { if(CaptureDevices.empty()) CaptureDevices = probe_devices(SND_PCM_STREAM_CAPTURE); @@ -910,7 +910,7 @@ void AlsaCapture::open(const char *name) [name](const DevMap &entry) -> bool { return entry.name == name; }); if(iter == CaptureDevices.cend()) throw al::backend_exception{al::backend_error::NoDevice, - "Device name \"%s\" not found", name}; + "Device name \"%.*s\" not found", static_cast(name.length()), name.data()}; driver = iter->device_name; } else diff --git a/alc/backends/base.h b/alc/backends/base.h index 07b430e0..a4079fe4 100644 --- a/alc/backends/base.h +++ b/alc/backends/base.h @@ -7,6 +7,7 @@ #include #include #include +#include #include "core/device.h" #include "core/except.h" @@ -20,7 +21,7 @@ struct ClockLatency { }; struct BackendBase { - virtual void open(const char *name) = 0; + virtual void open(std::string_view name) = 0; virtual bool reset(); virtual void start() = 0; diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index 12c667ac..1684545b 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -329,7 +329,7 @@ struct CoreAudioPlayback final : public BackendBase { const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) noexcept; - void open(const char *name) override; + void open(std::string_view name) override; bool reset() override; void start() override; void stop() override; @@ -362,11 +362,11 @@ OSStatus CoreAudioPlayback::MixerProc(AudioUnitRenderActionFlags*, const AudioTi } -void CoreAudioPlayback::open(const char *name) +void CoreAudioPlayback::open(std::string_view name) { #if CAN_ENUMERATE AudioDeviceID audioDevice{kAudioDeviceUnknown}; - if(!name) + if(name.empty()) GetHwProperty(kAudioHardwarePropertyDefaultOutputDevice, sizeof(audioDevice), &audioDevice); else @@ -379,16 +379,16 @@ void CoreAudioPlayback::open(const char *name) auto devmatch = std::find_if(PlaybackList.cbegin(), PlaybackList.cend(), find_name); if(devmatch == PlaybackList.cend()) throw al::backend_exception{al::backend_error::NoDevice, - "Device name \"%s\" not found", name}; + "Device name \"%.*s\" not found", static_cast(name.length()), name.data()}; audioDevice = devmatch->mId; } #else - if(!name) + if(name.empty()) name = ca_device; - else if(strcmp(name, ca_device) != 0) - throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found", - name}; + else if(name != ca_device) + throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found", + static_cast(name.length()), name.data()}; #endif /* open the default output unit */ @@ -436,7 +436,7 @@ void CoreAudioPlayback::open(const char *name) mAudioUnit = audioUnit; #if CAN_ENUMERATE - if(name) + if(!name.empty()) mDevice->DeviceName = name; else { @@ -608,7 +608,7 @@ struct CoreAudioCapture final : public BackendBase { const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) noexcept; - void open(const char *name) override; + void open(std::string_view name) override; void start() override; void stop() override; void captureSamples(std::byte *buffer, uint samples) override; @@ -663,11 +663,11 @@ OSStatus CoreAudioCapture::RecordProc(AudioUnitRenderActionFlags *ioActionFlags, } -void CoreAudioCapture::open(const char *name) +void CoreAudioCapture::open(std::string_view name) { #if CAN_ENUMERATE AudioDeviceID audioDevice{kAudioDeviceUnknown}; - if(!name) + if(name.empty()) GetHwProperty(kAudioHardwarePropertyDefaultInputDevice, sizeof(audioDevice), &audioDevice); else @@ -680,16 +680,16 @@ void CoreAudioCapture::open(const char *name) auto devmatch = std::find_if(CaptureList.cbegin(), CaptureList.cend(), find_name); if(devmatch == CaptureList.cend()) throw al::backend_exception{al::backend_error::NoDevice, - "Device name \"%s\" not found", name}; + "Device name \"%.*s\" not found", static_cast(name.length()), name.data()}; audioDevice = devmatch->mId; } #else - if(!name) + if(name.empty()) name = ca_device; - else if(strcmp(name, ca_device) != 0) - throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found", - name}; + else if(name != ca_device) + throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found", + static_cast(name.length()), name.data()}; #endif AudioComponentDescription desc{}; @@ -887,7 +887,7 @@ void CoreAudioCapture::open(const char *name) mDevice->Frequency, Resampler::FastBSinc24); #if CAN_ENUMERATE - if(name) + if(!name.empty()) mDevice->DeviceName = name; else { diff --git a/alc/backends/dsound.cpp b/alc/backends/dsound.cpp index 54fac898..b5596f1c 100644 --- a/alc/backends/dsound.cpp +++ b/alc/backends/dsound.cpp @@ -178,7 +178,7 @@ struct DSoundPlayback final : public BackendBase { int mixerProc(); - void open(const char *name) override; + void open(std::string_view name) override; bool reset() override; void start() override; void stop() override; @@ -301,7 +301,7 @@ FORCE_ALIGN int DSoundPlayback::mixerProc() return 0; } -void DSoundPlayback::open(const char *name) +void DSoundPlayback::open(std::string_view name) { HRESULT hr; if(PlaybackDevices.empty()) @@ -316,9 +316,9 @@ void DSoundPlayback::open(const char *name) } const GUID *guid{nullptr}; - if(!name && !PlaybackDevices.empty()) + if(name.empty() && !PlaybackDevices.empty()) { - name = PlaybackDevices[0].name.c_str(); + name = PlaybackDevices[0].name; guid = &PlaybackDevices[0].guid; } else @@ -334,7 +334,8 @@ void DSoundPlayback::open(const char *name) [&id](const DevMap &entry) -> bool { return entry.guid == id; }); if(iter == PlaybackDevices.cend()) throw al::backend_exception{al::backend_error::NoDevice, - "Device name \"%s\" not found", name}; + "Device name \"%.*s\" not found", static_cast(name.length()), + name.data()}; } guid = &iter->guid; } @@ -549,7 +550,7 @@ struct DSoundCapture final : public BackendBase { DSoundCapture(DeviceBase *device) noexcept : BackendBase{device} { } ~DSoundCapture() override; - void open(const char *name) override; + void open(std::string_view name) override; void start() override; void stop() override; void captureSamples(std::byte *buffer, uint samples) override; @@ -576,7 +577,7 @@ DSoundCapture::~DSoundCapture() } -void DSoundCapture::open(const char *name) +void DSoundCapture::open(std::string_view name) { HRESULT hr; if(CaptureDevices.empty()) @@ -591,9 +592,9 @@ void DSoundCapture::open(const char *name) } const GUID *guid{nullptr}; - if(!name && !CaptureDevices.empty()) + if(name.empty() && !CaptureDevices.empty()) { - name = CaptureDevices[0].name.c_str(); + name = CaptureDevices[0].name; guid = &CaptureDevices[0].guid; } else @@ -609,7 +610,8 @@ void DSoundCapture::open(const char *name) [&id](const DevMap &entry) -> bool { return entry.guid == id; }); if(iter == CaptureDevices.cend()) throw al::backend_exception{al::backend_error::NoDevice, - "Device name \"%s\" not found", name}; + "Device name \"%.*s\" not found", static_cast(name.length()), + name.data()}; } guid = &iter->guid; } diff --git a/alc/backends/jack.cpp b/alc/backends/jack.cpp index 66fc0877..a0a5c440 100644 --- a/alc/backends/jack.cpp +++ b/alc/backends/jack.cpp @@ -298,7 +298,7 @@ struct JackPlayback final : public BackendBase { int mixerProc(); - void open(const char *name) override; + void open(std::string_view name) override; bool reset() override; void start() override; void stop() override; @@ -460,7 +460,7 @@ int JackPlayback::mixerProc() } -void JackPlayback::open(const char *name) +void JackPlayback::open(std::string_view name) { if(!mClient) { @@ -484,9 +484,9 @@ void JackPlayback::open(const char *name) if(PlaybackList.empty()) EnumerateDevices(mClient, PlaybackList); - if(!name && !PlaybackList.empty()) + if(name.empty() && !PlaybackList.empty()) { - name = PlaybackList[0].mName.c_str(); + name = PlaybackList[0].mName; mPortPattern = PlaybackList[0].mPattern; } else @@ -496,14 +496,10 @@ void JackPlayback::open(const char *name) auto iter = std::find_if(PlaybackList.cbegin(), PlaybackList.cend(), check_name); if(iter == PlaybackList.cend()) throw al::backend_exception{al::backend_error::NoDevice, - "Device name \"%s\" not found", name?name:""}; + "Device name \"%.*s\" not found", static_cast(name.length()), name.data()}; mPortPattern = iter->mPattern; } - mRTMixing = GetConfigValueBool(name, "jack", "rt-mix", true); - jack_set_process_callback(mClient, - mRTMixing ? &JackPlayback::processRtC : &JackPlayback::processC, this); - mDevice->DeviceName = name; } @@ -514,6 +510,10 @@ bool JackPlayback::reset() std::for_each(mPort.begin(), mPort.end(), unregister_port); mPort.fill(nullptr); + mRTMixing = GetConfigValueBool(mDevice->DeviceName.c_str(), "jack", "rt-mix", true); + jack_set_process_callback(mClient, + mRTMixing ? &JackPlayback::processRtC : &JackPlayback::processC, this); + /* Ignore the requested buffer metrics and just keep one JACK-sized buffer * ready for when requested. */ diff --git a/alc/backends/loopback.cpp b/alc/backends/loopback.cpp index bf4ab246..2972fc01 100644 --- a/alc/backends/loopback.cpp +++ b/alc/backends/loopback.cpp @@ -30,7 +30,7 @@ namespace { struct LoopbackBackend final : public BackendBase { LoopbackBackend(DeviceBase *device) noexcept : BackendBase{device} { } - void open(const char *name) override; + void open(std::string_view name) override; bool reset() override; void start() override; void stop() override; @@ -39,7 +39,7 @@ struct LoopbackBackend final : public BackendBase { }; -void LoopbackBackend::open(const char *name) +void LoopbackBackend::open(std::string_view name) { mDevice->DeviceName = name; } diff --git a/alc/backends/null.cpp b/alc/backends/null.cpp index 73420ad3..3c68e4ce 100644 --- a/alc/backends/null.cpp +++ b/alc/backends/null.cpp @@ -50,7 +50,7 @@ struct NullBackend final : public BackendBase { int mixerProc(); - void open(const char *name) override; + void open(std::string_view name) override; bool reset() override; void start() override; void stop() override; @@ -105,13 +105,13 @@ int NullBackend::mixerProc() } -void NullBackend::open(const char *name) +void NullBackend::open(std::string_view name) { - if(!name) + if(name.empty()) name = nullDevice; - else if(strcmp(name, nullDevice) != 0) - throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found", - name}; + else if(name != nullDevice) + throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found", + static_cast(name.length()), name.data()}; mDevice->DeviceName = name; } diff --git a/alc/backends/oboe.cpp b/alc/backends/oboe.cpp index cc44b867..b7bab19a 100644 --- a/alc/backends/oboe.cpp +++ b/alc/backends/oboe.cpp @@ -30,7 +30,7 @@ struct OboePlayback final : public BackendBase, public oboe::AudioStreamCallback void onErrorAfterClose(oboe::AudioStream* /* audioStream */, oboe::Result /* error */) override; - void open(const char *name) override; + void open(std::string_view name) override; bool reset() override; void start() override; void stop() override; @@ -56,13 +56,13 @@ void OboePlayback::onErrorAfterClose(oboe::AudioStream* audioStream, oboe::Resul TRACE("Error was %s", oboe::convertToText(error)); } -void OboePlayback::open(const char *name) +void OboePlayback::open(std::string_view name) { - if(!name) + if(name.empty()) name = device_name; - else if(std::strcmp(name, device_name) != 0) - throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found", - name}; + else if(name != device_name) + throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found", + static_cast(name.length()), name.data()}; /* Open a basic output stream, just to ensure it can work. */ oboe::ManagedStream stream; @@ -220,7 +220,7 @@ struct OboeCapture final : public BackendBase, public oboe::AudioStreamCallback oboe::DataCallbackResult onAudioReady(oboe::AudioStream *oboeStream, void *audioData, int32_t numFrames) override; - void open(const char *name) override; + void open(std::string_view name) override; void start() override; void stop() override; void captureSamples(std::byte *buffer, uint samples) override; @@ -235,13 +235,13 @@ oboe::DataCallbackResult OboeCapture::onAudioReady(oboe::AudioStream*, void *aud } -void OboeCapture::open(const char *name) +void OboeCapture::open(std::string_view name) { - if(!name) + if(name.empty()) name = device_name; - else if(std::strcmp(name, device_name) != 0) - throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found", - name}; + else if(name != device_name) + throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found", + static_cast(name.length()), name.data()}; oboe::AudioStreamBuilder builder; builder.setDirection(oboe::Direction::Input) diff --git a/alc/backends/opensl.cpp b/alc/backends/opensl.cpp index 35c57d77..61e3c9a7 100644 --- a/alc/backends/opensl.cpp +++ b/alc/backends/opensl.cpp @@ -164,7 +164,7 @@ struct OpenSLPlayback final : public BackendBase { int mixerProc(); - void open(const char *name) override; + void open(std::string_view name) override; bool reset() override; void start() override; void stop() override; @@ -312,13 +312,13 @@ int OpenSLPlayback::mixerProc() } -void OpenSLPlayback::open(const char *name) +void OpenSLPlayback::open(std::string_view name) { - if(!name) + if(name.empty()) name = opensl_device; - else if(strcmp(name, opensl_device) != 0) - throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found", - name}; + else if(name != opensl_device) + throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found", + static_cast(name.length()), name.data()}; /* There's only one device, so if it's already open, there's nothing to do. */ if(mEngineObj) return; @@ -645,7 +645,7 @@ struct OpenSLCapture final : public BackendBase { void process(SLAndroidSimpleBufferQueueItf bq) noexcept; - void open(const char *name) override; + void open(std::string_view name) override; void start() override; void stop() override; void captureSamples(std::byte *buffer, uint samples) override; @@ -686,13 +686,13 @@ void OpenSLCapture::process(SLAndroidSimpleBufferQueueItf) noexcept } -void OpenSLCapture::open(const char* name) +void OpenSLCapture::open(std::string_view name) { - if(!name) + if(name.empty()) name = opensl_device; - else if(strcmp(name, opensl_device) != 0) - throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found", - name}; + else if(name != opensl_device) + throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found", + static_cast(name.length()), name.data()}; SLresult result{slCreateEngine(&mEngineObj, 0, nullptr, 0, nullptr, nullptr)}; PrintErr(result, "slCreateEngine"); diff --git a/alc/backends/oss.cpp b/alc/backends/oss.cpp index 554ccc24..87d3ba35 100644 --- a/alc/backends/oss.cpp +++ b/alc/backends/oss.cpp @@ -227,7 +227,7 @@ struct OSSPlayback final : public BackendBase { int mixerProc(); - void open(const char *name) override; + void open(std::string_view name) override; bool reset() override; void start() override; void stop() override; @@ -304,10 +304,10 @@ int OSSPlayback::mixerProc() } -void OSSPlayback::open(const char *name) +void OSSPlayback::open(std::string_view name) { const char *devname{DefaultPlayback.c_str()}; - if(!name) + if(name.empty()) name = DefaultName; else { @@ -320,7 +320,7 @@ void OSSPlayback::open(const char *name) ); if(iter == PlaybackDevices.cend()) throw al::backend_exception{al::backend_error::NoDevice, - "Device name \"%s\" not found", name}; + "Device name \"%.*s\" not found", static_cast(name.length()), name.data()}; devname = iter->device_name.c_str(); } @@ -443,7 +443,7 @@ struct OSScapture final : public BackendBase { int recordProc(); - void open(const char *name) override; + void open(std::string_view name) override; void start() override; void stop() override; void captureSamples(std::byte *buffer, uint samples) override; @@ -512,10 +512,10 @@ int OSScapture::recordProc() } -void OSScapture::open(const char *name) +void OSScapture::open(std::string_view name) { const char *devname{DefaultCapture.c_str()}; - if(!name) + if(name.empty()) name = DefaultName; else { @@ -528,7 +528,7 @@ void OSScapture::open(const char *name) ); if(iter == CaptureDevices.cend()) throw al::backend_exception{al::backend_error::NoDevice, - "Device name \"%s\" not found", name}; + "Device name \"%.*s\" not found", static_cast(name.length()), name.data()}; devname = iter->device_name.c_str(); } diff --git a/alc/backends/pipewire.cpp b/alc/backends/pipewire.cpp index 902d6374..9a63d2f4 100644 --- a/alc/backends/pipewire.cpp +++ b/alc/backends/pipewire.cpp @@ -1325,7 +1325,7 @@ class PipeWirePlayback final : public BackendBase { void ioChangedCallback(uint32_t id, void *area, uint32_t size) noexcept; void outputCallback() noexcept; - void open(const char *name) override; + void open(std::string_view name) override; bool reset() override; void start() override; void stop() override; @@ -1428,14 +1428,14 @@ void PipeWirePlayback::outputCallback() noexcept } -void PipeWirePlayback::open(const char *name) +void PipeWirePlayback::open(std::string_view name) { static std::atomic OpenCount{0}; uint64_t targetid{PwIdAny}; std::string devname{}; gEventHandler.waitForInit(); - if(!name) + if(name.empty()) { EventWatcherLockGuard _{gEventHandler}; auto&& devlist = DeviceNode::GetList(); @@ -1470,7 +1470,7 @@ void PipeWirePlayback::open(const char *name) auto match = std::find_if(devlist.cbegin(), devlist.cend(), match_name); if(match == devlist.cend()) throw al::backend_exception{al::backend_error::NoDevice, - "Device name \"%s\" not found", name}; + "Device name \"%.*s\" not found", static_cast(name.length()), name.data()}; targetid = match->mSerial; devname = match->mName; @@ -1823,7 +1823,7 @@ class PipeWireCapture final : public BackendBase { void stateChangedCallback(pw_stream_state old, pw_stream_state state, const char *error) noexcept; void inputCallback() noexcept; - void open(const char *name) override; + void open(std::string_view name) override; void start() override; void stop() override; void captureSamples(std::byte *buffer, uint samples) override; @@ -1875,14 +1875,14 @@ void PipeWireCapture::inputCallback() noexcept } -void PipeWireCapture::open(const char *name) +void PipeWireCapture::open(std::string_view name) { static std::atomic OpenCount{0}; uint64_t targetid{PwIdAny}; std::string devname{}; gEventHandler.waitForInit(); - if(!name) + if(name.empty()) { EventWatcherLockGuard _{gEventHandler}; auto&& devlist = DeviceNode::GetList(); @@ -1920,16 +1920,17 @@ void PipeWireCapture::open(const char *name) auto match_name = [name](const DeviceNode &n) -> bool { return n.mType != NodeType::Sink && n.mName == name; }; auto match = std::find_if(devlist.cbegin(), devlist.cend(), match_name); - if(match == devlist.cend() && std::strncmp(name, MonitorPrefix, MonitorPrefixLen) == 0) + if(match == devlist.cend() && name.length() >= MonitorPrefixLen + && std::strncmp(name.data(), MonitorPrefix, MonitorPrefixLen) == 0) { - const char *sinkname{name + MonitorPrefixLen}; + const std::string_view sinkname{name.substr(MonitorPrefixLen)}; auto match_sinkname = [sinkname](const DeviceNode &n) -> bool { return n.mType == NodeType::Sink && n.mName == sinkname; }; match = std::find_if(devlist.cbegin(), devlist.cend(), match_sinkname); } if(match == devlist.cend()) throw al::backend_exception{al::backend_error::NoDevice, - "Device name \"%s\" not found", name}; + "Device name \"%.*s\" not found", static_cast(name.length()), name.data()}; targetid = match->mSerial; devname = name; diff --git a/alc/backends/portaudio.cpp b/alc/backends/portaudio.cpp index 2551f448..979a54d6 100644 --- a/alc/backends/portaudio.cpp +++ b/alc/backends/portaudio.cpp @@ -86,7 +86,7 @@ struct PortPlayback final : public BackendBase { framesPerBuffer, timeInfo, statusFlags); } - void open(const char *name) override; + void open(std::string_view name) override; bool reset() override; void start() override; void stop() override; @@ -116,13 +116,13 @@ int PortPlayback::writeCallback(const void*, void *outputBuffer, unsigned long f } -void PortPlayback::open(const char *name) +void PortPlayback::open(std::string_view name) { - if(!name) + if(name.empty()) name = pa_device; - else if(strcmp(name, pa_device) != 0) - throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found", - name}; + else if(name != pa_device) + throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found", + static_cast(name.length()), name.data()}; PaStreamParameters params{}; auto devidopt = ConfigValueInt(nullptr, "port", "device"); @@ -245,7 +245,7 @@ struct PortCapture final : public BackendBase { framesPerBuffer, timeInfo, statusFlags); } - void open(const char *name) override; + void open(std::string_view name) override; void start() override; void stop() override; void captureSamples(std::byte *buffer, uint samples) override; @@ -276,13 +276,13 @@ int PortCapture::readCallback(const void *inputBuffer, void*, unsigned long fram } -void PortCapture::open(const char *name) +void PortCapture::open(std::string_view name) { - if(!name) + if(name.empty()) name = pa_device; - else if(strcmp(name, pa_device) != 0) - throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found", - name}; + else if(name != pa_device) + throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found", + static_cast(name.length()), name.data()}; uint samples{mDevice->BufferSize}; samples = maxu(samples, 100 * mDevice->Frequency / 1000); diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index 8c6cc4d3..e2cea8a8 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -647,7 +647,7 @@ struct PulsePlayback final : public BackendBase { void sinkNameCallback(pa_context *context, const pa_sink_info *info, int eol) noexcept; void streamMovedCallback(pa_stream *stream) noexcept; - void open(const char *name) override; + void open(std::string_view name) override; bool reset() override; void start() override; void stop() override; @@ -782,14 +782,14 @@ void PulsePlayback::streamMovedCallback(pa_stream *stream) noexcept } -void PulsePlayback::open(const char *name) +void PulsePlayback::open(std::string_view name) { mMainloop = PulseMainloop::Create(); mMainloop.start(); const char *pulse_name{nullptr}; const char *dev_name{nullptr}; - if(name) + if(!name.empty()) { if(PlaybackDevices.empty()) mMainloop.probePlaybackDevices(); @@ -798,7 +798,7 @@ void PulsePlayback::open(const char *name) [name](const DevMap &entry) -> bool { return entry.name == name; }); if(iter == PlaybackDevices.cend()) throw al::backend_exception{al::backend_error::NoDevice, - "Device name \"%s\" not found", name}; + "Device name \"%.*s\" not found", static_cast(name.length()), name.data()}; pulse_name = iter->device_name.c_str(); dev_name = iter->name.c_str(); } @@ -1066,7 +1066,7 @@ struct PulseCapture final : public BackendBase { void sourceNameCallback(pa_context *context, const pa_source_info *info, int eol) noexcept; void streamMovedCallback(pa_stream *stream) noexcept; - void open(const char *name) override; + void open(std::string_view name) override; void start() override; void stop() override; void captureSamples(std::byte *buffer, uint samples) override; @@ -1123,7 +1123,7 @@ void PulseCapture::streamMovedCallback(pa_stream *stream) noexcept } -void PulseCapture::open(const char *name) +void PulseCapture::open(std::string_view name) { if(!mMainloop) { @@ -1132,7 +1132,7 @@ void PulseCapture::open(const char *name) } const char *pulse_name{nullptr}; - if(name) + if(!name.empty()) { if(CaptureDevices.empty()) mMainloop.probeCaptureDevices(); @@ -1141,7 +1141,7 @@ void PulseCapture::open(const char *name) [name](const DevMap &entry) -> bool { return entry.name == name; }); if(iter == CaptureDevices.cend()) throw al::backend_exception{al::backend_error::NoDevice, - "Device name \"%s\" not found", name}; + "Device name \"%.*s\" not found", static_cast(name.length()), name.data()}; pulse_name = iter->device_name.c_str(); mDevice->DeviceName = iter->name; } diff --git a/alc/backends/sdl2.cpp b/alc/backends/sdl2.cpp index e1e40e27..f5ed4316 100644 --- a/alc/backends/sdl2.cpp +++ b/alc/backends/sdl2.cpp @@ -54,7 +54,7 @@ struct Sdl2Backend final : public BackendBase { void audioCallback(Uint8 *stream, int len) noexcept; - void open(const char *name) override; + void open(std::string_view name) override; bool reset() override; void start() override; void stop() override; @@ -84,7 +84,7 @@ void Sdl2Backend::audioCallback(Uint8 *stream, int len) noexcept mDevice->renderSamples(stream, ulen / mFrameSize, mDevice->channelsFromFmt()); } -void Sdl2Backend::open(const char *name) +void Sdl2Backend::open(std::string_view name) { SDL_AudioSpec want{}, have{}; @@ -109,16 +109,29 @@ void Sdl2Backend::open(const char *name) * necessarily the first in the list. */ SDL_AudioDeviceID devid; - if(!name || strcmp(name, defaultDeviceName) == 0) + if(name.empty() || name == defaultDeviceName) + { + name = defaultDeviceName; devid = SDL_OpenAudioDevice(nullptr, SDL_FALSE, &want, &have, SDL_AUDIO_ALLOW_ANY_CHANGE); + } else { const size_t prefix_len = strlen(DEVNAME_PREFIX); - if(strncmp(name, DEVNAME_PREFIX, prefix_len) == 0) - devid = SDL_OpenAudioDevice(name+prefix_len, SDL_FALSE, &want, &have, + if(name.length() >= prefix_len && strncmp(name.data(), DEVNAME_PREFIX, prefix_len) == 0) + { + /* Copy the string_view to a string to ensure it's null terminated + * for this call. + */ + const std::string devname{name.substr(prefix_len)}; + devid = SDL_OpenAudioDevice(devname.c_str(), SDL_FALSE, &want, &have, SDL_AUDIO_ALLOW_ANY_CHANGE); + } else - devid = SDL_OpenAudioDevice(name, SDL_FALSE, &want, &have, SDL_AUDIO_ALLOW_ANY_CHANGE); + { + const std::string devname{name}; + devid = SDL_OpenAudioDevice(devname.c_str(), SDL_FALSE, &want, &have, + SDL_AUDIO_ALLOW_ANY_CHANGE); + } } if(!devid) throw al::backend_exception{al::backend_error::NoDevice, "%s", SDL_GetError()}; @@ -160,7 +173,7 @@ void Sdl2Backend::open(const char *name) mFmtType = devtype; mUpdateSize = have.samples; - mDevice->DeviceName = name ? name : defaultDeviceName; + mDevice->DeviceName = name; } bool Sdl2Backend::reset() diff --git a/alc/backends/sndio.cpp b/alc/backends/sndio.cpp index 8daa928c..d54c337b 100644 --- a/alc/backends/sndio.cpp +++ b/alc/backends/sndio.cpp @@ -57,7 +57,7 @@ struct SndioPlayback final : public BackendBase { int mixerProc(); - void open(const char *name) override; + void open(std::string_view name) override; bool reset() override; void start() override; void stop() override; @@ -112,13 +112,13 @@ int SndioPlayback::mixerProc() } -void SndioPlayback::open(const char *name) +void SndioPlayback::open(std::string_view name) { - if(!name) + if(name.empty()) name = sndio_device; - else if(strcmp(name, sndio_device) != 0) - throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found", - name}; + else if(name != sndio_device) + throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found", + static_cast(name.length()), name.data()}; sio_hdl *sndHandle{sio_open(nullptr, SIO_PLAY, 0)}; if(!sndHandle) @@ -280,7 +280,7 @@ struct SndioCapture final : public BackendBase { int recordProc(); - void open(const char *name) override; + void open(std::string_view name) override; void start() override; void stop() override; void captureSamples(std::byte *buffer, uint samples) override; @@ -382,13 +382,13 @@ int SndioCapture::recordProc() } -void SndioCapture::open(const char *name) +void SndioCapture::open(std::string_view name) { - if(!name) + if(name.empty()) name = sndio_device; - else if(strcmp(name, sndio_device) != 0) - throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found", - name}; + else if(name != sndio_device) + throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found", + static_cast(name.length()), name.data()}; mSndHandle = sio_open(nullptr, SIO_REC, true); if(mSndHandle == nullptr) diff --git a/alc/backends/solaris.cpp b/alc/backends/solaris.cpp index 15dcc98f..38f9db19 100644 --- a/alc/backends/solaris.cpp +++ b/alc/backends/solaris.cpp @@ -62,7 +62,7 @@ struct SolarisBackend final : public BackendBase { int mixerProc(); - void open(const char *name) override; + void open(std::string_view name) override; bool reset() override; void start() override; void stop() override; @@ -139,13 +139,13 @@ int SolarisBackend::mixerProc() } -void SolarisBackend::open(const char *name) +void SolarisBackend::open(std::string_view name) { - if(!name) + if(name.empty()) name = solaris_device; - else if(strcmp(name, solaris_device) != 0) - throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found", - name}; + else if(name != solaris_device) + throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found", + static_cast(name.length()), name.data()}; int fd{::open(solaris_driver.c_str(), O_WRONLY)}; if(fd == -1) diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index dccbeba2..96c56fa8 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -868,7 +868,7 @@ constexpr char MessageStr[static_cast(MsgType::Count)][16]{ struct WasapiProxy { virtual ~WasapiProxy() = default; - virtual HRESULT openProxy(const char *name) = 0; + virtual HRESULT openProxy(std::string_view name) = 0; virtual void closeProxy() = 0; virtual HRESULT resetProxy() = 0; @@ -878,7 +878,7 @@ struct WasapiProxy { struct Msg { MsgType mType; WasapiProxy *mProxy; - const char *mParam; + std::string_view mParam; std::promise mPromise; explicit operator bool() const noexcept { return mType != MsgType::QuitThread; } @@ -889,7 +889,7 @@ struct WasapiProxy { static std::optional sDeviceHelper; - std::future pushMessage(MsgType type, const char *param=nullptr) + std::future pushMessage(MsgType type, std::string_view param={}) { std::promise promise; std::future future{promise.get_future()}; @@ -907,7 +907,7 @@ struct WasapiProxy { std::future future{promise.get_future()}; { std::lock_guard _{mMsgQueueLock}; - mMsgQueue.emplace_back(Msg{type, nullptr, nullptr, std::move(promise)}); + mMsgQueue.emplace_back(Msg{type, nullptr, {}, std::move(promise)}); } mMsgQueueCond.notify_one(); return future; @@ -958,9 +958,10 @@ int WasapiProxy::messageHandler(std::promise *promise) TRACE("Starting message loop\n"); while(Msg msg{popMessage()}) { - TRACE("Got message \"%s\" (0x%04x, this=%p, param=%p)\n", + TRACE("Got message \"%s\" (0x%04x, this=%p, param={%p,%zu})\n", MessageStr[static_cast(msg.mType)], static_cast(msg.mType), - static_cast(msg.mProxy), static_cast(msg.mParam)); + static_cast(msg.mProxy), static_cast(msg.mParam.data()), + msg.mParam.length()); switch(msg.mType) { @@ -1010,8 +1011,8 @@ struct WasapiPlayback final : public BackendBase, WasapiProxy { int mixerProc(); - void open(const char *name) override; - HRESULT openProxy(const char *name) override; + void open(std::string_view name) override; + HRESULT openProxy(std::string_view name) override; void closeProxy() override; bool reset() override; @@ -1147,7 +1148,7 @@ FORCE_ALIGN int WasapiPlayback::mixerProc() } -void WasapiPlayback::open(const char *name) +void WasapiPlayback::open(std::string_view name) { if(SUCCEEDED(mOpenStatus)) throw al::backend_exception{al::backend_error::DeviceError, @@ -1161,11 +1162,10 @@ void WasapiPlayback::open(const char *name) "Failed to create notify events"}; } - if(name && std::strncmp(name, DevNameHead, DevNameHeadLen) == 0) + if(name.length() >= DevNameHeadLen + && std::strncmp(name.data(), DevNameHead, DevNameHeadLen) == 0) { - name += DevNameHeadLen; - if(*name == '\0') - name = nullptr; + name = name.substr(DevNameHeadLen); } mOpenStatus = pushMessage(MsgType::OpenDevice, name).get(); @@ -1174,11 +1174,11 @@ void WasapiPlayback::open(const char *name) mOpenStatus}; } -HRESULT WasapiPlayback::openProxy(const char *name) +HRESULT WasapiPlayback::openProxy(std::string_view name) { std::string devname; std::wstring devid; - if(name) + if(!name.empty()) { auto devlock = DeviceListLock{gDeviceList}; auto list = al::span{devlock.getPlaybackList()}; @@ -1194,7 +1194,8 @@ HRESULT WasapiPlayback::openProxy(const char *name) } if(iter == list.cend()) { - WARN("Failed to find device name matching \"%s\"\n", name); + WARN("Failed to find device name matching \"%.*s\"\n", static_cast(name.length()), + name.data()); return E_FAIL; } devname = iter->name; @@ -1654,8 +1655,8 @@ struct WasapiCapture final : public BackendBase, WasapiProxy { int recordProc(); - void open(const char *name) override; - HRESULT openProxy(const char *name) override; + void open(std::string_view name) override; + HRESULT openProxy(std::string_view name) override; void closeProxy() override; HRESULT resetProxy() override; @@ -1787,7 +1788,7 @@ FORCE_ALIGN int WasapiCapture::recordProc() } -void WasapiCapture::open(const char *name) +void WasapiCapture::open(std::string_view name) { if(SUCCEEDED(mOpenStatus)) throw al::backend_exception{al::backend_error::DeviceError, @@ -1801,11 +1802,10 @@ void WasapiCapture::open(const char *name) "Failed to create notify events"}; } - if(name && std::strncmp(name, DevNameHead, DevNameHeadLen) == 0) + if(name.length() >= DevNameHeadLen + && std::strncmp(name.data(), DevNameHead, DevNameHeadLen) == 0) { - name += DevNameHeadLen; - if(*name == '\0') - name = nullptr; + name = name.substr(DevNameHeadLen); } mOpenStatus = pushMessage(MsgType::OpenDevice, name).get(); @@ -1822,11 +1822,11 @@ void WasapiCapture::open(const char *name) } } -HRESULT WasapiCapture::openProxy(const char *name) +HRESULT WasapiCapture::openProxy(std::string_view name) { std::string devname; std::wstring devid; - if(name) + if(!name.empty()) { auto devlock = DeviceListLock{gDeviceList}; auto devlist = al::span{devlock.getCaptureList()}; @@ -1842,7 +1842,8 @@ HRESULT WasapiCapture::openProxy(const char *name) } if(iter == devlist.cend()) { - WARN("Failed to find device name matching \"%s\"\n", name); + WARN("Failed to find device name matching \"%.*s\"\n", static_cast(name.length()), + name.data()); return E_FAIL; } devname = iter->name; diff --git a/alc/backends/wave.cpp b/alc/backends/wave.cpp index 40592ee7..1078c654 100644 --- a/alc/backends/wave.cpp +++ b/alc/backends/wave.cpp @@ -96,7 +96,7 @@ struct WaveBackend final : public BackendBase { int mixerProc(); - void open(const char *name) override; + void open(std::string_view name) override; bool reset() override; void start() override; void stop() override; @@ -194,24 +194,24 @@ int WaveBackend::mixerProc() return 0; } -void WaveBackend::open(const char *name) +void WaveBackend::open(std::string_view name) { auto fname = ConfigValueStr(nullptr, "wave", "file"); if(!fname) throw al::backend_exception{al::backend_error::NoDevice, "No wave output filename"}; - if(!name) + if(name.empty()) name = waveDevice; - else if(strcmp(name, waveDevice) != 0) - throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found", - name}; + else if(name != waveDevice) + throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found", + static_cast(name.length()), name.data()}; /* There's only one "device", so if it's already open, we're done. */ if(mFile) return; #ifdef _WIN32 { - std::wstring wname{utf8_to_wstr(fname->c_str())}; + std::wstring wname{utf8_to_wstr(fname.value())}; mFile = _wfopen(wname.c_str(), L"wb"); } #else diff --git a/alc/backends/winmm.cpp b/alc/backends/winmm.cpp index c22f1c4d..f0fb0a1c 100644 --- a/alc/backends/winmm.cpp +++ b/alc/backends/winmm.cpp @@ -135,7 +135,7 @@ struct WinMMPlayback final : public BackendBase { int mixerProc(); - void open(const char *name) override; + void open(std::string_view name) override; bool reset() override; void start() override; void stop() override; @@ -208,18 +208,18 @@ FORCE_ALIGN int WinMMPlayback::mixerProc() } -void WinMMPlayback::open(const char *name) +void WinMMPlayback::open(std::string_view name) { if(PlaybackDevices.empty()) ProbePlaybackDevices(); // Find the Device ID matching the deviceName if valid - auto iter = name ? + auto iter = !name.empty() ? std::find(PlaybackDevices.cbegin(), PlaybackDevices.cend(), name) : PlaybackDevices.cbegin(); if(iter == PlaybackDevices.cend()) - throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found", - name}; + throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found", + static_cast(name.length()), name.data()}; auto DeviceID = static_cast(std::distance(PlaybackDevices.cbegin(), iter)); DevFmtType fmttype{mDevice->FmtType}; @@ -370,7 +370,7 @@ struct WinMMCapture final : public BackendBase { int captureProc(); - void open(const char *name) override; + void open(std::string_view name) override; void start() override; void stop() override; void captureSamples(std::byte *buffer, uint samples) override; @@ -446,18 +446,18 @@ int WinMMCapture::captureProc() } -void WinMMCapture::open(const char *name) +void WinMMCapture::open(std::string_view name) { if(CaptureDevices.empty()) ProbeCaptureDevices(); // Find the Device ID matching the deviceName if valid - auto iter = name ? + auto iter = !name.empty() ? std::find(CaptureDevices.cbegin(), CaptureDevices.cend(), name) : CaptureDevices.cbegin(); if(iter == CaptureDevices.cend()) - throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found", - name}; + throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found", + static_cast(name.length()), name.data()}; auto DeviceID = static_cast(std::distance(CaptureDevices.cbegin(), iter)); switch(mDevice->FmtChans) diff --git a/common/strutils.cpp b/common/strutils.cpp index 355cd030..f7868e2e 100644 --- a/common/strutils.cpp +++ b/common/strutils.cpp @@ -10,31 +10,32 @@ #define WIN32_LEAN_AND_MEAN #include -std::string wstr_to_utf8(const WCHAR *wstr) +std::string wstr_to_utf8(std::wstring_view wstr) { std::string ret; - int len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr); + int len{WideCharToMultiByte(CP_UTF8, 0, wstr.data(), static_cast(wstr.length()), nullptr, + 0, nullptr, nullptr)}; if(len > 0) { ret.resize(len); - WideCharToMultiByte(CP_UTF8, 0, wstr, -1, &ret[0], len, nullptr, nullptr); - ret.pop_back(); + WideCharToMultiByte(CP_UTF8, 0, wstr.data(), static_cast(wstr.length()), &ret[0], len, + nullptr, nullptr); } return ret; } -std::wstring utf8_to_wstr(const char *str) +std::wstring utf8_to_wstr(std::string_view str) { std::wstring ret; - int len = MultiByteToWideChar(CP_UTF8, 0, str, -1, nullptr, 0); + int len{MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast(str.length()), nullptr, + 0)}; if(len > 0) { ret.resize(len); - MultiByteToWideChar(CP_UTF8, 0, str, -1, &ret[0], len); - ret.pop_back(); + MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast(str.length()), &ret[0], len); } return ret; diff --git a/common/strutils.h b/common/strutils.h index 67f057a7..7eee0c1d 100644 --- a/common/strutils.h +++ b/common/strutils.h @@ -5,10 +5,11 @@ #include #ifdef _WIN32 +#include #include -std::string wstr_to_utf8(const wchar_t *wstr); -std::wstring utf8_to_wstr(const char *str); +std::string wstr_to_utf8(std::wstring_view wstr); +std::wstring utf8_to_wstr(std::string_view str); #endif namespace al { -- cgit v1.2.3 From 5ae60a58ead6b9eda23cbaf953dec90292031aa7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 11 Aug 2023 08:08:44 -0700 Subject: Track the current/active format for pipewire nodes --- alc/backends/pipewire.cpp | 140 ++++++++++++++++++++++++++++------------------ 1 file changed, 85 insertions(+), 55 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/pipewire.cpp b/alc/backends/pipewire.cpp index 9a63d2f4..dbca20d9 100644 --- a/alc/backends/pipewire.cpp +++ b/alc/backends/pipewire.cpp @@ -461,10 +461,10 @@ struct NodeProxy { static constexpr pw_node_events nodeEvents{CreateNodeEvents()}; ppw_node_add_listener(mNode.get(), &mListener, &nodeEvents, this); - /* Track changes to the enumerable formats (indicates the default - * format, which is what we're interested in). + /* Track changes to the enumerable and current formats (indicates the + * default and active format, which is what we're interested in). */ - uint32_t fmtids[]{SPA_PARAM_EnumFormat}; + uint32_t fmtids[]{SPA_PARAM_EnumFormat, SPA_PARAM_Format}; ppw_node_subscribe_params(mNode.get(), std::data(fmtids), std::size(fmtids)); } ~NodeProxy() @@ -643,9 +643,9 @@ struct DeviceNode { static void Remove(uint32_t id); static auto GetList() noexcept { return al::span{sList}; } - void parseSampleRate(const spa_pod *value) noexcept; - void parsePositions(const spa_pod *value) noexcept; - void parseChannelCount(const spa_pod *value) noexcept; + void parseSampleRate(const spa_pod *value, bool force_update) noexcept; + void parsePositions(const spa_pod *value, bool force_update) noexcept; + void parseChannelCount(const spa_pod *value, bool force_update) noexcept; void callEvent(alc::EventType type, std::string_view message) { @@ -769,7 +769,7 @@ bool MatchChannelMap(const al::span map0, const spa_audio_channe return true; } -void DeviceNode::parseSampleRate(const spa_pod *value) noexcept +void DeviceNode::parseSampleRate(const spa_pod *value, bool force_update) noexcept { /* TODO: Can this be anything else? Long, Float, Double? */ uint32_t nvals{}, choiceType{}; @@ -778,7 +778,7 @@ void DeviceNode::parseSampleRate(const spa_pod *value) noexcept const uint podType{get_pod_type(value)}; if(podType != SPA_TYPE_Int) { - WARN("Unhandled sample rate POD type: %u\n", podType); + WARN(" Unhandled sample rate POD type: %u\n", podType); return; } @@ -786,15 +786,15 @@ void DeviceNode::parseSampleRate(const spa_pod *value) noexcept { if(nvals != 3) { - WARN("Unexpected SPA_CHOICE_Range count: %u\n", nvals); + WARN(" Unexpected SPA_CHOICE_Range count: %u\n", nvals); return; } auto srates = get_pod_body(value); /* [0] is the default, [1] is the min, and [2] is the max. */ - TRACE("Device ID %" PRIu64 " sample rate: %d (range: %d -> %d)\n", mSerial, srates[0], - srates[1], srates[2]); - mSampleRate = static_cast(clampi(srates[0], MIN_OUTPUT_RATE, MAX_OUTPUT_RATE)); + TRACE(" sample rate: %d (range: %d -> %d)\n", srates[0], srates[1], srates[2]); + if(!mSampleRate || force_update) + mSampleRate = static_cast(clampi(srates[0], MIN_OUTPUT_RATE, MAX_OUTPUT_RATE)); return; } @@ -802,7 +802,7 @@ void DeviceNode::parseSampleRate(const spa_pod *value) noexcept { if(nvals == 0) { - WARN("Unexpected SPA_CHOICE_Enum count: %u\n", nvals); + WARN(" Unexpected SPA_CHOICE_Enum count: %u\n", nvals); return; } auto srates = get_pod_body(value, nvals); @@ -814,7 +814,7 @@ void DeviceNode::parseSampleRate(const spa_pod *value) noexcept others += ", "; others += std::to_string(srates[i]); } - TRACE("Device ID %" PRIu64 " sample rate: %d (%s)\n", mSerial, srates[0], others.c_str()); + TRACE(" sample rate: %d (%s)\n", srates[0], others.c_str()); /* Pick the first rate listed that's within the allowed range (default * rate if possible). */ @@ -822,7 +822,8 @@ void DeviceNode::parseSampleRate(const spa_pod *value) noexcept { if(rate >= MIN_OUTPUT_RATE && rate <= MAX_OUTPUT_RATE) { - mSampleRate = static_cast(rate); + if(!mSampleRate || force_update) + mSampleRate = static_cast(rate); break; } } @@ -833,63 +834,88 @@ void DeviceNode::parseSampleRate(const spa_pod *value) noexcept { if(nvals != 1) { - WARN("Unexpected SPA_CHOICE_None count: %u\n", nvals); + WARN(" Unexpected SPA_CHOICE_None count: %u\n", nvals); return; } auto srates = get_pod_body(value); - TRACE("Device ID %" PRIu64 " sample rate: %d\n", mSerial, srates[0]); - mSampleRate = static_cast(clampi(srates[0], MIN_OUTPUT_RATE, MAX_OUTPUT_RATE)); + TRACE(" sample rate: %d\n", srates[0]); + if(!mSampleRate || force_update) + mSampleRate = static_cast(clampi(srates[0], MIN_OUTPUT_RATE, MAX_OUTPUT_RATE)); return; } - WARN("Unhandled sample rate choice type: %u\n", choiceType); + WARN(" Unhandled sample rate choice type: %u\n", choiceType); } -void DeviceNode::parsePositions(const spa_pod *value) noexcept +void DeviceNode::parsePositions(const spa_pod *value, bool force_update) noexcept { + uint32_t choiceCount{}, choiceType{}; + value = spa_pod_get_values(value, &choiceCount, &choiceType); + + if(choiceType != SPA_CHOICE_None || choiceCount != 1) + { + ERR(" Unexpected positions choice: type=%u, count=%u\n", choiceType, choiceCount); + return; + } + const auto chanmap = get_array_span(value); if(chanmap.empty()) return; - mIs51Rear = false; - - if(MatchChannelMap(chanmap, X714Map)) - mChannels = DevFmtX714; - else if(MatchChannelMap(chanmap, X71Map)) - mChannels = DevFmtX71; - else if(MatchChannelMap(chanmap, X61Map)) - mChannels = DevFmtX61; - else if(MatchChannelMap(chanmap, X51Map)) - mChannels = DevFmtX51; - else if(MatchChannelMap(chanmap, X51RearMap)) - { - mChannels = DevFmtX51; - mIs51Rear = true; - } - else if(MatchChannelMap(chanmap, QuadMap)) - mChannels = DevFmtQuad; - else if(MatchChannelMap(chanmap, StereoMap)) - mChannels = DevFmtStereo; - else - mChannels = DevFmtMono; - TRACE("Device ID %" PRIu64 " got %zu position%s for %s%s\n", mSerial, chanmap.size(), - (chanmap.size()==1)?"":"s", DevFmtChannelsString(mChannels), mIs51Rear?"(rear)":""); + if(mChannels == InvalidChannelConfig || force_update) + { + mIs51Rear = false; + + if(MatchChannelMap(chanmap, X714Map)) + mChannels = DevFmtX714; + else if(MatchChannelMap(chanmap, X71Map)) + mChannels = DevFmtX71; + else if(MatchChannelMap(chanmap, X61Map)) + mChannels = DevFmtX61; + else if(MatchChannelMap(chanmap, X51Map)) + mChannels = DevFmtX51; + else if(MatchChannelMap(chanmap, X51RearMap)) + { + mChannels = DevFmtX51; + mIs51Rear = true; + } + else if(MatchChannelMap(chanmap, QuadMap)) + mChannels = DevFmtQuad; + else if(MatchChannelMap(chanmap, StereoMap)) + mChannels = DevFmtStereo; + else + mChannels = DevFmtMono; + } + TRACE(" %zu position%s for %s%s\n", chanmap.size(), (chanmap.size()==1)?"":"s", + DevFmtChannelsString(mChannels), mIs51Rear?"(rear)":""); } -void DeviceNode::parseChannelCount(const spa_pod *value) noexcept +void DeviceNode::parseChannelCount(const spa_pod *value, bool force_update) noexcept { /* As a fallback with just a channel count, just assume mono or stereo. */ + uint32_t choiceCount{}, choiceType{}; + value = spa_pod_get_values(value, &choiceCount, &choiceType); + + if(choiceType != SPA_CHOICE_None || choiceCount != 1) + { + ERR(" Unexpected positions choice: type=%u, count=%u\n", choiceType, choiceCount); + return; + } + const auto chancount = get_value(value); if(!chancount) return; - mIs51Rear = false; + if(mChannels == InvalidChannelConfig || force_update) + { + mIs51Rear = false; - if(*chancount >= 2) - mChannels = DevFmtStereo; - else if(*chancount >= 1) - mChannels = DevFmtMono; - TRACE("Device ID %" PRIu64 " got %d channel%s for %s\n", mSerial, *chancount, - (*chancount==1)?"":"s", DevFmtChannelsString(mChannels)); + if(*chancount >= 2) + mChannels = DevFmtStereo; + else if(*chancount >= 1) + mChannels = DevFmtMono; + } + TRACE(" %d channel%s for %s\n", *chancount, (*chancount==1)?"":"s", + DevFmtChannelsString(mChannels)); } @@ -992,18 +1018,22 @@ void NodeProxy::infoCallback(const pw_node_info *info) noexcept void NodeProxy::paramCallback(int, uint32_t id, uint32_t, uint32_t, const spa_pod *param) noexcept { - if(id == SPA_PARAM_EnumFormat) + if(id == SPA_PARAM_EnumFormat || id == SPA_PARAM_Format) { DeviceNode *node{DeviceNode::Find(mId)}; if(!node) UNLIKELY return; + TRACE("Device ID %" PRIu64 " %s format:\n", node->mSerial, + (id == SPA_PARAM_EnumFormat) ? "enumerable" : "current"); + + const bool force_update{id == SPA_PARAM_Format}; if(const spa_pod_prop *prop{spa_pod_find_prop(param, nullptr, SPA_FORMAT_AUDIO_rate)}) - node->parseSampleRate(&prop->value); + node->parseSampleRate(&prop->value, force_update); if(const spa_pod_prop *prop{spa_pod_find_prop(param, nullptr, SPA_FORMAT_AUDIO_position)}) - node->parsePositions(&prop->value); + node->parsePositions(&prop->value, force_update); else if((prop=spa_pod_find_prop(param, nullptr, SPA_FORMAT_AUDIO_channels)) != nullptr) - node->parseChannelCount(&prop->value); + node->parseChannelCount(&prop->value, force_update); } } -- cgit v1.2.3 From eaad1b353611d589653f3b7ea2d671f3a59a42b0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 21 Aug 2023 02:43:34 -0700 Subject: Clear errno prior to the call that may set it --- alc/backends/pipewire.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'alc/backends') diff --git a/alc/backends/pipewire.cpp b/alc/backends/pipewire.cpp index dbca20d9..ede4399b 100644 --- a/alc/backends/pipewire.cpp +++ b/alc/backends/pipewire.cpp @@ -965,6 +965,7 @@ void NodeProxy::infoCallback(const pw_node_info *info) noexcept #ifdef PW_KEY_OBJECT_SERIAL if(const char *serial_str{spa_dict_lookup(info->props, PW_KEY_OBJECT_SERIAL)}) { + errno = 0; char *serial_end{}; serial_id = std::strtoull(serial_str, &serial_end, 0); if(*serial_end != '\0' || errno == ERANGE) -- cgit v1.2.3 From c53ee243ec5af8392a15d4e315b36dec4b5f41cf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 30 Aug 2023 23:45:15 -0700 Subject: Combine separate loops into one --- alc/backends/pipewire.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/pipewire.cpp b/alc/backends/pipewire.cpp index ede4399b..6a39df72 100644 --- a/alc/backends/pipewire.cpp +++ b/alc/backends/pipewire.cpp @@ -1444,16 +1444,14 @@ void PipeWirePlayback::outputCallback() noexcept length = minu(length, data.maxsize/sizeof(float)); *chanptr_end = static_cast(data.data); ++chanptr_end; - } - - mDevice->renderSamples({mChannelPtrs.get(), chanptr_end}, length); - for(const auto &data : datas) - { data.chunk->offset = 0; data.chunk->stride = sizeof(float); data.chunk->size = length * sizeof(float); } + + mDevice->renderSamples({mChannelPtrs.get(), chanptr_end}, length); + pw_buf->size = length; pw_stream_queue_buffer(mStream.get(), pw_buf); } @@ -1745,7 +1743,10 @@ void PipeWirePlayback::start() } #endif if(!--wait_count) + { + ERR("Timeout getting PipeWire stream buffering info\n"); break; + } plock.unlock(); std::this_thread::sleep_for(milliseconds{20}); -- cgit v1.2.3 From d2d6365b3f965922f6c25198bcd9de30ccf9f6bb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 31 Aug 2023 04:25:03 -0700 Subject: Handle a null string in DeviceHelper::OnDefaultDeviceChanged --- alc/backends/wasapi.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 96c56fa8..c9ea7980 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -526,18 +526,18 @@ struct DeviceHelper final : private IMMNotificationClient if(role != eMultimedia) return S_OK; + const std::wstring_view devid{pwstrDefaultDeviceId ? pwstrDefaultDeviceId + : std::wstring_view{}}; if(flow == eRender) { - DeviceListLock{gDeviceList}.setPlaybackDefaultId(pwstrDefaultDeviceId); - const std::string msg{"Default playback device changed: "+ - wstr_to_utf8(pwstrDefaultDeviceId)}; + DeviceListLock{gDeviceList}.setPlaybackDefaultId(devid); + const std::string msg{"Default playback device changed: " + wstr_to_utf8(devid)}; alc::Event(alc::EventType::DefaultDeviceChanged, alc::DeviceType::Playback, msg); } else if(flow == eCapture) { - DeviceListLock{gDeviceList}.setCaptureDefaultId(pwstrDefaultDeviceId); - const std::string msg{"Default capture device changed: "+ - wstr_to_utf8(pwstrDefaultDeviceId)}; + DeviceListLock{gDeviceList}.setCaptureDefaultId(devid); + const std::string msg{"Default capture device changed: " + wstr_to_utf8(devid)}; alc::Event(alc::EventType::DefaultDeviceChanged, alc::DeviceType::Capture, msg); } return S_OK; -- cgit v1.2.3 From 7d895a9b8b847df55e2a97a216ac7d04d757d1c8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Sep 2023 07:53:23 -0700 Subject: Avoid putting strings in fixed arrays of char arrays --- alc/backends/wasapi.cpp | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index c9ea7980..0dda4d66 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -851,17 +851,22 @@ enum class MsgType { StopDevice, CloseDevice, - Count, - QuitThread = Count + QuitThread }; -constexpr char MessageStr[static_cast(MsgType::Count)][16]{ - "Open Device", - "Reset Device", - "Start Device", - "Stop Device", - "Close Device", -}; +constexpr const char *GetMessageTypeName(MsgType type) noexcept +{ + switch(type) + { + case MsgType::OpenDevice: return "Open Device"; + case MsgType::ResetDevice: return "Reset Device"; + case MsgType::StartDevice: return "Start Device"; + case MsgType::StopDevice: return "Stop Device"; + case MsgType::CloseDevice: return "Close Device"; + case MsgType::QuitThread: break; + } + return ""; +} /* Proxy interface used by the message handler. */ @@ -883,11 +888,11 @@ struct WasapiProxy { explicit operator bool() const noexcept { return mType != MsgType::QuitThread; } }; - static std::deque mMsgQueue; - static std::mutex mMsgQueueLock; - static std::condition_variable mMsgQueueCond; + static inline std::deque mMsgQueue; + static inline std::mutex mMsgQueueLock; + static inline std::condition_variable mMsgQueueCond; - static std::optional sDeviceHelper; + static inline std::optional sDeviceHelper; std::future pushMessage(MsgType type, std::string_view param={}) { @@ -924,10 +929,6 @@ struct WasapiProxy { static int messageHandler(std::promise *promise); }; -std::deque WasapiProxy::mMsgQueue; -std::mutex WasapiProxy::mMsgQueueLock; -std::condition_variable WasapiProxy::mMsgQueueCond; -std::optional WasapiProxy::sDeviceHelper; int WasapiProxy::messageHandler(std::promise *promise) { @@ -958,10 +959,10 @@ int WasapiProxy::messageHandler(std::promise *promise) TRACE("Starting message loop\n"); while(Msg msg{popMessage()}) { - TRACE("Got message \"%s\" (0x%04x, this=%p, param={%p,%zu})\n", - MessageStr[static_cast(msg.mType)], static_cast(msg.mType), - static_cast(msg.mProxy), static_cast(msg.mParam.data()), - msg.mParam.length()); + TRACE("Got message \"%s\" (0x%04x, this=%p, param=\"%.*s\")\n", + GetMessageTypeName(msg.mType), static_cast(msg.mType), + static_cast(msg.mProxy), static_cast(msg.mParam.length()), + msg.mParam.data()); switch(msg.mType) { -- cgit v1.2.3 From 73cad63efd4f34937a7b00a7df18f004eeb832a6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 3 Sep 2023 10:53:08 -0700 Subject: Don't use a custom config for the pipewire event loop --- alc/backends/pipewire.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'alc/backends') diff --git a/alc/backends/pipewire.cpp b/alc/backends/pipewire.cpp index 6a39df72..1c4e2cc4 100644 --- a/alc/backends/pipewire.cpp +++ b/alc/backends/pipewire.cpp @@ -1146,7 +1146,7 @@ bool EventManager::init() return false; } - mContext = mLoop.newContext(pw_properties_new(PW_KEY_CONFIG_NAME, "client-rt.conf", nullptr)); + mContext = mLoop.newContext(); if(!mContext) { ERR("Failed to create PipeWire event context (errno: %d)\n", errno); -- cgit v1.2.3 From 0eeb3c29f412dd38666dc57e9bc117e3e1073d78 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 20 Sep 2023 19:48:04 -0700 Subject: Preliminary implementation of WASAPI spatial audio playback --- alc/backends/wasapi.cpp | 699 +++++++++++++++++++++++++++++++++++++----------- alsoftrc.sample | 6 + core/device.h | 5 + 3 files changed, 549 insertions(+), 161 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 0dda4d66..4129ac9d 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -31,7 +31,9 @@ #include #include +#include #include +#include #include #include #include @@ -106,6 +108,9 @@ using ReferenceTime = std::chrono::duration(n)}; } +constexpr AudioObjectType operator|(AudioObjectType lhs, AudioObjectType rhs) noexcept +{ return static_cast(lhs | al::to_underlying(rhs)); } + #define MONO SPEAKER_FRONT_CENTER #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT) @@ -134,10 +139,40 @@ constexpr DWORD X61Mask{MaskFromTopBits(X6DOT1)}; constexpr DWORD X71Mask{MaskFromTopBits(X7DOT1)}; constexpr DWORD X714Mask{MaskFromTopBits(X7DOT1DOT4)}; +constexpr AudioObjectType ChannelMask_Mono{AudioObjectType_FrontCenter}; +constexpr AudioObjectType ChannelMask_Stereo{AudioObjectType_FrontLeft + | AudioObjectType_FrontRight}; +constexpr AudioObjectType ChannelMask_Quad{AudioObjectType_FrontLeft | AudioObjectType_FrontRight + | AudioObjectType_BackLeft | AudioObjectType_BackRight}; +constexpr AudioObjectType ChannelMask_X51{AudioObjectType_FrontLeft | AudioObjectType_FrontRight + | AudioObjectType_FrontCenter | AudioObjectType_LowFrequency | AudioObjectType_SideLeft + | AudioObjectType_SideRight}; +constexpr AudioObjectType ChannelMask_X51Rear{AudioObjectType_FrontLeft + | AudioObjectType_FrontRight | AudioObjectType_FrontCenter | AudioObjectType_LowFrequency + | AudioObjectType_BackLeft | AudioObjectType_BackRight}; +constexpr AudioObjectType ChannelMask_X61{AudioObjectType_FrontLeft | AudioObjectType_FrontRight + | AudioObjectType_FrontCenter | AudioObjectType_LowFrequency | AudioObjectType_SideLeft + | AudioObjectType_SideRight | AudioObjectType_BackCenter}; +constexpr AudioObjectType ChannelMask_X71{AudioObjectType_FrontLeft | AudioObjectType_FrontRight + | AudioObjectType_FrontCenter | AudioObjectType_LowFrequency | AudioObjectType_SideLeft + | AudioObjectType_SideRight | AudioObjectType_BackLeft | AudioObjectType_BackRight}; +constexpr AudioObjectType ChannelMask_X714{AudioObjectType_FrontLeft | AudioObjectType_FrontRight + | AudioObjectType_FrontCenter | AudioObjectType_LowFrequency | AudioObjectType_SideLeft + | AudioObjectType_SideRight | AudioObjectType_BackLeft | AudioObjectType_BackRight + | AudioObjectType_TopFrontLeft | AudioObjectType_TopFrontRight | AudioObjectType_TopBackLeft + | AudioObjectType_TopBackRight}; + constexpr char DevNameHead[] = "OpenAL Soft on "; constexpr size_t DevNameHeadLen{std::size(DevNameHead) - 1}; +template +struct overloaded : Ts... { using Ts::operator()...; }; + +template +overloaded(Ts...) -> overloaded; + + /* Scales the given reftime value, rounding the result. */ inline uint RefTime2Samples(const ReferenceTime &val, uint srate) { @@ -1011,6 +1046,7 @@ struct WasapiPlayback final : public BackendBase, WasapiProxy { ~WasapiPlayback() override; int mixerProc(); + int mixerSpatialProc(); void open(std::string_view name) override; HRESULT openProxy(std::string_view name) override; @@ -1025,10 +1061,22 @@ struct WasapiPlayback final : public BackendBase, WasapiProxy { ClockLatency getClockLatency() override; + void prepareFormat(WAVEFORMATEXTENSIBLE &OutputType); + void finalizeFormat(WAVEFORMATEXTENSIBLE &OutputType); + HRESULT mOpenStatus{E_FAIL}; DeviceHandle mMMDev{nullptr}; - ComPtr mClient{nullptr}; - ComPtr mRender{nullptr}; + + struct PlainDevice { + ComPtr mClient{nullptr}; + ComPtr mRender{nullptr}; + }; + struct SpatialDevice { + ComPtr mClient{nullptr}; + ComPtr mRender{nullptr}; + AudioObjectType mStaticMask{}; + }; + std::variant mAudio; HANDLE mNotifyEvent{nullptr}; UINT32 mOrigBufferSize{}, mOrigUpdateSize{}; @@ -1069,6 +1117,8 @@ FORCE_ALIGN int WasapiPlayback::mixerProc() return 1; } + auto &audio = std::get(mAudio); + SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); @@ -1078,7 +1128,7 @@ FORCE_ALIGN int WasapiPlayback::mixerProc() while(!mKillNow.load(std::memory_order_relaxed)) { UINT32 written; - hr = mClient->GetCurrentPadding(&written); + hr = audio.mClient->GetCurrentPadding(&written); if(FAILED(hr)) { ERR("Failed to get padding: 0x%08lx\n", hr); @@ -1097,7 +1147,7 @@ FORCE_ALIGN int WasapiPlayback::mixerProc() } BYTE *buffer; - hr = mRender->GetBuffer(len, &buffer); + hr = audio.mRender->GetBuffer(len, &buffer); if(SUCCEEDED(hr)) { if(mResampler) @@ -1133,7 +1183,7 @@ FORCE_ALIGN int WasapiPlayback::mixerProc() mDevice->renderSamples(buffer, len, mFormat.Format.nChannels); mPadding.store(written + len, std::memory_order_relaxed); } - hr = mRender->ReleaseBuffer(len, 0); + hr = audio.mRender->ReleaseBuffer(len, 0); } if(FAILED(hr)) { @@ -1148,6 +1198,90 @@ FORCE_ALIGN int WasapiPlayback::mixerProc() return 0; } +FORCE_ALIGN int WasapiPlayback::mixerSpatialProc() +{ + HRESULT hr{CoInitializeEx(nullptr, COINIT_MULTITHREADED)}; + if(FAILED(hr)) + { + ERR("CoInitializeEx(nullptr, COINIT_MULTITHREADED) failed: 0x%08lx\n", hr); + mDevice->handleDisconnect("COM init failed: 0x%08lx", hr); + return 1; + } + + auto &audio = std::get(mAudio); + + SetRTPriority(); + althrd_setname(MIXER_THREAD_NAME); + + std::vector> channels; + std::vector buffers; + + /* TODO: Set mPadding appropriately. There doesn't seem to be a way to + * update it dynamically based on the stream, so it may need to be set to a + * fixed size. + */ + + while(!mKillNow.load(std::memory_order_relaxed)) + { + if(DWORD res{WaitForSingleObjectEx(mNotifyEvent, 1000, FALSE)}; res != WAIT_OBJECT_0) + { + ERR("WaitForSingleObjectEx error: 0x%lx\n", res); + + hr = audio.mRender->Reset(); + if(FAILED(hr)) + { + ERR("ISpatialAudioObjectRenderStream::Reset failed: 0x%08lx\n", hr); + mDevice->handleDisconnect("Device lost: 0x%08lx", hr); + break; + } + } + + UINT32 dynamicCount{}, framesToDo{}; + hr = audio.mRender->BeginUpdatingAudioObjects(&dynamicCount, &framesToDo); + if(SUCCEEDED(hr)) + { + if(channels.empty()) UNLIKELY + { + DWORD flags{audio.mStaticMask}; + channels.reserve(static_cast(al::popcount(flags))); + while(flags) + { + DWORD id{1u << al::countr_zero(flags)}; + flags &= ~id; + + channels.emplace_back(); + audio.mRender->ActivateSpatialAudioObject(static_cast(id), + al::out_ptr(channels.back())); + } + buffers.resize(channels.size()); + } + + /* We have to call to get each channel's buffer individually every + * update, unfortunately. + */ + std::transform(channels.cbegin(), channels.cend(), buffers.begin(), + [](const ComPtr &obj) -> float* + { + BYTE *buffer{}; + UINT32 size{}; + obj->GetBuffer(&buffer, &size); + return reinterpret_cast(buffer); + }); + + mDevice->renderSamples(buffers, framesToDo); + + hr = audio.mRender->EndUpdatingAudioObjects(); + } + + if(FAILED(hr)) + ERR("Failed to update playback objects: 0x%08lx\n", hr); + } + mPadding.store(0u, std::memory_order_release); + + CoUninitialize(); + return 0; +} + void WasapiPlayback::open(std::string_view name) { @@ -1209,7 +1343,6 @@ HRESULT WasapiPlayback::openProxy(std::string_view name) WARN("Failed to open device \"%s\"\n", devname.empty() ? "(default)" : devname.c_str()); return hr; } - mClient = nullptr; if(!devname.empty()) mDevice->DeviceName = DevNameHead + std::move(devname); else @@ -1220,50 +1353,13 @@ HRESULT WasapiPlayback::openProxy(std::string_view name) void WasapiPlayback::closeProxy() { - mClient = nullptr; + mAudio.emplace(); mMMDev = nullptr; } -bool WasapiPlayback::reset() -{ - HRESULT hr{pushMessage(MsgType::ResetDevice).get()}; - if(FAILED(hr)) - throw al::backend_exception{al::backend_error::DeviceError, "0x%08lx", hr}; - return true; -} - -HRESULT WasapiPlayback::resetProxy() +void WasapiPlayback::prepareFormat(WAVEFORMATEXTENSIBLE &OutputType) { - mClient = nullptr; - HRESULT hr{sDeviceHelper->activateAudioClient(mMMDev, __uuidof(IAudioClient), - al::out_ptr(mClient))}; - if(FAILED(hr)) - { - ERR("Failed to reactivate audio client: 0x%08lx\n", hr); - return hr; - } - - WAVEFORMATEX *wfx; - hr = mClient->GetMixFormat(&wfx); - if(FAILED(hr)) - { - ERR("Failed to get mix format: 0x%08lx\n", hr); - return hr; - } - TraceFormat("Device mix format", wfx); - - WAVEFORMATEXTENSIBLE OutputType; - if(!MakeExtensible(&OutputType, wfx)) - { - CoTaskMemFree(wfx); - return E_FAIL; - } - CoTaskMemFree(wfx); - wfx = nullptr; - - const ReferenceTime per_time{ReferenceTime{seconds{mDevice->UpdateSize}} / mDevice->Frequency}; - const ReferenceTime buf_time{ReferenceTime{seconds{mDevice->BufferSize}} / mDevice->Frequency}; bool isRear51{false}; if(!mDevice->Flags.test(FrequencyRequest)) @@ -1379,132 +1475,372 @@ HRESULT WasapiPlayback::resetProxy() OutputType.Format.wBitsPerSample / 8); OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec * OutputType.Format.nBlockAlign; +} - TraceFormat("Requesting playback format", &OutputType.Format); - hr = mClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx); - if(FAILED(hr)) +void WasapiPlayback::finalizeFormat(WAVEFORMATEXTENSIBLE &OutputType) +{ + if(!GetConfigValueBool(mDevice->DeviceName.c_str(), "wasapi", "allow-resampler", true)) + mDevice->Frequency = OutputType.Format.nSamplesPerSec; + else + mDevice->Frequency = minu(mDevice->Frequency, OutputType.Format.nSamplesPerSec); + + const uint32_t chancount{OutputType.Format.nChannels}; + const DWORD chanmask{OutputType.dwChannelMask}; + /* Don't update the channel format if the requested format fits what's + * supported. + */ + bool chansok{false}; + if(mDevice->Flags.test(ChannelsRequest)) + { + /* When requesting a channel configuration, make sure it fits the + * mask's lsb (to ensure no gaps in the output channels). If there's no + * mask, assume the request fits with enough channels. + */ + switch(mDevice->FmtChans) + { + case DevFmtMono: + chansok = (chancount >= 1 && ((chanmask&MonoMask) == MONO || !chanmask)); + break; + case DevFmtStereo: + chansok = (chancount >= 2 && ((chanmask&StereoMask) == STEREO || !chanmask)); + break; + case DevFmtQuad: + chansok = (chancount >= 4 && ((chanmask&QuadMask) == QUAD || !chanmask)); + break; + case DevFmtX51: + chansok = (chancount >= 6 && ((chanmask&X51Mask) == X5DOT1 + || (chanmask&X51RearMask) == X5DOT1REAR || !chanmask)); + break; + case DevFmtX61: + chansok = (chancount >= 7 && ((chanmask&X61Mask) == X6DOT1 || !chanmask)); + break; + case DevFmtX71: + case DevFmtX3D71: + chansok = (chancount >= 8 && ((chanmask&X71Mask) == X7DOT1 || !chanmask)); + break; + case DevFmtX714: + chansok = (chancount >= 12 && ((chanmask&X714Mask) == X7DOT1DOT4 || !chanmask)); + case DevFmtAmbi3D: + break; + } + } + if(!chansok) { - WARN("Failed to check format support: 0x%08lx\n", hr); - hr = mClient->GetMixFormat(&wfx); + if(chancount >= 12 && (chanmask&X714Mask) == X7DOT1DOT4) + mDevice->FmtChans = DevFmtX714; + else if(chancount >= 8 && (chanmask&X71Mask) == X7DOT1) + mDevice->FmtChans = DevFmtX71; + else if(chancount >= 7 && (chanmask&X61Mask) == X6DOT1) + mDevice->FmtChans = DevFmtX61; + else if(chancount >= 6 && ((chanmask&X51Mask) == X5DOT1 + || (chanmask&X51RearMask) == X5DOT1REAR)) + mDevice->FmtChans = DevFmtX51; + else if(chancount >= 4 && (chanmask&QuadMask) == QUAD) + mDevice->FmtChans = DevFmtQuad; + else if(chancount >= 2 && ((chanmask&StereoMask) == STEREO || !chanmask)) + mDevice->FmtChans = DevFmtStereo; + else if(chancount >= 1 && ((chanmask&MonoMask) == MONO || !chanmask)) + mDevice->FmtChans = DevFmtMono; + else + { + ERR("Unhandled extensible channels: %d -- 0x%08lx\n", OutputType.Format.nChannels, + OutputType.dwChannelMask); + mDevice->FmtChans = DevFmtStereo; + OutputType.Format.nChannels = 2; + OutputType.dwChannelMask = STEREO; + } } - if(FAILED(hr)) + + if(IsEqualGUID(OutputType.SubFormat, KSDATAFORMAT_SUBTYPE_PCM)) { - ERR("Failed to find a supported format: 0x%08lx\n", hr); - return hr; + if(OutputType.Format.wBitsPerSample == 8) + mDevice->FmtType = DevFmtUByte; + else if(OutputType.Format.wBitsPerSample == 16) + mDevice->FmtType = DevFmtShort; + else if(OutputType.Format.wBitsPerSample == 32) + mDevice->FmtType = DevFmtInt; + else + { + mDevice->FmtType = DevFmtShort; + OutputType.Format.wBitsPerSample = 16; + } + } + else if(IsEqualGUID(OutputType.SubFormat, KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) + { + mDevice->FmtType = DevFmtFloat; + OutputType.Format.wBitsPerSample = 32; } + else + { + ERR("Unhandled format sub-type: %s\n", GuidPrinter{OutputType.SubFormat}.c_str()); + mDevice->FmtType = DevFmtShort; + if(OutputType.Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE) + OutputType.Format.wFormatTag = WAVE_FORMAT_PCM; + OutputType.Format.wBitsPerSample = 16; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + } + OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; +} - if(wfx != nullptr) + +bool WasapiPlayback::reset() +{ + HRESULT hr{pushMessage(MsgType::ResetDevice).get()}; + if(FAILED(hr)) + throw al::backend_exception{al::backend_error::DeviceError, "0x%08lx", hr}; + return true; +} + +HRESULT WasapiPlayback::resetProxy() +{ + if(GetConfigValueBool(mDevice->DeviceName.c_str(), "wasapi", "spatial-api", false)) { - TraceFormat("Got playback format", wfx); - if(!MakeExtensible(&OutputType, wfx)) + auto &audio = mAudio.emplace(); + HRESULT hr{sDeviceHelper->activateAudioClient(mMMDev, __uuidof(ISpatialAudioClient), + al::out_ptr(audio.mClient))}; + if(FAILED(hr)) { - CoTaskMemFree(wfx); - return E_FAIL; + ERR("Failed to activate spatial audio client: 0x%08lx\n", hr); + goto no_spatial; } - CoTaskMemFree(wfx); - wfx = nullptr; - if(!GetConfigValueBool(mDevice->DeviceName.c_str(), "wasapi", "allow-resampler", true)) - mDevice->Frequency = OutputType.Format.nSamplesPerSec; - else - mDevice->Frequency = minu(mDevice->Frequency, OutputType.Format.nSamplesPerSec); + ComPtr fmtenum; + hr = audio.mClient->GetSupportedAudioObjectFormatEnumerator(al::out_ptr(fmtenum)); + if(FAILED(hr)) + { + ERR("Failed to get format enumerator: 0x%08lx\n", hr); + goto no_spatial; + } - const uint32_t chancount{OutputType.Format.nChannels}; - const DWORD chanmask{OutputType.dwChannelMask}; - /* Don't update the channel format if the requested format fits what's - * supported. - */ - bool chansok{false}; - if(mDevice->Flags.test(ChannelsRequest)) + UINT32 fmtcount{}; + hr = fmtenum->GetCount(&fmtcount); + if(FAILED(hr) || fmtcount == 0) { - /* When requesting a channel configuration, make sure it fits the - * mask's lsb (to ensure no gaps in the output channels). If - * there's no mask, assume the request fits with enough channels. - */ - switch(mDevice->FmtChans) + ERR("Failed to get format count: 0x%08lx\n", hr); + goto no_spatial; + } + + WAVEFORMATEX *preferredFormat{}; + hr = fmtenum->GetFormat(0, &preferredFormat); + if(FAILED(hr)) + { + ERR("Failed to get preferred format: 0x%08lx\n", hr); + goto no_spatial; + } + TraceFormat("Preferred mix format", preferredFormat); + + UINT32 maxFrames{}; + hr = audio.mClient->GetMaxFrameCount(preferredFormat, &maxFrames); + if(FAILED(hr)) + ERR("Failed to get max frames: 0x%08lx\n", hr); + else + TRACE("Max frames: %u\n", maxFrames); + for(UINT32 i{1};i < fmtcount;++i) + { + WAVEFORMATEX *other{}; + hr = fmtenum->GetFormat(i, &other); + if(FAILED(hr)) + ERR("Failed to format %u: 0x%08lx\n", i+1, hr); + else { - case DevFmtMono: - chansok = (chancount >= 1 && ((chanmask&MonoMask) == MONO || !chanmask)); - break; - case DevFmtStereo: - chansok = (chancount >= 2 && ((chanmask&StereoMask) == STEREO || !chanmask)); - break; - case DevFmtQuad: - chansok = (chancount >= 4 && ((chanmask&QuadMask) == QUAD || !chanmask)); - break; - case DevFmtX51: - chansok = (chancount >= 6 && ((chanmask&X51Mask) == X5DOT1 - || (chanmask&X51RearMask) == X5DOT1REAR || !chanmask)); - break; - case DevFmtX61: - chansok = (chancount >= 7 && ((chanmask&X61Mask) == X6DOT1 || !chanmask)); - break; - case DevFmtX71: - case DevFmtX3D71: - chansok = (chancount >= 8 && ((chanmask&X71Mask) == X7DOT1 || !chanmask)); - break; - case DevFmtX714: - chansok = (chancount >= 12 && ((chanmask&X714Mask) == X7DOT1DOT4 || !chanmask)); - case DevFmtAmbi3D: - break; + TraceFormat("Other mix format", other); + hr = audio.mClient->GetMaxFrameCount(other, &maxFrames); + if(FAILED(hr)) + ERR("Failed to get max frames: 0x%08lx\n", hr); + else + TRACE("Max frames: %u\n", maxFrames); } } - if(!chansok) + + WAVEFORMATEXTENSIBLE OutputType; + if(!MakeExtensible(&OutputType, preferredFormat)) + goto no_spatial; + + /* Force 32-bit float. This is currently required for planar output. */ + if(OutputType.Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE + && OutputType.Format.wFormatTag != WAVE_FORMAT_IEEE_FLOAT) + { + OutputType.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; + OutputType.Format.cbSize = 0; + } + if(OutputType.Format.wBitsPerSample != 32) { + OutputType.Format.nAvgBytesPerSec = OutputType.Format.nAvgBytesPerSec * 32u + / OutputType.Format.wBitsPerSample; + OutputType.Format.nBlockAlign = static_cast(OutputType.Format.nBlockAlign * 32 + / OutputType.Format.wBitsPerSample); + OutputType.Format.wBitsPerSample = 32; + } + OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + + bool isRear51{false}; + if(!mDevice->Flags.test(ChannelsRequest)) + { + const uint32_t chancount{OutputType.Format.nChannels}; + const DWORD chanmask{OutputType.dwChannelMask}; if(chancount >= 12 && (chanmask&X714Mask) == X7DOT1DOT4) mDevice->FmtChans = DevFmtX714; else if(chancount >= 8 && (chanmask&X71Mask) == X7DOT1) mDevice->FmtChans = DevFmtX71; else if(chancount >= 7 && (chanmask&X61Mask) == X6DOT1) mDevice->FmtChans = DevFmtX61; - else if(chancount >= 6 && ((chanmask&X51Mask) == X5DOT1 - || (chanmask&X51RearMask) == X5DOT1REAR)) + else if(chancount >= 6 && (chanmask&X51Mask) == X5DOT1) + mDevice->FmtChans = DevFmtX51; + else if(chancount >= 6 && (chanmask&X51RearMask) == X5DOT1REAR) + { mDevice->FmtChans = DevFmtX51; + isRear51 = true; + } else if(chancount >= 4 && (chanmask&QuadMask) == QUAD) mDevice->FmtChans = DevFmtQuad; else if(chancount >= 2 && ((chanmask&StereoMask) == STEREO || !chanmask)) mDevice->FmtChans = DevFmtStereo; - else if(chancount >= 1 && ((chanmask&MonoMask) == MONO || !chanmask)) - mDevice->FmtChans = DevFmtMono; - else - { - ERR("Unhandled extensible channels: %d -- 0x%08lx\n", OutputType.Format.nChannels, - OutputType.dwChannelMask); - mDevice->FmtChans = DevFmtStereo; - OutputType.Format.nChannels = 2; - OutputType.dwChannelMask = STEREO; - } + /* HACK: Don't autoselect mono. Wine returns this and makes the + * audio terrible. + */ + else if(!(chancount >= 1 && ((chanmask&MonoMask) == MONO || !chanmask))) + ERR("Unhandled channel config: %d -- 0x%08lx\n", chancount, chanmask); + } + else + { + const uint32_t chancount{OutputType.Format.nChannels}; + const DWORD chanmask{OutputType.dwChannelMask}; + isRear51 = (chancount == 6 && (chanmask&X51RearMask) == X5DOT1REAR); } - if(IsEqualGUID(OutputType.SubFormat, KSDATAFORMAT_SUBTYPE_PCM)) + auto getTypeMask = [isRear51](DevFmtChannels chans) noexcept { - if(OutputType.Format.wBitsPerSample == 8) - mDevice->FmtType = DevFmtUByte; - else if(OutputType.Format.wBitsPerSample == 16) - mDevice->FmtType = DevFmtShort; - else if(OutputType.Format.wBitsPerSample == 32) - mDevice->FmtType = DevFmtInt; - else + switch(chans) { - mDevice->FmtType = DevFmtShort; - OutputType.Format.wBitsPerSample = 16; + case DevFmtMono: return ChannelMask_Mono; + case DevFmtStereo: return ChannelMask_Stereo; + case DevFmtQuad: return ChannelMask_Quad; + case DevFmtX51: return isRear51 ? ChannelMask_X51Rear : ChannelMask_X51; + case DevFmtX61: return ChannelMask_X61; + case DevFmtX3D71: + case DevFmtX71: return ChannelMask_X71; + case DevFmtX714: return ChannelMask_X714; + case DevFmtAmbi3D: + break; } - } - else if(IsEqualGUID(OutputType.SubFormat, KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) + return ChannelMask_Stereo; + }; + + SpatialAudioObjectRenderStreamActivationParams streamParams{}; + streamParams.ObjectFormat = &OutputType.Format; + streamParams.StaticObjectTypeMask = getTypeMask(mDevice->FmtChans); + streamParams.Category = AudioCategory_Media; + streamParams.EventHandle = mNotifyEvent; + + PropVariant paramProp{}; + paramProp->vt = VT_BLOB; + paramProp->blob.cbSize = sizeof(streamParams); + paramProp->blob.pBlobData = reinterpret_cast(&streamParams); + + hr = audio.mClient->ActivateSpatialAudioStream(paramProp.get(), + __uuidof(ISpatialAudioObjectRenderStream), al::out_ptr(audio.mRender)); + if(FAILED(hr)) { - mDevice->FmtType = DevFmtFloat; - OutputType.Format.wBitsPerSample = 32; + ERR("Failed to activate spatial audio stream: 0x%08lx\n", hr); + goto no_spatial; } - else + + audio.mStaticMask = streamParams.StaticObjectTypeMask; + mFormat = OutputType; + + /* TODO: Support resampling. */ + mDevice->FmtType = DevFmtFloat; + mDevice->Flags.reset(DirectEar).set(Virtualization); + if(streamParams.StaticObjectTypeMask == ChannelMask_Stereo) + mDevice->FmtChans = DevFmtStereo; + mDevice->Frequency = mFormat.Format.nSamplesPerSec; + + setDefaultWFXChannelOrder(); + + /* TODO: Get the real update and buffer size. Does + * ISpatialAudioClient::GetMaxFrameCount give the buffer size, update + * size, or neither? According to MSDN, it + * + * "Gets the maximum possible frame count per processing pass." + * + * If it tries to keep a full buffer, the max possible could be a full + * buffer for the first update or underrun. Though if it always does a + * period at a time, it doesn't make sense for a pass to be less. + * + * Perhaps activating a normal IAudioClient to get the period size is + * the proper thing to do (still won't get us the buffer size though). + */ + mOrigBufferSize = mDevice->BufferSize; + mOrigUpdateSize = mDevice->UpdateSize; + + mResampler = nullptr; + mResampleBuffer = nullptr; + mBufferFilled = 0; + + return S_OK; + } + +no_spatial: + mDevice->Flags.reset(Virtualization); + + auto &audio = mAudio.emplace(); + HRESULT hr{sDeviceHelper->activateAudioClient(mMMDev, __uuidof(IAudioClient), + al::out_ptr(audio.mClient))}; + if(FAILED(hr)) + { + ERR("Failed to reactivate audio client: 0x%08lx\n", hr); + return hr; + } + + WAVEFORMATEX *wfx; + hr = audio.mClient->GetMixFormat(&wfx); + if(FAILED(hr)) + { + ERR("Failed to get mix format: 0x%08lx\n", hr); + return hr; + } + TraceFormat("Device mix format", wfx); + + WAVEFORMATEXTENSIBLE OutputType; + if(!MakeExtensible(&OutputType, wfx)) + { + CoTaskMemFree(wfx); + return E_FAIL; + } + CoTaskMemFree(wfx); + wfx = nullptr; + + const ReferenceTime per_time{ReferenceTime{seconds{mDevice->UpdateSize}} / mDevice->Frequency}; + const ReferenceTime buf_time{ReferenceTime{seconds{mDevice->BufferSize}} / mDevice->Frequency}; + + prepareFormat(OutputType); + + TraceFormat("Requesting playback format", &OutputType.Format); + hr = audio.mClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx); + if(FAILED(hr)) + { + WARN("Failed to check format support: 0x%08lx\n", hr); + hr = audio.mClient->GetMixFormat(&wfx); + } + if(FAILED(hr)) + { + ERR("Failed to find a supported format: 0x%08lx\n", hr); + return hr; + } + + if(wfx != nullptr) + { + TraceFormat("Got playback format", wfx); + if(!MakeExtensible(&OutputType, wfx)) { - ERR("Unhandled format sub-type: %s\n", GuidPrinter{OutputType.SubFormat}.c_str()); - mDevice->FmtType = DevFmtShort; - if(OutputType.Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE) - OutputType.Format.wFormatTag = WAVE_FORMAT_PCM; - OutputType.Format.wBitsPerSample = 16; - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + CoTaskMemFree(wfx); + return E_FAIL; } - OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; + CoTaskMemFree(wfx); + wfx = nullptr; + + finalizeFormat(OutputType); } mFormat = OutputType; @@ -1516,7 +1852,7 @@ HRESULT WasapiPlayback::resetProxy() #endif setDefaultWFXChannelOrder(); - hr = mClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, + hr = audio.mClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, buf_time.count(), 0, &OutputType.Format, nullptr); if(FAILED(hr)) { @@ -1526,15 +1862,22 @@ HRESULT WasapiPlayback::resetProxy() UINT32 buffer_len{}; ReferenceTime min_per{}; - hr = mClient->GetDevicePeriod(&reinterpret_cast(min_per), nullptr); + hr = audio.mClient->GetDevicePeriod(&reinterpret_cast(min_per), nullptr); if(SUCCEEDED(hr)) - hr = mClient->GetBufferSize(&buffer_len); + hr = audio.mClient->GetBufferSize(&buffer_len); if(FAILED(hr)) { ERR("Failed to get audio buffer info: 0x%08lx\n", hr); return hr; } + hr = audio.mClient->SetEventHandle(mNotifyEvent); + if(FAILED(hr)) + { + ERR("Failed to set event handle: 0x%08lx\n", hr); + return hr; + } + /* Find the nearest multiple of the period size to the update size */ if(min_per < per_time) min_per *= maxi64((per_time + min_per/2) / min_per, 1); @@ -1564,13 +1907,6 @@ HRESULT WasapiPlayback::resetProxy() mDevice->UpdateSize); } - hr = mClient->SetEventHandle(mNotifyEvent); - if(FAILED(hr)) - { - ERR("Failed to set event handle: 0x%08lx\n", hr); - return hr; - } - return hr; } @@ -1587,31 +1923,61 @@ HRESULT WasapiPlayback::startProxy() { ResetEvent(mNotifyEvent); - HRESULT hr{mClient->Start()}; - if(FAILED(hr)) + auto mstate_fallback = [](std::monostate) -> HRESULT + { return E_FAIL; }; + auto start_plain = [&](PlainDevice &audio) -> HRESULT { - ERR("Failed to start audio client: 0x%08lx\n", hr); - return hr; - } + HRESULT hr{audio.mClient->Start()}; + if(FAILED(hr)) + { + ERR("Failed to start audio client: 0x%08lx\n", hr); + return hr; + } - hr = mClient->GetService(__uuidof(IAudioRenderClient), al::out_ptr(mRender)); - if(SUCCEEDED(hr)) + hr = audio.mClient->GetService(__uuidof(IAudioRenderClient), al::out_ptr(audio.mRender)); + if(SUCCEEDED(hr)) + { + try { + mKillNow.store(false, std::memory_order_release); + mThread = std::thread{std::mem_fn(&WasapiPlayback::mixerProc), this}; + } + catch(...) { + audio.mRender = nullptr; + ERR("Failed to start thread\n"); + hr = E_FAIL; + } + } + if(FAILED(hr)) + audio.mClient->Stop(); + return hr; + }; + auto start_spatial = [&](SpatialDevice &audio) -> HRESULT { + HRESULT hr{audio.mRender->Start()}; + if(FAILED(hr)) + { + ERR("Failed to start spatial audio stream: 0x%08lx\n", hr); + return hr; + } + try { mKillNow.store(false, std::memory_order_release); - mThread = std::thread{std::mem_fn(&WasapiPlayback::mixerProc), this}; + mThread = std::thread{std::mem_fn(&WasapiPlayback::mixerSpatialProc), this}; } catch(...) { - mRender = nullptr; ERR("Failed to start thread\n"); hr = E_FAIL; } - } - if(FAILED(hr)) - mClient->Stop(); + if(FAILED(hr)) + { + audio.mRender->Stop(); + audio.mRender->Reset(); + } + return hr; + }; - return hr; + return std::visit(overloaded{mstate_fallback, start_plain, start_spatial}, mAudio); } @@ -1620,14 +1986,25 @@ void WasapiPlayback::stop() void WasapiPlayback::stopProxy() { - if(!mRender || !mThread.joinable()) + if(!mThread.joinable()) return; mKillNow.store(true, std::memory_order_release); mThread.join(); - mRender = nullptr; - mClient->Stop(); + auto mstate_fallback = [](std::monostate) -> void + { }; + auto stop_plain = [](PlainDevice &audio) -> void + { + audio.mRender = nullptr; + audio.mClient->Stop(); + }; + auto stop_spatial = [](SpatialDevice &audio) -> void + { + audio.mRender->Stop(); + audio.mRender->Reset(); + }; + std::visit(overloaded{mstate_fallback, stop_plain, stop_spatial}, mAudio); } diff --git a/alsoftrc.sample b/alsoftrc.sample index 8ba14389..42802184 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -579,6 +579,12 @@ ## [wasapi] +## spatial-api: +# Specifies whether to use a Spatial Audio stream for playback. This may +# provide expanded capabilities for surround sound and with-height speaker +# configurations. Very experimental. +#spatial-api = false + ## allow-resampler: # Specifies whether to allow an extra resampler pass on the output. Enabling # this will allow the playback device to be set to a different sample rate diff --git a/core/device.h b/core/device.h index 33cdfe89..b088e130 100644 --- a/core/device.h +++ b/core/device.h @@ -165,6 +165,11 @@ enum { // ear buds, etc). DirectEar, + /* Specifies if output is using speaker virtualization (e.g. Windows + * Spatial Audio). + */ + Virtualization, + DeviceFlagsCount }; -- cgit v1.2.3 From 3d5bd75559ff85ea2a019968361212482afd904b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 20 Sep 2023 20:03:39 -0700 Subject: Fix MSVC compilation MinGW's headers don't seem to define operator| for AudioObjectType. --- alc/backends/wasapi.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 4129ac9d..de974774 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -108,8 +108,10 @@ using ReferenceTime = std::chrono::duration(n)}; } +#ifndef _MSC_VER constexpr AudioObjectType operator|(AudioObjectType lhs, AudioObjectType rhs) noexcept { return static_cast(lhs | al::to_underlying(rhs)); } +#endif #define MONO SPEAKER_FRONT_CENTER -- cgit v1.2.3 From dda61d7b0fe1de983c7af10efd321fa01c4831d8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 20 Sep 2023 20:14:33 -0700 Subject: Don't assume an enum's underlying type --- alc/backends/wasapi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index de974774..25845527 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -1244,7 +1244,7 @@ FORCE_ALIGN int WasapiPlayback::mixerSpatialProc() { if(channels.empty()) UNLIKELY { - DWORD flags{audio.mStaticMask}; + auto flags = al::to_underlying(audio.mStaticMask); channels.reserve(static_cast(al::popcount(flags))); while(flags) { -- cgit v1.2.3 From de9d6d722bd14ed452c02dbaa41a37bdca5df9ca Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 20 Sep 2023 20:37:04 -0700 Subject: Again try to fix handling an enum type --- alc/backends/wasapi.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 25845527..1fd37e37 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -1244,7 +1244,8 @@ FORCE_ALIGN int WasapiPlayback::mixerSpatialProc() { if(channels.empty()) UNLIKELY { - auto flags = al::to_underlying(audio.mStaticMask); + using UT = std::make_unsigned_t; + auto flags = static_cast(al::to_underlying(audio.mStaticMask)); channels.reserve(static_cast(al::popcount(flags))); while(flags) { -- cgit v1.2.3 From 36de3493c1c2fcab966d72c73520e625da1f1e31 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 21 Sep 2023 07:09:05 -0700 Subject: Don't assume the size of AudioObjectType --- alc/backends/wasapi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 1fd37e37..9c2553d1 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -1249,7 +1249,7 @@ FORCE_ALIGN int WasapiPlayback::mixerSpatialProc() channels.reserve(static_cast(al::popcount(flags))); while(flags) { - DWORD id{1u << al::countr_zero(flags)}; + auto id = UT{1} << al::countr_zero(flags); flags &= ~id; channels.emplace_back(); -- cgit v1.2.3 From 1b8c63910fc36a292ae591f5bedc8654c0173be9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 21 Sep 2023 13:04:46 -0700 Subject: Try to get the device period for spatial audio streams --- alc/backends/wasapi.cpp | 82 +++++++++++++++++++++++++++++++------------------ 1 file changed, 52 insertions(+), 30 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 9c2553d1..d06d7401 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -176,10 +176,11 @@ overloaded(Ts...) -> overloaded; /* Scales the given reftime value, rounding the result. */ -inline uint RefTime2Samples(const ReferenceTime &val, uint srate) +template +constexpr uint RefTime2Samples(const ReferenceTime &val, T srate) noexcept { const auto retval = (val*srate + ReferenceTime{seconds{1}}/2) / seconds{1}; - return static_cast(mini64(retval, std::numeric_limits::max())); + return static_cast(std::min(retval, std::numeric_limits::max())); } @@ -1637,21 +1638,22 @@ HRESULT WasapiPlayback::resetProxy() if(FAILED(hr)) ERR("Failed to get max frames: 0x%08lx\n", hr); else - TRACE("Max frames: %u\n", maxFrames); + TRACE("Max sample frames: %u\n", maxFrames); for(UINT32 i{1};i < fmtcount;++i) { - WAVEFORMATEX *other{}; - hr = fmtenum->GetFormat(i, &other); + WAVEFORMATEX *otherFormat{}; + hr = fmtenum->GetFormat(i, &otherFormat); if(FAILED(hr)) ERR("Failed to format %u: 0x%08lx\n", i+1, hr); else { - TraceFormat("Other mix format", other); - hr = audio.mClient->GetMaxFrameCount(other, &maxFrames); + TraceFormat("Other mix format", otherFormat); + UINT32 otherMaxFrames{}; + hr = audio.mClient->GetMaxFrameCount(otherFormat, &otherMaxFrames); if(FAILED(hr)) ERR("Failed to get max frames: 0x%08lx\n", hr); else - TRACE("Max frames: %u\n", maxFrames); + TRACE("Max sample frames: %u\n", otherMaxFrames); } } @@ -1716,16 +1718,16 @@ HRESULT WasapiPlayback::resetProxy() { switch(chans) { - case DevFmtMono: return ChannelMask_Mono; - case DevFmtStereo: return ChannelMask_Stereo; - case DevFmtQuad: return ChannelMask_Quad; - case DevFmtX51: return isRear51 ? ChannelMask_X51Rear : ChannelMask_X51; - case DevFmtX61: return ChannelMask_X61; - case DevFmtX3D71: - case DevFmtX71: return ChannelMask_X71; - case DevFmtX714: return ChannelMask_X714; - case DevFmtAmbi3D: - break; + case DevFmtMono: return ChannelMask_Mono; + case DevFmtStereo: return ChannelMask_Stereo; + case DevFmtQuad: return ChannelMask_Quad; + case DevFmtX51: return isRear51 ? ChannelMask_X51Rear : ChannelMask_X51; + case DevFmtX61: return ChannelMask_X61; + case DevFmtX3D71: + case DevFmtX71: return ChannelMask_X71; + case DevFmtX714: return ChannelMask_X714; + case DevFmtAmbi3D: + break; } return ChannelMask_Stereo; }; @@ -1761,21 +1763,41 @@ HRESULT WasapiPlayback::resetProxy() setDefaultWFXChannelOrder(); - /* TODO: Get the real update and buffer size. Does - * ISpatialAudioClient::GetMaxFrameCount give the buffer size, update - * size, or neither? According to MSDN, it - * - * "Gets the maximum possible frame count per processing pass." + /* FIXME: Get the real update and buffer size. Presumably the actual + * device is configured once ActivateSpatialAudioStream succeeds, and + * an IAudioClient from the same IMMDevice accesses the same device + * configuration. This isn't obviously correct, but for now assume + * IAudioClient::GetDevicePeriod returns the current device period time + * that ISpatialAudioObjectRenderStream will try to wake up at. * - * If it tries to keep a full buffer, the max possible could be a full - * buffer for the first update or underrun. Though if it always does a - * period at a time, it doesn't make sense for a pass to be less. - * - * Perhaps activating a normal IAudioClient to get the period size is - * the proper thing to do (still won't get us the buffer size though). + * Unfortunately this won't get the buffer size of the + * ISpatialAudioObjectRenderStream, so we only assume there's two + * periods. */ - mOrigBufferSize = mDevice->BufferSize; mOrigUpdateSize = mDevice->UpdateSize; + mOrigBufferSize = mOrigUpdateSize*2; + ReferenceTime per_time{ReferenceTime{seconds{mDevice->UpdateSize}} / mDevice->Frequency}; + + ComPtr tmpClient; + hr = sDeviceHelper->activateAudioClient(mMMDev, __uuidof(IAudioClient), + al::out_ptr(tmpClient)); + if(FAILED(hr)) + ERR("Failed to activate audio client: 0x%08lx\n", hr); + else + { + hr = tmpClient->GetDevicePeriod(&reinterpret_cast(per_time), nullptr); + if(FAILED(hr)) + ERR("Failed to get device period: 0x%08lx\n", hr); + else + { + mOrigUpdateSize = RefTime2Samples(per_time, mFormat.Format.nSamplesPerSec); + mOrigBufferSize = mOrigUpdateSize*2; + } + } + tmpClient = nullptr; + + mDevice->UpdateSize = RefTime2Samples(per_time, mDevice->Frequency); + mDevice->BufferSize = mDevice->UpdateSize*2; mResampler = nullptr; mResampleBuffer = nullptr; -- cgit v1.2.3 From 6f33ba65d6470a99dac860dcd8472d47370be77f Mon Sep 17 00:00:00 2001 From: Deal Date: Sat, 23 Sep 2023 00:33:09 +0800 Subject: UWP: migrate C++/CX to C++/WinRT (#916) --- CMakeLists.txt | 28 +++++------ alc/alconfig.cpp | 10 +++- alc/backends/wasapi.cpp | 123 ++++++++++++++++++++++-------------------------- 3 files changed, 78 insertions(+), 83 deletions(-) (limited to 'alc/backends') diff --git a/CMakeLists.txt b/CMakeLists.txt index b75514b2..7a01eb9f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1062,19 +1062,8 @@ if(WIN32) set(HAVE_WASAPI 1) set(BACKENDS "${BACKENDS} WASAPI,") set(ALC_OBJS ${ALC_OBJS} alc/backends/wasapi.cpp alc/backends/wasapi.h) - if(ALSOFT_UWP) - set_source_files_properties(alc/backends/wasapi.cpp alc/alconfig.cpp PROPERTIES COMPILE_FLAGS /ZW) - endif() endif() endif() - - # Setup properly link flags for UWP - if(ALSOFT_UWP AND HAVE_WASAPI) - # Add compile and link flags required C++/CX - set(C_FLAGS "/Zc:twoPhase-" ${C_FLAGS}) - set(LINKER_FLAGS_DEBUG "/nodefaultlib:vccorlibd /nodefaultlib:msvcrtd vccorlibd.lib msvcrtd.lib ${LINKER_FLAGS_DEBUG}") - set(LINKER_FLAGS_RELEASE "/nodefaultlib:vccorlib /nodefaultlib:msvcrt vccorlib.lib msvcrt.lib ${LINKER_FLAGS_RELEASE}") - endif() endif() if(ALSOFT_REQUIRE_WINMM AND NOT HAVE_WINMM) message(FATAL_ERROR "Failed to enabled required WinMM backend") @@ -1419,13 +1408,20 @@ else() endif() target_link_libraries(${IMPL_TARGET} PRIVATE alcommon ${LINKER_FLAGS} ${EXTRA_LIBS} ${MATH_LIB}) - if(ALSOFT_UWP AND HAVE_WASAPI) + if(ALSOFT_UWP) + find_program(NUGET_EXE NAMES nuget) + if(NOT NUGET_EXE) + message("NUGET.EXE not found.") + message(FATAL_ERROR "Please install this executable, and run CMake again.") + endif() + + exec_program(${NUGET_EXE} + ARGS install "Microsoft.Windows.CppWinRT" -Version 2.0.230706.1 -ExcludeVersion -OutputDirectory "\"${CMAKE_BINARY_DIR}/packages\"") + set_target_properties(${IMPL_TARGET} PROPERTIES - LINK_FLAGS_DEBUG "${LINKER_FLAGS_DEBUG}" - LINK_FLAGS_RELEASE "${LINKER_FLAGS_RELEASE}" - LINK_FLAGS_MINSIZEREL "${LINKER_FLAGS_RELEASE}" - LINK_FLAGS_RELWITHDEBINFO "${LINKER_FLAGS_RELEASE}" + VS_PROJECT_IMPORT ${CMAKE_BINARY_DIR}/packages/Microsoft.Windows.CppWinRT/build/native/Microsoft.Windows.CppWinRT.props ) + target_link_libraries(${IMPL_TARGET} PRIVATE ${CMAKE_BINARY_DIR}/packages/Microsoft.Windows.CppWinRT/build/native/Microsoft.Windows.CppWinRT.targets) endif() if(NOT WIN32 AND NOT APPLE) diff --git a/alc/alconfig.cpp b/alc/alconfig.cpp index 03139abe..097ba3a0 100644 --- a/alc/alconfig.cpp +++ b/alc/alconfig.cpp @@ -45,6 +45,13 @@ #include "strutils.h" #include "vector.h" +#if defined(ALSOFT_UWP) +#include // !!This is important!! +#include +#include +#include +using namespace winrt; +#endif namespace { @@ -336,7 +343,8 @@ void ReadALConfig() if (!SHGetSpecialFolderPathW(nullptr, buffer, CSIDL_APPDATA, FALSE)) return; #else - auto buffer = Windows::Storage::ApplicationData::Current->RoamingFolder->Path->Data(); + winrt::Windows::Storage::ApplicationDataContainer localSettings = winrt::Windows::Storage::ApplicationData::Current().LocalSettings(); + auto buffer = Windows::Storage::ApplicationData::Current().RoamingFolder().Path(); #endif std::string filepath{wstr_to_utf8(buffer)}; filepath += "\\alsoft.ini"; diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index d06d7401..fc626fc6 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -73,8 +73,15 @@ #include "strutils.h" #if defined(ALSOFT_UWP) -#include -using namespace Platform; + +#include // !!This is important!! +#include +#include +#include +#include +#include + +using namespace winrt; using namespace Windows::Foundation; using namespace Windows::Media::Devices; using namespace Windows::Devices::Enumeration; @@ -276,8 +283,8 @@ enum EDataFlow { #endif #if defined(ALSOFT_UWP) -using DeviceHandle = DeviceInformation^; -using EventRegistrationToken = Windows::Foundation::EventRegistrationToken; +using DeviceHandle = Windows::Devices::Enumeration::DeviceInformation; +using EventRegistrationToken = winrt::event_token; #else using DeviceHandle = ComPtr; #endif @@ -329,11 +336,11 @@ static NameGUIDPair GetDeviceNameAndGuid(const DeviceHandle &device) guid = UnknownGuid; } #else - std::string name{wstr_to_utf8(device->Name->Data())}; + std::string name{wstr_to_utf8(device.Name())}; std::string guid; // device->Id is DeviceInterfacePath: \\?\SWD#MMDEVAPI#{0.0.0.00000000}.{a21c17a0-fc1d-405e-ab5a-b513422b57d1}#{e6327cad-dcec-4949-ae8a-991e976a79d2} - Platform::String^ devIfPath = device->Id; - if(auto devIdStart = wcsstr(devIfPath->Data(), L"}.")) + auto devIfPath = device.Id(); + if(auto devIdStart = wcsstr(devIfPath.data(), L"}.")) { devIdStart += 2; // L"}." if(auto devIdStartEnd = wcschr(devIdStart, L'#')) @@ -388,35 +395,32 @@ struct DeviceHelper final : private IMMNotificationClient */ mActiveClientEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); - mRenderDeviceChangedToken = MediaDevice::DefaultAudioRenderDeviceChanged += - ref new TypedEventHandler( - [this](Platform::Object ^ sender, DefaultAudioRenderDeviceChangedEventArgs ^ args) { - if(args->Role == AudioDeviceRole::Default) - { - const std::string msg{"Default playback device changed: "+ - wstr_to_utf8(args->Id->Data())}; - alc::Event(alc::EventType::DefaultDeviceChanged, alc::DeviceType::Playback, - msg); - } + mRenderDeviceChangedToken = MediaDevice::DefaultAudioRenderDeviceChanged([this](const IInspectable& /*sender*/, const DefaultAudioRenderDeviceChangedEventArgs& args) { + if (args.Role() == AudioDeviceRole::Default) + { + const std::string msg{ "Default playback device changed: " + + wstr_to_utf8(args.Id())}; + alc::Event(alc::EventType::DefaultDeviceChanged, alc::DeviceType::Playback, + msg); + } }); - mCaptureDeviceChangedToken = MediaDevice::DefaultAudioCaptureDeviceChanged += - ref new TypedEventHandler( - [this](Platform::Object ^ sender, DefaultAudioCaptureDeviceChangedEventArgs ^ args) { - if(args->Role == AudioDeviceRole::Default) - { - const std::string msg{"Default capture device changed: "+ - wstr_to_utf8(args->Id->Data())}; - alc::Event(alc::EventType::DefaultDeviceChanged, alc::DeviceType::Capture, - msg); - } + + mCaptureDeviceChangedToken = MediaDevice::DefaultAudioCaptureDeviceChanged([this](const IInspectable& /*sender*/, const DefaultAudioCaptureDeviceChangedEventArgs& args) { + if (args.Role() == AudioDeviceRole::Default) + { + const std::string msg{ "Default capture device changed: " + + wstr_to_utf8(args.Id()) }; + alc::Event(alc::EventType::DefaultDeviceChanged, alc::DeviceType::Capture, + msg); + } }); #endif } ~DeviceHelper() { #if defined(ALSOFT_UWP) - MediaDevice::DefaultAudioRenderDeviceChanged -= mRenderDeviceChangedToken; - MediaDevice::DefaultAudioCaptureDeviceChanged -= mCaptureDeviceChangedToken; + MediaDevice::DefaultAudioRenderDeviceChanged(mRenderDeviceChangedToken); + MediaDevice::DefaultAudioCaptureDeviceChanged(mCaptureDeviceChangedToken); if(mActiveClientEvent != nullptr) CloseHandle(mActiveClientEvent); @@ -612,21 +616,16 @@ struct DeviceHelper final : private IMMNotificationClient return hr; #else const auto deviceRole = Windows::Media::Devices::AudioDeviceRole::Default; - Platform::String^ devIfPath = + auto devIfPath = devid.empty() ? (flow == eRender ? MediaDevice::GetDefaultAudioRenderId(deviceRole) : MediaDevice::GetDefaultAudioCaptureId(deviceRole)) - : ref new Platform::String(devid.data()); - if (!devIfPath) + : winrt::hstring(devid.data()); + if (devIfPath.empty()) return E_POINTER; - Concurrency::task createDeviceOp( - DeviceInformation::CreateFromIdAsync(devIfPath, nullptr, DeviceInformationKind::DeviceInterface)); - auto status = createDeviceOp.then([&](DeviceInformation^ deviceInfo) - { - device = deviceInfo; - }).wait(); - if(status != Concurrency::task_status::completed) - { + + auto&& deviceInfo = DeviceInformation::CreateFromIdAsync(devIfPath, nullptr, DeviceInformationKind::DeviceInterface).get(); + if (!deviceInfo) return E_NOINTERFACE; - } + device = deviceInfo; return S_OK; #endif } @@ -638,7 +637,7 @@ struct DeviceHelper final : private IMMNotificationClient HRESULT activateAudioClient(_In_ DeviceHandle &device, _In_ REFIID iid, void **ppv) { ComPtr asyncOp; - HRESULT hr{ActivateAudioInterfaceAsync(device->Id->Data(), iid, nullptr, this, + HRESULT hr{ActivateAudioInterfaceAsync(device.Id().data(), iid, nullptr, this, al::out_ptr(asyncOp))}; if(FAILED(hr)) return hr; @@ -713,40 +712,32 @@ struct DeviceHelper final : private IMMNotificationClient const auto deviceRole = Windows::Media::Devices::AudioDeviceRole::Default; auto DefaultAudioId = flowdir == eRender ? MediaDevice::GetDefaultAudioRenderId(deviceRole) : MediaDevice::GetDefaultAudioCaptureId(deviceRole); - if (!DefaultAudioId) + if (DefaultAudioId.empty()) return defaultId; - Concurrency::task createDefaultOp(DeviceInformation::CreateFromIdAsync(DefaultAudioId, nullptr, DeviceInformationKind::DeviceInterface)); - auto task_status = createDefaultOp.then([&defaultId](DeviceInformation ^ deviceInfo) - { - if(deviceInfo) - defaultId = deviceInfo->Id->Data(); - }).wait(); - if(task_status != Concurrency::task_group_status::completed) + + auto deviceInfo = DeviceInformation::CreateFromIdAsync(DefaultAudioId, nullptr, DeviceInformationKind::DeviceInterface).get(); + if(!deviceInfo) return defaultId; // Get the string identifier of the audio renderer auto AudioSelector = flowdir == eRender ? MediaDevice::GetAudioRenderSelector() : MediaDevice::GetAudioCaptureSelector(); // Setup the asynchronous callback - Concurrency::task enumOperation( - DeviceInformation::FindAllAsync(AudioSelector, /*PropertyList*/nullptr, DeviceInformationKind::DeviceInterface)); - task_status = enumOperation.then([this,&list](DeviceInformationCollection ^ DeviceInfoCollection) + auto&& DeviceInfoCollection = DeviceInformation::FindAllAsync(AudioSelector, /*PropertyList*/nullptr, DeviceInformationKind::DeviceInterface).get(); + if(DeviceInfoCollection) { - if(DeviceInfoCollection) - { - try { - auto deviceCount = DeviceInfoCollection->Size; - for(unsigned int i{0};i < deviceCount;++i) - { - DeviceInformation^ deviceInfo = DeviceInfoCollection->GetAt(i); - if(deviceInfo) - std::ignore = AddDevice(deviceInfo, deviceInfo->Id->Data(), list); - } - } - catch (Platform::Exception ^ e) { + try { + auto deviceCount = DeviceInfoCollection.Size(); + for(unsigned int i{0};i < deviceCount;++i) + { + deviceInfo = DeviceInfoCollection.GetAt(i); + if(deviceInfo) + std::ignore = AddDevice(deviceInfo, deviceInfo.Id().data(), list); } } - }).wait(); + catch (std::exception& /*ex*/) { + } + } #endif return defaultId; -- cgit v1.2.3 From c53ed17c59345526ba41b62bd886c2cbaaca423b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 22 Sep 2023 13:13:09 -0700 Subject: Avoid casting an integer literal --- al/auxeffectslot.cpp | 2 +- al/buffer.cpp | 2 +- al/eax/call.h | 2 +- al/effect.cpp | 2 +- al/filter.cpp | 2 +- al/source.cpp | 29 +++++++++++++++++------------ al/state.cpp | 2 +- alc/alu.cpp | 2 +- alc/backends/wave.cpp | 4 ++-- alc/context.cpp | 4 ++-- alc/device.cpp | 6 +++--- core/hrtf.cpp | 2 +- core/mixer/mixer_neon.cpp | 4 ++-- core/mixer/mixer_sse.cpp | 4 ++-- core/voice.cpp | 4 ++-- 15 files changed, 38 insertions(+), 33 deletions(-) (limited to 'alc/backends') diff --git a/al/auxeffectslot.cpp b/al/auxeffectslot.cpp index 66a65b5c..33252410 100644 --- a/al/auxeffectslot.cpp +++ b/al/auxeffectslot.cpp @@ -239,7 +239,7 @@ EffectSlotType EffectSlotTypeFromEnum(ALenum type) bool EnsureEffectSlots(ALCcontext *context, size_t needed) { size_t count{std::accumulate(context->mEffectSlotList.cbegin(), - context->mEffectSlotList.cend(), size_t{0}, + context->mEffectSlotList.cend(), 0_uz, [](size_t cur, const EffectSlotSubList &sublist) noexcept -> size_t { return cur + static_cast(al::popcount(sublist.FreeMask)); })}; diff --git a/al/buffer.cpp b/al/buffer.cpp index 28afc7c0..8ba874e4 100644 --- a/al/buffer.cpp +++ b/al/buffer.cpp @@ -174,7 +174,7 @@ constexpr ALbitfieldSOFT INVALID_MAP_FLAGS{~unsigned(AL_MAP_READ_BIT_SOFT | AL_M bool EnsureBuffers(ALCdevice *device, size_t needed) { - size_t count{std::accumulate(device->BufferList.cbegin(), device->BufferList.cend(), size_t{0}, + size_t count{std::accumulate(device->BufferList.cbegin(), device->BufferList.cend(), 0_uz, [](size_t cur, const BufferSubList &sublist) noexcept -> size_t { return cur + static_cast(al::popcount(sublist.FreeMask)); })}; diff --git a/al/eax/call.h b/al/eax/call.h index f2ad529e..45ff328c 100644 --- a/al/eax/call.h +++ b/al/eax/call.h @@ -61,7 +61,7 @@ public: template al::span get_values() const { - return get_values(~size_t{}); + return get_values(~0_uz); } template diff --git a/al/effect.cpp b/al/effect.cpp index 5c7f9627..c4b06407 100644 --- a/al/effect.cpp +++ b/al/effect.cpp @@ -162,7 +162,7 @@ void InitEffectParams(ALeffect *effect, ALenum type) bool EnsureEffects(ALCdevice *device, size_t needed) { - size_t count{std::accumulate(device->EffectList.cbegin(), device->EffectList.cend(), size_t{0}, + size_t count{std::accumulate(device->EffectList.cbegin(), device->EffectList.cend(), 0_uz, [](size_t cur, const EffectSubList &sublist) noexcept -> size_t { return cur + static_cast(al::popcount(sublist.FreeMask)); })}; diff --git a/al/filter.cpp b/al/filter.cpp index e6520e6a..f0a078b7 100644 --- a/al/filter.cpp +++ b/al/filter.cpp @@ -117,7 +117,7 @@ void InitFilterParams(ALfilter *filter, ALenum type) bool EnsureFilters(ALCdevice *device, size_t needed) { - size_t count{std::accumulate(device->FilterList.cbegin(), device->FilterList.cend(), size_t{0}, + size_t count{std::accumulate(device->FilterList.cbegin(), device->FilterList.cend(), 0_uz, [](size_t cur, const FilterSubList &sublist) noexcept -> size_t { return cur + static_cast(al::popcount(sublist.FreeMask)); })}; diff --git a/al/source.cpp b/al/source.cpp index 01a981d3..2fbd1703 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -719,8 +719,7 @@ inline ALenum GetSourceState(ALsource *source, Voice *voice) bool EnsureSources(ALCcontext *context, size_t needed) { - size_t count{std::accumulate(context->mSourceList.cbegin(), context->mSourceList.cend(), - size_t{0}, + size_t count{std::accumulate(context->mSourceList.cbegin(), context->mSourceList.cend(), 0_uz, [](size_t cur, const SourceSubList &sublist) noexcept -> size_t { return cur + static_cast(al::popcount(sublist.FreeMask)); })}; @@ -3697,7 +3696,8 @@ ALsource* ALsource::EaxLookupSource(ALCcontext& al_context, ALuint source_id) no void ALsource::eax_set_sends_defaults(EaxSends& sends, const EaxFxSlotIds& ids) noexcept { - for (auto i = size_t{}; i < EAX_MAX_FXSLOTS; ++i) { + for(size_t i{0};i < EAX_MAX_FXSLOTS;++i) + { auto& send = sends[i]; send.guidReceivingFXSlotID = *(ids[i]); send.lSend = EAXSOURCE_DEFAULTSEND; @@ -3809,7 +3809,8 @@ void ALsource::eax5_set_active_fx_slots_defaults(EAX50ACTIVEFXSLOTS& slots) noex void ALsource::eax5_set_speaker_levels_defaults(EaxSpeakerLevels& speaker_levels) noexcept { - for (auto i = size_t{}; i < eax_max_speakers; ++i) { + for(size_t i{0};i < eax_max_speakers;++i) + { auto& speaker_level = speaker_levels[i]; speaker_level.lSpeakerID = static_cast(EAXSPEAKER_FRONT_LEFT + i); speaker_level.lLevel = EAXSOURCE_DEFAULTSPEAKERLEVEL; @@ -3912,7 +3913,7 @@ void ALsource::eax4_translate(const Eax4Props& src, Eax5Props& dst) noexcept // dst.sends = src.sends; - for (auto i = size_t{}; i < EAX_MAX_FXSLOTS; ++i) + for(size_t i{0};i < EAX_MAX_FXSLOTS;++i) dst.sends[i].guidReceivingFXSlotID = *(eax5_fx_slot_ids[i]); // Active FX slots. @@ -3974,19 +3975,21 @@ EaxAlLowPassParam ALsource::eax_create_direct_filter_param() const noexcept static_cast(mEax.source.lDirectHF) + static_cast(mEax.source.lObstruction); - for (auto i = std::size_t{}; i < EAX_MAX_FXSLOTS; ++i) + for(size_t i{0};i < EAX_MAX_FXSLOTS;++i) { if(!mEaxActiveFxSlots[i]) continue; - if(has_source_occlusion) { + if(has_source_occlusion) + { const auto& fx_slot = mEaxAlContext->eaxGetFxSlot(i); const auto& fx_slot_eax = fx_slot.eax_get_eax_fx_slot(); const auto is_environmental_fx = ((fx_slot_eax.ulFlags & EAXFXSLOTFLAGS_ENVIRONMENT) != 0); const auto is_primary = (mEaxPrimaryFxSlotId.value_or(-1) == fx_slot.eax_get_index()); const auto is_listener_environment = (is_environmental_fx && is_primary); - if(is_listener_environment) { + if(is_listener_environment) + { gain_mb += eax_calculate_dst_occlusion_mb( mEax.source.lOcclusion, mEax.source.flOcclusionDirectRatio, @@ -3998,7 +4001,8 @@ EaxAlLowPassParam ALsource::eax_create_direct_filter_param() const noexcept const auto& send = mEax.sends[i]; - if(send.lOcclusion != 0) { + if(send.lOcclusion != 0) + { gain_mb += eax_calculate_dst_occlusion_mb( send.lOcclusion, send.flOcclusionDirectRatio, @@ -4073,8 +4077,9 @@ void ALsource::eax_update_direct_filter() void ALsource::eax_update_room_filters() { - for (auto i = size_t{}; i < EAX_MAX_FXSLOTS; ++i) { - if (!mEaxActiveFxSlots[i]) + for(size_t i{0};i < EAX_MAX_FXSLOTS;++i) + { + if(!mEaxActiveFxSlots[i]) continue; auto& fx_slot = mEaxAlContext->eaxGetFxSlot(i); @@ -4880,7 +4885,7 @@ void ALsource::eax_commit_active_fx_slots() // Deactivate EFX auxiliary effect slots for inactive slots. Active slots // will be updated with the room filters. - for(auto i = size_t{}; i < EAX_MAX_FXSLOTS; ++i) + for(size_t i{0};i < EAX_MAX_FXSLOTS;++i) { if(!mEaxActiveFxSlots[i]) eax_set_al_source_send(nullptr, i, EaxAlLowPassParam{1.0f, 1.0f}); diff --git a/al/state.cpp b/al/state.cpp index 1c41d63c..5131edd9 100644 --- a/al/state.cpp +++ b/al/state.cpp @@ -229,7 +229,7 @@ void GetValue(ALCcontext *context, ALenum pname, T *values) case AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_EXT: { std::lock_guard _{context->mDebugCbLock}; - *values = cast_value(context->mDebugLog.empty() ? size_t{0} + *values = cast_value(context->mDebugLog.empty() ? 0_uz : (context->mDebugLog.front().mMessage.size()+1)); return; } diff --git a/alc/alu.cpp b/alc/alu.cpp index 1fa9d1d4..6eb4691e 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -733,7 +733,7 @@ void AmbiRotator(AmbiRotateMatrix &matrix, const int order) } } last_band = band_idx; - band_idx += static_cast(l)*size_t{2} + 1; + band_idx += static_cast(l)*2_uz + 1; } } /* End ambisonic rotation helpers. */ diff --git a/alc/backends/wave.cpp b/alc/backends/wave.cpp index 1078c654..794d5cb8 100644 --- a/alc/backends/wave.cpp +++ b/alc/backends/wave.cpp @@ -154,13 +154,13 @@ int WaveBackend::mixerProc() if(bytesize == 2) { - const size_t len{mBuffer.size() & ~size_t{1}}; + const size_t len{mBuffer.size() & ~1_uz}; for(size_t i{0};i < len;i+=2) std::swap(mBuffer[i], mBuffer[i+1]); } else if(bytesize == 4) { - const size_t len{mBuffer.size() & ~size_t{3}}; + const size_t len{mBuffer.size() & ~3_uz}; for(size_t i{0};i < len;i+=4) { std::swap(mBuffer[i ], mBuffer[i+3]); diff --git a/alc/context.cpp b/alc/context.cpp index 3b1de7b9..8c930056 100644 --- a/alc/context.cpp +++ b/alc/context.cpp @@ -127,7 +127,7 @@ ALCcontext::~ALCcontext() { TRACE("Freeing context %p\n", voidp{this}); - size_t count{std::accumulate(mSourceList.cbegin(), mSourceList.cend(), size_t{0u}, + size_t count{std::accumulate(mSourceList.cbegin(), mSourceList.cend(), 0_uz, [](size_t cur, const SourceSubList &sublist) noexcept -> size_t { return cur + static_cast(al::popcount(~sublist.FreeMask)); })}; if(count > 0) @@ -140,7 +140,7 @@ ALCcontext::~ALCcontext() #endif // ALSOFT_EAX mDefaultSlot = nullptr; - count = std::accumulate(mEffectSlotList.cbegin(), mEffectSlotList.cend(), size_t{0u}, + count = std::accumulate(mEffectSlotList.cbegin(), mEffectSlotList.cend(), 0_uz, [](size_t cur, const EffectSlotSubList &sublist) noexcept -> size_t { return cur + static_cast(al::popcount(~sublist.FreeMask)); }); if(count > 0) diff --git a/alc/device.cpp b/alc/device.cpp index 66b13c5e..27aa6f36 100644 --- a/alc/device.cpp +++ b/alc/device.cpp @@ -34,19 +34,19 @@ ALCdevice::~ALCdevice() Backend = nullptr; - size_t count{std::accumulate(BufferList.cbegin(), BufferList.cend(), size_t{0u}, + size_t count{std::accumulate(BufferList.cbegin(), BufferList.cend(), 0_uz, [](size_t cur, const BufferSubList &sublist) noexcept -> size_t { return cur + static_cast(al::popcount(~sublist.FreeMask)); })}; if(count > 0) WARN("%zu Buffer%s not deleted\n", count, (count==1)?"":"s"); - count = std::accumulate(EffectList.cbegin(), EffectList.cend(), size_t{0u}, + count = std::accumulate(EffectList.cbegin(), EffectList.cend(), 0_uz, [](size_t cur, const EffectSubList &sublist) noexcept -> size_t { return cur + static_cast(al::popcount(~sublist.FreeMask)); }); if(count > 0) WARN("%zu Effect%s not deleted\n", count, (count==1)?"":"s"); - count = std::accumulate(FilterList.cbegin(), FilterList.cend(), size_t{0u}, + count = std::accumulate(FilterList.cbegin(), FilterList.cend(), 0_uz, [](size_t cur, const FilterSubList &sublist) noexcept -> size_t { return cur + static_cast(al::popcount(~sublist.FreeMask)); }); if(count > 0) diff --git a/core/hrtf.cpp b/core/hrtf.cpp index f131e72d..9a13a004 100644 --- a/core/hrtf.cpp +++ b/core/hrtf.cpp @@ -1368,7 +1368,7 @@ HrtfStorePtr GetLoadedHrtf(const std::string &name, const uint devrate) TRACE("Resampling HRTF %s (%uhz -> %uhz)\n", name.c_str(), hrtf->mSampleRate, devrate); /* Calculate the last elevation's index and get the total IR count. */ - const size_t lastEv{std::accumulate(hrtf->mFields.begin(), hrtf->mFields.end(), size_t{0}, + const size_t lastEv{std::accumulate(hrtf->mFields.begin(), hrtf->mFields.end(), 0_uz, [](const size_t curval, const HrtfStore::Field &field) noexcept -> size_t { return curval + field.evCount; } ) - 1}; diff --git a/core/mixer/mixer_neon.cpp b/core/mixer/mixer_neon.cpp index ef2936b3..ead775af 100644 --- a/core/mixer/mixer_neon.cpp +++ b/core/mixer/mixer_neon.cpp @@ -342,7 +342,7 @@ void Mix_(const al::span InSamples, const al::span 0) ? 1.0f / static_cast(Counter) : 0.0f}; const auto min_len = minz(Counter, InSamples.size()); - const auto aligned_len = minz((min_len+3) & ~size_t{3}, InSamples.size()) - min_len; + const auto aligned_len = minz((min_len+3) & ~3_uz, InSamples.size()) - min_len; for(FloatBufferLine &output : OutBuffer) MixLine(InSamples, al::assume_aligned<16>(output.data()+OutPos), *CurrentGains++, @@ -355,7 +355,7 @@ void Mix_(const al::span InSamples, float *OutBuffer, floa { const float delta{(Counter > 0) ? 1.0f / static_cast(Counter) : 0.0f}; const auto min_len = minz(Counter, InSamples.size()); - const auto aligned_len = minz((min_len+3) & ~size_t{3}, InSamples.size()) - min_len; + const auto aligned_len = minz((min_len+3) & ~3_uz, InSamples.size()) - min_len; MixLine(InSamples, al::assume_aligned<16>(OutBuffer), CurrentGain, TargetGain, delta, min_len, aligned_len, Counter); diff --git a/core/mixer/mixer_sse.cpp b/core/mixer/mixer_sse.cpp index 0aa5d5fb..70f77c14 100644 --- a/core/mixer/mixer_sse.cpp +++ b/core/mixer/mixer_sse.cpp @@ -307,7 +307,7 @@ void Mix_(const al::span InSamples, const al::span 0) ? 1.0f / static_cast(Counter) : 0.0f}; const auto min_len = minz(Counter, InSamples.size()); - const auto aligned_len = minz((min_len+3) & ~size_t{3}, InSamples.size()) - min_len; + const auto aligned_len = minz((min_len+3) & ~3_uz, InSamples.size()) - min_len; for(FloatBufferLine &output : OutBuffer) MixLine(InSamples, al::assume_aligned<16>(output.data()+OutPos), *CurrentGains++, @@ -320,7 +320,7 @@ void Mix_(const al::span InSamples, float *OutBuffer, float { const float delta{(Counter > 0) ? 1.0f / static_cast(Counter) : 0.0f}; const auto min_len = minz(Counter, InSamples.size()); - const auto aligned_len = minz((min_len+3) & ~size_t{3}, InSamples.size()) - min_len; + const auto aligned_len = minz((min_len+3) & ~3_uz, InSamples.size()) - min_len; MixLine(InSamples, al::assume_aligned<16>(OutBuffer), CurrentGain, TargetGain, delta, min_len, aligned_len, Counter); diff --git a/core/voice.cpp b/core/voice.cpp index 92da3e76..b8acc7a6 100644 --- a/core/voice.cpp +++ b/core/voice.cpp @@ -330,7 +330,7 @@ inline void LoadSamples(float *RESTRICT dstSamples, const std::byte *sr for(;skip;--skip) { const size_t byteShift{(nibbleOffset&1) * 4}; - const size_t wordOffset{(nibbleOffset>>1) & ~size_t{3}}; + const size_t wordOffset{(nibbleOffset>>1) & ~3_uz}; const size_t byteOffset{wordOffset*srcStep + ((nibbleOffset>>1)&3u)}; ++nibbleOffset; @@ -344,7 +344,7 @@ inline void LoadSamples(float *RESTRICT dstSamples, const std::byte *sr for(size_t i{0};i < todo;++i) { const size_t byteShift{(nibbleOffset&1) * 4}; - const size_t wordOffset{(nibbleOffset>>1) & ~size_t{3}}; + const size_t wordOffset{(nibbleOffset>>1) & ~3_uz}; const size_t byteOffset{wordOffset*srcStep + ((nibbleOffset>>1)&3u)}; ++nibbleOffset; -- cgit v1.2.3 From 2e24d1ed773c2fb0f5b85acb9c02acb9c8b5462d Mon Sep 17 00:00:00 2001 From: Deal Date: Sun, 24 Sep 2023 00:13:00 +0800 Subject: Fix cppwinrt exception type capture (#918) --- alc/backends/wasapi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index fc626fc6..ebd095fd 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -735,7 +735,7 @@ struct DeviceHelper final : private IMMNotificationClient std::ignore = AddDevice(deviceInfo, deviceInfo.Id().data(), list); } } - catch (std::exception& /*ex*/) { + catch (const winrt::hresult_error& /*ex*/) { } } #endif -- cgit v1.2.3 From 64746158a139b6389e656c8640e456dd623c4bd1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 24 Sep 2023 15:58:49 -0700 Subject: Support resampling with WASAPI spatial audio output --- alc/backends/wasapi.cpp | 81 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 67 insertions(+), 14 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index ebd095fd..4494317a 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -115,11 +115,6 @@ using ReferenceTime = std::chrono::duration(n)}; } -#ifndef _MSC_VER -constexpr AudioObjectType operator|(AudioObjectType lhs, AudioObjectType rhs) noexcept -{ return static_cast(lhs | al::to_underlying(rhs)); } -#endif - #define MONO SPEAKER_FRONT_CENTER #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT) @@ -148,6 +143,12 @@ constexpr DWORD X61Mask{MaskFromTopBits(X6DOT1)}; constexpr DWORD X71Mask{MaskFromTopBits(X7DOT1)}; constexpr DWORD X714Mask{MaskFromTopBits(X7DOT1DOT4)}; + +#ifndef _MSC_VER +constexpr AudioObjectType operator|(AudioObjectType lhs, AudioObjectType rhs) noexcept +{ return static_cast(lhs | al::to_underlying(rhs)); } +#endif + constexpr AudioObjectType ChannelMask_Mono{AudioObjectType_FrontCenter}; constexpr AudioObjectType ChannelMask_Stereo{AudioObjectType_FrontLeft | AudioObjectType_FrontRight}; @@ -171,6 +172,7 @@ constexpr AudioObjectType ChannelMask_X714{AudioObjectType_FrontLeft | AudioObje | AudioObjectType_TopFrontLeft | AudioObjectType_TopFrontRight | AudioObjectType_TopBackLeft | AudioObjectType_TopBackRight}; + constexpr char DevNameHead[] = "OpenAL Soft on "; constexpr size_t DevNameHeadLen{std::size(DevNameHead) - 1}; @@ -182,6 +184,14 @@ template overloaded(Ts...) -> overloaded; +template +auto as_unsigned(T value) noexcept +{ + using UT = std::make_unsigned_t; + return static_cast(value); +} + + /* Scales the given reftime value, rounding the result. */ template constexpr uint RefTime2Samples(const ReferenceTime &val, T srate) noexcept @@ -1209,11 +1219,14 @@ FORCE_ALIGN int WasapiPlayback::mixerSpatialProc() std::vector> channels; std::vector buffers; + std::vector resbuffers; + std::vector tmpbuffers; /* TODO: Set mPadding appropriately. There doesn't seem to be a way to - * update it dynamically based on the stream, so it may need to be set to a - * fixed size. + * update it dynamically based on the stream, so a fixed size may be the + * best we can do. */ + mPadding.store(mDevice->BufferSize-mDevice->UpdateSize, std::memory_order_release); while(!mKillNow.load(std::memory_order_relaxed)) { @@ -1236,12 +1249,11 @@ FORCE_ALIGN int WasapiPlayback::mixerSpatialProc() { if(channels.empty()) UNLIKELY { - using UT = std::make_unsigned_t; - auto flags = static_cast(al::to_underlying(audio.mStaticMask)); - channels.reserve(static_cast(al::popcount(flags))); + auto flags = as_unsigned(audio.mStaticMask); + channels.reserve(as_unsigned(al::popcount(flags))); while(flags) { - auto id = UT{1} << al::countr_zero(flags); + auto id = decltype(flags){1} << al::countr_zero(flags); flags &= ~id; channels.emplace_back(); @@ -1249,6 +1261,14 @@ FORCE_ALIGN int WasapiPlayback::mixerSpatialProc() al::out_ptr(channels.back())); } buffers.resize(channels.size()); + if(mResampler) + { + tmpbuffers.resize(buffers.size()); + resbuffers.resize(buffers.size()); + for(size_t i{0};i < tmpbuffers.size();++i) + resbuffers[i] = reinterpret_cast(mResampleBuffer.get()) + + mDevice->UpdateSize*i; + } } /* We have to call to get each channel's buffer individually every @@ -1263,7 +1283,27 @@ FORCE_ALIGN int WasapiPlayback::mixerSpatialProc() return reinterpret_cast(buffer); }); - mDevice->renderSamples(buffers, framesToDo); + if(!mResampler) + mDevice->renderSamples(buffers, framesToDo); + else + { + std::lock_guard _{mMutex}; + for(UINT32 pos{0};pos < framesToDo;) + { + if(mBufferFilled == 0) + { + mDevice->renderSamples(resbuffers, mDevice->UpdateSize); + std::copy(resbuffers.cbegin(), resbuffers.cend(), tmpbuffers.begin()); + mBufferFilled = mDevice->UpdateSize; + } + + const uint got{mResampler->convertPlanar(tmpbuffers.data(), &mBufferFilled, + reinterpret_cast(buffers.data()), framesToDo-pos)}; + for(auto &buf : buffers) + buf += got; + pos += got; + } + } hr = audio.mRender->EndUpdatingAudioObjects(); } @@ -1745,12 +1785,10 @@ HRESULT WasapiPlayback::resetProxy() audio.mStaticMask = streamParams.StaticObjectTypeMask; mFormat = OutputType; - /* TODO: Support resampling. */ mDevice->FmtType = DevFmtFloat; mDevice->Flags.reset(DirectEar).set(Virtualization); if(streamParams.StaticObjectTypeMask == ChannelMask_Stereo) mDevice->FmtChans = DevFmtStereo; - mDevice->Frequency = mFormat.Format.nSamplesPerSec; setDefaultWFXChannelOrder(); @@ -1793,6 +1831,21 @@ HRESULT WasapiPlayback::resetProxy() mResampler = nullptr; mResampleBuffer = nullptr; mBufferFilled = 0; + if(mDevice->Frequency != mFormat.Format.nSamplesPerSec) + { + const auto flags = as_unsigned(streamParams.StaticObjectTypeMask); + const auto channelCount = as_unsigned(al::popcount(flags)); + mResampler = SampleConverter::Create(mDevice->FmtType, mDevice->FmtType, + channelCount, mDevice->Frequency, mFormat.Format.nSamplesPerSec, + Resampler::FastBSinc24); + mResampleBuffer = std::make_unique(size_t{mDevice->UpdateSize} * channelCount * + mFormat.Format.wBitsPerSample / 8); + + TRACE("Created converter for %s/%s format, dst: %luhz (%u), src: %uhz (%u)\n", + DevFmtChannelsString(mDevice->FmtChans), DevFmtTypeString(mDevice->FmtType), + mFormat.Format.nSamplesPerSec, mOrigUpdateSize, mDevice->Frequency, + mDevice->UpdateSize); + } return S_OK; } -- cgit v1.2.3 From acc618a1a68c99d61bf0c1897ba1af24e4ebed01 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 24 Sep 2023 16:06:15 -0700 Subject: Match the output sample rate if not requesting one --- alc/backends/wasapi.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 4494317a..516ac02c 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -1710,6 +1710,10 @@ HRESULT WasapiPlayback::resetProxy() OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + /* Match the output rate if not requesting anything specific. */ + if(!mDevice->Flags.test(FrequencyRequest)) + mDevice->Frequency = OutputType.Format.nSamplesPerSec; + bool isRear51{false}; if(!mDevice->Flags.test(ChannelsRequest)) { -- cgit v1.2.3 From 4fb1c23ca3679cc8e9840ebcab975176bd034ab4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 24 Sep 2023 19:10:06 -0700 Subject: Honor the wasapi allow-resampler option with spatial sound output --- alc/backends/wasapi.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 516ac02c..e26af7c9 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -1793,6 +1793,10 @@ HRESULT WasapiPlayback::resetProxy() mDevice->Flags.reset(DirectEar).set(Virtualization); if(streamParams.StaticObjectTypeMask == ChannelMask_Stereo) mDevice->FmtChans = DevFmtStereo; + if(!GetConfigValueBool(mDevice->DeviceName.c_str(), "wasapi", "allow-resampler", true)) + mDevice->Frequency = OutputType.Format.nSamplesPerSec; + else + mDevice->Frequency = minu(mDevice->Frequency, OutputType.Format.nSamplesPerSec); setDefaultWFXChannelOrder(); -- cgit v1.2.3 From 3ab2ca28f82073e0baeb25f49163f7353be4b2ca Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Sep 2023 19:55:06 -0700 Subject: Constify some pointers to indicate they won't change --- alc/backends/wasapi.cpp | 2 +- core/converter.cpp | 2 +- core/converter.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index e26af7c9..7eae84c1 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -1298,7 +1298,7 @@ FORCE_ALIGN int WasapiPlayback::mixerSpatialProc() } const uint got{mResampler->convertPlanar(tmpbuffers.data(), &mBufferFilled, - reinterpret_cast(buffers.data()), framesToDo-pos)}; + reinterpret_cast(buffers.data()), framesToDo-pos)}; for(auto &buf : buffers) buf += got; pos += got; diff --git a/core/converter.cpp b/core/converter.cpp index dea31bd5..5b2f3e15 100644 --- a/core/converter.cpp +++ b/core/converter.cpp @@ -309,7 +309,7 @@ uint SampleConverter::convert(const void **src, uint *srcframes, void *dst, uint return pos; } -uint SampleConverter::convertPlanar(const void **src, uint *srcframes, void **dst, uint dstframes) +uint SampleConverter::convertPlanar(const void **src, uint *srcframes, void *const*dst, uint dstframes) { const uint increment{mIncrement}; uint NumSrcSamples{*srcframes}; diff --git a/core/converter.h b/core/converter.h index d811b46b..49ca124d 100644 --- a/core/converter.h +++ b/core/converter.h @@ -36,7 +36,7 @@ struct SampleConverter { SampleConverter(size_t numchans) : mChan{numchans} { } uint convert(const void **src, uint *srcframes, void *dst, uint dstframes); - uint convertPlanar(const void **src, uint *srcframes, void **dst, uint dstframes); + uint convertPlanar(const void **src, uint *srcframes, void *const*dst, uint dstframes); uint availableOut(uint srcframes) const; using SampleOffset = std::chrono::duration>; -- cgit v1.2.3 From 43a57e02ea5b767960b9da2899d5765dae46a035 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 26 Sep 2023 18:34:51 -0700 Subject: Set the appropriate padding size It's based on the original/stream size, not the ALCdevice's. --- alc/backends/wasapi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 7eae84c1..b68439a8 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -1226,7 +1226,7 @@ FORCE_ALIGN int WasapiPlayback::mixerSpatialProc() * update it dynamically based on the stream, so a fixed size may be the * best we can do. */ - mPadding.store(mDevice->BufferSize-mDevice->UpdateSize, std::memory_order_release); + mPadding.store(mOrigBufferSize-mOrigUpdateSize, std::memory_order_release); while(!mKillNow.load(std::memory_order_relaxed)) { -- cgit v1.2.3 From fbe9d42d8a48330bb3ccc3966d1d94b438565f35 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 29 Sep 2023 12:26:17 -0700 Subject: Ensure the WASAPI resample buffer is cleared when mixing starts Otherwise, stopping and restarting without resetting could leave it with invalid pointers. --- alc/backends/wasapi.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index b68439a8..71975b55 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -1129,6 +1129,9 @@ FORCE_ALIGN int WasapiPlayback::mixerProc() const uint frame_size{mFormat.Format.nChannels * mFormat.Format.wBitsPerSample / 8u}; const uint update_size{mOrigUpdateSize}; const UINT32 buffer_len{mOrigBufferSize}; + const void *resbufferptr{}; + + mBufferFilled = 0; while(!mKillNow.load(std::memory_order_relaxed)) { UINT32 written; @@ -1163,22 +1166,15 @@ FORCE_ALIGN int WasapiPlayback::mixerProc() { mDevice->renderSamples(mResampleBuffer.get(), mDevice->UpdateSize, mFormat.Format.nChannels); + resbufferptr = mResampleBuffer.get(); mBufferFilled = mDevice->UpdateSize; } - const void *src{mResampleBuffer.get()}; - uint srclen{mBufferFilled}; - uint got{mResampler->convert(&src, &srclen, buffer, len-done)}; + uint got{mResampler->convert(&resbufferptr, &mBufferFilled, buffer, len-done)}; buffer += got*frame_size; done += got; mPadding.store(written + done, std::memory_order_relaxed); - if(srclen) - { - const char *bsrc{static_cast(src)}; - std::copy(bsrc, bsrc + srclen*frame_size, mResampleBuffer.get()); - } - mBufferFilled = srclen; } } else @@ -1228,6 +1224,7 @@ FORCE_ALIGN int WasapiPlayback::mixerSpatialProc() */ mPadding.store(mOrigBufferSize-mOrigUpdateSize, std::memory_order_release); + mBufferFilled = 0; while(!mKillNow.load(std::memory_order_relaxed)) { if(DWORD res{WaitForSingleObjectEx(mNotifyEvent, 1000, FALSE)}; res != WAIT_OBJECT_0) -- cgit v1.2.3 From 014fb03d8353c8a495b4df4c44a7f29c93adba79 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 29 Sep 2023 13:29:51 -0700 Subject: Add a wrapper for COM initialization This helps ensure COM is initialized and deinitialized in order relative to other objects (e.g. ComPtr). --- alc/backends/dsound.cpp | 12 +++--------- alc/backends/wasapi.cpp | 46 +++++++++++++++++++++------------------------- common/comptr.h | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 34 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/dsound.cpp b/alc/backends/dsound.cpp index b5596f1c..58aa69b2 100644 --- a/alc/backends/dsound.cpp +++ b/alc/backends/dsound.cpp @@ -307,12 +307,10 @@ void DSoundPlayback::open(std::string_view name) if(PlaybackDevices.empty()) { /* Initialize COM to prevent name truncation */ - HRESULT hrcom{CoInitialize(nullptr)}; + ComWrapper com{}; hr = DirectSoundEnumerateW(DSoundEnumDevices, &PlaybackDevices); if(FAILED(hr)) ERR("Error enumerating DirectSound devices (0x%lx)!\n", hr); - if(SUCCEEDED(hrcom)) - CoUninitialize(); } const GUID *guid{nullptr}; @@ -583,12 +581,10 @@ void DSoundCapture::open(std::string_view name) if(CaptureDevices.empty()) { /* Initialize COM to prevent name truncation */ - HRESULT hrcom{CoInitialize(nullptr)}; + ComWrapper com{}; hr = DirectSoundCaptureEnumerateW(DSoundEnumDevices, &CaptureDevices); if(FAILED(hr)) ERR("Error enumerating DirectSound devices (0x%lx)!\n", hr); - if(SUCCEEDED(hrcom)) - CoUninitialize(); } const GUID *guid{nullptr}; @@ -815,8 +811,8 @@ std::string DSoundBackendFactory::probe(BackendType type) }; /* Initialize COM to prevent name truncation */ + ComWrapper com{}; HRESULT hr; - HRESULT hrcom{CoInitialize(nullptr)}; switch(type) { case BackendType::Playback: @@ -835,8 +831,6 @@ std::string DSoundBackendFactory::probe(BackendType type) std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device); break; } - if(SUCCEEDED(hrcom)) - CoUninitialize(); return outnames; } diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 71975b55..62c4c58a 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -973,15 +973,15 @@ int WasapiProxy::messageHandler(std::promise *promise) { TRACE("Starting message thread\n"); - HRESULT hr{CoInitializeEx(nullptr, COINIT_MULTITHREADED)}; - if(FAILED(hr)) + ComWrapper com{COINIT_MULTITHREADED}; + if(!com) { - WARN("Failed to initialize COM: 0x%08lx\n", hr); - promise->set_value(hr); + WARN("Failed to initialize COM: 0x%08lx\n", com.status()); + promise->set_value(com.status()); return 0; } - hr = sDeviceHelper.emplace().init(); + HRESULT hr{sDeviceHelper.emplace().init()}; promise->set_value(hr); promise = nullptr; if(FAILED(hr)) @@ -1040,7 +1040,6 @@ int WasapiProxy::messageHandler(std::promise *promise) skip_loop: sDeviceHelper.reset(); - CoUninitialize(); return 0; } @@ -1113,11 +1112,11 @@ WasapiPlayback::~WasapiPlayback() FORCE_ALIGN int WasapiPlayback::mixerProc() { - HRESULT hr{CoInitializeEx(nullptr, COINIT_MULTITHREADED)}; - if(FAILED(hr)) + ComWrapper com{COINIT_MULTITHREADED}; + if(!com) { - ERR("CoInitializeEx(nullptr, COINIT_MULTITHREADED) failed: 0x%08lx\n", hr); - mDevice->handleDisconnect("COM init failed: 0x%08lx", hr); + ERR("CoInitializeEx(nullptr, COINIT_MULTITHREADED) failed: 0x%08lx\n", com.status()); + mDevice->handleDisconnect("COM init failed: 0x%08lx", com.status()); return 1; } @@ -1135,7 +1134,7 @@ FORCE_ALIGN int WasapiPlayback::mixerProc() while(!mKillNow.load(std::memory_order_relaxed)) { UINT32 written; - hr = audio.mClient->GetCurrentPadding(&written); + HRESULT hr{audio.mClient->GetCurrentPadding(&written)}; if(FAILED(hr)) { ERR("Failed to get padding: 0x%08lx\n", hr); @@ -1194,17 +1193,16 @@ FORCE_ALIGN int WasapiPlayback::mixerProc() } mPadding.store(0u, std::memory_order_release); - CoUninitialize(); return 0; } FORCE_ALIGN int WasapiPlayback::mixerSpatialProc() { - HRESULT hr{CoInitializeEx(nullptr, COINIT_MULTITHREADED)}; - if(FAILED(hr)) + ComWrapper com{COINIT_MULTITHREADED}; + if(!com) { - ERR("CoInitializeEx(nullptr, COINIT_MULTITHREADED) failed: 0x%08lx\n", hr); - mDevice->handleDisconnect("COM init failed: 0x%08lx", hr); + ERR("CoInitializeEx(nullptr, COINIT_MULTITHREADED) failed: 0x%08lx\n", com.status()); + mDevice->handleDisconnect("COM init failed: 0x%08lx", com.status()); return 1; } @@ -1231,7 +1229,7 @@ FORCE_ALIGN int WasapiPlayback::mixerSpatialProc() { ERR("WaitForSingleObjectEx error: 0x%lx\n", res); - hr = audio.mRender->Reset(); + HRESULT hr{audio.mRender->Reset()}; if(FAILED(hr)) { ERR("ISpatialAudioObjectRenderStream::Reset failed: 0x%08lx\n", hr); @@ -1241,7 +1239,7 @@ FORCE_ALIGN int WasapiPlayback::mixerSpatialProc() } UINT32 dynamicCount{}, framesToDo{}; - hr = audio.mRender->BeginUpdatingAudioObjects(&dynamicCount, &framesToDo); + HRESULT hr{audio.mRender->BeginUpdatingAudioObjects(&dynamicCount, &framesToDo)}; if(SUCCEEDED(hr)) { if(channels.empty()) UNLIKELY @@ -1310,7 +1308,6 @@ FORCE_ALIGN int WasapiPlayback::mixerSpatialProc() } mPadding.store(0u, std::memory_order_release); - CoUninitialize(); return 0; } @@ -2150,11 +2147,11 @@ WasapiCapture::~WasapiCapture() FORCE_ALIGN int WasapiCapture::recordProc() { - HRESULT hr{CoInitializeEx(nullptr, COINIT_MULTITHREADED)}; - if(FAILED(hr)) + ComWrapper com{COINIT_MULTITHREADED}; + if(!com) { - ERR("CoInitializeEx(nullptr, COINIT_MULTITHREADED) failed: 0x%08lx\n", hr); - mDevice->handleDisconnect("COM init failed: 0x%08lx", hr); + ERR("CoInitializeEx(nullptr, COINIT_MULTITHREADED) failed: 0x%08lx\n", com.status()); + mDevice->handleDisconnect("COM init failed: 0x%08lx", com.status()); return 1; } @@ -2164,7 +2161,7 @@ FORCE_ALIGN int WasapiCapture::recordProc() while(!mKillNow.load(std::memory_order_relaxed)) { UINT32 avail; - hr = mCapture->GetNextPacketSize(&avail); + HRESULT hr{mCapture->GetNextPacketSize(&avail)}; if(FAILED(hr)) ERR("Failed to get next packet size: 0x%08lx\n", hr); else if(avail > 0) @@ -2235,7 +2232,6 @@ FORCE_ALIGN int WasapiCapture::recordProc() ERR("WaitForSingleObjectEx error: 0x%lx\n", res); } - CoUninitialize(); return 0; } diff --git a/common/comptr.h b/common/comptr.h index 5a733ea2..9f8fd294 100644 --- a/common/comptr.h +++ b/common/comptr.h @@ -7,6 +7,44 @@ #include #include +#define WIN32_LEAN_AND_MEAN +#include +#include + +struct ComWrapper { + HRESULT mStatus{}; + + ComWrapper(void *reserved, DWORD coinit) + : mStatus{CoInitializeEx(reserved, coinit)} + { } + ComWrapper(DWORD coinit=COINIT_APARTMENTTHREADED) + : mStatus{CoInitializeEx(nullptr, coinit)} + { } + ComWrapper(ComWrapper&& rhs) { mStatus = std::exchange(rhs.mStatus, E_FAIL); } + ComWrapper(const ComWrapper&) = delete; + ~ComWrapper() { if(SUCCEEDED(mStatus)) CoUninitialize(); } + + ComWrapper& operator=(ComWrapper&& rhs) + { + if(SUCCEEDED(mStatus)) + CoUninitialize(); + mStatus = std::exchange(rhs.mStatus, E_FAIL); + return *this; + } + ComWrapper& operator=(const ComWrapper&) = delete; + + HRESULT status() const noexcept { return mStatus; } + explicit operator bool() const noexcept { return SUCCEEDED(status()); } + + void uninit() + { + if(SUCCEEDED(mStatus)) + CoUninitialize(); + mStatus = E_FAIL; + } +}; + + template struct ComPtr { using element_type = T; -- cgit v1.2.3 From cd09bd95ca655011cf1654f1cd8775f3edbcbb71 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 1 Oct 2023 14:47:14 -0700 Subject: Get the default WASAPI device on UWP --- alc/backends/wasapi.cpp | 39 ++++++++++++++------------------------- 1 file changed, 14 insertions(+), 25 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 62c4c58a..b6d7aaed 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -110,9 +110,9 @@ using std::chrono::nanoseconds; using std::chrono::milliseconds; using std::chrono::seconds; -using ReferenceTime = std::chrono::duration>; +using ReferenceTime = std::chrono::duration>; -inline constexpr ReferenceTime operator "" _reftime(unsigned long long int n) noexcept +constexpr ReferenceTime operator "" _reftime(unsigned long long int n) noexcept { return ReferenceTime{static_cast(n)}; } @@ -185,7 +185,7 @@ overloaded(Ts...) -> overloaded; template -auto as_unsigned(T value) noexcept +constexpr auto as_unsigned(T value) noexcept { using UT = std::make_unsigned_t; return static_cast(value); @@ -248,9 +248,9 @@ struct DevMap { }; DevMap::~DevMap() = default; -bool checkName(const al::span list, const std::string &name) +bool checkName(const al::span list, const std::string_view name) { - auto match_name = [&name](const DevMap &entry) -> bool { return entry.name == name; }; + auto match_name = [name](const DevMap &entry) -> bool { return entry.name == name; }; return std::find_if(list.cbegin(), list.cend(), match_name) != list.cend(); } @@ -309,7 +309,7 @@ static NameGUIDPair GetDeviceNameAndGuid(const DeviceHandle &device) std::string name, guid; ComPtr ps; - HRESULT hr = device->OpenPropertyStore(STGM_READ, al::out_ptr(ps)); + HRESULT hr{device->OpenPropertyStore(STGM_READ, al::out_ptr(ps))}; if(FAILED(hr)) { WARN("OpenPropertyStore failed: 0x%08lx\n", hr); @@ -319,32 +319,20 @@ static NameGUIDPair GetDeviceNameAndGuid(const DeviceHandle &device) PropVariant pvprop; hr = ps->GetValue(al::bit_cast(DEVPKEY_Device_FriendlyName), pvprop.get()); if(FAILED(hr)) - { WARN("GetValue Device_FriendlyName failed: 0x%08lx\n", hr); - name = UnknownName; - } else if(pvprop->vt == VT_LPWSTR) name = wstr_to_utf8(pvprop->pwszVal); else - { WARN("Unexpected Device_FriendlyName PROPVARIANT type: 0x%04x\n", pvprop->vt); - name = UnknownName; - } pvprop.clear(); hr = ps->GetValue(al::bit_cast(PKEY_AudioEndpoint_GUID), pvprop.get()); if(FAILED(hr)) - { WARN("GetValue AudioEndpoint_GUID failed: 0x%08lx\n", hr); - guid = UnknownGuid; - } else if(pvprop->vt == VT_LPWSTR) guid = wstr_to_utf8(pvprop->pwszVal); else - { WARN("Unexpected AudioEndpoint_GUID PROPVARIANT type: 0x%04x\n", pvprop->vt); - guid = UnknownGuid; - } #else std::string name{wstr_to_utf8(device.Name())}; std::string guid; @@ -361,9 +349,9 @@ static NameGUIDPair GetDeviceNameAndGuid(const DeviceHandle &device) [](char ch) { return static_cast(std::toupper(ch)); }); } } +#endif if(name.empty()) name = UnknownName; if(guid.empty()) guid = UnknownGuid; -#endif return std::make_pair(std::move(name), std::move(guid)); } #if !defined(ALSOFT_UWP) @@ -722,12 +710,13 @@ struct DeviceHelper final : private IMMNotificationClient const auto deviceRole = Windows::Media::Devices::AudioDeviceRole::Default; auto DefaultAudioId = flowdir == eRender ? MediaDevice::GetDefaultAudioRenderId(deviceRole) : MediaDevice::GetDefaultAudioCaptureId(deviceRole); - if (DefaultAudioId.empty()) - return defaultId; - - auto deviceInfo = DeviceInformation::CreateFromIdAsync(DefaultAudioId, nullptr, DeviceInformationKind::DeviceInterface).get(); - if(!deviceInfo) - return defaultId; + if(!DefaultAudioId.empty()) + { + auto deviceInfo = DeviceInformation::CreateFromIdAsync(DefaultAudioId, nullptr, + DeviceInformationKind::DeviceInterface).get(); + if(deviceInfo) + defaultId = deviceInfo.Id().data(); + } // Get the string identifier of the audio renderer auto AudioSelector = flowdir == eRender ? MediaDevice::GetAudioRenderSelector() : MediaDevice::GetAudioCaptureSelector(); -- cgit v1.2.3 From 32b89db9aee9b30ce37469a670750bfeb63e57c9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 1 Oct 2023 23:20:08 -0700 Subject: Declare a missing variable --- alc/backends/wasapi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'alc/backends') diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index b6d7aaed..37151ef9 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -729,7 +729,7 @@ struct DeviceHelper final : private IMMNotificationClient auto deviceCount = DeviceInfoCollection.Size(); for(unsigned int i{0};i < deviceCount;++i) { - deviceInfo = DeviceInfoCollection.GetAt(i); + auto deviceInfo = DeviceInfoCollection.GetAt(i); if(deviceInfo) std::ignore = AddDevice(deviceInfo, deviceInfo.Id().data(), list); } -- cgit v1.2.3 From b8645438006de7e0a19ec4abe1c3314fec97c209 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 21 Oct 2023 21:03:44 -0700 Subject: Use a dynamically resizing spa_pod_builder Rather than relying on a fixed-size buffer --- alc/backends/pipewire.cpp | 61 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 14 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/pipewire.cpp b/alc/backends/pipewire.cpp index 1c4e2cc4..6cfb31a4 100644 --- a/alc/backends/pipewire.cpp +++ b/alc/backends/pipewire.cpp @@ -109,12 +109,12 @@ template constexpr auto get_pod_body(const spa_pod *pod) noexcept { return al::span{static_cast(SPA_POD_BODY(pod)), N}; } -constexpr auto make_pod_builder(void *data, uint32_t size) noexcept -{ return SPA_POD_BUILDER_INIT(data, size); } - constexpr auto get_array_value_type(const spa_pod *pod) noexcept { return SPA_POD_ARRAY_VALUE_TYPE(pod); } +constexpr auto make_pod_builder(void *data, uint32_t size) noexcept +{ return SPA_POD_BUILDER_INIT(data, size); } + constexpr auto PwIdAny = PW_ID_ANY; } // namespace @@ -122,6 +122,44 @@ _Pragma("GCC diagnostic pop") namespace { +struct PodDynamicBuilder { +private: + std::vector mStorage; + spa_pod_builder mPod{}; + + int overflow(uint32_t size) noexcept + { + try { + mStorage.resize(size); + } + catch(...) { + ERR("Failed to resize POD storage\n"); + return -ENOMEM; + } + mPod.data = mStorage.data(); + mPod.size = size; + return 0; + } + +public: + PodDynamicBuilder(uint32_t initSize=0) : mStorage(initSize) + , mPod{make_pod_builder(mStorage.data(), initSize)} + { + static constexpr auto callbacks{[] + { + spa_pod_builder_callbacks cb{}; + cb.version = SPA_VERSION_POD_BUILDER_CALLBACKS; + cb.overflow = [](void *data, uint32_t size) noexcept + { return static_cast(data)->overflow(size); }; + return cb; + }()}; + + spa_pod_builder_set_callbacks(&mPod, &callbacks, this); + } + + spa_pod_builder *get() noexcept { return &mPod; } +}; + /* Added in 0.3.33, but we currently only require 0.3.23. */ #ifndef PW_KEY_NODE_RATE #define PW_KEY_NODE_RATE "node.rate" @@ -1592,14 +1630,10 @@ bool PipeWirePlayback::reset() */ spa_audio_info_raw info{make_spa_info(mDevice, is51rear, ForceF32Planar)}; - /* TODO: How to tell what an appropriate size is? Examples just use this - * magic value. - */ - constexpr uint32_t pod_buffer_size{1024}; - auto pod_buffer = std::make_unique(pod_buffer_size); - spa_pod_builder b{make_pod_builder(pod_buffer.get(), pod_buffer_size)}; + static constexpr uint32_t pod_buffer_size{1024}; + PodDynamicBuilder b(pod_buffer_size); - const spa_pod *params{spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &info)}; + const spa_pod *params{spa_format_audio_raw_build(b.get(), SPA_PARAM_EnumFormat, &info)}; if(!params) throw al::backend_exception{al::backend_error::DeviceError, "Failed to set PipeWire audio format parameters"}; @@ -2021,11 +2055,10 @@ void PipeWireCapture::open(std::string_view name) } spa_audio_info_raw info{make_spa_info(mDevice, is51rear, UseDevType)}; - constexpr uint32_t pod_buffer_size{1024}; - auto pod_buffer = std::make_unique(pod_buffer_size); - spa_pod_builder b{make_pod_builder(pod_buffer.get(), pod_buffer_size)}; + static constexpr uint32_t pod_buffer_size{1024}; + PodDynamicBuilder b(pod_buffer_size); - const spa_pod *params[]{spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &info)}; + const spa_pod *params[]{spa_format_audio_raw_build(b.get(), SPA_PARAM_EnumFormat, &info)}; if(!params[0]) throw al::backend_exception{al::backend_error::DeviceError, "Failed to set PipeWire audio format parameters"}; -- cgit v1.2.3 From c03603b58d4cf6a25d36bca00305970bc9f163b4 Mon Sep 17 00:00:00 2001 From: MathiusD Date: Sun, 26 Nov 2023 03:33:00 +0100 Subject: Add query fonction in ALC_SOFT_system_events unreleased extension (#938) * feat(ALC_SOFT_system_events): Add alcEventIsSupportedSOFT method in ALC_SOFT_system_events unreleased extension The purpose of this addition (to my collection) are allow to retrieve which events are supported and if events are fully supported or if some case isn't managed for some reason For exemple only some backends provide system events: * pipewire -> Full support of extension * wasapi -> Full support of extension * pulseaudio -> Support of add and remove devices events only * coreaudio -> Support of default device change only * feat(ALC_SOFT_system_events): Fix typo in alext.h Cf following review : https://github.com/kcat/openal-soft/pull/938#discussion_r1404509828 * feat(ALC_SOFT_system_events): Remove ALC_EVENT_NOT_SUPPORTED_SOFT token Cf following discussions between this comment : https://github.com/kcat/openal-soft/pull/938#issuecomment-1825876452 to this comment : https://github.com/kcat/openal-soft/pull/938#issuecomment-1826419406 --- alc/alc.cpp | 40 +++++++++++++++++++++++++++++++++++ alc/backends/base.h | 5 +++++ alc/backends/coreaudio.cpp | 11 +++++++++- alc/backends/coreaudio.h | 2 ++ alc/backends/pipewire.cpp | 17 ++++++++++++++- alc/backends/pipewire.h | 2 ++ alc/backends/pulseaudio.cpp | 14 ++++++++++++- alc/backends/pulseaudio.h | 2 ++ alc/backends/wasapi.cpp | 17 ++++++++++++++- alc/backends/wasapi.h | 2 ++ alc/events.cpp | 26 +++++++++++------------ alc/events.h | 8 +++++++ alc/export_list.h | 1 + include/AL/alext.h | 4 ++++ utils/openal-info.c | 51 +++++++++++++++++++++++++++++++++++++++++++++ 15 files changed, 184 insertions(+), 18 deletions(-) (limited to 'alc/backends') diff --git a/alc/alc.cpp b/alc/alc.cpp index 08ef0063..be41f278 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -69,6 +69,7 @@ #include "al/filter.h" #include "al/listener.h" #include "al/source.h" +#include "alc/events.h" #include "albit.h" #include "alconfig.h" #include "almalloc.h" @@ -3469,3 +3470,42 @@ FORCE_ALIGN ALCboolean ALC_APIENTRY alcReopenDeviceSOFT(ALCdevice *device, ResetDeviceParams(dev.get(), attribs); return ALC_TRUE; } + +/************************************************ + * ALC event query functions + ************************************************/ + +FORCE_ALIGN ALCenum ALC_APIENTRY alcEventIsSupportedSOFT(ALCenum eventType, ALCenum deviceType) noexcept +{ + auto etype = alc::GetEventType(eventType); + if(!etype) + { + WARN("Invalid event type: 0x%04x\n", eventType); + alcSetError(nullptr, ALC_INVALID_ENUM); + return ALC_EVENT_NOT_SUPPORTED_SOFT; + } + switch(deviceType) + { + case al::to_underlying(alc::DeviceType::Playback): + { + if(!PlaybackFactory) + { + return ALC_EVENT_NOT_SUPPORTED_SOFT; + } + + auto supported = PlaybackFactory->queryEventSupport(*etype, BackendType::Playback); + return al::to_underlying(supported); + } + case al::to_underlying(alc::DeviceType::Capture): + { + if(!CaptureFactory) + { + return ALC_EVENT_NOT_SUPPORTED_SOFT; + } + + auto supported = CaptureFactory->queryEventSupport(*etype, BackendType::Capture); + return al::to_underlying(supported); + } + } + return ALC_EVENT_NOT_SUPPORTED_SOFT; +} \ No newline at end of file diff --git a/alc/backends/base.h b/alc/backends/base.h index a4079fe4..ea3b57a3 100644 --- a/alc/backends/base.h +++ b/alc/backends/base.h @@ -11,6 +11,7 @@ #include "core/device.h" #include "core/except.h" +#include "alc/events.h" using uint = unsigned int; @@ -79,6 +80,10 @@ struct BackendFactory { virtual bool querySupport(BackendType type) = 0; + virtual alc::EventSupport queryEventSupport(alc::EventType eventType, BackendType type) { + return alc::EventSupport::NoSupport; + } + virtual std::string probe(BackendType type) = 0; virtual BackendPtr createBackend(DeviceBase *device, BackendType type) = 0; diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index 1684545b..eb4e5880 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -39,7 +39,6 @@ #include "core/device.h" #include "core/logging.h" #include "ringbuffer.h" -#include "alc/events.h" #include #include @@ -1013,3 +1012,13 @@ BackendPtr CoreAudioBackendFactory::createBackend(DeviceBase *device, BackendTyp return BackendPtr{new CoreAudioCapture{device}}; return nullptr; } + +alc::EventSupport CoreAudioBackendFactory::queryEventSupport(alc::EventType eventType, BackendType type) +{ + switch(eventType) { + case alc::EventType::DefaultDeviceChanged: { + return alc::EventSupport::FullSupport; + } + } + return alc::EventSupport::NoSupport; +} diff --git a/alc/backends/coreaudio.h b/alc/backends/coreaudio.h index 1252edde..6ea4307c 100644 --- a/alc/backends/coreaudio.h +++ b/alc/backends/coreaudio.h @@ -9,6 +9,8 @@ public: bool querySupport(BackendType type) override; + alc::EventSupport queryEventSupport(alc::EventType eventType, BackendType type) override; + std::string probe(BackendType type) override; BackendPtr createBackend(DeviceBase *device, BackendType type) override; diff --git a/alc/backends/pipewire.cpp b/alc/backends/pipewire.cpp index 6cfb31a4..d1a9d095 100644 --- a/alc/backends/pipewire.cpp +++ b/alc/backends/pipewire.cpp @@ -40,7 +40,6 @@ #include "albit.h" #include "alc/alconfig.h" -#include "alc/events.h" #include "almalloc.h" #include "alnumeric.h" #include "alspan.h" @@ -2266,3 +2265,19 @@ BackendFactory &PipeWireBackendFactory::getFactory() static PipeWireBackendFactory factory{}; return factory; } + +alc::EventSupport PipeWireBackendFactory::queryEventSupport(alc::EventType eventType, BackendType type) +{ + switch(eventType) { + case alc::EventType::DefaultDeviceChanged: { + return alc::EventSupport::FullSupport; + } + case alc::EventType::DeviceAdded: { + return alc::EventSupport::FullSupport; + } + case alc::EventType::DeviceRemoved: { + return alc::EventSupport::FullSupport; + } + } + return alc::EventSupport::NoSupport; +} \ No newline at end of file diff --git a/alc/backends/pipewire.h b/alc/backends/pipewire.h index 5f930239..5493684f 100644 --- a/alc/backends/pipewire.h +++ b/alc/backends/pipewire.h @@ -13,6 +13,8 @@ public: bool querySupport(BackendType type) override; + alc::EventSupport queryEventSupport(alc::EventType eventType, BackendType type) override; + std::string probe(BackendType type) override; BackendPtr createBackend(DeviceBase *device, BackendType type) override; diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index e2cea8a8..23ed1415 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -41,7 +41,6 @@ #include "albit.h" #include "alc/alconfig.h" -#include "alc/events.h" #include "almalloc.h" #include "alnumeric.h" #include "alspan.h" @@ -1491,3 +1490,16 @@ BackendFactory &PulseBackendFactory::getFactory() static PulseBackendFactory factory{}; return factory; } + +alc::EventSupport PulseBackendFactory::queryEventSupport(alc::EventType eventType, BackendType type) +{ + switch(eventType) { + case alc::EventType::DeviceAdded: { + return alc::EventSupport::FullSupport; + } + case alc::EventType::DeviceRemoved: { + return alc::EventSupport::FullSupport; + } + } + return alc::EventSupport::NoSupport; +} diff --git a/alc/backends/pulseaudio.h b/alc/backends/pulseaudio.h index 6690fe8a..4752a891 100644 --- a/alc/backends/pulseaudio.h +++ b/alc/backends/pulseaudio.h @@ -9,6 +9,8 @@ public: bool querySupport(BackendType type) override; + alc::EventSupport queryEventSupport(alc::EventType eventType, BackendType type) override; + std::string probe(BackendType type) override; BackendPtr createBackend(DeviceBase *device, BackendType type) override; diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 37151ef9..a4d6ea2f 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -60,7 +60,6 @@ #include "albit.h" #include "alc/alconfig.h" -#include "alc/events.h" #include "alnumeric.h" #include "alspan.h" #include "althrd_setname.h" @@ -2741,3 +2740,19 @@ BackendFactory &WasapiBackendFactory::getFactory() static WasapiBackendFactory factory{}; return factory; } + +alc::EventSupport WasapiBackendFactory::queryEventSupport(alc::EventType eventType, BackendType type) +{ + switch(eventType) { + case alc::EventType::DefaultDeviceChanged: { + return alc::EventSupport::FullSupport; + } + case alc::EventType::DeviceAdded: { + return alc::EventSupport::FullSupport; + } + case alc::EventType::DeviceRemoved: { + return alc::EventSupport::FullSupport; + } + } + return alc::EventSupport::NoSupport; +} diff --git a/alc/backends/wasapi.h b/alc/backends/wasapi.h index bb2671ee..12fd95ef 100644 --- a/alc/backends/wasapi.h +++ b/alc/backends/wasapi.h @@ -9,6 +9,8 @@ public: bool querySupport(BackendType type) override; + alc::EventSupport queryEventSupport(alc::EventType eventType, BackendType type) override; + std::string probe(BackendType type) override; BackendPtr createBackend(DeviceBase *device, BackendType type) override; diff --git a/alc/events.cpp b/alc/events.cpp index a80faf8a..1010a338 100644 --- a/alc/events.cpp +++ b/alc/events.cpp @@ -3,8 +3,6 @@ #include "events.h" -#include - #include "alspan.h" #include "core/logging.h" #include "device.h" @@ -12,17 +10,6 @@ namespace { -std::optional GetEventType(ALCenum type) -{ - switch(type) - { - case ALC_EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT: return alc::EventType::DefaultDeviceChanged; - case ALC_EVENT_TYPE_DEVICE_ADDED_SOFT: return alc::EventType::DeviceAdded; - case ALC_EVENT_TYPE_DEVICE_REMOVED_SOFT: return alc::EventType::DeviceRemoved; - } - return std::nullopt; -} - ALCenum EnumFromEventType(const alc::EventType type) { switch(type) @@ -39,6 +26,17 @@ ALCenum EnumFromEventType(const alc::EventType type) namespace alc { +std::optional GetEventType(ALCenum type) +{ + switch(type) + { + case ALC_EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT: return alc::EventType::DefaultDeviceChanged; + case ALC_EVENT_TYPE_DEVICE_ADDED_SOFT: return alc::EventType::DeviceAdded; + case ALC_EVENT_TYPE_DEVICE_REMOVED_SOFT: return alc::EventType::DeviceRemoved; + } + return std::nullopt; +} + void Event(EventType eventType, DeviceType deviceType, ALCdevice *device, std::string_view message) noexcept { auto eventlock = std::unique_lock{EventMutex}; @@ -73,7 +71,7 @@ FORCE_ALIGN ALCboolean ALC_APIENTRY alcEventControlSOFT(ALCsizei count, const AL alc::EventBitSet eventSet{0}; for(ALCenum type : al::span{events, static_cast(count)}) { - auto etype = GetEventType(type); + auto etype = alc::GetEventType(type); if(!etype) { WARN("Invalid event type: 0x%04x\n", type); diff --git a/alc/events.h b/alc/events.h index 4acc505d..3f53ec76 100644 --- a/alc/events.h +++ b/alc/events.h @@ -6,6 +6,7 @@ #include #include +#include #include @@ -19,6 +20,13 @@ enum class EventType : uint8_t { Count }; +std::optional GetEventType(ALCenum type); + +enum class EventSupport : ALCenum { + FullSupport = ALC_EVENT_SUPPORTED_SOFT, + NoSupport = ALC_EVENT_NOT_SUPPORTED_SOFT, +}; + enum class DeviceType : ALCenum { Playback = ALC_PLAYBACK_DEVICE_SOFT, Capture = ALC_CAPTURE_DEVICE_SOFT, diff --git a/alc/export_list.h b/alc/export_list.h index 47b04a08..c5af1ab0 100644 --- a/alc/export_list.h +++ b/alc/export_list.h @@ -56,6 +56,7 @@ inline const FuncExport alcFunctions[]{ DECL(alcReopenDeviceSOFT), + DECL(alcEventIsSupportedSOFT), DECL(alcEventControlSOFT), DECL(alcEventCallbackSOFT), diff --git a/include/AL/alext.h b/include/AL/alext.h index b99d6aac..c75e0770 100644 --- a/include/AL/alext.h +++ b/include/AL/alext.h @@ -720,11 +720,15 @@ void AL_APIENTRY alGetObjectLabelEXT(ALenum identifier, ALuint name, ALsizei buf #define ALC_EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT 0x19D6 #define ALC_EVENT_TYPE_DEVICE_ADDED_SOFT 0x19D7 #define ALC_EVENT_TYPE_DEVICE_REMOVED_SOFT 0x19D8 +#define ALC_EVENT_SUPPORTED_SOFT 0x19D9 +#define ALC_EVENT_NOT_SUPPORTED_SOFT 0x19DA typedef void (ALC_APIENTRY*ALCEVENTPROCTYPESOFT)(ALCenum eventType, ALCenum deviceType, ALCdevice *device, ALCsizei length, const ALCchar *message, void *userParam) ALC_API_NOEXCEPT17; +typedef ALCenum (ALC_APIENTRY*LPALCEVENTISSUPPORTEDSOFT)(ALCenum eventType, ALCenum deviceType) ALC_API_NOEXCEPT17; typedef ALCboolean (ALC_APIENTRY*LPALCEVENTCONTROLSOFT)(ALCsizei count, const ALCenum *events, ALCboolean enable) ALC_API_NOEXCEPT17; typedef void (ALC_APIENTRY*LPALCEVENTCALLBACKSOFT)(ALCEVENTPROCTYPESOFT callback, void *userParam) ALC_API_NOEXCEPT17; #ifdef AL_ALEXT_PROTOTYPES +ALCenum ALC_APIENTRY alcEventIsSupportedSOFT(ALCenum eventType, ALCenum deviceType) ALC_API_NOEXCEPT; ALCboolean ALC_APIENTRY alcEventControlSOFT(ALCsizei count, const ALCenum *events, ALCboolean enable) ALC_API_NOEXCEPT; void ALC_APIENTRY alcEventCallbackSOFT(ALCEVENTPROCTYPESOFT callback, void *userParam) ALC_API_NOEXCEPT; #endif diff --git a/utils/openal-info.c b/utils/openal-info.c index 0af27422..11c49245 100644 --- a/utils/openal-info.c +++ b/utils/openal-info.c @@ -230,6 +230,56 @@ static void printModeInfo(ALCdevice *device) } } +static void printALCSOFTSystemEventIsSupportedResult(LPALCEVENTISSUPPORTEDSOFT alcEventIsSupportedSOFT, ALCenum eventType, ALCenum deviceType) +{ + if (alcEventIsSupportedSOFT == NULL) + { + printf("ERROR (alcEventIsSupportedSOFT missing)\n"); + return; + } + ALCenum supported = alcEventIsSupportedSOFT(eventType, deviceType); + if (supported == ALC_EVENT_SUPPORTED_SOFT) + { + printf("SUPPORTED\n"); + } + else if (supported == ALC_EVENT_NOT_SUPPORTED_SOFT) + { + printf("NOT SUPPORTED\n"); + } + else + { + printf("UNEXPECTED VALUE : %d\n", supported); + } +} + +static void printALC_SOFT_system_event(void) +{ + printf("ALC_SOFT_system_events:"); + if (alcIsExtensionPresent(NULL, "ALC_SOFT_system_events")) + { + static LPALCEVENTISSUPPORTEDSOFT alcEventIsSupportedSOFT; + alcEventIsSupportedSOFT = FUNCTION_CAST(LPALCEVENTISSUPPORTEDSOFT, alGetProcAddress("alcEventIsSupportedSOFT")); + printf(" Supported.\n"); + printf(" Events:\n"); + printf(" ALC_EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT for ALC_PLAYBACK_DEVICE_SOFT - "); + printALCSOFTSystemEventIsSupportedResult(alcEventIsSupportedSOFT, ALC_EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT, ALC_PLAYBACK_DEVICE_SOFT); + printf(" ALC_EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT for ALC_CAPTURE_DEVICE_SOFT - "); + printALCSOFTSystemEventIsSupportedResult(alcEventIsSupportedSOFT, ALC_EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT, ALC_CAPTURE_DEVICE_SOFT); + printf(" ALC_EVENT_TYPE_DEVICE_ADDED_SOFT for ALC_PLAYBACK_DEVICE_SOFT - "); + printALCSOFTSystemEventIsSupportedResult(alcEventIsSupportedSOFT, ALC_EVENT_TYPE_DEVICE_ADDED_SOFT, ALC_PLAYBACK_DEVICE_SOFT); + printf(" ALC_EVENT_TYPE_DEVICE_ADDED_SOFT for ALC_CAPTURE_DEVICE_SOFT - "); + printALCSOFTSystemEventIsSupportedResult(alcEventIsSupportedSOFT, ALC_EVENT_TYPE_DEVICE_ADDED_SOFT, ALC_CAPTURE_DEVICE_SOFT); + printf(" ALC_EVENT_TYPE_DEVICE_REMOVED_SOFT for ALC_PLAYBACK_DEVICE_SOFT - "); + printALCSOFTSystemEventIsSupportedResult(alcEventIsSupportedSOFT, ALC_EVENT_TYPE_DEVICE_REMOVED_SOFT, ALC_PLAYBACK_DEVICE_SOFT); + printf(" ALC_EVENT_TYPE_DEVICE_REMOVED_SOFT for ALC_CAPTURE_DEVICE_SOFT - "); + printALCSOFTSystemEventIsSupportedResult(alcEventIsSupportedSOFT, ALC_EVENT_TYPE_DEVICE_REMOVED_SOFT, ALC_CAPTURE_DEVICE_SOFT); + } + else + { + printf(" Not supported.\n"); + } +} + static void printALInfo(void) { printf("OpenAL vendor string: %s\n", alGetString(AL_VENDOR)); @@ -435,6 +485,7 @@ int main(int argc, char *argv[]) } printALCInfo(device); printHRTFInfo(device); + printALC_SOFT_system_event(); context = alcCreateContext(device, NULL); if(!context || alcMakeContextCurrent(context) == ALC_FALSE) -- cgit v1.2.3 From 2a27a2ca5ea0f6b6b8fff065212959ea60021647 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 25 Nov 2023 18:58:00 -0800 Subject: Fix some unused parameter and unhandled enum warnings --- alc/alc.cpp | 35 +++++++++++++++-------------------- alc/backends/base.h | 5 ++--- alc/backends/coreaudio.cpp | 15 ++++++++++----- alc/backends/pipewire.cpp | 23 +++++++++++------------ alc/backends/pulseaudio.cpp | 18 ++++++++++-------- alc/backends/wasapi.cpp | 25 ++++++++++++++----------- 6 files changed, 62 insertions(+), 59 deletions(-) (limited to 'alc/backends') diff --git a/alc/alc.cpp b/alc/alc.cpp index be41f278..6017e743 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -3484,28 +3484,23 @@ FORCE_ALIGN ALCenum ALC_APIENTRY alcEventIsSupportedSOFT(ALCenum eventType, ALCe alcSetError(nullptr, ALC_INVALID_ENUM); return ALC_EVENT_NOT_SUPPORTED_SOFT; } + + auto supported = alc::EventSupport::NoSupport; switch(deviceType) { - case al::to_underlying(alc::DeviceType::Playback): - { - if(!PlaybackFactory) - { - return ALC_EVENT_NOT_SUPPORTED_SOFT; - } + case ALC_PLAYBACK_DEVICE_SOFT: + if(PlaybackFactory) + supported = PlaybackFactory->queryEventSupport(*etype, BackendType::Playback); + break; - auto supported = PlaybackFactory->queryEventSupport(*etype, BackendType::Playback); - return al::to_underlying(supported); - } - case al::to_underlying(alc::DeviceType::Capture): - { - if(!CaptureFactory) - { - return ALC_EVENT_NOT_SUPPORTED_SOFT; - } + case ALC_CAPTURE_DEVICE_SOFT: + if(CaptureFactory) + supported = CaptureFactory->queryEventSupport(*etype, BackendType::Capture); + break; - auto supported = CaptureFactory->queryEventSupport(*etype, BackendType::Capture); - return al::to_underlying(supported); - } + default: + WARN("Invalid device type: 0x%04x\n", deviceType); + alcSetError(nullptr, ALC_INVALID_ENUM); } - return ALC_EVENT_NOT_SUPPORTED_SOFT; -} \ No newline at end of file + return al::to_underlying(supported); +} diff --git a/alc/backends/base.h b/alc/backends/base.h index ea3b57a3..eea0d238 100644 --- a/alc/backends/base.h +++ b/alc/backends/base.h @@ -80,9 +80,8 @@ struct BackendFactory { virtual bool querySupport(BackendType type) = 0; - virtual alc::EventSupport queryEventSupport(alc::EventType eventType, BackendType type) { - return alc::EventSupport::NoSupport; - } + virtual alc::EventSupport queryEventSupport(alc::EventType, BackendType) + { return alc::EventSupport::NoSupport; } virtual std::string probe(BackendType type) = 0; diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index eb4e5880..16b0781e 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -1013,12 +1013,17 @@ BackendPtr CoreAudioBackendFactory::createBackend(DeviceBase *device, BackendTyp return nullptr; } -alc::EventSupport CoreAudioBackendFactory::queryEventSupport(alc::EventType eventType, BackendType type) +alc::EventSupport CoreAudioBackendFactory::queryEventSupport(alc::EventType eventType, BackendType) { - switch(eventType) { - case alc::EventType::DefaultDeviceChanged: { - return alc::EventSupport::FullSupport; - } + switch(eventType) + { + case alc::EventType::DefaultDeviceChanged: + return alc::EventSupport::FullSupport; + + case alc::EventType::DeviceAdded: + case alc::EventType::DeviceRemoved: + case alc::EventType::Count: + break; } return alc::EventSupport::NoSupport; } diff --git a/alc/backends/pipewire.cpp b/alc/backends/pipewire.cpp index d1a9d095..6a001d7a 100644 --- a/alc/backends/pipewire.cpp +++ b/alc/backends/pipewire.cpp @@ -2266,18 +2266,17 @@ BackendFactory &PipeWireBackendFactory::getFactory() return factory; } -alc::EventSupport PipeWireBackendFactory::queryEventSupport(alc::EventType eventType, BackendType type) +alc::EventSupport PipeWireBackendFactory::queryEventSupport(alc::EventType eventType, BackendType) { - switch(eventType) { - case alc::EventType::DefaultDeviceChanged: { - return alc::EventSupport::FullSupport; - } - case alc::EventType::DeviceAdded: { - return alc::EventSupport::FullSupport; - } - case alc::EventType::DeviceRemoved: { - return alc::EventSupport::FullSupport; - } + switch(eventType) + { + case alc::EventType::DefaultDeviceChanged: + case alc::EventType::DeviceAdded: + case alc::EventType::DeviceRemoved: + return alc::EventSupport::FullSupport; + + case alc::EventType::Count: + break; } return alc::EventSupport::NoSupport; -} \ No newline at end of file +} diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index 23ed1415..bebc182d 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -1491,15 +1491,17 @@ BackendFactory &PulseBackendFactory::getFactory() return factory; } -alc::EventSupport PulseBackendFactory::queryEventSupport(alc::EventType eventType, BackendType type) +alc::EventSupport PulseBackendFactory::queryEventSupport(alc::EventType eventType, BackendType) { - switch(eventType) { - case alc::EventType::DeviceAdded: { - return alc::EventSupport::FullSupport; - } - case alc::EventType::DeviceRemoved: { - return alc::EventSupport::FullSupport; - } + switch(eventType) + { + case alc::EventType::DeviceAdded: + case alc::EventType::DeviceRemoved: + return alc::EventSupport::FullSupport; + + case alc::EventType::DefaultDeviceChanged: + case alc::EventType::Count: + break; } return alc::EventSupport::NoSupport; } diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index a4d6ea2f..3ee98457 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -2741,18 +2741,21 @@ BackendFactory &WasapiBackendFactory::getFactory() return factory; } -alc::EventSupport WasapiBackendFactory::queryEventSupport(alc::EventType eventType, BackendType type) +alc::EventSupport WasapiBackendFactory::queryEventSupport(alc::EventType eventType, BackendType) { - switch(eventType) { - case alc::EventType::DefaultDeviceChanged: { - return alc::EventSupport::FullSupport; - } - case alc::EventType::DeviceAdded: { - return alc::EventSupport::FullSupport; - } - case alc::EventType::DeviceRemoved: { - return alc::EventSupport::FullSupport; - } + switch(eventType) + { + case alc::EventType::DefaultDeviceChanged: + return alc::EventSupport::FullSupport; + + case alc::EventType::DeviceAdded: + case alc::EventType::DeviceRemoved: +#if !defined(ALSOFT_UWP) + return alc::EventSupport::FullSupport; +#endif + + case alc::EventType::Count: + break; } return alc::EventSupport::NoSupport; } -- cgit v1.2.3