1ed57291f9
An Omarchy shell plugin: a Python/asyncio daemon that discovers network displays and serves an encoded screen capture for them to pull, plus a Quickshell bar widget and panel to drive it. The screen comes from the xdg-desktop-portal ScreenCast interface (asked for every time, never remembered), goes through GStreamer, and is served from a local HTTP port. Desktop audio is mixed in from the default output's monitor. The container follows the receiver: WebM/VP8 for Cast, MPEG-TS/H.264 for DLNA, HLS for AirPlay video. The stream port has to be reachable from the LAN, and none of these protocols can carry a credential, so the capability is the URL: a fresh random path per session, refused to anything off the LAN, capped at four concurrent readers.
42 lines
1.3 KiB
Python
42 lines
1.3 KiB
Python
"""What every receiver protocol has to provide."""
|
|
from __future__ import annotations
|
|
|
|
from ..devices import Device
|
|
|
|
|
|
class BackendError(Exception):
|
|
pass
|
|
|
|
|
|
class Backend:
|
|
kind = ""
|
|
#: Containers this protocol can be handed, best first.
|
|
containers: tuple[str, ...] = ("webm",)
|
|
#: Does it pull a plain HTTP stream (True) or an HLS playlist (False)?
|
|
progressive = True
|
|
|
|
def __init__(self, daemon) -> None:
|
|
self.daemon = daemon
|
|
|
|
async def play(self, device: Device, url: str, *, container: str, title: str) -> None:
|
|
raise NotImplementedError
|
|
|
|
async def stop(self, device: Device) -> None:
|
|
raise NotImplementedError
|
|
|
|
async def set_volume(self, device: Device, volume: float) -> None:
|
|
raise BackendError("this receiver has no volume control")
|
|
|
|
async def set_muted(self, device: Device, muted: bool) -> None:
|
|
raise BackendError("this receiver has no mute control")
|
|
|
|
async def transport(self, device: Device, action: str) -> None:
|
|
raise BackendError("this receiver has no transport control")
|
|
|
|
async def poll(self, device: Device) -> dict:
|
|
"""Live status of the session: {state, app, volume, muted, error}."""
|
|
return {}
|
|
|
|
async def close(self) -> None:
|
|
return None
|