Я не могу найти правильный способ написания своего цикла для воспроизведения звука и / или я неправильно понимаю значение параметров start_threshold, stop_threshold и util_min для Alsa. Я хотел бы достичь минимальной задержки и знать правильные параметры, которые нужно изменить, чтобы моя цепочка захвата-воспроизведения-воспроизведения была устойчивой к изменениям времени обработки звука. В этом примере я читаю сэмплы из файла, чтобы сосредоточиться на части воспроизведения.
Это моя конфигурация устройства вывода, открытая в режиме блокировки (Ubuntu 16.04, PulseAudio присутствует, default
устройство):
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 и слышу только шум. Это действительно странно для меня.
Где моя ошибка?
Спасибо.