📄 captureecho.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//==========================================================================;
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
//
//--------------------------------------------------------------------------;
#include "main.h"
#include "WinApp.h"
#include "ComUty.h"
#include "DebugUty.h"
#include "DSoundUty.h"
namespace
{
// Class CEvent
// ============
// This class wraps an event handle to ameliorate event lifetime
// management. Since we want the class size to be _exactly_ the same
// as the HANDLE we'll set the struct alignment to 1 byte.
# include <pshpack1.h>
class CEvent
{
public:
CEvent()
: m_hEvent(NULL)
{
}
~CEvent()
{
Close();
}
bool Create()
{
m_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
return m_hEvent!=NULL;
}
void Close()
{
if (m_hEvent!=NULL)
CloseHandle(m_hEvent);
m_hEvent=NULL;
}
operator HANDLE() // by returning an r-value, we still protect the data member
{
return m_hEvent;
}
protected:
HANDLE m_hEvent;
};
# include <poppack.h>
}
// class CCaptureEchoApplication
// =============================
// This class represents the application and is self-explanatory.
// See WinApp.h for info on CWindowsApplication
class CCaptureEchoApplication : public CWindowsApplication
{
public:
CCaptureEchoApplication();
virtual bool Initialize();
virtual void Run();
virtual void Shutdown();
virtual bool ProcessCommandLine();
private:
CComPointer<IDirectSound> m_piDS;
CComPointer<IDirectSoundCapture> m_piDSC;
CComPointer<IDirectSoundBuffer> m_piDSBPrimary;
DWORD m_dwTimeout;
DWORD m_dwDelay;
DWORD m_dwFormatIndex;
void DisplayUsage();
};
int
WINAPI
WinMain (
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPWSTR lpCmd,
int nCmdShow )
{
// Declare a single instance of the application.
CCaptureEchoApplication Application;
return CWindowsApplication::WinMain(hInstance, 0, lpCmd, nCmdShow);
}
CCaptureEchoApplication::CCaptureEchoApplication()
: m_dwTimeout(DEFAULT_TIMEOUT), // N-second default timeout
m_dwDelay(DEFAULT_DELAY), // N-second delay
m_dwFormatIndex(DEFAULT_CAPTURE_FORMAT) // 44kHz 16-bit stereo default
{
// Nothing to do here
}
bool CCaptureEchoApplication::Initialize()
{
HRESULT hr;
const DSBUFFERDESC dsbdPrimary = { sizeof(DSBUFFERDESC), DSBCAPS_PRIMARYBUFFER, 0, 0, NULL };
if (!CWindowsApplication::Initialize())
return false;
if (!ProcessCommandLine())
return false;
// Get the Direct Sound interface for the default Direct Sound object
hr = DirectSoundCreate(NULL, m_piDS.AsOutParam(), NULL);
CheckHRESULT(hr, "DirectSoundCreate", return false);
// Set the cooperative level
hr = m_piDS->SetCooperativeLevel(m_hWnd, DSSCL_NORMAL);
CheckHRESULT(hr, "IDirectSound::SetCooperativeLevel(DSSCL_NORMAL)", return false);
// Get the Direct Sound Capture interface for the default Direct Sound Capture object
hr = DirectSoundCaptureCreate(NULL, m_piDSC.AsOutParam(), NULL);
CheckHRESULT(hr, "DirectSoundCaptureCreate", return false);
// Create the primary sound buffer
hr = m_piDS->CreateSoundBuffer(&dsbdPrimary, m_piDSBPrimary.AsOutParam(), NULL);
CheckHRESULT(hr, "IDirectSound::CreateSoundBuffer for the primary sound buffer", return false);
// Play the primary sound buffer
hr = m_piDSBPrimary->Play(0,0,DSBPLAY_LOOPING);
CheckHRESULT(hr,"IDirectSoundBuffer::Play(Looping) on Primary Sound buffer", return false);
return true;
}
void CCaptureEchoApplication::Shutdown()
{
// Note: shutdown will be called even when Initialize fails
// Release application global objects
m_piDSBPrimary.ReleaseInterface();
m_piDSC.ReleaseInterface();
m_piDS.ReleaseInterface();
CWindowsApplication::Shutdown();
}
void CCaptureEchoApplication::Run()
{
const int nNumStreamingBlocks = 4;
HRESULT hr;
CEvent rhEvents[nNumStreamingBlocks];
DSBPOSITIONNOTIFY rdsbpnNotifications[nNumStreamingBlocks];
CComPointer<IDirectSoundBuffer> piDSB, piDSBPrimary;
CComPointer<IDirectSoundCaptureBuffer> piDSCB;
CComPointer<IDirectSoundNotify> piDSNCapture;
WAVEFORMATEX wfx;
DSBUFFERDESC dsbd;
DSCBUFFERDESC dscbd;
DWORD dwStartTime, dwTimeElapsed, dwTmp, dwWaitResult = 0;
DWORD dwLastReadPosition, dwReadPosition, dwBlockSize, dwWritePosition, dwBufferSize;
LPBYTE pbAudioCapturePtr0, pbAudioCapturePtr1, pbAudioPlaybackPtr0, pbAudioPlaybackPtr1;
DWORD dwAudioCaptureBytes0, dwAudioCaptureBytes1, dwAudioPlaybackBytes0, dwAudioPlaybackBytes1;
bool fPlaying;
int i;
dbgout(TEXT("Capturing %g seconds and playing back with a %lums delay.\n"),
static_cast<double>(m_dwTimeout)/1000.0, m_dwDelay);
// Because this application is using DirectSound as well as DirectSoundCapture,
// capture buffer creation can fail when the format of the capture buffer is not
// the same as that of the primary buffer. The reason is that some cards have only
// a single clock and cannot support capture and playback at two different frequencies.
// To simplify buffer creation, we'll borrow the wave format of the primary buffer
// to create our capure and playback buffers.
hr = m_piDSBPrimary->GetFormat(&wfx, sizeof(wfx), NULL);
CheckHRESULT(hr,"IDirectSoundBuffer::GetFormat on the primary sound buffer", return);
// Some dsound drivers support multiple capture formats.
//
// Set the requested format (specified on command line) instead of using
// only the format of the primary buffer.
hr = SetRequestedCaptureFormat(m_piDSC.AsInParam(), wfx, m_dwFormatIndex);
CheckHRESULT(hr, "SetRequestedCaptureFormat", return);
// The buffer size should be aligned along wfx.nBlockAlign.
// We're going to use four blocks, each of which is 2 seconds long.
// Change this to fit your specific memory requirements
// and your platform's specific alignment requirements
dwBlockSize = (m_dwDelay>>1)*wfx.nAvgBytesPerSec/1000;
dwBlockSize -= dwBlockSize%wfx.nBlockAlign;
dwBufferSize = dwBlockSize*nNumStreamingBlocks;
// Create the Capture Buffer
dscbd.dwSize = sizeof(DSCBUFFERDESC);
dscbd.dwFlags = 0;
dscbd.dwBufferBytes = dwBufferSize;
dscbd.dwReserved = 0;
dscbd.lpwfxFormat = &wfx;
hr = m_piDSC->CreateCaptureBuffer(&dscbd, piDSCB.AsOutParam(), NULL);
CheckHRESULT(hr, "IDirectSoundCapture::CreateCaptureBuffer", return);
// Create a streaming playback buffer
dsbd.dwSize = sizeof(DSBUFFERDESC);
dsbd.dwFlags = DSBCAPS_CTRLALL | DSBCAPS_GLOBALFOCUS;
dsbd.dwBufferBytes = dwBufferSize;
dsbd.dwReserved = 0;
dsbd.lpwfxFormat = &wfx;
hr = m_piDS->CreateSoundBuffer(&dsbd, piDSB.AsOutParam(), NULL);
CheckHRESULT(hr, "IDirectSound::CreateSoundBuffer", return);
// clear the playback buffer
hr = ClearSoundBuffer(piDSB.AsInParam());
CheckHRESULT(hr, "ClearSoundBuffer", return);
// Set up the notifications
for (i=0; i<nNumStreamingBlocks; i++)
{
if (!rhEvents[i].Create())
{
dbgout(TEXT("Could not create the notification event %d\n"), i);
return;
}
rdsbpnNotifications[i].dwOffset = dwBlockSize*(i+1)-wfx.nBlockAlign;
rdsbpnNotifications[i].hEventNotify = rhEvents[i];
}
hr = piDSCB->QueryInterface(IID_IDirectSoundNotify, reinterpret_cast<void**>(piDSNCapture.AsOutParam()));
CheckHRESULT(hr, "IDirectSoundCaptureBuffer::QueryInterface", return);
hr = piDSNCapture->SetNotificationPositions(nNumStreamingBlocks, rdsbpnNotifications);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -