最近搞了一个用于播放网络上传来的PCM数据的网络播放声音的东东,这里是主要是想说明一下如何使用waveXXX系列函数编写声音播放程序,同时要注意的就是为了保持声音播放的连续性采用了双缓冲的方式,可以先试单缓冲播放时听听效果,一播一卡一播一卡,采用了双缓冲以后声音马上连续播放了。
下面符上代码,直接在win32控制台程序下就可以运行:
// vc console
#include <stdio.h>
#include <windows.h>
#include <winsock.h>
#include <mmreg.h>
#pragma comment(lib, "Winmm.lib")
#pragma comment(lib, "Ws2_32.lib")
#define IP "192.168.1.131"
int _tmain(int argc, _TCHAR* argv[])
{
//初始化网络
WSADATA wsa;
DWORD nResult = WSAStartup( MAKEWORD(2,2), &wsa );
if( nResult != 0 )
{
printf("WSAStartup初始化网络失败! 错误号: %d\n", WSAGetLastError());
return 0;
}
else
{
printf("WSAStartup初始化网络成功!\n");
}
//创建SOCKET套接字
SOCKET ClientSock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if( ClientSock == INVALID_SOCKET )
{
printf( "socket创建失败! 错误号: %d\n", WSAGetLastError() );
return 0;
}
else
{
printf( "socket创建成功!\n" );
}
//定义地址
SOCKADDR_IN addr;
addr.sin_family = AF_INET;
addr.sin_port = 8000;
addr.sin_addr.S_un.S_addr = inet_addr( IP ); // INADDR_ANY
//绑定地址
if ( SOCKET_ERROR == connect( ClientSock, (sockaddr*)&addr, sizeof(addr) ) )
{
printf( "connect函数链接地址失败! 错误号: %d\n", WSAGetLastError() );
return 0;
}
else
{
printf( "connect函数链接地址成功!\n" );
}
//----------------------------------------------------------------------------
HWAVEOUT hWaveOut; //波形音频输出句柄
WAVEFORMATEX waveformat;
memset(&waveformat, 0x00, sizeof(WAVEFORMATEX));
// 典型参数设置方法
waveformat.nSamplesPerSec = 44100; /* sample rate */
waveformat.wBitsPerSample = 16; /* sample size */
waveformat.nChannels = 2; /* channels */
waveformat.cbSize = 0; /* size of _extra_ info */
waveformat.wFormatTag = WAVE_FORMAT_PCM;//WAVE_FORMAT_PCM;
waveformat.nBlockAlign = (waveformat.wBitsPerSample * waveformat.nChannels) >> 3;
waveformat.nAvgBytesPerSec = waveformat.nBlockAlign * waveformat.nSamplesPerSec;
waveOutOpen (&hWaveOut, WAVE_MAPPER,&waveformat,0, 0, CALLBACK_NULL);
/*
这里要注意的就是对于音频要采用双缓冲技术来保证声音的连续性,
所谓双缓冲就是使用两个WAVEHDR结构体与HWAVEOUT进行绑定,绑定
就是通过waveOutPrepareHeader (hWaveOut, waveHdr[i], sizeof (WAVEHDR));实现的,
然后在播放的时候分别播放两个waveOutWrite (hWaveOut, waveHdr[i], sizeof (WAVEHDR));
*/
LPBYTE lpData[2]; // = { 0x80 };
LPWAVEHDR waveHdr[2]; //音频数据信息头
//这里是分配内存
for(int i=0; i<2; i++)
{
lpData[i] = new BYTE[65536];
memset(lpData[i], 0x80, 65536); //在音频数据中0x80代表静音符号
waveHdr[i] = new WAVEHDR;
memset(waveHdr[i], 0x00, sizeof(WAVEHDR));
}
//这里是对上面的数据进行初始化
for(int i=0; i<2; i++)
{
waveHdr[i]->lpData = (LPSTR)lpData[i] ;
waveHdr[i]->dwBufferLength = 65536;
waveHdr[i]->dwFlags = WHDR_PREPARED; //#define WHDR_PREPARED 0x00000002 /* set if this header has been prepared */
waveHdr[i]->dwLoops = 0;
//准备信息头
waveOutPrepareHeader (hWaveOut, waveHdr[i], sizeof (WAVEHDR));
}
while(1)
{
for(int i=0; i<2; i++)
{
if(SOCKET_ERROR == recv(ClientSock, (char*)lpData[i], 65536, 0))
break;
waveOutWrite (hWaveOut, waveHdr[i], sizeof (WAVEHDR));
}
}
printf("播放完成!\n");
}