Skip to content

Python (seyd)

Generated from the docstrings of sdks/python/seyd. The package is a thin wrapper over libseyd (ADR 0004): every call maps onto one C ABI function, and no protocol logic lives in Python. See A robot in Python for the guide and C ABI for what each call does underneath.

Seyd — hyper-low-latency P2P streaming for robots, as a Python package.

A thin wrapper over libseyd (ADR 0004): all protocol logic lives in the Rust core, so this package and seydd and the C++/ROS 2 wrappers cannot drift.

from seyd import Agent, ChannelKind
with Agent("my-robot", "wss://signal.seyd.io/ws") as agent:
video = agent.add_channel(ChannelKind.VIDEO, "main", fps=25)
agent.on_command = lambda channel, payload: print(payload)
agent.start()
...

Exported names: ABI_VERSION, Agent, Channel, ChannelKind, Counters, Role, SeydError, SeydLibraryNotFound, SignalState, __version__.

A Seyd robot.

Configure channels, register handlers, then start(). Handlers run on one Seyd thread, in order, and must not block — a slow handler delays every later event. Do real work on your own thread or queue.

with Agent("my-robot", "wss://signal.example/ws") as agent:
video = agent.add_channel(ChannelKind.VIDEO, "main",
codec="avc1.42001f", fps=25)
agent.on_command = lambda ch, data: drive(data)
agent.start()
for au in encoder:
agent.push_frame(video, au.bytes, keyframe=au.is_idr,
capture_ts_us=au.pts_us)
Agent(robot_id: str, signal_url: str, *, credential_path: str | None = None, quic_port: int = 0, ipv6: bool = True, port_mapping: bool = True, host_override: str | None = None, qos_profile: str = 'balanced', max_sessions: int = 0)

Assign a callable; all are optional. Handlers run on one Seyd thread, in order, and must not block.

Attribute Type Fires
on_session_started Callable[[str, Role, str], None] | None Called as (session_id, role, path_label) when a pilot is admitted.
on_session_ended Callable[[str, str], None] | None Called as (session_id, reason). Park actuators here — it fires whether the pilot said goodbye or simply vanished.
on_command Callable[[int, bytes], None] | None Called as (channel_id, payload) for each driver command.
on_requested_config Callable[[Mapping], None] | None Called as (config) with Seyd’s targets for the publisher — the video-config document of docs/protocol/seydd.md: maxBitrateKbps, latencyBudgetMs, maxGopMs, preferIntraRefresh, suggestedFps, reason. The one place Seyd talks to the encoder. Keyframes are on demand (ADR 0009): answer on_recovery_request and treat maxGopMs as a long ceiling, not a cadence.
on_recovery_request Callable[[int, str, str], None] | None Called as (channel_id, kind, reason) where kind is ltr, intra_refresh or idr.
on_signal_state Callable[[SignalState, str | None], None] | None Called as (state, detail); the robot is unreachable while down.
on_nat_report Callable[[Mapping], None] | None Called as (report) with the NAT report each time candidates are announced.

add_channel(kind: ChannelKind, name: str, *, codec: str | None = None, fps: int = 0) -> Channel

Section titled “add_channel(kind: ChannelKind, name: str, *, codec: str | None = None, fps: int = 0) -> Channel”

Add a channel. Only valid before start().

Channels are numbered from 1 in the order they are added, and that numbering is what the pilot sees.

Property.

The channel added under name.

Bind, discover, announce and start serving.

Blocks while candidates are gathered (a second or two). Handlers begin firing once this returns.

Stop serving. Blocks until no further handler can run. Idempotent.

Stop and release the agent. The object is unusable afterwards.

push_frame(channel: Channel | int, data: bytes, *, keyframe: bool, capture_ts_us: int) -> None

Section titled “push_frame(channel: Channel | int, data: bytes, *, keyframe: bool, capture_ts_us: int) -> None”

Hand one encoded access unit to a video channel.

Never blocks. A frame arriving while the previous one is still going out is dropped by admission control — keyframes never are — and counted in frames_dropped_backlog. capture_ts_us is the source’s capture clock; the pilot paces presentation on it (ADR 0005), so pass the encoder’s timestamp rather than “now” whenever you have it.

push_message(channel: Channel | int, data: bytes | str | Mapping) -> None

Section titled “push_message(channel: Channel | int, data: bytes | str | Mapping) -> None”

Send a message on a sensor channel. Never blocks.

dict is encoded as JSON and str as UTF-8, since that is what almost every sensor channel carries.

Switch the QoS ceiling (latency, balanced, quality).

set_status(status: Mapping | None) -> None

Section titled “set_status(status: Mapping | None) -> None”

Publish free-form robot status to the console. None clears it.

Property.

Property.

A configured channel. Truthy id; usable directly as a push_* target.

Channel(id: int, kind: ChannelKind, name: str, codec: str, fps: int)

Bases: enum.IntEnum

What a channel carries. Video is FEC-protected and whole-frame-or-nothing.

Member Value
VIDEO 0
SENSOR 1
COMMAND 2

Bases: dict

Engine counters. A plain mapping, with attribute access for convenience.

Bases: enum.IntEnum

A driver may send commands; an observer’s commands are dropped by the agent.

Member Value
DRIVER 0
OBSERVER 1

Bases: RuntimeError

A call into libseyd failed. status is the seyd_status code.

SeydError(status: int, message: str)

Bases: RuntimeError

libseyd could not be located. Set SEYD_LIBRARY to its full path.

Bases: enum.IntEnum

Member Value
CONNECTED 0
DISCONNECTED 1
DENIED 2

The SEYD_ABI_VERSION of the header the package was generated against; compared with seyd_abi_version() of the loaded library at import.