实现网络音频聊天

编程爱好者

在前几期的文章中,我们已经实现了实时的多人文字聊天和文件传输功能,可以说QQ的基本功能我们都已经实现了。如果文字聊天你觉得有点泛味,还可以使用QQ的一个比较高级的功能——音频聊天。本期我们就来编程实现音频聊天,说不定可以帮你省下不少的电话费哟。

本篇是一个实现局域网音频聊天的程序。要实现音频聊天功能,主要是用WaveIn对象进行音频采集和用WaveOut对象进行音频输出。

如何做音频采集

要使用WaveIn和WaveOut进行音频采集和音频输出,程序必须包含“mmsystem.h”头文件,还要加入多媒体库“winmm.lib”。

音频采集的工作是由WaveIn完成的。以下是用WaveIn实现音频采集的流程(如图1)。

24-g16-1-1.jpg
图1

下面是程序的实现代码:

#define BUFF

ER_SIZE 16384

HWAVEIN m

_hWaveIn;//录音设备句柄

PBYTE m_pBu

ffer1, m_pBuffer2;//音频数据缓存

PWAVEHDR m_pWaveHdr1, m_

pWaveHdr2; //音频数据头

WAVEFORMA

TEX m_WaveForMa

tex;//音频格式

//为音频数据头分配内存

m_pWaveHdr1 = new WAVEHDR;

m_pWaveHdr2 = new WAVEHDR;

//为音频数据缓存分配内存

m_pBuffer1 = new BYTE[BUFFER_SI

ZE];

m_pBuffer2 = new BYTE[BUFFER_SI

ZE];

//填写音频格式

m_WaveForMatex.wFormatTag = WAV

E_FORMAT_PCM;//数据格式,WAVE_FO

RMAT_PCM表示脉冲编码调制

m_WaveForMatex.nChannels = 1;//声道

m_WaveForMatex.nSamplesPerSec = 11025;//采样频率

m_WaveForMatex.nAvgBytesPerSec = 11025;//码率

m_WaveForMatex.nBlockAlign = 1;

m_WaveForMatex.wBitsPerSample = 8;//样本大小

m_WaveForMatex.cbSize = 0;

//打开录音设备

if( waveInOpen(

&m_hWaveIn,//录音设备句柄

WAVE_MAPPER,//录音设备ID

&m_WaveForMatex,//音频格式结构的指针

(DWORD)this->m_hWnd,//窗口句柄,表示用该窗口接收录音设备的消息

NULL,

CALLBACK_WINDOW) )//处理消息方式的符号位

{ delete[] m_pBuffer1;

delete[] m_pBuffer2;

AfxMessageBox( "无法打开录音设备" );}

m_pWaveHdr1->lpData = (LPTSTR)m_pBuffer1;//音频数据的内存指针

m_pWaveHdr1->dwBufferLength = BUFFER_SIZE;//音频数据的长度

m_pWaveHdr1->dwBytesRecorded = 0;

m_pWaveHdr1->dwUser = 0;

m_pWaveHdr1->dwFlags = 0;

m_pWaveHdr1->dwLoops = 1;//循环次数

m_pWaveHdr1->lpNext = NULL;

m_pWaveHdr1->reserved = 0;

//为录音设备准备数据头

waveInPrepareHeader( m_hWaveIn, m_pWaveHdr1, sizeof( WAVEHDR ) );

m_pWaveHdr2->lpData = (LPTSTR)m_pBuffer2;

m_pWaveHdr2->dwBufferLength = BUFFER_SIZE;

m_pWaveHdr2->dwBytesRecorded = 0;

m_pWaveHdr2->dwUser = 0;

m_pWaveHdr2->dwFlags = 0;

m_pWaveHdr2->dwLoops = 1;

m_pWaveHdr2->lpNext = NULL;

m_pWaveHdr2->reserved = 0;

waveInPrepareHeader( m_hWaveIn, m_pWaveHdr2, sizeof( WAVEHDR ) );

//为录音设备加入数据头

waveInAddBuffer( m_hWaveIn, m_pWaveHdr1, sizeof( WAVEHDR ) );

waveInAddBuffer( m_hWaveIn, m_pWaveHdr2, sizeof( WAVEHDR ) );

waveInStart( m_hWaveIn );//开始录音

程序分析:上面打开录音设备的函数中,有一个参数是窗口句柄。指定一个窗口句柄后,以后该录音设备的消息将由该指定的窗口所接收。

WaveIn处理的方式也是以消息的方式进行处理的。如用waveInOpen()函数打开一个录音设备后,将会发出MM_WIM_OPEN消息。

WaveIn还有以下相关函数:

● 停止录音

MMRESULT waveInReset( HWAVEIN hwi );

● 关闭录音设备

MMRESULT waveInClose( HWAVEIN hwi );

如何进行音频输出

音频输出的工作由WaveOut对象完成,以下是WaveOut实现输出音频的流程(如图2)。

24-g16-1-2.jpg
图2

下面是程序的实现代码:

HWAVEO

UT m_hWaveO

ut;

if(waveOut

Open(&m_hWa

veOut,WAVE_

MAPPER,&m_

WaveForMatex,(DWORD)this

->m_hWnd,NU

LL,CALLBACK

_WINDOW))

{ delete[] m_pBufferOut;

AfxMessag

eBox( "无法打开音频输出设备" );}

m_pWave

HdrOut->lpDat

a = (LPTSTR)m_pBufferOut;

m_pWaveHdrOut->dwBufferLength = BUFFER_SIZE;

m_pWaveHdrOut->dwBytesRecorded = 0;

m_pWaveHdrOut->dwUser = 0;

m_pWaveHdrOut->dwFlags = 0;

m_pWaveHdrOut->dwLoops = 1;

m_pWaveHdrOut->lpNext = NULL;

m_pWaveHdrOut->reserved = 0;

waveOutPrepareHeader( m_hWaveOut, m_pWaveHdrOut, sizeof( WAVEHDR ) );

//播放音频

waveOutWrite( m_hWaveOut, m_pWaveHdrOut, sizeof( WAVEHDR ) );

下面是WaveOut常用的消息:

● MM_WOM_OPEN——打开设备

● MM_WOM_DONE——播放完毕

● MM_WIM_CLOSE——关闭录音设备

关闭音频输出设备:

MMRESULT waveOutClose( HWAVEOUT hwo );

实现网络即时音频聊天

我们已经知道如何使用WaveIn和WaveOut来进行音频采集和音频播放了。现在要实现音频聊天,无非是把音频数据缓存后收发。关于在网络上收发数据的操作前面两期已讲得很多了,把例程代码稍加修改即可。

值得注意的是,如果要在局域网里实现音频聊天,由于网络传输比较快,所以可以考虑使用TCP/IP编程。而要在Internet里实现的话,考虑到语音传输的连续性,一般都采用UDP/IP编程。

编后:到此,我们的网络编程一点通系列文章就全部刊载完毕了。我们通过编程,实现了国内主流聊天软件QQ的文字聊天、文件传输和语音聊天功能,同时也教会了大家如何进行TCP/IP和UDP/IP编程。相信大家如果能在此基础上进一步学习,必定能够在网络编程方面有一番造诣。