www.gusucode.com > 用于语音视频聊天的类源码程序 > 用于语音视频聊天的类源码程序/TACMConvert.cpp

    //---------------------------------------------------------------------------


#pragma hdrstop

#include "TACMConvert.h"
#include <vcl.h>
extern TStrings *DebugMsg;
BOOL CALLBACK find_driver_enum(HACMDRIVERID hadid, DWORD dwInstance, DWORD fdwSupport);
BOOL CALLBACK find_format_enum(HACMDRIVERID hadid, LPACMFORMATDETAILS pafd, DWORD dwInstance, DWORD fdwSupport);
//---------------------------------------------------------------------------
#pragma package(smart_init)

// callback function for format enumeration
TACMConvert::TACMConvert()
{
  pwfDrv=NULL;
  ACMDrv=NULL;
//初始化源数据格式
  memset(&wfSrc, 0, sizeof(WAVEFORMATEX));
  wfSrc.cbSize = 0;
  wfSrc.wFormatTag = WAVE_FORMAT_PCM; // pcm
  wfSrc.nChannels = 1; // mono
  wfSrc.nSamplesPerSec = SamplesPerSec; // 11.025 kHz
  wfSrc.wBitsPerSample = BitsPerSample; // 8 bit
  wfSrc.nBlockAlign = wfSrc.nChannels * wfSrc.wBitsPerSample / 8;
  wfSrc.nAvgBytesPerSec = wfSrc.nSamplesPerSec * wfSrc.nBlockAlign;

}
bool TACMConvert::Init()
{
//获取 ACMDrvID
  FIND_DRIVER_INFO fdi;
  fdi.ACMConvert=this;
  fdi.hadid = NULL;
  fdi.wFormatTag = WAVE_FORMAT_DSPGROUP_TRUESPEECH;
  MMRESULT mmr = acmDriverEnum(find_driver_enum, (DWORD)(VOID*)&fdi, 0);
  if(mmr==0 && fdi.hadid!=NULL)
    ACMDrvID = fdi.hadid;
  else
    return(false);
//    throw Exception("找不到音频压缩模块");

//打开ACMDrv
  mmr = acmDriverOpen(&ACMDrv, ACMDrvID, 0);
  if(mmr)
    return(false);
//    throw Exception("打开音频压缩模块失败");

//获取最大的 MAX_SIZE_FORMAT
  mmr = acmMetrics((HACMOBJ)ACMDrv, ACM_METRIC_MAX_SIZE_FORMAT, &MaxFromatSize);
  if(MaxFromatSize < sizeof(WAVEFORMATEX))
    MaxFromatSize = sizeof(WAVEFORMATEX); // for MS-PCM
  pwfPCM=&wfSrc;
/*
  pwfPCM=(WAVEFORMATEX*)malloc(MaxFromatSize);
  if(!GetDriverFormat(WAVE_FORMAT_PCM,pwfPCM))
   { throw Exception("获取PCM格式失败");
     return ;
   }

  DebugMsg->Add("PCM格式: ");
  DebugMsg->Add("   wFormatTag:"+IntToStr(pwfPCM->wFormatTag));
  DebugMsg->Add("   nChannels:"+IntToStr(pwfPCM->nChannels));
  DebugMsg->Add("   nSamplesPerSec:"+IntToStr(pwfPCM->nSamplesPerSec));
  DebugMsg->Add("   nAvgBytesPerSec:"+IntToStr(pwfPCM->nAvgBytesPerSec));
  DebugMsg->Add("   nBlockAlign:"+IntToStr(pwfPCM->nBlockAlign));
  DebugMsg->Add("   wBitsPerSample:"+IntToStr(pwfPCM->wBitsPerSample));
  DebugMsg->Add("   cbSize:"+IntToStr(pwfPCM->cbSize));
  DebugMsg->Add("");
*/

  pwfDrv=(WAVEFORMATEX*)malloc(MaxFromatSize);
  if(!GetDriverFormat(WAVE_FORMAT_DSPGROUP_TRUESPEECH,pwfDrv))
    return(false);
//    throw Exception("获取压缩格式失败");
/*
  DebugMsg->Add("压缩格式: ");
  DebugMsg->Add("   wFormatTag:"+IntToStr(pwfDrv->wFormatTag));
  DebugMsg->Add("   nChannels:"+IntToStr(pwfDrv->nChannels));
  DebugMsg->Add("   nSamplesPerSec:"+IntToStr(pwfDrv->nSamplesPerSec));
  DebugMsg->Add("   nAvgBytesPerSec:"+IntToStr(pwfDrv->nAvgBytesPerSec));
  DebugMsg->Add("   nBlockAlign:"+IntToStr(pwfDrv->nBlockAlign));
  DebugMsg->Add("   wBitsPerSample:"+IntToStr(pwfDrv->wBitsPerSample));
  DebugMsg->Add("   cbSize:"+IntToStr(pwfDrv->cbSize));
  DebugMsg->Add("");
*/
//
  mmr = acmStreamOpen(&sPCM_TRUESPEECH,
                      ACMDrv, // driver handle
                      pwfPCM, // source format
                      pwfDrv, // destination format
                      NULL, // no filter
                      NULL, // no callback
                      0, // instance data (not used)
                      ACM_STREAMOPENF_NONREALTIME); // flags
  if (mmr)
    return(false);
//     throw Exception("acmStreamOpen 失败 PCM->Drv :"+IntToStr(mmr));

  mmr = acmStreamOpen(&sTRUESPEECH_PCM,
                      ACMDrv, // driver handle
                      pwfDrv, // source format
                      pwfPCM, // destination format
                      NULL, // no filter
                      NULL, // no callback
                      0, // instance data (not used)
                      ACM_STREAMOPENF_NONREALTIME); // flags
  if (mmr)
    return(false);
//    throw Exception("acmStreamOpen 失败 Drv->PCM :"+IntToStr(mmr));
  return(true);
}

TACMConvert::~TACMConvert()
{
//  free(pwfPCM);
  if(pwfDrv)
    free(pwfDrv);
  acmStreamClose(sPCM_TRUESPEECH, 0);
  acmStreamClose(sTRUESPEECH_PCM, 0);
  if(ACMDrv)
    acmDriverClose(ACMDrv, 0);
}

bool TACMConvert::Compress(BYTE *Data,int &DataLen)
{

//Src->PCM
/*
  HACMSTREAM hstr = NULL;
  MMRESULT  mmr = acmStreamOpen(&hstr,
                      NULL, // any driver
                      &wfSrc, // source format
                      pwfPCM, // destination format
                      NULL, // no filter
                      NULL, // no callback
                      0, // instance data (not used)
                      ACM_STREAMOPENF_NONREALTIME); // flags
  if (mmr)
   { throw Exception("acmStreamOpen 失败 Src->PCM :"+IntToStr(mmr));
     return(false);
   }
  int PCMSamples = DataLen * pwfPCM->nSamplesPerSec / wfSrc.nSamplesPerSec;
  int PCMDatalen = PCMSamples * pwfPCM->wBitsPerSample / 8;
  BYTE *PCMData = new BYTE [PCMDatalen];
//  memset(pDst1Data, 0, dwDst1Bytes);
  ACMSTREAMHEADER strhdr;
  memset(&strhdr, 0, sizeof(ACMSTREAMHEADER));
  strhdr.cbStruct = sizeof(ACMSTREAMHEADER);
  strhdr.pbSrc = Data;
  strhdr.cbSrcLength = DataLen;
  strhdr.pbDst = PCMData;
  strhdr.cbDstLength = PCMDatalen;

  mmr = acmStreamPrepareHeader(hstr, &strhdr, 0);

  mmr = acmStreamConvert(hstr, &strhdr, 0);
  if (mmr)
   { throw Exception("acmStreamConvert 失败 Src->PCM :"+IntToStr(mmr));
     return(false);
   }
  acmStreamClose(hstr, 0);
*/
//PCM->Drv

//  DWORD DrvDatalen = pwfDrv->nAvgBytesPerSec * PCMSamples / pwfPCM->nSamplesPerSec;
//  DrvDatalen = DrvDatalen * 3 / 2; // add a little room
//  BYTE *DrvData = new BYTE [DrvDatalen];
  MMRESULT mmr;
  memset(&sHeadPCM_TRUESPEECH, 0, sizeof(ACMSTREAMHEADER));
  sHeadPCM_TRUESPEECH.cbStruct = sizeof(ACMSTREAMHEADER);
  sHeadPCM_TRUESPEECH.pbSrc = Data; // the source data to convert
  sHeadPCM_TRUESPEECH.cbSrcLength = DataLen;
  sHeadPCM_TRUESPEECH.cbSrcLengthUsed = DataLen;
  sHeadPCM_TRUESPEECH.pbDst = Data;
  sHeadPCM_TRUESPEECH.cbDstLength = DataLen;

  mmr = acmStreamPrepareHeader(sPCM_TRUESPEECH, &sHeadPCM_TRUESPEECH, 0);
  if(mmr!=MMSYSERR_NOERROR)
    return(false);

//  if(!CheckError(mmr,"acmStreamPrepareHeader 失败 PCM->Drv"))
//    return(false);
  mmr = acmStreamConvert(sPCM_TRUESPEECH, &sHeadPCM_TRUESPEECH, 0);
  if(mmr!=MMSYSERR_NOERROR)
    return(false);

//  if(!CheckError(mmr,"acmStreamConvert 失败 PCM->Drv"))
//    return(false);
  DataLen=sHeadPCM_TRUESPEECH.cbDstLengthUsed;
  return(true);
}

bool TACMConvert::UnCompress(BYTE *Data,int DataLen)
{
//解压
  UncmpLen=0;
  MMRESULT mmr;
  memset(&sHeadTRUESPEECH_PCM, 0, sizeof(ACMSTREAMHEADER));
  sHeadTRUESPEECH_PCM.cbStruct = sizeof(ACMSTREAMHEADER);
  sHeadTRUESPEECH_PCM.pbSrc = Data;
  sHeadTRUESPEECH_PCM.cbSrcLength = DataLen;
  sHeadTRUESPEECH_PCM.cbSrcLengthUsed = DataLen;
  sHeadTRUESPEECH_PCM.pbDst = UncmpData; // the source data to convert
  sHeadTRUESPEECH_PCM.cbDstLength = SamplesPerSec * BitsPerSample/4;

  mmr = acmStreamPrepareHeader(sTRUESPEECH_PCM, &sHeadTRUESPEECH_PCM, 0);
  if(mmr!=MMSYSERR_NOERROR)
    return(false);

//  if(!CheckError(mmr,"acmStreamPrepareHeader 失败 Drv->PCM"))
//    return(false);

  mmr = acmStreamConvert(sTRUESPEECH_PCM, &sHeadTRUESPEECH_PCM, 0);
  if(mmr!=MMSYSERR_NOERROR)
    return(false);
//  if(!CheckError(mmr,"acmStreamConvert 失败 Drv->PCM"))
//    return(false);
  UncmpLen=sHeadTRUESPEECH_PCM.cbDstLengthUsed;
  return(true);
}
/*
bool TACMConvert::CheckError(MMRESULT  mmr,AnsiString Prompt)
{
   switch(mmr)
     { case 0: return(true);
       case ACMERR_BUSY: DebugMsg->Add(Prompt+" ACMERR_BUSY"); return(false);
       //The stream header specified in pash is currently in use and cannot be reused.
       case ACMERR_UNPREPARED: DebugMsg->Add(Prompt+" ACMERR_UNPREPARED"); return(false);
       // The stream header specified in pash is currently not prepared by the acmStreamPrepareHeader function.
       case MMSYSERR_INVALFLAG: DebugMsg->Add(Prompt+" MMSYSERR_INVALFLAG"); return(false);
       // At least one flag is invalid.
       case MMSYSERR_INVALHANDLE: DebugMsg->Add(Prompt+" MMSYSERR_INVALHANDLE"); return(false);
       // The specified handle is invalid.
       case MMSYSERR_INVALPARAM: DebugMsg->Add(Prompt+" MMSYSERR_INVALPARAM"); return(false);
       case MMSYSERR_NOMEM : DebugMsg->Add(Prompt+" MMSYSERR_NOMEM"); return(false);
       default :
          DebugMsg->Add(Prompt+" "+IntToStr(mmr));
          return(false);
     }
}
*/
bool TACMConvert::GetDriverFormat(WORD wFormatTag,WAVEFORMATEX *pwf)
{
    memset(pwf, 0, MaxFromatSize);
    pwf->cbSize = MaxFromatSize - sizeof(WAVEFORMATEX);
    pwf->wFormatTag = wFormatTag;

    ACMFORMATDETAILS fd;
    memset(&fd, 0, sizeof(fd));
    fd.cbStruct = sizeof(ACMFORMATDETAILS);
    fd.pwfx = pwf;
    fd.cbwfx = MaxFromatSize;
    fd.dwFormatTag = wFormatTag;

    // set up a struct to control the enumeration
    FIND_DRIVER_INFO fdi;
    fdi.ACMConvert=this;
    fdi.hadid = NULL;
    fdi.wFormatTag = wFormatTag;

    MMRESULT mmr = acmFormatEnum(ACMDrv, &fd, find_format_enum, (DWORD)(VOID*)&fdi, 0);
    if ((fdi.hadid == NULL) || mmr)
      return(false);
    return(true);
}
BOOL CALLBACK find_format_enum(HACMDRIVERID hadid, LPACMFORMATDETAILS pafd, DWORD dwInstance, DWORD fdwSupport)
{
	FIND_DRIVER_INFO* pdi = (FIND_DRIVER_INFO*) dwInstance;
	if (pafd->dwFormatTag == (DWORD)pdi->wFormatTag) {
		// found it
		pdi->hadid = hadid;
		return FALSE; // stop enumerating
	}

	return TRUE; // continue enumerating
}

BOOL CALLBACK find_driver_enum(HACMDRIVERID hadid, DWORD dwInstance, DWORD fdwSupport)
{
	FIND_DRIVER_INFO* pdi = (FIND_DRIVER_INFO*) dwInstance;

	// open the driver
	HACMDRIVER had = NULL;
	MMRESULT mmr = acmDriverOpen(&had, hadid, 0);
	if (mmr) {

		// some error
		return FALSE; // stop enumerating

	}

	// enumerate the formats it supports
	DWORD dwSize = 0;
	mmr = acmMetrics((HACMOBJ)had, ACM_METRIC_MAX_SIZE_FORMAT, &dwSize);
	if (dwSize < sizeof(WAVEFORMATEX)) dwSize = sizeof(WAVEFORMATEX); // for MS-PCM
	WAVEFORMATEX* pwf = (WAVEFORMATEX*) malloc(dwSize);
	memset(pwf, 0, dwSize);
	pwf->cbSize = LOWORD(dwSize) - sizeof(WAVEFORMATEX);
	pwf->wFormatTag = pdi->wFormatTag;
	ACMFORMATDETAILS fd;
	memset(&fd, 0, sizeof(fd));
	fd.cbStruct = sizeof(fd);
	fd.pwfx = pwf;
	fd.cbwfx = dwSize;
	fd.dwFormatTag = pdi->wFormatTag;
	mmr = acmFormatEnum(had, &fd, find_format_enum, (DWORD)(VOID*)pdi, 0);
	free(pwf);
	acmDriverClose(had, 0);
	if (pdi->hadid || mmr)
         {
		// found it or some error
		return FALSE; // stop enumerating
	 }
	return TRUE; // continue enumeration
}