Vanara/PInvoke/CoreAudio/AudioEngineBaseApo.cs

804 lines
44 KiB
C#

using System;
using System.Runtime.InteropServices;
using Vanara.InteropServices;
using static Vanara.PInvoke.PropSys;
using IAudioMediaType = System.IntPtr; // TODO: Replace IAudioMediaType with reference to new library when done.
namespace Vanara.PInvoke
{
/// <summary>Functions, structures and constants from Windows Core Audio Api.</summary>
public static partial class CoreAudio
{
/// <summary>
/// <para>
/// The <c>APO_CONNECTION_BUFFER_TYPE</c> enumeration defines constants that indicate whether the audio engine allocates the
/// connection buffer or uses the buffer that is provided by the APO. These flags are used by the <c>Type</c> member of the
/// <c>APO_CONNECTION_DESCRIPTOR</c> structure that stores the configuration settings of an APO connection. These settings are
/// required by the audio engine when an APO connection is created.
/// </para>
/// </summary>
/// <remarks>The Terminal Services AudioEndpoint API is for use in Remote Desktop scenarios; it is not for client applications.</remarks>
// https://docs.microsoft.com/en-us/previous-versions/dd408130(v=vs.85) typedef enum { APO_CONNECTION_BUFFER_TYPE_ALLOCATED = 0,
// APO_CONNECTION_BUFFER_TYPE_EXTERNAL = 1, APO_CONNECTION_BUFFER_TYPE_DEPENDANT = 2 } APO_CONNECTION_BUFFER_TYPE;
[PInvokeData("Audioenginebaseapo.h")]
public enum APO_CONNECTION_BUFFER_TYPE
{
/// <summary>The connection buffer is internally allocated by the audio engine.</summary>
APO_CONNECTION_BUFFER_TYPE_ALLOCATED = 0,
/// <summary>
/// The connection buffer is allocated by the APO, and the audio engine must use the connection buffer that is specified in the
/// pBuffer member of the APO_CONNECTION_DESCRIPTOR structure.
/// </summary>
APO_CONNECTION_BUFFER_TYPE_EXTERNAL = 1,
/// <summary>The connection buffer is extracted by the audio engine from another connection.</summary>
APO_CONNECTION_BUFFER_TYPE_DEPENDANT = 2,
}
/// <summary>
/// <para>The APO_FLAG enumeration defines constants that are used as flags by an audio processing object (APO).</para>
/// <para>This enumeration is used by the APO_REG_PROPERTIES structure to help describe the registration properties of an APO.</para>
/// </summary>
// https://docs.microsoft.com/en-us/windows/win32/api/audioenginebaseapo/ne-audioenginebaseapo-apo_flag typedef enum APO_FLAG {
// APO_FLAG_NONE, APO_FLAG_INPLACE, APO_FLAG_SAMPLESPERFRAME_MUST_MATCH, APO_FLAG_FRAMESPERSECOND_MUST_MATCH,
// APO_FLAG_BITSPERSAMPLE_MUST_MATCH, APO_FLAG_MIXER, APO_FLAG_DEFAULT } ;
[PInvokeData("audioenginebaseapo.h", MSDNShortId = "42134625-A351-4CB6-B83C-3F2E662D1938")]
[Flags]
public enum APO_FLAG
{
/// <summary>Indicates that there are no flags enabled for this APO.</summary>
APO_FLAG_NONE = 0x00,
/// <summary>
/// Indicates that this APO can perform in-place processing. This allows the processor to use a common buffer for input and output.
/// </summary>
APO_FLAG_INPLACE = 0x01,
/// <summary>Indicates that the samples per frame for the input and output connections must match.</summary>
APO_FLAG_SAMPLESPERFRAME_MUST_MATCH = 0x02,
/// <summary>Indicates that the frames per second for the input and output connections must match.</summary>
APO_FLAG_FRAMESPERSECOND_MUST_MATCH = 0x04,
/// <summary>Indicates that bits per sample AND bytes per sample container for the input and output connections must match.</summary>
APO_FLAG_BITSPERSAMPLE_MUST_MATCH = 0x08,
/// <summary/>
APO_FLAG_MIXER = 0x10,
/// <summary>
/// The value of this member is determined by the logical OR result of the three preceding members. In other
/// words:APO_FLAG_DEFAULT = ( APO_FLAG_SAMPLESPERFRAME_MUST_MATCH
/// </summary>
APO_FLAG_DEFAULT = APO_FLAG_SAMPLESPERFRAME_MUST_MATCH | APO_FLAG_FRAMESPERSECOND_MUST_MATCH | APO_FLAG_BITSPERSAMPLE_MUST_MATCH,
}
/// <summary>
/// <para>
/// System Effects Audio Processing Objects (sAPOs) are typically used in or called from real-time process threads. However, it is
/// sometimes necessary to use an sAPO in a non real-time mode. For example, when an sAPO is initialized, it is called from a non
/// real-time thread. But when audio processing begins, the sAPO is called from a real-time thread. The interface exposes methods
/// that enable a client to access the non real-time compliant parts of an sAPO.
/// </para>
/// <para>The interface supports the following methods:</para>
/// </summary>
// https://docs.microsoft.com/en-us/windows/win32/api/audioenginebaseapo/nn-audioenginebaseapo-iaudioprocessingobject
[PInvokeData("audioenginebaseapo.h", MSDNShortId = "71be0151-20dd-40e3-a478-d67e4d8d9c36")]
[ComImport, Guid("FD7F2B29-24D0-4b5c-B177-592C39F9CA10"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAudioProcessingObject
{
/// <summary>
/// The Reset method resets the APO to its original state. This method does not cause any changes in the connection objects that
/// are attached to the input or the output of the APO.
/// </summary>
/// <remarks>
/// This method is not real-time compliant and must not be called from a real-time processing thread. The implementation of this
/// method does not and must not touch paged memory. Additionally, it must not call any blocking system routines.
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/audioenginebaseapo/nf-audioenginebaseapo-iaudioprocessingobject-reset
// HRESULT Reset();
void Reset();
/// <summary>
/// The GetLatency method returns the latency for this APO. Latency is the amount of time it takes a frame to traverse the
/// processing pass of an APO.
/// </summary>
/// <returns>
/// A MFTIME structure that will receive the number of units of delay that this APO introduces. Each unit of delay represents
/// 100 nanoseconds.
/// </returns>
/// <remarks>
/// <para>
/// If the client that is calling this APO knows the sampling rate, the client can calculate the latency in terms of the number
/// of frames. To get the total latency of the entire audio signal processing stream, the client must query every APO in the
/// processing chain and add up the results.
/// </para>
/// <para><c>Important</c> This method is not real-time compliant and must not be called from a real-time processing thread.</para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/audioenginebaseapo/nf-audioenginebaseapo-iaudioprocessingobject-getlatency
// HRESULT GetLatency( HNSTIME *pTime );
long GetLatency();
/// <summary>GetRegistrationProperties returns the registration properties of the audio processing object (APO).</summary>
/// <returns>The registration properties of the APO. This parameter is of type APO_REG_PROPERTIES.</returns>
/// <remarks>
/// <para>The caller must free the memory returned by .</para>
/// <para><c>Note</c> This method must not be called from a real-time processing thread.</para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/audioenginebaseapo/nf-audioenginebaseapo-iaudioprocessingobject-getregistrationproperties
// HRESULT GetRegistrationProperties( APO_REG_PROPERTIES **ppRegProps );
SafeCoTaskMemHandle GetRegistrationProperties();
/// <summary>The Initialize method initializes the APO and supports data of variable length.</summary>
/// <param name="cbDataSize">This is the size, in bytes, of the initialization data.</param>
/// <param name="pbyData">This is initialization data that is specific to this APO.</param>
/// <remarks>
/// If this method is used to initialize an APO without the need to initialize any data, it is acceptable to supply a
/// <c>NULL</c> as the value of the pbyData parameter and a 0 (zero) as the value of the cbDataSize parameter. The data that is
/// supplied is of variable length and must have the following format:
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/audioenginebaseapo/nf-audioenginebaseapo-iaudioprocessingobject-initialize
// HRESULT Initialize( UINT32 cbDataSize, BYTE *pbyData );
void Initialize(uint cbDataSize, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] byte[] pbyData);
/// <summary>
/// This method negotiates with the Windows Vista audio engine to establish a data format for the stream of audio data.
/// </summary>
/// <param name="pOppositeFormat">
/// A pointer to an IAudioMediaType interface. This parameter is used to indicate the output format of the data. The value of
/// pOppositeFormat must be set to <c>NULL</c> to indicate that the output format can be any type.
/// </param>
/// <param name="pRequestedInputFormat">
/// A pointer to an IAudioMediaType interface. This parameter is used to indicate the input format that is to be verified.
/// </param>
/// <param name="ppSupportedInputFormat">
/// This parameter indicates the supported format that is closest to the format to be verified.
/// </param>
/// <returns>
/// <para>
/// If the call completed successfully, the ppSupportedInputFormat parameter returns a pRequestedInputFormat pointer and the
/// IsInputFormatSupported method returns a value of S_OK. Otherwise, this method returns one of the following error codes:
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>S_FALSE</term>
/// <term>The format of the input/output format pair is not supported. ppSupportedInputFormat returns a suggested new format.</term>
/// </item>
/// <item>
/// <term>APOERR_FORMAT_NOT_SUPPORTED</term>
/// <term>The format to be verified is not supported. The value of ppSupportedInputFormat does not change.</term>
/// </item>
/// <item>
/// <term>E_POINTER</term>
/// <term>Invalid pointer that is passed to the method. The value of ppSupportedInputFormat does not change.</term>
/// </item>
/// <item>
/// <term>Other HRESULT values</term>
/// <term>These additional error conditions are tracked by the audio engine.</term>
/// </item>
/// </list>
/// </returns>
/// <remarks>
/// <para>
/// There are differences in the implementation of the method by the different APOs. For example, with certain implementations,
/// the output can only be of type float when the input format is of type integer.
/// </para>
/// <para>
/// To initiate format negotiation, the audio service first sets the output of the LFX sAPO to the default float32-based format.
/// The audio service then calls the method of the LFX sAPO, suggests the default format, and monitors the HRESULT response of
/// this method. If the input of the LFX sAPO can support the suggested format, it returns S_OK, together with a reference to
/// the supported format. If the input of the LFX sAPO cannot support the suggested format, it returns S_FALSE together with a
/// reference to a format that is the closest match to the suggested one. If the LFX sAPO cannot support the suggested format
/// and does not have a close match, it returns APOERR_FORMAT_NOT_SUPPORTED. The GFX sAPO works with the output format of the
/// LFX sAPO. So the GFX sAPO is not involved in the format negotiation process.
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/audioenginebaseapo/nf-audioenginebaseapo-iaudioprocessingobject-isinputformatsupported
// HRESULT IsInputFormatSupported( IAudioMediaType *pOppositeFormat, IAudioMediaType *pRequestedInputFormat, IAudioMediaType
// **ppSupportedInputFormat );
[PreserveSig]
HRESULT IsInputFormatSupported(IAudioMediaType pOppositeFormat, IAudioMediaType pRequestedInputFormat, out IAudioMediaType ppSupportedInputFormat);
/// <summary>The method is used to verify that a specific output format is supported.</summary>
/// <param name="pOppositeFormat">
/// A pointer to an IAudioMediaType interface. This parameter indicates the output format. This parameter must be set to
/// <c>NULL</c> to indicate that the output format can be any type.
/// </param>
/// <param name="pRequestedOutputFormat">
/// A pointer to an <c>IAudioMediaType</c> interface. This parameter indicates the output format that is to be verified.
/// </param>
/// <param name="ppSupportedOutputFormat">
/// This parameter indicates the supported output format that is closest to the format to be verified.
/// </param>
/// <returns>
/// <para>
/// If the call completes successfully, the ppSupportedOutputFormat parameter returns a pRequestedOutputFormat pointer and the
/// IsOutputFormatSupported method returns a value of S_OK. Otherwise, this method returns one of the following error codes:
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>S_FALSE</term>
/// <term>
/// The format of Input/output format pair is not supported. The ppSupportedOutPutFormat parameter returns a suggested new format.
/// </term>
/// </item>
/// <item>
/// <term>APOERR_FORMAT_NOT_SUPPORTED</term>
/// <term>The format is not supported. The value of ppSupportedOutputFormat does not change.</term>
/// </item>
/// <item>
/// <term>E_POINTER</term>
/// <term>An invalid pointer was passed to the function. The value of ppSupportedOutputFormat does not change.</term>
/// </item>
/// <item>
/// <term>Other HRESULT values</term>
/// <term>These additional error conditions are tracked by the audio engine.</term>
/// </item>
/// </list>
/// </returns>
/// <remarks>
/// There are differences in the implementation of the method by the different APOs. For example, with certain implementations,
/// the output can only be of type float when the input format is of type integer.
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/audioenginebaseapo/nf-audioenginebaseapo-iaudioprocessingobject-isoutputformatsupported
// HRESULT IsOutputFormatSupported( IAudioMediaType *pOppositeFormat, IAudioMediaType *pRequestedOutputFormat, IAudioMediaType
// **ppSupportedOutputFormat );
[PreserveSig]
HRESULT IsOutputFormatSupported(IAudioMediaType pOppositeFormat, IAudioMediaType pRequestedOutputFormat, out IAudioMediaType ppSupportedOutputFormat);
/// <summary>GetInputChannelCount returns the input channel count (samples-per-frame) for this APO.</summary>
/// <returns>The input channel count.</returns>
/// <remarks>The input channel count that is returned refers to the input side of the APO.</remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/audioenginebaseapo/nf-audioenginebaseapo-iaudioprocessingobject-getinputchannelcount
// HRESULT GetInputChannelCount( UINT32 *pu32ChannelCount );
uint GetInputChannelCount();
}
/// <summary>
/// <para>The interface is used to configure the APO. This interface uses its methods to lock and unlock the APO for processing.</para>
/// <para>The interface supports the following methods:</para>
/// </summary>
// https://docs.microsoft.com/en-us/windows/win32/api/audioenginebaseapo/nn-audioenginebaseapo-iaudioprocessingobjectconfiguration
[PInvokeData("audioenginebaseapo.h", MSDNShortId = "6311a5d1-b9d3-4c62-99aa-8feda32b4a2f")]
[ComImport, Guid("0E5ED805-ABA6-49c3-8F9A-2B8C889C4FA8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAudioProcessingObjectConfiguration
{
/// <summary>The method is used to verify that the APO is locked and ready to process data.</summary>
/// <param name="u32NumInputConnections">Number of input connections that are attached to this APO.</param>
/// <param name="ppInputConnections">Connection descriptor for each input connection that is attached to this APO.</param>
/// <param name="u32NumOutputConnections">Number of output connections that are attached to this APO.</param>
/// <param name="ppOutputConnections">Connection descriptor for each output connection that is attached to this APO.</param>
/// <remarks>
/// When the method is called, it first performs an internal check to see if the APO has been initialized and is ready to
/// process data. Each APO has different initialization requirements so each APO must define its own Initialize method if needed.
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/audioenginebaseapo/nf-audioenginebaseapo-iaudioprocessingobjectconfiguration-lockforprocess
// HRESULT LockForProcess( UINT32 u32NumInputConnections, APO_CONNECTION_DESCRIPTOR **ppInputConnections, UINT32
// u32NumOutputConnections, APO_CONNECTION_DESCRIPTOR **ppOutputConnections );
void LockForProcess([In] uint u32NumInputConnections, [In, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStruct, SizeParamIndex = 0)] APO_CONNECTION_DESCRIPTOR[] ppInputConnections,
[In] uint u32NumOutputConnections, [In, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStruct, SizeParamIndex = 2)] APO_CONNECTION_DESCRIPTOR[] ppOutputConnections);
/// <summary>The method releases the lock that was imposed on the APO by the LockForProcess method.</summary>
/// <remarks>
/// The method places the APO in a mode that makes configuration changes possible. These changes include Add, Remove, and Swap
/// of the input and output connections that are attached to the APO.
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/audioenginebaseapo/nf-audioenginebaseapo-iaudioprocessingobjectconfiguration-unlockforprocess
// HRESULT UnlockForProcess();
void UnlockForProcess();
}
/// <summary>
/// <para>
/// This interface can operate in real-time mode and its methods can be called form real-time processing threads. The implementation
/// of the methods for this interface must not block or touch paged memory. Additionally, you must not call any blocking system
/// routines in the implementation of the methods.
/// </para>
/// <para>The interface includes the following methods:</para>
/// </summary>
// https://docs.microsoft.com/en-us/windows/win32/api/audioenginebaseapo/nn-audioenginebaseapo-iaudioprocessingobjectrt
[PInvokeData("audioenginebaseapo.h", MSDNShortId = "640ac817-16f2-47c8-87e9-1ae0136e6e55")]
[ComImport, Guid("9E1D6A6D-DDBC-4E95-A4C7-AD64BA37846C"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAudioProcessingObjectRT
{
/// <summary>The APOProcess method causes the APO to make a processing pass.</summary>
/// <param name="u32NumInputConnections">The number of input connections that are attached to this APO.</param>
/// <param name="ppInputConnections">An array of input connection property structures. There is one structure per input connection.</param>
/// <param name="u32NumOutputConnections">The number of output connections that are attached to this APO.</param>
/// <param name="ppOutputConnections">
/// An array of output connection property structures. There is one structure per output connection.
/// </param>
/// <returns>
/// <para>None</para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// </list>
/// </returns>
/// <remarks>
/// <para>
/// The method must not change the data in the ppOutputConnections array. But it must set the properties of the output
/// connections after processing.
/// </para>
/// <para>
/// The method is called from a real-time processing thread. The implementation of this method must not touch paged memory and
/// it should not call any system blocking routines.
/// </para>
/// <para>
/// For a detailed look at an implementation of this method, see the Swap sample code and refer to the Swapapolfx.cpp file.
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/audioenginebaseapo/nf-audioenginebaseapo-iaudioprocessingobjectrt-apoprocess
// void APOProcess( UINT32 u32NumInputConnections, APO_CONNECTION_PROPERTY **ppInputConnections, UINT32 u32NumOutputConnections,
// APO_CONNECTION_PROPERTY **ppOutputConnections );
[PreserveSig]
void APOProcess([In] uint u32NumInputConnections, [In, Out, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStruct, SizeParamIndex = 0)] APO_CONNECTION_PROPERTY[] ppInputConnections,
[In] uint u32NumOutputConnections, [In, Out, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStruct, SizeParamIndex = 2)] APO_CONNECTION_PROPERTY[] ppOutputConnections);
/// <summary>The method returns the number of input frames that an APO requires to generate a given number of output frames.</summary>
/// <param name="u32OutputFrameCount">This is a count of the number of output frames.</param>
/// <returns>
/// <para>The method returns the number of input frames that are required to generate the given number of output frames.</para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// </list>
/// </returns>
/// <remarks>
/// The method is called from a real-time processing thread. The implementation of this method must not touch paged memory and
/// it should not call any system blocking routines.
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/audioenginebaseapo/nf-audioenginebaseapo-iaudioprocessingobjectrt-calcinputframes
// UINT32 CalcInputFrames( UINT32 u32OutputFrameCount );
[PreserveSig]
uint CalcInputFrames(uint u32OutputFrameCount);
/// <summary>The method returns the number of output frames that an APO requires for a given number of input frames.</summary>
/// <param name="u32InputFrameCount">This is a count of the number of input frames.</param>
/// <returns>
/// <para>The method returns the number of output frames that an APO will generate for a given number of input frames.</para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// </list>
/// </returns>
/// <remarks>
/// The method can be called form a real-time processing thread. The implementation of this method must not block or touch paged
/// memory and it should not call any system blocking routines.
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/audioenginebaseapo/nf-audioenginebaseapo-iaudioprocessingobjectrt-calcoutputframes
// UINT32 CalcOutputFrames( UINT32 u32InputFrameCount );
[PreserveSig]
uint CalcOutputFrames([In] uint u32InputFrameCount);
}
/// <summary>
/// <para>
/// The IAudioSystemEffects interface uses the basic methods that are inherited from <c>IUnknown</c>, and must implement an
/// <c>Initialize</c> method. The parameters that are passed to this <c>Initialize</c> method must be passed directly to the
/// <c>IAudioProcessingObject::Initialize</c> method.
/// </para>
/// <para>
/// Refer to the IAudioProcessingObject::Initialize method for information about the structure and the parameters that are required
/// to implement the <c>IAudioSystemEffects::Initialize</c> method.
/// </para>
/// </summary>
// https://docs.microsoft.com/en-us/windows/win32/api/audioenginebaseapo/nn-audioenginebaseapo-iaudiosystemeffects
[PInvokeData("audioenginebaseapo.h", MSDNShortId = "86429c51-6831-4266-9774-1547dc04bcb0")]
[ComImport, Guid("5FA00F27-ADD6-499a-8A9D-6B98521FA75B"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAudioSystemEffects
{
}
/// <summary>
/// The <c>IAudioSystemEffects2</c> interface was introduced with Windows 8.1 for retrieving information about the processing
/// objects in a given mode.
/// </summary>
// https://docs.microsoft.com/en-us/windows/win32/api/audioenginebaseapo/nn-audioenginebaseapo-iaudiosystemeffects2
[PInvokeData("audioenginebaseapo.h", MSDNShortId = "5989BAFB-6B2D-4186-9A8D-96C8974E0D18")]
[ComImport, Guid("BAFE99D2-7436-44CE-9E0E-4D89AFBFFF56"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAudioSystemEffects2 : IAudioSystemEffects
{
/// <summary>
/// The GetEffectsList method is used for retrieving the list of audio processing effects that are currently active, and stores
/// an event to be signaled if the list changes.
/// </summary>
/// <param name="ppEffectsIds">
/// Pointer to the list of GUIDs that represent audio processing effects. The caller is responsible for freeing this memory by
/// calling CoTaskMemFree.
/// </param>
/// <param name="pcEffects">A count of the audio processing effects in the list.</param>
/// <param name="Event">The HANDLE of the event that will be signaled if the list changes.</param>
/// <remarks>
/// <para>
/// The APO signals the specified event when the list of audio processing effects changes from the list that was returned by
/// <c>GetEffectsList</c>. The APO uses this event until either <c>GetEffectsList</c> is called again, or the APO is destroyed.
/// The passed handle can be NULL, in which case the APO stops using any previous handle and does not signal an event.
/// </para>
/// <para>
/// An APO implements this method to allow Windows to discover the current effects applied by the APO. The list of effects may
/// depend on the processing mode that the APO initialized, and on any end user configuration. The processing mode is indicated
/// by the AudioProcessingMode member of APOInitSystemEffects2.
/// </para>
/// <para>
/// APOs should identify effects using GUIDs defined by Windows, such as AUDIO_EFFECT_TYPE_ACOUSTIC_ECHO_CANCELLATION. An APO
/// should only define and return a custom GUID in rare cases where the type of effect is clearly different from the ones
/// defined by Windows.
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/audioenginebaseapo/nf-audioenginebaseapo-iaudiosystemeffects2-geteffectslist
// HRESULT GetEffectsList( LPGUID *ppEffectsIds, UINT *pcEffects, HANDLE Event );
void GetEffectsList(out SafeCoTaskMemHandle ppEffectsIds, out uint pcEffects, [In] IntPtr Event);
}
/// <summary>
/// <para>
/// The interface is supported in Windows Vista and later versions of Windows. When you develop an audio processing object (APO) to
/// drive an audio adapter with an atypical format, the APO must support the interface.
/// </para>
/// <para>
/// The Windows operating system can instantiate your APO outside the audio engine and use the interface to retrieve information
/// about the atypical format. The associated user interface displays the data that is retrieved.
/// </para>
/// <para>
/// <c>Important</c> Although the interface continues to be supported in Windows, note that the type of APO to which you can apply
/// this interface depends on the version of Windows you are targeting. The following table provides more information:
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Target OS</term>
/// <term>Target APO type</term>
/// </listheader>
/// <item>
/// <term>Windows Vista</term>
/// <term>Global effects (GFX)</term>
/// </item>
/// <item>
/// <term>Windows 7</term>
/// <term>Global effects (GFX)</term>
/// </item>
/// <item>
/// <term>Windows 8</term>
/// <term>Global effects (GFX)</term>
/// </item>
/// <item>
/// <term>Windows 8.1</term>
/// <term>Endpoint effects (EFX)</term>
/// </item>
/// </list>
/// <para>The interface inherits from <c>IUnknown</c> and also supports the following methods:</para>
/// </summary>
// https://docs.microsoft.com/en-us/windows/win32/api/audioenginebaseapo/nn-audioenginebaseapo-iaudiosystemeffectscustomformats
[PInvokeData("audioenginebaseapo.h", MSDNShortId = "29b758c0-5bbe-489c-9950-bc92a185fbaf")]
[ComImport, Guid("B1176E34-BB7F-4f05-BEBD-1B18A534E097"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAudioSystemEffectsCustomFormats
{
/// <summary>The method retrieves the number of custom formats supported by the system effects audio processing object (sAPO).</summary>
/// <returns>
/// Specifies a pointer to an unsigned integer. The unsigned integer represents the number of formats supported by the sAPO.
/// </returns>
/// <remarks>For more information about sAPOs, see System Effects Audio Processing Objects.</remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/audioenginebaseapo/nf-audioenginebaseapo-iaudiosystemeffectscustomformats-getformatcount
// HRESULT GetFormatCount( UINT *pcFormats );
uint GetFormatCount();
/// <summary>The method retrieves an IAudioMediaType representation of a custom format.</summary>
/// <param name="nFormat">
/// Specifies the index of a supported format. This parameter can be any value in the range from zero to one less than the
/// return value of GetFormatCount. In other words, any value in the range from zero to GetFormatCount( ) - 1.
/// </param>
/// <returns>
/// Specifies a pointer to a pointer to an <c>IAudioMediaType</c> interface. It is the responsibility of the caller to release
/// the <c>IAudioMediaType</c> interface to which the ppFormat parameter points.
/// </returns>
/// <remarks>
/// When the audio system calls the method, the sAPO creates an audio media type object and returns an <c>IAudioMediaType</c>
/// interface. The sAPO implementation can use the CreateAudioMediaType utility function to create the audio media type object.
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/audioenginebaseapo/nf-audioenginebaseapo-iaudiosystemeffectscustomformats-getformat
// HRESULT GetFormat( UINT nFormat, IAudioMediaType **ppFormat );
IAudioMediaType GetFormat(uint nFormat);
/// <summary>The method retrieves a string representation of the custom format so that it can be displayed on a user-interface.</summary>
/// <param name="nFormat">
/// Specifies the index of a supported format. This parameter can be any value in the range from zero to one less than the
/// return value of GetFormatCount. In other words, any value in the range from zero to GetFormatCount( ) - 1.
/// </param>
/// <param name="ppwstrFormatRep">
/// Specifies the address of the buffer that receives a NULL-terminated Unicode string that describes the custom format.
/// </param>
/// <returns>
/// <para>
/// The method returns S_OK when the call is successful. Otherwise, it returns one of the error codes shown in the following table.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>E_POINTER</term>
/// <term>Invalid pointer passed to function</term>
/// </item>
/// <item>
/// <term>E_OUTOFMEMORY</term>
/// <term>Return buffer cannot be allocated</term>
/// </item>
/// <item>
/// <term>E_INVALIDARG</term>
/// <term>nFormat is out of range</term>
/// </item>
/// </list>
/// </returns>
/// <remarks>
/// The sAPO uses CoTaskMemAlloc to allocate the returned string. The caller must use CoTaskMemFree to delete the buffer that is
/// pointed to by the ppwstrFormatRep parameter.
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/audioenginebaseapo/nf-audioenginebaseapo-iaudiosystemeffectscustomformats-getformatrepresentation
// HRESULT GetFormatRepresentation( UINT nFormat, LPWSTR *ppwstrFormatRep );
void GetFormatRepresentation(uint nFormat, out SafeCoTaskMemString ppwstrFormatRep);
}
/// <summary>
/// The GetEffectsList method is used for retrieving the list of audio processing effects that are currently active, and stores an
/// event to be signaled if the list changes.
/// </summary>
/// <param name="ase2">The <c>IAudioSystemEffects2</c> instance.</param>
/// <param name="Event">The HANDLE of the event that will be signaled if the list changes.</param>
/// <returns>The list of GUIDs that represent audio processing effects.</returns>
/// <remarks>
/// <para>
/// The APO signals the specified event when the list of audio processing effects changes from the list that was returned by
/// <c>GetEffectsList</c>. The APO uses this event until either <c>GetEffectsList</c> is called again, or the APO is destroyed. The
/// passed handle can be NULL, in which case the APO stops using any previous handle and does not signal an event.
/// </para>
/// <para>
/// An APO implements this method to allow Windows to discover the current effects applied by the APO. The list of effects may
/// depend on the processing mode that the APO initialized, and on any end user configuration. The processing mode is indicated by
/// the AudioProcessingMode member of APOInitSystemEffects2.
/// </para>
/// <para>
/// APOs should identify effects using GUIDs defined by Windows, such as AUDIO_EFFECT_TYPE_ACOUSTIC_ECHO_CANCELLATION. An APO should
/// only define and return a custom GUID in rare cases where the type of effect is clearly different from the ones defined by Windows.
/// </para>
/// </remarks>
public static Guid[] GetEffectsList(this IAudioSystemEffects2 ase2, [In] IntPtr Event)
{
ase2.GetEffectsList(out var ids, out var i, Event);
using (ids)
return ids.ToArray<Guid>((int)i);
}
/// <summary>The method retrieves a string representation of the custom format so that it can be displayed on a user-interface.</summary>
/// <param name="fmts">The <c>IAudioSystemEffectsCustomFormats</c> instance.</param>
/// <param name="nFormat">
/// Specifies the index of a supported format. This parameter can be any value in the range from zero to one less than the return
/// value of GetFormatCount. In other words, any value in the range from zero to GetFormatCount( ) - 1.
/// </param>
/// <returns>A string that describes the custom format.</returns>
public static string GetFormatRepresentation(this IAudioSystemEffectsCustomFormats fmts, uint nFormat)
{
fmts.GetFormatRepresentation(nFormat, out var rep);
using (rep)
return (string)rep;
}
/// <summary>The APO_CONNECTION_DESCRIPTOR structure stores the description of an APO connection buffer.</summary>
/// <remarks>The Terminal Services AudioEndpoint API is for use in Remote Desktop scenarios; it is not for client applications.</remarks>
[PInvokeData("Audioenginebaseapo.h")]
[StructLayout(LayoutKind.Sequential)]
public struct APO_CONNECTION_DESCRIPTOR
{
/// <summary>
/// A value of the APO_CONNECTION_BUFFER_TYPE enumeration that indicates how the connection buffer inside the APO connection is
/// allocated. This member is set only by the APO connection during initialization. It is a private member that should be
/// cleared before creating the connection.
/// </summary>
public APO_CONNECTION_BUFFER_TYPE Type;
/// <summary>
/// A pointer to the buffer to be used for the APO connection. If this member is NULL, the audio engine allocates memory for the
/// buffer and the Type member is set to APO_CONNECTION_BUFFER_TYPE_ALLOCATED. Otherwise, the audio engine uses the specified
/// memory region as the connection buffer. The buffer to be used for the APO connection must be frame aligned or 128-bit
/// aligned, both at the beginning of the buffer and at the start of the audio buffer section. The buffer to be used for the APO
/// connection must be large enough to hold the number of frames indicated in u32MaxFrameCount. This member must point to the
/// beginning of the audio buffer area. If the audio engine must use the memory pointed by this member, the Type member is set
/// to APO_CONNECTION_BUFFER_TYPE_EXTERNAL.
/// </summary>
public IntPtr pBuffer;
/// <summary>
/// The maximum number of frames that the connection buffer can hold. The actual space allocated depends on the exact format of
/// the audio data specified by the pFormat member.
/// </summary>
public uint u32MaxFrameCount;
/// <summary>
/// A pointer to the audio media object that specifies the format of the connection. This also represents the format of the data
/// in the connection buffer.
/// </summary>
public IntPtr pFormat;
/// <summary>A tag that identifies a valid APO_CONNECTION_DESCRIPTOR structure. A valid structure is marked as APO_CONNECTION_DESCRIPTOR_SIGNATURE.</summary>
public uint u32Signature;
}
/// <summary>
/// The APO_REG_PROPERTIES structure is used by IAudioProcessingObject::GetRegistrationProperties for returning the registration
/// properties of an audio processing object (APO).
/// </summary>
// https://docs.microsoft.com/en-us/windows/win32/api/audioenginebaseapo/ns-audioenginebaseapo-apo_reg_properties typedef struct
// APO_REG_PROPERTIES { CLSID clsid; APO_FLAG Flags; WCHAR szFriendlyName[256]; WCHAR szCopyrightInfo[256]; UINT32 u32MajorVersion;
// UINT32 u32MinorVersion; UINT32 u32MinInputConnections; UINT32 u32MaxInputConnections; UINT32 u32MinOutputConnections; UINT32
// u32MaxOutputConnections; UINT32 u32MaxInstances; UINT32 u32NumAPOInterfaces; IID iidAPOInterfaceList[1]; } APO_REG_PROPERTIES, *PAPO_REG_PROPERTIES;
[PInvokeData("audioenginebaseapo.h", MSDNShortId = "466215E5-5345-4570-A29B-086562882F5D")]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct APO_REG_PROPERTIES
{
/// <summary>The class ID for this APO.</summary>
public Guid clsid;
/// <summary>The flags for this APO. This parameter is an enumerated constant of type APO_FLAG.</summary>
public APO_FLAG Flags;
/// <summary>The friendly name of this APO. This is a string of characters with a max length of 256.</summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string szFriendlyName;
/// <summary>The copyright info for this APO. This is a string of characters with a max length of 256.</summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string szCopyrightInfo;
/// <summary>The major version number for this APO.</summary>
public uint u32MajorVersion;
/// <summary>The minor version number for this APO.</summary>
public uint u32MinorVersion;
/// <summary>The minimum number of input connections for this APO.</summary>
public uint u32MinInputConnections;
/// <summary>The maximum number of input connections for this APO.</summary>
public uint u32MaxInputConnections;
/// <summary>The minimum number of output connections for this APO.</summary>
public uint u32MinOutputConnections;
/// <summary>The maximum number of output connections for this APO.</summary>
public uint u32MaxOutputConnections;
/// <summary>The maximum number of instances of this APO.</summary>
public uint u32MaxInstances;
/// <summary>The number of interfaces for this APO.</summary>
public uint u32NumAPOInterfaces;
/// <summary/>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public Guid[] iidAPOInterfaceList;
}
/// <summary>
/// The APOInitBaseStruct structure is the base initialization header that must precede other initialization data in IAudioProcessingObject::Initialize.
/// </summary>
/// <remarks>
/// If the specified CLSID does not match, then the APOInitBaseStruct structure was not designed for this APO, and this is an error
/// condition. And if the CLSID of the APO changes between versions, then the CLSID may also be used for version management. In the
/// case where the CLSID is used for version management, a previous version may still be supported by the APO.
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/audioenginebaseapo/ns-audioenginebaseapo-apoinitbasestruct typedef struct
// APOInitBaseStruct { UINT32 cbSize; CLSID clsid; } APOInitBaseStruct;
[PInvokeData("audioenginebaseapo.h", MSDNShortId = "15C973AE-B0E8-42FD-9F34-671A6A915B47")]
[StructLayout(LayoutKind.Sequential)]
public struct APOInitBaseStruct
{
/// <summary>The total size of the structure in bytes.</summary>
public uint cbSize;
/// <summary>The Class ID (CLSID) of the APO.</summary>
public Guid clsid;
}
/// <summary>The APOInitSystemEffects structure gets passed to the system effects APO for initialization.</summary>
// https://docs.microsoft.com/en-us/windows/win32/api/audioenginebaseapo/ns-audioenginebaseapo-apoinitsystemeffects typedef struct
// APOInitSystemEffects { APOInitBaseStruct APOInit; IPropertyStore *pAPOEndpointProperties; IPropertyStore
// *pAPOSystemEffectsProperties; void *pReserved; IMMDeviceCollection *pDeviceCollection; } APOInitSystemEffects;
[PInvokeData("audioenginebaseapo.h", MSDNShortId = "E33B1F94-4E3A-4EC1-AFB5-FD803FA391BC")]
[StructLayout(LayoutKind.Sequential)]
public struct APOInitSystemEffects
{
/// <summary>An APOInitBaseStruct structure.</summary>
public APOInitBaseStruct APOInit;
/// <summary>A pointer to an IPropertyStore object.</summary>
public IPropertyStore pAPOEndpointProperties;
/// <summary>A pointer to an IPropertyStore object.</summary>
public IPropertyStore pAPOSystemEffectsProperties;
/// <summary>Reserved for future use.</summary>
public IntPtr pReserved;
/// <summary>A pointer to an IMMDeviceCollection object.</summary>
public IMMDeviceCollection pDeviceCollection;
}
/// <summary>
/// The APOInitSystemEffects2 structure was introduced with Windows 8.1, to make it possible to provide additional initialization
/// context to the audio processing object (APO) for initialization.
/// </summary>
// https://docs.microsoft.com/en-us/windows/win32/api/audioenginebaseapo/ns-audioenginebaseapo-apoinitsystemeffects2 typedef struct
// APOInitSystemEffects2 { APOInitBaseStruct APOInit; IPropertyStore *pAPOEndpointProperties; IPropertyStore
// *pAPOSystemEffectsProperties; void *pReserved; IMMDeviceCollection *pDeviceCollection; UINT nSoftwareIoDeviceInCollection; UINT
// nSoftwareIoConnectorIndex; GUID AudioProcessingMode; BOOL InitializeForDiscoveryOnly; } APOInitSystemEffects2;
[PInvokeData("audioenginebaseapo.h", MSDNShortId = "87E59FCE-1965-4B23-B1F5-F54FEDD5A83E")]
[StructLayout(LayoutKind.Sequential)]
public struct APOInitSystemEffects2
{
/// <summary>An APOInitBaseStruct structure.</summary>
public APOInitBaseStruct APOInit;
/// <summary>A pointer to an IPropertyStore object.</summary>
public IPropertyStore pAPOEndpointProperties;
/// <summary>A pointer to an IPropertyStore object.</summary>
public IPropertyStore pAPOSystemEffectsProperties;
/// <summary>Reserved for future use.</summary>
public IntPtr pReserved;
/// <summary>A pointer to an IMMDeviceCollection object.</summary>
public IMMDeviceCollection pDeviceCollection;
/// <summary>
/// Specifies the MMDevice that implements the DeviceTopology that includes the software connector for which the APO is
/// initializing. The MMDevice is contained in pDeviceCollection.
/// </summary>
public uint nSoftwareIoDeviceInCollection;
/// <summary>Specifies the index of a Software_IO connector in the DeviceTopology.</summary>
public uint nSoftwareIoConnectorIndex;
/// <summary>Specifies the processing mode for the audio graph.</summary>
public Guid AudioProcessingMode;
/// <summary>Indicates whether the audio system is initializing the APO for effects discovery only.</summary>
[MarshalAs(UnmanagedType.Bool)]
public bool InitializeForDiscoveryOnly;
}
/// <summary>The AudioFXExtensionParams structure is passed to the system effects ControlPanel Extension PropertyPage via IShellPropSheetExt::AddPages.</summary>
// https://docs.microsoft.com/en-us/windows/win32/api/audioenginebaseapo/ns-audioenginebaseapo-audiofxextensionparams typedef struct
// __MIDL___MIDL_itf_audioenginebaseapo_0000_0008_0001 { LPARAM AddPageParam; LPWSTR pwstrEndpointID; IPropertyStore *pFxProperties;
// } AudioFXExtensionParams;
[PInvokeData("audioenginebaseapo.h", MSDNShortId = "832F1190-ED3E-4059-AB45-18C23D98663B")]
[StructLayout(LayoutKind.Sequential)]
public struct AudioFXExtensionParams
{
/// <summary>Parameters for the Property Page extension.</summary>
public IntPtr AddPageParam;
/// <summary>The ID for the audio endpoint.</summary>
[MarshalAs(UnmanagedType.LPWStr)]
public string pwstrEndpointID;
/// <summary>An IPropertyStore object.</summary>
public IPropertyStore pFxProperties;
}
}
}