Steven
Steven6 perc olvasás

A fülhallgató-bug: amikor a másik fél eltűnt a leiratunkból

A kétcsatornás átírás tökéletesen működött a laptop hangszóróin és a fülre simuló fejhallgatókon. Aztán valaki bedugott egy füles fülhallgatót, és a beszélgetőpartnere egyszerűen eltűnt a leiratból — mert a Chromium némán elnémította a hangunkat abban a pillanatban, amikor a partner megszólalt. Tizenegy javítás megbukott. A tizenkettedik az egész architektúrát megváltoztatta.

Mérnökség
Hang
Átírás
GeekBye kiadások
A fülhallgató-bug: amikor a másik fél eltűnt a leiratunkból

A GeekBye egy beszélgetés két oldalát írja át: a mikrofonodat az egyik csatornán, a másik résztvevő hangját (amit a számítógéped lejátszik) a másikon. Kifogástalanul működött a laptop hangszóróin. Működött a fülre simuló fejhallgatókon. Aztán egy felhasználó bedugott egy füles fülhallgatót, és a beszélgetőpartnere eltűnt a leiratból. Nem torzultan. Nem rosszul hozzárendelve. Eltűnt.

Ez a GeekBye v1.6.12 története, azé a bugé, amely tizenegy sikertelen javítást igényelt, és annak a pillanatnak a története, amikor rájöttünk, hogy a böngésző ellen küzdünk ahelyett, hogy vele dolgoznánk.

A track, amely élt és üres volt

A tünet hátborzongató volt. Elindítottál egy megbeszélést, minden rendben nézett ki, kimondtál egy szót — és attól a pillanattól kezdve a másik ember hangcsatornája tiszta digitális csendbe fordult. Megmértük: a rendszerhang jele normál energiaszinten állt (egy RMS 0.03–0.06 körül), és abban a pillanatban, amikor a mikrofon felvette a hangodat, 0.0000-ra esett, és ott is maradt a munkamenet hátralévő részére.

Itt jön az a rész, ami napokba került. A böngésző minden API-ja ragaszkodott hozzá, hogy a hang-track tökéletesen egészséges. readyState: live. enabled: true. muted: false. A platform által kitett minden státuszjelző szerint a stream rendben volt. A minták voltak halottak — egy élő cső, amely csak nullákat szállított. Sokáig nem hittünk a saját energiamérőnknek, mert a hivatalos verzió azt mondta, hogy a track működik.

A kiváltó ok kifejezetten a füles fülhallgatóra volt jellemző, és az ok fizikai: egy füles fülhallgató egyetlen eszköz, amely egyszerre a mikrofonbemeneted és a hangkimeneted. A laptop hangszórói és a fülre simuló fejhallgatók elválasztják ezeket — a kimenet egy helyre megy, a mikrofon máshol van. De amikor a bemenet és a kimenet ugyanaz az eszköz, akkor definíció szerint van egy visszacsatolási utad. Erős következtetésünk (ez a böngésző belsejében él, így nem tudunk fejezetet és verset idézni) az, hogy a Chromium érzékeli ezt a mikrofon-plusz-hangszóró-egy-eszközön formát, úgy dönt, hogy ez egy sipítani készülő visszacsatolási hurok, és védekezésképpen elnémítja a rögzítést — némán, anélkül, hogy bármelyik olvasható jelzőn keresztül szólna az alkalmazásnak.

Tizenegy javítás, több közülük rosszabb

Először a kézenfekvő módokon támadtuk meg, és minden próbálkozást leírtunk. Kapcsold ki a visszhangszűrést, a zajszűrést és az automatikus erősítést mindkét streamen. Indítsd a két streamet egymás után késleltetéssel, együtt helyett. Adj minden streamnek saját mintavételi frekvenciát. Adj hozzá egy néma gain csomópontot. Vezess mindent egyetlen közös audio contexten keresztül. Válts AudioWorkletre. Menj le egészen a nyers WebCodecs track processzorig.

Tizenegy megközelítés. Nemcsak megbuktak — több rontott is a helyzeten. Az egyik 30 másodperces késést vezetett be. Egy másik miatt a saját mikrofonod leirata a másik ember címkéjével jelent meg. Mélyen elmerültünk a részletekben, minden tünetet kezelve, a bug pedig folyton odébb mozdult.

Az áttörés egy átkeretezés volt: minden addigi javítás két különálló streamet próbált egészségben tartani. De két különálló stream volt pontosan az a dolog, amit a Chromium visszacsatolási heurisztikája látni és némítani tudott. Mi lenne, ha nem lenne mit összehasonlítani?

A javítás: adj a böngészőnek egy streamet, ne kettőt

A v1.6.12 abbahagyta a küzdelmet, és megváltoztatta az architektúrát. Ahelyett, hogy a mikrofont és a rendszerhangot két független streamként küldené, egyetlen mono streambe keveri őket a kliensen, mielőtt bármi elhagyná az alkalmazást. Amikor mindkét forrás egy csővezetéken folyik át, a trackek nem halhatnak meg egymástól függetlenül — többé nincs kéteszközös visszacsatolási forma, amit a böngésző érzékelhetne és némíthatna. A kiváltó feltétel egyszerűen megszűnik létezni.

Volt egy kellemes bónusz is. Két stream két klienstől-backendig WebSocketet és két backendtől-szolgáltatóig kapcsolatot jelentett; egy kevert stream ezt egyre és egyre csökkentette. A fülhallgató-bug javítása mellékhatásként felére csökkentette az átírási költségünket.

De a mono keverésnek van egy nyilvánvaló problémája: ha mindkét embert egy csatornába kevered, honnan tudod még, hogy ki mit mondott? Épp azt az elválasztást dobtad el, ami ezt megmondta.

A „ki beszélt" újraépítése az energiából

A válasz az volt, hogy megmérjük minden forrás hangerejét mielőtt összekevernénk őket, és minden hangdarabhoz csatolunk egy jelzést arról, melyik forrás dominált — mikrofon, rendszer vagy csend. A hangosabb forrás nyer. Elég egyszerű hangszórókon.

A füles fülhallgatóhoz kellett még egy réteg, és itt tér vissza a visszhang a történetbe — az ellenkező irányba fordítva, mint gondolnád. Füles fülhallgatón a másik ember hangja kiszivárog a fülesből és vissza a mikrofonba. Így odafigyelés nélkül az ő visszhangja, a mikrofoncsatornádra érkezve, hozzád kerül hozzárendelve. A javítás egy sor visszhang-tudatos küszöb: amikor a rendszerhang egy kis szint fölött szól, az a léc, amit a mikrofonodnak át kell ugrania ahhoz, hogy „te beszélsz"-nek számítson, magasra ugrik — egy normál 0.015-ről 0.1-re. Más szóval: amíg a másik ember beszél, a mikrofonodnak egyértelműen, félreérthetetlenül hangosabbnak kell lennie a visszhangjánál, mielőtt neked tulajdonítanánk a szavakat. A kétértelmű keretek alapértelmezetten a „rendszerhez" kerülnek, azzal a feltételezéssel, hogy visszhangok. Ez egy szándékos elfogultság, amely pontosan abban a helyzetben találja el jól az attribúciót, amelyben korábban elrontotta.

Az a proof-of-concept — mono keverés plusz energiaalapú, visszhang-tudatos hangfelismerés — a mai GeekBye által futtatott attribúciós rendszer őse. Az állványzatot ugyanabban a kiadásban kitéptük, amint bizonyított, az energiaszámítás pedig később egy rendesen tesztelt modullá keményedett. De a v1.6.12 az, ahol az ötlet megszületett, nyomás alatt, egy füles fülhallgatót viselő felhasználó által.

Három dolog, amit a fülhallgató-bug tanított

  1. Egy egészséges leíró halott adatot is szállíthat. Az egész vizsgálat azon fordult meg, hogy jobban bíztunk az energiamérőnkben, mint a platform státuszjelzőiben — live, enabled, unmuted, mind hazudott, miközben a minták nullák voltak. A hasznos adatot figyeld, ne az API önjelentését. Ha egy stream azt állítja, hogy rendben van, mérd meg, valóban az-e.
  2. Amikor a platform az architektúrád ellen küzd, változtasd meg az architektúrát — ne a platformot. Nem tudtuk érveléssel legyőzni a Chromium visszacsatolás-védelmét, és minden próbálkozás, hogy a széleken kikapcsoljuk, megbukott vagy visszaütött. A megfigyelhető feltétel eltávolítása — két stream eggyé válása — az egész problémát eltüntette. Szinte mindig olcsóbb eltávolítani a kiváltó okot, mint megnyerni egy csatát a böngészővel.
  3. Amikor a robusztusságért csatornákat vonsz össze, újra kell építened, amit tönkretettél. A mono keverés megölte a csatornaelválasztást, amely a „ki beszélt"-et hordozta. Azt az információt a keverés előtti energiából és visszhang-tudatos küszöbökből kellett újra levezetni. A kompenzáló logika nem utólagos gondolat a javításhoz — a javítás fele ő maga.

Ez a megbízhatósági történet negyedik fejezete, amelyből GeekBye v2 lesz. Az előző fejezetért lásd egy megszakadt kapcsolat nem omlaszthatná össze az egész alkalmazásodat (v1.6.8); a pipeline-újraírásért, amelyre ez a hangmunka épült, töröltünk 5000 sornyi hangkódot (v1.6.0); a teljes ívért pedig a szoftver tökéletesre szállításának anatómiája.

Kapcsolódó cikkek

Miért hallja félre az AI-átirat a szakkifejezéseket (és hogyan javítottuk meg)
Steven
Steven6 perc olvasás

Miért hallja félre az AI-átirat a szakkifejezéseket (és hogyan javítottuk meg)

Egy élő munkamenet a "what is the pointer in C++" kérdést úgy hallotta: "what is the point in life". Íme a nyomozás útja attól az átirattól a GeekBye v2.0.11-ig — keyterm biasing, egy kapcsolatbontó időzítési verseny, és a nap, amikor a saját javításunk visszafelé sült el.

Átírás
Megbízhatóság
Mérnökség
Hogyan streamelj élő jelentést villódzás nélkül
Steven
Steven5 perc olvasás

Hogyan streamelj élő jelentést villódzás nélkül

Amikor véget ér a megbeszélésed, a GeekBye összefoglalója mostantól élőben töltődik ki, ahelyett hogy egy töltésjelzőt kellene bámulnod. Ahhoz, hogy a streamelő felület nyugodtnak tűnjön, ne pedig szaggatottnak, kétszer kellett megoldanunk a villódzást — egyszer a strukturált mezőkre, egyszer a markdownra —, és a második javítás egy olyan renderelő volt, amelyik már a miénk volt.

Mérnökség
Frontend
Streamelés
Egy CSS-változó, öt átnézési kör és egy Swift eszközlánc, ami hazudott
Steven
Steven6 perc olvasás

Egy CSS-változó, öt átnézési kör és egy Swift eszközlánc, ami hazudott

A GeekBye v2.0.7 az egész overlay-t állíthatóan áttetszővé tette — ami egysoros CSS-módosításnak hangzik, és egyáltalán nem az volt. Az igazi történet az, amit a kódátnézés elkapott: két felület, amely nem volt hajlandó elhalványulni, egy felvételi sáv, ami rossznak tűnt ugyanazon az áttetszőségen, és egy fordított bináris, ami 672 bájtot ingadozott, mert a saját dokumentációnk a rossz Swift-verziót mondta egy átnézőnek.

Mérnökség
Design
Build