谁会directsound,谁会采集音频

紫竹先生 2008-06-16 12:23:12
我现在在做音频采集,但是一直采集不到声音,谁能给我点提示! 给我一段代码更好!邮箱:zhufude1987@126.com
...全文
461 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
covsno 2008-06-25
  • 打赏
  • 举报
回复
dxsdk sample
AgedBOY 2008-06-24
  • 打赏
  • 举报
回复
IamNieo都奉献那么完整的代码了,别人基本没得回答了。呵呵。那我就再给你来段短一点的代码吧~~

不过假如你的采集音频工作只是想“录音”,则使用DSound是不太合适的,高射炮打蚊子了。不如采用DShow来录音。(况且DShow也是基于DSound的啊)

创建一个cpp文件,贴入下面代码,再在你的stdafx.h里面include两个头文件:atlbase.h和dshow.h。


#include "stdafx.h"
#pragma comment(lib, "strmiids.lib")

HRESULT WINAPI FindFirstACapDevice(IBaseFilter** pCapDev)
{
HRESULT hr;
ATLASSERT(pCapDev);
*pCapDev = NULL;

// Prepare to enumerate capture device

CComPtr<IBindCtx> pBC;
if(FAILED(hr = CreateBindCtx(0, &pBC)))
return hr;

CComPtr<ICreateDevEnum> pCDE;
if(FAILED(hr = pCDE.CoCreateInstance(CLSID_SystemDeviceEnum)))
return hr;

CComPtr<IEnumMoniker> pEnumMoniker;
if(S_OK != (hr = pCDE->CreateClassEnumerator(CLSID_AudioInputDeviceCategory,
&pEnumMoniker.p, 0)))
return hr;

if(S_OK != (hr = pEnumMoniker->Reset()))
return hr;

// Enumerate the first available capture device
ULONG cFetched;
CComPtr<IMoniker> pMoniker;
if(S_OK != (hr = pEnumMoniker->Next(1, &pMoniker.p, &cFetched)))
return hr;

// Get device filter
if(FAILED(hr = pMoniker->BindToObject(pBC, NULL, IID_IBaseFilter, (void**)pCapDev)))
return hr;

return S_OK;
}

// {3C78B8E2-6C4D-11d1-ADE2-0000F8754B99}
static const GUID CLSID_WavDest =
{ 0x3c78b8e2, 0x6c4d, 0x11d1, { 0xad, 0xe2, 0x0, 0x0, 0xf8, 0x75, 0x4b, 0x99 } };

HRESULT WINAPI BuildACapGraph(IGraphBuilder** ppGraph, LPCWSTR pwszWavFileName)
{
HRESULT hr;
ATLASSERT(ppGraph);
ATLASSERT(pwszWavFileName);
*ppGraph = NULL;

// Get audio capture device object
CComPtr<IBaseFilter> pASrc;
if(FAILED(hr = FindFirstACapDevice(&pASrc)))
return hr;

// Create .WAV format creator
CComPtr<IBaseFilter> pWavDst;
if(FAILED(hr = pWavDst.CoCreateInstance(CLSID_WavDest)))
return hr;

// Create file writer
CComPtr<IBaseFilter> pFileWriter;
if(FAILED(hr = pFileWriter.CoCreateInstance(CLSID_FileWriter)))
return hr;
CComQIPtr<IFileSinkFilter> pFileSink = pFileWriter;
if(FAILED(hr = pFileSink->SetFileName(pwszWavFileName, NULL)))
return hr;

// Create filter graph and capture builder
CComPtr<IGraphBuilder> pGraph;
if(FAILED(hr = pGraph.CoCreateInstance(CLSID_FilterGraph)))
return hr;
CComPtr<ICaptureGraphBuilder2> pCapBuilder;
if(FAILED(hr = pCapBuilder.CoCreateInstance(CLSID_CaptureGraphBuilder2)))
return hr;
if(FAILED(hr = pCapBuilder->SetFiltergraph(pGraph)))
return hr;

// Connect
pGraph->AddFilter(pASrc, L"");
pGraph->AddFilter(pWavDst, L"");
pGraph->AddFilter(pFileWriter, L"");
if(FAILED(hr = pCapBuilder->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Audio,
pASrc, pWavDst, pFileWriter)))
return hr;

// Everything is ok, return the graph object to caller
pGraph.CopyTo(ppGraph);

return S_OK;
}

HRESULT WINAPI StartStopACap(IGraphBuilder* pGraph, BOOL bStart)
{
// Set graph to running status
CComQIPtr<IMediaControl> pCtrl = pGraph;
if(bStart)
pCtrl->Run();
else
pCtrl->Stop();
// Wait for the status changing
OAFilterState unused;
return pCtrl->GetState(INFINITE, &unused);
}


调用代码如下:

CComPtr<IGraphBuilder> g_pGraph;


LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;

switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
break;
case ID_FILE_STARTSTOP:
if(!g_pGraph) // Not capturing, start capturing now
{
BuildACapGraph(&g_pGraph, L"c:\\test.wav");
StartStopACap(g_pGraph, TRUE);
}
else // Is capturing, stop it now
{
StartStopACap(g_pGraph, FALSE);
g_pGraph.Release();
}
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
nieoding 2008-06-24
  • 打赏
  • 举报
回复
DWORD WINAPI WavRecord::ThreadRecord(LPVOID p)
{
bool bDone = false;
WavRecord* pParent = (WavRecord*)p;

MSG msg;
while(!bDone)
{
DWORD dwResult = MsgWaitForMultipleObjects( 1, &pParent->g_hNotificationEvent,
FALSE, INFINITE, QS_ALLEVENTS );
switch( dwResult )
{
case WAIT_OBJECT_0 + 0:
if(FAILED(pParent->RecordCapturedData()))
{
if(pParent->GetCallbackProc()!=NULL)
pParent->GetCallbackProc()(pParent->m_parent,NULL,NULL,NULL);
bDone = true;
}
break;
case WAIT_OBJECT_0 + 1:
while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
if( msg.message == WM_QUIT ) return 0;

}
break;
}
}
pParent->Stop(TRUE);
return 0;
}

bool WavRecord::Init(int nNotifyNum)
{
this->m_nNotifyNumber = nNotifyNum;
if(this->g_aPosNotify)
delete this->g_aPosNotify;
g_aPosNotify = new DSBPOSITIONNOTIFY[this->m_nNotifyNumber+1];
return !FAILED(this->InitDirectSound(NULL));
}



bool WavRecord::Start(int nSamplesPerSec,int nChannels,int wBitsPerSample)
{
bool bReturn = false;
try
{
if(FAILED(this->CreateCaptureBuffer(nSamplesPerSec,nChannels,wBitsPerSample)))
throw 1;
if(this->m_hThread==NULL)
{
this->m_hThread = ::CreateThread(NULL,0,WavRecord::ThreadRecord,(LPVOID)this,0,&this->m_dwThreadID);
if(this->m_hThread==NULL)
{
this->m_error = ERROR_MEDIA_AUDIO_THREAD;
throw 1;
}
}
LPDIRECTSOUNDCAPTUREBUFFER dsb = (LPDIRECTSOUNDCAPTUREBUFFER)g_pDSBCapture;
if(FAILED(dsb->Start(DSCBSTART_LOOPING)))
{
this->m_error = ERROR_MEDIA_AUDIO_DEVICE;
throw 1;
}
this->m_bRecording = true;
bReturn = true;
}
catch(int)
{
this->m_bRecording = false;
}
return bReturn;
}

int WavRecord::GetLastError(){return m_error;}

bool WavRecord::IsRecording(){return m_bRecording;}
void WavRecord::Stop(BOOL KillThread/*=FALSE*/
,BOOL Delay/*=FALSE*/)
{
this->m_bRecording = false;
if(KillThread)
{
if(this->m_hThread!=NULL)
{
PostThreadMessage( this->m_dwThreadID, WM_QUIT, 0, 0 );
WaitForSingleObject( this->m_hThread, INFINITE );
CloseHandle( this->m_hThread );
this->m_hThread = NULL;
}
}
if(!Delay)
{
if( NULL == g_pDSBCapture )
return;
LPDIRECTSOUNDCAPTUREBUFFER dsb = (LPDIRECTSOUNDCAPTUREBUFFER)g_pDSBCapture;
if( FAILED( dsb->Stop() ) )
return;
RecordCapturedData();
}
else
CreateThread(NULL,0,WavRecord::ThreadStop,(LPVOID)this,0,NULL);
}
nieoding 2008-06-24
  • 打赏
  • 举报
回复
wavRecord.cpp

HRESULT WavRecord::InitDirectSound(GUID* pDeviceGuid )
{
HRESULT hr;

ZeroMemory( g_aPosNotify, sizeof(DSBPOSITIONNOTIFY) *
(this->m_nNotifyNumber + 1) );
g_dwCaptureBufferSize = 0;
g_dwNotifySize = 0;



// Create IDirectSoundCapture using the preferred capture device
if(pDeviceGuid)
hr = DirectSoundCaptureCreate( pDeviceGuid, (LPDIRECTSOUNDCAPTURE*)&g_pDSCapture, NULL ) ;
else
hr = DirectSoundCaptureCreate( &DSDEVID_DefaultCapture, (LPDIRECTSOUNDCAPTURE*)&g_pDSCapture, NULL ) ;

if( FAILED( hr ) )
{
this->m_error= ERROR_MEDIA_AUDIO_COM;
return hr;
}

return S_OK;
}

HRESULT WavRecord::FreeDirectSound()
{

// Release DirectSound interfaces
LPDIRECTSOUNDNOTIFY notify = (LPDIRECTSOUNDNOTIFY)g_pDSNotify;
SAFE_RELEASE( notify );
g_pDSNotify = 0;
LPDIRECTSOUNDCAPTUREBUFFER dsb = (LPDIRECTSOUNDCAPTUREBUFFER)g_pDSBCapture;
SAFE_RELEASE( dsb );
g_pDSBCapture = 0;
LPDIRECTSOUNDCAPTURE dsc = (LPDIRECTSOUNDCAPTURE)g_pDSCapture;
SAFE_RELEASE( dsc );
g_pDSCapture = 0;


return S_OK;
}


HRESULT WavRecord::InitNotifications()
{
HRESULT hr;

if( NULL == g_pDSBCapture )
{
this->m_error = ERROR_MEDIA_AUDIO_COM;
return E_FAIL;
}
LPDIRECTSOUNDCAPTUREBUFFER capture = (LPDIRECTSOUNDCAPTUREBUFFER)g_pDSBCapture;

// Create a notification event, for when the sound stops playing
if( FAILED( hr = capture->QueryInterface( IID_IDirectSoundNotify,
(VOID**)&g_pDSNotify ) ) )
{
this->m_error = ERROR_MEDIA_AUDIO_COM;
return hr;
}

// Setup the notification positions
DSBPOSITIONNOTIFY * ar_notify = (DSBPOSITIONNOTIFY*)g_aPosNotify;
for( INT i = 0; i < this->m_nNotifyNumber; i++ )
{
ar_notify[i].dwOffset = (g_dwNotifySize * i) + g_dwNotifySize - 1;
ar_notify[i].hEventNotify = g_hNotificationEvent;
}

// Tell DirectSound when to notify us. the notification will come in the from
// of signaled events that are handled in WinMain()
LPDIRECTSOUNDNOTIFY notify = (LPDIRECTSOUNDNOTIFY)g_pDSNotify;
if( FAILED( hr = notify->SetNotificationPositions( this->m_nNotifyNumber,
ar_notify ) ) )
{
this->m_error = ERROR_MEDIA_AUDIO_COM;
return hr;
}

return S_OK;
}

HRESULT WavRecord::RecordCapturedData()
{
HRESULT hr;
VOID* pbCaptureData = NULL;
DWORD dwCaptureLength;
VOID* pbCaptureData2 = NULL;
DWORD dwCaptureLength2;
DWORD dwReadPos;
DWORD dwCapturePos;
LONG lLockSize;

if( NULL == g_pDSBCapture )
{
this->m_error = ERROR_MEDIA_AUDIO_CAPTURE;
return S_FALSE;
}
LPDIRECTSOUNDCAPTUREBUFFER capture = (LPDIRECTSOUNDCAPTUREBUFFER)g_pDSBCapture;

if( FAILED( hr = capture->GetCurrentPosition( &dwCapturePos, &dwReadPos ) ) )
{
this->m_error = ERROR_MEDIA_AUDIO_CAPTURE;
return hr;
}

lLockSize = dwReadPos - g_dwNextCaptureOffset;
if( lLockSize < 0 )
lLockSize += g_dwCaptureBufferSize;

// Block align lock size so that we are always write on a boundary
lLockSize -= (lLockSize % g_dwNotifySize);

if( lLockSize == 0 )
{
this->m_error = ERROR_MEDIA_AUDIO_CAPTURE;
return S_FALSE;
}

// Lock the capture buffer down
if( FAILED( hr = capture->Lock( g_dwNextCaptureOffset, lLockSize,
&pbCaptureData, &dwCaptureLength,
&pbCaptureData2, &dwCaptureLength2, 0L ) ) )
{
this->m_error = ERROR_MEDIA_AUDIO_CAPTURE;
return hr;
}

int totallen = dwCaptureLength+dwCaptureLength2;
PBYTE data= new BYTE[totallen];

memcpy(data,pbCaptureData,dwCaptureLength);

// Move the capture offset along
g_dwNextCaptureOffset += dwCaptureLength;
g_dwNextCaptureOffset %= g_dwCaptureBufferSize; // Circular buffer

if( pbCaptureData2 != NULL )
{
memcpy(data+dwCaptureLength,pbCaptureData2,dwCaptureLength2);

// Move the capture offset along
g_dwNextCaptureOffset += dwCaptureLength2;
g_dwNextCaptureOffset %= g_dwCaptureBufferSize; // Circular buffer
}



// Unlock the capture buffer
capture->Unlock( pbCaptureData, dwCaptureLength,
pbCaptureData2, dwCaptureLength2 );



if(this->m_proc)
{
this->m_proc(this->m_parent,this,data,totallen);
}
if(data)
delete data;

return S_OK;
}

WAVCALLBACK WavRecord::SetCallbackProc(WAVCALLBACK proc,LPVOID parent)
{
WAVCALLBACK backup = this->m_proc;
this->m_parent = parent;
this->m_proc = proc;
return backup;
}
WAVCALLBACK WavRecord::GetCallbackProc()
{
return this->m_proc;
}




HRESULT WavRecord::CreateCaptureBuffer( int nSamplesPerSec,int nChannels,int wBitsPerSample)
{
WAVEFORMATEX wfx;
ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
wfx.wFormatTag = (WORD) WAVE_FORMAT_PCM;
wfx.nChannels = nChannels;
wfx.nSamplesPerSec = nSamplesPerSec;
wfx.wBitsPerSample = wBitsPerSample;
wfx.nBlockAlign = (WORD) (wfx.wBitsPerSample / 8 * wfx.nChannels);
wfx.nAvgBytesPerSec = (DWORD) (wfx.nSamplesPerSec * wfx.nBlockAlign);

WAVEFORMATEX * pwfxInput = &wfx;

HRESULT hr;
DSCBUFFERDESC dscbd;

LPDIRECTSOUNDNOTIFY notify = (LPDIRECTSOUNDNOTIFY)g_pDSNotify;
SAFE_RELEASE( notify);
g_pDSNotify = 0;

LPDIRECTSOUNDCAPTUREBUFFER dsb = (LPDIRECTSOUNDCAPTUREBUFFER)g_pDSBCapture;
SAFE_RELEASE( dsb );
g_pDSBCapture = 0;

// Set the notification size
g_dwNotifySize = max( 1024, pwfxInput->nAvgBytesPerSec / 8 );
g_dwNotifySize -= g_dwNotifySize % pwfxInput->nBlockAlign;

// Set the buffer sizes
g_dwCaptureBufferSize = g_dwNotifySize * this->m_nNotifyNumber;


// Create the capture buffer
ZeroMemory( &dscbd, sizeof(dscbd) );
dscbd.dwSize = sizeof(dscbd);
dscbd.dwBufferBytes = g_dwCaptureBufferSize;
dscbd.lpwfxFormat = pwfxInput; // Set the format during creatation
if(g_pDSCapture==NULL)
{
this->m_error = ERROR_MEDIA_AUDIO_COM;
return S_FALSE;
}
LPDIRECTSOUNDCAPTURE capture = (LPDIRECTSOUNDCAPTURE )g_pDSCapture;
if( FAILED( hr = capture->CreateCaptureBuffer( &dscbd,
(LPDIRECTSOUNDCAPTUREBUFFER*)&g_pDSBCapture,
NULL ) ) )
{
this->m_error = ERROR_MEDIA_AUDIO_BUFFER;
return hr;
}

g_dwNextCaptureOffset = 0;

if( FAILED( hr = InitNotifications() ) )
return hr;

return S_OK;
}



WavRecord::WavRecord(void)
{
g_hNotificationEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
g_pDSCapture = NULL;
g_pDSBCapture = NULL;
g_pDSNotify = NULL;
g_aPosNotify = NULL;
m_hThread = NULL;
m_dwThreadID = 0;
m_bRecording = false;
m_nNotifyNumber = 1;
m_del = false;
m_proc = NULL;
m_error = 0;
}

WavRecord::~WavRecord(void)
{
Exit();
m_del = true;
}

void WavRecord::Exit()
{
Stop(TRUE);
FreeDirectSound();
if(g_aPosNotify)
{
delete g_aPosNotify;
g_aPosNotify = NULL;
}
if(g_hNotificationEvent!=NULL)
{
CloseHandle(g_hNotificationEvent);
g_hNotificationEvent = NULL;
}
}

DWORD WINAPI WavRecord::ThreadStop(LPVOID p)
{
Sleep(200);
WavRecord* pParent = (WavRecord*)p;
LPDIRECTSOUNDCAPTUREBUFFER dsb = (LPDIRECTSOUNDCAPTUREBUFFER)pParent->g_pDSBCapture;

if( !pParent->m_del && pParent->g_pDSBCapture && !FAILED( dsb->Stop() ) )
pParent->RecordCapturedData();
return 0;
}
nieoding 2008-06-24
  • 打赏
  • 举报
回复
我从以前的代码里抽出来一部分关于DirectX声音采样的代码,供你参考

wavRecord.h

typedef BOOL (*WAVCALLBACK)(LPVOID,LPVOID,LPBYTE,int);
class WavRecord
{
public:
WavRecord(void);
~WavRecord(void);
protected:
bool m_bRecording;
int m_error;
HANDLE m_hThread;
DWORD m_dwThreadID;
WAVCALLBACK m_proc;
int m_nNotifyNumber;
public:
void* g_pDSCapture ;
void* g_pDSBCapture ;
void* g_pDSNotify ;
//WAVEFORMATEX g_wfxInput;
void* g_aPosNotify;
HANDLE g_hNotificationEvent;
DWORD g_dwCaptureBufferSize;
DWORD g_dwNextCaptureOffset;
DWORD g_dwNotifySize;
public:
static DWORD WINAPI ThreadRecord(LPVOID);
static DWORD WINAPI ThreadStop(LPVOID);
private:
HRESULT InitDirectSound(GUID* pDeviceGuid );
HRESULT FreeDirectSound();
HRESULT InitNotifications();
HRESULT RecordCapturedData();
HRESULT CreateCaptureBuffer( int nSamplesPerSec,int nChannels,int wBitsPerSample);
public:
LPVOID m_parent;
bool m_del;
int GetLastError();
bool IsRecording();
bool Start(int nSamplesPerSec,int nChannels,int wBitsPerSample);
void Stop( BOOL KillThread = FALSE,BOOL Delay = FALSE);
bool Init(int nNotifyNum = 16);
void Exit();
WAVCALLBACK SetCallbackProc(WAVCALLBACK proc,LPVOID parent);
WAVCALLBACK GetCallbackProc();
};

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧