Selkies
Developer Referencewebrtc_mode

WebRTCService

The WebRTC streaming service run under the centralized stream server.

Owns the whole WebRTC data path for a session: signaling, peer management, one media pipeline per display, input handling, monitoring, and the congestion-control/pacer loop. Mirrors the websockets service's policies (per-display settings, extended-desktop layout, capture pause rules) so the two transports stay in behavioral parity.

Attributes

attributesettingsOptional[AppSettings]
= settings
attributetasksList[asyncio.Task]
= []
attributeshutdown_event
= asyncio.Event()
attribute_shutdown_called
= False
attributesignaling_clientOptional[WebRTCSignalingClient]
= None
attributemedia_pipelineOptional[MediaPipelinePixel]
= None

The primary display's pipeline (also stored under the "primary" key of display_pipelines).

attributertc_appOptional[RTCApp]
= None
attributeinput_handlerOptional[WebRTCInput]
= None
attributeresource_monitorOptional[resource_stats.ResourceMonitor]
= None
attributemetricsOptional[Metrics]
= None
attributepeer_id
= 1
attributeargsOptional[SimpleNamespace]
= None

Mutable per-session snapshot of the client-tunable settings (seeded from SETTING_DEFINITIONS); the primary display's authority, and the seed for joining secondaries.

attributemonitoring_utils_usedDict[str, bool]
= {}
attributemon_hmac_turnOptional[HMACRTCMonitor]
= None
attributemon_rest_apiOptional[RESTRTCMonitor]
= None
attributemon_rtc_config_fileOptional[RTCConfigFileMonitor]
= None
attributemon_cloudflare_turnOptional[CloudflareRTCMonitor]
= None
attributepeer_managerOptional[WebRTCPeerManagement]
= None
attributesupervisor
= supervisor
attributedisplay_clientsDict[str, Dict[str, Any]]
= {}

Per-secondary-display registration state — requested dimensions, position, and the display's own copies of the client-tunable video settings.

attributedisplay_layoutsDict[str, Dict[str, int]]
= {}

The computed extended-desktop layout the input handler offsets coordinates against.

attribute_client_scalesDict[str, float]
= {}
attribute_client_stream_boxesDict[str, Tuple[Tuple[float, float, float, float], float]]
= {}
attributedisplay_pipelinesDict[str, MediaPipelinePixel]
= {}

One MediaPipelinePixel per connected display id.

attribute_display_dpisDict[str, int]
= {}
attribute_last_idr_request_timesDict[str, float]
= {}
attribute_display_lock
= asyncio.Lock()
attribute_primary_dimsOptional[Tuple[int, int]]
= None

The primary's last layout-path resolution request, or None while the pipeline dimensions are its authority.

attribute_wayland_ctl_moduleOptional[Any]
= None

Fallback pixelflux handle for Wayland output management when the primary has no live capture module (any handle reaches the shared compositor backend).

attribute_host_output_capacityOptional[int]
= None

Host-capture mode: outputs the host compositor can back displays with; None until a query answers, never set when self-compositing (outputs are minted on demand there).

attribute_last_resize_requestOptional[Tuple[int, int]]
= None

Last (w, h) a client asked the primary to become; the realized size may differ (CVT cell alignment), so idempotence is judged against the request too.

attribute_wm_swap
= MultiMonitorWindowManager()

Swaps heavy DEs, which tile poorly across the per-display regions, for a minimal Openbox once a secondary joins.

attribute_congestion_steerDict[str, CongestionSteer]
= {}

Each display's CongestionSteer, the state its CBR target is steered with.

attributeRECONNECT_GRACE_S
= 3.0

Seconds the primary capture outlives its last consumer, so a controller tab reload (drop and re-add within a second or two) reuses the warm capture while viewers and the secondary display stream through.

attribute_primary_stop_grace_taskOptional[asyncio.Task]
= None

The pending deferred primary-capture stop.

attribute_mic_controlOptional[AudioControl]
= None

Sound-server control connection for the shared SelkiesVirtualMic, provisioned once on the first mic packet (the data plane is per-peer pcmflux playback into the input sink).

attribute_mic_module_indexOptional[int]
= None

Loaded virtual-source module, reused when the websockets path already loaded it.

attribute_mic_module_owned
= False

Whether this path loaded the module and so unloads it on shutdown.

attribute_mic_provisioned
= False

Set once _mic_module_index is known.

attribute_mic_provision_lock
= asyncio.Lock()

Serializes concurrent first-packet provisioning across peers.

attribute_VIDEO_SETTING_APPLIERSDict[str, Callable[[MediaPipelinePixel, Any], Awaitable[Any]]]
= {'rate_control_mode': lambda p, v: p.update_rate_control_mode(RateControlMode(v)), 'video_crf': lambda p, v: p.set_crf(v), 'video_bitrate': lambda p, v: p.set_video_bitrate(v), 'framerate': lambda p, v: p.set_framerate(v), 'use_cpu': lambda p, v: p.set_use_cpu(bool(v)), 'encoder': lambda p, v: p.set_encoder(str(v)), 'video_fullcolor': lambda p, v: p.set_video_fullcolor(bool(v)), 'video_streaming_mode': lambda p, v: p.set_video_streaming_mode(bool(v)), 'use_paint_over_quality': lambda p, v: p.set_use_paint_over_quality(bool(v)), 'video_paintover_crf': lambda p, v: p.set_video_paintover_crf(int(v)), 'video_paintover_burst_frames': lambda p, v: p.set_video_paintover_burst_frames(int(v))}

Setting name to live per-pipeline setter; each display's pipeline owns its running values.

Functions

constructor__init__(supervisor) -> None
Source Code
def __init__(self, supervisor: CentralizedStreamServer) -> None:
    super().__init__("webrtc")
    self.settings: Optional[AppSettings] = settings
    self.tasks: List[asyncio.Task] = []
    self.shutdown_event = asyncio.Event()
    self._shutdown_called = False
    self.signaling_client: Optional[WebRTCSignalingClient] = None
    self.media_pipeline: Optional[MediaPipelinePixel] = None
    self.rtc_app: Optional[RTCApp] = None
    self.input_handler: Optional[WebRTCInput] = None
    self.resource_monitor: Optional[resource_stats.ResourceMonitor] = None
    self.metrics: Optional[Metrics] = None
    self.peer_id = 1
    self.args: Optional[SimpleNamespace] = None
    self.monitoring_utils_used: Dict[str, bool] = {}
    self.mon_hmac_turn: Optional[HMACRTCMonitor] = None
    self.mon_rest_api: Optional[RESTRTCMonitor] = None
    self.mon_rtc_config_file: Optional[RTCConfigFileMonitor] = None
    self.mon_cloudflare_turn: Optional[CloudflareRTCMonitor] = None
    self.peer_manager: Optional[WebRTCPeerManagement] = None
    self.supervisor = supervisor
    self.display_clients: Dict[str, Dict[str, Any]] = {}
    self.display_layouts: Dict[str, Dict[str, int]] = {}
    # Each page's reported CSS-to-remote scale, by display id (the primary
    # included), rebroadcast with the layout for cross-display drags.
    self._client_scales: Dict[str, float] = {}
    # Each page's stream box on the user's desktop, by display id: origin
    # and remote pixels per desktop pixel, with when it last changed.
    self._client_stream_boxes: Dict[
        str, Tuple[Tuple[float, float, float, float], float]] = {}
    self.display_pipelines: Dict[str, MediaPipelinePixel] = {}
    # The DPI each secondary's page asked for; the primary's is _last_applied_dpi.
    self._display_dpis: Dict[str, int] = {}
    self._last_idr_request_times: Dict[str, float] = {}
    self._display_lock = asyncio.Lock()
    self._primary_dims: Optional[Tuple[int, int]] = None
    self._wayland_ctl_module: Optional[Any] = None
    self._host_output_capacity: Optional[int] = None
    self._last_resize_request: Optional[Tuple[int, int]] = None
    self._wm_swap = MultiMonitorWindowManager()
    self._congestion_steer: Dict[str, CongestionSteer] = {}
    self.RECONNECT_GRACE_S = 3.0
    self._primary_stop_grace_task: Optional[asyncio.Task] = None

    self._mic_control: Optional[AudioControl] = None
    self._mic_module_index: Optional[int] = None
    self._mic_module_owned = False
    self._mic_provisioned = False
    self._mic_provision_lock = asyncio.Lock()

    self._init_default_settings()
paramsupervisorCentralizedStreamServer

Returns

None
func_init_default_settings() -> None

Seed self.args from SETTING_DEFINITIONS and derive the manual startup geometry.

Range settings pin to the single allowed value when the range is locked (min == max), otherwise take the definition's default; other types copy the configured value verbatim.

Source Code
def _init_default_settings(self) -> None:
    """Seed ``self.args`` from ``SETTING_DEFINITIONS`` and derive the manual
    startup geometry.

    Range settings pin to the single allowed value when the range is locked
    (min == max), otherwise take the definition's default; other types copy
    the configured value verbatim.
    """
    self.args = SimpleNamespace()
    try:
        for setting_def in SETTING_DEFINITIONS:
            name = setting_def["name"]
            stype = setting_def["type"]
            if stype == "bool":
                value = getattr(self.settings, name)[0]
            elif stype == "range":
                min, max = getattr(self.settings, name)
                value = (
                    min
                    if min == max
                    else setting_def.get("meta", {}).get("default_value", 0)
                )
            elif stype == "enum":
                value = getattr(self.settings, name)
            elif stype in ("int", "float", "str", "list"):
                value = getattr(self.settings, name)
            else:
                continue
            setattr(self.args, name, value)
    except Exception as e:
        logger.error(f"Error initializing default settings: {e}", exc_info=True)

    self._manual_dims: Optional[Tuple[int, int]] = None
    if getattr(self.args, "manual_resolution", False):
        width = int(getattr(self.args, "manual_width", 0) or 0)
        height = int(getattr(self.args, "manual_height", 0) or 0)
        if width > 0 and height > 0:
            self._manual_dims = (width - (width % 2), height - (height % 2))

Returns

None
funcinitialize_components() -> None

Build every component: metrics, signaling, the primary media pipeline, the RTC app, the input handler, and the monitors, then wire the peer manager with the fetched RTC configuration.

The settings are re-snapshotted first: the service is constructed once at boot, but a live transport switch lands here with the settings singleton already re-resolved for webrtc (encoder filter, rate-control default). Metrics backs both the Prometheus endpoint and the WebRTC CSV statistics, so it is built when either flag is on. A configured manual resolution is applied before the pipeline is sized: on X11 the screen is resized now and the pipeline takes what the X server realized (CVT cell alignment can widen the mode); on Wayland the dimensions are the resize, since the capture start sizes the compositor output from them, and the capture scale is seeded from the configured DPI so the first start honors it (handle_scaling updates it later). The interposer socket paths and the gamepad backend are process-wide state shared with the websockets service, so both transports read the same settings for them.

Source Code
async def initialize_components(self) -> None:
    """Build every component: metrics, signaling, the primary media
    pipeline, the RTC app, the input handler, and the monitors, then wire
    the peer manager with the fetched RTC configuration.

    The settings are re-snapshotted first: the service is constructed once
    at boot, but a live transport switch lands here with the settings
    singleton already re-resolved for webrtc (encoder filter, rate-control
    default). Metrics backs both the Prometheus endpoint and the WebRTC
    CSV statistics, so it is built when either flag is on. A configured
    manual resolution is applied before the pipeline is sized: on X11 the
    screen is resized now and the pipeline takes what the X server
    realized (CVT cell alignment can widen the mode); on Wayland the
    dimensions are the resize, since the capture start sizes the compositor
    output from them, and the capture scale is seeded from the configured
    DPI so the first start honors it (`handle_scaling` updates it later).
    The interposer socket paths and the gamepad backend are process-wide
    state shared with the websockets service, so both transports read the
    same settings for them.
    """

    self._init_default_settings()

    if self.args.enable_metrics_http or self.args.enable_webrtc_statistics:
        webrtc_csv = self.args.enable_webrtc_statistics
        self.metrics = Metrics(using_webrtc_csv=webrtc_csv)

    self.signaling_client = self.create_signaling_client()

    # Surround (>2ch) rides Chromium's multiopus codec; the offered codec set
    # must be swapped before any peer connection builds its capabilities.
    if int(self.args.audio_channels) > 2:
        configure_multiopus(int(self.args.audio_channels))

    self.media_pipeline = MediaPipelinePixel(
        async_event_loop=asyncio.get_running_loop(),
        encoder=self.args.encoder,
        framerate=int(self.args.framerate),
        # kbps, as consumed by pixelflux.
        video_bitrate=int(self.args.video_bitrate),
        # Enum with a wider server-side value_range: an operator override can
        # arrive as an arbitrary numeric string.
        audio_bitrate=int(float(self.args.audio_bitrate)),
        audio_channels=int(self.args.audio_channels),
        audio_enabled=self.args.audio_enabled,
        audio_device_name=self.args.audio_device_name,
        crf=int(self.args.video_crf),
        video_fullcolor=bool(self.args.video_fullcolor),
        use_cpu=bool(self.args.use_cpu),
        video_streaming_mode=bool(self.args.video_streaming_mode),
        use_paint_over_quality=bool(self.args.use_paint_over_quality),
        video_paintover_crf=int(self.args.video_paintover_crf),
        video_paintover_burst_frames=int(self.args.video_paintover_burst_frames),
    )
    if self._manual_dims:
        if not IS_WAYLAND:
            realized = await resize_display(f"{self._manual_dims[0]}x{self._manual_dims[1]}")
            if realized:
                self._manual_dims = realized
        self.media_pipeline.width, self.media_pipeline.height = self._manual_dims
    if self.args.enable_rate_control:
        self.media_pipeline.rc_mode = RateControlMode(self.args.rate_control_mode)
    else:
        # Rate control disabled runs CRF on both transports.
        self.media_pipeline.rc_mode = RateControlMode.CRF

    (
        stun_servers,
        turn_servers,
        rtc_config,
        self.monitoring_utils_used,
    ) = await get_rtc_configuration(self.args)
    self.rtc_app = RTCApp(
        async_event_loop=asyncio.get_running_loop(),
        encoder=self.args.encoder,
        stun_servers=stun_servers,
        turn_servers=turn_servers,
    )
    self.rtc_app.media_pipeline = self.media_pipeline
    self.rtc_app.provision_virtual_mic = self._provision_webrtc_virtual_mic
    await self.rtc_app.open_ice_muxes()
    if self.rtc_app.ice_lite_enabled():
        logger.info("WebRTC ICE-lite: the server offers host candidates only and answers the client's checks; STUN/TURN serve the client side")
    self.display_pipelines["primary"] = self.media_pipeline

    self.input_handler = WebRTCInput(
        rtc_app=self.rtc_app,
        uinput_mouse_socket_path=getattr(self.args, "uinput_mouse_socket", "") or "",
        js_socket_path_prefix=getattr(self.args, "js_socket_path", "/tmp"),
        enable_clipboard=self.args.enable_clipboard,
        enable_binary_clipboard="true"
        if self.args.enable_binary_clipboard
        else "false",
        enable_cursors=self.args.enable_cursors,
        cursor_size=self.args.cursor_size,
        cursor_scale=1.0,
        cursor_debug=self.args.debug_cursors,
        upload_dir=self.args.file_manager_path,
        is_wayland=IS_WAYLAND,
        app_wayland_display=(getattr(self.args, "app_wayland_display", "")
                             or getattr(self.args, "wayland_host_display", "")),
        uinput_gamepad=getattr(self.args, "uinput_gamepad", "auto"),
        # Duck-typed layout source: send_x11_mouse offsets a secondary
        # display's coordinates by display_layouts[display_id].
        data_server_instance=self,
    )
    self.input_handler.initialize_upload_dir()
    if IS_WAYLAND:
        self.media_pipeline.scale = await self.input_handler.realize_wayland_dpi(
            getattr(settings, "scaling_dpi", "96") or 96)

    # Keyed to the pipeline's render node so the GPU stats describe the encoding GPU.
    stats_gpu_id = parse_gpu_id(getattr(self.args, "gpu_id", ""))
    self.resource_monitor = resource_stats.ResourceMonitor(
        gpu_id=stats_gpu_id if (stats_gpu_id or 0) > 0 else 0,
        dri_node=getattr(self.args, "encode_dri", "") or "",
        metrics=self.metrics,
    )

    self.create_peer_manager(rtc_config)

Returns

None
funccreate_signaling_client() -> WebRTCSignalingClient

Create and configure signaling client.

Source Code
def create_signaling_client(self) -> WebRTCSignalingClient:
    """Create and configure signaling client."""
    using_https = self.args.enable_https
    using_basic_auth = self.args.enable_basic_auth
    ws_protocol = "wss:" if using_https else "ws:"

    prefix = self.settings.subfolder
    username = self.settings.basic_auth_user
    password = self.settings.basic_auth_password
    client = WebRTCSignalingClient(
        f"{ws_protocol}//localhost:{self.args.port}{prefix}/api/ws",
        enable_https=using_https,
        enable_basic_auth=using_basic_auth,
        basic_auth_user=username,
        basic_auth_password=password,
        server_token=getattr(self.settings, "master_token", None),
    )
    return client

Returns

selkies.webrtc_signaling_client.WebRTCSignalingClient
funchandle_signaling_error(error) -> None

Handle signaling errors.

Source Code
async def handle_signaling_error(self, error: Exception) -> None:
    """Handle signaling errors."""
    logger.error(f"Signaling client error: {error}. Closing the pipelines")
    await self.handle_signaling_disconnect()
paramerrorException

Returns

None
funchandle_signaling_disconnect() -> None

Tear down every RTC connection once the signaling link drops.

Source Code
async def handle_signaling_disconnect(self) -> None:
    """Tear down every RTC connection once the signaling link drops."""
    logger.info("Signaling disconnected, cleaning up all resources")
    try:
        await self.rtc_app.stop_all_rtc_connections()
    except Exception as e:
        logger.error(
            f"Error during signaling disconnect cleanup: {e}", exc_info=True
        )

Returns

None
funchandle_session_start(session_peer_id, client_type, client_token=None, display_id='primary', display_position='right', fullcolor_codecs=None) -> None

Start an RTC connection for a joining peer.

A secondary display's controller is gated on the effective second-screen availability first: the published setting can lag a host-side change, so the capacity is re-read and a refusal closes the peer's signaling socket with a fatal verdict (a bare return would leave the page on "Connecting..." forever).

Source Code
async def handle_session_start(
    self, session_peer_id: str, client_type: str, client_token: Optional[str] = None,
    display_id: str = "primary", display_position: str = "right",
    fullcolor_codecs: Optional[List[str]] = None,
) -> None:
    """Start an RTC connection for a joining peer.

    A secondary display's controller is gated on the effective second-screen
    availability first: the published setting can lag a host-side change, so
    the capacity is re-read and a refusal closes the peer's signaling socket
    with a fatal verdict (a bare return would leave the page on
    "Connecting..." forever).

    Args:
        session_peer_id: The signaling peer id of the joining client.
        client_type: "controller" or a viewer/shared role name.
        client_token: Optional per-client auth token (governs input role).
        display_id: The display this peer consumes ("primary" or a
            secondary id).
        display_position: Where a joining secondary sits relative to the
            primary ("right", "left", "up", "down").
    """
    # From the registry, not SESSION_START: the signaling server that validated
    # the claim is this process, and the relay's fields are positional.
    peer = self.peer_manager.peers.get(session_peer_id) if self.peer_manager else None
    client_slot = getattr(peer, "client_slot", None) if peer else None
    logger.debug(
        f"starting session for client peer id: {session_peer_id} of type: {client_type} (display '{display_id}')"
    )
    try:
        if display_id != "primary" and client_type == "controller":
            await self._refresh_second_screen_capacity()
            available, reason = self._second_screen_availability()
            if not available:
                logger.warning(
                    "Secondary display '%s' refused: %s", display_id, reason,
                )
                await self._close_peer_signaling_ws(
                    session_peer_id, 4000, reason.encode(),
                )
                return
            # Dimensions arrive through the client's first resize message.
            entry = self.display_clients.setdefault(display_id, {"width": 0, "height": 0})
            entry["position"] = display_position
            self._seed_display_settings(entry)
        await self.rtc_app.start_rtc_connection(
            session_peer_id, client_type, client_token, display_id, client_slot,
            fullcolor_codecs=fullcolor_codecs)
        if self.args.enable_webrtc_statistics and self.metrics:
            await self.metrics.initialize_webrtc_csv_file(self.args.webrtc_statistics_dir)
        logger.info(f"Session started for peer {session_peer_id} ({client_type}, display '{display_id}').")
    except Exception as e:
        logger.error(
            f"Error starting session for client peer id {session_peer_id}: {e}",
            exc_info=True,
        )
        await self.rtc_app.stop_rtc_connection(session_peer_id, client_type)
paramsession_peer_idstr

The signaling peer id of the joining client.

paramclient_typestr

"controller" or a viewer/shared role name.

paramclient_tokenOptional[str]
= None

Optional per-client auth token (governs input role).

paramdisplay_idstr
= 'primary'

The display this peer consumes ("primary" or a secondary id).

paramdisplay_positionstr
= 'right'

Where a joining secondary sits relative to the primary ("right", "left", "up", "down").

paramfullcolor_codecsOptional[List[str]]
= None

Returns

None
funchandle_session_end(session_peer_id, client_type) -> None

Handle end of a session initiated by a client. Stops the RTC connection and media pipeline for the given session peer id.

Source Code
async def handle_session_end(self, session_peer_id: str, client_type: str) -> None:
    """Handle end of a session initiated by a client.
    Stops the RTC connection and media pipeline for the given session peer id.
    """
    try:
        if self.rtc_app:
            await self.rtc_app.stop_rtc_connection(session_peer_id, client_type)
        logger.info(
            f"session ended for client peer id {session_peer_id} of type {client_type}"
        )
    except Exception as e:
        logger.error(
            f"Error handling session end for {session_peer_id}: {e}", exc_info=True
        )
paramsession_peer_idstr
paramclient_typestr

Returns

None
funccreate_peer_manager(rtc_config) -> None

Build the signaling-side peer manager with the fetched RTC config and the TURN/STUN/sharing options the handshake needs.

Source Code
def create_peer_manager(self, rtc_config: Any) -> None:
    """Build the signaling-side peer manager with the fetched RTC config
    and the TURN/STUN/sharing options the handshake needs."""
    options = argparse.Namespace(
        keepalive_timeout=30,
        rtc_config_file=self.args.rtc_config_json,
        turn_shared_secret=self.args.turn_shared_secret,
        rtc_config=rtc_config,
        turn_host=self.args.turn_host,
        turn_port=self.args.turn_port,
        turn_protocol=self.args.turn_protocol,
        turn_tls=self.args.turn_tls,
        turn_auth_header_name=self.args.turn_rest_username_auth_header,
        stun_host=self.args.stun_host,
        stun_port=self.args.stun_port,
        enable_sharing=self.args.enable_sharing,
        enable_shared=self.args.enable_shared,
        enable_player2=self.args.enable_player2,
        enable_player3=self.args.enable_player3,
        enable_player4=self.args.enable_player4,
    )
    self.peer_manager = WebRTCPeerManagement(options)
    self.peer_manager.on_client_presence = self.supervisor.set_clients_present
paramrtc_configAny

Returns

None
funcsetup_callbacks() -> None

Wire signaling, RTC app, media pipeline, input handler and monitor callbacks to each other.

Cursors come from pixelflux on both backends (Wayland compositor / X11 XFixes monitor) and route through the input handler's transport callback, capped at its DPI-scaled cursor size. Offers resolve their codec and SDP munging per display, so displays can run different encoders and chroma formats and a live full-color toggle reaches every later offer. DPI scaling is wired independently of enable_resize, which gates only the primary's dynamic resolution (in on_resize_handler): the websockets transport applies scaling through the SETTINGS payload regardless of the resize gate, and a secondary display's whole bring-up rides its resize message.

Source Code
def setup_callbacks(self) -> None:
    """Wire signaling, RTC app, media pipeline, input handler and monitor
    callbacks to each other.

    Cursors come from pixelflux on both backends (Wayland compositor / X11
    XFixes monitor) and route through the input handler's transport
    callback, capped at its DPI-scaled cursor size. Offers resolve their
    codec and SDP munging per display, so displays can run different
    encoders and chroma formats and a live full-color toggle reaches
    every later offer. DPI scaling is wired independently of
    `enable_resize`, which gates only the primary's dynamic resolution
    (in `on_resize_handler`): the websockets transport applies scaling
    through the SETTINGS payload regardless of the resize gate, and a
    secondary display's whole bring-up rides its resize message.
    """
    if not self.rtc_app or not self.media_pipeline or not self.input_handler:
        return

    self.signaling_client.on_error = self.handle_signaling_error
    self.signaling_client.on_disconnect = self.handle_signaling_disconnect
    self.signaling_client.on_session_start = self.handle_session_start
    self.signaling_client.on_session_end = self.handle_session_end
    self.signaling_client.on_sdp = self.rtc_app.set_sdp
    self.signaling_client.on_ice = self.rtc_app.set_ice

    self.media_pipeline.produce_data = self.rtc_app.consume_data
    self.media_pipeline.on_encoder_demoted = (
        lambda encoder: asyncio.ensure_future(self._encoder_demoted("primary", encoder))
    )
    self.media_pipeline.on_stream_info = self._publish_stream_info
    self.media_pipeline.on_pipeline_started = self.send_current_cursor

    self.rtc_app.request_idr_frame = self.request_idr_for_display
    self.rtc_app.invalidate_reference = self.invalidate_reference_for_display
    self._invalidation_log: Dict[str, tuple] = {}
    self.rtc_app.start_display_media = self.start_display_media
    self.rtc_app.stop_display_media = self.stop_display_media
    self.rtc_app.on_sdp = self.signaling_client.send_sdp
    self.rtc_app.on_ice = self.signaling_client.send_ice
    self.rtc_app.on_data_open = self.handle_data_channel_open
    self.rtc_app.on_data_close = lambda: logger.info("Data channel closed")
    self.rtc_app.on_data_error = lambda e: logger.error(f"Data channel error: {e}")
    self.rtc_app.on_data_message = self.input_handler.on_message
    self.rtc_app.on_peer_gone = self.handle_peer_gone
    self.input_handler.on_request_keyframe = self.request_idr_for_display

    self.input_handler.on_cursor_change = lambda data: (
        self.rtc_app.send_cursor_data(data)
    )
    self.media_pipeline.on_cursor_data = lambda data: (
        self.input_handler.on_cursor_change(data)
    )
    self.media_pipeline.get_cursor_size_cap = lambda: getattr(
        self.input_handler, "cursor_size_cap", 0
    )
    self.input_handler.on_video_encoder_bit_rate = self.handle_video_bitrate_change
    self.input_handler.on_audio_encoder_bit_rate = self.handle_audio_bitrate_change
    self.input_handler.on_mouse_pointer_visible = self.handle_pointer_visible
    self.input_handler.on_clipboard_read = lambda d, t: (
        self.rtc_app.send_clipboard_data(d, t)
    )
    self.input_handler.on_set_fps = self.handle_fps_change
    self.input_handler.on_client_fps = lambda fps: (
        self.metrics.set_fps(fps) if self.metrics else None
    )
    self.input_handler.on_client_latency = lambda latency: (
        self.metrics.set_latency(latency) if self.metrics else None
    )
    self.input_handler.on_ping_response = lambda latency: (
        self.rtc_app.send_latency_time(latency)
    )
    self.input_handler.on_client_webrtc_stats = self.handle_client_werbtc_stats
    self.input_handler.on_update_settings = self.handle_update_settings
    self.input_handler.on_update_rate_control_mode = self.handle_rate_control_change
    self.input_handler.on_update_crf = self.handle_crf_change
    self.rtc_app.get_encoder_for_display = self._encoder_for_display
    self.rtc_app.on_video_codec_declined = self._video_codec_declined
    self.rtc_app.on_fullcolor_declined = self._fullcolor_declined
    self.rtc_app.get_fullcolor_for_display = self._fullcolor_for_display
    self.rtc_app.get_use_cpu_for_display = self._use_cpu_for_display
    self.rtc_app.on_video_consumer_active = self.handle_video_consumer_active
    self.rtc_app.on_audio_consumer_active = self.handle_audio_consumer_active
    self.rtc_app.on_consumers_changed = self.handle_consumers_changed
    # /api/tokens updates must reach live WebRTC peers too.
    sessions.webrtc_reconcile_hook = self.reconcile_webrtc_peers

    self.input_handler.on_scaling_ratio = self.handle_scaling
    self.input_handler.on_resize = self.on_resize_handler
    self.input_handler.on_session_compositor_adopted = self._resync_wayland_session_scale

    self.resource_monitor.on_tick = self.handle_resource_tick
    self.resource_monitor.watched = lambda: bool(self.rtc_app and self.rtc_app.stats_displays())

Returns

None
func_second_screen_availability() -> Tuple[bool, str]

Whether this session can actually attach a second display, and the reason when it cannot (websockets-mode parity).

The admin flag gates first. Past it X11 mints a RandR monitor on demand; host capture is bounded by the host compositor's real output count (unknown until a pipeline start establishes the host session); and the self-composited Wayland backend rides the input handler's session-screen ladder: the session compositor's control socket grows a screen on demand, a spare screen the session already opened is arranged instead without one, and a session running directly on the capture compositor needs neither.

Source Code
def _second_screen_availability(self) -> Tuple[bool, str]:
    """Whether this session can actually attach a second display, and the
    reason when it cannot (websockets-mode parity).

    The admin flag gates first. Past it X11 mints a RandR monitor on
    demand; host capture is bounded by the host compositor's real output
    count (unknown until a pipeline start establishes the host session);
    and the self-composited Wayland backend rides the
    input handler's session-screen ladder: the session compositor's
    control socket grows a screen on demand, a spare screen the session
    already opened is arranged instead without one, and a session running
    directly on the capture compositor needs neither.

    Returns:
        A ``(available, reason)`` pair; ``reason`` is empty when available.
    """
    enabled, _ = self.settings.second_screen
    if not enabled:
        return False, "Second screens are disabled on this server."
    if not IS_WAYLAND:
        return True, ""
    if (self.settings.wayland_host_display or "").strip():
        capacity = self._host_output_capacity
        if capacity is None or capacity < 0:
            return False, "The host compositor's outputs are not known yet."
        if capacity < 2:
            return False, "The host compositor has a single output, so a second display has nothing to capture."
        return True, ""
    if self.input_handler is None:
        return False, "The input system is not up yet."
    return self.input_handler.session_screen_capability()

Returns

typing.Tuple

A (available, reason) pair; reason is empty when available.

func_refresh_second_screen_capacity() -> bool

Re-read what bounds a second display on this backend.

Host capture re-reads how many outputs the host exposes; the nested Wayland backend re-probes the session compositor's control socket. X11 has no bound.

Source Code
async def _refresh_second_screen_capacity(self) -> bool:
    """Re-read what bounds a second display on this backend.

    Host capture re-reads how many outputs the host exposes; the nested
    Wayland backend re-probes the session compositor's control socket.
    X11 has no bound.

    Returns:
        True when the answer changed, i.e. the second-screen availability
        that clients were told may have flipped.
    """
    if not IS_WAYLAND:
        return False
    if not (self.settings.wayland_host_display or "").strip():
        if self.input_handler is None:
            return False
        before = self.input_handler.session_screen_capability()[0]
        fresh = await self.input_handler.probe_session_screen_capability()
        return fresh[0] != before
    module = self._wayland_capture_handle()
    if module is None:
        return False
    try:
        capacity = int(await asyncio.to_thread(module.output_capacity))
    except Exception as e:
        logger.warning(f"Wayland output capacity query failed: {e}")
        return False
    changed = capacity != self._host_output_capacity
    self._host_output_capacity = capacity
    return changed

Returns

bool

True when the answer changed, i.e. the second-screen availability

func_server_settings_payload() -> Dict[str, Any]

get_server_settings with second_screen and ui_sidebar_show_apps published as EFFECTIVE availability — the admin flag AND what the backend can actually do — so dashboards never offer a second display the server would immediately refuse, nor an apps panel whose every button would fail. Adds the terminal the apps panel launches in, chosen by the session's windowing system (absent when none is installed: the client keeps its default), and what the apps panel already has installed, which no browser's own storage can answer for a session opened somewhere else — absent until the runner has answered, because a client told nothing is installed clears its own record.

Source Code
def _server_settings_payload(self) -> Dict[str, Any]:
    """get_server_settings with second_screen and ui_sidebar_show_apps
    published as EFFECTIVE availability — the admin flag AND what the
    backend can actually do — so dashboards never offer a second display
    the server would immediately refuse, nor an apps panel whose every
    button would fail. Adds the terminal the apps panel launches in, chosen
    by the session's windowing system (absent when none is installed: the
    client keeps its default), and what the apps panel already has
    installed, which no browser's own storage can answer for a session
    opened somewhere else — absent until the runner has answered, because a
    client told nothing is installed clears its own record."""
    payload = get_server_settings()
    available, _ = self._second_screen_availability()
    entry = payload.get("settings", {}).get("second_screen")
    if isinstance(entry, dict) and entry.get("value") and not available:
        payload["settings"]["second_screen"] = dict(entry, value=False)
    apps = payload.get("settings", {}).get("ui_sidebar_show_apps")
    if (isinstance(apps, dict) and apps.get("value")
            and self.input_handler and not self.input_handler.apps_available()):
        payload["settings"]["ui_sidebar_show_apps"] = dict(apps, value=False)
    installed = self.input_handler.installed_apps() if self.input_handler else None
    if installed is not None:
        payload["settings"]["apps_installed"] = {"value": installed}
    return payload

Returns

typing.Dict[str, typing.Any]
funchandle_data_channel_open(channel=None) -> None

Greet the peer that just joined: every display page and viewer needs the server settings for conditional UI, the current cursor, and the display roster. Sent on ITS channel when given; without one, falls back to broadcasting.

Source Code
def handle_data_channel_open(self, channel: Optional[Any] = None) -> None:
    """Greet the peer that just joined: every display page and viewer needs
    the server settings for conditional UI, the current cursor, and the
    display roster. Sent on ITS channel when given; without one, falls back
    to broadcasting."""
    logger.info("Peer data channel open for input.")
    server_settings_payload = self._server_settings_payload()
    if channel is not None:
        self.rtc_app.send_message_to_channel(
            channel, "server_settings", server_settings_payload
        )
        self.rtc_app.send_message_to_channel(
            channel, "display_config_update", self._display_config_payload()
        )
        peer = next((obj for obj in self.rtc_app.peer_connections.values()
                     if obj.get("data_channel") is channel), None)
        if peer is not None and peer.get("client_type") == ClientType.CONTROLLER \
                and (peer.get("display_id") or "primary") == "primary":
            for name, size in self.supervisor.pending_print_documents():
                self.rtc_app.send_print_document(name, size, channel)
        if peer is not None and peer.get("client_type") == ClientType.CONTROLLER:
            did = peer.get("display_id") or "primary"
            settled = getattr(getattr(self.display_pipelines.get(did), "stream_watch", None), "info", None)
            if settled:
                self.rtc_app.send_stream_info(did, settled, channel)
    else:
        self.rtc_app.send_media_data_over_channel(
            "server_settings", server_settings_payload
        )
        self._broadcast_display_config()
    self.send_current_cursor(channel)
paramchannelOptional[Any]
= None

Returns

None
funcannounce_print_document(name, size) -> None

Tell every controller peer a printed document waits in the spool.

Source Code
async def announce_print_document(self, name: str, size: int) -> None:
    """Tell every controller peer a printed document waits in the spool."""
    if self.rtc_app:
        self.rtc_app.send_print_document(name, size)
paramnamestr
paramsizeint

Returns

None
funcsessions() -> List[Dict[str, Any]]
Source Code
async def sessions(self) -> List[Dict[str, Any]]:
    return await self.rtc_app.sessions() if self.rtc_app else []

Returns

typing.List[typing.Dict[str, typing.Any]]
funcdisconnect_session(session_id) -> bool
Source Code
async def disconnect_session(self, session_id: str) -> bool:
    return bool(self.rtc_app) and await self.rtc_app.disconnect_peer(session_id)
paramsession_idstr

Returns

bool
funcsend_current_cursor(channel=None) -> None

Resend the current cursor (on channel open / video restart): to one peer's channel when given, otherwise to every connected peer.

Idempotent; a slept/woken tab clears its cursor canvas and needs it back.

Source Code
def send_current_cursor(self, channel: Optional[Any] = None) -> None:
    """Resend the current cursor (on channel open / video restart): to one
    peer's channel when given, otherwise to every connected peer.

    Idempotent; a slept/woken tab clears its cursor canvas and needs it back.
    """
    if not self.rtc_app:
        return
    cursor_data = None
    if self.input_handler:
        try:
            cursor_data = self.input_handler.get_current_cursor_data()
        except Exception as e:
            logger.warning(f"Failed to fetch current cursor data: {e}")
    if cursor_data is None:
        cursor_data = self.rtc_app.last_cursor_sent
    if not cursor_data:
        return
    try:
        if channel is not None:
            self.rtc_app.send_message_to_channel(channel, "cursor", cursor_data)
        else:
            self.rtc_app.send_cursor_data(cursor_data)
    except Exception as e:
        logger.warning(f"Failed to send current cursor to client: {e}")
paramchannelOptional[Any]
= None

Returns

None
funchandle_pointer_visible(visible) -> None

Compose the cursor into the captured video, on every display's capture (the websockets capture_cursor tunable is likewise global).

Source Code
async def handle_pointer_visible(self, visible: bool) -> None:
    """Compose the cursor into the captured video, on every display's capture
    (the websockets capture_cursor tunable is likewise global)."""
    for pipeline in list(self.display_pipelines.values()):
        if pipeline is not None:
            await pipeline.set_pointer_visible(visible)
paramvisiblebool

Returns

None
funchandle_video_bitrate_change(bitrate, display_id='primary') -> None

Video bitrate change for the display whose page sent it; sanitized against the server's configured range like the SETTINGS path, so the opcode cannot bypass a locked/narrowed range.

Source Code
async def handle_video_bitrate_change(self, bitrate: int, display_id: str = "primary") -> None:
    """Video bitrate change for the display whose page sent it; sanitized
    against the server's configured range like the SETTINGS path, so the
    opcode cannot bypass a locked/narrowed range."""
    sanitized = sanitize_client_setting("video_bitrate", bitrate, self.settings, logger)
    if sanitized is None or sanitized == self._display_setting(display_id, "video_bitrate"):
        return
    await self._apply_display_setting(display_id or "primary", "video_bitrate", sanitized)
parambitrateint
paramdisplay_idstr
= 'primary'

Returns

None
funchandle_audio_bitrate_change(bitrate) -> None

Handle audio bitrate change request (bps; sanitized like SETTINGS).

Source Code
async def handle_audio_bitrate_change(self, bitrate: int) -> None:
    """Handle audio bitrate change request (bps; sanitized like SETTINGS)."""
    sanitized = sanitize_client_setting("audio_bitrate", bitrate, self.settings, logger)
    if sanitized is None or sanitized == getattr(self.args, "audio_bitrate", None):
        return
    if self.media_pipeline:
        await self.media_pipeline.set_audio_bitrate(int(sanitized))
    self.args.audio_bitrate = sanitized
parambitrateint

Returns

None
funchandle_fps_change(fps, display_id='primary') -> None

Framerate change for the display whose page sent it; sanitized against the server's configured range like the SETTINGS path.

Source Code
async def handle_fps_change(self, fps: int, display_id: str = "primary") -> None:
    """Framerate change for the display whose page sent it; sanitized against
    the server's configured range like the SETTINGS path."""
    sanitized = sanitize_client_setting("framerate", fps, self.settings, logger)
    if sanitized is None or sanitized == self._display_setting(display_id, "framerate"):
        return
    await self._apply_display_setting(display_id or "primary", "framerate", sanitized)
paramfpsint
paramdisplay_idstr
= 'primary'

Returns

None
funchandle_rate_control_change(mode, display_id='primary') -> None

Rate-control switch for the display whose page sent it; honors the server's enable_rate_control lock like the SETTINGS path.

Source Code
async def handle_rate_control_change(self, mode: Any, display_id: str = "primary") -> None:
    """Rate-control switch for the display whose page sent it; honors the
    server's enable_rate_control lock like the SETTINGS path."""
    if self.args.enable_rate_control is False:
        logger.debug("Server has rate control disabled. Ignoring rate-control change.")
        return
    # Store the plain value: str(<str-Enum>) formats as the member name on
    # some supported Python versions, which would corrupt later comparisons.
    mode_str = mode.value if isinstance(mode, RateControlMode) else str(mode)
    await self._apply_display_setting(display_id or "primary", "rate_control_mode", mode_str)
parammodeAny
paramdisplay_idstr
= 'primary'

Returns

None
funchandle_crf_change(crf, display_id='primary') -> None

CRF change for the display whose page sent it; sanitized against the server's configured range like the SETTINGS path.

Source Code
async def handle_crf_change(self, crf: int, display_id: str = "primary") -> None:
    """CRF change for the display whose page sent it; sanitized against the
    server's configured range like the SETTINGS path."""
    sanitized = sanitize_client_setting("video_crf", int(crf), self.settings, logger)
    if sanitized is None or sanitized == self._display_setting(display_id, "video_crf"):
        return
    await self._apply_display_setting(display_id or "primary", "video_crf", sanitized)
paramcrfint
paramdisplay_idstr
= 'primary'

Returns

None
funchandle_client_werbtc_stats(webrtc_stat_type, webrtc_stats) -> None

Ingest client-reported WebRTC stats, gated on the Metrics object itself (built for metrics-http AND/OR the CSV statistics flag) so CSV-only configs actually ingest the stats they enabled.

Source Code
async def handle_client_werbtc_stats(
    self, webrtc_stat_type: str, webrtc_stats: str
) -> None:
    """Ingest client-reported WebRTC stats, gated on the Metrics object
    itself (built for metrics-http AND/OR the CSV statistics flag) so
    CSV-only configs actually ingest the stats they enabled."""
    if self.metrics:
        await self.metrics.set_webrtc_stats(webrtc_stat_type, webrtc_stats)
paramwebrtc_stat_typestr
paramwebrtc_statsstr

Returns

None
funcon_resize_handler(res, display_id='primary') -> None

Route a client resolution to its display: the primary resizes the real display directly while it is alone; once a secondary display is connected (or for any secondary), the resolution feeds the extended-desktop layout instead (websockets parity).

The layout path honors an admin manual-resolution lock the way the single-display path does: every display follows the server's geometry, so a second screen cannot be the way a client escapes the lock, and a locked size is the server's own, beyond a client alignment toggle.

Source Code
async def on_resize_handler(self, res: str, display_id: str = "primary") -> None:
    """Route a client resolution to its display: the primary resizes the real
    display directly while it is alone; once a secondary display is connected
    (or for any secondary), the resolution feeds the extended-desktop layout
    instead (websockets parity).

    The layout path honors an admin manual-resolution lock the way the
    single-display path does: every display follows the server's geometry,
    so a second screen cannot be the way a client escapes the lock, and a
    locked size is the server's own, beyond a client alignment toggle.
    """
    display_id = display_id or "primary"
    logger.debug(f"Resize message for display '{display_id}': {res}")
    if display_id == "primary" and not self.args.enable_resize:
        logger.warning(f"remote resizing disabled, skipping resize to {res}")
        return
    if display_id != "primary" or self.display_clients:
        locked_dims = self._server_locked_dims()
        if locked_dims is not None:
            logger.warning(
                f"Client attempted to resize to {res} but server is in manual resolution mode. "
                f"Using the configured {locked_dims[0]}x{locked_dims[1]} instead."
            )
            w, h = locked_dims
        else:
            dims = parse_resize_dims(res)
            if dims is None:
                logger.error(f"Invalid resize request: {res}")
                return
            w, h = dims
            if self._display_setting(display_id, "force_aligned_resolution"):
                w, h = align_dims_16(w, h)
        if display_id == "primary":
            self._primary_dims = (w, h)
        else:
            entry = self.display_clients.get(display_id)
            if entry is None:
                logger.warning(f"Resize for unknown display '{display_id}' ignored.")
                return
            entry["width"], entry["height"] = w, h
        await self.reconfigure_displays()
        return
    self._primary_dims = None
    await self._resize_primary_display(res)
paramresstr
paramdisplay_idstr
= 'primary'

Returns

None
func_server_locked_dims() -> Optional[Tuple[int, int]]

The geometry an admin-configured manual-resolution lock pins the desktop to, or None when the server sets no lock. Derived on every read from the server settings (never from the client-writable args, whose manual trio is the client's own manual/auto toggle) and from the dimensions startup realized, so the lock cannot drift with client state. The settings layer guarantees positive manual dimensions while the lock is on; its own defaults stand in should one be unusable, so a locked server never falls back to honoring the client's request.

Source Code
def _server_locked_dims(self) -> Optional[Tuple[int, int]]:
    """The geometry an admin-configured manual-resolution lock pins the desktop
    to, or None when the server sets no lock. Derived on every read from the
    server settings (never from the client-writable args, whose manual trio is
    the client's own manual/auto toggle) and from the dimensions startup
    realized, so the lock cannot drift with client state. The settings layer
    guarantees positive manual dimensions while the lock is on; its own
    defaults stand in should one be unusable, so a locked server never
    falls back to honoring the client's request."""
    server_is_manual, _ = self.settings.manual_resolution
    if not server_is_manual:
        return None
    if self._manual_dims:
        return self._manual_dims
    width = int(getattr(self.settings, "manual_width", 0) or 0)
    height = int(getattr(self.settings, "manual_height", 0) or 0)
    if width <= 0:
        width = 1024
    if height <= 0:
        height = 768
    return (width - (width % 2), height - (height % 2))

Returns

typing.Optional[typing.Tuple[int, int]]
func_resize_primary_display(res) -> None

Resize the single (primary-only) display to a client-requested resolution, keep the capture dimensions in sync with what was realized, and tell the client the realized size when it differs.

Only an admin-configured manual-resolution lock blocks client resizes (websockets parity); the client's own manual/auto toggle in args must not gate here, since in client manual mode the chosen resolution arrives through this same path. Idempotent: clients re-assert their resolution on reconnects and settings broadcasts, and re-applying the current size would churn RandR (X11) or restart the capture (Wayland) for nothing; the last request counts as applied too, or a request the realized size differs from (CVT cell alignment) would read as pending forever. On Wayland there is no X server to resize: the screen is grown ahead of the capture restart, the restarted capture resizes the view, the compositor's realized geometry (it may even-mask or refuse the mode) is reconciled and pushed to the client, the screen is fitted to it, and a nested session's own screen is re-sized to the same geometry at the DPI in force.

Source Code
async def _resize_primary_display(self, res: str) -> None:
    """Resize the single (primary-only) display to a client-requested
    resolution, keep the capture dimensions in sync with what was realized,
    and tell the client the realized size when it differs.

    Only an admin-configured manual-resolution lock blocks client resizes
    (websockets parity); the client's own manual/auto toggle in `args`
    must not gate here, since in client manual mode the chosen resolution
    arrives through this same path. Idempotent: clients re-assert their
    resolution on reconnects and settings broadcasts, and re-applying the
    current size would churn RandR (X11) or restart the capture (Wayland)
    for nothing; the last request counts as applied too, or a request the
    realized size differs from (CVT cell alignment) would read as pending
    forever. On Wayland there is no X server to resize: the screen is
    grown ahead of the capture restart, the restarted capture resizes the
    view, the compositor's realized geometry (it may even-mask or refuse
    the mode) is reconciled and pushed to the client, the screen is fitted
    to it, and a nested session's own screen is re-sized to the same
    geometry at the DPI in force.
    """
    if self._server_locked_dims() is not None:
        logger.warning(
            f"Client attempted to resize to {res} but server is in manual resolution mode. Request ignored."
        )
        return
    try:
        dims = parse_resize_dims(res)
        if dims is None:
            logger.error(f"Invalid resize request: {res}. Ignoring")
            if self.media_pipeline:
                self.media_pipeline.last_resize_success = False
            return
        target_w, target_h = dims
        if getattr(self.args, "force_aligned_resolution", False):
            target_w, target_h = align_dims_16(target_w, target_h)

        if (
            self.media_pipeline
            and self.media_pipeline.last_resize_success
            and (
                (self.media_pipeline.width == target_w
                 and self.media_pipeline.height == target_h)
                or self._last_resize_request == (target_w, target_h)
            )
        ):
            logger.debug(f"Redundant resize request for primary to {target_w}x{target_h}. No action.")
            return
        logger.info(f"Resize requested for display 'primary' with resolution: {target_w}x{target_h}")

        if IS_WAYLAND:
            self.media_pipeline.width = target_w
            self.media_pipeline.height = target_h
            # The capture, not the whole pipeline: the session's first request
            # can land while audio is still coming up. An unstarted capture
            # reads the new size when it starts.
            if self.media_pipeline.is_screen_capturing():
                await self._size_wayland_screen(target_w, target_h, grow_only=True)
                await self.media_pipeline.restart_screen_capture()
                await self._push_wayland_realized_geometry("primary", self.media_pipeline)
                await self._size_wayland_screen(
                    self.media_pipeline.width, self.media_pipeline.height)
                # A nested session's screen is its own compositor's, not the
                # capture's: sizing only the capture leaves its applications
                # laid out for the size the last DPI change realized.
                if self.input_handler is not None:
                    await self.input_handler.realize_wayland_dpi(
                        getattr(self, "_last_applied_dpi", None)
                        or getattr(settings, "scaling_dpi", 96) or 96,
                        "primary",
                        (self.media_pipeline.width, self.media_pipeline.height))
            self.media_pipeline.last_resize_success = True
            self._last_resize_request = (target_w, target_h)
            logger.info(
                f"Wayland capture resized to {self.media_pipeline.width}x{self.media_pipeline.height}"
                f" (requested {target_w}x{target_h})"
            )
            return

        realized = await resize_display(f"{target_w}x{target_h}")
        if realized:
            realized_w, realized_h = realized
            if (realized_w, realized_h) != (target_w, target_h):
                logger.info(
                    f"resize_display realized {realized_w}x{realized_h} for request {target_w}x{target_h}"
                )
            else:
                logger.debug(f"resize_display('{target_w}x{target_h}') reported success")
            # A zero-size region re-reads the live root now and keeps root-follow;
            # the auto-adjust poll trails ~30 frames, leaving new bands out of frame.
            capture_module = getattr(self.media_pipeline, "capture_module", None)
            if capture_module is not None:
                try:
                    await asyncio.to_thread(
                        capture_module.update_capture_region, 0, 0, 0, 0
                    )
                except Exception as e:
                    logger.warning(f"Capture re-follow after resize failed: {e}")
            self.media_pipeline.width = realized_w
            self.media_pipeline.height = realized_h
            self.media_pipeline.last_resize_success = True
            self._last_resize_request = (target_w, target_h)
            if self.rtc_app is not None:
                self.rtc_app.send_remote_resolution(f"{realized_w}x{realized_h}", "primary")
        else:
            logger.error(
                f"resize_display('{target_w}x{target_h}') reported failure"
            )
            self.media_pipeline.last_resize_success = False

    except Exception as e:
        logger.error(
            f"Error during resize handling for '{res}': {e}", exc_info=True
        )
        if self.media_pipeline:
            self.media_pipeline.last_resize_success = False
paramresstr

Returns

None
funcrequest_idr_for_display(display_id='primary', unless_pending=False) -> None

Schedule a dynamic IDR frame on the display's encoder, throttled by a per-display floor (websockets REQUEST_KEYFRAME parity).

Any number of viewers share one encoder, and an unthrottled data-channel request or PLI storm would let a single client force keyframe bursts for every consumer. A request landing inside the floor is satisfied by the IDR the previous request already scheduled.

Source Code
async def request_idr_for_display(self, display_id: str = "primary",
                                  unless_pending: bool = False) -> None:
    """Schedule a dynamic IDR frame on the display's encoder, throttled by a
    per-display floor (websockets REQUEST_KEYFRAME parity).

    Any number of viewers share one encoder, and an unthrottled
    data-channel request or PLI storm would let a single client force
    keyframe bursts for every consumer. A request landing inside the floor
    is satisfied by the IDR the previous request already scheduled.

    Args:
        unless_pending: Hold the request only while that IDR has yet to be
            captured, whatever the floor says: a pacer's GOP reset needs a
            keyframe from after the reset, and one captured before it
            leaves the stream dead until the pacer's resurrect timeout.
    """
    display_id = display_id or "primary"
    pipeline = self.display_pipelines.get(display_id)
    if pipeline is None:
        return
    now = time.monotonic()
    if unless_pending:
        if pipeline.idr_pending:
            return
    elif now - self._last_idr_request_times.get(display_id, 0.0) < IDR_REQUEST_FLOOR_S:
        return
    self._last_idr_request_times[display_id] = now
    await pipeline.dynamic_idr_frame()
paramdisplay_idstr
= 'primary'
paramunless_pendingbool
= False

Hold the request only while that IDR has yet to be captured, whatever the floor says: a pacer's GOP reset needs a keyframe from after the reset, and one captured before it leaves the stream dead until the pacer's resurrect timeout.

Returns

None
funcinvalidate_reference_for_display(display_id, frame_id) -> None

Tell the display's encoder a peer lost frame_id, so the frames after it stop predicting from it (websockets LOST_FRAME parity). Logged once per display per five seconds with the count of the rest, since loss comes in bursts.

Source Code
def invalidate_reference_for_display(self, display_id: str, frame_id: int) -> None:
    """Tell the display's encoder a peer lost `frame_id`, so the frames after it stop
    predicting from it (websockets LOST_FRAME parity). Logged once per display per
    five seconds with the count of the rest, since loss comes in bursts."""
    display_id = display_id or "primary"
    pipeline = self.display_pipelines.get(display_id)
    if pipeline is None:
        return
    pipeline.invalidate_reference(frame_id)
    now = time.monotonic()
    last, more = self._invalidation_log.get(display_id, (0.0, 0))
    if now - last >= 5.0:
        suffix = f" (+{more} more in the last 5 s)" if more else ""
        logger.info(f"Display '{display_id}': frame {frame_id} lost by a peer; the encoder predicts past it.{suffix}")
        self._invalidation_log[display_id] = (now, 0)
    else:
        self._invalidation_log[display_id] = (last, more + 1)
paramdisplay_idstr
paramframe_idint

Returns

None
func_provision_webrtc_virtual_mic() -> None

Bring up the SelkiesVirtualMic once for the WebRTC transport (shared provisioning with the websockets 0x02 path). Called from the per-peer mic playback start on the first mic packet; the lock + flag make concurrent first-packet calls across peers provision exactly once, and the shared helper reuses a source the websockets path already loaded rather than double-loading it.

Source Code
async def _provision_webrtc_virtual_mic(self) -> None:
    """Bring up the SelkiesVirtualMic once for the WebRTC transport (shared
    provisioning with the websockets 0x02 path). Called from the per-peer mic
    playback start on the first mic packet; the lock + flag make concurrent
    first-packet calls across peers provision exactly once, and the shared
    helper reuses a source the websockets path already loaded rather than
    double-loading it."""
    if self._mic_provisioned:
        return
    async with self._mic_provision_lock:
        if self._mic_provisioned:
            return
        if self._mic_control is None:
            self._mic_control = AudioControl("selkies-webrtc-mic")
        audio_device_name = getattr(self.media_pipeline, "audio_device_name", None)
        is_capturing = bool(getattr(self.media_pipeline, "_is_pcmflux_capturing", False))
        self._mic_module_index, self._mic_module_owned = (
            await self._mic_control.ensure_virtual_microphone(audio_device_name, is_capturing)
        )
        self._mic_provisioned = self._mic_module_index is not None

Returns

None
func_teardown_webrtc_virtual_mic() -> None

Unload the virtual-source module (only if this path loaded it) and release the mic control connection on shutdown.

Source Code
async def _teardown_webrtc_virtual_mic(self) -> None:
    """Unload the virtual-source module (only if this path loaded it) and
    release the mic control connection on shutdown."""
    control = self._mic_control
    self._mic_control = None
    if control is None:
        return
    if self._mic_module_index is not None and self._mic_module_owned:
        logger.info(f"Unloading WebRTC virtual mic module {self._mic_module_index}.")
        await control.unload_module(self._mic_module_index)
    self._mic_module_index = None
    self._mic_module_owned = False
    self._mic_provisioned = False
    await control.aclose()

Returns

None
funcstart_display_media(display_id) -> None

A display's consumer connected: the primary starts its pipeline right away; a secondary waits for its dimensions (the client's first resize message), which trigger the layout pass that creates its pipeline.

A consumer reclaiming the primary cancels a pending grace stop, and start_media_pipeline is idempotent, so a controller tab reload that reconnects inside the grace reuses the still-warm capture. The pipeline starts only the captures its consumers receive: a peer whose session policy starts video or audio off is registered paused, and a warm pipeline is settled against the consumer set afterwards, so a paused reconnect stops what it no longer receives. A Wayland start only enqueues a compositor command, so its real outcome is read back through the same barrier the secondaries use: a pipeline that believes it is running with no live capture would leave the page waiting on frames that never arrive, so it is stopped and logged and the next consumer retries (this also surfaces host death, where reap_dead_host flips is_capturing off). The pipeline start is what establishes the host session in host-capture mode, so the host's output count — and the second-screen availability announced on channel open — can first become known here and is re-published.

Source Code
async def start_display_media(self, display_id: str) -> None:
    """A display's consumer connected: the primary starts its pipeline right
    away; a secondary waits for its dimensions (the client's first resize
    message), which trigger the layout pass that creates its pipeline.

    A consumer reclaiming the primary cancels a pending grace stop, and
    `start_media_pipeline` is idempotent, so a controller tab reload that
    reconnects inside the grace reuses the still-warm capture. The
    pipeline starts only the captures its consumers receive: a peer whose
    session policy starts video or audio off is registered paused, and a
    warm pipeline is settled against the consumer set afterwards, so a
    paused reconnect stops what it no longer receives. A Wayland start
    only enqueues a compositor command, so its real outcome is read back
    through the same barrier the secondaries use: a pipeline that
    believes it is running with no live capture would leave the page
    waiting on frames that never arrive, so it is stopped and logged and
    the next consumer retries (this also surfaces host death, where
    `reap_dead_host` flips `is_capturing` off). The pipeline start is what
    establishes the host session in host-capture mode, so the host's
    output count — and the second-screen availability announced on
    channel open — can first become known here and is re-published.
    """
    if display_id == "primary" and self.media_pipeline:
        self._cancel_primary_stop_grace()
        consumers = self._display_consumers("primary")
        video_wanted = any(not p.get("video_paused", False) for p in consumers) or not consumers
        audio_wanted = any(not p.get("audio_paused", False) for p in consumers) or not consumers
        await self.media_pipeline.start_media_pipeline(video=video_wanted, audio=audio_wanted)
        await self._settle_primary_consumers()
        if (IS_WAYLAND and video_wanted and self.media_pipeline.is_media_pipeline_running()
                and not await self._wayland_capture_live("primary", self.media_pipeline)):
            last_error = self._wayland_capture_last_error(self.media_pipeline, "primary")
            logger.error(
                "Primary Wayland capture is not live after start"
                + (f": {last_error}." if last_error else "."))
            await self.media_pipeline.stop_media_pipeline()
            return
        caveat = (self._wayland_capture_last_error(self.media_pipeline, "primary")
                  if IS_WAYLAND else None)
        if caveat:
            logger.warning(f"Primary Wayland capture started with a caveat: {caveat}")
        if await self._refresh_second_screen_capacity() and self.rtc_app:
            self.rtc_app.send_media_data_over_channel(
                "server_settings", self._server_settings_payload()
            )
paramdisplay_idstr

Returns

None
funcstop_display_media(display_id) -> None

Release a display's pipeline: the primary's stop is deferred by a reconnect grace (a controller tab reload reconnects within a second or two and reuses the warm capture, and viewers/display2 keep streaming throughout — websockets _teardown_if_unclaimed parity); a secondary is fully unregistered and the desktop re-laid-out at once.

Source Code
async def stop_display_media(self, display_id: str) -> None:
    """Release a display's pipeline: the primary's stop is deferred by a
    reconnect grace (a controller tab reload reconnects within a second or
    two and reuses the warm capture, and viewers/display2 keep streaming
    throughout — websockets _teardown_if_unclaimed parity); a secondary is
    fully unregistered and the desktop re-laid-out at once."""
    if display_id == "primary":
        self._schedule_primary_stop_grace()
        return
    async with self._display_lock:
        pipeline = self.display_pipelines.pop(display_id, None)
        self.display_clients.pop(display_id, None)
        self._display_dpis.pop(display_id, None)
        self.display_layouts.pop(display_id, None)
        self._client_scales.pop(display_id, None)
        self._client_stream_boxes.pop(display_id, None)
        if pipeline is not None:
            await pipeline.stop_media_pipeline()
    await self.reconfigure_displays()
paramdisplay_idstr

Returns

None
func_cancel_primary_stop_grace() -> None

Drop a pending deferred primary-capture stop: a consumer reclaimed the display before the grace elapsed.

Source Code
def _cancel_primary_stop_grace(self) -> None:
    """Drop a pending deferred primary-capture stop: a consumer reclaimed
    the display before the grace elapsed."""
    task = self._primary_stop_grace_task
    self._primary_stop_grace_task = None
    if task is not None and not task.done():
        task.cancel()

Returns

None
func_schedule_primary_stop_grace() -> None

Stop the primary capture after RECONNECT_GRACE_S unless a consumer reclaims it first. A page reload drops and re-adds its peer within the window, so tearing the capture down immediately would black out a reconnecting controller (and stall the audio fan-out the viewers share) for no reason; if nobody reclaims the primary, the stop runs after the grace. At most one grace is pending at a time.

Source Code
def _schedule_primary_stop_grace(self) -> None:
    """Stop the primary capture after RECONNECT_GRACE_S unless a consumer
    reclaims it first. A page reload drops and re-adds its peer within the
    window, so tearing the capture down immediately would black out a
    reconnecting controller (and stall the audio fan-out the viewers share)
    for no reason; if nobody reclaims the primary, the stop runs after the
    grace. At most one grace is pending at a time."""
    if self._primary_stop_grace_task is not None and not self._primary_stop_grace_task.done():
        return
    if self.media_pipeline is None or not self.media_pipeline.is_media_pipeline_running():
        return

    async def _stop_after_grace() -> None:
        """Stop the primary unless reclaimed. No lock: the event loop
        serializes start/stop with this coroutine's resume."""
        try:
            await asyncio.sleep(self.RECONNECT_GRACE_S)
        except asyncio.CancelledError:
            return
        self._primary_stop_grace_task = None
        if self._primary_display_has_consumer():
            logger.info("Primary reclaimed within the grace; capture kept.")
            return
        if self.media_pipeline is not None:
            logger.info("Primary unclaimed after the grace; stopping its capture.")
            await self.media_pipeline.stop_media_pipeline()

    self._primary_stop_grace_task = asyncio.create_task(_stop_after_grace())

Returns

None
func_primary_display_has_consumer() -> bool

Whether any peer (controller or viewer) still consumes the primary.

Source Code
def _primary_display_has_consumer(self) -> bool:
    """Whether any peer (controller or viewer) still consumes the primary."""
    if self.rtc_app is None:
        return False
    return any(
        (p.get("display_id") or "primary") == "primary"
        for p in self.rtc_app.peer_connections.values()
    )

Returns

bool
func_wayland_capture_handle() -> Optional[Any]

A pixelflux handle for compositor output management (any ScreenCapture reaches the shared Wayland backend); prefers the primary pipeline's live capture module.

Source Code
def _wayland_capture_handle(self) -> Optional[Any]:
    """A pixelflux handle for compositor output management (any ScreenCapture
    reaches the shared Wayland backend); prefers the primary pipeline's live
    capture module."""
    module = getattr(self.media_pipeline, "capture_module", None)
    if module is not None:
        return module
    if PixelfluxScreenCapture is None:
        return None
    if self._wayland_ctl_module is None:
        self._wayland_ctl_module = PixelfluxScreenCapture()
    return self._wayland_ctl_module

Returns

typing.Optional[typing.Any]
func_size_wayland_screen(width, height, grow_only=False) -> None

Size the primary's screen (output 0) to its display rectangle.

The primary's capture binds to the view covering that screen, and a capture start sizes the view alone, which the screen must already hold: so the screen is grown ahead of the capture restart and fitted to the rectangle once the capture carries it -- an early shrink is refused by the compositor, which leaves no view hanging outside its screen.

Source Code
async def _size_wayland_screen(self, width: int, height: int,
                               grow_only: bool = False) -> None:
    """Size the primary's screen (output 0) to its display rectangle.

    The primary's capture binds to the view covering that screen, and a
    capture start sizes the view alone, which the screen must already hold:
    so the screen is grown ahead of the capture restart and fitted to the
    rectangle once the capture carries it -- an early shrink is refused by
    the compositor, which leaves no view hanging outside its screen."""
    module = self._wayland_capture_handle()
    if module is None or width <= 0 or height <= 0:
        return
    scale = float(getattr(self.media_pipeline, "scale", 1.0) or 1.0)
    try:
        if grow_only:
            outputs = {o[0]: o for o in await asyncio.to_thread(module.list_outputs)}
            screen = outputs.get(WAYLAND_SCREEN_OUTPUT_ID)
            if screen:
                width, height = max(width, screen[3]), max(height, screen[4])
        ok = await asyncio.to_thread(
            module.resize_output, WAYLAND_SCREEN_OUTPUT_ID, width, height, scale)
        if not ok:
            logger.warning(f"Wayland screen resize to {width}x{height} refused.")
    except Exception as e:
        logger.error(f"Wayland resize_output failed: {e}")
paramwidthint
paramheightint
paramgrow_onlybool
= False

Returns

None
func_destroy_wayland_secondary_outputs(keep_did=None) -> None

Retire every secondary display's compositor screen except keep_did's.

The primary's screen (output 0) and the view its capture binds to always persist -- the primary is the session, not an extension of it.

Source Code
async def _destroy_wayland_secondary_outputs(self, keep_did: Optional[str] = None) -> None:
    """Retire every secondary display's compositor screen except `keep_did`'s.

    The primary's screen (output 0) and the view its capture binds to
    always persist -- the primary is the session, not an extension of it.
    """
    module = self._wayland_capture_handle()
    if module is None:
        return
    keep = {WAYLAND_SCREEN_OUTPUT_ID, wayland_output_id("primary")}
    if keep_did:
        keep.add(wayland_output_id(keep_did))
    try:
        for out in await asyncio.to_thread(module.list_outputs):
            if out[0] not in keep:
                await asyncio.to_thread(module.destroy_output, out[0])
    except Exception as e:
        logger.warning(f"Wayland output teardown failed: {e}")
    if self.input_handler:
        # The session keeps a screen per surviving display: the kept
        # secondary's while it is being (re)placed, only the primary's on
        # teardown, where a removed screen's windows return to the primary.
        await self.input_handler.ensure_session_screens(
            [keep_did] if keep_did else [])
        # Which of the session's own screens a capture drives changed.
        self.input_handler.resync_session_screens()
paramkeep_didOptional[str]
= None

Returns

None
func_apply_wayland_extension(did, layouts) -> bool

Realize the extended layout as compositor screens, BEFORE the secondary's pipeline binds a capture — the Wayland counterpart of apply_extended_layout.

Every display is a screen of the session compositor's own, so it lays its windows and panels out per monitor. The primary (output 0) MOVES to its layout offset ('left'/'up' place it off-origin); a secondary reposition is a destroy + recreate (its capture rebinds on the pipeline restart that follows), destroyed before the primary moves so the rectangles never overlap. A secondary that keeps its origin but shrinks gives the room up in place ahead of the move, and grows into the room the move leaves on the same restart; a retained output the compositor still finds in the primary's way is recreated after all.

Source Code
async def _apply_wayland_extension(self, did: str, layouts: Dict[str, Dict[str, int]]) -> bool:
    """Realize the extended layout as compositor screens, BEFORE the
    secondary's pipeline binds a capture — the Wayland counterpart of
    apply_extended_layout.

    Every display is a screen of the session compositor's own, so it lays
    its windows and panels out per monitor. The primary (output 0) MOVES to
    its layout offset ('left'/'up' place it off-origin); a secondary
    reposition is a destroy + recreate (its capture rebinds on the pipeline
    restart that follows), destroyed before the primary moves so the
    rectangles never overlap. A secondary that keeps its origin but shrinks
    gives the room up in place ahead of the move, and grows into the room
    the move leaves on the same restart; a retained output the compositor
    still finds in the primary's way is recreated after all.

    Returns:
        False when the output cannot be created or the primary cannot move
        (the caller drops the display).
    """
    module = self._wayland_capture_handle()
    if module is None:
        return False
    oid = wayland_output_id(did)
    s = layouts[did]
    dpi = self._display_dpi(did)
    scale = float(dpi) / 96.0
    try:
        outputs = {o[0]: o for o in await asyncio.to_thread(module.list_outputs)}
    except Exception as e:
        logger.error(f"Wayland list_outputs failed: {e}")
        outputs = {}
    await self._destroy_wayland_secondary_outputs(keep_did=did)
    existing = outputs.get(oid)
    if existing is not None and (existing[1], existing[2]) != (s["x"], s["y"]):
        logger.info(f"Wayland output {oid} moves to +{s['x']}+{s['y']}; recreating it.")
        await asyncio.to_thread(module.destroy_output, oid)
        existing = None
    elif (existing is not None
          and not await wayland_shrink_output(module, existing, s["w"], s["h"])):
        logger.info(f"Wayland output {oid} cannot shrink to {s['w']}x{s['h']}; recreating it.")
        await asyncio.to_thread(module.destroy_output, oid)
        existing = None
    p = layouts.get("primary") or {"x": 0, "y": 0}
    existing0 = outputs.get(WAYLAND_SCREEN_OUTPUT_ID)
    current0 = (existing0[1], existing0[2]) if existing0 is not None else (0, 0)
    if (p["x"], p["y"]) != current0:
        moved = await wayland_reposition_primary(module, p["x"], p["y"])
        if not moved and existing is not None:
            logger.info(f"Wayland output {oid} blocks the primary's move; recreating it.")
            await asyncio.to_thread(module.destroy_output, oid)
            existing = None
            moved = await wayland_reposition_primary(module, p["x"], p["y"])
        if not moved:
            return False
    if existing is not None:
        return True
    pw, ph = p.get("w"), p.get("h")
    if (existing0 is not None and pw and ph
            and (pw < existing0[3] or ph < existing0[4])):
        # The secondary drops into the room a shrinking primary frees, and the
        # compositor refuses an output overlapping the primary's rectangle, as
        # it refuses a screen too small for the live view its capture holds:
        # the capture takes the new rectangle, then the screen gives the room
        # up, before the secondary is placed.
        if (self.media_pipeline.width, self.media_pipeline.height) != (pw, ph):
            await self.media_pipeline.update_capture_region(p["x"], p["y"], pw, ph)
            await self._push_wayland_realized_geometry("primary", self.media_pipeline)
        if not await asyncio.to_thread(
                module.resize_output, WAYLAND_SCREEN_OUTPUT_ID, pw, ph, existing0[5]):
            logger.warning(f"Wayland screen shrink to {pw}x{ph} refused.")
    if self.input_handler:
        # The screen this display owns, grown just ahead of the output
        # that adopts its host window, then given the display's own DPI;
        # what the session leaves is this output's capture scale.
        await self.input_handler.ensure_session_screen(
            did, size=(s["w"], s["h"]), scale=scale)
        scale = await self.input_handler.realize_wayland_dpi(dpi, did, (s["w"], s["h"]))
    try:
        created = bool(await asyncio.to_thread(
            module.create_output, oid, s["w"], s["h"], s["x"], s["y"], scale))
    except Exception as e:
        logger.error(f"Wayland create_output {oid} failed: {e}")
        return False
    if created and self.input_handler:
        # Which of the session's own screens a capture drives changed.
        self.input_handler.resync_session_screens()
    return created
paramdidstr
paramlayoutsDict[str, Dict[str, int]]

Returns

bool

False when the output cannot be created or the primary cannot move

func_wayland_capture_live(did, pipeline) -> bool

Whether the display's capture really runs in the compositor. The geometry read is a barrier: it is answered only after the queued capture start finished, so is_capturing is authoritative afterwards.

Source Code
async def _wayland_capture_live(self, did: str, pipeline: MediaPipelinePixel) -> bool:
    """Whether the display's capture really runs in the compositor. The
    geometry read is a barrier: it is answered only after the queued capture
    start finished, so is_capturing is authoritative afterwards."""
    module = getattr(pipeline, "capture_module", None)
    if module is None:
        return False
    try:
        await asyncio.to_thread(module.get_realized_geometry, wayland_output_id(did))
        return bool(module.is_capturing)
    except Exception:
        return False
paramdidstr
parampipelineMediaPipelinePixel

Returns

bool
func_wayland_capture_last_error(pipeline, did) -> Optional[str]

The reason a display's Wayland capture failed, or a caveat a live one came up with (encoder fell back to CPU, host connect refused), or None. Read straight from capture_state (no barrier); the caller ensures ordering.

Source Code
def _wayland_capture_last_error(
    self, pipeline: Optional[MediaPipelinePixel], did: str
) -> Optional[str]:
    """The reason a display's Wayland capture failed, or a caveat a live one came up
    with (encoder fell back to CPU, host connect refused), or None. Read straight from
    ``capture_state`` (no barrier); the caller ensures ordering."""
    module = getattr(pipeline, "capture_module", None) if pipeline is not None else None
    if module is None:
        return None
    try:
        _state, last_error = module.capture_state(wayland_output_id(did))
        return last_error
    except Exception:
        return None
parampipelineOptional[MediaPipelinePixel]
paramdidstr

Returns

typing.Optional[str]
func_realized_wayland_dims(did) -> Optional[Tuple[int, int]]

The (width, height) the compositor currently has for this display's output, or None when it cannot be read.

Source Code
async def _realized_wayland_dims(self, did: str) -> Optional[Tuple[int, int]]:
    """The ``(width, height)`` the compositor currently has for this
    display's output, or None when it cannot be read."""
    if not IS_WAYLAND:
        return None
    pipeline = (self.media_pipeline if did == "primary"
                else self.display_pipelines.get(did))
    module = getattr(pipeline, "capture_module", None)
    if module is None:
        return None
    try:
        geom = await asyncio.to_thread(
            module.get_realized_geometry, wayland_output_id(did))
    except Exception as e:
        logger.warning(f"Wayland realized-geometry read failed for '{did}': {e}")
        return None
    if geom is None:
        logger.warning(f"Wayland realized-geometry read for '{did}' timed out; size unknown.")
        return None
    w, h, _scale = geom
    return (w, h) if w > 0 and h > 0 else None
paramdidstr

Returns

typing.Optional[typing.Tuple[int, int]]
func_push_wayland_realized_geometry(did, pipeline) -> None

Read what the pixelflux compositor actually realized on this display's output after a capture (re)start (it may even-mask dimensions or keep the old mode on a GBM allocation failure), fold it into the pipeline/layout state the input math offsets against, and push the corrected size to the clients over the existing system resolution message — the WR counterpart of the WS realized clamp + broadcast. The stream itself re-negotiates through the encoder (the track's intrinsic size IS the realized resolution); this closes the control-plane loop. The read is also a barrier: the compositor answers only after the queued capture (re)start finished. The push is unconditional (idempotent, WS-broadcast parity: the client's request may have been snapped by sanitization before the pipeline saw it) and scoped to this display's channels so a secondary's size never rescales the primary page.

Source Code
async def _push_wayland_realized_geometry(
    self, did: str, pipeline: Optional[MediaPipelinePixel]
) -> None:
    """Read what the pixelflux compositor actually realized on this
    display's output after a capture (re)start (it may even-mask dimensions
    or keep the old mode on a GBM allocation failure), fold it into the
    pipeline/layout state the input math offsets against, and push the
    corrected size to the clients over the existing system resolution
    message — the WR counterpart of the WS realized clamp + broadcast. The
    stream itself re-negotiates through the encoder (the track's intrinsic
    size IS the realized resolution); this closes the control-plane loop.
    The read is also a barrier: the compositor answers only after the
    queued capture (re)start finished. The push is unconditional
    (idempotent, WS-broadcast parity: the client's request may have been
    snapped by sanitization before the pipeline saw it) and scoped to this
    display's channels so a secondary's size never rescales the primary
    page."""
    if not IS_WAYLAND or pipeline is None:
        return
    module = getattr(pipeline, "capture_module", None)
    if module is None:
        return
    try:
        geom = await asyncio.to_thread(
            module.get_realized_geometry, wayland_output_id(did))
    except Exception as e:
        logger.warning(f"Wayland realized-geometry read failed for '{did}': {e}")
        return
    if geom is None:
        # A timeout is unknown geometry, not "nothing to reconcile".
        logger.warning(f"Wayland realized-geometry read for '{did}' timed out; state left unreconciled.")
        return
    w, h, scale = geom
    if w <= 0 or h <= 0:
        return
    pipeline.width, pipeline.height = w, h
    if did == "primary":
        if self._primary_dims is not None:
            self._primary_dims = (w, h)
    else:
        entry = self.display_clients.get(did)
        if entry is not None:
            entry["width"], entry["height"] = w, h
    layout = self.display_layouts.get(did)
    if layout is not None:
        layout["w"], layout["h"] = w, h
    logger.info(f"Wayland realized geometry for '{did}': {w}x{h} @ scale {scale}")
    if self.rtc_app is not None:
        self.rtc_app.send_remote_resolution(f"{w}x{h}", did)
paramdidstr
parampipelineOptional[MediaPipelinePixel]

Returns

None
func_apply_wayland_cursor_size(dpi_value) -> None

Wayland counterpart of the X11 per-DPI cursor resize: the compositor reloads its theme cursor (composited overlay and named-cursor delivery both re-render) at the DPI-scaled size, live, no capture restart.

Source Code
async def _apply_wayland_cursor_size(self, dpi_value: float) -> None:
    """Wayland counterpart of the X11 per-DPI cursor resize: the compositor
    reloads its theme cursor (composited overlay and named-cursor delivery
    both re-render) at the DPI-scaled size, live, no capture restart."""
    if CURSOR_SIZE is None:
        return
    module = self._wayland_capture_handle()
    if module is None:
        return
    size = cursor_size_for_dpi(dpi_value, CURSOR_SIZE)
    try:
        if await asyncio.to_thread(module.set_cursor_size, size):
            logger.debug(f"Wayland cursor size set to {size} (DPI {dpi_value}).")
        else:
            logger.warning(f"Wayland compositor refused cursor size {size}.")
    except Exception as e:
        logger.warning(f"Wayland cursor resize failed: {e}")
paramdpi_valuefloat

Returns

None
func_display_consumers(display_id) -> List[Dict[str, Any]]

Registered peers (controller + viewers) consuming this display's stream.

Source Code
def _display_consumers(self, display_id: str) -> List[Dict[str, Any]]:
    """Registered peers (controller + viewers) consuming this display's
    stream."""
    if self.rtc_app is None:
        return []
    return [
        p for p in self.rtc_app.peer_connections.values()
        if (p.get("display_id") or "primary") == display_id
    ]
paramdisplay_idstr

Returns

typing.List[typing.Dict[str, typing.Any]]
funchandle_peer_gone(peer_id, peer=None) -> None

Release the input a departing peer may still be holding, matching the websockets disconnect cleanup. Gamepad slots are per-connection, so they are always released. Held keys and pointer buttons are one global desktop state instead: they are force-released only when the departing peer could drive input and no input-capable peer is left, so a viewer (or a second display's peer) leaving never drops the controller's held keys or its in-flight drag. A controller that vanishes while others remain is covered by the input handler's heartbeat stale-sweep.

Source Code
async def handle_peer_gone(
    self, peer_id: str, peer: Optional[Dict[str, Any]] = None
) -> None:
    """Release the input a departing peer may still be holding, matching the
    websockets disconnect cleanup. Gamepad slots are per-connection, so they
    are always released. Held keys and pointer buttons are one global desktop
    state instead: they are force-released only when the departing peer could
    drive input and no input-capable peer is left, so a viewer (or a second
    display's peer) leaving never drops the controller's held keys or its
    in-flight drag. A controller that vanishes while others remain is covered
    by the input handler's heartbeat stale-sweep."""
    if self.input_handler is None:
        return
    try:
        await self.input_handler.release_gamepads_for_conn(peer_id)
    except Exception as e:
        logger.warning(f"Gamepad release for departed peer {peer_id} failed: {e}")
    if self.rtc_app is None or not self.rtc_app.peer_holds_input_authority(peer):
        return
    if (peer.get("display_id") or "primary") != "primary":
        # The departing peer is already out of peer_connections: survivors only.
        for survivor in list(self.rtc_app.peer_connections.values()):
            if self.rtc_app.peer_holds_input_authority(survivor):
                return
    for release in (self.input_handler.release_mouse_buttons,
                    self.input_handler.reset_keyboard):
        try:
            await release()
        except Exception as e:
            logger.warning(f"Input release for departed peer {peer_id} failed: {e}")
parampeer_idstr
parampeerOptional[Dict[str, Any]]
= None

Returns

None
funchandle_video_consumer_active(peer_id, display_id, active) -> None

Tab-visibility pause/resume for ONE peer (data-channel STOP_VIDEO / START_VIDEO, websockets parity). The peer's own RTP sender gates its delivery; the shared capture only stops once EVERY consumer of the display (controller and viewers alike) is paused. A resuming peer always gets an IDR — its decoder needs a resync even when the capture kept running for other consumers — with PLI as the fallback.

Source Code
async def handle_video_consumer_active(self, peer_id: str, display_id: str, active: bool) -> None:
    """Tab-visibility pause/resume for ONE peer (data-channel STOP_VIDEO /
    START_VIDEO, websockets parity). The peer's own RTP sender gates its
    delivery; the shared capture only stops once EVERY consumer of the
    display (controller and viewers alike) is paused. A resuming peer always
    gets an IDR — its decoder needs a resync even when the capture kept
    running for other consumers — with PLI as the fallback."""
    display_id = display_id or "primary"
    peer = self.rtc_app.peer_connections.get(peer_id) if self.rtc_app else None
    if peer is None:
        return
    peer["video_paused"] = not active
    sender = peer.get("video_sender")
    if sender is not None:
        # A disabled sender keeps draining its relay proxy but sends no RTP,
        # so only this peer's stream stalls.
        sender._enabled = active
    pipeline = self.display_pipelines.get(display_id)
    if pipeline is None:
        return
    if active:
        await self._resume_display_capture(display_id, pipeline,
                                           "consumer resume", idr_always=True)
    elif all(p.get("video_paused", False) for p in self._display_consumers(display_id)):
        if await pipeline.pause_screen_capture():
            logger.info(
                f"All consumers of display '{display_id}' are paused; capture stopped."
            )
parampeer_idstr
paramdisplay_idstr
paramactivebool

Returns

None
funchandle_audio_consumer_active(peer_id, active) -> None

The side menu's audio toggle for ONE peer (data-channel STOP_AUDIO / START_AUDIO). The peer's own RTP sender gates its delivery, so a late joiner is unaffected; the shared pcmflux capture stops once no peer receives audio and restarts for the first that asks again. Audio lives on the primary display, whatever display the peer renders.

Source Code
async def handle_audio_consumer_active(self, peer_id: str, active: bool) -> None:
    """The side menu's audio toggle for ONE peer (data-channel STOP_AUDIO /
    START_AUDIO). The peer's own RTP sender gates its delivery, so a
    late joiner is unaffected; the shared pcmflux capture stops once no
    peer receives audio and restarts for the first that asks again. Audio
    lives on the primary display, whatever display the peer renders."""
    peer = self.rtc_app.peer_connections.get(peer_id) if self.rtc_app else None
    if peer is None:
        return
    peer["audio_paused"] = not active
    sender = peer.get("audio_sender")
    if sender is not None:
        sender._enabled = active
    await self._settle_primary_audio()
parampeer_idstr
paramactivebool

Returns

None
func_settle_primary_audio() -> None

Pause the primary's audio capture once every peer is audio-paused, and resume it while any peer receives audio; a no-op on a pipeline that is not running (start_display_media decides what starts).

Source Code
async def _settle_primary_audio(self) -> None:
    """Pause the primary's audio capture once every peer is audio-paused,
    and resume it while any peer receives audio; a no-op on a pipeline
    that is not running (start_display_media decides what starts)."""
    pipeline = self.media_pipeline
    if pipeline is None or not pipeline.is_media_pipeline_running():
        return
    consumers = self._display_consumers("primary")
    if consumers and all(p.get("audio_paused", False) for p in consumers):
        if await pipeline.pause_audio_capture():
            logger.info("No peer receives audio; audio capture stopped.")
    elif consumers and await pipeline.resume_audio_capture():
        logger.info("Audio capture restarted for a peer that receives audio.")

Returns

None
func_settle_primary_consumers() -> None

Apply the all-paused rule to both of the primary's captures after a pipeline start that may have found them warm.

Source Code
async def _settle_primary_consumers(self) -> None:
    """Apply the all-paused rule to both of the primary's captures after
    a pipeline start that may have found them warm."""
    pipeline = self.display_pipelines.get("primary")
    if pipeline is not None:
        consumers = self._display_consumers("primary")
        if consumers and all(p.get("video_paused", False) for p in consumers):
            if await pipeline.pause_screen_capture():
                logger.info("No peer receives video; capture stopped.")
    await self._settle_primary_audio()

Returns

None
func_close_peer_signaling_ws(peer_id, code, message) -> None

Fatal verdict on ONE peer's signaling socket (websockets KILL parity); bounded so a wedged socket cannot stall the caller.

Source Code
async def _close_peer_signaling_ws(self, peer_id: str, code: int, message: bytes) -> None:
    """Fatal verdict on ONE peer's signaling socket (websockets KILL parity);
    bounded so a wedged socket cannot stall the caller."""
    if self.peer_manager is None:
        return
    async with self.peer_manager.lock:
        peer = self.peer_manager.peers.get(peer_id)
        peer_ws = getattr(peer, "ws", None) if peer is not None else None
    if peer_ws is not None and not peer_ws.closed:
        try:
            await asyncio.wait_for(peer_ws.close(code=code, message=message), timeout=2.0)
        except Exception:
            pass
parampeer_idstr
paramcodeint
parammessagebytes

Returns

None
funcreconcile_webrtc_peers() -> None

Token-update reconciliation for LIVE WebRTC peers (websockets reconcile_clients parity): a revoked or role-changed token closes the peer (signaling verdict 4002 + pipeline stop); an mk-token handoff pushes the new input verdict to every surviving peer over its data channel, controllers included (a handoff strips their authority too). Per-message input authority already reads the live store — this covers the media stream and the client-side grant, which otherwise persist until the peer disconnects itself. A slot-only change keeps the peer but is pushed as a role_update (websockets ROLE_UPDATE parity): the gamepad slot mapping lives client-side and would silently desync.

Source Code
async def reconcile_webrtc_peers(self) -> None:
    """Token-update reconciliation for LIVE WebRTC peers (websockets
    reconcile_clients parity): a revoked or role-changed token closes the
    peer (signaling verdict 4002 + pipeline stop); an mk-token handoff
    pushes the new input verdict to every surviving peer over its data
    channel, controllers included (a handoff strips their authority too).
    Per-message input authority already reads the live store — this covers
    the media stream and the client-side grant, which otherwise persist
    until the peer disconnects itself. A slot-only change keeps the peer
    but is pushed as a role_update (websockets ROLE_UPDATE parity): the
    gamepad slot mapping lives client-side and would silently desync."""
    if self.rtc_app is None:
        return
    tokens, mk = current_session_tokens()
    for peer_id, peer in list(self.rtc_app.peer_connections.items()):
        token = peer.get("client_token")
        if not token:
            # Token-less peer: governed by its URL role only.
            continue
        ctype = peer.get("client_type")
        role_now = "controller" if ctype == ClientType.CONTROLLER else "viewer"
        new_perms = tokens.get(token)
        if not new_perms or (new_perms.get("role") or "controller") != role_now:
            reason = "Token revoked" if not new_perms else "Permissions changed significantly"
            logger.info(f"Disconnecting WebRTC peer {peer_id}: {reason}")
            await self._close_peer_signaling_ws(peer_id, 4002, reason.encode())
            try:
                await self.rtc_app.stop_rtc_connection(peer_id, role_now)
            except Exception:
                logger.warning(f"stop_rtc_connection failed for {peer_id}", exc_info=True)
            continue
        self.rtc_app._send_collab_state(peer.get("data_channel"), ctype, token)
        new_slot = new_perms.get("slot")
        if new_slot != peer.get("client_slot"):
            peer["client_slot"] = new_slot
            channel = peer.get("data_channel")
            if channel is not None and channel.readyState == "open":
                try:
                    verdict = json.dumps({"role": role_now, "slot": new_slot})
                    channel.send(json.dumps(
                        {"type": "system", "data": {"action": f"role_update,{verdict}"}}))
                except Exception:
                    logger.debug("role_update send failed (channel closing)", exc_info=True)

Returns

None
funchandle_consumers_changed(display_id) -> None

A peer joined or left a display's consumer set: re-evaluate the all-paused stop in both directions — a departing unpaused peer cannot leave the capture running for hidden-only consumers, and a JOINING unpaused peer must re-open a capture the rule stopped (else a viewer arriving while every prior consumer is hidden gets a permanently black stream: a paused capture emits no RTP, so the browser never even PLIs). The primary's audio capture follows the same rule over the peers' audio pauses. (A departing controller's pipeline is torn down elsewhere; the pause and resume calls no-op on a stopped pipeline.)

Source Code
async def handle_consumers_changed(self, display_id: str) -> None:
    """A peer joined or left a display's consumer set: re-evaluate the
    all-paused stop in both directions — a departing unpaused peer cannot
    leave the capture running for hidden-only consumers, and a JOINING
    unpaused peer must re-open a capture the rule stopped (else a viewer
    arriving while every prior consumer is hidden gets a permanently black
    stream: a paused capture emits no RTP, so the browser never even PLIs).
    The primary's audio capture follows the same rule over the peers'
    audio pauses. (A departing controller's pipeline is torn down
    elsewhere; the pause and resume calls no-op on a stopped pipeline.)"""
    display_id = display_id or "primary"
    pipeline = self.display_pipelines.get(display_id)
    if pipeline is None:
        return
    consumers = self._display_consumers(display_id)
    if not consumers:
        return
    if all(p.get("video_paused", False) for p in consumers):
        if await pipeline.pause_screen_capture():
            logger.info(
                f"All remaining consumers of display '{display_id}' are paused; capture stopped."
            )
    else:
        # A live capture already flows RTP; the joining browser's PLI resyncs it.
        await self._resume_display_capture(display_id, pipeline, "joining consumer")
    if display_id == "primary":
        await self._settle_primary_audio()
paramdisplay_idstr

Returns

None
func_resume_display_capture(display_id, pipeline, why, idr_always=False) -> None

Resume a capture stopped by the all-consumers-paused rule (no-op on a live or fully-stopped pipeline) and request the resync IDR — always, or only when the resume actually restarted the capture.

Source Code
async def _resume_display_capture(self, display_id: str, pipeline: MediaPipelinePixel,
                                  why: str, idr_always: bool = False) -> None:
    """Resume a capture stopped by the all-consumers-paused rule (no-op on a
    live or fully-stopped pipeline) and request the resync IDR — always, or
    only when the resume actually restarted the capture."""
    restarted = False
    try:
        restarted = await pipeline.resume_screen_capture()
        if restarted:
            logger.info(f"Display '{display_id}': capture restarted ({why}).")
    except Exception as e:
        logger.error(f"Display '{display_id}': capture resume failed ({why}): {e}")
    if idr_always or restarted:
        await self.request_idr_for_display(display_id)
paramdisplay_idstr
parampipelineMediaPipelinePixel
paramwhystr
paramidr_alwaysbool
= False

Returns

None
func_drop_wayland_secondary(did, reason) -> None

Refuse a secondary display the compositor cannot realize: unregister it, stop its pipeline, destroy its screen, and close its peers with a fatal signaling verdict (4000) so the client does not re-register in a loop — the Wayland mirror of the X11 unrealizable-extension drop. The primary's screen, which may sit at a 'left'/'up' offset for the arrangement this display anchored, goes back to the origin. Caller holds _display_lock.

Source Code
async def _drop_wayland_secondary(self, did: str, reason: str) -> None:
    """Refuse a secondary display the compositor cannot realize: unregister
    it, stop its pipeline, destroy its screen, and close its peers with a
    fatal signaling verdict (4000) so the client does not re-register in a
    loop — the Wayland mirror of the X11 unrealizable-extension drop. The
    primary's screen, which may sit at a 'left'/'up' offset for the
    arrangement this display anchored, goes back to the origin. Caller
    holds _display_lock."""
    pipeline = self.display_pipelines.pop(did, None)
    self.display_clients.pop(did, None)
    self._display_dpis.pop(did, None)
    self.display_layouts.pop(did, None)
    self._client_scales.pop(did, None)
    self._client_stream_boxes.pop(did, None)
    primary_layout = self.display_layouts.get("primary")
    if primary_layout:
        # Input offsets follow the layout; the primary re-anchors at the origin.
        primary_layout["x"], primary_layout["y"] = 0, 0
    if pipeline is not None:
        await pipeline.stop_media_pipeline()
    module = self._wayland_capture_handle()
    if module is not None:
        try:
            await asyncio.to_thread(module.destroy_output, wayland_output_id(did))
        except Exception:
            pass
        await wayland_reposition_primary(module, 0, 0)
    if self.input_handler:
        await self.input_handler.ensure_session_screens([])
        self.input_handler.resync_session_screens()
    if self.peer_manager is not None:
        async with self.peer_manager.lock:
            doomed = [
                p.ws for p in self.peer_manager.peers.values()
                if p.peer_type != "server"
                and getattr(p, "display_id", "primary") == did
                and getattr(p, "ws", None) is not None and not p.ws.closed
            ]
        for peer_ws in doomed:
            try:
                await asyncio.wait_for(
                    peer_ws.close(code=4000, message=reason.encode("utf-8")),
                    timeout=2.0,
                )
            except Exception:
                pass
    if self.rtc_app is not None:
        await self.rtc_app.close_display_peers(did)
    logger.error(f"Secondary display '{did}' dropped on Wayland: {reason}")
paramdidstr
paramreasonstr

Returns

None
func_drop_x11_secondary(did, reason) -> None

Refuse a secondary display the X server cannot fit in its root: unregister it, stop its pipeline, and close its peers with a fatal signaling verdict (4000) so the client does not reload and re-register in a loop — the X11 mirror of the compositor-side drop, and the websockets engine's KILL parity. Caller holds _display_lock.

Unregistering inline rather than through stop_display_media, which would re-acquire the lock.

Source Code
async def _drop_x11_secondary(self, did: str, reason: str) -> None:
    """Refuse a secondary display the X server cannot fit in its root:
    unregister it, stop its pipeline, and close its peers with a fatal
    signaling verdict (4000) so the client does not reload and re-register
    in a loop — the X11 mirror of the compositor-side drop, and the
    websockets engine's KILL parity. Caller holds _display_lock.

    Unregistering inline rather than through stop_display_media, which
    would re-acquire the lock.
    """
    pipeline = self.display_pipelines.pop(did, None)
    self.display_clients.pop(did, None)
    self._display_dpis.pop(did, None)
    self.display_layouts.pop(did, None)
    self._client_scales.pop(did, None)
    self._client_stream_boxes.pop(did, None)
    primary_layout = self.display_layouts.get("primary")
    if primary_layout:
        # Input offsets follow the layout; the primary is back at the origin.
        primary_layout["x"], primary_layout["y"] = 0, 0
    if pipeline is not None:
        await pipeline.stop_media_pipeline()
    if self.peer_manager is not None:
        async with self.peer_manager.lock:
            doomed = [
                p.ws for p in self.peer_manager.peers.values()
                if p.peer_type != "server"
                and getattr(p, "display_id", "primary") == did
                and getattr(p, "ws", None) is not None and not p.ws.closed
            ]
        for peer_ws in doomed:
            try:
                await asyncio.wait_for(
                    peer_ws.close(code=4000, message=reason.encode("utf-8")),
                    timeout=2.0,
                )
            except Exception:
                pass
    if self.rtc_app is not None:
        await self.rtc_app.close_display_peers(did)
    logger.error(
        f"Extended layout for '{did}' is unrealizable; the secondary display stays "
        f"disabled. {reason}"
    )
paramdidstr
paramreasonstr

Returns

None
funcreconfigure_displays() -> None

Lay the extended desktop out for the connected displays and point each display's capture at its region — the WR counterpart of the websockets reconfigure engine, for the primary plus one secondary display. On Wayland the layout realizes as compositor outputs instead of xrandr monitors.

With no laid-out secondary the plain full-screen capture is restored: the secondary's compositor output goes away (its windows relocate to the primary) and the primary re-anchors at the origin, or on X11 the stale selkies-* monitors are cleared and the framebuffer shrunk; a secondary registered without dimensions yet (or whose layout was unrealizable) sends the primary's diverted resolution request straight to the real display. Otherwise the primary size comes from its last layout-path request, else its pipeline dimensions (or the live screen resolution on X11), passes the auto-resize feedback clamp, and the dual layout is realized. A layout the server cannot realize takes the secondary down with it, since an input channel left connected would keep feeding a display with no laid-out region. A new secondary's pipeline is built from its own settings (its SETTINGS arrive before its first resize lays it out), falling back per key to the service defaults, and a bring-up failure drops it so the next reconfigure retries instead of finding a dead pipeline.

Source Code
async def reconfigure_displays(self) -> None:
    """Lay the extended desktop out for the connected displays and point each
    display's capture at its region — the WR counterpart of the websockets
    reconfigure engine, for the primary plus one secondary display. On
    Wayland the layout realizes as compositor outputs instead of xrandr
    monitors.

    With no laid-out secondary the plain full-screen capture is restored:
    the secondary's compositor output goes away (its windows relocate to
    the primary) and the primary re-anchors at the origin, or on X11 the
    stale selkies-* monitors are cleared and the framebuffer shrunk; a
    secondary registered without dimensions yet (or whose layout was
    unrealizable) sends the primary's diverted resolution request straight
    to the real display. Otherwise the primary size comes from its last
    layout-path request, else its pipeline dimensions (or the live screen
    resolution on X11), passes the auto-resize feedback clamp, and the
    dual layout is realized. A layout the server cannot realize takes the
    secondary down with it, since an input channel left connected would
    keep feeding a display with no laid-out region. A new secondary's
    pipeline is built from its own settings (its SETTINGS arrive before
    its first resize lays it out), falling back per key to the service
    defaults, and a bring-up failure drops it so the next reconfigure
    retries instead of finding a dead pipeline.
    """
    async with self._display_lock:
        secondary = next(
            ((did, info) for did, info in self.display_clients.items()
             if did != "primary" and info.get("width", 0) > 0 and info.get("height", 0) > 0),
            None,
        )
        if secondary is None:
            if self.display_layouts:
                self.display_layouts = {}
                p_w, p_h = self._primary_dims or (self.media_pipeline.width, self.media_pipeline.height)
                # The pipeline dimensions are the primary's authority again.
                self._primary_dims = None
                if IS_WAYLAND:
                    await self._destroy_wayland_secondary_outputs()
                    await wayland_reposition_primary(self._wayland_capture_handle(), 0, 0)
                    self.media_pipeline.capture_region = None
                    if (self.media_pipeline.width, self.media_pipeline.height) != (p_w, p_h):
                        self.media_pipeline.width, self.media_pipeline.height = p_w, p_h
                        if self.media_pipeline.is_media_pipeline_running():
                            await self.media_pipeline.restart_screen_capture()
                    await self._size_wayland_screen(
                        self.media_pipeline.width, self.media_pipeline.height)
                    self._broadcast_display_config()
                    return
                # Before the shrink, so no monitor lingers outside the framebuffer.
                await retire_displays()
                realized = await resize_display(f"{p_w}x{p_h}")
                if realized:
                    p_w, p_h = realized
                self.media_pipeline.capture_region = None
                self.media_pipeline.width, self.media_pipeline.height = p_w, p_h
                if self.media_pipeline.is_media_pipeline_running():
                    await self.media_pipeline.restart_screen_capture()
                self._push_x11_layout_geometry({"primary": {"w": p_w, "h": p_h}})
            elif self._primary_dims is not None:
                await self._resize_primary_display(
                    "{}x{}".format(*self._primary_dims)
                )
            self._broadcast_display_config()
            return
        did, info = secondary
        # display_clients holds the secondaries; the primary counts too.
        await self._wm_swap.ensure_for(len({"primary", *self.display_clients}), IS_WAYLAND)
        if self._primary_dims is None:
            p_w, p_h = self.media_pipeline.width, self.media_pipeline.height
            if IS_WAYLAND:
                # The compositor rejects overlapping outputs, so the offset comes
                # from its realized geometry, not a capture size trailing a resize.
                realized = await self._realized_wayland_dims("primary")
                if realized is not None:
                    p_w, p_h = realized
            if p_w <= 0 or p_h <= 0:
                if IS_WAYLAND:
                    logger.error("Cannot determine primary display size; aborting layout.")
                    return
                curr, _, _, _, _ = await get_new_res("1x1")
                try:
                    p_w, p_h = (int(v) for v in curr.lower().split("x"))
                except (ValueError, AttributeError):
                    logger.error("Cannot determine primary display size; aborting layout.")
                    return
            self._primary_dims = (p_w, p_h)
        position = info.get("position", "right")
        self._primary_dims = clamp_primary_feedback(
            self._primary_dims, self.display_layouts, position
        )
        layouts, total_w, total_h = compute_dual_layout(
            self._primary_dims, (info["width"], info["height"]), position,
        )
        layouts[did] = layouts.pop("secondary")
        if IS_WAYLAND:
            if not await self._apply_wayland_extension(did, layouts):
                await self._drop_wayland_secondary(
                    did, "The compositor cannot create an output for this display."
                )
                return
        else:
            # apply_extended_layout fits `layouts` to the root really produced:
            # kept displays may shrink and an unplaceable one disappears from it.
            requested = {d: (r["w"], r["h"]) for d, r in layouts.items()}
            if (not await apply_extended_layout(layouts, total_w, total_h)
                    or did not in layouts):
                await self._drop_x11_secondary(
                    did, "The X server cannot extend the desktop to fit this display."
                )
                return
            # Write back only what the root cut down: a rectangle the layout
            # itself derived must not feed the next pass as its own input.
            for fitted_id, fitted in layouts.items():
                if (fitted["w"], fitted["h"]) == requested[fitted_id]:
                    continue
                client = self.display_clients.get(fitted_id)
                if client is not None:
                    client["width"], client["height"] = fitted["w"], fitted["h"]
                if fitted_id == "primary":
                    self._primary_dims = (fitted["w"], fitted["h"])
        self.display_layouts = layouts
        p = layouts["primary"]
        if IS_WAYLAND:
            # _apply_wayland_extension already moved the primary output; only a
            # size change needs the capture restart that resizes it.
            if (self.media_pipeline.width, self.media_pipeline.height) != (p["w"], p["h"]):
                await self.media_pipeline.update_capture_region(p["x"], p["y"], p["w"], p["h"])
                await self._push_wayland_realized_geometry("primary", self.media_pipeline)
        else:
            await self.media_pipeline.update_capture_region(p["x"], p["y"], p["w"], p["h"])
        s = layouts[did]
        pipeline = self.display_pipelines.get(did)
        if pipeline is None:
            setting = lambda key: self._display_setting(did, key)
            pipeline = MediaPipelinePixel(
                async_event_loop=asyncio.get_running_loop(),
                encoder=str(setting("encoder")),
                framerate=int(setting("framerate")),
                video_bitrate=int(setting("video_bitrate")),
                audio_enabled=False,
                width=s["w"],
                height=s["h"],
                crf=int(setting("video_crf")),
                video_fullcolor=bool(setting("video_fullcolor")),
                use_cpu=bool(setting("use_cpu")),
                video_streaming_mode=bool(setting("video_streaming_mode")),
                use_paint_over_quality=bool(setting("use_paint_over_quality")),
                video_paintover_crf=int(setting("video_paintover_crf")),
                video_paintover_burst_frames=int(setting("video_paintover_burst_frames")),
                display_id=did,
                capture_region=(s["x"], s["y"]),
            )
            if self.args.enable_rate_control:
                pipeline.rc_mode = RateControlMode(setting("rate_control_mode"))
            else:
                pipeline.rc_mode = self.media_pipeline.rc_mode
            # The scale ladder runs for this display's own screen rather than
            # copying whatever the primary was left with (a no-op field on X11).
            if IS_WAYLAND and self.input_handler is not None:
                pipeline.scale = await self.input_handler.realize_wayland_dpi(
                    self._display_dpi(did), did, (s["w"], s["h"]))
            else:
                pipeline.scale = getattr(self.media_pipeline, "scale", 1.0)
            # The native-cursor toggle is global across displays.
            pipeline.capture_cursor = self.media_pipeline.capture_cursor
            pipeline.produce_data = (
                lambda buf, pts, kind, keyframe=True, timing=None, dependency=None, _did=did:
                    self.rtc_app.consume_data(buf, pts, kind, keyframe, _did, timing, dependency)
            )
            # pixelflux's cursor-callback slot is process-global (last registration
            # wins), so every display must route cursors into the same sink.
            pipeline.on_cursor_data = self.media_pipeline.on_cursor_data
            pipeline.on_encoder_demoted = (
                lambda encoder, _did=did: asyncio.ensure_future(self._encoder_demoted(_did, encoder))
            )
            pipeline.on_stream_info = self._publish_stream_info
            pipeline.get_cursor_size_cap = self.media_pipeline.get_cursor_size_cap
            self.display_pipelines[did] = pipeline
            try:
                await pipeline.start_media_pipeline()
            except Exception as e:
                logger.error(f"Secondary display '{did}' pipeline failed to start ({e}); will retry on next reconfigure.")
                self.display_pipelines.pop(did, None)
                if IS_WAYLAND:
                    await self._drop_wayland_secondary(
                        did, "The compositor could not start a capture for this display."
                    )
                return
            if IS_WAYLAND and not await self._wayland_capture_live(did, pipeline):
                last_error = self._wayland_capture_last_error(pipeline, did)
                await self._drop_wayland_secondary(
                    did,
                    last_error or "The compositor could not start a capture for this "
                    "display (encoder session or GPU resources exhausted).",
                )
                return
            if IS_WAYLAND:
                await self._push_wayland_realized_geometry(did, pipeline)
            logger.info(f"Secondary display '{did}' pipeline started at {s}")
        else:
            # A Wayland restart is a full capture reconfigure: skip it when the
            # region is unchanged and the capture is verifiably live.
            unchanged = IS_WAYLAND and (
                (pipeline.width, pipeline.height) == (s["w"], s["h"])
                and pipeline.capture_region == (s["x"], s["y"])
                and await self._wayland_capture_live(did, pipeline)
            )
            if not unchanged:
                await pipeline.update_capture_region(s["x"], s["y"], s["w"], s["h"])
                if IS_WAYLAND:
                    await self._push_wayland_realized_geometry(did, pipeline)
        if not IS_WAYLAND:
            self._push_x11_layout_geometry(layouts)
        elif self.input_handler:
            # The capture outputs now sit where the arrangement asks; the
            # session compositor arranges its own screens by its own rule
            # until it is told this one.
            self.input_handler.schedule_session_screen_layout(layouts)
    self._broadcast_display_config()

Returns

None
func_push_x11_layout_geometry(layouts) -> None

Tell each laid-out display's pages the size the X11 layout pass gave it (websockets parity: the engine broadcasts every display's realized resolution after each pass). The root may not fit the request, and a page whose display the server cut down would otherwise keep its requested size in its manual-mode bookkeeping and re-assert it forever; idempotent on the client for an unchanged size. The Wayland branches push through the compositor's realized geometry instead.

Source Code
def _push_x11_layout_geometry(self, layouts: Dict[str, Dict[str, int]]) -> None:
    """Tell each laid-out display's pages the size the X11 layout pass gave
    it (websockets parity: the engine broadcasts every display's realized
    resolution after each pass). The root may not fit the request, and a
    page whose display the server cut down would otherwise keep its
    requested size in its manual-mode bookkeeping and re-assert it
    forever; idempotent on the client for an unchanged size. The Wayland
    branches push through the compositor's realized geometry instead."""
    if self.rtc_app is None:
        return
    for did, rect in layouts.items():
        w, h = int(rect.get("w", 0)), int(rect.get("h", 0))
        if w > 0 and h > 0:
            self.rtc_app.send_remote_resolution(f"{w}x{h}", did)
paramlayoutsDict[str, Dict[str, int]]

Returns

None
funcset_client_stream_box(display_id, origin_x, origin_y, scale_x, scale_y) -> None

Record where a display's page draws its stream on the user's desktop.

Rebroadcast with the layout, since a page maps a drag that crossed onto a neighbor through the neighbor's box rather than off its own edge. Only the browser knows those origins, and they are the only thing relating two viewports whose monitors, window chrome and device pixel ratios all differ. Ignored for an unknown display or an impossible box.

Source Code
async def set_client_stream_box(self, display_id: str, origin_x: float,
                                origin_y: float, scale_x: float,
                                scale_y: float) -> None:
    """Record where a display's page draws its stream on the user's desktop.

    Rebroadcast with the layout, since a page maps a drag that crossed onto
    a neighbor through the neighbor's box rather than off its own edge.
    Only the browser knows those origins, and they are the only thing
    relating two viewports whose monitors, window chrome and device pixel
    ratios all differ. Ignored for an unknown display or an impossible box.
    """
    if display_id not in self.display_layouts:
        return
    if not (0.05 <= scale_x <= 100.0 and 0.05 <= scale_y <= 100.0):
        return
    if not (abs(origin_x) <= 100000.0 and abs(origin_y) <= 100000.0):
        return
    box = (origin_x, origin_y, scale_x, scale_y)
    now = time.monotonic()
    stored = self._client_stream_boxes.get(display_id)
    if stored is not None:
        if stored[0] == box:
            return
        # One box a page publishes is one broadcast to every client; a page
        # that alternated two would otherwise amplify at whatever rate it
        # sent. The page republishes what the layout comes back missing, so
        # a dropped update is not a lost one.
        if now - stored[1] < 0.2:
            return
    self._client_stream_boxes[display_id] = (box, now)
    self._broadcast_display_config()
paramdisplay_idstr
paramorigin_xfloat
paramorigin_yfloat
paramscale_xfloat
paramscale_yfloat

Returns

None
func_display_config_payload() -> Dict[str, Any]

display_config_update body: the display roster, the backend, plus each laid-out display's rectangle, its client's reported CSS-to-remote scale and the desktop box that client draws it in, so a page can map a cross-display drag into its neighbor's region and, on X11, a secondary can follow the primary's density.

Source Code
def _display_config_payload(self) -> Dict[str, Any]:
    """display_config_update body: the display roster, the backend, plus
    each laid-out display's rectangle, its client's reported CSS-to-remote
    scale and the desktop box that client draws it in, so a page can map a
    cross-display drag into its neighbor's region and, on X11, a secondary
    can follow the primary's density."""
    displays = ["primary"] + [d for d in self.display_clients.keys() if d != "primary"]
    payload: Dict[str, Any] = {"displays": displays, "wayland": IS_WAYLAND}
    layouts = {}
    for did, rect in (self.display_layouts or {}).items():
        entry: Dict[str, Any] = dict(rect)
        scale = self._client_scales.get(did)
        if scale:
            entry["scale"] = scale
        stored = self._client_stream_boxes.get(did)
        if stored:
            (entry["originX"], entry["originY"],
             entry["scaleX"], entry["scaleY"]) = stored[0]
        layouts[did] = entry
    if layouts:
        payload["layouts"] = layouts
    return payload

Returns

typing.Dict[str, typing.Any]
func_broadcast_display_config() -> None

Tell every connected page which displays are attached (websockets parity: the primary page forces browser-cursor rendering while a secondary is connected, keyed off this broadcast).

Source Code
def _broadcast_display_config(self) -> None:
    """Tell every connected page which displays are attached (websockets
    parity: the primary page forces browser-cursor rendering while a
    secondary is connected, keyed off this broadcast)."""
    if not self.rtc_app:
        return
    self.rtc_app.send_media_data_over_channel(
        "display_config_update", self._display_config_payload()
    )

Returns

None
func_update_cursor_cap(dpi_value) -> None

Scale the remote-cursor delivery cap with the DPI and push it to every running capture (pixelflux applies cursor_size_cap live through update_tunables; later (re)starts read it through CaptureSettings).

Source Code
def _update_cursor_cap(self, dpi_value: float) -> None:
    """Scale the remote-cursor delivery cap with the DPI and push it to
    every running capture (pixelflux applies cursor_size_cap live through
    update_tunables; later (re)starts read it through CaptureSettings)."""
    ih = self.input_handler
    if ih is None:
        return
    try:
        ih.system_dpi = float(dpi_value)
        ih.cursor_size_cap = int(ih.max_cursor_size * float(dpi_value) / 96.0)
    except Exception as e:
        logger.debug(f"cursor cap update skipped: {e}")
        return
    updated = 0
    for did, pipeline in list(self.display_pipelines.items()):
        module = getattr(pipeline, "capture_module", None)
        if pipeline is None or module is None or not pipeline.is_media_pipeline_running():
            continue
        try:
            module.update_tunables(pipeline.generate_capture_settings())
            updated += 1
        except Exception as e:
            logger.debug(f"Live cursor cap update skipped for '{did}': {e}")
    logger.debug(f"Cursor size cap {ih.cursor_size_cap}px for DPI {dpi_value} "
                f"({updated} live capture(s) updated).")
paramdpi_valuefloat

Returns

None
funchandle_scaling(dpi_value, display_id='primary') -> None

Apply a client DPI sync to the desktop (X11 xrdb/cursor themes) or run the per-display Wayland scale ladder.

Fractional DPI is legal on the shared verb (websockets parity); the desktop DPI property itself is integral. Bounded by the declared scaling_dpi span so a client cannot drive xrdb — and, with it, the cursor size and the Wayland compositor scale — to an arbitrary value. An operator-set DPI (CLI/env) governs the desktop and is never clobbered by a client sync. Idempotent: the dashboard and the core each re-assert their DPI on settings broadcasts, and every apply churns xrdb, xsettingsd SIGHUP and cursor themes. On Wayland the DPI runs the scale ladder per display: the session compositor scales the screen backing it, and only what it leaves becomes that display's capture scale, whose change restarts the capture (the WS path threads the same scale through CaptureSettings). On Wayland a secondary's page scales the screen it owns and nothing else: the cursor cap and size stay the primary's. X11 has one DPI, so a secondary's is refused there.

Source Code
async def handle_scaling(self, dpi_value: float, display_id: str = "primary") -> None:
    """Apply a client DPI sync to the desktop (X11 xrdb/cursor themes) or
    run the per-display Wayland scale ladder.

    Fractional DPI is legal on the shared verb (websockets parity); the
    desktop DPI property itself is integral. Bounded by the declared
    scaling_dpi span so a client cannot drive xrdb — and, with it, the
    cursor size and the Wayland compositor scale — to an arbitrary value.
    An operator-set DPI (CLI/env) governs the desktop and is never
    clobbered by a client sync. Idempotent: the dashboard and the core
    each re-assert their DPI on settings broadcasts, and every apply churns
    xrdb, xsettingsd SIGHUP and cursor themes. On Wayland the DPI runs the
    scale ladder per display: the session compositor scales the screen
    backing it, and only what it leaves becomes that display's capture
    scale, whose change restarts the capture (the WS path threads the same
    scale through CaptureSettings). On Wayland a secondary's page scales
    the screen it owns and nothing else: the cursor cap and size stay the
    primary's. X11 has one DPI, so a secondary's is refused there.

    Args:
        dpi_value: The DPI the page asked for.
        display_id: The display whose page sent it.
    """
    try:
        dpi_value = min(SCALING_DPI_MAX,
                        max(SCALING_DPI_MIN, int(round(float(dpi_value)))))
    except (TypeError, ValueError, OverflowError):
        logger.warning(f"Ignoring malformed DPI sync: {dpi_value!r}")
        return
    if settings._overridden.get("scaling_dpi", False):
        logger.info("Ignoring client DPI sync: scaling_dpi is operator-overridden.")
        return
    display_id = display_id or "primary"
    if display_id != "primary":
        if not IS_WAYLAND:
            logger.info(f"Ignoring DPI {dpi_value} from '{display_id}': "
                        "the desktop DPI follows the primary display.")
            return
        if self._display_dpis.get(display_id) == int(dpi_value):
            return
        self._display_dpis[display_id] = int(dpi_value)
        await self._realize_wayland_dpi(dpi_value, display_id)
        return
    if getattr(self, "_last_applied_dpi", None) == int(dpi_value):
        logger.debug(f"DPI already {int(dpi_value)}; skipping re-apply.")
        return
    if not IS_WAYLAND:
        if await set_dpi(int(dpi_value)):
            self._last_applied_dpi = int(dpi_value)
            logger.info(f"Successfully set DPI to {dpi_value}")
        else:
            logger.error(f"Failed to set DPI to {dpi_value}")

    # Before the Wayland restarts below, which read the cap through
    # CaptureSettings; a compositor that absorbs the scale restarts nothing.
    self._update_cursor_cap(dpi_value)

    if IS_WAYLAND:
        self._last_applied_dpi = int(dpi_value)
        await self._realize_wayland_dpi(dpi_value)
        await self._apply_wayland_cursor_size(dpi_value)
        return

    if CURSOR_SIZE is None:
        # Auto: only the DPI itself is applied.
        return

    new_cursor_size = cursor_size_for_dpi(dpi_value, CURSOR_SIZE)

    logger.debug(
        f"Attempting to set cursor size to: {new_cursor_size} (based on DPI {dpi_value})"
    )
    if await set_cursor_size(new_cursor_size):
        logger.debug(f"Successfully set cursor size to {new_cursor_size}")
    else:
        logger.error(f"Failed to set cursor size to {new_cursor_size}")
paramdpi_valuefloat

The DPI the page asked for.

paramdisplay_idstr
= 'primary'

The display whose page sent it.

Returns

None
func_realize_wayland_dpi(dpi_value, display_id=None) -> None

Run the Wayland scale ladder for one display's pipeline, or the primary's and every secondary at the DPI its own page asked for, and restart the captures whose scale changed.

Source Code
async def _realize_wayland_dpi(self, dpi_value: int,
                               display_id: Optional[str] = None) -> None:
    """Run the Wayland scale ladder for one display's pipeline, or the
    primary's and every secondary at the DPI its own page asked for, and
    restart the captures whose scale changed.

    Args:
        dpi_value: The DPI to realize; the primary's when `display_id` is None.
        display_id: The one display to scale, else all of them.
    """
    targets = ([(display_id, self.display_pipelines.get(display_id))]
               if display_id else list(self.display_pipelines.items()))
    for did, pipeline in targets:
        if pipeline is None:
            continue
        # Per display, never over the argument: a session-wide pass that
        # reassigned it would hand the next display the last secondary's
        # DPI, and the primary is not always the first pipeline (it is
        # re-inserted last when it reconnects behind a live secondary).
        target_dpi = (self._display_dpi(did)
                      if display_id is None and did != "primary" else dpi_value)
        new_scale = (await self.input_handler.realize_wayland_dpi(
            target_dpi, did, (pipeline.width, pipeline.height))
            if self.input_handler else float(target_dpi) / 96.0)
        if pipeline.scale == new_scale:
            continue
        pipeline.scale = new_scale
        if pipeline.is_media_pipeline_running():
            if did == "primary":
                # The capture is a view over the primary's screen, and a
                # capture start sizes the view alone: the screen carries
                # the scale to the session (its window's preferred
                # fractional scale).
                await self._size_wayland_screen(pipeline.width, pipeline.height)
            await pipeline.restart_screen_capture()
            await self._push_wayland_realized_geometry(did, pipeline)
paramdpi_valueint

The DPI to realize; the primary's when display_id is None.

paramdisplay_idOptional[str]
= None

The one display to scale, else all of them.

Returns

None
func_resync_wayland_session_scale(dpi) -> None

A session compositor was adopted after captures started: run the scale ladder again for every display, so the session takes the desktop DPI as its output scale and the capture output, which took it while the session was still starting, drops back to 1.0.

Serialized against the layout pass: the adoption can land during the one that started the captures it restarts.

Source Code
async def _resync_wayland_session_scale(self, dpi: Any) -> None:
    """A session compositor was adopted after captures started: run the
    scale ladder again for every display, so the session takes the desktop
    DPI as its output scale and the capture output, which took it while the
    session was still starting, drops back to 1.0.

    Serialized against the layout pass: the adoption can land during the
    one that started the captures it restarts.

    Args:
        dpi: The primary's DPI; each other display re-applies its own.
    """
    if not IS_WAYLAND or self.input_handler is None:
        return
    try:
        dpi_value = int(float(dpi))
    except (TypeError, ValueError):
        return
    async with self._display_lock:
        await self._realize_wayland_dpi(dpi_value)
paramdpiAny

The primary's DPI; each other display re-applies its own.

Returns

None
func_display_dpi(display_id) -> int

The DPI a display's page asked for, else the primary's, else the configured default.

Source Code
def _display_dpi(self, display_id: str) -> int:
    """The DPI a display's page asked for, else the primary's, else the configured default."""
    own = self._display_dpis.get(display_id) if display_id != "primary" else None
    return int(own or getattr(self, "_last_applied_dpi", None)
               or float(getattr(settings, "scaling_dpi", 96) or 96))
paramdisplay_idstr

Returns

int
func_publish_stream_info(display_id, info) -> None

Tell a display's controllers what its capture streams and how.

Source Code
async def _publish_stream_info(self, display_id: str, info: Dict[str, Any]) -> None:
    """Tell a display's controllers what its capture streams and how."""
    if self.rtc_app:
        self.rtc_app.send_stream_info(display_id, info)
paramdisplay_idstr
paraminfoDict[str, Any]

Returns

None
func_send_stream_stats() -> None

One stream_stats to the controllers with their stats open: the host's figures and their display's encode. The link is the page's own to measure.

Source Code
def _send_stream_stats(self) -> None:
    """One `stream_stats` to the controllers with their stats open: the host's
    figures and their display's encode. The link is the page's own to measure."""
    host = stream_stats.host_stats(self.resource_monitor)
    for did in self.rtc_app.stats_displays():
        stats = dict(host)
        pipeline = self.display_pipelines.get(did)
        watch = getattr(pipeline, "stream_watch", None)
        if watch is not None:
            stats.update(watch.rates())
        self.rtc_app.send_stream_stats(did, stats)

Returns

None
funchandle_resource_tick(t) -> None

Resource-monitor tick: send stream_stats and a ping to the controllers watching their stats, and recover the audio capture if its worker died since the last tick.

pcmflux reports a clean start while its worker is still coming up, so a device that dies during bring-up (or later) only shows through last_error; polling it here cycles the audio capture. Audio lives on the primary pipeline; the call no-ops on the audio-less secondaries.

Source Code
async def handle_resource_tick(self, t: float) -> None:
    """Resource-monitor tick: send `stream_stats` and a ping to the
    controllers watching their stats, and recover the audio capture if its
    worker died since the last tick.

    pcmflux reports a clean start while its worker is still coming up, so a
    device that dies during bring-up (or later) only shows through
    `last_error`; polling it here cycles the audio capture. Audio lives on
    the primary pipeline; the call no-ops on the audio-less secondaries.
    """
    if self.input_handler and self.rtc_app and self.rtc_app.stats_displays():
        self.input_handler.ping_start = t
        self._send_stream_stats()
        self.rtc_app.send_ping(t)
    if self.media_pipeline is not None:
        try:
            await self.media_pipeline.recover_audio_if_failed()
        except Exception as e:
            logger.debug(f"audio health poll skipped: {e}")
paramtfloat

Returns

None
func_seed_display_settings(entry) -> None

Give a joining secondary display its own copy of every client-tunable video setting, taken from the args at join time (websockets parity: a display registers with a full seeded snapshot). Sharing the args instead would make a later primary change move what the secondary reports as its current value while its stream keeps running the old one, and the equality guards on its own controls would then compare against a value that display never ran.

Source Code
def _seed_display_settings(self, entry: Dict[str, Any]) -> None:
    """Give a joining secondary display its own copy of every client-tunable
    video setting, taken from the args at join time (websockets parity: a
    display registers with a full seeded snapshot). Sharing the args instead
    would make a later primary change move what the secondary reports as its
    current value while its stream keeps running the old one, and the equality
    guards on its own controls would then compare against a value that display
    never ran."""
    for key in list(self._VIDEO_SETTING_APPLIERS) + ["force_aligned_resolution"]:
        if key in entry:
            continue
        value = getattr(self.args, key, None)
        if value is not None:
            entry[key] = value
paramentryDict[str, Any]

Returns

None
func_display_setting(display_id, key) -> Any

A display's current value for a client-tunable setting: the primary reads the service args; a secondary reads its own stored overrides, falling back to the args it was seeded from (websockets model: each display's SETTINGS payload configures only that display's stream).

Source Code
def _display_setting(self, display_id: str, key: str) -> Any:
    """A display's current value for a client-tunable setting: the primary
    reads the service args; a secondary reads its own stored overrides,
    falling back to the args it was seeded from (websockets model: each
    display's SETTINGS payload configures only that display's stream)."""
    if display_id != "primary":
        entry = self.display_clients.get(display_id)
        if entry is not None and key in entry:
            return entry[key]
    return getattr(self.args, key, None)
paramdisplay_idstr
paramkeystr

Returns

typing.Any
func_store_display_setting(display_id, key, value) -> None

Record a setting as the display's current value (args for the primary, the display's own entry for a secondary).

Source Code
def _store_display_setting(self, display_id: str, key: str, value: Any) -> None:
    """Record a setting as the display's current value (args for the
    primary, the display's own entry for a secondary)."""
    if display_id == "primary":
        setattr(self.args, key, value)
    else:
        entry = self.display_clients.get(display_id)
        if entry is not None:
            entry[key] = value
paramdisplay_idstr
paramkeystr
paramvalueAny

Returns

None
func_apply_display_setting(display_id, key, value) -> None

Store one video setting as the display's current value and apply it to the display's live pipeline when it exists (a secondary that has not been laid out yet picks the stored value up at pipeline creation).

The primary's encoder is written through to the settings singleton: transport services re-seed from it on a mode switch, so a client pick must live there to survive the trip, and _encoder_client_set marks a fresh pick during the webrtc leg, which outranks any stashed pre-clamp value on the switch back. The RTCApp's global encoder is kept current too: it is the default codec/munge choice for connections created later, while secondaries resolve per display.

Source Code
async def _apply_display_setting(self, display_id: str, key: str, value: Any) -> None:
    """Store one video setting as the display's current value and apply it to
    the display's live pipeline when it exists (a secondary that has not been
    laid out yet picks the stored value up at pipeline creation).

    The primary's encoder is written through to the settings singleton:
    transport services re-seed from it on a mode switch, so a client pick
    must live there to survive the trip, and `_encoder_client_set` marks a
    fresh pick during the webrtc leg, which outranks any stashed pre-clamp
    value on the switch back. The RTCApp's global encoder is kept current
    too: it is the default codec/munge choice for connections created
    later, while secondaries resolve per display.
    """
    applier = self._VIDEO_SETTING_APPLIERS.get(key)
    if applier is None:
        return
    self._store_display_setting(display_id, key, value)
    # The senders take the new codec ahead of the capture restart that
    # produces it, so no frame of one codec goes out packed as another.
    if key == "encoder" and self.rtc_app:
        self.rtc_app.switch_display_codec(display_id, str(value))
    pipeline = self.display_pipelines.get(display_id)
    if pipeline is not None:
        await applier(pipeline, value)
    if key == "encoder" and display_id == "primary":
        self.settings.encoder = str(value)
        self.settings._encoder_client_set = True
        if self.rtc_app:
            self.rtc_app.encoder = str(value)
paramdisplay_idstr
paramkeystr
paramvalueAny

Returns

None
func_encoder_for_display(display_id) -> str
Source Code
def _encoder_for_display(self, display_id: str) -> str:
    return str(self._display_setting(display_id, "encoder") or self.args.encoder)
paramdisplay_idstr

Returns

str
func_encoder_demoted(display_id, encoder) -> None

A display's capture streams encoder in place of the one asked for: the setting follows, its RTP senders switch codec, and every client hears of it.

Source Code
async def _encoder_demoted(self, display_id: str, encoder: str) -> None:
    """A display's capture streams `encoder` in place of the one asked for: the
    setting follows, its RTP senders switch codec, and every client hears of it."""
    self._store_display_setting(display_id, "encoder", encoder)
    if display_id == "primary":
        self.settings.encoder = encoder
        if self.rtc_app:
            self.rtc_app.encoder = encoder
    if self.rtc_app:
        self.rtc_app.switch_display_codec(display_id, encoder)
        self.rtc_app.send_media_data_over_channel("server_settings", self._server_settings_payload())
paramdisplay_idstr
paramencoderstr

Returns

None
func_video_codec_declined(display_id, mime, fallback) -> bool

A peer's answer left out the display's codec: the display moves to fallback and every client hears of it, unless the operator's menu holds the encoder, which leaves that peer without video.

Source Code
async def _video_codec_declined(self, display_id: str, mime: str, fallback: str) -> bool:
    """A peer's answer left out the display's codec: the display moves to
    `fallback` and every client hears of it, unless the operator's menu
    holds the encoder, which leaves that peer without video."""
    current = self._encoder_for_display(display_id)
    if current == fallback:
        return True
    definition = next(d for d in SETTING_DEFINITIONS if d["name"] == "encoder")
    allowed = definition.get("meta", {}).get("allowed", [])
    if fallback not in allowed:
        return False
    logger.warning(
        "Encoder %r (%s) is not decoded by a WebRTC peer of display %r; using %r.",
        current, mime, display_id, fallback)
    await self._apply_display_setting(display_id, "encoder", fallback)
    if self.rtc_app:
        self.rtc_app.send_media_data_over_channel(
            "server_settings", self._server_settings_payload())
    return True
paramdisplay_idstr
parammimestr
paramfallbackstr

Returns

bool
func_fullcolor_declined(display_id) -> bool

A joining WebRTC peer decodes none of the 4:4:4 the display's codec carries: full color goes off for the display, so the offer describes 4:2:0 from its first frame, and every client hears of it; a full color the operator holds stays, which leaves that peer without a picture.

Source Code
async def _fullcolor_declined(self, display_id: str) -> bool:
    """A joining WebRTC peer decodes none of the 4:4:4 the display's codec
    carries: full color goes off for the display, so the offer describes
    4:2:0 from its first frame, and every client hears of it; a full color
    the operator holds stays, which leaves that peer without a picture."""
    if not self._fullcolor_for_display(display_id):
        return True
    limit = getattr(self.settings, "video_fullcolor", None)
    if isinstance(limit, (tuple, list)) and len(limit) > 1 and limit[1]:
        return False
    logger.warning("A WebRTC peer of display %r decodes no 4:4:4 of its codec; full color is off.",
                   display_id)
    await self._apply_display_setting(display_id, "video_fullcolor", False)
    if display_id == "primary":
        # The settings payload advertises the primary's value: an operator override
        # left in it would come back from the client and flip the stream to 4:4:4.
        self.settings.video_fullcolor = (False, False)
        self.settings._overridden["video_fullcolor"] = False
    if self.rtc_app:
        self.rtc_app.send_media_data_over_channel(
            "server_settings", self._server_settings_payload())
    return True
paramdisplay_idstr

Returns

bool
func_fullcolor_for_display(display_id) -> bool
Source Code
def _fullcolor_for_display(self, display_id: str) -> bool:
    return bool(self._display_setting(display_id, "video_fullcolor"))
paramdisplay_idstr

Returns

bool
func_use_cpu_for_display(display_id) -> bool
Source Code
def _use_cpu_for_display(self, display_id: str) -> bool:
    return bool(self._display_setting(display_id, "use_cpu"))
paramdisplay_idstr

Returns

bool
funchandle_update_settings(settings_json, display_id='primary') -> None

Apply a client SETTINGS payload to the display that sent it.

Every allowed entry needs server-side backing: a live setter dispatched below, or state the server reads later (the manual-resolution trio feeds the start-time resize and resolution policy; the live resize itself rides the r, input message). Video keys apply to the SENDING display only (websockets model); audio and the clipboard policy are stream-global whichever display asserts them. A scaling_dpi in the primary's payload, or in any display's on Wayland, runs handle_scaling (websockets parity: the client seeds its DPR-derived value into its very first payload, so the right scale lands on the first sync rather than the dashboard's later correction); a secondary's displayPosition may move it to any side of the primary after joining.

Source Code
async def handle_update_settings(
    self, settings_json: Dict[str, Any], display_id: str = "primary"
) -> None:
    """Apply a client SETTINGS payload to the display that sent it.

    Every allowed entry needs server-side backing: a live setter dispatched
    below, or state the server reads later (the manual-resolution trio feeds
    the start-time resize and resolution policy; the live resize itself
    rides the `r,` input message). Video keys apply to the SENDING display
    only (websockets model); audio and the clipboard policy are
    stream-global whichever display asserts them. A `scaling_dpi` in the
    primary's payload, or in any display's on Wayland, runs
    `handle_scaling` (websockets parity: the client seeds its DPR-derived
    value into its very first payload, so the right scale lands on the
    first sync rather than the dashboard's later correction); a
    secondary's `displayPosition` may move it to any side of the primary
    after joining.
    """
    settings_allowed_to_update = [
        "rate_control_mode",
        "video_crf",
        "video_bitrate",
        "audio_bitrate",
        "framerate",
        "use_cpu",
        "enable_binary_clipboard",
        "manual_resolution",
        "manual_width",
        "manual_height",
        "force_aligned_resolution",
        "encoder",
        "video_fullcolor",
        "video_streaming_mode",
        "use_paint_over_quality",
        "video_paintover_crf",
        "video_paintover_burst_frames",
    ]
    # Startup resolution policy, not a per-stream tunable.
    primary_only_keys = ("manual_resolution", "manual_width", "manual_height")

    display_id = display_id or "primary"
    if display_id != "primary" and display_id not in self.display_clients:
        logger.warning(
            f"Ignoring settings for unknown display '{display_id}' (not connected)."
        )
        return

    # Seat-global hint: base-layout push on Wayland, informational on X11.
    kb_layout = settings_json.get("keyboardLayout")
    if kb_layout and self.input_handler is not None:
        await self.input_handler.apply_client_keyboard_layout(kb_layout)

    dpi_val = settings_json.get("scaling_dpi")
    if dpi_val is not None and (display_id == "primary" or IS_WAYLAND):
        try:
            await self.handle_scaling(float(dpi_val), display_id)
        except (TypeError, ValueError):
            logger.warning(f"Ignoring malformed scaling_dpi in SETTINGS: {dpi_val!r}")

    def sanitize_value(name: str, client_value: Any) -> Any:
        """One-transport wrapper over the shared sanitizer (settings.py)."""
        return sanitize_client_setting(name, client_value, self.settings, logger)

    # The page's CSS-to-remote scale, rebroadcast with the layout so a
    # neighboring display can scale a cross-display drag over it. Stored
    # before any position-triggered reconfigure, whose broadcast carries it.
    if settings_json.get("displayScale") is not None:
        try:
            client_scale = float(settings_json.get("displayScale"))
        except (TypeError, ValueError):
            client_scale = 0.0
        if 0.05 <= client_scale <= 100.0 and \
                self._client_scales.get(display_id) != client_scale:
            self._client_scales[display_id] = client_scale
            self._broadcast_display_config()

    new_position = settings_json.get("displayPosition")
    if new_position is not None and display_id != "primary":
        new_position = str(new_position)
        if new_position not in ("right", "left", "up", "down"):
            logger.warning(f"Ignoring invalid displayPosition from '{display_id}': {new_position!r}")
        else:
            entry = self.display_clients.get(display_id)
            if entry is not None and entry.get("position", "right") != new_position:
                entry["position"] = new_position
                await self.reconfigure_displays()

    for key in settings_allowed_to_update:
        client_value = settings_json.get(key)
        if client_value is None:
            continue
        if key == "rate_control_mode" and self.args.enable_rate_control is False:
            logger.debug(
                f"Server has rate control disabled. Ignoring update for '{key}'."
            )
            continue
        if key in primary_only_keys and display_id != "primary":
            continue
        if getattr(self.args, key, None) is None:
            logger.warning(f"Received unknown setting '{key}' from client")
            continue
        current_value = self._display_setting(display_id, key)
        sanitized_value = sanitize_value(key, client_value)
        if sanitized_value is None or sanitized_value == current_value:
            continue
        if key == "audio_bitrate":
            # Audio lives only on the primary pipeline.
            if self.media_pipeline:
                await self.media_pipeline.set_audio_bitrate(int(sanitized_value))
            setattr(self.args, key, sanitized_value)
        elif key == "enable_binary_clipboard":
            await self.input_handler.update_binary_clipboard_setting(sanitized_value)
            setattr(self.args, key, sanitized_value)
        elif key in self._VIDEO_SETTING_APPLIERS:
            await self._apply_display_setting(display_id, key, sanitized_value)
        else:
            # No live setter: stored for the resize paths / startup to read.
            self._store_display_setting(display_id, key, sanitized_value)
        logger.debug(
            f"Updated setting '{key}' for display '{display_id}' from {current_value} to {sanitized_value}"
        )
paramsettings_jsonDict[str, Any]
paramdisplay_idstr
= 'primary'

Returns

None
funcmon_rtc_config(stun_servers, turn_servers, rtc_config) -> None

Monitor callback: fan a refreshed RTC config out to the signaling server (for clients) and the RTC app (for its own ICE agents).

Source Code
def mon_rtc_config(
    self, stun_servers: List[str], turn_servers: List[str], rtc_config: Any
) -> None:
    """Monitor callback: fan a refreshed RTC config out to the signaling
    server (for clients) and the RTC app (for its own ICE agents)."""
    if self.peer_manager:
        logger.debug("updating signaling server RTC config")
        self.peer_manager.set_rtc_config(rtc_config)
    if self.rtc_app:
        logger.debug("updating STUN/TURN servers in RTC app")
        self.rtc_app.update_rtc_config(stun_servers, turn_servers)
paramstun_serversList[str]
paramturn_serversList[str]
paramrtc_configAny

Returns

None
func_ensure_pacer(pc, peer, display_id) -> Optional[Any]

Ensure the per-transport packet pacer is enabled/configured (called from the congestion loop; idempotent and cheap).

Encoder ceiling: the display's configured video bitrate, CBR or not. The shared DTLS transport is reachable via pc.sctp only once the data-channel m-line is negotiated, while media (and TWCC estimates) can flow before that, so any transceiver's sender transport — the same shared RTCDtlsTransport — serves as the fallback. The IDR floor is bootstrapped from the session-start keyframe: on a late attach, waiting for the next natural IDR would start it at 0 and reset on the first real burst.

Source Code
def _ensure_pacer(self, pc: Any, peer: Dict[str, Any], display_id: str) -> Optional[Any]:
    """Ensure the per-transport packet pacer is enabled/configured (called
    from the congestion loop; idempotent and cheap).

    Encoder ceiling: the display's configured video bitrate, CBR or not.
    The shared DTLS transport is reachable via `pc.sctp` only once the
    data-channel m-line is negotiated, while media (and TWCC estimates)
    can flow before that, so any transceiver's sender transport — the same
    shared RTCDtlsTransport — serves as the fallback. The IDR floor is
    bootstrapped from the session-start keyframe: on a late attach, waiting
    for the next natural IDR would start it at 0 and reset on the first
    real burst.

    Returns:
        The DTLS transport (so callers can snapshot its pacer), or None
        when it is not available yet.
    """
    transport = getattr(getattr(pc, "sctp", None), "transport", None)
    if transport is None:
        for tr in pc.getTransceivers() or []:
            transport = getattr(getattr(tr, "sender", None), "transport", None)
            if transport is not None:
                break
    if transport is None:
        return None
    lo_kbps, hi_kbps = settings.video_bitrate
    enc_kbps = float(self._display_setting(display_id, "video_bitrate") or hi_kbps)
    enc_bps = int(max(lo_kbps, min(hi_kbps, enc_kbps)) * 1000)
    if not transport.pacer_enabled():
        vsender = None
        for tr in pc.getTransceivers() or []:
            if getattr(tr, "kind", None) == "video":
                vsender = tr.sender
                break
        transport.enable_pacer(
            encoder_bps=enc_bps,
            # Must hit the encoder pipeline: video rides the pre-encoded pack()
            # path, where the sender's __force_keyframe flag is silently ignored.
            request_keyframe=lambda did_=display_id: asyncio.ensure_future(
                self.request_idr_for_display(did_, unless_pending=True)),
        )
        kf_bytes = getattr(vsender, "_keyframe_bytes", None)
        if kf_bytes:
            transport.note_video_keyframe(
                kf_bytes, natural=getattr(vsender, "_keyframe_natural", True))
        if transport.pacer_enabled():
            logger.info(
                f"WebRTC pacer enabled for display '{display_id}' "
                f"(encoder ceiling {enc_bps // 1000} kbps)")
    else:
        transport.set_pacer_encoder_bps(enc_bps)
    return transport
parampcAny
parampeerDict[str, Any]
paramdisplay_idstr

Returns

typing.Optional

The DTLS transport (so callers can snapshot its pacer), or None

func_congestion_control_loop() -> None

GCC-style bitrate adaptation from transport-wide-cc receiver feedback: per display, follow the slowest of ITS peers' goodput estimates with headroom, back off multiplicatively on two ticks of loss in a row and hold there before recovering (CongestionSteer), and retarget that display's encoder within the allowed video_bitrate range — one display's congested link never steers another's stream. Only CBR mode has a target to steer. Each peer's own loss also sets how many FlexFEC repair packets its sender adds per group (RTCRtpSender.steer_fec).

Each peer's feedback is drained per tick, so a decision is taken over a tick's worth of it rather than whichever window landed last: a single window is a few tens of packets, too few for its loss fraction to mean anything, and a display that sends little (a still second screen) is made of such windows. A tick that drains nothing steers nothing.

The user-selected bitrate is the ceiling: control only backs off below it and recovers up to it. Clamping to the allowed range instead let a fast local segment ramp an 8000 kbps session to 80000+ kbps, saturating the real path (TURN/WAN) with queuing lag and loss-corrupted frames. Damage-gated encoders are application-limited, so measured goodput is merely what was sent (an idle screen reads ~0), not link capacity: it may lift the target when it shows real headroom but never drags it down; otherwise the target recovers multiplicatively toward the ceiling after a loss backoff. The pacer rides the same tick but is configured for every peer before the feedback gate, since it must run on links that never send transport-cc; this is its only configuration path, so one bad peer must never kill the loop.

Source Code
async def _congestion_control_loop(self) -> None:
    """GCC-style bitrate adaptation from transport-wide-cc receiver feedback:
    per display, follow the slowest of ITS peers' goodput estimates with
    headroom, back off multiplicatively on two ticks of loss in a row and
    hold there before recovering (`CongestionSteer`), and retarget that
    display's encoder within the allowed video_bitrate range — one display's
    congested link never steers another's stream. Only CBR mode has a target
    to steer. Each peer's own loss also sets how many FlexFEC repair packets
    its sender adds per group (`RTCRtpSender.steer_fec`).

    Each peer's feedback is drained per tick, so a decision is taken over a
    tick's worth of it rather than whichever window landed last: a single
    window is a few tens of packets, too few for its loss fraction to mean
    anything, and a display that sends little (a still second screen) is
    made of such windows. A tick that drains nothing steers nothing.

    The user-selected bitrate is the ceiling: control only backs off below
    it and recovers up to it. Clamping to the allowed range instead let a
    fast local segment ramp an 8000 kbps session to 80000+ kbps, saturating
    the real path (TURN/WAN) with queuing lag and loss-corrupted frames.
    Damage-gated encoders are application-limited, so measured goodput is
    merely what was sent (an idle screen reads ~0), not link capacity: it
    may lift the target when it shows real headroom but never drags it
    down; otherwise the target recovers multiplicatively toward the
    ceiling after a loss backoff. The pacer rides the same tick but is
    configured for every peer before the feedback gate, since it must run
    on links that never send transport-cc; this is its only configuration
    path, so one bad peer must never kill the loop.
    """
    lo_kbps, hi_kbps = settings.video_bitrate
    logger.debug(
        f"Congestion control loop started (CBR only, range {lo_kbps}-{hi_kbps} kbps)."
    )
    # No getattr default: a misnamed setting must raise, not disable the pacer.
    pacer_on = bool(settings.webrtc_pacer[0])
    logger.debug(f"WebRTC pacer setting: {'ON' if pacer_on else 'OFF'}.")
    while True:
        await asyncio.sleep(1.0)
        rtc_app = self.rtc_app
        if not rtc_app:
            continue
        per_display: Dict[str, Dict[str, Any]] = {}
        for peer in rtc_app.peer_connections.values():
            pc = peer.get("peer_conn")
            did = peer.get("display_id", "primary") or "primary"
            if pacer_on:
                try:
                    dtls = self._ensure_pacer(pc, peer, did)
                    if self.metrics is not None and dtls is not None:
                        self.metrics.set_pacer_snapshot(did, dtls.pacer_snapshot())
                except Exception:
                    logger.exception("_ensure_pacer failed (display %s)", did)
            transport = getattr(getattr(pc, "sctp", None), "transport", None)
            window = transport.take_twcc_window() if transport is not None else None
            if window is None:
                continue
            sender = peer.get("video_sender")
            if sender is not None:
                sender.steer_fec(window["loss_fraction"])
            bucket = per_display.setdefault(
                did, {"goodputs": [], "worst_loss": 0.0})
            if window["goodput_bps"]:
                bucket["goodputs"].append(window["goodput_bps"])
            bucket["worst_loss"] = max(bucket["worst_loss"], window["loss_fraction"])
        if self.metrics is not None:
            self.metrics.set_bridge_drops(rtc_app.bridge_drops())
        for did, bucket in per_display.items():
            if not self.args.congestion_control:
                continue
            pipeline = self.display_pipelines.get(did)
            if (
                pipeline is None
                or getattr(pipeline, "rc_mode", None) != RateControlMode.CBR
            ):
                continue
            goodputs, worst_loss = bucket["goodputs"], bucket["worst_loss"]
            if not goodputs:
                continue
            current = float(pipeline.video_bitrate)
            ceiling = float(self._display_setting(did, "video_bitrate") or hi_kbps)
            ceiling = max(lo_kbps, min(hi_kbps, ceiling))
            # Goodput may lift the target, never drag it down (see docstring).
            steer = self._congestion_steer.setdefault(did, CongestionSteer())
            target = round(steer.target(
                current, ceiling, lo_kbps, min(goodputs), worst_loss, time.monotonic()))
            if target != round(current):
                logger.info(
                    f"Congestion control[{did}]: video bitrate {current:.0f} -> {target:.0f} kbps "
                    f"(goodput {min(goodputs) / 1e3:.1f} kbps, loss {worst_loss:.1%})"
                )
                await pipeline.set_video_bitrate(target)

Returns

None
funcstart_components() -> None

Start the background tasks: input/clipboard/cursor workers, the startup scale, the congestion/pacer loop, the monitors, the signaling client, and the configured TURN credential refreshers.

On Wayland the configured DPI becomes the session compositor's output scale (96 is unity, so nothing is applied then), and with none up yet the input handler re-applies when it adopts one; the X11 desktop's density was settled before the listener opened, so the first session compares against it (handle_scaling re-derives the cursor size on DPI changes; Wayland gets it via CaptureSettings). Logical monitors describe the layout of whichever transport defined them, and a live switch leaves the previous one's behind — a desktop keeps tiling against a stale rectangle — so on X11 they are cleared; this service defines its own when a second display arrives and needs none for a single one.

Source Code
async def start_components(self) -> None:
    """Start the background tasks: input/clipboard/cursor workers, the
    startup scale, the congestion/pacer loop, the monitors, the signaling
    client, and the configured TURN credential refreshers.

    On Wayland the configured DPI becomes the session compositor's output
    scale (96 is unity, so nothing is applied then), and with none up yet
    the input handler re-applies when it adopts one; the X11 desktop's
    density was settled before the listener opened, so the first session
    compares against it (`handle_scaling` re-derives the cursor size on
    DPI changes; Wayland gets it via CaptureSettings). Logical monitors
    describe the layout of whichever
    transport defined them, and a live switch leaves the previous one's
    behind — a desktop keeps tiling against a stale rectangle — so on X11
    they are cleared; this service defines its own
    when a second display arrives and needs none for a single one.
    """
    if self.input_handler:
        self.tasks.append(asyncio.create_task(self.input_handler.connect()))
        self.tasks.append(asyncio.create_task(self.input_handler.start_clipboard()))
        self.tasks.append(asyncio.create_task(self.input_handler.probe_apps_runner()))

    startup_dpi = int(float(getattr(settings, "scaling_dpi", "96") or 96))
    if IS_WAYLAND:
        if startup_dpi != 96:
            if self.input_handler is not None:
                await self.input_handler.realize_wayland_dpi(startup_dpi)
            self._last_applied_dpi = startup_dpi
    else:
        # Settled before the listener opened; a page's first DPI compares against it.
        self._last_applied_dpi = applied_dpi() or startup_dpi

    if not IS_WAYLAND:
        await retire_displays()

    # The pacer rides the congestion loop's tick but is gated on its own flag.
    if self.args.congestion_control or bool(settings.webrtc_pacer[0]):
        self.tasks.append(asyncio.create_task(self._congestion_control_loop()))

    if self.resource_monitor:
        self.resource_monitor.start()
    if self.signaling_client:
        self.signaling_client.start()

    if self.monitoring_utils_used:
        turn_rest_username = self.args.turn_rest_username.replace(":", "-")
        if self.monitoring_utils_used.get("using_hmac_turn", False):
            self.mon_hmac_turn = HMACRTCMonitor(
                turn_host=self.args.turn_host,
                turn_port=self.args.turn_port,
                turn_shared_secret=self.args.turn_shared_secret,
                turn_username=turn_rest_username,
                turn_protocol=self.args.turn_protocol,
                turn_tls=self.args.turn_tls,
                stun_host=self.args.stun_host,
                stun_port=self.args.stun_port,
                period=60,
                enabled=True,
            )
            self.mon_hmac_turn.on_rtc_config = self.mon_rtc_config
            self.mon_hmac_turn.start()
        if self.monitoring_utils_used.get("using_rest_api", False):
            self.mon_rest_api = RESTRTCMonitor(
                turn_rest_uri=self.args.turn_rest_uri,
                turn_rest_username=turn_rest_username,
                turn_rest_username_auth_header=self.args.turn_rest_username_auth_header,
                turn_protocol=self.args.turn_protocol,
                turn_rest_protocol_header=self.args.turn_rest_protocol_header,
                turn_tls=self.args.turn_tls,
                turn_rest_tls_header=self.args.turn_rest_tls_header,
                turn_api_key=self.args.turn_rest_api_key,
                period=60,
                enabled=True,
            )
            self.mon_rest_api.on_rtc_config = self.mon_rtc_config
            self.mon_rest_api.start()
        if self.monitoring_utils_used.get("using_rtc_config_json", False):
            self.mon_rtc_config_file = RTCConfigFileMonitor(
                rtc_file=self.args.rtc_config_json, enabled=True
            )
            self.mon_rtc_config_file.on_rtc_config = self.mon_rtc_config
            await self.mon_rtc_config_file.start()
        if self.monitoring_utils_used.get("using_cloudflare_turn", False):
            self.mon_cloudflare_turn = CloudflareRTCMonitor(
                turn_token_id=self.args.cloudflare_turn_token_id,
                api_token=self.args.cloudflare_turn_api_token,
                enabled=True,
            )
            self.mon_cloudflare_turn.on_rtc_config = self.mon_rtc_config
            self.mon_cloudflare_turn.start()

Returns

None
funcshutdown() -> None

Gracefully shutdown all components.

Source Code
async def shutdown(self) -> None:
    """Gracefully shutdown all components."""
    if self._shutdown_called:
        logger.debug("Shutdown already called, skipping")
        return
    self._shutdown_called = True
    logger.debug("Starting shutdown sequence")
    if self.rtc_app is not None:
        capture_demand.detach(self.rtc_app)

    self._cancel_primary_stop_grace()
    for task in list(self.tasks):
        try:
            if not task.done():
                task.cancel()
        except Exception:
            logger.exception("Error canceling task during shutdown")

    async def _await_with_timeout(
        coro: Awaitable[Any], name: str, timeout: float = 3.0
    ) -> Optional[Any]:
        """Await one component's stop with a timeout, swallowing every
        error so one wedged component cannot abort the whole shutdown."""
        try:
            return await asyncio.wait_for(coro, timeout=timeout)
        except asyncio.TimeoutError:
            logger.warning(
                f"Timeout while waiting for {name} to stop (after {timeout}s)"
            )
        except asyncio.CancelledError:
            logger.debug(f"{name} was canceled during shutdown")
        except Exception as e:
            logger.exception(f"Error while stopping {name}: {e}")
        return None

    try:
        await asyncio.wait_for(
            asyncio.gather(*self.tasks, return_exceptions=True), timeout=5.0
        )
    except asyncio.TimeoutError:
        logger.warning(
            "Some background tasks did not exit within timeout; continuing with component shutdown"
        )
    except Exception:
        logger.exception("Unexpected error while awaiting background tasks")

    stop_coros = []
    if self.signaling_client:
        stop_coros.append(
            (
                _await_with_timeout(
                    self.signaling_client.stop(), "signaling_client", 3.0
                )
            )
        )
    for display_id, pipeline in list(self.display_pipelines.items()):
        stop_coros.append(
            (
                _await_with_timeout(
                    pipeline.stop_media_pipeline(), f"media_pipeline[{display_id}]", 3.0
                )
            )
        )
    if self.media_pipeline and "primary" not in self.display_pipelines:
        stop_coros.append(
            (
                _await_with_timeout(
                    self.media_pipeline.stop_media_pipeline(), "media_pipeline", 3.0
                )
            )
        )
    if self.rtc_app:
        stop_coros.append(
            (
                _await_with_timeout(
                    self.rtc_app.stop_all_rtc_connections(), "rtc_app", 3.0
                )
            )
        )
    stop_coros.append(
        _await_with_timeout(
            self._teardown_webrtc_virtual_mic(), "webrtc_virtual_mic", 3.0
        )
    )
    if self.input_handler:
        try:
            self.input_handler.stop_clipboard()
        except Exception:
            logger.exception("Error stopping clipboard monitor")
        stop_coros.append(
            (
                _await_with_timeout(
                    self.input_handler.disconnect(), "input_handler.disconnect", 3.0
                )
            )
        )

    if self.resource_monitor:
        stop_coros.append(
            (_await_with_timeout(self.resource_monitor.stop(), "resource_monitor", 2.0))
        )

    if self.mon_hmac_turn:
        stop_coros.append(
            (
                _await_with_timeout(
                    self.mon_hmac_turn.stop(), "HMAC RTC Monitor", 2.0
                )
            )
        )
    if self.mon_rest_api:
        stop_coros.append(
            (_await_with_timeout(self.mon_rest_api.stop(), "REST RTC Monitor", 2.0))
        )
    if self.mon_rtc_config_file:
        stop_coros.append(
            (
                _await_with_timeout(
                    self.mon_rtc_config_file.stop(), "RTC Config File Monitor", 2.0
                )
            )
        )
    if self.mon_cloudflare_turn:
        stop_coros.append(
            (
                _await_with_timeout(
                    self.mon_cloudflare_turn.stop(), "Cloudflare TURN RTC Monitor", 2.0
                )
            )
        )

    if stop_coros:
        try:
            await asyncio.wait_for(
                asyncio.gather(*stop_coros, return_exceptions=True), timeout=5
            )
        except asyncio.TimeoutError:
            logger.warning(
                "Component shutdown exceeded global timeout; some components may still be cleaning up"
            )
        except Exception:
            logger.exception(
                "Unexpected error during concurrent component shutdown"
            )
    if self.metrics:
        try:
            # unregister() drains the CSV executor with shutdown(wait=True).
            await asyncio.to_thread(self.metrics.unregister)
        except Exception as e:
            logger.exception(f"Error unregistering metrics: {e}")

    self.tasks.clear()

    self.signaling_client = None
    self.media_pipeline = None
    if self.rtc_app is not None:
        try:
            await self.rtc_app.close_ice_muxes()
        except Exception:
            logger.exception("Error releasing the shared ICE ports")
    self.rtc_app = None
    self.input_handler = None
    self.resource_monitor = None
    self.metrics = None
    self.mon_hmac_turn = None
    self.mon_rest_api = None
    self.mon_rtc_config_file = None

    logger.info("Shutdown complete")

Returns

None
funcrun() -> None

Bring the service up and block until the shutdown event fires.

Source Code
async def run(self) -> None:
    """Bring the service up and block until the shutdown event fires."""
    self._shutdown_called = False
    try:
        _install_webrtc_teardown_noise_filters(asyncio.get_running_loop())
        await self.initialize_components()
        self.setup_callbacks()

        await self.start_components()
        await self.shutdown_event.wait()

    except asyncio.CancelledError:
        logger.info("Received webrtc stream mode shutdown")
    except Exception as e:
        logger.critical(f"Fatal error: {e}", exc_info=True)
        sys.exit(1)
    finally:
        await self.shutdown()

Returns

None
funcstart() -> None

Supervisor entry point: run the service until stop() is called.

Source Code
async def start(self) -> None:
    """Supervisor entry point: run the service until stop() is called."""
    self.shutdown_event.clear()
    await self.run()

Returns

None
funcstop() -> None

Signal run() to exit and shut the service down.

Source Code
async def stop(self) -> None:
    """Signal run() to exit and shut the service down."""
    self.shutdown_event.set()

Returns

None
funcregister_routes(api_prefix, main_router) -> None

Register the WebRTC HTTP/WebSocket endpoints.

Every endpoint lives under /api so the single nginx /api proxy rule fronts them — the signaling socket included, since that location forwards WebSocket upgrades. Paths off /api (such as a bare /turn or /webrtc/signaling) would sit unproxied behind the LSIO nginx: the TURN fetch and the signaling handshake would 404 and freeze the dashboard.

Source Code
def register_routes(self, api_prefix: str, main_router: web.UrlDispatcher) -> None:
    """Register the WebRTC HTTP/WebSocket endpoints.

    Every endpoint lives under /api so the single nginx /api proxy rule
    fronts them — the signaling socket included, since that location
    forwards WebSocket upgrades. Paths off /api (such as a bare /turn or
    /webrtc/signaling) would sit unproxied behind the LSIO nginx: the TURN
    fetch and the signaling handshake would 404 and freeze the dashboard.
    """
    main_router.add_get(
        f"{api_prefix}/api/webrtc/signaling{{slash:/?}}", self.rtc_ws_handler
    )
    main_router.add_get(f"{api_prefix}/api/ws", self.rtc_ws_handler)
    main_router.add_get(f"{api_prefix}/api/turn", self.handle_turn_req)
paramapi_prefixstr
parammain_routerweb.UrlDispatcher

Returns

None
funcrtc_ws_handler(request) -> Union[web.Response, web.WebSocketResponse]

Accept a signaling WebSocket, refusing with 409/503 while the WebRTC mode is inactive or still starting.

Source Code
async def rtc_ws_handler(
    self, request: web.Request
) -> Union[web.Response, web.WebSocketResponse]:
    """Accept a signaling WebSocket, refusing with 409/503 while the WebRTC
    mode is inactive or still starting."""
    if self.supervisor.current_mode != self.mode:
        return web.Response(status=409, text="WebRTC mode is inactive")
    if self.peer_manager is None:
        return web.Response(status=503, headers={"Retry-After": "1"},
                            text="WebRTC service is still starting")
    # autoping=False so the signaling loop sees PONG frames and can feed
    # the upload uplink gauge's clock; the loop answers PING itself.
    ws = web.WebSocketResponse(autoping=False)
    await ws.prepare(request)

    peername = request.transport.get_extra_info("peername")
    remote_address = peername if peername else (request.remote, 0)
    await self.peer_manager.signaling_handler(
        ws, remote_address, auth_role_ceiling=request.get("auth_role_ceiling")
    )
    return ws
paramrequestweb.Request

Returns

typing.Union[aiohttp.web.aiohttp.web.Response, aiohttp.web.aiohttp.web.WebSocketResponse]
funcuplink_session_conns() -> List[Tuple[Any, Optional[str], Optional[str]]]

(websocket, session token, peer ip) per connected browser signaling peer, for the supervisor's upload uplink gauge. The signaling socket stays open for the session's life, so it is the WebRTC transport's window onto the client's uplink.

Source Code
def uplink_session_conns(self) -> List[Tuple[Any, Optional[str], Optional[str]]]:
    """``(websocket, session token, peer ip)`` per connected browser
    signaling peer, for the supervisor's upload uplink gauge. The
    signaling socket stays open for the session's life, so it is the
    WebRTC transport's window onto the client's uplink."""
    if self.peer_manager is None:
        return []
    conns = []
    for peer in list(self.peer_manager.peers.values()):
        if peer.peer_type != "client":
            continue
        raddr = peer.raddr
        ip = raddr[0] if isinstance(raddr, (tuple, list)) and raddr else None
        conns.append((peer.ws, peer.client_token, ip))
    return conns

Returns

typing.List[typing.Tuple[typing.Any, typing.Optional[str], typing.Optional[str]]]
funchandle_turn_req(request) -> web.Response

Serve a TURN credential request via the peer manager, refusing with 409/503 while the WebRTC mode is inactive or still starting.

Source Code
async def handle_turn_req(self, request: web.Request) -> web.Response:
    """Serve a TURN credential request via the peer manager, refusing with
    409/503 while the WebRTC mode is inactive or still starting."""
    if self.supervisor.current_mode != self.mode:
        return web.json_response({"error": "WebRTC mode is inactive"}, status=409)
    if self.peer_manager is None:
        return web.json_response(
            {"error": "WebRTC service is still starting"},
            status=503, headers={"Retry-After": "1"})
    return await self.peer_manager.handle_turn_req(request)
paramrequestweb.Request

Returns

aiohttp.web.aiohttp.web.Response

On this page

Edit on GitHub