huo821894237 2017-03-31 07:01 采纳率: 0%
浏览 2842

基于WASAPI的音频捕获和音频播放,注意“禁用前面板插孔检测”。

http://blog.csdn.net/XscKernel/article/details/52204853#cpp
参照该博主的文章,再次感谢。

需要安装windows SDKs,还用到ksuser和Ole32两个库。

  • 写回答

2条回答 默认 最新

  • huo821894237 2017-03-31 07:02
    关注

    录音:

     #include <mmdeviceapi.h>
    #include <Audioclient.h>
    #include <windows.h>
    #include <stdio.h>
    #include <string.h>
    
    #define REFTIMES_PER_SEC        10000000
    #define REFTIMES_PER_MILLISEC   10000
    
    #define EXIT_ON_ERROR(hres)  \
        if (FAILED(hres)) { goto Exit; }
    
    #define SAFE_RELEASE(punk)  \
        if ((punk) != NULL) { (punk)->Release(); (punk) = NULL; }
    
    const CLSID CLSID_MMDeviceEnumerator    = __uuidof(MMDeviceEnumerator);
    const IID IID_IMMDeviceEnumerator       = __uuidof(IMMDeviceEnumerator);
    const IID IID_IAudioClient              = __uuidof(IAudioClient);
    const IID IID_IAudioCaptureClient       = __uuidof(IAudioCaptureClient);
    
    FILE *fp = NULL;
    
    class MyAudioSink {
    public:
        int SetFormat(WAVEFORMATEX *pwfx);
        int CopyData(char *pData, UINT32 numFramesAvailable, BOOL *pbDone);
    };
    
    int MyAudioSink::SetFormat(WAVEFORMATEX *pwfx)
    {
        FILE *fp = fopen("capture_format.txt", "w");
        char str[128];
        sprintf(str, "wFormatTag \t\tis %x\nnChannels \t\tis %d\nnSamplesPerSec \tis %ld\nnAvgBytesPerSec is %ld\nwBitsPerSample \tis %d",
                pwfx->wFormatTag, pwfx->nChannels, pwfx->nSamplesPerSec, pwfx->nAvgBytesPerSec, pwfx->wBitsPerSample);
        fwrite(str, 1, strlen(str), fp);
        fclose(fp);
        return 0;
    }
    
    int MyAudioSink::CopyData(char *pData, UINT32 numFramesAvailable, BOOL *pbDone)
    {
        if(pData != NULL)
            fwrite(pData, numFramesAvailable, 1, fp);
        return 0;
    }
    
    // pwfx->nSamplesPerSec = 44100;
    BOOL AdjustFormatTo16Bits(WAVEFORMATEX *pwfx)
    {
        BOOL bRet(FALSE);
        if(pwfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
            pwfx->wFormatTag = WAVE_FORMAT_PCM;
        else if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
        {
            PWAVEFORMATEXTENSIBLE pEx = reinterpret_cast<PWAVEFORMATEXTENSIBLE>(pwfx);
            if (IsEqualGUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, pEx->SubFormat))
            {
                pEx->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
                pEx->Samples.wValidBitsPerSample = 16;
            }
        }
        else
            return bRet;
        pwfx->wBitsPerSample = 16;
        pwfx->nBlockAlign = pwfx->nChannels * pwfx->wBitsPerSample / 8;
        pwfx->nAvgBytesPerSec = pwfx->nBlockAlign * pwfx->nSamplesPerSec;
        bRet = TRUE;
        return bRet;
    }
    
    HRESULT RecordAudioStream(MyAudioSink *pMySink)
    {
        HRESULT         hr;
    //    REFERENCE_TIME  hnsActualDuration;
        UINT32          bufferFrameCount;
        UINT32          numFramesAvailable;
        BYTE *          pData;
        DWORD           flags;
        REFERENCE_TIME  hnsDefaultDevicePeriod(0);
    
        IMMDeviceEnumerator *   pEnumerator             = NULL;
        IMMDevice *             pDevice                 = NULL;
        IAudioClient *          pAudioClient            = NULL;
        IAudioCaptureClient *   pCaptureClient          = NULL;
        WAVEFORMATEX *          pwfx                    = NULL;
        UINT32                  packetLength            = 0;
        BOOL                    bDone                   = FALSE;
        HANDLE                  hTimerWakeUp            = NULL;
    
        hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&pEnumerator);
        EXIT_ON_ERROR(hr)
    
        hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice);
        EXIT_ON_ERROR(hr)
    
        hr = pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pAudioClient);
        EXIT_ON_ERROR(hr)
    
        hr = pAudioClient->GetDevicePeriod(&hnsDefaultDevicePeriod, NULL);
    
        hr = pAudioClient->GetMixFormat(&pwfx);
        EXIT_ON_ERROR(hr)
    
        AdjustFormatTo16Bits(pwfx);
    
        hTimerWakeUp = CreateWaitableTimer(NULL, FALSE, NULL);
    
        hr = pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_LOOPBACK, 0, 0, pwfx, NULL);
        EXIT_ON_ERROR(hr)
    
        // Get the size of the allocated buffer.
        hr = pAudioClient->GetBufferSize(&bufferFrameCount);
        EXIT_ON_ERROR(hr)
    
        hr = pAudioClient->GetService(IID_IAudioCaptureClient, (void**)&pCaptureClient);
        EXIT_ON_ERROR(hr)
    
        LARGE_INTEGER liFirstFire;
        liFirstFire.QuadPart = -hnsDefaultDevicePeriod / 2; // negative means relative time
        LONG lTimeBetweenFires = (LONG)hnsDefaultDevicePeriod / 2 / (10 * 1000);
    
        SetWaitableTimer(hTimerWakeUp, &liFirstFire, lTimeBetweenFires, NULL, NULL, FALSE);
    
        // Notify the audio sink which format to use.
        hr = pMySink->SetFormat(pwfx);
        EXIT_ON_ERROR(hr)
    
        // Calculate the actual duration of the allocated buffer.
    //    hnsActualDuration = (double)REFTIMES_PER_SEC * bufferFrameCount / pwfx->nSamplesPerSec;
    
        hr = pAudioClient->Start();  // Start recording.
        EXIT_ON_ERROR(hr)
    
        HANDLE waitArray[1] = {hTimerWakeUp};
    
        // Each loop fills about half of the shared buffer.
        while (bDone == FALSE)
        {
            WaitForMultipleObjects(sizeof(waitArray) / sizeof(waitArray[0]), waitArray, FALSE, INFINITE);
    
            hr = pCaptureClient->GetNextPacketSize(&packetLength);
            EXIT_ON_ERROR(hr)
    
            while (packetLength != 0)
            {
                // Get the available data in the shared buffer.
                hr = pCaptureClient->GetBuffer(&pData, &numFramesAvailable, &flags, NULL, NULL);
                EXIT_ON_ERROR(hr)
    
                // Copy the available capture data to the audio sink.
                hr = pMySink->CopyData((char *)pData, numFramesAvailable * pwfx->nBlockAlign, &bDone);
                EXIT_ON_ERROR(hr)
    
                hr = pCaptureClient->ReleaseBuffer(numFramesAvailable);
                EXIT_ON_ERROR(hr)
    
                hr = pCaptureClient->GetNextPacketSize(&packetLength);
                EXIT_ON_ERROR(hr)
            }
        }
    
        hr = pAudioClient->Stop();  // Stop recording.
        EXIT_ON_ERROR(hr)
    
    Exit:
        CoTaskMemFree(pwfx);
        SAFE_RELEASE(pEnumerator)
        SAFE_RELEASE(pDevice)
        SAFE_RELEASE(pAudioClient)
        SAFE_RELEASE(pCaptureClient)
    
        return hr;
    }
    
    int main()
    {
        fp = fopen("foobar","wb");
        MyAudioSink test;
    
        CoInitialize(NULL);
        RecordAudioStream(&test);
        CoUninitialize();
    
        fclose(fp);
        return 0;
    }
    
    

    播放:

     #include <mmdeviceapi.h>
    #include <Audioclient.h>
    #include <windows.h>
    #include <stdio.h>
    #include <string.h>
    
    #define REFTIMES_PER_SEC        10000000
    #define REFTIMES_PER_MILLISEC   10000
    
    #define EXIT_ON_ERROR(hres)  \
        if (FAILED(hres)) { goto Exit; }
    
    #define SAFE_RELEASE(punk)  \
        if ((punk) != NULL) { (punk)->Release(); (punk) = NULL; }
    
    const CLSID CLSID_MMDeviceEnumerator    = __uuidof(MMDeviceEnumerator);
    const IID IID_IMMDeviceEnumerator       = __uuidof(IMMDeviceEnumerator);
    const IID IID_IAudioClient              = __uuidof(IAudioClient);
    const IID IID_IAudioRenderClient        = __uuidof(IAudioRenderClient);
    
    FILE *fp = NULL;
    
    class MyAudioSource {
    public:
        int SetFormat(WAVEFORMATEX *pwfx);
        int LoadData(UINT32 numFramesAvailable, char *pData, DWORD *pbDone);
    };
    
    int MyAudioSource::SetFormat(WAVEFORMATEX *pwfx)
    {
        FILE *fp = fopen("render_format.txt", "w");
        char str[128];
        sprintf(str, "wFormatTag \t\tis %x\nnChannels \t\tis %d\nnSamplesPerSec \tis %ld\nnAvgBytesPerSec is %ld\nwBitsPerSample \tis %d",
                pwfx->wFormatTag, pwfx->nChannels, pwfx->nSamplesPerSec, pwfx->nAvgBytesPerSec, pwfx->wBitsPerSample);
        fwrite(str, 1, strlen(str), fp);
        fclose(fp);
        return 0;
    }
    
    int MyAudioSource::LoadData(UINT32 numFramesAvailable, char *pData, DWORD *pbDone)
    {
        int ret = fread(pData, 1, numFramesAvailable, fp);
        printf("fread returns %d\n", ret);
        if(0 == ret)
            *pbDone = AUDCLNT_BUFFERFLAGS_SILENT;
        return 0;
    }
    
    BOOL AdjustFormatTo16Bits(WAVEFORMATEX *pwfx)
    {
        BOOL bRet(FALSE);
        if(pwfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
            pwfx->wFormatTag = WAVE_FORMAT_PCM;
        else if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
        {
            PWAVEFORMATEXTENSIBLE pEx = reinterpret_cast<PWAVEFORMATEXTENSIBLE>(pwfx);
            if (IsEqualGUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, pEx->SubFormat))
            {
                pEx->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
                pEx->Samples.wValidBitsPerSample = 16;
            }
        }
        else
            return bRet;
        pwfx->wBitsPerSample = 16;
        pwfx->nBlockAlign = pwfx->nChannels * pwfx->wBitsPerSample / 8;
        pwfx->nAvgBytesPerSec = pwfx->nBlockAlign * pwfx->nSamplesPerSec;
        bRet = TRUE;
        return bRet;
    }
    
    HRESULT PlayAudioStream(MyAudioSource *pMySource)
    {
        HRESULT hr;
        REFERENCE_TIME hnsRequestedDuration = REFTIMES_PER_SEC;
        REFERENCE_TIME hnsActualDuration;
        IMMDeviceEnumerator *pEnumerator = NULL;
        IMMDevice *pDevice = NULL;
        IAudioClient *pAudioClient = NULL;
        IAudioRenderClient *pRenderClient = NULL;
        WAVEFORMATEX *pwfx = NULL;
        UINT32 bufferFrameCount;
        UINT32 numFramesAvailable;
        UINT32 numFramesPadding;
        BYTE *pData;
        DWORD flags = 0;
    
        hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&pEnumerator);
        EXIT_ON_ERROR(hr)
    
        hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice);
        EXIT_ON_ERROR(hr)
    
        hr = pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pAudioClient);
        EXIT_ON_ERROR(hr)
    
        hr = pAudioClient->GetMixFormat(&pwfx);
        EXIT_ON_ERROR(hr)
    
        AdjustFormatTo16Bits(pwfx);
    
        hr = pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, hnsRequestedDuration, 0, pwfx, NULL);
        EXIT_ON_ERROR(hr)
    
        // Tell the audio source which format to use.
        hr = pMySource->SetFormat(pwfx);
        EXIT_ON_ERROR(hr)
    
        // Get the actual size of the allocated buffer.
        hr = pAudioClient->GetBufferSize(&bufferFrameCount);
        EXIT_ON_ERROR(hr)
    
        hr = pAudioClient->GetService(IID_IAudioRenderClient, (void**)&pRenderClient);
        EXIT_ON_ERROR(hr)
    
        // Grab the entire buffer for the initial fill operation.
        hr = pRenderClient->GetBuffer(bufferFrameCount, &pData);
        EXIT_ON_ERROR(hr)
    
        // Load the initial data into the shared buffer.
        hr = pMySource->LoadData(bufferFrameCount * pwfx->nBlockAlign, (char *)pData, &flags);
        EXIT_ON_ERROR(hr)
    
        hr = pRenderClient->ReleaseBuffer(bufferFrameCount, flags);
        EXIT_ON_ERROR(hr)
    
        // Calculate the actual duration of the allocated buffer.
        hnsActualDuration = (double)REFTIMES_PER_SEC * bufferFrameCount / pwfx->nSamplesPerSec;
    
        hr = pAudioClient->Start();  // Start playing.
        EXIT_ON_ERROR(hr)
    
        // Each loop fills about half of the shared buffer.
        while (flags != AUDCLNT_BUFFERFLAGS_SILENT)
        {
            // Sleep for half the buffer duration.
            Sleep((DWORD)(hnsActualDuration / REFTIMES_PER_MILLISEC / 2));
    
            // See how much buffer space is available.
            hr = pAudioClient->GetCurrentPadding(&numFramesPadding);
            EXIT_ON_ERROR(hr)
    
            numFramesAvailable = bufferFrameCount - numFramesPadding;
    
            // Grab all the available space in the shared buffer.
            hr = pRenderClient->GetBuffer(numFramesAvailable, &pData);
            EXIT_ON_ERROR(hr)
    
            // Get next 1/2-second of data from the audio source.
            hr = pMySource->LoadData(numFramesAvailable * pwfx->nBlockAlign, (char *)pData, &flags);
            EXIT_ON_ERROR(hr)
    
            hr = pRenderClient->ReleaseBuffer(numFramesAvailable, flags);
            EXIT_ON_ERROR(hr)
        }
    
        // Wait for last data in buffer to play before stopping.
        Sleep((DWORD)(hnsActualDuration / REFTIMES_PER_MILLISEC / 2));
    
        hr = pAudioClient->Stop();  // Stop playing.
        EXIT_ON_ERROR(hr)
    
    Exit:
        CoTaskMemFree(pwfx);
        SAFE_RELEASE(pEnumerator)
        SAFE_RELEASE(pDevice)
        SAFE_RELEASE(pAudioClient)
        SAFE_RELEASE(pRenderClient)
    
        return hr;
    }
    
    int main()
    {
        fp = fopen("foobar","rb");
        MyAudioSource test;
    
        CoInitialize(NULL);
        PlayAudioStream(&test);
        CoUninitialize();
    
        fclose(fp);
        return 0;
    }
    
    
    评论

报告相同问题?

悬赏问题

  • ¥100 Jenkins自动化部署—悬赏100元
  • ¥15 关于#python#的问题:求帮写python代码
  • ¥20 MATLAB画图图形出现上下震荡的线条
  • ¥15 关于#windows#的问题:怎么用WIN 11系统的电脑 克隆WIN NT3.51-4.0系统的硬盘
  • ¥15 perl MISA分析p3_in脚本出错
  • ¥15 k8s部署jupyterlab,jupyterlab保存不了文件
  • ¥15 ubuntu虚拟机打包apk错误
  • ¥199 rust编程架构设计的方案 有偿
  • ¥15 回答4f系统的像差计算
  • ¥15 java如何提取出pdf里的文字?