From af016d2b224b179a20c9b4bc64289cc5e2efaecd Mon Sep 17 00:00:00 2001 From: Adam Frisby Date: Wed, 24 Jul 2019 14:24:54 -0400 Subject: [PATCH 1/2] Add basic Core Audio API DeviceTopology/Connector support --- NAudio/CoreAudioApi/Connector.cs | 105 ++++++++++++++++++ NAudio/CoreAudioApi/ConnectorType.cs | 34 ++++++ NAudio/CoreAudioApi/DeviceTopology.cs | 54 +++++++++ NAudio/CoreAudioApi/Interfaces/IConnector.cs | 26 +++++ .../Interfaces/IDeviceTopology.cs | 25 +++++ NAudio/CoreAudioApi/Interfaces/IPart.cs | 19 ++++ NAudio/CoreAudioApi/Interfaces/IPartsList.cs | 20 ++++ NAudio/CoreAudioApi/Interfaces/ISubunit.cs | 15 +++ NAudio/CoreAudioApi/MMDevice.cs | 44 ++++++++ NAudio/CoreAudioApi/PropertyKeys.cs | 4 + 10 files changed, 346 insertions(+) create mode 100644 NAudio/CoreAudioApi/Connector.cs create mode 100644 NAudio/CoreAudioApi/ConnectorType.cs create mode 100644 NAudio/CoreAudioApi/DeviceTopology.cs create mode 100644 NAudio/CoreAudioApi/Interfaces/IConnector.cs create mode 100644 NAudio/CoreAudioApi/Interfaces/IDeviceTopology.cs create mode 100644 NAudio/CoreAudioApi/Interfaces/IPart.cs create mode 100644 NAudio/CoreAudioApi/Interfaces/IPartsList.cs create mode 100644 NAudio/CoreAudioApi/Interfaces/ISubunit.cs diff --git a/NAudio/CoreAudioApi/Connector.cs b/NAudio/CoreAudioApi/Connector.cs new file mode 100644 index 00000000..b2da26ac --- /dev/null +++ b/NAudio/CoreAudioApi/Connector.cs @@ -0,0 +1,105 @@ +using NAudio.CoreAudioApi.Interfaces; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NAudio.CoreAudioApi +{ + public class Connector + { + private readonly IConnector connectorInterface; + + internal Connector(IConnector connector) + { + connectorInterface = connector; + } + + /// + /// Connects this connector to a connector in another device-topology object + /// + public void ConnectTo(Connector other) + { + connectorInterface.ConnectTo(other.connectorInterface); + } + + /// + /// Retreives the type of this connector + /// + public ConnectorType Type + { + get + { + connectorInterface.GetType(out var result); + return result; + } + } + + /// + /// Retreives the data flow of this connector + /// + public DataFlow DataFlow + { + get + { + connectorInterface.GetDataFlow(out var result); + return result; + } + } + + /// + /// Disconnects this connector from it's connected connector (if connected) + /// + public void Disconnect() + { + connectorInterface.Disconnect(); + } + + /// + /// Indicates whether this connector is connected to another connector + /// + public bool IsConnected + { + get + { + connectorInterface.IsConnected(out var result); + return result; + } + } + + /// + /// Retreives the connector this connector is connected to (if connected) + /// + public Connector ConnectedTo + { + get + { + connectorInterface.GetConnectedTo(out var result); + return new Connector(result); + } + } + + /// + /// Retreives the global ID of the connector this connector is connected to (if connected) + /// + public string ConnectedToConnectorId + { + get + { + connectorInterface.GetConnectorIdConnectedTo(out var result); + return result; + } + } + + /// + /// Retreives the device ID of the audio device this connector is connected to (if connected) + /// + public string ConnectedToDeviceId + { + get + { + connectorInterface.GetDeviceIdConnectedTo(out var result); + return result; + } + } + } +} diff --git a/NAudio/CoreAudioApi/ConnectorType.cs b/NAudio/CoreAudioApi/ConnectorType.cs new file mode 100644 index 00000000..f01f4228 --- /dev/null +++ b/NAudio/CoreAudioApi/ConnectorType.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NAudio.CoreAudioApi +{ + public enum ConnectorType + { + /// + /// The connector is part of a connection of unknown type. + /// + UnknownConnector, + /// + /// The connector is part of a physical connection to an auxiliary device that is installed inside the system chassis + /// + PhysicalInternal, + /// + /// The connector is part of a physical connection to an external device. + /// + PhysicalExternal, + /// + /// The connector is part of a software-configured I/O connection (typically a DMA channel) between system memory and an audio hardware device on an audio adapter. + /// + SoftwareIo, + /// + /// The connector is part of a permanent connection that is fixed and cannot be configured under software control. + /// + SoftwareFixed, + /// + /// The connector is part of a connection to a network. + /// + Network, + } +} diff --git a/NAudio/CoreAudioApi/DeviceTopology.cs b/NAudio/CoreAudioApi/DeviceTopology.cs new file mode 100644 index 00000000..f2be34a6 --- /dev/null +++ b/NAudio/CoreAudioApi/DeviceTopology.cs @@ -0,0 +1,54 @@ +using NAudio.CoreAudioApi.Interfaces; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NAudio.CoreAudioApi +{ + /// + /// Windows CoreAudio DeviceTopology + /// + public class DeviceTopology + { + private readonly IDeviceTopology deviceTopologyInterface; + + internal DeviceTopology(IDeviceTopology deviceTopology) + { + deviceTopologyInterface = deviceTopology; + } + + /// + /// Retrieves the number of connections associated with this device-topology object + /// + public uint ConnectorCount + { + get + { + deviceTopologyInterface.GetConnectorCount(out var count); + return count; + } + } + + /// + /// Retrieves the connector at the supplied index + /// + public Connector GetConnector(uint index) + { + deviceTopologyInterface.GetConnector(index, out var connectorInterface); + return new Connector(connectorInterface); + } + + /// + /// Retrieves the device id of the device represented by this device-topology object + /// + public string DeviceId + { + get + { + deviceTopologyInterface.GetDeviceId(out var result); + return result; + } + } + + } +} diff --git a/NAudio/CoreAudioApi/Interfaces/IConnector.cs b/NAudio/CoreAudioApi/Interfaces/IConnector.cs new file mode 100644 index 00000000..0e26da7e --- /dev/null +++ b/NAudio/CoreAudioApi/Interfaces/IConnector.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; + +namespace NAudio.CoreAudioApi.Interfaces +{ + /// + /// Windows CoreAudio IConnector interface + /// Defined in devicetopology.h + /// + [Guid("9C2C4058-23F5-41DE-877A-DF3AF236A09E"), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + ComImport] + internal interface IConnector + { + int GetType(out ConnectorType type); + int GetDataFlow(out DataFlow flow); + int ConnectTo([In] IConnector connectTo); + int Disconnect(); + int IsConnected(out bool connected); + int GetConnectedTo(out IConnector conTo); + int GetConnectorIdConnectedTo([MarshalAs(UnmanagedType.LPWStr)] out string id); + int GetDeviceIdConnectedTo([MarshalAs(UnmanagedType.LPWStr)] out string id); + } +} diff --git a/NAudio/CoreAudioApi/Interfaces/IDeviceTopology.cs b/NAudio/CoreAudioApi/Interfaces/IDeviceTopology.cs new file mode 100644 index 00000000..bd378109 --- /dev/null +++ b/NAudio/CoreAudioApi/Interfaces/IDeviceTopology.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; + +namespace NAudio.CoreAudioApi.Interfaces +{ + /// + /// Windows CoreAudio IDeviceTopology interface + /// Defined in devicetopology.h + /// + [Guid("2A07407E-6497-4A18-9787-32F79BD0D98F"), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + ComImport] + internal interface IDeviceTopology + { + int GetConnectorCount(out uint count); + int GetConnector(uint index, out IConnector connector); + int GetSubunitCount(out uint count); + int GetSubunit(uint index, out ISubunit subunit); + int GetPartById(uint id, out IPart part); + int GetDeviceId([MarshalAs(UnmanagedType.LPWStr)] out string id); + int GetSignalPath(IPart from, IPart to, bool rejectMixedPaths, out IPartsList parts); + } +} diff --git a/NAudio/CoreAudioApi/Interfaces/IPart.cs b/NAudio/CoreAudioApi/Interfaces/IPart.cs new file mode 100644 index 00000000..02b1662b --- /dev/null +++ b/NAudio/CoreAudioApi/Interfaces/IPart.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; + +namespace NAudio.CoreAudioApi.Interfaces +{ + /// + /// Windows CoreAudio IPart interface + /// Defined in devicetopology.h + /// + [Guid("AE2DE0E4-5BCA-4F2D-AA46-5D13F8FDB3A9"), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + ComImport] + internal interface IPart + { + // Stub, Not implemented + } +} diff --git a/NAudio/CoreAudioApi/Interfaces/IPartsList.cs b/NAudio/CoreAudioApi/Interfaces/IPartsList.cs new file mode 100644 index 00000000..dcf31efd --- /dev/null +++ b/NAudio/CoreAudioApi/Interfaces/IPartsList.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; + +namespace NAudio.CoreAudioApi.Interfaces +{ + /// + /// Windows CoreAudio IPartsList interface + /// Defined in devicetopology.h + /// + [Guid("6DAA848C-5EB0-45CC-AEA5-998A2CDA1FFB"), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + ComImport] + internal interface IPartsList + { + int GetCount(out uint count); + int GetPart(uint index, out IPart part); + } +} diff --git a/NAudio/CoreAudioApi/Interfaces/ISubunit.cs b/NAudio/CoreAudioApi/Interfaces/ISubunit.cs new file mode 100644 index 00000000..57c09b21 --- /dev/null +++ b/NAudio/CoreAudioApi/Interfaces/ISubunit.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; + +namespace NAudio.CoreAudioApi.Interfaces +{ + [Guid("82149A85-DBA6-4487-86BB-EA8F7FEFCC71"), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + ComImport] + internal interface ISubunit + { + // Stub, Not Implemented + } +} diff --git a/NAudio/CoreAudioApi/MMDevice.cs b/NAudio/CoreAudioApi/MMDevice.cs index b7e5a450..55b0d51d 100644 --- a/NAudio/CoreAudioApi/MMDevice.cs +++ b/NAudio/CoreAudioApi/MMDevice.cs @@ -39,6 +39,7 @@ public class MMDevice : IDisposable private AudioMeterInformation audioMeterInformation; private AudioEndpointVolume audioEndpointVolume; private AudioSessionManager audioSessionManager; + private DeviceTopology deviceTopology; #endregion #region Guids @@ -47,6 +48,7 @@ public class MMDevice : IDisposable private static Guid IID_IAudioEndpointVolume = new Guid("5CDF2C82-841E-4546-9722-0CF74078229A"); private static Guid IID_IAudioClient = new Guid("1CB9AD4C-DBFA-4c32-B178-C2F568A703B2"); private static Guid IDD_IAudioSessionManager = new Guid("BFA971F1-4D5E-40BB-935E-967039BFBEE4"); + private static Guid IDD_IDeviceTopology = new Guid("2A07407E-6497-4A18-9787-32F79BD0D98F"); // ReSharper restore InconsistentNaming #endregion @@ -85,6 +87,13 @@ private void GetAudioSessionManager() Marshal.ThrowExceptionForHR(deviceInterface.Activate(ref IDD_IAudioSessionManager, ClsCtx.ALL, IntPtr.Zero, out var result)); audioSessionManager = new AudioSessionManager(result as IAudioSessionManager); } + + private void GetDeviceTopology() + { + Marshal.ThrowExceptionForHR(deviceInterface.Activate(ref IDD_IDeviceTopology, ClsCtx.ALL, IntPtr.Zero, out var result)); + deviceTopology = new DeviceTopology(result as IDeviceTopology); + } + #endregion #region Properties @@ -139,6 +148,21 @@ public AudioSessionManager AudioSessionManager } } + /// + /// DeviceTopology instance + /// + public DeviceTopology DeviceTopology + { + get + { + if (deviceTopology == null) + { + GetDeviceTopology(); + } + return deviceTopology; + } + } + /// /// Properties /// @@ -214,6 +238,26 @@ public string IconPath } } + /// + /// Device Instance Id of Device + /// + public string InstanceId + { + get + { + if (propertyStore == null) + { + GetPropertyInformation(); + } + if (propertyStore.Contains(PropertyKeys.PKEY_Device_InstanceId)) + { + return (string)propertyStore[PropertyKeys.PKEY_Device_InstanceId].Value; + } + + return "Unknown"; + } + } + /// /// Device ID /// diff --git a/NAudio/CoreAudioApi/PropertyKeys.cs b/NAudio/CoreAudioApi/PropertyKeys.cs index 167fd9f0..25b40daf 100644 --- a/NAudio/CoreAudioApi/PropertyKeys.cs +++ b/NAudio/CoreAudioApi/PropertyKeys.cs @@ -97,5 +97,9 @@ public static class PropertyKeys /// Device interface key property. /// public static readonly PropertyKey PKEY_Device_InterfaceKey = new PropertyKey(new Guid(unchecked((int)0x233164c8), unchecked((short)0x1b2c), 0x4c7d, 0xbc, 0x68, 0xb6, 0x71, 0x68, 0x7a, 0x25, 0x67), 1); + /// + /// System-supplied device instance identification string, assigned by PnP manager, persistent across system restarts. + /// + public static readonly PropertyKey PKEY_Device_InstanceId = new PropertyKey(new Guid(0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57), 256); } } From 70f7f0a0fdf37f20f05cee9eb8805c16ea85ca97 Mon Sep 17 00:00:00 2001 From: Mark Heath Date: Tue, 6 Aug 2019 20:07:39 +0100 Subject: [PATCH 2/2] fix some compiler warnings --- NAudio/CoreAudioApi/Connector.cs | 6 +++--- NAudio/CoreAudioApi/ConnectorType.cs | 9 ++++----- NAudio/FileFormats/SoundFont/SampleHeader.cs | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/NAudio/CoreAudioApi/Connector.cs b/NAudio/CoreAudioApi/Connector.cs index b2da26ac..1dea0938 100644 --- a/NAudio/CoreAudioApi/Connector.cs +++ b/NAudio/CoreAudioApi/Connector.cs @@ -1,10 +1,10 @@ using NAudio.CoreAudioApi.Interfaces; -using System; -using System.Collections.Generic; -using System.Text; namespace NAudio.CoreAudioApi { + /// + /// Connector + /// public class Connector { private readonly IConnector connectorInterface; diff --git a/NAudio/CoreAudioApi/ConnectorType.cs b/NAudio/CoreAudioApi/ConnectorType.cs index f01f4228..7e5a80cb 100644 --- a/NAudio/CoreAudioApi/ConnectorType.cs +++ b/NAudio/CoreAudioApi/ConnectorType.cs @@ -1,9 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace NAudio.CoreAudioApi +namespace NAudio.CoreAudioApi { + /// + /// Connector Type + /// public enum ConnectorType { /// diff --git a/NAudio/FileFormats/SoundFont/SampleHeader.cs b/NAudio/FileFormats/SoundFont/SampleHeader.cs index 327c2766..68f02fbc 100644 --- a/NAudio/FileFormats/SoundFont/SampleHeader.cs +++ b/NAudio/FileFormats/SoundFont/SampleHeader.cs @@ -47,7 +47,7 @@ public class SampleHeader public SFSampleLink SFSampleLink; /// - /// + /// /// public override string ToString() => SampleName;