#!/usr/bin/env python3 """ambicatcher — processo di cattura separato: scrive frame RGB grezzi su stdout. Vive in un processo a sé per due motivi: 1) isolare GStreamer/PipeWire e dbus-python dal demone (che resta Python puro: Gio per il D-Bus, numpy, pyserial); 2) la sessione ScreenCast appartiene a QUESTO processo: quando termina, il portal la chiude e l'indicatore "Trasmissione dello schermo" sparisce dal vassoio. Uso: ambicatcher.py --leds 47 --rows 72 --sub 4 --fps 60 Stampa una riga JSON di intestazione ({"node":..,"w":..,"h":..} oppure {"error":..}) poi frame da (leds*sub) x rows pixel RGB, senza separatori. """ import argparse import json import os import signal import sys def main(): ap = argparse.ArgumentParser() ap.add_argument("--leds", type=int, default=47) ap.add_argument("--sub", type=int, default=4) ap.add_argument("--rows", type=int, default=72) ap.add_argument("--fps", type=int, default=60) ap.add_argument("--drain", action="store_true", help="termina quando stdin si chiude (usato dal demone)") a = ap.parse_args() gw, gh = a.leds * a.sub, a.rows def bye(*_): raise SystemExit(0) signal.signal(signal.SIGTERM, bye) signal.signal(signal.SIGINT, bye) out = sys.stdout.buffer try: from ambicapture import Capture, close_stream, screencast_stream node, w, h = screencast_stream() out.write((json.dumps({"node": node, "w": w, "h": h}) + "\n").encode()) out.flush() cap = Capture(node, a.leds, sub=a.sub, rows=a.rows, fps=a.fps) cap.start() except Exception as e: out.write((json.dumps({"error": f"{type(e).__name__}: {e}"}) + "\n").encode()) out.flush() return 1 if a.drain: import select import threading def watchdog(): # stdin chiuso dal padre = termina (e con noi la sessione portal) try: while True: if not sys.stdin.buffer.read(1): break except Exception: pass os.kill(os.getpid(), signal.SIGTERM) threading.Thread(target=watchdog, daemon=True).start() try: while True: frame = cap.frame(200) if frame is None: continue out.write(frame.tobytes()) out.flush() except (BrokenPipeError, KeyboardInterrupt): pass finally: try: cap.stop() except Exception: pass close_stream() return 0 if __name__ == "__main__": sys.exit(main())