mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	misc: Improve defaults for macOS and handling of missing audio backends. (#7273)
* misc: Improve backend defaults for macOS. * audio_core: Improve handling of missing audio backends.
This commit is contained in:
		
							parent
							
								
									dccb8f6b17
								
							
						
					
					
						commit
						178e602589
					
				
					 11 changed files with 109 additions and 107 deletions
				
			
		|  | @ -155,6 +155,10 @@ else() | |||
|     endif() | ||||
| endif() | ||||
| 
 | ||||
| if (NOT APPLE) | ||||
|     add_compile_definitions(HAS_OPENGL) | ||||
| endif() | ||||
| 
 | ||||
| add_subdirectory(common) | ||||
| add_subdirectory(core) | ||||
| add_subdirectory(video_core) | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ void DspInterface::SetSink(AudioCore::SinkType sink_type, std::string_view audio | |||
|     // Dispose of the current sink first to avoid contention.
 | ||||
|     sink.reset(); | ||||
| 
 | ||||
|     sink = CreateSinkFromID(sink_type, audio_device); | ||||
|     sink = AudioCore::GetSinkDetails(sink_type).create_sink(audio_device); | ||||
|     sink->SetCallback( | ||||
|         [this](s16* buffer, std::size_t num_frames) { OutputCallback(buffer, num_frames); }); | ||||
|     time_stretcher.SetOutputSampleRate(sink->GetNativeSampleRate()); | ||||
|  |  | |||
|  | @ -20,24 +20,10 @@ | |||
| 
 | ||||
| namespace AudioCore { | ||||
| namespace { | ||||
| struct InputDetails { | ||||
|     using FactoryFn = std::unique_ptr<Input> (*)(std::string_view); | ||||
|     using ListDevicesFn = std::vector<std::string> (*)(); | ||||
| 
 | ||||
|     /// Type of this input.
 | ||||
|     InputType type; | ||||
|     /// Name for this input.
 | ||||
|     std::string_view name; | ||||
|     /// A method to call to construct an instance of this type of input.
 | ||||
|     FactoryFn factory; | ||||
|     /// A method to call to list available devices.
 | ||||
|     ListDevicesFn list_devices; | ||||
| }; | ||||
| 
 | ||||
| // input_details is ordered in terms of desirability, with the best choice at the top.
 | ||||
| constexpr std::array input_details = { | ||||
| #ifdef HAVE_CUBEB | ||||
|     InputDetails{InputType::Cubeb, "Real Device (Cubeb)", | ||||
|     InputDetails{InputType::Cubeb, "Real Device (Cubeb)", true, | ||||
|                  [](std::string_view device_id) -> std::unique_ptr<Input> { | ||||
|                      if (!Core::System::GetInstance().HasMicPermission()) { | ||||
|                          LOG_WARNING(Audio, | ||||
|  | @ -49,7 +35,7 @@ constexpr std::array input_details = { | |||
|                  &ListCubebInputDevices}, | ||||
| #endif | ||||
| #ifdef HAVE_OPENAL | ||||
|     InputDetails{InputType::OpenAL, "Real Device (OpenAL)", | ||||
|     InputDetails{InputType::OpenAL, "Real Device (OpenAL)", true, | ||||
|                  [](std::string_view device_id) -> std::unique_ptr<Input> { | ||||
|                      if (!Core::System::GetInstance().HasMicPermission()) { | ||||
|                          LOG_WARNING(Audio, | ||||
|  | @ -60,17 +46,22 @@ constexpr std::array input_details = { | |||
|                  }, | ||||
|                  &ListOpenALInputDevices}, | ||||
| #endif | ||||
|     InputDetails{InputType::Static, "Static Noise", | ||||
|     InputDetails{InputType::Static, "Static Noise", false, | ||||
|                  [](std::string_view device_id) -> std::unique_ptr<Input> { | ||||
|                      return std::make_unique<StaticInput>(); | ||||
|                  }, | ||||
|                  [] { return std::vector<std::string>{"Static Noise"}; }}, | ||||
|     InputDetails{InputType::Null, "None", | ||||
|     InputDetails{InputType::Null, "None", false, | ||||
|                  [](std::string_view device_id) -> std::unique_ptr<Input> { | ||||
|                      return std::make_unique<NullInput>(); | ||||
|                  }, | ||||
|                  [] { return std::vector<std::string>{"None"}; }}, | ||||
| }; | ||||
| } // Anonymous namespace
 | ||||
| 
 | ||||
| std::vector<InputDetails> ListInputs() { | ||||
|     return {input_details.begin(), input_details.end()}; | ||||
| } | ||||
| 
 | ||||
| const InputDetails& GetInputDetails(InputType input_type) { | ||||
|     auto iter = std::find_if( | ||||
|  | @ -88,21 +79,5 @@ const InputDetails& GetInputDetails(InputType input_type) { | |||
| 
 | ||||
|     return *iter; | ||||
| } | ||||
| } // Anonymous namespace
 | ||||
| 
 | ||||
| std::string_view GetInputName(InputType input_type) { | ||||
|     if (input_type == InputType::Auto) { | ||||
|         return "Auto"; | ||||
|     } | ||||
|     return GetInputDetails(input_type).name; | ||||
| } | ||||
| 
 | ||||
| std::vector<std::string> GetDeviceListForInput(InputType input_type) { | ||||
|     return GetInputDetails(input_type).list_devices(); | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<Input> CreateInputFromID(InputType input_type, std::string_view device_id) { | ||||
|     return GetInputDetails(input_type).factory(device_id); | ||||
| } | ||||
| 
 | ||||
| } // namespace AudioCore
 | ||||
|  |  | |||
|  | @ -20,17 +20,28 @@ enum class InputType : u32 { | |||
|     Static = 2, | ||||
|     Cubeb = 3, | ||||
|     OpenAL = 4, | ||||
| 
 | ||||
|     NumInputTypes, | ||||
| }; | ||||
| 
 | ||||
| /// Gets the name of a input type.
 | ||||
| std::string_view GetInputName(InputType input_type); | ||||
| struct InputDetails { | ||||
|     using FactoryFn = std::unique_ptr<Input> (*)(std::string_view device_id); | ||||
|     using ListDevicesFn = std::vector<std::string> (*)(); | ||||
| 
 | ||||
| /// Gets the list of devices for a particular input identified by the given ID.
 | ||||
| std::vector<std::string> GetDeviceListForInput(InputType input_type); | ||||
|     /// Type of this input.
 | ||||
|     InputType type; | ||||
|     /// Name for this input.
 | ||||
|     std::string_view name; | ||||
|     /// Whether the input is backed by real devices.
 | ||||
|     bool real; | ||||
|     /// A method to call to construct an instance of this type of input.
 | ||||
|     FactoryFn create_input; | ||||
|     /// A method to call to list available devices.
 | ||||
|     ListDevicesFn list_devices; | ||||
| }; | ||||
| 
 | ||||
| /// Creates an audio input identified by the given device ID.
 | ||||
| std::unique_ptr<Input> CreateInputFromID(InputType input_type, std::string_view device_id); | ||||
| /// Lists all available input types.
 | ||||
| std::vector<InputDetails> ListInputs(); | ||||
| 
 | ||||
| /// Gets the details of an input type.
 | ||||
| const InputDetails& GetInputDetails(InputType input_type); | ||||
| 
 | ||||
| } // namespace AudioCore
 | ||||
|  |  | |||
|  | @ -21,20 +21,6 @@ | |||
| 
 | ||||
| namespace AudioCore { | ||||
| namespace { | ||||
| struct SinkDetails { | ||||
|     using FactoryFn = std::unique_ptr<Sink> (*)(std::string_view); | ||||
|     using ListDevicesFn = std::vector<std::string> (*)(); | ||||
| 
 | ||||
|     /// Type of this sink.
 | ||||
|     SinkType type; | ||||
|     /// Name for this sink.
 | ||||
|     std::string_view name; | ||||
|     /// 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 std::array sink_details = { | ||||
| #ifdef HAVE_CUBEB | ||||
|  | @ -64,6 +50,11 @@ constexpr std::array sink_details = { | |||
|                 }, | ||||
|                 [] { return std::vector<std::string>{"None"}; }}, | ||||
| }; | ||||
| } // Anonymous namespace
 | ||||
| 
 | ||||
| std::vector<SinkDetails> ListSinks() { | ||||
|     return {sink_details.begin(), sink_details.end()}; | ||||
| } | ||||
| 
 | ||||
| const SinkDetails& GetSinkDetails(SinkType sink_type) { | ||||
|     auto iter = std::find_if( | ||||
|  | @ -81,21 +72,5 @@ const SinkDetails& GetSinkDetails(SinkType sink_type) { | |||
| 
 | ||||
|     return *iter; | ||||
| } | ||||
| } // Anonymous namespace
 | ||||
| 
 | ||||
| std::string_view GetSinkName(SinkType sink_type) { | ||||
|     if (sink_type == SinkType::Auto) { | ||||
|         return "Auto"; | ||||
|     } | ||||
|     return GetSinkDetails(sink_type).name; | ||||
| } | ||||
| 
 | ||||
| std::vector<std::string> GetDeviceListForSink(SinkType sink_type) { | ||||
|     return GetSinkDetails(sink_type).list_devices(); | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<Sink> CreateSinkFromID(SinkType sink_type, std::string_view device_id) { | ||||
|     return GetSinkDetails(sink_type).factory(device_id); | ||||
| } | ||||
| 
 | ||||
| } // namespace AudioCore
 | ||||
|  |  | |||
|  | @ -20,17 +20,26 @@ enum class SinkType : u32 { | |||
|     Cubeb = 2, | ||||
|     OpenAL = 3, | ||||
|     SDL2 = 4, | ||||
| 
 | ||||
|     NumSinkTypes, | ||||
| }; | ||||
| 
 | ||||
| /// Gets the name of a sink type.
 | ||||
| std::string_view GetSinkName(SinkType sink_type); | ||||
| struct SinkDetails { | ||||
|     using FactoryFn = std::unique_ptr<Sink> (*)(std::string_view); | ||||
|     using ListDevicesFn = std::vector<std::string> (*)(); | ||||
| 
 | ||||
| /// Gets the list of devices for a particular sink identified by the given ID.
 | ||||
| std::vector<std::string> GetDeviceListForSink(SinkType sink_type); | ||||
|     /// Type of this sink.
 | ||||
|     SinkType type; | ||||
|     /// Name for this sink.
 | ||||
|     std::string_view name; | ||||
|     /// A method to call to construct an instance of this type of sink.
 | ||||
|     FactoryFn create_sink; | ||||
|     /// A method to call to list available devices.
 | ||||
|     ListDevicesFn list_devices; | ||||
| }; | ||||
| 
 | ||||
| /// Creates an audio sink identified by the given device ID.
 | ||||
| std::unique_ptr<Sink> CreateSinkFromID(SinkType sink_type, std::string_view device_id); | ||||
| /// Lists all available sink types.
 | ||||
| std::vector<SinkDetails> ListSinks(); | ||||
| 
 | ||||
| /// Gets the details of an sink type.
 | ||||
| const SinkDetails& GetSinkDetails(SinkType input_type); | ||||
| 
 | ||||
| } // namespace AudioCore
 | ||||
|  |  | |||
|  | @ -351,10 +351,6 @@ if(UNIX AND NOT APPLE) | |||
|     install(TARGETS citra-qt RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") | ||||
| endif() | ||||
| 
 | ||||
| if (NOT APPLE) | ||||
|     target_compile_definitions(citra-qt PRIVATE HAS_OPENGL) | ||||
| endif() | ||||
| 
 | ||||
| if (CITRA_USE_PRECOMPILED_HEADERS) | ||||
|     target_precompile_headers(citra-qt PRIVATE precompiled_headers.h) | ||||
| endif() | ||||
|  |  | |||
|  | @ -21,9 +21,10 @@ ConfigureAudio::ConfigureAudio(bool is_powered_on, QWidget* parent) | |||
|     ui->setupUi(this); | ||||
| 
 | ||||
|     ui->output_type_combo_box->clear(); | ||||
|     for (u32 type = 0; type < static_cast<u32>(AudioCore::SinkType::NumSinkTypes); type++) { | ||||
|         ui->output_type_combo_box->addItem(QString::fromUtf8( | ||||
|             AudioCore::GetSinkName(static_cast<AudioCore::SinkType>(type)).data())); | ||||
|     ui->output_type_combo_box->addItem(tr("Auto"), QVariant::fromValue(AudioCore::SinkType::Auto)); | ||||
|     for (const auto& sink : AudioCore::ListSinks()) { | ||||
|         ui->output_type_combo_box->addItem(QString::fromUtf8(sink.name), | ||||
|                                            QVariant::fromValue(sink.type)); | ||||
|     } | ||||
| 
 | ||||
|     ui->emulation_combo_box->setEnabled(!is_powered_on); | ||||
|  | @ -32,9 +33,10 @@ ConfigureAudio::ConfigureAudio(bool is_powered_on, QWidget* parent) | |||
|             &ConfigureAudio::SetVolumeIndicatorText); | ||||
| 
 | ||||
|     ui->input_type_combo_box->clear(); | ||||
|     for (u32 type = 0; type < static_cast<u32>(AudioCore::InputType::NumInputTypes); type++) { | ||||
|         ui->input_type_combo_box->addItem(QString::fromUtf8( | ||||
|             AudioCore::GetInputName(static_cast<AudioCore::InputType>(type)).data())); | ||||
|     ui->input_type_combo_box->addItem(tr("Auto"), QVariant::fromValue(AudioCore::InputType::Auto)); | ||||
|     for (const auto& input : AudioCore::ListInputs()) { | ||||
|         ui->input_type_combo_box->addItem(QString::fromUtf8(input.name), | ||||
|                                           QVariant::fromValue(input.type)); | ||||
|     } | ||||
| 
 | ||||
|     ui->volume_label->setVisible(Settings::IsConfiguringGlobal()); | ||||
|  | @ -89,8 +91,18 @@ void ConfigureAudio::SetConfiguration() { | |||
| } | ||||
| 
 | ||||
| void ConfigureAudio::SetOutputTypeFromSinkType() { | ||||
|     ui->output_type_combo_box->setCurrentIndex( | ||||
|         static_cast<int>(Settings::values.output_type.GetValue())); | ||||
|     int new_index = -1; | ||||
| 
 | ||||
|     for (int index = 0; index < ui->output_type_combo_box->count(); index++) { | ||||
|         const auto sink_type = | ||||
|             static_cast<AudioCore::SinkType>(ui->output_type_combo_box->itemData(index).toUInt()); | ||||
|         if (Settings::values.output_type.GetValue() == sink_type) { | ||||
|             new_index = index; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     ui->output_type_combo_box->setCurrentIndex(new_index); | ||||
| } | ||||
| 
 | ||||
| void ConfigureAudio::SetOutputDeviceFromDeviceID() { | ||||
|  | @ -108,8 +120,18 @@ void ConfigureAudio::SetOutputDeviceFromDeviceID() { | |||
| } | ||||
| 
 | ||||
| void ConfigureAudio::SetInputTypeFromInputType() { | ||||
|     ui->input_type_combo_box->setCurrentIndex( | ||||
|         static_cast<int>(Settings::values.input_type.GetValue())); | ||||
|     int new_index = -1; | ||||
| 
 | ||||
|     for (int index = 0; index < ui->input_type_combo_box->count(); index++) { | ||||
|         const auto input_type = | ||||
|             static_cast<AudioCore::InputType>(ui->input_type_combo_box->itemData(index).toUInt()); | ||||
|         if (Settings::values.input_type.GetValue() == input_type) { | ||||
|             new_index = index; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     ui->input_type_combo_box->setCurrentIndex(new_index); | ||||
| } | ||||
| 
 | ||||
| void ConfigureAudio::SetInputDeviceFromDeviceID() { | ||||
|  | @ -142,30 +164,34 @@ void ConfigureAudio::ApplyConfiguration() { | |||
| 
 | ||||
|     if (Settings::IsConfiguringGlobal()) { | ||||
|         Settings::values.output_type = | ||||
|             static_cast<AudioCore::SinkType>(ui->output_type_combo_box->currentIndex()); | ||||
|             static_cast<AudioCore::SinkType>(ui->output_type_combo_box->currentData().toUInt()); | ||||
|         Settings::values.output_device = ui->output_device_combo_box->currentText().toStdString(); | ||||
|         Settings::values.input_type = | ||||
|             static_cast<AudioCore::InputType>(ui->input_type_combo_box->currentIndex()); | ||||
|             static_cast<AudioCore::InputType>(ui->input_type_combo_box->currentData().toUInt()); | ||||
|         Settings::values.input_device = ui->input_device_combo_box->currentText().toStdString(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void ConfigureAudio::UpdateAudioOutputDevices(int sink_index) { | ||||
|     auto sink_type = static_cast<AudioCore::SinkType>(sink_index); | ||||
|     auto sink_type = | ||||
|         static_cast<AudioCore::SinkType>(ui->output_type_combo_box->itemData(sink_index).toUInt()); | ||||
|     auto& sink_details = AudioCore::GetSinkDetails(sink_type); | ||||
| 
 | ||||
|     ui->output_device_combo_box->clear(); | ||||
|     ui->output_device_combo_box->addItem(QString::fromUtf8(AudioCore::auto_device_name)); | ||||
| 
 | ||||
|     for (const auto& device : AudioCore::GetDeviceListForSink(sink_type)) { | ||||
|     for (const auto& device : sink_details.list_devices()) { | ||||
|         ui->output_device_combo_box->addItem(QString::fromStdString(device)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void ConfigureAudio::UpdateAudioInputDevices(int input_index) { | ||||
|     auto input_type = static_cast<AudioCore::InputType>(input_index); | ||||
|     auto input_type = | ||||
|         static_cast<AudioCore::InputType>(ui->input_type_combo_box->itemData(input_index).toUInt()); | ||||
|     auto& input_details = AudioCore::GetInputDetails(input_type); | ||||
| 
 | ||||
| #if defined(__APPLE__) | ||||
|     if (input_type != AudioCore::InputType::Null && input_type != AudioCore::InputType::Static) { | ||||
|     if (input_details.real) { | ||||
|         AppleAuthorization::CheckAuthorizationForMicrophone(); | ||||
|     } | ||||
| #endif | ||||
|  | @ -173,7 +199,7 @@ void ConfigureAudio::UpdateAudioInputDevices(int input_index) { | |||
|     ui->input_device_combo_box->clear(); | ||||
|     ui->input_device_combo_box->addItem(QString::fromUtf8(AudioCore::auto_device_name)); | ||||
| 
 | ||||
|     for (const auto& device : AudioCore::GetDeviceListForInput(input_type)) { | ||||
|     for (const auto& device : input_details.list_devices()) { | ||||
|         ui->input_device_combo_box->addItem(QString::fromStdString(device)); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -441,8 +441,13 @@ struct Values { | |||
|     Setting<bool> allow_plugin_loader{true, "allow_plugin_loader"}; | ||||
| 
 | ||||
|     // Renderer
 | ||||
|     SwitchableSetting<GraphicsAPI, true> graphics_api{GraphicsAPI::OpenGL, GraphicsAPI::Software, | ||||
|                                                       GraphicsAPI::Vulkan, "graphics_api"}; | ||||
|     SwitchableSetting<GraphicsAPI, true> graphics_api{ | ||||
| #ifdef HAS_OPENGL | ||||
|         GraphicsAPI::OpenGL, | ||||
| #else | ||||
|         GraphicsAPI::Vulkan, | ||||
| #endif | ||||
|         GraphicsAPI::Software, GraphicsAPI::Vulkan, "graphics_api"}; | ||||
|     SwitchableSetting<u32> physical_device{0, "physical_device"}; | ||||
|     Setting<bool> use_gles{false, "use_gles"}; | ||||
|     Setting<bool> renderer_debug{false, "renderer_debug"}; | ||||
|  |  | |||
|  | @ -375,8 +375,8 @@ struct MIC_U::Impl { | |||
|             mic.reset(); | ||||
|         } | ||||
| 
 | ||||
|         mic = AudioCore::CreateInputFromID(Settings::values.input_type.GetValue(), | ||||
|                                            Settings::values.input_device.GetValue()); | ||||
|         mic = AudioCore::GetInputDetails(Settings::values.input_type.GetValue()) | ||||
|                   .create_input(Settings::values.input_device.GetValue()); | ||||
|         if (was_sampling) { | ||||
|             StartSampling(); | ||||
|         } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue