桌面录音

  公司做一个项目,需要把 windows 扬声器的声音捕捉下来,这个可以参考MSDN文档,上面有示例程序:
Loopback Recording

Capturing a Stream

这程序并不完整,还需要做一些修改才行:

下面是我 调试通过的代码:

#include <Mmdeviceapi.h>
#include <Audioclient.h>

//-----------------------------------------------------------
// Record an audio stream from the default audio capture
// device. The RecordAudioStream function allocates a shared
// buffer big enough to hold one second of PCM audio data.
// The function uses this buffer to stream data from the
// capture device. The main loop runs every 1/2 second.
//-----------------------------------------------------------

// REFERENCE_TIME time units per second and per millisecond
#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);



class MyAudioSink {
public:
        //WAVEFORMATEX *pwfx = NULL;
        int     SetFormat(WAVEFORMATEX *pwfx);

        int     CopyData(char * pData,UINT32 numFramesAvailable,BOOL *pbDone);
};



int MyAudioSink::SetFormat(WAVEFORMATEX *pwfx)
{
    printf("wFormatTag is %x\n",        pwfx->wFormatTag);
    printf("nChannels is %x\n",         pwfx->nChannels);
    printf("nSamplesPerSec is %d\n",    pwfx->nSamplesPerSec);
    printf("nAvgBytesPerSec is %d\n",   pwfx->nAvgBytesPerSec);
    printf("wBitsPerSample is %d\n",    pwfx->wBitsPerSample);

    return 0;
}

int MyAudioSink::CopyData(char *    pData,UINT32 numFramesAvailable,BOOL *pbDone)
{
    if(pData != NULL)
        fwrite(pData, numFramesAvailable ,1,fp);

    return 0;
}

/// pwfx->nSamplesPerSec    = 44100; 
/// 不支持修改采样率, 看来只能等得到数据之后再 swr 转换了 
BOOL AdjustFormatTo16Bits(WAVEFORMATEX *pwfx)
{
    BOOL bRet(FALSE);

    if(pwfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
    {
        pwfx->wFormatTag = WAVE_FORMAT_PCM;
        pwfx->wBitsPerSample = 16;
        pwfx->nBlockAlign = pwfx->nChannels * pwfx->wBitsPerSample / 8;
        pwfx->nAvgBytesPerSec = pwfx->nBlockAlign * pwfx->nSamplesPerSec;

        bRet = TRUE;
    }
    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;
           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);

    REFERENCE_TIME          hnsRequestedDuration    = REFTIMES_PER_SEC;
    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 /*eCapture*/, 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 ,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); // convert to milliseconds

    BOOL bOK = 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] = { /*htemp hEventStop,*/ hTimerWakeUp };

    // Each loop fills about half of the shared buffer.
    while (bDone == FALSE)
    {
        // Sleep for half the buffer duration.
        //Sleep(hnsActualDuration/REFTIMES_PER_MILLISEC/2);
        //WaitForSingleObject(hTimerWakeUp,INFINITE);
        WaitForMultipleObjects(sizeof(waitArray)/sizeof(waitArray[0]), waitArray, FALSE, INFINITE);
        //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)

            //if (flags & AUDCLNT_BUFFERFLAGS_SILENT)
            //{
            //  pData = NULL;  // Tell CopyData to write silence.
            //}

            // 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 _tmain(int argc, _TCHAR* argv[])
{
    fp      = fopen("F://work//record.pcm","wb");
    CoInitialize(NULL);
    MyAudioSink test;

    RecordAudioStream(&test);

    return 0;
}

留着以后使用

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值