2014-09-24 129 views
0

我試圖以重複的方式播放1000ms的wav文件。所以玩1000毫秒,然後沉默1000毫秒,然後聲音再次1000毫秒,...Linux ALSA snd_pcm_writei時序

但是,當我在這個過程中打印的時間,我注意到snd_pcm_writei()佔用了一些聲音已被播放,並且因而後〜1600ms而不是1000ms。我正在使用阻止模式。

Play Sound: ~1600ms 
Silence:  ~1000ms 
Play Sound: ~1600ms 
.... 

如果我使用非阻塞模式,聲音播放的時間很短,幾ms。 WAV文件的

屬性:

RIFF (little-endian) data, WAVE audio, Microsoft PCM, 16 bit, mono 8000 Hz 

PCM的設置:

err = snd_pcm_hw_params_set_rate_resample(PCM, params, 0); 
err = snd_pcm_nonblock(PCM, 0); 
err = snd_pcm_hw_params_set_access(PCM, params, SND_PCM_ACCESS_RW_INTERLEAVED); 
err = snd_pcm_hw_params_set_format(PCM, params, SND_PCM_FORMAT_S16_LE); 
err = snd_pcm_hw_params_set_channels(PCM, params, 1); 
err = snd_pcm_hw_params_set_rate_near(PCM, params, &rrate, 0); 
err = snd_pcm_hw_params_set_buffer_size_near(PCM, params, &buffer_size); 
err = snd_pcm_hw_params_set_period_size_near(PCM, params, &period_size, &dir); 
err = snd_pcm_hw_params(PCM, params); 

snd_pcm_sw_params_current(PCM, swparams); 
snd_pcm_sw_params_set_start_threshold(PCM, swparams, (buffer_size/period_size) * period_size); 
snd_pcm_sw_params_set_avail_min(PCM, swparams, period_event ? buffer_size : period_size); 
snd_pcm_sw_params(PCM, swparams); 

音頻樣本的1000毫秒的緩衝區爲16000個字節,似乎是正確的,因爲(8000樣本/秒)* 2字節/ sample(單聲道+ S16_LE)。

要開始播放的wav文件,我使用這段代碼:

qDebug() << QTime::currentTime().toString("hh:mm:ss:zzz") << " Play sound"; 
err = snd_pcm_writei(PCM, Buffer, 16000); 
qDebug() << QTime::currentTime().toString("hh:mm:ss:zzz") << " End sound"; 

沒有人有一個解釋或提示,以實現這一目標?也許這是一個錯誤的設置,或者我需要使用非阻塞模式。

感謝

編輯:

返回值或rrate是8000,所以看起來不錯。這裏是一些實際的時間打印。

"10:48:54:893" Play sound 
"10:48:56:794" End sound 
"10:48:57:802" Play sound 
"10:48:58:913" End sound 
"10:48:59:923" Play sound 
"10:49:01:853" End sound 
"10:49:02:862" Play sound 
"10:49:04:793" End sound 
"10:49:05:803" Play sound 
"10:49:06:593" End sound 
"10:49:07:602" Play sound 

END和PLAY之間的時間在1000ms左右,PLAY和END之間的時間在800ms到1900ms之間,所以根本不準確。

+0

'snd_pcm_hw_params_set_rate_near()'返回的'rrate'的值是什麼? – 2014-09-24 07:35:29

+0

'snd_pcm_writei'接受幀計數作爲第三個參數,而不是字節。 – 2014-09-24 08:40:12

+0

你真的聽到了聲音嗎? 您正在測量的不是播放時間,而是測量填充ALSA緩衝區的時間。 如果我們假設ALSA緩衝區長度爲1000ms,那麼首先調用snd_pcm_writei(pcm,buff,8000)會立即返回。 – 2014-09-24 11:44:02

回答

0

@ГеннадийКазачёк:

是的,我總是能聽到聲音。 我第一次改變長度爲8000像你所建議的。它並沒有真正的幫助,但顯然是一個錯誤。

然後,我改變了緩衝區大小和periodsize:

之前

snd_pcm_uframes_t buffer_size = 768; 
snd_pcm_uframes_t period_size = 256; 

snd_pcm_uframes_t buffer_size = 768*2; 
snd_pcm_uframes_t period_size = 256*2; 

後,我不知道爲什麼,但時序是調整之後正確的。 感謝您的幫助!