Linux ALSA snd_pcm_writei计时

时间:2014-09-24 06:54:13

标签: linux audio embedded-linux alsa

我正在尝试以重复的方式播放1000毫秒的wav文件。所以播放1000ms,然后播放1000ms的静音,再播放1000ms的音频,......

但是当我在这个过程中打印时间时,我注意到声音播放后snd_pcm_writei()会占用一些,因此 ~1600ms而不是1000ms 。我正在使用阻止模式。

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

如果我使用非阻塞模式,声音会播放很短的时间,几毫秒。

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);

具有1000ms音频样本的缓冲区为16000字节,因为(8000个样本/秒)* 2字节/样本(单声道+ 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之间,因此根本不准确。

1 个答案:

答案 0 :(得分:0)

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

是的,我总能听到声音。 我首先将长度改为8000,就像你建议的那样。 它没有真正帮助,但显然是一个错误。

然后我更改了buffersize和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;

我不知道为什么但调整后的时间是正确的。 谢谢你的帮助!