Linux ALSA snd_pcm_写入定时

Linux ALSA snd_pcm_写入定时,linux,audio,embedded-linux,alsa,Linux,Audio,Embedded Linux,Alsa,我尝试以重复的方式播放1000毫秒的wav文件。所以播放1000毫秒,然后播放1000毫秒的静音,然后再播放1000毫秒的音频,… 但是,当我在这个过程中打印计时时,我注意到snd_pcm_writei()在声音播放后会占用一些时间,因此是约1600ms,而不是1000ms。我正在使用阻塞模式 Play Sound: ~1600ms Silence: ~1000ms Play Sound: ~1600ms .... 如果我使用非阻塞模式,声音会播放很短的时间,几毫秒 w

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

但是,当我在这个过程中打印计时时,我注意到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);
1000毫秒音频采样的缓冲区是16000字节,这似乎是正确的,因为(8000个采样/s)*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";

结束和结束之间的时间约为1000ms,结束和结束之间的时间为800ms到1900ms,因此根本不准确。

@Гаазгггггг

是的,我总是听到声音。 我首先按照你的建议把长度改为8000。 它并没有真正起到帮助作用,但显然是一个bug

然后我更改了buffersize和periodsize:

以前

snd_pcm_uframes_t buffer_size = 768;
snd_pcm_uframes_t period_size = 256;
之后

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

snd_pcm_hw_params_set_rate_near()
返回的
rrate
值是多少?
snd_pcm_writei
接受帧计数作为第三个参数,而不是字节。您真的听到声音了吗?你不是在测量打球的时间,而是在测量填满ALSA缓冲区的时间。如果我们假设ALSA缓冲区的长度为1000毫秒,那么第一次调用'snd_pcm_writei(pcm,buff,8000)将立即返回。
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;