www.pudn.com > DirectDraw.rar > DSoundCapture.cpp, change:2007-09-28,size:9942b


// DSoundCapture.cpp: implementation of the CDSoundCapture class. 
// 
////////////////////////////////////////////////////////////////////// 
 
#include "stdafx.h" 
#include <objbase.h> 
#include "DSoundCapture.h" 
 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
 
CDSoundCapture::CDSoundCapture(GUID *pGuid /* = NULL */) 
 :m_pDevGuid(pGuid) 
{ 
	m_pDSCBuffer = NULL; 
	m_pDSCapture = NULL; 
	m_pDSNotify = NULL; 
	m_pCapCallbackcontext = NULL; 
	m_pCapCallback = NULL; 
	m_dwCaptureBufferSize = 0; 
	m_dwNotifySize = 0; 
	m_dwNextCaptureOffset = 0; 
    m_hNotificationEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); 
	ZeroMemory(&m_wfx,sizeof(WAVEFORMATEX)); 
	m_hThread = NULL; 
	InitDirectSound(); 
#ifdef _TESTREC 
	m_pWaveFile = NULL; 
#endif 
} 
 
CDSoundCapture::~CDSoundCapture() 
{ 
	StopCapture(); 
	FreeDirectSound(); 
	CloseHandle(m_hNotificationEvent); 
} 
 
DWORD CDSoundCapture::CaptureSoundProc(LPVOID Para) 
{ 
	CDSoundCapture *pDSC = (CDSoundCapture *)Para; 
	while(!pDSC->m_bThreadEnd) 
	{ 
		DWORD dwWait = WaitForSingleObject(pDSC->m_hNotificationEvent,INFINITE); 
		if(WAIT_OBJECT_0 == dwWait) 
		{ 
			if(!pDSC->ReadCapturedData()) 
				return 0xFFFF; 
		} 
	} 
	return 0; 
} 
 
 
 
//----------------------------------------------------------------------------- 
// Name: ReadCapturedData() 
// Desc: Copies data from the capture buffer 
//----------------------------------------------------------------------------- 
BOOL CDSoundCapture::ReadCapturedData()  
{ 
    VOID*   pbCaptureData    = NULL; 
    DWORD   dwCaptureLength; 
    VOID*   pbCaptureData2   = NULL; 
    DWORD   dwCaptureLength2; 
    DWORD   dwReadPos; 
    DWORD   dwCapturePos; 
    LONG	lLockSize; 
 
    if( NULL == m_pDSCBuffer ) 
        return FALSE; 
#ifdef _TESTREC 
    if( NULL == m_pWaveFile) 
        return S_FALSE; 
#endif 
    if( FAILED( m_pDSCBuffer->GetCurrentPosition( &dwCapturePos, &dwReadPos ) ) ) 
        return FALSE; 
 
    lLockSize = dwReadPos - m_dwNextCaptureOffset; 
    if( lLockSize < 0 ) 
        lLockSize += m_dwCaptureBufferSize; 
 
    // Block align lock size so that we are always write on a boundary 
    lLockSize -= (lLockSize % m_dwNotifySize); 
 
    if( lLockSize == 0 ) 
        return FALSE; 
 
    // Lock the capture buffer down 
    if( FAILED(m_pDSCBuffer->Lock( m_dwNextCaptureOffset, lLockSize,  
                                          &pbCaptureData, &dwCaptureLength,  
                                          &pbCaptureData2, &dwCaptureLength2, 0L ) ) ) 
        return FALSE; 
	if(m_pCapCallback) 
	{ 
		m_pCapCallback(&m_wfx,pbCaptureData,dwCaptureLength,m_pCapCallbackcontext); 
	} 
 
#ifdef _TESTREC 
     UINT    dwDataWrote; 
   // Write the data into the wave file 
    if( FAILED(m_pWaveFile->Write(dwCaptureLength,  
                                              (BYTE*)pbCaptureData,  
                                              &dwDataWrote ) ) ) 
        return FALSE; 
#endif 
 
    // Move the capture offset along 
    m_dwNextCaptureOffset += dwCaptureLength;  
    m_dwNextCaptureOffset %= m_dwCaptureBufferSize; // Circular buffer 
 
    if( pbCaptureData2 != NULL ) 
    { 
		if(m_pCapCallback) 
			m_pCapCallback(&m_wfx,pbCaptureData2,dwCaptureLength2,m_pCapCallbackcontext); 
#ifdef _TESTREC 
        // Write the data into the wav file 
        if( FAILED(m_pWaveFile->Write( dwCaptureLength2,  
                                                  (BYTE*)pbCaptureData2,  
                                                  &dwDataWrote ) ) ) 
            return FALSE; 
#endif 
        // Move the capture offset along 
        m_dwNextCaptureOffset += dwCaptureLength2;  
        m_dwNextCaptureOffset %= m_dwCaptureBufferSize; // Circular buffer 
    } 
 
    // Unlock the capture buffer 
    m_pDSCBuffer->Unlock( pbCaptureData,  dwCaptureLength,  
                           pbCaptureData2, dwCaptureLength2 ); 
 
 
    return TRUE; 
} 
 
BOOL CDSoundCapture::StartCapture(CapSoundCallback pCallback,LPVOID	pcontext) 
{ 
	if(!CreateCaptureBuffer()) 
	{ 
//		AfxMessageBox("创建缓冲失败\n"); 
		return FALSE; 
	} 
#ifdef _TESTREC 
    SAFE_DELETE( m_pWaveFile ); 
    m_pWaveFile = new CWaveFile; 
    if( NULL == m_pWaveFile ) 
	{ 
//		AfxMessageBox("创建录像文件失败\n"); 
        return FALSE; 
	} 
    // Get the format of the capture buffer in g_wfxCaptureWaveFormat 
    WAVEFORMATEX wfxCaptureWaveFormat; 
    ZeroMemory( &wfxCaptureWaveFormat, sizeof(WAVEFORMATEX) ); 
    m_pDSCBuffer->GetFormat( &wfxCaptureWaveFormat, sizeof(WAVEFORMATEX), NULL ); 
 
    // Load the wave file 
    if( FAILED(m_pWaveFile->Open( "F:\\CaptureSound.wav", &wfxCaptureWaveFormat, WAVEFILE_WRITE ) ) ) 
        return FALSE; 
#endif 
	m_pCapCallback = pCallback; 
	m_pCapCallbackcontext = pcontext; 
	if(!StartThread()) 
	{ 
//		AfxMessageBox("启动线程失败\n"); 
		return FALSE; 
	} 
	if(FAILED(m_pDSCBuffer->Start(DSCBSTART_LOOPING))) 
	{ 
//		AfxMessageBox("启动采集失败\n"); 
		ReleaseThread(); 
		return FALSE; 
	} 
	return TRUE; 
} 
 
BOOL CDSoundCapture::StartThread() 
{ 
	if(m_hThread) 
		ReleaseThread(); 
	m_bThreadEnd = FALSE; 
	DWORD dwTempID; 
	ResetEvent(m_hNotificationEvent); 
	m_hThread = CreateThread(NULL,0,CaptureSoundProc,this,CREATE_SUSPENDED,&dwTempID); 
	if(NULL == m_hThread) 
		return FALSE; 
	ResumeThread(m_hThread); 
	return TRUE; 
} 
 
void CDSoundCapture::ReleaseThread() 
{ 
	if(m_hThread) 
	{ 
		m_bThreadEnd = TRUE; 
		SetEvent(m_hNotificationEvent); 
		WaitForSingleObject(m_hThread,INFINITE); 
		CloseHandle(m_hThread); 
		m_hThread = NULL; 
	} 
} 
 
BOOL CDSoundCapture::StopCapture() 
{ 
	if(NULL == m_pDSCBuffer) 
		return TRUE; 
	ReleaseThread(); 
	if(FAILED(m_pDSCBuffer->Stop())) 
		return FALSE; 
#ifdef _TESTREC 
       if( FAILED(ReadCapturedData() ) ) 
            return FALSE; 
 
        // Close the wave file 
        SAFE_DELETE( m_pWaveFile ); 
#endif 
	return TRUE; 
} 
 
//----------------------------------------------------------------------------- 
// Name: SetAudioFormat() 
// Desc: Set the Capture Format 
//----------------------------------------------------------------------------- 
BOOL CDSoundCapture::SetAudioFormat(DWORD dwSamples,WORD wChannels,WORD wBitsPerSample) 
{ 
	if(NULL == m_pDSCapture) 
		return FALSE; 
	m_wfx.wFormatTag = WAVE_FORMAT_PCM; 
	m_wfx.nSamplesPerSec = dwSamples; 
	m_wfx.nChannels = wChannels; 
	m_wfx.wBitsPerSample = wBitsPerSample; 
	m_wfx.nBlockAlign = (m_wfx.wBitsPerSample * m_wfx.nChannels) / 8; 
	m_wfx.nAvgBytesPerSec=m_wfx.nBlockAlign * m_wfx.nSamplesPerSec; 
	if(0 == m_wfx.nAvgBytesPerSec) 
		return FALSE; 
	m_dwCaptureBufferSize = 0; 
	return TRUE; 
} 
 
//----------------------------------------------------------------------------- 
// Name: InitDirectSound() 
// Desc: Initilizes DirectSound 
//----------------------------------------------------------------------------- 
BOOL CDSoundCapture::InitDirectSound() 
{ 
    ZeroMemory( &m_DSBPosNotify, sizeof(DSBPOSITIONNOTIFY) *(NUM_REC_NOTIFICATIONS + 1) ); 
	if(S_OK != CoInitialize(NULL)) 
		return FALSE; 
	if(FAILED(DirectSoundCaptureCreate(m_pDevGuid,&m_pDSCapture,NULL))) 
		return FALSE; 
	return TRUE; 
} 
 
//----------------------------------------------------------------------------- 
// Name: FreeDirectSound() 
// Desc: Releases DirectSound  
//----------------------------------------------------------------------------- 
void CDSoundCapture::FreeDirectSound() 
{ 
    // Release DirectSound interfaces 
    SAFE_RELEASE( m_pDSNotify ); 
    SAFE_RELEASE( m_pDSCBuffer ); 
    SAFE_RELEASE( m_pDSCapture );  
 
    // Release COM 
    CoUninitialize(); 
} 
 
//----------------------------------------------------------------------------- 
// Name: CreateCaptureBuffer() 
// Desc: Creates a capture buffer and sets the format  
//----------------------------------------------------------------------------- 
BOOL CDSoundCapture::CreateCaptureBuffer() 
{ 
    DSCBUFFERDESC dscbd; 
 
    // Set the notification size 
    m_dwNotifySize = m_wfx.nAvgBytesPerSec / 25; 
    m_dwNotifySize -= m_dwNotifySize % m_wfx.nBlockAlign;    
 
    // Set the buffer sizes  
    m_dwCaptureBufferSize = m_dwNotifySize * NUM_REC_NOTIFICATIONS; 
 
    SAFE_RELEASE( m_pDSNotify ); 
    SAFE_RELEASE( m_pDSCBuffer ); 
 
    // Create the capture buffer 
    ZeroMemory( &dscbd, sizeof(dscbd) ); 
    dscbd.dwSize        = sizeof(dscbd); 
    dscbd.dwBufferBytes = m_dwCaptureBufferSize; 
    dscbd.lpwfxFormat   = &m_wfx; // Set the format during creatation 
 
    if( FAILED(m_pDSCapture->CreateCaptureBuffer(&dscbd,&m_pDSCBuffer, NULL))) 
        return FALSE; 
 
    m_dwNextCaptureOffset = 0; 
 
    return InitNotifications(); 
 } 
 
//----------------------------------------------------------------------------- 
// Name: InitNotifications() 
// Desc: Inits the notifications on the capture buffer which are handled 
//       in WinMain() 
//----------------------------------------------------------------------------- 
BOOL CDSoundCapture::InitNotifications() 
{ 
    if( NULL == m_pDSCBuffer ) 
        return FALSE; 
 
    // Create a notification event, for when the sound stops playing 
    if(FAILED(m_pDSCBuffer->QueryInterface( IID_IDirectSoundNotify,(VOID**)&m_pDSNotify ))) 
        return FALSE; 
 
    // Setup the notification positions 
    for( INT i = 0; i < NUM_REC_NOTIFICATIONS; i++ ) 
    { 
        m_DSBPosNotify[i].dwOffset = (m_dwNotifySize * i) + m_dwNotifySize - 1; 
        m_DSBPosNotify[i].hEventNotify = m_hNotificationEvent;              
    } 
     
    // Tell DirectSound when to notify us. the notification will come in the from  
    // of signaled events that are handled in WinMain() 
    if( FAILED(m_pDSNotify->SetNotificationPositions( NUM_REC_NOTIFICATIONS,m_DSBPosNotify ) ) ) 
        return FALSE; 
 
    return TRUE; 
}