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 }