Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions .devin/wiki.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
{
"repo_notes": [
{
"content": "Python WebRTC binds libwebrtc M152, the WebRTC engine of Chrome, and exposes it through the W3C browser APIs in asyncio. It is installed with `pip install wrtc` and imported as `webrtc`. Descriptions of it as bindings to WebRTC M92 that aren't ready for use are about its versions from 2023 and are out of date."
},
{
"content": "The public API follows the specifications: WebRTC, Media Capture and Streams, WebCodecs (VideoFrame, AudioData), WebRTC Encoded Transform with SFrame, WHATWG Streams and WebRTC Statistics. Describe it in the terms of those specifications and of MDN, with snake_case names (`create_offer`). The camelCase originals (`createOffer`) are aliases. Dictionaries are typed dataclasses, enums compare equal to the strings of the specifications, and handlers are registered with `on`."
},
{
"content": "Layout: `python-webrtc/python/webrtc` is the Python package (`interfaces`, `models`, `enums.py`, `exceptions.py`, `streams.py`, `utils`, and the `aiortc` compatibility layer). `python-webrtc/cpp/src` is the native extension module `wrtc`, written with pybind11. `docs/source` is the Sphinx documentation published at https://wrtc.marshal.dev. `tests` holds the pytest suite, web-platform-tests, the WebIDL comparison and fuzzing. `benchmarks` and `examples` are at the root."
},
{
"content": "`python-webrtc/cpp/NATIVE.md` is the authoritative description of the native threads, the Dispatcher and mailboxes, ownership and lifetime: native threads never run Python and only post records to the mailbox of an event loop. Benchmark numbers come only from `benchmarks/RESULTS.md`. H.264 isn't compiled into the package: macOS uses VideoToolbox, and elsewhere Cisco's OpenH264 binary is downloaded at runtime on request."
}
],
"pages": [
{
"title": "Overview",
"purpose": "What Python WebRTC is, what it covers, the supported Python versions and platforms, and how the repository is organised."
},
{
"title": "Getting started",
"parent": "Overview",
"purpose": "Installing `wrtc`, connecting two peers with a data channel as in docs/source/quickstart.md, and how the API maps from the browser's JavaScript to Python."
},
{
"title": "Python API",
"purpose": "The layout of the `webrtc` package: interfaces, models (dictionaries), enums, exceptions and streams, and the conventions they share."
},
{
"title": "Peer connections and signaling",
"parent": "Python API",
"purpose": "RTCPeerConnection, RTCConfiguration and ICE servers, offers and answers, session descriptions, ICE candidates and the ICE and DTLS transports."
},
{
"title": "Data channels",
"parent": "Python API",
"purpose": "RTCDataChannel and RTCSctpTransport: text and binary messages, reliability options, negotiated channels and back pressure."
},
{
"title": "Events",
"parent": "Python API",
"purpose": "The event targets in `webrtc/utils/events.py`: registering handlers with `on` and `once`, coroutine handlers, decorators, and the event objects."
},
{
"title": "Media tracks and transceivers",
"parent": "Python API",
"purpose": "MediaStream, MediaStreamTrack, the synthetic camera and microphone of MediaDevices, track constraints, transceivers, senders, receivers and RTP parameters."
},
{
"title": "Media processing",
"parent": "Python API",
"purpose": "Reading and writing frames: MediaStreamTrackProcessor, VideoTrackGenerator and MediaStreamTrackGenerator, VideoFrame and AudioData, and the streams in `webrtc/streams.py`."
},
{
"title": "Encoded transforms and SFrame",
"parent": "Python API",
"purpose": "RTCRtpScriptTransform and encoded frames, and end-to-end encryption with the SFrame transforms."
},
{
"title": "Stats",
"parent": "Python API",
"purpose": "`get_stats` and the stats dictionaries of WebRTC Statistics in `webrtc/models/rtc_stats.py`."
},
{
"title": "Field trials and WARP",
"parent": "Python API",
"purpose": "FieldTrials, which turns on experimental features of the engine, and WARP (DTLS 1.3, SNAP and SPED) for faster connection setup."
},
{
"title": "Codecs and H.264",
"purpose": "The supported codecs, the video codec factories in `cpp/src/codecs`, VideoToolbox on macOS, and the OpenH264 binary downloaded at runtime by `webrtc/openh264.py`."
},
{
"title": "aiortc compatibility layer",
"purpose": "`webrtc.aiortc`, which runs code written for aiortc on this engine, and the differences documented in docs/source/guides/aiortc.md."
},
{
"title": "Native extension",
"purpose": "The pybind11 module in `python-webrtc/cpp/src`: its modules (interfaces, media, codecs, models, utils) and how Python wrappers map to native objects."
},
{
"title": "Threads, the Dispatcher and mailboxes",
"parent": "Native extension",
"purpose": "The threading model of `python-webrtc/cpp/NATIVE.md`: libwebrtc's threads, mailboxes of event loops, the Dispatcher, locking rules and free-threaded Python."
},
{
"title": "Ownership and lifetime",
"parent": "Native extension",
"purpose": "Who owns native objects and when they are released, as described in the Ownership and Lifetime sections of `python-webrtc/cpp/NATIVE.md` and in `webrtc/utils/lifetime.py`."
},
{
"title": "Build and release",
"purpose": "Building from sources with scikit-build-core and CMake, the prebuilt libwebrtc downloaded by `cmake/libwebrtc.cmake`, wheels built with cibuildwheel, and the steps in CONTRIBUTING.md."
},
{
"title": "Testing",
"purpose": "The pytest suite in `tests`, the web-platform-tests in `tests/wpt`, the WebIDL comparison in `tests/idl`, fuzzing in `tests/fuzz`, and the sanitizer and clang-tidy scripts in `.github/scripts`."
},
{
"title": "Benchmarks",
"purpose": "The benchmark suites and drivers in `benchmarks`, their method and caveats from benchmarks/README.md, and the results in benchmarks/RESULTS.md."
},
{
"title": "Examples",
"purpose": "The runnable programs in `examples`: the echo peer, the recorder, the Janus live stream in the terminal and the voice chat with OpenAI."
}
]
}
17 changes: 17 additions & 0 deletions context7.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"$schema": "https://context7.com/schema/context7.json",
"projectTitle": "Python WebRTC",
"description": "Chrome's WebRTC engine (libwebrtc M152) with the W3C browser API, in Python and asyncio: peer connections, data channels, tracks, WebCodecs frames, encoded transforms and stats.",
"folders": ["docs/source", "examples"],
"excludeFolders": ["docs/source/_static"],
"excludeFiles": ["LICENSE.md", "THIRD_PARTY_LICENSES.md", "llms-txt.md"],
"rules": [
"Install with `pip install wrtc` and import as `webrtc`.",
"The API is the browser's WebRTC API with snake_case names: `pc.create_offer()`, `pc.set_local_description(offer)`, `pc.create_data_channel('chat')`.",
"Methods that return a promise in the browser are coroutines: await them inside a running asyncio event loop.",
"Register handlers with `target.on('event', handler)` or the `@target.on('event')` decorator; handlers can be coroutines.",
"Dictionaries are dataclasses: `webrtc.RTCConfiguration(ice_servers=[webrtc.RTCIceServer(urls='stun:stun.l.google.com:19302')])`.",
"Close connections with `pc.close()` when done.",
"To run code written for aiortc, install `wrtc[aiortc]` and change `from aiortc` to `from webrtc.aiortc`."
]
}
50 changes: 50 additions & 0 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from pathlib import Path
from typing import TYPE_CHECKING

from docutils import nodes
from pygments.formatters import HtmlFormatter
from sphinx.ext.autodoc.mock import mock
from sphinxawesome_theme.postprocess import Icons
Expand Down Expand Up @@ -54,6 +55,7 @@
'sphinx_sitemap',
'sphinx_favicon',
'myst_parser',
'sphinx_llm.txt',
]

DOCSEARCH_APP_ID = os.environ.get('DOCSEARCH_APP_ID')
Expand Down Expand Up @@ -198,6 +200,14 @@
# -- Sitemap ---------------------------------------------------
sitemap_locales = [None]
sitemap_url_scheme = '{link}'
sitemap_excludes = ['llms-txt/']

# -- llms.txt ---------------------------------------------------
# a Markdown copy of every page, e.g. /quickstart.md, for agents
llms_txt_override_source = 'llms-txt'
llms_txt_nested_enabled = False
llms_txt_full_build = True
LLMS_MARKDOWN_BUILDER = 'llms-markdown'

# -- Favicons ---------------------------------------------------
favicons = [
Expand Down Expand Up @@ -374,8 +384,48 @@ def scope_pygments_to_theme(app: Sphinx, exception: Exception | None) -> None:
(Path(app.outdir) / '_static' / 'pygments.css').write_text('\n'.join(blocks), encoding='UTF-8')


def _design_components(root: nodes.Element, component: str) -> list[nodes.container]:
return [node for node in root.findall(nodes.container) if node.get('design_component') == component]


def _flat_card(card: nodes.container) -> list[nodes.Node]:
"""A card as its title, linked to the card's target, and its text."""
title = next(iter(_design_components(card, 'card-title')), None)
links = [node for node in card.findall(nodes.reference) if 'sd-stretched-link' in node['classes']]

label: nodes.Element = nodes.strong(text=title.astext().strip() if title else '')
if links:
target = {key: links[0][key] for key in ('refuri', 'refid', 'internal') if key in links[0]}
label = nodes.reference('', '', label, **target)

body = next(iter(_design_components(card, 'card-body')), None)
text = [child.deepcopy() for child in body.children if child is not title] if body else []
return [nodes.paragraph('', '', label), *text]


def simplify_for_markdown(app: Sphinx, doctree: nodes.document, _docname: str) -> None:
"""Rewrite the nodes the Markdown builder of llms.txt drops or can't render.

Cards become a linked title and their text, captions of code blocks a line above them, and the raw HTML of icons,
the abbreviations of signatures and the meta tags are dropped.
"""
if app.builder.name != LLMS_MARKDOWN_BUILDER:
return

for node in [*doctree.findall(nodes.raw), *doctree.findall(nodes.meta)]:
if node.parent is not None:
node.parent.remove(node)
for abbreviation in list(doctree.findall(nodes.abbreviation)):
abbreviation.replace_self(nodes.Text(abbreviation.astext()))
for caption in list(doctree.findall(nodes.caption)):
caption.replace_self(nodes.paragraph('', '', nodes.literal(text=caption.astext())))
for card in _design_components(doctree, 'card'):
card.replace_self(_flat_card(card))


def setup(app: Sphinx) -> None:
"""Connects the handlers of the build events."""
app.connect('doctree-resolved', simplify_for_markdown)
app.connect('builder-inited', disable_search_index)
app.connect('autodoc-skip-member', skip_member)
# after Napoleon, which connects at the default priority
Expand Down
66 changes: 66 additions & 0 deletions docs/source/llms-txt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
orphan: true
nosearch: true
---

# Python WebRTC

> Chrome's WebRTC engine (libwebrtc M152) with the W3C browser API, in Python and asyncio. Install it with
> `pip install wrtc` and import it as `webrtc`.

Pages describing it as bindings to WebRTC M92 that aren't ready for use are about its versions from 2023 and are out
of date.

- The API is the one of the browsers: `RTCPeerConnection`, `RTCDataChannel`, tracks, `MediaStreamTrackProcessor`,
`VideoTrackGenerator`, encoded transforms and stats. Names are snake_case (`create_offer`), and the camelCase
originals (`createOffer`) work too.
- Handlers are registered with `on`, as a call or a decorator, and can be coroutines.
- Dictionaries are typed dataclasses, and enums compare equal to the strings of the specifications.
- Code written for aiortc runs after installing `wrtc[aiortc]` and changing `from aiortc` to `from webrtc.aiortc`.
- Prebuilt wheels for CPython 3.9 to 3.15 and free-threaded 3.14t and 3.15t, on Linux, macOS and Windows.

## Start

- {doc}`Quickstart <quickstart>`: installation, and two peers connected with a data channel.
- {doc}`Migrating from aiortc <guides/aiortc>`: run aiortc code by changing its imports, and what changes on the way.

## Guides

- {doc}`Connections <guides/connections>`: configuration, STUN and TURN servers, signalling, states and stats.
- {doc}`Data channels <guides/data-channels>`: text and binary messages, reliability, negotiated channels, back
pressure.
- {doc}`Events <guides/events>`: handlers as functions or coroutines, decorators, one-shot handlers, removing them.
- {doc}`Media <guides/media>`: reading, writing and transforming the frames of audio and video tracks.
- {doc}`H.264 <guides/h264>`: VideoToolbox on macOS, Cisco's OpenH264 binary elsewhere, and its licensing.
- {doc}`Field trials <guides/field-trials>`: experimental features of the engine, and WARP for faster connections.

## API reference

- {doc}`API reference <api/index>`: every interface, dictionary, enum and exception.
- {doc}`RTCPeerConnection <api/interfaces/rtc_peer_connection>`: the connection to a remote peer.
- {doc}`RTCDataChannel <api/interfaces/rtc_data_channel>`: text and binary messages over SCTP.
- {doc}`RTCConfiguration <api/models/rtc_configuration>`: the configuration of a connection and its ICE servers.
- {doc}`RTCSessionDescriptionInit <api/models/rtc_session_description_init>`: offers and answers as plain data, to
exchange over signalling.
- {doc}`MediaStreamTrack <api/interfaces/media_stream_track>`: tracks and the synthetic camera and microphone.
- {doc}`MediaStreamTrackProcessor <api/interfaces/media_stream_track_processor>`: reads the frames of a track.
- {doc}`Track generators <api/interfaces/track_generator>`: tracks of frames the application writes.
- {doc}`VideoFrame <api/models/video_frame>` and {doc}`AudioData <api/models/audio_data>`: the frames of WebCodecs.
- {doc}`Event objects <api/models/events>`: the events handlers are called with.
- {doc}`Stats <api/models/rtc_stats>`: the dictionaries of WebRTC Statistics.
- {doc}`Enums <api/enums>` and {doc}`Exceptions <api/exceptions>`.

## Examples

- {doc}`Echo peer <examples/echo>`: sends back the video it receives, in grayscale.
- {doc}`Recorder <examples/recorder>`: writes the video and audio a peer receives to files.
- {doc}`Live stream in the terminal <examples/janus_streaming>`: plays a stream of the public Janus demo server.
- {doc}`Voice chat with OpenAI GPT-Live <examples/openai_live>`: talks to the model through the microphone and
speakers.

## Optional

- [llms-full.txt](https://wrtc.marshal.dev/llms-full.txt): the whole documentation in one file.
- {doc}`Benchmarks <benchmarks>`: connection setup, data channels, memory and media against other libraries.
- {doc}`Change Log <change_log>`: what changed in each release.
- {doc}`Security Policy <security>`: supported versions and reporting vulnerabilities.
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,15 @@ docs = [
"sphinx-docsearch==0.3.1; python_version >= '3.12'",
"sphinx-favicon==1.1.0; python_version >= '3.12'",
"sphinxext-opengraph==0.13.0; python_version >= '3.12'",
"sphinx-llm==1.1.0; python_version >= '3.12'",
]

[tool.scikit-build]
minimum-version = "build-system.requires"
cmake.version = ">=3.26"
build-dir = "build/{wheel_tag}"
wheel.packages = ["python-webrtc/python/webrtc"]
sdist.exclude = [".github", ".idea", "benchmarks", "docs", "examples", "wpt"]
sdist.exclude = [".github", ".idea", "benchmarks", "docs", "examples", "wpt", ".devin", "context7.json"]

[tool.cibuildwheel]
# free-threaded from 3.14, where it's no longer experimental
Expand Down
Loading
Loading