Skip to main content

pyagorartc

Async Python client for Agora RTC signalling, for WebRTC consumers that are not the Agora SDK: a browser behind Home Assistant, go2rtc, pion.

A device publishes video to an Agora channel. pyagorartc finds the Agora edge, turns the consumer's SDP offer into Agora's ORTC, joins the channel over the gateway WebSocket, subscribes to the stream, and hands back an answer SDP. Media then flows directly between the consumer and the Agora edge. It also sends Agora RTM peer messages over REST, which some vendors use as a device control channel.

It knows channels, tokens, edges, SDP and gateway messages. It does not know any vendor. Mammotion mowers and PetKit cameras are the two known hosts; vendor behaviour plugs in through callbacks and options.

What it does not do

  • No media. It never touches RTP. The consumer receives the stream.
  • No decryption. Agora channel encryption (aes_*) is applied inside the SDK's media path. The fields are modelled but never sent (the SDK RSA-wraps the secret), and a plain WebRTC consumer cannot decode an encrypted stream anyway (D20, Q17).
  • No relay. It does not run go2rtc, a TURN server, or an HTTP/WHEP endpoint. Those are host jobs.
  • No vendor API. Credentials arrive already fetched.
  • No recovery policy. It times peer recovery; the host decides what recovery means.

Status

Alpha (0.x). The API below is the target surface; pyagorartc.__all__ is the supported part of it (Constitution §10). Wire behaviour comes from recordings, the Agora Web SDK 4.24.3 and two shipped integrations; what is still a guess is listed in docs/open_questions.md.

Install

pip install pyagorartc

Python 3.13+. Dependencies: aiohttp, websockets>=13.1, sdp-transform.

Usage

import aiohttp
from pyagorartc import AgoraAPClient, AgoraSession, ChannelCredentials, CloseReason, PyAgoraRTCError, SessionOptions


async def on_closed(reason: CloseReason) -> None:
    print("session ended:", reason)


async def on_peer_left(uid: int) -> None:
    print("publisher", uid, "left; ask the device to publish again")


async def stream(viewer, creds: ChannelCredentials) -> None:
    async with aiohttp.ClientSession() as http:
        ap = await AgoraAPClient(http).choose_server(creds)
        viewer.set_ice_servers(ap.get_ice_servers())       # before the viewer makes its offer
        offer_sdp = await viewer.create_offer()

        session = AgoraSession(creds, ap, options=SessionOptions(target_uid=1),
                               on_closed=on_closed, on_peer_left=on_peer_left)
        try:
            answer_sdp = await session.join(offer_sdp, session_id="viewer-1")
            await viewer.set_answer(answer_sdp)
            await viewer.wait_until_done()
        except PyAgoraRTCError as err:
            print("join failed:", err)
        finally:
            await session.close()                          # cancel and await owned tasks, leave, close

viewer stands for whatever produces the offer. One session serves one offer; a new offer is a new AgoraSession. Candidates known before join() go in with session.add_ice_candidate(...).

Vendor policy

Concern Library provides Host provides
Token refresh token_provider, 30 s debounce (D8) the vendor call that mints a token
Device keep-alive keepalive, keepalive_interval_s, deadline (D15) the call to the device
Stream recovery peer-recovery timing, on_peer_left(uid) (D14) re-requesting the stream
Which camera SessionOptions.target_uid slot → uid
Consumer quirks declare_remote_video_ssrc, disable_audio, instant_video, subscribe retry choosing them
set_client_role after join send_set_client_role, default off (D6) knowing the device tolerates it
RTM control RtmRestClient.send_peer_message (D18) the commands and their cadence
Viewer transport answer SDP, ICE servers, candidate helpers views, auth, relays

The full table is in docs/architecture.md §4.

Errors

All exceptions derive from PyAgoraRTCError. None carries a token, ticket, credential or key.

Exception Meaning
APError Edge discovery failed on every access-point host.
APRejectedError The access point answered, but rejected every service (.codes).
SdpError The offer could not be converted, or no answer could be built.
GatewayConnectError No gateway edge accepted the WebSocket, or it closed (or stalled) before the join result.
JoinRejectedError The gateway refused the join (.code).
JoinTimeoutError No join result in time.
SessionClosedError The session has already ended.
RtmError An RTM peer message was not accepted (.status, .code).

A failed join raises; it never returns a made-up answer (D9). A running session reports its end once, through on_closed(CloseReason) (D14).

Documentation

Licence

GPL-3.0-or-later. See LICENSE.

Metadata

Release files for PyAgoraRTC 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for PyAgoraRTC 0.2.0
File Size Uploaded
pyagorartc-0.2.0.tar.gz 310.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for PyAgoraRTC 0.2.0
File Interpreter ABI Platform
pyagorartc-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 375.3 kB

Release files / pyagorartc-0.2.0.tar.gz

Download URL pyagorartc-0.2.0.tar.gz
Size 310.3 kB
Tags Source
SHA-256 checksum
How to use checksums
8bb6a4c15ad56c879eb5594c365add4844691d33c9d79a61cecb7976c7df01e6
BLAKE2b-256 checksum
How to use checksums
8822645c3393f58aa4745e53c7fc4ec70379f382bf8899a238958624a122b4dd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 30, 2026.

Transparency log

Release files / pyagorartc-0.2.0-py3-none-any.whl

Download URL pyagorartc-0.2.0-py3-none-any.whl
Size 65.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
334df85659d8d37467a6d888521476639b6fc0c9179bf3661540a87378736978
BLAKE2b-256 checksum
How to use checksums
4dfeee1ff4774e112969a58b1a20a313e225d14cbda3fba4b6ab705d4e4ecd72
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 30, 2026.

Transparency log

Release history Release notifications | RSS feed

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

This release

0.2.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page