diff options
Diffstat (limited to 'alc/backends')
-rw-r--r-- | alc/backends/alsa.cpp | 121 | ||||
-rw-r--r-- | alc/backends/base.cpp | 9 | ||||
-rw-r--r-- | alc/backends/base.h | 23 | ||||
-rw-r--r-- | alc/backends/coreaudio.cpp | 8 | ||||
-rw-r--r-- | alc/backends/dsound.cpp | 16 | ||||
-rw-r--r-- | alc/backends/jack.cpp | 47 | ||||
-rw-r--r-- | alc/backends/loopback.cpp | 2 | ||||
-rw-r--r-- | alc/backends/null.cpp | 3 | ||||
-rw-r--r-- | alc/backends/oboe.cpp | 13 | ||||
-rw-r--r-- | alc/backends/opensl.cpp | 77 | ||||
-rw-r--r-- | alc/backends/oss.cpp | 28 | ||||
-rw-r--r-- | alc/backends/pipewire.cpp | 132 | ||||
-rw-r--r-- | alc/backends/portaudio.cpp | 74 | ||||
-rw-r--r-- | alc/backends/pulseaudio.cpp | 75 | ||||
-rw-r--r-- | alc/backends/sdl2.cpp | 27 | ||||
-rw-r--r-- | alc/backends/sndio.cpp | 164 | ||||
-rw-r--r-- | alc/backends/solaris.cpp | 20 | ||||
-rw-r--r-- | alc/backends/wasapi.cpp | 62 | ||||
-rw-r--r-- | alc/backends/wave.cpp | 117 | ||||
-rw-r--r-- | alc/backends/winmm.cpp | 36 |
20 files changed, 474 insertions, 580 deletions
diff --git a/alc/backends/alsa.cpp b/alc/backends/alsa.cpp index 0d9ff30d..4bda5b02 100644 --- a/alc/backends/alsa.cpp +++ b/alc/backends/alsa.cpp @@ -53,6 +53,7 @@ namespace { +/* NOLINTNEXTLINE(*-avoid-c-arrays) */ constexpr char alsaDevice[] = "ALSA Default"; @@ -252,10 +253,11 @@ std::vector<DevMap> PlaybackDevices; std::vector<DevMap> CaptureDevices; -const char *prefix_name(snd_pcm_stream_t stream) +const std::string_view prefix_name(snd_pcm_stream_t stream) { - assert(stream == SND_PCM_STREAM_PLAYBACK || stream == SND_PCM_STREAM_CAPTURE); - return (stream==SND_PCM_STREAM_PLAYBACK) ? "device-prefix" : "capture-prefix"; + if(stream == SND_PCM_STREAM_PLAYBACK) + return "device-prefix"; + return "capture-prefix"; } std::vector<DevMap> probe_devices(snd_pcm_stream_t stream) @@ -267,11 +269,11 @@ std::vector<DevMap> probe_devices(snd_pcm_stream_t stream) snd_pcm_info_t *pcminfo; snd_pcm_info_malloc(&pcminfo); - auto defname = ConfigValueStr(nullptr, "alsa", + auto defname = ConfigValueStr({}, "alsa", (stream == SND_PCM_STREAM_PLAYBACK) ? "device" : "capture"); devlist.emplace_back(alsaDevice, defname ? defname->c_str() : "default"); - if(auto customdevs = ConfigValueStr(nullptr, "alsa", + if(auto customdevs = ConfigValueStr({}, "alsa", (stream == SND_PCM_STREAM_PLAYBACK) ? "custom-devices" : "custom-captures")) { size_t nextpos{customdevs->find_first_not_of(';')}; @@ -299,8 +301,8 @@ std::vector<DevMap> probe_devices(snd_pcm_stream_t stream) } } - const std::string main_prefix{ - ConfigValueStr(nullptr, "alsa", prefix_name(stream)).value_or("plughw:")}; + const std::string main_prefix{ConfigValueStr({}, "alsa", prefix_name(stream)) + .value_or("plughw:")}; int card{-1}; int err{snd_card_next(&card)}; @@ -309,12 +311,14 @@ std::vector<DevMap> probe_devices(snd_pcm_stream_t stream) std::string name{"hw:" + std::to_string(card)}; snd_ctl_t *handle; - if((err=snd_ctl_open(&handle, name.c_str(), 0)) < 0) + err = snd_ctl_open(&handle, name.c_str(), 0); + if(err < 0) { ERR("control open (hw:%d): %s\n", card, snd_strerror(err)); continue; } - if((err=snd_ctl_card_info(handle, info)) < 0) + err = snd_ctl_card_info(handle, info); + if(err < 0) { ERR("control hardware info (hw:%d): %s\n", card, snd_strerror(err)); snd_ctl_close(handle); @@ -326,8 +330,7 @@ std::vector<DevMap> probe_devices(snd_pcm_stream_t stream) name = prefix_name(stream); name += '-'; name += cardid; - const std::string card_prefix{ - ConfigValueStr(nullptr, "alsa", name.c_str()).value_or(main_prefix)}; + const std::string card_prefix{ConfigValueStr({}, "alsa", name).value_or(main_prefix)}; int dev{-1}; while(true) @@ -339,7 +342,8 @@ std::vector<DevMap> probe_devices(snd_pcm_stream_t stream) snd_pcm_info_set_device(pcminfo, static_cast<uint>(dev)); snd_pcm_info_set_subdevice(pcminfo, 0); snd_pcm_info_set_stream(pcminfo, stream); - if((err=snd_ctl_pcm_info(handle, pcminfo)) < 0) + err = snd_ctl_pcm_info(handle, pcminfo); + if(err < 0) { if(err != -ENOENT) ERR("control digital audio info (hw:%d): %s\n", card, snd_strerror(err)); @@ -352,8 +356,7 @@ std::vector<DevMap> probe_devices(snd_pcm_stream_t stream) name += cardid; name += '-'; name += std::to_string(dev); - const std::string device_prefix{ - ConfigValueStr(nullptr, "alsa", name.c_str()).value_or(card_prefix)}; + const std::string device_prefix{ConfigValueStr({},"alsa", name).value_or(card_prefix)}; /* "CardName, PcmName (CARD=cardid,DEV=dev)" */ name = cardname; @@ -405,13 +408,14 @@ int verify_state(snd_pcm_t *handle) break; case SND_PCM_STATE_XRUN: - if((err=snd_pcm_recover(handle, -EPIPE, 1)) < 0) - return err; + err=snd_pcm_recover(handle, -EPIPE, 1); + if(err < 0) return err; break; case SND_PCM_STATE_SUSPENDED: - if((err=snd_pcm_recover(handle, -ESTRPIPE, 1)) < 0) - return err; + err = snd_pcm_recover(handle, -ESTRPIPE, 1); + if(err < 0) return err; break; + case SND_PCM_STATE_DISCONNECTED: return -ENODEV; } @@ -443,8 +447,6 @@ struct AlsaPlayback final : public BackendBase { std::atomic<bool> mKillNow{true}; std::thread mThread; - - DEF_NEWDEL(AlsaPlayback) }; AlsaPlayback::~AlsaPlayback() @@ -644,7 +646,7 @@ void AlsaPlayback::open(std::string_view name) else { name = alsaDevice; - if(auto driveropt = ConfigValueStr(nullptr, "alsa", "device")) + if(auto driveropt = ConfigValueStr({}, "alsa", "device")) driver = std::move(driveropt).value(); } TRACE("Opening device \"%s\"\n", driver.c_str()); @@ -692,7 +694,7 @@ bool AlsaPlayback::reset() break; } - bool allowmmap{!!GetConfigValueBool(mDevice->DeviceName.c_str(), "alsa", "mmap", true)}; + bool allowmmap{GetConfigValueBool(mDevice->DeviceName, "alsa", "mmap", true)}; uint periodLen{static_cast<uint>(mDevice->UpdateSize * 1000000_u64 / mDevice->Frequency)}; uint bufferLen{static_cast<uint>(mDevice->BufferSize * 1000000_u64 / mDevice->Frequency)}; uint rate{mDevice->Frequency}; @@ -700,7 +702,8 @@ bool AlsaPlayback::reset() int err{}; HwParamsPtr hp{CreateHwParams()}; #define CHECK(x) do { \ - if((err=(x)) < 0) \ + err = (x); \ + if(err < 0) \ throw al::backend_exception{al::backend_error::DeviceError, #x " failed: %s", \ snd_strerror(err)}; \ } while(0) @@ -715,17 +718,18 @@ bool AlsaPlayback::reset() /* test and set format (implicitly sets sample bits) */ if(snd_pcm_hw_params_test_format(mPcmHandle, hp.get(), format) < 0) { - static const struct { + struct FormatMap { snd_pcm_format_t format; DevFmtType fmttype; - } formatlist[] = { - { SND_PCM_FORMAT_FLOAT, DevFmtFloat }, - { SND_PCM_FORMAT_S32, DevFmtInt }, - { SND_PCM_FORMAT_U32, DevFmtUInt }, - { SND_PCM_FORMAT_S16, DevFmtShort }, - { SND_PCM_FORMAT_U16, DevFmtUShort }, - { SND_PCM_FORMAT_S8, DevFmtByte }, - { SND_PCM_FORMAT_U8, DevFmtUByte }, + }; + static constexpr std::array formatlist{ + FormatMap{SND_PCM_FORMAT_FLOAT, DevFmtFloat }, + FormatMap{SND_PCM_FORMAT_S32, DevFmtInt }, + FormatMap{SND_PCM_FORMAT_U32, DevFmtUInt }, + FormatMap{SND_PCM_FORMAT_S16, DevFmtShort }, + FormatMap{SND_PCM_FORMAT_U16, DevFmtUShort}, + FormatMap{SND_PCM_FORMAT_S8, DevFmtByte }, + FormatMap{SND_PCM_FORMAT_U8, DevFmtUByte }, }; for(const auto &fmt : formatlist) @@ -750,7 +754,7 @@ bool AlsaPlayback::reset() else mDevice->FmtChans = DevFmtStereo; } /* set rate (implicitly constrains period/buffer parameters) */ - if(!GetConfigValueBool(mDevice->DeviceName.c_str(), "alsa", "allow-resampler", false) + if(!GetConfigValueBool(mDevice->DeviceName, "alsa", "allow-resampler", false) || !mDevice->Flags.test(FrequencyRequest)) { if(snd_pcm_hw_params_set_rate_resample(mPcmHandle, hp.get(), 0) < 0) @@ -760,11 +764,11 @@ bool AlsaPlayback::reset() WARN("Failed to enable ALSA resampler\n"); CHECK(snd_pcm_hw_params_set_rate_near(mPcmHandle, hp.get(), &rate, nullptr)); /* set period time (implicitly constrains period/buffer parameters) */ - if((err=snd_pcm_hw_params_set_period_time_near(mPcmHandle, hp.get(), &periodLen, nullptr)) < 0) - ERR("snd_pcm_hw_params_set_period_time_near failed: %s\n", snd_strerror(err)); + err = snd_pcm_hw_params_set_period_time_near(mPcmHandle, hp.get(), &periodLen, nullptr); + if(err < 0) ERR("snd_pcm_hw_params_set_period_time_near failed: %s\n", snd_strerror(err)); /* set buffer time (implicitly sets buffer size/bytes/time and period size/bytes) */ - if((err=snd_pcm_hw_params_set_buffer_time_near(mPcmHandle, hp.get(), &bufferLen, nullptr)) < 0) - ERR("snd_pcm_hw_params_set_buffer_time_near failed: %s\n", snd_strerror(err)); + err = snd_pcm_hw_params_set_buffer_time_near(mPcmHandle, hp.get(), &bufferLen, nullptr); + if(err < 0) ERR("snd_pcm_hw_params_set_buffer_time_near failed: %s\n", snd_strerror(err)); /* install and prepare hardware configuration */ CHECK(snd_pcm_hw_params(mPcmHandle, hp.get())); @@ -802,7 +806,8 @@ void AlsaPlayback::start() snd_pcm_access_t access{}; HwParamsPtr hp{CreateHwParams()}; #define CHECK(x) do { \ - if((err=(x)) < 0) \ + err = (x); \ + if(err < 0) \ throw al::backend_exception{al::backend_error::DeviceError, #x " failed: %s", \ snd_strerror(err)}; \ } while(0) @@ -852,7 +857,7 @@ ClockLatency AlsaPlayback::getClockLatency() ClockLatency ret; std::lock_guard<std::mutex> _{mMutex}; - ret.ClockTime = GetDeviceClockTime(mDevice); + ret.ClockTime = mDevice->getClockTime(); snd_pcm_sframes_t delay{}; int err{snd_pcm_delay(mPcmHandle, &delay)}; if(err < 0) @@ -886,8 +891,6 @@ struct AlsaCapture final : public BackendBase { RingBufferPtr mRing{nullptr}; snd_pcm_sframes_t mLastAvail{0}; - - DEF_NEWDEL(AlsaCapture) }; AlsaCapture::~AlsaCapture() @@ -916,7 +919,7 @@ void AlsaCapture::open(std::string_view name) else { name = alsaDevice; - if(auto driveropt = ConfigValueStr(nullptr, "alsa", "capture")) + if(auto driveropt = ConfigValueStr({}, "alsa", "capture")) driver = std::move(driveropt).value(); } @@ -961,7 +964,8 @@ void AlsaCapture::open(std::string_view name) bool needring{false}; HwParamsPtr hp{CreateHwParams()}; #define CHECK(x) do { \ - if((err=(x)) < 0) \ + err = (x); \ + if(err < 0) \ throw al::backend_exception{al::backend_error::DeviceError, #x " failed: %s", \ snd_strerror(err)}; \ } while(0) @@ -1039,7 +1043,7 @@ void AlsaCapture::captureSamples(std::byte *buffer, uint samples) { if(mRing) { - mRing->read(buffer, samples); + std::ignore = mRing->read(buffer, samples); return; } @@ -1068,7 +1072,8 @@ void AlsaCapture::captureSamples(std::byte *buffer, uint samples) if(amt == -EAGAIN) continue; - if((amt=snd_pcm_recover(mPcmHandle, static_cast<int>(amt), 1)) >= 0) + amt = snd_pcm_recover(mPcmHandle, static_cast<int>(amt), 1); + if(amt >= 0) { amt = snd_pcm_start(mPcmHandle); if(amt >= 0) @@ -1105,7 +1110,8 @@ uint AlsaCapture::availableSamples() { ERR("avail update failed: %s\n", snd_strerror(static_cast<int>(avail))); - if((avail=snd_pcm_recover(mPcmHandle, static_cast<int>(avail), 1)) >= 0) + avail = snd_pcm_recover(mPcmHandle, static_cast<int>(avail), 1); + if(avail >= 0) { if(mDoCapture) avail = snd_pcm_start(mPcmHandle); @@ -1141,7 +1147,8 @@ uint AlsaCapture::availableSamples() if(amt == -EAGAIN) continue; - if((amt=snd_pcm_recover(mPcmHandle, static_cast<int>(amt), 1)) >= 0) + amt = snd_pcm_recover(mPcmHandle, static_cast<int>(amt), 1); + if(amt >= 0) { if(mDoCapture) amt = snd_pcm_start(mPcmHandle); @@ -1170,7 +1177,7 @@ ClockLatency AlsaCapture::getClockLatency() { ClockLatency ret; - ret.ClockTime = GetDeviceClockTime(mDevice); + ret.ClockTime = mDevice->getClockTime(); snd_pcm_sframes_t delay{}; int err{snd_pcm_delay(mPcmHandle, &delay)}; if(err < 0) @@ -1189,13 +1196,9 @@ ClockLatency AlsaCapture::getClockLatency() bool AlsaBackendFactory::init() { - bool error{false}; - #ifdef HAVE_DYNLOAD if(!alsa_handle) { - std::string missing_funcs; - alsa_handle = LoadLib("libasound.so.2"); if(!alsa_handle) { @@ -1203,27 +1206,25 @@ bool AlsaBackendFactory::init() return false; } - error = false; + std::string missing_funcs; #define LOAD_FUNC(f) do { \ - p##f = al::bit_cast<decltype(p##f)>(GetSymbol(alsa_handle, #f)); \ - if(p##f == nullptr) { \ - error = true; \ - missing_funcs += "\n" #f; \ - } \ + p##f = reinterpret_cast<decltype(p##f)>(GetSymbol(alsa_handle, #f)); \ + if(p##f == nullptr) missing_funcs += "\n" #f; \ } while(0) ALSA_FUNCS(LOAD_FUNC); #undef LOAD_FUNC - if(error) + if(!missing_funcs.empty()) { WARN("Missing expected functions:%s\n", missing_funcs.c_str()); CloseLib(alsa_handle); alsa_handle = nullptr; + return false; } } #endif - return !error; + return true; } bool AlsaBackendFactory::querySupport(BackendType type) diff --git a/alc/backends/base.cpp b/alc/backends/base.cpp index ab3ad028..b287b6d9 100644 --- a/alc/backends/base.cpp +++ b/alc/backends/base.cpp @@ -45,21 +45,20 @@ uint BackendBase::availableSamples() ClockLatency BackendBase::getClockLatency() { - ClockLatency ret; + ClockLatency ret{}; uint refcount; do { refcount = mDevice->waitForMix(); - ret.ClockTime = GetDeviceClockTime(mDevice); + ret.ClockTime = mDevice->getClockTime(); std::atomic_thread_fence(std::memory_order_acquire); - } while(refcount != ReadRef(mDevice->MixCount)); + } while(refcount != mDevice->mMixCount.load(std::memory_order_relaxed)); /* NOTE: The device will generally have about all but one periods filled at * any given time during playback. Without a more accurate measurement from * the output, this is an okay approximation. */ - ret.Latency = std::max(std::chrono::seconds{mDevice->BufferSize-mDevice->UpdateSize}, - std::chrono::seconds::zero()); + ret.Latency = std::chrono::seconds{mDevice->BufferSize - mDevice->UpdateSize}; ret.Latency /= mDevice->Frequency; return ret; diff --git a/alc/backends/base.h b/alc/backends/base.h index eea0d238..6726cd9a 100644 --- a/alc/backends/base.h +++ b/alc/backends/base.h @@ -52,18 +52,6 @@ enum class BackendType { }; -/* Helper to get the current clock time from the device's ClockBase, and - * SamplesDone converted from the sample rate. - */ -inline std::chrono::nanoseconds GetDeviceClockTime(DeviceBase *device) -{ - using std::chrono::seconds; - using std::chrono::nanoseconds; - - auto ns = nanoseconds{seconds{device->SamplesDone}} / device->Frequency; - return device->ClockBase + ns; -} - /* Helper to get the device latency from the backend, including any fixed * latency from post-processing. */ @@ -76,6 +64,8 @@ inline ClockLatency GetClockLatency(DeviceBase *device, BackendBase *backend) struct BackendFactory { + virtual ~BackendFactory() = default; + virtual bool init() = 0; virtual bool querySupport(BackendType type) = 0; @@ -86,9 +76,6 @@ struct BackendFactory { virtual std::string probe(BackendType type) = 0; virtual BackendPtr createBackend(DeviceBase *device, BackendType type) = 0; - -protected: - virtual ~BackendFactory() = default; }; namespace al { @@ -103,15 +90,15 @@ class backend_exception final : public base_exception { backend_error mErrorCode; public: -#ifdef __USE_MINGW_ANSI_STDIO - [[gnu::format(gnu_printf, 3, 4)]] +#ifdef __MINGW32__ + [[gnu::format(__MINGW_PRINTF_FORMAT, 3, 4)]] #else [[gnu::format(printf, 3, 4)]] #endif backend_exception(backend_error code, const char *msg, ...); ~backend_exception() override; - backend_error errorCode() const noexcept { return mErrorCode; } + [[nodiscard]] auto errorCode() const noexcept -> backend_error { return mErrorCode; } }; } // namespace al diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index 16b0781e..86c4b89b 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -337,8 +337,6 @@ struct CoreAudioPlayback final : public BackendBase { uint mFrameSize{0u}; AudioStreamBasicDescription mFormat{}; // This is the OpenAL format as a CoreAudio ASBD - - DEF_NEWDEL(CoreAudioPlayback) }; CoreAudioPlayback::~CoreAudioPlayback() @@ -623,8 +621,6 @@ struct CoreAudioCapture final : public BackendBase { std::vector<char> mCaptureData; RingBufferPtr mRing{nullptr}; - - DEF_NEWDEL(CoreAudioCapture) }; CoreAudioCapture::~CoreAudioCapture() @@ -657,7 +653,7 @@ OSStatus CoreAudioCapture::RecordProc(AudioUnitRenderActionFlags *ioActionFlags, return err; } - mRing->write(mCaptureData.data(), inNumberFrames); + std::ignore = mRing->write(mCaptureData.data(), inNumberFrames); return noErr; } @@ -924,7 +920,7 @@ void CoreAudioCapture::captureSamples(std::byte *buffer, uint samples) { if(!mConverter) { - mRing->read(buffer, samples); + std::ignore = mRing->read(buffer, samples); return; } diff --git a/alc/backends/dsound.cpp b/alc/backends/dsound.cpp index 58aa69b2..e51c7ab5 100644 --- a/alc/backends/dsound.cpp +++ b/alc/backends/dsound.cpp @@ -35,11 +35,11 @@ #include <algorithm> #include <atomic> #include <cassert> +#include <cstdio> +#include <cstdlib> #include <functional> #include <memory.h> #include <mutex> -#include <stdlib.h> -#include <stdio.h> #include <string> #include <thread> #include <vector> @@ -191,8 +191,6 @@ struct DSoundPlayback final : public BackendBase { std::atomic<bool> mKillNow{true}; std::thread mThread; - - DEF_NEWDEL(DSoundPlayback) }; DSoundPlayback::~DSoundPlayback() @@ -560,8 +558,6 @@ struct DSoundCapture final : public BackendBase { DWORD mCursor{0u}; RingBufferPtr mRing; - - DEF_NEWDEL(DSoundCapture) }; DSoundCapture::~DSoundCapture() @@ -717,7 +713,7 @@ void DSoundCapture::stop() } void DSoundCapture::captureSamples(std::byte *buffer, uint samples) -{ mRing->read(buffer, samples); } +{ std::ignore = mRing->read(buffer, samples); } uint DSoundCapture::availableSamples() { @@ -740,9 +736,9 @@ uint DSoundCapture::availableSamples() } if(SUCCEEDED(hr)) { - mRing->write(ReadPtr1, ReadCnt1/FrameSize); + std::ignore = mRing->write(ReadPtr1, ReadCnt1/FrameSize); if(ReadPtr2 != nullptr && ReadCnt2 > 0) - mRing->write(ReadPtr2, ReadCnt2/FrameSize); + std::ignore = mRing->write(ReadPtr2, ReadCnt2/FrameSize); hr = mDSCbuffer->Unlock(ReadPtr1, ReadCnt1, ReadPtr2, ReadCnt2); mCursor = ReadCursor; } @@ -778,7 +774,7 @@ bool DSoundBackendFactory::init() } #define LOAD_FUNC(f) do { \ - p##f = al::bit_cast<decltype(p##f)>(GetSymbol(ds_handle, #f)); \ + p##f = reinterpret_cast<decltype(p##f)>(GetSymbol(ds_handle, #f)); \ if(!p##f) \ { \ CloseLib(ds_handle); \ diff --git a/alc/backends/jack.cpp b/alc/backends/jack.cpp index a0a5c440..529bb9fe 100644 --- a/alc/backends/jack.cpp +++ b/alc/backends/jack.cpp @@ -102,19 +102,16 @@ decltype(jack_error_callback) * pjack_error_callback; #endif +/* NOLINTNEXTLINE(*-avoid-c-arrays) */ constexpr char JackDefaultAudioType[] = JACK_DEFAULT_AUDIO_TYPE; jack_options_t ClientOptions = JackNullOption; bool jack_load() { - bool error{false}; - #ifdef HAVE_DYNLOAD if(!jack_handle) { - std::string missing_funcs; - #ifdef _WIN32 #define JACKLIB "libjack.dll" #else @@ -127,38 +124,36 @@ bool jack_load() return false; } - error = false; + std::string missing_funcs; #define LOAD_FUNC(f) do { \ - p##f = al::bit_cast<decltype(p##f)>(GetSymbol(jack_handle, #f)); \ - if(p##f == nullptr) { \ - error = true; \ - missing_funcs += "\n" #f; \ - } \ + p##f = reinterpret_cast<decltype(p##f)>(GetSymbol(jack_handle, #f)); \ + if(p##f == nullptr) missing_funcs += "\n" #f; \ } while(0) JACK_FUNCS(LOAD_FUNC); #undef LOAD_FUNC /* Optional symbols. These don't exist in all versions of JACK. */ -#define LOAD_SYM(f) p##f = al::bit_cast<decltype(p##f)>(GetSymbol(jack_handle, #f)) +#define LOAD_SYM(f) p##f = reinterpret_cast<decltype(p##f)>(GetSymbol(jack_handle, #f)) LOAD_SYM(jack_error_callback); #undef LOAD_SYM - if(error) + if(!missing_funcs.empty()) { WARN("Missing expected functions:%s\n", missing_funcs.c_str()); CloseLib(jack_handle); jack_handle = nullptr; + return false; } } #endif - return !error; + return true; } struct JackDeleter { void operator()(void *ptr) { jack_free(ptr); } }; -using JackPortsPtr = std::unique_ptr<const char*[],JackDeleter>; +using JackPortsPtr = std::unique_ptr<const char*[],JackDeleter>; /* NOLINT(*-avoid-c-arrays) */ struct DeviceEntry { std::string mName; @@ -209,7 +204,7 @@ void EnumerateDevices(jack_client_t *client, std::vector<DeviceEntry> &list) } } - if(auto listopt = ConfigValueStr(nullptr, "jack", "custom-devices")) + if(auto listopt = ConfigValueStr({}, "jack", "custom-devices")) { for(size_t strpos{0};strpos < listopt->size();) { @@ -307,7 +302,7 @@ struct JackPlayback final : public BackendBase { std::string mPortPattern; jack_client_t *mClient{nullptr}; - std::array<jack_port_t*,MAX_OUTPUT_CHANNELS> mPort{}; + std::array<jack_port_t*,MaxOutputChannels> mPort{}; std::mutex mMutex; @@ -318,8 +313,6 @@ struct JackPlayback final : public BackendBase { std::atomic<bool> mKillNow{true}; std::thread mThread; - - DEF_NEWDEL(JackPlayback) }; JackPlayback::~JackPlayback() @@ -339,7 +332,7 @@ JackPlayback::~JackPlayback() int JackPlayback::processRt(jack_nframes_t numframes) noexcept { - std::array<jack_default_audio_sample_t*,MAX_OUTPUT_CHANNELS> out; + std::array<jack_default_audio_sample_t*,MaxOutputChannels> out; size_t numchans{0}; for(auto port : mPort) { @@ -363,7 +356,7 @@ int JackPlayback::processRt(jack_nframes_t numframes) noexcept int JackPlayback::process(jack_nframes_t numframes) noexcept { - std::array<jack_default_audio_sample_t*,MAX_OUTPUT_CHANNELS> out; + std::array<jack_default_audio_sample_t*,MaxOutputChannels> out; size_t numchans{0}; for(auto port : mPort) { @@ -378,7 +371,7 @@ int JackPlayback::process(jack_nframes_t numframes) noexcept jack_nframes_t todo{minu(numframes, static_cast<uint>(data.first.len))}; auto write_first = [&data,numchans,todo](float *outbuf) -> float* { - const float *RESTRICT in = reinterpret_cast<float*>(data.first.buf); + const auto *RESTRICT in = reinterpret_cast<const float*>(data.first.buf); auto deinterlace_input = [&in,numchans]() noexcept -> float { float ret{*in}; @@ -397,7 +390,7 @@ int JackPlayback::process(jack_nframes_t numframes) noexcept { auto write_second = [&data,numchans,todo](float *outbuf) -> float* { - const float *RESTRICT in = reinterpret_cast<float*>(data.second.buf); + const auto *RESTRICT in = reinterpret_cast<const float*>(data.second.buf); auto deinterlace_input = [&in,numchans]() noexcept -> float { float ret{*in}; @@ -510,7 +503,7 @@ 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); + mRTMixing = GetConfigValueBool(mDevice->DeviceName, "jack", "rt-mix", true); jack_set_process_callback(mClient, mRTMixing ? &JackPlayback::processRtC : &JackPlayback::processC, this); @@ -528,7 +521,7 @@ bool JackPlayback::reset() } else { - const char *devname{mDevice->DeviceName.c_str()}; + const std::string_view devname{mDevice->DeviceName}; uint bufsize{ConfigValueUInt(devname, "jack", "buffer-size").value_or(mDevice->UpdateSize)}; bufsize = maxu(NextPowerOf2(bufsize), mDevice->UpdateSize); mDevice->BufferSize = bufsize + mDevice->UpdateSize; @@ -578,7 +571,7 @@ void JackPlayback::start() if(jack_activate(mClient)) throw al::backend_exception{al::backend_error::DeviceError, "Failed to activate client"}; - const char *devname{mDevice->DeviceName.c_str()}; + const std::string_view devname{mDevice->DeviceName}; if(ConfigValueBool(devname, "jack", "connect-ports").value_or(true)) { JackPortsPtr pnames{jack_get_ports(mClient, mPortPattern.c_str(), JackDefaultAudioType, @@ -657,7 +650,7 @@ ClockLatency JackPlayback::getClockLatency() ClockLatency ret; std::lock_guard<std::mutex> _{mMutex}; - ret.ClockTime = GetDeviceClockTime(mDevice); + ret.ClockTime = mDevice->getClockTime(); ret.Latency = std::chrono::seconds{mRing ? mRing->readSpace() : mDevice->UpdateSize}; ret.Latency /= mDevice->Frequency; @@ -677,7 +670,7 @@ bool JackBackendFactory::init() if(!jack_load()) return false; - if(!GetConfigValueBool(nullptr, "jack", "spawn-server", false)) + if(!GetConfigValueBool({}, "jack", "spawn-server", false)) ClientOptions = static_cast<jack_options_t>(ClientOptions | JackNoStartServer); const PathNamePair &binname = GetProcBinary(); diff --git a/alc/backends/loopback.cpp b/alc/backends/loopback.cpp index 2972fc01..e42e35b0 100644 --- a/alc/backends/loopback.cpp +++ b/alc/backends/loopback.cpp @@ -34,8 +34,6 @@ struct LoopbackBackend final : public BackendBase { bool reset() override; void start() override; void stop() override; - - DEF_NEWDEL(LoopbackBackend) }; diff --git a/alc/backends/null.cpp b/alc/backends/null.cpp index 3c68e4ce..f28eaa47 100644 --- a/alc/backends/null.cpp +++ b/alc/backends/null.cpp @@ -42,6 +42,7 @@ using std::chrono::seconds; using std::chrono::milliseconds; using std::chrono::nanoseconds; +/* NOLINTNEXTLINE(*-avoid-c-arrays) */ constexpr char nullDevice[] = "No Output"; @@ -57,8 +58,6 @@ struct NullBackend final : public BackendBase { std::atomic<bool> mKillNow{true}; std::thread mThread; - - DEF_NEWDEL(NullBackend) }; int NullBackend::mixerProc() diff --git a/alc/backends/oboe.cpp b/alc/backends/oboe.cpp index b7bab19a..d55a7066 100644 --- a/alc/backends/oboe.cpp +++ b/alc/backends/oboe.cpp @@ -4,8 +4,8 @@ #include "oboe.h" #include <cassert> +#include <cstdint> #include <cstring> -#include <stdint.h> #include "alnumeric.h" #include "core/device.h" @@ -17,6 +17,7 @@ namespace { +/* NOLINTNEXTLINE(*-avoid-c-arrays) */ constexpr char device_name[] = "Oboe Default"; @@ -48,11 +49,10 @@ oboe::DataCallbackResult OboePlayback::onAudioReady(oboe::AudioStream *oboeStrea return oboe::DataCallbackResult::Continue; } -void OboePlayback::onErrorAfterClose(oboe::AudioStream* audioStream, oboe::Result error) +void OboePlayback::onErrorAfterClose(oboe::AudioStream*, oboe::Result error) { - if (error == oboe::Result::ErrorDisconnected) { + if(error == oboe::Result::ErrorDisconnected) mDevice->handleDisconnect("Oboe AudioStream was disconnected: %s", oboe::convertToText(error)); - } TRACE("Error was %s", oboe::convertToText(error)); } @@ -81,6 +81,7 @@ bool OboePlayback::reset() oboe::AudioStreamBuilder builder; builder.setDirection(oboe::Direction::Output); builder.setPerformanceMode(oboe::PerformanceMode::LowLatency); + builder.setUsage(oboe::Usage::Game); /* Don't let Oboe convert. We should be able to handle anything it gives * back. */ @@ -230,7 +231,7 @@ struct OboeCapture final : public BackendBase, public oboe::AudioStreamCallback oboe::DataCallbackResult OboeCapture::onAudioReady(oboe::AudioStream*, void *audioData, int32_t numFrames) { - mRing->write(audioData, static_cast<uint32_t>(numFrames)); + std::ignore = mRing->write(audioData, static_cast<uint32_t>(numFrames)); return oboe::DataCallbackResult::Continue; } @@ -330,7 +331,7 @@ uint OboeCapture::availableSamples() { return static_cast<uint>(mRing->readSpace()); } void OboeCapture::captureSamples(std::byte *buffer, uint samples) -{ mRing->read(buffer, samples); } +{ std::ignore = mRing->read(buffer, samples); } } // namespace diff --git a/alc/backends/opensl.cpp b/alc/backends/opensl.cpp index 61e3c9a7..6b2de909 100644 --- a/alc/backends/opensl.cpp +++ b/alc/backends/opensl.cpp @@ -23,10 +23,10 @@ #include "opensl.h" -#include <stdlib.h> #include <jni.h> #include <array> +#include <cstdlib> #include <cstring> #include <mutex> #include <new> @@ -56,6 +56,7 @@ namespace { #define VCALL0(obj, func) ((*(obj))->func((obj) EXTRACT_VCALL_ARGS +/* NOLINTNEXTLINE(*-avoid-c-arrays) */ constexpr char opensl_device[] = "OpenSL"; @@ -189,8 +190,6 @@ struct OpenSLPlayback final : public BackendBase { std::atomic<bool> mKillNow{true}; std::thread mThread; - - DEF_NEWDEL(OpenSLPlayback) }; OpenSLPlayback::~OpenSLPlayback() @@ -375,74 +374,6 @@ bool OpenSLPlayback::reset() mRing = nullptr; -#if 0 - if(!mDevice->Flags.get<FrequencyRequest>()) - { - /* FIXME: Disabled until I figure out how to get the Context needed for - * the getSystemService call. - */ - JNIEnv *env = Android_GetJNIEnv(); - jobject jctx = Android_GetContext(); - - /* Get necessary stuff for using java.lang.Integer, - * android.content.Context, and android.media.AudioManager. - */ - jclass int_cls = JCALL(env,FindClass)("java/lang/Integer"); - jmethodID int_parseint = JCALL(env,GetStaticMethodID)(int_cls, - "parseInt", "(Ljava/lang/String;)I" - ); - TRACE("Integer: %p, parseInt: %p\n", int_cls, int_parseint); - - jclass ctx_cls = JCALL(env,FindClass)("android/content/Context"); - jfieldID ctx_audsvc = JCALL(env,GetStaticFieldID)(ctx_cls, - "AUDIO_SERVICE", "Ljava/lang/String;" - ); - jmethodID ctx_getSysSvc = JCALL(env,GetMethodID)(ctx_cls, - "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;" - ); - TRACE("Context: %p, AUDIO_SERVICE: %p, getSystemService: %p\n", - ctx_cls, ctx_audsvc, ctx_getSysSvc); - - jclass audmgr_cls = JCALL(env,FindClass)("android/media/AudioManager"); - jfieldID audmgr_prop_out_srate = JCALL(env,GetStaticFieldID)(audmgr_cls, - "PROPERTY_OUTPUT_SAMPLE_RATE", "Ljava/lang/String;" - ); - jmethodID audmgr_getproperty = JCALL(env,GetMethodID)(audmgr_cls, - "getProperty", "(Ljava/lang/String;)Ljava/lang/String;" - ); - TRACE("AudioManager: %p, PROPERTY_OUTPUT_SAMPLE_RATE: %p, getProperty: %p\n", - audmgr_cls, audmgr_prop_out_srate, audmgr_getproperty); - - const char *strchars; - jstring strobj; - - /* Now make the calls. */ - //AudioManager audMgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE); - strobj = JCALL(env,GetStaticObjectField)(ctx_cls, ctx_audsvc); - jobject audMgr = JCALL(env,CallObjectMethod)(jctx, ctx_getSysSvc, strobj); - strchars = JCALL(env,GetStringUTFChars)(strobj, nullptr); - TRACE("Context.getSystemService(%s) = %p\n", strchars, audMgr); - JCALL(env,ReleaseStringUTFChars)(strobj, strchars); - - //String srateStr = audMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE); - strobj = JCALL(env,GetStaticObjectField)(audmgr_cls, audmgr_prop_out_srate); - jstring srateStr = JCALL(env,CallObjectMethod)(audMgr, audmgr_getproperty, strobj); - strchars = JCALL(env,GetStringUTFChars)(strobj, nullptr); - TRACE("audMgr.getProperty(%s) = %p\n", strchars, srateStr); - JCALL(env,ReleaseStringUTFChars)(strobj, strchars); - - //int sampleRate = Integer.parseInt(srateStr); - sampleRate = JCALL(env,CallStaticIntMethod)(int_cls, int_parseint, srateStr); - - strchars = JCALL(env,GetStringUTFChars)(srateStr, nullptr); - TRACE("Got system sample rate %uhz (%s)\n", sampleRate, strchars); - JCALL(env,ReleaseStringUTFChars)(srateStr, strchars); - - if(!sampleRate) sampleRate = device->Frequency; - else sampleRate = maxu(sampleRate, MIN_OUTPUT_RATE); - } -#endif - mDevice->FmtChans = DevFmtStereo; mDevice->FmtType = DevFmtShort; @@ -631,7 +562,7 @@ ClockLatency OpenSLPlayback::getClockLatency() ClockLatency ret; std::lock_guard<std::mutex> _{mMutex}; - ret.ClockTime = GetDeviceClockTime(mDevice); + ret.ClockTime = mDevice->getClockTime(); ret.Latency = std::chrono::seconds{mRing->readSpace() * mDevice->UpdateSize}; ret.Latency /= mDevice->Frequency; @@ -662,8 +593,6 @@ struct OpenSLCapture final : public BackendBase { uint mSplOffset{0u}; uint mFrameSize{0}; - - DEF_NEWDEL(OpenSLCapture) }; OpenSLCapture::~OpenSLCapture() diff --git a/alc/backends/oss.cpp b/alc/backends/oss.cpp index 87d3ba35..d541b534 100644 --- a/alc/backends/oss.cpp +++ b/alc/backends/oss.cpp @@ -79,7 +79,9 @@ namespace { +/* NOLINTNEXTLINE(*-avoid-c-arrays) */ constexpr char DefaultName[] = "OSS Default"; + std::string DefaultPlayback{"/dev/dsp"}; std::string DefaultCapture{"/dev/dsp"}; @@ -238,8 +240,6 @@ struct OSSPlayback final : public BackendBase { std::atomic<bool> mKillNow{true}; std::thread mThread; - - DEF_NEWDEL(OSSPlayback) }; OSSPlayback::~OSSPlayback() @@ -367,11 +367,9 @@ bool OSSPlayback::reset() uint numFragmentsLogSize{(periods << 16) | log2FragmentSize}; audio_buf_info info{}; - const char *err; -#define CHECKERR(func) if((func) < 0) { \ - err = #func; \ - goto err; \ -} +#define CHECKERR(func) if((func) < 0) \ + throw al::backend_exception{al::backend_error::DeviceError, "%s failed: %s\n", #func, strerror(errno)}; + /* Don't fail if SETFRAGMENT fails. We can handle just about anything * that's reported back via GETOSPACE */ ioctl(mFd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize); @@ -379,12 +377,6 @@ bool OSSPlayback::reset() CHECKERR(ioctl(mFd, SNDCTL_DSP_CHANNELS, &numChannels)); CHECKERR(ioctl(mFd, SNDCTL_DSP_SPEED, &ossSpeed)); CHECKERR(ioctl(mFd, SNDCTL_DSP_GETOSPACE, &info)); - if(0) - { - err: - ERR("%s failed: %s\n", err, strerror(errno)); - return false; - } #undef CHECKERR if(mDevice->channelsFromFmt() != numChannels) @@ -409,7 +401,7 @@ bool OSSPlayback::reset() setDefaultChannelOrder(); - mMixData.resize(mDevice->UpdateSize * mDevice->frameSizeFromFmt()); + mMixData.resize(size_t{mDevice->UpdateSize} * mDevice->frameSizeFromFmt()); return true; } @@ -455,8 +447,6 @@ struct OSScapture final : public BackendBase { std::atomic<bool> mKillNow{true}; std::thread mThread; - - DEF_NEWDEL(OSScapture) }; OSScapture::~OSScapture() @@ -617,7 +607,7 @@ void OSScapture::stop() } void OSScapture::captureSamples(std::byte *buffer, uint samples) -{ mRing->read(buffer, samples); } +{ std::ignore = mRing->read(buffer, samples); } uint OSScapture::availableSamples() { return static_cast<uint>(mRing->readSpace()); } @@ -633,9 +623,9 @@ BackendFactory &OSSBackendFactory::getFactory() bool OSSBackendFactory::init() { - if(auto devopt = ConfigValueStr(nullptr, "oss", "device")) + if(auto devopt = ConfigValueStr({}, "oss", "device")) DefaultPlayback = std::move(*devopt); - if(auto capopt = ConfigValueStr(nullptr, "oss", "capture")) + if(auto capopt = ConfigValueStr({}, "oss", "capture")) DefaultCapture = std::move(*capopt); return true; diff --git a/alc/backends/pipewire.cpp b/alc/backends/pipewire.cpp index 6a001d7a..55bcf6f4 100644 --- a/alc/backends/pipewire.cpp +++ b/alc/backends/pipewire.cpp @@ -28,12 +28,12 @@ #include <cstring> #include <cerrno> #include <chrono> +#include <cstdint> #include <ctime> #include <list> #include <memory> #include <mutex> #include <optional> -#include <stdint.h> #include <thread> #include <type_traits> #include <utility> @@ -76,6 +76,10 @@ _Pragma("GCC diagnostic ignored \"-Weverything\"") #include "spa/pod/builder.h" #include "spa/utils/json.h" +/* NOLINTBEGIN : All kinds of unsafe C stuff here from PipeWire headers + * (function-like macros, C style casts in macros, etc), which we can't do + * anything about except wrap into inline functions. + */ namespace { /* Wrap some nasty macros here too... */ template<typename ...Args> @@ -117,6 +121,7 @@ constexpr auto make_pod_builder(void *data, uint32_t size) noexcept constexpr auto PwIdAny = PW_ID_ANY; } // namespace +/* NOLINTEND */ _Pragma("GCC diagnostic pop") namespace { @@ -169,8 +174,10 @@ using std::chrono::milliseconds; using std::chrono::nanoseconds; using uint = unsigned int; +/* NOLINTBEGIN(*-avoid-c-arrays) */ constexpr char pwireDevice[] = "PipeWire Output"; constexpr char pwireInput[] = "PipeWire Input"; +/* NOLINTEND(*-avoid-c-arrays) */ bool check_version(const char *version) @@ -238,7 +245,7 @@ bool pwire_load() if(pwire_handle) return true; - static constexpr char pwire_library[] = "libpipewire-0.3.so.0"; + const char *pwire_library{"libpipewire-0.3.so.0"}; std::string missing_funcs; pwire_handle = LoadLib(pwire_library); @@ -249,7 +256,7 @@ bool pwire_load() } #define LOAD_FUNC(f) do { \ - p##f = al::bit_cast<decltype(p##f)>(GetSymbol(pwire_handle, #f)); \ + p##f = reinterpret_cast<decltype(p##f)>(GetSymbol(pwire_handle, #f)); \ if(p##f == nullptr) missing_funcs += "\n" #f; \ } while(0); PWIRE_FUNCS(LOAD_FUNC) @@ -367,11 +374,11 @@ To as(From) noexcept = delete; * - pw_metadata */ template<> -pw_proxy* as(pw_registry *reg) noexcept { return al::bit_cast<pw_proxy*>(reg); } +pw_proxy* as(pw_registry *reg) noexcept { return reinterpret_cast<pw_proxy*>(reg); } template<> -pw_proxy* as(pw_node *node) noexcept { return al::bit_cast<pw_proxy*>(node); } +pw_proxy* as(pw_node *node) noexcept { return reinterpret_cast<pw_proxy*>(node); } template<> -pw_proxy* as(pw_metadata *mdata) noexcept { return al::bit_cast<pw_proxy*>(mdata); } +pw_proxy* as(pw_metadata *mdata) noexcept { return reinterpret_cast<pw_proxy*>(mdata); } struct PwContextDeleter { @@ -434,9 +441,11 @@ public: explicit operator bool() const noexcept { return mLoop != nullptr; } + [[nodiscard]] auto start() const { return pw_thread_loop_start(mLoop); } auto stop() const { return pw_thread_loop_stop(mLoop); } + [[nodiscard]] auto getLoop() const { return pw_thread_loop_get_loop(mLoop); } auto lock() const { return pw_thread_loop_lock(mLoop); } @@ -501,8 +510,8 @@ struct NodeProxy { /* 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, SPA_PARAM_Format}; - ppw_node_subscribe_params(mNode.get(), std::data(fmtids), std::size(fmtids)); + std::array<uint32_t,2> fmtids{{SPA_PARAM_EnumFormat, SPA_PARAM_Format}}; + ppw_node_subscribe_params(mNode.get(), fmtids.data(), fmtids.size()); } ~NodeProxy() { spa_hook_remove(&mListener); } @@ -765,25 +774,32 @@ void DeviceNode::Remove(uint32_t id) } -const spa_audio_channel MonoMap[]{ +constexpr std::array MonoMap{ SPA_AUDIO_CHANNEL_MONO -}, StereoMap[] { +}; +constexpr std::array StereoMap{ SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR -}, QuadMap[]{ +}; +constexpr std::array QuadMap{ SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_RL, SPA_AUDIO_CHANNEL_RR -}, X51Map[]{ +}; +constexpr std::array X51Map{ SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE, SPA_AUDIO_CHANNEL_SL, SPA_AUDIO_CHANNEL_SR -}, X51RearMap[]{ +}; +constexpr std::array X51RearMap{ SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE, SPA_AUDIO_CHANNEL_RL, SPA_AUDIO_CHANNEL_RR -}, X61Map[]{ +}; +constexpr std::array X61Map{ SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE, SPA_AUDIO_CHANNEL_RC, SPA_AUDIO_CHANNEL_SL, SPA_AUDIO_CHANNEL_SR -}, X71Map[]{ +}; +constexpr std::array X71Map{ SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE, SPA_AUDIO_CHANNEL_RL, SPA_AUDIO_CHANNEL_RR, SPA_AUDIO_CHANNEL_SL, SPA_AUDIO_CHANNEL_SR -}, X714Map[]{ +}; +constexpr std::array X714Map{ SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE, SPA_AUDIO_CHANNEL_RL, SPA_AUDIO_CHANNEL_RR, SPA_AUDIO_CHANNEL_SL, SPA_AUDIO_CHANNEL_SR, SPA_AUDIO_CHANNEL_TFL, SPA_AUDIO_CHANNEL_TFR, SPA_AUDIO_CHANNEL_TRL, SPA_AUDIO_CHANNEL_TRR @@ -793,10 +809,10 @@ const spa_audio_channel MonoMap[]{ * Checks if every channel in 'map1' exists in 'map0' (that is, map0 is equal * to or a superset of map1). */ -template<size_t N> -bool MatchChannelMap(const al::span<const uint32_t> map0, const spa_audio_channel (&map1)[N]) +bool MatchChannelMap(const al::span<const uint32_t> map0, + const al::span<const spa_audio_channel> map1) { - if(map0.size() < N) + if(map0.size() < map1.size()) return false; for(const spa_audio_channel chid : map1) { @@ -831,7 +847,7 @@ void DeviceNode::parseSampleRate(const spa_pod *value, bool force_update) noexce /* [0] is the default, [1] is the min, and [2] is the max. */ TRACE(" sample rate: %d (range: %d -> %d)\n", srates[0], srates[1], srates[2]); if(!mSampleRate || force_update) - mSampleRate = static_cast<uint>(clampi(srates[0], MIN_OUTPUT_RATE, MAX_OUTPUT_RATE)); + mSampleRate = static_cast<uint>(clampi(srates[0], MinOutputRate, MaxOutputRate)); return; } @@ -857,7 +873,7 @@ void DeviceNode::parseSampleRate(const spa_pod *value, bool force_update) noexce */ for(const auto &rate : srates) { - if(rate >= MIN_OUTPUT_RATE && rate <= MAX_OUTPUT_RATE) + if(rate >= int{MinOutputRate} && rate <= int{MaxOutputRate}) { if(!mSampleRate || force_update) mSampleRate = static_cast<uint>(rate); @@ -878,7 +894,7 @@ void DeviceNode::parseSampleRate(const spa_pod *value, bool force_update) noexce TRACE(" sample rate: %d\n", srates[0]); if(!mSampleRate || force_update) - mSampleRate = static_cast<uint>(clampi(srates[0], MIN_OUTPUT_RATE, MAX_OUTPUT_RATE)); + mSampleRate = static_cast<uint>(clampi(srates[0], MinOutputRate, MaxOutputRate)); return; } @@ -956,6 +972,7 @@ void DeviceNode::parseChannelCount(const spa_pod *value, bool force_update) noex } +/* NOLINTBEGIN(*-avoid-c-arrays) */ constexpr char MonitorPrefix[]{"Monitor of "}; constexpr auto MonitorPrefixLen = std::size(MonitorPrefix) - 1; constexpr char AudioSinkClass[]{"Audio/Sink"}; @@ -963,6 +980,7 @@ constexpr char AudioSourceClass[]{"Audio/Source"}; constexpr char AudioSourceVirtualClass[]{"Audio/Source/Virtual"}; constexpr char AudioDuplexClass[]{"Audio/Duplex"}; constexpr char StreamClass[]{"Stream/"}; +/* NOLINTEND(*-avoid-c-arrays) */ void NodeProxy::infoCallback(const pw_node_info *info) noexcept { @@ -1070,8 +1088,11 @@ void NodeProxy::paramCallback(int, uint32_t id, uint32_t, uint32_t, const spa_po if(const spa_pod_prop *prop{spa_pod_find_prop(param, nullptr, SPA_FORMAT_AUDIO_position)}) node->parsePositions(&prop->value, force_update); - else if((prop=spa_pod_find_prop(param, nullptr, SPA_FORMAT_AUDIO_channels)) != nullptr) - node->parseChannelCount(&prop->value, force_update); + else + { + prop = spa_pod_find_prop(param, nullptr, SPA_FORMAT_AUDIO_channels); + if(prop) node->parseChannelCount(&prop->value, force_update); + } } } @@ -1103,8 +1124,8 @@ int MetadataProxy::propertyCallback(uint32_t id, const char *key, const char *ty return 0; } - spa_json it[2]{}; - spa_json_init(&it[0], value, strlen(value)); + std::array<spa_json,2> it{}; + spa_json_init(it.data(), value, strlen(value)); if(spa_json_enter_object(&it[0], &it[1]) <= 0) return 0; @@ -1407,8 +1428,7 @@ class PipeWirePlayback final : public BackendBase { PwStreamPtr mStream; spa_hook mStreamListener{}; spa_io_rate_match *mRateMatch{}; - std::unique_ptr<float*[]> mChannelPtrs; - uint mNumChannels{}; + std::vector<float*> mChannelPtrs; static constexpr pw_stream_events CreateEvents() { @@ -1425,13 +1445,11 @@ class PipeWirePlayback final : public BackendBase { public: PipeWirePlayback(DeviceBase *device) noexcept : BackendBase{device} { } - ~PipeWirePlayback() + ~PipeWirePlayback() final { /* Stop the mainloop so the stream can be properly destroyed. */ if(mLoop) mLoop.stop(); } - - DEF_NEWDEL(PipeWirePlayback) }; @@ -1455,7 +1473,7 @@ void PipeWirePlayback::outputCallback() noexcept if(!pw_buf) UNLIKELY return; const al::span<spa_data> datas{pw_buf->buffer->datas, - minu(mNumChannels, pw_buf->buffer->n_datas)}; + minz(mChannelPtrs.size(), pw_buf->buffer->n_datas)}; #if PW_CHECK_VERSION(0,3,49) /* In 0.3.49, pw_buffer::requested specifies the number of samples needed * by the resampler/graph for this audio update. @@ -1475,7 +1493,7 @@ void PipeWirePlayback::outputCallback() noexcept * buffer length in any one channel is smaller than we wanted (shouldn't * be, but just in case). */ - float **chanptr_end{mChannelPtrs.get()}; + auto chanptr_end = mChannelPtrs.begin(); for(const auto &data : datas) { length = minu(length, data.maxsize/sizeof(float)); @@ -1487,7 +1505,7 @@ void PipeWirePlayback::outputCallback() noexcept data.chunk->size = length * sizeof(float); } - mDevice->renderSamples({mChannelPtrs.get(), chanptr_end}, length); + mDevice->renderSamples(mChannelPtrs, length); pw_buf->size = length; pw_stream_queue_buffer(mStream.get(), pw_buf); @@ -1590,7 +1608,7 @@ bool PipeWirePlayback::reset() } mStreamListener = {}; mRateMatch = nullptr; - mTimeBase = GetDeviceClockTime(mDevice); + mTimeBase = mDevice->getClockTime(); /* If connecting to a specific device, update various device parameters to * match its format. @@ -1611,11 +1629,12 @@ bool PipeWirePlayback::reset() { /* Scale the update size if the sample rate changes. */ const double scale{static_cast<double>(match->mSampleRate) / mDevice->Frequency}; - const double numbufs{static_cast<double>(mDevice->BufferSize)/mDevice->UpdateSize}; + const double updatesize{std::round(mDevice->UpdateSize * scale)}; + const double buffersize{std::round(mDevice->BufferSize * scale)}; + mDevice->Frequency = match->mSampleRate; - mDevice->UpdateSize = static_cast<uint>(clampd(mDevice->UpdateSize*scale + 0.5, - 64.0, 8192.0)); - mDevice->BufferSize = static_cast<uint>(numbufs*mDevice->UpdateSize + 0.5); + mDevice->UpdateSize = static_cast<uint>(clampd(updatesize, 64.0, 8192.0)); + mDevice->BufferSize = static_cast<uint>(maxd(buffersize, 128.0)); } if(!mDevice->Flags.test(ChannelsRequest) && match->mChannels != InvalidChannelConfig) mDevice->FmtChans = match->mChannels; @@ -1673,7 +1692,7 @@ bool PipeWirePlayback::reset() pw_stream_flags flags{PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_INACTIVE | PW_STREAM_FLAG_MAP_BUFFERS}; - if(GetConfigValueBool(mDevice->DeviceName.c_str(), "pipewire", "rt-mix", true)) + if(GetConfigValueBool(mDevice->DeviceName, "pipewire", "rt-mix", false)) flags |= PW_STREAM_FLAG_RT_PROCESS; if(int res{pw_stream_connect(mStream.get(), PW_DIRECTION_OUTPUT, PwIdAny, flags, ¶ms, 1)}) throw al::backend_exception{al::backend_error::DeviceError, @@ -1698,8 +1717,7 @@ bool PipeWirePlayback::reset() */ plock.unlock(); - mNumChannels = mDevice->channelsFromFmt(); - mChannelPtrs = std::make_unique<float*[]>(mNumChannels); + mChannelPtrs.resize(mDevice->channelsFromFmt()); setDefaultWFXChannelOrder(); @@ -1757,7 +1775,7 @@ void PipeWirePlayback::start() mDevice->UpdateSize = updatesize; mDevice->BufferSize = static_cast<uint>(ptime.buffered + delay + - totalbuffers*updatesize); + uint64_t{totalbuffers}*updatesize); break; } #else @@ -1791,8 +1809,7 @@ void PipeWirePlayback::stop() { MainloopUniqueLock plock{mLoop}; if(int res{pw_stream_set_active(mStream.get(), false)}) - throw al::backend_exception{al::backend_error::DeviceError, - "Failed to stop PipeWire stream (res: %d)", res}; + ERR("Failed to stop PipeWire stream (res: %d)\n", res); /* Wait for the stream to stop playing. */ plock.wait([stream=mStream.get()]() @@ -1824,10 +1841,10 @@ ClockLatency PipeWirePlayback::getClockLatency() uint refcount; do { refcount = mDevice->waitForMix(); - mixtime = GetDeviceClockTime(mDevice); + mixtime = mDevice->getClockTime(); clock_gettime(CLOCK_MONOTONIC, &tspec); std::atomic_thread_fence(std::memory_order_acquire); - } while(refcount != ReadRef(mDevice->MixCount)); + } while(refcount != mDevice->mMixCount.load(std::memory_order_relaxed)); /* Convert the monotonic clock, stream ticks, and stream delay to * nanoseconds. @@ -1916,9 +1933,7 @@ class PipeWireCapture final : public BackendBase { public: PipeWireCapture(DeviceBase *device) noexcept : BackendBase{device} { } - ~PipeWireCapture() { if(mLoop) mLoop.stop(); } - - DEF_NEWDEL(PipeWireCapture) + ~PipeWireCapture() final { if(mLoop) mLoop.stop(); } }; @@ -1934,7 +1949,8 @@ void PipeWireCapture::inputCallback() noexcept const uint offset{minu(bufdata->chunk->offset, bufdata->maxsize)}; const uint size{minu(bufdata->chunk->size, bufdata->maxsize - offset)}; - mRing->write(static_cast<char*>(bufdata->data) + offset, size / mRing->getElemSize()); + std::ignore = mRing->write(static_cast<char*>(bufdata->data) + offset, + size / mRing->getElemSize()); pw_stream_queue_buffer(mStream.get(), pw_buf); } @@ -2057,7 +2073,8 @@ void PipeWireCapture::open(std::string_view name) static constexpr uint32_t pod_buffer_size{1024}; PodDynamicBuilder b(pod_buffer_size); - const spa_pod *params[]{spa_format_audio_raw_build(b.get(), SPA_PARAM_EnumFormat, &info)}; + std::array params{static_cast<const spa_pod*>(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"}; @@ -2099,7 +2116,7 @@ void PipeWireCapture::open(std::string_view name) constexpr pw_stream_flags Flags{PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_INACTIVE | PW_STREAM_FLAG_MAP_BUFFERS | PW_STREAM_FLAG_RT_PROCESS}; - if(int res{pw_stream_connect(mStream.get(), PW_DIRECTION_INPUT, PwIdAny, Flags, params, 1)}) + if(int res{pw_stream_connect(mStream.get(), PW_DIRECTION_INPUT, PwIdAny, Flags, params.data(), 1)}) throw al::backend_exception{al::backend_error::DeviceError, "Error connecting PipeWire stream (res: %d)", res}; @@ -2145,8 +2162,7 @@ void PipeWireCapture::stop() { MainloopUniqueLock plock{mLoop}; if(int res{pw_stream_set_active(mStream.get(), false)}) - throw al::backend_exception{al::backend_error::DeviceError, - "Failed to stop PipeWire stream (res: %d)", res}; + ERR("Failed to stop PipeWire stream (res: %d)\n", res); plock.wait([stream=mStream.get()]() { return pw_stream_get_state(stream, nullptr) != PW_STREAM_STATE_STREAMING; }); @@ -2156,7 +2172,7 @@ uint PipeWireCapture::availableSamples() { return static_cast<uint>(mRing->readSpace()); } void PipeWireCapture::captureSamples(std::byte *buffer, uint samples) -{ mRing->read(buffer, samples); } +{ std::ignore = mRing->read(buffer, samples); } } // namespace @@ -2175,11 +2191,11 @@ bool PipeWireBackendFactory::init() } TRACE("Found PipeWire version \"%s\" (%s or newer)\n", version, pw_get_headers_version()); - pw_init(0, nullptr); + pw_init(nullptr, nullptr); if(!gEventHandler.init()) return false; - if(!GetConfigValueBool(nullptr, "pipewire", "assume-audio", false) + if(!GetConfigValueBool({}, "pipewire", "assume-audio", false) && !gEventHandler.waitForAudio()) { gEventHandler.kill(); diff --git a/alc/backends/portaudio.cpp b/alc/backends/portaudio.cpp index 979a54d6..7c61e134 100644 --- a/alc/backends/portaudio.cpp +++ b/alc/backends/portaudio.cpp @@ -39,7 +39,8 @@ namespace { -constexpr char pa_device[] = "PortAudio Default"; +/* NOLINTNEXTLINE(*-avoid-c-arrays) */ +constexpr char pa_device[]{"PortAudio Default"}; #ifdef HAVE_DYNLOAD @@ -78,13 +79,6 @@ struct PortPlayback final : public BackendBase { int writeCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags) noexcept; - static int writeCallbackC(const void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, - const PaStreamCallbackFlags statusFlags, void *userData) noexcept - { - return static_cast<PortPlayback*>(userData)->writeCallback(inputBuffer, outputBuffer, - framesPerBuffer, timeInfo, statusFlags); - } void open(std::string_view name) override; bool reset() override; @@ -94,8 +88,6 @@ struct PortPlayback final : public BackendBase { PaStream *mStream{nullptr}; PaStreamParameters mParams{}; uint mUpdateSize{0u}; - - DEF_NEWDEL(PortPlayback) }; PortPlayback::~PortPlayback() @@ -125,7 +117,7 @@ void PortPlayback::open(std::string_view name) static_cast<int>(name.length()), name.data()}; PaStreamParameters params{}; - auto devidopt = ConfigValueInt(nullptr, "port", "device"); + auto devidopt = ConfigValueInt({}, "port", "device"); if(devidopt && *devidopt >= 0) params.device = *devidopt; else params.device = Pa_GetDefaultOutputDevice(); params.suggestedLatency = mDevice->BufferSize / static_cast<double>(mDevice->Frequency); @@ -156,19 +148,21 @@ void PortPlayback::open(std::string_view name) break; } -retry_open: + static constexpr auto writeCallback = [](const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, + const PaStreamCallbackFlags statusFlags, void *userData) noexcept + { + return static_cast<PortPlayback*>(userData)->writeCallback(inputBuffer, outputBuffer, + framesPerBuffer, timeInfo, statusFlags); + }; PaStream *stream{}; - PaError err{Pa_OpenStream(&stream, nullptr, ¶ms, mDevice->Frequency, mDevice->UpdateSize, - paNoFlag, &PortPlayback::writeCallbackC, this)}; - if(err != paNoError) + while(PaError err{Pa_OpenStream(&stream, nullptr, ¶ms, mDevice->Frequency, + mDevice->UpdateSize, paNoFlag, writeCallback, this)}) { - if(params.sampleFormat == paFloat32) - { - params.sampleFormat = paInt16; - goto retry_open; - } - throw al::backend_exception{al::backend_error::NoDevice, "Failed to open stream: %s", - Pa_GetErrorText(err)}; + if(params.sampleFormat != paFloat32) + throw al::backend_exception{al::backend_error::NoDevice, "Failed to open stream: %s", + Pa_GetErrorText(err)}; + params.sampleFormat = paInt16; } Pa_CloseStream(mStream); @@ -237,13 +231,6 @@ struct PortCapture final : public BackendBase { int readCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags) noexcept; - static int readCallbackC(const void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, - const PaStreamCallbackFlags statusFlags, void *userData) noexcept - { - return static_cast<PortCapture*>(userData)->readCallback(inputBuffer, outputBuffer, - framesPerBuffer, timeInfo, statusFlags); - } void open(std::string_view name) override; void start() override; @@ -252,11 +239,9 @@ struct PortCapture final : public BackendBase { uint availableSamples() override; PaStream *mStream{nullptr}; - PaStreamParameters mParams; + PaStreamParameters mParams{}; RingBufferPtr mRing{nullptr}; - - DEF_NEWDEL(PortCapture) }; PortCapture::~PortCapture() @@ -271,7 +256,7 @@ PortCapture::~PortCapture() int PortCapture::readCallback(const void *inputBuffer, void*, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo*, const PaStreamCallbackFlags) noexcept { - mRing->write(inputBuffer, framesPerBuffer); + std::ignore = mRing->write(inputBuffer, framesPerBuffer); return 0; } @@ -290,7 +275,7 @@ void PortCapture::open(std::string_view name) mRing = RingBuffer::Create(samples, frame_size, false); - auto devidopt = ConfigValueInt(nullptr, "port", "capture"); + auto devidopt = ConfigValueInt({}, "port", "capture"); if(devidopt && *devidopt >= 0) mParams.device = *devidopt; else mParams.device = Pa_GetDefaultOutputDevice(); mParams.suggestedLatency = 0.0f; @@ -320,8 +305,15 @@ void PortCapture::open(std::string_view name) } mParams.channelCount = static_cast<int>(mDevice->channelsFromFmt()); + static constexpr auto readCallback = [](const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, + const PaStreamCallbackFlags statusFlags, void *userData) noexcept + { + return static_cast<PortCapture*>(userData)->readCallback(inputBuffer, outputBuffer, + framesPerBuffer, timeInfo, statusFlags); + }; PaError err{Pa_OpenStream(&mStream, &mParams, nullptr, mDevice->Frequency, - paFramesPerBufferUnspecified, paNoFlag, &PortCapture::readCallbackC, this)}; + paFramesPerBufferUnspecified, paNoFlag, readCallback, this)}; if(err != paNoError) throw al::backend_exception{al::backend_error::NoDevice, "Failed to open stream: %s", Pa_GetErrorText(err)}; @@ -350,15 +342,13 @@ uint PortCapture::availableSamples() { return static_cast<uint>(mRing->readSpace()); } void PortCapture::captureSamples(std::byte *buffer, uint samples) -{ mRing->read(buffer, samples); } +{ std::ignore = mRing->read(buffer, samples); } } // namespace bool PortBackendFactory::init() { - PaError err; - #ifdef HAVE_DYNLOAD if(!pa_handle) { @@ -377,7 +367,7 @@ bool PortBackendFactory::init() return false; #define LOAD_FUNC(f) do { \ - p##f = al::bit_cast<decltype(p##f)>(GetSymbol(pa_handle, #f)); \ + p##f = reinterpret_cast<decltype(p##f)>(GetSymbol(pa_handle, #f)); \ if(p##f == nullptr) \ { \ CloseLib(pa_handle); \ @@ -397,7 +387,8 @@ bool PortBackendFactory::init() LOAD_FUNC(Pa_GetStreamInfo); #undef LOAD_FUNC - if((err=Pa_Initialize()) != paNoError) + const PaError err{Pa_Initialize()}; + if(err != paNoError) { ERR("Pa_Initialize() returned an error: %s\n", Pa_GetErrorText(err)); CloseLib(pa_handle); @@ -406,7 +397,8 @@ bool PortBackendFactory::init() } } #else - if((err=Pa_Initialize()) != paNoError) + const PaError err{Pa_Initialize()}; + if(err != paNoError) { ERR("Pa_Initialize() returned an error: %s\n", Pa_GetErrorText(err)); return false; diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index bebc182d..e976fc27 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -28,12 +28,12 @@ #include <atomic> #include <bitset> #include <chrono> +#include <cstdint> +#include <cstdlib> #include <cstring> #include <limits> #include <mutex> #include <optional> -#include <stdint.h> -#include <stdlib.h> #include <string> #include <sys/types.h> #include <utility> @@ -320,11 +320,12 @@ public: explicit operator bool() const noexcept { return mLoop != nullptr; } + [[nodiscard]] auto start() const { return pa_threaded_mainloop_start(mLoop); } 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; } + [[nodiscard]] auto getApi() const { return pa_threaded_mainloop_get_api(mLoop); } + [[nodiscard]] auto getContext() const noexcept { return mContext; } auto lock() const { return pa_threaded_mainloop_lock(mLoop); } auto unlock() const { return pa_threaded_mainloop_unlock(mLoop); } @@ -509,8 +510,8 @@ void MainloopUniqueLock::connectContext() pa_context_set_state_callback(mutex()->mContext, [](pa_context *ctx, void *pdata) noexcept { return static_cast<MainloopUniqueLock*>(pdata)->contextStateCallback(ctx); }, this); - int err; - if((err=pa_context_connect(mutex()->mContext, nullptr, pulse_ctx_flags, nullptr)) >= 0) + int err{pa_context_connect(mutex()->mContext, nullptr, pulse_ctx_flags, nullptr)}; + if(err >= 0) { pa_context_state_t state; while((state=pa_context_get_state(mutex()->mContext)) != PA_CONTEXT_READY) @@ -657,14 +658,12 @@ struct PulsePlayback final : public BackendBase { std::optional<std::string> mDeviceName{std::nullopt}; bool mIs51Rear{false}; - pa_buffer_attr mAttr; - pa_sample_spec mSpec; + pa_buffer_attr mAttr{}; + pa_sample_spec mSpec{}; pa_stream *mStream{nullptr}; uint mFrameSize{0u}; - - DEF_NEWDEL(PulsePlayback) }; PulsePlayback::~PulsePlayback() @@ -753,9 +752,9 @@ void PulsePlayback::sinkInfoCallback(pa_context*, const pa_sink_info *info, int else { mIs51Rear = false; - char chanmap_str[PA_CHANNEL_MAP_SNPRINT_MAX]{}; - pa_channel_map_snprint(chanmap_str, sizeof(chanmap_str), &info->channel_map); - WARN("Failed to find format for channel map:\n %s\n", chanmap_str); + std::array<char,PA_CHANNEL_MAP_SNPRINT_MAX> chanmap_str{}; + pa_channel_map_snprint(chanmap_str.data(), chanmap_str.size(), &info->channel_map); + WARN("Failed to find format for channel map:\n %s\n", chanmap_str.data()); } if(info->active_port) @@ -784,7 +783,9 @@ void PulsePlayback::streamMovedCallback(pa_stream *stream) noexcept void PulsePlayback::open(std::string_view name) { mMainloop = PulseMainloop::Create(); - mMainloop.start(); + if(mMainloop.start() != 0) + throw al::backend_exception{al::backend_error::DeviceError, + "Failed to start device mainloop"}; const char *pulse_name{nullptr}; const char *dev_name{nullptr}; @@ -807,7 +808,7 @@ void PulsePlayback::open(std::string_view name) pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | PA_STREAM_FIX_CHANNELS}; - if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", true)) + if(!GetConfigValueBool({}, "pulse", "allow-moves", true)) flags |= PA_STREAM_DONT_MOVE; pa_sample_spec spec{}; @@ -866,9 +867,9 @@ bool PulsePlayback::reset() pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_EARLY_REQUESTS}; - if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", true)) + if(!GetConfigValueBool({}, "pulse", "allow-moves", true)) flags |= PA_STREAM_DONT_MOVE; - if(GetConfigValueBool(mDevice->DeviceName.c_str(), "pulse", "adjust-latency", false)) + if(GetConfigValueBool(mDevice->DeviceName, "pulse", "adjust-latency", false)) { /* ADJUST_LATENCY can't be specified with EARLY_REQUESTS, for some * reason. So if the user wants to adjust the overall device latency, @@ -877,7 +878,7 @@ bool PulsePlayback::reset() flags &= ~PA_STREAM_EARLY_REQUESTS; flags |= PA_STREAM_ADJUST_LATENCY; } - if(GetConfigValueBool(mDevice->DeviceName.c_str(), "pulse", "fix-rate", false) + if(GetConfigValueBool(mDevice->DeviceName, "pulse", "fix-rate", false) || !mDevice->Flags.test(FrequencyRequest)) flags |= PA_STREAM_FIX_RATE; @@ -967,8 +968,9 @@ bool PulsePlayback::reset() const auto scale = static_cast<double>(mSpec.rate) / mDevice->Frequency; const auto perlen = static_cast<uint>(clampd(scale*mDevice->UpdateSize + 0.5, 64.0, 8192.0)); - const auto buflen = static_cast<uint>(clampd(scale*mDevice->BufferSize + 0.5, perlen*2, - std::numeric_limits<int>::max()/mFrameSize)); + const auto bufmax = uint{std::numeric_limits<int>::max() / mFrameSize}; + const auto buflen = static_cast<uint>(clampd(scale*mDevice->BufferSize + 0.5, perlen*2.0, + bufmax)); mAttr.maxlength = ~0u; mAttr.tlength = buflen * mFrameSize; @@ -1034,7 +1036,7 @@ ClockLatency PulsePlayback::getClockLatency() { MainloopUniqueLock plock{mMainloop}; - ret.ClockTime = GetDeviceClockTime(mDevice); + ret.ClockTime = mDevice->getClockTime(); err = pa_stream_get_latency(mStream, &latency, &neg); } @@ -1087,8 +1089,6 @@ struct PulseCapture final : public BackendBase { pa_sample_spec mSpec{}; pa_stream *mStream{nullptr}; - - DEF_NEWDEL(PulseCapture) }; PulseCapture::~PulseCapture() @@ -1127,7 +1127,9 @@ void PulseCapture::open(std::string_view name) if(!mMainloop) { mMainloop = PulseMainloop::Create(); - mMainloop.start(); + if(mMainloop.start() != 0) + throw al::backend_exception{al::backend_error::DeviceError, + "Failed to start device mainloop"}; } const char *pulse_name{nullptr}; @@ -1214,7 +1216,7 @@ void PulseCapture::open(std::string_view name) mAttr.fragsize = minu(samples, 50*mDevice->Frequency/1000) * frame_size; pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_ADJUST_LATENCY}; - if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", true)) + if(!GetConfigValueBool({}, "pulse", "allow-moves", true)) flags |= PA_STREAM_DONT_MOVE; TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); @@ -1362,7 +1364,7 @@ ClockLatency PulseCapture::getClockLatency() { MainloopUniqueLock plock{mMainloop}; - ret.ClockTime = GetDeviceClockTime(mDevice); + ret.ClockTime = mDevice->getClockTime(); err = pa_stream_get_latency(mStream, &latency, &neg); } @@ -1387,9 +1389,6 @@ bool PulseBackendFactory::init() #ifdef HAVE_DYNLOAD if(!pulse_handle) { - bool ret{true}; - std::string missing_funcs; - #ifdef _WIN32 #define PALIB "libpulse-0.dll" #elif defined(__APPLE__) && defined(__MACH__) @@ -1404,17 +1403,15 @@ bool PulseBackendFactory::init() return false; } + std::string missing_funcs; #define LOAD_FUNC(x) do { \ - p##x = al::bit_cast<decltype(p##x)>(GetSymbol(pulse_handle, #x)); \ - if(!(p##x)) { \ - ret = false; \ - missing_funcs += "\n" #x; \ - } \ + p##x = reinterpret_cast<decltype(p##x)>(GetSymbol(pulse_handle, #x)); \ + if(!(p##x)) missing_funcs += "\n" #x; \ } while(0) PULSE_FUNCS(LOAD_FUNC) #undef LOAD_FUNC - if(!ret) + if(!missing_funcs.empty()) { WARN("Missing expected functions:%s\n", missing_funcs.c_str()); CloseLib(pulse_handle); @@ -1425,14 +1422,18 @@ bool PulseBackendFactory::init() #endif /* HAVE_DYNLOAD */ pulse_ctx_flags = PA_CONTEXT_NOFLAGS; - if(!GetConfigValueBool(nullptr, "pulse", "spawn-server", false)) + if(!GetConfigValueBool({}, "pulse", "spawn-server", false)) pulse_ctx_flags |= PA_CONTEXT_NOAUTOSPAWN; try { if(!gGlobalMainloop) { gGlobalMainloop = PulseMainloop::Create(); - gGlobalMainloop.start(); + if(gGlobalMainloop.start() != 0) + { + gGlobalMainloop = nullptr; + return false; + } } MainloopUniqueLock plock{gGlobalMainloop}; diff --git a/alc/backends/sdl2.cpp b/alc/backends/sdl2.cpp index f5ed4316..b69f17fd 100644 --- a/alc/backends/sdl2.cpp +++ b/alc/backends/sdl2.cpp @@ -26,6 +26,7 @@ #include <cstdlib> #include <cstring> #include <string> +#include <string_view> #include "almalloc.h" #include "alnumeric.h" @@ -46,7 +47,9 @@ namespace { #define DEVNAME_PREFIX "" #endif -constexpr char defaultDeviceName[] = DEVNAME_PREFIX "Default Device"; +constexpr auto getDevicePrefix() noexcept -> std::string_view { return DEVNAME_PREFIX; } +constexpr auto getDefaultDeviceName() noexcept -> std::string_view +{ return DEVNAME_PREFIX "Default Device"; } struct Sdl2Backend final : public BackendBase { Sdl2Backend(DeviceBase *device) noexcept : BackendBase{device} { } @@ -66,8 +69,6 @@ struct Sdl2Backend final : public BackendBase { DevFmtChannels mFmtChans{}; DevFmtType mFmtType{}; uint mUpdateSize{0u}; - - DEF_NEWDEL(Sdl2Backend) }; Sdl2Backend::~Sdl2Backend() @@ -108,6 +109,7 @@ void Sdl2Backend::open(std::string_view name) /* Passing nullptr to SDL_OpenAudioDevice opens a default, which isn't * necessarily the first in the list. */ + const auto defaultDeviceName = getDefaultDeviceName(); SDL_AudioDeviceID devid; if(name.empty() || name == defaultDeviceName) { @@ -116,13 +118,13 @@ void Sdl2Backend::open(std::string_view name) } else { - const size_t prefix_len = strlen(DEVNAME_PREFIX); - if(name.length() >= prefix_len && strncmp(name.data(), DEVNAME_PREFIX, prefix_len) == 0) + const auto namePrefix = getDevicePrefix(); + if(name.size() >= namePrefix.size() && name.substr(0, namePrefix.size()) == namePrefix) { /* Copy the string_view to a string to ensure it's null terminated * for this call. */ - const std::string devname{name.substr(prefix_len)}; + const std::string devname{name.substr(namePrefix.size())}; devid = SDL_OpenAudioDevice(devname.c_str(), SDL_FALSE, &want, &have, SDL_AUDIO_ALLOW_ANY_CHANGE); } @@ -217,13 +219,16 @@ std::string SDL2BackendFactory::probe(BackendType type) int num_devices{SDL_GetNumAudioDevices(SDL_FALSE)}; /* Includes null char. */ - outnames.append(defaultDeviceName, sizeof(defaultDeviceName)); + outnames += getDefaultDeviceName(); + outnames += '\0'; for(int i{0};i < num_devices;++i) { - std::string name{DEVNAME_PREFIX}; - name += SDL_GetAudioDeviceName(i, SDL_FALSE); - if(!name.empty()) - outnames.append(name.c_str(), name.length()+1); + outnames += getDevicePrefix(); + if(const char *name = SDL_GetAudioDeviceName(i, SDL_FALSE)) + outnames += name; + else + outnames += "Unknown Device Name #"+std::to_string(i); + outnames += '\0'; } return outnames; } diff --git a/alc/backends/sndio.cpp b/alc/backends/sndio.cpp index d54c337b..ce3de366 100644 --- a/alc/backends/sndio.cpp +++ b/alc/backends/sndio.cpp @@ -23,11 +23,11 @@ #include "sndio.h" #include <cinttypes> +#include <cstdio> +#include <cstdlib> +#include <cstring> #include <functional> #include <poll.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> #include <thread> #include <vector> @@ -43,10 +43,11 @@ namespace { -static const char sndio_device[] = "SndIO Default"; +/* NOLINTNEXTLINE(*-avoid-c-arrays) */ +constexpr char sndio_device[] = "SndIO Default"; struct SioPar : public sio_par { - SioPar() { sio_initpar(this); } + SioPar() : sio_par{} { sio_initpar(this); } void clear() { sio_initpar(this); } }; @@ -69,8 +70,6 @@ struct SndioPlayback final : public BackendBase { std::atomic<bool> mKillNow{true}; std::thread mThread; - - DEF_NEWDEL(SndioPlayback) }; SndioPlayback::~SndioPlayback() @@ -136,72 +135,75 @@ bool SndioPlayback::reset() SioPar par; auto tryfmt = mDevice->FmtType; -retry_params: - switch(tryfmt) + while(true) { - case DevFmtByte: - par.bits = 8; - par.sig = 1; - break; - case DevFmtUByte: - par.bits = 8; - par.sig = 0; - break; - case DevFmtShort: - par.bits = 16; - par.sig = 1; - break; - case DevFmtUShort: - par.bits = 16; - par.sig = 0; - break; - case DevFmtFloat: - case DevFmtInt: - par.bits = 32; - par.sig = 1; - break; - case DevFmtUInt: - par.bits = 32; - par.sig = 0; - break; - } - par.bps = SIO_BPS(par.bits); - par.le = SIO_LE_NATIVE; - par.msb = 1; - - par.rate = mDevice->Frequency; - par.pchan = mDevice->channelsFromFmt(); - - par.round = mDevice->UpdateSize; - par.appbufsz = mDevice->BufferSize - mDevice->UpdateSize; - if(!par.appbufsz) par.appbufsz = mDevice->UpdateSize; + switch(tryfmt) + { + case DevFmtByte: + par.bits = 8; + par.sig = 1; + break; + case DevFmtUByte: + par.bits = 8; + par.sig = 0; + break; + case DevFmtShort: + par.bits = 16; + par.sig = 1; + break; + case DevFmtUShort: + par.bits = 16; + par.sig = 0; + break; + case DevFmtFloat: + case DevFmtInt: + par.bits = 32; + par.sig = 1; + break; + case DevFmtUInt: + par.bits = 32; + par.sig = 0; + break; + } + par.bps = SIO_BPS(par.bits); + par.le = SIO_LE_NATIVE; + par.msb = 1; + + par.rate = mDevice->Frequency; + par.pchan = mDevice->channelsFromFmt(); + + par.round = mDevice->UpdateSize; + par.appbufsz = mDevice->BufferSize - mDevice->UpdateSize; + if(!par.appbufsz) par.appbufsz = mDevice->UpdateSize; + + try { + if(!sio_setpar(mSndHandle, &par)) + throw al::backend_exception{al::backend_error::DeviceError, + "Failed to set device parameters"}; + + par.clear(); + if(!sio_getpar(mSndHandle, &par)) + throw al::backend_exception{al::backend_error::DeviceError, + "Failed to get device parameters"}; + + if(par.bps > 1 && par.le != SIO_LE_NATIVE) + throw al::backend_exception{al::backend_error::DeviceError, + "%s-endian samples not supported", par.le ? "Little" : "Big"}; + if(par.bits < par.bps*8 && !par.msb) + throw al::backend_exception{al::backend_error::DeviceError, + "MSB-padded samples not supported (%u of %u bits)", par.bits, par.bps*8}; + if(par.pchan < 1) + throw al::backend_exception{al::backend_error::DeviceError, + "No playback channels on device"}; - try { - if(!sio_setpar(mSndHandle, &par)) - throw al::backend_exception{al::backend_error::DeviceError, - "Failed to set device parameters"}; - - par.clear(); - if(!sio_getpar(mSndHandle, &par)) - throw al::backend_exception{al::backend_error::DeviceError, - "Failed to get device parameters"}; - - if(par.bps > 1 && par.le != SIO_LE_NATIVE) - throw al::backend_exception{al::backend_error::DeviceError, - "%s-endian samples not supported", par.le ? "Little" : "Big"}; - if(par.bits < par.bps*8 && !par.msb) - throw al::backend_exception{al::backend_error::DeviceError, - "MSB-padded samples not supported (%u of %u bits)", par.bits, par.bps*8}; - if(par.pchan < 1) - throw al::backend_exception{al::backend_error::DeviceError, - "No playback channels on device"}; - } - catch(al::backend_exception &e) { - if(tryfmt == DevFmtShort) - throw; - par.clear(); - tryfmt = DevFmtShort; - goto retry_params; + break; + } + catch(al::backend_exception &e) { + if(tryfmt == DevFmtShort) + throw; + par.clear(); + tryfmt = DevFmtShort; + } } if(par.bps == 1) @@ -229,7 +231,7 @@ retry_params: mDevice->UpdateSize = par.round; mDevice->BufferSize = par.bufsz + par.round; - mBuffer.resize(mDevice->UpdateSize * par.pchan*par.bps); + mBuffer.resize(size_t{mDevice->UpdateSize} * par.pchan*par.bps); if(par.sig == 1) std::fill(mBuffer.begin(), mBuffer.end(), std::byte{}); else if(par.bits == 8) @@ -292,8 +294,6 @@ struct SndioCapture final : public BackendBase { std::atomic<bool> mKillNow{true}; std::thread mThread; - - DEF_NEWDEL(SndioCapture) }; SndioCapture::~SndioCapture() @@ -317,19 +317,19 @@ int SndioCapture::recordProc() return 1; } - auto fds = std::make_unique<pollfd[]>(static_cast<uint>(nfds_pre)); + auto fds = std::vector<pollfd>(static_cast<uint>(nfds_pre)); while(!mKillNow.load(std::memory_order_acquire) && mDevice->Connected.load(std::memory_order_acquire)) { /* Wait until there's some samples to read. */ - const int nfds{sio_pollfd(mSndHandle, fds.get(), POLLIN)}; + const int nfds{sio_pollfd(mSndHandle, fds.data(), POLLIN)}; if(nfds <= 0) { mDevice->handleDisconnect("Failed to get polling fds: %d", nfds); break; } - int pollres{::poll(fds.get(), static_cast<uint>(nfds), 2000)}; + int pollres{::poll(fds.data(), fds.size(), 2000)}; if(pollres < 0) { if(errno == EINTR) continue; @@ -339,7 +339,7 @@ int SndioCapture::recordProc() if(pollres == 0) continue; - const int revents{sio_revents(mSndHandle, fds.get())}; + const int revents{sio_revents(mSndHandle, fds.data())}; if((revents&POLLHUP)) { mDevice->handleDisconnect("Got POLLHUP from poll events"); @@ -373,8 +373,8 @@ int SndioCapture::recordProc() if(buffer.empty()) { /* Got samples to read, but no place to store it. Drop it. */ - static char junk[4096]; - sio_read(mSndHandle, junk, sizeof(junk) - (sizeof(junk)%frameSize)); + static std::array<char,4096> junk; + sio_read(mSndHandle, junk.data(), junk.size() - (junk.size()%frameSize)); } } @@ -461,7 +461,7 @@ void SndioCapture::open(std::string_view name) DevFmtTypeString(mDevice->FmtType), DevFmtChannelsString(mDevice->FmtChans), mDevice->Frequency, par.sig?'s':'u', par.bps*8, par.rchan, par.rate}; - mRing = RingBuffer::Create(mDevice->BufferSize, par.bps*par.rchan, false); + mRing = RingBuffer::Create(mDevice->BufferSize, size_t{par.bps}*par.rchan, false); mDevice->BufferSize = static_cast<uint>(mRing->writeSpace()); mDevice->UpdateSize = par.round; @@ -497,7 +497,7 @@ void SndioCapture::stop() } void SndioCapture::captureSamples(std::byte *buffer, uint samples) -{ mRing->read(buffer, samples); } +{ std::ignore = mRing->read(buffer, samples); } uint SndioCapture::availableSamples() { return static_cast<uint>(mRing->readSpace()); } diff --git a/alc/backends/solaris.cpp b/alc/backends/solaris.cpp index 38f9db19..c7387284 100644 --- a/alc/backends/solaris.cpp +++ b/alc/backends/solaris.cpp @@ -51,6 +51,7 @@ namespace { +/* NOLINTNEXTLINE(*-avoid-c-arrays) */ constexpr char solaris_device[] = "Solaris Default"; std::string solaris_driver{"/dev/audio"}; @@ -74,8 +75,6 @@ struct SolarisBackend final : public BackendBase { std::atomic<bool> mKillNow{true}; std::thread mThread; - - DEF_NEWDEL(SolarisBackend) }; SolarisBackend::~SolarisBackend() @@ -91,7 +90,7 @@ int SolarisBackend::mixerProc() althrd_setname(MIXER_THREAD_NAME); const size_t frame_step{mDevice->channelsFromFmt()}; - const uint frame_size{mDevice->frameSizeFromFmt()}; + const size_t frame_size{mDevice->frameSizeFromFmt()}; while(!mKillNow.load(std::memory_order_acquire) && mDevice->Connected.load(std::memory_order_acquire)) @@ -115,12 +114,12 @@ int SolarisBackend::mixerProc() continue; } - std::byte *write_ptr{mBuffer.data()}; - size_t to_write{mBuffer.size()}; - mDevice->renderSamples(write_ptr, static_cast<uint>(to_write/frame_size), frame_step); - while(to_write > 0 && !mKillNow.load(std::memory_order_acquire)) + al::span<std::byte> buffer{mBuffer}; + mDevice->renderSamples(buffer.data(), static_cast<uint>(buffer.size()/frame_size), + frame_step); + while(!buffer.empty() && !mKillNow.load(std::memory_order_acquire)) { - ssize_t wrote{write(mFd, write_ptr, to_write)}; + ssize_t wrote{write(mFd, buffer.data(), buffer.size())}; if(wrote < 0) { if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) @@ -130,8 +129,7 @@ int SolarisBackend::mixerProc() break; } - to_write -= static_cast<size_t>(wrote); - write_ptr += wrote; + buffer = buffer.subspan(static_cast<size_t>(wrote)); } } @@ -267,7 +265,7 @@ BackendFactory &SolarisBackendFactory::getFactory() bool SolarisBackendFactory::init() { - if(auto devopt = ConfigValueStr(nullptr, "solaris", "device")) + if(auto devopt = ConfigValueStr({}, "solaris", "device")) solaris_driver = std::move(*devopt); return true; } diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 3ee98457..4fcae59c 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -25,8 +25,8 @@ #define WIN32_LEAN_AND_MEAN #include <windows.h> -#include <stdlib.h> -#include <stdio.h> +#include <cstdio> +#include <cstdlib> #include <memory.h> #include <wtypes.h> @@ -171,7 +171,7 @@ constexpr AudioObjectType ChannelMask_X714{AudioObjectType_FrontLeft | AudioObje | AudioObjectType_TopFrontLeft | AudioObjectType_TopFrontRight | AudioObjectType_TopBackLeft | AudioObjectType_TopBackRight}; - +/* NOLINTNEXTLINE(*-avoid-c-arrays) */ constexpr char DevNameHead[] = "OpenAL Soft on "; constexpr size_t DevNameHeadLen{std::size(DevNameHead) - 1}; @@ -201,16 +201,16 @@ constexpr uint RefTime2Samples(const ReferenceTime &val, T srate) noexcept class GuidPrinter { - char mMsg[64]; + std::array<char,64> mMsg; public: GuidPrinter(const GUID &guid) { - std::snprintf(mMsg, std::size(mMsg), "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + std::snprintf(mMsg.data(), mMsg.size(), "{%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]); } - const char *c_str() const { return mMsg; } + [[nodiscard]] auto c_str() const -> const char* { return mMsg.data(); } }; struct PropVariant { @@ -270,13 +270,13 @@ private: struct DeviceListLock : public std::unique_lock<DeviceList> { using std::unique_lock<DeviceList>::unique_lock; - auto& getPlaybackList() const noexcept { return mutex()->mPlayback; } - auto& getCaptureList() const noexcept { return mutex()->mCapture; } + [[nodiscard]] auto& getPlaybackList() const noexcept { return mutex()->mPlayback; } + [[nodiscard]] 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; } + [[nodiscard]] auto getPlaybackDefaultId() const noexcept -> std::wstring_view { return mutex()->mPlaybackDefaultId; } void setCaptureDefaultId(std::wstring_view devid) const { mutex()->mCaptureDefaultId = devid; } - std::wstring_view getCaptureDefaultId() const noexcept { return mutex()->mCaptureDefaultId; } + [[nodiscard]] auto getCaptureDefaultId() const noexcept -> std::wstring_view { return mutex()->mCaptureDefaultId; } }; DeviceList gDeviceList; @@ -302,8 +302,10 @@ using DeviceHandle = ComPtr<IMMDevice>; using NameGUIDPair = std::pair<std::string,std::string>; static NameGUIDPair GetDeviceNameAndGuid(const DeviceHandle &device) { + /* NOLINTBEGIN(*-avoid-c-arrays) */ static constexpr char UnknownName[]{"Unknown Device Name"}; static constexpr char UnknownGuid[]{"Unknown Device GUID"}; + /* NOLINTEND(*-avoid-c-arrays) */ #if !defined(ALSOFT_UWP) std::string name, guid; @@ -384,9 +386,9 @@ struct DeviceHelper final : public IActivateAudioInterfaceCompletionHandler struct DeviceHelper final : private IMMNotificationClient #endif { +#if defined(ALSOFT_UWP) DeviceHelper() { -#if defined(ALSOFT_UWP) /* TODO: UWP also needs to watch for device added/removed events and * dynamically add/remove devices from the lists. */ @@ -411,8 +413,10 @@ struct DeviceHelper final : private IMMNotificationClient msg); } }); -#endif } +#else + DeviceHelper() = default; +#endif ~DeviceHelper() { #if defined(ALSOFT_UWP) @@ -1071,7 +1075,7 @@ struct WasapiPlayback final : public BackendBase, WasapiProxy { HANDLE mNotifyEvent{nullptr}; UINT32 mOrigBufferSize{}, mOrigUpdateSize{}; - std::unique_ptr<char[]> mResampleBuffer{}; + std::vector<char> mResampleBuffer{}; uint mBufferFilled{0}; SampleConverterPtr mResampler; @@ -1082,8 +1086,6 @@ struct WasapiPlayback final : public BackendBase, WasapiProxy { std::atomic<bool> mKillNow{true}; std::thread mThread; - - DEF_NEWDEL(WasapiPlayback) }; WasapiPlayback::~WasapiPlayback() @@ -1151,9 +1153,9 @@ FORCE_ALIGN int WasapiPlayback::mixerProc() { if(mBufferFilled == 0) { - mDevice->renderSamples(mResampleBuffer.get(), mDevice->UpdateSize, + mDevice->renderSamples(mResampleBuffer.data(), mDevice->UpdateSize, mFormat.Format.nChannels); - resbufferptr = mResampleBuffer.get(); + resbufferptr = mResampleBuffer.data(); mBufferFilled = mDevice->UpdateSize; } @@ -1249,7 +1251,7 @@ FORCE_ALIGN int WasapiPlayback::mixerSpatialProc() tmpbuffers.resize(buffers.size()); resbuffers.resize(buffers.size()); for(size_t i{0};i < tmpbuffers.size();++i) - resbuffers[i] = reinterpret_cast<float*>(mResampleBuffer.get()) + + resbuffers[i] = reinterpret_cast<float*>(mResampleBuffer.data()) + mDevice->UpdateSize*i; } } @@ -1496,7 +1498,7 @@ void WasapiPlayback::prepareFormat(WAVEFORMATEXTENSIBLE &OutputType) void WasapiPlayback::finalizeFormat(WAVEFORMATEXTENSIBLE &OutputType) { - if(!GetConfigValueBool(mDevice->DeviceName.c_str(), "wasapi", "allow-resampler", true)) + if(!GetConfigValueBool(mDevice->DeviceName, "wasapi", "allow-resampler", true)) mDevice->Frequency = OutputType.Format.nSamplesPerSec; else mDevice->Frequency = minu(mDevice->Frequency, OutputType.Format.nSamplesPerSec); @@ -1610,7 +1612,7 @@ bool WasapiPlayback::reset() HRESULT WasapiPlayback::resetProxy() { - if(GetConfigValueBool(mDevice->DeviceName.c_str(), "wasapi", "spatial-api", false)) + if(GetConfigValueBool(mDevice->DeviceName, "wasapi", "spatial-api", false)) { auto &audio = mAudio.emplace<SpatialDevice>(); HRESULT hr{sDeviceHelper->activateAudioClient(mMMDev, __uuidof(ISpatialAudioClient), @@ -1775,7 +1777,7 @@ 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)) + if(!GetConfigValueBool(mDevice->DeviceName, "wasapi", "allow-resampler", true)) mDevice->Frequency = OutputType.Format.nSamplesPerSec; else mDevice->Frequency = minu(mDevice->Frequency, OutputType.Format.nSamplesPerSec); @@ -1819,7 +1821,8 @@ HRESULT WasapiPlayback::resetProxy() mDevice->BufferSize = mDevice->UpdateSize*2; mResampler = nullptr; - mResampleBuffer = nullptr; + mResampleBuffer.clear(); + mResampleBuffer.shrink_to_fit(); mBufferFilled = 0; if(mDevice->Frequency != mFormat.Format.nSamplesPerSec) { @@ -1828,7 +1831,7 @@ HRESULT WasapiPlayback::resetProxy() mResampler = SampleConverter::Create(mDevice->FmtType, mDevice->FmtType, channelCount, mDevice->Frequency, mFormat.Format.nSamplesPerSec, Resampler::FastBSinc24); - mResampleBuffer = std::make_unique<char[]>(size_t{mDevice->UpdateSize} * channelCount * + mResampleBuffer.resize(size_t{mDevice->UpdateSize} * channelCount * mFormat.Format.wBitsPerSample / 8); TRACE("Created converter for %s/%s format, dst: %luhz (%u), src: %uhz (%u)\n", @@ -1950,15 +1953,16 @@ no_spatial: mDevice->BufferSize/2); mResampler = nullptr; - mResampleBuffer = nullptr; + mResampleBuffer.clear(); + mResampleBuffer.shrink_to_fit(); mBufferFilled = 0; if(mDevice->Frequency != mFormat.Format.nSamplesPerSec) { mResampler = SampleConverter::Create(mDevice->FmtType, mDevice->FmtType, mFormat.Format.nChannels, mDevice->Frequency, mFormat.Format.nSamplesPerSec, Resampler::FastBSinc24); - mResampleBuffer = std::make_unique<char[]>(size_t{mDevice->UpdateSize} * - mFormat.Format.nChannels * mFormat.Format.wBitsPerSample / 8); + mResampleBuffer.resize(size_t{mDevice->UpdateSize} * mFormat.Format.nChannels * + mFormat.Format.wBitsPerSample / 8); TRACE("Created converter for %s/%s format, dst: %luhz (%u), src: %uhz (%u)\n", DevFmtChannelsString(mDevice->FmtChans), DevFmtTypeString(mDevice->FmtType), @@ -2072,7 +2076,7 @@ ClockLatency WasapiPlayback::getClockLatency() ClockLatency ret; std::lock_guard<std::mutex> _{mMutex}; - ret.ClockTime = GetDeviceClockTime(mDevice); + ret.ClockTime = mDevice->getClockTime(); ret.Latency = seconds{mPadding.load(std::memory_order_relaxed)}; ret.Latency /= mFormat.Format.nSamplesPerSec; if(mResampler) @@ -2117,8 +2121,6 @@ struct WasapiCapture final : public BackendBase, WasapiProxy { std::atomic<bool> mKillNow{true}; std::thread mThread; - - DEF_NEWDEL(WasapiCapture) }; WasapiCapture::~WasapiCapture() @@ -2651,7 +2653,7 @@ void WasapiCapture::stopProxy() void WasapiCapture::captureSamples(std::byte *buffer, uint samples) -{ mRing->read(buffer, samples); } +{ std::ignore = mRing->read(buffer, samples); } uint WasapiCapture::availableSamples() { return static_cast<uint>(mRing->readSpace()); } diff --git a/alc/backends/wave.cpp b/alc/backends/wave.cpp index 794d5cb8..985bb539 100644 --- a/alc/backends/wave.cpp +++ b/alc/backends/wave.cpp @@ -55,38 +55,44 @@ using std::chrono::nanoseconds; using ubyte = unsigned char; using ushort = unsigned short; +struct FileDeleter { + void operator()(gsl::owner<FILE*> f) { fclose(f); } +}; +using FilePtr = std::unique_ptr<FILE,FileDeleter>; + +/* NOLINTNEXTLINE(*-avoid-c-arrays) */ constexpr char waveDevice[] = "Wave File Writer"; -constexpr ubyte SUBTYPE_PCM[]{ +constexpr std::array<ubyte,16> SUBTYPE_PCM{{ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 -}; -constexpr ubyte SUBTYPE_FLOAT[]{ +}}; +constexpr std::array<ubyte,16> SUBTYPE_FLOAT{{ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 -}; +}}; -constexpr ubyte SUBTYPE_BFORMAT_PCM[]{ +constexpr std::array<ubyte,16> SUBTYPE_BFORMAT_PCM{{ 0x01, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1, 0xca, 0x00, 0x00, 0x00 -}; +}}; -constexpr ubyte SUBTYPE_BFORMAT_FLOAT[]{ +constexpr std::array<ubyte,16> SUBTYPE_BFORMAT_FLOAT{{ 0x03, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1, 0xca, 0x00, 0x00, 0x00 -}; +}}; void fwrite16le(ushort val, FILE *f) { - ubyte data[2]{ static_cast<ubyte>(val&0xff), static_cast<ubyte>((val>>8)&0xff) }; - fwrite(data, 1, 2, f); + std::array data{static_cast<ubyte>(val&0xff), static_cast<ubyte>((val>>8)&0xff)}; + fwrite(data.data(), 1, data.size(), f); } void fwrite32le(uint val, FILE *f) { - ubyte data[4]{ static_cast<ubyte>(val&0xff), static_cast<ubyte>((val>>8)&0xff), - static_cast<ubyte>((val>>16)&0xff), static_cast<ubyte>((val>>24)&0xff) }; - fwrite(data, 1, 4, f); + std::array data{static_cast<ubyte>(val&0xff), static_cast<ubyte>((val>>8)&0xff), + static_cast<ubyte>((val>>16)&0xff), static_cast<ubyte>((val>>24)&0xff)}; + fwrite(data.data(), 1, data.size(), f); } @@ -101,23 +107,16 @@ struct WaveBackend final : public BackendBase { void start() override; void stop() override; - FILE *mFile{nullptr}; + FilePtr mFile{nullptr}; long mDataStart{-1}; std::vector<std::byte> mBuffer; std::atomic<bool> mKillNow{true}; std::thread mThread; - - DEF_NEWDEL(WaveBackend) }; -WaveBackend::~WaveBackend() -{ - if(mFile) - fclose(mFile); - mFile = nullptr; -} +WaveBackend::~WaveBackend() = default; int WaveBackend::mixerProc() { @@ -169,8 +168,8 @@ int WaveBackend::mixerProc() } } - const size_t fs{fwrite(mBuffer.data(), frameSize, mDevice->UpdateSize, mFile)}; - if(fs < mDevice->UpdateSize || ferror(mFile)) + const size_t fs{fwrite(mBuffer.data(), frameSize, mDevice->UpdateSize, mFile.get())}; + if(fs < mDevice->UpdateSize || ferror(mFile.get())) { ERR("Error writing to file\n"); mDevice->handleDisconnect("Failed to write playback samples"); @@ -196,7 +195,7 @@ int WaveBackend::mixerProc() void WaveBackend::open(std::string_view name) { - auto fname = ConfigValueStr(nullptr, "wave", "file"); + auto fname = ConfigValueStr({}, "wave", "file"); if(!fname) throw al::backend_exception{al::backend_error::NoDevice, "No wave output filename"}; @@ -212,10 +211,10 @@ void WaveBackend::open(std::string_view name) #ifdef _WIN32 { std::wstring wname{utf8_to_wstr(fname.value())}; - mFile = _wfopen(wname.c_str(), L"wb"); + mFile = FilePtr{_wfopen(wname.c_str(), L"wb")}; } #else - mFile = fopen(fname->c_str(), "wb"); + mFile = FilePtr{fopen(fname->c_str(), "wb")}; #endif if(!mFile) throw al::backend_exception{al::backend_error::DeviceError, "Could not open file '%s': %s", @@ -228,12 +227,11 @@ bool WaveBackend::reset() { uint channels{0}, bytes{0}, chanmask{0}; bool isbformat{false}; - size_t val; - fseek(mFile, 0, SEEK_SET); - clearerr(mFile); + fseek(mFile.get(), 0, SEEK_SET); + clearerr(mFile.get()); - if(GetConfigValueBool(nullptr, "wave", "bformat", false)) + if(GetConfigValueBool({}, "wave", "bformat", false)) { mDevice->FmtChans = DevFmtAmbi3D; mDevice->mAmbiOrder = 1; @@ -282,49 +280,48 @@ bool WaveBackend::reset() bytes = mDevice->bytesFromFmt(); channels = mDevice->channelsFromFmt(); - rewind(mFile); + rewind(mFile.get()); - fputs("RIFF", mFile); - fwrite32le(0xFFFFFFFF, mFile); // 'RIFF' header len; filled in at close + fputs("RIFF", mFile.get()); + fwrite32le(0xFFFFFFFF, mFile.get()); // 'RIFF' header len; filled in at close - fputs("WAVE", mFile); + fputs("WAVE", mFile.get()); - fputs("fmt ", mFile); - fwrite32le(40, mFile); // 'fmt ' header len; 40 bytes for EXTENSIBLE + fputs("fmt ", mFile.get()); + fwrite32le(40, mFile.get()); // 'fmt ' header len; 40 bytes for EXTENSIBLE // 16-bit val, format type id (extensible: 0xFFFE) - fwrite16le(0xFFFE, mFile); + fwrite16le(0xFFFE, mFile.get()); // 16-bit val, channel count - fwrite16le(static_cast<ushort>(channels), mFile); + fwrite16le(static_cast<ushort>(channels), mFile.get()); // 32-bit val, frequency - fwrite32le(mDevice->Frequency, mFile); + fwrite32le(mDevice->Frequency, mFile.get()); // 32-bit val, bytes per second - fwrite32le(mDevice->Frequency * channels * bytes, mFile); + fwrite32le(mDevice->Frequency * channels * bytes, mFile.get()); // 16-bit val, frame size - fwrite16le(static_cast<ushort>(channels * bytes), mFile); + fwrite16le(static_cast<ushort>(channels * bytes), mFile.get()); // 16-bit val, bits per sample - fwrite16le(static_cast<ushort>(bytes * 8), mFile); + fwrite16le(static_cast<ushort>(bytes * 8), mFile.get()); // 16-bit val, extra byte count - fwrite16le(22, mFile); + fwrite16le(22, mFile.get()); // 16-bit val, valid bits per sample - fwrite16le(static_cast<ushort>(bytes * 8), mFile); + fwrite16le(static_cast<ushort>(bytes * 8), mFile.get()); // 32-bit val, channel mask - fwrite32le(chanmask, mFile); + fwrite32le(chanmask, mFile.get()); // 16 byte GUID, sub-type format - val = fwrite((mDevice->FmtType == DevFmtFloat) ? - (isbformat ? SUBTYPE_BFORMAT_FLOAT : SUBTYPE_FLOAT) : - (isbformat ? SUBTYPE_BFORMAT_PCM : SUBTYPE_PCM), 1, 16, mFile); - (void)val; + std::ignore = fwrite((mDevice->FmtType == DevFmtFloat) ? + (isbformat ? SUBTYPE_BFORMAT_FLOAT.data() : SUBTYPE_FLOAT.data()) : + (isbformat ? SUBTYPE_BFORMAT_PCM.data() : SUBTYPE_PCM.data()), 1, 16, mFile.get()); - fputs("data", mFile); - fwrite32le(0xFFFFFFFF, mFile); // 'data' header len; filled in at close + fputs("data", mFile.get()); + fwrite32le(0xFFFFFFFF, mFile.get()); // 'data' header len; filled in at close - if(ferror(mFile)) + if(ferror(mFile.get())) { ERR("Error writing header: %s\n", strerror(errno)); return false; } - mDataStart = ftell(mFile); + mDataStart = ftell(mFile.get()); setDefaultWFXChannelOrder(); @@ -336,7 +333,7 @@ bool WaveBackend::reset() void WaveBackend::start() { - if(mDataStart > 0 && fseek(mFile, 0, SEEK_END) != 0) + if(mDataStart > 0 && fseek(mFile.get(), 0, SEEK_END) != 0) WARN("Failed to seek on output file\n"); try { mKillNow.store(false, std::memory_order_release); @@ -356,14 +353,14 @@ void WaveBackend::stop() if(mDataStart > 0) { - long size{ftell(mFile)}; + long size{ftell(mFile.get())}; if(size > 0) { long dataLen{size - mDataStart}; - if(fseek(mFile, 4, SEEK_SET) == 0) - fwrite32le(static_cast<uint>(size-8), mFile); // 'WAVE' header len - if(fseek(mFile, mDataStart-4, SEEK_SET) == 0) - fwrite32le(static_cast<uint>(dataLen), mFile); // 'data' header len + if(fseek(mFile.get(), 4, SEEK_SET) == 0) + fwrite32le(static_cast<uint>(size-8), mFile.get()); // 'WAVE' header len + if(fseek(mFile.get(), mDataStart-4, SEEK_SET) == 0) + fwrite32le(static_cast<uint>(dataLen), mFile.get()); // 'data' header len } } } diff --git a/alc/backends/winmm.cpp b/alc/backends/winmm.cpp index f0fb0a1c..e593defb 100644 --- a/alc/backends/winmm.cpp +++ b/alc/backends/winmm.cpp @@ -22,8 +22,8 @@ #include "winmm.h" -#include <stdlib.h> -#include <stdio.h> +#include <cstdlib> +#include <cstdio> #include <memory.h> #include <windows.h> @@ -46,6 +46,7 @@ #include "core/logging.h" #include "ringbuffer.h" #include "strutils.h" +#include "vector.h" #ifndef WAVE_FORMAT_IEEE_FLOAT #define WAVE_FORMAT_IEEE_FLOAT 0x0003 @@ -62,7 +63,7 @@ std::vector<std::string> CaptureDevices; bool checkName(const std::vector<std::string> &list, const std::string &name) { return std::find(list.cbegin(), list.cend(), name) != list.cend(); } -void ProbePlaybackDevices(void) +void ProbePlaybackDevices() { PlaybackDevices.clear(); @@ -93,7 +94,7 @@ void ProbePlaybackDevices(void) } } -void ProbeCaptureDevices(void) +void ProbeCaptureDevices() { CaptureDevices.clear(); @@ -144,6 +145,7 @@ struct WinMMPlayback final : public BackendBase { al::semaphore mSem; uint mIdx{0u}; std::array<WAVEHDR,4> mWaveBuffer{}; + al::vector<char,16> mBuffer; HWAVEOUT mOutHdl{nullptr}; @@ -151,8 +153,6 @@ struct WinMMPlayback final : public BackendBase { std::atomic<bool> mKillNow{true}; std::thread mThread; - - DEF_NEWDEL(WinMMPlayback) }; WinMMPlayback::~WinMMPlayback() @@ -160,9 +160,6 @@ WinMMPlayback::~WinMMPlayback() if(mOutHdl) waveOutClose(mOutHdl); mOutHdl = nullptr; - - al_free(mWaveBuffer[0].lpData); - std::fill(mWaveBuffer.begin(), mWaveBuffer.end(), WAVEHDR{}); } /* WinMMPlayback::waveOutProc @@ -313,11 +310,11 @@ bool WinMMPlayback::reset() } setDefaultWFXChannelOrder(); - uint BufferSize{mDevice->UpdateSize * mFormat.nChannels * mDevice->bytesFromFmt()}; + const uint BufferSize{mDevice->UpdateSize * mFormat.nChannels * mDevice->bytesFromFmt()}; - al_free(mWaveBuffer[0].lpData); + decltype(mBuffer)(BufferSize*mWaveBuffer.size()).swap(mBuffer); mWaveBuffer[0] = WAVEHDR{}; - mWaveBuffer[0].lpData = static_cast<char*>(al_calloc(16, BufferSize * mWaveBuffer.size())); + mWaveBuffer[0].lpData = mBuffer.data(); mWaveBuffer[0].dwBufferLength = BufferSize; for(size_t i{1};i < mWaveBuffer.size();i++) { @@ -380,6 +377,7 @@ struct WinMMCapture final : public BackendBase { al::semaphore mSem; uint mIdx{0}; std::array<WAVEHDR,4> mWaveBuffer{}; + al::vector<char,16> mBuffer; HWAVEIN mInHdl{nullptr}; @@ -389,8 +387,6 @@ struct WinMMCapture final : public BackendBase { std::atomic<bool> mKillNow{true}; std::thread mThread; - - DEF_NEWDEL(WinMMCapture) }; WinMMCapture::~WinMMCapture() @@ -399,9 +395,6 @@ WinMMCapture::~WinMMCapture() if(mInHdl) waveInClose(mInHdl); mInHdl = nullptr; - - al_free(mWaveBuffer[0].lpData); - std::fill(mWaveBuffer.begin(), mWaveBuffer.end(), WAVEHDR{}); } /* WinMMCapture::waveInProc @@ -435,7 +428,8 @@ int WinMMCapture::captureProc() WAVEHDR &waveHdr = mWaveBuffer[widx]; widx = (widx+1) % mWaveBuffer.size(); - mRing->write(waveHdr.lpData, waveHdr.dwBytesRecorded / mFormat.nBlockAlign); + std::ignore = mRing->write(waveHdr.lpData, + waveHdr.dwBytesRecorded / mFormat.nBlockAlign); mReadable.fetch_sub(1, std::memory_order_acq_rel); waveInAddBuffer(mInHdl, &waveHdr, sizeof(WAVEHDR)); } while(--todo); @@ -519,9 +513,9 @@ void WinMMCapture::open(std::string_view name) mRing = RingBuffer::Create(CapturedDataSize, mFormat.nBlockAlign, false); - al_free(mWaveBuffer[0].lpData); + decltype(mBuffer)(BufferSize*mWaveBuffer.size()).swap(mBuffer); mWaveBuffer[0] = WAVEHDR{}; - mWaveBuffer[0].lpData = static_cast<char*>(al_calloc(16, BufferSize * mWaveBuffer.size())); + mWaveBuffer[0].lpData = mBuffer.data(); mWaveBuffer[0].dwBufferLength = BufferSize; for(size_t i{1};i < mWaveBuffer.size();++i) { @@ -573,7 +567,7 @@ void WinMMCapture::stop() } void WinMMCapture::captureSamples(std::byte *buffer, uint samples) -{ mRing->read(buffer, samples); } +{ std::ignore = mRing->read(buffer, samples); } uint WinMMCapture::availableSamples() { return static_cast<uint>(mRing->readSpace()); } |