LINUX.ORG.RU

Принцип работы звука в linux

 , ,


0

1

Добрый день! До определенного момента считал, что звук в linux воспроизводится благодаря xserver...но после трассировки mplayer немного потерялся. Буду благодарен за пояснение данного процесса (в какой сокет/файл записывается аудиопоток?).

Вот, что нашел:

Вырезки из «strace mplayer»:

pipe2([5, 6], O_CLOEXEC) 

и в цикле записывает (4 - это аудиофайл)

read(4, "~\2760\v\305'\251\357\377\376\273\377\277\351#~\0\0\0\20\6g?\367\342\327U\303ej\351J"..., 4096) = 4096
write(6, "W", 1)                        = 1

Кроме того перед этим открывает

socket(AF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC, 0) = 9
connect(9, {sa_family=AF_LOCAL, sun_path="/run/user/1000/pulse/native"}, 110) = 0
но ничего не пишет в него

А также нашел открытие сокета X11, но он закрывается еще до начала воспроизведения:

connect(8, {sa_family=AF_LOCAL, sun_path=@"/tmp/.X11-unix/X1"}, 20) = 0
getpeername(8, {sa_family=AF_LOCAL, sun_path=@"/tmp/.X11-unix/X1"}, [20]) = 0
getsockname(8, {sa_family=AF_LOCAL, NULL}, [2]) = 0
fcntl(8, F_GETFL)                       = 0x2 (flags O_RDWR)
fcntl(8, F_SETFL, O_RDWR|O_NONBLOCK)    = 0
fcntl(8, F_SETFD, FD_CLOEXEC)           = 0
writev(8, [{"l\0\v\0\0\0\22\0\20\0\0\0", 12}, {"", 0}, {"MIT-MAGIC-COOKIE-1", 18}, {"\0\0", 2}, {"q\234\r\32d\203m\347\32;\221\3265\26k<", 16}, {"", 0}], 6) = 48
recvfrom(8, "\1\0\v\0\0\0\213\5", 8, 0, NULL, NULL) = 8
recvfrom(8, "\30\240\265\0\0\0\200\3\377\377\37\0\0\1\0\0\24\0\377\377\1\7\0\0  \10\377\0\0\0\0"..., 5676, 0, NULL, NULL) = 5676
writev(8, [{"\20\0\5\0\f\0\0\0PULSE_SERVER", 20}], 1) = 20
recvmsg(8, {msg_name(0)=NULL, msg_iov(1)=[{"\1\0\1\0\0\0\0\0\220\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 4096}], msg_controllen=0, msg_flags=0}, 0) = 32
writev(8, [{"\24\0\6\0\234\2\0\0\220\1\0\0\37\0\0\0\0\0\0\0\377\3\0\0", 24}], 1) = 24
recvmsg(8, {msg_name(0)=NULL, msg_iov(1)=[{"\1\10\2\0\21\0\0\0\37\0\0\0\0\0\0\0B\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096}], msg_controllen=0, msg_flags=0}, 0) = 100
writev(8, [{"\20\0\6\0\20\0\0\0PULSE_SESSION_ID", 24}], 1) = 24
recvmsg(8, {msg_name(0)=NULL, msg_iov(1)=[{"\1\0\3\0\0\0\0\0\355\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 4096}], msg_controllen=0, msg_flags=0}, 0) = 32
writev(8, [{"\24\0\6\0\234\2\0\0\355\1\0\0\37\0\0\0\0\0\0\0\377\3\0\0", 24}], 1) = 24
recvmsg(8, {msg_name(0)=NULL, msg_iov(1)=[{"\1\10\4\0\1\0\0\0\37\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096}], msg_controllen=0, msg_flags=0}, 0) = 36
writev(8, [{"\20\0\5\0\n\0\0\0PULSE_SINK\0\0", 20}], 1) = 20
recvmsg(8, {msg_name(0)=NULL, msg_iov(1)=[{"\1\0\5\0\0\0\0\0\221\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 4096}], msg_controllen=0, msg_flags=0}, 0) = 32
writev(8, [{"\24\0\6\0\234\2\0\0\221\1\0\0\37\0\0\0\0\0\0\0\377\3\0\0", 24}], 1) = 24
recvmsg(8, {msg_name(0)=NULL, msg_iov(1)=[{"\1\0\6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 4096}], msg_controllen=0, msg_flags=0}, 0) = 32
writev(8, [{"\20\0\5\0\f\0\0\0PULSE_SOURCE", 20}], 1) = 20
recvmsg(8, {msg_name(0)=NULL, msg_iov(1)=[{"\1\0\7\0\0\0\0\0\222\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 4096}], msg_controllen=0, msg_flags=0}, 0) = 32
writev(8, [{"\24\0\6\0\234\2\0\0\222\1\0\0\37\0\0\0\0\0\0\0\377\3\0\0", 24}], 1) = 24
recvmsg(8, {msg_name(0)=NULL, msg_iov(1)=[{"\1\0\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 4096}], msg_controllen=0, msg_flags=0}, 0) = 32
writev(8, [{"\20\0\5\0\f\0\0\0PULSE_COOKIE", 20}], 1) = 20
recvmsg(8, {msg_name(0)=NULL, msg_iov(1)=[{"\1\0\t\0\0\0\0\0\223\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 4096}], msg_controllen=0, msg_flags=0}, 0) = 32
writev(8, [{"\24\0\6\0\234\2\0\0\223\1\0\0\37\0\0\0\0\0\0\0\377\3\0\0", 24}], 1) = 24
recvmsg(8, {msg_name(0)=NULL, msg_iov(1)=[{"\1\10\n\0\200\0\0\0\37\0\0\0\0\0\0\0\0\2\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096}], msg_controllen=0, msg_flags=0}, 0) = 544
shutdown(8, SHUT_RDWR)                  = 0
close(8)                                = 0

PS: лез в исходники mplayer, но там уперся в библиотечные функции pulseaudio, которые в свою очередь пестрят изобильным интерфейсом и многочисленными ответвлениями, так что копать дальше ради того, чтобы узнать как оно работает не стал. (мне, для личного FAQ, достаточно внешний интерфейс, и алгоритм его взаимодействия с ядром на пальцах)

Исключительно через alsa. Pulseaudio тоже работает через alsa. Сама alsa из юзерспейса представляет собой ioctl() завёрнутые в библиотеки, просто-так «куда-то писать» нельзя.

anonymous ()

Звук выводится ALSA. Для микширования от разных программ используется PulseAudio, и оно тоже работает поверх ALSA. Причем PulseAudio можно как и вовсе не использовать, так и заменить другой прослойкой. А X11 в выводе звука вообще не участвует, музыку можно и без него слушать.

Vsevolod-linuxoid ★★★★★ ()
Ответ на: комментарий от DELIRIUM

Хм, ну в чем преимущество чистой альсы перед пульсой я знаю, звук не шипит и не заикается. Но зачем применять устаревший OSS? Или ты про то, что Ъ на BSD?

Vsevolod-linuxoid ★★★★★ ()
Последнее исправление: Vsevolod-linuxoid (всего исправлений: 1)
Ответ на: комментарий от cyber_eagle

Всем спасибо!

Вот вызов snd_pcm_open() для hw:0

open("/dev/snd/controlC0", O_RDONLY|O_CLOEXEC) = 3
fcntl(3, F_SETFD, FD_CLOEXEC)           = 0
ioctl(3, SNDRV_CTL_IOCTL_CARD_INFO, 0x7ffd5fe7afe0) = 0
close(3)                                = 0
open("/dev/snd/controlC0", O_RDWR|O_CLOEXEC) = 3
fcntl(3, F_SETFD, FD_CLOEXEC)           = 0
ioctl(3, SNDRV_CTL_IOCTL_PVERSION, 0x7ffd5fe7b164) = 0
ioctl(3, SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE, 0x7ffd5fe7b1cc) = 0
open("/dev/snd/pcmC0D0c", O_RDWR|O_NONBLOCK|O_CLOEXEC) = 4
fcntl(4, F_SETFD, FD_CLOEXEC)           = 0
close(3)                                = 0
ioctl(4, SNDRV_PCM_IOCTL_INFO, 0x7ffd5fe7b070) = 0
fcntl(4, F_GETFL)                       = 0x8802 (flags O_RDWR|O_NONBLOCK|O_LARGEFILE)
ioctl(4, SNDRV_PCM_IOCTL_PVERSION, 0x7ffd5fe7afc0) = 0
ioctl(4, SNDRV_PCM_IOCTL_TTSTAMP, 0x7ffd5fe7afc4) = 0
mmap(NULL, 4096, PROT_READ, MAP_SHARED, 4, 0x80000000) = 0x7f43fbc7d000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, 4, 0x81000000) = 0x7f43fbc7c000
fcntl(4, F_GETFL)                       = 0x8802 (flags O_RDWR|O_NONBLOCK|O_LARGEFILE)
fcntl(4, F_SETFL, O_RDWR|O_LARGEFILE)   = 0
cyber_eagle ()

Должно с самого начала - заинтересовать DIY bit-perfect звуко-воспроизведение на данной электронике ЭВМ/лаптопа.

Для проверки ALSA тракта, выполняется:

lor@lor ~ % cat /proc/asound/card*/pcm*p/sub*/hw_params
access: MMAP_INTERLEAVED
format: S16_LE
subformat: STD
channels: 2
rate: 48000 (48000/1)
period_size: 44100
buffer_size: 88200
closed
closed

И для проверки bit-perfect с mpd:

Dec 23 21:25 : decoder_thread: probing plugin flac
Dec 23 21:25 : decoder: audio_format=96000:24:2, seekable=true
Dec 23 21:25 : alsa_output: opened default type=IOPLUG
Dec 23 21:25 : alsa_output: format=S24_LE (Signed 24 bit Little Endian)
Dec 23 21:25 : alsa_output: buffer: size=48..524288 time=500..5461334
Dec 23 21:25 : alsa_output: period: size=16..174763 time=166..1820448
Dec 23 21:25 : alsa_output: default period_time = buffer_time/4 = 500000/4 = 125000
Dec 23 21:25 : alsa_output: buffer_size=48000 period_size=12000
Dec 23 21:25 : output: opened plugin=alsa name="USB-Audio - USB Advanced Audio Device" audio_format=96000:24:2
Dec 23 21:25 : output: Failed to open mixer for 'USB-Audio - USB Advanced Audio Device'

Наглядно видны ошибки?
Внешний USB DAC 96Khz не играет flac 96Khz.
Прийдётся выяснять снова, почему забыл в kernel init указать нужные hw параметры саунд кард.

К тому, что ТС цепляется к файлам, не подозревая, что звуковоспроизведение не настроено изначально верно.

blitz ()

но ничего не пишет в него

libpulse.so запускает ещё как минимум одну нить, в которой крутится её основной цикл. Запускай strace с параметром -f, чтобы отслеживать вызовы во всех нитях.

i-rinat ★★★★★ ()

Привет. В 2002 году было выпущено ядро Linux 2.6. Одним из новшеств была звуковая система ALSA. Мы ей пользуемся до сих пор.

В ALSA также была была эмуляция OSS - предыдущей звуковой системы. Потому что было много программ, выпущенных до 2002 года, и с ними нужно было сохранять совместимость! В 2012 году, в юбилей ALSA, в новых установках Linux стали отключать эмуляцию OSS. Включить её можно, вручную загрузив драйверы (модули) ядра snd-pcm-oss, snd-mixer-oss и snd-seq-oss. Также, вместо этого можно запускать старую программу при помощи aoss или padsp.

В 2008 году было выпущено говно под названием PulseAudio. Оно ровным счётом ничего не давало, а также не решало никаких проблем. Но его сделали, и, не спросив пользователя, включили по умолчанию. Сделав не очевидным способ выключить. Многие, конечно, возмутились, и отключили PulseAudio хотя бы из-за такой наглости! Но году в 2010-2011 протестная активность стала утихать. Стало много новоприбывших, которые не застали линукс без пульсы. У которых работает синдром утёнка: что первое увидел, то и идеал. И пользователи, отключающие пульсу, стали в меньшинстве.

А ещё есть звуковой сервер JACK. Он очень крутой. И очень рекомендуется тем, кто профессионально работает со звуком. JACK работает поверх ALSA: ALSA это звуковая система, а JACK это звуковой сервер. PulseAudio, кстати, тоже работает поверх ALSA. Но, как я уже говорил, ничего не даёт. Лишняя сущность. Как отключать, я написал здесь. Это может понадобиться в случае проблем со звуком.

Если тебе интересен JACK, посмотри также на ядро Linux с патчами -rt. Это low-latency ядро Linux, с которым задержка звука становится очень маленькой. Это ничего не даёт при прослушивании музыки, но при записи очень критично, позволяет избавиться от эффекта «белого шума». Впрочем, кому я это рассказываю - ты и так всё знаешь!

Программы выводят звук, связываясь с системной библиотекой libasound2. Если хотят выводить через PulseAudio, то с помощью libpulse, а если через JACK, то с помощью libjack. А старая звуковая система OSS создавала файл-устройство /dev/dsp, в который программы просто копировали PCM-поток! Это было весело. Например, если скопировать туда /boot/vmlinuz, получится как будто волны прибоя. В 00-е было здорово экспериментировать с разным файлами, а также с /dev/random. Сейчас тоже можно это делать, если загрузить те модули ядра.

А ещё есть SDL и OpenAL. Первое это библиотека, значительно упрощающая написание игр. Она охватывает вывод графики на монитор, работу со звуком и устройствами ввода: мышь, клавиатура, геймпад. Эдакий DirectX в мире Linux! А ещё есть OpenAL. Его можно использовать в своей игреx, и на звук будет накладываться эффект Допплера, в зависимости от местоположения игрока в пространстве. Но игроделы в основном не используют OpenAL так глубоко, они его используют чтобы не заморачиваться с ALSA/PulseAudio, а на винде эта библиотека стала очень популярна в 2006 году, когда Microsoft «убила» DirectSound.

ZenitharChampion ★★★★★ ()
Последнее исправление: ZenitharChampion (всего исправлений: 9)
Ответ на: комментарий от cyber_eagle

Исходный файл - flac 96Khz 24bit.

Dec 23 21:25 : decoder_thread: probing plugin flac
Dec 23 21:25 : decoder: audio_format=96000:24:2, seekable=true
Играется с mpd через внешний USB DAC, который поддерживает 96Khz 24bit.

При этом, ALSA driver показывает в диагностике (самое важное):

Dec 23 21:25 : alsa_output: buffer_size=48000 period_size=12000

В переводе - «USB DAC не смог договориться с ALSA на идеальное звуковоспроизведение - 96000 96Khz и поэтому сделал down-sampling с 96Khz на 48000 48Khz»

<i>в таких случаях кадр режется/заполняется нулями?</i>
Down-sampling 96Khz->48Khz - пропуск/вырез - с интерполяцией - половины кадров в звуко-дорожке.
На слух, и с мониторами Technics Japan - качество самой звуко-дорожки решает.

Тем не менее, USB DAC работает некорректно. Нужно опять вспоминать, данные hw и прописывать вручную в строке kernel и конфигурации mpd.

blitz ()