windows下使用waveoutwrite播放pcm的问题

lishi_1991 2015-09-05 04:20:53
我的需求是接受网络发过来的g711数据,在windows接收,转换成pcm播放。
我的设计是接收网络数据开一个线程,接收到后放到一个队列缓冲区;
播放音频开一个线程从队列缓冲区获取音频数据转换播放,采用sleep控制每次拿数据播放的间隔;如果到时间而队列缓冲区没有数据就waveoutwrite 空buf。
现在问题是接收播放一开始没什么问题,播放一段时间后(时间不定几分钟到几十分钟都有可能)声音就出现异常,出现哒哒声,并且声音颤抖,声音延时也很明显,此时如果我把程序重启声音就正常了。
我之前做过linux下alsa音频,在调用类似waveourwrite音频写入函数时发生underun报错现象和这个一样,当时采用报错后写入空数据能够恢复正常。alsa音频驱动报错是因为一定时间内音频硬件缓存没有数据进入就报错,所以此时写入空数据就能恢复。
但是waveoutwrite函数没有任何报错,我想请问各位有没有什么好的办法解决一下,或者各位在做网络音频播放的时候采用什么设计思路呢。
我初始化waveout设备代码如下
static HWAVEOUT        playWavOut;
static WAVEHDR playWavHdr;
static WAVEFORMATEX playWaveform;
static HANDLE playWait;
playWaveform.wFormatTag = WAVE_FORMAT_PCM;
playWaveform.nChannels = N_CHANNEL;
playWaveform.nSamplesPerSec = SAMPLE_RATE;
playWaveform.wBitsPerSample = BITS_PER_SAMPLE;
playWaveform.nBlockAlign = (N_CHANNEL*BITS_PER_SAMPLE)/8;
playWaveform.nAvgBytesPerSec = SAMPLE_RATE*playWaveform.nBlockAlign;
playWaveform.cbSize = 0;
if(playWait){
CloseHandle(playWait);
playWait=NULL;
}
playWait = CreateEvent(NULL, 0, 0, NULL);
if (!waveOutGetNumDevs() ){
TRACE("waveOutGetNumDevs ERR audio.c 95 \n");
_have_init_playback = -1;
return -1;
}
if(waveOutOpen (0,0,&playWaveform,0,0,WAVE_FORMAT_QUERY))
{
TRACE("wave设备初始化失败~");
return false;
}
ret = waveOutOpen(&playWavOut, WAVE_MAPPER, &playWaveform, (DWORD_PTR)playWait, 0L, CALLBACK_EVENT);
TRACE("******* waveOutOpen *******\n");
//ret = waveOutOpen(&playWavOut, WAVE_MAPPER, &playWaveform, NULL, 0L, CALLBACK_EVENT);
if(ret != MMSYSERR_NOERROR){
TRACE("waveOutOpen ERR audio.c 102 \n");
_have_init_playback = -1;
return -1;
}


播放pcm的代码如下:
void playbackPCM(char *buf,int len)
{
int mRet = 0;
ZeroMemory(&playWavHdr, sizeof(WAVEHDR));
playWavHdr.lpData = buf;
playWavHdr.dwBufferLength = len;
playWavHdr.dwFlags = 0L;
playWavHdr.dwLoops = 1L;
mRet = waveOutPrepareHeader(playWavOut, &playWavHdr, sizeof(WAVEHDR));
if( mRet != MMSYSERR_NOERROR ) {
TRACE("waveOutPrepareHeader ERR %d\n",mRet);
}
mRet = waveOutWrite(playWavOut, &playWavHdr, sizeof(WAVEHDR));
if( mRet != MMSYSERR_NOERROR ) {
TRACE("waveOutWrite ERR %d\n",mRet);
}
waveOutUnprepareHeader(playWavOut,&playWavHdr,sizeof(WAVEHDR));
WaitForSingleObject(playWait, INFINITE);
}

谢谢大家。
...全文
971 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
souvis 2016-11-11
  • 打赏
  • 举报
回复
waveOutWrite后不能立即waveOutUnprepareHeader的,因为写入是非阻塞行为,函数返回后声卡驱动还在后台进行播放,应该等到当前数据块播放完成后(MM_WOM_DONE消息通知或者自己检查WAVEHDR的dwFlags )再UnprepareHeader
lishi_1991 2015-09-14
  • 打赏
  • 举报
回复
结贴吧,后来也没找到为什么会出现放音错误,就放弃用waveoutwrite 放音,后来从网上找到一个用directshow放音的例子就拿过来用了,发现挺不错的,运行很长时间不会出错,也不会有耳机插拔的问题。
赵4老师 2015-09-07
  • 打赏
  • 举报
回复
不知道有多少前人掉在TCP Socket send(人多)send(病少)send(财富) recv(人多病)recv(少财富) 陷阱里面啊! http://bbs.csdn.net/topics/380167545 参考开源项目YATE
dong364 2015-09-06
  • 打赏
  • 举报
回复
检查下buf的大小,有效性,是否及时释放,是否被覆盖,是否加锁等等
worldy 2015-09-05
  • 打赏
  • 举报
回复
我猜是数据衔接的时候出现问题的,你自己好好查查
lishi_1991 2015-09-05
  • 打赏
  • 举报
回复
有人遇到过这个问题吗,给指条明路吧
lishi_1991 2015-09-05
  • 打赏
  • 举报
回复
引用 1 楼 worldy 的回复:
你将协议头尾数据当成音频数据去搞了吧?
没有协议头尾是我自己定的,我放进队列缓冲区的时候已经去掉。而且播放时候一开始一段时间是正常的。
worldy 2015-09-05
  • 打赏
  • 举报
回复
你将协议头尾数据当成音频数据去搞了吧?

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧