Steven
Steven6 menit baca

Bug earbud: ketika lawan bicara menghilang dari transkrip kami

Transkripsi dua kanal bekerja sempurna di speaker laptop dan headphone over-ear. Lalu seseorang mencolokkan earbud, dan lawan bicara mereka begitu saja menghilang dari transkrip — karena Chromium diam-diam membisukan audio kami pada saat mereka berbicara. Sebelas perbaikan gagal. Yang kedua belas mengubah seluruh arsitektur.

Rekayasa
Audio
Transkripsi
Rilis GeekBye
Bug earbud: ketika lawan bicara menghilang dari transkrip kami

GeekBye mentranskripsikan dua sisi percakapan: mikrofon Anda di satu kanal, audio lawan bicara (apa yang diputar komputer Anda) di kanal lain. Ini bekerja tanpa cela di speaker laptop. Ini bekerja di headphone over-ear. Lalu seorang pengguna mencolokkan earbud, dan orang yang mereka ajak bicara lenyap dari transkrip. Tidak kacau. Tidak salah atribusi. Hilang.

Ini adalah kisah GeekBye v1.6.12, bug yang butuh sebelas perbaikan gagal, dan momen kami menyadari bahwa kami sedang melawan browser alih-alih bekerja sama dengannya.

Track yang hidup dan kosong

Gejalanya menyeramkan. Anda memulai rapat, semuanya terlihat baik, Anda mengucapkan satu kata — dan sejak saat itu, kanal audio lawan bicara masuk ke keheningan digital murni. Kami mengukurnya: sinyal audio sistem berada pada tingkat energi normal (RMS sekitar 0.03–0.06), dan pada saat mikrofon menangkap suara Anda, ia turun ke 0.0000 dan tetap di sana selama sisa sesi.

Inilah bagian yang memakan waktu kami berhari-hari. Setiap API browser bersikeras bahwa track audio itu sepenuhnya sehat. readyState: live. enabled: true. muted: false. Menurut setiap flag status yang diekspos platform, aliran itu baik-baik saja. Yang mati adalah sampel-nya — pipa hidup yang tidak membawa apa pun selain nol. Kami menghabiskan waktu lama tidak memercayai pengukur energi kami sendiri, karena cerita resminya bilang track itu berfungsi.

Pemicunya spesifik pada earbud, dan alasannya bersifat fisik: sebuah earbud adalah satu perangkat yang sekaligus merupakan input mikrofon dan output audio Anda. Speaker laptop dan headphone over-ear memisahkan keduanya — output ke satu tempat, mikrofon di tempat lain. Tetapi ketika input dan output adalah perangkat yang sama, Anda memiliki, menurut definisi, sebuah jalur umpan balik. Kesimpulan kuat kami (ini hidup di dalam perut browser, jadi kami tidak bisa mengutip bab dan ayatnya) adalah bahwa Chromium mendeteksi bentuk mikrofon-plus-speaker-pada-satu-perangkat itu, memutuskan itu adalah loop umpan balik yang akan melengking, dan secara protektif membisukan penangkapan — diam-diam, tanpa memberi tahu aplikasi melalui satu pun flag yang bisa dibaca aplikasi.

Sebelas perbaikan, beberapa malah lebih buruk

Kami menyerangnya dulu dengan cara-cara yang jelas, dan mencatat setiap percobaan. Menonaktifkan penghapusan gema, penekanan derau, dan auto gain di kedua aliran. Memulai kedua aliran secara berurutan dengan jeda alih-alih bersamaan. Memberi setiap aliran sample rate-nya sendiri. Menambahkan node gain senyap. Mengarahkan semuanya melalui satu konteks audio bersama. Beralih ke AudioWorklet. Turun sampai ke prosesor track WebCodecs mentah.

Sebelas pendekatan. Bukan hanya gagal — beberapa malah memperburuknya. Satu memperkenalkan jeda 30 detik. Yang lain menyebabkan transkrip mikrofon Anda muncul dengan label lawan bicara. Kami tenggelam jauh di dalam belukar, mengobati setiap gejala, dan bug itu terus berpindah.

Terobosannya adalah pembingkaian ulang: setiap perbaikan sejauh itu mencoba menjaga dua aliran terpisah tetap sehat. Tetapi dua aliran terpisah adalah persis hal yang bisa dilihat dan dibisukan oleh heuristik umpan balik Chromium. Bagaimana jika tidak ada yang bisa dibandingkan?

Perbaikannya: beri browser satu aliran, bukan dua

v1.6.12 berhenti melawan dan mengubah arsitektur. Alih-alih mengirim mikrofon dan audio sistem sebagai dua aliran independen, ia mencampurnya menjadi satu aliran mono di klien sebelum apa pun meninggalkan aplikasi. Ketika kedua sumber mengalir melalui satu pipeline, track tidak bisa mati secara independen — tidak ada lagi bentuk umpan balik dua-perangkat untuk dideteksi dan dibisukan browser. Kondisi pemicunya sekadar berhenti ada.

Ada bonus yang menyenangkan. Dua aliran berarti dua WebSocket klien-ke-backend dan dua koneksi backend-ke-penyedia; satu aliran campuran meruntuhkannya menjadi satu dan satu. Memperbaiki bug earbud memangkas separuh biaya transkripsi kami sebagai efek samping.

Tetapi mixing mono punya masalah yang jelas: jika Anda memadukan kedua orang menjadi satu kanal, bagaimana Anda masih tahu siapa mengatakan apa? Anda telah membuang justru pemisahan yang memberi tahu Anda hal itu.

Membangun ulang "siapa yang bicara" dari energi

Jawabannya adalah mengukur kenyaringan setiap sumber sebelum mencampurnya, dan menempelkan petunjuk pada setiap potongan audio yang menyebutkan sumber mana yang dominan — mikrofon, sistem, atau senyap. Sumber yang lebih keras menang. Cukup sederhana di speaker.

Earbud butuh satu lapisan lagi, dan di sinilah gema kembali ke dalam cerita — mengarah ke arah yang berlawanan dari yang mungkin Anda kira. Di earbud, suara lawan bicara bocor keluar dari earbud dan kembali masuk ke mikrofon. Jadi tanpa kehati-hatian, gema mereka, yang tiba di kanal mikrofon Anda, disalahatribusikan ke Anda. Perbaikannya adalah seperangkat ambang sadar-gema: ketika audio sistem berbunyi di atas ambang kecil, batas yang harus dilampaui mikrofon Anda untuk dihitung sebagai "Anda berbicara" melonjak jauh — dari 0.015 normal ke 0.1. Dengan kata lain: selagi lawan bicara berbicara, mikrofon Anda harus jelas, tanpa ambiguitas lebih keras daripada gema mereka sebelum kami mengkreditkan kata-kata itu kepada Anda. Frame yang ambigu secara default ke "sistem", dengan asumsi itu gema. Ini adalah bias sengaja yang membuat atribusi benar justru dalam situasi yang dulu selalu salah.

Proof-of-concept itu — mixing mono ditambah deteksi suara berbasis energi dan sadar-gema — adalah leluhur sistem atribusi yang dijalankan GeekBye saat ini. Perancahnya dicabut dalam rilis yang sama begitu terbukti, dan matematika energinya kemudian mengeras menjadi modul yang teruji dengan benar. Tetapi v1.6.12 adalah tempat ide itu lahir, di bawah tekanan, oleh seorang pengguna dengan sepasang earbud.

Tiga hal yang diajarkan bug earbud

  1. Sebuah handle yang sehat bisa membawa data yang mati. Seluruh investigasi berputar pada memercayai pengukur energi kami di atas flag status platform — live, enabled, unmuted, semuanya berbohong sementara sampelnya nol. Pantau muatannya, bukan laporan-diri API. Jika sebuah aliran mengklaim baik-baik saja, ukur apakah ia benar-benar begitu.
  2. Ketika platform melawan arsitektur Anda, ubah arsitekturnya — bukan platformnya. Kami tidak bisa mengalahkan argumen perlindungan umpan balik Chromium, dan setiap upaya menonaktifkannya dari pinggiran gagal atau berbalik merugikan. Menghapus kondisi yang dapat diamati — dua aliran menjadi satu — membuat seluruh masalah lenyap. Hampir selalu lebih murah menghapus pemicu daripada memenangkan perkelahian dengan browser.
  3. Ketika Anda meruntuhkan kanal demi ketahanan, Anda harus membangun ulang apa yang Anda hancurkan. Mencampur ke mono membunuh pemisahan kanal yang membawa "siapa yang bicara". Informasi itu harus diturunkan ulang dari energi pra-campur dan ambang sadar-gema. Logika kompensasi itu bukan renungan belakangan atas perbaikan — ia adalah separuh dari perbaikan.

Ini adalah bab keempat dari kisah keandalan yang menjadi GeekBye v2. Untuk bab sebelumnya, lihat koneksi yang putus seharusnya tidak membuat seluruh aplikasi Anda crash (v1.6.8); untuk penulisan ulang pipeline yang menjadi dasar pekerjaan audio ini, kami menghapus 5.000 baris kode audio (v1.6.0); dan untuk keseluruhan alurnya, anatomi merilis perangkat lunak hingga kesempurnaan.

Artikel Terkait

Anatomi Merilis Perangkat Lunak hingga Sempurna: Bagaimana Code Review Menangkap yang Tak Terjangkau Tes
Steven
Steven6 menit baca

Anatomi Merilis Perangkat Lunak hingga Sempurna: Bagaimana Code Review Menangkap yang Tak Terjangkau Tes

Sepanjang seri GeekBye v2, hal yang sama terus terjadi: sebuah perbaikan lolos setiap tes di mesin developer, lalu code review membuktikan bahwa perbaikan itu akan gagal untuk hampir semua orang. Inilah alur kerja di balik sembilan rilis — gerbang review, penangkapan yang mengutamakan perbaikan, dan disiplin menguji-sebelum-rilis yang mengubah "berhasil di mesin saya" menjadi "berhasil".

Rekayasa
Proses
Code Review
Satu Variabel CSS, Lima Putaran Review, dan Toolchain Swift yang Berbohong
Steven
Steven6 menit baca

Satu Variabel CSS, Lima Putaran Review, dan Toolchain Swift yang Berbohong

GeekBye v2.0.7 membuat seluruh overlay bisa diatur transparansinya — yang kedengarannya seperti perubahan CSS satu baris dan sama sekali bukan. Cerita sebenarnya ada pada apa yang ditangkap code review: dua permukaan yang menolak memudar, sebuah bar rekaman yang terlihat salah pada opacity yang sama, dan sebuah binary terkompilasi yang bolak-balik 672 byte karena dokumentasi kami sendiri memberi tahu reviewer versi Swift yang keliru.

Rekayasa
Desain
Build
Kami Menghapus 5.000 Baris Kode Audio — dan Transkrip Mulai Muncul Dua Kali
Steven
Steven6 menit baca

Kami Menghapus 5.000 Baris Kode Audio — dan Transkrip Mulai Muncul Dua Kali

GeekBye v1.6 mencabut dua transkriber Swift di perangkat dan menggantinya dengan satu pipeline terpadu — penghapusan bersih lebih dari 5.000 baris, dilakukan saat orang sedang di tengah rapat di aplikasi. Lalu transkrip mulai muncul dua kali, karena bug itu berpindah ke satu lapisan yang masih mengira ada dua mesin.

Rekayasa
Transkripsi
Arsitektur