加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

windows操作系统下利用wavein和waveout函数录音和放音

(2013-11-04 16:37:20)
标签:

it

1、先设置wavein和waveout参数:采样率、数据位数、通道数、数据格式等参数,然后建立wavein和waveout的回调函数,代码如下:

 wfx.nSamplesPerSec = 8000;
 wfx.wBitsPerSample = 16;
 wfx.nChannels= 1;
 wfx.cbSize = 0;
 wfx.wFormatTag = WAVE_FORMAT_PCM;
 wfx.nBlockAlign = (wfx.wBitsPerSample * wfx.nChannels) >> 3;
 wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
 waveFreeBlockCount_IN = 5;
 
 if(waveInOpen(&hWaveIn, WAVE_MAPPER, &wfx, (DWORD_PTR)waveInProc, (DWORD_PTR)&waveFreeBlockCount_IN, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
 {
  ExitProcess(1);
 
 waveBlocks = allocateBlocks(BLOCK_SIZE, BLOCK_COUNT);
 waveFreeBlockCount = BLOCK_COUNT;
 waveCurrentBlock= 0;
 InitializeCriticalSection(&waveCriticalSection);
 
 wfx.nSamplesPerSec = 8000;
 wfx.wBitsPerSample = 16;
 wfx.nChannels= 1;
 wfx.cbSize = 0;
 wfx.wFormatTag = WAVE_FORMAT_PCM;
 wfx.nBlockAlign = (wfx.wBitsPerSample * wfx.nChannels) >> 3;
 wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
 
 if(waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, (DWORD_PTR)waveOutProc, (DWORD_PTR)&waveFreeBlockCount, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
 {
  ExitProcess(1);
 }
 
 //建立两个数组(这里可以建立多个数组)用来缓冲音频数据 
 //DWORD bufsize = 2 * 1024;
 DWORD bufsize = 1985*2;
 pBuffer1 = new BYTE[bufsize]; 
 pBuffer2 = new BYTE[bufsize];
 pBuffer3 = new BYTE[bufsize]; 
 pBuffer4 = new BYTE[bufsize];
 pBuffer5 = new BYTE[bufsize];
 //将建立好的wHdr1做为备用
 wHdr1.lpData = (LPSTR)pBuffer1; 
 wHdr1.dwBufferLength = bufsize; 
 wHdr1.dwBytesRecorded = 0; 
 wHdr1.dwUser = 0; 
 wHdr1.dwFlags = 0; 
 wHdr1.dwLoops = 1; 
 wHdr1.lpNext = NULL; 
 wHdr1.reserved = 0;    
 waveInPrepareHeader(hWaveIn,&wHdr1,sizeof(WAVEHDR)); 
 //将建立好的wHdr2做为备用
 wHdr2.lpData = (LPSTR)pBuffer2; 
 wHdr2.dwBufferLength = bufsize; 
 wHdr2.dwBytesRecorded = 0; 
 wHdr2.dwUser = 0; 
 wHdr2.dwFlags = 0; 
 wHdr2.dwLoops = 1; 
 wHdr2.lpNext = NULL; 
 wHdr2.reserved = 0;   
 waveInPrepareHeader(hWaveIn,&wHdr2,sizeof(WAVEHDR)); 
 //将建立好的wHdr3做为备用
 wHdr3.lpData = (LPSTR)pBuffer3; 
 wHdr3.dwBufferLength = bufsize; 
 wHdr3.dwBytesRecorded = 0; 
 wHdr3.dwUser = 0; 
 wHdr3.dwFlags = 0; 
 wHdr3.dwLoops = 1; 
 wHdr3.lpNext = NULL; 
 wHdr3.reserved = 0;  
 waveInPrepareHeader(hWaveIn,&wHdr3,sizeof(WAVEHDR)); 
 //将建立好的wHdr4做为备用  
 wHdr4.lpData = (LPSTR)pBuffer4; 
 wHdr4.dwBufferLength = bufsize; 
 wHdr4.dwBytesRecorded = 0; 
 wHdr4.dwUser = 0; 
 wHdr4.dwFlags = 0; 
 wHdr4.dwLoops = 1; 
 wHdr4.lpNext = NULL; 
 wHdr4.reserved = 0;  
 waveInPrepareHeader(hWaveIn,&wHdr4,sizeof(WAVEHDR));
 //将建立好的wHdr5做为备用
 wHdr5.lpData = (LPSTR)pBuffer5; 
 wHdr5.dwBufferLength = bufsize; 
 wHdr5.dwBytesRecorded = 0; 
 wHdr5.dwUser = 0; 
 wHdr5.dwFlags = 0; 
 wHdr5.dwLoops = 1; 
 wHdr5.lpNext = NULL; 
 wHdr5.reserved = 0; 
 waveInPrepareHeader(hWaveIn,&wHdr5,sizeof(WAVEHDR)); 
 //将两个wHdr添加到waveIn中去 
 waveInAddBuffer (hWaveIn, &wHdr1, sizeof (WAVEHDR)) ; 
 waveInAddBuffer (hWaveIn, &wHdr2, sizeof (WAVEHDR)) ;
 waveInAddBuffer (hWaveIn, &wHdr3, sizeof (WAVEHDR)) ; 
 waveInAddBuffer (hWaveIn, &wHdr4, sizeof (WAVEHDR)) ;
 waveInAddBuffer (hWaveIn, &wHdr5, sizeof (WAVEHDR)) ;
 //开始音频采集 
 UDP_Decode_num = 1;
 Stop_Mic_Data_Flag = 0;
 MIC_Receive_Flag = 1;
 Code_Data_Flag_A = 0;
 Code_Data_Flag_B = 0;
 Code_Data_Flag_C = 0;
 Code_Data_Flag_D = 0;
 Code_Data_Flag_E = 0;

 waveInStart(hWaveIn);    //启动语音采集
 

2、wavein和waveout回调函数

static void CALLBACK waveInProc(HWAVEIN hWaveIn,UINT uMsg,DWORD dwInstance,DWORD dwParam1,DWORD dwParam2)
{
 //这个CIMAADPCMDlg就是你的音频采集类 
 //CPCM_PLAYDlg *pWnd = (CPCM_PLAYDlg*)dwInstance; 
 int re(0); 
 switch(uMsg)  
 
  case WIM_OPEN: 
   TRACE("WIM_OPEN\n"); 
   break;   

  case WIM_DATA: 
   //TRACE("WIM_DATA\n"); 
   //这里就是对采集到的数据做处理的地方,我是做了发送处理 
   //((PWAVEHDR)dwParam1)->lpData这就是采集到的数据指针 
   //((PWAVEHDR)dwParam1)->dwBytesRecorded这就是采集到的数据长度 
   //re = send(pWnd->sends,((PWAVEHDR)dwParam1)->lpData,((PWAVEHDR)dwParam1)->dwBytesRecorded,0); 
   //处理完了之后还要再把这个缓冲数组加回去 
   if(Code_Data_Flag_A == 0 && MIC_Receive_Flag == 1)
   {
    BUF1 = ((PWAVEHDR)dwParam1)->lpData;
    MIC_Receive_Num = ((PWAVEHDR)dwParam1)->dwBytesRecorded;
    MIC_Receive_Flag = 2;
    Code_Data_Flag_A = 1;
   }
   else if(Code_Data_Flag_B == 0 && MIC_Receive_Flag == 2)
   {
    BUF2 = ((PWAVEHDR)dwParam1)->lpData;
    MIC_Receive_Num = ((PWAVEHDR)dwParam1)->dwBytesRecorded;
    MIC_Receive_Flag = 3;
    Code_Data_Flag_B = 1;
   }
   else if(Code_Data_Flag_C == 0 && MIC_Receive_Flag == 3)
   {
    BUF3 = ((PWAVEHDR)dwParam1)->lpData;
    MIC_Receive_Num = ((PWAVEHDR)dwParam1)->dwBytesRecorded;
    MIC_Receive_Flag = 4;
    Code_Data_Flag_C = 1;
   }
   else if(Code_Data_Flag_C == 0 && MIC_Receive_Flag == 4)
   {
    BUF4 = ((PWAVEHDR)dwParam1)->lpData;
    MIC_Receive_Num = ((PWAVEHDR)dwParam1)->dwBytesRecorded;
    MIC_Receive_Flag = 5;
    Code_Data_Flag_D = 1;
   }
   else if(Code_Data_Flag_C == 0 && MIC_Receive_Flag == 5)
   {
    BUF5 = ((PWAVEHDR)dwParam1)->lpData;
    MIC_Receive_Num = ((PWAVEHDR)dwParam1)->dwBytesRecorded;
    MIC_Receive_Flag = 1;
    Code_Data_Flag_E = 1;
   }
   //BUF1 = ((PWAVEHDR)dwParam1)->lpData;
   //MIC_Receive_Num = ((PWAVEHDR)dwParam1)->dwBytesRecorded;
   //MIC_Receive_Flag = 1;
   //Stop_Mic_Data_Flag代表是否继续采集,因为当停止采集的时候,只有当所有的 
   //缓冲数组都腾出来之后才能close,所以需要停止采集时就不要再waveInAddBuffer了 
   if(Stop_Mic_Data_Flag == 0)
   {
    waveInPrepareHeader(hWaveIn, (PWAVEHDR) dwParam1, sizeof (WAVEHDR));
    waveInAddBuffer (hWaveIn, (PWAVEHDR) dwParam1, sizeof (WAVEHDR)) ;
    //TRACE("%d\n",Stop_Mic_Data_Flag);
   }
     
    break; 
  
  case WIM_CLOSE: 
    TRACE("WIM_CLOSE\n"); 
     break; 
   default: 
    break; 
 
}

static void CALLBACK waveOutProc(HWAVEOUT hWaveOut,UINT uMsg,DWORD dwInstance,DWORD dwParam1,DWORD dwParam2)
{
 
 int* freeBlockCounter = (int*)dwInstance;
 
 if(uMsg != WOM_DONE)
  return;

 EnterCriticalSection(&waveCriticalSection);
 (*freeBlockCounter)++;
 LeaveCriticalSection(&waveCriticalSection);
}

void writeAudio(HWAVEOUT hWaveOut,LPSTR data, int size)
{
 WAVEHDR* current;
 int remain;
 current = &waveBlocks[waveCurrentBlock];
 while(size > 0)
 {
  
  if(current->dwFlags & WHDR_PREPARED)
  {
   waveOutUnprepareHeader(hWaveOut,current, sizeof(WAVEHDR));
  }
  if(size < (int)(BLOCK_SIZE -current->dwUser))
  {
   memcpy(current->lpData +current->dwUser, data, size);
   current->dwUser += size;
   break;
  }
  remain = BLOCK_SIZE - (int)current->dwUser;
  memcpy(current->lpData + current->dwUser, data, remain);
  size -= remain;
  data += remain;
  current->dwBufferLength = BLOCK_SIZE;
  waveOutPrepareHeader(hWaveOut, current, sizeof(WAVEHDR));
  waveOutWrite(hWaveOut, current, sizeof(WAVEHDR));
  EnterCriticalSection(&waveCriticalSection);
  waveFreeBlockCount--;
  LeaveCriticalSection(&waveCriticalSection);
  
  while(!waveFreeBlockCount)
  {
   Sleep(10);
  }
  
  waveCurrentBlock++;
  waveCurrentBlock %= BLOCK_COUNT;
  current = &waveBlocks[waveCurrentBlock];
  current->dwUser = 0;
 }

}

WAVEHDR* allocateBlocks(int size, int count)
{
 unsigned char* buffer;
 int i;
 WAVEHDR* blocks;
 DWORD totalBufferSize = (size + sizeof(WAVEHDR)) * count;
 
 if((buffer = (unsigned char*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, totalBufferSize)) == NULL)
 {
  fprintf(stderr, "Memory allocationerror\n");
  ExitProcess(1);
 }
 
 blocks = (WAVEHDR*)buffer;
 buffer += sizeof(WAVEHDR) * count;
 for(i = 0; i < count; i++)
 {
  blocks[i].dwBufferLength = size;
  blocks[i].lpData = (LPSTR)buffer;
  buffer += size;
 }
 return blocks;
}
void freeBlocks(WAVEHDR* blockArray)
{
 
 HeapFree(GetProcessHeap(), 0, blockArray);
}

3、变量定义

#define BLOCK_SIZE 20480
#define BLOCK_COUNT 20
 
//WAVEHDR waveHeader1,waveHeader2;
BYTE *pBuffer1,*pBuffer2,*pBuffer3,*pBuffer4,*pBuffer5;//采集音频时的数据缓存 

WAVEHDR wHdr1,wHdr2,wHdr3,wHdr4,wHdr5; //采集音频时包含数据缓存的结构体 
int Stop_Mic_Data_Flag;
int MIC_Receive_Flag;
int MIC_Receive_Num;
LPSTR  BUF1  = (char*)malloc(4000);
LPSTR  BUF2  = (char*)malloc(4000);
LPSTR  BUF3  = (char*)malloc(4000);
LPSTR  BUF4  = (char*)malloc(4000);
LPSTR  BUF5  = (char*)malloc(4000); 
WAVEFORMATEX waveFormat;
WAVEOUTCAPS pwoc;
HWAVEOUT hWaveOut;
HWAVEIN hWaveIn;
WAVEFORMATEX * lpFormat;
WAVEFORMATEX wfx;
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
LPSTR loadAudioBlock(LPCWSTR filename, DWORD* blockSize);

void writeAudioBlock(HWAVEOUT hWaveOut , LPSTR block, DWORD size);
//消息回掉函数
static void CALLBACK waveOutProc(HWAVEOUT, UINT, DWORD, DWORD, DWORD);
static void CALLBACK waveInProc(HWAVEIN, UINT, DWORD, DWORD, DWORD);

static WAVEHDR* allocateBlocks(int size, int count);
static void freeBlocks(WAVEHDR* blockArray);
static void writeAudio(HWAVEOUT hWaveOut, LPSTR data, int size);

static CRITICAL_SECTION waveCriticalSection;
static WAVEHDR* waveBlocks;
static volatile int waveFreeBlockCount;
static volatile int waveFreeBlockCount_IN;
static int waveCurrentBlock;
4、需要加载头文件

#include "mmreg.h"
#include "mmsystem.h"
#pragma comment(lib, "ws2_32.lib")

5、附加说明

经验证明:语音采集开辟5个缓冲区,每个大于采集时间大于100ms,放音开辟20个缓冲区,每个大于100ms,能完全保证语音采集和放音的连续性,无中断发生。

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有