Skip to content

Commit

Permalink
Migrate from NAudio.CoreAudioApi to AudioSwitcher.AudioApi.CoreAudio.…
Browse files Browse the repository at this point in the history
… Requires modified library until xenolightning/AudioSwitcher#70 is merged.
  • Loading branch information
Sypwn committed Nov 26, 2023
1 parent 136e288 commit dc7c1ad
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 71 deletions.
2 changes: 2 additions & 0 deletions WinAudioAssistant/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Data;
using System.Windows;
using WinAudioAssistant.Models;
using AudioSwitcher.AudioApi.CoreAudio;

namespace WinAudioAssistant
{
Expand All @@ -10,6 +11,7 @@ namespace WinAudioAssistant
/// </summary>
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();

Expand Down
50 changes: 22 additions & 28 deletions WinAudioAssistant/Models/AudioEndpointInfo.cs
Original file line number Diff line number Diff line change
@@ -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
{
Expand All @@ -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.
Expand All @@ -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() + "}";

/// <summary>
/// Use named arguments for optional parameters. The order of arguments may change in the future.
/// </summary>
/// <remarks>Test remark.</remarks>
public AudioEndpointInfo(DataFlow dataFlow,
public AudioEndpointInfo(DeviceType dataFlow,
Guid audioEndpoint_GUID,
EndpointFormFactor? audioEndpoint_FormFactor = null,
Guid? audioEndpoint_JackSubType = null,
Expand All @@ -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;
Expand All @@ -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);
}
Expand All @@ -85,8 +79,8 @@ public AudioEndpointInfo(MMDevice device)
/// <returns>True if a matching endpoint was found in the system.</returns>
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;
Expand All @@ -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;
}

Expand Down
38 changes: 20 additions & 18 deletions WinAudioAssistant/Models/AudioEndpointManager.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using NAudio.CoreAudioApi;
using System;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
Expand All @@ -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));
}
Expand All @@ -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)
{
Expand Down
10 changes: 5 additions & 5 deletions WinAudioAssistant/Models/ManagedDevice.cs
Original file line number Diff line number Diff line change
@@ -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
{
Expand All @@ -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);
}

Expand All @@ -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)
{
Expand All @@ -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)
{
Expand Down
9 changes: 4 additions & 5 deletions WinAudioAssistant/ViewModels/DevicePriorityViewModel.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;

Expand All @@ -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;
}

Expand Down
16 changes: 8 additions & 8 deletions WinAudioAssistant/ViewModels/EditDeviceViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using NAudio.CoreAudioApi;
using System;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
Expand All @@ -8,6 +7,7 @@
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using AudioSwitcher.AudioApi;
using WinAudioAssistant.Models;

namespace WinAudioAssistant.ViewModels
Expand All @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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();
Expand Down Expand Up @@ -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;
Expand Down
12 changes: 6 additions & 6 deletions WinAudioAssistant/Views/DevicePriorityView.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using NAudio.CoreAudioApi;
using System.Text;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
Expand All @@ -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;

Expand All @@ -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 };

}

Expand Down
21 changes: 20 additions & 1 deletion WinAudioAssistant/WinAudioAssistant.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,26 @@

<ItemGroup>
<PackageReference Include="gong-wpf-dragdrop" Version="3.2.1" />
<PackageReference Include="NAudio.Wasapi" Version="2.2.1" />
</ItemGroup>
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<Reference Include="AudioSwitcher.AudioApi">
<HintPath>.\Libs\Debug\AudioSwitcher.AudioApi.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Condition=" '$(Configuration)' == 'Release' ">
<Reference Include="AudioSwitcher.AudioApi">
<HintPath>.\Libs\Release\AudioSwitcher.AudioApi.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<Reference Include="AudioSwitcher.AudioApi.CoreAudio">
<HintPath>.\Libs\Debug\AudioSwitcher.AudioApi.CoreAudio.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Condition=" '$(Configuration)' == 'Release' ">
<Reference Include="AudioSwitcher.AudioApi.CoreAudio">
<HintPath>.\Libs\Release\AudioSwitcher.AudioApi.CoreAudio.dll</HintPath>
</Reference>
</ItemGroup>

</Project>

0 comments on commit dc7c1ad

Please sign in to comment.