From 7cb653297129b9656574d9a1b6ecf101f2730eb7 Mon Sep 17 00:00:00 2001
From: Xpl0itR <xpl0itr@outlook.com>
Date: Sat, 4 Jul 2020 00:16:49 +0100
Subject: [PATCH] Implement audio backend configuration option (#1325)

* Implement audio backend configuration option

* Use OpenAL by default

* Increment version number in config.json

and add 30px to the height of the settings window

* nits

* capitalise audio backend names
---
 Ryujinx.Common/Configuration/AudioBackend.cs  |  9 ++
 .../Configuration/ConfigurationFileFormat.cs  |  7 +-
 .../Configuration/ConfigurationState.cs       | 32 ++++--
 Ryujinx/Config.json                           |  3 +-
 Ryujinx/Ui/MainWindow.cs                      | 32 +++---
 Ryujinx/Ui/SettingsWindow.cs                  | 13 ++-
 Ryujinx/Ui/SettingsWindow.glade               | 98 +++++++++++++------
 Ryujinx/_schema.json                          | 12 +++
 8 files changed, 152 insertions(+), 54 deletions(-)
 create mode 100644 Ryujinx.Common/Configuration/AudioBackend.cs

diff --git a/Ryujinx.Common/Configuration/AudioBackend.cs b/Ryujinx.Common/Configuration/AudioBackend.cs
new file mode 100644
index 0000000000..2823335489
--- /dev/null
+++ b/Ryujinx.Common/Configuration/AudioBackend.cs
@@ -0,0 +1,9 @@
+namespace Ryujinx.Configuration
+{
+    public enum AudioBackend
+    {
+        Dummy,
+        OpenAl,
+        SoundIo
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Common/Configuration/ConfigurationFileFormat.cs b/Ryujinx.Common/Configuration/ConfigurationFileFormat.cs
index e00e1eaa78..d67d71b833 100644
--- a/Ryujinx.Common/Configuration/ConfigurationFileFormat.cs
+++ b/Ryujinx.Common/Configuration/ConfigurationFileFormat.cs
@@ -13,7 +13,7 @@ namespace Ryujinx.Configuration
         /// <summary>
         /// The current version of the file format
         /// </summary>
-        public const int CurrentVersion = 9;
+        public const int CurrentVersion = 10;
 
         public int Version { get; set; }
 
@@ -127,6 +127,11 @@ namespace Ryujinx.Configuration
         /// </summary>
         public int FsGlobalAccessLogMode { get; set; }
 
+        /// <summary>
+        /// The selected audio backend
+        /// </summary>
+        public AudioBackend AudioBackend { get; set; }
+
         /// <summary>
         /// Enable or disable ignoring missing services
         /// </summary>
diff --git a/Ryujinx.Common/Configuration/ConfigurationState.cs b/Ryujinx.Common/Configuration/ConfigurationState.cs
index 2a85f7e197..0f5367f9f0 100644
--- a/Ryujinx.Common/Configuration/ConfigurationState.cs
+++ b/Ryujinx.Common/Configuration/ConfigurationState.cs
@@ -205,6 +205,11 @@ namespace Ryujinx.Configuration
             /// </summary>
             public ReactiveObject<int> FsGlobalAccessLogMode { get; private set; }
 
+            /// <summary>
+            /// The selected audio backend
+            /// </summary>
+            public ReactiveObject<AudioBackend> AudioBackend { get; private set; }
+
             /// <summary>
             /// Enable or disable ignoring missing services
             /// </summary>
@@ -221,6 +226,7 @@ namespace Ryujinx.Configuration
                 EnablePtc                 = new ReactiveObject<bool>();
                 EnableFsIntegrityChecks   = new ReactiveObject<bool>();
                 FsGlobalAccessLogMode     = new ReactiveObject<int>();
+                AudioBackend              = new ReactiveObject<AudioBackend>();
                 IgnoreMissingServices     = new ReactiveObject<bool>();
             }
         }
@@ -370,6 +376,7 @@ namespace Ryujinx.Configuration
                 EnablePtc                 = System.EnablePtc,
                 EnableFsIntegrityChecks   = System.EnableFsIntegrityChecks,
                 FsGlobalAccessLogMode     = System.FsGlobalAccessLogMode,
+                AudioBackend              = System.AudioBackend,
                 IgnoreMissingServices     = System.IgnoreMissingServices,
                 GuiColumns                = new GuiColumns
                 {
@@ -425,6 +432,7 @@ namespace Ryujinx.Configuration
             System.EnablePtc.Value                 = false;
             System.EnableFsIntegrityChecks.Value   = true;
             System.FsGlobalAccessLogMode.Value     = 0;
+            System.AudioBackend.Value              = AudioBackend.OpenAl;
             System.IgnoreMissingServices.Value     = false;
             Ui.GuiColumns.FavColumn.Value          = true;
             Ui.GuiColumns.IconColumn.Value         = true;
@@ -547,7 +555,8 @@ namespace Ryujinx.Configuration
                 Common.Logging.Logger.PrintWarning(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 6.");
 
                 configurationFileFormat.ControllerConfig = new List<ControllerConfig>();
-                configurationFileFormat.KeyboardConfig   = new List<KeyboardConfig>{
+                configurationFileFormat.KeyboardConfig   = new List<KeyboardConfig>
+                {
                     new KeyboardConfig
                     {
                         Index          = 0,
@@ -634,15 +643,18 @@ namespace Ryujinx.Configuration
                 configurationFileUpdated = true;
             }
 
+            if (configurationFileFormat.Version < 10)
+            {
+                Common.Logging.Logger.PrintWarning(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 10.");
+
+                configurationFileFormat.AudioBackend = AudioBackend.OpenAl;
+
+                configurationFileUpdated = true;
+            }
+
             List<InputConfig> inputConfig = new List<InputConfig>();
-            foreach (ControllerConfig controllerConfig in configurationFileFormat.ControllerConfig)
-            {
-                inputConfig.Add(controllerConfig);
-            }
-            foreach (KeyboardConfig keyboardConfig in configurationFileFormat.KeyboardConfig)
-            {
-                inputConfig.Add(keyboardConfig);
-            }
+            inputConfig.AddRange(configurationFileFormat.ControllerConfig);
+            inputConfig.AddRange(configurationFileFormat.KeyboardConfig);
 
             Graphics.MaxAnisotropy.Value           = configurationFileFormat.MaxAnisotropy;
             Graphics.ShadersDumpPath.Value         = configurationFileFormat.GraphicsShadersDumpPath;
@@ -660,13 +672,13 @@ namespace Ryujinx.Configuration
             System.TimeZone.Value                  = configurationFileFormat.SystemTimeZone;
             System.SystemTimeOffset.Value          = configurationFileFormat.SystemTimeOffset;
             System.EnableDockedMode.Value          = configurationFileFormat.DockedMode;
-            System.EnableDockedMode.Value          = configurationFileFormat.DockedMode;
             EnableDiscordIntegration.Value         = configurationFileFormat.EnableDiscordIntegration;
             Graphics.EnableVsync.Value             = configurationFileFormat.EnableVsync;
             System.EnableMulticoreScheduling.Value = configurationFileFormat.EnableMulticoreScheduling;
             System.EnablePtc.Value                 = configurationFileFormat.EnablePtc;
             System.EnableFsIntegrityChecks.Value   = configurationFileFormat.EnableFsIntegrityChecks;
             System.FsGlobalAccessLogMode.Value     = configurationFileFormat.FsGlobalAccessLogMode;
+            System.AudioBackend.Value              = configurationFileFormat.AudioBackend;
             System.IgnoreMissingServices.Value     = configurationFileFormat.IgnoreMissingServices;
             Ui.GuiColumns.FavColumn.Value          = configurationFileFormat.GuiColumns.FavColumn;
             Ui.GuiColumns.IconColumn.Value         = configurationFileFormat.GuiColumns.IconColumn;
diff --git a/Ryujinx/Config.json b/Ryujinx/Config.json
index a23df338e7..4551b869ff 100644
--- a/Ryujinx/Config.json
+++ b/Ryujinx/Config.json
@@ -1,5 +1,5 @@
 {
-  "version": 9,
+  "version": 10,
   "max_anisotropy": -1,
   "graphics_shaders_dump_path": "",
   "logging_enable_debug": false,
@@ -22,6 +22,7 @@
   "enable_ptc": false,
   "enable_fs_integrity_checks": true,
   "fs_global_access_log_mode": 0,
+  "audio_backend": "OpenAl",
   "ignore_missing_services": false,
   "gui_columns": {
     "fav_column": true,
diff --git a/Ryujinx/Ui/MainWindow.cs b/Ryujinx/Ui/MainWindow.cs
index 3bfeee5578..8fa7dba70a 100644
--- a/Ryujinx/Ui/MainWindow.cs
+++ b/Ryujinx/Ui/MainWindow.cs
@@ -647,24 +647,32 @@ namespace Ryujinx.Ui
             return new Renderer();
         }
 
-        /// <summary>
-        /// Picks an <see cref="IAalOutput"/> audio output renderer supported on this machine
-        /// </summary>
-        /// <returns>An <see cref="IAalOutput"/> supported by this machine</returns>
         private static IAalOutput InitializeAudioEngine()
         {
-            if (OpenALAudioOut.IsSupported)
+            if (ConfigurationState.Instance.System.AudioBackend.Value == AudioBackend.SoundIo)
             {
-                return new OpenALAudioOut();
+                if (SoundIoAudioOut.IsSupported)
+                {
+                    return new SoundIoAudioOut();
+                }
+                else
+                {
+                    Logger.PrintWarning(LogClass.Audio, "SoundIO is not supported, falling back to dummy audio out.");
+                }
             }
-            else if (SoundIoAudioOut.IsSupported)
+            else if (ConfigurationState.Instance.System.AudioBackend.Value == AudioBackend.OpenAl)
             {
-                return new SoundIoAudioOut();
-            }
-            else
-            {
-                return new DummyAudioOut();
+                if (OpenALAudioOut.IsSupported)
+                {
+                    return new OpenALAudioOut();
+                }
+                else
+                {
+                    Logger.PrintWarning(LogClass.Audio, "OpenAL is not supported, falling back to dummy audio out.");
+                }
             }
+
+            return new DummyAudioOut();
         }
 
         //Events
diff --git a/Ryujinx/Ui/SettingsWindow.cs b/Ryujinx/Ui/SettingsWindow.cs
index 6e681fffc6..499ed101b8 100644
--- a/Ryujinx/Ui/SettingsWindow.cs
+++ b/Ryujinx/Ui/SettingsWindow.cs
@@ -1,5 +1,7 @@
 using Gtk;
+using Ryujinx.Audio;
 using Ryujinx.Configuration;
+using Ryujinx.Common.Configuration.Hid;
 using Ryujinx.Configuration.System;
 using Ryujinx.HLE.HOS.Services.Time.TimeZone;
 using Ryujinx.HLE.FileSystem;
@@ -9,7 +11,7 @@ using System.Diagnostics;
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Ryujinx.Common.Configuration.Hid;
+
 using GUI = Gtk.Builder.ObjectAttribute;
 
 namespace Ryujinx.Ui
@@ -42,6 +44,7 @@ namespace Ryujinx.Ui
         [GUI] ComboBoxText _systemLanguageSelect;
         [GUI] ComboBoxText _systemRegionSelect;
         [GUI] ComboBoxText _systemTimeZoneSelect;
+        [GUI] ComboBoxText _audioBackendSelect;
         [GUI] SpinButton   _systemTimeYearSpin;
         [GUI] SpinButton   _systemTimeMonthSpin;
         [GUI] SpinButton   _systemTimeDaySpin;
@@ -191,8 +194,15 @@ namespace Ryujinx.Ui
                 _systemTimeZoneSelect.Append(locationName, locationName);
             }
 
+            _audioBackendSelect.Append(AudioBackend.Dummy.ToString(), AudioBackend.Dummy.ToString());
+            if (SoundIoAudioOut.IsSupported)
+                _audioBackendSelect.Append(AudioBackend.SoundIo.ToString(), "SoundIO");
+            if (OpenALAudioOut.IsSupported)
+                _audioBackendSelect.Append(AudioBackend.OpenAl.ToString(), "OpenAL");
+
             _systemLanguageSelect.SetActiveId(ConfigurationState.Instance.System.Language.Value.ToString());
             _systemRegionSelect.SetActiveId(ConfigurationState.Instance.System.Region.Value.ToString());
+            _audioBackendSelect.SetActiveId(ConfigurationState.Instance.System.AudioBackend.Value.ToString());
             _systemTimeZoneSelect.SetActiveId(timeZoneContentManager.SanityCheckDeviceLocationName());
             _anisotropy.SetActiveId(ConfigurationState.Instance.Graphics.MaxAnisotropy.Value.ToString());
 
@@ -417,6 +427,7 @@ namespace Ryujinx.Ui
             ConfigurationState.Instance.Ui.EnableCustomTheme.Value             = _custThemeToggle.Active;
             ConfigurationState.Instance.System.Language.Value                  = Enum.Parse<Language>(_systemLanguageSelect.ActiveId);
             ConfigurationState.Instance.System.Region.Value                    = Enum.Parse<Configuration.System.Region>(_systemRegionSelect.ActiveId);
+            ConfigurationState.Instance.System.AudioBackend.Value              = Enum.Parse<AudioBackend>(_audioBackendSelect.ActiveId);
             ConfigurationState.Instance.System.TimeZone.Value                  = _systemTimeZoneSelect.ActiveId;
             ConfigurationState.Instance.System.SystemTimeOffset.Value          = _systemTimeOffset;
             ConfigurationState.Instance.Ui.CustomThemePath.Value               = _custThemePath.Buffer.Text;
diff --git a/Ryujinx/Ui/SettingsWindow.glade b/Ryujinx/Ui/SettingsWindow.glade
index a0eab22feb..52171031d9 100644
--- a/Ryujinx/Ui/SettingsWindow.glade
+++ b/Ryujinx/Ui/SettingsWindow.glade
@@ -7,13 +7,41 @@
     <property name="step_increment">1</property>
     <property name="page_increment">10</property>
   </object>
+  <object class="GtkAdjustment" id="_systemTimeDaySpinAdjustment">
+    <property name="lower">1</property>
+    <property name="upper">31</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">5</property>
+  </object>
+  <object class="GtkAdjustment" id="_systemTimeHourSpinAdjustment">
+    <property name="upper">23</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">5</property>
+  </object>
+  <object class="GtkAdjustment" id="_systemTimeMinuteSpinAdjustment">
+    <property name="upper">59</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">5</property>
+  </object>
+  <object class="GtkAdjustment" id="_systemTimeMonthSpinAdjustment">
+    <property name="lower">1</property>
+    <property name="upper">12</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">5</property>
+  </object>
+  <object class="GtkAdjustment" id="_systemTimeYearSpinAdjustment">
+    <property name="lower">2000</property>
+    <property name="upper">2060</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
   <object class="GtkWindow" id="_settingsWin">
     <property name="can_focus">False</property>
     <property name="title" translatable="yes">Ryujinx - Settings</property>
     <property name="modal">True</property>
     <property name="window_position">center</property>
     <property name="default_width">650</property>
-    <property name="default_height">520</property>
+    <property name="default_height">550</property>
     <child>
       <placeholder/>
     </child>
@@ -1441,6 +1469,46 @@
                                 <property name="position">1</property>
                               </packing>
                             </child>
+                            <child>
+                              <object class="GtkBox" id="AudioBackendBox">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <child>
+                                  <object class="GtkLabel">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="tooltip_text" translatable="yes">Change System Region</property>
+                                    <property name="halign">end</property>
+                                    <property name="label" translatable="yes">Audio Backend: </property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">True</property>
+                                    <property name="padding">5</property>
+                                    <property name="position">2</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkComboBoxText" id="_audioBackendSelect">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="tooltip_text" translatable="yes">Change Audio Backend</property>
+                                    <property name="margin_left">5</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">3</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="padding">5</property>
+                                <property name="position">2</property>
+                              </packing>
+                            </child>
                           </object>
                           <packing>
                             <property name="expand">False</property>
@@ -2121,32 +2189,4 @@
       </object>
     </child>
   </object>
-  <object class="GtkAdjustment" id="_systemTimeDaySpinAdjustment">
-    <property name="lower">1</property>
-    <property name="upper">31</property>
-    <property name="step_increment">1</property>
-    <property name="page_increment">5</property>
-  </object>
-  <object class="GtkAdjustment" id="_systemTimeHourSpinAdjustment">
-    <property name="upper">23</property>
-    <property name="step_increment">1</property>
-    <property name="page_increment">5</property>
-  </object>
-  <object class="GtkAdjustment" id="_systemTimeMinuteSpinAdjustment">
-    <property name="upper">59</property>
-    <property name="step_increment">1</property>
-    <property name="page_increment">5</property>
-  </object>
-  <object class="GtkAdjustment" id="_systemTimeMonthSpinAdjustment">
-    <property name="lower">1</property>
-    <property name="upper">12</property>
-    <property name="step_increment">1</property>
-    <property name="page_increment">5</property>
-  </object>
-  <object class="GtkAdjustment" id="_systemTimeYearSpinAdjustment">
-    <property name="lower">2000</property>
-    <property name="upper">2060</property>
-    <property name="step_increment">1</property>
-    <property name="page_increment">10</property>
-  </object>
 </interface>
diff --git a/Ryujinx/_schema.json b/Ryujinx/_schema.json
index 6d57b7887b..e53b49cb0d 100644
--- a/Ryujinx/_schema.json
+++ b/Ryujinx/_schema.json
@@ -1003,6 +1003,18 @@
         3
       ]
     },
+    "audio_backend": {
+      "$id": "#/properties/audio_backend",
+      "type": "string",
+      "title": "The selected audio backend",
+      "description": "The selected audio backend",
+      "default": "OpenAl",
+      "enum": [
+        "Dummy",
+        "SoundIo",
+        "OpenAl"
+      ]
+    },
     "ignore_missing_services": {
       "$id": "#/properties/ignore_missing_services",
       "type": "boolean",