using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
namespace HuaXuApp
{
//IAudioClient sample, (c) 2012 Lucian Wischik
//------------------------------------------------
//In Windows 8 store apps, the waveOut family of functions are no longer available.
//The closest alternative is IAudioClient. In this sample we construct PCM buffers by
// writing to a memory array, and send them to the IAudioClient.
//IAudioClient has a simple playback sample here: http://msdn.microsoft.com/en-us/library/windows/desktop/dd316756(v=vs.85).aspx
//and a capture sample here: http://msdn.microsoft.com/en-us/library/windows/desktop/dd370800(v=vs.85).aspx
//For Win8 app store you obtain IAudioClient slightly differently, as in this sample: http://code.msdn.microsoft.com/windowsapps/Windows-Audio-Session-22dcab6b
//Module Module1
//Sub Main()
// Dim p As New ConsoleProgress
// p.Report("---- Using .NET45 ----")
// TestFromConsoleAsync(p).GetAwaiter().GetResult()
// p.Report("---- WinRT ----")
// TestFromWin8Async(p).GetAwaiter().GetResult()
//End Sub
//Class ConsoleProgress
// Implements IProgress(Of String)
// Public Sub Report(value As String) Implements IProgress(Of String).Report
// Console.WriteLine(value)
// End Sub
//End Class
//Async Function TestFromConsoleAsync(progress As IProgress(Of String)) As Task
// Dim pEnum = CType(New MMDeviceEnumerator, IMMDeviceEnumerator)
// // Enumerating devices...
// Dim pDevices As IMMDeviceCollection = Nothing : pEnum.EnumAudioEndpoints(EDataFlow.eAll, DeviceStateFlags.DEVICE_STATE_ACTIVE, pDevices)
// Dim pcDevices = 0 : pDevices.GetCount(pcDevices)
// For i = 0 To pcDevices - 1
// Dim pDevice As IMMDevice = Nothing : pDevices.Item(i, pDevice)
// Dim pProps As IPropertyStore = Nothing : pDevice.OpenPropertyStore(StgmMode.STGM_READ, pProps)
// Dim varName As PROPVARIANT = Nothing : pProps.GetValue(PKEY_Device_FriendlyName, varName)
// progress.Report(CStr(varName.Value))
// PropVariantClear(varName)
// Runtime.InteropServices.Marshal.FinalReleaseComObject(pProps) : pProps = Nothing
// Runtime.InteropServices.Marshal.FinalReleaseComObject(pDevice)
// Next
// Runtime.InteropServices.Marshal.FinalReleaseComObject(pDevices) : pDevices = Nothing
// progress.Report("")
// // Generating audio programmatically
// Dim buf1 = Await GenerateAudioAsync()
// // Recording audio
// Dim pDeviceR As IMMDevice = Nothing : pEnum.GetDefaultAudioEndpoint(EDataFlow.eCapture, ERole.eConsole, pDeviceR)
// Dim pAudioClientR As IAudioClient2 = Nothing : pDeviceR.Activate(IID_IAudioClient2, CLSCTX.CLSCTX_ALL, Nothing, pAudioClientR)
// Runtime.InteropServices.Marshal.FinalReleaseComObject(pDeviceR) : pDeviceR = Nothing
// InitializeAudioClient(pAudioClientR)
// Dim reportInstructionsTask = ReportInstructionsAsync(progress)
// Dim buf2 = Await RecordSoundFromAudioClientAsync(pAudioClientR, progress)
// Await reportInstructionsTask
// Await Task.Delay(100)
// Runtime.InteropServices.Marshal.FinalReleaseComObject(pAudioClientR) : pAudioClientR = Nothing
// // Playing audio (two streams simultaneously - they share the audio device, but must be done on different IAudioClients)
// Dim pDeviceP1 As IMMDevice = Nothing : pEnum.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eConsole, pDeviceP1)
// Dim pAudioClientP1 As IAudioClient2 = Nothing : pDeviceP1.Activate(IID_IAudioClient2, CLSCTX.CLSCTX_ALL, Nothing, pAudioClientP1)
// Runtime.InteropServices.Marshal.FinalReleaseComObject(pDeviceP1) : pDeviceP1 = Nothing
// InitializeAudioClient(pAudioClientP1)
// //
// Dim pDeviceP2 As IMMDevice = Nothing : pEnum.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eConsole, pDeviceP2)
// Dim pAudioClientP2 As IAudioClient2 = Nothing : pDeviceP2.Activate(IID_IAudioClient2, CLSCTX.CLSCTX_ALL, Nothing, pAudioClientP2)
// Runtime.InteropServices.Marshal.FinalReleaseComObject(pDeviceP2) : pDeviceP2 = Nothing
// InitializeAudioClient(pAudioClientP2)
// //
// Dim playTask1 = PlaySoundOnAudioClientAsync(pAudioClientP1, buf1, progress)
// Dim playTask2 = PlaySoundOnAudioClientAsync(pAudioClientP2, buf2, progress)
// Await Task.WhenAll(playTask1, playTask2)
// //
// Runtime.InteropServices.Marshal.FinalReleaseComObject(pAudioClientP1) : pAudioClientP1 = Nothing
// Runtime.InteropServices.Marshal.FinalReleaseComObject(pAudioClientP2) : pAudioClientP2 = Nothing
// Runtime.InteropServices.Marshal.FinalReleaseComObject(pEnum) : pEnum = Nothing
//End Function
public class AudioClient
{
public IAudioClient2 pAudioClientR;
public async Task TestFromWin8Async( IProgress<string> progress)
{
//默认角色中用于音频捕获设备的标识字符串
string defaultDeviceIdR = Windows.Media.Devices.MediaDevice.GetDefaultAudioCaptureId(Windows.Media.Devices.AudioDeviceRole.Default);
//默认角色中用于音频呈现设备的标识字符串
string defaultDeviceIdP = Windows.Media.Devices.MediaDevice.GetDefaultAudioRenderId(Windows.Media.Devices.AudioDeviceRole.Default);
// We can enumerate devices as follows:
//枚举音频捕获和音频呈现的设备
string audioSelectorR = Windows.Media.Devices.MediaDevice.GetAudioCaptureSelector();
Windows.Devices.Enumeration.DeviceInformationCollection devicesR = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(audioSelectorR, new List<string>() { Interop.PKEY_AudioEndpoint_Supports_EventDriven_Mode.ToString() });
string audioSelectorP = Windows.Media.Devices.MediaDevice.GetAudioRenderSelector();
Windows.Devices.Enumeration.DeviceInformationCollection devicesP = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(audioSelectorP, new List<string>() { Interop.PKEY_AudioEndpoint_Supports_EventDriven_Mode.ToString() });
//foreach(var device in devicesR.Concat(devicesP))
//{
// progress.Report((device.Id == defaultDeviceIdP ? "P ":(device.Id == defaultDeviceIdR ? "R ":" ")) + device.Name);
//}
//progress.Report("");
// Generating audio programmatically
//调用GenerateAudioAsync通过编程的方式产生音频
//short[] buf1 = await GenerateAudioAsync();
// Recording audio
// CAPABILITY: Microphone
// PERMISSION: Microphone - it pops up a blocking alert in InitializeAudioClient the first time after installation, and
// on subsequent attempts it either succeeds or fails depending on whether the user has granted permission
//Dim icbhR As New ActivateAudioInterfaceCompletionHandler(AddressOf InitializeAudioClient)
//录音
//第一次运行的时候会弹出是否允许使用麦克风的消息框。需要在Package.appxmanifest里配置使用麦克风。
//初始化音频设备
ActivateAudioInterfaceCompletionHandler icbhR = new ActivateAudioInterfaceCompletionHandler(
(IAudioClient2 pAudioClient) =>
{
//实例化音频波形格式的结构体
WAVEFORMATEX wfx = new WAVEFORMATEX() { wFormatTag = 1, nChannels = 2, nSamplesPerSec = 44100, wBitsPerSample = 16, nBlockAlign = 4, nAvgBytesPerSec = 44100 * 4, cbSize = 0 };
//调用接口中的Initialize方法初始化音频设备
pAudioClient.Initialize(AUDCLNT_SHAREMODE.AUDCLNT_SHAREMODE_SHARED, AUDCLNT_FLAGS.AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_FLAGS.AUDCLNT_STREAMFLAGS_NOPERSIST, 1000000, 0, ref wfx, IntPtr.Zero);
}
);
IActivateAudioInterfaceAsyncOperation activationOperationR = null;
//允许windows应用商店程序访问WASAPI中的先前存在的COM接口。
Interop.ActivateAudioInterfaceAsync(defaultDeviceIdR, Interop.IID_IAudioClient2, IntPtr.Zero, icbhR, ref activationOperationR);
//存储音频数据的数组
short[] buf2 = {0, 0};
try
{
pAudioClientR = await icbhR;
//var reportInstructionsTask = ReportInstructionsAsync(progress);
buf2 = await RecordSoundFromAudioClientAsync(pAudioClientR, progress);
Marshal.FinalReleaseComObject(pAudioClientR);
pAudioClientR = null;
//await reportInstructionsTask;
}
catch( UnauthorizedAccessException ex /*When ex.HResult = -2147024891*/)
{
//progress.Report("OOPS! Can//t record. Please go to Charms > Settings > Permissions to grant microphone permission");
}
finally
{
Marshal.FinalReleaseComObject(activationOperationR);
activationOperationR = null;
}
// Playing audio (two streams simultaneously - they share the audio device, but must be done on different IAudioClients)
//ActivateAudioInterfaceCompletionHandler icbhP1 = new ActivateAudioInterfaceCompletionHandler(InitializeAudioClient);
//IActivateAudioInterfaceAsyncOperation activationOperationP1 = null;
//Interop.ActivateAudioInterfaceAsync(defaultDeviceIdP, Interop.IID_IAudioClient2, IntPtr.Zero, icbhP1, ref activationOperationP1);
//var pAudioClientP1 = await icbhP1;
//Marshal.FinalReleaseComObject(activationOperationP1);
//activationOperationP1 = null;
//
ActivateAudioInterfaceCompletionHandler icbhP2 = new ActivateAudioInterfaceCompletionHandler(InitializeAudioClient);
IActivateAudioInterfaceAsyncOperation activationOperationP2 = null;
Interop.ActivateAudioInterfaceAsync(defaultDeviceIdP, Interop.IID_IAudioClient2, IntPtr.Zero, icbhP2, ref activationOperationP2);
var pAudioClientP2 = await icbhP2;
Marshal.FinalReleaseComObject(activationOperationP2);
activationOperationP2 = null;
//
//var playTask1 = PlaySoundOnAudioClientAsync(pAudioClientP1, buf1, progress);
//var playTask2 = PlaySoundOnAudioClientAsync(pAudioClientP2, buf2, progress);
//await Task.WhenAll(playTask2);
//await Task.WhenAll(playTask1, playTask2);
//
//Marshal.FinalReleaseComObject(pAudioClientP1);
//pAudioClientP1 = null;
Marshal.FinalReleaseComObject(pAudioClientP2);
pAudioClientP2 = null;
}
public Task<short[]> GenerateAudioAsync()
{
return Task.Run(
()=> {
int[] MaryHadALittleLamb = {247, 220, 196, 220, 247, 247, 247, 220, 220, 220, 247, 294, 294};
short[] buf1 = new short[44100 * 2 * MaryHadALittleLamb.Length * 8 / 10];
var phase = 0.0;
for(int i = 0 ;i<= buf1.Length / 2 - 1;i++)
{
int imusic = MaryHadALittleLamb.Length * 10 * i * 2 / buf1.Length;
double freq = (imusic % 10 == 0 ? 0: MaryHadALittleLamb[imusic / 10]);
phase += freq * 2.0 * 3.1415 / 44100.0;
short amp = Convert.ToInt16(Math.Sin(phase) * 0.5 * short.MaxValue - 1);
buf1[i * 2 + 0] = amp;
buf1[i * 2 + 1] = amp;
}
return buf1;
});
}
public async Task ReportInstructionsAsync(IProgress<string> progress)
{
progress.Report(@"RECORDING HAS STARTED... please sing ""Mary had a little lamb""!" + Environment.NewLine + "...");
string[] str = {"Mary", "", "had", "a ", "little ", "", "lamb, ", "little ", "", "lamb, ", "little ", "", "lamb"};
foreach(string word in str)
{
if (!string.IsNullOrEmpty(word))
{
progress.Report(word);
}
await Task.Delay(800);
}
}
public void InitializeAudioClient(IAudioClient2 pAudioClient)
{
WAVEFORMATEX wfx = new WAVEFORMATEX() { wFormatTag = 1, nChannels = 2, nSamplesPerSec = 44100, wBitsPerSample = 16, nBlockAlign = 4, nAvgBytesPerSec = 44100 * 4, cbSize = 0 };
// Other alternative ways we could pick wave-format... (note that IsFormatSupported will return pwfx=Nothing if wfx was satisfactory)
IntPtr pwfx_default = IntPtr.Zero;
pAudioClient.GetMixFormat(ref pwfx_default); // we could ask it for its preferred format
WAVEFORMATEX wfx_default = (WAVEFORMATEX)(Marshal.PtrToStructure(pwfx_default,typeof(WAVEFORMATEX)));
if(pwfx_default != IntPtr.Zero)
{
Marshal.FreeCoTaskMem(pwfx_default);
pwfx_default = IntPtr.Zero;
}
IntPtr pwfx_suggested = IntPtr.Zero;
pAudioClient.IsFormatSupported(AUDCLNT_SHAREMODE.AUDCLNT_SHAREMODE_SHARED, ref wfx, ref pwfx_suggested);
if(pwfx_suggested != IntPtr.Zero)
{
var wfx_suggested = (WAVEFORMATEX)(Marshal.PtrToStructure(pwfx_suggested, typeof(WAVEFORMATEX)));
Marshal.FreeCoTaskMem(pwfx_suggested);
}
// If pAudioClient was initialized with IID_ICaptureClient, then...
// CAPABILITY: Microphone
// PERMISSION: Microphone (granted on the charms bar). The first time this app is run after installation, the call to
// Initialize() will block while a UI prompt is shown asking for permission. On subsequent runs, it will remember the
// answer, and either succeed immediately or return E_ACCESS_DENIED (UnathorizedAccessException When ex.HResult = -2147024891)
pAudioClient.Initialize(AUDCLNT_SHAREMODE.AUDCLNT_SHAREMODE_SHARED, AUDCLNT_FLAGS.AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_FLAGS.AUDCLNT_STREAMFLAGS_NOPERSIST, 10000000, 0, ref wfx, IntPtr.Zero);
}
public async Task<short[]> RecordSoundFromAudioClientAsync(IAudioClient2 pAudioClient,IProgress<string> progress)
{
IntPtr hEvent = Interop.CreateEventEx(IntPtr.Zero, IntPtr.Zero, 0, EventAccess.EVENT_ALL_ACCESS);
pAudioClient.SetEventHandle(hEvent);
int bufferFrameCount = 0;
pAudioClient.GetBufferSize(ref bufferFrameCount);
object ppv = null;
pAudioClient.GetService(Interop.IID_IAudioCaptureClient, ref ppv);
IAudioCaptureClient pCaptureClient = (IAudioCaptureClient)(ppv);
short[] buf = new short[44100 * 10 * 2]; // ten seconds of audio
int nFrames = 0;
pAudioClient.Start();
while(true)
{
await Interop.WaitForSingleObjectAsync(hEvent);
IntPtr pData = IntPtr.Zero; int NumFramesToRead = 0; int dwFlags = 0;
pCaptureClient.GetBuffer(ref pData, ref NumFramesToRead, ref dwFlags, IntPtr.Zero, IntPtr.Zero);
//int nFramesToCopy = Math.Min(NumFramesToRead, buf.Length / 2 - nFrames);
buf = new short[NumFramesToRead * 2];
//Marshal.Copy(pData, buf, nFrames * 2, nFramesToCopy * 2);
Marshal.Copy(pData, buf, 0, NumFramesToRead*2);
pCaptureClient.ReleaseBuffer(NumFramesToRead);
//nFrames += nFramesToCopy;
double Goal = 0;
for (int i = 0; i < buf.Length; i++)
{
if (buf[i] < 0)
{
Goal -= buf[i];
}
else
{
Goal += buf[i];
}
}
Goal = (int)Math.Abs(Goal / buf.Length);
//把值转换为分贝
if (Goal == 0) Goal = 1;
Goal = (int)(100 + (20 * Math.Log10(Goal * 1.0 / 32768)));
if (Goal < 74) Goal = 74;
if (Goal > 100) Goal = 100;
progress.Report(Goal.ToString());
//progress.Report(NumFramesToRead.ToString() + ":" + nFrames.ToString());
//if (nFrames >= buf.Length / 2)
//{
// break;
//}
}
pAudioClient.Stop();
Marshal.FinalReleaseComObject(pCaptureClient);
pCaptureClient = null;
Interop.CloseHandle(hEvent);
hEvent = IntPtr.Zero;
return buf;
}
public async Task PlaySoundOnAudioClientAsync(IAudioClient2 pAudioClient, short[] buf,IProgress<string> progress)
{
IntPtr hEvent = Interop.CreateEventEx(IntPtr.Zero, IntPtr.Zero, 0, EventAccess.EVENT_ALL_ACCESS);
pAudioClient.SetEventHandle(hEvent);
int bufferFrameCount = 0;
pAudioClient.GetBufferSize(ref bufferFrameCount);
object ppv = null;
pAudioClient.GetService(Interop.IID_IAudioRenderClient, ref ppv);
IAudioRenderClient pRenderClient = (IAudioRenderClient)(ppv);
int nFrame = 0;
pAudioClient.Start();
while(true)
{
await Interop.WaitForSingleObjectAsync(hEvent);
int numFramesPadding = 0;
pAudioClient.GetCurrentPadding(ref numFramesPadding);
int numFramesAvailable = bufferFrameCount - numFramesPadding;
if(numFramesAvailable == 0 ) continue;
int numFramesToCopy = Math.Min(numFramesAvailable, buf.Length / 2 - nFrame);
IntPtr pData = IntPtr.Zero;
pRenderClient.GetBuffer(numFramesToCopy, ref pData);
Marshal.Copy(buf, nFrame * 2, pData, numFramesToCopy * 2);
pRenderClient.ReleaseBuffer(numFramesToCopy, 0);
nFrame += numFramesToCopy;
if(nFrame >= buf.Length / 2) break;
}
// and wait until the buffer plays out to the end
while(true)
{
int numFramesPadding = 0;
pAudioClient.GetCurrentPadding(ref numFramesPadding);
if(numFramesPadding == 0) break;
await Task.Delay(20);
}
pAudioClient.Stop();
Marshal.FinalReleaseComObject(pRenderClient);
pRenderClient = null;
Interop.CloseHandle(hEvent);
hEvent = IntPtr.Zero;
}
}
public class ActivateAudioInterfaceCompletionHandler: IActivateAudioInterfaceCompletionHandler, IAgileObject
{
private Action<IAudioClient2> InitializeAction;
private TaskCompletionSource<IAudioClient2> tcs = new TaskCompletionSource<IAudioClient2>();
public ActivateAudioInterfaceCompletionHandler(Action<IAudioClient2> InitializeAction)
{
if(InitializeAction == null)throw new NullReferenceException(@"Must do IAudioClient.Initialize in the callback; in case of recording, it might pop up a permissions prompt, and block");
this.InitializeAction = InitializeAction;
}
void IActivateAudioInterfaceCompletionHandler.ActivateCompleted(IActivateAudioInterfaceAsyncOperation activateOperation )
{
// First get the activation results, and see if anything bad happened then
int hr = 0;object unk = null;
activateOperation.GetActivateResult(ref hr, ref unk);
if(hr != 0)
{
tcs.TrySetException(Marshal.GetExceptionForHR(hr, new IntPtr(-1)));
return;
}
IAudioClient2 pAudioClient = (IAudioClient2)(unk);
// Next try to call the client//s (synchronous, blocking) initialization method. We trust that WinRT
// has invoked our callback on a thread where it//s okay to block.
try
{
InitializeAction(pAudioClient);
tcs.SetResult(pAudioClient);
}
catch(Exception ex)
{
tcs.TrySetException(ex);
}
}
public TaskAwaiter<IAudioClient2> GetAwaiter()
{
return tcs.Task.GetAwaiter();
}
//<Runtime.InteropServices.ComImport, Runtime.InteropServices.Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")> Class MMDeviceEnumerator
//End Class
//<Runtime.InteropServices.ComImport, Runtime.InteropServices.InterfaceType(Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown), Runtime.InteropServices.Guid("A95664D2-9614-4F35-A746-DE8DB63617E6")>
//Public Interface IMMDeviceEnumerator
// Sub EnumAudioEndpoints(dataflow As EDataFlow, dwStateMask As DeviceStateFlags, ByRef ppDevices As IMMDeviceCollection)
// Sub GetDefaultAudioEndpoint(dataflow As EDataFlow, role As ERole, ByRef ppDevice As IMMDevice)
// Sub GetDevice(<Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPWStr)> pwstrId As String, ByRef ppDevice As IntPtr)
// Sub RegisterEndpointNotificationCallback(pClient As IntPtr)
// Sub UnregisterEndpointNotificationCallback(pClient As IntPtr)
//End Interface
//<Runtime.InteropServices.ComImport, Runtime.InteropServices.InterfaceType(Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown), Runtime.InteropServices.Guid("0BD7A1BE-7A1A-44DB-8397-CC5392387B5E")>
//Public Interface IMMDeviceCollection
// Sub GetCount(ByRef pcDevices As Integer)
// Sub Item(nDevice As Integer, ByRef ppDevice As IMMDevice)
//End Interface
//<Runtime.InteropServices.ComImport, Runtime.InteropServices.InterfaceType(Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown), Runtime.InteropServices.Guid("D666063F-1587-4E43-81F1-B948E807363F")>
//Public Interface IMMDevice
// Sub Activate(<Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> iid As Guid, dwClsCtx As CLSCTX, pActivationParams As IntPtr, ByRef ppInterface As IAudioClient2)
// Sub OpenPropertyStore(stgmAccess As Integer, ByRef ppProperties As IPropertyStore)
// Sub GetId(<Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPWStr)> ByRef ppstrId As String)
// Sub GetState(ByRef pdwState As Integer)
//End Interface
//<Runtime.InteropServices.ComImport, Runtime.InteropServices.InterfaceType(Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown), Runtime.InteropServices.Guid("886d8eeb-8cf2-4446-8d02-cdba1dbdcf99")>
//Public Interface IPropertyStore
// //virtual HRESULT STDMETHODCALLTYPE GetCount(/*[out]*/ __RPC__out DWORD *cProps)
// Sub GetCount(ByRef cProps As Integer)
// //virtual HRESULT STDMETHODCALLTYPE GetAt(/*Runtime.InteropServices.In*/ DWORD iProp, /*[out]*/ __RPC__out PROPERTYKEY *pkey)
// Sub GetAt(iProp As Integer, ByRef pkey As IntPtr)
// //virtual HRESULT STDMETHODCALLTYPE GetValue(/*Runtime.InteropServices.In*/ __RPC__in REFPROPERTYKEY key, /*[out]*/ __RPC__out PROPVARIANT *pv)
// Sub GetValue(ByRef key As PROPERTYKEY, ByRef pv As PROPVARIANT)
// //virtual HRESULT STDMETHODCALLTYPE SetValue(/*Runtime.InteropServices.In*/ __RPC__in REFPROPERTYKEY key, /*Runtime.InteropServices.In*/ __RPC__in REFPROPVARIANT propvar)
// Sub SetValue(ByRef key As PROPERTYKEY, ByRef propvar As IntPtr)
// //virtual HRESULT STDMETHODCALLTYPE Commit()
// Sub Commit()
//End Interface
}
public static class Interop
{
public static Task WaitForSingleObjectAsync(IntPtr hEvent)
{
return Task.Run(() =>
{
int r = WaitForSingleObjectEx(hEvent, unchecked((int)0xFFFFFFFF), true);
if (r != 0) { throw new Exception("Unexpected event"); }
}
);
}
[DllImport("Mmdevapi.dll", ExactSpelling = true, PreserveSig = false)]
public static extern void ActivateAudioInterfaceAsync([MarshalAs(UnmanagedType.LPWStr)] string deviceInterfacePath, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, IntPtr activationParams, IActivateAudioInterfaceCompletionHandler completionHandler, ref IActivateAudioInterfaceAsyncOperation activationOperation);
//<Runtime.InteropServices.DllImport("ole32.dll", ExactSpelling:=True, PreserveSig:=False)>
//Public Sub PropVariantClear(ByRef pvar As PROPVARIANT)
//End Sub
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = false, PreserveSig = true, SetLastError = true)]
public static extern IntPtr CreateEventEx(IntPtr lpEventAttributes, IntPtr lpName, int dwFlags, EventAccess dwDesiredAccess);
[DllImport("kernel32.dll", ExactSpelling = true, PreserveSig = true, SetLastError = true)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32", ExactSpelling = true, PreserveSig = true, SetLastError = true)]
public static extern int WaitForSingleObjectEx(IntPtr hEvent, int milliseconds, bool bAlertable);
//Public ReadOnly PKEY_Device_FriendlyName As New PROPERTYKEY With {.fmtid = New Guid("a45c254e-df1c-4efd-8020-67d146a850e0"), .pid = 14}
//Public ReadOnly PKEY_Device_DeviceDesc As New PROPERTYKEY With {.fmtid = New Guid("a45c254e-df1c-4efd-8020-67d146a850e0"), .pid = 2}
public static readonly PROPERTYKEY PKEY_AudioEndpoint_Supports_EventDriven_Mode = new PROPERTYKEY() { fmtid = new Guid("1da5d803-d492-4edd-8c23-e0c0ffee7f0e"), pid = 7 };
public static readonly Guid IID_IAudioClient = new Guid("1CB9AD4C-DBFA-4c32-B178-C2F568A703B2");
public static readonly Guid IID_IAudioClient2 = new Guid("726778CD-F60A-4eda-82DE-E47610CD78AA");
public static readonly Guid IID_IAudioRenderClient = new Guid("F294ACFC-3146-4483-A7BF-ADDCA7C260E2");
public static readonly Guid IID_IAudioCaptureClient = new Guid("C8ADBD64-E71E-48a0-A4DE-185C395CD317");
}
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("1CB9AD4C-DBFA-4c32-B178-C2F568A703B2")]
public interface IAudioClient
{
void Initialize(AUDCLNT_SHAREMODE ShareMode, AUDCLNT_FLAGS StreamFlags, long hnsBufferDuration, long hnsPeriodicity, ref WAVEFORMATEX pFormat, IntPtr AudioSessionGuid);
//virtual HRESULT STDMETHODCALLTYPE GetBufferSize(/*[out]*/ _Out_ UINT32 *pNumBufferFrames) = 0;
void GetBufferSize(ref int pNumBufferFrames);
//virtual HRESULT STDMETHODCALLTYPE GetStreamLatency(/*[out]*/ _Out_ REFERENCE_TIME *phnsLatency) = 0;
void GetStreamLatency(ref long phnsLatency);
//virtual HRESULT STDMETHODCALLTYPE GetCurrentPadding(/*[out]*/ _Out_ UINT32 *pNumPaddingFrames) = 0;
void GetCurrentPadding(ref int pNumPaddingFrames);
//virtual HRESULT STDMETHODCALLTYPE IsFormatSupported(/*[in]*/ _In_ AUDCLNT_SHAREMODE ShareMode, /*[in]*/ _In_ const WAVEFORMATEX *pFormat, /*[unique][out]*/ _Out_opt_ WAVEFORMATEX **ppClosestMatch) = 0;
void IsFormatSupported(AUDCLNT_SHAREMODE ShareMode, ref WAVEFORMATEX pFormat, ref IntPtr ppClosestMatch);
//virtual HRESULT STDMETHODCALLTYPE GetMixFormat(/*[out]*/ _Out_ WAVEFORMATEX **ppDeviceFormat) = 0;
void GetMixFormat(ref IntPtr ppDeviceFormat);
//virtual HRESULT STDMETHODCALLTYPE GetDevicePeriod(/*[out]*/ _Out_opt_ REFERENCE_TIME *phnsDefaultDevicePeriod, /*[out]*/ _Out_opt_ REFERENCE_TIME *phnsMinimumDevicePeriod) = 0;
void GetDevicePeriod(ref long phnsDefaultDevicePeriod, ref long phnsMinimumDevicePeriod);
//virtual HRESULT STDMETHODCALLTYPE Start( void) = 0;
void Start();
//virtual HRESULT STDMETHODCALLTYPE Stop( void) = 0;
void Stop();
//virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0;
void Reset();
//virtual HRESULT STDMETHODCALLTYPE SetEventHandle(/*[in]*/ HANDLE eventHandle) = 0;
void SetEventHandle(IntPtr eventHandle);
//virtual HRESULT STDMETHODCALLTYPE GetService(/*[in]*/ _In_ REFIID riid, /*[iid_is][out]*/ _Out_ void **ppv) = 0;
void GetService([MarshalAs(UnmanagedType.LPStruct)] Guid riid, [MarshalAs(UnmanagedType.IUnknown)] ref object ppv);
}
[ComImport,InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("726778CD-F60A-4eda-82DE-E47610CD78AA")]
public interface IAudioClient2
{
void Initialize(AUDCLNT_SHAREMODE ShareMode, AUDCLNT_FLAGS StreamFlags, long hnsBufferDuration, long hnsPeriodicity, ref WAVEFORMATEX pFormat, IntPtr AudioSessionGuid);
void GetBufferSize(ref int pNumBufferFrames);
void GetStreamLatency(ref long phnsLatency);
void GetCurrentPadding(ref int pNumPaddingFrames);
void IsFormatSupported(AUDCLNT_SHAREMODE ShareMode, ref WAVEFORMATEX pFormat, ref IntPtr ppClosestMatch);
void GetMixFormat(ref IntPtr ppDeviceFormat);
void GetDevicePeriod(ref long phnsDefaultDevicePeriod, ref long phnsMinimumDevicePeriod);
void Start();
void Stop();
void Reset();
void SetEventHandle(IntPtr eventHandle);
void GetService([MarshalAs(UnmanagedType.LPStruct)] Guid riid, [MarshalAs(UnmanagedType.IUnknown)] ref object ppv);
//virtual HRESULT STDMETHODCALLTYPE IsOffloadCapable(/*[in]*/ _In_ AUDIO_STREAM_CATEGORY Category, /*[in]*/ _Out_ BOOL *pbOffloadCapable) = 0;
void IsOffloadCapable(int Category, ref bool pbOffloadCapable);
//virtual HRESULT STDMETHODCALLTYPE SetClientProperties(/*[in]*/ _In_ const AudioClientProperties *pProperties) = 0;
void SetClientProperties(IntPtr 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;
void GetBufferSizeLimits(IntPtr pFormat, bool bEventDriven, IntPtr phnsMinBufferDuration, IntPtr phnsMaxBufferDuration);
}
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("F294ACFC-3146-4483-A7BF-ADDCA7C260E2")]
public interface IAudioRenderClient
{
//virtual HRESULT STDMETHODCALLTYPE GetBuffer(/*[in]*/ _In_ UINT32 NumFramesRequested, /*[out]*/ _Outptr_result_buffer_(_Inexpressible_("NumFramesRequested * pFormat->nBlockAlign")) BYTE **ppData) = 0;
void GetBuffer(int NumFramesRequested, ref IntPtr ppData);
//virtual HRESULT STDMETHODCALLTYPE ReleaseBuffer(/*[in]*/ _In_ UINT32 NumFramesWritten, /*[in]*/ _In_ DWORD dwFlags) = 0;
void ReleaseBuffer(int NumFramesWritten, int dwFlags);
}
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown),Guid("C8ADBD64-E71E-48a0-A4DE-185C395CD317")]
public interface IAudioCaptureClient
{
//virtual HRESULT STDMETHODCALLTYPE GetBuffer(/*[out]*/ _Outptr_result_buffer_(_Inexpressible_("*pNumFramesToRead * pFormat->nBlockAlign")) BYTE **ppData, /*[out]*/ _Out_ UINT32 *pNumFramesToRead, /*[out]*/_Out_ DWORD *pdwFlags, /*[out]*/_Out_opt_ UINT64 *pu64DevicePosition, /*[out]*/_Out_opt_ UINT64 *pu64QPCPosition) = 0;
void GetBuffer(ref IntPtr ppData, ref int pNumFramesToRead, ref int pdwFlags, IntPtr pu64DevicePosition, IntPtr pu64QPCPosition);
//virtual HRESULT STDMETHODCALLTYPE ReleaseBuffer(/*[in]*/ _In_ UINT32 NumFramesRead) = 0;
void ReleaseBuffer(int NumFramesRead);
//virtual HRESULT STDMETHODCALLTYPE GetNextPacketSize(/*[out]*/ _Out_ UINT32 *pNumFramesInNextPacket) = 0;
void GetNextPacketSize(ref int pNumFramesInNextPacket);
}
[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);
}
[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(ref int activateResult, [MarshalAs(UnmanagedType.IUnknown)] ref object activateInterface);
}
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("94ea2b94-e9cc-49e0-c0ff-ee64ca8f5b90")]
public interface IAgileObject
{}
[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct WAVEFORMATEX
{
public short wFormatTag;
public short nChannels;
public int nSamplesPerSec;
public int nAvgBytesPerSec;
public short nBlockAlign;
public short wBitsPerSample;
public short cbSize;
}
//<Runtime.InteropServices.StructLayout(Runtime.InteropServices.LayoutKind.Sequential, Pack:=1)> Public Structure PROPVARIANT
// Dim vt As UShort
// Dim wReserved1 As UShort
// Dim wReserved2 As UShort
// Dim wReserved3 As UShort
// Dim p As IntPtr
// Dim p2 As Integer
// ReadOnly Property Value As Object
// Get
// Select Case vt
// Case 31 : Return Runtime.InteropServices.Marshal.PtrToStringUni(p) // VT_LPWSTR
// Case Else
// Throw New NotImplementedException
// End Select
// End Get
// End Property
//End Structure
[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct PROPERTYKEY
{
[MarshalAs(UnmanagedType.Struct)]
public Guid fmtid;
public int pid;
public override string ToString()
{
return "{" + fmtid.ToString() + "} " + pid.ToString();
}
}
//Enum EDataFlow
// eRender = 0
// eCapture = 1
// eAll = 2
// EDataFlow_enum_count = 3
//End Enum
//Enum ERole
// eConsole = 0
// eMultimedia = 1
// eCommunications = 2
// ERole_enum_count = 3
//End Enum
//Enum StgmMode
// STGM_READ = 0
// STGM_WRITE = 1
// STGM_READWRITE = 2
//End Enum
public enum AUDCLNT_SHAREMODE
{
AUDCLNT_SHAREMODE_SHARED = 0,
AUDCLNT_SHAREMODE_EXCLUSIVE = 1
}
//<Flags> Enum DeviceStateFlags
// DEVICE_STATE_ACTIVE = 1
// DEVICE_STATE_DISABLED = 2
// DEVICE_STATE_NOTPRESENT = 4
// DEVICE_STATE_UNPLUGGED = 8
// DEVICE_STATEMASK_ALL = 15
//End Enum
[Flags]
public enum AUDCLNT_FLAGS
{
AUDCLNT_STREAMFLAGS_CROSSPROCESS = 0x10000,
AUDCLNT_STREAMFLAGS_LOOPBACK = 0x20000,
AUDCLNT_STREAMFLAGS_EVENTCALLBACK = 0x40000,
AUDCLNT_STREAMFLAGS_NOPERSIST = 0x80000,
AUDCLNT_STREAMFLAGS_RATEADJUST = 0x100000,
AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED = 0x10000000,
AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE = 0x20000000,
AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED = 0x40000000
}
[Flags]
public enum EventAccess
{
STANDARD_RIGHTS_REQUIRED = 0x000F0000,
SYNCHRONIZE = 0x00100000,
EVENT_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3),
EVENT_MODIFY_STATE = 0x0002,
}
//<Flags> Enum CLSCTX
// CLSCTX_INPROC_SERVER = 1
// CLSCTX_INPROC_HANDLER = 2
// CLSCTX_LOCAL_SERVER = 4
// CLSCTX_REMOTE_SERVER = 16
// CLSCTX_ALL = CLSCTX_INPROC_SERVER Or CLSCTX_INPROC_HANDLER Or CLSCTX_LOCAL_SERVER Or CLSCTX_REMOTE_SERVER
//End Enum
}