轉(zhuǎn)載自:http://blog.csdn.net/soliddream66/article/details/5353960
問(wèn)題背景
錄音播音實(shí)際需求
1、隨時(shí)終止
2、錄音并非文件,而是形成rtp發(fā)送
3、播音并非源于文件,而是源于rtp
因此Waveform audio使用的buffer較小,不斷的裝載/發(fā)送 buffer,終止的時(shí)候Reset并且close.
大致如下調(diào)用的循環(huán)
錄音
waveInUnprepareHeader
waveInPrepareHeader
waveInAddBuffer
播音
waveOutUnprepareHeader
waveOutPrepareHeader
waveOutWrite
循環(huán)周期40ms,我采用的是回調(diào)函數(shù)。問(wèn)題是有時(shí)候調(diào)用waveInReset/waveOutReset會(huì)形成死鎖,調(diào)用waveInReset/waveOutReset的線程與回調(diào)函數(shù)所在的線程死鎖在一塊了。
原因分析
這方面網(wǎng)上有文章提到,就是調(diào)用waveInReset/waveOutReset的同時(shí)調(diào)用了錄音/播音循環(huán)調(diào)用的某個(gè)函數(shù)會(huì)形成死鎖。我再稍作解釋下,我們知道buffer滿了或是調(diào)用Reset都會(huì)觸發(fā)消息(回調(diào)函數(shù)方式的話就是MM_WOM_DONE/MM_WIM_DATA),由于調(diào)用waveInReset/waveOutReset所在的線程,與回調(diào)函數(shù)所在的線程不是一個(gè)線程,因此很容易撞車,也就是說(shuō),你調(diào)用reset的時(shí)候,另一個(gè)線程正好在處理MM_WOM_DONE/MM_WIM_DATA,于是就這樣死鎖了。
解決方案
方案一
先加上標(biāo)記(假設(shè)標(biāo)記bReset:bool),令bReset為true;
標(biāo)記作用如下
if(!bReset)
{
錄音
waveInUnprepareHeader
waveInPrepareHeader
waveInAddBuffer
播音
waveOutUnprepareHeader
waveOutPrepareHeader
waveOutWrite
}
延時(shí)調(diào)用waveInReset/waveOutReset,延時(shí)時(shí)間長(zhǎng)度以循環(huán)周期為妙,我這個(gè)例子中也就是采用40ms。
當(dāng)然也可以采用臨界保護(hù)。
方案二
換一個(gè)角度去考慮問(wèn)題,之所以死鎖,是因?yàn)閮蓚€(gè)線程沖突了的緣故,所以可以建立一個(gè)線程
錄音
waveInUnprepareHeader
waveInPrepareHeader
waveInAddBuffer
播音
waveOutUnprepareHeader
waveOutPrepareHeader
waveOutWrite
與waveInReset/waveOutReset都放到這個(gè)線程去處理,自然不會(huì)發(fā)生死鎖了。