2024-06-23 17:36:53 +08:00

461 lines
14 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Audio.cpp: implementation of the CAudio class.
//
//////////////////////////////////////////////////////////////////////
#include "../stdafx.h"
#include "Audio.h"
// ÒýÈëG729°ü
extern "C"
{
#include "va_g729a.h"
}
#pragma comment(lib,"va_g729a.lib")
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CAudio::CAudio()
{
m_hEventWaveIn = CreateEvent(NULL, false, false, NULL);
m_hStartRecord = CreateEvent(NULL, false, false, NULL);
m_hThreadCallBack = NULL;
m_nWaveInIndex = 0;
m_nWaveOutIndex = 0;
m_nBufferLength = SIZE_AUDIO_FRAME; // m_GSMWavefmt.wfx.nSamplesPerSec / 8(bit)
m_bIsWaveInUsed = false;
m_bIsWaveOutUsed = false;
for (int i = 0; i < 2; i++)
{
m_lpInAudioData[i] = new BYTE[m_nBufferLength];
m_lpInAudioHdr[i] = new WAVEHDR;
ZeroMemory(m_lpInAudioData[i],m_nBufferLength);
m_lpOutAudioData[i] = new BYTE[m_nBufferLength];
m_lpOutAudioHdr[i] = new WAVEHDR;
ZeroMemory(m_lpOutAudioData[i],m_nBufferLength);
}
m_SelectedDevice = 0;
va_g729a_init_encoder();
va_g729a_init_decoder();
}
CAudio::~CAudio()
{
if (m_bIsWaveInUsed)
{
waveInStop(m_hWaveIn);
waveInReset(m_hWaveIn);
for (int i = 0; i < 2; i++)
waveInUnprepareHeader(m_hWaveIn, m_lpInAudioHdr[i], sizeof(WAVEHDR));
waveInClose(m_hWaveIn);
TerminateThread(m_hThreadCallBack, -1);
}
if (m_bIsWaveOutUsed)
{
waveOutReset(m_hWaveOut);
for (int i = 0; i < 2; i++)
waveOutUnprepareHeader(m_hWaveOut, m_lpInAudioHdr[i], sizeof(WAVEHDR));
waveOutClose(m_hWaveOut);
}
for (int i = 0; i < 2; i++)
{
delete [] m_lpInAudioData[i];
delete m_lpInAudioHdr[i];
delete [] m_lpOutAudioData[i];
delete m_lpOutAudioHdr[i];
}
CloseHandle(m_hEventWaveIn);
CloseHandle(m_hStartRecord);
CloseHandle(m_hThreadCallBack);
}
LPBYTE CAudio::getRecordBuffer(LPDWORD lpdwBytes)
{
// Not open WaveIn yet, so open it...
if (!m_bIsWaveInUsed && !InitializeWaveIn())
{
return NULL;
}
if (lpdwBytes == NULL)
{
return NULL;
}
SetEvent(m_hStartRecord);
WaitForSingleObject(m_hEventWaveIn, INFINITE);
*lpdwBytes = m_nBufferLength;
return m_lpInAudioData[m_nWaveInIndex];
}
bool CAudio::playBuffer(LPBYTE lpWaveBuffer, DWORD dwBytes)
{
if (!m_bIsWaveOutUsed && !InitializeWaveOut())
return NULL;
for (DWORD i = 0; i < dwBytes; i += m_nBufferLength)
{
memcpy(m_lpOutAudioData[m_nWaveOutIndex], lpWaveBuffer, m_nBufferLength);
waveOutWrite(m_hWaveOut, m_lpOutAudioHdr[m_nWaveOutIndex], sizeof(WAVEHDR));
m_nWaveOutIndex = 1 - m_nWaveOutIndex;
}
return true;
}
bool CAudio::InitializeWaveIn()
{
if (!waveInGetNumDevs())
return false;
WAVEFORMATEX waveform; //²É¼¯ÒôƵµÄ¸ñʽ£¬½á¹¹Ìå
SetDeviceType(&waveform);
MMRESULT mmResult;
DWORD dwThreadID = 0;
m_hThreadCallBack = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)waveInCallBack, (LPVOID)this, CREATE_SUSPENDED, &dwThreadID);
// UINT_PTR uDeviceID ÄËËùÓò¨ÐÎÊäÈëÉ豸֮ID¡£Èô´ËΪ WAVE_MAPPER£¬ÏµÍ³Ôò»á×Ô¶¯Ñ°ÕÒºÏÊÊÉ豸
mmResult = waveInOpen(&m_hWaveIn, m_SelectedDevice, &waveform, (LONG)dwThreadID, (LONG)0, CALLBACK_THREAD);
if (mmResult != MMSYSERR_NOERROR)
{
return false;
}
for (int i = 0; i < 2; i++)
{
m_lpInAudioHdr[i]->lpData = (LPSTR)m_lpInAudioData[i];
m_lpInAudioHdr[i]->dwBufferLength = m_nBufferLength;
m_lpInAudioHdr[i]->dwFlags = 0;
m_lpInAudioHdr[i]->dwLoops = 0;
//²¨ÐÎÉùÒôÊäÈëÉ豸׼±¸Ò»¸ö»º³åÇø
waveInPrepareHeader(m_hWaveIn, m_lpInAudioHdr[i], sizeof(WAVEHDR));
}
//Ïò²¨ÐÎÉùÒôÊäÈëÉ豸Ìí¼Ó»º³åÇø
waveInAddBuffer(m_hWaveIn, m_lpInAudioHdr[m_nWaveInIndex], sizeof(WAVEHDR));
ResumeThread(m_hThreadCallBack);
//¿ªÊ¼Â¼Òô
waveInStart(m_hWaveIn);
m_bIsWaveInUsed = true;
return true;
}
int FindMixernIndex(char *szPname)
{
MIXERCAPS mxcaps = {0};
HMIXER hMixer = NULL;
for ( UINT i = 0; i < mixerGetNumDevs (); i++ )
{
if ( MMSYSERR_NOERROR != mixerGetDevCaps ( i, &mxcaps, sizeof ( MIXERCAPS ) ) ){ continue; }
if ( MMSYSERR_NOERROR != mixerOpen ( &hMixer, i, NULL, NULL, 0 ) ){ continue; }
MIXERLINE mxl = { sizeof ( MIXERLINE ), 0, 0, 0, 0, 0, MIXERLINE_COMPONENTTYPE_DST_WAVEIN, 0};
if ( MMSYSERR_NOERROR != mixerGetLineInfo ( (HMIXEROBJ)hMixer, &mxl, MIXER_GETLINEINFOF_COMPONENTTYPE ) ){
mixerClose ( hMixer );
continue;
}
if (strcmp(mxcaps.szPname,szPname) == 0)
{
mixerClose ( hMixer );
return i;
}
}
return -1;
}
bool CAudio::ActiveMixerInputChannel(char * szMixerDevice, int nMixerLineIndex)
{
int nMixerDeviceIndex = FindMixernIndex(szMixerDevice);
if (nMixerDeviceIndex == -1)
return false;
bool result = false;
HMIXER hMixer = NULL;
MIXERCONTROL mxc = { sizeof ( MIXERCONTROL ), 0 };
MIXERLINE mxl = { sizeof ( MIXERLINE ), 0, 0, 0, 0, 0, MIXERLINE_COMPONENTTYPE_DST_WAVEIN, 0};
if ( MMSYSERR_NOERROR != mixerOpen ( &hMixer, nMixerDeviceIndex, NULL, NULL, 0 ) )
return false;
if ( MMSYSERR_NOERROR != mixerGetLineInfo ( (HMIXEROBJ)hMixer, &mxl, MIXER_GETLINEINFOF_COMPONENTTYPE ) )
{
mixerClose ( hMixer );
return false;
}
MIXERLINECONTROLS mxlc = { sizeof ( MIXERLINECONTROLS ), mxl.dwLineID, MIXERCONTROL_CONTROLTYPE_MIXER, 1, mxc.cbStruct, &mxc };
mxl.dwSource = nMixerLineIndex;
if ( MMSYSERR_NOERROR != mixerGetLineInfo ( (HMIXEROBJ)hMixer, &mxl, MIXER_GETLINEINFOF_DESTINATION | MIXER_GETLINEINFOF_SOURCE ) )
{
mixerClose ( hMixer );
return false;
}
if ( MMSYSERR_NOERROR != mixerGetLineControls ( (HMIXEROBJ)hMixer, &mxlc, MIXER_GETLINECONTROLSF_ONEBYTYPE ) )
{
mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_MUX;
if ( MMSYSERR_NOERROR != mixerGetLineControls ( (HMIXEROBJ)hMixer, &mxlc, MIXER_GETLINECONTROLSF_ONEBYTYPE ) )
{
mixerClose ( hMixer );
return false;
}
}
if ( mxc.cMultipleItems == 0 )
{
mixerClose ( hMixer );
return false;
}
PMIXERCONTROLDETAILS_BOOLEAN mxcdbls = (PMIXERCONTROLDETAILS_BOOLEAN)malloc ( sizeof ( MIXERCONTROLDETAILS_BOOLEAN ) * mxc.cMultipleItems );
PMIXERCONTROLDETAILS_LISTTEXT mxcdlts = (PMIXERCONTROLDETAILS_LISTTEXT)malloc ( sizeof ( MIXERCONTROLDETAILS_LISTTEXT ) * mxc.cMultipleItems );
MIXERCONTROLDETAILS mxcd = { sizeof ( MIXERCONTROLDETAILS ), mxc.dwControlID, 1, (HWND)mxc.cMultipleItems, sizeof ( MIXERCONTROLDETAILS_LISTTEXT ), mxcdlts };
if ( MMSYSERR_NOERROR == mixerGetControlDetails ( (HMIXEROBJ)hMixer, &mxcd, MIXER_GETCONTROLDETAILSF_LISTTEXT ) )
{
memset ( mxcdbls, 0, sizeof ( MIXERCONTROLDETAILS_BOOLEAN ) * mxc.cMultipleItems );
for ( DWORD i = 0; i < mxc.cMultipleItems; i++ )
{
if ( mxcdlts[i].dwParam1 == mxl.dwLineID )
{
mxcdbls[i].fValue = 1;
mxcd.paDetails = mxcdbls;
mxcd.cbDetails = sizeof ( MIXERCONTROLDETAILS_BOOLEAN );
result = (MMSYSERR_NOERROR == mixerSetControlDetails ( (HMIXEROBJ)hMixer, &mxcd, MIXER_SETCONTROLDETAILSF_VALUE ) ); break;
}
}
}
free ( mxcdbls );
free ( mxcdlts );
mixerClose ( hMixer );
return result;
}
int CAudio::EnumerateInputLines( char * szPname, char * str )
{
if(str == NULL ||szPname == NULL )
return -1;
MIXERCAPS mxcaps = {0};
HMIXER hMixer = NULL;
int nRet = -1;
for ( UINT i = 0; i < mixerGetNumDevs (); i++ )
{
if ( MMSYSERR_NOERROR != mixerGetDevCaps ( i, &mxcaps, sizeof ( MIXERCAPS ) ) )
continue;
if ( MMSYSERR_NOERROR != mixerOpen ( &hMixer, i, NULL, NULL, 0 ) )
continue;
MIXERLINE mxl = { sizeof ( MIXERLINE ), 0, 0, 0, 0, 0, MIXERLINE_COMPONENTTYPE_DST_WAVEIN, 0};
if ( MMSYSERR_NOERROR != mixerGetLineInfo ( (HMIXEROBJ)hMixer, &mxl, MIXER_GETLINEINFOF_COMPONENTTYPE ) )
{
mixerClose ( hMixer );
continue;
}
if (strcmp(mxcaps.szPname,szPname) != 0)
{
mixerClose ( hMixer );
continue;
}
MIXERCONTROL mxc = { sizeof ( MIXERCONTROL ), 0 };
MIXERLINECONTROLS mxlc = { sizeof ( MIXERLINECONTROLS ), mxl.dwLineID, MIXERCONTROL_CONTROLTYPE_MIXER, 1, mxc.cbStruct, &mxc };
if ( MMSYSERR_NOERROR != mixerGetLineControls ( (HMIXEROBJ)hMixer, &mxlc, MIXER_GETLINECONTROLSF_ONEBYTYPE ) )
{
mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_MUX;
if ( MMSYSERR_NOERROR != mixerGetLineControls ( (HMIXEROBJ)hMixer, &mxlc, MIXER_GETLINECONTROLSF_ONEBYTYPE ) )
{
mixerClose ( hMixer );
continue;
}
}
if ( mxc.cMultipleItems == 0 )
{
mixerClose ( hMixer );
continue;
}
MIXERCONTROLDETAILS mxcd = { sizeof ( MIXERCONTROLDETAILS ), mxc.dwControlID, 1, 0 };
PMIXERCONTROLDETAILS_LISTTEXT mxcdlts = (PMIXERCONTROLDETAILS_LISTTEXT)malloc ( sizeof ( MIXERCONTROLDETAILS_LISTTEXT ) * mxc.cMultipleItems );
mxcd.cbDetails = sizeof ( MIXERCONTROLDETAILS_LISTTEXT );
mxcd.cMultipleItems = mxc.cMultipleItems;
mxcd.paDetails = mxcdlts;
if ( MMSYSERR_NOERROR != mixerGetControlDetails ( (HMIXEROBJ)hMixer, &mxcd, MIXER_GETCONTROLDETAILSF_LISTTEXT ) )
{
free ( mxcdlts );
mixerClose ( hMixer );
continue;
}
PMIXERCONTROLDETAILS_BOOLEAN mxcdbls = (PMIXERCONTROLDETAILS_BOOLEAN)malloc ( sizeof ( MIXERCONTROLDETAILS_BOOLEAN ) * mxc.cMultipleItems );
mxcd.cbDetails = sizeof ( MIXERCONTROLDETAILS_BOOLEAN );
mxcd.cMultipleItems = mxc.cMultipleItems;
mxcd.paDetails = mxcdbls;
if ( MMSYSERR_NOERROR != mixerGetControlDetails ( (HMIXEROBJ)hMixer, &mxcd, MIXER_GETCONTROLDETAILSF_VALUE ) )
{
free ( mxcdbls );
mixerClose ( hMixer );
continue;
}
DWORD dwConnections = mxl.cConnections;
DWORD dwDestination = mxl.dwDestination;
for ( DWORD j = 0; j < dwConnections; j++ )
{
mxl.dwDestination = dwDestination;
mxl.dwSource = j;
if ( MMSYSERR_NOERROR != mixerGetLineInfo ( (HMIXEROBJ)hMixer, &mxl, MIXER_GETLINEINFOF_DESTINATION | MIXER_GETLINEINFOF_SOURCE ) ){ continue; }
for ( DWORD k = 0; k < mxc.cMultipleItems; k++ )
{
if ( mxcdlts[k].dwParam1 == mxl.dwLineID )
{
strcat(str,mxl.szName);
strcat(str,"@");
if (mxcdbls[k].fValue)
nRet = j;
break;
}
}
}
free ( mxcdbls );
free ( mxcdlts );
mixerClose ( hMixer );
}
return nRet;
}
void CAudio::SetDeviceType(WAVEFORMATEX* pwfe)
{
memset( pwfe, 0, sizeof(WAVEFORMATEX) );
pwfe->wFormatTag = WAVE_FORMAT_PCM;//ÉùÒô¸ñʽΪPCM
pwfe->nSamplesPerSec = 8000;//²ÉÑùÂÊ£¬16000´Î/Ãë
pwfe->wBitsPerSample = 16;//²ÉÑù±ÈÌØ£¬16bits/´Î
pwfe->nChannels = 1;//²ÉÑùÉùµÀÊý£¬2ÉùµÀ
pwfe->nBlockAlign = pwfe->wBitsPerSample*pwfe->nChannels/8;//Ò»¸ö¿éµÄ´óС£¬²ÉÑùbitµÄ×Ö½ÚÊý³ËÒÔÉùµÀÊý
pwfe->nAvgBytesPerSec = pwfe->nBlockAlign*pwfe->nSamplesPerSec ;//ÿÃëµÄÊý¾ÝÂÊ£¬¾ÍÊÇÿÃëÄܲɼ¯¶àÉÙ×Ö½ÚµÄÊý¾Ý
pwfe->cbSize = 0;//Ò»°ãΪ0}
}
bool CAudio::InitializeWaveOut()
{
if (!waveOutGetNumDevs())
return false;
for (int i = 0; i < 2; i++)
memset(m_lpOutAudioData[i], 0, m_nBufferLength);
WAVEFORMATEX waveform; //²É¼¯ÒôƵµÄ¸ñʽ£¬½á¹¹Ìå
SetDeviceType(&waveform);
MMRESULT mmResult;
mmResult = waveOutOpen(&m_hWaveOut, (WORD)WAVE_MAPPER, &waveform, (LONG)0, (LONG)0, CALLBACK_NULL);
if (mmResult != MMSYSERR_NOERROR)
return false;
for (i = 0; i < 2; i++)
{
m_lpOutAudioHdr[i]->lpData = (LPSTR)m_lpOutAudioData[i];
m_lpOutAudioHdr[i]->dwBufferLength = m_nBufferLength;
m_lpOutAudioHdr[i]->dwFlags = 0;
m_lpOutAudioHdr[i]->dwLoops = 0;
waveOutPrepareHeader(m_hWaveOut, m_lpOutAudioHdr[i], sizeof(WAVEHDR));
}
m_bIsWaveOutUsed = true;
return true;
}
DWORD WINAPI CAudio::waveInCallBack( LPVOID lparam )
{
CAudio *pThis = (CAudio *)lparam;
MSG Msg;
while (GetMessage(&Msg, NULL, 0, 0))
{
if (Msg.message == MM_WIM_DATA)
{
// ֪ͨµÄÊý¾Ýµ½À´
SetEvent(pThis->m_hEventWaveIn);
// µÈ´ý¿ªÊ¼Ï´Î¼Òô
WaitForSingleObject(pThis->m_hStartRecord, INFINITE);
pThis->m_nWaveInIndex = 1 - pThis->m_nWaveInIndex;
MMRESULT mmResult = waveInAddBuffer(pThis->m_hWaveIn, pThis->m_lpInAudioHdr[pThis->m_nWaveInIndex], sizeof(WAVEHDR));
if (mmResult != MMSYSERR_NOERROR)
{
return -1;
}
}
// Why never happend this
if (Msg.message == MM_WIM_CLOSE)
break;
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return 0;
}
//////////////////////////////////////////////////////////////////////////
// ÒôƵѹËõ ½âѹËõ²¿·Ö
int CAudio::Compress(char *pBuf, char *pDstBuf, int nLen)
{
short* pSpBuf = (short*)pBuf;
BYTE* pBDstBuf = (BYTE*)pDstBuf;
int nRet=0;
nLen/=sizeof(short);
while(nLen>0)
{
va_g729a_encoder(pSpBuf,pBDstBuf);
pSpBuf+=L_FRAME;
nLen-=L_FRAME;
nRet+=L_FRAME_COMPRESSED;
pBDstBuf+=L_FRAME_COMPRESSED;
}
return nRet;
}
int CAudio::DeCompress(char *pBuf, char *pDstBuf, int nLen)
{
int bfi = 0;
BYTE* pSpBuf = (BYTE*)pBuf;
short* pBDstBuf = (short*)pDstBuf;
int nRet=0;
while(nLen>0)
{
va_g729a_decoder(pSpBuf,pBDstBuf,bfi);
pSpBuf+=L_FRAME_COMPRESSED;
nLen-=L_FRAME_COMPRESSED;
nRet+=L_FRAME;
pBDstBuf+=L_FRAME;
}
return nRet*sizeof(short);
}