gpt4 book ai didi

linux - ALSA:播放音频的正确方法 - 阻塞模式和线程

转载 作者:太空宇宙 更新时间:2023-11-04 10:09:13 25 4
gpt4 key购买 nike

我无法以正确的方式编写播放音频的循环和/或我没有正确理解 Alsa 的 start_threshold、stop_threshold 和 avail_min 参数的含义。我想达到最低延迟并知道要修改的正确参数,以便使我的捕获过程回放链能够容忍音频处理时间的变化。在这个例子中,我从文件中读取样本,以专注于播放部分。

这是我的输出设备配置,以阻塞模式打开(Ubuntu 16.04,存在 PulseAudio,默认 设备):

ALSA <-> PulseAudio PCM I/O Plugin
Its setup is:
stream : PLAYBACK
access : RW_INTERLEAVED
format : FLOAT_LE
subformat : STD
channels : 1
rate : 44100
exact rate : 44100 (44100/1)
msbits : 32
buffer_size : 6144
period_size : 2048
period_time : 46439
tstamp_mode : NONE
tstamp_type : GETTIMEOFDAY
period_step : 1
avail_min : 4096
period_event : 0
start_threshold : 2048
stop_threshold : 2048
silence_threshold: 0
silence_size : 0
boundary : 6917529027641081856

我的播放线程从另一个线程获取音频缓冲区,该线程从文件中读取样本(因此比播放速率更快)。这是回放函数(Cython代码):

cdef int play_buffer(self, buffer_t *buf) nogil:

cdef int rc
cdef long t0, t1

t0 = timestamp_us()
rc = snd_pcm_writei(self.handle, buf.data, buf.period_size)
t1 = timestamp_us()

if rc >= 0:
printf("[%ld / %6ld] snd_pcm_writei: OK %d\n", t0, t1 - t0, rc)
else:
printf("[%ld / %6ld] snd_pcm_writei: ERR %d [%s]\n", t0, t1 - t0, rc, snd_strerror(rc))

if rc < 0:
if rc == -errno.EPIPE:
rc = snd_pcm_prepare(self.handle)
printf("snd_pcm_prepare: %d\n", rc)

else:
printf("play_buffer ERR %d\n", rc)
return WRITE_ERROR

elif rc != buf.period_size:
printf('snd_pcm_writei(): short write %d != %d', rc, buf.period_size)

return OK

这是输出(timestamp_us() 以微秒为单位返回系统时间):

[1525102519583090 /    540] snd_pcm_writei: OK 2048
[1525102519585406 / 16] snd_pcm_writei: ERR -32 [Broken pipe]
snd_pcm_prepare: 0
[1525102519587798 / 393] snd_pcm_writei: OK 2048
[1525102519590018 / 3] snd_pcm_writei: ERR -32 [Broken pipe]
snd_pcm_prepare: 0
[1525102519592303 / 415] snd_pcm_writei: OK 2048
[1525102519594523 / 3] snd_pcm_writei: ERR -32 [Broken pipe]
snd_pcm_prepare: 0
[1525102519596823 / 1905] snd_pcm_writei: OK 2048
[1525102519599242 / 12] snd_pcm_writei: ERR -32 [Broken pipe]
snd_pcm_prepare: 0
[1525102519601707 / 8023] snd_pcm_writei: OK 2048
[1525102519609754 / 45] snd_pcm_writei: OK 2048
[1525102519609811 / 27] snd_pcm_writei: OK 2048
[1525102519609847 / 28] snd_pcm_writei: OK 2048
[1525102519611328 / 40] snd_pcm_writei: OK 2048
[1525102519613546 / 48501] snd_pcm_writei: OK 2048
[1525102519662079 / 50678] snd_pcm_writei: OK 2048
[1525102519712804 / 49487] snd_pcm_writei: OK 2048
[1525102519762318 / 50521] snd_pcm_writei: OK 2048
[1525102519812868 / 49497] snd_pcm_writei: OK 2048
[1525102519862394 / 49630] snd_pcm_writei: OK 2048
[1525102519912051 / 49875] snd_pcm_writei: OK 2048
[1525102519961953 / 50647] snd_pcm_writei: OK 2048
[1525102520012655 / 49949] snd_pcm_writei: OK 2048
[1525102520062632 / 49713] snd_pcm_writei: OK 2048
[1525102520112373 / 49495] snd_pcm_writei: OK 2048
[1525102520161898 / 62] snd_pcm_writei: OK 2048
[1525102520161977 / 50485] snd_pcm_writei: OK 2048
[1525102520212490 / 49514] snd_pcm_writei: OK 2048
.. continues with no errors ...

一开始我不明白这些 EPIPE 错误的原因;我期待的是 snd_pcm_writei 要么立即返回,要么等待(或多或少)一段持续时间再返回,因为我处于阻塞模式并且我提供样本比回放更快采样率要求。当错误序列结束时,播放正常。此外,如果我为我的线程设置实时优先级 (pthread_setschedparam()),我会得到一个无穷无尽的 OK 2048/ERR -32 列表,而且我只听到噪音。这对我来说真的很奇怪。

我的错误在哪里?

谢谢。

最佳答案

一开始,缓冲区是空的,所以你应该尽快填充它,不要等待。

要减少延迟,请减小缓冲区大小。
要降低欠载运行的风险,请增加缓冲区大小。
你不能同时做这两件事。您必须为您的特定情况选择平衡这两个目标的缓冲区大小。

开始阈值指定设备在缓冲区中有那么多帧时自动开始播放。您应该将其设置为缓冲区大小。

停止阈值指定设备在可用(空闲)帧数达到此值时停止。您应该将其保留为默认值,即缓冲区大小。

avail_min 参数指定在中断导致您的应用程序实际被唤醒之前必须有多少帧可用。

关于linux - ALSA:播放音频的正确方法 - 阻塞模式和线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50103858/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com