From 4cd700011b39c56f5c207f9b46b41236858f8928 Mon Sep 17 00:00:00 2001 From: "Ilya (Marshal)" Date: Sun, 11 Oct 2026 21:56:50 +0200 Subject: [PATCH] Redesign the README and docs homepage --- CHANGES.md | 98 ++++++++- CONTRIBUTING.md | 46 ++++ README.md | 208 ++++++++++--------- docs/source/examples/index.md | 8 - docs/source/examples/telegram_group_calls.md | 8 - docs/source/index.md | 107 ++++++++-- examples/README.md | 4 - pyproject.toml | 10 +- 8 files changed, 342 insertions(+), 147 deletions(-) create mode 100644 CONTRIBUTING.md delete mode 100644 docs/source/examples/telegram_group_calls.md diff --git a/CHANGES.md b/CHANGES.md index d418f68..931e084 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,7 +2,7 @@ ## Version 0.0.1 -**XX.XX.2026** +**11.10.2026** **๐Ÿ”Œ The whole WebRTC API is bound. Every interface, every method, every dictionary: all 154 binding issues of the [tracker](https://github.com/users/MarshalX/projects/1/views/1) are done, and the API goes beyond them** @@ -10,6 +10,10 @@ **๐Ÿ” WebRTC Encoded Transform: the encoded frames of senders and receivers in Python with `RTCRtpScriptTransform`, and end-to-end encryption with SFrame** +**๐ŸŽฅ H.264 without bundling it: VideoToolbox on macOS, offered by default, and Cisco's OpenH264 binary on request elsewhere** + +**๐Ÿš€ Field trials and WARP: DTLS 1.3, SNAP and SPED cut round trips off connection setup** + **โšก libwebrtc M152, pre-built wheels for Linux (x86_64 and aarch64), macOS and Windows, CPython 3.9 โ€“ 3.15, free-threaded 3.14t and 3.15t too** **๐Ÿงช The public API follows the WebIDL of the specifications and runs the original web-platform-tests** @@ -38,10 +42,17 @@ In numbers: 229 public classes, 50 enums with the string values of the specifica * Align WebIDL dictionaries with the spec as typed models by [@MarshalX](https://github.com/MarshalX) in [#212](https://github.com/MarshalX/python-webrtc/pull/212) * Align the public API with the WPT WebIDL by [@MarshalX](https://github.com/MarshalX) in [#214](https://github.com/MarshalX/python-webrtc/pull/214) * Type event handlers per event, add listener management methods by [@MarshalX](https://github.com/MarshalX) in [#215](https://github.com/MarshalX/python-webrtc/pull/215) +* Add H.264 through Cisco's OpenH264 binary, downloaded on request by [@MarshalX](https://github.com/MarshalX) in [#218](https://github.com/MarshalX/python-webrtc/pull/218) +* Add H.264 on macOS through VideoToolbox, offered by default by [@MarshalX](https://github.com/MarshalX) in [#219](https://github.com/MarshalX/python-webrtc/pull/219) +* Encode H.264 with our own VideoToolbox session: AutoLevel, no rate freeze, High for Chrome by [@MarshalX](https://github.com/MarshalX) in [#233](https://github.com/MarshalX/python-webrtc/pull/233) +* Match browsers on SDP munging, connection states, `setParameters` and close by [@MarshalX](https://github.com/MarshalX) in [#227](https://github.com/MarshalX/python-webrtc/pull/227) * Replace `to_async` with `call_native`, drop its timeout by [@MarshalX](https://github.com/MarshalX) in [#206](https://github.com/MarshalX/python-webrtc/pull/206) * Add the OpenAI GPT-Live voice chat example by [@MarshalX](https://github.com/MarshalX) in [#198](https://github.com/MarshalX/python-webrtc/pull/198) -* Add field trials, connect the GPT-Live example with WARP, skip loopback candidates by [@MarshalX](https://github.com/MarshalX) +* Add field trials, connect the GPT-Live example with WARP, skip loopback candidates by [@MarshalX](https://github.com/MarshalX) in [#225](https://github.com/MarshalX/python-webrtc/pull/225) * Add the Janus streaming example by [@MarshalX](https://github.com/MarshalX) in [#205](https://github.com/MarshalX/python-webrtc/pull/205) +* Play Janus streams in stereo by munging the Opus answer by [@MarshalX](https://github.com/MarshalX) in [#234](https://github.com/MarshalX/python-webrtc/pull/234) +* Rework the docs website with guides, examples and the API reference by [@MarshalX](https://github.com/MarshalX) in [#217](https://github.com/MarshalX/python-webrtc/pull/217) +* Rewrite the API docs with MDN links by [@MarshalX](https://github.com/MarshalX) in [#221](https://github.com/MarshalX/python-webrtc/pull/221) * Run original web-platform-tests through a PythonMonkey shim by [@MarshalX](https://github.com/MarshalX) in [#193](https://github.com/MarshalX/python-webrtc/pull/193) * Sync tests with web-platform-tests by [@MarshalX](https://github.com/MarshalX) in [#192](https://github.com/MarshalX/python-webrtc/pull/192) * Compare the public API with the WPT WebIDL by [@MarshalX](https://github.com/MarshalX) in [#211](https://github.com/MarshalX/python-webrtc/pull/211) @@ -50,12 +61,91 @@ In numbers: 229 public classes, 50 enums with the string values of the specifica * Enable all ruff rules, fix findings by [@MarshalX](https://github.com/MarshalX) in [#210](https://github.com/MarshalX/python-webrtc/pull/210) * Type check with Pyrefly at full strictness, fix findings by [@MarshalX](https://github.com/MarshalX) in [#213](https://github.com/MarshalX/python-webrtc/pull/213) * Run tests on GitHub Actions by [@MarshalX](https://github.com/MarshalX) in [#187](https://github.com/MarshalX/python-webrtc/pull/187) +* Build on Ubuntu 22.04 in CI by [@MarshalX](https://github.com/MarshalX) in [#189](https://github.com/MarshalX/python-webrtc/pull/189) +* Make CI wheel builds and PyPI publish safe to retry by [@MarshalX](https://github.com/MarshalX) in [#226](https://github.com/MarshalX/python-webrtc/pull/226) +* Retry and cache CI downloads, build the sdist in each wheel job by [@MarshalX](https://github.com/MarshalX) in [#230](https://github.com/MarshalX/python-webrtc/pull/230) +* Run isolated tests as functions instead of code strings by [@MarshalX](https://github.com/MarshalX) in [#228](https://github.com/MarshalX/python-webrtc/pull/228) +* Add an unattended bug hunt with stacks, crash triage and C++/Python coverage by [@MarshalX](https://github.com/MarshalX) in [#231](https://github.com/MarshalX/python-webrtc/pull/231) +* Update the licence holder and headers, rebuild third-party licences for M152 by [@MarshalX](https://github.com/MarshalX) in [#220](https://github.com/MarshalX/python-webrtc/pull/220) * Fix wrapper ownership: shared_ptr lifetimes, no factory leaks or dangling observers by [@MarshalX](https://github.com/MarshalX) in [#194](https://github.com/MarshalX/python-webrtc/pull/194) * Fix the GC deadlock by releasing wrappers off libwebrtc threads by [@MarshalX](https://github.com/MarshalX) in [#199](https://github.com/MarshalX/python-webrtc/pull/199) * Fix deadlocks, leaks and crashes found by sanitizers and chaos tests by [@MarshalX](https://github.com/MarshalX) in [#200](https://github.com/MarshalX/python-webrtc/pull/200) * Fix `set_parameters` hanging when libwebrtc drops the callback by [@MarshalX](https://github.com/MarshalX) in [#208](https://github.com/MarshalX/python-webrtc/pull/208) * Fix sender and receiver leaks by releasing handlers of ended tracks by [@MarshalX](https://github.com/MarshalX) in [#216](https://github.com/MarshalX/python-webrtc/pull/216) +* Fix spec bugs found by a stricter WPT by [@MarshalX](https://github.com/MarshalX) in [#222](https://github.com/MarshalX/python-webrtc/pull/222) +* Fix callback crashes, exit hangs and thread churn in the native layer by [@MarshalX](https://github.com/MarshalX) in [#223](https://github.com/MarshalX/python-webrtc/pull/223) +* Fix stream, track and event-loop bugs, and a wrapper deadlock by [@MarshalX](https://github.com/MarshalX) in [#224](https://github.com/MarshalX/python-webrtc/pull/224) +* Release tasks stranded by a closed test loop by [@MarshalX](https://github.com/MarshalX) in [#229](https://github.com/MarshalX/python-webrtc/pull/229) * Rebuild object lifetime: unreferenced connections, channels and live tracks stay alive while they have handlers or pending work, native threads never run Python, wrappers take no attributes by [@MarshalX](https://github.com/MarshalX) in [#232](https://github.com/MarshalX/python-webrtc/pull/232) * Fire `ended` on remote tracks when a connection closes, keep a failed `RTCIceTransport` for an ICE restart by [@MarshalX](https://github.com/MarshalX) in [#232](https://github.com/MarshalX/python-webrtc/pull/232) -* Fix a cancelled operation of a connection breaking the operations queued before and after it by [@MarshalX](https://github.com/MarshalX) -* Fix the docs build with the current `sphinx-favicon` by [@MarshalX](https://github.com/MarshalX), closes [#186](https://github.com/MarshalX/python-webrtc/issues/186) +* Fix a cancelled operation of a connection breaking the operations queued before and after it by [@MarshalX](https://github.com/MarshalX) in [#217](https://github.com/MarshalX/python-webrtc/pull/217) +* Fix the docs build with the current `sphinx-favicon` by [@MarshalX](https://github.com/MarshalX) in [#217](https://github.com/MarshalX/python-webrtc/pull/217), closes [#186](https://github.com/MarshalX/python-webrtc/issues/186) + +## Version 0.0.0.dev9 + +**03.03.2022** + +* Add `RTCDtlsTransport` and `RTCPeerConnection.add_transceiver`, with `RtpEncodingParameters`, `RtpTransceiverInit` and `MediaType` +* `transport` of `RTCRtpSender` and `RTCRtpReceiver` +* `MediaStreamTrack.kind` is a `MediaType` + +## Version 0.0.0.dev8 + +**02.03.2022** + +* Add `RTCRtpTransceiver`, `RTCRtpReceiver` and `RTCIceTransport` +* `get_transceivers`, `get_senders` and `get_receivers` of `RTCPeerConnection` +* Unified Plan is the default SDP semantics + +## Version 0.0.0.dev7 + +**26.02.2022** + +* Fix a segfault of the `MediaStream` from `get_user_media` +* Compare Python wrappers by their native objects +* Add the test suite with pytest + +## Version 0.0.0.dev6 + +**10.02.2022** + +* Bind `RTCError`, `SdpParseError` and the common exceptions; failed async calls raise them +* Fix a segfault in `RTCPeerConnection.close` +* Add the security policy + +## Version 0.0.0.dev5 + +**09.02.2022** + +* Fix a segfault of `RTCSessionDescription` (double destruction) +* Publish the sdist, include third-party licences in the package + +## Version 0.0.0.dev4 + +**06.02.2022** + +* Keep one Python wrapper per native object, which fixes many segfaults and bus errors +* Fix `MediaStream` pointers and the creation of `RTCRtpSender` +* Docs: favicons, OpenGraph, keyboard navigation and mobile layout + +## Version 0.0.0.dev3 + +**03.02.2022** + +* Docs on Read the Docs, a README with the logo + +## Version 0.0.0.dev2 + +**03.02.2022** + +* `RTCPeerConnection` with `create_offer`, `create_answer`, `set_local_description`, `set_remote_description`, `add_track` and `close` +* `MediaStream`, `MediaStreamTrack` and `get_user_media` +* `RTCRtpSender`, and `RTCAudioSource` to send PCM from Python +* The pure Python `webrtc` module over the native `wrtc`, with docs +* Wheels for Linux, macOS (Intel and Apple Silicon) and Windows + +## Version 0.0.0.dev1 + +**03.01.2022** + +* The first upload: the package skeleton diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..e79130c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,46 @@ +# Contributing + +Contributions of any size are welcome. For bugs and features, [open an issue](https://github.com/MarshalX/python-webrtc/issues/new); +for questions, [start a discussion](https://github.com/MarshalX/python-webrtc/discussions/new). + +## Development + +Requires [uv](https://docs.astral.sh/uv/). + +``` bash +make dev # editable install into .venv, C++ is rebuilt on import when changed +make test # run the test suite +make lint # ruff +make stub # regenerate type stubs of the native module +make wheels # build wheels for the current platform the same way CI does +``` + +## Building from sources (sdist) + +- CMake 3.26 or higher +- A C++20 compiler: Clang on Linux (libwebrtc there is built against Chromium's libc++), Apple Clang on macOS, MSVC on Windows +- ~150 MB of free disk space + +Nothing else has to be installed or configured manually: a prebuilt static libwebrtc for the target platform +(from [libwebrtc-bin](https://github.com/crow-misia/libwebrtc-bin)) is downloaded once, verified and unpacked +into a shared cache (`~/.cache/python-webrtc`, `%LOCALAPPDATA%\python-webrtc` on Windows or `$WRTC_CACHE_DIR`). +Only the headers in use are extracted and debug info is stripped, so it takes ~60 MB per platform. +Pass `-Ccmake.define.LIBWEBRTC_ROOT=/path/to/libwebrtc` to use your own libwebrtc build instead. + +## Releasing + +1. Bump `version` in `pyproject.toml` and run `uv lock`. +2. Push a `v` tag. CI builds the sdist and wheels for every platform and publishes them to PyPI. + +Publishing uses [trusted publishing](https://docs.pypi.org/trusted-publishers/): the PyPI project needs a +trusted publisher for this repository's `ci.yml` workflow, and the repository a `pypi` environment. No tokens needed. + +## Updating WebRTC + +The libwebrtc version and archive hashes are pinned in `cmake/libwebrtc.cmake`: + +1. Set `LIBWEBRTC_VERSION` to a [libwebrtc-bin release](https://github.com/crow-misia/libwebrtc-bin/releases) + and update the `LIBWEBRTC_SHA256_*` values (the release page lists a SHA256 digest per asset). +2. Refresh the Linux libc++ pins as described in [`cmake/libcxx/README.md`](cmake/libcxx/README.md). +3. Build and run the tests. On Linux, check whether `cmake/libwebrtc_linux_fixups.cpp` is still needed: + remove it and see whether the module imports (it is linked with `-z now`, so missing symbols fail on import). diff --git a/README.md b/README.md index cb979ea..21ecf1a 100644 --- a/README.md +++ b/README.md @@ -1,143 +1,151 @@

- python-webrtc logo - -
- A Python extension that provides bindings to WebRTC M152 -
- - Examples + Python WebRTC logo +

+ +

Chrome's WebRTC engine, with the browser API, in Python.

+ +

+ Documentation โ€ข - - Documentation - + Quickstart โ€ข - - PyPI - + Examples + โ€ข + PyPI

-## Python WebRTC +--- -> Let's use the native WebRTC with strict compatibility and fully implemented stuff! +Python WebRTC binds **libwebrtc M152**, the engine inside Chrome, and exposes it through the **W3C APIs you +already know from the browser**: `RTCPeerConnection`, data channels, tracks, WebCodecs frames, encoded transforms and +stats. Talk to browsers, servers, SFUs and AI agents peer-to-peer, with no vendor service in between. -This project follows the [W3C specification](https://w3c.github.io/webrtc-pc/) with some modifications and additions to make it work better with Python applications. Audio and video are read from tracks and written to them with the APIs of browsers: `MediaStreamTrackProcessor`, `VideoTrackGenerator` and `MediaStreamTrackGenerator`, with the `VideoFrame` and `AudioData` of WebCodecs. +```bash +pip install wrtc +``` -## DISCLAIMER +## If you know it in JavaScript, you know it in Python -This project is still under development and isn't ready for any serious use. In the current stage, it's possible to establish connection and work with audio, but many interfaces and methods not implemented yet. + + + + + + +
BrowserPython
-You can easily check status of methods and interfaces availability [here](https://github.com/users/MarshalX/projects/1/views/1). +```js +const pc = new RTCPeerConnection(); +const channel = pc.createDataChannel('chat'); +channel.onopen = () => channel.send('Hello!'); +channel.onmessage = (e) => console.log(e.data); +pc.onicecandidate = (e) => signaling.send(e.candidate); + +const offer = await pc.createOffer(); +await pc.setLocalDescription(offer); +signaling.send(pc.localDescription); +``` -#### Snippet + ```python -import asyncio -import webrtc +pc = webrtc.RTCPeerConnection() +channel = pc.create_data_channel('chat') +channel.on('open', lambda e: channel.send('Hello!')) +channel.on('message', lambda e: print(e.data)) +pc.on('icecandidate', lambda e: signaling.send(e.candidate)) + +offer = await pc.create_offer() +await pc.set_local_description(offer) +signaling.send(pc.local_description) +``` +
-async def main(): - pc = webrtc.RTCPeerConnection() +Names follow the specifications in snake_case, and the camelCase originals (`createOffer`) work too. Enums compare +equal to the strings of the specification, dictionaries are typed dataclasses, and everything is asyncio. - stream = await webrtc.media_devices.get_user_media(webrtc.MediaStreamConstraints(audio=True)) - for track in stream.get_tracks(): - pc.add_track(track, stream) +## Highlights - generator = webrtc.MediaStreamTrackGenerator('audio') - pc.add_track(generator) +- ๐ŸŒ **The real engine.** ICE, DTLS, SCTP, congestion control, jitter buffers and codecs are Chrome's own, so + interop with browsers is the browsers' interop. +- ๐Ÿงฉ **The browser API.** Written against the W3C specifications and tested with the + [web-platform-tests](https://github.com/web-platform-tests/wpt) the browsers use. +- ๐ŸŽž๏ธ **Every modern codec.** VP8, VP9, AV1, H.264 and Opus. Hardware H.264 through VideoToolbox on macOS. +- โšก **Native media path.** Packets, decoding and encoding never touch Python. You see frames, not packets. +- ๐Ÿ–ผ๏ธ **Frames in, frames out.** `MediaStreamTrackProcessor`, `VideoTrackGenerator` and `MediaStreamTrackGenerator` + with WebCodecs' `VideoFrame` and `AudioData`, piped through WHATWG Streams. +- ๐Ÿ” **Encoded transforms.** `RTCRtpScriptTransform` and end-to-end encryption with SFrame. +- ๐Ÿš€ **Fast connection setup.** [WARP](https://wrtc.marshal.dev/guides/field-trials/#warp): DTLS 1.3, SNAP and + SPED cut round trips off every new connection. +- ๐Ÿ“ฆ **`pip install` and go.** Prebuilt wheels for Linux, macOS and Windows, CPython 3.9โ€“3.15, including + free-threaded 3.14t and 3.15t. Nothing else to install. +- ๐Ÿท๏ธ **Typed.** Full type stubs, so your editor knows every interface, dictionary and event. - local_sdp = await pc.create_offer() - print(local_sdp.sdp) +## How it compares +| | **Python WebRTC** | aiortc | LiveKit SDK | GStreamer webrtcbin | +|---------------------------------------------------------|----------------------|-------------------|----------------------------|-----------------------| +| Engine | libwebrtc (Chrome's) | own, in Python | libwebrtc | own, in C | +| Connects peer-to-peer to any WebRTC endpoint | โœ… | โœ… | โŒ needs a LiveKit server | โœ… | +| Browser API (`RTCPeerConnection`, `createOffer`, โ€ฆ) | โœ… | similar | โŒ rooms | โŒ GObject signals | +| Media path | native | Python | native | native | +| VP9 and AV1 | โœ… | โŒ | โœ… | โœ… | +| `pip install` on Linux, macOS and Windows | โœ… | โœ… | โœ… | โŒ system packages | -if __name__ == '__main__': - asyncio.run(main()) -``` +## Codecs + +| | Linux and Windows | macOS | +|-------|---------------------------------------------------------------------------|-----------------------------| +| Video | VP8, VP9, AV1, H.264 with [OpenH264](https://wrtc.marshal.dev/guides/h264/) | VP8, VP9, AV1, H.264 with VideoToolbox | +| Audio | Opus, G.722, G.711 | Opus, G.722, G.711 | -### Requirements +No H.264 implementation is built into the package. `webrtc.openh264.install()` downloads Cisco's binary on the +user's device, under Cisco's patent license. -#### Pre-built wheels +## Platforms -Python 3.9 โ€“ 3.15 (CPython), free-threaded 3.14t and 3.15t too, on: +Prebuilt wheels for CPython 3.9โ€“3.15, and free-threaded 3.14t and 3.15t, on: | Linux | macOS | Windows | |---------------------------------------------|------------------------------|---------| | x86_64 and aarch64 (glibc 2.27+, manylinux) | 13+, Intel and Apple Silicon | x64 | -#### Building from sources (sdist) +Elsewhere pip builds it from sources with CMake and a C++20 compiler. See [CONTRIBUTING.md](https://github.com/MarshalX/python-webrtc/blob/main/CONTRIBUTING.md#building-from-sources-sdist). -- CMake 3.26 or higher -- A C++20 compiler: Clang on Linux (libwebrtc there is built against Chromium's libc++), Apple Clang on macOS, MSVC on Windows -- ~150 MB of free disk space +## Examples -Nothing else has to be installed or configured manually: a prebuilt static libwebrtc for the target platform -(from [libwebrtc-bin](https://github.com/crow-misia/libwebrtc-bin)) is downloaded once, verified and unpacked -into a shared cache (`~/.cache/python-webrtc`, `%LOCALAPPDATA%\python-webrtc` on Windows or `$WRTC_CACHE_DIR`). -Only the headers in use are extracted and debug info is stripped, so it takes ~60 MB per platform. -Pass `-Ccmake.define.LIBWEBRTC_ROOT=/path/to/libwebrtc` to use your own libwebrtc build instead. +Complete programs, ready to copy. The ones with dependencies declare them inline, so `uv run` needs nothing installed. -### Installing +- ๐Ÿค– [**Voice chat with OpenAI GPT-Live**](https://github.com/MarshalX/python-webrtc/blob/main/examples/openai_live.py): talk to the model through your microphone and + speakers. No server, just an API key. +- ๐Ÿ“บ [**Live stream in the terminal**](https://github.com/MarshalX/python-webrtc/blob/main/examples/janus_streaming.py): watch a public Janus stream as colored + characters, with the audio on your speakers. +- ๐Ÿ” [**Echo peer**](https://github.com/MarshalX/python-webrtc/blob/main/examples/echo.py): send the received video back in grayscale. +- ๐Ÿ’พ [**Recorder**](https://github.com/MarshalX/python-webrtc/blob/main/examples/recorder.py): write received video and audio to files. -Pre-built wheel: -``` bash -pip install wrtc -``` - -Build from sources: -``` bash -pip install wrtc --no-binary wrtc -``` - -### Development - -Requires [uv](https://docs.astral.sh/uv/). - -``` bash -make dev # editable install into .venv, C++ is rebuilt on import when changed -make test # run the test suite -make lint # ruff -make stub # regenerate type stubs of the native module -make wheels # build wheels for the current platform the same way CI does +```bash +uv run https://raw.githubusercontent.com/MarshalX/python-webrtc/main/examples/janus_streaming.py ``` -#### Releasing - -1. Bump `version` in `pyproject.toml` and run `uv lock`. -2. Push a `v` tag. CI builds the sdist and wheels for every platform and publishes them to PyPI. - -Publishing uses [trusted publishing](https://docs.pypi.org/trusted-publishers/): the PyPI project needs a -trusted publisher for this repository's `ci.yml` workflow, and the repository a `pypi` environment. No tokens needed. - -#### Updating WebRTC - -The libwebrtc version and archive hashes are pinned in `cmake/libwebrtc.cmake`: - -1. Set `LIBWEBRTC_VERSION` to a [libwebrtc-bin release](https://github.com/crow-misia/libwebrtc-bin/releases) - and update the `LIBWEBRTC_SHA256_*` values (the release page lists a SHA256 digest per asset). -2. Refresh the Linux libc++ pins as described in [`cmake/libcxx/README.md`](cmake/libcxx/README.md). -3. Build and run the tests. On Linux, check whether `cmake/libwebrtc_linux_fixups.cpp` is still needed: - remove it and see whether the module imports (it is linked with `-z now`, so missing symbols fail on import). - -### Documentation - -The documentation is live at [wrtc.marshal.dev](https://wrtc.marshal.dev/). - -### Getting help +## Status -You can get help in several ways: -- Report bugs, request new features by [creating an issue](https://github.com/MarshalX/python-webrtc/issues/new). -- Ask questions by [starting a discussion](https://github.com/MarshalX/python-webrtc/discussions/new). +Pre-1.0: the API follows the specifications, but compatibility between versions isn't guaranteed until 1.0.0. See +the [changelog](https://wrtc.marshal.dev/change_log/). -### Contributing +## Getting help -Contributions of any sizes are welcome. +- ๐Ÿ“– [Documentation](https://wrtc.marshal.dev/): quickstart, guides and the API reference. +- ๐Ÿ› [Report a bug or request a feature](https://github.com/MarshalX/python-webrtc/issues/new). +- ๐Ÿ’ฌ [Ask a question](https://github.com/MarshalX/python-webrtc/discussions/new). -### Special thanks to +## Contributing -- [Authors](https://github.com/node-webrtc/node-webrtc/blob/develop/AUTHORS) of [node-webrtc](https://github.com/node-webrtc/node-webrtc). -- Authors of [web-platform-tests](https://github.com/web-platform-tests/wpt). +Contributions of any size are welcome. [CONTRIBUTING.md](https://github.com/MarshalX/python-webrtc/blob/main/CONTRIBUTING.md) covers the development setup, building from +sources, releasing and updating libwebrtc. -### License +## License -The `python-webrtc` is published under the [BSD 3-Clause License](LICENSE.md). +Python WebRTC is published under the [BSD 3-Clause License](https://github.com/MarshalX/python-webrtc/blob/main/LICENSE.md). diff --git a/docs/source/examples/index.md b/docs/source/examples/index.md index 5f1ee98..e558943 100644 --- a/docs/source/examples/index.md +++ b/docs/source/examples/index.md @@ -37,13 +37,6 @@ Watches a public stream, with the video as colored characters and the audio on y Talks to the model through your microphone and speakers. ::: -:::{grid-item-card} {octicon}`people;1em;sd-mr-1` Telegram group calls -:link: telegram_group_calls -:link-type: doc - -Streams audio from a raw file to a group call. -::: - :::: ```{toctree} @@ -53,5 +46,4 @@ echo recorder janus_streaming openai_live -telegram_group_calls ``` diff --git a/docs/source/examples/telegram_group_calls.md b/docs/source/examples/telegram_group_calls.md deleted file mode 100644 index 50914ca..0000000 --- a/docs/source/examples/telegram_group_calls.md +++ /dev/null @@ -1,8 +0,0 @@ -# Telegram group calls - -Connects to a Telegram group call and streams audio from a raw file, with {obj}`~webrtc.MediaStreamTrackGenerator`. - -```{literalinclude} ../../../examples/telegram_group_calls.py -:language: python -:caption: examples/telegram_group_calls.py -``` diff --git a/docs/source/index.md b/docs/source/index.md index 7fd9490..9173bc3 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -1,39 +1,109 @@ --- myst: html_meta: - "description": "Python WebRTC: bindings to the native WebRTC, with the API of the browsers" + "description": "Python WebRTC: Chrome's WebRTC engine, with the browser API, in Python" --- # Python WebRTC -Bindings to the native WebRTC M152, with the API of the browsers: peer connections, data channels, media tracks -and their frames, encoded transforms and stats, as the W3C specifications define them, in asyncio. +**Chrome's WebRTC engine, with the browser API, in Python.** -```python -import asyncio -import webrtc +Python WebRTC binds libwebrtc M152, the engine inside Chrome, and exposes it through the W3C APIs you already know +from the browser: peer connections, data channels, tracks, WebCodecs frames, encoded transforms and stats, in +asyncio. Talk to browsers, servers, SFUs and AI agents peer-to-peer, with no vendor service in between. +```bash +pip install wrtc +``` -async def main(): - pc = webrtc.RTCPeerConnection() - channel = pc.create_data_channel('chat') +## If you know it in JavaScript, you know it in Python - offer = await pc.create_offer() - await pc.set_local_description(offer) - print(pc.local_description.sdp) +::::{tab-set} +:::{tab-item} Python +:sync: python -asyncio.run(main()) +```python +pc = webrtc.RTCPeerConnection() +channel = pc.create_data_channel('chat') +channel.on('open', lambda e: channel.send('Hello!')) +channel.on('message', lambda e: print(e.data)) +pc.on('icecandidate', lambda e: signaling.send(e.candidate)) + +offer = await pc.create_offer() +await pc.set_local_description(offer) +signaling.send(pc.local_description) ``` +::: -```bash -pip install wrtc +:::{tab-item} Browser +:sync: js + +```js +const pc = new RTCPeerConnection(); +const channel = pc.createDataChannel('chat'); +channel.onopen = () => channel.send('Hello!'); +channel.onmessage = (e) => console.log(e.data); +pc.onicecandidate = (e) => signaling.send(e.candidate); + +const offer = await pc.createOffer(); +await pc.setLocalDescription(offer); +signaling.send(pc.localDescription); ``` +::: + +:::: + +Names follow the specifications in snake_case (`create_offer`), and the camelCase originals (`createOffer`) work +too. Enums compare equal to the strings of the specification, and dictionaries are typed dataclasses. -:::{warning} -Under development. Until the 1.0.0 release, compatibility between versions is not guaranteed. +:::{note} +Pre-1.0: until the 1.0.0 release, compatibility between versions isn't guaranteed. ::: +## Why Python WebRTC + +::::{grid} 1 2 2 3 +:gutter: 3 + +:::{grid-item-card} {octicon}`globe;1em;sd-mr-1` The real engine +ICE, DTLS, SCTP, congestion control, jitter buffers and codecs are Chrome's own, so interop with browsers is the +browsers' interop. +::: + +:::{grid-item-card} {octicon}`code;1em;sd-mr-1` The browser API +Written against the W3C specifications and tested with the web-platform-tests the browsers use. +::: + +:::{grid-item-card} {octicon}`zap;1em;sd-mr-1` Native media path +Packets, decoding and encoding never touch Python. You see frames, not packets. +::: + +:::{grid-item-card} {octicon}`device-camera-video;1em;sd-mr-1` Every modern codec +VP8, VP9, AV1, H.264 and Opus. Hardware H.264 through VideoToolbox on macOS. See [H.264](guides/h264.md). +::: + +:::{grid-item-card} {octicon}`rocket;1em;sd-mr-1` Fast connection setup +[WARP](guides/field-trials.md#warp): DTLS 1.3, SNAP and SPED cut round trips off every new connection. +::: + +:::{grid-item-card} {octicon}`package;1em;sd-mr-1` pip install and go +Prebuilt wheels for Linux, macOS and Windows, including free-threaded Python. Nothing else to install. +::: + +:::: + +## How it compares + +| | **Python WebRTC** | aiortc | LiveKit SDK | GStreamer webrtcbin | +|-----------------------------------------------------|----------------------|----------------|---------------------------|---------------------| +| Engine | libwebrtc (Chrome's) | own, in Python | libwebrtc | own, in C | +| Connects peer-to-peer to any WebRTC endpoint | โœ… | โœ… | โŒ needs a LiveKit server | โœ… | +| Browser API (`RTCPeerConnection`, `createOffer`, โ€ฆ) | โœ… | similar | โŒ rooms | โŒ GObject signals | +| Media path | native | Python | native | native | +| VP9 and AV1 | โœ… | โŒ | โœ… | โœ… | +| `pip install` on Linux, macOS and Windows | โœ… | โœ… | โœ… | โŒ system packages | + ## Where to start ::::{grid} 1 2 2 3 @@ -93,9 +163,6 @@ What changed in each release. WebCodecs and WHATWG Streams. - **WebRTC Encoded Transform**: {obj}`~webrtc.RTCRtpScriptTransform` and end-to-end encryption with SFrame. -Names follow the specifications in snake_case (`create_offer`), and the camelCase originals (`createOffer`) work -too. Enums compare equal to the strings of the specification, and dictionaries are typed dataclasses. - ## Supported platforms Pre-built wheels for CPython 3.9 to 3.15, and free-threaded 3.14t and 3.15t, on: diff --git a/examples/README.md b/examples/README.md index 998f400..e1f93ac 100644 --- a/examples/README.md +++ b/examples/README.md @@ -4,10 +4,6 @@ All examples are licensed under the [CC0 License](LICENSE) and are therefore ful dedicated to the public domain. You can use them as the base for your own bots without worrying about copyrights. -### [telegram_group_calls.py](telegram_group_calls.py) - -**Sending audio with MediaStreamTrackGenerator.** The example of connection establishing with Telegram Group Calls and streaming audio from .RAW file. - ### [recorder.py](recorder.py) **Recording received media with MediaStreamTrackProcessor.** Writes the video and audio a peer receives to raw I420 and PCM files. diff --git a/pyproject.toml b/pyproject.toml index cd3a9ac..50cff7d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,17 +5,19 @@ build-backend = "scikit_build_core.build" [project] name = "wrtc" # "webrtc" isn't allowed on PyPI version = "0.0.1" -description = "a Python extension that provides bindings to WebRTC M152" +description = "Chrome's WebRTC engine (libwebrtc M152), with the browser API, in Python" readme = "README.md" license = "BSD-3-Clause" license-files = ["LICENSE.md", "THIRD_PARTY_LICENSES.md"] authors = [{ name = "Ilya (Marshal)", email = "ilya@marshal.dev" }] requires-python = ">=3.9" +keywords = ["webrtc", "libwebrtc", "rtc", "peer-to-peer", "data-channel", "video", "audio", "voip", "asyncio", "w3c"] dependencies = ["typing_extensions>=4.10"] classifiers = [ - "Development Status :: 1 - Planning", + "Development Status :: 3 - Alpha", "Natural Language :: English", "Intended Audience :: Developers", + "Framework :: AsyncIO", "Operating System :: MacOS", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX :: Linux", @@ -43,14 +45,16 @@ classifiers = [ "Programming Language :: Python :: 3.15", "Programming Language :: Python :: Implementation", "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Free Threading :: 2 - Beta", "Typing :: Typed", ] [project.urls] -Homepage = "https://github.com/MarshalX/python-webrtc" +Homepage = "https://wrtc.marshal.dev/" Documentation = "https://wrtc.marshal.dev/" Source = "https://github.com/MarshalX/python-webrtc" Tracker = "https://github.com/MarshalX/python-webrtc/issues" +Changelog = "https://wrtc.marshal.dev/change_log/" Author = "https://github.com/MarshalX" [dependency-groups]