From 0cad3f7391959d1ad83f948df37db608e3f0e72c Mon Sep 17 00:00:00 2001
From: Chris Robinson <chris.kcat@gmail.com>
Date: Thu, 29 Jun 2023 02:37:08 -0700
Subject: Specify a callback using a lambda

---
 alc/backends/sdl2.cpp | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

(limited to 'alc/backends/sdl2.cpp')

diff --git a/alc/backends/sdl2.cpp b/alc/backends/sdl2.cpp
index a4a5a9ac..e1e40e27 100644
--- a/alc/backends/sdl2.cpp
+++ b/alc/backends/sdl2.cpp
@@ -53,8 +53,6 @@ struct Sdl2Backend final : public BackendBase {
     ~Sdl2Backend() override;
 
     void audioCallback(Uint8 *stream, int len) noexcept;
-    static void audioCallbackC(void *ptr, Uint8 *stream, int len) noexcept
-    { static_cast<Sdl2Backend*>(ptr)->audioCallback(stream, len); }
 
     void open(const char *name) override;
     bool reset() override;
@@ -103,7 +101,8 @@ void Sdl2Backend::open(const char *name)
     }
     want.channels = (mDevice->FmtChans == DevFmtMono) ? 1 : 2;
     want.samples = static_cast<Uint16>(minu(mDevice->UpdateSize, 8192));
-    want.callback = &Sdl2Backend::audioCallbackC;
+    want.callback = [](void *ptr, Uint8 *stream, int len) noexcept
+    { return static_cast<Sdl2Backend*>(ptr)->audioCallback(stream, len); };
     want.userdata = this;
 
     /* Passing nullptr to SDL_OpenAudioDevice opens a default, which isn't
-- 
cgit v1.2.3


From 9296af5566afea4ba4cb78b374ef3ee0bf9bc04b Mon Sep 17 00:00:00 2001
From: Chris Robinson <chris.kcat@gmail.com>
Date: Sun, 6 Aug 2023 18:49:42 -0700
Subject: Use a string_view for the backend open method

---
 alc/alc.cpp                 | 41 ++++++++++++++++++++++++++++++-----
 alc/backends/alsa.cpp       | 16 +++++++-------
 alc/backends/base.h         |  3 ++-
 alc/backends/coreaudio.cpp  | 36 +++++++++++++++---------------
 alc/backends/dsound.cpp     | 22 ++++++++++---------
 alc/backends/jack.cpp       | 18 +++++++--------
 alc/backends/loopback.cpp   |  4 ++--
 alc/backends/null.cpp       | 12 +++++-----
 alc/backends/oboe.cpp       | 24 ++++++++++----------
 alc/backends/opensl.cpp     | 24 ++++++++++----------
 alc/backends/oss.cpp        | 16 +++++++-------
 alc/backends/pipewire.cpp   | 21 +++++++++---------
 alc/backends/portaudio.cpp  | 24 ++++++++++----------
 alc/backends/pulseaudio.cpp | 16 +++++++-------
 alc/backends/sdl2.cpp       | 27 +++++++++++++++++------
 alc/backends/sndio.cpp      | 24 ++++++++++----------
 alc/backends/solaris.cpp    | 12 +++++-----
 alc/backends/wasapi.cpp     | 53 +++++++++++++++++++++++----------------------
 alc/backends/wave.cpp       | 14 ++++++------
 alc/backends/winmm.cpp      | 20 ++++++++---------
 common/strutils.cpp         | 17 ++++++++-------
 common/strutils.h           |  5 +++--
 22 files changed, 249 insertions(+), 200 deletions(-)

(limited to 'alc/backends/sdl2.cpp')

diff --git a/alc/alc.cpp b/alc/alc.cpp
index 82f3ec4b..45a55793 100644
--- a/alc/alc.cpp
+++ b/alc/alc.cpp
@@ -2905,9 +2905,26 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) noexcep
     device->NumAuxSends = DefaultSends;
 
     try {
+        /* We need to ensure the device name isn't too long. The string_view is
+         * printed using the "%.*s" formatter, which uses an int for the
+         * precision/length. It wouldn't be a significant problem if larger
+         * values simply printed fewer characters due to truncation, but
+         * negative values are ignored, treating it like a normal null-
+         * terminated string, and string_views don't need to be null-
+         * terminated.
+         *
+         * Other than the annoyance of checking, this shouldn't be a problem.
+         * Two billion bytes is enough for a device name.
+         */
+        const std::string_view devname{deviceName ? deviceName : ""};
+        if(devname.length() >= std::numeric_limits<int>::max())
+            throw al::backend_exception{al::backend_error::NoDevice,
+                "Device name too long (%zu >= %d)", devname.length(),
+                std::numeric_limits<int>::max()};
+
         auto backend = PlaybackFactory->createBackend(device.get(), BackendType::Playback);
         std::lock_guard<std::recursive_mutex> _{ListLock};
-        backend->open(deviceName);
+        backend->open(devname);
         device->Backend = std::move(backend);
     }
     catch(al::backend_exception &e) {
@@ -3024,14 +3041,20 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName,
     device->UpdateSize = static_cast<uint>(samples);
     device->BufferSize = static_cast<uint>(samples);
 
+    TRACE("Capture format: %s, %s, %uhz, %u / %u buffer\n", DevFmtChannelsString(device->FmtChans),
+        DevFmtTypeString(device->FmtType), device->Frequency, device->UpdateSize,
+        device->BufferSize);
+
     try {
-        TRACE("Capture format: %s, %s, %uhz, %u / %u buffer\n",
-            DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType),
-            device->Frequency, device->UpdateSize, device->BufferSize);
+        const std::string_view devname{deviceName ? deviceName : ""};
+        if(devname.length() >= std::numeric_limits<int>::max())
+            throw al::backend_exception{al::backend_error::NoDevice,
+                "Device name too long (%zu >= %d)", devname.length(),
+                std::numeric_limits<int>::max()};
 
         auto backend = CaptureFactory->createBackend(device.get(), BackendType::Capture);
         std::lock_guard<std::recursive_mutex> _{ListLock};
-        backend->open(deviceName);
+        backend->open(devname);
         device->Backend = std::move(backend);
     }
     catch(al::backend_exception &e) {
@@ -3393,8 +3416,14 @@ FORCE_ALIGN ALCboolean ALC_APIENTRY alcReopenDeviceSOFT(ALCdevice *device,
 
     BackendPtr newbackend;
     try {
+        const std::string_view devname{deviceName ? deviceName : ""};
+        if(devname.length() >= std::numeric_limits<int>::max())
+            throw al::backend_exception{al::backend_error::NoDevice,
+                "Device name too long (%zu >= %d)", devname.length(),
+                std::numeric_limits<int>::max()};
+
         newbackend = PlaybackFactory->createBackend(dev.get(), BackendType::Playback);
-        newbackend->open(deviceName);
+        newbackend->open(devname);
     }
     catch(al::backend_exception &e) {
         listlock.unlock();
diff --git a/alc/backends/alsa.cpp b/alc/backends/alsa.cpp
index 83eef183..0d9ff30d 100644
--- a/alc/backends/alsa.cpp
+++ b/alc/backends/alsa.cpp
@@ -427,7 +427,7 @@ struct AlsaPlayback final : public BackendBase {
     int mixerProc();
     int mixerNoMMapProc();
 
-    void open(const char *name) override;
+    void open(std::string_view name) override;
     bool reset() override;
     void start() override;
     void stop() override;
@@ -626,10 +626,10 @@ int AlsaPlayback::mixerNoMMapProc()
 }
 
 
-void AlsaPlayback::open(const char *name)
+void AlsaPlayback::open(std::string_view name)
 {
     std::string driver{"default"};
-    if(name)
+    if(!name.empty())
     {
         if(PlaybackDevices.empty())
             PlaybackDevices = probe_devices(SND_PCM_STREAM_PLAYBACK);
@@ -638,7 +638,7 @@ void AlsaPlayback::open(const char *name)
             [name](const DevMap &entry) -> bool { return entry.name == name; });
         if(iter == PlaybackDevices.cend())
             throw al::backend_exception{al::backend_error::NoDevice,
-                "Device name \"%s\" not found", name};
+                "Device name \"%.*s\" not found", static_cast<int>(name.length()), name.data()};
         driver = iter->device_name;
     }
     else
@@ -871,7 +871,7 @@ struct AlsaCapture final : public BackendBase {
     AlsaCapture(DeviceBase *device) noexcept : BackendBase{device} { }
     ~AlsaCapture() override;
 
-    void open(const char *name) override;
+    void open(std::string_view name) override;
     void start() override;
     void stop() override;
     void captureSamples(std::byte *buffer, uint samples) override;
@@ -898,10 +898,10 @@ AlsaCapture::~AlsaCapture()
 }
 
 
-void AlsaCapture::open(const char *name)
+void AlsaCapture::open(std::string_view name)
 {
     std::string driver{"default"};
-    if(name)
+    if(!name.empty())
     {
         if(CaptureDevices.empty())
             CaptureDevices = probe_devices(SND_PCM_STREAM_CAPTURE);
@@ -910,7 +910,7 @@ void AlsaCapture::open(const char *name)
             [name](const DevMap &entry) -> bool { return entry.name == name; });
         if(iter == CaptureDevices.cend())
             throw al::backend_exception{al::backend_error::NoDevice,
-                "Device name \"%s\" not found", name};
+                "Device name \"%.*s\" not found", static_cast<int>(name.length()), name.data()};
         driver = iter->device_name;
     }
     else
diff --git a/alc/backends/base.h b/alc/backends/base.h
index 07b430e0..a4079fe4 100644
--- a/alc/backends/base.h
+++ b/alc/backends/base.h
@@ -7,6 +7,7 @@
 #include <memory>
 #include <ratio>
 #include <string>
+#include <string_view>
 
 #include "core/device.h"
 #include "core/except.h"
@@ -20,7 +21,7 @@ struct ClockLatency {
 };
 
 struct BackendBase {
-    virtual void open(const char *name) = 0;
+    virtual void open(std::string_view name) = 0;
 
     virtual bool reset();
     virtual void start() = 0;
diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp
index 12c667ac..1684545b 100644
--- a/alc/backends/coreaudio.cpp
+++ b/alc/backends/coreaudio.cpp
@@ -329,7 +329,7 @@ struct CoreAudioPlayback final : public BackendBase {
         const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames,
         AudioBufferList *ioData) noexcept;
 
-    void open(const char *name) override;
+    void open(std::string_view name) override;
     bool reset() override;
     void start() override;
     void stop() override;
@@ -362,11 +362,11 @@ OSStatus CoreAudioPlayback::MixerProc(AudioUnitRenderActionFlags*, const AudioTi
 }
 
 
-void CoreAudioPlayback::open(const char *name)
+void CoreAudioPlayback::open(std::string_view name)
 {
 #if CAN_ENUMERATE
     AudioDeviceID audioDevice{kAudioDeviceUnknown};
-    if(!name)
+    if(name.empty())
         GetHwProperty(kAudioHardwarePropertyDefaultOutputDevice, sizeof(audioDevice),
             &audioDevice);
     else
@@ -379,16 +379,16 @@ void CoreAudioPlayback::open(const char *name)
         auto devmatch = std::find_if(PlaybackList.cbegin(), PlaybackList.cend(), find_name);
         if(devmatch == PlaybackList.cend())
             throw al::backend_exception{al::backend_error::NoDevice,
-                "Device name \"%s\" not found", name};
+                "Device name \"%.*s\" not found", static_cast<int>(name.length()), name.data()};
 
         audioDevice = devmatch->mId;
     }
 #else
-    if(!name)
+    if(name.empty())
         name = ca_device;
-    else if(strcmp(name, ca_device) != 0)
-        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
-            name};
+    else if(name != ca_device)
+        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found",
+            static_cast<int>(name.length()), name.data()};
 #endif
 
     /* open the default output unit */
@@ -436,7 +436,7 @@ void CoreAudioPlayback::open(const char *name)
     mAudioUnit = audioUnit;
 
 #if CAN_ENUMERATE
-    if(name)
+    if(!name.empty())
         mDevice->DeviceName = name;
     else
     {
@@ -608,7 +608,7 @@ struct CoreAudioCapture final : public BackendBase {
         const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber,
         UInt32 inNumberFrames, AudioBufferList *ioData) noexcept;
 
-    void open(const char *name) override;
+    void open(std::string_view name) override;
     void start() override;
     void stop() override;
     void captureSamples(std::byte *buffer, uint samples) override;
@@ -663,11 +663,11 @@ OSStatus CoreAudioCapture::RecordProc(AudioUnitRenderActionFlags *ioActionFlags,
 }
 
 
-void CoreAudioCapture::open(const char *name)
+void CoreAudioCapture::open(std::string_view name)
 {
 #if CAN_ENUMERATE
     AudioDeviceID audioDevice{kAudioDeviceUnknown};
-    if(!name)
+    if(name.empty())
         GetHwProperty(kAudioHardwarePropertyDefaultInputDevice, sizeof(audioDevice),
             &audioDevice);
     else
@@ -680,16 +680,16 @@ void CoreAudioCapture::open(const char *name)
         auto devmatch = std::find_if(CaptureList.cbegin(), CaptureList.cend(), find_name);
         if(devmatch == CaptureList.cend())
             throw al::backend_exception{al::backend_error::NoDevice,
-                "Device name \"%s\" not found", name};
+                "Device name \"%.*s\" not found", static_cast<int>(name.length()), name.data()};
 
         audioDevice = devmatch->mId;
     }
 #else
-    if(!name)
+    if(name.empty())
         name = ca_device;
-    else if(strcmp(name, ca_device) != 0)
-        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
-            name};
+    else if(name != ca_device)
+        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found",
+            static_cast<int>(name.length()), name.data()};
 #endif
 
     AudioComponentDescription desc{};
@@ -887,7 +887,7 @@ void CoreAudioCapture::open(const char *name)
             mDevice->Frequency, Resampler::FastBSinc24);
 
 #if CAN_ENUMERATE
-    if(name)
+    if(!name.empty())
         mDevice->DeviceName = name;
     else
     {
diff --git a/alc/backends/dsound.cpp b/alc/backends/dsound.cpp
index 54fac898..b5596f1c 100644
--- a/alc/backends/dsound.cpp
+++ b/alc/backends/dsound.cpp
@@ -178,7 +178,7 @@ struct DSoundPlayback final : public BackendBase {
 
     int mixerProc();
 
-    void open(const char *name) override;
+    void open(std::string_view name) override;
     bool reset() override;
     void start() override;
     void stop() override;
@@ -301,7 +301,7 @@ FORCE_ALIGN int DSoundPlayback::mixerProc()
     return 0;
 }
 
-void DSoundPlayback::open(const char *name)
+void DSoundPlayback::open(std::string_view name)
 {
     HRESULT hr;
     if(PlaybackDevices.empty())
@@ -316,9 +316,9 @@ void DSoundPlayback::open(const char *name)
     }
 
     const GUID *guid{nullptr};
-    if(!name && !PlaybackDevices.empty())
+    if(name.empty() && !PlaybackDevices.empty())
     {
-        name = PlaybackDevices[0].name.c_str();
+        name = PlaybackDevices[0].name;
         guid = &PlaybackDevices[0].guid;
     }
     else
@@ -334,7 +334,8 @@ void DSoundPlayback::open(const char *name)
                     [&id](const DevMap &entry) -> bool { return entry.guid == id; });
             if(iter == PlaybackDevices.cend())
                 throw al::backend_exception{al::backend_error::NoDevice,
-                    "Device name \"%s\" not found", name};
+                    "Device name \"%.*s\" not found", static_cast<int>(name.length()),
+                    name.data()};
         }
         guid = &iter->guid;
     }
@@ -549,7 +550,7 @@ struct DSoundCapture final : public BackendBase {
     DSoundCapture(DeviceBase *device) noexcept : BackendBase{device} { }
     ~DSoundCapture() override;
 
-    void open(const char *name) override;
+    void open(std::string_view name) override;
     void start() override;
     void stop() override;
     void captureSamples(std::byte *buffer, uint samples) override;
@@ -576,7 +577,7 @@ DSoundCapture::~DSoundCapture()
 }
 
 
-void DSoundCapture::open(const char *name)
+void DSoundCapture::open(std::string_view name)
 {
     HRESULT hr;
     if(CaptureDevices.empty())
@@ -591,9 +592,9 @@ void DSoundCapture::open(const char *name)
     }
 
     const GUID *guid{nullptr};
-    if(!name && !CaptureDevices.empty())
+    if(name.empty() && !CaptureDevices.empty())
     {
-        name = CaptureDevices[0].name.c_str();
+        name = CaptureDevices[0].name;
         guid = &CaptureDevices[0].guid;
     }
     else
@@ -609,7 +610,8 @@ void DSoundCapture::open(const char *name)
                     [&id](const DevMap &entry) -> bool { return entry.guid == id; });
             if(iter == CaptureDevices.cend())
                 throw al::backend_exception{al::backend_error::NoDevice,
-                    "Device name \"%s\" not found", name};
+                    "Device name \"%.*s\" not found", static_cast<int>(name.length()),
+                    name.data()};
         }
         guid = &iter->guid;
     }
diff --git a/alc/backends/jack.cpp b/alc/backends/jack.cpp
index 66fc0877..a0a5c440 100644
--- a/alc/backends/jack.cpp
+++ b/alc/backends/jack.cpp
@@ -298,7 +298,7 @@ struct JackPlayback final : public BackendBase {
 
     int mixerProc();
 
-    void open(const char *name) override;
+    void open(std::string_view name) override;
     bool reset() override;
     void start() override;
     void stop() override;
@@ -460,7 +460,7 @@ int JackPlayback::mixerProc()
 }
 
 
-void JackPlayback::open(const char *name)
+void JackPlayback::open(std::string_view name)
 {
     if(!mClient)
     {
@@ -484,9 +484,9 @@ void JackPlayback::open(const char *name)
     if(PlaybackList.empty())
         EnumerateDevices(mClient, PlaybackList);
 
-    if(!name && !PlaybackList.empty())
+    if(name.empty() && !PlaybackList.empty())
     {
-        name = PlaybackList[0].mName.c_str();
+        name = PlaybackList[0].mName;
         mPortPattern = PlaybackList[0].mPattern;
     }
     else
@@ -496,14 +496,10 @@ void JackPlayback::open(const char *name)
         auto iter = std::find_if(PlaybackList.cbegin(), PlaybackList.cend(), check_name);
         if(iter == PlaybackList.cend())
             throw al::backend_exception{al::backend_error::NoDevice,
-                "Device name \"%s\" not found", name?name:""};
+                "Device name \"%.*s\" not found", static_cast<int>(name.length()), name.data()};
         mPortPattern = iter->mPattern;
     }
 
-    mRTMixing = GetConfigValueBool(name, "jack", "rt-mix", true);
-    jack_set_process_callback(mClient,
-        mRTMixing ? &JackPlayback::processRtC : &JackPlayback::processC, this);
-
     mDevice->DeviceName = name;
 }
 
@@ -514,6 +510,10 @@ bool JackPlayback::reset()
     std::for_each(mPort.begin(), mPort.end(), unregister_port);
     mPort.fill(nullptr);
 
+    mRTMixing = GetConfigValueBool(mDevice->DeviceName.c_str(), "jack", "rt-mix", true);
+    jack_set_process_callback(mClient,
+        mRTMixing ? &JackPlayback::processRtC : &JackPlayback::processC, this);
+
     /* Ignore the requested buffer metrics and just keep one JACK-sized buffer
      * ready for when requested.
      */
diff --git a/alc/backends/loopback.cpp b/alc/backends/loopback.cpp
index bf4ab246..2972fc01 100644
--- a/alc/backends/loopback.cpp
+++ b/alc/backends/loopback.cpp
@@ -30,7 +30,7 @@ namespace {
 struct LoopbackBackend final : public BackendBase {
     LoopbackBackend(DeviceBase *device) noexcept : BackendBase{device} { }
 
-    void open(const char *name) override;
+    void open(std::string_view name) override;
     bool reset() override;
     void start() override;
     void stop() override;
@@ -39,7 +39,7 @@ struct LoopbackBackend final : public BackendBase {
 };
 
 
-void LoopbackBackend::open(const char *name)
+void LoopbackBackend::open(std::string_view name)
 {
     mDevice->DeviceName = name;
 }
diff --git a/alc/backends/null.cpp b/alc/backends/null.cpp
index 73420ad3..3c68e4ce 100644
--- a/alc/backends/null.cpp
+++ b/alc/backends/null.cpp
@@ -50,7 +50,7 @@ struct NullBackend final : public BackendBase {
 
     int mixerProc();
 
-    void open(const char *name) override;
+    void open(std::string_view name) override;
     bool reset() override;
     void start() override;
     void stop() override;
@@ -105,13 +105,13 @@ int NullBackend::mixerProc()
 }
 
 
-void NullBackend::open(const char *name)
+void NullBackend::open(std::string_view name)
 {
-    if(!name)
+    if(name.empty())
         name = nullDevice;
-    else if(strcmp(name, nullDevice) != 0)
-        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
-            name};
+    else if(name != nullDevice)
+        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found",
+            static_cast<int>(name.length()), name.data()};
 
     mDevice->DeviceName = name;
 }
diff --git a/alc/backends/oboe.cpp b/alc/backends/oboe.cpp
index cc44b867..b7bab19a 100644
--- a/alc/backends/oboe.cpp
+++ b/alc/backends/oboe.cpp
@@ -30,7 +30,7 @@ struct OboePlayback final : public BackendBase, public oboe::AudioStreamCallback
 
     void onErrorAfterClose(oboe::AudioStream* /* audioStream */, oboe::Result /* error */) override;
 
-    void open(const char *name) override;
+    void open(std::string_view name) override;
     bool reset() override;
     void start() override;
     void stop() override;
@@ -56,13 +56,13 @@ void OboePlayback::onErrorAfterClose(oboe::AudioStream* audioStream, oboe::Resul
     TRACE("Error was %s", oboe::convertToText(error));
 }
 
-void OboePlayback::open(const char *name)
+void OboePlayback::open(std::string_view name)
 {
-    if(!name)
+    if(name.empty())
         name = device_name;
-    else if(std::strcmp(name, device_name) != 0)
-        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
-            name};
+    else if(name != device_name)
+        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found",
+            static_cast<int>(name.length()), name.data()};
 
     /* Open a basic output stream, just to ensure it can work. */
     oboe::ManagedStream stream;
@@ -220,7 +220,7 @@ struct OboeCapture final : public BackendBase, public oboe::AudioStreamCallback
     oboe::DataCallbackResult onAudioReady(oboe::AudioStream *oboeStream, void *audioData,
         int32_t numFrames) override;
 
-    void open(const char *name) override;
+    void open(std::string_view name) override;
     void start() override;
     void stop() override;
     void captureSamples(std::byte *buffer, uint samples) override;
@@ -235,13 +235,13 @@ oboe::DataCallbackResult OboeCapture::onAudioReady(oboe::AudioStream*, void *aud
 }
 
 
-void OboeCapture::open(const char *name)
+void OboeCapture::open(std::string_view name)
 {
-    if(!name)
+    if(name.empty())
         name = device_name;
-    else if(std::strcmp(name, device_name) != 0)
-        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
-            name};
+    else if(name != device_name)
+        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found",
+            static_cast<int>(name.length()), name.data()};
 
     oboe::AudioStreamBuilder builder;
     builder.setDirection(oboe::Direction::Input)
diff --git a/alc/backends/opensl.cpp b/alc/backends/opensl.cpp
index 35c57d77..61e3c9a7 100644
--- a/alc/backends/opensl.cpp
+++ b/alc/backends/opensl.cpp
@@ -164,7 +164,7 @@ struct OpenSLPlayback final : public BackendBase {
 
     int mixerProc();
 
-    void open(const char *name) override;
+    void open(std::string_view name) override;
     bool reset() override;
     void start() override;
     void stop() override;
@@ -312,13 +312,13 @@ int OpenSLPlayback::mixerProc()
 }
 
 
-void OpenSLPlayback::open(const char *name)
+void OpenSLPlayback::open(std::string_view name)
 {
-    if(!name)
+    if(name.empty())
         name = opensl_device;
-    else if(strcmp(name, opensl_device) != 0)
-        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
-            name};
+    else if(name != opensl_device)
+        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found",
+            static_cast<int>(name.length()), name.data()};
 
     /* There's only one device, so if it's already open, there's nothing to do. */
     if(mEngineObj) return;
@@ -645,7 +645,7 @@ struct OpenSLCapture final : public BackendBase {
 
     void process(SLAndroidSimpleBufferQueueItf bq) noexcept;
 
-    void open(const char *name) override;
+    void open(std::string_view name) override;
     void start() override;
     void stop() override;
     void captureSamples(std::byte *buffer, uint samples) override;
@@ -686,13 +686,13 @@ void OpenSLCapture::process(SLAndroidSimpleBufferQueueItf) noexcept
 }
 
 
-void OpenSLCapture::open(const char* name)
+void OpenSLCapture::open(std::string_view name)
 {
-    if(!name)
+    if(name.empty())
         name = opensl_device;
-    else if(strcmp(name, opensl_device) != 0)
-        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
-            name};
+    else if(name != opensl_device)
+        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found",
+            static_cast<int>(name.length()), name.data()};
 
     SLresult result{slCreateEngine(&mEngineObj, 0, nullptr, 0, nullptr, nullptr)};
     PrintErr(result, "slCreateEngine");
diff --git a/alc/backends/oss.cpp b/alc/backends/oss.cpp
index 554ccc24..87d3ba35 100644
--- a/alc/backends/oss.cpp
+++ b/alc/backends/oss.cpp
@@ -227,7 +227,7 @@ struct OSSPlayback final : public BackendBase {
 
     int mixerProc();
 
-    void open(const char *name) override;
+    void open(std::string_view name) override;
     bool reset() override;
     void start() override;
     void stop() override;
@@ -304,10 +304,10 @@ int OSSPlayback::mixerProc()
 }
 
 
-void OSSPlayback::open(const char *name)
+void OSSPlayback::open(std::string_view name)
 {
     const char *devname{DefaultPlayback.c_str()};
-    if(!name)
+    if(name.empty())
         name = DefaultName;
     else
     {
@@ -320,7 +320,7 @@ void OSSPlayback::open(const char *name)
         );
         if(iter == PlaybackDevices.cend())
             throw al::backend_exception{al::backend_error::NoDevice,
-                "Device name \"%s\" not found", name};
+                "Device name \"%.*s\" not found", static_cast<int>(name.length()), name.data()};
         devname = iter->device_name.c_str();
     }
 
@@ -443,7 +443,7 @@ struct OSScapture final : public BackendBase {
 
     int recordProc();
 
-    void open(const char *name) override;
+    void open(std::string_view name) override;
     void start() override;
     void stop() override;
     void captureSamples(std::byte *buffer, uint samples) override;
@@ -512,10 +512,10 @@ int OSScapture::recordProc()
 }
 
 
-void OSScapture::open(const char *name)
+void OSScapture::open(std::string_view name)
 {
     const char *devname{DefaultCapture.c_str()};
-    if(!name)
+    if(name.empty())
         name = DefaultName;
     else
     {
@@ -528,7 +528,7 @@ void OSScapture::open(const char *name)
         );
         if(iter == CaptureDevices.cend())
             throw al::backend_exception{al::backend_error::NoDevice,
-                "Device name \"%s\" not found", name};
+                "Device name \"%.*s\" not found", static_cast<int>(name.length()), name.data()};
         devname = iter->device_name.c_str();
     }
 
diff --git a/alc/backends/pipewire.cpp b/alc/backends/pipewire.cpp
index 902d6374..9a63d2f4 100644
--- a/alc/backends/pipewire.cpp
+++ b/alc/backends/pipewire.cpp
@@ -1325,7 +1325,7 @@ class PipeWirePlayback final : public BackendBase {
     void ioChangedCallback(uint32_t id, void *area, uint32_t size) noexcept;
     void outputCallback() noexcept;
 
-    void open(const char *name) override;
+    void open(std::string_view name) override;
     bool reset() override;
     void start() override;
     void stop() override;
@@ -1428,14 +1428,14 @@ void PipeWirePlayback::outputCallback() noexcept
 }
 
 
-void PipeWirePlayback::open(const char *name)
+void PipeWirePlayback::open(std::string_view name)
 {
     static std::atomic<uint> OpenCount{0};
 
     uint64_t targetid{PwIdAny};
     std::string devname{};
     gEventHandler.waitForInit();
-    if(!name)
+    if(name.empty())
     {
         EventWatcherLockGuard _{gEventHandler};
         auto&& devlist = DeviceNode::GetList();
@@ -1470,7 +1470,7 @@ void PipeWirePlayback::open(const char *name)
         auto match = std::find_if(devlist.cbegin(), devlist.cend(), match_name);
         if(match == devlist.cend())
             throw al::backend_exception{al::backend_error::NoDevice,
-                "Device name \"%s\" not found", name};
+                "Device name \"%.*s\" not found", static_cast<int>(name.length()), name.data()};
 
         targetid = match->mSerial;
         devname = match->mName;
@@ -1823,7 +1823,7 @@ class PipeWireCapture final : public BackendBase {
     void stateChangedCallback(pw_stream_state old, pw_stream_state state, const char *error) noexcept;
     void inputCallback() noexcept;
 
-    void open(const char *name) override;
+    void open(std::string_view name) override;
     void start() override;
     void stop() override;
     void captureSamples(std::byte *buffer, uint samples) override;
@@ -1875,14 +1875,14 @@ void PipeWireCapture::inputCallback() noexcept
 }
 
 
-void PipeWireCapture::open(const char *name)
+void PipeWireCapture::open(std::string_view name)
 {
     static std::atomic<uint> OpenCount{0};
 
     uint64_t targetid{PwIdAny};
     std::string devname{};
     gEventHandler.waitForInit();
-    if(!name)
+    if(name.empty())
     {
         EventWatcherLockGuard _{gEventHandler};
         auto&& devlist = DeviceNode::GetList();
@@ -1920,16 +1920,17 @@ void PipeWireCapture::open(const char *name)
         auto match_name = [name](const DeviceNode &n) -> bool
         { return n.mType != NodeType::Sink && n.mName == name; };
         auto match = std::find_if(devlist.cbegin(), devlist.cend(), match_name);
-        if(match == devlist.cend() && std::strncmp(name, MonitorPrefix, MonitorPrefixLen) == 0)
+        if(match == devlist.cend() && name.length() >= MonitorPrefixLen
+            && std::strncmp(name.data(), MonitorPrefix, MonitorPrefixLen) == 0)
         {
-            const char *sinkname{name + MonitorPrefixLen};
+            const std::string_view sinkname{name.substr(MonitorPrefixLen)};
             auto match_sinkname = [sinkname](const DeviceNode &n) -> bool
             { return n.mType == NodeType::Sink && n.mName == sinkname; };
             match = std::find_if(devlist.cbegin(), devlist.cend(), match_sinkname);
         }
         if(match == devlist.cend())
             throw al::backend_exception{al::backend_error::NoDevice,
-                "Device name \"%s\" not found", name};
+                "Device name \"%.*s\" not found", static_cast<int>(name.length()), name.data()};
 
         targetid = match->mSerial;
         devname = name;
diff --git a/alc/backends/portaudio.cpp b/alc/backends/portaudio.cpp
index 2551f448..979a54d6 100644
--- a/alc/backends/portaudio.cpp
+++ b/alc/backends/portaudio.cpp
@@ -86,7 +86,7 @@ struct PortPlayback final : public BackendBase {
             framesPerBuffer, timeInfo, statusFlags);
     }
 
-    void open(const char *name) override;
+    void open(std::string_view name) override;
     bool reset() override;
     void start() override;
     void stop() override;
@@ -116,13 +116,13 @@ int PortPlayback::writeCallback(const void*, void *outputBuffer, unsigned long f
 }
 
 
-void PortPlayback::open(const char *name)
+void PortPlayback::open(std::string_view name)
 {
-    if(!name)
+    if(name.empty())
         name = pa_device;
-    else if(strcmp(name, pa_device) != 0)
-        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
-            name};
+    else if(name != pa_device)
+        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found",
+            static_cast<int>(name.length()), name.data()};
 
     PaStreamParameters params{};
     auto devidopt = ConfigValueInt(nullptr, "port", "device");
@@ -245,7 +245,7 @@ struct PortCapture final : public BackendBase {
             framesPerBuffer, timeInfo, statusFlags);
     }
 
-    void open(const char *name) override;
+    void open(std::string_view name) override;
     void start() override;
     void stop() override;
     void captureSamples(std::byte *buffer, uint samples) override;
@@ -276,13 +276,13 @@ int PortCapture::readCallback(const void *inputBuffer, void*, unsigned long fram
 }
 
 
-void PortCapture::open(const char *name)
+void PortCapture::open(std::string_view name)
 {
-    if(!name)
+    if(name.empty())
         name = pa_device;
-    else if(strcmp(name, pa_device) != 0)
-        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
-            name};
+    else if(name != pa_device)
+        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found",
+            static_cast<int>(name.length()), name.data()};
 
     uint samples{mDevice->BufferSize};
     samples = maxu(samples, 100 * mDevice->Frequency / 1000);
diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp
index 8c6cc4d3..e2cea8a8 100644
--- a/alc/backends/pulseaudio.cpp
+++ b/alc/backends/pulseaudio.cpp
@@ -647,7 +647,7 @@ struct PulsePlayback final : public BackendBase {
     void sinkNameCallback(pa_context *context, const pa_sink_info *info, int eol) noexcept;
     void streamMovedCallback(pa_stream *stream) noexcept;
 
-    void open(const char *name) override;
+    void open(std::string_view name) override;
     bool reset() override;
     void start() override;
     void stop() override;
@@ -782,14 +782,14 @@ void PulsePlayback::streamMovedCallback(pa_stream *stream) noexcept
 }
 
 
-void PulsePlayback::open(const char *name)
+void PulsePlayback::open(std::string_view name)
 {
     mMainloop = PulseMainloop::Create();
     mMainloop.start();
 
     const char *pulse_name{nullptr};
     const char *dev_name{nullptr};
-    if(name)
+    if(!name.empty())
     {
         if(PlaybackDevices.empty())
             mMainloop.probePlaybackDevices();
@@ -798,7 +798,7 @@ void PulsePlayback::open(const char *name)
             [name](const DevMap &entry) -> bool { return entry.name == name; });
         if(iter == PlaybackDevices.cend())
             throw al::backend_exception{al::backend_error::NoDevice,
-                "Device name \"%s\" not found", name};
+                "Device name \"%.*s\" not found", static_cast<int>(name.length()), name.data()};
         pulse_name = iter->device_name.c_str();
         dev_name = iter->name.c_str();
     }
@@ -1066,7 +1066,7 @@ struct PulseCapture final : public BackendBase {
     void sourceNameCallback(pa_context *context, const pa_source_info *info, int eol) noexcept;
     void streamMovedCallback(pa_stream *stream) noexcept;
 
-    void open(const char *name) override;
+    void open(std::string_view name) override;
     void start() override;
     void stop() override;
     void captureSamples(std::byte *buffer, uint samples) override;
@@ -1123,7 +1123,7 @@ void PulseCapture::streamMovedCallback(pa_stream *stream) noexcept
 }
 
 
-void PulseCapture::open(const char *name)
+void PulseCapture::open(std::string_view name)
 {
     if(!mMainloop)
     {
@@ -1132,7 +1132,7 @@ void PulseCapture::open(const char *name)
     }
 
     const char *pulse_name{nullptr};
-    if(name)
+    if(!name.empty())
     {
         if(CaptureDevices.empty())
             mMainloop.probeCaptureDevices();
@@ -1141,7 +1141,7 @@ void PulseCapture::open(const char *name)
             [name](const DevMap &entry) -> bool { return entry.name == name; });
         if(iter == CaptureDevices.cend())
             throw al::backend_exception{al::backend_error::NoDevice,
-                "Device name \"%s\" not found", name};
+                "Device name \"%.*s\" not found", static_cast<int>(name.length()), name.data()};
         pulse_name = iter->device_name.c_str();
         mDevice->DeviceName = iter->name;
     }
diff --git a/alc/backends/sdl2.cpp b/alc/backends/sdl2.cpp
index e1e40e27..f5ed4316 100644
--- a/alc/backends/sdl2.cpp
+++ b/alc/backends/sdl2.cpp
@@ -54,7 +54,7 @@ struct Sdl2Backend final : public BackendBase {
 
     void audioCallback(Uint8 *stream, int len) noexcept;
 
-    void open(const char *name) override;
+    void open(std::string_view name) override;
     bool reset() override;
     void start() override;
     void stop() override;
@@ -84,7 +84,7 @@ void Sdl2Backend::audioCallback(Uint8 *stream, int len) noexcept
     mDevice->renderSamples(stream, ulen / mFrameSize, mDevice->channelsFromFmt());
 }
 
-void Sdl2Backend::open(const char *name)
+void Sdl2Backend::open(std::string_view name)
 {
     SDL_AudioSpec want{}, have{};
 
@@ -109,16 +109,29 @@ void Sdl2Backend::open(const char *name)
      * necessarily the first in the list.
      */
     SDL_AudioDeviceID devid;
-    if(!name || strcmp(name, defaultDeviceName) == 0)
+    if(name.empty() || name == defaultDeviceName)
+    {
+        name = defaultDeviceName;
         devid = SDL_OpenAudioDevice(nullptr, SDL_FALSE, &want, &have, SDL_AUDIO_ALLOW_ANY_CHANGE);
+    }
     else
     {
         const size_t prefix_len = strlen(DEVNAME_PREFIX);
-        if(strncmp(name, DEVNAME_PREFIX, prefix_len) == 0)
-            devid = SDL_OpenAudioDevice(name+prefix_len, SDL_FALSE, &want, &have,
+        if(name.length() >= prefix_len && strncmp(name.data(), DEVNAME_PREFIX, prefix_len) == 0)
+        {
+            /* Copy the string_view to a string to ensure it's null terminated
+             * for this call.
+             */
+            const std::string devname{name.substr(prefix_len)};
+            devid = SDL_OpenAudioDevice(devname.c_str(), SDL_FALSE, &want, &have,
                 SDL_AUDIO_ALLOW_ANY_CHANGE);
+        }
         else
-            devid = SDL_OpenAudioDevice(name, SDL_FALSE, &want, &have, SDL_AUDIO_ALLOW_ANY_CHANGE);
+        {
+            const std::string devname{name};
+            devid = SDL_OpenAudioDevice(devname.c_str(), SDL_FALSE, &want, &have,
+                SDL_AUDIO_ALLOW_ANY_CHANGE);
+        }
     }
     if(!devid)
         throw al::backend_exception{al::backend_error::NoDevice, "%s", SDL_GetError()};
@@ -160,7 +173,7 @@ void Sdl2Backend::open(const char *name)
     mFmtType = devtype;
     mUpdateSize = have.samples;
 
-    mDevice->DeviceName = name ? name : defaultDeviceName;
+    mDevice->DeviceName = name;
 }
 
 bool Sdl2Backend::reset()
diff --git a/alc/backends/sndio.cpp b/alc/backends/sndio.cpp
index 8daa928c..d54c337b 100644
--- a/alc/backends/sndio.cpp
+++ b/alc/backends/sndio.cpp
@@ -57,7 +57,7 @@ struct SndioPlayback final : public BackendBase {
 
     int mixerProc();
 
-    void open(const char *name) override;
+    void open(std::string_view name) override;
     bool reset() override;
     void start() override;
     void stop() override;
@@ -112,13 +112,13 @@ int SndioPlayback::mixerProc()
 }
 
 
-void SndioPlayback::open(const char *name)
+void SndioPlayback::open(std::string_view name)
 {
-    if(!name)
+    if(name.empty())
         name = sndio_device;
-    else if(strcmp(name, sndio_device) != 0)
-        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
-            name};
+    else if(name != sndio_device)
+        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found",
+            static_cast<int>(name.length()), name.data()};
 
     sio_hdl *sndHandle{sio_open(nullptr, SIO_PLAY, 0)};
     if(!sndHandle)
@@ -280,7 +280,7 @@ struct SndioCapture final : public BackendBase {
 
     int recordProc();
 
-    void open(const char *name) override;
+    void open(std::string_view name) override;
     void start() override;
     void stop() override;
     void captureSamples(std::byte *buffer, uint samples) override;
@@ -382,13 +382,13 @@ int SndioCapture::recordProc()
 }
 
 
-void SndioCapture::open(const char *name)
+void SndioCapture::open(std::string_view name)
 {
-    if(!name)
+    if(name.empty())
         name = sndio_device;
-    else if(strcmp(name, sndio_device) != 0)
-        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
-            name};
+    else if(name != sndio_device)
+        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found",
+            static_cast<int>(name.length()), name.data()};
 
     mSndHandle = sio_open(nullptr, SIO_REC, true);
     if(mSndHandle == nullptr)
diff --git a/alc/backends/solaris.cpp b/alc/backends/solaris.cpp
index 15dcc98f..38f9db19 100644
--- a/alc/backends/solaris.cpp
+++ b/alc/backends/solaris.cpp
@@ -62,7 +62,7 @@ struct SolarisBackend final : public BackendBase {
 
     int mixerProc();
 
-    void open(const char *name) override;
+    void open(std::string_view name) override;
     bool reset() override;
     void start() override;
     void stop() override;
@@ -139,13 +139,13 @@ int SolarisBackend::mixerProc()
 }
 
 
-void SolarisBackend::open(const char *name)
+void SolarisBackend::open(std::string_view name)
 {
-    if(!name)
+    if(name.empty())
         name = solaris_device;
-    else if(strcmp(name, solaris_device) != 0)
-        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
-            name};
+    else if(name != solaris_device)
+        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found",
+            static_cast<int>(name.length()), name.data()};
 
     int fd{::open(solaris_driver.c_str(), O_WRONLY)};
     if(fd == -1)
diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp
index dccbeba2..96c56fa8 100644
--- a/alc/backends/wasapi.cpp
+++ b/alc/backends/wasapi.cpp
@@ -868,7 +868,7 @@ constexpr char MessageStr[static_cast<size_t>(MsgType::Count)][16]{
 struct WasapiProxy {
     virtual ~WasapiProxy() = default;
 
-    virtual HRESULT openProxy(const char *name) = 0;
+    virtual HRESULT openProxy(std::string_view name) = 0;
     virtual void closeProxy() = 0;
 
     virtual HRESULT resetProxy() = 0;
@@ -878,7 +878,7 @@ struct WasapiProxy {
     struct Msg {
         MsgType mType;
         WasapiProxy *mProxy;
-        const char *mParam;
+        std::string_view mParam;
         std::promise<HRESULT> mPromise;
 
         explicit operator bool() const noexcept { return mType != MsgType::QuitThread; }
@@ -889,7 +889,7 @@ struct WasapiProxy {
 
     static std::optional<DeviceHelper> sDeviceHelper;
 
-    std::future<HRESULT> pushMessage(MsgType type, const char *param=nullptr)
+    std::future<HRESULT> pushMessage(MsgType type, std::string_view param={})
     {
         std::promise<HRESULT> promise;
         std::future<HRESULT> future{promise.get_future()};
@@ -907,7 +907,7 @@ struct WasapiProxy {
         std::future<HRESULT> future{promise.get_future()};
         {
             std::lock_guard<std::mutex> _{mMsgQueueLock};
-            mMsgQueue.emplace_back(Msg{type, nullptr, nullptr, std::move(promise)});
+            mMsgQueue.emplace_back(Msg{type, nullptr, {}, std::move(promise)});
         }
         mMsgQueueCond.notify_one();
         return future;
@@ -958,9 +958,10 @@ int WasapiProxy::messageHandler(std::promise<HRESULT> *promise)
     TRACE("Starting message loop\n");
     while(Msg msg{popMessage()})
     {
-        TRACE("Got message \"%s\" (0x%04x, this=%p, param=%p)\n",
+        TRACE("Got message \"%s\" (0x%04x, this=%p, param={%p,%zu})\n",
             MessageStr[static_cast<size_t>(msg.mType)], static_cast<uint>(msg.mType),
-            static_cast<void*>(msg.mProxy), static_cast<const void*>(msg.mParam));
+            static_cast<void*>(msg.mProxy), static_cast<const void*>(msg.mParam.data()),
+            msg.mParam.length());
 
         switch(msg.mType)
         {
@@ -1010,8 +1011,8 @@ struct WasapiPlayback final : public BackendBase, WasapiProxy {
 
     int mixerProc();
 
-    void open(const char *name) override;
-    HRESULT openProxy(const char *name) override;
+    void open(std::string_view name) override;
+    HRESULT openProxy(std::string_view name) override;
     void closeProxy() override;
 
     bool reset() override;
@@ -1147,7 +1148,7 @@ FORCE_ALIGN int WasapiPlayback::mixerProc()
 }
 
 
-void WasapiPlayback::open(const char *name)
+void WasapiPlayback::open(std::string_view name)
 {
     if(SUCCEEDED(mOpenStatus))
         throw al::backend_exception{al::backend_error::DeviceError,
@@ -1161,11 +1162,10 @@ void WasapiPlayback::open(const char *name)
             "Failed to create notify events"};
     }
 
-    if(name && std::strncmp(name, DevNameHead, DevNameHeadLen) == 0)
+    if(name.length() >= DevNameHeadLen
+        && std::strncmp(name.data(), DevNameHead, DevNameHeadLen) == 0)
     {
-        name += DevNameHeadLen;
-        if(*name == '\0')
-            name = nullptr;
+        name = name.substr(DevNameHeadLen);
     }
 
     mOpenStatus = pushMessage(MsgType::OpenDevice, name).get();
@@ -1174,11 +1174,11 @@ void WasapiPlayback::open(const char *name)
             mOpenStatus};
 }
 
-HRESULT WasapiPlayback::openProxy(const char *name)
+HRESULT WasapiPlayback::openProxy(std::string_view name)
 {
     std::string devname;
     std::wstring devid;
-    if(name)
+    if(!name.empty())
     {
         auto devlock = DeviceListLock{gDeviceList};
         auto list = al::span{devlock.getPlaybackList()};
@@ -1194,7 +1194,8 @@ HRESULT WasapiPlayback::openProxy(const char *name)
         }
         if(iter == list.cend())
         {
-            WARN("Failed to find device name matching \"%s\"\n", name);
+            WARN("Failed to find device name matching \"%.*s\"\n", static_cast<int>(name.length()),
+                name.data());
             return E_FAIL;
         }
         devname = iter->name;
@@ -1654,8 +1655,8 @@ struct WasapiCapture final : public BackendBase, WasapiProxy {
 
     int recordProc();
 
-    void open(const char *name) override;
-    HRESULT openProxy(const char *name) override;
+    void open(std::string_view name) override;
+    HRESULT openProxy(std::string_view name) override;
     void closeProxy() override;
 
     HRESULT resetProxy() override;
@@ -1787,7 +1788,7 @@ FORCE_ALIGN int WasapiCapture::recordProc()
 }
 
 
-void WasapiCapture::open(const char *name)
+void WasapiCapture::open(std::string_view name)
 {
     if(SUCCEEDED(mOpenStatus))
         throw al::backend_exception{al::backend_error::DeviceError,
@@ -1801,11 +1802,10 @@ void WasapiCapture::open(const char *name)
             "Failed to create notify events"};
     }
 
-    if(name && std::strncmp(name, DevNameHead, DevNameHeadLen) == 0)
+    if(name.length() >= DevNameHeadLen
+        && std::strncmp(name.data(), DevNameHead, DevNameHeadLen) == 0)
     {
-        name += DevNameHeadLen;
-        if(*name == '\0')
-            name = nullptr;
+        name = name.substr(DevNameHeadLen);
     }
 
     mOpenStatus = pushMessage(MsgType::OpenDevice, name).get();
@@ -1822,11 +1822,11 @@ void WasapiCapture::open(const char *name)
     }
 }
 
-HRESULT WasapiCapture::openProxy(const char *name)
+HRESULT WasapiCapture::openProxy(std::string_view name)
 {
     std::string devname;
     std::wstring devid;
-    if(name)
+    if(!name.empty())
     {
         auto devlock = DeviceListLock{gDeviceList};
         auto devlist = al::span{devlock.getCaptureList()};
@@ -1842,7 +1842,8 @@ HRESULT WasapiCapture::openProxy(const char *name)
         }
         if(iter == devlist.cend())
         {
-            WARN("Failed to find device name matching \"%s\"\n", name);
+            WARN("Failed to find device name matching \"%.*s\"\n", static_cast<int>(name.length()),
+                name.data());
             return E_FAIL;
         }
         devname = iter->name;
diff --git a/alc/backends/wave.cpp b/alc/backends/wave.cpp
index 40592ee7..1078c654 100644
--- a/alc/backends/wave.cpp
+++ b/alc/backends/wave.cpp
@@ -96,7 +96,7 @@ struct WaveBackend final : public BackendBase {
 
     int mixerProc();
 
-    void open(const char *name) override;
+    void open(std::string_view name) override;
     bool reset() override;
     void start() override;
     void stop() override;
@@ -194,24 +194,24 @@ int WaveBackend::mixerProc()
     return 0;
 }
 
-void WaveBackend::open(const char *name)
+void WaveBackend::open(std::string_view name)
 {
     auto fname = ConfigValueStr(nullptr, "wave", "file");
     if(!fname) throw al::backend_exception{al::backend_error::NoDevice,
         "No wave output filename"};
 
-    if(!name)
+    if(name.empty())
         name = waveDevice;
-    else if(strcmp(name, waveDevice) != 0)
-        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
-            name};
+    else if(name != waveDevice)
+        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found",
+            static_cast<int>(name.length()), name.data()};
 
     /* There's only one "device", so if it's already open, we're done. */
     if(mFile) return;
 
 #ifdef _WIN32
     {
-        std::wstring wname{utf8_to_wstr(fname->c_str())};
+        std::wstring wname{utf8_to_wstr(fname.value())};
         mFile = _wfopen(wname.c_str(), L"wb");
     }
 #else
diff --git a/alc/backends/winmm.cpp b/alc/backends/winmm.cpp
index c22f1c4d..f0fb0a1c 100644
--- a/alc/backends/winmm.cpp
+++ b/alc/backends/winmm.cpp
@@ -135,7 +135,7 @@ struct WinMMPlayback final : public BackendBase {
 
     int mixerProc();
 
-    void open(const char *name) override;
+    void open(std::string_view name) override;
     bool reset() override;
     void start() override;
     void stop() override;
@@ -208,18 +208,18 @@ FORCE_ALIGN int WinMMPlayback::mixerProc()
 }
 
 
-void WinMMPlayback::open(const char *name)
+void WinMMPlayback::open(std::string_view name)
 {
     if(PlaybackDevices.empty())
         ProbePlaybackDevices();
 
     // Find the Device ID matching the deviceName if valid
-    auto iter = name ?
+    auto iter = !name.empty() ?
         std::find(PlaybackDevices.cbegin(), PlaybackDevices.cend(), name) :
         PlaybackDevices.cbegin();
     if(iter == PlaybackDevices.cend())
-        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
-            name};
+        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found",
+            static_cast<int>(name.length()), name.data()};
     auto DeviceID = static_cast<UINT>(std::distance(PlaybackDevices.cbegin(), iter));
 
     DevFmtType fmttype{mDevice->FmtType};
@@ -370,7 +370,7 @@ struct WinMMCapture final : public BackendBase {
 
     int captureProc();
 
-    void open(const char *name) override;
+    void open(std::string_view name) override;
     void start() override;
     void stop() override;
     void captureSamples(std::byte *buffer, uint samples) override;
@@ -446,18 +446,18 @@ int WinMMCapture::captureProc()
 }
 
 
-void WinMMCapture::open(const char *name)
+void WinMMCapture::open(std::string_view name)
 {
     if(CaptureDevices.empty())
         ProbeCaptureDevices();
 
     // Find the Device ID matching the deviceName if valid
-    auto iter = name ?
+    auto iter = !name.empty() ?
         std::find(CaptureDevices.cbegin(), CaptureDevices.cend(), name) :
         CaptureDevices.cbegin();
     if(iter == CaptureDevices.cend())
-        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
-            name};
+        throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found",
+            static_cast<int>(name.length()), name.data()};
     auto DeviceID = static_cast<UINT>(std::distance(CaptureDevices.cbegin(), iter));
 
     switch(mDevice->FmtChans)
diff --git a/common/strutils.cpp b/common/strutils.cpp
index 355cd030..f7868e2e 100644
--- a/common/strutils.cpp
+++ b/common/strutils.cpp
@@ -10,31 +10,32 @@
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 
-std::string wstr_to_utf8(const WCHAR *wstr)
+std::string wstr_to_utf8(std::wstring_view wstr)
 {
     std::string ret;
 
-    int len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr);
+    int len{WideCharToMultiByte(CP_UTF8, 0, wstr.data(), static_cast<int>(wstr.length()), nullptr,
+        0, nullptr, nullptr)};
     if(len > 0)
     {
         ret.resize(len);
-        WideCharToMultiByte(CP_UTF8, 0, wstr, -1, &ret[0], len, nullptr, nullptr);
-        ret.pop_back();
+        WideCharToMultiByte(CP_UTF8, 0, wstr.data(), static_cast<int>(wstr.length()), &ret[0], len,
+            nullptr, nullptr);
     }
 
     return ret;
 }
 
-std::wstring utf8_to_wstr(const char *str)
+std::wstring utf8_to_wstr(std::string_view str)
 {
     std::wstring ret;
 
-    int len = MultiByteToWideChar(CP_UTF8, 0, str, -1, nullptr, 0);
+    int len{MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast<int>(str.length()), nullptr,
+        0)};
     if(len > 0)
     {
         ret.resize(len);
-        MultiByteToWideChar(CP_UTF8, 0, str, -1, &ret[0], len);
-        ret.pop_back();
+        MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast<int>(str.length()), &ret[0], len);
     }
 
     return ret;
diff --git a/common/strutils.h b/common/strutils.h
index 67f057a7..7eee0c1d 100644
--- a/common/strutils.h
+++ b/common/strutils.h
@@ -5,10 +5,11 @@
 #include <string>
 
 #ifdef _WIN32
+#include <string_view>
 #include <wchar.h>
 
-std::string wstr_to_utf8(const wchar_t *wstr);
-std::wstring utf8_to_wstr(const char *str);
+std::string wstr_to_utf8(std::wstring_view wstr);
+std::wstring utf8_to_wstr(std::string_view str);
 #endif
 
 namespace al {
-- 
cgit v1.2.3