Playback Sinkron di Banyak Layar, Presisi Sampai Frame

Playback Sinkron di Banyak Layar, Presisi Sampai Frame
Video wall itu sembilan layar yang pura-pura jadi satu. Signage mirror itu konten yang sama di dua puluh layar sepanjang koridor. Tuntutan keduanya sama: semua perangkat harus sepakat sekarang jam berapa, dan frame mana yang harus tampil pada detik itu.
Meleset sedikit saja, pelanggan yang lewat melihat iklan yang sama jalan tidak barengan — seperti band yang tidak bisa jaga tempo. Di platform signage yang saya bangun, sinkronisasi diperlakukan sebagai protokol sesi, bukan sekadar urusan menyetel jam.
NTP itu perlu, tapi tidak cukup
Jawaban refleksnya biasanya "pakai NTP saja." Betul, pakai — tapi pahami dulu apa yang NTP berikan. Di LAN yang sehat, NTP menyamakan jam sistem sampai selisihnya tinggal puluhan milidetik.
Masalahnya, playback tidak mulai saat jam bilang mulai. Playback mulai saat decoder siap, buffer terisi, dan pipeline display selesai flush. Dua perangkat yang jamnya sudah sepakat sempurna tetap bisa menampilkan frame pertama terpaut 300 ms di layar. Sinkronisasi jam menjawab sekarang jam berapa — bukan kapan frame ini muncul. Dua-duanya harus dijawab.
Sync session: master clock dan ready barrier
Struktur yang terbukti bekerja: sync session — sesi terkoordinasi yang dikawal server, atau satu perangkat master yang dipilih di LAN. Dua komponennya: master clock, jam acuan tunggal yang diikuti semua layar, dan ready barrier — titik tunggu bersama, semua layar menunggu aba-aba yang sama sebelum mulai.
Tiap perangkat mengukur offset jamnya terhadap master clock, lalu lapor ready. Dan ready harus punya arti yang ketat: media terunduh penuh, frame pertama sudah di-decode, pipeline pause di posisi nol. Begitu semua peserta ready, server menyiarkan timestamp mulai yang masih cukup jauh di depan. Perangkat membalas ack, lalu masing-masing mengonversi waktu master ke waktu lokalnya pakai offset tadi. Semua mulai barengan.
Ada satu detail yang tidak keren tapi menanggung beban besar: beri setiap sesi nomor generasi, di-seed supaya tidak pernah berulang walau server restart. Klien basi yang masih pegang nomor lama jadi tidak bisa ikut ack ke sesi baru dan merusak start-nya. Dengan sesi yang bernomor, pesan telat tinggal diabaikan.
Koreksi drift lewat rate, bukan lewat seeking
Mulai barengan baru setengah cerita — decoder kelas konsumen pasti drift. Karena itu tiap perangkat melaporkan posisi playback-nya sebagai telemetri, dan koordinator membandingkannya dengan timeline master.
Respons yang salah untuk error 40 ms: seeking. Lompatannya kelihatan, ada frame yang jatuh, audio meletup — di layar yang sedang ditonton pelanggan. Respons yang benar: rate adjustment. Putar di kecepatan 100,5% atau 99,5% sampai selisihnya habis, lalu balik normal. Setengah persen tidak akan terasa; koreksinya larut pelan-pelan, bukan muncul mendadak.
Resync keras disimpan untuk dua kasus saja: error posisi yang melewati ambang besar, dan index drift — perangkat memutar item yang salah sama sekali. Untuk yang terakhir, restart terjadwal yang bersih lebih ampuh daripada rate nudge sebanyak apa pun.
Preloading dan disiplin buffer
Streaming sambil berharap lancar tidak punya tempat di sini. Konten harus sudah terunduh ke disk sebelum boleh ikut diputar — ready barrier tadi yang menegakkan aturannya. Pemanasan decoder juga membantu: decode frame pertama, tahan di posisi pause. Bagian startup yang paling susah ditebak durasinya jadi pindah ke sebelum sinyal mulai — di sana, lambat sedikit pun tidak ada yang lihat.
Soal buffer, ukuran yang seragam dan diketahui di semua perangkat lebih penting daripada ukuran yang besar. Perangkat identik dengan setelan identik akan drift bareng-bareng, jadi loop koreksi yang di-tune sekali berlaku di semua unit. Hardware campur-campur dalam satu wall bikin setiap toleransi melebar berlipat.
Rejoin setelah reboot
Layar pasti pernah reboot: listrik padam, update OTA, watchdog menjalankan tugasnya. Aturan rejoin-nya satu: wall tidak pernah menunggu.
Perangkat yang baru hidup lagi menanyakan state sesi ke server — nomor generasi, item yang sedang jalan, posisi timeline master. Item itu di-preload, playback masuk di posisi hasil hitungan, dan sisa selisihnya dikoreksi lewat rate dalam beberapa detik berikutnya. Layar tetangganya tidak pause, tidak restart, tidak terganggu sama sekali. Desain sync yang harus menghentikan sesi demi menerima anggota baru akan gugur di kedipan listrik pertama.
Kapan "cukup dekat" memang cukup
Toleransi itu anggaran, dan besarnya ditentukan tata letak layar. Layar mirror di dinding yang berjauhan? Selisih puluhan milidetik tidak akan ketahuan, karena tidak ada orang yang memandang dua layar itu sekaligus. Begitu ada audio, anggarannya menyempit: telinga menangkap gema lebih dulu daripada mata menangkap selisih gambar.
Video wall yang rapat bezel-ke-bezel adalah kasus paling ketat. Selisih satu frame — 16 ms pada 60 fps — sudah tampak seperti sobekan melintang di sambungan layar. Di sini hardware identik, setelan decoder identik, dan ambang koreksi yang rapat hukumnya wajib. Sebaliknya, merekayasa kasus ketat untuk koridor layar mirror cuma buang-buang anggaran. Kenali dulu wall macam apa yang sedang Anda bangun.
Intinya
Playback sinkron itu berlapis: NTP untuk jam, ready barrier untuk start, rate adjustment untuk drift, preloading untuk prediktabilitas, dan jalur rejoin yang tidak pernah menghentikan pertunjukan.
Konteks pengelolaan perangkatnya saya bahas di mengelola banyak Android TV box untuk signage. Untuk transport yang membawa pesan sync-nya, pilihannya klasik — pertimbangannya ada di MQTT vs WebSocket untuk IoT real-time.
Artikel Terkait
Mau bangun hal serupa?
Jasa Pengembangan Backend IoT & Integrasi Multi-Protokol
Backend yang menyerap telemetri perangkat lintas MQTT, WebSocket, Modbus, dan BLE, lalu menyatukannya jadi dashboard real-time yang andal.
Lihat cara saya bisa bantu