Screencast: cast the desktop to Cast, DLNA and AirPlay receivers
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.
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
"""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
|
||||
Reference in New Issue
Block a user