3 puan yazan GN⁺ 2023-08-21 | 1 yorum | WhatsApp'ta paylaş
  • Görüntülü toplantılarda reMarkable 2 eskizlerini paylaşmak için kullanılan araç, dizüstünde yerel bir servis olmadan açılacak şekilde değişti; böylece sunum yapan kişi yalnızca tarayıcıyla anında streaming başlatabiliyor
  • Yeni yapı, reMarkable içindeki HTTP sunucusu ve ham görüntüyü alıp canvas üzerine çizen tarayıcı JavaScript istemcisiyle basitleştirildi
  • WebSocket alternatifi çalışsa da iOS sorunları ve sunucu ek yükü devam etti; bu yüzden sabit çözünürlüklü görüntüleri http.ResponseWriter ile sürekli yazıp fetch stream’iyle okuyan ham stream yaklaşımında karar kılındı
  • 1872x1404 ham kare yaklaşık 2,5 MB olduğundan, firmware 3.3 sonrası 16 renk değeri uint4 olarak paketlenerek %50 azaltıldı ve RLE ile ortalama yaklaşık 200 KB aktarım seviyesine indirildi
  • /dev/input/event* izlenerek giriş yokken yeni kare gönderimi durduruluyor; bağlı istemci olsa bile CPU kullanımı 0’a düşüyor, yazı yazarken ise yaklaşık %10 CPU ile çalışıyor

Eski aracın neden zahmetli olduğu

  • 2021’de yapılan reMarkable streaming aracı, görüntülü toplantılar sırasında eskiz paylaşmak için kullanılıyordu; yalnızca tarayıcı sekmesini paylaşmak yeterli olduğundan sunum içeriğine odaklanmak kolaydı
  • Eski uygulama üç bileşene ayrılıyordu
    • Sunucu: reMarkable cihazında çalışır ve mevcut ekranın ham görüntüsünü dışa açar
    • İstemci: Dizüstünde sunucunun ham görüntüsünü alır ve tarayıcının görebileceği bir biçime işler
    • Renderer: Tarayıcı veya VLC gibi bir HTTP MJPEG stream’ini okuyup ekranda gösterir
  • Cihaz CPU kullanımını azaltmak için sunucu yalnızca istemci bağlandığında görüntü çıkarıyordu ve iletişimde gRPC kullanılıyordu
  • Dizüstü istemcisi görüntüyü tekrar tekrar alıyor, JPEG olarak encode ediyor ve MJPEG stream’ini HTTP servisi olarak sunuyordu
  • Sunum ortamlarında reMarkable adresi, istemci çalıştırma yetkisi ve renderer’ın bilmesi gereken istemci IP’si gibi ağ yapılandırmaları yük oluyordu

Yalnızca tarayıcıyla açılan yeni yapı

  • Yeni hedef, herhangi bir tarayıcıda yalnızca reMarkable adresi girildiğinde stream’e erişilebilmesini sağlamaktı
  • Ayrı dizüstü istemcisi kaldırıldı ve reMarkable’ın sunucu bileşeninin içine HTTP sunucusu koyan bir yapıya geçildi
  • Tarayıcıda çalışacak istemci için JavaScript veya WASM biçimi gerekiyordu
    • Başta Go deneyiminden yararlanmak için WASM’e derleme değerlendirildi, ancak önemli değişiklikler gerektiren kısıtlar nedeniyle vazgeçildi
    • İstemcinin ikinci sürümü sonunda JavaScript ile yazıldı
  • JavaScript kod parçaları ve açıklamalar elde etme sürecinde ChatGPT kullanıldı, ancak istenen çözümün yönü doğrudan belirlendi

canvas render etme yöntemi

  • MJPEG stream’inden uzaklaşmak için tarayıcının temel görüntü işleme öğesi olan canvas kullanıldı
  • reMarkable’dan alınan ham görüntü Uint8Array olarak okunuyor; ImageData içindeki RGBA piksel verisinde aynı değer R/G/B’ye konuyor ve alfa değeri 255 yapılarak gösteriliyor
  • Duyarlı gösterim, döndürme ve renklendirme olasılığı için sabit boyutlu fixedCanvas gizli durumda tutuluyor
  • Gösterim amaçlı canvas’a, gizli canvas içeriği drawImage ile kopyalanıyor
  • Tarayıcı penceresi boyutu değiştiğinde, kapsayıcı boyutu ve 1872/1404 oranı temel alınarak gösterim canvas’ının genişliği ve yüksekliği ayarlanıyor

WebSocket’i bırakıp ham stream’e geçiş

  • gRPC web geliştirmede yaygın bir tercih olmadığından, ilk alternatif uygulama iletişim ve kapsülleme aracı olarak WebSocket kullandı
  • WebSocket mesajları ham görüntüyü içeriyor, tarayıcı istemcisi her mesaj aldığında canvas’ı güncelleyerek streaming etkisi veriyordu
  • Bu yöntem, sunucu tarafındaki mesaj gönderim sıklığını ayarlayarak reMarkable’ın bellek ve CPU yükünü yönetebiliyordu
  • Ancak iOS’ta sorunlar vardı ve sunucu tarafı WebSocket uygulamasının ek yükünü kontrol etmek de zordu
  • Nihai yapı kapsüllemeyi kaldırdı ve sabit görüntü boyutundan yararlanarak ham görüntüyü doğrudan ağ üzerinden gönderdi
    • Go sunucusu görüntüyü tekrar tekrar http.ResponseWriter içine Write eder
    • Tarayıcı istemcisi fetch('/stream') içindeki ReadableStream’i okur ve gelen chunk’ları canvas verisine yansıtır

Aktarım miktarı optimizasyonu

  • reMarkable 2’nin ham görüntüsü 1872x1404 çözünürlükte yaklaşık 2,5 MB’tır ve bu verinin her karede aktarılması gerekir
  • Firmware 3.3 sonrası reMarkable’ın 16 renk değeri uint8 yerine uint4 dizisi olarak ifade edilebilir
    • Go ve JavaScript’te yerel uint4 tipi yoktur
    • İki piksel değerini tek bir uint8 byte içinde saklama yöntemiyle bunun etrafından dolaşılır
    • Go’da iki uint4 değeri üst 4 bit ve alt 4 bit olarak paketlenir, JavaScript’te ise tekrar açılır
    • Bu gösterim veri miktarını %50 azaltabilir
  • Ek sıkıştırma için Run Length Encoding (RLE) kullanılır
    • RLE, aynı piksel değerinin art arda kaç kez geldiğini ve değeri birlikte gönderen basit bir algoritmadır
    • 0 0 0 0 0 0 1 1 1 0 0 0 0 örneği 6 0 3 1 4 0 olarak ifade edilir
  • Sayaç değeri en fazla 1872*1404’e kadar büyüyebileceğinden uint64 gibi bir tip gerekebilir ve bazı durumlarda sıkıştırılmış sonuç orijinalden daha büyük olma riski taşır
  • Bunu önlemek için sayaç uzunluğu 15 ile sınırlandı ve sayaç ile piksel değerini tek byte’a sığdıran denge noktası seçildi
  • RLE uygulaması Go’nun io.Writer’ı gibi çalışır ve yeniden kullanılabilir; gerekirse RLE iki kez uygulanabilir, ancak şu anda buna ihtiyaç duyulmadı
  • Paketleme ve RLE sonrası ortalama aktarım miktarı yaklaşık 200 KB düzeyindedir

Yalnızca değişiklik olduğunda kare gönderimi

  • Son optimizasyon, yalnızca ekran değiştiğinde yeni kare gönderme yöntemidir
  • Değişiklik olup olmadığını checksum ile hesaplamak CPU yükünü artırabilir
  • reMarkable Linux tabanlı olduğundan kalem veya dokunma girdisi /dev/input/event* üzerinden iletilir
  • Bir goroutine bu giriş olaylarını izler ve yalnızca gerektiğinde görüntü gönderir
  • Olay yoksa, istemci bağlı olsa bile CPU kullanımı 0’a düşer
  • Yazı yazarken CPU kullanımı yaklaşık %10 düzeyindedir

Firmware değişiklikleri ve bakım yükü

  • Bu uygulama hacklemeye dayanır; temel zorluk, görüntüyü alma arayüzünü istemci/renderer’dan etkili biçimde ayırmaktır
  • Önceki uygulamada istemci ve sunucu protobuf tanımlarıyla tamamen ayrılmıştı
  • reMarkable 3.3 firmware’i aracı bozdu ve ilgili içerik GitHub’daki issue 36 içinde yer alıyor
    • O zamanki düzeltme yalnızca istemci bileşenini etkiledi
  • Firmware 3.6 da GitHub’daki issue 58 uyarınca bozucu değişiklikler getirebilir
    • Bu durumda daha kapsamlı düzeltmeler gerekebilir
    • Ancak istemci sunucuya entegre edilmiş kendi kendine yeterli bir yapıda olduğu için cihaz güncellemesi daha basit hale gelebilir
  • Uygulama ve kaynak kod github.com/owulveryck/goMarkableStream adresinde sunuluyor

1 yorum

 
GN⁺ 2023-08-21
Hacker News görüşleri
  • reMarkable tablet ekranını dizüstü bilgisayara stream eden 2021 tarihli aracı yeniden elden geçirip yayımlamış; yeni yazıda mimariyi, bileşenleri ve kullanıcı deneyimini iyileştirme sürecini derinlemesine ele alıyor
    Ürün yöneticisi bakış açısıyla kullanıcıların nasıl hissettiğine bakarak etkinleştirme sürecini sadeleştirmiş, yerel servis olmadan çalışır hale getirmiş ve ağ kullanımını da optimize etmiş

    • Harika bir proje gibi görünüyor. Ctrl-C sonrası ./goMarkableStream ile yeniden başlatınca bir ölçüde çalıştı ama hâlâ sık sık waiting for reMarkable screen çıkıyor ve servis kararsız
      reMarkable2’yi 3.5.2.1807’ye yükselttikten sonra kurdum; dizüstü, sayfa ve kitap üzerine çizsem de tepki vermedi, ara sıra read /dev/input/event2: file already closed, read /dev/input/event1: file already closed gibi loglar görünüyor
      https://192.168.8.143:2001/ ve https://10.11.99.1:2001/ ikisi de HTML ve canvas sunuyor; Chrome, Firefox ve Brave’de de denedim
      Stream başına bir tarayıcı, bir IP sınırı var gibi görünüyor ama hangi adresi ve tarayıcıyı kullanırsam kullanayım bazen waiting for reMarkable screen çıkıyor. nohup ./goMarkableStream & sonrası PuTTY’yi kapatıp istemciyi yeniden başlatınca tüm tarayıcılar aynı duruma geldi; https://10.11.99.1:2001/stream adresine bakınca too many requests dönüyor. Stream’i nasıl yeniden başlatmam gerektiğini merak ediyorum
    • USB bağlantısıyla da uygulanıp uygulanamayacağını merak ediyorum
  • Alternatif olarak SuperNote’u büyük memnuniyetle kullanıyorum. Ekran yansıtma mümkün olduğu için toplantı sırasında hızlıca diyagram çizmek için çok iyi
    Dezavantajı, SuperNote’un küçük bir web sunucusu çalıştırıp Firefox ile bağlanma yöntemi kullanması; yani dizüstü bilgisayar ile SuperNote’un aynı ağda olması gerekiyor. Ev ofiste sorun değil ama şirket politikaları nedeniyle engellenebilir
    İster RM2 ister SuperNote olsun, fikirlerini kalem ve kâğıtla yazmayı sevenler için harika araçlar; uygulamalardan veya metin belgelerinden epey farklı hissettiriyorlar ve notların üzerine karalama da yapılabiliyor
    [0]: https://supernote.com/

    • Onyx Boox Note da iyi çalışıyor ve 5 yıldan fazla zaman geçmesine rağmen güncelleme yayımlamaya devam ediyor
      Ancak satın alırken GPL ihlalini göze almak gerekiyor. Tamamen Android tabanlı olmasına rağmen işletim sistemi kaynak kodunu yayımlamıyor
    • E-kitap okuyucu ve not alma amaçlı bir e-ink tablet arıyordum; öneri faydalı oldu. Remarkable 2 ile Boox arasında kararsızdım ve SuperNote’un yazılım güncelleme deneyiminin nasıl olduğunu merak ediyorum
      Önümüzdeki 3-5 yıl boyunca özellik güncellemeleri ya da en azından güvenlik güncellemeleri alamayacak bir cihaz satın almaktan endişeliyim
    • Hatırladığım kadarıyla SuperNote, birlikte dağıttığı yazılımın GPL koşullarına uymuyordu; tutumlarının değişip değişmediğini merak ediyorum
    • Henüz “aynı ağda olma” sorununu yaşamadım ama yerleşik Ngrok özelliği eklemek birkaç dakikalık basit bir iş gibi görünüyor. Böylece internet üzerinden streaming yapılabilir
    • SuperNote’un yazma hissinin RM2 ile karşılaştırıldığında nasıl olduğunu merak ediyorum
  • HTML canvas render işlemi, burada açıklandığı gibi typed array kullanılırsa daha hızlı olabilir: https://hacks.mozilla.org/2011/12/faster-canvas-pixel-manipu...

    • Teşekkürler, bir göz atacağım
  • Burada görmek istediğim içerik tam da böyle yazılar. ChatGPT’nin pek bilmediği bir alandaki sorunu öğrenip çözmeye nasıl yardımcı olduğunu görmek hoşuma gitti; “geliştirici bendim ve ChatGPT kodlayandı” ifadesiyle de özdeşleştim
    Basitliğin aslında karmaşık olduğu sözü de doğru

  • JPEG’i seçmelerinin nedeni muhtemelen MJPEG’e çevirmesinin kolay olması ve destekleyen tarafa bırakınca decoding işinin neredeyse bedavaya gelmesiydi. Ancak bu, reMarkable CPU’suna ciddi yük bindiren etken olabilir
    JPEG fotoğraflar için daha uygun ama reMarkable ekranı daha çok illüstrasyona benziyor; üstelik siyah-beyaz tonlarında. PNG gibi başka genel görüntü formatları ya da basit RLE sıkıştırma bile CPU yükünü daha düşük tutabilir

    • Kesin konuşmak gerekirse reMarkable tek renkli değil, gri tonlamalı; hatırladığım kadarıyla 16 gri seviyesini destekliyor. Eşlik eden uygulamada kalem için mavi-kırmızı, fosforlu kalem için sarı-yeşil gibi görünen renkli mürekkepler de var
      Ayrıca kendi dosya biçimi bitmap değil, kalem girdisi tabanlı
    • Başta JPEG’i seçme nedeni doğru. Ancak bu yüzden istemci/sunucu yapısını tercih ettim; encoding tablet üzerinde değil, istemci olan dizüstü bilgisayarda yapıldı
      Profil çıkarınca CPU’nun büyük kısmının kablo üzerinden veri aktarımına gittiğini gördüm, bu yüzden sıkıştırma ekledim. Şu anda CPU kullanımı düşük
  • Framebuffer’ın değişen bölgelerini בלבד göndermeyi değerlendirdiniz mi merak ediyorum. Bu, veri aktarım hızını ciddi ölçüde azaltabilir: https://github.com/pl-semiotics/mxc_epdc_fb_damage
    rM VNC projesi de bunu yapıyor ama istemci tarafında yazılım gerektirmeyen bu uygulamanın kullanıcı deneyimini daha çok beğeniyorum

    • Bu yöntemin sorunu, cihaz üzerinde bir miktar analiz gerektirmesi; kodu mümkün olduğunca az müdahaleci tutmak istiyorum. Ucuz yoldan yapmanın bir yolu var mı bakacağım
  • Gerçekten harika ve ReMarkable 2’yi sevmek istiyorum ama güvenli olmayan bir cihaz olduğu yönündeki duruş nedeniyle bu kolay değil: https://support.remarkable.com/s/article/Does-reMarkable-off...

    • Bağlantıdaki içerik, bu cihazın yerine geçmeyi amaçladığı kâğıtla aynı seviyede fiziksel güvenliğe sahip olduğu anlamına geliyor. Yani biri cihaza erişirse okuyabilir.
      Ağa bağlı güvensiz bir cihaz dendiğinde genellikle akla gelen, bilinen yazılım açıklarından bahsetmiyor.
    • Gayriresmî olarak gocryptfs tabanlı home dizini şifrelemesi mümkün: https://github.com/RedTeamPentesting/remarkable-encryption
    • Yazılım da şu an için çok sınırlı. Resmî olarak cihazda bir marketplace ya da eklentilerin kullanılmasına izin vermemesi üzücü.
    • Tam disk şifrelemesi sunan bir e-kitap okuyucu var mı?
  • “Başta istemciyi WASM’e derlemeye çalıştım. Go geliştirme deneyiminden yararlanabildiğim için umut verici görünüyordu, ancak ciddi değişiklikler gerektiren çeşitli sınırlamalarla karşılaştım” kısmı hakkında daha fazla okumak isterim.

    • Temel sorun gRPC kütüphanesiydi ve mevcut destek çok sınırlıydı. Ayrıca Go’da JPEG sıkıştırma yavaş ve CPU’yu yoğun kullanıyor.
      MJPEG stream’i oluştursanız bile bunun nasıl gösterileceği de bir sorundu. Canvas yöntemini düşündüm, ancak WASM ile JS arasında büyük kopyalamalar yapmadan canvas backend’ine erişmek zordu; ayrıca boyutu da 2,5 MB idi.
      Sonuçta WASM’e bel bağlamak, görüntü döndürme gibi JS’te varsayılan olarak erişilebilen birçok temel görüntü işlemini doğrudan kendim uygulamam gerekecekmiş gibi görünüyordu.
  • Bu aracın yerleşik streaming’den, yani ekran paylaşımı özelliğinden nasıl farklı olduğunu merak ediyorum.

    • Yerleşik özelliği kullanmak için masaüstü uygulamasını kurmak gerekiyor ve bildiğim kadarıyla Linux sürümü yok.
      https://support.remarkable.com/s/article/Screen-Share
      Yazıdaki çözüm, yeterli özelliklere sahip bir tarayıcı olduğu sürece Linux’ta da çalışıyor gibi görünüyor.
    • En büyük fark, artık istemci kurulumu gerekmemesi. Tarayıcıya reMarkable adresini yazmanız yeterli, içeriği görebiliyorsunuz.
    • Bu özelliğin zaten olduğunu sanıyordum. Ekran paylaşımı gayet iyi ve canlı yayın için de kullanıyorum.
  • reMarkable’ı seviyorum ama bundan sonra da para ödemeyi düşünmediğim abonelik yerine böyle streaming özelliklerine odaklanmalarını isterim.