mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 05:10:03 +00:00 
			
		
		
		
	Merge pull request #4512 from FearlessTobi/port-1902
Port yuzu-emu/yuzu#1902: "audio_core: Make g_sink_details internally linked"
This commit is contained in:
		
						commit
						fbd0944a5a
					
				
					 7 changed files with 63 additions and 37 deletions
				
			
		|  | @ -26,7 +26,7 @@ struct CubebSink::Impl { | |||
|     static void LogCallback(char const* fmt, ...); | ||||
| }; | ||||
| 
 | ||||
| CubebSink::CubebSink(std::string target_device_name) : impl(std::make_unique<Impl>()) { | ||||
| CubebSink::CubebSink(std::string_view 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; | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ namespace AudioCore { | |||
| 
 | ||||
| class CubebSink final : public Sink { | ||||
| public: | ||||
|     explicit CubebSink(std::string device_id); | ||||
|     explicit CubebSink(std::string_view device_id); | ||||
|     ~CubebSink() override; | ||||
| 
 | ||||
|     unsigned int GetNativeSampleRate() const override; | ||||
|  |  | |||
|  | @ -15,8 +15,7 @@ DspInterface::DspInterface() = default; | |||
| DspInterface::~DspInterface() = default; | ||||
| 
 | ||||
| void DspInterface::SetSink(const std::string& sink_id, const std::string& audio_device) { | ||||
|     const SinkDetails& sink_details = GetSinkDetails(sink_id); | ||||
|     sink = sink_details.factory(audio_device); | ||||
|     sink = CreateSinkFromID(Settings::values.sink_id, Settings::values.audio_device_id); | ||||
|     sink->SetCallback( | ||||
|         [this](s16* buffer, std::size_t num_frames) { OutputCallback(buffer, num_frames); }); | ||||
|     time_stretcher.SetOutputSampleRate(sink->GetNativeSampleRate()); | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ namespace AudioCore { | |||
| 
 | ||||
| class NullSink final : public Sink { | ||||
| public: | ||||
|     NullSink(std::string) {} | ||||
|     explicit NullSink(std::string_view) {} | ||||
|     ~NullSink() override = default; | ||||
| 
 | ||||
|     unsigned int GetNativeSampleRate() const override { | ||||
|  |  | |||
|  | @ -17,34 +17,75 @@ | |||
| #include "common/logging/log.h" | ||||
| 
 | ||||
| namespace AudioCore { | ||||
| namespace { | ||||
| struct SinkDetails { | ||||
|     using FactoryFn = std::unique_ptr<Sink> (*)(std::string_view); | ||||
|     using ListDevicesFn = std::vector<std::string> (*)(); | ||||
| 
 | ||||
| // g_sink_details is ordered in terms of desirability, with the best choice at the top.
 | ||||
| const std::vector<SinkDetails> g_sink_details = { | ||||
|     /// Name for this sink.
 | ||||
|     const char* id; | ||||
|     /// A method to call to construct an instance of this type of sink.
 | ||||
|     FactoryFn factory; | ||||
|     /// A method to call to list available devices.
 | ||||
|     ListDevicesFn list_devices; | ||||
| }; | ||||
| 
 | ||||
| // sink_details is ordered in terms of desirability, with the best choice at the top.
 | ||||
| constexpr SinkDetails sink_details[] = { | ||||
| #ifdef HAVE_CUBEB | ||||
|     SinkDetails{"cubeb", &std::make_unique<CubebSink, std::string>, &ListCubebSinkDevices}, | ||||
|     SinkDetails{"cubeb", | ||||
|                 [](std::string_view device_id) -> std::unique_ptr<Sink> { | ||||
|                     return std::make_unique<CubebSink>(device_id); | ||||
|                 }, | ||||
|                 &ListCubebSinkDevices}, | ||||
| #endif | ||||
| #ifdef HAVE_SDL2 | ||||
|     SinkDetails{"sdl2", &std::make_unique<SDL2Sink, std::string>, &ListSDL2SinkDevices}, | ||||
|     SinkDetails{"sdl2", | ||||
|                 [](std::string_view device_id) -> std::unique_ptr<Sink> { | ||||
|                     return std::make_unique<SDL2Sink>(std::string(device_id)); | ||||
|                 }, | ||||
|                 &ListSDL2SinkDevices}, | ||||
| #endif | ||||
|     SinkDetails{"null", &std::make_unique<NullSink, std::string>, | ||||
|     SinkDetails{"null", | ||||
|                 [](std::string_view device_id) -> std::unique_ptr<Sink> { | ||||
|                     return std::make_unique<NullSink>(device_id); | ||||
|                 }, | ||||
|                 [] { return std::vector<std::string>{"null"}; }}, | ||||
| }; | ||||
| 
 | ||||
| const SinkDetails& GetSinkDetails(std::string_view sink_id) { | ||||
|     auto iter = | ||||
|         std::find_if(g_sink_details.begin(), g_sink_details.end(), | ||||
|         std::find_if(std::begin(sink_details), std::end(sink_details), | ||||
|                      [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" || iter == std::end(sink_details)) { | ||||
|         if (sink_id != "auto") { | ||||
|             LOG_ERROR(Audio, "AudioCore::SelectSink given invalid sink_id {}", sink_id); | ||||
|         } | ||||
|         // Auto-select.
 | ||||
|         // g_sink_details is ordered in terms of desirability, with the best choice at the front.
 | ||||
|         iter = g_sink_details.begin(); | ||||
|         // sink_details is ordered in terms of desirability, with the best choice at the front.
 | ||||
|         iter = std::begin(sink_details); | ||||
|     } | ||||
| 
 | ||||
|     return *iter; | ||||
| } | ||||
| } // Anonymous namespace
 | ||||
| 
 | ||||
| std::vector<const char*> GetSinkIDs() { | ||||
|     std::vector<const char*> sink_ids(std::size(sink_details)); | ||||
| 
 | ||||
|     std::transform(std::begin(sink_details), std::end(sink_details), std::begin(sink_ids), | ||||
|                    [](const auto& sink) { return sink.id; }); | ||||
| 
 | ||||
|     return sink_ids; | ||||
| } | ||||
| 
 | ||||
| std::vector<std::string> GetDeviceListForSink(std::string_view sink_id) { | ||||
|     return GetSinkDetails(sink_id).list_devices(); | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<Sink> CreateSinkFromID(std::string_view sink_id, std::string_view device_id) { | ||||
|     return GetSinkDetails(sink_id).factory(device_id); | ||||
| } | ||||
| 
 | ||||
| } // namespace AudioCore
 | ||||
|  |  | |||
|  | @ -4,34 +4,21 @@ | |||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <functional> | ||||
| #include <memory> | ||||
| #include <string> | ||||
| #include <string_view> | ||||
| #include <utility> | ||||
| #include <vector> | ||||
| 
 | ||||
| namespace AudioCore { | ||||
| 
 | ||||
| class Sink; | ||||
| 
 | ||||
| struct SinkDetails { | ||||
|     using FactoryFn = std::function<std::unique_ptr<Sink>(std::string)>; | ||||
|     using ListDevicesFn = std::function<std::vector<std::string>()>; | ||||
| /// Retrieves the IDs for all available audio sinks.
 | ||||
| std::vector<const char*> GetSinkIDs(); | ||||
| 
 | ||||
|     SinkDetails(const char* id_, FactoryFn factory_, ListDevicesFn list_devices_) | ||||
|         : id(id_), factory(std::move(factory_)), list_devices(std::move(list_devices_)) {} | ||||
| /// Gets the list of devices for a particular sink identified by the given ID.
 | ||||
| std::vector<std::string> GetDeviceListForSink(std::string_view sink_id); | ||||
| 
 | ||||
|     /// Name for this sink.
 | ||||
|     const char* id; | ||||
|     /// A method to call to construct an instance of this type of sink.
 | ||||
|     FactoryFn factory; | ||||
|     /// A method to call to list available devices.
 | ||||
|     ListDevicesFn list_devices; | ||||
| }; | ||||
| 
 | ||||
| extern const std::vector<SinkDetails> g_sink_details; | ||||
| 
 | ||||
| const SinkDetails& GetSinkDetails(std::string_view sink_id); | ||||
| /// Creates an audio sink identified by the given device ID.
 | ||||
| std::unique_ptr<Sink> CreateSinkFromID(std::string_view sink_id, std::string_view device_id); | ||||
| 
 | ||||
| } // namespace AudioCore
 | ||||
|  |  | |||
|  | @ -15,8 +15,8 @@ ConfigureAudio::ConfigureAudio(QWidget* parent) | |||
| 
 | ||||
|     ui->output_sink_combo_box->clear(); | ||||
|     ui->output_sink_combo_box->addItem("auto"); | ||||
|     for (const auto& sink_detail : AudioCore::g_sink_details) { | ||||
|         ui->output_sink_combo_box->addItem(sink_detail.id); | ||||
|     for (const char* id : AudioCore::GetSinkIDs()) { | ||||
|         ui->output_sink_combo_box->addItem(id); | ||||
|     } | ||||
| 
 | ||||
|     connect(ui->volume_slider, &QSlider::valueChanged, this, | ||||
|  | @ -92,8 +92,7 @@ void ConfigureAudio::updateAudioDevices(int sink_index) { | |||
|     ui->audio_device_combo_box->addItem(AudioCore::auto_device_name); | ||||
| 
 | ||||
|     const std::string sink_id = ui->output_sink_combo_box->itemText(sink_index).toStdString(); | ||||
|     const std::vector<std::string> device_list = AudioCore::GetSinkDetails(sink_id).list_devices(); | ||||
|     for (const auto& device : device_list) { | ||||
|     for (const auto& device : AudioCore::GetDeviceListForSink(sink_id)) { | ||||
|         ui->audio_device_combo_box->addItem(QString::fromStdString(device)); | ||||
|     } | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue