mirror of https://github.com/naudio/NAudio.git
Browse Source
Dropping async IAudioClient2 activation down into the WASAPI package
process-audio-capture
Dropping async IAudioClient2 activation down into the WASAPI package
process-audio-capture

18 changed files with 339 additions and 217 deletions
-
12NAudio.Uap/WasapiCaptureRT.cs
-
181NAudio.Uap/WasapiOutRT.cs
-
54NAudio.Wasapi/CoreAudioApi/ActivateAudioInterfaceCompletionHandler.cs
-
35NAudio.Wasapi/CoreAudioApi/AudioClient.cs
-
2NAudio.Wasapi/CoreAudioApi/AudioClientBufferFlags.cs
-
2NAudio.Wasapi/CoreAudioApi/AudioClientProperties.cs
-
62NAudio.Wasapi/CoreAudioApi/AudioClientStreamFlags.cs
-
21NAudio.Wasapi/CoreAudioApi/AudioClientStreamOptions.cs
-
30NAudio.Wasapi/CoreAudioApi/AudioStreamCategory.cs
-
14NAudio.Wasapi/CoreAudioApi/Interfaces/IActivateAudioInterfaceAsyncOperation.cs
-
16NAudio.Wasapi/CoreAudioApi/Interfaces/IActivateAudioInterfaceCompletionHandler.cs
-
11NAudio.Wasapi/CoreAudioApi/Interfaces/IAgileObject.cs
-
2NAudio.Wasapi/CoreAudioApi/Interfaces/IAudioClient.cs
-
42NAudio.Wasapi/CoreAudioApi/Interfaces/IAudioClient2.cs
-
26NAudio.Wasapi/CoreAudioApi/NativeMethods.cs
-
42NAudio.Wasapi/MediaFoundationReader.cs
-
2NAudioUniversalDemo/Package.appxmanifest
-
2RELEASE_NOTES.md
@ -0,0 +1,54 @@ |
|||
using NAudio.CoreAudioApi.Interfaces; |
|||
using NAudio.Wasapi.CoreAudioApi.Interfaces; |
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace NAudio.Wasapi.CoreAudioApi |
|||
{ |
|||
internal class ActivateAudioInterfaceCompletionHandler : |
|||
IActivateAudioInterfaceCompletionHandler, IAgileObject |
|||
{ |
|||
private Action<IAudioClient2> initializeAction; |
|||
private TaskCompletionSource<IAudioClient2> tcs = new TaskCompletionSource<IAudioClient2>(); |
|||
|
|||
public ActivateAudioInterfaceCompletionHandler( |
|||
Action<IAudioClient2> initializeAction) |
|||
{ |
|||
this.initializeAction = initializeAction; |
|||
} |
|||
|
|||
public void ActivateCompleted(IActivateAudioInterfaceAsyncOperation activateOperation) |
|||
{ |
|||
// First get the activation results, and see if anything bad happened then
|
|||
activateOperation.GetActivateResult(out int hr, out object unk); |
|||
if (hr != 0) |
|||
{ |
|||
tcs.TrySetException(Marshal.GetExceptionForHR(hr, new IntPtr(-1))); |
|||
return; |
|||
} |
|||
|
|||
var pAudioClient = (IAudioClient2)unk; |
|||
|
|||
// Next try to call the client's (synchronous, blocking) initialization method.
|
|||
try |
|||
{ |
|||
initializeAction(pAudioClient); |
|||
tcs.SetResult(pAudioClient); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
tcs.TrySetException(ex); |
|||
} |
|||
|
|||
|
|||
} |
|||
|
|||
|
|||
public TaskAwaiter<IAudioClient2> GetAwaiter() |
|||
{ |
|||
return tcs.Task.GetAwaiter(); |
|||
} |
|||
} |
|||
} |
@ -1,17 +1,34 @@ |
|||
namespace NAudio.CoreAudioApi |
|||
using System; |
|||
|
|||
namespace NAudio.CoreAudioApi |
|||
{ |
|||
/// <summary>
|
|||
/// Defines values that describe the characteristics of an audio stream.
|
|||
/// AUDCLNT_STREAMOPTIONS
|
|||
/// https://docs.microsoft.com/en-us/windows/win32/api/audioclient/ne-audioclient-audclnt_streamoptions
|
|||
/// </summary>
|
|||
[Flags] |
|||
public enum AudioClientStreamOptions |
|||
{ |
|||
/// <summary>
|
|||
/// AUDCLNT_STREAMOPTIONS_NONE
|
|||
/// No stream options.
|
|||
/// </summary>
|
|||
None = 0, |
|||
/// <summary>
|
|||
/// AUDCLNT_STREAMOPTIONS_RAW
|
|||
/// The audio stream is a 'raw' stream that bypasses all signal processing except for endpoint specific, always-on processing in the APO, driver, and hardware.
|
|||
/// </summary>
|
|||
Raw = 0x1 |
|||
Raw = 0x1, |
|||
/// <summary>
|
|||
/// AUDCLNT_STREAMOPTIONS_MATCH_FORMAT
|
|||
/// The audio client is requesting that the audio engine match the format proposed by the client. The audio engine
|
|||
/// will match this format only if the format is supported by the audio driver and associated APOs.
|
|||
/// </summary>
|
|||
MatchFormat = 0x2, |
|||
/// <summary>
|
|||
/// AUDCLNT_STREAMOPTIONS_AMBISONICS
|
|||
/// </summary>
|
|||
Ambisonics = 0x4, |
|||
} |
|||
} |
@ -0,0 +1,14 @@ |
|||
using System; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace NAudio.Wasapi.CoreAudioApi.Interfaces |
|||
{ |
|||
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("72A22D78-CDE4-431D-B8CC-843A71199B6D")] |
|||
public interface IActivateAudioInterfaceAsyncOperation |
|||
{ |
|||
//virtual HRESULT STDMETHODCALLTYPE GetActivateResult(/*[out]*/ _Out_
|
|||
// HRESULT *activateResult, /*[out]*/ _Outptr_result_maybenull_ IUnknown **activatedInterface) = 0;
|
|||
void GetActivateResult([Out] out int activateResult, |
|||
[Out, MarshalAs(UnmanagedType.IUnknown)] out object activateInterface); |
|||
} |
|||
} |
@ -0,0 +1,16 @@ |
|||
using NAudio.CoreAudioApi.Interfaces; |
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace NAudio.Wasapi.CoreAudioApi.Interfaces |
|||
{ |
|||
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("41D949AB-9862-444A-80F6-C261334DA5EB")] |
|||
public interface IActivateAudioInterfaceCompletionHandler |
|||
{ |
|||
//virtual HRESULT STDMETHODCALLTYPE ActivateCompleted(/*[in]*/ _In_
|
|||
// IActivateAudioInterfaceAsyncOperation *activateOperation) = 0;
|
|||
void ActivateCompleted(IActivateAudioInterfaceAsyncOperation activateOperation); |
|||
} |
|||
} |
@ -0,0 +1,11 @@ |
|||
using System; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace NAudio.Wasapi.CoreAudioApi.Interfaces |
|||
{ |
|||
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("94ea2b94-e9cc-49e0-c0ff-ee64ca8f5b90")] |
|||
interface IAgileObject |
|||
{ |
|||
|
|||
} |
|||
} |
@ -0,0 +1,42 @@ |
|||
using System; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace NAudio.CoreAudioApi.Interfaces |
|||
{ |
|||
/// <summary>
|
|||
/// https://docs.microsoft.com/en-us/windows/win32/api/audioclient/nn-audioclient-iaudioclient2
|
|||
/// </summary>
|
|||
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("726778CD-F60A-4eda-82DE-E47610CD78AA")] |
|||
public interface IAudioClient2 : IAudioClient |
|||
{ |
|||
//virtual HRESULT STDMETHODCALLTYPE IsOffloadCapable(/*[in]*/ _In_
|
|||
// AUDIO_STREAM_CATEGORY Category, /*[in]*/ _Out_ BOOL *pbOffloadCapable) = 0;
|
|||
/// <summary>
|
|||
/// The IsOffloadCapable method retrieves information about whether or not the endpoint on which a stream is created is capable of supporting an offloaded audio stream.
|
|||
/// </summary>
|
|||
/// <param name="category">An enumeration that specifies the category of an audio stream.</param>
|
|||
/// <param name="pbOffloadCapable">A pointer to a Boolean value. TRUE indicates that the endpoint is offload-capable. FALSE indicates that the endpoint is not offload-capable.</param>
|
|||
void IsOffloadCapable(AudioStreamCategory category, out bool pbOffloadCapable); |
|||
//virtual HRESULT STDMETHODCALLTYPE SetClientProperties(/*[in]*/ _In_
|
|||
// const AudioClientProperties *pProperties) = 0;
|
|||
/// <summary>
|
|||
/// Pointer to an AudioClientProperties structure.
|
|||
/// </summary>
|
|||
/// <param name="pProperties"></param>
|
|||
void SetClientProperties([In] IntPtr pProperties); |
|||
// TODO: try this: void SetClientProperties([In, MarshalAs(UnmanagedType.LPStruct)] AudioClientProperties pProperties);
|
|||
//virtual HRESULT STDMETHODCALLTYPE GetBufferSizeLimits(/*[in]*/ _In_
|
|||
// const WAVEFORMATEX *pFormat, /*[in]*/ _In_ BOOL bEventDriven, /*[in]*/
|
|||
// _Out_ REFERENCE_TIME *phnsMinBufferDuration, /*[in]*/ _Out_
|
|||
// REFERENCE_TIME *phnsMaxBufferDuration) = 0;
|
|||
/// <summary>
|
|||
/// The GetBufferSizeLimits method returns the buffer size limits of the hardware audio engine in 100-nanosecond units.
|
|||
/// </summary>
|
|||
/// <param name="pFormat">A pointer to the target format that is being queried for the buffer size limit.</param>
|
|||
/// <param name="bEventDriven">Boolean value to indicate whether or not the stream can be event-driven.</param>
|
|||
/// <param name="phnsMinBufferDuration">Returns a pointer to the minimum buffer size (in 100-nanosecond units) that is required for the underlying hardware audio engine to operate at the format specified in the pFormat parameter, without frequent audio glitching.</param>
|
|||
/// <param name="phnsMaxBufferDuration">Returns a pointer to the maximum buffer size (in 100-nanosecond units) that the underlying hardware audio engine can support for the format specified in the pFormat parameter.</param>
|
|||
void GetBufferSizeLimits(IntPtr pFormat, bool bEventDriven, |
|||
out long phnsMinBufferDuration, out long phnsMaxBufferDuration); |
|||
} |
|||
} |
@ -0,0 +1,26 @@ |
|||
using NAudio.Wasapi.CoreAudioApi.Interfaces; |
|||
using System; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace NAudio.Wasapi.CoreAudioApi |
|||
{ |
|||
static class NativeMethods |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// Enables Windows Store apps to access preexisting Component Object Model (COM) interfaces in the WASAPI family.
|
|||
/// </summary>
|
|||
/// <param name="deviceInterfacePath">A device interface ID for an audio device. This is normally retrieved from a DeviceInformation object or one of the methods of the MediaDevice class.</param>
|
|||
/// <param name="riid">The IID of a COM interface in the WASAPI family, such as IAudioClient.</param>
|
|||
/// <param name="activationParams">Interface-specific activation parameters. For more information, see the pActivationParams parameter in IMMDevice::Activate. </param>
|
|||
/// <param name="completionHandler"></param>
|
|||
/// <param name="activationOperation"></param>
|
|||
[DllImport("Mmdevapi.dll", ExactSpelling = true, PreserveSig = false)] |
|||
public static extern void ActivateAudioInterfaceAsync( |
|||
[In, MarshalAs(UnmanagedType.LPWStr)] string deviceInterfacePath, |
|||
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid, |
|||
[In] IntPtr activationParams, // n.b. is actually a pointer to a PropVariant, but we never need to pass anything but null
|
|||
[In] IActivateAudioInterfaceCompletionHandler completionHandler, |
|||
out IActivateAudioInterfaceAsyncOperation activationOperation); |
|||
} |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue