- Alat untuk membagikan sketsa reMarkable 2 saat konferensi video diubah agar bisa dibuka tanpa layanan lokal di laptop, sehingga presenter dapat memulai streaming seketika hanya dengan browser
- Arsitektur baru disederhanakan menjadi server HTTP di dalam reMarkable dan klien JavaScript di browser yang menerima gambar mentah lalu menggambarnya ke
canvas - Alternatif WebSocket sempat berfungsi, tetapi masalah di iOS dan overhead server masih tersisa, sehingga akhirnya dirapikan menjadi pendekatan stream mentah: terus menulis gambar beresolusi tetap ke
http.ResponseWriterdan membacanya lewat streamfetch - Frame mentah 1872x1404 berukuran sekitar 2.5MB, jadi setelah firmware 3.3 nilai 16 warna dipaketkan sebagai uint4 untuk mengurangi 50%, lalu dengan RLE rata-rata turun hingga sekitar 200KB per transfer
- Dengan memantau
/dev/input/event*, pengiriman frame baru dihentikan saat tidak ada input; bahkan jika klien tetap terhubung penggunaan CPU turun ke 0, dan saat menulis berjalan di sekitar 10% CPU
Mengapa alat lama terasa merepotkan
- Alat streaming reMarkable yang dibuat pada 2021 digunakan untuk membagikan sketsa saat konferensi video, dan karena cukup membagikan tab browser, presenter jadi lebih mudah fokus pada materi presentasi
- Implementasi lama dibagi menjadi tiga komponen
- Server: berjalan di perangkat reMarkable dan mengekspos gambar mentah dari layar saat ini
- Klien: mengambil gambar mentah dari server di laptop dan memprosesnya menjadi format yang bisa dilihat browser
- Renderer: menampilkan layar dengan membaca stream HTTP MJPEG, misalnya di browser atau VLC
- Untuk mengurangi penggunaan CPU perangkat, server hanya mengekstrak gambar saat klien terhubung, dan komunikasi menggunakan gRPC
- Klien di laptop berulang kali mengambil gambar, mengenkodenya menjadi JPEG, lalu menyediakan stream MJPEG sebagai layanan HTTP
- Dalam lingkungan presentasi, konfigurasi jaringan seperti alamat reMarkable, izin menjalankan klien, dan IP klien yang harus diketahui renderer menjadi beban tersendiri
Arsitektur baru yang bisa dibuka hanya dengan browser
- Tujuan baru adalah membuat stream dapat diakses dari browser mana pun hanya dengan memasukkan alamat reMarkable
- Klien laptop terpisah dihilangkan, dan strukturnya diubah dengan menanamkan server HTTP ke dalam komponen server di reMarkable
- Klien yang berjalan di browser perlu berbentuk JavaScript atau WASM
- Awalnya kompilasi ke WASM dipertimbangkan agar bisa memanfaatkan pengalaman dengan Go, tetapi dibatalkan karena keterbatasan yang membutuhkan cukup banyak perubahan
- Klien versi kedua akhirnya ditulis dalam JavaScript
- ChatGPT digunakan dalam proses mendapatkan potongan kode JavaScript dan penjelasannya, tetapi arah solusi yang diinginkan ditentukan sendiri
Metode rendering canvas
- Untuk keluar dari stream MJPEG, digunakan
canvas, elemen dasar manipulasi gambar di browser - Gambar mentah dari reMarkable dibaca sebagai
Uint8Array, lalu nilai yang sama dimasukkan ke data piksel RGBA milikImageDatapada R/G/B dan nilai alfa diset ke 255 untuk ditampilkan - Untuk kemungkinan tampilan responsif, rotasi, dan pewarnaan,
fixedCanvasberukuran tetap dipertahankan dalam keadaan tersembunyi - Isi kanvas tersembunyi kemudian disalin ke kanvas tampilan dengan
drawImage - Saat ukuran jendela browser berubah, lebar dan tinggi kanvas tampilan disesuaikan berdasarkan ukuran container dan rasio 1872/1404
Meninggalkan WebSocket dan beralih ke stream mentah
- Karena gRPC bukan pilihan yang umum dalam pengembangan web, implementasi pengganti pertama memakai WebSocket sebagai sarana komunikasi dan enkapsulasi
- Pesan WebSocket memuat gambar mentah, dan klien browser memperbarui kanvas setiap kali pesan diterima agar terlihat seperti streaming
- Pendekatan ini memungkinkan frekuensi pengiriman pesan di sisi server diatur untuk mengelola beban memori dan CPU pada reMarkable
- Namun, ada masalah di iOS dan overhead implementasi WebSocket di sisi server juga sulit dikendalikan
- Arsitektur akhirnya menghapus enkapsulasi dan memanfaatkan ukuran gambar yang tetap untuk langsung mengirim gambar mentah melalui jaringan
- Server Go berulang kali
Writegambar kehttp.ResponseWriter - Klien browser membaca
ReadableStreamdarifetch('/stream')dan menerapkan chunk yang masuk ke data kanvas
- Server Go berulang kali
Optimasi ukuran transfer
- Gambar mentah reMarkable 2 berukuran sekitar 2.5MB pada resolusi 1872x1404, dan data ini harus ditransfer di setiap frame
- Sejak firmware 3.3, 16 nilai warna pada reMarkable bisa direpresentasikan sebagai array uint4 alih-alih uint8
- Go dan JavaScript tidak memiliki tipe uint4 bawaan
- Ini diakali dengan menyimpan dua nilai piksel dalam satu byte uint8
- Di Go, dua nilai uint4 dipaketkan ke 4 bit atas dan 4 bit bawah, lalu di JavaScript dibuka kembali
- Representasi ini dapat mengurangi ukuran data sebesar 50%
- Untuk kompresi tambahan digunakan Run Length Encoding (RLE)
- RLE adalah algoritme sederhana yang mengirim jumlah kemunculan berurutan dari nilai piksel yang sama beserta nilainya
- Contoh
0 0 0 0 0 0 1 1 1 0 0 0 0direpresentasikan sebagai6 0 3 1 4 0
- Nilai hitung bisa membesar hingga 1872*1404 sehingga mungkin membutuhkan tipe seperti uint64, dan dalam beberapa kasus hasil kompresi berisiko lebih besar daripada data asli
- Untuk menghindarinya, panjang hitungan dibatasi hingga 15, dan dipilih titik keseimbangan dengan menaruh nilai hitung dan nilai piksel dalam satu byte
- Implementasi RLE bekerja seperti
io.Writerdi Go sehingga bisa digunakan kembali, dan jika perlu RLE bahkan bisa diterapkan dua kali, meski saat ini tidak diperlukan - Setelah packing dan RLE, rata-rata ukuran transfer berada di sekitar 200KB
Mengirim frame hanya saat ada perubahan
- Optimasi terakhir adalah mengirim frame baru hanya saat layar berubah
- Menghitung checksum untuk memeriksa perubahan bisa menambah beban CPU
- reMarkable berbasis Linux, jadi input pena atau sentuhan dikirim melalui
/dev/input/event* - Sebuah goroutine memantau event input ini dan hanya mengirim gambar saat diperlukan
- Jika tidak ada event, penggunaan CPU turun ke 0 bahkan ketika klien masih terhubung
- Saat menulis, penggunaan CPU berada di kisaran 10%
Perubahan firmware dan beban pemeliharaan
- Aplikasi ini berbasis hacking, dan tantangan intinya adalah memisahkan antarmuka pengambilan gambar dari klien/renderer secara efektif
- Implementasi sebelumnya memisahkan klien dan server sepenuhnya melalui definisi protobuf
- Firmware reMarkable 3.3 merusak alat ini, dan rinciannya ada di GitHub issue 36
- Saat itu perbaikannya hanya memengaruhi komponen klien
- Firmware 3.6 juga, menurut GitHub issue 58, dapat membawa perubahan yang merusak
- Dalam kasus ini, perbaikan yang lebih luas mungkin diperlukan
- Namun, karena klien kini terintegrasi ke server dalam struktur yang mandiri, pembaruan perangkat bisa menjadi lebih sederhana
- Aplikasi dan kode sumber tersedia di github.com/owulveryck/goMarkableStream
1 komentar
Opini Hacker News
Alat tahun 2021 untuk melakukan streaming layar tablet reMarkable ke laptop telah dipoles ulang dan dirilis, dan tulisan baru ini membahas secara mendalam proses peningkatan arsitektur, komponen, dan pengalaman pengguna
Dari sudut pandang manajer produk, proses aktivasi disederhanakan dengan melihat bagaimana pengguna merasakannya, dibuat agar berjalan tanpa layanan lokal, dan penggunaan jaringan juga dioptimalkan
Ctrl-Clalu memulai ulang dengan./goMarkableStream, ini berjalan sampai batas tertentu, tetapiwaiting for reMarkable screenmasih sering muncul dan layanannya tidak stabilSaya memasangnya setelah memperbarui reMarkable2 ke 3.5.2.1807, tetapi tidak ada respons saat menggambar di laptop, lembar kerja, maupun buku, dan log seperti
read /dev/input/event2: file already closed,read /dev/input/event1: file already closedkadang terlihatBaik https://192.168.8.143:2001/ maupun https://10.11.99.1:2001/ menyajikan HTML dan kanvas, dan saya juga mencobanya di Chrome, Firefox, dan Brave
Tampaknya ada batasan satu browser dan satu IP per stream, tetapi dengan alamat dan browser apa pun, kadang
waiting for reMarkable screentetap muncul. Setelahnohup ./goMarkableStream &, lalu menutup PuTTY dan memulai ulang klien, semua browser menjadi berada dalam keadaan yang sama, dan saat membuka https://10.11.99.1:2001/stream hasilnya mengembalikantoo many requests. Saya penasaran bagaimana cara memulai ulang streamSebagai alternatif, saya sangat puas memakai SuperNote. Karena bisa melakukan screen mirroring, alat ini sangat bagus untuk menggambar diagram dengan cepat saat rapat
Kekurangannya adalah SuperNote menjalankan web server kecil lalu diakses lewat Firefox, sehingga laptop dan SuperNote harus berada di jaringan yang sama. Di home office ini bukan masalah, tetapi bisa saja diblokir oleh kebijakan perusahaan
Baik RM2 maupun SuperNote adalah alat yang hebat bagi orang yang suka menuangkan ide dengan pena dan kertas, rasanya cukup berbeda dari aplikasi atau dokumen teks, dan Anda juga bisa mencoret-coret catatan
[0]: https://supernote.com/
Namun saat membelinya, Anda harus siap menerima pelanggaran GPL. Meski sepenuhnya berbasis Android, mereka tidak merilis source code sistem operasinya
Saya khawatir akan membeli perangkat yang dalam 3–5 tahun ke depan tidak mendapat dukungan pembaruan fitur, atau setidaknya pembaruan keamanan
Rendering kanvas HTML bisa dibuat lebih cepat dengan memakai typed array seperti yang dijelaskan di sini: https://hacks.mozilla.org/2011/12/faster-canvas-pixel-manipu...
Tulisan seperti inilah konten yang ingin saya lihat di sini. Saya suka bagaimana ChatGPT membantu mempelajari dan memecahkan masalah di area yang tidak terlalu dikuasainya, dan saya setuju dengan ungkapan “saya adalah developer dan ChatGPT adalah coder”
Pernyataan bahwa kesederhanaan pada kenyataannya kompleks juga benar
Saya rasa JPEG dipilih karena mudah diubah menjadi MJPEG, dan jika diserahkan ke pihak yang mendukungnya, decoding bisa ditangani nyaris gratis. Namun itu bisa menjadi faktor yang memberi beban besar pada CPU reMarkable
JPEG lebih cocok untuk foto, sementara layar reMarkable lebih mirip ilustrasi, dan terlebih lagi bernuansa hitam-putih. Memakai format gambar umum lain seperti PNG atau sekadar kompresi RLE sederhana pun sepertinya akan memberi beban CPU yang lebih rendah
Selain itu, format file proprietarinya berbasis input tulisan tangan, bukan bitmap
Setelah melakukan profiling, sebagian besar CPU dipakai untuk transfer data melalui kabel, jadi saya menambahkan kompresi. Sekarang penggunaan CPU rendah
Penasaran apakah Anda sudah mempertimbangkan cara hanya mengirim area framebuffer yang berubah. Itu bisa sangat mengurangi laju transfer data: https://github.com/pl-semiotics/mxc_epdc_fb_damage
Proyek rM VNC juga melakukan itu, tetapi saya lebih suka pengalaman pengguna aplikasi ini yang tidak memerlukan perangkat lunak di sisi klien
Benar-benar keren dan saya ingin menyukai ReMarkable 2, tetapi sulit karena posisinya sebagai perangkat yang tidak aman: https://support.remarkable.com/s/article/Does-reMarkable-off...
Ini bukan soal kerentanan software yang diketahui, seperti yang biasanya terbayang saat menyebut perangkat tidak aman yang terhubung ke jaringan
Ingin membaca lebih lanjut bagian “Awalnya saya mencoba mengompilasi klien ke WASM. Itu terlihat menjanjikan karena bisa memanfaatkan pengalaman pengembangan Go, tetapi saya menemui beberapa keterbatasan yang membutuhkan banyak modifikasi”
Bahkan jika berhasil membuat stream MJPEG, cara menampilkannya juga menjadi masalah. Saya sempat mempertimbangkan pendekatan canvas, tetapi sulit mengakses backend canvas tanpa penyalinan besar antara WASM dan JS, dan ukurannya juga 2,5MB
Pada akhirnya, jika bergantung pada WASM, sepertinya banyak operasi dasar gambar yang secara bawaan bisa diakses di JS, seperti rotasi gambar, harus diimplementasikan sendiri
Penasaran bagaimana tool ini berbeda dari streaming bawaan, yaitu fitur berbagi layar
https://support.remarkable.com/s/article/Screen-Share
Solusi dalam tulisan ini tampaknya berjalan di Linux selama ada browser dengan fitur yang memadai
Saya suka reMarkable, tetapi ke depannya berharap mereka lebih fokus pada fitur streaming seperti ini daripada langganan yang tidak akan pernah saya bayar