dimhold.by
← Артыкулы

У Linux запісаць дынамікі можна бясплатна, пакуль не кранеш гучнасць

earshot, мой лакальны транскрыбатар, стаў публічным у жніўні. У яго README ёсць табліца пра запіс гуку, яе пісаў я. Мікрафон працуе на ўсіх 3 сістэмах. Пра сістэмны гук, гэта значыць пра тое, што граюць дынамікі, у табліцы напісана “works out of the box” для Linux. Для Windows патрэбны Stereo Mix або VB-CABLE, а для “macOS 12 and later” патрэбны BlackHole. Пад табліцай я напісаў, што macOS увогуле не дае звычайнаму працэсу API для запісу сістэмнага гуку.

Гэты радок я напісаў па памяці. Памяць з тых гадоў, калі ўсе ставілі Soundflower, каб запісаць гук на Маку. Ці праўда гэта дагэтуль, я не правяраў. Радок пра Linux я таксама не ставіў пад сумнеў, бо на маёй машыне ўсё проста працавала. На гэтым тыдні я прайшоўся па абодвух радках.

Што насамрэч даюць аперацыйныя сістэмы

Машыны з Windows або з Макам для гэтага ў мяне няма, таму гэтая частка паводле дакументацыі і зыходнікаў.

У Windows запіс з выхаду ёсць у WASAPI з часоў Vista. Адкрываеш паток запісу на прыладзе прайгравання са сцягам AUDCLNT_STREAMFLAGS_LOOPBACK. Яшчэ ёсць process loopback, ён запісвае гук адной праграмы і яе даччыных працэсаў. Мінімальнай версіяй Microsoft называе Windows 10 зборкі 20348. Ніводзін кліенцкі выпуск Windows 10 да гэтай зборкі не дайшоў, гэта зборка Windows Server 2022, так што на справе гаворка пра Windows 11 або гэты сервер. У macOS гук з’явіўся ў ScreenCaptureKit з macOS 13. З macOS 14.2 у Core Audio ёсць яшчэ AudioHardwareCreateProcessTap, адвод з выхаду аднаго працэсу або ўсіх адразу. Так што мая фраза пра macOS няправільная для ўсіх версій пачынаючы з 13.

earshot усё роўна патрэбна віртуальная прылада з-за ffmpeg. Сам earshot ніякую аўдыяпрыладу не адкрывае, ён запускае ffmpeg, чытае з яго stdout PCM 16 кГц мона і пакідае платформу на ffmpeg. Сёння, 11 кастрычніка, я паглядзеў спіс libavdevice у галіне master у ffmpeg. Для гуку ў Windows там ёсць dshow, а ўваходу WASAPI няма. На macOS ва ўваходзе avfoundation няма кода ScreenCaptureKit, таму з крыніц гуку ён бачыць толькі прылады запісу.

запіс таго, што граюць дынамікі, кастрычнік 2026 што дае АС, з якой версіі што чытае ffmpeg што трэба earshot Linux крыніца monitor PulseAudio, PipeWire -f pulse чытае monitor нічога Windows WASAPI loopback, Vista process loopback, 20348 -f dshow уваходу WASAPI няма Stereo Mix або VB-CABLE macOS ScreenCaptureKit, 13 process tap, 14.2 -f avfoundation толькі прылады запісу BlackHole
Слупкі пра АС паводле дакументацыі Microsoft і Apple, слупок ffmpeg паводле libavdevice у галіне master на 11 кастрычніка 2026. Прагнаны толькі радок Linux.

Linux, з замерам

Радок пра Linux я мог памераць. Нода, на якой я працую, гэта сервер без гукавой карты. Таму я распакаваў PulseAudio 16.1 і PipeWire 1.0.5 з WirePlumber 0.4.17 з пакетаў Ubuntu 24.04 у лакальную папку і стварыў віртуальныя выхады. Абодва серверы я ганяў адными і тымі ж pacat і pactl, так што кліенцкі бок аднолькавы. Тэставы гук гэта 3 секунды шуму з фіксаваным зернем плюс тон 1 кГц, 48 кГц стэрэа. Кожны запіс я выраўноўваю па арыгінале і параўноўваю адлік за адлікам.

Пры гучнасці 100% monitor вяртае гук біт у біт. Гэта 144 000 кадраў са 144 000, на абодвух серверах і ў кожным прагоне канчатковага стэнда.

Потым я пасунуў паўзунок на PulseAudio. На выхадзе з гучнасцю 50% запіс роўны арыгіналу, памножанаму на 0,125, з дакладнасцю да акруглення апошняга біта. Гэта 0,5 у кубе, крывая гучнасці PulseAudio. Выключаны гук на выхадзе дае чыстыя нулі. Гучнасць адной праграмы на 50% падчас прайгравання таксама дае 0,125. Значыць, на PulseAudio monitor чытае гук пасля ўсіх гэтых рэгулятараў.

І сервер гэта запамінае. Пасля таго як я сцішыў адну праграму, яе наступны паток зноў пачаўся з 0,125. Сервер захоўвае гэтую гучнасць на дыску па ролі патоку, а калі ролі няма, то па ідэнтыфікатары або назве праграмы. Для earshot гэта значыць, што старая налада праграмы дзейнічае і на яе наступны званок.

Я ледзь не напісаў, што PipeWire паводзіць сябе гэтак жа. На маіх першых выхадах так і было. Потым праверка па зыходніках паказала прычыну. Гэтыя выхады я ствараў праз слой сумяшчальнасці PipeWire з PulseAudio. Гэты слой уключае ім monitor.channel-volumes. У самога PipeWire па змаўчанні гэтая налада выключаная. WirePlumber 0.4.17 пакідае яе выключанай для сапраўдных гукавых карт. Тады я зрабіў яшчэ адзін выхад наўпрост у PipeWire, з наладай па змаўчанні. На ім выхад на 50% даў запіс біт у біт, выключаны гук таксама. Гучнасць праграмы па-ранейшаму давала 0,125 і па-ранейшаму запаміналася.

адкуль чытае monitor, PulseAudio 16.1 і PipeWire 1.0.5 праграма гучнасць прагр. мікшар гучнасць, mute дынамікі праграма на 50%: ×0,125 на абодвух запамінаецца для новага патоку monitor PipeWire, па зм. выхад і mute: не ўплываюць monitor PulseAudio выхад 50%: ×0,125, mute: нулі
Па 3 прагоны на кожным выхадзе. На 100% любы запіс супадае біт у біт. У выхаду PipeWire налада monitor па змаўчанні, тая, што WirePlumber 0.4.17 пакідае сапраўдным гукавым картам.

Пераключэнне выхаду на абодвух працуе нармальна. Я пачаў запіс з @DEFAULT_MONITOR@, пераключыў выхад па змаўчанні на іншы і граў туды. Абодва серверы перавялі запіс на новы monitor. Запіс зноў супаў біт у біт.

Дзе пачынае балець

earshot адпраўляе ў мадэль не любы гук. Ён рэжа паток на кадры па 20 мс. Кадр лічыцца маўленнем, калі яго RMS не меншы за 600 па шкале 16 біт. Фрагмент застаецца, толькі калі ў ім набралася хаця б 300 мс такіх кадраў. Гэтыя значэнні па змаўчанні выбіраў я сам і ні разу не думаў пра іх разам з паўзунком гучнасці.

Таму я прайграў запіс маўлення на рознай гучнасці. Запісваў ffmpeg 6.1.1 з тымі ж аргументамі, якія earshot збірае на Linux, толькі ў файл, а не ў stdout. Потым аддаў вынік сегментару earshot на каміце 15da817 з наладамі па змаўчанні. Запіс гэта 10 гарвардскіх фраз з Open Speech Repository, для прайгравання я ператварыў яго ў стэрэа. На 100% пік каля -12 dBFS, а ў самага гучнага кадра ў 20 мс RMS ад 3500 да 3650, у залежнасці ад прагону.

колькі фрагментаў earshot нарэзаў з 10 фраз 100% 90% 80% 70% 60% 50% 40% 30% PulseAudio, паўзунок выхаду 10 10 10 8 0 0 0 0 PipeWire, паўзунок выхаду 10 10 10 10 10 10 10 10 PipeWire, паўзунок прагр. 10 10 10 9 0 0 0 0
10 гарвардскіх фраз з Open Speech Repository, запісаных з monitor праз ffmpeg з аргументамі earshot і разрэзаных яго сегментарам з наладамі па змаўчанні: маўленне гэта RMS ад 600, фрагменту трэба 300 мс такога маўлення.

На PulseAudio з паўзунком выхаду earshot нарэзвае з 10 фраз 10 фрагментаў да 80% уключна. На 70% нарэзвае 8. З 60% і ніжэй ніводнага. На 60% самыя гучныя кадры ўсё яшчэ праходзяць парог 600, бо 3650, памножанае на 0,216, гэта каля 790, але такіх кадраў ва ўсім запісе ўсяго 18. Ніводзін фрагмент не набірае з іх 300 мс. На PipeWire паўзунок выхаду нічога не мяняе. earshot нарэзвае ўсе 10 фрагментаў нават на 30%. Паўзунок праграмы вяртае там той жа абрыў: 9 фрагментаў на 70%, ніводнага з 60% і ніжэй. Розніцу 8 супраць 9 на 70% я спісваю на акругленне і межы кадраў і далей не правяраў. Ні ў адным з гэтых прагонаў нічога не падае, ffmpeg і сегментар працуюць далей, а расшыфроўка застаецца пустой.

Мяне нейкі час падманваў і ўласны стэнд. У першых прагонах запіс пачынаўся за 1 секунду да прайгравання і спыняўся праз 1 секунду пасля. Некаторыя запісы гублялі да секунды ў пачатку або кавалак у канцы. З запасам у 3 секунды з кожнага боку гэта больш не паўтаралася. Канцы губляліся таму, што pipewire-pulse аддае запісу даныя буйнымі кавалкамі. Чаму прападаў пачатак, я не ведаю і не капаў.

Што мяняецца для earshot

У README радок пра Linux не павінен казаць толькі “works out of the box”. Працуе, але што менавіта запісваецца, залежыць ад гучнасці. На PulseAudio паўзунок выхаду і выключэнне гуку вырашаюць, ці пачуе earshot маўленне ўвогуле. На PipeWire гэта вырашае толькі гучнасць праграмы. У абодвух выпадках пустая расшыфроўка прыходзіць без аніякай памылкі. Радок пра macOS проста няправільны. Яго трэба прыбраць з README і з docs/audio-capture.md таксама.

Для Windows і macOS сумленнае рашэнне гэта ўласны шлях запісу побач з ffmpeg. Гэта значыць WASAPI loopback з аднаго боку і process tap з другога. Гэта больш кода, чым ёсць у earshot цяпер. Я яго не напісаў.

Што я не правяраў

Нічога з гэтага не запускалася ні на Windows, ні на macOS. Я не ведаю, ці бачыць WASAPI loopback або process tap гук да сістэмнай гучнасці ці пасля.

Усе выхады былі віртуальнымі. PulseAudio можа прымяняць частку гучнасці ў жалезе гукавой карты. Паводле зыходнікаў гэтая частка ідзе пасля monitor, а выключэнне гуку заўсёды робіцца праграмна. Значыць, на ноўтбуку з PulseAudio абрыў можа апынуцца ніжэй па паўзунку, а выключаны гук усё роўна павінен даваць цішыню. Гэта я прачытаў у кодзе, запусціць не мог. Мой выхад у PipeWire толькі паўтарае наладу па змаўчанні для сапраўднай карты. Сапраўднай картай ён ад гэтага не становіцца.

Сам абрыў адносіцца толькі да гэтага запісу. Цішэйшы званок зрушвае яго ўверх па паўзунку, гучнейшы ўніз. Парог 600 да таго ж мяняецца сцягам --threshold.