461 lines
14 KiB
C++
461 lines
14 KiB
C++
// 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);
|
||
}
|