summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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) {
56} 56}
57 57
58void SelectSink(std::string sink_id) { 58void SelectSink(std::string sink_id) {
59 auto iter = 59 const SinkDetails& sink_details = GetSinkDetails(sink_id);
60 std::find_if(g_sink_details.begin(), g_sink_details.end(), 60 DSP::HLE::SetSink(sink_details.factory());
61 [sink_id](const auto& sink_detail) { return sink_detail.id == sink_id; });
62
63 if (sink_id == "auto" || iter == g_sink_details.end()) {
64 if (sink_id != "auto") {
65 LOG_ERROR(Audio, "AudioCore::SelectSink given invalid sink_id %s", sink_id.c_str());
66 }
67 // Auto-select.
68 // g_sink_details is ordered in terms of desirability, with the best choice at the front.
69 iter = g_sink_details.begin();
70 }
71
72 DSP::HLE::SetSink(iter->factory());
73} 61}
74 62
75void EnableStretching(bool enable) { 63void 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:
23 size_t SamplesInQueue() const override { 23 size_t SamplesInQueue() const override {
24 return 0; 24 return 0;
25 } 25 }
26
27 void SetDevice(int device_id) override {}
28
29 std::vector<std::string> GetDeviceList() const override {
30 return {};
31 }
26}; 32};
27 33
28} // namespace AudioCore 34} // 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 @@
4 4
5#include <list> 5#include <list>
6#include <numeric> 6#include <numeric>
7#include <vector>
8#include <SDL.h> 7#include <SDL.h>
9#include "audio_core/audio_core.h" 8#include "audio_core/audio_core.h"
10#include "audio_core/sdl2_sink.h" 9#include "audio_core/sdl2_sink.h"
11#include "common/assert.h" 10#include "common/assert.h"
12#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "core/settings.h"
13 13
14namespace AudioCore { 14namespace AudioCore {
15 15
@@ -42,10 +42,24 @@ SDL2Sink::SDL2Sink() : impl(std::make_unique<Impl>()) {
42 SDL_AudioSpec obtained_audiospec; 42 SDL_AudioSpec obtained_audiospec;
43 SDL_zero(obtained_audiospec); 43 SDL_zero(obtained_audiospec);
44 44
45 impl->audio_device_id = 45 int device_count = SDL_GetNumAudioDevices(0);
46 SDL_OpenAudioDevice(nullptr, false, &desired_audiospec, &obtained_audiospec, 0); 46 device_list.clear();
47 for (int i = 0; i < device_count; ++i) {
48 device_list.push_back(SDL_GetAudioDeviceName(i, 0));
49 }
50
51 const char* device = nullptr;
52
53 if (device_count >= 1 && Settings::values.audio_device_id != "auto" &&
54 !Settings::values.audio_device_id.empty()) {
55 device = Settings::values.audio_device_id.c_str();
56 }
57
58 impl->audio_device_id = SDL_OpenAudioDevice(device, false, &desired_audiospec,
59 &obtained_audiospec, SDL_AUDIO_ALLOW_ANY_CHANGE);
47 if (impl->audio_device_id <= 0) { 60 if (impl->audio_device_id <= 0) {
48 LOG_CRITICAL(Audio_Sink, "SDL_OpenAudioDevice failed with: %s", SDL_GetError()); 61 LOG_CRITICAL(Audio_Sink, "SDL_OpenAudioDevice failed with code %d for device \"%s\"",
62 impl->audio_device_id, Settings::values.audio_device_id.c_str());
49 return; 63 return;
50 } 64 }
51 65
@@ -69,6 +83,10 @@ unsigned int SDL2Sink::GetNativeSampleRate() const {
69 return impl->sample_rate; 83 return impl->sample_rate;
70} 84}
71 85
86std::vector<std::string> SDL2Sink::GetDeviceList() const {
87 return device_list;
88}
89
72void SDL2Sink::EnqueueSamples(const s16* samples, size_t sample_count) { 90void SDL2Sink::EnqueueSamples(const s16* samples, size_t sample_count) {
73 if (impl->audio_device_id <= 0) 91 if (impl->audio_device_id <= 0)
74 return; 92 return;
@@ -96,6 +114,10 @@ size_t SDL2Sink::SamplesInQueue() const {
96 return total_size; 114 return total_size;
97} 115}
98 116
117void SDL2Sink::SetDevice(int device_id) {
118 this->device_id = device_id;
119}
120
99void SDL2Sink::Impl::Callback(void* impl_, u8* buffer, int buffer_size_in_bytes) { 121void SDL2Sink::Impl::Callback(void* impl_, u8* buffer, int buffer_size_in_bytes) {
100 Impl* impl = reinterpret_cast<Impl*>(impl_); 122 Impl* impl = reinterpret_cast<Impl*>(impl_);
101 123
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:
21 21
22 size_t SamplesInQueue() const override; 22 size_t SamplesInQueue() const override;
23 23
24 std::vector<std::string> GetDeviceList() const override;
25 void SetDevice(int device_id);
26
24private: 27private:
25 struct Impl; 28 struct Impl;
26 std::unique_ptr<Impl> impl; 29 std::unique_ptr<Impl> impl;
30 int device_id;
31 std::vector<std::string> device_list;
27}; 32};
28 33
29} // namespace AudioCore 34} // 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:
31 31
32 /// Samples enqueued that have not been played yet. 32 /// Samples enqueued that have not been played yet.
33 virtual std::size_t SamplesInQueue() const = 0; 33 virtual std::size_t SamplesInQueue() const = 0;
34
35 /**
36 * Sets the desired output device.
37 * @paran device_id Id of the desired device.
38 */
39 virtual void SetDevice(int device_id) = 0;
40
41 /// Returns the list of available devices.
42 virtual std::vector<std::string> GetDeviceList() const = 0;
34}; 43};
35 44
36} // namespace 45} // 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 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
5#include <memory> 6#include <memory>
6#include <vector> 7#include <vector>
7#include "audio_core/null_sink.h" 8#include "audio_core/null_sink.h"
@@ -9,6 +10,7 @@
9#ifdef HAVE_SDL2 10#ifdef HAVE_SDL2
10#include "audio_core/sdl2_sink.h" 11#include "audio_core/sdl2_sink.h"
11#endif 12#endif
13#include "common/logging/log.h"
12 14
13namespace AudioCore { 15namespace AudioCore {
14 16
@@ -20,4 +22,21 @@ const std::vector<SinkDetails> g_sink_details = {
20 {"null", []() { return std::make_unique<NullSink>(); }}, 22 {"null", []() { return std::make_unique<NullSink>(); }},
21}; 23};
22 24
25const SinkDetails& GetSinkDetails(std::string sink_id) {
26 auto iter =
27 std::find_if(g_sink_details.begin(), g_sink_details.end(),
28 [sink_id](const auto& sink_detail) { return sink_detail.id == sink_id; });
29
30 if (sink_id == "auto" || iter == g_sink_details.end()) {
31 if (sink_id != "auto") {
32 LOG_ERROR(Audio, "AudioCore::SelectSink given invalid sink_id %s", sink_id.c_str());
33 }
34 // Auto-select.
35 // g_sink_details is ordered in terms of desirability, with the best choice at the front.
36 iter = g_sink_details.begin();
37 }
38
39 return *iter;
40}
41
23} // namespace AudioCore 42} // 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 {
24 24
25extern const std::vector<SinkDetails> g_sink_details; 25extern const std::vector<SinkDetails> g_sink_details;
26 26
27const SinkDetails& GetSinkDetails(std::string sink_id);
28
27} // namespace AudioCore 29} // 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() {
82 Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto"); 82 Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto");
83 Settings::values.enable_audio_stretching = 83 Settings::values.enable_audio_stretching =
84 sdl2_config->GetBoolean("Audio", "enable_audio_stretching", true); 84 sdl2_config->GetBoolean("Audio", "enable_audio_stretching", true);
85 Settings::values.audio_device_id = sdl2_config->Get("Audio", "output_device", "auto");
85 86
86 // Data Storage 87 // Data Storage
87 Settings::values.use_virtual_sd = 88 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 =
91# 0: No, 1 (default): Yes 91# 0: No, 1 (default): Yes
92enable_audio_stretching = 92enable_audio_stretching =
93 93
94# Which audio device to use.
95# auto (default): Auto-select
96output_device =
97
94[Data Storage] 98[Data Storage]
95# Whether to create a virtual SD card. 99# Whether to create a virtual SD card.
96# 1 (default): Yes, 0: No 100# 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() {
63 Settings::values.sink_id = qt_config->value("output_engine", "auto").toString().toStdString(); 63 Settings::values.sink_id = qt_config->value("output_engine", "auto").toString().toStdString();
64 Settings::values.enable_audio_stretching = 64 Settings::values.enable_audio_stretching =
65 qt_config->value("enable_audio_stretching", true).toBool(); 65 qt_config->value("enable_audio_stretching", true).toBool();
66 Settings::values.audio_device_id =
67 qt_config->value("output_device", "auto").toString().toStdString();
66 qt_config->endGroup(); 68 qt_config->endGroup();
67 69
68 qt_config->beginGroup("Data Storage"); 70 qt_config->beginGroup("Data Storage");
@@ -169,6 +171,7 @@ void Config::SaveValues() {
169 qt_config->beginGroup("Audio"); 171 qt_config->beginGroup("Audio");
170 qt_config->setValue("output_engine", QString::fromStdString(Settings::values.sink_id)); 172 qt_config->setValue("output_engine", QString::fromStdString(Settings::values.sink_id));
171 qt_config->setValue("enable_audio_stretching", Settings::values.enable_audio_stretching); 173 qt_config->setValue("enable_audio_stretching", Settings::values.enable_audio_stretching);
174 qt_config->setValue("output_device", QString::fromStdString(Settings::values.audio_device_id));
172 qt_config->endGroup(); 175 qt_config->endGroup();
173 176
174 qt_config->beginGroup("Data Storage"); 177 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 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <memory>
6#include "audio_core/audio_core.h"
7#include "audio_core/sink.h"
5#include "audio_core/sink_details.h" 8#include "audio_core/sink_details.h"
6#include "citra_qt/configure_audio.h" 9#include "citra_qt/configure_audio.h"
7#include "core/settings.h" 10#include "core/settings.h"
@@ -18,6 +21,8 @@ ConfigureAudio::ConfigureAudio(QWidget* parent)
18 } 21 }
19 22
20 this->setConfiguration(); 23 this->setConfiguration();
24 connect(ui->output_sink_combo_box, SIGNAL(currentIndexChanged(int)), this,
25 SLOT(updateAudioDevices(int)));
21} 26}
22 27
23ConfigureAudio::~ConfigureAudio() {} 28ConfigureAudio::~ConfigureAudio() {}
@@ -33,6 +38,19 @@ void ConfigureAudio::setConfiguration() {
33 ui->output_sink_combo_box->setCurrentIndex(new_sink_index); 38 ui->output_sink_combo_box->setCurrentIndex(new_sink_index);
34 39
35 ui->toggle_audio_stretching->setChecked(Settings::values.enable_audio_stretching); 40 ui->toggle_audio_stretching->setChecked(Settings::values.enable_audio_stretching);
41
42 // The device list cannot be pre-populated (nor listed) until the output sink is known.
43 updateAudioDevices(new_sink_index);
44
45 int new_device_index = -1;
46 for (int index = 0; index < ui->audio_device_combo_box->count(); index++) {
47 if (ui->audio_device_combo_box->itemText(index).toStdString() ==
48 Settings::values.audio_device_id) {
49 new_device_index = index;
50 break;
51 }
52 }
53 ui->audio_device_combo_box->setCurrentIndex(new_device_index);
36} 54}
37 55
38void ConfigureAudio::applyConfiguration() { 56void ConfigureAudio::applyConfiguration() {
@@ -40,5 +58,20 @@ void ConfigureAudio::applyConfiguration() {
40 ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex()) 58 ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex())
41 .toStdString(); 59 .toStdString();
42 Settings::values.enable_audio_stretching = ui->toggle_audio_stretching->isChecked(); 60 Settings::values.enable_audio_stretching = ui->toggle_audio_stretching->isChecked();
61 Settings::values.audio_device_id =
62 ui->audio_device_combo_box->itemText(ui->audio_device_combo_box->currentIndex())
63 .toStdString();
43 Settings::Apply(); 64 Settings::Apply();
44} 65}
66
67void ConfigureAudio::updateAudioDevices(int sink_index) {
68 ui->audio_device_combo_box->clear();
69 ui->audio_device_combo_box->addItem("auto");
70
71 std::string sink_id = ui->output_sink_combo_box->itemText(sink_index).toStdString();
72 std::vector<std::string> device_list =
73 AudioCore::GetSinkDetails(sink_id).factory()->GetDeviceList();
74 for (const auto& device : device_list) {
75 ui->audio_device_combo_box->addItem(device.c_str());
76 }
77}
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:
20 20
21 void applyConfiguration(); 21 void applyConfiguration();
22 22
23public slots:
24 void updateAudioDevices(int sink_index);
25
23private: 26private:
24 void setConfiguration(); 27 void setConfiguration();
25 28
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 @@
35 </property> 35 </property>
36 </widget> 36 </widget>
37 </item> 37 </item>
38 <item>
39 <layout class="QHBoxLayout">
40 <item>
41 <widget class="QLabel">
42 <property name="text">
43 <string>Audio Device:</string>
44 </property>
45 </widget>
46 </item>
47 <item>
48 <widget class="QComboBox" name="audio_device_combo_box">
49 </widget>
50 </item>
51 </layout>
52 </item>
38 </layout> 53 </layout>
39 </widget> 54 </widget>
40 </item> 55 </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 {
104 // Audio 104 // Audio
105 std::string sink_id; 105 std::string sink_id;
106 bool enable_audio_stretching; 106 bool enable_audio_stretching;
107 std::string audio_device_id;
107 108
108 // Debugging 109 // Debugging
109 bool use_gdbstub; 110 bool use_gdbstub;