尔冬橙

博客园 首页 新随笔 联系 订阅 管理
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
}

 

posted on 2013-01-04 21:19  尔冬橙  阅读(2508)  评论(6编辑  收藏  举报