diff --git a/WinAudioAssistant/App.xaml.cs b/WinAudioAssistant/App.xaml.cs index 9ef0c68..c221eb7 100644 --- a/WinAudioAssistant/App.xaml.cs +++ b/WinAudioAssistant/App.xaml.cs @@ -2,6 +2,7 @@ using System.Data; using System.Windows; using WinAudioAssistant.Models; +using AudioSwitcher.AudioApi.CoreAudio; namespace WinAudioAssistant { @@ -10,6 +11,7 @@ namespace WinAudioAssistant /// public partial class App : Application { + public static CoreAudioController CoreAudioController { get; private set; } = new(); public static UserSettings UserSettings { get; private set; } = new(); public static AudioEndpointManager AudioEndpointManager { get; private set; } = new(); diff --git a/WinAudioAssistant/Models/AudioEndpointInfo.cs b/WinAudioAssistant/Models/AudioEndpointInfo.cs index 44b8bb4..4c27b7a 100644 --- a/WinAudioAssistant/Models/AudioEndpointInfo.cs +++ b/WinAudioAssistant/Models/AudioEndpointInfo.cs @@ -1,10 +1,11 @@ -using NAudio.CoreAudioApi; -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; +using AudioSwitcher.AudioApi; +using AudioSwitcher.AudioApi.CoreAudio; namespace WinAudioAssistant.Models { @@ -25,7 +26,7 @@ public enum EndpointFormFactor public struct AudioEndpointInfo { - public readonly DataFlow DataFlow { get; } + public readonly DeviceType DataFlow { get; } public readonly Guid AudioEndpoint_GUID { get; } // Globally unique to this endpoint public DeviceState? DeviceState { get; private set;} public EndpointFormFactor? AudioEndpoint_FormFactor { get; private set; } // Speakers, headphones, headset, SPDIF, etc. @@ -34,15 +35,15 @@ public struct AudioEndpointInfo public string? Device_DeviceDesc { get; private set; } // The endpoint's name, which can be changed in the control panel public string? DeviceClass_IconPath { get; private set; } public string? DeviceInterface_FriendlyName { get; private set; } // Set by the driver, but may have a different value if there are duplicate devices - public string? HostDeviceDesc { get; private set; } // (Actual property name unkown) Appears to be the name of the host device. Usually same as DeviceInterface_FriendlyName. + public string? HostDeviceDesc { get; private set; } // (Actual property name unkown) Appears to be the name of the host device. Usually same as DeviceInterface_FriendlyName, but more consistent. - public readonly string ID => (DataFlow == DataFlow.Render ? "{0.0.0.00000000}.{" : "{0.0.1.00000000}.{") + AudioEndpoint_GUID.ToString() + "}"; + public readonly string ID => (DataFlow == DeviceType.Playback ? "{0.0.0.00000000}.{" : "{0.0.1.00000000}.{") + AudioEndpoint_GUID.ToString() + "}"; /// /// Use named arguments for optional parameters. The order of arguments may change in the future. /// /// Test remark. - public AudioEndpointInfo(DataFlow dataFlow, + public AudioEndpointInfo(DeviceType dataFlow, Guid audioEndpoint_GUID, EndpointFormFactor? audioEndpoint_FormFactor = null, Guid? audioEndpoint_JackSubType = null, @@ -52,7 +53,7 @@ public AudioEndpointInfo(DataFlow dataFlow, string? deviceInterface_FriendlyName = null, string? hostDeviceDesc = null) { - Trace.Assert(dataFlow != DataFlow.All, "AudioEndpointInfo created with DataFlow.All"); + Trace.Assert(dataFlow != DeviceType.All, "AudioEndpointInfo created with DeviceType.All"); DataFlow = dataFlow; AudioEndpoint_GUID = audioEndpoint_GUID; AudioEndpoint_FormFactor = audioEndpoint_FormFactor; @@ -63,18 +64,11 @@ public AudioEndpointInfo(DataFlow dataFlow, DeviceInterface_FriendlyName = deviceInterface_FriendlyName; HostDeviceDesc = hostDeviceDesc; } - public AudioEndpointInfo(MMDevice device) + public AudioEndpointInfo(CoreAudioDevice device) { - Trace.Assert(device.DataFlow != DataFlow.All, "AudioEndpointInfo created with DataFlow.All"); - DataFlow = device.DataFlow; - if (Guid.TryParse(device.Properties[propertyKeys.AudioEndpoint_GUID]?.Value as string, out var guid)) - { - AudioEndpoint_GUID = guid; - } - else - { - AudioEndpoint_GUID = Guid.Empty; - } + Trace.Assert(device.DeviceType != DeviceType.All, "AudioEndpointInfo created with DeviceType.All"); + DataFlow = device.DeviceType; + AudioEndpoint_GUID = device.Id; Debug.Assert(AudioEndpoint_GUID != Guid.Empty, "AudioEndpointInfo created with empty GUID"); UpdateFromDevice(device); } @@ -85,8 +79,8 @@ public AudioEndpointInfo(MMDevice device) /// True if a matching endpoint was found in the system. public bool UpdateFromSystem() { - var device = new MMDeviceEnumerator().GetDevice(ID); - if (device?.Properties[propertyKeys.AudioEndpoint_GUID]?.Value is Guid guid && guid == AudioEndpoint_GUID) + var device = App.CoreAudioController.GetDevice(AudioEndpoint_GUID); + if (device?.Properties[propertyKeys.AudioEndpoint_GUID] is Guid guid && guid == AudioEndpoint_GUID) { UpdateFromDevice(device); return true; @@ -97,23 +91,23 @@ public bool UpdateFromSystem() } } - public void UpdateFromDevice(MMDevice device) + public void UpdateFromDevice(CoreAudioDevice device) { DeviceState = device.State; - if (device.Properties[propertyKeys.AudioEndpoint_FormFactor]?.Value is uint formFactor) + if (device.Properties[propertyKeys.AudioEndpoint_FormFactor] is uint formFactor) AudioEndpoint_FormFactor = (EndpointFormFactor)formFactor; - if (Guid.TryParse(device.Properties[propertyKeys.AudioEndpoint_JackSubType]?.Value as string, out var jackSubType)) + if (Guid.TryParse(device.Properties[propertyKeys.AudioEndpoint_JackSubType] as string, out var jackSubType)) AudioEndpoint_JackSubType = jackSubType; - if (device.Properties[propertyKeys.Device_ContainerId]?.Value is Guid containerId && + if (device.Properties[propertyKeys.Device_ContainerId] is Guid containerId && containerId != new Guid(0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff)) Device_ContainerId = containerId; - if (device.Properties[propertyKeys.Device_DeviceDesc]?.Value is string deviceDesc) + if (device.Properties[propertyKeys.Device_DeviceDesc] is string deviceDesc) Device_DeviceDesc = deviceDesc; - if (device.Properties[propertyKeys.DeviceClass_IconPath]?.Value is string iconPath) + if (device.Properties[propertyKeys.DeviceClass_IconPath] is string iconPath) DeviceClass_IconPath = iconPath; - if (device.Properties[propertyKeys.DeviceInterface_FriendlyName]?.Value is string friendlyName) + if (device.Properties[propertyKeys.DeviceInterface_FriendlyName] is string friendlyName) DeviceInterface_FriendlyName = friendlyName; - if (device.Properties[propertyKeys.Device_DeviceDesc]?.Value is string hostDeviceDesc) + if (device.Properties[propertyKeys.Device_DeviceDesc] is string hostDeviceDesc) HostDeviceDesc = hostDeviceDesc; } diff --git a/WinAudioAssistant/Models/AudioEndpointManager.cs b/WinAudioAssistant/Models/AudioEndpointManager.cs index 907ac41..e688259 100644 --- a/WinAudioAssistant/Models/AudioEndpointManager.cs +++ b/WinAudioAssistant/Models/AudioEndpointManager.cs @@ -1,5 +1,4 @@ -using NAudio.CoreAudioApi; -using System; +using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; @@ -25,8 +24,7 @@ public AudioEndpointManager() public void UpdateCachedEndpoints() { _cachedEndpoints.Clear(); - var enumerator = new MMDeviceEnumerator(); - foreach (var device in enumerator.EnumerateAudioEndPoints(DataFlow.All, DeviceState.All)) + foreach (var device in App.CoreAudioController.GetDevices()) { _cachedEndpoints.Add(new AudioEndpointInfo(device)); } @@ -38,32 +36,36 @@ public void UpdateCachedEndpoints() public static void ListAllEndpoints() { using StreamWriter writer = new("endpoints.txt", append: false); - var enumerator = new MMDeviceEnumerator(); - foreach (var device in enumerator.EnumerateAudioEndPoints(DataFlow.All, DeviceState.All)) + foreach (var device in App.CoreAudioController.GetDevices()) { writer.WriteLine(""); writer.WriteLine("AudioEndpoint:"); - writer.WriteLine($" ID={device.ID}"); - writer.WriteLine($" DataFlow={device.DataFlow}"); + writer.WriteLine($" DeviceType={device.DeviceType}"); + writer.WriteLine($" FullName={device.FullName}"); + writer.WriteLine($" GetHashCode={device.GetHashCode()}"); + writer.WriteLine($" Icon={device.Icon}"); + writer.WriteLine($" IconPath={device.IconPath}"); + writer.WriteLine($" Id={device.Id}"); + writer.WriteLine($" InterfaceName={device.InterfaceName}"); + writer.WriteLine($" IsDefaultDevice={device.IsDefaultDevice}"); + writer.WriteLine($" IsDefaultCommunicationsDevice={device.IsDefaultCommunicationsDevice}"); + writer.WriteLine($" Name={device.Name}"); + writer.WriteLine($" RealId={device.RealId}"); writer.WriteLine($" State={device.State}"); - writer.WriteLine($" FriendlyName={device.FriendlyName}"); - writer.WriteLine($" DeviceFriendlyName={device.DeviceFriendlyName}"); - writer.WriteLine($" InstanceID={device.InstanceId}"); - writer.WriteLine($" DeviceTopology.DeviceId={device.DeviceTopology.DeviceId}"); - writer.WriteLine($" DeviceTopology.ConnectorCount={device.DeviceTopology.ConnectorCount}"); + writer.WriteLine(" Properties:"); - for (int i = 0; i < device.Properties.Count; i++) + foreach (var property in device.Properties) { - var formatId = device.Properties[i].Key.formatId; - var propertyId = device.Properties[i].Key.propertyId; + var formatId = property.Key.FormatId; + var propertyId = property.Key.PropertyId; string valueType; string? value; var propertyKeyDef = PropertyKeyDefLookup.Lookup(formatId, propertyId); try { - valueType = device.Properties[i].Value.GetType().ToString(); - value = device.Properties[i].Value.ToString(); + valueType = property.Value.GetType().ToString(); + value = property.Value.ToString(); } catch (NotImplementedException) { diff --git a/WinAudioAssistant/Models/ManagedDevice.cs b/WinAudioAssistant/Models/ManagedDevice.cs index 979e753..fe475ff 100644 --- a/WinAudioAssistant/Models/ManagedDevice.cs +++ b/WinAudioAssistant/Models/ManagedDevice.cs @@ -1,10 +1,10 @@ -using NAudio.CoreAudioApi; -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; +using AudioSwitcher.AudioApi; namespace WinAudioAssistant.Models { @@ -13,7 +13,7 @@ public abstract class ManagedDevice public string Name { get; set; } = ""; public AudioEndpointInfo EndpointInfo { get; protected set; } - public abstract DataFlow DataFlow(); + public abstract DeviceType DataFlow(); public abstract void SetEndpoint(AudioEndpointInfo endpointInfo); } @@ -25,7 +25,7 @@ public ManagedInputDevice(AudioEndpointInfo endpointInfo) EndpointInfo = endpointInfo; } - public override DataFlow DataFlow() => NAudio.CoreAudioApi.DataFlow.Capture; + public override DeviceType DataFlow() => DeviceType.Capture; public override void SetEndpoint(AudioEndpointInfo endpointInfo) { @@ -42,7 +42,7 @@ public ManagedOutputDevice(AudioEndpointInfo endpointInfo) EndpointInfo = endpointInfo; } - public override DataFlow DataFlow() => NAudio.CoreAudioApi.DataFlow.Render; + public override DeviceType DataFlow() => DeviceType.Playback; public override void SetEndpoint(AudioEndpointInfo endpointInfo) { diff --git a/WinAudioAssistant/ViewModels/DevicePriorityViewModel.cs b/WinAudioAssistant/ViewModels/DevicePriorityViewModel.cs index b29d3bb..cf3fdb8 100644 --- a/WinAudioAssistant/ViewModels/DevicePriorityViewModel.cs +++ b/WinAudioAssistant/ViewModels/DevicePriorityViewModel.cs @@ -1,7 +1,4 @@ -using GongSolutions.Wpf.DragDrop; -using Microsoft.VisualBasic; -using NAudio.CoreAudioApi; -using System; +using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; @@ -10,6 +7,8 @@ using System.Text; using System.Threading.Tasks; using System.Windows.Controls; +using GongSolutions.Wpf.DragDrop; +using AudioSwitcher.AudioApi; using WinAudioAssistant.Models; using WinAudioAssistant.Views; @@ -18,7 +17,7 @@ namespace WinAudioAssistant.ViewModels // Assigned to each ListBox in the view code-behind public struct ListBoxTag { - public DataFlow DataFlow; + public DeviceType DataFlow; public bool IsComms; } diff --git a/WinAudioAssistant/ViewModels/EditDeviceViewModel.cs b/WinAudioAssistant/ViewModels/EditDeviceViewModel.cs index 686754a..6faba85 100644 --- a/WinAudioAssistant/ViewModels/EditDeviceViewModel.cs +++ b/WinAudioAssistant/ViewModels/EditDeviceViewModel.cs @@ -1,5 +1,4 @@ -using NAudio.CoreAudioApi; -using System; +using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; @@ -8,6 +7,7 @@ using System.Text; using System.Threading.Tasks; using System.Windows; +using AudioSwitcher.AudioApi; using WinAudioAssistant.Models; namespace WinAudioAssistant.ViewModels @@ -24,7 +24,7 @@ protected virtual void OnPropertyChanged(string propertyName) private bool _initialized = false; private ManagedDevice? _managedDevice; // Original managed device reference. Null if creating a new one public ManagedDevice? ManagedDevice { get => _managedDevice;} - public DataFlow DataFlow { get; private set; } + public DeviceType DataFlow { get; private set; } public bool IsComms { get; private set; } = false; // Managed device properties, stored here until changes are applied @@ -111,7 +111,7 @@ public void Initialize(ManagedDevice device, bool isComms) _managedDevice = device; DataFlow = device.DataFlow(); IsComms = isComms; - WindowTitle = "Edit " + (DataFlow == DataFlow.Capture ? "Input" : "Output") + (isComms ? "Comms " : "") + " Managed Device"; + WindowTitle = "Edit " + (DataFlow == DeviceType.Capture ? "Input" : "Output") + (isComms ? "Comms " : "") + " Managed Device"; ManagedDeviceName = device.Name; ManagedDeviceEndpoint = device.EndpointInfo; @@ -121,14 +121,14 @@ public void Initialize(ManagedDevice device, bool isComms) OnPropertyChanged(string.Empty); // Refreshes all properties } - public void Initialize(DataFlow dataFlow, bool isComms) + public void Initialize(DeviceType dataFlow, bool isComms) { //Creating a new managed device Debug.Assert(!_initialized); if (_initialized) return; DataFlow = dataFlow; IsComms = isComms; - WindowTitle = "New " + (DataFlow == DataFlow.Capture ? "Input" : "Output") + (isComms ? "Comms " : "") + " Managed Device"; + WindowTitle = "New " + (DataFlow == DeviceType.Capture ? "Input" : "Output") + (isComms ? "Comms " : "") + " Managed Device"; _initialized = true; UpdateFilteredEndpoints(); @@ -185,8 +185,8 @@ public bool Apply() // Creating a new managed device _managedDevice = DataFlow switch { - DataFlow.Capture => new ManagedInputDevice(ManagedDeviceEndpoint.Value), - DataFlow.Render => new ManagedOutputDevice(ManagedDeviceEndpoint.Value), + DeviceType.Capture => new ManagedInputDevice(ManagedDeviceEndpoint.Value), + DeviceType.Playback => new ManagedOutputDevice(ManagedDeviceEndpoint.Value), _ => throw new NotImplementedException() }; _managedDevice.Name = ManagedDeviceName; diff --git a/WinAudioAssistant/Views/DevicePriorityView.xaml.cs b/WinAudioAssistant/Views/DevicePriorityView.xaml.cs index 0b5f2a9..7ed1a07 100644 --- a/WinAudioAssistant/Views/DevicePriorityView.xaml.cs +++ b/WinAudioAssistant/Views/DevicePriorityView.xaml.cs @@ -1,5 +1,4 @@ -using NAudio.CoreAudioApi; -using System.Text; +using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; @@ -9,6 +8,7 @@ using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; +using AudioSwitcher.AudioApi; using WinAudioAssistant.Models; using WinAudioAssistant.ViewModels; @@ -23,10 +23,10 @@ public partial class DevicePriorityView : Window public DevicePriorityView() { InitializeComponent(); - OutputPriorityListBox.Tag = new ListBoxTag { DataFlow = DataFlow.Render, IsComms = false }; - CommsOutputPriorityListBox.Tag = new ListBoxTag { DataFlow = DataFlow.Render, IsComms = true }; - InputPriorityListBox.Tag = new ListBoxTag { DataFlow = DataFlow.Capture, IsComms = false }; - CommsInputPriorityListBox.Tag = new ListBoxTag { DataFlow = DataFlow.Capture, IsComms = true }; + OutputPriorityListBox.Tag = new ListBoxTag { DataFlow = DeviceType.Playback, IsComms = false }; + CommsOutputPriorityListBox.Tag = new ListBoxTag { DataFlow = DeviceType.Playback, IsComms = true }; + InputPriorityListBox.Tag = new ListBoxTag { DataFlow = DeviceType.Capture, IsComms = false }; + CommsInputPriorityListBox.Tag = new ListBoxTag { DataFlow = DeviceType.Capture, IsComms = true }; } diff --git a/WinAudioAssistant/WinAudioAssistant.csproj b/WinAudioAssistant/WinAudioAssistant.csproj index 18b6413..1222adc 100644 --- a/WinAudioAssistant/WinAudioAssistant.csproj +++ b/WinAudioAssistant/WinAudioAssistant.csproj @@ -10,7 +10,26 @@ - + + + + .\Libs\Debug\AudioSwitcher.AudioApi.dll + + + + + .\Libs\Release\AudioSwitcher.AudioApi.dll + + + + + .\Libs\Debug\AudioSwitcher.AudioApi.CoreAudio.dll + + + + + .\Libs\Release\AudioSwitcher.AudioApi.CoreAudio.dll +