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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,6 @@ jobs:
with:
path: dist
merge-multiple: true
- uses: pypa/[email protected].2
- uses: pypa/[email protected].3
with:
skip-existing: true
4 changes: 2 additions & 2 deletions benchmarks/drivers/webrtc-rs/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 31 additions & 1 deletion docs/source/_static/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,36 @@ dl.py > dt .sig-prename {
overflow-wrap: anywhere;
}

/* Long names in prose would scroll the page sideways on phones. */
#content {
overflow-wrap: anywhere;
}

#content code.literal .pre {
white-space: pre-wrap;
}

/* Tables scroll instead. */
#content table {
overflow-wrap: normal;
}

/* The previous and next links: long titles wrap instead of widening the page. */
main .border-t.justify-between > div {
min-width: 0;
overflow-wrap: anywhere;
}

/* The muted link color is too faint on the code background. */
#right-sidebar a code {
background: transparent;
}

/* Inactive tab labels are too faint by default. */
.sd-tab-set {
--sd-color-tabs-label-inactive: hsl(var(--muted-foreground));
}

/* API signatures. */
:root {
--sig-accent: #b3123c;
Expand Down Expand Up @@ -54,7 +84,7 @@ dl.py a.reference .pre {
dl.py > dt .sig-prename {
font-size: 0.85em;
font-weight: 400;
opacity: 0.6;
color: hsl(var(--muted-foreground));
}

dl.py.class > dd {
Expand Down
51 changes: 39 additions & 12 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
suppress_warnings = ['myst.header', 'ref.python']

# -- Pygments ---------------------------------------------------
pygments_style = 'friendly'
pygments_style = 'xcode'
pygments_style_dark = 'monokai'

# -- MyST-Parser ---------------------------------------------------
Expand Down Expand Up @@ -205,7 +205,7 @@
# -- Sitemap ---------------------------------------------------
sitemap_locales = [None]
sitemap_url_scheme = '{link}'
sitemap_excludes = ['llms-txt/']
sitemap_excludes = ['llms-txt/', 'search/', 'genindex/']

# -- llms.txt ---------------------------------------------------
# a Markdown copy of every page, e.g. /quickstart.md, for agents
Expand Down Expand Up @@ -339,8 +339,35 @@ def hide_enum_signatures(
return None


def _add_alias(py_objects: dict[str, Any], name: str, target: str) -> None:
"""Make ``name`` resolve to the documented ``target``, unless it's documented itself."""
if name not in py_objects:
entry = py_objects[target]
py_objects[name] = entry.__class__(entry.docname, entry.node_id, entry.objtype, aliased=True)


def _alias_class(py_objects: dict[str, Any], short: str, cls: type) -> None:
"""Alias a class and its members to ``short``, and the documented members of its bases to both names."""
canonical = f'{cls.__module__}.{cls.__qualname__}'
if canonical not in py_objects:
return

_add_alias(py_objects, short, canonical)

# the nearest definition wins, as in the class
for owner in inspect.getmro(cls):
owner_canonical = f'{owner.__module__}.{owner.__qualname__}'
members = [key[len(owner_canonical) :] for key in py_objects if key.startswith(f'{owner_canonical}.')]
for member in members:
_add_alias(py_objects, f'{canonical}{member}', f'{owner_canonical}{member}')
_add_alias(py_objects, f'{short}{member}', f'{owner_canonical}{member}')


def register_short_aliases(app: Sphinx, env: BuildEnvironment) -> None:
"""Resolve ``webrtc.X`` references to the module the object is documented in."""
"""Resolve ``webrtc.X`` references to the module the object is documented in.

A class also gets the documented members of its bases, like ``from_json`` of every dictionary.
"""
# parallel builds import the package in the workers only
with mock(app.config.autodoc_mock_imports):
import webrtc # ruff: ignore[import-outside-top-level]
Expand All @@ -349,17 +376,17 @@ def register_short_aliases(app: Sphinx, env: BuildEnvironment) -> None:
for name in webrtc.__all__:
obj = getattr(webrtc, name, None)
module = getattr(obj, '__module__', None)
if not module or module == 'webrtc' or not (inspect.isclass(obj) or inspect.isfunction(obj)):
if not module or module == 'webrtc':
continue

if inspect.isclass(obj):
_alias_class(py_objects, f'webrtc.{name}', obj)
continue

canonical = f'{module}.{obj.__qualname__}'
# the object and its members
targets = [key for key in py_objects if key == canonical or key.startswith(f'{canonical}.')]
for target in targets:
short = f'webrtc.{name}{target[len(canonical) :]}'
if short not in py_objects:
entry = py_objects[target]
py_objects[short] = entry.__class__(entry.docname, entry.node_id, entry.objtype, aliased=True)
# a function, or a module-level instance like field_trials
canonical = f'{module}.{obj.__qualname__}' if inspect.isfunction(obj) else f'{module}.{name}'
if canonical in py_objects:
_add_alias(py_objects, f'webrtc.{name}', canonical)


def disable_search_index(app: Sphinx) -> None:
Expand Down
2 changes: 1 addition & 1 deletion docs/source/guides/comparison.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ webrtcbin. This page compares them as of 24 October 2026, with a source for ever

## Features

| | **Python WebRTC** | aiortc | LiveKit SDK | GStreamer webrtcbin |
| Feature | **Python WebRTC** | aiortc | LiveKit SDK | GStreamer webrtcbin |
|---------------------------|----------------------------|--------------------------|------------------------------|-----------------------|
| Engine | libwebrtc M152 | own, in Python | libwebrtc M150, through Rust | own, in C |
| Connects to | any WebRTC endpoint | any WebRTC endpoint | a LiveKit server | any WebRTC endpoint |
Expand Down
2 changes: 1 addition & 1 deletion docs/source/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ Prebuilt wheels for Linux, macOS and Windows, including free-threaded Python. No

## How it compares

| | **Python WebRTC** | aiortc | LiveKit SDK | GStreamer webrtcbin |
| Feature | **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 | ✅ |
Expand Down
1 change: 1 addition & 0 deletions python-webrtc/python/webrtc/interfaces/field_trials.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ def update(

@override
def clear(self) -> None:
"""Removes all trials at once."""
_apply({})

@override
Expand Down
6 changes: 3 additions & 3 deletions python-webrtc/python/webrtc/interfaces/rtc_peer_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -800,7 +800,7 @@ async def get_stats(self, selector: webrtc.MediaStreamTrack | None = None) -> we

@staticmethod
async def generate_certificate(keygen_algorithm: AlgorithmIdentifier) -> webrtc.RTCCertificate:
"""Generates a key and a self-signed certificate on a worker thread, for :attr:`RTCConfiguration.certificates`.
"""Generates a key and a self-signed certificate on a worker thread, for ``RTCConfiguration.certificates``.

See :mdn:`RTCPeerConnection/generateCertificate_static`.

Expand Down Expand Up @@ -843,8 +843,8 @@ def set_configuration(self, configuration: webrtc.RTCConfiguration | None = None
Raises:
webrtc.InvalidStateError: If the connection is closed.
webrtc.InvalidModificationError: If a member that can't be changed differs, like
:attr:`webrtc.RTCConfiguration.bundle_policy` or
:attr:`webrtc.RTCConfiguration.always_negotiate_data_channels`.
``webrtc.RTCConfiguration.bundle_policy`` or
``webrtc.RTCConfiguration.always_negotiate_data_channels``.
webrtc.InvalidSyntaxError: If an ICE server URL is invalid.
webrtc.InvalidAccessError: If a TURN server has no credentials, or a certificate has expired.
ValueError: If a member of the configuration is out of range.
Expand Down
6 changes: 3 additions & 3 deletions python-webrtc/python/webrtc/interfaces/sframe_transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ def _decrypt(self, data: Buffer, frame: RTCEncodedVideoFrame | RTCEncodedAudioFr


class _SFrameStream(WebRTCObject[wrtc.SFrameTransform], Generic[_C]):
"""A GenericTransformStream of SFrame. Frames or buffers written to :attr:`writable` are read back transformed.
"""A GenericTransformStream of SFrame. Frames or buffers written to ``writable`` are read back transformed.

The type parameter is its chunk type. It's encoded frames by default, to match the streams of the transformer
it's piped between. Use ``bytes`` for buffers, as in ``SFrameEncryptorStream[bytes]``, or :obj:`SFrameChunk`
Expand Down Expand Up @@ -328,7 +328,7 @@ def writable(self) -> WritableStream[_C | Buffer]:
class SFrameEncryptorStream(_SFrameEncryptorManager, _SFrameStream[_C]):
"""A transform stream that encrypts the frames or buffers written to it with SFrame.

It has :attr:`readable` and :attr:`writable` like a :obj:`webrtc.TransformStream`, so it can be piped through in
It has ``readable`` and ``writable`` like a :obj:`webrtc.TransformStream`, so it can be piped through in
the worker of an :obj:`webrtc.RTCRtpScriptTransform`. A frame comes out with its data encrypted, and a buffer
comes out as the :obj:`bytes` of the ciphertext. Until a key is set, chunks are dropped. The type parameter is
the output type. It's encoded frames by default, and ``SFrameEncryptorStream[bytes]`` handles buffers.
Expand Down Expand Up @@ -359,7 +359,7 @@ class SFrameDecryptorStream(
):
"""A transform stream that decrypts the SFrame frames or buffers written to it.

It has :attr:`readable` and :attr:`writable` like a :obj:`webrtc.TransformStream`. A frame comes out with its
It has ``readable`` and ``writable`` like a :obj:`webrtc.TransformStream`. A frame comes out with its
data decrypted, and a buffer comes out as the :obj:`bytes` of the plaintext. A chunk that fails to decrypt is
dropped and reported by an ``error`` event. The type parameter is the output type. It's encoded frames by
default, and ``SFrameDecryptorStream[bytes]`` handles buffers.
Expand Down
6 changes: 3 additions & 3 deletions python-webrtc/python/webrtc/models/media_track_constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ class MediaTrackSupportedConstraints(Dictionary):
"""The constraints the library recognizes, as :meth:`webrtc.MediaDevices.get_supported_constraints` returns.

Every member is :obj:`True`. A recognized constraint that the source has no capability or setting for (like
:attr:`facing_mode` on the synthetic camera) is ignored when ideal and fails when required.
``facing_mode`` on the synthetic camera) is ignored when ideal and fails when required.

See :mdn:`MediaDevices/getSupportedConstraints`.

Expand Down Expand Up @@ -213,7 +213,7 @@ class MediaTrackSettings(Dictionary):
"""What a track carries now, as :meth:`webrtc.MediaStreamTrack.get_settings` returns.

Members are :obj:`None` when they don't apply to the track or aren't known yet. The library never fills
:attr:`facing_mode` or :attr:`background_blur`.
``facing_mode`` or ``background_blur``.

See :mdn:`MediaTrackSettings`.

Expand Down Expand Up @@ -471,7 +471,7 @@ class MediaTrackConstraints(MediaTrackConstraintSet):
"""The constraints of a track, as given to :meth:`webrtc.MediaStreamTrack.apply_constraints`.

They're also given per track to :meth:`webrtc.MediaDevices.get_user_media`. The members are the ones of
:obj:`MediaTrackConstraintSet`, plus :attr:`advanced`.
:obj:`MediaTrackConstraintSet`, plus ``advanced``.

See :mdn:`MediaTrackConstraints`.

Expand Down
2 changes: 1 addition & 1 deletion python-webrtc/python/webrtc/models/rtc_certificate.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ class RTCCertificate(WebRTCObject[wrtc.RTCCertificate]):
"""A certificate and its private key, which a connection authenticates with in DTLS.

Only :meth:`webrtc.RTCPeerConnection.generate_certificate` creates it, and a connection uses it through
:attr:`webrtc.RTCConfiguration.certificates`. A connection without one generates its own.
``webrtc.RTCConfiguration.certificates``. A connection without one generates its own.
See :mdn:`RTCCertificate`.
"""

Expand Down
4 changes: 2 additions & 2 deletions python-webrtc/python/webrtc/models/rtc_encoded_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,9 @@ class RTCEncodedVideoFrameMetadata(RTCEncodedFrameMetadata):
See :mdn:`RTCEncodedVideoFrame/getMetadata`.

Args:
frame_id (:obj:`int`, optional): The identifier of the frame, which :attr:`dependencies` of later frames
frame_id (:obj:`int`, optional): The identifier of the frame, which ``dependencies`` of later frames
refer to.
dependencies (:obj:`list` of :obj:`int`, optional): The :attr:`frame_id` values of the frames this one
dependencies (:obj:`list` of :obj:`int`, optional): The ``frame_id`` values of the frames this one
depends on.
width (:obj:`int`, optional): The width of the frame, in pixels.
height (:obj:`int`, optional): The height of the frame, in pixels.
Expand Down
4 changes: 2 additions & 2 deletions python-webrtc/python/webrtc/models/rtc_ice_candidate.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ class RTCIceCandidate:

A :obj:`webrtc.RTCPeerConnection` gathers them (see its ``icecandidate`` event). Each one is sent to the remote
peer and added there with :meth:`webrtc.RTCPeerConnection.add_ice_candidate`. The constructor doesn't reject an
unparsable :attr:`candidate`, and the properties parsed from it are :obj:`None` then. Instances are immutable.
unparsable ``candidate``, and the properties parsed from it are :obj:`None` then. Instances are immutable.

See :mdn:`RTCIceCandidate`.

Expand Down Expand Up @@ -414,7 +414,7 @@ def port(self) -> int | None:

@property
def type(self) -> RTCIceCandidateType | None:
""":obj:`webrtc.RTCIceCandidateType`, optional: How the candidate was found: host, reflexive or relay.
""":obj:`webrtc.RTCIceCandidateType`, optional: How the candidate was found, as host, reflexive or relay.

See :mdn:`RTCIceCandidate/type`.
"""
Expand Down
2 changes: 1 addition & 1 deletion python-webrtc/python/webrtc/models/rtp_parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ def _from_native(cls, native: wrtc.RtpParameters) -> RTCRtpReceiveParameters:
class RTCRtpSendParameters(RTCRtpParameters):
"""The parameters a sender sends with, from :meth:`webrtc.RTCRtpSender.get_parameters`.

Only :attr:`encodings` (all but their ``rid``) and :attr:`degradation_preference` can be changed with
Only ``encodings`` (all but their ``rid``) and ``degradation_preference`` can be changed with
:meth:`webrtc.RTCRtpSender.set_parameters`.

See :mdn:`RTCRtpSender/getParameters`.
Expand Down
10 changes: 5 additions & 5 deletions python-webrtc/python/webrtc/models/video_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
class DOMRectReadOnly:
"""An immutable rectangle, like the coded or visible part of a frame.

The width and height may be negative. The edges are then measured from :attr:`x` and :attr:`y` backwards.
The width and height may be negative. The edges are then measured from ``x`` and ``y`` backwards.

See :mdn:`DOMRectReadOnly`.

Expand All @@ -74,31 +74,31 @@ class DOMRectReadOnly:

@property
def top(self) -> float:
""":obj:`float`: The smaller of :attr:`y` and :attr:`y` plus :attr:`height`.
""":obj:`float`: The smaller of ``y`` and ``y`` plus ``height``.

See :mdn:`DOMRectReadOnly/top`.
"""
return min(self.y, self.y + self.height)

@property
def right(self) -> float:
""":obj:`float`: The larger of :attr:`x` and :attr:`x` plus :attr:`width`.
""":obj:`float`: The larger of ``x`` and ``x`` plus ``width``.

See :mdn:`DOMRectReadOnly/right`.
"""
return max(self.x, self.x + self.width)

@property
def bottom(self) -> float:
""":obj:`float`: The larger of :attr:`y` and :attr:`y` plus :attr:`height`.
""":obj:`float`: The larger of ``y`` and ``y`` plus ``height``.

See :mdn:`DOMRectReadOnly/bottom`.
"""
return max(self.y, self.y + self.height)

@property
def left(self) -> float:
""":obj:`float`: The smaller of :attr:`x` and :attr:`x` plus :attr:`width`.
""":obj:`float`: The smaller of ``x`` and ``x`` plus ``width``.

See :mdn:`DOMRectReadOnly/left`.
"""
Expand Down
4 changes: 2 additions & 2 deletions python-webrtc/python/webrtc/streams.py
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ class ReadableStreamReadResult(Dictionary, Generic[_T]):
See :mdn:`ReadableStreamDefaultReader/read`.

Args:
value (optional): The chunk read. It's :obj:`None` when :attr:`done` is set.
value (optional): The chunk read. It's :obj:`None` when ``done`` is set.
done (:obj:`bool`, optional): :obj:`True` once the stream is closed and every chunk was read.
"""

Expand Down Expand Up @@ -696,7 +696,7 @@ def pipe_to(
"""Reads every chunk and writes it to a writable stream, respecting its backpressure.

Both streams are locked while the pipe runs. There's no abort signal, so cancel the returned future to stop
the pipe. The destination is then aborted unless :attr:`StreamPipeOptions.prevent_abort` is set.
the pipe. The destination is then aborted unless ``StreamPipeOptions.prevent_abort`` is set.

See :mdn:`ReadableStream/pipeTo`.

Expand Down
6 changes: 3 additions & 3 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading