summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/audio_core/audio_core.cpp16
-rw-r--r--src/audio_core/null_sink.h6
-rw-r--r--src/audio_core/sdl2_sink.cpp30
-rw-r--r--src/audio_core/sdl2_sink.h5
-rw-r--r--src/audio_core/sink.h9
-rw-r--r--src/audio_core/sink_details.cpp19
-rw-r--r--src/audio_core/sink_details.h2
-rw-r--r--src/citra/config.cpp1
-rw-r--r--src/citra/default_ini.h4
-rw-r--r--src/citra_qt/config.cpp3
-rw-r--r--src/citra_qt/configure_audio.cpp33
-rw-r--r--src/citra_qt/configure_audio.h3
-rw-r--r--src/citra_qt/configure_audio.ui15
-rw-r--r--src/core/settings.h1
14 files changed, 129 insertions, 18 deletions
diff --git a/src/audio_core/audio_core.cpp b/src/audio_core/audio_core.cpp
index ba6acf28e..84f9c03a7 100644
--- a/src/audio_core/audio_core.cpp
+++ b/src/audio_core/audio_core.cpp
@@ -56,20 +56,8 @@ void AddAddressSpace(Kernel::VMManager& address_space) {
}
void SelectSink(std::string sink_id) {
- auto iter =
- std::find_if(g_sink_details.begin(), g_sink_details.end(),
- [sink_id](const auto& sink_detail) { return sink_detail.id == sink_id; });
-
- if (sink_id == "auto" || iter == g_sink_details.end()) {
- if (sink_id != "auto") {
- LOG_ERROR(Audio, "AudioCore::SelectSink given invalid sink_id %s", sink_id.c_str());
- }
- // Auto-select.
- // g_sink_details is ordered in terms of desirability, with the best choice at the front.
- iter = g_sink_details.begin();
- }
-
- DSP::HLE::SetSink(iter->factory());
+ const SinkDetails& sink_details = GetSinkDetails(sink_id);
+ DSP::HLE::SetSink(sink_details.factory());
}
void EnableStretching(bool enable) {
diff --git a/src/audio_core/null_sink.h b/src/audio_core/null_sink.h
index e7668438c..c732926a2 100644
--- a/src/audio_core/null_sink.h
+++ b/src/audio_core/null_sink.h
@@ -23,6 +23,12 @@ public:
size_t SamplesInQueue() const override {
return 0;
}
+
+ void SetDevice(int device_id) override {}
+
+ 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 4b66cd826..933c5f16d 100644
--- a/src/audio_core/sdl2_sink.cpp
+++ b/src/audio_core/sdl2_sink.cpp
@@ -4,12 +4,12 @@
#include <list>
#include <numeric>
-#include <vector>
#include <SDL.h>
#include "audio_core/audio_core.h"
#include "audio_core/sdl2_sink.h"
#include "common/assert.h"
#include "common/logging/log.h"
+#include "core/settings.h"
namespace AudioCore {
@@ -42,10 +42,24 @@ SDL2Sink::SDL2Sink() : impl(std::make_unique<Impl>()) {
SDL_AudioSpec obtained_audiospec;
SDL_zero(obtained_audiospec);
- impl->audio_device_id =
- SDL_OpenAudioDevice(nullptr, false, &desired_audiospec, &obtained_audiospec, 0);
+ 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();
+ }
+
+ impl->audio_device_id = SDL_OpenAudioDevice(device, false, &desired_audiospec,
+ &obtained_audiospec, SDL_AUDIO_ALLOW_ANY_CHANGE);
if (impl->audio_device_id <= 0) {
- LOG_CRITICAL(Audio_Sink, "SDL_OpenAudioDevice failed with: %s", SDL_GetError());
+ LOG_CRITICAL(Audio_Sink, "SDL_OpenAudioDevice failed with code %d for device \"%s\"",
+ impl->audio_device_id, Settings::values.audio_device_id.c_str());
return;
}
@@ -69,6 +83,10 @@ 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;
@@ -96,6 +114,10 @@ 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 ccd0f7c7e..ce75733b7 100644
--- a/src/audio_core/sdl2_sink.h
+++ b/src/audio_core/sdl2_sink.h
@@ -21,9 +21,14 @@ public:
size_t SamplesInQueue() const override;
+ std::vector<std::string> GetDeviceList() const override;
+ void SetDevice(int device_id);
+
private:
struct Impl;
std::unique_ptr<Impl> impl;
+ int device_id;
+ std::vector<std::string> device_list;
};
} // namespace AudioCore
diff --git a/src/audio_core/sink.h b/src/audio_core/sink.h
index 08f3bab5b..558c8c0fe 100644
--- a/src/audio_core/sink.h
+++ b/src/audio_core/sink.h
@@ -31,6 +31,15 @@ public:
/// Samples enqueued that have not been played yet.
virtual std::size_t SamplesInQueue() const = 0;
+
+ /**
+ * Sets the desired output device.
+ * @paran 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;
};
} // namespace
diff --git a/src/audio_core/sink_details.cpp b/src/audio_core/sink_details.cpp
index 95ccc9e9d..6972395af 100644
--- a/src/audio_core/sink_details.cpp
+++ b/src/audio_core/sink_details.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
#include <memory>
#include <vector>
#include "audio_core/null_sink.h"
@@ -9,6 +10,7 @@
#ifdef HAVE_SDL2
#include "audio_core/sdl2_sink.h"
#endif
+#include "common/logging/log.h"
namespace AudioCore {
@@ -20,4 +22,21 @@ const std::vector<SinkDetails> g_sink_details = {
{"null", []() { return std::make_unique<NullSink>(); }},
};
+const SinkDetails& GetSinkDetails(std::string sink_id) {
+ auto iter =
+ std::find_if(g_sink_details.begin(), g_sink_details.end(),
+ [sink_id](const auto& sink_detail) { return sink_detail.id == sink_id; });
+
+ if (sink_id == "auto" || iter == g_sink_details.end()) {
+ if (sink_id != "auto") {
+ LOG_ERROR(Audio, "AudioCore::SelectSink given invalid sink_id %s", sink_id.c_str());
+ }
+ // Auto-select.
+ // g_sink_details is ordered in terms of desirability, with the best choice at the front.
+ iter = g_sink_details.begin();
+ }
+
+ return *iter;
+}
+
} // namespace AudioCore
diff --git a/src/audio_core/sink_details.h b/src/audio_core/sink_details.h
index 4b30cf835..9d3735171 100644
--- a/src/audio_core/sink_details.h
+++ b/src/audio_core/sink_details.h
@@ -24,4 +24,6 @@ struct SinkDetails {
extern const std::vector<SinkDetails> g_sink_details;
+const SinkDetails& GetSinkDetails(std::string sink_id);
+
} // namespace AudioCore
diff --git a/src/citra/config.cpp b/src/citra/config.cpp
index 1d0faf193..827c90e55 100644
--- a/src/citra/config.cpp
+++ b/src/citra/config.cpp
@@ -82,6 +82,7 @@ void Config::ReadValues() {
Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto");
Settings::values.enable_audio_stretching =
sdl2_config->GetBoolean("Audio", "enable_audio_stretching", true);
+ Settings::values.audio_device_id = sdl2_config->Get("Audio", "output_device", "auto");
// Data Storage
Settings::values.use_virtual_sd =
diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h
index 7996813b4..d728fb9e8 100644
--- a/src/citra/default_ini.h
+++ b/src/citra/default_ini.h
@@ -91,6 +91,10 @@ output_engine =
# 0: No, 1 (default): Yes
enable_audio_stretching =
+# Which audio device to use.
+# auto (default): Auto-select
+output_device =
+
[Data Storage]
# Whether to create a virtual SD card.
# 1 (default): Yes, 0: No
diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp
index 8021667d0..f776e16b2 100644
--- a/src/citra_qt/config.cpp
+++ b/src/citra_qt/config.cpp
@@ -63,6 +63,8 @@ void Config::ReadValues() {
Settings::values.sink_id = qt_config->value("output_engine", "auto").toString().toStdString();
Settings::values.enable_audio_stretching =
qt_config->value("enable_audio_stretching", true).toBool();
+ Settings::values.audio_device_id =
+ qt_config->value("output_device", "auto").toString().toStdString();
qt_config->endGroup();
qt_config->beginGroup("Data Storage");
@@ -169,6 +171,7 @@ void Config::SaveValues() {
qt_config->beginGroup("Audio");
qt_config->setValue("output_engine", QString::fromStdString(Settings::values.sink_id));
qt_config->setValue("enable_audio_stretching", Settings::values.enable_audio_stretching);
+ qt_config->setValue("output_device", QString::fromStdString(Settings::values.audio_device_id));
qt_config->endGroup();
qt_config->beginGroup("Data Storage");
diff --git a/src/citra_qt/configure_audio.cpp b/src/citra_qt/configure_audio.cpp
index 3cdd4c780..3ddcf9232 100644
--- a/src/citra_qt/configure_audio.cpp
+++ b/src/citra_qt/configure_audio.cpp
@@ -2,6 +2,9 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <memory>
+#include "audio_core/audio_core.h"
+#include "audio_core/sink.h"
#include "audio_core/sink_details.h"
#include "citra_qt/configure_audio.h"
#include "core/settings.h"
@@ -18,6 +21,8 @@ ConfigureAudio::ConfigureAudio(QWidget* parent)
}
this->setConfiguration();
+ connect(ui->output_sink_combo_box, SIGNAL(currentIndexChanged(int)), this,
+ SLOT(updateAudioDevices(int)));
}
ConfigureAudio::~ConfigureAudio() {}
@@ -33,6 +38,19 @@ void ConfigureAudio::setConfiguration() {
ui->output_sink_combo_box->setCurrentIndex(new_sink_index);
ui->toggle_audio_stretching->setChecked(Settings::values.enable_audio_stretching);
+
+ // The device list cannot be pre-populated (nor listed) until the output sink is known.
+ updateAudioDevices(new_sink_index);
+
+ int new_device_index = -1;
+ for (int index = 0; index < ui->audio_device_combo_box->count(); index++) {
+ if (ui->audio_device_combo_box->itemText(index).toStdString() ==
+ Settings::values.audio_device_id) {
+ new_device_index = index;
+ break;
+ }
+ }
+ ui->audio_device_combo_box->setCurrentIndex(new_device_index);
}
void ConfigureAudio::applyConfiguration() {
@@ -40,5 +58,20 @@ void ConfigureAudio::applyConfiguration() {
ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex())
.toStdString();
Settings::values.enable_audio_stretching = ui->toggle_audio_stretching->isChecked();
+ Settings::values.audio_device_id =
+ ui->audio_device_combo_box->itemText(ui->audio_device_combo_box->currentIndex())
+ .toStdString();
Settings::Apply();
}
+
+void ConfigureAudio::updateAudioDevices(int sink_index) {
+ ui->audio_device_combo_box->clear();
+ 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();
+ for (const auto& device : device_list) {
+ ui->audio_device_combo_box->addItem(device.c_str());
+ }
+}
diff --git a/src/citra_qt/configure_audio.h b/src/citra_qt/configure_audio.h
index 51df2e27b..8190e694f 100644
--- a/src/citra_qt/configure_audio.h
+++ b/src/citra_qt/configure_audio.h
@@ -20,6 +20,9 @@ public:
void applyConfiguration();
+public slots:
+ void updateAudioDevices(int sink_index);
+
private:
void setConfiguration();
diff --git a/src/citra_qt/configure_audio.ui b/src/citra_qt/configure_audio.ui
index 3e2b4635f..dd870eb61 100644
--- a/src/citra_qt/configure_audio.ui
+++ b/src/citra_qt/configure_audio.ui
@@ -35,6 +35,21 @@
</property>
</widget>
</item>
+ <item>
+ <layout class="QHBoxLayout">
+ <item>
+ <widget class="QLabel">
+ <property name="text">
+ <string>Audio Device:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="audio_device_combo_box">
+ </widget>
+ </item>
+ </layout>
+ </item>
</layout>
</widget>
</item>
diff --git a/src/core/settings.h b/src/core/settings.h
index 8dbda653a..e22ce0f16 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -104,6 +104,7 @@ struct Values {
// Audio
std::string sink_id;
bool enable_audio_stretching;
+ std::string audio_device_id;
// Debugging
bool use_gdbstub;