音频传输心得

我暑假写了一个网络即时语音通讯的工具,较好的解决了声音采集和播放的问题,我把我的想法贴出来跟大家切磋,望指正。我的e-mial:[email protected] 
      语音录制的关键是解决好声音的连续和延迟这两个问题,可以采用五个内存块循环使用,每个内存块录制声音的长度为100ms,在录音开始前,用waveInPrepareHeader和waveInAddBuffer函数把所有的五个内存块都添加到录音设备以保存录音数据,这样就可以连续录制长达500ms的语音数据,当每个内存块录满数据后,消息响应函数处理完相应的操作后,马上通过调用waveInAddBuffer函数把缓冲区重新添加到录音设备,这样就保证了总存在可用的缓冲区保存录音数据,不会产生录音中断。事实也证明这样的处理方法在连续性和延迟性都有良好的表现。这里还有一个技巧值得注意:因为是五个同样的缓冲区在循环使用,因此对每个缓冲区调用一次waveInPrepareHeader函数就可以了,实现缓冲区的重复使用只要反复调用waveInAddBuffer函数把相应的缓冲区重新添加到录音设备就行了,直到录音结束才调用waveInUnprepareHeader函数清空内存块。 
        像录音一样,放音也必须首先打开播放设备和指定录音格式,然后调用waveOutPrepareHeader函数为播放设备准备缓冲区,随后就可以用waveOutWrite函数把需要播放的音频数据块发送到播放设备的缓存进行播放,直到放音结束才取消分配给放音设备的内存块,关闭放音设备。为了避免频繁的调用waveOutPrepareHeader和waveOutUnprepareHeader这两个函数,像录音一样采用若干缓冲区成队列地进行循环,这样在整个放音过程只分别调用这两个函数一次,节省了时间开销,对提高语音播放的连续性很有帮助的。当从网络中接收到压缩了的音频数据,解压后就拷贝到当前WAVEHDR结构的lpData成员指向的内存块,调用waveOutWrite函数进行播放,在缓冲区队列循环中用一个int变量标记当前的WAVEHDR结构用以控制队列的循环,但这样做有可能发生错误,就是当播放线程被阻塞时,有可能一个缓冲区的音频数据还没有播放完毕又对同一个缓冲区写数据,这是不允许的。解决的办法是尽量增加缓冲区的数目,事实证明使用20个缓冲区(每个缓冲区存放100ms的音频数据)可以有效的防止这种错误的发生,当然这样并不能完全地避免错误,此时就必须调用waveOutReset对放音设备重置,这就会丢失一些数据,但对于语音来说是可以容忍的。对于语音通讯来说,延时不能太长,否则就会令人感到很别扭的,因为采用的缓冲区多就有可能会把延迟累积下来,使得延迟越来越长,这时可以每隔一分钟调用waveOutReset对放音设备重置一次,可以再设一个int变量标记缓冲区队列的循环次数,当每达到30次(刚好一分钟)就重置一次,消除积累延迟(会丢失一些数据)。

你可能感兴趣的:(网络,工具,通讯)