From 05fc17b88a88389c95f3cdab6cd05b7d0b5488e0 Mon Sep 17 00:00:00 2001
From: MerryMage <MerryMage@users.noreply.github.com>
Date: Mon, 2 Jul 2018 13:23:40 +0100
Subject: [PATCH 1/4] sink: Remove unnecessary SetDevice method

Unused, doesn't do anything.
---
 src/audio_core/cubeb_sink.cpp | 2 --
 src/audio_core/cubeb_sink.h   | 1 -
 src/audio_core/null_sink.h    | 2 --
 src/audio_core/sdl2_sink.cpp  | 4 ----
 src/audio_core/sdl2_sink.h    | 2 --
 src/audio_core/sink.h         | 6 ------
 6 files changed, 17 deletions(-)

diff --git a/src/audio_core/cubeb_sink.cpp b/src/audio_core/cubeb_sink.cpp
index 231560269..55395e15c 100644
--- a/src/audio_core/cubeb_sink.cpp
+++ b/src/audio_core/cubeb_sink.cpp
@@ -120,8 +120,6 @@ size_t CubebSink::SamplesInQueue() const {
     return impl->queue.size() / 2;
 }
 
-void CubebSink::SetDevice(int device_id) {}
-
 long CubebSink::Impl::DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer,
                                    void* output_buffer, long num_frames) {
     Impl* impl = static_cast<Impl*>(user_data);
diff --git a/src/audio_core/cubeb_sink.h b/src/audio_core/cubeb_sink.h
index 1fb521834..0fa82ffad 100644
--- a/src/audio_core/cubeb_sink.h
+++ b/src/audio_core/cubeb_sink.h
@@ -22,7 +22,6 @@ public:
     size_t SamplesInQueue() const override;
 
     std::vector<std::string> GetDeviceList() const override;
-    void SetDevice(int device_id) override;
 
 private:
     struct Impl;
diff --git a/src/audio_core/null_sink.h b/src/audio_core/null_sink.h
index 3b2129f8f..6299e3e16 100644
--- a/src/audio_core/null_sink.h
+++ b/src/audio_core/null_sink.h
@@ -24,8 +24,6 @@ public:
         return 0;
     }
 
-    void SetDevice(int device_id) override {}
-
     std::vector<std::string> GetDeviceList() const override {
         return {};
     }
diff --git a/src/audio_core/sdl2_sink.cpp b/src/audio_core/sdl2_sink.cpp
index c3fba3b84..7bc6ecd55 100644
--- a/src/audio_core/sdl2_sink.cpp
+++ b/src/audio_core/sdl2_sink.cpp
@@ -114,10 +114,6 @@ size_t SDL2Sink::SamplesInQueue() const {
     return total_size;
 }
 
-void SDL2Sink::SetDevice(int device_id) {
-    this->device_id = device_id;
-}
-
 void SDL2Sink::Impl::Callback(void* impl_, u8* buffer, int buffer_size_in_bytes) {
     Impl* impl = reinterpret_cast<Impl*>(impl_);
 
diff --git a/src/audio_core/sdl2_sink.h b/src/audio_core/sdl2_sink.h
index bcc725369..acc86264b 100644
--- a/src/audio_core/sdl2_sink.h
+++ b/src/audio_core/sdl2_sink.h
@@ -22,12 +22,10 @@ public:
     size_t SamplesInQueue() const override;
 
     std::vector<std::string> GetDeviceList() const override;
-    void SetDevice(int device_id) override;
 
 private:
     struct Impl;
     std::unique_ptr<Impl> impl;
-    int device_id;
     std::vector<std::string> device_list;
 };
 
diff --git a/src/audio_core/sink.h b/src/audio_core/sink.h
index 19fe12860..837427794 100644
--- a/src/audio_core/sink.h
+++ b/src/audio_core/sink.h
@@ -32,12 +32,6 @@ public:
     /// Samples enqueued that have not been played yet.
     virtual std::size_t SamplesInQueue() const = 0;
 
-    /**
-     * Sets the desired output device.
-     * @param device_id ID of the desired device.
-     */
-    virtual void SetDevice(int device_id) = 0;
-
     /// Returns the list of available devices.
     virtual std::vector<std::string> GetDeviceList() const = 0;
 };

From ce5a5412ae0a30131db6b194616b9d3fd3063fc7 Mon Sep 17 00:00:00 2001
From: MerryMage <MerryMage@users.noreply.github.com>
Date: Mon, 2 Jul 2018 13:26:14 +0100
Subject: [PATCH 2/4] sink_details: Remove unnecessary lambdas

---
 src/audio_core/sink_details.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/audio_core/sink_details.cpp b/src/audio_core/sink_details.cpp
index 2a51b2b2b..1ccf813bb 100644
--- a/src/audio_core/sink_details.cpp
+++ b/src/audio_core/sink_details.cpp
@@ -21,12 +21,12 @@ namespace AudioCore {
 // g_sink_details is ordered in terms of desirability, with the best choice at the top.
 const std::vector<SinkDetails> g_sink_details = {
 #ifdef HAVE_CUBEB
-    {"cubeb", []() { return std::make_unique<CubebSink>(); }},
+    {"cubeb", &std::make_unique<CubebSink>},
 #endif
 #ifdef HAVE_SDL2
-    {"sdl2", []() { return std::make_unique<SDL2Sink>(); }},
+    {"sdl2", &std::make_unique<SDL2Sink>},
 #endif
-    {"null", []() { return std::make_unique<NullSink>(); }},
+    {"null", &std::make_unique<NullSink>},
 };
 
 const SinkDetails& GetSinkDetails(std::string sink_id) {

From d269beab0d63d2f3def51d3fb97cb4b9975a96ce Mon Sep 17 00:00:00 2001
From: MerryMage <MerryMage@users.noreply.github.com>
Date: Mon, 2 Jul 2018 14:03:14 +0100
Subject: [PATCH 3/4] sink_details: Listing available devices should be
 separate from sink construction

---
 src/audio_core/cubeb_sink.cpp                 | 66 +++++++++++--------
 src/audio_core/cubeb_sink.h                   |  6 +-
 src/audio_core/dsp_interface.cpp              |  4 +-
 src/audio_core/dsp_interface.h                |  2 +-
 src/audio_core/null_sink.h                    |  5 +-
 src/audio_core/sdl2_sink.cpp                  | 38 ++++++-----
 src/audio_core/sdl2_sink.h                    |  7 +-
 src/audio_core/sink.h                         |  3 -
 src/audio_core/sink_details.cpp               |  7 +-
 src/audio_core/sink_details.h                 |  9 ++-
 .../configuration/configure_audio.cpp         |  3 +-
 src/core/core.cpp                             |  2 +-
 src/core/settings.cpp                         |  2 +-
 13 files changed, 84 insertions(+), 70 deletions(-)

diff --git a/src/audio_core/cubeb_sink.cpp b/src/audio_core/cubeb_sink.cpp
index 55395e15c..9d0782598 100644
--- a/src/audio_core/cubeb_sink.cpp
+++ b/src/audio_core/cubeb_sink.cpp
@@ -7,7 +7,6 @@
 #include "audio_core/audio_types.h"
 #include "audio_core/cubeb_sink.h"
 #include "common/logging/log.h"
-#include "core/settings.h"
 
 namespace AudioCore {
 
@@ -25,13 +24,12 @@ struct CubebSink::Impl {
     static void StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state);
 };
 
-CubebSink::CubebSink() : impl(std::make_unique<Impl>()) {
+CubebSink::CubebSink(std::string target_device_name) : impl(std::make_unique<Impl>()) {
     if (cubeb_init(&impl->ctx, "Citra", nullptr) != CUBEB_OK) {
         LOG_CRITICAL(Audio_Sink, "cubeb_init failed");
         return;
     }
 
-    const char* target_device_name = nullptr;
     cubeb_devid output_device = nullptr;
 
     cubeb_stream_params params;
@@ -46,27 +44,21 @@ CubebSink::CubebSink() : impl(std::make_unique<Impl>()) {
     if (cubeb_get_min_latency(impl->ctx, &params, &minimum_latency) != CUBEB_OK)
         LOG_CRITICAL(Audio_Sink, "Error getting minimum latency");
 
-    cubeb_device_collection collection;
-    if (cubeb_enumerate_devices(impl->ctx, CUBEB_DEVICE_TYPE_OUTPUT, &collection) != CUBEB_OK) {
-        LOG_WARNING(Audio_Sink, "Audio output device enumeration not supported");
-    } else {
-        if (collection.count >= 1 && Settings::values.audio_device_id != "auto" &&
-            !Settings::values.audio_device_id.empty()) {
-            target_device_name = Settings::values.audio_device_id.c_str();
-        }
-
-        for (size_t i = 0; i < collection.count; i++) {
-            const cubeb_device_info& device = collection.device[i];
-            if (device.friendly_name) {
-                impl->device_list.emplace_back(device.friendly_name);
-
-                if (target_device_name && strcmp(target_device_name, device.friendly_name) == 0) {
-                    output_device = device.devid;
-                }
+    if (target_device_name != "auto" && !target_device_name.empty()) {
+        cubeb_device_collection collection;
+        if (cubeb_enumerate_devices(impl->ctx, CUBEB_DEVICE_TYPE_OUTPUT, &collection) != CUBEB_OK) {
+            LOG_WARNING(Audio_Sink, "Audio output device enumeration not supported");
+        } else {
+            const auto collection_end = collection.device + collection.count;
+            const auto device = std::find_if(collection.device, collection_end,
+                                             [&](const cubeb_device_info& device) {
+                                                 return target_device_name == device.friendly_name;
+                                             });
+            if (device != collection_end) {
+                output_device = device->devid;
             }
+            cubeb_device_collection_destroy(impl->ctx, &collection);
         }
-
-        cubeb_device_collection_destroy(impl->ctx, &collection);
     }
 
     if (cubeb_stream_init(impl->ctx, &impl->stream, "Citra Audio Output", nullptr, nullptr,
@@ -101,10 +93,6 @@ unsigned int CubebSink::GetNativeSampleRate() const {
     return impl->sample_rate;
 }
 
-std::vector<std::string> CubebSink::GetDeviceList() const {
-    return impl->device_list;
-}
-
 void CubebSink::EnqueueSamples(const s16* samples, size_t sample_count) {
     if (!impl->ctx)
         return;
@@ -144,4 +132,30 @@ long CubebSink::Impl::DataCallback(cubeb_stream* stream, void* user_data, const
 
 void CubebSink::Impl::StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state) {}
 
+std::vector<std::string> ListCubebSinkDevices() {
+    std::vector<std::string> device_list;
+    cubeb* ctx;
+
+    if (cubeb_init(&ctx, "Citra Device Enumerator", nullptr) != CUBEB_OK) {
+        LOG_CRITICAL(Audio_Sink, "cubeb_init failed");
+        return {};
+    }
+
+    cubeb_device_collection collection;
+    if (cubeb_enumerate_devices(ctx, CUBEB_DEVICE_TYPE_OUTPUT, &collection) != CUBEB_OK) {
+        LOG_WARNING(Audio_Sink, "Audio output device enumeration not supported");
+    } else {
+        for (size_t i = 0; i < collection.count; i++) {
+            const cubeb_device_info& device = collection.device[i];
+            if (device.friendly_name) {
+                device_list.emplace_back(device.friendly_name);
+            }
+        }
+        cubeb_device_collection_destroy(ctx, &collection);
+    }
+
+    cubeb_destroy(ctx);
+    return device_list;
+}
+
 } // namespace AudioCore
diff --git a/src/audio_core/cubeb_sink.h b/src/audio_core/cubeb_sink.h
index 0fa82ffad..a2ef228aa 100644
--- a/src/audio_core/cubeb_sink.h
+++ b/src/audio_core/cubeb_sink.h
@@ -12,7 +12,7 @@ namespace AudioCore {
 
 class CubebSink final : public Sink {
 public:
-    CubebSink();
+    explicit CubebSink(std::string device_id);
     ~CubebSink() override;
 
     unsigned int GetNativeSampleRate() const override;
@@ -21,11 +21,11 @@ public:
 
     size_t SamplesInQueue() const override;
 
-    std::vector<std::string> GetDeviceList() const override;
-
 private:
     struct Impl;
     std::unique_ptr<Impl> impl;
 };
 
+std::vector<std::string> ListCubebSinkDevices();
+
 } // namespace AudioCore
diff --git a/src/audio_core/dsp_interface.cpp b/src/audio_core/dsp_interface.cpp
index c93d4571a..dcb902582 100644
--- a/src/audio_core/dsp_interface.cpp
+++ b/src/audio_core/dsp_interface.cpp
@@ -18,9 +18,9 @@ DspInterface::~DspInterface() {
     }
 }
 
-void DspInterface::SetSink(const std::string& sink_id) {
+void DspInterface::SetSink(const std::string& sink_id, const std::string& audio_device) {
     const SinkDetails& sink_details = GetSinkDetails(sink_id);
-    sink = sink_details.factory();
+    sink = sink_details.factory(audio_device);
     time_stretcher.SetOutputSampleRate(sink->GetNativeSampleRate());
 }
 
diff --git a/src/audio_core/dsp_interface.h b/src/audio_core/dsp_interface.h
index 1f3024dc8..fa62ba691 100644
--- a/src/audio_core/dsp_interface.h
+++ b/src/audio_core/dsp_interface.h
@@ -61,7 +61,7 @@ public:
     virtual std::array<u8, Memory::DSP_RAM_SIZE>& GetDspMemory() = 0;
 
     /// Select the sink to use based on sink id.
-    void SetSink(const std::string& sink_id);
+    void SetSink(const std::string& sink_id, const std::string& audio_device);
     /// Get the current sink
     Sink& GetSink();
     /// Enable/Disable audio stretching.
diff --git a/src/audio_core/null_sink.h b/src/audio_core/null_sink.h
index 6299e3e16..97a228f28 100644
--- a/src/audio_core/null_sink.h
+++ b/src/audio_core/null_sink.h
@@ -12,6 +12,7 @@ namespace AudioCore {
 
 class NullSink final : public Sink {
 public:
+    NullSink(std::string) {}
     ~NullSink() override = default;
 
     unsigned int GetNativeSampleRate() const override {
@@ -23,10 +24,6 @@ public:
     size_t SamplesInQueue() const override {
         return 0;
     }
-
-    std::vector<std::string> GetDeviceList() const override {
-        return {};
-    }
 };
 
 } // namespace AudioCore
diff --git a/src/audio_core/sdl2_sink.cpp b/src/audio_core/sdl2_sink.cpp
index 7bc6ecd55..7b3439c4e 100644
--- a/src/audio_core/sdl2_sink.cpp
+++ b/src/audio_core/sdl2_sink.cpp
@@ -9,7 +9,6 @@
 #include "audio_core/sdl2_sink.h"
 #include "common/assert.h"
 #include "common/logging/log.h"
-#include "core/settings.h"
 
 namespace AudioCore {
 
@@ -23,7 +22,7 @@ struct SDL2Sink::Impl {
     static void Callback(void* impl_, u8* buffer, int buffer_size_in_bytes);
 };
 
-SDL2Sink::SDL2Sink() : impl(std::make_unique<Impl>()) {
+SDL2Sink::SDL2Sink(std::string device_name) : impl(std::make_unique<Impl>()) {
     if (SDL_Init(SDL_INIT_AUDIO) < 0) {
         LOG_CRITICAL(Audio_Sink, "SDL_Init(SDL_INIT_AUDIO) failed with: {}", SDL_GetError());
         impl->audio_device_id = 0;
@@ -42,24 +41,16 @@ SDL2Sink::SDL2Sink() : impl(std::make_unique<Impl>()) {
     SDL_AudioSpec obtained_audiospec;
     SDL_zero(obtained_audiospec);
 
-    int device_count = SDL_GetNumAudioDevices(0);
-    device_list.clear();
-    for (int i = 0; i < device_count; ++i) {
-        device_list.push_back(SDL_GetAudioDeviceName(i, 0));
-    }
-
     const char* device = nullptr;
-
-    if (device_count >= 1 && Settings::values.audio_device_id != "auto" &&
-        !Settings::values.audio_device_id.empty()) {
-        device = Settings::values.audio_device_id.c_str();
+    if (device_name != "auto" && !device_name.empty()) {
+        device = device_name.c_str();
     }
 
     impl->audio_device_id = SDL_OpenAudioDevice(
         device, false, &desired_audiospec, &obtained_audiospec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);
     if (impl->audio_device_id <= 0) {
         LOG_CRITICAL(Audio_Sink, "SDL_OpenAudioDevice failed with code {} for device \"{}\"",
-                     impl->audio_device_id, Settings::values.audio_device_id);
+                     impl->audio_device_id, device_name);
         return;
     }
 
@@ -83,10 +74,6 @@ unsigned int SDL2Sink::GetNativeSampleRate() const {
     return impl->sample_rate;
 }
 
-std::vector<std::string> SDL2Sink::GetDeviceList() const {
-    return device_list;
-}
-
 void SDL2Sink::EnqueueSamples(const s16* samples, size_t sample_count) {
     if (impl->audio_device_id <= 0)
         return;
@@ -140,4 +127,21 @@ void SDL2Sink::Impl::Callback(void* impl_, u8* buffer, int buffer_size_in_bytes)
     }
 }
 
+std::vector<std::string> ListSDL2SinkDevices() {
+    if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
+        LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem failed with: {}", SDL_GetError());
+        return {};
+    }
+
+    std::vector<std::string> device_list;
+    const int device_count = SDL_GetNumAudioDevices(0);
+    for (int i = 0; i < device_count; ++i) {
+        device_list.push_back(SDL_GetAudioDeviceName(i, 0));
+    }
+
+    SDL_QuitSubSystem(SDL_INIT_AUDIO);
+
+    return device_list;
+}
+
 } // namespace AudioCore
diff --git a/src/audio_core/sdl2_sink.h b/src/audio_core/sdl2_sink.h
index acc86264b..33b5df283 100644
--- a/src/audio_core/sdl2_sink.h
+++ b/src/audio_core/sdl2_sink.h
@@ -12,7 +12,7 @@ namespace AudioCore {
 
 class SDL2Sink final : public Sink {
 public:
-    SDL2Sink();
+    explicit SDL2Sink(std::string device_id);
     ~SDL2Sink() override;
 
     unsigned int GetNativeSampleRate() const override;
@@ -21,12 +21,11 @@ public:
 
     size_t SamplesInQueue() const override;
 
-    std::vector<std::string> GetDeviceList() const override;
-
 private:
     struct Impl;
     std::unique_ptr<Impl> impl;
-    std::vector<std::string> device_list;
 };
 
+std::vector<std::string> ListSDL2SinkDevices();
+
 } // namespace AudioCore
diff --git a/src/audio_core/sink.h b/src/audio_core/sink.h
index 837427794..e8b0d755f 100644
--- a/src/audio_core/sink.h
+++ b/src/audio_core/sink.h
@@ -31,9 +31,6 @@ public:
 
     /// Samples enqueued that have not been played yet.
     virtual std::size_t SamplesInQueue() const = 0;
-
-    /// Returns the list of available devices.
-    virtual std::vector<std::string> GetDeviceList() const = 0;
 };
 
 } // namespace AudioCore
diff --git a/src/audio_core/sink_details.cpp b/src/audio_core/sink_details.cpp
index 1ccf813bb..2bac7e3e1 100644
--- a/src/audio_core/sink_details.cpp
+++ b/src/audio_core/sink_details.cpp
@@ -21,12 +21,13 @@ namespace AudioCore {
 // g_sink_details is ordered in terms of desirability, with the best choice at the top.
 const std::vector<SinkDetails> g_sink_details = {
 #ifdef HAVE_CUBEB
-    {"cubeb", &std::make_unique<CubebSink>},
+    SinkDetails{"cubeb", &std::make_unique<CubebSink, std::string>, &ListCubebSinkDevices},
 #endif
 #ifdef HAVE_SDL2
-    {"sdl2", &std::make_unique<SDL2Sink>},
+    SinkDetails{"sdl2", &std::make_unique<SDL2Sink, std::string>, &ListSDL2SinkDevices},
 #endif
-    {"null", &std::make_unique<NullSink>},
+    SinkDetails{"null", &std::make_unique<NullSink, std::string>,
+                [] { return std::vector<std::string>{"null"}; }},
 };
 
 const SinkDetails& GetSinkDetails(std::string sink_id) {
diff --git a/src/audio_core/sink_details.h b/src/audio_core/sink_details.h
index 9d3735171..17ecd1e93 100644
--- a/src/audio_core/sink_details.h
+++ b/src/audio_core/sink_details.h
@@ -13,13 +13,16 @@ namespace AudioCore {
 class Sink;
 
 struct SinkDetails {
-    SinkDetails(const char* id_, std::function<std::unique_ptr<Sink>()> factory_)
-        : id(id_), factory(factory_) {}
+    SinkDetails(const char* id_, std::function<std::unique_ptr<Sink>(std::string)> factory_,
+                std::function<std::vector<std::string>()> list_devices_)
+        : id(id_), factory(factory_), list_devices(list_devices_) {}
 
     /// Name for this sink.
     const char* id;
     /// A method to call to construct an instance of this type of sink.
-    std::function<std::unique_ptr<Sink>()> factory;
+    std::function<std::unique_ptr<Sink>(std::string device_id)> factory;
+    /// A method to call to list available devices.
+    std::function<std::vector<std::string>()> list_devices;
 };
 
 extern const std::vector<SinkDetails> g_sink_details;
diff --git a/src/citra_qt/configuration/configure_audio.cpp b/src/citra_qt/configuration/configure_audio.cpp
index 46424dbb9..2a2932bb9 100644
--- a/src/citra_qt/configuration/configure_audio.cpp
+++ b/src/citra_qt/configuration/configure_audio.cpp
@@ -69,8 +69,7 @@ void ConfigureAudio::updateAudioDevices(int sink_index) {
     ui->audio_device_combo_box->addItem("auto");
 
     std::string sink_id = ui->output_sink_combo_box->itemText(sink_index).toStdString();
-    std::vector<std::string> device_list =
-        AudioCore::GetSinkDetails(sink_id).factory()->GetDeviceList();
+    std::vector<std::string> device_list = AudioCore::GetSinkDetails(sink_id).list_devices();
     for (const auto& device : device_list) {
         ui->audio_device_combo_box->addItem(device.c_str());
     }
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 287014c4c..6d3ddc136 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -166,7 +166,7 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
     }
 
     dsp_core = std::make_unique<AudioCore::DspHle>();
-    dsp_core->SetSink(Settings::values.sink_id);
+    dsp_core->SetSink(Settings::values.sink_id, Settings::values.audio_device_id);
     dsp_core->EnableStretching(Settings::values.enable_audio_stretching);
 
     telemetry_session = std::make_unique<Core::TelemetrySession>();
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index 3cc38b982..422903b70 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -32,7 +32,7 @@ void Apply() {
     }
 
     if (Core::System::GetInstance().IsPoweredOn()) {
-        Core::DSP().SetSink(values.sink_id);
+        Core::DSP().SetSink(values.sink_id, values.audio_device_id);
         Core::DSP().EnableStretching(values.enable_audio_stretching);
     }
 

From 7d642b25e9feb9d58cc8cbf6e82d6fa3612f8cec Mon Sep 17 00:00:00 2001
From: MerryMage <MerryMage@users.noreply.github.com>
Date: Thu, 12 Jul 2018 15:52:06 +0100
Subject: [PATCH 4/4] sink: Make auto device name a constant

---
 src/audio_core/cubeb_sink.cpp                  | 2 +-
 src/audio_core/sdl2_sink.cpp                   | 2 +-
 src/audio_core/sink.h                          | 2 ++
 src/citra_qt/configuration/configure_audio.cpp | 2 +-
 4 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/src/audio_core/cubeb_sink.cpp b/src/audio_core/cubeb_sink.cpp
index 9d0782598..e679a9588 100644
--- a/src/audio_core/cubeb_sink.cpp
+++ b/src/audio_core/cubeb_sink.cpp
@@ -44,7 +44,7 @@ CubebSink::CubebSink(std::string target_device_name) : impl(std::make_unique<Imp
     if (cubeb_get_min_latency(impl->ctx, &params, &minimum_latency) != CUBEB_OK)
         LOG_CRITICAL(Audio_Sink, "Error getting minimum latency");
 
-    if (target_device_name != "auto" && !target_device_name.empty()) {
+    if (target_device_name != auto_device_name && !target_device_name.empty()) {
         cubeb_device_collection collection;
         if (cubeb_enumerate_devices(impl->ctx, CUBEB_DEVICE_TYPE_OUTPUT, &collection) != CUBEB_OK) {
             LOG_WARNING(Audio_Sink, "Audio output device enumeration not supported");
diff --git a/src/audio_core/sdl2_sink.cpp b/src/audio_core/sdl2_sink.cpp
index 7b3439c4e..f18da8845 100644
--- a/src/audio_core/sdl2_sink.cpp
+++ b/src/audio_core/sdl2_sink.cpp
@@ -42,7 +42,7 @@ SDL2Sink::SDL2Sink(std::string device_name) : impl(std::make_unique<Impl>()) {
     SDL_zero(obtained_audiospec);
 
     const char* device = nullptr;
-    if (device_name != "auto" && !device_name.empty()) {
+    if (device_name != auto_device_name && !device_name.empty()) {
         device = device_name.c_str();
     }
 
diff --git a/src/audio_core/sink.h b/src/audio_core/sink.h
index e8b0d755f..723756b67 100644
--- a/src/audio_core/sink.h
+++ b/src/audio_core/sink.h
@@ -9,6 +9,8 @@
 
 namespace AudioCore {
 
+constexpr char auto_device_name[] = "auto";
+
 /**
  * This class is an interface for an audio sink. An audio sink accepts samples in stereo signed
  * PCM16 format to be output. Sinks *do not* handle resampling and expect the correct sample rate.
diff --git a/src/citra_qt/configuration/configure_audio.cpp b/src/citra_qt/configuration/configure_audio.cpp
index 2a2932bb9..a06276a87 100644
--- a/src/citra_qt/configuration/configure_audio.cpp
+++ b/src/citra_qt/configuration/configure_audio.cpp
@@ -66,7 +66,7 @@ void ConfigureAudio::applyConfiguration() {
 
 void ConfigureAudio::updateAudioDevices(int sink_index) {
     ui->audio_device_combo_box->clear();
-    ui->audio_device_combo_box->addItem("auto");
+    ui->audio_device_combo_box->addItem(AudioCore::auto_device_name);
 
     std::string sink_id = ui->output_sink_combo_box->itemText(sink_index).toStdString();
     std::vector<std::string> device_list = AudioCore::GetSinkDetails(sink_id).list_devices();