diff --git a/.gitattributes b/.gitattributes
index 52b735b3..9b4c18b0 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,5 +1,6 @@
**/*.dll filter=lfs diff=lfs merge=lfs -text
**/*.so filter=lfs diff=lfs merge=lfs -text
**/*.dylib filter=lfs diff=lfs merge=lfs -text
+**/*.jpg filter=lfs diff=lfs merge=lfs -text
livekit-protocol/livekit/protocol/** linguist-generated=true
livekit-rtc/livekit/rtc/_proto/** linguist-generated=true
diff --git a/.github/banner_dark.png b/.github/banner_dark.png
index a80f87f1..766f636c 100644
Binary files a/.github/banner_dark.png and b/.github/banner_dark.png differ
diff --git a/.github/banner_light.png b/.github/banner_light.png
index de0d1dbd..02539b12 100644
Binary files a/.github/banner_light.png and b/.github/banner_light.png differ
diff --git a/.github/update_versions.py b/.github/update_versions.py
new file mode 100644
index 00000000..691fd8a5
--- /dev/null
+++ b/.github/update_versions.py
@@ -0,0 +1,149 @@
+import pathlib
+import re
+import click
+from packaging.version import Version
+
+PACKAGES = {
+ "livekit": "livekit-rtc/livekit/rtc/version.py",
+ "livekit-api": "livekit-api/livekit/api/version.py",
+ "livekit-protocol": "livekit-protocol/livekit/protocol/version.py",
+}
+
+TAG_PREFIXES = {
+ "livekit": "rtc",
+ "livekit-api": "api",
+ "livekit-protocol": "protocol",
+}
+
+
+def _esc(*codes: int) -> str:
+ return "\033[" + ";".join(str(c) for c in codes) + "m"
+
+
+def read_version(f: pathlib.Path) -> str:
+ text = f.read_text()
+ m = re.search(r'__version__\s*=\s*[\'"]([^\'"]+)[\'"]', text)
+ if not m:
+ raise ValueError(f"could not find __version__ in {f}")
+ return m.group(1)
+
+
+def write_new_version(f: pathlib.Path, new_version: str) -> None:
+ text = f.read_text()
+ new_text = re.sub(
+ r'__version__\s*=\s*[\'"][^\'"]*[\'"]',
+ f'__version__ = "{new_version}"',
+ text,
+ count=1,
+ )
+ f.write_text(new_text)
+
+
+def bump_version(cur: str, bump_type: str) -> str:
+ v = Version(cur)
+ if bump_type == "release":
+ return v.base_version
+ if bump_type == "patch":
+ return f"{v.major}.{v.minor}.{v.micro + 1}"
+ if bump_type == "minor":
+ return f"{v.major}.{v.minor + 1}.0"
+ if bump_type == "major":
+ return f"{v.major + 1}.0.0"
+ raise ValueError(f"unknown bump type: {bump_type}")
+
+
+def bump_prerelease(cur: str, bump_type: str) -> str:
+ v = Version(cur)
+ base = v.base_version
+ if bump_type == "rc":
+ if v.pre and v.pre[0] == "rc":
+ next_rc = v.pre[1] + 1
+ else:
+ next_rc = 1
+ return f"{base}.rc{next_rc}"
+ raise ValueError(f"unknown prerelease bump type: {bump_type}")
+
+
+def update_api_protocol_dependency(new_protocol_version: str) -> None:
+ """Update livekit-api's dependency on livekit-protocol."""
+ pyproject = pathlib.Path("livekit-api/pyproject.toml")
+ if not pyproject.exists():
+ return
+ old_text = pyproject.read_text()
+ new_text = re.sub(
+ r'"livekit-protocol>=[\w.\-]+,',
+ f'"livekit-protocol>={new_protocol_version},',
+ old_text,
+ )
+ if new_text != old_text:
+ pyproject.write_text(new_text)
+ print(f"Updated livekit-api dependency on livekit-protocol to >={new_protocol_version}")
+
+
+def do_bump(package: str, bump_type: str) -> None:
+ version_path = PACKAGES[package]
+ vf = pathlib.Path(version_path)
+ cur = read_version(vf)
+ new = bump_version(cur, bump_type)
+ print(f"{package}: {_esc(31)}{cur}{_esc(0)} -> {_esc(32)}{new}{_esc(0)}")
+ write_new_version(vf, new)
+
+ if package == "livekit-protocol":
+ update_api_protocol_dependency(new)
+
+
+def do_prerelease(package: str, prerelease_type: str) -> None:
+ version_path = PACKAGES[package]
+ vf = pathlib.Path(version_path)
+ cur = read_version(vf)
+ new = bump_prerelease(cur, prerelease_type)
+ print(f"{package}: {_esc(31)}{cur}{_esc(0)} -> {_esc(32)}{new}{_esc(0)}")
+ write_new_version(vf, new)
+
+ if package == "livekit-protocol":
+ update_api_protocol_dependency(new)
+
+
+@click.command()
+@click.option(
+ "--package",
+ type=click.Choice(list(PACKAGES.keys())),
+ required=True,
+ help="Package to bump.",
+)
+@click.option(
+ "--pre",
+ type=click.Choice(["rc", "none"]),
+ default="none",
+ help="Pre-release type.",
+)
+@click.option(
+ "--bump-type",
+ type=click.Choice(["patch", "minor", "major", "release"]),
+ default="patch",
+ help="Type of version bump.",
+)
+@click.option(
+ "--print-version",
+ is_flag=True,
+ default=False,
+ help="Print current version and tag prefix, don't bump.",
+)
+def bump(package: str, pre: str, bump_type: str, print_version: bool) -> None:
+ if print_version:
+ vf = pathlib.Path(PACKAGES[package])
+ version = read_version(vf)
+ tag_prefix = TAG_PREFIXES[package]
+ # Output as key=value for easy parsing
+ print(f"version={version}")
+ print(f"tag_prefix={tag_prefix}")
+ return
+
+ if pre == "none":
+ do_bump(package, bump_type)
+ else:
+ do_prerelease(package, pre)
+
+
+if __name__ == "__main__":
+ bump()
diff --git a/.github/workflows/build-api.yml b/.github/workflows/build-api.yml
index 5f47f74d..d2e112f2 100644
--- a/.github/workflows/build-api.yml
+++ b/.github/workflows/build-api.yml
@@ -26,18 +26,18 @@ jobs:
run:
working-directory: ${{ env.PACKAGE_DIR }}
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
submodules: true
- - uses: actions/setup-python@v4
+ - uses: actions/setup-python@7f4fc3e22c37d6ff65e88745f38bd3157c663f7c # v4
- name: Build wheel & sdist
run: |
pip3 install build wheel
python3 -m build --wheel --sdist
- - uses: actions/upload-artifact@v3
+ - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: api-release
path: |
@@ -50,17 +50,14 @@ jobs:
runs-on: ubuntu-latest
permissions:
id-token: write
- if: startsWith(github.ref, 'refs/tags/api-v')
+ if: startsWith(github.ref, 'refs/tags/api-v') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false)
steps:
- - uses: actions/download-artifact@v3
+ - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: api-release
path: dist
- - uses: pypa/gh-action-pypi-publish@release/v1
- with:
- user: __token__
- password: ${{ secrets.PYPI_API_TOKEN }}
+ - uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1
docs:
needs: [publish]
diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml
index 99bd94ec..d358a164 100644
--- a/.github/workflows/build-docs.yml
+++ b/.github/workflows/build-docs.yml
@@ -1,12 +1,4 @@
-# This workflow will upload a Python Package using Twine when a release is created
-# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries
-
-# This workflow uses actions that are not certified by GitHub.
-# They are provided by a third-party and are governed by
-# separate terms of service, privacy policy, and support
-# documentation.
-
-name: Build Docs
+name: Build Docs
on:
workflow_dispatch:
@@ -45,29 +37,36 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
- with:
- submodules: recursive
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ with:
+ submodules: recursive
- - name: Install Package to Document
- run: python -m pip install ${{ inputs.package_dir }}/
+ - name: Install Package to Document
+ env:
+ PACKAGE_DIR: ${{ inputs.package_dir }}
+ run: python -m pip install "$PACKAGE_DIR/"
- - name: Download ffi
- run: |
- if [[ '${{ inputs.package_name }}' = 'livekit.rtc' ]]; then
- pip install requests
- python livekit-rtc/rust-sdks/download_ffi.py --output $(python -m site --user-site)/livekit/rtc/resources
- fi
+ - name: Download ffi
+ env:
+ PACKAGE_NAME: ${{ inputs.package_name }}
+ run: |
+ if [[ "$PACKAGE_NAME" = 'livekit.rtc' ]]; then
+ pip install requests
+ python livekit-rtc/rust-sdks/download_ffi.py --output "$(python -m site --user-site)/livekit/rtc/resources"
+ fi
- - name: Install pdoc
- run: pip install --upgrade pdoc
+ - name: Install pdoc
+ run: pip install --upgrade pdoc
- - name: Build Docs
- run: python -m pdoc ${{ inputs.package_name }} --docformat=google --output-dir docs
+ - name: Build Docs
+ env:
+ PACKAGE_NAME: ${{ inputs.package_name }}
+ run: python -m pdoc "$PACKAGE_NAME" --docformat=google --output-dir docs
- - name: S3 Upload
- run: aws s3 cp docs/ s3://livekit-docs/${{ inputs.package_dir }} --recursive
- env:
- AWS_ACCESS_KEY_ID: ${{ secrets.DOCS_DEPLOY_AWS_ACCESS_KEY }}
- AWS_SECRET_ACCESS_KEY: ${{ secrets.DOCS_DEPLOY_AWS_API_SECRET }}
- AWS_DEFAULT_REGION: "us-east-1"
\ No newline at end of file
+ - name: S3 Upload
+ env:
+ PACKAGE_DIR: ${{ inputs.package_dir }}
+ AWS_ACCESS_KEY_ID: ${{ secrets.DOCS_DEPLOY_AWS_ACCESS_KEY }}
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.DOCS_DEPLOY_AWS_API_SECRET }}
+ AWS_DEFAULT_REGION: "us-east-1"
+ run: aws s3 cp docs/ "s3://livekit-docs/$PACKAGE_DIR" --recursive
diff --git a/.github/workflows/build-protocol.yml b/.github/workflows/build-protocol.yml
index 23ff014f..b6cd615f 100644
--- a/.github/workflows/build-protocol.yml
+++ b/.github/workflows/build-protocol.yml
@@ -28,24 +28,24 @@ jobs:
run:
working-directory: ${{ env.PACKAGE_DIR }}
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
submodules: true
ref: ${{ github.event.pull_request.head.ref }}
- - uses: actions/setup-python@v4
+ - uses: actions/setup-python@7f4fc3e22c37d6ff65e88745f38bd3157c663f7c # v4
- name: Install Protoc
- uses: arduino/setup-protoc@v2
+ uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b # v3
with:
- version: "25.3"
+ version: "25.1"
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: generate python stubs
run: ./generate_proto.sh
- name: Add changes
- uses: EndBug/add-and-commit@v9
+ uses: EndBug/add-and-commit@a94899bca583c204427a224a7af87c02f9b325d5 # v9
with:
add: '["livekit-protocol/"]'
default_author: github_actions
@@ -58,18 +58,18 @@ jobs:
run:
working-directory: ${{ env.PACKAGE_DIR }}
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
submodules: true
- - uses: actions/setup-python@v4
+ - uses: actions/setup-python@7f4fc3e22c37d6ff65e88745f38bd3157c663f7c # v4
- name: Build wheel & sdist
run: |
pip3 install build wheel
python3 -m build --wheel --sdist
- - uses: actions/upload-artifact@v3
+ - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: protocol-release
path: |
@@ -82,17 +82,14 @@ jobs:
runs-on: ubuntu-latest
permissions:
id-token: write
- if: startsWith(github.ref, 'refs/tags/protocol-v')
+ if: startsWith(github.ref, 'refs/tags/protocol-v') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false)
steps:
- - uses: actions/download-artifact@v3
+ - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: protocol-release
path: dist
- - uses: pypa/gh-action-pypi-publish@release/v1
- with:
- user: __token__
- password: ${{ secrets.PYPI_API_TOKEN }}
+ - uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1
docs:
needs: [publish]
diff --git a/.github/workflows/build-rtc.yml b/.github/workflows/build-rtc.yml
index ac58b75b..9b721bb8 100644
--- a/.github/workflows/build-rtc.yml
+++ b/.github/workflows/build-rtc.yml
@@ -19,6 +19,42 @@ env:
PACKAGE_DIR: ./livekit-rtc
jobs:
+ generate_protobuf:
+ runs-on: ubuntu-latest
+ name: Generating protobuf
+ if: github.event_name == 'pull_request'
+
+ defaults:
+ run:
+ working-directory: ${{ env.PACKAGE_DIR }}
+ steps:
+ - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3
+ with:
+ submodules: true
+ ref: ${{ github.event.pull_request.head.ref }}
+
+ - uses: actions/setup-python@7f4fc3e22c37d6ff65e88745f38bd3157c663f7c # v4
+
+ - name: Install Protoc
+ uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b # v3
+ with:
+ version: "25.1"
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Install deps
+ run: |
+ pip3 install mypy-protobuf==3.6.0 "protobuf>=4.25.0,<5.0.0"
+
+ - name: generate python stubs
+ run: ./generate_proto.sh
+
+ - name: Add changes
+ uses: EndBug/add-and-commit@a94899bca583c204427a224a7af87c02f9b325d5 # v9
+ with:
+ add: '["livekit-rtc/"]'
+ default_author: github_actions
+ message: generated protobuf
+
build_wheels:
name: Build RTC wheels (${{ matrix.archs }})
runs-on: ${{ matrix.os }}
@@ -29,7 +65,7 @@ jobs:
include:
- os: ubuntu-latest
archs: x86_64
- - os: buildjet-4vcpu-ubuntu-2204-arm
+ - os: namespace-profile-default-arm64
archs: aarch64
- os: windows-latest
archs: AMD64
@@ -39,28 +75,23 @@ jobs:
run:
working-directory: ${{ env.PACKAGE_DIR }}
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
submodules: true
- - uses: actions/setup-python@v4
-
- - name: Install cibuildwheel
- if: runner.os != 'macOS'
- run: python3 -m pip install cibuildwheel==2.17.0
-
- - name: Install cibuildwheel on macOS
- if: runner.os == 'macOS'
- run: python3 -m pip install --break-system-packages cibuildwheel==2.17.0
+ - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
+ id: setup-python
+ with:
+ python-version: "3.11"
- name: Build wheels
- run: python3 -m cibuildwheel --output-dir dist
+ run: pipx run --python '${{ steps.setup-python.outputs.python-path }}' cibuildwheel==3.3.1 --output-dir dist
env:
CIBW_ARCHS: ${{ matrix.archs }}
- - uses: actions/upload-artifact@v3
+ - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
- name: rtc-release
+ name: rtc-release-${{ matrix.os }}
path: livekit-rtc/dist/*.whl
make_sdist:
@@ -70,7 +101,7 @@ jobs:
run:
working-directory: ${{ env.PACKAGE_DIR }}
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
submodules: true
@@ -79,28 +110,83 @@ jobs:
pip3 install build
python3 -m build --sdist
- - uses: actions/upload-artifact@v3
+ - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
- name: rtc-release
+ name: rtc-release-sdist
path: livekit-rtc/dist/*.tar.gz
+
+ test:
+ name: Test (${{ matrix.os }}, Python ${{ matrix.python-version }})
+ needs: [build_wheels]
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ # Linux x86_64 tests
+ - os: ubuntu-latest
+ python-version: "3.9"
+ artifact: rtc-release-ubuntu-latest
+ - os: ubuntu-latest
+ python-version: "3.10"
+ artifact: rtc-release-ubuntu-latest
+ - os: ubuntu-latest
+ python-version: "3.11"
+ artifact: rtc-release-ubuntu-latest
+ - os: ubuntu-latest
+ python-version: "3.12"
+ artifact: rtc-release-ubuntu-latest
+ - os: ubuntu-latest
+ python-version: "3.13"
+ artifact: rtc-release-ubuntu-latest
+ - os: ubuntu-latest
+ python-version: "3.14"
+ artifact: rtc-release-ubuntu-latest
+ # macOS tests (arm64 runner)
+ - os: macos-latest
+ python-version: "3.9"
+ artifact: rtc-release-macos-latest
+ - os: macos-latest
+ python-version: "3.12"
+ artifact: rtc-release-macos-latest
+ - os: macos-latest
+ python-version: "3.14"
+ artifact: rtc-release-macos-latest
+ # Windows tests
+ - os: windows-latest
+ python-version: "3.9"
+ artifact: rtc-release-windows-latest
+ - os: windows-latest
+ python-version: "3.12"
+ artifact: rtc-release-windows-latest
+ - os: windows-latest
+ python-version: "3.14"
+ artifact: rtc-release-windows-latest
+ uses: ./.github/workflows/tests.yml
+ with:
+ os: ${{ matrix.os }}
+ python-version: ${{ matrix.python-version }}
+ artifact-name: ${{ matrix.artifact }}
+ secrets:
+ LIVEKIT_URL: ${{ secrets.LIVEKIT_URL }}
+ LIVEKIT_API_KEY: ${{ secrets.LIVEKIT_API_KEY }}
+ LIVEKIT_API_SECRET: ${{ secrets.LIVEKIT_API_SECRET }}
+
publish:
name: Publish RTC release
- needs: [build_wheels, make_sdist]
+ needs: [build_wheels, make_sdist, test]
runs-on: ubuntu-latest
permissions:
id-token: write
- if: startsWith(github.ref, 'refs/tags/rtc-v')
+ if: startsWith(github.ref, 'refs/tags/rtc-v') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false)
steps:
- - uses: actions/download-artifact@v3
+ - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
- name: rtc-release
+ pattern: rtc-release-*
path: dist
+ merge-multiple: true
- - uses: pypa/gh-action-pypi-publish@release/v1
- with:
- user: __token__
- password: ${{ secrets.PYPI_API_TOKEN }}
+ - uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1
docs:
needs: [publish]
diff --git a/.github/workflows/check-types.yml b/.github/workflows/check-types.yml
index 2ebfa830..631c22d2 100644
--- a/.github/workflows/check-types.yml
+++ b/.github/workflows/check-types.yml
@@ -1,4 +1,4 @@
-name: Check Types
+name: Check Types
on:
push:
@@ -13,23 +13,29 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
- with:
- submodules: recursive
-
- - name: Set up Python 3.9
- uses: actions/setup-python@v2
- with:
- python-version: 3.9
-
- - name: Download ffi
- run: python -m pip install requests && python livekit-rtc/rust-sdks/download_ffi.py --output $(python -m site --user-site)/livekit/rtc/resources
-
- - name: Install mypy
- run: python -m pip install --upgrade mypy
-
- - name: Install packages
- run: python -m pip install ./livekit-api ./livekit-protocol ./livekit-rtc
-
- - name: Check Types
- run: python -m mypy --install-type --non-interactive -p 'livekit-protocol' -p 'livekit-api' -p 'livekit-rtc'
\ No newline at end of file
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ with:
+ submodules: recursive
+
+ - name: Set up Python 3.9
+ uses: actions/setup-python@e9aba2c848f5ebd159c070c61ea2c4e2b122355e # v2
+ with:
+ python-version: 3.9
+
+ - name: Install uv
+ uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
+ with:
+ enable-cache: true
+ cache-dependency-glob: "uv.lock"
+
+ - name: Install the project
+ run: uv sync --all-extras --dev
+
+ - name: Install workspace packages
+ run: uv pip install -e livekit-protocol -e livekit-api -e livekit-rtc
+
+ - name: Download ffi
+ run: uv run python livekit-rtc/rust-sdks/download_ffi.py --output .venv/lib/python3.9/site-packages/livekit/rtc/resources
+
+ - name: Check Types
+ run: uv run mypy livekit-protocol livekit-api livekit-rtc
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
new file mode 100644
index 00000000..9687bc5e
--- /dev/null
+++ b/.github/workflows/publish.yml
@@ -0,0 +1,411 @@
+name: Publish to PyPI
+
+on:
+ # Step 1: Dispatch creates a version bump PR
+ workflow_dispatch:
+ inputs:
+ package:
+ description: "Package to publish"
+ type: choice
+ required: true
+ options:
+ - livekit
+ - livekit-api
+ - livekit-protocol
+ version:
+ description: "What to publish"
+ type: choice
+ required: true
+ options:
+ - "patch (1.5.1 → 1.5.2)"
+ - "minor (1.5.1 → 1.6.0)"
+ - "major (1.5.1 → 2.0.0)"
+ - "patch-rc (1.5.1 → 1.5.2.rc1)"
+ - "minor-rc (1.5.1 → 1.6.0.rc1)"
+ - "major-rc (1.5.1 → 2.0.0.rc1)"
+ - "next-rc (.rc1 → .rc2)"
+ - "promote (1.6.0.rc2 → 1.6.0)"
+ branch:
+ description: "Branch to publish from (default: main)"
+ type: string
+ required: false
+ default: "main"
+
+ # Step 2: Merging the release PR triggers build + publish
+ pull_request:
+ types: [closed]
+
+permissions:
+ contents: write
+ pull-requests: write
+ id-token: write
+
+jobs:
+ # ── Step 1: Create a version bump PR ──────────────────────────
+ bump:
+ name: Create release PR
+ if: github.event_name == 'workflow_dispatch'
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ with:
+ ref: ${{ inputs.branch }}
+ submodules: true
+
+ - name: Guard non-main branches
+ env:
+ INPUT_VERSION: ${{ inputs.version }}
+ INPUT_BRANCH: ${{ inputs.branch }}
+ run: |
+ key=$(echo "$INPUT_VERSION" | awk '{print $1}')
+ if [ "$INPUT_BRANCH" != "main" ]; then
+ case "$key" in
+ *-rc|next-rc) ;; # allowed
+ *) echo "::error::Only RC releases are allowed from non-main branches (got '$key' on '$INPUT_BRANCH')"; exit 1 ;;
+ esac
+ fi
+
+ - name: Set up Python
+ uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
+ with:
+ python-version: "3.10"
+
+ - name: Install dependencies
+ run: pip install click packaging
+
+ - name: Bump version
+ env:
+ INPUT_VERSION: ${{ inputs.version }}
+ INPUT_PACKAGE: ${{ inputs.package }}
+ run: |
+ key=$(echo "$INPUT_VERSION" | awk '{print $1}')
+ pkg="$INPUT_PACKAGE"
+
+ case "$key" in
+ patch|minor|major)
+ python .github/update_versions.py --package "$pkg" --bump-type "$key"
+ ;;
+ patch-rc|minor-rc|major-rc)
+ bump="${key%-rc}"
+ python .github/update_versions.py --package "$pkg" --bump-type "$bump"
+ python .github/update_versions.py --package "$pkg" --pre rc
+ ;;
+ next-rc)
+ python .github/update_versions.py --package "$pkg" --pre rc
+ ;;
+ promote)
+ python .github/update_versions.py --package "$pkg" --bump-type release
+ ;;
+ esac
+
+ - name: Read new version
+ id: version
+ env:
+ INPUT_PACKAGE: ${{ inputs.package }}
+ run: |
+ eval "$(python .github/update_versions.py --package "$INPUT_PACKAGE" --print-version)"
+ echo "version=$version" >> "$GITHUB_OUTPUT"
+ echo "tag_prefix=$tag_prefix" >> "$GITHUB_OUTPUT"
+ echo "Package: $INPUT_PACKAGE, New version: $version, Tag: ${tag_prefix}-v${version}"
+
+ - name: Close existing release PRs for this package
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ TAG_PREFIX: ${{ steps.version.outputs.tag_prefix }}
+ run: |
+ prefix="release/${TAG_PREFIX}-v"
+ gh pr list --state open --json number,headRefName \
+ --jq ".[] | select(.headRefName | startswith(\"$prefix\")) | .number" | while read -r pr; do
+ echo "Superseding release PR #$pr"
+ gh pr comment "$pr" --body "Superseded by a new release."
+ gh pr close "$pr" --delete-branch || true
+ done
+
+ - name: Create release PR
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ VERSION: ${{ steps.version.outputs.version }}
+ TAG_PREFIX: ${{ steps.version.outputs.tag_prefix }}
+ INPUT_BRANCH: ${{ inputs.branch }}
+ INPUT_PACKAGE: ${{ inputs.package }}
+ run: |
+ branch="release/${TAG_PREFIX}-v${VERSION}"
+
+ git config user.name "github-actions[bot]"
+ git config user.email "github-actions[bot]@users.noreply.github.com"
+ git checkout -b "$branch"
+ git add -A
+ git commit -m "${TAG_PREFIX}-v${VERSION}"
+ git push --force origin "$branch"
+
+ gh pr create \
+ --base "$INPUT_BRANCH" \
+ --head "$branch" \
+ --title "${INPUT_PACKAGE} v${VERSION}" \
+ --body "Merging this PR will publish **${INPUT_PACKAGE}** v${VERSION} to PyPI." \
+
+
+ # ── Step 2: Publish on merge ──────────────────────────────────
+ detect:
+ name: Detect package
+ if: |
+ github.event_name == 'pull_request'
+ && github.event.pull_request.merged == true
+ && startsWith(github.event.pull_request.head.ref, 'release/')
+ runs-on: ubuntu-latest
+ outputs:
+ package: ${{ steps.detect.outputs.package }}
+ tag: ${{ steps.detect.outputs.tag }}
+ steps:
+ - name: Parse release branch
+ id: detect
+ env:
+ HEAD_REF: ${{ github.event.pull_request.head.ref }}
+ run: |
+ # branch is like release/rtc-v1.2.0, release/api-v1.1.1, release/protocol-v1.1.5
+ ref="${HEAD_REF#release/}"
+ prefix="${ref%%-v*}"
+
+ case "$prefix" in
+ rtc) package="livekit" ;;
+ api) package="livekit-api" ;;
+ protocol) package="livekit-protocol" ;;
+ *) echo "::error::Unknown release prefix: $prefix"; exit 1 ;;
+ esac
+
+ echo "package=$package" >> "$GITHUB_OUTPUT"
+ echo "tag=$ref" >> "$GITHUB_OUTPUT"
+ echo "Releasing $package (tag: $ref)"
+
+ tag:
+ name: Tag release
+ needs: detect
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ with:
+ ref: ${{ github.event.pull_request.merge_commit_sha }}
+
+ - name: Create git tag
+ env:
+ TAG: ${{ needs.detect.outputs.tag }}
+ run: |
+ git config user.name "github-actions[bot]"
+ git config user.email "github-actions[bot]@users.noreply.github.com"
+ git tag "$TAG"
+ git push origin "$TAG"
+
+ # ── RTC builds (multi-platform) ──────────────────────────────
+ build-rtc:
+ name: Build RTC wheels (${{ matrix.archs }})
+ needs: detect
+ if: needs.detect.outputs.package == 'livekit'
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - os: ubuntu-latest
+ archs: x86_64
+ - os: namespace-profile-default-arm64
+ archs: aarch64
+ - os: windows-latest
+ archs: AMD64
+ - os: macos-latest
+ archs: x86_64 arm64
+ defaults:
+ run:
+ working-directory: ./livekit-rtc
+ steps:
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ with:
+ submodules: true
+
+ - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
+ id: setup-python
+ with:
+ python-version: "3.11"
+
+ - name: Build wheels
+ run: pipx run --python '${{ steps.setup-python.outputs.python-path }}' cibuildwheel==3.3.1 --output-dir dist
+ env:
+ CIBW_ARCHS: ${{ matrix.archs }}
+
+ - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
+ with:
+ name: dist-rtc-${{ matrix.os }}
+ path: livekit-rtc/dist/*.whl
+
+ build-rtc-sdist:
+ name: Build RTC sdist
+ needs: detect
+ if: needs.detect.outputs.package == 'livekit'
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ working-directory: ./livekit-rtc
+ steps:
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ with:
+ submodules: true
+
+ - name: Build sdist
+ run: |
+ pip3 install build
+ python3 -m build --sdist
+
+ - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
+ with:
+ name: dist-rtc-sdist
+ path: livekit-rtc/dist/*.tar.gz
+
+ publish-rtc:
+ name: Publish livekit (RTC)
+ needs: [detect, build-rtc, build-rtc-sdist]
+ if: needs.detect.outputs.package == 'livekit'
+ runs-on: ubuntu-latest
+ environment: pypi
+ permissions:
+ id-token: write
+ steps:
+ - name: Download build artifacts
+ uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
+ with:
+ pattern: dist-rtc-*
+ path: dist
+ merge-multiple: true
+
+ - name: List distributions
+ run: ls -la dist/
+
+ - name: Publish to PyPI
+ uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1
+
+ # ── API build ────────────────────────────────────────────────
+ build-api:
+ name: Build API
+ needs: detect
+ if: needs.detect.outputs.package == 'livekit-api'
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ working-directory: ./livekit-api
+ steps:
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ with:
+ submodules: true
+
+ - uses: actions/setup-python@7f4fc3e22c37d6ff65e88745f38bd3157c663f7c # v4
+
+ - name: Build wheel & sdist
+ run: |
+ pip3 install build wheel
+ python3 -m build --wheel --sdist
+
+ - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
+ with:
+ name: dist-api
+ path: |
+ livekit-api/dist/*.whl
+ livekit-api/dist/*.tar.gz
+
+ publish-api:
+ name: Publish livekit-api
+ needs: [detect, build-api]
+ if: needs.detect.outputs.package == 'livekit-api'
+ runs-on: ubuntu-latest
+ environment: pypi
+ permissions:
+ id-token: write
+ steps:
+ - name: Download build artifact
+ uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
+ with:
+ name: dist-api
+ path: dist/
+
+ - name: List distributions
+ run: ls -la dist/
+
+ - name: Publish to PyPI
+ uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1
+
+ # ── Protocol build ───────────────────────────────────────────
+ build-protocol:
+ name: Build Protocol
+ needs: detect
+ if: needs.detect.outputs.package == 'livekit-protocol'
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ working-directory: ./livekit-protocol
+ steps:
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ with:
+ submodules: true
+
+ - uses: actions/setup-python@7f4fc3e22c37d6ff65e88745f38bd3157c663f7c # v4
+
+ - name: Build wheel & sdist
+ run: |
+ pip3 install build wheel
+ python3 -m build --wheel --sdist
+
+ - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
+ with:
+ name: dist-protocol
+ path: |
+ livekit-protocol/dist/*.whl
+ livekit-protocol/dist/*.tar.gz
+
+ publish-protocol:
+ name: Publish livekit-protocol
+ needs: [detect, build-protocol]
+ if: needs.detect.outputs.package == 'livekit-protocol'
+ runs-on: ubuntu-latest
+ environment: pypi
+ permissions:
+ id-token: write
+ steps:
+ - name: Download build artifact
+ uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
+ with:
+ name: dist-protocol
+ path: dist/
+
+ - name: List distributions
+ run: ls -la dist/
+
+ - name: Publish to PyPI
+ uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1
+
+ # ── Docs ─────────────────────────────────────────────────────
+ docs-rtc:
+ name: Build RTC docs
+ needs: [detect, publish-rtc]
+ if: needs.detect.outputs.package == 'livekit'
+ uses: ./.github/workflows/build-docs.yml
+ with:
+ package_dir: livekit-rtc
+ package_name: livekit.rtc
+ secrets: inherit
+
+ docs-api:
+ name: Build API docs
+ needs: [detect, publish-api]
+ if: needs.detect.outputs.package == 'livekit-api'
+ uses: ./.github/workflows/build-docs.yml
+ with:
+ package_dir: livekit-api
+ package_name: livekit.api
+ secrets: inherit
+
+ docs-protocol:
+ name: Build Protocol docs
+ needs: [detect, publish-protocol]
+ if: needs.detect.outputs.package == 'livekit-protocol'
+ uses: ./.github/workflows/build-docs.yml
+ with:
+ package_dir: livekit-protocol
+ package_name: livekit.protocol
+ secrets: inherit
diff --git a/.github/workflows/release-gate.yml b/.github/workflows/release-gate.yml
new file mode 100644
index 00000000..7ed81085
--- /dev/null
+++ b/.github/workflows/release-gate.yml
@@ -0,0 +1,41 @@
+name: Release gate
+
+on:
+ pull_request:
+ types: [opened, synchronize, reopened]
+ pull_request_review:
+ types: [submitted, dismissed]
+
+permissions:
+ pull-requests: read
+
+jobs:
+ release-gate:
+ name: Release gate
+ runs-on: ubuntu-latest
+ steps:
+ - name: Check release PR requirements
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ HEAD_REF: ${{ github.event.pull_request.head.ref }}
+ PR_AUTHOR: ${{ github.event.pull_request.user.login }}
+ PR_NUMBER: ${{ github.event.pull_request.number }}
+ REPO: ${{ github.repository }}
+ run: |
+ if [[ "$HEAD_REF" != release/* ]]; then
+ echo "Not a release PR, skipping"
+ exit 0
+ fi
+
+ if [ "$PR_AUTHOR" != "github-actions[bot]" ]; then
+ echo "::error::Release PRs must be created by the publish workflow, not by '$PR_AUTHOR'"
+ exit 1
+ fi
+
+ approvals=$(gh api "repos/$REPO/pulls/$PR_NUMBER/reviews" \
+ --jq '[group_by(.user.login)[] | sort_by(.submitted_at) | last | select(.state == "APPROVED") | .user.login] | length')
+ echo "Approvals: $approvals"
+ if [ "$approvals" -lt 2 ]; then
+ echo "::error::Release PRs require at least 2 approvals (got $approvals)"
+ exit 1
+ fi
diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml
index 06514b44..983dca8a 100644
--- a/.github/workflows/ruff.yml
+++ b/.github/workflows/ruff.yml
@@ -4,19 +4,22 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
- - uses: actions/setup-python@v4
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ - uses: actions/setup-python@7f4fc3e22c37d6ff65e88745f38bd3157c663f7c # v4
with:
python-version: "3.9"
- - name: Install dependencies
- run: |
- python -m pip install --upgrade pip
- pip install ruff
+ - name: Install uv
+ uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
+ with:
+ enable-cache: true
+ cache-dependency-glob: "uv.lock"
+
+ - name: Install the project
+ run: uv sync --all-extras --dev
- name: Ruff livekit-api
- run: ruff check --output-format=github .
+ run: uvx ruff check --output-format=github .
- name: Check format
- run: ruff format --check .
-
+ run: uvx ruff format --check .
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 7f6ab5ef..5834e804 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -1,27 +1,141 @@
name: Tests
on:
- push:
- branches:
- - main
- pull_request:
- branches:
- - main
- workflow_dispatch:
+ workflow_call:
+ inputs:
+ os:
+ description: "Runner OS (e.g., ubuntu-latest, macos-latest, windows-latest)"
+ required: true
+ type: string
+ python-version:
+ description: "Python version to test"
+ required: true
+ type: string
+ artifact-name:
+ description: "Name of the wheel artifact to download"
+ required: true
+ type: string
+ run-id:
+ description: "Workflow run ID to download artifacts from (optional, uses current run if not specified)"
+ required: false
+ type: string
+ secrets:
+ LIVEKIT_URL:
+ required: true
+ LIVEKIT_API_KEY:
+ required: true
+ LIVEKIT_API_SECRET:
+ required: true
jobs:
- tests:
- name: Run tests
- runs-on: ubuntu-latest
+ test:
+ name: Test (${{ inputs.os }}, Python ${{ inputs.python-version }})
+ runs-on: ${{ inputs.os }}
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
submodules: true
lfs: true
- - uses: actions/setup-python@v4
- - name: Run tests
+ - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
+ with:
+ python-version: ${{ inputs.python-version }}
+ allow-prereleases: true
+
+ - name: Install uv
+ uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
+ with:
+ enable-cache: true
+ cache-dependency-glob: "uv.lock"
+
+ - name: Download livekit-rtc wheel (current run)
+ if: ${{ inputs.run-id == '' }}
+ uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
+ with:
+ name: ${{ inputs.artifact-name }}
+ path: rtc-wheel
+
+ - name: Download livekit-rtc wheel (from specific run)
+ if: ${{ inputs.run-id != '' }}
+ uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
+ with:
+ name: ${{ inputs.artifact-name }}
+ path: rtc-wheel
+ run-id: ${{ inputs.run-id }}
+ github-token: ${{ github.token }}
+
+ - name: Select compatible wheel (macOS)
+ if: runner.os == 'macOS'
+ id: select-wheel-macos
run: |
- python3 ./livekit-rtc/rust-sdks/download_ffi.py --output livekit-rtc/livekit/rtc/resources
- pip3 install pytest ./livekit-protocol ./livekit-api ./livekit-rtc
- pytest . --ignore=livekit-rtc/rust-sdks
+ # macOS artifacts contain both x86_64 and arm64 wheels, select the right one
+ WHEEL=$(python3 -c "
+ import glob
+ import platform
+ import sys
+
+ wheels = glob.glob('rtc-wheel/*.whl')
+ machine = platform.machine().lower()
+
+ arch_map = {
+ 'x86_64': ['x86_64'],
+ 'arm64': ['arm64'],
+ }
+ patterns = arch_map.get(machine, [machine])
+
+ for wheel in wheels:
+ wheel_lower = wheel.lower()
+ if any(p in wheel_lower for p in patterns):
+ print(wheel)
+ sys.exit(0)
+
+ print(f'No matching wheel found for {machine}', file=sys.stderr)
+ sys.exit(1)
+ ")
+ echo "wheel=$WHEEL" >> $GITHUB_OUTPUT
+
+ - name: Create venv and install dependencies (Unix)
+ if: runner.os == 'Linux'
+ run: |
+ uv venv .test-venv
+ source .test-venv/bin/activate
+ uv pip install rtc-wheel/*.whl ./livekit-api ./livekit-protocol
+ uv pip install pytest pytest-asyncio numpy matplotlib
+
+ - name: Create venv and install dependencies (macOS)
+ if: runner.os == 'macOS'
+ run: |
+ uv venv .test-venv
+ source .test-venv/bin/activate
+ uv pip install "${{ steps.select-wheel-macos.outputs.wheel }}"
+ uv pip install ./livekit-api ./livekit-protocol
+ uv pip install pytest pytest-asyncio numpy matplotlib
+
+ - name: Create venv and install dependencies (Windows)
+ if: runner.os == 'Windows'
+ run: |
+ uv venv .test-venv
+ $wheel = (Get-ChildItem rtc-wheel\*.whl)[0].FullName
+ uv pip install --python .test-venv $wheel .\livekit-api .\livekit-protocol
+ uv pip install --python .test-venv pytest pytest-asyncio numpy matplotlib
+ shell: pwsh
+
+ - name: Run tests (Unix)
+ if: runner.os != 'Windows'
+ env:
+ LIVEKIT_URL: ${{ secrets.LIVEKIT_URL }}
+ LIVEKIT_API_KEY: ${{ secrets.LIVEKIT_API_KEY }}
+ LIVEKIT_API_SECRET: ${{ secrets.LIVEKIT_API_SECRET }}
+ run: |
+ source .test-venv/bin/activate
+ pytest tests/
+
+ - name: Run tests (Windows)
+ if: runner.os == 'Windows'
+ env:
+ LIVEKIT_URL: ${{ secrets.LIVEKIT_URL }}
+ LIVEKIT_API_KEY: ${{ secrets.LIVEKIT_API_KEY }}
+ LIVEKIT_API_SECRET: ${{ secrets.LIVEKIT_API_SECRET }}
+ run: .test-venv\Scripts\python.exe -m pytest tests/
+ shell: pwsh
+
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 1756b987..ea0eda1f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -162,4 +162,6 @@ cython_debug/
# vscode project settings
.vscode
-.DS_Store
\ No newline at end of file
+.DS_Store
+
+docs
\ No newline at end of file
diff --git a/README.md b/README.md
index 5f4bbb3f..e0b8962e 100644
--- a/README.md
+++ b/README.md
@@ -6,130 +6,295 @@
-
-
-[](https://pypi.org/project/livekit/)
-
-# 📹🎙️🐍 Python SDK for LiveKit
-
+
+
+[](https://pypi.org/project/livekit/)
+[](https://pypi.org/project/livekit-api/)
+
+# 📹🎙️🐍 Python SDK for LiveKit
+
-Use this SDK to add real-time video, audio and data features to your Python app. By connecting to a self- or cloud-hosted LiveKit server, you can quickly build applications like interactive live streaming or video calls with just a few lines of code.
-
-
-This repo contains two packages
-
-- [livekit](https://pypi.org/project/livekit/): Real-time SDK for connecting to LiveKit as a participant
-- [livekit-api](https://pypi.org/project/livekit-api/): Access token generation and server APIs
-
-## Using Server API
-
-```shell
-$ pip install livekit-api
-```
-
-### Generating an access token
-
-```python
-from livekit import api
-import os
-
-# will automatically use the LIVEKIT_API_KEY and LIVEKIT_API_SECRET env vars
-token = api.AccessToken() \
- .with_identity("python-bot") \
- .with_name("Python Bot") \
- .with_grants(api.VideoGrants(
- room_join=True,
- room="my-room",
- )).to_jwt()
-```
-
-### Creating a room
-
-RoomService uses asyncio and aiohttp to make API calls. It needs to be used with an event loop.
-
-```python
-from livekit import api
-import asyncio
-
-async def main():
- lkapi = api.LiveKitAPI(
- 'http://localhost:7880',
- )
- room_info = await lkapi.room.create_room(
- api.CreateRoomRequest(name="my-room"),
- )
- print(room_info)
- results = await lkapi.room.list_rooms(api.ListRoomsRequest())
- print(results)
- await lkapi.aclose()
-
-asyncio.get_event_loop().run_until_complete(main())
-```
-
-## Using Real-time SDK
-
-```shell
-$ pip install livekit
-```
-
-### Connecting to a room
-
-```python
-from livekit import rtc
-
-async def main():
- room = rtc.Room()
-
- @room.on("participant_connected")
- def on_participant_connected(participant: rtc.RemoteParticipant):
- logging.info(
- "participant connected: %s %s", participant.sid, participant.identity)
-
- async def receive_frames(stream: rtc.VideoStream):
- async for frame in video_stream:
- # received a video frame from the track, process it here
- pass
-
- # track_subscribed is emitted whenever the local participant is subscribed to a new track
- @room.on("track_subscribed")
- def on_track_subscribed(track: rtc.Track, publication: rtc.RemoteTrackPublication, participant: rtc.RemoteParticipant):
- logging.info("track subscribed: %s", publication.sid)
- if track.kind == rtc.TrackKind.KIND_VIDEO:
- video_stream = rtc.VideoStream(track)
- asyncio.ensure_future(receive_frames(video_stream))
-
- # By default, autosubscribe is enabled. The participant will be subscribed to
- # all published tracks in the room
- await room.connect(URL, TOKEN)
- logging.info("connected to room %s", room.name)
-
- # participants and tracks that are already available in the room
- # participant_connected and track_published events will *not* be emitted for them
- for participant in room.participants.items():
- for publication in participant.tracks.items():
- print("track publication: %s", publication.sid)
-```
-
-## Examples
-
-- [Facelandmark](https://github.com/livekit/python-sdks/tree/main/examples/face_landmark): Use mediapipe to detect face landmarks (eyes, nose ...)
-- [Basic room](https://github.com/livekit/python-sdks/blob/main/examples/basic_room.py): Connect to a room
-- [Publish hue](https://github.com/livekit/python-sdks/blob/main/examples/publish_hue.py): Publish a rainbow video track
-- [Publish wave](https://github.com/livekit/python-sdks/blob/main/examples/publish_hue.py): Publish a sine wave
-
-## Getting help / Contributing
-
-Please join us on [Slack](https://livekit.io/join-slack) to get help from our devs / community members. We welcome your contributions(PRs) and details can be discussed there.
-
+Use this SDK to add realtime video, audio and data features to your Python app. By connecting to LiveKit Cloud or a self-hosted server, you can quickly build applications such as multi-modal AI, live streaming, or video calls with just a few lines of code.
+
+
+This repo contains two packages
+
+- [livekit](https://pypi.org/project/livekit/): Real-time SDK for connecting to LiveKit as a participant
+- [livekit-api](https://pypi.org/project/livekit-api/): Access token generation and server APIs
+
+## Using Server API
+
+```shell
+$ pip install livekit-api
+```
+
+### Generating an access token
+
+```python
+from livekit import api
+import os
+
+# will automatically use the LIVEKIT_API_KEY and LIVEKIT_API_SECRET env vars
+token = api.AccessToken() \
+ .with_identity("python-bot") \
+ .with_name("Python Bot") \
+ .with_grants(api.VideoGrants(
+ room_join=True,
+ room="my-room",
+ )).to_jwt()
+```
+
+### Creating a room
+
+RoomService uses asyncio and aiohttp to make API calls. It needs to be used with an event loop.
+
+```python
+from livekit import api
+import asyncio
+
+async def main():
+ lkapi = api.LiveKitAPI("https://my-project.livekit.cloud")
+ room_info = await lkapi.room.create_room(
+ api.CreateRoomRequest(name="my-room"),
+ )
+ print(room_info)
+ results = await lkapi.room.list_rooms(api.ListRoomsRequest())
+ print(results)
+ await lkapi.aclose()
+
+asyncio.run(main())
+```
+
+### Using other APIs
+
+Services can be accessed via the LiveKitAPI object.
+
+```python
+lkapi = api.LiveKitAPI("https://my-project.livekit.cloud")
+
+# Room Service
+room_svc = lkapi.room
+
+# Egress Service
+egress_svc = lkapi.egress
+
+# Ingress Service
+ingress_svc = lkapi.ingress
+
+# Sip Service
+sip_svc = lkapi.sip
+
+# Agent Dispatch
+dispatch_svc = lkapi.agent_dispatch
+
+# Connector Service
+connector_svc = lkapi.connector
+```
+
+## Using Real-time SDK
+
+```shell
+$ pip install livekit
+```
+
+### Connecting to a room
+
+see [room_example](examples/room_example.py) for full example
+
+```python
+from livekit import rtc
+
+async def main():
+ room = rtc.Room()
+
+ @room.on("participant_connected")
+ def on_participant_connected(participant: rtc.RemoteParticipant):
+ logging.info(
+ "participant connected: %s %s", participant.sid, participant.identity)
+
+ async def receive_frames(stream: rtc.VideoStream):
+ async for frame in stream:
+ # received a video frame from the track, process it here
+ pass
+
+ # track_subscribed is emitted whenever the local participant is subscribed to a new track
+ @room.on("track_subscribed")
+ def on_track_subscribed(track: rtc.Track, publication: rtc.RemoteTrackPublication, participant: rtc.RemoteParticipant):
+ logging.info("track subscribed: %s", publication.sid)
+ if track.kind == rtc.TrackKind.KIND_VIDEO:
+ video_stream = rtc.VideoStream(track)
+ asyncio.ensure_future(receive_frames(video_stream))
+
+ # By default, autosubscribe is enabled. The participant will be subscribed to
+ # all published tracks in the room
+ await room.connect(URL, TOKEN)
+ logging.info("connected to room %s", room.name)
+
+ # participants and tracks that are already available in the room
+ # participant_connected and track_published events will *not* be emitted for them
+ for identity, participant in room.remote_participants.items():
+ print(f"identity: {identity}")
+ print(f"participant: {participant}")
+ for tid, publication in participant.track_publications.items():
+ print(f"\ttrack id: {publication}")
+```
+
+### RPC
+
+Perform your own predefined method calls from one participant to another.
+
+This feature is especially powerful when used with [Agents](https://docs.livekit.io/agents), for instance to forward LLM function calls to your client application.
+
+#### Registering an RPC method
+
+The participant who implements the method and will receive its calls must first register support:
+
+```python
+@room.local_participant.register_rpc_method("greet")
+async def handle_greet(data: RpcInvocationData):
+ print(f"Received greeting from {data.caller_identity}: {data.payload}")
+ return f"Hello, {data.caller_identity}!"
+```
+
+In addition to the payload, your handler will also receive `response_timeout`, which informs you the maximum time available to return a response. If you are unable to respond in time, the call will result in an error on the caller's side.
+
+#### Performing an RPC request
+
+The caller may then initiate an RPC call like so:
+
+```python
+try:
+ response = await room.local_participant.perform_rpc(
+ destination_identity='recipient-identity',
+ method='greet',
+ payload='Hello from RPC!'
+ )
+ print(f"RPC response: {response}")
+except Exception as e:
+ print(f"RPC call failed: {e}")
+```
+
+You may find it useful to adjust the `response_timeout` parameter, which indicates the amount of time you will wait for a response. We recommend keeping this value as low as possible while still satisfying the constraints of your application.
+
+## Using local media devices
+
+The `MediaDevices` class provides a high-level interface for working with local audio input (microphone) and output (speakers) devices. It's built on top of the `sounddevice` library and integrates seamlessly with LiveKit's audio processing features. In order to use `MediaDevices`, you must have the `sounddevice` library installed in your local Python environment, if it's not available, `MediaDevices` will not work.
+
+### Capturing microphone input
+
+```python
+from livekit import rtc
+
+# Create a MediaDevices instance
+devices = rtc.MediaDevices()
+
+# Open the default microphone with audio processing enabled
+mic = devices.open_input(
+ enable_aec=True, # Acoustic Echo Cancellation
+ noise_suppression=True, # Noise suppression
+ high_pass_filter=True, # High-pass filter
+ auto_gain_control=True # Automatic gain control
+)
+
+# Use the audio source to create a track and publish it
+track = rtc.LocalAudioTrack.create_audio_track("microphone", mic.source)
+await room.local_participant.publish_track(track)
+
+# Clean up when done
+await mic.aclose()
+```
+
+### Playing audio to speakers
+
+```python
+# Open the default output device
+player = devices.open_output()
+
+# Add remote audio tracks to the player (typically in a track_subscribed handler)
+@room.on("track_subscribed")
+def on_track_subscribed(track: rtc.Track, publication, participant):
+ if track.kind == rtc.TrackKind.KIND_AUDIO:
+ player.add_track(track)
+
+# Start playback (mixes all added tracks)
+await player.start()
+
+# Clean up when done
+await player.aclose()
+```
+
+### Full duplex audio (microphone + speakers)
+
+For full duplex audio with echo cancellation, open the input device first (with AEC enabled), then open the output device. The output player will automatically feed the APM's reverse stream for effective echo cancellation:
+
+```python
+devices = rtc.MediaDevices()
+
+# Open microphone with AEC
+mic = devices.open_input(enable_aec=True)
+
+# Open speakers - automatically uses the mic's APM for echo cancellation
+player = devices.open_output()
+
+# Publish microphone
+track = rtc.LocalAudioTrack.create_audio_track("mic", mic.source)
+await room.local_participant.publish_track(track)
+
+# Add remote tracks and start playback
+player.add_track(remote_audio_track)
+await player.start()
+```
+
+### Listing available devices
+
+```python
+devices = rtc.MediaDevices()
+
+# List input devices
+input_devices = devices.list_input_devices()
+for device in input_devices:
+ print(f"{device['index']}: {device['name']}")
+
+# List output devices
+output_devices = devices.list_output_devices()
+for device in output_devices:
+ print(f"{device['index']}: {device['name']}")
+
+# Get default device indices
+default_input = devices.default_input_device()
+default_output = devices.default_output_device()
+```
+
+See [publish_mic.py](examples/local_audio/publish_mic.py) and [full_duplex.py](examples/local_audio/full_duplex.py) for complete examples.
+
+
+#### Errors
+
+LiveKit is a dynamic realtime environment and calls can fail for various reasons.
+
+You may throw errors of the type `RpcError` with a string `message` in an RPC method handler and they will be received on the caller's side with the message intact. Other errors will not be transmitted and will instead arrive to the caller as `1500` ("Application Error"). Other built-in errors are detailed in `RpcError`.
+
+## Examples
+
+- [Facelandmark](https://github.com/livekit/python-sdks/tree/main/examples/face_landmark): Use mediapipe to detect face landmarks (eyes, nose ...)
+- [Basic room](https://github.com/livekit/python-sdks/blob/main/examples/basic_room.py): Connect to a room
+- [Publish hue](https://github.com/livekit/python-sdks/blob/main/examples/publish_hue.py): Publish a rainbow video track
+- [Publish wave](https://github.com/livekit/python-sdks/blob/main/examples/publish_wave.py): Publish a sine wave
+
+## Getting help / Contributing
+
+Please join us on [Slack](https://livekit.io/join-slack) to get help from our devs / community members. We welcome your contributions(PRs) and details can be discussed there.
+
-
+
diff --git a/dev-requirements.txt b/dev-requirements.txt
deleted file mode 100644
index a31ca5fd..00000000
--- a/dev-requirements.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-# download binaries
-requests
-
-# build wheels
-wheel
-setuptools
-twine
-auditwheel; sys_platform == 'linux'
-cibuildwheel
-
-pytest
diff --git a/examples/agent_dispatch.py b/examples/agent_dispatch.py
new file mode 100644
index 00000000..c53c4ae2
--- /dev/null
+++ b/examples/agent_dispatch.py
@@ -0,0 +1,61 @@
+import asyncio
+from livekit import api
+
+room_name = "my-room"
+agent_name = "test-agent"
+
+"""
+This example demonstrates how to have an agent join a room
+without using the automatic dispatch. In order to use this
+feature, you must have an agent running with `agent_name` set
+when defining your WorkerOptions. A dispatch requests the
+agent to enter a specific room with optional metadata.
+"""
+
+
+async def create_explicit_dispatch():
+ lkapi = api.LiveKitAPI()
+
+ dispatch = await lkapi.agent_dispatch.create_dispatch(
+ api.CreateAgentDispatchRequest(
+ agent_name=agent_name, room=room_name, metadata="my_metadata"
+ )
+ )
+ print("created dispatch", dispatch)
+
+ dispatches = await lkapi.agent_dispatch.list_dispatch(room_name=room_name)
+ print(f"there are {len(dispatches)} dispatches in {room_name}")
+ await lkapi.aclose()
+
+
+"""
+When agent name is set, the agent will no longer be automatically dispatched
+to new rooms. If you want that agent to be dispatched to a new room as soon as
+the participant connects, you can set the RoomConfiguration with the agent
+definition in the access token.
+"""
+
+
+async def create_token_with_agent_dispatch() -> str:
+ token = (
+ api.AccessToken()
+ .with_identity("my_participant")
+ .with_grants(api.VideoGrants(room_join=True, room=room_name))
+ .with_room_config(
+ api.RoomConfiguration(
+ agents=[api.RoomAgentDispatch(agent_name="test-agent", metadata="my_metadata")],
+ ),
+ )
+ .to_jwt()
+ )
+ return token
+
+
+async def main():
+ token = await create_token_with_agent_dispatch()
+ print("created participant token", token)
+ print("creating explicit dispatch")
+ await create_explicit_dispatch()
+
+
+asyncio.run(main())
diff --git a/examples/api.py b/examples/api.py
index bdb6348a..f9e34265 100644
--- a/examples/api.py
+++ b/examples/api.py
@@ -3,8 +3,8 @@
async def main():
- # will automatically use the LIVEKIT_API_KEY and LIVEKIT_API_SECRET env vars
- lkapi = api.LiveKitAPI("http://localhost:7880")
+ # will automatically use LIVEKIT_URL, LIVEKIT_API_KEY and LIVEKIT_API_SECRET env vars
+ lkapi = api.LiveKitAPI()
room_info = await lkapi.room.create_room(
api.CreateRoomRequest(name="my-room"),
)
@@ -15,4 +15,4 @@ async def main():
if __name__ == "__main__":
- asyncio.get_event_loop().run_until_complete(main())
+ asyncio.run(main())
diff --git a/examples/basic_room.py b/examples/basic_room.py
index 7d1544b5..5fa64f95 100644
--- a/examples/basic_room.py
+++ b/examples/basic_room.py
@@ -12,15 +12,11 @@
async def main(room: rtc.Room) -> None:
@room.on("participant_connected")
def on_participant_connected(participant: rtc.RemoteParticipant) -> None:
- logging.info(
- "participant connected: %s %s", participant.sid, participant.identity
- )
+ logging.info("participant connected: %s %s", participant.sid, participant.identity)
@room.on("participant_disconnected")
def on_participant_disconnected(participant: rtc.RemoteParticipant):
- logging.info(
- "participant disconnected: %s %s", participant.sid, participant.identity
- )
+ logging.info("participant disconnected: %s %s", participant.sid, participant.identity)
@room.on("local_track_published")
def on_local_track_published(
@@ -78,9 +74,7 @@ def on_track_unsubscribed(
logging.info("track unsubscribed: %s", publication.sid)
@room.on("track_muted")
- def on_track_muted(
- publication: rtc.RemoteTrackPublication, participant: rtc.RemoteParticipant
- ):
+ def on_track_muted(publication: rtc.RemoteTrackPublication, participant: rtc.RemoteParticipant):
logging.info("track muted: %s", publication.sid)
@room.on("track_unmuted")
@@ -94,9 +88,7 @@ def on_data_received(data: rtc.DataPacket):
logging.info("received data from %s: %s", data.participant.identity, data.data)
@room.on("connection_quality_changed")
- def on_connection_quality_changed(
- participant: rtc.Participant, quality: rtc.ConnectionQuality
- ):
+ def on_connection_quality_changed(participant: rtc.Participant, quality: rtc.ConnectionQuality):
logging.info("connection quality changed for %s", participant.identity)
@room.on("track_subscription_failed")
@@ -125,6 +117,10 @@ def on_reconnecting() -> None:
def on_reconnected() -> None:
logging.info("reconnected")
+ @room.on("room_updated")
+ def on_room_updated() -> None:
+ logging.info(f"room updated, participants: {room.num_participants}")
+
token = (
api.AccessToken()
.with_identity("python-bot")
@@ -138,8 +134,8 @@ def on_reconnected() -> None:
.to_jwt()
)
await room.connect(os.getenv("LIVEKIT_URL"), token)
- logging.info("connected to room %s", room.name)
- logging.info("participants: %s", room.participants)
+ logging.info(f"connected to room {room.name}, created {room.creation_time}")
+ logging.info(f"participants: {room.remote_participants}")
await asyncio.sleep(2)
await room.local_participant.publish_data("hello world")
diff --git a/examples/data-streams/data_streams.py b/examples/data-streams/data_streams.py
new file mode 100644
index 00000000..babd4ef5
--- /dev/null
+++ b/examples/data-streams/data_streams.py
@@ -0,0 +1,96 @@
+import os
+import logging
+import asyncio
+from signal import SIGINT, SIGTERM
+from livekit import rtc
+
+# Set the following environment variables with your own values
+TOKEN = os.environ.get("LIVEKIT_TOKEN")
+URL = os.environ.get("LIVEKIT_URL")
+
+
+async def main(room: rtc.Room):
+ logging.basicConfig(level=logging.INFO)
+ logger = logging.getLogger(__name__)
+
+ active_tasks = []
+
+ async def greetParticipant(identity: str):
+ text_writer = await room.local_participant.stream_text(
+ destination_identities=[identity], topic="chat"
+ )
+ for char in "Hi! Just a friendly message":
+ await text_writer.write(char)
+ await text_writer.aclose()
+
+ await room.local_participant.send_file(
+ "./green_tree_python.jpg",
+ destination_identities=[identity],
+ topic="files",
+ )
+
+ async def on_chat_message_received(reader: rtc.TextStreamReader, participant_identity: str):
+ full_text = await reader.read_all()
+ logger.info("Received chat message from %s: '%s'", participant_identity, full_text)
+
+ async def on_welcome_image_received(reader: rtc.ByteStreamReader, participant_identity: str):
+ logger.info("Received image from %s: '%s'", participant_identity, reader.info.name)
+ with open(reader.info.name, mode="wb") as f:
+ async for chunk in reader:
+ f.write(chunk)
+
+ f.close()
+
+ @room.on("participant_connected")
+ def on_participant_connected(participant: rtc.RemoteParticipant):
+ logger.info("participant connected: %s %s", participant.sid, participant.identity)
+ asyncio.create_task(greetParticipant(participant.identity))
+
+ def _handle_chat_stream(reader, participant_identity):
+ task = asyncio.create_task(on_chat_message_received(reader, participant_identity))
+ active_tasks.append(task)
+ task.add_done_callback(lambda _: active_tasks.remove(task))
+
+ room.register_text_stream_handler("chat", _handle_chat_stream)
+
+ def _handle_welcome_image_stream(reader, participant_identity):
+ task = asyncio.create_task(on_welcome_image_received(reader, participant_identity))
+ active_tasks.append(task)
+ task.add_done_callback(lambda _: active_tasks.remove(task))
+
+ room.register_byte_stream_handler("files", _handle_welcome_image_stream)
+
+ # By default, autosubscribe is enabled. The participant will be subscribed to
+ # all published tracks in the room
+ await room.connect(URL, TOKEN)
+ logger.info("connected to room %s", room.name)
+
+ for identity, participant in room.remote_participants.items():
+ logger.info("Sending a welcome message to %s", identity)
+ await greetParticipant(participant.identity)
+
+
+if __name__ == "__main__":
+ logging.basicConfig(
+ level=logging.INFO,
+ handlers=[
+ logging.FileHandler("data_stream_example.log"),
+ logging.StreamHandler(),
+ ],
+ )
+
+ loop = asyncio.get_event_loop()
+ room = rtc.Room(loop=loop)
+
+ async def cleanup():
+ await room.disconnect()
+ loop.stop()
+
+ asyncio.ensure_future(main(room))
+ for signal in [SIGINT, SIGTERM]:
+ loop.add_signal_handler(signal, lambda: asyncio.ensure_future(cleanup()))
+
+ try:
+ loop.run_forever()
+ finally:
+ loop.close()
diff --git a/examples/data-streams/green_tree_python.jpg b/examples/data-streams/green_tree_python.jpg
new file mode 100644
index 00000000..9c49df47
--- /dev/null
+++ b/examples/data-streams/green_tree_python.jpg
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a27eb74910a778fa47ae2c5ac9b0fda51b3c9f7dd26762f071b75f92da0efd3d
+size 2627889
diff --git a/examples/data_tracks/publisher.py b/examples/data_tracks/publisher.py
new file mode 100644
index 00000000..d3185ccd
--- /dev/null
+++ b/examples/data_tracks/publisher.py
@@ -0,0 +1,70 @@
+import os
+import logging
+import asyncio
+import time
+from signal import SIGINT, SIGTERM
+from livekit import rtc
+
+# Set the following environment variables with your own values
+TOKEN = os.environ.get("LIVEKIT_TOKEN")
+URL = os.environ.get("LIVEKIT_URL")
+
+
+async def read_sensor() -> bytes:
+ # Dynamically read some sensor data...
+ return bytes([0xFA] * 256)
+
+
+async def push_frames(track: rtc.LocalDataTrack):
+ while True:
+ logging.info("Pushing frame")
+ data = await read_sensor()
+ try:
+ frame = rtc.DataTrackFrame(payload=data, user_timestamp=int(time.time() * 1000))
+ track.try_push(frame)
+ except rtc.PushFrameError as e:
+ logging.error("Failed to push frame: %s", e)
+ await asyncio.sleep(0.5)
+
+
+async def main(room: rtc.Room):
+ logging.basicConfig(level=logging.INFO)
+ logger = logging.getLogger(__name__)
+
+ await room.connect(URL, TOKEN)
+ logger.info("connected to room %s", room.name)
+
+ track = await room.local_participant.publish_data_track(name="my_sensor_data")
+ await push_frames(track)
+
+
+if __name__ == "__main__":
+ logging.basicConfig(
+ level=logging.INFO,
+ handlers=[
+ logging.FileHandler("publisher.log"),
+ logging.StreamHandler(),
+ ],
+ )
+
+ loop = asyncio.get_event_loop()
+ room = rtc.Room(loop=loop)
+
+ main_task = asyncio.ensure_future(main(room))
+
+ async def cleanup():
+ main_task.cancel()
+ try:
+ await main_task
+ except asyncio.CancelledError:
+ pass
+ await room.disconnect()
+ loop.stop()
+
+ for signal in [SIGINT, SIGTERM]:
+ loop.add_signal_handler(signal, lambda: asyncio.ensure_future(cleanup()))
+
+ try:
+ loop.run_forever()
+ finally:
+ loop.close()
diff --git a/examples/data_tracks/subscriber.py b/examples/data_tracks/subscriber.py
new file mode 100644
index 00000000..bc5e988f
--- /dev/null
+++ b/examples/data_tracks/subscriber.py
@@ -0,0 +1,69 @@
+import os
+import logging
+import asyncio
+import time
+from signal import SIGINT, SIGTERM
+from livekit import rtc
+
+# Set the following environment variables with your own values
+TOKEN = os.environ.get("LIVEKIT_TOKEN")
+URL = os.environ.get("LIVEKIT_URL")
+
+
+async def subscribe(track: rtc.RemoteDataTrack):
+ logging.info(
+ "Subscribing to '%s' published by '%s'",
+ track.info.name,
+ track.publisher_identity,
+ )
+ try:
+ async for frame in track.subscribe():
+ logging.info("Received frame (%d bytes)", len(frame.payload))
+
+ if frame.user_timestamp is not None:
+ latency = (int(time.time() * 1000) - frame.user_timestamp) / 1000.0
+ logging.info("Latency: %.3f s", latency)
+ except rtc.SubscribeDataTrackError as e:
+ logging.error("Failed to subscribe to '%s': %s", track.info.name, e.message)
+
+
+async def main(room: rtc.Room):
+ logging.basicConfig(level=logging.INFO)
+ logger = logging.getLogger(__name__)
+
+ active_tasks = []
+
+ @room.on("data_track_published")
+ def on_data_track_published(track: rtc.RemoteDataTrack):
+ task = asyncio.create_task(subscribe(track))
+ active_tasks.append(task)
+ task.add_done_callback(lambda _: active_tasks.remove(task))
+
+ await room.connect(URL, TOKEN)
+ logger.info("connected to room %s", room.name)
+
+
+if __name__ == "__main__":
+ logging.basicConfig(
+ level=logging.INFO,
+ handlers=[
+ logging.FileHandler("subscriber.log"),
+ logging.StreamHandler(),
+ ],
+ )
+
+ loop = asyncio.get_event_loop()
+ room = rtc.Room(loop=loop)
+
+ async def cleanup():
+ await room.disconnect()
+ loop.stop()
+
+ asyncio.ensure_future(main(room))
+ for signal in [SIGINT, SIGTERM]:
+ loop.add_signal_handler(signal, lambda: asyncio.ensure_future(cleanup()))
+
+ try:
+ loop.run_forever()
+ finally:
+ loop.close()
diff --git a/examples/e2ee.py b/examples/e2ee.py
index b9617773..96db94c8 100644
--- a/examples/e2ee.py
+++ b/examples/e2ee.py
@@ -1,15 +1,19 @@
import asyncio
import logging
+import os
from signal import SIGINT, SIGTERM
import numpy as np
from livekit import rtc
-URL = "ws://localhost:7880"
-TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE5MDY2MTMyODgsImlzcyI6IkFQSVRzRWZpZFpqclFvWSIsIm5hbWUiOiJuYXRpdmUiLCJuYmYiOjE2NzI2MTMyODgsInN1YiI6Im5hdGl2ZSIsInZpZGVvIjp7InJvb20iOiJ0ZXN0Iiwicm9vbUFkbWluIjp0cnVlLCJyb29tQ3JlYXRlIjp0cnVlLCJyb29tSm9pbiI6dHJ1ZSwicm9vbUxpc3QiOnRydWV9fQ.uSNIangMRu8jZD5mnRYoCHjcsQWCrJXgHCs0aNIgBFY" # noqa
+URL = os.environ.get("LIVEKIT_URL", "ws://localhost:7880")
+TOKEN = os.environ.get(
+ "LIVEKIT_TOKEN",
+ "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE5MDY2MTMyODgsImlzcyI6IkFQSVRzRWZpZFpqclFvWSIsIm5hbWUiOiJuYXRpdmUiLCJuYmYiOjE2NzI2MTMyODgsInN1YiI6Im5hdGl2ZSIsInZpZGVvIjp7InJvb20iOiJ0ZXN0Iiwicm9vbUFkbWluIjp0cnVlLCJyb29tQ3JlYXRlIjp0cnVlLCJyb29tSm9pbiI6dHJ1ZSwicm9vbUxpc3QiOnRydWV9fQ.uSNIangMRu8jZD5mnRYoCHjcsQWCrJXgHCs0aNIgBFY",
+) # noqa
-# ("livekitrocks") this is our shared key, it must match the one used by your clients
-SHARED_KEY = b"livekitrocks"
+# This shared key must match the one used by your clients
+SHARED_KEY = os.environ.get("E2EE_SHARED_KEY", "livekitrocks").encode()
WIDTH, HEIGHT = 1280, 720
@@ -47,8 +51,7 @@ async def draw_cube(source: rtc.VideoSource):
[3, 7],
]
- frame = rtc.ArgbFrame.create(rtc.VideoFormatType.FORMAT_ARGB, WIDTH, HEIGHT)
- arr = np.frombuffer(frame.data, dtype=np.uint8)
+ arr = np.zeros((WIDTH * HEIGHT * 4), dtype=np.uint8)
angle = 0
while True:
@@ -88,7 +91,7 @@ async def draw_cube(source: rtc.VideoSource):
idx = (y + dy) * WIDTH * 4 + (x + dx) * 4
arr[idx : idx + 4] = [255, 255, 255, 255]
- f = rtc.VideoFrame(frame.to_i420())
+ f = rtc.VideoFrame(WIDTH, HEIGHT, rtc.VideoBufferType.ARGB, arr)
source.capture_frame(f)
angle += 0.02
@@ -98,9 +101,7 @@ async def draw_cube(source: rtc.VideoSource):
async def main(room: rtc.Room):
@room.on("e2ee_state_changed")
- def on_e2ee_state_changed(
- participant: rtc.Participant, state: rtc.EncryptionState
- ) -> None:
+ def on_e2ee_state_changed(participant: rtc.Participant, state: rtc.EncryptionState) -> None:
logging.info("e2ee state changed: %s %s", participant.identity, state)
logging.info("connecting to %s", URL)
@@ -109,7 +110,7 @@ def on_e2ee_state_changed(
e2ee_options.key_provider_options.shared_key = SHARED_KEY
await room.connect(
- URL, TOKEN, options=rtc.RoomOptions(auto_subscribe=True, e2ee=e2ee_options)
+ URL, TOKEN, options=rtc.RoomOptions(auto_subscribe=True, encryption=e2ee_options)
)
logging.info("connected to room %s", room.name)
diff --git a/examples/face_landmark/face_landmark.py b/examples/face_landmark/face_landmark.py
index edc20f36..99fe04e3 100644
--- a/examples/face_landmark/face_landmark.py
+++ b/examples/face_landmark/face_landmark.py
@@ -72,9 +72,7 @@ def draw_landmarks_on_image(rgb_image, detection_result):
face_landmarks_proto = landmark_pb2.NormalizedLandmarkList()
face_landmarks_proto.landmark.extend(
[
- landmark_pb2.NormalizedLandmark(
- x=landmark.x, y=landmark.y, z=landmark.z
- )
+ landmark_pb2.NormalizedLandmark(x=landmark.x, y=landmark.y, z=landmark.z)
for landmark in face_landmarks
]
)
@@ -113,9 +111,7 @@ async def frame_loop(video_stream: rtc.VideoStream) -> None:
arr = arr.reshape((buffer.height, buffer.width, 3))
mp_image = mp.Image(image_format=mp.ImageFormat.SRGB, data=arr)
- detection_result = landmarker.detect_for_video(
- mp_image, frame_event.timestamp_us
- )
+ detection_result = landmarker.detect_for_video(mp_image, frame_event.timestamp_us)
draw_landmarks_on_image(arr, detection_result)
diff --git a/examples/local_audio/db_meter.py b/examples/local_audio/db_meter.py
new file mode 100644
index 00000000..65f07d68
--- /dev/null
+++ b/examples/local_audio/db_meter.py
@@ -0,0 +1,262 @@
+"""
+Audio dB meter utilities for LiveKit Python SDK examples.
+
+This module provides functions to calculate and display audio levels in decibels (dB)
+from raw audio samples, useful for monitoring microphone input and room audio levels.
+"""
+
+import math
+import queue
+import time
+from typing import List
+
+# dB meter configuration constants
+DB_METER_UPDATE_INTERVAL_MS = 50 # Update every 50ms
+MIC_METER_WIDTH = 25 # Width of the mic dB meter bar
+ROOM_METER_WIDTH = 25 # Width of the room dB meter bar
+
+
+def calculate_db_level(samples: List[int]) -> float:
+ """
+ Calculate decibel level from audio samples.
+
+ Args:
+ samples: List of 16-bit audio samples
+
+ Returns:
+ dB level as float. Returns -60.0 for silence/empty samples.
+ """
+ if not samples:
+ return -60.0 # Very quiet
+
+ # Calculate RMS (Root Mean Square)
+ sum_squares = sum(
+ (sample / 32767.0) ** 2 # Normalize to -1.0 to 1.0 range
+ for sample in samples
+ )
+
+ rms = math.sqrt(sum_squares / len(samples))
+
+ # Convert to dB (20 * log10(rms))
+ if rms > 0.0:
+ return 20.0 * math.log10(rms)
+ else:
+ return -60.0 # Very quiet
+
+
+def get_meter_color(db_level: float, position_ratio: float) -> str:
+ """
+ Get ANSI color code based on dB level and position in meter.
+
+ Args:
+ db_level: Current dB level
+ position_ratio: Position in meter (0.0 to 1.0)
+
+ Returns:
+ ANSI color code string
+ """
+ # Determine color based on both dB level and position in the meter
+ if db_level > -6.0 and position_ratio > 0.85:
+ return "\x1b[91m" # Bright red - clipping/very loud
+ elif db_level > -12.0 and position_ratio > 0.7:
+ return "\x1b[31m" # Red - loud
+ elif db_level > -18.0 and position_ratio > 0.5:
+ return "\x1b[93m" # Bright yellow - medium-loud
+ elif db_level > -30.0 and position_ratio > 0.3:
+ return "\x1b[33m" # Yellow - medium
+ elif position_ratio > 0.1:
+ return "\x1b[92m" # Bright green - low-medium
+ else:
+ return "\x1b[32m" # Green - low
+
+
+def format_single_meter(db_level: float, meter_width: int, meter_label: str) -> str:
+ """
+ Format a single dB meter with colors.
+
+ Args:
+ db_level: dB level to display
+ meter_width: Width of the meter bar in characters
+ meter_label: Label text for the meter
+
+ Returns:
+ Formatted meter string with ANSI colors
+ """
+ # ANSI color codes
+ COLOR_RESET = "\x1b[0m"
+ COLOR_DIM = "\x1b[2m"
+
+ db_clamped = max(-60.0, min(0.0, db_level))
+ normalized = (db_clamped + 60.0) / 60.0 # Normalize to 0.0-1.0
+ filled_width = int(normalized * meter_width)
+
+ meter = meter_label
+
+ # Add the dB value with appropriate color
+ if db_level > -6.0:
+ db_color = "\x1b[91m" # Bright red
+ elif db_level > -12.0:
+ db_color = "\x1b[31m" # Red
+ elif db_level > -24.0:
+ db_color = "\x1b[33m" # Yellow
+ else:
+ db_color = "\x1b[32m" # Green
+
+ meter += f"{db_color}{db_level:>7.1f}{COLOR_RESET} "
+
+ # Add the visual meter with colors
+ meter += "["
+ for i in range(meter_width):
+ position_ratio = i / meter_width
+
+ if i < filled_width:
+ color = get_meter_color(db_level, position_ratio)
+ meter += f"{color}█{COLOR_RESET}" # Full block for active levels
+ else:
+ meter += f"{COLOR_DIM}░{COLOR_RESET}" # Light shade for empty
+
+ meter += "]"
+ return meter
+
+
+def format_dual_meters(mic_db: float, room_db: float) -> str:
+ """
+ Format both dB meters on the same line.
+
+ Args:
+ mic_db: Microphone dB level
+ room_db: Room audio dB level
+
+ Returns:
+ Formatted dual meter string
+ """
+ mic_meter = format_single_meter(mic_db, MIC_METER_WIDTH, "Mic: ")
+ room_meter = format_single_meter(room_db, ROOM_METER_WIDTH, " Room: ")
+
+ return f"{mic_meter}{room_meter}"
+
+
+def display_dual_db_meters(
+ mic_db_receiver, room_db_receiver, room_name: str = "Audio Levels Monitor"
+) -> None:
+ """
+ Display dual dB meters continuously until interrupted.
+
+ Args:
+ mic_db_receiver: Queue or receiver for microphone dB levels
+ room_db_receiver: Queue or receiver for room dB levels
+ room_name: Name of the room to display as the title
+ """
+ try:
+ last_update = time.time()
+ current_mic_db = -60.0
+ current_room_db = -60.0
+
+ print() # Start on a new line
+ print(f"\x1b[92mRoom [{room_name}]\x1b[0m")
+ print(
+ "\x1b[2m────────────────────────────────────────────────────────────────────────────────\x1b[0m"
+ )
+
+ while True:
+ # Check for new data (non-blocking)
+ try:
+ while True: # Drain all available data
+ mic_db = mic_db_receiver.get_nowait()
+ current_mic_db = mic_db
+ except queue.Empty:
+ pass # No more data available
+
+ try:
+ while True: # Drain all available data
+ room_db = room_db_receiver.get_nowait()
+ current_room_db = room_db
+ except queue.Empty:
+ pass # No more data available
+
+ # Update display at regular intervals
+ current_time = time.time()
+ if current_time - last_update >= DB_METER_UPDATE_INTERVAL_MS / 1000.0:
+ # Clear current line and display meters in place
+ print(
+ f"\r\x1b[K{format_dual_meters(current_mic_db, current_room_db)}",
+ end="",
+ flush=True,
+ )
+ last_update = current_time
+
+ # Small sleep to prevent busy waiting
+ time.sleep(0.01)
+
+ except KeyboardInterrupt:
+ print() # Move to next line after Ctrl+C
+
+
+def display_single_db_meter(db_receiver, label: str = "Mic Level: ") -> None:
+ """
+ Display a single dB meter continuously until interrupted.
+
+ Args:
+ db_receiver: Queue or receiver for dB levels
+ label: Label for the meter display
+ """
+ try:
+ last_update = time.time()
+ current_db = -60.0
+ first_display = True
+
+ if first_display:
+ print() # Start on a new line
+ print(f"\x1b[92m{label}\x1b[0m")
+ print("\x1b[2m────────────────────────────────────────\x1b[0m")
+ first_display = False
+
+ while True:
+ # Check for new data (non-blocking)
+ try:
+ while True: # Drain all available data
+ db_level = db_receiver.get_nowait()
+ current_db = db_level
+ except queue.Empty:
+ pass # No more data available
+
+ # Update display at regular intervals
+ current_time = time.time()
+ if current_time - last_update >= DB_METER_UPDATE_INTERVAL_MS / 1000.0:
+ # Clear current line and display meter in place
+ meter = format_single_meter(current_db, 40, label)
+ print(f"\r\x1b[K{meter}", end="", flush=True)
+ last_update = current_time
+
+ # Small sleep to prevent busy waiting
+ time.sleep(0.01)
+
+ except KeyboardInterrupt:
+ print() # Move to next line after Ctrl+C
+
+
+# Example usage and testing functions
+def demo_db_meter() -> None:
+ """Demo function to test dB meter functionality."""
+ import random
+
+ # Simulate some test data
+ class MockReceiver:
+ def __init__(self):
+ self.data = []
+
+ def get_nowait(self):
+ if not self.data:
+ # Generate random dB value between -60 and 0
+ self.data.append(random.uniform(-60, 0))
+ return self.data.pop(0)
+
+ mic_receiver = MockReceiver()
+ room_receiver = MockReceiver()
+
+ print("Starting dB meter demo (Ctrl+C to stop)...")
+ display_dual_db_meters(mic_receiver, room_receiver)
+
+
+if __name__ == "__main__":
+ demo_db_meter()
diff --git a/examples/local_audio/full_duplex.py b/examples/local_audio/full_duplex.py
new file mode 100644
index 00000000..534e29c4
--- /dev/null
+++ b/examples/local_audio/full_duplex.py
@@ -0,0 +1,142 @@
+import os
+import asyncio
+import logging
+import threading
+import queue
+from dotenv import load_dotenv, find_dotenv
+
+from livekit import api, rtc
+from db_meter import calculate_db_level, display_single_db_meter
+
+
+async def main() -> None:
+ logging.basicConfig(level=logging.INFO)
+
+ # Load environment variables from a .env file if present
+ load_dotenv(find_dotenv())
+
+ url = os.getenv("LIVEKIT_URL")
+ api_key = os.getenv("LIVEKIT_API_KEY")
+ api_secret = os.getenv("LIVEKIT_API_SECRET")
+ token = os.getenv("LIVEKIT_TOKEN")
+ # check for either token or api_key and api_secret
+ if not url or (not token and (not api_key or not api_secret)):
+ raise RuntimeError(
+ "LIVEKIT_TOKEN or LIVEKIT_API_KEY and LIVEKIT_API_SECRET must be set in env"
+ )
+
+ room = rtc.Room()
+
+ devices = rtc.MediaDevices()
+
+ # Open microphone & speaker
+ mic = devices.open_input()
+ player = devices.open_output()
+
+ # dB level monitoring (mic only)
+ mic_db_queue = queue.Queue()
+
+ def on_track_subscribed(
+ track: rtc.Track,
+ publication: rtc.RemoteTrackPublication,
+ participant: rtc.RemoteParticipant,
+ ):
+ if track.kind == rtc.TrackKind.KIND_AUDIO:
+ asyncio.create_task(player.add_track(track))
+ logging.info("subscribed to audio from %s", participant.identity)
+
+ room.on("track_subscribed", on_track_subscribed)
+
+ def on_track_unsubscribed(
+ track: rtc.Track,
+ publication: rtc.RemoteTrackPublication,
+ participant: rtc.RemoteParticipant,
+ ):
+ asyncio.create_task(player.remove_track(track))
+ logging.info("unsubscribed from audio of %s", participant.identity)
+
+ room.on("track_unsubscribed", on_track_unsubscribed)
+
+ # generate token if not provided
+ if not token:
+ token = (
+ api.AccessToken(api_key, api_secret)
+ .with_identity("local-audio")
+ .with_name("Local Audio")
+ .with_grants(
+ api.VideoGrants(
+ room_join=True,
+ room="local-audio",
+ )
+ )
+ .to_jwt()
+ )
+
+ try:
+ await room.connect(url, token)
+ logging.info("connected to room %s", room.name)
+
+ # Publish microphone
+ track = rtc.LocalAudioTrack.create_audio_track("mic", mic.source)
+ pub_opts = rtc.TrackPublishOptions()
+ pub_opts.source = rtc.TrackSource.SOURCE_MICROPHONE
+ await room.local_participant.publish_track(track, pub_opts)
+ logging.info("published local microphone")
+
+ # Start dB meter display in a separate thread
+ meter_thread = threading.Thread(
+ target=display_single_db_meter,
+ args=(mic_db_queue,),
+ kwargs={"label": "Mic Level: "},
+ daemon=True,
+ )
+ meter_thread.start()
+
+ # Start playing mixed remote audio (tracks added via event handlers)
+ await player.start()
+
+ # Monitor microphone dB levels
+ async def monitor_mic_db():
+ mic_stream = rtc.AudioStream(track, sample_rate=48000, num_channels=1)
+ frame_count = 0
+ sample_interval = 5 # Process every 5th frame to reduce load
+
+ try:
+ async for frame_event in mic_stream:
+ # Skip frames to reduce processing load
+ frame_count += 1
+ if frame_count % sample_interval != 0:
+ continue
+
+ frame = frame_event.frame
+ # Convert frame data to list of samples
+ samples = list(frame.data)
+ db_level = calculate_db_level(samples)
+ # Update queue with latest value (non-blocking)
+ try:
+ mic_db_queue.put_nowait(db_level)
+ except queue.Full:
+ pass # Drop if queue is full
+ except Exception:
+ pass
+ finally:
+ await mic_stream.aclose()
+
+ asyncio.create_task(monitor_mic_db())
+
+ # Run until Ctrl+C
+ while True:
+ await asyncio.sleep(1)
+ except KeyboardInterrupt:
+ pass
+ finally:
+ await mic.aclose()
+ await player.aclose()
+ try:
+ await room.disconnect()
+ except Exception:
+ pass
+
+
+if __name__ == "__main__":
+ asyncio.run(main())
diff --git a/examples/local_audio/list_devices.py b/examples/local_audio/list_devices.py
new file mode 100644
index 00000000..a22edd15
--- /dev/null
+++ b/examples/local_audio/list_devices.py
@@ -0,0 +1,42 @@
+from livekit.rtc import MediaDevices
+
+
+def main():
+ # Create a MediaDevices instance
+ devices = MediaDevices()
+
+ # Get default devices
+ default_input_idx = devices.default_input_device()
+ default_output_idx = devices.default_output_device()
+
+ # List input devices
+ print("=== Input Devices ===")
+ input_devices = devices.list_input_devices()
+ if not input_devices:
+ print("No input devices found")
+ else:
+ for dev in input_devices:
+ default_marker = " (default)" if dev["index"] == default_input_idx else ""
+ print(
+ f" [{dev['index']}] {dev['name']}{default_marker} - "
+ f"{dev['max_input_channels']} channels @ {dev['default_samplerate']} Hz"
+ )
+
+ print()
+
+ # List output devices
+ print("=== Output Devices ===")
+ output_devices = devices.list_output_devices()
+ if not output_devices:
+ print("No output devices found")
+ else:
+ for dev in output_devices:
+ default_marker = " (default)" if dev["index"] == default_output_idx else ""
+ print(
+ f" [{dev['index']}] {dev['name']}{default_marker} - "
+ f"{dev['max_output_channels']} channels @ {dev['default_samplerate']} Hz"
+ )
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/local_audio/publish_mic.py b/examples/local_audio/publish_mic.py
new file mode 100644
index 00000000..26937a06
--- /dev/null
+++ b/examples/local_audio/publish_mic.py
@@ -0,0 +1,99 @@
+import os
+import asyncio
+import logging
+import threading
+import queue
+from dotenv import load_dotenv, find_dotenv
+
+from livekit import api, rtc
+from db_meter import calculate_db_level, display_single_db_meter
+
+
+async def main() -> None:
+ logging.basicConfig(level=logging.INFO)
+
+ # Load environment variables from a .env file if present
+ load_dotenv(find_dotenv())
+
+ url = os.getenv("LIVEKIT_URL")
+ api_key = os.getenv("LIVEKIT_API_KEY")
+ api_secret = os.getenv("LIVEKIT_API_SECRET")
+ if not url or not api_key or not api_secret:
+ raise RuntimeError(
+ "LIVEKIT_URL and LIVEKIT_API_KEY and LIVEKIT_API_SECRET must be set in env"
+ )
+
+ room = rtc.Room()
+
+ # Create media devices helper and open default microphone with AEC enabled
+ devices = rtc.MediaDevices()
+ mic = devices.open_input(enable_aec=True)
+
+ # dB level monitoring
+ mic_db_queue = queue.Queue()
+
+ token = (
+ api.AccessToken(api_key, api_secret)
+ .with_identity("local-audio")
+ .with_name("Local Audio")
+ .with_grants(
+ api.VideoGrants(
+ room_join=True,
+ room="local-audio",
+ )
+ )
+ .to_jwt()
+ )
+
+ try:
+ await room.connect(url, token)
+ logging.info("connected to room %s", room.name)
+
+ track = rtc.LocalAudioTrack.create_audio_track("mic", mic.source)
+ pub_opts = rtc.TrackPublishOptions()
+ pub_opts.source = rtc.TrackSource.SOURCE_MICROPHONE
+ await room.local_participant.publish_track(track, pub_opts)
+ logging.info("published local microphone")
+
+ # Start dB meter display in a separate thread
+ meter_thread = threading.Thread(
+ target=display_single_db_meter, args=(mic_db_queue, "Mic: "), daemon=True
+ )
+ meter_thread.start()
+
+ # Monitor microphone dB levels
+ async def monitor_mic_db():
+ mic_stream = rtc.AudioStream(track, sample_rate=48000, num_channels=1)
+ try:
+ async for frame_event in mic_stream:
+ frame = frame_event.frame
+ # Convert frame data to list of samples
+ samples = list(frame.data)
+ db_level = calculate_db_level(samples)
+ # Update queue with latest value (non-blocking)
+ try:
+ mic_db_queue.put_nowait(db_level)
+ except queue.Full:
+ pass # Drop if queue is full
+ except Exception:
+ pass
+ finally:
+ await mic_stream.aclose()
+
+ asyncio.create_task(monitor_mic_db())
+
+ # Run until Ctrl+C
+ while True:
+ await asyncio.sleep(1)
+ except KeyboardInterrupt:
+ pass
+ finally:
+ await mic.aclose()
+ try:
+ await room.disconnect()
+ except Exception:
+ pass
+
+
+if __name__ == "__main__":
+ asyncio.run(main())
diff --git a/examples/multiple_connections.py b/examples/multiple_connections.py
new file mode 100644
index 00000000..a3d03771
--- /dev/null
+++ b/examples/multiple_connections.py
@@ -0,0 +1,56 @@
+import os
+import asyncio
+from livekit import api, rtc
+
+# This example demonstrates running multiple connections sequentially in the same thread.
+# This is useful when interoperating with a synchronous framework like Django or Flask
+# where you would connect to a LiveKit room as part of a request handler.
+
+# LIVEKIT_URL needs to be set
+# also, set either LIVEKIT_TOKEN, or API_KEY and API_SECRET
+
+
+async def main():
+ url = os.environ["LIVEKIT_URL"]
+ token = os.getenv("LIVEKIT_TOKEN")
+ room = rtc.Room()
+ if not token:
+ token = (
+ api.AccessToken()
+ .with_identity("python-bot")
+ .with_name("Python Bot")
+ .with_grants(
+ api.VideoGrants(
+ room_join=True,
+ room="my-room",
+ )
+ )
+ .to_jwt()
+ )
+
+ track_sub = asyncio.Event()
+
+ @room.on("track_subscribed")
+ def on_track_subscribed(
+ track: rtc.Track,
+ publication: rtc.RemoteTrackPublication,
+ participant: rtc.RemoteParticipant,
+ ):
+ if track.kind == rtc.TrackKind.KIND_AUDIO:
+ stream = rtc.AudioStream(track) # the error comes from this line
+ track_sub.set()
+ # any created streams would need to be closed explicitly to avoid leaks
+ asyncio.get_event_loop().create_task(stream.aclose())
+ print("subscribed to audio track")
+
+ await room.connect(url, token)
+ print(f"connected to room: {room.name}")
+ await track_sub.wait()
+ await room.disconnect()
+ print("disconnected from room")
+
+
+if __name__ == "__main__":
+ asyncio.run(main())
+ asyncio.run(main())
+ print("successfully ran multiple connections")
diff --git a/examples/participant_attributes.py b/examples/participant_attributes.py
new file mode 100644
index 00000000..cf203948
--- /dev/null
+++ b/examples/participant_attributes.py
@@ -0,0 +1,71 @@
+import asyncio
+import logging
+from signal import SIGINT, SIGTERM
+import os
+
+from livekit import api, rtc
+
+# ensure LIVEKIT_URL, LIVEKIT_API_KEY, and LIVEKIT_API_SECRET are set
+
+
+async def main(room: rtc.Room) -> None:
+ token = (
+ api.AccessToken()
+ .with_identity("python-bot")
+ .with_name("Python Bot")
+ .with_grants(
+ api.VideoGrants(
+ room_join=True,
+ room="my-room",
+ can_update_own_metadata=True,
+ )
+ )
+ .to_jwt()
+ )
+
+ @room.on("participant_attributes_changed")
+ def on_participant_attributes_changed(
+ changed_attributes: dict[str, str], participant: rtc.Participant
+ ):
+ logging.info(
+ "participant attributes changed: %s %s",
+ participant.attributes,
+ changed_attributes,
+ )
+
+ await room.connect(os.getenv("LIVEKIT_URL"), token)
+ logging.info("connected to room %s", room.name)
+
+ # Create an attribute
+ await room.local_participant.set_attributes({"foo": "bar"})
+ # Delete an attribute
+ await room.local_participant.set_attributes({"foo": ""})
+
+ # Create another attribute
+ await room.local_participant.set_attributes({"baz": "qux"})
+
+ # Update an attribute
+ await room.local_participant.set_attributes({"baz": "biz"})
+
+
+if __name__ == "__main__":
+ logging.basicConfig(
+ level=logging.INFO,
+ handlers=[logging.FileHandler("basic_room.log"), logging.StreamHandler()],
+ )
+
+ loop = asyncio.get_event_loop()
+ room = rtc.Room(loop=loop)
+
+ async def cleanup():
+ await room.disconnect()
+ loop.stop()
+
+ asyncio.ensure_future(main(room))
+ for signal in [SIGINT, SIGTERM]:
+ loop.add_signal_handler(signal, lambda: asyncio.ensure_future(cleanup()))
+
+ try:
+ loop.run_forever()
+ finally:
+ loop.close()
diff --git a/examples/play_audio_stream.py b/examples/play_audio_stream.py
new file mode 100644
index 00000000..442491d0
--- /dev/null
+++ b/examples/play_audio_stream.py
@@ -0,0 +1,158 @@
+import asyncio
+import os
+import numpy as np
+import sounddevice as sd
+
+from livekit import rtc, api
+from livekit.plugins import noise_cancellation
+
+SAMPLERATE = 48000
+BLOCKSIZE = 480 # 10ms chunks at 48kHz
+CHANNELS = 1
+
+
+class AudioBuffer:
+ def __init__(self, blocksize=BLOCKSIZE):
+ self.blocksize = blocksize
+ self.buffer = np.array([], dtype=np.int16)
+
+ def add_frame(self, frame_data):
+ self.buffer = np.concatenate([self.buffer, frame_data])
+
+ def get_chunk(self):
+ if len(self.buffer) >= self.blocksize:
+ chunk = self.buffer[: self.blocksize]
+ self.buffer = self.buffer[self.blocksize :]
+ return chunk
+ return None
+
+ def get_padded_chunk(self):
+ if len(self.buffer) > 0:
+ chunk = np.zeros(self.blocksize, dtype=np.int16)
+ available = min(len(self.buffer), self.blocksize)
+ chunk[:available] = self.buffer[:available]
+ self.buffer = self.buffer[available:]
+ return chunk
+ return np.zeros(self.blocksize, dtype=np.int16)
+
+
+async def audio_player(queue: asyncio.Queue):
+ """Pull from the queue and stream audio using sounddevice."""
+ buffer = AudioBuffer(BLOCKSIZE)
+
+ def callback(outdata, frames, time, status):
+ if status:
+ print(f"Audio callback status: {status}")
+
+ # Try to fill buffer from queue
+ while not queue.empty():
+ try:
+ data = queue.get_nowait()
+ buffer.add_frame(data)
+ except asyncio.QueueEmpty:
+ break
+
+ # Get exactly the right amount of data
+ chunk = buffer.get_chunk()
+ if chunk is not None:
+ outdata[:] = chunk.reshape(-1, 1)
+ else:
+ # Not enough data, use what we have padded with zeros
+ outdata[:] = buffer.get_padded_chunk().reshape(-1, 1)
+
+ stream = sd.OutputStream(
+ samplerate=SAMPLERATE,
+ channels=CHANNELS,
+ blocksize=BLOCKSIZE,
+ dtype="int16",
+ callback=callback,
+ latency="low",
+ )
+ with stream:
+ while True:
+ await asyncio.sleep(0.1) # keep the loop alive
+
+
+async def rtc_session(room, queue: asyncio.Queue):
+ track: rtc.RemoteAudioTrack | None = None
+ while not track:
+ for participant in room.remote_participants.values():
+ for t in participant.track_publications.values():
+ if t.kind == rtc.TrackKind.KIND_AUDIO and t.subscribed:
+ track = t.track
+ break
+ if track:
+ break
+ if not track:
+ print("waiting for audio track")
+ await asyncio.sleep(2)
+
+ stream = rtc.AudioStream.from_track(
+ track=track,
+ sample_rate=SAMPLERATE,
+ num_channels=1,
+ noise_cancellation=noise_cancellation.BVC(), # or NC()
+ )
+
+ print("playing stream")
+ try:
+ # Process audio frames from the stream
+ async for audio_frame_event in stream:
+ frame = audio_frame_event.frame
+
+ audio_data = np.frombuffer(frame.data, dtype=np.int16)
+
+ try:
+ await queue.put(audio_data)
+ except asyncio.QueueFull:
+ # Skip this frame if queue is full
+ print("Warning: Audio queue full, dropping frame")
+ continue
+
+ finally:
+ # Clean up the stream when done
+ await stream.aclose()
+
+
+async def main():
+ queue = asyncio.Queue(maxsize=50)
+ player_task = asyncio.create_task(audio_player(queue))
+
+ token = (
+ api.AccessToken()
+ .with_identity("python-bot")
+ .with_name("Python Bot")
+ .with_grants(
+ api.VideoGrants(
+ room_join=True,
+ room="my-room",
+ agent=True,
+ )
+ )
+ .to_jwt()
+ )
+ url = os.getenv("LIVEKIT_URL")
+
+ room = rtc.Room()
+ await room.connect(
+ url,
+ token,
+ options=rtc.RoomOptions(
+ auto_subscribe=True,
+ ),
+ )
+ print(f"Connected to room: {room.name}")
+
+ try:
+ await rtc_session(room, queue)
+ finally:
+ # Clean up
+ await room.disconnect()
+ player_task.cancel()
+ try:
+ await player_task
+ except asyncio.CancelledError:
+ pass
+
+
+asyncio.run(main())
diff --git a/examples/publish_hue.py b/examples/publish_hue.py
index 8c26d083..a20a519a 100644
--- a/examples/publish_hue.py
+++ b/examples/publish_hue.py
@@ -3,12 +3,13 @@
import logging
import os
from signal import SIGINT, SIGTERM
+from time import perf_counter
import numpy as np
from livekit import api, rtc
WIDTH, HEIGHT = 1280, 720
-
+FPS = 30
# ensure LIVEKIT_URL, LIVEKIT_API_KEY, and LIVEKIT_API_SECRET are set
@@ -26,6 +27,13 @@ async def main(room: rtc.Room):
)
.to_jwt()
)
+
+ @room.on("participant_disconnected")
+ def on_participant_disconnected(participant: rtc.Participant):
+ logging.info(
+ f"participant {participant.identity} disconnected, reason: {rtc.DisconnectReason.Name(participant.disconnect_reason)}"
+ )
+
url = os.getenv("LIVEKIT_URL")
logging.info("connecting to %s", url)
try:
@@ -38,24 +46,51 @@ async def main(room: rtc.Room):
# publish a track
source = rtc.VideoSource(WIDTH, HEIGHT)
track = rtc.LocalVideoTrack.create_video_track("hue", source)
- options = rtc.TrackPublishOptions()
- options.source = rtc.TrackSource.SOURCE_CAMERA
+ options = rtc.TrackPublishOptions(
+ source=rtc.TrackSource.SOURCE_CAMERA,
+ simulcast=True,
+ video_encoding=rtc.VideoEncoding(
+ max_framerate=FPS,
+ max_bitrate=3_000_000,
+ ),
+ )
publication = await room.local_participant.publish_track(track, options)
logging.info("published track %s", publication.sid)
asyncio.ensure_future(draw_color_cycle(source))
+ # uncomment the below to test Track Subscription Permissions
+ # https://docs.livekit.io/home/client/tracks/publish/#subscription-permissions
+ # await asyncio.sleep(10)
+
+ # logging.info(
+ # "setting track subscription permissions to False, no one can subscribe to the track"
+ # )
+ # room.local_participant.set_track_subscription_permissions(allow_all_participants=False)
+
+ # await asyncio.sleep(10)
+
+ # logging.info("allowing user to subscribe to the track")
+ # room.local_participant.set_track_subscription_permissions(
+ # allow_all_participants=False,
+ # participant_permissions=[
+ # rtc.ParticipantTrackPermission(
+ # participant_identity="allowed-user-identity",
+ # allow_all=True,
+ # )
+ # ],
+ # )
+
async def draw_color_cycle(source: rtc.VideoSource):
argb_frame = bytearray(WIDTH * HEIGHT * 4)
arr = np.frombuffer(argb_frame, dtype=np.uint8)
- framerate = 1 / 30
+ framerate = 1 / FPS
hue = 0.0
+ next_frame_time = perf_counter()
while True:
- start_time = asyncio.get_event_loop().time()
-
rgb = colorsys.hsv_to_rgb(hue, 1.0, 1.0)
rgb = [(x * 255) for x in rgb] # type: ignore
@@ -69,8 +104,10 @@ async def draw_color_cycle(source: rtc.VideoSource):
source.capture_frame(frame)
hue = (hue + framerate / 3) % 1.0
- code_duration = asyncio.get_event_loop().time() - start_time
- await asyncio.sleep(1 / 30 - code_duration)
+ # code_duration = perf_counter() - start_time
+ next_frame_time += 1 / FPS
+ await asyncio.sleep(next_frame_time - perf_counter())
+ # await asyncio.sleep(1 / FPS - code_duration)
if __name__ == "__main__":
diff --git a/examples/room_example.py b/examples/room_example.py
new file mode 100644
index 00000000..6efb0361
--- /dev/null
+++ b/examples/room_example.py
@@ -0,0 +1,67 @@
+import os
+import logging
+import asyncio
+from livekit import rtc
+
+# Set the following environment variables with your own values
+TOKEN = os.environ.get("LIVEKIT_TOKEN")
+URL = os.environ.get("LIVEKIT_URL")
+
+
+async def main():
+ logging.basicConfig(level=logging.INFO)
+ logger = logging.getLogger(__name__)
+ room = rtc.Room()
+
+ @room.on("participant_connected")
+ def on_participant_connected(participant: rtc.RemoteParticipant):
+ logger.info("participant connected: %s %s", participant.sid, participant.identity)
+
+ async def receive_frames(stream: rtc.VideoStream):
+ async for frame in stream:
+ # received a video frame from the track, process it here
+ pass
+
+ # track_subscribed is emitted whenever the local participant is subscribed to a new track
+ @room.on("track_subscribed")
+ def on_track_subscribed(
+ track: rtc.Track,
+ publication: rtc.RemoteTrackPublication,
+ participant: rtc.RemoteParticipant,
+ ):
+ logger.info("track subscribed: %s", publication.sid)
+ if track.kind == rtc.TrackKind.KIND_VIDEO:
+ video_stream = rtc.VideoStream(track)
+ asyncio.ensure_future(receive_frames(video_stream))
+
+ # By default, autosubscribe is enabled. The participant will be subscribed to
+ # all published tracks in the room
+ await room.connect(URL, TOKEN)
+ logger.info("connected to room %s", room.name)
+
+ for identity, participant in room.remote_participants.items():
+ print(f"identity: {identity}")
+ print(f"participant: {participant}")
+ # Now participant is the RemoteParticipant object, not a tuple
+ print(f"participant sid: {participant.sid}")
+ print(f"participant identity: {participant.identity}")
+ print(f"participant name: {participant.name}")
+ print(f"participant kind: {participant.kind}")
+ print(f"participant track publications: {participant.track_publications}")
+ for tid, publication in participant.track_publications.items():
+ print(f"\ttrack id: {tid}")
+ print(f"\t\ttrack publication: {publication}")
+ print(f"\t\ttrack kind: {publication.kind}")
+ print(f"\t\ttrack name: {publication.name}")
+ print(f"\t\ttrack source: {publication.source}")
+
+ print(f"participant metadata: {participant.metadata}")
+
+
+if __name__ == "__main__":
+ # exit if token and url are not set
+ if not TOKEN or not URL:
+ print("TOKEN and URL are required environment variables")
+ exit(1)
+
+ asyncio.run(main())
diff --git a/examples/rpc.py b/examples/rpc.py
new file mode 100644
index 00000000..005701fa
--- /dev/null
+++ b/examples/rpc.py
@@ -0,0 +1,277 @@
+from livekit import rtc, api
+import os
+import json
+import asyncio
+from dotenv import load_dotenv
+from livekit.rtc.rpc import RpcInvocationData
+
+load_dotenv(dotenv_path=".env.local", override=False)
+LIVEKIT_API_KEY = os.getenv("LIVEKIT_API_KEY")
+LIVEKIT_API_SECRET = os.getenv("LIVEKIT_API_SECRET")
+LIVEKIT_URL = os.getenv("LIVEKIT_URL")
+if not LIVEKIT_API_KEY or not LIVEKIT_API_SECRET or not LIVEKIT_URL:
+ raise ValueError("Missing required environment variables. Please check your .env.local file.")
+
+
+async def main():
+ rooms = [] # Keep track of all rooms for cleanup
+ try:
+ room_name = f"rpc-test-{os.urandom(4).hex()}"
+ print(f"Connecting participants to room: {room_name}")
+
+ callers_room, greeters_room, math_genius_room = await asyncio.gather(
+ connect_participant("caller", room_name),
+ connect_participant("greeter", room_name),
+ connect_participant("math-genius", room_name),
+ )
+ rooms = [callers_room, greeters_room, math_genius_room]
+
+ register_receiver_methods(greeters_room, math_genius_room)
+
+ try:
+ print("\n\nRunning greeting example...")
+ await asyncio.gather(perform_greeting(callers_room))
+ except Exception as error:
+ print("Error:", error)
+
+ try:
+ print("\n\nRunning error handling example...")
+ await perform_divide(callers_room)
+ except Exception as error:
+ print("Error:", error)
+
+ try:
+ print("\n\nRunning math example...")
+ await perform_square_root(callers_room)
+ await asyncio.sleep(2)
+ await perform_quantum_hypergeometric_series(callers_room)
+ except Exception as error:
+ print("Error:", error)
+
+ try:
+ print("\n\nRunning long calculation with timeout...")
+ await asyncio.create_task(perform_long_calculation(callers_room))
+ except Exception as error:
+ print("Error:", error)
+
+ try:
+ print("\n\nRunning long calculation with disconnect...")
+ # Start the long calculation
+ long_calc_task = asyncio.create_task(perform_long_calculation(callers_room))
+ # Wait a bit then disconnect the math genius
+ await asyncio.sleep(5)
+ print("\nDisconnecting math genius early...")
+ await math_genius_room.disconnect()
+ # Wait for the calculation to fail
+ await long_calc_task
+ except Exception as error:
+ print("Error:", error)
+
+ print("\n\nParticipants done, disconnecting remaining participants...")
+ await callers_room.disconnect()
+ await greeters_room.disconnect()
+
+ print("Participants disconnected. Example completed.")
+
+ except KeyboardInterrupt:
+ print("\nReceived interrupt signal, cleaning up...")
+ except Exception as e:
+ print(f"Unexpected error: {e}")
+ finally:
+ # Clean up all rooms
+ print("Disconnecting all participants...")
+ await asyncio.gather(*(room.disconnect() for room in rooms), return_exceptions=True)
+ print("Cleanup complete")
+
+
+def register_receiver_methods(greeters_room: rtc.Room, math_genius_room: rtc.Room):
+ @greeters_room.local_participant.register_rpc_method("arrival")
+ async def arrival_method(
+ data: RpcInvocationData,
+ ):
+ print(f'[Greeter] Oh {data.caller_identity} arrived and said "{data.payload}"')
+ await asyncio.sleep(2)
+ return "Welcome and have a wonderful day!"
+
+ @math_genius_room.local_participant.register_rpc_method("square-root")
+ async def square_root_method(
+ data: RpcInvocationData,
+ ):
+ json_data = json.loads(data.payload)
+ number = json_data["number"]
+ print(
+ f"[Math Genius] I guess {data.caller_identity} wants the square root of {number}. I've only got {data.response_timeout} seconds to respond but I think I can pull it off."
+ )
+
+ print("[Math Genius] *doing math*…")
+ await asyncio.sleep(2)
+
+ result = number**0.5
+ print(f"[Math Genius] Aha! It's {result}")
+ return json.dumps({"result": result})
+
+ @math_genius_room.local_participant.register_rpc_method("divide")
+ async def divide_method(
+ data: RpcInvocationData,
+ ):
+ json_data = json.loads(data.payload)
+ dividend = json_data["dividend"]
+ divisor = json_data["divisor"]
+ print(f"[Math Genius] {data.caller_identity} wants to divide {dividend} by {divisor}.")
+
+ result = dividend / divisor
+ return json.dumps({"result": result})
+
+ @math_genius_room.local_participant.register_rpc_method("long-calculation")
+ async def long_calculation_method(
+ data: RpcInvocationData,
+ ):
+ print(f"[Math Genius] Starting a very long calculation for {data.caller_identity}")
+ print(
+ f"[Math Genius] This will take 30 seconds even though you're only giving me {data.response_timeout} seconds"
+ )
+ await asyncio.sleep(30)
+ return json.dumps({"result": "Calculation complete!"})
+
+
+async def perform_greeting(room: rtc.Room):
+ print("[Caller] Letting the greeter know that I've arrived")
+ try:
+ response = await room.local_participant.perform_rpc(
+ destination_identity="greeter", method="arrival", payload="Hello"
+ )
+ print(f'[Caller] That\'s nice, the greeter said: "{response}"')
+ except Exception as error:
+ print(f"[Caller] RPC call failed: {error}")
+ raise
+
+
+async def perform_square_root(room: rtc.Room):
+ print("[Caller] What's the square root of 16?")
+ try:
+ response = await room.local_participant.perform_rpc(
+ destination_identity="math-genius",
+ method="square-root",
+ payload=json.dumps({"number": 16}),
+ )
+ parsed_response = json.loads(response)
+ print(f"[Caller] Nice, the answer was {parsed_response['result']}")
+ except Exception as error:
+ print(f"[Caller] RPC call failed: {error}")
+ raise
+
+
+async def perform_quantum_hypergeometric_series(room: rtc.Room):
+ print("[Caller] What's the quantum hypergeometric series of 42?")
+ try:
+ response = await room.local_participant.perform_rpc(
+ destination_identity="math-genius",
+ method="quantum-hypergeometric-series",
+ payload=json.dumps({"number": 42}),
+ )
+ parsed_response = json.loads(response)
+ print(f"[Caller] genius says {parsed_response['result']}!")
+ except rtc.RpcError as error:
+ if error.code == rtc.RpcError.ErrorCode.UNSUPPORTED_METHOD:
+ print("[Caller] Aww looks like the genius doesn't know that one.")
+ return
+ print("[Caller] Unexpected error:", error)
+ raise
+ except Exception as error:
+ print("[Caller] Unexpected error:", error)
+ raise
+
+
+async def perform_divide(room: rtc.Room):
+ print("[Caller] Let's divide 10 by 0.")
+ try:
+ response = await room.local_participant.perform_rpc(
+ destination_identity="math-genius",
+ method="divide",
+ payload=json.dumps({"dividend": 10, "divisor": 0}),
+ )
+ parsed_response = json.loads(response)
+ print(f"[Caller] The result is {parsed_response['result']}")
+ except rtc.RpcError as error:
+ if error.code == rtc.RpcError.ErrorCode.APPLICATION_ERROR:
+ print("[Caller] Aww something went wrong with that one, lets try something else.")
+ else:
+ print(f"[Caller] RPC call failed with unexpected RpcError: {error}")
+ except Exception as error:
+ print(f"[Caller] RPC call failed with unexpected error: {error}")
+
+
+async def perform_long_calculation(room: rtc.Room):
+ print("[Caller] Giving the math genius 10s to complete a long calculation")
+ try:
+ response = await room.local_participant.perform_rpc(
+ destination_identity="math-genius",
+ method="long-calculation",
+ payload=json.dumps({}),
+ response_timeout=10,
+ )
+ parsed_response = json.loads(response)
+ print(f"[Caller] Result: {parsed_response['result']}")
+ except rtc.RpcError as error:
+ if error.code == rtc.RpcError.ErrorCode.RESPONSE_TIMEOUT:
+ print("[Caller] Math genius took too long to respond")
+ elif error.code == rtc.RpcError.ErrorCode.RECIPIENT_DISCONNECTED:
+ print("[Caller] Math genius disconnected before response was received")
+ else:
+ print(f"[Caller] Unexpected RPC error: {error}")
+ except Exception as error:
+ print(f"[Caller] Unexpected error: {error}")
+
+
+def create_token(identity: str, room_name: str):
+ token = (
+ api.AccessToken(LIVEKIT_API_KEY, LIVEKIT_API_SECRET)
+ .with_identity(identity)
+ .with_grants(
+ api.VideoGrants(
+ room=room_name,
+ room_join=True,
+ can_publish=True,
+ can_subscribe=True,
+ )
+ )
+ )
+ return token.to_jwt()
+
+
+async def connect_participant(identity: str, room_name: str) -> rtc.Room:
+ room = rtc.Room()
+ token = create_token(identity, room_name)
+
+ def on_disconnected(reason: str):
+ print(f"[{identity}] Disconnected from room: {reason}")
+
+ room.on("disconnected", on_disconnected)
+
+ await room.connect(LIVEKIT_URL, token)
+
+ async def wait_for_participants():
+ if room.remote_participants:
+ return
+ participant_connected = asyncio.Event()
+
+ def _on_participant_connected(participant: rtc.RemoteParticipant):
+ room.off("participant_connected", _on_participant_connected)
+ participant_connected.set()
+
+ room.on("participant_connected", _on_participant_connected)
+ await participant_connected.wait()
+
+ try:
+ await asyncio.wait_for(wait_for_participants(), timeout=5.0)
+ except asyncio.TimeoutError:
+ raise TimeoutError("Timed out waiting for participants")
+
+ return room
+
+
+if __name__ == "__main__":
+ try:
+ asyncio.run(main())
+ except KeyboardInterrupt:
+ print("\nProgram terminated by user")
diff --git a/examples/video-stream/README.md b/examples/video-stream/README.md
new file mode 100644
index 00000000..8b02faa2
--- /dev/null
+++ b/examples/video-stream/README.md
@@ -0,0 +1,48 @@
+# Video and Audio Synchronization Examples
+
+This example demonstrates how to synchronize video and audio streams using the `AVSynchronizer` utility.
+
+## AVSynchronizer Usage
+
+The `AVSynchronizer` helps maintain synchronization between video and audio frames. The key principle is to push the initial synchronized video and audio frames together. After that, subsequent frames will be automatically synchronized according to the configured video FPS and audio sample rate.
+
+```python
+av_sync = AVSynchronizer(
+ audio_source=audio_source,
+ video_source=video_source,
+ video_fps=30.0,
+ video_queue_size_ms=100
+)
+
+# Push frames to synchronizer
+await av_sync.push(video_frame)
+await av_sync.push(audio_frame)
+```
+
+## Examples
+
+### 1. Video File Playback (`video_play.py`)
+
+Demonstrates synchronizing video and audio from separate sources while maintaining sync:
+
+- Reads video and audio streams separately from a media file (using `av` library)
+- Uses separate tasks to push video and audio frames to the synchronizer
+- Since the streams are continuous, a larger `queue_size_ms` can be used, though this will increase memory usage
+
+#### Usage:
+
+```bash
+python video_play.py
+```
+
+### 2. Audio Visualization (`audio_wave.py`)
+
+Demonstrates generating video based on audio input:
+
+- Generates audio frames with alternating sine waves and silence
+- Creates video frames visualizing the audio waveform (using `cv2` library)
+- Shows how to handle cases with and without audio:
+ - When audio is present: Push synchronized video and audio frames
+ - During silence: Push only video frames
+- Since video and audio frames are pushed in the same loop, audio frames must be smaller than the audio source queue size to avoid blocking
+- Uses a small `queue_size_ms` (e.g. 50ms) to control frame generation speed during silence periods
diff --git a/examples/video-stream/audio_wave.py b/examples/video-stream/audio_wave.py
new file mode 100644
index 00000000..8c600b9a
--- /dev/null
+++ b/examples/video-stream/audio_wave.py
@@ -0,0 +1,321 @@
+import asyncio
+import logging
+import os
+import signal
+import time
+from collections import deque
+from dataclasses import dataclass
+from typing import AsyncIterable, Optional, Union
+
+import numpy as np
+from livekit import rtc, api
+import sys
+
+try:
+ import cv2
+except ImportError:
+ raise RuntimeError(
+ "cv2 is required to run this example, install with `pip install opencv-python`"
+ )
+
+# ensure LIVEKIT_URL, LIVEKIT_API_KEY, and LIVEKIT_API_SECRET are set
+
+logger = logging.getLogger(__name__)
+
+
+@dataclass
+class MediaInfo:
+ video_width: int
+ video_height: int
+ video_fps: float
+ audio_sample_rate: int
+ audio_channels: int
+
+
+class _AudioEndSentinel:
+ pass
+
+
+async def audio_generator(
+ media_info: MediaInfo,
+ output_audio: asyncio.Queue[Union[rtc.AudioFrame, _AudioEndSentinel]],
+):
+ """Generates audio frames with alternating sine wave and silence periods"""
+ frequency = 480 # Hz
+ amplitude = 0.5
+ period = 7.0
+ sine_duration = 5.0 # Duration of sine wave in each period
+ chunk_size = 1024
+
+ while True:
+ current_time = 0.0
+
+ # Generate audio for sine_duration seconds
+ while current_time < sine_duration:
+ t = np.linspace(
+ current_time,
+ current_time + chunk_size / media_info.audio_sample_rate,
+ num=chunk_size,
+ endpoint=False,
+ )
+ # Create volume envelope using sine wave
+ volume = np.abs(np.sin(2 * np.pi * current_time / sine_duration))
+ samples = amplitude * volume * np.sin(2 * np.pi * frequency * t)
+
+ # Convert to int16, (samples, channels)
+ samples = (samples[:, np.newaxis] * 32767).astype(np.int16)
+ if media_info.audio_channels > 1:
+ samples = np.repeat(samples, media_info.audio_channels, axis=1)
+
+ # Create audio frame
+ audio_frame = rtc.AudioFrame(
+ data=samples.tobytes(),
+ sample_rate=media_info.audio_sample_rate,
+ num_channels=samples.shape[1],
+ samples_per_channel=samples.shape[0],
+ )
+ await output_audio.put(audio_frame)
+ current_time += chunk_size / media_info.audio_sample_rate
+ await asyncio.sleep(0)
+ await output_audio.put(_AudioEndSentinel())
+
+ # Simulate silence
+ silence_duration = period - sine_duration
+ await asyncio.sleep(silence_duration)
+
+
+class WaveformVisualizer:
+ def __init__(self, history_length: int = 1000):
+ self.history_length = history_length
+ self.volume_history: deque[float] = deque(maxlen=history_length)
+ self.start_time = time.time()
+
+ def draw_timestamp(self, canvas: np.ndarray, fps: float):
+ height, width = canvas.shape[:2]
+ text = f"{time.time() - self.start_time:.1f}s @ {fps:.1f}fps"
+ font_face = cv2.FONT_HERSHEY_SIMPLEX
+ font_scale = 2.0
+ thickness = 2
+
+ (text_width, text_height), baseline = cv2.getTextSize(
+ text, font_face, font_scale, thickness
+ )
+ x = (width - text_width) // 2
+ y = int((height - text_height) * 0.4 + baseline)
+ cv2.putText(canvas, text, (x, y), font_face, font_scale, (0, 0, 0), thickness)
+
+ def draw_current_wave(self, canvas: np.ndarray, audio_samples: np.ndarray) -> np.ndarray:
+ """Draw the current waveform and return the current values"""
+ height, width = canvas.shape[:2]
+ center_y = height // 2 + 100
+
+ normalized_samples = audio_samples.astype(np.float32) / 32767.0
+ normalized_samples = normalized_samples.mean(axis=1) # (samples,)
+ num_points = min(width, len(normalized_samples))
+
+ if len(normalized_samples) > num_points:
+ indices = np.linspace(0, len(normalized_samples) - 1, num_points, dtype=int)
+ plot_data = normalized_samples[indices]
+ else:
+ plot_data = normalized_samples
+
+ x_coords = np.linspace(0, width, num_points, dtype=int)
+ y_coords = (plot_data * 200) + center_y
+
+ cv2.line(canvas, (0, center_y), (width, center_y), (200, 200, 200), 1)
+ points = np.column_stack((x_coords, y_coords.astype(int)))
+ for i in range(len(points) - 1):
+ cv2.line(canvas, tuple(points[i]), tuple(points[i + 1]), (0, 255, 0), 2)
+
+ return plot_data
+
+ def draw_volume_history(self, canvas: np.ndarray, current_volume: float):
+ height, width = canvas.shape[:2]
+ center_y = height // 2
+
+ self.volume_history.append(current_volume)
+ cv2.line(canvas, (0, center_y - 250), (width, center_y - 250), (200, 200, 200), 1)
+
+ volume_x = np.linspace(0, width, len(self.volume_history), dtype=int)
+ volume_y = center_y - 250 + (np.array(self.volume_history) * 200)
+ points = np.column_stack((volume_x, volume_y.astype(int)))
+ for i in range(len(points) - 1):
+ cv2.line(canvas, tuple(points[i]), tuple(points[i + 1]), (255, 0, 0), 2)
+
+ def draw(self, canvas: np.ndarray, audio_samples: np.ndarray, fps: float):
+ self.draw_timestamp(canvas, fps)
+ plot_data = self.draw_current_wave(canvas, audio_samples)
+ current_volume = np.abs(plot_data).mean()
+ self.draw_volume_history(canvas, current_volume)
+
+
+async def video_generator(
+ media_info: MediaInfo,
+ input_audio: asyncio.Queue[Union[rtc.AudioFrame, _AudioEndSentinel]],
+ av_sync: rtc.AVSynchronizer, # only used for drawing the actual fps on the video
+) -> AsyncIterable[tuple[rtc.VideoFrame, Optional[rtc.AudioFrame]]]:
+ canvas = np.zeros((media_info.video_height, media_info.video_width, 4), dtype=np.uint8)
+ canvas.fill(255)
+
+ def _np_to_video_frame(image: np.ndarray) -> rtc.VideoFrame:
+ return rtc.VideoFrame(
+ width=image.shape[1],
+ height=image.shape[0],
+ type=rtc.VideoBufferType.RGBA,
+ data=image.tobytes(),
+ )
+
+ audio_samples_per_frame = int(media_info.audio_sample_rate / media_info.video_fps)
+ audio_buffer = np.zeros((0, media_info.audio_channels), dtype=np.int16)
+ wave_visualizer = WaveformVisualizer()
+ while True:
+ try:
+ # timeout has to be shorter than the frame interval to avoid starvation
+ audio_frame = await asyncio.wait_for(
+ input_audio.get(), timeout=0.5 / media_info.video_fps
+ )
+ except asyncio.TimeoutError:
+ # generate frame without audio (e.g. silence state)
+ new_frame = canvas.copy()
+ wave_visualizer.draw(new_frame, np.zeros((1, 2)), av_sync.actual_fps)
+ video_frame = _np_to_video_frame(new_frame)
+ yield video_frame, None
+
+ # speed is controlled by the video fps in av_sync
+ await asyncio.sleep(0)
+ continue
+
+ if isinstance(audio_frame, _AudioEndSentinel):
+ # drop the audio buffer when the audio finished
+ audio_buffer = np.zeros((0, media_info.audio_channels), dtype=np.int16)
+ continue
+
+ audio_samples = np.frombuffer(audio_frame.data, dtype=np.int16).reshape(
+ -1, audio_frame.num_channels
+ ) # (samples, channels)
+ # accumulate audio samples to the buffer
+ audio_buffer = np.concatenate([audio_buffer, audio_samples], axis=0)
+
+ while audio_buffer.shape[0] >= audio_samples_per_frame:
+ sub_samples = audio_buffer[:audio_samples_per_frame, :]
+ audio_buffer = audio_buffer[audio_samples_per_frame:, :]
+
+ new_frame = canvas.copy()
+ wave_visualizer.draw(new_frame, sub_samples, av_sync.actual_fps)
+ video_frame = _np_to_video_frame(new_frame)
+ sub_audio_frame = rtc.AudioFrame(
+ data=sub_samples.tobytes(),
+ sample_rate=audio_frame.sample_rate,
+ num_channels=sub_samples.shape[1],
+ samples_per_channel=sub_samples.shape[0],
+ )
+ yield video_frame, sub_audio_frame
+
+
+async def main(room: rtc.Room, room_name: str):
+ token = (
+ api.AccessToken()
+ .with_identity("python-publisher")
+ .with_name("Python Publisher")
+ .with_grants(
+ api.VideoGrants(
+ room_join=True,
+ room=room_name,
+ agent=True,
+ )
+ )
+ .to_jwt()
+ )
+ url = os.getenv("LIVEKIT_URL")
+ logging.info("connecting to %s", url)
+
+ try:
+ await room.connect(url, token)
+ logging.info("connected to room %s", room.name)
+ except rtc.ConnectError as e:
+ logging.error("failed to connect to the room: %s", e)
+ return
+
+ # Create media info
+ media_info = MediaInfo(
+ video_width=1280,
+ video_height=720,
+ video_fps=30.0,
+ audio_sample_rate=48000,
+ audio_channels=2,
+ )
+
+ # Create video and audio sources/tracks
+ queue_size_ms = 50
+ video_source = rtc.VideoSource(
+ width=media_info.video_width,
+ height=media_info.video_height,
+ )
+ audio_source = rtc.AudioSource(
+ sample_rate=media_info.audio_sample_rate,
+ num_channels=media_info.audio_channels,
+ queue_size_ms=queue_size_ms,
+ )
+
+ video_track = rtc.LocalVideoTrack.create_video_track("video", video_source)
+ audio_track = rtc.LocalAudioTrack.create_audio_track("audio", audio_source)
+
+ # Publish tracks
+ video_options = rtc.TrackPublishOptions(source=rtc.TrackSource.SOURCE_CAMERA)
+ audio_options = rtc.TrackPublishOptions(source=rtc.TrackSource.SOURCE_MICROPHONE)
+
+ await room.local_participant.publish_track(video_track, video_options)
+ await room.local_participant.publish_track(audio_track, audio_options)
+
+ # Create AV synchronizer
+ av_sync = rtc.AVSynchronizer(
+ audio_source=audio_source,
+ video_source=video_source,
+ video_fps=media_info.video_fps,
+ video_queue_size_ms=queue_size_ms,
+ )
+
+ # Start audio generator
+ audio_queue = asyncio.Queue[Union[rtc.AudioFrame, _AudioEndSentinel]](maxsize=1)
+ audio_task = asyncio.create_task(audio_generator(media_info, audio_queue))
+
+ try:
+ async for video_frame, audio_frame in video_generator(
+ media_info, audio_queue, av_sync=av_sync
+ ):
+ await av_sync.push(video_frame)
+ if audio_frame:
+ await av_sync.push(audio_frame)
+ finally:
+ audio_task.cancel()
+ await av_sync.aclose()
+ await audio_source.aclose()
+ await video_source.aclose()
+
+
+if __name__ == "__main__":
+ logging.basicConfig(
+ level=logging.INFO,
+ handlers=[logging.FileHandler("audio_wave.log"), logging.StreamHandler()],
+ )
+
+ if len(sys.argv) != 2:
+ print("Usage: python audio_wave.py ")
+ sys.exit(1)
+
+ room_name = sys.argv[1]
+ loop = asyncio.get_event_loop()
+ room = rtc.Room(loop=loop)
+
+ async def cleanup():
+ await room.disconnect()
+ loop.stop()
+
+ asyncio.ensure_future(main(room, room_name))
+ for signal in [signal.SIGINT, signal.SIGTERM]:
+ loop.add_signal_handler(signal, lambda: asyncio.ensure_future(cleanup()))
+
+ try:
+ loop.run_forever()
+ finally:
+ loop.close()
diff --git a/examples/video-stream/video_play.py b/examples/video-stream/video_play.py
new file mode 100644
index 00000000..f40ed4ec
--- /dev/null
+++ b/examples/video-stream/video_play.py
@@ -0,0 +1,249 @@
+import asyncio
+import logging
+from dataclasses import dataclass
+from pathlib import Path
+from typing import AsyncIterable, Union
+import sys
+
+import numpy as np
+import os
+import signal
+from livekit import api
+from livekit import rtc
+
+try:
+ import av
+except ImportError:
+ raise RuntimeError("av is required to run this example, install with `pip install av`")
+
+# ensure LIVEKIT_URL, LIVEKIT_API_KEY, and LIVEKIT_API_SECRET are set
+
+logger = logging.getLogger(__name__)
+
+
+@dataclass
+class MediaInfo:
+ video_width: int
+ video_height: int
+ video_fps: float
+ audio_sample_rate: int
+ audio_channels: int
+
+
+class MediaFileStreamer:
+ """Streams video and audio frames from a media file in an endless loop."""
+
+ def __init__(self, media_file: Union[str, Path]) -> None:
+ self._media_file = str(media_file)
+ # Create separate containers for each stream
+ self._video_container = av.open(self._media_file)
+ self._audio_container = av.open(self._media_file)
+
+ # Cache media info
+ video_stream = self._video_container.streams.video[0]
+ audio_stream = self._audio_container.streams.audio[0]
+ self._info = MediaInfo(
+ video_width=video_stream.width,
+ video_height=video_stream.height,
+ video_fps=float(video_stream.average_rate), # type: ignore
+ audio_sample_rate=audio_stream.sample_rate,
+ audio_channels=audio_stream.channels,
+ )
+
+ @property
+ def info(self) -> MediaInfo:
+ return self._info
+
+ async def stream_video(self) -> AsyncIterable[tuple[rtc.VideoFrame, float]]:
+ """Streams video frames from the media file in an endless loop."""
+ for i, av_frame in enumerate(self._video_container.decode(video=0)):
+ # Convert video frame to RGBA
+ frame = av_frame.to_rgb().to_ndarray()
+ frame_rgba = np.ones((frame.shape[0], frame.shape[1], 4), dtype=np.uint8)
+ frame_rgba[:, :, :3] = frame
+ yield (
+ rtc.VideoFrame(
+ width=frame.shape[1],
+ height=frame.shape[0],
+ type=rtc.VideoBufferType.RGBA,
+ data=frame_rgba.tobytes(),
+ ),
+ av_frame.time,
+ )
+
+ async def stream_audio(self) -> AsyncIterable[tuple[rtc.AudioFrame, float]]:
+ """Streams audio frames from the media file in an endless loop."""
+ for av_frame in self._audio_container.decode(audio=0):
+ # Convert audio frame to raw int16 samples
+ frame = av_frame.to_ndarray().T # Transpose to (samples, channels)
+ frame = (frame * 32768).astype(np.int16)
+ duration = len(frame) / self.info.audio_sample_rate
+ yield (
+ rtc.AudioFrame(
+ data=frame.tobytes(),
+ sample_rate=self.info.audio_sample_rate,
+ num_channels=frame.shape[1],
+ samples_per_channel=frame.shape[0],
+ ),
+ av_frame.time + duration,
+ )
+
+ def reset(self):
+ self._video_container.seek(0)
+ self._audio_container.seek(0)
+
+ async def aclose(self) -> None:
+ """Closes the media container and stops streaming."""
+ self._video_container.close()
+ self._audio_container.close()
+
+
+async def main(room: rtc.Room, room_name: str, media_path: str):
+ token = (
+ api.AccessToken()
+ .with_identity("python-publisher")
+ .with_name("Python Publisher")
+ .with_grants(
+ api.VideoGrants(
+ room_join=True,
+ room=room_name,
+ agent=True,
+ )
+ )
+ .to_jwt()
+ )
+ url = os.getenv("LIVEKIT_URL")
+ logging.info("connecting to %s", url)
+
+ try:
+ await room.connect(url, token)
+ logging.info("connected to room %s", room.name)
+ except rtc.ConnectError as e:
+ logging.error("failed to connect to the room: %s", e)
+ return
+
+ # Create media streamer
+ streamer = MediaFileStreamer(media_path)
+ media_info = streamer.info
+
+ # Create video and audio sources/tracks
+ queue_size_ms = 1000
+ video_source = rtc.VideoSource(
+ width=media_info.video_width,
+ height=media_info.video_height,
+ )
+ logger.info(media_info)
+ audio_source = rtc.AudioSource(
+ sample_rate=media_info.audio_sample_rate,
+ num_channels=media_info.audio_channels,
+ queue_size_ms=queue_size_ms,
+ )
+
+ video_track = rtc.LocalVideoTrack.create_video_track("video", video_source)
+ audio_track = rtc.LocalAudioTrack.create_audio_track("audio", audio_source)
+
+ # Publish tracks
+ video_options = rtc.TrackPublishOptions(
+ source=rtc.TrackSource.SOURCE_CAMERA,
+ video_encoding=rtc.VideoEncoding(
+ max_framerate=30,
+ max_bitrate=5_000_000,
+ ),
+ )
+ audio_options = rtc.TrackPublishOptions(source=rtc.TrackSource.SOURCE_MICROPHONE)
+
+ await room.local_participant.publish_track(video_track, video_options)
+ await room.local_participant.publish_track(audio_track, audio_options)
+
+ av_sync = rtc.AVSynchronizer(
+ audio_source=audio_source,
+ video_source=video_source,
+ video_fps=media_info.video_fps,
+ video_queue_size_ms=queue_size_ms,
+ )
+
+ async def _push_frames(
+ stream: AsyncIterable[tuple[rtc.VideoFrame | rtc.AudioFrame, float]],
+ av_sync: rtc.AVSynchronizer,
+ ):
+ async for frame, timestamp in stream:
+ await av_sync.push(frame, timestamp)
+ await asyncio.sleep(0)
+
+ async def _log_fps(av_sync: rtc.AVSynchronizer):
+ start_time = asyncio.get_running_loop().time()
+ while True:
+ await asyncio.sleep(2)
+ wall_time = asyncio.get_running_loop().time() - start_time
+ diff = av_sync.last_video_time - av_sync.last_audio_time
+ logger.info(
+ f"fps: {av_sync.actual_fps:.2f}, wall_time: {wall_time:.3f}s, "
+ f"video_time: {av_sync.last_video_time:.3f}s, "
+ f"audio_time: {av_sync.last_audio_time:.3f}s, diff: {diff:.3f}s"
+ )
+
+ try:
+ while True:
+ streamer.reset()
+
+ video_stream = streamer.stream_video()
+ audio_stream = streamer.stream_audio()
+
+ # read the head frames and push them at the same time
+ first_video_frame, video_timestamp = await video_stream.__anext__()
+ first_audio_frame, audio_timestamp = await audio_stream.__anext__()
+ logger.info(
+ f"first video duration: {1 / media_info.video_fps:.3f}s, "
+ f"first audio duration: {first_audio_frame.duration:.3f}s"
+ )
+ await av_sync.push(first_video_frame, video_timestamp)
+ await av_sync.push(first_audio_frame, audio_timestamp)
+
+ video_task = asyncio.create_task(_push_frames(video_stream, av_sync))
+ audio_task = asyncio.create_task(_push_frames(audio_stream, av_sync))
+
+ log_fps_task = asyncio.create_task(_log_fps(av_sync))
+
+ # wait for both tasks to complete
+ await asyncio.gather(video_task, audio_task)
+ await av_sync.wait_for_playout()
+
+ # clean up
+ av_sync.reset()
+ log_fps_task.cancel()
+ logger.info("playout finished")
+ finally:
+ await streamer.aclose()
+ await av_sync.aclose()
+ await audio_source.aclose()
+ await video_source.aclose()
+
+
+if __name__ == "__main__":
+ logging.basicConfig(
+ level=logging.INFO,
+ handlers=[logging.FileHandler("video_play.log"), logging.StreamHandler()],
+ )
+
+ if len(sys.argv) != 3:
+ print("Usage: python video_play.py ")
+ sys.exit(1)
+
+ room_name = sys.argv[1]
+ media_path = sys.argv[2]
+
+ loop = asyncio.get_event_loop()
+ room = rtc.Room(loop=loop)
+
+ async def cleanup():
+ await room.disconnect()
+ loop.stop()
+
+ asyncio.ensure_future(main(room, room_name, media_path))
+ for signal in [signal.SIGINT, signal.SIGTERM]:
+ loop.add_signal_handler(signal, lambda: asyncio.ensure_future(cleanup()))
+
+ try:
+ loop.run_forever()
+ finally:
+ loop.close()
diff --git a/livekit-api/README.md b/livekit-api/README.md
index c4b77002..14b5e35f 100644
--- a/livekit-api/README.md
+++ b/livekit-api/README.md
@@ -1,3 +1,6 @@
# LiveKit Server APIs
Access LiveKit server APIs and generate access tokens.
+
+See https://docs.livekit.io/reference/server/server-apis for more information.
+
diff --git a/livekit-api/livekit/api/__init__.py b/livekit-api/livekit/api/__init__.py
index 714ce134..fb115f6f 100644
--- a/livekit-api/livekit/api/__init__.py
+++ b/livekit-api/livekit/api/__init__.py
@@ -12,19 +12,58 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-"""LiveKit API SDK"""
+"""LiveKit Server APIs for Python
+
+`pip install livekit-api`
+
+Manage rooms, participants, egress, ingress, SIP, and Agent dispatch.
+
+Primary entry point is `LiveKitAPI`.
+
+See https://docs.livekit.io/reference/server/server-apis for more information.
+"""
# flake8: noqa
# re-export packages from protocol
+from livekit.protocol.agent_dispatch import *
+from livekit.protocol.agent import *
from livekit.protocol.egress import *
from livekit.protocol.ingress import *
from livekit.protocol.models import *
from livekit.protocol.room import *
from livekit.protocol.webhook import *
from livekit.protocol.sip import *
+from livekit.protocol.connector_whatsapp import *
+from livekit.protocol.connector_twilio import *
from .twirp_client import TwirpError, TwirpErrorCode
from .livekit_api import LiveKitAPI
-from .access_token import VideoGrants, SIPGrants, AccessToken, TokenVerifier
+from .access_token import (
+ InferenceGrants,
+ ObservabilityGrants,
+ VideoGrants,
+ SIPGrants,
+ AccessToken,
+ TokenVerifier,
+)
from .webhook import WebhookReceiver
from .version import __version__
+
+__all__ = [
+ "LiveKitAPI",
+ "room_service",
+ "egress_service",
+ "ingress_service",
+ "sip_service",
+ "agent_dispatch_service",
+ "connector_service",
+ "InferenceGrants",
+ "ObservabilityGrants",
+ "VideoGrants",
+ "SIPGrants",
+ "AccessToken",
+ "TokenVerifier",
+ "WebhookReceiver",
+ "TwirpError",
+ "TwirpErrorCode",
+]
diff --git a/livekit-api/livekit/api/_service.py b/livekit-api/livekit/api/_service.py
index 31527d00..7777f6ee 100644
--- a/livekit-api/livekit/api/_service.py
+++ b/livekit-api/livekit/api/_service.py
@@ -1,6 +1,5 @@
from __future__ import annotations
-from typing import Dict
import aiohttp
from abc import ABC
from .twirp_client import TwirpClient
@@ -10,19 +9,19 @@
class Service(ABC):
- def __init__(
- self, session: aiohttp.ClientSession, host: str, api_key: str, api_secret: str
- ):
+ def __init__(self, session: aiohttp.ClientSession, host: str, api_key: str, api_secret: str):
self._client = TwirpClient(session, host, "livekit")
self.api_key = api_key
self.api_secret = api_secret
def _auth_header(
- self, grants: VideoGrants, sip: SIPGrants | None = None
- ) -> Dict[str, str]:
- tok = AccessToken(self.api_key, self.api_secret).with_grants(grants)
+ self, grants: VideoGrants | None, sip: SIPGrants | None = None
+ ) -> dict[str, str]:
+ tok = AccessToken(self.api_key, self.api_secret)
+ if grants:
+ tok.with_grants(grants)
if sip is not None:
- tok = tok.with_sip_grants(sip)
+ tok.with_sip_grants(sip)
token = tok.to_jwt()
diff --git a/livekit-api/livekit/api/access_token.py b/livekit-api/livekit/api/access_token.py
index e840b9a5..9d0e5145 100644
--- a/livekit-api/livekit/api/access_token.py
+++ b/livekit-api/livekit/api/access_token.py
@@ -13,57 +13,63 @@
# limitations under the License.
import calendar
-import dataclasses
import re
import datetime
import os
import jwt
-from typing import Optional, List
+import dataclasses
+from dataclasses import dataclass
+from typing import Optional, List, Literal
+from google.protobuf.json_format import MessageToDict, ParseDict
+
+from livekit.protocol.room import RoomConfiguration
DEFAULT_TTL = datetime.timedelta(hours=6)
DEFAULT_LEEWAY = datetime.timedelta(minutes=1)
-@dataclasses.dataclass
+@dataclass
class VideoGrants:
# actions on rooms
- room_create: bool = False
- room_list: bool = False
- room_record: bool = False
+ room_create: Optional[bool] = None
+ room_list: Optional[bool] = None
+ room_record: Optional[bool] = None
# actions on a particular room
- room_admin: bool = False
- room_join: bool = False
+ room_admin: Optional[bool] = None
+ room_join: Optional[bool] = None
room: str = ""
+ # allows forwarding participant to room
+ destination_room: Optional[str] = None
+
# permissions within a room
can_publish: bool = True
can_subscribe: bool = True
can_publish_data: bool = True
# TrackSource types that a participant may publish.
- # When set, it supercedes CanPublish. Only sources explicitly set here can be
+ # When set, it supersedes CanPublish. Only sources explicitly set here can be
# published
- can_publish_sources: List[str] = dataclasses.field(default_factory=list)
+ can_publish_sources: Optional[List[str]] = None
# by default, a participant is not allowed to update its own metadata
- can_update_own_metadata: bool = False
+ can_update_own_metadata: Optional[bool] = None
# actions on ingresses
- ingress_admin: bool = False # applies to all ingress
+ ingress_admin: Optional[bool] = None # applies to all ingress
# participant is not visible to other participants (useful when making bots)
- hidden: bool = False
+ hidden: Optional[bool] = None
- # indicates to the room that current participant is a recorder
- recorder: bool = False
+ # [deprecated] indicates to the room that current participant is a recorder
+ recorder: Optional[bool] = None
# indicates that the holder can register as an Agent framework worker
- # it is also set on all participants that are joining as Agent
- agent: bool = False
+ agent: Optional[bool] = None
-@dataclasses.dataclass
+@dataclass
class SIPGrants:
# manage sip resources
admin: bool = False
@@ -71,17 +77,49 @@ class SIPGrants:
call: bool = False
-@dataclasses.dataclass
+@dataclass
+class InferenceGrants:
+ # perform inference
+ perform: bool = False
+
+
+@dataclass
+class ObservabilityGrants:
+ # write grants to publish observability data
+ write: bool = False
+
+
+@dataclass
class Claims:
identity: str = ""
name: str = ""
- video: VideoGrants = dataclasses.field(default_factory=VideoGrants)
- sip: SIPGrants = dataclasses.field(default_factory=SIPGrants)
+ kind: str = ""
metadata: str = ""
- sha256: str = ""
+ video: Optional[VideoGrants] = None
+ sip: Optional[SIPGrants] = None
+ inference: Optional[InferenceGrants] = None
+ observability: Optional[ObservabilityGrants] = None
+ attributes: Optional[dict[str, str]] = None
+ sha256: Optional[str] = None
+ room_preset: Optional[str] = None
+ room_config: Optional[RoomConfiguration] = None
+
+ def asdict(self) -> dict:
+ # in order to produce minimal jwt size, exclude None or empty values
+ claims = dataclasses.asdict(
+ self,
+ dict_factory=lambda items: {
+ snake_to_lower_camel(k): v for k, v in items if v is not None and v != ""
+ },
+ )
+ if self.room_config:
+ claims["roomConfig"] = MessageToDict(self.room_config)
+ return claims
class AccessToken:
+ ParticipantKind = Literal["standard", "egress", "ingress", "sip", "agent"]
+
def __init__(
self,
api_key: Optional[str] = None,
@@ -113,10 +151,22 @@ def with_sip_grants(self, grants: SIPGrants) -> "AccessToken":
self.claims.sip = grants
return self
+ def with_observability_grants(self, grants: ObservabilityGrants) -> "AccessToken":
+ self.claims.observability = grants
+ return self
+
+ def with_inference_grants(self, grants: InferenceGrants) -> "AccessToken":
+ self.claims.inference = grants
+ return self
+
def with_identity(self, identity: str) -> "AccessToken":
self.identity = identity
return self
+ def with_kind(self, kind: ParticipantKind) -> "AccessToken":
+ self.claims.kind = kind
+ return self
+
def with_name(self, name: str) -> "AccessToken":
self.claims.name = name
return self
@@ -125,31 +175,40 @@ def with_metadata(self, metadata: str) -> "AccessToken":
self.claims.metadata = metadata
return self
+ def with_attributes(self, attributes: dict[str, str]) -> "AccessToken":
+ self.claims.attributes = attributes
+ return self
+
def with_sha256(self, sha256: str) -> "AccessToken":
self.claims.sha256 = sha256
return self
+ def with_room_preset(self, preset: str) -> "AccessToken":
+ self.claims.room_preset = preset
+ return self
+
+ def with_room_config(self, config: RoomConfiguration) -> "AccessToken":
+ self.claims.room_config = config
+ return self
+
def to_jwt(self) -> str:
video = self.claims.video
- if video.room_join and (not self.identity or not video.room):
+ if video and video.room_join and (not self.identity or not video.room):
raise ValueError("identity and room must be set when joining a room")
- claims = dataclasses.asdict(
- self.claims,
- dict_factory=lambda items: {snake_to_lower_camel(k): v for k, v in items},
- )
- claims.update(
+ # we want to exclude None values from the token
+ jwt_claims = self.claims.asdict()
+ jwt_claims.update(
{
"sub": self.identity,
"iss": self.api_key,
- "nbf": calendar.timegm(datetime.datetime.utcnow().utctimetuple()),
+ "nbf": calendar.timegm(datetime.datetime.now(datetime.timezone.utc).utctimetuple()),
"exp": calendar.timegm(
- (datetime.datetime.utcnow() + self.ttl).utctimetuple()
+ (datetime.datetime.now(datetime.timezone.utc) + self.ttl).utctimetuple()
),
}
)
-
- return jwt.encode(claims, self.api_secret, algorithm="HS256")
+ return jwt.encode(jwt_claims, self.api_secret, algorithm="HS256")
class TokenVerifier:
@@ -163,51 +222,65 @@ def __init__(
api_key = api_key or os.getenv("LIVEKIT_API_KEY")
api_secret = api_secret or os.getenv("LIVEKIT_API_SECRET")
- if not api_key or not api_secret:
- raise ValueError("api_key and api_secret must be set")
-
self.api_key = api_key
self.api_secret = api_secret
self._leeway = leeway
- def verify(self, token: str) -> Claims:
+ def verify(self, token: str, *, verify_signature: bool = True) -> Claims:
+ if verify_signature and (not self.api_key or not self.api_secret):
+ raise ValueError("api_key and api_secret must be set")
+
claims = jwt.decode(
token,
- self.api_secret,
- issuer=self.api_key,
+ key=self.api_secret or "",
+ issuer=self.api_key or "",
algorithms=["HS256"],
leeway=self._leeway.total_seconds(),
+ options={"verify_signature": verify_signature},
)
-
video_dict = claims.get("video", dict())
video_dict = {camel_to_snake(k): v for k, v in video_dict.items()}
- video_dict = {
- k: v for k, v in video_dict.items() if k in VideoGrants.__dataclass_fields__
- }
+ video_dict = {k: v for k, v in video_dict.items() if k in VideoGrants.__dataclass_fields__}
video = VideoGrants(**video_dict)
sip_dict = claims.get("sip", dict())
sip_dict = {camel_to_snake(k): v for k, v in sip_dict.items()}
- sip_dict = {
- k: v for k, v in sip_dict.items() if k in SIPGrants.__dataclass_fields__
- }
+ sip_dict = {k: v for k, v in sip_dict.items() if k in SIPGrants.__dataclass_fields__}
sip = SIPGrants(**sip_dict)
- return Claims(
+ inference_dict = claims.get("inference", dict())
+ inference_dict = {camel_to_snake(k): v for k, v in inference_dict.items()}
+ inference_dict = {
+ k: v for k, v in inference_dict.items() if k in InferenceGrants.__dataclass_fields__
+ }
+ inference = InferenceGrants(**inference_dict)
+
+ grant_claims = Claims(
identity=claims.get("sub", ""),
name=claims.get("name", ""),
video=video,
sip=sip,
+ inference=inference,
+ attributes=claims.get("attributes", {}),
metadata=claims.get("metadata", ""),
sha256=claims.get("sha256", ""),
)
+ if claims.get("roomPreset"):
+ grant_claims.room_preset = claims.get("roomPreset")
+ if claims.get("roomConfig"):
+ grant_claims.room_config = ParseDict(
+ claims.get("roomConfig"),
+ RoomConfiguration(),
+ ignore_unknown_fields=True,
+ )
+
+ return grant_claims
+
def camel_to_snake(t: str):
return re.sub(r"(? AgentDispatch:
+ """Create an explicit dispatch for an agent to join a room.
+
+ To use explicit dispatch, your agent must be registered with an `agentName`.
+
+ Args:
+ req (CreateAgentDispatchRequest): Request containing dispatch creation parameters
+
+ Returns:
+ AgentDispatch: The created agent dispatch object
+ """
+ return await self._client.request(
+ SVC,
+ "CreateDispatch",
+ req,
+ self._auth_header(VideoGrants(room_admin=True, room=req.room)),
+ AgentDispatch,
+ )
+
+ async def delete_dispatch(self, dispatch_id: str, room_name: str) -> AgentDispatch:
+ """Delete an explicit dispatch for an agent in a room.
+
+ Args:
+ dispatch_id (str): ID of the dispatch to delete
+ room_name (str): Name of the room containing the dispatch
+
+ Returns:
+ AgentDispatch: The deleted agent dispatch object
+ """
+ return await self._client.request(
+ SVC,
+ "DeleteDispatch",
+ DeleteAgentDispatchRequest(
+ dispatch_id=dispatch_id,
+ room=room_name,
+ ),
+ self._auth_header(VideoGrants(room_admin=True, room=room_name)),
+ AgentDispatch,
+ )
+
+ async def list_dispatch(self, room_name: str) -> list[AgentDispatch]:
+ """List all agent dispatches in a room.
+
+ Args:
+ room_name (str): Name of the room to list dispatches from
+
+ Returns:
+ list[AgentDispatch]: List of agent dispatch objects in the room
+ """
+ res = await self._client.request(
+ SVC,
+ "ListDispatch",
+ ListAgentDispatchRequest(room=room_name),
+ self._auth_header(VideoGrants(room_admin=True, room=room_name)),
+ ListAgentDispatchResponse,
+ )
+ return list(res.agent_dispatches)
+
+ async def get_dispatch(self, dispatch_id: str, room_name: str) -> Optional[AgentDispatch]:
+ """Get an Agent dispatch by ID
+
+ Args:
+ dispatch_id (str): ID of the dispatch to retrieve
+ room_name (str): Name of the room containing the dispatch
+
+ Returns:
+ Optional[AgentDispatch]: The requested agent dispatch object if found, None otherwise
+ """
+ res = await self._client.request(
+ SVC,
+ "ListDispatch",
+ ListAgentDispatchRequest(dispatch_id=dispatch_id, room=room_name),
+ self._auth_header(VideoGrants(room_admin=True, room=room_name)),
+ ListAgentDispatchResponse,
+ )
+ if len(res.agent_dispatches) > 0:
+ return res.agent_dispatches[0]
+ return None
diff --git a/livekit-api/livekit/api/connector_service.py b/livekit-api/livekit/api/connector_service.py
new file mode 100644
index 00000000..2d686e89
--- /dev/null
+++ b/livekit-api/livekit/api/connector_service.py
@@ -0,0 +1,139 @@
+from __future__ import annotations
+
+import aiohttp
+
+from livekit.protocol.connector_whatsapp import (
+ DialWhatsAppCallRequest,
+ DialWhatsAppCallResponse,
+ DisconnectWhatsAppCallRequest,
+ DisconnectWhatsAppCallResponse,
+ ConnectWhatsAppCallRequest,
+ ConnectWhatsAppCallResponse,
+ AcceptWhatsAppCallRequest,
+ AcceptWhatsAppCallResponse,
+)
+from livekit.protocol.connector_twilio import (
+ ConnectTwilioCallRequest,
+ ConnectTwilioCallResponse,
+)
+from ._service import Service
+from .access_token import VideoGrants
+
+SVC = "Connector"
+"""@private"""
+
+
+class ConnectorService(Service):
+ """Client for LiveKit Connector Service API
+
+ Recommended way to use this service is via `livekit.api.LiveKitAPI`:
+
+ ```python
+ from livekit import api
+ lkapi = api.LiveKitAPI()
+ connector_service = lkapi.connector
+ ```
+ """
+
+ def __init__(self, session: aiohttp.ClientSession, url: str, api_key: str, api_secret: str):
+ super().__init__(session, url, api_key, api_secret)
+
+ async def dial_whatsapp_call(
+ self, request: DialWhatsAppCallRequest
+ ) -> DialWhatsAppCallResponse:
+ """
+ Initiate an outbound WhatsApp call
+
+ Args:
+ request: DialWhatsAppCallRequest containing call parameters
+
+ Returns:
+ DialWhatsAppCallResponse with the WhatsApp call ID and room name
+ """
+ return await self._client.request(
+ SVC,
+ "DialWhatsAppCall",
+ request,
+ self._auth_header(VideoGrants(room_create=True)),
+ DialWhatsAppCallResponse,
+ )
+
+ async def disconnect_whatsapp_call(
+ self, request: DisconnectWhatsAppCallRequest
+ ) -> DisconnectWhatsAppCallResponse:
+ """
+ Disconnect an active WhatsApp call
+
+ Args:
+ request: DisconnectWhatsAppCallRequest containing the call ID to disconnect
+
+ Returns:
+ DisconnectWhatsAppCallResponse (empty response)
+ """
+ return await self._client.request(
+ SVC,
+ "DisconnectWhatsAppCall",
+ request,
+ self._auth_header(VideoGrants(room_create=True)),
+ DisconnectWhatsAppCallResponse,
+ )
+
+ async def connect_whatsapp_call(
+ self, request: ConnectWhatsAppCallRequest
+ ) -> ConnectWhatsAppCallResponse:
+ """
+ Connect a WhatsApp call with SDP information
+
+ Args:
+ request: ConnectWhatsAppCallRequest containing call ID and SDP
+
+ Returns:
+ ConnectWhatsAppCallResponse (empty response)
+ """
+ return await self._client.request(
+ SVC,
+ "ConnectWhatsAppCall",
+ request,
+ self._auth_header(VideoGrants(room_create=True)),
+ ConnectWhatsAppCallResponse,
+ )
+
+ async def accept_whatsapp_call(
+ self, request: AcceptWhatsAppCallRequest
+ ) -> AcceptWhatsAppCallResponse:
+ """
+ Accept an inbound WhatsApp call
+
+ Args:
+ request: AcceptWhatsAppCallRequest containing call parameters and SDP
+
+ Returns:
+ AcceptWhatsAppCallResponse with the room name
+ """
+ return await self._client.request(
+ SVC,
+ "AcceptWhatsAppCall",
+ request,
+ self._auth_header(VideoGrants(room_create=True)),
+ AcceptWhatsAppCallResponse,
+ )
+
+ async def connect_twilio_call(
+ self, request: ConnectTwilioCallRequest
+ ) -> ConnectTwilioCallResponse:
+ """
+ Connect a Twilio call to a LiveKit room
+
+ Args:
+ request: ConnectTwilioCallRequest containing call parameters
+
+ Returns:
+ ConnectTwilioCallResponse with the websocket URL for Twilio media stream
+ """
+ return await self._client.request(
+ SVC,
+ "ConnectTwilioCall",
+ request,
+ self._auth_header(VideoGrants(room_create=True)),
+ ConnectTwilioCallResponse,
+ )
diff --git a/livekit-api/livekit/api/egress_service.py b/livekit-api/livekit/api/egress_service.py
index a875459b..491bff3b 100644
--- a/livekit-api/livekit/api/egress_service.py
+++ b/livekit-api/livekit/api/egress_service.py
@@ -1,112 +1,134 @@
import aiohttp
-from livekit.protocol import egress as proto_egress
+from livekit.protocol.egress import (
+ RoomCompositeEgressRequest,
+ WebEgressRequest,
+ ParticipantEgressRequest,
+ TrackCompositeEgressRequest,
+ TrackEgressRequest,
+ UpdateLayoutRequest,
+ UpdateStreamRequest,
+ ListEgressRequest,
+ StopEgressRequest,
+ EgressInfo,
+ ListEgressResponse,
+)
from ._service import Service
from .access_token import VideoGrants
SVC = "Egress"
+"""@private"""
class EgressService(Service):
- def __init__(
- self, session: aiohttp.ClientSession, url: str, api_key: str, api_secret: str
- ):
+ """Client for LiveKit Egress Service API
+
+ Recommended way to use this service is via `livekit.api.LiveKitAPI`:
+
+ ```python
+ from livekit import api
+ lkapi = api.LiveKitAPI()
+ egress = lkapi.egress
+ ```
+
+ Also see https://docs.livekit.io/home/egress/overview/
+ """
+
+ def __init__(self, session: aiohttp.ClientSession, url: str, api_key: str, api_secret: str):
super().__init__(session, url, api_key, api_secret)
- async def start_room_composite_egress(
- self, start: proto_egress.RoomCompositeEgressRequest
- ) -> proto_egress.EgressInfo:
+ async def start_room_composite_egress(self, start: RoomCompositeEgressRequest) -> EgressInfo:
+ """Starts a composite recording of a room."""
return await self._client.request(
SVC,
"StartRoomCompositeEgress",
start,
self._auth_header(VideoGrants(room_record=True)),
- proto_egress.EgressInfo,
+ EgressInfo,
)
- async def start_web_egress(
- self, start: proto_egress.WebEgressRequest
- ) -> proto_egress.EgressInfo:
+ async def start_web_egress(self, start: WebEgressRequest) -> EgressInfo:
+ """Starts a recording of a web page."""
return await self._client.request(
SVC,
"StartWebEgress",
start,
self._auth_header(VideoGrants(room_record=True)),
- proto_egress.EgressInfo,
+ EgressInfo,
)
- async def start_participant_egress(
- self, start: proto_egress.ParticipantEgressRequest
- ) -> proto_egress.EgressInfo:
+ async def start_participant_egress(self, start: ParticipantEgressRequest) -> EgressInfo:
+ """Starts a recording of a participant."""
return await self._client.request(
SVC,
"StartParticipantEgress",
start,
self._auth_header(VideoGrants(room_record=True)),
- proto_egress.EgressInfo,
+ EgressInfo,
)
- async def start_track_composite_egress(
- self, start: proto_egress.TrackCompositeEgressRequest
- ) -> proto_egress.EgressInfo:
+ async def start_track_composite_egress(self, start: TrackCompositeEgressRequest) -> EgressInfo:
+ """Starts a composite recording with audio and video tracks."""
return await self._client.request(
SVC,
"StartTrackCompositeEgress",
start,
self._auth_header(VideoGrants(room_record=True)),
- proto_egress.EgressInfo,
+ EgressInfo,
)
- async def start_track_egress(
- self, start: proto_egress.TrackEgressRequest
- ) -> proto_egress.EgressInfo:
+ async def start_track_egress(self, start: TrackEgressRequest) -> EgressInfo:
+ """Starts a recording of a single track."""
return await self._client.request(
SVC,
"StartTrackEgress",
start,
self._auth_header(VideoGrants(room_record=True)),
- proto_egress.EgressInfo,
+ EgressInfo,
)
- async def update_layout(
- self, update: proto_egress.UpdateLayoutRequest
- ) -> proto_egress.EgressInfo:
+ async def update_layout(self, update: UpdateLayoutRequest) -> EgressInfo:
+ """Updates the layout of a composite recording."""
return await self._client.request(
SVC,
"UpdateLayout",
update,
self._auth_header(VideoGrants(room_record=True)),
- proto_egress.EgressInfo,
+ EgressInfo,
)
- async def update_stream(
- self, update: proto_egress.UpdateStreamRequest
- ) -> proto_egress.EgressInfo:
+ async def update_stream(self, update: UpdateStreamRequest) -> EgressInfo:
+ """Updates the stream of a RoomComposite, Web, or Participant recording."""
return await self._client.request(
SVC,
"UpdateStream",
update,
self._auth_header(VideoGrants(room_record=True)),
- proto_egress.EgressInfo,
+ EgressInfo,
)
- async def list_egress(
- self, list: proto_egress.ListEgressRequest
- ) -> proto_egress.ListEgressResponse:
+ async def list_egress(self, list: ListEgressRequest) -> ListEgressResponse:
+ """Lists all active egress and recently completed recordings.
+
+ Args:
+ list (ListEgressRequest): arg contains optional filters:
+ - room_name: str - List all egresses for a specific room
+ - egress_id: str - Only list egress with matching ID
+ - active: bool - Only list active egresses
+ """
return await self._client.request(
SVC,
"ListEgress",
list,
self._auth_header(VideoGrants(room_record=True)),
- proto_egress.ListEgressResponse,
+ ListEgressResponse,
)
- async def stop_egress(
- self, stop: proto_egress.StopEgressRequest
- ) -> proto_egress.EgressInfo:
+ async def stop_egress(self, stop: StopEgressRequest) -> EgressInfo:
+ """Stops an active egress recording."""
return await self._client.request(
SVC,
"StopEgress",
stop,
self._auth_header(VideoGrants(room_record=True)),
- proto_egress.EgressInfo,
+ EgressInfo,
)
diff --git a/livekit-api/livekit/api/ingress_service.py b/livekit-api/livekit/api/ingress_service.py
index abf691ef..296dabbe 100644
--- a/livekit-api/livekit/api/ingress_service.py
+++ b/livekit-api/livekit/api/ingress_service.py
@@ -1,57 +1,68 @@
import aiohttp
-from livekit.protocol import ingress as proto_ingress
+from livekit.protocol.ingress import (
+ CreateIngressRequest,
+ IngressInfo,
+ UpdateIngressRequest,
+ ListIngressRequest,
+ DeleteIngressRequest,
+ ListIngressResponse,
+)
from ._service import Service
from .access_token import VideoGrants
SVC = "Ingress"
+"""@private"""
class IngressService(Service):
- def __init__(
- self, session: aiohttp.ClientSession, url: str, api_key: str, api_secret: str
- ):
+ """Client for LiveKit Ingress Service API
+
+ Recommended way to use this service is via `livekit.api.LiveKitAPI`:
+
+ ```python
+ from livekit import api
+ lkapi = api.LiveKitAPI()
+ ingress = lkapi.ingress
+ ```
+
+ Also see https://docs.livekit.io/home/ingress/overview/
+ """
+
+ def __init__(self, session: aiohttp.ClientSession, url: str, api_key: str, api_secret: str):
super().__init__(session, url, api_key, api_secret)
- async def create_ingress(
- self, create: proto_ingress.CreateIngressRequest
- ) -> proto_ingress.IngressInfo:
+ async def create_ingress(self, create: CreateIngressRequest) -> IngressInfo:
return await self._client.request(
SVC,
"CreateIngress",
create,
self._auth_header(VideoGrants(ingress_admin=True)),
- proto_ingress.IngressInfo,
+ IngressInfo,
)
- async def update_ingress(
- self, update: proto_ingress.UpdateIngressRequest
- ) -> proto_ingress.IngressInfo:
+ async def update_ingress(self, update: UpdateIngressRequest) -> IngressInfo:
return await self._client.request(
SVC,
"UpdateIngress",
update,
self._auth_header(VideoGrants(ingress_admin=True)),
- proto_ingress.IngressInfo,
+ IngressInfo,
)
- async def list_ingress(
- self, list: proto_ingress.ListIngressRequest
- ) -> proto_ingress.ListIngressResponse:
+ async def list_ingress(self, list: ListIngressRequest) -> ListIngressResponse:
return await self._client.request(
SVC,
"ListIngress",
list,
self._auth_header(VideoGrants(ingress_admin=True)),
- proto_ingress.ListIngressResponse,
+ ListIngressResponse,
)
- async def delete_ingress(
- self, delete: proto_ingress.DeleteIngressRequest
- ) -> proto_ingress.IngressInfo:
+ async def delete_ingress(self, delete: DeleteIngressRequest) -> IngressInfo:
return await self._client.request(
SVC,
"DeleteIngress",
delete,
self._auth_header(VideoGrants(ingress_admin=True)),
- proto_ingress.IngressInfo,
+ IngressInfo,
)
diff --git a/livekit-api/livekit/api/livekit_api.py b/livekit-api/livekit/api/livekit_api.py
index efe00ff8..e57bb4e3 100644
--- a/livekit-api/livekit/api/livekit_api.py
+++ b/livekit-api/livekit/api/livekit_api.py
@@ -4,18 +4,43 @@
from .egress_service import EgressService
from .ingress_service import IngressService
from .sip_service import SipService
+from .agent_dispatch_service import AgentDispatchService
+from .connector_service import ConnectorService
from typing import Optional
class LiveKitAPI:
+ """LiveKit Server API Client
+
+ This class is the main entrypoint, which exposes all services.
+
+ Usage:
+
+ ```python
+ from livekit import api
+ lkapi = api.LiveKitAPI()
+ rooms = await lkapi.room.list_rooms(api.proto_room.ListRoomsRequest(names=['test-room']))
+ ```
+ """
+
def __init__(
self,
url: Optional[str] = None,
api_key: Optional[str] = None,
api_secret: Optional[str] = None,
*,
- timeout: aiohttp.ClientTimeout = aiohttp.ClientTimeout(total=60), # 60 seconds
+ timeout: Optional[aiohttp.ClientTimeout] = None,
+ session: Optional[aiohttp.ClientSession] = None,
):
+ """Create a new LiveKitAPI instance.
+
+ Args:
+ url: LiveKit server URL (read from `LIVEKIT_URL` environment variable if not provided)
+ api_key: API key (read from `LIVEKIT_API_KEY` environment variable if not provided)
+ api_secret: API secret (read from `LIVEKIT_API_SECRET` environment variable if not provided)
+ timeout: Request timeout (default: 60 seconds)
+ session: aiohttp.ClientSession instance to use for requests, if not provided, a new one will be created
+ """
url = url or os.getenv("LIVEKIT_URL")
api_key = api_key or os.getenv("LIVEKIT_API_KEY")
api_secret = api_secret or os.getenv("LIVEKIT_API_SECRET")
@@ -26,27 +51,67 @@ def __init__(
if not api_key or not api_secret:
raise ValueError("api_key and api_secret must be set")
- self._session = aiohttp.ClientSession(timeout=timeout)
+ self._custom_session = True
+ self._session = session
+ if not self._session:
+ self._custom_session = False
+ if not timeout:
+ timeout = aiohttp.ClientTimeout(total=60)
+ self._session = aiohttp.ClientSession(timeout=timeout)
+
self._room = RoomService(self._session, url, api_key, api_secret)
self._ingress = IngressService(self._session, url, api_key, api_secret)
self._egress = EgressService(self._session, url, api_key, api_secret)
self._sip = SipService(self._session, url, api_key, api_secret)
+ self._agent_dispatch = AgentDispatchService(self._session, url, api_key, api_secret)
+ self._connector = ConnectorService(self._session, url, api_key, api_secret)
+
+ @property
+ def agent_dispatch(self) -> AgentDispatchService:
+ """Instance of the AgentDispatchService"""
+ return self._agent_dispatch
@property
- def room(self):
+ def room(self) -> RoomService:
+ """Instance of the RoomService"""
return self._room
@property
- def ingress(self):
+ def ingress(self) -> IngressService:
+ """Instance of the IngressService"""
return self._ingress
@property
- def egress(self):
+ def egress(self) -> EgressService:
+ """Instance of the EgressService"""
return self._egress
@property
- def sip(self):
+ def sip(self) -> SipService:
+ """Instance of the SipService"""
return self._sip
+ @property
+ def connector(self) -> ConnectorService:
+ """Instance of the ConnectorService"""
+ return self._connector
+
async def aclose(self):
- await self._session.close()
+ """Close the API client
+
+ Call this before your application exits or when the API client is no longer needed."""
+ # we do not close custom sessions, that's up to the caller
+ if not self._custom_session:
+ await self._session.close()
+
+ async def __aenter__(self):
+ """@private
+
+ Support for `async with`"""
+ return self
+
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
+ """@private
+
+ Support for `async with`"""
+ await self.aclose()
diff --git a/livekit-api/livekit/api/room_service.py b/livekit-api/livekit/api/room_service.py
index 9c1b197a..5c0e3b76 100644
--- a/livekit-api/livekit/api/room_service.py
+++ b/livekit-api/livekit/api/room_service.py
@@ -1,136 +1,348 @@
import aiohttp
-from livekit.protocol import room as proto_room
-from livekit.protocol import models as proto_models
+from uuid import uuid4
+from livekit.protocol.room import (
+ CreateRoomRequest,
+ ListRoomsRequest,
+ DeleteRoomRequest,
+ ListRoomsResponse,
+ DeleteRoomResponse,
+ ListParticipantsRequest,
+ ListParticipantsResponse,
+ RoomParticipantIdentity,
+ MuteRoomTrackRequest,
+ MuteRoomTrackResponse,
+ UpdateParticipantRequest,
+ UpdateSubscriptionsRequest,
+ SendDataRequest,
+ SendDataResponse,
+ UpdateRoomMetadataRequest,
+ RemoveParticipantResponse,
+ UpdateSubscriptionsResponse,
+ ForwardParticipantRequest,
+ ForwardParticipantResponse,
+ MoveParticipantRequest,
+ MoveParticipantResponse,
+)
+from livekit.protocol.models import Room, ParticipantInfo
from ._service import Service
from .access_token import VideoGrants
SVC = "RoomService"
+"""@private"""
class RoomService(Service):
- def __init__(
- self, session: aiohttp.ClientSession, url: str, api_key: str, api_secret: str
- ):
+ """Client for LiveKit RoomService API
+
+ Recommended way to use this service is via `livekit.api.LiveKitAPI`:
+
+ ```python
+ from livekit import api
+ lkapi = api.LiveKitAPI()
+ room_service = lkapi.room
+ ```
+
+ Also see https://docs.livekit.io/home/server/managing-rooms/ and https://docs.livekit.io/home/server/managing-participants/
+ """
+
+ def __init__(self, session: aiohttp.ClientSession, url: str, api_key: str, api_secret: str):
super().__init__(session, url, api_key, api_secret)
async def create_room(
- self, create: proto_room.CreateRoomRequest
- ) -> proto_models.Room:
+ self,
+ create: CreateRoomRequest,
+ ) -> Room:
+ """Creates a new room with specified configuration.
+
+ Args:
+ create (CreateRoomRequest): arg containing:
+ - name: str - Unique room name
+ - empty_timeout: int - Seconds to keep room open if empty
+ - max_participants: int - Max allowed participants
+ - metadata: str - Custom room metadata
+ - egress: RoomEgress - Egress configuration
+ - min_playout_delay: int - Minimum playout delay in ms
+ - max_playout_delay: int - Maximum playout delay in ms
+ - sync_streams: bool - Enable A/V sync for playout delays >200ms
+
+ Returns:
+ Room: The created room object
+ """
return await self._client.request(
SVC,
"CreateRoom",
create,
self._auth_header(VideoGrants(room_create=True)),
- proto_models.Room,
+ Room,
)
- async def list_rooms(
- self, list: proto_room.ListRoomsRequest
- ) -> proto_room.ListRoomsResponse:
+ async def list_rooms(self, list: ListRoomsRequest) -> ListRoomsResponse:
+ """Lists active rooms.
+
+ Args:
+ list (ListRoomsRequest): arg containing:
+ - names: list[str] - Optional list of room names to filter by
+
+ Returns:
+ ListRoomsResponse:
+ - rooms: list[Room] - List of active Room objects
+ """
return await self._client.request(
SVC,
"ListRooms",
list,
self._auth_header(VideoGrants(room_list=True)),
- proto_room.ListRoomsResponse,
+ ListRoomsResponse,
)
- async def delete_room(
- self, delete: proto_room.DeleteRoomRequest
- ) -> proto_room.DeleteRoomResponse:
+ async def delete_room(self, delete: DeleteRoomRequest) -> DeleteRoomResponse:
+ """Deletes a room and disconnects all participants.
+
+ Args:
+ delete (DeleteRoomRequest): arg containing:
+ - room: str - Name of room to delete
+
+ Returns:
+ DeleteRoomResponse: Empty response object
+ """
return await self._client.request(
SVC,
"DeleteRoom",
delete,
self._auth_header(VideoGrants(room_create=True)),
- proto_room.DeleteRoomResponse,
+ DeleteRoomResponse,
)
- async def update_room_metadata(
- self, update: proto_room.UpdateRoomMetadataRequest
- ) -> proto_models.Room:
+ async def update_room_metadata(self, update: UpdateRoomMetadataRequest) -> Room:
+ """Updates a room's [metadata](https://docs.livekit.io/home/client/data/room-metadata/).
+
+ Args:
+ update (UpdateRoomMetadataRequest): arg containing:
+ - room: str - Name of room to update
+ - metadata: str - New metadata to set
+
+ Returns:
+ Room: Updated Room object
+ """
return await self._client.request(
SVC,
"UpdateRoomMetadata",
update,
self._auth_header(VideoGrants(room_admin=True, room=update.room)),
- proto_models.Room,
+ Room,
)
- async def list_participants(
- self, list: proto_room.ListParticipantsRequest
- ) -> proto_room.ListParticipantsResponse:
+ async def list_participants(self, list: ListParticipantsRequest) -> ListParticipantsResponse:
+ """Lists all participants in a room.
+
+ Args:
+ list (ListParticipantsRequest): arg containing:
+ - room: str - Name of room to list participants from
+
+ Returns:
+ ListParticipantsResponse:
+ - participants: list[ParticipantInfo] - List of participant details
+ """
return await self._client.request(
SVC,
"ListParticipants",
list,
self._auth_header(VideoGrants(room_admin=True, room=list.room)),
- proto_room.ListParticipantsResponse,
+ ListParticipantsResponse,
)
- async def get_participant(
- self, get: proto_room.RoomParticipantIdentity
- ) -> proto_models.ParticipantInfo:
+ async def get_participant(self, get: RoomParticipantIdentity) -> ParticipantInfo:
+ """Gets details about a specific participant.
+
+ Args:
+ get (RoomParticipantIdentity): arg containing:
+ - room: str - Room name
+ - identity: str - Participant identity to look up
+
+ Returns:
+ ParticipantInfo:
+ - sid: str - Participant session ID
+ - identity: str - Participant identity
+ - state: int - Connection state
+ - tracks: list[TrackInfo] - Published tracks
+ - metadata: str - Participant metadata
+ - joined_at: int - Join timestamp
+ - name: str - Display name
+ - version: int - Protocol version
+ - permission: ParticipantPermission - Granted permissions
+ - region: str - Connected region
+ """
return await self._client.request(
SVC,
"GetParticipant",
get,
self._auth_header(VideoGrants(room_admin=True, room=get.room)),
- proto_models.ParticipantInfo,
+ ParticipantInfo,
)
async def remove_participant(
- self, remove: proto_room.RoomParticipantIdentity
- ) -> proto_room.RemoveParticipantResponse:
+ self, remove: RoomParticipantIdentity
+ ) -> RemoveParticipantResponse:
+ """Removes a participant from a room.
+
+ Args:
+ remove (RoomParticipantIdentity): arg containing:
+ - room: str - Room name
+ - identity: str - Identity of participant to remove
+
+ Returns:
+ RemoveParticipantResponse: Empty response object
+ """
return await self._client.request(
SVC,
"RemoveParticipant",
remove,
self._auth_header(VideoGrants(room_admin=True, room=remove.room)),
- proto_room.RemoveParticipantResponse,
+ RemoveParticipantResponse,
+ )
+
+ async def forward_participant(self, forward: ForwardParticipantRequest) -> None:
+ """Forwards a participant and their published tracks from one room to another.
+
+ This feature is only available for LiveKit Cloud/Private Cloud.
+
+ Args:
+ forward (ForwardParticipantRequest): arg containing:
+ - room: str - Room name
+ - identity: str - identity of Participant to forward
+ - destination_room: str - Destination room name
+ """
+ # currently nothing is returned
+ await self._client.request(
+ SVC,
+ "ForwardParticipant",
+ forward,
+ self._auth_header(
+ VideoGrants(
+ room_admin=True, room=forward.room, destination_room=forward.destination_room
+ )
+ ),
+ ForwardParticipantResponse,
+ )
+
+ async def move_participant(self, move: MoveParticipantRequest) -> None:
+ """Moves a participant from one room to another.
+
+ This feature is only available for LiveKit Cloud/Private Cloud.
+
+ Args:
+ move (MoveParticipantRequest): arg containing:
+ - room: str - Room name
+ - identity: str - Participant identity
+ - destination_room: str - Destination room name
+ """
+ # currently nothing is returned
+ await self._client.request(
+ SVC,
+ "MoveParticipant",
+ move,
+ self._auth_header(
+ VideoGrants(
+ room_admin=True,
+ room=move.room,
+ destination_room=move.destination_room,
+ )
+ ),
+ MoveParticipantResponse,
)
async def mute_published_track(
self,
- update: proto_room.MuteRoomTrackRequest,
- ) -> proto_room.MuteRoomTrackResponse:
+ update: MuteRoomTrackRequest,
+ ) -> MuteRoomTrackResponse:
+ """Mutes or unmutes a participant's published track.
+
+ Args:
+ update (MuteRoomTrackRequest): arg containing:
+ - room: str - Room name
+ - identity: str - Participant identity
+ - track_sid: str - Track session ID to mute
+ - muted: bool - True to mute, False to unmute
+
+ Returns:
+ MuteRoomTrackResponse containing:
+ - track: TrackInfo - Updated track information
+ """
return await self._client.request(
SVC,
"MutePublishedTrack",
update,
self._auth_header(VideoGrants(room_admin=True, room=update.room)),
- proto_room.MuteRoomTrackResponse,
+ MuteRoomTrackResponse,
)
- async def update_participant(
- self, update: proto_room.UpdateParticipantRequest
- ) -> proto_models.ParticipantInfo:
+ async def update_participant(self, update: UpdateParticipantRequest) -> ParticipantInfo:
+ """Updates a participant's metadata or permissions.
+
+ Args:
+ update (UpdateParticipantRequest): arg containing:
+ - room: str - Room name
+ - identity: str - Participant identity
+ - metadata: str - New metadata
+ - permission: ParticipantPermission - New permissions
+ - name: str - New display name
+ - attributes: dict[str, str] - Key-value attributes
+
+ Returns:
+ ParticipantInfo: Updated participant information
+ """
return await self._client.request(
SVC,
"UpdateParticipant",
update,
self._auth_header(VideoGrants(room_admin=True, room=update.room)),
- proto_models.ParticipantInfo,
+ ParticipantInfo,
)
async def update_subscriptions(
- self, update: proto_room.UpdateSubscriptionsRequest
- ) -> proto_room.UpdateSubscriptionsResponse:
+ self, update: UpdateSubscriptionsRequest
+ ) -> UpdateSubscriptionsResponse:
+ """Updates a participant's track subscriptions.
+
+ Args:
+ update (UpdateSubscriptionsRequest): arg containing:
+ - room: str - Room name
+ - identity: str - Participant identity
+ - track_sids: list[str] - Track session IDs
+ - subscribe: bool - True to subscribe, False to unsubscribe
+ - participant_tracks: list[ParticipantTracks] - Participant track mappings
+
+ Returns:
+ UpdateSubscriptionsResponse: Empty response object
+ """
return await self._client.request(
SVC,
"UpdateSubscriptions",
update,
self._auth_header(VideoGrants(room_admin=True, room=update.room)),
- proto_room.UpdateSubscriptionsResponse,
+ UpdateSubscriptionsResponse,
)
- async def send_data(
- self, send: proto_room.SendDataRequest
- ) -> proto_room.SendDataResponse:
+ async def send_data(self, send: SendDataRequest) -> SendDataResponse:
+ """Sends data to participants in a room.
+
+ Args:
+ send (SendDataRequest): arg containing:
+ - room: str - Room name
+ - data: bytes - Data payload to send
+ - kind: DataPacket.Kind - RELIABLE or LOSSY delivery
+ - destination_identities: list[str] - Target participant identities
+ - topic: str - Optional topic for the message
+
+ Returns:
+ SendDataResponse: Empty response object
+ """
+
+ send.nonce = uuid4().bytes
return await self._client.request(
SVC,
"SendData",
send,
self._auth_header(VideoGrants(room_admin=True, room=send.room)),
- proto_room.SendDataResponse,
+ SendDataResponse,
)
diff --git a/livekit-api/livekit/api/sip_service.py b/livekit-api/livekit/api/sip_service.py
index 80810528..0364c797 100644
--- a/livekit-api/livekit/api/sip_service.py
+++ b/livekit-api/livekit/api/sip_service.py
@@ -1,134 +1,830 @@
+from __future__ import annotations
+
import aiohttp
-from livekit.protocol import sip as proto_sip
+import warnings
+from typing import Optional
+
+from livekit.protocol.models import ListUpdate
+from livekit.protocol.sip import (
+ SIPOutboundConfig,
+ SIPTrunkInfo,
+ CreateSIPInboundTrunkRequest,
+ UpdateSIPInboundTrunkRequest,
+ SIPInboundTrunkInfo,
+ SIPInboundTrunkUpdate,
+ CreateSIPOutboundTrunkRequest,
+ UpdateSIPOutboundTrunkRequest,
+ SIPOutboundTrunkInfo,
+ SIPOutboundTrunkUpdate,
+ ListSIPInboundTrunkRequest,
+ ListSIPInboundTrunkResponse,
+ ListSIPOutboundTrunkRequest,
+ ListSIPOutboundTrunkResponse,
+ DeleteSIPTrunkRequest,
+ SIPDispatchRule,
+ SIPDispatchRuleInfo,
+ SIPDispatchRuleUpdate,
+ CreateSIPDispatchRuleRequest,
+ UpdateSIPDispatchRuleRequest,
+ ListSIPDispatchRuleRequest,
+ ListSIPDispatchRuleResponse,
+ DeleteSIPDispatchRuleRequest,
+ CreateSIPParticipantRequest,
+ TransferSIPParticipantRequest,
+ SIPParticipantInfo,
+ SIPTransport,
+)
from ._service import Service
from .access_token import VideoGrants, SIPGrants
SVC = "SIP"
+"""@private"""
class SipService(Service):
- def __init__(
- self, session: aiohttp.ClientSession, url: str, api_key: str, api_secret: str
- ):
+ """Client for LiveKit SIP Service API
+
+ Recommended way to use this service is via `livekit.api.LiveKitAPI`:
+
+ ```python
+ from livekit import api
+ lkapi = api.LiveKitAPI()
+ sip_service = lkapi.sip
+ ```
+ """
+
+ def __init__(self, session: aiohttp.ClientSession, url: str, api_key: str, api_secret: str):
super().__init__(session, url, api_key, api_secret)
- async def create_sip_trunk(
- self, create: proto_sip.CreateSIPTrunkRequest
- ) -> proto_sip.SIPTrunkInfo:
+ async def create_inbound_trunk(
+ self, create: CreateSIPInboundTrunkRequest
+ ) -> SIPInboundTrunkInfo:
+ """Create a new SIP inbound trunk.
+
+ Args:
+ create: Request containing trunk details
+
+ Returns:
+ Created SIP inbound trunk
+ """
return await self._client.request(
SVC,
- "CreateSIPTrunk",
+ "CreateSIPInboundTrunk",
create,
- self._auth_header(VideoGrants(), sip=SIPGrants(admin=True)),
- proto_sip.SIPTrunkInfo,
+ self._admin_headers(),
+ SIPInboundTrunkInfo,
)
async def create_sip_inbound_trunk(
- self, create: proto_sip.CreateSIPInboundTrunkRequest
- ) -> proto_sip.SIPInboundTrunkInfo:
+ self, create: CreateSIPInboundTrunkRequest
+ ) -> SIPInboundTrunkInfo:
+ """Create a new SIP inbound trunk.
+
+ .. deprecated::
+ Use :meth:`create_inbound_trunk` instead.
+
+ Args:
+ create: Request containing trunk details
+
+ Returns:
+ Created SIP inbound trunk
+ """
+ warnings.warn(
+ "create_sip_inbound_trunk is deprecated, use create_inbound_trunk instead",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ return await self.create_inbound_trunk(create)
+
+ async def update_inbound_trunk(
+ self,
+ trunk_id: str,
+ trunk: SIPInboundTrunkInfo,
+ ) -> SIPInboundTrunkInfo:
+ """Updates an existing SIP inbound trunk by replacing it entirely.
+
+ Args:
+ trunk_id: ID of the SIP inbound trunk to update
+ trunk: SIP inbound trunk to update with
+
+ Returns:
+ Updated SIP inbound trunk
+ """
return await self._client.request(
SVC,
- "CreateSIPInboundTrunk",
- create,
- self._auth_header(VideoGrants(), sip=SIPGrants(admin=True)),
- proto_sip.SIPInboundTrunkInfo,
+ "UpdateSIPInboundTrunk",
+ UpdateSIPInboundTrunkRequest(
+ sip_trunk_id=trunk_id,
+ replace=trunk,
+ ),
+ self._admin_headers(),
+ SIPInboundTrunkInfo,
)
- async def create_sip_outbound_trunk(
- self, create: proto_sip.CreateSIPOutboundTrunkRequest
- ) -> proto_sip.SIPOutboundTrunkInfo:
+ async def update_sip_inbound_trunk(
+ self,
+ trunk_id: str,
+ trunk: SIPInboundTrunkInfo,
+ ) -> SIPInboundTrunkInfo:
+ """Updates an existing SIP inbound trunk by replacing it entirely.
+
+ .. deprecated::
+ Use :meth:`update_inbound_trunk` instead.
+
+ Args:
+ trunk_id: ID of the SIP inbound trunk to update
+ trunk: SIP inbound trunk to update with
+
+ Returns:
+ Updated SIP inbound trunk
+ """
+ warnings.warn(
+ "update_sip_inbound_trunk is deprecated, use update_inbound_trunk instead",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ return await self.update_inbound_trunk(trunk_id, trunk)
+
+ async def update_inbound_trunk_fields(
+ self,
+ trunk_id: str,
+ *,
+ numbers: Optional[ListUpdate | list[str]] = None,
+ allowed_addresses: Optional[ListUpdate | list[str]] = None,
+ allowed_numbers: Optional[ListUpdate | list[str]] = None,
+ auth_username: Optional[str] = None,
+ auth_password: Optional[str] = None,
+ name: Optional[str] = None,
+ metadata: Optional[str] = None,
+ ) -> SIPInboundTrunkInfo:
+ """Updates specific fields of an existing SIP inbound trunk.
+
+ Only provided fields will be updated.
+ """
+ update = SIPInboundTrunkUpdate(
+ auth_username=auth_username,
+ auth_password=auth_password,
+ name=name,
+ metadata=metadata,
+ )
+ if numbers is not None:
+ if isinstance(numbers, ListUpdate):
+ update.numbers.set.extend(numbers.set)
+ update.numbers.add.extend(numbers.add)
+ update.numbers.remove.extend(numbers.remove)
+ else:
+ update.numbers.set.extend(numbers)
+ if allowed_addresses is not None:
+ if isinstance(allowed_addresses, ListUpdate):
+ update.allowed_addresses.set.extend(allowed_addresses.set)
+ update.allowed_addresses.add.extend(allowed_addresses.add)
+ update.allowed_addresses.remove.extend(allowed_addresses.remove)
+ else:
+ update.allowed_addresses.set.extend(allowed_addresses)
+ if allowed_numbers is not None:
+ if isinstance(allowed_numbers, ListUpdate):
+ update.allowed_numbers.set.extend(allowed_numbers.set)
+ update.allowed_numbers.add.extend(allowed_numbers.add)
+ update.allowed_numbers.remove.extend(allowed_numbers.remove)
+ else:
+ update.allowed_numbers.set.extend(allowed_numbers)
+
+ return await self._client.request(
+ SVC,
+ "UpdateSIPInboundTrunk",
+ UpdateSIPInboundTrunkRequest(
+ sip_trunk_id=trunk_id,
+ update=update,
+ ),
+ self._admin_headers(),
+ SIPInboundTrunkInfo,
+ )
+
+ async def update_sip_inbound_trunk_fields(
+ self,
+ trunk_id: str,
+ *,
+ numbers: Optional[list[str]] = None,
+ allowed_addresses: Optional[list[str]] = None,
+ allowed_numbers: Optional[list[str]] = None,
+ auth_username: Optional[str] = None,
+ auth_password: Optional[str] = None,
+ name: Optional[str] = None,
+ metadata: Optional[str] = None,
+ ) -> SIPInboundTrunkInfo:
+ """Updates specific fields of an existing SIP inbound trunk.
+
+ .. deprecated::
+ Use :meth:`update_inbound_trunk_fields` instead.
+
+ Only provided fields will be updated.
+ """
+ warnings.warn(
+ "update_sip_inbound_trunk_fields is deprecated, use update_inbound_trunk_fields instead",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ return await self.update_inbound_trunk_fields(
+ trunk_id,
+ numbers=numbers,
+ allowed_addresses=allowed_addresses,
+ allowed_numbers=allowed_numbers,
+ auth_username=auth_username,
+ auth_password=auth_password,
+ name=name,
+ metadata=metadata,
+ )
+
+ async def create_outbound_trunk(
+ self, create: CreateSIPOutboundTrunkRequest
+ ) -> SIPOutboundTrunkInfo:
+ """Create a new SIP outbound trunk.
+
+ Args:
+ create: Request containing trunk details
+
+ Returns:
+ Created SIP outbound trunk
+ """
return await self._client.request(
SVC,
"CreateSIPOutboundTrunk",
create,
- self._auth_header(VideoGrants(), sip=SIPGrants(admin=True)),
- proto_sip.SIPOutboundTrunkInfo,
+ self._admin_headers(),
+ SIPOutboundTrunkInfo,
+ )
+
+ async def create_sip_outbound_trunk(
+ self, create: CreateSIPOutboundTrunkRequest
+ ) -> SIPOutboundTrunkInfo:
+ """Create a new SIP outbound trunk.
+
+ .. deprecated::
+ Use :meth:`create_outbound_trunk` instead.
+
+ Args:
+ create: Request containing trunk details
+
+ Returns:
+ Created SIP outbound trunk
+ """
+ warnings.warn(
+ "create_sip_outbound_trunk is deprecated, use create_outbound_trunk instead",
+ DeprecationWarning,
+ stacklevel=2,
)
+ return await self.create_outbound_trunk(create)
- async def list_sip_trunk(
- self, list: proto_sip.ListSIPTrunkRequest
- ) -> proto_sip.ListSIPTrunkResponse:
+ async def update_outbound_trunk(
+ self,
+ trunk_id: str,
+ trunk: SIPOutboundTrunkInfo,
+ ) -> SIPOutboundTrunkInfo:
+ """Updates an existing SIP outbound trunk by replacing it entirely.
+
+ Args:
+ trunk_id: ID of the SIP outbound trunk to update
+ trunk: SIP outbound trunk to update with
+
+ Returns:
+ Updated SIP outbound trunk
+ """
return await self._client.request(
SVC,
- "ListSIPTrunk",
- list,
- self._auth_header(VideoGrants(), sip=SIPGrants(admin=True)),
- proto_sip.ListSIPTrunkResponse,
+ "UpdateSIPOutboundTrunk",
+ UpdateSIPOutboundTrunkRequest(
+ sip_trunk_id=trunk_id,
+ replace=trunk,
+ ),
+ self._admin_headers(),
+ SIPOutboundTrunkInfo,
)
- async def list_sip_inbound_trunk(
- self, list: proto_sip.ListSIPInboundTrunkRequest
- ) -> proto_sip.ListSIPInboundTrunkResponse:
+ async def update_sip_outbound_trunk(
+ self,
+ trunk_id: str,
+ trunk: SIPOutboundTrunkInfo,
+ ) -> SIPOutboundTrunkInfo:
+ """Updates an existing SIP outbound trunk by replacing it entirely.
+
+ .. deprecated::
+ Use :meth:`update_outbound_trunk` instead.
+
+ Args:
+ trunk_id: ID of the SIP outbound trunk to update
+ trunk: SIP outbound trunk to update with
+
+ Returns:
+ Updated SIP outbound trunk
+ """
+ warnings.warn(
+ "update_sip_outbound_trunk is deprecated, use update_outbound_trunk instead",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ return await self.update_outbound_trunk(trunk_id, trunk)
+
+ async def update_outbound_trunk_fields(
+ self,
+ trunk_id: str,
+ *,
+ address: str | None = None,
+ transport: SIPTransport | None = None,
+ numbers: Optional[ListUpdate | list[str]] = None,
+ auth_username: str | None = None,
+ auth_password: str | None = None,
+ name: str | None = None,
+ metadata: str | None = None,
+ ) -> SIPOutboundTrunkInfo:
+ """Updates specific fields of an existing SIP outbound trunk.
+
+ Only provided fields will be updated.
+ """
+ update = SIPOutboundTrunkUpdate(
+ address=address,
+ transport=transport,
+ auth_username=auth_username,
+ auth_password=auth_password,
+ name=name,
+ metadata=metadata,
+ )
+ if numbers is not None:
+ if isinstance(numbers, ListUpdate):
+ update.numbers.set.extend(numbers.set)
+ update.numbers.add.extend(numbers.add)
+ update.numbers.remove.extend(numbers.remove)
+ else:
+ update.numbers.set.extend(numbers)
+
+ return await self._client.request(
+ SVC,
+ "UpdateSIPOutboundTrunk",
+ UpdateSIPOutboundTrunkRequest(
+ sip_trunk_id=trunk_id,
+ update=update,
+ ),
+ self._admin_headers(),
+ SIPOutboundTrunkInfo,
+ )
+
+ async def update_sip_outbound_trunk_fields(
+ self,
+ trunk_id: str,
+ *,
+ address: str | None = None,
+ transport: SIPTransport | None = None,
+ numbers: list[str] | None = None,
+ auth_username: str | None = None,
+ auth_password: str | None = None,
+ name: str | None = None,
+ metadata: str | None = None,
+ ) -> SIPOutboundTrunkInfo:
+ """Updates specific fields of an existing SIP outbound trunk.
+
+ .. deprecated::
+ Use :meth:`update_outbound_trunk_fields` instead.
+
+ Only provided fields will be updated.
+ """
+ warnings.warn(
+ "update_sip_outbound_trunk_fields is deprecated, use update_outbound_trunk_fields instead",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ return await self.update_outbound_trunk_fields(
+ trunk_id,
+ address=address,
+ transport=transport,
+ numbers=numbers,
+ auth_username=auth_username,
+ auth_password=auth_password,
+ name=name,
+ metadata=metadata,
+ )
+
+ async def list_inbound_trunk(
+ self, list: ListSIPInboundTrunkRequest
+ ) -> ListSIPInboundTrunkResponse:
+ """List SIP inbound trunks with optional filtering.
+
+ Args:
+ list: Request with optional filtering parameters
+
+ Returns:
+ Response containing list of SIP inbound trunks
+ """
return await self._client.request(
SVC,
"ListSIPInboundTrunk",
list,
- self._auth_header(VideoGrants(), sip=SIPGrants(admin=True)),
- proto_sip.ListSIPInboundTrunkResponse,
+ self._admin_headers(),
+ ListSIPInboundTrunkResponse,
)
- async def list_sip_outbound_trunk(
- self, list: proto_sip.ListSIPOutboundTrunkRequest
- ) -> proto_sip.ListSIPOutboundTrunkResponse:
+ async def list_sip_inbound_trunk(
+ self, list: ListSIPInboundTrunkRequest
+ ) -> ListSIPInboundTrunkResponse:
+ """List SIP inbound trunks with optional filtering.
+
+ .. deprecated::
+ Use :meth:`list_inbound_trunk` instead.
+
+ Args:
+ list: Request with optional filtering parameters
+
+ Returns:
+ Response containing list of SIP inbound trunks
+ """
+ warnings.warn(
+ "list_sip_inbound_trunk is deprecated, use list_inbound_trunk instead",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ return await self.list_inbound_trunk(list)
+
+ async def list_outbound_trunk(
+ self, list: ListSIPOutboundTrunkRequest
+ ) -> ListSIPOutboundTrunkResponse:
+ """List SIP outbound trunks with optional filtering.
+
+ Args:
+ list: Request with optional filtering parameters
+
+ Returns:
+ Response containing list of SIP outbound trunks
+ """
return await self._client.request(
SVC,
"ListSIPOutboundTrunk",
list,
- self._auth_header(VideoGrants(), sip=SIPGrants(admin=True)),
- proto_sip.ListSIPOutboundTrunkResponse,
+ self._admin_headers(),
+ ListSIPOutboundTrunkResponse,
)
- async def delete_sip_trunk(
- self, delete: proto_sip.DeleteSIPTrunkRequest
- ) -> proto_sip.SIPTrunkInfo:
+ async def list_sip_outbound_trunk(
+ self, list: ListSIPOutboundTrunkRequest
+ ) -> ListSIPOutboundTrunkResponse:
+ """List SIP outbound trunks with optional filtering.
+
+ .. deprecated::
+ Use :meth:`list_outbound_trunk` instead.
+
+ Args:
+ list: Request with optional filtering parameters
+
+ Returns:
+ Response containing list of SIP outbound trunks
+ """
+ warnings.warn(
+ "list_sip_outbound_trunk is deprecated, use list_outbound_trunk instead",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ return await self.list_outbound_trunk(list)
+
+ async def delete_trunk(self, delete: DeleteSIPTrunkRequest) -> SIPTrunkInfo:
+ """Delete a SIP trunk.
+
+ Args:
+ delete: Request containing trunk ID to delete
+
+ Returns:
+ Deleted trunk information
+ """
return await self._client.request(
SVC,
"DeleteSIPTrunk",
delete,
- self._auth_header(VideoGrants(), sip=SIPGrants(admin=True)),
- proto_sip.SIPTrunkInfo,
+ self._admin_headers(),
+ SIPTrunkInfo,
)
- async def create_sip_dispatch_rule(
- self, create: proto_sip.CreateSIPDispatchRuleRequest
- ) -> proto_sip.SIPDispatchRuleInfo:
+ async def delete_sip_trunk(self, delete: DeleteSIPTrunkRequest) -> SIPTrunkInfo:
+ """Delete a SIP trunk.
+
+ .. deprecated::
+ Use :meth:`delete_trunk` instead.
+
+ Args:
+ delete: Request containing trunk ID to delete
+
+ Returns:
+ Deleted trunk information
+ """
+ warnings.warn(
+ "delete_sip_trunk is deprecated, use delete_trunk instead",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ return await self.delete_trunk(delete)
+
+ async def create_dispatch_rule(
+ self, create: CreateSIPDispatchRuleRequest
+ ) -> SIPDispatchRuleInfo:
+ """Create a new SIP dispatch rule.
+
+ Args:
+ create: Request containing rule details
+
+ Returns:
+ Created SIP dispatch rule
+ """
return await self._client.request(
SVC,
"CreateSIPDispatchRule",
create,
- self._auth_header(VideoGrants(), sip=SIPGrants(admin=True)),
- proto_sip.SIPDispatchRuleInfo,
+ self._admin_headers(),
+ SIPDispatchRuleInfo,
)
- async def list_sip_dispatch_rule(
- self, list: proto_sip.ListSIPDispatchRuleRequest
- ) -> proto_sip.ListSIPDispatchRuleResponse:
+ async def create_sip_dispatch_rule(
+ self, create: CreateSIPDispatchRuleRequest
+ ) -> SIPDispatchRuleInfo:
+ """Create a new SIP dispatch rule.
+
+ .. deprecated::
+ Use :meth:`create_dispatch_rule` instead.
+
+ Args:
+ create: Request containing rule details
+
+ Returns:
+ Created SIP dispatch rule
+ """
+ warnings.warn(
+ "create_sip_dispatch_rule is deprecated, use create_dispatch_rule instead",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ return await self.create_dispatch_rule(create)
+
+ async def update_dispatch_rule(
+ self,
+ rule_id: str,
+ rule: SIPDispatchRuleInfo,
+ ) -> SIPDispatchRuleInfo:
+ """Updates an existing SIP dispatch rule by replacing it entirely.
+
+ Args:
+ rule_id: ID of the SIP dispatch rule to update
+ rule: SIP dispatch rule to update with
+
+ Returns:
+ Updated SIP dispatch rule
+ """
+ return await self._client.request(
+ SVC,
+ "UpdateSIPDispatchRule",
+ UpdateSIPDispatchRuleRequest(sip_dispatch_rule_id=rule_id, replace=rule),
+ self._admin_headers(),
+ SIPDispatchRuleInfo,
+ )
+
+ async def update_sip_dispatch_rule(
+ self,
+ rule_id: str,
+ rule: SIPDispatchRuleInfo,
+ ) -> SIPDispatchRuleInfo:
+ """Updates an existing SIP dispatch rule by replacing it entirely.
+
+ .. deprecated::
+ Use :meth:`update_dispatch_rule` instead.
+
+ Args:
+ rule_id: ID of the SIP dispatch rule to update
+ rule: SIP dispatch rule to update with
+
+ Returns:
+ Updated SIP dispatch rule
+ """
+ warnings.warn(
+ "update_sip_dispatch_rule is deprecated, use update_dispatch_rule instead",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ return await self.update_dispatch_rule(rule_id, rule)
+
+ async def update_dispatch_rule_fields(
+ self,
+ rule_id: str,
+ *,
+ trunk_ids: Optional[ListUpdate | list[str]] = None,
+ rule: Optional[SIPDispatchRule] = None,
+ name: Optional[str] = None,
+ metadata: Optional[str] = None,
+ attributes: Optional[dict[str, str]] = None,
+ ) -> SIPDispatchRuleInfo:
+ """Updates specific fields of an existing SIP dispatch rule.
+
+ Only provided fields will be updated.
+ """
+ update = SIPDispatchRuleUpdate(
+ name=name,
+ metadata=metadata,
+ rule=rule,
+ attributes=attributes,
+ )
+ if trunk_ids is not None:
+ if isinstance(trunk_ids, ListUpdate):
+ update.trunk_ids.set.extend(trunk_ids.set)
+ update.trunk_ids.add.extend(trunk_ids.add)
+ update.trunk_ids.remove.extend(trunk_ids.remove)
+ else:
+ update.trunk_ids.set.extend(trunk_ids)
+
+ return await self._client.request(
+ SVC,
+ "UpdateSIPDispatchRule",
+ UpdateSIPDispatchRuleRequest(sip_dispatch_rule_id=rule_id, update=update),
+ self._admin_headers(),
+ SIPDispatchRuleInfo,
+ )
+
+ async def update_sip_dispatch_rule_fields(
+ self,
+ rule_id: str,
+ *,
+ trunk_ids: Optional[list[str]] = None,
+ rule: Optional[SIPDispatchRule] = None,
+ name: Optional[str] = None,
+ metadata: Optional[str] = None,
+ attributes: Optional[dict[str, str]] = None,
+ ) -> SIPDispatchRuleInfo:
+ """Updates specific fields of an existing SIP dispatch rule.
+
+ .. deprecated::
+ Use :meth:`update_dispatch_rule_fields` instead.
+
+ Only provided fields will be updated.
+ """
+ warnings.warn(
+ "update_sip_dispatch_rule_fields is deprecated, use update_dispatch_rule_fields instead",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ return await self.update_dispatch_rule_fields(
+ rule_id,
+ trunk_ids=trunk_ids,
+ rule=rule,
+ name=name,
+ metadata=metadata,
+ attributes=attributes,
+ )
+
+ async def list_dispatch_rule(
+ self, list: ListSIPDispatchRuleRequest
+ ) -> ListSIPDispatchRuleResponse:
+ """List SIP dispatch rules with optional filtering.
+
+ Args:
+ list: Request with optional filtering parameters
+
+ Returns:
+ Response containing list of SIP dispatch rules
+ """
return await self._client.request(
SVC,
"ListSIPDispatchRule",
list,
- self._auth_header(VideoGrants(), sip=SIPGrants(admin=True)),
- proto_sip.ListSIPDispatchRuleResponse,
+ self._admin_headers(),
+ ListSIPDispatchRuleResponse,
)
- async def delete_sip_dispatch_rule(
- self, delete: proto_sip.DeleteSIPDispatchRuleRequest
- ) -> proto_sip.SIPDispatchRuleInfo:
+ async def list_sip_dispatch_rule(
+ self, list: ListSIPDispatchRuleRequest
+ ) -> ListSIPDispatchRuleResponse:
+ """List SIP dispatch rules with optional filtering.
+
+ .. deprecated::
+ Use :meth:`list_dispatch_rule` instead.
+
+ Args:
+ list: Request with optional filtering parameters
+
+ Returns:
+ Response containing list of SIP dispatch rules
+ """
+ warnings.warn(
+ "list_sip_dispatch_rule is deprecated, use list_dispatch_rule instead",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ return await self.list_dispatch_rule(list)
+
+ async def delete_dispatch_rule(
+ self, delete: DeleteSIPDispatchRuleRequest
+ ) -> SIPDispatchRuleInfo:
+ """Delete a SIP dispatch rule.
+
+ Args:
+ delete: Request containing rule ID to delete
+
+ Returns:
+ Deleted rule information
+ """
return await self._client.request(
SVC,
"DeleteSIPDispatchRule",
delete,
- self._auth_header(VideoGrants(), sip=SIPGrants(admin=True)),
- proto_sip.SIPDispatchRuleInfo,
+ self._admin_headers(),
+ SIPDispatchRuleInfo,
)
+ async def delete_sip_dispatch_rule(
+ self, delete: DeleteSIPDispatchRuleRequest
+ ) -> SIPDispatchRuleInfo:
+ """Delete a SIP dispatch rule.
+
+ .. deprecated::
+ Use :meth:`delete_dispatch_rule` instead.
+
+ Args:
+ delete: Request containing rule ID to delete
+
+ Returns:
+ Deleted rule information
+ """
+ warnings.warn(
+ "delete_sip_dispatch_rule is deprecated, use delete_dispatch_rule instead",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ return await self.delete_dispatch_rule(delete)
+
async def create_sip_participant(
- self, create: proto_sip.CreateSIPParticipantRequest
- ) -> proto_sip.SIPParticipantInfo:
+ self,
+ create: CreateSIPParticipantRequest,
+ *,
+ timeout: Optional[float] = None,
+ trunk_id: Optional[str] = None,
+ outbound_trunk_config: Optional[SIPOutboundConfig] = None,
+ ) -> SIPParticipantInfo:
+ """Create a new SIP participant.
+
+ Args:
+ create: Request containing participant details
+ timeout: Optional request timeout in seconds
+ trunk_id: Optional SIP trunk ID to use for the participant
+ outbound_trunk_config: Optional outbound trunk configuration for the participant
+
+ Returns:
+ Created SIP participant
+
+ Raises:
+ SIPError: If the SIP operation fails
+ """
+ client_timeout: Optional[aiohttp.ClientTimeout] = None
+ if timeout:
+ # obay user specified timeout
+ client_timeout = aiohttp.ClientTimeout(total=timeout)
+ elif create.wait_until_answered:
+ # ensure default timeout isn't too short when using sync mode
+ if (
+ self._client._session.timeout
+ and self._client._session.timeout.total
+ and self._client._session.timeout.total < 20
+ ):
+ client_timeout = aiohttp.ClientTimeout(total=20)
+
+ if trunk_id:
+ create.sip_trunk_id = trunk_id
+
+ if outbound_trunk_config:
+ create.trunk = outbound_trunk_config
+
return await self._client.request(
SVC,
"CreateSIPParticipant",
create,
self._auth_header(VideoGrants(), sip=SIPGrants(call=True)),
- proto_sip.SIPParticipantInfo,
+ SIPParticipantInfo,
+ timeout=client_timeout,
)
+
+ async def transfer_sip_participant(
+ self, transfer: TransferSIPParticipantRequest
+ ) -> SIPParticipantInfo:
+ """Transfer a SIP participant to a different room.
+
+ Args:
+ transfer: Request containing transfer details
+
+ Returns:
+ Updated SIP participant information
+ """
+ return await self._client.request(
+ SVC,
+ "TransferSIPParticipant",
+ transfer,
+ self._auth_header(
+ VideoGrants(
+ room_admin=True,
+ room=transfer.room_name,
+ ),
+ sip=SIPGrants(call=True),
+ ),
+ SIPParticipantInfo,
+ )
+
+ def _admin_headers(self) -> dict[str, str]:
+ return self._auth_header(VideoGrants(), sip=SIPGrants(admin=True))
diff --git a/livekit-api/livekit/api/twirp_client.py b/livekit-api/livekit/api/twirp_client.py
index 1c930270..ce828c3f 100644
--- a/livekit-api/livekit/api/twirp_client.py
+++ b/livekit-api/livekit/api/twirp_client.py
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from typing import Dict, Type, TypeVar
+from typing import Dict, Type, TypeVar, Optional
import aiohttp
from google.protobuf.message import Message
@@ -22,9 +22,18 @@
class TwirpError(Exception):
- def __init__(self, code: str, msg: str) -> None:
+ def __init__(
+ self,
+ code: str,
+ msg: str,
+ *,
+ status: int,
+ metadata: Optional[Dict[str, str]] = None,
+ ) -> None:
self._code = code
self._msg = msg
+ self._status = status
+ self._metadata = metadata or {}
@property
def code(self) -> str:
@@ -34,6 +43,23 @@ def code(self) -> str:
def message(self) -> str:
return self._msg
+ @property
+ def status(self) -> int:
+ """HTTP status code"""
+ return self._status
+
+ @property
+ def metadata(self) -> Dict[str, str]:
+ """Twirp metadata"""
+ return self._metadata
+
+ def __str__(self) -> str:
+ result = f"TwirpError(code={self.code}, message={self.message}, status={self.status}"
+ if self.metadata:
+ result += f", metadata={self.metadata}"
+ result += ")"
+ return result
+
class TwirpErrorCode:
CANCELED = "canceled"
@@ -85,17 +111,24 @@ async def request(
data: Message,
headers: Dict[str, str],
response_class: Type[T],
+ *,
+ timeout: Optional[aiohttp.ClientTimeout] = None,
) -> T:
url = f"{self.host}/{self.prefix}/{self.pkg}.{service}/{method}"
headers["Content-Type"] = "application/protobuf"
serialized_data = data.SerializeToString()
async with self._session.post(
- url, headers=headers, data=serialized_data
+ url, headers=headers, data=serialized_data, timeout=timeout
) as resp:
if resp.status == 200:
return response_class.FromString(await resp.read())
else:
# when we have an error, Twirp always encode it in json
error_data = await resp.json()
- raise TwirpError(error_data["code"], error_data["msg"])
+ raise TwirpError(
+ error_data.get("code", "unknown"),
+ error_data.get("msg", ""),
+ status=resp.status,
+ metadata=error_data.get("meta"),
+ )
diff --git a/livekit-api/livekit/api/version.py b/livekit-api/livekit/api/version.py
index dd9b22cc..6849410a 100644
--- a/livekit-api/livekit/api/version.py
+++ b/livekit-api/livekit/api/version.py
@@ -1 +1 @@
-__version__ = "0.5.1"
+__version__ = "1.1.0"
diff --git a/livekit-api/livekit/api/webhook.py b/livekit-api/livekit/api/webhook.py
index 760c9a90..9f500637 100644
--- a/livekit-api/livekit/api/webhook.py
+++ b/livekit-api/livekit/api/webhook.py
@@ -1,5 +1,5 @@
from .access_token import TokenVerifier
-from livekit.protocol import webhook as proto_webhook
+from livekit.protocol.webhook import WebhookEvent
from google.protobuf.json_format import Parse
import hashlib
import base64
@@ -9,8 +9,10 @@ class WebhookReceiver:
def __init__(self, token_verifier: TokenVerifier):
self._verifier = token_verifier
- def receive(self, body: str, auth_token: str) -> proto_webhook.WebhookEvent:
+ def receive(self, body: str, auth_token: str) -> WebhookEvent:
claims = self._verifier.verify(auth_token)
+ if claims.sha256 is None:
+ raise Exception("sha256 was not found in the token")
body_hash = hashlib.sha256(body.encode()).digest()
claims_hash = base64.b64decode(claims.sha256)
@@ -18,4 +20,4 @@ def receive(self, body: str, auth_token: str) -> proto_webhook.WebhookEvent:
if body_hash != claims_hash:
raise Exception("hash mismatch")
- return Parse(body, proto_webhook.WebhookEvent(), ignore_unknown_fields=True)
+ return Parse(body, WebhookEvent(), ignore_unknown_fields=True)
diff --git a/livekit-api/pyproject.toml b/livekit-api/pyproject.toml
index 15caa0ee..100d5469 100644
--- a/livekit-api/pyproject.toml
+++ b/livekit-api/pyproject.toml
@@ -1,5 +1,51 @@
[build-system]
-requires = [
- "setuptools>=42",
+requires = ["hatchling"]
+build-backend = "hatchling.build"
+
+[project]
+name = "livekit-api"
+dynamic = ["version"]
+description = "Python Server API for LiveKit"
+readme = "README.md"
+requires-python = ">=3.9.0"
+license = "Apache-2.0"
+keywords = ["webrtc", "realtime", "audio", "video", "livekit"]
+authors = [
+ { name = "LiveKit", email = "support@livekit.io" }
]
-build-backend = "setuptools.build_meta"
+classifiers = [
+ "Intended Audience :: Developers",
+ "Topic :: Multimedia :: Sound/Audio",
+ "Topic :: Multimedia :: Video",
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 3.7",
+ "Programming Language :: Python :: 3.8",
+ "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
+ "Programming Language :: Python :: 3 :: Only",
+]
+dependencies = [
+ "pyjwt>=2.0.0",
+ "aiohttp>=3.9.0",
+ "protobuf>=4",
+ "types-protobuf>=4",
+ "livekit-protocol>=1.1.6,<2.0.0",
+]
+
+[project.urls]
+Documentation = "https://docs.livekit.io"
+Website = "https://livekit.io/"
+Source = "https://github.com/livekit/python-sdks/"
+
+[tool.uv.sources]
+livekit-protocol = { workspace = true }
+
+[tool.hatch.version]
+path = "livekit/api/version.py"
+
+[tool.hatch.build.targets.wheel]
+packages = ["livekit"]
+
+[tool.hatch.build.targets.sdist]
+include = ["/livekit"]
diff --git a/livekit-api/setup.py b/livekit-api/setup.py
deleted file mode 100644
index ae57e4d0..00000000
--- a/livekit-api/setup.py
+++ /dev/null
@@ -1,66 +0,0 @@
-# Copyright 2023 LiveKit, Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import os
-import pathlib
-from typing import Any, Dict
-
-import setuptools # type: ignore
-
-here = pathlib.Path(__file__).parent.resolve()
-about: Dict[Any, Any] = {}
-with open(os.path.join(here, "livekit", "api", "version.py"), "r") as f:
- exec(f.read(), about)
-
-
-setuptools.setup(
- name="livekit-api",
- version=about["__version__"],
- description="Python Server API for LiveKit",
- long_description=(here / "README.md").read_text(encoding="utf-8"),
- long_description_content_type="text/markdown",
- url="https://github.com/livekit/python-sdks",
- classifiers=[
- "Intended Audience :: Developers",
- "License :: OSI Approved :: Apache Software License",
- "Topic :: Multimedia :: Sound/Audio",
- "Topic :: Multimedia :: Video",
- "Topic :: Scientific/Engineering :: Artificial Intelligence",
- "Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.7",
- "Programming Language :: Python :: 3.8",
- "Programming Language :: Python :: 3.9",
- "Programming Language :: Python :: 3.10",
- "Programming Language :: Python :: 3 :: Only",
- ],
- keywords=["webrtc", "realtime", "audio", "video", "livekit"],
- license="Apache-2.0",
- packages=setuptools.find_namespace_packages(include=["livekit.*"]),
- python_requires=">=3.9.0",
- install_requires=[
- "pyjwt>=2.0.0",
- "aiohttp>=3.9.0",
- "protobuf>=3",
- "types-protobuf>=4,<5",
- "livekit-protocol>=0.5.1,<2",
- ],
- package_data={
- "livekit.api": ["py.typed", "*.pyi", "**/*.pyi"],
- },
- project_urls={
- "Documentation": "https://docs.livekit.io",
- "Website": "https://livekit.io/",
- "Source": "https://github.com/livekit/python-sdks/",
- },
-)
diff --git a/livekit-protocol/generate_proto.sh b/livekit-protocol/generate_proto.sh
index 692ec7a5..6fe99749 100755
--- a/livekit-protocol/generate_proto.sh
+++ b/livekit-protocol/generate_proto.sh
@@ -18,6 +18,7 @@
set -e
+
API_PROTOCOL=./protocol/protobufs
API_OUT_PYTHON=./livekit/protocol
@@ -31,8 +32,19 @@ protoc \
$API_PROTOCOL/livekit_ingress.proto \
$API_PROTOCOL/livekit_models.proto \
$API_PROTOCOL/livekit_agent.proto \
+ $API_PROTOCOL/livekit_agent_dispatch.proto \
+ $API_PROTOCOL/livekit_metrics.proto \
$API_PROTOCOL/livekit_sip.proto \
- $API_PROTOCOL/livekit_analytics.proto
+ $API_PROTOCOL/livekit_analytics.proto \
+ $API_PROTOCOL/livekit_rtc.proto \
+ $API_PROTOCOL/agent/livekit_agent_session.proto \
+ $API_PROTOCOL/agent/livekit_agent_inference.proto \
+ $API_PROTOCOL/agent/livekit_agent_text.proto \
+ $API_PROTOCOL/agent/livekit_agent_dev.proto \
+ $API_PROTOCOL/logger/options.proto \
+ $API_PROTOCOL/livekit_connector_whatsapp.proto \
+ $API_PROTOCOL/livekit_connector_twilio.proto \
+ $API_PROTOCOL/livekit_connector.proto
touch -a "$API_OUT_PYTHON/__init__.py"
@@ -58,11 +70,49 @@ mv "$API_OUT_PYTHON/livekit_models_pb2.py" "$API_OUT_PYTHON/models.py"
mv "$API_OUT_PYTHON/livekit_models_pb2.pyi" "$API_OUT_PYTHON/models.pyi"
mv "$API_OUT_PYTHON/livekit_agent_pb2.py" "$API_OUT_PYTHON/agent.py"
mv "$API_OUT_PYTHON/livekit_agent_pb2.pyi" "$API_OUT_PYTHON/agent.pyi"
+mv "$API_OUT_PYTHON/livekit_agent_dispatch_pb2.py" "$API_OUT_PYTHON/agent_dispatch.py"
+mv "$API_OUT_PYTHON/livekit_agent_dispatch_pb2.pyi" "$API_OUT_PYTHON/agent_dispatch.pyi"
mv "$API_OUT_PYTHON/livekit_analytics_pb2.py" "$API_OUT_PYTHON/analytics.py"
mv "$API_OUT_PYTHON/livekit_analytics_pb2.pyi" "$API_OUT_PYTHON/analytics.pyi"
mv "$API_OUT_PYTHON/livekit_sip_pb2.py" "$API_OUT_PYTHON/sip.py"
mv "$API_OUT_PYTHON/livekit_sip_pb2.pyi" "$API_OUT_PYTHON/sip.pyi"
+mv "$API_OUT_PYTHON/livekit_metrics_pb2.py" "$API_OUT_PYTHON/metrics.py"
+mv "$API_OUT_PYTHON/livekit_metrics_pb2.pyi" "$API_OUT_PYTHON/metrics.pyi"
+mv "$API_OUT_PYTHON/livekit_rtc_pb2.py" "$API_OUT_PYTHON/rtc.py"
+mv "$API_OUT_PYTHON/livekit_rtc_pb2.pyi" "$API_OUT_PYTHON/rtc.pyi"
+mv "$API_OUT_PYTHON/livekit_connector_whatsapp_pb2.py" "$API_OUT_PYTHON/connector_whatsapp.py"
+mv "$API_OUT_PYTHON/livekit_connector_whatsapp_pb2.pyi" "$API_OUT_PYTHON/connector_whatsapp.pyi"
+mv "$API_OUT_PYTHON/livekit_connector_twilio_pb2.py" "$API_OUT_PYTHON/connector_twilio.py"
+mv "$API_OUT_PYTHON/livekit_connector_twilio_pb2.pyi" "$API_OUT_PYTHON/connector_twilio.pyi"
+mv "$API_OUT_PYTHON/livekit_connector_pb2.py" "$API_OUT_PYTHON/connector.py"
+mv "$API_OUT_PYTHON/livekit_connector_pb2.pyi" "$API_OUT_PYTHON/connector.pyi"
+
+mkdir -p "$API_OUT_PYTHON/agent_pb"
+mv "$API_OUT_PYTHON/agent/livekit_agent_inference_pb2.py" "$API_OUT_PYTHON/agent_pb/agent_inference.py"
+mv "$API_OUT_PYTHON/agent/livekit_agent_inference_pb2.pyi" "$API_OUT_PYTHON/agent_pb/agent_inference.pyi"
+mv "$API_OUT_PYTHON/agent/livekit_agent_session_pb2.py" "$API_OUT_PYTHON/agent_pb/agent_session.py"
+mv "$API_OUT_PYTHON/agent/livekit_agent_session_pb2.pyi" "$API_OUT_PYTHON/agent_pb/agent_session.pyi"
+mv "$API_OUT_PYTHON/agent/livekit_agent_text_pb2.py" "$API_OUT_PYTHON/agent_pb/agent_text.py"
+mv "$API_OUT_PYTHON/agent/livekit_agent_text_pb2.pyi" "$API_OUT_PYTHON/agent_pb/agent_text.pyi"
+mv "$API_OUT_PYTHON/agent/livekit_agent_dev_pb2.py" "$API_OUT_PYTHON/agent_pb/agent_dev.py"
+mv "$API_OUT_PYTHON/agent/livekit_agent_dev_pb2.pyi" "$API_OUT_PYTHON/agent_pb/agent_dev.pyi"
+
+mkdir -p "$API_OUT_PYTHON/logger_pb"
+mv "$API_OUT_PYTHON/logger/options_pb2.py" "$API_OUT_PYTHON/logger_pb/options.py"
+mv "$API_OUT_PYTHON/logger/options_pb2.pyi" "$API_OUT_PYTHON/logger_pb/options.pyi"
+
+find "$API_OUT_PYTHON" -name '*.py' -o -name '*.pyi' | xargs perl -i -pe 's|^(import (livekit_egress_pb2\|livekit_room_pb2\|livekit_webhook_pb2\|livekit_ingress_pb2\|livekit_models_pb2\|livekit_agent_pb2\|livekit_agent_dispatch_pb2\|livekit_analytics_pb2\|livekit_sip_pb2\|livekit_metrics_pb2\|livekit_rtc_pb2\|livekit_connector_whatsapp_pb2\|livekit_connector_twilio_pb2\|livekit_connector_pb2\|livekit_agent_session_pb2\|livekit_agent_inference_pb2\|livekit_agent_dev_pb2\|livekit_agent_text_pb2\|options_pb2))|from . $1|g'
+
+find "$API_OUT_PYTHON" -name '*.py' -o -name '*.pyi' | xargs perl -i -pe 's|livekit_(\w+)_pb2|${1}|g'
+
+# fix logger imports for top-level files
+find "$API_OUT_PYTHON" -maxdepth 1 -name '*.py' -o -name '*.pyi' | xargs perl -i -pe 's|from logger import options_pb2 as ([^ ]+)|from .logger_pb import options as $1|g'
+
+# fix logger imports for files in subdirectories (need parent-relative import)
+find "$API_OUT_PYTHON" -mindepth 2 -name '*.py' -o -name '*.pyi' | xargs perl -i -pe 's|from logger import options_pb2 as ([^ ]+)|from ..logger_pb import options as $1|g'
-perl -i -pe 's|^(import (livekit_egress_pb2\|livekit_room_pb2\|livekit_webhook_pb2\|livekit_ingress_pb2\|livekit_models_pb2\|livekit_agent_pb2\|livekit_analytics_pb2\|livekit_sip_pb2))|from . $1|g' "$API_OUT_PYTHON"/*.py "$API_OUT_PYTHON"/*.pyi
+# fix `from agent import agent_xxx as xxx` to `from . import agent_xxx as xxx`
+find "$API_OUT_PYTHON"/agent_pb -name '*.py' -o -name '*.pyi' | xargs perl -i -pe 's|from agent import (agent_\w+) as ([^ ]+)|from . import $1 as $2|g'
-perl -i -pe 's|livekit_(\w+)_pb2|${1}|g' "$API_OUT_PYTHON"/*.py "$API_OUT_PYTHON"/*.pyi
+# fixes - error: ClassVar can only be used for assignments in class body [misc]
+perl -i -pe 's|^(\w+_FIELD_NUMBER): _ClassVar\[int\]|$1: int|g' "$API_OUT_PYTHON/logger_pb/options.pyi"
diff --git a/livekit-protocol/livekit/protocol/__init__.py b/livekit-protocol/livekit/protocol/__init__.py
index b6e0b419..b971bb95 100644
--- a/livekit-protocol/livekit/protocol/__init__.py
+++ b/livekit-protocol/livekit/protocol/__init__.py
@@ -1,9 +1,28 @@
from . import agent
+from . import agent_pb
+from . import agent_dispatch
from . import analytics
from . import egress
from . import ingress
+from . import metrics
from . import models
from . import room
from . import webhook
from . import sip
from .version import __version__
+
+
+__all__ = [
+ "agent",
+ "agent_pb",
+ "agent_dispatch",
+ "analytics",
+ "egress",
+ "ingress",
+ "metrics",
+ "models",
+ "room",
+ "webhook",
+ "sip",
+ "__version__",
+]
diff --git a/livekit-protocol/livekit/protocol/agent.py b/livekit-protocol/livekit/protocol/agent.py
index b83ff034..8c4bc443 100644
--- a/livekit-protocol/livekit/protocol/agent.py
+++ b/livekit-protocol/livekit/protocol/agent.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: livekit_agent.proto
-# Protobuf Python Version: 4.25.3
+# Protobuf Python Version: 4.25.1
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
@@ -13,9 +13,10 @@
from . import models as _models_
+from .logger_pb import options as logger_dot_options__pb2
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x13livekit_agent.proto\x12\x07livekit\x1a\x14livekit_models.proto\"\xa7\x01\n\nWorkerInfo\x12\n\n\x02id\x18\x01 \x01(\t\x12\x11\n\tnamespace\x18\x02 \x01(\t\x12\x0f\n\x07version\x18\x03 \x01(\t\x12\x0c\n\x04name\x18\x04 \x01(\t\x12\x1e\n\x04type\x18\x05 \x01(\x0e\x32\x10.livekit.JobType\x12;\n\x13\x61llowed_permissions\x18\x06 \x01(\x0b\x32\x1e.livekit.ParticipantPermission\"6\n\tAgentInfo\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0f\n\x07version\x18\x03 \x01(\t\"\xa5\x01\n\x03Job\x12\n\n\x02id\x18\x01 \x01(\t\x12\x1e\n\x04type\x18\x02 \x01(\x0e\x32\x10.livekit.JobType\x12\x1b\n\x04room\x18\x03 \x01(\x0b\x32\r.livekit.Room\x12\x32\n\x0bparticipant\x18\x04 \x01(\x0b\x32\x18.livekit.ParticipantInfoH\x00\x88\x01\x01\x12\x11\n\tnamespace\x18\x05 \x01(\tB\x0e\n\x0c_participant\"\xf8\x02\n\rWorkerMessage\x12\x32\n\x08register\x18\x01 \x01(\x0b\x32\x1e.livekit.RegisterWorkerRequestH\x00\x12\x35\n\x0c\x61vailability\x18\x02 \x01(\x0b\x32\x1d.livekit.AvailabilityResponseH\x00\x12\x34\n\rupdate_worker\x18\x03 \x01(\x0b\x32\x1b.livekit.UpdateWorkerStatusH\x00\x12.\n\nupdate_job\x18\x04 \x01(\x0b\x32\x18.livekit.UpdateJobStatusH\x00\x12#\n\x04ping\x18\x05 \x01(\x0b\x32\x13.livekit.WorkerPingH\x00\x12\x33\n\x0csimulate_job\x18\x06 \x01(\x0b\x32\x1b.livekit.SimulateJobRequestH\x00\x12\x31\n\x0bmigrate_job\x18\x07 \x01(\x0b\x32\x1a.livekit.MigrateJobRequestH\x00\x42\t\n\x07message\"\xd8\x01\n\rServerMessage\x12\x33\n\x08register\x18\x01 \x01(\x0b\x32\x1f.livekit.RegisterWorkerResponseH\x00\x12\x34\n\x0c\x61vailability\x18\x02 \x01(\x0b\x32\x1c.livekit.AvailabilityRequestH\x00\x12,\n\nassignment\x18\x03 \x01(\x0b\x32\x16.livekit.JobAssignmentH\x00\x12#\n\x04pong\x18\x04 \x01(\x0b\x32\x13.livekit.WorkerPongH\x00\x42\t\n\x07message\"\x80\x01\n\x12SimulateJobRequest\x12\x1e\n\x04type\x18\x01 \x01(\x0e\x32\x10.livekit.JobType\x12\x1b\n\x04room\x18\x02 \x01(\x0b\x32\r.livekit.Room\x12-\n\x0bparticipant\x18\x03 \x01(\x0b\x32\x18.livekit.ParticipantInfo\"\x1f\n\nWorkerPing\x12\x11\n\ttimestamp\x18\x01 \x01(\x03\"7\n\nWorkerPong\x12\x16\n\x0elast_timestamp\x18\x01 \x01(\x03\x12\x11\n\ttimestamp\x18\x02 \x01(\x03\"\xd0\x01\n\x15RegisterWorkerRequest\x12\x1e\n\x04type\x18\x01 \x01(\x0e\x32\x10.livekit.JobType\x12\x0f\n\x07version\x18\x03 \x01(\t\x12\x0c\n\x04name\x18\x04 \x01(\t\x12\x15\n\rping_interval\x18\x05 \x01(\r\x12\x16\n\tnamespace\x18\x06 \x01(\tH\x00\x88\x01\x01\x12;\n\x13\x61llowed_permissions\x18\x07 \x01(\x0b\x32\x1e.livekit.ParticipantPermissionB\x0c\n\n_namespace\"U\n\x16RegisterWorkerResponse\x12\x11\n\tworker_id\x18\x01 \x01(\t\x12(\n\x0bserver_info\x18\x03 \x01(\x0b\x32\x13.livekit.ServerInfo\"#\n\x11MigrateJobRequest\x12\x0e\n\x06job_id\x18\x01 \x01(\t\"B\n\x13\x41vailabilityRequest\x12\x19\n\x03job\x18\x01 \x01(\x0b\x32\x0c.livekit.Job\x12\x10\n\x08resuming\x18\x02 \x01(\x08\"\xa8\x01\n\x14\x41vailabilityResponse\x12\x0e\n\x06job_id\x18\x01 \x01(\t\x12\x11\n\tavailable\x18\x02 \x01(\x08\x12\x17\n\x0fsupports_resume\x18\x03 \x01(\x08\x12\x18\n\x10participant_name\x18\x04 \x01(\t\x12\x1c\n\x14participant_identity\x18\x05 \x01(\t\x12\x1c\n\x14participant_metadata\x18\x06 \x01(\t\"\x96\x01\n\x0fUpdateJobStatus\x12\x0e\n\x06job_id\x18\x01 \x01(\t\x12\'\n\x06status\x18\x02 \x01(\x0e\x32\x12.livekit.JobStatusH\x00\x88\x01\x01\x12\r\n\x05\x65rror\x18\x03 \x01(\t\x12\x15\n\x08metadata\x18\x04 \x01(\tH\x01\x88\x01\x01\x12\x0c\n\x04load\x18\x05 \x01(\x02\x42\t\n\x07_statusB\x0b\n\t_metadata\"}\n\x12UpdateWorkerStatus\x12*\n\x06status\x18\x01 \x01(\x0e\x32\x15.livekit.WorkerStatusH\x00\x88\x01\x01\x12\x15\n\x08metadata\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x0c\n\x04load\x18\x03 \x01(\x02\x42\t\n\x07_statusB\x0b\n\t_metadata\"S\n\rJobAssignment\x12\x19\n\x03job\x18\x01 \x01(\x0b\x32\x0c.livekit.Job\x12\x10\n\x03url\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\r\n\x05token\x18\x03 \x01(\tB\x06\n\x04_url*(\n\x07JobType\x12\x0b\n\x07JT_ROOM\x10\x00\x12\x10\n\x0cJT_PUBLISHER\x10\x01*-\n\x0cWorkerStatus\x12\x10\n\x0cWS_AVAILABLE\x10\x00\x12\x0b\n\x07WS_FULL\x10\x01*:\n\tJobStatus\x12\x0e\n\nJS_UNKNOWN\x10\x00\x12\x0e\n\nJS_SUCCESS\x10\x01\x12\r\n\tJS_FAILED\x10\x02\x42\x46Z#github.com/livekit/protocol/livekit\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x13livekit_agent.proto\x12\x07livekit\x1a\x14livekit_models.proto\x1a\x14logger/options.proto\"\xaf\x02\n\x03Job\x12\n\n\x02id\x18\x01 \x01(\t\x12\"\n\x0b\x64ispatch_id\x18\t \x01(\tB\r\xbaP\ndispatchID\x12\x1e\n\x04type\x18\x02 \x01(\x0e\x32\x10.livekit.JobType\x12\x1b\n\x04room\x18\x03 \x01(\x0b\x32\r.livekit.Room\x12\x32\n\x0bparticipant\x18\x04 \x01(\x0b\x32\x18.livekit.ParticipantInfoH\x00\x88\x01\x01\x12\x15\n\tnamespace\x18\x05 \x01(\tB\x02\x18\x01\x12\x10\n\x08metadata\x18\x06 \x01(\t\x12\x12\n\nagent_name\x18\x07 \x01(\t\x12 \n\x05state\x18\x08 \x01(\x0b\x32\x11.livekit.JobState\x12\x18\n\x10\x65nable_recording\x18\n \x01(\x08\x42\x0e\n\x0c_participant\"\xd3\x01\n\x08JobState\x12\"\n\x06status\x18\x01 \x01(\x0e\x32\x12.livekit.JobStatus\x12\r\n\x05\x65rror\x18\x02 \x01(\t\x12\x12\n\nstarted_at\x18\x03 \x01(\x03\x12\x10\n\x08\x65nded_at\x18\x04 \x01(\x03\x12\x12\n\nupdated_at\x18\x05 \x01(\x03\x12\x1c\n\x14participant_identity\x18\x06 \x01(\t\x12\x1e\n\tworker_id\x18\x07 \x01(\tB\x0b\xbaP\x08workerID\x12\x1c\n\x08\x61gent_id\x18\x08 \x01(\tB\n\xbaP\x07\x61gentID\"\xf8\x02\n\rWorkerMessage\x12\x32\n\x08register\x18\x01 \x01(\x0b\x32\x1e.livekit.RegisterWorkerRequestH\x00\x12\x35\n\x0c\x61vailability\x18\x02 \x01(\x0b\x32\x1d.livekit.AvailabilityResponseH\x00\x12\x34\n\rupdate_worker\x18\x03 \x01(\x0b\x32\x1b.livekit.UpdateWorkerStatusH\x00\x12.\n\nupdate_job\x18\x04 \x01(\x0b\x32\x18.livekit.UpdateJobStatusH\x00\x12#\n\x04ping\x18\x05 \x01(\x0b\x32\x13.livekit.WorkerPingH\x00\x12\x33\n\x0csimulate_job\x18\x06 \x01(\x0b\x32\x1b.livekit.SimulateJobRequestH\x00\x12\x31\n\x0bmigrate_job\x18\x07 \x01(\x0b\x32\x1a.livekit.MigrateJobRequestH\x00\x42\t\n\x07message\"\x88\x02\n\rServerMessage\x12\x33\n\x08register\x18\x01 \x01(\x0b\x32\x1f.livekit.RegisterWorkerResponseH\x00\x12\x34\n\x0c\x61vailability\x18\x02 \x01(\x0b\x32\x1c.livekit.AvailabilityRequestH\x00\x12,\n\nassignment\x18\x03 \x01(\x0b\x32\x16.livekit.JobAssignmentH\x00\x12.\n\x0btermination\x18\x05 \x01(\x0b\x32\x17.livekit.JobTerminationH\x00\x12#\n\x04pong\x18\x04 \x01(\x0b\x32\x13.livekit.WorkerPongH\x00\x42\t\n\x07message\"\x80\x01\n\x12SimulateJobRequest\x12\x1e\n\x04type\x18\x01 \x01(\x0e\x32\x10.livekit.JobType\x12\x1b\n\x04room\x18\x02 \x01(\x0b\x32\r.livekit.Room\x12-\n\x0bparticipant\x18\x03 \x01(\x0b\x32\x18.livekit.ParticipantInfo\"\x1f\n\nWorkerPing\x12\x11\n\ttimestamp\x18\x01 \x01(\x03\"7\n\nWorkerPong\x12\x16\n\x0elast_timestamp\x18\x01 \x01(\x03\x12\x11\n\ttimestamp\x18\x02 \x01(\x03\"\xd6\x01\n\x15RegisterWorkerRequest\x12\x1e\n\x04type\x18\x01 \x01(\x0e\x32\x10.livekit.JobType\x12\x12\n\nagent_name\x18\x08 \x01(\t\x12\x0f\n\x07version\x18\x03 \x01(\t\x12\x15\n\rping_interval\x18\x05 \x01(\r\x12\x16\n\tnamespace\x18\x06 \x01(\tH\x00\x88\x01\x01\x12;\n\x13\x61llowed_permissions\x18\x07 \x01(\x0b\x32\x1e.livekit.ParticipantPermissionB\x0c\n\n_namespace\"b\n\x16RegisterWorkerResponse\x12\x1e\n\tworker_id\x18\x01 \x01(\tB\x0b\xbaP\x08workerID\x12(\n\x0bserver_info\x18\x03 \x01(\x0b\x32\x13.livekit.ServerInfo\"$\n\x11MigrateJobRequest\x12\x0f\n\x07job_ids\x18\x02 \x03(\t\"B\n\x13\x41vailabilityRequest\x12\x19\n\x03job\x18\x01 \x01(\x0b\x32\x0c.livekit.Job\x12\x10\n\x08resuming\x18\x02 \x01(\x08\"\xdd\x02\n\x14\x41vailabilityResponse\x12\x18\n\x06job_id\x18\x01 \x01(\tB\x08\xbaP\x05jobID\x12\x11\n\tavailable\x18\x02 \x01(\x08\x12\x17\n\x0fsupports_resume\x18\x03 \x01(\x08\x12\x11\n\tterminate\x18\x08 \x01(\x08\x12\x18\n\x10participant_name\x18\x04 \x01(\t\x12\x1c\n\x14participant_identity\x18\x05 \x01(\t\x12\x1c\n\x14participant_metadata\x18\x06 \x01(\t\x12X\n\x16participant_attributes\x18\x07 \x03(\x0b\x32\x38.livekit.AvailabilityResponse.ParticipantAttributesEntry\x1a<\n\x1aParticipantAttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"^\n\x0fUpdateJobStatus\x12\x18\n\x06job_id\x18\x01 \x01(\tB\x08\xbaP\x05jobID\x12\"\n\x06status\x18\x02 \x01(\x0e\x32\x12.livekit.JobStatus\x12\r\n\x05\x65rror\x18\x03 \x01(\t\"l\n\x12UpdateWorkerStatus\x12*\n\x06status\x18\x01 \x01(\x0e\x32\x15.livekit.WorkerStatusH\x00\x88\x01\x01\x12\x0c\n\x04load\x18\x03 \x01(\x02\x12\x11\n\tjob_count\x18\x04 \x01(\rB\t\n\x07_status\"S\n\rJobAssignment\x12\x19\n\x03job\x18\x01 \x01(\x0b\x32\x0c.livekit.Job\x12\x10\n\x03url\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\r\n\x05token\x18\x03 \x01(\tB\x06\n\x04_url\"*\n\x0eJobTermination\x12\x18\n\x06job_id\x18\x01 \x01(\tB\x08\xbaP\x05jobID*<\n\x07JobType\x12\x0b\n\x07JT_ROOM\x10\x00\x12\x10\n\x0cJT_PUBLISHER\x10\x01\x12\x12\n\x0eJT_PARTICIPANT\x10\x02*-\n\x0cWorkerStatus\x12\x10\n\x0cWS_AVAILABLE\x10\x00\x12\x0b\n\x07WS_FULL\x10\x01*J\n\tJobStatus\x12\x0e\n\nJS_PENDING\x10\x00\x12\x0e\n\nJS_RUNNING\x10\x01\x12\x0e\n\nJS_SUCCESS\x10\x02\x12\r\n\tJS_FAILED\x10\x03\x42\x46Z#github.com/livekit/protocol/livekit\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -23,42 +24,62 @@
if _descriptor._USE_C_DESCRIPTORS == False:
_globals['DESCRIPTOR']._options = None
_globals['DESCRIPTOR']._serialized_options = b'Z#github.com/livekit/protocol/livekit\252\002\rLiveKit.Proto\352\002\016LiveKit::Proto'
- _globals['_JOBTYPE']._serialized_start=2206
- _globals['_JOBTYPE']._serialized_end=2246
- _globals['_WORKERSTATUS']._serialized_start=2248
- _globals['_WORKERSTATUS']._serialized_end=2293
- _globals['_JOBSTATUS']._serialized_start=2295
- _globals['_JOBSTATUS']._serialized_end=2353
- _globals['_WORKERINFO']._serialized_start=55
- _globals['_WORKERINFO']._serialized_end=222
- _globals['_AGENTINFO']._serialized_start=224
- _globals['_AGENTINFO']._serialized_end=278
- _globals['_JOB']._serialized_start=281
- _globals['_JOB']._serialized_end=446
- _globals['_WORKERMESSAGE']._serialized_start=449
- _globals['_WORKERMESSAGE']._serialized_end=825
- _globals['_SERVERMESSAGE']._serialized_start=828
- _globals['_SERVERMESSAGE']._serialized_end=1044
- _globals['_SIMULATEJOBREQUEST']._serialized_start=1047
- _globals['_SIMULATEJOBREQUEST']._serialized_end=1175
- _globals['_WORKERPING']._serialized_start=1177
- _globals['_WORKERPING']._serialized_end=1208
- _globals['_WORKERPONG']._serialized_start=1210
- _globals['_WORKERPONG']._serialized_end=1265
- _globals['_REGISTERWORKERREQUEST']._serialized_start=1268
- _globals['_REGISTERWORKERREQUEST']._serialized_end=1476
- _globals['_REGISTERWORKERRESPONSE']._serialized_start=1478
- _globals['_REGISTERWORKERRESPONSE']._serialized_end=1563
- _globals['_MIGRATEJOBREQUEST']._serialized_start=1565
- _globals['_MIGRATEJOBREQUEST']._serialized_end=1600
- _globals['_AVAILABILITYREQUEST']._serialized_start=1602
- _globals['_AVAILABILITYREQUEST']._serialized_end=1668
- _globals['_AVAILABILITYRESPONSE']._serialized_start=1671
- _globals['_AVAILABILITYRESPONSE']._serialized_end=1839
- _globals['_UPDATEJOBSTATUS']._serialized_start=1842
- _globals['_UPDATEJOBSTATUS']._serialized_end=1992
- _globals['_UPDATEWORKERSTATUS']._serialized_start=1994
- _globals['_UPDATEWORKERSTATUS']._serialized_end=2119
- _globals['_JOBASSIGNMENT']._serialized_start=2121
- _globals['_JOBASSIGNMENT']._serialized_end=2204
+ _globals['_JOB'].fields_by_name['dispatch_id']._options = None
+ _globals['_JOB'].fields_by_name['dispatch_id']._serialized_options = b'\272P\ndispatchID'
+ _globals['_JOB'].fields_by_name['namespace']._options = None
+ _globals['_JOB'].fields_by_name['namespace']._serialized_options = b'\030\001'
+ _globals['_JOBSTATE'].fields_by_name['worker_id']._options = None
+ _globals['_JOBSTATE'].fields_by_name['worker_id']._serialized_options = b'\272P\010workerID'
+ _globals['_JOBSTATE'].fields_by_name['agent_id']._options = None
+ _globals['_JOBSTATE'].fields_by_name['agent_id']._serialized_options = b'\272P\007agentID'
+ _globals['_REGISTERWORKERRESPONSE'].fields_by_name['worker_id']._options = None
+ _globals['_REGISTERWORKERRESPONSE'].fields_by_name['worker_id']._serialized_options = b'\272P\010workerID'
+ _globals['_AVAILABILITYRESPONSE_PARTICIPANTATTRIBUTESENTRY']._options = None
+ _globals['_AVAILABILITYRESPONSE_PARTICIPANTATTRIBUTESENTRY']._serialized_options = b'8\001'
+ _globals['_AVAILABILITYRESPONSE'].fields_by_name['job_id']._options = None
+ _globals['_AVAILABILITYRESPONSE'].fields_by_name['job_id']._serialized_options = b'\272P\005jobID'
+ _globals['_UPDATEJOBSTATUS'].fields_by_name['job_id']._options = None
+ _globals['_UPDATEJOBSTATUS'].fields_by_name['job_id']._serialized_options = b'\272P\005jobID'
+ _globals['_JOBTERMINATION'].fields_by_name['job_id']._options = None
+ _globals['_JOBTERMINATION'].fields_by_name['job_id']._serialized_options = b'\272P\005jobID'
+ _globals['_JOBTYPE']._serialized_start=2573
+ _globals['_JOBTYPE']._serialized_end=2633
+ _globals['_WORKERSTATUS']._serialized_start=2635
+ _globals['_WORKERSTATUS']._serialized_end=2680
+ _globals['_JOBSTATUS']._serialized_start=2682
+ _globals['_JOBSTATUS']._serialized_end=2756
+ _globals['_JOB']._serialized_start=77
+ _globals['_JOB']._serialized_end=380
+ _globals['_JOBSTATE']._serialized_start=383
+ _globals['_JOBSTATE']._serialized_end=594
+ _globals['_WORKERMESSAGE']._serialized_start=597
+ _globals['_WORKERMESSAGE']._serialized_end=973
+ _globals['_SERVERMESSAGE']._serialized_start=976
+ _globals['_SERVERMESSAGE']._serialized_end=1240
+ _globals['_SIMULATEJOBREQUEST']._serialized_start=1243
+ _globals['_SIMULATEJOBREQUEST']._serialized_end=1371
+ _globals['_WORKERPING']._serialized_start=1373
+ _globals['_WORKERPING']._serialized_end=1404
+ _globals['_WORKERPONG']._serialized_start=1406
+ _globals['_WORKERPONG']._serialized_end=1461
+ _globals['_REGISTERWORKERREQUEST']._serialized_start=1464
+ _globals['_REGISTERWORKERREQUEST']._serialized_end=1678
+ _globals['_REGISTERWORKERRESPONSE']._serialized_start=1680
+ _globals['_REGISTERWORKERRESPONSE']._serialized_end=1778
+ _globals['_MIGRATEJOBREQUEST']._serialized_start=1780
+ _globals['_MIGRATEJOBREQUEST']._serialized_end=1816
+ _globals['_AVAILABILITYREQUEST']._serialized_start=1818
+ _globals['_AVAILABILITYREQUEST']._serialized_end=1884
+ _globals['_AVAILABILITYRESPONSE']._serialized_start=1887
+ _globals['_AVAILABILITYRESPONSE']._serialized_end=2236
+ _globals['_AVAILABILITYRESPONSE_PARTICIPANTATTRIBUTESENTRY']._serialized_start=2176
+ _globals['_AVAILABILITYRESPONSE_PARTICIPANTATTRIBUTESENTRY']._serialized_end=2236
+ _globals['_UPDATEJOBSTATUS']._serialized_start=2238
+ _globals['_UPDATEJOBSTATUS']._serialized_end=2332
+ _globals['_UPDATEWORKERSTATUS']._serialized_start=2334
+ _globals['_UPDATEWORKERSTATUS']._serialized_end=2442
+ _globals['_JOBASSIGNMENT']._serialized_start=2444
+ _globals['_JOBASSIGNMENT']._serialized_end=2527
+ _globals['_JOBTERMINATION']._serialized_start=2529
+ _globals['_JOBTERMINATION']._serialized_end=2571
# @@protoc_insertion_point(module_scope)
diff --git a/livekit-protocol/livekit/protocol/agent.pyi b/livekit-protocol/livekit/protocol/agent.pyi
index 502f695b..a0a7901b 100644
--- a/livekit-protocol/livekit/protocol/agent.pyi
+++ b/livekit-protocol/livekit/protocol/agent.pyi
@@ -1,8 +1,10 @@
from . import models as _models
+from .logger_pb import options as _options_pb2
+from google.protobuf.internal import containers as _containers
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
-from typing import ClassVar as _ClassVar, Mapping as _Mapping, Optional as _Optional, Union as _Union
+from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union
DESCRIPTOR: _descriptor.FileDescriptor
@@ -10,6 +12,7 @@ class JobType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
JT_ROOM: _ClassVar[JobType]
JT_PUBLISHER: _ClassVar[JobType]
+ JT_PARTICIPANT: _ClassVar[JobType]
class WorkerStatus(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
@@ -18,56 +21,63 @@ class WorkerStatus(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
class JobStatus(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
- JS_UNKNOWN: _ClassVar[JobStatus]
+ JS_PENDING: _ClassVar[JobStatus]
+ JS_RUNNING: _ClassVar[JobStatus]
JS_SUCCESS: _ClassVar[JobStatus]
JS_FAILED: _ClassVar[JobStatus]
JT_ROOM: JobType
JT_PUBLISHER: JobType
+JT_PARTICIPANT: JobType
WS_AVAILABLE: WorkerStatus
WS_FULL: WorkerStatus
-JS_UNKNOWN: JobStatus
+JS_PENDING: JobStatus
+JS_RUNNING: JobStatus
JS_SUCCESS: JobStatus
JS_FAILED: JobStatus
-class WorkerInfo(_message.Message):
- __slots__ = ("id", "namespace", "version", "name", "type", "allowed_permissions")
- ID_FIELD_NUMBER: _ClassVar[int]
- NAMESPACE_FIELD_NUMBER: _ClassVar[int]
- VERSION_FIELD_NUMBER: _ClassVar[int]
- NAME_FIELD_NUMBER: _ClassVar[int]
- TYPE_FIELD_NUMBER: _ClassVar[int]
- ALLOWED_PERMISSIONS_FIELD_NUMBER: _ClassVar[int]
- id: str
- namespace: str
- version: str
- name: str
- type: JobType
- allowed_permissions: _models.ParticipantPermission
- def __init__(self, id: _Optional[str] = ..., namespace: _Optional[str] = ..., version: _Optional[str] = ..., name: _Optional[str] = ..., type: _Optional[_Union[JobType, str]] = ..., allowed_permissions: _Optional[_Union[_models.ParticipantPermission, _Mapping]] = ...) -> None: ...
-
-class AgentInfo(_message.Message):
- __slots__ = ("id", "name", "version")
- ID_FIELD_NUMBER: _ClassVar[int]
- NAME_FIELD_NUMBER: _ClassVar[int]
- VERSION_FIELD_NUMBER: _ClassVar[int]
- id: str
- name: str
- version: str
- def __init__(self, id: _Optional[str] = ..., name: _Optional[str] = ..., version: _Optional[str] = ...) -> None: ...
-
class Job(_message.Message):
- __slots__ = ("id", "type", "room", "participant", "namespace")
+ __slots__ = ("id", "dispatch_id", "type", "room", "participant", "namespace", "metadata", "agent_name", "state", "enable_recording")
ID_FIELD_NUMBER: _ClassVar[int]
+ DISPATCH_ID_FIELD_NUMBER: _ClassVar[int]
TYPE_FIELD_NUMBER: _ClassVar[int]
ROOM_FIELD_NUMBER: _ClassVar[int]
PARTICIPANT_FIELD_NUMBER: _ClassVar[int]
NAMESPACE_FIELD_NUMBER: _ClassVar[int]
+ METADATA_FIELD_NUMBER: _ClassVar[int]
+ AGENT_NAME_FIELD_NUMBER: _ClassVar[int]
+ STATE_FIELD_NUMBER: _ClassVar[int]
+ ENABLE_RECORDING_FIELD_NUMBER: _ClassVar[int]
id: str
+ dispatch_id: str
type: JobType
room: _models.Room
participant: _models.ParticipantInfo
namespace: str
- def __init__(self, id: _Optional[str] = ..., type: _Optional[_Union[JobType, str]] = ..., room: _Optional[_Union[_models.Room, _Mapping]] = ..., participant: _Optional[_Union[_models.ParticipantInfo, _Mapping]] = ..., namespace: _Optional[str] = ...) -> None: ...
+ metadata: str
+ agent_name: str
+ state: JobState
+ enable_recording: bool
+ def __init__(self, id: _Optional[str] = ..., dispatch_id: _Optional[str] = ..., type: _Optional[_Union[JobType, str]] = ..., room: _Optional[_Union[_models.Room, _Mapping]] = ..., participant: _Optional[_Union[_models.ParticipantInfo, _Mapping]] = ..., namespace: _Optional[str] = ..., metadata: _Optional[str] = ..., agent_name: _Optional[str] = ..., state: _Optional[_Union[JobState, _Mapping]] = ..., enable_recording: bool = ...) -> None: ...
+
+class JobState(_message.Message):
+ __slots__ = ("status", "error", "started_at", "ended_at", "updated_at", "participant_identity", "worker_id", "agent_id")
+ STATUS_FIELD_NUMBER: _ClassVar[int]
+ ERROR_FIELD_NUMBER: _ClassVar[int]
+ STARTED_AT_FIELD_NUMBER: _ClassVar[int]
+ ENDED_AT_FIELD_NUMBER: _ClassVar[int]
+ UPDATED_AT_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: _ClassVar[int]
+ WORKER_ID_FIELD_NUMBER: _ClassVar[int]
+ AGENT_ID_FIELD_NUMBER: _ClassVar[int]
+ status: JobStatus
+ error: str
+ started_at: int
+ ended_at: int
+ updated_at: int
+ participant_identity: str
+ worker_id: str
+ agent_id: str
+ def __init__(self, status: _Optional[_Union[JobStatus, str]] = ..., error: _Optional[str] = ..., started_at: _Optional[int] = ..., ended_at: _Optional[int] = ..., updated_at: _Optional[int] = ..., participant_identity: _Optional[str] = ..., worker_id: _Optional[str] = ..., agent_id: _Optional[str] = ...) -> None: ...
class WorkerMessage(_message.Message):
__slots__ = ("register", "availability", "update_worker", "update_job", "ping", "simulate_job", "migrate_job")
@@ -88,16 +98,18 @@ class WorkerMessage(_message.Message):
def __init__(self, register: _Optional[_Union[RegisterWorkerRequest, _Mapping]] = ..., availability: _Optional[_Union[AvailabilityResponse, _Mapping]] = ..., update_worker: _Optional[_Union[UpdateWorkerStatus, _Mapping]] = ..., update_job: _Optional[_Union[UpdateJobStatus, _Mapping]] = ..., ping: _Optional[_Union[WorkerPing, _Mapping]] = ..., simulate_job: _Optional[_Union[SimulateJobRequest, _Mapping]] = ..., migrate_job: _Optional[_Union[MigrateJobRequest, _Mapping]] = ...) -> None: ...
class ServerMessage(_message.Message):
- __slots__ = ("register", "availability", "assignment", "pong")
+ __slots__ = ("register", "availability", "assignment", "termination", "pong")
REGISTER_FIELD_NUMBER: _ClassVar[int]
AVAILABILITY_FIELD_NUMBER: _ClassVar[int]
ASSIGNMENT_FIELD_NUMBER: _ClassVar[int]
+ TERMINATION_FIELD_NUMBER: _ClassVar[int]
PONG_FIELD_NUMBER: _ClassVar[int]
register: RegisterWorkerResponse
availability: AvailabilityRequest
assignment: JobAssignment
+ termination: JobTermination
pong: WorkerPong
- def __init__(self, register: _Optional[_Union[RegisterWorkerResponse, _Mapping]] = ..., availability: _Optional[_Union[AvailabilityRequest, _Mapping]] = ..., assignment: _Optional[_Union[JobAssignment, _Mapping]] = ..., pong: _Optional[_Union[WorkerPong, _Mapping]] = ...) -> None: ...
+ def __init__(self, register: _Optional[_Union[RegisterWorkerResponse, _Mapping]] = ..., availability: _Optional[_Union[AvailabilityRequest, _Mapping]] = ..., assignment: _Optional[_Union[JobAssignment, _Mapping]] = ..., termination: _Optional[_Union[JobTermination, _Mapping]] = ..., pong: _Optional[_Union[WorkerPong, _Mapping]] = ...) -> None: ...
class SimulateJobRequest(_message.Message):
__slots__ = ("type", "room", "participant")
@@ -124,20 +136,20 @@ class WorkerPong(_message.Message):
def __init__(self, last_timestamp: _Optional[int] = ..., timestamp: _Optional[int] = ...) -> None: ...
class RegisterWorkerRequest(_message.Message):
- __slots__ = ("type", "version", "name", "ping_interval", "namespace", "allowed_permissions")
+ __slots__ = ("type", "agent_name", "version", "ping_interval", "namespace", "allowed_permissions")
TYPE_FIELD_NUMBER: _ClassVar[int]
+ AGENT_NAME_FIELD_NUMBER: _ClassVar[int]
VERSION_FIELD_NUMBER: _ClassVar[int]
- NAME_FIELD_NUMBER: _ClassVar[int]
PING_INTERVAL_FIELD_NUMBER: _ClassVar[int]
NAMESPACE_FIELD_NUMBER: _ClassVar[int]
ALLOWED_PERMISSIONS_FIELD_NUMBER: _ClassVar[int]
type: JobType
+ agent_name: str
version: str
- name: str
ping_interval: int
namespace: str
allowed_permissions: _models.ParticipantPermission
- def __init__(self, type: _Optional[_Union[JobType, str]] = ..., version: _Optional[str] = ..., name: _Optional[str] = ..., ping_interval: _Optional[int] = ..., namespace: _Optional[str] = ..., allowed_permissions: _Optional[_Union[_models.ParticipantPermission, _Mapping]] = ...) -> None: ...
+ def __init__(self, type: _Optional[_Union[JobType, str]] = ..., agent_name: _Optional[str] = ..., version: _Optional[str] = ..., ping_interval: _Optional[int] = ..., namespace: _Optional[str] = ..., allowed_permissions: _Optional[_Union[_models.ParticipantPermission, _Mapping]] = ...) -> None: ...
class RegisterWorkerResponse(_message.Message):
__slots__ = ("worker_id", "server_info")
@@ -148,10 +160,10 @@ class RegisterWorkerResponse(_message.Message):
def __init__(self, worker_id: _Optional[str] = ..., server_info: _Optional[_Union[_models.ServerInfo, _Mapping]] = ...) -> None: ...
class MigrateJobRequest(_message.Message):
- __slots__ = ("job_id",)
- JOB_ID_FIELD_NUMBER: _ClassVar[int]
- job_id: str
- def __init__(self, job_id: _Optional[str] = ...) -> None: ...
+ __slots__ = ("job_ids",)
+ JOB_IDS_FIELD_NUMBER: _ClassVar[int]
+ job_ids: _containers.RepeatedScalarFieldContainer[str]
+ def __init__(self, job_ids: _Optional[_Iterable[str]] = ...) -> None: ...
class AvailabilityRequest(_message.Message):
__slots__ = ("job", "resuming")
@@ -162,44 +174,51 @@ class AvailabilityRequest(_message.Message):
def __init__(self, job: _Optional[_Union[Job, _Mapping]] = ..., resuming: bool = ...) -> None: ...
class AvailabilityResponse(_message.Message):
- __slots__ = ("job_id", "available", "supports_resume", "participant_name", "participant_identity", "participant_metadata")
+ __slots__ = ("job_id", "available", "supports_resume", "terminate", "participant_name", "participant_identity", "participant_metadata", "participant_attributes")
+ class ParticipantAttributesEntry(_message.Message):
+ __slots__ = ("key", "value")
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: str
+ value: str
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
JOB_ID_FIELD_NUMBER: _ClassVar[int]
AVAILABLE_FIELD_NUMBER: _ClassVar[int]
SUPPORTS_RESUME_FIELD_NUMBER: _ClassVar[int]
+ TERMINATE_FIELD_NUMBER: _ClassVar[int]
PARTICIPANT_NAME_FIELD_NUMBER: _ClassVar[int]
PARTICIPANT_IDENTITY_FIELD_NUMBER: _ClassVar[int]
PARTICIPANT_METADATA_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_ATTRIBUTES_FIELD_NUMBER: _ClassVar[int]
job_id: str
available: bool
supports_resume: bool
+ terminate: bool
participant_name: str
participant_identity: str
participant_metadata: str
- def __init__(self, job_id: _Optional[str] = ..., available: bool = ..., supports_resume: bool = ..., participant_name: _Optional[str] = ..., participant_identity: _Optional[str] = ..., participant_metadata: _Optional[str] = ...) -> None: ...
+ participant_attributes: _containers.ScalarMap[str, str]
+ def __init__(self, job_id: _Optional[str] = ..., available: bool = ..., supports_resume: bool = ..., terminate: bool = ..., participant_name: _Optional[str] = ..., participant_identity: _Optional[str] = ..., participant_metadata: _Optional[str] = ..., participant_attributes: _Optional[_Mapping[str, str]] = ...) -> None: ...
class UpdateJobStatus(_message.Message):
- __slots__ = ("job_id", "status", "error", "metadata", "load")
+ __slots__ = ("job_id", "status", "error")
JOB_ID_FIELD_NUMBER: _ClassVar[int]
STATUS_FIELD_NUMBER: _ClassVar[int]
ERROR_FIELD_NUMBER: _ClassVar[int]
- METADATA_FIELD_NUMBER: _ClassVar[int]
- LOAD_FIELD_NUMBER: _ClassVar[int]
job_id: str
status: JobStatus
error: str
- metadata: str
- load: float
- def __init__(self, job_id: _Optional[str] = ..., status: _Optional[_Union[JobStatus, str]] = ..., error: _Optional[str] = ..., metadata: _Optional[str] = ..., load: _Optional[float] = ...) -> None: ...
+ def __init__(self, job_id: _Optional[str] = ..., status: _Optional[_Union[JobStatus, str]] = ..., error: _Optional[str] = ...) -> None: ...
class UpdateWorkerStatus(_message.Message):
- __slots__ = ("status", "metadata", "load")
+ __slots__ = ("status", "load", "job_count")
STATUS_FIELD_NUMBER: _ClassVar[int]
- METADATA_FIELD_NUMBER: _ClassVar[int]
LOAD_FIELD_NUMBER: _ClassVar[int]
+ JOB_COUNT_FIELD_NUMBER: _ClassVar[int]
status: WorkerStatus
- metadata: str
load: float
- def __init__(self, status: _Optional[_Union[WorkerStatus, str]] = ..., metadata: _Optional[str] = ..., load: _Optional[float] = ...) -> None: ...
+ job_count: int
+ def __init__(self, status: _Optional[_Union[WorkerStatus, str]] = ..., load: _Optional[float] = ..., job_count: _Optional[int] = ...) -> None: ...
class JobAssignment(_message.Message):
__slots__ = ("job", "url", "token")
@@ -210,3 +229,9 @@ class JobAssignment(_message.Message):
url: str
token: str
def __init__(self, job: _Optional[_Union[Job, _Mapping]] = ..., url: _Optional[str] = ..., token: _Optional[str] = ...) -> None: ...
+
+class JobTermination(_message.Message):
+ __slots__ = ("job_id",)
+ JOB_ID_FIELD_NUMBER: _ClassVar[int]
+ job_id: str
+ def __init__(self, job_id: _Optional[str] = ...) -> None: ...
diff --git a/livekit-protocol/livekit/protocol/agent_dispatch.py b/livekit-protocol/livekit/protocol/agent_dispatch.py
new file mode 100644
index 00000000..49a2109d
--- /dev/null
+++ b/livekit-protocol/livekit/protocol/agent_dispatch.py
@@ -0,0 +1,55 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: livekit_agent_dispatch.proto
+# Protobuf Python Version: 4.25.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from . import agent as _agent_
+from .logger_pb import options as logger_dot_options__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1clivekit_agent_dispatch.proto\x12\x07livekit\x1a\x13livekit_agent.proto\x1a\x14logger/options.proto\"\x88\x01\n\x1a\x43reateAgentDispatchRequest\x12\x12\n\nagent_name\x18\x01 \x01(\t\x12\x0c\n\x04room\x18\x02 \x01(\t\x12\x15\n\x08metadata\x18\x03 \x01(\tB\x03\xa8P\x01\x12\x31\n\x0erestart_policy\x18\x04 \x01(\x0e\x32\x19.livekit.JobRestartPolicy\"q\n\x11RoomAgentDispatch\x12\x12\n\nagent_name\x18\x01 \x01(\t\x12\x15\n\x08metadata\x18\x02 \x01(\tB\x03\xa8P\x01\x12\x31\n\x0erestart_policy\x18\x03 \x01(\x0e\x32\x19.livekit.JobRestartPolicy\"N\n\x1a\x44\x65leteAgentDispatchRequest\x12\"\n\x0b\x64ispatch_id\x18\x01 \x01(\tB\r\xbaP\ndispatchID\x12\x0c\n\x04room\x18\x02 \x01(\t\"L\n\x18ListAgentDispatchRequest\x12\"\n\x0b\x64ispatch_id\x18\x01 \x01(\tB\r\xbaP\ndispatchID\x12\x0c\n\x04room\x18\x02 \x01(\t\"M\n\x19ListAgentDispatchResponse\x12\x30\n\x10\x61gent_dispatches\x18\x01 \x03(\x0b\x32\x16.livekit.AgentDispatch\"\xb3\x01\n\rAgentDispatch\x12\n\n\x02id\x18\x01 \x01(\t\x12\x12\n\nagent_name\x18\x02 \x01(\t\x12\x0c\n\x04room\x18\x03 \x01(\t\x12\x15\n\x08metadata\x18\x04 \x01(\tB\x03\xa8P\x01\x12*\n\x05state\x18\x05 \x01(\x0b\x32\x1b.livekit.AgentDispatchState\x12\x31\n\x0erestart_policy\x18\x06 \x01(\x0e\x32\x19.livekit.JobRestartPolicy\"X\n\x12\x41gentDispatchState\x12\x1a\n\x04jobs\x18\x01 \x03(\x0b\x32\x0c.livekit.Job\x12\x12\n\ncreated_at\x18\x02 \x01(\x03\x12\x12\n\ndeleted_at\x18\x03 \x01(\x03*5\n\x10JobRestartPolicy\x12\x12\n\x0eJRP_ON_FAILURE\x10\x00\x12\r\n\tJRP_NEVER\x10\x01\x32\x8b\x02\n\x14\x41gentDispatchService\x12M\n\x0e\x43reateDispatch\x12#.livekit.CreateAgentDispatchRequest\x1a\x16.livekit.AgentDispatch\x12M\n\x0e\x44\x65leteDispatch\x12#.livekit.DeleteAgentDispatchRequest\x1a\x16.livekit.AgentDispatch\x12U\n\x0cListDispatch\x12!.livekit.ListAgentDispatchRequest\x1a\".livekit.ListAgentDispatchResponseBFZ#github.com/livekit/protocol/livekit\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'agent_dispatch', _globals)
+if _descriptor._USE_C_DESCRIPTORS == False:
+ _globals['DESCRIPTOR']._options = None
+ _globals['DESCRIPTOR']._serialized_options = b'Z#github.com/livekit/protocol/livekit\252\002\rLiveKit.Proto\352\002\016LiveKit::Proto'
+ _globals['_CREATEAGENTDISPATCHREQUEST'].fields_by_name['metadata']._options = None
+ _globals['_CREATEAGENTDISPATCHREQUEST'].fields_by_name['metadata']._serialized_options = b'\250P\001'
+ _globals['_ROOMAGENTDISPATCH'].fields_by_name['metadata']._options = None
+ _globals['_ROOMAGENTDISPATCH'].fields_by_name['metadata']._serialized_options = b'\250P\001'
+ _globals['_DELETEAGENTDISPATCHREQUEST'].fields_by_name['dispatch_id']._options = None
+ _globals['_DELETEAGENTDISPATCHREQUEST'].fields_by_name['dispatch_id']._serialized_options = b'\272P\ndispatchID'
+ _globals['_LISTAGENTDISPATCHREQUEST'].fields_by_name['dispatch_id']._options = None
+ _globals['_LISTAGENTDISPATCHREQUEST'].fields_by_name['dispatch_id']._serialized_options = b'\272P\ndispatchID'
+ _globals['_AGENTDISPATCH'].fields_by_name['metadata']._options = None
+ _globals['_AGENTDISPATCH'].fields_by_name['metadata']._serialized_options = b'\250P\001'
+ _globals['_JOBRESTARTPOLICY']._serialized_start=847
+ _globals['_JOBRESTARTPOLICY']._serialized_end=900
+ _globals['_CREATEAGENTDISPATCHREQUEST']._serialized_start=85
+ _globals['_CREATEAGENTDISPATCHREQUEST']._serialized_end=221
+ _globals['_ROOMAGENTDISPATCH']._serialized_start=223
+ _globals['_ROOMAGENTDISPATCH']._serialized_end=336
+ _globals['_DELETEAGENTDISPATCHREQUEST']._serialized_start=338
+ _globals['_DELETEAGENTDISPATCHREQUEST']._serialized_end=416
+ _globals['_LISTAGENTDISPATCHREQUEST']._serialized_start=418
+ _globals['_LISTAGENTDISPATCHREQUEST']._serialized_end=494
+ _globals['_LISTAGENTDISPATCHRESPONSE']._serialized_start=496
+ _globals['_LISTAGENTDISPATCHRESPONSE']._serialized_end=573
+ _globals['_AGENTDISPATCH']._serialized_start=576
+ _globals['_AGENTDISPATCH']._serialized_end=755
+ _globals['_AGENTDISPATCHSTATE']._serialized_start=757
+ _globals['_AGENTDISPATCHSTATE']._serialized_end=845
+ _globals['_AGENTDISPATCHSERVICE']._serialized_start=903
+ _globals['_AGENTDISPATCHSERVICE']._serialized_end=1170
+# @@protoc_insertion_point(module_scope)
diff --git a/livekit-protocol/livekit/protocol/agent_dispatch.pyi b/livekit-protocol/livekit/protocol/agent_dispatch.pyi
new file mode 100644
index 00000000..35ecdd48
--- /dev/null
+++ b/livekit-protocol/livekit/protocol/agent_dispatch.pyi
@@ -0,0 +1,86 @@
+from . import agent as _agent
+from .logger_pb import options as _options_pb2
+from google.protobuf.internal import containers as _containers
+from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union
+
+DESCRIPTOR: _descriptor.FileDescriptor
+
+class JobRestartPolicy(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ JRP_ON_FAILURE: _ClassVar[JobRestartPolicy]
+ JRP_NEVER: _ClassVar[JobRestartPolicy]
+JRP_ON_FAILURE: JobRestartPolicy
+JRP_NEVER: JobRestartPolicy
+
+class CreateAgentDispatchRequest(_message.Message):
+ __slots__ = ("agent_name", "room", "metadata", "restart_policy")
+ AGENT_NAME_FIELD_NUMBER: _ClassVar[int]
+ ROOM_FIELD_NUMBER: _ClassVar[int]
+ METADATA_FIELD_NUMBER: _ClassVar[int]
+ RESTART_POLICY_FIELD_NUMBER: _ClassVar[int]
+ agent_name: str
+ room: str
+ metadata: str
+ restart_policy: JobRestartPolicy
+ def __init__(self, agent_name: _Optional[str] = ..., room: _Optional[str] = ..., metadata: _Optional[str] = ..., restart_policy: _Optional[_Union[JobRestartPolicy, str]] = ...) -> None: ...
+
+class RoomAgentDispatch(_message.Message):
+ __slots__ = ("agent_name", "metadata", "restart_policy")
+ AGENT_NAME_FIELD_NUMBER: _ClassVar[int]
+ METADATA_FIELD_NUMBER: _ClassVar[int]
+ RESTART_POLICY_FIELD_NUMBER: _ClassVar[int]
+ agent_name: str
+ metadata: str
+ restart_policy: JobRestartPolicy
+ def __init__(self, agent_name: _Optional[str] = ..., metadata: _Optional[str] = ..., restart_policy: _Optional[_Union[JobRestartPolicy, str]] = ...) -> None: ...
+
+class DeleteAgentDispatchRequest(_message.Message):
+ __slots__ = ("dispatch_id", "room")
+ DISPATCH_ID_FIELD_NUMBER: _ClassVar[int]
+ ROOM_FIELD_NUMBER: _ClassVar[int]
+ dispatch_id: str
+ room: str
+ def __init__(self, dispatch_id: _Optional[str] = ..., room: _Optional[str] = ...) -> None: ...
+
+class ListAgentDispatchRequest(_message.Message):
+ __slots__ = ("dispatch_id", "room")
+ DISPATCH_ID_FIELD_NUMBER: _ClassVar[int]
+ ROOM_FIELD_NUMBER: _ClassVar[int]
+ dispatch_id: str
+ room: str
+ def __init__(self, dispatch_id: _Optional[str] = ..., room: _Optional[str] = ...) -> None: ...
+
+class ListAgentDispatchResponse(_message.Message):
+ __slots__ = ("agent_dispatches",)
+ AGENT_DISPATCHES_FIELD_NUMBER: _ClassVar[int]
+ agent_dispatches: _containers.RepeatedCompositeFieldContainer[AgentDispatch]
+ def __init__(self, agent_dispatches: _Optional[_Iterable[_Union[AgentDispatch, _Mapping]]] = ...) -> None: ...
+
+class AgentDispatch(_message.Message):
+ __slots__ = ("id", "agent_name", "room", "metadata", "state", "restart_policy")
+ ID_FIELD_NUMBER: _ClassVar[int]
+ AGENT_NAME_FIELD_NUMBER: _ClassVar[int]
+ ROOM_FIELD_NUMBER: _ClassVar[int]
+ METADATA_FIELD_NUMBER: _ClassVar[int]
+ STATE_FIELD_NUMBER: _ClassVar[int]
+ RESTART_POLICY_FIELD_NUMBER: _ClassVar[int]
+ id: str
+ agent_name: str
+ room: str
+ metadata: str
+ state: AgentDispatchState
+ restart_policy: JobRestartPolicy
+ def __init__(self, id: _Optional[str] = ..., agent_name: _Optional[str] = ..., room: _Optional[str] = ..., metadata: _Optional[str] = ..., state: _Optional[_Union[AgentDispatchState, _Mapping]] = ..., restart_policy: _Optional[_Union[JobRestartPolicy, str]] = ...) -> None: ...
+
+class AgentDispatchState(_message.Message):
+ __slots__ = ("jobs", "created_at", "deleted_at")
+ JOBS_FIELD_NUMBER: _ClassVar[int]
+ CREATED_AT_FIELD_NUMBER: _ClassVar[int]
+ DELETED_AT_FIELD_NUMBER: _ClassVar[int]
+ jobs: _containers.RepeatedCompositeFieldContainer[_agent.Job]
+ created_at: int
+ deleted_at: int
+ def __init__(self, jobs: _Optional[_Iterable[_Union[_agent.Job, _Mapping]]] = ..., created_at: _Optional[int] = ..., deleted_at: _Optional[int] = ...) -> None: ...
diff --git a/livekit-protocol/livekit/protocol/agent_pb/__init__.py b/livekit-protocol/livekit/protocol/agent_pb/__init__.py
new file mode 100644
index 00000000..a2404969
--- /dev/null
+++ b/livekit-protocol/livekit/protocol/agent_pb/__init__.py
@@ -0,0 +1 @@
+from . import agent_dev, agent_session, agent_text, agent_inference
diff --git a/livekit-protocol/livekit/protocol/agent_pb/agent_dev.py b/livekit-protocol/livekit/protocol/agent_pb/agent_dev.py
new file mode 100644
index 00000000..215aa7a4
--- /dev/null
+++ b/livekit-protocol/livekit/protocol/agent_pb/agent_dev.py
@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: agent/livekit_agent_dev.proto
+# Protobuf Python Version: 4.25.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1d\x61gent/livekit_agent_dev.proto\x12\rlivekit.agent\"\xbc\x01\n\x0f\x41gentDevMessage\x12M\n\x18get_running_jobs_request\x18\x01 \x01(\x0b\x32).livekit.agent.GetRunningAgentJobsRequestH\x00\x12O\n\x19get_running_jobs_response\x18\x02 \x01(\x0b\x32*.livekit.agent.GetRunningAgentJobsResponseH\x00\x42\t\n\x07message\"\x1c\n\x1aGetRunningAgentJobsRequest\"O\n\x1bGetRunningAgentJobsResponse\x12\x30\n\x04jobs\x18\x01 \x03(\x0b\x32\".livekit.agent.RunningAgentJobInfo\"\xaa\x01\n\x13RunningAgentJobInfo\x12\x0b\n\x03job\x18\x01 \x01(\x0c\x12\x13\n\x0b\x61\x63\x63\x65pt_name\x18\x02 \x01(\t\x12\x17\n\x0f\x61\x63\x63\x65pt_identity\x18\x03 \x01(\t\x12\x17\n\x0f\x61\x63\x63\x65pt_metadata\x18\x04 \x01(\t\x12\x0b\n\x03url\x18\x05 \x01(\t\x12\r\n\x05token\x18\x06 \x01(\t\x12\x11\n\tworker_id\x18\x07 \x01(\t\x12\x10\n\x08mock_job\x18\x08 \x01(\x08\x42+Z)github.com/livekit/protocol/livekit/agentb\x06proto3')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'agent.agent_dev', _globals)
+if _descriptor._USE_C_DESCRIPTORS == False:
+ _globals['DESCRIPTOR']._options = None
+ _globals['DESCRIPTOR']._serialized_options = b'Z)github.com/livekit/protocol/livekit/agent'
+ _globals['_AGENTDEVMESSAGE']._serialized_start=49
+ _globals['_AGENTDEVMESSAGE']._serialized_end=237
+ _globals['_GETRUNNINGAGENTJOBSREQUEST']._serialized_start=239
+ _globals['_GETRUNNINGAGENTJOBSREQUEST']._serialized_end=267
+ _globals['_GETRUNNINGAGENTJOBSRESPONSE']._serialized_start=269
+ _globals['_GETRUNNINGAGENTJOBSRESPONSE']._serialized_end=348
+ _globals['_RUNNINGAGENTJOBINFO']._serialized_start=351
+ _globals['_RUNNINGAGENTJOBINFO']._serialized_end=521
+# @@protoc_insertion_point(module_scope)
diff --git a/livekit-protocol/livekit/protocol/agent_pb/agent_dev.pyi b/livekit-protocol/livekit/protocol/agent_pb/agent_dev.pyi
new file mode 100644
index 00000000..2929222f
--- /dev/null
+++ b/livekit-protocol/livekit/protocol/agent_pb/agent_dev.pyi
@@ -0,0 +1,44 @@
+from google.protobuf.internal import containers as _containers
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union
+
+DESCRIPTOR: _descriptor.FileDescriptor
+
+class AgentDevMessage(_message.Message):
+ __slots__ = ("get_running_jobs_request", "get_running_jobs_response")
+ GET_RUNNING_JOBS_REQUEST_FIELD_NUMBER: _ClassVar[int]
+ GET_RUNNING_JOBS_RESPONSE_FIELD_NUMBER: _ClassVar[int]
+ get_running_jobs_request: GetRunningAgentJobsRequest
+ get_running_jobs_response: GetRunningAgentJobsResponse
+ def __init__(self, get_running_jobs_request: _Optional[_Union[GetRunningAgentJobsRequest, _Mapping]] = ..., get_running_jobs_response: _Optional[_Union[GetRunningAgentJobsResponse, _Mapping]] = ...) -> None: ...
+
+class GetRunningAgentJobsRequest(_message.Message):
+ __slots__ = ()
+ def __init__(self) -> None: ...
+
+class GetRunningAgentJobsResponse(_message.Message):
+ __slots__ = ("jobs",)
+ JOBS_FIELD_NUMBER: _ClassVar[int]
+ jobs: _containers.RepeatedCompositeFieldContainer[RunningAgentJobInfo]
+ def __init__(self, jobs: _Optional[_Iterable[_Union[RunningAgentJobInfo, _Mapping]]] = ...) -> None: ...
+
+class RunningAgentJobInfo(_message.Message):
+ __slots__ = ("job", "accept_name", "accept_identity", "accept_metadata", "url", "token", "worker_id", "mock_job")
+ JOB_FIELD_NUMBER: _ClassVar[int]
+ ACCEPT_NAME_FIELD_NUMBER: _ClassVar[int]
+ ACCEPT_IDENTITY_FIELD_NUMBER: _ClassVar[int]
+ ACCEPT_METADATA_FIELD_NUMBER: _ClassVar[int]
+ URL_FIELD_NUMBER: _ClassVar[int]
+ TOKEN_FIELD_NUMBER: _ClassVar[int]
+ WORKER_ID_FIELD_NUMBER: _ClassVar[int]
+ MOCK_JOB_FIELD_NUMBER: _ClassVar[int]
+ job: bytes
+ accept_name: str
+ accept_identity: str
+ accept_metadata: str
+ url: str
+ token: str
+ worker_id: str
+ mock_job: bool
+ def __init__(self, job: _Optional[bytes] = ..., accept_name: _Optional[str] = ..., accept_identity: _Optional[str] = ..., accept_metadata: _Optional[str] = ..., url: _Optional[str] = ..., token: _Optional[str] = ..., worker_id: _Optional[str] = ..., mock_job: bool = ...) -> None: ...
diff --git a/livekit-protocol/livekit/protocol/agent_pb/agent_inference.py b/livekit-protocol/livekit/protocol/agent_pb/agent_inference.py
new file mode 100644
index 00000000..e07eaf2d
--- /dev/null
+++ b/livekit-protocol/livekit/protocol/agent_pb/agent_inference.py
@@ -0,0 +1,88 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: agent/livekit_agent_inference.proto
+# Protobuf Python Version: 4.25.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from . import agent_session as agent_dot__agent__session_
+from google.protobuf import duration_pb2 as google_dot_protobuf_dot_duration__pb2
+from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n#agent/livekit_agent_inference.proto\x12\rlivekit.agent\x1a!agent/livekit_agent_session.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xe1\x01\n\x0fSessionSettings\x12\x13\n\x0bsample_rate\x18\x01 \x01(\r\x12.\n\x08\x65ncoding\x18\x02 \x01(\x0e\x32\x1c.livekit.agent.AudioEncoding\x12\x32\n\x0c\x65ot_settings\x18\x03 \x01(\x0b\x32\x1a.livekit.agent.EotSettingsH\x00\x12\x44\n\x15interruption_settings\x18\x04 \x01(\x0b\x32#.livekit.agent.InterruptionSettingsH\x00\x42\x0f\n\rtype_settings\"/\n\x0eInferenceError\x12\x0f\n\x07message\x18\x01 \x01(\t\x12\x0c\n\x04\x63ode\x18\x02 \x01(\r\"D\n\x0b\x45otSettings\x12\x35\n\x12\x64\x65tection_interval\x18\x01 \x01(\x0b\x32\x19.google.protobuf.Duration\"\xe5\x01\n\x14InterruptionSettings\x12\x11\n\tthreshold\x18\x01 \x01(\x02\x12\x12\n\nmin_frames\x18\x02 \x01(\r\x12\x35\n\x12max_audio_duration\x18\x03 \x01(\x0b\x32\x19.google.protobuf.Duration\x12\x38\n\x15\x61udio_prefix_duration\x18\x04 \x01(\x0b\x32\x19.google.protobuf.Duration\x12\x35\n\x12\x64\x65tection_interval\x18\x05 \x01(\x0b\x32\x19.google.protobuf.Duration\"A\n\rSessionCreate\x12\x30\n\x08settings\x18\x01 \x01(\x0b\x32\x1e.livekit.agent.SessionSettings\"`\n\nInputAudio\x12\r\n\x05\x61udio\x18\x01 \x01(\x0c\x12.\n\ncreated_at\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x13\n\x0bnum_samples\x18\x03 \x01(\r\"C\n\x13\x45otInputChatContext\x12,\n\x08messages\x18\x01 \x03(\x0b\x32\x1a.livekit.agent.ChatMessage\"\x0e\n\x0cSessionFlush\"\x0e\n\x0cSessionClose\"$\n\x0eInferenceStart\x12\x12\n\nrequest_id\x18\x01 \x01(\t\"#\n\rInferenceStop\x12\x12\n\nrequest_id\x18\x01 \x01(\t\"\r\n\x0b\x42ufferStart\"\x0c\n\nBufferStop\"\xbe\x04\n\rClientMessage\x12.\n\ncreated_at\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x36\n\x0esession_create\x18\x02 \x01(\x0b\x32\x1c.livekit.agent.SessionCreateH\x00\x12\x30\n\x0binput_audio\x18\x03 \x01(\x0b\x32\x19.livekit.agent.InputAudioH\x00\x12\x34\n\rsession_flush\x18\x04 \x01(\x0b\x32\x1b.livekit.agent.SessionFlushH\x00\x12\x34\n\rsession_close\x18\x05 \x01(\x0b\x32\x1b.livekit.agent.SessionCloseH\x00\x12\x38\n\x0finference_start\x18\x06 \x01(\x0b\x32\x1d.livekit.agent.InferenceStartH\x00\x12\x36\n\x0einference_stop\x18\x07 \x01(\x0b\x32\x1c.livekit.agent.InferenceStopH\x00\x12\x32\n\x0c\x62uffer_start\x18\x08 \x01(\x0b\x32\x1a.livekit.agent.BufferStartH\x00\x12\x30\n\x0b\x62uffer_stop\x18\t \x01(\x0b\x32\x19.livekit.agent.BufferStopH\x00\x12\x44\n\x16\x65ot_input_chat_context\x18\n \x01(\x0b\x32\".livekit.agent.EotInputChatContextH\x00\x42\t\n\x07message\"\x81\x01\n\x13\x45otInferenceRequest\x12\r\n\x05\x61udio\x18\x01 \x01(\x0c\x12\x16\n\x0e\x61ssistant_text\x18\x02 \x01(\t\x12.\n\x08\x65ncoding\x18\x03 \x01(\x0e\x32\x1c.livekit.agent.AudioEncoding\x12\x13\n\x0bsample_rate\x18\x04 \x01(\r\"r\n\x1cInterruptionInferenceRequest\x12\r\n\x05\x61udio\x18\x01 \x01(\x0c\x12.\n\x08\x65ncoding\x18\x02 \x01(\x0e\x32\x1c.livekit.agent.AudioEncoding\x12\x13\n\x0bsample_rate\x18\x03 \x01(\r\"\xb9\x01\n\x10InferenceRequest\x12\x43\n\x15\x65ot_inference_request\x18\x01 \x01(\x0b\x32\".livekit.agent.EotInferenceRequestH\x00\x12U\n\x1einterruption_inference_request\x18\x02 \x01(\x0b\x32+.livekit.agent.InterruptionInferenceRequestH\x00\x42\t\n\x07request\"\xd0\x03\n\x0eInferenceStats\x12\x43\n\x1a\x65\x61rliest_client_created_at\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00\x88\x01\x01\x12\x41\n\x18latest_client_created_at\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x01\x88\x01\x01\x12:\n\x12\x63lient_e2e_latency\x18\x03 \x01(\x0b\x32\x19.google.protobuf.DurationH\x02\x88\x01\x01\x12\x35\n\x12server_e2e_latency\x18\x04 \x01(\x0b\x32\x19.google.protobuf.Duration\x12\x39\n\x16preprocessing_duration\x18\x05 \x01(\x0b\x32\x19.google.protobuf.Duration\x12\x35\n\x12inference_duration\x18\x06 \x01(\x0b\x32\x19.google.protobuf.DurationB\x1d\n\x1b_earliest_client_created_atB\x1b\n\x19_latest_client_created_atB\x15\n\x13_client_e2e_latency\"Y\n\x14\x45otInferenceResponse\x12\x13\n\x0bprobability\x18\x01 \x01(\x02\x12,\n\x05stats\x18\x02 \x01(\x0b\x32\x1d.livekit.agent.InferenceStats\"}\n\x1dInterruptionInferenceResponse\x12\x17\n\x0fis_interruption\x18\x01 \x01(\x08\x12\x15\n\rprobabilities\x18\x02 \x03(\x02\x12,\n\x05stats\x18\x03 \x01(\x0b\x32\x1d.livekit.agent.InferenceStats\"\xbf\x01\n\x11InferenceResponse\x12\x45\n\x16\x65ot_inference_response\x18\x01 \x01(\x0b\x32#.livekit.agent.EotInferenceResponseH\x00\x12W\n\x1finterruption_inference_response\x18\x02 \x01(\x0b\x32,.livekit.agent.InterruptionInferenceResponseH\x00\x42\n\n\x08response\"\x10\n\x0eSessionCreated\"\x12\n\x10InferenceStarted\"\x12\n\x10InferenceStopped\"\x0f\n\rSessionClosed\"\xef\x01\n\rEotPrediction\x12\x13\n\x0bprobability\x18\x01 \x01(\x02\x12\x36\n\x0finference_stats\x18\x02 \x01(\x0b\x32\x1d.livekit.agent.InferenceStats\x12\x38\n\x07\x62\x61\x63kend\x18\x03 \x01(\x0e\x32\'.livekit.agent.EotPrediction.EotBackend\"W\n\nEotBackend\x12\x17\n\x13\x45OT_BACKEND_UNKNOWN\x10\x00\x12\x1a\n\x16\x45OT_BACKEND_MULTIMODAL\x10\x01\x12\x14\n\x10\x45OT_BACKEND_TEXT\x10\x02\"\x80\x01\n\x16InterruptionPrediction\x12\x17\n\x0fis_interruption\x18\x01 \x01(\x08\x12\x15\n\rprobabilities\x18\x02 \x03(\x02\x12\x36\n\x0finference_stats\x18\x03 \x01(\x0b\x32\x1d.livekit.agent.InferenceStats\"\xeb\x04\n\rServerMessage\x12\x35\n\x11server_created_at\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x17\n\nrequest_id\x18\x02 \x01(\tH\x01\x88\x01\x01\x12:\n\x11\x63lient_created_at\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x02\x88\x01\x01\x12\x38\n\x0fsession_created\x18\x04 \x01(\x0b\x32\x1d.livekit.agent.SessionCreatedH\x00\x12<\n\x11inference_started\x18\x05 \x01(\x0b\x32\x1f.livekit.agent.InferenceStartedH\x00\x12<\n\x11inference_stopped\x18\x06 \x01(\x0b\x32\x1f.livekit.agent.InferenceStoppedH\x00\x12\x36\n\x0esession_closed\x18\x07 \x01(\x0b\x32\x1c.livekit.agent.SessionClosedH\x00\x12.\n\x05\x65rror\x18\x08 \x01(\x0b\x32\x1d.livekit.agent.InferenceErrorH\x00\x12\x36\n\x0e\x65ot_prediction\x18\t \x01(\x0b\x32\x1c.livekit.agent.EotPredictionH\x00\x12H\n\x17interruption_prediction\x18\n \x01(\x0b\x32%.livekit.agent.InterruptionPredictionH\x00\x42\t\n\x07messageB\r\n\x0b_request_idB\x14\n\x12_client_created_at*F\n\rAudioEncoding\x12\x1c\n\x18\x41UDIO_ENCODING_PCM_S16LE\x10\x00\x12\x17\n\x13\x41UDIO_ENCODING_OPUS\x10\x01\x42NH\x01Z)github.com/livekit/protocol/livekit/agent\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'agent.agent_inference', _globals)
+if _descriptor._USE_C_DESCRIPTORS == False:
+ _globals['DESCRIPTOR']._options = None
+ _globals['DESCRIPTOR']._serialized_options = b'H\001Z)github.com/livekit/protocol/livekit/agent\252\002\rLiveKit.Proto\352\002\016LiveKit::Proto'
+ _globals['_AUDIOENCODING']._serialized_start=4065
+ _globals['_AUDIOENCODING']._serialized_end=4135
+ _globals['_SESSIONSETTINGS']._serialized_start=155
+ _globals['_SESSIONSETTINGS']._serialized_end=380
+ _globals['_INFERENCEERROR']._serialized_start=382
+ _globals['_INFERENCEERROR']._serialized_end=429
+ _globals['_EOTSETTINGS']._serialized_start=431
+ _globals['_EOTSETTINGS']._serialized_end=499
+ _globals['_INTERRUPTIONSETTINGS']._serialized_start=502
+ _globals['_INTERRUPTIONSETTINGS']._serialized_end=731
+ _globals['_SESSIONCREATE']._serialized_start=733
+ _globals['_SESSIONCREATE']._serialized_end=798
+ _globals['_INPUTAUDIO']._serialized_start=800
+ _globals['_INPUTAUDIO']._serialized_end=896
+ _globals['_EOTINPUTCHATCONTEXT']._serialized_start=898
+ _globals['_EOTINPUTCHATCONTEXT']._serialized_end=965
+ _globals['_SESSIONFLUSH']._serialized_start=967
+ _globals['_SESSIONFLUSH']._serialized_end=981
+ _globals['_SESSIONCLOSE']._serialized_start=983
+ _globals['_SESSIONCLOSE']._serialized_end=997
+ _globals['_INFERENCESTART']._serialized_start=999
+ _globals['_INFERENCESTART']._serialized_end=1035
+ _globals['_INFERENCESTOP']._serialized_start=1037
+ _globals['_INFERENCESTOP']._serialized_end=1072
+ _globals['_BUFFERSTART']._serialized_start=1074
+ _globals['_BUFFERSTART']._serialized_end=1087
+ _globals['_BUFFERSTOP']._serialized_start=1089
+ _globals['_BUFFERSTOP']._serialized_end=1101
+ _globals['_CLIENTMESSAGE']._serialized_start=1104
+ _globals['_CLIENTMESSAGE']._serialized_end=1678
+ _globals['_EOTINFERENCEREQUEST']._serialized_start=1681
+ _globals['_EOTINFERENCEREQUEST']._serialized_end=1810
+ _globals['_INTERRUPTIONINFERENCEREQUEST']._serialized_start=1812
+ _globals['_INTERRUPTIONINFERENCEREQUEST']._serialized_end=1926
+ _globals['_INFERENCEREQUEST']._serialized_start=1929
+ _globals['_INFERENCEREQUEST']._serialized_end=2114
+ _globals['_INFERENCESTATS']._serialized_start=2117
+ _globals['_INFERENCESTATS']._serialized_end=2581
+ _globals['_EOTINFERENCERESPONSE']._serialized_start=2583
+ _globals['_EOTINFERENCERESPONSE']._serialized_end=2672
+ _globals['_INTERRUPTIONINFERENCERESPONSE']._serialized_start=2674
+ _globals['_INTERRUPTIONINFERENCERESPONSE']._serialized_end=2799
+ _globals['_INFERENCERESPONSE']._serialized_start=2802
+ _globals['_INFERENCERESPONSE']._serialized_end=2993
+ _globals['_SESSIONCREATED']._serialized_start=2995
+ _globals['_SESSIONCREATED']._serialized_end=3011
+ _globals['_INFERENCESTARTED']._serialized_start=3013
+ _globals['_INFERENCESTARTED']._serialized_end=3031
+ _globals['_INFERENCESTOPPED']._serialized_start=3033
+ _globals['_INFERENCESTOPPED']._serialized_end=3051
+ _globals['_SESSIONCLOSED']._serialized_start=3053
+ _globals['_SESSIONCLOSED']._serialized_end=3068
+ _globals['_EOTPREDICTION']._serialized_start=3071
+ _globals['_EOTPREDICTION']._serialized_end=3310
+ _globals['_EOTPREDICTION_EOTBACKEND']._serialized_start=3223
+ _globals['_EOTPREDICTION_EOTBACKEND']._serialized_end=3310
+ _globals['_INTERRUPTIONPREDICTION']._serialized_start=3313
+ _globals['_INTERRUPTIONPREDICTION']._serialized_end=3441
+ _globals['_SERVERMESSAGE']._serialized_start=3444
+ _globals['_SERVERMESSAGE']._serialized_end=4063
+# @@protoc_insertion_point(module_scope)
diff --git a/livekit-protocol/livekit/protocol/agent_pb/agent_inference.pyi b/livekit-protocol/livekit/protocol/agent_pb/agent_inference.pyi
new file mode 100644
index 00000000..19fe0f84
--- /dev/null
+++ b/livekit-protocol/livekit/protocol/agent_pb/agent_inference.pyi
@@ -0,0 +1,271 @@
+from . import agent_session as _agent_session
+from google.protobuf import duration_pb2 as _duration_pb2
+from google.protobuf import timestamp_pb2 as _timestamp_pb2
+from google.protobuf.internal import containers as _containers
+from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union
+
+DESCRIPTOR: _descriptor.FileDescriptor
+
+class AudioEncoding(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ AUDIO_ENCODING_PCM_S16LE: _ClassVar[AudioEncoding]
+ AUDIO_ENCODING_OPUS: _ClassVar[AudioEncoding]
+AUDIO_ENCODING_PCM_S16LE: AudioEncoding
+AUDIO_ENCODING_OPUS: AudioEncoding
+
+class SessionSettings(_message.Message):
+ __slots__ = ("sample_rate", "encoding", "eot_settings", "interruption_settings")
+ SAMPLE_RATE_FIELD_NUMBER: _ClassVar[int]
+ ENCODING_FIELD_NUMBER: _ClassVar[int]
+ EOT_SETTINGS_FIELD_NUMBER: _ClassVar[int]
+ INTERRUPTION_SETTINGS_FIELD_NUMBER: _ClassVar[int]
+ sample_rate: int
+ encoding: AudioEncoding
+ eot_settings: EotSettings
+ interruption_settings: InterruptionSettings
+ def __init__(self, sample_rate: _Optional[int] = ..., encoding: _Optional[_Union[AudioEncoding, str]] = ..., eot_settings: _Optional[_Union[EotSettings, _Mapping]] = ..., interruption_settings: _Optional[_Union[InterruptionSettings, _Mapping]] = ...) -> None: ...
+
+class InferenceError(_message.Message):
+ __slots__ = ("message", "code")
+ MESSAGE_FIELD_NUMBER: _ClassVar[int]
+ CODE_FIELD_NUMBER: _ClassVar[int]
+ message: str
+ code: int
+ def __init__(self, message: _Optional[str] = ..., code: _Optional[int] = ...) -> None: ...
+
+class EotSettings(_message.Message):
+ __slots__ = ("detection_interval",)
+ DETECTION_INTERVAL_FIELD_NUMBER: _ClassVar[int]
+ detection_interval: _duration_pb2.Duration
+ def __init__(self, detection_interval: _Optional[_Union[_duration_pb2.Duration, _Mapping]] = ...) -> None: ...
+
+class InterruptionSettings(_message.Message):
+ __slots__ = ("threshold", "min_frames", "max_audio_duration", "audio_prefix_duration", "detection_interval")
+ THRESHOLD_FIELD_NUMBER: _ClassVar[int]
+ MIN_FRAMES_FIELD_NUMBER: _ClassVar[int]
+ MAX_AUDIO_DURATION_FIELD_NUMBER: _ClassVar[int]
+ AUDIO_PREFIX_DURATION_FIELD_NUMBER: _ClassVar[int]
+ DETECTION_INTERVAL_FIELD_NUMBER: _ClassVar[int]
+ threshold: float
+ min_frames: int
+ max_audio_duration: _duration_pb2.Duration
+ audio_prefix_duration: _duration_pb2.Duration
+ detection_interval: _duration_pb2.Duration
+ def __init__(self, threshold: _Optional[float] = ..., min_frames: _Optional[int] = ..., max_audio_duration: _Optional[_Union[_duration_pb2.Duration, _Mapping]] = ..., audio_prefix_duration: _Optional[_Union[_duration_pb2.Duration, _Mapping]] = ..., detection_interval: _Optional[_Union[_duration_pb2.Duration, _Mapping]] = ...) -> None: ...
+
+class SessionCreate(_message.Message):
+ __slots__ = ("settings",)
+ SETTINGS_FIELD_NUMBER: _ClassVar[int]
+ settings: SessionSettings
+ def __init__(self, settings: _Optional[_Union[SessionSettings, _Mapping]] = ...) -> None: ...
+
+class InputAudio(_message.Message):
+ __slots__ = ("audio", "created_at", "num_samples")
+ AUDIO_FIELD_NUMBER: _ClassVar[int]
+ CREATED_AT_FIELD_NUMBER: _ClassVar[int]
+ NUM_SAMPLES_FIELD_NUMBER: _ClassVar[int]
+ audio: bytes
+ created_at: _timestamp_pb2.Timestamp
+ num_samples: int
+ def __init__(self, audio: _Optional[bytes] = ..., created_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., num_samples: _Optional[int] = ...) -> None: ...
+
+class EotInputChatContext(_message.Message):
+ __slots__ = ("messages",)
+ MESSAGES_FIELD_NUMBER: _ClassVar[int]
+ messages: _containers.RepeatedCompositeFieldContainer[_agent_session.ChatMessage]
+ def __init__(self, messages: _Optional[_Iterable[_Union[_agent_session.ChatMessage, _Mapping]]] = ...) -> None: ...
+
+class SessionFlush(_message.Message):
+ __slots__ = ()
+ def __init__(self) -> None: ...
+
+class SessionClose(_message.Message):
+ __slots__ = ()
+ def __init__(self) -> None: ...
+
+class InferenceStart(_message.Message):
+ __slots__ = ("request_id",)
+ REQUEST_ID_FIELD_NUMBER: _ClassVar[int]
+ request_id: str
+ def __init__(self, request_id: _Optional[str] = ...) -> None: ...
+
+class InferenceStop(_message.Message):
+ __slots__ = ("request_id",)
+ REQUEST_ID_FIELD_NUMBER: _ClassVar[int]
+ request_id: str
+ def __init__(self, request_id: _Optional[str] = ...) -> None: ...
+
+class BufferStart(_message.Message):
+ __slots__ = ()
+ def __init__(self) -> None: ...
+
+class BufferStop(_message.Message):
+ __slots__ = ()
+ def __init__(self) -> None: ...
+
+class ClientMessage(_message.Message):
+ __slots__ = ("created_at", "session_create", "input_audio", "session_flush", "session_close", "inference_start", "inference_stop", "buffer_start", "buffer_stop", "eot_input_chat_context")
+ CREATED_AT_FIELD_NUMBER: _ClassVar[int]
+ SESSION_CREATE_FIELD_NUMBER: _ClassVar[int]
+ INPUT_AUDIO_FIELD_NUMBER: _ClassVar[int]
+ SESSION_FLUSH_FIELD_NUMBER: _ClassVar[int]
+ SESSION_CLOSE_FIELD_NUMBER: _ClassVar[int]
+ INFERENCE_START_FIELD_NUMBER: _ClassVar[int]
+ INFERENCE_STOP_FIELD_NUMBER: _ClassVar[int]
+ BUFFER_START_FIELD_NUMBER: _ClassVar[int]
+ BUFFER_STOP_FIELD_NUMBER: _ClassVar[int]
+ EOT_INPUT_CHAT_CONTEXT_FIELD_NUMBER: _ClassVar[int]
+ created_at: _timestamp_pb2.Timestamp
+ session_create: SessionCreate
+ input_audio: InputAudio
+ session_flush: SessionFlush
+ session_close: SessionClose
+ inference_start: InferenceStart
+ inference_stop: InferenceStop
+ buffer_start: BufferStart
+ buffer_stop: BufferStop
+ eot_input_chat_context: EotInputChatContext
+ def __init__(self, created_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., session_create: _Optional[_Union[SessionCreate, _Mapping]] = ..., input_audio: _Optional[_Union[InputAudio, _Mapping]] = ..., session_flush: _Optional[_Union[SessionFlush, _Mapping]] = ..., session_close: _Optional[_Union[SessionClose, _Mapping]] = ..., inference_start: _Optional[_Union[InferenceStart, _Mapping]] = ..., inference_stop: _Optional[_Union[InferenceStop, _Mapping]] = ..., buffer_start: _Optional[_Union[BufferStart, _Mapping]] = ..., buffer_stop: _Optional[_Union[BufferStop, _Mapping]] = ..., eot_input_chat_context: _Optional[_Union[EotInputChatContext, _Mapping]] = ...) -> None: ...
+
+class EotInferenceRequest(_message.Message):
+ __slots__ = ("audio", "assistant_text", "encoding", "sample_rate")
+ AUDIO_FIELD_NUMBER: _ClassVar[int]
+ ASSISTANT_TEXT_FIELD_NUMBER: _ClassVar[int]
+ ENCODING_FIELD_NUMBER: _ClassVar[int]
+ SAMPLE_RATE_FIELD_NUMBER: _ClassVar[int]
+ audio: bytes
+ assistant_text: str
+ encoding: AudioEncoding
+ sample_rate: int
+ def __init__(self, audio: _Optional[bytes] = ..., assistant_text: _Optional[str] = ..., encoding: _Optional[_Union[AudioEncoding, str]] = ..., sample_rate: _Optional[int] = ...) -> None: ...
+
+class InterruptionInferenceRequest(_message.Message):
+ __slots__ = ("audio", "encoding", "sample_rate")
+ AUDIO_FIELD_NUMBER: _ClassVar[int]
+ ENCODING_FIELD_NUMBER: _ClassVar[int]
+ SAMPLE_RATE_FIELD_NUMBER: _ClassVar[int]
+ audio: bytes
+ encoding: AudioEncoding
+ sample_rate: int
+ def __init__(self, audio: _Optional[bytes] = ..., encoding: _Optional[_Union[AudioEncoding, str]] = ..., sample_rate: _Optional[int] = ...) -> None: ...
+
+class InferenceRequest(_message.Message):
+ __slots__ = ("eot_inference_request", "interruption_inference_request")
+ EOT_INFERENCE_REQUEST_FIELD_NUMBER: _ClassVar[int]
+ INTERRUPTION_INFERENCE_REQUEST_FIELD_NUMBER: _ClassVar[int]
+ eot_inference_request: EotInferenceRequest
+ interruption_inference_request: InterruptionInferenceRequest
+ def __init__(self, eot_inference_request: _Optional[_Union[EotInferenceRequest, _Mapping]] = ..., interruption_inference_request: _Optional[_Union[InterruptionInferenceRequest, _Mapping]] = ...) -> None: ...
+
+class InferenceStats(_message.Message):
+ __slots__ = ("earliest_client_created_at", "latest_client_created_at", "client_e2e_latency", "server_e2e_latency", "preprocessing_duration", "inference_duration")
+ EARLIEST_CLIENT_CREATED_AT_FIELD_NUMBER: _ClassVar[int]
+ LATEST_CLIENT_CREATED_AT_FIELD_NUMBER: _ClassVar[int]
+ CLIENT_E2E_LATENCY_FIELD_NUMBER: _ClassVar[int]
+ SERVER_E2E_LATENCY_FIELD_NUMBER: _ClassVar[int]
+ PREPROCESSING_DURATION_FIELD_NUMBER: _ClassVar[int]
+ INFERENCE_DURATION_FIELD_NUMBER: _ClassVar[int]
+ earliest_client_created_at: _timestamp_pb2.Timestamp
+ latest_client_created_at: _timestamp_pb2.Timestamp
+ client_e2e_latency: _duration_pb2.Duration
+ server_e2e_latency: _duration_pb2.Duration
+ preprocessing_duration: _duration_pb2.Duration
+ inference_duration: _duration_pb2.Duration
+ def __init__(self, earliest_client_created_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., latest_client_created_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., client_e2e_latency: _Optional[_Union[_duration_pb2.Duration, _Mapping]] = ..., server_e2e_latency: _Optional[_Union[_duration_pb2.Duration, _Mapping]] = ..., preprocessing_duration: _Optional[_Union[_duration_pb2.Duration, _Mapping]] = ..., inference_duration: _Optional[_Union[_duration_pb2.Duration, _Mapping]] = ...) -> None: ...
+
+class EotInferenceResponse(_message.Message):
+ __slots__ = ("probability", "stats")
+ PROBABILITY_FIELD_NUMBER: _ClassVar[int]
+ STATS_FIELD_NUMBER: _ClassVar[int]
+ probability: float
+ stats: InferenceStats
+ def __init__(self, probability: _Optional[float] = ..., stats: _Optional[_Union[InferenceStats, _Mapping]] = ...) -> None: ...
+
+class InterruptionInferenceResponse(_message.Message):
+ __slots__ = ("is_interruption", "probabilities", "stats")
+ IS_INTERRUPTION_FIELD_NUMBER: _ClassVar[int]
+ PROBABILITIES_FIELD_NUMBER: _ClassVar[int]
+ STATS_FIELD_NUMBER: _ClassVar[int]
+ is_interruption: bool
+ probabilities: _containers.RepeatedScalarFieldContainer[float]
+ stats: InferenceStats
+ def __init__(self, is_interruption: bool = ..., probabilities: _Optional[_Iterable[float]] = ..., stats: _Optional[_Union[InferenceStats, _Mapping]] = ...) -> None: ...
+
+class InferenceResponse(_message.Message):
+ __slots__ = ("eot_inference_response", "interruption_inference_response")
+ EOT_INFERENCE_RESPONSE_FIELD_NUMBER: _ClassVar[int]
+ INTERRUPTION_INFERENCE_RESPONSE_FIELD_NUMBER: _ClassVar[int]
+ eot_inference_response: EotInferenceResponse
+ interruption_inference_response: InterruptionInferenceResponse
+ def __init__(self, eot_inference_response: _Optional[_Union[EotInferenceResponse, _Mapping]] = ..., interruption_inference_response: _Optional[_Union[InterruptionInferenceResponse, _Mapping]] = ...) -> None: ...
+
+class SessionCreated(_message.Message):
+ __slots__ = ()
+ def __init__(self) -> None: ...
+
+class InferenceStarted(_message.Message):
+ __slots__ = ()
+ def __init__(self) -> None: ...
+
+class InferenceStopped(_message.Message):
+ __slots__ = ()
+ def __init__(self) -> None: ...
+
+class SessionClosed(_message.Message):
+ __slots__ = ()
+ def __init__(self) -> None: ...
+
+class EotPrediction(_message.Message):
+ __slots__ = ("probability", "inference_stats", "backend")
+ class EotBackend(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ EOT_BACKEND_UNKNOWN: _ClassVar[EotPrediction.EotBackend]
+ EOT_BACKEND_MULTIMODAL: _ClassVar[EotPrediction.EotBackend]
+ EOT_BACKEND_TEXT: _ClassVar[EotPrediction.EotBackend]
+ EOT_BACKEND_UNKNOWN: EotPrediction.EotBackend
+ EOT_BACKEND_MULTIMODAL: EotPrediction.EotBackend
+ EOT_BACKEND_TEXT: EotPrediction.EotBackend
+ PROBABILITY_FIELD_NUMBER: _ClassVar[int]
+ INFERENCE_STATS_FIELD_NUMBER: _ClassVar[int]
+ BACKEND_FIELD_NUMBER: _ClassVar[int]
+ probability: float
+ inference_stats: InferenceStats
+ backend: EotPrediction.EotBackend
+ def __init__(self, probability: _Optional[float] = ..., inference_stats: _Optional[_Union[InferenceStats, _Mapping]] = ..., backend: _Optional[_Union[EotPrediction.EotBackend, str]] = ...) -> None: ...
+
+class InterruptionPrediction(_message.Message):
+ __slots__ = ("is_interruption", "probabilities", "inference_stats")
+ IS_INTERRUPTION_FIELD_NUMBER: _ClassVar[int]
+ PROBABILITIES_FIELD_NUMBER: _ClassVar[int]
+ INFERENCE_STATS_FIELD_NUMBER: _ClassVar[int]
+ is_interruption: bool
+ probabilities: _containers.RepeatedScalarFieldContainer[float]
+ inference_stats: InferenceStats
+ def __init__(self, is_interruption: bool = ..., probabilities: _Optional[_Iterable[float]] = ..., inference_stats: _Optional[_Union[InferenceStats, _Mapping]] = ...) -> None: ...
+
+class ServerMessage(_message.Message):
+ __slots__ = ("server_created_at", "request_id", "client_created_at", "session_created", "inference_started", "inference_stopped", "session_closed", "error", "eot_prediction", "interruption_prediction")
+ SERVER_CREATED_AT_FIELD_NUMBER: _ClassVar[int]
+ REQUEST_ID_FIELD_NUMBER: _ClassVar[int]
+ CLIENT_CREATED_AT_FIELD_NUMBER: _ClassVar[int]
+ SESSION_CREATED_FIELD_NUMBER: _ClassVar[int]
+ INFERENCE_STARTED_FIELD_NUMBER: _ClassVar[int]
+ INFERENCE_STOPPED_FIELD_NUMBER: _ClassVar[int]
+ SESSION_CLOSED_FIELD_NUMBER: _ClassVar[int]
+ ERROR_FIELD_NUMBER: _ClassVar[int]
+ EOT_PREDICTION_FIELD_NUMBER: _ClassVar[int]
+ INTERRUPTION_PREDICTION_FIELD_NUMBER: _ClassVar[int]
+ server_created_at: _timestamp_pb2.Timestamp
+ request_id: str
+ client_created_at: _timestamp_pb2.Timestamp
+ session_created: SessionCreated
+ inference_started: InferenceStarted
+ inference_stopped: InferenceStopped
+ session_closed: SessionClosed
+ error: InferenceError
+ eot_prediction: EotPrediction
+ interruption_prediction: InterruptionPrediction
+ def __init__(self, server_created_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., request_id: _Optional[str] = ..., client_created_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., session_created: _Optional[_Union[SessionCreated, _Mapping]] = ..., inference_started: _Optional[_Union[InferenceStarted, _Mapping]] = ..., inference_stopped: _Optional[_Union[InferenceStopped, _Mapping]] = ..., session_closed: _Optional[_Union[SessionClosed, _Mapping]] = ..., error: _Optional[_Union[InferenceError, _Mapping]] = ..., eot_prediction: _Optional[_Union[EotPrediction, _Mapping]] = ..., interruption_prediction: _Optional[_Union[InterruptionPrediction, _Mapping]] = ...) -> None: ...
diff --git a/livekit-protocol/livekit/protocol/agent_pb/agent_session.py b/livekit-protocol/livekit/protocol/agent_pb/agent_session.py
new file mode 100644
index 00000000..93bb1aaf
--- /dev/null
+++ b/livekit-protocol/livekit/protocol/agent_pb/agent_session.py
@@ -0,0 +1,148 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: agent/livekit_agent_session.proto
+# Protobuf Python Version: 4.25.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2
+from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
+from ..logger_pb import options as logger_dot_options__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n!agent/livekit_agent_session.proto\x12\rlivekit.agent\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x14logger/options.proto\"\xc3\x03\n\rMetricsReport\x12\x37\n\x13started_speaking_at\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x37\n\x13stopped_speaking_at\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12 \n\x13transcription_delay\x18\x03 \x01(\x01H\x00\x88\x01\x01\x12\x1e\n\x11\x65nd_of_turn_delay\x18\x04 \x01(\x01H\x01\x88\x01\x01\x12)\n\x1con_user_turn_completed_delay\x18\x05 \x01(\x01H\x02\x88\x01\x01\x12\x1a\n\rllm_node_ttft\x18\x06 \x01(\x01H\x03\x88\x01\x01\x12\x1a\n\rtts_node_ttfb\x18\x07 \x01(\x01H\x04\x88\x01\x01\x12\x18\n\x0b\x65\x32\x65_latency\x18\x08 \x01(\x01H\x05\x88\x01\x01\x42\x16\n\x14_transcription_delayB\x14\n\x12_end_of_turn_delayB\x1f\n\x1d_on_user_turn_completed_delayB\x10\n\x0e_llm_node_ttftB\x10\n\x0e_tts_node_ttfbB\x0e\n\x0c_e2e_latency\"\xed\x01\n\x0bTimedString\x12\x0c\n\x04text\x18\x01 \x01(\t\x12\x17\n\nstart_time\x18\x02 \x01(\x01H\x00\x88\x01\x01\x12\x15\n\x08\x65nd_time\x18\x03 \x01(\x01H\x01\x88\x01\x01\x12\x17\n\nconfidence\x18\x04 \x01(\x01H\x02\x88\x01\x01\x12\x1e\n\x11start_time_offset\x18\x05 \x01(\x01H\x03\x88\x01\x01\x12\x17\n\nspeaker_id\x18\x06 \x01(\tH\x04\x88\x01\x01\x42\r\n\x0b_start_timeB\x0b\n\t_end_timeB\r\n\x0b_confidenceB\x14\n\x12_start_time_offsetB\r\n\x0b_speaker_id\"\xb9\x03\n\x0b\x43hatMessage\x12\n\n\x02id\x18\x01 \x01(\t\x12%\n\x04role\x18\x02 \x01(\x0e\x32\x17.livekit.agent.ChatRole\x12\x37\n\x07\x63ontent\x18\x03 \x03(\x0b\x32&.livekit.agent.ChatMessage.ChatContent\x12\x13\n\x0binterrupted\x18\x04 \x01(\x08\x12\"\n\x15transcript_confidence\x18\x05 \x01(\x01H\x00\x88\x01\x01\x12\x34\n\x05\x65xtra\x18\x06 \x03(\x0b\x32%.livekit.agent.ChatMessage.ExtraEntry\x12-\n\x07metrics\x18\x07 \x01(\x0b\x32\x1c.livekit.agent.MetricsReport\x12.\n\ncreated_at\x18\x08 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x1a(\n\x0b\x43hatContent\x12\x0e\n\x04text\x18\x01 \x01(\tH\x00\x42\t\n\x07payload\x1a,\n\nExtraEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\x18\n\x16_transcript_confidence\"\x87\x01\n\x0c\x46unctionCall\x12\n\n\x02id\x18\x01 \x01(\t\x12\x1a\n\x07\x63\x61ll_id\x18\x02 \x01(\tB\t\xbaP\x06\x63\x61llID\x12\x11\n\targuments\x18\x03 \x01(\t\x12\x0c\n\x04name\x18\x04 \x01(\t\x12.\n\ncreated_at\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"\x9c\x01\n\x12\x46unctionCallOutput\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x1a\n\x07\x63\x61ll_id\x18\x03 \x01(\tB\t\xbaP\x06\x63\x61llID\x12\x0e\n\x06output\x18\x04 \x01(\t\x12\x10\n\x08is_error\x18\x05 \x01(\x08\x12.\n\ncreated_at\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"\xaa\x01\n\x0c\x41gentHandoff\x12\n\n\x02id\x18\x01 \x01(\t\x12(\n\x0cold_agent_id\x18\x02 \x01(\tB\r\xbaP\noldAgentIDH\x00\x88\x01\x01\x12#\n\x0cnew_agent_id\x18\x03 \x01(\tB\r\xbaP\nnewAgentID\x12.\n\ncreated_at\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.TimestampB\x0f\n\r_old_agent_id\"\xa7\x01\n\x11\x41gentConfigUpdate\x12\n\n\x02id\x18\x01 \x01(\t\x12\x19\n\x0cinstructions\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x0btools_added\x18\x03 \x03(\t\x12\x15\n\rtools_removed\x18\x04 \x03(\t\x12.\n\ncreated_at\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.TimestampB\x0f\n\r_instructions\"\xf5\x02\n\x0b\x43hatContext\x12\x32\n\x05items\x18\x01 \x03(\x0b\x32#.livekit.agent.ChatContext.ChatItem\x1a\xb1\x02\n\x08\x43hatItem\x12-\n\x07message\x18\x01 \x01(\x0b\x32\x1a.livekit.agent.ChatMessageH\x00\x12\x34\n\rfunction_call\x18\x02 \x01(\x0b\x32\x1b.livekit.agent.FunctionCallH\x00\x12\x41\n\x14\x66unction_call_output\x18\x03 \x01(\x0b\x32!.livekit.agent.FunctionCallOutputH\x00\x12\x34\n\ragent_handoff\x18\x04 \x01(\x0b\x32\x1b.livekit.agent.AgentHandoffH\x00\x12?\n\x13\x61gent_config_update\x18\x05 \x01(\x0b\x32 .livekit.agent.AgentConfigUpdateH\x00\x42\x06\n\x04item\"\x88\x03\n\rLLMModelUsage\x12\x10\n\x08provider\x18\x01 \x01(\t\x12\r\n\x05model\x18\x02 \x01(\t\x12\x14\n\x0cinput_tokens\x18\x03 \x01(\x05\x12\x1b\n\x13input_cached_tokens\x18\x04 \x01(\x05\x12\x1a\n\x12input_audio_tokens\x18\x05 \x01(\x05\x12!\n\x19input_cached_audio_tokens\x18\x06 \x01(\x05\x12\x19\n\x11input_text_tokens\x18\x07 \x01(\x05\x12 \n\x18input_cached_text_tokens\x18\x08 \x01(\x05\x12\x1a\n\x12input_image_tokens\x18\t \x01(\x05\x12!\n\x19input_cached_image_tokens\x18\n \x01(\x05\x12\x15\n\routput_tokens\x18\x0b \x01(\x05\x12\x1b\n\x13output_audio_tokens\x18\x0c \x01(\x05\x12\x1a\n\x12output_text_tokens\x18\r \x01(\x05\x12\x18\n\x10session_duration\x18\x0e \x01(\x01\"\x8f\x01\n\rTTSModelUsage\x12\x10\n\x08provider\x18\x01 \x01(\t\x12\r\n\x05model\x18\x02 \x01(\t\x12\x14\n\x0cinput_tokens\x18\x03 \x01(\x05\x12\x15\n\routput_tokens\x18\x04 \x01(\x05\x12\x18\n\x10\x63haracters_count\x18\x05 \x01(\x05\x12\x16\n\x0e\x61udio_duration\x18\x06 \x01(\x01\"u\n\rSTTModelUsage\x12\x10\n\x08provider\x18\x01 \x01(\t\x12\r\n\x05model\x18\x02 \x01(\t\x12\x14\n\x0cinput_tokens\x18\x03 \x01(\x05\x12\x15\n\routput_tokens\x18\x04 \x01(\x05\x12\x16\n\x0e\x61udio_duration\x18\x05 \x01(\x01\"Q\n\x16InterruptionModelUsage\x12\x10\n\x08provider\x18\x01 \x01(\t\x12\r\n\x05model\x18\x02 \x01(\t\x12\x16\n\x0etotal_requests\x18\x03 \x01(\x05\"\xdb\x01\n\nModelUsage\x12+\n\x03llm\x18\x01 \x01(\x0b\x32\x1c.livekit.agent.LLMModelUsageH\x00\x12+\n\x03tts\x18\x02 \x01(\x0b\x32\x1c.livekit.agent.TTSModelUsageH\x00\x12+\n\x03stt\x18\x03 \x01(\x0b\x32\x1c.livekit.agent.STTModelUsageH\x00\x12=\n\x0cinterruption\x18\x04 \x01(\x0b\x32%.livekit.agent.InterruptionModelUsageH\x00\x42\x07\n\x05usage\"C\n\x11\x41gentSessionUsage\x12.\n\x0bmodel_usage\x18\x01 \x03(\x0b\x32\x19.livekit.agent.ModelUsage\"\xae\x0c\n\x11\x41gentSessionEvent\x12.\n\ncreated_at\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12Q\n\x13\x61gent_state_changed\x18\n \x01(\x0b\x32\x32.livekit.agent.AgentSessionEvent.AgentStateChangedH\x00\x12O\n\x12user_state_changed\x18\x0b \x01(\x0b\x32\x31.livekit.agent.AgentSessionEvent.UserStateChangedH\x00\x12Y\n\x17\x63onversation_item_added\x18\x0c \x01(\x0b\x32\x36.livekit.agent.AgentSessionEvent.ConversationItemAddedH\x00\x12W\n\x16user_input_transcribed\x18\r \x01(\x0b\x32\x35.livekit.agent.AgentSessionEvent.UserInputTranscribedH\x00\x12Y\n\x17\x66unction_tools_executed\x18\x0e \x01(\x0b\x32\x36.livekit.agent.AgentSessionEvent.FunctionToolsExecutedH\x00\x12\x37\n\x05\x65rror\x18\x0f \x01(\x0b\x32&.livekit.agent.AgentSessionEvent.ErrorH\x00\x12P\n\x12overlapping_speech\x18\x10 \x01(\x0b\x32\x32.livekit.agent.AgentSessionEvent.OverlappingSpeechH\x00\x12U\n\x15session_usage_updated\x18\x11 \x01(\x0b\x32\x34.livekit.agent.AgentSessionEvent.SessionUsageUpdatedH\x00\x1ao\n\x11\x41gentStateChanged\x12,\n\told_state\x18\x01 \x01(\x0e\x32\x19.livekit.agent.AgentState\x12,\n\tnew_state\x18\x02 \x01(\x0e\x32\x19.livekit.agent.AgentState\x1al\n\x10UserStateChanged\x12+\n\told_state\x18\x01 \x01(\x0e\x32\x18.livekit.agent.UserState\x12+\n\tnew_state\x18\x02 \x01(\x0e\x32\x18.livekit.agent.UserState\x1aJ\n\x15\x43onversationItemAdded\x12\x31\n\x04item\x18\x01 \x01(\x0b\x32#.livekit.agent.ChatContext.ChatItem\x1a`\n\x14UserInputTranscribed\x12\x12\n\ntranscript\x18\x01 \x01(\t\x12\x10\n\x08is_final\x18\x02 \x01(\x08\x12\x15\n\x08language\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x0b\n\t_language\x1a\x8e\x01\n\x15\x46unctionToolsExecuted\x12\x33\n\x0e\x66unction_calls\x18\x01 \x03(\x0b\x32\x1b.livekit.agent.FunctionCall\x12@\n\x15\x66unction_call_outputs\x18\x02 \x03(\x0b\x32!.livekit.agent.FunctionCallOutput\x1a\x18\n\x05\x45rror\x12\x0f\n\x07message\x18\x01 \x01(\t\x1a\xca\x01\n\x11OverlappingSpeech\x12\x17\n\x0fis_interruption\x18\x01 \x01(\x08\x12;\n\x12overlap_started_at\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00\x88\x01\x01\x12\x17\n\x0f\x64\x65tection_delay\x18\x03 \x01(\x01\x12/\n\x0b\x64\x65tected_at\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.TimestampB\x15\n\x13_overlap_started_at\x1a\x46\n\x13SessionUsageUpdated\x12/\n\x05usage\x18\x01 \x01(\x0b\x32 .livekit.agent.AgentSessionUsageB\x07\n\x05\x65vent\"\xe7\x05\n\x0eSessionRequest\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12\x32\n\x04ping\x18\x02 \x01(\x0b\x32\".livekit.agent.SessionRequest.PingH\x00\x12H\n\x10get_chat_history\x18\x04 \x01(\x0b\x32,.livekit.agent.SessionRequest.GetChatHistoryH\x00\x12;\n\trun_input\x18\x05 \x01(\x0b\x32&.livekit.agent.SessionRequest.RunInputH\x00\x12\x44\n\x0eget_agent_info\x18\x06 \x01(\x0b\x32*.livekit.agent.SessionRequest.GetAgentInfoH\x00\x12J\n\x11get_session_state\x18\x07 \x01(\x0b\x32-.livekit.agent.SessionRequest.GetSessionStateH\x00\x12\x42\n\rget_rtc_stats\x18\x08 \x01(\x0b\x32).livekit.agent.SessionRequest.GetRTCStatsH\x00\x12J\n\x11get_session_usage\x18\t \x01(\x0b\x32-.livekit.agent.SessionRequest.GetSessionUsageH\x00\x12L\n\x12get_framework_info\x18\n \x01(\x0b\x32..livekit.agent.SessionRequest.GetFrameworkInfoH\x00\x1a\x06\n\x04Ping\x1a\x10\n\x0eGetChatHistory\x1a\x18\n\x08RunInput\x12\x0c\n\x04text\x18\x01 \x01(\t\x1a\x0e\n\x0cGetAgentInfo\x1a\x11\n\x0fGetSessionState\x1a\r\n\x0bGetRTCStats\x1a\x11\n\x0fGetSessionUsage\x1a\x12\n\x10GetFrameworkInfoB\t\n\x07request\"\xe7\x0c\n\x0fSessionResponse\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12\x12\n\x05\x65rror\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x33\n\x04pong\x18\x03 \x01(\x0b\x32#.livekit.agent.SessionResponse.PongH\x00\x12Q\n\x10get_chat_history\x18\x05 \x01(\x0b\x32\x35.livekit.agent.SessionResponse.GetChatHistoryResponseH\x00\x12\x44\n\trun_input\x18\x06 \x01(\x0b\x32/.livekit.agent.SessionResponse.RunInputResponseH\x00\x12M\n\x0eget_agent_info\x18\x07 \x01(\x0b\x32\x33.livekit.agent.SessionResponse.GetAgentInfoResponseH\x00\x12S\n\x11get_session_state\x18\x08 \x01(\x0b\x32\x36.livekit.agent.SessionResponse.GetSessionStateResponseH\x00\x12K\n\rget_rtc_stats\x18\t \x01(\x0b\x32\x32.livekit.agent.SessionResponse.GetRTCStatsResponseH\x00\x12S\n\x11get_session_usage\x18\n \x01(\x0b\x32\x36.livekit.agent.SessionResponse.GetSessionUsageResponseH\x00\x12U\n\x12get_framework_info\x18\x0b \x01(\x0b\x32\x37.livekit.agent.SessionResponse.GetFrameworkInfoResponseH\x00\x1a\x06\n\x04Pong\x1aL\n\x16GetChatHistoryResponse\x12\x32\n\x05items\x18\x01 \x03(\x0b\x32#.livekit.agent.ChatContext.ChatItem\x1a\x94\x01\n\x14GetAgentInfoResponse\x12\n\n\x02id\x18\x01 \x01(\t\x12\x19\n\x0cinstructions\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\r\n\x05tools\x18\x03 \x03(\t\x12\x35\n\x08\x63hat_ctx\x18\x04 \x03(\x0b\x32#.livekit.agent.ChatContext.ChatItemB\x0f\n\r_instructions\x1a\x46\n\x10RunInputResponse\x12\x32\n\x05items\x18\x01 \x03(\x0b\x32#.livekit.agent.ChatContext.ChatItem\x1a\xbf\x02\n\x17GetSessionStateResponse\x12.\n\x0b\x61gent_state\x18\x01 \x01(\x0e\x32\x19.livekit.agent.AgentState\x12,\n\nuser_state\x18\x02 \x01(\x0e\x32\x18.livekit.agent.UserState\x12\x10\n\x08\x61gent_id\x18\x03 \x01(\t\x12T\n\x07options\x18\x04 \x03(\x0b\x32\x43.livekit.agent.SessionResponse.GetSessionStateResponse.OptionsEntry\x12.\n\ncreated_at\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x1a.\n\x0cOptionsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1az\n\x13GetRTCStatsResponse\x12\x30\n\x0fpublisher_stats\x18\x01 \x03(\x0b\x32\x17.google.protobuf.Struct\x12\x31\n\x10subscriber_stats\x18\x02 \x03(\x0b\x32\x17.google.protobuf.Struct\x1az\n\x17GetSessionUsageResponse\x12/\n\x05usage\x18\x01 \x01(\x0b\x32 .livekit.agent.AgentSessionUsage\x12.\n\ncreated_at\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x1a<\n\x18GetFrameworkInfoResponse\x12\x0b\n\x03sdk\x18\x01 \x01(\t\x12\x13\n\x0bsdk_version\x18\x02 \x01(\tB\n\n\x08responseB\x08\n\x06_error\"\xba\x06\n\x13\x41gentSessionMessage\x12N\n\x0b\x61udio_input\x18\x01 \x01(\x0b\x32\x37.livekit.agent.AgentSessionMessage.ConsoleIO.AudioFrameH\x00\x12O\n\x0c\x61udio_output\x18\x02 \x01(\x0b\x32\x37.livekit.agent.AgentSessionMessage.ConsoleIO.AudioFrameH\x00\x12\x31\n\x05\x65vent\x18\x03 \x01(\x0b\x32 .livekit.agent.AgentSessionEventH\x00\x12\x30\n\x07request\x18\x04 \x01(\x0b\x32\x1d.livekit.agent.SessionRequestH\x00\x12\x32\n\x08response\x18\x05 \x01(\x0b\x32\x1e.livekit.agent.SessionResponseH\x00\x12_\n\x14\x61udio_playback_flush\x18\x06 \x01(\x0b\x32?.livekit.agent.AgentSessionMessage.ConsoleIO.AudioPlaybackFlushH\x00\x12_\n\x14\x61udio_playback_clear\x18\x07 \x01(\x0b\x32?.livekit.agent.AgentSessionMessage.ConsoleIO.AudioPlaybackClearH\x00\x12\x65\n\x17\x61udio_playback_finished\x18\x08 \x01(\x0b\x32\x42.livekit.agent.AgentSessionMessage.ConsoleIO.AudioPlaybackFinishedH\x00\x1a\xb4\x01\n\tConsoleIO\x1a\x62\n\nAudioFrame\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\x12\x13\n\x0bsample_rate\x18\x02 \x01(\r\x12\x14\n\x0cnum_channels\x18\x03 \x01(\r\x12\x1b\n\x13samples_per_channel\x18\x04 \x01(\r\x1a\x14\n\x12\x41udioPlaybackFlush\x1a\x14\n\x12\x41udioPlaybackClear\x1a\x17\n\x15\x41udioPlaybackFinishedB\t\n\x07message*>\n\x08\x43hatRole\x12\r\n\tDEVELOPER\x10\x00\x12\n\n\x06SYSTEM\x10\x01\x12\x08\n\x04USER\x10\x02\x12\r\n\tASSISTANT\x10\x03*b\n\nAgentState\x12\x13\n\x0f\x41S_INITIALIZING\x10\x00\x12\x0b\n\x07\x41S_IDLE\x10\x01\x12\x10\n\x0c\x41S_LISTENING\x10\x02\x12\x0f\n\x0b\x41S_THINKING\x10\x03\x12\x0f\n\x0b\x41S_SPEAKING\x10\x04*;\n\tUserState\x12\x0f\n\x0bUS_SPEAKING\x10\x00\x12\x10\n\x0cUS_LISTENING\x10\x01\x12\x0b\n\x07US_AWAY\x10\x02\x42+Z)github.com/livekit/protocol/livekit/agentb\x06proto3')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'agent.agent_session', _globals)
+if _descriptor._USE_C_DESCRIPTORS == False:
+ _globals['DESCRIPTOR']._options = None
+ _globals['DESCRIPTOR']._serialized_options = b'Z)github.com/livekit/protocol/livekit/agent'
+ _globals['_CHATMESSAGE_EXTRAENTRY']._options = None
+ _globals['_CHATMESSAGE_EXTRAENTRY']._serialized_options = b'8\001'
+ _globals['_FUNCTIONCALL'].fields_by_name['call_id']._options = None
+ _globals['_FUNCTIONCALL'].fields_by_name['call_id']._serialized_options = b'\272P\006callID'
+ _globals['_FUNCTIONCALLOUTPUT'].fields_by_name['call_id']._options = None
+ _globals['_FUNCTIONCALLOUTPUT'].fields_by_name['call_id']._serialized_options = b'\272P\006callID'
+ _globals['_AGENTHANDOFF'].fields_by_name['old_agent_id']._options = None
+ _globals['_AGENTHANDOFF'].fields_by_name['old_agent_id']._serialized_options = b'\272P\noldAgentID'
+ _globals['_AGENTHANDOFF'].fields_by_name['new_agent_id']._options = None
+ _globals['_AGENTHANDOFF'].fields_by_name['new_agent_id']._serialized_options = b'\272P\nnewAgentID'
+ _globals['_SESSIONRESPONSE_GETSESSIONSTATERESPONSE_OPTIONSENTRY']._options = None
+ _globals['_SESSIONRESPONSE_GETSESSIONSTATERESPONSE_OPTIONSENTRY']._serialized_options = b'8\001'
+ _globals['_CHATROLE']._serialized_start=8127
+ _globals['_CHATROLE']._serialized_end=8189
+ _globals['_AGENTSTATE']._serialized_start=8191
+ _globals['_AGENTSTATE']._serialized_end=8289
+ _globals['_USERSTATE']._serialized_start=8291
+ _globals['_USERSTATE']._serialized_end=8350
+ _globals['_METRICSREPORT']._serialized_start=138
+ _globals['_METRICSREPORT']._serialized_end=589
+ _globals['_TIMEDSTRING']._serialized_start=592
+ _globals['_TIMEDSTRING']._serialized_end=829
+ _globals['_CHATMESSAGE']._serialized_start=832
+ _globals['_CHATMESSAGE']._serialized_end=1273
+ _globals['_CHATMESSAGE_CHATCONTENT']._serialized_start=1161
+ _globals['_CHATMESSAGE_CHATCONTENT']._serialized_end=1201
+ _globals['_CHATMESSAGE_EXTRAENTRY']._serialized_start=1203
+ _globals['_CHATMESSAGE_EXTRAENTRY']._serialized_end=1247
+ _globals['_FUNCTIONCALL']._serialized_start=1276
+ _globals['_FUNCTIONCALL']._serialized_end=1411
+ _globals['_FUNCTIONCALLOUTPUT']._serialized_start=1414
+ _globals['_FUNCTIONCALLOUTPUT']._serialized_end=1570
+ _globals['_AGENTHANDOFF']._serialized_start=1573
+ _globals['_AGENTHANDOFF']._serialized_end=1743
+ _globals['_AGENTCONFIGUPDATE']._serialized_start=1746
+ _globals['_AGENTCONFIGUPDATE']._serialized_end=1913
+ _globals['_CHATCONTEXT']._serialized_start=1916
+ _globals['_CHATCONTEXT']._serialized_end=2289
+ _globals['_CHATCONTEXT_CHATITEM']._serialized_start=1984
+ _globals['_CHATCONTEXT_CHATITEM']._serialized_end=2289
+ _globals['_LLMMODELUSAGE']._serialized_start=2292
+ _globals['_LLMMODELUSAGE']._serialized_end=2684
+ _globals['_TTSMODELUSAGE']._serialized_start=2687
+ _globals['_TTSMODELUSAGE']._serialized_end=2830
+ _globals['_STTMODELUSAGE']._serialized_start=2832
+ _globals['_STTMODELUSAGE']._serialized_end=2949
+ _globals['_INTERRUPTIONMODELUSAGE']._serialized_start=2951
+ _globals['_INTERRUPTIONMODELUSAGE']._serialized_end=3032
+ _globals['_MODELUSAGE']._serialized_start=3035
+ _globals['_MODELUSAGE']._serialized_end=3254
+ _globals['_AGENTSESSIONUSAGE']._serialized_start=3256
+ _globals['_AGENTSESSIONUSAGE']._serialized_end=3323
+ _globals['_AGENTSESSIONEVENT']._serialized_start=3326
+ _globals['_AGENTSESSIONEVENT']._serialized_end=4908
+ _globals['_AGENTSESSIONEVENT_AGENTSTATECHANGED']._serialized_start=4056
+ _globals['_AGENTSESSIONEVENT_AGENTSTATECHANGED']._serialized_end=4167
+ _globals['_AGENTSESSIONEVENT_USERSTATECHANGED']._serialized_start=4169
+ _globals['_AGENTSESSIONEVENT_USERSTATECHANGED']._serialized_end=4277
+ _globals['_AGENTSESSIONEVENT_CONVERSATIONITEMADDED']._serialized_start=4279
+ _globals['_AGENTSESSIONEVENT_CONVERSATIONITEMADDED']._serialized_end=4353
+ _globals['_AGENTSESSIONEVENT_USERINPUTTRANSCRIBED']._serialized_start=4355
+ _globals['_AGENTSESSIONEVENT_USERINPUTTRANSCRIBED']._serialized_end=4451
+ _globals['_AGENTSESSIONEVENT_FUNCTIONTOOLSEXECUTED']._serialized_start=4454
+ _globals['_AGENTSESSIONEVENT_FUNCTIONTOOLSEXECUTED']._serialized_end=4596
+ _globals['_AGENTSESSIONEVENT_ERROR']._serialized_start=4598
+ _globals['_AGENTSESSIONEVENT_ERROR']._serialized_end=4622
+ _globals['_AGENTSESSIONEVENT_OVERLAPPINGSPEECH']._serialized_start=4625
+ _globals['_AGENTSESSIONEVENT_OVERLAPPINGSPEECH']._serialized_end=4827
+ _globals['_AGENTSESSIONEVENT_SESSIONUSAGEUPDATED']._serialized_start=4829
+ _globals['_AGENTSESSIONEVENT_SESSIONUSAGEUPDATED']._serialized_end=4899
+ _globals['_SESSIONREQUEST']._serialized_start=4911
+ _globals['_SESSIONREQUEST']._serialized_end=5654
+ _globals['_SESSIONREQUEST_PING']._serialized_start=5504
+ _globals['_SESSIONREQUEST_PING']._serialized_end=5510
+ _globals['_SESSIONREQUEST_GETCHATHISTORY']._serialized_start=5512
+ _globals['_SESSIONREQUEST_GETCHATHISTORY']._serialized_end=5528
+ _globals['_SESSIONREQUEST_RUNINPUT']._serialized_start=5530
+ _globals['_SESSIONREQUEST_RUNINPUT']._serialized_end=5554
+ _globals['_SESSIONREQUEST_GETAGENTINFO']._serialized_start=5556
+ _globals['_SESSIONREQUEST_GETAGENTINFO']._serialized_end=5570
+ _globals['_SESSIONREQUEST_GETSESSIONSTATE']._serialized_start=5572
+ _globals['_SESSIONREQUEST_GETSESSIONSTATE']._serialized_end=5589
+ _globals['_SESSIONREQUEST_GETRTCSTATS']._serialized_start=5591
+ _globals['_SESSIONREQUEST_GETRTCSTATS']._serialized_end=5604
+ _globals['_SESSIONREQUEST_GETSESSIONUSAGE']._serialized_start=5606
+ _globals['_SESSIONREQUEST_GETSESSIONUSAGE']._serialized_end=5623
+ _globals['_SESSIONREQUEST_GETFRAMEWORKINFO']._serialized_start=5625
+ _globals['_SESSIONREQUEST_GETFRAMEWORKINFO']._serialized_end=5643
+ _globals['_SESSIONRESPONSE']._serialized_start=5657
+ _globals['_SESSIONRESPONSE']._serialized_end=7296
+ _globals['_SESSIONRESPONSE_PONG']._serialized_start=6335
+ _globals['_SESSIONRESPONSE_PONG']._serialized_end=6341
+ _globals['_SESSIONRESPONSE_GETCHATHISTORYRESPONSE']._serialized_start=6343
+ _globals['_SESSIONRESPONSE_GETCHATHISTORYRESPONSE']._serialized_end=6419
+ _globals['_SESSIONRESPONSE_GETAGENTINFORESPONSE']._serialized_start=6422
+ _globals['_SESSIONRESPONSE_GETAGENTINFORESPONSE']._serialized_end=6570
+ _globals['_SESSIONRESPONSE_RUNINPUTRESPONSE']._serialized_start=6572
+ _globals['_SESSIONRESPONSE_RUNINPUTRESPONSE']._serialized_end=6642
+ _globals['_SESSIONRESPONSE_GETSESSIONSTATERESPONSE']._serialized_start=6645
+ _globals['_SESSIONRESPONSE_GETSESSIONSTATERESPONSE']._serialized_end=6964
+ _globals['_SESSIONRESPONSE_GETSESSIONSTATERESPONSE_OPTIONSENTRY']._serialized_start=6918
+ _globals['_SESSIONRESPONSE_GETSESSIONSTATERESPONSE_OPTIONSENTRY']._serialized_end=6964
+ _globals['_SESSIONRESPONSE_GETRTCSTATSRESPONSE']._serialized_start=6966
+ _globals['_SESSIONRESPONSE_GETRTCSTATSRESPONSE']._serialized_end=7088
+ _globals['_SESSIONRESPONSE_GETSESSIONUSAGERESPONSE']._serialized_start=7090
+ _globals['_SESSIONRESPONSE_GETSESSIONUSAGERESPONSE']._serialized_end=7212
+ _globals['_SESSIONRESPONSE_GETFRAMEWORKINFORESPONSE']._serialized_start=7214
+ _globals['_SESSIONRESPONSE_GETFRAMEWORKINFORESPONSE']._serialized_end=7274
+ _globals['_AGENTSESSIONMESSAGE']._serialized_start=7299
+ _globals['_AGENTSESSIONMESSAGE']._serialized_end=8125
+ _globals['_AGENTSESSIONMESSAGE_CONSOLEIO']._serialized_start=7934
+ _globals['_AGENTSESSIONMESSAGE_CONSOLEIO']._serialized_end=8114
+ _globals['_AGENTSESSIONMESSAGE_CONSOLEIO_AUDIOFRAME']._serialized_start=7947
+ _globals['_AGENTSESSIONMESSAGE_CONSOLEIO_AUDIOFRAME']._serialized_end=8045
+ _globals['_AGENTSESSIONMESSAGE_CONSOLEIO_AUDIOPLAYBACKFLUSH']._serialized_start=8047
+ _globals['_AGENTSESSIONMESSAGE_CONSOLEIO_AUDIOPLAYBACKFLUSH']._serialized_end=8067
+ _globals['_AGENTSESSIONMESSAGE_CONSOLEIO_AUDIOPLAYBACKCLEAR']._serialized_start=8069
+ _globals['_AGENTSESSIONMESSAGE_CONSOLEIO_AUDIOPLAYBACKCLEAR']._serialized_end=8089
+ _globals['_AGENTSESSIONMESSAGE_CONSOLEIO_AUDIOPLAYBACKFINISHED']._serialized_start=8091
+ _globals['_AGENTSESSIONMESSAGE_CONSOLEIO_AUDIOPLAYBACKFINISHED']._serialized_end=8114
+# @@protoc_insertion_point(module_scope)
diff --git a/livekit-protocol/livekit/protocol/agent_pb/agent_session.pyi b/livekit-protocol/livekit/protocol/agent_pb/agent_session.pyi
new file mode 100644
index 00000000..1b08d3e6
--- /dev/null
+++ b/livekit-protocol/livekit/protocol/agent_pb/agent_session.pyi
@@ -0,0 +1,534 @@
+from google.protobuf import struct_pb2 as _struct_pb2
+from google.protobuf import timestamp_pb2 as _timestamp_pb2
+from ..logger_pb import options as _options_pb2
+from google.protobuf.internal import containers as _containers
+from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union
+
+DESCRIPTOR: _descriptor.FileDescriptor
+
+class ChatRole(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ DEVELOPER: _ClassVar[ChatRole]
+ SYSTEM: _ClassVar[ChatRole]
+ USER: _ClassVar[ChatRole]
+ ASSISTANT: _ClassVar[ChatRole]
+
+class AgentState(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ AS_INITIALIZING: _ClassVar[AgentState]
+ AS_IDLE: _ClassVar[AgentState]
+ AS_LISTENING: _ClassVar[AgentState]
+ AS_THINKING: _ClassVar[AgentState]
+ AS_SPEAKING: _ClassVar[AgentState]
+
+class UserState(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ US_SPEAKING: _ClassVar[UserState]
+ US_LISTENING: _ClassVar[UserState]
+ US_AWAY: _ClassVar[UserState]
+DEVELOPER: ChatRole
+SYSTEM: ChatRole
+USER: ChatRole
+ASSISTANT: ChatRole
+AS_INITIALIZING: AgentState
+AS_IDLE: AgentState
+AS_LISTENING: AgentState
+AS_THINKING: AgentState
+AS_SPEAKING: AgentState
+US_SPEAKING: UserState
+US_LISTENING: UserState
+US_AWAY: UserState
+
+class MetricsReport(_message.Message):
+ __slots__ = ("started_speaking_at", "stopped_speaking_at", "transcription_delay", "end_of_turn_delay", "on_user_turn_completed_delay", "llm_node_ttft", "tts_node_ttfb", "e2e_latency")
+ STARTED_SPEAKING_AT_FIELD_NUMBER: _ClassVar[int]
+ STOPPED_SPEAKING_AT_FIELD_NUMBER: _ClassVar[int]
+ TRANSCRIPTION_DELAY_FIELD_NUMBER: _ClassVar[int]
+ END_OF_TURN_DELAY_FIELD_NUMBER: _ClassVar[int]
+ ON_USER_TURN_COMPLETED_DELAY_FIELD_NUMBER: _ClassVar[int]
+ LLM_NODE_TTFT_FIELD_NUMBER: _ClassVar[int]
+ TTS_NODE_TTFB_FIELD_NUMBER: _ClassVar[int]
+ E2E_LATENCY_FIELD_NUMBER: _ClassVar[int]
+ started_speaking_at: _timestamp_pb2.Timestamp
+ stopped_speaking_at: _timestamp_pb2.Timestamp
+ transcription_delay: float
+ end_of_turn_delay: float
+ on_user_turn_completed_delay: float
+ llm_node_ttft: float
+ tts_node_ttfb: float
+ e2e_latency: float
+ def __init__(self, started_speaking_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., stopped_speaking_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., transcription_delay: _Optional[float] = ..., end_of_turn_delay: _Optional[float] = ..., on_user_turn_completed_delay: _Optional[float] = ..., llm_node_ttft: _Optional[float] = ..., tts_node_ttfb: _Optional[float] = ..., e2e_latency: _Optional[float] = ...) -> None: ...
+
+class TimedString(_message.Message):
+ __slots__ = ("text", "start_time", "end_time", "confidence", "start_time_offset", "speaker_id")
+ TEXT_FIELD_NUMBER: _ClassVar[int]
+ START_TIME_FIELD_NUMBER: _ClassVar[int]
+ END_TIME_FIELD_NUMBER: _ClassVar[int]
+ CONFIDENCE_FIELD_NUMBER: _ClassVar[int]
+ START_TIME_OFFSET_FIELD_NUMBER: _ClassVar[int]
+ SPEAKER_ID_FIELD_NUMBER: _ClassVar[int]
+ text: str
+ start_time: float
+ end_time: float
+ confidence: float
+ start_time_offset: float
+ speaker_id: str
+ def __init__(self, text: _Optional[str] = ..., start_time: _Optional[float] = ..., end_time: _Optional[float] = ..., confidence: _Optional[float] = ..., start_time_offset: _Optional[float] = ..., speaker_id: _Optional[str] = ...) -> None: ...
+
+class ChatMessage(_message.Message):
+ __slots__ = ("id", "role", "content", "interrupted", "transcript_confidence", "extra", "metrics", "created_at")
+ class ChatContent(_message.Message):
+ __slots__ = ("text",)
+ TEXT_FIELD_NUMBER: _ClassVar[int]
+ text: str
+ def __init__(self, text: _Optional[str] = ...) -> None: ...
+ class ExtraEntry(_message.Message):
+ __slots__ = ("key", "value")
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: str
+ value: str
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
+ ID_FIELD_NUMBER: _ClassVar[int]
+ ROLE_FIELD_NUMBER: _ClassVar[int]
+ CONTENT_FIELD_NUMBER: _ClassVar[int]
+ INTERRUPTED_FIELD_NUMBER: _ClassVar[int]
+ TRANSCRIPT_CONFIDENCE_FIELD_NUMBER: _ClassVar[int]
+ EXTRA_FIELD_NUMBER: _ClassVar[int]
+ METRICS_FIELD_NUMBER: _ClassVar[int]
+ CREATED_AT_FIELD_NUMBER: _ClassVar[int]
+ id: str
+ role: ChatRole
+ content: _containers.RepeatedCompositeFieldContainer[ChatMessage.ChatContent]
+ interrupted: bool
+ transcript_confidence: float
+ extra: _containers.ScalarMap[str, str]
+ metrics: MetricsReport
+ created_at: _timestamp_pb2.Timestamp
+ def __init__(self, id: _Optional[str] = ..., role: _Optional[_Union[ChatRole, str]] = ..., content: _Optional[_Iterable[_Union[ChatMessage.ChatContent, _Mapping]]] = ..., interrupted: bool = ..., transcript_confidence: _Optional[float] = ..., extra: _Optional[_Mapping[str, str]] = ..., metrics: _Optional[_Union[MetricsReport, _Mapping]] = ..., created_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ...) -> None: ...
+
+class FunctionCall(_message.Message):
+ __slots__ = ("id", "call_id", "arguments", "name", "created_at")
+ ID_FIELD_NUMBER: _ClassVar[int]
+ CALL_ID_FIELD_NUMBER: _ClassVar[int]
+ ARGUMENTS_FIELD_NUMBER: _ClassVar[int]
+ NAME_FIELD_NUMBER: _ClassVar[int]
+ CREATED_AT_FIELD_NUMBER: _ClassVar[int]
+ id: str
+ call_id: str
+ arguments: str
+ name: str
+ created_at: _timestamp_pb2.Timestamp
+ def __init__(self, id: _Optional[str] = ..., call_id: _Optional[str] = ..., arguments: _Optional[str] = ..., name: _Optional[str] = ..., created_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ...) -> None: ...
+
+class FunctionCallOutput(_message.Message):
+ __slots__ = ("id", "name", "call_id", "output", "is_error", "created_at")
+ ID_FIELD_NUMBER: _ClassVar[int]
+ NAME_FIELD_NUMBER: _ClassVar[int]
+ CALL_ID_FIELD_NUMBER: _ClassVar[int]
+ OUTPUT_FIELD_NUMBER: _ClassVar[int]
+ IS_ERROR_FIELD_NUMBER: _ClassVar[int]
+ CREATED_AT_FIELD_NUMBER: _ClassVar[int]
+ id: str
+ name: str
+ call_id: str
+ output: str
+ is_error: bool
+ created_at: _timestamp_pb2.Timestamp
+ def __init__(self, id: _Optional[str] = ..., name: _Optional[str] = ..., call_id: _Optional[str] = ..., output: _Optional[str] = ..., is_error: bool = ..., created_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ...) -> None: ...
+
+class AgentHandoff(_message.Message):
+ __slots__ = ("id", "old_agent_id", "new_agent_id", "created_at")
+ ID_FIELD_NUMBER: _ClassVar[int]
+ OLD_AGENT_ID_FIELD_NUMBER: _ClassVar[int]
+ NEW_AGENT_ID_FIELD_NUMBER: _ClassVar[int]
+ CREATED_AT_FIELD_NUMBER: _ClassVar[int]
+ id: str
+ old_agent_id: str
+ new_agent_id: str
+ created_at: _timestamp_pb2.Timestamp
+ def __init__(self, id: _Optional[str] = ..., old_agent_id: _Optional[str] = ..., new_agent_id: _Optional[str] = ..., created_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ...) -> None: ...
+
+class AgentConfigUpdate(_message.Message):
+ __slots__ = ("id", "instructions", "tools_added", "tools_removed", "created_at")
+ ID_FIELD_NUMBER: _ClassVar[int]
+ INSTRUCTIONS_FIELD_NUMBER: _ClassVar[int]
+ TOOLS_ADDED_FIELD_NUMBER: _ClassVar[int]
+ TOOLS_REMOVED_FIELD_NUMBER: _ClassVar[int]
+ CREATED_AT_FIELD_NUMBER: _ClassVar[int]
+ id: str
+ instructions: str
+ tools_added: _containers.RepeatedScalarFieldContainer[str]
+ tools_removed: _containers.RepeatedScalarFieldContainer[str]
+ created_at: _timestamp_pb2.Timestamp
+ def __init__(self, id: _Optional[str] = ..., instructions: _Optional[str] = ..., tools_added: _Optional[_Iterable[str]] = ..., tools_removed: _Optional[_Iterable[str]] = ..., created_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ...) -> None: ...
+
+class ChatContext(_message.Message):
+ __slots__ = ("items",)
+ class ChatItem(_message.Message):
+ __slots__ = ("message", "function_call", "function_call_output", "agent_handoff", "agent_config_update")
+ MESSAGE_FIELD_NUMBER: _ClassVar[int]
+ FUNCTION_CALL_FIELD_NUMBER: _ClassVar[int]
+ FUNCTION_CALL_OUTPUT_FIELD_NUMBER: _ClassVar[int]
+ AGENT_HANDOFF_FIELD_NUMBER: _ClassVar[int]
+ AGENT_CONFIG_UPDATE_FIELD_NUMBER: _ClassVar[int]
+ message: ChatMessage
+ function_call: FunctionCall
+ function_call_output: FunctionCallOutput
+ agent_handoff: AgentHandoff
+ agent_config_update: AgentConfigUpdate
+ def __init__(self, message: _Optional[_Union[ChatMessage, _Mapping]] = ..., function_call: _Optional[_Union[FunctionCall, _Mapping]] = ..., function_call_output: _Optional[_Union[FunctionCallOutput, _Mapping]] = ..., agent_handoff: _Optional[_Union[AgentHandoff, _Mapping]] = ..., agent_config_update: _Optional[_Union[AgentConfigUpdate, _Mapping]] = ...) -> None: ...
+ ITEMS_FIELD_NUMBER: _ClassVar[int]
+ items: _containers.RepeatedCompositeFieldContainer[ChatContext.ChatItem]
+ def __init__(self, items: _Optional[_Iterable[_Union[ChatContext.ChatItem, _Mapping]]] = ...) -> None: ...
+
+class LLMModelUsage(_message.Message):
+ __slots__ = ("provider", "model", "input_tokens", "input_cached_tokens", "input_audio_tokens", "input_cached_audio_tokens", "input_text_tokens", "input_cached_text_tokens", "input_image_tokens", "input_cached_image_tokens", "output_tokens", "output_audio_tokens", "output_text_tokens", "session_duration")
+ PROVIDER_FIELD_NUMBER: _ClassVar[int]
+ MODEL_FIELD_NUMBER: _ClassVar[int]
+ INPUT_TOKENS_FIELD_NUMBER: _ClassVar[int]
+ INPUT_CACHED_TOKENS_FIELD_NUMBER: _ClassVar[int]
+ INPUT_AUDIO_TOKENS_FIELD_NUMBER: _ClassVar[int]
+ INPUT_CACHED_AUDIO_TOKENS_FIELD_NUMBER: _ClassVar[int]
+ INPUT_TEXT_TOKENS_FIELD_NUMBER: _ClassVar[int]
+ INPUT_CACHED_TEXT_TOKENS_FIELD_NUMBER: _ClassVar[int]
+ INPUT_IMAGE_TOKENS_FIELD_NUMBER: _ClassVar[int]
+ INPUT_CACHED_IMAGE_TOKENS_FIELD_NUMBER: _ClassVar[int]
+ OUTPUT_TOKENS_FIELD_NUMBER: _ClassVar[int]
+ OUTPUT_AUDIO_TOKENS_FIELD_NUMBER: _ClassVar[int]
+ OUTPUT_TEXT_TOKENS_FIELD_NUMBER: _ClassVar[int]
+ SESSION_DURATION_FIELD_NUMBER: _ClassVar[int]
+ provider: str
+ model: str
+ input_tokens: int
+ input_cached_tokens: int
+ input_audio_tokens: int
+ input_cached_audio_tokens: int
+ input_text_tokens: int
+ input_cached_text_tokens: int
+ input_image_tokens: int
+ input_cached_image_tokens: int
+ output_tokens: int
+ output_audio_tokens: int
+ output_text_tokens: int
+ session_duration: float
+ def __init__(self, provider: _Optional[str] = ..., model: _Optional[str] = ..., input_tokens: _Optional[int] = ..., input_cached_tokens: _Optional[int] = ..., input_audio_tokens: _Optional[int] = ..., input_cached_audio_tokens: _Optional[int] = ..., input_text_tokens: _Optional[int] = ..., input_cached_text_tokens: _Optional[int] = ..., input_image_tokens: _Optional[int] = ..., input_cached_image_tokens: _Optional[int] = ..., output_tokens: _Optional[int] = ..., output_audio_tokens: _Optional[int] = ..., output_text_tokens: _Optional[int] = ..., session_duration: _Optional[float] = ...) -> None: ...
+
+class TTSModelUsage(_message.Message):
+ __slots__ = ("provider", "model", "input_tokens", "output_tokens", "characters_count", "audio_duration")
+ PROVIDER_FIELD_NUMBER: _ClassVar[int]
+ MODEL_FIELD_NUMBER: _ClassVar[int]
+ INPUT_TOKENS_FIELD_NUMBER: _ClassVar[int]
+ OUTPUT_TOKENS_FIELD_NUMBER: _ClassVar[int]
+ CHARACTERS_COUNT_FIELD_NUMBER: _ClassVar[int]
+ AUDIO_DURATION_FIELD_NUMBER: _ClassVar[int]
+ provider: str
+ model: str
+ input_tokens: int
+ output_tokens: int
+ characters_count: int
+ audio_duration: float
+ def __init__(self, provider: _Optional[str] = ..., model: _Optional[str] = ..., input_tokens: _Optional[int] = ..., output_tokens: _Optional[int] = ..., characters_count: _Optional[int] = ..., audio_duration: _Optional[float] = ...) -> None: ...
+
+class STTModelUsage(_message.Message):
+ __slots__ = ("provider", "model", "input_tokens", "output_tokens", "audio_duration")
+ PROVIDER_FIELD_NUMBER: _ClassVar[int]
+ MODEL_FIELD_NUMBER: _ClassVar[int]
+ INPUT_TOKENS_FIELD_NUMBER: _ClassVar[int]
+ OUTPUT_TOKENS_FIELD_NUMBER: _ClassVar[int]
+ AUDIO_DURATION_FIELD_NUMBER: _ClassVar[int]
+ provider: str
+ model: str
+ input_tokens: int
+ output_tokens: int
+ audio_duration: float
+ def __init__(self, provider: _Optional[str] = ..., model: _Optional[str] = ..., input_tokens: _Optional[int] = ..., output_tokens: _Optional[int] = ..., audio_duration: _Optional[float] = ...) -> None: ...
+
+class InterruptionModelUsage(_message.Message):
+ __slots__ = ("provider", "model", "total_requests")
+ PROVIDER_FIELD_NUMBER: _ClassVar[int]
+ MODEL_FIELD_NUMBER: _ClassVar[int]
+ TOTAL_REQUESTS_FIELD_NUMBER: _ClassVar[int]
+ provider: str
+ model: str
+ total_requests: int
+ def __init__(self, provider: _Optional[str] = ..., model: _Optional[str] = ..., total_requests: _Optional[int] = ...) -> None: ...
+
+class ModelUsage(_message.Message):
+ __slots__ = ("llm", "tts", "stt", "interruption")
+ LLM_FIELD_NUMBER: _ClassVar[int]
+ TTS_FIELD_NUMBER: _ClassVar[int]
+ STT_FIELD_NUMBER: _ClassVar[int]
+ INTERRUPTION_FIELD_NUMBER: _ClassVar[int]
+ llm: LLMModelUsage
+ tts: TTSModelUsage
+ stt: STTModelUsage
+ interruption: InterruptionModelUsage
+ def __init__(self, llm: _Optional[_Union[LLMModelUsage, _Mapping]] = ..., tts: _Optional[_Union[TTSModelUsage, _Mapping]] = ..., stt: _Optional[_Union[STTModelUsage, _Mapping]] = ..., interruption: _Optional[_Union[InterruptionModelUsage, _Mapping]] = ...) -> None: ...
+
+class AgentSessionUsage(_message.Message):
+ __slots__ = ("model_usage",)
+ MODEL_USAGE_FIELD_NUMBER: _ClassVar[int]
+ model_usage: _containers.RepeatedCompositeFieldContainer[ModelUsage]
+ def __init__(self, model_usage: _Optional[_Iterable[_Union[ModelUsage, _Mapping]]] = ...) -> None: ...
+
+class AgentSessionEvent(_message.Message):
+ __slots__ = ("created_at", "agent_state_changed", "user_state_changed", "conversation_item_added", "user_input_transcribed", "function_tools_executed", "error", "overlapping_speech", "session_usage_updated")
+ class AgentStateChanged(_message.Message):
+ __slots__ = ("old_state", "new_state")
+ OLD_STATE_FIELD_NUMBER: _ClassVar[int]
+ NEW_STATE_FIELD_NUMBER: _ClassVar[int]
+ old_state: AgentState
+ new_state: AgentState
+ def __init__(self, old_state: _Optional[_Union[AgentState, str]] = ..., new_state: _Optional[_Union[AgentState, str]] = ...) -> None: ...
+ class UserStateChanged(_message.Message):
+ __slots__ = ("old_state", "new_state")
+ OLD_STATE_FIELD_NUMBER: _ClassVar[int]
+ NEW_STATE_FIELD_NUMBER: _ClassVar[int]
+ old_state: UserState
+ new_state: UserState
+ def __init__(self, old_state: _Optional[_Union[UserState, str]] = ..., new_state: _Optional[_Union[UserState, str]] = ...) -> None: ...
+ class ConversationItemAdded(_message.Message):
+ __slots__ = ("item",)
+ ITEM_FIELD_NUMBER: _ClassVar[int]
+ item: ChatContext.ChatItem
+ def __init__(self, item: _Optional[_Union[ChatContext.ChatItem, _Mapping]] = ...) -> None: ...
+ class UserInputTranscribed(_message.Message):
+ __slots__ = ("transcript", "is_final", "language")
+ TRANSCRIPT_FIELD_NUMBER: _ClassVar[int]
+ IS_FINAL_FIELD_NUMBER: _ClassVar[int]
+ LANGUAGE_FIELD_NUMBER: _ClassVar[int]
+ transcript: str
+ is_final: bool
+ language: str
+ def __init__(self, transcript: _Optional[str] = ..., is_final: bool = ..., language: _Optional[str] = ...) -> None: ...
+ class FunctionToolsExecuted(_message.Message):
+ __slots__ = ("function_calls", "function_call_outputs")
+ FUNCTION_CALLS_FIELD_NUMBER: _ClassVar[int]
+ FUNCTION_CALL_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
+ function_calls: _containers.RepeatedCompositeFieldContainer[FunctionCall]
+ function_call_outputs: _containers.RepeatedCompositeFieldContainer[FunctionCallOutput]
+ def __init__(self, function_calls: _Optional[_Iterable[_Union[FunctionCall, _Mapping]]] = ..., function_call_outputs: _Optional[_Iterable[_Union[FunctionCallOutput, _Mapping]]] = ...) -> None: ...
+ class Error(_message.Message):
+ __slots__ = ("message",)
+ MESSAGE_FIELD_NUMBER: _ClassVar[int]
+ message: str
+ def __init__(self, message: _Optional[str] = ...) -> None: ...
+ class OverlappingSpeech(_message.Message):
+ __slots__ = ("is_interruption", "overlap_started_at", "detection_delay", "detected_at")
+ IS_INTERRUPTION_FIELD_NUMBER: _ClassVar[int]
+ OVERLAP_STARTED_AT_FIELD_NUMBER: _ClassVar[int]
+ DETECTION_DELAY_FIELD_NUMBER: _ClassVar[int]
+ DETECTED_AT_FIELD_NUMBER: _ClassVar[int]
+ is_interruption: bool
+ overlap_started_at: _timestamp_pb2.Timestamp
+ detection_delay: float
+ detected_at: _timestamp_pb2.Timestamp
+ def __init__(self, is_interruption: bool = ..., overlap_started_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., detection_delay: _Optional[float] = ..., detected_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ...) -> None: ...
+ class SessionUsageUpdated(_message.Message):
+ __slots__ = ("usage",)
+ USAGE_FIELD_NUMBER: _ClassVar[int]
+ usage: AgentSessionUsage
+ def __init__(self, usage: _Optional[_Union[AgentSessionUsage, _Mapping]] = ...) -> None: ...
+ CREATED_AT_FIELD_NUMBER: _ClassVar[int]
+ AGENT_STATE_CHANGED_FIELD_NUMBER: _ClassVar[int]
+ USER_STATE_CHANGED_FIELD_NUMBER: _ClassVar[int]
+ CONVERSATION_ITEM_ADDED_FIELD_NUMBER: _ClassVar[int]
+ USER_INPUT_TRANSCRIBED_FIELD_NUMBER: _ClassVar[int]
+ FUNCTION_TOOLS_EXECUTED_FIELD_NUMBER: _ClassVar[int]
+ ERROR_FIELD_NUMBER: _ClassVar[int]
+ OVERLAPPING_SPEECH_FIELD_NUMBER: _ClassVar[int]
+ SESSION_USAGE_UPDATED_FIELD_NUMBER: _ClassVar[int]
+ created_at: _timestamp_pb2.Timestamp
+ agent_state_changed: AgentSessionEvent.AgentStateChanged
+ user_state_changed: AgentSessionEvent.UserStateChanged
+ conversation_item_added: AgentSessionEvent.ConversationItemAdded
+ user_input_transcribed: AgentSessionEvent.UserInputTranscribed
+ function_tools_executed: AgentSessionEvent.FunctionToolsExecuted
+ error: AgentSessionEvent.Error
+ overlapping_speech: AgentSessionEvent.OverlappingSpeech
+ session_usage_updated: AgentSessionEvent.SessionUsageUpdated
+ def __init__(self, created_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., agent_state_changed: _Optional[_Union[AgentSessionEvent.AgentStateChanged, _Mapping]] = ..., user_state_changed: _Optional[_Union[AgentSessionEvent.UserStateChanged, _Mapping]] = ..., conversation_item_added: _Optional[_Union[AgentSessionEvent.ConversationItemAdded, _Mapping]] = ..., user_input_transcribed: _Optional[_Union[AgentSessionEvent.UserInputTranscribed, _Mapping]] = ..., function_tools_executed: _Optional[_Union[AgentSessionEvent.FunctionToolsExecuted, _Mapping]] = ..., error: _Optional[_Union[AgentSessionEvent.Error, _Mapping]] = ..., overlapping_speech: _Optional[_Union[AgentSessionEvent.OverlappingSpeech, _Mapping]] = ..., session_usage_updated: _Optional[_Union[AgentSessionEvent.SessionUsageUpdated, _Mapping]] = ...) -> None: ...
+
+class SessionRequest(_message.Message):
+ __slots__ = ("request_id", "ping", "get_chat_history", "run_input", "get_agent_info", "get_session_state", "get_rtc_stats", "get_session_usage", "get_framework_info")
+ class Ping(_message.Message):
+ __slots__ = ()
+ def __init__(self) -> None: ...
+ class GetChatHistory(_message.Message):
+ __slots__ = ()
+ def __init__(self) -> None: ...
+ class RunInput(_message.Message):
+ __slots__ = ("text",)
+ TEXT_FIELD_NUMBER: _ClassVar[int]
+ text: str
+ def __init__(self, text: _Optional[str] = ...) -> None: ...
+ class GetAgentInfo(_message.Message):
+ __slots__ = ()
+ def __init__(self) -> None: ...
+ class GetSessionState(_message.Message):
+ __slots__ = ()
+ def __init__(self) -> None: ...
+ class GetRTCStats(_message.Message):
+ __slots__ = ()
+ def __init__(self) -> None: ...
+ class GetSessionUsage(_message.Message):
+ __slots__ = ()
+ def __init__(self) -> None: ...
+ class GetFrameworkInfo(_message.Message):
+ __slots__ = ()
+ def __init__(self) -> None: ...
+ REQUEST_ID_FIELD_NUMBER: _ClassVar[int]
+ PING_FIELD_NUMBER: _ClassVar[int]
+ GET_CHAT_HISTORY_FIELD_NUMBER: _ClassVar[int]
+ RUN_INPUT_FIELD_NUMBER: _ClassVar[int]
+ GET_AGENT_INFO_FIELD_NUMBER: _ClassVar[int]
+ GET_SESSION_STATE_FIELD_NUMBER: _ClassVar[int]
+ GET_RTC_STATS_FIELD_NUMBER: _ClassVar[int]
+ GET_SESSION_USAGE_FIELD_NUMBER: _ClassVar[int]
+ GET_FRAMEWORK_INFO_FIELD_NUMBER: _ClassVar[int]
+ request_id: str
+ ping: SessionRequest.Ping
+ get_chat_history: SessionRequest.GetChatHistory
+ run_input: SessionRequest.RunInput
+ get_agent_info: SessionRequest.GetAgentInfo
+ get_session_state: SessionRequest.GetSessionState
+ get_rtc_stats: SessionRequest.GetRTCStats
+ get_session_usage: SessionRequest.GetSessionUsage
+ get_framework_info: SessionRequest.GetFrameworkInfo
+ def __init__(self, request_id: _Optional[str] = ..., ping: _Optional[_Union[SessionRequest.Ping, _Mapping]] = ..., get_chat_history: _Optional[_Union[SessionRequest.GetChatHistory, _Mapping]] = ..., run_input: _Optional[_Union[SessionRequest.RunInput, _Mapping]] = ..., get_agent_info: _Optional[_Union[SessionRequest.GetAgentInfo, _Mapping]] = ..., get_session_state: _Optional[_Union[SessionRequest.GetSessionState, _Mapping]] = ..., get_rtc_stats: _Optional[_Union[SessionRequest.GetRTCStats, _Mapping]] = ..., get_session_usage: _Optional[_Union[SessionRequest.GetSessionUsage, _Mapping]] = ..., get_framework_info: _Optional[_Union[SessionRequest.GetFrameworkInfo, _Mapping]] = ...) -> None: ...
+
+class SessionResponse(_message.Message):
+ __slots__ = ("request_id", "error", "pong", "get_chat_history", "run_input", "get_agent_info", "get_session_state", "get_rtc_stats", "get_session_usage", "get_framework_info")
+ class Pong(_message.Message):
+ __slots__ = ()
+ def __init__(self) -> None: ...
+ class GetChatHistoryResponse(_message.Message):
+ __slots__ = ("items",)
+ ITEMS_FIELD_NUMBER: _ClassVar[int]
+ items: _containers.RepeatedCompositeFieldContainer[ChatContext.ChatItem]
+ def __init__(self, items: _Optional[_Iterable[_Union[ChatContext.ChatItem, _Mapping]]] = ...) -> None: ...
+ class GetAgentInfoResponse(_message.Message):
+ __slots__ = ("id", "instructions", "tools", "chat_ctx")
+ ID_FIELD_NUMBER: _ClassVar[int]
+ INSTRUCTIONS_FIELD_NUMBER: _ClassVar[int]
+ TOOLS_FIELD_NUMBER: _ClassVar[int]
+ CHAT_CTX_FIELD_NUMBER: _ClassVar[int]
+ id: str
+ instructions: str
+ tools: _containers.RepeatedScalarFieldContainer[str]
+ chat_ctx: _containers.RepeatedCompositeFieldContainer[ChatContext.ChatItem]
+ def __init__(self, id: _Optional[str] = ..., instructions: _Optional[str] = ..., tools: _Optional[_Iterable[str]] = ..., chat_ctx: _Optional[_Iterable[_Union[ChatContext.ChatItem, _Mapping]]] = ...) -> None: ...
+ class RunInputResponse(_message.Message):
+ __slots__ = ("items",)
+ ITEMS_FIELD_NUMBER: _ClassVar[int]
+ items: _containers.RepeatedCompositeFieldContainer[ChatContext.ChatItem]
+ def __init__(self, items: _Optional[_Iterable[_Union[ChatContext.ChatItem, _Mapping]]] = ...) -> None: ...
+ class GetSessionStateResponse(_message.Message):
+ __slots__ = ("agent_state", "user_state", "agent_id", "options", "created_at")
+ class OptionsEntry(_message.Message):
+ __slots__ = ("key", "value")
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: str
+ value: str
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
+ AGENT_STATE_FIELD_NUMBER: _ClassVar[int]
+ USER_STATE_FIELD_NUMBER: _ClassVar[int]
+ AGENT_ID_FIELD_NUMBER: _ClassVar[int]
+ OPTIONS_FIELD_NUMBER: _ClassVar[int]
+ CREATED_AT_FIELD_NUMBER: _ClassVar[int]
+ agent_state: AgentState
+ user_state: UserState
+ agent_id: str
+ options: _containers.ScalarMap[str, str]
+ created_at: _timestamp_pb2.Timestamp
+ def __init__(self, agent_state: _Optional[_Union[AgentState, str]] = ..., user_state: _Optional[_Union[UserState, str]] = ..., agent_id: _Optional[str] = ..., options: _Optional[_Mapping[str, str]] = ..., created_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ...) -> None: ...
+ class GetRTCStatsResponse(_message.Message):
+ __slots__ = ("publisher_stats", "subscriber_stats")
+ PUBLISHER_STATS_FIELD_NUMBER: _ClassVar[int]
+ SUBSCRIBER_STATS_FIELD_NUMBER: _ClassVar[int]
+ publisher_stats: _containers.RepeatedCompositeFieldContainer[_struct_pb2.Struct]
+ subscriber_stats: _containers.RepeatedCompositeFieldContainer[_struct_pb2.Struct]
+ def __init__(self, publisher_stats: _Optional[_Iterable[_Union[_struct_pb2.Struct, _Mapping]]] = ..., subscriber_stats: _Optional[_Iterable[_Union[_struct_pb2.Struct, _Mapping]]] = ...) -> None: ...
+ class GetSessionUsageResponse(_message.Message):
+ __slots__ = ("usage", "created_at")
+ USAGE_FIELD_NUMBER: _ClassVar[int]
+ CREATED_AT_FIELD_NUMBER: _ClassVar[int]
+ usage: AgentSessionUsage
+ created_at: _timestamp_pb2.Timestamp
+ def __init__(self, usage: _Optional[_Union[AgentSessionUsage, _Mapping]] = ..., created_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ...) -> None: ...
+ class GetFrameworkInfoResponse(_message.Message):
+ __slots__ = ("sdk", "sdk_version")
+ SDK_FIELD_NUMBER: _ClassVar[int]
+ SDK_VERSION_FIELD_NUMBER: _ClassVar[int]
+ sdk: str
+ sdk_version: str
+ def __init__(self, sdk: _Optional[str] = ..., sdk_version: _Optional[str] = ...) -> None: ...
+ REQUEST_ID_FIELD_NUMBER: _ClassVar[int]
+ ERROR_FIELD_NUMBER: _ClassVar[int]
+ PONG_FIELD_NUMBER: _ClassVar[int]
+ GET_CHAT_HISTORY_FIELD_NUMBER: _ClassVar[int]
+ RUN_INPUT_FIELD_NUMBER: _ClassVar[int]
+ GET_AGENT_INFO_FIELD_NUMBER: _ClassVar[int]
+ GET_SESSION_STATE_FIELD_NUMBER: _ClassVar[int]
+ GET_RTC_STATS_FIELD_NUMBER: _ClassVar[int]
+ GET_SESSION_USAGE_FIELD_NUMBER: _ClassVar[int]
+ GET_FRAMEWORK_INFO_FIELD_NUMBER: _ClassVar[int]
+ request_id: str
+ error: str
+ pong: SessionResponse.Pong
+ get_chat_history: SessionResponse.GetChatHistoryResponse
+ run_input: SessionResponse.RunInputResponse
+ get_agent_info: SessionResponse.GetAgentInfoResponse
+ get_session_state: SessionResponse.GetSessionStateResponse
+ get_rtc_stats: SessionResponse.GetRTCStatsResponse
+ get_session_usage: SessionResponse.GetSessionUsageResponse
+ get_framework_info: SessionResponse.GetFrameworkInfoResponse
+ def __init__(self, request_id: _Optional[str] = ..., error: _Optional[str] = ..., pong: _Optional[_Union[SessionResponse.Pong, _Mapping]] = ..., get_chat_history: _Optional[_Union[SessionResponse.GetChatHistoryResponse, _Mapping]] = ..., run_input: _Optional[_Union[SessionResponse.RunInputResponse, _Mapping]] = ..., get_agent_info: _Optional[_Union[SessionResponse.GetAgentInfoResponse, _Mapping]] = ..., get_session_state: _Optional[_Union[SessionResponse.GetSessionStateResponse, _Mapping]] = ..., get_rtc_stats: _Optional[_Union[SessionResponse.GetRTCStatsResponse, _Mapping]] = ..., get_session_usage: _Optional[_Union[SessionResponse.GetSessionUsageResponse, _Mapping]] = ..., get_framework_info: _Optional[_Union[SessionResponse.GetFrameworkInfoResponse, _Mapping]] = ...) -> None: ...
+
+class AgentSessionMessage(_message.Message):
+ __slots__ = ("audio_input", "audio_output", "event", "request", "response", "audio_playback_flush", "audio_playback_clear", "audio_playback_finished")
+ class ConsoleIO(_message.Message):
+ __slots__ = ()
+ class AudioFrame(_message.Message):
+ __slots__ = ("data", "sample_rate", "num_channels", "samples_per_channel")
+ DATA_FIELD_NUMBER: _ClassVar[int]
+ SAMPLE_RATE_FIELD_NUMBER: _ClassVar[int]
+ NUM_CHANNELS_FIELD_NUMBER: _ClassVar[int]
+ SAMPLES_PER_CHANNEL_FIELD_NUMBER: _ClassVar[int]
+ data: bytes
+ sample_rate: int
+ num_channels: int
+ samples_per_channel: int
+ def __init__(self, data: _Optional[bytes] = ..., sample_rate: _Optional[int] = ..., num_channels: _Optional[int] = ..., samples_per_channel: _Optional[int] = ...) -> None: ...
+ class AudioPlaybackFlush(_message.Message):
+ __slots__ = ()
+ def __init__(self) -> None: ...
+ class AudioPlaybackClear(_message.Message):
+ __slots__ = ()
+ def __init__(self) -> None: ...
+ class AudioPlaybackFinished(_message.Message):
+ __slots__ = ()
+ def __init__(self) -> None: ...
+ def __init__(self) -> None: ...
+ AUDIO_INPUT_FIELD_NUMBER: _ClassVar[int]
+ AUDIO_OUTPUT_FIELD_NUMBER: _ClassVar[int]
+ EVENT_FIELD_NUMBER: _ClassVar[int]
+ REQUEST_FIELD_NUMBER: _ClassVar[int]
+ RESPONSE_FIELD_NUMBER: _ClassVar[int]
+ AUDIO_PLAYBACK_FLUSH_FIELD_NUMBER: _ClassVar[int]
+ AUDIO_PLAYBACK_CLEAR_FIELD_NUMBER: _ClassVar[int]
+ AUDIO_PLAYBACK_FINISHED_FIELD_NUMBER: _ClassVar[int]
+ audio_input: AgentSessionMessage.ConsoleIO.AudioFrame
+ audio_output: AgentSessionMessage.ConsoleIO.AudioFrame
+ event: AgentSessionEvent
+ request: SessionRequest
+ response: SessionResponse
+ audio_playback_flush: AgentSessionMessage.ConsoleIO.AudioPlaybackFlush
+ audio_playback_clear: AgentSessionMessage.ConsoleIO.AudioPlaybackClear
+ audio_playback_finished: AgentSessionMessage.ConsoleIO.AudioPlaybackFinished
+ def __init__(self, audio_input: _Optional[_Union[AgentSessionMessage.ConsoleIO.AudioFrame, _Mapping]] = ..., audio_output: _Optional[_Union[AgentSessionMessage.ConsoleIO.AudioFrame, _Mapping]] = ..., event: _Optional[_Union[AgentSessionEvent, _Mapping]] = ..., request: _Optional[_Union[SessionRequest, _Mapping]] = ..., response: _Optional[_Union[SessionResponse, _Mapping]] = ..., audio_playback_flush: _Optional[_Union[AgentSessionMessage.ConsoleIO.AudioPlaybackFlush, _Mapping]] = ..., audio_playback_clear: _Optional[_Union[AgentSessionMessage.ConsoleIO.AudioPlaybackClear, _Mapping]] = ..., audio_playback_finished: _Optional[_Union[AgentSessionMessage.ConsoleIO.AudioPlaybackFinished, _Mapping]] = ...) -> None: ...
diff --git a/livekit-protocol/livekit/protocol/agent_pb/agent_text.py b/livekit-protocol/livekit/protocol/agent_pb/agent_text.py
new file mode 100644
index 00000000..b07aa3af
--- /dev/null
+++ b/livekit-protocol/livekit/protocol/agent_pb/agent_text.py
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: agent/livekit_agent_text.proto
+# Protobuf Python Version: 4.25.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from . import agent_session as agent_dot__agent__session_
+from ..logger_pb import options as logger_dot_options__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1e\x61gent/livekit_agent_text.proto\x12\rlivekit.agent\x1a!agent/livekit_agent_session.proto\x1a\x14logger/options.proto\"\xdc\x01\n\x12TextMessageRequest\x12\x0c\n\x04text\x18\x01 \x01(\t\x12 \n\nmessage_id\x18\x02 \x01(\tB\x0c\xbaP\tmessageID\x12 \n\nsession_id\x18\x03 \x01(\tB\x0c\xbaP\tsessionID\x12\x12\n\nagent_name\x18\x04 \x01(\t\x12\x10\n\x08metadata\x18\x05 \x01(\t\x12<\n\rsession_state\x18\x06 \x01(\x0b\x32 .livekit.agent.AgentSessionStateH\x00\x88\x01\x01\x42\x10\n\x0e_session_state\"\xf8\x02\n\x13TextMessageResponse\x12 \n\nmessage_id\x18\x01 \x01(\tB\x0c\xbaP\tmessageID\x12 \n\nsession_id\x18\x02 \x01(\tB\x0c\xbaP\tsessionID\x12-\n\x07message\x18\x03 \x01(\x0b\x32\x1a.livekit.agent.ChatMessageH\x00\x12\x34\n\rfunction_call\x18\x04 \x01(\x0b\x32\x1b.livekit.agent.FunctionCallH\x00\x12\x41\n\x14\x66unction_call_output\x18\x05 \x01(\x0b\x32!.livekit.agent.FunctionCallOutputH\x00\x12\x34\n\ragent_handoff\x18\x06 \x01(\x0b\x32\x1b.livekit.agent.AgentHandoffH\x00\x12\x36\n\x08\x63omplete\x18\x07 \x01(\x0b\x32\".livekit.agent.TextMessageCompleteH\x00\x42\x07\n\x05\x65vent\"\x8c\x01\n\x13TextMessageComplete\x12\x39\n\rsession_state\x18\x01 \x01(\x0b\x32 .livekit.agent.AgentSessionStateH\x00\x12\x30\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x1f.livekit.agent.TextMessageErrorH\x00\x42\x08\n\x06result\"Q\n\x11\x41gentSessionState\x12\x0f\n\x07version\x18\x01 \x01(\x04\x12\x12\n\x08snapshot\x18\x02 \x01(\x0cH\x00\x12\x0f\n\x05\x64\x65lta\x18\x03 \x01(\x0cH\x00\x42\x06\n\x04\x64\x61ta\"V\n\x10TextMessageError\x12\x0f\n\x07message\x18\x01 \x01(\t\x12\x31\n\x04\x63ode\x18\x02 \x01(\x0e\x32#.livekit.agent.TextMessageErrorCode*s\n\x14TextMessageErrorCode\x12\x12\n\x0eINTERNAL_ERROR\x10\x00\x12\x1b\n\x17SESSION_STATE_NOT_FOUND\x10\x01\x12\x16\n\x12TEXT_HANDLER_ERROR\x10\x02\x12\x12\n\x0ePROCESS_CLOSED\x10\x03\x42LZ)github.com/livekit/protocol/livekit/agent\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'agent.agent_text', _globals)
+if _descriptor._USE_C_DESCRIPTORS == False:
+ _globals['DESCRIPTOR']._options = None
+ _globals['DESCRIPTOR']._serialized_options = b'Z)github.com/livekit/protocol/livekit/agent\252\002\rLiveKit.Proto\352\002\016LiveKit::Proto'
+ _globals['_TEXTMESSAGEREQUEST'].fields_by_name['message_id']._options = None
+ _globals['_TEXTMESSAGEREQUEST'].fields_by_name['message_id']._serialized_options = b'\272P\tmessageID'
+ _globals['_TEXTMESSAGEREQUEST'].fields_by_name['session_id']._options = None
+ _globals['_TEXTMESSAGEREQUEST'].fields_by_name['session_id']._serialized_options = b'\272P\tsessionID'
+ _globals['_TEXTMESSAGERESPONSE'].fields_by_name['message_id']._options = None
+ _globals['_TEXTMESSAGERESPONSE'].fields_by_name['message_id']._serialized_options = b'\272P\tmessageID'
+ _globals['_TEXTMESSAGERESPONSE'].fields_by_name['session_id']._options = None
+ _globals['_TEXTMESSAGERESPONSE'].fields_by_name['session_id']._serialized_options = b'\272P\tsessionID'
+ _globals['_TEXTMESSAGEERRORCODE']._serialized_start=1022
+ _globals['_TEXTMESSAGEERRORCODE']._serialized_end=1137
+ _globals['_TEXTMESSAGEREQUEST']._serialized_start=107
+ _globals['_TEXTMESSAGEREQUEST']._serialized_end=327
+ _globals['_TEXTMESSAGERESPONSE']._serialized_start=330
+ _globals['_TEXTMESSAGERESPONSE']._serialized_end=706
+ _globals['_TEXTMESSAGECOMPLETE']._serialized_start=709
+ _globals['_TEXTMESSAGECOMPLETE']._serialized_end=849
+ _globals['_AGENTSESSIONSTATE']._serialized_start=851
+ _globals['_AGENTSESSIONSTATE']._serialized_end=932
+ _globals['_TEXTMESSAGEERROR']._serialized_start=934
+ _globals['_TEXTMESSAGEERROR']._serialized_end=1020
+# @@protoc_insertion_point(module_scope)
diff --git a/livekit-protocol/livekit/protocol/agent_pb/agent_text.pyi b/livekit-protocol/livekit/protocol/agent_pb/agent_text.pyi
new file mode 100644
index 00000000..2f2199f0
--- /dev/null
+++ b/livekit-protocol/livekit/protocol/agent_pb/agent_text.pyi
@@ -0,0 +1,79 @@
+from . import agent_session as _agent_session
+from ..logger_pb import options as _options_pb2
+from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from typing import ClassVar as _ClassVar, Mapping as _Mapping, Optional as _Optional, Union as _Union
+
+DESCRIPTOR: _descriptor.FileDescriptor
+
+class TextMessageErrorCode(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ INTERNAL_ERROR: _ClassVar[TextMessageErrorCode]
+ SESSION_STATE_NOT_FOUND: _ClassVar[TextMessageErrorCode]
+ TEXT_HANDLER_ERROR: _ClassVar[TextMessageErrorCode]
+ PROCESS_CLOSED: _ClassVar[TextMessageErrorCode]
+INTERNAL_ERROR: TextMessageErrorCode
+SESSION_STATE_NOT_FOUND: TextMessageErrorCode
+TEXT_HANDLER_ERROR: TextMessageErrorCode
+PROCESS_CLOSED: TextMessageErrorCode
+
+class TextMessageRequest(_message.Message):
+ __slots__ = ("text", "message_id", "session_id", "agent_name", "metadata", "session_state")
+ TEXT_FIELD_NUMBER: _ClassVar[int]
+ MESSAGE_ID_FIELD_NUMBER: _ClassVar[int]
+ SESSION_ID_FIELD_NUMBER: _ClassVar[int]
+ AGENT_NAME_FIELD_NUMBER: _ClassVar[int]
+ METADATA_FIELD_NUMBER: _ClassVar[int]
+ SESSION_STATE_FIELD_NUMBER: _ClassVar[int]
+ text: str
+ message_id: str
+ session_id: str
+ agent_name: str
+ metadata: str
+ session_state: AgentSessionState
+ def __init__(self, text: _Optional[str] = ..., message_id: _Optional[str] = ..., session_id: _Optional[str] = ..., agent_name: _Optional[str] = ..., metadata: _Optional[str] = ..., session_state: _Optional[_Union[AgentSessionState, _Mapping]] = ...) -> None: ...
+
+class TextMessageResponse(_message.Message):
+ __slots__ = ("message_id", "session_id", "message", "function_call", "function_call_output", "agent_handoff", "complete")
+ MESSAGE_ID_FIELD_NUMBER: _ClassVar[int]
+ SESSION_ID_FIELD_NUMBER: _ClassVar[int]
+ MESSAGE_FIELD_NUMBER: _ClassVar[int]
+ FUNCTION_CALL_FIELD_NUMBER: _ClassVar[int]
+ FUNCTION_CALL_OUTPUT_FIELD_NUMBER: _ClassVar[int]
+ AGENT_HANDOFF_FIELD_NUMBER: _ClassVar[int]
+ COMPLETE_FIELD_NUMBER: _ClassVar[int]
+ message_id: str
+ session_id: str
+ message: _agent_session.ChatMessage
+ function_call: _agent_session.FunctionCall
+ function_call_output: _agent_session.FunctionCallOutput
+ agent_handoff: _agent_session.AgentHandoff
+ complete: TextMessageComplete
+ def __init__(self, message_id: _Optional[str] = ..., session_id: _Optional[str] = ..., message: _Optional[_Union[_agent_session.ChatMessage, _Mapping]] = ..., function_call: _Optional[_Union[_agent_session.FunctionCall, _Mapping]] = ..., function_call_output: _Optional[_Union[_agent_session.FunctionCallOutput, _Mapping]] = ..., agent_handoff: _Optional[_Union[_agent_session.AgentHandoff, _Mapping]] = ..., complete: _Optional[_Union[TextMessageComplete, _Mapping]] = ...) -> None: ...
+
+class TextMessageComplete(_message.Message):
+ __slots__ = ("session_state", "error")
+ SESSION_STATE_FIELD_NUMBER: _ClassVar[int]
+ ERROR_FIELD_NUMBER: _ClassVar[int]
+ session_state: AgentSessionState
+ error: TextMessageError
+ def __init__(self, session_state: _Optional[_Union[AgentSessionState, _Mapping]] = ..., error: _Optional[_Union[TextMessageError, _Mapping]] = ...) -> None: ...
+
+class AgentSessionState(_message.Message):
+ __slots__ = ("version", "snapshot", "delta")
+ VERSION_FIELD_NUMBER: _ClassVar[int]
+ SNAPSHOT_FIELD_NUMBER: _ClassVar[int]
+ DELTA_FIELD_NUMBER: _ClassVar[int]
+ version: int
+ snapshot: bytes
+ delta: bytes
+ def __init__(self, version: _Optional[int] = ..., snapshot: _Optional[bytes] = ..., delta: _Optional[bytes] = ...) -> None: ...
+
+class TextMessageError(_message.Message):
+ __slots__ = ("message", "code")
+ MESSAGE_FIELD_NUMBER: _ClassVar[int]
+ CODE_FIELD_NUMBER: _ClassVar[int]
+ message: str
+ code: TextMessageErrorCode
+ def __init__(self, message: _Optional[str] = ..., code: _Optional[_Union[TextMessageErrorCode, str]] = ...) -> None: ...
diff --git a/livekit-protocol/livekit/protocol/analytics.py b/livekit-protocol/livekit/protocol/analytics.py
index 15fef1ba..f5535463 100644
--- a/livekit-protocol/livekit/protocol/analytics.py
+++ b/livekit-protocol/livekit/protocol/analytics.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: livekit_analytics.proto
-# Protobuf Python Version: 4.25.3
+# Protobuf Python Version: 4.25.1
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
@@ -16,9 +16,12 @@
from . import models as _models_
from . import egress as _egress_
from . import ingress as _ingress_
+from . import sip as _sip_
+from . import room as _room_
+from .logger_pb import options as logger_dot_options__pb2
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x17livekit_analytics.proto\x12\x07livekit\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x14livekit_models.proto\x1a\x14livekit_egress.proto\x1a\x15livekit_ingress.proto\"T\n\x13\x41nalyticsVideoLayer\x12\r\n\x05layer\x18\x01 \x01(\x05\x12\x0f\n\x07packets\x18\x02 \x01(\r\x12\r\n\x05\x62ytes\x18\x03 \x01(\x04\x12\x0e\n\x06\x66rames\x18\x04 \x01(\r\"\xb5\x03\n\x0f\x41nalyticsStream\x12\x0c\n\x04ssrc\x18\x01 \x01(\r\x12\x17\n\x0fprimary_packets\x18\x02 \x01(\r\x12\x15\n\rprimary_bytes\x18\x03 \x01(\x04\x12\x1a\n\x12retransmit_packets\x18\x04 \x01(\r\x12\x18\n\x10retransmit_bytes\x18\x05 \x01(\x04\x12\x17\n\x0fpadding_packets\x18\x06 \x01(\r\x12\x15\n\rpadding_bytes\x18\x07 \x01(\x04\x12\x14\n\x0cpackets_lost\x18\x08 \x01(\r\x12\x0e\n\x06\x66rames\x18\t \x01(\r\x12\x0b\n\x03rtt\x18\n \x01(\r\x12\x0e\n\x06jitter\x18\x0b \x01(\r\x12\r\n\x05nacks\x18\x0c \x01(\r\x12\x0c\n\x04plis\x18\r \x01(\r\x12\x0c\n\x04\x66irs\x18\x0e \x01(\r\x12\x32\n\x0cvideo_layers\x18\x0f \x03(\x0b\x32\x1c.livekit.AnalyticsVideoLayer\x12.\n\nstart_time\x18\x11 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12,\n\x08\x65nd_time\x18\x12 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"\xd2\x02\n\rAnalyticsStat\x12\n\n\x02id\x18\x0e \x01(\t\x12\x15\n\ranalytics_key\x18\x01 \x01(\t\x12!\n\x04kind\x18\x02 \x01(\x0e\x32\x13.livekit.StreamType\x12.\n\ntime_stamp\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x0c\n\x04node\x18\x04 \x01(\t\x12\x0f\n\x07room_id\x18\x05 \x01(\t\x12\x11\n\troom_name\x18\x06 \x01(\t\x12\x16\n\x0eparticipant_id\x18\x07 \x01(\t\x12\x10\n\x08track_id\x18\x08 \x01(\t\x12\r\n\x05score\x18\t \x01(\x02\x12)\n\x07streams\x18\n \x03(\x0b\x32\x18.livekit.AnalyticsStream\x12\x0c\n\x04mime\x18\x0b \x01(\t\x12\x11\n\tmin_score\x18\x0c \x01(\x02\x12\x14\n\x0cmedian_score\x18\r \x01(\x02\"7\n\x0e\x41nalyticsStats\x12%\n\x05stats\x18\x01 \x03(\x0b\x32\x16.livekit.AnalyticsStat\"\x9a\x02\n\x13\x41nalyticsClientMeta\x12\x0e\n\x06region\x18\x01 \x01(\t\x12\x0c\n\x04node\x18\x02 \x01(\t\x12\x13\n\x0b\x63lient_addr\x18\x03 \x01(\t\x12\x1b\n\x13\x63lient_connect_time\x18\x04 \x01(\r\x12\x17\n\x0f\x63onnection_type\x18\x05 \x01(\t\x12\x32\n\x10reconnect_reason\x18\x06 \x01(\x0e\x32\x18.livekit.ReconnectReason\x12\x15\n\x08geo_hash\x18\x07 \x01(\tH\x00\x88\x01\x01\x12\x14\n\x07\x63ountry\x18\x08 \x01(\tH\x01\x88\x01\x01\x12\x14\n\x07isp_asn\x18\t \x01(\rH\x02\x88\x01\x01\x42\x0b\n\t_geo_hashB\n\n\x08_countryB\n\n\x08_isp_asn\"\xda\x05\n\x0e\x41nalyticsEvent\x12\n\n\x02id\x18\x19 \x01(\t\x12)\n\x04type\x18\x01 \x01(\x0e\x32\x1b.livekit.AnalyticsEventType\x12-\n\ttimestamp\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x0f\n\x07room_id\x18\x03 \x01(\t\x12\x1b\n\x04room\x18\x04 \x01(\x0b\x32\r.livekit.Room\x12\x16\n\x0eparticipant_id\x18\x05 \x01(\t\x12-\n\x0bparticipant\x18\x06 \x01(\x0b\x32\x18.livekit.ParticipantInfo\x12\x10\n\x08track_id\x18\x07 \x01(\t\x12!\n\x05track\x18\x08 \x01(\x0b\x32\x12.livekit.TrackInfo\x12\x15\n\ranalytics_key\x18\n \x01(\t\x12(\n\x0b\x63lient_info\x18\x0b \x01(\x0b\x32\x13.livekit.ClientInfo\x12\x31\n\x0b\x63lient_meta\x18\x0c \x01(\x0b\x32\x1c.livekit.AnalyticsClientMeta\x12\x11\n\tegress_id\x18\r \x01(\t\x12\x12\n\ningress_id\x18\x13 \x01(\t\x12;\n\x1cmax_subscribed_video_quality\x18\x0e \x01(\x0e\x32\x15.livekit.VideoQuality\x12+\n\tpublisher\x18\x0f \x01(\x0b\x32\x18.livekit.ParticipantInfo\x12\x0c\n\x04mime\x18\x10 \x01(\t\x12#\n\x06\x65gress\x18\x11 \x01(\x0b\x32\x13.livekit.EgressInfo\x12%\n\x07ingress\x18\x12 \x01(\x0b\x32\x14.livekit.IngressInfo\x12\r\n\x05\x65rror\x18\x14 \x01(\t\x12$\n\trtp_stats\x18\x15 \x01(\x0b\x32\x11.livekit.RTPStats\x12\x13\n\x0bvideo_layer\x18\x16 \x01(\x05\x12\x0f\n\x07node_id\x18\x18 \x01(\t\":\n\x0f\x41nalyticsEvents\x12\'\n\x06\x65vents\x18\x01 \x03(\x0b\x32\x17.livekit.AnalyticsEvent\"\xa4\x01\n\x18\x41nalyticsRoomParticipant\x12\n\n\x02id\x18\x01 \x01(\t\x12\x10\n\x08identity\x18\x02 \x01(\t\x12\x0c\n\x04name\x18\x03 \x01(\t\x12-\n\x05state\x18\x04 \x01(\x0e\x32\x1e.livekit.ParticipantInfo.State\x12-\n\tjoined_at\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"\xa6\x01\n\rAnalyticsRoom\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x12\n\nproject_id\x18\x05 \x01(\t\x12.\n\ncreated_at\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x37\n\x0cparticipants\x18\x04 \x03(\x0b\x32!.livekit.AnalyticsRoomParticipant\"\x94\x01\n\x12\x41nalyticsNodeRooms\x12\x0f\n\x07node_id\x18\x01 \x01(\t\x12\x17\n\x0fsequence_number\x18\x02 \x01(\x04\x12-\n\ttimestamp\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12%\n\x05rooms\x18\x04 \x03(\x0b\x32\x16.livekit.AnalyticsRoom**\n\nStreamType\x12\x0c\n\x08UPSTREAM\x10\x00\x12\x0e\n\nDOWNSTREAM\x10\x01*\x95\x05\n\x12\x41nalyticsEventType\x12\x10\n\x0cROOM_CREATED\x10\x00\x12\x0e\n\nROOM_ENDED\x10\x01\x12\x16\n\x12PARTICIPANT_JOINED\x10\x02\x12\x14\n\x10PARTICIPANT_LEFT\x10\x03\x12\x13\n\x0fTRACK_PUBLISHED\x10\x04\x12\x1b\n\x17TRACK_PUBLISH_REQUESTED\x10\x14\x12\x15\n\x11TRACK_UNPUBLISHED\x10\x05\x12\x14\n\x10TRACK_SUBSCRIBED\x10\x06\x12\x1d\n\x19TRACK_SUBSCRIBE_REQUESTED\x10\x15\x12\x1a\n\x16TRACK_SUBSCRIBE_FAILED\x10\x19\x12\x16\n\x12TRACK_UNSUBSCRIBED\x10\x07\x12\x1a\n\x16TRACK_PUBLISHED_UPDATE\x10\n\x12\x0f\n\x0bTRACK_MUTED\x10\x17\x12\x11\n\rTRACK_UNMUTED\x10\x18\x12\x17\n\x13TRACK_PUBLISH_STATS\x10\x1a\x12\x19\n\x15TRACK_SUBSCRIBE_STATS\x10\x1b\x12\x16\n\x12PARTICIPANT_ACTIVE\x10\x0b\x12\x17\n\x13PARTICIPANT_RESUMED\x10\x16\x12\x12\n\x0e\x45GRESS_STARTED\x10\x0c\x12\x10\n\x0c\x45GRESS_ENDED\x10\r\x12\x12\n\x0e\x45GRESS_UPDATED\x10\x1c\x12&\n\"TRACK_MAX_SUBSCRIBED_VIDEO_QUALITY\x10\x0e\x12\x0f\n\x0bRECONNECTED\x10\x0f\x12\x13\n\x0fINGRESS_CREATED\x10\x12\x12\x13\n\x0fINGRESS_DELETED\x10\x13\x12\x13\n\x0fINGRESS_STARTED\x10\x10\x12\x11\n\rINGRESS_ENDED\x10\x11\x12\x13\n\x0fINGRESS_UPDATED\x10\x1d\x42\x46Z#github.com/livekit/protocol/livekit\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x17livekit_analytics.proto\x12\x07livekit\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x14livekit_models.proto\x1a\x14livekit_egress.proto\x1a\x15livekit_ingress.proto\x1a\x11livekit_sip.proto\x1a\x12livekit_room.proto\x1a\x14logger/options.proto\"T\n\x13\x41nalyticsVideoLayer\x12\r\n\x05layer\x18\x01 \x01(\x05\x12\x0f\n\x07packets\x18\x02 \x01(\r\x12\r\n\x05\x62ytes\x18\x03 \x01(\x04\x12\x0e\n\x06\x66rames\x18\x04 \x01(\r\"\xd3\x03\n\x0f\x41nalyticsStream\x12\x0c\n\x04ssrc\x18\x01 \x01(\r\x12\x17\n\x0fprimary_packets\x18\x02 \x01(\r\x12\x15\n\rprimary_bytes\x18\x03 \x01(\x04\x12\x1a\n\x12retransmit_packets\x18\x04 \x01(\r\x12\x18\n\x10retransmit_bytes\x18\x05 \x01(\x04\x12\x17\n\x0fpadding_packets\x18\x06 \x01(\r\x12\x15\n\rpadding_bytes\x18\x07 \x01(\x04\x12\x14\n\x0cpackets_lost\x18\x08 \x01(\r\x12\x0e\n\x06\x66rames\x18\t \x01(\r\x12\x0b\n\x03rtt\x18\n \x01(\r\x12\x0e\n\x06jitter\x18\x0b \x01(\r\x12\r\n\x05nacks\x18\x0c \x01(\r\x12\x0c\n\x04plis\x18\r \x01(\r\x12\x0c\n\x04\x66irs\x18\x0e \x01(\r\x12\x32\n\x0cvideo_layers\x18\x0f \x03(\x0b\x32\x1c.livekit.AnalyticsVideoLayer\x12.\n\nstart_time\x18\x11 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12,\n\x08\x65nd_time\x18\x12 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x1c\n\x14packets_out_of_order\x18\x13 \x01(\r\"\xfb\x02\n\rAnalyticsStat\x12\n\n\x02id\x18\x0e \x01(\t\x12\x15\n\ranalytics_key\x18\x01 \x01(\t\x12!\n\x04kind\x18\x02 \x01(\x0e\x32\x13.livekit.StreamType\x12.\n\ntime_stamp\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x0c\n\x04node\x18\x04 \x01(\t\x12\x1a\n\x07room_id\x18\x05 \x01(\tB\t\xbaP\x06roomID\x12\x11\n\troom_name\x18\x06 \x01(\t\x12(\n\x0eparticipant_id\x18\x07 \x01(\tB\x10\xbaP\rparticipantID\x12\x1c\n\x08track_id\x18\x08 \x01(\tB\n\xbaP\x07trackID\x12\r\n\x05score\x18\t \x01(\x02\x12)\n\x07streams\x18\n \x03(\x0b\x32\x18.livekit.AnalyticsStream\x12\x0c\n\x04mime\x18\x0b \x01(\t\x12\x11\n\tmin_score\x18\x0c \x01(\x02\x12\x14\n\x0cmedian_score\x18\r \x01(\x02\"7\n\x0e\x41nalyticsStats\x12%\n\x05stats\x18\x01 \x03(\x0b\x32\x16.livekit.AnalyticsStat\"\x9a\x02\n\x13\x41nalyticsClientMeta\x12\x0e\n\x06region\x18\x01 \x01(\t\x12\x0c\n\x04node\x18\x02 \x01(\t\x12\x13\n\x0b\x63lient_addr\x18\x03 \x01(\t\x12\x1b\n\x13\x63lient_connect_time\x18\x04 \x01(\r\x12\x17\n\x0f\x63onnection_type\x18\x05 \x01(\t\x12\x32\n\x10reconnect_reason\x18\x06 \x01(\x0e\x32\x18.livekit.ReconnectReason\x12\x15\n\x08geo_hash\x18\x07 \x01(\tH\x00\x88\x01\x01\x12\x14\n\x07\x63ountry\x18\x08 \x01(\tH\x01\x88\x01\x01\x12\x14\n\x07isp_asn\x18\t \x01(\rH\x02\x88\x01\x01\x42\x0b\n\t_geo_hashB\n\n\x08_countryB\n\n\x08_isp_asn\"\x9e\n\n\x0e\x41nalyticsEvent\x12\n\n\x02id\x18\x19 \x01(\t\x12)\n\x04type\x18\x01 \x01(\x0e\x32\x1b.livekit.AnalyticsEventType\x12-\n\ttimestamp\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x1a\n\x07room_id\x18\x03 \x01(\tB\t\xbaP\x06roomID\x12\x1b\n\x04room\x18\x04 \x01(\x0b\x32\r.livekit.Room\x12(\n\x0eparticipant_id\x18\x05 \x01(\tB\x10\xbaP\rparticipantID\x12-\n\x0bparticipant\x18\x06 \x01(\x0b\x32\x18.livekit.ParticipantInfo\x12\x1c\n\x08track_id\x18\x07 \x01(\tB\n\xbaP\x07trackID\x12!\n\x05track\x18\x08 \x01(\x0b\x32\x12.livekit.TrackInfo\x12\x15\n\ranalytics_key\x18\n \x01(\t\x12(\n\x0b\x63lient_info\x18\x0b \x01(\x0b\x32\x13.livekit.ClientInfo\x12\x31\n\x0b\x63lient_meta\x18\x0c \x01(\x0b\x32\x1c.livekit.AnalyticsClientMeta\x12\x1e\n\tegress_id\x18\r \x01(\tB\x0b\xbaP\x08\x65gressID\x12 \n\ningress_id\x18\x13 \x01(\tB\x0c\xbaP\tingressID\x12;\n\x1cmax_subscribed_video_quality\x18\x0e \x01(\x0e\x32\x15.livekit.VideoQuality\x12+\n\tpublisher\x18\x0f \x01(\x0b\x32\x18.livekit.ParticipantInfo\x12\x0c\n\x04mime\x18\x10 \x01(\t\x12#\n\x06\x65gress\x18\x11 \x01(\x0b\x32\x13.livekit.EgressInfo\x12%\n\x07ingress\x18\x12 \x01(\x0b\x32\x14.livekit.IngressInfo\x12\r\n\x05\x65rror\x18\x14 \x01(\t\x12$\n\trtp_stats\x18\x15 \x01(\x0b\x32\x11.livekit.RTPStats\x12\x13\n\x0bvideo_layer\x18\x16 \x01(\x05\x12\x1a\n\x07node_id\x18\x18 \x01(\tB\t\xbaP\x06nodeID\x12!\n\x0bsip_call_id\x18\x1a \x01(\tB\x0c\xbaP\tsipCallID\x12&\n\x08sip_call\x18\x1b \x01(\x0b\x32\x14.livekit.SIPCallInfo\x12#\n\x0csip_trunk_id\x18\x1c \x01(\tB\r\xbaP\nsipTrunkID\x12\x37\n\x11sip_inbound_trunk\x18\x1d \x01(\x0b\x32\x1c.livekit.SIPInboundTrunkInfo\x12\x39\n\x12sip_outbound_trunk\x18\x1e \x01(\x0b\x32\x1d.livekit.SIPOutboundTrunkInfo\x12\x32\n\x14sip_dispatch_rule_id\x18\x1f \x01(\tB\x14\xbaP\x11sipDispatchRuleID\x12\x37\n\x11sip_dispatch_rule\x18 \x01(\x0b\x32\x1c.livekit.SIPDispatchRuleInfo\x12.\n\x0csip_transfer\x18$ \x01(\x0b\x32\x18.livekit.SIPTransferInfo\x12#\n\x06report\x18! \x01(\x0b\x32\x13.livekit.ReportInfo\x12&\n\x08\x61pi_call\x18\" \x01(\x0b\x32\x14.livekit.APICallInfo\x12%\n\x07webhook\x18# \x01(\x0b\x32\x14.livekit.WebhookInfo\":\n\x0f\x41nalyticsEvents\x12\'\n\x06\x65vents\x18\x01 \x03(\x0b\x32\x17.livekit.AnalyticsEvent\"\xa4\x01\n\x18\x41nalyticsRoomParticipant\x12\n\n\x02id\x18\x01 \x01(\t\x12\x10\n\x08identity\x18\x02 \x01(\t\x12\x0c\n\x04name\x18\x03 \x01(\t\x12-\n\x05state\x18\x04 \x01(\x0e\x32\x1e.livekit.ParticipantInfo.State\x12-\n\tjoined_at\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"\xb4\x01\n\rAnalyticsRoom\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12 \n\nproject_id\x18\x05 \x01(\tB\x0c\xbaP\tprojectID\x12.\n\ncreated_at\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x37\n\x0cparticipants\x18\x04 \x03(\x0b\x32!.livekit.AnalyticsRoomParticipant\"\x9f\x01\n\x12\x41nalyticsNodeRooms\x12\x1a\n\x07node_id\x18\x01 \x01(\tB\t\xbaP\x06nodeID\x12\x17\n\x0fsequence_number\x18\x02 \x01(\x04\x12-\n\ttimestamp\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12%\n\x05rooms\x18\x04 \x03(\x0b\x32\x16.livekit.AnalyticsRoom\"K\n\nReportInfo\x12\x32\n\rfeature_usage\x18\x01 \x01(\x0b\x32\x19.livekit.FeatureUsageInfoH\x00\x42\t\n\x07message\"i\n\tTimeRange\x12.\n\nstarted_at\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12,\n\x08\x65nded_at\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"\x89\x04\n\x10\x46\x65\x61tureUsageInfo\x12\x32\n\x07\x66\x65\x61ture\x18\x01 \x01(\x0e\x32!.livekit.FeatureUsageInfo.Feature\x12 \n\nproject_id\x18\x02 \x01(\tB\x0c\xbaP\tprojectID\x12\x11\n\troom_name\x18\x03 \x01(\t\x12\x1a\n\x07room_id\x18\x04 \x01(\tB\t\xbaP\x06roomID\x12\x1c\n\x14participant_identity\x18\x05 \x01(\t\x12(\n\x0eparticipant_id\x18\x06 \x01(\tB\x10\xbaP\rparticipantID\x12\x1c\n\x08track_id\x18\x07 \x01(\tB\n\xbaP\x07trackID\x12\'\n\x0btime_ranges\x18\x08 \x03(\x0b\x32\x12.livekit.TimeRange\x12@\n\x0c\x66\x65\x61ture_info\x18\t \x03(\x0b\x32*.livekit.FeatureUsageInfo.FeatureInfoEntry\x1a\x32\n\x10\x46\x65\x61tureInfoEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"k\n\x07\x46\x65\x61ture\x12\x1c\n\x18KRISP_NOISE_CANCELLATION\x10\x00\x12\'\n#KRISP_BACKGROUND_VOICE_CANCELLATION\x10\x01\x12\x19\n\x15\x41IC_AUDIO_ENHANCEMENT\x10\x02\"\xb3\x05\n\x0e\x41PICallRequest\x12\x39\n\x13\x63reate_room_request\x18\x01 \x01(\x0b\x32\x1a.livekit.CreateRoomRequestH\x00\x12\x37\n\x12list_rooms_request\x18\x02 \x01(\x0b\x32\x19.livekit.ListRoomsRequestH\x00\x12\x39\n\x13\x64\x65lete_room_request\x18\x03 \x01(\x0b\x32\x1a.livekit.DeleteRoomRequestH\x00\x12\x45\n\x19list_participants_request\x18\x04 \x01(\x0b\x32 .livekit.ListParticipantsRequestH\x00\x12\x45\n\x19room_participant_identity\x18\x05 \x01(\x0b\x32 .livekit.RoomParticipantIdentityH\x00\x12@\n\x17mute_room_track_request\x18\x06 \x01(\x0b\x32\x1d.livekit.MuteRoomTrackRequestH\x00\x12G\n\x1aupdate_participant_request\x18\x07 \x01(\x0b\x32!.livekit.UpdateParticipantRequestH\x00\x12K\n\x1cupdate_subscriptions_request\x18\x08 \x01(\x0b\x32#.livekit.UpdateSubscriptionsRequestH\x00\x12\x35\n\x11send_data_request\x18\t \x01(\x0b\x32\x18.livekit.SendDataRequestH\x00\x12J\n\x1cupdate_room_metadata_request\x18\n \x01(\x0b\x32\".livekit.UpdateRoomMetadataRequestH\x00\x42\t\n\x07message\"\xb7\x03\n\x0b\x41PICallInfo\x12 \n\nproject_id\x18\x01 \x01(\tB\x0c\xbaP\tprojectID\x12(\n\x07request\x18\x02 \x01(\x0b\x32\x17.livekit.APICallRequest\x12\x0f\n\x07service\x18\x03 \x01(\t\x12\x0e\n\x06method\x18\x04 \x01(\t\x12\x1a\n\x07node_id\x18\x05 \x01(\tB\t\xbaP\x06nodeID\x12\x0e\n\x06status\x18\x06 \x01(\x05\x12\x18\n\x10twirp_error_code\x18\x07 \x01(\t\x12\x1b\n\x13twirp_error_message\x18\x08 \x01(\t\x12\x11\n\troom_name\x18\t \x01(\t\x12\x1a\n\x07room_id\x18\n \x01(\tB\t\xbaP\x06roomID\x12\x1c\n\x14participant_identity\x18\x0b \x01(\t\x12(\n\x0eparticipant_id\x18\x0c \x01(\tB\x10\xbaP\rparticipantID\x12\x1c\n\x08track_id\x18\r \x01(\tB\n\xbaP\x07trackID\x12.\n\nstarted_at\x18\x0e \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x13\n\x0b\x64uration_ns\x18\x0f \x01(\x03\"\x89\x05\n\x0bWebhookInfo\x12\x1c\n\x08\x65vent_id\x18\x01 \x01(\tB\n\xbaP\x07\x65ventID\x12\r\n\x05\x65vent\x18\x02 \x01(\t\x12 \n\nproject_id\x18\x03 \x01(\tB\x0c\xbaP\tprojectID\x12\x11\n\troom_name\x18\x04 \x01(\t\x12\x1a\n\x07room_id\x18\x05 \x01(\tB\t\xbaP\x06roomID\x12\x1c\n\x14participant_identity\x18\x06 \x01(\t\x12(\n\x0eparticipant_id\x18\x07 \x01(\tB\x10\xbaP\rparticipantID\x12\x1c\n\x08track_id\x18\x08 \x01(\tB\n\xbaP\x07trackID\x12\x1e\n\tegress_id\x18\t \x01(\tB\x0b\xbaP\x08\x65gressID\x12 \n\ningress_id\x18\n \x01(\tB\x0c\xbaP\tingressID\x12.\n\ncreated_at\x18\x0b \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12-\n\tqueued_at\x18\x0c \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x19\n\x11queue_duration_ns\x18\r \x01(\x03\x12+\n\x07sent_at\x18\x0e \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x18\n\x10send_duration_ns\x18\x0f \x01(\x03\x12\x0b\n\x03url\x18\x10 \x01(\t\x12\x13\n\x0bnum_dropped\x18\x11 \x01(\x05\x12\x12\n\nis_dropped\x18\x12 \x01(\x08\x12\x16\n\x0eservice_status\x18\x13 \x01(\t\x12\x1a\n\x12service_error_code\x18\x14 \x01(\x05\x12\x15\n\rservice_error\x18\x15 \x01(\t\x12\x12\n\nsend_error\x18\x16 \x01(\t**\n\nStreamType\x12\x0c\n\x08UPSTREAM\x10\x00\x12\x0e\n\nDOWNSTREAM\x10\x01*\xc6\x08\n\x12\x41nalyticsEventType\x12\x10\n\x0cROOM_CREATED\x10\x00\x12\x0e\n\nROOM_ENDED\x10\x01\x12\x16\n\x12PARTICIPANT_JOINED\x10\x02\x12\x14\n\x10PARTICIPANT_LEFT\x10\x03\x12\"\n\x1ePARTICIPANT_CONNECTION_ABORTED\x10-\x12\x13\n\x0fTRACK_PUBLISHED\x10\x04\x12\x1b\n\x17TRACK_PUBLISH_REQUESTED\x10\x14\x12\x15\n\x11TRACK_UNPUBLISHED\x10\x05\x12\x14\n\x10TRACK_SUBSCRIBED\x10\x06\x12\x1d\n\x19TRACK_SUBSCRIBE_REQUESTED\x10\x15\x12\x1a\n\x16TRACK_SUBSCRIBE_FAILED\x10\x19\x12\x16\n\x12TRACK_UNSUBSCRIBED\x10\x07\x12\x1a\n\x16TRACK_PUBLISHED_UPDATE\x10\n\x12\x0f\n\x0bTRACK_MUTED\x10\x17\x12\x11\n\rTRACK_UNMUTED\x10\x18\x12\x17\n\x13TRACK_PUBLISH_STATS\x10\x1a\x12\x19\n\x15TRACK_SUBSCRIBE_STATS\x10\x1b\x12\x16\n\x12PARTICIPANT_ACTIVE\x10\x0b\x12\x17\n\x13PARTICIPANT_RESUMED\x10\x16\x12\x12\n\x0e\x45GRESS_STARTED\x10\x0c\x12\x10\n\x0c\x45GRESS_ENDED\x10\r\x12\x12\n\x0e\x45GRESS_UPDATED\x10\x1c\x12&\n\"TRACK_MAX_SUBSCRIBED_VIDEO_QUALITY\x10\x0e\x12\x0f\n\x0bRECONNECTED\x10\x0f\x12\x13\n\x0fINGRESS_CREATED\x10\x12\x12\x13\n\x0fINGRESS_DELETED\x10\x13\x12\x13\n\x0fINGRESS_STARTED\x10\x10\x12\x11\n\rINGRESS_ENDED\x10\x11\x12\x13\n\x0fINGRESS_UPDATED\x10\x1d\x12\x1d\n\x19SIP_INBOUND_TRUNK_CREATED\x10\x1e\x12\x1d\n\x19SIP_INBOUND_TRUNK_DELETED\x10\x1f\x12\x1e\n\x1aSIP_OUTBOUND_TRUNK_CREATED\x10 \x12\x1e\n\x1aSIP_OUTBOUND_TRUNK_DELETED\x10!\x12\x1d\n\x19SIP_DISPATCH_RULE_CREATED\x10\"\x12\x1d\n\x19SIP_DISPATCH_RULE_DELETED\x10#\x12\x1b\n\x17SIP_PARTICIPANT_CREATED\x10$\x12\x15\n\x11SIP_CALL_INCOMING\x10%\x12\x14\n\x10SIP_CALL_STARTED\x10&\x12\x12\n\x0eSIP_CALL_ENDED\x10\'\x12\x1a\n\x16SIP_TRANSFER_REQUESTED\x10+\x12\x19\n\x15SIP_TRANSFER_COMPLETE\x10,\x12\x13\n\x0fSIP_CALL_UPDATE\x10.\x12\n\n\x06REPORT\x10(\x12\x0c\n\x08\x41PI_CALL\x10)\x12\x0b\n\x07WEBHOOK\x10*BFZ#github.com/livekit/protocol/livekit\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -26,28 +29,106 @@
if _descriptor._USE_C_DESCRIPTORS == False:
_globals['DESCRIPTOR']._options = None
_globals['DESCRIPTOR']._serialized_options = b'Z#github.com/livekit/protocol/livekit\252\002\rLiveKit.Proto\352\002\016LiveKit::Proto'
- _globals['_STREAMTYPE']._serialized_start=2625
- _globals['_STREAMTYPE']._serialized_end=2667
- _globals['_ANALYTICSEVENTTYPE']._serialized_start=2670
- _globals['_ANALYTICSEVENTTYPE']._serialized_end=3331
- _globals['_ANALYTICSVIDEOLAYER']._serialized_start=136
- _globals['_ANALYTICSVIDEOLAYER']._serialized_end=220
- _globals['_ANALYTICSSTREAM']._serialized_start=223
- _globals['_ANALYTICSSTREAM']._serialized_end=660
- _globals['_ANALYTICSSTAT']._serialized_start=663
- _globals['_ANALYTICSSTAT']._serialized_end=1001
- _globals['_ANALYTICSSTATS']._serialized_start=1003
- _globals['_ANALYTICSSTATS']._serialized_end=1058
- _globals['_ANALYTICSCLIENTMETA']._serialized_start=1061
- _globals['_ANALYTICSCLIENTMETA']._serialized_end=1343
- _globals['_ANALYTICSEVENT']._serialized_start=1346
- _globals['_ANALYTICSEVENT']._serialized_end=2076
- _globals['_ANALYTICSEVENTS']._serialized_start=2078
- _globals['_ANALYTICSEVENTS']._serialized_end=2136
- _globals['_ANALYTICSROOMPARTICIPANT']._serialized_start=2139
- _globals['_ANALYTICSROOMPARTICIPANT']._serialized_end=2303
- _globals['_ANALYTICSROOM']._serialized_start=2306
- _globals['_ANALYTICSROOM']._serialized_end=2472
- _globals['_ANALYTICSNODEROOMS']._serialized_start=2475
- _globals['_ANALYTICSNODEROOMS']._serialized_end=2623
+ _globals['_ANALYTICSSTAT'].fields_by_name['room_id']._options = None
+ _globals['_ANALYTICSSTAT'].fields_by_name['room_id']._serialized_options = b'\272P\006roomID'
+ _globals['_ANALYTICSSTAT'].fields_by_name['participant_id']._options = None
+ _globals['_ANALYTICSSTAT'].fields_by_name['participant_id']._serialized_options = b'\272P\rparticipantID'
+ _globals['_ANALYTICSSTAT'].fields_by_name['track_id']._options = None
+ _globals['_ANALYTICSSTAT'].fields_by_name['track_id']._serialized_options = b'\272P\007trackID'
+ _globals['_ANALYTICSEVENT'].fields_by_name['room_id']._options = None
+ _globals['_ANALYTICSEVENT'].fields_by_name['room_id']._serialized_options = b'\272P\006roomID'
+ _globals['_ANALYTICSEVENT'].fields_by_name['participant_id']._options = None
+ _globals['_ANALYTICSEVENT'].fields_by_name['participant_id']._serialized_options = b'\272P\rparticipantID'
+ _globals['_ANALYTICSEVENT'].fields_by_name['track_id']._options = None
+ _globals['_ANALYTICSEVENT'].fields_by_name['track_id']._serialized_options = b'\272P\007trackID'
+ _globals['_ANALYTICSEVENT'].fields_by_name['egress_id']._options = None
+ _globals['_ANALYTICSEVENT'].fields_by_name['egress_id']._serialized_options = b'\272P\010egressID'
+ _globals['_ANALYTICSEVENT'].fields_by_name['ingress_id']._options = None
+ _globals['_ANALYTICSEVENT'].fields_by_name['ingress_id']._serialized_options = b'\272P\tingressID'
+ _globals['_ANALYTICSEVENT'].fields_by_name['node_id']._options = None
+ _globals['_ANALYTICSEVENT'].fields_by_name['node_id']._serialized_options = b'\272P\006nodeID'
+ _globals['_ANALYTICSEVENT'].fields_by_name['sip_call_id']._options = None
+ _globals['_ANALYTICSEVENT'].fields_by_name['sip_call_id']._serialized_options = b'\272P\tsipCallID'
+ _globals['_ANALYTICSEVENT'].fields_by_name['sip_trunk_id']._options = None
+ _globals['_ANALYTICSEVENT'].fields_by_name['sip_trunk_id']._serialized_options = b'\272P\nsipTrunkID'
+ _globals['_ANALYTICSEVENT'].fields_by_name['sip_dispatch_rule_id']._options = None
+ _globals['_ANALYTICSEVENT'].fields_by_name['sip_dispatch_rule_id']._serialized_options = b'\272P\021sipDispatchRuleID'
+ _globals['_ANALYTICSROOM'].fields_by_name['project_id']._options = None
+ _globals['_ANALYTICSROOM'].fields_by_name['project_id']._serialized_options = b'\272P\tprojectID'
+ _globals['_ANALYTICSNODEROOMS'].fields_by_name['node_id']._options = None
+ _globals['_ANALYTICSNODEROOMS'].fields_by_name['node_id']._serialized_options = b'\272P\006nodeID'
+ _globals['_FEATUREUSAGEINFO_FEATUREINFOENTRY']._options = None
+ _globals['_FEATUREUSAGEINFO_FEATUREINFOENTRY']._serialized_options = b'8\001'
+ _globals['_FEATUREUSAGEINFO'].fields_by_name['project_id']._options = None
+ _globals['_FEATUREUSAGEINFO'].fields_by_name['project_id']._serialized_options = b'\272P\tprojectID'
+ _globals['_FEATUREUSAGEINFO'].fields_by_name['room_id']._options = None
+ _globals['_FEATUREUSAGEINFO'].fields_by_name['room_id']._serialized_options = b'\272P\006roomID'
+ _globals['_FEATUREUSAGEINFO'].fields_by_name['participant_id']._options = None
+ _globals['_FEATUREUSAGEINFO'].fields_by_name['participant_id']._serialized_options = b'\272P\rparticipantID'
+ _globals['_FEATUREUSAGEINFO'].fields_by_name['track_id']._options = None
+ _globals['_FEATUREUSAGEINFO'].fields_by_name['track_id']._serialized_options = b'\272P\007trackID'
+ _globals['_APICALLINFO'].fields_by_name['project_id']._options = None
+ _globals['_APICALLINFO'].fields_by_name['project_id']._serialized_options = b'\272P\tprojectID'
+ _globals['_APICALLINFO'].fields_by_name['node_id']._options = None
+ _globals['_APICALLINFO'].fields_by_name['node_id']._serialized_options = b'\272P\006nodeID'
+ _globals['_APICALLINFO'].fields_by_name['room_id']._options = None
+ _globals['_APICALLINFO'].fields_by_name['room_id']._serialized_options = b'\272P\006roomID'
+ _globals['_APICALLINFO'].fields_by_name['participant_id']._options = None
+ _globals['_APICALLINFO'].fields_by_name['participant_id']._serialized_options = b'\272P\rparticipantID'
+ _globals['_APICALLINFO'].fields_by_name['track_id']._options = None
+ _globals['_APICALLINFO'].fields_by_name['track_id']._serialized_options = b'\272P\007trackID'
+ _globals['_WEBHOOKINFO'].fields_by_name['event_id']._options = None
+ _globals['_WEBHOOKINFO'].fields_by_name['event_id']._serialized_options = b'\272P\007eventID'
+ _globals['_WEBHOOKINFO'].fields_by_name['project_id']._options = None
+ _globals['_WEBHOOKINFO'].fields_by_name['project_id']._serialized_options = b'\272P\tprojectID'
+ _globals['_WEBHOOKINFO'].fields_by_name['room_id']._options = None
+ _globals['_WEBHOOKINFO'].fields_by_name['room_id']._serialized_options = b'\272P\006roomID'
+ _globals['_WEBHOOKINFO'].fields_by_name['participant_id']._options = None
+ _globals['_WEBHOOKINFO'].fields_by_name['participant_id']._serialized_options = b'\272P\rparticipantID'
+ _globals['_WEBHOOKINFO'].fields_by_name['track_id']._options = None
+ _globals['_WEBHOOKINFO'].fields_by_name['track_id']._serialized_options = b'\272P\007trackID'
+ _globals['_WEBHOOKINFO'].fields_by_name['egress_id']._options = None
+ _globals['_WEBHOOKINFO'].fields_by_name['egress_id']._serialized_options = b'\272P\010egressID'
+ _globals['_WEBHOOKINFO'].fields_by_name['ingress_id']._options = None
+ _globals['_WEBHOOKINFO'].fields_by_name['ingress_id']._serialized_options = b'\272P\tingressID'
+ _globals['_STREAMTYPE']._serialized_start=5858
+ _globals['_STREAMTYPE']._serialized_end=5900
+ _globals['_ANALYTICSEVENTTYPE']._serialized_start=5903
+ _globals['_ANALYTICSEVENTTYPE']._serialized_end=6997
+ _globals['_ANALYTICSVIDEOLAYER']._serialized_start=197
+ _globals['_ANALYTICSVIDEOLAYER']._serialized_end=281
+ _globals['_ANALYTICSSTREAM']._serialized_start=284
+ _globals['_ANALYTICSSTREAM']._serialized_end=751
+ _globals['_ANALYTICSSTAT']._serialized_start=754
+ _globals['_ANALYTICSSTAT']._serialized_end=1133
+ _globals['_ANALYTICSSTATS']._serialized_start=1135
+ _globals['_ANALYTICSSTATS']._serialized_end=1190
+ _globals['_ANALYTICSCLIENTMETA']._serialized_start=1193
+ _globals['_ANALYTICSCLIENTMETA']._serialized_end=1475
+ _globals['_ANALYTICSEVENT']._serialized_start=1478
+ _globals['_ANALYTICSEVENT']._serialized_end=2788
+ _globals['_ANALYTICSEVENTS']._serialized_start=2790
+ _globals['_ANALYTICSEVENTS']._serialized_end=2848
+ _globals['_ANALYTICSROOMPARTICIPANT']._serialized_start=2851
+ _globals['_ANALYTICSROOMPARTICIPANT']._serialized_end=3015
+ _globals['_ANALYTICSROOM']._serialized_start=3018
+ _globals['_ANALYTICSROOM']._serialized_end=3198
+ _globals['_ANALYTICSNODEROOMS']._serialized_start=3201
+ _globals['_ANALYTICSNODEROOMS']._serialized_end=3360
+ _globals['_REPORTINFO']._serialized_start=3362
+ _globals['_REPORTINFO']._serialized_end=3437
+ _globals['_TIMERANGE']._serialized_start=3439
+ _globals['_TIMERANGE']._serialized_end=3544
+ _globals['_FEATUREUSAGEINFO']._serialized_start=3547
+ _globals['_FEATUREUSAGEINFO']._serialized_end=4068
+ _globals['_FEATUREUSAGEINFO_FEATUREINFOENTRY']._serialized_start=3909
+ _globals['_FEATUREUSAGEINFO_FEATUREINFOENTRY']._serialized_end=3959
+ _globals['_FEATUREUSAGEINFO_FEATURE']._serialized_start=3961
+ _globals['_FEATUREUSAGEINFO_FEATURE']._serialized_end=4068
+ _globals['_APICALLREQUEST']._serialized_start=4071
+ _globals['_APICALLREQUEST']._serialized_end=4762
+ _globals['_APICALLINFO']._serialized_start=4765
+ _globals['_APICALLINFO']._serialized_end=5204
+ _globals['_WEBHOOKINFO']._serialized_start=5207
+ _globals['_WEBHOOKINFO']._serialized_end=5856
# @@protoc_insertion_point(module_scope)
diff --git a/livekit-protocol/livekit/protocol/analytics.pyi b/livekit-protocol/livekit/protocol/analytics.pyi
index 30cfbd50..d9805772 100644
--- a/livekit-protocol/livekit/protocol/analytics.pyi
+++ b/livekit-protocol/livekit/protocol/analytics.pyi
@@ -2,6 +2,9 @@ from google.protobuf import timestamp_pb2 as _timestamp_pb2
from . import models as _models
from . import egress as _egress
from . import ingress as _ingress
+from . import sip as _sip
+from . import room as _room
+from .logger_pb import options as _options_pb2
from google.protobuf.internal import containers as _containers
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
from google.protobuf import descriptor as _descriptor
@@ -21,6 +24,7 @@ class AnalyticsEventType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
ROOM_ENDED: _ClassVar[AnalyticsEventType]
PARTICIPANT_JOINED: _ClassVar[AnalyticsEventType]
PARTICIPANT_LEFT: _ClassVar[AnalyticsEventType]
+ PARTICIPANT_CONNECTION_ABORTED: _ClassVar[AnalyticsEventType]
TRACK_PUBLISHED: _ClassVar[AnalyticsEventType]
TRACK_PUBLISH_REQUESTED: _ClassVar[AnalyticsEventType]
TRACK_UNPUBLISHED: _ClassVar[AnalyticsEventType]
@@ -45,12 +49,29 @@ class AnalyticsEventType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
INGRESS_STARTED: _ClassVar[AnalyticsEventType]
INGRESS_ENDED: _ClassVar[AnalyticsEventType]
INGRESS_UPDATED: _ClassVar[AnalyticsEventType]
+ SIP_INBOUND_TRUNK_CREATED: _ClassVar[AnalyticsEventType]
+ SIP_INBOUND_TRUNK_DELETED: _ClassVar[AnalyticsEventType]
+ SIP_OUTBOUND_TRUNK_CREATED: _ClassVar[AnalyticsEventType]
+ SIP_OUTBOUND_TRUNK_DELETED: _ClassVar[AnalyticsEventType]
+ SIP_DISPATCH_RULE_CREATED: _ClassVar[AnalyticsEventType]
+ SIP_DISPATCH_RULE_DELETED: _ClassVar[AnalyticsEventType]
+ SIP_PARTICIPANT_CREATED: _ClassVar[AnalyticsEventType]
+ SIP_CALL_INCOMING: _ClassVar[AnalyticsEventType]
+ SIP_CALL_STARTED: _ClassVar[AnalyticsEventType]
+ SIP_CALL_ENDED: _ClassVar[AnalyticsEventType]
+ SIP_TRANSFER_REQUESTED: _ClassVar[AnalyticsEventType]
+ SIP_TRANSFER_COMPLETE: _ClassVar[AnalyticsEventType]
+ SIP_CALL_UPDATE: _ClassVar[AnalyticsEventType]
+ REPORT: _ClassVar[AnalyticsEventType]
+ API_CALL: _ClassVar[AnalyticsEventType]
+ WEBHOOK: _ClassVar[AnalyticsEventType]
UPSTREAM: StreamType
DOWNSTREAM: StreamType
ROOM_CREATED: AnalyticsEventType
ROOM_ENDED: AnalyticsEventType
PARTICIPANT_JOINED: AnalyticsEventType
PARTICIPANT_LEFT: AnalyticsEventType
+PARTICIPANT_CONNECTION_ABORTED: AnalyticsEventType
TRACK_PUBLISHED: AnalyticsEventType
TRACK_PUBLISH_REQUESTED: AnalyticsEventType
TRACK_UNPUBLISHED: AnalyticsEventType
@@ -75,6 +96,22 @@ INGRESS_DELETED: AnalyticsEventType
INGRESS_STARTED: AnalyticsEventType
INGRESS_ENDED: AnalyticsEventType
INGRESS_UPDATED: AnalyticsEventType
+SIP_INBOUND_TRUNK_CREATED: AnalyticsEventType
+SIP_INBOUND_TRUNK_DELETED: AnalyticsEventType
+SIP_OUTBOUND_TRUNK_CREATED: AnalyticsEventType
+SIP_OUTBOUND_TRUNK_DELETED: AnalyticsEventType
+SIP_DISPATCH_RULE_CREATED: AnalyticsEventType
+SIP_DISPATCH_RULE_DELETED: AnalyticsEventType
+SIP_PARTICIPANT_CREATED: AnalyticsEventType
+SIP_CALL_INCOMING: AnalyticsEventType
+SIP_CALL_STARTED: AnalyticsEventType
+SIP_CALL_ENDED: AnalyticsEventType
+SIP_TRANSFER_REQUESTED: AnalyticsEventType
+SIP_TRANSFER_COMPLETE: AnalyticsEventType
+SIP_CALL_UPDATE: AnalyticsEventType
+REPORT: AnalyticsEventType
+API_CALL: AnalyticsEventType
+WEBHOOK: AnalyticsEventType
class AnalyticsVideoLayer(_message.Message):
__slots__ = ("layer", "packets", "bytes", "frames")
@@ -89,7 +126,7 @@ class AnalyticsVideoLayer(_message.Message):
def __init__(self, layer: _Optional[int] = ..., packets: _Optional[int] = ..., bytes: _Optional[int] = ..., frames: _Optional[int] = ...) -> None: ...
class AnalyticsStream(_message.Message):
- __slots__ = ("ssrc", "primary_packets", "primary_bytes", "retransmit_packets", "retransmit_bytes", "padding_packets", "padding_bytes", "packets_lost", "frames", "rtt", "jitter", "nacks", "plis", "firs", "video_layers", "start_time", "end_time")
+ __slots__ = ("ssrc", "primary_packets", "primary_bytes", "retransmit_packets", "retransmit_bytes", "padding_packets", "padding_bytes", "packets_lost", "frames", "rtt", "jitter", "nacks", "plis", "firs", "video_layers", "start_time", "end_time", "packets_out_of_order")
SSRC_FIELD_NUMBER: _ClassVar[int]
PRIMARY_PACKETS_FIELD_NUMBER: _ClassVar[int]
PRIMARY_BYTES_FIELD_NUMBER: _ClassVar[int]
@@ -107,6 +144,7 @@ class AnalyticsStream(_message.Message):
VIDEO_LAYERS_FIELD_NUMBER: _ClassVar[int]
START_TIME_FIELD_NUMBER: _ClassVar[int]
END_TIME_FIELD_NUMBER: _ClassVar[int]
+ PACKETS_OUT_OF_ORDER_FIELD_NUMBER: _ClassVar[int]
ssrc: int
primary_packets: int
primary_bytes: int
@@ -124,7 +162,8 @@ class AnalyticsStream(_message.Message):
video_layers: _containers.RepeatedCompositeFieldContainer[AnalyticsVideoLayer]
start_time: _timestamp_pb2.Timestamp
end_time: _timestamp_pb2.Timestamp
- def __init__(self, ssrc: _Optional[int] = ..., primary_packets: _Optional[int] = ..., primary_bytes: _Optional[int] = ..., retransmit_packets: _Optional[int] = ..., retransmit_bytes: _Optional[int] = ..., padding_packets: _Optional[int] = ..., padding_bytes: _Optional[int] = ..., packets_lost: _Optional[int] = ..., frames: _Optional[int] = ..., rtt: _Optional[int] = ..., jitter: _Optional[int] = ..., nacks: _Optional[int] = ..., plis: _Optional[int] = ..., firs: _Optional[int] = ..., video_layers: _Optional[_Iterable[_Union[AnalyticsVideoLayer, _Mapping]]] = ..., start_time: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., end_time: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ...) -> None: ...
+ packets_out_of_order: int
+ def __init__(self, ssrc: _Optional[int] = ..., primary_packets: _Optional[int] = ..., primary_bytes: _Optional[int] = ..., retransmit_packets: _Optional[int] = ..., retransmit_bytes: _Optional[int] = ..., padding_packets: _Optional[int] = ..., padding_bytes: _Optional[int] = ..., packets_lost: _Optional[int] = ..., frames: _Optional[int] = ..., rtt: _Optional[int] = ..., jitter: _Optional[int] = ..., nacks: _Optional[int] = ..., plis: _Optional[int] = ..., firs: _Optional[int] = ..., video_layers: _Optional[_Iterable[_Union[AnalyticsVideoLayer, _Mapping]]] = ..., start_time: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., end_time: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., packets_out_of_order: _Optional[int] = ...) -> None: ...
class AnalyticsStat(_message.Message):
__slots__ = ("id", "analytics_key", "kind", "time_stamp", "node", "room_id", "room_name", "participant_id", "track_id", "score", "streams", "mime", "min_score", "median_score")
@@ -187,7 +226,7 @@ class AnalyticsClientMeta(_message.Message):
def __init__(self, region: _Optional[str] = ..., node: _Optional[str] = ..., client_addr: _Optional[str] = ..., client_connect_time: _Optional[int] = ..., connection_type: _Optional[str] = ..., reconnect_reason: _Optional[_Union[_models.ReconnectReason, str]] = ..., geo_hash: _Optional[str] = ..., country: _Optional[str] = ..., isp_asn: _Optional[int] = ...) -> None: ...
class AnalyticsEvent(_message.Message):
- __slots__ = ("id", "type", "timestamp", "room_id", "room", "participant_id", "participant", "track_id", "track", "analytics_key", "client_info", "client_meta", "egress_id", "ingress_id", "max_subscribed_video_quality", "publisher", "mime", "egress", "ingress", "error", "rtp_stats", "video_layer", "node_id")
+ __slots__ = ("id", "type", "timestamp", "room_id", "room", "participant_id", "participant", "track_id", "track", "analytics_key", "client_info", "client_meta", "egress_id", "ingress_id", "max_subscribed_video_quality", "publisher", "mime", "egress", "ingress", "error", "rtp_stats", "video_layer", "node_id", "sip_call_id", "sip_call", "sip_trunk_id", "sip_inbound_trunk", "sip_outbound_trunk", "sip_dispatch_rule_id", "sip_dispatch_rule", "sip_transfer", "report", "api_call", "webhook")
ID_FIELD_NUMBER: _ClassVar[int]
TYPE_FIELD_NUMBER: _ClassVar[int]
TIMESTAMP_FIELD_NUMBER: _ClassVar[int]
@@ -211,6 +250,17 @@ class AnalyticsEvent(_message.Message):
RTP_STATS_FIELD_NUMBER: _ClassVar[int]
VIDEO_LAYER_FIELD_NUMBER: _ClassVar[int]
NODE_ID_FIELD_NUMBER: _ClassVar[int]
+ SIP_CALL_ID_FIELD_NUMBER: _ClassVar[int]
+ SIP_CALL_FIELD_NUMBER: _ClassVar[int]
+ SIP_TRUNK_ID_FIELD_NUMBER: _ClassVar[int]
+ SIP_INBOUND_TRUNK_FIELD_NUMBER: _ClassVar[int]
+ SIP_OUTBOUND_TRUNK_FIELD_NUMBER: _ClassVar[int]
+ SIP_DISPATCH_RULE_ID_FIELD_NUMBER: _ClassVar[int]
+ SIP_DISPATCH_RULE_FIELD_NUMBER: _ClassVar[int]
+ SIP_TRANSFER_FIELD_NUMBER: _ClassVar[int]
+ REPORT_FIELD_NUMBER: _ClassVar[int]
+ API_CALL_FIELD_NUMBER: _ClassVar[int]
+ WEBHOOK_FIELD_NUMBER: _ClassVar[int]
id: str
type: AnalyticsEventType
timestamp: _timestamp_pb2.Timestamp
@@ -234,7 +284,18 @@ class AnalyticsEvent(_message.Message):
rtp_stats: _models.RTPStats
video_layer: int
node_id: str
- def __init__(self, id: _Optional[str] = ..., type: _Optional[_Union[AnalyticsEventType, str]] = ..., timestamp: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., room_id: _Optional[str] = ..., room: _Optional[_Union[_models.Room, _Mapping]] = ..., participant_id: _Optional[str] = ..., participant: _Optional[_Union[_models.ParticipantInfo, _Mapping]] = ..., track_id: _Optional[str] = ..., track: _Optional[_Union[_models.TrackInfo, _Mapping]] = ..., analytics_key: _Optional[str] = ..., client_info: _Optional[_Union[_models.ClientInfo, _Mapping]] = ..., client_meta: _Optional[_Union[AnalyticsClientMeta, _Mapping]] = ..., egress_id: _Optional[str] = ..., ingress_id: _Optional[str] = ..., max_subscribed_video_quality: _Optional[_Union[_models.VideoQuality, str]] = ..., publisher: _Optional[_Union[_models.ParticipantInfo, _Mapping]] = ..., mime: _Optional[str] = ..., egress: _Optional[_Union[_egress.EgressInfo, _Mapping]] = ..., ingress: _Optional[_Union[_ingress.IngressInfo, _Mapping]] = ..., error: _Optional[str] = ..., rtp_stats: _Optional[_Union[_models.RTPStats, _Mapping]] = ..., video_layer: _Optional[int] = ..., node_id: _Optional[str] = ...) -> None: ...
+ sip_call_id: str
+ sip_call: _sip.SIPCallInfo
+ sip_trunk_id: str
+ sip_inbound_trunk: _sip.SIPInboundTrunkInfo
+ sip_outbound_trunk: _sip.SIPOutboundTrunkInfo
+ sip_dispatch_rule_id: str
+ sip_dispatch_rule: _sip.SIPDispatchRuleInfo
+ sip_transfer: _sip.SIPTransferInfo
+ report: ReportInfo
+ api_call: APICallInfo
+ webhook: WebhookInfo
+ def __init__(self, id: _Optional[str] = ..., type: _Optional[_Union[AnalyticsEventType, str]] = ..., timestamp: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., room_id: _Optional[str] = ..., room: _Optional[_Union[_models.Room, _Mapping]] = ..., participant_id: _Optional[str] = ..., participant: _Optional[_Union[_models.ParticipantInfo, _Mapping]] = ..., track_id: _Optional[str] = ..., track: _Optional[_Union[_models.TrackInfo, _Mapping]] = ..., analytics_key: _Optional[str] = ..., client_info: _Optional[_Union[_models.ClientInfo, _Mapping]] = ..., client_meta: _Optional[_Union[AnalyticsClientMeta, _Mapping]] = ..., egress_id: _Optional[str] = ..., ingress_id: _Optional[str] = ..., max_subscribed_video_quality: _Optional[_Union[_models.VideoQuality, str]] = ..., publisher: _Optional[_Union[_models.ParticipantInfo, _Mapping]] = ..., mime: _Optional[str] = ..., egress: _Optional[_Union[_egress.EgressInfo, _Mapping]] = ..., ingress: _Optional[_Union[_ingress.IngressInfo, _Mapping]] = ..., error: _Optional[str] = ..., rtp_stats: _Optional[_Union[_models.RTPStats, _Mapping]] = ..., video_layer: _Optional[int] = ..., node_id: _Optional[str] = ..., sip_call_id: _Optional[str] = ..., sip_call: _Optional[_Union[_sip.SIPCallInfo, _Mapping]] = ..., sip_trunk_id: _Optional[str] = ..., sip_inbound_trunk: _Optional[_Union[_sip.SIPInboundTrunkInfo, _Mapping]] = ..., sip_outbound_trunk: _Optional[_Union[_sip.SIPOutboundTrunkInfo, _Mapping]] = ..., sip_dispatch_rule_id: _Optional[str] = ..., sip_dispatch_rule: _Optional[_Union[_sip.SIPDispatchRuleInfo, _Mapping]] = ..., sip_transfer: _Optional[_Union[_sip.SIPTransferInfo, _Mapping]] = ..., report: _Optional[_Union[ReportInfo, _Mapping]] = ..., api_call: _Optional[_Union[APICallInfo, _Mapping]] = ..., webhook: _Optional[_Union[WebhookInfo, _Mapping]] = ...) -> None: ...
class AnalyticsEvents(_message.Message):
__slots__ = ("events",)
@@ -281,3 +342,160 @@ class AnalyticsNodeRooms(_message.Message):
timestamp: _timestamp_pb2.Timestamp
rooms: _containers.RepeatedCompositeFieldContainer[AnalyticsRoom]
def __init__(self, node_id: _Optional[str] = ..., sequence_number: _Optional[int] = ..., timestamp: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., rooms: _Optional[_Iterable[_Union[AnalyticsRoom, _Mapping]]] = ...) -> None: ...
+
+class ReportInfo(_message.Message):
+ __slots__ = ("feature_usage",)
+ FEATURE_USAGE_FIELD_NUMBER: _ClassVar[int]
+ feature_usage: FeatureUsageInfo
+ def __init__(self, feature_usage: _Optional[_Union[FeatureUsageInfo, _Mapping]] = ...) -> None: ...
+
+class TimeRange(_message.Message):
+ __slots__ = ("started_at", "ended_at")
+ STARTED_AT_FIELD_NUMBER: _ClassVar[int]
+ ENDED_AT_FIELD_NUMBER: _ClassVar[int]
+ started_at: _timestamp_pb2.Timestamp
+ ended_at: _timestamp_pb2.Timestamp
+ def __init__(self, started_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., ended_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ...) -> None: ...
+
+class FeatureUsageInfo(_message.Message):
+ __slots__ = ("feature", "project_id", "room_name", "room_id", "participant_identity", "participant_id", "track_id", "time_ranges", "feature_info")
+ class Feature(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ KRISP_NOISE_CANCELLATION: _ClassVar[FeatureUsageInfo.Feature]
+ KRISP_BACKGROUND_VOICE_CANCELLATION: _ClassVar[FeatureUsageInfo.Feature]
+ AIC_AUDIO_ENHANCEMENT: _ClassVar[FeatureUsageInfo.Feature]
+ KRISP_NOISE_CANCELLATION: FeatureUsageInfo.Feature
+ KRISP_BACKGROUND_VOICE_CANCELLATION: FeatureUsageInfo.Feature
+ AIC_AUDIO_ENHANCEMENT: FeatureUsageInfo.Feature
+ class FeatureInfoEntry(_message.Message):
+ __slots__ = ("key", "value")
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: str
+ value: str
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
+ FEATURE_FIELD_NUMBER: _ClassVar[int]
+ PROJECT_ID_FIELD_NUMBER: _ClassVar[int]
+ ROOM_NAME_FIELD_NUMBER: _ClassVar[int]
+ ROOM_ID_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_ID_FIELD_NUMBER: _ClassVar[int]
+ TRACK_ID_FIELD_NUMBER: _ClassVar[int]
+ TIME_RANGES_FIELD_NUMBER: _ClassVar[int]
+ FEATURE_INFO_FIELD_NUMBER: _ClassVar[int]
+ feature: FeatureUsageInfo.Feature
+ project_id: str
+ room_name: str
+ room_id: str
+ participant_identity: str
+ participant_id: str
+ track_id: str
+ time_ranges: _containers.RepeatedCompositeFieldContainer[TimeRange]
+ feature_info: _containers.ScalarMap[str, str]
+ def __init__(self, feature: _Optional[_Union[FeatureUsageInfo.Feature, str]] = ..., project_id: _Optional[str] = ..., room_name: _Optional[str] = ..., room_id: _Optional[str] = ..., participant_identity: _Optional[str] = ..., participant_id: _Optional[str] = ..., track_id: _Optional[str] = ..., time_ranges: _Optional[_Iterable[_Union[TimeRange, _Mapping]]] = ..., feature_info: _Optional[_Mapping[str, str]] = ...) -> None: ...
+
+class APICallRequest(_message.Message):
+ __slots__ = ("create_room_request", "list_rooms_request", "delete_room_request", "list_participants_request", "room_participant_identity", "mute_room_track_request", "update_participant_request", "update_subscriptions_request", "send_data_request", "update_room_metadata_request")
+ CREATE_ROOM_REQUEST_FIELD_NUMBER: _ClassVar[int]
+ LIST_ROOMS_REQUEST_FIELD_NUMBER: _ClassVar[int]
+ DELETE_ROOM_REQUEST_FIELD_NUMBER: _ClassVar[int]
+ LIST_PARTICIPANTS_REQUEST_FIELD_NUMBER: _ClassVar[int]
+ ROOM_PARTICIPANT_IDENTITY_FIELD_NUMBER: _ClassVar[int]
+ MUTE_ROOM_TRACK_REQUEST_FIELD_NUMBER: _ClassVar[int]
+ UPDATE_PARTICIPANT_REQUEST_FIELD_NUMBER: _ClassVar[int]
+ UPDATE_SUBSCRIPTIONS_REQUEST_FIELD_NUMBER: _ClassVar[int]
+ SEND_DATA_REQUEST_FIELD_NUMBER: _ClassVar[int]
+ UPDATE_ROOM_METADATA_REQUEST_FIELD_NUMBER: _ClassVar[int]
+ create_room_request: _room.CreateRoomRequest
+ list_rooms_request: _room.ListRoomsRequest
+ delete_room_request: _room.DeleteRoomRequest
+ list_participants_request: _room.ListParticipantsRequest
+ room_participant_identity: _room.RoomParticipantIdentity
+ mute_room_track_request: _room.MuteRoomTrackRequest
+ update_participant_request: _room.UpdateParticipantRequest
+ update_subscriptions_request: _room.UpdateSubscriptionsRequest
+ send_data_request: _room.SendDataRequest
+ update_room_metadata_request: _room.UpdateRoomMetadataRequest
+ def __init__(self, create_room_request: _Optional[_Union[_room.CreateRoomRequest, _Mapping]] = ..., list_rooms_request: _Optional[_Union[_room.ListRoomsRequest, _Mapping]] = ..., delete_room_request: _Optional[_Union[_room.DeleteRoomRequest, _Mapping]] = ..., list_participants_request: _Optional[_Union[_room.ListParticipantsRequest, _Mapping]] = ..., room_participant_identity: _Optional[_Union[_room.RoomParticipantIdentity, _Mapping]] = ..., mute_room_track_request: _Optional[_Union[_room.MuteRoomTrackRequest, _Mapping]] = ..., update_participant_request: _Optional[_Union[_room.UpdateParticipantRequest, _Mapping]] = ..., update_subscriptions_request: _Optional[_Union[_room.UpdateSubscriptionsRequest, _Mapping]] = ..., send_data_request: _Optional[_Union[_room.SendDataRequest, _Mapping]] = ..., update_room_metadata_request: _Optional[_Union[_room.UpdateRoomMetadataRequest, _Mapping]] = ...) -> None: ...
+
+class APICallInfo(_message.Message):
+ __slots__ = ("project_id", "request", "service", "method", "node_id", "status", "twirp_error_code", "twirp_error_message", "room_name", "room_id", "participant_identity", "participant_id", "track_id", "started_at", "duration_ns")
+ PROJECT_ID_FIELD_NUMBER: _ClassVar[int]
+ REQUEST_FIELD_NUMBER: _ClassVar[int]
+ SERVICE_FIELD_NUMBER: _ClassVar[int]
+ METHOD_FIELD_NUMBER: _ClassVar[int]
+ NODE_ID_FIELD_NUMBER: _ClassVar[int]
+ STATUS_FIELD_NUMBER: _ClassVar[int]
+ TWIRP_ERROR_CODE_FIELD_NUMBER: _ClassVar[int]
+ TWIRP_ERROR_MESSAGE_FIELD_NUMBER: _ClassVar[int]
+ ROOM_NAME_FIELD_NUMBER: _ClassVar[int]
+ ROOM_ID_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_ID_FIELD_NUMBER: _ClassVar[int]
+ TRACK_ID_FIELD_NUMBER: _ClassVar[int]
+ STARTED_AT_FIELD_NUMBER: _ClassVar[int]
+ DURATION_NS_FIELD_NUMBER: _ClassVar[int]
+ project_id: str
+ request: APICallRequest
+ service: str
+ method: str
+ node_id: str
+ status: int
+ twirp_error_code: str
+ twirp_error_message: str
+ room_name: str
+ room_id: str
+ participant_identity: str
+ participant_id: str
+ track_id: str
+ started_at: _timestamp_pb2.Timestamp
+ duration_ns: int
+ def __init__(self, project_id: _Optional[str] = ..., request: _Optional[_Union[APICallRequest, _Mapping]] = ..., service: _Optional[str] = ..., method: _Optional[str] = ..., node_id: _Optional[str] = ..., status: _Optional[int] = ..., twirp_error_code: _Optional[str] = ..., twirp_error_message: _Optional[str] = ..., room_name: _Optional[str] = ..., room_id: _Optional[str] = ..., participant_identity: _Optional[str] = ..., participant_id: _Optional[str] = ..., track_id: _Optional[str] = ..., started_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., duration_ns: _Optional[int] = ...) -> None: ...
+
+class WebhookInfo(_message.Message):
+ __slots__ = ("event_id", "event", "project_id", "room_name", "room_id", "participant_identity", "participant_id", "track_id", "egress_id", "ingress_id", "created_at", "queued_at", "queue_duration_ns", "sent_at", "send_duration_ns", "url", "num_dropped", "is_dropped", "service_status", "service_error_code", "service_error", "send_error")
+ EVENT_ID_FIELD_NUMBER: _ClassVar[int]
+ EVENT_FIELD_NUMBER: _ClassVar[int]
+ PROJECT_ID_FIELD_NUMBER: _ClassVar[int]
+ ROOM_NAME_FIELD_NUMBER: _ClassVar[int]
+ ROOM_ID_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_ID_FIELD_NUMBER: _ClassVar[int]
+ TRACK_ID_FIELD_NUMBER: _ClassVar[int]
+ EGRESS_ID_FIELD_NUMBER: _ClassVar[int]
+ INGRESS_ID_FIELD_NUMBER: _ClassVar[int]
+ CREATED_AT_FIELD_NUMBER: _ClassVar[int]
+ QUEUED_AT_FIELD_NUMBER: _ClassVar[int]
+ QUEUE_DURATION_NS_FIELD_NUMBER: _ClassVar[int]
+ SENT_AT_FIELD_NUMBER: _ClassVar[int]
+ SEND_DURATION_NS_FIELD_NUMBER: _ClassVar[int]
+ URL_FIELD_NUMBER: _ClassVar[int]
+ NUM_DROPPED_FIELD_NUMBER: _ClassVar[int]
+ IS_DROPPED_FIELD_NUMBER: _ClassVar[int]
+ SERVICE_STATUS_FIELD_NUMBER: _ClassVar[int]
+ SERVICE_ERROR_CODE_FIELD_NUMBER: _ClassVar[int]
+ SERVICE_ERROR_FIELD_NUMBER: _ClassVar[int]
+ SEND_ERROR_FIELD_NUMBER: _ClassVar[int]
+ event_id: str
+ event: str
+ project_id: str
+ room_name: str
+ room_id: str
+ participant_identity: str
+ participant_id: str
+ track_id: str
+ egress_id: str
+ ingress_id: str
+ created_at: _timestamp_pb2.Timestamp
+ queued_at: _timestamp_pb2.Timestamp
+ queue_duration_ns: int
+ sent_at: _timestamp_pb2.Timestamp
+ send_duration_ns: int
+ url: str
+ num_dropped: int
+ is_dropped: bool
+ service_status: str
+ service_error_code: int
+ service_error: str
+ send_error: str
+ def __init__(self, event_id: _Optional[str] = ..., event: _Optional[str] = ..., project_id: _Optional[str] = ..., room_name: _Optional[str] = ..., room_id: _Optional[str] = ..., participant_identity: _Optional[str] = ..., participant_id: _Optional[str] = ..., track_id: _Optional[str] = ..., egress_id: _Optional[str] = ..., ingress_id: _Optional[str] = ..., created_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., queued_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., queue_duration_ns: _Optional[int] = ..., sent_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., send_duration_ns: _Optional[int] = ..., url: _Optional[str] = ..., num_dropped: _Optional[int] = ..., is_dropped: bool = ..., service_status: _Optional[str] = ..., service_error_code: _Optional[int] = ..., service_error: _Optional[str] = ..., send_error: _Optional[str] = ...) -> None: ...
diff --git a/livekit-protocol/livekit/protocol/connector.py b/livekit-protocol/livekit/protocol/connector.py
new file mode 100644
index 00000000..e656930f
--- /dev/null
+++ b/livekit-protocol/livekit/protocol/connector.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: livekit_connector.proto
+# Protobuf Python Version: 4.25.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from . import connector_whatsapp as _connector__whatsapp_
+from . import connector_twilio as _connector__twilio_
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x17livekit_connector.proto\x12\x07livekit\x1a livekit_connector_whatsapp.proto\x1a\x1elivekit_connector_twilio.proto*:\n\rConnectorType\x12\x0f\n\x0bUnspecified\x10\x00\x12\x0c\n\x08WhatsApp\x10\x01\x12\n\n\x06Twilio\x10\x02\x32\xec\x03\n\tConnector\x12W\n\x10\x44ialWhatsAppCall\x12 .livekit.DialWhatsAppCallRequest\x1a!.livekit.DialWhatsAppCallResponse\x12i\n\x16\x44isconnectWhatsAppCall\x12&.livekit.DisconnectWhatsAppCallRequest\x1a\'.livekit.DisconnectWhatsAppCallResponse\x12`\n\x13\x43onnectWhatsAppCall\x12#.livekit.ConnectWhatsAppCallRequest\x1a$.livekit.ConnectWhatsAppCallResponse\x12]\n\x12\x41\x63\x63\x65ptWhatsAppCall\x12\".livekit.AcceptWhatsAppCallRequest\x1a#.livekit.AcceptWhatsAppCallResponse\x12Z\n\x11\x43onnectTwilioCall\x12!.livekit.ConnectTwilioCallRequest\x1a\".livekit.ConnectTwilioCallResponseBFZ#github.com/livekit/protocol/livekit\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'connector', _globals)
+if _descriptor._USE_C_DESCRIPTORS == False:
+ _globals['DESCRIPTOR']._options = None
+ _globals['DESCRIPTOR']._serialized_options = b'Z#github.com/livekit/protocol/livekit\252\002\rLiveKit.Proto\352\002\016LiveKit::Proto'
+ _globals['_CONNECTORTYPE']._serialized_start=102
+ _globals['_CONNECTORTYPE']._serialized_end=160
+ _globals['_CONNECTOR']._serialized_start=163
+ _globals['_CONNECTOR']._serialized_end=655
+# @@protoc_insertion_point(module_scope)
diff --git a/livekit-protocol/livekit/protocol/connector.pyi b/livekit-protocol/livekit/protocol/connector.pyi
new file mode 100644
index 00000000..98459956
--- /dev/null
+++ b/livekit-protocol/livekit/protocol/connector.pyi
@@ -0,0 +1,16 @@
+from . import connector_whatsapp as _connector_whatsapp
+from . import connector_twilio as _connector_twilio
+from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
+from google.protobuf import descriptor as _descriptor
+from typing import ClassVar as _ClassVar
+
+DESCRIPTOR: _descriptor.FileDescriptor
+
+class ConnectorType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ Unspecified: _ClassVar[ConnectorType]
+ WhatsApp: _ClassVar[ConnectorType]
+ Twilio: _ClassVar[ConnectorType]
+Unspecified: ConnectorType
+WhatsApp: ConnectorType
+Twilio: ConnectorType
diff --git a/livekit-protocol/livekit/protocol/connector_twilio.py b/livekit-protocol/livekit/protocol/connector_twilio.py
new file mode 100644
index 00000000..f315e693
--- /dev/null
+++ b/livekit-protocol/livekit/protocol/connector_twilio.py
@@ -0,0 +1,43 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: livekit_connector_twilio.proto
+# Protobuf Python Version: 4.25.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from . import agent_dispatch as _agent__dispatch_
+from .logger_pb import options as logger_dot_options__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1elivekit_connector_twilio.proto\x12\x07livekit\x1a\x1clivekit_agent_dispatch.proto\x1a\x14logger/options.proto\"\x8f\x05\n\x18\x43onnectTwilioCallRequest\x12T\n\x15twilio_call_direction\x18\x01 \x01(\x0e\x32\x35.livekit.ConnectTwilioCallRequest.TwilioCallDirection\x12\x11\n\troom_name\x18\x02 \x01(\t\x12*\n\x06\x61gents\x18\x03 \x03(\x0b\x32\x1a.livekit.RoomAgentDispatch\x12\x1c\n\x14participant_identity\x18\x04 \x01(\t\x12>\n\x10participant_name\x18\x05 \x01(\tB$\xa8P\x01\xb2P\x1e\x12\x42\n\x14participant_metadata\x18\x06 \x01(\tB$\xa8P\x01\xb2P\x1e\x12\x82\x01\n\x16participant_attributes\x18\x07 \x03(\x0b\x32<.livekit.ConnectTwilioCallRequest.ParticipantAttributesEntryB$\xa8P\x01\xb2P\x1e\x12\x1b\n\x13\x64\x65stination_country\x18\x08 \x01(\t\x1a<\n\x1aParticipantAttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\\\n\x13TwilioCallDirection\x12!\n\x1dTWILIO_CALL_DIRECTION_INBOUND\x10\x00\x12\"\n\x1eTWILIO_CALL_DIRECTION_OUTBOUND\x10\x01\"0\n\x19\x43onnectTwilioCallResponse\x12\x13\n\x0b\x63onnect_url\x18\x01 \x01(\tBFZ#github.com/livekit/protocol/livekit\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'connector_twilio', _globals)
+if _descriptor._USE_C_DESCRIPTORS == False:
+ _globals['DESCRIPTOR']._options = None
+ _globals['DESCRIPTOR']._serialized_options = b'Z#github.com/livekit/protocol/livekit\252\002\rLiveKit.Proto\352\002\016LiveKit::Proto'
+ _globals['_CONNECTTWILIOCALLREQUEST_PARTICIPANTATTRIBUTESENTRY']._options = None
+ _globals['_CONNECTTWILIOCALLREQUEST_PARTICIPANTATTRIBUTESENTRY']._serialized_options = b'8\001'
+ _globals['_CONNECTTWILIOCALLREQUEST'].fields_by_name['participant_name']._options = None
+ _globals['_CONNECTTWILIOCALLREQUEST'].fields_by_name['participant_name']._serialized_options = b'\250P\001\262P\036'
+ _globals['_CONNECTTWILIOCALLREQUEST'].fields_by_name['participant_metadata']._options = None
+ _globals['_CONNECTTWILIOCALLREQUEST'].fields_by_name['participant_metadata']._serialized_options = b'\250P\001\262P\036'
+ _globals['_CONNECTTWILIOCALLREQUEST'].fields_by_name['participant_attributes']._options = None
+ _globals['_CONNECTTWILIOCALLREQUEST'].fields_by_name['participant_attributes']._serialized_options = b'\250P\001\262P\036'
+ _globals['_CONNECTTWILIOCALLREQUEST']._serialized_start=96
+ _globals['_CONNECTTWILIOCALLREQUEST']._serialized_end=751
+ _globals['_CONNECTTWILIOCALLREQUEST_PARTICIPANTATTRIBUTESENTRY']._serialized_start=597
+ _globals['_CONNECTTWILIOCALLREQUEST_PARTICIPANTATTRIBUTESENTRY']._serialized_end=657
+ _globals['_CONNECTTWILIOCALLREQUEST_TWILIOCALLDIRECTION']._serialized_start=659
+ _globals['_CONNECTTWILIOCALLREQUEST_TWILIOCALLDIRECTION']._serialized_end=751
+ _globals['_CONNECTTWILIOCALLRESPONSE']._serialized_start=753
+ _globals['_CONNECTTWILIOCALLRESPONSE']._serialized_end=801
+# @@protoc_insertion_point(module_scope)
diff --git a/livekit-protocol/livekit/protocol/connector_twilio.pyi b/livekit-protocol/livekit/protocol/connector_twilio.pyi
new file mode 100644
index 00000000..abf53ec8
--- /dev/null
+++ b/livekit-protocol/livekit/protocol/connector_twilio.pyi
@@ -0,0 +1,48 @@
+from . import agent_dispatch as _agent_dispatch
+from .logger_pb import options as _options_pb2
+from google.protobuf.internal import containers as _containers
+from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union
+
+DESCRIPTOR: _descriptor.FileDescriptor
+
+class ConnectTwilioCallRequest(_message.Message):
+ __slots__ = ("twilio_call_direction", "room_name", "agents", "participant_identity", "participant_name", "participant_metadata", "participant_attributes", "destination_country")
+ class TwilioCallDirection(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ TWILIO_CALL_DIRECTION_INBOUND: _ClassVar[ConnectTwilioCallRequest.TwilioCallDirection]
+ TWILIO_CALL_DIRECTION_OUTBOUND: _ClassVar[ConnectTwilioCallRequest.TwilioCallDirection]
+ TWILIO_CALL_DIRECTION_INBOUND: ConnectTwilioCallRequest.TwilioCallDirection
+ TWILIO_CALL_DIRECTION_OUTBOUND: ConnectTwilioCallRequest.TwilioCallDirection
+ class ParticipantAttributesEntry(_message.Message):
+ __slots__ = ("key", "value")
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: str
+ value: str
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
+ TWILIO_CALL_DIRECTION_FIELD_NUMBER: _ClassVar[int]
+ ROOM_NAME_FIELD_NUMBER: _ClassVar[int]
+ AGENTS_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_NAME_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_METADATA_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_ATTRIBUTES_FIELD_NUMBER: _ClassVar[int]
+ DESTINATION_COUNTRY_FIELD_NUMBER: _ClassVar[int]
+ twilio_call_direction: ConnectTwilioCallRequest.TwilioCallDirection
+ room_name: str
+ agents: _containers.RepeatedCompositeFieldContainer[_agent_dispatch.RoomAgentDispatch]
+ participant_identity: str
+ participant_name: str
+ participant_metadata: str
+ participant_attributes: _containers.ScalarMap[str, str]
+ destination_country: str
+ def __init__(self, twilio_call_direction: _Optional[_Union[ConnectTwilioCallRequest.TwilioCallDirection, str]] = ..., room_name: _Optional[str] = ..., agents: _Optional[_Iterable[_Union[_agent_dispatch.RoomAgentDispatch, _Mapping]]] = ..., participant_identity: _Optional[str] = ..., participant_name: _Optional[str] = ..., participant_metadata: _Optional[str] = ..., participant_attributes: _Optional[_Mapping[str, str]] = ..., destination_country: _Optional[str] = ...) -> None: ...
+
+class ConnectTwilioCallResponse(_message.Message):
+ __slots__ = ("connect_url",)
+ CONNECT_URL_FIELD_NUMBER: _ClassVar[int]
+ connect_url: str
+ def __init__(self, connect_url: _Optional[str] = ...) -> None: ...
diff --git a/livekit-protocol/livekit/protocol/connector_whatsapp.py b/livekit-protocol/livekit/protocol/connector_whatsapp.py
new file mode 100644
index 00000000..e9b53732
--- /dev/null
+++ b/livekit-protocol/livekit/protocol/connector_whatsapp.py
@@ -0,0 +1,93 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: livekit_connector_whatsapp.proto
+# Protobuf Python Version: 4.25.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from google.protobuf import duration_pb2 as google_dot_protobuf_dot_duration__pb2
+from . import agent_dispatch as _agent__dispatch_
+from . import rtc as _rtc_
+from .logger_pb import options as logger_dot_options__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n livekit_connector_whatsapp.proto\x12\x07livekit\x1a\x1egoogle/protobuf/duration.proto\x1a\x1clivekit_agent_dispatch.proto\x1a\x11livekit_rtc.proto\x1a\x14logger/options.proto\"\xde\x05\n\x17\x44ialWhatsAppCallRequest\x12:\n\x18whatsapp_phone_number_id\x18\x01 \x01(\tB\x18\xbaP\x15whatsappPhoneNumberID\x12%\n\x18whatsapp_to_phone_number\x18\x02 \x01(\tB\x03\xa8P\x01\x12\x1d\n\x10whatsapp_api_key\x18\x03 \x01(\tB\x03\xa8P\x01\x12\"\n\x1awhatsapp_cloud_api_version\x18\x0c \x01(\t\x12)\n!whatsapp_biz_opaque_callback_data\x18\x04 \x01(\t\x12\x11\n\troom_name\x18\x05 \x01(\t\x12*\n\x06\x61gents\x18\x06 \x03(\x0b\x32\x1a.livekit.RoomAgentDispatch\x12\x1c\n\x14participant_identity\x18\x07 \x01(\t\x12>\n\x10participant_name\x18\x08 \x01(\tB$\xa8P\x01\xb2P\x1e\x12\x42\n\x14participant_metadata\x18\t \x01(\tB$\xa8P\x01\xb2P\x1e\x12\x81\x01\n\x16participant_attributes\x18\n \x03(\x0b\x32;.livekit.DialWhatsAppCallRequest.ParticipantAttributesEntryB$\xa8P\x01\xb2P\x1e\x12\x1b\n\x13\x64\x65stination_country\x18\x0b \x01(\t\x12\x32\n\x0fringing_timeout\x18\r \x01(\x0b\x32\x19.google.protobuf.Duration\x1a<\n\x1aParticipantAttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"Z\n\x18\x44ialWhatsAppCallResponse\x12+\n\x10whatsapp_call_id\x18\x01 \x01(\tB\x11\xbaP\x0ewhatsappCallID\x12\x11\n\troom_name\x18\x02 \x01(\t\"\xff\x01\n\x1d\x44isconnectWhatsAppCallRequest\x12+\n\x10whatsapp_call_id\x18\x01 \x01(\tB\x11\xbaP\x0ewhatsappCallID\x12\x1d\n\x10whatsapp_api_key\x18\x02 \x01(\tB\x03\xa8P\x01\x12R\n\x11\x64isconnect_reason\x18\x03 \x01(\x0e\x32\x37.livekit.DisconnectWhatsAppCallRequest.DisconnectReason\">\n\x10\x44isconnectReason\x12\x16\n\x12\x42USINESS_INITIATED\x10\x00\x12\x12\n\x0eUSER_INITIATED\x10\x01\" \n\x1e\x44isconnectWhatsAppCallResponse\"s\n\x1a\x43onnectWhatsAppCallRequest\x12+\n\x10whatsapp_call_id\x18\x01 \x01(\tB\x11\xbaP\x0ewhatsappCallID\x12(\n\x03sdp\x18\x02 \x01(\x0b\x32\x1b.livekit.SessionDescription\"\x1d\n\x1b\x43onnectWhatsAppCallResponse\"\xaf\x06\n\x19\x41\x63\x63\x65ptWhatsAppCallRequest\x12:\n\x18whatsapp_phone_number_id\x18\x01 \x01(\tB\x18\xbaP\x15whatsappPhoneNumberID\x12\x1d\n\x10whatsapp_api_key\x18\x02 \x01(\tB\x03\xa8P\x01\x12\"\n\x1awhatsapp_cloud_api_version\x18\r \x01(\t\x12+\n\x10whatsapp_call_id\x18\x03 \x01(\tB\x11\xbaP\x0ewhatsappCallID\x12)\n!whatsapp_biz_opaque_callback_data\x18\x04 \x01(\t\x12(\n\x03sdp\x18\x05 \x01(\x0b\x32\x1b.livekit.SessionDescription\x12\x11\n\troom_name\x18\x06 \x01(\t\x12*\n\x06\x61gents\x18\x07 \x03(\x0b\x32\x1a.livekit.RoomAgentDispatch\x12\x1c\n\x14participant_identity\x18\x08 \x01(\t\x12>\n\x10participant_name\x18\t \x01(\tB$\xa8P\x01\xb2P\x1e\x12\x42\n\x14participant_metadata\x18\n \x01(\tB$\xa8P\x01\xb2P\x1e\x12\x83\x01\n\x16participant_attributes\x18\x0b \x03(\x0b\x32=.livekit.AcceptWhatsAppCallRequest.ParticipantAttributesEntryB$\xa8P\x01\xb2P\x1e\x12\x1b\n\x13\x64\x65stination_country\x18\x0c \x01(\t\x12\x32\n\x0fringing_timeout\x18\x0e \x01(\x0b\x32\x19.google.protobuf.Duration\x12\x1b\n\x13wait_until_answered\x18\x0f \x01(\x08\x1a<\n\x1aParticipantAttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"/\n\x1a\x41\x63\x63\x65ptWhatsAppCallResponse\x12\x11\n\troom_name\x18\x01 \x01(\t\"n\n\x0cWhatsAppCall\x12+\n\x10whatsapp_call_id\x18\x01 \x01(\tB\x11\xbaP\x0ewhatsappCallID\x12\x31\n\tdirection\x18\x02 \x01(\x0e\x32\x1e.livekit.WhatsAppCallDirection*b\n\x15WhatsAppCallDirection\x12#\n\x1fWHATSAPP_CALL_DIRECTION_INBOUND\x10\x00\x12$\n WHATSAPP_CALL_DIRECTION_OUTBOUND\x10\x02\x42\x46Z#github.com/livekit/protocol/livekit\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'connector_whatsapp', _globals)
+if _descriptor._USE_C_DESCRIPTORS == False:
+ _globals['DESCRIPTOR']._options = None
+ _globals['DESCRIPTOR']._serialized_options = b'Z#github.com/livekit/protocol/livekit\252\002\rLiveKit.Proto\352\002\016LiveKit::Proto'
+ _globals['_DIALWHATSAPPCALLREQUEST_PARTICIPANTATTRIBUTESENTRY']._options = None
+ _globals['_DIALWHATSAPPCALLREQUEST_PARTICIPANTATTRIBUTESENTRY']._serialized_options = b'8\001'
+ _globals['_DIALWHATSAPPCALLREQUEST'].fields_by_name['whatsapp_phone_number_id']._options = None
+ _globals['_DIALWHATSAPPCALLREQUEST'].fields_by_name['whatsapp_phone_number_id']._serialized_options = b'\272P\025whatsappPhoneNumberID'
+ _globals['_DIALWHATSAPPCALLREQUEST'].fields_by_name['whatsapp_to_phone_number']._options = None
+ _globals['_DIALWHATSAPPCALLREQUEST'].fields_by_name['whatsapp_to_phone_number']._serialized_options = b'\250P\001'
+ _globals['_DIALWHATSAPPCALLREQUEST'].fields_by_name['whatsapp_api_key']._options = None
+ _globals['_DIALWHATSAPPCALLREQUEST'].fields_by_name['whatsapp_api_key']._serialized_options = b'\250P\001'
+ _globals['_DIALWHATSAPPCALLREQUEST'].fields_by_name['participant_name']._options = None
+ _globals['_DIALWHATSAPPCALLREQUEST'].fields_by_name['participant_name']._serialized_options = b'\250P\001\262P\036'
+ _globals['_DIALWHATSAPPCALLREQUEST'].fields_by_name['participant_metadata']._options = None
+ _globals['_DIALWHATSAPPCALLREQUEST'].fields_by_name['participant_metadata']._serialized_options = b'\250P\001\262P\036'
+ _globals['_DIALWHATSAPPCALLREQUEST'].fields_by_name['participant_attributes']._options = None
+ _globals['_DIALWHATSAPPCALLREQUEST'].fields_by_name['participant_attributes']._serialized_options = b'\250P\001\262P\036'
+ _globals['_DIALWHATSAPPCALLRESPONSE'].fields_by_name['whatsapp_call_id']._options = None
+ _globals['_DIALWHATSAPPCALLRESPONSE'].fields_by_name['whatsapp_call_id']._serialized_options = b'\272P\016whatsappCallID'
+ _globals['_DISCONNECTWHATSAPPCALLREQUEST'].fields_by_name['whatsapp_call_id']._options = None
+ _globals['_DISCONNECTWHATSAPPCALLREQUEST'].fields_by_name['whatsapp_call_id']._serialized_options = b'\272P\016whatsappCallID'
+ _globals['_DISCONNECTWHATSAPPCALLREQUEST'].fields_by_name['whatsapp_api_key']._options = None
+ _globals['_DISCONNECTWHATSAPPCALLREQUEST'].fields_by_name['whatsapp_api_key']._serialized_options = b'\250P\001'
+ _globals['_CONNECTWHATSAPPCALLREQUEST'].fields_by_name['whatsapp_call_id']._options = None
+ _globals['_CONNECTWHATSAPPCALLREQUEST'].fields_by_name['whatsapp_call_id']._serialized_options = b'\272P\016whatsappCallID'
+ _globals['_ACCEPTWHATSAPPCALLREQUEST_PARTICIPANTATTRIBUTESENTRY']._options = None
+ _globals['_ACCEPTWHATSAPPCALLREQUEST_PARTICIPANTATTRIBUTESENTRY']._serialized_options = b'8\001'
+ _globals['_ACCEPTWHATSAPPCALLREQUEST'].fields_by_name['whatsapp_phone_number_id']._options = None
+ _globals['_ACCEPTWHATSAPPCALLREQUEST'].fields_by_name['whatsapp_phone_number_id']._serialized_options = b'\272P\025whatsappPhoneNumberID'
+ _globals['_ACCEPTWHATSAPPCALLREQUEST'].fields_by_name['whatsapp_api_key']._options = None
+ _globals['_ACCEPTWHATSAPPCALLREQUEST'].fields_by_name['whatsapp_api_key']._serialized_options = b'\250P\001'
+ _globals['_ACCEPTWHATSAPPCALLREQUEST'].fields_by_name['whatsapp_call_id']._options = None
+ _globals['_ACCEPTWHATSAPPCALLREQUEST'].fields_by_name['whatsapp_call_id']._serialized_options = b'\272P\016whatsappCallID'
+ _globals['_ACCEPTWHATSAPPCALLREQUEST'].fields_by_name['participant_name']._options = None
+ _globals['_ACCEPTWHATSAPPCALLREQUEST'].fields_by_name['participant_name']._serialized_options = b'\250P\001\262P\036'
+ _globals['_ACCEPTWHATSAPPCALLREQUEST'].fields_by_name['participant_metadata']._options = None
+ _globals['_ACCEPTWHATSAPPCALLREQUEST'].fields_by_name['participant_metadata']._serialized_options = b'\250P\001\262P\036'
+ _globals['_ACCEPTWHATSAPPCALLREQUEST'].fields_by_name['participant_attributes']._options = None
+ _globals['_ACCEPTWHATSAPPCALLREQUEST'].fields_by_name['participant_attributes']._serialized_options = b'\250P\001\262P\036'
+ _globals['_WHATSAPPCALL'].fields_by_name['whatsapp_call_id']._options = None
+ _globals['_WHATSAPPCALL'].fields_by_name['whatsapp_call_id']._serialized_options = b'\272P\016whatsappCallID'
+ _globals['_WHATSAPPCALLDIRECTION']._serialized_start=2396
+ _globals['_WHATSAPPCALLDIRECTION']._serialized_end=2494
+ _globals['_DIALWHATSAPPCALLREQUEST']._serialized_start=149
+ _globals['_DIALWHATSAPPCALLREQUEST']._serialized_end=883
+ _globals['_DIALWHATSAPPCALLREQUEST_PARTICIPANTATTRIBUTESENTRY']._serialized_start=823
+ _globals['_DIALWHATSAPPCALLREQUEST_PARTICIPANTATTRIBUTESENTRY']._serialized_end=883
+ _globals['_DIALWHATSAPPCALLRESPONSE']._serialized_start=885
+ _globals['_DIALWHATSAPPCALLRESPONSE']._serialized_end=975
+ _globals['_DISCONNECTWHATSAPPCALLREQUEST']._serialized_start=978
+ _globals['_DISCONNECTWHATSAPPCALLREQUEST']._serialized_end=1233
+ _globals['_DISCONNECTWHATSAPPCALLREQUEST_DISCONNECTREASON']._serialized_start=1171
+ _globals['_DISCONNECTWHATSAPPCALLREQUEST_DISCONNECTREASON']._serialized_end=1233
+ _globals['_DISCONNECTWHATSAPPCALLRESPONSE']._serialized_start=1235
+ _globals['_DISCONNECTWHATSAPPCALLRESPONSE']._serialized_end=1267
+ _globals['_CONNECTWHATSAPPCALLREQUEST']._serialized_start=1269
+ _globals['_CONNECTWHATSAPPCALLREQUEST']._serialized_end=1384
+ _globals['_CONNECTWHATSAPPCALLRESPONSE']._serialized_start=1386
+ _globals['_CONNECTWHATSAPPCALLRESPONSE']._serialized_end=1415
+ _globals['_ACCEPTWHATSAPPCALLREQUEST']._serialized_start=1418
+ _globals['_ACCEPTWHATSAPPCALLREQUEST']._serialized_end=2233
+ _globals['_ACCEPTWHATSAPPCALLREQUEST_PARTICIPANTATTRIBUTESENTRY']._serialized_start=823
+ _globals['_ACCEPTWHATSAPPCALLREQUEST_PARTICIPANTATTRIBUTESENTRY']._serialized_end=883
+ _globals['_ACCEPTWHATSAPPCALLRESPONSE']._serialized_start=2235
+ _globals['_ACCEPTWHATSAPPCALLRESPONSE']._serialized_end=2282
+ _globals['_WHATSAPPCALL']._serialized_start=2284
+ _globals['_WHATSAPPCALL']._serialized_end=2394
+# @@protoc_insertion_point(module_scope)
diff --git a/livekit-protocol/livekit/protocol/connector_whatsapp.pyi b/livekit-protocol/livekit/protocol/connector_whatsapp.pyi
new file mode 100644
index 00000000..15379886
--- /dev/null
+++ b/livekit-protocol/livekit/protocol/connector_whatsapp.pyi
@@ -0,0 +1,150 @@
+from google.protobuf import duration_pb2 as _duration_pb2
+from . import agent_dispatch as _agent_dispatch
+from . import rtc as _rtc
+from .logger_pb import options as _options_pb2
+from google.protobuf.internal import containers as _containers
+from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union
+
+DESCRIPTOR: _descriptor.FileDescriptor
+
+class WhatsAppCallDirection(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ WHATSAPP_CALL_DIRECTION_INBOUND: _ClassVar[WhatsAppCallDirection]
+ WHATSAPP_CALL_DIRECTION_OUTBOUND: _ClassVar[WhatsAppCallDirection]
+WHATSAPP_CALL_DIRECTION_INBOUND: WhatsAppCallDirection
+WHATSAPP_CALL_DIRECTION_OUTBOUND: WhatsAppCallDirection
+
+class DialWhatsAppCallRequest(_message.Message):
+ __slots__ = ("whatsapp_phone_number_id", "whatsapp_to_phone_number", "whatsapp_api_key", "whatsapp_cloud_api_version", "whatsapp_biz_opaque_callback_data", "room_name", "agents", "participant_identity", "participant_name", "participant_metadata", "participant_attributes", "destination_country", "ringing_timeout")
+ class ParticipantAttributesEntry(_message.Message):
+ __slots__ = ("key", "value")
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: str
+ value: str
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
+ WHATSAPP_PHONE_NUMBER_ID_FIELD_NUMBER: _ClassVar[int]
+ WHATSAPP_TO_PHONE_NUMBER_FIELD_NUMBER: _ClassVar[int]
+ WHATSAPP_API_KEY_FIELD_NUMBER: _ClassVar[int]
+ WHATSAPP_CLOUD_API_VERSION_FIELD_NUMBER: _ClassVar[int]
+ WHATSAPP_BIZ_OPAQUE_CALLBACK_DATA_FIELD_NUMBER: _ClassVar[int]
+ ROOM_NAME_FIELD_NUMBER: _ClassVar[int]
+ AGENTS_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_NAME_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_METADATA_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_ATTRIBUTES_FIELD_NUMBER: _ClassVar[int]
+ DESTINATION_COUNTRY_FIELD_NUMBER: _ClassVar[int]
+ RINGING_TIMEOUT_FIELD_NUMBER: _ClassVar[int]
+ whatsapp_phone_number_id: str
+ whatsapp_to_phone_number: str
+ whatsapp_api_key: str
+ whatsapp_cloud_api_version: str
+ whatsapp_biz_opaque_callback_data: str
+ room_name: str
+ agents: _containers.RepeatedCompositeFieldContainer[_agent_dispatch.RoomAgentDispatch]
+ participant_identity: str
+ participant_name: str
+ participant_metadata: str
+ participant_attributes: _containers.ScalarMap[str, str]
+ destination_country: str
+ ringing_timeout: _duration_pb2.Duration
+ def __init__(self, whatsapp_phone_number_id: _Optional[str] = ..., whatsapp_to_phone_number: _Optional[str] = ..., whatsapp_api_key: _Optional[str] = ..., whatsapp_cloud_api_version: _Optional[str] = ..., whatsapp_biz_opaque_callback_data: _Optional[str] = ..., room_name: _Optional[str] = ..., agents: _Optional[_Iterable[_Union[_agent_dispatch.RoomAgentDispatch, _Mapping]]] = ..., participant_identity: _Optional[str] = ..., participant_name: _Optional[str] = ..., participant_metadata: _Optional[str] = ..., participant_attributes: _Optional[_Mapping[str, str]] = ..., destination_country: _Optional[str] = ..., ringing_timeout: _Optional[_Union[_duration_pb2.Duration, _Mapping]] = ...) -> None: ...
+
+class DialWhatsAppCallResponse(_message.Message):
+ __slots__ = ("whatsapp_call_id", "room_name")
+ WHATSAPP_CALL_ID_FIELD_NUMBER: _ClassVar[int]
+ ROOM_NAME_FIELD_NUMBER: _ClassVar[int]
+ whatsapp_call_id: str
+ room_name: str
+ def __init__(self, whatsapp_call_id: _Optional[str] = ..., room_name: _Optional[str] = ...) -> None: ...
+
+class DisconnectWhatsAppCallRequest(_message.Message):
+ __slots__ = ("whatsapp_call_id", "whatsapp_api_key", "disconnect_reason")
+ class DisconnectReason(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ BUSINESS_INITIATED: _ClassVar[DisconnectWhatsAppCallRequest.DisconnectReason]
+ USER_INITIATED: _ClassVar[DisconnectWhatsAppCallRequest.DisconnectReason]
+ BUSINESS_INITIATED: DisconnectWhatsAppCallRequest.DisconnectReason
+ USER_INITIATED: DisconnectWhatsAppCallRequest.DisconnectReason
+ WHATSAPP_CALL_ID_FIELD_NUMBER: _ClassVar[int]
+ WHATSAPP_API_KEY_FIELD_NUMBER: _ClassVar[int]
+ DISCONNECT_REASON_FIELD_NUMBER: _ClassVar[int]
+ whatsapp_call_id: str
+ whatsapp_api_key: str
+ disconnect_reason: DisconnectWhatsAppCallRequest.DisconnectReason
+ def __init__(self, whatsapp_call_id: _Optional[str] = ..., whatsapp_api_key: _Optional[str] = ..., disconnect_reason: _Optional[_Union[DisconnectWhatsAppCallRequest.DisconnectReason, str]] = ...) -> None: ...
+
+class DisconnectWhatsAppCallResponse(_message.Message):
+ __slots__ = ()
+ def __init__(self) -> None: ...
+
+class ConnectWhatsAppCallRequest(_message.Message):
+ __slots__ = ("whatsapp_call_id", "sdp")
+ WHATSAPP_CALL_ID_FIELD_NUMBER: _ClassVar[int]
+ SDP_FIELD_NUMBER: _ClassVar[int]
+ whatsapp_call_id: str
+ sdp: _rtc.SessionDescription
+ def __init__(self, whatsapp_call_id: _Optional[str] = ..., sdp: _Optional[_Union[_rtc.SessionDescription, _Mapping]] = ...) -> None: ...
+
+class ConnectWhatsAppCallResponse(_message.Message):
+ __slots__ = ()
+ def __init__(self) -> None: ...
+
+class AcceptWhatsAppCallRequest(_message.Message):
+ __slots__ = ("whatsapp_phone_number_id", "whatsapp_api_key", "whatsapp_cloud_api_version", "whatsapp_call_id", "whatsapp_biz_opaque_callback_data", "sdp", "room_name", "agents", "participant_identity", "participant_name", "participant_metadata", "participant_attributes", "destination_country", "ringing_timeout", "wait_until_answered")
+ class ParticipantAttributesEntry(_message.Message):
+ __slots__ = ("key", "value")
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: str
+ value: str
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
+ WHATSAPP_PHONE_NUMBER_ID_FIELD_NUMBER: _ClassVar[int]
+ WHATSAPP_API_KEY_FIELD_NUMBER: _ClassVar[int]
+ WHATSAPP_CLOUD_API_VERSION_FIELD_NUMBER: _ClassVar[int]
+ WHATSAPP_CALL_ID_FIELD_NUMBER: _ClassVar[int]
+ WHATSAPP_BIZ_OPAQUE_CALLBACK_DATA_FIELD_NUMBER: _ClassVar[int]
+ SDP_FIELD_NUMBER: _ClassVar[int]
+ ROOM_NAME_FIELD_NUMBER: _ClassVar[int]
+ AGENTS_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_NAME_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_METADATA_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_ATTRIBUTES_FIELD_NUMBER: _ClassVar[int]
+ DESTINATION_COUNTRY_FIELD_NUMBER: _ClassVar[int]
+ RINGING_TIMEOUT_FIELD_NUMBER: _ClassVar[int]
+ WAIT_UNTIL_ANSWERED_FIELD_NUMBER: _ClassVar[int]
+ whatsapp_phone_number_id: str
+ whatsapp_api_key: str
+ whatsapp_cloud_api_version: str
+ whatsapp_call_id: str
+ whatsapp_biz_opaque_callback_data: str
+ sdp: _rtc.SessionDescription
+ room_name: str
+ agents: _containers.RepeatedCompositeFieldContainer[_agent_dispatch.RoomAgentDispatch]
+ participant_identity: str
+ participant_name: str
+ participant_metadata: str
+ participant_attributes: _containers.ScalarMap[str, str]
+ destination_country: str
+ ringing_timeout: _duration_pb2.Duration
+ wait_until_answered: bool
+ def __init__(self, whatsapp_phone_number_id: _Optional[str] = ..., whatsapp_api_key: _Optional[str] = ..., whatsapp_cloud_api_version: _Optional[str] = ..., whatsapp_call_id: _Optional[str] = ..., whatsapp_biz_opaque_callback_data: _Optional[str] = ..., sdp: _Optional[_Union[_rtc.SessionDescription, _Mapping]] = ..., room_name: _Optional[str] = ..., agents: _Optional[_Iterable[_Union[_agent_dispatch.RoomAgentDispatch, _Mapping]]] = ..., participant_identity: _Optional[str] = ..., participant_name: _Optional[str] = ..., participant_metadata: _Optional[str] = ..., participant_attributes: _Optional[_Mapping[str, str]] = ..., destination_country: _Optional[str] = ..., ringing_timeout: _Optional[_Union[_duration_pb2.Duration, _Mapping]] = ..., wait_until_answered: bool = ...) -> None: ...
+
+class AcceptWhatsAppCallResponse(_message.Message):
+ __slots__ = ("room_name",)
+ ROOM_NAME_FIELD_NUMBER: _ClassVar[int]
+ room_name: str
+ def __init__(self, room_name: _Optional[str] = ...) -> None: ...
+
+class WhatsAppCall(_message.Message):
+ __slots__ = ("whatsapp_call_id", "direction")
+ WHATSAPP_CALL_ID_FIELD_NUMBER: _ClassVar[int]
+ DIRECTION_FIELD_NUMBER: _ClassVar[int]
+ whatsapp_call_id: str
+ direction: WhatsAppCallDirection
+ def __init__(self, whatsapp_call_id: _Optional[str] = ..., direction: _Optional[_Union[WhatsAppCallDirection, str]] = ...) -> None: ...
diff --git a/livekit-protocol/livekit/protocol/egress.py b/livekit-protocol/livekit/protocol/egress.py
index 1fc90211..7b56242e 100644
--- a/livekit-protocol/livekit/protocol/egress.py
+++ b/livekit-protocol/livekit/protocol/egress.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: livekit_egress.proto
-# Protobuf Python Version: 4.25.3
+# Protobuf Python Version: 4.25.1
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
@@ -13,9 +13,10 @@
from . import models as _models_
+from .logger_pb import options as logger_dot_options__pb2
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x14livekit_egress.proto\x12\x07livekit\x1a\x14livekit_models.proto\"\xcd\x04\n\x1aRoomCompositeEgressRequest\x12\x11\n\troom_name\x18\x01 \x01(\t\x12\x0e\n\x06layout\x18\x02 \x01(\t\x12\x12\n\naudio_only\x18\x03 \x01(\x08\x12\x12\n\nvideo_only\x18\x04 \x01(\x08\x12\x17\n\x0f\x63ustom_base_url\x18\x05 \x01(\t\x12.\n\x04\x66ile\x18\x06 \x01(\x0b\x32\x1a.livekit.EncodedFileOutputB\x02\x18\x01H\x00\x12+\n\x06stream\x18\x07 \x01(\x0b\x32\x15.livekit.StreamOutputB\x02\x18\x01H\x00\x12\x34\n\x08segments\x18\n \x01(\x0b\x32\x1c.livekit.SegmentedFileOutputB\x02\x18\x01H\x00\x12\x30\n\x06preset\x18\x08 \x01(\x0e\x32\x1e.livekit.EncodingOptionsPresetH\x01\x12,\n\x08\x61\x64vanced\x18\t \x01(\x0b\x32\x18.livekit.EncodingOptionsH\x01\x12\x30\n\x0c\x66ile_outputs\x18\x0b \x03(\x0b\x32\x1a.livekit.EncodedFileOutput\x12-\n\x0estream_outputs\x18\x0c \x03(\x0b\x32\x15.livekit.StreamOutput\x12\x35\n\x0fsegment_outputs\x18\r \x03(\x0b\x32\x1c.livekit.SegmentedFileOutput\x12+\n\rimage_outputs\x18\x0e \x03(\x0b\x32\x14.livekit.ImageOutputB\x08\n\x06outputB\t\n\x07options\"\xb0\x04\n\x10WebEgressRequest\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x12\n\naudio_only\x18\x02 \x01(\x08\x12\x12\n\nvideo_only\x18\x03 \x01(\x08\x12\x1a\n\x12\x61wait_start_signal\x18\x0c \x01(\x08\x12.\n\x04\x66ile\x18\x04 \x01(\x0b\x32\x1a.livekit.EncodedFileOutputB\x02\x18\x01H\x00\x12+\n\x06stream\x18\x05 \x01(\x0b\x32\x15.livekit.StreamOutputB\x02\x18\x01H\x00\x12\x34\n\x08segments\x18\x06 \x01(\x0b\x32\x1c.livekit.SegmentedFileOutputB\x02\x18\x01H\x00\x12\x30\n\x06preset\x18\x07 \x01(\x0e\x32\x1e.livekit.EncodingOptionsPresetH\x01\x12,\n\x08\x61\x64vanced\x18\x08 \x01(\x0b\x32\x18.livekit.EncodingOptionsH\x01\x12\x30\n\x0c\x66ile_outputs\x18\t \x03(\x0b\x32\x1a.livekit.EncodedFileOutput\x12-\n\x0estream_outputs\x18\n \x03(\x0b\x32\x15.livekit.StreamOutput\x12\x35\n\x0fsegment_outputs\x18\x0b \x03(\x0b\x32\x1c.livekit.SegmentedFileOutput\x12+\n\rimage_outputs\x18\r \x03(\x0b\x32\x14.livekit.ImageOutputB\x08\n\x06outputB\t\n\x07options\"\x85\x03\n\x18ParticipantEgressRequest\x12\x11\n\troom_name\x18\x01 \x01(\t\x12\x10\n\x08identity\x18\x02 \x01(\t\x12\x14\n\x0cscreen_share\x18\x03 \x01(\x08\x12\x30\n\x06preset\x18\x04 \x01(\x0e\x32\x1e.livekit.EncodingOptionsPresetH\x00\x12,\n\x08\x61\x64vanced\x18\x05 \x01(\x0b\x32\x18.livekit.EncodingOptionsH\x00\x12\x30\n\x0c\x66ile_outputs\x18\x06 \x03(\x0b\x32\x1a.livekit.EncodedFileOutput\x12-\n\x0estream_outputs\x18\x07 \x03(\x0b\x32\x15.livekit.StreamOutput\x12\x35\n\x0fsegment_outputs\x18\x08 \x03(\x0b\x32\x1c.livekit.SegmentedFileOutput\x12+\n\rimage_outputs\x18\t \x03(\x0b\x32\x14.livekit.ImageOutputB\t\n\x07options\"\xad\x04\n\x1bTrackCompositeEgressRequest\x12\x11\n\troom_name\x18\x01 \x01(\t\x12\x16\n\x0e\x61udio_track_id\x18\x02 \x01(\t\x12\x16\n\x0evideo_track_id\x18\x03 \x01(\t\x12.\n\x04\x66ile\x18\x04 \x01(\x0b\x32\x1a.livekit.EncodedFileOutputB\x02\x18\x01H\x00\x12+\n\x06stream\x18\x05 \x01(\x0b\x32\x15.livekit.StreamOutputB\x02\x18\x01H\x00\x12\x34\n\x08segments\x18\x08 \x01(\x0b\x32\x1c.livekit.SegmentedFileOutputB\x02\x18\x01H\x00\x12\x30\n\x06preset\x18\x06 \x01(\x0e\x32\x1e.livekit.EncodingOptionsPresetH\x01\x12,\n\x08\x61\x64vanced\x18\x07 \x01(\x0b\x32\x18.livekit.EncodingOptionsH\x01\x12\x30\n\x0c\x66ile_outputs\x18\x0b \x03(\x0b\x32\x1a.livekit.EncodedFileOutput\x12-\n\x0estream_outputs\x18\x0c \x03(\x0b\x32\x15.livekit.StreamOutput\x12\x35\n\x0fsegment_outputs\x18\r \x03(\x0b\x32\x1c.livekit.SegmentedFileOutput\x12+\n\rimage_outputs\x18\x0e \x03(\x0b\x32\x14.livekit.ImageOutputB\x08\n\x06outputB\t\n\x07options\"\x87\x01\n\x12TrackEgressRequest\x12\x11\n\troom_name\x18\x01 \x01(\t\x12\x10\n\x08track_id\x18\x02 \x01(\t\x12)\n\x04\x66ile\x18\x03 \x01(\x0b\x32\x19.livekit.DirectFileOutputH\x00\x12\x17\n\rwebsocket_url\x18\x04 \x01(\tH\x00\x42\x08\n\x06output\"\x8e\x02\n\x11\x45ncodedFileOutput\x12+\n\tfile_type\x18\x01 \x01(\x0e\x32\x18.livekit.EncodedFileType\x12\x10\n\x08\x66ilepath\x18\x02 \x01(\t\x12\x18\n\x10\x64isable_manifest\x18\x06 \x01(\x08\x12\x1f\n\x02s3\x18\x03 \x01(\x0b\x32\x11.livekit.S3UploadH\x00\x12!\n\x03gcp\x18\x04 \x01(\x0b\x32\x12.livekit.GCPUploadH\x00\x12)\n\x05\x61zure\x18\x05 \x01(\x0b\x32\x18.livekit.AzureBlobUploadH\x00\x12\'\n\x06\x61liOSS\x18\x07 \x01(\x0b\x32\x15.livekit.AliOSSUploadH\x00\x42\x08\n\x06output\"\xa0\x03\n\x13SegmentedFileOutput\x12\x30\n\x08protocol\x18\x01 \x01(\x0e\x32\x1e.livekit.SegmentedFileProtocol\x12\x17\n\x0f\x66ilename_prefix\x18\x02 \x01(\t\x12\x15\n\rplaylist_name\x18\x03 \x01(\t\x12\x1a\n\x12live_playlist_name\x18\x0b \x01(\t\x12\x18\n\x10segment_duration\x18\x04 \x01(\r\x12\x35\n\x0f\x66ilename_suffix\x18\n \x01(\x0e\x32\x1c.livekit.SegmentedFileSuffix\x12\x18\n\x10\x64isable_manifest\x18\x08 \x01(\x08\x12\x1f\n\x02s3\x18\x05 \x01(\x0b\x32\x11.livekit.S3UploadH\x00\x12!\n\x03gcp\x18\x06 \x01(\x0b\x32\x12.livekit.GCPUploadH\x00\x12)\n\x05\x61zure\x18\x07 \x01(\x0b\x32\x18.livekit.AzureBlobUploadH\x00\x12\'\n\x06\x61liOSS\x18\t \x01(\x0b\x32\x15.livekit.AliOSSUploadH\x00\x42\x08\n\x06output\"\xe0\x01\n\x10\x44irectFileOutput\x12\x10\n\x08\x66ilepath\x18\x01 \x01(\t\x12\x18\n\x10\x64isable_manifest\x18\x05 \x01(\x08\x12\x1f\n\x02s3\x18\x02 \x01(\x0b\x32\x11.livekit.S3UploadH\x00\x12!\n\x03gcp\x18\x03 \x01(\x0b\x32\x12.livekit.GCPUploadH\x00\x12)\n\x05\x61zure\x18\x04 \x01(\x0b\x32\x18.livekit.AzureBlobUploadH\x00\x12\'\n\x06\x61liOSS\x18\x06 \x01(\x0b\x32\x15.livekit.AliOSSUploadH\x00\x42\x08\n\x06output\"\xf8\x02\n\x0bImageOutput\x12\x18\n\x10\x63\x61pture_interval\x18\x01 \x01(\r\x12\r\n\x05width\x18\x02 \x01(\x05\x12\x0e\n\x06height\x18\x03 \x01(\x05\x12\x17\n\x0f\x66ilename_prefix\x18\x04 \x01(\t\x12\x31\n\x0f\x66ilename_suffix\x18\x05 \x01(\x0e\x32\x18.livekit.ImageFileSuffix\x12(\n\x0bimage_codec\x18\x06 \x01(\x0e\x32\x13.livekit.ImageCodec\x12\x18\n\x10\x64isable_manifest\x18\x07 \x01(\x08\x12\x1f\n\x02s3\x18\x08 \x01(\x0b\x32\x11.livekit.S3UploadH\x00\x12!\n\x03gcp\x18\t \x01(\x0b\x32\x12.livekit.GCPUploadH\x00\x12)\n\x05\x61zure\x18\n \x01(\x0b\x32\x18.livekit.AzureBlobUploadH\x00\x12\'\n\x06\x61liOSS\x18\x0b \x01(\x0b\x32\x15.livekit.AliOSSUploadH\x00\x42\x08\n\x06output\"\xc8\x02\n\x08S3Upload\x12\x12\n\naccess_key\x18\x01 \x01(\t\x12\x0e\n\x06secret\x18\x02 \x01(\t\x12\x15\n\rsession_token\x18\x0b \x01(\t\x12\x0e\n\x06region\x18\x03 \x01(\t\x12\x10\n\x08\x65ndpoint\x18\x04 \x01(\t\x12\x0e\n\x06\x62ucket\x18\x05 \x01(\t\x12\x18\n\x10\x66orce_path_style\x18\x06 \x01(\x08\x12\x31\n\x08metadata\x18\x07 \x03(\x0b\x32\x1f.livekit.S3Upload.MetadataEntry\x12\x0f\n\x07tagging\x18\x08 \x01(\t\x12\x1b\n\x13\x63ontent_disposition\x18\t \x01(\t\x12#\n\x05proxy\x18\n \x01(\x0b\x32\x14.livekit.ProxyConfig\x1a/\n\rMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"U\n\tGCPUpload\x12\x13\n\x0b\x63redentials\x18\x01 \x01(\t\x12\x0e\n\x06\x62ucket\x18\x02 \x01(\t\x12#\n\x05proxy\x18\x03 \x01(\x0b\x32\x14.livekit.ProxyConfig\"T\n\x0f\x41zureBlobUpload\x12\x14\n\x0c\x61\x63\x63ount_name\x18\x01 \x01(\t\x12\x13\n\x0b\x61\x63\x63ount_key\x18\x02 \x01(\t\x12\x16\n\x0e\x63ontainer_name\x18\x03 \x01(\t\"d\n\x0c\x41liOSSUpload\x12\x12\n\naccess_key\x18\x01 \x01(\t\x12\x0e\n\x06secret\x18\x02 \x01(\t\x12\x0e\n\x06region\x18\x03 \x01(\t\x12\x10\n\x08\x65ndpoint\x18\x04 \x01(\t\x12\x0e\n\x06\x62ucket\x18\x05 \x01(\t\">\n\x0bProxyConfig\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x10\n\x08username\x18\x02 \x01(\t\x12\x10\n\x08password\x18\x03 \x01(\t\"G\n\x0cStreamOutput\x12)\n\x08protocol\x18\x01 \x01(\x0e\x32\x17.livekit.StreamProtocol\x12\x0c\n\x04urls\x18\x02 \x03(\t\"\xb7\x02\n\x0f\x45ncodingOptions\x12\r\n\x05width\x18\x01 \x01(\x05\x12\x0e\n\x06height\x18\x02 \x01(\x05\x12\r\n\x05\x64\x65pth\x18\x03 \x01(\x05\x12\x11\n\tframerate\x18\x04 \x01(\x05\x12(\n\x0b\x61udio_codec\x18\x05 \x01(\x0e\x32\x13.livekit.AudioCodec\x12\x15\n\raudio_bitrate\x18\x06 \x01(\x05\x12\x15\n\raudio_quality\x18\x0b \x01(\x05\x12\x17\n\x0f\x61udio_frequency\x18\x07 \x01(\x05\x12(\n\x0bvideo_codec\x18\x08 \x01(\x0e\x32\x13.livekit.VideoCodec\x12\x15\n\rvideo_bitrate\x18\t \x01(\x05\x12\x15\n\rvideo_quality\x18\x0c \x01(\x05\x12\x1a\n\x12key_frame_interval\x18\n \x01(\x01\"8\n\x13UpdateLayoutRequest\x12\x11\n\tegress_id\x18\x01 \x01(\t\x12\x0e\n\x06layout\x18\x02 \x01(\t\"]\n\x13UpdateStreamRequest\x12\x11\n\tegress_id\x18\x01 \x01(\t\x12\x17\n\x0f\x61\x64\x64_output_urls\x18\x02 \x03(\t\x12\x1a\n\x12remove_output_urls\x18\x03 \x03(\t\"I\n\x11ListEgressRequest\x12\x11\n\troom_name\x18\x01 \x01(\t\x12\x11\n\tegress_id\x18\x02 \x01(\t\x12\x0e\n\x06\x61\x63tive\x18\x03 \x01(\x08\"8\n\x12ListEgressResponse\x12\"\n\x05items\x18\x01 \x03(\x0b\x32\x13.livekit.EgressInfo\"&\n\x11StopEgressRequest\x12\x11\n\tegress_id\x18\x01 \x01(\t\"\xb6\x06\n\nEgressInfo\x12\x11\n\tegress_id\x18\x01 \x01(\t\x12\x0f\n\x07room_id\x18\x02 \x01(\t\x12\x11\n\troom_name\x18\r \x01(\t\x12%\n\x06status\x18\x03 \x01(\x0e\x32\x15.livekit.EgressStatus\x12\x12\n\nstarted_at\x18\n \x01(\x03\x12\x10\n\x08\x65nded_at\x18\x0b \x01(\x03\x12\x12\n\nupdated_at\x18\x12 \x01(\x03\x12\x0f\n\x07\x64\x65tails\x18\x15 \x01(\t\x12\r\n\x05\x65rror\x18\t \x01(\t\x12\x12\n\nerror_code\x18\x16 \x01(\x05\x12=\n\x0eroom_composite\x18\x04 \x01(\x0b\x32#.livekit.RoomCompositeEgressRequestH\x00\x12(\n\x03web\x18\x0e \x01(\x0b\x32\x19.livekit.WebEgressRequestH\x00\x12\x38\n\x0bparticipant\x18\x13 \x01(\x0b\x32!.livekit.ParticipantEgressRequestH\x00\x12?\n\x0ftrack_composite\x18\x05 \x01(\x0b\x32$.livekit.TrackCompositeEgressRequestH\x00\x12,\n\x05track\x18\x06 \x01(\x0b\x32\x1b.livekit.TrackEgressRequestH\x00\x12-\n\x06stream\x18\x07 \x01(\x0b\x32\x17.livekit.StreamInfoListB\x02\x18\x01H\x01\x12%\n\x04\x66ile\x18\x08 \x01(\x0b\x32\x11.livekit.FileInfoB\x02\x18\x01H\x01\x12-\n\x08segments\x18\x0c \x01(\x0b\x32\x15.livekit.SegmentsInfoB\x02\x18\x01H\x01\x12+\n\x0estream_results\x18\x0f \x03(\x0b\x32\x13.livekit.StreamInfo\x12\'\n\x0c\x66ile_results\x18\x10 \x03(\x0b\x32\x11.livekit.FileInfo\x12.\n\x0fsegment_results\x18\x11 \x03(\x0b\x32\x15.livekit.SegmentsInfo\x12*\n\rimage_results\x18\x14 \x03(\x0b\x32\x13.livekit.ImagesInfoB\t\n\x07requestB\x08\n\x06result\"7\n\x0eStreamInfoList\x12!\n\x04info\x18\x01 \x03(\x0b\x32\x13.livekit.StreamInfo:\x02\x18\x01\"\xbc\x01\n\nStreamInfo\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x12\n\nstarted_at\x18\x02 \x01(\x03\x12\x10\n\x08\x65nded_at\x18\x03 \x01(\x03\x12\x10\n\x08\x64uration\x18\x04 \x01(\x03\x12*\n\x06status\x18\x05 \x01(\x0e\x32\x1a.livekit.StreamInfo.Status\x12\r\n\x05\x65rror\x18\x06 \x01(\t\".\n\x06Status\x12\n\n\x06\x41\x43TIVE\x10\x00\x12\x0c\n\x08\x46INISHED\x10\x01\x12\n\n\x06\x46\x41ILED\x10\x02\"t\n\x08\x46ileInfo\x12\x10\n\x08\x66ilename\x18\x01 \x01(\t\x12\x12\n\nstarted_at\x18\x02 \x01(\x03\x12\x10\n\x08\x65nded_at\x18\x03 \x01(\x03\x12\x10\n\x08\x64uration\x18\x06 \x01(\x03\x12\x0c\n\x04size\x18\x04 \x01(\x03\x12\x10\n\x08location\x18\x05 \x01(\t\"\xd9\x01\n\x0cSegmentsInfo\x12\x15\n\rplaylist_name\x18\x01 \x01(\t\x12\x1a\n\x12live_playlist_name\x18\x08 \x01(\t\x12\x10\n\x08\x64uration\x18\x02 \x01(\x03\x12\x0c\n\x04size\x18\x03 \x01(\x03\x12\x19\n\x11playlist_location\x18\x04 \x01(\t\x12\x1e\n\x16live_playlist_location\x18\t \x01(\t\x12\x15\n\rsegment_count\x18\x05 \x01(\x03\x12\x12\n\nstarted_at\x18\x06 \x01(\x03\x12\x10\n\x08\x65nded_at\x18\x07 \x01(\x03\"G\n\nImagesInfo\x12\x13\n\x0bimage_count\x18\x01 \x01(\x03\x12\x12\n\nstarted_at\x18\x02 \x01(\x03\x12\x10\n\x08\x65nded_at\x18\x03 \x01(\x03\"\xeb\x01\n\x15\x41utoParticipantEgress\x12\x30\n\x06preset\x18\x01 \x01(\x0e\x32\x1e.livekit.EncodingOptionsPresetH\x00\x12,\n\x08\x61\x64vanced\x18\x02 \x01(\x0b\x32\x18.livekit.EncodingOptionsH\x00\x12\x30\n\x0c\x66ile_outputs\x18\x03 \x03(\x0b\x32\x1a.livekit.EncodedFileOutput\x12\x35\n\x0fsegment_outputs\x18\x04 \x03(\x0b\x32\x1c.livekit.SegmentedFileOutputB\t\n\x07options\"\xdf\x01\n\x0f\x41utoTrackEgress\x12\x10\n\x08\x66ilepath\x18\x01 \x01(\t\x12\x18\n\x10\x64isable_manifest\x18\x05 \x01(\x08\x12\x1f\n\x02s3\x18\x02 \x01(\x0b\x32\x11.livekit.S3UploadH\x00\x12!\n\x03gcp\x18\x03 \x01(\x0b\x32\x12.livekit.GCPUploadH\x00\x12)\n\x05\x61zure\x18\x04 \x01(\x0b\x32\x18.livekit.AzureBlobUploadH\x00\x12\'\n\x06\x61liOSS\x18\x06 \x01(\x0b\x32\x15.livekit.AliOSSUploadH\x00\x42\x08\n\x06output*9\n\x0f\x45ncodedFileType\x12\x14\n\x10\x44\x45\x46\x41ULT_FILETYPE\x10\x00\x12\x07\n\x03MP4\x10\x01\x12\x07\n\x03OGG\x10\x02*N\n\x15SegmentedFileProtocol\x12#\n\x1f\x44\x45\x46\x41ULT_SEGMENTED_FILE_PROTOCOL\x10\x00\x12\x10\n\x0cHLS_PROTOCOL\x10\x01*/\n\x13SegmentedFileSuffix\x12\t\n\x05INDEX\x10\x00\x12\r\n\tTIMESTAMP\x10\x01*E\n\x0fImageFileSuffix\x12\x16\n\x12IMAGE_SUFFIX_INDEX\x10\x00\x12\x1a\n\x16IMAGE_SUFFIX_TIMESTAMP\x10\x01*0\n\x0eStreamProtocol\x12\x14\n\x10\x44\x45\x46\x41ULT_PROTOCOL\x10\x00\x12\x08\n\x04RTMP\x10\x01*\xcf\x01\n\x15\x45ncodingOptionsPreset\x12\x10\n\x0cH264_720P_30\x10\x00\x12\x10\n\x0cH264_720P_60\x10\x01\x12\x11\n\rH264_1080P_30\x10\x02\x12\x11\n\rH264_1080P_60\x10\x03\x12\x19\n\x15PORTRAIT_H264_720P_30\x10\x04\x12\x19\n\x15PORTRAIT_H264_720P_60\x10\x05\x12\x1a\n\x16PORTRAIT_H264_1080P_30\x10\x06\x12\x1a\n\x16PORTRAIT_H264_1080P_60\x10\x07*\x9f\x01\n\x0c\x45gressStatus\x12\x13\n\x0f\x45GRESS_STARTING\x10\x00\x12\x11\n\rEGRESS_ACTIVE\x10\x01\x12\x11\n\rEGRESS_ENDING\x10\x02\x12\x13\n\x0f\x45GRESS_COMPLETE\x10\x03\x12\x11\n\rEGRESS_FAILED\x10\x04\x12\x12\n\x0e\x45GRESS_ABORTED\x10\x05\x12\x18\n\x14\x45GRESS_LIMIT_REACHED\x10\x06\x32\x9c\x05\n\x06\x45gress\x12T\n\x18StartRoomCompositeEgress\x12#.livekit.RoomCompositeEgressRequest\x1a\x13.livekit.EgressInfo\x12@\n\x0eStartWebEgress\x12\x19.livekit.WebEgressRequest\x1a\x13.livekit.EgressInfo\x12P\n\x16StartParticipantEgress\x12!.livekit.ParticipantEgressRequest\x1a\x13.livekit.EgressInfo\x12V\n\x19StartTrackCompositeEgress\x12$.livekit.TrackCompositeEgressRequest\x1a\x13.livekit.EgressInfo\x12\x44\n\x10StartTrackEgress\x12\x1b.livekit.TrackEgressRequest\x1a\x13.livekit.EgressInfo\x12\x41\n\x0cUpdateLayout\x12\x1c.livekit.UpdateLayoutRequest\x1a\x13.livekit.EgressInfo\x12\x41\n\x0cUpdateStream\x12\x1c.livekit.UpdateStreamRequest\x1a\x13.livekit.EgressInfo\x12\x45\n\nListEgress\x12\x1a.livekit.ListEgressRequest\x1a\x1b.livekit.ListEgressResponse\x12=\n\nStopEgress\x12\x1a.livekit.StopEgressRequest\x1a\x13.livekit.EgressInfoBFZ#github.com/livekit/protocol/livekit\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x14livekit_egress.proto\x12\x07livekit\x1a\x14livekit_models.proto\x1a\x14logger/options.proto\"\x89\x03\n\x12StartEgressRequest\x12\x11\n\troom_name\x18\x01 \x01(\t\x12+\n\x08template\x18\x02 \x01(\x0b\x32\x17.livekit.TemplateSourceH\x00\x12!\n\x03web\x18\x03 \x01(\x0b\x32\x12.livekit.WebSourceH\x00\x12%\n\x05media\x18\x04 \x01(\x0b\x32\x14.livekit.MediaSourceH\x00\x12\x30\n\x06preset\x18\x05 \x01(\x0e\x32\x1e.livekit.EncodingOptionsPresetH\x01\x12,\n\x08\x61\x64vanced\x18\x06 \x01(\x0b\x32\x18.livekit.EncodingOptionsH\x01\x12 \n\x07outputs\x18\x07 \x03(\x0b\x32\x0f.livekit.Output\x12\'\n\x07storage\x18\x08 \x01(\x0b\x32\x16.livekit.StorageConfig\x12(\n\x08webhooks\x18\t \x03(\x0b\x32\x16.livekit.WebhookConfigB\x08\n\x06sourceB\n\n\x08\x65ncoding\"a\n\x0eTemplateSource\x12\x0e\n\x06layout\x18\x01 \x01(\t\x12\x12\n\naudio_only\x18\x02 \x01(\x08\x12\x12\n\nvideo_only\x18\x03 \x01(\x08\x12\x17\n\x0f\x63ustom_base_url\x18\x04 \x01(\t\"\\\n\tWebSource\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x12\n\naudio_only\x18\x02 \x01(\x08\x12\x12\n\nvideo_only\x18\x03 \x01(\x08\x12\x1a\n\x12\x61wait_start_signal\x18\x04 \x01(\x08\"\xc1\x01\n\x0bMediaSource\x12)\n\x0evideo_track_id\x18\x01 \x01(\tB\x0f\xbaP\x0cvideoTrackIDH\x00\x12\x36\n\x11participant_video\x18\x02 \x01(\x0b\x32\x19.livekit.ParticipantVideoH\x00\x12#\n\x05\x61udio\x18\x03 \x01(\x0b\x32\x14.livekit.AudioConfig\x12!\n\x04\x64\x61ta\x18\x04 \x01(\x0b\x32\x13.livekit.DataConfigB\x07\n\x05video\"A\n\x10ParticipantVideo\x12\x10\n\x08identity\x18\x01 \x01(\t\x12\x1b\n\x13prefer_screen_share\x18\x02 \x01(\x08\"2\n\x0b\x41udioConfig\x12#\n\x06routes\x18\x01 \x03(\x0b\x32\x13.livekit.AudioRoute\"\xb8\x01\n\nAudioRoute\x12\x1e\n\x08track_id\x18\x01 \x01(\tB\n\xbaP\x07trackIDH\x00\x12\x1e\n\x14participant_identity\x18\x02 \x01(\tH\x00\x12\x39\n\x10participant_kind\x18\x03 \x01(\x0e\x32\x1d.livekit.ParticipantInfo.KindH\x00\x12&\n\x07\x63hannel\x18\x04 \x01(\x0e\x32\x15.livekit.AudioChannelB\x07\n\x05match\"6\n\nDataConfig\x12(\n\tselectors\x18\x01 \x03(\x0b\x32\x15.livekit.DataSelector\"h\n\x0c\x44\x61taSelector\x12\x1e\n\x08track_id\x18\x01 \x01(\tB\n\xbaP\x07trackIDH\x00\x12\x1e\n\x14participant_identity\x18\x02 \x01(\tH\x00\x12\x0f\n\x05topic\x18\x03 \x01(\tH\x00\x42\x07\n\x05match\"\xbf\x02\n\x0f\x45ncodingOptions\x12\r\n\x05width\x18\x01 \x01(\x05\x12\x0e\n\x06height\x18\x02 \x01(\x05\x12\r\n\x05\x64\x65pth\x18\x03 \x01(\x05\x12\x11\n\tframerate\x18\x04 \x01(\x05\x12(\n\x0b\x61udio_codec\x18\x05 \x01(\x0e\x32\x13.livekit.AudioCodec\x12\x15\n\raudio_bitrate\x18\x06 \x01(\x05\x12\x17\n\x0f\x61udio_frequency\x18\x07 \x01(\x05\x12(\n\x0bvideo_codec\x18\x08 \x01(\x0e\x32\x13.livekit.VideoCodec\x12\x15\n\rvideo_bitrate\x18\t \x01(\x05\x12\x1a\n\x12key_frame_interval\x18\n \x01(\x01\x12\x19\n\raudio_quality\x18\x0b \x01(\x05\x42\x02\x18\x01\x12\x19\n\rvideo_quality\x18\x0c \x01(\x05\x42\x02\x18\x01\"\xe3\x01\n\x06Output\x12#\n\x04\x66ile\x18\x01 \x01(\x0b\x32\x13.livekit.FileOutputH\x00\x12\'\n\x06stream\x18\x02 \x01(\x0b\x32\x15.livekit.StreamOutputH\x00\x12\x30\n\x08segments\x18\x03 \x01(\x0b\x32\x1c.livekit.SegmentedFileOutputH\x00\x12&\n\x06images\x18\x04 \x01(\x0b\x32\x14.livekit.ImageOutputH\x00\x12\'\n\x07storage\x18\x06 \x01(\x0b\x32\x16.livekit.StorageConfigB\x08\n\x06\x63onfig\"e\n\nFileOutput\x12+\n\tfile_type\x18\x01 \x01(\x0e\x32\x18.livekit.EncodedFileType\x12\x10\n\x08\x66ilepath\x18\x02 \x01(\t\x12\x18\n\x10\x64isable_manifest\x18\x03 \x01(\x08\"G\n\x0cStreamOutput\x12)\n\x08protocol\x18\x01 \x01(\x0e\x32\x17.livekit.StreamProtocol\x12\x0c\n\x04urls\x18\x02 \x03(\t\"\xa0\x03\n\x13SegmentedFileOutput\x12\x30\n\x08protocol\x18\x01 \x01(\x0e\x32\x1e.livekit.SegmentedFileProtocol\x12\x17\n\x0f\x66ilename_prefix\x18\x02 \x01(\t\x12\x15\n\rplaylist_name\x18\x03 \x01(\t\x12\x1a\n\x12live_playlist_name\x18\x0b \x01(\t\x12\x18\n\x10segment_duration\x18\x04 \x01(\r\x12\x35\n\x0f\x66ilename_suffix\x18\n \x01(\x0e\x32\x1c.livekit.SegmentedFileSuffix\x12\x18\n\x10\x64isable_manifest\x18\x08 \x01(\x08\x12\x1f\n\x02s3\x18\x05 \x01(\x0b\x32\x11.livekit.S3UploadH\x00\x12!\n\x03gcp\x18\x06 \x01(\x0b\x32\x12.livekit.GCPUploadH\x00\x12)\n\x05\x61zure\x18\x07 \x01(\x0b\x32\x18.livekit.AzureBlobUploadH\x00\x12\'\n\x06\x61liOSS\x18\t \x01(\x0b\x32\x15.livekit.AliOSSUploadH\x00\x42\x08\n\x06output\"\xf8\x02\n\x0bImageOutput\x12\x18\n\x10\x63\x61pture_interval\x18\x01 \x01(\r\x12\r\n\x05width\x18\x02 \x01(\x05\x12\x0e\n\x06height\x18\x03 \x01(\x05\x12\x17\n\x0f\x66ilename_prefix\x18\x04 \x01(\t\x12\x31\n\x0f\x66ilename_suffix\x18\x05 \x01(\x0e\x32\x18.livekit.ImageFileSuffix\x12(\n\x0bimage_codec\x18\x06 \x01(\x0e\x32\x13.livekit.ImageCodec\x12\x18\n\x10\x64isable_manifest\x18\x07 \x01(\x08\x12\x1f\n\x02s3\x18\x08 \x01(\x0b\x32\x11.livekit.S3UploadH\x00\x12!\n\x03gcp\x18\t \x01(\x0b\x32\x12.livekit.GCPUploadH\x00\x12)\n\x05\x61zure\x18\n \x01(\x0b\x32\x18.livekit.AzureBlobUploadH\x00\x12\'\n\x06\x61liOSS\x18\x0b \x01(\x0b\x32\x15.livekit.AliOSSUploadH\x00\x42\x08\n\x06output\"\xb3\x01\n\rStorageConfig\x12\x1f\n\x02s3\x18\x01 \x01(\x0b\x32\x11.livekit.S3UploadH\x00\x12!\n\x03gcp\x18\x02 \x01(\x0b\x32\x12.livekit.GCPUploadH\x00\x12)\n\x05\x61zure\x18\x03 \x01(\x0b\x32\x18.livekit.AzureBlobUploadH\x00\x12\'\n\x06\x61liOSS\x18\x04 \x01(\x0b\x32\x15.livekit.AliOSSUploadH\x00\x42\n\n\x08provider\"\xb2\x03\n\x08S3Upload\x12\x17\n\naccess_key\x18\x01 \x01(\tB\x03\xa8P\x01\x12\x13\n\x06secret\x18\x02 \x01(\tB\x03\xa8P\x01\x12\x1a\n\rsession_token\x18\x0b \x01(\tB\x03\xa8P\x01\x12\x1c\n\x0f\x61ssume_role_arn\x18\x0c \x01(\tB\x03\xa8P\x01\x12;\n\x17\x61ssume_role_external_id\x18\r \x01(\tB\x1a\xa8P\x01\xbaP\x14\x61ssumeRoleExternalID\x12\x0e\n\x06region\x18\x03 \x01(\t\x12\x10\n\x08\x65ndpoint\x18\x04 \x01(\t\x12\x0e\n\x06\x62ucket\x18\x05 \x01(\t\x12\x18\n\x10\x66orce_path_style\x18\x06 \x01(\x08\x12\x31\n\x08metadata\x18\x07 \x03(\x0b\x32\x1f.livekit.S3Upload.MetadataEntry\x12\x0f\n\x07tagging\x18\x08 \x01(\t\x12\x1b\n\x13\x63ontent_disposition\x18\t \x01(\t\x12#\n\x05proxy\x18\n \x01(\x0b\x32\x14.livekit.ProxyConfig\x1a/\n\rMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"Z\n\tGCPUpload\x12\x18\n\x0b\x63redentials\x18\x01 \x01(\tB\x03\xa8P\x01\x12\x0e\n\x06\x62ucket\x18\x02 \x01(\t\x12#\n\x05proxy\x18\x03 \x01(\x0b\x32\x14.livekit.ProxyConfig\"^\n\x0f\x41zureBlobUpload\x12\x19\n\x0c\x61\x63\x63ount_name\x18\x01 \x01(\tB\x03\xa8P\x01\x12\x18\n\x0b\x61\x63\x63ount_key\x18\x02 \x01(\tB\x03\xa8P\x01\x12\x16\n\x0e\x63ontainer_name\x18\x03 \x01(\t\"n\n\x0c\x41liOSSUpload\x12\x17\n\naccess_key\x18\x01 \x01(\tB\x03\xa8P\x01\x12\x13\n\x06secret\x18\x02 \x01(\tB\x03\xa8P\x01\x12\x0e\n\x06region\x18\x03 \x01(\t\x12\x10\n\x08\x65ndpoint\x18\x04 \x01(\t\x12\x0e\n\x06\x62ucket\x18\x05 \x01(\t\"C\n\x0bProxyConfig\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x10\n\x08username\x18\x02 \x01(\t\x12\x15\n\x08password\x18\x03 \x01(\tB\x03\xa8P\x01\"V\n\x11ListEgressRequest\x12\x11\n\troom_name\x18\x01 \x01(\t\x12\x1e\n\tegress_id\x18\x02 \x01(\tB\x0b\xbaP\x08\x65gressID\x12\x0e\n\x06\x61\x63tive\x18\x03 \x01(\x08\"8\n\x12ListEgressResponse\x12\"\n\x05items\x18\x01 \x03(\x0b\x32\x13.livekit.EgressInfo\"\x87\x01\n\x13UpdateEgressRequest\x12\x1e\n\tegress_id\x18\x01 \x01(\tB\x0b\xbaP\x08\x65gressID\x12\x0b\n\x03url\x18\x02 \x01(\t\x12\x0e\n\x06layout\x18\x03 \x01(\t\x12\x17\n\x0f\x61\x64\x64_stream_urls\x18\x04 \x03(\t\x12\x1a\n\x12remove_stream_urls\x18\x05 \x03(\t\"3\n\x11StopEgressRequest\x12\x1e\n\tegress_id\x18\x01 \x01(\tB\x0b\xbaP\x08\x65gressID\"\xfb\x07\n\nEgressInfo\x12\x1e\n\tegress_id\x18\x01 \x01(\tB\x0b\xbaP\x08\x65gressID\x12\x1a\n\x07room_id\x18\x02 \x01(\tB\t\xbaP\x06roomID\x12\x11\n\troom_name\x18\r \x01(\t\x12.\n\x0bsource_type\x18\x1a \x01(\x0e\x32\x19.livekit.EgressSourceType\x12%\n\x06status\x18\x03 \x01(\x0e\x32\x15.livekit.EgressStatus\x12\x12\n\nstarted_at\x18\n \x01(\x03\x12\x10\n\x08\x65nded_at\x18\x0b \x01(\x03\x12\x12\n\nupdated_at\x18\x12 \x01(\x03\x12.\n\x06replay\x18\x1e \x01(\x0b\x32\x1c.livekit.ExportReplayRequestH\x00\x12=\n\x0eroom_composite\x18\x04 \x01(\x0b\x32#.livekit.RoomCompositeEgressRequestH\x00\x12(\n\x03web\x18\x0e \x01(\x0b\x32\x19.livekit.WebEgressRequestH\x00\x12\x38\n\x0bparticipant\x18\x13 \x01(\x0b\x32!.livekit.ParticipantEgressRequestH\x00\x12?\n\x0ftrack_composite\x18\x05 \x01(\x0b\x32$.livekit.TrackCompositeEgressRequestH\x00\x12,\n\x05track\x18\x06 \x01(\x0b\x32\x1b.livekit.TrackEgressRequestH\x00\x12+\n\x0estream_results\x18\x0f \x03(\x0b\x32\x13.livekit.StreamInfo\x12\'\n\x0c\x66ile_results\x18\x10 \x03(\x0b\x32\x11.livekit.FileInfo\x12.\n\x0fsegment_results\x18\x11 \x03(\x0b\x32\x15.livekit.SegmentsInfo\x12*\n\rimage_results\x18\x14 \x03(\x0b\x32\x13.livekit.ImagesInfo\x12\r\n\x05\x65rror\x18\t \x01(\t\x12\x12\n\nerror_code\x18\x16 \x01(\x05\x12\x0f\n\x07\x64\x65tails\x18\x15 \x01(\t\x12\x19\n\x11manifest_location\x18\x17 \x01(\t\x12\x1b\n\x13\x62\x61\x63kup_storage_used\x18\x19 \x01(\x08\x12\x13\n\x0bretry_count\x18\x1b \x01(\x05\x12-\n\x06stream\x18\x07 \x01(\x0b\x32\x17.livekit.StreamInfoListB\x02\x18\x01H\x01\x12%\n\x04\x66ile\x18\x08 \x01(\x0b\x32\x11.livekit.FileInfoB\x02\x18\x01H\x01\x12-\n\x08segments\x18\x0c \x01(\x0b\x32\x15.livekit.SegmentsInfoB\x02\x18\x01H\x01\x42\t\n\x07requestB\x08\n\x06result\"\xe4\x01\n\nStreamInfo\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x12\n\nstarted_at\x18\x02 \x01(\x03\x12\x10\n\x08\x65nded_at\x18\x03 \x01(\x03\x12\x10\n\x08\x64uration\x18\x04 \x01(\x03\x12*\n\x06status\x18\x05 \x01(\x0e\x32\x1a.livekit.StreamInfo.Status\x12\r\n\x05\x65rror\x18\x06 \x01(\t\x12\x15\n\rlast_retry_at\x18\x07 \x01(\x03\x12\x0f\n\x07retries\x18\x08 \x01(\r\".\n\x06Status\x12\n\n\x06\x41\x43TIVE\x10\x00\x12\x0c\n\x08\x46INISHED\x10\x01\x12\n\n\x06\x46\x41ILED\x10\x02\"t\n\x08\x46ileInfo\x12\x10\n\x08\x66ilename\x18\x01 \x01(\t\x12\x12\n\nstarted_at\x18\x02 \x01(\x03\x12\x10\n\x08\x65nded_at\x18\x03 \x01(\x03\x12\x10\n\x08\x64uration\x18\x06 \x01(\x03\x12\x0c\n\x04size\x18\x04 \x01(\x03\x12\x10\n\x08location\x18\x05 \x01(\t\"\xd9\x01\n\x0cSegmentsInfo\x12\x15\n\rplaylist_name\x18\x01 \x01(\t\x12\x1a\n\x12live_playlist_name\x18\x08 \x01(\t\x12\x10\n\x08\x64uration\x18\x02 \x01(\x03\x12\x0c\n\x04size\x18\x03 \x01(\x03\x12\x19\n\x11playlist_location\x18\x04 \x01(\t\x12\x1e\n\x16live_playlist_location\x18\t \x01(\t\x12\x15\n\rsegment_count\x18\x05 \x01(\x03\x12\x12\n\nstarted_at\x18\x06 \x01(\x03\x12\x10\n\x08\x65nded_at\x18\x07 \x01(\x03\"`\n\nImagesInfo\x12\x17\n\x0f\x66ilename_prefix\x18\x04 \x01(\t\x12\x13\n\x0bimage_count\x18\x01 \x01(\x03\x12\x12\n\nstarted_at\x18\x02 \x01(\x03\x12\x10\n\x08\x65nded_at\x18\x03 \x01(\x03\"\xeb\x01\n\x15\x41utoParticipantEgress\x12\x30\n\x06preset\x18\x01 \x01(\x0e\x32\x1e.livekit.EncodingOptionsPresetH\x00\x12,\n\x08\x61\x64vanced\x18\x02 \x01(\x0b\x32\x18.livekit.EncodingOptionsH\x00\x12\x30\n\x0c\x66ile_outputs\x18\x03 \x03(\x0b\x32\x1a.livekit.EncodedFileOutput\x12\x35\n\x0fsegment_outputs\x18\x04 \x03(\x0b\x32\x1c.livekit.SegmentedFileOutputB\t\n\x07options\"\xdf\x01\n\x0f\x41utoTrackEgress\x12\x10\n\x08\x66ilepath\x18\x01 \x01(\t\x12\x18\n\x10\x64isable_manifest\x18\x05 \x01(\x08\x12\x1f\n\x02s3\x18\x02 \x01(\x0b\x32\x11.livekit.S3UploadH\x00\x12!\n\x03gcp\x18\x03 \x01(\x0b\x32\x12.livekit.GCPUploadH\x00\x12)\n\x05\x61zure\x18\x04 \x01(\x0b\x32\x18.livekit.AzureBlobUploadH\x00\x12\'\n\x06\x61liOSS\x18\x06 \x01(\x0b\x32\x15.livekit.AliOSSUploadH\x00\x42\x08\n\x06output\"\xc7\x03\n\x13\x45xportReplayRequest\x12\x1e\n\treplay_id\x18\x01 \x01(\tB\x0b\xbaP\x08replayID\x12\x17\n\x0fstart_offset_ms\x18\x02 \x01(\x03\x12\x15\n\rend_offset_ms\x18\x03 \x01(\x03\x12+\n\x08template\x18\x04 \x01(\x0b\x32\x17.livekit.TemplateSourceH\x00\x12!\n\x03web\x18\x05 \x01(\x0b\x32\x12.livekit.WebSourceH\x00\x12%\n\x05media\x18\x06 \x01(\x0b\x32\x14.livekit.MediaSourceH\x00\x12\x30\n\x06preset\x18\x07 \x01(\x0e\x32\x1e.livekit.EncodingOptionsPresetH\x01\x12,\n\x08\x61\x64vanced\x18\x08 \x01(\x0b\x32\x18.livekit.EncodingOptionsH\x01\x12 \n\x07outputs\x18\t \x03(\x0b\x32\x0f.livekit.Output\x12\'\n\x07storage\x18\n \x01(\x0b\x32\x16.livekit.StorageConfig\x12(\n\x08webhooks\x18\x0b \x03(\x0b\x32\x16.livekit.WebhookConfigB\x08\n\x06sourceB\n\n\x08\x65ncoding\"\xa3\x05\n\x1aRoomCompositeEgressRequest\x12\x11\n\troom_name\x18\x01 \x01(\t\x12\x0e\n\x06layout\x18\x02 \x01(\t\x12\x12\n\naudio_only\x18\x03 \x01(\x08\x12*\n\x0c\x61udio_mixing\x18\x0f \x01(\x0e\x32\x14.livekit.AudioMixing\x12\x12\n\nvideo_only\x18\x04 \x01(\x08\x12\x17\n\x0f\x63ustom_base_url\x18\x05 \x01(\t\x12.\n\x04\x66ile\x18\x06 \x01(\x0b\x32\x1a.livekit.EncodedFileOutputB\x02\x18\x01H\x00\x12+\n\x06stream\x18\x07 \x01(\x0b\x32\x15.livekit.StreamOutputB\x02\x18\x01H\x00\x12\x34\n\x08segments\x18\n \x01(\x0b\x32\x1c.livekit.SegmentedFileOutputB\x02\x18\x01H\x00\x12\x30\n\x06preset\x18\x08 \x01(\x0e\x32\x1e.livekit.EncodingOptionsPresetH\x01\x12,\n\x08\x61\x64vanced\x18\t \x01(\x0b\x32\x18.livekit.EncodingOptionsH\x01\x12\x30\n\x0c\x66ile_outputs\x18\x0b \x03(\x0b\x32\x1a.livekit.EncodedFileOutput\x12-\n\x0estream_outputs\x18\x0c \x03(\x0b\x32\x15.livekit.StreamOutput\x12\x35\n\x0fsegment_outputs\x18\r \x03(\x0b\x32\x1c.livekit.SegmentedFileOutput\x12+\n\rimage_outputs\x18\x0e \x03(\x0b\x32\x14.livekit.ImageOutput\x12(\n\x08webhooks\x18\x10 \x03(\x0b\x32\x16.livekit.WebhookConfigB\x08\n\x06outputB\t\n\x07options\"\xda\x04\n\x10WebEgressRequest\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x12\n\naudio_only\x18\x02 \x01(\x08\x12\x12\n\nvideo_only\x18\x03 \x01(\x08\x12\x1a\n\x12\x61wait_start_signal\x18\x0c \x01(\x08\x12.\n\x04\x66ile\x18\x04 \x01(\x0b\x32\x1a.livekit.EncodedFileOutputB\x02\x18\x01H\x00\x12+\n\x06stream\x18\x05 \x01(\x0b\x32\x15.livekit.StreamOutputB\x02\x18\x01H\x00\x12\x34\n\x08segments\x18\x06 \x01(\x0b\x32\x1c.livekit.SegmentedFileOutputB\x02\x18\x01H\x00\x12\x30\n\x06preset\x18\x07 \x01(\x0e\x32\x1e.livekit.EncodingOptionsPresetH\x01\x12,\n\x08\x61\x64vanced\x18\x08 \x01(\x0b\x32\x18.livekit.EncodingOptionsH\x01\x12\x30\n\x0c\x66ile_outputs\x18\t \x03(\x0b\x32\x1a.livekit.EncodedFileOutput\x12-\n\x0estream_outputs\x18\n \x03(\x0b\x32\x15.livekit.StreamOutput\x12\x35\n\x0fsegment_outputs\x18\x0b \x03(\x0b\x32\x1c.livekit.SegmentedFileOutput\x12+\n\rimage_outputs\x18\r \x03(\x0b\x32\x14.livekit.ImageOutput\x12(\n\x08webhooks\x18\x0e \x03(\x0b\x32\x16.livekit.WebhookConfigB\x08\n\x06outputB\t\n\x07options\"\xaf\x03\n\x18ParticipantEgressRequest\x12\x11\n\troom_name\x18\x01 \x01(\t\x12\x10\n\x08identity\x18\x02 \x01(\t\x12\x14\n\x0cscreen_share\x18\x03 \x01(\x08\x12\x30\n\x06preset\x18\x04 \x01(\x0e\x32\x1e.livekit.EncodingOptionsPresetH\x00\x12,\n\x08\x61\x64vanced\x18\x05 \x01(\x0b\x32\x18.livekit.EncodingOptionsH\x00\x12\x30\n\x0c\x66ile_outputs\x18\x06 \x03(\x0b\x32\x1a.livekit.EncodedFileOutput\x12-\n\x0estream_outputs\x18\x07 \x03(\x0b\x32\x15.livekit.StreamOutput\x12\x35\n\x0fsegment_outputs\x18\x08 \x03(\x0b\x32\x1c.livekit.SegmentedFileOutput\x12+\n\rimage_outputs\x18\t \x03(\x0b\x32\x14.livekit.ImageOutput\x12(\n\x08webhooks\x18\n \x03(\x0b\x32\x16.livekit.WebhookConfigB\t\n\x07options\"\xf9\x04\n\x1bTrackCompositeEgressRequest\x12\x11\n\troom_name\x18\x01 \x01(\t\x12\'\n\x0e\x61udio_track_id\x18\x02 \x01(\tB\x0f\xbaP\x0c\x61udioTrackID\x12\'\n\x0evideo_track_id\x18\x03 \x01(\tB\x0f\xbaP\x0cvideoTrackID\x12.\n\x04\x66ile\x18\x04 \x01(\x0b\x32\x1a.livekit.EncodedFileOutputB\x02\x18\x01H\x00\x12+\n\x06stream\x18\x05 \x01(\x0b\x32\x15.livekit.StreamOutputB\x02\x18\x01H\x00\x12\x34\n\x08segments\x18\x08 \x01(\x0b\x32\x1c.livekit.SegmentedFileOutputB\x02\x18\x01H\x00\x12\x30\n\x06preset\x18\x06 \x01(\x0e\x32\x1e.livekit.EncodingOptionsPresetH\x01\x12,\n\x08\x61\x64vanced\x18\x07 \x01(\x0b\x32\x18.livekit.EncodingOptionsH\x01\x12\x30\n\x0c\x66ile_outputs\x18\x0b \x03(\x0b\x32\x1a.livekit.EncodedFileOutput\x12-\n\x0estream_outputs\x18\x0c \x03(\x0b\x32\x15.livekit.StreamOutput\x12\x35\n\x0fsegment_outputs\x18\r \x03(\x0b\x32\x1c.livekit.SegmentedFileOutput\x12+\n\rimage_outputs\x18\x0e \x03(\x0b\x32\x14.livekit.ImageOutput\x12(\n\x08webhooks\x18\x0f \x03(\x0b\x32\x16.livekit.WebhookConfigB\x08\n\x06outputB\t\n\x07options\"\xbd\x01\n\x12TrackEgressRequest\x12\x11\n\troom_name\x18\x01 \x01(\t\x12\x1c\n\x08track_id\x18\x02 \x01(\tB\n\xbaP\x07trackID\x12)\n\x04\x66ile\x18\x03 \x01(\x0b\x32\x19.livekit.DirectFileOutputH\x00\x12\x17\n\rwebsocket_url\x18\x04 \x01(\tH\x00\x12(\n\x08webhooks\x18\x05 \x03(\x0b\x32\x16.livekit.WebhookConfigB\x08\n\x06output\"\xe0\x01\n\x10\x44irectFileOutput\x12\x10\n\x08\x66ilepath\x18\x01 \x01(\t\x12\x18\n\x10\x64isable_manifest\x18\x05 \x01(\x08\x12\x1f\n\x02s3\x18\x02 \x01(\x0b\x32\x11.livekit.S3UploadH\x00\x12!\n\x03gcp\x18\x03 \x01(\x0b\x32\x12.livekit.GCPUploadH\x00\x12)\n\x05\x61zure\x18\x04 \x01(\x0b\x32\x18.livekit.AzureBlobUploadH\x00\x12\'\n\x06\x61liOSS\x18\x06 \x01(\x0b\x32\x15.livekit.AliOSSUploadH\x00\x42\x08\n\x06output\"\x8e\x02\n\x11\x45ncodedFileOutput\x12+\n\tfile_type\x18\x01 \x01(\x0e\x32\x18.livekit.EncodedFileType\x12\x10\n\x08\x66ilepath\x18\x02 \x01(\t\x12\x18\n\x10\x64isable_manifest\x18\x06 \x01(\x08\x12\x1f\n\x02s3\x18\x03 \x01(\x0b\x32\x11.livekit.S3UploadH\x00\x12!\n\x03gcp\x18\x04 \x01(\x0b\x32\x12.livekit.GCPUploadH\x00\x12)\n\x05\x61zure\x18\x05 \x01(\x0b\x32\x18.livekit.AzureBlobUploadH\x00\x12\'\n\x06\x61liOSS\x18\x07 \x01(\x0b\x32\x15.livekit.AliOSSUploadH\x00\x42\x08\n\x06output\"E\n\x13UpdateLayoutRequest\x12\x1e\n\tegress_id\x18\x01 \x01(\tB\x0b\xbaP\x08\x65gressID\x12\x0e\n\x06layout\x18\x02 \x01(\t\"j\n\x13UpdateStreamRequest\x12\x1e\n\tegress_id\x18\x01 \x01(\tB\x0b\xbaP\x08\x65gressID\x12\x17\n\x0f\x61\x64\x64_output_urls\x18\x02 \x03(\t\x12\x1a\n\x12remove_output_urls\x18\x03 \x03(\t\"3\n\x0eStreamInfoList\x12!\n\x04info\x18\x01 \x03(\x0b\x32\x13.livekit.StreamInfo*W\n\x0c\x41udioChannel\x12\x16\n\x12\x41UDIO_CHANNEL_BOTH\x10\x00\x12\x16\n\x12\x41UDIO_CHANNEL_LEFT\x10\x01\x12\x17\n\x13\x41UDIO_CHANNEL_RIGHT\x10\x02*\xcf\x01\n\x15\x45ncodingOptionsPreset\x12\x10\n\x0cH264_720P_30\x10\x00\x12\x10\n\x0cH264_720P_60\x10\x01\x12\x11\n\rH264_1080P_30\x10\x02\x12\x11\n\rH264_1080P_60\x10\x03\x12\x19\n\x15PORTRAIT_H264_720P_30\x10\x04\x12\x19\n\x15PORTRAIT_H264_720P_60\x10\x05\x12\x1a\n\x16PORTRAIT_H264_1080P_30\x10\x06\x12\x1a\n\x16PORTRAIT_H264_1080P_60\x10\x07*B\n\x0f\x45ncodedFileType\x12\x14\n\x10\x44\x45\x46\x41ULT_FILETYPE\x10\x00\x12\x07\n\x03MP4\x10\x01\x12\x07\n\x03OGG\x10\x02\x12\x07\n\x03MP3\x10\x03*H\n\x0eStreamProtocol\x12\x14\n\x10\x44\x45\x46\x41ULT_PROTOCOL\x10\x00\x12\x08\n\x04RTMP\x10\x01\x12\x07\n\x03SRT\x10\x02\x12\r\n\tWEBSOCKET\x10\x03*N\n\x15SegmentedFileProtocol\x12#\n\x1f\x44\x45\x46\x41ULT_SEGMENTED_FILE_PROTOCOL\x10\x00\x12\x10\n\x0cHLS_PROTOCOL\x10\x01*/\n\x13SegmentedFileSuffix\x12\t\n\x05INDEX\x10\x00\x12\r\n\tTIMESTAMP\x10\x01*f\n\x0fImageFileSuffix\x12\x16\n\x12IMAGE_SUFFIX_INDEX\x10\x00\x12\x1a\n\x16IMAGE_SUFFIX_TIMESTAMP\x10\x01\x12\x1f\n\x1bIMAGE_SUFFIX_NONE_OVERWRITE\x10\x02*J\n\x10\x45gressSourceType\x12\x1a\n\x16\x45GRESS_SOURCE_TYPE_WEB\x10\x00\x12\x1a\n\x16\x45GRESS_SOURCE_TYPE_SDK\x10\x01*\x9f\x01\n\x0c\x45gressStatus\x12\x13\n\x0f\x45GRESS_STARTING\x10\x00\x12\x11\n\rEGRESS_ACTIVE\x10\x01\x12\x11\n\rEGRESS_ENDING\x10\x02\x12\x13\n\x0f\x45GRESS_COMPLETE\x10\x03\x12\x11\n\rEGRESS_FAILED\x10\x04\x12\x12\n\x0e\x45GRESS_ABORTED\x10\x05\x12\x18\n\x14\x45GRESS_LIMIT_REACHED\x10\x06*U\n\x0b\x41udioMixing\x12\x12\n\x0e\x44\x45\x46\x41ULT_MIXING\x10\x00\x12\x16\n\x12\x44UAL_CHANNEL_AGENT\x10\x01\x12\x1a\n\x16\x44UAL_CHANNEL_ALTERNATE\x10\x02\x32\x9c\x05\n\x06\x45gress\x12T\n\x18StartRoomCompositeEgress\x12#.livekit.RoomCompositeEgressRequest\x1a\x13.livekit.EgressInfo\x12@\n\x0eStartWebEgress\x12\x19.livekit.WebEgressRequest\x1a\x13.livekit.EgressInfo\x12P\n\x16StartParticipantEgress\x12!.livekit.ParticipantEgressRequest\x1a\x13.livekit.EgressInfo\x12V\n\x19StartTrackCompositeEgress\x12$.livekit.TrackCompositeEgressRequest\x1a\x13.livekit.EgressInfo\x12\x44\n\x10StartTrackEgress\x12\x1b.livekit.TrackEgressRequest\x1a\x13.livekit.EgressInfo\x12\x41\n\x0cUpdateLayout\x12\x1c.livekit.UpdateLayoutRequest\x1a\x13.livekit.EgressInfo\x12\x41\n\x0cUpdateStream\x12\x1c.livekit.UpdateStreamRequest\x1a\x13.livekit.EgressInfo\x12\x45\n\nListEgress\x12\x1a.livekit.ListEgressRequest\x1a\x1b.livekit.ListEgressResponse\x12=\n\nStopEgress\x12\x1a.livekit.StopEgressRequest\x1a\x13.livekit.EgressInfoBFZ#github.com/livekit/protocol/livekit\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -23,6 +24,58 @@
if _descriptor._USE_C_DESCRIPTORS == False:
_globals['DESCRIPTOR']._options = None
_globals['DESCRIPTOR']._serialized_options = b'Z#github.com/livekit/protocol/livekit\252\002\rLiveKit.Proto\352\002\016LiveKit::Proto'
+ _globals['_MEDIASOURCE'].fields_by_name['video_track_id']._options = None
+ _globals['_MEDIASOURCE'].fields_by_name['video_track_id']._serialized_options = b'\272P\014videoTrackID'
+ _globals['_AUDIOROUTE'].fields_by_name['track_id']._options = None
+ _globals['_AUDIOROUTE'].fields_by_name['track_id']._serialized_options = b'\272P\007trackID'
+ _globals['_DATASELECTOR'].fields_by_name['track_id']._options = None
+ _globals['_DATASELECTOR'].fields_by_name['track_id']._serialized_options = b'\272P\007trackID'
+ _globals['_ENCODINGOPTIONS'].fields_by_name['audio_quality']._options = None
+ _globals['_ENCODINGOPTIONS'].fields_by_name['audio_quality']._serialized_options = b'\030\001'
+ _globals['_ENCODINGOPTIONS'].fields_by_name['video_quality']._options = None
+ _globals['_ENCODINGOPTIONS'].fields_by_name['video_quality']._serialized_options = b'\030\001'
+ _globals['_S3UPLOAD_METADATAENTRY']._options = None
+ _globals['_S3UPLOAD_METADATAENTRY']._serialized_options = b'8\001'
+ _globals['_S3UPLOAD'].fields_by_name['access_key']._options = None
+ _globals['_S3UPLOAD'].fields_by_name['access_key']._serialized_options = b'\250P\001'
+ _globals['_S3UPLOAD'].fields_by_name['secret']._options = None
+ _globals['_S3UPLOAD'].fields_by_name['secret']._serialized_options = b'\250P\001'
+ _globals['_S3UPLOAD'].fields_by_name['session_token']._options = None
+ _globals['_S3UPLOAD'].fields_by_name['session_token']._serialized_options = b'\250P\001'
+ _globals['_S3UPLOAD'].fields_by_name['assume_role_arn']._options = None
+ _globals['_S3UPLOAD'].fields_by_name['assume_role_arn']._serialized_options = b'\250P\001'
+ _globals['_S3UPLOAD'].fields_by_name['assume_role_external_id']._options = None
+ _globals['_S3UPLOAD'].fields_by_name['assume_role_external_id']._serialized_options = b'\250P\001\272P\024assumeRoleExternalID'
+ _globals['_GCPUPLOAD'].fields_by_name['credentials']._options = None
+ _globals['_GCPUPLOAD'].fields_by_name['credentials']._serialized_options = b'\250P\001'
+ _globals['_AZUREBLOBUPLOAD'].fields_by_name['account_name']._options = None
+ _globals['_AZUREBLOBUPLOAD'].fields_by_name['account_name']._serialized_options = b'\250P\001'
+ _globals['_AZUREBLOBUPLOAD'].fields_by_name['account_key']._options = None
+ _globals['_AZUREBLOBUPLOAD'].fields_by_name['account_key']._serialized_options = b'\250P\001'
+ _globals['_ALIOSSUPLOAD'].fields_by_name['access_key']._options = None
+ _globals['_ALIOSSUPLOAD'].fields_by_name['access_key']._serialized_options = b'\250P\001'
+ _globals['_ALIOSSUPLOAD'].fields_by_name['secret']._options = None
+ _globals['_ALIOSSUPLOAD'].fields_by_name['secret']._serialized_options = b'\250P\001'
+ _globals['_PROXYCONFIG'].fields_by_name['password']._options = None
+ _globals['_PROXYCONFIG'].fields_by_name['password']._serialized_options = b'\250P\001'
+ _globals['_LISTEGRESSREQUEST'].fields_by_name['egress_id']._options = None
+ _globals['_LISTEGRESSREQUEST'].fields_by_name['egress_id']._serialized_options = b'\272P\010egressID'
+ _globals['_UPDATEEGRESSREQUEST'].fields_by_name['egress_id']._options = None
+ _globals['_UPDATEEGRESSREQUEST'].fields_by_name['egress_id']._serialized_options = b'\272P\010egressID'
+ _globals['_STOPEGRESSREQUEST'].fields_by_name['egress_id']._options = None
+ _globals['_STOPEGRESSREQUEST'].fields_by_name['egress_id']._serialized_options = b'\272P\010egressID'
+ _globals['_EGRESSINFO'].fields_by_name['egress_id']._options = None
+ _globals['_EGRESSINFO'].fields_by_name['egress_id']._serialized_options = b'\272P\010egressID'
+ _globals['_EGRESSINFO'].fields_by_name['room_id']._options = None
+ _globals['_EGRESSINFO'].fields_by_name['room_id']._serialized_options = b'\272P\006roomID'
+ _globals['_EGRESSINFO'].fields_by_name['stream']._options = None
+ _globals['_EGRESSINFO'].fields_by_name['stream']._serialized_options = b'\030\001'
+ _globals['_EGRESSINFO'].fields_by_name['file']._options = None
+ _globals['_EGRESSINFO'].fields_by_name['file']._serialized_options = b'\030\001'
+ _globals['_EGRESSINFO'].fields_by_name['segments']._options = None
+ _globals['_EGRESSINFO'].fields_by_name['segments']._serialized_options = b'\030\001'
+ _globals['_EXPORTREPLAYREQUEST'].fields_by_name['replay_id']._options = None
+ _globals['_EXPORTREPLAYREQUEST'].fields_by_name['replay_id']._serialized_options = b'\272P\010replayID'
_globals['_ROOMCOMPOSITEEGRESSREQUEST'].fields_by_name['file']._options = None
_globals['_ROOMCOMPOSITEEGRESSREQUEST'].fields_by_name['file']._serialized_options = b'\030\001'
_globals['_ROOMCOMPOSITEEGRESSREQUEST'].fields_by_name['stream']._options = None
@@ -35,98 +88,132 @@
_globals['_WEBEGRESSREQUEST'].fields_by_name['stream']._serialized_options = b'\030\001'
_globals['_WEBEGRESSREQUEST'].fields_by_name['segments']._options = None
_globals['_WEBEGRESSREQUEST'].fields_by_name['segments']._serialized_options = b'\030\001'
+ _globals['_TRACKCOMPOSITEEGRESSREQUEST'].fields_by_name['audio_track_id']._options = None
+ _globals['_TRACKCOMPOSITEEGRESSREQUEST'].fields_by_name['audio_track_id']._serialized_options = b'\272P\014audioTrackID'
+ _globals['_TRACKCOMPOSITEEGRESSREQUEST'].fields_by_name['video_track_id']._options = None
+ _globals['_TRACKCOMPOSITEEGRESSREQUEST'].fields_by_name['video_track_id']._serialized_options = b'\272P\014videoTrackID'
_globals['_TRACKCOMPOSITEEGRESSREQUEST'].fields_by_name['file']._options = None
_globals['_TRACKCOMPOSITEEGRESSREQUEST'].fields_by_name['file']._serialized_options = b'\030\001'
_globals['_TRACKCOMPOSITEEGRESSREQUEST'].fields_by_name['stream']._options = None
_globals['_TRACKCOMPOSITEEGRESSREQUEST'].fields_by_name['stream']._serialized_options = b'\030\001'
_globals['_TRACKCOMPOSITEEGRESSREQUEST'].fields_by_name['segments']._options = None
_globals['_TRACKCOMPOSITEEGRESSREQUEST'].fields_by_name['segments']._serialized_options = b'\030\001'
- _globals['_S3UPLOAD_METADATAENTRY']._options = None
- _globals['_S3UPLOAD_METADATAENTRY']._serialized_options = b'8\001'
- _globals['_EGRESSINFO'].fields_by_name['stream']._options = None
- _globals['_EGRESSINFO'].fields_by_name['stream']._serialized_options = b'\030\001'
- _globals['_EGRESSINFO'].fields_by_name['file']._options = None
- _globals['_EGRESSINFO'].fields_by_name['file']._serialized_options = b'\030\001'
- _globals['_EGRESSINFO'].fields_by_name['segments']._options = None
- _globals['_EGRESSINFO'].fields_by_name['segments']._serialized_options = b'\030\001'
- _globals['_STREAMINFOLIST']._options = None
- _globals['_STREAMINFOLIST']._serialized_options = b'\030\001'
- _globals['_ENCODEDFILETYPE']._serialized_start=6929
- _globals['_ENCODEDFILETYPE']._serialized_end=6986
- _globals['_SEGMENTEDFILEPROTOCOL']._serialized_start=6988
- _globals['_SEGMENTEDFILEPROTOCOL']._serialized_end=7066
- _globals['_SEGMENTEDFILESUFFIX']._serialized_start=7068
- _globals['_SEGMENTEDFILESUFFIX']._serialized_end=7115
- _globals['_IMAGEFILESUFFIX']._serialized_start=7117
- _globals['_IMAGEFILESUFFIX']._serialized_end=7186
- _globals['_STREAMPROTOCOL']._serialized_start=7188
- _globals['_STREAMPROTOCOL']._serialized_end=7236
- _globals['_ENCODINGOPTIONSPRESET']._serialized_start=7239
- _globals['_ENCODINGOPTIONSPRESET']._serialized_end=7446
- _globals['_EGRESSSTATUS']._serialized_start=7449
- _globals['_EGRESSSTATUS']._serialized_end=7608
- _globals['_ROOMCOMPOSITEEGRESSREQUEST']._serialized_start=56
- _globals['_ROOMCOMPOSITEEGRESSREQUEST']._serialized_end=645
- _globals['_WEBEGRESSREQUEST']._serialized_start=648
- _globals['_WEBEGRESSREQUEST']._serialized_end=1208
- _globals['_PARTICIPANTEGRESSREQUEST']._serialized_start=1211
- _globals['_PARTICIPANTEGRESSREQUEST']._serialized_end=1600
- _globals['_TRACKCOMPOSITEEGRESSREQUEST']._serialized_start=1603
- _globals['_TRACKCOMPOSITEEGRESSREQUEST']._serialized_end=2160
- _globals['_TRACKEGRESSREQUEST']._serialized_start=2163
- _globals['_TRACKEGRESSREQUEST']._serialized_end=2298
- _globals['_ENCODEDFILEOUTPUT']._serialized_start=2301
- _globals['_ENCODEDFILEOUTPUT']._serialized_end=2571
- _globals['_SEGMENTEDFILEOUTPUT']._serialized_start=2574
- _globals['_SEGMENTEDFILEOUTPUT']._serialized_end=2990
- _globals['_DIRECTFILEOUTPUT']._serialized_start=2993
- _globals['_DIRECTFILEOUTPUT']._serialized_end=3217
- _globals['_IMAGEOUTPUT']._serialized_start=3220
- _globals['_IMAGEOUTPUT']._serialized_end=3596
- _globals['_S3UPLOAD']._serialized_start=3599
- _globals['_S3UPLOAD']._serialized_end=3927
- _globals['_S3UPLOAD_METADATAENTRY']._serialized_start=3880
- _globals['_S3UPLOAD_METADATAENTRY']._serialized_end=3927
- _globals['_GCPUPLOAD']._serialized_start=3929
- _globals['_GCPUPLOAD']._serialized_end=4014
- _globals['_AZUREBLOBUPLOAD']._serialized_start=4016
- _globals['_AZUREBLOBUPLOAD']._serialized_end=4100
- _globals['_ALIOSSUPLOAD']._serialized_start=4102
- _globals['_ALIOSSUPLOAD']._serialized_end=4202
- _globals['_PROXYCONFIG']._serialized_start=4204
- _globals['_PROXYCONFIG']._serialized_end=4266
- _globals['_STREAMOUTPUT']._serialized_start=4268
- _globals['_STREAMOUTPUT']._serialized_end=4339
- _globals['_ENCODINGOPTIONS']._serialized_start=4342
- _globals['_ENCODINGOPTIONS']._serialized_end=4653
- _globals['_UPDATELAYOUTREQUEST']._serialized_start=4655
- _globals['_UPDATELAYOUTREQUEST']._serialized_end=4711
- _globals['_UPDATESTREAMREQUEST']._serialized_start=4713
- _globals['_UPDATESTREAMREQUEST']._serialized_end=4806
- _globals['_LISTEGRESSREQUEST']._serialized_start=4808
- _globals['_LISTEGRESSREQUEST']._serialized_end=4881
- _globals['_LISTEGRESSRESPONSE']._serialized_start=4883
- _globals['_LISTEGRESSRESPONSE']._serialized_end=4939
- _globals['_STOPEGRESSREQUEST']._serialized_start=4941
- _globals['_STOPEGRESSREQUEST']._serialized_end=4979
- _globals['_EGRESSINFO']._serialized_start=4982
- _globals['_EGRESSINFO']._serialized_end=5804
- _globals['_STREAMINFOLIST']._serialized_start=5806
- _globals['_STREAMINFOLIST']._serialized_end=5861
- _globals['_STREAMINFO']._serialized_start=5864
- _globals['_STREAMINFO']._serialized_end=6052
- _globals['_STREAMINFO_STATUS']._serialized_start=6006
- _globals['_STREAMINFO_STATUS']._serialized_end=6052
- _globals['_FILEINFO']._serialized_start=6054
- _globals['_FILEINFO']._serialized_end=6170
- _globals['_SEGMENTSINFO']._serialized_start=6173
- _globals['_SEGMENTSINFO']._serialized_end=6390
- _globals['_IMAGESINFO']._serialized_start=6392
- _globals['_IMAGESINFO']._serialized_end=6463
- _globals['_AUTOPARTICIPANTEGRESS']._serialized_start=6466
- _globals['_AUTOPARTICIPANTEGRESS']._serialized_end=6701
- _globals['_AUTOTRACKEGRESS']._serialized_start=6704
- _globals['_AUTOTRACKEGRESS']._serialized_end=6927
- _globals['_EGRESS']._serialized_start=7611
- _globals['_EGRESS']._serialized_end=8279
+ _globals['_TRACKEGRESSREQUEST'].fields_by_name['track_id']._options = None
+ _globals['_TRACKEGRESSREQUEST'].fields_by_name['track_id']._serialized_options = b'\272P\007trackID'
+ _globals['_UPDATELAYOUTREQUEST'].fields_by_name['egress_id']._options = None
+ _globals['_UPDATELAYOUTREQUEST'].fields_by_name['egress_id']._serialized_options = b'\272P\010egressID'
+ _globals['_UPDATESTREAMREQUEST'].fields_by_name['egress_id']._options = None
+ _globals['_UPDATESTREAMREQUEST'].fields_by_name['egress_id']._serialized_options = b'\272P\010egressID'
+ _globals['_AUDIOCHANNEL']._serialized_start=10069
+ _globals['_AUDIOCHANNEL']._serialized_end=10156
+ _globals['_ENCODINGOPTIONSPRESET']._serialized_start=10159
+ _globals['_ENCODINGOPTIONSPRESET']._serialized_end=10366
+ _globals['_ENCODEDFILETYPE']._serialized_start=10368
+ _globals['_ENCODEDFILETYPE']._serialized_end=10434
+ _globals['_STREAMPROTOCOL']._serialized_start=10436
+ _globals['_STREAMPROTOCOL']._serialized_end=10508
+ _globals['_SEGMENTEDFILEPROTOCOL']._serialized_start=10510
+ _globals['_SEGMENTEDFILEPROTOCOL']._serialized_end=10588
+ _globals['_SEGMENTEDFILESUFFIX']._serialized_start=10590
+ _globals['_SEGMENTEDFILESUFFIX']._serialized_end=10637
+ _globals['_IMAGEFILESUFFIX']._serialized_start=10639
+ _globals['_IMAGEFILESUFFIX']._serialized_end=10741
+ _globals['_EGRESSSOURCETYPE']._serialized_start=10743
+ _globals['_EGRESSSOURCETYPE']._serialized_end=10817
+ _globals['_EGRESSSTATUS']._serialized_start=10820
+ _globals['_EGRESSSTATUS']._serialized_end=10979
+ _globals['_AUDIOMIXING']._serialized_start=10981
+ _globals['_AUDIOMIXING']._serialized_end=11066
+ _globals['_STARTEGRESSREQUEST']._serialized_start=78
+ _globals['_STARTEGRESSREQUEST']._serialized_end=471
+ _globals['_TEMPLATESOURCE']._serialized_start=473
+ _globals['_TEMPLATESOURCE']._serialized_end=570
+ _globals['_WEBSOURCE']._serialized_start=572
+ _globals['_WEBSOURCE']._serialized_end=664
+ _globals['_MEDIASOURCE']._serialized_start=667
+ _globals['_MEDIASOURCE']._serialized_end=860
+ _globals['_PARTICIPANTVIDEO']._serialized_start=862
+ _globals['_PARTICIPANTVIDEO']._serialized_end=927
+ _globals['_AUDIOCONFIG']._serialized_start=929
+ _globals['_AUDIOCONFIG']._serialized_end=979
+ _globals['_AUDIOROUTE']._serialized_start=982
+ _globals['_AUDIOROUTE']._serialized_end=1166
+ _globals['_DATACONFIG']._serialized_start=1168
+ _globals['_DATACONFIG']._serialized_end=1222
+ _globals['_DATASELECTOR']._serialized_start=1224
+ _globals['_DATASELECTOR']._serialized_end=1328
+ _globals['_ENCODINGOPTIONS']._serialized_start=1331
+ _globals['_ENCODINGOPTIONS']._serialized_end=1650
+ _globals['_OUTPUT']._serialized_start=1653
+ _globals['_OUTPUT']._serialized_end=1880
+ _globals['_FILEOUTPUT']._serialized_start=1882
+ _globals['_FILEOUTPUT']._serialized_end=1983
+ _globals['_STREAMOUTPUT']._serialized_start=1985
+ _globals['_STREAMOUTPUT']._serialized_end=2056
+ _globals['_SEGMENTEDFILEOUTPUT']._serialized_start=2059
+ _globals['_SEGMENTEDFILEOUTPUT']._serialized_end=2475
+ _globals['_IMAGEOUTPUT']._serialized_start=2478
+ _globals['_IMAGEOUTPUT']._serialized_end=2854
+ _globals['_STORAGECONFIG']._serialized_start=2857
+ _globals['_STORAGECONFIG']._serialized_end=3036
+ _globals['_S3UPLOAD']._serialized_start=3039
+ _globals['_S3UPLOAD']._serialized_end=3473
+ _globals['_S3UPLOAD_METADATAENTRY']._serialized_start=3426
+ _globals['_S3UPLOAD_METADATAENTRY']._serialized_end=3473
+ _globals['_GCPUPLOAD']._serialized_start=3475
+ _globals['_GCPUPLOAD']._serialized_end=3565
+ _globals['_AZUREBLOBUPLOAD']._serialized_start=3567
+ _globals['_AZUREBLOBUPLOAD']._serialized_end=3661
+ _globals['_ALIOSSUPLOAD']._serialized_start=3663
+ _globals['_ALIOSSUPLOAD']._serialized_end=3773
+ _globals['_PROXYCONFIG']._serialized_start=3775
+ _globals['_PROXYCONFIG']._serialized_end=3842
+ _globals['_LISTEGRESSREQUEST']._serialized_start=3844
+ _globals['_LISTEGRESSREQUEST']._serialized_end=3930
+ _globals['_LISTEGRESSRESPONSE']._serialized_start=3932
+ _globals['_LISTEGRESSRESPONSE']._serialized_end=3988
+ _globals['_UPDATEEGRESSREQUEST']._serialized_start=3991
+ _globals['_UPDATEEGRESSREQUEST']._serialized_end=4126
+ _globals['_STOPEGRESSREQUEST']._serialized_start=4128
+ _globals['_STOPEGRESSREQUEST']._serialized_end=4179
+ _globals['_EGRESSINFO']._serialized_start=4182
+ _globals['_EGRESSINFO']._serialized_end=5201
+ _globals['_STREAMINFO']._serialized_start=5204
+ _globals['_STREAMINFO']._serialized_end=5432
+ _globals['_STREAMINFO_STATUS']._serialized_start=5386
+ _globals['_STREAMINFO_STATUS']._serialized_end=5432
+ _globals['_FILEINFO']._serialized_start=5434
+ _globals['_FILEINFO']._serialized_end=5550
+ _globals['_SEGMENTSINFO']._serialized_start=5553
+ _globals['_SEGMENTSINFO']._serialized_end=5770
+ _globals['_IMAGESINFO']._serialized_start=5772
+ _globals['_IMAGESINFO']._serialized_end=5868
+ _globals['_AUTOPARTICIPANTEGRESS']._serialized_start=5871
+ _globals['_AUTOPARTICIPANTEGRESS']._serialized_end=6106
+ _globals['_AUTOTRACKEGRESS']._serialized_start=6109
+ _globals['_AUTOTRACKEGRESS']._serialized_end=6332
+ _globals['_EXPORTREPLAYREQUEST']._serialized_start=6335
+ _globals['_EXPORTREPLAYREQUEST']._serialized_end=6790
+ _globals['_ROOMCOMPOSITEEGRESSREQUEST']._serialized_start=6793
+ _globals['_ROOMCOMPOSITEEGRESSREQUEST']._serialized_end=7468
+ _globals['_WEBEGRESSREQUEST']._serialized_start=7471
+ _globals['_WEBEGRESSREQUEST']._serialized_end=8073
+ _globals['_PARTICIPANTEGRESSREQUEST']._serialized_start=8076
+ _globals['_PARTICIPANTEGRESSREQUEST']._serialized_end=8507
+ _globals['_TRACKCOMPOSITEEGRESSREQUEST']._serialized_start=8510
+ _globals['_TRACKCOMPOSITEEGRESSREQUEST']._serialized_end=9143
+ _globals['_TRACKEGRESSREQUEST']._serialized_start=9146
+ _globals['_TRACKEGRESSREQUEST']._serialized_end=9335
+ _globals['_DIRECTFILEOUTPUT']._serialized_start=9338
+ _globals['_DIRECTFILEOUTPUT']._serialized_end=9562
+ _globals['_ENCODEDFILEOUTPUT']._serialized_start=9565
+ _globals['_ENCODEDFILEOUTPUT']._serialized_end=9835
+ _globals['_UPDATELAYOUTREQUEST']._serialized_start=9837
+ _globals['_UPDATELAYOUTREQUEST']._serialized_end=9906
+ _globals['_UPDATESTREAMREQUEST']._serialized_start=9908
+ _globals['_UPDATESTREAMREQUEST']._serialized_end=10014
+ _globals['_STREAMINFOLIST']._serialized_start=10016
+ _globals['_STREAMINFOLIST']._serialized_end=10067
+ _globals['_EGRESS']._serialized_start=11069
+ _globals['_EGRESS']._serialized_end=11737
# @@protoc_insertion_point(module_scope)
diff --git a/livekit-protocol/livekit/protocol/egress.pyi b/livekit-protocol/livekit/protocol/egress.pyi
index 50d0ed2f..0806e21a 100644
--- a/livekit-protocol/livekit/protocol/egress.pyi
+++ b/livekit-protocol/livekit/protocol/egress.pyi
@@ -1,4 +1,5 @@
from . import models as _models
+from .logger_pb import options as _options_pb2
from google.protobuf.internal import containers as _containers
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
from google.protobuf import descriptor as _descriptor
@@ -7,11 +8,36 @@ from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Map
DESCRIPTOR: _descriptor.FileDescriptor
+class AudioChannel(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ AUDIO_CHANNEL_BOTH: _ClassVar[AudioChannel]
+ AUDIO_CHANNEL_LEFT: _ClassVar[AudioChannel]
+ AUDIO_CHANNEL_RIGHT: _ClassVar[AudioChannel]
+
+class EncodingOptionsPreset(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ H264_720P_30: _ClassVar[EncodingOptionsPreset]
+ H264_720P_60: _ClassVar[EncodingOptionsPreset]
+ H264_1080P_30: _ClassVar[EncodingOptionsPreset]
+ H264_1080P_60: _ClassVar[EncodingOptionsPreset]
+ PORTRAIT_H264_720P_30: _ClassVar[EncodingOptionsPreset]
+ PORTRAIT_H264_720P_60: _ClassVar[EncodingOptionsPreset]
+ PORTRAIT_H264_1080P_30: _ClassVar[EncodingOptionsPreset]
+ PORTRAIT_H264_1080P_60: _ClassVar[EncodingOptionsPreset]
+
class EncodedFileType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
DEFAULT_FILETYPE: _ClassVar[EncodedFileType]
MP4: _ClassVar[EncodedFileType]
OGG: _ClassVar[EncodedFileType]
+ MP3: _ClassVar[EncodedFileType]
+
+class StreamProtocol(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ DEFAULT_PROTOCOL: _ClassVar[StreamProtocol]
+ RTMP: _ClassVar[StreamProtocol]
+ SRT: _ClassVar[StreamProtocol]
+ WEBSOCKET: _ClassVar[StreamProtocol]
class SegmentedFileProtocol(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
@@ -27,22 +53,12 @@ class ImageFileSuffix(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
IMAGE_SUFFIX_INDEX: _ClassVar[ImageFileSuffix]
IMAGE_SUFFIX_TIMESTAMP: _ClassVar[ImageFileSuffix]
+ IMAGE_SUFFIX_NONE_OVERWRITE: _ClassVar[ImageFileSuffix]
-class StreamProtocol(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
- __slots__ = ()
- DEFAULT_PROTOCOL: _ClassVar[StreamProtocol]
- RTMP: _ClassVar[StreamProtocol]
-
-class EncodingOptionsPreset(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+class EgressSourceType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
- H264_720P_30: _ClassVar[EncodingOptionsPreset]
- H264_720P_60: _ClassVar[EncodingOptionsPreset]
- H264_1080P_30: _ClassVar[EncodingOptionsPreset]
- H264_1080P_60: _ClassVar[EncodingOptionsPreset]
- PORTRAIT_H264_720P_30: _ClassVar[EncodingOptionsPreset]
- PORTRAIT_H264_720P_60: _ClassVar[EncodingOptionsPreset]
- PORTRAIT_H264_1080P_30: _ClassVar[EncodingOptionsPreset]
- PORTRAIT_H264_1080P_60: _ClassVar[EncodingOptionsPreset]
+ EGRESS_SOURCE_TYPE_WEB: _ClassVar[EgressSourceType]
+ EGRESS_SOURCE_TYPE_SDK: _ClassVar[EgressSourceType]
class EgressStatus(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
@@ -53,25 +69,40 @@ class EgressStatus(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
EGRESS_FAILED: _ClassVar[EgressStatus]
EGRESS_ABORTED: _ClassVar[EgressStatus]
EGRESS_LIMIT_REACHED: _ClassVar[EgressStatus]
+
+class AudioMixing(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ DEFAULT_MIXING: _ClassVar[AudioMixing]
+ DUAL_CHANNEL_AGENT: _ClassVar[AudioMixing]
+ DUAL_CHANNEL_ALTERNATE: _ClassVar[AudioMixing]
+AUDIO_CHANNEL_BOTH: AudioChannel
+AUDIO_CHANNEL_LEFT: AudioChannel
+AUDIO_CHANNEL_RIGHT: AudioChannel
+H264_720P_30: EncodingOptionsPreset
+H264_720P_60: EncodingOptionsPreset
+H264_1080P_30: EncodingOptionsPreset
+H264_1080P_60: EncodingOptionsPreset
+PORTRAIT_H264_720P_30: EncodingOptionsPreset
+PORTRAIT_H264_720P_60: EncodingOptionsPreset
+PORTRAIT_H264_1080P_30: EncodingOptionsPreset
+PORTRAIT_H264_1080P_60: EncodingOptionsPreset
DEFAULT_FILETYPE: EncodedFileType
MP4: EncodedFileType
OGG: EncodedFileType
+MP3: EncodedFileType
+DEFAULT_PROTOCOL: StreamProtocol
+RTMP: StreamProtocol
+SRT: StreamProtocol
+WEBSOCKET: StreamProtocol
DEFAULT_SEGMENTED_FILE_PROTOCOL: SegmentedFileProtocol
HLS_PROTOCOL: SegmentedFileProtocol
INDEX: SegmentedFileSuffix
TIMESTAMP: SegmentedFileSuffix
IMAGE_SUFFIX_INDEX: ImageFileSuffix
IMAGE_SUFFIX_TIMESTAMP: ImageFileSuffix
-DEFAULT_PROTOCOL: StreamProtocol
-RTMP: StreamProtocol
-H264_720P_30: EncodingOptionsPreset
-H264_720P_60: EncodingOptionsPreset
-H264_1080P_30: EncodingOptionsPreset
-H264_1080P_60: EncodingOptionsPreset
-PORTRAIT_H264_720P_30: EncodingOptionsPreset
-PORTRAIT_H264_720P_60: EncodingOptionsPreset
-PORTRAIT_H264_1080P_30: EncodingOptionsPreset
-PORTRAIT_H264_1080P_60: EncodingOptionsPreset
+IMAGE_SUFFIX_NONE_OVERWRITE: ImageFileSuffix
+EGRESS_SOURCE_TYPE_WEB: EgressSourceType
+EGRESS_SOURCE_TYPE_SDK: EgressSourceType
EGRESS_STARTING: EgressStatus
EGRESS_ACTIVE: EgressStatus
EGRESS_ENDING: EgressStatus
@@ -79,148 +110,169 @@ EGRESS_COMPLETE: EgressStatus
EGRESS_FAILED: EgressStatus
EGRESS_ABORTED: EgressStatus
EGRESS_LIMIT_REACHED: EgressStatus
+DEFAULT_MIXING: AudioMixing
+DUAL_CHANNEL_AGENT: AudioMixing
+DUAL_CHANNEL_ALTERNATE: AudioMixing
-class RoomCompositeEgressRequest(_message.Message):
- __slots__ = ("room_name", "layout", "audio_only", "video_only", "custom_base_url", "file", "stream", "segments", "preset", "advanced", "file_outputs", "stream_outputs", "segment_outputs", "image_outputs")
+class StartEgressRequest(_message.Message):
+ __slots__ = ("room_name", "template", "web", "media", "preset", "advanced", "outputs", "storage", "webhooks")
ROOM_NAME_FIELD_NUMBER: _ClassVar[int]
+ TEMPLATE_FIELD_NUMBER: _ClassVar[int]
+ WEB_FIELD_NUMBER: _ClassVar[int]
+ MEDIA_FIELD_NUMBER: _ClassVar[int]
+ PRESET_FIELD_NUMBER: _ClassVar[int]
+ ADVANCED_FIELD_NUMBER: _ClassVar[int]
+ OUTPUTS_FIELD_NUMBER: _ClassVar[int]
+ STORAGE_FIELD_NUMBER: _ClassVar[int]
+ WEBHOOKS_FIELD_NUMBER: _ClassVar[int]
+ room_name: str
+ template: TemplateSource
+ web: WebSource
+ media: MediaSource
+ preset: EncodingOptionsPreset
+ advanced: EncodingOptions
+ outputs: _containers.RepeatedCompositeFieldContainer[Output]
+ storage: StorageConfig
+ webhooks: _containers.RepeatedCompositeFieldContainer[_models.WebhookConfig]
+ def __init__(self, room_name: _Optional[str] = ..., template: _Optional[_Union[TemplateSource, _Mapping]] = ..., web: _Optional[_Union[WebSource, _Mapping]] = ..., media: _Optional[_Union[MediaSource, _Mapping]] = ..., preset: _Optional[_Union[EncodingOptionsPreset, str]] = ..., advanced: _Optional[_Union[EncodingOptions, _Mapping]] = ..., outputs: _Optional[_Iterable[_Union[Output, _Mapping]]] = ..., storage: _Optional[_Union[StorageConfig, _Mapping]] = ..., webhooks: _Optional[_Iterable[_Union[_models.WebhookConfig, _Mapping]]] = ...) -> None: ...
+
+class TemplateSource(_message.Message):
+ __slots__ = ("layout", "audio_only", "video_only", "custom_base_url")
LAYOUT_FIELD_NUMBER: _ClassVar[int]
AUDIO_ONLY_FIELD_NUMBER: _ClassVar[int]
VIDEO_ONLY_FIELD_NUMBER: _ClassVar[int]
CUSTOM_BASE_URL_FIELD_NUMBER: _ClassVar[int]
- FILE_FIELD_NUMBER: _ClassVar[int]
- STREAM_FIELD_NUMBER: _ClassVar[int]
- SEGMENTS_FIELD_NUMBER: _ClassVar[int]
- PRESET_FIELD_NUMBER: _ClassVar[int]
- ADVANCED_FIELD_NUMBER: _ClassVar[int]
- FILE_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
- STREAM_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
- SEGMENT_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
- IMAGE_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
- room_name: str
layout: str
audio_only: bool
video_only: bool
custom_base_url: str
- file: EncodedFileOutput
- stream: StreamOutput
- segments: SegmentedFileOutput
- preset: EncodingOptionsPreset
- advanced: EncodingOptions
- file_outputs: _containers.RepeatedCompositeFieldContainer[EncodedFileOutput]
- stream_outputs: _containers.RepeatedCompositeFieldContainer[StreamOutput]
- segment_outputs: _containers.RepeatedCompositeFieldContainer[SegmentedFileOutput]
- image_outputs: _containers.RepeatedCompositeFieldContainer[ImageOutput]
- def __init__(self, room_name: _Optional[str] = ..., layout: _Optional[str] = ..., audio_only: bool = ..., video_only: bool = ..., custom_base_url: _Optional[str] = ..., file: _Optional[_Union[EncodedFileOutput, _Mapping]] = ..., stream: _Optional[_Union[StreamOutput, _Mapping]] = ..., segments: _Optional[_Union[SegmentedFileOutput, _Mapping]] = ..., preset: _Optional[_Union[EncodingOptionsPreset, str]] = ..., advanced: _Optional[_Union[EncodingOptions, _Mapping]] = ..., file_outputs: _Optional[_Iterable[_Union[EncodedFileOutput, _Mapping]]] = ..., stream_outputs: _Optional[_Iterable[_Union[StreamOutput, _Mapping]]] = ..., segment_outputs: _Optional[_Iterable[_Union[SegmentedFileOutput, _Mapping]]] = ..., image_outputs: _Optional[_Iterable[_Union[ImageOutput, _Mapping]]] = ...) -> None: ...
+ def __init__(self, layout: _Optional[str] = ..., audio_only: bool = ..., video_only: bool = ..., custom_base_url: _Optional[str] = ...) -> None: ...
-class WebEgressRequest(_message.Message):
- __slots__ = ("url", "audio_only", "video_only", "await_start_signal", "file", "stream", "segments", "preset", "advanced", "file_outputs", "stream_outputs", "segment_outputs", "image_outputs")
+class WebSource(_message.Message):
+ __slots__ = ("url", "audio_only", "video_only", "await_start_signal")
URL_FIELD_NUMBER: _ClassVar[int]
AUDIO_ONLY_FIELD_NUMBER: _ClassVar[int]
VIDEO_ONLY_FIELD_NUMBER: _ClassVar[int]
AWAIT_START_SIGNAL_FIELD_NUMBER: _ClassVar[int]
- FILE_FIELD_NUMBER: _ClassVar[int]
- STREAM_FIELD_NUMBER: _ClassVar[int]
- SEGMENTS_FIELD_NUMBER: _ClassVar[int]
- PRESET_FIELD_NUMBER: _ClassVar[int]
- ADVANCED_FIELD_NUMBER: _ClassVar[int]
- FILE_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
- STREAM_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
- SEGMENT_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
- IMAGE_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
url: str
audio_only: bool
video_only: bool
await_start_signal: bool
- file: EncodedFileOutput
- stream: StreamOutput
- segments: SegmentedFileOutput
- preset: EncodingOptionsPreset
- advanced: EncodingOptions
- file_outputs: _containers.RepeatedCompositeFieldContainer[EncodedFileOutput]
- stream_outputs: _containers.RepeatedCompositeFieldContainer[StreamOutput]
- segment_outputs: _containers.RepeatedCompositeFieldContainer[SegmentedFileOutput]
- image_outputs: _containers.RepeatedCompositeFieldContainer[ImageOutput]
- def __init__(self, url: _Optional[str] = ..., audio_only: bool = ..., video_only: bool = ..., await_start_signal: bool = ..., file: _Optional[_Union[EncodedFileOutput, _Mapping]] = ..., stream: _Optional[_Union[StreamOutput, _Mapping]] = ..., segments: _Optional[_Union[SegmentedFileOutput, _Mapping]] = ..., preset: _Optional[_Union[EncodingOptionsPreset, str]] = ..., advanced: _Optional[_Union[EncodingOptions, _Mapping]] = ..., file_outputs: _Optional[_Iterable[_Union[EncodedFileOutput, _Mapping]]] = ..., stream_outputs: _Optional[_Iterable[_Union[StreamOutput, _Mapping]]] = ..., segment_outputs: _Optional[_Iterable[_Union[SegmentedFileOutput, _Mapping]]] = ..., image_outputs: _Optional[_Iterable[_Union[ImageOutput, _Mapping]]] = ...) -> None: ...
+ def __init__(self, url: _Optional[str] = ..., audio_only: bool = ..., video_only: bool = ..., await_start_signal: bool = ...) -> None: ...
-class ParticipantEgressRequest(_message.Message):
- __slots__ = ("room_name", "identity", "screen_share", "preset", "advanced", "file_outputs", "stream_outputs", "segment_outputs", "image_outputs")
- ROOM_NAME_FIELD_NUMBER: _ClassVar[int]
+class MediaSource(_message.Message):
+ __slots__ = ("video_track_id", "participant_video", "audio", "data")
+ VIDEO_TRACK_ID_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_VIDEO_FIELD_NUMBER: _ClassVar[int]
+ AUDIO_FIELD_NUMBER: _ClassVar[int]
+ DATA_FIELD_NUMBER: _ClassVar[int]
+ video_track_id: str
+ participant_video: ParticipantVideo
+ audio: AudioConfig
+ data: DataConfig
+ def __init__(self, video_track_id: _Optional[str] = ..., participant_video: _Optional[_Union[ParticipantVideo, _Mapping]] = ..., audio: _Optional[_Union[AudioConfig, _Mapping]] = ..., data: _Optional[_Union[DataConfig, _Mapping]] = ...) -> None: ...
+
+class ParticipantVideo(_message.Message):
+ __slots__ = ("identity", "prefer_screen_share")
IDENTITY_FIELD_NUMBER: _ClassVar[int]
- SCREEN_SHARE_FIELD_NUMBER: _ClassVar[int]
- PRESET_FIELD_NUMBER: _ClassVar[int]
- ADVANCED_FIELD_NUMBER: _ClassVar[int]
- FILE_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
- STREAM_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
- SEGMENT_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
- IMAGE_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
- room_name: str
+ PREFER_SCREEN_SHARE_FIELD_NUMBER: _ClassVar[int]
identity: str
- screen_share: bool
- preset: EncodingOptionsPreset
- advanced: EncodingOptions
- file_outputs: _containers.RepeatedCompositeFieldContainer[EncodedFileOutput]
- stream_outputs: _containers.RepeatedCompositeFieldContainer[StreamOutput]
- segment_outputs: _containers.RepeatedCompositeFieldContainer[SegmentedFileOutput]
- image_outputs: _containers.RepeatedCompositeFieldContainer[ImageOutput]
- def __init__(self, room_name: _Optional[str] = ..., identity: _Optional[str] = ..., screen_share: bool = ..., preset: _Optional[_Union[EncodingOptionsPreset, str]] = ..., advanced: _Optional[_Union[EncodingOptions, _Mapping]] = ..., file_outputs: _Optional[_Iterable[_Union[EncodedFileOutput, _Mapping]]] = ..., stream_outputs: _Optional[_Iterable[_Union[StreamOutput, _Mapping]]] = ..., segment_outputs: _Optional[_Iterable[_Union[SegmentedFileOutput, _Mapping]]] = ..., image_outputs: _Optional[_Iterable[_Union[ImageOutput, _Mapping]]] = ...) -> None: ...
+ prefer_screen_share: bool
+ def __init__(self, identity: _Optional[str] = ..., prefer_screen_share: bool = ...) -> None: ...
-class TrackCompositeEgressRequest(_message.Message):
- __slots__ = ("room_name", "audio_track_id", "video_track_id", "file", "stream", "segments", "preset", "advanced", "file_outputs", "stream_outputs", "segment_outputs", "image_outputs")
- ROOM_NAME_FIELD_NUMBER: _ClassVar[int]
- AUDIO_TRACK_ID_FIELD_NUMBER: _ClassVar[int]
- VIDEO_TRACK_ID_FIELD_NUMBER: _ClassVar[int]
+class AudioConfig(_message.Message):
+ __slots__ = ("routes",)
+ ROUTES_FIELD_NUMBER: _ClassVar[int]
+ routes: _containers.RepeatedCompositeFieldContainer[AudioRoute]
+ def __init__(self, routes: _Optional[_Iterable[_Union[AudioRoute, _Mapping]]] = ...) -> None: ...
+
+class AudioRoute(_message.Message):
+ __slots__ = ("track_id", "participant_identity", "participant_kind", "channel")
+ TRACK_ID_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_KIND_FIELD_NUMBER: _ClassVar[int]
+ CHANNEL_FIELD_NUMBER: _ClassVar[int]
+ track_id: str
+ participant_identity: str
+ participant_kind: _models.ParticipantInfo.Kind
+ channel: AudioChannel
+ def __init__(self, track_id: _Optional[str] = ..., participant_identity: _Optional[str] = ..., participant_kind: _Optional[_Union[_models.ParticipantInfo.Kind, str]] = ..., channel: _Optional[_Union[AudioChannel, str]] = ...) -> None: ...
+
+class DataConfig(_message.Message):
+ __slots__ = ("selectors",)
+ SELECTORS_FIELD_NUMBER: _ClassVar[int]
+ selectors: _containers.RepeatedCompositeFieldContainer[DataSelector]
+ def __init__(self, selectors: _Optional[_Iterable[_Union[DataSelector, _Mapping]]] = ...) -> None: ...
+
+class DataSelector(_message.Message):
+ __slots__ = ("track_id", "participant_identity", "topic")
+ TRACK_ID_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: _ClassVar[int]
+ TOPIC_FIELD_NUMBER: _ClassVar[int]
+ track_id: str
+ participant_identity: str
+ topic: str
+ def __init__(self, track_id: _Optional[str] = ..., participant_identity: _Optional[str] = ..., topic: _Optional[str] = ...) -> None: ...
+
+class EncodingOptions(_message.Message):
+ __slots__ = ("width", "height", "depth", "framerate", "audio_codec", "audio_bitrate", "audio_frequency", "video_codec", "video_bitrate", "key_frame_interval", "audio_quality", "video_quality")
+ WIDTH_FIELD_NUMBER: _ClassVar[int]
+ HEIGHT_FIELD_NUMBER: _ClassVar[int]
+ DEPTH_FIELD_NUMBER: _ClassVar[int]
+ FRAMERATE_FIELD_NUMBER: _ClassVar[int]
+ AUDIO_CODEC_FIELD_NUMBER: _ClassVar[int]
+ AUDIO_BITRATE_FIELD_NUMBER: _ClassVar[int]
+ AUDIO_FREQUENCY_FIELD_NUMBER: _ClassVar[int]
+ VIDEO_CODEC_FIELD_NUMBER: _ClassVar[int]
+ VIDEO_BITRATE_FIELD_NUMBER: _ClassVar[int]
+ KEY_FRAME_INTERVAL_FIELD_NUMBER: _ClassVar[int]
+ AUDIO_QUALITY_FIELD_NUMBER: _ClassVar[int]
+ VIDEO_QUALITY_FIELD_NUMBER: _ClassVar[int]
+ width: int
+ height: int
+ depth: int
+ framerate: int
+ audio_codec: _models.AudioCodec
+ audio_bitrate: int
+ audio_frequency: int
+ video_codec: _models.VideoCodec
+ video_bitrate: int
+ key_frame_interval: float
+ audio_quality: int
+ video_quality: int
+ def __init__(self, width: _Optional[int] = ..., height: _Optional[int] = ..., depth: _Optional[int] = ..., framerate: _Optional[int] = ..., audio_codec: _Optional[_Union[_models.AudioCodec, str]] = ..., audio_bitrate: _Optional[int] = ..., audio_frequency: _Optional[int] = ..., video_codec: _Optional[_Union[_models.VideoCodec, str]] = ..., video_bitrate: _Optional[int] = ..., key_frame_interval: _Optional[float] = ..., audio_quality: _Optional[int] = ..., video_quality: _Optional[int] = ...) -> None: ...
+
+class Output(_message.Message):
+ __slots__ = ("file", "stream", "segments", "images", "storage")
FILE_FIELD_NUMBER: _ClassVar[int]
STREAM_FIELD_NUMBER: _ClassVar[int]
SEGMENTS_FIELD_NUMBER: _ClassVar[int]
- PRESET_FIELD_NUMBER: _ClassVar[int]
- ADVANCED_FIELD_NUMBER: _ClassVar[int]
- FILE_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
- STREAM_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
- SEGMENT_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
- IMAGE_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
- room_name: str
- audio_track_id: str
- video_track_id: str
- file: EncodedFileOutput
+ IMAGES_FIELD_NUMBER: _ClassVar[int]
+ STORAGE_FIELD_NUMBER: _ClassVar[int]
+ file: FileOutput
stream: StreamOutput
segments: SegmentedFileOutput
- preset: EncodingOptionsPreset
- advanced: EncodingOptions
- file_outputs: _containers.RepeatedCompositeFieldContainer[EncodedFileOutput]
- stream_outputs: _containers.RepeatedCompositeFieldContainer[StreamOutput]
- segment_outputs: _containers.RepeatedCompositeFieldContainer[SegmentedFileOutput]
- image_outputs: _containers.RepeatedCompositeFieldContainer[ImageOutput]
- def __init__(self, room_name: _Optional[str] = ..., audio_track_id: _Optional[str] = ..., video_track_id: _Optional[str] = ..., file: _Optional[_Union[EncodedFileOutput, _Mapping]] = ..., stream: _Optional[_Union[StreamOutput, _Mapping]] = ..., segments: _Optional[_Union[SegmentedFileOutput, _Mapping]] = ..., preset: _Optional[_Union[EncodingOptionsPreset, str]] = ..., advanced: _Optional[_Union[EncodingOptions, _Mapping]] = ..., file_outputs: _Optional[_Iterable[_Union[EncodedFileOutput, _Mapping]]] = ..., stream_outputs: _Optional[_Iterable[_Union[StreamOutput, _Mapping]]] = ..., segment_outputs: _Optional[_Iterable[_Union[SegmentedFileOutput, _Mapping]]] = ..., image_outputs: _Optional[_Iterable[_Union[ImageOutput, _Mapping]]] = ...) -> None: ...
+ images: ImageOutput
+ storage: StorageConfig
+ def __init__(self, file: _Optional[_Union[FileOutput, _Mapping]] = ..., stream: _Optional[_Union[StreamOutput, _Mapping]] = ..., segments: _Optional[_Union[SegmentedFileOutput, _Mapping]] = ..., images: _Optional[_Union[ImageOutput, _Mapping]] = ..., storage: _Optional[_Union[StorageConfig, _Mapping]] = ...) -> None: ...
-class TrackEgressRequest(_message.Message):
- __slots__ = ("room_name", "track_id", "file", "websocket_url")
- ROOM_NAME_FIELD_NUMBER: _ClassVar[int]
- TRACK_ID_FIELD_NUMBER: _ClassVar[int]
- FILE_FIELD_NUMBER: _ClassVar[int]
- WEBSOCKET_URL_FIELD_NUMBER: _ClassVar[int]
- room_name: str
- track_id: str
- file: DirectFileOutput
- websocket_url: str
- def __init__(self, room_name: _Optional[str] = ..., track_id: _Optional[str] = ..., file: _Optional[_Union[DirectFileOutput, _Mapping]] = ..., websocket_url: _Optional[str] = ...) -> None: ...
-
-class EncodedFileOutput(_message.Message):
- __slots__ = ("file_type", "filepath", "disable_manifest", "s3", "gcp", "azure", "aliOSS")
+class FileOutput(_message.Message):
+ __slots__ = ("file_type", "filepath", "disable_manifest")
FILE_TYPE_FIELD_NUMBER: _ClassVar[int]
FILEPATH_FIELD_NUMBER: _ClassVar[int]
DISABLE_MANIFEST_FIELD_NUMBER: _ClassVar[int]
- S3_FIELD_NUMBER: _ClassVar[int]
- GCP_FIELD_NUMBER: _ClassVar[int]
- AZURE_FIELD_NUMBER: _ClassVar[int]
- ALIOSS_FIELD_NUMBER: _ClassVar[int]
file_type: EncodedFileType
filepath: str
disable_manifest: bool
- s3: S3Upload
- gcp: GCPUpload
- azure: AzureBlobUpload
- aliOSS: AliOSSUpload
- def __init__(self, file_type: _Optional[_Union[EncodedFileType, str]] = ..., filepath: _Optional[str] = ..., disable_manifest: bool = ..., s3: _Optional[_Union[S3Upload, _Mapping]] = ..., gcp: _Optional[_Union[GCPUpload, _Mapping]] = ..., azure: _Optional[_Union[AzureBlobUpload, _Mapping]] = ..., aliOSS: _Optional[_Union[AliOSSUpload, _Mapping]] = ...) -> None: ...
+ def __init__(self, file_type: _Optional[_Union[EncodedFileType, str]] = ..., filepath: _Optional[str] = ..., disable_manifest: bool = ...) -> None: ...
+
+class StreamOutput(_message.Message):
+ __slots__ = ("protocol", "urls")
+ PROTOCOL_FIELD_NUMBER: _ClassVar[int]
+ URLS_FIELD_NUMBER: _ClassVar[int]
+ protocol: StreamProtocol
+ urls: _containers.RepeatedScalarFieldContainer[str]
+ def __init__(self, protocol: _Optional[_Union[StreamProtocol, str]] = ..., urls: _Optional[_Iterable[str]] = ...) -> None: ...
class SegmentedFileOutput(_message.Message):
__slots__ = ("protocol", "filename_prefix", "playlist_name", "live_playlist_name", "segment_duration", "filename_suffix", "disable_manifest", "s3", "gcp", "azure", "aliOSS")
@@ -248,22 +300,6 @@ class SegmentedFileOutput(_message.Message):
aliOSS: AliOSSUpload
def __init__(self, protocol: _Optional[_Union[SegmentedFileProtocol, str]] = ..., filename_prefix: _Optional[str] = ..., playlist_name: _Optional[str] = ..., live_playlist_name: _Optional[str] = ..., segment_duration: _Optional[int] = ..., filename_suffix: _Optional[_Union[SegmentedFileSuffix, str]] = ..., disable_manifest: bool = ..., s3: _Optional[_Union[S3Upload, _Mapping]] = ..., gcp: _Optional[_Union[GCPUpload, _Mapping]] = ..., azure: _Optional[_Union[AzureBlobUpload, _Mapping]] = ..., aliOSS: _Optional[_Union[AliOSSUpload, _Mapping]] = ...) -> None: ...
-class DirectFileOutput(_message.Message):
- __slots__ = ("filepath", "disable_manifest", "s3", "gcp", "azure", "aliOSS")
- FILEPATH_FIELD_NUMBER: _ClassVar[int]
- DISABLE_MANIFEST_FIELD_NUMBER: _ClassVar[int]
- S3_FIELD_NUMBER: _ClassVar[int]
- GCP_FIELD_NUMBER: _ClassVar[int]
- AZURE_FIELD_NUMBER: _ClassVar[int]
- ALIOSS_FIELD_NUMBER: _ClassVar[int]
- filepath: str
- disable_manifest: bool
- s3: S3Upload
- gcp: GCPUpload
- azure: AzureBlobUpload
- aliOSS: AliOSSUpload
- def __init__(self, filepath: _Optional[str] = ..., disable_manifest: bool = ..., s3: _Optional[_Union[S3Upload, _Mapping]] = ..., gcp: _Optional[_Union[GCPUpload, _Mapping]] = ..., azure: _Optional[_Union[AzureBlobUpload, _Mapping]] = ..., aliOSS: _Optional[_Union[AliOSSUpload, _Mapping]] = ...) -> None: ...
-
class ImageOutput(_message.Message):
__slots__ = ("capture_interval", "width", "height", "filename_prefix", "filename_suffix", "image_codec", "disable_manifest", "s3", "gcp", "azure", "aliOSS")
CAPTURE_INTERVAL_FIELD_NUMBER: _ClassVar[int]
@@ -290,8 +326,20 @@ class ImageOutput(_message.Message):
aliOSS: AliOSSUpload
def __init__(self, capture_interval: _Optional[int] = ..., width: _Optional[int] = ..., height: _Optional[int] = ..., filename_prefix: _Optional[str] = ..., filename_suffix: _Optional[_Union[ImageFileSuffix, str]] = ..., image_codec: _Optional[_Union[_models.ImageCodec, str]] = ..., disable_manifest: bool = ..., s3: _Optional[_Union[S3Upload, _Mapping]] = ..., gcp: _Optional[_Union[GCPUpload, _Mapping]] = ..., azure: _Optional[_Union[AzureBlobUpload, _Mapping]] = ..., aliOSS: _Optional[_Union[AliOSSUpload, _Mapping]] = ...) -> None: ...
+class StorageConfig(_message.Message):
+ __slots__ = ("s3", "gcp", "azure", "aliOSS")
+ S3_FIELD_NUMBER: _ClassVar[int]
+ GCP_FIELD_NUMBER: _ClassVar[int]
+ AZURE_FIELD_NUMBER: _ClassVar[int]
+ ALIOSS_FIELD_NUMBER: _ClassVar[int]
+ s3: S3Upload
+ gcp: GCPUpload
+ azure: AzureBlobUpload
+ aliOSS: AliOSSUpload
+ def __init__(self, s3: _Optional[_Union[S3Upload, _Mapping]] = ..., gcp: _Optional[_Union[GCPUpload, _Mapping]] = ..., azure: _Optional[_Union[AzureBlobUpload, _Mapping]] = ..., aliOSS: _Optional[_Union[AliOSSUpload, _Mapping]] = ...) -> None: ...
+
class S3Upload(_message.Message):
- __slots__ = ("access_key", "secret", "session_token", "region", "endpoint", "bucket", "force_path_style", "metadata", "tagging", "content_disposition", "proxy")
+ __slots__ = ("access_key", "secret", "session_token", "assume_role_arn", "assume_role_external_id", "region", "endpoint", "bucket", "force_path_style", "metadata", "tagging", "content_disposition", "proxy")
class MetadataEntry(_message.Message):
__slots__ = ("key", "value")
KEY_FIELD_NUMBER: _ClassVar[int]
@@ -302,6 +350,8 @@ class S3Upload(_message.Message):
ACCESS_KEY_FIELD_NUMBER: _ClassVar[int]
SECRET_FIELD_NUMBER: _ClassVar[int]
SESSION_TOKEN_FIELD_NUMBER: _ClassVar[int]
+ ASSUME_ROLE_ARN_FIELD_NUMBER: _ClassVar[int]
+ ASSUME_ROLE_EXTERNAL_ID_FIELD_NUMBER: _ClassVar[int]
REGION_FIELD_NUMBER: _ClassVar[int]
ENDPOINT_FIELD_NUMBER: _ClassVar[int]
BUCKET_FIELD_NUMBER: _ClassVar[int]
@@ -313,6 +363,8 @@ class S3Upload(_message.Message):
access_key: str
secret: str
session_token: str
+ assume_role_arn: str
+ assume_role_external_id: str
region: str
endpoint: str
bucket: str
@@ -321,7 +373,7 @@ class S3Upload(_message.Message):
tagging: str
content_disposition: str
proxy: ProxyConfig
- def __init__(self, access_key: _Optional[str] = ..., secret: _Optional[str] = ..., session_token: _Optional[str] = ..., region: _Optional[str] = ..., endpoint: _Optional[str] = ..., bucket: _Optional[str] = ..., force_path_style: bool = ..., metadata: _Optional[_Mapping[str, str]] = ..., tagging: _Optional[str] = ..., content_disposition: _Optional[str] = ..., proxy: _Optional[_Union[ProxyConfig, _Mapping]] = ...) -> None: ...
+ def __init__(self, access_key: _Optional[str] = ..., secret: _Optional[str] = ..., session_token: _Optional[str] = ..., assume_role_arn: _Optional[str] = ..., assume_role_external_id: _Optional[str] = ..., region: _Optional[str] = ..., endpoint: _Optional[str] = ..., bucket: _Optional[str] = ..., force_path_style: bool = ..., metadata: _Optional[_Mapping[str, str]] = ..., tagging: _Optional[str] = ..., content_disposition: _Optional[str] = ..., proxy: _Optional[_Union[ProxyConfig, _Mapping]] = ...) -> None: ...
class GCPUpload(_message.Message):
__slots__ = ("credentials", "bucket", "proxy")
@@ -367,60 +419,6 @@ class ProxyConfig(_message.Message):
password: str
def __init__(self, url: _Optional[str] = ..., username: _Optional[str] = ..., password: _Optional[str] = ...) -> None: ...
-class StreamOutput(_message.Message):
- __slots__ = ("protocol", "urls")
- PROTOCOL_FIELD_NUMBER: _ClassVar[int]
- URLS_FIELD_NUMBER: _ClassVar[int]
- protocol: StreamProtocol
- urls: _containers.RepeatedScalarFieldContainer[str]
- def __init__(self, protocol: _Optional[_Union[StreamProtocol, str]] = ..., urls: _Optional[_Iterable[str]] = ...) -> None: ...
-
-class EncodingOptions(_message.Message):
- __slots__ = ("width", "height", "depth", "framerate", "audio_codec", "audio_bitrate", "audio_quality", "audio_frequency", "video_codec", "video_bitrate", "video_quality", "key_frame_interval")
- WIDTH_FIELD_NUMBER: _ClassVar[int]
- HEIGHT_FIELD_NUMBER: _ClassVar[int]
- DEPTH_FIELD_NUMBER: _ClassVar[int]
- FRAMERATE_FIELD_NUMBER: _ClassVar[int]
- AUDIO_CODEC_FIELD_NUMBER: _ClassVar[int]
- AUDIO_BITRATE_FIELD_NUMBER: _ClassVar[int]
- AUDIO_QUALITY_FIELD_NUMBER: _ClassVar[int]
- AUDIO_FREQUENCY_FIELD_NUMBER: _ClassVar[int]
- VIDEO_CODEC_FIELD_NUMBER: _ClassVar[int]
- VIDEO_BITRATE_FIELD_NUMBER: _ClassVar[int]
- VIDEO_QUALITY_FIELD_NUMBER: _ClassVar[int]
- KEY_FRAME_INTERVAL_FIELD_NUMBER: _ClassVar[int]
- width: int
- height: int
- depth: int
- framerate: int
- audio_codec: _models.AudioCodec
- audio_bitrate: int
- audio_quality: int
- audio_frequency: int
- video_codec: _models.VideoCodec
- video_bitrate: int
- video_quality: int
- key_frame_interval: float
- def __init__(self, width: _Optional[int] = ..., height: _Optional[int] = ..., depth: _Optional[int] = ..., framerate: _Optional[int] = ..., audio_codec: _Optional[_Union[_models.AudioCodec, str]] = ..., audio_bitrate: _Optional[int] = ..., audio_quality: _Optional[int] = ..., audio_frequency: _Optional[int] = ..., video_codec: _Optional[_Union[_models.VideoCodec, str]] = ..., video_bitrate: _Optional[int] = ..., video_quality: _Optional[int] = ..., key_frame_interval: _Optional[float] = ...) -> None: ...
-
-class UpdateLayoutRequest(_message.Message):
- __slots__ = ("egress_id", "layout")
- EGRESS_ID_FIELD_NUMBER: _ClassVar[int]
- LAYOUT_FIELD_NUMBER: _ClassVar[int]
- egress_id: str
- layout: str
- def __init__(self, egress_id: _Optional[str] = ..., layout: _Optional[str] = ...) -> None: ...
-
-class UpdateStreamRequest(_message.Message):
- __slots__ = ("egress_id", "add_output_urls", "remove_output_urls")
- EGRESS_ID_FIELD_NUMBER: _ClassVar[int]
- ADD_OUTPUT_URLS_FIELD_NUMBER: _ClassVar[int]
- REMOVE_OUTPUT_URLS_FIELD_NUMBER: _ClassVar[int]
- egress_id: str
- add_output_urls: _containers.RepeatedScalarFieldContainer[str]
- remove_output_urls: _containers.RepeatedScalarFieldContainer[str]
- def __init__(self, egress_id: _Optional[str] = ..., add_output_urls: _Optional[_Iterable[str]] = ..., remove_output_urls: _Optional[_Iterable[str]] = ...) -> None: ...
-
class ListEgressRequest(_message.Message):
__slots__ = ("room_name", "egress_id", "active")
ROOM_NAME_FIELD_NUMBER: _ClassVar[int]
@@ -437,6 +435,20 @@ class ListEgressResponse(_message.Message):
items: _containers.RepeatedCompositeFieldContainer[EgressInfo]
def __init__(self, items: _Optional[_Iterable[_Union[EgressInfo, _Mapping]]] = ...) -> None: ...
+class UpdateEgressRequest(_message.Message):
+ __slots__ = ("egress_id", "url", "layout", "add_stream_urls", "remove_stream_urls")
+ EGRESS_ID_FIELD_NUMBER: _ClassVar[int]
+ URL_FIELD_NUMBER: _ClassVar[int]
+ LAYOUT_FIELD_NUMBER: _ClassVar[int]
+ ADD_STREAM_URLS_FIELD_NUMBER: _ClassVar[int]
+ REMOVE_STREAM_URLS_FIELD_NUMBER: _ClassVar[int]
+ egress_id: str
+ url: str
+ layout: str
+ add_stream_urls: _containers.RepeatedScalarFieldContainer[str]
+ remove_stream_urls: _containers.RepeatedScalarFieldContainer[str]
+ def __init__(self, egress_id: _Optional[str] = ..., url: _Optional[str] = ..., layout: _Optional[str] = ..., add_stream_urls: _Optional[_Iterable[str]] = ..., remove_stream_urls: _Optional[_Iterable[str]] = ...) -> None: ...
+
class StopEgressRequest(_message.Message):
__slots__ = ("egress_id",)
EGRESS_ID_FIELD_NUMBER: _ClassVar[int]
@@ -444,61 +456,65 @@ class StopEgressRequest(_message.Message):
def __init__(self, egress_id: _Optional[str] = ...) -> None: ...
class EgressInfo(_message.Message):
- __slots__ = ("egress_id", "room_id", "room_name", "status", "started_at", "ended_at", "updated_at", "details", "error", "error_code", "room_composite", "web", "participant", "track_composite", "track", "stream", "file", "segments", "stream_results", "file_results", "segment_results", "image_results")
+ __slots__ = ("egress_id", "room_id", "room_name", "source_type", "status", "started_at", "ended_at", "updated_at", "replay", "room_composite", "web", "participant", "track_composite", "track", "stream_results", "file_results", "segment_results", "image_results", "error", "error_code", "details", "manifest_location", "backup_storage_used", "retry_count", "stream", "file", "segments")
EGRESS_ID_FIELD_NUMBER: _ClassVar[int]
ROOM_ID_FIELD_NUMBER: _ClassVar[int]
ROOM_NAME_FIELD_NUMBER: _ClassVar[int]
+ SOURCE_TYPE_FIELD_NUMBER: _ClassVar[int]
STATUS_FIELD_NUMBER: _ClassVar[int]
STARTED_AT_FIELD_NUMBER: _ClassVar[int]
ENDED_AT_FIELD_NUMBER: _ClassVar[int]
UPDATED_AT_FIELD_NUMBER: _ClassVar[int]
- DETAILS_FIELD_NUMBER: _ClassVar[int]
- ERROR_FIELD_NUMBER: _ClassVar[int]
- ERROR_CODE_FIELD_NUMBER: _ClassVar[int]
+ REPLAY_FIELD_NUMBER: _ClassVar[int]
ROOM_COMPOSITE_FIELD_NUMBER: _ClassVar[int]
WEB_FIELD_NUMBER: _ClassVar[int]
PARTICIPANT_FIELD_NUMBER: _ClassVar[int]
TRACK_COMPOSITE_FIELD_NUMBER: _ClassVar[int]
TRACK_FIELD_NUMBER: _ClassVar[int]
- STREAM_FIELD_NUMBER: _ClassVar[int]
- FILE_FIELD_NUMBER: _ClassVar[int]
- SEGMENTS_FIELD_NUMBER: _ClassVar[int]
STREAM_RESULTS_FIELD_NUMBER: _ClassVar[int]
FILE_RESULTS_FIELD_NUMBER: _ClassVar[int]
SEGMENT_RESULTS_FIELD_NUMBER: _ClassVar[int]
IMAGE_RESULTS_FIELD_NUMBER: _ClassVar[int]
+ ERROR_FIELD_NUMBER: _ClassVar[int]
+ ERROR_CODE_FIELD_NUMBER: _ClassVar[int]
+ DETAILS_FIELD_NUMBER: _ClassVar[int]
+ MANIFEST_LOCATION_FIELD_NUMBER: _ClassVar[int]
+ BACKUP_STORAGE_USED_FIELD_NUMBER: _ClassVar[int]
+ RETRY_COUNT_FIELD_NUMBER: _ClassVar[int]
+ STREAM_FIELD_NUMBER: _ClassVar[int]
+ FILE_FIELD_NUMBER: _ClassVar[int]
+ SEGMENTS_FIELD_NUMBER: _ClassVar[int]
egress_id: str
room_id: str
room_name: str
+ source_type: EgressSourceType
status: EgressStatus
started_at: int
ended_at: int
updated_at: int
- details: str
- error: str
- error_code: int
+ replay: ExportReplayRequest
room_composite: RoomCompositeEgressRequest
web: WebEgressRequest
participant: ParticipantEgressRequest
track_composite: TrackCompositeEgressRequest
track: TrackEgressRequest
- stream: StreamInfoList
- file: FileInfo
- segments: SegmentsInfo
stream_results: _containers.RepeatedCompositeFieldContainer[StreamInfo]
file_results: _containers.RepeatedCompositeFieldContainer[FileInfo]
segment_results: _containers.RepeatedCompositeFieldContainer[SegmentsInfo]
image_results: _containers.RepeatedCompositeFieldContainer[ImagesInfo]
- def __init__(self, egress_id: _Optional[str] = ..., room_id: _Optional[str] = ..., room_name: _Optional[str] = ..., status: _Optional[_Union[EgressStatus, str]] = ..., started_at: _Optional[int] = ..., ended_at: _Optional[int] = ..., updated_at: _Optional[int] = ..., details: _Optional[str] = ..., error: _Optional[str] = ..., error_code: _Optional[int] = ..., room_composite: _Optional[_Union[RoomCompositeEgressRequest, _Mapping]] = ..., web: _Optional[_Union[WebEgressRequest, _Mapping]] = ..., participant: _Optional[_Union[ParticipantEgressRequest, _Mapping]] = ..., track_composite: _Optional[_Union[TrackCompositeEgressRequest, _Mapping]] = ..., track: _Optional[_Union[TrackEgressRequest, _Mapping]] = ..., stream: _Optional[_Union[StreamInfoList, _Mapping]] = ..., file: _Optional[_Union[FileInfo, _Mapping]] = ..., segments: _Optional[_Union[SegmentsInfo, _Mapping]] = ..., stream_results: _Optional[_Iterable[_Union[StreamInfo, _Mapping]]] = ..., file_results: _Optional[_Iterable[_Union[FileInfo, _Mapping]]] = ..., segment_results: _Optional[_Iterable[_Union[SegmentsInfo, _Mapping]]] = ..., image_results: _Optional[_Iterable[_Union[ImagesInfo, _Mapping]]] = ...) -> None: ...
-
-class StreamInfoList(_message.Message):
- __slots__ = ("info",)
- INFO_FIELD_NUMBER: _ClassVar[int]
- info: _containers.RepeatedCompositeFieldContainer[StreamInfo]
- def __init__(self, info: _Optional[_Iterable[_Union[StreamInfo, _Mapping]]] = ...) -> None: ...
+ error: str
+ error_code: int
+ details: str
+ manifest_location: str
+ backup_storage_used: bool
+ retry_count: int
+ stream: StreamInfoList
+ file: FileInfo
+ segments: SegmentsInfo
+ def __init__(self, egress_id: _Optional[str] = ..., room_id: _Optional[str] = ..., room_name: _Optional[str] = ..., source_type: _Optional[_Union[EgressSourceType, str]] = ..., status: _Optional[_Union[EgressStatus, str]] = ..., started_at: _Optional[int] = ..., ended_at: _Optional[int] = ..., updated_at: _Optional[int] = ..., replay: _Optional[_Union[ExportReplayRequest, _Mapping]] = ..., room_composite: _Optional[_Union[RoomCompositeEgressRequest, _Mapping]] = ..., web: _Optional[_Union[WebEgressRequest, _Mapping]] = ..., participant: _Optional[_Union[ParticipantEgressRequest, _Mapping]] = ..., track_composite: _Optional[_Union[TrackCompositeEgressRequest, _Mapping]] = ..., track: _Optional[_Union[TrackEgressRequest, _Mapping]] = ..., stream_results: _Optional[_Iterable[_Union[StreamInfo, _Mapping]]] = ..., file_results: _Optional[_Iterable[_Union[FileInfo, _Mapping]]] = ..., segment_results: _Optional[_Iterable[_Union[SegmentsInfo, _Mapping]]] = ..., image_results: _Optional[_Iterable[_Union[ImagesInfo, _Mapping]]] = ..., error: _Optional[str] = ..., error_code: _Optional[int] = ..., details: _Optional[str] = ..., manifest_location: _Optional[str] = ..., backup_storage_used: bool = ..., retry_count: _Optional[int] = ..., stream: _Optional[_Union[StreamInfoList, _Mapping]] = ..., file: _Optional[_Union[FileInfo, _Mapping]] = ..., segments: _Optional[_Union[SegmentsInfo, _Mapping]] = ...) -> None: ...
class StreamInfo(_message.Message):
- __slots__ = ("url", "started_at", "ended_at", "duration", "status", "error")
+ __slots__ = ("url", "started_at", "ended_at", "duration", "status", "error", "last_retry_at", "retries")
class Status(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
ACTIVE: _ClassVar[StreamInfo.Status]
@@ -513,13 +529,17 @@ class StreamInfo(_message.Message):
DURATION_FIELD_NUMBER: _ClassVar[int]
STATUS_FIELD_NUMBER: _ClassVar[int]
ERROR_FIELD_NUMBER: _ClassVar[int]
+ LAST_RETRY_AT_FIELD_NUMBER: _ClassVar[int]
+ RETRIES_FIELD_NUMBER: _ClassVar[int]
url: str
started_at: int
ended_at: int
duration: int
status: StreamInfo.Status
error: str
- def __init__(self, url: _Optional[str] = ..., started_at: _Optional[int] = ..., ended_at: _Optional[int] = ..., duration: _Optional[int] = ..., status: _Optional[_Union[StreamInfo.Status, str]] = ..., error: _Optional[str] = ...) -> None: ...
+ last_retry_at: int
+ retries: int
+ def __init__(self, url: _Optional[str] = ..., started_at: _Optional[int] = ..., ended_at: _Optional[int] = ..., duration: _Optional[int] = ..., status: _Optional[_Union[StreamInfo.Status, str]] = ..., error: _Optional[str] = ..., last_retry_at: _Optional[int] = ..., retries: _Optional[int] = ...) -> None: ...
class FileInfo(_message.Message):
__slots__ = ("filename", "started_at", "ended_at", "duration", "size", "location")
@@ -560,14 +580,16 @@ class SegmentsInfo(_message.Message):
def __init__(self, playlist_name: _Optional[str] = ..., live_playlist_name: _Optional[str] = ..., duration: _Optional[int] = ..., size: _Optional[int] = ..., playlist_location: _Optional[str] = ..., live_playlist_location: _Optional[str] = ..., segment_count: _Optional[int] = ..., started_at: _Optional[int] = ..., ended_at: _Optional[int] = ...) -> None: ...
class ImagesInfo(_message.Message):
- __slots__ = ("image_count", "started_at", "ended_at")
+ __slots__ = ("filename_prefix", "image_count", "started_at", "ended_at")
+ FILENAME_PREFIX_FIELD_NUMBER: _ClassVar[int]
IMAGE_COUNT_FIELD_NUMBER: _ClassVar[int]
STARTED_AT_FIELD_NUMBER: _ClassVar[int]
ENDED_AT_FIELD_NUMBER: _ClassVar[int]
+ filename_prefix: str
image_count: int
started_at: int
ended_at: int
- def __init__(self, image_count: _Optional[int] = ..., started_at: _Optional[int] = ..., ended_at: _Optional[int] = ...) -> None: ...
+ def __init__(self, filename_prefix: _Optional[str] = ..., image_count: _Optional[int] = ..., started_at: _Optional[int] = ..., ended_at: _Optional[int] = ...) -> None: ...
class AutoParticipantEgress(_message.Message):
__slots__ = ("preset", "advanced", "file_outputs", "segment_outputs")
@@ -596,3 +618,223 @@ class AutoTrackEgress(_message.Message):
azure: AzureBlobUpload
aliOSS: AliOSSUpload
def __init__(self, filepath: _Optional[str] = ..., disable_manifest: bool = ..., s3: _Optional[_Union[S3Upload, _Mapping]] = ..., gcp: _Optional[_Union[GCPUpload, _Mapping]] = ..., azure: _Optional[_Union[AzureBlobUpload, _Mapping]] = ..., aliOSS: _Optional[_Union[AliOSSUpload, _Mapping]] = ...) -> None: ...
+
+class ExportReplayRequest(_message.Message):
+ __slots__ = ("replay_id", "start_offset_ms", "end_offset_ms", "template", "web", "media", "preset", "advanced", "outputs", "storage", "webhooks")
+ REPLAY_ID_FIELD_NUMBER: _ClassVar[int]
+ START_OFFSET_MS_FIELD_NUMBER: _ClassVar[int]
+ END_OFFSET_MS_FIELD_NUMBER: _ClassVar[int]
+ TEMPLATE_FIELD_NUMBER: _ClassVar[int]
+ WEB_FIELD_NUMBER: _ClassVar[int]
+ MEDIA_FIELD_NUMBER: _ClassVar[int]
+ PRESET_FIELD_NUMBER: _ClassVar[int]
+ ADVANCED_FIELD_NUMBER: _ClassVar[int]
+ OUTPUTS_FIELD_NUMBER: _ClassVar[int]
+ STORAGE_FIELD_NUMBER: _ClassVar[int]
+ WEBHOOKS_FIELD_NUMBER: _ClassVar[int]
+ replay_id: str
+ start_offset_ms: int
+ end_offset_ms: int
+ template: TemplateSource
+ web: WebSource
+ media: MediaSource
+ preset: EncodingOptionsPreset
+ advanced: EncodingOptions
+ outputs: _containers.RepeatedCompositeFieldContainer[Output]
+ storage: StorageConfig
+ webhooks: _containers.RepeatedCompositeFieldContainer[_models.WebhookConfig]
+ def __init__(self, replay_id: _Optional[str] = ..., start_offset_ms: _Optional[int] = ..., end_offset_ms: _Optional[int] = ..., template: _Optional[_Union[TemplateSource, _Mapping]] = ..., web: _Optional[_Union[WebSource, _Mapping]] = ..., media: _Optional[_Union[MediaSource, _Mapping]] = ..., preset: _Optional[_Union[EncodingOptionsPreset, str]] = ..., advanced: _Optional[_Union[EncodingOptions, _Mapping]] = ..., outputs: _Optional[_Iterable[_Union[Output, _Mapping]]] = ..., storage: _Optional[_Union[StorageConfig, _Mapping]] = ..., webhooks: _Optional[_Iterable[_Union[_models.WebhookConfig, _Mapping]]] = ...) -> None: ...
+
+class RoomCompositeEgressRequest(_message.Message):
+ __slots__ = ("room_name", "layout", "audio_only", "audio_mixing", "video_only", "custom_base_url", "file", "stream", "segments", "preset", "advanced", "file_outputs", "stream_outputs", "segment_outputs", "image_outputs", "webhooks")
+ ROOM_NAME_FIELD_NUMBER: _ClassVar[int]
+ LAYOUT_FIELD_NUMBER: _ClassVar[int]
+ AUDIO_ONLY_FIELD_NUMBER: _ClassVar[int]
+ AUDIO_MIXING_FIELD_NUMBER: _ClassVar[int]
+ VIDEO_ONLY_FIELD_NUMBER: _ClassVar[int]
+ CUSTOM_BASE_URL_FIELD_NUMBER: _ClassVar[int]
+ FILE_FIELD_NUMBER: _ClassVar[int]
+ STREAM_FIELD_NUMBER: _ClassVar[int]
+ SEGMENTS_FIELD_NUMBER: _ClassVar[int]
+ PRESET_FIELD_NUMBER: _ClassVar[int]
+ ADVANCED_FIELD_NUMBER: _ClassVar[int]
+ FILE_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
+ STREAM_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
+ SEGMENT_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
+ IMAGE_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
+ WEBHOOKS_FIELD_NUMBER: _ClassVar[int]
+ room_name: str
+ layout: str
+ audio_only: bool
+ audio_mixing: AudioMixing
+ video_only: bool
+ custom_base_url: str
+ file: EncodedFileOutput
+ stream: StreamOutput
+ segments: SegmentedFileOutput
+ preset: EncodingOptionsPreset
+ advanced: EncodingOptions
+ file_outputs: _containers.RepeatedCompositeFieldContainer[EncodedFileOutput]
+ stream_outputs: _containers.RepeatedCompositeFieldContainer[StreamOutput]
+ segment_outputs: _containers.RepeatedCompositeFieldContainer[SegmentedFileOutput]
+ image_outputs: _containers.RepeatedCompositeFieldContainer[ImageOutput]
+ webhooks: _containers.RepeatedCompositeFieldContainer[_models.WebhookConfig]
+ def __init__(self, room_name: _Optional[str] = ..., layout: _Optional[str] = ..., audio_only: bool = ..., audio_mixing: _Optional[_Union[AudioMixing, str]] = ..., video_only: bool = ..., custom_base_url: _Optional[str] = ..., file: _Optional[_Union[EncodedFileOutput, _Mapping]] = ..., stream: _Optional[_Union[StreamOutput, _Mapping]] = ..., segments: _Optional[_Union[SegmentedFileOutput, _Mapping]] = ..., preset: _Optional[_Union[EncodingOptionsPreset, str]] = ..., advanced: _Optional[_Union[EncodingOptions, _Mapping]] = ..., file_outputs: _Optional[_Iterable[_Union[EncodedFileOutput, _Mapping]]] = ..., stream_outputs: _Optional[_Iterable[_Union[StreamOutput, _Mapping]]] = ..., segment_outputs: _Optional[_Iterable[_Union[SegmentedFileOutput, _Mapping]]] = ..., image_outputs: _Optional[_Iterable[_Union[ImageOutput, _Mapping]]] = ..., webhooks: _Optional[_Iterable[_Union[_models.WebhookConfig, _Mapping]]] = ...) -> None: ...
+
+class WebEgressRequest(_message.Message):
+ __slots__ = ("url", "audio_only", "video_only", "await_start_signal", "file", "stream", "segments", "preset", "advanced", "file_outputs", "stream_outputs", "segment_outputs", "image_outputs", "webhooks")
+ URL_FIELD_NUMBER: _ClassVar[int]
+ AUDIO_ONLY_FIELD_NUMBER: _ClassVar[int]
+ VIDEO_ONLY_FIELD_NUMBER: _ClassVar[int]
+ AWAIT_START_SIGNAL_FIELD_NUMBER: _ClassVar[int]
+ FILE_FIELD_NUMBER: _ClassVar[int]
+ STREAM_FIELD_NUMBER: _ClassVar[int]
+ SEGMENTS_FIELD_NUMBER: _ClassVar[int]
+ PRESET_FIELD_NUMBER: _ClassVar[int]
+ ADVANCED_FIELD_NUMBER: _ClassVar[int]
+ FILE_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
+ STREAM_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
+ SEGMENT_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
+ IMAGE_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
+ WEBHOOKS_FIELD_NUMBER: _ClassVar[int]
+ url: str
+ audio_only: bool
+ video_only: bool
+ await_start_signal: bool
+ file: EncodedFileOutput
+ stream: StreamOutput
+ segments: SegmentedFileOutput
+ preset: EncodingOptionsPreset
+ advanced: EncodingOptions
+ file_outputs: _containers.RepeatedCompositeFieldContainer[EncodedFileOutput]
+ stream_outputs: _containers.RepeatedCompositeFieldContainer[StreamOutput]
+ segment_outputs: _containers.RepeatedCompositeFieldContainer[SegmentedFileOutput]
+ image_outputs: _containers.RepeatedCompositeFieldContainer[ImageOutput]
+ webhooks: _containers.RepeatedCompositeFieldContainer[_models.WebhookConfig]
+ def __init__(self, url: _Optional[str] = ..., audio_only: bool = ..., video_only: bool = ..., await_start_signal: bool = ..., file: _Optional[_Union[EncodedFileOutput, _Mapping]] = ..., stream: _Optional[_Union[StreamOutput, _Mapping]] = ..., segments: _Optional[_Union[SegmentedFileOutput, _Mapping]] = ..., preset: _Optional[_Union[EncodingOptionsPreset, str]] = ..., advanced: _Optional[_Union[EncodingOptions, _Mapping]] = ..., file_outputs: _Optional[_Iterable[_Union[EncodedFileOutput, _Mapping]]] = ..., stream_outputs: _Optional[_Iterable[_Union[StreamOutput, _Mapping]]] = ..., segment_outputs: _Optional[_Iterable[_Union[SegmentedFileOutput, _Mapping]]] = ..., image_outputs: _Optional[_Iterable[_Union[ImageOutput, _Mapping]]] = ..., webhooks: _Optional[_Iterable[_Union[_models.WebhookConfig, _Mapping]]] = ...) -> None: ...
+
+class ParticipantEgressRequest(_message.Message):
+ __slots__ = ("room_name", "identity", "screen_share", "preset", "advanced", "file_outputs", "stream_outputs", "segment_outputs", "image_outputs", "webhooks")
+ ROOM_NAME_FIELD_NUMBER: _ClassVar[int]
+ IDENTITY_FIELD_NUMBER: _ClassVar[int]
+ SCREEN_SHARE_FIELD_NUMBER: _ClassVar[int]
+ PRESET_FIELD_NUMBER: _ClassVar[int]
+ ADVANCED_FIELD_NUMBER: _ClassVar[int]
+ FILE_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
+ STREAM_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
+ SEGMENT_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
+ IMAGE_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
+ WEBHOOKS_FIELD_NUMBER: _ClassVar[int]
+ room_name: str
+ identity: str
+ screen_share: bool
+ preset: EncodingOptionsPreset
+ advanced: EncodingOptions
+ file_outputs: _containers.RepeatedCompositeFieldContainer[EncodedFileOutput]
+ stream_outputs: _containers.RepeatedCompositeFieldContainer[StreamOutput]
+ segment_outputs: _containers.RepeatedCompositeFieldContainer[SegmentedFileOutput]
+ image_outputs: _containers.RepeatedCompositeFieldContainer[ImageOutput]
+ webhooks: _containers.RepeatedCompositeFieldContainer[_models.WebhookConfig]
+ def __init__(self, room_name: _Optional[str] = ..., identity: _Optional[str] = ..., screen_share: bool = ..., preset: _Optional[_Union[EncodingOptionsPreset, str]] = ..., advanced: _Optional[_Union[EncodingOptions, _Mapping]] = ..., file_outputs: _Optional[_Iterable[_Union[EncodedFileOutput, _Mapping]]] = ..., stream_outputs: _Optional[_Iterable[_Union[StreamOutput, _Mapping]]] = ..., segment_outputs: _Optional[_Iterable[_Union[SegmentedFileOutput, _Mapping]]] = ..., image_outputs: _Optional[_Iterable[_Union[ImageOutput, _Mapping]]] = ..., webhooks: _Optional[_Iterable[_Union[_models.WebhookConfig, _Mapping]]] = ...) -> None: ...
+
+class TrackCompositeEgressRequest(_message.Message):
+ __slots__ = ("room_name", "audio_track_id", "video_track_id", "file", "stream", "segments", "preset", "advanced", "file_outputs", "stream_outputs", "segment_outputs", "image_outputs", "webhooks")
+ ROOM_NAME_FIELD_NUMBER: _ClassVar[int]
+ AUDIO_TRACK_ID_FIELD_NUMBER: _ClassVar[int]
+ VIDEO_TRACK_ID_FIELD_NUMBER: _ClassVar[int]
+ FILE_FIELD_NUMBER: _ClassVar[int]
+ STREAM_FIELD_NUMBER: _ClassVar[int]
+ SEGMENTS_FIELD_NUMBER: _ClassVar[int]
+ PRESET_FIELD_NUMBER: _ClassVar[int]
+ ADVANCED_FIELD_NUMBER: _ClassVar[int]
+ FILE_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
+ STREAM_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
+ SEGMENT_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
+ IMAGE_OUTPUTS_FIELD_NUMBER: _ClassVar[int]
+ WEBHOOKS_FIELD_NUMBER: _ClassVar[int]
+ room_name: str
+ audio_track_id: str
+ video_track_id: str
+ file: EncodedFileOutput
+ stream: StreamOutput
+ segments: SegmentedFileOutput
+ preset: EncodingOptionsPreset
+ advanced: EncodingOptions
+ file_outputs: _containers.RepeatedCompositeFieldContainer[EncodedFileOutput]
+ stream_outputs: _containers.RepeatedCompositeFieldContainer[StreamOutput]
+ segment_outputs: _containers.RepeatedCompositeFieldContainer[SegmentedFileOutput]
+ image_outputs: _containers.RepeatedCompositeFieldContainer[ImageOutput]
+ webhooks: _containers.RepeatedCompositeFieldContainer[_models.WebhookConfig]
+ def __init__(self, room_name: _Optional[str] = ..., audio_track_id: _Optional[str] = ..., video_track_id: _Optional[str] = ..., file: _Optional[_Union[EncodedFileOutput, _Mapping]] = ..., stream: _Optional[_Union[StreamOutput, _Mapping]] = ..., segments: _Optional[_Union[SegmentedFileOutput, _Mapping]] = ..., preset: _Optional[_Union[EncodingOptionsPreset, str]] = ..., advanced: _Optional[_Union[EncodingOptions, _Mapping]] = ..., file_outputs: _Optional[_Iterable[_Union[EncodedFileOutput, _Mapping]]] = ..., stream_outputs: _Optional[_Iterable[_Union[StreamOutput, _Mapping]]] = ..., segment_outputs: _Optional[_Iterable[_Union[SegmentedFileOutput, _Mapping]]] = ..., image_outputs: _Optional[_Iterable[_Union[ImageOutput, _Mapping]]] = ..., webhooks: _Optional[_Iterable[_Union[_models.WebhookConfig, _Mapping]]] = ...) -> None: ...
+
+class TrackEgressRequest(_message.Message):
+ __slots__ = ("room_name", "track_id", "file", "websocket_url", "webhooks")
+ ROOM_NAME_FIELD_NUMBER: _ClassVar[int]
+ TRACK_ID_FIELD_NUMBER: _ClassVar[int]
+ FILE_FIELD_NUMBER: _ClassVar[int]
+ WEBSOCKET_URL_FIELD_NUMBER: _ClassVar[int]
+ WEBHOOKS_FIELD_NUMBER: _ClassVar[int]
+ room_name: str
+ track_id: str
+ file: DirectFileOutput
+ websocket_url: str
+ webhooks: _containers.RepeatedCompositeFieldContainer[_models.WebhookConfig]
+ def __init__(self, room_name: _Optional[str] = ..., track_id: _Optional[str] = ..., file: _Optional[_Union[DirectFileOutput, _Mapping]] = ..., websocket_url: _Optional[str] = ..., webhooks: _Optional[_Iterable[_Union[_models.WebhookConfig, _Mapping]]] = ...) -> None: ...
+
+class DirectFileOutput(_message.Message):
+ __slots__ = ("filepath", "disable_manifest", "s3", "gcp", "azure", "aliOSS")
+ FILEPATH_FIELD_NUMBER: _ClassVar[int]
+ DISABLE_MANIFEST_FIELD_NUMBER: _ClassVar[int]
+ S3_FIELD_NUMBER: _ClassVar[int]
+ GCP_FIELD_NUMBER: _ClassVar[int]
+ AZURE_FIELD_NUMBER: _ClassVar[int]
+ ALIOSS_FIELD_NUMBER: _ClassVar[int]
+ filepath: str
+ disable_manifest: bool
+ s3: S3Upload
+ gcp: GCPUpload
+ azure: AzureBlobUpload
+ aliOSS: AliOSSUpload
+ def __init__(self, filepath: _Optional[str] = ..., disable_manifest: bool = ..., s3: _Optional[_Union[S3Upload, _Mapping]] = ..., gcp: _Optional[_Union[GCPUpload, _Mapping]] = ..., azure: _Optional[_Union[AzureBlobUpload, _Mapping]] = ..., aliOSS: _Optional[_Union[AliOSSUpload, _Mapping]] = ...) -> None: ...
+
+class EncodedFileOutput(_message.Message):
+ __slots__ = ("file_type", "filepath", "disable_manifest", "s3", "gcp", "azure", "aliOSS")
+ FILE_TYPE_FIELD_NUMBER: _ClassVar[int]
+ FILEPATH_FIELD_NUMBER: _ClassVar[int]
+ DISABLE_MANIFEST_FIELD_NUMBER: _ClassVar[int]
+ S3_FIELD_NUMBER: _ClassVar[int]
+ GCP_FIELD_NUMBER: _ClassVar[int]
+ AZURE_FIELD_NUMBER: _ClassVar[int]
+ ALIOSS_FIELD_NUMBER: _ClassVar[int]
+ file_type: EncodedFileType
+ filepath: str
+ disable_manifest: bool
+ s3: S3Upload
+ gcp: GCPUpload
+ azure: AzureBlobUpload
+ aliOSS: AliOSSUpload
+ def __init__(self, file_type: _Optional[_Union[EncodedFileType, str]] = ..., filepath: _Optional[str] = ..., disable_manifest: bool = ..., s3: _Optional[_Union[S3Upload, _Mapping]] = ..., gcp: _Optional[_Union[GCPUpload, _Mapping]] = ..., azure: _Optional[_Union[AzureBlobUpload, _Mapping]] = ..., aliOSS: _Optional[_Union[AliOSSUpload, _Mapping]] = ...) -> None: ...
+
+class UpdateLayoutRequest(_message.Message):
+ __slots__ = ("egress_id", "layout")
+ EGRESS_ID_FIELD_NUMBER: _ClassVar[int]
+ LAYOUT_FIELD_NUMBER: _ClassVar[int]
+ egress_id: str
+ layout: str
+ def __init__(self, egress_id: _Optional[str] = ..., layout: _Optional[str] = ...) -> None: ...
+
+class UpdateStreamRequest(_message.Message):
+ __slots__ = ("egress_id", "add_output_urls", "remove_output_urls")
+ EGRESS_ID_FIELD_NUMBER: _ClassVar[int]
+ ADD_OUTPUT_URLS_FIELD_NUMBER: _ClassVar[int]
+ REMOVE_OUTPUT_URLS_FIELD_NUMBER: _ClassVar[int]
+ egress_id: str
+ add_output_urls: _containers.RepeatedScalarFieldContainer[str]
+ remove_output_urls: _containers.RepeatedScalarFieldContainer[str]
+ def __init__(self, egress_id: _Optional[str] = ..., add_output_urls: _Optional[_Iterable[str]] = ..., remove_output_urls: _Optional[_Iterable[str]] = ...) -> None: ...
+
+class StreamInfoList(_message.Message):
+ __slots__ = ("info",)
+ INFO_FIELD_NUMBER: _ClassVar[int]
+ info: _containers.RepeatedCompositeFieldContainer[StreamInfo]
+ def __init__(self, info: _Optional[_Iterable[_Union[StreamInfo, _Mapping]]] = ...) -> None: ...
diff --git a/livekit-protocol/livekit/protocol/ingress.py b/livekit-protocol/livekit/protocol/ingress.py
index 7e29ad86..a5b7bc11 100644
--- a/livekit-protocol/livekit/protocol/ingress.py
+++ b/livekit-protocol/livekit/protocol/ingress.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: livekit_ingress.proto
-# Protobuf Python Version: 4.25.3
+# Protobuf Python Version: 4.25.1
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
@@ -13,9 +13,10 @@
from . import models as _models_
+from .logger_pb import options as logger_dot_options__pb2
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15livekit_ingress.proto\x12\x07livekit\x1a\x14livekit_models.proto\"\xf7\x02\n\x14\x43reateIngressRequest\x12)\n\ninput_type\x18\x01 \x01(\x0e\x32\x15.livekit.IngressInput\x12\x0b\n\x03url\x18\t \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x11\n\troom_name\x18\x03 \x01(\t\x12\x1c\n\x14participant_identity\x18\x04 \x01(\t\x12\x18\n\x10participant_name\x18\x05 \x01(\t\x12\x1c\n\x14participant_metadata\x18\n \x01(\t\x12\x1e\n\x12\x62ypass_transcoding\x18\x08 \x01(\x08\x42\x02\x18\x01\x12\x1f\n\x12\x65nable_transcoding\x18\x0b \x01(\x08H\x00\x88\x01\x01\x12+\n\x05\x61udio\x18\x06 \x01(\x0b\x32\x1c.livekit.IngressAudioOptions\x12+\n\x05video\x18\x07 \x01(\x0b\x32\x1c.livekit.IngressVideoOptionsB\x15\n\x13_enable_transcoding\"\xcd\x01\n\x13IngressAudioOptions\x12\x0c\n\x04name\x18\x01 \x01(\t\x12$\n\x06source\x18\x02 \x01(\x0e\x32\x14.livekit.TrackSource\x12\x35\n\x06preset\x18\x03 \x01(\x0e\x32#.livekit.IngressAudioEncodingPresetH\x00\x12\x37\n\x07options\x18\x04 \x01(\x0b\x32$.livekit.IngressAudioEncodingOptionsH\x00\x42\x12\n\x10\x65ncoding_options\"\xcd\x01\n\x13IngressVideoOptions\x12\x0c\n\x04name\x18\x01 \x01(\t\x12$\n\x06source\x18\x02 \x01(\x0e\x32\x14.livekit.TrackSource\x12\x35\n\x06preset\x18\x03 \x01(\x0e\x32#.livekit.IngressVideoEncodingPresetH\x00\x12\x37\n\x07options\x18\x04 \x01(\x0b\x32$.livekit.IngressVideoEncodingOptionsH\x00\x42\x12\n\x10\x65ncoding_options\"\x7f\n\x1bIngressAudioEncodingOptions\x12(\n\x0b\x61udio_codec\x18\x01 \x01(\x0e\x32\x13.livekit.AudioCodec\x12\x0f\n\x07\x62itrate\x18\x02 \x01(\r\x12\x13\n\x0b\x64isable_dtx\x18\x03 \x01(\x08\x12\x10\n\x08\x63hannels\x18\x04 \x01(\r\"\x80\x01\n\x1bIngressVideoEncodingOptions\x12(\n\x0bvideo_codec\x18\x01 \x01(\x0e\x32\x13.livekit.VideoCodec\x12\x12\n\nframe_rate\x18\x02 \x01(\x01\x12#\n\x06layers\x18\x03 \x03(\x0b\x32\x13.livekit.VideoLayer\"\xce\x03\n\x0bIngressInfo\x12\x12\n\ningress_id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x12\n\nstream_key\x18\x03 \x01(\t\x12\x0b\n\x03url\x18\x04 \x01(\t\x12)\n\ninput_type\x18\x05 \x01(\x0e\x32\x15.livekit.IngressInput\x12\x1e\n\x12\x62ypass_transcoding\x18\r \x01(\x08\x42\x02\x18\x01\x12\x1f\n\x12\x65nable_transcoding\x18\x0f \x01(\x08H\x00\x88\x01\x01\x12+\n\x05\x61udio\x18\x06 \x01(\x0b\x32\x1c.livekit.IngressAudioOptions\x12+\n\x05video\x18\x07 \x01(\x0b\x32\x1c.livekit.IngressVideoOptions\x12\x11\n\troom_name\x18\x08 \x01(\t\x12\x1c\n\x14participant_identity\x18\t \x01(\t\x12\x18\n\x10participant_name\x18\n \x01(\t\x12\x1c\n\x14participant_metadata\x18\x0e \x01(\t\x12\x10\n\x08reusable\x18\x0b \x01(\x08\x12$\n\x05state\x18\x0c \x01(\x0b\x32\x15.livekit.IngressStateB\x15\n\x13_enable_transcoding\"\x9e\x03\n\x0cIngressState\x12,\n\x06status\x18\x01 \x01(\x0e\x32\x1c.livekit.IngressState.Status\x12\r\n\x05\x65rror\x18\x02 \x01(\t\x12\'\n\x05video\x18\x03 \x01(\x0b\x32\x18.livekit.InputVideoState\x12\'\n\x05\x61udio\x18\x04 \x01(\x0b\x32\x18.livekit.InputAudioState\x12\x0f\n\x07room_id\x18\x05 \x01(\t\x12\x12\n\nstarted_at\x18\x07 \x01(\x03\x12\x10\n\x08\x65nded_at\x18\x08 \x01(\x03\x12\x12\n\nupdated_at\x18\n \x01(\x03\x12\x13\n\x0bresource_id\x18\t \x01(\t\x12\"\n\x06tracks\x18\x06 \x03(\x0b\x32\x12.livekit.TrackInfo\"{\n\x06Status\x12\x15\n\x11\x45NDPOINT_INACTIVE\x10\x00\x12\x16\n\x12\x45NDPOINT_BUFFERING\x10\x01\x12\x17\n\x13\x45NDPOINT_PUBLISHING\x10\x02\x12\x12\n\x0e\x45NDPOINT_ERROR\x10\x03\x12\x15\n\x11\x45NDPOINT_COMPLETE\x10\x04\"o\n\x0fInputVideoState\x12\x11\n\tmime_type\x18\x01 \x01(\t\x12\x17\n\x0f\x61verage_bitrate\x18\x02 \x01(\r\x12\r\n\x05width\x18\x03 \x01(\r\x12\x0e\n\x06height\x18\x04 \x01(\r\x12\x11\n\tframerate\x18\x05 \x01(\x01\"d\n\x0fInputAudioState\x12\x11\n\tmime_type\x18\x01 \x01(\t\x12\x17\n\x0f\x61verage_bitrate\x18\x02 \x01(\r\x12\x10\n\x08\x63hannels\x18\x03 \x01(\r\x12\x13\n\x0bsample_rate\x18\x04 \x01(\r\"\xef\x02\n\x14UpdateIngressRequest\x12\x12\n\ningress_id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x11\n\troom_name\x18\x03 \x01(\t\x12\x1c\n\x14participant_identity\x18\x04 \x01(\t\x12\x18\n\x10participant_name\x18\x05 \x01(\t\x12\x1c\n\x14participant_metadata\x18\t \x01(\t\x12#\n\x12\x62ypass_transcoding\x18\x08 \x01(\x08\x42\x02\x18\x01H\x00\x88\x01\x01\x12\x1f\n\x12\x65nable_transcoding\x18\n \x01(\x08H\x01\x88\x01\x01\x12+\n\x05\x61udio\x18\x06 \x01(\x0b\x32\x1c.livekit.IngressAudioOptions\x12+\n\x05video\x18\x07 \x01(\x0b\x32\x1c.livekit.IngressVideoOptionsB\x15\n\x13_bypass_transcodingB\x15\n\x13_enable_transcoding\";\n\x12ListIngressRequest\x12\x11\n\troom_name\x18\x01 \x01(\t\x12\x12\n\ningress_id\x18\x02 \x01(\t\":\n\x13ListIngressResponse\x12#\n\x05items\x18\x01 \x03(\x0b\x32\x14.livekit.IngressInfo\"*\n\x14\x44\x65leteIngressRequest\x12\x12\n\ningress_id\x18\x01 \x01(\t*=\n\x0cIngressInput\x12\x0e\n\nRTMP_INPUT\x10\x00\x12\x0e\n\nWHIP_INPUT\x10\x01\x12\r\n\tURL_INPUT\x10\x02*I\n\x1aIngressAudioEncodingPreset\x12\x16\n\x12OPUS_STEREO_96KBPS\x10\x00\x12\x13\n\x0fOPUS_MONO_64KBS\x10\x01*\x84\x03\n\x1aIngressVideoEncodingPreset\x12\x1c\n\x18H264_720P_30FPS_3_LAYERS\x10\x00\x12\x1d\n\x19H264_1080P_30FPS_3_LAYERS\x10\x01\x12\x1c\n\x18H264_540P_25FPS_2_LAYERS\x10\x02\x12\x1b\n\x17H264_720P_30FPS_1_LAYER\x10\x03\x12\x1c\n\x18H264_1080P_30FPS_1_LAYER\x10\x04\x12(\n$H264_720P_30FPS_3_LAYERS_HIGH_MOTION\x10\x05\x12)\n%H264_1080P_30FPS_3_LAYERS_HIGH_MOTION\x10\x06\x12(\n$H264_540P_25FPS_2_LAYERS_HIGH_MOTION\x10\x07\x12\'\n#H264_720P_30FPS_1_LAYER_HIGH_MOTION\x10\x08\x12(\n$H264_1080P_30FPS_1_LAYER_HIGH_MOTION\x10\t2\xa5\x02\n\x07Ingress\x12\x44\n\rCreateIngress\x12\x1d.livekit.CreateIngressRequest\x1a\x14.livekit.IngressInfo\x12\x44\n\rUpdateIngress\x12\x1d.livekit.UpdateIngressRequest\x1a\x14.livekit.IngressInfo\x12H\n\x0bListIngress\x12\x1b.livekit.ListIngressRequest\x1a\x1c.livekit.ListIngressResponse\x12\x44\n\rDeleteIngress\x12\x1d.livekit.DeleteIngressRequest\x1a\x14.livekit.IngressInfoBFZ#github.com/livekit/protocol/livekit\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15livekit_ingress.proto\x12\x07livekit\x1a\x14livekit_models.proto\x1a\x14logger/options.proto\"\xc4\x03\n\x14\x43reateIngressRequest\x12)\n\ninput_type\x18\x01 \x01(\x0e\x32\x15.livekit.IngressInput\x12\x0b\n\x03url\x18\t \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x11\n\troom_name\x18\x03 \x01(\t\x12\x1c\n\x14participant_identity\x18\x04 \x01(\t\x12\x1d\n\x10participant_name\x18\x05 \x01(\tB\x03\xa8P\x01\x12\x42\n\x14participant_metadata\x18\n \x01(\tB$\xa8P\x01\xb2P\x1e\x12\x1e\n\x12\x62ypass_transcoding\x18\x08 \x01(\x08\x42\x02\x18\x01\x12\x1f\n\x12\x65nable_transcoding\x18\x0b \x01(\x08H\x00\x88\x01\x01\x12+\n\x05\x61udio\x18\x06 \x01(\x0b\x32\x1c.livekit.IngressAudioOptions\x12+\n\x05video\x18\x07 \x01(\x0b\x32\x1c.livekit.IngressVideoOptions\x12\x14\n\x07\x65nabled\x18\x0c \x01(\x08H\x01\x88\x01\x01\x42\x15\n\x13_enable_transcodingB\n\n\x08_enabled\"\xcd\x01\n\x13IngressAudioOptions\x12\x0c\n\x04name\x18\x01 \x01(\t\x12$\n\x06source\x18\x02 \x01(\x0e\x32\x14.livekit.TrackSource\x12\x35\n\x06preset\x18\x03 \x01(\x0e\x32#.livekit.IngressAudioEncodingPresetH\x00\x12\x37\n\x07options\x18\x04 \x01(\x0b\x32$.livekit.IngressAudioEncodingOptionsH\x00\x42\x12\n\x10\x65ncoding_options\"\xcd\x01\n\x13IngressVideoOptions\x12\x0c\n\x04name\x18\x01 \x01(\t\x12$\n\x06source\x18\x02 \x01(\x0e\x32\x14.livekit.TrackSource\x12\x35\n\x06preset\x18\x03 \x01(\x0e\x32#.livekit.IngressVideoEncodingPresetH\x00\x12\x37\n\x07options\x18\x04 \x01(\x0b\x32$.livekit.IngressVideoEncodingOptionsH\x00\x42\x12\n\x10\x65ncoding_options\"\x7f\n\x1bIngressAudioEncodingOptions\x12(\n\x0b\x61udio_codec\x18\x01 \x01(\x0e\x32\x13.livekit.AudioCodec\x12\x0f\n\x07\x62itrate\x18\x02 \x01(\r\x12\x13\n\x0b\x64isable_dtx\x18\x03 \x01(\x08\x12\x10\n\x08\x63hannels\x18\x04 \x01(\r\"\x80\x01\n\x1bIngressVideoEncodingOptions\x12(\n\x0bvideo_codec\x18\x01 \x01(\x0e\x32\x13.livekit.VideoCodec\x12\x12\n\nframe_rate\x18\x02 \x01(\x01\x12#\n\x06layers\x18\x03 \x03(\x0b\x32\x13.livekit.VideoLayer\"\xa9\x04\n\x0bIngressInfo\x12 \n\ningress_id\x18\x01 \x01(\tB\x0c\xbaP\tingressID\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x12\n\nstream_key\x18\x03 \x01(\t\x12\x0b\n\x03url\x18\x04 \x01(\t\x12)\n\ninput_type\x18\x05 \x01(\x0e\x32\x15.livekit.IngressInput\x12\x1e\n\x12\x62ypass_transcoding\x18\r \x01(\x08\x42\x02\x18\x01\x12\x1f\n\x12\x65nable_transcoding\x18\x0f \x01(\x08H\x00\x88\x01\x01\x12+\n\x05\x61udio\x18\x06 \x01(\x0b\x32\x1c.livekit.IngressAudioOptions\x12+\n\x05video\x18\x07 \x01(\x0b\x32\x1c.livekit.IngressVideoOptions\x12\x11\n\troom_name\x18\x08 \x01(\t\x12\x1c\n\x14participant_identity\x18\t \x01(\t\x12\x1d\n\x10participant_name\x18\n \x01(\tB\x03\xa8P\x01\x12\x42\n\x14participant_metadata\x18\x0e \x01(\tB$\xa8P\x01\xb2P\x1e\x12\x10\n\x08reusable\x18\x0b \x01(\x08\x12$\n\x05state\x18\x0c \x01(\x0b\x32\x15.livekit.IngressState\x12\x14\n\x07\x65nabled\x18\x10 \x01(\x08H\x01\x88\x01\x01\x42\x15\n\x13_enable_transcodingB\n\n\x08_enabled\"\xb8\x03\n\x0cIngressState\x12,\n\x06status\x18\x01 \x01(\x0e\x32\x1c.livekit.IngressState.Status\x12\r\n\x05\x65rror\x18\x02 \x01(\t\x12\'\n\x05video\x18\x03 \x01(\x0b\x32\x18.livekit.InputVideoState\x12\'\n\x05\x61udio\x18\x04 \x01(\x0b\x32\x18.livekit.InputAudioState\x12\x1a\n\x07room_id\x18\x05 \x01(\tB\t\xbaP\x06roomID\x12\x12\n\nstarted_at\x18\x07 \x01(\x03\x12\x10\n\x08\x65nded_at\x18\x08 \x01(\x03\x12\x12\n\nupdated_at\x18\n \x01(\x03\x12\"\n\x0bresource_id\x18\t \x01(\tB\r\xbaP\nresourceID\x12\"\n\x06tracks\x18\x06 \x03(\x0b\x32\x12.livekit.TrackInfo\"{\n\x06Status\x12\x15\n\x11\x45NDPOINT_INACTIVE\x10\x00\x12\x16\n\x12\x45NDPOINT_BUFFERING\x10\x01\x12\x17\n\x13\x45NDPOINT_PUBLISHING\x10\x02\x12\x12\n\x0e\x45NDPOINT_ERROR\x10\x03\x12\x15\n\x11\x45NDPOINT_COMPLETE\x10\x04\"o\n\x0fInputVideoState\x12\x11\n\tmime_type\x18\x01 \x01(\t\x12\x17\n\x0f\x61verage_bitrate\x18\x02 \x01(\r\x12\r\n\x05width\x18\x03 \x01(\r\x12\x0e\n\x06height\x18\x04 \x01(\r\x12\x11\n\tframerate\x18\x05 \x01(\x01\"d\n\x0fInputAudioState\x12\x11\n\tmime_type\x18\x01 \x01(\t\x12\x17\n\x0f\x61verage_bitrate\x18\x02 \x01(\r\x12\x10\n\x08\x63hannels\x18\x03 \x01(\r\x12\x13\n\x0bsample_rate\x18\x04 \x01(\r\"\xca\x03\n\x14UpdateIngressRequest\x12 \n\ningress_id\x18\x01 \x01(\tB\x0c\xbaP\tingressID\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x11\n\troom_name\x18\x03 \x01(\t\x12\x1c\n\x14participant_identity\x18\x04 \x01(\t\x12\x1d\n\x10participant_name\x18\x05 \x01(\tB\x03\xa8P\x01\x12\x42\n\x14participant_metadata\x18\t \x01(\tB$\xa8P\x01\xb2P\x1e\x12#\n\x12\x62ypass_transcoding\x18\x08 \x01(\x08\x42\x02\x18\x01H\x00\x88\x01\x01\x12\x1f\n\x12\x65nable_transcoding\x18\n \x01(\x08H\x01\x88\x01\x01\x12+\n\x05\x61udio\x18\x06 \x01(\x0b\x32\x1c.livekit.IngressAudioOptions\x12+\n\x05video\x18\x07 \x01(\x0b\x32\x1c.livekit.IngressVideoOptions\x12\x14\n\x07\x65nabled\x18\x0b \x01(\x08H\x02\x88\x01\x01\x42\x15\n\x13_bypass_transcodingB\x15\n\x13_enable_transcodingB\n\n\x08_enabled\"w\n\x12ListIngressRequest\x12,\n\npage_token\x18\x03 \x01(\x0b\x32\x18.livekit.TokenPagination\x12\x11\n\troom_name\x18\x01 \x01(\t\x12 \n\ningress_id\x18\x02 \x01(\tB\x0c\xbaP\tingressID\"m\n\x13ListIngressResponse\x12\x31\n\x0fnext_page_token\x18\x02 \x01(\x0b\x32\x18.livekit.TokenPagination\x12#\n\x05items\x18\x01 \x03(\x0b\x32\x14.livekit.IngressInfo\"8\n\x14\x44\x65leteIngressRequest\x12 \n\ningress_id\x18\x01 \x01(\tB\x0c\xbaP\tingressID*=\n\x0cIngressInput\x12\x0e\n\nRTMP_INPUT\x10\x00\x12\x0e\n\nWHIP_INPUT\x10\x01\x12\r\n\tURL_INPUT\x10\x02*I\n\x1aIngressAudioEncodingPreset\x12\x16\n\x12OPUS_STEREO_96KBPS\x10\x00\x12\x13\n\x0fOPUS_MONO_64KBS\x10\x01*\x84\x03\n\x1aIngressVideoEncodingPreset\x12\x1c\n\x18H264_720P_30FPS_3_LAYERS\x10\x00\x12\x1d\n\x19H264_1080P_30FPS_3_LAYERS\x10\x01\x12\x1c\n\x18H264_540P_25FPS_2_LAYERS\x10\x02\x12\x1b\n\x17H264_720P_30FPS_1_LAYER\x10\x03\x12\x1c\n\x18H264_1080P_30FPS_1_LAYER\x10\x04\x12(\n$H264_720P_30FPS_3_LAYERS_HIGH_MOTION\x10\x05\x12)\n%H264_1080P_30FPS_3_LAYERS_HIGH_MOTION\x10\x06\x12(\n$H264_540P_25FPS_2_LAYERS_HIGH_MOTION\x10\x07\x12\'\n#H264_720P_30FPS_1_LAYER_HIGH_MOTION\x10\x08\x12(\n$H264_1080P_30FPS_1_LAYER_HIGH_MOTION\x10\t2\xa5\x02\n\x07Ingress\x12\x44\n\rCreateIngress\x12\x1d.livekit.CreateIngressRequest\x1a\x14.livekit.IngressInfo\x12\x44\n\rUpdateIngress\x12\x1d.livekit.UpdateIngressRequest\x1a\x14.livekit.IngressInfo\x12H\n\x0bListIngress\x12\x1b.livekit.ListIngressRequest\x1a\x1c.livekit.ListIngressResponse\x12\x44\n\rDeleteIngress\x12\x1d.livekit.DeleteIngressRequest\x1a\x14.livekit.IngressInfoBFZ#github.com/livekit/protocol/livekit\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -23,46 +24,70 @@
if _descriptor._USE_C_DESCRIPTORS == False:
_globals['DESCRIPTOR']._options = None
_globals['DESCRIPTOR']._serialized_options = b'Z#github.com/livekit/protocol/livekit\252\002\rLiveKit.Proto\352\002\016LiveKit::Proto'
+ _globals['_CREATEINGRESSREQUEST'].fields_by_name['participant_name']._options = None
+ _globals['_CREATEINGRESSREQUEST'].fields_by_name['participant_name']._serialized_options = b'\250P\001'
+ _globals['_CREATEINGRESSREQUEST'].fields_by_name['participant_metadata']._options = None
+ _globals['_CREATEINGRESSREQUEST'].fields_by_name['participant_metadata']._serialized_options = b'\250P\001\262P\036'
_globals['_CREATEINGRESSREQUEST'].fields_by_name['bypass_transcoding']._options = None
_globals['_CREATEINGRESSREQUEST'].fields_by_name['bypass_transcoding']._serialized_options = b'\030\001'
+ _globals['_INGRESSINFO'].fields_by_name['ingress_id']._options = None
+ _globals['_INGRESSINFO'].fields_by_name['ingress_id']._serialized_options = b'\272P\tingressID'
_globals['_INGRESSINFO'].fields_by_name['bypass_transcoding']._options = None
_globals['_INGRESSINFO'].fields_by_name['bypass_transcoding']._serialized_options = b'\030\001'
+ _globals['_INGRESSINFO'].fields_by_name['participant_name']._options = None
+ _globals['_INGRESSINFO'].fields_by_name['participant_name']._serialized_options = b'\250P\001'
+ _globals['_INGRESSINFO'].fields_by_name['participant_metadata']._options = None
+ _globals['_INGRESSINFO'].fields_by_name['participant_metadata']._serialized_options = b'\250P\001\262P\036'
+ _globals['_INGRESSSTATE'].fields_by_name['room_id']._options = None
+ _globals['_INGRESSSTATE'].fields_by_name['room_id']._serialized_options = b'\272P\006roomID'
+ _globals['_INGRESSSTATE'].fields_by_name['resource_id']._options = None
+ _globals['_INGRESSSTATE'].fields_by_name['resource_id']._serialized_options = b'\272P\nresourceID'
+ _globals['_UPDATEINGRESSREQUEST'].fields_by_name['ingress_id']._options = None
+ _globals['_UPDATEINGRESSREQUEST'].fields_by_name['ingress_id']._serialized_options = b'\272P\tingressID'
+ _globals['_UPDATEINGRESSREQUEST'].fields_by_name['participant_name']._options = None
+ _globals['_UPDATEINGRESSREQUEST'].fields_by_name['participant_name']._serialized_options = b'\250P\001'
+ _globals['_UPDATEINGRESSREQUEST'].fields_by_name['participant_metadata']._options = None
+ _globals['_UPDATEINGRESSREQUEST'].fields_by_name['participant_metadata']._serialized_options = b'\250P\001\262P\036'
_globals['_UPDATEINGRESSREQUEST'].fields_by_name['bypass_transcoding']._options = None
_globals['_UPDATEINGRESSREQUEST'].fields_by_name['bypass_transcoding']._serialized_options = b'\030\001'
- _globals['_INGRESSINPUT']._serialized_start=2742
- _globals['_INGRESSINPUT']._serialized_end=2803
- _globals['_INGRESSAUDIOENCODINGPRESET']._serialized_start=2805
- _globals['_INGRESSAUDIOENCODINGPRESET']._serialized_end=2878
- _globals['_INGRESSVIDEOENCODINGPRESET']._serialized_start=2881
- _globals['_INGRESSVIDEOENCODINGPRESET']._serialized_end=3269
- _globals['_CREATEINGRESSREQUEST']._serialized_start=57
- _globals['_CREATEINGRESSREQUEST']._serialized_end=432
- _globals['_INGRESSAUDIOOPTIONS']._serialized_start=435
- _globals['_INGRESSAUDIOOPTIONS']._serialized_end=640
- _globals['_INGRESSVIDEOOPTIONS']._serialized_start=643
- _globals['_INGRESSVIDEOOPTIONS']._serialized_end=848
- _globals['_INGRESSAUDIOENCODINGOPTIONS']._serialized_start=850
- _globals['_INGRESSAUDIOENCODINGOPTIONS']._serialized_end=977
- _globals['_INGRESSVIDEOENCODINGOPTIONS']._serialized_start=980
- _globals['_INGRESSVIDEOENCODINGOPTIONS']._serialized_end=1108
- _globals['_INGRESSINFO']._serialized_start=1111
- _globals['_INGRESSINFO']._serialized_end=1573
- _globals['_INGRESSSTATE']._serialized_start=1576
- _globals['_INGRESSSTATE']._serialized_end=1990
- _globals['_INGRESSSTATE_STATUS']._serialized_start=1867
- _globals['_INGRESSSTATE_STATUS']._serialized_end=1990
- _globals['_INPUTVIDEOSTATE']._serialized_start=1992
- _globals['_INPUTVIDEOSTATE']._serialized_end=2103
- _globals['_INPUTAUDIOSTATE']._serialized_start=2105
- _globals['_INPUTAUDIOSTATE']._serialized_end=2205
- _globals['_UPDATEINGRESSREQUEST']._serialized_start=2208
- _globals['_UPDATEINGRESSREQUEST']._serialized_end=2575
- _globals['_LISTINGRESSREQUEST']._serialized_start=2577
- _globals['_LISTINGRESSREQUEST']._serialized_end=2636
- _globals['_LISTINGRESSRESPONSE']._serialized_start=2638
- _globals['_LISTINGRESSRESPONSE']._serialized_end=2696
- _globals['_DELETEINGRESSREQUEST']._serialized_start=2698
- _globals['_DELETEINGRESSREQUEST']._serialized_end=2740
- _globals['_INGRESS']._serialized_start=3272
- _globals['_INGRESS']._serialized_end=3565
+ _globals['_LISTINGRESSREQUEST'].fields_by_name['ingress_id']._options = None
+ _globals['_LISTINGRESSREQUEST'].fields_by_name['ingress_id']._serialized_options = b'\272P\tingressID'
+ _globals['_DELETEINGRESSREQUEST'].fields_by_name['ingress_id']._options = None
+ _globals['_DELETEINGRESSREQUEST'].fields_by_name['ingress_id']._serialized_options = b'\272P\tingressID'
+ _globals['_INGRESSINPUT']._serialized_start=3174
+ _globals['_INGRESSINPUT']._serialized_end=3235
+ _globals['_INGRESSAUDIOENCODINGPRESET']._serialized_start=3237
+ _globals['_INGRESSAUDIOENCODINGPRESET']._serialized_end=3310
+ _globals['_INGRESSVIDEOENCODINGPRESET']._serialized_start=3313
+ _globals['_INGRESSVIDEOENCODINGPRESET']._serialized_end=3701
+ _globals['_CREATEINGRESSREQUEST']._serialized_start=79
+ _globals['_CREATEINGRESSREQUEST']._serialized_end=531
+ _globals['_INGRESSAUDIOOPTIONS']._serialized_start=534
+ _globals['_INGRESSAUDIOOPTIONS']._serialized_end=739
+ _globals['_INGRESSVIDEOOPTIONS']._serialized_start=742
+ _globals['_INGRESSVIDEOOPTIONS']._serialized_end=947
+ _globals['_INGRESSAUDIOENCODINGOPTIONS']._serialized_start=949
+ _globals['_INGRESSAUDIOENCODINGOPTIONS']._serialized_end=1076
+ _globals['_INGRESSVIDEOENCODINGOPTIONS']._serialized_start=1079
+ _globals['_INGRESSVIDEOENCODINGOPTIONS']._serialized_end=1207
+ _globals['_INGRESSINFO']._serialized_start=1210
+ _globals['_INGRESSINFO']._serialized_end=1763
+ _globals['_INGRESSSTATE']._serialized_start=1766
+ _globals['_INGRESSSTATE']._serialized_end=2206
+ _globals['_INGRESSSTATE_STATUS']._serialized_start=2083
+ _globals['_INGRESSSTATE_STATUS']._serialized_end=2206
+ _globals['_INPUTVIDEOSTATE']._serialized_start=2208
+ _globals['_INPUTVIDEOSTATE']._serialized_end=2319
+ _globals['_INPUTAUDIOSTATE']._serialized_start=2321
+ _globals['_INPUTAUDIOSTATE']._serialized_end=2421
+ _globals['_UPDATEINGRESSREQUEST']._serialized_start=2424
+ _globals['_UPDATEINGRESSREQUEST']._serialized_end=2882
+ _globals['_LISTINGRESSREQUEST']._serialized_start=2884
+ _globals['_LISTINGRESSREQUEST']._serialized_end=3003
+ _globals['_LISTINGRESSRESPONSE']._serialized_start=3005
+ _globals['_LISTINGRESSRESPONSE']._serialized_end=3114
+ _globals['_DELETEINGRESSREQUEST']._serialized_start=3116
+ _globals['_DELETEINGRESSREQUEST']._serialized_end=3172
+ _globals['_INGRESS']._serialized_start=3704
+ _globals['_INGRESS']._serialized_end=3997
# @@protoc_insertion_point(module_scope)
diff --git a/livekit-protocol/livekit/protocol/ingress.pyi b/livekit-protocol/livekit/protocol/ingress.pyi
index fb9f8273..d214cba8 100644
--- a/livekit-protocol/livekit/protocol/ingress.pyi
+++ b/livekit-protocol/livekit/protocol/ingress.pyi
@@ -1,4 +1,5 @@
from . import models as _models
+from .logger_pb import options as _options_pb2
from google.protobuf.internal import containers as _containers
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
from google.protobuf import descriptor as _descriptor
@@ -47,7 +48,7 @@ H264_720P_30FPS_1_LAYER_HIGH_MOTION: IngressVideoEncodingPreset
H264_1080P_30FPS_1_LAYER_HIGH_MOTION: IngressVideoEncodingPreset
class CreateIngressRequest(_message.Message):
- __slots__ = ("input_type", "url", "name", "room_name", "participant_identity", "participant_name", "participant_metadata", "bypass_transcoding", "enable_transcoding", "audio", "video")
+ __slots__ = ("input_type", "url", "name", "room_name", "participant_identity", "participant_name", "participant_metadata", "bypass_transcoding", "enable_transcoding", "audio", "video", "enabled")
INPUT_TYPE_FIELD_NUMBER: _ClassVar[int]
URL_FIELD_NUMBER: _ClassVar[int]
NAME_FIELD_NUMBER: _ClassVar[int]
@@ -59,6 +60,7 @@ class CreateIngressRequest(_message.Message):
ENABLE_TRANSCODING_FIELD_NUMBER: _ClassVar[int]
AUDIO_FIELD_NUMBER: _ClassVar[int]
VIDEO_FIELD_NUMBER: _ClassVar[int]
+ ENABLED_FIELD_NUMBER: _ClassVar[int]
input_type: IngressInput
url: str
name: str
@@ -70,7 +72,8 @@ class CreateIngressRequest(_message.Message):
enable_transcoding: bool
audio: IngressAudioOptions
video: IngressVideoOptions
- def __init__(self, input_type: _Optional[_Union[IngressInput, str]] = ..., url: _Optional[str] = ..., name: _Optional[str] = ..., room_name: _Optional[str] = ..., participant_identity: _Optional[str] = ..., participant_name: _Optional[str] = ..., participant_metadata: _Optional[str] = ..., bypass_transcoding: bool = ..., enable_transcoding: bool = ..., audio: _Optional[_Union[IngressAudioOptions, _Mapping]] = ..., video: _Optional[_Union[IngressVideoOptions, _Mapping]] = ...) -> None: ...
+ enabled: bool
+ def __init__(self, input_type: _Optional[_Union[IngressInput, str]] = ..., url: _Optional[str] = ..., name: _Optional[str] = ..., room_name: _Optional[str] = ..., participant_identity: _Optional[str] = ..., participant_name: _Optional[str] = ..., participant_metadata: _Optional[str] = ..., bypass_transcoding: bool = ..., enable_transcoding: bool = ..., audio: _Optional[_Union[IngressAudioOptions, _Mapping]] = ..., video: _Optional[_Union[IngressVideoOptions, _Mapping]] = ..., enabled: bool = ...) -> None: ...
class IngressAudioOptions(_message.Message):
__slots__ = ("name", "source", "preset", "options")
@@ -119,7 +122,7 @@ class IngressVideoEncodingOptions(_message.Message):
def __init__(self, video_codec: _Optional[_Union[_models.VideoCodec, str]] = ..., frame_rate: _Optional[float] = ..., layers: _Optional[_Iterable[_Union[_models.VideoLayer, _Mapping]]] = ...) -> None: ...
class IngressInfo(_message.Message):
- __slots__ = ("ingress_id", "name", "stream_key", "url", "input_type", "bypass_transcoding", "enable_transcoding", "audio", "video", "room_name", "participant_identity", "participant_name", "participant_metadata", "reusable", "state")
+ __slots__ = ("ingress_id", "name", "stream_key", "url", "input_type", "bypass_transcoding", "enable_transcoding", "audio", "video", "room_name", "participant_identity", "participant_name", "participant_metadata", "reusable", "state", "enabled")
INGRESS_ID_FIELD_NUMBER: _ClassVar[int]
NAME_FIELD_NUMBER: _ClassVar[int]
STREAM_KEY_FIELD_NUMBER: _ClassVar[int]
@@ -135,6 +138,7 @@ class IngressInfo(_message.Message):
PARTICIPANT_METADATA_FIELD_NUMBER: _ClassVar[int]
REUSABLE_FIELD_NUMBER: _ClassVar[int]
STATE_FIELD_NUMBER: _ClassVar[int]
+ ENABLED_FIELD_NUMBER: _ClassVar[int]
ingress_id: str
name: str
stream_key: str
@@ -150,7 +154,8 @@ class IngressInfo(_message.Message):
participant_metadata: str
reusable: bool
state: IngressState
- def __init__(self, ingress_id: _Optional[str] = ..., name: _Optional[str] = ..., stream_key: _Optional[str] = ..., url: _Optional[str] = ..., input_type: _Optional[_Union[IngressInput, str]] = ..., bypass_transcoding: bool = ..., enable_transcoding: bool = ..., audio: _Optional[_Union[IngressAudioOptions, _Mapping]] = ..., video: _Optional[_Union[IngressVideoOptions, _Mapping]] = ..., room_name: _Optional[str] = ..., participant_identity: _Optional[str] = ..., participant_name: _Optional[str] = ..., participant_metadata: _Optional[str] = ..., reusable: bool = ..., state: _Optional[_Union[IngressState, _Mapping]] = ...) -> None: ...
+ enabled: bool
+ def __init__(self, ingress_id: _Optional[str] = ..., name: _Optional[str] = ..., stream_key: _Optional[str] = ..., url: _Optional[str] = ..., input_type: _Optional[_Union[IngressInput, str]] = ..., bypass_transcoding: bool = ..., enable_transcoding: bool = ..., audio: _Optional[_Union[IngressAudioOptions, _Mapping]] = ..., video: _Optional[_Union[IngressVideoOptions, _Mapping]] = ..., room_name: _Optional[str] = ..., participant_identity: _Optional[str] = ..., participant_name: _Optional[str] = ..., participant_metadata: _Optional[str] = ..., reusable: bool = ..., state: _Optional[_Union[IngressState, _Mapping]] = ..., enabled: bool = ...) -> None: ...
class IngressState(_message.Message):
__slots__ = ("status", "error", "video", "audio", "room_id", "started_at", "ended_at", "updated_at", "resource_id", "tracks")
@@ -215,7 +220,7 @@ class InputAudioState(_message.Message):
def __init__(self, mime_type: _Optional[str] = ..., average_bitrate: _Optional[int] = ..., channels: _Optional[int] = ..., sample_rate: _Optional[int] = ...) -> None: ...
class UpdateIngressRequest(_message.Message):
- __slots__ = ("ingress_id", "name", "room_name", "participant_identity", "participant_name", "participant_metadata", "bypass_transcoding", "enable_transcoding", "audio", "video")
+ __slots__ = ("ingress_id", "name", "room_name", "participant_identity", "participant_name", "participant_metadata", "bypass_transcoding", "enable_transcoding", "audio", "video", "enabled")
INGRESS_ID_FIELD_NUMBER: _ClassVar[int]
NAME_FIELD_NUMBER: _ClassVar[int]
ROOM_NAME_FIELD_NUMBER: _ClassVar[int]
@@ -226,6 +231,7 @@ class UpdateIngressRequest(_message.Message):
ENABLE_TRANSCODING_FIELD_NUMBER: _ClassVar[int]
AUDIO_FIELD_NUMBER: _ClassVar[int]
VIDEO_FIELD_NUMBER: _ClassVar[int]
+ ENABLED_FIELD_NUMBER: _ClassVar[int]
ingress_id: str
name: str
room_name: str
@@ -236,21 +242,26 @@ class UpdateIngressRequest(_message.Message):
enable_transcoding: bool
audio: IngressAudioOptions
video: IngressVideoOptions
- def __init__(self, ingress_id: _Optional[str] = ..., name: _Optional[str] = ..., room_name: _Optional[str] = ..., participant_identity: _Optional[str] = ..., participant_name: _Optional[str] = ..., participant_metadata: _Optional[str] = ..., bypass_transcoding: bool = ..., enable_transcoding: bool = ..., audio: _Optional[_Union[IngressAudioOptions, _Mapping]] = ..., video: _Optional[_Union[IngressVideoOptions, _Mapping]] = ...) -> None: ...
+ enabled: bool
+ def __init__(self, ingress_id: _Optional[str] = ..., name: _Optional[str] = ..., room_name: _Optional[str] = ..., participant_identity: _Optional[str] = ..., participant_name: _Optional[str] = ..., participant_metadata: _Optional[str] = ..., bypass_transcoding: bool = ..., enable_transcoding: bool = ..., audio: _Optional[_Union[IngressAudioOptions, _Mapping]] = ..., video: _Optional[_Union[IngressVideoOptions, _Mapping]] = ..., enabled: bool = ...) -> None: ...
class ListIngressRequest(_message.Message):
- __slots__ = ("room_name", "ingress_id")
+ __slots__ = ("page_token", "room_name", "ingress_id")
+ PAGE_TOKEN_FIELD_NUMBER: _ClassVar[int]
ROOM_NAME_FIELD_NUMBER: _ClassVar[int]
INGRESS_ID_FIELD_NUMBER: _ClassVar[int]
+ page_token: _models.TokenPagination
room_name: str
ingress_id: str
- def __init__(self, room_name: _Optional[str] = ..., ingress_id: _Optional[str] = ...) -> None: ...
+ def __init__(self, page_token: _Optional[_Union[_models.TokenPagination, _Mapping]] = ..., room_name: _Optional[str] = ..., ingress_id: _Optional[str] = ...) -> None: ...
class ListIngressResponse(_message.Message):
- __slots__ = ("items",)
+ __slots__ = ("next_page_token", "items")
+ NEXT_PAGE_TOKEN_FIELD_NUMBER: _ClassVar[int]
ITEMS_FIELD_NUMBER: _ClassVar[int]
+ next_page_token: _models.TokenPagination
items: _containers.RepeatedCompositeFieldContainer[IngressInfo]
- def __init__(self, items: _Optional[_Iterable[_Union[IngressInfo, _Mapping]]] = ...) -> None: ...
+ def __init__(self, next_page_token: _Optional[_Union[_models.TokenPagination, _Mapping]] = ..., items: _Optional[_Iterable[_Union[IngressInfo, _Mapping]]] = ...) -> None: ...
class DeleteIngressRequest(_message.Message):
__slots__ = ("ingress_id",)
diff --git a/livekit-protocol/livekit/protocol/logger_pb/__init__.py b/livekit-protocol/livekit/protocol/logger_pb/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/livekit-protocol/livekit/protocol/logger_pb/options.py b/livekit-protocol/livekit/protocol/logger_pb/options.py
new file mode 100644
index 00000000..c83ad645
--- /dev/null
+++ b/livekit-protocol/livekit/protocol/logger_pb/options.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: logger/options.proto
+# Protobuf Python Version: 4.25.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from google.protobuf import descriptor_pb2 as google_dot_protobuf_dot_descriptor__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x14logger/options.proto\x12\x06logger\x1a google/protobuf/descriptor.proto:.\n\x06redact\x12\x1d.google.protobuf.FieldOptions\x18\x85\n \x01(\x08:5\n\rredact_format\x12\x1d.google.protobuf.FieldOptions\x18\x86\n \x01(\t:,\n\x04name\x12\x1d.google.protobuf.FieldOptions\x18\x87\n \x01(\tBMZ*github.com/livekit/protocol/livekit/logger\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'logger.options_pb2', _globals)
+if _descriptor._USE_C_DESCRIPTORS == False:
+ _globals['DESCRIPTOR']._options = None
+ _globals['DESCRIPTOR']._serialized_options = b'Z*github.com/livekit/protocol/livekit/logger\252\002\rLiveKit.Proto\352\002\016LiveKit::Proto'
+# @@protoc_insertion_point(module_scope)
diff --git a/livekit-protocol/livekit/protocol/logger_pb/options.pyi b/livekit-protocol/livekit/protocol/logger_pb/options.pyi
new file mode 100644
index 00000000..3c7f24ec
--- /dev/null
+++ b/livekit-protocol/livekit/protocol/logger_pb/options.pyi
@@ -0,0 +1,11 @@
+from google.protobuf import descriptor_pb2 as _descriptor_pb2
+from google.protobuf import descriptor as _descriptor
+from typing import ClassVar as _ClassVar
+
+DESCRIPTOR: _descriptor.FileDescriptor
+REDACT_FIELD_NUMBER: int
+redact: _descriptor.FieldDescriptor
+REDACT_FORMAT_FIELD_NUMBER: int
+redact_format: _descriptor.FieldDescriptor
+NAME_FIELD_NUMBER: int
+name: _descriptor.FieldDescriptor
diff --git a/livekit-protocol/livekit/protocol/metrics.py b/livekit-protocol/livekit/protocol/metrics.py
new file mode 100644
index 00000000..8ba9ce02
--- /dev/null
+++ b/livekit-protocol/livekit/protocol/metrics.py
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: livekit_metrics.proto
+# Protobuf Python Version: 4.25.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
+from .logger_pb import options as logger_dot_options__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15livekit_metrics.proto\x12\x07livekit\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x14logger/options.proto\"\xc6\x01\n\x0cMetricsBatch\x12\x14\n\x0ctimestamp_ms\x18\x01 \x01(\x03\x12\x38\n\x14normalized_timestamp\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x10\n\x08str_data\x18\x03 \x03(\t\x12.\n\x0btime_series\x18\x04 \x03(\x0b\x32\x19.livekit.TimeSeriesMetric\x12$\n\x06\x65vents\x18\x05 \x03(\x0b\x32\x14.livekit.EventMetric\"\x87\x01\n\x10TimeSeriesMetric\x12\r\n\x05label\x18\x01 \x01(\r\x12\x1c\n\x14participant_identity\x18\x02 \x01(\r\x12\x11\n\ttrack_sid\x18\x03 \x01(\r\x12&\n\x07samples\x18\x04 \x03(\x0b\x32\x15.livekit.MetricSample\x12\x0b\n\x03rid\x18\x05 \x01(\r\"m\n\x0cMetricSample\x12\x14\n\x0ctimestamp_ms\x18\x01 \x01(\x03\x12\x38\n\x14normalized_timestamp\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\r\n\x05value\x18\x03 \x01(\x02\"\xdc\x02\n\x0b\x45ventMetric\x12\r\n\x05label\x18\x01 \x01(\r\x12\x1c\n\x14participant_identity\x18\x02 \x01(\r\x12\x11\n\ttrack_sid\x18\x03 \x01(\r\x12\x1a\n\x12start_timestamp_ms\x18\x04 \x01(\x03\x12\x1d\n\x10\x65nd_timestamp_ms\x18\x05 \x01(\x03H\x00\x88\x01\x01\x12>\n\x1anormalized_start_timestamp\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x41\n\x18normalized_end_timestamp\x18\x07 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x01\x88\x01\x01\x12\x10\n\x08metadata\x18\x08 \x01(\t\x12\x0b\n\x03rid\x18\t \x01(\rB\x13\n\x11_end_timestamp_msB\x1b\n\x19_normalized_end_timestamp\"\xb1\x02\n\x16MetricsRecordingHeader\x12\x1a\n\x07room_id\x18\x01 \x01(\tB\t\xbaP\x06roomID\x12\x10\n\x08\x64uration\x18\x03 \x01(\x04\x12.\n\nstart_time\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12@\n\troom_tags\x18\x05 \x03(\x0b\x32-.livekit.MetricsRecordingHeader.RoomTagsEntry\x12\x11\n\troom_name\x18\x06 \x01(\t\x12\x33\n\x0froom_start_time\x18\x07 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x1a/\n\rRoomTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01*\x81\x07\n\x0bMetricLabel\x12\x13\n\x0f\x41GENTS_LLM_TTFT\x10\x00\x12\x13\n\x0f\x41GENTS_STT_TTFT\x10\x01\x12\x13\n\x0f\x41GENTS_TTS_TTFB\x10\x02\x12(\n$CLIENT_VIDEO_SUBSCRIBER_FREEZE_COUNT\x10\x03\x12\x31\n-CLIENT_VIDEO_SUBSCRIBER_TOTAL_FREEZE_DURATION\x10\x04\x12\'\n#CLIENT_VIDEO_SUBSCRIBER_PAUSE_COUNT\x10\x05\x12\x31\n-CLIENT_VIDEO_SUBSCRIBER_TOTAL_PAUSES_DURATION\x10\x06\x12-\n)CLIENT_AUDIO_SUBSCRIBER_CONCEALED_SAMPLES\x10\x07\x12\x34\n0CLIENT_AUDIO_SUBSCRIBER_SILENT_CONCEALED_SAMPLES\x10\x08\x12.\n*CLIENT_AUDIO_SUBSCRIBER_CONCEALMENT_EVENTS\x10\t\x12.\n*CLIENT_AUDIO_SUBSCRIBER_INTERRUPTION_COUNT\x10\n\x12\x37\n3CLIENT_AUDIO_SUBSCRIBER_TOTAL_INTERRUPTION_DURATION\x10\x0b\x12)\n%CLIENT_SUBSCRIBER_JITTER_BUFFER_DELAY\x10\x0c\x12\x31\n-CLIENT_SUBSCRIBER_JITTER_BUFFER_EMITTED_COUNT\x10\r\x12@\n None: ...
+
+class TimeSeriesMetric(_message.Message):
+ __slots__ = ("label", "participant_identity", "track_sid", "samples", "rid")
+ LABEL_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: _ClassVar[int]
+ TRACK_SID_FIELD_NUMBER: _ClassVar[int]
+ SAMPLES_FIELD_NUMBER: _ClassVar[int]
+ RID_FIELD_NUMBER: _ClassVar[int]
+ label: int
+ participant_identity: int
+ track_sid: int
+ samples: _containers.RepeatedCompositeFieldContainer[MetricSample]
+ rid: int
+ def __init__(self, label: _Optional[int] = ..., participant_identity: _Optional[int] = ..., track_sid: _Optional[int] = ..., samples: _Optional[_Iterable[_Union[MetricSample, _Mapping]]] = ..., rid: _Optional[int] = ...) -> None: ...
+
+class MetricSample(_message.Message):
+ __slots__ = ("timestamp_ms", "normalized_timestamp", "value")
+ TIMESTAMP_MS_FIELD_NUMBER: _ClassVar[int]
+ NORMALIZED_TIMESTAMP_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ timestamp_ms: int
+ normalized_timestamp: _timestamp_pb2.Timestamp
+ value: float
+ def __init__(self, timestamp_ms: _Optional[int] = ..., normalized_timestamp: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., value: _Optional[float] = ...) -> None: ...
+
+class EventMetric(_message.Message):
+ __slots__ = ("label", "participant_identity", "track_sid", "start_timestamp_ms", "end_timestamp_ms", "normalized_start_timestamp", "normalized_end_timestamp", "metadata", "rid")
+ LABEL_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: _ClassVar[int]
+ TRACK_SID_FIELD_NUMBER: _ClassVar[int]
+ START_TIMESTAMP_MS_FIELD_NUMBER: _ClassVar[int]
+ END_TIMESTAMP_MS_FIELD_NUMBER: _ClassVar[int]
+ NORMALIZED_START_TIMESTAMP_FIELD_NUMBER: _ClassVar[int]
+ NORMALIZED_END_TIMESTAMP_FIELD_NUMBER: _ClassVar[int]
+ METADATA_FIELD_NUMBER: _ClassVar[int]
+ RID_FIELD_NUMBER: _ClassVar[int]
+ label: int
+ participant_identity: int
+ track_sid: int
+ start_timestamp_ms: int
+ end_timestamp_ms: int
+ normalized_start_timestamp: _timestamp_pb2.Timestamp
+ normalized_end_timestamp: _timestamp_pb2.Timestamp
+ metadata: str
+ rid: int
+ def __init__(self, label: _Optional[int] = ..., participant_identity: _Optional[int] = ..., track_sid: _Optional[int] = ..., start_timestamp_ms: _Optional[int] = ..., end_timestamp_ms: _Optional[int] = ..., normalized_start_timestamp: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., normalized_end_timestamp: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., metadata: _Optional[str] = ..., rid: _Optional[int] = ...) -> None: ...
+
+class MetricsRecordingHeader(_message.Message):
+ __slots__ = ("room_id", "duration", "start_time", "room_tags", "room_name", "room_start_time")
+ class RoomTagsEntry(_message.Message):
+ __slots__ = ("key", "value")
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: str
+ value: str
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
+ ROOM_ID_FIELD_NUMBER: _ClassVar[int]
+ DURATION_FIELD_NUMBER: _ClassVar[int]
+ START_TIME_FIELD_NUMBER: _ClassVar[int]
+ ROOM_TAGS_FIELD_NUMBER: _ClassVar[int]
+ ROOM_NAME_FIELD_NUMBER: _ClassVar[int]
+ ROOM_START_TIME_FIELD_NUMBER: _ClassVar[int]
+ room_id: str
+ duration: int
+ start_time: _timestamp_pb2.Timestamp
+ room_tags: _containers.ScalarMap[str, str]
+ room_name: str
+ room_start_time: _timestamp_pb2.Timestamp
+ def __init__(self, room_id: _Optional[str] = ..., duration: _Optional[int] = ..., start_time: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., room_tags: _Optional[_Mapping[str, str]] = ..., room_name: _Optional[str] = ..., room_start_time: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ...) -> None: ...
diff --git a/livekit-protocol/livekit/protocol/models.py b/livekit-protocol/livekit/protocol/models.py
index 16037c31..71eb11c8 100644
--- a/livekit-protocol/livekit/protocol/models.py
+++ b/livekit-protocol/livekit/protocol/models.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: livekit_models.proto
-# Protobuf Python Version: 4.25.3
+# Protobuf Python Version: 4.25.1
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
@@ -13,9 +13,11 @@
from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
+from . import metrics as _metrics_
+from .logger_pb import options as logger_dot_options__pb2
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x14livekit_models.proto\x12\x07livekit\x1a\x1fgoogle/protobuf/timestamp.proto\"\xc9\x02\n\x04Room\x12\x0b\n\x03sid\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x15\n\rempty_timeout\x18\x03 \x01(\r\x12\x19\n\x11\x64\x65parture_timeout\x18\x0e \x01(\r\x12\x18\n\x10max_participants\x18\x04 \x01(\r\x12\x15\n\rcreation_time\x18\x05 \x01(\x03\x12\x15\n\rturn_password\x18\x06 \x01(\t\x12&\n\x0e\x65nabled_codecs\x18\x07 \x03(\x0b\x32\x0e.livekit.Codec\x12\x10\n\x08metadata\x18\x08 \x01(\t\x12\x18\n\x10num_participants\x18\t \x01(\r\x12\x16\n\x0enum_publishers\x18\x0b \x01(\r\x12\x18\n\x10\x61\x63tive_recording\x18\n \x01(\x08\x12&\n\x07version\x18\r \x01(\x0b\x32\x15.livekit.TimedVersion\"(\n\x05\x43odec\x12\x0c\n\x04mime\x18\x01 \x01(\t\x12\x11\n\tfmtp_line\x18\x02 \x01(\t\"9\n\x0cPlayoutDelay\x12\x0f\n\x07\x65nabled\x18\x01 \x01(\x08\x12\x0b\n\x03min\x18\x02 \x01(\r\x12\x0b\n\x03max\x18\x03 \x01(\r\"\xe6\x01\n\x15ParticipantPermission\x12\x15\n\rcan_subscribe\x18\x01 \x01(\x08\x12\x13\n\x0b\x63\x61n_publish\x18\x02 \x01(\x08\x12\x18\n\x10\x63\x61n_publish_data\x18\x03 \x01(\x08\x12\x31\n\x13\x63\x61n_publish_sources\x18\t \x03(\x0e\x32\x14.livekit.TrackSource\x12\x0e\n\x06hidden\x18\x07 \x01(\x08\x12\x14\n\x08recorder\x18\x08 \x01(\x08\x42\x02\x18\x01\x12\x1b\n\x13\x63\x61n_update_metadata\x18\n \x01(\x08\x12\x11\n\x05\x61gent\x18\x0b \x01(\x08\x42\x02\x18\x01\"\xc2\x04\n\x0fParticipantInfo\x12\x0b\n\x03sid\x18\x01 \x01(\t\x12\x10\n\x08identity\x18\x02 \x01(\t\x12-\n\x05state\x18\x03 \x01(\x0e\x32\x1e.livekit.ParticipantInfo.State\x12\"\n\x06tracks\x18\x04 \x03(\x0b\x32\x12.livekit.TrackInfo\x12\x10\n\x08metadata\x18\x05 \x01(\t\x12\x11\n\tjoined_at\x18\x06 \x01(\x03\x12\x0c\n\x04name\x18\t \x01(\t\x12\x0f\n\x07version\x18\n \x01(\r\x12\x32\n\npermission\x18\x0b \x01(\x0b\x32\x1e.livekit.ParticipantPermission\x12\x0e\n\x06region\x18\x0c \x01(\t\x12\x14\n\x0cis_publisher\x18\r \x01(\x08\x12+\n\x04kind\x18\x0e \x01(\x0e\x32\x1d.livekit.ParticipantInfo.Kind\x12<\n\nattributes\x18\x0f \x03(\x0b\x32(.livekit.ParticipantInfo.AttributesEntry\x1a\x31\n\x0f\x41ttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\">\n\x05State\x12\x0b\n\x07JOINING\x10\x00\x12\n\n\x06JOINED\x10\x01\x12\n\n\x06\x41\x43TIVE\x10\x02\x12\x10\n\x0c\x44ISCONNECTED\x10\x03\"A\n\x04Kind\x12\x0c\n\x08STANDARD\x10\x00\x12\x0b\n\x07INGRESS\x10\x01\x12\n\n\x06\x45GRESS\x10\x02\x12\x07\n\x03SIP\x10\x03\x12\t\n\x05\x41GENT\x10\x04\"3\n\nEncryption\"%\n\x04Type\x12\x08\n\x04NONE\x10\x00\x12\x07\n\x03GCM\x10\x01\x12\n\n\x06\x43USTOM\x10\x02\"f\n\x12SimulcastCodecInfo\x12\x11\n\tmime_type\x18\x01 \x01(\t\x12\x0b\n\x03mid\x18\x02 \x01(\t\x12\x0b\n\x03\x63id\x18\x03 \x01(\t\x12#\n\x06layers\x18\x04 \x03(\x0b\x32\x13.livekit.VideoLayer\"\xf5\x03\n\tTrackInfo\x12\x0b\n\x03sid\x18\x01 \x01(\t\x12 \n\x04type\x18\x02 \x01(\x0e\x32\x12.livekit.TrackType\x12\x0c\n\x04name\x18\x03 \x01(\t\x12\r\n\x05muted\x18\x04 \x01(\x08\x12\r\n\x05width\x18\x05 \x01(\r\x12\x0e\n\x06height\x18\x06 \x01(\r\x12\x11\n\tsimulcast\x18\x07 \x01(\x08\x12\x13\n\x0b\x64isable_dtx\x18\x08 \x01(\x08\x12$\n\x06source\x18\t \x01(\x0e\x32\x14.livekit.TrackSource\x12#\n\x06layers\x18\n \x03(\x0b\x32\x13.livekit.VideoLayer\x12\x11\n\tmime_type\x18\x0b \x01(\t\x12\x0b\n\x03mid\x18\x0c \x01(\t\x12+\n\x06\x63odecs\x18\r \x03(\x0b\x32\x1b.livekit.SimulcastCodecInfo\x12\x0e\n\x06stereo\x18\x0e \x01(\x08\x12\x13\n\x0b\x64isable_red\x18\x0f \x01(\x08\x12,\n\nencryption\x18\x10 \x01(\x0e\x32\x18.livekit.Encryption.Type\x12\x0e\n\x06stream\x18\x11 \x01(\t\x12&\n\x07version\x18\x12 \x01(\x0b\x32\x15.livekit.TimedVersion\x12\x32\n\x0e\x61udio_features\x18\x13 \x03(\x0e\x32\x1a.livekit.AudioTrackFeature\"r\n\nVideoLayer\x12&\n\x07quality\x18\x01 \x01(\x0e\x32\x15.livekit.VideoQuality\x12\r\n\x05width\x18\x02 \x01(\r\x12\x0e\n\x06height\x18\x03 \x01(\r\x12\x0f\n\x07\x62itrate\x18\x04 \x01(\r\x12\x0c\n\x04ssrc\x18\x05 \x01(\r\"\xd1\x02\n\nDataPacket\x12*\n\x04kind\x18\x01 \x01(\x0e\x32\x18.livekit.DataPacket.KindB\x02\x18\x01\x12\x1c\n\x14participant_identity\x18\x04 \x01(\t\x12\x1e\n\x16\x64\x65stination_identities\x18\x05 \x03(\t\x12#\n\x04user\x18\x02 \x01(\x0b\x32\x13.livekit.UserPacketH\x00\x12\x33\n\x07speaker\x18\x03 \x01(\x0b\x32\x1c.livekit.ActiveSpeakerUpdateB\x02\x18\x01H\x00\x12$\n\x08sip_dtmf\x18\x06 \x01(\x0b\x32\x10.livekit.SipDTMFH\x00\x12/\n\rtranscription\x18\x07 \x01(\x0b\x32\x16.livekit.TranscriptionH\x00\"\x1f\n\x04Kind\x12\x0c\n\x08RELIABLE\x10\x00\x12\t\n\x05LOSSY\x10\x01\x42\x07\n\x05value\"=\n\x13\x41\x63tiveSpeakerUpdate\x12&\n\x08speakers\x18\x01 \x03(\x0b\x32\x14.livekit.SpeakerInfo\"9\n\x0bSpeakerInfo\x12\x0b\n\x03sid\x18\x01 \x01(\t\x12\r\n\x05level\x18\x02 \x01(\x02\x12\x0e\n\x06\x61\x63tive\x18\x03 \x01(\x08\"\xa0\x02\n\nUserPacket\x12\x1b\n\x0fparticipant_sid\x18\x01 \x01(\tB\x02\x18\x01\x12 \n\x14participant_identity\x18\x05 \x01(\tB\x02\x18\x01\x12\x0f\n\x07payload\x18\x02 \x01(\x0c\x12\x1c\n\x10\x64\x65stination_sids\x18\x03 \x03(\tB\x02\x18\x01\x12\"\n\x16\x64\x65stination_identities\x18\x06 \x03(\tB\x02\x18\x01\x12\x12\n\x05topic\x18\x04 \x01(\tH\x00\x88\x01\x01\x12\x0f\n\x02id\x18\x08 \x01(\tH\x01\x88\x01\x01\x12\x17\n\nstart_time\x18\t \x01(\x04H\x02\x88\x01\x01\x12\x15\n\x08\x65nd_time\x18\n \x01(\x04H\x03\x88\x01\x01\x42\x08\n\x06_topicB\x05\n\x03_idB\r\n\x0b_start_timeB\x0b\n\t_end_time\"&\n\x07SipDTMF\x12\x0c\n\x04\x63ode\x18\x03 \x01(\r\x12\r\n\x05\x64igit\x18\x04 \x01(\t\"|\n\rTranscription\x12(\n transcribed_participant_identity\x18\x02 \x01(\t\x12\x10\n\x08track_id\x18\x03 \x01(\t\x12/\n\x08segments\x18\x04 \x03(\x0b\x32\x1d.livekit.TranscriptionSegment\"w\n\x14TranscriptionSegment\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04text\x18\x02 \x01(\t\x12\x12\n\nstart_time\x18\x03 \x01(\x04\x12\x10\n\x08\x65nd_time\x18\x04 \x01(\x04\x12\r\n\x05\x66inal\x18\x05 \x01(\x08\x12\x10\n\x08language\x18\x06 \x01(\t\"@\n\x11ParticipantTracks\x12\x17\n\x0fparticipant_sid\x18\x01 \x01(\t\x12\x12\n\ntrack_sids\x18\x02 \x03(\t\"\xce\x01\n\nServerInfo\x12,\n\x07\x65\x64ition\x18\x01 \x01(\x0e\x32\x1b.livekit.ServerInfo.Edition\x12\x0f\n\x07version\x18\x02 \x01(\t\x12\x10\n\x08protocol\x18\x03 \x01(\x05\x12\x0e\n\x06region\x18\x04 \x01(\t\x12\x0f\n\x07node_id\x18\x05 \x01(\t\x12\x12\n\ndebug_info\x18\x06 \x01(\t\x12\x16\n\x0e\x61gent_protocol\x18\x07 \x01(\x05\"\"\n\x07\x45\x64ition\x12\x0c\n\x08Standard\x10\x00\x12\t\n\x05\x43loud\x10\x01\"\xdd\x02\n\nClientInfo\x12$\n\x03sdk\x18\x01 \x01(\x0e\x32\x17.livekit.ClientInfo.SDK\x12\x0f\n\x07version\x18\x02 \x01(\t\x12\x10\n\x08protocol\x18\x03 \x01(\x05\x12\n\n\x02os\x18\x04 \x01(\t\x12\x12\n\nos_version\x18\x05 \x01(\t\x12\x14\n\x0c\x64\x65vice_model\x18\x06 \x01(\t\x12\x0f\n\x07\x62rowser\x18\x07 \x01(\t\x12\x17\n\x0f\x62rowser_version\x18\x08 \x01(\t\x12\x0f\n\x07\x61\x64\x64ress\x18\t \x01(\t\x12\x0f\n\x07network\x18\n \x01(\t\"\x83\x01\n\x03SDK\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x06\n\x02JS\x10\x01\x12\t\n\x05SWIFT\x10\x02\x12\x0b\n\x07\x41NDROID\x10\x03\x12\x0b\n\x07\x46LUTTER\x10\x04\x12\x06\n\x02GO\x10\x05\x12\t\n\x05UNITY\x10\x06\x12\x10\n\x0cREACT_NATIVE\x10\x07\x12\x08\n\x04RUST\x10\x08\x12\n\n\x06PYTHON\x10\t\x12\x07\n\x03\x43PP\x10\n\"\x8c\x02\n\x13\x43lientConfiguration\x12*\n\x05video\x18\x01 \x01(\x0b\x32\x1b.livekit.VideoConfiguration\x12+\n\x06screen\x18\x02 \x01(\x0b\x32\x1b.livekit.VideoConfiguration\x12\x37\n\x11resume_connection\x18\x03 \x01(\x0e\x32\x1c.livekit.ClientConfigSetting\x12\x30\n\x0f\x64isabled_codecs\x18\x04 \x01(\x0b\x32\x17.livekit.DisabledCodecs\x12\x31\n\x0b\x66orce_relay\x18\x05 \x01(\x0e\x32\x1c.livekit.ClientConfigSetting\"L\n\x12VideoConfiguration\x12\x36\n\x10hardware_encoder\x18\x01 \x01(\x0e\x32\x1c.livekit.ClientConfigSetting\"Q\n\x0e\x44isabledCodecs\x12\x1e\n\x06\x63odecs\x18\x01 \x03(\x0b\x32\x0e.livekit.Codec\x12\x1f\n\x07publish\x18\x02 \x03(\x0b\x32\x0e.livekit.Codec\"\x80\x02\n\x08RTPDrift\x12.\n\nstart_time\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12,\n\x08\x65nd_time\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x10\n\x08\x64uration\x18\x03 \x01(\x01\x12\x17\n\x0fstart_timestamp\x18\x04 \x01(\x04\x12\x15\n\rend_timestamp\x18\x05 \x01(\x04\x12\x17\n\x0frtp_clock_ticks\x18\x06 \x01(\x04\x12\x15\n\rdrift_samples\x18\x07 \x01(\x03\x12\x10\n\x08\x64rift_ms\x18\x08 \x01(\x01\x12\x12\n\nclock_rate\x18\t \x01(\x01\"\xa0\n\n\x08RTPStats\x12.\n\nstart_time\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12,\n\x08\x65nd_time\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x10\n\x08\x64uration\x18\x03 \x01(\x01\x12\x0f\n\x07packets\x18\x04 \x01(\r\x12\x13\n\x0bpacket_rate\x18\x05 \x01(\x01\x12\r\n\x05\x62ytes\x18\x06 \x01(\x04\x12\x14\n\x0cheader_bytes\x18\' \x01(\x04\x12\x0f\n\x07\x62itrate\x18\x07 \x01(\x01\x12\x14\n\x0cpackets_lost\x18\x08 \x01(\r\x12\x18\n\x10packet_loss_rate\x18\t \x01(\x01\x12\x1e\n\x16packet_loss_percentage\x18\n \x01(\x02\x12\x19\n\x11packets_duplicate\x18\x0b \x01(\r\x12\x1d\n\x15packet_duplicate_rate\x18\x0c \x01(\x01\x12\x17\n\x0f\x62ytes_duplicate\x18\r \x01(\x04\x12\x1e\n\x16header_bytes_duplicate\x18( \x01(\x04\x12\x19\n\x11\x62itrate_duplicate\x18\x0e \x01(\x01\x12\x17\n\x0fpackets_padding\x18\x0f \x01(\r\x12\x1b\n\x13packet_padding_rate\x18\x10 \x01(\x01\x12\x15\n\rbytes_padding\x18\x11 \x01(\x04\x12\x1c\n\x14header_bytes_padding\x18) \x01(\x04\x12\x17\n\x0f\x62itrate_padding\x18\x12 \x01(\x01\x12\x1c\n\x14packets_out_of_order\x18\x13 \x01(\r\x12\x0e\n\x06\x66rames\x18\x14 \x01(\r\x12\x12\n\nframe_rate\x18\x15 \x01(\x01\x12\x16\n\x0ejitter_current\x18\x16 \x01(\x01\x12\x12\n\njitter_max\x18\x17 \x01(\x01\x12:\n\rgap_histogram\x18\x18 \x03(\x0b\x32#.livekit.RTPStats.GapHistogramEntry\x12\r\n\x05nacks\x18\x19 \x01(\r\x12\x11\n\tnack_acks\x18% \x01(\r\x12\x13\n\x0bnack_misses\x18\x1a \x01(\r\x12\x15\n\rnack_repeated\x18& \x01(\r\x12\x0c\n\x04plis\x18\x1b \x01(\r\x12,\n\x08last_pli\x18\x1c \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x0c\n\x04\x66irs\x18\x1d \x01(\r\x12,\n\x08last_fir\x18\x1e \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x13\n\x0brtt_current\x18\x1f \x01(\r\x12\x0f\n\x07rtt_max\x18 \x01(\r\x12\x12\n\nkey_frames\x18! \x01(\r\x12\x32\n\x0elast_key_frame\x18\" \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x17\n\x0flayer_lock_plis\x18# \x01(\r\x12\x37\n\x13last_layer_lock_pli\x18$ \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\'\n\x0cpacket_drift\x18, \x01(\x0b\x32\x11.livekit.RTPDrift\x12\'\n\x0creport_drift\x18- \x01(\x0b\x32\x11.livekit.RTPDrift\x12/\n\x14rebased_report_drift\x18. \x01(\x0b\x32\x11.livekit.RTPDrift\x1a\x33\n\x11GapHistogramEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\r:\x02\x38\x01\"1\n\x0cTimedVersion\x12\x12\n\nunix_micro\x18\x01 \x01(\x03\x12\r\n\x05ticks\x18\x02 \x01(\x05*/\n\nAudioCodec\x12\x0e\n\nDEFAULT_AC\x10\x00\x12\x08\n\x04OPUS\x10\x01\x12\x07\n\x03\x41\x41\x43\x10\x02*V\n\nVideoCodec\x12\x0e\n\nDEFAULT_VC\x10\x00\x12\x11\n\rH264_BASELINE\x10\x01\x12\r\n\tH264_MAIN\x10\x02\x12\r\n\tH264_HIGH\x10\x03\x12\x07\n\x03VP8\x10\x04*)\n\nImageCodec\x12\x0e\n\nIC_DEFAULT\x10\x00\x12\x0b\n\x07IC_JPEG\x10\x01*+\n\tTrackType\x12\t\n\x05\x41UDIO\x10\x00\x12\t\n\x05VIDEO\x10\x01\x12\x08\n\x04\x44\x41TA\x10\x02*`\n\x0bTrackSource\x12\x0b\n\x07UNKNOWN\x10\x00\x12\n\n\x06\x43\x41MERA\x10\x01\x12\x0e\n\nMICROPHONE\x10\x02\x12\x10\n\x0cSCREEN_SHARE\x10\x03\x12\x16\n\x12SCREEN_SHARE_AUDIO\x10\x04*6\n\x0cVideoQuality\x12\x07\n\x03LOW\x10\x00\x12\n\n\x06MEDIUM\x10\x01\x12\x08\n\x04HIGH\x10\x02\x12\x07\n\x03OFF\x10\x03*@\n\x11\x43onnectionQuality\x12\x08\n\x04POOR\x10\x00\x12\x08\n\x04GOOD\x10\x01\x12\r\n\tEXCELLENT\x10\x02\x12\x08\n\x04LOST\x10\x03*;\n\x13\x43lientConfigSetting\x12\t\n\x05UNSET\x10\x00\x12\x0c\n\x08\x44ISABLED\x10\x01\x12\x0b\n\x07\x45NABLED\x10\x02*\xdb\x01\n\x10\x44isconnectReason\x12\x12\n\x0eUNKNOWN_REASON\x10\x00\x12\x14\n\x10\x43LIENT_INITIATED\x10\x01\x12\x16\n\x12\x44UPLICATE_IDENTITY\x10\x02\x12\x13\n\x0fSERVER_SHUTDOWN\x10\x03\x12\x17\n\x13PARTICIPANT_REMOVED\x10\x04\x12\x10\n\x0cROOM_DELETED\x10\x05\x12\x12\n\x0eSTATE_MISMATCH\x10\x06\x12\x10\n\x0cJOIN_FAILURE\x10\x07\x12\r\n\tMIGRATION\x10\x08\x12\x10\n\x0cSIGNAL_CLOSE\x10\t*\x89\x01\n\x0fReconnectReason\x12\x0e\n\nRR_UNKNOWN\x10\x00\x12\x1a\n\x16RR_SIGNAL_DISCONNECTED\x10\x01\x12\x17\n\x13RR_PUBLISHER_FAILED\x10\x02\x12\x18\n\x14RR_SUBSCRIBER_FAILED\x10\x03\x12\x17\n\x13RR_SWITCH_CANDIDATE\x10\x04*T\n\x11SubscriptionError\x12\x0e\n\nSE_UNKNOWN\x10\x00\x12\x18\n\x14SE_CODEC_UNSUPPORTED\x10\x01\x12\x15\n\x11SE_TRACK_NOTFOUND\x10\x02*\xa3\x01\n\x11\x41udioTrackFeature\x12\r\n\tTF_STEREO\x10\x00\x12\r\n\tTF_NO_DTX\x10\x01\x12\x18\n\x14TF_AUTO_GAIN_CONTROL\x10\x02\x12\x18\n\x14TF_ECHO_CANCELLATION\x10\x03\x12\x18\n\x14TF_NOISE_SUPPRESSION\x10\x04\x12\"\n\x1eTF_ENHANCED_NOISE_CANCELLATION\x10\x05\x42\x46Z#github.com/livekit/protocol/livekit\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x14livekit_models.proto\x12\x07livekit\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x15livekit_metrics.proto\x1a\x14logger/options.proto\"9\n\nPagination\x12\x1c\n\x08\x61\x66ter_id\x18\x01 \x01(\tB\n\xbaP\x07\x61\x66terID\x12\r\n\x05limit\x18\x02 \x01(\x05\" \n\x0fTokenPagination\x12\r\n\x05token\x18\x01 \x01(\t\"E\n\nListUpdate\x12\x0b\n\x03set\x18\x01 \x03(\t\x12\x0b\n\x03\x61\x64\x64\x18\x02 \x03(\t\x12\x0e\n\x06remove\x18\x03 \x03(\t\x12\r\n\x05\x63lear\x18\x04 \x01(\x08\"\x89\x03\n\x04Room\x12\x0b\n\x03sid\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x15\n\rempty_timeout\x18\x03 \x01(\r\x12\x19\n\x11\x64\x65parture_timeout\x18\x0e \x01(\r\x12\x18\n\x10max_participants\x18\x04 \x01(\r\x12\x15\n\rcreation_time\x18\x05 \x01(\x03\x12\x18\n\x10\x63reation_time_ms\x18\x0f \x01(\x03\x12\x15\n\rturn_password\x18\x06 \x01(\t\x12&\n\x0e\x65nabled_codecs\x18\x07 \x03(\x0b\x32\x0e.livekit.Codec\x12\x36\n\x08metadata\x18\x08 \x01(\tB$\xa8P\x01\xb2P\x1e\x12\x18\n\x10num_participants\x18\t \x01(\r\x12\x16\n\x0enum_publishers\x18\x0b \x01(\r\x12\x18\n\x10\x61\x63tive_recording\x18\n \x01(\x08\x12&\n\x07version\x18\r \x01(\x0b\x32\x15.livekit.TimedVersion\"(\n\x05\x43odec\x12\x0c\n\x04mime\x18\x01 \x01(\t\x12\x11\n\tfmtp_line\x18\x02 \x01(\t\"9\n\x0cPlayoutDelay\x12\x0f\n\x07\x65nabled\x18\x01 \x01(\x08\x12\x0b\n\x03min\x18\x02 \x01(\r\x12\x0b\n\x03max\x18\x03 \x01(\r\"\xa7\x02\n\x15ParticipantPermission\x12\x15\n\rcan_subscribe\x18\x01 \x01(\x08\x12\x13\n\x0b\x63\x61n_publish\x18\x02 \x01(\x08\x12\x18\n\x10\x63\x61n_publish_data\x18\x03 \x01(\x08\x12\x31\n\x13\x63\x61n_publish_sources\x18\t \x03(\x0e\x32\x14.livekit.TrackSource\x12\x0e\n\x06hidden\x18\x07 \x01(\x08\x12\x14\n\x08recorder\x18\x08 \x01(\x08\x42\x02\x18\x01\x12\x1b\n\x13\x63\x61n_update_metadata\x18\n \x01(\x08\x12\x11\n\x05\x61gent\x18\x0b \x01(\x08\x42\x02\x18\x01\x12\x1d\n\x15\x63\x61n_subscribe_metrics\x18\x0c \x01(\x08\x12 \n\x18\x63\x61n_manage_agent_session\x18\r \x01(\x08\"\xe8\x07\n\x0fParticipantInfo\x12\x0b\n\x03sid\x18\x01 \x01(\t\x12\x10\n\x08identity\x18\x02 \x01(\t\x12-\n\x05state\x18\x03 \x01(\x0e\x32\x1e.livekit.ParticipantInfo.State\x12\"\n\x06tracks\x18\x04 \x03(\x0b\x32\x12.livekit.TrackInfo\x12\x36\n\x08metadata\x18\x05 \x01(\tB$\xa8P\x01\xb2P\x1e\x12\x11\n\tjoined_at\x18\x06 \x01(\x03\x12\x14\n\x0cjoined_at_ms\x18\x11 \x01(\x03\x12\x11\n\x04name\x18\t \x01(\tB\x03\xa8P\x01\x12\x0f\n\x07version\x18\n \x01(\r\x12\x32\n\npermission\x18\x0b \x01(\x0b\x32\x1e.livekit.ParticipantPermission\x12\x0e\n\x06region\x18\x0c \x01(\t\x12\x14\n\x0cis_publisher\x18\r \x01(\x08\x12+\n\x04kind\x18\x0e \x01(\x0e\x32\x1d.livekit.ParticipantInfo.Kind\x12\x62\n\nattributes\x18\x0f \x03(\x0b\x32(.livekit.ParticipantInfo.AttributesEntryB$\xa8P\x01\xb2P\x1e\x12\x34\n\x11\x64isconnect_reason\x18\x10 \x01(\x0e\x32\x19.livekit.DisconnectReason\x12\x39\n\x0ckind_details\x18\x12 \x03(\x0e\x32#.livekit.ParticipantInfo.KindDetail\x12+\n\x0b\x64\x61ta_tracks\x18\x13 \x03(\x0b\x32\x16.livekit.DataTrackInfo\x12\x17\n\x0f\x63lient_protocol\x18\x14 \x01(\x05\x1a\x31\n\x0f\x41ttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\">\n\x05State\x12\x0b\n\x07JOINING\x10\x00\x12\n\n\x06JOINED\x10\x01\x12\n\n\x06\x41\x43TIVE\x10\x02\x12\x10\n\x0c\x44ISCONNECTED\x10\x03\"\\\n\x04Kind\x12\x0c\n\x08STANDARD\x10\x00\x12\x0b\n\x07INGRESS\x10\x01\x12\n\n\x06\x45GRESS\x10\x02\x12\x07\n\x03SIP\x10\x03\x12\t\n\x05\x41GENT\x10\x04\x12\r\n\tCONNECTOR\x10\x07\x12\n\n\x06\x42RIDGE\x10\x08\"k\n\nKindDetail\x12\x0f\n\x0b\x43LOUD_AGENT\x10\x00\x12\r\n\tFORWARDED\x10\x01\x12\x16\n\x12\x43ONNECTOR_WHATSAPP\x10\x02\x12\x14\n\x10\x43ONNECTOR_TWILIO\x10\x03\x12\x0f\n\x0b\x42RIDGE_RTSP\x10\x04\"3\n\nEncryption\"%\n\x04Type\x12\x08\n\x04NONE\x10\x00\x12\x07\n\x03GCM\x10\x01\x12\n\n\x06\x43USTOM\x10\x02\"\xab\x01\n\x12SimulcastCodecInfo\x12\x11\n\tmime_type\x18\x01 \x01(\t\x12\x0b\n\x03mid\x18\x02 \x01(\t\x12\x0b\n\x03\x63id\x18\x03 \x01(\t\x12#\n\x06layers\x18\x04 \x03(\x0b\x32\x13.livekit.VideoLayer\x12\x32\n\x10video_layer_mode\x18\x05 \x01(\x0e\x32\x18.livekit.VideoLayer.Mode\x12\x0f\n\x07sdp_cid\x18\x06 \x01(\t\"\x83\x05\n\tTrackInfo\x12\x0b\n\x03sid\x18\x01 \x01(\t\x12 \n\x04type\x18\x02 \x01(\x0e\x32\x12.livekit.TrackType\x12\x11\n\x04name\x18\x03 \x01(\tB\x03\xa8P\x01\x12\r\n\x05muted\x18\x04 \x01(\x08\x12\r\n\x05width\x18\x05 \x01(\r\x12\x0e\n\x06height\x18\x06 \x01(\r\x12\x15\n\tsimulcast\x18\x07 \x01(\x08\x42\x02\x18\x01\x12\x17\n\x0b\x64isable_dtx\x18\x08 \x01(\x08\x42\x02\x18\x01\x12$\n\x06source\x18\t \x01(\x0e\x32\x14.livekit.TrackSource\x12\'\n\x06layers\x18\n \x03(\x0b\x32\x13.livekit.VideoLayerB\x02\x18\x01\x12\x11\n\tmime_type\x18\x0b \x01(\t\x12\x0b\n\x03mid\x18\x0c \x01(\t\x12+\n\x06\x63odecs\x18\r \x03(\x0b\x32\x1b.livekit.SimulcastCodecInfo\x12\x12\n\x06stereo\x18\x0e \x01(\x08\x42\x02\x18\x01\x12\x13\n\x0b\x64isable_red\x18\x0f \x01(\x08\x12,\n\nencryption\x18\x10 \x01(\x0e\x32\x18.livekit.Encryption.Type\x12\x0e\n\x06stream\x18\x11 \x01(\t\x12&\n\x07version\x18\x12 \x01(\x0b\x32\x15.livekit.TimedVersion\x12\x32\n\x0e\x61udio_features\x18\x13 \x03(\x0e\x32\x1a.livekit.AudioTrackFeature\x12\x37\n\x13\x62\x61\x63kup_codec_policy\x18\x14 \x01(\x0e\x32\x1a.livekit.BackupCodecPolicy\x12>\n\x17packet_trailer_features\x18\x15 \x03(\x0e\x32\x1d.livekit.PacketTrailerFeature\"l\n\rDataTrackInfo\x12\x12\n\npub_handle\x18\x01 \x01(\r\x12\x0b\n\x03sid\x18\x02 \x01(\t\x12\x0c\n\x04name\x18\x03 \x01(\t\x12,\n\nencryption\x18\x04 \x01(\x0e\x32\x18.livekit.Encryption.Type\"f\n DataTrackExtensionParticipantSid\x12)\n\x02id\x18\x01 \x01(\x0e\x32\x1d.livekit.DataTrackExtensionID\x12\x17\n\x0fparticipant_sid\x18\x02 \x01(\t\"F\n\x1c\x44\x61taTrackSubscriptionOptions\x12\x17\n\ntarget_fps\x18\x01 \x01(\rH\x00\x88\x01\x01\x42\r\n\x0b_target_fps\"\xc4\x02\n\nVideoLayer\x12&\n\x07quality\x18\x01 \x01(\x0e\x32\x15.livekit.VideoQuality\x12\r\n\x05width\x18\x02 \x01(\r\x12\x0e\n\x06height\x18\x03 \x01(\r\x12\x0f\n\x07\x62itrate\x18\x04 \x01(\r\x12\x0c\n\x04ssrc\x18\x05 \x01(\r\x12\x15\n\rspatial_layer\x18\x06 \x01(\x05\x12\x0b\n\x03rid\x18\x07 \x01(\t\x12\x13\n\x0brepair_ssrc\x18\x08 \x01(\r\"\x96\x01\n\x04Mode\x12\x0f\n\x0bMODE_UNUSED\x10\x00\x12 \n\x1cONE_SPATIAL_LAYER_PER_STREAM\x10\x01\x12&\n\"MULTIPLE_SPATIAL_LAYERS_PER_STREAM\x10\x02\x12\x33\n/ONE_SPATIAL_LAYER_PER_STREAM_INCOMPLETE_RTCP_SR\x10\x03\"\xa7\x06\n\nDataPacket\x12*\n\x04kind\x18\x01 \x01(\x0e\x32\x18.livekit.DataPacket.KindB\x02\x18\x01\x12\x1c\n\x14participant_identity\x18\x04 \x01(\t\x12\x1e\n\x16\x64\x65stination_identities\x18\x05 \x03(\t\x12#\n\x04user\x18\x02 \x01(\x0b\x32\x13.livekit.UserPacketH\x00\x12\x33\n\x07speaker\x18\x03 \x01(\x0b\x32\x1c.livekit.ActiveSpeakerUpdateB\x02\x18\x01H\x00\x12$\n\x08sip_dtmf\x18\x06 \x01(\x0b\x32\x10.livekit.SipDTMFH\x00\x12/\n\rtranscription\x18\x07 \x01(\x0b\x32\x16.livekit.TranscriptionH\x00\x12(\n\x07metrics\x18\x08 \x01(\x0b\x32\x15.livekit.MetricsBatchH\x00\x12,\n\x0c\x63hat_message\x18\t \x01(\x0b\x32\x14.livekit.ChatMessageH\x00\x12*\n\x0brpc_request\x18\n \x01(\x0b\x32\x13.livekit.RpcRequestH\x00\x12\"\n\x07rpc_ack\x18\x0b \x01(\x0b\x32\x0f.livekit.RpcAckH\x00\x12,\n\x0crpc_response\x18\x0c \x01(\x0b\x32\x14.livekit.RpcResponseH\x00\x12\x33\n\rstream_header\x18\r \x01(\x0b\x32\x1a.livekit.DataStream.HeaderH\x00\x12\x31\n\x0cstream_chunk\x18\x0e \x01(\x0b\x32\x19.livekit.DataStream.ChunkH\x00\x12\x35\n\x0estream_trailer\x18\x0f \x01(\x0b\x32\x1b.livekit.DataStream.TrailerH\x00\x12\x34\n\x10\x65ncrypted_packet\x18\x12 \x01(\x0b\x32\x18.livekit.EncryptedPacketH\x00\x12\x10\n\x08sequence\x18\x10 \x01(\r\x12\x17\n\x0fparticipant_sid\x18\x11 \x01(\t\"\x1f\n\x04Kind\x12\x0c\n\x08RELIABLE\x10\x00\x12\t\n\x05LOSSY\x10\x01\x42\x07\n\x05value\"|\n\x0f\x45ncryptedPacket\x12\x31\n\x0f\x65ncryption_type\x18\x01 \x01(\x0e\x32\x18.livekit.Encryption.Type\x12\n\n\x02iv\x18\x02 \x01(\x0c\x12\x11\n\tkey_index\x18\x03 \x01(\r\x12\x17\n\x0f\x65ncrypted_value\x18\x04 \x01(\x0c\"\x91\x03\n\x16\x45ncryptedPacketPayload\x12#\n\x04user\x18\x01 \x01(\x0b\x32\x13.livekit.UserPacketH\x00\x12,\n\x0c\x63hat_message\x18\x03 \x01(\x0b\x32\x14.livekit.ChatMessageH\x00\x12*\n\x0brpc_request\x18\x04 \x01(\x0b\x32\x13.livekit.RpcRequestH\x00\x12\"\n\x07rpc_ack\x18\x05 \x01(\x0b\x32\x0f.livekit.RpcAckH\x00\x12,\n\x0crpc_response\x18\x06 \x01(\x0b\x32\x14.livekit.RpcResponseH\x00\x12\x33\n\rstream_header\x18\x07 \x01(\x0b\x32\x1a.livekit.DataStream.HeaderH\x00\x12\x31\n\x0cstream_chunk\x18\x08 \x01(\x0b\x32\x19.livekit.DataStream.ChunkH\x00\x12\x35\n\x0estream_trailer\x18\t \x01(\x0b\x32\x1b.livekit.DataStream.TrailerH\x00\x42\x07\n\x05value\"A\n\x13\x41\x63tiveSpeakerUpdate\x12&\n\x08speakers\x18\x01 \x03(\x0b\x32\x14.livekit.SpeakerInfo:\x02\x18\x01\"9\n\x0bSpeakerInfo\x12\x0b\n\x03sid\x18\x01 \x01(\t\x12\r\n\x05level\x18\x02 \x01(\x02\x12\x0e\n\x06\x61\x63tive\x18\x03 \x01(\x08\"\xaf\x02\n\nUserPacket\x12\x1b\n\x0fparticipant_sid\x18\x01 \x01(\tB\x02\x18\x01\x12 \n\x14participant_identity\x18\x05 \x01(\tB\x02\x18\x01\x12\x0f\n\x07payload\x18\x02 \x01(\x0c\x12\x1c\n\x10\x64\x65stination_sids\x18\x03 \x03(\tB\x02\x18\x01\x12\"\n\x16\x64\x65stination_identities\x18\x06 \x03(\tB\x02\x18\x01\x12\x12\n\x05topic\x18\x04 \x01(\tH\x00\x88\x01\x01\x12\x0f\n\x02id\x18\x08 \x01(\tH\x01\x88\x01\x01\x12\x17\n\nstart_time\x18\t \x01(\x04H\x02\x88\x01\x01\x12\x15\n\x08\x65nd_time\x18\n \x01(\x04H\x03\x88\x01\x01\x12\r\n\x05nonce\x18\x0b \x01(\x0c\x42\x08\n\x06_topicB\x05\n\x03_idB\r\n\x0b_start_timeB\x0b\n\t_end_time\"&\n\x07SipDTMF\x12\x0c\n\x04\x63ode\x18\x03 \x01(\r\x12\r\n\x05\x64igit\x18\x04 \x01(\t\"\x88\x01\n\rTranscription\x12(\n transcribed_participant_identity\x18\x02 \x01(\t\x12\x1c\n\x08track_id\x18\x03 \x01(\tB\n\xbaP\x07trackID\x12/\n\x08segments\x18\x04 \x03(\x0b\x32\x1d.livekit.TranscriptionSegment\"w\n\x14TranscriptionSegment\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04text\x18\x02 \x01(\t\x12\x12\n\nstart_time\x18\x03 \x01(\x04\x12\x10\n\x08\x65nd_time\x18\x04 \x01(\x04\x12\r\n\x05\x66inal\x18\x05 \x01(\x08\x12\x10\n\x08language\x18\x06 \x01(\t\"\x91\x01\n\x0b\x43hatMessage\x12\n\n\x02id\x18\x01 \x01(\t\x12\x11\n\ttimestamp\x18\x02 \x01(\x03\x12\x1b\n\x0e\x65\x64it_timestamp\x18\x03 \x01(\x03H\x00\x88\x01\x01\x12\x0f\n\x07message\x18\x04 \x01(\t\x12\x0f\n\x07\x64\x65leted\x18\x05 \x01(\x08\x12\x11\n\tgenerated\x18\x06 \x01(\x08\x42\x11\n\x0f_edit_timestamp\"\x83\x01\n\nRpcRequest\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0e\n\x06method\x18\x02 \x01(\t\x12\x0f\n\x07payload\x18\x03 \x01(\t\x12\x1b\n\x13response_timeout_ms\x18\x04 \x01(\r\x12\x0f\n\x07version\x18\x05 \x01(\r\x12\x1a\n\x12\x63ompressed_payload\x18\x06 \x01(\x0c\"*\n\x06RpcAck\x12 \n\nrequest_id\x18\x01 \x01(\tB\x0c\xbaP\trequestID\"\x8d\x01\n\x0bRpcResponse\x12 \n\nrequest_id\x18\x01 \x01(\tB\x0c\xbaP\trequestID\x12\x11\n\x07payload\x18\x02 \x01(\tH\x00\x12\"\n\x05\x65rror\x18\x03 \x01(\x0b\x32\x11.livekit.RpcErrorH\x00\x12\x1c\n\x12\x63ompressed_payload\x18\x04 \x01(\x0cH\x00\x42\x07\n\x05value\"7\n\x08RpcError\x12\x0c\n\x04\x63ode\x18\x01 \x01(\r\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\t\"@\n\x11ParticipantTracks\x12\x17\n\x0fparticipant_sid\x18\x01 \x01(\t\x12\x12\n\ntrack_sids\x18\x02 \x03(\t\"\xd9\x01\n\nServerInfo\x12,\n\x07\x65\x64ition\x18\x01 \x01(\x0e\x32\x1b.livekit.ServerInfo.Edition\x12\x0f\n\x07version\x18\x02 \x01(\t\x12\x10\n\x08protocol\x18\x03 \x01(\x05\x12\x0e\n\x06region\x18\x04 \x01(\t\x12\x1a\n\x07node_id\x18\x05 \x01(\tB\t\xbaP\x06nodeID\x12\x12\n\ndebug_info\x18\x06 \x01(\t\x12\x16\n\x0e\x61gent_protocol\x18\x07 \x01(\x05\"\"\n\x07\x45\x64ition\x12\x0c\n\x08Standard\x10\x00\x12\t\n\x05\x43loud\x10\x01\"\xa6\x04\n\nClientInfo\x12$\n\x03sdk\x18\x01 \x01(\x0e\x32\x17.livekit.ClientInfo.SDK\x12\x0f\n\x07version\x18\x02 \x01(\t\x12\x10\n\x08protocol\x18\x03 \x01(\x05\x12\n\n\x02os\x18\x04 \x01(\t\x12\x12\n\nos_version\x18\x05 \x01(\t\x12\x14\n\x0c\x64\x65vice_model\x18\x06 \x01(\t\x12\x0f\n\x07\x62rowser\x18\x07 \x01(\t\x12\x17\n\x0f\x62rowser_version\x18\x08 \x01(\t\x12\x0f\n\x07\x61\x64\x64ress\x18\t \x01(\t\x12\x0f\n\x07network\x18\n \x01(\t\x12\x12\n\nother_sdks\x18\x0b \x01(\t\x12\x17\n\x0f\x63lient_protocol\x18\x0c \x01(\x05\x12\x34\n\x0c\x63\x61pabilities\x18\r \x03(\x0e\x32\x1e.livekit.ClientInfo.Capability\"\xb3\x01\n\x03SDK\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x06\n\x02JS\x10\x01\x12\t\n\x05SWIFT\x10\x02\x12\x0b\n\x07\x41NDROID\x10\x03\x12\x0b\n\x07\x46LUTTER\x10\x04\x12\x06\n\x02GO\x10\x05\x12\t\n\x05UNITY\x10\x06\x12\x10\n\x0cREACT_NATIVE\x10\x07\x12\x08\n\x04RUST\x10\x08\x12\n\n\x06PYTHON\x10\t\x12\x07\n\x03\x43PP\x10\n\x12\r\n\tUNITY_WEB\x10\x0b\x12\x08\n\x04NODE\x10\x0c\x12\n\n\x06UNREAL\x10\r\x12\t\n\x05\x45SP32\x10\x0e\"4\n\nCapability\x12\x0e\n\nCAP_UNUSED\x10\x00\x12\x16\n\x12\x43\x41P_PACKET_TRAILER\x10\x01\"\x8c\x02\n\x13\x43lientConfiguration\x12*\n\x05video\x18\x01 \x01(\x0b\x32\x1b.livekit.VideoConfiguration\x12+\n\x06screen\x18\x02 \x01(\x0b\x32\x1b.livekit.VideoConfiguration\x12\x37\n\x11resume_connection\x18\x03 \x01(\x0e\x32\x1c.livekit.ClientConfigSetting\x12\x30\n\x0f\x64isabled_codecs\x18\x04 \x01(\x0b\x32\x17.livekit.DisabledCodecs\x12\x31\n\x0b\x66orce_relay\x18\x05 \x01(\x0e\x32\x1c.livekit.ClientConfigSetting\"L\n\x12VideoConfiguration\x12\x36\n\x10hardware_encoder\x18\x01 \x01(\x0e\x32\x1c.livekit.ClientConfigSetting\"Q\n\x0e\x44isabledCodecs\x12\x1e\n\x06\x63odecs\x18\x01 \x03(\x0b\x32\x0e.livekit.Codec\x12\x1f\n\x07publish\x18\x02 \x03(\x0b\x32\x0e.livekit.Codec\"\x80\x02\n\x08RTPDrift\x12.\n\nstart_time\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12,\n\x08\x65nd_time\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x10\n\x08\x64uration\x18\x03 \x01(\x01\x12\x17\n\x0fstart_timestamp\x18\x04 \x01(\x04\x12\x15\n\rend_timestamp\x18\x05 \x01(\x04\x12\x17\n\x0frtp_clock_ticks\x18\x06 \x01(\x04\x12\x15\n\rdrift_samples\x18\x07 \x01(\x03\x12\x10\n\x08\x64rift_ms\x18\x08 \x01(\x01\x12\x12\n\nclock_rate\x18\t \x01(\x01\"\xd6\n\n\x08RTPStats\x12.\n\nstart_time\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12,\n\x08\x65nd_time\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x10\n\x08\x64uration\x18\x03 \x01(\x01\x12\x0f\n\x07packets\x18\x04 \x01(\r\x12\x13\n\x0bpacket_rate\x18\x05 \x01(\x01\x12\r\n\x05\x62ytes\x18\x06 \x01(\x04\x12\x14\n\x0cheader_bytes\x18\' \x01(\x04\x12\x0f\n\x07\x62itrate\x18\x07 \x01(\x01\x12\x14\n\x0cpackets_lost\x18\x08 \x01(\r\x12\x18\n\x10packet_loss_rate\x18\t \x01(\x01\x12\x1e\n\x16packet_loss_percentage\x18\n \x01(\x02\x12\x19\n\x11packets_duplicate\x18\x0b \x01(\r\x12\x1d\n\x15packet_duplicate_rate\x18\x0c \x01(\x01\x12\x17\n\x0f\x62ytes_duplicate\x18\r \x01(\x04\x12\x1e\n\x16header_bytes_duplicate\x18( \x01(\x04\x12\x19\n\x11\x62itrate_duplicate\x18\x0e \x01(\x01\x12\x17\n\x0fpackets_padding\x18\x0f \x01(\r\x12\x1b\n\x13packet_padding_rate\x18\x10 \x01(\x01\x12\x15\n\rbytes_padding\x18\x11 \x01(\x04\x12\x1c\n\x14header_bytes_padding\x18) \x01(\x04\x12\x17\n\x0f\x62itrate_padding\x18\x12 \x01(\x01\x12\x1c\n\x14packets_out_of_order\x18\x13 \x01(\r\x12\x0e\n\x06\x66rames\x18\x14 \x01(\r\x12\x12\n\nframe_rate\x18\x15 \x01(\x01\x12\x16\n\x0ejitter_current\x18\x16 \x01(\x01\x12\x12\n\njitter_max\x18\x17 \x01(\x01\x12:\n\rgap_histogram\x18\x18 \x03(\x0b\x32#.livekit.RTPStats.GapHistogramEntry\x12\r\n\x05nacks\x18\x19 \x01(\r\x12\x11\n\tnack_acks\x18% \x01(\r\x12\x13\n\x0bnack_misses\x18\x1a \x01(\r\x12\x15\n\rnack_repeated\x18& \x01(\r\x12\x0c\n\x04plis\x18\x1b \x01(\r\x12,\n\x08last_pli\x18\x1c \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x0c\n\x04\x66irs\x18\x1d \x01(\r\x12,\n\x08last_fir\x18\x1e \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x13\n\x0brtt_current\x18\x1f \x01(\r\x12\x0f\n\x07rtt_max\x18 \x01(\r\x12\x12\n\nkey_frames\x18! \x01(\r\x12\x32\n\x0elast_key_frame\x18\" \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x17\n\x0flayer_lock_plis\x18# \x01(\r\x12\x37\n\x13last_layer_lock_pli\x18$ \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\'\n\x0cpacket_drift\x18, \x01(\x0b\x32\x11.livekit.RTPDrift\x12+\n\x10ntp_report_drift\x18- \x01(\x0b\x32\x11.livekit.RTPDrift\x12/\n\x14rebased_report_drift\x18. \x01(\x0b\x32\x11.livekit.RTPDrift\x12\x30\n\x15received_report_drift\x18/ \x01(\x0b\x32\x11.livekit.RTPDrift\x1a\x33\n\x11GapHistogramEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\r:\x02\x38\x01\"\xa2\x01\n\x15RTCPSenderReportState\x12\x15\n\rrtp_timestamp\x18\x01 \x01(\r\x12\x19\n\x11rtp_timestamp_ext\x18\x02 \x01(\x04\x12\x15\n\rntp_timestamp\x18\x03 \x01(\x04\x12\n\n\x02\x61t\x18\x04 \x01(\x03\x12\x13\n\x0b\x61t_adjusted\x18\x05 \x01(\x03\x12\x0f\n\x07packets\x18\x06 \x01(\r\x12\x0e\n\x06octets\x18\x07 \x01(\x04\"\xc9\x02\n\x11RTPForwarderState\x12\x0f\n\x07started\x18\x01 \x01(\x08\x12\x1f\n\x17reference_layer_spatial\x18\x02 \x01(\x05\x12\x16\n\x0epre_start_time\x18\x03 \x01(\x03\x12\x1b\n\x13\x65xt_first_timestamp\x18\x04 \x01(\x04\x12$\n\x1c\x64ummy_start_timestamp_offset\x18\x05 \x01(\x04\x12+\n\nrtp_munger\x18\x06 \x01(\x0b\x32\x17.livekit.RTPMungerState\x12-\n\nvp8_munger\x18\x07 \x01(\x0b\x32\x17.livekit.VP8MungerStateH\x00\x12;\n\x13sender_report_state\x18\x08 \x03(\x0b\x32\x1e.livekit.RTCPSenderReportStateB\x0e\n\x0c\x63odec_munger\"\xcb\x01\n\x0eRTPMungerState\x12 \n\x18\x65xt_last_sequence_number\x18\x01 \x01(\x04\x12\'\n\x1f\x65xt_second_last_sequence_number\x18\x02 \x01(\x04\x12\x1a\n\x12\x65xt_last_timestamp\x18\x03 \x01(\x04\x12!\n\x19\x65xt_second_last_timestamp\x18\x04 \x01(\x04\x12\x13\n\x0blast_marker\x18\x05 \x01(\x08\x12\x1a\n\x12second_last_marker\x18\x06 \x01(\x08\"\xcd\x01\n\x0eVP8MungerState\x12\x30\n\x13\x65xt_last_picture_id\x18\x01 \x01(\x05\x42\x13\xbaP\x10\x65xtLastPictureID\x12\x17\n\x0fpicture_id_used\x18\x02 \x01(\x08\x12\x18\n\x10last_tl0_pic_idx\x18\x03 \x01(\r\x12\x18\n\x10tl0_pic_idx_used\x18\x04 \x01(\x08\x12\x10\n\x08tid_used\x18\x05 \x01(\x08\x12\x14\n\x0clast_key_idx\x18\x06 \x01(\r\x12\x14\n\x0ckey_idx_used\x18\x07 \x01(\x08\"1\n\x0cTimedVersion\x12\x12\n\nunix_micro\x18\x01 \x01(\x03\x12\r\n\x05ticks\x18\x02 \x01(\x05\"\x88\x08\n\nDataStream\x1a\xb8\x01\n\nTextHeader\x12\x39\n\x0eoperation_type\x18\x01 \x01(\x0e\x32!.livekit.DataStream.OperationType\x12\x0f\n\x07version\x18\x02 \x01(\x05\x12.\n\x12reply_to_stream_id\x18\x03 \x01(\tB\x12\xbaP\x0freplyToStreamID\x12\x1b\n\x13\x61ttached_stream_ids\x18\x04 \x03(\t\x12\x11\n\tgenerated\x18\x05 \x01(\x08\x1a\x1a\n\nByteHeader\x12\x0c\n\x04name\x18\x01 \x01(\t\x1a\xb3\x03\n\x06Header\x12\x1e\n\tstream_id\x18\x01 \x01(\tB\x0b\xbaP\x08streamID\x12\x11\n\ttimestamp\x18\x02 \x01(\x03\x12\r\n\x05topic\x18\x03 \x01(\t\x12\x11\n\tmime_type\x18\x04 \x01(\t\x12\x19\n\x0ctotal_length\x18\x05 \x01(\x04H\x01\x88\x01\x01\x12\x35\n\x0f\x65ncryption_type\x18\x07 \x01(\x0e\x32\x18.livekit.Encryption.TypeB\x02\x18\x01\x12>\n\nattributes\x18\x08 \x03(\x0b\x32*.livekit.DataStream.Header.AttributesEntry\x12\x35\n\x0btext_header\x18\t \x01(\x0b\x32\x1e.livekit.DataStream.TextHeaderH\x00\x12\x35\n\x0b\x62yte_header\x18\n \x01(\x0b\x32\x1e.livekit.DataStream.ByteHeaderH\x00\x1a\x31\n\x0f\x41ttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\x10\n\x0e\x63ontent_headerB\x0f\n\r_total_length\x1az\n\x05\x43hunk\x12\x1e\n\tstream_id\x18\x01 \x01(\tB\x0b\xbaP\x08streamID\x12\x13\n\x0b\x63hunk_index\x18\x02 \x01(\x04\x12\x0f\n\x07\x63ontent\x18\x03 \x01(\x0c\x12\x0f\n\x07version\x18\x04 \x01(\x05\x12\x13\n\x02iv\x18\x05 \x01(\x0c\x42\x02\x18\x01H\x00\x88\x01\x01\x42\x05\n\x03_iv\x1a\xad\x01\n\x07Trailer\x12\x1e\n\tstream_id\x18\x01 \x01(\tB\x0b\xbaP\x08streamID\x12\x0e\n\x06reason\x18\x02 \x01(\t\x12?\n\nattributes\x18\x03 \x03(\x0b\x32+.livekit.DataStream.Trailer.AttributesEntry\x1a\x31\n\x0f\x41ttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"A\n\rOperationType\x12\n\n\x06\x43REATE\x10\x00\x12\n\n\x06UPDATE\x10\x01\x12\n\n\x06\x44\x45LETE\x10\x02\x12\x0c\n\x08REACTION\x10\x03\">\n\x0c\x46ilterParams\x12\x16\n\x0einclude_events\x18\x01 \x03(\t\x12\x16\n\x0e\x65xclude_events\x18\x02 \x03(\t\"_\n\rWebhookConfig\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x13\n\x0bsigning_key\x18\x02 \x01(\t\x12,\n\rfilter_params\x18\x03 \x01(\x0b\x32\x15.livekit.FilterParams\"6\n\x14SubscribedAudioCodec\x12\r\n\x05\x63odec\x18\x01 \x01(\t\x12\x0f\n\x07\x65nabled\x18\x02 \x01(\x08*;\n\nAudioCodec\x12\x0e\n\nDEFAULT_AC\x10\x00\x12\x08\n\x04OPUS\x10\x01\x12\x07\n\x03\x41\x41\x43\x10\x02\x12\n\n\x06\x41\x43_MP3\x10\x03*V\n\nVideoCodec\x12\x0e\n\nDEFAULT_VC\x10\x00\x12\x11\n\rH264_BASELINE\x10\x01\x12\r\n\tH264_MAIN\x10\x02\x12\r\n\tH264_HIGH\x10\x03\x12\x07\n\x03VP8\x10\x04*)\n\nImageCodec\x12\x0e\n\nIC_DEFAULT\x10\x00\x12\x0b\n\x07IC_JPEG\x10\x01*I\n\x11\x42\x61\x63kupCodecPolicy\x12\x15\n\x11PREFER_REGRESSION\x10\x00\x12\r\n\tSIMULCAST\x10\x01\x12\x0e\n\nREGRESSION\x10\x02*+\n\tTrackType\x12\t\n\x05\x41UDIO\x10\x00\x12\t\n\x05VIDEO\x10\x01\x12\x08\n\x04\x44\x41TA\x10\x02*`\n\x0bTrackSource\x12\x0b\n\x07UNKNOWN\x10\x00\x12\n\n\x06\x43\x41MERA\x10\x01\x12\x0e\n\nMICROPHONE\x10\x02\x12\x10\n\x0cSCREEN_SHARE\x10\x03\x12\x16\n\x12SCREEN_SHARE_AUDIO\x10\x04*B\n\x14\x44\x61taTrackExtensionID\x12\x10\n\x0c\x44TEI_INVALID\x10\x00\x12\x18\n\x14\x44TEI_PARTICIPANT_SID\x10\x01*6\n\x0cVideoQuality\x12\x07\n\x03LOW\x10\x00\x12\n\n\x06MEDIUM\x10\x01\x12\x08\n\x04HIGH\x10\x02\x12\x07\n\x03OFF\x10\x03*@\n\x11\x43onnectionQuality\x12\x08\n\x04POOR\x10\x00\x12\x08\n\x04GOOD\x10\x01\x12\r\n\tEXCELLENT\x10\x02\x12\x08\n\x04LOST\x10\x03*;\n\x13\x43lientConfigSetting\x12\t\n\x05UNSET\x10\x00\x12\x0c\n\x08\x44ISABLED\x10\x01\x12\x0b\n\x07\x45NABLED\x10\x02*\xe8\x02\n\x10\x44isconnectReason\x12\x12\n\x0eUNKNOWN_REASON\x10\x00\x12\x14\n\x10\x43LIENT_INITIATED\x10\x01\x12\x16\n\x12\x44UPLICATE_IDENTITY\x10\x02\x12\x13\n\x0fSERVER_SHUTDOWN\x10\x03\x12\x17\n\x13PARTICIPANT_REMOVED\x10\x04\x12\x10\n\x0cROOM_DELETED\x10\x05\x12\x12\n\x0eSTATE_MISMATCH\x10\x06\x12\x10\n\x0cJOIN_FAILURE\x10\x07\x12\r\n\tMIGRATION\x10\x08\x12\x10\n\x0cSIGNAL_CLOSE\x10\t\x12\x0f\n\x0bROOM_CLOSED\x10\n\x12\x14\n\x10USER_UNAVAILABLE\x10\x0b\x12\x11\n\rUSER_REJECTED\x10\x0c\x12\x15\n\x11SIP_TRUNK_FAILURE\x10\r\x12\x16\n\x12\x43ONNECTION_TIMEOUT\x10\x0e\x12\x11\n\rMEDIA_FAILURE\x10\x0f\x12\x0f\n\x0b\x41GENT_ERROR\x10\x10*\x89\x01\n\x0fReconnectReason\x12\x0e\n\nRR_UNKNOWN\x10\x00\x12\x1a\n\x16RR_SIGNAL_DISCONNECTED\x10\x01\x12\x17\n\x13RR_PUBLISHER_FAILED\x10\x02\x12\x18\n\x14RR_SUBSCRIBER_FAILED\x10\x03\x12\x17\n\x13RR_SWITCH_CANDIDATE\x10\x04*T\n\x11SubscriptionError\x12\x0e\n\nSE_UNKNOWN\x10\x00\x12\x18\n\x14SE_CODEC_UNSUPPORTED\x10\x01\x12\x15\n\x11SE_TRACK_NOTFOUND\x10\x02*\xbd\x01\n\x11\x41udioTrackFeature\x12\r\n\tTF_STEREO\x10\x00\x12\r\n\tTF_NO_DTX\x10\x01\x12\x18\n\x14TF_AUTO_GAIN_CONTROL\x10\x02\x12\x18\n\x14TF_ECHO_CANCELLATION\x10\x03\x12\x18\n\x14TF_NOISE_SUPPRESSION\x10\x04\x12\"\n\x1eTF_ENHANCED_NOISE_CANCELLATION\x10\x05\x12\x18\n\x14TF_PRECONNECT_BUFFER\x10\x06*@\n\x14PacketTrailerFeature\x12\x16\n\x12PTF_USER_TIMESTAMP\x10\x00\x12\x10\n\x0cPTF_FRAME_ID\x10\x01\x42\x46Z#github.com/livekit/protocol/livekit\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -23,16 +25,38 @@
if _descriptor._USE_C_DESCRIPTORS == False:
_globals['DESCRIPTOR']._options = None
_globals['DESCRIPTOR']._serialized_options = b'Z#github.com/livekit/protocol/livekit\252\002\rLiveKit.Proto\352\002\016LiveKit::Proto'
+ _globals['_PAGINATION'].fields_by_name['after_id']._options = None
+ _globals['_PAGINATION'].fields_by_name['after_id']._serialized_options = b'\272P\007afterID'
+ _globals['_ROOM'].fields_by_name['metadata']._options = None
+ _globals['_ROOM'].fields_by_name['metadata']._serialized_options = b'\250P\001\262P\036'
_globals['_PARTICIPANTPERMISSION'].fields_by_name['recorder']._options = None
_globals['_PARTICIPANTPERMISSION'].fields_by_name['recorder']._serialized_options = b'\030\001'
_globals['_PARTICIPANTPERMISSION'].fields_by_name['agent']._options = None
_globals['_PARTICIPANTPERMISSION'].fields_by_name['agent']._serialized_options = b'\030\001'
_globals['_PARTICIPANTINFO_ATTRIBUTESENTRY']._options = None
_globals['_PARTICIPANTINFO_ATTRIBUTESENTRY']._serialized_options = b'8\001'
+ _globals['_PARTICIPANTINFO'].fields_by_name['metadata']._options = None
+ _globals['_PARTICIPANTINFO'].fields_by_name['metadata']._serialized_options = b'\250P\001\262P\036'
+ _globals['_PARTICIPANTINFO'].fields_by_name['name']._options = None
+ _globals['_PARTICIPANTINFO'].fields_by_name['name']._serialized_options = b'\250P\001'
+ _globals['_PARTICIPANTINFO'].fields_by_name['attributes']._options = None
+ _globals['_PARTICIPANTINFO'].fields_by_name['attributes']._serialized_options = b'\250P\001\262P\036'
+ _globals['_TRACKINFO'].fields_by_name['name']._options = None
+ _globals['_TRACKINFO'].fields_by_name['name']._serialized_options = b'\250P\001'
+ _globals['_TRACKINFO'].fields_by_name['simulcast']._options = None
+ _globals['_TRACKINFO'].fields_by_name['simulcast']._serialized_options = b'\030\001'
+ _globals['_TRACKINFO'].fields_by_name['disable_dtx']._options = None
+ _globals['_TRACKINFO'].fields_by_name['disable_dtx']._serialized_options = b'\030\001'
+ _globals['_TRACKINFO'].fields_by_name['layers']._options = None
+ _globals['_TRACKINFO'].fields_by_name['layers']._serialized_options = b'\030\001'
+ _globals['_TRACKINFO'].fields_by_name['stereo']._options = None
+ _globals['_TRACKINFO'].fields_by_name['stereo']._serialized_options = b'\030\001'
_globals['_DATAPACKET'].fields_by_name['kind']._options = None
_globals['_DATAPACKET'].fields_by_name['kind']._serialized_options = b'\030\001'
_globals['_DATAPACKET'].fields_by_name['speaker']._options = None
_globals['_DATAPACKET'].fields_by_name['speaker']._serialized_options = b'\030\001'
+ _globals['_ACTIVESPEAKERUPDATE']._options = None
+ _globals['_ACTIVESPEAKERUPDATE']._serialized_options = b'\030\001'
_globals['_USERPACKET'].fields_by_name['participant_sid']._options = None
_globals['_USERPACKET'].fields_by_name['participant_sid']._serialized_options = b'\030\001'
_globals['_USERPACKET'].fields_by_name['participant_identity']._options = None
@@ -41,96 +65,192 @@
_globals['_USERPACKET'].fields_by_name['destination_sids']._serialized_options = b'\030\001'
_globals['_USERPACKET'].fields_by_name['destination_identities']._options = None
_globals['_USERPACKET'].fields_by_name['destination_identities']._serialized_options = b'\030\001'
+ _globals['_TRANSCRIPTION'].fields_by_name['track_id']._options = None
+ _globals['_TRANSCRIPTION'].fields_by_name['track_id']._serialized_options = b'\272P\007trackID'
+ _globals['_RPCACK'].fields_by_name['request_id']._options = None
+ _globals['_RPCACK'].fields_by_name['request_id']._serialized_options = b'\272P\trequestID'
+ _globals['_RPCRESPONSE'].fields_by_name['request_id']._options = None
+ _globals['_RPCRESPONSE'].fields_by_name['request_id']._serialized_options = b'\272P\trequestID'
+ _globals['_SERVERINFO'].fields_by_name['node_id']._options = None
+ _globals['_SERVERINFO'].fields_by_name['node_id']._serialized_options = b'\272P\006nodeID'
_globals['_RTPSTATS_GAPHISTOGRAMENTRY']._options = None
_globals['_RTPSTATS_GAPHISTOGRAMENTRY']._serialized_options = b'8\001'
- _globals['_AUDIOCODEC']._serialized_start=5814
- _globals['_AUDIOCODEC']._serialized_end=5861
- _globals['_VIDEOCODEC']._serialized_start=5863
- _globals['_VIDEOCODEC']._serialized_end=5949
- _globals['_IMAGECODEC']._serialized_start=5951
- _globals['_IMAGECODEC']._serialized_end=5992
- _globals['_TRACKTYPE']._serialized_start=5994
- _globals['_TRACKTYPE']._serialized_end=6037
- _globals['_TRACKSOURCE']._serialized_start=6039
- _globals['_TRACKSOURCE']._serialized_end=6135
- _globals['_VIDEOQUALITY']._serialized_start=6137
- _globals['_VIDEOQUALITY']._serialized_end=6191
- _globals['_CONNECTIONQUALITY']._serialized_start=6193
- _globals['_CONNECTIONQUALITY']._serialized_end=6257
- _globals['_CLIENTCONFIGSETTING']._serialized_start=6259
- _globals['_CLIENTCONFIGSETTING']._serialized_end=6318
- _globals['_DISCONNECTREASON']._serialized_start=6321
- _globals['_DISCONNECTREASON']._serialized_end=6540
- _globals['_RECONNECTREASON']._serialized_start=6543
- _globals['_RECONNECTREASON']._serialized_end=6680
- _globals['_SUBSCRIPTIONERROR']._serialized_start=6682
- _globals['_SUBSCRIPTIONERROR']._serialized_end=6766
- _globals['_AUDIOTRACKFEATURE']._serialized_start=6769
- _globals['_AUDIOTRACKFEATURE']._serialized_end=6932
- _globals['_ROOM']._serialized_start=67
- _globals['_ROOM']._serialized_end=396
- _globals['_CODEC']._serialized_start=398
- _globals['_CODEC']._serialized_end=438
- _globals['_PLAYOUTDELAY']._serialized_start=440
- _globals['_PLAYOUTDELAY']._serialized_end=497
- _globals['_PARTICIPANTPERMISSION']._serialized_start=500
- _globals['_PARTICIPANTPERMISSION']._serialized_end=730
- _globals['_PARTICIPANTINFO']._serialized_start=733
- _globals['_PARTICIPANTINFO']._serialized_end=1311
- _globals['_PARTICIPANTINFO_ATTRIBUTESENTRY']._serialized_start=1131
- _globals['_PARTICIPANTINFO_ATTRIBUTESENTRY']._serialized_end=1180
- _globals['_PARTICIPANTINFO_STATE']._serialized_start=1182
- _globals['_PARTICIPANTINFO_STATE']._serialized_end=1244
- _globals['_PARTICIPANTINFO_KIND']._serialized_start=1246
- _globals['_PARTICIPANTINFO_KIND']._serialized_end=1311
- _globals['_ENCRYPTION']._serialized_start=1313
- _globals['_ENCRYPTION']._serialized_end=1364
- _globals['_ENCRYPTION_TYPE']._serialized_start=1327
- _globals['_ENCRYPTION_TYPE']._serialized_end=1364
- _globals['_SIMULCASTCODECINFO']._serialized_start=1366
- _globals['_SIMULCASTCODECINFO']._serialized_end=1468
- _globals['_TRACKINFO']._serialized_start=1471
- _globals['_TRACKINFO']._serialized_end=1972
- _globals['_VIDEOLAYER']._serialized_start=1974
- _globals['_VIDEOLAYER']._serialized_end=2088
- _globals['_DATAPACKET']._serialized_start=2091
- _globals['_DATAPACKET']._serialized_end=2428
- _globals['_DATAPACKET_KIND']._serialized_start=2388
- _globals['_DATAPACKET_KIND']._serialized_end=2419
- _globals['_ACTIVESPEAKERUPDATE']._serialized_start=2430
- _globals['_ACTIVESPEAKERUPDATE']._serialized_end=2491
- _globals['_SPEAKERINFO']._serialized_start=2493
- _globals['_SPEAKERINFO']._serialized_end=2550
- _globals['_USERPACKET']._serialized_start=2553
- _globals['_USERPACKET']._serialized_end=2841
- _globals['_SIPDTMF']._serialized_start=2843
- _globals['_SIPDTMF']._serialized_end=2881
- _globals['_TRANSCRIPTION']._serialized_start=2883
- _globals['_TRANSCRIPTION']._serialized_end=3007
- _globals['_TRANSCRIPTIONSEGMENT']._serialized_start=3009
- _globals['_TRANSCRIPTIONSEGMENT']._serialized_end=3128
- _globals['_PARTICIPANTTRACKS']._serialized_start=3130
- _globals['_PARTICIPANTTRACKS']._serialized_end=3194
- _globals['_SERVERINFO']._serialized_start=3197
- _globals['_SERVERINFO']._serialized_end=3403
- _globals['_SERVERINFO_EDITION']._serialized_start=3369
- _globals['_SERVERINFO_EDITION']._serialized_end=3403
- _globals['_CLIENTINFO']._serialized_start=3406
- _globals['_CLIENTINFO']._serialized_end=3755
- _globals['_CLIENTINFO_SDK']._serialized_start=3624
- _globals['_CLIENTINFO_SDK']._serialized_end=3755
- _globals['_CLIENTCONFIGURATION']._serialized_start=3758
- _globals['_CLIENTCONFIGURATION']._serialized_end=4026
- _globals['_VIDEOCONFIGURATION']._serialized_start=4028
- _globals['_VIDEOCONFIGURATION']._serialized_end=4104
- _globals['_DISABLEDCODECS']._serialized_start=4106
- _globals['_DISABLEDCODECS']._serialized_end=4187
- _globals['_RTPDRIFT']._serialized_start=4190
- _globals['_RTPDRIFT']._serialized_end=4446
- _globals['_RTPSTATS']._serialized_start=4449
- _globals['_RTPSTATS']._serialized_end=5761
- _globals['_RTPSTATS_GAPHISTOGRAMENTRY']._serialized_start=5710
- _globals['_RTPSTATS_GAPHISTOGRAMENTRY']._serialized_end=5761
- _globals['_TIMEDVERSION']._serialized_start=5763
- _globals['_TIMEDVERSION']._serialized_end=5812
+ _globals['_VP8MUNGERSTATE'].fields_by_name['ext_last_picture_id']._options = None
+ _globals['_VP8MUNGERSTATE'].fields_by_name['ext_last_picture_id']._serialized_options = b'\272P\020extLastPictureID'
+ _globals['_DATASTREAM_TEXTHEADER'].fields_by_name['reply_to_stream_id']._options = None
+ _globals['_DATASTREAM_TEXTHEADER'].fields_by_name['reply_to_stream_id']._serialized_options = b'\272P\017replyToStreamID'
+ _globals['_DATASTREAM_HEADER_ATTRIBUTESENTRY']._options = None
+ _globals['_DATASTREAM_HEADER_ATTRIBUTESENTRY']._serialized_options = b'8\001'
+ _globals['_DATASTREAM_HEADER'].fields_by_name['stream_id']._options = None
+ _globals['_DATASTREAM_HEADER'].fields_by_name['stream_id']._serialized_options = b'\272P\010streamID'
+ _globals['_DATASTREAM_HEADER'].fields_by_name['encryption_type']._options = None
+ _globals['_DATASTREAM_HEADER'].fields_by_name['encryption_type']._serialized_options = b'\030\001'
+ _globals['_DATASTREAM_CHUNK'].fields_by_name['stream_id']._options = None
+ _globals['_DATASTREAM_CHUNK'].fields_by_name['stream_id']._serialized_options = b'\272P\010streamID'
+ _globals['_DATASTREAM_CHUNK'].fields_by_name['iv']._options = None
+ _globals['_DATASTREAM_CHUNK'].fields_by_name['iv']._serialized_options = b'\030\001'
+ _globals['_DATASTREAM_TRAILER_ATTRIBUTESENTRY']._options = None
+ _globals['_DATASTREAM_TRAILER_ATTRIBUTESENTRY']._serialized_options = b'8\001'
+ _globals['_DATASTREAM_TRAILER'].fields_by_name['stream_id']._options = None
+ _globals['_DATASTREAM_TRAILER'].fields_by_name['stream_id']._serialized_options = b'\272P\010streamID'
+ _globals['_AUDIOCODEC']._serialized_start=11271
+ _globals['_AUDIOCODEC']._serialized_end=11330
+ _globals['_VIDEOCODEC']._serialized_start=11332
+ _globals['_VIDEOCODEC']._serialized_end=11418
+ _globals['_IMAGECODEC']._serialized_start=11420
+ _globals['_IMAGECODEC']._serialized_end=11461
+ _globals['_BACKUPCODECPOLICY']._serialized_start=11463
+ _globals['_BACKUPCODECPOLICY']._serialized_end=11536
+ _globals['_TRACKTYPE']._serialized_start=11538
+ _globals['_TRACKTYPE']._serialized_end=11581
+ _globals['_TRACKSOURCE']._serialized_start=11583
+ _globals['_TRACKSOURCE']._serialized_end=11679
+ _globals['_DATATRACKEXTENSIONID']._serialized_start=11681
+ _globals['_DATATRACKEXTENSIONID']._serialized_end=11747
+ _globals['_VIDEOQUALITY']._serialized_start=11749
+ _globals['_VIDEOQUALITY']._serialized_end=11803
+ _globals['_CONNECTIONQUALITY']._serialized_start=11805
+ _globals['_CONNECTIONQUALITY']._serialized_end=11869
+ _globals['_CLIENTCONFIGSETTING']._serialized_start=11871
+ _globals['_CLIENTCONFIGSETTING']._serialized_end=11930
+ _globals['_DISCONNECTREASON']._serialized_start=11933
+ _globals['_DISCONNECTREASON']._serialized_end=12293
+ _globals['_RECONNECTREASON']._serialized_start=12296
+ _globals['_RECONNECTREASON']._serialized_end=12433
+ _globals['_SUBSCRIPTIONERROR']._serialized_start=12435
+ _globals['_SUBSCRIPTIONERROR']._serialized_end=12519
+ _globals['_AUDIOTRACKFEATURE']._serialized_start=12522
+ _globals['_AUDIOTRACKFEATURE']._serialized_end=12711
+ _globals['_PACKETTRAILERFEATURE']._serialized_start=12713
+ _globals['_PACKETTRAILERFEATURE']._serialized_end=12777
+ _globals['_PAGINATION']._serialized_start=111
+ _globals['_PAGINATION']._serialized_end=168
+ _globals['_TOKENPAGINATION']._serialized_start=170
+ _globals['_TOKENPAGINATION']._serialized_end=202
+ _globals['_LISTUPDATE']._serialized_start=204
+ _globals['_LISTUPDATE']._serialized_end=273
+ _globals['_ROOM']._serialized_start=276
+ _globals['_ROOM']._serialized_end=669
+ _globals['_CODEC']._serialized_start=671
+ _globals['_CODEC']._serialized_end=711
+ _globals['_PLAYOUTDELAY']._serialized_start=713
+ _globals['_PLAYOUTDELAY']._serialized_end=770
+ _globals['_PARTICIPANTPERMISSION']._serialized_start=773
+ _globals['_PARTICIPANTPERMISSION']._serialized_end=1068
+ _globals['_PARTICIPANTINFO']._serialized_start=1071
+ _globals['_PARTICIPANTINFO']._serialized_end=2071
+ _globals['_PARTICIPANTINFO_ATTRIBUTESENTRY']._serialized_start=1755
+ _globals['_PARTICIPANTINFO_ATTRIBUTESENTRY']._serialized_end=1804
+ _globals['_PARTICIPANTINFO_STATE']._serialized_start=1806
+ _globals['_PARTICIPANTINFO_STATE']._serialized_end=1868
+ _globals['_PARTICIPANTINFO_KIND']._serialized_start=1870
+ _globals['_PARTICIPANTINFO_KIND']._serialized_end=1962
+ _globals['_PARTICIPANTINFO_KINDDETAIL']._serialized_start=1964
+ _globals['_PARTICIPANTINFO_KINDDETAIL']._serialized_end=2071
+ _globals['_ENCRYPTION']._serialized_start=2073
+ _globals['_ENCRYPTION']._serialized_end=2124
+ _globals['_ENCRYPTION_TYPE']._serialized_start=2087
+ _globals['_ENCRYPTION_TYPE']._serialized_end=2124
+ _globals['_SIMULCASTCODECINFO']._serialized_start=2127
+ _globals['_SIMULCASTCODECINFO']._serialized_end=2298
+ _globals['_TRACKINFO']._serialized_start=2301
+ _globals['_TRACKINFO']._serialized_end=2944
+ _globals['_DATATRACKINFO']._serialized_start=2946
+ _globals['_DATATRACKINFO']._serialized_end=3054
+ _globals['_DATATRACKEXTENSIONPARTICIPANTSID']._serialized_start=3056
+ _globals['_DATATRACKEXTENSIONPARTICIPANTSID']._serialized_end=3158
+ _globals['_DATATRACKSUBSCRIPTIONOPTIONS']._serialized_start=3160
+ _globals['_DATATRACKSUBSCRIPTIONOPTIONS']._serialized_end=3230
+ _globals['_VIDEOLAYER']._serialized_start=3233
+ _globals['_VIDEOLAYER']._serialized_end=3557
+ _globals['_VIDEOLAYER_MODE']._serialized_start=3407
+ _globals['_VIDEOLAYER_MODE']._serialized_end=3557
+ _globals['_DATAPACKET']._serialized_start=3560
+ _globals['_DATAPACKET']._serialized_end=4367
+ _globals['_DATAPACKET_KIND']._serialized_start=4327
+ _globals['_DATAPACKET_KIND']._serialized_end=4358
+ _globals['_ENCRYPTEDPACKET']._serialized_start=4369
+ _globals['_ENCRYPTEDPACKET']._serialized_end=4493
+ _globals['_ENCRYPTEDPACKETPAYLOAD']._serialized_start=4496
+ _globals['_ENCRYPTEDPACKETPAYLOAD']._serialized_end=4897
+ _globals['_ACTIVESPEAKERUPDATE']._serialized_start=4899
+ _globals['_ACTIVESPEAKERUPDATE']._serialized_end=4964
+ _globals['_SPEAKERINFO']._serialized_start=4966
+ _globals['_SPEAKERINFO']._serialized_end=5023
+ _globals['_USERPACKET']._serialized_start=5026
+ _globals['_USERPACKET']._serialized_end=5329
+ _globals['_SIPDTMF']._serialized_start=5331
+ _globals['_SIPDTMF']._serialized_end=5369
+ _globals['_TRANSCRIPTION']._serialized_start=5372
+ _globals['_TRANSCRIPTION']._serialized_end=5508
+ _globals['_TRANSCRIPTIONSEGMENT']._serialized_start=5510
+ _globals['_TRANSCRIPTIONSEGMENT']._serialized_end=5629
+ _globals['_CHATMESSAGE']._serialized_start=5632
+ _globals['_CHATMESSAGE']._serialized_end=5777
+ _globals['_RPCREQUEST']._serialized_start=5780
+ _globals['_RPCREQUEST']._serialized_end=5911
+ _globals['_RPCACK']._serialized_start=5913
+ _globals['_RPCACK']._serialized_end=5955
+ _globals['_RPCRESPONSE']._serialized_start=5958
+ _globals['_RPCRESPONSE']._serialized_end=6099
+ _globals['_RPCERROR']._serialized_start=6101
+ _globals['_RPCERROR']._serialized_end=6156
+ _globals['_PARTICIPANTTRACKS']._serialized_start=6158
+ _globals['_PARTICIPANTTRACKS']._serialized_end=6222
+ _globals['_SERVERINFO']._serialized_start=6225
+ _globals['_SERVERINFO']._serialized_end=6442
+ _globals['_SERVERINFO_EDITION']._serialized_start=6408
+ _globals['_SERVERINFO_EDITION']._serialized_end=6442
+ _globals['_CLIENTINFO']._serialized_start=6445
+ _globals['_CLIENTINFO']._serialized_end=6995
+ _globals['_CLIENTINFO_SDK']._serialized_start=6762
+ _globals['_CLIENTINFO_SDK']._serialized_end=6941
+ _globals['_CLIENTINFO_CAPABILITY']._serialized_start=6943
+ _globals['_CLIENTINFO_CAPABILITY']._serialized_end=6995
+ _globals['_CLIENTCONFIGURATION']._serialized_start=6998
+ _globals['_CLIENTCONFIGURATION']._serialized_end=7266
+ _globals['_VIDEOCONFIGURATION']._serialized_start=7268
+ _globals['_VIDEOCONFIGURATION']._serialized_end=7344
+ _globals['_DISABLEDCODECS']._serialized_start=7346
+ _globals['_DISABLEDCODECS']._serialized_end=7427
+ _globals['_RTPDRIFT']._serialized_start=7430
+ _globals['_RTPDRIFT']._serialized_end=7686
+ _globals['_RTPSTATS']._serialized_start=7689
+ _globals['_RTPSTATS']._serialized_end=9055
+ _globals['_RTPSTATS_GAPHISTOGRAMENTRY']._serialized_start=9004
+ _globals['_RTPSTATS_GAPHISTOGRAMENTRY']._serialized_end=9055
+ _globals['_RTCPSENDERREPORTSTATE']._serialized_start=9058
+ _globals['_RTCPSENDERREPORTSTATE']._serialized_end=9220
+ _globals['_RTPFORWARDERSTATE']._serialized_start=9223
+ _globals['_RTPFORWARDERSTATE']._serialized_end=9552
+ _globals['_RTPMUNGERSTATE']._serialized_start=9555
+ _globals['_RTPMUNGERSTATE']._serialized_end=9758
+ _globals['_VP8MUNGERSTATE']._serialized_start=9761
+ _globals['_VP8MUNGERSTATE']._serialized_end=9966
+ _globals['_TIMEDVERSION']._serialized_start=9968
+ _globals['_TIMEDVERSION']._serialized_end=10017
+ _globals['_DATASTREAM']._serialized_start=10020
+ _globals['_DATASTREAM']._serialized_end=11052
+ _globals['_DATASTREAM_TEXTHEADER']._serialized_start=10035
+ _globals['_DATASTREAM_TEXTHEADER']._serialized_end=10219
+ _globals['_DATASTREAM_BYTEHEADER']._serialized_start=10221
+ _globals['_DATASTREAM_BYTEHEADER']._serialized_end=10247
+ _globals['_DATASTREAM_HEADER']._serialized_start=10250
+ _globals['_DATASTREAM_HEADER']._serialized_end=10685
+ _globals['_DATASTREAM_HEADER_ATTRIBUTESENTRY']._serialized_start=1755
+ _globals['_DATASTREAM_HEADER_ATTRIBUTESENTRY']._serialized_end=1804
+ _globals['_DATASTREAM_CHUNK']._serialized_start=10687
+ _globals['_DATASTREAM_CHUNK']._serialized_end=10809
+ _globals['_DATASTREAM_TRAILER']._serialized_start=10812
+ _globals['_DATASTREAM_TRAILER']._serialized_end=10985
+ _globals['_DATASTREAM_TRAILER_ATTRIBUTESENTRY']._serialized_start=1755
+ _globals['_DATASTREAM_TRAILER_ATTRIBUTESENTRY']._serialized_end=1804
+ _globals['_DATASTREAM_OPERATIONTYPE']._serialized_start=10987
+ _globals['_DATASTREAM_OPERATIONTYPE']._serialized_end=11052
+ _globals['_FILTERPARAMS']._serialized_start=11054
+ _globals['_FILTERPARAMS']._serialized_end=11116
+ _globals['_WEBHOOKCONFIG']._serialized_start=11118
+ _globals['_WEBHOOKCONFIG']._serialized_end=11213
+ _globals['_SUBSCRIBEDAUDIOCODEC']._serialized_start=11215
+ _globals['_SUBSCRIBEDAUDIOCODEC']._serialized_end=11269
# @@protoc_insertion_point(module_scope)
diff --git a/livekit-protocol/livekit/protocol/models.pyi b/livekit-protocol/livekit/protocol/models.pyi
index cdef3e6c..35ce8a95 100644
--- a/livekit-protocol/livekit/protocol/models.pyi
+++ b/livekit-protocol/livekit/protocol/models.pyi
@@ -1,4 +1,6 @@
from google.protobuf import timestamp_pb2 as _timestamp_pb2
+from . import metrics as _metrics
+from .logger_pb import options as _options_pb2
from google.protobuf.internal import containers as _containers
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
from google.protobuf import descriptor as _descriptor
@@ -12,6 +14,7 @@ class AudioCodec(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
DEFAULT_AC: _ClassVar[AudioCodec]
OPUS: _ClassVar[AudioCodec]
AAC: _ClassVar[AudioCodec]
+ AC_MP3: _ClassVar[AudioCodec]
class VideoCodec(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
@@ -26,6 +29,12 @@ class ImageCodec(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
IC_DEFAULT: _ClassVar[ImageCodec]
IC_JPEG: _ClassVar[ImageCodec]
+class BackupCodecPolicy(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ PREFER_REGRESSION: _ClassVar[BackupCodecPolicy]
+ SIMULCAST: _ClassVar[BackupCodecPolicy]
+ REGRESSION: _ClassVar[BackupCodecPolicy]
+
class TrackType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
AUDIO: _ClassVar[TrackType]
@@ -40,6 +49,11 @@ class TrackSource(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
SCREEN_SHARE: _ClassVar[TrackSource]
SCREEN_SHARE_AUDIO: _ClassVar[TrackSource]
+class DataTrackExtensionID(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ DTEI_INVALID: _ClassVar[DataTrackExtensionID]
+ DTEI_PARTICIPANT_SID: _ClassVar[DataTrackExtensionID]
+
class VideoQuality(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
LOW: _ClassVar[VideoQuality]
@@ -72,6 +86,13 @@ class DisconnectReason(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
JOIN_FAILURE: _ClassVar[DisconnectReason]
MIGRATION: _ClassVar[DisconnectReason]
SIGNAL_CLOSE: _ClassVar[DisconnectReason]
+ ROOM_CLOSED: _ClassVar[DisconnectReason]
+ USER_UNAVAILABLE: _ClassVar[DisconnectReason]
+ USER_REJECTED: _ClassVar[DisconnectReason]
+ SIP_TRUNK_FAILURE: _ClassVar[DisconnectReason]
+ CONNECTION_TIMEOUT: _ClassVar[DisconnectReason]
+ MEDIA_FAILURE: _ClassVar[DisconnectReason]
+ AGENT_ERROR: _ClassVar[DisconnectReason]
class ReconnectReason(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
@@ -95,9 +116,16 @@ class AudioTrackFeature(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
TF_ECHO_CANCELLATION: _ClassVar[AudioTrackFeature]
TF_NOISE_SUPPRESSION: _ClassVar[AudioTrackFeature]
TF_ENHANCED_NOISE_CANCELLATION: _ClassVar[AudioTrackFeature]
+ TF_PRECONNECT_BUFFER: _ClassVar[AudioTrackFeature]
+
+class PacketTrailerFeature(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ PTF_USER_TIMESTAMP: _ClassVar[PacketTrailerFeature]
+ PTF_FRAME_ID: _ClassVar[PacketTrailerFeature]
DEFAULT_AC: AudioCodec
OPUS: AudioCodec
AAC: AudioCodec
+AC_MP3: AudioCodec
DEFAULT_VC: VideoCodec
H264_BASELINE: VideoCodec
H264_MAIN: VideoCodec
@@ -105,6 +133,9 @@ H264_HIGH: VideoCodec
VP8: VideoCodec
IC_DEFAULT: ImageCodec
IC_JPEG: ImageCodec
+PREFER_REGRESSION: BackupCodecPolicy
+SIMULCAST: BackupCodecPolicy
+REGRESSION: BackupCodecPolicy
AUDIO: TrackType
VIDEO: TrackType
DATA: TrackType
@@ -113,6 +144,8 @@ CAMERA: TrackSource
MICROPHONE: TrackSource
SCREEN_SHARE: TrackSource
SCREEN_SHARE_AUDIO: TrackSource
+DTEI_INVALID: DataTrackExtensionID
+DTEI_PARTICIPANT_SID: DataTrackExtensionID
LOW: VideoQuality
MEDIUM: VideoQuality
HIGH: VideoQuality
@@ -134,6 +167,13 @@ STATE_MISMATCH: DisconnectReason
JOIN_FAILURE: DisconnectReason
MIGRATION: DisconnectReason
SIGNAL_CLOSE: DisconnectReason
+ROOM_CLOSED: DisconnectReason
+USER_UNAVAILABLE: DisconnectReason
+USER_REJECTED: DisconnectReason
+SIP_TRUNK_FAILURE: DisconnectReason
+CONNECTION_TIMEOUT: DisconnectReason
+MEDIA_FAILURE: DisconnectReason
+AGENT_ERROR: DisconnectReason
RR_UNKNOWN: ReconnectReason
RR_SIGNAL_DISCONNECTED: ReconnectReason
RR_PUBLISHER_FAILED: ReconnectReason
@@ -148,15 +188,45 @@ TF_AUTO_GAIN_CONTROL: AudioTrackFeature
TF_ECHO_CANCELLATION: AudioTrackFeature
TF_NOISE_SUPPRESSION: AudioTrackFeature
TF_ENHANCED_NOISE_CANCELLATION: AudioTrackFeature
+TF_PRECONNECT_BUFFER: AudioTrackFeature
+PTF_USER_TIMESTAMP: PacketTrailerFeature
+PTF_FRAME_ID: PacketTrailerFeature
+
+class Pagination(_message.Message):
+ __slots__ = ("after_id", "limit")
+ AFTER_ID_FIELD_NUMBER: _ClassVar[int]
+ LIMIT_FIELD_NUMBER: _ClassVar[int]
+ after_id: str
+ limit: int
+ def __init__(self, after_id: _Optional[str] = ..., limit: _Optional[int] = ...) -> None: ...
+
+class TokenPagination(_message.Message):
+ __slots__ = ("token",)
+ TOKEN_FIELD_NUMBER: _ClassVar[int]
+ token: str
+ def __init__(self, token: _Optional[str] = ...) -> None: ...
+
+class ListUpdate(_message.Message):
+ __slots__ = ("set", "add", "remove", "clear")
+ SET_FIELD_NUMBER: _ClassVar[int]
+ ADD_FIELD_NUMBER: _ClassVar[int]
+ REMOVE_FIELD_NUMBER: _ClassVar[int]
+ CLEAR_FIELD_NUMBER: _ClassVar[int]
+ set: _containers.RepeatedScalarFieldContainer[str]
+ add: _containers.RepeatedScalarFieldContainer[str]
+ remove: _containers.RepeatedScalarFieldContainer[str]
+ clear: bool
+ def __init__(self, set: _Optional[_Iterable[str]] = ..., add: _Optional[_Iterable[str]] = ..., remove: _Optional[_Iterable[str]] = ..., clear: bool = ...) -> None: ...
class Room(_message.Message):
- __slots__ = ("sid", "name", "empty_timeout", "departure_timeout", "max_participants", "creation_time", "turn_password", "enabled_codecs", "metadata", "num_participants", "num_publishers", "active_recording", "version")
+ __slots__ = ("sid", "name", "empty_timeout", "departure_timeout", "max_participants", "creation_time", "creation_time_ms", "turn_password", "enabled_codecs", "metadata", "num_participants", "num_publishers", "active_recording", "version")
SID_FIELD_NUMBER: _ClassVar[int]
NAME_FIELD_NUMBER: _ClassVar[int]
EMPTY_TIMEOUT_FIELD_NUMBER: _ClassVar[int]
DEPARTURE_TIMEOUT_FIELD_NUMBER: _ClassVar[int]
MAX_PARTICIPANTS_FIELD_NUMBER: _ClassVar[int]
CREATION_TIME_FIELD_NUMBER: _ClassVar[int]
+ CREATION_TIME_MS_FIELD_NUMBER: _ClassVar[int]
TURN_PASSWORD_FIELD_NUMBER: _ClassVar[int]
ENABLED_CODECS_FIELD_NUMBER: _ClassVar[int]
METADATA_FIELD_NUMBER: _ClassVar[int]
@@ -170,6 +240,7 @@ class Room(_message.Message):
departure_timeout: int
max_participants: int
creation_time: int
+ creation_time_ms: int
turn_password: str
enabled_codecs: _containers.RepeatedCompositeFieldContainer[Codec]
metadata: str
@@ -177,7 +248,7 @@ class Room(_message.Message):
num_publishers: int
active_recording: bool
version: TimedVersion
- def __init__(self, sid: _Optional[str] = ..., name: _Optional[str] = ..., empty_timeout: _Optional[int] = ..., departure_timeout: _Optional[int] = ..., max_participants: _Optional[int] = ..., creation_time: _Optional[int] = ..., turn_password: _Optional[str] = ..., enabled_codecs: _Optional[_Iterable[_Union[Codec, _Mapping]]] = ..., metadata: _Optional[str] = ..., num_participants: _Optional[int] = ..., num_publishers: _Optional[int] = ..., active_recording: bool = ..., version: _Optional[_Union[TimedVersion, _Mapping]] = ...) -> None: ...
+ def __init__(self, sid: _Optional[str] = ..., name: _Optional[str] = ..., empty_timeout: _Optional[int] = ..., departure_timeout: _Optional[int] = ..., max_participants: _Optional[int] = ..., creation_time: _Optional[int] = ..., creation_time_ms: _Optional[int] = ..., turn_password: _Optional[str] = ..., enabled_codecs: _Optional[_Iterable[_Union[Codec, _Mapping]]] = ..., metadata: _Optional[str] = ..., num_participants: _Optional[int] = ..., num_publishers: _Optional[int] = ..., active_recording: bool = ..., version: _Optional[_Union[TimedVersion, _Mapping]] = ...) -> None: ...
class Codec(_message.Message):
__slots__ = ("mime", "fmtp_line")
@@ -198,7 +269,7 @@ class PlayoutDelay(_message.Message):
def __init__(self, enabled: bool = ..., min: _Optional[int] = ..., max: _Optional[int] = ...) -> None: ...
class ParticipantPermission(_message.Message):
- __slots__ = ("can_subscribe", "can_publish", "can_publish_data", "can_publish_sources", "hidden", "recorder", "can_update_metadata", "agent")
+ __slots__ = ("can_subscribe", "can_publish", "can_publish_data", "can_publish_sources", "hidden", "recorder", "can_update_metadata", "agent", "can_subscribe_metrics", "can_manage_agent_session")
CAN_SUBSCRIBE_FIELD_NUMBER: _ClassVar[int]
CAN_PUBLISH_FIELD_NUMBER: _ClassVar[int]
CAN_PUBLISH_DATA_FIELD_NUMBER: _ClassVar[int]
@@ -207,6 +278,8 @@ class ParticipantPermission(_message.Message):
RECORDER_FIELD_NUMBER: _ClassVar[int]
CAN_UPDATE_METADATA_FIELD_NUMBER: _ClassVar[int]
AGENT_FIELD_NUMBER: _ClassVar[int]
+ CAN_SUBSCRIBE_METRICS_FIELD_NUMBER: _ClassVar[int]
+ CAN_MANAGE_AGENT_SESSION_FIELD_NUMBER: _ClassVar[int]
can_subscribe: bool
can_publish: bool
can_publish_data: bool
@@ -215,10 +288,12 @@ class ParticipantPermission(_message.Message):
recorder: bool
can_update_metadata: bool
agent: bool
- def __init__(self, can_subscribe: bool = ..., can_publish: bool = ..., can_publish_data: bool = ..., can_publish_sources: _Optional[_Iterable[_Union[TrackSource, str]]] = ..., hidden: bool = ..., recorder: bool = ..., can_update_metadata: bool = ..., agent: bool = ...) -> None: ...
+ can_subscribe_metrics: bool
+ can_manage_agent_session: bool
+ def __init__(self, can_subscribe: bool = ..., can_publish: bool = ..., can_publish_data: bool = ..., can_publish_sources: _Optional[_Iterable[_Union[TrackSource, str]]] = ..., hidden: bool = ..., recorder: bool = ..., can_update_metadata: bool = ..., agent: bool = ..., can_subscribe_metrics: bool = ..., can_manage_agent_session: bool = ...) -> None: ...
class ParticipantInfo(_message.Message):
- __slots__ = ("sid", "identity", "state", "tracks", "metadata", "joined_at", "name", "version", "permission", "region", "is_publisher", "kind", "attributes")
+ __slots__ = ("sid", "identity", "state", "tracks", "metadata", "joined_at", "joined_at_ms", "name", "version", "permission", "region", "is_publisher", "kind", "attributes", "disconnect_reason", "kind_details", "data_tracks", "client_protocol")
class State(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
JOINING: _ClassVar[ParticipantInfo.State]
@@ -236,11 +311,27 @@ class ParticipantInfo(_message.Message):
EGRESS: _ClassVar[ParticipantInfo.Kind]
SIP: _ClassVar[ParticipantInfo.Kind]
AGENT: _ClassVar[ParticipantInfo.Kind]
+ CONNECTOR: _ClassVar[ParticipantInfo.Kind]
+ BRIDGE: _ClassVar[ParticipantInfo.Kind]
STANDARD: ParticipantInfo.Kind
INGRESS: ParticipantInfo.Kind
EGRESS: ParticipantInfo.Kind
SIP: ParticipantInfo.Kind
AGENT: ParticipantInfo.Kind
+ CONNECTOR: ParticipantInfo.Kind
+ BRIDGE: ParticipantInfo.Kind
+ class KindDetail(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ CLOUD_AGENT: _ClassVar[ParticipantInfo.KindDetail]
+ FORWARDED: _ClassVar[ParticipantInfo.KindDetail]
+ CONNECTOR_WHATSAPP: _ClassVar[ParticipantInfo.KindDetail]
+ CONNECTOR_TWILIO: _ClassVar[ParticipantInfo.KindDetail]
+ BRIDGE_RTSP: _ClassVar[ParticipantInfo.KindDetail]
+ CLOUD_AGENT: ParticipantInfo.KindDetail
+ FORWARDED: ParticipantInfo.KindDetail
+ CONNECTOR_WHATSAPP: ParticipantInfo.KindDetail
+ CONNECTOR_TWILIO: ParticipantInfo.KindDetail
+ BRIDGE_RTSP: ParticipantInfo.KindDetail
class AttributesEntry(_message.Message):
__slots__ = ("key", "value")
KEY_FIELD_NUMBER: _ClassVar[int]
@@ -254,6 +345,7 @@ class ParticipantInfo(_message.Message):
TRACKS_FIELD_NUMBER: _ClassVar[int]
METADATA_FIELD_NUMBER: _ClassVar[int]
JOINED_AT_FIELD_NUMBER: _ClassVar[int]
+ JOINED_AT_MS_FIELD_NUMBER: _ClassVar[int]
NAME_FIELD_NUMBER: _ClassVar[int]
VERSION_FIELD_NUMBER: _ClassVar[int]
PERMISSION_FIELD_NUMBER: _ClassVar[int]
@@ -261,12 +353,17 @@ class ParticipantInfo(_message.Message):
IS_PUBLISHER_FIELD_NUMBER: _ClassVar[int]
KIND_FIELD_NUMBER: _ClassVar[int]
ATTRIBUTES_FIELD_NUMBER: _ClassVar[int]
+ DISCONNECT_REASON_FIELD_NUMBER: _ClassVar[int]
+ KIND_DETAILS_FIELD_NUMBER: _ClassVar[int]
+ DATA_TRACKS_FIELD_NUMBER: _ClassVar[int]
+ CLIENT_PROTOCOL_FIELD_NUMBER: _ClassVar[int]
sid: str
identity: str
state: ParticipantInfo.State
tracks: _containers.RepeatedCompositeFieldContainer[TrackInfo]
metadata: str
joined_at: int
+ joined_at_ms: int
name: str
version: int
permission: ParticipantPermission
@@ -274,7 +371,11 @@ class ParticipantInfo(_message.Message):
is_publisher: bool
kind: ParticipantInfo.Kind
attributes: _containers.ScalarMap[str, str]
- def __init__(self, sid: _Optional[str] = ..., identity: _Optional[str] = ..., state: _Optional[_Union[ParticipantInfo.State, str]] = ..., tracks: _Optional[_Iterable[_Union[TrackInfo, _Mapping]]] = ..., metadata: _Optional[str] = ..., joined_at: _Optional[int] = ..., name: _Optional[str] = ..., version: _Optional[int] = ..., permission: _Optional[_Union[ParticipantPermission, _Mapping]] = ..., region: _Optional[str] = ..., is_publisher: bool = ..., kind: _Optional[_Union[ParticipantInfo.Kind, str]] = ..., attributes: _Optional[_Mapping[str, str]] = ...) -> None: ...
+ disconnect_reason: DisconnectReason
+ kind_details: _containers.RepeatedScalarFieldContainer[ParticipantInfo.KindDetail]
+ data_tracks: _containers.RepeatedCompositeFieldContainer[DataTrackInfo]
+ client_protocol: int
+ def __init__(self, sid: _Optional[str] = ..., identity: _Optional[str] = ..., state: _Optional[_Union[ParticipantInfo.State, str]] = ..., tracks: _Optional[_Iterable[_Union[TrackInfo, _Mapping]]] = ..., metadata: _Optional[str] = ..., joined_at: _Optional[int] = ..., joined_at_ms: _Optional[int] = ..., name: _Optional[str] = ..., version: _Optional[int] = ..., permission: _Optional[_Union[ParticipantPermission, _Mapping]] = ..., region: _Optional[str] = ..., is_publisher: bool = ..., kind: _Optional[_Union[ParticipantInfo.Kind, str]] = ..., attributes: _Optional[_Mapping[str, str]] = ..., disconnect_reason: _Optional[_Union[DisconnectReason, str]] = ..., kind_details: _Optional[_Iterable[_Union[ParticipantInfo.KindDetail, str]]] = ..., data_tracks: _Optional[_Iterable[_Union[DataTrackInfo, _Mapping]]] = ..., client_protocol: _Optional[int] = ...) -> None: ...
class Encryption(_message.Message):
__slots__ = ()
@@ -289,19 +390,23 @@ class Encryption(_message.Message):
def __init__(self) -> None: ...
class SimulcastCodecInfo(_message.Message):
- __slots__ = ("mime_type", "mid", "cid", "layers")
+ __slots__ = ("mime_type", "mid", "cid", "layers", "video_layer_mode", "sdp_cid")
MIME_TYPE_FIELD_NUMBER: _ClassVar[int]
MID_FIELD_NUMBER: _ClassVar[int]
CID_FIELD_NUMBER: _ClassVar[int]
LAYERS_FIELD_NUMBER: _ClassVar[int]
+ VIDEO_LAYER_MODE_FIELD_NUMBER: _ClassVar[int]
+ SDP_CID_FIELD_NUMBER: _ClassVar[int]
mime_type: str
mid: str
cid: str
layers: _containers.RepeatedCompositeFieldContainer[VideoLayer]
- def __init__(self, mime_type: _Optional[str] = ..., mid: _Optional[str] = ..., cid: _Optional[str] = ..., layers: _Optional[_Iterable[_Union[VideoLayer, _Mapping]]] = ...) -> None: ...
+ video_layer_mode: VideoLayer.Mode
+ sdp_cid: str
+ def __init__(self, mime_type: _Optional[str] = ..., mid: _Optional[str] = ..., cid: _Optional[str] = ..., layers: _Optional[_Iterable[_Union[VideoLayer, _Mapping]]] = ..., video_layer_mode: _Optional[_Union[VideoLayer.Mode, str]] = ..., sdp_cid: _Optional[str] = ...) -> None: ...
class TrackInfo(_message.Message):
- __slots__ = ("sid", "type", "name", "muted", "width", "height", "simulcast", "disable_dtx", "source", "layers", "mime_type", "mid", "codecs", "stereo", "disable_red", "encryption", "stream", "version", "audio_features")
+ __slots__ = ("sid", "type", "name", "muted", "width", "height", "simulcast", "disable_dtx", "source", "layers", "mime_type", "mid", "codecs", "stereo", "disable_red", "encryption", "stream", "version", "audio_features", "backup_codec_policy", "packet_trailer_features")
SID_FIELD_NUMBER: _ClassVar[int]
TYPE_FIELD_NUMBER: _ClassVar[int]
NAME_FIELD_NUMBER: _ClassVar[int]
@@ -321,6 +426,8 @@ class TrackInfo(_message.Message):
STREAM_FIELD_NUMBER: _ClassVar[int]
VERSION_FIELD_NUMBER: _ClassVar[int]
AUDIO_FEATURES_FIELD_NUMBER: _ClassVar[int]
+ BACKUP_CODEC_POLICY_FIELD_NUMBER: _ClassVar[int]
+ PACKET_TRAILER_FEATURES_FIELD_NUMBER: _ClassVar[int]
sid: str
type: TrackType
name: str
@@ -340,24 +447,68 @@ class TrackInfo(_message.Message):
stream: str
version: TimedVersion
audio_features: _containers.RepeatedScalarFieldContainer[AudioTrackFeature]
- def __init__(self, sid: _Optional[str] = ..., type: _Optional[_Union[TrackType, str]] = ..., name: _Optional[str] = ..., muted: bool = ..., width: _Optional[int] = ..., height: _Optional[int] = ..., simulcast: bool = ..., disable_dtx: bool = ..., source: _Optional[_Union[TrackSource, str]] = ..., layers: _Optional[_Iterable[_Union[VideoLayer, _Mapping]]] = ..., mime_type: _Optional[str] = ..., mid: _Optional[str] = ..., codecs: _Optional[_Iterable[_Union[SimulcastCodecInfo, _Mapping]]] = ..., stereo: bool = ..., disable_red: bool = ..., encryption: _Optional[_Union[Encryption.Type, str]] = ..., stream: _Optional[str] = ..., version: _Optional[_Union[TimedVersion, _Mapping]] = ..., audio_features: _Optional[_Iterable[_Union[AudioTrackFeature, str]]] = ...) -> None: ...
+ backup_codec_policy: BackupCodecPolicy
+ packet_trailer_features: _containers.RepeatedScalarFieldContainer[PacketTrailerFeature]
+ def __init__(self, sid: _Optional[str] = ..., type: _Optional[_Union[TrackType, str]] = ..., name: _Optional[str] = ..., muted: bool = ..., width: _Optional[int] = ..., height: _Optional[int] = ..., simulcast: bool = ..., disable_dtx: bool = ..., source: _Optional[_Union[TrackSource, str]] = ..., layers: _Optional[_Iterable[_Union[VideoLayer, _Mapping]]] = ..., mime_type: _Optional[str] = ..., mid: _Optional[str] = ..., codecs: _Optional[_Iterable[_Union[SimulcastCodecInfo, _Mapping]]] = ..., stereo: bool = ..., disable_red: bool = ..., encryption: _Optional[_Union[Encryption.Type, str]] = ..., stream: _Optional[str] = ..., version: _Optional[_Union[TimedVersion, _Mapping]] = ..., audio_features: _Optional[_Iterable[_Union[AudioTrackFeature, str]]] = ..., backup_codec_policy: _Optional[_Union[BackupCodecPolicy, str]] = ..., packet_trailer_features: _Optional[_Iterable[_Union[PacketTrailerFeature, str]]] = ...) -> None: ...
+
+class DataTrackInfo(_message.Message):
+ __slots__ = ("pub_handle", "sid", "name", "encryption")
+ PUB_HANDLE_FIELD_NUMBER: _ClassVar[int]
+ SID_FIELD_NUMBER: _ClassVar[int]
+ NAME_FIELD_NUMBER: _ClassVar[int]
+ ENCRYPTION_FIELD_NUMBER: _ClassVar[int]
+ pub_handle: int
+ sid: str
+ name: str
+ encryption: Encryption.Type
+ def __init__(self, pub_handle: _Optional[int] = ..., sid: _Optional[str] = ..., name: _Optional[str] = ..., encryption: _Optional[_Union[Encryption.Type, str]] = ...) -> None: ...
+
+class DataTrackExtensionParticipantSid(_message.Message):
+ __slots__ = ("id", "participant_sid")
+ ID_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_SID_FIELD_NUMBER: _ClassVar[int]
+ id: DataTrackExtensionID
+ participant_sid: str
+ def __init__(self, id: _Optional[_Union[DataTrackExtensionID, str]] = ..., participant_sid: _Optional[str] = ...) -> None: ...
+
+class DataTrackSubscriptionOptions(_message.Message):
+ __slots__ = ("target_fps",)
+ TARGET_FPS_FIELD_NUMBER: _ClassVar[int]
+ target_fps: int
+ def __init__(self, target_fps: _Optional[int] = ...) -> None: ...
class VideoLayer(_message.Message):
- __slots__ = ("quality", "width", "height", "bitrate", "ssrc")
+ __slots__ = ("quality", "width", "height", "bitrate", "ssrc", "spatial_layer", "rid", "repair_ssrc")
+ class Mode(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ MODE_UNUSED: _ClassVar[VideoLayer.Mode]
+ ONE_SPATIAL_LAYER_PER_STREAM: _ClassVar[VideoLayer.Mode]
+ MULTIPLE_SPATIAL_LAYERS_PER_STREAM: _ClassVar[VideoLayer.Mode]
+ ONE_SPATIAL_LAYER_PER_STREAM_INCOMPLETE_RTCP_SR: _ClassVar[VideoLayer.Mode]
+ MODE_UNUSED: VideoLayer.Mode
+ ONE_SPATIAL_LAYER_PER_STREAM: VideoLayer.Mode
+ MULTIPLE_SPATIAL_LAYERS_PER_STREAM: VideoLayer.Mode
+ ONE_SPATIAL_LAYER_PER_STREAM_INCOMPLETE_RTCP_SR: VideoLayer.Mode
QUALITY_FIELD_NUMBER: _ClassVar[int]
WIDTH_FIELD_NUMBER: _ClassVar[int]
HEIGHT_FIELD_NUMBER: _ClassVar[int]
BITRATE_FIELD_NUMBER: _ClassVar[int]
SSRC_FIELD_NUMBER: _ClassVar[int]
+ SPATIAL_LAYER_FIELD_NUMBER: _ClassVar[int]
+ RID_FIELD_NUMBER: _ClassVar[int]
+ REPAIR_SSRC_FIELD_NUMBER: _ClassVar[int]
quality: VideoQuality
width: int
height: int
bitrate: int
ssrc: int
- def __init__(self, quality: _Optional[_Union[VideoQuality, str]] = ..., width: _Optional[int] = ..., height: _Optional[int] = ..., bitrate: _Optional[int] = ..., ssrc: _Optional[int] = ...) -> None: ...
+ spatial_layer: int
+ rid: str
+ repair_ssrc: int
+ def __init__(self, quality: _Optional[_Union[VideoQuality, str]] = ..., width: _Optional[int] = ..., height: _Optional[int] = ..., bitrate: _Optional[int] = ..., ssrc: _Optional[int] = ..., spatial_layer: _Optional[int] = ..., rid: _Optional[str] = ..., repair_ssrc: _Optional[int] = ...) -> None: ...
class DataPacket(_message.Message):
- __slots__ = ("kind", "participant_identity", "destination_identities", "user", "speaker", "sip_dtmf", "transcription")
+ __slots__ = ("kind", "participant_identity", "destination_identities", "user", "speaker", "sip_dtmf", "transcription", "metrics", "chat_message", "rpc_request", "rpc_ack", "rpc_response", "stream_header", "stream_chunk", "stream_trailer", "encrypted_packet", "sequence", "participant_sid")
class Kind(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
RELIABLE: _ClassVar[DataPacket.Kind]
@@ -371,6 +522,17 @@ class DataPacket(_message.Message):
SPEAKER_FIELD_NUMBER: _ClassVar[int]
SIP_DTMF_FIELD_NUMBER: _ClassVar[int]
TRANSCRIPTION_FIELD_NUMBER: _ClassVar[int]
+ METRICS_FIELD_NUMBER: _ClassVar[int]
+ CHAT_MESSAGE_FIELD_NUMBER: _ClassVar[int]
+ RPC_REQUEST_FIELD_NUMBER: _ClassVar[int]
+ RPC_ACK_FIELD_NUMBER: _ClassVar[int]
+ RPC_RESPONSE_FIELD_NUMBER: _ClassVar[int]
+ STREAM_HEADER_FIELD_NUMBER: _ClassVar[int]
+ STREAM_CHUNK_FIELD_NUMBER: _ClassVar[int]
+ STREAM_TRAILER_FIELD_NUMBER: _ClassVar[int]
+ ENCRYPTED_PACKET_FIELD_NUMBER: _ClassVar[int]
+ SEQUENCE_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_SID_FIELD_NUMBER: _ClassVar[int]
kind: DataPacket.Kind
participant_identity: str
destination_identities: _containers.RepeatedScalarFieldContainer[str]
@@ -378,7 +540,50 @@ class DataPacket(_message.Message):
speaker: ActiveSpeakerUpdate
sip_dtmf: SipDTMF
transcription: Transcription
- def __init__(self, kind: _Optional[_Union[DataPacket.Kind, str]] = ..., participant_identity: _Optional[str] = ..., destination_identities: _Optional[_Iterable[str]] = ..., user: _Optional[_Union[UserPacket, _Mapping]] = ..., speaker: _Optional[_Union[ActiveSpeakerUpdate, _Mapping]] = ..., sip_dtmf: _Optional[_Union[SipDTMF, _Mapping]] = ..., transcription: _Optional[_Union[Transcription, _Mapping]] = ...) -> None: ...
+ metrics: _metrics.MetricsBatch
+ chat_message: ChatMessage
+ rpc_request: RpcRequest
+ rpc_ack: RpcAck
+ rpc_response: RpcResponse
+ stream_header: DataStream.Header
+ stream_chunk: DataStream.Chunk
+ stream_trailer: DataStream.Trailer
+ encrypted_packet: EncryptedPacket
+ sequence: int
+ participant_sid: str
+ def __init__(self, kind: _Optional[_Union[DataPacket.Kind, str]] = ..., participant_identity: _Optional[str] = ..., destination_identities: _Optional[_Iterable[str]] = ..., user: _Optional[_Union[UserPacket, _Mapping]] = ..., speaker: _Optional[_Union[ActiveSpeakerUpdate, _Mapping]] = ..., sip_dtmf: _Optional[_Union[SipDTMF, _Mapping]] = ..., transcription: _Optional[_Union[Transcription, _Mapping]] = ..., metrics: _Optional[_Union[_metrics.MetricsBatch, _Mapping]] = ..., chat_message: _Optional[_Union[ChatMessage, _Mapping]] = ..., rpc_request: _Optional[_Union[RpcRequest, _Mapping]] = ..., rpc_ack: _Optional[_Union[RpcAck, _Mapping]] = ..., rpc_response: _Optional[_Union[RpcResponse, _Mapping]] = ..., stream_header: _Optional[_Union[DataStream.Header, _Mapping]] = ..., stream_chunk: _Optional[_Union[DataStream.Chunk, _Mapping]] = ..., stream_trailer: _Optional[_Union[DataStream.Trailer, _Mapping]] = ..., encrypted_packet: _Optional[_Union[EncryptedPacket, _Mapping]] = ..., sequence: _Optional[int] = ..., participant_sid: _Optional[str] = ...) -> None: ...
+
+class EncryptedPacket(_message.Message):
+ __slots__ = ("encryption_type", "iv", "key_index", "encrypted_value")
+ ENCRYPTION_TYPE_FIELD_NUMBER: _ClassVar[int]
+ IV_FIELD_NUMBER: _ClassVar[int]
+ KEY_INDEX_FIELD_NUMBER: _ClassVar[int]
+ ENCRYPTED_VALUE_FIELD_NUMBER: _ClassVar[int]
+ encryption_type: Encryption.Type
+ iv: bytes
+ key_index: int
+ encrypted_value: bytes
+ def __init__(self, encryption_type: _Optional[_Union[Encryption.Type, str]] = ..., iv: _Optional[bytes] = ..., key_index: _Optional[int] = ..., encrypted_value: _Optional[bytes] = ...) -> None: ...
+
+class EncryptedPacketPayload(_message.Message):
+ __slots__ = ("user", "chat_message", "rpc_request", "rpc_ack", "rpc_response", "stream_header", "stream_chunk", "stream_trailer")
+ USER_FIELD_NUMBER: _ClassVar[int]
+ CHAT_MESSAGE_FIELD_NUMBER: _ClassVar[int]
+ RPC_REQUEST_FIELD_NUMBER: _ClassVar[int]
+ RPC_ACK_FIELD_NUMBER: _ClassVar[int]
+ RPC_RESPONSE_FIELD_NUMBER: _ClassVar[int]
+ STREAM_HEADER_FIELD_NUMBER: _ClassVar[int]
+ STREAM_CHUNK_FIELD_NUMBER: _ClassVar[int]
+ STREAM_TRAILER_FIELD_NUMBER: _ClassVar[int]
+ user: UserPacket
+ chat_message: ChatMessage
+ rpc_request: RpcRequest
+ rpc_ack: RpcAck
+ rpc_response: RpcResponse
+ stream_header: DataStream.Header
+ stream_chunk: DataStream.Chunk
+ stream_trailer: DataStream.Trailer
+ def __init__(self, user: _Optional[_Union[UserPacket, _Mapping]] = ..., chat_message: _Optional[_Union[ChatMessage, _Mapping]] = ..., rpc_request: _Optional[_Union[RpcRequest, _Mapping]] = ..., rpc_ack: _Optional[_Union[RpcAck, _Mapping]] = ..., rpc_response: _Optional[_Union[RpcResponse, _Mapping]] = ..., stream_header: _Optional[_Union[DataStream.Header, _Mapping]] = ..., stream_chunk: _Optional[_Union[DataStream.Chunk, _Mapping]] = ..., stream_trailer: _Optional[_Union[DataStream.Trailer, _Mapping]] = ...) -> None: ...
class ActiveSpeakerUpdate(_message.Message):
__slots__ = ("speakers",)
@@ -397,7 +602,7 @@ class SpeakerInfo(_message.Message):
def __init__(self, sid: _Optional[str] = ..., level: _Optional[float] = ..., active: bool = ...) -> None: ...
class UserPacket(_message.Message):
- __slots__ = ("participant_sid", "participant_identity", "payload", "destination_sids", "destination_identities", "topic", "id", "start_time", "end_time")
+ __slots__ = ("participant_sid", "participant_identity", "payload", "destination_sids", "destination_identities", "topic", "id", "start_time", "end_time", "nonce")
PARTICIPANT_SID_FIELD_NUMBER: _ClassVar[int]
PARTICIPANT_IDENTITY_FIELD_NUMBER: _ClassVar[int]
PAYLOAD_FIELD_NUMBER: _ClassVar[int]
@@ -407,6 +612,7 @@ class UserPacket(_message.Message):
ID_FIELD_NUMBER: _ClassVar[int]
START_TIME_FIELD_NUMBER: _ClassVar[int]
END_TIME_FIELD_NUMBER: _ClassVar[int]
+ NONCE_FIELD_NUMBER: _ClassVar[int]
participant_sid: str
participant_identity: str
payload: bytes
@@ -416,7 +622,8 @@ class UserPacket(_message.Message):
id: str
start_time: int
end_time: int
- def __init__(self, participant_sid: _Optional[str] = ..., participant_identity: _Optional[str] = ..., payload: _Optional[bytes] = ..., destination_sids: _Optional[_Iterable[str]] = ..., destination_identities: _Optional[_Iterable[str]] = ..., topic: _Optional[str] = ..., id: _Optional[str] = ..., start_time: _Optional[int] = ..., end_time: _Optional[int] = ...) -> None: ...
+ nonce: bytes
+ def __init__(self, participant_sid: _Optional[str] = ..., participant_identity: _Optional[str] = ..., payload: _Optional[bytes] = ..., destination_sids: _Optional[_Iterable[str]] = ..., destination_identities: _Optional[_Iterable[str]] = ..., topic: _Optional[str] = ..., id: _Optional[str] = ..., start_time: _Optional[int] = ..., end_time: _Optional[int] = ..., nonce: _Optional[bytes] = ...) -> None: ...
class SipDTMF(_message.Message):
__slots__ = ("code", "digit")
@@ -452,6 +659,66 @@ class TranscriptionSegment(_message.Message):
language: str
def __init__(self, id: _Optional[str] = ..., text: _Optional[str] = ..., start_time: _Optional[int] = ..., end_time: _Optional[int] = ..., final: bool = ..., language: _Optional[str] = ...) -> None: ...
+class ChatMessage(_message.Message):
+ __slots__ = ("id", "timestamp", "edit_timestamp", "message", "deleted", "generated")
+ ID_FIELD_NUMBER: _ClassVar[int]
+ TIMESTAMP_FIELD_NUMBER: _ClassVar[int]
+ EDIT_TIMESTAMP_FIELD_NUMBER: _ClassVar[int]
+ MESSAGE_FIELD_NUMBER: _ClassVar[int]
+ DELETED_FIELD_NUMBER: _ClassVar[int]
+ GENERATED_FIELD_NUMBER: _ClassVar[int]
+ id: str
+ timestamp: int
+ edit_timestamp: int
+ message: str
+ deleted: bool
+ generated: bool
+ def __init__(self, id: _Optional[str] = ..., timestamp: _Optional[int] = ..., edit_timestamp: _Optional[int] = ..., message: _Optional[str] = ..., deleted: bool = ..., generated: bool = ...) -> None: ...
+
+class RpcRequest(_message.Message):
+ __slots__ = ("id", "method", "payload", "response_timeout_ms", "version", "compressed_payload")
+ ID_FIELD_NUMBER: _ClassVar[int]
+ METHOD_FIELD_NUMBER: _ClassVar[int]
+ PAYLOAD_FIELD_NUMBER: _ClassVar[int]
+ RESPONSE_TIMEOUT_MS_FIELD_NUMBER: _ClassVar[int]
+ VERSION_FIELD_NUMBER: _ClassVar[int]
+ COMPRESSED_PAYLOAD_FIELD_NUMBER: _ClassVar[int]
+ id: str
+ method: str
+ payload: str
+ response_timeout_ms: int
+ version: int
+ compressed_payload: bytes
+ def __init__(self, id: _Optional[str] = ..., method: _Optional[str] = ..., payload: _Optional[str] = ..., response_timeout_ms: _Optional[int] = ..., version: _Optional[int] = ..., compressed_payload: _Optional[bytes] = ...) -> None: ...
+
+class RpcAck(_message.Message):
+ __slots__ = ("request_id",)
+ REQUEST_ID_FIELD_NUMBER: _ClassVar[int]
+ request_id: str
+ def __init__(self, request_id: _Optional[str] = ...) -> None: ...
+
+class RpcResponse(_message.Message):
+ __slots__ = ("request_id", "payload", "error", "compressed_payload")
+ REQUEST_ID_FIELD_NUMBER: _ClassVar[int]
+ PAYLOAD_FIELD_NUMBER: _ClassVar[int]
+ ERROR_FIELD_NUMBER: _ClassVar[int]
+ COMPRESSED_PAYLOAD_FIELD_NUMBER: _ClassVar[int]
+ request_id: str
+ payload: str
+ error: RpcError
+ compressed_payload: bytes
+ def __init__(self, request_id: _Optional[str] = ..., payload: _Optional[str] = ..., error: _Optional[_Union[RpcError, _Mapping]] = ..., compressed_payload: _Optional[bytes] = ...) -> None: ...
+
+class RpcError(_message.Message):
+ __slots__ = ("code", "message", "data")
+ CODE_FIELD_NUMBER: _ClassVar[int]
+ MESSAGE_FIELD_NUMBER: _ClassVar[int]
+ DATA_FIELD_NUMBER: _ClassVar[int]
+ code: int
+ message: str
+ data: str
+ def __init__(self, code: _Optional[int] = ..., message: _Optional[str] = ..., data: _Optional[str] = ...) -> None: ...
+
class ParticipantTracks(_message.Message):
__slots__ = ("participant_sid", "track_sids")
PARTICIPANT_SID_FIELD_NUMBER: _ClassVar[int]
@@ -485,7 +752,7 @@ class ServerInfo(_message.Message):
def __init__(self, edition: _Optional[_Union[ServerInfo.Edition, str]] = ..., version: _Optional[str] = ..., protocol: _Optional[int] = ..., region: _Optional[str] = ..., node_id: _Optional[str] = ..., debug_info: _Optional[str] = ..., agent_protocol: _Optional[int] = ...) -> None: ...
class ClientInfo(_message.Message):
- __slots__ = ("sdk", "version", "protocol", "os", "os_version", "device_model", "browser", "browser_version", "address", "network")
+ __slots__ = ("sdk", "version", "protocol", "os", "os_version", "device_model", "browser", "browser_version", "address", "network", "other_sdks", "client_protocol", "capabilities")
class SDK(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
UNKNOWN: _ClassVar[ClientInfo.SDK]
@@ -499,6 +766,10 @@ class ClientInfo(_message.Message):
RUST: _ClassVar[ClientInfo.SDK]
PYTHON: _ClassVar[ClientInfo.SDK]
CPP: _ClassVar[ClientInfo.SDK]
+ UNITY_WEB: _ClassVar[ClientInfo.SDK]
+ NODE: _ClassVar[ClientInfo.SDK]
+ UNREAL: _ClassVar[ClientInfo.SDK]
+ ESP32: _ClassVar[ClientInfo.SDK]
UNKNOWN: ClientInfo.SDK
JS: ClientInfo.SDK
SWIFT: ClientInfo.SDK
@@ -510,6 +781,16 @@ class ClientInfo(_message.Message):
RUST: ClientInfo.SDK
PYTHON: ClientInfo.SDK
CPP: ClientInfo.SDK
+ UNITY_WEB: ClientInfo.SDK
+ NODE: ClientInfo.SDK
+ UNREAL: ClientInfo.SDK
+ ESP32: ClientInfo.SDK
+ class Capability(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ CAP_UNUSED: _ClassVar[ClientInfo.Capability]
+ CAP_PACKET_TRAILER: _ClassVar[ClientInfo.Capability]
+ CAP_UNUSED: ClientInfo.Capability
+ CAP_PACKET_TRAILER: ClientInfo.Capability
SDK_FIELD_NUMBER: _ClassVar[int]
VERSION_FIELD_NUMBER: _ClassVar[int]
PROTOCOL_FIELD_NUMBER: _ClassVar[int]
@@ -520,6 +801,9 @@ class ClientInfo(_message.Message):
BROWSER_VERSION_FIELD_NUMBER: _ClassVar[int]
ADDRESS_FIELD_NUMBER: _ClassVar[int]
NETWORK_FIELD_NUMBER: _ClassVar[int]
+ OTHER_SDKS_FIELD_NUMBER: _ClassVar[int]
+ CLIENT_PROTOCOL_FIELD_NUMBER: _ClassVar[int]
+ CAPABILITIES_FIELD_NUMBER: _ClassVar[int]
sdk: ClientInfo.SDK
version: str
protocol: int
@@ -530,7 +814,10 @@ class ClientInfo(_message.Message):
browser_version: str
address: str
network: str
- def __init__(self, sdk: _Optional[_Union[ClientInfo.SDK, str]] = ..., version: _Optional[str] = ..., protocol: _Optional[int] = ..., os: _Optional[str] = ..., os_version: _Optional[str] = ..., device_model: _Optional[str] = ..., browser: _Optional[str] = ..., browser_version: _Optional[str] = ..., address: _Optional[str] = ..., network: _Optional[str] = ...) -> None: ...
+ other_sdks: str
+ client_protocol: int
+ capabilities: _containers.RepeatedScalarFieldContainer[ClientInfo.Capability]
+ def __init__(self, sdk: _Optional[_Union[ClientInfo.SDK, str]] = ..., version: _Optional[str] = ..., protocol: _Optional[int] = ..., os: _Optional[str] = ..., os_version: _Optional[str] = ..., device_model: _Optional[str] = ..., browser: _Optional[str] = ..., browser_version: _Optional[str] = ..., address: _Optional[str] = ..., network: _Optional[str] = ..., other_sdks: _Optional[str] = ..., client_protocol: _Optional[int] = ..., capabilities: _Optional[_Iterable[_Union[ClientInfo.Capability, str]]] = ...) -> None: ...
class ClientConfiguration(_message.Message):
__slots__ = ("video", "screen", "resume_connection", "disabled_codecs", "force_relay")
@@ -583,7 +870,7 @@ class RTPDrift(_message.Message):
def __init__(self, start_time: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., end_time: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., duration: _Optional[float] = ..., start_timestamp: _Optional[int] = ..., end_timestamp: _Optional[int] = ..., rtp_clock_ticks: _Optional[int] = ..., drift_samples: _Optional[int] = ..., drift_ms: _Optional[float] = ..., clock_rate: _Optional[float] = ...) -> None: ...
class RTPStats(_message.Message):
- __slots__ = ("start_time", "end_time", "duration", "packets", "packet_rate", "bytes", "header_bytes", "bitrate", "packets_lost", "packet_loss_rate", "packet_loss_percentage", "packets_duplicate", "packet_duplicate_rate", "bytes_duplicate", "header_bytes_duplicate", "bitrate_duplicate", "packets_padding", "packet_padding_rate", "bytes_padding", "header_bytes_padding", "bitrate_padding", "packets_out_of_order", "frames", "frame_rate", "jitter_current", "jitter_max", "gap_histogram", "nacks", "nack_acks", "nack_misses", "nack_repeated", "plis", "last_pli", "firs", "last_fir", "rtt_current", "rtt_max", "key_frames", "last_key_frame", "layer_lock_plis", "last_layer_lock_pli", "packet_drift", "report_drift", "rebased_report_drift")
+ __slots__ = ("start_time", "end_time", "duration", "packets", "packet_rate", "bytes", "header_bytes", "bitrate", "packets_lost", "packet_loss_rate", "packet_loss_percentage", "packets_duplicate", "packet_duplicate_rate", "bytes_duplicate", "header_bytes_duplicate", "bitrate_duplicate", "packets_padding", "packet_padding_rate", "bytes_padding", "header_bytes_padding", "bitrate_padding", "packets_out_of_order", "frames", "frame_rate", "jitter_current", "jitter_max", "gap_histogram", "nacks", "nack_acks", "nack_misses", "nack_repeated", "plis", "last_pli", "firs", "last_fir", "rtt_current", "rtt_max", "key_frames", "last_key_frame", "layer_lock_plis", "last_layer_lock_pli", "packet_drift", "ntp_report_drift", "rebased_report_drift", "received_report_drift")
class GapHistogramEntry(_message.Message):
__slots__ = ("key", "value")
KEY_FIELD_NUMBER: _ClassVar[int]
@@ -633,8 +920,9 @@ class RTPStats(_message.Message):
LAYER_LOCK_PLIS_FIELD_NUMBER: _ClassVar[int]
LAST_LAYER_LOCK_PLI_FIELD_NUMBER: _ClassVar[int]
PACKET_DRIFT_FIELD_NUMBER: _ClassVar[int]
- REPORT_DRIFT_FIELD_NUMBER: _ClassVar[int]
+ NTP_REPORT_DRIFT_FIELD_NUMBER: _ClassVar[int]
REBASED_REPORT_DRIFT_FIELD_NUMBER: _ClassVar[int]
+ RECEIVED_REPORT_DRIFT_FIELD_NUMBER: _ClassVar[int]
start_time: _timestamp_pb2.Timestamp
end_time: _timestamp_pb2.Timestamp
duration: float
@@ -677,9 +965,82 @@ class RTPStats(_message.Message):
layer_lock_plis: int
last_layer_lock_pli: _timestamp_pb2.Timestamp
packet_drift: RTPDrift
- report_drift: RTPDrift
+ ntp_report_drift: RTPDrift
rebased_report_drift: RTPDrift
- def __init__(self, start_time: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., end_time: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., duration: _Optional[float] = ..., packets: _Optional[int] = ..., packet_rate: _Optional[float] = ..., bytes: _Optional[int] = ..., header_bytes: _Optional[int] = ..., bitrate: _Optional[float] = ..., packets_lost: _Optional[int] = ..., packet_loss_rate: _Optional[float] = ..., packet_loss_percentage: _Optional[float] = ..., packets_duplicate: _Optional[int] = ..., packet_duplicate_rate: _Optional[float] = ..., bytes_duplicate: _Optional[int] = ..., header_bytes_duplicate: _Optional[int] = ..., bitrate_duplicate: _Optional[float] = ..., packets_padding: _Optional[int] = ..., packet_padding_rate: _Optional[float] = ..., bytes_padding: _Optional[int] = ..., header_bytes_padding: _Optional[int] = ..., bitrate_padding: _Optional[float] = ..., packets_out_of_order: _Optional[int] = ..., frames: _Optional[int] = ..., frame_rate: _Optional[float] = ..., jitter_current: _Optional[float] = ..., jitter_max: _Optional[float] = ..., gap_histogram: _Optional[_Mapping[int, int]] = ..., nacks: _Optional[int] = ..., nack_acks: _Optional[int] = ..., nack_misses: _Optional[int] = ..., nack_repeated: _Optional[int] = ..., plis: _Optional[int] = ..., last_pli: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., firs: _Optional[int] = ..., last_fir: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., rtt_current: _Optional[int] = ..., rtt_max: _Optional[int] = ..., key_frames: _Optional[int] = ..., last_key_frame: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., layer_lock_plis: _Optional[int] = ..., last_layer_lock_pli: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., packet_drift: _Optional[_Union[RTPDrift, _Mapping]] = ..., report_drift: _Optional[_Union[RTPDrift, _Mapping]] = ..., rebased_report_drift: _Optional[_Union[RTPDrift, _Mapping]] = ...) -> None: ...
+ received_report_drift: RTPDrift
+ def __init__(self, start_time: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., end_time: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., duration: _Optional[float] = ..., packets: _Optional[int] = ..., packet_rate: _Optional[float] = ..., bytes: _Optional[int] = ..., header_bytes: _Optional[int] = ..., bitrate: _Optional[float] = ..., packets_lost: _Optional[int] = ..., packet_loss_rate: _Optional[float] = ..., packet_loss_percentage: _Optional[float] = ..., packets_duplicate: _Optional[int] = ..., packet_duplicate_rate: _Optional[float] = ..., bytes_duplicate: _Optional[int] = ..., header_bytes_duplicate: _Optional[int] = ..., bitrate_duplicate: _Optional[float] = ..., packets_padding: _Optional[int] = ..., packet_padding_rate: _Optional[float] = ..., bytes_padding: _Optional[int] = ..., header_bytes_padding: _Optional[int] = ..., bitrate_padding: _Optional[float] = ..., packets_out_of_order: _Optional[int] = ..., frames: _Optional[int] = ..., frame_rate: _Optional[float] = ..., jitter_current: _Optional[float] = ..., jitter_max: _Optional[float] = ..., gap_histogram: _Optional[_Mapping[int, int]] = ..., nacks: _Optional[int] = ..., nack_acks: _Optional[int] = ..., nack_misses: _Optional[int] = ..., nack_repeated: _Optional[int] = ..., plis: _Optional[int] = ..., last_pli: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., firs: _Optional[int] = ..., last_fir: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., rtt_current: _Optional[int] = ..., rtt_max: _Optional[int] = ..., key_frames: _Optional[int] = ..., last_key_frame: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., layer_lock_plis: _Optional[int] = ..., last_layer_lock_pli: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., packet_drift: _Optional[_Union[RTPDrift, _Mapping]] = ..., ntp_report_drift: _Optional[_Union[RTPDrift, _Mapping]] = ..., rebased_report_drift: _Optional[_Union[RTPDrift, _Mapping]] = ..., received_report_drift: _Optional[_Union[RTPDrift, _Mapping]] = ...) -> None: ...
+
+class RTCPSenderReportState(_message.Message):
+ __slots__ = ("rtp_timestamp", "rtp_timestamp_ext", "ntp_timestamp", "at", "at_adjusted", "packets", "octets")
+ RTP_TIMESTAMP_FIELD_NUMBER: _ClassVar[int]
+ RTP_TIMESTAMP_EXT_FIELD_NUMBER: _ClassVar[int]
+ NTP_TIMESTAMP_FIELD_NUMBER: _ClassVar[int]
+ AT_FIELD_NUMBER: _ClassVar[int]
+ AT_ADJUSTED_FIELD_NUMBER: _ClassVar[int]
+ PACKETS_FIELD_NUMBER: _ClassVar[int]
+ OCTETS_FIELD_NUMBER: _ClassVar[int]
+ rtp_timestamp: int
+ rtp_timestamp_ext: int
+ ntp_timestamp: int
+ at: int
+ at_adjusted: int
+ packets: int
+ octets: int
+ def __init__(self, rtp_timestamp: _Optional[int] = ..., rtp_timestamp_ext: _Optional[int] = ..., ntp_timestamp: _Optional[int] = ..., at: _Optional[int] = ..., at_adjusted: _Optional[int] = ..., packets: _Optional[int] = ..., octets: _Optional[int] = ...) -> None: ...
+
+class RTPForwarderState(_message.Message):
+ __slots__ = ("started", "reference_layer_spatial", "pre_start_time", "ext_first_timestamp", "dummy_start_timestamp_offset", "rtp_munger", "vp8_munger", "sender_report_state")
+ STARTED_FIELD_NUMBER: _ClassVar[int]
+ REFERENCE_LAYER_SPATIAL_FIELD_NUMBER: _ClassVar[int]
+ PRE_START_TIME_FIELD_NUMBER: _ClassVar[int]
+ EXT_FIRST_TIMESTAMP_FIELD_NUMBER: _ClassVar[int]
+ DUMMY_START_TIMESTAMP_OFFSET_FIELD_NUMBER: _ClassVar[int]
+ RTP_MUNGER_FIELD_NUMBER: _ClassVar[int]
+ VP8_MUNGER_FIELD_NUMBER: _ClassVar[int]
+ SENDER_REPORT_STATE_FIELD_NUMBER: _ClassVar[int]
+ started: bool
+ reference_layer_spatial: int
+ pre_start_time: int
+ ext_first_timestamp: int
+ dummy_start_timestamp_offset: int
+ rtp_munger: RTPMungerState
+ vp8_munger: VP8MungerState
+ sender_report_state: _containers.RepeatedCompositeFieldContainer[RTCPSenderReportState]
+ def __init__(self, started: bool = ..., reference_layer_spatial: _Optional[int] = ..., pre_start_time: _Optional[int] = ..., ext_first_timestamp: _Optional[int] = ..., dummy_start_timestamp_offset: _Optional[int] = ..., rtp_munger: _Optional[_Union[RTPMungerState, _Mapping]] = ..., vp8_munger: _Optional[_Union[VP8MungerState, _Mapping]] = ..., sender_report_state: _Optional[_Iterable[_Union[RTCPSenderReportState, _Mapping]]] = ...) -> None: ...
+
+class RTPMungerState(_message.Message):
+ __slots__ = ("ext_last_sequence_number", "ext_second_last_sequence_number", "ext_last_timestamp", "ext_second_last_timestamp", "last_marker", "second_last_marker")
+ EXT_LAST_SEQUENCE_NUMBER_FIELD_NUMBER: _ClassVar[int]
+ EXT_SECOND_LAST_SEQUENCE_NUMBER_FIELD_NUMBER: _ClassVar[int]
+ EXT_LAST_TIMESTAMP_FIELD_NUMBER: _ClassVar[int]
+ EXT_SECOND_LAST_TIMESTAMP_FIELD_NUMBER: _ClassVar[int]
+ LAST_MARKER_FIELD_NUMBER: _ClassVar[int]
+ SECOND_LAST_MARKER_FIELD_NUMBER: _ClassVar[int]
+ ext_last_sequence_number: int
+ ext_second_last_sequence_number: int
+ ext_last_timestamp: int
+ ext_second_last_timestamp: int
+ last_marker: bool
+ second_last_marker: bool
+ def __init__(self, ext_last_sequence_number: _Optional[int] = ..., ext_second_last_sequence_number: _Optional[int] = ..., ext_last_timestamp: _Optional[int] = ..., ext_second_last_timestamp: _Optional[int] = ..., last_marker: bool = ..., second_last_marker: bool = ...) -> None: ...
+
+class VP8MungerState(_message.Message):
+ __slots__ = ("ext_last_picture_id", "picture_id_used", "last_tl0_pic_idx", "tl0_pic_idx_used", "tid_used", "last_key_idx", "key_idx_used")
+ EXT_LAST_PICTURE_ID_FIELD_NUMBER: _ClassVar[int]
+ PICTURE_ID_USED_FIELD_NUMBER: _ClassVar[int]
+ LAST_TL0_PIC_IDX_FIELD_NUMBER: _ClassVar[int]
+ TL0_PIC_IDX_USED_FIELD_NUMBER: _ClassVar[int]
+ TID_USED_FIELD_NUMBER: _ClassVar[int]
+ LAST_KEY_IDX_FIELD_NUMBER: _ClassVar[int]
+ KEY_IDX_USED_FIELD_NUMBER: _ClassVar[int]
+ ext_last_picture_id: int
+ picture_id_used: bool
+ last_tl0_pic_idx: int
+ tl0_pic_idx_used: bool
+ tid_used: bool
+ last_key_idx: int
+ key_idx_used: bool
+ def __init__(self, ext_last_picture_id: _Optional[int] = ..., picture_id_used: bool = ..., last_tl0_pic_idx: _Optional[int] = ..., tl0_pic_idx_used: bool = ..., tid_used: bool = ..., last_key_idx: _Optional[int] = ..., key_idx_used: bool = ...) -> None: ...
class TimedVersion(_message.Message):
__slots__ = ("unix_micro", "ticks")
@@ -688,3 +1049,118 @@ class TimedVersion(_message.Message):
unix_micro: int
ticks: int
def __init__(self, unix_micro: _Optional[int] = ..., ticks: _Optional[int] = ...) -> None: ...
+
+class DataStream(_message.Message):
+ __slots__ = ()
+ class OperationType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ CREATE: _ClassVar[DataStream.OperationType]
+ UPDATE: _ClassVar[DataStream.OperationType]
+ DELETE: _ClassVar[DataStream.OperationType]
+ REACTION: _ClassVar[DataStream.OperationType]
+ CREATE: DataStream.OperationType
+ UPDATE: DataStream.OperationType
+ DELETE: DataStream.OperationType
+ REACTION: DataStream.OperationType
+ class TextHeader(_message.Message):
+ __slots__ = ("operation_type", "version", "reply_to_stream_id", "attached_stream_ids", "generated")
+ OPERATION_TYPE_FIELD_NUMBER: _ClassVar[int]
+ VERSION_FIELD_NUMBER: _ClassVar[int]
+ REPLY_TO_STREAM_ID_FIELD_NUMBER: _ClassVar[int]
+ ATTACHED_STREAM_IDS_FIELD_NUMBER: _ClassVar[int]
+ GENERATED_FIELD_NUMBER: _ClassVar[int]
+ operation_type: DataStream.OperationType
+ version: int
+ reply_to_stream_id: str
+ attached_stream_ids: _containers.RepeatedScalarFieldContainer[str]
+ generated: bool
+ def __init__(self, operation_type: _Optional[_Union[DataStream.OperationType, str]] = ..., version: _Optional[int] = ..., reply_to_stream_id: _Optional[str] = ..., attached_stream_ids: _Optional[_Iterable[str]] = ..., generated: bool = ...) -> None: ...
+ class ByteHeader(_message.Message):
+ __slots__ = ("name",)
+ NAME_FIELD_NUMBER: _ClassVar[int]
+ name: str
+ def __init__(self, name: _Optional[str] = ...) -> None: ...
+ class Header(_message.Message):
+ __slots__ = ("stream_id", "timestamp", "topic", "mime_type", "total_length", "encryption_type", "attributes", "text_header", "byte_header")
+ class AttributesEntry(_message.Message):
+ __slots__ = ("key", "value")
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: str
+ value: str
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
+ STREAM_ID_FIELD_NUMBER: _ClassVar[int]
+ TIMESTAMP_FIELD_NUMBER: _ClassVar[int]
+ TOPIC_FIELD_NUMBER: _ClassVar[int]
+ MIME_TYPE_FIELD_NUMBER: _ClassVar[int]
+ TOTAL_LENGTH_FIELD_NUMBER: _ClassVar[int]
+ ENCRYPTION_TYPE_FIELD_NUMBER: _ClassVar[int]
+ ATTRIBUTES_FIELD_NUMBER: _ClassVar[int]
+ TEXT_HEADER_FIELD_NUMBER: _ClassVar[int]
+ BYTE_HEADER_FIELD_NUMBER: _ClassVar[int]
+ stream_id: str
+ timestamp: int
+ topic: str
+ mime_type: str
+ total_length: int
+ encryption_type: Encryption.Type
+ attributes: _containers.ScalarMap[str, str]
+ text_header: DataStream.TextHeader
+ byte_header: DataStream.ByteHeader
+ def __init__(self, stream_id: _Optional[str] = ..., timestamp: _Optional[int] = ..., topic: _Optional[str] = ..., mime_type: _Optional[str] = ..., total_length: _Optional[int] = ..., encryption_type: _Optional[_Union[Encryption.Type, str]] = ..., attributes: _Optional[_Mapping[str, str]] = ..., text_header: _Optional[_Union[DataStream.TextHeader, _Mapping]] = ..., byte_header: _Optional[_Union[DataStream.ByteHeader, _Mapping]] = ...) -> None: ...
+ class Chunk(_message.Message):
+ __slots__ = ("stream_id", "chunk_index", "content", "version", "iv")
+ STREAM_ID_FIELD_NUMBER: _ClassVar[int]
+ CHUNK_INDEX_FIELD_NUMBER: _ClassVar[int]
+ CONTENT_FIELD_NUMBER: _ClassVar[int]
+ VERSION_FIELD_NUMBER: _ClassVar[int]
+ IV_FIELD_NUMBER: _ClassVar[int]
+ stream_id: str
+ chunk_index: int
+ content: bytes
+ version: int
+ iv: bytes
+ def __init__(self, stream_id: _Optional[str] = ..., chunk_index: _Optional[int] = ..., content: _Optional[bytes] = ..., version: _Optional[int] = ..., iv: _Optional[bytes] = ...) -> None: ...
+ class Trailer(_message.Message):
+ __slots__ = ("stream_id", "reason", "attributes")
+ class AttributesEntry(_message.Message):
+ __slots__ = ("key", "value")
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: str
+ value: str
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
+ STREAM_ID_FIELD_NUMBER: _ClassVar[int]
+ REASON_FIELD_NUMBER: _ClassVar[int]
+ ATTRIBUTES_FIELD_NUMBER: _ClassVar[int]
+ stream_id: str
+ reason: str
+ attributes: _containers.ScalarMap[str, str]
+ def __init__(self, stream_id: _Optional[str] = ..., reason: _Optional[str] = ..., attributes: _Optional[_Mapping[str, str]] = ...) -> None: ...
+ def __init__(self) -> None: ...
+
+class FilterParams(_message.Message):
+ __slots__ = ("include_events", "exclude_events")
+ INCLUDE_EVENTS_FIELD_NUMBER: _ClassVar[int]
+ EXCLUDE_EVENTS_FIELD_NUMBER: _ClassVar[int]
+ include_events: _containers.RepeatedScalarFieldContainer[str]
+ exclude_events: _containers.RepeatedScalarFieldContainer[str]
+ def __init__(self, include_events: _Optional[_Iterable[str]] = ..., exclude_events: _Optional[_Iterable[str]] = ...) -> None: ...
+
+class WebhookConfig(_message.Message):
+ __slots__ = ("url", "signing_key", "filter_params")
+ URL_FIELD_NUMBER: _ClassVar[int]
+ SIGNING_KEY_FIELD_NUMBER: _ClassVar[int]
+ FILTER_PARAMS_FIELD_NUMBER: _ClassVar[int]
+ url: str
+ signing_key: str
+ filter_params: FilterParams
+ def __init__(self, url: _Optional[str] = ..., signing_key: _Optional[str] = ..., filter_params: _Optional[_Union[FilterParams, _Mapping]] = ...) -> None: ...
+
+class SubscribedAudioCodec(_message.Message):
+ __slots__ = ("codec", "enabled")
+ CODEC_FIELD_NUMBER: _ClassVar[int]
+ ENABLED_FIELD_NUMBER: _ClassVar[int]
+ codec: str
+ enabled: bool
+ def __init__(self, codec: _Optional[str] = ..., enabled: bool = ...) -> None: ...
diff --git a/livekit-protocol/livekit/protocol/room.py b/livekit-protocol/livekit/protocol/room.py
index 2caebeb8..279f8582 100644
--- a/livekit-protocol/livekit/protocol/room.py
+++ b/livekit-protocol/livekit/protocol/room.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: livekit_room.proto
-# Protobuf Python Version: 4.25.3
+# Protobuf Python Version: 4.25.1
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
@@ -14,9 +14,11 @@
from . import models as _models_
from . import egress as _egress_
+from . import agent_dispatch as _agent__dispatch_
+from .logger_pb import options as logger_dot_options__pb2
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x12livekit_room.proto\x12\x07livekit\x1a\x14livekit_models.proto\x1a\x14livekit_egress.proto\"\x81\x02\n\x11\x43reateRoomRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x15\n\rempty_timeout\x18\x02 \x01(\r\x12\x19\n\x11\x64\x65parture_timeout\x18\n \x01(\r\x12\x18\n\x10max_participants\x18\x03 \x01(\r\x12\x0f\n\x07node_id\x18\x04 \x01(\t\x12\x10\n\x08metadata\x18\x05 \x01(\t\x12#\n\x06\x65gress\x18\x06 \x01(\x0b\x32\x13.livekit.RoomEgress\x12\x19\n\x11min_playout_delay\x18\x07 \x01(\r\x12\x19\n\x11max_playout_delay\x18\x08 \x01(\r\x12\x14\n\x0csync_streams\x18\t \x01(\x08\"\x9e\x01\n\nRoomEgress\x12\x31\n\x04room\x18\x01 \x01(\x0b\x32#.livekit.RoomCompositeEgressRequest\x12\x33\n\x0bparticipant\x18\x03 \x01(\x0b\x32\x1e.livekit.AutoParticipantEgress\x12(\n\x06tracks\x18\x02 \x01(\x0b\x32\x18.livekit.AutoTrackEgress\"!\n\x10ListRoomsRequest\x12\r\n\x05names\x18\x01 \x03(\t\"1\n\x11ListRoomsResponse\x12\x1c\n\x05rooms\x18\x01 \x03(\x0b\x32\r.livekit.Room\"!\n\x11\x44\x65leteRoomRequest\x12\x0c\n\x04room\x18\x01 \x01(\t\"\x14\n\x12\x44\x65leteRoomResponse\"\'\n\x17ListParticipantsRequest\x12\x0c\n\x04room\x18\x01 \x01(\t\"J\n\x18ListParticipantsResponse\x12.\n\x0cparticipants\x18\x01 \x03(\x0b\x32\x18.livekit.ParticipantInfo\"9\n\x17RoomParticipantIdentity\x12\x0c\n\x04room\x18\x01 \x01(\t\x12\x10\n\x08identity\x18\x02 \x01(\t\"\x1b\n\x19RemoveParticipantResponse\"X\n\x14MuteRoomTrackRequest\x12\x0c\n\x04room\x18\x01 \x01(\t\x12\x10\n\x08identity\x18\x02 \x01(\t\x12\x11\n\ttrack_sid\x18\x03 \x01(\t\x12\r\n\x05muted\x18\x04 \x01(\x08\":\n\x15MuteRoomTrackResponse\x12!\n\x05track\x18\x01 \x01(\x0b\x32\x12.livekit.TrackInfo\"\x88\x02\n\x18UpdateParticipantRequest\x12\x0c\n\x04room\x18\x01 \x01(\t\x12\x10\n\x08identity\x18\x02 \x01(\t\x12\x10\n\x08metadata\x18\x03 \x01(\t\x12\x32\n\npermission\x18\x04 \x01(\x0b\x32\x1e.livekit.ParticipantPermission\x12\x0c\n\x04name\x18\x05 \x01(\t\x12\x45\n\nattributes\x18\x06 \x03(\x0b\x32\x31.livekit.UpdateParticipantRequest.AttributesEntry\x1a\x31\n\x0f\x41ttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x9b\x01\n\x1aUpdateSubscriptionsRequest\x12\x0c\n\x04room\x18\x01 \x01(\t\x12\x10\n\x08identity\x18\x02 \x01(\t\x12\x12\n\ntrack_sids\x18\x03 \x03(\t\x12\x11\n\tsubscribe\x18\x04 \x01(\x08\x12\x36\n\x12participant_tracks\x18\x05 \x03(\x0b\x32\x1a.livekit.ParticipantTracks\"\x1d\n\x1bUpdateSubscriptionsResponse\"\xb1\x01\n\x0fSendDataRequest\x12\x0c\n\x04room\x18\x01 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12&\n\x04kind\x18\x03 \x01(\x0e\x32\x18.livekit.DataPacket.Kind\x12\x1c\n\x10\x64\x65stination_sids\x18\x04 \x03(\tB\x02\x18\x01\x12\x1e\n\x16\x64\x65stination_identities\x18\x06 \x03(\t\x12\x12\n\x05topic\x18\x05 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_topic\"\x12\n\x10SendDataResponse\";\n\x19UpdateRoomMetadataRequest\x12\x0c\n\x04room\x18\x01 \x01(\t\x12\x10\n\x08metadata\x18\x02 \x01(\t2\xe6\x06\n\x0bRoomService\x12\x37\n\nCreateRoom\x12\x1a.livekit.CreateRoomRequest\x1a\r.livekit.Room\x12\x42\n\tListRooms\x12\x19.livekit.ListRoomsRequest\x1a\x1a.livekit.ListRoomsResponse\x12\x45\n\nDeleteRoom\x12\x1a.livekit.DeleteRoomRequest\x1a\x1b.livekit.DeleteRoomResponse\x12W\n\x10ListParticipants\x12 .livekit.ListParticipantsRequest\x1a!.livekit.ListParticipantsResponse\x12L\n\x0eGetParticipant\x12 .livekit.RoomParticipantIdentity\x1a\x18.livekit.ParticipantInfo\x12Y\n\x11RemoveParticipant\x12 .livekit.RoomParticipantIdentity\x1a\".livekit.RemoveParticipantResponse\x12S\n\x12MutePublishedTrack\x12\x1d.livekit.MuteRoomTrackRequest\x1a\x1e.livekit.MuteRoomTrackResponse\x12P\n\x11UpdateParticipant\x12!.livekit.UpdateParticipantRequest\x1a\x18.livekit.ParticipantInfo\x12`\n\x13UpdateSubscriptions\x12#.livekit.UpdateSubscriptionsRequest\x1a$.livekit.UpdateSubscriptionsResponse\x12?\n\x08SendData\x12\x18.livekit.SendDataRequest\x1a\x19.livekit.SendDataResponse\x12G\n\x12UpdateRoomMetadata\x12\".livekit.UpdateRoomMetadataRequest\x1a\r.livekit.RoomBFZ#github.com/livekit/protocol/livekit\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x12livekit_room.proto\x12\x07livekit\x1a\x14livekit_models.proto\x1a\x14livekit_egress.proto\x1a\x1clivekit_agent_dispatch.proto\x1a\x14logger/options.proto\"\xec\x03\n\x11\x43reateRoomRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x13\n\x0broom_preset\x18\x0c \x01(\t\x12\x15\n\rempty_timeout\x18\x02 \x01(\r\x12\x19\n\x11\x64\x65parture_timeout\x18\n \x01(\r\x12\x18\n\x10max_participants\x18\x03 \x01(\r\x12\x1a\n\x07node_id\x18\x04 \x01(\tB\t\xbaP\x06nodeID\x12\x36\n\x08metadata\x18\x05 \x01(\tB$\xa8P\x01\xb2P\x1e\x12\x32\n\x04tags\x18\x0f \x03(\x0b\x32$.livekit.CreateRoomRequest.TagsEntry\x12#\n\x06\x65gress\x18\x06 \x01(\x0b\x32\x13.livekit.RoomEgress\x12\x19\n\x11min_playout_delay\x18\x07 \x01(\r\x12\x19\n\x11max_playout_delay\x18\x08 \x01(\r\x12\x14\n\x0csync_streams\x18\t \x01(\x08\x12\x16\n\x0ereplay_enabled\x18\r \x01(\x08\x12*\n\x06\x61gents\x18\x0e \x03(\x0b\x32\x1a.livekit.RoomAgentDispatch\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x9e\x01\n\nRoomEgress\x12\x31\n\x04room\x18\x01 \x01(\x0b\x32#.livekit.RoomCompositeEgressRequest\x12\x33\n\x0bparticipant\x18\x03 \x01(\x0b\x32\x1e.livekit.AutoParticipantEgress\x12(\n\x06tracks\x18\x02 \x01(\x0b\x32\x18.livekit.AutoTrackEgress\";\n\tRoomAgent\x12.\n\ndispatches\x18\x01 \x03(\x0b\x32\x1a.livekit.RoomAgentDispatch\"!\n\x10ListRoomsRequest\x12\r\n\x05names\x18\x01 \x03(\t\"1\n\x11ListRoomsResponse\x12\x1c\n\x05rooms\x18\x01 \x03(\x0b\x32\r.livekit.Room\"!\n\x11\x44\x65leteRoomRequest\x12\x0c\n\x04room\x18\x01 \x01(\t\"\x14\n\x12\x44\x65leteRoomResponse\"\'\n\x17ListParticipantsRequest\x12\x0c\n\x04room\x18\x01 \x01(\t\"J\n\x18ListParticipantsResponse\x12.\n\x0cparticipants\x18\x01 \x03(\x0b\x32\x18.livekit.ParticipantInfo\"9\n\x17RoomParticipantIdentity\x12\x0c\n\x04room\x18\x01 \x01(\t\x12\x10\n\x08identity\x18\x02 \x01(\t\"\x1b\n\x19RemoveParticipantResponse\"X\n\x14MuteRoomTrackRequest\x12\x0c\n\x04room\x18\x01 \x01(\t\x12\x10\n\x08identity\x18\x02 \x01(\t\x12\x11\n\ttrack_sid\x18\x03 \x01(\t\x12\r\n\x05muted\x18\x04 \x01(\x08\":\n\x15MuteRoomTrackResponse\x12!\n\x05track\x18\x01 \x01(\x0b\x32\x12.livekit.TrackInfo\"\xfa\x02\n\x18UpdateParticipantRequest\x12\x0c\n\x04room\x18\x01 \x01(\t\x12\x10\n\x08identity\x18\x02 \x01(\t\x12\x36\n\x08metadata\x18\x03 \x01(\tB$\xa8P\x01\xb2P\x1e\x12\x32\n\npermission\x18\x04 \x01(\x0b\x32\x1e.livekit.ParticipantPermission\x12\x32\n\x04name\x18\x05 \x01(\tB$\xa8P\x01\xb2P\x1e\x12k\n\nattributes\x18\x06 \x03(\x0b\x32\x31.livekit.UpdateParticipantRequest.AttributesEntryB$\xa8P\x01\xb2P\x1e\x1a\x31\n\x0f\x41ttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x9b\x01\n\x1aUpdateSubscriptionsRequest\x12\x0c\n\x04room\x18\x01 \x01(\t\x12\x10\n\x08identity\x18\x02 \x01(\t\x12\x12\n\ntrack_sids\x18\x03 \x03(\t\x12\x11\n\tsubscribe\x18\x04 \x01(\x08\x12\x36\n\x12participant_tracks\x18\x05 \x03(\x0b\x32\x1a.livekit.ParticipantTracks\"\x1d\n\x1bUpdateSubscriptionsResponse\"\xc0\x01\n\x0fSendDataRequest\x12\x0c\n\x04room\x18\x01 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12&\n\x04kind\x18\x03 \x01(\x0e\x32\x18.livekit.DataPacket.Kind\x12\x1c\n\x10\x64\x65stination_sids\x18\x04 \x03(\tB\x02\x18\x01\x12\x1e\n\x16\x64\x65stination_identities\x18\x06 \x03(\t\x12\x12\n\x05topic\x18\x05 \x01(\tH\x00\x88\x01\x01\x12\r\n\x05nonce\x18\x07 \x01(\x0c\x42\x08\n\x06_topic\"\x12\n\x10SendDataResponse\"a\n\x19UpdateRoomMetadataRequest\x12\x0c\n\x04room\x18\x01 \x01(\t\x12\x36\n\x08metadata\x18\x02 \x01(\tB$\xa8P\x01\xb2P\x1e\"\xa3\x03\n\x11RoomConfiguration\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x15\n\rempty_timeout\x18\x02 \x01(\r\x12\x19\n\x11\x64\x65parture_timeout\x18\x03 \x01(\r\x12\x18\n\x10max_participants\x18\x04 \x01(\r\x12\x36\n\x08metadata\x18\x0b \x01(\tB$\xa8P\x01\xb2P\x1e\x12#\n\x06\x65gress\x18\x05 \x01(\x0b\x32\x13.livekit.RoomEgress\x12\x19\n\x11min_playout_delay\x18\x07 \x01(\r\x12\x19\n\x11max_playout_delay\x18\x08 \x01(\r\x12\x14\n\x0csync_streams\x18\t \x01(\x08\x12*\n\x06\x61gents\x18\n \x03(\x0b\x32\x1a.livekit.RoomAgentDispatch\x12\x32\n\x04tags\x18\x0c \x03(\x0b\x32$.livekit.RoomConfiguration.TagsEntry\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"U\n\x19\x46orwardParticipantRequest\x12\x0c\n\x04room\x18\x01 \x01(\t\x12\x10\n\x08identity\x18\x02 \x01(\t\x12\x18\n\x10\x64\x65stination_room\x18\x03 \x01(\t\"\x1c\n\x1a\x46orwardParticipantResponse\"R\n\x16MoveParticipantRequest\x12\x0c\n\x04room\x18\x01 \x01(\t\x12\x10\n\x08identity\x18\x02 \x01(\t\x12\x18\n\x10\x64\x65stination_room\x18\x03 \x01(\t\"\x19\n\x17MoveParticipantResponse\"}\n\x11PerformRpcRequest\x12\x0c\n\x04room\x18\x01 \x01(\t\x12\x1c\n\x14\x64\x65stination_identity\x18\x02 \x01(\t\x12\x0e\n\x06method\x18\x03 \x01(\t\x12\x0f\n\x07payload\x18\x04 \x01(\t\x12\x1b\n\x13response_timeout_ms\x18\x05 \x01(\r\"%\n\x12PerformRpcResponse\x12\x0f\n\x07payload\x18\x01 \x01(\t2\xe2\x08\n\x0bRoomService\x12\x37\n\nCreateRoom\x12\x1a.livekit.CreateRoomRequest\x1a\r.livekit.Room\x12\x42\n\tListRooms\x12\x19.livekit.ListRoomsRequest\x1a\x1a.livekit.ListRoomsResponse\x12\x45\n\nDeleteRoom\x12\x1a.livekit.DeleteRoomRequest\x1a\x1b.livekit.DeleteRoomResponse\x12W\n\x10ListParticipants\x12 .livekit.ListParticipantsRequest\x1a!.livekit.ListParticipantsResponse\x12L\n\x0eGetParticipant\x12 .livekit.RoomParticipantIdentity\x1a\x18.livekit.ParticipantInfo\x12Y\n\x11RemoveParticipant\x12 .livekit.RoomParticipantIdentity\x1a\".livekit.RemoveParticipantResponse\x12S\n\x12MutePublishedTrack\x12\x1d.livekit.MuteRoomTrackRequest\x1a\x1e.livekit.MuteRoomTrackResponse\x12P\n\x11UpdateParticipant\x12!.livekit.UpdateParticipantRequest\x1a\x18.livekit.ParticipantInfo\x12`\n\x13UpdateSubscriptions\x12#.livekit.UpdateSubscriptionsRequest\x1a$.livekit.UpdateSubscriptionsResponse\x12?\n\x08SendData\x12\x18.livekit.SendDataRequest\x1a\x19.livekit.SendDataResponse\x12G\n\x12UpdateRoomMetadata\x12\".livekit.UpdateRoomMetadataRequest\x1a\r.livekit.Room\x12]\n\x12\x46orwardParticipant\x12\".livekit.ForwardParticipantRequest\x1a#.livekit.ForwardParticipantResponse\x12T\n\x0fMoveParticipant\x12\x1f.livekit.MoveParticipantRequest\x1a .livekit.MoveParticipantResponse\x12\x45\n\nPerformRpc\x12\x1a.livekit.PerformRpcRequest\x1a\x1b.livekit.PerformRpcResponseBFZ#github.com/livekit/protocol/livekit\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -24,48 +26,86 @@
if _descriptor._USE_C_DESCRIPTORS == False:
_globals['DESCRIPTOR']._options = None
_globals['DESCRIPTOR']._serialized_options = b'Z#github.com/livekit/protocol/livekit\252\002\rLiveKit.Proto\352\002\016LiveKit::Proto'
+ _globals['_CREATEROOMREQUEST_TAGSENTRY']._options = None
+ _globals['_CREATEROOMREQUEST_TAGSENTRY']._serialized_options = b'8\001'
+ _globals['_CREATEROOMREQUEST'].fields_by_name['node_id']._options = None
+ _globals['_CREATEROOMREQUEST'].fields_by_name['node_id']._serialized_options = b'\272P\006nodeID'
+ _globals['_CREATEROOMREQUEST'].fields_by_name['metadata']._options = None
+ _globals['_CREATEROOMREQUEST'].fields_by_name['metadata']._serialized_options = b'\250P\001\262P\036'
_globals['_UPDATEPARTICIPANTREQUEST_ATTRIBUTESENTRY']._options = None
_globals['_UPDATEPARTICIPANTREQUEST_ATTRIBUTESENTRY']._serialized_options = b'8\001'
+ _globals['_UPDATEPARTICIPANTREQUEST'].fields_by_name['metadata']._options = None
+ _globals['_UPDATEPARTICIPANTREQUEST'].fields_by_name['metadata']._serialized_options = b'\250P\001\262P\036'
+ _globals['_UPDATEPARTICIPANTREQUEST'].fields_by_name['name']._options = None
+ _globals['_UPDATEPARTICIPANTREQUEST'].fields_by_name['name']._serialized_options = b'\250P\001\262P\036'
+ _globals['_UPDATEPARTICIPANTREQUEST'].fields_by_name['attributes']._options = None
+ _globals['_UPDATEPARTICIPANTREQUEST'].fields_by_name['attributes']._serialized_options = b'\250P\001\262P\036'
_globals['_SENDDATAREQUEST'].fields_by_name['destination_sids']._options = None
_globals['_SENDDATAREQUEST'].fields_by_name['destination_sids']._serialized_options = b'\030\001'
- _globals['_CREATEROOMREQUEST']._serialized_start=76
- _globals['_CREATEROOMREQUEST']._serialized_end=333
- _globals['_ROOMEGRESS']._serialized_start=336
- _globals['_ROOMEGRESS']._serialized_end=494
- _globals['_LISTROOMSREQUEST']._serialized_start=496
- _globals['_LISTROOMSREQUEST']._serialized_end=529
- _globals['_LISTROOMSRESPONSE']._serialized_start=531
- _globals['_LISTROOMSRESPONSE']._serialized_end=580
- _globals['_DELETEROOMREQUEST']._serialized_start=582
- _globals['_DELETEROOMREQUEST']._serialized_end=615
- _globals['_DELETEROOMRESPONSE']._serialized_start=617
- _globals['_DELETEROOMRESPONSE']._serialized_end=637
- _globals['_LISTPARTICIPANTSREQUEST']._serialized_start=639
- _globals['_LISTPARTICIPANTSREQUEST']._serialized_end=678
- _globals['_LISTPARTICIPANTSRESPONSE']._serialized_start=680
- _globals['_LISTPARTICIPANTSRESPONSE']._serialized_end=754
- _globals['_ROOMPARTICIPANTIDENTITY']._serialized_start=756
- _globals['_ROOMPARTICIPANTIDENTITY']._serialized_end=813
- _globals['_REMOVEPARTICIPANTRESPONSE']._serialized_start=815
- _globals['_REMOVEPARTICIPANTRESPONSE']._serialized_end=842
- _globals['_MUTEROOMTRACKREQUEST']._serialized_start=844
- _globals['_MUTEROOMTRACKREQUEST']._serialized_end=932
- _globals['_MUTEROOMTRACKRESPONSE']._serialized_start=934
- _globals['_MUTEROOMTRACKRESPONSE']._serialized_end=992
- _globals['_UPDATEPARTICIPANTREQUEST']._serialized_start=995
- _globals['_UPDATEPARTICIPANTREQUEST']._serialized_end=1259
- _globals['_UPDATEPARTICIPANTREQUEST_ATTRIBUTESENTRY']._serialized_start=1210
- _globals['_UPDATEPARTICIPANTREQUEST_ATTRIBUTESENTRY']._serialized_end=1259
- _globals['_UPDATESUBSCRIPTIONSREQUEST']._serialized_start=1262
- _globals['_UPDATESUBSCRIPTIONSREQUEST']._serialized_end=1417
- _globals['_UPDATESUBSCRIPTIONSRESPONSE']._serialized_start=1419
- _globals['_UPDATESUBSCRIPTIONSRESPONSE']._serialized_end=1448
- _globals['_SENDDATAREQUEST']._serialized_start=1451
- _globals['_SENDDATAREQUEST']._serialized_end=1628
- _globals['_SENDDATARESPONSE']._serialized_start=1630
- _globals['_SENDDATARESPONSE']._serialized_end=1648
- _globals['_UPDATEROOMMETADATAREQUEST']._serialized_start=1650
- _globals['_UPDATEROOMMETADATAREQUEST']._serialized_end=1709
- _globals['_ROOMSERVICE']._serialized_start=1712
- _globals['_ROOMSERVICE']._serialized_end=2582
+ _globals['_UPDATEROOMMETADATAREQUEST'].fields_by_name['metadata']._options = None
+ _globals['_UPDATEROOMMETADATAREQUEST'].fields_by_name['metadata']._serialized_options = b'\250P\001\262P\036'
+ _globals['_ROOMCONFIGURATION_TAGSENTRY']._options = None
+ _globals['_ROOMCONFIGURATION_TAGSENTRY']._serialized_options = b'8\001'
+ _globals['_ROOMCONFIGURATION'].fields_by_name['metadata']._options = None
+ _globals['_ROOMCONFIGURATION'].fields_by_name['metadata']._serialized_options = b'\250P\001\262P\036'
+ _globals['_CREATEROOMREQUEST']._serialized_start=128
+ _globals['_CREATEROOMREQUEST']._serialized_end=620
+ _globals['_CREATEROOMREQUEST_TAGSENTRY']._serialized_start=577
+ _globals['_CREATEROOMREQUEST_TAGSENTRY']._serialized_end=620
+ _globals['_ROOMEGRESS']._serialized_start=623
+ _globals['_ROOMEGRESS']._serialized_end=781
+ _globals['_ROOMAGENT']._serialized_start=783
+ _globals['_ROOMAGENT']._serialized_end=842
+ _globals['_LISTROOMSREQUEST']._serialized_start=844
+ _globals['_LISTROOMSREQUEST']._serialized_end=877
+ _globals['_LISTROOMSRESPONSE']._serialized_start=879
+ _globals['_LISTROOMSRESPONSE']._serialized_end=928
+ _globals['_DELETEROOMREQUEST']._serialized_start=930
+ _globals['_DELETEROOMREQUEST']._serialized_end=963
+ _globals['_DELETEROOMRESPONSE']._serialized_start=965
+ _globals['_DELETEROOMRESPONSE']._serialized_end=985
+ _globals['_LISTPARTICIPANTSREQUEST']._serialized_start=987
+ _globals['_LISTPARTICIPANTSREQUEST']._serialized_end=1026
+ _globals['_LISTPARTICIPANTSRESPONSE']._serialized_start=1028
+ _globals['_LISTPARTICIPANTSRESPONSE']._serialized_end=1102
+ _globals['_ROOMPARTICIPANTIDENTITY']._serialized_start=1104
+ _globals['_ROOMPARTICIPANTIDENTITY']._serialized_end=1161
+ _globals['_REMOVEPARTICIPANTRESPONSE']._serialized_start=1163
+ _globals['_REMOVEPARTICIPANTRESPONSE']._serialized_end=1190
+ _globals['_MUTEROOMTRACKREQUEST']._serialized_start=1192
+ _globals['_MUTEROOMTRACKREQUEST']._serialized_end=1280
+ _globals['_MUTEROOMTRACKRESPONSE']._serialized_start=1282
+ _globals['_MUTEROOMTRACKRESPONSE']._serialized_end=1340
+ _globals['_UPDATEPARTICIPANTREQUEST']._serialized_start=1343
+ _globals['_UPDATEPARTICIPANTREQUEST']._serialized_end=1721
+ _globals['_UPDATEPARTICIPANTREQUEST_ATTRIBUTESENTRY']._serialized_start=1672
+ _globals['_UPDATEPARTICIPANTREQUEST_ATTRIBUTESENTRY']._serialized_end=1721
+ _globals['_UPDATESUBSCRIPTIONSREQUEST']._serialized_start=1724
+ _globals['_UPDATESUBSCRIPTIONSREQUEST']._serialized_end=1879
+ _globals['_UPDATESUBSCRIPTIONSRESPONSE']._serialized_start=1881
+ _globals['_UPDATESUBSCRIPTIONSRESPONSE']._serialized_end=1910
+ _globals['_SENDDATAREQUEST']._serialized_start=1913
+ _globals['_SENDDATAREQUEST']._serialized_end=2105
+ _globals['_SENDDATARESPONSE']._serialized_start=2107
+ _globals['_SENDDATARESPONSE']._serialized_end=2125
+ _globals['_UPDATEROOMMETADATAREQUEST']._serialized_start=2127
+ _globals['_UPDATEROOMMETADATAREQUEST']._serialized_end=2224
+ _globals['_ROOMCONFIGURATION']._serialized_start=2227
+ _globals['_ROOMCONFIGURATION']._serialized_end=2646
+ _globals['_ROOMCONFIGURATION_TAGSENTRY']._serialized_start=577
+ _globals['_ROOMCONFIGURATION_TAGSENTRY']._serialized_end=620
+ _globals['_FORWARDPARTICIPANTREQUEST']._serialized_start=2648
+ _globals['_FORWARDPARTICIPANTREQUEST']._serialized_end=2733
+ _globals['_FORWARDPARTICIPANTRESPONSE']._serialized_start=2735
+ _globals['_FORWARDPARTICIPANTRESPONSE']._serialized_end=2763
+ _globals['_MOVEPARTICIPANTREQUEST']._serialized_start=2765
+ _globals['_MOVEPARTICIPANTREQUEST']._serialized_end=2847
+ _globals['_MOVEPARTICIPANTRESPONSE']._serialized_start=2849
+ _globals['_MOVEPARTICIPANTRESPONSE']._serialized_end=2874
+ _globals['_PERFORMRPCREQUEST']._serialized_start=2876
+ _globals['_PERFORMRPCREQUEST']._serialized_end=3001
+ _globals['_PERFORMRPCRESPONSE']._serialized_start=3003
+ _globals['_PERFORMRPCRESPONSE']._serialized_end=3040
+ _globals['_ROOMSERVICE']._serialized_start=3043
+ _globals['_ROOMSERVICE']._serialized_end=4165
# @@protoc_insertion_point(module_scope)
diff --git a/livekit-protocol/livekit/protocol/room.pyi b/livekit-protocol/livekit/protocol/room.pyi
index 2ba90dd9..959a31d3 100644
--- a/livekit-protocol/livekit/protocol/room.pyi
+++ b/livekit-protocol/livekit/protocol/room.pyi
@@ -1,5 +1,7 @@
from . import models as _models
from . import egress as _egress
+from . import agent_dispatch as _agent_dispatch
+from .logger_pb import options as _options_pb2
from google.protobuf.internal import containers as _containers
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
@@ -8,28 +10,43 @@ from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Map
DESCRIPTOR: _descriptor.FileDescriptor
class CreateRoomRequest(_message.Message):
- __slots__ = ("name", "empty_timeout", "departure_timeout", "max_participants", "node_id", "metadata", "egress", "min_playout_delay", "max_playout_delay", "sync_streams")
+ __slots__ = ("name", "room_preset", "empty_timeout", "departure_timeout", "max_participants", "node_id", "metadata", "tags", "egress", "min_playout_delay", "max_playout_delay", "sync_streams", "replay_enabled", "agents")
+ class TagsEntry(_message.Message):
+ __slots__ = ("key", "value")
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: str
+ value: str
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
NAME_FIELD_NUMBER: _ClassVar[int]
+ ROOM_PRESET_FIELD_NUMBER: _ClassVar[int]
EMPTY_TIMEOUT_FIELD_NUMBER: _ClassVar[int]
DEPARTURE_TIMEOUT_FIELD_NUMBER: _ClassVar[int]
MAX_PARTICIPANTS_FIELD_NUMBER: _ClassVar[int]
NODE_ID_FIELD_NUMBER: _ClassVar[int]
METADATA_FIELD_NUMBER: _ClassVar[int]
+ TAGS_FIELD_NUMBER: _ClassVar[int]
EGRESS_FIELD_NUMBER: _ClassVar[int]
MIN_PLAYOUT_DELAY_FIELD_NUMBER: _ClassVar[int]
MAX_PLAYOUT_DELAY_FIELD_NUMBER: _ClassVar[int]
SYNC_STREAMS_FIELD_NUMBER: _ClassVar[int]
+ REPLAY_ENABLED_FIELD_NUMBER: _ClassVar[int]
+ AGENTS_FIELD_NUMBER: _ClassVar[int]
name: str
+ room_preset: str
empty_timeout: int
departure_timeout: int
max_participants: int
node_id: str
metadata: str
+ tags: _containers.ScalarMap[str, str]
egress: RoomEgress
min_playout_delay: int
max_playout_delay: int
sync_streams: bool
- def __init__(self, name: _Optional[str] = ..., empty_timeout: _Optional[int] = ..., departure_timeout: _Optional[int] = ..., max_participants: _Optional[int] = ..., node_id: _Optional[str] = ..., metadata: _Optional[str] = ..., egress: _Optional[_Union[RoomEgress, _Mapping]] = ..., min_playout_delay: _Optional[int] = ..., max_playout_delay: _Optional[int] = ..., sync_streams: bool = ...) -> None: ...
+ replay_enabled: bool
+ agents: _containers.RepeatedCompositeFieldContainer[_agent_dispatch.RoomAgentDispatch]
+ def __init__(self, name: _Optional[str] = ..., room_preset: _Optional[str] = ..., empty_timeout: _Optional[int] = ..., departure_timeout: _Optional[int] = ..., max_participants: _Optional[int] = ..., node_id: _Optional[str] = ..., metadata: _Optional[str] = ..., tags: _Optional[_Mapping[str, str]] = ..., egress: _Optional[_Union[RoomEgress, _Mapping]] = ..., min_playout_delay: _Optional[int] = ..., max_playout_delay: _Optional[int] = ..., sync_streams: bool = ..., replay_enabled: bool = ..., agents: _Optional[_Iterable[_Union[_agent_dispatch.RoomAgentDispatch, _Mapping]]] = ...) -> None: ...
class RoomEgress(_message.Message):
__slots__ = ("room", "participant", "tracks")
@@ -41,6 +58,12 @@ class RoomEgress(_message.Message):
tracks: _egress.AutoTrackEgress
def __init__(self, room: _Optional[_Union[_egress.RoomCompositeEgressRequest, _Mapping]] = ..., participant: _Optional[_Union[_egress.AutoParticipantEgress, _Mapping]] = ..., tracks: _Optional[_Union[_egress.AutoTrackEgress, _Mapping]] = ...) -> None: ...
+class RoomAgent(_message.Message):
+ __slots__ = ("dispatches",)
+ DISPATCHES_FIELD_NUMBER: _ClassVar[int]
+ dispatches: _containers.RepeatedCompositeFieldContainer[_agent_dispatch.RoomAgentDispatch]
+ def __init__(self, dispatches: _Optional[_Iterable[_Union[_agent_dispatch.RoomAgentDispatch, _Mapping]]] = ...) -> None: ...
+
class ListRoomsRequest(_message.Message):
__slots__ = ("names",)
NAMES_FIELD_NUMBER: _ClassVar[int]
@@ -147,20 +170,22 @@ class UpdateSubscriptionsResponse(_message.Message):
def __init__(self) -> None: ...
class SendDataRequest(_message.Message):
- __slots__ = ("room", "data", "kind", "destination_sids", "destination_identities", "topic")
+ __slots__ = ("room", "data", "kind", "destination_sids", "destination_identities", "topic", "nonce")
ROOM_FIELD_NUMBER: _ClassVar[int]
DATA_FIELD_NUMBER: _ClassVar[int]
KIND_FIELD_NUMBER: _ClassVar[int]
DESTINATION_SIDS_FIELD_NUMBER: _ClassVar[int]
DESTINATION_IDENTITIES_FIELD_NUMBER: _ClassVar[int]
TOPIC_FIELD_NUMBER: _ClassVar[int]
+ NONCE_FIELD_NUMBER: _ClassVar[int]
room: str
data: bytes
kind: _models.DataPacket.Kind
destination_sids: _containers.RepeatedScalarFieldContainer[str]
destination_identities: _containers.RepeatedScalarFieldContainer[str]
topic: str
- def __init__(self, room: _Optional[str] = ..., data: _Optional[bytes] = ..., kind: _Optional[_Union[_models.DataPacket.Kind, str]] = ..., destination_sids: _Optional[_Iterable[str]] = ..., destination_identities: _Optional[_Iterable[str]] = ..., topic: _Optional[str] = ...) -> None: ...
+ nonce: bytes
+ def __init__(self, room: _Optional[str] = ..., data: _Optional[bytes] = ..., kind: _Optional[_Union[_models.DataPacket.Kind, str]] = ..., destination_sids: _Optional[_Iterable[str]] = ..., destination_identities: _Optional[_Iterable[str]] = ..., topic: _Optional[str] = ..., nonce: _Optional[bytes] = ...) -> None: ...
class SendDataResponse(_message.Message):
__slots__ = ()
@@ -173,3 +198,84 @@ class UpdateRoomMetadataRequest(_message.Message):
room: str
metadata: str
def __init__(self, room: _Optional[str] = ..., metadata: _Optional[str] = ...) -> None: ...
+
+class RoomConfiguration(_message.Message):
+ __slots__ = ("name", "empty_timeout", "departure_timeout", "max_participants", "metadata", "egress", "min_playout_delay", "max_playout_delay", "sync_streams", "agents", "tags")
+ class TagsEntry(_message.Message):
+ __slots__ = ("key", "value")
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: str
+ value: str
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
+ NAME_FIELD_NUMBER: _ClassVar[int]
+ EMPTY_TIMEOUT_FIELD_NUMBER: _ClassVar[int]
+ DEPARTURE_TIMEOUT_FIELD_NUMBER: _ClassVar[int]
+ MAX_PARTICIPANTS_FIELD_NUMBER: _ClassVar[int]
+ METADATA_FIELD_NUMBER: _ClassVar[int]
+ EGRESS_FIELD_NUMBER: _ClassVar[int]
+ MIN_PLAYOUT_DELAY_FIELD_NUMBER: _ClassVar[int]
+ MAX_PLAYOUT_DELAY_FIELD_NUMBER: _ClassVar[int]
+ SYNC_STREAMS_FIELD_NUMBER: _ClassVar[int]
+ AGENTS_FIELD_NUMBER: _ClassVar[int]
+ TAGS_FIELD_NUMBER: _ClassVar[int]
+ name: str
+ empty_timeout: int
+ departure_timeout: int
+ max_participants: int
+ metadata: str
+ egress: RoomEgress
+ min_playout_delay: int
+ max_playout_delay: int
+ sync_streams: bool
+ agents: _containers.RepeatedCompositeFieldContainer[_agent_dispatch.RoomAgentDispatch]
+ tags: _containers.ScalarMap[str, str]
+ def __init__(self, name: _Optional[str] = ..., empty_timeout: _Optional[int] = ..., departure_timeout: _Optional[int] = ..., max_participants: _Optional[int] = ..., metadata: _Optional[str] = ..., egress: _Optional[_Union[RoomEgress, _Mapping]] = ..., min_playout_delay: _Optional[int] = ..., max_playout_delay: _Optional[int] = ..., sync_streams: bool = ..., agents: _Optional[_Iterable[_Union[_agent_dispatch.RoomAgentDispatch, _Mapping]]] = ..., tags: _Optional[_Mapping[str, str]] = ...) -> None: ...
+
+class ForwardParticipantRequest(_message.Message):
+ __slots__ = ("room", "identity", "destination_room")
+ ROOM_FIELD_NUMBER: _ClassVar[int]
+ IDENTITY_FIELD_NUMBER: _ClassVar[int]
+ DESTINATION_ROOM_FIELD_NUMBER: _ClassVar[int]
+ room: str
+ identity: str
+ destination_room: str
+ def __init__(self, room: _Optional[str] = ..., identity: _Optional[str] = ..., destination_room: _Optional[str] = ...) -> None: ...
+
+class ForwardParticipantResponse(_message.Message):
+ __slots__ = ()
+ def __init__(self) -> None: ...
+
+class MoveParticipantRequest(_message.Message):
+ __slots__ = ("room", "identity", "destination_room")
+ ROOM_FIELD_NUMBER: _ClassVar[int]
+ IDENTITY_FIELD_NUMBER: _ClassVar[int]
+ DESTINATION_ROOM_FIELD_NUMBER: _ClassVar[int]
+ room: str
+ identity: str
+ destination_room: str
+ def __init__(self, room: _Optional[str] = ..., identity: _Optional[str] = ..., destination_room: _Optional[str] = ...) -> None: ...
+
+class MoveParticipantResponse(_message.Message):
+ __slots__ = ()
+ def __init__(self) -> None: ...
+
+class PerformRpcRequest(_message.Message):
+ __slots__ = ("room", "destination_identity", "method", "payload", "response_timeout_ms")
+ ROOM_FIELD_NUMBER: _ClassVar[int]
+ DESTINATION_IDENTITY_FIELD_NUMBER: _ClassVar[int]
+ METHOD_FIELD_NUMBER: _ClassVar[int]
+ PAYLOAD_FIELD_NUMBER: _ClassVar[int]
+ RESPONSE_TIMEOUT_MS_FIELD_NUMBER: _ClassVar[int]
+ room: str
+ destination_identity: str
+ method: str
+ payload: str
+ response_timeout_ms: int
+ def __init__(self, room: _Optional[str] = ..., destination_identity: _Optional[str] = ..., method: _Optional[str] = ..., payload: _Optional[str] = ..., response_timeout_ms: _Optional[int] = ...) -> None: ...
+
+class PerformRpcResponse(_message.Message):
+ __slots__ = ("payload",)
+ PAYLOAD_FIELD_NUMBER: _ClassVar[int]
+ payload: str
+ def __init__(self, payload: _Optional[str] = ...) -> None: ...
diff --git a/livekit-protocol/livekit/protocol/rtc.py b/livekit-protocol/livekit/protocol/rtc.py
new file mode 100644
index 00000000..08a5b7b9
--- /dev/null
+++ b/livekit-protocol/livekit/protocol/rtc.py
@@ -0,0 +1,199 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: livekit_rtc.proto
+# Protobuf Python Version: 4.25.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from . import models as _models_
+from .logger_pb import options as logger_dot_options__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11livekit_rtc.proto\x12\x07livekit\x1a\x14livekit_models.proto\x1a\x14logger/options.proto\"\xae\x08\n\rSignalRequest\x12,\n\x05offer\x18\x01 \x01(\x0b\x32\x1b.livekit.SessionDescriptionH\x00\x12-\n\x06\x61nswer\x18\x02 \x01(\x0b\x32\x1b.livekit.SessionDescriptionH\x00\x12*\n\x07trickle\x18\x03 \x01(\x0b\x32\x17.livekit.TrickleRequestH\x00\x12-\n\tadd_track\x18\x04 \x01(\x0b\x32\x18.livekit.AddTrackRequestH\x00\x12)\n\x04mute\x18\x05 \x01(\x0b\x32\x19.livekit.MuteTrackRequestH\x00\x12\x33\n\x0csubscription\x18\x06 \x01(\x0b\x32\x1b.livekit.UpdateSubscriptionH\x00\x12\x35\n\rtrack_setting\x18\x07 \x01(\x0b\x32\x1c.livekit.UpdateTrackSettingsH\x00\x12&\n\x05leave\x18\x08 \x01(\x0b\x32\x15.livekit.LeaveRequestH\x00\x12\x37\n\rupdate_layers\x18\n \x01(\x0b\x32\x1a.livekit.UpdateVideoLayersB\x02\x18\x01H\x00\x12\x42\n\x17subscription_permission\x18\x0b \x01(\x0b\x32\x1f.livekit.SubscriptionPermissionH\x00\x12(\n\nsync_state\x18\x0c \x01(\x0b\x32\x12.livekit.SyncStateH\x00\x12-\n\x08simulate\x18\r \x01(\x0b\x32\x19.livekit.SimulateScenarioH\x00\x12\x0e\n\x04ping\x18\x0e \x01(\x03H\x00\x12=\n\x0fupdate_metadata\x18\x0f \x01(\x0b\x32\".livekit.UpdateParticipantMetadataH\x00\x12!\n\x08ping_req\x18\x10 \x01(\x0b\x32\r.livekit.PingH\x00\x12<\n\x12update_audio_track\x18\x11 \x01(\x0b\x32\x1e.livekit.UpdateLocalAudioTrackH\x00\x12<\n\x12update_video_track\x18\x12 \x01(\x0b\x32\x1e.livekit.UpdateLocalVideoTrackH\x00\x12\x46\n\x1apublish_data_track_request\x18\x13 \x01(\x0b\x32 .livekit.PublishDataTrackRequestH\x00\x12J\n\x1cunpublish_data_track_request\x18\x14 \x01(\x0b\x32\".livekit.UnpublishDataTrackRequestH\x00\x12\x43\n\x18update_data_subscription\x18\x15 \x01(\x0b\x32\x1f.livekit.UpdateDataSubscriptionH\x00\x42\t\n\x07message\"\x96\x0c\n\x0eSignalResponse\x12%\n\x04join\x18\x01 \x01(\x0b\x32\x15.livekit.JoinResponseH\x00\x12-\n\x06\x61nswer\x18\x02 \x01(\x0b\x32\x1b.livekit.SessionDescriptionH\x00\x12,\n\x05offer\x18\x03 \x01(\x0b\x32\x1b.livekit.SessionDescriptionH\x00\x12*\n\x07trickle\x18\x04 \x01(\x0b\x32\x17.livekit.TrickleRequestH\x00\x12,\n\x06update\x18\x05 \x01(\x0b\x32\x1a.livekit.ParticipantUpdateH\x00\x12:\n\x0ftrack_published\x18\x06 \x01(\x0b\x32\x1f.livekit.TrackPublishedResponseH\x00\x12&\n\x05leave\x18\x08 \x01(\x0b\x32\x15.livekit.LeaveRequestH\x00\x12)\n\x04mute\x18\t \x01(\x0b\x32\x19.livekit.MuteTrackRequestH\x00\x12\x34\n\x10speakers_changed\x18\n \x01(\x0b\x32\x18.livekit.SpeakersChangedH\x00\x12*\n\x0broom_update\x18\x0b \x01(\x0b\x32\x13.livekit.RoomUpdateH\x00\x12>\n\x12\x63onnection_quality\x18\x0c \x01(\x0b\x32 .livekit.ConnectionQualityUpdateH\x00\x12\x39\n\x13stream_state_update\x18\r \x01(\x0b\x32\x1a.livekit.StreamStateUpdateH\x00\x12\x45\n\x19subscribed_quality_update\x18\x0e \x01(\x0b\x32 .livekit.SubscribedQualityUpdateH\x00\x12O\n\x1esubscription_permission_update\x18\x0f \x01(\x0b\x32%.livekit.SubscriptionPermissionUpdateH\x00\x12\x17\n\rrefresh_token\x18\x10 \x01(\tH\x00\x12>\n\x11track_unpublished\x18\x11 \x01(\x0b\x32!.livekit.TrackUnpublishedResponseH\x00\x12\x0e\n\x04pong\x18\x12 \x01(\x03H\x00\x12/\n\treconnect\x18\x13 \x01(\x0b\x32\x1a.livekit.ReconnectResponseH\x00\x12\"\n\tpong_resp\x18\x14 \x01(\x0b\x32\r.livekit.PongH\x00\x12>\n\x15subscription_response\x18\x15 \x01(\x0b\x32\x1d.livekit.SubscriptionResponseH\x00\x12\x34\n\x10request_response\x18\x16 \x01(\x0b\x32\x18.livekit.RequestResponseH\x00\x12\x34\n\x10track_subscribed\x18\x17 \x01(\x0b\x32\x18.livekit.TrackSubscribedH\x00\x12\x30\n\nroom_moved\x18\x18 \x01(\x0b\x32\x1a.livekit.RoomMovedResponseH\x00\x12G\n\x1amedia_sections_requirement\x18\x19 \x01(\x0b\x32!.livekit.MediaSectionsRequirementH\x00\x12L\n\x1dsubscribed_audio_codec_update\x18\x1a \x01(\x0b\x32#.livekit.SubscribedAudioCodecUpdateH\x00\x12H\n\x1bpublish_data_track_response\x18\x1b \x01(\x0b\x32!.livekit.PublishDataTrackResponseH\x00\x12L\n\x1dunpublish_data_track_response\x18\x1c \x01(\x0b\x32#.livekit.UnpublishDataTrackResponseH\x00\x12L\n\x1d\x64\x61ta_track_subscriber_handles\x18\x1d \x01(\x0b\x32#.livekit.DataTrackSubscriberHandlesH\x00\x42\t\n\x07message\"\x85\x01\n\x0eSimulcastCodec\x12\r\n\x05\x63odec\x18\x01 \x01(\t\x12\x0b\n\x03\x63id\x18\x02 \x01(\t\x12#\n\x06layers\x18\x04 \x03(\x0b\x32\x13.livekit.VideoLayer\x12\x32\n\x10video_layer_mode\x18\x05 \x01(\x0e\x32\x18.livekit.VideoLayer.Mode\"\xb4\x04\n\x0f\x41\x64\x64TrackRequest\x12\x0b\n\x03\x63id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12 \n\x04type\x18\x03 \x01(\x0e\x32\x12.livekit.TrackType\x12\r\n\x05width\x18\x04 \x01(\r\x12\x0e\n\x06height\x18\x05 \x01(\r\x12\r\n\x05muted\x18\x06 \x01(\x08\x12\x17\n\x0b\x64isable_dtx\x18\x07 \x01(\x08\x42\x02\x18\x01\x12$\n\x06source\x18\x08 \x01(\x0e\x32\x14.livekit.TrackSource\x12#\n\x06layers\x18\t \x03(\x0b\x32\x13.livekit.VideoLayer\x12\x31\n\x10simulcast_codecs\x18\n \x03(\x0b\x32\x17.livekit.SimulcastCodec\x12\x0b\n\x03sid\x18\x0b \x01(\t\x12\x12\n\x06stereo\x18\x0c \x01(\x08\x42\x02\x18\x01\x12\x13\n\x0b\x64isable_red\x18\r \x01(\x08\x12,\n\nencryption\x18\x0e \x01(\x0e\x32\x18.livekit.Encryption.Type\x12\x0e\n\x06stream\x18\x0f \x01(\t\x12\x37\n\x13\x62\x61\x63kup_codec_policy\x18\x10 \x01(\x0e\x32\x1a.livekit.BackupCodecPolicy\x12\x32\n\x0e\x61udio_features\x18\x11 \x03(\x0e\x32\x1a.livekit.AudioTrackFeature\x12>\n\x17packet_trailer_features\x18\x12 \x03(\x0e\x32\x1d.livekit.PacketTrailerFeature\"i\n\x17PublishDataTrackRequest\x12\x12\n\npub_handle\x18\x01 \x01(\r\x12\x0c\n\x04name\x18\x02 \x01(\t\x12,\n\nencryption\x18\x03 \x01(\x0e\x32\x18.livekit.Encryption.Type\"@\n\x18PublishDataTrackResponse\x12$\n\x04info\x18\x01 \x01(\x0b\x32\x16.livekit.DataTrackInfo\"/\n\x19UnpublishDataTrackRequest\x12\x12\n\npub_handle\x18\x01 \x01(\r\"B\n\x1aUnpublishDataTrackResponse\x12$\n\x04info\x18\x01 \x01(\x0b\x32\x16.livekit.DataTrackInfo\"\xad\x02\n\x1a\x44\x61taTrackSubscriberHandles\x12H\n\x0bsub_handles\x18\x01 \x03(\x0b\x32\x33.livekit.DataTrackSubscriberHandles.SubHandlesEntry\x1aZ\n\x12PublishedDataTrack\x12\x1a\n\x12publisher_identity\x18\x01 \x01(\t\x12\x15\n\rpublisher_sid\x18\x02 \x01(\t\x12\x11\n\ttrack_sid\x18\x03 \x01(\t\x1ai\n\x0fSubHandlesEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12\x45\n\x05value\x18\x02 \x01(\x0b\x32\x36.livekit.DataTrackSubscriberHandles.PublishedDataTrack:\x02\x38\x01\"]\n\x0eTrickleRequest\x12\x15\n\rcandidateInit\x18\x01 \x01(\t\x12%\n\x06target\x18\x02 \x01(\x0e\x32\x15.livekit.SignalTarget\x12\r\n\x05\x66inal\x18\x03 \x01(\x08\".\n\x10MuteTrackRequest\x12\x0b\n\x03sid\x18\x01 \x01(\t\x12\r\n\x05muted\x18\x02 \x01(\x08\"\x8b\x04\n\x0cJoinResponse\x12\x1b\n\x04room\x18\x01 \x01(\x0b\x32\r.livekit.Room\x12-\n\x0bparticipant\x18\x02 \x01(\x0b\x32\x18.livekit.ParticipantInfo\x12\x34\n\x12other_participants\x18\x03 \x03(\x0b\x32\x18.livekit.ParticipantInfo\x12\x16\n\x0eserver_version\x18\x04 \x01(\t\x12\'\n\x0bice_servers\x18\x05 \x03(\x0b\x32\x12.livekit.ICEServer\x12\x1a\n\x12subscriber_primary\x18\x06 \x01(\x08\x12\x17\n\x0f\x61lternative_url\x18\x07 \x01(\t\x12:\n\x14\x63lient_configuration\x18\x08 \x01(\x0b\x32\x1c.livekit.ClientConfiguration\x12\x15\n\rserver_region\x18\t \x01(\t\x12\x14\n\x0cping_timeout\x18\n \x01(\x05\x12\x15\n\rping_interval\x18\x0b \x01(\x05\x12(\n\x0bserver_info\x18\x0c \x01(\x0b\x32\x13.livekit.ServerInfo\x12\x13\n\x0bsif_trailer\x18\r \x01(\x0c\x12.\n\x16\x65nabled_publish_codecs\x18\x0e \x03(\x0b\x32\x0e.livekit.Codec\x12\x14\n\x0c\x66\x61st_publish\x18\x0f \x01(\x08\"\xbc\x01\n\x11ReconnectResponse\x12\'\n\x0bice_servers\x18\x01 \x03(\x0b\x32\x12.livekit.ICEServer\x12:\n\x14\x63lient_configuration\x18\x02 \x01(\x0b\x32\x1c.livekit.ClientConfiguration\x12(\n\x0bserver_info\x18\x03 \x01(\x0b\x32\x13.livekit.ServerInfo\x12\x18\n\x10last_message_seq\x18\x04 \x01(\r\"H\n\x16TrackPublishedResponse\x12\x0b\n\x03\x63id\x18\x01 \x01(\t\x12!\n\x05track\x18\x02 \x01(\x0b\x32\x12.livekit.TrackInfo\"-\n\x18TrackUnpublishedResponse\x12\x11\n\ttrack_sid\x18\x01 \x01(\t\"\xc9\x01\n\x12SessionDescription\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x0b\n\x03sdp\x18\x02 \x01(\t\x12\n\n\x02id\x18\x03 \x01(\r\x12W\n\x0fmid_to_track_id\x18\x04 \x03(\x0b\x32-.livekit.SessionDescription.MidToTrackIdEntryB\x0f\xbaP\x0cmidToTrackID\x1a\x33\n\x11MidToTrackIdEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"C\n\x11ParticipantUpdate\x12.\n\x0cparticipants\x18\x01 \x03(\x0b\x32\x18.livekit.ParticipantInfo\"s\n\x12UpdateSubscription\x12\x12\n\ntrack_sids\x18\x01 \x03(\t\x12\x11\n\tsubscribe\x18\x02 \x01(\x08\x12\x36\n\x12participant_tracks\x18\x03 \x03(\x0b\x32\x1a.livekit.ParticipantTracks\"\xb9\x01\n\x16UpdateDataSubscription\x12\x37\n\x07updates\x18\x01 \x03(\x0b\x32&.livekit.UpdateDataSubscription.Update\x1a\x66\n\x06Update\x12\x11\n\ttrack_sid\x18\x01 \x01(\t\x12\x11\n\tsubscribe\x18\x02 \x01(\x08\x12\x36\n\x07options\x18\x03 \x01(\x0b\x32%.livekit.DataTrackSubscriptionOptions\"\xa1\x01\n\x13UpdateTrackSettings\x12\x12\n\ntrack_sids\x18\x01 \x03(\t\x12\x10\n\x08\x64isabled\x18\x03 \x01(\x08\x12&\n\x07quality\x18\x04 \x01(\x0e\x32\x15.livekit.VideoQuality\x12\r\n\x05width\x18\x05 \x01(\r\x12\x0e\n\x06height\x18\x06 \x01(\r\x12\x0b\n\x03\x66ps\x18\x07 \x01(\r\x12\x10\n\x08priority\x18\x08 \x01(\r\"X\n\x15UpdateLocalAudioTrack\x12\x11\n\ttrack_sid\x18\x01 \x01(\t\x12,\n\x08\x66\x65\x61tures\x18\x02 \x03(\x0e\x32\x1a.livekit.AudioTrackFeature\"I\n\x15UpdateLocalVideoTrack\x12\x11\n\ttrack_sid\x18\x01 \x01(\t\x12\r\n\x05width\x18\x02 \x01(\r\x12\x0e\n\x06height\x18\x03 \x01(\r\"\xdd\x01\n\x0cLeaveRequest\x12\x15\n\rcan_reconnect\x18\x01 \x01(\x08\x12)\n\x06reason\x18\x02 \x01(\x0e\x32\x19.livekit.DisconnectReason\x12,\n\x06\x61\x63tion\x18\x03 \x01(\x0e\x32\x1c.livekit.LeaveRequest.Action\x12(\n\x07regions\x18\x04 \x01(\x0b\x32\x17.livekit.RegionSettings\"3\n\x06\x41\x63tion\x12\x0e\n\nDISCONNECT\x10\x00\x12\n\n\x06RESUME\x10\x01\x12\r\n\tRECONNECT\x10\x02\"O\n\x11UpdateVideoLayers\x12\x11\n\ttrack_sid\x18\x01 \x01(\t\x12#\n\x06layers\x18\x02 \x03(\x0b\x32\x13.livekit.VideoLayer:\x02\x18\x01\"\xca\x02\n\x19UpdateParticipantMetadata\x12\x36\n\x08metadata\x18\x01 \x01(\tB$\xa8P\x01\xb2P\x1e\x12\x32\n\x04name\x18\x02 \x01(\tB$\xa8P\x01\xb2P\x1e\x12l\n\nattributes\x18\x03 \x03(\x0b\x32\x32.livekit.UpdateParticipantMetadata.AttributesEntryB$\xa8P\x01\xb2P\x1e\x12 \n\nrequest_id\x18\x04 \x01(\rB\x0c\xbaP\trequestID\x1a\x31\n\x0f\x41ttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"I\n\tICEServer\x12\x0c\n\x04urls\x18\x01 \x03(\t\x12\x15\n\x08username\x18\x02 \x01(\tB\x03\xa8P\x01\x12\x17\n\ncredential\x18\x03 \x01(\tB\x03\xa8P\x01\"9\n\x0fSpeakersChanged\x12&\n\x08speakers\x18\x01 \x03(\x0b\x32\x14.livekit.SpeakerInfo\")\n\nRoomUpdate\x12\x1b\n\x04room\x18\x01 \x01(\x0b\x32\r.livekit.Room\"l\n\x15\x43onnectionQualityInfo\x12\x17\n\x0fparticipant_sid\x18\x01 \x01(\t\x12+\n\x07quality\x18\x02 \x01(\x0e\x32\x1a.livekit.ConnectionQuality\x12\r\n\x05score\x18\x03 \x01(\x02\"J\n\x17\x43onnectionQualityUpdate\x12/\n\x07updates\x18\x01 \x03(\x0b\x32\x1e.livekit.ConnectionQualityInfo\"b\n\x0fStreamStateInfo\x12\x17\n\x0fparticipant_sid\x18\x01 \x01(\t\x12\x11\n\ttrack_sid\x18\x02 \x01(\t\x12#\n\x05state\x18\x03 \x01(\x0e\x32\x14.livekit.StreamState\"D\n\x11StreamStateUpdate\x12/\n\rstream_states\x18\x01 \x03(\x0b\x32\x18.livekit.StreamStateInfo\"L\n\x11SubscribedQuality\x12&\n\x07quality\x18\x01 \x01(\x0e\x32\x15.livekit.VideoQuality\x12\x0f\n\x07\x65nabled\x18\x02 \x01(\x08\"O\n\x0fSubscribedCodec\x12\r\n\x05\x63odec\x18\x01 \x01(\t\x12-\n\tqualities\x18\x02 \x03(\x0b\x32\x1a.livekit.SubscribedQuality\"\x9f\x01\n\x17SubscribedQualityUpdate\x12\x11\n\ttrack_sid\x18\x01 \x01(\t\x12<\n\x14subscribed_qualities\x18\x02 \x03(\x0b\x32\x1a.livekit.SubscribedQualityB\x02\x18\x01\x12\x33\n\x11subscribed_codecs\x18\x03 \x03(\x0b\x32\x18.livekit.SubscribedCodec\"o\n\x1aSubscribedAudioCodecUpdate\x12\x11\n\ttrack_sid\x18\x01 \x01(\t\x12>\n\x17subscribed_audio_codecs\x18\x02 \x03(\x0b\x32\x1d.livekit.SubscribedAudioCodec\"p\n\x0fTrackPermission\x12\x17\n\x0fparticipant_sid\x18\x01 \x01(\t\x12\x12\n\nall_tracks\x18\x02 \x01(\x08\x12\x12\n\ntrack_sids\x18\x03 \x03(\t\x12\x1c\n\x14participant_identity\x18\x04 \x01(\t\"g\n\x16SubscriptionPermission\x12\x18\n\x10\x61ll_participants\x18\x01 \x01(\x08\x12\x33\n\x11track_permissions\x18\x02 \x03(\x0b\x32\x18.livekit.TrackPermission\"[\n\x1cSubscriptionPermissionUpdate\x12\x17\n\x0fparticipant_sid\x18\x01 \x01(\t\x12\x11\n\ttrack_sid\x18\x02 \x01(\t\x12\x0f\n\x07\x61llowed\x18\x03 \x01(\x08\"\xa4\x01\n\x11RoomMovedResponse\x12\x1b\n\x04room\x18\x01 \x01(\x0b\x32\r.livekit.Room\x12\r\n\x05token\x18\x02 \x01(\t\x12-\n\x0bparticipant\x18\x03 \x01(\x0b\x32\x18.livekit.ParticipantInfo\x12\x34\n\x12other_participants\x18\x04 \x03(\x0b\x32\x18.livekit.ParticipantInfo\"\xa4\x03\n\tSyncState\x12+\n\x06\x61nswer\x18\x01 \x01(\x0b\x32\x1b.livekit.SessionDescription\x12\x31\n\x0csubscription\x18\x02 \x01(\x0b\x32\x1b.livekit.UpdateSubscription\x12\x37\n\x0epublish_tracks\x18\x03 \x03(\x0b\x32\x1f.livekit.TrackPublishedResponse\x12/\n\rdata_channels\x18\x04 \x03(\x0b\x32\x18.livekit.DataChannelInfo\x12*\n\x05offer\x18\x05 \x01(\x0b\x32\x1b.livekit.SessionDescription\x12\x1b\n\x13track_sids_disabled\x18\x06 \x03(\t\x12\x44\n\x1a\x64\x61tachannel_receive_states\x18\x07 \x03(\x0b\x32 .livekit.DataChannelReceiveState\x12>\n\x13publish_data_tracks\x18\x08 \x03(\x0b\x32!.livekit.PublishDataTrackResponse\"B\n\x17\x44\x61taChannelReceiveState\x12\x15\n\rpublisher_sid\x18\x01 \x01(\t\x12\x10\n\x08last_seq\x18\x02 \x01(\r\"S\n\x0f\x44\x61taChannelInfo\x12\r\n\x05label\x18\x01 \x01(\t\x12\n\n\x02id\x18\x02 \x01(\r\x12%\n\x06target\x18\x03 \x01(\x0e\x32\x15.livekit.SignalTarget\"\xe0\x02\n\x10SimulateScenario\x12\x18\n\x0espeaker_update\x18\x01 \x01(\x05H\x00\x12\x16\n\x0cnode_failure\x18\x02 \x01(\x08H\x00\x12\x13\n\tmigration\x18\x03 \x01(\x08H\x00\x12\x16\n\x0cserver_leave\x18\x04 \x01(\x08H\x00\x12?\n\x19switch_candidate_protocol\x18\x05 \x01(\x0e\x32\x1a.livekit.CandidateProtocolH\x00\x12\x1e\n\x14subscriber_bandwidth\x18\x06 \x01(\x03H\x00\x12%\n\x1b\x64isconnect_signal_on_resume\x18\x07 \x01(\x08H\x00\x12\x31\n\'disconnect_signal_on_resume_no_messages\x18\x08 \x01(\x08H\x00\x12&\n\x1cleave_request_full_reconnect\x18\t \x01(\x08H\x00\x42\n\n\x08scenario\"&\n\x04Ping\x12\x11\n\ttimestamp\x18\x01 \x01(\x03\x12\x0b\n\x03rtt\x18\x02 \x01(\x03\"6\n\x04Pong\x12\x1b\n\x13last_ping_timestamp\x18\x01 \x01(\x03\x12\x11\n\ttimestamp\x18\x02 \x01(\x03\"6\n\x0eRegionSettings\x12$\n\x07regions\x18\x01 \x03(\x0b\x32\x13.livekit.RegionInfo\";\n\nRegionInfo\x12\x0e\n\x06region\x18\x01 \x01(\t\x12\x0b\n\x03url\x18\x02 \x01(\t\x12\x10\n\x08\x64istance\x18\x03 \x01(\x03\"R\n\x14SubscriptionResponse\x12\x11\n\ttrack_sid\x18\x01 \x01(\t\x12\'\n\x03\x65rr\x18\x02 \x01(\x0e\x32\x1a.livekit.SubscriptionError\"\x96\x06\n\x0fRequestResponse\x12 \n\nrequest_id\x18\x01 \x01(\rB\x0c\xbaP\trequestID\x12/\n\x06reason\x18\x02 \x01(\x0e\x32\x1f.livekit.RequestResponse.Reason\x12\x0f\n\x07message\x18\x03 \x01(\t\x12*\n\x07trickle\x18\x04 \x01(\x0b\x32\x17.livekit.TrickleRequestH\x00\x12-\n\tadd_track\x18\x05 \x01(\x0b\x32\x18.livekit.AddTrackRequestH\x00\x12)\n\x04mute\x18\x06 \x01(\x0b\x32\x19.livekit.MuteTrackRequestH\x00\x12=\n\x0fupdate_metadata\x18\x07 \x01(\x0b\x32\".livekit.UpdateParticipantMetadataH\x00\x12<\n\x12update_audio_track\x18\x08 \x01(\x0b\x32\x1e.livekit.UpdateLocalAudioTrackH\x00\x12<\n\x12update_video_track\x18\t \x01(\x0b\x32\x1e.livekit.UpdateLocalVideoTrackH\x00\x12>\n\x12publish_data_track\x18\n \x01(\x0b\x32 .livekit.PublishDataTrackRequestH\x00\x12\x42\n\x14unpublish_data_track\x18\x0b \x01(\x0b\x32\".livekit.UnpublishDataTrackRequestH\x00\"\xce\x01\n\x06Reason\x12\x06\n\x02OK\x10\x00\x12\r\n\tNOT_FOUND\x10\x01\x12\x0f\n\x0bNOT_ALLOWED\x10\x02\x12\x12\n\x0eLIMIT_EXCEEDED\x10\x03\x12\n\n\x06QUEUED\x10\x04\x12\x14\n\x10UNSUPPORTED_TYPE\x10\x05\x12\x16\n\x12UNCLASSIFIED_ERROR\x10\x06\x12\x12\n\x0eINVALID_HANDLE\x10\x07\x12\x10\n\x0cINVALID_NAME\x10\x08\x12\x14\n\x10\x44UPLICATE_HANDLE\x10\t\x12\x12\n\x0e\x44UPLICATE_NAME\x10\nB\t\n\x07request\"$\n\x0fTrackSubscribed\x12\x11\n\ttrack_sid\x18\x01 \x01(\t\"\xe5\x01\n\x12\x43onnectionSettings\x12\x16\n\x0e\x61uto_subscribe\x18\x01 \x01(\x08\x12\x17\n\x0f\x61\x64\x61ptive_stream\x18\x02 \x01(\x08\x12#\n\x16subscriber_allow_pause\x18\x03 \x01(\x08H\x00\x88\x01\x01\x12\x18\n\x10\x64isable_ice_lite\x18\x04 \x01(\x08\x12&\n\x19\x61uto_subscribe_data_track\x18\x05 \x01(\x08H\x01\x88\x01\x01\x42\x19\n\x17_subscriber_allow_pauseB\x1c\n\x1a_auto_subscribe_data_track\"\xd2\x04\n\x0bJoinRequest\x12(\n\x0b\x63lient_info\x18\x01 \x01(\x0b\x32\x13.livekit.ClientInfo\x12\x38\n\x13\x63onnection_settings\x18\x02 \x01(\x0b\x32\x1b.livekit.ConnectionSettings\x12\x36\n\x08metadata\x18\x03 \x01(\tB$\xa8P\x01\xb2P\x1e\x12u\n\x16participant_attributes\x18\x04 \x03(\x0b\x32/.livekit.JoinRequest.ParticipantAttributesEntryB$\xa8P\x01\xb2P\x1e\x12\x34\n\x12\x61\x64\x64_track_requests\x18\x05 \x03(\x0b\x32\x18.livekit.AddTrackRequest\x12\x34\n\x0fpublisher_offer\x18\x06 \x01(\x0b\x32\x1b.livekit.SessionDescription\x12\x11\n\treconnect\x18\x07 \x01(\x08\x12\x32\n\x10reconnect_reason\x18\x08 \x01(\x0e\x32\x18.livekit.ReconnectReason\x12\x17\n\x0fparticipant_sid\x18\t \x01(\t\x12&\n\nsync_state\x18\n \x01(\x0b\x32\x12.livekit.SyncState\x1a<\n\x1aParticipantAttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x8b\x01\n\x12WrappedJoinRequest\x12<\n\x0b\x63ompression\x18\x01 \x01(\x0e\x32\'.livekit.WrappedJoinRequest.Compression\x12\x14\n\x0cjoin_request\x18\x02 \x01(\x0c\"!\n\x0b\x43ompression\x12\x08\n\x04NONE\x10\x00\x12\x08\n\x04GZIP\x10\x01\"B\n\x18MediaSectionsRequirement\x12\x12\n\nnum_audios\x18\x01 \x01(\r\x12\x12\n\nnum_videos\x18\x02 \x01(\r*-\n\x0cSignalTarget\x12\r\n\tPUBLISHER\x10\x00\x12\x0e\n\nSUBSCRIBER\x10\x01*%\n\x0bStreamState\x12\n\n\x06\x41\x43TIVE\x10\x00\x12\n\n\x06PAUSED\x10\x01*.\n\x11\x43\x61ndidateProtocol\x12\x07\n\x03UDP\x10\x00\x12\x07\n\x03TCP\x10\x01\x12\x07\n\x03TLS\x10\x02\x42\x46Z#github.com/livekit/protocol/livekit\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'rtc', _globals)
+if _descriptor._USE_C_DESCRIPTORS == False:
+ _globals['DESCRIPTOR']._options = None
+ _globals['DESCRIPTOR']._serialized_options = b'Z#github.com/livekit/protocol/livekit\252\002\rLiveKit.Proto\352\002\016LiveKit::Proto'
+ _globals['_SIGNALREQUEST'].fields_by_name['update_layers']._options = None
+ _globals['_SIGNALREQUEST'].fields_by_name['update_layers']._serialized_options = b'\030\001'
+ _globals['_ADDTRACKREQUEST'].fields_by_name['disable_dtx']._options = None
+ _globals['_ADDTRACKREQUEST'].fields_by_name['disable_dtx']._serialized_options = b'\030\001'
+ _globals['_ADDTRACKREQUEST'].fields_by_name['stereo']._options = None
+ _globals['_ADDTRACKREQUEST'].fields_by_name['stereo']._serialized_options = b'\030\001'
+ _globals['_DATATRACKSUBSCRIBERHANDLES_SUBHANDLESENTRY']._options = None
+ _globals['_DATATRACKSUBSCRIBERHANDLES_SUBHANDLESENTRY']._serialized_options = b'8\001'
+ _globals['_SESSIONDESCRIPTION_MIDTOTRACKIDENTRY']._options = None
+ _globals['_SESSIONDESCRIPTION_MIDTOTRACKIDENTRY']._serialized_options = b'8\001'
+ _globals['_SESSIONDESCRIPTION'].fields_by_name['mid_to_track_id']._options = None
+ _globals['_SESSIONDESCRIPTION'].fields_by_name['mid_to_track_id']._serialized_options = b'\272P\014midToTrackID'
+ _globals['_UPDATEVIDEOLAYERS']._options = None
+ _globals['_UPDATEVIDEOLAYERS']._serialized_options = b'\030\001'
+ _globals['_UPDATEPARTICIPANTMETADATA_ATTRIBUTESENTRY']._options = None
+ _globals['_UPDATEPARTICIPANTMETADATA_ATTRIBUTESENTRY']._serialized_options = b'8\001'
+ _globals['_UPDATEPARTICIPANTMETADATA'].fields_by_name['metadata']._options = None
+ _globals['_UPDATEPARTICIPANTMETADATA'].fields_by_name['metadata']._serialized_options = b'\250P\001\262P\036'
+ _globals['_UPDATEPARTICIPANTMETADATA'].fields_by_name['name']._options = None
+ _globals['_UPDATEPARTICIPANTMETADATA'].fields_by_name['name']._serialized_options = b'\250P\001\262P\036'
+ _globals['_UPDATEPARTICIPANTMETADATA'].fields_by_name['attributes']._options = None
+ _globals['_UPDATEPARTICIPANTMETADATA'].fields_by_name['attributes']._serialized_options = b'\250P\001\262P\036'
+ _globals['_UPDATEPARTICIPANTMETADATA'].fields_by_name['request_id']._options = None
+ _globals['_UPDATEPARTICIPANTMETADATA'].fields_by_name['request_id']._serialized_options = b'\272P\trequestID'
+ _globals['_ICESERVER'].fields_by_name['username']._options = None
+ _globals['_ICESERVER'].fields_by_name['username']._serialized_options = b'\250P\001'
+ _globals['_ICESERVER'].fields_by_name['credential']._options = None
+ _globals['_ICESERVER'].fields_by_name['credential']._serialized_options = b'\250P\001'
+ _globals['_SUBSCRIBEDQUALITYUPDATE'].fields_by_name['subscribed_qualities']._options = None
+ _globals['_SUBSCRIBEDQUALITYUPDATE'].fields_by_name['subscribed_qualities']._serialized_options = b'\030\001'
+ _globals['_REQUESTRESPONSE'].fields_by_name['request_id']._options = None
+ _globals['_REQUESTRESPONSE'].fields_by_name['request_id']._serialized_options = b'\272P\trequestID'
+ _globals['_JOINREQUEST_PARTICIPANTATTRIBUTESENTRY']._options = None
+ _globals['_JOINREQUEST_PARTICIPANTATTRIBUTESENTRY']._serialized_options = b'8\001'
+ _globals['_JOINREQUEST'].fields_by_name['metadata']._options = None
+ _globals['_JOINREQUEST'].fields_by_name['metadata']._serialized_options = b'\250P\001\262P\036'
+ _globals['_JOINREQUEST'].fields_by_name['participant_attributes']._options = None
+ _globals['_JOINREQUEST'].fields_by_name['participant_attributes']._serialized_options = b'\250P\001\262P\036'
+ _globals['_SIGNALTARGET']._serialized_start=11075
+ _globals['_SIGNALTARGET']._serialized_end=11120
+ _globals['_STREAMSTATE']._serialized_start=11122
+ _globals['_STREAMSTATE']._serialized_end=11159
+ _globals['_CANDIDATEPROTOCOL']._serialized_start=11161
+ _globals['_CANDIDATEPROTOCOL']._serialized_end=11207
+ _globals['_SIGNALREQUEST']._serialized_start=75
+ _globals['_SIGNALREQUEST']._serialized_end=1145
+ _globals['_SIGNALRESPONSE']._serialized_start=1148
+ _globals['_SIGNALRESPONSE']._serialized_end=2706
+ _globals['_SIMULCASTCODEC']._serialized_start=2709
+ _globals['_SIMULCASTCODEC']._serialized_end=2842
+ _globals['_ADDTRACKREQUEST']._serialized_start=2845
+ _globals['_ADDTRACKREQUEST']._serialized_end=3409
+ _globals['_PUBLISHDATATRACKREQUEST']._serialized_start=3411
+ _globals['_PUBLISHDATATRACKREQUEST']._serialized_end=3516
+ _globals['_PUBLISHDATATRACKRESPONSE']._serialized_start=3518
+ _globals['_PUBLISHDATATRACKRESPONSE']._serialized_end=3582
+ _globals['_UNPUBLISHDATATRACKREQUEST']._serialized_start=3584
+ _globals['_UNPUBLISHDATATRACKREQUEST']._serialized_end=3631
+ _globals['_UNPUBLISHDATATRACKRESPONSE']._serialized_start=3633
+ _globals['_UNPUBLISHDATATRACKRESPONSE']._serialized_end=3699
+ _globals['_DATATRACKSUBSCRIBERHANDLES']._serialized_start=3702
+ _globals['_DATATRACKSUBSCRIBERHANDLES']._serialized_end=4003
+ _globals['_DATATRACKSUBSCRIBERHANDLES_PUBLISHEDDATATRACK']._serialized_start=3806
+ _globals['_DATATRACKSUBSCRIBERHANDLES_PUBLISHEDDATATRACK']._serialized_end=3896
+ _globals['_DATATRACKSUBSCRIBERHANDLES_SUBHANDLESENTRY']._serialized_start=3898
+ _globals['_DATATRACKSUBSCRIBERHANDLES_SUBHANDLESENTRY']._serialized_end=4003
+ _globals['_TRICKLEREQUEST']._serialized_start=4005
+ _globals['_TRICKLEREQUEST']._serialized_end=4098
+ _globals['_MUTETRACKREQUEST']._serialized_start=4100
+ _globals['_MUTETRACKREQUEST']._serialized_end=4146
+ _globals['_JOINRESPONSE']._serialized_start=4149
+ _globals['_JOINRESPONSE']._serialized_end=4672
+ _globals['_RECONNECTRESPONSE']._serialized_start=4675
+ _globals['_RECONNECTRESPONSE']._serialized_end=4863
+ _globals['_TRACKPUBLISHEDRESPONSE']._serialized_start=4865
+ _globals['_TRACKPUBLISHEDRESPONSE']._serialized_end=4937
+ _globals['_TRACKUNPUBLISHEDRESPONSE']._serialized_start=4939
+ _globals['_TRACKUNPUBLISHEDRESPONSE']._serialized_end=4984
+ _globals['_SESSIONDESCRIPTION']._serialized_start=4987
+ _globals['_SESSIONDESCRIPTION']._serialized_end=5188
+ _globals['_SESSIONDESCRIPTION_MIDTOTRACKIDENTRY']._serialized_start=5137
+ _globals['_SESSIONDESCRIPTION_MIDTOTRACKIDENTRY']._serialized_end=5188
+ _globals['_PARTICIPANTUPDATE']._serialized_start=5190
+ _globals['_PARTICIPANTUPDATE']._serialized_end=5257
+ _globals['_UPDATESUBSCRIPTION']._serialized_start=5259
+ _globals['_UPDATESUBSCRIPTION']._serialized_end=5374
+ _globals['_UPDATEDATASUBSCRIPTION']._serialized_start=5377
+ _globals['_UPDATEDATASUBSCRIPTION']._serialized_end=5562
+ _globals['_UPDATEDATASUBSCRIPTION_UPDATE']._serialized_start=5460
+ _globals['_UPDATEDATASUBSCRIPTION_UPDATE']._serialized_end=5562
+ _globals['_UPDATETRACKSETTINGS']._serialized_start=5565
+ _globals['_UPDATETRACKSETTINGS']._serialized_end=5726
+ _globals['_UPDATELOCALAUDIOTRACK']._serialized_start=5728
+ _globals['_UPDATELOCALAUDIOTRACK']._serialized_end=5816
+ _globals['_UPDATELOCALVIDEOTRACK']._serialized_start=5818
+ _globals['_UPDATELOCALVIDEOTRACK']._serialized_end=5891
+ _globals['_LEAVEREQUEST']._serialized_start=5894
+ _globals['_LEAVEREQUEST']._serialized_end=6115
+ _globals['_LEAVEREQUEST_ACTION']._serialized_start=6064
+ _globals['_LEAVEREQUEST_ACTION']._serialized_end=6115
+ _globals['_UPDATEVIDEOLAYERS']._serialized_start=6117
+ _globals['_UPDATEVIDEOLAYERS']._serialized_end=6196
+ _globals['_UPDATEPARTICIPANTMETADATA']._serialized_start=6199
+ _globals['_UPDATEPARTICIPANTMETADATA']._serialized_end=6529
+ _globals['_UPDATEPARTICIPANTMETADATA_ATTRIBUTESENTRY']._serialized_start=6480
+ _globals['_UPDATEPARTICIPANTMETADATA_ATTRIBUTESENTRY']._serialized_end=6529
+ _globals['_ICESERVER']._serialized_start=6531
+ _globals['_ICESERVER']._serialized_end=6604
+ _globals['_SPEAKERSCHANGED']._serialized_start=6606
+ _globals['_SPEAKERSCHANGED']._serialized_end=6663
+ _globals['_ROOMUPDATE']._serialized_start=6665
+ _globals['_ROOMUPDATE']._serialized_end=6706
+ _globals['_CONNECTIONQUALITYINFO']._serialized_start=6708
+ _globals['_CONNECTIONQUALITYINFO']._serialized_end=6816
+ _globals['_CONNECTIONQUALITYUPDATE']._serialized_start=6818
+ _globals['_CONNECTIONQUALITYUPDATE']._serialized_end=6892
+ _globals['_STREAMSTATEINFO']._serialized_start=6894
+ _globals['_STREAMSTATEINFO']._serialized_end=6992
+ _globals['_STREAMSTATEUPDATE']._serialized_start=6994
+ _globals['_STREAMSTATEUPDATE']._serialized_end=7062
+ _globals['_SUBSCRIBEDQUALITY']._serialized_start=7064
+ _globals['_SUBSCRIBEDQUALITY']._serialized_end=7140
+ _globals['_SUBSCRIBEDCODEC']._serialized_start=7142
+ _globals['_SUBSCRIBEDCODEC']._serialized_end=7221
+ _globals['_SUBSCRIBEDQUALITYUPDATE']._serialized_start=7224
+ _globals['_SUBSCRIBEDQUALITYUPDATE']._serialized_end=7383
+ _globals['_SUBSCRIBEDAUDIOCODECUPDATE']._serialized_start=7385
+ _globals['_SUBSCRIBEDAUDIOCODECUPDATE']._serialized_end=7496
+ _globals['_TRACKPERMISSION']._serialized_start=7498
+ _globals['_TRACKPERMISSION']._serialized_end=7610
+ _globals['_SUBSCRIPTIONPERMISSION']._serialized_start=7612
+ _globals['_SUBSCRIPTIONPERMISSION']._serialized_end=7715
+ _globals['_SUBSCRIPTIONPERMISSIONUPDATE']._serialized_start=7717
+ _globals['_SUBSCRIPTIONPERMISSIONUPDATE']._serialized_end=7808
+ _globals['_ROOMMOVEDRESPONSE']._serialized_start=7811
+ _globals['_ROOMMOVEDRESPONSE']._serialized_end=7975
+ _globals['_SYNCSTATE']._serialized_start=7978
+ _globals['_SYNCSTATE']._serialized_end=8398
+ _globals['_DATACHANNELRECEIVESTATE']._serialized_start=8400
+ _globals['_DATACHANNELRECEIVESTATE']._serialized_end=8466
+ _globals['_DATACHANNELINFO']._serialized_start=8468
+ _globals['_DATACHANNELINFO']._serialized_end=8551
+ _globals['_SIMULATESCENARIO']._serialized_start=8554
+ _globals['_SIMULATESCENARIO']._serialized_end=8906
+ _globals['_PING']._serialized_start=8908
+ _globals['_PING']._serialized_end=8946
+ _globals['_PONG']._serialized_start=8948
+ _globals['_PONG']._serialized_end=9002
+ _globals['_REGIONSETTINGS']._serialized_start=9004
+ _globals['_REGIONSETTINGS']._serialized_end=9058
+ _globals['_REGIONINFO']._serialized_start=9060
+ _globals['_REGIONINFO']._serialized_end=9119
+ _globals['_SUBSCRIPTIONRESPONSE']._serialized_start=9121
+ _globals['_SUBSCRIPTIONRESPONSE']._serialized_end=9203
+ _globals['_REQUESTRESPONSE']._serialized_start=9206
+ _globals['_REQUESTRESPONSE']._serialized_end=9996
+ _globals['_REQUESTRESPONSE_REASON']._serialized_start=9779
+ _globals['_REQUESTRESPONSE_REASON']._serialized_end=9985
+ _globals['_TRACKSUBSCRIBED']._serialized_start=9998
+ _globals['_TRACKSUBSCRIBED']._serialized_end=10034
+ _globals['_CONNECTIONSETTINGS']._serialized_start=10037
+ _globals['_CONNECTIONSETTINGS']._serialized_end=10266
+ _globals['_JOINREQUEST']._serialized_start=10269
+ _globals['_JOINREQUEST']._serialized_end=10863
+ _globals['_JOINREQUEST_PARTICIPANTATTRIBUTESENTRY']._serialized_start=10803
+ _globals['_JOINREQUEST_PARTICIPANTATTRIBUTESENTRY']._serialized_end=10863
+ _globals['_WRAPPEDJOINREQUEST']._serialized_start=10866
+ _globals['_WRAPPEDJOINREQUEST']._serialized_end=11005
+ _globals['_WRAPPEDJOINREQUEST_COMPRESSION']._serialized_start=10972
+ _globals['_WRAPPEDJOINREQUEST_COMPRESSION']._serialized_end=11005
+ _globals['_MEDIASECTIONSREQUIREMENT']._serialized_start=11007
+ _globals['_MEDIASECTIONSREQUIREMENT']._serialized_end=11073
+# @@protoc_insertion_point(module_scope)
diff --git a/livekit-protocol/livekit/protocol/rtc.pyi b/livekit-protocol/livekit/protocol/rtc.pyi
new file mode 100644
index 00000000..da3d829f
--- /dev/null
+++ b/livekit-protocol/livekit/protocol/rtc.pyi
@@ -0,0 +1,802 @@
+from . import models as _models
+from .logger_pb import options as _options_pb2
+from google.protobuf.internal import containers as _containers
+from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union
+
+DESCRIPTOR: _descriptor.FileDescriptor
+
+class SignalTarget(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ PUBLISHER: _ClassVar[SignalTarget]
+ SUBSCRIBER: _ClassVar[SignalTarget]
+
+class StreamState(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ ACTIVE: _ClassVar[StreamState]
+ PAUSED: _ClassVar[StreamState]
+
+class CandidateProtocol(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ UDP: _ClassVar[CandidateProtocol]
+ TCP: _ClassVar[CandidateProtocol]
+ TLS: _ClassVar[CandidateProtocol]
+PUBLISHER: SignalTarget
+SUBSCRIBER: SignalTarget
+ACTIVE: StreamState
+PAUSED: StreamState
+UDP: CandidateProtocol
+TCP: CandidateProtocol
+TLS: CandidateProtocol
+
+class SignalRequest(_message.Message):
+ __slots__ = ("offer", "answer", "trickle", "add_track", "mute", "subscription", "track_setting", "leave", "update_layers", "subscription_permission", "sync_state", "simulate", "ping", "update_metadata", "ping_req", "update_audio_track", "update_video_track", "publish_data_track_request", "unpublish_data_track_request", "update_data_subscription")
+ OFFER_FIELD_NUMBER: _ClassVar[int]
+ ANSWER_FIELD_NUMBER: _ClassVar[int]
+ TRICKLE_FIELD_NUMBER: _ClassVar[int]
+ ADD_TRACK_FIELD_NUMBER: _ClassVar[int]
+ MUTE_FIELD_NUMBER: _ClassVar[int]
+ SUBSCRIPTION_FIELD_NUMBER: _ClassVar[int]
+ TRACK_SETTING_FIELD_NUMBER: _ClassVar[int]
+ LEAVE_FIELD_NUMBER: _ClassVar[int]
+ UPDATE_LAYERS_FIELD_NUMBER: _ClassVar[int]
+ SUBSCRIPTION_PERMISSION_FIELD_NUMBER: _ClassVar[int]
+ SYNC_STATE_FIELD_NUMBER: _ClassVar[int]
+ SIMULATE_FIELD_NUMBER: _ClassVar[int]
+ PING_FIELD_NUMBER: _ClassVar[int]
+ UPDATE_METADATA_FIELD_NUMBER: _ClassVar[int]
+ PING_REQ_FIELD_NUMBER: _ClassVar[int]
+ UPDATE_AUDIO_TRACK_FIELD_NUMBER: _ClassVar[int]
+ UPDATE_VIDEO_TRACK_FIELD_NUMBER: _ClassVar[int]
+ PUBLISH_DATA_TRACK_REQUEST_FIELD_NUMBER: _ClassVar[int]
+ UNPUBLISH_DATA_TRACK_REQUEST_FIELD_NUMBER: _ClassVar[int]
+ UPDATE_DATA_SUBSCRIPTION_FIELD_NUMBER: _ClassVar[int]
+ offer: SessionDescription
+ answer: SessionDescription
+ trickle: TrickleRequest
+ add_track: AddTrackRequest
+ mute: MuteTrackRequest
+ subscription: UpdateSubscription
+ track_setting: UpdateTrackSettings
+ leave: LeaveRequest
+ update_layers: UpdateVideoLayers
+ subscription_permission: SubscriptionPermission
+ sync_state: SyncState
+ simulate: SimulateScenario
+ ping: int
+ update_metadata: UpdateParticipantMetadata
+ ping_req: Ping
+ update_audio_track: UpdateLocalAudioTrack
+ update_video_track: UpdateLocalVideoTrack
+ publish_data_track_request: PublishDataTrackRequest
+ unpublish_data_track_request: UnpublishDataTrackRequest
+ update_data_subscription: UpdateDataSubscription
+ def __init__(self, offer: _Optional[_Union[SessionDescription, _Mapping]] = ..., answer: _Optional[_Union[SessionDescription, _Mapping]] = ..., trickle: _Optional[_Union[TrickleRequest, _Mapping]] = ..., add_track: _Optional[_Union[AddTrackRequest, _Mapping]] = ..., mute: _Optional[_Union[MuteTrackRequest, _Mapping]] = ..., subscription: _Optional[_Union[UpdateSubscription, _Mapping]] = ..., track_setting: _Optional[_Union[UpdateTrackSettings, _Mapping]] = ..., leave: _Optional[_Union[LeaveRequest, _Mapping]] = ..., update_layers: _Optional[_Union[UpdateVideoLayers, _Mapping]] = ..., subscription_permission: _Optional[_Union[SubscriptionPermission, _Mapping]] = ..., sync_state: _Optional[_Union[SyncState, _Mapping]] = ..., simulate: _Optional[_Union[SimulateScenario, _Mapping]] = ..., ping: _Optional[int] = ..., update_metadata: _Optional[_Union[UpdateParticipantMetadata, _Mapping]] = ..., ping_req: _Optional[_Union[Ping, _Mapping]] = ..., update_audio_track: _Optional[_Union[UpdateLocalAudioTrack, _Mapping]] = ..., update_video_track: _Optional[_Union[UpdateLocalVideoTrack, _Mapping]] = ..., publish_data_track_request: _Optional[_Union[PublishDataTrackRequest, _Mapping]] = ..., unpublish_data_track_request: _Optional[_Union[UnpublishDataTrackRequest, _Mapping]] = ..., update_data_subscription: _Optional[_Union[UpdateDataSubscription, _Mapping]] = ...) -> None: ...
+
+class SignalResponse(_message.Message):
+ __slots__ = ("join", "answer", "offer", "trickle", "update", "track_published", "leave", "mute", "speakers_changed", "room_update", "connection_quality", "stream_state_update", "subscribed_quality_update", "subscription_permission_update", "refresh_token", "track_unpublished", "pong", "reconnect", "pong_resp", "subscription_response", "request_response", "track_subscribed", "room_moved", "media_sections_requirement", "subscribed_audio_codec_update", "publish_data_track_response", "unpublish_data_track_response", "data_track_subscriber_handles")
+ JOIN_FIELD_NUMBER: _ClassVar[int]
+ ANSWER_FIELD_NUMBER: _ClassVar[int]
+ OFFER_FIELD_NUMBER: _ClassVar[int]
+ TRICKLE_FIELD_NUMBER: _ClassVar[int]
+ UPDATE_FIELD_NUMBER: _ClassVar[int]
+ TRACK_PUBLISHED_FIELD_NUMBER: _ClassVar[int]
+ LEAVE_FIELD_NUMBER: _ClassVar[int]
+ MUTE_FIELD_NUMBER: _ClassVar[int]
+ SPEAKERS_CHANGED_FIELD_NUMBER: _ClassVar[int]
+ ROOM_UPDATE_FIELD_NUMBER: _ClassVar[int]
+ CONNECTION_QUALITY_FIELD_NUMBER: _ClassVar[int]
+ STREAM_STATE_UPDATE_FIELD_NUMBER: _ClassVar[int]
+ SUBSCRIBED_QUALITY_UPDATE_FIELD_NUMBER: _ClassVar[int]
+ SUBSCRIPTION_PERMISSION_UPDATE_FIELD_NUMBER: _ClassVar[int]
+ REFRESH_TOKEN_FIELD_NUMBER: _ClassVar[int]
+ TRACK_UNPUBLISHED_FIELD_NUMBER: _ClassVar[int]
+ PONG_FIELD_NUMBER: _ClassVar[int]
+ RECONNECT_FIELD_NUMBER: _ClassVar[int]
+ PONG_RESP_FIELD_NUMBER: _ClassVar[int]
+ SUBSCRIPTION_RESPONSE_FIELD_NUMBER: _ClassVar[int]
+ REQUEST_RESPONSE_FIELD_NUMBER: _ClassVar[int]
+ TRACK_SUBSCRIBED_FIELD_NUMBER: _ClassVar[int]
+ ROOM_MOVED_FIELD_NUMBER: _ClassVar[int]
+ MEDIA_SECTIONS_REQUIREMENT_FIELD_NUMBER: _ClassVar[int]
+ SUBSCRIBED_AUDIO_CODEC_UPDATE_FIELD_NUMBER: _ClassVar[int]
+ PUBLISH_DATA_TRACK_RESPONSE_FIELD_NUMBER: _ClassVar[int]
+ UNPUBLISH_DATA_TRACK_RESPONSE_FIELD_NUMBER: _ClassVar[int]
+ DATA_TRACK_SUBSCRIBER_HANDLES_FIELD_NUMBER: _ClassVar[int]
+ join: JoinResponse
+ answer: SessionDescription
+ offer: SessionDescription
+ trickle: TrickleRequest
+ update: ParticipantUpdate
+ track_published: TrackPublishedResponse
+ leave: LeaveRequest
+ mute: MuteTrackRequest
+ speakers_changed: SpeakersChanged
+ room_update: RoomUpdate
+ connection_quality: ConnectionQualityUpdate
+ stream_state_update: StreamStateUpdate
+ subscribed_quality_update: SubscribedQualityUpdate
+ subscription_permission_update: SubscriptionPermissionUpdate
+ refresh_token: str
+ track_unpublished: TrackUnpublishedResponse
+ pong: int
+ reconnect: ReconnectResponse
+ pong_resp: Pong
+ subscription_response: SubscriptionResponse
+ request_response: RequestResponse
+ track_subscribed: TrackSubscribed
+ room_moved: RoomMovedResponse
+ media_sections_requirement: MediaSectionsRequirement
+ subscribed_audio_codec_update: SubscribedAudioCodecUpdate
+ publish_data_track_response: PublishDataTrackResponse
+ unpublish_data_track_response: UnpublishDataTrackResponse
+ data_track_subscriber_handles: DataTrackSubscriberHandles
+ def __init__(self, join: _Optional[_Union[JoinResponse, _Mapping]] = ..., answer: _Optional[_Union[SessionDescription, _Mapping]] = ..., offer: _Optional[_Union[SessionDescription, _Mapping]] = ..., trickle: _Optional[_Union[TrickleRequest, _Mapping]] = ..., update: _Optional[_Union[ParticipantUpdate, _Mapping]] = ..., track_published: _Optional[_Union[TrackPublishedResponse, _Mapping]] = ..., leave: _Optional[_Union[LeaveRequest, _Mapping]] = ..., mute: _Optional[_Union[MuteTrackRequest, _Mapping]] = ..., speakers_changed: _Optional[_Union[SpeakersChanged, _Mapping]] = ..., room_update: _Optional[_Union[RoomUpdate, _Mapping]] = ..., connection_quality: _Optional[_Union[ConnectionQualityUpdate, _Mapping]] = ..., stream_state_update: _Optional[_Union[StreamStateUpdate, _Mapping]] = ..., subscribed_quality_update: _Optional[_Union[SubscribedQualityUpdate, _Mapping]] = ..., subscription_permission_update: _Optional[_Union[SubscriptionPermissionUpdate, _Mapping]] = ..., refresh_token: _Optional[str] = ..., track_unpublished: _Optional[_Union[TrackUnpublishedResponse, _Mapping]] = ..., pong: _Optional[int] = ..., reconnect: _Optional[_Union[ReconnectResponse, _Mapping]] = ..., pong_resp: _Optional[_Union[Pong, _Mapping]] = ..., subscription_response: _Optional[_Union[SubscriptionResponse, _Mapping]] = ..., request_response: _Optional[_Union[RequestResponse, _Mapping]] = ..., track_subscribed: _Optional[_Union[TrackSubscribed, _Mapping]] = ..., room_moved: _Optional[_Union[RoomMovedResponse, _Mapping]] = ..., media_sections_requirement: _Optional[_Union[MediaSectionsRequirement, _Mapping]] = ..., subscribed_audio_codec_update: _Optional[_Union[SubscribedAudioCodecUpdate, _Mapping]] = ..., publish_data_track_response: _Optional[_Union[PublishDataTrackResponse, _Mapping]] = ..., unpublish_data_track_response: _Optional[_Union[UnpublishDataTrackResponse, _Mapping]] = ..., data_track_subscriber_handles: _Optional[_Union[DataTrackSubscriberHandles, _Mapping]] = ...) -> None: ...
+
+class SimulcastCodec(_message.Message):
+ __slots__ = ("codec", "cid", "layers", "video_layer_mode")
+ CODEC_FIELD_NUMBER: _ClassVar[int]
+ CID_FIELD_NUMBER: _ClassVar[int]
+ LAYERS_FIELD_NUMBER: _ClassVar[int]
+ VIDEO_LAYER_MODE_FIELD_NUMBER: _ClassVar[int]
+ codec: str
+ cid: str
+ layers: _containers.RepeatedCompositeFieldContainer[_models.VideoLayer]
+ video_layer_mode: _models.VideoLayer.Mode
+ def __init__(self, codec: _Optional[str] = ..., cid: _Optional[str] = ..., layers: _Optional[_Iterable[_Union[_models.VideoLayer, _Mapping]]] = ..., video_layer_mode: _Optional[_Union[_models.VideoLayer.Mode, str]] = ...) -> None: ...
+
+class AddTrackRequest(_message.Message):
+ __slots__ = ("cid", "name", "type", "width", "height", "muted", "disable_dtx", "source", "layers", "simulcast_codecs", "sid", "stereo", "disable_red", "encryption", "stream", "backup_codec_policy", "audio_features", "packet_trailer_features")
+ CID_FIELD_NUMBER: _ClassVar[int]
+ NAME_FIELD_NUMBER: _ClassVar[int]
+ TYPE_FIELD_NUMBER: _ClassVar[int]
+ WIDTH_FIELD_NUMBER: _ClassVar[int]
+ HEIGHT_FIELD_NUMBER: _ClassVar[int]
+ MUTED_FIELD_NUMBER: _ClassVar[int]
+ DISABLE_DTX_FIELD_NUMBER: _ClassVar[int]
+ SOURCE_FIELD_NUMBER: _ClassVar[int]
+ LAYERS_FIELD_NUMBER: _ClassVar[int]
+ SIMULCAST_CODECS_FIELD_NUMBER: _ClassVar[int]
+ SID_FIELD_NUMBER: _ClassVar[int]
+ STEREO_FIELD_NUMBER: _ClassVar[int]
+ DISABLE_RED_FIELD_NUMBER: _ClassVar[int]
+ ENCRYPTION_FIELD_NUMBER: _ClassVar[int]
+ STREAM_FIELD_NUMBER: _ClassVar[int]
+ BACKUP_CODEC_POLICY_FIELD_NUMBER: _ClassVar[int]
+ AUDIO_FEATURES_FIELD_NUMBER: _ClassVar[int]
+ PACKET_TRAILER_FEATURES_FIELD_NUMBER: _ClassVar[int]
+ cid: str
+ name: str
+ type: _models.TrackType
+ width: int
+ height: int
+ muted: bool
+ disable_dtx: bool
+ source: _models.TrackSource
+ layers: _containers.RepeatedCompositeFieldContainer[_models.VideoLayer]
+ simulcast_codecs: _containers.RepeatedCompositeFieldContainer[SimulcastCodec]
+ sid: str
+ stereo: bool
+ disable_red: bool
+ encryption: _models.Encryption.Type
+ stream: str
+ backup_codec_policy: _models.BackupCodecPolicy
+ audio_features: _containers.RepeatedScalarFieldContainer[_models.AudioTrackFeature]
+ packet_trailer_features: _containers.RepeatedScalarFieldContainer[_models.PacketTrailerFeature]
+ def __init__(self, cid: _Optional[str] = ..., name: _Optional[str] = ..., type: _Optional[_Union[_models.TrackType, str]] = ..., width: _Optional[int] = ..., height: _Optional[int] = ..., muted: bool = ..., disable_dtx: bool = ..., source: _Optional[_Union[_models.TrackSource, str]] = ..., layers: _Optional[_Iterable[_Union[_models.VideoLayer, _Mapping]]] = ..., simulcast_codecs: _Optional[_Iterable[_Union[SimulcastCodec, _Mapping]]] = ..., sid: _Optional[str] = ..., stereo: bool = ..., disable_red: bool = ..., encryption: _Optional[_Union[_models.Encryption.Type, str]] = ..., stream: _Optional[str] = ..., backup_codec_policy: _Optional[_Union[_models.BackupCodecPolicy, str]] = ..., audio_features: _Optional[_Iterable[_Union[_models.AudioTrackFeature, str]]] = ..., packet_trailer_features: _Optional[_Iterable[_Union[_models.PacketTrailerFeature, str]]] = ...) -> None: ...
+
+class PublishDataTrackRequest(_message.Message):
+ __slots__ = ("pub_handle", "name", "encryption")
+ PUB_HANDLE_FIELD_NUMBER: _ClassVar[int]
+ NAME_FIELD_NUMBER: _ClassVar[int]
+ ENCRYPTION_FIELD_NUMBER: _ClassVar[int]
+ pub_handle: int
+ name: str
+ encryption: _models.Encryption.Type
+ def __init__(self, pub_handle: _Optional[int] = ..., name: _Optional[str] = ..., encryption: _Optional[_Union[_models.Encryption.Type, str]] = ...) -> None: ...
+
+class PublishDataTrackResponse(_message.Message):
+ __slots__ = ("info",)
+ INFO_FIELD_NUMBER: _ClassVar[int]
+ info: _models.DataTrackInfo
+ def __init__(self, info: _Optional[_Union[_models.DataTrackInfo, _Mapping]] = ...) -> None: ...
+
+class UnpublishDataTrackRequest(_message.Message):
+ __slots__ = ("pub_handle",)
+ PUB_HANDLE_FIELD_NUMBER: _ClassVar[int]
+ pub_handle: int
+ def __init__(self, pub_handle: _Optional[int] = ...) -> None: ...
+
+class UnpublishDataTrackResponse(_message.Message):
+ __slots__ = ("info",)
+ INFO_FIELD_NUMBER: _ClassVar[int]
+ info: _models.DataTrackInfo
+ def __init__(self, info: _Optional[_Union[_models.DataTrackInfo, _Mapping]] = ...) -> None: ...
+
+class DataTrackSubscriberHandles(_message.Message):
+ __slots__ = ("sub_handles",)
+ class PublishedDataTrack(_message.Message):
+ __slots__ = ("publisher_identity", "publisher_sid", "track_sid")
+ PUBLISHER_IDENTITY_FIELD_NUMBER: _ClassVar[int]
+ PUBLISHER_SID_FIELD_NUMBER: _ClassVar[int]
+ TRACK_SID_FIELD_NUMBER: _ClassVar[int]
+ publisher_identity: str
+ publisher_sid: str
+ track_sid: str
+ def __init__(self, publisher_identity: _Optional[str] = ..., publisher_sid: _Optional[str] = ..., track_sid: _Optional[str] = ...) -> None: ...
+ class SubHandlesEntry(_message.Message):
+ __slots__ = ("key", "value")
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: int
+ value: DataTrackSubscriberHandles.PublishedDataTrack
+ def __init__(self, key: _Optional[int] = ..., value: _Optional[_Union[DataTrackSubscriberHandles.PublishedDataTrack, _Mapping]] = ...) -> None: ...
+ SUB_HANDLES_FIELD_NUMBER: _ClassVar[int]
+ sub_handles: _containers.MessageMap[int, DataTrackSubscriberHandles.PublishedDataTrack]
+ def __init__(self, sub_handles: _Optional[_Mapping[int, DataTrackSubscriberHandles.PublishedDataTrack]] = ...) -> None: ...
+
+class TrickleRequest(_message.Message):
+ __slots__ = ("candidateInit", "target", "final")
+ CANDIDATEINIT_FIELD_NUMBER: _ClassVar[int]
+ TARGET_FIELD_NUMBER: _ClassVar[int]
+ FINAL_FIELD_NUMBER: _ClassVar[int]
+ candidateInit: str
+ target: SignalTarget
+ final: bool
+ def __init__(self, candidateInit: _Optional[str] = ..., target: _Optional[_Union[SignalTarget, str]] = ..., final: bool = ...) -> None: ...
+
+class MuteTrackRequest(_message.Message):
+ __slots__ = ("sid", "muted")
+ SID_FIELD_NUMBER: _ClassVar[int]
+ MUTED_FIELD_NUMBER: _ClassVar[int]
+ sid: str
+ muted: bool
+ def __init__(self, sid: _Optional[str] = ..., muted: bool = ...) -> None: ...
+
+class JoinResponse(_message.Message):
+ __slots__ = ("room", "participant", "other_participants", "server_version", "ice_servers", "subscriber_primary", "alternative_url", "client_configuration", "server_region", "ping_timeout", "ping_interval", "server_info", "sif_trailer", "enabled_publish_codecs", "fast_publish")
+ ROOM_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_FIELD_NUMBER: _ClassVar[int]
+ OTHER_PARTICIPANTS_FIELD_NUMBER: _ClassVar[int]
+ SERVER_VERSION_FIELD_NUMBER: _ClassVar[int]
+ ICE_SERVERS_FIELD_NUMBER: _ClassVar[int]
+ SUBSCRIBER_PRIMARY_FIELD_NUMBER: _ClassVar[int]
+ ALTERNATIVE_URL_FIELD_NUMBER: _ClassVar[int]
+ CLIENT_CONFIGURATION_FIELD_NUMBER: _ClassVar[int]
+ SERVER_REGION_FIELD_NUMBER: _ClassVar[int]
+ PING_TIMEOUT_FIELD_NUMBER: _ClassVar[int]
+ PING_INTERVAL_FIELD_NUMBER: _ClassVar[int]
+ SERVER_INFO_FIELD_NUMBER: _ClassVar[int]
+ SIF_TRAILER_FIELD_NUMBER: _ClassVar[int]
+ ENABLED_PUBLISH_CODECS_FIELD_NUMBER: _ClassVar[int]
+ FAST_PUBLISH_FIELD_NUMBER: _ClassVar[int]
+ room: _models.Room
+ participant: _models.ParticipantInfo
+ other_participants: _containers.RepeatedCompositeFieldContainer[_models.ParticipantInfo]
+ server_version: str
+ ice_servers: _containers.RepeatedCompositeFieldContainer[ICEServer]
+ subscriber_primary: bool
+ alternative_url: str
+ client_configuration: _models.ClientConfiguration
+ server_region: str
+ ping_timeout: int
+ ping_interval: int
+ server_info: _models.ServerInfo
+ sif_trailer: bytes
+ enabled_publish_codecs: _containers.RepeatedCompositeFieldContainer[_models.Codec]
+ fast_publish: bool
+ def __init__(self, room: _Optional[_Union[_models.Room, _Mapping]] = ..., participant: _Optional[_Union[_models.ParticipantInfo, _Mapping]] = ..., other_participants: _Optional[_Iterable[_Union[_models.ParticipantInfo, _Mapping]]] = ..., server_version: _Optional[str] = ..., ice_servers: _Optional[_Iterable[_Union[ICEServer, _Mapping]]] = ..., subscriber_primary: bool = ..., alternative_url: _Optional[str] = ..., client_configuration: _Optional[_Union[_models.ClientConfiguration, _Mapping]] = ..., server_region: _Optional[str] = ..., ping_timeout: _Optional[int] = ..., ping_interval: _Optional[int] = ..., server_info: _Optional[_Union[_models.ServerInfo, _Mapping]] = ..., sif_trailer: _Optional[bytes] = ..., enabled_publish_codecs: _Optional[_Iterable[_Union[_models.Codec, _Mapping]]] = ..., fast_publish: bool = ...) -> None: ...
+
+class ReconnectResponse(_message.Message):
+ __slots__ = ("ice_servers", "client_configuration", "server_info", "last_message_seq")
+ ICE_SERVERS_FIELD_NUMBER: _ClassVar[int]
+ CLIENT_CONFIGURATION_FIELD_NUMBER: _ClassVar[int]
+ SERVER_INFO_FIELD_NUMBER: _ClassVar[int]
+ LAST_MESSAGE_SEQ_FIELD_NUMBER: _ClassVar[int]
+ ice_servers: _containers.RepeatedCompositeFieldContainer[ICEServer]
+ client_configuration: _models.ClientConfiguration
+ server_info: _models.ServerInfo
+ last_message_seq: int
+ def __init__(self, ice_servers: _Optional[_Iterable[_Union[ICEServer, _Mapping]]] = ..., client_configuration: _Optional[_Union[_models.ClientConfiguration, _Mapping]] = ..., server_info: _Optional[_Union[_models.ServerInfo, _Mapping]] = ..., last_message_seq: _Optional[int] = ...) -> None: ...
+
+class TrackPublishedResponse(_message.Message):
+ __slots__ = ("cid", "track")
+ CID_FIELD_NUMBER: _ClassVar[int]
+ TRACK_FIELD_NUMBER: _ClassVar[int]
+ cid: str
+ track: _models.TrackInfo
+ def __init__(self, cid: _Optional[str] = ..., track: _Optional[_Union[_models.TrackInfo, _Mapping]] = ...) -> None: ...
+
+class TrackUnpublishedResponse(_message.Message):
+ __slots__ = ("track_sid",)
+ TRACK_SID_FIELD_NUMBER: _ClassVar[int]
+ track_sid: str
+ def __init__(self, track_sid: _Optional[str] = ...) -> None: ...
+
+class SessionDescription(_message.Message):
+ __slots__ = ("type", "sdp", "id", "mid_to_track_id")
+ class MidToTrackIdEntry(_message.Message):
+ __slots__ = ("key", "value")
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: str
+ value: str
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
+ TYPE_FIELD_NUMBER: _ClassVar[int]
+ SDP_FIELD_NUMBER: _ClassVar[int]
+ ID_FIELD_NUMBER: _ClassVar[int]
+ MID_TO_TRACK_ID_FIELD_NUMBER: _ClassVar[int]
+ type: str
+ sdp: str
+ id: int
+ mid_to_track_id: _containers.ScalarMap[str, str]
+ def __init__(self, type: _Optional[str] = ..., sdp: _Optional[str] = ..., id: _Optional[int] = ..., mid_to_track_id: _Optional[_Mapping[str, str]] = ...) -> None: ...
+
+class ParticipantUpdate(_message.Message):
+ __slots__ = ("participants",)
+ PARTICIPANTS_FIELD_NUMBER: _ClassVar[int]
+ participants: _containers.RepeatedCompositeFieldContainer[_models.ParticipantInfo]
+ def __init__(self, participants: _Optional[_Iterable[_Union[_models.ParticipantInfo, _Mapping]]] = ...) -> None: ...
+
+class UpdateSubscription(_message.Message):
+ __slots__ = ("track_sids", "subscribe", "participant_tracks")
+ TRACK_SIDS_FIELD_NUMBER: _ClassVar[int]
+ SUBSCRIBE_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_TRACKS_FIELD_NUMBER: _ClassVar[int]
+ track_sids: _containers.RepeatedScalarFieldContainer[str]
+ subscribe: bool
+ participant_tracks: _containers.RepeatedCompositeFieldContainer[_models.ParticipantTracks]
+ def __init__(self, track_sids: _Optional[_Iterable[str]] = ..., subscribe: bool = ..., participant_tracks: _Optional[_Iterable[_Union[_models.ParticipantTracks, _Mapping]]] = ...) -> None: ...
+
+class UpdateDataSubscription(_message.Message):
+ __slots__ = ("updates",)
+ class Update(_message.Message):
+ __slots__ = ("track_sid", "subscribe", "options")
+ TRACK_SID_FIELD_NUMBER: _ClassVar[int]
+ SUBSCRIBE_FIELD_NUMBER: _ClassVar[int]
+ OPTIONS_FIELD_NUMBER: _ClassVar[int]
+ track_sid: str
+ subscribe: bool
+ options: _models.DataTrackSubscriptionOptions
+ def __init__(self, track_sid: _Optional[str] = ..., subscribe: bool = ..., options: _Optional[_Union[_models.DataTrackSubscriptionOptions, _Mapping]] = ...) -> None: ...
+ UPDATES_FIELD_NUMBER: _ClassVar[int]
+ updates: _containers.RepeatedCompositeFieldContainer[UpdateDataSubscription.Update]
+ def __init__(self, updates: _Optional[_Iterable[_Union[UpdateDataSubscription.Update, _Mapping]]] = ...) -> None: ...
+
+class UpdateTrackSettings(_message.Message):
+ __slots__ = ("track_sids", "disabled", "quality", "width", "height", "fps", "priority")
+ TRACK_SIDS_FIELD_NUMBER: _ClassVar[int]
+ DISABLED_FIELD_NUMBER: _ClassVar[int]
+ QUALITY_FIELD_NUMBER: _ClassVar[int]
+ WIDTH_FIELD_NUMBER: _ClassVar[int]
+ HEIGHT_FIELD_NUMBER: _ClassVar[int]
+ FPS_FIELD_NUMBER: _ClassVar[int]
+ PRIORITY_FIELD_NUMBER: _ClassVar[int]
+ track_sids: _containers.RepeatedScalarFieldContainer[str]
+ disabled: bool
+ quality: _models.VideoQuality
+ width: int
+ height: int
+ fps: int
+ priority: int
+ def __init__(self, track_sids: _Optional[_Iterable[str]] = ..., disabled: bool = ..., quality: _Optional[_Union[_models.VideoQuality, str]] = ..., width: _Optional[int] = ..., height: _Optional[int] = ..., fps: _Optional[int] = ..., priority: _Optional[int] = ...) -> None: ...
+
+class UpdateLocalAudioTrack(_message.Message):
+ __slots__ = ("track_sid", "features")
+ TRACK_SID_FIELD_NUMBER: _ClassVar[int]
+ FEATURES_FIELD_NUMBER: _ClassVar[int]
+ track_sid: str
+ features: _containers.RepeatedScalarFieldContainer[_models.AudioTrackFeature]
+ def __init__(self, track_sid: _Optional[str] = ..., features: _Optional[_Iterable[_Union[_models.AudioTrackFeature, str]]] = ...) -> None: ...
+
+class UpdateLocalVideoTrack(_message.Message):
+ __slots__ = ("track_sid", "width", "height")
+ TRACK_SID_FIELD_NUMBER: _ClassVar[int]
+ WIDTH_FIELD_NUMBER: _ClassVar[int]
+ HEIGHT_FIELD_NUMBER: _ClassVar[int]
+ track_sid: str
+ width: int
+ height: int
+ def __init__(self, track_sid: _Optional[str] = ..., width: _Optional[int] = ..., height: _Optional[int] = ...) -> None: ...
+
+class LeaveRequest(_message.Message):
+ __slots__ = ("can_reconnect", "reason", "action", "regions")
+ class Action(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ DISCONNECT: _ClassVar[LeaveRequest.Action]
+ RESUME: _ClassVar[LeaveRequest.Action]
+ RECONNECT: _ClassVar[LeaveRequest.Action]
+ DISCONNECT: LeaveRequest.Action
+ RESUME: LeaveRequest.Action
+ RECONNECT: LeaveRequest.Action
+ CAN_RECONNECT_FIELD_NUMBER: _ClassVar[int]
+ REASON_FIELD_NUMBER: _ClassVar[int]
+ ACTION_FIELD_NUMBER: _ClassVar[int]
+ REGIONS_FIELD_NUMBER: _ClassVar[int]
+ can_reconnect: bool
+ reason: _models.DisconnectReason
+ action: LeaveRequest.Action
+ regions: RegionSettings
+ def __init__(self, can_reconnect: bool = ..., reason: _Optional[_Union[_models.DisconnectReason, str]] = ..., action: _Optional[_Union[LeaveRequest.Action, str]] = ..., regions: _Optional[_Union[RegionSettings, _Mapping]] = ...) -> None: ...
+
+class UpdateVideoLayers(_message.Message):
+ __slots__ = ("track_sid", "layers")
+ TRACK_SID_FIELD_NUMBER: _ClassVar[int]
+ LAYERS_FIELD_NUMBER: _ClassVar[int]
+ track_sid: str
+ layers: _containers.RepeatedCompositeFieldContainer[_models.VideoLayer]
+ def __init__(self, track_sid: _Optional[str] = ..., layers: _Optional[_Iterable[_Union[_models.VideoLayer, _Mapping]]] = ...) -> None: ...
+
+class UpdateParticipantMetadata(_message.Message):
+ __slots__ = ("metadata", "name", "attributes", "request_id")
+ class AttributesEntry(_message.Message):
+ __slots__ = ("key", "value")
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: str
+ value: str
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
+ METADATA_FIELD_NUMBER: _ClassVar[int]
+ NAME_FIELD_NUMBER: _ClassVar[int]
+ ATTRIBUTES_FIELD_NUMBER: _ClassVar[int]
+ REQUEST_ID_FIELD_NUMBER: _ClassVar[int]
+ metadata: str
+ name: str
+ attributes: _containers.ScalarMap[str, str]
+ request_id: int
+ def __init__(self, metadata: _Optional[str] = ..., name: _Optional[str] = ..., attributes: _Optional[_Mapping[str, str]] = ..., request_id: _Optional[int] = ...) -> None: ...
+
+class ICEServer(_message.Message):
+ __slots__ = ("urls", "username", "credential")
+ URLS_FIELD_NUMBER: _ClassVar[int]
+ USERNAME_FIELD_NUMBER: _ClassVar[int]
+ CREDENTIAL_FIELD_NUMBER: _ClassVar[int]
+ urls: _containers.RepeatedScalarFieldContainer[str]
+ username: str
+ credential: str
+ def __init__(self, urls: _Optional[_Iterable[str]] = ..., username: _Optional[str] = ..., credential: _Optional[str] = ...) -> None: ...
+
+class SpeakersChanged(_message.Message):
+ __slots__ = ("speakers",)
+ SPEAKERS_FIELD_NUMBER: _ClassVar[int]
+ speakers: _containers.RepeatedCompositeFieldContainer[_models.SpeakerInfo]
+ def __init__(self, speakers: _Optional[_Iterable[_Union[_models.SpeakerInfo, _Mapping]]] = ...) -> None: ...
+
+class RoomUpdate(_message.Message):
+ __slots__ = ("room",)
+ ROOM_FIELD_NUMBER: _ClassVar[int]
+ room: _models.Room
+ def __init__(self, room: _Optional[_Union[_models.Room, _Mapping]] = ...) -> None: ...
+
+class ConnectionQualityInfo(_message.Message):
+ __slots__ = ("participant_sid", "quality", "score")
+ PARTICIPANT_SID_FIELD_NUMBER: _ClassVar[int]
+ QUALITY_FIELD_NUMBER: _ClassVar[int]
+ SCORE_FIELD_NUMBER: _ClassVar[int]
+ participant_sid: str
+ quality: _models.ConnectionQuality
+ score: float
+ def __init__(self, participant_sid: _Optional[str] = ..., quality: _Optional[_Union[_models.ConnectionQuality, str]] = ..., score: _Optional[float] = ...) -> None: ...
+
+class ConnectionQualityUpdate(_message.Message):
+ __slots__ = ("updates",)
+ UPDATES_FIELD_NUMBER: _ClassVar[int]
+ updates: _containers.RepeatedCompositeFieldContainer[ConnectionQualityInfo]
+ def __init__(self, updates: _Optional[_Iterable[_Union[ConnectionQualityInfo, _Mapping]]] = ...) -> None: ...
+
+class StreamStateInfo(_message.Message):
+ __slots__ = ("participant_sid", "track_sid", "state")
+ PARTICIPANT_SID_FIELD_NUMBER: _ClassVar[int]
+ TRACK_SID_FIELD_NUMBER: _ClassVar[int]
+ STATE_FIELD_NUMBER: _ClassVar[int]
+ participant_sid: str
+ track_sid: str
+ state: StreamState
+ def __init__(self, participant_sid: _Optional[str] = ..., track_sid: _Optional[str] = ..., state: _Optional[_Union[StreamState, str]] = ...) -> None: ...
+
+class StreamStateUpdate(_message.Message):
+ __slots__ = ("stream_states",)
+ STREAM_STATES_FIELD_NUMBER: _ClassVar[int]
+ stream_states: _containers.RepeatedCompositeFieldContainer[StreamStateInfo]
+ def __init__(self, stream_states: _Optional[_Iterable[_Union[StreamStateInfo, _Mapping]]] = ...) -> None: ...
+
+class SubscribedQuality(_message.Message):
+ __slots__ = ("quality", "enabled")
+ QUALITY_FIELD_NUMBER: _ClassVar[int]
+ ENABLED_FIELD_NUMBER: _ClassVar[int]
+ quality: _models.VideoQuality
+ enabled: bool
+ def __init__(self, quality: _Optional[_Union[_models.VideoQuality, str]] = ..., enabled: bool = ...) -> None: ...
+
+class SubscribedCodec(_message.Message):
+ __slots__ = ("codec", "qualities")
+ CODEC_FIELD_NUMBER: _ClassVar[int]
+ QUALITIES_FIELD_NUMBER: _ClassVar[int]
+ codec: str
+ qualities: _containers.RepeatedCompositeFieldContainer[SubscribedQuality]
+ def __init__(self, codec: _Optional[str] = ..., qualities: _Optional[_Iterable[_Union[SubscribedQuality, _Mapping]]] = ...) -> None: ...
+
+class SubscribedQualityUpdate(_message.Message):
+ __slots__ = ("track_sid", "subscribed_qualities", "subscribed_codecs")
+ TRACK_SID_FIELD_NUMBER: _ClassVar[int]
+ SUBSCRIBED_QUALITIES_FIELD_NUMBER: _ClassVar[int]
+ SUBSCRIBED_CODECS_FIELD_NUMBER: _ClassVar[int]
+ track_sid: str
+ subscribed_qualities: _containers.RepeatedCompositeFieldContainer[SubscribedQuality]
+ subscribed_codecs: _containers.RepeatedCompositeFieldContainer[SubscribedCodec]
+ def __init__(self, track_sid: _Optional[str] = ..., subscribed_qualities: _Optional[_Iterable[_Union[SubscribedQuality, _Mapping]]] = ..., subscribed_codecs: _Optional[_Iterable[_Union[SubscribedCodec, _Mapping]]] = ...) -> None: ...
+
+class SubscribedAudioCodecUpdate(_message.Message):
+ __slots__ = ("track_sid", "subscribed_audio_codecs")
+ TRACK_SID_FIELD_NUMBER: _ClassVar[int]
+ SUBSCRIBED_AUDIO_CODECS_FIELD_NUMBER: _ClassVar[int]
+ track_sid: str
+ subscribed_audio_codecs: _containers.RepeatedCompositeFieldContainer[_models.SubscribedAudioCodec]
+ def __init__(self, track_sid: _Optional[str] = ..., subscribed_audio_codecs: _Optional[_Iterable[_Union[_models.SubscribedAudioCodec, _Mapping]]] = ...) -> None: ...
+
+class TrackPermission(_message.Message):
+ __slots__ = ("participant_sid", "all_tracks", "track_sids", "participant_identity")
+ PARTICIPANT_SID_FIELD_NUMBER: _ClassVar[int]
+ ALL_TRACKS_FIELD_NUMBER: _ClassVar[int]
+ TRACK_SIDS_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: _ClassVar[int]
+ participant_sid: str
+ all_tracks: bool
+ track_sids: _containers.RepeatedScalarFieldContainer[str]
+ participant_identity: str
+ def __init__(self, participant_sid: _Optional[str] = ..., all_tracks: bool = ..., track_sids: _Optional[_Iterable[str]] = ..., participant_identity: _Optional[str] = ...) -> None: ...
+
+class SubscriptionPermission(_message.Message):
+ __slots__ = ("all_participants", "track_permissions")
+ ALL_PARTICIPANTS_FIELD_NUMBER: _ClassVar[int]
+ TRACK_PERMISSIONS_FIELD_NUMBER: _ClassVar[int]
+ all_participants: bool
+ track_permissions: _containers.RepeatedCompositeFieldContainer[TrackPermission]
+ def __init__(self, all_participants: bool = ..., track_permissions: _Optional[_Iterable[_Union[TrackPermission, _Mapping]]] = ...) -> None: ...
+
+class SubscriptionPermissionUpdate(_message.Message):
+ __slots__ = ("participant_sid", "track_sid", "allowed")
+ PARTICIPANT_SID_FIELD_NUMBER: _ClassVar[int]
+ TRACK_SID_FIELD_NUMBER: _ClassVar[int]
+ ALLOWED_FIELD_NUMBER: _ClassVar[int]
+ participant_sid: str
+ track_sid: str
+ allowed: bool
+ def __init__(self, participant_sid: _Optional[str] = ..., track_sid: _Optional[str] = ..., allowed: bool = ...) -> None: ...
+
+class RoomMovedResponse(_message.Message):
+ __slots__ = ("room", "token", "participant", "other_participants")
+ ROOM_FIELD_NUMBER: _ClassVar[int]
+ TOKEN_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_FIELD_NUMBER: _ClassVar[int]
+ OTHER_PARTICIPANTS_FIELD_NUMBER: _ClassVar[int]
+ room: _models.Room
+ token: str
+ participant: _models.ParticipantInfo
+ other_participants: _containers.RepeatedCompositeFieldContainer[_models.ParticipantInfo]
+ def __init__(self, room: _Optional[_Union[_models.Room, _Mapping]] = ..., token: _Optional[str] = ..., participant: _Optional[_Union[_models.ParticipantInfo, _Mapping]] = ..., other_participants: _Optional[_Iterable[_Union[_models.ParticipantInfo, _Mapping]]] = ...) -> None: ...
+
+class SyncState(_message.Message):
+ __slots__ = ("answer", "subscription", "publish_tracks", "data_channels", "offer", "track_sids_disabled", "datachannel_receive_states", "publish_data_tracks")
+ ANSWER_FIELD_NUMBER: _ClassVar[int]
+ SUBSCRIPTION_FIELD_NUMBER: _ClassVar[int]
+ PUBLISH_TRACKS_FIELD_NUMBER: _ClassVar[int]
+ DATA_CHANNELS_FIELD_NUMBER: _ClassVar[int]
+ OFFER_FIELD_NUMBER: _ClassVar[int]
+ TRACK_SIDS_DISABLED_FIELD_NUMBER: _ClassVar[int]
+ DATACHANNEL_RECEIVE_STATES_FIELD_NUMBER: _ClassVar[int]
+ PUBLISH_DATA_TRACKS_FIELD_NUMBER: _ClassVar[int]
+ answer: SessionDescription
+ subscription: UpdateSubscription
+ publish_tracks: _containers.RepeatedCompositeFieldContainer[TrackPublishedResponse]
+ data_channels: _containers.RepeatedCompositeFieldContainer[DataChannelInfo]
+ offer: SessionDescription
+ track_sids_disabled: _containers.RepeatedScalarFieldContainer[str]
+ datachannel_receive_states: _containers.RepeatedCompositeFieldContainer[DataChannelReceiveState]
+ publish_data_tracks: _containers.RepeatedCompositeFieldContainer[PublishDataTrackResponse]
+ def __init__(self, answer: _Optional[_Union[SessionDescription, _Mapping]] = ..., subscription: _Optional[_Union[UpdateSubscription, _Mapping]] = ..., publish_tracks: _Optional[_Iterable[_Union[TrackPublishedResponse, _Mapping]]] = ..., data_channels: _Optional[_Iterable[_Union[DataChannelInfo, _Mapping]]] = ..., offer: _Optional[_Union[SessionDescription, _Mapping]] = ..., track_sids_disabled: _Optional[_Iterable[str]] = ..., datachannel_receive_states: _Optional[_Iterable[_Union[DataChannelReceiveState, _Mapping]]] = ..., publish_data_tracks: _Optional[_Iterable[_Union[PublishDataTrackResponse, _Mapping]]] = ...) -> None: ...
+
+class DataChannelReceiveState(_message.Message):
+ __slots__ = ("publisher_sid", "last_seq")
+ PUBLISHER_SID_FIELD_NUMBER: _ClassVar[int]
+ LAST_SEQ_FIELD_NUMBER: _ClassVar[int]
+ publisher_sid: str
+ last_seq: int
+ def __init__(self, publisher_sid: _Optional[str] = ..., last_seq: _Optional[int] = ...) -> None: ...
+
+class DataChannelInfo(_message.Message):
+ __slots__ = ("label", "id", "target")
+ LABEL_FIELD_NUMBER: _ClassVar[int]
+ ID_FIELD_NUMBER: _ClassVar[int]
+ TARGET_FIELD_NUMBER: _ClassVar[int]
+ label: str
+ id: int
+ target: SignalTarget
+ def __init__(self, label: _Optional[str] = ..., id: _Optional[int] = ..., target: _Optional[_Union[SignalTarget, str]] = ...) -> None: ...
+
+class SimulateScenario(_message.Message):
+ __slots__ = ("speaker_update", "node_failure", "migration", "server_leave", "switch_candidate_protocol", "subscriber_bandwidth", "disconnect_signal_on_resume", "disconnect_signal_on_resume_no_messages", "leave_request_full_reconnect")
+ SPEAKER_UPDATE_FIELD_NUMBER: _ClassVar[int]
+ NODE_FAILURE_FIELD_NUMBER: _ClassVar[int]
+ MIGRATION_FIELD_NUMBER: _ClassVar[int]
+ SERVER_LEAVE_FIELD_NUMBER: _ClassVar[int]
+ SWITCH_CANDIDATE_PROTOCOL_FIELD_NUMBER: _ClassVar[int]
+ SUBSCRIBER_BANDWIDTH_FIELD_NUMBER: _ClassVar[int]
+ DISCONNECT_SIGNAL_ON_RESUME_FIELD_NUMBER: _ClassVar[int]
+ DISCONNECT_SIGNAL_ON_RESUME_NO_MESSAGES_FIELD_NUMBER: _ClassVar[int]
+ LEAVE_REQUEST_FULL_RECONNECT_FIELD_NUMBER: _ClassVar[int]
+ speaker_update: int
+ node_failure: bool
+ migration: bool
+ server_leave: bool
+ switch_candidate_protocol: CandidateProtocol
+ subscriber_bandwidth: int
+ disconnect_signal_on_resume: bool
+ disconnect_signal_on_resume_no_messages: bool
+ leave_request_full_reconnect: bool
+ def __init__(self, speaker_update: _Optional[int] = ..., node_failure: bool = ..., migration: bool = ..., server_leave: bool = ..., switch_candidate_protocol: _Optional[_Union[CandidateProtocol, str]] = ..., subscriber_bandwidth: _Optional[int] = ..., disconnect_signal_on_resume: bool = ..., disconnect_signal_on_resume_no_messages: bool = ..., leave_request_full_reconnect: bool = ...) -> None: ...
+
+class Ping(_message.Message):
+ __slots__ = ("timestamp", "rtt")
+ TIMESTAMP_FIELD_NUMBER: _ClassVar[int]
+ RTT_FIELD_NUMBER: _ClassVar[int]
+ timestamp: int
+ rtt: int
+ def __init__(self, timestamp: _Optional[int] = ..., rtt: _Optional[int] = ...) -> None: ...
+
+class Pong(_message.Message):
+ __slots__ = ("last_ping_timestamp", "timestamp")
+ LAST_PING_TIMESTAMP_FIELD_NUMBER: _ClassVar[int]
+ TIMESTAMP_FIELD_NUMBER: _ClassVar[int]
+ last_ping_timestamp: int
+ timestamp: int
+ def __init__(self, last_ping_timestamp: _Optional[int] = ..., timestamp: _Optional[int] = ...) -> None: ...
+
+class RegionSettings(_message.Message):
+ __slots__ = ("regions",)
+ REGIONS_FIELD_NUMBER: _ClassVar[int]
+ regions: _containers.RepeatedCompositeFieldContainer[RegionInfo]
+ def __init__(self, regions: _Optional[_Iterable[_Union[RegionInfo, _Mapping]]] = ...) -> None: ...
+
+class RegionInfo(_message.Message):
+ __slots__ = ("region", "url", "distance")
+ REGION_FIELD_NUMBER: _ClassVar[int]
+ URL_FIELD_NUMBER: _ClassVar[int]
+ DISTANCE_FIELD_NUMBER: _ClassVar[int]
+ region: str
+ url: str
+ distance: int
+ def __init__(self, region: _Optional[str] = ..., url: _Optional[str] = ..., distance: _Optional[int] = ...) -> None: ...
+
+class SubscriptionResponse(_message.Message):
+ __slots__ = ("track_sid", "err")
+ TRACK_SID_FIELD_NUMBER: _ClassVar[int]
+ ERR_FIELD_NUMBER: _ClassVar[int]
+ track_sid: str
+ err: _models.SubscriptionError
+ def __init__(self, track_sid: _Optional[str] = ..., err: _Optional[_Union[_models.SubscriptionError, str]] = ...) -> None: ...
+
+class RequestResponse(_message.Message):
+ __slots__ = ("request_id", "reason", "message", "trickle", "add_track", "mute", "update_metadata", "update_audio_track", "update_video_track", "publish_data_track", "unpublish_data_track")
+ class Reason(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ OK: _ClassVar[RequestResponse.Reason]
+ NOT_FOUND: _ClassVar[RequestResponse.Reason]
+ NOT_ALLOWED: _ClassVar[RequestResponse.Reason]
+ LIMIT_EXCEEDED: _ClassVar[RequestResponse.Reason]
+ QUEUED: _ClassVar[RequestResponse.Reason]
+ UNSUPPORTED_TYPE: _ClassVar[RequestResponse.Reason]
+ UNCLASSIFIED_ERROR: _ClassVar[RequestResponse.Reason]
+ INVALID_HANDLE: _ClassVar[RequestResponse.Reason]
+ INVALID_NAME: _ClassVar[RequestResponse.Reason]
+ DUPLICATE_HANDLE: _ClassVar[RequestResponse.Reason]
+ DUPLICATE_NAME: _ClassVar[RequestResponse.Reason]
+ OK: RequestResponse.Reason
+ NOT_FOUND: RequestResponse.Reason
+ NOT_ALLOWED: RequestResponse.Reason
+ LIMIT_EXCEEDED: RequestResponse.Reason
+ QUEUED: RequestResponse.Reason
+ UNSUPPORTED_TYPE: RequestResponse.Reason
+ UNCLASSIFIED_ERROR: RequestResponse.Reason
+ INVALID_HANDLE: RequestResponse.Reason
+ INVALID_NAME: RequestResponse.Reason
+ DUPLICATE_HANDLE: RequestResponse.Reason
+ DUPLICATE_NAME: RequestResponse.Reason
+ REQUEST_ID_FIELD_NUMBER: _ClassVar[int]
+ REASON_FIELD_NUMBER: _ClassVar[int]
+ MESSAGE_FIELD_NUMBER: _ClassVar[int]
+ TRICKLE_FIELD_NUMBER: _ClassVar[int]
+ ADD_TRACK_FIELD_NUMBER: _ClassVar[int]
+ MUTE_FIELD_NUMBER: _ClassVar[int]
+ UPDATE_METADATA_FIELD_NUMBER: _ClassVar[int]
+ UPDATE_AUDIO_TRACK_FIELD_NUMBER: _ClassVar[int]
+ UPDATE_VIDEO_TRACK_FIELD_NUMBER: _ClassVar[int]
+ PUBLISH_DATA_TRACK_FIELD_NUMBER: _ClassVar[int]
+ UNPUBLISH_DATA_TRACK_FIELD_NUMBER: _ClassVar[int]
+ request_id: int
+ reason: RequestResponse.Reason
+ message: str
+ trickle: TrickleRequest
+ add_track: AddTrackRequest
+ mute: MuteTrackRequest
+ update_metadata: UpdateParticipantMetadata
+ update_audio_track: UpdateLocalAudioTrack
+ update_video_track: UpdateLocalVideoTrack
+ publish_data_track: PublishDataTrackRequest
+ unpublish_data_track: UnpublishDataTrackRequest
+ def __init__(self, request_id: _Optional[int] = ..., reason: _Optional[_Union[RequestResponse.Reason, str]] = ..., message: _Optional[str] = ..., trickle: _Optional[_Union[TrickleRequest, _Mapping]] = ..., add_track: _Optional[_Union[AddTrackRequest, _Mapping]] = ..., mute: _Optional[_Union[MuteTrackRequest, _Mapping]] = ..., update_metadata: _Optional[_Union[UpdateParticipantMetadata, _Mapping]] = ..., update_audio_track: _Optional[_Union[UpdateLocalAudioTrack, _Mapping]] = ..., update_video_track: _Optional[_Union[UpdateLocalVideoTrack, _Mapping]] = ..., publish_data_track: _Optional[_Union[PublishDataTrackRequest, _Mapping]] = ..., unpublish_data_track: _Optional[_Union[UnpublishDataTrackRequest, _Mapping]] = ...) -> None: ...
+
+class TrackSubscribed(_message.Message):
+ __slots__ = ("track_sid",)
+ TRACK_SID_FIELD_NUMBER: _ClassVar[int]
+ track_sid: str
+ def __init__(self, track_sid: _Optional[str] = ...) -> None: ...
+
+class ConnectionSettings(_message.Message):
+ __slots__ = ("auto_subscribe", "adaptive_stream", "subscriber_allow_pause", "disable_ice_lite", "auto_subscribe_data_track")
+ AUTO_SUBSCRIBE_FIELD_NUMBER: _ClassVar[int]
+ ADAPTIVE_STREAM_FIELD_NUMBER: _ClassVar[int]
+ SUBSCRIBER_ALLOW_PAUSE_FIELD_NUMBER: _ClassVar[int]
+ DISABLE_ICE_LITE_FIELD_NUMBER: _ClassVar[int]
+ AUTO_SUBSCRIBE_DATA_TRACK_FIELD_NUMBER: _ClassVar[int]
+ auto_subscribe: bool
+ adaptive_stream: bool
+ subscriber_allow_pause: bool
+ disable_ice_lite: bool
+ auto_subscribe_data_track: bool
+ def __init__(self, auto_subscribe: bool = ..., adaptive_stream: bool = ..., subscriber_allow_pause: bool = ..., disable_ice_lite: bool = ..., auto_subscribe_data_track: bool = ...) -> None: ...
+
+class JoinRequest(_message.Message):
+ __slots__ = ("client_info", "connection_settings", "metadata", "participant_attributes", "add_track_requests", "publisher_offer", "reconnect", "reconnect_reason", "participant_sid", "sync_state")
+ class ParticipantAttributesEntry(_message.Message):
+ __slots__ = ("key", "value")
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: str
+ value: str
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
+ CLIENT_INFO_FIELD_NUMBER: _ClassVar[int]
+ CONNECTION_SETTINGS_FIELD_NUMBER: _ClassVar[int]
+ METADATA_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_ATTRIBUTES_FIELD_NUMBER: _ClassVar[int]
+ ADD_TRACK_REQUESTS_FIELD_NUMBER: _ClassVar[int]
+ PUBLISHER_OFFER_FIELD_NUMBER: _ClassVar[int]
+ RECONNECT_FIELD_NUMBER: _ClassVar[int]
+ RECONNECT_REASON_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_SID_FIELD_NUMBER: _ClassVar[int]
+ SYNC_STATE_FIELD_NUMBER: _ClassVar[int]
+ client_info: _models.ClientInfo
+ connection_settings: ConnectionSettings
+ metadata: str
+ participant_attributes: _containers.ScalarMap[str, str]
+ add_track_requests: _containers.RepeatedCompositeFieldContainer[AddTrackRequest]
+ publisher_offer: SessionDescription
+ reconnect: bool
+ reconnect_reason: _models.ReconnectReason
+ participant_sid: str
+ sync_state: SyncState
+ def __init__(self, client_info: _Optional[_Union[_models.ClientInfo, _Mapping]] = ..., connection_settings: _Optional[_Union[ConnectionSettings, _Mapping]] = ..., metadata: _Optional[str] = ..., participant_attributes: _Optional[_Mapping[str, str]] = ..., add_track_requests: _Optional[_Iterable[_Union[AddTrackRequest, _Mapping]]] = ..., publisher_offer: _Optional[_Union[SessionDescription, _Mapping]] = ..., reconnect: bool = ..., reconnect_reason: _Optional[_Union[_models.ReconnectReason, str]] = ..., participant_sid: _Optional[str] = ..., sync_state: _Optional[_Union[SyncState, _Mapping]] = ...) -> None: ...
+
+class WrappedJoinRequest(_message.Message):
+ __slots__ = ("compression", "join_request")
+ class Compression(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ NONE: _ClassVar[WrappedJoinRequest.Compression]
+ GZIP: _ClassVar[WrappedJoinRequest.Compression]
+ NONE: WrappedJoinRequest.Compression
+ GZIP: WrappedJoinRequest.Compression
+ COMPRESSION_FIELD_NUMBER: _ClassVar[int]
+ JOIN_REQUEST_FIELD_NUMBER: _ClassVar[int]
+ compression: WrappedJoinRequest.Compression
+ join_request: bytes
+ def __init__(self, compression: _Optional[_Union[WrappedJoinRequest.Compression, str]] = ..., join_request: _Optional[bytes] = ...) -> None: ...
+
+class MediaSectionsRequirement(_message.Message):
+ __slots__ = ("num_audios", "num_videos")
+ NUM_AUDIOS_FIELD_NUMBER: _ClassVar[int]
+ NUM_VIDEOS_FIELD_NUMBER: _ClassVar[int]
+ num_audios: int
+ num_videos: int
+ def __init__(self, num_audios: _Optional[int] = ..., num_videos: _Optional[int] = ...) -> None: ...
diff --git a/livekit-protocol/livekit/protocol/sip.py b/livekit-protocol/livekit/protocol/sip.py
index 7106c3cc..1ece178b 100644
--- a/livekit-protocol/livekit/protocol/sip.py
+++ b/livekit-protocol/livekit/protocol/sip.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: livekit_sip.proto
-# Protobuf Python Version: 4.25.3
+# Protobuf Python Version: 4.25.1
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
@@ -12,9 +12,16 @@
_sym_db = _symbol_database.Default()
+from google.protobuf import any_pb2 as google_dot_protobuf_dot_any__pb2
+from google.protobuf import duration_pb2 as google_dot_protobuf_dot_duration__pb2
+from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2
+from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
+from . import models as _models_
+from . import room as _room_
+from .logger_pb import options as logger_dot_options__pb2
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11livekit_sip.proto\x12\x07livekit\"\xaf\x02\n\x15\x43reateSIPTrunkRequest\x12\x19\n\x11inbound_addresses\x18\x01 \x03(\t\x12\x18\n\x10outbound_address\x18\x02 \x01(\t\x12\x17\n\x0foutbound_number\x18\x03 \x01(\t\x12!\n\x15inbound_numbers_regex\x18\x04 \x03(\tB\x02\x18\x01\x12\x17\n\x0finbound_numbers\x18\t \x03(\t\x12\x18\n\x10inbound_username\x18\x05 \x01(\t\x12\x18\n\x10inbound_password\x18\x06 \x01(\t\x12\x19\n\x11outbound_username\x18\x07 \x01(\t\x12\x19\n\x11outbound_password\x18\x08 \x01(\t\x12\x0c\n\x04name\x18\n \x01(\t\x12\x10\n\x08metadata\x18\x0b \x01(\t:\x02\x18\x01\"\xdb\x03\n\x0cSIPTrunkInfo\x12\x14\n\x0csip_trunk_id\x18\x01 \x01(\t\x12-\n\x04kind\x18\x0e \x01(\x0e\x32\x1f.livekit.SIPTrunkInfo.TrunkKind\x12\x19\n\x11inbound_addresses\x18\x02 \x03(\t\x12\x18\n\x10outbound_address\x18\x03 \x01(\t\x12\x17\n\x0foutbound_number\x18\x04 \x01(\t\x12(\n\ttransport\x18\r \x01(\x0e\x32\x15.livekit.SIPTransport\x12!\n\x15inbound_numbers_regex\x18\x05 \x03(\tB\x02\x18\x01\x12\x17\n\x0finbound_numbers\x18\n \x03(\t\x12\x18\n\x10inbound_username\x18\x06 \x01(\t\x12\x18\n\x10inbound_password\x18\x07 \x01(\t\x12\x19\n\x11outbound_username\x18\x08 \x01(\t\x12\x19\n\x11outbound_password\x18\t \x01(\t\x12\x0c\n\x04name\x18\x0b \x01(\t\x12\x10\n\x08metadata\x18\x0c \x01(\t\"D\n\tTrunkKind\x12\x10\n\x0cTRUNK_LEGACY\x10\x00\x12\x11\n\rTRUNK_INBOUND\x10\x01\x12\x12\n\x0eTRUNK_OUTBOUND\x10\x02:\x02\x18\x01\"K\n\x1c\x43reateSIPInboundTrunkRequest\x12+\n\x05trunk\x18\x01 \x01(\x0b\x32\x1c.livekit.SIPInboundTrunkInfo\"\xbe\x01\n\x13SIPInboundTrunkInfo\x12\x14\n\x0csip_trunk_id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x10\n\x08metadata\x18\x03 \x01(\t\x12\x0f\n\x07numbers\x18\x04 \x03(\t\x12\x19\n\x11\x61llowed_addresses\x18\x05 \x03(\t\x12\x17\n\x0f\x61llowed_numbers\x18\x06 \x03(\t\x12\x15\n\rauth_username\x18\x07 \x01(\t\x12\x15\n\rauth_password\x18\x08 \x01(\t\"M\n\x1d\x43reateSIPOutboundTrunkRequest\x12,\n\x05trunk\x18\x01 \x01(\x0b\x32\x1d.livekit.SIPOutboundTrunkInfo\"\xc6\x01\n\x14SIPOutboundTrunkInfo\x12\x14\n\x0csip_trunk_id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x10\n\x08metadata\x18\x03 \x01(\t\x12\x0f\n\x07\x61\x64\x64ress\x18\x04 \x01(\t\x12(\n\ttransport\x18\x05 \x01(\x0e\x32\x15.livekit.SIPTransport\x12\x0f\n\x07numbers\x18\x06 \x03(\t\x12\x15\n\rauth_username\x18\x07 \x01(\t\x12\x15\n\rauth_password\x18\x08 \x01(\t\"\x19\n\x13ListSIPTrunkRequest:\x02\x18\x01\"@\n\x14ListSIPTrunkResponse\x12$\n\x05items\x18\x01 \x03(\x0b\x32\x15.livekit.SIPTrunkInfo:\x02\x18\x01\"\x1c\n\x1aListSIPInboundTrunkRequest\"J\n\x1bListSIPInboundTrunkResponse\x12+\n\x05items\x18\x01 \x03(\x0b\x32\x1c.livekit.SIPInboundTrunkInfo\"\x1d\n\x1bListSIPOutboundTrunkRequest\"L\n\x1cListSIPOutboundTrunkResponse\x12,\n\x05items\x18\x01 \x03(\x0b\x32\x1d.livekit.SIPOutboundTrunkInfo\"-\n\x15\x44\x65leteSIPTrunkRequest\x12\x14\n\x0csip_trunk_id\x18\x01 \x01(\t\"7\n\x15SIPDispatchRuleDirect\x12\x11\n\troom_name\x18\x01 \x01(\t\x12\x0b\n\x03pin\x18\x02 \x01(\t\"=\n\x19SIPDispatchRuleIndividual\x12\x13\n\x0broom_prefix\x18\x01 \x01(\t\x12\x0b\n\x03pin\x18\x02 \x01(\t\"\xa1\x01\n\x0fSIPDispatchRule\x12>\n\x14\x64ispatch_rule_direct\x18\x01 \x01(\x0b\x32\x1e.livekit.SIPDispatchRuleDirectH\x00\x12\x46\n\x18\x64ispatch_rule_individual\x18\x02 \x01(\x0b\x32\".livekit.SIPDispatchRuleIndividualH\x00\x42\x06\n\x04rule\"\xab\x02\n\x1c\x43reateSIPDispatchRuleRequest\x12&\n\x04rule\x18\x01 \x01(\x0b\x32\x18.livekit.SIPDispatchRule\x12\x11\n\ttrunk_ids\x18\x02 \x03(\t\x12\x19\n\x11hide_phone_number\x18\x03 \x01(\x08\x12\x17\n\x0finbound_numbers\x18\x06 \x03(\t\x12\x0c\n\x04name\x18\x04 \x01(\t\x12\x10\n\x08metadata\x18\x05 \x01(\t\x12I\n\nattributes\x18\x07 \x03(\x0b\x32\x35.livekit.CreateSIPDispatchRuleRequest.AttributesEntry\x1a\x31\n\x0f\x41ttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xb7\x02\n\x13SIPDispatchRuleInfo\x12\x1c\n\x14sip_dispatch_rule_id\x18\x01 \x01(\t\x12&\n\x04rule\x18\x02 \x01(\x0b\x32\x18.livekit.SIPDispatchRule\x12\x11\n\ttrunk_ids\x18\x03 \x03(\t\x12\x19\n\x11hide_phone_number\x18\x04 \x01(\x08\x12\x17\n\x0finbound_numbers\x18\x07 \x03(\t\x12\x0c\n\x04name\x18\x05 \x01(\t\x12\x10\n\x08metadata\x18\x06 \x01(\t\x12@\n\nattributes\x18\x08 \x03(\x0b\x32,.livekit.SIPDispatchRuleInfo.AttributesEntry\x1a\x31\n\x0f\x41ttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x1c\n\x1aListSIPDispatchRuleRequest\"J\n\x1bListSIPDispatchRuleResponse\x12+\n\x05items\x18\x01 \x03(\x0b\x32\x1c.livekit.SIPDispatchRuleInfo\"<\n\x1c\x44\x65leteSIPDispatchRuleRequest\x12\x1c\n\x14sip_dispatch_rule_id\x18\x01 \x01(\t\"\x90\x03\n\x1b\x43reateSIPParticipantRequest\x12\x14\n\x0csip_trunk_id\x18\x01 \x01(\t\x12\x13\n\x0bsip_call_to\x18\x02 \x01(\t\x12\x11\n\troom_name\x18\x03 \x01(\t\x12\x1c\n\x14participant_identity\x18\x04 \x01(\t\x12\x18\n\x10participant_name\x18\x07 \x01(\t\x12\x1c\n\x14participant_metadata\x18\x08 \x01(\t\x12_\n\x16participant_attributes\x18\t \x03(\x0b\x32?.livekit.CreateSIPParticipantRequest.ParticipantAttributesEntry\x12\x0c\n\x04\x64tmf\x18\x05 \x01(\t\x12\x15\n\rplay_ringtone\x18\x06 \x01(\x08\x12\x19\n\x11hide_phone_number\x18\n \x01(\x08\x1a<\n\x1aParticipantAttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"r\n\x12SIPParticipantInfo\x12\x16\n\x0eparticipant_id\x18\x01 \x01(\t\x12\x1c\n\x14participant_identity\x18\x02 \x01(\t\x12\x11\n\troom_name\x18\x03 \x01(\t\x12\x13\n\x0bsip_call_id\x18\x04 \x01(\t*k\n\x0cSIPTransport\x12\x16\n\x12SIP_TRANSPORT_AUTO\x10\x00\x12\x15\n\x11SIP_TRANSPORT_UDP\x10\x01\x12\x15\n\x11SIP_TRANSPORT_TCP\x10\x02\x12\x15\n\x11SIP_TRANSPORT_TLS\x10\x03\x32\xed\x07\n\x03SIP\x12L\n\x0e\x43reateSIPTrunk\x12\x1e.livekit.CreateSIPTrunkRequest\x1a\x15.livekit.SIPTrunkInfo\"\x03\x88\x02\x01\x12P\n\x0cListSIPTrunk\x12\x1c.livekit.ListSIPTrunkRequest\x1a\x1d.livekit.ListSIPTrunkResponse\"\x03\x88\x02\x01\x12\\\n\x15\x43reateSIPInboundTrunk\x12%.livekit.CreateSIPInboundTrunkRequest\x1a\x1c.livekit.SIPInboundTrunkInfo\x12_\n\x16\x43reateSIPOutboundTrunk\x12&.livekit.CreateSIPOutboundTrunkRequest\x1a\x1d.livekit.SIPOutboundTrunkInfo\x12`\n\x13ListSIPInboundTrunk\x12#.livekit.ListSIPInboundTrunkRequest\x1a$.livekit.ListSIPInboundTrunkResponse\x12\x63\n\x14ListSIPOutboundTrunk\x12$.livekit.ListSIPOutboundTrunkRequest\x1a%.livekit.ListSIPOutboundTrunkResponse\x12G\n\x0e\x44\x65leteSIPTrunk\x12\x1e.livekit.DeleteSIPTrunkRequest\x1a\x15.livekit.SIPTrunkInfo\x12\\\n\x15\x43reateSIPDispatchRule\x12%.livekit.CreateSIPDispatchRuleRequest\x1a\x1c.livekit.SIPDispatchRuleInfo\x12`\n\x13ListSIPDispatchRule\x12#.livekit.ListSIPDispatchRuleRequest\x1a$.livekit.ListSIPDispatchRuleResponse\x12\\\n\x15\x44\x65leteSIPDispatchRule\x12%.livekit.DeleteSIPDispatchRuleRequest\x1a\x1c.livekit.SIPDispatchRuleInfo\x12Y\n\x14\x43reateSIPParticipant\x12$.livekit.CreateSIPParticipantRequest\x1a\x1b.livekit.SIPParticipantInfoBFZ#github.com/livekit/protocol/livekit\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11livekit_sip.proto\x12\x07livekit\x1a\x19google/protobuf/any.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x14livekit_models.proto\x1a\x12livekit_room.proto\x1a\x14logger/options.proto\"A\n\tSIPStatus\x12$\n\x04\x63ode\x18\x01 \x01(\x0e\x32\x16.livekit.SIPStatusCode\x12\x0e\n\x06status\x18\x02 \x01(\t\"\xe9\x02\n\x15\x43reateSIPTrunkRequest\x12\x19\n\x11inbound_addresses\x18\x01 \x03(\t\x12\x18\n\x10outbound_address\x18\x02 \x01(\t\x12\x17\n\x0foutbound_number\x18\x03 \x01(\t\x12!\n\x15inbound_numbers_regex\x18\x04 \x03(\tB\x02\x18\x01\x12\x17\n\x0finbound_numbers\x18\t \x03(\t\x12\x1d\n\x10inbound_username\x18\x05 \x01(\tB\x03\xa8P\x01\x12\x1d\n\x10inbound_password\x18\x06 \x01(\tB\x03\xa8P\x01\x12\x1e\n\x11outbound_username\x18\x07 \x01(\tB\x03\xa8P\x01\x12\x1e\n\x11outbound_password\x18\x08 \x01(\tB\x03\xa8P\x01\x12\x0c\n\x04name\x18\n \x01(\t\x12\x36\n\x08metadata\x18\x0b \x01(\tB$\xa8P\x01\xb2P\x1e:\x02\x18\x01\"g\n\x0cProviderInfo\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12#\n\x04type\x18\x03 \x01(\x0e\x32\x15.livekit.ProviderType\x12\x18\n\x10prevent_transfer\x18\x04 \x01(\x08\"\xa4\x04\n\x0cSIPTrunkInfo\x12#\n\x0csip_trunk_id\x18\x01 \x01(\tB\r\xbaP\nsipTrunkID\x12-\n\x04kind\x18\x0e \x01(\x0e\x32\x1f.livekit.SIPTrunkInfo.TrunkKind\x12\x19\n\x11inbound_addresses\x18\x02 \x03(\t\x12\x18\n\x10outbound_address\x18\x03 \x01(\t\x12\x17\n\x0foutbound_number\x18\x04 \x01(\t\x12(\n\ttransport\x18\r \x01(\x0e\x32\x15.livekit.SIPTransport\x12!\n\x15inbound_numbers_regex\x18\x05 \x03(\tB\x02\x18\x01\x12\x17\n\x0finbound_numbers\x18\n \x03(\t\x12\x1d\n\x10inbound_username\x18\x06 \x01(\tB\x03\xa8P\x01\x12\x1d\n\x10inbound_password\x18\x07 \x01(\tB\x03\xa8P\x01\x12\x1e\n\x11outbound_username\x18\x08 \x01(\tB\x03\xa8P\x01\x12\x1e\n\x11outbound_password\x18\t \x01(\tB\x03\xa8P\x01\x12\x0c\n\x04name\x18\x0b \x01(\t\x12\x36\n\x08metadata\x18\x0c \x01(\tB$\xa8P\x01\xb2P\x1e\"D\n\tTrunkKind\x12\x10\n\x0cTRUNK_LEGACY\x10\x00\x12\x11\n\rTRUNK_INBOUND\x10\x01\x12\x12\n\x0eTRUNK_OUTBOUND\x10\x02:\x02\x18\x01\"K\n\x1c\x43reateSIPInboundTrunkRequest\x12+\n\x05trunk\x18\x01 \x01(\x0b\x32\x1c.livekit.SIPInboundTrunkInfo\"\xb0\x01\n\x1cUpdateSIPInboundTrunkRequest\x12#\n\x0csip_trunk_id\x18\x01 \x01(\tB\r\xbaP\nsipTrunkID\x12/\n\x07replace\x18\x02 \x01(\x0b\x32\x1c.livekit.SIPInboundTrunkInfoH\x00\x12\x30\n\x06update\x18\x03 \x01(\x0b\x32\x1e.livekit.SIPInboundTrunkUpdateH\x00\x42\x08\n\x06\x61\x63tion\"\xff\x07\n\x13SIPInboundTrunkInfo\x12#\n\x0csip_trunk_id\x18\x01 \x01(\tB\r\xbaP\nsipTrunkID\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x36\n\x08metadata\x18\x03 \x01(\tB$\xa8P\x01\xb2P\x1e\x12\x0f\n\x07numbers\x18\x04 \x03(\t\x12\x19\n\x11\x61llowed_addresses\x18\x05 \x03(\t\x12\x17\n\x0f\x61llowed_numbers\x18\x06 \x03(\t\x12\x1a\n\rauth_username\x18\x07 \x01(\tB\x03\xa8P\x01\x12\x1a\n\rauth_password\x18\x08 \x01(\tB\x03\xa8P\x01\x12`\n\x07headers\x18\t \x03(\x0b\x32).livekit.SIPInboundTrunkInfo.HeadersEntryB$\xa8P\x01\xb2P\x1e\x12T\n\x15headers_to_attributes\x18\n \x03(\x0b\x32\x35.livekit.SIPInboundTrunkInfo.HeadersToAttributesEntry\x12T\n\x15\x61ttributes_to_headers\x18\x0e \x03(\x0b\x32\x35.livekit.SIPInboundTrunkInfo.AttributesToHeadersEntry\x12\x32\n\x0finclude_headers\x18\x0f \x01(\x0e\x32\x19.livekit.SIPHeaderOptions\x12\x32\n\x0fringing_timeout\x18\x0b \x01(\x0b\x32\x19.google.protobuf.Duration\x12\x34\n\x11max_call_duration\x18\x0c \x01(\x0b\x32\x19.google.protobuf.Duration\x12\x15\n\rkrisp_enabled\x18\r \x01(\x08\x12\x35\n\x10media_encryption\x18\x10 \x01(\x0e\x32\x1b.livekit.SIPMediaEncryption\x12.\n\ncreated_at\x18\x11 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12.\n\nupdated_at\x18\x12 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x1a.\n\x0cHeadersEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a:\n\x18HeadersToAttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a:\n\x18\x41ttributesToHeadersEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xb8\x03\n\x15SIPInboundTrunkUpdate\x12$\n\x07numbers\x18\x01 \x01(\x0b\x32\x13.livekit.ListUpdate\x12.\n\x11\x61llowed_addresses\x18\x02 \x01(\x0b\x32\x13.livekit.ListUpdate\x12,\n\x0f\x61llowed_numbers\x18\x03 \x01(\x0b\x32\x13.livekit.ListUpdate\x12\x1f\n\rauth_username\x18\x04 \x01(\tB\x03\xa8P\x01H\x00\x88\x01\x01\x12\x1f\n\rauth_password\x18\x05 \x01(\tB\x03\xa8P\x01H\x01\x88\x01\x01\x12\x11\n\x04name\x18\x06 \x01(\tH\x02\x88\x01\x01\x12;\n\x08metadata\x18\x07 \x01(\tB$\xa8P\x01\xb2P\x1eH\x03\x88\x01\x01\x12:\n\x10media_encryption\x18\x08 \x01(\x0e\x32\x1b.livekit.SIPMediaEncryptionH\x04\x88\x01\x01\x42\x10\n\x0e_auth_usernameB\x10\n\x0e_auth_passwordB\x07\n\x05_nameB\x0b\n\t_metadataB\x13\n\x11_media_encryption\"M\n\x1d\x43reateSIPOutboundTrunkRequest\x12,\n\x05trunk\x18\x01 \x01(\x0b\x32\x1d.livekit.SIPOutboundTrunkInfo\"\xb3\x01\n\x1dUpdateSIPOutboundTrunkRequest\x12#\n\x0csip_trunk_id\x18\x01 \x01(\tB\r\xbaP\nsipTrunkID\x12\x30\n\x07replace\x18\x02 \x01(\x0b\x32\x1d.livekit.SIPOutboundTrunkInfoH\x00\x12\x31\n\x06update\x18\x03 \x01(\x0b\x32\x1f.livekit.SIPOutboundTrunkUpdateH\x00\x42\x08\n\x06\x61\x63tion\"\xb9\x07\n\x14SIPOutboundTrunkInfo\x12#\n\x0csip_trunk_id\x18\x01 \x01(\tB\r\xbaP\nsipTrunkID\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x36\n\x08metadata\x18\x03 \x01(\tB$\xa8P\x01\xb2P\x1e\x12\x0f\n\x07\x61\x64\x64ress\x18\x04 \x01(\t\x12\x1b\n\x13\x64\x65stination_country\x18\x0e \x01(\t\x12(\n\ttransport\x18\x05 \x01(\x0e\x32\x15.livekit.SIPTransport\x12\x0f\n\x07numbers\x18\x06 \x03(\t\x12\x1a\n\rauth_username\x18\x07 \x01(\tB\x03\xa8P\x01\x12\x1a\n\rauth_password\x18\x08 \x01(\tB\x03\xa8P\x01\x12\x61\n\x07headers\x18\t \x03(\x0b\x32*.livekit.SIPOutboundTrunkInfo.HeadersEntryB$\xa8P\x01\xb2P\x1e\x12U\n\x15headers_to_attributes\x18\n \x03(\x0b\x32\x36.livekit.SIPOutboundTrunkInfo.HeadersToAttributesEntry\x12U\n\x15\x61ttributes_to_headers\x18\x0b \x03(\x0b\x32\x36.livekit.SIPOutboundTrunkInfo.AttributesToHeadersEntry\x12\x32\n\x0finclude_headers\x18\x0c \x01(\x0e\x32\x19.livekit.SIPHeaderOptions\x12\x35\n\x10media_encryption\x18\r \x01(\x0e\x32\x1b.livekit.SIPMediaEncryption\x12\x11\n\tfrom_host\x18\x0f \x01(\t\x12.\n\ncreated_at\x18\x10 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12.\n\nupdated_at\x18\x11 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x1a.\n\x0cHeadersEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a:\n\x18HeadersToAttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a:\n\x18\x41ttributesToHeadersEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x9a\x04\n\x16SIPOutboundTrunkUpdate\x12\x14\n\x07\x61\x64\x64ress\x18\x01 \x01(\tH\x00\x88\x01\x01\x12-\n\ttransport\x18\x02 \x01(\x0e\x32\x15.livekit.SIPTransportH\x01\x88\x01\x01\x12 \n\x13\x64\x65stination_country\x18\t \x01(\tH\x02\x88\x01\x01\x12$\n\x07numbers\x18\x03 \x01(\x0b\x32\x13.livekit.ListUpdate\x12\x1f\n\rauth_username\x18\x04 \x01(\tB\x03\xa8P\x01H\x03\x88\x01\x01\x12\x1f\n\rauth_password\x18\x05 \x01(\tB\x03\xa8P\x01H\x04\x88\x01\x01\x12\x11\n\x04name\x18\x06 \x01(\tH\x05\x88\x01\x01\x12;\n\x08metadata\x18\x07 \x01(\tB$\xa8P\x01\xb2P\x1eH\x06\x88\x01\x01\x12:\n\x10media_encryption\x18\x08 \x01(\x0e\x32\x1b.livekit.SIPMediaEncryptionH\x07\x88\x01\x01\x12\x16\n\tfrom_host\x18\n \x01(\tH\x08\x88\x01\x01\x42\n\n\x08_addressB\x0c\n\n_transportB\x16\n\x14_destination_countryB\x10\n\x0e_auth_usernameB\x10\n\x0e_auth_passwordB\x07\n\x05_nameB\x0b\n\t_metadataB\x13\n\x11_media_encryptionB\x0c\n\n_from_host\"@\n\x19GetSIPInboundTrunkRequest\x12#\n\x0csip_trunk_id\x18\x01 \x01(\tB\r\xbaP\nsipTrunkID\"I\n\x1aGetSIPInboundTrunkResponse\x12+\n\x05trunk\x18\x01 \x01(\x0b\x32\x1c.livekit.SIPInboundTrunkInfo\"A\n\x1aGetSIPOutboundTrunkRequest\x12#\n\x0csip_trunk_id\x18\x01 \x01(\tB\r\xbaP\nsipTrunkID\"K\n\x1bGetSIPOutboundTrunkResponse\x12,\n\x05trunk\x18\x01 \x01(\x0b\x32\x1d.livekit.SIPOutboundTrunkInfo\"<\n\x13ListSIPTrunkRequest\x12!\n\x04page\x18\x01 \x01(\x0b\x32\x13.livekit.Pagination:\x02\x18\x01\"@\n\x14ListSIPTrunkResponse\x12$\n\x05items\x18\x01 \x03(\x0b\x32\x15.livekit.SIPTrunkInfo:\x02\x18\x01\"c\n\x1aListSIPInboundTrunkRequest\x12!\n\x04page\x18\x03 \x01(\x0b\x32\x13.livekit.Pagination\x12\x11\n\ttrunk_ids\x18\x01 \x03(\t\x12\x0f\n\x07numbers\x18\x02 \x03(\t\"J\n\x1bListSIPInboundTrunkResponse\x12+\n\x05items\x18\x01 \x03(\x0b\x32\x1c.livekit.SIPInboundTrunkInfo\"d\n\x1bListSIPOutboundTrunkRequest\x12!\n\x04page\x18\x03 \x01(\x0b\x32\x13.livekit.Pagination\x12\x11\n\ttrunk_ids\x18\x01 \x03(\t\x12\x0f\n\x07numbers\x18\x02 \x03(\t\"L\n\x1cListSIPOutboundTrunkResponse\x12,\n\x05items\x18\x01 \x03(\x0b\x32\x1d.livekit.SIPOutboundTrunkInfo\"<\n\x15\x44\x65leteSIPTrunkRequest\x12#\n\x0csip_trunk_id\x18\x01 \x01(\tB\r\xbaP\nsipTrunkID\"7\n\x15SIPDispatchRuleDirect\x12\x11\n\troom_name\x18\x01 \x01(\t\x12\x0b\n\x03pin\x18\x02 \x01(\t\"T\n\x19SIPDispatchRuleIndividual\x12\x13\n\x0broom_prefix\x18\x01 \x01(\t\x12\x0b\n\x03pin\x18\x02 \x01(\t\x12\x15\n\rno_randomness\x18\x03 \x01(\x08\"L\n\x15SIPDispatchRuleCallee\x12\x13\n\x0broom_prefix\x18\x01 \x01(\t\x12\x0b\n\x03pin\x18\x02 \x01(\t\x12\x11\n\trandomize\x18\x03 \x01(\x08\"\xe1\x01\n\x0fSIPDispatchRule\x12>\n\x14\x64ispatch_rule_direct\x18\x01 \x01(\x0b\x32\x1e.livekit.SIPDispatchRuleDirectH\x00\x12\x46\n\x18\x64ispatch_rule_individual\x18\x02 \x01(\x0b\x32\".livekit.SIPDispatchRuleIndividualH\x00\x12>\n\x14\x64ispatch_rule_callee\x18\x03 \x01(\x0b\x32\x1e.livekit.SIPDispatchRuleCalleeH\x00\x42\x06\n\x04rule\"\x92\x04\n\x1c\x43reateSIPDispatchRuleRequest\x12\x33\n\rdispatch_rule\x18\n \x01(\x0b\x32\x1c.livekit.SIPDispatchRuleInfo\x12*\n\x04rule\x18\x01 \x01(\x0b\x32\x18.livekit.SIPDispatchRuleB\x02\x18\x01\x12\x15\n\ttrunk_ids\x18\x02 \x03(\tB\x02\x18\x01\x12\x1d\n\x11hide_phone_number\x18\x03 \x01(\x08\x42\x02\x18\x01\x12\x1b\n\x0finbound_numbers\x18\x06 \x03(\tB\x02\x18\x01\x12\x10\n\x04name\x18\x04 \x01(\tB\x02\x18\x01\x12\x38\n\x08metadata\x18\x05 \x01(\tB&\x18\x01\xa8P\x01\xb2P\x1e\x12q\n\nattributes\x18\x07 \x03(\x0b\x32\x35.livekit.CreateSIPDispatchRuleRequest.AttributesEntryB&\x18\x01\xa8P\x01\xb2P\x1e\x12\x17\n\x0broom_preset\x18\x08 \x01(\tB\x02\x18\x01\x12\x33\n\x0broom_config\x18\t \x01(\x0b\x32\x1a.livekit.RoomConfigurationB\x02\x18\x01\x1a\x31\n\x0f\x41ttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xbf\x01\n\x1cUpdateSIPDispatchRuleRequest\x12\x32\n\x14sip_dispatch_rule_id\x18\x01 \x01(\tB\x14\xbaP\x11sipDispatchRuleID\x12/\n\x07replace\x18\x02 \x01(\x0b\x32\x1c.livekit.SIPDispatchRuleInfoH\x00\x12\x30\n\x06update\x18\x03 \x01(\x0b\x32\x1e.livekit.SIPDispatchRuleUpdateH\x00\x42\x08\n\x06\x61\x63tion\"\x9e\x05\n\x13SIPDispatchRuleInfo\x12\x32\n\x14sip_dispatch_rule_id\x18\x01 \x01(\tB\x14\xbaP\x11sipDispatchRuleID\x12&\n\x04rule\x18\x02 \x01(\x0b\x32\x18.livekit.SIPDispatchRule\x12\x11\n\ttrunk_ids\x18\x03 \x03(\t\x12\x19\n\x11hide_phone_number\x18\x04 \x01(\x08\x12\x17\n\x0finbound_numbers\x18\x07 \x03(\t\x12\x0f\n\x07numbers\x18\r \x03(\t\x12\x0c\n\x04name\x18\x05 \x01(\t\x12\x36\n\x08metadata\x18\x06 \x01(\tB$\xa8P\x01\xb2P\x1e\x12\x66\n\nattributes\x18\x08 \x03(\x0b\x32,.livekit.SIPDispatchRuleInfo.AttributesEntryB$\xa8P\x01\xb2P\x1e\x12\x13\n\x0broom_preset\x18\t \x01(\t\x12/\n\x0broom_config\x18\n \x01(\x0b\x32\x1a.livekit.RoomConfiguration\x12\x15\n\rkrisp_enabled\x18\x0b \x01(\x08\x12\x35\n\x10media_encryption\x18\x0c \x01(\x0e\x32\x1b.livekit.SIPMediaEncryption\x12.\n\ncreated_at\x18\x0e \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12.\n\nupdated_at\x18\x0f \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x1a\x31\n\x0f\x41ttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xbb\x03\n\x15SIPDispatchRuleUpdate\x12&\n\ttrunk_ids\x18\x01 \x01(\x0b\x32\x13.livekit.ListUpdate\x12&\n\x04rule\x18\x02 \x01(\x0b\x32\x18.livekit.SIPDispatchRule\x12\x11\n\x04name\x18\x03 \x01(\tH\x00\x88\x01\x01\x12;\n\x08metadata\x18\x04 \x01(\tB$\xa8P\x01\xb2P\x1eH\x01\x88\x01\x01\x12h\n\nattributes\x18\x05 \x03(\x0b\x32..livekit.SIPDispatchRuleUpdate.AttributesEntryB$\xa8P\x01\xb2P\x1e\x12:\n\x10media_encryption\x18\x06 \x01(\x0e\x32\x1b.livekit.SIPMediaEncryptionH\x02\x88\x01\x01\x1a\x31\n\x0f\x41ttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\x07\n\x05_nameB\x0b\n\t_metadataB\x13\n\x11_media_encryption\"m\n\x1aListSIPDispatchRuleRequest\x12!\n\x04page\x18\x03 \x01(\x0b\x32\x13.livekit.Pagination\x12\x19\n\x11\x64ispatch_rule_ids\x18\x01 \x03(\t\x12\x11\n\ttrunk_ids\x18\x02 \x03(\t\"J\n\x1bListSIPDispatchRuleResponse\x12+\n\x05items\x18\x01 \x03(\x0b\x32\x1c.livekit.SIPDispatchRuleInfo\"R\n\x1c\x44\x65leteSIPDispatchRuleRequest\x12\x32\n\x14sip_dispatch_rule_id\x18\x01 \x01(\tB\x14\xbaP\x11sipDispatchRuleID\"\xd7\x03\n\x11SIPOutboundConfig\x12\x10\n\x08hostname\x18\x01 \x01(\t\x12\x1b\n\x13\x64\x65stination_country\x18\x07 \x01(\t\x12(\n\ttransport\x18\x02 \x01(\x0e\x32\x15.livekit.SIPTransport\x12\x1a\n\rauth_username\x18\x03 \x01(\tB\x03\xa8P\x01\x12\x1a\n\rauth_password\x18\x04 \x01(\tB\x03\xa8P\x01\x12R\n\x15headers_to_attributes\x18\x05 \x03(\x0b\x32\x33.livekit.SIPOutboundConfig.HeadersToAttributesEntry\x12R\n\x15\x61ttributes_to_headers\x18\x06 \x03(\x0b\x32\x33.livekit.SIPOutboundConfig.AttributesToHeadersEntry\x12\x11\n\tfrom_host\x18\x08 \x01(\t\x1a:\n\x18HeadersToAttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a:\n\x18\x41ttributesToHeadersEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xa1\t\n\x1b\x43reateSIPParticipantRequest\x12#\n\x0csip_trunk_id\x18\x01 \x01(\tB\r\xbaP\nsipTrunkID\x12)\n\x05trunk\x18\x14 \x01(\x0b\x32\x1a.livekit.SIPOutboundConfig\x12\x13\n\x0bsip_call_to\x18\x02 \x01(\t\x12\x12\n\nsip_number\x18\x0f \x01(\t\x12\x11\n\troom_name\x18\x03 \x01(\t\x12\x1c\n\x14participant_identity\x18\x04 \x01(\t\x12>\n\x10participant_name\x18\x07 \x01(\tB$\xa8P\x01\xb2P\x1e\x12\x42\n\x14participant_metadata\x18\x08 \x01(\tB$\xa8P\x01\xb2P\x1e\x12\x85\x01\n\x16participant_attributes\x18\t \x03(\x0b\x32?.livekit.CreateSIPParticipantRequest.ParticipantAttributesEntryB$\xa8P\x01\xb2P\x1e\x12\x0c\n\x04\x64tmf\x18\x05 \x01(\t\x12\x19\n\rplay_ringtone\x18\x06 \x01(\x08\x42\x02\x18\x01\x12\x15\n\rplay_dialtone\x18\r \x01(\x08\x12\x19\n\x11hide_phone_number\x18\n \x01(\x08\x12h\n\x07headers\x18\x10 \x03(\x0b\x32\x31.livekit.CreateSIPParticipantRequest.HeadersEntryB$\xa8P\x01\xb2P\x1e\x12\x32\n\x0finclude_headers\x18\x11 \x01(\x0e\x32\x19.livekit.SIPHeaderOptions\x12\x32\n\x0fringing_timeout\x18\x0b \x01(\x0b\x32\x19.google.protobuf.Duration\x12\x34\n\x11max_call_duration\x18\x0c \x01(\x0b\x32\x19.google.protobuf.Duration\x12\x15\n\rkrisp_enabled\x18\x0e \x01(\x08\x12\x35\n\x10media_encryption\x18\x12 \x01(\x0e\x32\x1b.livekit.SIPMediaEncryption\x12\x1b\n\x13wait_until_answered\x18\x13 \x01(\x08\x12?\n\x0c\x64isplay_name\x18\x15 \x01(\tB$\xa8P\x01\xb2P\x1eH\x00\x88\x01\x01\x12.\n\x0b\x64\x65stination\x18\x16 \x01(\x0b\x32\x14.livekit.DestinationH\x01\x88\x01\x01\x1a<\n\x1aParticipantAttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a.\n\x0cHeadersEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\x0f\n\r_display_nameB\x0e\n\x0c_destination\"\x92\x01\n\x12SIPParticipantInfo\x12(\n\x0eparticipant_id\x18\x01 \x01(\tB\x10\xbaP\rparticipantID\x12\x1c\n\x14participant_identity\x18\x02 \x01(\t\x12\x11\n\troom_name\x18\x03 \x01(\t\x12!\n\x0bsip_call_id\x18\x04 \x01(\tB\x0c\xbaP\tsipCallID\"\xcc\x02\n\x1dTransferSIPParticipantRequest\x12\x1c\n\x14participant_identity\x18\x01 \x01(\t\x12\x11\n\troom_name\x18\x02 \x01(\t\x12\x13\n\x0btransfer_to\x18\x03 \x01(\t\x12\x15\n\rplay_dialtone\x18\x04 \x01(\x08\x12j\n\x07headers\x18\x05 \x03(\x0b\x32\x33.livekit.TransferSIPParticipantRequest.HeadersEntryB$\xa8P\x01\xb2P\x1e\x12\x32\n\x0fringing_timeout\x18\x06 \x01(\x0b\x32\x19.google.protobuf.Duration\x1a.\n\x0cHeadersEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x99\x08\n\x0bSIPCallInfo\x12\x1a\n\x07\x63\x61ll_id\x18\x01 \x01(\tB\t\xbaP\x06\x63\x61llID\x12\x1c\n\x08trunk_id\x18\x02 \x01(\tB\n\xbaP\x07trunkID\x12+\n\x10\x64ispatch_rule_id\x18\x10 \x01(\tB\x11\xbaP\x0e\x64ispatchRuleID\x12\x0e\n\x06region\x18\x11 \x01(\t\x12\x11\n\troom_name\x18\x03 \x01(\t\x12\x1a\n\x07room_id\x18\x04 \x01(\tB\t\xbaP\x06roomID\x12\x1c\n\x14participant_identity\x18\x05 \x01(\t\x12u\n\x16participant_attributes\x18\x12 \x03(\x0b\x32/.livekit.SIPCallInfo.ParticipantAttributesEntryB$\xa8P\x01\xb2P\x1e\x12!\n\x08\x66rom_uri\x18\x06 \x01(\x0b\x32\x0f.livekit.SIPUri\x12\x1f\n\x06to_uri\x18\x07 \x01(\x0b\x32\x0f.livekit.SIPUri\x12\x16\n\ncreated_at\x18\t \x01(\x03\x42\x02\x18\x01\x12\x16\n\nstarted_at\x18\n \x01(\x03\x42\x02\x18\x01\x12\x14\n\x08\x65nded_at\x18\x0b \x01(\x03\x42\x02\x18\x01\x12-\n\x10\x65nabled_features\x18\x0e \x03(\x0e\x32\x13.livekit.SIPFeature\x12\x31\n\x0e\x63\x61ll_direction\x18\x0f \x01(\x0e\x32\x19.livekit.SIPCallDirection\x12+\n\x0b\x63\x61ll_status\x18\x08 \x01(\x0e\x32\x16.livekit.SIPCallStatus\x12\x15\n\rcreated_at_ns\x18\x16 \x01(\x03\x12\x15\n\rstarted_at_ns\x18\x17 \x01(\x03\x12\x13\n\x0b\x65nded_at_ns\x18\x18 \x01(\x03\x12\x34\n\x11\x64isconnect_reason\x18\x0c \x01(\x0e\x32\x19.livekit.DisconnectReason\x12\r\n\x05\x65rror\x18\r \x01(\t\x12,\n\x10\x63\x61ll_status_code\x18\x13 \x01(\x0b\x32\x12.livekit.SIPStatus\x12\x13\n\x0b\x61udio_codec\x18\x14 \x01(\t\x12\x18\n\x10media_encryption\x18\x15 \x01(\t\x12\x16\n\x0epcap_file_link\x18\x19 \x01(\t\x12*\n\x0c\x63\x61ll_context\x18\x1a \x03(\x0b\x32\x14.google.protobuf.Any\x12,\n\rprovider_info\x18\x1b \x01(\x0b\x32\x15.livekit.ProviderInfo\x12!\n\x0bsip_call_id\x18\x1c \x01(\tB\x0c\xbaP\tsipCallID\x1a<\n\x1aParticipantAttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xa0\x02\n\x0fSIPTransferInfo\x12\"\n\x0btransfer_id\x18\x01 \x01(\tB\r\xbaP\ntransferID\x12\x1a\n\x07\x63\x61ll_id\x18\x02 \x01(\tB\t\xbaP\x06\x63\x61llID\x12\x13\n\x0btransfer_to\x18\x03 \x01(\t\x12 \n\x18transfer_initiated_at_ns\x18\x04 \x01(\x03\x12 \n\x18transfer_completed_at_ns\x18\x05 \x01(\x03\x12\x33\n\x0ftransfer_status\x18\x06 \x01(\x0e\x32\x1a.livekit.SIPTransferStatus\x12\r\n\x05\x65rror\x18\x07 \x01(\t\x12\x30\n\x14transfer_status_code\x18\x08 \x01(\x0b\x32\x12.livekit.SIPStatus\"h\n\x06SIPUri\x12\x0c\n\x04user\x18\x01 \x01(\t\x12\x0c\n\x04host\x18\x02 \x01(\t\x12\n\n\x02ip\x18\x03 \x01(\t\x12\x0c\n\x04port\x18\x04 \x01(\r\x12(\n\ttransport\x18\x05 \x01(\x0e\x32\x15.livekit.SIPTransport\"<\n\x0b\x44\x65stination\x12\x0c\n\x04\x63ity\x18\x01 \x01(\t\x12\x0f\n\x07\x63ountry\x18\x02 \x01(\t\x12\x0e\n\x06region\x18\x03 \x01(\t*\xde\x14\n\rSIPStatusCode\x12\x16\n\x12SIP_STATUS_UNKNOWN\x10\x00\x12\x15\n\x11SIP_STATUS_TRYING\x10\x64\x12\x17\n\x12SIP_STATUS_RINGING\x10\xb4\x01\x12!\n\x1cSIP_STATUS_CALL_IS_FORWARDED\x10\xb5\x01\x12\x16\n\x11SIP_STATUS_QUEUED\x10\xb6\x01\x12 \n\x1bSIP_STATUS_SESSION_PROGRESS\x10\xb7\x01\x12\'\n\"SIP_STATUS_EARLY_DIALOG_TERMINATED\x10\xc7\x01\x12\x12\n\rSIP_STATUS_OK\x10\xc8\x01\x12\x18\n\x13SIP_STATUS_ACCEPTED\x10\xca\x01\x12\x1f\n\x1aSIP_STATUS_NO_NOTIFICATION\x10\xcc\x01\x12 \n\x1bSIP_STATUS_MULTIPLE_CHOICES\x10\xac\x02\x12!\n\x1cSIP_STATUS_MOVED_PERMANENTLY\x10\xad\x02\x12!\n\x1cSIP_STATUS_MOVED_TEMPORARILY\x10\xae\x02\x12\x19\n\x14SIP_STATUS_USE_PROXY\x10\xb1\x02\x12#\n\x1eSIP_STATUS_ALTERNATIVE_SERVICE\x10\xfc\x02\x12\x1b\n\x16SIP_STATUS_BAD_REQUEST\x10\x90\x03\x12\x1c\n\x17SIP_STATUS_UNAUTHORIZED\x10\x91\x03\x12 \n\x1bSIP_STATUS_PAYMENT_REQUIRED\x10\x92\x03\x12\x19\n\x14SIP_STATUS_FORBIDDEN\x10\x93\x03\x12\x18\n\x13SIP_STATUS_NOTFOUND\x10\x94\x03\x12\"\n\x1dSIP_STATUS_METHOD_NOT_ALLOWED\x10\x95\x03\x12\x1e\n\x19SIP_STATUS_NOT_ACCEPTABLE\x10\x96\x03\x12#\n\x1eSIP_STATUS_PROXY_AUTH_REQUIRED\x10\x97\x03\x12\x1f\n\x1aSIP_STATUS_REQUEST_TIMEOUT\x10\x98\x03\x12\x18\n\x13SIP_STATUS_CONFLICT\x10\x99\x03\x12\x14\n\x0fSIP_STATUS_GONE\x10\x9a\x03\x12\x1f\n\x1aSIP_STATUS_LENGTH_REQUIRED\x10\x9b\x03\x12*\n%SIP_STATUS_CONDITIONAL_REQUEST_FAILED\x10\x9c\x03\x12(\n#SIP_STATUS_REQUEST_ENTITY_TOO_LARGE\x10\x9d\x03\x12$\n\x1fSIP_STATUS_REQUEST_URI_TOO_LONG\x10\x9e\x03\x12&\n!SIP_STATUS_UNSUPPORTED_MEDIA_TYPE\x10\x9f\x03\x12/\n*SIP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE\x10\xa0\x03\x12)\n$SIP_STATUS_UNKNOWN_RESOURCE_PRIORITY\x10\xa1\x03\x12\x1d\n\x18SIP_STATUS_BAD_EXTENSION\x10\xa4\x03\x12\"\n\x1dSIP_STATUS_EXTENSION_REQUIRED\x10\xa5\x03\x12*\n%SIP_STATUS_SESSION_INTERVAL_TOO_SMALL\x10\xa6\x03\x12\"\n\x1dSIP_STATUS_INTERVAL_TOO_BRIEF\x10\xa7\x03\x12(\n#SIP_STATUS_BAD_LOCATION_INFORMATION\x10\xa8\x03\x12!\n\x1cSIP_STATUS_BAD_ALERT_MESSAGE\x10\xa9\x03\x12#\n\x1eSIP_STATUS_USE_IDENTITY_HEADER\x10\xac\x03\x12)\n$SIP_STATUS_PROVIDE_REFERRER_IDENTITY\x10\xad\x03\x12\x1b\n\x16SIP_STATUS_FLOW_FAILED\x10\xae\x03\x12$\n\x1fSIP_STATUS_ANONYMITY_DISALLOWED\x10\xb1\x03\x12!\n\x1cSIP_STATUS_BAD_IDENTITY_INFO\x10\xb4\x03\x12\'\n\"SIP_STATUS_UNSUPPORTED_CERTIFICATE\x10\xb5\x03\x12\'\n\"SIP_STATUS_INVALID_IDENTITY_HEADER\x10\xb6\x03\x12\x30\n+SIP_STATUS_FIRST_HOP_LACKS_OUTBOUND_SUPPORT\x10\xb7\x03\x12$\n\x1fSIP_STATUS_MAX_BREADTH_EXCEEDED\x10\xb8\x03\x12 \n\x1bSIP_STATUS_BAD_INFO_PACKAGE\x10\xd5\x03\x12\x1e\n\x19SIP_STATUS_CONSENT_NEEDED\x10\xd6\x03\x12\'\n\"SIP_STATUS_TEMPORARILY_UNAVAILABLE\x10\xe0\x03\x12\x30\n+SIP_STATUS_CALL_TRANSACTION_DOES_NOT_EXISTS\x10\xe1\x03\x12\x1d\n\x18SIP_STATUS_LOOP_DETECTED\x10\xe2\x03\x12\x1d\n\x18SIP_STATUS_TOO_MANY_HOPS\x10\xe3\x03\x12\"\n\x1dSIP_STATUS_ADDRESS_INCOMPLETE\x10\xe4\x03\x12\x19\n\x14SIP_STATUS_AMBIGUOUS\x10\xe5\x03\x12\x19\n\x14SIP_STATUS_BUSY_HERE\x10\xe6\x03\x12\"\n\x1dSIP_STATUS_REQUEST_TERMINATED\x10\xe7\x03\x12#\n\x1eSIP_STATUS_NOT_ACCEPTABLE_HERE\x10\xe8\x03\x12\x19\n\x14SIP_STATUS_BAD_EVENT\x10\xe9\x03\x12\x1f\n\x1aSIP_STATUS_REQUEST_PENDING\x10\xeb\x03\x12\x1e\n\x19SIP_STATUS_UNDECIPHERABLE\x10\xed\x03\x12+\n&SIP_STATUS_SECURITY_AGREEMENT_REQUIRED\x10\xee\x03\x12%\n SIP_STATUS_INTERNAL_SERVER_ERROR\x10\xf4\x03\x12\x1f\n\x1aSIP_STATUS_NOT_IMPLEMENTED\x10\xf5\x03\x12\x1b\n\x16SIP_STATUS_BAD_GATEWAY\x10\xf6\x03\x12#\n\x1eSIP_STATUS_SERVICE_UNAVAILABLE\x10\xf7\x03\x12\x1f\n\x1aSIP_STATUS_GATEWAY_TIMEOUT\x10\xf8\x03\x12%\n SIP_STATUS_VERSION_NOT_SUPPORTED\x10\xf9\x03\x12!\n\x1cSIP_STATUS_MESSAGE_TOO_LARGE\x10\x81\x04\x12&\n!SIP_STATUS_GLOBAL_BUSY_EVERYWHERE\x10\xd8\x04\x12\x1e\n\x19SIP_STATUS_GLOBAL_DECLINE\x10\xdb\x04\x12.\n)SIP_STATUS_GLOBAL_DOES_NOT_EXIST_ANYWHERE\x10\xdc\x04\x12%\n SIP_STATUS_GLOBAL_NOT_ACCEPTABLE\x10\xde\x04\x12\x1f\n\x1aSIP_STATUS_GLOBAL_UNWANTED\x10\xdf\x04\x12\x1f\n\x1aSIP_STATUS_GLOBAL_REJECTED\x10\xe0\x04*k\n\x0cSIPTransport\x12\x16\n\x12SIP_TRANSPORT_AUTO\x10\x00\x12\x15\n\x11SIP_TRANSPORT_UDP\x10\x01\x12\x15\n\x11SIP_TRANSPORT_TCP\x10\x02\x12\x15\n\x11SIP_TRANSPORT_TLS\x10\x03*N\n\x10SIPHeaderOptions\x12\x12\n\x0eSIP_NO_HEADERS\x10\x00\x12\x11\n\rSIP_X_HEADERS\x10\x01\x12\x13\n\x0fSIP_ALL_HEADERS\x10\x02*o\n\x12SIPMediaEncryption\x12\x1d\n\x19SIP_MEDIA_ENCRYPT_DISABLE\x10\x00\x12\x1b\n\x17SIP_MEDIA_ENCRYPT_ALLOW\x10\x01\x12\x1d\n\x19SIP_MEDIA_ENCRYPT_REQUIRE\x10\x02*a\n\x0cProviderType\x12\x19\n\x15PROVIDER_TYPE_UNKNOWN\x10\x00\x12\x1a\n\x16PROVIDER_TYPE_INTERNAL\x10\x01\x12\x1a\n\x16PROVIDER_TYPE_EXTERNAL\x10\x02*w\n\rSIPCallStatus\x12\x15\n\x11SCS_CALL_INCOMING\x10\x00\x12\x1a\n\x16SCS_PARTICIPANT_JOINED\x10\x01\x12\x0e\n\nSCS_ACTIVE\x10\x02\x12\x14\n\x10SCS_DISCONNECTED\x10\x03\x12\r\n\tSCS_ERROR\x10\x04*c\n\x11SIPTransferStatus\x12\x18\n\x14STS_TRANSFER_ONGOING\x10\x00\x12\x17\n\x13STS_TRANSFER_FAILED\x10\x01\x12\x1b\n\x17STS_TRANSFER_SUCCESSFUL\x10\x02*)\n\nSIPFeature\x12\x08\n\x04NONE\x10\x00\x12\x11\n\rKRISP_ENABLED\x10\x01*F\n\x10SIPCallDirection\x12\x0f\n\x0bSCD_UNKNOWN\x10\x00\x12\x0f\n\x0bSCD_INBOUND\x10\x01\x12\x10\n\x0cSCD_OUTBOUND\x10\x02\x32\xd7\x0b\n\x03SIP\x12P\n\x0cListSIPTrunk\x12\x1c.livekit.ListSIPTrunkRequest\x1a\x1d.livekit.ListSIPTrunkResponse\"\x03\x88\x02\x01\x12\\\n\x15\x43reateSIPInboundTrunk\x12%.livekit.CreateSIPInboundTrunkRequest\x1a\x1c.livekit.SIPInboundTrunkInfo\x12_\n\x16\x43reateSIPOutboundTrunk\x12&.livekit.CreateSIPOutboundTrunkRequest\x1a\x1d.livekit.SIPOutboundTrunkInfo\x12\\\n\x15UpdateSIPInboundTrunk\x12%.livekit.UpdateSIPInboundTrunkRequest\x1a\x1c.livekit.SIPInboundTrunkInfo\x12_\n\x16UpdateSIPOutboundTrunk\x12&.livekit.UpdateSIPOutboundTrunkRequest\x1a\x1d.livekit.SIPOutboundTrunkInfo\x12]\n\x12GetSIPInboundTrunk\x12\".livekit.GetSIPInboundTrunkRequest\x1a#.livekit.GetSIPInboundTrunkResponse\x12`\n\x13GetSIPOutboundTrunk\x12#.livekit.GetSIPOutboundTrunkRequest\x1a$.livekit.GetSIPOutboundTrunkResponse\x12`\n\x13ListSIPInboundTrunk\x12#.livekit.ListSIPInboundTrunkRequest\x1a$.livekit.ListSIPInboundTrunkResponse\x12\x63\n\x14ListSIPOutboundTrunk\x12$.livekit.ListSIPOutboundTrunkRequest\x1a%.livekit.ListSIPOutboundTrunkResponse\x12G\n\x0e\x44\x65leteSIPTrunk\x12\x1e.livekit.DeleteSIPTrunkRequest\x1a\x15.livekit.SIPTrunkInfo\x12\\\n\x15\x43reateSIPDispatchRule\x12%.livekit.CreateSIPDispatchRuleRequest\x1a\x1c.livekit.SIPDispatchRuleInfo\x12\\\n\x15UpdateSIPDispatchRule\x12%.livekit.UpdateSIPDispatchRuleRequest\x1a\x1c.livekit.SIPDispatchRuleInfo\x12`\n\x13ListSIPDispatchRule\x12#.livekit.ListSIPDispatchRuleRequest\x1a$.livekit.ListSIPDispatchRuleResponse\x12\\\n\x15\x44\x65leteSIPDispatchRule\x12%.livekit.DeleteSIPDispatchRuleRequest\x1a\x1c.livekit.SIPDispatchRuleInfo\x12Y\n\x14\x43reateSIPParticipant\x12$.livekit.CreateSIPParticipantRequest\x1a\x1b.livekit.SIPParticipantInfo\x12X\n\x16TransferSIPParticipant\x12&.livekit.TransferSIPParticipantRequest\x1a\x16.google.protobuf.EmptyBFZ#github.com/livekit/protocol/livekit\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -24,82 +31,324 @@
_globals['DESCRIPTOR']._serialized_options = b'Z#github.com/livekit/protocol/livekit\252\002\rLiveKit.Proto\352\002\016LiveKit::Proto'
_globals['_CREATESIPTRUNKREQUEST'].fields_by_name['inbound_numbers_regex']._options = None
_globals['_CREATESIPTRUNKREQUEST'].fields_by_name['inbound_numbers_regex']._serialized_options = b'\030\001'
+ _globals['_CREATESIPTRUNKREQUEST'].fields_by_name['inbound_username']._options = None
+ _globals['_CREATESIPTRUNKREQUEST'].fields_by_name['inbound_username']._serialized_options = b'\250P\001'
+ _globals['_CREATESIPTRUNKREQUEST'].fields_by_name['inbound_password']._options = None
+ _globals['_CREATESIPTRUNKREQUEST'].fields_by_name['inbound_password']._serialized_options = b'\250P\001'
+ _globals['_CREATESIPTRUNKREQUEST'].fields_by_name['outbound_username']._options = None
+ _globals['_CREATESIPTRUNKREQUEST'].fields_by_name['outbound_username']._serialized_options = b'\250P\001'
+ _globals['_CREATESIPTRUNKREQUEST'].fields_by_name['outbound_password']._options = None
+ _globals['_CREATESIPTRUNKREQUEST'].fields_by_name['outbound_password']._serialized_options = b'\250P\001'
+ _globals['_CREATESIPTRUNKREQUEST'].fields_by_name['metadata']._options = None
+ _globals['_CREATESIPTRUNKREQUEST'].fields_by_name['metadata']._serialized_options = b'\250P\001\262P\036'
_globals['_CREATESIPTRUNKREQUEST']._options = None
_globals['_CREATESIPTRUNKREQUEST']._serialized_options = b'\030\001'
+ _globals['_SIPTRUNKINFO'].fields_by_name['sip_trunk_id']._options = None
+ _globals['_SIPTRUNKINFO'].fields_by_name['sip_trunk_id']._serialized_options = b'\272P\nsipTrunkID'
_globals['_SIPTRUNKINFO'].fields_by_name['inbound_numbers_regex']._options = None
_globals['_SIPTRUNKINFO'].fields_by_name['inbound_numbers_regex']._serialized_options = b'\030\001'
+ _globals['_SIPTRUNKINFO'].fields_by_name['inbound_username']._options = None
+ _globals['_SIPTRUNKINFO'].fields_by_name['inbound_username']._serialized_options = b'\250P\001'
+ _globals['_SIPTRUNKINFO'].fields_by_name['inbound_password']._options = None
+ _globals['_SIPTRUNKINFO'].fields_by_name['inbound_password']._serialized_options = b'\250P\001'
+ _globals['_SIPTRUNKINFO'].fields_by_name['outbound_username']._options = None
+ _globals['_SIPTRUNKINFO'].fields_by_name['outbound_username']._serialized_options = b'\250P\001'
+ _globals['_SIPTRUNKINFO'].fields_by_name['outbound_password']._options = None
+ _globals['_SIPTRUNKINFO'].fields_by_name['outbound_password']._serialized_options = b'\250P\001'
+ _globals['_SIPTRUNKINFO'].fields_by_name['metadata']._options = None
+ _globals['_SIPTRUNKINFO'].fields_by_name['metadata']._serialized_options = b'\250P\001\262P\036'
_globals['_SIPTRUNKINFO']._options = None
_globals['_SIPTRUNKINFO']._serialized_options = b'\030\001'
+ _globals['_UPDATESIPINBOUNDTRUNKREQUEST'].fields_by_name['sip_trunk_id']._options = None
+ _globals['_UPDATESIPINBOUNDTRUNKREQUEST'].fields_by_name['sip_trunk_id']._serialized_options = b'\272P\nsipTrunkID'
+ _globals['_SIPINBOUNDTRUNKINFO_HEADERSENTRY']._options = None
+ _globals['_SIPINBOUNDTRUNKINFO_HEADERSENTRY']._serialized_options = b'8\001'
+ _globals['_SIPINBOUNDTRUNKINFO_HEADERSTOATTRIBUTESENTRY']._options = None
+ _globals['_SIPINBOUNDTRUNKINFO_HEADERSTOATTRIBUTESENTRY']._serialized_options = b'8\001'
+ _globals['_SIPINBOUNDTRUNKINFO_ATTRIBUTESTOHEADERSENTRY']._options = None
+ _globals['_SIPINBOUNDTRUNKINFO_ATTRIBUTESTOHEADERSENTRY']._serialized_options = b'8\001'
+ _globals['_SIPINBOUNDTRUNKINFO'].fields_by_name['sip_trunk_id']._options = None
+ _globals['_SIPINBOUNDTRUNKINFO'].fields_by_name['sip_trunk_id']._serialized_options = b'\272P\nsipTrunkID'
+ _globals['_SIPINBOUNDTRUNKINFO'].fields_by_name['metadata']._options = None
+ _globals['_SIPINBOUNDTRUNKINFO'].fields_by_name['metadata']._serialized_options = b'\250P\001\262P\036'
+ _globals['_SIPINBOUNDTRUNKINFO'].fields_by_name['auth_username']._options = None
+ _globals['_SIPINBOUNDTRUNKINFO'].fields_by_name['auth_username']._serialized_options = b'\250P\001'
+ _globals['_SIPINBOUNDTRUNKINFO'].fields_by_name['auth_password']._options = None
+ _globals['_SIPINBOUNDTRUNKINFO'].fields_by_name['auth_password']._serialized_options = b'\250P\001'
+ _globals['_SIPINBOUNDTRUNKINFO'].fields_by_name['headers']._options = None
+ _globals['_SIPINBOUNDTRUNKINFO'].fields_by_name['headers']._serialized_options = b'\250P\001\262P\036'
+ _globals['_SIPINBOUNDTRUNKUPDATE'].fields_by_name['auth_username']._options = None
+ _globals['_SIPINBOUNDTRUNKUPDATE'].fields_by_name['auth_username']._serialized_options = b'\250P\001'
+ _globals['_SIPINBOUNDTRUNKUPDATE'].fields_by_name['auth_password']._options = None
+ _globals['_SIPINBOUNDTRUNKUPDATE'].fields_by_name['auth_password']._serialized_options = b'\250P\001'
+ _globals['_SIPINBOUNDTRUNKUPDATE'].fields_by_name['metadata']._options = None
+ _globals['_SIPINBOUNDTRUNKUPDATE'].fields_by_name['metadata']._serialized_options = b'\250P\001\262P\036'
+ _globals['_UPDATESIPOUTBOUNDTRUNKREQUEST'].fields_by_name['sip_trunk_id']._options = None
+ _globals['_UPDATESIPOUTBOUNDTRUNKREQUEST'].fields_by_name['sip_trunk_id']._serialized_options = b'\272P\nsipTrunkID'
+ _globals['_SIPOUTBOUNDTRUNKINFO_HEADERSENTRY']._options = None
+ _globals['_SIPOUTBOUNDTRUNKINFO_HEADERSENTRY']._serialized_options = b'8\001'
+ _globals['_SIPOUTBOUNDTRUNKINFO_HEADERSTOATTRIBUTESENTRY']._options = None
+ _globals['_SIPOUTBOUNDTRUNKINFO_HEADERSTOATTRIBUTESENTRY']._serialized_options = b'8\001'
+ _globals['_SIPOUTBOUNDTRUNKINFO_ATTRIBUTESTOHEADERSENTRY']._options = None
+ _globals['_SIPOUTBOUNDTRUNKINFO_ATTRIBUTESTOHEADERSENTRY']._serialized_options = b'8\001'
+ _globals['_SIPOUTBOUNDTRUNKINFO'].fields_by_name['sip_trunk_id']._options = None
+ _globals['_SIPOUTBOUNDTRUNKINFO'].fields_by_name['sip_trunk_id']._serialized_options = b'\272P\nsipTrunkID'
+ _globals['_SIPOUTBOUNDTRUNKINFO'].fields_by_name['metadata']._options = None
+ _globals['_SIPOUTBOUNDTRUNKINFO'].fields_by_name['metadata']._serialized_options = b'\250P\001\262P\036'
+ _globals['_SIPOUTBOUNDTRUNKINFO'].fields_by_name['auth_username']._options = None
+ _globals['_SIPOUTBOUNDTRUNKINFO'].fields_by_name['auth_username']._serialized_options = b'\250P\001'
+ _globals['_SIPOUTBOUNDTRUNKINFO'].fields_by_name['auth_password']._options = None
+ _globals['_SIPOUTBOUNDTRUNKINFO'].fields_by_name['auth_password']._serialized_options = b'\250P\001'
+ _globals['_SIPOUTBOUNDTRUNKINFO'].fields_by_name['headers']._options = None
+ _globals['_SIPOUTBOUNDTRUNKINFO'].fields_by_name['headers']._serialized_options = b'\250P\001\262P\036'
+ _globals['_SIPOUTBOUNDTRUNKUPDATE'].fields_by_name['auth_username']._options = None
+ _globals['_SIPOUTBOUNDTRUNKUPDATE'].fields_by_name['auth_username']._serialized_options = b'\250P\001'
+ _globals['_SIPOUTBOUNDTRUNKUPDATE'].fields_by_name['auth_password']._options = None
+ _globals['_SIPOUTBOUNDTRUNKUPDATE'].fields_by_name['auth_password']._serialized_options = b'\250P\001'
+ _globals['_SIPOUTBOUNDTRUNKUPDATE'].fields_by_name['metadata']._options = None
+ _globals['_SIPOUTBOUNDTRUNKUPDATE'].fields_by_name['metadata']._serialized_options = b'\250P\001\262P\036'
+ _globals['_GETSIPINBOUNDTRUNKREQUEST'].fields_by_name['sip_trunk_id']._options = None
+ _globals['_GETSIPINBOUNDTRUNKREQUEST'].fields_by_name['sip_trunk_id']._serialized_options = b'\272P\nsipTrunkID'
+ _globals['_GETSIPOUTBOUNDTRUNKREQUEST'].fields_by_name['sip_trunk_id']._options = None
+ _globals['_GETSIPOUTBOUNDTRUNKREQUEST'].fields_by_name['sip_trunk_id']._serialized_options = b'\272P\nsipTrunkID'
_globals['_LISTSIPTRUNKREQUEST']._options = None
_globals['_LISTSIPTRUNKREQUEST']._serialized_options = b'\030\001'
_globals['_LISTSIPTRUNKRESPONSE']._options = None
_globals['_LISTSIPTRUNKRESPONSE']._serialized_options = b'\030\001'
+ _globals['_DELETESIPTRUNKREQUEST'].fields_by_name['sip_trunk_id']._options = None
+ _globals['_DELETESIPTRUNKREQUEST'].fields_by_name['sip_trunk_id']._serialized_options = b'\272P\nsipTrunkID'
_globals['_CREATESIPDISPATCHRULEREQUEST_ATTRIBUTESENTRY']._options = None
_globals['_CREATESIPDISPATCHRULEREQUEST_ATTRIBUTESENTRY']._serialized_options = b'8\001'
+ _globals['_CREATESIPDISPATCHRULEREQUEST'].fields_by_name['rule']._options = None
+ _globals['_CREATESIPDISPATCHRULEREQUEST'].fields_by_name['rule']._serialized_options = b'\030\001'
+ _globals['_CREATESIPDISPATCHRULEREQUEST'].fields_by_name['trunk_ids']._options = None
+ _globals['_CREATESIPDISPATCHRULEREQUEST'].fields_by_name['trunk_ids']._serialized_options = b'\030\001'
+ _globals['_CREATESIPDISPATCHRULEREQUEST'].fields_by_name['hide_phone_number']._options = None
+ _globals['_CREATESIPDISPATCHRULEREQUEST'].fields_by_name['hide_phone_number']._serialized_options = b'\030\001'
+ _globals['_CREATESIPDISPATCHRULEREQUEST'].fields_by_name['inbound_numbers']._options = None
+ _globals['_CREATESIPDISPATCHRULEREQUEST'].fields_by_name['inbound_numbers']._serialized_options = b'\030\001'
+ _globals['_CREATESIPDISPATCHRULEREQUEST'].fields_by_name['name']._options = None
+ _globals['_CREATESIPDISPATCHRULEREQUEST'].fields_by_name['name']._serialized_options = b'\030\001'
+ _globals['_CREATESIPDISPATCHRULEREQUEST'].fields_by_name['metadata']._options = None
+ _globals['_CREATESIPDISPATCHRULEREQUEST'].fields_by_name['metadata']._serialized_options = b'\030\001\250P\001\262P\036'
+ _globals['_CREATESIPDISPATCHRULEREQUEST'].fields_by_name['attributes']._options = None
+ _globals['_CREATESIPDISPATCHRULEREQUEST'].fields_by_name['attributes']._serialized_options = b'\030\001\250P\001\262P\036'
+ _globals['_CREATESIPDISPATCHRULEREQUEST'].fields_by_name['room_preset']._options = None
+ _globals['_CREATESIPDISPATCHRULEREQUEST'].fields_by_name['room_preset']._serialized_options = b'\030\001'
+ _globals['_CREATESIPDISPATCHRULEREQUEST'].fields_by_name['room_config']._options = None
+ _globals['_CREATESIPDISPATCHRULEREQUEST'].fields_by_name['room_config']._serialized_options = b'\030\001'
+ _globals['_UPDATESIPDISPATCHRULEREQUEST'].fields_by_name['sip_dispatch_rule_id']._options = None
+ _globals['_UPDATESIPDISPATCHRULEREQUEST'].fields_by_name['sip_dispatch_rule_id']._serialized_options = b'\272P\021sipDispatchRuleID'
_globals['_SIPDISPATCHRULEINFO_ATTRIBUTESENTRY']._options = None
_globals['_SIPDISPATCHRULEINFO_ATTRIBUTESENTRY']._serialized_options = b'8\001'
+ _globals['_SIPDISPATCHRULEINFO'].fields_by_name['sip_dispatch_rule_id']._options = None
+ _globals['_SIPDISPATCHRULEINFO'].fields_by_name['sip_dispatch_rule_id']._serialized_options = b'\272P\021sipDispatchRuleID'
+ _globals['_SIPDISPATCHRULEINFO'].fields_by_name['metadata']._options = None
+ _globals['_SIPDISPATCHRULEINFO'].fields_by_name['metadata']._serialized_options = b'\250P\001\262P\036'
+ _globals['_SIPDISPATCHRULEINFO'].fields_by_name['attributes']._options = None
+ _globals['_SIPDISPATCHRULEINFO'].fields_by_name['attributes']._serialized_options = b'\250P\001\262P\036'
+ _globals['_SIPDISPATCHRULEUPDATE_ATTRIBUTESENTRY']._options = None
+ _globals['_SIPDISPATCHRULEUPDATE_ATTRIBUTESENTRY']._serialized_options = b'8\001'
+ _globals['_SIPDISPATCHRULEUPDATE'].fields_by_name['metadata']._options = None
+ _globals['_SIPDISPATCHRULEUPDATE'].fields_by_name['metadata']._serialized_options = b'\250P\001\262P\036'
+ _globals['_SIPDISPATCHRULEUPDATE'].fields_by_name['attributes']._options = None
+ _globals['_SIPDISPATCHRULEUPDATE'].fields_by_name['attributes']._serialized_options = b'\250P\001\262P\036'
+ _globals['_DELETESIPDISPATCHRULEREQUEST'].fields_by_name['sip_dispatch_rule_id']._options = None
+ _globals['_DELETESIPDISPATCHRULEREQUEST'].fields_by_name['sip_dispatch_rule_id']._serialized_options = b'\272P\021sipDispatchRuleID'
+ _globals['_SIPOUTBOUNDCONFIG_HEADERSTOATTRIBUTESENTRY']._options = None
+ _globals['_SIPOUTBOUNDCONFIG_HEADERSTOATTRIBUTESENTRY']._serialized_options = b'8\001'
+ _globals['_SIPOUTBOUNDCONFIG_ATTRIBUTESTOHEADERSENTRY']._options = None
+ _globals['_SIPOUTBOUNDCONFIG_ATTRIBUTESTOHEADERSENTRY']._serialized_options = b'8\001'
+ _globals['_SIPOUTBOUNDCONFIG'].fields_by_name['auth_username']._options = None
+ _globals['_SIPOUTBOUNDCONFIG'].fields_by_name['auth_username']._serialized_options = b'\250P\001'
+ _globals['_SIPOUTBOUNDCONFIG'].fields_by_name['auth_password']._options = None
+ _globals['_SIPOUTBOUNDCONFIG'].fields_by_name['auth_password']._serialized_options = b'\250P\001'
_globals['_CREATESIPPARTICIPANTREQUEST_PARTICIPANTATTRIBUTESENTRY']._options = None
_globals['_CREATESIPPARTICIPANTREQUEST_PARTICIPANTATTRIBUTESENTRY']._serialized_options = b'8\001'
- _globals['_SIP'].methods_by_name['CreateSIPTrunk']._options = None
- _globals['_SIP'].methods_by_name['CreateSIPTrunk']._serialized_options = b'\210\002\001'
+ _globals['_CREATESIPPARTICIPANTREQUEST_HEADERSENTRY']._options = None
+ _globals['_CREATESIPPARTICIPANTREQUEST_HEADERSENTRY']._serialized_options = b'8\001'
+ _globals['_CREATESIPPARTICIPANTREQUEST'].fields_by_name['sip_trunk_id']._options = None
+ _globals['_CREATESIPPARTICIPANTREQUEST'].fields_by_name['sip_trunk_id']._serialized_options = b'\272P\nsipTrunkID'
+ _globals['_CREATESIPPARTICIPANTREQUEST'].fields_by_name['participant_name']._options = None
+ _globals['_CREATESIPPARTICIPANTREQUEST'].fields_by_name['participant_name']._serialized_options = b'\250P\001\262P\036'
+ _globals['_CREATESIPPARTICIPANTREQUEST'].fields_by_name['participant_metadata']._options = None
+ _globals['_CREATESIPPARTICIPANTREQUEST'].fields_by_name['participant_metadata']._serialized_options = b'\250P\001\262P\036'
+ _globals['_CREATESIPPARTICIPANTREQUEST'].fields_by_name['participant_attributes']._options = None
+ _globals['_CREATESIPPARTICIPANTREQUEST'].fields_by_name['participant_attributes']._serialized_options = b'\250P\001\262P\036'
+ _globals['_CREATESIPPARTICIPANTREQUEST'].fields_by_name['play_ringtone']._options = None
+ _globals['_CREATESIPPARTICIPANTREQUEST'].fields_by_name['play_ringtone']._serialized_options = b'\030\001'
+ _globals['_CREATESIPPARTICIPANTREQUEST'].fields_by_name['headers']._options = None
+ _globals['_CREATESIPPARTICIPANTREQUEST'].fields_by_name['headers']._serialized_options = b'\250P\001\262P\036'
+ _globals['_CREATESIPPARTICIPANTREQUEST'].fields_by_name['display_name']._options = None
+ _globals['_CREATESIPPARTICIPANTREQUEST'].fields_by_name['display_name']._serialized_options = b'\250P\001\262P\036'
+ _globals['_SIPPARTICIPANTINFO'].fields_by_name['participant_id']._options = None
+ _globals['_SIPPARTICIPANTINFO'].fields_by_name['participant_id']._serialized_options = b'\272P\rparticipantID'
+ _globals['_SIPPARTICIPANTINFO'].fields_by_name['sip_call_id']._options = None
+ _globals['_SIPPARTICIPANTINFO'].fields_by_name['sip_call_id']._serialized_options = b'\272P\tsipCallID'
+ _globals['_TRANSFERSIPPARTICIPANTREQUEST_HEADERSENTRY']._options = None
+ _globals['_TRANSFERSIPPARTICIPANTREQUEST_HEADERSENTRY']._serialized_options = b'8\001'
+ _globals['_TRANSFERSIPPARTICIPANTREQUEST'].fields_by_name['headers']._options = None
+ _globals['_TRANSFERSIPPARTICIPANTREQUEST'].fields_by_name['headers']._serialized_options = b'\250P\001\262P\036'
+ _globals['_SIPCALLINFO_PARTICIPANTATTRIBUTESENTRY']._options = None
+ _globals['_SIPCALLINFO_PARTICIPANTATTRIBUTESENTRY']._serialized_options = b'8\001'
+ _globals['_SIPCALLINFO'].fields_by_name['call_id']._options = None
+ _globals['_SIPCALLINFO'].fields_by_name['call_id']._serialized_options = b'\272P\006callID'
+ _globals['_SIPCALLINFO'].fields_by_name['trunk_id']._options = None
+ _globals['_SIPCALLINFO'].fields_by_name['trunk_id']._serialized_options = b'\272P\007trunkID'
+ _globals['_SIPCALLINFO'].fields_by_name['dispatch_rule_id']._options = None
+ _globals['_SIPCALLINFO'].fields_by_name['dispatch_rule_id']._serialized_options = b'\272P\016dispatchRuleID'
+ _globals['_SIPCALLINFO'].fields_by_name['room_id']._options = None
+ _globals['_SIPCALLINFO'].fields_by_name['room_id']._serialized_options = b'\272P\006roomID'
+ _globals['_SIPCALLINFO'].fields_by_name['participant_attributes']._options = None
+ _globals['_SIPCALLINFO'].fields_by_name['participant_attributes']._serialized_options = b'\250P\001\262P\036'
+ _globals['_SIPCALLINFO'].fields_by_name['created_at']._options = None
+ _globals['_SIPCALLINFO'].fields_by_name['created_at']._serialized_options = b'\030\001'
+ _globals['_SIPCALLINFO'].fields_by_name['started_at']._options = None
+ _globals['_SIPCALLINFO'].fields_by_name['started_at']._serialized_options = b'\030\001'
+ _globals['_SIPCALLINFO'].fields_by_name['ended_at']._options = None
+ _globals['_SIPCALLINFO'].fields_by_name['ended_at']._serialized_options = b'\030\001'
+ _globals['_SIPCALLINFO'].fields_by_name['sip_call_id']._options = None
+ _globals['_SIPCALLINFO'].fields_by_name['sip_call_id']._serialized_options = b'\272P\tsipCallID'
+ _globals['_SIPTRANSFERINFO'].fields_by_name['transfer_id']._options = None
+ _globals['_SIPTRANSFERINFO'].fields_by_name['transfer_id']._serialized_options = b'\272P\ntransferID'
+ _globals['_SIPTRANSFERINFO'].fields_by_name['call_id']._options = None
+ _globals['_SIPTRANSFERINFO'].fields_by_name['call_id']._serialized_options = b'\272P\006callID'
_globals['_SIP'].methods_by_name['ListSIPTrunk']._options = None
_globals['_SIP'].methods_by_name['ListSIPTrunk']._serialized_options = b'\210\002\001'
- _globals['_SIPTRANSPORT']._serialized_start=3306
- _globals['_SIPTRANSPORT']._serialized_end=3413
- _globals['_CREATESIPTRUNKREQUEST']._serialized_start=31
- _globals['_CREATESIPTRUNKREQUEST']._serialized_end=334
- _globals['_SIPTRUNKINFO']._serialized_start=337
- _globals['_SIPTRUNKINFO']._serialized_end=812
- _globals['_SIPTRUNKINFO_TRUNKKIND']._serialized_start=740
- _globals['_SIPTRUNKINFO_TRUNKKIND']._serialized_end=808
- _globals['_CREATESIPINBOUNDTRUNKREQUEST']._serialized_start=814
- _globals['_CREATESIPINBOUNDTRUNKREQUEST']._serialized_end=889
- _globals['_SIPINBOUNDTRUNKINFO']._serialized_start=892
- _globals['_SIPINBOUNDTRUNKINFO']._serialized_end=1082
- _globals['_CREATESIPOUTBOUNDTRUNKREQUEST']._serialized_start=1084
- _globals['_CREATESIPOUTBOUNDTRUNKREQUEST']._serialized_end=1161
- _globals['_SIPOUTBOUNDTRUNKINFO']._serialized_start=1164
- _globals['_SIPOUTBOUNDTRUNKINFO']._serialized_end=1362
- _globals['_LISTSIPTRUNKREQUEST']._serialized_start=1364
- _globals['_LISTSIPTRUNKREQUEST']._serialized_end=1389
- _globals['_LISTSIPTRUNKRESPONSE']._serialized_start=1391
- _globals['_LISTSIPTRUNKRESPONSE']._serialized_end=1455
- _globals['_LISTSIPINBOUNDTRUNKREQUEST']._serialized_start=1457
- _globals['_LISTSIPINBOUNDTRUNKREQUEST']._serialized_end=1485
- _globals['_LISTSIPINBOUNDTRUNKRESPONSE']._serialized_start=1487
- _globals['_LISTSIPINBOUNDTRUNKRESPONSE']._serialized_end=1561
- _globals['_LISTSIPOUTBOUNDTRUNKREQUEST']._serialized_start=1563
- _globals['_LISTSIPOUTBOUNDTRUNKREQUEST']._serialized_end=1592
- _globals['_LISTSIPOUTBOUNDTRUNKRESPONSE']._serialized_start=1594
- _globals['_LISTSIPOUTBOUNDTRUNKRESPONSE']._serialized_end=1670
- _globals['_DELETESIPTRUNKREQUEST']._serialized_start=1672
- _globals['_DELETESIPTRUNKREQUEST']._serialized_end=1717
- _globals['_SIPDISPATCHRULEDIRECT']._serialized_start=1719
- _globals['_SIPDISPATCHRULEDIRECT']._serialized_end=1774
- _globals['_SIPDISPATCHRULEINDIVIDUAL']._serialized_start=1776
- _globals['_SIPDISPATCHRULEINDIVIDUAL']._serialized_end=1837
- _globals['_SIPDISPATCHRULE']._serialized_start=1840
- _globals['_SIPDISPATCHRULE']._serialized_end=2001
- _globals['_CREATESIPDISPATCHRULEREQUEST']._serialized_start=2004
- _globals['_CREATESIPDISPATCHRULEREQUEST']._serialized_end=2303
- _globals['_CREATESIPDISPATCHRULEREQUEST_ATTRIBUTESENTRY']._serialized_start=2254
- _globals['_CREATESIPDISPATCHRULEREQUEST_ATTRIBUTESENTRY']._serialized_end=2303
- _globals['_SIPDISPATCHRULEINFO']._serialized_start=2306
- _globals['_SIPDISPATCHRULEINFO']._serialized_end=2617
- _globals['_SIPDISPATCHRULEINFO_ATTRIBUTESENTRY']._serialized_start=2254
- _globals['_SIPDISPATCHRULEINFO_ATTRIBUTESENTRY']._serialized_end=2303
- _globals['_LISTSIPDISPATCHRULEREQUEST']._serialized_start=2619
- _globals['_LISTSIPDISPATCHRULEREQUEST']._serialized_end=2647
- _globals['_LISTSIPDISPATCHRULERESPONSE']._serialized_start=2649
- _globals['_LISTSIPDISPATCHRULERESPONSE']._serialized_end=2723
- _globals['_DELETESIPDISPATCHRULEREQUEST']._serialized_start=2725
- _globals['_DELETESIPDISPATCHRULEREQUEST']._serialized_end=2785
- _globals['_CREATESIPPARTICIPANTREQUEST']._serialized_start=2788
- _globals['_CREATESIPPARTICIPANTREQUEST']._serialized_end=3188
- _globals['_CREATESIPPARTICIPANTREQUEST_PARTICIPANTATTRIBUTESENTRY']._serialized_start=3128
- _globals['_CREATESIPPARTICIPANTREQUEST_PARTICIPANTATTRIBUTESENTRY']._serialized_end=3188
- _globals['_SIPPARTICIPANTINFO']._serialized_start=3190
- _globals['_SIPPARTICIPANTINFO']._serialized_end=3304
- _globals['_SIP']._serialized_start=3416
- _globals['_SIP']._serialized_end=4421
+ _globals['_SIPSTATUSCODE']._serialized_start=11841
+ _globals['_SIPSTATUSCODE']._serialized_end=14495
+ _globals['_SIPTRANSPORT']._serialized_start=14497
+ _globals['_SIPTRANSPORT']._serialized_end=14604
+ _globals['_SIPHEADEROPTIONS']._serialized_start=14606
+ _globals['_SIPHEADEROPTIONS']._serialized_end=14684
+ _globals['_SIPMEDIAENCRYPTION']._serialized_start=14686
+ _globals['_SIPMEDIAENCRYPTION']._serialized_end=14797
+ _globals['_PROVIDERTYPE']._serialized_start=14799
+ _globals['_PROVIDERTYPE']._serialized_end=14896
+ _globals['_SIPCALLSTATUS']._serialized_start=14898
+ _globals['_SIPCALLSTATUS']._serialized_end=15017
+ _globals['_SIPTRANSFERSTATUS']._serialized_start=15019
+ _globals['_SIPTRANSFERSTATUS']._serialized_end=15118
+ _globals['_SIPFEATURE']._serialized_start=15120
+ _globals['_SIPFEATURE']._serialized_end=15161
+ _globals['_SIPCALLDIRECTION']._serialized_start=15163
+ _globals['_SIPCALLDIRECTION']._serialized_end=15233
+ _globals['_SIPSTATUS']._serialized_start=215
+ _globals['_SIPSTATUS']._serialized_end=280
+ _globals['_CREATESIPTRUNKREQUEST']._serialized_start=283
+ _globals['_CREATESIPTRUNKREQUEST']._serialized_end=644
+ _globals['_PROVIDERINFO']._serialized_start=646
+ _globals['_PROVIDERINFO']._serialized_end=749
+ _globals['_SIPTRUNKINFO']._serialized_start=752
+ _globals['_SIPTRUNKINFO']._serialized_end=1300
+ _globals['_SIPTRUNKINFO_TRUNKKIND']._serialized_start=1228
+ _globals['_SIPTRUNKINFO_TRUNKKIND']._serialized_end=1296
+ _globals['_CREATESIPINBOUNDTRUNKREQUEST']._serialized_start=1302
+ _globals['_CREATESIPINBOUNDTRUNKREQUEST']._serialized_end=1377
+ _globals['_UPDATESIPINBOUNDTRUNKREQUEST']._serialized_start=1380
+ _globals['_UPDATESIPINBOUNDTRUNKREQUEST']._serialized_end=1556
+ _globals['_SIPINBOUNDTRUNKINFO']._serialized_start=1559
+ _globals['_SIPINBOUNDTRUNKINFO']._serialized_end=2582
+ _globals['_SIPINBOUNDTRUNKINFO_HEADERSENTRY']._serialized_start=2416
+ _globals['_SIPINBOUNDTRUNKINFO_HEADERSENTRY']._serialized_end=2462
+ _globals['_SIPINBOUNDTRUNKINFO_HEADERSTOATTRIBUTESENTRY']._serialized_start=2464
+ _globals['_SIPINBOUNDTRUNKINFO_HEADERSTOATTRIBUTESENTRY']._serialized_end=2522
+ _globals['_SIPINBOUNDTRUNKINFO_ATTRIBUTESTOHEADERSENTRY']._serialized_start=2524
+ _globals['_SIPINBOUNDTRUNKINFO_ATTRIBUTESTOHEADERSENTRY']._serialized_end=2582
+ _globals['_SIPINBOUNDTRUNKUPDATE']._serialized_start=2585
+ _globals['_SIPINBOUNDTRUNKUPDATE']._serialized_end=3025
+ _globals['_CREATESIPOUTBOUNDTRUNKREQUEST']._serialized_start=3027
+ _globals['_CREATESIPOUTBOUNDTRUNKREQUEST']._serialized_end=3104
+ _globals['_UPDATESIPOUTBOUNDTRUNKREQUEST']._serialized_start=3107
+ _globals['_UPDATESIPOUTBOUNDTRUNKREQUEST']._serialized_end=3286
+ _globals['_SIPOUTBOUNDTRUNKINFO']._serialized_start=3289
+ _globals['_SIPOUTBOUNDTRUNKINFO']._serialized_end=4242
+ _globals['_SIPOUTBOUNDTRUNKINFO_HEADERSENTRY']._serialized_start=2416
+ _globals['_SIPOUTBOUNDTRUNKINFO_HEADERSENTRY']._serialized_end=2462
+ _globals['_SIPOUTBOUNDTRUNKINFO_HEADERSTOATTRIBUTESENTRY']._serialized_start=2464
+ _globals['_SIPOUTBOUNDTRUNKINFO_HEADERSTOATTRIBUTESENTRY']._serialized_end=2522
+ _globals['_SIPOUTBOUNDTRUNKINFO_ATTRIBUTESTOHEADERSENTRY']._serialized_start=2524
+ _globals['_SIPOUTBOUNDTRUNKINFO_ATTRIBUTESTOHEADERSENTRY']._serialized_end=2582
+ _globals['_SIPOUTBOUNDTRUNKUPDATE']._serialized_start=4245
+ _globals['_SIPOUTBOUNDTRUNKUPDATE']._serialized_end=4783
+ _globals['_GETSIPINBOUNDTRUNKREQUEST']._serialized_start=4785
+ _globals['_GETSIPINBOUNDTRUNKREQUEST']._serialized_end=4849
+ _globals['_GETSIPINBOUNDTRUNKRESPONSE']._serialized_start=4851
+ _globals['_GETSIPINBOUNDTRUNKRESPONSE']._serialized_end=4924
+ _globals['_GETSIPOUTBOUNDTRUNKREQUEST']._serialized_start=4926
+ _globals['_GETSIPOUTBOUNDTRUNKREQUEST']._serialized_end=4991
+ _globals['_GETSIPOUTBOUNDTRUNKRESPONSE']._serialized_start=4993
+ _globals['_GETSIPOUTBOUNDTRUNKRESPONSE']._serialized_end=5068
+ _globals['_LISTSIPTRUNKREQUEST']._serialized_start=5070
+ _globals['_LISTSIPTRUNKREQUEST']._serialized_end=5130
+ _globals['_LISTSIPTRUNKRESPONSE']._serialized_start=5132
+ _globals['_LISTSIPTRUNKRESPONSE']._serialized_end=5196
+ _globals['_LISTSIPINBOUNDTRUNKREQUEST']._serialized_start=5198
+ _globals['_LISTSIPINBOUNDTRUNKREQUEST']._serialized_end=5297
+ _globals['_LISTSIPINBOUNDTRUNKRESPONSE']._serialized_start=5299
+ _globals['_LISTSIPINBOUNDTRUNKRESPONSE']._serialized_end=5373
+ _globals['_LISTSIPOUTBOUNDTRUNKREQUEST']._serialized_start=5375
+ _globals['_LISTSIPOUTBOUNDTRUNKREQUEST']._serialized_end=5475
+ _globals['_LISTSIPOUTBOUNDTRUNKRESPONSE']._serialized_start=5477
+ _globals['_LISTSIPOUTBOUNDTRUNKRESPONSE']._serialized_end=5553
+ _globals['_DELETESIPTRUNKREQUEST']._serialized_start=5555
+ _globals['_DELETESIPTRUNKREQUEST']._serialized_end=5615
+ _globals['_SIPDISPATCHRULEDIRECT']._serialized_start=5617
+ _globals['_SIPDISPATCHRULEDIRECT']._serialized_end=5672
+ _globals['_SIPDISPATCHRULEINDIVIDUAL']._serialized_start=5674
+ _globals['_SIPDISPATCHRULEINDIVIDUAL']._serialized_end=5758
+ _globals['_SIPDISPATCHRULECALLEE']._serialized_start=5760
+ _globals['_SIPDISPATCHRULECALLEE']._serialized_end=5836
+ _globals['_SIPDISPATCHRULE']._serialized_start=5839
+ _globals['_SIPDISPATCHRULE']._serialized_end=6064
+ _globals['_CREATESIPDISPATCHRULEREQUEST']._serialized_start=6067
+ _globals['_CREATESIPDISPATCHRULEREQUEST']._serialized_end=6597
+ _globals['_CREATESIPDISPATCHRULEREQUEST_ATTRIBUTESENTRY']._serialized_start=6548
+ _globals['_CREATESIPDISPATCHRULEREQUEST_ATTRIBUTESENTRY']._serialized_end=6597
+ _globals['_UPDATESIPDISPATCHRULEREQUEST']._serialized_start=6600
+ _globals['_UPDATESIPDISPATCHRULEREQUEST']._serialized_end=6791
+ _globals['_SIPDISPATCHRULEINFO']._serialized_start=6794
+ _globals['_SIPDISPATCHRULEINFO']._serialized_end=7464
+ _globals['_SIPDISPATCHRULEINFO_ATTRIBUTESENTRY']._serialized_start=6548
+ _globals['_SIPDISPATCHRULEINFO_ATTRIBUTESENTRY']._serialized_end=6597
+ _globals['_SIPDISPATCHRULEUPDATE']._serialized_start=7467
+ _globals['_SIPDISPATCHRULEUPDATE']._serialized_end=7910
+ _globals['_SIPDISPATCHRULEUPDATE_ATTRIBUTESENTRY']._serialized_start=6548
+ _globals['_SIPDISPATCHRULEUPDATE_ATTRIBUTESENTRY']._serialized_end=6597
+ _globals['_LISTSIPDISPATCHRULEREQUEST']._serialized_start=7912
+ _globals['_LISTSIPDISPATCHRULEREQUEST']._serialized_end=8021
+ _globals['_LISTSIPDISPATCHRULERESPONSE']._serialized_start=8023
+ _globals['_LISTSIPDISPATCHRULERESPONSE']._serialized_end=8097
+ _globals['_DELETESIPDISPATCHRULEREQUEST']._serialized_start=8099
+ _globals['_DELETESIPDISPATCHRULEREQUEST']._serialized_end=8181
+ _globals['_SIPOUTBOUNDCONFIG']._serialized_start=8184
+ _globals['_SIPOUTBOUNDCONFIG']._serialized_end=8655
+ _globals['_SIPOUTBOUNDCONFIG_HEADERSTOATTRIBUTESENTRY']._serialized_start=2464
+ _globals['_SIPOUTBOUNDCONFIG_HEADERSTOATTRIBUTESENTRY']._serialized_end=2522
+ _globals['_SIPOUTBOUNDCONFIG_ATTRIBUTESTOHEADERSENTRY']._serialized_start=2524
+ _globals['_SIPOUTBOUNDCONFIG_ATTRIBUTESTOHEADERSENTRY']._serialized_end=2582
+ _globals['_CREATESIPPARTICIPANTREQUEST']._serialized_start=8658
+ _globals['_CREATESIPPARTICIPANTREQUEST']._serialized_end=9843
+ _globals['_CREATESIPPARTICIPANTREQUEST_PARTICIPANTATTRIBUTESENTRY']._serialized_start=9702
+ _globals['_CREATESIPPARTICIPANTREQUEST_PARTICIPANTATTRIBUTESENTRY']._serialized_end=9762
+ _globals['_CREATESIPPARTICIPANTREQUEST_HEADERSENTRY']._serialized_start=2416
+ _globals['_CREATESIPPARTICIPANTREQUEST_HEADERSENTRY']._serialized_end=2462
+ _globals['_SIPPARTICIPANTINFO']._serialized_start=9846
+ _globals['_SIPPARTICIPANTINFO']._serialized_end=9992
+ _globals['_TRANSFERSIPPARTICIPANTREQUEST']._serialized_start=9995
+ _globals['_TRANSFERSIPPARTICIPANTREQUEST']._serialized_end=10327
+ _globals['_TRANSFERSIPPARTICIPANTREQUEST_HEADERSENTRY']._serialized_start=2416
+ _globals['_TRANSFERSIPPARTICIPANTREQUEST_HEADERSENTRY']._serialized_end=2462
+ _globals['_SIPCALLINFO']._serialized_start=10330
+ _globals['_SIPCALLINFO']._serialized_end=11379
+ _globals['_SIPCALLINFO_PARTICIPANTATTRIBUTESENTRY']._serialized_start=9702
+ _globals['_SIPCALLINFO_PARTICIPANTATTRIBUTESENTRY']._serialized_end=9762
+ _globals['_SIPTRANSFERINFO']._serialized_start=11382
+ _globals['_SIPTRANSFERINFO']._serialized_end=11670
+ _globals['_SIPURI']._serialized_start=11672
+ _globals['_SIPURI']._serialized_end=11776
+ _globals['_DESTINATION']._serialized_start=11778
+ _globals['_DESTINATION']._serialized_end=11838
+ _globals['_SIP']._serialized_start=15236
+ _globals['_SIP']._serialized_end=16731
# @@protoc_insertion_point(module_scope)
diff --git a/livekit-protocol/livekit/protocol/sip.pyi b/livekit-protocol/livekit/protocol/sip.pyi
index 770b8e30..58da739b 100644
--- a/livekit-protocol/livekit/protocol/sip.pyi
+++ b/livekit-protocol/livekit/protocol/sip.pyi
@@ -1,3 +1,10 @@
+from google.protobuf import any_pb2 as _any_pb2
+from google.protobuf import duration_pb2 as _duration_pb2
+from google.protobuf import empty_pb2 as _empty_pb2
+from google.protobuf import timestamp_pb2 as _timestamp_pb2
+from . import models as _models
+from . import room as _room
+from .logger_pb import options as _options_pb2
from google.protobuf.internal import containers as _containers
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
from google.protobuf import descriptor as _descriptor
@@ -6,16 +13,244 @@ from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Map
DESCRIPTOR: _descriptor.FileDescriptor
+class SIPStatusCode(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ SIP_STATUS_UNKNOWN: _ClassVar[SIPStatusCode]
+ SIP_STATUS_TRYING: _ClassVar[SIPStatusCode]
+ SIP_STATUS_RINGING: _ClassVar[SIPStatusCode]
+ SIP_STATUS_CALL_IS_FORWARDED: _ClassVar[SIPStatusCode]
+ SIP_STATUS_QUEUED: _ClassVar[SIPStatusCode]
+ SIP_STATUS_SESSION_PROGRESS: _ClassVar[SIPStatusCode]
+ SIP_STATUS_EARLY_DIALOG_TERMINATED: _ClassVar[SIPStatusCode]
+ SIP_STATUS_OK: _ClassVar[SIPStatusCode]
+ SIP_STATUS_ACCEPTED: _ClassVar[SIPStatusCode]
+ SIP_STATUS_NO_NOTIFICATION: _ClassVar[SIPStatusCode]
+ SIP_STATUS_MULTIPLE_CHOICES: _ClassVar[SIPStatusCode]
+ SIP_STATUS_MOVED_PERMANENTLY: _ClassVar[SIPStatusCode]
+ SIP_STATUS_MOVED_TEMPORARILY: _ClassVar[SIPStatusCode]
+ SIP_STATUS_USE_PROXY: _ClassVar[SIPStatusCode]
+ SIP_STATUS_ALTERNATIVE_SERVICE: _ClassVar[SIPStatusCode]
+ SIP_STATUS_BAD_REQUEST: _ClassVar[SIPStatusCode]
+ SIP_STATUS_UNAUTHORIZED: _ClassVar[SIPStatusCode]
+ SIP_STATUS_PAYMENT_REQUIRED: _ClassVar[SIPStatusCode]
+ SIP_STATUS_FORBIDDEN: _ClassVar[SIPStatusCode]
+ SIP_STATUS_NOTFOUND: _ClassVar[SIPStatusCode]
+ SIP_STATUS_METHOD_NOT_ALLOWED: _ClassVar[SIPStatusCode]
+ SIP_STATUS_NOT_ACCEPTABLE: _ClassVar[SIPStatusCode]
+ SIP_STATUS_PROXY_AUTH_REQUIRED: _ClassVar[SIPStatusCode]
+ SIP_STATUS_REQUEST_TIMEOUT: _ClassVar[SIPStatusCode]
+ SIP_STATUS_CONFLICT: _ClassVar[SIPStatusCode]
+ SIP_STATUS_GONE: _ClassVar[SIPStatusCode]
+ SIP_STATUS_LENGTH_REQUIRED: _ClassVar[SIPStatusCode]
+ SIP_STATUS_CONDITIONAL_REQUEST_FAILED: _ClassVar[SIPStatusCode]
+ SIP_STATUS_REQUEST_ENTITY_TOO_LARGE: _ClassVar[SIPStatusCode]
+ SIP_STATUS_REQUEST_URI_TOO_LONG: _ClassVar[SIPStatusCode]
+ SIP_STATUS_UNSUPPORTED_MEDIA_TYPE: _ClassVar[SIPStatusCode]
+ SIP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE: _ClassVar[SIPStatusCode]
+ SIP_STATUS_UNKNOWN_RESOURCE_PRIORITY: _ClassVar[SIPStatusCode]
+ SIP_STATUS_BAD_EXTENSION: _ClassVar[SIPStatusCode]
+ SIP_STATUS_EXTENSION_REQUIRED: _ClassVar[SIPStatusCode]
+ SIP_STATUS_SESSION_INTERVAL_TOO_SMALL: _ClassVar[SIPStatusCode]
+ SIP_STATUS_INTERVAL_TOO_BRIEF: _ClassVar[SIPStatusCode]
+ SIP_STATUS_BAD_LOCATION_INFORMATION: _ClassVar[SIPStatusCode]
+ SIP_STATUS_BAD_ALERT_MESSAGE: _ClassVar[SIPStatusCode]
+ SIP_STATUS_USE_IDENTITY_HEADER: _ClassVar[SIPStatusCode]
+ SIP_STATUS_PROVIDE_REFERRER_IDENTITY: _ClassVar[SIPStatusCode]
+ SIP_STATUS_FLOW_FAILED: _ClassVar[SIPStatusCode]
+ SIP_STATUS_ANONYMITY_DISALLOWED: _ClassVar[SIPStatusCode]
+ SIP_STATUS_BAD_IDENTITY_INFO: _ClassVar[SIPStatusCode]
+ SIP_STATUS_UNSUPPORTED_CERTIFICATE: _ClassVar[SIPStatusCode]
+ SIP_STATUS_INVALID_IDENTITY_HEADER: _ClassVar[SIPStatusCode]
+ SIP_STATUS_FIRST_HOP_LACKS_OUTBOUND_SUPPORT: _ClassVar[SIPStatusCode]
+ SIP_STATUS_MAX_BREADTH_EXCEEDED: _ClassVar[SIPStatusCode]
+ SIP_STATUS_BAD_INFO_PACKAGE: _ClassVar[SIPStatusCode]
+ SIP_STATUS_CONSENT_NEEDED: _ClassVar[SIPStatusCode]
+ SIP_STATUS_TEMPORARILY_UNAVAILABLE: _ClassVar[SIPStatusCode]
+ SIP_STATUS_CALL_TRANSACTION_DOES_NOT_EXISTS: _ClassVar[SIPStatusCode]
+ SIP_STATUS_LOOP_DETECTED: _ClassVar[SIPStatusCode]
+ SIP_STATUS_TOO_MANY_HOPS: _ClassVar[SIPStatusCode]
+ SIP_STATUS_ADDRESS_INCOMPLETE: _ClassVar[SIPStatusCode]
+ SIP_STATUS_AMBIGUOUS: _ClassVar[SIPStatusCode]
+ SIP_STATUS_BUSY_HERE: _ClassVar[SIPStatusCode]
+ SIP_STATUS_REQUEST_TERMINATED: _ClassVar[SIPStatusCode]
+ SIP_STATUS_NOT_ACCEPTABLE_HERE: _ClassVar[SIPStatusCode]
+ SIP_STATUS_BAD_EVENT: _ClassVar[SIPStatusCode]
+ SIP_STATUS_REQUEST_PENDING: _ClassVar[SIPStatusCode]
+ SIP_STATUS_UNDECIPHERABLE: _ClassVar[SIPStatusCode]
+ SIP_STATUS_SECURITY_AGREEMENT_REQUIRED: _ClassVar[SIPStatusCode]
+ SIP_STATUS_INTERNAL_SERVER_ERROR: _ClassVar[SIPStatusCode]
+ SIP_STATUS_NOT_IMPLEMENTED: _ClassVar[SIPStatusCode]
+ SIP_STATUS_BAD_GATEWAY: _ClassVar[SIPStatusCode]
+ SIP_STATUS_SERVICE_UNAVAILABLE: _ClassVar[SIPStatusCode]
+ SIP_STATUS_GATEWAY_TIMEOUT: _ClassVar[SIPStatusCode]
+ SIP_STATUS_VERSION_NOT_SUPPORTED: _ClassVar[SIPStatusCode]
+ SIP_STATUS_MESSAGE_TOO_LARGE: _ClassVar[SIPStatusCode]
+ SIP_STATUS_GLOBAL_BUSY_EVERYWHERE: _ClassVar[SIPStatusCode]
+ SIP_STATUS_GLOBAL_DECLINE: _ClassVar[SIPStatusCode]
+ SIP_STATUS_GLOBAL_DOES_NOT_EXIST_ANYWHERE: _ClassVar[SIPStatusCode]
+ SIP_STATUS_GLOBAL_NOT_ACCEPTABLE: _ClassVar[SIPStatusCode]
+ SIP_STATUS_GLOBAL_UNWANTED: _ClassVar[SIPStatusCode]
+ SIP_STATUS_GLOBAL_REJECTED: _ClassVar[SIPStatusCode]
+
class SIPTransport(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
SIP_TRANSPORT_AUTO: _ClassVar[SIPTransport]
SIP_TRANSPORT_UDP: _ClassVar[SIPTransport]
SIP_TRANSPORT_TCP: _ClassVar[SIPTransport]
SIP_TRANSPORT_TLS: _ClassVar[SIPTransport]
+
+class SIPHeaderOptions(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ SIP_NO_HEADERS: _ClassVar[SIPHeaderOptions]
+ SIP_X_HEADERS: _ClassVar[SIPHeaderOptions]
+ SIP_ALL_HEADERS: _ClassVar[SIPHeaderOptions]
+
+class SIPMediaEncryption(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ SIP_MEDIA_ENCRYPT_DISABLE: _ClassVar[SIPMediaEncryption]
+ SIP_MEDIA_ENCRYPT_ALLOW: _ClassVar[SIPMediaEncryption]
+ SIP_MEDIA_ENCRYPT_REQUIRE: _ClassVar[SIPMediaEncryption]
+
+class ProviderType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ PROVIDER_TYPE_UNKNOWN: _ClassVar[ProviderType]
+ PROVIDER_TYPE_INTERNAL: _ClassVar[ProviderType]
+ PROVIDER_TYPE_EXTERNAL: _ClassVar[ProviderType]
+
+class SIPCallStatus(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ SCS_CALL_INCOMING: _ClassVar[SIPCallStatus]
+ SCS_PARTICIPANT_JOINED: _ClassVar[SIPCallStatus]
+ SCS_ACTIVE: _ClassVar[SIPCallStatus]
+ SCS_DISCONNECTED: _ClassVar[SIPCallStatus]
+ SCS_ERROR: _ClassVar[SIPCallStatus]
+
+class SIPTransferStatus(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ STS_TRANSFER_ONGOING: _ClassVar[SIPTransferStatus]
+ STS_TRANSFER_FAILED: _ClassVar[SIPTransferStatus]
+ STS_TRANSFER_SUCCESSFUL: _ClassVar[SIPTransferStatus]
+
+class SIPFeature(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ NONE: _ClassVar[SIPFeature]
+ KRISP_ENABLED: _ClassVar[SIPFeature]
+
+class SIPCallDirection(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+ __slots__ = ()
+ SCD_UNKNOWN: _ClassVar[SIPCallDirection]
+ SCD_INBOUND: _ClassVar[SIPCallDirection]
+ SCD_OUTBOUND: _ClassVar[SIPCallDirection]
+SIP_STATUS_UNKNOWN: SIPStatusCode
+SIP_STATUS_TRYING: SIPStatusCode
+SIP_STATUS_RINGING: SIPStatusCode
+SIP_STATUS_CALL_IS_FORWARDED: SIPStatusCode
+SIP_STATUS_QUEUED: SIPStatusCode
+SIP_STATUS_SESSION_PROGRESS: SIPStatusCode
+SIP_STATUS_EARLY_DIALOG_TERMINATED: SIPStatusCode
+SIP_STATUS_OK: SIPStatusCode
+SIP_STATUS_ACCEPTED: SIPStatusCode
+SIP_STATUS_NO_NOTIFICATION: SIPStatusCode
+SIP_STATUS_MULTIPLE_CHOICES: SIPStatusCode
+SIP_STATUS_MOVED_PERMANENTLY: SIPStatusCode
+SIP_STATUS_MOVED_TEMPORARILY: SIPStatusCode
+SIP_STATUS_USE_PROXY: SIPStatusCode
+SIP_STATUS_ALTERNATIVE_SERVICE: SIPStatusCode
+SIP_STATUS_BAD_REQUEST: SIPStatusCode
+SIP_STATUS_UNAUTHORIZED: SIPStatusCode
+SIP_STATUS_PAYMENT_REQUIRED: SIPStatusCode
+SIP_STATUS_FORBIDDEN: SIPStatusCode
+SIP_STATUS_NOTFOUND: SIPStatusCode
+SIP_STATUS_METHOD_NOT_ALLOWED: SIPStatusCode
+SIP_STATUS_NOT_ACCEPTABLE: SIPStatusCode
+SIP_STATUS_PROXY_AUTH_REQUIRED: SIPStatusCode
+SIP_STATUS_REQUEST_TIMEOUT: SIPStatusCode
+SIP_STATUS_CONFLICT: SIPStatusCode
+SIP_STATUS_GONE: SIPStatusCode
+SIP_STATUS_LENGTH_REQUIRED: SIPStatusCode
+SIP_STATUS_CONDITIONAL_REQUEST_FAILED: SIPStatusCode
+SIP_STATUS_REQUEST_ENTITY_TOO_LARGE: SIPStatusCode
+SIP_STATUS_REQUEST_URI_TOO_LONG: SIPStatusCode
+SIP_STATUS_UNSUPPORTED_MEDIA_TYPE: SIPStatusCode
+SIP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE: SIPStatusCode
+SIP_STATUS_UNKNOWN_RESOURCE_PRIORITY: SIPStatusCode
+SIP_STATUS_BAD_EXTENSION: SIPStatusCode
+SIP_STATUS_EXTENSION_REQUIRED: SIPStatusCode
+SIP_STATUS_SESSION_INTERVAL_TOO_SMALL: SIPStatusCode
+SIP_STATUS_INTERVAL_TOO_BRIEF: SIPStatusCode
+SIP_STATUS_BAD_LOCATION_INFORMATION: SIPStatusCode
+SIP_STATUS_BAD_ALERT_MESSAGE: SIPStatusCode
+SIP_STATUS_USE_IDENTITY_HEADER: SIPStatusCode
+SIP_STATUS_PROVIDE_REFERRER_IDENTITY: SIPStatusCode
+SIP_STATUS_FLOW_FAILED: SIPStatusCode
+SIP_STATUS_ANONYMITY_DISALLOWED: SIPStatusCode
+SIP_STATUS_BAD_IDENTITY_INFO: SIPStatusCode
+SIP_STATUS_UNSUPPORTED_CERTIFICATE: SIPStatusCode
+SIP_STATUS_INVALID_IDENTITY_HEADER: SIPStatusCode
+SIP_STATUS_FIRST_HOP_LACKS_OUTBOUND_SUPPORT: SIPStatusCode
+SIP_STATUS_MAX_BREADTH_EXCEEDED: SIPStatusCode
+SIP_STATUS_BAD_INFO_PACKAGE: SIPStatusCode
+SIP_STATUS_CONSENT_NEEDED: SIPStatusCode
+SIP_STATUS_TEMPORARILY_UNAVAILABLE: SIPStatusCode
+SIP_STATUS_CALL_TRANSACTION_DOES_NOT_EXISTS: SIPStatusCode
+SIP_STATUS_LOOP_DETECTED: SIPStatusCode
+SIP_STATUS_TOO_MANY_HOPS: SIPStatusCode
+SIP_STATUS_ADDRESS_INCOMPLETE: SIPStatusCode
+SIP_STATUS_AMBIGUOUS: SIPStatusCode
+SIP_STATUS_BUSY_HERE: SIPStatusCode
+SIP_STATUS_REQUEST_TERMINATED: SIPStatusCode
+SIP_STATUS_NOT_ACCEPTABLE_HERE: SIPStatusCode
+SIP_STATUS_BAD_EVENT: SIPStatusCode
+SIP_STATUS_REQUEST_PENDING: SIPStatusCode
+SIP_STATUS_UNDECIPHERABLE: SIPStatusCode
+SIP_STATUS_SECURITY_AGREEMENT_REQUIRED: SIPStatusCode
+SIP_STATUS_INTERNAL_SERVER_ERROR: SIPStatusCode
+SIP_STATUS_NOT_IMPLEMENTED: SIPStatusCode
+SIP_STATUS_BAD_GATEWAY: SIPStatusCode
+SIP_STATUS_SERVICE_UNAVAILABLE: SIPStatusCode
+SIP_STATUS_GATEWAY_TIMEOUT: SIPStatusCode
+SIP_STATUS_VERSION_NOT_SUPPORTED: SIPStatusCode
+SIP_STATUS_MESSAGE_TOO_LARGE: SIPStatusCode
+SIP_STATUS_GLOBAL_BUSY_EVERYWHERE: SIPStatusCode
+SIP_STATUS_GLOBAL_DECLINE: SIPStatusCode
+SIP_STATUS_GLOBAL_DOES_NOT_EXIST_ANYWHERE: SIPStatusCode
+SIP_STATUS_GLOBAL_NOT_ACCEPTABLE: SIPStatusCode
+SIP_STATUS_GLOBAL_UNWANTED: SIPStatusCode
+SIP_STATUS_GLOBAL_REJECTED: SIPStatusCode
SIP_TRANSPORT_AUTO: SIPTransport
SIP_TRANSPORT_UDP: SIPTransport
SIP_TRANSPORT_TCP: SIPTransport
SIP_TRANSPORT_TLS: SIPTransport
+SIP_NO_HEADERS: SIPHeaderOptions
+SIP_X_HEADERS: SIPHeaderOptions
+SIP_ALL_HEADERS: SIPHeaderOptions
+SIP_MEDIA_ENCRYPT_DISABLE: SIPMediaEncryption
+SIP_MEDIA_ENCRYPT_ALLOW: SIPMediaEncryption
+SIP_MEDIA_ENCRYPT_REQUIRE: SIPMediaEncryption
+PROVIDER_TYPE_UNKNOWN: ProviderType
+PROVIDER_TYPE_INTERNAL: ProviderType
+PROVIDER_TYPE_EXTERNAL: ProviderType
+SCS_CALL_INCOMING: SIPCallStatus
+SCS_PARTICIPANT_JOINED: SIPCallStatus
+SCS_ACTIVE: SIPCallStatus
+SCS_DISCONNECTED: SIPCallStatus
+SCS_ERROR: SIPCallStatus
+STS_TRANSFER_ONGOING: SIPTransferStatus
+STS_TRANSFER_FAILED: SIPTransferStatus
+STS_TRANSFER_SUCCESSFUL: SIPTransferStatus
+NONE: SIPFeature
+KRISP_ENABLED: SIPFeature
+SCD_UNKNOWN: SIPCallDirection
+SCD_INBOUND: SIPCallDirection
+SCD_OUTBOUND: SIPCallDirection
+
+class SIPStatus(_message.Message):
+ __slots__ = ("code", "status")
+ CODE_FIELD_NUMBER: _ClassVar[int]
+ STATUS_FIELD_NUMBER: _ClassVar[int]
+ code: SIPStatusCode
+ status: str
+ def __init__(self, code: _Optional[_Union[SIPStatusCode, str]] = ..., status: _Optional[str] = ...) -> None: ...
class CreateSIPTrunkRequest(_message.Message):
__slots__ = ("inbound_addresses", "outbound_address", "outbound_number", "inbound_numbers_regex", "inbound_numbers", "inbound_username", "inbound_password", "outbound_username", "outbound_password", "name", "metadata")
@@ -43,6 +278,18 @@ class CreateSIPTrunkRequest(_message.Message):
metadata: str
def __init__(self, inbound_addresses: _Optional[_Iterable[str]] = ..., outbound_address: _Optional[str] = ..., outbound_number: _Optional[str] = ..., inbound_numbers_regex: _Optional[_Iterable[str]] = ..., inbound_numbers: _Optional[_Iterable[str]] = ..., inbound_username: _Optional[str] = ..., inbound_password: _Optional[str] = ..., outbound_username: _Optional[str] = ..., outbound_password: _Optional[str] = ..., name: _Optional[str] = ..., metadata: _Optional[str] = ...) -> None: ...
+class ProviderInfo(_message.Message):
+ __slots__ = ("id", "name", "type", "prevent_transfer")
+ ID_FIELD_NUMBER: _ClassVar[int]
+ NAME_FIELD_NUMBER: _ClassVar[int]
+ TYPE_FIELD_NUMBER: _ClassVar[int]
+ PREVENT_TRANSFER_FIELD_NUMBER: _ClassVar[int]
+ id: str
+ name: str
+ type: ProviderType
+ prevent_transfer: bool
+ def __init__(self, id: _Optional[str] = ..., name: _Optional[str] = ..., type: _Optional[_Union[ProviderType, str]] = ..., prevent_transfer: bool = ...) -> None: ...
+
class SIPTrunkInfo(_message.Message):
__slots__ = ("sip_trunk_id", "kind", "inbound_addresses", "outbound_address", "outbound_number", "transport", "inbound_numbers_regex", "inbound_numbers", "inbound_username", "inbound_password", "outbound_username", "outbound_password", "name", "metadata")
class TrunkKind(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
@@ -89,8 +336,39 @@ class CreateSIPInboundTrunkRequest(_message.Message):
trunk: SIPInboundTrunkInfo
def __init__(self, trunk: _Optional[_Union[SIPInboundTrunkInfo, _Mapping]] = ...) -> None: ...
+class UpdateSIPInboundTrunkRequest(_message.Message):
+ __slots__ = ("sip_trunk_id", "replace", "update")
+ SIP_TRUNK_ID_FIELD_NUMBER: _ClassVar[int]
+ REPLACE_FIELD_NUMBER: _ClassVar[int]
+ UPDATE_FIELD_NUMBER: _ClassVar[int]
+ sip_trunk_id: str
+ replace: SIPInboundTrunkInfo
+ update: SIPInboundTrunkUpdate
+ def __init__(self, sip_trunk_id: _Optional[str] = ..., replace: _Optional[_Union[SIPInboundTrunkInfo, _Mapping]] = ..., update: _Optional[_Union[SIPInboundTrunkUpdate, _Mapping]] = ...) -> None: ...
+
class SIPInboundTrunkInfo(_message.Message):
- __slots__ = ("sip_trunk_id", "name", "metadata", "numbers", "allowed_addresses", "allowed_numbers", "auth_username", "auth_password")
+ __slots__ = ("sip_trunk_id", "name", "metadata", "numbers", "allowed_addresses", "allowed_numbers", "auth_username", "auth_password", "headers", "headers_to_attributes", "attributes_to_headers", "include_headers", "ringing_timeout", "max_call_duration", "krisp_enabled", "media_encryption", "created_at", "updated_at")
+ class HeadersEntry(_message.Message):
+ __slots__ = ("key", "value")
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: str
+ value: str
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
+ class HeadersToAttributesEntry(_message.Message):
+ __slots__ = ("key", "value")
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: str
+ value: str
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
+ class AttributesToHeadersEntry(_message.Message):
+ __slots__ = ("key", "value")
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: str
+ value: str
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
SIP_TRUNK_ID_FIELD_NUMBER: _ClassVar[int]
NAME_FIELD_NUMBER: _ClassVar[int]
METADATA_FIELD_NUMBER: _ClassVar[int]
@@ -99,6 +377,16 @@ class SIPInboundTrunkInfo(_message.Message):
ALLOWED_NUMBERS_FIELD_NUMBER: _ClassVar[int]
AUTH_USERNAME_FIELD_NUMBER: _ClassVar[int]
AUTH_PASSWORD_FIELD_NUMBER: _ClassVar[int]
+ HEADERS_FIELD_NUMBER: _ClassVar[int]
+ HEADERS_TO_ATTRIBUTES_FIELD_NUMBER: _ClassVar[int]
+ ATTRIBUTES_TO_HEADERS_FIELD_NUMBER: _ClassVar[int]
+ INCLUDE_HEADERS_FIELD_NUMBER: _ClassVar[int]
+ RINGING_TIMEOUT_FIELD_NUMBER: _ClassVar[int]
+ MAX_CALL_DURATION_FIELD_NUMBER: _ClassVar[int]
+ KRISP_ENABLED_FIELD_NUMBER: _ClassVar[int]
+ MEDIA_ENCRYPTION_FIELD_NUMBER: _ClassVar[int]
+ CREATED_AT_FIELD_NUMBER: _ClassVar[int]
+ UPDATED_AT_FIELD_NUMBER: _ClassVar[int]
sip_trunk_id: str
name: str
metadata: str
@@ -107,7 +395,37 @@ class SIPInboundTrunkInfo(_message.Message):
allowed_numbers: _containers.RepeatedScalarFieldContainer[str]
auth_username: str
auth_password: str
- def __init__(self, sip_trunk_id: _Optional[str] = ..., name: _Optional[str] = ..., metadata: _Optional[str] = ..., numbers: _Optional[_Iterable[str]] = ..., allowed_addresses: _Optional[_Iterable[str]] = ..., allowed_numbers: _Optional[_Iterable[str]] = ..., auth_username: _Optional[str] = ..., auth_password: _Optional[str] = ...) -> None: ...
+ headers: _containers.ScalarMap[str, str]
+ headers_to_attributes: _containers.ScalarMap[str, str]
+ attributes_to_headers: _containers.ScalarMap[str, str]
+ include_headers: SIPHeaderOptions
+ ringing_timeout: _duration_pb2.Duration
+ max_call_duration: _duration_pb2.Duration
+ krisp_enabled: bool
+ media_encryption: SIPMediaEncryption
+ created_at: _timestamp_pb2.Timestamp
+ updated_at: _timestamp_pb2.Timestamp
+ def __init__(self, sip_trunk_id: _Optional[str] = ..., name: _Optional[str] = ..., metadata: _Optional[str] = ..., numbers: _Optional[_Iterable[str]] = ..., allowed_addresses: _Optional[_Iterable[str]] = ..., allowed_numbers: _Optional[_Iterable[str]] = ..., auth_username: _Optional[str] = ..., auth_password: _Optional[str] = ..., headers: _Optional[_Mapping[str, str]] = ..., headers_to_attributes: _Optional[_Mapping[str, str]] = ..., attributes_to_headers: _Optional[_Mapping[str, str]] = ..., include_headers: _Optional[_Union[SIPHeaderOptions, str]] = ..., ringing_timeout: _Optional[_Union[_duration_pb2.Duration, _Mapping]] = ..., max_call_duration: _Optional[_Union[_duration_pb2.Duration, _Mapping]] = ..., krisp_enabled: bool = ..., media_encryption: _Optional[_Union[SIPMediaEncryption, str]] = ..., created_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., updated_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ...) -> None: ...
+
+class SIPInboundTrunkUpdate(_message.Message):
+ __slots__ = ("numbers", "allowed_addresses", "allowed_numbers", "auth_username", "auth_password", "name", "metadata", "media_encryption")
+ NUMBERS_FIELD_NUMBER: _ClassVar[int]
+ ALLOWED_ADDRESSES_FIELD_NUMBER: _ClassVar[int]
+ ALLOWED_NUMBERS_FIELD_NUMBER: _ClassVar[int]
+ AUTH_USERNAME_FIELD_NUMBER: _ClassVar[int]
+ AUTH_PASSWORD_FIELD_NUMBER: _ClassVar[int]
+ NAME_FIELD_NUMBER: _ClassVar[int]
+ METADATA_FIELD_NUMBER: _ClassVar[int]
+ MEDIA_ENCRYPTION_FIELD_NUMBER: _ClassVar[int]
+ numbers: _models.ListUpdate
+ allowed_addresses: _models.ListUpdate
+ allowed_numbers: _models.ListUpdate
+ auth_username: str
+ auth_password: str
+ name: str
+ metadata: str
+ media_encryption: SIPMediaEncryption
+ def __init__(self, numbers: _Optional[_Union[_models.ListUpdate, _Mapping]] = ..., allowed_addresses: _Optional[_Union[_models.ListUpdate, _Mapping]] = ..., allowed_numbers: _Optional[_Union[_models.ListUpdate, _Mapping]] = ..., auth_username: _Optional[str] = ..., auth_password: _Optional[str] = ..., name: _Optional[str] = ..., metadata: _Optional[str] = ..., media_encryption: _Optional[_Union[SIPMediaEncryption, str]] = ...) -> None: ...
class CreateSIPOutboundTrunkRequest(_message.Message):
__slots__ = ("trunk",)
@@ -115,29 +433,128 @@ class CreateSIPOutboundTrunkRequest(_message.Message):
trunk: SIPOutboundTrunkInfo
def __init__(self, trunk: _Optional[_Union[SIPOutboundTrunkInfo, _Mapping]] = ...) -> None: ...
+class UpdateSIPOutboundTrunkRequest(_message.Message):
+ __slots__ = ("sip_trunk_id", "replace", "update")
+ SIP_TRUNK_ID_FIELD_NUMBER: _ClassVar[int]
+ REPLACE_FIELD_NUMBER: _ClassVar[int]
+ UPDATE_FIELD_NUMBER: _ClassVar[int]
+ sip_trunk_id: str
+ replace: SIPOutboundTrunkInfo
+ update: SIPOutboundTrunkUpdate
+ def __init__(self, sip_trunk_id: _Optional[str] = ..., replace: _Optional[_Union[SIPOutboundTrunkInfo, _Mapping]] = ..., update: _Optional[_Union[SIPOutboundTrunkUpdate, _Mapping]] = ...) -> None: ...
+
class SIPOutboundTrunkInfo(_message.Message):
- __slots__ = ("sip_trunk_id", "name", "metadata", "address", "transport", "numbers", "auth_username", "auth_password")
+ __slots__ = ("sip_trunk_id", "name", "metadata", "address", "destination_country", "transport", "numbers", "auth_username", "auth_password", "headers", "headers_to_attributes", "attributes_to_headers", "include_headers", "media_encryption", "from_host", "created_at", "updated_at")
+ class HeadersEntry(_message.Message):
+ __slots__ = ("key", "value")
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: str
+ value: str
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
+ class HeadersToAttributesEntry(_message.Message):
+ __slots__ = ("key", "value")
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: str
+ value: str
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
+ class AttributesToHeadersEntry(_message.Message):
+ __slots__ = ("key", "value")
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: str
+ value: str
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
SIP_TRUNK_ID_FIELD_NUMBER: _ClassVar[int]
NAME_FIELD_NUMBER: _ClassVar[int]
METADATA_FIELD_NUMBER: _ClassVar[int]
ADDRESS_FIELD_NUMBER: _ClassVar[int]
+ DESTINATION_COUNTRY_FIELD_NUMBER: _ClassVar[int]
TRANSPORT_FIELD_NUMBER: _ClassVar[int]
NUMBERS_FIELD_NUMBER: _ClassVar[int]
AUTH_USERNAME_FIELD_NUMBER: _ClassVar[int]
AUTH_PASSWORD_FIELD_NUMBER: _ClassVar[int]
+ HEADERS_FIELD_NUMBER: _ClassVar[int]
+ HEADERS_TO_ATTRIBUTES_FIELD_NUMBER: _ClassVar[int]
+ ATTRIBUTES_TO_HEADERS_FIELD_NUMBER: _ClassVar[int]
+ INCLUDE_HEADERS_FIELD_NUMBER: _ClassVar[int]
+ MEDIA_ENCRYPTION_FIELD_NUMBER: _ClassVar[int]
+ FROM_HOST_FIELD_NUMBER: _ClassVar[int]
+ CREATED_AT_FIELD_NUMBER: _ClassVar[int]
+ UPDATED_AT_FIELD_NUMBER: _ClassVar[int]
sip_trunk_id: str
name: str
metadata: str
address: str
+ destination_country: str
transport: SIPTransport
numbers: _containers.RepeatedScalarFieldContainer[str]
auth_username: str
auth_password: str
- def __init__(self, sip_trunk_id: _Optional[str] = ..., name: _Optional[str] = ..., metadata: _Optional[str] = ..., address: _Optional[str] = ..., transport: _Optional[_Union[SIPTransport, str]] = ..., numbers: _Optional[_Iterable[str]] = ..., auth_username: _Optional[str] = ..., auth_password: _Optional[str] = ...) -> None: ...
+ headers: _containers.ScalarMap[str, str]
+ headers_to_attributes: _containers.ScalarMap[str, str]
+ attributes_to_headers: _containers.ScalarMap[str, str]
+ include_headers: SIPHeaderOptions
+ media_encryption: SIPMediaEncryption
+ from_host: str
+ created_at: _timestamp_pb2.Timestamp
+ updated_at: _timestamp_pb2.Timestamp
+ def __init__(self, sip_trunk_id: _Optional[str] = ..., name: _Optional[str] = ..., metadata: _Optional[str] = ..., address: _Optional[str] = ..., destination_country: _Optional[str] = ..., transport: _Optional[_Union[SIPTransport, str]] = ..., numbers: _Optional[_Iterable[str]] = ..., auth_username: _Optional[str] = ..., auth_password: _Optional[str] = ..., headers: _Optional[_Mapping[str, str]] = ..., headers_to_attributes: _Optional[_Mapping[str, str]] = ..., attributes_to_headers: _Optional[_Mapping[str, str]] = ..., include_headers: _Optional[_Union[SIPHeaderOptions, str]] = ..., media_encryption: _Optional[_Union[SIPMediaEncryption, str]] = ..., from_host: _Optional[str] = ..., created_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., updated_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ...) -> None: ...
+
+class SIPOutboundTrunkUpdate(_message.Message):
+ __slots__ = ("address", "transport", "destination_country", "numbers", "auth_username", "auth_password", "name", "metadata", "media_encryption", "from_host")
+ ADDRESS_FIELD_NUMBER: _ClassVar[int]
+ TRANSPORT_FIELD_NUMBER: _ClassVar[int]
+ DESTINATION_COUNTRY_FIELD_NUMBER: _ClassVar[int]
+ NUMBERS_FIELD_NUMBER: _ClassVar[int]
+ AUTH_USERNAME_FIELD_NUMBER: _ClassVar[int]
+ AUTH_PASSWORD_FIELD_NUMBER: _ClassVar[int]
+ NAME_FIELD_NUMBER: _ClassVar[int]
+ METADATA_FIELD_NUMBER: _ClassVar[int]
+ MEDIA_ENCRYPTION_FIELD_NUMBER: _ClassVar[int]
+ FROM_HOST_FIELD_NUMBER: _ClassVar[int]
+ address: str
+ transport: SIPTransport
+ destination_country: str
+ numbers: _models.ListUpdate
+ auth_username: str
+ auth_password: str
+ name: str
+ metadata: str
+ media_encryption: SIPMediaEncryption
+ from_host: str
+ def __init__(self, address: _Optional[str] = ..., transport: _Optional[_Union[SIPTransport, str]] = ..., destination_country: _Optional[str] = ..., numbers: _Optional[_Union[_models.ListUpdate, _Mapping]] = ..., auth_username: _Optional[str] = ..., auth_password: _Optional[str] = ..., name: _Optional[str] = ..., metadata: _Optional[str] = ..., media_encryption: _Optional[_Union[SIPMediaEncryption, str]] = ..., from_host: _Optional[str] = ...) -> None: ...
+
+class GetSIPInboundTrunkRequest(_message.Message):
+ __slots__ = ("sip_trunk_id",)
+ SIP_TRUNK_ID_FIELD_NUMBER: _ClassVar[int]
+ sip_trunk_id: str
+ def __init__(self, sip_trunk_id: _Optional[str] = ...) -> None: ...
+
+class GetSIPInboundTrunkResponse(_message.Message):
+ __slots__ = ("trunk",)
+ TRUNK_FIELD_NUMBER: _ClassVar[int]
+ trunk: SIPInboundTrunkInfo
+ def __init__(self, trunk: _Optional[_Union[SIPInboundTrunkInfo, _Mapping]] = ...) -> None: ...
+
+class GetSIPOutboundTrunkRequest(_message.Message):
+ __slots__ = ("sip_trunk_id",)
+ SIP_TRUNK_ID_FIELD_NUMBER: _ClassVar[int]
+ sip_trunk_id: str
+ def __init__(self, sip_trunk_id: _Optional[str] = ...) -> None: ...
+
+class GetSIPOutboundTrunkResponse(_message.Message):
+ __slots__ = ("trunk",)
+ TRUNK_FIELD_NUMBER: _ClassVar[int]
+ trunk: SIPOutboundTrunkInfo
+ def __init__(self, trunk: _Optional[_Union[SIPOutboundTrunkInfo, _Mapping]] = ...) -> None: ...
class ListSIPTrunkRequest(_message.Message):
- __slots__ = ()
- def __init__(self) -> None: ...
+ __slots__ = ("page",)
+ PAGE_FIELD_NUMBER: _ClassVar[int]
+ page: _models.Pagination
+ def __init__(self, page: _Optional[_Union[_models.Pagination, _Mapping]] = ...) -> None: ...
class ListSIPTrunkResponse(_message.Message):
__slots__ = ("items",)
@@ -146,8 +563,14 @@ class ListSIPTrunkResponse(_message.Message):
def __init__(self, items: _Optional[_Iterable[_Union[SIPTrunkInfo, _Mapping]]] = ...) -> None: ...
class ListSIPInboundTrunkRequest(_message.Message):
- __slots__ = ()
- def __init__(self) -> None: ...
+ __slots__ = ("page", "trunk_ids", "numbers")
+ PAGE_FIELD_NUMBER: _ClassVar[int]
+ TRUNK_IDS_FIELD_NUMBER: _ClassVar[int]
+ NUMBERS_FIELD_NUMBER: _ClassVar[int]
+ page: _models.Pagination
+ trunk_ids: _containers.RepeatedScalarFieldContainer[str]
+ numbers: _containers.RepeatedScalarFieldContainer[str]
+ def __init__(self, page: _Optional[_Union[_models.Pagination, _Mapping]] = ..., trunk_ids: _Optional[_Iterable[str]] = ..., numbers: _Optional[_Iterable[str]] = ...) -> None: ...
class ListSIPInboundTrunkResponse(_message.Message):
__slots__ = ("items",)
@@ -156,8 +579,14 @@ class ListSIPInboundTrunkResponse(_message.Message):
def __init__(self, items: _Optional[_Iterable[_Union[SIPInboundTrunkInfo, _Mapping]]] = ...) -> None: ...
class ListSIPOutboundTrunkRequest(_message.Message):
- __slots__ = ()
- def __init__(self) -> None: ...
+ __slots__ = ("page", "trunk_ids", "numbers")
+ PAGE_FIELD_NUMBER: _ClassVar[int]
+ TRUNK_IDS_FIELD_NUMBER: _ClassVar[int]
+ NUMBERS_FIELD_NUMBER: _ClassVar[int]
+ page: _models.Pagination
+ trunk_ids: _containers.RepeatedScalarFieldContainer[str]
+ numbers: _containers.RepeatedScalarFieldContainer[str]
+ def __init__(self, page: _Optional[_Union[_models.Pagination, _Mapping]] = ..., trunk_ids: _Optional[_Iterable[str]] = ..., numbers: _Optional[_Iterable[str]] = ...) -> None: ...
class ListSIPOutboundTrunkResponse(_message.Message):
__slots__ = ("items",)
@@ -180,23 +609,37 @@ class SIPDispatchRuleDirect(_message.Message):
def __init__(self, room_name: _Optional[str] = ..., pin: _Optional[str] = ...) -> None: ...
class SIPDispatchRuleIndividual(_message.Message):
- __slots__ = ("room_prefix", "pin")
+ __slots__ = ("room_prefix", "pin", "no_randomness")
+ ROOM_PREFIX_FIELD_NUMBER: _ClassVar[int]
+ PIN_FIELD_NUMBER: _ClassVar[int]
+ NO_RANDOMNESS_FIELD_NUMBER: _ClassVar[int]
+ room_prefix: str
+ pin: str
+ no_randomness: bool
+ def __init__(self, room_prefix: _Optional[str] = ..., pin: _Optional[str] = ..., no_randomness: bool = ...) -> None: ...
+
+class SIPDispatchRuleCallee(_message.Message):
+ __slots__ = ("room_prefix", "pin", "randomize")
ROOM_PREFIX_FIELD_NUMBER: _ClassVar[int]
PIN_FIELD_NUMBER: _ClassVar[int]
+ RANDOMIZE_FIELD_NUMBER: _ClassVar[int]
room_prefix: str
pin: str
- def __init__(self, room_prefix: _Optional[str] = ..., pin: _Optional[str] = ...) -> None: ...
+ randomize: bool
+ def __init__(self, room_prefix: _Optional[str] = ..., pin: _Optional[str] = ..., randomize: bool = ...) -> None: ...
class SIPDispatchRule(_message.Message):
- __slots__ = ("dispatch_rule_direct", "dispatch_rule_individual")
+ __slots__ = ("dispatch_rule_direct", "dispatch_rule_individual", "dispatch_rule_callee")
DISPATCH_RULE_DIRECT_FIELD_NUMBER: _ClassVar[int]
DISPATCH_RULE_INDIVIDUAL_FIELD_NUMBER: _ClassVar[int]
+ DISPATCH_RULE_CALLEE_FIELD_NUMBER: _ClassVar[int]
dispatch_rule_direct: SIPDispatchRuleDirect
dispatch_rule_individual: SIPDispatchRuleIndividual
- def __init__(self, dispatch_rule_direct: _Optional[_Union[SIPDispatchRuleDirect, _Mapping]] = ..., dispatch_rule_individual: _Optional[_Union[SIPDispatchRuleIndividual, _Mapping]] = ...) -> None: ...
+ dispatch_rule_callee: SIPDispatchRuleCallee
+ def __init__(self, dispatch_rule_direct: _Optional[_Union[SIPDispatchRuleDirect, _Mapping]] = ..., dispatch_rule_individual: _Optional[_Union[SIPDispatchRuleIndividual, _Mapping]] = ..., dispatch_rule_callee: _Optional[_Union[SIPDispatchRuleCallee, _Mapping]] = ...) -> None: ...
class CreateSIPDispatchRuleRequest(_message.Message):
- __slots__ = ("rule", "trunk_ids", "hide_phone_number", "inbound_numbers", "name", "metadata", "attributes")
+ __slots__ = ("dispatch_rule", "rule", "trunk_ids", "hide_phone_number", "inbound_numbers", "name", "metadata", "attributes", "room_preset", "room_config")
class AttributesEntry(_message.Message):
__slots__ = ("key", "value")
KEY_FIELD_NUMBER: _ClassVar[int]
@@ -204,6 +647,7 @@ class CreateSIPDispatchRuleRequest(_message.Message):
key: str
value: str
def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
+ DISPATCH_RULE_FIELD_NUMBER: _ClassVar[int]
RULE_FIELD_NUMBER: _ClassVar[int]
TRUNK_IDS_FIELD_NUMBER: _ClassVar[int]
HIDE_PHONE_NUMBER_FIELD_NUMBER: _ClassVar[int]
@@ -211,6 +655,9 @@ class CreateSIPDispatchRuleRequest(_message.Message):
NAME_FIELD_NUMBER: _ClassVar[int]
METADATA_FIELD_NUMBER: _ClassVar[int]
ATTRIBUTES_FIELD_NUMBER: _ClassVar[int]
+ ROOM_PRESET_FIELD_NUMBER: _ClassVar[int]
+ ROOM_CONFIG_FIELD_NUMBER: _ClassVar[int]
+ dispatch_rule: SIPDispatchRuleInfo
rule: SIPDispatchRule
trunk_ids: _containers.RepeatedScalarFieldContainer[str]
hide_phone_number: bool
@@ -218,10 +665,22 @@ class CreateSIPDispatchRuleRequest(_message.Message):
name: str
metadata: str
attributes: _containers.ScalarMap[str, str]
- def __init__(self, rule: _Optional[_Union[SIPDispatchRule, _Mapping]] = ..., trunk_ids: _Optional[_Iterable[str]] = ..., hide_phone_number: bool = ..., inbound_numbers: _Optional[_Iterable[str]] = ..., name: _Optional[str] = ..., metadata: _Optional[str] = ..., attributes: _Optional[_Mapping[str, str]] = ...) -> None: ...
+ room_preset: str
+ room_config: _room.RoomConfiguration
+ def __init__(self, dispatch_rule: _Optional[_Union[SIPDispatchRuleInfo, _Mapping]] = ..., rule: _Optional[_Union[SIPDispatchRule, _Mapping]] = ..., trunk_ids: _Optional[_Iterable[str]] = ..., hide_phone_number: bool = ..., inbound_numbers: _Optional[_Iterable[str]] = ..., name: _Optional[str] = ..., metadata: _Optional[str] = ..., attributes: _Optional[_Mapping[str, str]] = ..., room_preset: _Optional[str] = ..., room_config: _Optional[_Union[_room.RoomConfiguration, _Mapping]] = ...) -> None: ...
+
+class UpdateSIPDispatchRuleRequest(_message.Message):
+ __slots__ = ("sip_dispatch_rule_id", "replace", "update")
+ SIP_DISPATCH_RULE_ID_FIELD_NUMBER: _ClassVar[int]
+ REPLACE_FIELD_NUMBER: _ClassVar[int]
+ UPDATE_FIELD_NUMBER: _ClassVar[int]
+ sip_dispatch_rule_id: str
+ replace: SIPDispatchRuleInfo
+ update: SIPDispatchRuleUpdate
+ def __init__(self, sip_dispatch_rule_id: _Optional[str] = ..., replace: _Optional[_Union[SIPDispatchRuleInfo, _Mapping]] = ..., update: _Optional[_Union[SIPDispatchRuleUpdate, _Mapping]] = ...) -> None: ...
class SIPDispatchRuleInfo(_message.Message):
- __slots__ = ("sip_dispatch_rule_id", "rule", "trunk_ids", "hide_phone_number", "inbound_numbers", "name", "metadata", "attributes")
+ __slots__ = ("sip_dispatch_rule_id", "rule", "trunk_ids", "hide_phone_number", "inbound_numbers", "numbers", "name", "metadata", "attributes", "room_preset", "room_config", "krisp_enabled", "media_encryption", "created_at", "updated_at")
class AttributesEntry(_message.Message):
__slots__ = ("key", "value")
KEY_FIELD_NUMBER: _ClassVar[int]
@@ -234,22 +693,65 @@ class SIPDispatchRuleInfo(_message.Message):
TRUNK_IDS_FIELD_NUMBER: _ClassVar[int]
HIDE_PHONE_NUMBER_FIELD_NUMBER: _ClassVar[int]
INBOUND_NUMBERS_FIELD_NUMBER: _ClassVar[int]
+ NUMBERS_FIELD_NUMBER: _ClassVar[int]
NAME_FIELD_NUMBER: _ClassVar[int]
METADATA_FIELD_NUMBER: _ClassVar[int]
ATTRIBUTES_FIELD_NUMBER: _ClassVar[int]
+ ROOM_PRESET_FIELD_NUMBER: _ClassVar[int]
+ ROOM_CONFIG_FIELD_NUMBER: _ClassVar[int]
+ KRISP_ENABLED_FIELD_NUMBER: _ClassVar[int]
+ MEDIA_ENCRYPTION_FIELD_NUMBER: _ClassVar[int]
+ CREATED_AT_FIELD_NUMBER: _ClassVar[int]
+ UPDATED_AT_FIELD_NUMBER: _ClassVar[int]
sip_dispatch_rule_id: str
rule: SIPDispatchRule
trunk_ids: _containers.RepeatedScalarFieldContainer[str]
hide_phone_number: bool
inbound_numbers: _containers.RepeatedScalarFieldContainer[str]
+ numbers: _containers.RepeatedScalarFieldContainer[str]
+ name: str
+ metadata: str
+ attributes: _containers.ScalarMap[str, str]
+ room_preset: str
+ room_config: _room.RoomConfiguration
+ krisp_enabled: bool
+ media_encryption: SIPMediaEncryption
+ created_at: _timestamp_pb2.Timestamp
+ updated_at: _timestamp_pb2.Timestamp
+ def __init__(self, sip_dispatch_rule_id: _Optional[str] = ..., rule: _Optional[_Union[SIPDispatchRule, _Mapping]] = ..., trunk_ids: _Optional[_Iterable[str]] = ..., hide_phone_number: bool = ..., inbound_numbers: _Optional[_Iterable[str]] = ..., numbers: _Optional[_Iterable[str]] = ..., name: _Optional[str] = ..., metadata: _Optional[str] = ..., attributes: _Optional[_Mapping[str, str]] = ..., room_preset: _Optional[str] = ..., room_config: _Optional[_Union[_room.RoomConfiguration, _Mapping]] = ..., krisp_enabled: bool = ..., media_encryption: _Optional[_Union[SIPMediaEncryption, str]] = ..., created_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., updated_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ...) -> None: ...
+
+class SIPDispatchRuleUpdate(_message.Message):
+ __slots__ = ("trunk_ids", "rule", "name", "metadata", "attributes", "media_encryption")
+ class AttributesEntry(_message.Message):
+ __slots__ = ("key", "value")
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: str
+ value: str
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
+ TRUNK_IDS_FIELD_NUMBER: _ClassVar[int]
+ RULE_FIELD_NUMBER: _ClassVar[int]
+ NAME_FIELD_NUMBER: _ClassVar[int]
+ METADATA_FIELD_NUMBER: _ClassVar[int]
+ ATTRIBUTES_FIELD_NUMBER: _ClassVar[int]
+ MEDIA_ENCRYPTION_FIELD_NUMBER: _ClassVar[int]
+ trunk_ids: _models.ListUpdate
+ rule: SIPDispatchRule
name: str
metadata: str
attributes: _containers.ScalarMap[str, str]
- def __init__(self, sip_dispatch_rule_id: _Optional[str] = ..., rule: _Optional[_Union[SIPDispatchRule, _Mapping]] = ..., trunk_ids: _Optional[_Iterable[str]] = ..., hide_phone_number: bool = ..., inbound_numbers: _Optional[_Iterable[str]] = ..., name: _Optional[str] = ..., metadata: _Optional[str] = ..., attributes: _Optional[_Mapping[str, str]] = ...) -> None: ...
+ media_encryption: SIPMediaEncryption
+ def __init__(self, trunk_ids: _Optional[_Union[_models.ListUpdate, _Mapping]] = ..., rule: _Optional[_Union[SIPDispatchRule, _Mapping]] = ..., name: _Optional[str] = ..., metadata: _Optional[str] = ..., attributes: _Optional[_Mapping[str, str]] = ..., media_encryption: _Optional[_Union[SIPMediaEncryption, str]] = ...) -> None: ...
class ListSIPDispatchRuleRequest(_message.Message):
- __slots__ = ()
- def __init__(self) -> None: ...
+ __slots__ = ("page", "dispatch_rule_ids", "trunk_ids")
+ PAGE_FIELD_NUMBER: _ClassVar[int]
+ DISPATCH_RULE_IDS_FIELD_NUMBER: _ClassVar[int]
+ TRUNK_IDS_FIELD_NUMBER: _ClassVar[int]
+ page: _models.Pagination
+ dispatch_rule_ids: _containers.RepeatedScalarFieldContainer[str]
+ trunk_ids: _containers.RepeatedScalarFieldContainer[str]
+ def __init__(self, page: _Optional[_Union[_models.Pagination, _Mapping]] = ..., dispatch_rule_ids: _Optional[_Iterable[str]] = ..., trunk_ids: _Optional[_Iterable[str]] = ...) -> None: ...
class ListSIPDispatchRuleResponse(_message.Message):
__slots__ = ("items",)
@@ -263,8 +765,42 @@ class DeleteSIPDispatchRuleRequest(_message.Message):
sip_dispatch_rule_id: str
def __init__(self, sip_dispatch_rule_id: _Optional[str] = ...) -> None: ...
+class SIPOutboundConfig(_message.Message):
+ __slots__ = ("hostname", "destination_country", "transport", "auth_username", "auth_password", "headers_to_attributes", "attributes_to_headers", "from_host")
+ class HeadersToAttributesEntry(_message.Message):
+ __slots__ = ("key", "value")
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: str
+ value: str
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
+ class AttributesToHeadersEntry(_message.Message):
+ __slots__ = ("key", "value")
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: str
+ value: str
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
+ HOSTNAME_FIELD_NUMBER: _ClassVar[int]
+ DESTINATION_COUNTRY_FIELD_NUMBER: _ClassVar[int]
+ TRANSPORT_FIELD_NUMBER: _ClassVar[int]
+ AUTH_USERNAME_FIELD_NUMBER: _ClassVar[int]
+ AUTH_PASSWORD_FIELD_NUMBER: _ClassVar[int]
+ HEADERS_TO_ATTRIBUTES_FIELD_NUMBER: _ClassVar[int]
+ ATTRIBUTES_TO_HEADERS_FIELD_NUMBER: _ClassVar[int]
+ FROM_HOST_FIELD_NUMBER: _ClassVar[int]
+ hostname: str
+ destination_country: str
+ transport: SIPTransport
+ auth_username: str
+ auth_password: str
+ headers_to_attributes: _containers.ScalarMap[str, str]
+ attributes_to_headers: _containers.ScalarMap[str, str]
+ from_host: str
+ def __init__(self, hostname: _Optional[str] = ..., destination_country: _Optional[str] = ..., transport: _Optional[_Union[SIPTransport, str]] = ..., auth_username: _Optional[str] = ..., auth_password: _Optional[str] = ..., headers_to_attributes: _Optional[_Mapping[str, str]] = ..., attributes_to_headers: _Optional[_Mapping[str, str]] = ..., from_host: _Optional[str] = ...) -> None: ...
+
class CreateSIPParticipantRequest(_message.Message):
- __slots__ = ("sip_trunk_id", "sip_call_to", "room_name", "participant_identity", "participant_name", "participant_metadata", "participant_attributes", "dtmf", "play_ringtone", "hide_phone_number")
+ __slots__ = ("sip_trunk_id", "trunk", "sip_call_to", "sip_number", "room_name", "participant_identity", "participant_name", "participant_metadata", "participant_attributes", "dtmf", "play_ringtone", "play_dialtone", "hide_phone_number", "headers", "include_headers", "ringing_timeout", "max_call_duration", "krisp_enabled", "media_encryption", "wait_until_answered", "display_name", "destination")
class ParticipantAttributesEntry(_message.Message):
__slots__ = ("key", "value")
KEY_FIELD_NUMBER: _ClassVar[int]
@@ -272,8 +808,17 @@ class CreateSIPParticipantRequest(_message.Message):
key: str
value: str
def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
+ class HeadersEntry(_message.Message):
+ __slots__ = ("key", "value")
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: str
+ value: str
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
SIP_TRUNK_ID_FIELD_NUMBER: _ClassVar[int]
+ TRUNK_FIELD_NUMBER: _ClassVar[int]
SIP_CALL_TO_FIELD_NUMBER: _ClassVar[int]
+ SIP_NUMBER_FIELD_NUMBER: _ClassVar[int]
ROOM_NAME_FIELD_NUMBER: _ClassVar[int]
PARTICIPANT_IDENTITY_FIELD_NUMBER: _ClassVar[int]
PARTICIPANT_NAME_FIELD_NUMBER: _ClassVar[int]
@@ -281,9 +826,21 @@ class CreateSIPParticipantRequest(_message.Message):
PARTICIPANT_ATTRIBUTES_FIELD_NUMBER: _ClassVar[int]
DTMF_FIELD_NUMBER: _ClassVar[int]
PLAY_RINGTONE_FIELD_NUMBER: _ClassVar[int]
+ PLAY_DIALTONE_FIELD_NUMBER: _ClassVar[int]
HIDE_PHONE_NUMBER_FIELD_NUMBER: _ClassVar[int]
+ HEADERS_FIELD_NUMBER: _ClassVar[int]
+ INCLUDE_HEADERS_FIELD_NUMBER: _ClassVar[int]
+ RINGING_TIMEOUT_FIELD_NUMBER: _ClassVar[int]
+ MAX_CALL_DURATION_FIELD_NUMBER: _ClassVar[int]
+ KRISP_ENABLED_FIELD_NUMBER: _ClassVar[int]
+ MEDIA_ENCRYPTION_FIELD_NUMBER: _ClassVar[int]
+ WAIT_UNTIL_ANSWERED_FIELD_NUMBER: _ClassVar[int]
+ DISPLAY_NAME_FIELD_NUMBER: _ClassVar[int]
+ DESTINATION_FIELD_NUMBER: _ClassVar[int]
sip_trunk_id: str
+ trunk: SIPOutboundConfig
sip_call_to: str
+ sip_number: str
room_name: str
participant_identity: str
participant_name: str
@@ -291,8 +848,18 @@ class CreateSIPParticipantRequest(_message.Message):
participant_attributes: _containers.ScalarMap[str, str]
dtmf: str
play_ringtone: bool
+ play_dialtone: bool
hide_phone_number: bool
- def __init__(self, sip_trunk_id: _Optional[str] = ..., sip_call_to: _Optional[str] = ..., room_name: _Optional[str] = ..., participant_identity: _Optional[str] = ..., participant_name: _Optional[str] = ..., participant_metadata: _Optional[str] = ..., participant_attributes: _Optional[_Mapping[str, str]] = ..., dtmf: _Optional[str] = ..., play_ringtone: bool = ..., hide_phone_number: bool = ...) -> None: ...
+ headers: _containers.ScalarMap[str, str]
+ include_headers: SIPHeaderOptions
+ ringing_timeout: _duration_pb2.Duration
+ max_call_duration: _duration_pb2.Duration
+ krisp_enabled: bool
+ media_encryption: SIPMediaEncryption
+ wait_until_answered: bool
+ display_name: str
+ destination: Destination
+ def __init__(self, sip_trunk_id: _Optional[str] = ..., trunk: _Optional[_Union[SIPOutboundConfig, _Mapping]] = ..., sip_call_to: _Optional[str] = ..., sip_number: _Optional[str] = ..., room_name: _Optional[str] = ..., participant_identity: _Optional[str] = ..., participant_name: _Optional[str] = ..., participant_metadata: _Optional[str] = ..., participant_attributes: _Optional[_Mapping[str, str]] = ..., dtmf: _Optional[str] = ..., play_ringtone: bool = ..., play_dialtone: bool = ..., hide_phone_number: bool = ..., headers: _Optional[_Mapping[str, str]] = ..., include_headers: _Optional[_Union[SIPHeaderOptions, str]] = ..., ringing_timeout: _Optional[_Union[_duration_pb2.Duration, _Mapping]] = ..., max_call_duration: _Optional[_Union[_duration_pb2.Duration, _Mapping]] = ..., krisp_enabled: bool = ..., media_encryption: _Optional[_Union[SIPMediaEncryption, str]] = ..., wait_until_answered: bool = ..., display_name: _Optional[str] = ..., destination: _Optional[_Union[Destination, _Mapping]] = ...) -> None: ...
class SIPParticipantInfo(_message.Message):
__slots__ = ("participant_id", "participant_identity", "room_name", "sip_call_id")
@@ -305,3 +872,137 @@ class SIPParticipantInfo(_message.Message):
room_name: str
sip_call_id: str
def __init__(self, participant_id: _Optional[str] = ..., participant_identity: _Optional[str] = ..., room_name: _Optional[str] = ..., sip_call_id: _Optional[str] = ...) -> None: ...
+
+class TransferSIPParticipantRequest(_message.Message):
+ __slots__ = ("participant_identity", "room_name", "transfer_to", "play_dialtone", "headers", "ringing_timeout")
+ class HeadersEntry(_message.Message):
+ __slots__ = ("key", "value")
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: str
+ value: str
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: _ClassVar[int]
+ ROOM_NAME_FIELD_NUMBER: _ClassVar[int]
+ TRANSFER_TO_FIELD_NUMBER: _ClassVar[int]
+ PLAY_DIALTONE_FIELD_NUMBER: _ClassVar[int]
+ HEADERS_FIELD_NUMBER: _ClassVar[int]
+ RINGING_TIMEOUT_FIELD_NUMBER: _ClassVar[int]
+ participant_identity: str
+ room_name: str
+ transfer_to: str
+ play_dialtone: bool
+ headers: _containers.ScalarMap[str, str]
+ ringing_timeout: _duration_pb2.Duration
+ def __init__(self, participant_identity: _Optional[str] = ..., room_name: _Optional[str] = ..., transfer_to: _Optional[str] = ..., play_dialtone: bool = ..., headers: _Optional[_Mapping[str, str]] = ..., ringing_timeout: _Optional[_Union[_duration_pb2.Duration, _Mapping]] = ...) -> None: ...
+
+class SIPCallInfo(_message.Message):
+ __slots__ = ("call_id", "trunk_id", "dispatch_rule_id", "region", "room_name", "room_id", "participant_identity", "participant_attributes", "from_uri", "to_uri", "created_at", "started_at", "ended_at", "enabled_features", "call_direction", "call_status", "created_at_ns", "started_at_ns", "ended_at_ns", "disconnect_reason", "error", "call_status_code", "audio_codec", "media_encryption", "pcap_file_link", "call_context", "provider_info", "sip_call_id")
+ class ParticipantAttributesEntry(_message.Message):
+ __slots__ = ("key", "value")
+ KEY_FIELD_NUMBER: _ClassVar[int]
+ VALUE_FIELD_NUMBER: _ClassVar[int]
+ key: str
+ value: str
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
+ CALL_ID_FIELD_NUMBER: _ClassVar[int]
+ TRUNK_ID_FIELD_NUMBER: _ClassVar[int]
+ DISPATCH_RULE_ID_FIELD_NUMBER: _ClassVar[int]
+ REGION_FIELD_NUMBER: _ClassVar[int]
+ ROOM_NAME_FIELD_NUMBER: _ClassVar[int]
+ ROOM_ID_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: _ClassVar[int]
+ PARTICIPANT_ATTRIBUTES_FIELD_NUMBER: _ClassVar[int]
+ FROM_URI_FIELD_NUMBER: _ClassVar[int]
+ TO_URI_FIELD_NUMBER: _ClassVar[int]
+ CREATED_AT_FIELD_NUMBER: _ClassVar[int]
+ STARTED_AT_FIELD_NUMBER: _ClassVar[int]
+ ENDED_AT_FIELD_NUMBER: _ClassVar[int]
+ ENABLED_FEATURES_FIELD_NUMBER: _ClassVar[int]
+ CALL_DIRECTION_FIELD_NUMBER: _ClassVar[int]
+ CALL_STATUS_FIELD_NUMBER: _ClassVar[int]
+ CREATED_AT_NS_FIELD_NUMBER: _ClassVar[int]
+ STARTED_AT_NS_FIELD_NUMBER: _ClassVar[int]
+ ENDED_AT_NS_FIELD_NUMBER: _ClassVar[int]
+ DISCONNECT_REASON_FIELD_NUMBER: _ClassVar[int]
+ ERROR_FIELD_NUMBER: _ClassVar[int]
+ CALL_STATUS_CODE_FIELD_NUMBER: _ClassVar[int]
+ AUDIO_CODEC_FIELD_NUMBER: _ClassVar[int]
+ MEDIA_ENCRYPTION_FIELD_NUMBER: _ClassVar[int]
+ PCAP_FILE_LINK_FIELD_NUMBER: _ClassVar[int]
+ CALL_CONTEXT_FIELD_NUMBER: _ClassVar[int]
+ PROVIDER_INFO_FIELD_NUMBER: _ClassVar[int]
+ SIP_CALL_ID_FIELD_NUMBER: _ClassVar[int]
+ call_id: str
+ trunk_id: str
+ dispatch_rule_id: str
+ region: str
+ room_name: str
+ room_id: str
+ participant_identity: str
+ participant_attributes: _containers.ScalarMap[str, str]
+ from_uri: SIPUri
+ to_uri: SIPUri
+ created_at: int
+ started_at: int
+ ended_at: int
+ enabled_features: _containers.RepeatedScalarFieldContainer[SIPFeature]
+ call_direction: SIPCallDirection
+ call_status: SIPCallStatus
+ created_at_ns: int
+ started_at_ns: int
+ ended_at_ns: int
+ disconnect_reason: _models.DisconnectReason
+ error: str
+ call_status_code: SIPStatus
+ audio_codec: str
+ media_encryption: str
+ pcap_file_link: str
+ call_context: _containers.RepeatedCompositeFieldContainer[_any_pb2.Any]
+ provider_info: ProviderInfo
+ sip_call_id: str
+ def __init__(self, call_id: _Optional[str] = ..., trunk_id: _Optional[str] = ..., dispatch_rule_id: _Optional[str] = ..., region: _Optional[str] = ..., room_name: _Optional[str] = ..., room_id: _Optional[str] = ..., participant_identity: _Optional[str] = ..., participant_attributes: _Optional[_Mapping[str, str]] = ..., from_uri: _Optional[_Union[SIPUri, _Mapping]] = ..., to_uri: _Optional[_Union[SIPUri, _Mapping]] = ..., created_at: _Optional[int] = ..., started_at: _Optional[int] = ..., ended_at: _Optional[int] = ..., enabled_features: _Optional[_Iterable[_Union[SIPFeature, str]]] = ..., call_direction: _Optional[_Union[SIPCallDirection, str]] = ..., call_status: _Optional[_Union[SIPCallStatus, str]] = ..., created_at_ns: _Optional[int] = ..., started_at_ns: _Optional[int] = ..., ended_at_ns: _Optional[int] = ..., disconnect_reason: _Optional[_Union[_models.DisconnectReason, str]] = ..., error: _Optional[str] = ..., call_status_code: _Optional[_Union[SIPStatus, _Mapping]] = ..., audio_codec: _Optional[str] = ..., media_encryption: _Optional[str] = ..., pcap_file_link: _Optional[str] = ..., call_context: _Optional[_Iterable[_Union[_any_pb2.Any, _Mapping]]] = ..., provider_info: _Optional[_Union[ProviderInfo, _Mapping]] = ..., sip_call_id: _Optional[str] = ...) -> None: ...
+
+class SIPTransferInfo(_message.Message):
+ __slots__ = ("transfer_id", "call_id", "transfer_to", "transfer_initiated_at_ns", "transfer_completed_at_ns", "transfer_status", "error", "transfer_status_code")
+ TRANSFER_ID_FIELD_NUMBER: _ClassVar[int]
+ CALL_ID_FIELD_NUMBER: _ClassVar[int]
+ TRANSFER_TO_FIELD_NUMBER: _ClassVar[int]
+ TRANSFER_INITIATED_AT_NS_FIELD_NUMBER: _ClassVar[int]
+ TRANSFER_COMPLETED_AT_NS_FIELD_NUMBER: _ClassVar[int]
+ TRANSFER_STATUS_FIELD_NUMBER: _ClassVar[int]
+ ERROR_FIELD_NUMBER: _ClassVar[int]
+ TRANSFER_STATUS_CODE_FIELD_NUMBER: _ClassVar[int]
+ transfer_id: str
+ call_id: str
+ transfer_to: str
+ transfer_initiated_at_ns: int
+ transfer_completed_at_ns: int
+ transfer_status: SIPTransferStatus
+ error: str
+ transfer_status_code: SIPStatus
+ def __init__(self, transfer_id: _Optional[str] = ..., call_id: _Optional[str] = ..., transfer_to: _Optional[str] = ..., transfer_initiated_at_ns: _Optional[int] = ..., transfer_completed_at_ns: _Optional[int] = ..., transfer_status: _Optional[_Union[SIPTransferStatus, str]] = ..., error: _Optional[str] = ..., transfer_status_code: _Optional[_Union[SIPStatus, _Mapping]] = ...) -> None: ...
+
+class SIPUri(_message.Message):
+ __slots__ = ("user", "host", "ip", "port", "transport")
+ USER_FIELD_NUMBER: _ClassVar[int]
+ HOST_FIELD_NUMBER: _ClassVar[int]
+ IP_FIELD_NUMBER: _ClassVar[int]
+ PORT_FIELD_NUMBER: _ClassVar[int]
+ TRANSPORT_FIELD_NUMBER: _ClassVar[int]
+ user: str
+ host: str
+ ip: str
+ port: int
+ transport: SIPTransport
+ def __init__(self, user: _Optional[str] = ..., host: _Optional[str] = ..., ip: _Optional[str] = ..., port: _Optional[int] = ..., transport: _Optional[_Union[SIPTransport, str]] = ...) -> None: ...
+
+class Destination(_message.Message):
+ __slots__ = ("city", "country", "region")
+ CITY_FIELD_NUMBER: _ClassVar[int]
+ COUNTRY_FIELD_NUMBER: _ClassVar[int]
+ REGION_FIELD_NUMBER: _ClassVar[int]
+ city: str
+ country: str
+ region: str
+ def __init__(self, city: _Optional[str] = ..., country: _Optional[str] = ..., region: _Optional[str] = ...) -> None: ...
diff --git a/livekit-protocol/livekit/protocol/version.py b/livekit-protocol/livekit/protocol/version.py
index dd9b22cc..1436d8fe 100644
--- a/livekit-protocol/livekit/protocol/version.py
+++ b/livekit-protocol/livekit/protocol/version.py
@@ -1 +1 @@
-__version__ = "0.5.1"
+__version__ = "1.1.6"
diff --git a/livekit-protocol/livekit/protocol/webhook.py b/livekit-protocol/livekit/protocol/webhook.py
index 7c9f12c4..70cc46fe 100644
--- a/livekit-protocol/livekit/protocol/webhook.py
+++ b/livekit-protocol/livekit/protocol/webhook.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: livekit_webhook.proto
-# Protobuf Python Version: 4.25.3
+# Protobuf Python Version: 4.25.1
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
@@ -17,7 +17,7 @@
from . import ingress as _ingress_
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15livekit_webhook.proto\x12\x07livekit\x1a\x14livekit_models.proto\x1a\x14livekit_egress.proto\x1a\x15livekit_ingress.proto\"\x97\x02\n\x0cWebhookEvent\x12\r\n\x05\x65vent\x18\x01 \x01(\t\x12\x1b\n\x04room\x18\x02 \x01(\x0b\x32\r.livekit.Room\x12-\n\x0bparticipant\x18\x03 \x01(\x0b\x32\x18.livekit.ParticipantInfo\x12(\n\x0b\x65gress_info\x18\t \x01(\x0b\x32\x13.livekit.EgressInfo\x12*\n\x0cingress_info\x18\n \x01(\x0b\x32\x14.livekit.IngressInfo\x12!\n\x05track\x18\x08 \x01(\x0b\x32\x12.livekit.TrackInfo\x12\n\n\x02id\x18\x06 \x01(\t\x12\x12\n\ncreated_at\x18\x07 \x01(\x03\x12\x13\n\x0bnum_dropped\x18\x0b \x01(\x05\x42\x46Z#github.com/livekit/protocol/livekit\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15livekit_webhook.proto\x12\x07livekit\x1a\x14livekit_models.proto\x1a\x14livekit_egress.proto\x1a\x15livekit_ingress.proto\"\x9b\x02\n\x0cWebhookEvent\x12\r\n\x05\x65vent\x18\x01 \x01(\t\x12\x1b\n\x04room\x18\x02 \x01(\x0b\x32\r.livekit.Room\x12-\n\x0bparticipant\x18\x03 \x01(\x0b\x32\x18.livekit.ParticipantInfo\x12(\n\x0b\x65gress_info\x18\t \x01(\x0b\x32\x13.livekit.EgressInfo\x12*\n\x0cingress_info\x18\n \x01(\x0b\x32\x14.livekit.IngressInfo\x12!\n\x05track\x18\x08 \x01(\x0b\x32\x12.livekit.TrackInfo\x12\n\n\x02id\x18\x06 \x01(\t\x12\x12\n\ncreated_at\x18\x07 \x01(\x03\x12\x17\n\x0bnum_dropped\x18\x0b \x01(\x05\x42\x02\x18\x01\x42\x46Z#github.com/livekit/protocol/livekit\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -25,6 +25,8 @@
if _descriptor._USE_C_DESCRIPTORS == False:
_globals['DESCRIPTOR']._options = None
_globals['DESCRIPTOR']._serialized_options = b'Z#github.com/livekit/protocol/livekit\252\002\rLiveKit.Proto\352\002\016LiveKit::Proto'
+ _globals['_WEBHOOKEVENT'].fields_by_name['num_dropped']._options = None
+ _globals['_WEBHOOKEVENT'].fields_by_name['num_dropped']._serialized_options = b'\030\001'
_globals['_WEBHOOKEVENT']._serialized_start=102
- _globals['_WEBHOOKEVENT']._serialized_end=381
+ _globals['_WEBHOOKEVENT']._serialized_end=385
# @@protoc_insertion_point(module_scope)
diff --git a/livekit-protocol/protocol b/livekit-protocol/protocol
index 79b5ea9e..a4ac2627 160000
--- a/livekit-protocol/protocol
+++ b/livekit-protocol/protocol
@@ -1 +1 @@
-Subproject commit 79b5ea9ea9a29991ca6819323173e080aae9cfd3
+Subproject commit a4ac2627b46a7d515005db589a4eda3100dc1b8a
diff --git a/livekit-protocol/pyproject.toml b/livekit-protocol/pyproject.toml
new file mode 100644
index 00000000..5901cc0b
--- /dev/null
+++ b/livekit-protocol/pyproject.toml
@@ -0,0 +1,42 @@
+[build-system]
+requires = ["hatchling"]
+build-backend = "hatchling.build"
+
+[project]
+name = "livekit-protocol"
+dynamic = ["version"]
+description = "Python protocol stubs for LiveKit"
+requires-python = ">=3.7.0"
+license = "Apache-2.0"
+readme = { content-type = "text/plain", text = "Python protocol stubs for LiveKit" }
+keywords = ["webrtc", "realtime", "audio", "video", "livekit"]
+authors = [
+ { name = "LiveKit", email = "support@livekit.io" }
+]
+classifiers = [
+ "Intended Audience :: Developers",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 3.7",
+ "Programming Language :: Python :: 3.8",
+ "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
+ "Programming Language :: Python :: 3 :: Only",
+]
+dependencies = [
+ "protobuf>=4",
+ "types-protobuf>=4",
+]
+
+[project.urls]
+Documentation = "https://docs.livekit.io"
+Website = "https://livekit.io/"
+Source = "https://github.com/livekit/python-sdks/"
+
+[tool.hatch.version]
+path = "livekit/protocol/version.py"
+
+[tool.hatch.build.targets.wheel]
+packages = ["livekit"]
+
+[tool.hatch.build.targets.sdist]
+include = ["/livekit"]
diff --git a/livekit-protocol/setup.py b/livekit-protocol/setup.py
deleted file mode 100644
index 9bec5035..00000000
--- a/livekit-protocol/setup.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# Copyright 2023 LiveKit, Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import os
-import pathlib
-from typing import Any, Dict
-
-import setuptools # type: ignore
-
-here = pathlib.Path(__file__).parent.resolve()
-about: Dict[Any, Any] = {}
-with open(os.path.join(here, "livekit", "protocol", "version.py"), "r") as f:
- exec(f.read(), about)
-
-
-setuptools.setup(
- name="livekit-protocol",
- version=about["__version__"],
- description="Python protocol stubs for LiveKit",
- long_description="Python protocol stubs for LiveKit",
- long_description_content_type="text/markdown",
- url="https://github.com/livekit/python-sdks",
- classifiers=[
- "Intended Audience :: Developers",
- "Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.7",
- "Programming Language :: Python :: 3.8",
- "Programming Language :: Python :: 3.9",
- "Programming Language :: Python :: 3.10",
- "Programming Language :: Python :: 3 :: Only",
- ],
- keywords=["webrtc", "realtime", "audio", "video", "livekit"],
- license="Apache-2.0",
- packages=setuptools.find_namespace_packages(include=["livekit.*"]),
- python_requires=">=3.7.0",
- install_requires=[
- "protobuf>=3",
- "types-protobuf>=4,<5",
- ],
- package_data={
- "livekit.protocol": ["*.pyi", "**/*.pyi", "py.typed"],
- },
- project_urls={
- "Documentation": "https://docs.livekit.io",
- "Website": "https://livekit.io/",
- "Source": "https://github.com/livekit/python-sdks/",
- },
-)
diff --git a/livekit-rtc/README.md b/livekit-rtc/README.md
index 105e723f..516f9b6c 100644
--- a/livekit-rtc/README.md
+++ b/livekit-rtc/README.md
@@ -1,3 +1,6 @@
-# LiveKit Real-time Python SDK
+# LiveKit SDK for Python
+
+Python SDK to integrate LiveKit's real-time video, audio, and data capabilities into your Python applications using WebRTC. Designed for use with [LiveKit Agents](https://github.com/livekit/agents) to build powerful voice AI apps.
+
+See https://docs.livekit.io/ for more information.
-The LiveKit Python SDK provides a convenient interface for integrating LiveKit's real-time video and audio capabilities into your Python applications. With it, developers can easily leverage LiveKit's WebRTC functionalities, allowing them to focus on building their AI models or other application logic without worrying about the complexities of WebRTC.
diff --git a/livekit-rtc/generate_proto.sh b/livekit-rtc/generate_proto.sh
index 1c4d0f03..76d8bb8a 100755
--- a/livekit-rtc/generate_proto.sh
+++ b/livekit-rtc/generate_proto.sh
@@ -12,7 +12,9 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
+#
# This script requires protobuf-compiler and https://github.com/nipunn1313/mypy-protobuf
+# (Used by the build-rtc CI)
FFI_PROTOCOL=./rust-sdks/livekit-ffi/protocol
FFI_OUT_PYTHON=./livekit/rtc/_proto
@@ -29,12 +31,16 @@ protoc \
$FFI_PROTOCOL/participant.proto \
$FFI_PROTOCOL/room.proto \
$FFI_PROTOCOL/track.proto \
+ $FFI_PROTOCOL/data_track.proto \
$FFI_PROTOCOL/video_frame.proto \
$FFI_PROTOCOL/e2ee.proto \
- $FFI_PROTOCOL/stats.proto
+ $FFI_PROTOCOL/stats.proto \
+ $FFI_PROTOCOL/track_publication.proto \
+ $FFI_PROTOCOL/rpc.proto \
+ $FFI_PROTOCOL/data_stream.proto
touch -a "$FFI_OUT_PYTHON/__init__.py"
for f in "$FFI_OUT_PYTHON"/*.py "$FFI_OUT_PYTHON"/*.pyi; do
- perl -i -pe 's|^(import (audio_frame_pb2\|ffi_pb2\|handle_pb2\|participant_pb2\|room_pb2\|track_pb2\|video_frame_pb2\|e2ee_pb2\|stats_pb2))|from . $1|g' "$f"
+ perl -i -pe 's|^(import (audio_frame_pb2\|ffi_pb2\|handle_pb2\|participant_pb2\|room_pb2\|track_pb2\|video_frame_pb2\|e2ee_pb2\|stats_pb2\|rpc_pb2\|track_publication_pb2\|data_stream_pb2\|data_track_pb2))|from . $1|g' "$f"
done
diff --git a/livekit-rtc/jupyter-html/.gitignore b/livekit-rtc/jupyter-html/.gitignore
new file mode 100644
index 00000000..a547bf36
--- /dev/null
+++ b/livekit-rtc/jupyter-html/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/livekit-rtc/jupyter-html/README.md b/livekit-rtc/jupyter-html/README.md
new file mode 100644
index 00000000..40ede56e
--- /dev/null
+++ b/livekit-rtc/jupyter-html/README.md
@@ -0,0 +1,54 @@
+# React + TypeScript + Vite
+
+This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
+
+Currently, two official plugins are available:
+
+- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
+- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
+
+## Expanding the ESLint configuration
+
+If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
+
+```js
+export default tseslint.config({
+ extends: [
+ // Remove ...tseslint.configs.recommended and replace with this
+ ...tseslint.configs.recommendedTypeChecked,
+ // Alternatively, use this for stricter rules
+ ...tseslint.configs.strictTypeChecked,
+ // Optionally, add this for stylistic rules
+ ...tseslint.configs.stylisticTypeChecked,
+ ],
+ languageOptions: {
+ // other options...
+ parserOptions: {
+ project: ['./tsconfig.node.json', './tsconfig.app.json'],
+ tsconfigRootDir: import.meta.dirname,
+ },
+ },
+})
+```
+
+You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
+
+```js
+// eslint.config.js
+import reactX from 'eslint-plugin-react-x'
+import reactDom from 'eslint-plugin-react-dom'
+
+export default tseslint.config({
+ plugins: {
+ // Add the react-x and react-dom plugins
+ 'react-x': reactX,
+ 'react-dom': reactDom,
+ },
+ rules: {
+ // other rules...
+ // Enable its recommended typescript rules
+ ...reactX.configs['recommended-typescript'].rules,
+ ...reactDom.configs.recommended.rules,
+ },
+})
+```
diff --git a/livekit-rtc/jupyter-html/eslint.config.js b/livekit-rtc/jupyter-html/eslint.config.js
new file mode 100644
index 00000000..092408a9
--- /dev/null
+++ b/livekit-rtc/jupyter-html/eslint.config.js
@@ -0,0 +1,28 @@
+import js from '@eslint/js'
+import globals from 'globals'
+import reactHooks from 'eslint-plugin-react-hooks'
+import reactRefresh from 'eslint-plugin-react-refresh'
+import tseslint from 'typescript-eslint'
+
+export default tseslint.config(
+ { ignores: ['dist'] },
+ {
+ extends: [js.configs.recommended, ...tseslint.configs.recommended],
+ files: ['**/*.{ts,tsx}'],
+ languageOptions: {
+ ecmaVersion: 2020,
+ globals: globals.browser,
+ },
+ plugins: {
+ 'react-hooks': reactHooks,
+ 'react-refresh': reactRefresh,
+ },
+ rules: {
+ ...reactHooks.configs.recommended.rules,
+ 'react-refresh/only-export-components': [
+ 'warn',
+ { allowConstantExport: true },
+ ],
+ },
+ },
+)
diff --git a/livekit-rtc/jupyter-html/index.html b/livekit-rtc/jupyter-html/index.html
new file mode 100644
index 00000000..e4b78eae
--- /dev/null
+++ b/livekit-rtc/jupyter-html/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Vite + React + TS
+
+
+
+
+
+
diff --git a/livekit-rtc/jupyter-html/package.json b/livekit-rtc/jupyter-html/package.json
new file mode 100644
index 00000000..91a3f01a
--- /dev/null
+++ b/livekit-rtc/jupyter-html/package.json
@@ -0,0 +1,33 @@
+{
+ "name": "jupyter-html",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc -b && vite build --outDir=../livekit/rtc/resources/jupyter-html",
+ "lint": "eslint .",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "@livekit/components-react": "^2.9.20",
+ "@livekit/components-styles": "^1.2.0",
+ "livekit-client": "^2.17.2",
+ "react": "^19.2.4",
+ "react-dom": "^19.2.4"
+ },
+ "devDependencies": {
+ "@eslint/js": "^9.39.3",
+ "@types/react": "^19.2.14",
+ "@types/react-dom": "^19.2.3",
+ "@vitejs/plugin-react": "^4.7.0",
+ "eslint": "^9.39.3",
+ "eslint-plugin-react-hooks": "^5.2.0",
+ "eslint-plugin-react-refresh": "^0.4.26",
+ "globals": "^17.0.0",
+ "typescript": "~5.7.3",
+ "typescript-eslint": "^8.56.1",
+ "vite": "^6.4.1",
+ "vite-plugin-singlefile": "^2.3.0"
+ }
+}
\ No newline at end of file
diff --git a/livekit-rtc/jupyter-html/pnpm-lock.yaml b/livekit-rtc/jupyter-html/pnpm-lock.yaml
new file mode 100644
index 00000000..7c9845c1
--- /dev/null
+++ b/livekit-rtc/jupyter-html/pnpm-lock.yaml
@@ -0,0 +1,2291 @@
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+importers:
+
+ .:
+ dependencies:
+ '@livekit/components-react':
+ specifier: ^2.9.20
+ version: 2.9.20(livekit-client@2.17.2(@types/dom-mediacapture-record@1.0.22))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tslib@2.8.1)
+ '@livekit/components-styles':
+ specifier: ^1.2.0
+ version: 1.2.0
+ livekit-client:
+ specifier: ^2.17.2
+ version: 2.17.2(@types/dom-mediacapture-record@1.0.22)
+ react:
+ specifier: ^19.2.4
+ version: 19.2.4
+ react-dom:
+ specifier: ^19.2.4
+ version: 19.2.4(react@19.2.4)
+ devDependencies:
+ '@eslint/js':
+ specifier: ^9.39.3
+ version: 9.39.4
+ '@types/react':
+ specifier: ^19.2.14
+ version: 19.2.14
+ '@types/react-dom':
+ specifier: ^19.2.3
+ version: 19.2.3(@types/react@19.2.14)
+ '@vitejs/plugin-react':
+ specifier: ^4.7.0
+ version: 4.7.0(vite@6.4.2)
+ eslint:
+ specifier: ^9.39.3
+ version: 9.39.4
+ eslint-plugin-react-hooks:
+ specifier: ^5.2.0
+ version: 5.2.0(eslint@9.39.4)
+ eslint-plugin-react-refresh:
+ specifier: ^0.4.26
+ version: 0.4.26(eslint@9.39.4)
+ globals:
+ specifier: ^17.0.0
+ version: 17.5.0
+ typescript:
+ specifier: ~5.7.3
+ version: 5.7.3
+ typescript-eslint:
+ specifier: ^8.56.1
+ version: 8.56.1(eslint@9.39.4)(typescript@5.7.3)
+ vite:
+ specifier: ^6.4.1
+ version: 6.4.2
+ vite-plugin-singlefile:
+ specifier: ^2.3.0
+ version: 2.3.0(rollup@4.60.1)(vite@6.4.2)
+
+packages:
+
+ '@babel/code-frame@7.29.0':
+ resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/compat-data@7.29.0':
+ resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/core@7.29.0':
+ resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/generator@7.29.1':
+ resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-compilation-targets@7.28.6':
+ resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-globals@7.28.0':
+ resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-imports@7.28.6':
+ resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-transforms@7.28.6':
+ resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+
+ '@babel/helper-plugin-utils@7.28.6':
+ resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-string-parser@7.27.1':
+ resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-identifier@7.28.5':
+ resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-option@7.27.1':
+ resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helpers@7.28.6':
+ resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/parser@7.29.0':
+ resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
+ '@babel/plugin-transform-react-jsx-self@7.27.1':
+ resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-transform-react-jsx-source@7.27.1':
+ resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/template@7.28.6':
+ resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/traverse@7.29.0':
+ resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/types@7.29.0':
+ resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==}
+ engines: {node: '>=6.9.0'}
+
+ '@bufbuild/protobuf@1.10.1':
+ resolution: {integrity: sha512-wJ8ReQbHxsAfXhrf9ixl0aYbZorRuOWpBNzm8pL8ftmSxQx/wnJD5Eg861NwJU/czy2VXFIebCeZnZrI9rktIQ==}
+
+ '@esbuild/aix-ppc64@0.25.12':
+ resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [aix]
+
+ '@esbuild/android-arm64@0.25.12':
+ resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [android]
+
+ '@esbuild/android-arm@0.25.12':
+ resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [android]
+
+ '@esbuild/android-x64@0.25.12':
+ resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [android]
+
+ '@esbuild/darwin-arm64@0.25.12':
+ resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@esbuild/darwin-x64@0.25.12':
+ resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@esbuild/freebsd-arm64@0.25.12':
+ resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@esbuild/freebsd-x64@0.25.12':
+ resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@esbuild/linux-arm64@0.25.12':
+ resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@esbuild/linux-arm@0.25.12':
+ resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [linux]
+
+ '@esbuild/linux-ia32@0.25.12':
+ resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [linux]
+
+ '@esbuild/linux-loong64@0.25.12':
+ resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==}
+ engines: {node: '>=18'}
+ cpu: [loong64]
+ os: [linux]
+
+ '@esbuild/linux-mips64el@0.25.12':
+ resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==}
+ engines: {node: '>=18'}
+ cpu: [mips64el]
+ os: [linux]
+
+ '@esbuild/linux-ppc64@0.25.12':
+ resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@esbuild/linux-riscv64@0.25.12':
+ resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==}
+ engines: {node: '>=18'}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@esbuild/linux-s390x@0.25.12':
+ resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==}
+ engines: {node: '>=18'}
+ cpu: [s390x]
+ os: [linux]
+
+ '@esbuild/linux-x64@0.25.12':
+ resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [linux]
+
+ '@esbuild/netbsd-arm64@0.25.12':
+ resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [netbsd]
+
+ '@esbuild/netbsd-x64@0.25.12':
+ resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [netbsd]
+
+ '@esbuild/openbsd-arm64@0.25.12':
+ resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openbsd]
+
+ '@esbuild/openbsd-x64@0.25.12':
+ resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [openbsd]
+
+ '@esbuild/openharmony-arm64@0.25.12':
+ resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@esbuild/sunos-x64@0.25.12':
+ resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [sunos]
+
+ '@esbuild/win32-arm64@0.25.12':
+ resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@esbuild/win32-ia32@0.25.12':
+ resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@esbuild/win32-x64@0.25.12':
+ resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [win32]
+
+ '@eslint-community/eslint-utils@4.9.1':
+ resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+
+ '@eslint-community/regexpp@4.12.2':
+ resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==}
+ engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+
+ '@eslint/config-array@0.21.2':
+ resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/config-helpers@0.4.2':
+ resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/core@0.17.0':
+ resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/eslintrc@3.3.5':
+ resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/js@9.39.4':
+ resolution: {integrity: sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/object-schema@2.1.7':
+ resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/plugin-kit@0.4.1':
+ resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@floating-ui/core@1.7.4':
+ resolution: {integrity: sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==}
+
+ '@floating-ui/dom@1.7.4':
+ resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==}
+
+ '@floating-ui/utils@0.2.10':
+ resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==}
+
+ '@humanfs/core@0.19.1':
+ resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
+ engines: {node: '>=18.18.0'}
+
+ '@humanfs/node@0.16.7':
+ resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==}
+ engines: {node: '>=18.18.0'}
+
+ '@humanwhocodes/module-importer@1.0.1':
+ resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
+ engines: {node: '>=12.22'}
+
+ '@humanwhocodes/retry@0.4.3':
+ resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==}
+ engines: {node: '>=18.18'}
+
+ '@jridgewell/gen-mapping@0.3.13':
+ resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
+
+ '@jridgewell/remapping@2.3.5':
+ resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
+
+ '@jridgewell/resolve-uri@3.1.2':
+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/sourcemap-codec@1.5.5':
+ resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
+
+ '@jridgewell/trace-mapping@0.3.31':
+ resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
+
+ '@livekit/components-core@0.12.13':
+ resolution: {integrity: sha512-DQmi84afHoHjZ62wm8y+XPNIDHTwFHAltjd3lmyXj8UZHOY7wcza4vFt1xnghJOD5wLRY58L1dkAgAw59MgWvw==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ livekit-client: ^2.17.2
+ tslib: ^2.6.2
+
+ '@livekit/components-react@2.9.20':
+ resolution: {integrity: sha512-hjkYOsJj9Jbghb7wM5cI8HoVisKeL6Zcy1VnRWTLm0sqVbto8GJp/17T4Udx85mCPY6Jgh8I1Cv0yVzgz7CQtg==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@livekit/krisp-noise-filter': ^0.2.12 || ^0.3.0
+ livekit-client: ^2.17.2
+ react: '>=18'
+ react-dom: '>=18'
+ tslib: ^2.6.2
+ peerDependenciesMeta:
+ '@livekit/krisp-noise-filter':
+ optional: true
+
+ '@livekit/components-styles@1.2.0':
+ resolution: {integrity: sha512-74/rt0lDh6aHmOPmWAeDE9C4OrNW9RIdmhX/YRbovQBVNGNVWojRjl3FgQZ5LPFXO6l1maKB4JhXcBFENVxVvw==}
+ engines: {node: '>=18'}
+
+ '@livekit/mutex@1.1.1':
+ resolution: {integrity: sha512-EsshAucklmpuUAfkABPxJNhzj9v2sG7JuzFDL4ML1oJQSV14sqrpTYnsaOudMAw9yOaW53NU3QQTlUQoRs4czw==}
+
+ '@livekit/protocol@1.44.0':
+ resolution: {integrity: sha512-/vfhDUGcUKO8Q43r6i+5FrDhl5oZjm/X3U4x2Iciqvgn5C8qbj+57YPcWSJ1kyIZm5Cm6AV2nAPjMm3ETD/iyg==}
+
+ '@rolldown/pluginutils@1.0.0-beta.27':
+ resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==}
+
+ '@rollup/rollup-android-arm-eabi@4.60.1':
+ resolution: {integrity: sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==}
+ cpu: [arm]
+ os: [android]
+
+ '@rollup/rollup-android-arm64@4.60.1':
+ resolution: {integrity: sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA==}
+ cpu: [arm64]
+ os: [android]
+
+ '@rollup/rollup-darwin-arm64@4.60.1':
+ resolution: {integrity: sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@rollup/rollup-darwin-x64@4.60.1':
+ resolution: {integrity: sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@rollup/rollup-freebsd-arm64@4.60.1':
+ resolution: {integrity: sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w==}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@rollup/rollup-freebsd-x64@4.60.1':
+ resolution: {integrity: sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g==}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.60.1':
+ resolution: {integrity: sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==}
+ cpu: [arm]
+ os: [linux]
+ libc: [glibc]
+
+ '@rollup/rollup-linux-arm-musleabihf@4.60.1':
+ resolution: {integrity: sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==}
+ cpu: [arm]
+ os: [linux]
+ libc: [musl]
+
+ '@rollup/rollup-linux-arm64-gnu@4.60.1':
+ resolution: {integrity: sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rollup/rollup-linux-arm64-musl@4.60.1':
+ resolution: {integrity: sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@rollup/rollup-linux-loong64-gnu@4.60.1':
+ resolution: {integrity: sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==}
+ cpu: [loong64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rollup/rollup-linux-loong64-musl@4.60.1':
+ resolution: {integrity: sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==}
+ cpu: [loong64]
+ os: [linux]
+ libc: [musl]
+
+ '@rollup/rollup-linux-ppc64-gnu@4.60.1':
+ resolution: {integrity: sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==}
+ cpu: [ppc64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rollup/rollup-linux-ppc64-musl@4.60.1':
+ resolution: {integrity: sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==}
+ cpu: [ppc64]
+ os: [linux]
+ libc: [musl]
+
+ '@rollup/rollup-linux-riscv64-gnu@4.60.1':
+ resolution: {integrity: sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==}
+ cpu: [riscv64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rollup/rollup-linux-riscv64-musl@4.60.1':
+ resolution: {integrity: sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==}
+ cpu: [riscv64]
+ os: [linux]
+ libc: [musl]
+
+ '@rollup/rollup-linux-s390x-gnu@4.60.1':
+ resolution: {integrity: sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==}
+ cpu: [s390x]
+ os: [linux]
+ libc: [glibc]
+
+ '@rollup/rollup-linux-x64-gnu@4.60.1':
+ resolution: {integrity: sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg==}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rollup/rollup-linux-x64-musl@4.60.1':
+ resolution: {integrity: sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w==}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@rollup/rollup-openbsd-x64@4.60.1':
+ resolution: {integrity: sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw==}
+ cpu: [x64]
+ os: [openbsd]
+
+ '@rollup/rollup-openharmony-arm64@4.60.1':
+ resolution: {integrity: sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA==}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@rollup/rollup-win32-arm64-msvc@4.60.1':
+ resolution: {integrity: sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@rollup/rollup-win32-ia32-msvc@4.60.1':
+ resolution: {integrity: sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg==}
+ cpu: [ia32]
+ os: [win32]
+
+ '@rollup/rollup-win32-x64-gnu@4.60.1':
+ resolution: {integrity: sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg==}
+ cpu: [x64]
+ os: [win32]
+
+ '@rollup/rollup-win32-x64-msvc@4.60.1':
+ resolution: {integrity: sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ==}
+ cpu: [x64]
+ os: [win32]
+
+ '@types/babel__core@7.20.5':
+ resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
+
+ '@types/babel__generator@7.27.0':
+ resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==}
+
+ '@types/babel__template@7.4.4':
+ resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==}
+
+ '@types/babel__traverse@7.28.0':
+ resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==}
+
+ '@types/dom-mediacapture-record@1.0.22':
+ resolution: {integrity: sha512-mUMZLK3NvwRLcAAT9qmcK+9p7tpU2FHdDsntR3YI4+GY88XrgG4XiE7u1Q2LAN2/FZOz/tdMDC3GQCR4T8nFuw==}
+
+ '@types/estree@1.0.8':
+ resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
+
+ '@types/json-schema@7.0.15':
+ resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
+
+ '@types/react-dom@19.2.3':
+ resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==}
+ peerDependencies:
+ '@types/react': ^19.2.0
+
+ '@types/react@19.2.14':
+ resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==}
+
+ '@typescript-eslint/eslint-plugin@8.56.1':
+ resolution: {integrity: sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ '@typescript-eslint/parser': ^8.56.1
+ eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
+ typescript: '>=4.8.4 <6.0.0'
+
+ '@typescript-eslint/parser@8.56.1':
+ resolution: {integrity: sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
+ typescript: '>=4.8.4 <6.0.0'
+
+ '@typescript-eslint/project-service@8.56.1':
+ resolution: {integrity: sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ typescript: '>=4.8.4 <6.0.0'
+
+ '@typescript-eslint/scope-manager@8.56.1':
+ resolution: {integrity: sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@typescript-eslint/tsconfig-utils@8.56.1':
+ resolution: {integrity: sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ typescript: '>=4.8.4 <6.0.0'
+
+ '@typescript-eslint/type-utils@8.56.1':
+ resolution: {integrity: sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
+ typescript: '>=4.8.4 <6.0.0'
+
+ '@typescript-eslint/types@8.56.1':
+ resolution: {integrity: sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@typescript-eslint/typescript-estree@8.56.1':
+ resolution: {integrity: sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ typescript: '>=4.8.4 <6.0.0'
+
+ '@typescript-eslint/utils@8.56.1':
+ resolution: {integrity: sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
+ typescript: '>=4.8.4 <6.0.0'
+
+ '@typescript-eslint/visitor-keys@8.56.1':
+ resolution: {integrity: sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@vitejs/plugin-react@4.7.0':
+ resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==}
+ engines: {node: ^14.18.0 || >=16.0.0}
+ peerDependencies:
+ vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
+
+ acorn-jsx@5.3.2:
+ resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
+ peerDependencies:
+ acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+
+ acorn@8.16.0:
+ resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==}
+ engines: {node: '>=0.4.0'}
+ hasBin: true
+
+ ajv@6.14.0:
+ resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==}
+
+ ansi-styles@4.3.0:
+ resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+ engines: {node: '>=8'}
+
+ argparse@2.0.1:
+ resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+
+ balanced-match@1.0.2:
+ resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+
+ balanced-match@4.0.4:
+ resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==}
+ engines: {node: 18 || 20 || >=22}
+
+ baseline-browser-mapping@2.10.0:
+ resolution: {integrity: sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
+ brace-expansion@1.1.14:
+ resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==}
+
+ brace-expansion@5.0.5:
+ resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==}
+ engines: {node: 18 || 20 || >=22}
+
+ braces@3.0.3:
+ resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
+ engines: {node: '>=8'}
+
+ browserslist@4.28.1:
+ resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==}
+ engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+ hasBin: true
+
+ callsites@3.1.0:
+ resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
+ engines: {node: '>=6'}
+
+ caniuse-lite@1.0.30001774:
+ resolution: {integrity: sha512-DDdwPGz99nmIEv216hKSgLD+D4ikHQHjBC/seF98N9CPqRX4M5mSxT9eTV6oyisnJcuzxtZy4n17yKKQYmYQOA==}
+
+ chalk@4.1.2:
+ resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
+ engines: {node: '>=10'}
+
+ clsx@2.1.1:
+ resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
+ engines: {node: '>=6'}
+
+ color-convert@2.0.1:
+ resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+ engines: {node: '>=7.0.0'}
+
+ color-name@1.1.4:
+ resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+
+ concat-map@0.0.1:
+ resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+
+ convert-source-map@2.0.0:
+ resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+
+ cross-spawn@7.0.6:
+ resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
+ engines: {node: '>= 8'}
+
+ csstype@3.2.3:
+ resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
+
+ debug@4.4.3:
+ resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ deep-is@0.1.4:
+ resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
+
+ electron-to-chromium@1.5.302:
+ resolution: {integrity: sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==}
+
+ esbuild@0.25.12:
+ resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==}
+ engines: {node: '>=18'}
+ hasBin: true
+
+ escalade@3.2.0:
+ resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
+ engines: {node: '>=6'}
+
+ escape-string-regexp@4.0.0:
+ resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
+ engines: {node: '>=10'}
+
+ eslint-plugin-react-hooks@5.2.0:
+ resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0
+
+ eslint-plugin-react-refresh@0.4.26:
+ resolution: {integrity: sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ==}
+ peerDependencies:
+ eslint: '>=8.40'
+
+ eslint-scope@8.4.0:
+ resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ eslint-visitor-keys@3.4.3:
+ resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+ eslint-visitor-keys@4.2.1:
+ resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ eslint-visitor-keys@5.0.1:
+ resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==}
+ engines: {node: ^20.19.0 || ^22.13.0 || >=24}
+
+ eslint@9.39.4:
+ resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ hasBin: true
+ peerDependencies:
+ jiti: '*'
+ peerDependenciesMeta:
+ jiti:
+ optional: true
+
+ espree@10.4.0:
+ resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ esquery@1.7.0:
+ resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==}
+ engines: {node: '>=0.10'}
+
+ esrecurse@4.3.0:
+ resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
+ engines: {node: '>=4.0'}
+
+ estraverse@5.3.0:
+ resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
+ engines: {node: '>=4.0'}
+
+ esutils@2.0.3:
+ resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
+ engines: {node: '>=0.10.0'}
+
+ events@3.3.0:
+ resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
+ engines: {node: '>=0.8.x'}
+
+ fast-deep-equal@3.1.3:
+ resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+
+ fast-json-stable-stringify@2.1.0:
+ resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
+
+ fast-levenshtein@2.0.6:
+ resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
+
+ fdir@6.5.0:
+ resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
+ engines: {node: '>=12.0.0'}
+ peerDependencies:
+ picomatch: ^3 || ^4
+ peerDependenciesMeta:
+ picomatch:
+ optional: true
+
+ file-entry-cache@8.0.0:
+ resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
+ engines: {node: '>=16.0.0'}
+
+ fill-range@7.1.1:
+ resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
+ engines: {node: '>=8'}
+
+ find-up@5.0.0:
+ resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
+ engines: {node: '>=10'}
+
+ flat-cache@4.0.1:
+ resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
+ engines: {node: '>=16'}
+
+ flatted@3.4.2:
+ resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==}
+
+ fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
+ gensync@1.0.0-beta.2:
+ resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
+ engines: {node: '>=6.9.0'}
+
+ glob-parent@6.0.2:
+ resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
+ engines: {node: '>=10.13.0'}
+
+ globals@14.0.0:
+ resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
+ engines: {node: '>=18'}
+
+ globals@17.5.0:
+ resolution: {integrity: sha512-qoV+HK2yFl/366t2/Cb3+xxPUo5BuMynomoDmiaZBIdbs+0pYbjfZU+twLhGKp4uCZ/+NbtpVepH5bGCxRyy2g==}
+ engines: {node: '>=18'}
+
+ has-flag@4.0.0:
+ resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
+ engines: {node: '>=8'}
+
+ ignore@5.3.2:
+ resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
+ engines: {node: '>= 4'}
+
+ ignore@7.0.5:
+ resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==}
+ engines: {node: '>= 4'}
+
+ import-fresh@3.3.1:
+ resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
+ engines: {node: '>=6'}
+
+ imurmurhash@0.1.4:
+ resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
+ engines: {node: '>=0.8.19'}
+
+ is-extglob@2.1.1:
+ resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+ engines: {node: '>=0.10.0'}
+
+ is-glob@4.0.3:
+ resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+ engines: {node: '>=0.10.0'}
+
+ is-number@7.0.0:
+ resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+ engines: {node: '>=0.12.0'}
+
+ isexe@2.0.0:
+ resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+
+ jose@6.1.3:
+ resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==}
+
+ js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
+ js-yaml@4.1.1:
+ resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
+ hasBin: true
+
+ jsesc@3.1.0:
+ resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ json-buffer@3.0.1:
+ resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
+
+ json-schema-traverse@0.4.1:
+ resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
+
+ json-stable-stringify-without-jsonify@1.0.1:
+ resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
+
+ json5@2.2.3:
+ resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ keyv@4.5.4:
+ resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
+
+ levn@0.4.1:
+ resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
+ engines: {node: '>= 0.8.0'}
+
+ livekit-client@2.17.2:
+ resolution: {integrity: sha512-+67y2EtAWZabARlY7kANl/VT1Uu1EJYR5a8qwpT2ub/uBCltsEgEDOxCIMwE9HFR5w+z41HR6GL9hyEvW/y6CQ==}
+ peerDependencies:
+ '@types/dom-mediacapture-record': ^1
+
+ locate-path@6.0.0:
+ resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
+ engines: {node: '>=10'}
+
+ lodash.debounce@4.0.8:
+ resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
+
+ lodash.merge@4.6.2:
+ resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+
+ loglevel@1.9.1:
+ resolution: {integrity: sha512-hP3I3kCrDIMuRwAwHltphhDM1r8i55H33GgqjXbrisuJhF4kRhW1dNuxsRklp4bXl8DSdLaNLuiL4A/LWRfxvg==}
+ engines: {node: '>= 0.6.0'}
+
+ loglevel@1.9.2:
+ resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==}
+ engines: {node: '>= 0.6.0'}
+
+ lru-cache@5.1.1:
+ resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+
+ micromatch@4.0.8:
+ resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
+ engines: {node: '>=8.6'}
+
+ minimatch@10.2.5:
+ resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==}
+ engines: {node: 18 || 20 || >=22}
+
+ minimatch@3.1.5:
+ resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==}
+
+ ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+ nanoid@3.3.11:
+ resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+
+ natural-compare@1.4.0:
+ resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+
+ node-releases@2.0.27:
+ resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==}
+
+ optionator@0.9.4:
+ resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
+ engines: {node: '>= 0.8.0'}
+
+ p-limit@3.1.0:
+ resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
+ engines: {node: '>=10'}
+
+ p-locate@5.0.0:
+ resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
+ engines: {node: '>=10'}
+
+ parent-module@1.0.1:
+ resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
+ engines: {node: '>=6'}
+
+ path-exists@4.0.0:
+ resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
+ engines: {node: '>=8'}
+
+ path-key@3.1.1:
+ resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+ engines: {node: '>=8'}
+
+ picocolors@1.1.1:
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+
+ picomatch@2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+
+ picomatch@4.0.4:
+ resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==}
+ engines: {node: '>=12'}
+
+ postcss@8.5.9:
+ resolution: {integrity: sha512-7a70Nsot+EMX9fFU3064K/kdHWZqGVY+BADLyXc8Dfv+mTLLVl6JzJpPaCZ2kQL9gIJvKXSLMHhqdRRjwQeFtw==}
+ engines: {node: ^10 || ^12 || >=14}
+
+ prelude-ls@1.2.1:
+ resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
+ engines: {node: '>= 0.8.0'}
+
+ punycode@2.3.1:
+ resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
+ engines: {node: '>=6'}
+
+ react-dom@19.2.4:
+ resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==}
+ peerDependencies:
+ react: ^19.2.4
+
+ react-refresh@0.17.0:
+ resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==}
+ engines: {node: '>=0.10.0'}
+
+ react@19.2.4:
+ resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==}
+ engines: {node: '>=0.10.0'}
+
+ resolve-from@4.0.0:
+ resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
+ engines: {node: '>=4'}
+
+ rollup@4.60.1:
+ resolution: {integrity: sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==}
+ engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+ hasBin: true
+
+ rxjs@7.8.2:
+ resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==}
+
+ scheduler@0.27.0:
+ resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
+
+ sdp-transform@2.15.0:
+ resolution: {integrity: sha512-KrOH82c/W+GYQ0LHqtr3caRpM3ITglq3ljGUIb8LTki7ByacJZ9z+piSGiwZDsRyhQbYBOBJgr2k6X4BZXi3Kw==}
+ hasBin: true
+
+ sdp@3.2.1:
+ resolution: {integrity: sha512-lwsAIzOPlH8/7IIjjz3K0zYBk7aBVVcvjMwt3M4fLxpjMYyy7i3I97SLHebgn4YBjirkzfp3RvRDWSKsh/+WFw==}
+
+ semver@6.3.1:
+ resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
+ hasBin: true
+
+ semver@7.7.4:
+ resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==}
+ engines: {node: '>=10'}
+ hasBin: true
+
+ shebang-command@2.0.0:
+ resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+ engines: {node: '>=8'}
+
+ shebang-regex@3.0.0:
+ resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+ engines: {node: '>=8'}
+
+ source-map-js@1.2.1:
+ resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
+ engines: {node: '>=0.10.0'}
+
+ strip-json-comments@3.1.1:
+ resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
+ engines: {node: '>=8'}
+
+ supports-color@7.2.0:
+ resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+ engines: {node: '>=8'}
+
+ tinyglobby@0.2.16:
+ resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==}
+ engines: {node: '>=12.0.0'}
+
+ to-regex-range@5.0.1:
+ resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+ engines: {node: '>=8.0'}
+
+ ts-api-utils@2.4.0:
+ resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==}
+ engines: {node: '>=18.12'}
+ peerDependencies:
+ typescript: '>=4.8.4'
+
+ ts-debounce@4.0.0:
+ resolution: {integrity: sha512-+1iDGY6NmOGidq7i7xZGA4cm8DAa6fqdYcvO5Z6yBevH++Bdo9Qt/mN0TzHUgcCcKv1gmh9+W5dHqz8pMWbCbg==}
+
+ tslib@2.8.1:
+ resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
+
+ type-check@0.4.0:
+ resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
+ engines: {node: '>= 0.8.0'}
+
+ typed-emitter@2.1.0:
+ resolution: {integrity: sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA==}
+
+ typescript-eslint@8.56.1:
+ resolution: {integrity: sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
+ typescript: '>=4.8.4 <6.0.0'
+
+ typescript@5.7.3:
+ resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+
+ update-browserslist-db@1.2.3:
+ resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==}
+ hasBin: true
+ peerDependencies:
+ browserslist: '>= 4.21.0'
+
+ uri-js@4.4.1:
+ resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+
+ usehooks-ts@3.1.1:
+ resolution: {integrity: sha512-I4diPp9Cq6ieSUH2wu+fDAVQO43xwtulo+fKEidHUwZPnYImbtkTjzIJYcDcJqxgmX31GVqNFURodvcgHcW0pA==}
+ engines: {node: '>=16.15.0'}
+ peerDependencies:
+ react: ^16.8.0 || ^17 || ^18 || ^19 || ^19.0.0-rc
+
+ vite-plugin-singlefile@2.3.0:
+ resolution: {integrity: sha512-DAcHzYypM0CasNLSz/WG0VdKOCxGHErfrjOoyIPiNxTPTGmO6rRD/te93n1YL/s+miXq66ipF1brMBikf99c6A==}
+ engines: {node: '>18.0.0'}
+ peerDependencies:
+ rollup: ^4.44.1
+ vite: ^5.4.11 || ^6.0.0 || ^7.0.0
+
+ vite@6.4.2:
+ resolution: {integrity: sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ==}
+ engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
+ jiti: '>=1.21.0'
+ less: '*'
+ lightningcss: ^1.21.0
+ sass: '*'
+ sass-embedded: '*'
+ stylus: '*'
+ sugarss: '*'
+ terser: ^5.16.0
+ tsx: ^4.8.1
+ yaml: ^2.4.2
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ jiti:
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ tsx:
+ optional: true
+ yaml:
+ optional: true
+
+ webrtc-adapter@9.0.4:
+ resolution: {integrity: sha512-5ZZY1+lGq8LEKuDlg9M2RPJHlH3R7OVwyHqMcUsLKCgd9Wvf+QrFTCItkXXYPmrJn8H6gRLXbSgxLLdexiqHxw==}
+ engines: {node: '>=6.0.0', npm: '>=3.10.0'}
+
+ which@2.0.2:
+ resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+ engines: {node: '>= 8'}
+ hasBin: true
+
+ word-wrap@1.2.5:
+ resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
+ engines: {node: '>=0.10.0'}
+
+ yallist@3.1.1:
+ resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+
+ yocto-queue@0.1.0:
+ resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
+ engines: {node: '>=10'}
+
+snapshots:
+
+ '@babel/code-frame@7.29.0':
+ dependencies:
+ '@babel/helper-validator-identifier': 7.28.5
+ js-tokens: 4.0.0
+ picocolors: 1.1.1
+
+ '@babel/compat-data@7.29.0': {}
+
+ '@babel/core@7.29.0':
+ dependencies:
+ '@babel/code-frame': 7.29.0
+ '@babel/generator': 7.29.1
+ '@babel/helper-compilation-targets': 7.28.6
+ '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0)
+ '@babel/helpers': 7.28.6
+ '@babel/parser': 7.29.0
+ '@babel/template': 7.28.6
+ '@babel/traverse': 7.29.0
+ '@babel/types': 7.29.0
+ '@jridgewell/remapping': 2.3.5
+ convert-source-map: 2.0.0
+ debug: 4.4.3
+ gensync: 1.0.0-beta.2
+ json5: 2.2.3
+ semver: 6.3.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/generator@7.29.1':
+ dependencies:
+ '@babel/parser': 7.29.0
+ '@babel/types': 7.29.0
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
+ jsesc: 3.1.0
+
+ '@babel/helper-compilation-targets@7.28.6':
+ dependencies:
+ '@babel/compat-data': 7.29.0
+ '@babel/helper-validator-option': 7.27.1
+ browserslist: 4.28.1
+ lru-cache: 5.1.1
+ semver: 6.3.1
+
+ '@babel/helper-globals@7.28.0': {}
+
+ '@babel/helper-module-imports@7.28.6':
+ dependencies:
+ '@babel/traverse': 7.29.0
+ '@babel/types': 7.29.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-module-imports': 7.28.6
+ '@babel/helper-validator-identifier': 7.28.5
+ '@babel/traverse': 7.29.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-plugin-utils@7.28.6': {}
+
+ '@babel/helper-string-parser@7.27.1': {}
+
+ '@babel/helper-validator-identifier@7.28.5': {}
+
+ '@babel/helper-validator-option@7.27.1': {}
+
+ '@babel/helpers@7.28.6':
+ dependencies:
+ '@babel/template': 7.28.6
+ '@babel/types': 7.29.0
+
+ '@babel/parser@7.29.0':
+ dependencies:
+ '@babel/types': 7.29.0
+
+ '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/template@7.28.6':
+ dependencies:
+ '@babel/code-frame': 7.29.0
+ '@babel/parser': 7.29.0
+ '@babel/types': 7.29.0
+
+ '@babel/traverse@7.29.0':
+ dependencies:
+ '@babel/code-frame': 7.29.0
+ '@babel/generator': 7.29.1
+ '@babel/helper-globals': 7.28.0
+ '@babel/parser': 7.29.0
+ '@babel/template': 7.28.6
+ '@babel/types': 7.29.0
+ debug: 4.4.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/types@7.29.0':
+ dependencies:
+ '@babel/helper-string-parser': 7.27.1
+ '@babel/helper-validator-identifier': 7.28.5
+
+ '@bufbuild/protobuf@1.10.1': {}
+
+ '@esbuild/aix-ppc64@0.25.12':
+ optional: true
+
+ '@esbuild/android-arm64@0.25.12':
+ optional: true
+
+ '@esbuild/android-arm@0.25.12':
+ optional: true
+
+ '@esbuild/android-x64@0.25.12':
+ optional: true
+
+ '@esbuild/darwin-arm64@0.25.12':
+ optional: true
+
+ '@esbuild/darwin-x64@0.25.12':
+ optional: true
+
+ '@esbuild/freebsd-arm64@0.25.12':
+ optional: true
+
+ '@esbuild/freebsd-x64@0.25.12':
+ optional: true
+
+ '@esbuild/linux-arm64@0.25.12':
+ optional: true
+
+ '@esbuild/linux-arm@0.25.12':
+ optional: true
+
+ '@esbuild/linux-ia32@0.25.12':
+ optional: true
+
+ '@esbuild/linux-loong64@0.25.12':
+ optional: true
+
+ '@esbuild/linux-mips64el@0.25.12':
+ optional: true
+
+ '@esbuild/linux-ppc64@0.25.12':
+ optional: true
+
+ '@esbuild/linux-riscv64@0.25.12':
+ optional: true
+
+ '@esbuild/linux-s390x@0.25.12':
+ optional: true
+
+ '@esbuild/linux-x64@0.25.12':
+ optional: true
+
+ '@esbuild/netbsd-arm64@0.25.12':
+ optional: true
+
+ '@esbuild/netbsd-x64@0.25.12':
+ optional: true
+
+ '@esbuild/openbsd-arm64@0.25.12':
+ optional: true
+
+ '@esbuild/openbsd-x64@0.25.12':
+ optional: true
+
+ '@esbuild/openharmony-arm64@0.25.12':
+ optional: true
+
+ '@esbuild/sunos-x64@0.25.12':
+ optional: true
+
+ '@esbuild/win32-arm64@0.25.12':
+ optional: true
+
+ '@esbuild/win32-ia32@0.25.12':
+ optional: true
+
+ '@esbuild/win32-x64@0.25.12':
+ optional: true
+
+ '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4)':
+ dependencies:
+ eslint: 9.39.4
+ eslint-visitor-keys: 3.4.3
+
+ '@eslint-community/regexpp@4.12.2': {}
+
+ '@eslint/config-array@0.21.2':
+ dependencies:
+ '@eslint/object-schema': 2.1.7
+ debug: 4.4.3
+ minimatch: 3.1.5
+ transitivePeerDependencies:
+ - supports-color
+
+ '@eslint/config-helpers@0.4.2':
+ dependencies:
+ '@eslint/core': 0.17.0
+
+ '@eslint/core@0.17.0':
+ dependencies:
+ '@types/json-schema': 7.0.15
+
+ '@eslint/eslintrc@3.3.5':
+ dependencies:
+ ajv: 6.14.0
+ debug: 4.4.3
+ espree: 10.4.0
+ globals: 14.0.0
+ ignore: 5.3.2
+ import-fresh: 3.3.1
+ js-yaml: 4.1.1
+ minimatch: 3.1.5
+ strip-json-comments: 3.1.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@eslint/js@9.39.4': {}
+
+ '@eslint/object-schema@2.1.7': {}
+
+ '@eslint/plugin-kit@0.4.1':
+ dependencies:
+ '@eslint/core': 0.17.0
+ levn: 0.4.1
+
+ '@floating-ui/core@1.7.4':
+ dependencies:
+ '@floating-ui/utils': 0.2.10
+
+ '@floating-ui/dom@1.7.4':
+ dependencies:
+ '@floating-ui/core': 1.7.4
+ '@floating-ui/utils': 0.2.10
+
+ '@floating-ui/utils@0.2.10': {}
+
+ '@humanfs/core@0.19.1': {}
+
+ '@humanfs/node@0.16.7':
+ dependencies:
+ '@humanfs/core': 0.19.1
+ '@humanwhocodes/retry': 0.4.3
+
+ '@humanwhocodes/module-importer@1.0.1': {}
+
+ '@humanwhocodes/retry@0.4.3': {}
+
+ '@jridgewell/gen-mapping@0.3.13':
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@jridgewell/remapping@2.3.5':
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@jridgewell/resolve-uri@3.1.2': {}
+
+ '@jridgewell/sourcemap-codec@1.5.5': {}
+
+ '@jridgewell/trace-mapping@0.3.31':
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.5.5
+
+ '@livekit/components-core@0.12.13(livekit-client@2.17.2(@types/dom-mediacapture-record@1.0.22))(tslib@2.8.1)':
+ dependencies:
+ '@floating-ui/dom': 1.7.4
+ livekit-client: 2.17.2(@types/dom-mediacapture-record@1.0.22)
+ loglevel: 1.9.1
+ rxjs: 7.8.2
+ tslib: 2.8.1
+
+ '@livekit/components-react@2.9.20(livekit-client@2.17.2(@types/dom-mediacapture-record@1.0.22))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tslib@2.8.1)':
+ dependencies:
+ '@livekit/components-core': 0.12.13(livekit-client@2.17.2(@types/dom-mediacapture-record@1.0.22))(tslib@2.8.1)
+ clsx: 2.1.1
+ events: 3.3.0
+ jose: 6.1.3
+ livekit-client: 2.17.2(@types/dom-mediacapture-record@1.0.22)
+ react: 19.2.4
+ react-dom: 19.2.4(react@19.2.4)
+ tslib: 2.8.1
+ usehooks-ts: 3.1.1(react@19.2.4)
+
+ '@livekit/components-styles@1.2.0': {}
+
+ '@livekit/mutex@1.1.1': {}
+
+ '@livekit/protocol@1.44.0':
+ dependencies:
+ '@bufbuild/protobuf': 1.10.1
+
+ '@rolldown/pluginutils@1.0.0-beta.27': {}
+
+ '@rollup/rollup-android-arm-eabi@4.60.1':
+ optional: true
+
+ '@rollup/rollup-android-arm64@4.60.1':
+ optional: true
+
+ '@rollup/rollup-darwin-arm64@4.60.1':
+ optional: true
+
+ '@rollup/rollup-darwin-x64@4.60.1':
+ optional: true
+
+ '@rollup/rollup-freebsd-arm64@4.60.1':
+ optional: true
+
+ '@rollup/rollup-freebsd-x64@4.60.1':
+ optional: true
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.60.1':
+ optional: true
+
+ '@rollup/rollup-linux-arm-musleabihf@4.60.1':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-gnu@4.60.1':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-musl@4.60.1':
+ optional: true
+
+ '@rollup/rollup-linux-loong64-gnu@4.60.1':
+ optional: true
+
+ '@rollup/rollup-linux-loong64-musl@4.60.1':
+ optional: true
+
+ '@rollup/rollup-linux-ppc64-gnu@4.60.1':
+ optional: true
+
+ '@rollup/rollup-linux-ppc64-musl@4.60.1':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-gnu@4.60.1':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-musl@4.60.1':
+ optional: true
+
+ '@rollup/rollup-linux-s390x-gnu@4.60.1':
+ optional: true
+
+ '@rollup/rollup-linux-x64-gnu@4.60.1':
+ optional: true
+
+ '@rollup/rollup-linux-x64-musl@4.60.1':
+ optional: true
+
+ '@rollup/rollup-openbsd-x64@4.60.1':
+ optional: true
+
+ '@rollup/rollup-openharmony-arm64@4.60.1':
+ optional: true
+
+ '@rollup/rollup-win32-arm64-msvc@4.60.1':
+ optional: true
+
+ '@rollup/rollup-win32-ia32-msvc@4.60.1':
+ optional: true
+
+ '@rollup/rollup-win32-x64-gnu@4.60.1':
+ optional: true
+
+ '@rollup/rollup-win32-x64-msvc@4.60.1':
+ optional: true
+
+ '@types/babel__core@7.20.5':
+ dependencies:
+ '@babel/parser': 7.29.0
+ '@babel/types': 7.29.0
+ '@types/babel__generator': 7.27.0
+ '@types/babel__template': 7.4.4
+ '@types/babel__traverse': 7.28.0
+
+ '@types/babel__generator@7.27.0':
+ dependencies:
+ '@babel/types': 7.29.0
+
+ '@types/babel__template@7.4.4':
+ dependencies:
+ '@babel/parser': 7.29.0
+ '@babel/types': 7.29.0
+
+ '@types/babel__traverse@7.28.0':
+ dependencies:
+ '@babel/types': 7.29.0
+
+ '@types/dom-mediacapture-record@1.0.22': {}
+
+ '@types/estree@1.0.8': {}
+
+ '@types/json-schema@7.0.15': {}
+
+ '@types/react-dom@19.2.3(@types/react@19.2.14)':
+ dependencies:
+ '@types/react': 19.2.14
+
+ '@types/react@19.2.14':
+ dependencies:
+ csstype: 3.2.3
+
+ '@typescript-eslint/eslint-plugin@8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.39.4)(typescript@5.7.3))(eslint@9.39.4)(typescript@5.7.3)':
+ dependencies:
+ '@eslint-community/regexpp': 4.12.2
+ '@typescript-eslint/parser': 8.56.1(eslint@9.39.4)(typescript@5.7.3)
+ '@typescript-eslint/scope-manager': 8.56.1
+ '@typescript-eslint/type-utils': 8.56.1(eslint@9.39.4)(typescript@5.7.3)
+ '@typescript-eslint/utils': 8.56.1(eslint@9.39.4)(typescript@5.7.3)
+ '@typescript-eslint/visitor-keys': 8.56.1
+ eslint: 9.39.4
+ ignore: 7.0.5
+ natural-compare: 1.4.0
+ ts-api-utils: 2.4.0(typescript@5.7.3)
+ typescript: 5.7.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/parser@8.56.1(eslint@9.39.4)(typescript@5.7.3)':
+ dependencies:
+ '@typescript-eslint/scope-manager': 8.56.1
+ '@typescript-eslint/types': 8.56.1
+ '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.7.3)
+ '@typescript-eslint/visitor-keys': 8.56.1
+ debug: 4.4.3
+ eslint: 9.39.4
+ typescript: 5.7.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/project-service@8.56.1(typescript@5.7.3)':
+ dependencies:
+ '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.7.3)
+ '@typescript-eslint/types': 8.56.1
+ debug: 4.4.3
+ typescript: 5.7.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/scope-manager@8.56.1':
+ dependencies:
+ '@typescript-eslint/types': 8.56.1
+ '@typescript-eslint/visitor-keys': 8.56.1
+
+ '@typescript-eslint/tsconfig-utils@8.56.1(typescript@5.7.3)':
+ dependencies:
+ typescript: 5.7.3
+
+ '@typescript-eslint/type-utils@8.56.1(eslint@9.39.4)(typescript@5.7.3)':
+ dependencies:
+ '@typescript-eslint/types': 8.56.1
+ '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.7.3)
+ '@typescript-eslint/utils': 8.56.1(eslint@9.39.4)(typescript@5.7.3)
+ debug: 4.4.3
+ eslint: 9.39.4
+ ts-api-utils: 2.4.0(typescript@5.7.3)
+ typescript: 5.7.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/types@8.56.1': {}
+
+ '@typescript-eslint/typescript-estree@8.56.1(typescript@5.7.3)':
+ dependencies:
+ '@typescript-eslint/project-service': 8.56.1(typescript@5.7.3)
+ '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.7.3)
+ '@typescript-eslint/types': 8.56.1
+ '@typescript-eslint/visitor-keys': 8.56.1
+ debug: 4.4.3
+ minimatch: 10.2.5
+ semver: 7.7.4
+ tinyglobby: 0.2.16
+ ts-api-utils: 2.4.0(typescript@5.7.3)
+ typescript: 5.7.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/utils@8.56.1(eslint@9.39.4)(typescript@5.7.3)':
+ dependencies:
+ '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4)
+ '@typescript-eslint/scope-manager': 8.56.1
+ '@typescript-eslint/types': 8.56.1
+ '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.7.3)
+ eslint: 9.39.4
+ typescript: 5.7.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/visitor-keys@8.56.1':
+ dependencies:
+ '@typescript-eslint/types': 8.56.1
+ eslint-visitor-keys: 5.0.1
+
+ '@vitejs/plugin-react@4.7.0(vite@6.4.2)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0)
+ '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0)
+ '@rolldown/pluginutils': 1.0.0-beta.27
+ '@types/babel__core': 7.20.5
+ react-refresh: 0.17.0
+ vite: 6.4.2
+ transitivePeerDependencies:
+ - supports-color
+
+ acorn-jsx@5.3.2(acorn@8.16.0):
+ dependencies:
+ acorn: 8.16.0
+
+ acorn@8.16.0: {}
+
+ ajv@6.14.0:
+ dependencies:
+ fast-deep-equal: 3.1.3
+ fast-json-stable-stringify: 2.1.0
+ json-schema-traverse: 0.4.1
+ uri-js: 4.4.1
+
+ ansi-styles@4.3.0:
+ dependencies:
+ color-convert: 2.0.1
+
+ argparse@2.0.1: {}
+
+ balanced-match@1.0.2: {}
+
+ balanced-match@4.0.4: {}
+
+ baseline-browser-mapping@2.10.0: {}
+
+ brace-expansion@1.1.14:
+ dependencies:
+ balanced-match: 1.0.2
+ concat-map: 0.0.1
+
+ brace-expansion@5.0.5:
+ dependencies:
+ balanced-match: 4.0.4
+
+ braces@3.0.3:
+ dependencies:
+ fill-range: 7.1.1
+
+ browserslist@4.28.1:
+ dependencies:
+ baseline-browser-mapping: 2.10.0
+ caniuse-lite: 1.0.30001774
+ electron-to-chromium: 1.5.302
+ node-releases: 2.0.27
+ update-browserslist-db: 1.2.3(browserslist@4.28.1)
+
+ callsites@3.1.0: {}
+
+ caniuse-lite@1.0.30001774: {}
+
+ chalk@4.1.2:
+ dependencies:
+ ansi-styles: 4.3.0
+ supports-color: 7.2.0
+
+ clsx@2.1.1: {}
+
+ color-convert@2.0.1:
+ dependencies:
+ color-name: 1.1.4
+
+ color-name@1.1.4: {}
+
+ concat-map@0.0.1: {}
+
+ convert-source-map@2.0.0: {}
+
+ cross-spawn@7.0.6:
+ dependencies:
+ path-key: 3.1.1
+ shebang-command: 2.0.0
+ which: 2.0.2
+
+ csstype@3.2.3: {}
+
+ debug@4.4.3:
+ dependencies:
+ ms: 2.1.3
+
+ deep-is@0.1.4: {}
+
+ electron-to-chromium@1.5.302: {}
+
+ esbuild@0.25.12:
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.25.12
+ '@esbuild/android-arm': 0.25.12
+ '@esbuild/android-arm64': 0.25.12
+ '@esbuild/android-x64': 0.25.12
+ '@esbuild/darwin-arm64': 0.25.12
+ '@esbuild/darwin-x64': 0.25.12
+ '@esbuild/freebsd-arm64': 0.25.12
+ '@esbuild/freebsd-x64': 0.25.12
+ '@esbuild/linux-arm': 0.25.12
+ '@esbuild/linux-arm64': 0.25.12
+ '@esbuild/linux-ia32': 0.25.12
+ '@esbuild/linux-loong64': 0.25.12
+ '@esbuild/linux-mips64el': 0.25.12
+ '@esbuild/linux-ppc64': 0.25.12
+ '@esbuild/linux-riscv64': 0.25.12
+ '@esbuild/linux-s390x': 0.25.12
+ '@esbuild/linux-x64': 0.25.12
+ '@esbuild/netbsd-arm64': 0.25.12
+ '@esbuild/netbsd-x64': 0.25.12
+ '@esbuild/openbsd-arm64': 0.25.12
+ '@esbuild/openbsd-x64': 0.25.12
+ '@esbuild/openharmony-arm64': 0.25.12
+ '@esbuild/sunos-x64': 0.25.12
+ '@esbuild/win32-arm64': 0.25.12
+ '@esbuild/win32-ia32': 0.25.12
+ '@esbuild/win32-x64': 0.25.12
+
+ escalade@3.2.0: {}
+
+ escape-string-regexp@4.0.0: {}
+
+ eslint-plugin-react-hooks@5.2.0(eslint@9.39.4):
+ dependencies:
+ eslint: 9.39.4
+
+ eslint-plugin-react-refresh@0.4.26(eslint@9.39.4):
+ dependencies:
+ eslint: 9.39.4
+
+ eslint-scope@8.4.0:
+ dependencies:
+ esrecurse: 4.3.0
+ estraverse: 5.3.0
+
+ eslint-visitor-keys@3.4.3: {}
+
+ eslint-visitor-keys@4.2.1: {}
+
+ eslint-visitor-keys@5.0.1: {}
+
+ eslint@9.39.4:
+ dependencies:
+ '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4)
+ '@eslint-community/regexpp': 4.12.2
+ '@eslint/config-array': 0.21.2
+ '@eslint/config-helpers': 0.4.2
+ '@eslint/core': 0.17.0
+ '@eslint/eslintrc': 3.3.5
+ '@eslint/js': 9.39.4
+ '@eslint/plugin-kit': 0.4.1
+ '@humanfs/node': 0.16.7
+ '@humanwhocodes/module-importer': 1.0.1
+ '@humanwhocodes/retry': 0.4.3
+ '@types/estree': 1.0.8
+ ajv: 6.14.0
+ chalk: 4.1.2
+ cross-spawn: 7.0.6
+ debug: 4.4.3
+ escape-string-regexp: 4.0.0
+ eslint-scope: 8.4.0
+ eslint-visitor-keys: 4.2.1
+ espree: 10.4.0
+ esquery: 1.7.0
+ esutils: 2.0.3
+ fast-deep-equal: 3.1.3
+ file-entry-cache: 8.0.0
+ find-up: 5.0.0
+ glob-parent: 6.0.2
+ ignore: 5.3.2
+ imurmurhash: 0.1.4
+ is-glob: 4.0.3
+ json-stable-stringify-without-jsonify: 1.0.1
+ lodash.merge: 4.6.2
+ minimatch: 3.1.5
+ natural-compare: 1.4.0
+ optionator: 0.9.4
+ transitivePeerDependencies:
+ - supports-color
+
+ espree@10.4.0:
+ dependencies:
+ acorn: 8.16.0
+ acorn-jsx: 5.3.2(acorn@8.16.0)
+ eslint-visitor-keys: 4.2.1
+
+ esquery@1.7.0:
+ dependencies:
+ estraverse: 5.3.0
+
+ esrecurse@4.3.0:
+ dependencies:
+ estraverse: 5.3.0
+
+ estraverse@5.3.0: {}
+
+ esutils@2.0.3: {}
+
+ events@3.3.0: {}
+
+ fast-deep-equal@3.1.3: {}
+
+ fast-json-stable-stringify@2.1.0: {}
+
+ fast-levenshtein@2.0.6: {}
+
+ fdir@6.5.0(picomatch@4.0.4):
+ optionalDependencies:
+ picomatch: 4.0.4
+
+ file-entry-cache@8.0.0:
+ dependencies:
+ flat-cache: 4.0.1
+
+ fill-range@7.1.1:
+ dependencies:
+ to-regex-range: 5.0.1
+
+ find-up@5.0.0:
+ dependencies:
+ locate-path: 6.0.0
+ path-exists: 4.0.0
+
+ flat-cache@4.0.1:
+ dependencies:
+ flatted: 3.4.2
+ keyv: 4.5.4
+
+ flatted@3.4.2: {}
+
+ fsevents@2.3.3:
+ optional: true
+
+ gensync@1.0.0-beta.2: {}
+
+ glob-parent@6.0.2:
+ dependencies:
+ is-glob: 4.0.3
+
+ globals@14.0.0: {}
+
+ globals@17.5.0: {}
+
+ has-flag@4.0.0: {}
+
+ ignore@5.3.2: {}
+
+ ignore@7.0.5: {}
+
+ import-fresh@3.3.1:
+ dependencies:
+ parent-module: 1.0.1
+ resolve-from: 4.0.0
+
+ imurmurhash@0.1.4: {}
+
+ is-extglob@2.1.1: {}
+
+ is-glob@4.0.3:
+ dependencies:
+ is-extglob: 2.1.1
+
+ is-number@7.0.0: {}
+
+ isexe@2.0.0: {}
+
+ jose@6.1.3: {}
+
+ js-tokens@4.0.0: {}
+
+ js-yaml@4.1.1:
+ dependencies:
+ argparse: 2.0.1
+
+ jsesc@3.1.0: {}
+
+ json-buffer@3.0.1: {}
+
+ json-schema-traverse@0.4.1: {}
+
+ json-stable-stringify-without-jsonify@1.0.1: {}
+
+ json5@2.2.3: {}
+
+ keyv@4.5.4:
+ dependencies:
+ json-buffer: 3.0.1
+
+ levn@0.4.1:
+ dependencies:
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+
+ livekit-client@2.17.2(@types/dom-mediacapture-record@1.0.22):
+ dependencies:
+ '@livekit/mutex': 1.1.1
+ '@livekit/protocol': 1.44.0
+ '@types/dom-mediacapture-record': 1.0.22
+ events: 3.3.0
+ jose: 6.1.3
+ loglevel: 1.9.2
+ sdp-transform: 2.15.0
+ ts-debounce: 4.0.0
+ tslib: 2.8.1
+ typed-emitter: 2.1.0
+ webrtc-adapter: 9.0.4
+
+ locate-path@6.0.0:
+ dependencies:
+ p-locate: 5.0.0
+
+ lodash.debounce@4.0.8: {}
+
+ lodash.merge@4.6.2: {}
+
+ loglevel@1.9.1: {}
+
+ loglevel@1.9.2: {}
+
+ lru-cache@5.1.1:
+ dependencies:
+ yallist: 3.1.1
+
+ micromatch@4.0.8:
+ dependencies:
+ braces: 3.0.3
+ picomatch: 2.3.1
+
+ minimatch@10.2.5:
+ dependencies:
+ brace-expansion: 5.0.5
+
+ minimatch@3.1.5:
+ dependencies:
+ brace-expansion: 1.1.14
+
+ ms@2.1.3: {}
+
+ nanoid@3.3.11: {}
+
+ natural-compare@1.4.0: {}
+
+ node-releases@2.0.27: {}
+
+ optionator@0.9.4:
+ dependencies:
+ deep-is: 0.1.4
+ fast-levenshtein: 2.0.6
+ levn: 0.4.1
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+ word-wrap: 1.2.5
+
+ p-limit@3.1.0:
+ dependencies:
+ yocto-queue: 0.1.0
+
+ p-locate@5.0.0:
+ dependencies:
+ p-limit: 3.1.0
+
+ parent-module@1.0.1:
+ dependencies:
+ callsites: 3.1.0
+
+ path-exists@4.0.0: {}
+
+ path-key@3.1.1: {}
+
+ picocolors@1.1.1: {}
+
+ picomatch@2.3.1: {}
+
+ picomatch@4.0.4: {}
+
+ postcss@8.5.9:
+ dependencies:
+ nanoid: 3.3.11
+ picocolors: 1.1.1
+ source-map-js: 1.2.1
+
+ prelude-ls@1.2.1: {}
+
+ punycode@2.3.1: {}
+
+ react-dom@19.2.4(react@19.2.4):
+ dependencies:
+ react: 19.2.4
+ scheduler: 0.27.0
+
+ react-refresh@0.17.0: {}
+
+ react@19.2.4: {}
+
+ resolve-from@4.0.0: {}
+
+ rollup@4.60.1:
+ dependencies:
+ '@types/estree': 1.0.8
+ optionalDependencies:
+ '@rollup/rollup-android-arm-eabi': 4.60.1
+ '@rollup/rollup-android-arm64': 4.60.1
+ '@rollup/rollup-darwin-arm64': 4.60.1
+ '@rollup/rollup-darwin-x64': 4.60.1
+ '@rollup/rollup-freebsd-arm64': 4.60.1
+ '@rollup/rollup-freebsd-x64': 4.60.1
+ '@rollup/rollup-linux-arm-gnueabihf': 4.60.1
+ '@rollup/rollup-linux-arm-musleabihf': 4.60.1
+ '@rollup/rollup-linux-arm64-gnu': 4.60.1
+ '@rollup/rollup-linux-arm64-musl': 4.60.1
+ '@rollup/rollup-linux-loong64-gnu': 4.60.1
+ '@rollup/rollup-linux-loong64-musl': 4.60.1
+ '@rollup/rollup-linux-ppc64-gnu': 4.60.1
+ '@rollup/rollup-linux-ppc64-musl': 4.60.1
+ '@rollup/rollup-linux-riscv64-gnu': 4.60.1
+ '@rollup/rollup-linux-riscv64-musl': 4.60.1
+ '@rollup/rollup-linux-s390x-gnu': 4.60.1
+ '@rollup/rollup-linux-x64-gnu': 4.60.1
+ '@rollup/rollup-linux-x64-musl': 4.60.1
+ '@rollup/rollup-openbsd-x64': 4.60.1
+ '@rollup/rollup-openharmony-arm64': 4.60.1
+ '@rollup/rollup-win32-arm64-msvc': 4.60.1
+ '@rollup/rollup-win32-ia32-msvc': 4.60.1
+ '@rollup/rollup-win32-x64-gnu': 4.60.1
+ '@rollup/rollup-win32-x64-msvc': 4.60.1
+ fsevents: 2.3.3
+
+ rxjs@7.8.2:
+ dependencies:
+ tslib: 2.8.1
+
+ scheduler@0.27.0: {}
+
+ sdp-transform@2.15.0: {}
+
+ sdp@3.2.1: {}
+
+ semver@6.3.1: {}
+
+ semver@7.7.4: {}
+
+ shebang-command@2.0.0:
+ dependencies:
+ shebang-regex: 3.0.0
+
+ shebang-regex@3.0.0: {}
+
+ source-map-js@1.2.1: {}
+
+ strip-json-comments@3.1.1: {}
+
+ supports-color@7.2.0:
+ dependencies:
+ has-flag: 4.0.0
+
+ tinyglobby@0.2.16:
+ dependencies:
+ fdir: 6.5.0(picomatch@4.0.4)
+ picomatch: 4.0.4
+
+ to-regex-range@5.0.1:
+ dependencies:
+ is-number: 7.0.0
+
+ ts-api-utils@2.4.0(typescript@5.7.3):
+ dependencies:
+ typescript: 5.7.3
+
+ ts-debounce@4.0.0: {}
+
+ tslib@2.8.1: {}
+
+ type-check@0.4.0:
+ dependencies:
+ prelude-ls: 1.2.1
+
+ typed-emitter@2.1.0:
+ optionalDependencies:
+ rxjs: 7.8.2
+
+ typescript-eslint@8.56.1(eslint@9.39.4)(typescript@5.7.3):
+ dependencies:
+ '@typescript-eslint/eslint-plugin': 8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.39.4)(typescript@5.7.3))(eslint@9.39.4)(typescript@5.7.3)
+ '@typescript-eslint/parser': 8.56.1(eslint@9.39.4)(typescript@5.7.3)
+ '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.7.3)
+ '@typescript-eslint/utils': 8.56.1(eslint@9.39.4)(typescript@5.7.3)
+ eslint: 9.39.4
+ typescript: 5.7.3
+ transitivePeerDependencies:
+ - supports-color
+
+ typescript@5.7.3: {}
+
+ update-browserslist-db@1.2.3(browserslist@4.28.1):
+ dependencies:
+ browserslist: 4.28.1
+ escalade: 3.2.0
+ picocolors: 1.1.1
+
+ uri-js@4.4.1:
+ dependencies:
+ punycode: 2.3.1
+
+ usehooks-ts@3.1.1(react@19.2.4):
+ dependencies:
+ lodash.debounce: 4.0.8
+ react: 19.2.4
+
+ vite-plugin-singlefile@2.3.0(rollup@4.60.1)(vite@6.4.2):
+ dependencies:
+ micromatch: 4.0.8
+ rollup: 4.60.1
+ vite: 6.4.2
+
+ vite@6.4.2:
+ dependencies:
+ esbuild: 0.25.12
+ fdir: 6.5.0(picomatch@4.0.4)
+ picomatch: 4.0.4
+ postcss: 8.5.9
+ rollup: 4.60.1
+ tinyglobby: 0.2.16
+ optionalDependencies:
+ fsevents: 2.3.3
+
+ webrtc-adapter@9.0.4:
+ dependencies:
+ sdp: 3.2.1
+
+ which@2.0.2:
+ dependencies:
+ isexe: 2.0.0
+
+ word-wrap@1.2.5: {}
+
+ yallist@3.1.1: {}
+
+ yocto-queue@0.1.0: {}
diff --git a/livekit-rtc/jupyter-html/src/App.css b/livekit-rtc/jupyter-html/src/App.css
new file mode 100644
index 00000000..d030aa77
--- /dev/null
+++ b/livekit-rtc/jupyter-html/src/App.css
@@ -0,0 +1,135 @@
+:root {
+ --lk-fg: #111;
+ --lk-fg-secondary: #333;
+ --lk-fg-tertiary: #555;
+
+ --lk-bg: #fff;
+ --lk-bg-secondary: #f5f5f5;
+ --lk-bg-tertiary: #fafafa;
+
+ --lk-accent-fg: #fff;
+ --lk-accent-bg: #1f8cf9;
+
+ --lk-danger-fg: #fff;
+ --lk-danger: #f91f31;
+ --lk-danger-text: #6d0311;
+ --lk-danger-bg: #fecdd4;
+
+ --lk-success-fg: #fff;
+ --lk-success: #1ff968;
+ --lk-success-text: #036d26;
+ --lk-success-bg: #cdfedd;
+
+ --lk-control-fg: var(--fg);
+ --lk-control-bg: var(--bg-secondary);
+
+ --lk-connection-excellent: #06db4d;
+ --lk-connection-good: #f9b11f;
+ --lk-connection-poor: #f91f31;
+
+
+ --lk-va-bar-gap: 8px;
+ --lk-va-bar-width: 8px;
+}
+
+
+/* reset unwanted default styles */
+
+.lk-disconnect-button {
+ border: unset;
+ color: unset;
+ font-weight: unset;
+ font-size: 0.8em;
+}
+
+.lk-agent-control-bar {
+ width: 100%;
+ justify-content: space-between;
+}
+
+@media screen and (max-width: 600px) {
+ .lk-start-audio-button {
+ position: unset;
+ top: unset;
+ left: unset;
+ transform: unset;
+ }
+}
+
+.lk-start-audio-button {
+ color: #000;
+ background-color: #dadada;
+}
+
+.app-container {
+ max-width: 800px;
+ margin: 0 auto;
+ padding: 10px;
+}
+
+.content {
+ width: 100%;
+ max-width: 100%;
+ overflow-x: hidden;
+ padding: 0;
+ margin: 0;
+}
+
+.header {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ align-items: center;
+ height: 32px;
+ border-bottom: 1px solid #eee;
+ padding-bottom: 8px;
+ width: 100%;
+}
+
+.header-left {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+}
+
+.header h2 {
+ margin: 0;
+ font-size: 1em;
+ font-weight: normal;
+ color: #444;
+}
+
+.header-controls {
+ display: flex;
+ align-items: center;
+ gap: 15px;
+}
+
+.connection-state,
+.state-inactive {
+ font-size: 0.85em;
+ margin: 0;
+ padding: 0;
+}
+
+.connection-state {
+ color: #0066cc;
+}
+
+.state-inactive {
+ color: #999;
+}
+
+.controls {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
+
+.agent-visualizer {
+ display: flex;
+ flex-direction: row;
+ width: 25%;
+ margin-right: 32px;
+ height: var(--lk-control-bar-height);
+}
\ No newline at end of file
diff --git a/livekit-rtc/jupyter-html/src/App.tsx b/livekit-rtc/jupyter-html/src/App.tsx
new file mode 100644
index 00000000..76244832
--- /dev/null
+++ b/livekit-rtc/jupyter-html/src/App.tsx
@@ -0,0 +1,113 @@
+import React, { useState } from 'react';
+import {
+ LiveKitRoom,
+ BarVisualizer,
+ useVoiceAssistant,
+ RoomAudioRenderer,
+ useConnectionState,
+ DisconnectButton,
+ useStartAudio,
+ VoiceAssistantControlBar,
+} from '@livekit/components-react';
+import '@livekit/components-styles';
+import './App.css';
+import type { SVGProps } from 'react';
+import { ConnectionState } from 'livekit-client';
+
+
+export function getJoinInfo(): { url: string; token: string } {
+ if (import.meta.env.MODE === "development") {
+ const url = import.meta.env.VITE_LIVEKIT_URL;
+ const token = import.meta.env.VITE_LIVEKIT_TOKEN;
+ return { url, token };
+ }
+
+ return { url: "##livekit-url-placeholder##", token: "##livekit-token-placeholder##" };
+}
+
+const LeaveIcon = (props: SVGProps) => (
+
+);
+
+const ConnectedContent: React.FC<{ onDisconnect: () => void }> = ({ onDisconnect }) => {
+ const connectionState = useConnectionState();
+ const { canPlayAudio } = useStartAudio({ props: {} }); // why do I need props..?
+ const { state: agentState, audioTrack } = useVoiceAssistant();
+
+ return (
+
+
+
+
+
+ {canPlayAudio && connectionState == ConnectionState.Connected && agentState !== "connecting" &&
+
+
}
+
+
+ );
+};
+
+const App = () => {
+ const [error, setError] = useState(null);
+ const [isConnected, setIsConnected] = useState(true);
+ const joinInfo = getJoinInfo();
+
+ if (error) return Error: {error}
;
+
+ if (!isConnected) {
+ return (
+
+ );
+ }
+
+ return (
+ setError(err.message)}
+ >
+ setIsConnected(false)} />
+
+
+ );
+};
+export default App;
\ No newline at end of file
diff --git a/livekit-rtc/jupyter-html/src/main.tsx b/livekit-rtc/jupyter-html/src/main.tsx
new file mode 100644
index 00000000..4aff0256
--- /dev/null
+++ b/livekit-rtc/jupyter-html/src/main.tsx
@@ -0,0 +1,9 @@
+import { StrictMode } from 'react'
+import { createRoot } from 'react-dom/client'
+import App from './App.tsx'
+
+createRoot(document.getElementById('root')!).render(
+
+
+ ,
+)
diff --git a/livekit-rtc/jupyter-html/src/vite-env.d.ts b/livekit-rtc/jupyter-html/src/vite-env.d.ts
new file mode 100644
index 00000000..11f02fe2
--- /dev/null
+++ b/livekit-rtc/jupyter-html/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/livekit-rtc/jupyter-html/tsconfig.app.json b/livekit-rtc/jupyter-html/tsconfig.app.json
new file mode 100644
index 00000000..358ca9ba
--- /dev/null
+++ b/livekit-rtc/jupyter-html/tsconfig.app.json
@@ -0,0 +1,26 @@
+{
+ "compilerOptions": {
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "isolatedModules": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+ "jsx": "react-jsx",
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true,
+ "noUncheckedSideEffectImports": true
+ },
+ "include": ["src"]
+}
diff --git a/livekit-rtc/jupyter-html/tsconfig.json b/livekit-rtc/jupyter-html/tsconfig.json
new file mode 100644
index 00000000..1ffef600
--- /dev/null
+++ b/livekit-rtc/jupyter-html/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "files": [],
+ "references": [
+ { "path": "./tsconfig.app.json" },
+ { "path": "./tsconfig.node.json" }
+ ]
+}
diff --git a/livekit-rtc/jupyter-html/tsconfig.node.json b/livekit-rtc/jupyter-html/tsconfig.node.json
new file mode 100644
index 00000000..db0becc8
--- /dev/null
+++ b/livekit-rtc/jupyter-html/tsconfig.node.json
@@ -0,0 +1,24 @@
+{
+ "compilerOptions": {
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
+ "target": "ES2022",
+ "lib": ["ES2023"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "isolatedModules": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true,
+ "noUncheckedSideEffectImports": true
+ },
+ "include": ["vite.config.ts"]
+}
diff --git a/livekit-rtc/jupyter-html/vite.config.ts b/livekit-rtc/jupyter-html/vite.config.ts
new file mode 100644
index 00000000..3b4cae11
--- /dev/null
+++ b/livekit-rtc/jupyter-html/vite.config.ts
@@ -0,0 +1,11 @@
+import { defineConfig } from 'vite';
+import react from '@vitejs/plugin-react';
+import { viteSingleFile } from 'vite-plugin-singlefile';
+
+export default defineConfig({
+ plugins: [
+ react(),
+ viteSingleFile() // This plugin inlines all JS and CSS into index.html
+ ],
+});
+
diff --git a/livekit-rtc/livekit/rtc/__init__.py b/livekit-rtc/livekit/rtc/__init__.py
index c04d96a0..ab67f519 100644
--- a/livekit-rtc/livekit/rtc/__init__.py
+++ b/livekit-rtc/livekit/rtc/__init__.py
@@ -12,10 +12,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-"""LiveKit RTC SDK"""
+"""LiveKit SDK for Python
+`pip install livekit`
+
+See https://docs.livekit.io/home/client/connect/#installing-the-livekit-sdk for more information.
+"""
from ._proto import stats_pb2 as stats
-from ._proto.e2ee_pb2 import EncryptionState, EncryptionType
+from ._proto.e2ee_pb2 import EncryptionState, EncryptionType, KeyDerivationFunction
+from ._proto.participant_pb2 import ParticipantKind, ParticipantState, DisconnectReason
from ._proto.room_pb2 import (
ConnectionQuality,
ConnectionState,
@@ -24,13 +29,19 @@
IceServer,
IceTransportType,
TrackPublishOptions,
+ VideoEncoding,
+)
+from ._proto.track_pb2 import (
+ StreamState,
+ TrackKind,
+ TrackSource,
+ ParticipantTrackPermission,
)
-from ._proto.track_pb2 import StreamState, TrackKind, TrackSource
-from ._proto.video_frame_pb2 import VideoBufferType, VideoRotation
+from ._proto.video_frame_pb2 import VideoBufferType, VideoCodec, VideoRotation
from .audio_frame import AudioFrame
from .audio_source import AudioSource
-from .audio_stream import AudioFrameEvent, AudioStream
-from .chat import ChatManager, ChatMessage
+from .audio_stream import AudioFrameEvent, AudioStream, NoiseCancellationOptions
+from .audio_filter import AudioFilter
from .e2ee import (
E2EEManager,
E2EEOptions,
@@ -38,8 +49,20 @@
KeyProvider,
KeyProviderOptions,
)
-from .participant import LocalParticipant, Participant, RemoteParticipant
-from .room import ConnectError, DataPacket, Room, RoomOptions, RtcConfiguration, SipDTMF
+from .participant import (
+ LocalParticipant,
+ Participant,
+ RemoteParticipant,
+)
+from .room import (
+ ConnectError,
+ DataPacket,
+ Room,
+ RoomOptions,
+ RtcConfiguration,
+ SipDTMF,
+ RtcStats,
+)
from .track import (
AudioTrack,
LocalAudioTrack,
@@ -51,6 +74,7 @@
Track,
VideoTrack,
)
+from .event_emitter import EventEmitter
from .track_publication import (
LocalTrackPublication,
RemoteTrackPublication,
@@ -63,6 +87,37 @@
)
from .video_source import VideoSource
from .video_stream import VideoFrameEvent, VideoStream
+from .audio_resampler import AudioResampler, AudioResamplerQuality
+from .audio_mixer import AudioMixer
+from .apm import AudioProcessingModule
+
+try:
+ from .media_devices import MediaDevices as MediaDevices
+
+ _HAS_MEDIA_DEVICES = True
+except Exception: # pragma: no cover - optional dependency (sounddevice)
+ _HAS_MEDIA_DEVICES = False
+from .utils import combine_audio_frames
+from .rpc import RpcError, RpcInvocationData
+from .synchronizer import AVSynchronizer
+from .data_stream import (
+ TextStreamInfo,
+ ByteStreamInfo,
+ TextStreamReader,
+ TextStreamWriter,
+ ByteStreamWriter,
+ ByteStreamReader,
+)
+from .data_track import (
+ LocalDataTrack,
+ RemoteDataTrack,
+ DataTrackStream,
+ DataTrackFrame,
+ DataTrackInfo,
+ PushFrameError,
+ SubscribeDataTrackError,
+)
+from .frame_processor import FrameProcessor
__all__ = [
"ConnectionQuality",
@@ -74,24 +129,32 @@
"IceServer",
"EncryptionType",
"EncryptionState",
+ "KeyDerivationFunction",
"StreamState",
"TrackKind",
"TrackSource",
+ "ParticipantTrackPermission",
"VideoBufferType",
"VideoRotation",
"stats",
"AudioFrame",
"AudioSource",
"AudioStream",
+ "NoiseCancellationOptions",
+ "AudioFilter",
"AudioFrameEvent",
"LocalParticipant",
"Participant",
+ "ParticipantKind",
+ "ParticipantState",
+ "DisconnectReason",
"RemoteParticipant",
"ConnectError",
"Room",
"RoomOptions",
"RtcConfiguration",
"SipDTMF",
+ "RtcStats",
"DataPacket",
"LocalAudioTrack",
"LocalVideoTrack",
@@ -112,11 +175,38 @@
"TrackPublication",
"Transcription",
"TranscriptionSegment",
+ "VideoCodec",
+ "VideoEncoding",
"VideoFrame",
+ "VideoFrameEvent",
"VideoSource",
"VideoStream",
- "VideoFrameEvent",
- "ChatManager",
- "ChatMessage",
+ "AudioMixer",
+ "AudioResampler",
+ "AudioResamplerQuality",
+ "RpcError",
+ "RpcInvocationData",
+ "EventEmitter",
+ "combine_audio_frames",
+ "AVSynchronizer",
+ "TextStreamInfo",
+ "ByteStreamInfo",
+ "TextStreamReader",
+ "TextStreamWriter",
+ "ByteStreamReader",
+ "ByteStreamWriter",
+ "AudioProcessingModule",
+ "FrameProcessor",
+ "LocalDataTrack",
+ "RemoteDataTrack",
+ "DataTrackStream",
+ "DataTrackFrame",
+ "DataTrackInfo",
+ "PushFrameError",
+ "SubscribeDataTrackError",
"__version__",
]
+
+# add MediaDevices if available
+if _HAS_MEDIA_DEVICES:
+ __all__.append("MediaDevices")
diff --git a/livekit-rtc/livekit/rtc/_event_emitter.py b/livekit-rtc/livekit/rtc/_event_emitter.py
deleted file mode 100644
index 3c534bbe..00000000
--- a/livekit-rtc/livekit/rtc/_event_emitter.py
+++ /dev/null
@@ -1,48 +0,0 @@
-from typing import Callable, Dict, Set, Optional, Generic, TypeVar
-
-T = TypeVar("T")
-
-
-class EventEmitter(Generic[T]):
- def __init__(self) -> None:
- self._events: Dict[T, Set[Callable]] = dict()
-
- def emit(self, event: T, *args, **kwargs) -> None:
- if event in self._events:
- callables = self._events[event].copy()
- for callback in callables:
- callback(*args, **kwargs)
-
- def once(self, event: T, callback: Optional[Callable] = None) -> Callable:
- if callback is not None:
-
- def once_callback(*args, **kwargs):
- self.off(event, once_callback)
- callback(*args, **kwargs)
-
- return self.on(event, once_callback)
- else:
-
- def decorator(callback: Callable) -> Callable:
- self.once(event, callback)
- return callback
-
- return decorator
-
- def on(self, event: T, callback: Optional[Callable] = None) -> Callable:
- if callback is not None:
- if event not in self._events:
- self._events[event] = set()
- self._events[event].add(callback)
- return callback
- else:
-
- def decorator(callback: Callable) -> Callable:
- self.on(event, callback)
- return callback
-
- return decorator
-
- def off(self, event: T, callback: Callable) -> None:
- if event in self._events:
- self._events[event].remove(callback)
diff --git a/livekit-rtc/livekit/rtc/_ffi_client.py b/livekit-rtc/livekit/rtc/_ffi_client.py
index 9412bfba..21a91e97 100644
--- a/livekit-rtc/livekit/rtc/_ffi_client.py
+++ b/livekit-rtc/livekit/rtc/_ffi_client.py
@@ -14,41 +14,47 @@
import signal
import asyncio
+import sys
from contextlib import ExitStack
import ctypes
import importlib.resources
+from .version import __version__
import logging
import os
import platform
import atexit
import threading
-from typing import Generic, List, Optional, TypeVar
+from typing import Callable, Generic, List, Optional, TypeVar
from ._proto import ffi_pb2 as proto_ffi
from ._utils import Queue, classproperty
-
-logger = logging.getLogger("livekit")
+from .log import logger
_resource_files = ExitStack()
atexit.register(_resource_files.close)
+def _lib_name():
+ if platform.system() == "Linux":
+ return "liblivekit_ffi.so"
+ elif platform.system() == "Darwin":
+ return "liblivekit_ffi.dylib"
+ elif platform.system() == "Windows":
+ return "livekit_ffi.dll"
+ return None
+
+
def get_ffi_lib():
# allow to override the lib path using an env var
libpath = os.environ.get("LIVEKIT_LIB_PATH", "").strip()
if libpath:
return ctypes.CDLL(libpath)
- if platform.system() == "Linux":
- libname = "liblivekit_ffi.so"
- elif platform.system() == "Darwin":
- libname = "liblivekit_ffi.dylib"
- elif platform.system() == "Windows":
- libname = "livekit_ffi.dll"
- else:
+ libname = _lib_name()
+ if libname is None:
raise Exception(
- f"no ffi library found for platform {platform.system()}. \
- Set LIVEKIT_LIB_PATH to specify a the lib path"
+ f"no ffi library found for platform {platform.system()}. "
+ "Set LIVEKIT_LIB_PATH to specify the lib path"
)
res = importlib.resources.files("livekit.rtc.resources") / libname
@@ -57,23 +63,8 @@ def get_ffi_lib():
return ctypes.CDLL(str(path))
-ffi_lib = get_ffi_lib()
ffi_cb_fnc = ctypes.CFUNCTYPE(None, ctypes.POINTER(ctypes.c_uint8), ctypes.c_size_t)
-# C function types
-ffi_lib.livekit_ffi_initialize.argtypes = [ffi_cb_fnc, ctypes.c_bool]
-
-ffi_lib.livekit_ffi_request.argtypes = [
- ctypes.POINTER(ctypes.c_ubyte),
- ctypes.c_size_t,
- ctypes.POINTER(ctypes.POINTER(ctypes.c_ubyte)),
- ctypes.POINTER(ctypes.c_size_t),
-]
-ffi_lib.livekit_ffi_request.restype = ctypes.c_uint64
-
-ffi_lib.livekit_ffi_drop_handle.argtypes = [ctypes.c_uint64]
-ffi_lib.livekit_ffi_drop_handle.restype = ctypes.c_bool
-
INVALID_HANDLE = 0
@@ -92,7 +83,10 @@ def disposed(self) -> bool:
def dispose(self) -> None:
if self.handle != INVALID_HANDLE and not self._disposed:
self._disposed = True
- assert ffi_lib.livekit_ffi_drop_handle(ctypes.c_uint64(self.handle))
+ assert FfiClient.instance._ffi_lib.livekit_ffi_drop_handle(ctypes.c_uint64(self.handle))
+
+ def __repr__(self) -> str:
+ return f"FfiHandle({self.handle})"
T = TypeVar("T")
@@ -101,24 +95,55 @@ def dispose(self) -> None:
class FfiQueue(Generic[T]):
def __init__(self) -> None:
self._lock = threading.RLock()
- self._subscribers: List[tuple[Queue[T], asyncio.AbstractEventLoop]] = []
+ # Format: (queue, loop, filter_fn or None)
+ self._subscribers: List[
+ tuple[Queue[T], asyncio.AbstractEventLoop, Optional[Callable[[T], bool]]]
+ ] = []
def put(self, item: T) -> None:
with self._lock:
- for queue, loop in self._subscribers:
- loop.call_soon_threadsafe(queue.put_nowait, item)
-
- def subscribe(self, loop: Optional[asyncio.AbstractEventLoop] = None) -> Queue[T]:
+ for queue, loop, filter_fn in self._subscribers:
+ # If filter provided, skip items that don't match
+ if filter_fn is not None:
+ try:
+ if not filter_fn(item):
+ continue
+ except Exception:
+ pass # On filter error, deliver the item
+
+ try:
+ loop.call_soon_threadsafe(queue.put_nowait, item)
+ except Exception as e:
+ # this could happen if user closes the runloop without unsubscribing first
+ # it's not good when it does occur, but we should not fail the entire runloop
+ logger.error("error putting to queue: %s", e)
+
+ def subscribe(
+ self,
+ loop: Optional[asyncio.AbstractEventLoop] = None,
+ filter_fn: Optional[Callable[[T], bool]] = None,
+ ) -> Queue[T]:
+ """Subscribe to FFI events.
+
+ Args:
+ loop: Event loop to use (defaults to current).
+ filter_fn: Optional filter function. If provided, only items where
+ filter_fn(item) returns True will be delivered.
+ If None, receives all events (original behavior).
+
+ Returns:
+ Queue to receive events from.
+ """
with self._lock:
queue = Queue[T]()
loop = loop or asyncio.get_event_loop()
- self._subscribers.append((queue, loop))
+ self._subscribers.append((queue, loop, filter_fn))
return queue
def unsubscribe(self, queue: Queue[T]) -> None:
with self._lock:
# looping here is ok, since we don't expect a lot of subscribers
- for i, (q, _) in enumerate(self._subscribers):
+ for i, (q, _, _) in enumerate(self._subscribers):
if q == queue:
self._subscribers.pop(i)
break
@@ -129,7 +154,7 @@ def ffi_event_callback(
data_ptr: ctypes.POINTER(ctypes.c_uint8), # type: ignore
data_len: ctypes.c_size_t,
) -> None:
- event_data = bytes(data_ptr[: int(data_len)])
+ event_data = ctypes.string_at(data_ptr, int(data_len))
event = proto_ffi.FfiEvent()
event.ParseFromString(event_data)
@@ -157,7 +182,7 @@ def ffi_event_callback(
return # no need to queue the logs
elif which == "panic":
- logger.critical("Panic: %s", event.panic.message)
+ print("FFI Panic: ", event.panic.message, file=sys.stderr, flush=True)
# We are in a unrecoverable state, terminate the process
os.kill(os.getpid(), signal.SIGTERM)
return
@@ -187,16 +212,51 @@ class FfiClient:
_instance: Optional["FfiClient"] = None
@classproperty
- def instance(self):
- if self._instance is None:
- self._instance = FfiClient()
- return self._instance
+ def instance(cls) -> "FfiClient":
+ if cls._instance is None:
+ cls._instance = FfiClient()
+ return cls._instance
def __init__(self) -> None:
self._lock = threading.RLock()
self._queue = FfiQueue[proto_ffi.FfiEvent]()
- ffi_lib.livekit_ffi_initialize(ffi_event_callback, True)
+ try:
+ self._ffi_lib = get_ffi_lib()
+ except Exception as e:
+ libname = _lib_name() or "livekit_ffi"
+ raise ImportError(
+ "failed to load %s: %s\n"
+ "Install the livekit package with: pip install livekit\n"
+ "Or set LIVEKIT_LIB_PATH to the path of the native library." % (libname, e)
+ ) from None
+ self._ffi_lib.livekit_ffi_initialize.argtypes = [
+ ffi_cb_fnc,
+ ctypes.c_bool,
+ ctypes.c_char_p,
+ ctypes.c_char_p,
+ ]
+ self._ffi_lib.livekit_ffi_request.argtypes = [
+ ctypes.POINTER(ctypes.c_ubyte),
+ ctypes.c_size_t,
+ ctypes.POINTER(ctypes.POINTER(ctypes.c_ubyte)),
+ ctypes.POINTER(ctypes.c_size_t),
+ ]
+ self._ffi_lib.livekit_ffi_request.restype = ctypes.c_uint64
+ self._ffi_lib.livekit_ffi_drop_handle.argtypes = [ctypes.c_uint64]
+ self._ffi_lib.livekit_ffi_drop_handle.restype = ctypes.c_bool
+ self._ffi_lib.livekit_ffi_dispose.argtypes = []
+ self._ffi_lib.livekit_ffi_dispose.restype = None
+
+ self._ffi_lib.livekit_ffi_initialize(
+ ffi_event_callback, True, b"python", __version__.encode("ascii")
+ )
+
+ ffi_lib = self._ffi_lib
+
+ @atexit.register
+ def _dispose_lk_ffi():
+ ffi_lib.livekit_ffi_dispose()
@property
def queue(self) -> FfiQueue[proto_ffi.FfiEvent]:
@@ -209,14 +269,13 @@ def request(self, req: proto_ffi.FfiRequest) -> proto_ffi.FfiResponse:
resp_ptr = ctypes.POINTER(ctypes.c_ubyte)()
resp_len = ctypes.c_size_t()
- handle = ffi_lib.livekit_ffi_request(
+ handle = self._ffi_lib.livekit_ffi_request(
data, proto_len, ctypes.byref(resp_ptr), ctypes.byref(resp_len)
)
assert handle != INVALID_HANDLE
- resp_data = bytes(resp_ptr[: resp_len.value])
+ resp_data = ctypes.string_at(resp_ptr, resp_len.value)
resp = proto_ffi.FfiResponse()
resp.ParseFromString(resp_data)
-
- FfiHandle(handle)
+ FfiHandle(handle).dispose()
return resp
diff --git a/livekit-rtc/livekit/rtc/_proto/audio_frame_pb2.py b/livekit-rtc/livekit/rtc/_proto/audio_frame_pb2.py
index 7bf9939a..c634580d 100644
--- a/livekit-rtc/livekit/rtc/_proto/audio_frame_pb2.py
+++ b/livekit-rtc/livekit/rtc/_proto/audio_frame_pb2.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: audio_frame.proto
-# Protobuf Python Version: 4.25.3
+# Protobuf Python Version: 4.25.1
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
@@ -13,9 +13,10 @@
from . import handle_pb2 as handle__pb2
+from . import track_pb2 as track__pb2
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11\x61udio_frame.proto\x12\rlivekit.proto\x1a\x0chandle.proto\"[\n\x15NewAudioStreamRequest\x12\x14\n\x0ctrack_handle\x18\x01 \x01(\x04\x12,\n\x04type\x18\x02 \x01(\x0e\x32\x1e.livekit.proto.AudioStreamType\"I\n\x16NewAudioStreamResponse\x12/\n\x06stream\x18\x01 \x01(\x0b\x32\x1f.livekit.proto.OwnedAudioStream\"\xb5\x01\n\x15NewAudioSourceRequest\x12,\n\x04type\x18\x01 \x01(\x0e\x32\x1e.livekit.proto.AudioSourceType\x12\x37\n\x07options\x18\x02 \x01(\x0b\x32!.livekit.proto.AudioSourceOptionsH\x00\x88\x01\x01\x12\x13\n\x0bsample_rate\x18\x03 \x01(\r\x12\x14\n\x0cnum_channels\x18\x04 \x01(\rB\n\n\x08_options\"I\n\x16NewAudioSourceResponse\x12/\n\x06source\x18\x01 \x01(\x0b\x32\x1f.livekit.proto.OwnedAudioSource\"f\n\x18\x43\x61ptureAudioFrameRequest\x12\x15\n\rsource_handle\x18\x01 \x01(\x04\x12\x33\n\x06\x62uffer\x18\x02 \x01(\x0b\x32#.livekit.proto.AudioFrameBufferInfo\"-\n\x19\x43\x61ptureAudioFrameResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x01(\x04\"K\n\x19\x43\x61ptureAudioFrameCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x01(\x04\x12\x12\n\x05\x65rror\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_error\"\x1a\n\x18NewAudioResamplerRequest\"R\n\x19NewAudioResamplerResponse\x12\x35\n\tresampler\x18\x01 \x01(\x0b\x32\".livekit.proto.OwnedAudioResampler\"\x93\x01\n\x17RemixAndResampleRequest\x12\x18\n\x10resampler_handle\x18\x01 \x01(\x04\x12\x33\n\x06\x62uffer\x18\x02 \x01(\x0b\x32#.livekit.proto.AudioFrameBufferInfo\x12\x14\n\x0cnum_channels\x18\x03 \x01(\r\x12\x13\n\x0bsample_rate\x18\x04 \x01(\r\"P\n\x18RemixAndResampleResponse\x12\x34\n\x06\x62uffer\x18\x01 \x01(\x0b\x32$.livekit.proto.OwnedAudioFrameBuffer\"p\n\x14\x41udioFrameBufferInfo\x12\x10\n\x08\x64\x61ta_ptr\x18\x01 \x01(\x04\x12\x14\n\x0cnum_channels\x18\x02 \x01(\r\x12\x13\n\x0bsample_rate\x18\x03 \x01(\r\x12\x1b\n\x13samples_per_channel\x18\x04 \x01(\r\"y\n\x15OwnedAudioFrameBuffer\x12-\n\x06handle\x18\x01 \x01(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12\x31\n\x04info\x18\x02 \x01(\x0b\x32#.livekit.proto.AudioFrameBufferInfo\"?\n\x0f\x41udioStreamInfo\x12,\n\x04type\x18\x01 \x01(\x0e\x32\x1e.livekit.proto.AudioStreamType\"o\n\x10OwnedAudioStream\x12-\n\x06handle\x18\x01 \x01(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12,\n\x04info\x18\x02 \x01(\x0b\x32\x1e.livekit.proto.AudioStreamInfo\"\x9f\x01\n\x10\x41udioStreamEvent\x12\x15\n\rstream_handle\x18\x01 \x01(\x04\x12;\n\x0e\x66rame_received\x18\x02 \x01(\x0b\x32!.livekit.proto.AudioFrameReceivedH\x00\x12,\n\x03\x65os\x18\x03 \x01(\x0b\x32\x1d.livekit.proto.AudioStreamEOSH\x00\x42\t\n\x07message\"I\n\x12\x41udioFrameReceived\x12\x33\n\x05\x66rame\x18\x01 \x01(\x0b\x32$.livekit.proto.OwnedAudioFrameBuffer\"\x10\n\x0e\x41udioStreamEOS\"e\n\x12\x41udioSourceOptions\x12\x19\n\x11\x65\x63ho_cancellation\x18\x01 \x01(\x08\x12\x19\n\x11noise_suppression\x18\x02 \x01(\x08\x12\x19\n\x11\x61uto_gain_control\x18\x03 \x01(\x08\"?\n\x0f\x41udioSourceInfo\x12,\n\x04type\x18\x02 \x01(\x0e\x32\x1e.livekit.proto.AudioSourceType\"o\n\x10OwnedAudioSource\x12-\n\x06handle\x18\x01 \x01(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12,\n\x04info\x18\x02 \x01(\x0b\x32\x1e.livekit.proto.AudioSourceInfo\"\x14\n\x12\x41udioResamplerInfo\"u\n\x13OwnedAudioResampler\x12-\n\x06handle\x18\x01 \x01(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12/\n\x04info\x18\x02 \x01(\x0b\x32!.livekit.proto.AudioResamplerInfo*A\n\x0f\x41udioStreamType\x12\x17\n\x13\x41UDIO_STREAM_NATIVE\x10\x00\x12\x15\n\x11\x41UDIO_STREAM_HTML\x10\x01**\n\x0f\x41udioSourceType\x12\x17\n\x13\x41UDIO_SOURCE_NATIVE\x10\x00\x42\x10\xaa\x02\rLiveKit.Protob\x06proto3')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11\x61udio_frame.proto\x12\rlivekit.proto\x1a\x0chandle.proto\x1a\x0btrack.proto\"\xf6\x01\n\x15NewAudioStreamRequest\x12\x14\n\x0ctrack_handle\x18\x01 \x02(\x04\x12,\n\x04type\x18\x02 \x02(\x0e\x32\x1e.livekit.proto.AudioStreamType\x12\x13\n\x0bsample_rate\x18\x03 \x01(\r\x12\x14\n\x0cnum_channels\x18\x04 \x01(\r\x12\x1e\n\x16\x61udio_filter_module_id\x18\x05 \x01(\t\x12\x1c\n\x14\x61udio_filter_options\x18\x06 \x01(\t\x12\x15\n\rframe_size_ms\x18\x07 \x01(\r\x12\x19\n\x11queue_size_frames\x18\x08 \x01(\r\"I\n\x16NewAudioStreamResponse\x12/\n\x06stream\x18\x01 \x02(\x0b\x32\x1f.livekit.proto.OwnedAudioStream\"\xba\x02\n!AudioStreamFromParticipantRequest\x12\x1a\n\x12participant_handle\x18\x01 \x02(\x04\x12,\n\x04type\x18\x02 \x02(\x0e\x32\x1e.livekit.proto.AudioStreamType\x12\x30\n\x0ctrack_source\x18\x03 \x01(\x0e\x32\x1a.livekit.proto.TrackSource\x12\x13\n\x0bsample_rate\x18\x05 \x01(\r\x12\x14\n\x0cnum_channels\x18\x06 \x01(\r\x12\x1e\n\x16\x61udio_filter_module_id\x18\x07 \x01(\t\x12\x1c\n\x14\x61udio_filter_options\x18\x08 \x01(\t\x12\x15\n\rframe_size_ms\x18\t \x01(\r\x12\x19\n\x11queue_size_frames\x18\n \x01(\r\"U\n\"AudioStreamFromParticipantResponse\x12/\n\x06stream\x18\x01 \x02(\x0b\x32\x1f.livekit.proto.OwnedAudioStream\"\xbb\x01\n\x15NewAudioSourceRequest\x12,\n\x04type\x18\x01 \x02(\x0e\x32\x1e.livekit.proto.AudioSourceType\x12\x32\n\x07options\x18\x02 \x01(\x0b\x32!.livekit.proto.AudioSourceOptions\x12\x13\n\x0bsample_rate\x18\x03 \x02(\r\x12\x14\n\x0cnum_channels\x18\x04 \x02(\r\x12\x15\n\rqueue_size_ms\x18\x05 \x01(\r\"I\n\x16NewAudioSourceResponse\x12/\n\x06source\x18\x01 \x02(\x0b\x32\x1f.livekit.proto.OwnedAudioSource\"\x80\x01\n\x18\x43\x61ptureAudioFrameRequest\x12\x15\n\rsource_handle\x18\x01 \x02(\x04\x12\x33\n\x06\x62uffer\x18\x02 \x02(\x0b\x32#.livekit.proto.AudioFrameBufferInfo\x12\x18\n\x10request_async_id\x18\x03 \x01(\x04\"-\n\x19\x43\x61ptureAudioFrameResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"<\n\x19\x43\x61ptureAudioFrameCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"0\n\x17\x43learAudioBufferRequest\x12\x15\n\rsource_handle\x18\x01 \x02(\x04\"\x1a\n\x18\x43learAudioBufferResponse\"\x1a\n\x18NewAudioResamplerRequest\"R\n\x19NewAudioResamplerResponse\x12\x35\n\tresampler\x18\x01 \x02(\x0b\x32\".livekit.proto.OwnedAudioResampler\"\x93\x01\n\x17RemixAndResampleRequest\x12\x18\n\x10resampler_handle\x18\x01 \x02(\x04\x12\x33\n\x06\x62uffer\x18\x02 \x02(\x0b\x32#.livekit.proto.AudioFrameBufferInfo\x12\x14\n\x0cnum_channels\x18\x03 \x02(\r\x12\x13\n\x0bsample_rate\x18\x04 \x02(\r\"P\n\x18RemixAndResampleResponse\x12\x34\n\x06\x62uffer\x18\x01 \x02(\x0b\x32$.livekit.proto.OwnedAudioFrameBuffer\"\x95\x01\n\rNewApmRequest\x12\x1e\n\x16\x65\x63ho_canceller_enabled\x18\x01 \x02(\x08\x12\x1f\n\x17gain_controller_enabled\x18\x02 \x02(\x08\x12 \n\x18high_pass_filter_enabled\x18\x03 \x02(\x08\x12!\n\x19noise_suppression_enabled\x18\x04 \x02(\x08\"6\n\x0eNewApmResponse\x12$\n\x03\x61pm\x18\x01 \x02(\x0b\x32\x17.livekit.proto.OwnedApm\"x\n\x17\x41pmProcessStreamRequest\x12\x12\n\napm_handle\x18\x01 \x02(\x04\x12\x10\n\x08\x64\x61ta_ptr\x18\x02 \x02(\x04\x12\x0c\n\x04size\x18\x03 \x02(\r\x12\x13\n\x0bsample_rate\x18\x04 \x02(\r\x12\x14\n\x0cnum_channels\x18\x05 \x02(\r\")\n\x18\x41pmProcessStreamResponse\x12\r\n\x05\x65rror\x18\x01 \x01(\t\"\x7f\n\x1e\x41pmProcessReverseStreamRequest\x12\x12\n\napm_handle\x18\x01 \x02(\x04\x12\x10\n\x08\x64\x61ta_ptr\x18\x02 \x02(\x04\x12\x0c\n\x04size\x18\x03 \x02(\r\x12\x13\n\x0bsample_rate\x18\x04 \x02(\r\x12\x14\n\x0cnum_channels\x18\x05 \x02(\r\"0\n\x1f\x41pmProcessReverseStreamResponse\x12\r\n\x05\x65rror\x18\x01 \x01(\t\"@\n\x18\x41pmSetStreamDelayRequest\x12\x12\n\napm_handle\x18\x01 \x02(\x04\x12\x10\n\x08\x64\x65lay_ms\x18\x02 \x02(\x05\"*\n\x19\x41pmSetStreamDelayResponse\x12\r\n\x05\x65rror\x18\x01 \x01(\t\"\x9c\x02\n\x16NewSoxResamplerRequest\x12\x12\n\ninput_rate\x18\x01 \x02(\x01\x12\x13\n\x0boutput_rate\x18\x02 \x02(\x01\x12\x14\n\x0cnum_channels\x18\x03 \x02(\r\x12<\n\x0finput_data_type\x18\x04 \x02(\x0e\x32#.livekit.proto.SoxResamplerDataType\x12=\n\x10output_data_type\x18\x05 \x02(\x0e\x32#.livekit.proto.SoxResamplerDataType\x12\x37\n\x0equality_recipe\x18\x06 \x02(\x0e\x32\x1f.livekit.proto.SoxQualityRecipe\x12\r\n\x05\x66lags\x18\x07 \x01(\r\"l\n\x17NewSoxResamplerResponse\x12\x35\n\tresampler\x18\x01 \x01(\x0b\x32 .livekit.proto.OwnedSoxResamplerH\x00\x12\x0f\n\x05\x65rror\x18\x02 \x01(\tH\x00\x42\t\n\x07message\"S\n\x17PushSoxResamplerRequest\x12\x18\n\x10resampler_handle\x18\x01 \x02(\x04\x12\x10\n\x08\x64\x61ta_ptr\x18\x02 \x02(\x04\x12\x0c\n\x04size\x18\x03 \x02(\r\"K\n\x18PushSoxResamplerResponse\x12\x12\n\noutput_ptr\x18\x01 \x02(\x04\x12\x0c\n\x04size\x18\x02 \x02(\r\x12\r\n\x05\x65rror\x18\x03 \x01(\t\"4\n\x18\x46lushSoxResamplerRequest\x12\x18\n\x10resampler_handle\x18\x01 \x02(\x04\"L\n\x19\x46lushSoxResamplerResponse\x12\x12\n\noutput_ptr\x18\x01 \x02(\x04\x12\x0c\n\x04size\x18\x02 \x02(\r\x12\r\n\x05\x65rror\x18\x03 \x01(\t\"p\n\x14\x41udioFrameBufferInfo\x12\x10\n\x08\x64\x61ta_ptr\x18\x01 \x02(\x04\x12\x14\n\x0cnum_channels\x18\x02 \x02(\r\x12\x13\n\x0bsample_rate\x18\x03 \x02(\r\x12\x1b\n\x13samples_per_channel\x18\x04 \x02(\r\"y\n\x15OwnedAudioFrameBuffer\x12-\n\x06handle\x18\x01 \x02(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12\x31\n\x04info\x18\x02 \x02(\x0b\x32#.livekit.proto.AudioFrameBufferInfo\"?\n\x0f\x41udioStreamInfo\x12,\n\x04type\x18\x01 \x02(\x0e\x32\x1e.livekit.proto.AudioStreamType\"o\n\x10OwnedAudioStream\x12-\n\x06handle\x18\x01 \x02(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12,\n\x04info\x18\x02 \x02(\x0b\x32\x1e.livekit.proto.AudioStreamInfo\"\x9f\x01\n\x10\x41udioStreamEvent\x12\x15\n\rstream_handle\x18\x01 \x02(\x04\x12;\n\x0e\x66rame_received\x18\x02 \x01(\x0b\x32!.livekit.proto.AudioFrameReceivedH\x00\x12,\n\x03\x65os\x18\x03 \x01(\x0b\x32\x1d.livekit.proto.AudioStreamEOSH\x00\x42\t\n\x07message\"I\n\x12\x41udioFrameReceived\x12\x33\n\x05\x66rame\x18\x01 \x02(\x0b\x32$.livekit.proto.OwnedAudioFrameBuffer\"\x10\n\x0e\x41udioStreamEOS\"e\n\x12\x41udioSourceOptions\x12\x19\n\x11\x65\x63ho_cancellation\x18\x01 \x02(\x08\x12\x19\n\x11noise_suppression\x18\x02 \x02(\x08\x12\x19\n\x11\x61uto_gain_control\x18\x03 \x02(\x08\"?\n\x0f\x41udioSourceInfo\x12,\n\x04type\x18\x02 \x02(\x0e\x32\x1e.livekit.proto.AudioSourceType\"o\n\x10OwnedAudioSource\x12-\n\x06handle\x18\x01 \x02(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12,\n\x04info\x18\x02 \x02(\x0b\x32\x1e.livekit.proto.AudioSourceInfo\"\x14\n\x12\x41udioResamplerInfo\"u\n\x13OwnedAudioResampler\x12-\n\x06handle\x18\x01 \x02(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12/\n\x04info\x18\x02 \x02(\x0b\x32!.livekit.proto.AudioResamplerInfo\"9\n\x08OwnedApm\x12-\n\x06handle\x18\x01 \x02(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\"\x12\n\x10SoxResamplerInfo\"q\n\x11OwnedSoxResampler\x12-\n\x06handle\x18\x01 \x02(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12-\n\x04info\x18\x02 \x02(\x0b\x32\x1f.livekit.proto.SoxResamplerInfo\"\\\n\x1cLoadAudioFilterPluginRequest\x12\x13\n\x0bplugin_path\x18\x01 \x02(\t\x12\x14\n\x0c\x64\x65pendencies\x18\x02 \x03(\t\x12\x11\n\tmodule_id\x18\x03 \x02(\t\".\n\x1dLoadAudioFilterPluginResponse\x12\r\n\x05\x65rror\x18\x01 \x01(\t*J\n\x14SoxResamplerDataType\x12\x18\n\x14SOXR_DATATYPE_INT16I\x10\x00\x12\x18\n\x14SOXR_DATATYPE_INT16S\x10\x01*\x8b\x01\n\x10SoxQualityRecipe\x12\x16\n\x12SOXR_QUALITY_QUICK\x10\x00\x12\x14\n\x10SOXR_QUALITY_LOW\x10\x01\x12\x17\n\x13SOXR_QUALITY_MEDIUM\x10\x02\x12\x15\n\x11SOXR_QUALITY_HIGH\x10\x03\x12\x19\n\x15SOXR_QUALITY_VERYHIGH\x10\x04*\x97\x01\n\x0bSoxFlagBits\x12\x16\n\x12SOXR_ROLLOFF_SMALL\x10\x00\x12\x17\n\x13SOXR_ROLLOFF_MEDIUM\x10\x01\x12\x15\n\x11SOXR_ROLLOFF_NONE\x10\x02\x12\x18\n\x14SOXR_HIGH_PREC_CLOCK\x10\x03\x12\x19\n\x15SOXR_DOUBLE_PRECISION\x10\x04\x12\x0b\n\x07SOXR_VR\x10\x05*A\n\x0f\x41udioStreamType\x12\x17\n\x13\x41UDIO_STREAM_NATIVE\x10\x00\x12\x15\n\x11\x41UDIO_STREAM_HTML\x10\x01**\n\x0f\x41udioSourceType\x12\x17\n\x13\x41UDIO_SOURCE_NATIVE\x10\x00\x42\x10\xaa\x02\rLiveKit.Proto')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -23,54 +24,106 @@
if _descriptor._USE_C_DESCRIPTORS == False:
_globals['DESCRIPTOR']._options = None
_globals['DESCRIPTOR']._serialized_options = b'\252\002\rLiveKit.Proto'
- _globals['_AUDIOSTREAMTYPE']._serialized_start=2141
- _globals['_AUDIOSTREAMTYPE']._serialized_end=2206
- _globals['_AUDIOSOURCETYPE']._serialized_start=2208
- _globals['_AUDIOSOURCETYPE']._serialized_end=2250
- _globals['_NEWAUDIOSTREAMREQUEST']._serialized_start=50
- _globals['_NEWAUDIOSTREAMREQUEST']._serialized_end=141
- _globals['_NEWAUDIOSTREAMRESPONSE']._serialized_start=143
- _globals['_NEWAUDIOSTREAMRESPONSE']._serialized_end=216
- _globals['_NEWAUDIOSOURCEREQUEST']._serialized_start=219
- _globals['_NEWAUDIOSOURCEREQUEST']._serialized_end=400
- _globals['_NEWAUDIOSOURCERESPONSE']._serialized_start=402
- _globals['_NEWAUDIOSOURCERESPONSE']._serialized_end=475
- _globals['_CAPTUREAUDIOFRAMEREQUEST']._serialized_start=477
- _globals['_CAPTUREAUDIOFRAMEREQUEST']._serialized_end=579
- _globals['_CAPTUREAUDIOFRAMERESPONSE']._serialized_start=581
- _globals['_CAPTUREAUDIOFRAMERESPONSE']._serialized_end=626
- _globals['_CAPTUREAUDIOFRAMECALLBACK']._serialized_start=628
- _globals['_CAPTUREAUDIOFRAMECALLBACK']._serialized_end=703
- _globals['_NEWAUDIORESAMPLERREQUEST']._serialized_start=705
- _globals['_NEWAUDIORESAMPLERREQUEST']._serialized_end=731
- _globals['_NEWAUDIORESAMPLERRESPONSE']._serialized_start=733
- _globals['_NEWAUDIORESAMPLERRESPONSE']._serialized_end=815
- _globals['_REMIXANDRESAMPLEREQUEST']._serialized_start=818
- _globals['_REMIXANDRESAMPLEREQUEST']._serialized_end=965
- _globals['_REMIXANDRESAMPLERESPONSE']._serialized_start=967
- _globals['_REMIXANDRESAMPLERESPONSE']._serialized_end=1047
- _globals['_AUDIOFRAMEBUFFERINFO']._serialized_start=1049
- _globals['_AUDIOFRAMEBUFFERINFO']._serialized_end=1161
- _globals['_OWNEDAUDIOFRAMEBUFFER']._serialized_start=1163
- _globals['_OWNEDAUDIOFRAMEBUFFER']._serialized_end=1284
- _globals['_AUDIOSTREAMINFO']._serialized_start=1286
- _globals['_AUDIOSTREAMINFO']._serialized_end=1349
- _globals['_OWNEDAUDIOSTREAM']._serialized_start=1351
- _globals['_OWNEDAUDIOSTREAM']._serialized_end=1462
- _globals['_AUDIOSTREAMEVENT']._serialized_start=1465
- _globals['_AUDIOSTREAMEVENT']._serialized_end=1624
- _globals['_AUDIOFRAMERECEIVED']._serialized_start=1626
- _globals['_AUDIOFRAMERECEIVED']._serialized_end=1699
- _globals['_AUDIOSTREAMEOS']._serialized_start=1701
- _globals['_AUDIOSTREAMEOS']._serialized_end=1717
- _globals['_AUDIOSOURCEOPTIONS']._serialized_start=1719
- _globals['_AUDIOSOURCEOPTIONS']._serialized_end=1820
- _globals['_AUDIOSOURCEINFO']._serialized_start=1822
- _globals['_AUDIOSOURCEINFO']._serialized_end=1885
- _globals['_OWNEDAUDIOSOURCE']._serialized_start=1887
- _globals['_OWNEDAUDIOSOURCE']._serialized_end=1998
- _globals['_AUDIORESAMPLERINFO']._serialized_start=2000
- _globals['_AUDIORESAMPLERINFO']._serialized_end=2020
- _globals['_OWNEDAUDIORESAMPLER']._serialized_start=2022
- _globals['_OWNEDAUDIORESAMPLER']._serialized_end=2139
+ _globals['_SOXRESAMPLERDATATYPE']._serialized_start=4499
+ _globals['_SOXRESAMPLERDATATYPE']._serialized_end=4573
+ _globals['_SOXQUALITYRECIPE']._serialized_start=4576
+ _globals['_SOXQUALITYRECIPE']._serialized_end=4715
+ _globals['_SOXFLAGBITS']._serialized_start=4718
+ _globals['_SOXFLAGBITS']._serialized_end=4869
+ _globals['_AUDIOSTREAMTYPE']._serialized_start=4871
+ _globals['_AUDIOSTREAMTYPE']._serialized_end=4936
+ _globals['_AUDIOSOURCETYPE']._serialized_start=4938
+ _globals['_AUDIOSOURCETYPE']._serialized_end=4980
+ _globals['_NEWAUDIOSTREAMREQUEST']._serialized_start=64
+ _globals['_NEWAUDIOSTREAMREQUEST']._serialized_end=310
+ _globals['_NEWAUDIOSTREAMRESPONSE']._serialized_start=312
+ _globals['_NEWAUDIOSTREAMRESPONSE']._serialized_end=385
+ _globals['_AUDIOSTREAMFROMPARTICIPANTREQUEST']._serialized_start=388
+ _globals['_AUDIOSTREAMFROMPARTICIPANTREQUEST']._serialized_end=702
+ _globals['_AUDIOSTREAMFROMPARTICIPANTRESPONSE']._serialized_start=704
+ _globals['_AUDIOSTREAMFROMPARTICIPANTRESPONSE']._serialized_end=789
+ _globals['_NEWAUDIOSOURCEREQUEST']._serialized_start=792
+ _globals['_NEWAUDIOSOURCEREQUEST']._serialized_end=979
+ _globals['_NEWAUDIOSOURCERESPONSE']._serialized_start=981
+ _globals['_NEWAUDIOSOURCERESPONSE']._serialized_end=1054
+ _globals['_CAPTUREAUDIOFRAMEREQUEST']._serialized_start=1057
+ _globals['_CAPTUREAUDIOFRAMEREQUEST']._serialized_end=1185
+ _globals['_CAPTUREAUDIOFRAMERESPONSE']._serialized_start=1187
+ _globals['_CAPTUREAUDIOFRAMERESPONSE']._serialized_end=1232
+ _globals['_CAPTUREAUDIOFRAMECALLBACK']._serialized_start=1234
+ _globals['_CAPTUREAUDIOFRAMECALLBACK']._serialized_end=1294
+ _globals['_CLEARAUDIOBUFFERREQUEST']._serialized_start=1296
+ _globals['_CLEARAUDIOBUFFERREQUEST']._serialized_end=1344
+ _globals['_CLEARAUDIOBUFFERRESPONSE']._serialized_start=1346
+ _globals['_CLEARAUDIOBUFFERRESPONSE']._serialized_end=1372
+ _globals['_NEWAUDIORESAMPLERREQUEST']._serialized_start=1374
+ _globals['_NEWAUDIORESAMPLERREQUEST']._serialized_end=1400
+ _globals['_NEWAUDIORESAMPLERRESPONSE']._serialized_start=1402
+ _globals['_NEWAUDIORESAMPLERRESPONSE']._serialized_end=1484
+ _globals['_REMIXANDRESAMPLEREQUEST']._serialized_start=1487
+ _globals['_REMIXANDRESAMPLEREQUEST']._serialized_end=1634
+ _globals['_REMIXANDRESAMPLERESPONSE']._serialized_start=1636
+ _globals['_REMIXANDRESAMPLERESPONSE']._serialized_end=1716
+ _globals['_NEWAPMREQUEST']._serialized_start=1719
+ _globals['_NEWAPMREQUEST']._serialized_end=1868
+ _globals['_NEWAPMRESPONSE']._serialized_start=1870
+ _globals['_NEWAPMRESPONSE']._serialized_end=1924
+ _globals['_APMPROCESSSTREAMREQUEST']._serialized_start=1926
+ _globals['_APMPROCESSSTREAMREQUEST']._serialized_end=2046
+ _globals['_APMPROCESSSTREAMRESPONSE']._serialized_start=2048
+ _globals['_APMPROCESSSTREAMRESPONSE']._serialized_end=2089
+ _globals['_APMPROCESSREVERSESTREAMREQUEST']._serialized_start=2091
+ _globals['_APMPROCESSREVERSESTREAMREQUEST']._serialized_end=2218
+ _globals['_APMPROCESSREVERSESTREAMRESPONSE']._serialized_start=2220
+ _globals['_APMPROCESSREVERSESTREAMRESPONSE']._serialized_end=2268
+ _globals['_APMSETSTREAMDELAYREQUEST']._serialized_start=2270
+ _globals['_APMSETSTREAMDELAYREQUEST']._serialized_end=2334
+ _globals['_APMSETSTREAMDELAYRESPONSE']._serialized_start=2336
+ _globals['_APMSETSTREAMDELAYRESPONSE']._serialized_end=2378
+ _globals['_NEWSOXRESAMPLERREQUEST']._serialized_start=2381
+ _globals['_NEWSOXRESAMPLERREQUEST']._serialized_end=2665
+ _globals['_NEWSOXRESAMPLERRESPONSE']._serialized_start=2667
+ _globals['_NEWSOXRESAMPLERRESPONSE']._serialized_end=2775
+ _globals['_PUSHSOXRESAMPLERREQUEST']._serialized_start=2777
+ _globals['_PUSHSOXRESAMPLERREQUEST']._serialized_end=2860
+ _globals['_PUSHSOXRESAMPLERRESPONSE']._serialized_start=2862
+ _globals['_PUSHSOXRESAMPLERRESPONSE']._serialized_end=2937
+ _globals['_FLUSHSOXRESAMPLERREQUEST']._serialized_start=2939
+ _globals['_FLUSHSOXRESAMPLERREQUEST']._serialized_end=2991
+ _globals['_FLUSHSOXRESAMPLERRESPONSE']._serialized_start=2993
+ _globals['_FLUSHSOXRESAMPLERRESPONSE']._serialized_end=3069
+ _globals['_AUDIOFRAMEBUFFERINFO']._serialized_start=3071
+ _globals['_AUDIOFRAMEBUFFERINFO']._serialized_end=3183
+ _globals['_OWNEDAUDIOFRAMEBUFFER']._serialized_start=3185
+ _globals['_OWNEDAUDIOFRAMEBUFFER']._serialized_end=3306
+ _globals['_AUDIOSTREAMINFO']._serialized_start=3308
+ _globals['_AUDIOSTREAMINFO']._serialized_end=3371
+ _globals['_OWNEDAUDIOSTREAM']._serialized_start=3373
+ _globals['_OWNEDAUDIOSTREAM']._serialized_end=3484
+ _globals['_AUDIOSTREAMEVENT']._serialized_start=3487
+ _globals['_AUDIOSTREAMEVENT']._serialized_end=3646
+ _globals['_AUDIOFRAMERECEIVED']._serialized_start=3648
+ _globals['_AUDIOFRAMERECEIVED']._serialized_end=3721
+ _globals['_AUDIOSTREAMEOS']._serialized_start=3723
+ _globals['_AUDIOSTREAMEOS']._serialized_end=3739
+ _globals['_AUDIOSOURCEOPTIONS']._serialized_start=3741
+ _globals['_AUDIOSOURCEOPTIONS']._serialized_end=3842
+ _globals['_AUDIOSOURCEINFO']._serialized_start=3844
+ _globals['_AUDIOSOURCEINFO']._serialized_end=3907
+ _globals['_OWNEDAUDIOSOURCE']._serialized_start=3909
+ _globals['_OWNEDAUDIOSOURCE']._serialized_end=4020
+ _globals['_AUDIORESAMPLERINFO']._serialized_start=4022
+ _globals['_AUDIORESAMPLERINFO']._serialized_end=4042
+ _globals['_OWNEDAUDIORESAMPLER']._serialized_start=4044
+ _globals['_OWNEDAUDIORESAMPLER']._serialized_end=4161
+ _globals['_OWNEDAPM']._serialized_start=4163
+ _globals['_OWNEDAPM']._serialized_end=4220
+ _globals['_SOXRESAMPLERINFO']._serialized_start=4222
+ _globals['_SOXRESAMPLERINFO']._serialized_end=4240
+ _globals['_OWNEDSOXRESAMPLER']._serialized_start=4242
+ _globals['_OWNEDSOXRESAMPLER']._serialized_end=4355
+ _globals['_LOADAUDIOFILTERPLUGINREQUEST']._serialized_start=4357
+ _globals['_LOADAUDIOFILTERPLUGINREQUEST']._serialized_end=4449
+ _globals['_LOADAUDIOFILTERPLUGINRESPONSE']._serialized_start=4451
+ _globals['_LOADAUDIOFILTERPLUGINRESPONSE']._serialized_end=4497
# @@protoc_insertion_point(module_scope)
diff --git a/livekit-rtc/livekit/rtc/_proto/audio_frame_pb2.pyi b/livekit-rtc/livekit/rtc/_proto/audio_frame_pb2.pyi
index a5097d6b..cb73e1ea 100644
--- a/livekit-rtc/livekit/rtc/_proto/audio_frame_pb2.pyi
+++ b/livekit-rtc/livekit/rtc/_proto/audio_frame_pb2.pyi
@@ -1,7 +1,7 @@
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
-Copyright 2023 LiveKit, Inc.
+Copyright 2025 LiveKit, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,12 +15,16 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
+
import builtins
+import collections.abc
import google.protobuf.descriptor
+import google.protobuf.internal.containers
import google.protobuf.internal.enum_type_wrapper
import google.protobuf.message
from . import handle_pb2
import sys
+from . import track_pb2
import typing
if sys.version_info >= (3, 10):
@@ -30,6 +34,79 @@ else:
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
+class _SoxResamplerDataType:
+ ValueType = typing.NewType("ValueType", builtins.int)
+ V: typing_extensions.TypeAlias = ValueType
+
+class _SoxResamplerDataTypeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_SoxResamplerDataType.ValueType], builtins.type):
+ DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
+ SOXR_DATATYPE_INT16I: _SoxResamplerDataType.ValueType # 0
+ """TODO(theomonnom): support other datatypes (shouldn't really be needed)"""
+ SOXR_DATATYPE_INT16S: _SoxResamplerDataType.ValueType # 1
+
+class SoxResamplerDataType(_SoxResamplerDataType, metaclass=_SoxResamplerDataTypeEnumTypeWrapper): ...
+
+SOXR_DATATYPE_INT16I: SoxResamplerDataType.ValueType # 0
+"""TODO(theomonnom): support other datatypes (shouldn't really be needed)"""
+SOXR_DATATYPE_INT16S: SoxResamplerDataType.ValueType # 1
+global___SoxResamplerDataType = SoxResamplerDataType
+
+class _SoxQualityRecipe:
+ ValueType = typing.NewType("ValueType", builtins.int)
+ V: typing_extensions.TypeAlias = ValueType
+
+class _SoxQualityRecipeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_SoxQualityRecipe.ValueType], builtins.type):
+ DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
+ SOXR_QUALITY_QUICK: _SoxQualityRecipe.ValueType # 0
+ SOXR_QUALITY_LOW: _SoxQualityRecipe.ValueType # 1
+ SOXR_QUALITY_MEDIUM: _SoxQualityRecipe.ValueType # 2
+ SOXR_QUALITY_HIGH: _SoxQualityRecipe.ValueType # 3
+ SOXR_QUALITY_VERYHIGH: _SoxQualityRecipe.ValueType # 4
+
+class SoxQualityRecipe(_SoxQualityRecipe, metaclass=_SoxQualityRecipeEnumTypeWrapper): ...
+
+SOXR_QUALITY_QUICK: SoxQualityRecipe.ValueType # 0
+SOXR_QUALITY_LOW: SoxQualityRecipe.ValueType # 1
+SOXR_QUALITY_MEDIUM: SoxQualityRecipe.ValueType # 2
+SOXR_QUALITY_HIGH: SoxQualityRecipe.ValueType # 3
+SOXR_QUALITY_VERYHIGH: SoxQualityRecipe.ValueType # 4
+global___SoxQualityRecipe = SoxQualityRecipe
+
+class _SoxFlagBits:
+ ValueType = typing.NewType("ValueType", builtins.int)
+ V: typing_extensions.TypeAlias = ValueType
+
+class _SoxFlagBitsEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_SoxFlagBits.ValueType], builtins.type):
+ DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
+ SOXR_ROLLOFF_SMALL: _SoxFlagBits.ValueType # 0
+ """1 << 0"""
+ SOXR_ROLLOFF_MEDIUM: _SoxFlagBits.ValueType # 1
+ """1 << 1"""
+ SOXR_ROLLOFF_NONE: _SoxFlagBits.ValueType # 2
+ """1 << 2"""
+ SOXR_HIGH_PREC_CLOCK: _SoxFlagBits.ValueType # 3
+ """1 << 3"""
+ SOXR_DOUBLE_PRECISION: _SoxFlagBits.ValueType # 4
+ """1 << 4"""
+ SOXR_VR: _SoxFlagBits.ValueType # 5
+ """1 << 5"""
+
+class SoxFlagBits(_SoxFlagBits, metaclass=_SoxFlagBitsEnumTypeWrapper): ...
+
+SOXR_ROLLOFF_SMALL: SoxFlagBits.ValueType # 0
+"""1 << 0"""
+SOXR_ROLLOFF_MEDIUM: SoxFlagBits.ValueType # 1
+"""1 << 1"""
+SOXR_ROLLOFF_NONE: SoxFlagBits.ValueType # 2
+"""1 << 2"""
+SOXR_HIGH_PREC_CLOCK: SoxFlagBits.ValueType # 3
+"""1 << 3"""
+SOXR_DOUBLE_PRECISION: SoxFlagBits.ValueType # 4
+"""1 << 4"""
+SOXR_VR: SoxFlagBits.ValueType # 5
+"""1 << 5"""
+global___SoxFlagBits = SoxFlagBits
+
class _AudioStreamType:
ValueType = typing.NewType("ValueType", builtins.int)
V: typing_extensions.TypeAlias = ValueType
@@ -61,7 +138,7 @@ class AudioSourceType(_AudioSourceType, metaclass=_AudioSourceTypeEnumTypeWrappe
AUDIO_SOURCE_NATIVE: AudioSourceType.ValueType # 0
global___AudioSourceType = AudioSourceType
-@typing_extensions.final
+@typing.final
class NewAudioStreamRequest(google.protobuf.message.Message):
"""Create a new AudioStream
AudioStream is used to receive audio frames from a track
@@ -71,19 +148,49 @@ class NewAudioStreamRequest(google.protobuf.message.Message):
TRACK_HANDLE_FIELD_NUMBER: builtins.int
TYPE_FIELD_NUMBER: builtins.int
+ SAMPLE_RATE_FIELD_NUMBER: builtins.int
+ NUM_CHANNELS_FIELD_NUMBER: builtins.int
+ AUDIO_FILTER_MODULE_ID_FIELD_NUMBER: builtins.int
+ AUDIO_FILTER_OPTIONS_FIELD_NUMBER: builtins.int
+ FRAME_SIZE_MS_FIELD_NUMBER: builtins.int
+ QUEUE_SIZE_FRAMES_FIELD_NUMBER: builtins.int
track_handle: builtins.int
type: global___AudioStreamType.ValueType
+ sample_rate: builtins.int
+ num_channels: builtins.int
+ audio_filter_module_id: builtins.str
+ """Unique identifier passed in LoadAudioFilterPluginRequest"""
+ audio_filter_options: builtins.str
+ frame_size_ms: builtins.int
+ queue_size_frames: builtins.int
+ """Maximum number of queued WebRTC sink frames. Each frame is typically 10 ms
+ of decoded PCM audio on the receive path. Omit this field to use the
+ default bounded queue size of 10 frames. Set it to 0 to request unbounded
+ buffering.
+
+ If your application consumes both audio and video, keep the queue sizing
+ strategy coordinated across both streams. Using a much larger queue, or
+ unbounded buffering, for only one of them can increase end-to-end latency
+ for that stream and cause audio/video drift.
+ """
def __init__(
self,
*,
- track_handle: builtins.int = ...,
- type: global___AudioStreamType.ValueType = ...,
+ track_handle: builtins.int | None = ...,
+ type: global___AudioStreamType.ValueType | None = ...,
+ sample_rate: builtins.int | None = ...,
+ num_channels: builtins.int | None = ...,
+ audio_filter_module_id: builtins.str | None = ...,
+ audio_filter_options: builtins.str | None = ...,
+ frame_size_ms: builtins.int | None = ...,
+ queue_size_frames: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["track_handle", b"track_handle", "type", b"type"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["audio_filter_module_id", b"audio_filter_module_id", "audio_filter_options", b"audio_filter_options", "frame_size_ms", b"frame_size_ms", "num_channels", b"num_channels", "queue_size_frames", b"queue_size_frames", "sample_rate", b"sample_rate", "track_handle", b"track_handle", "type", b"type"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["audio_filter_module_id", b"audio_filter_module_id", "audio_filter_options", b"audio_filter_options", "frame_size_ms", b"frame_size_ms", "num_channels", b"num_channels", "queue_size_frames", b"queue_size_frames", "sample_rate", b"sample_rate", "track_handle", b"track_handle", "type", b"type"]) -> None: ...
global___NewAudioStreamRequest = NewAudioStreamRequest
-@typing_extensions.final
+@typing.final
class NewAudioStreamResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -95,12 +202,79 @@ class NewAudioStreamResponse(google.protobuf.message.Message):
*,
stream: global___OwnedAudioStream | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["stream", b"stream"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["stream", b"stream"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["stream", b"stream"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["stream", b"stream"]) -> None: ...
global___NewAudioStreamResponse = NewAudioStreamResponse
-@typing_extensions.final
+@typing.final
+class AudioStreamFromParticipantRequest(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ PARTICIPANT_HANDLE_FIELD_NUMBER: builtins.int
+ TYPE_FIELD_NUMBER: builtins.int
+ TRACK_SOURCE_FIELD_NUMBER: builtins.int
+ SAMPLE_RATE_FIELD_NUMBER: builtins.int
+ NUM_CHANNELS_FIELD_NUMBER: builtins.int
+ AUDIO_FILTER_MODULE_ID_FIELD_NUMBER: builtins.int
+ AUDIO_FILTER_OPTIONS_FIELD_NUMBER: builtins.int
+ FRAME_SIZE_MS_FIELD_NUMBER: builtins.int
+ QUEUE_SIZE_FRAMES_FIELD_NUMBER: builtins.int
+ participant_handle: builtins.int
+ type: global___AudioStreamType.ValueType
+ track_source: track_pb2.TrackSource.ValueType
+ sample_rate: builtins.int
+ num_channels: builtins.int
+ audio_filter_module_id: builtins.str
+ audio_filter_options: builtins.str
+ frame_size_ms: builtins.int
+ queue_size_frames: builtins.int
+ """Maximum number of queued WebRTC sink frames. Each frame is typically 10 ms
+ of decoded PCM audio on the receive path. Omit this field to use the
+ default bounded queue size of 10 frames. Set it to 0 to request unbounded
+ buffering.
+
+ If your application consumes both audio and video, keep the queue sizing
+ strategy coordinated across both streams. Using a much larger queue, or
+ unbounded buffering, for only one of them can increase end-to-end latency
+ for that stream and cause audio/video drift.
+ """
+ def __init__(
+ self,
+ *,
+ participant_handle: builtins.int | None = ...,
+ type: global___AudioStreamType.ValueType | None = ...,
+ track_source: track_pb2.TrackSource.ValueType | None = ...,
+ sample_rate: builtins.int | None = ...,
+ num_channels: builtins.int | None = ...,
+ audio_filter_module_id: builtins.str | None = ...,
+ audio_filter_options: builtins.str | None = ...,
+ frame_size_ms: builtins.int | None = ...,
+ queue_size_frames: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["audio_filter_module_id", b"audio_filter_module_id", "audio_filter_options", b"audio_filter_options", "frame_size_ms", b"frame_size_ms", "num_channels", b"num_channels", "participant_handle", b"participant_handle", "queue_size_frames", b"queue_size_frames", "sample_rate", b"sample_rate", "track_source", b"track_source", "type", b"type"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["audio_filter_module_id", b"audio_filter_module_id", "audio_filter_options", b"audio_filter_options", "frame_size_ms", b"frame_size_ms", "num_channels", b"num_channels", "participant_handle", b"participant_handle", "queue_size_frames", b"queue_size_frames", "sample_rate", b"sample_rate", "track_source", b"track_source", "type", b"type"]) -> None: ...
+
+global___AudioStreamFromParticipantRequest = AudioStreamFromParticipantRequest
+
+@typing.final
+class AudioStreamFromParticipantResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ STREAM_FIELD_NUMBER: builtins.int
+ @property
+ def stream(self) -> global___OwnedAudioStream: ...
+ def __init__(
+ self,
+ *,
+ stream: global___OwnedAudioStream | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["stream", b"stream"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["stream", b"stream"]) -> None: ...
+
+global___AudioStreamFromParticipantResponse = AudioStreamFromParticipantResponse
+
+@typing.final
class NewAudioSourceRequest(google.protobuf.message.Message):
"""Create a new AudioSource"""
@@ -110,26 +284,28 @@ class NewAudioSourceRequest(google.protobuf.message.Message):
OPTIONS_FIELD_NUMBER: builtins.int
SAMPLE_RATE_FIELD_NUMBER: builtins.int
NUM_CHANNELS_FIELD_NUMBER: builtins.int
+ QUEUE_SIZE_MS_FIELD_NUMBER: builtins.int
type: global___AudioSourceType.ValueType
- @property
- def options(self) -> global___AudioSourceOptions: ...
sample_rate: builtins.int
num_channels: builtins.int
+ queue_size_ms: builtins.int
+ @property
+ def options(self) -> global___AudioSourceOptions: ...
def __init__(
self,
*,
- type: global___AudioSourceType.ValueType = ...,
+ type: global___AudioSourceType.ValueType | None = ...,
options: global___AudioSourceOptions | None = ...,
- sample_rate: builtins.int = ...,
- num_channels: builtins.int = ...,
+ sample_rate: builtins.int | None = ...,
+ num_channels: builtins.int | None = ...,
+ queue_size_ms: builtins.int | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_options", b"_options", "options", b"options"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_options", b"_options", "num_channels", b"num_channels", "options", b"options", "sample_rate", b"sample_rate", "type", b"type"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_options", b"_options"]) -> typing_extensions.Literal["options"] | None: ...
+ def HasField(self, field_name: typing.Literal["num_channels", b"num_channels", "options", b"options", "queue_size_ms", b"queue_size_ms", "sample_rate", b"sample_rate", "type", b"type"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["num_channels", b"num_channels", "options", b"options", "queue_size_ms", b"queue_size_ms", "sample_rate", b"sample_rate", "type", b"type"]) -> None: ...
global___NewAudioSourceRequest = NewAudioSourceRequest
-@typing_extensions.final
+@typing.final
class NewAudioSourceResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -141,14 +317,14 @@ class NewAudioSourceResponse(google.protobuf.message.Message):
*,
source: global___OwnedAudioSource | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["source", b"source"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["source", b"source"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["source", b"source"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["source", b"source"]) -> None: ...
global___NewAudioSourceResponse = NewAudioSourceResponse
-@typing_extensions.final
+@typing.final
class CaptureAudioFrameRequest(google.protobuf.message.Message):
- """Push a frame to an AudioSource
+ """Push a frame to an AudioSource
The data provided must be available as long as the client receive the callback.
"""
@@ -156,21 +332,24 @@ class CaptureAudioFrameRequest(google.protobuf.message.Message):
SOURCE_HANDLE_FIELD_NUMBER: builtins.int
BUFFER_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
source_handle: builtins.int
+ request_async_id: builtins.int
@property
def buffer(self) -> global___AudioFrameBufferInfo: ...
def __init__(
self,
*,
- source_handle: builtins.int = ...,
+ source_handle: builtins.int | None = ...,
buffer: global___AudioFrameBufferInfo | None = ...,
+ request_async_id: builtins.int | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["buffer", b"buffer"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["buffer", b"buffer", "source_handle", b"source_handle"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["buffer", b"buffer", "request_async_id", b"request_async_id", "source_handle", b"source_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["buffer", b"buffer", "request_async_id", b"request_async_id", "source_handle", b"source_handle"]) -> None: ...
global___CaptureAudioFrameRequest = CaptureAudioFrameRequest
-@typing_extensions.final
+@typing.final
class CaptureAudioFrameResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -179,13 +358,14 @@ class CaptureAudioFrameResponse(google.protobuf.message.Message):
def __init__(
self,
*,
- async_id: builtins.int = ...,
+ async_id: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["async_id", b"async_id"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
global___CaptureAudioFrameResponse = CaptureAudioFrameResponse
-@typing_extensions.final
+@typing.final
class CaptureAudioFrameCallback(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -196,16 +376,41 @@ class CaptureAudioFrameCallback(google.protobuf.message.Message):
def __init__(
self,
*,
- async_id: builtins.int = ...,
+ async_id: builtins.int | None = ...,
error: builtins.str | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_error", b"_error", "error", b"error"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_error", b"_error", "async_id", b"async_id", "error", b"error"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_error", b"_error"]) -> typing_extensions.Literal["error"] | None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> None: ...
global___CaptureAudioFrameCallback = CaptureAudioFrameCallback
-@typing_extensions.final
+@typing.final
+class ClearAudioBufferRequest(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ SOURCE_HANDLE_FIELD_NUMBER: builtins.int
+ source_handle: builtins.int
+ def __init__(
+ self,
+ *,
+ source_handle: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["source_handle", b"source_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["source_handle", b"source_handle"]) -> None: ...
+
+global___ClearAudioBufferRequest = ClearAudioBufferRequest
+
+@typing.final
+class ClearAudioBufferResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ def __init__(
+ self,
+ ) -> None: ...
+
+global___ClearAudioBufferResponse = ClearAudioBufferResponse
+
+@typing.final
class NewAudioResamplerRequest(google.protobuf.message.Message):
"""Create a new AudioResampler"""
@@ -217,7 +422,7 @@ class NewAudioResamplerRequest(google.protobuf.message.Message):
global___NewAudioResamplerRequest = NewAudioResamplerRequest
-@typing_extensions.final
+@typing.final
class NewAudioResamplerResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -229,12 +434,12 @@ class NewAudioResamplerResponse(google.protobuf.message.Message):
*,
resampler: global___OwnedAudioResampler | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["resampler", b"resampler"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["resampler", b"resampler"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["resampler", b"resampler"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["resampler", b"resampler"]) -> None: ...
global___NewAudioResamplerResponse = NewAudioResamplerResponse
-@typing_extensions.final
+@typing.final
class RemixAndResampleRequest(google.protobuf.message.Message):
"""Remix and resample an audio frame"""
@@ -245,24 +450,24 @@ class RemixAndResampleRequest(google.protobuf.message.Message):
NUM_CHANNELS_FIELD_NUMBER: builtins.int
SAMPLE_RATE_FIELD_NUMBER: builtins.int
resampler_handle: builtins.int
- @property
- def buffer(self) -> global___AudioFrameBufferInfo: ...
num_channels: builtins.int
sample_rate: builtins.int
+ @property
+ def buffer(self) -> global___AudioFrameBufferInfo: ...
def __init__(
self,
*,
- resampler_handle: builtins.int = ...,
+ resampler_handle: builtins.int | None = ...,
buffer: global___AudioFrameBufferInfo | None = ...,
- num_channels: builtins.int = ...,
- sample_rate: builtins.int = ...,
+ num_channels: builtins.int | None = ...,
+ sample_rate: builtins.int | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["buffer", b"buffer"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["buffer", b"buffer", "num_channels", b"num_channels", "resampler_handle", b"resampler_handle", "sample_rate", b"sample_rate"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["buffer", b"buffer", "num_channels", b"num_channels", "resampler_handle", b"resampler_handle", "sample_rate", b"sample_rate"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["buffer", b"buffer", "num_channels", b"num_channels", "resampler_handle", b"resampler_handle", "sample_rate", b"sample_rate"]) -> None: ...
global___RemixAndResampleRequest = RemixAndResampleRequest
-@typing_extensions.final
+@typing.final
class RemixAndResampleResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -274,12 +479,328 @@ class RemixAndResampleResponse(google.protobuf.message.Message):
*,
buffer: global___OwnedAudioFrameBuffer | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["buffer", b"buffer"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["buffer", b"buffer"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["buffer", b"buffer"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["buffer", b"buffer"]) -> None: ...
global___RemixAndResampleResponse = RemixAndResampleResponse
-@typing_extensions.final
+@typing.final
+class NewApmRequest(google.protobuf.message.Message):
+ """AEC"""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ECHO_CANCELLER_ENABLED_FIELD_NUMBER: builtins.int
+ GAIN_CONTROLLER_ENABLED_FIELD_NUMBER: builtins.int
+ HIGH_PASS_FILTER_ENABLED_FIELD_NUMBER: builtins.int
+ NOISE_SUPPRESSION_ENABLED_FIELD_NUMBER: builtins.int
+ echo_canceller_enabled: builtins.bool
+ gain_controller_enabled: builtins.bool
+ high_pass_filter_enabled: builtins.bool
+ noise_suppression_enabled: builtins.bool
+ def __init__(
+ self,
+ *,
+ echo_canceller_enabled: builtins.bool | None = ...,
+ gain_controller_enabled: builtins.bool | None = ...,
+ high_pass_filter_enabled: builtins.bool | None = ...,
+ noise_suppression_enabled: builtins.bool | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["echo_canceller_enabled", b"echo_canceller_enabled", "gain_controller_enabled", b"gain_controller_enabled", "high_pass_filter_enabled", b"high_pass_filter_enabled", "noise_suppression_enabled", b"noise_suppression_enabled"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["echo_canceller_enabled", b"echo_canceller_enabled", "gain_controller_enabled", b"gain_controller_enabled", "high_pass_filter_enabled", b"high_pass_filter_enabled", "noise_suppression_enabled", b"noise_suppression_enabled"]) -> None: ...
+
+global___NewApmRequest = NewApmRequest
+
+@typing.final
+class NewApmResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ APM_FIELD_NUMBER: builtins.int
+ @property
+ def apm(self) -> global___OwnedApm: ...
+ def __init__(
+ self,
+ *,
+ apm: global___OwnedApm | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["apm", b"apm"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["apm", b"apm"]) -> None: ...
+
+global___NewApmResponse = NewApmResponse
+
+@typing.final
+class ApmProcessStreamRequest(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ APM_HANDLE_FIELD_NUMBER: builtins.int
+ DATA_PTR_FIELD_NUMBER: builtins.int
+ SIZE_FIELD_NUMBER: builtins.int
+ SAMPLE_RATE_FIELD_NUMBER: builtins.int
+ NUM_CHANNELS_FIELD_NUMBER: builtins.int
+ apm_handle: builtins.int
+ data_ptr: builtins.int
+ """*mut i16"""
+ size: builtins.int
+ """in bytes"""
+ sample_rate: builtins.int
+ num_channels: builtins.int
+ def __init__(
+ self,
+ *,
+ apm_handle: builtins.int | None = ...,
+ data_ptr: builtins.int | None = ...,
+ size: builtins.int | None = ...,
+ sample_rate: builtins.int | None = ...,
+ num_channels: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["apm_handle", b"apm_handle", "data_ptr", b"data_ptr", "num_channels", b"num_channels", "sample_rate", b"sample_rate", "size", b"size"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["apm_handle", b"apm_handle", "data_ptr", b"data_ptr", "num_channels", b"num_channels", "sample_rate", b"sample_rate", "size", b"size"]) -> None: ...
+
+global___ApmProcessStreamRequest = ApmProcessStreamRequest
+
+@typing.final
+class ApmProcessStreamResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ERROR_FIELD_NUMBER: builtins.int
+ error: builtins.str
+ def __init__(
+ self,
+ *,
+ error: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["error", b"error"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["error", b"error"]) -> None: ...
+
+global___ApmProcessStreamResponse = ApmProcessStreamResponse
+
+@typing.final
+class ApmProcessReverseStreamRequest(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ APM_HANDLE_FIELD_NUMBER: builtins.int
+ DATA_PTR_FIELD_NUMBER: builtins.int
+ SIZE_FIELD_NUMBER: builtins.int
+ SAMPLE_RATE_FIELD_NUMBER: builtins.int
+ NUM_CHANNELS_FIELD_NUMBER: builtins.int
+ apm_handle: builtins.int
+ data_ptr: builtins.int
+ """*mut i16"""
+ size: builtins.int
+ """in bytes"""
+ sample_rate: builtins.int
+ num_channels: builtins.int
+ def __init__(
+ self,
+ *,
+ apm_handle: builtins.int | None = ...,
+ data_ptr: builtins.int | None = ...,
+ size: builtins.int | None = ...,
+ sample_rate: builtins.int | None = ...,
+ num_channels: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["apm_handle", b"apm_handle", "data_ptr", b"data_ptr", "num_channels", b"num_channels", "sample_rate", b"sample_rate", "size", b"size"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["apm_handle", b"apm_handle", "data_ptr", b"data_ptr", "num_channels", b"num_channels", "sample_rate", b"sample_rate", "size", b"size"]) -> None: ...
+
+global___ApmProcessReverseStreamRequest = ApmProcessReverseStreamRequest
+
+@typing.final
+class ApmProcessReverseStreamResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ERROR_FIELD_NUMBER: builtins.int
+ error: builtins.str
+ def __init__(
+ self,
+ *,
+ error: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["error", b"error"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["error", b"error"]) -> None: ...
+
+global___ApmProcessReverseStreamResponse = ApmProcessReverseStreamResponse
+
+@typing.final
+class ApmSetStreamDelayRequest(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ APM_HANDLE_FIELD_NUMBER: builtins.int
+ DELAY_MS_FIELD_NUMBER: builtins.int
+ apm_handle: builtins.int
+ delay_ms: builtins.int
+ def __init__(
+ self,
+ *,
+ apm_handle: builtins.int | None = ...,
+ delay_ms: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["apm_handle", b"apm_handle", "delay_ms", b"delay_ms"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["apm_handle", b"apm_handle", "delay_ms", b"delay_ms"]) -> None: ...
+
+global___ApmSetStreamDelayRequest = ApmSetStreamDelayRequest
+
+@typing.final
+class ApmSetStreamDelayResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ERROR_FIELD_NUMBER: builtins.int
+ error: builtins.str
+ def __init__(
+ self,
+ *,
+ error: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["error", b"error"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["error", b"error"]) -> None: ...
+
+global___ApmSetStreamDelayResponse = ApmSetStreamDelayResponse
+
+@typing.final
+class NewSoxResamplerRequest(google.protobuf.message.Message):
+ """New resampler using SoX (much better quality)"""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ INPUT_RATE_FIELD_NUMBER: builtins.int
+ OUTPUT_RATE_FIELD_NUMBER: builtins.int
+ NUM_CHANNELS_FIELD_NUMBER: builtins.int
+ INPUT_DATA_TYPE_FIELD_NUMBER: builtins.int
+ OUTPUT_DATA_TYPE_FIELD_NUMBER: builtins.int
+ QUALITY_RECIPE_FIELD_NUMBER: builtins.int
+ FLAGS_FIELD_NUMBER: builtins.int
+ input_rate: builtins.float
+ output_rate: builtins.float
+ num_channels: builtins.int
+ input_data_type: global___SoxResamplerDataType.ValueType
+ output_data_type: global___SoxResamplerDataType.ValueType
+ quality_recipe: global___SoxQualityRecipe.ValueType
+ flags: builtins.int
+ def __init__(
+ self,
+ *,
+ input_rate: builtins.float | None = ...,
+ output_rate: builtins.float | None = ...,
+ num_channels: builtins.int | None = ...,
+ input_data_type: global___SoxResamplerDataType.ValueType | None = ...,
+ output_data_type: global___SoxResamplerDataType.ValueType | None = ...,
+ quality_recipe: global___SoxQualityRecipe.ValueType | None = ...,
+ flags: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["flags", b"flags", "input_data_type", b"input_data_type", "input_rate", b"input_rate", "num_channels", b"num_channels", "output_data_type", b"output_data_type", "output_rate", b"output_rate", "quality_recipe", b"quality_recipe"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["flags", b"flags", "input_data_type", b"input_data_type", "input_rate", b"input_rate", "num_channels", b"num_channels", "output_data_type", b"output_data_type", "output_rate", b"output_rate", "quality_recipe", b"quality_recipe"]) -> None: ...
+
+global___NewSoxResamplerRequest = NewSoxResamplerRequest
+
+@typing.final
+class NewSoxResamplerResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ RESAMPLER_FIELD_NUMBER: builtins.int
+ ERROR_FIELD_NUMBER: builtins.int
+ error: builtins.str
+ @property
+ def resampler(self) -> global___OwnedSoxResampler: ...
+ def __init__(
+ self,
+ *,
+ resampler: global___OwnedSoxResampler | None = ...,
+ error: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["error", b"error", "message", b"message", "resampler", b"resampler"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["error", b"error", "message", b"message", "resampler", b"resampler"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["message", b"message"]) -> typing.Literal["resampler", "error"] | None: ...
+
+global___NewSoxResamplerResponse = NewSoxResamplerResponse
+
+@typing.final
+class PushSoxResamplerRequest(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ RESAMPLER_HANDLE_FIELD_NUMBER: builtins.int
+ DATA_PTR_FIELD_NUMBER: builtins.int
+ SIZE_FIELD_NUMBER: builtins.int
+ resampler_handle: builtins.int
+ data_ptr: builtins.int
+ """*const i16"""
+ size: builtins.int
+ """in bytes"""
+ def __init__(
+ self,
+ *,
+ resampler_handle: builtins.int | None = ...,
+ data_ptr: builtins.int | None = ...,
+ size: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["data_ptr", b"data_ptr", "resampler_handle", b"resampler_handle", "size", b"size"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["data_ptr", b"data_ptr", "resampler_handle", b"resampler_handle", "size", b"size"]) -> None: ...
+
+global___PushSoxResamplerRequest = PushSoxResamplerRequest
+
+@typing.final
+class PushSoxResamplerResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ OUTPUT_PTR_FIELD_NUMBER: builtins.int
+ SIZE_FIELD_NUMBER: builtins.int
+ ERROR_FIELD_NUMBER: builtins.int
+ output_ptr: builtins.int
+ """*const i16 (could be null)"""
+ size: builtins.int
+ """in bytes"""
+ error: builtins.str
+ def __init__(
+ self,
+ *,
+ output_ptr: builtins.int | None = ...,
+ size: builtins.int | None = ...,
+ error: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["error", b"error", "output_ptr", b"output_ptr", "size", b"size"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["error", b"error", "output_ptr", b"output_ptr", "size", b"size"]) -> None: ...
+
+global___PushSoxResamplerResponse = PushSoxResamplerResponse
+
+@typing.final
+class FlushSoxResamplerRequest(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ RESAMPLER_HANDLE_FIELD_NUMBER: builtins.int
+ resampler_handle: builtins.int
+ def __init__(
+ self,
+ *,
+ resampler_handle: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["resampler_handle", b"resampler_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["resampler_handle", b"resampler_handle"]) -> None: ...
+
+global___FlushSoxResamplerRequest = FlushSoxResamplerRequest
+
+@typing.final
+class FlushSoxResamplerResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ OUTPUT_PTR_FIELD_NUMBER: builtins.int
+ SIZE_FIELD_NUMBER: builtins.int
+ ERROR_FIELD_NUMBER: builtins.int
+ output_ptr: builtins.int
+ """*const i16 (could be null)"""
+ size: builtins.int
+ """in bytes"""
+ error: builtins.str
+ def __init__(
+ self,
+ *,
+ output_ptr: builtins.int | None = ...,
+ size: builtins.int | None = ...,
+ error: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["error", b"error", "output_ptr", b"output_ptr", "size", b"size"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["error", b"error", "output_ptr", b"output_ptr", "size", b"size"]) -> None: ...
+
+global___FlushSoxResamplerResponse = FlushSoxResamplerResponse
+
+@typing.final
class AudioFrameBufferInfo(google.protobuf.message.Message):
"""
AudioFrame buffer
@@ -299,16 +820,17 @@ class AudioFrameBufferInfo(google.protobuf.message.Message):
def __init__(
self,
*,
- data_ptr: builtins.int = ...,
- num_channels: builtins.int = ...,
- sample_rate: builtins.int = ...,
- samples_per_channel: builtins.int = ...,
+ data_ptr: builtins.int | None = ...,
+ num_channels: builtins.int | None = ...,
+ sample_rate: builtins.int | None = ...,
+ samples_per_channel: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["data_ptr", b"data_ptr", "num_channels", b"num_channels", "sample_rate", b"sample_rate", "samples_per_channel", b"samples_per_channel"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["data_ptr", b"data_ptr", "num_channels", b"num_channels", "sample_rate", b"sample_rate", "samples_per_channel", b"samples_per_channel"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["data_ptr", b"data_ptr", "num_channels", b"num_channels", "sample_rate", b"sample_rate", "samples_per_channel", b"samples_per_channel"]) -> None: ...
global___AudioFrameBufferInfo = AudioFrameBufferInfo
-@typing_extensions.final
+@typing.final
class OwnedAudioFrameBuffer(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -324,12 +846,12 @@ class OwnedAudioFrameBuffer(google.protobuf.message.Message):
handle: handle_pb2.FfiOwnedHandle | None = ...,
info: global___AudioFrameBufferInfo | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["handle", b"handle", "info", b"info"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["handle", b"handle", "info", b"info"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> None: ...
global___OwnedAudioFrameBuffer = OwnedAudioFrameBuffer
-@typing_extensions.final
+@typing.final
class AudioStreamInfo(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -338,13 +860,14 @@ class AudioStreamInfo(google.protobuf.message.Message):
def __init__(
self,
*,
- type: global___AudioStreamType.ValueType = ...,
+ type: global___AudioStreamType.ValueType | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["type", b"type"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["type", b"type"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["type", b"type"]) -> None: ...
global___AudioStreamInfo = AudioStreamInfo
-@typing_extensions.final
+@typing.final
class OwnedAudioStream(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -360,12 +883,12 @@ class OwnedAudioStream(google.protobuf.message.Message):
handle: handle_pb2.FfiOwnedHandle | None = ...,
info: global___AudioStreamInfo | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["handle", b"handle", "info", b"info"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["handle", b"handle", "info", b"info"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> None: ...
global___OwnedAudioStream = OwnedAudioStream
-@typing_extensions.final
+@typing.final
class AudioStreamEvent(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -380,17 +903,17 @@ class AudioStreamEvent(google.protobuf.message.Message):
def __init__(
self,
*,
- stream_handle: builtins.int = ...,
+ stream_handle: builtins.int | None = ...,
frame_received: global___AudioFrameReceived | None = ...,
eos: global___AudioStreamEOS | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["eos", b"eos", "frame_received", b"frame_received", "message", b"message"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["eos", b"eos", "frame_received", b"frame_received", "message", b"message", "stream_handle", b"stream_handle"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["message", b"message"]) -> typing_extensions.Literal["frame_received", "eos"] | None: ...
+ def HasField(self, field_name: typing.Literal["eos", b"eos", "frame_received", b"frame_received", "message", b"message", "stream_handle", b"stream_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["eos", b"eos", "frame_received", b"frame_received", "message", b"message", "stream_handle", b"stream_handle"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["message", b"message"]) -> typing.Literal["frame_received", "eos"] | None: ...
global___AudioStreamEvent = AudioStreamEvent
-@typing_extensions.final
+@typing.final
class AudioFrameReceived(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -402,12 +925,12 @@ class AudioFrameReceived(google.protobuf.message.Message):
*,
frame: global___OwnedAudioFrameBuffer | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["frame", b"frame"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["frame", b"frame"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["frame", b"frame"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["frame", b"frame"]) -> None: ...
global___AudioFrameReceived = AudioFrameReceived
-@typing_extensions.final
+@typing.final
class AudioStreamEOS(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -417,7 +940,7 @@ class AudioStreamEOS(google.protobuf.message.Message):
global___AudioStreamEOS = AudioStreamEOS
-@typing_extensions.final
+@typing.final
class AudioSourceOptions(google.protobuf.message.Message):
"""
AudioSource
@@ -434,15 +957,16 @@ class AudioSourceOptions(google.protobuf.message.Message):
def __init__(
self,
*,
- echo_cancellation: builtins.bool = ...,
- noise_suppression: builtins.bool = ...,
- auto_gain_control: builtins.bool = ...,
+ echo_cancellation: builtins.bool | None = ...,
+ noise_suppression: builtins.bool | None = ...,
+ auto_gain_control: builtins.bool | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["auto_gain_control", b"auto_gain_control", "echo_cancellation", b"echo_cancellation", "noise_suppression", b"noise_suppression"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["auto_gain_control", b"auto_gain_control", "echo_cancellation", b"echo_cancellation", "noise_suppression", b"noise_suppression"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["auto_gain_control", b"auto_gain_control", "echo_cancellation", b"echo_cancellation", "noise_suppression", b"noise_suppression"]) -> None: ...
global___AudioSourceOptions = AudioSourceOptions
-@typing_extensions.final
+@typing.final
class AudioSourceInfo(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -451,13 +975,14 @@ class AudioSourceInfo(google.protobuf.message.Message):
def __init__(
self,
*,
- type: global___AudioSourceType.ValueType = ...,
+ type: global___AudioSourceType.ValueType | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["type", b"type"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["type", b"type"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["type", b"type"]) -> None: ...
global___AudioSourceInfo = AudioSourceInfo
-@typing_extensions.final
+@typing.final
class OwnedAudioSource(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -473,12 +998,12 @@ class OwnedAudioSource(google.protobuf.message.Message):
handle: handle_pb2.FfiOwnedHandle | None = ...,
info: global___AudioSourceInfo | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["handle", b"handle", "info", b"info"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["handle", b"handle", "info", b"info"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> None: ...
global___OwnedAudioSource = OwnedAudioSource
-@typing_extensions.final
+@typing.final
class AudioResamplerInfo(google.protobuf.message.Message):
"""
AudioResampler
@@ -492,7 +1017,7 @@ class AudioResamplerInfo(google.protobuf.message.Message):
global___AudioResamplerInfo = AudioResamplerInfo
-@typing_extensions.final
+@typing.final
class OwnedAudioResampler(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -508,7 +1033,108 @@ class OwnedAudioResampler(google.protobuf.message.Message):
handle: handle_pb2.FfiOwnedHandle | None = ...,
info: global___AudioResamplerInfo | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["handle", b"handle", "info", b"info"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["handle", b"handle", "info", b"info"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> None: ...
global___OwnedAudioResampler = OwnedAudioResampler
+
+@typing.final
+class OwnedApm(google.protobuf.message.Message):
+ """
+ AEC
+ """
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ HANDLE_FIELD_NUMBER: builtins.int
+ @property
+ def handle(self) -> handle_pb2.FfiOwnedHandle: ...
+ def __init__(
+ self,
+ *,
+ handle: handle_pb2.FfiOwnedHandle | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["handle", b"handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["handle", b"handle"]) -> None: ...
+
+global___OwnedApm = OwnedApm
+
+@typing.final
+class SoxResamplerInfo(google.protobuf.message.Message):
+ """
+ Sox AudioResampler
+ """
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ def __init__(
+ self,
+ ) -> None: ...
+
+global___SoxResamplerInfo = SoxResamplerInfo
+
+@typing.final
+class OwnedSoxResampler(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ HANDLE_FIELD_NUMBER: builtins.int
+ INFO_FIELD_NUMBER: builtins.int
+ @property
+ def handle(self) -> handle_pb2.FfiOwnedHandle: ...
+ @property
+ def info(self) -> global___SoxResamplerInfo: ...
+ def __init__(
+ self,
+ *,
+ handle: handle_pb2.FfiOwnedHandle | None = ...,
+ info: global___SoxResamplerInfo | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> None: ...
+
+global___OwnedSoxResampler = OwnedSoxResampler
+
+@typing.final
+class LoadAudioFilterPluginRequest(google.protobuf.message.Message):
+ """Audio Filter Plugin"""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ PLUGIN_PATH_FIELD_NUMBER: builtins.int
+ DEPENDENCIES_FIELD_NUMBER: builtins.int
+ MODULE_ID_FIELD_NUMBER: builtins.int
+ plugin_path: builtins.str
+ """path for ffi audio filter plugin"""
+ module_id: builtins.str
+ """Unique identifier of the plugin"""
+ @property
+ def dependencies(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]:
+ """Optional: paths for dependency dylibs"""
+
+ def __init__(
+ self,
+ *,
+ plugin_path: builtins.str | None = ...,
+ dependencies: collections.abc.Iterable[builtins.str] | None = ...,
+ module_id: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["module_id", b"module_id", "plugin_path", b"plugin_path"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["dependencies", b"dependencies", "module_id", b"module_id", "plugin_path", b"plugin_path"]) -> None: ...
+
+global___LoadAudioFilterPluginRequest = LoadAudioFilterPluginRequest
+
+@typing.final
+class LoadAudioFilterPluginResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ERROR_FIELD_NUMBER: builtins.int
+ error: builtins.str
+ def __init__(
+ self,
+ *,
+ error: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["error", b"error"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["error", b"error"]) -> None: ...
+
+global___LoadAudioFilterPluginResponse = LoadAudioFilterPluginResponse
diff --git a/livekit-rtc/livekit/rtc/_proto/data_stream_pb2.py b/livekit-rtc/livekit/rtc/_proto/data_stream_pb2.py
new file mode 100644
index 00000000..3d12d60f
--- /dev/null
+++ b/livekit-rtc/livekit/rtc/_proto/data_stream_pb2.py
@@ -0,0 +1,155 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: data_stream.proto
+# Protobuf Python Version: 4.25.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from . import handle_pb2 as handle__pb2
+from . import e2ee_pb2 as e2ee__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11\x64\x61ta_stream.proto\x12\rlivekit.proto\x1a\x0chandle.proto\x1a\ne2ee.proto\"s\n\x15OwnedTextStreamReader\x12-\n\x06handle\x18\x01 \x02(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12+\n\x04info\x18\x02 \x02(\x0b\x32\x1d.livekit.proto.TextStreamInfo\"?\n&TextStreamReaderReadIncrementalRequest\x12\x15\n\rreader_handle\x18\x01 \x02(\x04\")\n\'TextStreamReaderReadIncrementalResponse\"Q\n\x1eTextStreamReaderReadAllRequest\x12\x15\n\rreader_handle\x18\x01 \x02(\x04\x12\x18\n\x10request_async_id\x18\x02 \x01(\x04\"3\n\x1fTextStreamReaderReadAllResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"}\n\x1fTextStreamReaderReadAllCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12\x11\n\x07\x63ontent\x18\x02 \x01(\tH\x00\x12+\n\x05\x65rror\x18\x03 \x01(\x0b\x32\x1a.livekit.proto.StreamErrorH\x00\x42\x08\n\x06result\"\xb3\x01\n\x15TextStreamReaderEvent\x12\x15\n\rreader_handle\x18\x01 \x02(\x04\x12\x46\n\x0e\x63hunk_received\x18\x02 \x01(\x0b\x32,.livekit.proto.TextStreamReaderChunkReceivedH\x00\x12\x31\n\x03\x65os\x18\x03 \x01(\x0b\x32\".livekit.proto.TextStreamReaderEOSH\x00\x42\x08\n\x06\x64\x65tail\"0\n\x1dTextStreamReaderChunkReceived\x12\x0f\n\x07\x63ontent\x18\x01 \x02(\t\"@\n\x13TextStreamReaderEOS\x12)\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x1a.livekit.proto.StreamError\"s\n\x15OwnedByteStreamReader\x12-\n\x06handle\x18\x01 \x02(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12+\n\x04info\x18\x02 \x02(\x0b\x32\x1d.livekit.proto.ByteStreamInfo\"?\n&ByteStreamReaderReadIncrementalRequest\x12\x15\n\rreader_handle\x18\x01 \x02(\x04\")\n\'ByteStreamReaderReadIncrementalResponse\"Q\n\x1e\x42yteStreamReaderReadAllRequest\x12\x15\n\rreader_handle\x18\x01 \x02(\x04\x12\x18\n\x10request_async_id\x18\x02 \x01(\x04\"3\n\x1f\x42yteStreamReaderReadAllResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"}\n\x1f\x42yteStreamReaderReadAllCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12\x11\n\x07\x63ontent\x18\x02 \x01(\x0cH\x00\x12+\n\x05\x65rror\x18\x03 \x01(\x0b\x32\x1a.livekit.proto.StreamErrorH\x00\x42\x08\n\x06result\"\x7f\n\"ByteStreamReaderWriteToFileRequest\x12\x15\n\rreader_handle\x18\x01 \x02(\x04\x12\x18\n\x10request_async_id\x18\x02 \x01(\x04\x12\x11\n\tdirectory\x18\x03 \x01(\t\x12\x15\n\rname_override\x18\x04 \x01(\t\"7\n#ByteStreamReaderWriteToFileResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"\x83\x01\n#ByteStreamReaderWriteToFileCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12\x13\n\tfile_path\x18\x02 \x01(\tH\x00\x12+\n\x05\x65rror\x18\x03 \x01(\x0b\x32\x1a.livekit.proto.StreamErrorH\x00\x42\x08\n\x06result\"\xb3\x01\n\x15\x42yteStreamReaderEvent\x12\x15\n\rreader_handle\x18\x01 \x02(\x04\x12\x46\n\x0e\x63hunk_received\x18\x02 \x01(\x0b\x32,.livekit.proto.ByteStreamReaderChunkReceivedH\x00\x12\x31\n\x03\x65os\x18\x03 \x01(\x0b\x32\".livekit.proto.ByteStreamReaderEOSH\x00\x42\x08\n\x06\x64\x65tail\"0\n\x1d\x42yteStreamReaderChunkReceived\x12\x0f\n\x07\x63ontent\x18\x01 \x02(\x0c\"@\n\x13\x42yteStreamReaderEOS\x12)\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x1a.livekit.proto.StreamError\"\x99\x01\n\x15StreamSendFileRequest\x12 \n\x18local_participant_handle\x18\x01 \x02(\x04\x12\x31\n\x07options\x18\x02 \x02(\x0b\x32 .livekit.proto.StreamByteOptions\x12\x11\n\tfile_path\x18\x03 \x02(\t\x12\x18\n\x10request_async_id\x18\x04 \x01(\x04\"*\n\x16StreamSendFileResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"\x90\x01\n\x16StreamSendFileCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12-\n\x04info\x18\x02 \x01(\x0b\x32\x1d.livekit.proto.ByteStreamInfoH\x00\x12+\n\x05\x65rror\x18\x03 \x01(\x0b\x32\x1a.livekit.proto.StreamErrorH\x00\x42\x08\n\x06result\"\x96\x01\n\x16StreamSendBytesRequest\x12 \n\x18local_participant_handle\x18\x01 \x02(\x04\x12\x31\n\x07options\x18\x02 \x02(\x0b\x32 .livekit.proto.StreamByteOptions\x12\r\n\x05\x62ytes\x18\x03 \x02(\x0c\x12\x18\n\x10request_async_id\x18\x04 \x01(\x04\"+\n\x17StreamSendBytesResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"\x91\x01\n\x17StreamSendBytesCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12-\n\x04info\x18\x02 \x01(\x0b\x32\x1d.livekit.proto.ByteStreamInfoH\x00\x12+\n\x05\x65rror\x18\x03 \x01(\x0b\x32\x1a.livekit.proto.StreamErrorH\x00\x42\x08\n\x06result\"\x94\x01\n\x15StreamSendTextRequest\x12 \n\x18local_participant_handle\x18\x01 \x02(\x04\x12\x31\n\x07options\x18\x02 \x02(\x0b\x32 .livekit.proto.StreamTextOptions\x12\x0c\n\x04text\x18\x03 \x02(\t\x12\x18\n\x10request_async_id\x18\x04 \x01(\x04\"*\n\x16StreamSendTextResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"\x90\x01\n\x16StreamSendTextCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12-\n\x04info\x18\x02 \x01(\x0b\x32\x1d.livekit.proto.TextStreamInfoH\x00\x12+\n\x05\x65rror\x18\x03 \x01(\x0b\x32\x1a.livekit.proto.StreamErrorH\x00\x42\x08\n\x06result\"s\n\x15OwnedByteStreamWriter\x12-\n\x06handle\x18\x01 \x02(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12+\n\x04info\x18\x02 \x02(\x0b\x32\x1d.livekit.proto.ByteStreamInfo\"\x86\x01\n\x15\x42yteStreamOpenRequest\x12 \n\x18local_participant_handle\x18\x01 \x02(\x04\x12\x31\n\x07options\x18\x02 \x02(\x0b\x32 .livekit.proto.StreamByteOptions\x12\x18\n\x10request_async_id\x18\x03 \x01(\x04\"*\n\x16\x42yteStreamOpenResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"\x99\x01\n\x16\x42yteStreamOpenCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12\x36\n\x06writer\x18\x02 \x01(\x0b\x32$.livekit.proto.OwnedByteStreamWriterH\x00\x12+\n\x05\x65rror\x18\x03 \x01(\x0b\x32\x1a.livekit.proto.StreamErrorH\x00\x42\x08\n\x06result\"^\n\x1c\x42yteStreamWriterWriteRequest\x12\x15\n\rwriter_handle\x18\x01 \x02(\x04\x12\r\n\x05\x62ytes\x18\x02 \x02(\x0c\x12\x18\n\x10request_async_id\x18\x03 \x01(\x04\"1\n\x1d\x42yteStreamWriterWriteResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"\\\n\x1d\x42yteStreamWriterWriteCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12)\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x1a.livekit.proto.StreamError\"_\n\x1c\x42yteStreamWriterCloseRequest\x12\x15\n\rwriter_handle\x18\x01 \x02(\x04\x12\x0e\n\x06reason\x18\x02 \x01(\t\x12\x18\n\x10request_async_id\x18\x03 \x01(\x04\"1\n\x1d\x42yteStreamWriterCloseResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"\\\n\x1d\x42yteStreamWriterCloseCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12)\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x1a.livekit.proto.StreamError\"s\n\x15OwnedTextStreamWriter\x12-\n\x06handle\x18\x01 \x02(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12+\n\x04info\x18\x02 \x02(\x0b\x32\x1d.livekit.proto.TextStreamInfo\"\x86\x01\n\x15TextStreamOpenRequest\x12 \n\x18local_participant_handle\x18\x01 \x02(\x04\x12\x31\n\x07options\x18\x02 \x02(\x0b\x32 .livekit.proto.StreamTextOptions\x12\x18\n\x10request_async_id\x18\x03 \x01(\x04\"*\n\x16TextStreamOpenResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"\x99\x01\n\x16TextStreamOpenCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12\x36\n\x06writer\x18\x02 \x01(\x0b\x32$.livekit.proto.OwnedTextStreamWriterH\x00\x12+\n\x05\x65rror\x18\x03 \x01(\x0b\x32\x1a.livekit.proto.StreamErrorH\x00\x42\x08\n\x06result\"]\n\x1cTextStreamWriterWriteRequest\x12\x15\n\rwriter_handle\x18\x01 \x02(\x04\x12\x0c\n\x04text\x18\x02 \x02(\t\x12\x18\n\x10request_async_id\x18\x03 \x01(\x04\"1\n\x1dTextStreamWriterWriteResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"\\\n\x1dTextStreamWriterWriteCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12)\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x1a.livekit.proto.StreamError\"_\n\x1cTextStreamWriterCloseRequest\x12\x15\n\rwriter_handle\x18\x01 \x02(\x04\x12\x0e\n\x06reason\x18\x02 \x01(\t\x12\x18\n\x10request_async_id\x18\x03 \x01(\x04\"1\n\x1dTextStreamWriterCloseResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"\\\n\x1dTextStreamWriterCloseCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12)\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x1a.livekit.proto.StreamError\"\x81\x04\n\x0eTextStreamInfo\x12\x11\n\tstream_id\x18\x01 \x02(\t\x12\x11\n\ttimestamp\x18\x02 \x02(\x03\x12\x11\n\tmime_type\x18\x03 \x02(\t\x12\r\n\x05topic\x18\x04 \x02(\t\x12\x14\n\x0ctotal_length\x18\x05 \x01(\x04\x12\x41\n\nattributes\x18\x06 \x03(\x0b\x32-.livekit.proto.TextStreamInfo.AttributesEntry\x12\x43\n\x0eoperation_type\x18\x07 \x02(\x0e\x32+.livekit.proto.TextStreamInfo.OperationType\x12\x0f\n\x07version\x18\x08 \x01(\x05\x12\x1a\n\x12reply_to_stream_id\x18\t \x01(\t\x12\x1b\n\x13\x61ttached_stream_ids\x18\n \x03(\t\x12\x11\n\tgenerated\x18\x0b \x01(\x08\x12\x36\n\x0f\x65ncryption_type\x18\x0c \x02(\x0e\x32\x1d.livekit.proto.EncryptionType\x1a\x31\n\x0f\x41ttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"A\n\rOperationType\x12\n\n\x06\x43REATE\x10\x00\x12\n\n\x06UPDATE\x10\x01\x12\n\n\x06\x44\x45LETE\x10\x02\x12\x0c\n\x08REACTION\x10\x03\"\xaa\x02\n\x0e\x42yteStreamInfo\x12\x11\n\tstream_id\x18\x01 \x02(\t\x12\x11\n\ttimestamp\x18\x02 \x02(\x03\x12\x11\n\tmime_type\x18\x03 \x02(\t\x12\r\n\x05topic\x18\x04 \x02(\t\x12\x14\n\x0ctotal_length\x18\x05 \x01(\x04\x12\x41\n\nattributes\x18\x06 \x03(\x0b\x32-.livekit.proto.ByteStreamInfo.AttributesEntry\x12\x0c\n\x04name\x18\x07 \x02(\t\x12\x36\n\x0f\x65ncryption_type\x18\x08 \x02(\x0e\x32\x1d.livekit.proto.EncryptionType\x1a\x31\n\x0f\x41ttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xe9\x02\n\x11StreamTextOptions\x12\r\n\x05topic\x18\x01 \x02(\t\x12\x44\n\nattributes\x18\x02 \x03(\x0b\x32\x30.livekit.proto.StreamTextOptions.AttributesEntry\x12\x1e\n\x16\x64\x65stination_identities\x18\x03 \x03(\t\x12\n\n\x02id\x18\x04 \x01(\t\x12\x43\n\x0eoperation_type\x18\x05 \x01(\x0e\x32+.livekit.proto.TextStreamInfo.OperationType\x12\x0f\n\x07version\x18\x06 \x01(\x05\x12\x1a\n\x12reply_to_stream_id\x18\x07 \x01(\t\x12\x1b\n\x13\x61ttached_stream_ids\x18\x08 \x03(\t\x12\x11\n\tgenerated\x18\t \x01(\x08\x1a\x31\n\x0f\x41ttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xfe\x01\n\x11StreamByteOptions\x12\r\n\x05topic\x18\x01 \x02(\t\x12\x44\n\nattributes\x18\x02 \x03(\x0b\x32\x30.livekit.proto.StreamByteOptions.AttributesEntry\x12\x1e\n\x16\x64\x65stination_identities\x18\x03 \x03(\t\x12\n\n\x02id\x18\x04 \x01(\t\x12\x0c\n\x04name\x18\x05 \x01(\t\x12\x11\n\tmime_type\x18\x06 \x01(\t\x12\x14\n\x0ctotal_length\x18\x07 \x01(\x04\x1a\x31\n\x0f\x41ttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\"\n\x0bStreamError\x12\x13\n\x0b\x64\x65scription\x18\x01 \x02(\tB\x10\xaa\x02\rLiveKit.Proto')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'data_stream_pb2', _globals)
+if _descriptor._USE_C_DESCRIPTORS == False:
+ _globals['DESCRIPTOR']._options = None
+ _globals['DESCRIPTOR']._serialized_options = b'\252\002\rLiveKit.Proto'
+ _globals['_TEXTSTREAMINFO_ATTRIBUTESENTRY']._options = None
+ _globals['_TEXTSTREAMINFO_ATTRIBUTESENTRY']._serialized_options = b'8\001'
+ _globals['_BYTESTREAMINFO_ATTRIBUTESENTRY']._options = None
+ _globals['_BYTESTREAMINFO_ATTRIBUTESENTRY']._serialized_options = b'8\001'
+ _globals['_STREAMTEXTOPTIONS_ATTRIBUTESENTRY']._options = None
+ _globals['_STREAMTEXTOPTIONS_ATTRIBUTESENTRY']._serialized_options = b'8\001'
+ _globals['_STREAMBYTEOPTIONS_ATTRIBUTESENTRY']._options = None
+ _globals['_STREAMBYTEOPTIONS_ATTRIBUTESENTRY']._serialized_options = b'8\001'
+ _globals['_OWNEDTEXTSTREAMREADER']._serialized_start=62
+ _globals['_OWNEDTEXTSTREAMREADER']._serialized_end=177
+ _globals['_TEXTSTREAMREADERREADINCREMENTALREQUEST']._serialized_start=179
+ _globals['_TEXTSTREAMREADERREADINCREMENTALREQUEST']._serialized_end=242
+ _globals['_TEXTSTREAMREADERREADINCREMENTALRESPONSE']._serialized_start=244
+ _globals['_TEXTSTREAMREADERREADINCREMENTALRESPONSE']._serialized_end=285
+ _globals['_TEXTSTREAMREADERREADALLREQUEST']._serialized_start=287
+ _globals['_TEXTSTREAMREADERREADALLREQUEST']._serialized_end=368
+ _globals['_TEXTSTREAMREADERREADALLRESPONSE']._serialized_start=370
+ _globals['_TEXTSTREAMREADERREADALLRESPONSE']._serialized_end=421
+ _globals['_TEXTSTREAMREADERREADALLCALLBACK']._serialized_start=423
+ _globals['_TEXTSTREAMREADERREADALLCALLBACK']._serialized_end=548
+ _globals['_TEXTSTREAMREADEREVENT']._serialized_start=551
+ _globals['_TEXTSTREAMREADEREVENT']._serialized_end=730
+ _globals['_TEXTSTREAMREADERCHUNKRECEIVED']._serialized_start=732
+ _globals['_TEXTSTREAMREADERCHUNKRECEIVED']._serialized_end=780
+ _globals['_TEXTSTREAMREADEREOS']._serialized_start=782
+ _globals['_TEXTSTREAMREADEREOS']._serialized_end=846
+ _globals['_OWNEDBYTESTREAMREADER']._serialized_start=848
+ _globals['_OWNEDBYTESTREAMREADER']._serialized_end=963
+ _globals['_BYTESTREAMREADERREADINCREMENTALREQUEST']._serialized_start=965
+ _globals['_BYTESTREAMREADERREADINCREMENTALREQUEST']._serialized_end=1028
+ _globals['_BYTESTREAMREADERREADINCREMENTALRESPONSE']._serialized_start=1030
+ _globals['_BYTESTREAMREADERREADINCREMENTALRESPONSE']._serialized_end=1071
+ _globals['_BYTESTREAMREADERREADALLREQUEST']._serialized_start=1073
+ _globals['_BYTESTREAMREADERREADALLREQUEST']._serialized_end=1154
+ _globals['_BYTESTREAMREADERREADALLRESPONSE']._serialized_start=1156
+ _globals['_BYTESTREAMREADERREADALLRESPONSE']._serialized_end=1207
+ _globals['_BYTESTREAMREADERREADALLCALLBACK']._serialized_start=1209
+ _globals['_BYTESTREAMREADERREADALLCALLBACK']._serialized_end=1334
+ _globals['_BYTESTREAMREADERWRITETOFILEREQUEST']._serialized_start=1336
+ _globals['_BYTESTREAMREADERWRITETOFILEREQUEST']._serialized_end=1463
+ _globals['_BYTESTREAMREADERWRITETOFILERESPONSE']._serialized_start=1465
+ _globals['_BYTESTREAMREADERWRITETOFILERESPONSE']._serialized_end=1520
+ _globals['_BYTESTREAMREADERWRITETOFILECALLBACK']._serialized_start=1523
+ _globals['_BYTESTREAMREADERWRITETOFILECALLBACK']._serialized_end=1654
+ _globals['_BYTESTREAMREADEREVENT']._serialized_start=1657
+ _globals['_BYTESTREAMREADEREVENT']._serialized_end=1836
+ _globals['_BYTESTREAMREADERCHUNKRECEIVED']._serialized_start=1838
+ _globals['_BYTESTREAMREADERCHUNKRECEIVED']._serialized_end=1886
+ _globals['_BYTESTREAMREADEREOS']._serialized_start=1888
+ _globals['_BYTESTREAMREADEREOS']._serialized_end=1952
+ _globals['_STREAMSENDFILEREQUEST']._serialized_start=1955
+ _globals['_STREAMSENDFILEREQUEST']._serialized_end=2108
+ _globals['_STREAMSENDFILERESPONSE']._serialized_start=2110
+ _globals['_STREAMSENDFILERESPONSE']._serialized_end=2152
+ _globals['_STREAMSENDFILECALLBACK']._serialized_start=2155
+ _globals['_STREAMSENDFILECALLBACK']._serialized_end=2299
+ _globals['_STREAMSENDBYTESREQUEST']._serialized_start=2302
+ _globals['_STREAMSENDBYTESREQUEST']._serialized_end=2452
+ _globals['_STREAMSENDBYTESRESPONSE']._serialized_start=2454
+ _globals['_STREAMSENDBYTESRESPONSE']._serialized_end=2497
+ _globals['_STREAMSENDBYTESCALLBACK']._serialized_start=2500
+ _globals['_STREAMSENDBYTESCALLBACK']._serialized_end=2645
+ _globals['_STREAMSENDTEXTREQUEST']._serialized_start=2648
+ _globals['_STREAMSENDTEXTREQUEST']._serialized_end=2796
+ _globals['_STREAMSENDTEXTRESPONSE']._serialized_start=2798
+ _globals['_STREAMSENDTEXTRESPONSE']._serialized_end=2840
+ _globals['_STREAMSENDTEXTCALLBACK']._serialized_start=2843
+ _globals['_STREAMSENDTEXTCALLBACK']._serialized_end=2987
+ _globals['_OWNEDBYTESTREAMWRITER']._serialized_start=2989
+ _globals['_OWNEDBYTESTREAMWRITER']._serialized_end=3104
+ _globals['_BYTESTREAMOPENREQUEST']._serialized_start=3107
+ _globals['_BYTESTREAMOPENREQUEST']._serialized_end=3241
+ _globals['_BYTESTREAMOPENRESPONSE']._serialized_start=3243
+ _globals['_BYTESTREAMOPENRESPONSE']._serialized_end=3285
+ _globals['_BYTESTREAMOPENCALLBACK']._serialized_start=3288
+ _globals['_BYTESTREAMOPENCALLBACK']._serialized_end=3441
+ _globals['_BYTESTREAMWRITERWRITEREQUEST']._serialized_start=3443
+ _globals['_BYTESTREAMWRITERWRITEREQUEST']._serialized_end=3537
+ _globals['_BYTESTREAMWRITERWRITERESPONSE']._serialized_start=3539
+ _globals['_BYTESTREAMWRITERWRITERESPONSE']._serialized_end=3588
+ _globals['_BYTESTREAMWRITERWRITECALLBACK']._serialized_start=3590
+ _globals['_BYTESTREAMWRITERWRITECALLBACK']._serialized_end=3682
+ _globals['_BYTESTREAMWRITERCLOSEREQUEST']._serialized_start=3684
+ _globals['_BYTESTREAMWRITERCLOSEREQUEST']._serialized_end=3779
+ _globals['_BYTESTREAMWRITERCLOSERESPONSE']._serialized_start=3781
+ _globals['_BYTESTREAMWRITERCLOSERESPONSE']._serialized_end=3830
+ _globals['_BYTESTREAMWRITERCLOSECALLBACK']._serialized_start=3832
+ _globals['_BYTESTREAMWRITERCLOSECALLBACK']._serialized_end=3924
+ _globals['_OWNEDTEXTSTREAMWRITER']._serialized_start=3926
+ _globals['_OWNEDTEXTSTREAMWRITER']._serialized_end=4041
+ _globals['_TEXTSTREAMOPENREQUEST']._serialized_start=4044
+ _globals['_TEXTSTREAMOPENREQUEST']._serialized_end=4178
+ _globals['_TEXTSTREAMOPENRESPONSE']._serialized_start=4180
+ _globals['_TEXTSTREAMOPENRESPONSE']._serialized_end=4222
+ _globals['_TEXTSTREAMOPENCALLBACK']._serialized_start=4225
+ _globals['_TEXTSTREAMOPENCALLBACK']._serialized_end=4378
+ _globals['_TEXTSTREAMWRITERWRITEREQUEST']._serialized_start=4380
+ _globals['_TEXTSTREAMWRITERWRITEREQUEST']._serialized_end=4473
+ _globals['_TEXTSTREAMWRITERWRITERESPONSE']._serialized_start=4475
+ _globals['_TEXTSTREAMWRITERWRITERESPONSE']._serialized_end=4524
+ _globals['_TEXTSTREAMWRITERWRITECALLBACK']._serialized_start=4526
+ _globals['_TEXTSTREAMWRITERWRITECALLBACK']._serialized_end=4618
+ _globals['_TEXTSTREAMWRITERCLOSEREQUEST']._serialized_start=4620
+ _globals['_TEXTSTREAMWRITERCLOSEREQUEST']._serialized_end=4715
+ _globals['_TEXTSTREAMWRITERCLOSERESPONSE']._serialized_start=4717
+ _globals['_TEXTSTREAMWRITERCLOSERESPONSE']._serialized_end=4766
+ _globals['_TEXTSTREAMWRITERCLOSECALLBACK']._serialized_start=4768
+ _globals['_TEXTSTREAMWRITERCLOSECALLBACK']._serialized_end=4860
+ _globals['_TEXTSTREAMINFO']._serialized_start=4863
+ _globals['_TEXTSTREAMINFO']._serialized_end=5376
+ _globals['_TEXTSTREAMINFO_ATTRIBUTESENTRY']._serialized_start=5260
+ _globals['_TEXTSTREAMINFO_ATTRIBUTESENTRY']._serialized_end=5309
+ _globals['_TEXTSTREAMINFO_OPERATIONTYPE']._serialized_start=5311
+ _globals['_TEXTSTREAMINFO_OPERATIONTYPE']._serialized_end=5376
+ _globals['_BYTESTREAMINFO']._serialized_start=5379
+ _globals['_BYTESTREAMINFO']._serialized_end=5677
+ _globals['_BYTESTREAMINFO_ATTRIBUTESENTRY']._serialized_start=5260
+ _globals['_BYTESTREAMINFO_ATTRIBUTESENTRY']._serialized_end=5309
+ _globals['_STREAMTEXTOPTIONS']._serialized_start=5680
+ _globals['_STREAMTEXTOPTIONS']._serialized_end=6041
+ _globals['_STREAMTEXTOPTIONS_ATTRIBUTESENTRY']._serialized_start=5260
+ _globals['_STREAMTEXTOPTIONS_ATTRIBUTESENTRY']._serialized_end=5309
+ _globals['_STREAMBYTEOPTIONS']._serialized_start=6044
+ _globals['_STREAMBYTEOPTIONS']._serialized_end=6298
+ _globals['_STREAMBYTEOPTIONS_ATTRIBUTESENTRY']._serialized_start=5260
+ _globals['_STREAMBYTEOPTIONS_ATTRIBUTESENTRY']._serialized_end=5309
+ _globals['_STREAMERROR']._serialized_start=6300
+ _globals['_STREAMERROR']._serialized_end=6334
+# @@protoc_insertion_point(module_scope)
diff --git a/livekit-rtc/livekit/rtc/_proto/data_stream_pb2.pyi b/livekit-rtc/livekit/rtc/_proto/data_stream_pb2.pyi
new file mode 100644
index 00000000..e68dc45f
--- /dev/null
+++ b/livekit-rtc/livekit/rtc/_proto/data_stream_pb2.pyi
@@ -0,0 +1,1392 @@
+"""
+@generated by mypy-protobuf. Do not edit manually!
+isort:skip_file
+Copyright 2025 LiveKit, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import builtins
+import collections.abc
+from . import e2ee_pb2
+import google.protobuf.descriptor
+import google.protobuf.internal.containers
+import google.protobuf.internal.enum_type_wrapper
+import google.protobuf.message
+from . import handle_pb2
+import sys
+import typing
+
+if sys.version_info >= (3, 10):
+ import typing as typing_extensions
+else:
+ import typing_extensions
+
+DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
+
+@typing.final
+class OwnedTextStreamReader(google.protobuf.message.Message):
+ """MARK: - Text stream reader
+
+ A reader for an incoming stream.
+ """
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ HANDLE_FIELD_NUMBER: builtins.int
+ INFO_FIELD_NUMBER: builtins.int
+ @property
+ def handle(self) -> handle_pb2.FfiOwnedHandle: ...
+ @property
+ def info(self) -> global___TextStreamInfo: ...
+ def __init__(
+ self,
+ *,
+ handle: handle_pb2.FfiOwnedHandle | None = ...,
+ info: global___TextStreamInfo | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> None: ...
+
+global___OwnedTextStreamReader = OwnedTextStreamReader
+
+@typing.final
+class TextStreamReaderReadIncrementalRequest(google.protobuf.message.Message):
+ """Reads an incoming text stream incrementally."""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ READER_HANDLE_FIELD_NUMBER: builtins.int
+ reader_handle: builtins.int
+ def __init__(
+ self,
+ *,
+ reader_handle: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["reader_handle", b"reader_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["reader_handle", b"reader_handle"]) -> None: ...
+
+global___TextStreamReaderReadIncrementalRequest = TextStreamReaderReadIncrementalRequest
+
+@typing.final
+class TextStreamReaderReadIncrementalResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ def __init__(
+ self,
+ ) -> None: ...
+
+global___TextStreamReaderReadIncrementalResponse = TextStreamReaderReadIncrementalResponse
+
+@typing.final
+class TextStreamReaderReadAllRequest(google.protobuf.message.Message):
+ """Reads an incoming text stream in its entirety."""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ READER_HANDLE_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
+ reader_handle: builtins.int
+ request_async_id: builtins.int
+ def __init__(
+ self,
+ *,
+ reader_handle: builtins.int | None = ...,
+ request_async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["reader_handle", b"reader_handle", "request_async_id", b"request_async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["reader_handle", b"reader_handle", "request_async_id", b"request_async_id"]) -> None: ...
+
+global___TextStreamReaderReadAllRequest = TextStreamReaderReadAllRequest
+
+@typing.final
+class TextStreamReaderReadAllResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
+
+global___TextStreamReaderReadAllResponse = TextStreamReaderReadAllResponse
+
+@typing.final
+class TextStreamReaderReadAllCallback(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ CONTENT_FIELD_NUMBER: builtins.int
+ ERROR_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ content: builtins.str
+ @property
+ def error(self) -> global___StreamError: ...
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ content: builtins.str | None = ...,
+ error: global___StreamError | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "content", b"content", "error", b"error", "result", b"result"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "content", b"content", "error", b"error", "result", b"result"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["result", b"result"]) -> typing.Literal["content", "error"] | None: ...
+
+global___TextStreamReaderReadAllCallback = TextStreamReaderReadAllCallback
+
+@typing.final
+class TextStreamReaderEvent(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ READER_HANDLE_FIELD_NUMBER: builtins.int
+ CHUNK_RECEIVED_FIELD_NUMBER: builtins.int
+ EOS_FIELD_NUMBER: builtins.int
+ reader_handle: builtins.int
+ @property
+ def chunk_received(self) -> global___TextStreamReaderChunkReceived: ...
+ @property
+ def eos(self) -> global___TextStreamReaderEOS: ...
+ def __init__(
+ self,
+ *,
+ reader_handle: builtins.int | None = ...,
+ chunk_received: global___TextStreamReaderChunkReceived | None = ...,
+ eos: global___TextStreamReaderEOS | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["chunk_received", b"chunk_received", "detail", b"detail", "eos", b"eos", "reader_handle", b"reader_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["chunk_received", b"chunk_received", "detail", b"detail", "eos", b"eos", "reader_handle", b"reader_handle"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["detail", b"detail"]) -> typing.Literal["chunk_received", "eos"] | None: ...
+
+global___TextStreamReaderEvent = TextStreamReaderEvent
+
+@typing.final
+class TextStreamReaderChunkReceived(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ CONTENT_FIELD_NUMBER: builtins.int
+ content: builtins.str
+ def __init__(
+ self,
+ *,
+ content: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["content", b"content"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["content", b"content"]) -> None: ...
+
+global___TextStreamReaderChunkReceived = TextStreamReaderChunkReceived
+
+@typing.final
+class TextStreamReaderEOS(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ERROR_FIELD_NUMBER: builtins.int
+ @property
+ def error(self) -> global___StreamError: ...
+ def __init__(
+ self,
+ *,
+ error: global___StreamError | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["error", b"error"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["error", b"error"]) -> None: ...
+
+global___TextStreamReaderEOS = TextStreamReaderEOS
+
+@typing.final
+class OwnedByteStreamReader(google.protobuf.message.Message):
+ """MARK: - Byte stream reader
+
+ A reader for an incoming stream.
+ """
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ HANDLE_FIELD_NUMBER: builtins.int
+ INFO_FIELD_NUMBER: builtins.int
+ @property
+ def handle(self) -> handle_pb2.FfiOwnedHandle: ...
+ @property
+ def info(self) -> global___ByteStreamInfo: ...
+ def __init__(
+ self,
+ *,
+ handle: handle_pb2.FfiOwnedHandle | None = ...,
+ info: global___ByteStreamInfo | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> None: ...
+
+global___OwnedByteStreamReader = OwnedByteStreamReader
+
+@typing.final
+class ByteStreamReaderReadIncrementalRequest(google.protobuf.message.Message):
+ """Reads an incoming byte stream incrementally."""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ READER_HANDLE_FIELD_NUMBER: builtins.int
+ reader_handle: builtins.int
+ def __init__(
+ self,
+ *,
+ reader_handle: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["reader_handle", b"reader_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["reader_handle", b"reader_handle"]) -> None: ...
+
+global___ByteStreamReaderReadIncrementalRequest = ByteStreamReaderReadIncrementalRequest
+
+@typing.final
+class ByteStreamReaderReadIncrementalResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ def __init__(
+ self,
+ ) -> None: ...
+
+global___ByteStreamReaderReadIncrementalResponse = ByteStreamReaderReadIncrementalResponse
+
+@typing.final
+class ByteStreamReaderReadAllRequest(google.protobuf.message.Message):
+ """Reads an incoming byte stream in its entirety."""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ READER_HANDLE_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
+ reader_handle: builtins.int
+ request_async_id: builtins.int
+ def __init__(
+ self,
+ *,
+ reader_handle: builtins.int | None = ...,
+ request_async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["reader_handle", b"reader_handle", "request_async_id", b"request_async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["reader_handle", b"reader_handle", "request_async_id", b"request_async_id"]) -> None: ...
+
+global___ByteStreamReaderReadAllRequest = ByteStreamReaderReadAllRequest
+
+@typing.final
+class ByteStreamReaderReadAllResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
+
+global___ByteStreamReaderReadAllResponse = ByteStreamReaderReadAllResponse
+
+@typing.final
+class ByteStreamReaderReadAllCallback(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ CONTENT_FIELD_NUMBER: builtins.int
+ ERROR_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ content: builtins.bytes
+ @property
+ def error(self) -> global___StreamError: ...
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ content: builtins.bytes | None = ...,
+ error: global___StreamError | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "content", b"content", "error", b"error", "result", b"result"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "content", b"content", "error", b"error", "result", b"result"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["result", b"result"]) -> typing.Literal["content", "error"] | None: ...
+
+global___ByteStreamReaderReadAllCallback = ByteStreamReaderReadAllCallback
+
+@typing.final
+class ByteStreamReaderWriteToFileRequest(google.protobuf.message.Message):
+ """Writes data from an incoming stream to a file as it arrives."""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ READER_HANDLE_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
+ DIRECTORY_FIELD_NUMBER: builtins.int
+ NAME_OVERRIDE_FIELD_NUMBER: builtins.int
+ reader_handle: builtins.int
+ request_async_id: builtins.int
+ directory: builtins.str
+ """Directory to write the file in (must be writable by the current process).
+ If not provided, the file will be written to the system's temp directory.
+ """
+ name_override: builtins.str
+ """Name to use for the written file.
+ If not provided, the file's name and extension will be inferred from
+ the stream's info.
+ """
+ def __init__(
+ self,
+ *,
+ reader_handle: builtins.int | None = ...,
+ request_async_id: builtins.int | None = ...,
+ directory: builtins.str | None = ...,
+ name_override: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["directory", b"directory", "name_override", b"name_override", "reader_handle", b"reader_handle", "request_async_id", b"request_async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["directory", b"directory", "name_override", b"name_override", "reader_handle", b"reader_handle", "request_async_id", b"request_async_id"]) -> None: ...
+
+global___ByteStreamReaderWriteToFileRequest = ByteStreamReaderWriteToFileRequest
+
+@typing.final
+class ByteStreamReaderWriteToFileResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
+
+global___ByteStreamReaderWriteToFileResponse = ByteStreamReaderWriteToFileResponse
+
+@typing.final
+class ByteStreamReaderWriteToFileCallback(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ FILE_PATH_FIELD_NUMBER: builtins.int
+ ERROR_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ file_path: builtins.str
+ """Path the file was written to."""
+ @property
+ def error(self) -> global___StreamError: ...
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ file_path: builtins.str | None = ...,
+ error: global___StreamError | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error", "file_path", b"file_path", "result", b"result"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error", "file_path", b"file_path", "result", b"result"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["result", b"result"]) -> typing.Literal["file_path", "error"] | None: ...
+
+global___ByteStreamReaderWriteToFileCallback = ByteStreamReaderWriteToFileCallback
+
+@typing.final
+class ByteStreamReaderEvent(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ READER_HANDLE_FIELD_NUMBER: builtins.int
+ CHUNK_RECEIVED_FIELD_NUMBER: builtins.int
+ EOS_FIELD_NUMBER: builtins.int
+ reader_handle: builtins.int
+ @property
+ def chunk_received(self) -> global___ByteStreamReaderChunkReceived: ...
+ @property
+ def eos(self) -> global___ByteStreamReaderEOS: ...
+ def __init__(
+ self,
+ *,
+ reader_handle: builtins.int | None = ...,
+ chunk_received: global___ByteStreamReaderChunkReceived | None = ...,
+ eos: global___ByteStreamReaderEOS | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["chunk_received", b"chunk_received", "detail", b"detail", "eos", b"eos", "reader_handle", b"reader_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["chunk_received", b"chunk_received", "detail", b"detail", "eos", b"eos", "reader_handle", b"reader_handle"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["detail", b"detail"]) -> typing.Literal["chunk_received", "eos"] | None: ...
+
+global___ByteStreamReaderEvent = ByteStreamReaderEvent
+
+@typing.final
+class ByteStreamReaderChunkReceived(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ CONTENT_FIELD_NUMBER: builtins.int
+ content: builtins.bytes
+ def __init__(
+ self,
+ *,
+ content: builtins.bytes | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["content", b"content"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["content", b"content"]) -> None: ...
+
+global___ByteStreamReaderChunkReceived = ByteStreamReaderChunkReceived
+
+@typing.final
+class ByteStreamReaderEOS(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ERROR_FIELD_NUMBER: builtins.int
+ @property
+ def error(self) -> global___StreamError: ...
+ def __init__(
+ self,
+ *,
+ error: global___StreamError | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["error", b"error"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["error", b"error"]) -> None: ...
+
+global___ByteStreamReaderEOS = ByteStreamReaderEOS
+
+@typing.final
+class StreamSendFileRequest(google.protobuf.message.Message):
+ """MARK: - Send file
+
+ Sends the contents of a file over a data stream.
+ """
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ LOCAL_PARTICIPANT_HANDLE_FIELD_NUMBER: builtins.int
+ OPTIONS_FIELD_NUMBER: builtins.int
+ FILE_PATH_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
+ local_participant_handle: builtins.int
+ file_path: builtins.str
+ """Path of the file to send (must be readable by the current process)."""
+ request_async_id: builtins.int
+ @property
+ def options(self) -> global___StreamByteOptions: ...
+ def __init__(
+ self,
+ *,
+ local_participant_handle: builtins.int | None = ...,
+ options: global___StreamByteOptions | None = ...,
+ file_path: builtins.str | None = ...,
+ request_async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["file_path", b"file_path", "local_participant_handle", b"local_participant_handle", "options", b"options", "request_async_id", b"request_async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["file_path", b"file_path", "local_participant_handle", b"local_participant_handle", "options", b"options", "request_async_id", b"request_async_id"]) -> None: ...
+
+global___StreamSendFileRequest = StreamSendFileRequest
+
+@typing.final
+class StreamSendFileResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
+
+global___StreamSendFileResponse = StreamSendFileResponse
+
+@typing.final
+class StreamSendFileCallback(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ INFO_FIELD_NUMBER: builtins.int
+ ERROR_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ @property
+ def info(self) -> global___ByteStreamInfo: ...
+ @property
+ def error(self) -> global___StreamError: ...
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ info: global___ByteStreamInfo | None = ...,
+ error: global___StreamError | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error", "info", b"info", "result", b"result"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error", "info", b"info", "result", b"result"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["result", b"result"]) -> typing.Literal["info", "error"] | None: ...
+
+global___StreamSendFileCallback = StreamSendFileCallback
+
+@typing.final
+class StreamSendBytesRequest(google.protobuf.message.Message):
+ """MARK: - Send bytes
+
+ Sends bytes over a data stream.
+ """
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ LOCAL_PARTICIPANT_HANDLE_FIELD_NUMBER: builtins.int
+ OPTIONS_FIELD_NUMBER: builtins.int
+ BYTES_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
+ local_participant_handle: builtins.int
+ bytes: builtins.bytes
+ """Bytes to send."""
+ request_async_id: builtins.int
+ @property
+ def options(self) -> global___StreamByteOptions: ...
+ def __init__(
+ self,
+ *,
+ local_participant_handle: builtins.int | None = ...,
+ options: global___StreamByteOptions | None = ...,
+ bytes: builtins.bytes | None = ...,
+ request_async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["bytes", b"bytes", "local_participant_handle", b"local_participant_handle", "options", b"options", "request_async_id", b"request_async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["bytes", b"bytes", "local_participant_handle", b"local_participant_handle", "options", b"options", "request_async_id", b"request_async_id"]) -> None: ...
+
+global___StreamSendBytesRequest = StreamSendBytesRequest
+
+@typing.final
+class StreamSendBytesResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
+
+global___StreamSendBytesResponse = StreamSendBytesResponse
+
+@typing.final
+class StreamSendBytesCallback(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ INFO_FIELD_NUMBER: builtins.int
+ ERROR_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ @property
+ def info(self) -> global___ByteStreamInfo: ...
+ @property
+ def error(self) -> global___StreamError: ...
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ info: global___ByteStreamInfo | None = ...,
+ error: global___StreamError | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error", "info", b"info", "result", b"result"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error", "info", b"info", "result", b"result"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["result", b"result"]) -> typing.Literal["info", "error"] | None: ...
+
+global___StreamSendBytesCallback = StreamSendBytesCallback
+
+@typing.final
+class StreamSendTextRequest(google.protobuf.message.Message):
+ """MARK: - Send text
+
+ Sends text over a data stream.
+ """
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ LOCAL_PARTICIPANT_HANDLE_FIELD_NUMBER: builtins.int
+ OPTIONS_FIELD_NUMBER: builtins.int
+ TEXT_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
+ local_participant_handle: builtins.int
+ text: builtins.str
+ """Text to send."""
+ request_async_id: builtins.int
+ @property
+ def options(self) -> global___StreamTextOptions: ...
+ def __init__(
+ self,
+ *,
+ local_participant_handle: builtins.int | None = ...,
+ options: global___StreamTextOptions | None = ...,
+ text: builtins.str | None = ...,
+ request_async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["local_participant_handle", b"local_participant_handle", "options", b"options", "request_async_id", b"request_async_id", "text", b"text"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["local_participant_handle", b"local_participant_handle", "options", b"options", "request_async_id", b"request_async_id", "text", b"text"]) -> None: ...
+
+global___StreamSendTextRequest = StreamSendTextRequest
+
+@typing.final
+class StreamSendTextResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
+
+global___StreamSendTextResponse = StreamSendTextResponse
+
+@typing.final
+class StreamSendTextCallback(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ INFO_FIELD_NUMBER: builtins.int
+ ERROR_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ @property
+ def info(self) -> global___TextStreamInfo: ...
+ @property
+ def error(self) -> global___StreamError: ...
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ info: global___TextStreamInfo | None = ...,
+ error: global___StreamError | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error", "info", b"info", "result", b"result"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error", "info", b"info", "result", b"result"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["result", b"result"]) -> typing.Literal["info", "error"] | None: ...
+
+global___StreamSendTextCallback = StreamSendTextCallback
+
+@typing.final
+class OwnedByteStreamWriter(google.protobuf.message.Message):
+ """MARK: - Byte stream writer"""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ HANDLE_FIELD_NUMBER: builtins.int
+ INFO_FIELD_NUMBER: builtins.int
+ @property
+ def handle(self) -> handle_pb2.FfiOwnedHandle: ...
+ @property
+ def info(self) -> global___ByteStreamInfo: ...
+ def __init__(
+ self,
+ *,
+ handle: handle_pb2.FfiOwnedHandle | None = ...,
+ info: global___ByteStreamInfo | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> None: ...
+
+global___OwnedByteStreamWriter = OwnedByteStreamWriter
+
+@typing.final
+class ByteStreamOpenRequest(google.protobuf.message.Message):
+ """Opens an outgoing stream.
+ Call must be balanced with a StreamCloseRequest.
+ """
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ LOCAL_PARTICIPANT_HANDLE_FIELD_NUMBER: builtins.int
+ OPTIONS_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
+ local_participant_handle: builtins.int
+ request_async_id: builtins.int
+ @property
+ def options(self) -> global___StreamByteOptions:
+ """Options to use for opening the stream."""
+
+ def __init__(
+ self,
+ *,
+ local_participant_handle: builtins.int | None = ...,
+ options: global___StreamByteOptions | None = ...,
+ request_async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["local_participant_handle", b"local_participant_handle", "options", b"options", "request_async_id", b"request_async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["local_participant_handle", b"local_participant_handle", "options", b"options", "request_async_id", b"request_async_id"]) -> None: ...
+
+global___ByteStreamOpenRequest = ByteStreamOpenRequest
+
+@typing.final
+class ByteStreamOpenResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
+
+global___ByteStreamOpenResponse = ByteStreamOpenResponse
+
+@typing.final
+class ByteStreamOpenCallback(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ WRITER_FIELD_NUMBER: builtins.int
+ ERROR_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ @property
+ def writer(self) -> global___OwnedByteStreamWriter: ...
+ @property
+ def error(self) -> global___StreamError: ...
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ writer: global___OwnedByteStreamWriter | None = ...,
+ error: global___StreamError | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error", "result", b"result", "writer", b"writer"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error", "result", b"result", "writer", b"writer"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["result", b"result"]) -> typing.Literal["writer", "error"] | None: ...
+
+global___ByteStreamOpenCallback = ByteStreamOpenCallback
+
+@typing.final
+class ByteStreamWriterWriteRequest(google.protobuf.message.Message):
+ """Writes data to a stream writer."""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ WRITER_HANDLE_FIELD_NUMBER: builtins.int
+ BYTES_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
+ writer_handle: builtins.int
+ bytes: builtins.bytes
+ request_async_id: builtins.int
+ def __init__(
+ self,
+ *,
+ writer_handle: builtins.int | None = ...,
+ bytes: builtins.bytes | None = ...,
+ request_async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["bytes", b"bytes", "request_async_id", b"request_async_id", "writer_handle", b"writer_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["bytes", b"bytes", "request_async_id", b"request_async_id", "writer_handle", b"writer_handle"]) -> None: ...
+
+global___ByteStreamWriterWriteRequest = ByteStreamWriterWriteRequest
+
+@typing.final
+class ByteStreamWriterWriteResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
+
+global___ByteStreamWriterWriteResponse = ByteStreamWriterWriteResponse
+
+@typing.final
+class ByteStreamWriterWriteCallback(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ ERROR_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ @property
+ def error(self) -> global___StreamError: ...
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ error: global___StreamError | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> None: ...
+
+global___ByteStreamWriterWriteCallback = ByteStreamWriterWriteCallback
+
+@typing.final
+class ByteStreamWriterCloseRequest(google.protobuf.message.Message):
+ """Closes a stream writer."""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ WRITER_HANDLE_FIELD_NUMBER: builtins.int
+ REASON_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
+ writer_handle: builtins.int
+ reason: builtins.str
+ request_async_id: builtins.int
+ def __init__(
+ self,
+ *,
+ writer_handle: builtins.int | None = ...,
+ reason: builtins.str | None = ...,
+ request_async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["reason", b"reason", "request_async_id", b"request_async_id", "writer_handle", b"writer_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["reason", b"reason", "request_async_id", b"request_async_id", "writer_handle", b"writer_handle"]) -> None: ...
+
+global___ByteStreamWriterCloseRequest = ByteStreamWriterCloseRequest
+
+@typing.final
+class ByteStreamWriterCloseResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
+
+global___ByteStreamWriterCloseResponse = ByteStreamWriterCloseResponse
+
+@typing.final
+class ByteStreamWriterCloseCallback(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ ERROR_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ @property
+ def error(self) -> global___StreamError: ...
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ error: global___StreamError | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> None: ...
+
+global___ByteStreamWriterCloseCallback = ByteStreamWriterCloseCallback
+
+@typing.final
+class OwnedTextStreamWriter(google.protobuf.message.Message):
+ """MARK: - Text stream writer"""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ HANDLE_FIELD_NUMBER: builtins.int
+ INFO_FIELD_NUMBER: builtins.int
+ @property
+ def handle(self) -> handle_pb2.FfiOwnedHandle: ...
+ @property
+ def info(self) -> global___TextStreamInfo: ...
+ def __init__(
+ self,
+ *,
+ handle: handle_pb2.FfiOwnedHandle | None = ...,
+ info: global___TextStreamInfo | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> None: ...
+
+global___OwnedTextStreamWriter = OwnedTextStreamWriter
+
+@typing.final
+class TextStreamOpenRequest(google.protobuf.message.Message):
+ """Opens an outgoing text stream.
+ Call must be balanced with a TextStreamCloseRequest.
+ """
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ LOCAL_PARTICIPANT_HANDLE_FIELD_NUMBER: builtins.int
+ OPTIONS_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
+ local_participant_handle: builtins.int
+ request_async_id: builtins.int
+ @property
+ def options(self) -> global___StreamTextOptions:
+ """Options to use for opening the stream."""
+
+ def __init__(
+ self,
+ *,
+ local_participant_handle: builtins.int | None = ...,
+ options: global___StreamTextOptions | None = ...,
+ request_async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["local_participant_handle", b"local_participant_handle", "options", b"options", "request_async_id", b"request_async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["local_participant_handle", b"local_participant_handle", "options", b"options", "request_async_id", b"request_async_id"]) -> None: ...
+
+global___TextStreamOpenRequest = TextStreamOpenRequest
+
+@typing.final
+class TextStreamOpenResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
+
+global___TextStreamOpenResponse = TextStreamOpenResponse
+
+@typing.final
+class TextStreamOpenCallback(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ WRITER_FIELD_NUMBER: builtins.int
+ ERROR_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ @property
+ def writer(self) -> global___OwnedTextStreamWriter: ...
+ @property
+ def error(self) -> global___StreamError: ...
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ writer: global___OwnedTextStreamWriter | None = ...,
+ error: global___StreamError | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error", "result", b"result", "writer", b"writer"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error", "result", b"result", "writer", b"writer"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["result", b"result"]) -> typing.Literal["writer", "error"] | None: ...
+
+global___TextStreamOpenCallback = TextStreamOpenCallback
+
+@typing.final
+class TextStreamWriterWriteRequest(google.protobuf.message.Message):
+ """Writes text to a text stream writer."""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ WRITER_HANDLE_FIELD_NUMBER: builtins.int
+ TEXT_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
+ writer_handle: builtins.int
+ text: builtins.str
+ request_async_id: builtins.int
+ def __init__(
+ self,
+ *,
+ writer_handle: builtins.int | None = ...,
+ text: builtins.str | None = ...,
+ request_async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["request_async_id", b"request_async_id", "text", b"text", "writer_handle", b"writer_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["request_async_id", b"request_async_id", "text", b"text", "writer_handle", b"writer_handle"]) -> None: ...
+
+global___TextStreamWriterWriteRequest = TextStreamWriterWriteRequest
+
+@typing.final
+class TextStreamWriterWriteResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
+
+global___TextStreamWriterWriteResponse = TextStreamWriterWriteResponse
+
+@typing.final
+class TextStreamWriterWriteCallback(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ ERROR_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ @property
+ def error(self) -> global___StreamError: ...
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ error: global___StreamError | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> None: ...
+
+global___TextStreamWriterWriteCallback = TextStreamWriterWriteCallback
+
+@typing.final
+class TextStreamWriterCloseRequest(google.protobuf.message.Message):
+ """Closes a text stream writer."""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ WRITER_HANDLE_FIELD_NUMBER: builtins.int
+ REASON_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
+ writer_handle: builtins.int
+ reason: builtins.str
+ request_async_id: builtins.int
+ def __init__(
+ self,
+ *,
+ writer_handle: builtins.int | None = ...,
+ reason: builtins.str | None = ...,
+ request_async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["reason", b"reason", "request_async_id", b"request_async_id", "writer_handle", b"writer_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["reason", b"reason", "request_async_id", b"request_async_id", "writer_handle", b"writer_handle"]) -> None: ...
+
+global___TextStreamWriterCloseRequest = TextStreamWriterCloseRequest
+
+@typing.final
+class TextStreamWriterCloseResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
+
+global___TextStreamWriterCloseResponse = TextStreamWriterCloseResponse
+
+@typing.final
+class TextStreamWriterCloseCallback(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ ERROR_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ @property
+ def error(self) -> global___StreamError: ...
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ error: global___StreamError | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> None: ...
+
+global___TextStreamWriterCloseCallback = TextStreamWriterCloseCallback
+
+@typing.final
+class TextStreamInfo(google.protobuf.message.Message):
+ """Contains a subset of the fields from the stream header.
+ Protocol-level fields not relevant to the FFI client are omitted (e.g. encryption info).
+ """
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ class _OperationType:
+ ValueType = typing.NewType("ValueType", builtins.int)
+ V: typing_extensions.TypeAlias = ValueType
+
+ class _OperationTypeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[TextStreamInfo._OperationType.ValueType], builtins.type):
+ DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
+ CREATE: TextStreamInfo._OperationType.ValueType # 0
+ UPDATE: TextStreamInfo._OperationType.ValueType # 1
+ DELETE: TextStreamInfo._OperationType.ValueType # 2
+ REACTION: TextStreamInfo._OperationType.ValueType # 3
+
+ class OperationType(_OperationType, metaclass=_OperationTypeEnumTypeWrapper): ...
+ CREATE: TextStreamInfo.OperationType.ValueType # 0
+ UPDATE: TextStreamInfo.OperationType.ValueType # 1
+ DELETE: TextStreamInfo.OperationType.ValueType # 2
+ REACTION: TextStreamInfo.OperationType.ValueType # 3
+
+ @typing.final
+ class AttributesEntry(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ KEY_FIELD_NUMBER: builtins.int
+ VALUE_FIELD_NUMBER: builtins.int
+ key: builtins.str
+ value: builtins.str
+ def __init__(
+ self,
+ *,
+ key: builtins.str | None = ...,
+ value: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> None: ...
+
+ STREAM_ID_FIELD_NUMBER: builtins.int
+ TIMESTAMP_FIELD_NUMBER: builtins.int
+ MIME_TYPE_FIELD_NUMBER: builtins.int
+ TOPIC_FIELD_NUMBER: builtins.int
+ TOTAL_LENGTH_FIELD_NUMBER: builtins.int
+ ATTRIBUTES_FIELD_NUMBER: builtins.int
+ OPERATION_TYPE_FIELD_NUMBER: builtins.int
+ VERSION_FIELD_NUMBER: builtins.int
+ REPLY_TO_STREAM_ID_FIELD_NUMBER: builtins.int
+ ATTACHED_STREAM_IDS_FIELD_NUMBER: builtins.int
+ GENERATED_FIELD_NUMBER: builtins.int
+ ENCRYPTION_TYPE_FIELD_NUMBER: builtins.int
+ stream_id: builtins.str
+ """unique identifier for this data stream"""
+ timestamp: builtins.int
+ """using int64 for Unix timestamp"""
+ mime_type: builtins.str
+ topic: builtins.str
+ total_length: builtins.int
+ """only populated for finite streams, if it's a stream of unknown size this stays empty"""
+ operation_type: global___TextStreamInfo.OperationType.ValueType
+ version: builtins.int
+ """Optional: Version for updates/edits"""
+ reply_to_stream_id: builtins.str
+ """Optional: Reply to specific message"""
+ generated: builtins.bool
+ """true if the text has been generated by an agent from a participant's audio transcription"""
+ encryption_type: e2ee_pb2.EncryptionType.ValueType
+ @property
+ def attributes(self) -> google.protobuf.internal.containers.ScalarMap[builtins.str, builtins.str]:
+ """user defined attributes map that can carry additional info"""
+
+ @property
+ def attached_stream_ids(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]:
+ """file attachments for text streams"""
+
+ def __init__(
+ self,
+ *,
+ stream_id: builtins.str | None = ...,
+ timestamp: builtins.int | None = ...,
+ mime_type: builtins.str | None = ...,
+ topic: builtins.str | None = ...,
+ total_length: builtins.int | None = ...,
+ attributes: collections.abc.Mapping[builtins.str, builtins.str] | None = ...,
+ operation_type: global___TextStreamInfo.OperationType.ValueType | None = ...,
+ version: builtins.int | None = ...,
+ reply_to_stream_id: builtins.str | None = ...,
+ attached_stream_ids: collections.abc.Iterable[builtins.str] | None = ...,
+ generated: builtins.bool | None = ...,
+ encryption_type: e2ee_pb2.EncryptionType.ValueType | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["encryption_type", b"encryption_type", "generated", b"generated", "mime_type", b"mime_type", "operation_type", b"operation_type", "reply_to_stream_id", b"reply_to_stream_id", "stream_id", b"stream_id", "timestamp", b"timestamp", "topic", b"topic", "total_length", b"total_length", "version", b"version"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["attached_stream_ids", b"attached_stream_ids", "attributes", b"attributes", "encryption_type", b"encryption_type", "generated", b"generated", "mime_type", b"mime_type", "operation_type", b"operation_type", "reply_to_stream_id", b"reply_to_stream_id", "stream_id", b"stream_id", "timestamp", b"timestamp", "topic", b"topic", "total_length", b"total_length", "version", b"version"]) -> None: ...
+
+global___TextStreamInfo = TextStreamInfo
+
+@typing.final
+class ByteStreamInfo(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ @typing.final
+ class AttributesEntry(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ KEY_FIELD_NUMBER: builtins.int
+ VALUE_FIELD_NUMBER: builtins.int
+ key: builtins.str
+ value: builtins.str
+ def __init__(
+ self,
+ *,
+ key: builtins.str | None = ...,
+ value: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> None: ...
+
+ STREAM_ID_FIELD_NUMBER: builtins.int
+ TIMESTAMP_FIELD_NUMBER: builtins.int
+ MIME_TYPE_FIELD_NUMBER: builtins.int
+ TOPIC_FIELD_NUMBER: builtins.int
+ TOTAL_LENGTH_FIELD_NUMBER: builtins.int
+ ATTRIBUTES_FIELD_NUMBER: builtins.int
+ NAME_FIELD_NUMBER: builtins.int
+ ENCRYPTION_TYPE_FIELD_NUMBER: builtins.int
+ stream_id: builtins.str
+ """unique identifier for this data stream"""
+ timestamp: builtins.int
+ """using int64 for Unix timestamp"""
+ mime_type: builtins.str
+ topic: builtins.str
+ total_length: builtins.int
+ """only populated for finite streams, if it's a stream of unknown size this stays empty"""
+ name: builtins.str
+ encryption_type: e2ee_pb2.EncryptionType.ValueType
+ @property
+ def attributes(self) -> google.protobuf.internal.containers.ScalarMap[builtins.str, builtins.str]:
+ """user defined attributes map that can carry additional info"""
+
+ def __init__(
+ self,
+ *,
+ stream_id: builtins.str | None = ...,
+ timestamp: builtins.int | None = ...,
+ mime_type: builtins.str | None = ...,
+ topic: builtins.str | None = ...,
+ total_length: builtins.int | None = ...,
+ attributes: collections.abc.Mapping[builtins.str, builtins.str] | None = ...,
+ name: builtins.str | None = ...,
+ encryption_type: e2ee_pb2.EncryptionType.ValueType | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["encryption_type", b"encryption_type", "mime_type", b"mime_type", "name", b"name", "stream_id", b"stream_id", "timestamp", b"timestamp", "topic", b"topic", "total_length", b"total_length"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["attributes", b"attributes", "encryption_type", b"encryption_type", "mime_type", b"mime_type", "name", b"name", "stream_id", b"stream_id", "timestamp", b"timestamp", "topic", b"topic", "total_length", b"total_length"]) -> None: ...
+
+global___ByteStreamInfo = ByteStreamInfo
+
+@typing.final
+class StreamTextOptions(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ @typing.final
+ class AttributesEntry(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ KEY_FIELD_NUMBER: builtins.int
+ VALUE_FIELD_NUMBER: builtins.int
+ key: builtins.str
+ value: builtins.str
+ def __init__(
+ self,
+ *,
+ key: builtins.str | None = ...,
+ value: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> None: ...
+
+ TOPIC_FIELD_NUMBER: builtins.int
+ ATTRIBUTES_FIELD_NUMBER: builtins.int
+ DESTINATION_IDENTITIES_FIELD_NUMBER: builtins.int
+ ID_FIELD_NUMBER: builtins.int
+ OPERATION_TYPE_FIELD_NUMBER: builtins.int
+ VERSION_FIELD_NUMBER: builtins.int
+ REPLY_TO_STREAM_ID_FIELD_NUMBER: builtins.int
+ ATTACHED_STREAM_IDS_FIELD_NUMBER: builtins.int
+ GENERATED_FIELD_NUMBER: builtins.int
+ topic: builtins.str
+ id: builtins.str
+ operation_type: global___TextStreamInfo.OperationType.ValueType
+ version: builtins.int
+ reply_to_stream_id: builtins.str
+ generated: builtins.bool
+ @property
+ def attributes(self) -> google.protobuf.internal.containers.ScalarMap[builtins.str, builtins.str]: ...
+ @property
+ def destination_identities(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ...
+ @property
+ def attached_stream_ids(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ...
+ def __init__(
+ self,
+ *,
+ topic: builtins.str | None = ...,
+ attributes: collections.abc.Mapping[builtins.str, builtins.str] | None = ...,
+ destination_identities: collections.abc.Iterable[builtins.str] | None = ...,
+ id: builtins.str | None = ...,
+ operation_type: global___TextStreamInfo.OperationType.ValueType | None = ...,
+ version: builtins.int | None = ...,
+ reply_to_stream_id: builtins.str | None = ...,
+ attached_stream_ids: collections.abc.Iterable[builtins.str] | None = ...,
+ generated: builtins.bool | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["generated", b"generated", "id", b"id", "operation_type", b"operation_type", "reply_to_stream_id", b"reply_to_stream_id", "topic", b"topic", "version", b"version"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["attached_stream_ids", b"attached_stream_ids", "attributes", b"attributes", "destination_identities", b"destination_identities", "generated", b"generated", "id", b"id", "operation_type", b"operation_type", "reply_to_stream_id", b"reply_to_stream_id", "topic", b"topic", "version", b"version"]) -> None: ...
+
+global___StreamTextOptions = StreamTextOptions
+
+@typing.final
+class StreamByteOptions(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ @typing.final
+ class AttributesEntry(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ KEY_FIELD_NUMBER: builtins.int
+ VALUE_FIELD_NUMBER: builtins.int
+ key: builtins.str
+ value: builtins.str
+ def __init__(
+ self,
+ *,
+ key: builtins.str | None = ...,
+ value: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> None: ...
+
+ TOPIC_FIELD_NUMBER: builtins.int
+ ATTRIBUTES_FIELD_NUMBER: builtins.int
+ DESTINATION_IDENTITIES_FIELD_NUMBER: builtins.int
+ ID_FIELD_NUMBER: builtins.int
+ NAME_FIELD_NUMBER: builtins.int
+ MIME_TYPE_FIELD_NUMBER: builtins.int
+ TOTAL_LENGTH_FIELD_NUMBER: builtins.int
+ topic: builtins.str
+ id: builtins.str
+ name: builtins.str
+ mime_type: builtins.str
+ total_length: builtins.int
+ @property
+ def attributes(self) -> google.protobuf.internal.containers.ScalarMap[builtins.str, builtins.str]: ...
+ @property
+ def destination_identities(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ...
+ def __init__(
+ self,
+ *,
+ topic: builtins.str | None = ...,
+ attributes: collections.abc.Mapping[builtins.str, builtins.str] | None = ...,
+ destination_identities: collections.abc.Iterable[builtins.str] | None = ...,
+ id: builtins.str | None = ...,
+ name: builtins.str | None = ...,
+ mime_type: builtins.str | None = ...,
+ total_length: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["id", b"id", "mime_type", b"mime_type", "name", b"name", "topic", b"topic", "total_length", b"total_length"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["attributes", b"attributes", "destination_identities", b"destination_identities", "id", b"id", "mime_type", b"mime_type", "name", b"name", "topic", b"topic", "total_length", b"total_length"]) -> None: ...
+
+global___StreamByteOptions = StreamByteOptions
+
+@typing.final
+class StreamError(google.protobuf.message.Message):
+ """Error pertaining to a stream."""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ DESCRIPTION_FIELD_NUMBER: builtins.int
+ description: builtins.str
+ """TODO(ladvoc): make this an enum."""
+ def __init__(
+ self,
+ *,
+ description: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["description", b"description"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["description", b"description"]) -> None: ...
+
+global___StreamError = StreamError
diff --git a/livekit-rtc/livekit/rtc/_proto/data_track_pb2.py b/livekit-rtc/livekit/rtc/_proto/data_track_pb2.py
new file mode 100644
index 00000000..f59f0bf7
--- /dev/null
+++ b/livekit-rtc/livekit/rtc/_proto/data_track_pb2.py
@@ -0,0 +1,92 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: data_track.proto
+# Protobuf Python Version: 4.25.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from . import handle_pb2 as handle__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x10\x64\x61ta_track.proto\x12\rlivekit.proto\x1a\x0chandle.proto\"=\n\rDataTrackInfo\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x0b\n\x03sid\x18\x02 \x02(\t\x12\x11\n\tuses_e2ee\x18\x03 \x02(\x08\"9\n\x0e\x44\x61taTrackFrame\x12\x0f\n\x07payload\x18\x01 \x02(\x0c\x12\x16\n\x0euser_timestamp\x18\x02 \x01(\x04\"R\n\x0e\x44\x61taTrackError\x12/\n\x04\x63ode\x18\x01 \x02(\x0e\x32!.livekit.proto.DataTrackErrorCode\x12\x0f\n\x07message\x18\x02 \x02(\t\"`\n\x15PublishDataTrackError\x12\x36\n\x04\x63ode\x18\x01 \x02(\x0e\x32(.livekit.proto.PublishDataTrackErrorCode\x12\x0f\n\x07message\x18\x02 \x02(\t\"j\n\x1aLocalDataTrackTryPushError\x12;\n\x04\x63ode\x18\x01 \x02(\x0e\x32-.livekit.proto.LocalDataTrackTryPushErrorCode\x12\x0f\n\x07message\x18\x02 \x02(\t\"d\n\x17SubscribeDataTrackError\x12\x38\n\x04\x63ode\x18\x01 \x02(\x0e\x32*.livekit.proto.SubscribeDataTrackErrorCode\x12\x0f\n\x07message\x18\x02 \x02(\t\" \n\x10\x44\x61taTrackOptions\x12\x0c\n\x04name\x18\x01 \x02(\t\"\x87\x01\n\x17PublishDataTrackRequest\x12 \n\x18local_participant_handle\x18\x01 \x02(\x04\x12\x30\n\x07options\x18\x02 \x02(\x0b\x32\x1f.livekit.proto.DataTrackOptions\x12\x18\n\x10request_async_id\x18\x03 \x01(\x04\",\n\x18PublishDataTrackResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"\xa2\x01\n\x18PublishDataTrackCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12\x33\n\x05track\x18\x02 \x01(\x0b\x32\".livekit.proto.OwnedLocalDataTrackH\x00\x12\x35\n\x05\x65rror\x18\x03 \x01(\x0b\x32$.livekit.proto.PublishDataTrackErrorH\x00\x42\x08\n\x06result\"p\n\x13OwnedLocalDataTrack\x12-\n\x06handle\x18\x01 \x02(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12*\n\x04info\x18\x02 \x02(\x0b\x32\x1c.livekit.proto.DataTrackInfo\"b\n\x1cLocalDataTrackTryPushRequest\x12\x14\n\x0ctrack_handle\x18\x01 \x02(\x04\x12,\n\x05\x66rame\x18\x02 \x02(\x0b\x32\x1d.livekit.proto.DataTrackFrame\"Y\n\x1dLocalDataTrackTryPushResponse\x12\x38\n\x05\x65rror\x18\x02 \x01(\x0b\x32).livekit.proto.LocalDataTrackTryPushError\"8\n LocalDataTrackIsPublishedRequest\x12\x14\n\x0ctrack_handle\x18\x01 \x02(\x04\"9\n!LocalDataTrackIsPublishedResponse\x12\x14\n\x0cis_published\x18\x01 \x02(\x08\"6\n\x1eLocalDataTrackUnpublishRequest\x12\x14\n\x0ctrack_handle\x18\x01 \x02(\x04\"!\n\x1fLocalDataTrackUnpublishResponse\"\x8d\x01\n\x14OwnedRemoteDataTrack\x12-\n\x06handle\x18\x01 \x02(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12*\n\x04info\x18\x02 \x02(\x0b\x32\x1c.livekit.proto.DataTrackInfo\x12\x1a\n\x12publisher_identity\x18\x03 \x02(\t\"E\n\x14OwnedDataTrackStream\x12-\n\x06handle\x18\x01 \x02(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\"0\n\x19\x44\x61taTrackSubscribeOptions\x12\x13\n\x0b\x62uffer_size\x18\x01 \x01(\r\"9\n!RemoteDataTrackIsPublishedRequest\x12\x14\n\x0ctrack_handle\x18\x01 \x02(\x04\":\n\"RemoteDataTrackIsPublishedResponse\x12\x14\n\x0cis_published\x18\x01 \x02(\x08\"l\n\x19SubscribeDataTrackRequest\x12\x14\n\x0ctrack_handle\x18\x01 \x02(\x04\x12\x39\n\x07options\x18\x02 \x02(\x0b\x32(.livekit.proto.DataTrackSubscribeOptions\"Q\n\x1aSubscribeDataTrackResponse\x12\x33\n\x06stream\x18\x01 \x02(\x0b\x32#.livekit.proto.OwnedDataTrackStream\"3\n\x1a\x44\x61taTrackStreamReadRequest\x12\x15\n\rstream_handle\x18\x01 \x02(\x04\"\x1d\n\x1b\x44\x61taTrackStreamReadResponse\"\xb0\x01\n\x14\x44\x61taTrackStreamEvent\x12\x15\n\rstream_handle\x18\x01 \x02(\x04\x12\x45\n\x0e\x66rame_received\x18\x02 \x01(\x0b\x32+.livekit.proto.DataTrackStreamFrameReceivedH\x00\x12\x30\n\x03\x65os\x18\x03 \x01(\x0b\x32!.livekit.proto.DataTrackStreamEOSH\x00\x42\x08\n\x06\x64\x65tail\"L\n\x1c\x44\x61taTrackStreamFrameReceived\x12,\n\x05\x66rame\x18\x01 \x02(\x0b\x32\x1d.livekit.proto.DataTrackFrame\"#\n\x12\x44\x61taTrackStreamEOS\x12\r\n\x05\x65rror\x18\x01 \x01(\t*\x87\x03\n\x12\x44\x61taTrackErrorCode\x12!\n\x1d\x44\x41TA_TRACK_ERROR_CODE_UNKNOWN\x10\x00\x12(\n$DATA_TRACK_ERROR_CODE_INVALID_HANDLE\x10\x01\x12.\n*DATA_TRACK_ERROR_CODE_DUPLICATE_TRACK_NAME\x10\x02\x12+\n\'DATA_TRACK_ERROR_CODE_TRACK_UNPUBLISHED\x10\x03\x12%\n!DATA_TRACK_ERROR_CODE_BUFFER_FULL\x10\x04\x12-\n)DATA_TRACK_ERROR_CODE_SUBSCRIPTION_CLOSED\x10\x05\x12#\n\x1f\x44\x41TA_TRACK_ERROR_CODE_CANCELLED\x10\x06\x12(\n$DATA_TRACK_ERROR_CODE_PROTOCOL_ERROR\x10\x07\x12\"\n\x1e\x44\x41TA_TRACK_ERROR_CODE_INTERNAL\x10\x08*\xf3\x03\n\x19PublishDataTrackErrorCode\x12)\n%PUBLISH_DATA_TRACK_ERROR_CODE_UNKNOWN\x10\x00\x12\x30\n,PUBLISH_DATA_TRACK_ERROR_CODE_INVALID_HANDLE\x10\x01\x12\x30\n,PUBLISH_DATA_TRACK_ERROR_CODE_DUPLICATE_NAME\x10\x02\x12)\n%PUBLISH_DATA_TRACK_ERROR_CODE_TIMEOUT\x10\x03\x12.\n*PUBLISH_DATA_TRACK_ERROR_CODE_DISCONNECTED\x10\x04\x12-\n)PUBLISH_DATA_TRACK_ERROR_CODE_NOT_ALLOWED\x10\x05\x12.\n*PUBLISH_DATA_TRACK_ERROR_CODE_INVALID_NAME\x10\x06\x12/\n+PUBLISH_DATA_TRACK_ERROR_CODE_LIMIT_REACHED\x10\x07\x12\x30\n,PUBLISH_DATA_TRACK_ERROR_CODE_PROTOCOL_ERROR\x10\x08\x12*\n&PUBLISH_DATA_TRACK_ERROR_CODE_INTERNAL\x10\t*\xaf\x02\n\x1eLocalDataTrackTryPushErrorCode\x12\x30\n,LOCAL_DATA_TRACK_TRY_PUSH_ERROR_CODE_UNKNOWN\x10\x00\x12\x37\n3LOCAL_DATA_TRACK_TRY_PUSH_ERROR_CODE_INVALID_HANDLE\x10\x01\x12:\n6LOCAL_DATA_TRACK_TRY_PUSH_ERROR_CODE_TRACK_UNPUBLISHED\x10\x02\x12\x33\n/LOCAL_DATA_TRACK_TRY_PUSH_ERROR_CODE_QUEUE_FULL\x10\x03\x12\x31\n-LOCAL_DATA_TRACK_TRY_PUSH_ERROR_CODE_INTERNAL\x10\x04*\xf0\x02\n\x1bSubscribeDataTrackErrorCode\x12+\n\'SUBSCRIBE_DATA_TRACK_ERROR_CODE_UNKNOWN\x10\x00\x12\x32\n.SUBSCRIBE_DATA_TRACK_ERROR_CODE_INVALID_HANDLE\x10\x01\x12/\n+SUBSCRIBE_DATA_TRACK_ERROR_CODE_UNPUBLISHED\x10\x02\x12+\n\'SUBSCRIBE_DATA_TRACK_ERROR_CODE_TIMEOUT\x10\x03\x12\x30\n,SUBSCRIBE_DATA_TRACK_ERROR_CODE_DISCONNECTED\x10\x04\x12\x32\n.SUBSCRIBE_DATA_TRACK_ERROR_CODE_PROTOCOL_ERROR\x10\x05\x12,\n(SUBSCRIBE_DATA_TRACK_ERROR_CODE_INTERNAL\x10\x06\x42\x10\xaa\x02\rLiveKit.Proto')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'data_track_pb2', _globals)
+if _descriptor._USE_C_DESCRIPTORS == False:
+ _globals['DESCRIPTOR']._options = None
+ _globals['DESCRIPTOR']._serialized_options = b'\252\002\rLiveKit.Proto'
+ _globals['_DATATRACKERRORCODE']._serialized_start=2415
+ _globals['_DATATRACKERRORCODE']._serialized_end=2806
+ _globals['_PUBLISHDATATRACKERRORCODE']._serialized_start=2809
+ _globals['_PUBLISHDATATRACKERRORCODE']._serialized_end=3308
+ _globals['_LOCALDATATRACKTRYPUSHERRORCODE']._serialized_start=3311
+ _globals['_LOCALDATATRACKTRYPUSHERRORCODE']._serialized_end=3614
+ _globals['_SUBSCRIBEDATATRACKERRORCODE']._serialized_start=3617
+ _globals['_SUBSCRIBEDATATRACKERRORCODE']._serialized_end=3985
+ _globals['_DATATRACKINFO']._serialized_start=49
+ _globals['_DATATRACKINFO']._serialized_end=110
+ _globals['_DATATRACKFRAME']._serialized_start=112
+ _globals['_DATATRACKFRAME']._serialized_end=169
+ _globals['_DATATRACKERROR']._serialized_start=171
+ _globals['_DATATRACKERROR']._serialized_end=253
+ _globals['_PUBLISHDATATRACKERROR']._serialized_start=255
+ _globals['_PUBLISHDATATRACKERROR']._serialized_end=351
+ _globals['_LOCALDATATRACKTRYPUSHERROR']._serialized_start=353
+ _globals['_LOCALDATATRACKTRYPUSHERROR']._serialized_end=459
+ _globals['_SUBSCRIBEDATATRACKERROR']._serialized_start=461
+ _globals['_SUBSCRIBEDATATRACKERROR']._serialized_end=561
+ _globals['_DATATRACKOPTIONS']._serialized_start=563
+ _globals['_DATATRACKOPTIONS']._serialized_end=595
+ _globals['_PUBLISHDATATRACKREQUEST']._serialized_start=598
+ _globals['_PUBLISHDATATRACKREQUEST']._serialized_end=733
+ _globals['_PUBLISHDATATRACKRESPONSE']._serialized_start=735
+ _globals['_PUBLISHDATATRACKRESPONSE']._serialized_end=779
+ _globals['_PUBLISHDATATRACKCALLBACK']._serialized_start=782
+ _globals['_PUBLISHDATATRACKCALLBACK']._serialized_end=944
+ _globals['_OWNEDLOCALDATATRACK']._serialized_start=946
+ _globals['_OWNEDLOCALDATATRACK']._serialized_end=1058
+ _globals['_LOCALDATATRACKTRYPUSHREQUEST']._serialized_start=1060
+ _globals['_LOCALDATATRACKTRYPUSHREQUEST']._serialized_end=1158
+ _globals['_LOCALDATATRACKTRYPUSHRESPONSE']._serialized_start=1160
+ _globals['_LOCALDATATRACKTRYPUSHRESPONSE']._serialized_end=1249
+ _globals['_LOCALDATATRACKISPUBLISHEDREQUEST']._serialized_start=1251
+ _globals['_LOCALDATATRACKISPUBLISHEDREQUEST']._serialized_end=1307
+ _globals['_LOCALDATATRACKISPUBLISHEDRESPONSE']._serialized_start=1309
+ _globals['_LOCALDATATRACKISPUBLISHEDRESPONSE']._serialized_end=1366
+ _globals['_LOCALDATATRACKUNPUBLISHREQUEST']._serialized_start=1368
+ _globals['_LOCALDATATRACKUNPUBLISHREQUEST']._serialized_end=1422
+ _globals['_LOCALDATATRACKUNPUBLISHRESPONSE']._serialized_start=1424
+ _globals['_LOCALDATATRACKUNPUBLISHRESPONSE']._serialized_end=1457
+ _globals['_OWNEDREMOTEDATATRACK']._serialized_start=1460
+ _globals['_OWNEDREMOTEDATATRACK']._serialized_end=1601
+ _globals['_OWNEDDATATRACKSTREAM']._serialized_start=1603
+ _globals['_OWNEDDATATRACKSTREAM']._serialized_end=1672
+ _globals['_DATATRACKSUBSCRIBEOPTIONS']._serialized_start=1674
+ _globals['_DATATRACKSUBSCRIBEOPTIONS']._serialized_end=1722
+ _globals['_REMOTEDATATRACKISPUBLISHEDREQUEST']._serialized_start=1724
+ _globals['_REMOTEDATATRACKISPUBLISHEDREQUEST']._serialized_end=1781
+ _globals['_REMOTEDATATRACKISPUBLISHEDRESPONSE']._serialized_start=1783
+ _globals['_REMOTEDATATRACKISPUBLISHEDRESPONSE']._serialized_end=1841
+ _globals['_SUBSCRIBEDATATRACKREQUEST']._serialized_start=1843
+ _globals['_SUBSCRIBEDATATRACKREQUEST']._serialized_end=1951
+ _globals['_SUBSCRIBEDATATRACKRESPONSE']._serialized_start=1953
+ _globals['_SUBSCRIBEDATATRACKRESPONSE']._serialized_end=2034
+ _globals['_DATATRACKSTREAMREADREQUEST']._serialized_start=2036
+ _globals['_DATATRACKSTREAMREADREQUEST']._serialized_end=2087
+ _globals['_DATATRACKSTREAMREADRESPONSE']._serialized_start=2089
+ _globals['_DATATRACKSTREAMREADRESPONSE']._serialized_end=2118
+ _globals['_DATATRACKSTREAMEVENT']._serialized_start=2121
+ _globals['_DATATRACKSTREAMEVENT']._serialized_end=2297
+ _globals['_DATATRACKSTREAMFRAMERECEIVED']._serialized_start=2299
+ _globals['_DATATRACKSTREAMFRAMERECEIVED']._serialized_end=2375
+ _globals['_DATATRACKSTREAMEOS']._serialized_start=2377
+ _globals['_DATATRACKSTREAMEOS']._serialized_end=2412
+# @@protoc_insertion_point(module_scope)
diff --git a/livekit-rtc/livekit/rtc/_proto/data_track_pb2.pyi b/livekit-rtc/livekit/rtc/_proto/data_track_pb2.pyi
new file mode 100644
index 00000000..a12996c2
--- /dev/null
+++ b/livekit-rtc/livekit/rtc/_proto/data_track_pb2.pyi
@@ -0,0 +1,719 @@
+"""
+@generated by mypy-protobuf. Do not edit manually!
+isort:skip_file
+Copyright 2026 LiveKit, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import builtins
+import google.protobuf.descriptor
+import google.protobuf.internal.enum_type_wrapper
+import google.protobuf.message
+from . import handle_pb2
+import sys
+import typing
+
+if sys.version_info >= (3, 10):
+ import typing as typing_extensions
+else:
+ import typing_extensions
+
+DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
+
+class _DataTrackErrorCode:
+ ValueType = typing.NewType("ValueType", builtins.int)
+ V: typing_extensions.TypeAlias = ValueType
+
+class _DataTrackErrorCodeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_DataTrackErrorCode.ValueType], builtins.type):
+ DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
+ DATA_TRACK_ERROR_CODE_UNKNOWN: _DataTrackErrorCode.ValueType # 0
+ DATA_TRACK_ERROR_CODE_INVALID_HANDLE: _DataTrackErrorCode.ValueType # 1
+ DATA_TRACK_ERROR_CODE_DUPLICATE_TRACK_NAME: _DataTrackErrorCode.ValueType # 2
+ DATA_TRACK_ERROR_CODE_TRACK_UNPUBLISHED: _DataTrackErrorCode.ValueType # 3
+ DATA_TRACK_ERROR_CODE_BUFFER_FULL: _DataTrackErrorCode.ValueType # 4
+ DATA_TRACK_ERROR_CODE_SUBSCRIPTION_CLOSED: _DataTrackErrorCode.ValueType # 5
+ DATA_TRACK_ERROR_CODE_CANCELLED: _DataTrackErrorCode.ValueType # 6
+ DATA_TRACK_ERROR_CODE_PROTOCOL_ERROR: _DataTrackErrorCode.ValueType # 7
+ DATA_TRACK_ERROR_CODE_INTERNAL: _DataTrackErrorCode.ValueType # 8
+
+class DataTrackErrorCode(_DataTrackErrorCode, metaclass=_DataTrackErrorCodeEnumTypeWrapper): ...
+
+DATA_TRACK_ERROR_CODE_UNKNOWN: DataTrackErrorCode.ValueType # 0
+DATA_TRACK_ERROR_CODE_INVALID_HANDLE: DataTrackErrorCode.ValueType # 1
+DATA_TRACK_ERROR_CODE_DUPLICATE_TRACK_NAME: DataTrackErrorCode.ValueType # 2
+DATA_TRACK_ERROR_CODE_TRACK_UNPUBLISHED: DataTrackErrorCode.ValueType # 3
+DATA_TRACK_ERROR_CODE_BUFFER_FULL: DataTrackErrorCode.ValueType # 4
+DATA_TRACK_ERROR_CODE_SUBSCRIPTION_CLOSED: DataTrackErrorCode.ValueType # 5
+DATA_TRACK_ERROR_CODE_CANCELLED: DataTrackErrorCode.ValueType # 6
+DATA_TRACK_ERROR_CODE_PROTOCOL_ERROR: DataTrackErrorCode.ValueType # 7
+DATA_TRACK_ERROR_CODE_INTERNAL: DataTrackErrorCode.ValueType # 8
+global___DataTrackErrorCode = DataTrackErrorCode
+
+class _PublishDataTrackErrorCode:
+ ValueType = typing.NewType("ValueType", builtins.int)
+ V: typing_extensions.TypeAlias = ValueType
+
+class _PublishDataTrackErrorCodeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_PublishDataTrackErrorCode.ValueType], builtins.type):
+ DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
+ PUBLISH_DATA_TRACK_ERROR_CODE_UNKNOWN: _PublishDataTrackErrorCode.ValueType # 0
+ PUBLISH_DATA_TRACK_ERROR_CODE_INVALID_HANDLE: _PublishDataTrackErrorCode.ValueType # 1
+ PUBLISH_DATA_TRACK_ERROR_CODE_DUPLICATE_NAME: _PublishDataTrackErrorCode.ValueType # 2
+ PUBLISH_DATA_TRACK_ERROR_CODE_TIMEOUT: _PublishDataTrackErrorCode.ValueType # 3
+ PUBLISH_DATA_TRACK_ERROR_CODE_DISCONNECTED: _PublishDataTrackErrorCode.ValueType # 4
+ PUBLISH_DATA_TRACK_ERROR_CODE_NOT_ALLOWED: _PublishDataTrackErrorCode.ValueType # 5
+ PUBLISH_DATA_TRACK_ERROR_CODE_INVALID_NAME: _PublishDataTrackErrorCode.ValueType # 6
+ PUBLISH_DATA_TRACK_ERROR_CODE_LIMIT_REACHED: _PublishDataTrackErrorCode.ValueType # 7
+ PUBLISH_DATA_TRACK_ERROR_CODE_PROTOCOL_ERROR: _PublishDataTrackErrorCode.ValueType # 8
+ PUBLISH_DATA_TRACK_ERROR_CODE_INTERNAL: _PublishDataTrackErrorCode.ValueType # 9
+
+class PublishDataTrackErrorCode(_PublishDataTrackErrorCode, metaclass=_PublishDataTrackErrorCodeEnumTypeWrapper): ...
+
+PUBLISH_DATA_TRACK_ERROR_CODE_UNKNOWN: PublishDataTrackErrorCode.ValueType # 0
+PUBLISH_DATA_TRACK_ERROR_CODE_INVALID_HANDLE: PublishDataTrackErrorCode.ValueType # 1
+PUBLISH_DATA_TRACK_ERROR_CODE_DUPLICATE_NAME: PublishDataTrackErrorCode.ValueType # 2
+PUBLISH_DATA_TRACK_ERROR_CODE_TIMEOUT: PublishDataTrackErrorCode.ValueType # 3
+PUBLISH_DATA_TRACK_ERROR_CODE_DISCONNECTED: PublishDataTrackErrorCode.ValueType # 4
+PUBLISH_DATA_TRACK_ERROR_CODE_NOT_ALLOWED: PublishDataTrackErrorCode.ValueType # 5
+PUBLISH_DATA_TRACK_ERROR_CODE_INVALID_NAME: PublishDataTrackErrorCode.ValueType # 6
+PUBLISH_DATA_TRACK_ERROR_CODE_LIMIT_REACHED: PublishDataTrackErrorCode.ValueType # 7
+PUBLISH_DATA_TRACK_ERROR_CODE_PROTOCOL_ERROR: PublishDataTrackErrorCode.ValueType # 8
+PUBLISH_DATA_TRACK_ERROR_CODE_INTERNAL: PublishDataTrackErrorCode.ValueType # 9
+global___PublishDataTrackErrorCode = PublishDataTrackErrorCode
+
+class _LocalDataTrackTryPushErrorCode:
+ ValueType = typing.NewType("ValueType", builtins.int)
+ V: typing_extensions.TypeAlias = ValueType
+
+class _LocalDataTrackTryPushErrorCodeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_LocalDataTrackTryPushErrorCode.ValueType], builtins.type):
+ DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
+ LOCAL_DATA_TRACK_TRY_PUSH_ERROR_CODE_UNKNOWN: _LocalDataTrackTryPushErrorCode.ValueType # 0
+ LOCAL_DATA_TRACK_TRY_PUSH_ERROR_CODE_INVALID_HANDLE: _LocalDataTrackTryPushErrorCode.ValueType # 1
+ LOCAL_DATA_TRACK_TRY_PUSH_ERROR_CODE_TRACK_UNPUBLISHED: _LocalDataTrackTryPushErrorCode.ValueType # 2
+ LOCAL_DATA_TRACK_TRY_PUSH_ERROR_CODE_QUEUE_FULL: _LocalDataTrackTryPushErrorCode.ValueType # 3
+ LOCAL_DATA_TRACK_TRY_PUSH_ERROR_CODE_INTERNAL: _LocalDataTrackTryPushErrorCode.ValueType # 4
+
+class LocalDataTrackTryPushErrorCode(_LocalDataTrackTryPushErrorCode, metaclass=_LocalDataTrackTryPushErrorCodeEnumTypeWrapper): ...
+
+LOCAL_DATA_TRACK_TRY_PUSH_ERROR_CODE_UNKNOWN: LocalDataTrackTryPushErrorCode.ValueType # 0
+LOCAL_DATA_TRACK_TRY_PUSH_ERROR_CODE_INVALID_HANDLE: LocalDataTrackTryPushErrorCode.ValueType # 1
+LOCAL_DATA_TRACK_TRY_PUSH_ERROR_CODE_TRACK_UNPUBLISHED: LocalDataTrackTryPushErrorCode.ValueType # 2
+LOCAL_DATA_TRACK_TRY_PUSH_ERROR_CODE_QUEUE_FULL: LocalDataTrackTryPushErrorCode.ValueType # 3
+LOCAL_DATA_TRACK_TRY_PUSH_ERROR_CODE_INTERNAL: LocalDataTrackTryPushErrorCode.ValueType # 4
+global___LocalDataTrackTryPushErrorCode = LocalDataTrackTryPushErrorCode
+
+class _SubscribeDataTrackErrorCode:
+ ValueType = typing.NewType("ValueType", builtins.int)
+ V: typing_extensions.TypeAlias = ValueType
+
+class _SubscribeDataTrackErrorCodeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_SubscribeDataTrackErrorCode.ValueType], builtins.type):
+ DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
+ SUBSCRIBE_DATA_TRACK_ERROR_CODE_UNKNOWN: _SubscribeDataTrackErrorCode.ValueType # 0
+ SUBSCRIBE_DATA_TRACK_ERROR_CODE_INVALID_HANDLE: _SubscribeDataTrackErrorCode.ValueType # 1
+ SUBSCRIBE_DATA_TRACK_ERROR_CODE_UNPUBLISHED: _SubscribeDataTrackErrorCode.ValueType # 2
+ SUBSCRIBE_DATA_TRACK_ERROR_CODE_TIMEOUT: _SubscribeDataTrackErrorCode.ValueType # 3
+ SUBSCRIBE_DATA_TRACK_ERROR_CODE_DISCONNECTED: _SubscribeDataTrackErrorCode.ValueType # 4
+ SUBSCRIBE_DATA_TRACK_ERROR_CODE_PROTOCOL_ERROR: _SubscribeDataTrackErrorCode.ValueType # 5
+ SUBSCRIBE_DATA_TRACK_ERROR_CODE_INTERNAL: _SubscribeDataTrackErrorCode.ValueType # 6
+
+class SubscribeDataTrackErrorCode(_SubscribeDataTrackErrorCode, metaclass=_SubscribeDataTrackErrorCodeEnumTypeWrapper): ...
+
+SUBSCRIBE_DATA_TRACK_ERROR_CODE_UNKNOWN: SubscribeDataTrackErrorCode.ValueType # 0
+SUBSCRIBE_DATA_TRACK_ERROR_CODE_INVALID_HANDLE: SubscribeDataTrackErrorCode.ValueType # 1
+SUBSCRIBE_DATA_TRACK_ERROR_CODE_UNPUBLISHED: SubscribeDataTrackErrorCode.ValueType # 2
+SUBSCRIBE_DATA_TRACK_ERROR_CODE_TIMEOUT: SubscribeDataTrackErrorCode.ValueType # 3
+SUBSCRIBE_DATA_TRACK_ERROR_CODE_DISCONNECTED: SubscribeDataTrackErrorCode.ValueType # 4
+SUBSCRIBE_DATA_TRACK_ERROR_CODE_PROTOCOL_ERROR: SubscribeDataTrackErrorCode.ValueType # 5
+SUBSCRIBE_DATA_TRACK_ERROR_CODE_INTERNAL: SubscribeDataTrackErrorCode.ValueType # 6
+global___SubscribeDataTrackErrorCode = SubscribeDataTrackErrorCode
+
+@typing.final
+class DataTrackInfo(google.protobuf.message.Message):
+ """MARK: - Common
+
+ Information about a published data track.
+ """
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ NAME_FIELD_NUMBER: builtins.int
+ SID_FIELD_NUMBER: builtins.int
+ USES_E2EE_FIELD_NUMBER: builtins.int
+ name: builtins.str
+ """Name of the track assigned by the publisher."""
+ sid: builtins.str
+ """SFU-assigned track identifier."""
+ uses_e2ee: builtins.bool
+ """Whether or not frames sent on the track use end-to-end encryption."""
+ def __init__(
+ self,
+ *,
+ name: builtins.str | None = ...,
+ sid: builtins.str | None = ...,
+ uses_e2ee: builtins.bool | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["name", b"name", "sid", b"sid", "uses_e2ee", b"uses_e2ee"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["name", b"name", "sid", b"sid", "uses_e2ee", b"uses_e2ee"]) -> None: ...
+
+global___DataTrackInfo = DataTrackInfo
+
+@typing.final
+class DataTrackFrame(google.protobuf.message.Message):
+ """A frame published on a data track."""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ PAYLOAD_FIELD_NUMBER: builtins.int
+ USER_TIMESTAMP_FIELD_NUMBER: builtins.int
+ payload: builtins.bytes
+ user_timestamp: builtins.int
+ def __init__(
+ self,
+ *,
+ payload: builtins.bytes | None = ...,
+ user_timestamp: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["payload", b"payload", "user_timestamp", b"user_timestamp"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["payload", b"payload", "user_timestamp", b"user_timestamp"]) -> None: ...
+
+global___DataTrackFrame = DataTrackFrame
+
+@typing.final
+class DataTrackError(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ CODE_FIELD_NUMBER: builtins.int
+ MESSAGE_FIELD_NUMBER: builtins.int
+ code: global___DataTrackErrorCode.ValueType
+ message: builtins.str
+ def __init__(
+ self,
+ *,
+ code: global___DataTrackErrorCode.ValueType | None = ...,
+ message: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["code", b"code", "message", b"message"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["code", b"code", "message", b"message"]) -> None: ...
+
+global___DataTrackError = DataTrackError
+
+@typing.final
+class PublishDataTrackError(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ CODE_FIELD_NUMBER: builtins.int
+ MESSAGE_FIELD_NUMBER: builtins.int
+ code: global___PublishDataTrackErrorCode.ValueType
+ message: builtins.str
+ def __init__(
+ self,
+ *,
+ code: global___PublishDataTrackErrorCode.ValueType | None = ...,
+ message: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["code", b"code", "message", b"message"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["code", b"code", "message", b"message"]) -> None: ...
+
+global___PublishDataTrackError = PublishDataTrackError
+
+@typing.final
+class LocalDataTrackTryPushError(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ CODE_FIELD_NUMBER: builtins.int
+ MESSAGE_FIELD_NUMBER: builtins.int
+ code: global___LocalDataTrackTryPushErrorCode.ValueType
+ message: builtins.str
+ def __init__(
+ self,
+ *,
+ code: global___LocalDataTrackTryPushErrorCode.ValueType | None = ...,
+ message: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["code", b"code", "message", b"message"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["code", b"code", "message", b"message"]) -> None: ...
+
+global___LocalDataTrackTryPushError = LocalDataTrackTryPushError
+
+@typing.final
+class SubscribeDataTrackError(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ CODE_FIELD_NUMBER: builtins.int
+ MESSAGE_FIELD_NUMBER: builtins.int
+ code: global___SubscribeDataTrackErrorCode.ValueType
+ message: builtins.str
+ def __init__(
+ self,
+ *,
+ code: global___SubscribeDataTrackErrorCode.ValueType | None = ...,
+ message: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["code", b"code", "message", b"message"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["code", b"code", "message", b"message"]) -> None: ...
+
+global___SubscribeDataTrackError = SubscribeDataTrackError
+
+@typing.final
+class DataTrackOptions(google.protobuf.message.Message):
+ """MARK: - Local
+
+ Options for publishing a data track.
+ """
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ NAME_FIELD_NUMBER: builtins.int
+ name: builtins.str
+ """Track name used to identify the track to other participants.
+
+ Must not be empty and must be unique per publisher.
+ """
+ def __init__(
+ self,
+ *,
+ name: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["name", b"name"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["name", b"name"]) -> None: ...
+
+global___DataTrackOptions = DataTrackOptions
+
+@typing.final
+class PublishDataTrackRequest(google.protobuf.message.Message):
+ """Publish a data track"""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ LOCAL_PARTICIPANT_HANDLE_FIELD_NUMBER: builtins.int
+ OPTIONS_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
+ local_participant_handle: builtins.int
+ request_async_id: builtins.int
+ @property
+ def options(self) -> global___DataTrackOptions: ...
+ def __init__(
+ self,
+ *,
+ local_participant_handle: builtins.int | None = ...,
+ options: global___DataTrackOptions | None = ...,
+ request_async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["local_participant_handle", b"local_participant_handle", "options", b"options", "request_async_id", b"request_async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["local_participant_handle", b"local_participant_handle", "options", b"options", "request_async_id", b"request_async_id"]) -> None: ...
+
+global___PublishDataTrackRequest = PublishDataTrackRequest
+
+@typing.final
+class PublishDataTrackResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
+
+global___PublishDataTrackResponse = PublishDataTrackResponse
+
+@typing.final
+class PublishDataTrackCallback(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ TRACK_FIELD_NUMBER: builtins.int
+ ERROR_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ @property
+ def track(self) -> global___OwnedLocalDataTrack: ...
+ @property
+ def error(self) -> global___PublishDataTrackError: ...
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ track: global___OwnedLocalDataTrack | None = ...,
+ error: global___PublishDataTrackError | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error", "result", b"result", "track", b"track"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error", "result", b"result", "track", b"track"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["result", b"result"]) -> typing.Literal["track", "error"] | None: ...
+
+global___PublishDataTrackCallback = PublishDataTrackCallback
+
+@typing.final
+class OwnedLocalDataTrack(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ HANDLE_FIELD_NUMBER: builtins.int
+ INFO_FIELD_NUMBER: builtins.int
+ @property
+ def handle(self) -> handle_pb2.FfiOwnedHandle: ...
+ @property
+ def info(self) -> global___DataTrackInfo: ...
+ def __init__(
+ self,
+ *,
+ handle: handle_pb2.FfiOwnedHandle | None = ...,
+ info: global___DataTrackInfo | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> None: ...
+
+global___OwnedLocalDataTrack = OwnedLocalDataTrack
+
+@typing.final
+class LocalDataTrackTryPushRequest(google.protobuf.message.Message):
+ """Try pushing a frame to subscribers of the track."""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ TRACK_HANDLE_FIELD_NUMBER: builtins.int
+ FRAME_FIELD_NUMBER: builtins.int
+ track_handle: builtins.int
+ @property
+ def frame(self) -> global___DataTrackFrame: ...
+ def __init__(
+ self,
+ *,
+ track_handle: builtins.int | None = ...,
+ frame: global___DataTrackFrame | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["frame", b"frame", "track_handle", b"track_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["frame", b"frame", "track_handle", b"track_handle"]) -> None: ...
+
+global___LocalDataTrackTryPushRequest = LocalDataTrackTryPushRequest
+
+@typing.final
+class LocalDataTrackTryPushResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ERROR_FIELD_NUMBER: builtins.int
+ @property
+ def error(self) -> global___LocalDataTrackTryPushError: ...
+ def __init__(
+ self,
+ *,
+ error: global___LocalDataTrackTryPushError | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["error", b"error"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["error", b"error"]) -> None: ...
+
+global___LocalDataTrackTryPushResponse = LocalDataTrackTryPushResponse
+
+@typing.final
+class LocalDataTrackIsPublishedRequest(google.protobuf.message.Message):
+ """Checks if the track is still published."""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ TRACK_HANDLE_FIELD_NUMBER: builtins.int
+ track_handle: builtins.int
+ def __init__(
+ self,
+ *,
+ track_handle: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["track_handle", b"track_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["track_handle", b"track_handle"]) -> None: ...
+
+global___LocalDataTrackIsPublishedRequest = LocalDataTrackIsPublishedRequest
+
+@typing.final
+class LocalDataTrackIsPublishedResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ IS_PUBLISHED_FIELD_NUMBER: builtins.int
+ is_published: builtins.bool
+ def __init__(
+ self,
+ *,
+ is_published: builtins.bool | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["is_published", b"is_published"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["is_published", b"is_published"]) -> None: ...
+
+global___LocalDataTrackIsPublishedResponse = LocalDataTrackIsPublishedResponse
+
+@typing.final
+class LocalDataTrackUnpublishRequest(google.protobuf.message.Message):
+ """Unpublishes the track."""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ TRACK_HANDLE_FIELD_NUMBER: builtins.int
+ track_handle: builtins.int
+ def __init__(
+ self,
+ *,
+ track_handle: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["track_handle", b"track_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["track_handle", b"track_handle"]) -> None: ...
+
+global___LocalDataTrackUnpublishRequest = LocalDataTrackUnpublishRequest
+
+@typing.final
+class LocalDataTrackUnpublishResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ def __init__(
+ self,
+ ) -> None: ...
+
+global___LocalDataTrackUnpublishResponse = LocalDataTrackUnpublishResponse
+
+@typing.final
+class OwnedRemoteDataTrack(google.protobuf.message.Message):
+ """MARK: - Remote"""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ HANDLE_FIELD_NUMBER: builtins.int
+ INFO_FIELD_NUMBER: builtins.int
+ PUBLISHER_IDENTITY_FIELD_NUMBER: builtins.int
+ publisher_identity: builtins.str
+ """Identity of the remote participant who published the track."""
+ @property
+ def handle(self) -> handle_pb2.FfiOwnedHandle: ...
+ @property
+ def info(self) -> global___DataTrackInfo: ...
+ def __init__(
+ self,
+ *,
+ handle: handle_pb2.FfiOwnedHandle | None = ...,
+ info: global___DataTrackInfo | None = ...,
+ publisher_identity: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["handle", b"handle", "info", b"info", "publisher_identity", b"publisher_identity"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["handle", b"handle", "info", b"info", "publisher_identity", b"publisher_identity"]) -> None: ...
+
+global___OwnedRemoteDataTrack = OwnedRemoteDataTrack
+
+@typing.final
+class OwnedDataTrackStream(google.protobuf.message.Message):
+ """Handle to an active data track subscription.
+
+ Dropping the handle will unsubscribe from the track.
+ """
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ HANDLE_FIELD_NUMBER: builtins.int
+ @property
+ def handle(self) -> handle_pb2.FfiOwnedHandle: ...
+ def __init__(
+ self,
+ *,
+ handle: handle_pb2.FfiOwnedHandle | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["handle", b"handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["handle", b"handle"]) -> None: ...
+
+global___OwnedDataTrackStream = OwnedDataTrackStream
+
+@typing.final
+class DataTrackSubscribeOptions(google.protobuf.message.Message):
+ """Reserved for future subscription options."""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ BUFFER_SIZE_FIELD_NUMBER: builtins.int
+ buffer_size: builtins.int
+ """Maximum number of frames to buffer internally."""
+ def __init__(
+ self,
+ *,
+ buffer_size: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["buffer_size", b"buffer_size"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["buffer_size", b"buffer_size"]) -> None: ...
+
+global___DataTrackSubscribeOptions = DataTrackSubscribeOptions
+
+@typing.final
+class RemoteDataTrackIsPublishedRequest(google.protobuf.message.Message):
+ """Checks if the track is still published."""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ TRACK_HANDLE_FIELD_NUMBER: builtins.int
+ track_handle: builtins.int
+ def __init__(
+ self,
+ *,
+ track_handle: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["track_handle", b"track_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["track_handle", b"track_handle"]) -> None: ...
+
+global___RemoteDataTrackIsPublishedRequest = RemoteDataTrackIsPublishedRequest
+
+@typing.final
+class RemoteDataTrackIsPublishedResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ IS_PUBLISHED_FIELD_NUMBER: builtins.int
+ is_published: builtins.bool
+ def __init__(
+ self,
+ *,
+ is_published: builtins.bool | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["is_published", b"is_published"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["is_published", b"is_published"]) -> None: ...
+
+global___RemoteDataTrackIsPublishedResponse = RemoteDataTrackIsPublishedResponse
+
+@typing.final
+class SubscribeDataTrackRequest(google.protobuf.message.Message):
+ """Subscribe to a data track."""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ TRACK_HANDLE_FIELD_NUMBER: builtins.int
+ OPTIONS_FIELD_NUMBER: builtins.int
+ track_handle: builtins.int
+ @property
+ def options(self) -> global___DataTrackSubscribeOptions: ...
+ def __init__(
+ self,
+ *,
+ track_handle: builtins.int | None = ...,
+ options: global___DataTrackSubscribeOptions | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["options", b"options", "track_handle", b"track_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["options", b"options", "track_handle", b"track_handle"]) -> None: ...
+
+global___SubscribeDataTrackRequest = SubscribeDataTrackRequest
+
+@typing.final
+class SubscribeDataTrackResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ STREAM_FIELD_NUMBER: builtins.int
+ @property
+ def stream(self) -> global___OwnedDataTrackStream: ...
+ def __init__(
+ self,
+ *,
+ stream: global___OwnedDataTrackStream | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["stream", b"stream"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["stream", b"stream"]) -> None: ...
+
+global___SubscribeDataTrackResponse = SubscribeDataTrackResponse
+
+@typing.final
+class DataTrackStreamReadRequest(google.protobuf.message.Message):
+ """Signal readiness to handle the next frame.
+
+ This allows the client to put backpressure on the internal receive buffer.
+ Sending this request will cause the next frame to be sent via `DataTrackStreamFrameReceived`
+ once one is available.
+ """
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ STREAM_HANDLE_FIELD_NUMBER: builtins.int
+ stream_handle: builtins.int
+ def __init__(
+ self,
+ *,
+ stream_handle: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["stream_handle", b"stream_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["stream_handle", b"stream_handle"]) -> None: ...
+
+global___DataTrackStreamReadRequest = DataTrackStreamReadRequest
+
+@typing.final
+class DataTrackStreamReadResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ def __init__(
+ self,
+ ) -> None: ...
+
+global___DataTrackStreamReadResponse = DataTrackStreamReadResponse
+
+@typing.final
+class DataTrackStreamEvent(google.protobuf.message.Message):
+ """Event emitted on an active stream."""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ STREAM_HANDLE_FIELD_NUMBER: builtins.int
+ FRAME_RECEIVED_FIELD_NUMBER: builtins.int
+ EOS_FIELD_NUMBER: builtins.int
+ stream_handle: builtins.int
+ @property
+ def frame_received(self) -> global___DataTrackStreamFrameReceived: ...
+ @property
+ def eos(self) -> global___DataTrackStreamEOS: ...
+ def __init__(
+ self,
+ *,
+ stream_handle: builtins.int | None = ...,
+ frame_received: global___DataTrackStreamFrameReceived | None = ...,
+ eos: global___DataTrackStreamEOS | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["detail", b"detail", "eos", b"eos", "frame_received", b"frame_received", "stream_handle", b"stream_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["detail", b"detail", "eos", b"eos", "frame_received", b"frame_received", "stream_handle", b"stream_handle"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["detail", b"detail"]) -> typing.Literal["frame_received", "eos"] | None: ...
+
+global___DataTrackStreamEvent = DataTrackStreamEvent
+
+@typing.final
+class DataTrackStreamFrameReceived(google.protobuf.message.Message):
+ """A frame was received."""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ FRAME_FIELD_NUMBER: builtins.int
+ @property
+ def frame(self) -> global___DataTrackFrame: ...
+ def __init__(
+ self,
+ *,
+ frame: global___DataTrackFrame | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["frame", b"frame"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["frame", b"frame"]) -> None: ...
+
+global___DataTrackStreamFrameReceived = DataTrackStreamFrameReceived
+
+@typing.final
+class DataTrackStreamEOS(google.protobuf.message.Message):
+ """Stream has ended."""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ERROR_FIELD_NUMBER: builtins.int
+ error: builtins.str
+ """If the track could not be subscribed to, a message describing the error.
+ Absent if the stream ended normally.
+ """
+ def __init__(
+ self,
+ *,
+ error: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["error", b"error"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["error", b"error"]) -> None: ...
+
+global___DataTrackStreamEOS = DataTrackStreamEOS
diff --git a/livekit-rtc/livekit/rtc/_proto/e2ee_pb2.py b/livekit-rtc/livekit/rtc/_proto/e2ee_pb2.py
index 9794751d..0a0b9a52 100644
--- a/livekit-rtc/livekit/rtc/_proto/e2ee_pb2.py
+++ b/livekit-rtc/livekit/rtc/_proto/e2ee_pb2.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: e2ee.proto
-# Protobuf Python Version: 4.25.3
+# Protobuf Python Version: 4.25.1
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
@@ -14,7 +14,7 @@
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\ne2ee.proto\x12\rlivekit.proto\"c\n\x0c\x46rameCryptor\x12\x1c\n\x14participant_identity\x18\x01 \x01(\t\x12\x11\n\ttrack_sid\x18\x02 \x01(\t\x12\x11\n\tkey_index\x18\x03 \x01(\x05\x12\x0f\n\x07\x65nabled\x18\x04 \x01(\x08\"\x8a\x01\n\x12KeyProviderOptions\x12\x17\n\nshared_key\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x12\x1b\n\x13ratchet_window_size\x18\x02 \x01(\x05\x12\x14\n\x0cratchet_salt\x18\x03 \x01(\x0c\x12\x19\n\x11\x66\x61ilure_tolerance\x18\x04 \x01(\x05\x42\r\n\x0b_shared_key\"\x86\x01\n\x0b\x45\x32\x65\x65Options\x12\x36\n\x0f\x65ncryption_type\x18\x01 \x01(\x0e\x32\x1d.livekit.proto.EncryptionType\x12?\n\x14key_provider_options\x18\x02 \x01(\x0b\x32!.livekit.proto.KeyProviderOptions\"/\n\x1c\x45\x32\x65\x65ManagerSetEnabledRequest\x12\x0f\n\x07\x65nabled\x18\x01 \x01(\x08\"\x1f\n\x1d\x45\x32\x65\x65ManagerSetEnabledResponse\"$\n\"E2eeManagerGetFrameCryptorsRequest\"Z\n#E2eeManagerGetFrameCryptorsResponse\x12\x33\n\x0e\x66rame_cryptors\x18\x01 \x03(\x0b\x32\x1b.livekit.proto.FrameCryptor\"a\n\x1d\x46rameCryptorSetEnabledRequest\x12\x1c\n\x14participant_identity\x18\x01 \x01(\t\x12\x11\n\ttrack_sid\x18\x02 \x01(\t\x12\x0f\n\x07\x65nabled\x18\x03 \x01(\x08\" \n\x1e\x46rameCryptorSetEnabledResponse\"d\n\x1e\x46rameCryptorSetKeyIndexRequest\x12\x1c\n\x14participant_identity\x18\x01 \x01(\t\x12\x11\n\ttrack_sid\x18\x02 \x01(\t\x12\x11\n\tkey_index\x18\x03 \x01(\x05\"!\n\x1f\x46rameCryptorSetKeyIndexResponse\"<\n\x13SetSharedKeyRequest\x12\x12\n\nshared_key\x18\x01 \x01(\x0c\x12\x11\n\tkey_index\x18\x02 \x01(\x05\"\x16\n\x14SetSharedKeyResponse\",\n\x17RatchetSharedKeyRequest\x12\x11\n\tkey_index\x18\x01 \x01(\x05\"<\n\x18RatchetSharedKeyResponse\x12\x14\n\x07new_key\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x42\n\n\x08_new_key\"(\n\x13GetSharedKeyRequest\x12\x11\n\tkey_index\x18\x01 \x01(\x05\"0\n\x14GetSharedKeyResponse\x12\x10\n\x03key\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x42\x06\n\x04_key\"M\n\rSetKeyRequest\x12\x1c\n\x14participant_identity\x18\x01 \x01(\t\x12\x0b\n\x03key\x18\x02 \x01(\x0c\x12\x11\n\tkey_index\x18\x03 \x01(\x05\"\x10\n\x0eSetKeyResponse\"D\n\x11RatchetKeyRequest\x12\x1c\n\x14participant_identity\x18\x01 \x01(\t\x12\x11\n\tkey_index\x18\x02 \x01(\x05\"6\n\x12RatchetKeyResponse\x12\x14\n\x07new_key\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x42\n\n\x08_new_key\"@\n\rGetKeyRequest\x12\x1c\n\x14participant_identity\x18\x01 \x01(\t\x12\x11\n\tkey_index\x18\x02 \x01(\x05\"*\n\x0eGetKeyResponse\x12\x10\n\x03key\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x42\x06\n\x04_key\"\xcc\x05\n\x0b\x45\x32\x65\x65Request\x12\x13\n\x0broom_handle\x18\x01 \x01(\x04\x12J\n\x13manager_set_enabled\x18\x02 \x01(\x0b\x32+.livekit.proto.E2eeManagerSetEnabledRequestH\x00\x12W\n\x1amanager_get_frame_cryptors\x18\x03 \x01(\x0b\x32\x31.livekit.proto.E2eeManagerGetFrameCryptorsRequestH\x00\x12K\n\x13\x63ryptor_set_enabled\x18\x04 \x01(\x0b\x32,.livekit.proto.FrameCryptorSetEnabledRequestH\x00\x12N\n\x15\x63ryptor_set_key_index\x18\x05 \x01(\x0b\x32-.livekit.proto.FrameCryptorSetKeyIndexRequestH\x00\x12<\n\x0eset_shared_key\x18\x06 \x01(\x0b\x32\".livekit.proto.SetSharedKeyRequestH\x00\x12\x44\n\x12ratchet_shared_key\x18\x07 \x01(\x0b\x32&.livekit.proto.RatchetSharedKeyRequestH\x00\x12<\n\x0eget_shared_key\x18\x08 \x01(\x0b\x32\".livekit.proto.GetSharedKeyRequestH\x00\x12/\n\x07set_key\x18\t \x01(\x0b\x32\x1c.livekit.proto.SetKeyRequestH\x00\x12\x37\n\x0bratchet_key\x18\n \x01(\x0b\x32 .livekit.proto.RatchetKeyRequestH\x00\x12/\n\x07get_key\x18\x0b \x01(\x0b\x32\x1c.livekit.proto.GetKeyRequestH\x00\x42\t\n\x07message\"\xc2\x05\n\x0c\x45\x32\x65\x65Response\x12K\n\x13manager_set_enabled\x18\x01 \x01(\x0b\x32,.livekit.proto.E2eeManagerSetEnabledResponseH\x00\x12X\n\x1amanager_get_frame_cryptors\x18\x02 \x01(\x0b\x32\x32.livekit.proto.E2eeManagerGetFrameCryptorsResponseH\x00\x12L\n\x13\x63ryptor_set_enabled\x18\x03 \x01(\x0b\x32-.livekit.proto.FrameCryptorSetEnabledResponseH\x00\x12O\n\x15\x63ryptor_set_key_index\x18\x04 \x01(\x0b\x32..livekit.proto.FrameCryptorSetKeyIndexResponseH\x00\x12=\n\x0eset_shared_key\x18\x05 \x01(\x0b\x32#.livekit.proto.SetSharedKeyResponseH\x00\x12\x45\n\x12ratchet_shared_key\x18\x06 \x01(\x0b\x32\'.livekit.proto.RatchetSharedKeyResponseH\x00\x12=\n\x0eget_shared_key\x18\x07 \x01(\x0b\x32#.livekit.proto.GetSharedKeyResponseH\x00\x12\x30\n\x07set_key\x18\x08 \x01(\x0b\x32\x1d.livekit.proto.SetKeyResponseH\x00\x12\x38\n\x0bratchet_key\x18\t \x01(\x0b\x32!.livekit.proto.RatchetKeyResponseH\x00\x12\x30\n\x07get_key\x18\n \x01(\x0b\x32\x1d.livekit.proto.GetKeyResponseH\x00\x42\t\n\x07message*/\n\x0e\x45ncryptionType\x12\x08\n\x04NONE\x10\x00\x12\x07\n\x03GCM\x10\x01\x12\n\n\x06\x43USTOM\x10\x02*\x88\x01\n\x0f\x45ncryptionState\x12\x07\n\x03NEW\x10\x00\x12\x06\n\x02OK\x10\x01\x12\x15\n\x11\x45NCRYPTION_FAILED\x10\x02\x12\x15\n\x11\x44\x45\x43RYPTION_FAILED\x10\x03\x12\x0f\n\x0bMISSING_KEY\x10\x04\x12\x11\n\rKEY_RATCHETED\x10\x05\x12\x12\n\x0eINTERNAL_ERROR\x10\x06\x42\x10\xaa\x02\rLiveKit.Protob\x06proto3')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\ne2ee.proto\x12\rlivekit.proto\"c\n\x0c\x46rameCryptor\x12\x1c\n\x14participant_identity\x18\x01 \x02(\t\x12\x11\n\ttrack_sid\x18\x02 \x02(\t\x12\x11\n\tkey_index\x18\x03 \x02(\x05\x12\x0f\n\x07\x65nabled\x18\x04 \x02(\x08\"\xd4\x01\n\x12KeyProviderOptions\x12\x12\n\nshared_key\x18\x01 \x01(\x0c\x12\x1b\n\x13ratchet_window_size\x18\x02 \x02(\x05\x12\x14\n\x0cratchet_salt\x18\x03 \x02(\x0c\x12\x19\n\x11\x66\x61ilure_tolerance\x18\x04 \x02(\x05\x12\x15\n\rkey_ring_size\x18\x05 \x02(\x05\x12\x45\n\x17key_derivation_function\x18\x06 \x02(\x0e\x32$.livekit.proto.KeyDerivationFunction\"\x86\x01\n\x0b\x45\x32\x65\x65Options\x12\x36\n\x0f\x65ncryption_type\x18\x01 \x02(\x0e\x32\x1d.livekit.proto.EncryptionType\x12?\n\x14key_provider_options\x18\x02 \x02(\x0b\x32!.livekit.proto.KeyProviderOptions\"/\n\x1c\x45\x32\x65\x65ManagerSetEnabledRequest\x12\x0f\n\x07\x65nabled\x18\x01 \x02(\x08\"\x1f\n\x1d\x45\x32\x65\x65ManagerSetEnabledResponse\"$\n\"E2eeManagerGetFrameCryptorsRequest\"Z\n#E2eeManagerGetFrameCryptorsResponse\x12\x33\n\x0e\x66rame_cryptors\x18\x01 \x03(\x0b\x32\x1b.livekit.proto.FrameCryptor\"a\n\x1d\x46rameCryptorSetEnabledRequest\x12\x1c\n\x14participant_identity\x18\x01 \x02(\t\x12\x11\n\ttrack_sid\x18\x02 \x02(\t\x12\x0f\n\x07\x65nabled\x18\x03 \x02(\x08\" \n\x1e\x46rameCryptorSetEnabledResponse\"d\n\x1e\x46rameCryptorSetKeyIndexRequest\x12\x1c\n\x14participant_identity\x18\x01 \x02(\t\x12\x11\n\ttrack_sid\x18\x02 \x02(\t\x12\x11\n\tkey_index\x18\x03 \x02(\x05\"!\n\x1f\x46rameCryptorSetKeyIndexResponse\"<\n\x13SetSharedKeyRequest\x12\x12\n\nshared_key\x18\x01 \x02(\x0c\x12\x11\n\tkey_index\x18\x02 \x02(\x05\"\x16\n\x14SetSharedKeyResponse\",\n\x17RatchetSharedKeyRequest\x12\x11\n\tkey_index\x18\x01 \x02(\x05\"+\n\x18RatchetSharedKeyResponse\x12\x0f\n\x07new_key\x18\x01 \x01(\x0c\"(\n\x13GetSharedKeyRequest\x12\x11\n\tkey_index\x18\x01 \x02(\x05\"#\n\x14GetSharedKeyResponse\x12\x0b\n\x03key\x18\x01 \x01(\x0c\"M\n\rSetKeyRequest\x12\x1c\n\x14participant_identity\x18\x01 \x02(\t\x12\x0b\n\x03key\x18\x02 \x02(\x0c\x12\x11\n\tkey_index\x18\x03 \x02(\x05\"\x10\n\x0eSetKeyResponse\"D\n\x11RatchetKeyRequest\x12\x1c\n\x14participant_identity\x18\x01 \x02(\t\x12\x11\n\tkey_index\x18\x02 \x02(\x05\"%\n\x12RatchetKeyResponse\x12\x0f\n\x07new_key\x18\x01 \x01(\x0c\"@\n\rGetKeyRequest\x12\x1c\n\x14participant_identity\x18\x01 \x02(\t\x12\x11\n\tkey_index\x18\x02 \x02(\x05\"\x1d\n\x0eGetKeyResponse\x12\x0b\n\x03key\x18\x01 \x01(\x0c\"\xcc\x05\n\x0b\x45\x32\x65\x65Request\x12\x13\n\x0broom_handle\x18\x01 \x02(\x04\x12J\n\x13manager_set_enabled\x18\x02 \x01(\x0b\x32+.livekit.proto.E2eeManagerSetEnabledRequestH\x00\x12W\n\x1amanager_get_frame_cryptors\x18\x03 \x01(\x0b\x32\x31.livekit.proto.E2eeManagerGetFrameCryptorsRequestH\x00\x12K\n\x13\x63ryptor_set_enabled\x18\x04 \x01(\x0b\x32,.livekit.proto.FrameCryptorSetEnabledRequestH\x00\x12N\n\x15\x63ryptor_set_key_index\x18\x05 \x01(\x0b\x32-.livekit.proto.FrameCryptorSetKeyIndexRequestH\x00\x12<\n\x0eset_shared_key\x18\x06 \x01(\x0b\x32\".livekit.proto.SetSharedKeyRequestH\x00\x12\x44\n\x12ratchet_shared_key\x18\x07 \x01(\x0b\x32&.livekit.proto.RatchetSharedKeyRequestH\x00\x12<\n\x0eget_shared_key\x18\x08 \x01(\x0b\x32\".livekit.proto.GetSharedKeyRequestH\x00\x12/\n\x07set_key\x18\t \x01(\x0b\x32\x1c.livekit.proto.SetKeyRequestH\x00\x12\x37\n\x0bratchet_key\x18\n \x01(\x0b\x32 .livekit.proto.RatchetKeyRequestH\x00\x12/\n\x07get_key\x18\x0b \x01(\x0b\x32\x1c.livekit.proto.GetKeyRequestH\x00\x42\t\n\x07message\"\xc2\x05\n\x0c\x45\x32\x65\x65Response\x12K\n\x13manager_set_enabled\x18\x01 \x01(\x0b\x32,.livekit.proto.E2eeManagerSetEnabledResponseH\x00\x12X\n\x1amanager_get_frame_cryptors\x18\x02 \x01(\x0b\x32\x32.livekit.proto.E2eeManagerGetFrameCryptorsResponseH\x00\x12L\n\x13\x63ryptor_set_enabled\x18\x03 \x01(\x0b\x32-.livekit.proto.FrameCryptorSetEnabledResponseH\x00\x12O\n\x15\x63ryptor_set_key_index\x18\x04 \x01(\x0b\x32..livekit.proto.FrameCryptorSetKeyIndexResponseH\x00\x12=\n\x0eset_shared_key\x18\x05 \x01(\x0b\x32#.livekit.proto.SetSharedKeyResponseH\x00\x12\x45\n\x12ratchet_shared_key\x18\x06 \x01(\x0b\x32\'.livekit.proto.RatchetSharedKeyResponseH\x00\x12=\n\x0eget_shared_key\x18\x07 \x01(\x0b\x32#.livekit.proto.GetSharedKeyResponseH\x00\x12\x30\n\x07set_key\x18\x08 \x01(\x0b\x32\x1d.livekit.proto.SetKeyResponseH\x00\x12\x38\n\x0bratchet_key\x18\t \x01(\x0b\x32!.livekit.proto.RatchetKeyResponseH\x00\x12\x30\n\x07get_key\x18\n \x01(\x0b\x32\x1d.livekit.proto.GetKeyResponseH\x00\x42\t\n\x07message*/\n\x0e\x45ncryptionType\x12\x08\n\x04NONE\x10\x00\x12\x07\n\x03GCM\x10\x01\x12\n\n\x06\x43USTOM\x10\x02*-\n\x15KeyDerivationFunction\x12\n\n\x06PBKDF2\x10\x00\x12\x08\n\x04HKDF\x10\x01*\x88\x01\n\x0f\x45ncryptionState\x12\x07\n\x03NEW\x10\x00\x12\x06\n\x02OK\x10\x01\x12\x15\n\x11\x45NCRYPTION_FAILED\x10\x02\x12\x15\n\x11\x44\x45\x43RYPTION_FAILED\x10\x03\x12\x0f\n\x0bMISSING_KEY\x10\x04\x12\x11\n\rKEY_RATCHETED\x10\x05\x12\x12\n\x0eINTERNAL_ERROR\x10\x06\x42\x10\xaa\x02\rLiveKit.Proto')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -22,58 +22,60 @@
if _descriptor._USE_C_DESCRIPTORS == False:
_globals['DESCRIPTOR']._options = None
_globals['DESCRIPTOR']._serialized_options = b'\252\002\rLiveKit.Proto'
- _globals['_ENCRYPTIONTYPE']._serialized_start=2937
- _globals['_ENCRYPTIONTYPE']._serialized_end=2984
- _globals['_ENCRYPTIONSTATE']._serialized_start=2987
- _globals['_ENCRYPTIONSTATE']._serialized_end=3123
+ _globals['_ENCRYPTIONTYPE']._serialized_start=2951
+ _globals['_ENCRYPTIONTYPE']._serialized_end=2998
+ _globals['_KEYDERIVATIONFUNCTION']._serialized_start=3000
+ _globals['_KEYDERIVATIONFUNCTION']._serialized_end=3045
+ _globals['_ENCRYPTIONSTATE']._serialized_start=3048
+ _globals['_ENCRYPTIONSTATE']._serialized_end=3184
_globals['_FRAMECRYPTOR']._serialized_start=29
_globals['_FRAMECRYPTOR']._serialized_end=128
_globals['_KEYPROVIDEROPTIONS']._serialized_start=131
- _globals['_KEYPROVIDEROPTIONS']._serialized_end=269
- _globals['_E2EEOPTIONS']._serialized_start=272
- _globals['_E2EEOPTIONS']._serialized_end=406
- _globals['_E2EEMANAGERSETENABLEDREQUEST']._serialized_start=408
- _globals['_E2EEMANAGERSETENABLEDREQUEST']._serialized_end=455
- _globals['_E2EEMANAGERSETENABLEDRESPONSE']._serialized_start=457
- _globals['_E2EEMANAGERSETENABLEDRESPONSE']._serialized_end=488
- _globals['_E2EEMANAGERGETFRAMECRYPTORSREQUEST']._serialized_start=490
- _globals['_E2EEMANAGERGETFRAMECRYPTORSREQUEST']._serialized_end=526
- _globals['_E2EEMANAGERGETFRAMECRYPTORSRESPONSE']._serialized_start=528
- _globals['_E2EEMANAGERGETFRAMECRYPTORSRESPONSE']._serialized_end=618
- _globals['_FRAMECRYPTORSETENABLEDREQUEST']._serialized_start=620
- _globals['_FRAMECRYPTORSETENABLEDREQUEST']._serialized_end=717
- _globals['_FRAMECRYPTORSETENABLEDRESPONSE']._serialized_start=719
- _globals['_FRAMECRYPTORSETENABLEDRESPONSE']._serialized_end=751
- _globals['_FRAMECRYPTORSETKEYINDEXREQUEST']._serialized_start=753
- _globals['_FRAMECRYPTORSETKEYINDEXREQUEST']._serialized_end=853
- _globals['_FRAMECRYPTORSETKEYINDEXRESPONSE']._serialized_start=855
- _globals['_FRAMECRYPTORSETKEYINDEXRESPONSE']._serialized_end=888
- _globals['_SETSHAREDKEYREQUEST']._serialized_start=890
- _globals['_SETSHAREDKEYREQUEST']._serialized_end=950
- _globals['_SETSHAREDKEYRESPONSE']._serialized_start=952
- _globals['_SETSHAREDKEYRESPONSE']._serialized_end=974
- _globals['_RATCHETSHAREDKEYREQUEST']._serialized_start=976
- _globals['_RATCHETSHAREDKEYREQUEST']._serialized_end=1020
- _globals['_RATCHETSHAREDKEYRESPONSE']._serialized_start=1022
- _globals['_RATCHETSHAREDKEYRESPONSE']._serialized_end=1082
- _globals['_GETSHAREDKEYREQUEST']._serialized_start=1084
- _globals['_GETSHAREDKEYREQUEST']._serialized_end=1124
- _globals['_GETSHAREDKEYRESPONSE']._serialized_start=1126
- _globals['_GETSHAREDKEYRESPONSE']._serialized_end=1174
- _globals['_SETKEYREQUEST']._serialized_start=1176
- _globals['_SETKEYREQUEST']._serialized_end=1253
- _globals['_SETKEYRESPONSE']._serialized_start=1255
- _globals['_SETKEYRESPONSE']._serialized_end=1271
- _globals['_RATCHETKEYREQUEST']._serialized_start=1273
- _globals['_RATCHETKEYREQUEST']._serialized_end=1341
- _globals['_RATCHETKEYRESPONSE']._serialized_start=1343
- _globals['_RATCHETKEYRESPONSE']._serialized_end=1397
- _globals['_GETKEYREQUEST']._serialized_start=1399
- _globals['_GETKEYREQUEST']._serialized_end=1463
- _globals['_GETKEYRESPONSE']._serialized_start=1465
- _globals['_GETKEYRESPONSE']._serialized_end=1507
- _globals['_E2EEREQUEST']._serialized_start=1510
- _globals['_E2EEREQUEST']._serialized_end=2226
- _globals['_E2EERESPONSE']._serialized_start=2229
- _globals['_E2EERESPONSE']._serialized_end=2935
+ _globals['_KEYPROVIDEROPTIONS']._serialized_end=343
+ _globals['_E2EEOPTIONS']._serialized_start=346
+ _globals['_E2EEOPTIONS']._serialized_end=480
+ _globals['_E2EEMANAGERSETENABLEDREQUEST']._serialized_start=482
+ _globals['_E2EEMANAGERSETENABLEDREQUEST']._serialized_end=529
+ _globals['_E2EEMANAGERSETENABLEDRESPONSE']._serialized_start=531
+ _globals['_E2EEMANAGERSETENABLEDRESPONSE']._serialized_end=562
+ _globals['_E2EEMANAGERGETFRAMECRYPTORSREQUEST']._serialized_start=564
+ _globals['_E2EEMANAGERGETFRAMECRYPTORSREQUEST']._serialized_end=600
+ _globals['_E2EEMANAGERGETFRAMECRYPTORSRESPONSE']._serialized_start=602
+ _globals['_E2EEMANAGERGETFRAMECRYPTORSRESPONSE']._serialized_end=692
+ _globals['_FRAMECRYPTORSETENABLEDREQUEST']._serialized_start=694
+ _globals['_FRAMECRYPTORSETENABLEDREQUEST']._serialized_end=791
+ _globals['_FRAMECRYPTORSETENABLEDRESPONSE']._serialized_start=793
+ _globals['_FRAMECRYPTORSETENABLEDRESPONSE']._serialized_end=825
+ _globals['_FRAMECRYPTORSETKEYINDEXREQUEST']._serialized_start=827
+ _globals['_FRAMECRYPTORSETKEYINDEXREQUEST']._serialized_end=927
+ _globals['_FRAMECRYPTORSETKEYINDEXRESPONSE']._serialized_start=929
+ _globals['_FRAMECRYPTORSETKEYINDEXRESPONSE']._serialized_end=962
+ _globals['_SETSHAREDKEYREQUEST']._serialized_start=964
+ _globals['_SETSHAREDKEYREQUEST']._serialized_end=1024
+ _globals['_SETSHAREDKEYRESPONSE']._serialized_start=1026
+ _globals['_SETSHAREDKEYRESPONSE']._serialized_end=1048
+ _globals['_RATCHETSHAREDKEYREQUEST']._serialized_start=1050
+ _globals['_RATCHETSHAREDKEYREQUEST']._serialized_end=1094
+ _globals['_RATCHETSHAREDKEYRESPONSE']._serialized_start=1096
+ _globals['_RATCHETSHAREDKEYRESPONSE']._serialized_end=1139
+ _globals['_GETSHAREDKEYREQUEST']._serialized_start=1141
+ _globals['_GETSHAREDKEYREQUEST']._serialized_end=1181
+ _globals['_GETSHAREDKEYRESPONSE']._serialized_start=1183
+ _globals['_GETSHAREDKEYRESPONSE']._serialized_end=1218
+ _globals['_SETKEYREQUEST']._serialized_start=1220
+ _globals['_SETKEYREQUEST']._serialized_end=1297
+ _globals['_SETKEYRESPONSE']._serialized_start=1299
+ _globals['_SETKEYRESPONSE']._serialized_end=1315
+ _globals['_RATCHETKEYREQUEST']._serialized_start=1317
+ _globals['_RATCHETKEYREQUEST']._serialized_end=1385
+ _globals['_RATCHETKEYRESPONSE']._serialized_start=1387
+ _globals['_RATCHETKEYRESPONSE']._serialized_end=1424
+ _globals['_GETKEYREQUEST']._serialized_start=1426
+ _globals['_GETKEYREQUEST']._serialized_end=1490
+ _globals['_GETKEYRESPONSE']._serialized_start=1492
+ _globals['_GETKEYRESPONSE']._serialized_end=1521
+ _globals['_E2EEREQUEST']._serialized_start=1524
+ _globals['_E2EEREQUEST']._serialized_end=2240
+ _globals['_E2EERESPONSE']._serialized_start=2243
+ _globals['_E2EERESPONSE']._serialized_end=2949
# @@protoc_insertion_point(module_scope)
diff --git a/livekit-rtc/livekit/rtc/_proto/e2ee_pb2.pyi b/livekit-rtc/livekit/rtc/_proto/e2ee_pb2.pyi
index a34cf52d..53437b21 100644
--- a/livekit-rtc/livekit/rtc/_proto/e2ee_pb2.pyi
+++ b/livekit-rtc/livekit/rtc/_proto/e2ee_pb2.pyi
@@ -1,7 +1,7 @@
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
-Copyright 2023 LiveKit, Inc.
+Copyright 2025 LiveKit, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
+
import builtins
import collections.abc
import google.protobuf.descriptor
@@ -49,6 +50,21 @@ GCM: EncryptionType.ValueType # 1
CUSTOM: EncryptionType.ValueType # 2
global___EncryptionType = EncryptionType
+class _KeyDerivationFunction:
+ ValueType = typing.NewType("ValueType", builtins.int)
+ V: typing_extensions.TypeAlias = ValueType
+
+class _KeyDerivationFunctionEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_KeyDerivationFunction.ValueType], builtins.type):
+ DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
+ PBKDF2: _KeyDerivationFunction.ValueType # 0
+ HKDF: _KeyDerivationFunction.ValueType # 1
+
+class KeyDerivationFunction(_KeyDerivationFunction, metaclass=_KeyDerivationFunctionEnumTypeWrapper): ...
+
+PBKDF2: KeyDerivationFunction.ValueType # 0
+HKDF: KeyDerivationFunction.ValueType # 1
+global___KeyDerivationFunction = KeyDerivationFunction
+
class _EncryptionState:
ValueType = typing.NewType("ValueType", builtins.int)
V: typing_extensions.TypeAlias = ValueType
@@ -74,7 +90,7 @@ KEY_RATCHETED: EncryptionState.ValueType # 5
INTERNAL_ERROR: EncryptionState.ValueType # 6
global___EncryptionState = EncryptionState
-@typing_extensions.final
+@typing.final
class FrameCryptor(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -89,16 +105,17 @@ class FrameCryptor(google.protobuf.message.Message):
def __init__(
self,
*,
- participant_identity: builtins.str = ...,
- track_sid: builtins.str = ...,
- key_index: builtins.int = ...,
- enabled: builtins.bool = ...,
+ participant_identity: builtins.str | None = ...,
+ track_sid: builtins.str | None = ...,
+ key_index: builtins.int | None = ...,
+ enabled: builtins.bool | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["enabled", b"enabled", "key_index", b"key_index", "participant_identity", b"participant_identity", "track_sid", b"track_sid"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["enabled", b"enabled", "key_index", b"key_index", "participant_identity", b"participant_identity", "track_sid", b"track_sid"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["enabled", b"enabled", "key_index", b"key_index", "participant_identity", b"participant_identity", "track_sid", b"track_sid"]) -> None: ...
global___FrameCryptor = FrameCryptor
-@typing_extensions.final
+@typing.final
class KeyProviderOptions(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -106,27 +123,32 @@ class KeyProviderOptions(google.protobuf.message.Message):
RATCHET_WINDOW_SIZE_FIELD_NUMBER: builtins.int
RATCHET_SALT_FIELD_NUMBER: builtins.int
FAILURE_TOLERANCE_FIELD_NUMBER: builtins.int
+ KEY_RING_SIZE_FIELD_NUMBER: builtins.int
+ KEY_DERIVATION_FUNCTION_FIELD_NUMBER: builtins.int
shared_key: builtins.bytes
"""Only specify if you want to use a shared_key"""
ratchet_window_size: builtins.int
ratchet_salt: builtins.bytes
failure_tolerance: builtins.int
- """-1 = no tolerence"""
+ """-1 = no tolerance"""
+ key_ring_size: builtins.int
+ key_derivation_function: global___KeyDerivationFunction.ValueType
def __init__(
self,
*,
shared_key: builtins.bytes | None = ...,
- ratchet_window_size: builtins.int = ...,
- ratchet_salt: builtins.bytes = ...,
- failure_tolerance: builtins.int = ...,
+ ratchet_window_size: builtins.int | None = ...,
+ ratchet_salt: builtins.bytes | None = ...,
+ failure_tolerance: builtins.int | None = ...,
+ key_ring_size: builtins.int | None = ...,
+ key_derivation_function: global___KeyDerivationFunction.ValueType | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_shared_key", b"_shared_key", "shared_key", b"shared_key"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_shared_key", b"_shared_key", "failure_tolerance", b"failure_tolerance", "ratchet_salt", b"ratchet_salt", "ratchet_window_size", b"ratchet_window_size", "shared_key", b"shared_key"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_shared_key", b"_shared_key"]) -> typing_extensions.Literal["shared_key"] | None: ...
+ def HasField(self, field_name: typing.Literal["failure_tolerance", b"failure_tolerance", "key_derivation_function", b"key_derivation_function", "key_ring_size", b"key_ring_size", "ratchet_salt", b"ratchet_salt", "ratchet_window_size", b"ratchet_window_size", "shared_key", b"shared_key"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["failure_tolerance", b"failure_tolerance", "key_derivation_function", b"key_derivation_function", "key_ring_size", b"key_ring_size", "ratchet_salt", b"ratchet_salt", "ratchet_window_size", b"ratchet_window_size", "shared_key", b"shared_key"]) -> None: ...
global___KeyProviderOptions = KeyProviderOptions
-@typing_extensions.final
+@typing.final
class E2eeOptions(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -138,15 +160,15 @@ class E2eeOptions(google.protobuf.message.Message):
def __init__(
self,
*,
- encryption_type: global___EncryptionType.ValueType = ...,
+ encryption_type: global___EncryptionType.ValueType | None = ...,
key_provider_options: global___KeyProviderOptions | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["key_provider_options", b"key_provider_options"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["encryption_type", b"encryption_type", "key_provider_options", b"key_provider_options"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["encryption_type", b"encryption_type", "key_provider_options", b"key_provider_options"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["encryption_type", b"encryption_type", "key_provider_options", b"key_provider_options"]) -> None: ...
global___E2eeOptions = E2eeOptions
-@typing_extensions.final
+@typing.final
class E2eeManagerSetEnabledRequest(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -155,13 +177,14 @@ class E2eeManagerSetEnabledRequest(google.protobuf.message.Message):
def __init__(
self,
*,
- enabled: builtins.bool = ...,
+ enabled: builtins.bool | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["enabled", b"enabled"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["enabled", b"enabled"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["enabled", b"enabled"]) -> None: ...
global___E2eeManagerSetEnabledRequest = E2eeManagerSetEnabledRequest
-@typing_extensions.final
+@typing.final
class E2eeManagerSetEnabledResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -171,7 +194,7 @@ class E2eeManagerSetEnabledResponse(google.protobuf.message.Message):
global___E2eeManagerSetEnabledResponse = E2eeManagerSetEnabledResponse
-@typing_extensions.final
+@typing.final
class E2eeManagerGetFrameCryptorsRequest(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -181,7 +204,7 @@ class E2eeManagerGetFrameCryptorsRequest(google.protobuf.message.Message):
global___E2eeManagerGetFrameCryptorsRequest = E2eeManagerGetFrameCryptorsRequest
-@typing_extensions.final
+@typing.final
class E2eeManagerGetFrameCryptorsResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -193,11 +216,11 @@ class E2eeManagerGetFrameCryptorsResponse(google.protobuf.message.Message):
*,
frame_cryptors: collections.abc.Iterable[global___FrameCryptor] | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["frame_cryptors", b"frame_cryptors"]) -> None: ...
+ def ClearField(self, field_name: typing.Literal["frame_cryptors", b"frame_cryptors"]) -> None: ...
global___E2eeManagerGetFrameCryptorsResponse = E2eeManagerGetFrameCryptorsResponse
-@typing_extensions.final
+@typing.final
class FrameCryptorSetEnabledRequest(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -210,15 +233,16 @@ class FrameCryptorSetEnabledRequest(google.protobuf.message.Message):
def __init__(
self,
*,
- participant_identity: builtins.str = ...,
- track_sid: builtins.str = ...,
- enabled: builtins.bool = ...,
+ participant_identity: builtins.str | None = ...,
+ track_sid: builtins.str | None = ...,
+ enabled: builtins.bool | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["enabled", b"enabled", "participant_identity", b"participant_identity", "track_sid", b"track_sid"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["enabled", b"enabled", "participant_identity", b"participant_identity", "track_sid", b"track_sid"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["enabled", b"enabled", "participant_identity", b"participant_identity", "track_sid", b"track_sid"]) -> None: ...
global___FrameCryptorSetEnabledRequest = FrameCryptorSetEnabledRequest
-@typing_extensions.final
+@typing.final
class FrameCryptorSetEnabledResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -228,7 +252,7 @@ class FrameCryptorSetEnabledResponse(google.protobuf.message.Message):
global___FrameCryptorSetEnabledResponse = FrameCryptorSetEnabledResponse
-@typing_extensions.final
+@typing.final
class FrameCryptorSetKeyIndexRequest(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -241,15 +265,16 @@ class FrameCryptorSetKeyIndexRequest(google.protobuf.message.Message):
def __init__(
self,
*,
- participant_identity: builtins.str = ...,
- track_sid: builtins.str = ...,
- key_index: builtins.int = ...,
+ participant_identity: builtins.str | None = ...,
+ track_sid: builtins.str | None = ...,
+ key_index: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["key_index", b"key_index", "participant_identity", b"participant_identity", "track_sid", b"track_sid"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["key_index", b"key_index", "participant_identity", b"participant_identity", "track_sid", b"track_sid"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["key_index", b"key_index", "participant_identity", b"participant_identity", "track_sid", b"track_sid"]) -> None: ...
global___FrameCryptorSetKeyIndexRequest = FrameCryptorSetKeyIndexRequest
-@typing_extensions.final
+@typing.final
class FrameCryptorSetKeyIndexResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -259,7 +284,7 @@ class FrameCryptorSetKeyIndexResponse(google.protobuf.message.Message):
global___FrameCryptorSetKeyIndexResponse = FrameCryptorSetKeyIndexResponse
-@typing_extensions.final
+@typing.final
class SetSharedKeyRequest(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -270,14 +295,15 @@ class SetSharedKeyRequest(google.protobuf.message.Message):
def __init__(
self,
*,
- shared_key: builtins.bytes = ...,
- key_index: builtins.int = ...,
+ shared_key: builtins.bytes | None = ...,
+ key_index: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["key_index", b"key_index", "shared_key", b"shared_key"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["key_index", b"key_index", "shared_key", b"shared_key"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["key_index", b"key_index", "shared_key", b"shared_key"]) -> None: ...
global___SetSharedKeyRequest = SetSharedKeyRequest
-@typing_extensions.final
+@typing.final
class SetSharedKeyResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -287,7 +313,7 @@ class SetSharedKeyResponse(google.protobuf.message.Message):
global___SetSharedKeyResponse = SetSharedKeyResponse
-@typing_extensions.final
+@typing.final
class RatchetSharedKeyRequest(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -296,13 +322,14 @@ class RatchetSharedKeyRequest(google.protobuf.message.Message):
def __init__(
self,
*,
- key_index: builtins.int = ...,
+ key_index: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["key_index", b"key_index"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["key_index", b"key_index"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["key_index", b"key_index"]) -> None: ...
global___RatchetSharedKeyRequest = RatchetSharedKeyRequest
-@typing_extensions.final
+@typing.final
class RatchetSharedKeyResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -313,13 +340,12 @@ class RatchetSharedKeyResponse(google.protobuf.message.Message):
*,
new_key: builtins.bytes | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_new_key", b"_new_key", "new_key", b"new_key"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_new_key", b"_new_key", "new_key", b"new_key"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_new_key", b"_new_key"]) -> typing_extensions.Literal["new_key"] | None: ...
+ def HasField(self, field_name: typing.Literal["new_key", b"new_key"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["new_key", b"new_key"]) -> None: ...
global___RatchetSharedKeyResponse = RatchetSharedKeyResponse
-@typing_extensions.final
+@typing.final
class GetSharedKeyRequest(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -328,13 +354,14 @@ class GetSharedKeyRequest(google.protobuf.message.Message):
def __init__(
self,
*,
- key_index: builtins.int = ...,
+ key_index: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["key_index", b"key_index"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["key_index", b"key_index"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["key_index", b"key_index"]) -> None: ...
global___GetSharedKeyRequest = GetSharedKeyRequest
-@typing_extensions.final
+@typing.final
class GetSharedKeyResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -345,13 +372,12 @@ class GetSharedKeyResponse(google.protobuf.message.Message):
*,
key: builtins.bytes | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_key", b"_key", "key", b"key"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_key", b"_key", "key", b"key"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_key", b"_key"]) -> typing_extensions.Literal["key"] | None: ...
+ def HasField(self, field_name: typing.Literal["key", b"key"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["key", b"key"]) -> None: ...
global___GetSharedKeyResponse = GetSharedKeyResponse
-@typing_extensions.final
+@typing.final
class SetKeyRequest(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -364,15 +390,16 @@ class SetKeyRequest(google.protobuf.message.Message):
def __init__(
self,
*,
- participant_identity: builtins.str = ...,
- key: builtins.bytes = ...,
- key_index: builtins.int = ...,
+ participant_identity: builtins.str | None = ...,
+ key: builtins.bytes | None = ...,
+ key_index: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["key", b"key", "key_index", b"key_index", "participant_identity", b"participant_identity"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["key", b"key", "key_index", b"key_index", "participant_identity", b"participant_identity"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["key", b"key", "key_index", b"key_index", "participant_identity", b"participant_identity"]) -> None: ...
global___SetKeyRequest = SetKeyRequest
-@typing_extensions.final
+@typing.final
class SetKeyResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -382,7 +409,7 @@ class SetKeyResponse(google.protobuf.message.Message):
global___SetKeyResponse = SetKeyResponse
-@typing_extensions.final
+@typing.final
class RatchetKeyRequest(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -393,14 +420,15 @@ class RatchetKeyRequest(google.protobuf.message.Message):
def __init__(
self,
*,
- participant_identity: builtins.str = ...,
- key_index: builtins.int = ...,
+ participant_identity: builtins.str | None = ...,
+ key_index: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["key_index", b"key_index", "participant_identity", b"participant_identity"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["key_index", b"key_index", "participant_identity", b"participant_identity"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["key_index", b"key_index", "participant_identity", b"participant_identity"]) -> None: ...
global___RatchetKeyRequest = RatchetKeyRequest
-@typing_extensions.final
+@typing.final
class RatchetKeyResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -411,13 +439,12 @@ class RatchetKeyResponse(google.protobuf.message.Message):
*,
new_key: builtins.bytes | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_new_key", b"_new_key", "new_key", b"new_key"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_new_key", b"_new_key", "new_key", b"new_key"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_new_key", b"_new_key"]) -> typing_extensions.Literal["new_key"] | None: ...
+ def HasField(self, field_name: typing.Literal["new_key", b"new_key"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["new_key", b"new_key"]) -> None: ...
global___RatchetKeyResponse = RatchetKeyResponse
-@typing_extensions.final
+@typing.final
class GetKeyRequest(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -428,14 +455,15 @@ class GetKeyRequest(google.protobuf.message.Message):
def __init__(
self,
*,
- participant_identity: builtins.str = ...,
- key_index: builtins.int = ...,
+ participant_identity: builtins.str | None = ...,
+ key_index: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["key_index", b"key_index", "participant_identity", b"participant_identity"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["key_index", b"key_index", "participant_identity", b"participant_identity"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["key_index", b"key_index", "participant_identity", b"participant_identity"]) -> None: ...
global___GetKeyRequest = GetKeyRequest
-@typing_extensions.final
+@typing.final
class GetKeyResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -446,13 +474,12 @@ class GetKeyResponse(google.protobuf.message.Message):
*,
key: builtins.bytes | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_key", b"_key", "key", b"key"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_key", b"_key", "key", b"key"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_key", b"_key"]) -> typing_extensions.Literal["key"] | None: ...
+ def HasField(self, field_name: typing.Literal["key", b"key"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["key", b"key"]) -> None: ...
global___GetKeyResponse = GetKeyResponse
-@typing_extensions.final
+@typing.final
class E2eeRequest(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -491,7 +518,7 @@ class E2eeRequest(google.protobuf.message.Message):
def __init__(
self,
*,
- room_handle: builtins.int = ...,
+ room_handle: builtins.int | None = ...,
manager_set_enabled: global___E2eeManagerSetEnabledRequest | None = ...,
manager_get_frame_cryptors: global___E2eeManagerGetFrameCryptorsRequest | None = ...,
cryptor_set_enabled: global___FrameCryptorSetEnabledRequest | None = ...,
@@ -503,13 +530,13 @@ class E2eeRequest(google.protobuf.message.Message):
ratchet_key: global___RatchetKeyRequest | None = ...,
get_key: global___GetKeyRequest | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["cryptor_set_enabled", b"cryptor_set_enabled", "cryptor_set_key_index", b"cryptor_set_key_index", "get_key", b"get_key", "get_shared_key", b"get_shared_key", "manager_get_frame_cryptors", b"manager_get_frame_cryptors", "manager_set_enabled", b"manager_set_enabled", "message", b"message", "ratchet_key", b"ratchet_key", "ratchet_shared_key", b"ratchet_shared_key", "set_key", b"set_key", "set_shared_key", b"set_shared_key"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["cryptor_set_enabled", b"cryptor_set_enabled", "cryptor_set_key_index", b"cryptor_set_key_index", "get_key", b"get_key", "get_shared_key", b"get_shared_key", "manager_get_frame_cryptors", b"manager_get_frame_cryptors", "manager_set_enabled", b"manager_set_enabled", "message", b"message", "ratchet_key", b"ratchet_key", "ratchet_shared_key", b"ratchet_shared_key", "room_handle", b"room_handle", "set_key", b"set_key", "set_shared_key", b"set_shared_key"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["message", b"message"]) -> typing_extensions.Literal["manager_set_enabled", "manager_get_frame_cryptors", "cryptor_set_enabled", "cryptor_set_key_index", "set_shared_key", "ratchet_shared_key", "get_shared_key", "set_key", "ratchet_key", "get_key"] | None: ...
+ def HasField(self, field_name: typing.Literal["cryptor_set_enabled", b"cryptor_set_enabled", "cryptor_set_key_index", b"cryptor_set_key_index", "get_key", b"get_key", "get_shared_key", b"get_shared_key", "manager_get_frame_cryptors", b"manager_get_frame_cryptors", "manager_set_enabled", b"manager_set_enabled", "message", b"message", "ratchet_key", b"ratchet_key", "ratchet_shared_key", b"ratchet_shared_key", "room_handle", b"room_handle", "set_key", b"set_key", "set_shared_key", b"set_shared_key"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["cryptor_set_enabled", b"cryptor_set_enabled", "cryptor_set_key_index", b"cryptor_set_key_index", "get_key", b"get_key", "get_shared_key", b"get_shared_key", "manager_get_frame_cryptors", b"manager_get_frame_cryptors", "manager_set_enabled", b"manager_set_enabled", "message", b"message", "ratchet_key", b"ratchet_key", "ratchet_shared_key", b"ratchet_shared_key", "room_handle", b"room_handle", "set_key", b"set_key", "set_shared_key", b"set_shared_key"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["message", b"message"]) -> typing.Literal["manager_set_enabled", "manager_get_frame_cryptors", "cryptor_set_enabled", "cryptor_set_key_index", "set_shared_key", "ratchet_shared_key", "get_shared_key", "set_key", "ratchet_key", "get_key"] | None: ...
global___E2eeRequest = E2eeRequest
-@typing_extensions.final
+@typing.final
class E2eeResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -557,8 +584,8 @@ class E2eeResponse(google.protobuf.message.Message):
ratchet_key: global___RatchetKeyResponse | None = ...,
get_key: global___GetKeyResponse | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["cryptor_set_enabled", b"cryptor_set_enabled", "cryptor_set_key_index", b"cryptor_set_key_index", "get_key", b"get_key", "get_shared_key", b"get_shared_key", "manager_get_frame_cryptors", b"manager_get_frame_cryptors", "manager_set_enabled", b"manager_set_enabled", "message", b"message", "ratchet_key", b"ratchet_key", "ratchet_shared_key", b"ratchet_shared_key", "set_key", b"set_key", "set_shared_key", b"set_shared_key"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["cryptor_set_enabled", b"cryptor_set_enabled", "cryptor_set_key_index", b"cryptor_set_key_index", "get_key", b"get_key", "get_shared_key", b"get_shared_key", "manager_get_frame_cryptors", b"manager_get_frame_cryptors", "manager_set_enabled", b"manager_set_enabled", "message", b"message", "ratchet_key", b"ratchet_key", "ratchet_shared_key", b"ratchet_shared_key", "set_key", b"set_key", "set_shared_key", b"set_shared_key"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["message", b"message"]) -> typing_extensions.Literal["manager_set_enabled", "manager_get_frame_cryptors", "cryptor_set_enabled", "cryptor_set_key_index", "set_shared_key", "ratchet_shared_key", "get_shared_key", "set_key", "ratchet_key", "get_key"] | None: ...
+ def HasField(self, field_name: typing.Literal["cryptor_set_enabled", b"cryptor_set_enabled", "cryptor_set_key_index", b"cryptor_set_key_index", "get_key", b"get_key", "get_shared_key", b"get_shared_key", "manager_get_frame_cryptors", b"manager_get_frame_cryptors", "manager_set_enabled", b"manager_set_enabled", "message", b"message", "ratchet_key", b"ratchet_key", "ratchet_shared_key", b"ratchet_shared_key", "set_key", b"set_key", "set_shared_key", b"set_shared_key"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["cryptor_set_enabled", b"cryptor_set_enabled", "cryptor_set_key_index", b"cryptor_set_key_index", "get_key", b"get_key", "get_shared_key", b"get_shared_key", "manager_get_frame_cryptors", b"manager_get_frame_cryptors", "manager_set_enabled", b"manager_set_enabled", "message", b"message", "ratchet_key", b"ratchet_key", "ratchet_shared_key", b"ratchet_shared_key", "set_key", b"set_key", "set_shared_key", b"set_shared_key"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["message", b"message"]) -> typing.Literal["manager_set_enabled", "manager_get_frame_cryptors", "cryptor_set_enabled", "cryptor_set_key_index", "set_shared_key", "ratchet_shared_key", "get_shared_key", "set_key", "ratchet_key", "get_key"] | None: ...
global___E2eeResponse = E2eeResponse
diff --git a/livekit-rtc/livekit/rtc/_proto/ffi_pb2.py b/livekit-rtc/livekit/rtc/_proto/ffi_pb2.py
index e414f0ca..02c5dd28 100644
--- a/livekit-rtc/livekit/rtc/_proto/ffi_pb2.py
+++ b/livekit-rtc/livekit/rtc/_proto/ffi_pb2.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: ffi.proto
-# Protobuf Python Version: 4.25.3
+# Protobuf Python Version: 4.25.1
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
@@ -14,12 +14,16 @@
from . import e2ee_pb2 as e2ee__pb2
from . import track_pb2 as track__pb2
+from . import track_publication_pb2 as track__publication__pb2
from . import room_pb2 as room__pb2
from . import video_frame_pb2 as video__frame__pb2
from . import audio_frame_pb2 as audio__frame__pb2
+from . import rpc_pb2 as rpc__pb2
+from . import data_stream_pb2 as data__stream__pb2
+from . import data_track_pb2 as data__track__pb2
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\tffi.proto\x12\rlivekit.proto\x1a\ne2ee.proto\x1a\x0btrack.proto\x1a\nroom.proto\x1a\x11video_frame.proto\x1a\x11\x61udio_frame.proto\"\x9c\x0c\n\nFfiRequest\x12\x30\n\x07\x64ispose\x18\x02 \x01(\x0b\x32\x1d.livekit.proto.DisposeRequestH\x00\x12\x30\n\x07\x63onnect\x18\x03 \x01(\x0b\x32\x1d.livekit.proto.ConnectRequestH\x00\x12\x36\n\ndisconnect\x18\x04 \x01(\x0b\x32 .livekit.proto.DisconnectRequestH\x00\x12;\n\rpublish_track\x18\x05 \x01(\x0b\x32\".livekit.proto.PublishTrackRequestH\x00\x12?\n\x0funpublish_track\x18\x06 \x01(\x0b\x32$.livekit.proto.UnpublishTrackRequestH\x00\x12\x39\n\x0cpublish_data\x18\x07 \x01(\x0b\x32!.livekit.proto.PublishDataRequestH\x00\x12=\n\x0eset_subscribed\x18\x08 \x01(\x0b\x32#.livekit.proto.SetSubscribedRequestH\x00\x12J\n\x15update_local_metadata\x18\t \x01(\x0b\x32).livekit.proto.UpdateLocalMetadataRequestH\x00\x12\x42\n\x11update_local_name\x18\n \x01(\x0b\x32%.livekit.proto.UpdateLocalNameRequestH\x00\x12\x42\n\x11get_session_stats\x18\x0b \x01(\x0b\x32%.livekit.proto.GetSessionStatsRequestH\x00\x12K\n\x15publish_transcription\x18\x0c \x01(\x0b\x32*.livekit.proto.PublishTranscriptionRequestH\x00\x12\x44\n\x12\x63reate_video_track\x18\r \x01(\x0b\x32&.livekit.proto.CreateVideoTrackRequestH\x00\x12\x44\n\x12\x63reate_audio_track\x18\x0e \x01(\x0b\x32&.livekit.proto.CreateAudioTrackRequestH\x00\x12\x33\n\tget_stats\x18\x0f \x01(\x0b\x32\x1e.livekit.proto.GetStatsRequestH\x00\x12@\n\x10new_video_stream\x18\x10 \x01(\x0b\x32$.livekit.proto.NewVideoStreamRequestH\x00\x12@\n\x10new_video_source\x18\x11 \x01(\x0b\x32$.livekit.proto.NewVideoSourceRequestH\x00\x12\x46\n\x13\x63\x61pture_video_frame\x18\x12 \x01(\x0b\x32\'.livekit.proto.CaptureVideoFrameRequestH\x00\x12;\n\rvideo_convert\x18\x13 \x01(\x0b\x32\".livekit.proto.VideoConvertRequestH\x00\x12@\n\x10new_audio_stream\x18\x16 \x01(\x0b\x32$.livekit.proto.NewAudioStreamRequestH\x00\x12@\n\x10new_audio_source\x18\x17 \x01(\x0b\x32$.livekit.proto.NewAudioSourceRequestH\x00\x12\x46\n\x13\x63\x61pture_audio_frame\x18\x18 \x01(\x0b\x32\'.livekit.proto.CaptureAudioFrameRequestH\x00\x12\x46\n\x13new_audio_resampler\x18\x19 \x01(\x0b\x32\'.livekit.proto.NewAudioResamplerRequestH\x00\x12\x44\n\x12remix_and_resample\x18\x1a \x01(\x0b\x32&.livekit.proto.RemixAndResampleRequestH\x00\x12*\n\x04\x65\x32\x65\x65\x18\x1b \x01(\x0b\x32\x1a.livekit.proto.E2eeRequestH\x00\x42\t\n\x07message\"\xb5\x0c\n\x0b\x46\x66iResponse\x12\x31\n\x07\x64ispose\x18\x02 \x01(\x0b\x32\x1e.livekit.proto.DisposeResponseH\x00\x12\x31\n\x07\x63onnect\x18\x03 \x01(\x0b\x32\x1e.livekit.proto.ConnectResponseH\x00\x12\x37\n\ndisconnect\x18\x04 \x01(\x0b\x32!.livekit.proto.DisconnectResponseH\x00\x12<\n\rpublish_track\x18\x05 \x01(\x0b\x32#.livekit.proto.PublishTrackResponseH\x00\x12@\n\x0funpublish_track\x18\x06 \x01(\x0b\x32%.livekit.proto.UnpublishTrackResponseH\x00\x12:\n\x0cpublish_data\x18\x07 \x01(\x0b\x32\".livekit.proto.PublishDataResponseH\x00\x12>\n\x0eset_subscribed\x18\x08 \x01(\x0b\x32$.livekit.proto.SetSubscribedResponseH\x00\x12K\n\x15update_local_metadata\x18\t \x01(\x0b\x32*.livekit.proto.UpdateLocalMetadataResponseH\x00\x12\x43\n\x11update_local_name\x18\n \x01(\x0b\x32&.livekit.proto.UpdateLocalNameResponseH\x00\x12\x43\n\x11get_session_stats\x18\x0b \x01(\x0b\x32&.livekit.proto.GetSessionStatsResponseH\x00\x12L\n\x15publish_transcription\x18\x0c \x01(\x0b\x32+.livekit.proto.PublishTranscriptionResponseH\x00\x12\x45\n\x12\x63reate_video_track\x18\r \x01(\x0b\x32\'.livekit.proto.CreateVideoTrackResponseH\x00\x12\x45\n\x12\x63reate_audio_track\x18\x0e \x01(\x0b\x32\'.livekit.proto.CreateAudioTrackResponseH\x00\x12\x34\n\tget_stats\x18\x0f \x01(\x0b\x32\x1f.livekit.proto.GetStatsResponseH\x00\x12\x41\n\x10new_video_stream\x18\x10 \x01(\x0b\x32%.livekit.proto.NewVideoStreamResponseH\x00\x12\x41\n\x10new_video_source\x18\x11 \x01(\x0b\x32%.livekit.proto.NewVideoSourceResponseH\x00\x12G\n\x13\x63\x61pture_video_frame\x18\x12 \x01(\x0b\x32(.livekit.proto.CaptureVideoFrameResponseH\x00\x12<\n\rvideo_convert\x18\x13 \x01(\x0b\x32#.livekit.proto.VideoConvertResponseH\x00\x12\x41\n\x10new_audio_stream\x18\x16 \x01(\x0b\x32%.livekit.proto.NewAudioStreamResponseH\x00\x12\x41\n\x10new_audio_source\x18\x17 \x01(\x0b\x32%.livekit.proto.NewAudioSourceResponseH\x00\x12G\n\x13\x63\x61pture_audio_frame\x18\x18 \x01(\x0b\x32(.livekit.proto.CaptureAudioFrameResponseH\x00\x12G\n\x13new_audio_resampler\x18\x19 \x01(\x0b\x32(.livekit.proto.NewAudioResamplerResponseH\x00\x12\x45\n\x12remix_and_resample\x18\x1a \x01(\x0b\x32\'.livekit.proto.RemixAndResampleResponseH\x00\x12+\n\x04\x65\x32\x65\x65\x18\x1b \x01(\x0b\x32\x1b.livekit.proto.E2eeResponseH\x00\x42\t\n\x07message\"\xc4\x08\n\x08\x46\x66iEvent\x12.\n\nroom_event\x18\x01 \x01(\x0b\x32\x18.livekit.proto.RoomEventH\x00\x12\x30\n\x0btrack_event\x18\x02 \x01(\x0b\x32\x19.livekit.proto.TrackEventH\x00\x12=\n\x12video_stream_event\x18\x03 \x01(\x0b\x32\x1f.livekit.proto.VideoStreamEventH\x00\x12=\n\x12\x61udio_stream_event\x18\x04 \x01(\x0b\x32\x1f.livekit.proto.AudioStreamEventH\x00\x12\x31\n\x07\x63onnect\x18\x05 \x01(\x0b\x32\x1e.livekit.proto.ConnectCallbackH\x00\x12\x37\n\ndisconnect\x18\x06 \x01(\x0b\x32!.livekit.proto.DisconnectCallbackH\x00\x12\x31\n\x07\x64ispose\x18\x07 \x01(\x0b\x32\x1e.livekit.proto.DisposeCallbackH\x00\x12<\n\rpublish_track\x18\x08 \x01(\x0b\x32#.livekit.proto.PublishTrackCallbackH\x00\x12@\n\x0funpublish_track\x18\t \x01(\x0b\x32%.livekit.proto.UnpublishTrackCallbackH\x00\x12:\n\x0cpublish_data\x18\n \x01(\x0b\x32\".livekit.proto.PublishDataCallbackH\x00\x12L\n\x15publish_transcription\x18\x0b \x01(\x0b\x32+.livekit.proto.PublishTranscriptionCallbackH\x00\x12G\n\x13\x63\x61pture_audio_frame\x18\x0c \x01(\x0b\x32(.livekit.proto.CaptureAudioFrameCallbackH\x00\x12K\n\x15update_local_metadata\x18\r \x01(\x0b\x32*.livekit.proto.UpdateLocalMetadataCallbackH\x00\x12\x43\n\x11update_local_name\x18\x0e \x01(\x0b\x32&.livekit.proto.UpdateLocalNameCallbackH\x00\x12\x34\n\tget_stats\x18\x0f \x01(\x0b\x32\x1f.livekit.proto.GetStatsCallbackH\x00\x12\'\n\x04logs\x18\x10 \x01(\x0b\x32\x17.livekit.proto.LogBatchH\x00\x12\x43\n\x11get_session_stats\x18\x11 \x01(\x0b\x32&.livekit.proto.GetSessionStatsCallbackH\x00\x12%\n\x05panic\x18\x12 \x01(\x0b\x32\x14.livekit.proto.PanicH\x00\x42\t\n\x07message\"\x1f\n\x0e\x44isposeRequest\x12\r\n\x05\x61sync\x18\x01 \x01(\x08\"5\n\x0f\x44isposeResponse\x12\x15\n\x08\x61sync_id\x18\x01 \x01(\x04H\x00\x88\x01\x01\x42\x0b\n\t_async_id\"#\n\x0f\x44isposeCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x01(\x04\"\xb6\x01\n\tLogRecord\x12&\n\x05level\x18\x01 \x01(\x0e\x32\x17.livekit.proto.LogLevel\x12\x0e\n\x06target\x18\x02 \x01(\t\x12\x18\n\x0bmodule_path\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x11\n\x04\x66ile\x18\x04 \x01(\tH\x01\x88\x01\x01\x12\x11\n\x04line\x18\x05 \x01(\rH\x02\x88\x01\x01\x12\x0f\n\x07message\x18\x06 \x01(\tB\x0e\n\x0c_module_pathB\x07\n\x05_fileB\x07\n\x05_line\"5\n\x08LogBatch\x12)\n\x07records\x18\x01 \x03(\x0b\x32\x18.livekit.proto.LogRecord\"\x18\n\x05Panic\x12\x0f\n\x07message\x18\x01 \x01(\t*S\n\x08LogLevel\x12\r\n\tLOG_ERROR\x10\x00\x12\x0c\n\x08LOG_WARN\x10\x01\x12\x0c\n\x08LOG_INFO\x10\x02\x12\r\n\tLOG_DEBUG\x10\x03\x12\r\n\tLOG_TRACE\x10\x04\x42\x10\xaa\x02\rLiveKit.Protob\x06proto3')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\tffi.proto\x12\rlivekit.proto\x1a\ne2ee.proto\x1a\x0btrack.proto\x1a\x17track_publication.proto\x1a\nroom.proto\x1a\x11video_frame.proto\x1a\x11\x61udio_frame.proto\x1a\trpc.proto\x1a\x11\x64\x61ta_stream.proto\x1a\x10\x64\x61ta_track.proto\"\xa0*\n\nFfiRequest\x12\x30\n\x07\x64ispose\x18\x02 \x01(\x0b\x32\x1d.livekit.proto.DisposeRequestH\x00\x12\x30\n\x07\x63onnect\x18\x03 \x01(\x0b\x32\x1d.livekit.proto.ConnectRequestH\x00\x12\x36\n\ndisconnect\x18\x04 \x01(\x0b\x32 .livekit.proto.DisconnectRequestH\x00\x12;\n\rpublish_track\x18\x05 \x01(\x0b\x32\".livekit.proto.PublishTrackRequestH\x00\x12?\n\x0funpublish_track\x18\x06 \x01(\x0b\x32$.livekit.proto.UnpublishTrackRequestH\x00\x12\x39\n\x0cpublish_data\x18\x07 \x01(\x0b\x32!.livekit.proto.PublishDataRequestH\x00\x12=\n\x0eset_subscribed\x18\x08 \x01(\x0b\x32#.livekit.proto.SetSubscribedRequestH\x00\x12\x44\n\x12set_local_metadata\x18\t \x01(\x0b\x32&.livekit.proto.SetLocalMetadataRequestH\x00\x12<\n\x0eset_local_name\x18\n \x01(\x0b\x32\".livekit.proto.SetLocalNameRequestH\x00\x12H\n\x14set_local_attributes\x18\x0b \x01(\x0b\x32(.livekit.proto.SetLocalAttributesRequestH\x00\x12\x42\n\x11get_session_stats\x18\x0c \x01(\x0b\x32%.livekit.proto.GetSessionStatsRequestH\x00\x12K\n\x15publish_transcription\x18\r \x01(\x0b\x32*.livekit.proto.PublishTranscriptionRequestH\x00\x12@\n\x10publish_sip_dtmf\x18\x0e \x01(\x0b\x32$.livekit.proto.PublishSipDtmfRequestH\x00\x12\x44\n\x12\x63reate_video_track\x18\x0f \x01(\x0b\x32&.livekit.proto.CreateVideoTrackRequestH\x00\x12\x44\n\x12\x63reate_audio_track\x18\x10 \x01(\x0b\x32&.livekit.proto.CreateAudioTrackRequestH\x00\x12@\n\x10local_track_mute\x18\x11 \x01(\x0b\x32$.livekit.proto.LocalTrackMuteRequestH\x00\x12\x46\n\x13\x65nable_remote_track\x18\x12 \x01(\x0b\x32\'.livekit.proto.EnableRemoteTrackRequestH\x00\x12\x33\n\tget_stats\x18\x13 \x01(\x0b\x32\x1e.livekit.proto.GetStatsRequestH\x00\x12\x63\n\"set_track_subscription_permissions\x18\x30 \x01(\x0b\x32\x35.livekit.proto.SetTrackSubscriptionPermissionsRequestH\x00\x12@\n\x10new_video_stream\x18\x14 \x01(\x0b\x32$.livekit.proto.NewVideoStreamRequestH\x00\x12@\n\x10new_video_source\x18\x15 \x01(\x0b\x32$.livekit.proto.NewVideoSourceRequestH\x00\x12\x46\n\x13\x63\x61pture_video_frame\x18\x16 \x01(\x0b\x32\'.livekit.proto.CaptureVideoFrameRequestH\x00\x12;\n\rvideo_convert\x18\x17 \x01(\x0b\x32\".livekit.proto.VideoConvertRequestH\x00\x12Y\n\x1dvideo_stream_from_participant\x18\x18 \x01(\x0b\x32\x30.livekit.proto.VideoStreamFromParticipantRequestH\x00\x12@\n\x10new_audio_stream\x18\x19 \x01(\x0b\x32$.livekit.proto.NewAudioStreamRequestH\x00\x12@\n\x10new_audio_source\x18\x1a \x01(\x0b\x32$.livekit.proto.NewAudioSourceRequestH\x00\x12\x46\n\x13\x63\x61pture_audio_frame\x18\x1b \x01(\x0b\x32\'.livekit.proto.CaptureAudioFrameRequestH\x00\x12\x44\n\x12\x63lear_audio_buffer\x18\x1c \x01(\x0b\x32&.livekit.proto.ClearAudioBufferRequestH\x00\x12\x46\n\x13new_audio_resampler\x18\x1d \x01(\x0b\x32\'.livekit.proto.NewAudioResamplerRequestH\x00\x12\x44\n\x12remix_and_resample\x18\x1e \x01(\x0b\x32&.livekit.proto.RemixAndResampleRequestH\x00\x12*\n\x04\x65\x32\x65\x65\x18\x1f \x01(\x0b\x32\x1a.livekit.proto.E2eeRequestH\x00\x12Y\n\x1d\x61udio_stream_from_participant\x18 \x01(\x0b\x32\x30.livekit.proto.AudioStreamFromParticipantRequestH\x00\x12\x42\n\x11new_sox_resampler\x18! \x01(\x0b\x32%.livekit.proto.NewSoxResamplerRequestH\x00\x12\x44\n\x12push_sox_resampler\x18\" \x01(\x0b\x32&.livekit.proto.PushSoxResamplerRequestH\x00\x12\x46\n\x13\x66lush_sox_resampler\x18# \x01(\x0b\x32\'.livekit.proto.FlushSoxResamplerRequestH\x00\x12\x42\n\x11send_chat_message\x18$ \x01(\x0b\x32%.livekit.proto.SendChatMessageRequestH\x00\x12\x42\n\x11\x65\x64it_chat_message\x18% \x01(\x0b\x32%.livekit.proto.EditChatMessageRequestH\x00\x12\x37\n\x0bperform_rpc\x18& \x01(\x0b\x32 .livekit.proto.PerformRpcRequestH\x00\x12\x46\n\x13register_rpc_method\x18\' \x01(\x0b\x32\'.livekit.proto.RegisterRpcMethodRequestH\x00\x12J\n\x15unregister_rpc_method\x18( \x01(\x0b\x32).livekit.proto.UnregisterRpcMethodRequestH\x00\x12[\n\x1erpc_method_invocation_response\x18) \x01(\x0b\x32\x31.livekit.proto.RpcMethodInvocationResponseRequestH\x00\x12]\n\x1f\x65nable_remote_track_publication\x18* \x01(\x0b\x32\x32.livekit.proto.EnableRemoteTrackPublicationRequestH\x00\x12p\n)update_remote_track_publication_dimension\x18+ \x01(\x0b\x32;.livekit.proto.UpdateRemoteTrackPublicationDimensionRequestH\x00\x12\x44\n\x12send_stream_header\x18, \x01(\x0b\x32&.livekit.proto.SendStreamHeaderRequestH\x00\x12\x42\n\x11send_stream_chunk\x18- \x01(\x0b\x32%.livekit.proto.SendStreamChunkRequestH\x00\x12\x46\n\x13send_stream_trailer\x18. \x01(\x0b\x32\'.livekit.proto.SendStreamTrailerRequestH\x00\x12x\n.set_data_channel_buffered_amount_low_threshold\x18/ \x01(\x0b\x32>.livekit.proto.SetDataChannelBufferedAmountLowThresholdRequestH\x00\x12O\n\x18load_audio_filter_plugin\x18\x31 \x01(\x0b\x32+.livekit.proto.LoadAudioFilterPluginRequestH\x00\x12/\n\x07new_apm\x18\x32 \x01(\x0b\x32\x1c.livekit.proto.NewApmRequestH\x00\x12\x44\n\x12\x61pm_process_stream\x18\x33 \x01(\x0b\x32&.livekit.proto.ApmProcessStreamRequestH\x00\x12S\n\x1a\x61pm_process_reverse_stream\x18\x34 \x01(\x0b\x32-.livekit.proto.ApmProcessReverseStreamRequestH\x00\x12G\n\x14\x61pm_set_stream_delay\x18\x35 \x01(\x0b\x32\'.livekit.proto.ApmSetStreamDelayRequestH\x00\x12V\n\x15\x62yte_read_incremental\x18\x36 \x01(\x0b\x32\x35.livekit.proto.ByteStreamReaderReadIncrementalRequestH\x00\x12\x46\n\rbyte_read_all\x18\x37 \x01(\x0b\x32-.livekit.proto.ByteStreamReaderReadAllRequestH\x00\x12O\n\x12\x62yte_write_to_file\x18\x38 \x01(\x0b\x32\x31.livekit.proto.ByteStreamReaderWriteToFileRequestH\x00\x12V\n\x15text_read_incremental\x18\x39 \x01(\x0b\x32\x35.livekit.proto.TextStreamReaderReadIncrementalRequestH\x00\x12\x46\n\rtext_read_all\x18: \x01(\x0b\x32-.livekit.proto.TextStreamReaderReadAllRequestH\x00\x12\x39\n\tsend_file\x18; \x01(\x0b\x32$.livekit.proto.StreamSendFileRequestH\x00\x12\x39\n\tsend_text\x18< \x01(\x0b\x32$.livekit.proto.StreamSendTextRequestH\x00\x12@\n\x10\x62yte_stream_open\x18= \x01(\x0b\x32$.livekit.proto.ByteStreamOpenRequestH\x00\x12H\n\x11\x62yte_stream_write\x18> \x01(\x0b\x32+.livekit.proto.ByteStreamWriterWriteRequestH\x00\x12H\n\x11\x62yte_stream_close\x18? \x01(\x0b\x32+.livekit.proto.ByteStreamWriterCloseRequestH\x00\x12@\n\x10text_stream_open\x18@ \x01(\x0b\x32$.livekit.proto.TextStreamOpenRequestH\x00\x12H\n\x11text_stream_write\x18\x41 \x01(\x0b\x32+.livekit.proto.TextStreamWriterWriteRequestH\x00\x12H\n\x11text_stream_close\x18\x42 \x01(\x0b\x32+.livekit.proto.TextStreamWriterCloseRequestH\x00\x12;\n\nsend_bytes\x18\x43 \x01(\x0b\x32%.livekit.proto.StreamSendBytesRequestH\x00\x12\x66\n$set_remote_track_publication_quality\x18\x44 \x01(\x0b\x32\x36.livekit.proto.SetRemoteTrackPublicationQualityRequestH\x00\x12\x44\n\x12publish_data_track\x18\x45 \x01(\x0b\x32&.livekit.proto.PublishDataTrackRequestH\x00\x12P\n\x19local_data_track_try_push\x18\x46 \x01(\x0b\x32+.livekit.proto.LocalDataTrackTryPushRequestH\x00\x12S\n\x1alocal_data_track_unpublish\x18G \x01(\x0b\x32-.livekit.proto.LocalDataTrackUnpublishRequestH\x00\x12X\n\x1dlocal_data_track_is_published\x18H \x01(\x0b\x32/.livekit.proto.LocalDataTrackIsPublishedRequestH\x00\x12H\n\x14subscribe_data_track\x18I \x01(\x0b\x32(.livekit.proto.SubscribeDataTrackRequestH\x00\x12Z\n\x1eremote_data_track_is_published\x18J \x01(\x0b\x32\x30.livekit.proto.RemoteDataTrackIsPublishedRequestH\x00\x12K\n\x16\x64\x61ta_track_stream_read\x18K \x01(\x0b\x32).livekit.proto.DataTrackStreamReadRequestH\x00\x42\t\n\x07message\"\xa6*\n\x0b\x46\x66iResponse\x12\x31\n\x07\x64ispose\x18\x02 \x01(\x0b\x32\x1e.livekit.proto.DisposeResponseH\x00\x12\x31\n\x07\x63onnect\x18\x03 \x01(\x0b\x32\x1e.livekit.proto.ConnectResponseH\x00\x12\x37\n\ndisconnect\x18\x04 \x01(\x0b\x32!.livekit.proto.DisconnectResponseH\x00\x12<\n\rpublish_track\x18\x05 \x01(\x0b\x32#.livekit.proto.PublishTrackResponseH\x00\x12@\n\x0funpublish_track\x18\x06 \x01(\x0b\x32%.livekit.proto.UnpublishTrackResponseH\x00\x12:\n\x0cpublish_data\x18\x07 \x01(\x0b\x32\".livekit.proto.PublishDataResponseH\x00\x12>\n\x0eset_subscribed\x18\x08 \x01(\x0b\x32$.livekit.proto.SetSubscribedResponseH\x00\x12\x45\n\x12set_local_metadata\x18\t \x01(\x0b\x32\'.livekit.proto.SetLocalMetadataResponseH\x00\x12=\n\x0eset_local_name\x18\n \x01(\x0b\x32#.livekit.proto.SetLocalNameResponseH\x00\x12I\n\x14set_local_attributes\x18\x0b \x01(\x0b\x32).livekit.proto.SetLocalAttributesResponseH\x00\x12\x43\n\x11get_session_stats\x18\x0c \x01(\x0b\x32&.livekit.proto.GetSessionStatsResponseH\x00\x12L\n\x15publish_transcription\x18\r \x01(\x0b\x32+.livekit.proto.PublishTranscriptionResponseH\x00\x12\x41\n\x10publish_sip_dtmf\x18\x0e \x01(\x0b\x32%.livekit.proto.PublishSipDtmfResponseH\x00\x12\x45\n\x12\x63reate_video_track\x18\x0f \x01(\x0b\x32\'.livekit.proto.CreateVideoTrackResponseH\x00\x12\x45\n\x12\x63reate_audio_track\x18\x10 \x01(\x0b\x32\'.livekit.proto.CreateAudioTrackResponseH\x00\x12\x41\n\x10local_track_mute\x18\x11 \x01(\x0b\x32%.livekit.proto.LocalTrackMuteResponseH\x00\x12G\n\x13\x65nable_remote_track\x18\x12 \x01(\x0b\x32(.livekit.proto.EnableRemoteTrackResponseH\x00\x12\x34\n\tget_stats\x18\x13 \x01(\x0b\x32\x1f.livekit.proto.GetStatsResponseH\x00\x12\x64\n\"set_track_subscription_permissions\x18/ \x01(\x0b\x32\x36.livekit.proto.SetTrackSubscriptionPermissionsResponseH\x00\x12\x41\n\x10new_video_stream\x18\x14 \x01(\x0b\x32%.livekit.proto.NewVideoStreamResponseH\x00\x12\x41\n\x10new_video_source\x18\x15 \x01(\x0b\x32%.livekit.proto.NewVideoSourceResponseH\x00\x12G\n\x13\x63\x61pture_video_frame\x18\x16 \x01(\x0b\x32(.livekit.proto.CaptureVideoFrameResponseH\x00\x12<\n\rvideo_convert\x18\x17 \x01(\x0b\x32#.livekit.proto.VideoConvertResponseH\x00\x12Z\n\x1dvideo_stream_from_participant\x18\x18 \x01(\x0b\x32\x31.livekit.proto.VideoStreamFromParticipantResponseH\x00\x12\x41\n\x10new_audio_stream\x18\x19 \x01(\x0b\x32%.livekit.proto.NewAudioStreamResponseH\x00\x12\x41\n\x10new_audio_source\x18\x1a \x01(\x0b\x32%.livekit.proto.NewAudioSourceResponseH\x00\x12G\n\x13\x63\x61pture_audio_frame\x18\x1b \x01(\x0b\x32(.livekit.proto.CaptureAudioFrameResponseH\x00\x12\x45\n\x12\x63lear_audio_buffer\x18\x1c \x01(\x0b\x32\'.livekit.proto.ClearAudioBufferResponseH\x00\x12G\n\x13new_audio_resampler\x18\x1d \x01(\x0b\x32(.livekit.proto.NewAudioResamplerResponseH\x00\x12\x45\n\x12remix_and_resample\x18\x1e \x01(\x0b\x32\'.livekit.proto.RemixAndResampleResponseH\x00\x12Z\n\x1d\x61udio_stream_from_participant\x18\x1f \x01(\x0b\x32\x31.livekit.proto.AudioStreamFromParticipantResponseH\x00\x12+\n\x04\x65\x32\x65\x65\x18 \x01(\x0b\x32\x1b.livekit.proto.E2eeResponseH\x00\x12\x43\n\x11new_sox_resampler\x18! \x01(\x0b\x32&.livekit.proto.NewSoxResamplerResponseH\x00\x12\x45\n\x12push_sox_resampler\x18\" \x01(\x0b\x32\'.livekit.proto.PushSoxResamplerResponseH\x00\x12G\n\x13\x66lush_sox_resampler\x18# \x01(\x0b\x32(.livekit.proto.FlushSoxResamplerResponseH\x00\x12\x43\n\x11send_chat_message\x18$ \x01(\x0b\x32&.livekit.proto.SendChatMessageResponseH\x00\x12\x38\n\x0bperform_rpc\x18% \x01(\x0b\x32!.livekit.proto.PerformRpcResponseH\x00\x12G\n\x13register_rpc_method\x18& \x01(\x0b\x32(.livekit.proto.RegisterRpcMethodResponseH\x00\x12K\n\x15unregister_rpc_method\x18\' \x01(\x0b\x32*.livekit.proto.UnregisterRpcMethodResponseH\x00\x12\\\n\x1erpc_method_invocation_response\x18( \x01(\x0b\x32\x32.livekit.proto.RpcMethodInvocationResponseResponseH\x00\x12^\n\x1f\x65nable_remote_track_publication\x18) \x01(\x0b\x32\x33.livekit.proto.EnableRemoteTrackPublicationResponseH\x00\x12q\n)update_remote_track_publication_dimension\x18* \x01(\x0b\x32<.livekit.proto.UpdateRemoteTrackPublicationDimensionResponseH\x00\x12\x45\n\x12send_stream_header\x18+ \x01(\x0b\x32\'.livekit.proto.SendStreamHeaderResponseH\x00\x12\x43\n\x11send_stream_chunk\x18, \x01(\x0b\x32&.livekit.proto.SendStreamChunkResponseH\x00\x12G\n\x13send_stream_trailer\x18- \x01(\x0b\x32(.livekit.proto.SendStreamTrailerResponseH\x00\x12y\n.set_data_channel_buffered_amount_low_threshold\x18. \x01(\x0b\x32?.livekit.proto.SetDataChannelBufferedAmountLowThresholdResponseH\x00\x12P\n\x18load_audio_filter_plugin\x18\x30 \x01(\x0b\x32,.livekit.proto.LoadAudioFilterPluginResponseH\x00\x12\x30\n\x07new_apm\x18\x31 \x01(\x0b\x32\x1d.livekit.proto.NewApmResponseH\x00\x12\x45\n\x12\x61pm_process_stream\x18\x32 \x01(\x0b\x32\'.livekit.proto.ApmProcessStreamResponseH\x00\x12T\n\x1a\x61pm_process_reverse_stream\x18\x33 \x01(\x0b\x32..livekit.proto.ApmProcessReverseStreamResponseH\x00\x12H\n\x14\x61pm_set_stream_delay\x18\x34 \x01(\x0b\x32(.livekit.proto.ApmSetStreamDelayResponseH\x00\x12W\n\x15\x62yte_read_incremental\x18\x35 \x01(\x0b\x32\x36.livekit.proto.ByteStreamReaderReadIncrementalResponseH\x00\x12G\n\rbyte_read_all\x18\x36 \x01(\x0b\x32..livekit.proto.ByteStreamReaderReadAllResponseH\x00\x12P\n\x12\x62yte_write_to_file\x18\x37 \x01(\x0b\x32\x32.livekit.proto.ByteStreamReaderWriteToFileResponseH\x00\x12W\n\x15text_read_incremental\x18\x38 \x01(\x0b\x32\x36.livekit.proto.TextStreamReaderReadIncrementalResponseH\x00\x12G\n\rtext_read_all\x18\x39 \x01(\x0b\x32..livekit.proto.TextStreamReaderReadAllResponseH\x00\x12:\n\tsend_file\x18: \x01(\x0b\x32%.livekit.proto.StreamSendFileResponseH\x00\x12:\n\tsend_text\x18; \x01(\x0b\x32%.livekit.proto.StreamSendTextResponseH\x00\x12\x41\n\x10\x62yte_stream_open\x18< \x01(\x0b\x32%.livekit.proto.ByteStreamOpenResponseH\x00\x12I\n\x11\x62yte_stream_write\x18= \x01(\x0b\x32,.livekit.proto.ByteStreamWriterWriteResponseH\x00\x12I\n\x11\x62yte_stream_close\x18> \x01(\x0b\x32,.livekit.proto.ByteStreamWriterCloseResponseH\x00\x12\x41\n\x10text_stream_open\x18? \x01(\x0b\x32%.livekit.proto.TextStreamOpenResponseH\x00\x12I\n\x11text_stream_write\x18@ \x01(\x0b\x32,.livekit.proto.TextStreamWriterWriteResponseH\x00\x12I\n\x11text_stream_close\x18\x41 \x01(\x0b\x32,.livekit.proto.TextStreamWriterCloseResponseH\x00\x12<\n\nsend_bytes\x18\x42 \x01(\x0b\x32&.livekit.proto.StreamSendBytesResponseH\x00\x12g\n$set_remote_track_publication_quality\x18\x43 \x01(\x0b\x32\x37.livekit.proto.SetRemoteTrackPublicationQualityResponseH\x00\x12\x45\n\x12publish_data_track\x18\x44 \x01(\x0b\x32\'.livekit.proto.PublishDataTrackResponseH\x00\x12Q\n\x19local_data_track_try_push\x18\x45 \x01(\x0b\x32,.livekit.proto.LocalDataTrackTryPushResponseH\x00\x12T\n\x1alocal_data_track_unpublish\x18\x46 \x01(\x0b\x32..livekit.proto.LocalDataTrackUnpublishResponseH\x00\x12Y\n\x1dlocal_data_track_is_published\x18G \x01(\x0b\x32\x30.livekit.proto.LocalDataTrackIsPublishedResponseH\x00\x12I\n\x14subscribe_data_track\x18H \x01(\x0b\x32).livekit.proto.SubscribeDataTrackResponseH\x00\x12[\n\x1eremote_data_track_is_published\x18I \x01(\x0b\x32\x31.livekit.proto.RemoteDataTrackIsPublishedResponseH\x00\x12L\n\x16\x64\x61ta_track_stream_read\x18J \x01(\x0b\x32*.livekit.proto.DataTrackStreamReadResponseH\x00\x42\t\n\x07message\"\x94\x16\n\x08\x46\x66iEvent\x12.\n\nroom_event\x18\x01 \x01(\x0b\x32\x18.livekit.proto.RoomEventH\x00\x12\x30\n\x0btrack_event\x18\x02 \x01(\x0b\x32\x19.livekit.proto.TrackEventH\x00\x12=\n\x12video_stream_event\x18\x03 \x01(\x0b\x32\x1f.livekit.proto.VideoStreamEventH\x00\x12=\n\x12\x61udio_stream_event\x18\x04 \x01(\x0b\x32\x1f.livekit.proto.AudioStreamEventH\x00\x12\x31\n\x07\x63onnect\x18\x05 \x01(\x0b\x32\x1e.livekit.proto.ConnectCallbackH\x00\x12\x37\n\ndisconnect\x18\x07 \x01(\x0b\x32!.livekit.proto.DisconnectCallbackH\x00\x12\x31\n\x07\x64ispose\x18\x08 \x01(\x0b\x32\x1e.livekit.proto.DisposeCallbackH\x00\x12<\n\rpublish_track\x18\t \x01(\x0b\x32#.livekit.proto.PublishTrackCallbackH\x00\x12@\n\x0funpublish_track\x18\n \x01(\x0b\x32%.livekit.proto.UnpublishTrackCallbackH\x00\x12:\n\x0cpublish_data\x18\x0b \x01(\x0b\x32\".livekit.proto.PublishDataCallbackH\x00\x12L\n\x15publish_transcription\x18\x0c \x01(\x0b\x32+.livekit.proto.PublishTranscriptionCallbackH\x00\x12G\n\x13\x63\x61pture_audio_frame\x18\r \x01(\x0b\x32(.livekit.proto.CaptureAudioFrameCallbackH\x00\x12\x45\n\x12set_local_metadata\x18\x0e \x01(\x0b\x32\'.livekit.proto.SetLocalMetadataCallbackH\x00\x12=\n\x0eset_local_name\x18\x0f \x01(\x0b\x32#.livekit.proto.SetLocalNameCallbackH\x00\x12I\n\x14set_local_attributes\x18\x10 \x01(\x0b\x32).livekit.proto.SetLocalAttributesCallbackH\x00\x12\x34\n\tget_stats\x18\x11 \x01(\x0b\x32\x1f.livekit.proto.GetStatsCallbackH\x00\x12\'\n\x04logs\x18\x12 \x01(\x0b\x32\x17.livekit.proto.LogBatchH\x00\x12\x43\n\x11get_session_stats\x18\x13 \x01(\x0b\x32&.livekit.proto.GetSessionStatsCallbackH\x00\x12%\n\x05panic\x18\x14 \x01(\x0b\x32\x14.livekit.proto.PanicH\x00\x12\x41\n\x10publish_sip_dtmf\x18\x15 \x01(\x0b\x32%.livekit.proto.PublishSipDtmfCallbackH\x00\x12>\n\x0c\x63hat_message\x18\x16 \x01(\x0b\x32&.livekit.proto.SendChatMessageCallbackH\x00\x12\x38\n\x0bperform_rpc\x18\x17 \x01(\x0b\x32!.livekit.proto.PerformRpcCallbackH\x00\x12H\n\x15rpc_method_invocation\x18\x18 \x01(\x0b\x32\'.livekit.proto.RpcMethodInvocationEventH\x00\x12\x45\n\x12send_stream_header\x18\x19 \x01(\x0b\x32\'.livekit.proto.SendStreamHeaderCallbackH\x00\x12\x43\n\x11send_stream_chunk\x18\x1a \x01(\x0b\x32&.livekit.proto.SendStreamChunkCallbackH\x00\x12G\n\x13send_stream_trailer\x18\x1b \x01(\x0b\x32(.livekit.proto.SendStreamTrailerCallbackH\x00\x12H\n\x18\x62yte_stream_reader_event\x18\x1c \x01(\x0b\x32$.livekit.proto.ByteStreamReaderEventH\x00\x12U\n\x1b\x62yte_stream_reader_read_all\x18\x1d \x01(\x0b\x32..livekit.proto.ByteStreamReaderReadAllCallbackH\x00\x12^\n byte_stream_reader_write_to_file\x18\x1e \x01(\x0b\x32\x32.livekit.proto.ByteStreamReaderWriteToFileCallbackH\x00\x12\x41\n\x10\x62yte_stream_open\x18\x1f \x01(\x0b\x32%.livekit.proto.ByteStreamOpenCallbackH\x00\x12P\n\x18\x62yte_stream_writer_write\x18 \x01(\x0b\x32,.livekit.proto.ByteStreamWriterWriteCallbackH\x00\x12P\n\x18\x62yte_stream_writer_close\x18! \x01(\x0b\x32,.livekit.proto.ByteStreamWriterCloseCallbackH\x00\x12:\n\tsend_file\x18\" \x01(\x0b\x32%.livekit.proto.StreamSendFileCallbackH\x00\x12H\n\x18text_stream_reader_event\x18# \x01(\x0b\x32$.livekit.proto.TextStreamReaderEventH\x00\x12U\n\x1btext_stream_reader_read_all\x18$ \x01(\x0b\x32..livekit.proto.TextStreamReaderReadAllCallbackH\x00\x12\x41\n\x10text_stream_open\x18% \x01(\x0b\x32%.livekit.proto.TextStreamOpenCallbackH\x00\x12P\n\x18text_stream_writer_write\x18& \x01(\x0b\x32,.livekit.proto.TextStreamWriterWriteCallbackH\x00\x12P\n\x18text_stream_writer_close\x18\' \x01(\x0b\x32,.livekit.proto.TextStreamWriterCloseCallbackH\x00\x12:\n\tsend_text\x18( \x01(\x0b\x32%.livekit.proto.StreamSendTextCallbackH\x00\x12<\n\nsend_bytes\x18) \x01(\x0b\x32&.livekit.proto.StreamSendBytesCallbackH\x00\x12\x45\n\x12publish_data_track\x18* \x01(\x0b\x32\'.livekit.proto.PublishDataTrackCallbackH\x00\x12\x46\n\x17\x64\x61ta_track_stream_event\x18+ \x01(\x0b\x32#.livekit.proto.DataTrackStreamEventH\x00\x42\t\n\x07message\"\x1f\n\x0e\x44isposeRequest\x12\r\n\x05\x61sync\x18\x01 \x02(\x08\"#\n\x0f\x44isposeResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x01(\x04\"#\n\x0f\x44isposeCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"\x85\x01\n\tLogRecord\x12&\n\x05level\x18\x01 \x02(\x0e\x32\x17.livekit.proto.LogLevel\x12\x0e\n\x06target\x18\x02 \x02(\t\x12\x13\n\x0bmodule_path\x18\x03 \x01(\t\x12\x0c\n\x04\x66ile\x18\x04 \x01(\t\x12\x0c\n\x04line\x18\x05 \x01(\r\x12\x0f\n\x07message\x18\x06 \x02(\t\"5\n\x08LogBatch\x12)\n\x07records\x18\x01 \x03(\x0b\x32\x18.livekit.proto.LogRecord\"\x18\n\x05Panic\x12\x0f\n\x07message\x18\x01 \x02(\t*S\n\x08LogLevel\x12\r\n\tLOG_ERROR\x10\x00\x12\x0c\n\x08LOG_WARN\x10\x01\x12\x0c\n\x08LOG_INFO\x10\x02\x12\r\n\tLOG_DEBUG\x10\x03\x12\r\n\tLOG_TRACE\x10\x04\x42\x10\xaa\x02\rLiveKit.Proto')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -27,24 +31,24 @@
if _descriptor._USE_C_DESCRIPTORS == False:
_globals['DESCRIPTOR']._options = None
_globals['DESCRIPTOR']._serialized_options = b'\252\002\rLiveKit.Proto'
- _globals['_LOGLEVEL']._serialized_start=4748
- _globals['_LOGLEVEL']._serialized_end=4831
- _globals['_FFIREQUEST']._serialized_start=104
- _globals['_FFIREQUEST']._serialized_end=1668
- _globals['_FFIRESPONSE']._serialized_start=1671
- _globals['_FFIRESPONSE']._serialized_end=3260
- _globals['_FFIEVENT']._serialized_start=3263
- _globals['_FFIEVENT']._serialized_end=4355
- _globals['_DISPOSEREQUEST']._serialized_start=4357
- _globals['_DISPOSEREQUEST']._serialized_end=4388
- _globals['_DISPOSERESPONSE']._serialized_start=4390
- _globals['_DISPOSERESPONSE']._serialized_end=4443
- _globals['_DISPOSECALLBACK']._serialized_start=4445
- _globals['_DISPOSECALLBACK']._serialized_end=4480
- _globals['_LOGRECORD']._serialized_start=4483
- _globals['_LOGRECORD']._serialized_end=4665
- _globals['_LOGBATCH']._serialized_start=4667
- _globals['_LOGBATCH']._serialized_end=4720
- _globals['_PANIC']._serialized_start=4722
- _globals['_PANIC']._serialized_end=4746
+ _globals['_LOGLEVEL']._serialized_start=14167
+ _globals['_LOGLEVEL']._serialized_end=14250
+ _globals['_FFIREQUEST']._serialized_start=177
+ _globals['_FFIREQUEST']._serialized_end=5585
+ _globals['_FFIRESPONSE']._serialized_start=5588
+ _globals['_FFIRESPONSE']._serialized_end=11002
+ _globals['_FFIEVENT']._serialized_start=11005
+ _globals['_FFIEVENT']._serialized_end=13841
+ _globals['_DISPOSEREQUEST']._serialized_start=13843
+ _globals['_DISPOSEREQUEST']._serialized_end=13874
+ _globals['_DISPOSERESPONSE']._serialized_start=13876
+ _globals['_DISPOSERESPONSE']._serialized_end=13911
+ _globals['_DISPOSECALLBACK']._serialized_start=13913
+ _globals['_DISPOSECALLBACK']._serialized_end=13948
+ _globals['_LOGRECORD']._serialized_start=13951
+ _globals['_LOGRECORD']._serialized_end=14084
+ _globals['_LOGBATCH']._serialized_start=14086
+ _globals['_LOGBATCH']._serialized_end=14139
+ _globals['_PANIC']._serialized_start=14141
+ _globals['_PANIC']._serialized_end=14165
# @@protoc_insertion_point(module_scope)
diff --git a/livekit-rtc/livekit/rtc/_proto/ffi_pb2.pyi b/livekit-rtc/livekit/rtc/_proto/ffi_pb2.pyi
index 259880ab..3d71bcf0 100644
--- a/livekit-rtc/livekit/rtc/_proto/ffi_pb2.pyi
+++ b/livekit-rtc/livekit/rtc/_proto/ffi_pb2.pyi
@@ -1,7 +1,7 @@
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
-Copyright 2023 LiveKit, Inc.
+Copyright 2025 LiveKit, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,17 +15,22 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
+
from . import audio_frame_pb2
import builtins
import collections.abc
+from . import data_stream_pb2
+from . import data_track_pb2
from . import e2ee_pb2
import google.protobuf.descriptor
import google.protobuf.internal.containers
import google.protobuf.internal.enum_type_wrapper
import google.protobuf.message
from . import room_pb2
+from . import rpc_pb2
import sys
from . import track_pb2
+from . import track_publication_pb2
import typing
from . import video_frame_pb2
@@ -57,7 +62,7 @@ LOG_DEBUG: LogLevel.ValueType # 3
LOG_TRACE: LogLevel.ValueType # 4
global___LogLevel = LogLevel
-@typing_extensions.final
+@typing.final
class FfiRequest(google.protobuf.message.Message):
"""**How is the livekit-ffi working:
We refer as the ffi server the Rust server that is running the LiveKit client implementation, and we
@@ -98,28 +103,79 @@ class FfiRequest(google.protobuf.message.Message):
UNPUBLISH_TRACK_FIELD_NUMBER: builtins.int
PUBLISH_DATA_FIELD_NUMBER: builtins.int
SET_SUBSCRIBED_FIELD_NUMBER: builtins.int
- UPDATE_LOCAL_METADATA_FIELD_NUMBER: builtins.int
- UPDATE_LOCAL_NAME_FIELD_NUMBER: builtins.int
+ SET_LOCAL_METADATA_FIELD_NUMBER: builtins.int
+ SET_LOCAL_NAME_FIELD_NUMBER: builtins.int
+ SET_LOCAL_ATTRIBUTES_FIELD_NUMBER: builtins.int
GET_SESSION_STATS_FIELD_NUMBER: builtins.int
PUBLISH_TRANSCRIPTION_FIELD_NUMBER: builtins.int
+ PUBLISH_SIP_DTMF_FIELD_NUMBER: builtins.int
CREATE_VIDEO_TRACK_FIELD_NUMBER: builtins.int
CREATE_AUDIO_TRACK_FIELD_NUMBER: builtins.int
+ LOCAL_TRACK_MUTE_FIELD_NUMBER: builtins.int
+ ENABLE_REMOTE_TRACK_FIELD_NUMBER: builtins.int
GET_STATS_FIELD_NUMBER: builtins.int
+ SET_TRACK_SUBSCRIPTION_PERMISSIONS_FIELD_NUMBER: builtins.int
NEW_VIDEO_STREAM_FIELD_NUMBER: builtins.int
NEW_VIDEO_SOURCE_FIELD_NUMBER: builtins.int
CAPTURE_VIDEO_FRAME_FIELD_NUMBER: builtins.int
VIDEO_CONVERT_FIELD_NUMBER: builtins.int
+ VIDEO_STREAM_FROM_PARTICIPANT_FIELD_NUMBER: builtins.int
NEW_AUDIO_STREAM_FIELD_NUMBER: builtins.int
NEW_AUDIO_SOURCE_FIELD_NUMBER: builtins.int
CAPTURE_AUDIO_FRAME_FIELD_NUMBER: builtins.int
+ CLEAR_AUDIO_BUFFER_FIELD_NUMBER: builtins.int
NEW_AUDIO_RESAMPLER_FIELD_NUMBER: builtins.int
REMIX_AND_RESAMPLE_FIELD_NUMBER: builtins.int
E2EE_FIELD_NUMBER: builtins.int
+ AUDIO_STREAM_FROM_PARTICIPANT_FIELD_NUMBER: builtins.int
+ NEW_SOX_RESAMPLER_FIELD_NUMBER: builtins.int
+ PUSH_SOX_RESAMPLER_FIELD_NUMBER: builtins.int
+ FLUSH_SOX_RESAMPLER_FIELD_NUMBER: builtins.int
+ SEND_CHAT_MESSAGE_FIELD_NUMBER: builtins.int
+ EDIT_CHAT_MESSAGE_FIELD_NUMBER: builtins.int
+ PERFORM_RPC_FIELD_NUMBER: builtins.int
+ REGISTER_RPC_METHOD_FIELD_NUMBER: builtins.int
+ UNREGISTER_RPC_METHOD_FIELD_NUMBER: builtins.int
+ RPC_METHOD_INVOCATION_RESPONSE_FIELD_NUMBER: builtins.int
+ ENABLE_REMOTE_TRACK_PUBLICATION_FIELD_NUMBER: builtins.int
+ UPDATE_REMOTE_TRACK_PUBLICATION_DIMENSION_FIELD_NUMBER: builtins.int
+ SEND_STREAM_HEADER_FIELD_NUMBER: builtins.int
+ SEND_STREAM_CHUNK_FIELD_NUMBER: builtins.int
+ SEND_STREAM_TRAILER_FIELD_NUMBER: builtins.int
+ SET_DATA_CHANNEL_BUFFERED_AMOUNT_LOW_THRESHOLD_FIELD_NUMBER: builtins.int
+ LOAD_AUDIO_FILTER_PLUGIN_FIELD_NUMBER: builtins.int
+ NEW_APM_FIELD_NUMBER: builtins.int
+ APM_PROCESS_STREAM_FIELD_NUMBER: builtins.int
+ APM_PROCESS_REVERSE_STREAM_FIELD_NUMBER: builtins.int
+ APM_SET_STREAM_DELAY_FIELD_NUMBER: builtins.int
+ BYTE_READ_INCREMENTAL_FIELD_NUMBER: builtins.int
+ BYTE_READ_ALL_FIELD_NUMBER: builtins.int
+ BYTE_WRITE_TO_FILE_FIELD_NUMBER: builtins.int
+ TEXT_READ_INCREMENTAL_FIELD_NUMBER: builtins.int
+ TEXT_READ_ALL_FIELD_NUMBER: builtins.int
+ SEND_FILE_FIELD_NUMBER: builtins.int
+ SEND_TEXT_FIELD_NUMBER: builtins.int
+ BYTE_STREAM_OPEN_FIELD_NUMBER: builtins.int
+ BYTE_STREAM_WRITE_FIELD_NUMBER: builtins.int
+ BYTE_STREAM_CLOSE_FIELD_NUMBER: builtins.int
+ TEXT_STREAM_OPEN_FIELD_NUMBER: builtins.int
+ TEXT_STREAM_WRITE_FIELD_NUMBER: builtins.int
+ TEXT_STREAM_CLOSE_FIELD_NUMBER: builtins.int
+ SEND_BYTES_FIELD_NUMBER: builtins.int
+ SET_REMOTE_TRACK_PUBLICATION_QUALITY_FIELD_NUMBER: builtins.int
+ PUBLISH_DATA_TRACK_FIELD_NUMBER: builtins.int
+ LOCAL_DATA_TRACK_TRY_PUSH_FIELD_NUMBER: builtins.int
+ LOCAL_DATA_TRACK_UNPUBLISH_FIELD_NUMBER: builtins.int
+ LOCAL_DATA_TRACK_IS_PUBLISHED_FIELD_NUMBER: builtins.int
+ SUBSCRIBE_DATA_TRACK_FIELD_NUMBER: builtins.int
+ REMOTE_DATA_TRACK_IS_PUBLISHED_FIELD_NUMBER: builtins.int
+ DATA_TRACK_STREAM_READ_FIELD_NUMBER: builtins.int
@property
def dispose(self) -> global___DisposeRequest: ...
@property
def connect(self) -> room_pb2.ConnectRequest:
"""Room"""
+
@property
def disconnect(self) -> room_pb2.DisconnectRequest: ...
@property
@@ -131,23 +187,35 @@ class FfiRequest(google.protobuf.message.Message):
@property
def set_subscribed(self) -> room_pb2.SetSubscribedRequest: ...
@property
- def update_local_metadata(self) -> room_pb2.UpdateLocalMetadataRequest: ...
+ def set_local_metadata(self) -> room_pb2.SetLocalMetadataRequest: ...
+ @property
+ def set_local_name(self) -> room_pb2.SetLocalNameRequest: ...
@property
- def update_local_name(self) -> room_pb2.UpdateLocalNameRequest: ...
+ def set_local_attributes(self) -> room_pb2.SetLocalAttributesRequest: ...
@property
def get_session_stats(self) -> room_pb2.GetSessionStatsRequest: ...
@property
def publish_transcription(self) -> room_pb2.PublishTranscriptionRequest: ...
@property
+ def publish_sip_dtmf(self) -> room_pb2.PublishSipDtmfRequest: ...
+ @property
def create_video_track(self) -> track_pb2.CreateVideoTrackRequest:
"""Track"""
+
@property
def create_audio_track(self) -> track_pb2.CreateAudioTrackRequest: ...
@property
+ def local_track_mute(self) -> track_pb2.LocalTrackMuteRequest: ...
+ @property
+ def enable_remote_track(self) -> track_pb2.EnableRemoteTrackRequest: ...
+ @property
def get_stats(self) -> track_pb2.GetStatsRequest: ...
@property
+ def set_track_subscription_permissions(self) -> track_pb2.SetTrackSubscriptionPermissionsRequest: ...
+ @property
def new_video_stream(self) -> video_frame_pb2.NewVideoStreamRequest:
"""Video"""
+
@property
def new_video_source(self) -> video_frame_pb2.NewVideoSourceRequest: ...
@property
@@ -155,18 +223,125 @@ class FfiRequest(google.protobuf.message.Message):
@property
def video_convert(self) -> video_frame_pb2.VideoConvertRequest: ...
@property
+ def video_stream_from_participant(self) -> video_frame_pb2.VideoStreamFromParticipantRequest: ...
+ @property
def new_audio_stream(self) -> audio_frame_pb2.NewAudioStreamRequest:
"""Audio"""
+
@property
def new_audio_source(self) -> audio_frame_pb2.NewAudioSourceRequest: ...
@property
def capture_audio_frame(self) -> audio_frame_pb2.CaptureAudioFrameRequest: ...
@property
+ def clear_audio_buffer(self) -> audio_frame_pb2.ClearAudioBufferRequest: ...
+ @property
def new_audio_resampler(self) -> audio_frame_pb2.NewAudioResamplerRequest: ...
@property
def remix_and_resample(self) -> audio_frame_pb2.RemixAndResampleRequest: ...
@property
def e2ee(self) -> e2ee_pb2.E2eeRequest: ...
+ @property
+ def audio_stream_from_participant(self) -> audio_frame_pb2.AudioStreamFromParticipantRequest: ...
+ @property
+ def new_sox_resampler(self) -> audio_frame_pb2.NewSoxResamplerRequest: ...
+ @property
+ def push_sox_resampler(self) -> audio_frame_pb2.PushSoxResamplerRequest: ...
+ @property
+ def flush_sox_resampler(self) -> audio_frame_pb2.FlushSoxResamplerRequest: ...
+ @property
+ def send_chat_message(self) -> room_pb2.SendChatMessageRequest: ...
+ @property
+ def edit_chat_message(self) -> room_pb2.EditChatMessageRequest: ...
+ @property
+ def perform_rpc(self) -> rpc_pb2.PerformRpcRequest:
+ """RPC"""
+
+ @property
+ def register_rpc_method(self) -> rpc_pb2.RegisterRpcMethodRequest: ...
+ @property
+ def unregister_rpc_method(self) -> rpc_pb2.UnregisterRpcMethodRequest: ...
+ @property
+ def rpc_method_invocation_response(self) -> rpc_pb2.RpcMethodInvocationResponseRequest: ...
+ @property
+ def enable_remote_track_publication(self) -> track_publication_pb2.EnableRemoteTrackPublicationRequest:
+ """Track Publication"""
+
+ @property
+ def update_remote_track_publication_dimension(self) -> track_publication_pb2.UpdateRemoteTrackPublicationDimensionRequest: ...
+ @property
+ def send_stream_header(self) -> room_pb2.SendStreamHeaderRequest:
+ """Data Streams (low level)"""
+
+ @property
+ def send_stream_chunk(self) -> room_pb2.SendStreamChunkRequest: ...
+ @property
+ def send_stream_trailer(self) -> room_pb2.SendStreamTrailerRequest: ...
+ @property
+ def set_data_channel_buffered_amount_low_threshold(self) -> room_pb2.SetDataChannelBufferedAmountLowThresholdRequest:
+ """Data Channel"""
+
+ @property
+ def load_audio_filter_plugin(self) -> audio_frame_pb2.LoadAudioFilterPluginRequest:
+ """Audio Filter Plugin"""
+
+ @property
+ def new_apm(self) -> audio_frame_pb2.NewApmRequest: ...
+ @property
+ def apm_process_stream(self) -> audio_frame_pb2.ApmProcessStreamRequest: ...
+ @property
+ def apm_process_reverse_stream(self) -> audio_frame_pb2.ApmProcessReverseStreamRequest: ...
+ @property
+ def apm_set_stream_delay(self) -> audio_frame_pb2.ApmSetStreamDelayRequest: ...
+ @property
+ def byte_read_incremental(self) -> data_stream_pb2.ByteStreamReaderReadIncrementalRequest:
+ """Data Streams (high level)"""
+
+ @property
+ def byte_read_all(self) -> data_stream_pb2.ByteStreamReaderReadAllRequest: ...
+ @property
+ def byte_write_to_file(self) -> data_stream_pb2.ByteStreamReaderWriteToFileRequest: ...
+ @property
+ def text_read_incremental(self) -> data_stream_pb2.TextStreamReaderReadIncrementalRequest: ...
+ @property
+ def text_read_all(self) -> data_stream_pb2.TextStreamReaderReadAllRequest: ...
+ @property
+ def send_file(self) -> data_stream_pb2.StreamSendFileRequest: ...
+ @property
+ def send_text(self) -> data_stream_pb2.StreamSendTextRequest: ...
+ @property
+ def byte_stream_open(self) -> data_stream_pb2.ByteStreamOpenRequest: ...
+ @property
+ def byte_stream_write(self) -> data_stream_pb2.ByteStreamWriterWriteRequest: ...
+ @property
+ def byte_stream_close(self) -> data_stream_pb2.ByteStreamWriterCloseRequest: ...
+ @property
+ def text_stream_open(self) -> data_stream_pb2.TextStreamOpenRequest: ...
+ @property
+ def text_stream_write(self) -> data_stream_pb2.TextStreamWriterWriteRequest: ...
+ @property
+ def text_stream_close(self) -> data_stream_pb2.TextStreamWriterCloseRequest: ...
+ @property
+ def send_bytes(self) -> data_stream_pb2.StreamSendBytesRequest: ...
+ @property
+ def set_remote_track_publication_quality(self) -> track_publication_pb2.SetRemoteTrackPublicationQualityRequest: ...
+ @property
+ def publish_data_track(self) -> data_track_pb2.PublishDataTrackRequest:
+ """Data Track (local)"""
+
+ @property
+ def local_data_track_try_push(self) -> data_track_pb2.LocalDataTrackTryPushRequest: ...
+ @property
+ def local_data_track_unpublish(self) -> data_track_pb2.LocalDataTrackUnpublishRequest: ...
+ @property
+ def local_data_track_is_published(self) -> data_track_pb2.LocalDataTrackIsPublishedRequest: ...
+ @property
+ def subscribe_data_track(self) -> data_track_pb2.SubscribeDataTrackRequest:
+ """Data Track (remote)"""
+
+ @property
+ def remote_data_track_is_published(self) -> data_track_pb2.RemoteDataTrackIsPublishedRequest: ...
+ @property
+ def data_track_stream_read(self) -> data_track_pb2.DataTrackStreamReadRequest: ...
def __init__(
self,
*,
@@ -177,31 +352,81 @@ class FfiRequest(google.protobuf.message.Message):
unpublish_track: room_pb2.UnpublishTrackRequest | None = ...,
publish_data: room_pb2.PublishDataRequest | None = ...,
set_subscribed: room_pb2.SetSubscribedRequest | None = ...,
- update_local_metadata: room_pb2.UpdateLocalMetadataRequest | None = ...,
- update_local_name: room_pb2.UpdateLocalNameRequest | None = ...,
+ set_local_metadata: room_pb2.SetLocalMetadataRequest | None = ...,
+ set_local_name: room_pb2.SetLocalNameRequest | None = ...,
+ set_local_attributes: room_pb2.SetLocalAttributesRequest | None = ...,
get_session_stats: room_pb2.GetSessionStatsRequest | None = ...,
publish_transcription: room_pb2.PublishTranscriptionRequest | None = ...,
+ publish_sip_dtmf: room_pb2.PublishSipDtmfRequest | None = ...,
create_video_track: track_pb2.CreateVideoTrackRequest | None = ...,
create_audio_track: track_pb2.CreateAudioTrackRequest | None = ...,
+ local_track_mute: track_pb2.LocalTrackMuteRequest | None = ...,
+ enable_remote_track: track_pb2.EnableRemoteTrackRequest | None = ...,
get_stats: track_pb2.GetStatsRequest | None = ...,
+ set_track_subscription_permissions: track_pb2.SetTrackSubscriptionPermissionsRequest | None = ...,
new_video_stream: video_frame_pb2.NewVideoStreamRequest | None = ...,
new_video_source: video_frame_pb2.NewVideoSourceRequest | None = ...,
capture_video_frame: video_frame_pb2.CaptureVideoFrameRequest | None = ...,
video_convert: video_frame_pb2.VideoConvertRequest | None = ...,
+ video_stream_from_participant: video_frame_pb2.VideoStreamFromParticipantRequest | None = ...,
new_audio_stream: audio_frame_pb2.NewAudioStreamRequest | None = ...,
new_audio_source: audio_frame_pb2.NewAudioSourceRequest | None = ...,
capture_audio_frame: audio_frame_pb2.CaptureAudioFrameRequest | None = ...,
+ clear_audio_buffer: audio_frame_pb2.ClearAudioBufferRequest | None = ...,
new_audio_resampler: audio_frame_pb2.NewAudioResamplerRequest | None = ...,
remix_and_resample: audio_frame_pb2.RemixAndResampleRequest | None = ...,
e2ee: e2ee_pb2.E2eeRequest | None = ...,
+ audio_stream_from_participant: audio_frame_pb2.AudioStreamFromParticipantRequest | None = ...,
+ new_sox_resampler: audio_frame_pb2.NewSoxResamplerRequest | None = ...,
+ push_sox_resampler: audio_frame_pb2.PushSoxResamplerRequest | None = ...,
+ flush_sox_resampler: audio_frame_pb2.FlushSoxResamplerRequest | None = ...,
+ send_chat_message: room_pb2.SendChatMessageRequest | None = ...,
+ edit_chat_message: room_pb2.EditChatMessageRequest | None = ...,
+ perform_rpc: rpc_pb2.PerformRpcRequest | None = ...,
+ register_rpc_method: rpc_pb2.RegisterRpcMethodRequest | None = ...,
+ unregister_rpc_method: rpc_pb2.UnregisterRpcMethodRequest | None = ...,
+ rpc_method_invocation_response: rpc_pb2.RpcMethodInvocationResponseRequest | None = ...,
+ enable_remote_track_publication: track_publication_pb2.EnableRemoteTrackPublicationRequest | None = ...,
+ update_remote_track_publication_dimension: track_publication_pb2.UpdateRemoteTrackPublicationDimensionRequest | None = ...,
+ send_stream_header: room_pb2.SendStreamHeaderRequest | None = ...,
+ send_stream_chunk: room_pb2.SendStreamChunkRequest | None = ...,
+ send_stream_trailer: room_pb2.SendStreamTrailerRequest | None = ...,
+ set_data_channel_buffered_amount_low_threshold: room_pb2.SetDataChannelBufferedAmountLowThresholdRequest | None = ...,
+ load_audio_filter_plugin: audio_frame_pb2.LoadAudioFilterPluginRequest | None = ...,
+ new_apm: audio_frame_pb2.NewApmRequest | None = ...,
+ apm_process_stream: audio_frame_pb2.ApmProcessStreamRequest | None = ...,
+ apm_process_reverse_stream: audio_frame_pb2.ApmProcessReverseStreamRequest | None = ...,
+ apm_set_stream_delay: audio_frame_pb2.ApmSetStreamDelayRequest | None = ...,
+ byte_read_incremental: data_stream_pb2.ByteStreamReaderReadIncrementalRequest | None = ...,
+ byte_read_all: data_stream_pb2.ByteStreamReaderReadAllRequest | None = ...,
+ byte_write_to_file: data_stream_pb2.ByteStreamReaderWriteToFileRequest | None = ...,
+ text_read_incremental: data_stream_pb2.TextStreamReaderReadIncrementalRequest | None = ...,
+ text_read_all: data_stream_pb2.TextStreamReaderReadAllRequest | None = ...,
+ send_file: data_stream_pb2.StreamSendFileRequest | None = ...,
+ send_text: data_stream_pb2.StreamSendTextRequest | None = ...,
+ byte_stream_open: data_stream_pb2.ByteStreamOpenRequest | None = ...,
+ byte_stream_write: data_stream_pb2.ByteStreamWriterWriteRequest | None = ...,
+ byte_stream_close: data_stream_pb2.ByteStreamWriterCloseRequest | None = ...,
+ text_stream_open: data_stream_pb2.TextStreamOpenRequest | None = ...,
+ text_stream_write: data_stream_pb2.TextStreamWriterWriteRequest | None = ...,
+ text_stream_close: data_stream_pb2.TextStreamWriterCloseRequest | None = ...,
+ send_bytes: data_stream_pb2.StreamSendBytesRequest | None = ...,
+ set_remote_track_publication_quality: track_publication_pb2.SetRemoteTrackPublicationQualityRequest | None = ...,
+ publish_data_track: data_track_pb2.PublishDataTrackRequest | None = ...,
+ local_data_track_try_push: data_track_pb2.LocalDataTrackTryPushRequest | None = ...,
+ local_data_track_unpublish: data_track_pb2.LocalDataTrackUnpublishRequest | None = ...,
+ local_data_track_is_published: data_track_pb2.LocalDataTrackIsPublishedRequest | None = ...,
+ subscribe_data_track: data_track_pb2.SubscribeDataTrackRequest | None = ...,
+ remote_data_track_is_published: data_track_pb2.RemoteDataTrackIsPublishedRequest | None = ...,
+ data_track_stream_read: data_track_pb2.DataTrackStreamReadRequest | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["capture_audio_frame", b"capture_audio_frame", "capture_video_frame", b"capture_video_frame", "connect", b"connect", "create_audio_track", b"create_audio_track", "create_video_track", b"create_video_track", "disconnect", b"disconnect", "dispose", b"dispose", "e2ee", b"e2ee", "get_session_stats", b"get_session_stats", "get_stats", b"get_stats", "message", b"message", "new_audio_resampler", b"new_audio_resampler", "new_audio_source", b"new_audio_source", "new_audio_stream", b"new_audio_stream", "new_video_source", b"new_video_source", "new_video_stream", b"new_video_stream", "publish_data", b"publish_data", "publish_track", b"publish_track", "publish_transcription", b"publish_transcription", "remix_and_resample", b"remix_and_resample", "set_subscribed", b"set_subscribed", "unpublish_track", b"unpublish_track", "update_local_metadata", b"update_local_metadata", "update_local_name", b"update_local_name", "video_convert", b"video_convert"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["capture_audio_frame", b"capture_audio_frame", "capture_video_frame", b"capture_video_frame", "connect", b"connect", "create_audio_track", b"create_audio_track", "create_video_track", b"create_video_track", "disconnect", b"disconnect", "dispose", b"dispose", "e2ee", b"e2ee", "get_session_stats", b"get_session_stats", "get_stats", b"get_stats", "message", b"message", "new_audio_resampler", b"new_audio_resampler", "new_audio_source", b"new_audio_source", "new_audio_stream", b"new_audio_stream", "new_video_source", b"new_video_source", "new_video_stream", b"new_video_stream", "publish_data", b"publish_data", "publish_track", b"publish_track", "publish_transcription", b"publish_transcription", "remix_and_resample", b"remix_and_resample", "set_subscribed", b"set_subscribed", "unpublish_track", b"unpublish_track", "update_local_metadata", b"update_local_metadata", "update_local_name", b"update_local_name", "video_convert", b"video_convert"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["message", b"message"]) -> typing_extensions.Literal["dispose", "connect", "disconnect", "publish_track", "unpublish_track", "publish_data", "set_subscribed", "update_local_metadata", "update_local_name", "get_session_stats", "publish_transcription", "create_video_track", "create_audio_track", "get_stats", "new_video_stream", "new_video_source", "capture_video_frame", "video_convert", "new_audio_stream", "new_audio_source", "capture_audio_frame", "new_audio_resampler", "remix_and_resample", "e2ee"] | None: ...
+ def HasField(self, field_name: typing.Literal["apm_process_reverse_stream", b"apm_process_reverse_stream", "apm_process_stream", b"apm_process_stream", "apm_set_stream_delay", b"apm_set_stream_delay", "audio_stream_from_participant", b"audio_stream_from_participant", "byte_read_all", b"byte_read_all", "byte_read_incremental", b"byte_read_incremental", "byte_stream_close", b"byte_stream_close", "byte_stream_open", b"byte_stream_open", "byte_stream_write", b"byte_stream_write", "byte_write_to_file", b"byte_write_to_file", "capture_audio_frame", b"capture_audio_frame", "capture_video_frame", b"capture_video_frame", "clear_audio_buffer", b"clear_audio_buffer", "connect", b"connect", "create_audio_track", b"create_audio_track", "create_video_track", b"create_video_track", "data_track_stream_read", b"data_track_stream_read", "disconnect", b"disconnect", "dispose", b"dispose", "e2ee", b"e2ee", "edit_chat_message", b"edit_chat_message", "enable_remote_track", b"enable_remote_track", "enable_remote_track_publication", b"enable_remote_track_publication", "flush_sox_resampler", b"flush_sox_resampler", "get_session_stats", b"get_session_stats", "get_stats", b"get_stats", "load_audio_filter_plugin", b"load_audio_filter_plugin", "local_data_track_is_published", b"local_data_track_is_published", "local_data_track_try_push", b"local_data_track_try_push", "local_data_track_unpublish", b"local_data_track_unpublish", "local_track_mute", b"local_track_mute", "message", b"message", "new_apm", b"new_apm", "new_audio_resampler", b"new_audio_resampler", "new_audio_source", b"new_audio_source", "new_audio_stream", b"new_audio_stream", "new_sox_resampler", b"new_sox_resampler", "new_video_source", b"new_video_source", "new_video_stream", b"new_video_stream", "perform_rpc", b"perform_rpc", "publish_data", b"publish_data", "publish_data_track", b"publish_data_track", "publish_sip_dtmf", b"publish_sip_dtmf", "publish_track", b"publish_track", "publish_transcription", b"publish_transcription", "push_sox_resampler", b"push_sox_resampler", "register_rpc_method", b"register_rpc_method", "remix_and_resample", b"remix_and_resample", "remote_data_track_is_published", b"remote_data_track_is_published", "rpc_method_invocation_response", b"rpc_method_invocation_response", "send_bytes", b"send_bytes", "send_chat_message", b"send_chat_message", "send_file", b"send_file", "send_stream_chunk", b"send_stream_chunk", "send_stream_header", b"send_stream_header", "send_stream_trailer", b"send_stream_trailer", "send_text", b"send_text", "set_data_channel_buffered_amount_low_threshold", b"set_data_channel_buffered_amount_low_threshold", "set_local_attributes", b"set_local_attributes", "set_local_metadata", b"set_local_metadata", "set_local_name", b"set_local_name", "set_remote_track_publication_quality", b"set_remote_track_publication_quality", "set_subscribed", b"set_subscribed", "set_track_subscription_permissions", b"set_track_subscription_permissions", "subscribe_data_track", b"subscribe_data_track", "text_read_all", b"text_read_all", "text_read_incremental", b"text_read_incremental", "text_stream_close", b"text_stream_close", "text_stream_open", b"text_stream_open", "text_stream_write", b"text_stream_write", "unpublish_track", b"unpublish_track", "unregister_rpc_method", b"unregister_rpc_method", "update_remote_track_publication_dimension", b"update_remote_track_publication_dimension", "video_convert", b"video_convert", "video_stream_from_participant", b"video_stream_from_participant"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["apm_process_reverse_stream", b"apm_process_reverse_stream", "apm_process_stream", b"apm_process_stream", "apm_set_stream_delay", b"apm_set_stream_delay", "audio_stream_from_participant", b"audio_stream_from_participant", "byte_read_all", b"byte_read_all", "byte_read_incremental", b"byte_read_incremental", "byte_stream_close", b"byte_stream_close", "byte_stream_open", b"byte_stream_open", "byte_stream_write", b"byte_stream_write", "byte_write_to_file", b"byte_write_to_file", "capture_audio_frame", b"capture_audio_frame", "capture_video_frame", b"capture_video_frame", "clear_audio_buffer", b"clear_audio_buffer", "connect", b"connect", "create_audio_track", b"create_audio_track", "create_video_track", b"create_video_track", "data_track_stream_read", b"data_track_stream_read", "disconnect", b"disconnect", "dispose", b"dispose", "e2ee", b"e2ee", "edit_chat_message", b"edit_chat_message", "enable_remote_track", b"enable_remote_track", "enable_remote_track_publication", b"enable_remote_track_publication", "flush_sox_resampler", b"flush_sox_resampler", "get_session_stats", b"get_session_stats", "get_stats", b"get_stats", "load_audio_filter_plugin", b"load_audio_filter_plugin", "local_data_track_is_published", b"local_data_track_is_published", "local_data_track_try_push", b"local_data_track_try_push", "local_data_track_unpublish", b"local_data_track_unpublish", "local_track_mute", b"local_track_mute", "message", b"message", "new_apm", b"new_apm", "new_audio_resampler", b"new_audio_resampler", "new_audio_source", b"new_audio_source", "new_audio_stream", b"new_audio_stream", "new_sox_resampler", b"new_sox_resampler", "new_video_source", b"new_video_source", "new_video_stream", b"new_video_stream", "perform_rpc", b"perform_rpc", "publish_data", b"publish_data", "publish_data_track", b"publish_data_track", "publish_sip_dtmf", b"publish_sip_dtmf", "publish_track", b"publish_track", "publish_transcription", b"publish_transcription", "push_sox_resampler", b"push_sox_resampler", "register_rpc_method", b"register_rpc_method", "remix_and_resample", b"remix_and_resample", "remote_data_track_is_published", b"remote_data_track_is_published", "rpc_method_invocation_response", b"rpc_method_invocation_response", "send_bytes", b"send_bytes", "send_chat_message", b"send_chat_message", "send_file", b"send_file", "send_stream_chunk", b"send_stream_chunk", "send_stream_header", b"send_stream_header", "send_stream_trailer", b"send_stream_trailer", "send_text", b"send_text", "set_data_channel_buffered_amount_low_threshold", b"set_data_channel_buffered_amount_low_threshold", "set_local_attributes", b"set_local_attributes", "set_local_metadata", b"set_local_metadata", "set_local_name", b"set_local_name", "set_remote_track_publication_quality", b"set_remote_track_publication_quality", "set_subscribed", b"set_subscribed", "set_track_subscription_permissions", b"set_track_subscription_permissions", "subscribe_data_track", b"subscribe_data_track", "text_read_all", b"text_read_all", "text_read_incremental", b"text_read_incremental", "text_stream_close", b"text_stream_close", "text_stream_open", b"text_stream_open", "text_stream_write", b"text_stream_write", "unpublish_track", b"unpublish_track", "unregister_rpc_method", b"unregister_rpc_method", "update_remote_track_publication_dimension", b"update_remote_track_publication_dimension", "video_convert", b"video_convert", "video_stream_from_participant", b"video_stream_from_participant"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["message", b"message"]) -> typing.Literal["dispose", "connect", "disconnect", "publish_track", "unpublish_track", "publish_data", "set_subscribed", "set_local_metadata", "set_local_name", "set_local_attributes", "get_session_stats", "publish_transcription", "publish_sip_dtmf", "create_video_track", "create_audio_track", "local_track_mute", "enable_remote_track", "get_stats", "set_track_subscription_permissions", "new_video_stream", "new_video_source", "capture_video_frame", "video_convert", "video_stream_from_participant", "new_audio_stream", "new_audio_source", "capture_audio_frame", "clear_audio_buffer", "new_audio_resampler", "remix_and_resample", "e2ee", "audio_stream_from_participant", "new_sox_resampler", "push_sox_resampler", "flush_sox_resampler", "send_chat_message", "edit_chat_message", "perform_rpc", "register_rpc_method", "unregister_rpc_method", "rpc_method_invocation_response", "enable_remote_track_publication", "update_remote_track_publication_dimension", "send_stream_header", "send_stream_chunk", "send_stream_trailer", "set_data_channel_buffered_amount_low_threshold", "load_audio_filter_plugin", "new_apm", "apm_process_stream", "apm_process_reverse_stream", "apm_set_stream_delay", "byte_read_incremental", "byte_read_all", "byte_write_to_file", "text_read_incremental", "text_read_all", "send_file", "send_text", "byte_stream_open", "byte_stream_write", "byte_stream_close", "text_stream_open", "text_stream_write", "text_stream_close", "send_bytes", "set_remote_track_publication_quality", "publish_data_track", "local_data_track_try_push", "local_data_track_unpublish", "local_data_track_is_published", "subscribe_data_track", "remote_data_track_is_published", "data_track_stream_read"] | None: ...
global___FfiRequest = FfiRequest
-@typing_extensions.final
+@typing.final
class FfiResponse(google.protobuf.message.Message):
"""This is the output of livekit_ffi_request function."""
@@ -214,28 +439,78 @@ class FfiResponse(google.protobuf.message.Message):
UNPUBLISH_TRACK_FIELD_NUMBER: builtins.int
PUBLISH_DATA_FIELD_NUMBER: builtins.int
SET_SUBSCRIBED_FIELD_NUMBER: builtins.int
- UPDATE_LOCAL_METADATA_FIELD_NUMBER: builtins.int
- UPDATE_LOCAL_NAME_FIELD_NUMBER: builtins.int
+ SET_LOCAL_METADATA_FIELD_NUMBER: builtins.int
+ SET_LOCAL_NAME_FIELD_NUMBER: builtins.int
+ SET_LOCAL_ATTRIBUTES_FIELD_NUMBER: builtins.int
GET_SESSION_STATS_FIELD_NUMBER: builtins.int
PUBLISH_TRANSCRIPTION_FIELD_NUMBER: builtins.int
+ PUBLISH_SIP_DTMF_FIELD_NUMBER: builtins.int
CREATE_VIDEO_TRACK_FIELD_NUMBER: builtins.int
CREATE_AUDIO_TRACK_FIELD_NUMBER: builtins.int
+ LOCAL_TRACK_MUTE_FIELD_NUMBER: builtins.int
+ ENABLE_REMOTE_TRACK_FIELD_NUMBER: builtins.int
GET_STATS_FIELD_NUMBER: builtins.int
+ SET_TRACK_SUBSCRIPTION_PERMISSIONS_FIELD_NUMBER: builtins.int
NEW_VIDEO_STREAM_FIELD_NUMBER: builtins.int
NEW_VIDEO_SOURCE_FIELD_NUMBER: builtins.int
CAPTURE_VIDEO_FRAME_FIELD_NUMBER: builtins.int
VIDEO_CONVERT_FIELD_NUMBER: builtins.int
+ VIDEO_STREAM_FROM_PARTICIPANT_FIELD_NUMBER: builtins.int
NEW_AUDIO_STREAM_FIELD_NUMBER: builtins.int
NEW_AUDIO_SOURCE_FIELD_NUMBER: builtins.int
CAPTURE_AUDIO_FRAME_FIELD_NUMBER: builtins.int
+ CLEAR_AUDIO_BUFFER_FIELD_NUMBER: builtins.int
NEW_AUDIO_RESAMPLER_FIELD_NUMBER: builtins.int
REMIX_AND_RESAMPLE_FIELD_NUMBER: builtins.int
+ AUDIO_STREAM_FROM_PARTICIPANT_FIELD_NUMBER: builtins.int
E2EE_FIELD_NUMBER: builtins.int
+ NEW_SOX_RESAMPLER_FIELD_NUMBER: builtins.int
+ PUSH_SOX_RESAMPLER_FIELD_NUMBER: builtins.int
+ FLUSH_SOX_RESAMPLER_FIELD_NUMBER: builtins.int
+ SEND_CHAT_MESSAGE_FIELD_NUMBER: builtins.int
+ PERFORM_RPC_FIELD_NUMBER: builtins.int
+ REGISTER_RPC_METHOD_FIELD_NUMBER: builtins.int
+ UNREGISTER_RPC_METHOD_FIELD_NUMBER: builtins.int
+ RPC_METHOD_INVOCATION_RESPONSE_FIELD_NUMBER: builtins.int
+ ENABLE_REMOTE_TRACK_PUBLICATION_FIELD_NUMBER: builtins.int
+ UPDATE_REMOTE_TRACK_PUBLICATION_DIMENSION_FIELD_NUMBER: builtins.int
+ SEND_STREAM_HEADER_FIELD_NUMBER: builtins.int
+ SEND_STREAM_CHUNK_FIELD_NUMBER: builtins.int
+ SEND_STREAM_TRAILER_FIELD_NUMBER: builtins.int
+ SET_DATA_CHANNEL_BUFFERED_AMOUNT_LOW_THRESHOLD_FIELD_NUMBER: builtins.int
+ LOAD_AUDIO_FILTER_PLUGIN_FIELD_NUMBER: builtins.int
+ NEW_APM_FIELD_NUMBER: builtins.int
+ APM_PROCESS_STREAM_FIELD_NUMBER: builtins.int
+ APM_PROCESS_REVERSE_STREAM_FIELD_NUMBER: builtins.int
+ APM_SET_STREAM_DELAY_FIELD_NUMBER: builtins.int
+ BYTE_READ_INCREMENTAL_FIELD_NUMBER: builtins.int
+ BYTE_READ_ALL_FIELD_NUMBER: builtins.int
+ BYTE_WRITE_TO_FILE_FIELD_NUMBER: builtins.int
+ TEXT_READ_INCREMENTAL_FIELD_NUMBER: builtins.int
+ TEXT_READ_ALL_FIELD_NUMBER: builtins.int
+ SEND_FILE_FIELD_NUMBER: builtins.int
+ SEND_TEXT_FIELD_NUMBER: builtins.int
+ BYTE_STREAM_OPEN_FIELD_NUMBER: builtins.int
+ BYTE_STREAM_WRITE_FIELD_NUMBER: builtins.int
+ BYTE_STREAM_CLOSE_FIELD_NUMBER: builtins.int
+ TEXT_STREAM_OPEN_FIELD_NUMBER: builtins.int
+ TEXT_STREAM_WRITE_FIELD_NUMBER: builtins.int
+ TEXT_STREAM_CLOSE_FIELD_NUMBER: builtins.int
+ SEND_BYTES_FIELD_NUMBER: builtins.int
+ SET_REMOTE_TRACK_PUBLICATION_QUALITY_FIELD_NUMBER: builtins.int
+ PUBLISH_DATA_TRACK_FIELD_NUMBER: builtins.int
+ LOCAL_DATA_TRACK_TRY_PUSH_FIELD_NUMBER: builtins.int
+ LOCAL_DATA_TRACK_UNPUBLISH_FIELD_NUMBER: builtins.int
+ LOCAL_DATA_TRACK_IS_PUBLISHED_FIELD_NUMBER: builtins.int
+ SUBSCRIBE_DATA_TRACK_FIELD_NUMBER: builtins.int
+ REMOTE_DATA_TRACK_IS_PUBLISHED_FIELD_NUMBER: builtins.int
+ DATA_TRACK_STREAM_READ_FIELD_NUMBER: builtins.int
@property
def dispose(self) -> global___DisposeResponse: ...
@property
def connect(self) -> room_pb2.ConnectResponse:
"""Room"""
+
@property
def disconnect(self) -> room_pb2.DisconnectResponse: ...
@property
@@ -247,23 +522,35 @@ class FfiResponse(google.protobuf.message.Message):
@property
def set_subscribed(self) -> room_pb2.SetSubscribedResponse: ...
@property
- def update_local_metadata(self) -> room_pb2.UpdateLocalMetadataResponse: ...
+ def set_local_metadata(self) -> room_pb2.SetLocalMetadataResponse: ...
+ @property
+ def set_local_name(self) -> room_pb2.SetLocalNameResponse: ...
@property
- def update_local_name(self) -> room_pb2.UpdateLocalNameResponse: ...
+ def set_local_attributes(self) -> room_pb2.SetLocalAttributesResponse: ...
@property
def get_session_stats(self) -> room_pb2.GetSessionStatsResponse: ...
@property
def publish_transcription(self) -> room_pb2.PublishTranscriptionResponse: ...
@property
+ def publish_sip_dtmf(self) -> room_pb2.PublishSipDtmfResponse: ...
+ @property
def create_video_track(self) -> track_pb2.CreateVideoTrackResponse:
"""Track"""
+
@property
def create_audio_track(self) -> track_pb2.CreateAudioTrackResponse: ...
@property
+ def local_track_mute(self) -> track_pb2.LocalTrackMuteResponse: ...
+ @property
+ def enable_remote_track(self) -> track_pb2.EnableRemoteTrackResponse: ...
+ @property
def get_stats(self) -> track_pb2.GetStatsResponse: ...
@property
+ def set_track_subscription_permissions(self) -> track_pb2.SetTrackSubscriptionPermissionsResponse: ...
+ @property
def new_video_stream(self) -> video_frame_pb2.NewVideoStreamResponse:
"""Video"""
+
@property
def new_video_source(self) -> video_frame_pb2.NewVideoSourceResponse: ...
@property
@@ -271,18 +558,123 @@ class FfiResponse(google.protobuf.message.Message):
@property
def video_convert(self) -> video_frame_pb2.VideoConvertResponse: ...
@property
+ def video_stream_from_participant(self) -> video_frame_pb2.VideoStreamFromParticipantResponse: ...
+ @property
def new_audio_stream(self) -> audio_frame_pb2.NewAudioStreamResponse:
"""Audio"""
+
@property
def new_audio_source(self) -> audio_frame_pb2.NewAudioSourceResponse: ...
@property
def capture_audio_frame(self) -> audio_frame_pb2.CaptureAudioFrameResponse: ...
@property
+ def clear_audio_buffer(self) -> audio_frame_pb2.ClearAudioBufferResponse: ...
+ @property
def new_audio_resampler(self) -> audio_frame_pb2.NewAudioResamplerResponse: ...
@property
def remix_and_resample(self) -> audio_frame_pb2.RemixAndResampleResponse: ...
@property
+ def audio_stream_from_participant(self) -> audio_frame_pb2.AudioStreamFromParticipantResponse: ...
+ @property
def e2ee(self) -> e2ee_pb2.E2eeResponse: ...
+ @property
+ def new_sox_resampler(self) -> audio_frame_pb2.NewSoxResamplerResponse: ...
+ @property
+ def push_sox_resampler(self) -> audio_frame_pb2.PushSoxResamplerResponse: ...
+ @property
+ def flush_sox_resampler(self) -> audio_frame_pb2.FlushSoxResamplerResponse: ...
+ @property
+ def send_chat_message(self) -> room_pb2.SendChatMessageResponse: ...
+ @property
+ def perform_rpc(self) -> rpc_pb2.PerformRpcResponse:
+ """RPC"""
+
+ @property
+ def register_rpc_method(self) -> rpc_pb2.RegisterRpcMethodResponse: ...
+ @property
+ def unregister_rpc_method(self) -> rpc_pb2.UnregisterRpcMethodResponse: ...
+ @property
+ def rpc_method_invocation_response(self) -> rpc_pb2.RpcMethodInvocationResponseResponse: ...
+ @property
+ def enable_remote_track_publication(self) -> track_publication_pb2.EnableRemoteTrackPublicationResponse:
+ """Track Publication"""
+
+ @property
+ def update_remote_track_publication_dimension(self) -> track_publication_pb2.UpdateRemoteTrackPublicationDimensionResponse: ...
+ @property
+ def send_stream_header(self) -> room_pb2.SendStreamHeaderResponse:
+ """Data Streams"""
+
+ @property
+ def send_stream_chunk(self) -> room_pb2.SendStreamChunkResponse: ...
+ @property
+ def send_stream_trailer(self) -> room_pb2.SendStreamTrailerResponse: ...
+ @property
+ def set_data_channel_buffered_amount_low_threshold(self) -> room_pb2.SetDataChannelBufferedAmountLowThresholdResponse:
+ """Data Channel"""
+
+ @property
+ def load_audio_filter_plugin(self) -> audio_frame_pb2.LoadAudioFilterPluginResponse:
+ """Audio Filter Plugin"""
+
+ @property
+ def new_apm(self) -> audio_frame_pb2.NewApmResponse: ...
+ @property
+ def apm_process_stream(self) -> audio_frame_pb2.ApmProcessStreamResponse: ...
+ @property
+ def apm_process_reverse_stream(self) -> audio_frame_pb2.ApmProcessReverseStreamResponse: ...
+ @property
+ def apm_set_stream_delay(self) -> audio_frame_pb2.ApmSetStreamDelayResponse: ...
+ @property
+ def byte_read_incremental(self) -> data_stream_pb2.ByteStreamReaderReadIncrementalResponse:
+ """Data Streams (high level)"""
+
+ @property
+ def byte_read_all(self) -> data_stream_pb2.ByteStreamReaderReadAllResponse: ...
+ @property
+ def byte_write_to_file(self) -> data_stream_pb2.ByteStreamReaderWriteToFileResponse: ...
+ @property
+ def text_read_incremental(self) -> data_stream_pb2.TextStreamReaderReadIncrementalResponse: ...
+ @property
+ def text_read_all(self) -> data_stream_pb2.TextStreamReaderReadAllResponse: ...
+ @property
+ def send_file(self) -> data_stream_pb2.StreamSendFileResponse: ...
+ @property
+ def send_text(self) -> data_stream_pb2.StreamSendTextResponse: ...
+ @property
+ def byte_stream_open(self) -> data_stream_pb2.ByteStreamOpenResponse: ...
+ @property
+ def byte_stream_write(self) -> data_stream_pb2.ByteStreamWriterWriteResponse: ...
+ @property
+ def byte_stream_close(self) -> data_stream_pb2.ByteStreamWriterCloseResponse: ...
+ @property
+ def text_stream_open(self) -> data_stream_pb2.TextStreamOpenResponse: ...
+ @property
+ def text_stream_write(self) -> data_stream_pb2.TextStreamWriterWriteResponse: ...
+ @property
+ def text_stream_close(self) -> data_stream_pb2.TextStreamWriterCloseResponse: ...
+ @property
+ def send_bytes(self) -> data_stream_pb2.StreamSendBytesResponse: ...
+ @property
+ def set_remote_track_publication_quality(self) -> track_publication_pb2.SetRemoteTrackPublicationQualityResponse: ...
+ @property
+ def publish_data_track(self) -> data_track_pb2.PublishDataTrackResponse:
+ """Data Track (local)"""
+
+ @property
+ def local_data_track_try_push(self) -> data_track_pb2.LocalDataTrackTryPushResponse: ...
+ @property
+ def local_data_track_unpublish(self) -> data_track_pb2.LocalDataTrackUnpublishResponse: ...
+ @property
+ def local_data_track_is_published(self) -> data_track_pb2.LocalDataTrackIsPublishedResponse: ...
+ @property
+ def subscribe_data_track(self) -> data_track_pb2.SubscribeDataTrackResponse:
+ """Data Track (remote)"""
+
+ @property
+ def remote_data_track_is_published(self) -> data_track_pb2.RemoteDataTrackIsPublishedResponse: ...
+ @property
+ def data_track_stream_read(self) -> data_track_pb2.DataTrackStreamReadResponse: ...
def __init__(
self,
*,
@@ -293,31 +685,80 @@ class FfiResponse(google.protobuf.message.Message):
unpublish_track: room_pb2.UnpublishTrackResponse | None = ...,
publish_data: room_pb2.PublishDataResponse | None = ...,
set_subscribed: room_pb2.SetSubscribedResponse | None = ...,
- update_local_metadata: room_pb2.UpdateLocalMetadataResponse | None = ...,
- update_local_name: room_pb2.UpdateLocalNameResponse | None = ...,
+ set_local_metadata: room_pb2.SetLocalMetadataResponse | None = ...,
+ set_local_name: room_pb2.SetLocalNameResponse | None = ...,
+ set_local_attributes: room_pb2.SetLocalAttributesResponse | None = ...,
get_session_stats: room_pb2.GetSessionStatsResponse | None = ...,
publish_transcription: room_pb2.PublishTranscriptionResponse | None = ...,
+ publish_sip_dtmf: room_pb2.PublishSipDtmfResponse | None = ...,
create_video_track: track_pb2.CreateVideoTrackResponse | None = ...,
create_audio_track: track_pb2.CreateAudioTrackResponse | None = ...,
+ local_track_mute: track_pb2.LocalTrackMuteResponse | None = ...,
+ enable_remote_track: track_pb2.EnableRemoteTrackResponse | None = ...,
get_stats: track_pb2.GetStatsResponse | None = ...,
+ set_track_subscription_permissions: track_pb2.SetTrackSubscriptionPermissionsResponse | None = ...,
new_video_stream: video_frame_pb2.NewVideoStreamResponse | None = ...,
new_video_source: video_frame_pb2.NewVideoSourceResponse | None = ...,
capture_video_frame: video_frame_pb2.CaptureVideoFrameResponse | None = ...,
video_convert: video_frame_pb2.VideoConvertResponse | None = ...,
+ video_stream_from_participant: video_frame_pb2.VideoStreamFromParticipantResponse | None = ...,
new_audio_stream: audio_frame_pb2.NewAudioStreamResponse | None = ...,
new_audio_source: audio_frame_pb2.NewAudioSourceResponse | None = ...,
capture_audio_frame: audio_frame_pb2.CaptureAudioFrameResponse | None = ...,
+ clear_audio_buffer: audio_frame_pb2.ClearAudioBufferResponse | None = ...,
new_audio_resampler: audio_frame_pb2.NewAudioResamplerResponse | None = ...,
remix_and_resample: audio_frame_pb2.RemixAndResampleResponse | None = ...,
+ audio_stream_from_participant: audio_frame_pb2.AudioStreamFromParticipantResponse | None = ...,
e2ee: e2ee_pb2.E2eeResponse | None = ...,
+ new_sox_resampler: audio_frame_pb2.NewSoxResamplerResponse | None = ...,
+ push_sox_resampler: audio_frame_pb2.PushSoxResamplerResponse | None = ...,
+ flush_sox_resampler: audio_frame_pb2.FlushSoxResamplerResponse | None = ...,
+ send_chat_message: room_pb2.SendChatMessageResponse | None = ...,
+ perform_rpc: rpc_pb2.PerformRpcResponse | None = ...,
+ register_rpc_method: rpc_pb2.RegisterRpcMethodResponse | None = ...,
+ unregister_rpc_method: rpc_pb2.UnregisterRpcMethodResponse | None = ...,
+ rpc_method_invocation_response: rpc_pb2.RpcMethodInvocationResponseResponse | None = ...,
+ enable_remote_track_publication: track_publication_pb2.EnableRemoteTrackPublicationResponse | None = ...,
+ update_remote_track_publication_dimension: track_publication_pb2.UpdateRemoteTrackPublicationDimensionResponse | None = ...,
+ send_stream_header: room_pb2.SendStreamHeaderResponse | None = ...,
+ send_stream_chunk: room_pb2.SendStreamChunkResponse | None = ...,
+ send_stream_trailer: room_pb2.SendStreamTrailerResponse | None = ...,
+ set_data_channel_buffered_amount_low_threshold: room_pb2.SetDataChannelBufferedAmountLowThresholdResponse | None = ...,
+ load_audio_filter_plugin: audio_frame_pb2.LoadAudioFilterPluginResponse | None = ...,
+ new_apm: audio_frame_pb2.NewApmResponse | None = ...,
+ apm_process_stream: audio_frame_pb2.ApmProcessStreamResponse | None = ...,
+ apm_process_reverse_stream: audio_frame_pb2.ApmProcessReverseStreamResponse | None = ...,
+ apm_set_stream_delay: audio_frame_pb2.ApmSetStreamDelayResponse | None = ...,
+ byte_read_incremental: data_stream_pb2.ByteStreamReaderReadIncrementalResponse | None = ...,
+ byte_read_all: data_stream_pb2.ByteStreamReaderReadAllResponse | None = ...,
+ byte_write_to_file: data_stream_pb2.ByteStreamReaderWriteToFileResponse | None = ...,
+ text_read_incremental: data_stream_pb2.TextStreamReaderReadIncrementalResponse | None = ...,
+ text_read_all: data_stream_pb2.TextStreamReaderReadAllResponse | None = ...,
+ send_file: data_stream_pb2.StreamSendFileResponse | None = ...,
+ send_text: data_stream_pb2.StreamSendTextResponse | None = ...,
+ byte_stream_open: data_stream_pb2.ByteStreamOpenResponse | None = ...,
+ byte_stream_write: data_stream_pb2.ByteStreamWriterWriteResponse | None = ...,
+ byte_stream_close: data_stream_pb2.ByteStreamWriterCloseResponse | None = ...,
+ text_stream_open: data_stream_pb2.TextStreamOpenResponse | None = ...,
+ text_stream_write: data_stream_pb2.TextStreamWriterWriteResponse | None = ...,
+ text_stream_close: data_stream_pb2.TextStreamWriterCloseResponse | None = ...,
+ send_bytes: data_stream_pb2.StreamSendBytesResponse | None = ...,
+ set_remote_track_publication_quality: track_publication_pb2.SetRemoteTrackPublicationQualityResponse | None = ...,
+ publish_data_track: data_track_pb2.PublishDataTrackResponse | None = ...,
+ local_data_track_try_push: data_track_pb2.LocalDataTrackTryPushResponse | None = ...,
+ local_data_track_unpublish: data_track_pb2.LocalDataTrackUnpublishResponse | None = ...,
+ local_data_track_is_published: data_track_pb2.LocalDataTrackIsPublishedResponse | None = ...,
+ subscribe_data_track: data_track_pb2.SubscribeDataTrackResponse | None = ...,
+ remote_data_track_is_published: data_track_pb2.RemoteDataTrackIsPublishedResponse | None = ...,
+ data_track_stream_read: data_track_pb2.DataTrackStreamReadResponse | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["capture_audio_frame", b"capture_audio_frame", "capture_video_frame", b"capture_video_frame", "connect", b"connect", "create_audio_track", b"create_audio_track", "create_video_track", b"create_video_track", "disconnect", b"disconnect", "dispose", b"dispose", "e2ee", b"e2ee", "get_session_stats", b"get_session_stats", "get_stats", b"get_stats", "message", b"message", "new_audio_resampler", b"new_audio_resampler", "new_audio_source", b"new_audio_source", "new_audio_stream", b"new_audio_stream", "new_video_source", b"new_video_source", "new_video_stream", b"new_video_stream", "publish_data", b"publish_data", "publish_track", b"publish_track", "publish_transcription", b"publish_transcription", "remix_and_resample", b"remix_and_resample", "set_subscribed", b"set_subscribed", "unpublish_track", b"unpublish_track", "update_local_metadata", b"update_local_metadata", "update_local_name", b"update_local_name", "video_convert", b"video_convert"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["capture_audio_frame", b"capture_audio_frame", "capture_video_frame", b"capture_video_frame", "connect", b"connect", "create_audio_track", b"create_audio_track", "create_video_track", b"create_video_track", "disconnect", b"disconnect", "dispose", b"dispose", "e2ee", b"e2ee", "get_session_stats", b"get_session_stats", "get_stats", b"get_stats", "message", b"message", "new_audio_resampler", b"new_audio_resampler", "new_audio_source", b"new_audio_source", "new_audio_stream", b"new_audio_stream", "new_video_source", b"new_video_source", "new_video_stream", b"new_video_stream", "publish_data", b"publish_data", "publish_track", b"publish_track", "publish_transcription", b"publish_transcription", "remix_and_resample", b"remix_and_resample", "set_subscribed", b"set_subscribed", "unpublish_track", b"unpublish_track", "update_local_metadata", b"update_local_metadata", "update_local_name", b"update_local_name", "video_convert", b"video_convert"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["message", b"message"]) -> typing_extensions.Literal["dispose", "connect", "disconnect", "publish_track", "unpublish_track", "publish_data", "set_subscribed", "update_local_metadata", "update_local_name", "get_session_stats", "publish_transcription", "create_video_track", "create_audio_track", "get_stats", "new_video_stream", "new_video_source", "capture_video_frame", "video_convert", "new_audio_stream", "new_audio_source", "capture_audio_frame", "new_audio_resampler", "remix_and_resample", "e2ee"] | None: ...
+ def HasField(self, field_name: typing.Literal["apm_process_reverse_stream", b"apm_process_reverse_stream", "apm_process_stream", b"apm_process_stream", "apm_set_stream_delay", b"apm_set_stream_delay", "audio_stream_from_participant", b"audio_stream_from_participant", "byte_read_all", b"byte_read_all", "byte_read_incremental", b"byte_read_incremental", "byte_stream_close", b"byte_stream_close", "byte_stream_open", b"byte_stream_open", "byte_stream_write", b"byte_stream_write", "byte_write_to_file", b"byte_write_to_file", "capture_audio_frame", b"capture_audio_frame", "capture_video_frame", b"capture_video_frame", "clear_audio_buffer", b"clear_audio_buffer", "connect", b"connect", "create_audio_track", b"create_audio_track", "create_video_track", b"create_video_track", "data_track_stream_read", b"data_track_stream_read", "disconnect", b"disconnect", "dispose", b"dispose", "e2ee", b"e2ee", "enable_remote_track", b"enable_remote_track", "enable_remote_track_publication", b"enable_remote_track_publication", "flush_sox_resampler", b"flush_sox_resampler", "get_session_stats", b"get_session_stats", "get_stats", b"get_stats", "load_audio_filter_plugin", b"load_audio_filter_plugin", "local_data_track_is_published", b"local_data_track_is_published", "local_data_track_try_push", b"local_data_track_try_push", "local_data_track_unpublish", b"local_data_track_unpublish", "local_track_mute", b"local_track_mute", "message", b"message", "new_apm", b"new_apm", "new_audio_resampler", b"new_audio_resampler", "new_audio_source", b"new_audio_source", "new_audio_stream", b"new_audio_stream", "new_sox_resampler", b"new_sox_resampler", "new_video_source", b"new_video_source", "new_video_stream", b"new_video_stream", "perform_rpc", b"perform_rpc", "publish_data", b"publish_data", "publish_data_track", b"publish_data_track", "publish_sip_dtmf", b"publish_sip_dtmf", "publish_track", b"publish_track", "publish_transcription", b"publish_transcription", "push_sox_resampler", b"push_sox_resampler", "register_rpc_method", b"register_rpc_method", "remix_and_resample", b"remix_and_resample", "remote_data_track_is_published", b"remote_data_track_is_published", "rpc_method_invocation_response", b"rpc_method_invocation_response", "send_bytes", b"send_bytes", "send_chat_message", b"send_chat_message", "send_file", b"send_file", "send_stream_chunk", b"send_stream_chunk", "send_stream_header", b"send_stream_header", "send_stream_trailer", b"send_stream_trailer", "send_text", b"send_text", "set_data_channel_buffered_amount_low_threshold", b"set_data_channel_buffered_amount_low_threshold", "set_local_attributes", b"set_local_attributes", "set_local_metadata", b"set_local_metadata", "set_local_name", b"set_local_name", "set_remote_track_publication_quality", b"set_remote_track_publication_quality", "set_subscribed", b"set_subscribed", "set_track_subscription_permissions", b"set_track_subscription_permissions", "subscribe_data_track", b"subscribe_data_track", "text_read_all", b"text_read_all", "text_read_incremental", b"text_read_incremental", "text_stream_close", b"text_stream_close", "text_stream_open", b"text_stream_open", "text_stream_write", b"text_stream_write", "unpublish_track", b"unpublish_track", "unregister_rpc_method", b"unregister_rpc_method", "update_remote_track_publication_dimension", b"update_remote_track_publication_dimension", "video_convert", b"video_convert", "video_stream_from_participant", b"video_stream_from_participant"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["apm_process_reverse_stream", b"apm_process_reverse_stream", "apm_process_stream", b"apm_process_stream", "apm_set_stream_delay", b"apm_set_stream_delay", "audio_stream_from_participant", b"audio_stream_from_participant", "byte_read_all", b"byte_read_all", "byte_read_incremental", b"byte_read_incremental", "byte_stream_close", b"byte_stream_close", "byte_stream_open", b"byte_stream_open", "byte_stream_write", b"byte_stream_write", "byte_write_to_file", b"byte_write_to_file", "capture_audio_frame", b"capture_audio_frame", "capture_video_frame", b"capture_video_frame", "clear_audio_buffer", b"clear_audio_buffer", "connect", b"connect", "create_audio_track", b"create_audio_track", "create_video_track", b"create_video_track", "data_track_stream_read", b"data_track_stream_read", "disconnect", b"disconnect", "dispose", b"dispose", "e2ee", b"e2ee", "enable_remote_track", b"enable_remote_track", "enable_remote_track_publication", b"enable_remote_track_publication", "flush_sox_resampler", b"flush_sox_resampler", "get_session_stats", b"get_session_stats", "get_stats", b"get_stats", "load_audio_filter_plugin", b"load_audio_filter_plugin", "local_data_track_is_published", b"local_data_track_is_published", "local_data_track_try_push", b"local_data_track_try_push", "local_data_track_unpublish", b"local_data_track_unpublish", "local_track_mute", b"local_track_mute", "message", b"message", "new_apm", b"new_apm", "new_audio_resampler", b"new_audio_resampler", "new_audio_source", b"new_audio_source", "new_audio_stream", b"new_audio_stream", "new_sox_resampler", b"new_sox_resampler", "new_video_source", b"new_video_source", "new_video_stream", b"new_video_stream", "perform_rpc", b"perform_rpc", "publish_data", b"publish_data", "publish_data_track", b"publish_data_track", "publish_sip_dtmf", b"publish_sip_dtmf", "publish_track", b"publish_track", "publish_transcription", b"publish_transcription", "push_sox_resampler", b"push_sox_resampler", "register_rpc_method", b"register_rpc_method", "remix_and_resample", b"remix_and_resample", "remote_data_track_is_published", b"remote_data_track_is_published", "rpc_method_invocation_response", b"rpc_method_invocation_response", "send_bytes", b"send_bytes", "send_chat_message", b"send_chat_message", "send_file", b"send_file", "send_stream_chunk", b"send_stream_chunk", "send_stream_header", b"send_stream_header", "send_stream_trailer", b"send_stream_trailer", "send_text", b"send_text", "set_data_channel_buffered_amount_low_threshold", b"set_data_channel_buffered_amount_low_threshold", "set_local_attributes", b"set_local_attributes", "set_local_metadata", b"set_local_metadata", "set_local_name", b"set_local_name", "set_remote_track_publication_quality", b"set_remote_track_publication_quality", "set_subscribed", b"set_subscribed", "set_track_subscription_permissions", b"set_track_subscription_permissions", "subscribe_data_track", b"subscribe_data_track", "text_read_all", b"text_read_all", "text_read_incremental", b"text_read_incremental", "text_stream_close", b"text_stream_close", "text_stream_open", b"text_stream_open", "text_stream_write", b"text_stream_write", "unpublish_track", b"unpublish_track", "unregister_rpc_method", b"unregister_rpc_method", "update_remote_track_publication_dimension", b"update_remote_track_publication_dimension", "video_convert", b"video_convert", "video_stream_from_participant", b"video_stream_from_participant"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["message", b"message"]) -> typing.Literal["dispose", "connect", "disconnect", "publish_track", "unpublish_track", "publish_data", "set_subscribed", "set_local_metadata", "set_local_name", "set_local_attributes", "get_session_stats", "publish_transcription", "publish_sip_dtmf", "create_video_track", "create_audio_track", "local_track_mute", "enable_remote_track", "get_stats", "set_track_subscription_permissions", "new_video_stream", "new_video_source", "capture_video_frame", "video_convert", "video_stream_from_participant", "new_audio_stream", "new_audio_source", "capture_audio_frame", "clear_audio_buffer", "new_audio_resampler", "remix_and_resample", "audio_stream_from_participant", "e2ee", "new_sox_resampler", "push_sox_resampler", "flush_sox_resampler", "send_chat_message", "perform_rpc", "register_rpc_method", "unregister_rpc_method", "rpc_method_invocation_response", "enable_remote_track_publication", "update_remote_track_publication_dimension", "send_stream_header", "send_stream_chunk", "send_stream_trailer", "set_data_channel_buffered_amount_low_threshold", "load_audio_filter_plugin", "new_apm", "apm_process_stream", "apm_process_reverse_stream", "apm_set_stream_delay", "byte_read_incremental", "byte_read_all", "byte_write_to_file", "text_read_incremental", "text_read_all", "send_file", "send_text", "byte_stream_open", "byte_stream_write", "byte_stream_close", "text_stream_open", "text_stream_write", "text_stream_close", "send_bytes", "set_remote_track_publication_quality", "publish_data_track", "local_data_track_try_push", "local_data_track_unpublish", "local_data_track_is_published", "subscribe_data_track", "remote_data_track_is_published", "data_track_stream_read"] | None: ...
global___FfiResponse = FfiResponse
-@typing_extensions.final
+@typing.final
class FfiEvent(google.protobuf.message.Message):
"""To minimize complexity, participant events are not included in the protocol.
It is easily deducible from the room events and it turned out that is is easier to implement
@@ -338,12 +779,36 @@ class FfiEvent(google.protobuf.message.Message):
PUBLISH_DATA_FIELD_NUMBER: builtins.int
PUBLISH_TRANSCRIPTION_FIELD_NUMBER: builtins.int
CAPTURE_AUDIO_FRAME_FIELD_NUMBER: builtins.int
- UPDATE_LOCAL_METADATA_FIELD_NUMBER: builtins.int
- UPDATE_LOCAL_NAME_FIELD_NUMBER: builtins.int
+ SET_LOCAL_METADATA_FIELD_NUMBER: builtins.int
+ SET_LOCAL_NAME_FIELD_NUMBER: builtins.int
+ SET_LOCAL_ATTRIBUTES_FIELD_NUMBER: builtins.int
GET_STATS_FIELD_NUMBER: builtins.int
LOGS_FIELD_NUMBER: builtins.int
GET_SESSION_STATS_FIELD_NUMBER: builtins.int
PANIC_FIELD_NUMBER: builtins.int
+ PUBLISH_SIP_DTMF_FIELD_NUMBER: builtins.int
+ CHAT_MESSAGE_FIELD_NUMBER: builtins.int
+ PERFORM_RPC_FIELD_NUMBER: builtins.int
+ RPC_METHOD_INVOCATION_FIELD_NUMBER: builtins.int
+ SEND_STREAM_HEADER_FIELD_NUMBER: builtins.int
+ SEND_STREAM_CHUNK_FIELD_NUMBER: builtins.int
+ SEND_STREAM_TRAILER_FIELD_NUMBER: builtins.int
+ BYTE_STREAM_READER_EVENT_FIELD_NUMBER: builtins.int
+ BYTE_STREAM_READER_READ_ALL_FIELD_NUMBER: builtins.int
+ BYTE_STREAM_READER_WRITE_TO_FILE_FIELD_NUMBER: builtins.int
+ BYTE_STREAM_OPEN_FIELD_NUMBER: builtins.int
+ BYTE_STREAM_WRITER_WRITE_FIELD_NUMBER: builtins.int
+ BYTE_STREAM_WRITER_CLOSE_FIELD_NUMBER: builtins.int
+ SEND_FILE_FIELD_NUMBER: builtins.int
+ TEXT_STREAM_READER_EVENT_FIELD_NUMBER: builtins.int
+ TEXT_STREAM_READER_READ_ALL_FIELD_NUMBER: builtins.int
+ TEXT_STREAM_OPEN_FIELD_NUMBER: builtins.int
+ TEXT_STREAM_WRITER_WRITE_FIELD_NUMBER: builtins.int
+ TEXT_STREAM_WRITER_CLOSE_FIELD_NUMBER: builtins.int
+ SEND_TEXT_FIELD_NUMBER: builtins.int
+ SEND_BYTES_FIELD_NUMBER: builtins.int
+ PUBLISH_DATA_TRACK_FIELD_NUMBER: builtins.int
+ DATA_TRACK_STREAM_EVENT_FIELD_NUMBER: builtins.int
@property
def room_event(self) -> room_pb2.RoomEvent: ...
@property
@@ -369,9 +834,11 @@ class FfiEvent(google.protobuf.message.Message):
@property
def capture_audio_frame(self) -> audio_frame_pb2.CaptureAudioFrameCallback: ...
@property
- def update_local_metadata(self) -> room_pb2.UpdateLocalMetadataCallback: ...
+ def set_local_metadata(self) -> room_pb2.SetLocalMetadataCallback: ...
+ @property
+ def set_local_name(self) -> room_pb2.SetLocalNameCallback: ...
@property
- def update_local_name(self) -> room_pb2.UpdateLocalNameCallback: ...
+ def set_local_attributes(self) -> room_pb2.SetLocalAttributesCallback: ...
@property
def get_stats(self) -> track_pb2.GetStatsCallback: ...
@property
@@ -380,6 +847,60 @@ class FfiEvent(google.protobuf.message.Message):
def get_session_stats(self) -> room_pb2.GetSessionStatsCallback: ...
@property
def panic(self) -> global___Panic: ...
+ @property
+ def publish_sip_dtmf(self) -> room_pb2.PublishSipDtmfCallback: ...
+ @property
+ def chat_message(self) -> room_pb2.SendChatMessageCallback: ...
+ @property
+ def perform_rpc(self) -> rpc_pb2.PerformRpcCallback: ...
+ @property
+ def rpc_method_invocation(self) -> rpc_pb2.RpcMethodInvocationEvent: ...
+ @property
+ def send_stream_header(self) -> room_pb2.SendStreamHeaderCallback:
+ """Data Streams (low level)"""
+
+ @property
+ def send_stream_chunk(self) -> room_pb2.SendStreamChunkCallback: ...
+ @property
+ def send_stream_trailer(self) -> room_pb2.SendStreamTrailerCallback: ...
+ @property
+ def byte_stream_reader_event(self) -> data_stream_pb2.ByteStreamReaderEvent:
+ """Data Streams (high level)"""
+
+ @property
+ def byte_stream_reader_read_all(self) -> data_stream_pb2.ByteStreamReaderReadAllCallback: ...
+ @property
+ def byte_stream_reader_write_to_file(self) -> data_stream_pb2.ByteStreamReaderWriteToFileCallback: ...
+ @property
+ def byte_stream_open(self) -> data_stream_pb2.ByteStreamOpenCallback: ...
+ @property
+ def byte_stream_writer_write(self) -> data_stream_pb2.ByteStreamWriterWriteCallback: ...
+ @property
+ def byte_stream_writer_close(self) -> data_stream_pb2.ByteStreamWriterCloseCallback: ...
+ @property
+ def send_file(self) -> data_stream_pb2.StreamSendFileCallback: ...
+ @property
+ def text_stream_reader_event(self) -> data_stream_pb2.TextStreamReaderEvent: ...
+ @property
+ def text_stream_reader_read_all(self) -> data_stream_pb2.TextStreamReaderReadAllCallback: ...
+ @property
+ def text_stream_open(self) -> data_stream_pb2.TextStreamOpenCallback: ...
+ @property
+ def text_stream_writer_write(self) -> data_stream_pb2.TextStreamWriterWriteCallback: ...
+ @property
+ def text_stream_writer_close(self) -> data_stream_pb2.TextStreamWriterCloseCallback: ...
+ @property
+ def send_text(self) -> data_stream_pb2.StreamSendTextCallback: ...
+ @property
+ def send_bytes(self) -> data_stream_pb2.StreamSendBytesCallback: ...
+ @property
+ def publish_data_track(self) -> data_track_pb2.PublishDataTrackCallback:
+ """Data Track (local)"""
+
+ @property
+ def data_track_stream_event(self) -> data_track_pb2.DataTrackStreamEvent:
+ """Data Track (remote)"""
+
def __init__(
self,
*,
@@ -395,20 +916,44 @@ class FfiEvent(google.protobuf.message.Message):
publish_data: room_pb2.PublishDataCallback | None = ...,
publish_transcription: room_pb2.PublishTranscriptionCallback | None = ...,
capture_audio_frame: audio_frame_pb2.CaptureAudioFrameCallback | None = ...,
- update_local_metadata: room_pb2.UpdateLocalMetadataCallback | None = ...,
- update_local_name: room_pb2.UpdateLocalNameCallback | None = ...,
+ set_local_metadata: room_pb2.SetLocalMetadataCallback | None = ...,
+ set_local_name: room_pb2.SetLocalNameCallback | None = ...,
+ set_local_attributes: room_pb2.SetLocalAttributesCallback | None = ...,
get_stats: track_pb2.GetStatsCallback | None = ...,
logs: global___LogBatch | None = ...,
get_session_stats: room_pb2.GetSessionStatsCallback | None = ...,
panic: global___Panic | None = ...,
+ publish_sip_dtmf: room_pb2.PublishSipDtmfCallback | None = ...,
+ chat_message: room_pb2.SendChatMessageCallback | None = ...,
+ perform_rpc: rpc_pb2.PerformRpcCallback | None = ...,
+ rpc_method_invocation: rpc_pb2.RpcMethodInvocationEvent | None = ...,
+ send_stream_header: room_pb2.SendStreamHeaderCallback | None = ...,
+ send_stream_chunk: room_pb2.SendStreamChunkCallback | None = ...,
+ send_stream_trailer: room_pb2.SendStreamTrailerCallback | None = ...,
+ byte_stream_reader_event: data_stream_pb2.ByteStreamReaderEvent | None = ...,
+ byte_stream_reader_read_all: data_stream_pb2.ByteStreamReaderReadAllCallback | None = ...,
+ byte_stream_reader_write_to_file: data_stream_pb2.ByteStreamReaderWriteToFileCallback | None = ...,
+ byte_stream_open: data_stream_pb2.ByteStreamOpenCallback | None = ...,
+ byte_stream_writer_write: data_stream_pb2.ByteStreamWriterWriteCallback | None = ...,
+ byte_stream_writer_close: data_stream_pb2.ByteStreamWriterCloseCallback | None = ...,
+ send_file: data_stream_pb2.StreamSendFileCallback | None = ...,
+ text_stream_reader_event: data_stream_pb2.TextStreamReaderEvent | None = ...,
+ text_stream_reader_read_all: data_stream_pb2.TextStreamReaderReadAllCallback | None = ...,
+ text_stream_open: data_stream_pb2.TextStreamOpenCallback | None = ...,
+ text_stream_writer_write: data_stream_pb2.TextStreamWriterWriteCallback | None = ...,
+ text_stream_writer_close: data_stream_pb2.TextStreamWriterCloseCallback | None = ...,
+ send_text: data_stream_pb2.StreamSendTextCallback | None = ...,
+ send_bytes: data_stream_pb2.StreamSendBytesCallback | None = ...,
+ publish_data_track: data_track_pb2.PublishDataTrackCallback | None = ...,
+ data_track_stream_event: data_track_pb2.DataTrackStreamEvent | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["audio_stream_event", b"audio_stream_event", "capture_audio_frame", b"capture_audio_frame", "connect", b"connect", "disconnect", b"disconnect", "dispose", b"dispose", "get_session_stats", b"get_session_stats", "get_stats", b"get_stats", "logs", b"logs", "message", b"message", "panic", b"panic", "publish_data", b"publish_data", "publish_track", b"publish_track", "publish_transcription", b"publish_transcription", "room_event", b"room_event", "track_event", b"track_event", "unpublish_track", b"unpublish_track", "update_local_metadata", b"update_local_metadata", "update_local_name", b"update_local_name", "video_stream_event", b"video_stream_event"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["audio_stream_event", b"audio_stream_event", "capture_audio_frame", b"capture_audio_frame", "connect", b"connect", "disconnect", b"disconnect", "dispose", b"dispose", "get_session_stats", b"get_session_stats", "get_stats", b"get_stats", "logs", b"logs", "message", b"message", "panic", b"panic", "publish_data", b"publish_data", "publish_track", b"publish_track", "publish_transcription", b"publish_transcription", "room_event", b"room_event", "track_event", b"track_event", "unpublish_track", b"unpublish_track", "update_local_metadata", b"update_local_metadata", "update_local_name", b"update_local_name", "video_stream_event", b"video_stream_event"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["message", b"message"]) -> typing_extensions.Literal["room_event", "track_event", "video_stream_event", "audio_stream_event", "connect", "disconnect", "dispose", "publish_track", "unpublish_track", "publish_data", "publish_transcription", "capture_audio_frame", "update_local_metadata", "update_local_name", "get_stats", "logs", "get_session_stats", "panic"] | None: ...
+ def HasField(self, field_name: typing.Literal["audio_stream_event", b"audio_stream_event", "byte_stream_open", b"byte_stream_open", "byte_stream_reader_event", b"byte_stream_reader_event", "byte_stream_reader_read_all", b"byte_stream_reader_read_all", "byte_stream_reader_write_to_file", b"byte_stream_reader_write_to_file", "byte_stream_writer_close", b"byte_stream_writer_close", "byte_stream_writer_write", b"byte_stream_writer_write", "capture_audio_frame", b"capture_audio_frame", "chat_message", b"chat_message", "connect", b"connect", "data_track_stream_event", b"data_track_stream_event", "disconnect", b"disconnect", "dispose", b"dispose", "get_session_stats", b"get_session_stats", "get_stats", b"get_stats", "logs", b"logs", "message", b"message", "panic", b"panic", "perform_rpc", b"perform_rpc", "publish_data", b"publish_data", "publish_data_track", b"publish_data_track", "publish_sip_dtmf", b"publish_sip_dtmf", "publish_track", b"publish_track", "publish_transcription", b"publish_transcription", "room_event", b"room_event", "rpc_method_invocation", b"rpc_method_invocation", "send_bytes", b"send_bytes", "send_file", b"send_file", "send_stream_chunk", b"send_stream_chunk", "send_stream_header", b"send_stream_header", "send_stream_trailer", b"send_stream_trailer", "send_text", b"send_text", "set_local_attributes", b"set_local_attributes", "set_local_metadata", b"set_local_metadata", "set_local_name", b"set_local_name", "text_stream_open", b"text_stream_open", "text_stream_reader_event", b"text_stream_reader_event", "text_stream_reader_read_all", b"text_stream_reader_read_all", "text_stream_writer_close", b"text_stream_writer_close", "text_stream_writer_write", b"text_stream_writer_write", "track_event", b"track_event", "unpublish_track", b"unpublish_track", "video_stream_event", b"video_stream_event"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["audio_stream_event", b"audio_stream_event", "byte_stream_open", b"byte_stream_open", "byte_stream_reader_event", b"byte_stream_reader_event", "byte_stream_reader_read_all", b"byte_stream_reader_read_all", "byte_stream_reader_write_to_file", b"byte_stream_reader_write_to_file", "byte_stream_writer_close", b"byte_stream_writer_close", "byte_stream_writer_write", b"byte_stream_writer_write", "capture_audio_frame", b"capture_audio_frame", "chat_message", b"chat_message", "connect", b"connect", "data_track_stream_event", b"data_track_stream_event", "disconnect", b"disconnect", "dispose", b"dispose", "get_session_stats", b"get_session_stats", "get_stats", b"get_stats", "logs", b"logs", "message", b"message", "panic", b"panic", "perform_rpc", b"perform_rpc", "publish_data", b"publish_data", "publish_data_track", b"publish_data_track", "publish_sip_dtmf", b"publish_sip_dtmf", "publish_track", b"publish_track", "publish_transcription", b"publish_transcription", "room_event", b"room_event", "rpc_method_invocation", b"rpc_method_invocation", "send_bytes", b"send_bytes", "send_file", b"send_file", "send_stream_chunk", b"send_stream_chunk", "send_stream_header", b"send_stream_header", "send_stream_trailer", b"send_stream_trailer", "send_text", b"send_text", "set_local_attributes", b"set_local_attributes", "set_local_metadata", b"set_local_metadata", "set_local_name", b"set_local_name", "text_stream_open", b"text_stream_open", "text_stream_reader_event", b"text_stream_reader_event", "text_stream_reader_read_all", b"text_stream_reader_read_all", "text_stream_writer_close", b"text_stream_writer_close", "text_stream_writer_write", b"text_stream_writer_write", "track_event", b"track_event", "unpublish_track", b"unpublish_track", "video_stream_event", b"video_stream_event"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["message", b"message"]) -> typing.Literal["room_event", "track_event", "video_stream_event", "audio_stream_event", "connect", "disconnect", "dispose", "publish_track", "unpublish_track", "publish_data", "publish_transcription", "capture_audio_frame", "set_local_metadata", "set_local_name", "set_local_attributes", "get_stats", "logs", "get_session_stats", "panic", "publish_sip_dtmf", "chat_message", "perform_rpc", "rpc_method_invocation", "send_stream_header", "send_stream_chunk", "send_stream_trailer", "byte_stream_reader_event", "byte_stream_reader_read_all", "byte_stream_reader_write_to_file", "byte_stream_open", "byte_stream_writer_write", "byte_stream_writer_close", "send_file", "text_stream_reader_event", "text_stream_reader_read_all", "text_stream_open", "text_stream_writer_write", "text_stream_writer_close", "send_text", "send_bytes", "publish_data_track", "data_track_stream_event"] | None: ...
global___FfiEvent = FfiEvent
-@typing_extensions.final
+@typing.final
class DisposeRequest(google.protobuf.message.Message):
"""Stop all rooms synchronously (Do we need async here?).
e.g: This is used for the Unity Editor after each assemblies reload.
@@ -421,11 +966,12 @@ class DisposeRequest(google.protobuf.message.Message):
def __init__(
self,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["async", b"async"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["async", b"async"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async", b"async"]) -> None: ...
global___DisposeRequest = DisposeRequest
-@typing_extensions.final
+@typing.final
class DisposeResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -437,13 +983,12 @@ class DisposeResponse(google.protobuf.message.Message):
*,
async_id: builtins.int | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_async_id", b"_async_id", "async_id", b"async_id"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_async_id", b"_async_id", "async_id", b"async_id"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_async_id", b"_async_id"]) -> typing_extensions.Literal["async_id"] | None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
global___DisposeResponse = DisposeResponse
-@typing_extensions.final
+@typing.final
class DisposeCallback(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -452,13 +997,14 @@ class DisposeCallback(google.protobuf.message.Message):
def __init__(
self,
*,
- async_id: builtins.int = ...,
+ async_id: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["async_id", b"async_id"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
global___DisposeCallback = DisposeCallback
-@typing_extensions.final
+@typing.final
class LogRecord(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -478,25 +1024,19 @@ class LogRecord(google.protobuf.message.Message):
def __init__(
self,
*,
- level: global___LogLevel.ValueType = ...,
- target: builtins.str = ...,
+ level: global___LogLevel.ValueType | None = ...,
+ target: builtins.str | None = ...,
module_path: builtins.str | None = ...,
file: builtins.str | None = ...,
line: builtins.int | None = ...,
- message: builtins.str = ...,
+ message: builtins.str | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_file", b"_file", "_line", b"_line", "_module_path", b"_module_path", "file", b"file", "line", b"line", "module_path", b"module_path"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_file", b"_file", "_line", b"_line", "_module_path", b"_module_path", "file", b"file", "level", b"level", "line", b"line", "message", b"message", "module_path", b"module_path", "target", b"target"]) -> None: ...
- @typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_file", b"_file"]) -> typing_extensions.Literal["file"] | None: ...
- @typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_line", b"_line"]) -> typing_extensions.Literal["line"] | None: ...
- @typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_module_path", b"_module_path"]) -> typing_extensions.Literal["module_path"] | None: ...
+ def HasField(self, field_name: typing.Literal["file", b"file", "level", b"level", "line", b"line", "message", b"message", "module_path", b"module_path", "target", b"target"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["file", b"file", "level", b"level", "line", b"line", "message", b"message", "module_path", b"module_path", "target", b"target"]) -> None: ...
global___LogRecord = LogRecord
-@typing_extensions.final
+@typing.final
class LogBatch(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -508,11 +1048,11 @@ class LogBatch(google.protobuf.message.Message):
*,
records: collections.abc.Iterable[global___LogRecord] | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["records", b"records"]) -> None: ...
+ def ClearField(self, field_name: typing.Literal["records", b"records"]) -> None: ...
global___LogBatch = LogBatch
-@typing_extensions.final
+@typing.final
class Panic(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -521,8 +1061,9 @@ class Panic(google.protobuf.message.Message):
def __init__(
self,
*,
- message: builtins.str = ...,
+ message: builtins.str | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["message", b"message"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["message", b"message"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["message", b"message"]) -> None: ...
global___Panic = Panic
diff --git a/livekit-rtc/livekit/rtc/_proto/handle_pb2.py b/livekit-rtc/livekit/rtc/_proto/handle_pb2.py
index f3230797..2ae2db78 100644
--- a/livekit-rtc/livekit/rtc/_proto/handle_pb2.py
+++ b/livekit-rtc/livekit/rtc/_proto/handle_pb2.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: handle.proto
-# Protobuf Python Version: 4.25.3
+# Protobuf Python Version: 4.25.1
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
@@ -14,7 +14,7 @@
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0chandle.proto\x12\rlivekit.proto\"\x1c\n\x0e\x46\x66iOwnedHandle\x12\n\n\x02id\x18\x01 \x01(\x04\x42\x10\xaa\x02\rLiveKit.Protob\x06proto3')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0chandle.proto\x12\rlivekit.proto\"\x1c\n\x0e\x46\x66iOwnedHandle\x12\n\n\x02id\x18\x01 \x02(\x04\x42\x10\xaa\x02\rLiveKit.Proto')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
diff --git a/livekit-rtc/livekit/rtc/_proto/handle_pb2.pyi b/livekit-rtc/livekit/rtc/_proto/handle_pb2.pyi
index 5b525ca9..d433a6c2 100644
--- a/livekit-rtc/livekit/rtc/_proto/handle_pb2.pyi
+++ b/livekit-rtc/livekit/rtc/_proto/handle_pb2.pyi
@@ -1,7 +1,7 @@
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
-Copyright 2023 LiveKit, Inc.
+Copyright 2025 LiveKit, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,19 +15,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
+
import builtins
import google.protobuf.descriptor
import google.protobuf.message
-import sys
-
-if sys.version_info >= (3, 8):
- import typing as typing_extensions
-else:
- import typing_extensions
+import typing
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
-@typing_extensions.final
+@typing.final
class FfiOwnedHandle(google.protobuf.message.Message):
"""# Safety
The foreign language is responsable for disposing handles
@@ -47,8 +43,9 @@ class FfiOwnedHandle(google.protobuf.message.Message):
def __init__(
self,
*,
- id: builtins.int = ...,
+ id: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["id", b"id"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["id", b"id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["id", b"id"]) -> None: ...
global___FfiOwnedHandle = FfiOwnedHandle
diff --git a/livekit-rtc/livekit/rtc/_proto/participant_pb2.py b/livekit-rtc/livekit/rtc/_proto/participant_pb2.py
index 0141671d..f4943934 100644
--- a/livekit-rtc/livekit/rtc/_proto/participant_pb2.py
+++ b/livekit-rtc/livekit/rtc/_proto/participant_pb2.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: participant.proto
-# Protobuf Python Version: 4.25.3
+# Protobuf Python Version: 4.25.1
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
@@ -13,9 +13,10 @@
from . import handle_pb2 as handle__pb2
+from . import track_pb2 as track__pb2
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11participant.proto\x12\rlivekit.proto\x1a\x0chandle.proto\"P\n\x0fParticipantInfo\x12\x0b\n\x03sid\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x10\n\x08identity\x18\x03 \x01(\t\x12\x10\n\x08metadata\x18\x04 \x01(\t\"o\n\x10OwnedParticipant\x12-\n\x06handle\x18\x01 \x01(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12,\n\x04info\x18\x02 \x01(\x0b\x32\x1e.livekit.proto.ParticipantInfoB\x10\xaa\x02\rLiveKit.Protob\x06proto3')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11participant.proto\x12\rlivekit.proto\x1a\x0chandle.proto\x1a\x0btrack.proto\"\xea\x03\n\x0fParticipantInfo\x12\x0b\n\x03sid\x18\x01 \x02(\t\x12\x0c\n\x04name\x18\x02 \x02(\t\x12\x10\n\x08identity\x18\x03 \x02(\t\x12.\n\x05state\x18\x04 \x02(\x0e\x32\x1f.livekit.proto.ParticipantState\x12\x10\n\x08metadata\x18\x05 \x02(\t\x12\x42\n\nattributes\x18\x06 \x03(\x0b\x32..livekit.proto.ParticipantInfo.AttributesEntry\x12,\n\x04kind\x18\x07 \x02(\x0e\x32\x1e.livekit.proto.ParticipantKind\x12:\n\x11\x64isconnect_reason\x18\x08 \x02(\x0e\x32\x1f.livekit.proto.DisconnectReason\x12\x11\n\tjoined_at\x18\t \x02(\x03\x12:\n\x0ckind_details\x18\n \x03(\x0e\x32$.livekit.proto.ParticipantKindDetail\x12\x38\n\npermission\x18\x0b \x01(\x0b\x32$.livekit.proto.ParticipantPermission\x1a\x31\n\x0f\x41ttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"o\n\x10OwnedParticipant\x12-\n\x06handle\x18\x01 \x02(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12,\n\x04info\x18\x02 \x02(\x0b\x32\x1e.livekit.proto.ParticipantInfo\"\x84\x02\n\x15ParticipantPermission\x12\x15\n\rcan_subscribe\x18\x01 \x02(\x08\x12\x13\n\x0b\x63\x61n_publish\x18\x02 \x02(\x08\x12\x18\n\x10\x63\x61n_publish_data\x18\x03 \x02(\x08\x12\x37\n\x13\x63\x61n_publish_sources\x18\t \x03(\x0e\x32\x1a.livekit.proto.TrackSource\x12\x0e\n\x06hidden\x18\x07 \x02(\x08\x12\x1b\n\x13\x63\x61n_update_metadata\x18\n \x02(\x08\x12\x1d\n\x15\x63\x61n_subscribe_metrics\x18\x0c \x02(\x08\x12 \n\x18\x63\x61n_manage_agent_session\x18\r \x02(\x08*\x91\x01\n\x10ParticipantState\x12\x1d\n\x19PARTICIPANT_STATE_JOINING\x10\x00\x12\x1c\n\x18PARTICIPANT_STATE_JOINED\x10\x01\x12\x1c\n\x18PARTICIPANT_STATE_ACTIVE\x10\x02\x12\"\n\x1ePARTICIPANT_STATE_DISCONNECTED\x10\x03*\xde\x01\n\x0fParticipantKind\x12\x1d\n\x19PARTICIPANT_KIND_STANDARD\x10\x00\x12\x1c\n\x18PARTICIPANT_KIND_INGRESS\x10\x01\x12\x1b\n\x17PARTICIPANT_KIND_EGRESS\x10\x02\x12\x18\n\x14PARTICIPANT_KIND_SIP\x10\x03\x12\x1a\n\x16PARTICIPANT_KIND_AGENT\x10\x04\x12\x1e\n\x1aPARTICIPANT_KIND_CONNECTOR\x10\x05\x12\x1b\n\x17PARTICIPANT_KIND_BRIDGE\x10\x06*\xee\x01\n\x15ParticipantKindDetail\x12\'\n#PARTICIPANT_KIND_DETAIL_CLOUD_AGENT\x10\x00\x12%\n!PARTICIPANT_KIND_DETAIL_FORWARDED\x10\x01\x12.\n*PARTICIPANT_KIND_DETAIL_CONNECTOR_WHATSAPP\x10\x02\x12,\n(PARTICIPANT_KIND_DETAIL_CONNECTOR_TWILIO\x10\x03\x12\'\n#PARTICIPANT_KIND_DETAIL_BRIDGE_RTSP\x10\x04*\xe8\x02\n\x10\x44isconnectReason\x12\x12\n\x0eUNKNOWN_REASON\x10\x00\x12\x14\n\x10\x43LIENT_INITIATED\x10\x01\x12\x16\n\x12\x44UPLICATE_IDENTITY\x10\x02\x12\x13\n\x0fSERVER_SHUTDOWN\x10\x03\x12\x17\n\x13PARTICIPANT_REMOVED\x10\x04\x12\x10\n\x0cROOM_DELETED\x10\x05\x12\x12\n\x0eSTATE_MISMATCH\x10\x06\x12\x10\n\x0cJOIN_FAILURE\x10\x07\x12\r\n\tMIGRATION\x10\x08\x12\x10\n\x0cSIGNAL_CLOSE\x10\t\x12\x0f\n\x0bROOM_CLOSED\x10\n\x12\x14\n\x10USER_UNAVAILABLE\x10\x0b\x12\x11\n\rUSER_REJECTED\x10\x0c\x12\x15\n\x11SIP_TRUNK_FAILURE\x10\r\x12\x16\n\x12\x43ONNECTION_TIMEOUT\x10\x0e\x12\x11\n\rMEDIA_FAILURE\x10\x0f\x12\x0f\n\x0b\x41GENT_ERROR\x10\x10\x42\x10\xaa\x02\rLiveKit.Proto')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -23,8 +24,22 @@
if _descriptor._USE_C_DESCRIPTORS == False:
_globals['DESCRIPTOR']._options = None
_globals['DESCRIPTOR']._serialized_options = b'\252\002\rLiveKit.Proto'
- _globals['_PARTICIPANTINFO']._serialized_start=50
- _globals['_PARTICIPANTINFO']._serialized_end=130
- _globals['_OWNEDPARTICIPANT']._serialized_start=132
- _globals['_OWNEDPARTICIPANT']._serialized_end=243
+ _globals['_PARTICIPANTINFO_ATTRIBUTESENTRY']._options = None
+ _globals['_PARTICIPANTINFO_ATTRIBUTESENTRY']._serialized_options = b'8\001'
+ _globals['_PARTICIPANTSTATE']._serialized_start=933
+ _globals['_PARTICIPANTSTATE']._serialized_end=1078
+ _globals['_PARTICIPANTKIND']._serialized_start=1081
+ _globals['_PARTICIPANTKIND']._serialized_end=1303
+ _globals['_PARTICIPANTKINDDETAIL']._serialized_start=1306
+ _globals['_PARTICIPANTKINDDETAIL']._serialized_end=1544
+ _globals['_DISCONNECTREASON']._serialized_start=1547
+ _globals['_DISCONNECTREASON']._serialized_end=1907
+ _globals['_PARTICIPANTINFO']._serialized_start=64
+ _globals['_PARTICIPANTINFO']._serialized_end=554
+ _globals['_PARTICIPANTINFO_ATTRIBUTESENTRY']._serialized_start=505
+ _globals['_PARTICIPANTINFO_ATTRIBUTESENTRY']._serialized_end=554
+ _globals['_OWNEDPARTICIPANT']._serialized_start=556
+ _globals['_OWNEDPARTICIPANT']._serialized_end=667
+ _globals['_PARTICIPANTPERMISSION']._serialized_start=670
+ _globals['_PARTICIPANTPERMISSION']._serialized_end=930
# @@protoc_insertion_point(module_scope)
diff --git a/livekit-rtc/livekit/rtc/_proto/participant_pb2.pyi b/livekit-rtc/livekit/rtc/_proto/participant_pb2.pyi
index 0b30d59e..4c84d2c6 100644
--- a/livekit-rtc/livekit/rtc/_proto/participant_pb2.pyi
+++ b/livekit-rtc/livekit/rtc/_proto/participant_pb2.pyi
@@ -1,7 +1,7 @@
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
-Copyright 2023 LiveKit, Inc.
+Copyright 2025 LiveKit, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,44 +15,229 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
+
import builtins
+import collections.abc
import google.protobuf.descriptor
+import google.protobuf.internal.containers
+import google.protobuf.internal.enum_type_wrapper
import google.protobuf.message
from . import handle_pb2
import sys
+from . import track_pb2
+import typing
-if sys.version_info >= (3, 8):
+if sys.version_info >= (3, 10):
import typing as typing_extensions
else:
import typing_extensions
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
-@typing_extensions.final
+class _ParticipantState:
+ ValueType = typing.NewType("ValueType", builtins.int)
+ V: typing_extensions.TypeAlias = ValueType
+
+class _ParticipantStateEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_ParticipantState.ValueType], builtins.type):
+ DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
+ PARTICIPANT_STATE_JOINING: _ParticipantState.ValueType # 0
+ PARTICIPANT_STATE_JOINED: _ParticipantState.ValueType # 1
+ PARTICIPANT_STATE_ACTIVE: _ParticipantState.ValueType # 2
+ PARTICIPANT_STATE_DISCONNECTED: _ParticipantState.ValueType # 3
+
+class ParticipantState(_ParticipantState, metaclass=_ParticipantStateEnumTypeWrapper): ...
+
+PARTICIPANT_STATE_JOINING: ParticipantState.ValueType # 0
+PARTICIPANT_STATE_JOINED: ParticipantState.ValueType # 1
+PARTICIPANT_STATE_ACTIVE: ParticipantState.ValueType # 2
+PARTICIPANT_STATE_DISCONNECTED: ParticipantState.ValueType # 3
+global___ParticipantState = ParticipantState
+
+class _ParticipantKind:
+ ValueType = typing.NewType("ValueType", builtins.int)
+ V: typing_extensions.TypeAlias = ValueType
+
+class _ParticipantKindEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_ParticipantKind.ValueType], builtins.type):
+ DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
+ PARTICIPANT_KIND_STANDARD: _ParticipantKind.ValueType # 0
+ PARTICIPANT_KIND_INGRESS: _ParticipantKind.ValueType # 1
+ PARTICIPANT_KIND_EGRESS: _ParticipantKind.ValueType # 2
+ PARTICIPANT_KIND_SIP: _ParticipantKind.ValueType # 3
+ PARTICIPANT_KIND_AGENT: _ParticipantKind.ValueType # 4
+ PARTICIPANT_KIND_CONNECTOR: _ParticipantKind.ValueType # 5
+ PARTICIPANT_KIND_BRIDGE: _ParticipantKind.ValueType # 6
+
+class ParticipantKind(_ParticipantKind, metaclass=_ParticipantKindEnumTypeWrapper): ...
+
+PARTICIPANT_KIND_STANDARD: ParticipantKind.ValueType # 0
+PARTICIPANT_KIND_INGRESS: ParticipantKind.ValueType # 1
+PARTICIPANT_KIND_EGRESS: ParticipantKind.ValueType # 2
+PARTICIPANT_KIND_SIP: ParticipantKind.ValueType # 3
+PARTICIPANT_KIND_AGENT: ParticipantKind.ValueType # 4
+PARTICIPANT_KIND_CONNECTOR: ParticipantKind.ValueType # 5
+PARTICIPANT_KIND_BRIDGE: ParticipantKind.ValueType # 6
+global___ParticipantKind = ParticipantKind
+
+class _ParticipantKindDetail:
+ ValueType = typing.NewType("ValueType", builtins.int)
+ V: typing_extensions.TypeAlias = ValueType
+
+class _ParticipantKindDetailEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_ParticipantKindDetail.ValueType], builtins.type):
+ DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
+ PARTICIPANT_KIND_DETAIL_CLOUD_AGENT: _ParticipantKindDetail.ValueType # 0
+ PARTICIPANT_KIND_DETAIL_FORWARDED: _ParticipantKindDetail.ValueType # 1
+ PARTICIPANT_KIND_DETAIL_CONNECTOR_WHATSAPP: _ParticipantKindDetail.ValueType # 2
+ PARTICIPANT_KIND_DETAIL_CONNECTOR_TWILIO: _ParticipantKindDetail.ValueType # 3
+ PARTICIPANT_KIND_DETAIL_BRIDGE_RTSP: _ParticipantKindDetail.ValueType # 4
+
+class ParticipantKindDetail(_ParticipantKindDetail, metaclass=_ParticipantKindDetailEnumTypeWrapper): ...
+
+PARTICIPANT_KIND_DETAIL_CLOUD_AGENT: ParticipantKindDetail.ValueType # 0
+PARTICIPANT_KIND_DETAIL_FORWARDED: ParticipantKindDetail.ValueType # 1
+PARTICIPANT_KIND_DETAIL_CONNECTOR_WHATSAPP: ParticipantKindDetail.ValueType # 2
+PARTICIPANT_KIND_DETAIL_CONNECTOR_TWILIO: ParticipantKindDetail.ValueType # 3
+PARTICIPANT_KIND_DETAIL_BRIDGE_RTSP: ParticipantKindDetail.ValueType # 4
+global___ParticipantKindDetail = ParticipantKindDetail
+
+class _DisconnectReason:
+ ValueType = typing.NewType("ValueType", builtins.int)
+ V: typing_extensions.TypeAlias = ValueType
+
+class _DisconnectReasonEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_DisconnectReason.ValueType], builtins.type):
+ DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
+ UNKNOWN_REASON: _DisconnectReason.ValueType # 0
+ CLIENT_INITIATED: _DisconnectReason.ValueType # 1
+ """the client initiated the disconnect"""
+ DUPLICATE_IDENTITY: _DisconnectReason.ValueType # 2
+ """another participant with the same identity has joined the room"""
+ SERVER_SHUTDOWN: _DisconnectReason.ValueType # 3
+ """the server instance is shutting down"""
+ PARTICIPANT_REMOVED: _DisconnectReason.ValueType # 4
+ """RoomService.RemoveParticipant was called"""
+ ROOM_DELETED: _DisconnectReason.ValueType # 5
+ """RoomService.DeleteRoom was called"""
+ STATE_MISMATCH: _DisconnectReason.ValueType # 6
+ """the client is attempting to resume a session, but server is not aware of it"""
+ JOIN_FAILURE: _DisconnectReason.ValueType # 7
+ """client was unable to connect fully"""
+ MIGRATION: _DisconnectReason.ValueType # 8
+ """Cloud-only, the server requested Participant to migrate the connection elsewhere"""
+ SIGNAL_CLOSE: _DisconnectReason.ValueType # 9
+ """the signal websocket was closed unexpectedly"""
+ ROOM_CLOSED: _DisconnectReason.ValueType # 10
+ """the room was closed, due to all Standard and Ingress participants having left"""
+ USER_UNAVAILABLE: _DisconnectReason.ValueType # 11
+ """SIP callee did not respond in time"""
+ USER_REJECTED: _DisconnectReason.ValueType # 12
+ """SIP callee rejected the call (busy)"""
+ SIP_TRUNK_FAILURE: _DisconnectReason.ValueType # 13
+ """SIP protocol failure or unexpected response"""
+ CONNECTION_TIMEOUT: _DisconnectReason.ValueType # 14
+ MEDIA_FAILURE: _DisconnectReason.ValueType # 15
+ AGENT_ERROR: _DisconnectReason.ValueType # 16
+
+class DisconnectReason(_DisconnectReason, metaclass=_DisconnectReasonEnumTypeWrapper): ...
+
+UNKNOWN_REASON: DisconnectReason.ValueType # 0
+CLIENT_INITIATED: DisconnectReason.ValueType # 1
+"""the client initiated the disconnect"""
+DUPLICATE_IDENTITY: DisconnectReason.ValueType # 2
+"""another participant with the same identity has joined the room"""
+SERVER_SHUTDOWN: DisconnectReason.ValueType # 3
+"""the server instance is shutting down"""
+PARTICIPANT_REMOVED: DisconnectReason.ValueType # 4
+"""RoomService.RemoveParticipant was called"""
+ROOM_DELETED: DisconnectReason.ValueType # 5
+"""RoomService.DeleteRoom was called"""
+STATE_MISMATCH: DisconnectReason.ValueType # 6
+"""the client is attempting to resume a session, but server is not aware of it"""
+JOIN_FAILURE: DisconnectReason.ValueType # 7
+"""client was unable to connect fully"""
+MIGRATION: DisconnectReason.ValueType # 8
+"""Cloud-only, the server requested Participant to migrate the connection elsewhere"""
+SIGNAL_CLOSE: DisconnectReason.ValueType # 9
+"""the signal websocket was closed unexpectedly"""
+ROOM_CLOSED: DisconnectReason.ValueType # 10
+"""the room was closed, due to all Standard and Ingress participants having left"""
+USER_UNAVAILABLE: DisconnectReason.ValueType # 11
+"""SIP callee did not respond in time"""
+USER_REJECTED: DisconnectReason.ValueType # 12
+"""SIP callee rejected the call (busy)"""
+SIP_TRUNK_FAILURE: DisconnectReason.ValueType # 13
+"""SIP protocol failure or unexpected response"""
+CONNECTION_TIMEOUT: DisconnectReason.ValueType # 14
+MEDIA_FAILURE: DisconnectReason.ValueType # 15
+AGENT_ERROR: DisconnectReason.ValueType # 16
+global___DisconnectReason = DisconnectReason
+
+@typing.final
class ParticipantInfo(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
+ @typing.final
+ class AttributesEntry(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ KEY_FIELD_NUMBER: builtins.int
+ VALUE_FIELD_NUMBER: builtins.int
+ key: builtins.str
+ value: builtins.str
+ def __init__(
+ self,
+ *,
+ key: builtins.str | None = ...,
+ value: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> None: ...
+
SID_FIELD_NUMBER: builtins.int
NAME_FIELD_NUMBER: builtins.int
IDENTITY_FIELD_NUMBER: builtins.int
+ STATE_FIELD_NUMBER: builtins.int
METADATA_FIELD_NUMBER: builtins.int
+ ATTRIBUTES_FIELD_NUMBER: builtins.int
+ KIND_FIELD_NUMBER: builtins.int
+ DISCONNECT_REASON_FIELD_NUMBER: builtins.int
+ JOINED_AT_FIELD_NUMBER: builtins.int
+ KIND_DETAILS_FIELD_NUMBER: builtins.int
+ PERMISSION_FIELD_NUMBER: builtins.int
sid: builtins.str
name: builtins.str
identity: builtins.str
+ state: global___ParticipantState.ValueType
metadata: builtins.str
+ kind: global___ParticipantKind.ValueType
+ disconnect_reason: global___DisconnectReason.ValueType
+ joined_at: builtins.int
+ """ms timestamp of when the participant joined the room, maps to joined_at_ms in livekit_models"""
+ @property
+ def attributes(self) -> google.protobuf.internal.containers.ScalarMap[builtins.str, builtins.str]: ...
+ @property
+ def kind_details(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[global___ParticipantKindDetail.ValueType]: ...
+ @property
+ def permission(self) -> global___ParticipantPermission: ...
def __init__(
self,
*,
- sid: builtins.str = ...,
- name: builtins.str = ...,
- identity: builtins.str = ...,
- metadata: builtins.str = ...,
+ sid: builtins.str | None = ...,
+ name: builtins.str | None = ...,
+ identity: builtins.str | None = ...,
+ state: global___ParticipantState.ValueType | None = ...,
+ metadata: builtins.str | None = ...,
+ attributes: collections.abc.Mapping[builtins.str, builtins.str] | None = ...,
+ kind: global___ParticipantKind.ValueType | None = ...,
+ disconnect_reason: global___DisconnectReason.ValueType | None = ...,
+ joined_at: builtins.int | None = ...,
+ kind_details: collections.abc.Iterable[global___ParticipantKindDetail.ValueType] | None = ...,
+ permission: global___ParticipantPermission | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["identity", b"identity", "metadata", b"metadata", "name", b"name", "sid", b"sid"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["disconnect_reason", b"disconnect_reason", "identity", b"identity", "joined_at", b"joined_at", "kind", b"kind", "metadata", b"metadata", "name", b"name", "permission", b"permission", "sid", b"sid", "state", b"state"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["attributes", b"attributes", "disconnect_reason", b"disconnect_reason", "identity", b"identity", "joined_at", b"joined_at", "kind", b"kind", "kind_details", b"kind_details", "metadata", b"metadata", "name", b"name", "permission", b"permission", "sid", b"sid", "state", b"state"]) -> None: ...
global___ParticipantInfo = ParticipantInfo
-@typing_extensions.final
+@typing.final
class OwnedParticipant(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -68,7 +253,56 @@ class OwnedParticipant(google.protobuf.message.Message):
handle: handle_pb2.FfiOwnedHandle | None = ...,
info: global___ParticipantInfo | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["handle", b"handle", "info", b"info"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["handle", b"handle", "info", b"info"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> None: ...
global___OwnedParticipant = OwnedParticipant
+
+@typing.final
+class ParticipantPermission(google.protobuf.message.Message):
+ """copied from livekit-protocol/protocol/protobufs/livekit_models.proto and removed deprecated fields"""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ CAN_SUBSCRIBE_FIELD_NUMBER: builtins.int
+ CAN_PUBLISH_FIELD_NUMBER: builtins.int
+ CAN_PUBLISH_DATA_FIELD_NUMBER: builtins.int
+ CAN_PUBLISH_SOURCES_FIELD_NUMBER: builtins.int
+ HIDDEN_FIELD_NUMBER: builtins.int
+ CAN_UPDATE_METADATA_FIELD_NUMBER: builtins.int
+ CAN_SUBSCRIBE_METRICS_FIELD_NUMBER: builtins.int
+ CAN_MANAGE_AGENT_SESSION_FIELD_NUMBER: builtins.int
+ can_subscribe: builtins.bool
+ """allow participant to subscribe to other tracks in the room"""
+ can_publish: builtins.bool
+ """allow participant to publish new tracks to room"""
+ can_publish_data: builtins.bool
+ """allow participant to publish data"""
+ hidden: builtins.bool
+ """indicates that it's hidden to others"""
+ can_update_metadata: builtins.bool
+ """indicates that participant can update own metadata and attributes"""
+ can_subscribe_metrics: builtins.bool
+ """if a participant can subscribe to metrics"""
+ can_manage_agent_session: builtins.bool
+ """if a participant can manage an agent session via RemoteSession (control and access state)"""
+ @property
+ def can_publish_sources(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[track_pb2.TrackSource.ValueType]:
+ """sources that are allowed to be published"""
+
+ def __init__(
+ self,
+ *,
+ can_subscribe: builtins.bool | None = ...,
+ can_publish: builtins.bool | None = ...,
+ can_publish_data: builtins.bool | None = ...,
+ can_publish_sources: collections.abc.Iterable[track_pb2.TrackSource.ValueType] | None = ...,
+ hidden: builtins.bool | None = ...,
+ can_update_metadata: builtins.bool | None = ...,
+ can_subscribe_metrics: builtins.bool | None = ...,
+ can_manage_agent_session: builtins.bool | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["can_manage_agent_session", b"can_manage_agent_session", "can_publish", b"can_publish", "can_publish_data", b"can_publish_data", "can_subscribe", b"can_subscribe", "can_subscribe_metrics", b"can_subscribe_metrics", "can_update_metadata", b"can_update_metadata", "hidden", b"hidden"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["can_manage_agent_session", b"can_manage_agent_session", "can_publish", b"can_publish", "can_publish_data", b"can_publish_data", "can_publish_sources", b"can_publish_sources", "can_subscribe", b"can_subscribe", "can_subscribe_metrics", b"can_subscribe_metrics", "can_update_metadata", b"can_update_metadata", "hidden", b"hidden"]) -> None: ...
+
+global___ParticipantPermission = ParticipantPermission
diff --git a/livekit-rtc/livekit/rtc/_proto/room_pb2.py b/livekit-rtc/livekit/rtc/_proto/room_pb2.py
index b320a2f4..bbb9fa6a 100644
--- a/livekit-rtc/livekit/rtc/_proto/room_pb2.py
+++ b/livekit-rtc/livekit/rtc/_proto/room_pb2.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: room.proto
-# Protobuf Python Version: 4.25.3
+# Protobuf Python Version: 4.25.1
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
@@ -18,9 +18,11 @@
from . import track_pb2 as track__pb2
from . import video_frame_pb2 as video__frame__pb2
from . import stats_pb2 as stats__pb2
+from . import data_stream_pb2 as data__stream__pb2
+from . import data_track_pb2 as data__track__pb2
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\nroom.proto\x12\rlivekit.proto\x1a\ne2ee.proto\x1a\x0chandle.proto\x1a\x11participant.proto\x1a\x0btrack.proto\x1a\x11video_frame.proto\x1a\x0bstats.proto\"Y\n\x0e\x43onnectRequest\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\r\n\x05token\x18\x02 \x01(\t\x12+\n\x07options\x18\x03 \x01(\x0b\x32\x1a.livekit.proto.RoomOptions\"#\n\x0f\x43onnectResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x01(\x04\"\xfd\x02\n\x0f\x43onnectCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x01(\x04\x12\x12\n\x05\x65rror\x18\x02 \x01(\tH\x00\x88\x01\x01\x12&\n\x04room\x18\x03 \x01(\x0b\x32\x18.livekit.proto.OwnedRoom\x12:\n\x11local_participant\x18\x04 \x01(\x0b\x32\x1f.livekit.proto.OwnedParticipant\x12J\n\x0cparticipants\x18\x05 \x03(\x0b\x32\x34.livekit.proto.ConnectCallback.ParticipantWithTracks\x1a\x89\x01\n\x15ParticipantWithTracks\x12\x34\n\x0bparticipant\x18\x01 \x01(\x0b\x32\x1f.livekit.proto.OwnedParticipant\x12:\n\x0cpublications\x18\x02 \x03(\x0b\x32$.livekit.proto.OwnedTrackPublicationB\x08\n\x06_error\"(\n\x11\x44isconnectRequest\x12\x13\n\x0broom_handle\x18\x01 \x01(\x04\"&\n\x12\x44isconnectResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x01(\x04\"&\n\x12\x44isconnectCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x01(\x04\"\x82\x01\n\x13PublishTrackRequest\x12 \n\x18local_participant_handle\x18\x01 \x01(\x04\x12\x14\n\x0ctrack_handle\x18\x02 \x01(\x04\x12\x33\n\x07options\x18\x03 \x01(\x0b\x32\".livekit.proto.TrackPublishOptions\"(\n\x14PublishTrackResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x01(\x04\"\x81\x01\n\x14PublishTrackCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x01(\x04\x12\x12\n\x05\x65rror\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x39\n\x0bpublication\x18\x03 \x01(\x0b\x32$.livekit.proto.OwnedTrackPublicationB\x08\n\x06_error\"g\n\x15UnpublishTrackRequest\x12 \n\x18local_participant_handle\x18\x01 \x01(\x04\x12\x11\n\ttrack_sid\x18\x02 \x01(\t\x12\x19\n\x11stop_on_unpublish\x18\x03 \x01(\x08\"*\n\x16UnpublishTrackResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x01(\x04\"H\n\x16UnpublishTrackCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x01(\x04\x12\x12\n\x05\x65rror\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_error\"\xbf\x01\n\x12PublishDataRequest\x12 \n\x18local_participant_handle\x18\x01 \x01(\x04\x12\x10\n\x08\x64\x61ta_ptr\x18\x02 \x01(\x04\x12\x10\n\x08\x64\x61ta_len\x18\x03 \x01(\x04\x12+\n\x04kind\x18\x04 \x01(\x0e\x32\x1d.livekit.proto.DataPacketKind\x12\x18\n\x10\x64\x65stination_sids\x18\x05 \x03(\t\x12\x12\n\x05topic\x18\x06 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_topic\"\'\n\x13PublishDataResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x01(\x04\"E\n\x13PublishDataCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x01(\x04\x12\x12\n\x05\x65rror\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_error\"\xb8\x01\n\x1bPublishTranscriptionRequest\x12 \n\x18local_participant_handle\x18\x01 \x01(\x04\x12\x1c\n\x14participant_identity\x18\x02 \x01(\t\x12\x10\n\x08track_id\x18\x03 \x01(\t\x12\x35\n\x08segments\x18\x04 \x03(\x0b\x32#.livekit.proto.TranscriptionSegment\x12\x10\n\x08language\x18\x05 \x01(\t\"0\n\x1cPublishTranscriptionResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x01(\x04\"N\n\x1cPublishTranscriptionCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x01(\x04\x12\x12\n\x05\x65rror\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_error\"P\n\x1aUpdateLocalMetadataRequest\x12 \n\x18local_participant_handle\x18\x01 \x01(\x04\x12\x10\n\x08metadata\x18\x02 \x01(\t\"/\n\x1bUpdateLocalMetadataResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x01(\x04\"/\n\x1bUpdateLocalMetadataCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x01(\x04\"H\n\x16UpdateLocalNameRequest\x12 \n\x18local_participant_handle\x18\x01 \x01(\x04\x12\x0c\n\x04name\x18\x02 \x01(\t\"+\n\x17UpdateLocalNameResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x01(\x04\"+\n\x17UpdateLocalNameCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x01(\x04\"E\n\x14SetSubscribedRequest\x12\x11\n\tsubscribe\x18\x01 \x01(\x08\x12\x1a\n\x12publication_handle\x18\x02 \x01(\x04\"\x17\n\x15SetSubscribedResponse\"-\n\x16GetSessionStatsRequest\x12\x13\n\x0broom_handle\x18\x01 \x01(\x04\"+\n\x17GetSessionStatsResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x01(\x04\"\xae\x01\n\x17GetSessionStatsCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x01(\x04\x12\x12\n\x05\x65rror\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x30\n\x0fpublisher_stats\x18\x03 \x03(\x0b\x32\x17.livekit.proto.RtcStats\x12\x31\n\x10subscriber_stats\x18\x04 \x03(\x0b\x32\x17.livekit.proto.RtcStatsB\x08\n\x06_error\";\n\rVideoEncoding\x12\x13\n\x0bmax_bitrate\x18\x01 \x01(\x04\x12\x15\n\rmax_framerate\x18\x02 \x01(\x01\"$\n\rAudioEncoding\x12\x13\n\x0bmax_bitrate\x18\x01 \x01(\x04\"\x8a\x02\n\x13TrackPublishOptions\x12\x34\n\x0evideo_encoding\x18\x01 \x01(\x0b\x32\x1c.livekit.proto.VideoEncoding\x12\x34\n\x0e\x61udio_encoding\x18\x02 \x01(\x0b\x32\x1c.livekit.proto.AudioEncoding\x12.\n\x0bvideo_codec\x18\x03 \x01(\x0e\x32\x19.livekit.proto.VideoCodec\x12\x0b\n\x03\x64tx\x18\x04 \x01(\x08\x12\x0b\n\x03red\x18\x05 \x01(\x08\x12\x11\n\tsimulcast\x18\x06 \x01(\x08\x12*\n\x06source\x18\x07 \x01(\x0e\x32\x1a.livekit.proto.TrackSource\"=\n\tIceServer\x12\x0c\n\x04urls\x18\x01 \x03(\t\x12\x10\n\x08username\x18\x02 \x01(\t\x12\x10\n\x08password\x18\x03 \x01(\t\"\x84\x02\n\tRtcConfig\x12@\n\x12ice_transport_type\x18\x01 \x01(\x0e\x32\x1f.livekit.proto.IceTransportTypeH\x00\x88\x01\x01\x12P\n\x1a\x63ontinual_gathering_policy\x18\x02 \x01(\x0e\x32\'.livekit.proto.ContinualGatheringPolicyH\x01\x88\x01\x01\x12-\n\x0bice_servers\x18\x03 \x03(\x0b\x32\x18.livekit.proto.IceServerB\x15\n\x13_ice_transport_typeB\x1d\n\x1b_continual_gathering_policy\"\xe0\x01\n\x0bRoomOptions\x12\x16\n\x0e\x61uto_subscribe\x18\x01 \x01(\x08\x12\x17\n\x0f\x61\x64\x61ptive_stream\x18\x02 \x01(\x08\x12\x10\n\x08\x64ynacast\x18\x03 \x01(\x08\x12-\n\x04\x65\x32\x65\x65\x18\x04 \x01(\x0b\x32\x1a.livekit.proto.E2eeOptionsH\x00\x88\x01\x01\x12\x31\n\nrtc_config\x18\x05 \x01(\x0b\x32\x18.livekit.proto.RtcConfigH\x01\x88\x01\x01\x12\x14\n\x0cjoin_retries\x18\x06 \x01(\rB\x07\n\x05_e2eeB\r\n\x0b_rtc_config\"e\n\x14TranscriptionSegment\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04text\x18\x02 \x01(\t\x12\x12\n\nstart_time\x18\x03 \x01(\x04\x12\x10\n\x08\x65nd_time\x18\x04 \x01(\x04\x12\r\n\x05\x66inal\x18\x05 \x01(\x08\"0\n\nBufferInfo\x12\x10\n\x08\x64\x61ta_ptr\x18\x01 \x01(\x04\x12\x10\n\x08\x64\x61ta_len\x18\x02 \x01(\x04\"e\n\x0bOwnedBuffer\x12-\n\x06handle\x18\x01 \x01(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12\'\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x19.livekit.proto.BufferInfo\"\x80\x0c\n\tRoomEvent\x12\x13\n\x0broom_handle\x18\x01 \x01(\x04\x12\x44\n\x15participant_connected\x18\x02 \x01(\x0b\x32#.livekit.proto.ParticipantConnectedH\x00\x12J\n\x18participant_disconnected\x18\x03 \x01(\x0b\x32&.livekit.proto.ParticipantDisconnectedH\x00\x12\x43\n\x15local_track_published\x18\x04 \x01(\x0b\x32\".livekit.proto.LocalTrackPublishedH\x00\x12G\n\x17local_track_unpublished\x18\x05 \x01(\x0b\x32$.livekit.proto.LocalTrackUnpublishedH\x00\x12\x38\n\x0ftrack_published\x18\x06 \x01(\x0b\x32\x1d.livekit.proto.TrackPublishedH\x00\x12<\n\x11track_unpublished\x18\x07 \x01(\x0b\x32\x1f.livekit.proto.TrackUnpublishedH\x00\x12:\n\x10track_subscribed\x18\x08 \x01(\x0b\x32\x1e.livekit.proto.TrackSubscribedH\x00\x12>\n\x12track_unsubscribed\x18\t \x01(\x0b\x32 .livekit.proto.TrackUnsubscribedH\x00\x12K\n\x19track_subscription_failed\x18\n \x01(\x0b\x32&.livekit.proto.TrackSubscriptionFailedH\x00\x12\x30\n\x0btrack_muted\x18\x0b \x01(\x0b\x32\x19.livekit.proto.TrackMutedH\x00\x12\x34\n\rtrack_unmuted\x18\x0c \x01(\x0b\x32\x1b.livekit.proto.TrackUnmutedH\x00\x12G\n\x17\x61\x63tive_speakers_changed\x18\r \x01(\x0b\x32$.livekit.proto.ActiveSpeakersChangedH\x00\x12\x43\n\x15room_metadata_changed\x18\x0e \x01(\x0b\x32\".livekit.proto.RoomMetadataChangedH\x00\x12Q\n\x1cparticipant_metadata_changed\x18\x0f \x01(\x0b\x32).livekit.proto.ParticipantMetadataChangedH\x00\x12I\n\x18participant_name_changed\x18\x10 \x01(\x0b\x32%.livekit.proto.ParticipantNameChangedH\x00\x12M\n\x1a\x63onnection_quality_changed\x18\x11 \x01(\x0b\x32\'.livekit.proto.ConnectionQualityChangedH\x00\x12I\n\x18\x63onnection_state_changed\x18\x13 \x01(\x0b\x32%.livekit.proto.ConnectionStateChangedH\x00\x12\x33\n\x0c\x64isconnected\x18\x15 \x01(\x0b\x32\x1b.livekit.proto.DisconnectedH\x00\x12\x33\n\x0creconnecting\x18\x16 \x01(\x0b\x32\x1b.livekit.proto.ReconnectingH\x00\x12\x31\n\x0breconnected\x18\x17 \x01(\x0b\x32\x1a.livekit.proto.ReconnectedH\x00\x12=\n\x12\x65\x32\x65\x65_state_changed\x18\x18 \x01(\x0b\x32\x1f.livekit.proto.E2eeStateChangedH\x00\x12%\n\x03\x65os\x18\x19 \x01(\x0b\x32\x16.livekit.proto.RoomEOSH\x00\x12\x41\n\x14\x64\x61ta_packet_received\x18\x1a \x01(\x0b\x32!.livekit.proto.DataPacketReceivedH\x00\x42\t\n\x07message\"7\n\x08RoomInfo\x12\x0b\n\x03sid\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x10\n\x08metadata\x18\x03 \x01(\t\"a\n\tOwnedRoom\x12-\n\x06handle\x18\x01 \x01(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12%\n\x04info\x18\x02 \x01(\x0b\x32\x17.livekit.proto.RoomInfo\"E\n\x14ParticipantConnected\x12-\n\x04info\x18\x01 \x01(\x0b\x32\x1f.livekit.proto.OwnedParticipant\"2\n\x17ParticipantDisconnected\x12\x17\n\x0fparticipant_sid\x18\x01 \x01(\t\"(\n\x13LocalTrackPublished\x12\x11\n\ttrack_sid\x18\x01 \x01(\t\"0\n\x15LocalTrackUnpublished\x12\x17\n\x0fpublication_sid\x18\x01 \x01(\t\"d\n\x0eTrackPublished\x12\x17\n\x0fparticipant_sid\x18\x01 \x01(\t\x12\x39\n\x0bpublication\x18\x02 \x01(\x0b\x32$.livekit.proto.OwnedTrackPublication\"D\n\x10TrackUnpublished\x12\x17\n\x0fparticipant_sid\x18\x01 \x01(\t\x12\x17\n\x0fpublication_sid\x18\x02 \x01(\t\"T\n\x0fTrackSubscribed\x12\x17\n\x0fparticipant_sid\x18\x01 \x01(\t\x12(\n\x05track\x18\x02 \x01(\x0b\x32\x19.livekit.proto.OwnedTrack\"?\n\x11TrackUnsubscribed\x12\x17\n\x0fparticipant_sid\x18\x01 \x01(\t\x12\x11\n\ttrack_sid\x18\x02 \x01(\t\"T\n\x17TrackSubscriptionFailed\x12\x17\n\x0fparticipant_sid\x18\x01 \x01(\t\x12\x11\n\ttrack_sid\x18\x02 \x01(\t\x12\r\n\x05\x65rror\x18\x03 \x01(\t\"8\n\nTrackMuted\x12\x17\n\x0fparticipant_sid\x18\x01 \x01(\t\x12\x11\n\ttrack_sid\x18\x02 \x01(\t\":\n\x0cTrackUnmuted\x12\x17\n\x0fparticipant_sid\x18\x01 \x01(\t\x12\x11\n\ttrack_sid\x18\x02 \x01(\t\"Z\n\x10\x45\x32\x65\x65StateChanged\x12\x17\n\x0fparticipant_sid\x18\x01 \x01(\t\x12-\n\x05state\x18\x02 \x01(\x0e\x32\x1e.livekit.proto.EncryptionState\"1\n\x15\x41\x63tiveSpeakersChanged\x12\x18\n\x10participant_sids\x18\x01 \x03(\t\"\'\n\x13RoomMetadataChanged\x12\x10\n\x08metadata\x18\x01 \x01(\t\"G\n\x1aParticipantMetadataChanged\x12\x17\n\x0fparticipant_sid\x18\x01 \x01(\t\x12\x10\n\x08metadata\x18\x02 \x01(\t\"?\n\x16ParticipantNameChanged\x12\x17\n\x0fparticipant_sid\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\"f\n\x18\x43onnectionQualityChanged\x12\x17\n\x0fparticipant_sid\x18\x01 \x01(\t\x12\x31\n\x07quality\x18\x02 \x01(\x0e\x32 .livekit.proto.ConnectionQuality\"T\n\nUserPacket\x12(\n\x04\x64\x61ta\x18\x01 \x01(\x0b\x32\x1a.livekit.proto.OwnedBuffer\x12\x12\n\x05topic\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_topic\"5\n\x07SipDTMF\x12\x0c\n\x04\x63ode\x18\x01 \x01(\r\x12\x12\n\x05\x64igit\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_digit\"\xf5\x01\n\x12\x44\x61taPacketReceived\x12+\n\x04kind\x18\x01 \x01(\x0e\x32\x1d.livekit.proto.DataPacketKind\x12\x1c\n\x14participant_identity\x18\x02 \x01(\t\x12 \n\x0fparticipant_sid\x18\x03 \x01(\tB\x02\x18\x01H\x01\x88\x01\x01\x12)\n\x04user\x18\x04 \x01(\x0b\x32\x19.livekit.proto.UserPacketH\x00\x12*\n\x08sip_dtmf\x18\x05 \x01(\x0b\x32\x16.livekit.proto.SipDTMFH\x00\x42\x07\n\x05valueB\x12\n\x10_participant_sid\"G\n\x16\x43onnectionStateChanged\x12-\n\x05state\x18\x01 \x01(\x0e\x32\x1e.livekit.proto.ConnectionState\"\x0b\n\tConnected\"\x0e\n\x0c\x44isconnected\"\x0e\n\x0cReconnecting\"\r\n\x0bReconnected\"\t\n\x07RoomEOS*P\n\x10IceTransportType\x12\x13\n\x0fTRANSPORT_RELAY\x10\x00\x12\x14\n\x10TRANSPORT_NOHOST\x10\x01\x12\x11\n\rTRANSPORT_ALL\x10\x02*C\n\x18\x43ontinualGatheringPolicy\x12\x0f\n\x0bGATHER_ONCE\x10\x00\x12\x16\n\x12GATHER_CONTINUALLY\x10\x01*`\n\x11\x43onnectionQuality\x12\x10\n\x0cQUALITY_POOR\x10\x00\x12\x10\n\x0cQUALITY_GOOD\x10\x01\x12\x15\n\x11QUALITY_EXCELLENT\x10\x02\x12\x10\n\x0cQUALITY_LOST\x10\x03*S\n\x0f\x43onnectionState\x12\x15\n\x11\x43ONN_DISCONNECTED\x10\x00\x12\x12\n\x0e\x43ONN_CONNECTED\x10\x01\x12\x15\n\x11\x43ONN_RECONNECTING\x10\x02*3\n\x0e\x44\x61taPacketKind\x12\x0e\n\nKIND_LOSSY\x10\x00\x12\x11\n\rKIND_RELIABLE\x10\x01\x42\x10\xaa\x02\rLiveKit.Protob\x06proto3')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\nroom.proto\x12\rlivekit.proto\x1a\ne2ee.proto\x1a\x0chandle.proto\x1a\x11participant.proto\x1a\x0btrack.proto\x1a\x11video_frame.proto\x1a\x0bstats.proto\x1a\x11\x64\x61ta_stream.proto\x1a\x10\x64\x61ta_track.proto\"s\n\x0e\x43onnectRequest\x12\x0b\n\x03url\x18\x01 \x02(\t\x12\r\n\x05token\x18\x02 \x02(\t\x12+\n\x07options\x18\x03 \x02(\x0b\x32\x1a.livekit.proto.RoomOptions\x12\x18\n\x10request_async_id\x18\x04 \x01(\x04\"#\n\x0f\x43onnectResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"\xbf\x03\n\x0f\x43onnectCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12\x0f\n\x05\x65rror\x18\x02 \x01(\tH\x00\x12\x37\n\x06result\x18\x03 \x01(\x0b\x32%.livekit.proto.ConnectCallback.ResultH\x00\x1a\x89\x01\n\x15ParticipantWithTracks\x12\x34\n\x0bparticipant\x18\x01 \x02(\x0b\x32\x1f.livekit.proto.OwnedParticipant\x12:\n\x0cpublications\x18\x02 \x03(\x0b\x32$.livekit.proto.OwnedTrackPublication\x1a\xb8\x01\n\x06Result\x12&\n\x04room\x18\x01 \x02(\x0b\x32\x18.livekit.proto.OwnedRoom\x12:\n\x11local_participant\x18\x02 \x02(\x0b\x32\x1f.livekit.proto.OwnedParticipant\x12J\n\x0cparticipants\x18\x03 \x03(\x0b\x32\x34.livekit.proto.ConnectCallback.ParticipantWithTracksB\t\n\x07message\"s\n\x11\x44isconnectRequest\x12\x13\n\x0broom_handle\x18\x01 \x02(\x04\x12\x18\n\x10request_async_id\x18\x02 \x01(\x04\x12/\n\x06reason\x18\x03 \x01(\x0e\x32\x1f.livekit.proto.DisconnectReason\"&\n\x12\x44isconnectResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"&\n\x12\x44isconnectCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"\x9c\x01\n\x13PublishTrackRequest\x12 \n\x18local_participant_handle\x18\x01 \x02(\x04\x12\x14\n\x0ctrack_handle\x18\x02 \x02(\x04\x12\x33\n\x07options\x18\x03 \x02(\x0b\x32\".livekit.proto.TrackPublishOptions\x12\x18\n\x10request_async_id\x18\x04 \x01(\x04\"(\n\x14PublishTrackResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"\x81\x01\n\x14PublishTrackCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12\x0f\n\x05\x65rror\x18\x02 \x01(\tH\x00\x12;\n\x0bpublication\x18\x03 \x01(\x0b\x32$.livekit.proto.OwnedTrackPublicationH\x00\x42\t\n\x07message\"\x81\x01\n\x15UnpublishTrackRequest\x12 \n\x18local_participant_handle\x18\x01 \x02(\x04\x12\x11\n\ttrack_sid\x18\x02 \x02(\t\x12\x19\n\x11stop_on_unpublish\x18\x03 \x02(\x08\x12\x18\n\x10request_async_id\x18\x04 \x01(\x04\"*\n\x16UnpublishTrackResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"9\n\x16UnpublishTrackCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"\xd3\x01\n\x12PublishDataRequest\x12 \n\x18local_participant_handle\x18\x01 \x02(\x04\x12\x10\n\x08\x64\x61ta_ptr\x18\x02 \x02(\x04\x12\x10\n\x08\x64\x61ta_len\x18\x03 \x02(\x04\x12\x10\n\x08reliable\x18\x04 \x02(\x08\x12\x1c\n\x10\x64\x65stination_sids\x18\x05 \x03(\tB\x02\x18\x01\x12\r\n\x05topic\x18\x06 \x01(\t\x12\x1e\n\x16\x64\x65stination_identities\x18\x07 \x03(\t\x12\x18\n\x10request_async_id\x18\x08 \x01(\x04\"\'\n\x13PublishDataResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"6\n\x13PublishDataCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"\xc0\x01\n\x1bPublishTranscriptionRequest\x12 \n\x18local_participant_handle\x18\x01 \x02(\x04\x12\x1c\n\x14participant_identity\x18\x02 \x02(\t\x12\x10\n\x08track_id\x18\x03 \x02(\t\x12\x35\n\x08segments\x18\x04 \x03(\x0b\x32#.livekit.proto.TranscriptionSegment\x12\x18\n\x10request_async_id\x18\x05 \x01(\x04\"0\n\x1cPublishTranscriptionResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"?\n\x1cPublishTranscriptionCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"\x90\x01\n\x15PublishSipDtmfRequest\x12 \n\x18local_participant_handle\x18\x01 \x02(\x04\x12\x0c\n\x04\x63ode\x18\x02 \x02(\r\x12\r\n\x05\x64igit\x18\x03 \x02(\t\x12\x1e\n\x16\x64\x65stination_identities\x18\x04 \x03(\t\x12\x18\n\x10request_async_id\x18\x05 \x01(\x04\"*\n\x16PublishSipDtmfResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"9\n\x16PublishSipDtmfCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"g\n\x17SetLocalMetadataRequest\x12 \n\x18local_participant_handle\x18\x01 \x02(\x04\x12\x10\n\x08metadata\x18\x02 \x02(\t\x12\x18\n\x10request_async_id\x18\x03 \x01(\x04\",\n\x18SetLocalMetadataResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\";\n\x18SetLocalMetadataCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"\x9e\x01\n\x16SendChatMessageRequest\x12 \n\x18local_participant_handle\x18\x01 \x02(\x04\x12\x0f\n\x07message\x18\x02 \x02(\t\x12\x1e\n\x16\x64\x65stination_identities\x18\x03 \x03(\t\x12\x17\n\x0fsender_identity\x18\x04 \x01(\t\x12\x18\n\x10request_async_id\x18\x05 \x01(\x04\"\xd6\x01\n\x16\x45\x64itChatMessageRequest\x12 \n\x18local_participant_handle\x18\x01 \x02(\x04\x12\x11\n\tedit_text\x18\x02 \x02(\t\x12\x34\n\x10original_message\x18\x03 \x02(\x0b\x32\x1a.livekit.proto.ChatMessage\x12\x1e\n\x16\x64\x65stination_identities\x18\x04 \x03(\t\x12\x17\n\x0fsender_identity\x18\x05 \x01(\t\x12\x18\n\x10request_async_id\x18\x06 \x01(\x04\"+\n\x17SendChatMessageResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"{\n\x17SendChatMessageCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12\x0f\n\x05\x65rror\x18\x02 \x01(\tH\x00\x12\x32\n\x0c\x63hat_message\x18\x03 \x01(\x0b\x32\x1a.livekit.proto.ChatMessageH\x00\x42\t\n\x07message\"\x8b\x01\n\x19SetLocalAttributesRequest\x12 \n\x18local_participant_handle\x18\x01 \x02(\x04\x12\x32\n\nattributes\x18\x02 \x03(\x0b\x32\x1e.livekit.proto.AttributesEntry\x12\x18\n\x10request_async_id\x18\x03 \x01(\x04\"-\n\x0f\x41ttributesEntry\x12\x0b\n\x03key\x18\x01 \x02(\t\x12\r\n\x05value\x18\x02 \x02(\t\".\n\x1aSetLocalAttributesResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"=\n\x1aSetLocalAttributesCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"_\n\x13SetLocalNameRequest\x12 \n\x18local_participant_handle\x18\x01 \x02(\x04\x12\x0c\n\x04name\x18\x02 \x02(\t\x12\x18\n\x10request_async_id\x18\x03 \x01(\x04\"(\n\x14SetLocalNameResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"7\n\x14SetLocalNameCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"E\n\x14SetSubscribedRequest\x12\x11\n\tsubscribe\x18\x01 \x02(\x08\x12\x1a\n\x12publication_handle\x18\x02 \x02(\x04\"\x17\n\x15SetSubscribedResponse\"G\n\x16GetSessionStatsRequest\x12\x13\n\x0broom_handle\x18\x01 \x02(\x04\x12\x18\n\x10request_async_id\x18\x02 \x01(\x04\"+\n\x17GetSessionStatsResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"\xf7\x01\n\x17GetSessionStatsCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12\x0f\n\x05\x65rror\x18\x02 \x01(\tH\x00\x12?\n\x06result\x18\x03 \x01(\x0b\x32-.livekit.proto.GetSessionStatsCallback.ResultH\x00\x1am\n\x06Result\x12\x30\n\x0fpublisher_stats\x18\x01 \x03(\x0b\x32\x17.livekit.proto.RtcStats\x12\x31\n\x10subscriber_stats\x18\x02 \x03(\x0b\x32\x17.livekit.proto.RtcStatsB\t\n\x07message\";\n\rVideoEncoding\x12\x13\n\x0bmax_bitrate\x18\x01 \x02(\x04\x12\x15\n\rmax_framerate\x18\x02 \x02(\x01\"$\n\rAudioEncoding\x12\x13\n\x0bmax_bitrate\x18\x01 \x02(\x04\"\xfb\x02\n\x13TrackPublishOptions\x12\x34\n\x0evideo_encoding\x18\x01 \x01(\x0b\x32\x1c.livekit.proto.VideoEncoding\x12\x34\n\x0e\x61udio_encoding\x18\x02 \x01(\x0b\x32\x1c.livekit.proto.AudioEncoding\x12.\n\x0bvideo_codec\x18\x03 \x01(\x0e\x32\x19.livekit.proto.VideoCodec\x12\x0b\n\x03\x64tx\x18\x04 \x01(\x08\x12\x0b\n\x03red\x18\x05 \x01(\x08\x12\x11\n\tsimulcast\x18\x06 \x01(\x08\x12*\n\x06source\x18\x07 \x01(\x0e\x32\x1a.livekit.proto.TrackSource\x12\x0e\n\x06stream\x18\x08 \x01(\t\x12\x19\n\x11preconnect_buffer\x18\t \x01(\x08\x12\x44\n\x17packet_trailer_features\x18\n \x03(\x0e\x32#.livekit.proto.PacketTrailerFeature\"=\n\tIceServer\x12\x0c\n\x04urls\x18\x01 \x03(\t\x12\x10\n\x08username\x18\x02 \x01(\t\x12\x10\n\x08password\x18\x03 \x01(\t\"\xc4\x01\n\tRtcConfig\x12;\n\x12ice_transport_type\x18\x01 \x01(\x0e\x32\x1f.livekit.proto.IceTransportType\x12K\n\x1a\x63ontinual_gathering_policy\x18\x02 \x01(\x0e\x32\'.livekit.proto.ContinualGatheringPolicy\x12-\n\x0bice_servers\x18\x03 \x03(\x0b\x32\x18.livekit.proto.IceServer\"\xae\x02\n\x0bRoomOptions\x12\x16\n\x0e\x61uto_subscribe\x18\x01 \x01(\x08\x12\x17\n\x0f\x61\x64\x61ptive_stream\x18\x02 \x01(\x08\x12\x10\n\x08\x64ynacast\x18\x03 \x01(\x08\x12,\n\x04\x65\x32\x65\x65\x18\x04 \x01(\x0b\x32\x1a.livekit.proto.E2eeOptionsB\x02\x18\x01\x12,\n\nrtc_config\x18\x05 \x01(\x0b\x32\x18.livekit.proto.RtcConfig\x12\x14\n\x0cjoin_retries\x18\x06 \x01(\r\x12.\n\nencryption\x18\x07 \x01(\x0b\x32\x1a.livekit.proto.E2eeOptions\x12\x1e\n\x16single_peer_connection\x18\x08 \x01(\x08\x12\x1a\n\x12\x63onnect_timeout_ms\x18\t \x01(\x04\"w\n\x14TranscriptionSegment\x12\n\n\x02id\x18\x01 \x02(\t\x12\x0c\n\x04text\x18\x02 \x02(\t\x12\x12\n\nstart_time\x18\x03 \x02(\x04\x12\x10\n\x08\x65nd_time\x18\x04 \x02(\x04\x12\r\n\x05\x66inal\x18\x05 \x02(\x08\x12\x10\n\x08language\x18\x06 \x02(\t\"0\n\nBufferInfo\x12\x10\n\x08\x64\x61ta_ptr\x18\x01 \x02(\x04\x12\x10\n\x08\x64\x61ta_len\x18\x02 \x02(\x04\"e\n\x0bOwnedBuffer\x12-\n\x06handle\x18\x01 \x02(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12\'\n\x04\x64\x61ta\x18\x02 \x02(\x0b\x32\x19.livekit.proto.BufferInfo\"\x85\x17\n\tRoomEvent\x12\x13\n\x0broom_handle\x18\x01 \x02(\x04\x12\x44\n\x15participant_connected\x18\x02 \x01(\x0b\x32#.livekit.proto.ParticipantConnectedH\x00\x12J\n\x18participant_disconnected\x18\x03 \x01(\x0b\x32&.livekit.proto.ParticipantDisconnectedH\x00\x12\x43\n\x15local_track_published\x18\x04 \x01(\x0b\x32\".livekit.proto.LocalTrackPublishedH\x00\x12G\n\x17local_track_unpublished\x18\x05 \x01(\x0b\x32$.livekit.proto.LocalTrackUnpublishedH\x00\x12\x45\n\x16local_track_subscribed\x18\x06 \x01(\x0b\x32#.livekit.proto.LocalTrackSubscribedH\x00\x12\x38\n\x0ftrack_published\x18\x07 \x01(\x0b\x32\x1d.livekit.proto.TrackPublishedH\x00\x12<\n\x11track_unpublished\x18\x08 \x01(\x0b\x32\x1f.livekit.proto.TrackUnpublishedH\x00\x12:\n\x10track_subscribed\x18\t \x01(\x0b\x32\x1e.livekit.proto.TrackSubscribedH\x00\x12>\n\x12track_unsubscribed\x18\n \x01(\x0b\x32 .livekit.proto.TrackUnsubscribedH\x00\x12K\n\x19track_subscription_failed\x18\x0b \x01(\x0b\x32&.livekit.proto.TrackSubscriptionFailedH\x00\x12\x30\n\x0btrack_muted\x18\x0c \x01(\x0b\x32\x19.livekit.proto.TrackMutedH\x00\x12\x34\n\rtrack_unmuted\x18\r \x01(\x0b\x32\x1b.livekit.proto.TrackUnmutedH\x00\x12G\n\x17\x61\x63tive_speakers_changed\x18\x0e \x01(\x0b\x32$.livekit.proto.ActiveSpeakersChangedH\x00\x12\x43\n\x15room_metadata_changed\x18\x0f \x01(\x0b\x32\".livekit.proto.RoomMetadataChangedH\x00\x12\x39\n\x10room_sid_changed\x18\x10 \x01(\x0b\x32\x1d.livekit.proto.RoomSidChangedH\x00\x12Q\n\x1cparticipant_metadata_changed\x18\x11 \x01(\x0b\x32).livekit.proto.ParticipantMetadataChangedH\x00\x12I\n\x18participant_name_changed\x18\x12 \x01(\x0b\x32%.livekit.proto.ParticipantNameChangedH\x00\x12U\n\x1eparticipant_attributes_changed\x18\x13 \x01(\x0b\x32+.livekit.proto.ParticipantAttributesChangedH\x00\x12M\n\x1a\x63onnection_quality_changed\x18\x14 \x01(\x0b\x32\'.livekit.proto.ConnectionQualityChangedH\x00\x12I\n\x18\x63onnection_state_changed\x18\x15 \x01(\x0b\x32%.livekit.proto.ConnectionStateChangedH\x00\x12\x33\n\x0c\x64isconnected\x18\x16 \x01(\x0b\x32\x1b.livekit.proto.DisconnectedH\x00\x12\x33\n\x0creconnecting\x18\x17 \x01(\x0b\x32\x1b.livekit.proto.ReconnectingH\x00\x12\x31\n\x0breconnected\x18\x18 \x01(\x0b\x32\x1a.livekit.proto.ReconnectedH\x00\x12=\n\x12\x65\x32\x65\x65_state_changed\x18\x19 \x01(\x0b\x32\x1f.livekit.proto.E2eeStateChangedH\x00\x12%\n\x03\x65os\x18\x1a \x01(\x0b\x32\x16.livekit.proto.RoomEOSH\x00\x12\x41\n\x14\x64\x61ta_packet_received\x18\x1b \x01(\x0b\x32!.livekit.proto.DataPacketReceivedH\x00\x12\x46\n\x16transcription_received\x18\x1c \x01(\x0b\x32$.livekit.proto.TranscriptionReceivedH\x00\x12:\n\x0c\x63hat_message\x18\x1d \x01(\x0b\x32\".livekit.proto.ChatMessageReceivedH\x00\x12I\n\x16stream_header_received\x18\x1e \x01(\x0b\x32\'.livekit.proto.DataStreamHeaderReceivedH\x00\x12G\n\x15stream_chunk_received\x18\x1f \x01(\x0b\x32&.livekit.proto.DataStreamChunkReceivedH\x00\x12K\n\x17stream_trailer_received\x18 \x01(\x0b\x32(.livekit.proto.DataStreamTrailerReceivedH\x00\x12i\n\"data_channel_low_threshold_changed\x18! \x01(\x0b\x32;.livekit.proto.DataChannelBufferedAmountLowThresholdChangedH\x00\x12=\n\x12\x62yte_stream_opened\x18\" \x01(\x0b\x32\x1f.livekit.proto.ByteStreamOpenedH\x00\x12=\n\x12text_stream_opened\x18# \x01(\x0b\x32\x1f.livekit.proto.TextStreamOpenedH\x00\x12/\n\x0croom_updated\x18$ \x01(\x0b\x32\x17.livekit.proto.RoomInfoH\x00\x12(\n\x05moved\x18% \x01(\x0b\x32\x17.livekit.proto.RoomInfoH\x00\x12\x42\n\x14participants_updated\x18& \x01(\x0b\x32\".livekit.proto.ParticipantsUpdatedH\x00\x12\x62\n%participant_encryption_status_changed\x18\' \x01(\x0b\x32\x31.livekit.proto.ParticipantEncryptionStatusChangedH\x00\x12U\n\x1eparticipant_permission_changed\x18) \x01(\x0b\x32+.livekit.proto.ParticipantPermissionChangedH\x00\x12\x38\n\x0ftoken_refreshed\x18( \x01(\x0b\x32\x1d.livekit.proto.TokenRefreshedH\x00\x12>\n\x12participant_active\x18* \x01(\x0b\x32 .livekit.proto.ParticipantActiveH\x00\x12\x41\n\x14\x64\x61ta_track_published\x18+ \x01(\x0b\x32!.livekit.proto.DataTrackPublishedH\x00\x12\x45\n\x16\x64\x61ta_track_unpublished\x18, \x01(\x0b\x32#.livekit.proto.DataTrackUnpublishedH\x00\x42\t\n\x07message\"\xc9\x02\n\x08RoomInfo\x12\x0b\n\x03sid\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x02(\t\x12\x10\n\x08metadata\x18\x03 \x02(\t\x12.\n&lossy_dc_buffered_amount_low_threshold\x18\x04 \x02(\x04\x12\x31\n)reliable_dc_buffered_amount_low_threshold\x18\x05 \x02(\x04\x12\x15\n\rempty_timeout\x18\x06 \x02(\r\x12\x19\n\x11\x64\x65parture_timeout\x18\x07 \x02(\r\x12\x18\n\x10max_participants\x18\x08 \x02(\r\x12\x15\n\rcreation_time\x18\t \x02(\x03\x12\x18\n\x10num_participants\x18\n \x02(\r\x12\x16\n\x0enum_publishers\x18\x0b \x02(\r\x12\x18\n\x10\x61\x63tive_recording\x18\x0c \x02(\x08\"a\n\tOwnedRoom\x12-\n\x06handle\x18\x01 \x02(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12%\n\x04info\x18\x02 \x02(\x0b\x32\x17.livekit.proto.RoomInfo\"K\n\x13ParticipantsUpdated\x12\x34\n\x0cparticipants\x18\x01 \x03(\x0b\x32\x1e.livekit.proto.ParticipantInfo\"E\n\x14ParticipantConnected\x12-\n\x04info\x18\x01 \x02(\x0b\x32\x1f.livekit.proto.OwnedParticipant\"1\n\x11ParticipantActive\x12\x1c\n\x14participant_identity\x18\x01 \x02(\t\"s\n\x17ParticipantDisconnected\x12\x1c\n\x14participant_identity\x18\x01 \x02(\t\x12:\n\x11\x64isconnect_reason\x18\x02 \x02(\x0e\x32\x1f.livekit.proto.DisconnectReason\"(\n\x13LocalTrackPublished\x12\x11\n\ttrack_sid\x18\x01 \x02(\t\"0\n\x15LocalTrackUnpublished\x12\x17\n\x0fpublication_sid\x18\x01 \x02(\t\")\n\x14LocalTrackSubscribed\x12\x11\n\ttrack_sid\x18\x02 \x02(\t\"i\n\x0eTrackPublished\x12\x1c\n\x14participant_identity\x18\x01 \x02(\t\x12\x39\n\x0bpublication\x18\x02 \x02(\x0b\x32$.livekit.proto.OwnedTrackPublication\"I\n\x10TrackUnpublished\x12\x1c\n\x14participant_identity\x18\x01 \x02(\t\x12\x17\n\x0fpublication_sid\x18\x02 \x02(\t\"Y\n\x0fTrackSubscribed\x12\x1c\n\x14participant_identity\x18\x01 \x02(\t\x12(\n\x05track\x18\x02 \x02(\x0b\x32\x19.livekit.proto.OwnedTrack\"D\n\x11TrackUnsubscribed\x12\x1c\n\x14participant_identity\x18\x01 \x02(\t\x12\x11\n\ttrack_sid\x18\x02 \x02(\t\"Y\n\x17TrackSubscriptionFailed\x12\x1c\n\x14participant_identity\x18\x01 \x02(\t\x12\x11\n\ttrack_sid\x18\x02 \x02(\t\x12\r\n\x05\x65rror\x18\x03 \x02(\t\"=\n\nTrackMuted\x12\x1c\n\x14participant_identity\x18\x01 \x02(\t\x12\x11\n\ttrack_sid\x18\x02 \x02(\t\"?\n\x0cTrackUnmuted\x12\x1c\n\x14participant_identity\x18\x01 \x02(\t\x12\x11\n\ttrack_sid\x18\x02 \x02(\t\"_\n\x10\x45\x32\x65\x65StateChanged\x12\x1c\n\x14participant_identity\x18\x01 \x02(\t\x12-\n\x05state\x18\x02 \x02(\x0e\x32\x1e.livekit.proto.EncryptionState\"7\n\x15\x41\x63tiveSpeakersChanged\x12\x1e\n\x16participant_identities\x18\x01 \x03(\t\"\'\n\x13RoomMetadataChanged\x12\x10\n\x08metadata\x18\x01 \x02(\t\"\x1d\n\x0eRoomSidChanged\x12\x0b\n\x03sid\x18\x01 \x02(\t\"L\n\x1aParticipantMetadataChanged\x12\x1c\n\x14participant_identity\x18\x01 \x02(\t\x12\x10\n\x08metadata\x18\x02 \x02(\t\"\xac\x01\n\x1cParticipantAttributesChanged\x12\x1c\n\x14participant_identity\x18\x01 \x02(\t\x12\x32\n\nattributes\x18\x02 \x03(\x0b\x32\x1e.livekit.proto.AttributesEntry\x12:\n\x12\x63hanged_attributes\x18\x03 \x03(\x0b\x32\x1e.livekit.proto.AttributesEntry\"X\n\"ParticipantEncryptionStatusChanged\x12\x1c\n\x14participant_identity\x18\x01 \x02(\t\x12\x14\n\x0cis_encrypted\x18\x02 \x02(\x08\"D\n\x16ParticipantNameChanged\x12\x1c\n\x14participant_identity\x18\x01 \x02(\t\x12\x0c\n\x04name\x18\x02 \x02(\t\"v\n\x1cParticipantPermissionChanged\x12\x1c\n\x14participant_identity\x18\x01 \x02(\t\x12\x38\n\npermission\x18\x02 \x01(\x0b\x32$.livekit.proto.ParticipantPermission\"k\n\x18\x43onnectionQualityChanged\x12\x1c\n\x14participant_identity\x18\x01 \x02(\t\x12\x31\n\x07quality\x18\x02 \x02(\x0e\x32 .livekit.proto.ConnectionQuality\"E\n\nUserPacket\x12(\n\x04\x64\x61ta\x18\x01 \x02(\x0b\x32\x1a.livekit.proto.OwnedBuffer\x12\r\n\x05topic\x18\x02 \x01(\t\"y\n\x0b\x43hatMessage\x12\n\n\x02id\x18\x01 \x02(\t\x12\x11\n\ttimestamp\x18\x02 \x02(\x03\x12\x0f\n\x07message\x18\x03 \x02(\t\x12\x16\n\x0e\x65\x64it_timestamp\x18\x04 \x01(\x03\x12\x0f\n\x07\x64\x65leted\x18\x05 \x01(\x08\x12\x11\n\tgenerated\x18\x06 \x01(\x08\"`\n\x13\x43hatMessageReceived\x12+\n\x07message\x18\x01 \x02(\x0b\x32\x1a.livekit.proto.ChatMessage\x12\x1c\n\x14participant_identity\x18\x02 \x02(\t\"&\n\x07SipDTMF\x12\x0c\n\x04\x63ode\x18\x01 \x02(\r\x12\r\n\x05\x64igit\x18\x02 \x01(\t\"\xbf\x01\n\x12\x44\x61taPacketReceived\x12+\n\x04kind\x18\x01 \x02(\x0e\x32\x1d.livekit.proto.DataPacketKind\x12\x1c\n\x14participant_identity\x18\x02 \x02(\t\x12)\n\x04user\x18\x04 \x01(\x0b\x32\x19.livekit.proto.UserPacketH\x00\x12*\n\x08sip_dtmf\x18\x05 \x01(\x0b\x32\x16.livekit.proto.SipDTMFH\x00\x42\x07\n\x05value\"\x7f\n\x15TranscriptionReceived\x12\x1c\n\x14participant_identity\x18\x01 \x01(\t\x12\x11\n\ttrack_sid\x18\x02 \x01(\t\x12\x35\n\x08segments\x18\x03 \x03(\x0b\x32#.livekit.proto.TranscriptionSegment\"G\n\x16\x43onnectionStateChanged\x12-\n\x05state\x18\x01 \x02(\x0e\x32\x1e.livekit.proto.ConnectionState\"\x0b\n\tConnected\"?\n\x0c\x44isconnected\x12/\n\x06reason\x18\x01 \x02(\x0e\x32\x1f.livekit.proto.DisconnectReason\"\x0e\n\x0cReconnecting\"\r\n\x0bReconnected\"\x1f\n\x0eTokenRefreshed\x12\r\n\x05token\x18\x01 \x02(\t\"\t\n\x07RoomEOS\"\x8e\x07\n\nDataStream\x1a\xaa\x01\n\nTextHeader\x12?\n\x0eoperation_type\x18\x01 \x02(\x0e\x32\'.livekit.proto.DataStream.OperationType\x12\x0f\n\x07version\x18\x02 \x01(\x05\x12\x1a\n\x12reply_to_stream_id\x18\x03 \x01(\t\x12\x1b\n\x13\x61ttached_stream_ids\x18\x04 \x03(\t\x12\x11\n\tgenerated\x18\x05 \x01(\x08\x1a\x1a\n\nByteHeader\x12\x0c\n\x04name\x18\x01 \x02(\t\x1a\xeb\x02\n\x06Header\x12\x11\n\tstream_id\x18\x01 \x02(\t\x12\x11\n\ttimestamp\x18\x02 \x02(\x03\x12\x11\n\tmime_type\x18\x03 \x02(\t\x12\r\n\x05topic\x18\x04 \x02(\t\x12\x14\n\x0ctotal_length\x18\x05 \x01(\x04\x12\x44\n\nattributes\x18\x06 \x03(\x0b\x32\x30.livekit.proto.DataStream.Header.AttributesEntry\x12;\n\x0btext_header\x18\x07 \x01(\x0b\x32$.livekit.proto.DataStream.TextHeaderH\x00\x12;\n\x0b\x62yte_header\x18\x08 \x01(\x0b\x32$.livekit.proto.DataStream.ByteHeaderH\x00\x1a\x31\n\x0f\x41ttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\x10\n\x0e\x63ontent_header\x1a]\n\x05\x43hunk\x12\x11\n\tstream_id\x18\x01 \x02(\t\x12\x13\n\x0b\x63hunk_index\x18\x02 \x02(\x04\x12\x0f\n\x07\x63ontent\x18\x03 \x02(\x0c\x12\x0f\n\x07version\x18\x04 \x01(\x05\x12\n\n\x02iv\x18\x05 \x01(\x0c\x1a\xa6\x01\n\x07Trailer\x12\x11\n\tstream_id\x18\x01 \x02(\t\x12\x0e\n\x06reason\x18\x02 \x02(\t\x12\x45\n\nattributes\x18\x03 \x03(\x0b\x32\x31.livekit.proto.DataStream.Trailer.AttributesEntry\x1a\x31\n\x0f\x41ttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"A\n\rOperationType\x12\n\n\x06\x43REATE\x10\x00\x12\n\n\x06UPDATE\x10\x01\x12\n\n\x06\x44\x45LETE\x10\x02\x12\x0c\n\x08REACTION\x10\x03\"j\n\x18\x44\x61taStreamHeaderReceived\x12\x1c\n\x14participant_identity\x18\x01 \x02(\t\x12\x30\n\x06header\x18\x02 \x02(\x0b\x32 .livekit.proto.DataStream.Header\"g\n\x17\x44\x61taStreamChunkReceived\x12\x1c\n\x14participant_identity\x18\x01 \x02(\t\x12.\n\x05\x63hunk\x18\x02 \x02(\x0b\x32\x1f.livekit.proto.DataStream.Chunk\"m\n\x19\x44\x61taStreamTrailerReceived\x12\x1c\n\x14participant_identity\x18\x01 \x02(\t\x12\x32\n\x07trailer\x18\x02 \x02(\x0b\x32!.livekit.proto.DataStream.Trailer\"\xc0\x01\n\x17SendStreamHeaderRequest\x12 \n\x18local_participant_handle\x18\x01 \x02(\x04\x12\x30\n\x06header\x18\x02 \x02(\x0b\x32 .livekit.proto.DataStream.Header\x12\x1e\n\x16\x64\x65stination_identities\x18\x03 \x03(\t\x12\x17\n\x0fsender_identity\x18\x04 \x02(\t\x12\x18\n\x10request_async_id\x18\x05 \x01(\x04\"\xbd\x01\n\x16SendStreamChunkRequest\x12 \n\x18local_participant_handle\x18\x01 \x02(\x04\x12.\n\x05\x63hunk\x18\x02 \x02(\x0b\x32\x1f.livekit.proto.DataStream.Chunk\x12\x1e\n\x16\x64\x65stination_identities\x18\x03 \x03(\t\x12\x17\n\x0fsender_identity\x18\x04 \x02(\t\x12\x18\n\x10request_async_id\x18\x05 \x01(\x04\"\xc3\x01\n\x18SendStreamTrailerRequest\x12 \n\x18local_participant_handle\x18\x01 \x02(\x04\x12\x32\n\x07trailer\x18\x02 \x02(\x0b\x32!.livekit.proto.DataStream.Trailer\x12\x1e\n\x16\x64\x65stination_identities\x18\x03 \x03(\t\x12\x17\n\x0fsender_identity\x18\x04 \x02(\t\x12\x18\n\x10request_async_id\x18\x05 \x01(\x04\",\n\x18SendStreamHeaderResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"+\n\x17SendStreamChunkResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"-\n\x19SendStreamTrailerResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\";\n\x18SendStreamHeaderCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12\r\n\x05\x65rror\x18\x02 \x01(\t\":\n\x17SendStreamChunkCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"<\n\x19SendStreamTrailerCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"\x93\x01\n/SetDataChannelBufferedAmountLowThresholdRequest\x12 \n\x18local_participant_handle\x18\x01 \x02(\x04\x12\x11\n\tthreshold\x18\x02 \x02(\x04\x12+\n\x04kind\x18\x03 \x02(\x0e\x32\x1d.livekit.proto.DataPacketKind\"2\n0SetDataChannelBufferedAmountLowThresholdResponse\"n\n,DataChannelBufferedAmountLowThresholdChanged\x12+\n\x04kind\x18\x01 \x02(\x0e\x32\x1d.livekit.proto.DataPacketKind\x12\x11\n\tthreshold\x18\x02 \x02(\x04\"f\n\x10\x42yteStreamOpened\x12\x34\n\x06reader\x18\x01 \x02(\x0b\x32$.livekit.proto.OwnedByteStreamReader\x12\x1c\n\x14participant_identity\x18\x02 \x02(\t\"f\n\x10TextStreamOpened\x12\x34\n\x06reader\x18\x01 \x02(\x0b\x32$.livekit.proto.OwnedTextStreamReader\x12\x1c\n\x14participant_identity\x18\x02 \x02(\t\"H\n\x12\x44\x61taTrackPublished\x12\x32\n\x05track\x18\x01 \x02(\x0b\x32#.livekit.proto.OwnedRemoteDataTrack\"#\n\x14\x44\x61taTrackUnpublished\x12\x0b\n\x03sid\x18\x01 \x02(\t*P\n\x10IceTransportType\x12\x13\n\x0fTRANSPORT_RELAY\x10\x00\x12\x14\n\x10TRANSPORT_NOHOST\x10\x01\x12\x11\n\rTRANSPORT_ALL\x10\x02*C\n\x18\x43ontinualGatheringPolicy\x12\x0f\n\x0bGATHER_ONCE\x10\x00\x12\x16\n\x12GATHER_CONTINUALLY\x10\x01*`\n\x11\x43onnectionQuality\x12\x10\n\x0cQUALITY_POOR\x10\x00\x12\x10\n\x0cQUALITY_GOOD\x10\x01\x12\x15\n\x11QUALITY_EXCELLENT\x10\x02\x12\x10\n\x0cQUALITY_LOST\x10\x03*S\n\x0f\x43onnectionState\x12\x15\n\x11\x43ONN_DISCONNECTED\x10\x00\x12\x12\n\x0e\x43ONN_CONNECTED\x10\x01\x12\x15\n\x11\x43ONN_RECONNECTING\x10\x02*3\n\x0e\x44\x61taPacketKind\x12\x0e\n\nKIND_LOSSY\x10\x00\x12\x11\n\rKIND_RELIABLE\x10\x01\x42\x10\xaa\x02\rLiveKit.Proto')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -28,152 +30,262 @@
if _descriptor._USE_C_DESCRIPTORS == False:
_globals['DESCRIPTOR']._options = None
_globals['DESCRIPTOR']._serialized_options = b'\252\002\rLiveKit.Proto'
- _globals['_DATAPACKETRECEIVED'].fields_by_name['participant_sid']._options = None
- _globals['_DATAPACKETRECEIVED'].fields_by_name['participant_sid']._serialized_options = b'\030\001'
- _globals['_ICETRANSPORTTYPE']._serialized_start=7188
- _globals['_ICETRANSPORTTYPE']._serialized_end=7268
- _globals['_CONTINUALGATHERINGPOLICY']._serialized_start=7270
- _globals['_CONTINUALGATHERINGPOLICY']._serialized_end=7337
- _globals['_CONNECTIONQUALITY']._serialized_start=7339
- _globals['_CONNECTIONQUALITY']._serialized_end=7435
- _globals['_CONNECTIONSTATE']._serialized_start=7437
- _globals['_CONNECTIONSTATE']._serialized_end=7520
- _globals['_DATAPACKETKIND']._serialized_start=7522
- _globals['_DATAPACKETKIND']._serialized_end=7573
- _globals['_CONNECTREQUEST']._serialized_start=119
- _globals['_CONNECTREQUEST']._serialized_end=208
- _globals['_CONNECTRESPONSE']._serialized_start=210
- _globals['_CONNECTRESPONSE']._serialized_end=245
- _globals['_CONNECTCALLBACK']._serialized_start=248
- _globals['_CONNECTCALLBACK']._serialized_end=629
- _globals['_CONNECTCALLBACK_PARTICIPANTWITHTRACKS']._serialized_start=482
- _globals['_CONNECTCALLBACK_PARTICIPANTWITHTRACKS']._serialized_end=619
- _globals['_DISCONNECTREQUEST']._serialized_start=631
- _globals['_DISCONNECTREQUEST']._serialized_end=671
- _globals['_DISCONNECTRESPONSE']._serialized_start=673
- _globals['_DISCONNECTRESPONSE']._serialized_end=711
- _globals['_DISCONNECTCALLBACK']._serialized_start=713
- _globals['_DISCONNECTCALLBACK']._serialized_end=751
- _globals['_PUBLISHTRACKREQUEST']._serialized_start=754
- _globals['_PUBLISHTRACKREQUEST']._serialized_end=884
- _globals['_PUBLISHTRACKRESPONSE']._serialized_start=886
- _globals['_PUBLISHTRACKRESPONSE']._serialized_end=926
- _globals['_PUBLISHTRACKCALLBACK']._serialized_start=929
- _globals['_PUBLISHTRACKCALLBACK']._serialized_end=1058
- _globals['_UNPUBLISHTRACKREQUEST']._serialized_start=1060
- _globals['_UNPUBLISHTRACKREQUEST']._serialized_end=1163
- _globals['_UNPUBLISHTRACKRESPONSE']._serialized_start=1165
- _globals['_UNPUBLISHTRACKRESPONSE']._serialized_end=1207
- _globals['_UNPUBLISHTRACKCALLBACK']._serialized_start=1209
- _globals['_UNPUBLISHTRACKCALLBACK']._serialized_end=1281
- _globals['_PUBLISHDATAREQUEST']._serialized_start=1284
- _globals['_PUBLISHDATAREQUEST']._serialized_end=1475
- _globals['_PUBLISHDATARESPONSE']._serialized_start=1477
- _globals['_PUBLISHDATARESPONSE']._serialized_end=1516
- _globals['_PUBLISHDATACALLBACK']._serialized_start=1518
- _globals['_PUBLISHDATACALLBACK']._serialized_end=1587
- _globals['_PUBLISHTRANSCRIPTIONREQUEST']._serialized_start=1590
- _globals['_PUBLISHTRANSCRIPTIONREQUEST']._serialized_end=1774
- _globals['_PUBLISHTRANSCRIPTIONRESPONSE']._serialized_start=1776
- _globals['_PUBLISHTRANSCRIPTIONRESPONSE']._serialized_end=1824
- _globals['_PUBLISHTRANSCRIPTIONCALLBACK']._serialized_start=1826
- _globals['_PUBLISHTRANSCRIPTIONCALLBACK']._serialized_end=1904
- _globals['_UPDATELOCALMETADATAREQUEST']._serialized_start=1906
- _globals['_UPDATELOCALMETADATAREQUEST']._serialized_end=1986
- _globals['_UPDATELOCALMETADATARESPONSE']._serialized_start=1988
- _globals['_UPDATELOCALMETADATARESPONSE']._serialized_end=2035
- _globals['_UPDATELOCALMETADATACALLBACK']._serialized_start=2037
- _globals['_UPDATELOCALMETADATACALLBACK']._serialized_end=2084
- _globals['_UPDATELOCALNAMEREQUEST']._serialized_start=2086
- _globals['_UPDATELOCALNAMEREQUEST']._serialized_end=2158
- _globals['_UPDATELOCALNAMERESPONSE']._serialized_start=2160
- _globals['_UPDATELOCALNAMERESPONSE']._serialized_end=2203
- _globals['_UPDATELOCALNAMECALLBACK']._serialized_start=2205
- _globals['_UPDATELOCALNAMECALLBACK']._serialized_end=2248
- _globals['_SETSUBSCRIBEDREQUEST']._serialized_start=2250
- _globals['_SETSUBSCRIBEDREQUEST']._serialized_end=2319
- _globals['_SETSUBSCRIBEDRESPONSE']._serialized_start=2321
- _globals['_SETSUBSCRIBEDRESPONSE']._serialized_end=2344
- _globals['_GETSESSIONSTATSREQUEST']._serialized_start=2346
- _globals['_GETSESSIONSTATSREQUEST']._serialized_end=2391
- _globals['_GETSESSIONSTATSRESPONSE']._serialized_start=2393
- _globals['_GETSESSIONSTATSRESPONSE']._serialized_end=2436
- _globals['_GETSESSIONSTATSCALLBACK']._serialized_start=2439
- _globals['_GETSESSIONSTATSCALLBACK']._serialized_end=2613
- _globals['_VIDEOENCODING']._serialized_start=2615
- _globals['_VIDEOENCODING']._serialized_end=2674
- _globals['_AUDIOENCODING']._serialized_start=2676
- _globals['_AUDIOENCODING']._serialized_end=2712
- _globals['_TRACKPUBLISHOPTIONS']._serialized_start=2715
- _globals['_TRACKPUBLISHOPTIONS']._serialized_end=2981
- _globals['_ICESERVER']._serialized_start=2983
- _globals['_ICESERVER']._serialized_end=3044
- _globals['_RTCCONFIG']._serialized_start=3047
- _globals['_RTCCONFIG']._serialized_end=3307
- _globals['_ROOMOPTIONS']._serialized_start=3310
- _globals['_ROOMOPTIONS']._serialized_end=3534
- _globals['_TRANSCRIPTIONSEGMENT']._serialized_start=3536
- _globals['_TRANSCRIPTIONSEGMENT']._serialized_end=3637
- _globals['_BUFFERINFO']._serialized_start=3639
- _globals['_BUFFERINFO']._serialized_end=3687
- _globals['_OWNEDBUFFER']._serialized_start=3689
- _globals['_OWNEDBUFFER']._serialized_end=3790
- _globals['_ROOMEVENT']._serialized_start=3793
- _globals['_ROOMEVENT']._serialized_end=5329
- _globals['_ROOMINFO']._serialized_start=5331
- _globals['_ROOMINFO']._serialized_end=5386
- _globals['_OWNEDROOM']._serialized_start=5388
- _globals['_OWNEDROOM']._serialized_end=5485
- _globals['_PARTICIPANTCONNECTED']._serialized_start=5487
- _globals['_PARTICIPANTCONNECTED']._serialized_end=5556
- _globals['_PARTICIPANTDISCONNECTED']._serialized_start=5558
- _globals['_PARTICIPANTDISCONNECTED']._serialized_end=5608
- _globals['_LOCALTRACKPUBLISHED']._serialized_start=5610
- _globals['_LOCALTRACKPUBLISHED']._serialized_end=5650
- _globals['_LOCALTRACKUNPUBLISHED']._serialized_start=5652
- _globals['_LOCALTRACKUNPUBLISHED']._serialized_end=5700
- _globals['_TRACKPUBLISHED']._serialized_start=5702
- _globals['_TRACKPUBLISHED']._serialized_end=5802
- _globals['_TRACKUNPUBLISHED']._serialized_start=5804
- _globals['_TRACKUNPUBLISHED']._serialized_end=5872
- _globals['_TRACKSUBSCRIBED']._serialized_start=5874
- _globals['_TRACKSUBSCRIBED']._serialized_end=5958
- _globals['_TRACKUNSUBSCRIBED']._serialized_start=5960
- _globals['_TRACKUNSUBSCRIBED']._serialized_end=6023
- _globals['_TRACKSUBSCRIPTIONFAILED']._serialized_start=6025
- _globals['_TRACKSUBSCRIPTIONFAILED']._serialized_end=6109
- _globals['_TRACKMUTED']._serialized_start=6111
- _globals['_TRACKMUTED']._serialized_end=6167
- _globals['_TRACKUNMUTED']._serialized_start=6169
- _globals['_TRACKUNMUTED']._serialized_end=6227
- _globals['_E2EESTATECHANGED']._serialized_start=6229
- _globals['_E2EESTATECHANGED']._serialized_end=6319
- _globals['_ACTIVESPEAKERSCHANGED']._serialized_start=6321
- _globals['_ACTIVESPEAKERSCHANGED']._serialized_end=6370
- _globals['_ROOMMETADATACHANGED']._serialized_start=6372
- _globals['_ROOMMETADATACHANGED']._serialized_end=6411
- _globals['_PARTICIPANTMETADATACHANGED']._serialized_start=6413
- _globals['_PARTICIPANTMETADATACHANGED']._serialized_end=6484
- _globals['_PARTICIPANTNAMECHANGED']._serialized_start=6486
- _globals['_PARTICIPANTNAMECHANGED']._serialized_end=6549
- _globals['_CONNECTIONQUALITYCHANGED']._serialized_start=6551
- _globals['_CONNECTIONQUALITYCHANGED']._serialized_end=6653
- _globals['_USERPACKET']._serialized_start=6655
- _globals['_USERPACKET']._serialized_end=6739
- _globals['_SIPDTMF']._serialized_start=6741
- _globals['_SIPDTMF']._serialized_end=6794
- _globals['_DATAPACKETRECEIVED']._serialized_start=6797
- _globals['_DATAPACKETRECEIVED']._serialized_end=7042
- _globals['_CONNECTIONSTATECHANGED']._serialized_start=7044
- _globals['_CONNECTIONSTATECHANGED']._serialized_end=7115
- _globals['_CONNECTED']._serialized_start=7117
- _globals['_CONNECTED']._serialized_end=7128
- _globals['_DISCONNECTED']._serialized_start=7130
- _globals['_DISCONNECTED']._serialized_end=7144
- _globals['_RECONNECTING']._serialized_start=7146
- _globals['_RECONNECTING']._serialized_end=7160
- _globals['_RECONNECTED']._serialized_start=7162
- _globals['_RECONNECTED']._serialized_end=7175
- _globals['_ROOMEOS']._serialized_start=7177
- _globals['_ROOMEOS']._serialized_end=7186
+ _globals['_PUBLISHDATAREQUEST'].fields_by_name['destination_sids']._options = None
+ _globals['_PUBLISHDATAREQUEST'].fields_by_name['destination_sids']._serialized_options = b'\030\001'
+ _globals['_ROOMOPTIONS'].fields_by_name['e2ee']._options = None
+ _globals['_ROOMOPTIONS'].fields_by_name['e2ee']._serialized_options = b'\030\001'
+ _globals['_DATASTREAM_HEADER_ATTRIBUTESENTRY']._options = None
+ _globals['_DATASTREAM_HEADER_ATTRIBUTESENTRY']._serialized_options = b'8\001'
+ _globals['_DATASTREAM_TRAILER_ATTRIBUTESENTRY']._options = None
+ _globals['_DATASTREAM_TRAILER_ATTRIBUTESENTRY']._serialized_options = b'8\001'
+ _globals['_ICETRANSPORTTYPE']._serialized_start=14359
+ _globals['_ICETRANSPORTTYPE']._serialized_end=14439
+ _globals['_CONTINUALGATHERINGPOLICY']._serialized_start=14441
+ _globals['_CONTINUALGATHERINGPOLICY']._serialized_end=14508
+ _globals['_CONNECTIONQUALITY']._serialized_start=14510
+ _globals['_CONNECTIONQUALITY']._serialized_end=14606
+ _globals['_CONNECTIONSTATE']._serialized_start=14608
+ _globals['_CONNECTIONSTATE']._serialized_end=14691
+ _globals['_DATAPACKETKIND']._serialized_start=14693
+ _globals['_DATAPACKETKIND']._serialized_end=14744
+ _globals['_CONNECTREQUEST']._serialized_start=156
+ _globals['_CONNECTREQUEST']._serialized_end=271
+ _globals['_CONNECTRESPONSE']._serialized_start=273
+ _globals['_CONNECTRESPONSE']._serialized_end=308
+ _globals['_CONNECTCALLBACK']._serialized_start=311
+ _globals['_CONNECTCALLBACK']._serialized_end=758
+ _globals['_CONNECTCALLBACK_PARTICIPANTWITHTRACKS']._serialized_start=423
+ _globals['_CONNECTCALLBACK_PARTICIPANTWITHTRACKS']._serialized_end=560
+ _globals['_CONNECTCALLBACK_RESULT']._serialized_start=563
+ _globals['_CONNECTCALLBACK_RESULT']._serialized_end=747
+ _globals['_DISCONNECTREQUEST']._serialized_start=760
+ _globals['_DISCONNECTREQUEST']._serialized_end=875
+ _globals['_DISCONNECTRESPONSE']._serialized_start=877
+ _globals['_DISCONNECTRESPONSE']._serialized_end=915
+ _globals['_DISCONNECTCALLBACK']._serialized_start=917
+ _globals['_DISCONNECTCALLBACK']._serialized_end=955
+ _globals['_PUBLISHTRACKREQUEST']._serialized_start=958
+ _globals['_PUBLISHTRACKREQUEST']._serialized_end=1114
+ _globals['_PUBLISHTRACKRESPONSE']._serialized_start=1116
+ _globals['_PUBLISHTRACKRESPONSE']._serialized_end=1156
+ _globals['_PUBLISHTRACKCALLBACK']._serialized_start=1159
+ _globals['_PUBLISHTRACKCALLBACK']._serialized_end=1288
+ _globals['_UNPUBLISHTRACKREQUEST']._serialized_start=1291
+ _globals['_UNPUBLISHTRACKREQUEST']._serialized_end=1420
+ _globals['_UNPUBLISHTRACKRESPONSE']._serialized_start=1422
+ _globals['_UNPUBLISHTRACKRESPONSE']._serialized_end=1464
+ _globals['_UNPUBLISHTRACKCALLBACK']._serialized_start=1466
+ _globals['_UNPUBLISHTRACKCALLBACK']._serialized_end=1523
+ _globals['_PUBLISHDATAREQUEST']._serialized_start=1526
+ _globals['_PUBLISHDATAREQUEST']._serialized_end=1737
+ _globals['_PUBLISHDATARESPONSE']._serialized_start=1739
+ _globals['_PUBLISHDATARESPONSE']._serialized_end=1778
+ _globals['_PUBLISHDATACALLBACK']._serialized_start=1780
+ _globals['_PUBLISHDATACALLBACK']._serialized_end=1834
+ _globals['_PUBLISHTRANSCRIPTIONREQUEST']._serialized_start=1837
+ _globals['_PUBLISHTRANSCRIPTIONREQUEST']._serialized_end=2029
+ _globals['_PUBLISHTRANSCRIPTIONRESPONSE']._serialized_start=2031
+ _globals['_PUBLISHTRANSCRIPTIONRESPONSE']._serialized_end=2079
+ _globals['_PUBLISHTRANSCRIPTIONCALLBACK']._serialized_start=2081
+ _globals['_PUBLISHTRANSCRIPTIONCALLBACK']._serialized_end=2144
+ _globals['_PUBLISHSIPDTMFREQUEST']._serialized_start=2147
+ _globals['_PUBLISHSIPDTMFREQUEST']._serialized_end=2291
+ _globals['_PUBLISHSIPDTMFRESPONSE']._serialized_start=2293
+ _globals['_PUBLISHSIPDTMFRESPONSE']._serialized_end=2335
+ _globals['_PUBLISHSIPDTMFCALLBACK']._serialized_start=2337
+ _globals['_PUBLISHSIPDTMFCALLBACK']._serialized_end=2394
+ _globals['_SETLOCALMETADATAREQUEST']._serialized_start=2396
+ _globals['_SETLOCALMETADATAREQUEST']._serialized_end=2499
+ _globals['_SETLOCALMETADATARESPONSE']._serialized_start=2501
+ _globals['_SETLOCALMETADATARESPONSE']._serialized_end=2545
+ _globals['_SETLOCALMETADATACALLBACK']._serialized_start=2547
+ _globals['_SETLOCALMETADATACALLBACK']._serialized_end=2606
+ _globals['_SENDCHATMESSAGEREQUEST']._serialized_start=2609
+ _globals['_SENDCHATMESSAGEREQUEST']._serialized_end=2767
+ _globals['_EDITCHATMESSAGEREQUEST']._serialized_start=2770
+ _globals['_EDITCHATMESSAGEREQUEST']._serialized_end=2984
+ _globals['_SENDCHATMESSAGERESPONSE']._serialized_start=2986
+ _globals['_SENDCHATMESSAGERESPONSE']._serialized_end=3029
+ _globals['_SENDCHATMESSAGECALLBACK']._serialized_start=3031
+ _globals['_SENDCHATMESSAGECALLBACK']._serialized_end=3154
+ _globals['_SETLOCALATTRIBUTESREQUEST']._serialized_start=3157
+ _globals['_SETLOCALATTRIBUTESREQUEST']._serialized_end=3296
+ _globals['_ATTRIBUTESENTRY']._serialized_start=3298
+ _globals['_ATTRIBUTESENTRY']._serialized_end=3343
+ _globals['_SETLOCALATTRIBUTESRESPONSE']._serialized_start=3345
+ _globals['_SETLOCALATTRIBUTESRESPONSE']._serialized_end=3391
+ _globals['_SETLOCALATTRIBUTESCALLBACK']._serialized_start=3393
+ _globals['_SETLOCALATTRIBUTESCALLBACK']._serialized_end=3454
+ _globals['_SETLOCALNAMEREQUEST']._serialized_start=3456
+ _globals['_SETLOCALNAMEREQUEST']._serialized_end=3551
+ _globals['_SETLOCALNAMERESPONSE']._serialized_start=3553
+ _globals['_SETLOCALNAMERESPONSE']._serialized_end=3593
+ _globals['_SETLOCALNAMECALLBACK']._serialized_start=3595
+ _globals['_SETLOCALNAMECALLBACK']._serialized_end=3650
+ _globals['_SETSUBSCRIBEDREQUEST']._serialized_start=3652
+ _globals['_SETSUBSCRIBEDREQUEST']._serialized_end=3721
+ _globals['_SETSUBSCRIBEDRESPONSE']._serialized_start=3723
+ _globals['_SETSUBSCRIBEDRESPONSE']._serialized_end=3746
+ _globals['_GETSESSIONSTATSREQUEST']._serialized_start=3748
+ _globals['_GETSESSIONSTATSREQUEST']._serialized_end=3819
+ _globals['_GETSESSIONSTATSRESPONSE']._serialized_start=3821
+ _globals['_GETSESSIONSTATSRESPONSE']._serialized_end=3864
+ _globals['_GETSESSIONSTATSCALLBACK']._serialized_start=3867
+ _globals['_GETSESSIONSTATSCALLBACK']._serialized_end=4114
+ _globals['_GETSESSIONSTATSCALLBACK_RESULT']._serialized_start=3994
+ _globals['_GETSESSIONSTATSCALLBACK_RESULT']._serialized_end=4103
+ _globals['_VIDEOENCODING']._serialized_start=4116
+ _globals['_VIDEOENCODING']._serialized_end=4175
+ _globals['_AUDIOENCODING']._serialized_start=4177
+ _globals['_AUDIOENCODING']._serialized_end=4213
+ _globals['_TRACKPUBLISHOPTIONS']._serialized_start=4216
+ _globals['_TRACKPUBLISHOPTIONS']._serialized_end=4595
+ _globals['_ICESERVER']._serialized_start=4597
+ _globals['_ICESERVER']._serialized_end=4658
+ _globals['_RTCCONFIG']._serialized_start=4661
+ _globals['_RTCCONFIG']._serialized_end=4857
+ _globals['_ROOMOPTIONS']._serialized_start=4860
+ _globals['_ROOMOPTIONS']._serialized_end=5162
+ _globals['_TRANSCRIPTIONSEGMENT']._serialized_start=5164
+ _globals['_TRANSCRIPTIONSEGMENT']._serialized_end=5283
+ _globals['_BUFFERINFO']._serialized_start=5285
+ _globals['_BUFFERINFO']._serialized_end=5333
+ _globals['_OWNEDBUFFER']._serialized_start=5335
+ _globals['_OWNEDBUFFER']._serialized_end=5436
+ _globals['_ROOMEVENT']._serialized_start=5439
+ _globals['_ROOMEVENT']._serialized_end=8388
+ _globals['_ROOMINFO']._serialized_start=8391
+ _globals['_ROOMINFO']._serialized_end=8720
+ _globals['_OWNEDROOM']._serialized_start=8722
+ _globals['_OWNEDROOM']._serialized_end=8819
+ _globals['_PARTICIPANTSUPDATED']._serialized_start=8821
+ _globals['_PARTICIPANTSUPDATED']._serialized_end=8896
+ _globals['_PARTICIPANTCONNECTED']._serialized_start=8898
+ _globals['_PARTICIPANTCONNECTED']._serialized_end=8967
+ _globals['_PARTICIPANTACTIVE']._serialized_start=8969
+ _globals['_PARTICIPANTACTIVE']._serialized_end=9018
+ _globals['_PARTICIPANTDISCONNECTED']._serialized_start=9020
+ _globals['_PARTICIPANTDISCONNECTED']._serialized_end=9135
+ _globals['_LOCALTRACKPUBLISHED']._serialized_start=9137
+ _globals['_LOCALTRACKPUBLISHED']._serialized_end=9177
+ _globals['_LOCALTRACKUNPUBLISHED']._serialized_start=9179
+ _globals['_LOCALTRACKUNPUBLISHED']._serialized_end=9227
+ _globals['_LOCALTRACKSUBSCRIBED']._serialized_start=9229
+ _globals['_LOCALTRACKSUBSCRIBED']._serialized_end=9270
+ _globals['_TRACKPUBLISHED']._serialized_start=9272
+ _globals['_TRACKPUBLISHED']._serialized_end=9377
+ _globals['_TRACKUNPUBLISHED']._serialized_start=9379
+ _globals['_TRACKUNPUBLISHED']._serialized_end=9452
+ _globals['_TRACKSUBSCRIBED']._serialized_start=9454
+ _globals['_TRACKSUBSCRIBED']._serialized_end=9543
+ _globals['_TRACKUNSUBSCRIBED']._serialized_start=9545
+ _globals['_TRACKUNSUBSCRIBED']._serialized_end=9613
+ _globals['_TRACKSUBSCRIPTIONFAILED']._serialized_start=9615
+ _globals['_TRACKSUBSCRIPTIONFAILED']._serialized_end=9704
+ _globals['_TRACKMUTED']._serialized_start=9706
+ _globals['_TRACKMUTED']._serialized_end=9767
+ _globals['_TRACKUNMUTED']._serialized_start=9769
+ _globals['_TRACKUNMUTED']._serialized_end=9832
+ _globals['_E2EESTATECHANGED']._serialized_start=9834
+ _globals['_E2EESTATECHANGED']._serialized_end=9929
+ _globals['_ACTIVESPEAKERSCHANGED']._serialized_start=9931
+ _globals['_ACTIVESPEAKERSCHANGED']._serialized_end=9986
+ _globals['_ROOMMETADATACHANGED']._serialized_start=9988
+ _globals['_ROOMMETADATACHANGED']._serialized_end=10027
+ _globals['_ROOMSIDCHANGED']._serialized_start=10029
+ _globals['_ROOMSIDCHANGED']._serialized_end=10058
+ _globals['_PARTICIPANTMETADATACHANGED']._serialized_start=10060
+ _globals['_PARTICIPANTMETADATACHANGED']._serialized_end=10136
+ _globals['_PARTICIPANTATTRIBUTESCHANGED']._serialized_start=10139
+ _globals['_PARTICIPANTATTRIBUTESCHANGED']._serialized_end=10311
+ _globals['_PARTICIPANTENCRYPTIONSTATUSCHANGED']._serialized_start=10313
+ _globals['_PARTICIPANTENCRYPTIONSTATUSCHANGED']._serialized_end=10401
+ _globals['_PARTICIPANTNAMECHANGED']._serialized_start=10403
+ _globals['_PARTICIPANTNAMECHANGED']._serialized_end=10471
+ _globals['_PARTICIPANTPERMISSIONCHANGED']._serialized_start=10473
+ _globals['_PARTICIPANTPERMISSIONCHANGED']._serialized_end=10591
+ _globals['_CONNECTIONQUALITYCHANGED']._serialized_start=10593
+ _globals['_CONNECTIONQUALITYCHANGED']._serialized_end=10700
+ _globals['_USERPACKET']._serialized_start=10702
+ _globals['_USERPACKET']._serialized_end=10771
+ _globals['_CHATMESSAGE']._serialized_start=10773
+ _globals['_CHATMESSAGE']._serialized_end=10894
+ _globals['_CHATMESSAGERECEIVED']._serialized_start=10896
+ _globals['_CHATMESSAGERECEIVED']._serialized_end=10992
+ _globals['_SIPDTMF']._serialized_start=10994
+ _globals['_SIPDTMF']._serialized_end=11032
+ _globals['_DATAPACKETRECEIVED']._serialized_start=11035
+ _globals['_DATAPACKETRECEIVED']._serialized_end=11226
+ _globals['_TRANSCRIPTIONRECEIVED']._serialized_start=11228
+ _globals['_TRANSCRIPTIONRECEIVED']._serialized_end=11355
+ _globals['_CONNECTIONSTATECHANGED']._serialized_start=11357
+ _globals['_CONNECTIONSTATECHANGED']._serialized_end=11428
+ _globals['_CONNECTED']._serialized_start=11430
+ _globals['_CONNECTED']._serialized_end=11441
+ _globals['_DISCONNECTED']._serialized_start=11443
+ _globals['_DISCONNECTED']._serialized_end=11506
+ _globals['_RECONNECTING']._serialized_start=11508
+ _globals['_RECONNECTING']._serialized_end=11522
+ _globals['_RECONNECTED']._serialized_start=11524
+ _globals['_RECONNECTED']._serialized_end=11537
+ _globals['_TOKENREFRESHED']._serialized_start=11539
+ _globals['_TOKENREFRESHED']._serialized_end=11570
+ _globals['_ROOMEOS']._serialized_start=11572
+ _globals['_ROOMEOS']._serialized_end=11581
+ _globals['_DATASTREAM']._serialized_start=11584
+ _globals['_DATASTREAM']._serialized_end=12494
+ _globals['_DATASTREAM_TEXTHEADER']._serialized_start=11599
+ _globals['_DATASTREAM_TEXTHEADER']._serialized_end=11769
+ _globals['_DATASTREAM_BYTEHEADER']._serialized_start=11771
+ _globals['_DATASTREAM_BYTEHEADER']._serialized_end=11797
+ _globals['_DATASTREAM_HEADER']._serialized_start=11800
+ _globals['_DATASTREAM_HEADER']._serialized_end=12163
+ _globals['_DATASTREAM_HEADER_ATTRIBUTESENTRY']._serialized_start=12096
+ _globals['_DATASTREAM_HEADER_ATTRIBUTESENTRY']._serialized_end=12145
+ _globals['_DATASTREAM_CHUNK']._serialized_start=12165
+ _globals['_DATASTREAM_CHUNK']._serialized_end=12258
+ _globals['_DATASTREAM_TRAILER']._serialized_start=12261
+ _globals['_DATASTREAM_TRAILER']._serialized_end=12427
+ _globals['_DATASTREAM_TRAILER_ATTRIBUTESENTRY']._serialized_start=12096
+ _globals['_DATASTREAM_TRAILER_ATTRIBUTESENTRY']._serialized_end=12145
+ _globals['_DATASTREAM_OPERATIONTYPE']._serialized_start=12429
+ _globals['_DATASTREAM_OPERATIONTYPE']._serialized_end=12494
+ _globals['_DATASTREAMHEADERRECEIVED']._serialized_start=12496
+ _globals['_DATASTREAMHEADERRECEIVED']._serialized_end=12602
+ _globals['_DATASTREAMCHUNKRECEIVED']._serialized_start=12604
+ _globals['_DATASTREAMCHUNKRECEIVED']._serialized_end=12707
+ _globals['_DATASTREAMTRAILERRECEIVED']._serialized_start=12709
+ _globals['_DATASTREAMTRAILERRECEIVED']._serialized_end=12818
+ _globals['_SENDSTREAMHEADERREQUEST']._serialized_start=12821
+ _globals['_SENDSTREAMHEADERREQUEST']._serialized_end=13013
+ _globals['_SENDSTREAMCHUNKREQUEST']._serialized_start=13016
+ _globals['_SENDSTREAMCHUNKREQUEST']._serialized_end=13205
+ _globals['_SENDSTREAMTRAILERREQUEST']._serialized_start=13208
+ _globals['_SENDSTREAMTRAILERREQUEST']._serialized_end=13403
+ _globals['_SENDSTREAMHEADERRESPONSE']._serialized_start=13405
+ _globals['_SENDSTREAMHEADERRESPONSE']._serialized_end=13449
+ _globals['_SENDSTREAMCHUNKRESPONSE']._serialized_start=13451
+ _globals['_SENDSTREAMCHUNKRESPONSE']._serialized_end=13494
+ _globals['_SENDSTREAMTRAILERRESPONSE']._serialized_start=13496
+ _globals['_SENDSTREAMTRAILERRESPONSE']._serialized_end=13541
+ _globals['_SENDSTREAMHEADERCALLBACK']._serialized_start=13543
+ _globals['_SENDSTREAMHEADERCALLBACK']._serialized_end=13602
+ _globals['_SENDSTREAMCHUNKCALLBACK']._serialized_start=13604
+ _globals['_SENDSTREAMCHUNKCALLBACK']._serialized_end=13662
+ _globals['_SENDSTREAMTRAILERCALLBACK']._serialized_start=13664
+ _globals['_SENDSTREAMTRAILERCALLBACK']._serialized_end=13724
+ _globals['_SETDATACHANNELBUFFEREDAMOUNTLOWTHRESHOLDREQUEST']._serialized_start=13727
+ _globals['_SETDATACHANNELBUFFEREDAMOUNTLOWTHRESHOLDREQUEST']._serialized_end=13874
+ _globals['_SETDATACHANNELBUFFEREDAMOUNTLOWTHRESHOLDRESPONSE']._serialized_start=13876
+ _globals['_SETDATACHANNELBUFFEREDAMOUNTLOWTHRESHOLDRESPONSE']._serialized_end=13926
+ _globals['_DATACHANNELBUFFEREDAMOUNTLOWTHRESHOLDCHANGED']._serialized_start=13928
+ _globals['_DATACHANNELBUFFEREDAMOUNTLOWTHRESHOLDCHANGED']._serialized_end=14038
+ _globals['_BYTESTREAMOPENED']._serialized_start=14040
+ _globals['_BYTESTREAMOPENED']._serialized_end=14142
+ _globals['_TEXTSTREAMOPENED']._serialized_start=14144
+ _globals['_TEXTSTREAMOPENED']._serialized_end=14246
+ _globals['_DATATRACKPUBLISHED']._serialized_start=14248
+ _globals['_DATATRACKPUBLISHED']._serialized_end=14320
+ _globals['_DATATRACKUNPUBLISHED']._serialized_start=14322
+ _globals['_DATATRACKUNPUBLISHED']._serialized_end=14357
# @@protoc_insertion_point(module_scope)
diff --git a/livekit-rtc/livekit/rtc/_proto/room_pb2.pyi b/livekit-rtc/livekit/rtc/_proto/room_pb2.pyi
index e2d2ca05..7f19589a 100644
--- a/livekit-rtc/livekit/rtc/_proto/room_pb2.pyi
+++ b/livekit-rtc/livekit/rtc/_proto/room_pb2.pyi
@@ -1,7 +1,7 @@
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
-Copyright 2023 LiveKit, Inc.
+Copyright 2025 LiveKit, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,8 +15,11 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
+
import builtins
import collections.abc
+from . import data_stream_pb2
+from . import data_track_pb2
from . import e2ee_pb2
import google.protobuf.descriptor
import google.protobuf.internal.containers
@@ -123,7 +126,7 @@ KIND_LOSSY: DataPacketKind.ValueType # 0
KIND_RELIABLE: DataPacketKind.ValueType # 1
global___DataPacketKind = DataPacketKind
-@typing_extensions.final
+@typing.final
class ConnectRequest(google.protobuf.message.Message):
"""Connect to a new LiveKit room"""
@@ -132,23 +135,26 @@ class ConnectRequest(google.protobuf.message.Message):
URL_FIELD_NUMBER: builtins.int
TOKEN_FIELD_NUMBER: builtins.int
OPTIONS_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
url: builtins.str
token: builtins.str
+ request_async_id: builtins.int
@property
def options(self) -> global___RoomOptions: ...
def __init__(
self,
*,
- url: builtins.str = ...,
- token: builtins.str = ...,
+ url: builtins.str | None = ...,
+ token: builtins.str | None = ...,
options: global___RoomOptions | None = ...,
+ request_async_id: builtins.int | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["options", b"options"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["options", b"options", "token", b"token", "url", b"url"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["options", b"options", "request_async_id", b"request_async_id", "token", b"token", "url", b"url"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["options", b"options", "request_async_id", b"request_async_id", "token", b"token", "url", b"url"]) -> None: ...
global___ConnectRequest = ConnectRequest
-@typing_extensions.final
+@typing.final
class ConnectResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -157,17 +163,18 @@ class ConnectResponse(google.protobuf.message.Message):
def __init__(
self,
*,
- async_id: builtins.int = ...,
+ async_id: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["async_id", b"async_id"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
global___ConnectResponse = ConnectResponse
-@typing_extensions.final
+@typing.final
class ConnectCallback(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
- @typing_extensions.final
+ @typing.final
class ParticipantWithTracks(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -180,61 +187,84 @@ class ConnectCallback(google.protobuf.message.Message):
"""TrackInfo are not needed here, if we're subscribed to a track, the FfiServer will send
a TrackSubscribed event
"""
+
def __init__(
self,
*,
participant: participant_pb2.OwnedParticipant | None = ...,
publications: collections.abc.Iterable[track_pb2.OwnedTrackPublication] | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["participant", b"participant"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["participant", b"participant", "publications", b"publications"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["participant", b"participant"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["participant", b"participant", "publications", b"publications"]) -> None: ...
+
+ @typing.final
+ class Result(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ROOM_FIELD_NUMBER: builtins.int
+ LOCAL_PARTICIPANT_FIELD_NUMBER: builtins.int
+ PARTICIPANTS_FIELD_NUMBER: builtins.int
+ @property
+ def room(self) -> global___OwnedRoom: ...
+ @property
+ def local_participant(self) -> participant_pb2.OwnedParticipant: ...
+ @property
+ def participants(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___ConnectCallback.ParticipantWithTracks]: ...
+ def __init__(
+ self,
+ *,
+ room: global___OwnedRoom | None = ...,
+ local_participant: participant_pb2.OwnedParticipant | None = ...,
+ participants: collections.abc.Iterable[global___ConnectCallback.ParticipantWithTracks] | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["local_participant", b"local_participant", "room", b"room"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["local_participant", b"local_participant", "participants", b"participants", "room", b"room"]) -> None: ...
ASYNC_ID_FIELD_NUMBER: builtins.int
ERROR_FIELD_NUMBER: builtins.int
- ROOM_FIELD_NUMBER: builtins.int
- LOCAL_PARTICIPANT_FIELD_NUMBER: builtins.int
- PARTICIPANTS_FIELD_NUMBER: builtins.int
+ RESULT_FIELD_NUMBER: builtins.int
async_id: builtins.int
error: builtins.str
@property
- def room(self) -> global___OwnedRoom: ...
- @property
- def local_participant(self) -> participant_pb2.OwnedParticipant: ...
- @property
- def participants(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___ConnectCallback.ParticipantWithTracks]: ...
+ def result(self) -> global___ConnectCallback.Result: ...
def __init__(
self,
*,
- async_id: builtins.int = ...,
+ async_id: builtins.int | None = ...,
error: builtins.str | None = ...,
- room: global___OwnedRoom | None = ...,
- local_participant: participant_pb2.OwnedParticipant | None = ...,
- participants: collections.abc.Iterable[global___ConnectCallback.ParticipantWithTracks] | None = ...,
+ result: global___ConnectCallback.Result | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_error", b"_error", "error", b"error", "local_participant", b"local_participant", "room", b"room"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_error", b"_error", "async_id", b"async_id", "error", b"error", "local_participant", b"local_participant", "participants", b"participants", "room", b"room"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_error", b"_error"]) -> typing_extensions.Literal["error"] | None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error", "message", b"message", "result", b"result"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error", "message", b"message", "result", b"result"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["message", b"message"]) -> typing.Literal["error", "result"] | None: ...
global___ConnectCallback = ConnectCallback
-@typing_extensions.final
+@typing.final
class DisconnectRequest(google.protobuf.message.Message):
"""Disconnect from the a room"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
ROOM_HANDLE_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
+ REASON_FIELD_NUMBER: builtins.int
room_handle: builtins.int
+ request_async_id: builtins.int
+ reason: participant_pb2.DisconnectReason.ValueType
def __init__(
self,
*,
- room_handle: builtins.int = ...,
+ room_handle: builtins.int | None = ...,
+ request_async_id: builtins.int | None = ...,
+ reason: participant_pb2.DisconnectReason.ValueType | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["room_handle", b"room_handle"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["reason", b"reason", "request_async_id", b"request_async_id", "room_handle", b"room_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["reason", b"reason", "request_async_id", b"request_async_id", "room_handle", b"room_handle"]) -> None: ...
global___DisconnectRequest = DisconnectRequest
-@typing_extensions.final
+@typing.final
class DisconnectResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -243,13 +273,14 @@ class DisconnectResponse(google.protobuf.message.Message):
def __init__(
self,
*,
- async_id: builtins.int = ...,
+ async_id: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["async_id", b"async_id"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
global___DisconnectResponse = DisconnectResponse
-@typing_extensions.final
+@typing.final
class DisconnectCallback(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -258,13 +289,14 @@ class DisconnectCallback(google.protobuf.message.Message):
def __init__(
self,
*,
- async_id: builtins.int = ...,
+ async_id: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["async_id", b"async_id"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
global___DisconnectCallback = DisconnectCallback
-@typing_extensions.final
+@typing.final
class PublishTrackRequest(google.protobuf.message.Message):
"""Publish a track to the room"""
@@ -273,23 +305,26 @@ class PublishTrackRequest(google.protobuf.message.Message):
LOCAL_PARTICIPANT_HANDLE_FIELD_NUMBER: builtins.int
TRACK_HANDLE_FIELD_NUMBER: builtins.int
OPTIONS_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
local_participant_handle: builtins.int
track_handle: builtins.int
+ request_async_id: builtins.int
@property
def options(self) -> global___TrackPublishOptions: ...
def __init__(
self,
*,
- local_participant_handle: builtins.int = ...,
- track_handle: builtins.int = ...,
+ local_participant_handle: builtins.int | None = ...,
+ track_handle: builtins.int | None = ...,
options: global___TrackPublishOptions | None = ...,
+ request_async_id: builtins.int | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["options", b"options"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["local_participant_handle", b"local_participant_handle", "options", b"options", "track_handle", b"track_handle"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["local_participant_handle", b"local_participant_handle", "options", b"options", "request_async_id", b"request_async_id", "track_handle", b"track_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["local_participant_handle", b"local_participant_handle", "options", b"options", "request_async_id", b"request_async_id", "track_handle", b"track_handle"]) -> None: ...
global___PublishTrackRequest = PublishTrackRequest
-@typing_extensions.final
+@typing.final
class PublishTrackResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -298,13 +333,14 @@ class PublishTrackResponse(google.protobuf.message.Message):
def __init__(
self,
*,
- async_id: builtins.int = ...,
+ async_id: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["async_id", b"async_id"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
global___PublishTrackResponse = PublishTrackResponse
-@typing_extensions.final
+@typing.final
class PublishTrackCallback(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -318,17 +354,17 @@ class PublishTrackCallback(google.protobuf.message.Message):
def __init__(
self,
*,
- async_id: builtins.int = ...,
+ async_id: builtins.int | None = ...,
error: builtins.str | None = ...,
publication: track_pb2.OwnedTrackPublication | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_error", b"_error", "error", b"error", "publication", b"publication"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_error", b"_error", "async_id", b"async_id", "error", b"error", "publication", b"publication"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_error", b"_error"]) -> typing_extensions.Literal["error"] | None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error", "message", b"message", "publication", b"publication"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error", "message", b"message", "publication", b"publication"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["message", b"message"]) -> typing.Literal["error", "publication"] | None: ...
global___PublishTrackCallback = PublishTrackCallback
-@typing_extensions.final
+@typing.final
class UnpublishTrackRequest(google.protobuf.message.Message):
"""Unpublish a track from the room"""
@@ -337,21 +373,25 @@ class UnpublishTrackRequest(google.protobuf.message.Message):
LOCAL_PARTICIPANT_HANDLE_FIELD_NUMBER: builtins.int
TRACK_SID_FIELD_NUMBER: builtins.int
STOP_ON_UNPUBLISH_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
local_participant_handle: builtins.int
track_sid: builtins.str
stop_on_unpublish: builtins.bool
+ request_async_id: builtins.int
def __init__(
self,
*,
- local_participant_handle: builtins.int = ...,
- track_sid: builtins.str = ...,
- stop_on_unpublish: builtins.bool = ...,
+ local_participant_handle: builtins.int | None = ...,
+ track_sid: builtins.str | None = ...,
+ stop_on_unpublish: builtins.bool | None = ...,
+ request_async_id: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["local_participant_handle", b"local_participant_handle", "stop_on_unpublish", b"stop_on_unpublish", "track_sid", b"track_sid"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["local_participant_handle", b"local_participant_handle", "request_async_id", b"request_async_id", "stop_on_unpublish", b"stop_on_unpublish", "track_sid", b"track_sid"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["local_participant_handle", b"local_participant_handle", "request_async_id", b"request_async_id", "stop_on_unpublish", b"stop_on_unpublish", "track_sid", b"track_sid"]) -> None: ...
global___UnpublishTrackRequest = UnpublishTrackRequest
-@typing_extensions.final
+@typing.final
class UnpublishTrackResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -360,13 +400,14 @@ class UnpublishTrackResponse(google.protobuf.message.Message):
def __init__(
self,
*,
- async_id: builtins.int = ...,
+ async_id: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["async_id", b"async_id"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
global___UnpublishTrackResponse = UnpublishTrackResponse
-@typing_extensions.final
+@typing.final
class UnpublishTrackCallback(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -377,16 +418,15 @@ class UnpublishTrackCallback(google.protobuf.message.Message):
def __init__(
self,
*,
- async_id: builtins.int = ...,
+ async_id: builtins.int | None = ...,
error: builtins.str | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_error", b"_error", "error", b"error"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_error", b"_error", "async_id", b"async_id", "error", b"error"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_error", b"_error"]) -> typing_extensions.Literal["error"] | None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> None: ...
global___UnpublishTrackCallback = UnpublishTrackCallback
-@typing_extensions.final
+@typing.final
class PublishDataRequest(google.protobuf.message.Message):
"""Publish data to other participants"""
@@ -395,34 +435,39 @@ class PublishDataRequest(google.protobuf.message.Message):
LOCAL_PARTICIPANT_HANDLE_FIELD_NUMBER: builtins.int
DATA_PTR_FIELD_NUMBER: builtins.int
DATA_LEN_FIELD_NUMBER: builtins.int
- KIND_FIELD_NUMBER: builtins.int
+ RELIABLE_FIELD_NUMBER: builtins.int
DESTINATION_SIDS_FIELD_NUMBER: builtins.int
TOPIC_FIELD_NUMBER: builtins.int
+ DESTINATION_IDENTITIES_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
local_participant_handle: builtins.int
data_ptr: builtins.int
data_len: builtins.int
- kind: global___DataPacketKind.ValueType
- @property
- def destination_sids(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]:
- """destination"""
+ reliable: builtins.bool
topic: builtins.str
+ request_async_id: builtins.int
+ @property
+ def destination_sids(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ...
+ @property
+ def destination_identities(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ...
def __init__(
self,
*,
- local_participant_handle: builtins.int = ...,
- data_ptr: builtins.int = ...,
- data_len: builtins.int = ...,
- kind: global___DataPacketKind.ValueType = ...,
+ local_participant_handle: builtins.int | None = ...,
+ data_ptr: builtins.int | None = ...,
+ data_len: builtins.int | None = ...,
+ reliable: builtins.bool | None = ...,
destination_sids: collections.abc.Iterable[builtins.str] | None = ...,
topic: builtins.str | None = ...,
+ destination_identities: collections.abc.Iterable[builtins.str] | None = ...,
+ request_async_id: builtins.int | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_topic", b"_topic", "topic", b"topic"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_topic", b"_topic", "data_len", b"data_len", "data_ptr", b"data_ptr", "destination_sids", b"destination_sids", "kind", b"kind", "local_participant_handle", b"local_participant_handle", "topic", b"topic"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_topic", b"_topic"]) -> typing_extensions.Literal["topic"] | None: ...
+ def HasField(self, field_name: typing.Literal["data_len", b"data_len", "data_ptr", b"data_ptr", "local_participant_handle", b"local_participant_handle", "reliable", b"reliable", "request_async_id", b"request_async_id", "topic", b"topic"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["data_len", b"data_len", "data_ptr", b"data_ptr", "destination_identities", b"destination_identities", "destination_sids", b"destination_sids", "local_participant_handle", b"local_participant_handle", "reliable", b"reliable", "request_async_id", b"request_async_id", "topic", b"topic"]) -> None: ...
global___PublishDataRequest = PublishDataRequest
-@typing_extensions.final
+@typing.final
class PublishDataResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -431,13 +476,14 @@ class PublishDataResponse(google.protobuf.message.Message):
def __init__(
self,
*,
- async_id: builtins.int = ...,
+ async_id: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["async_id", b"async_id"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
global___PublishDataResponse = PublishDataResponse
-@typing_extensions.final
+@typing.final
class PublishDataCallback(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -448,16 +494,15 @@ class PublishDataCallback(google.protobuf.message.Message):
def __init__(
self,
*,
- async_id: builtins.int = ...,
+ async_id: builtins.int | None = ...,
error: builtins.str | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_error", b"_error", "error", b"error"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_error", b"_error", "async_id", b"async_id", "error", b"error"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_error", b"_error"]) -> typing_extensions.Literal["error"] | None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> None: ...
global___PublishDataCallback = PublishDataCallback
-@typing_extensions.final
+@typing.final
class PublishTranscriptionRequest(google.protobuf.message.Message):
"""Publish transcription messages to room"""
@@ -467,27 +512,28 @@ class PublishTranscriptionRequest(google.protobuf.message.Message):
PARTICIPANT_IDENTITY_FIELD_NUMBER: builtins.int
TRACK_ID_FIELD_NUMBER: builtins.int
SEGMENTS_FIELD_NUMBER: builtins.int
- LANGUAGE_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
local_participant_handle: builtins.int
participant_identity: builtins.str
track_id: builtins.str
+ request_async_id: builtins.int
@property
def segments(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___TranscriptionSegment]: ...
- language: builtins.str
def __init__(
self,
*,
- local_participant_handle: builtins.int = ...,
- participant_identity: builtins.str = ...,
- track_id: builtins.str = ...,
+ local_participant_handle: builtins.int | None = ...,
+ participant_identity: builtins.str | None = ...,
+ track_id: builtins.str | None = ...,
segments: collections.abc.Iterable[global___TranscriptionSegment] | None = ...,
- language: builtins.str = ...,
+ request_async_id: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["language", b"language", "local_participant_handle", b"local_participant_handle", "participant_identity", b"participant_identity", "segments", b"segments", "track_id", b"track_id"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["local_participant_handle", b"local_participant_handle", "participant_identity", b"participant_identity", "request_async_id", b"request_async_id", "track_id", b"track_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["local_participant_handle", b"local_participant_handle", "participant_identity", b"participant_identity", "request_async_id", b"request_async_id", "segments", b"segments", "track_id", b"track_id"]) -> None: ...
global___PublishTranscriptionRequest = PublishTranscriptionRequest
-@typing_extensions.final
+@typing.final
class PublishTranscriptionResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -496,13 +542,14 @@ class PublishTranscriptionResponse(google.protobuf.message.Message):
def __init__(
self,
*,
- async_id: builtins.int = ...,
+ async_id: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["async_id", b"async_id"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
global___PublishTranscriptionResponse = PublishTranscriptionResponse
-@typing_extensions.final
+@typing.final
class PublishTranscriptionCallback(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -513,37 +560,287 @@ class PublishTranscriptionCallback(google.protobuf.message.Message):
def __init__(
self,
*,
- async_id: builtins.int = ...,
+ async_id: builtins.int | None = ...,
error: builtins.str | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_error", b"_error", "error", b"error"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_error", b"_error", "async_id", b"async_id", "error", b"error"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_error", b"_error"]) -> typing_extensions.Literal["error"] | None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> None: ...
global___PublishTranscriptionCallback = PublishTranscriptionCallback
-@typing_extensions.final
-class UpdateLocalMetadataRequest(google.protobuf.message.Message):
+@typing.final
+class PublishSipDtmfRequest(google.protobuf.message.Message):
+ """Publish Sip DTMF messages to other participants"""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ LOCAL_PARTICIPANT_HANDLE_FIELD_NUMBER: builtins.int
+ CODE_FIELD_NUMBER: builtins.int
+ DIGIT_FIELD_NUMBER: builtins.int
+ DESTINATION_IDENTITIES_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
+ local_participant_handle: builtins.int
+ code: builtins.int
+ digit: builtins.str
+ request_async_id: builtins.int
+ @property
+ def destination_identities(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ...
+ def __init__(
+ self,
+ *,
+ local_participant_handle: builtins.int | None = ...,
+ code: builtins.int | None = ...,
+ digit: builtins.str | None = ...,
+ destination_identities: collections.abc.Iterable[builtins.str] | None = ...,
+ request_async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["code", b"code", "digit", b"digit", "local_participant_handle", b"local_participant_handle", "request_async_id", b"request_async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["code", b"code", "destination_identities", b"destination_identities", "digit", b"digit", "local_participant_handle", b"local_participant_handle", "request_async_id", b"request_async_id"]) -> None: ...
+
+global___PublishSipDtmfRequest = PublishSipDtmfRequest
+
+@typing.final
+class PublishSipDtmfResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
+
+global___PublishSipDtmfResponse = PublishSipDtmfResponse
+
+@typing.final
+class PublishSipDtmfCallback(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ ERROR_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ error: builtins.str
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ error: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> None: ...
+
+global___PublishSipDtmfCallback = PublishSipDtmfCallback
+
+@typing.final
+class SetLocalMetadataRequest(google.protobuf.message.Message):
"""Change the local participant's metadata"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
LOCAL_PARTICIPANT_HANDLE_FIELD_NUMBER: builtins.int
METADATA_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
local_participant_handle: builtins.int
metadata: builtins.str
+ request_async_id: builtins.int
+ def __init__(
+ self,
+ *,
+ local_participant_handle: builtins.int | None = ...,
+ metadata: builtins.str | None = ...,
+ request_async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["local_participant_handle", b"local_participant_handle", "metadata", b"metadata", "request_async_id", b"request_async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["local_participant_handle", b"local_participant_handle", "metadata", b"metadata", "request_async_id", b"request_async_id"]) -> None: ...
+
+global___SetLocalMetadataRequest = SetLocalMetadataRequest
+
+@typing.final
+class SetLocalMetadataResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
+
+global___SetLocalMetadataResponse = SetLocalMetadataResponse
+
+@typing.final
+class SetLocalMetadataCallback(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ ERROR_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ error: builtins.str
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ error: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> None: ...
+
+global___SetLocalMetadataCallback = SetLocalMetadataCallback
+
+@typing.final
+class SendChatMessageRequest(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ LOCAL_PARTICIPANT_HANDLE_FIELD_NUMBER: builtins.int
+ MESSAGE_FIELD_NUMBER: builtins.int
+ DESTINATION_IDENTITIES_FIELD_NUMBER: builtins.int
+ SENDER_IDENTITY_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
+ local_participant_handle: builtins.int
+ message: builtins.str
+ sender_identity: builtins.str
+ request_async_id: builtins.int
+ @property
+ def destination_identities(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ...
+ def __init__(
+ self,
+ *,
+ local_participant_handle: builtins.int | None = ...,
+ message: builtins.str | None = ...,
+ destination_identities: collections.abc.Iterable[builtins.str] | None = ...,
+ sender_identity: builtins.str | None = ...,
+ request_async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["local_participant_handle", b"local_participant_handle", "message", b"message", "request_async_id", b"request_async_id", "sender_identity", b"sender_identity"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["destination_identities", b"destination_identities", "local_participant_handle", b"local_participant_handle", "message", b"message", "request_async_id", b"request_async_id", "sender_identity", b"sender_identity"]) -> None: ...
+
+global___SendChatMessageRequest = SendChatMessageRequest
+
+@typing.final
+class EditChatMessageRequest(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ LOCAL_PARTICIPANT_HANDLE_FIELD_NUMBER: builtins.int
+ EDIT_TEXT_FIELD_NUMBER: builtins.int
+ ORIGINAL_MESSAGE_FIELD_NUMBER: builtins.int
+ DESTINATION_IDENTITIES_FIELD_NUMBER: builtins.int
+ SENDER_IDENTITY_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
+ local_participant_handle: builtins.int
+ edit_text: builtins.str
+ sender_identity: builtins.str
+ request_async_id: builtins.int
+ @property
+ def original_message(self) -> global___ChatMessage: ...
+ @property
+ def destination_identities(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ...
+ def __init__(
+ self,
+ *,
+ local_participant_handle: builtins.int | None = ...,
+ edit_text: builtins.str | None = ...,
+ original_message: global___ChatMessage | None = ...,
+ destination_identities: collections.abc.Iterable[builtins.str] | None = ...,
+ sender_identity: builtins.str | None = ...,
+ request_async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["edit_text", b"edit_text", "local_participant_handle", b"local_participant_handle", "original_message", b"original_message", "request_async_id", b"request_async_id", "sender_identity", b"sender_identity"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["destination_identities", b"destination_identities", "edit_text", b"edit_text", "local_participant_handle", b"local_participant_handle", "original_message", b"original_message", "request_async_id", b"request_async_id", "sender_identity", b"sender_identity"]) -> None: ...
+
+global___EditChatMessageRequest = EditChatMessageRequest
+
+@typing.final
+class SendChatMessageResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
+
+global___SendChatMessageResponse = SendChatMessageResponse
+
+@typing.final
+class SendChatMessageCallback(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ ERROR_FIELD_NUMBER: builtins.int
+ CHAT_MESSAGE_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ error: builtins.str
+ @property
+ def chat_message(self) -> global___ChatMessage: ...
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ error: builtins.str | None = ...,
+ chat_message: global___ChatMessage | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "chat_message", b"chat_message", "error", b"error", "message", b"message"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "chat_message", b"chat_message", "error", b"error", "message", b"message"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["message", b"message"]) -> typing.Literal["error", "chat_message"] | None: ...
+
+global___SendChatMessageCallback = SendChatMessageCallback
+
+@typing.final
+class SetLocalAttributesRequest(google.protobuf.message.Message):
+ """Change the local participant's attributes"""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ LOCAL_PARTICIPANT_HANDLE_FIELD_NUMBER: builtins.int
+ ATTRIBUTES_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
+ local_participant_handle: builtins.int
+ request_async_id: builtins.int
+ @property
+ def attributes(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___AttributesEntry]: ...
def __init__(
self,
*,
- local_participant_handle: builtins.int = ...,
- metadata: builtins.str = ...,
+ local_participant_handle: builtins.int | None = ...,
+ attributes: collections.abc.Iterable[global___AttributesEntry] | None = ...,
+ request_async_id: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["local_participant_handle", b"local_participant_handle", "metadata", b"metadata"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["local_participant_handle", b"local_participant_handle", "request_async_id", b"request_async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["attributes", b"attributes", "local_participant_handle", b"local_participant_handle", "request_async_id", b"request_async_id"]) -> None: ...
-global___UpdateLocalMetadataRequest = UpdateLocalMetadataRequest
+global___SetLocalAttributesRequest = SetLocalAttributesRequest
-@typing_extensions.final
-class UpdateLocalMetadataResponse(google.protobuf.message.Message):
+@typing.final
+class AttributesEntry(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ KEY_FIELD_NUMBER: builtins.int
+ VALUE_FIELD_NUMBER: builtins.int
+ key: builtins.str
+ value: builtins.str
+ def __init__(
+ self,
+ *,
+ key: builtins.str | None = ...,
+ value: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> None: ...
+
+global___AttributesEntry = AttributesEntry
+
+@typing.final
+class SetLocalAttributesResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
ASYNC_ID_FIELD_NUMBER: builtins.int
@@ -551,49 +848,58 @@ class UpdateLocalMetadataResponse(google.protobuf.message.Message):
def __init__(
self,
*,
- async_id: builtins.int = ...,
+ async_id: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["async_id", b"async_id"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
-global___UpdateLocalMetadataResponse = UpdateLocalMetadataResponse
+global___SetLocalAttributesResponse = SetLocalAttributesResponse
-@typing_extensions.final
-class UpdateLocalMetadataCallback(google.protobuf.message.Message):
+@typing.final
+class SetLocalAttributesCallback(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
ASYNC_ID_FIELD_NUMBER: builtins.int
+ ERROR_FIELD_NUMBER: builtins.int
async_id: builtins.int
+ error: builtins.str
def __init__(
self,
*,
- async_id: builtins.int = ...,
+ async_id: builtins.int | None = ...,
+ error: builtins.str | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["async_id", b"async_id"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> None: ...
-global___UpdateLocalMetadataCallback = UpdateLocalMetadataCallback
+global___SetLocalAttributesCallback = SetLocalAttributesCallback
-@typing_extensions.final
-class UpdateLocalNameRequest(google.protobuf.message.Message):
+@typing.final
+class SetLocalNameRequest(google.protobuf.message.Message):
"""Change the local participant's name"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
LOCAL_PARTICIPANT_HANDLE_FIELD_NUMBER: builtins.int
NAME_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
local_participant_handle: builtins.int
name: builtins.str
+ request_async_id: builtins.int
def __init__(
self,
*,
- local_participant_handle: builtins.int = ...,
- name: builtins.str = ...,
+ local_participant_handle: builtins.int | None = ...,
+ name: builtins.str | None = ...,
+ request_async_id: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["local_participant_handle", b"local_participant_handle", "name", b"name"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["local_participant_handle", b"local_participant_handle", "name", b"name", "request_async_id", b"request_async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["local_participant_handle", b"local_participant_handle", "name", b"name", "request_async_id", b"request_async_id"]) -> None: ...
-global___UpdateLocalNameRequest = UpdateLocalNameRequest
+global___SetLocalNameRequest = SetLocalNameRequest
-@typing_extensions.final
-class UpdateLocalNameResponse(google.protobuf.message.Message):
+@typing.final
+class SetLocalNameResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
ASYNC_ID_FIELD_NUMBER: builtins.int
@@ -601,28 +907,33 @@ class UpdateLocalNameResponse(google.protobuf.message.Message):
def __init__(
self,
*,
- async_id: builtins.int = ...,
+ async_id: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["async_id", b"async_id"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
-global___UpdateLocalNameResponse = UpdateLocalNameResponse
+global___SetLocalNameResponse = SetLocalNameResponse
-@typing_extensions.final
-class UpdateLocalNameCallback(google.protobuf.message.Message):
+@typing.final
+class SetLocalNameCallback(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
ASYNC_ID_FIELD_NUMBER: builtins.int
+ ERROR_FIELD_NUMBER: builtins.int
async_id: builtins.int
+ error: builtins.str
def __init__(
self,
*,
- async_id: builtins.int = ...,
+ async_id: builtins.int | None = ...,
+ error: builtins.str | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["async_id", b"async_id"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> None: ...
-global___UpdateLocalNameCallback = UpdateLocalNameCallback
+global___SetLocalNameCallback = SetLocalNameCallback
-@typing_extensions.final
+@typing.final
class SetSubscribedRequest(google.protobuf.message.Message):
"""Change the "desire" to subs2ribe to a track"""
@@ -635,14 +946,15 @@ class SetSubscribedRequest(google.protobuf.message.Message):
def __init__(
self,
*,
- subscribe: builtins.bool = ...,
- publication_handle: builtins.int = ...,
+ subscribe: builtins.bool | None = ...,
+ publication_handle: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["publication_handle", b"publication_handle", "subscribe", b"subscribe"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["publication_handle", b"publication_handle", "subscribe", b"subscribe"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["publication_handle", b"publication_handle", "subscribe", b"subscribe"]) -> None: ...
global___SetSubscribedRequest = SetSubscribedRequest
-@typing_extensions.final
+@typing.final
class SetSubscribedResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -652,22 +964,26 @@ class SetSubscribedResponse(google.protobuf.message.Message):
global___SetSubscribedResponse = SetSubscribedResponse
-@typing_extensions.final
+@typing.final
class GetSessionStatsRequest(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
ROOM_HANDLE_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
room_handle: builtins.int
+ request_async_id: builtins.int
def __init__(
self,
*,
- room_handle: builtins.int = ...,
+ room_handle: builtins.int | None = ...,
+ request_async_id: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["room_handle", b"room_handle"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["request_async_id", b"request_async_id", "room_handle", b"room_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["request_async_id", b"request_async_id", "room_handle", b"room_handle"]) -> None: ...
global___GetSessionStatsRequest = GetSessionStatsRequest
-@typing_extensions.final
+@typing.final
class GetSessionStatsResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -676,41 +992,56 @@ class GetSessionStatsResponse(google.protobuf.message.Message):
def __init__(
self,
*,
- async_id: builtins.int = ...,
+ async_id: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["async_id", b"async_id"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
global___GetSessionStatsResponse = GetSessionStatsResponse
-@typing_extensions.final
+@typing.final
class GetSessionStatsCallback(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
+ @typing.final
+ class Result(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ PUBLISHER_STATS_FIELD_NUMBER: builtins.int
+ SUBSCRIBER_STATS_FIELD_NUMBER: builtins.int
+ @property
+ def publisher_stats(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[stats_pb2.RtcStats]: ...
+ @property
+ def subscriber_stats(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[stats_pb2.RtcStats]: ...
+ def __init__(
+ self,
+ *,
+ publisher_stats: collections.abc.Iterable[stats_pb2.RtcStats] | None = ...,
+ subscriber_stats: collections.abc.Iterable[stats_pb2.RtcStats] | None = ...,
+ ) -> None: ...
+ def ClearField(self, field_name: typing.Literal["publisher_stats", b"publisher_stats", "subscriber_stats", b"subscriber_stats"]) -> None: ...
+
ASYNC_ID_FIELD_NUMBER: builtins.int
ERROR_FIELD_NUMBER: builtins.int
- PUBLISHER_STATS_FIELD_NUMBER: builtins.int
- SUBSCRIBER_STATS_FIELD_NUMBER: builtins.int
+ RESULT_FIELD_NUMBER: builtins.int
async_id: builtins.int
error: builtins.str
@property
- def publisher_stats(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[stats_pb2.RtcStats]: ...
- @property
- def subscriber_stats(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[stats_pb2.RtcStats]: ...
+ def result(self) -> global___GetSessionStatsCallback.Result: ...
def __init__(
self,
*,
- async_id: builtins.int = ...,
+ async_id: builtins.int | None = ...,
error: builtins.str | None = ...,
- publisher_stats: collections.abc.Iterable[stats_pb2.RtcStats] | None = ...,
- subscriber_stats: collections.abc.Iterable[stats_pb2.RtcStats] | None = ...,
+ result: global___GetSessionStatsCallback.Result | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_error", b"_error", "error", b"error"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_error", b"_error", "async_id", b"async_id", "error", b"error", "publisher_stats", b"publisher_stats", "subscriber_stats", b"subscriber_stats"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_error", b"_error"]) -> typing_extensions.Literal["error"] | None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error", "message", b"message", "result", b"result"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error", "message", b"message", "result", b"result"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["message", b"message"]) -> typing.Literal["error", "result"] | None: ...
global___GetSessionStatsCallback = GetSessionStatsCallback
-@typing_extensions.final
+@typing.final
class VideoEncoding(google.protobuf.message.Message):
"""
Options
@@ -725,14 +1056,15 @@ class VideoEncoding(google.protobuf.message.Message):
def __init__(
self,
*,
- max_bitrate: builtins.int = ...,
- max_framerate: builtins.float = ...,
+ max_bitrate: builtins.int | None = ...,
+ max_framerate: builtins.float | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["max_bitrate", b"max_bitrate", "max_framerate", b"max_framerate"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["max_bitrate", b"max_bitrate", "max_framerate", b"max_framerate"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["max_bitrate", b"max_bitrate", "max_framerate", b"max_framerate"]) -> None: ...
global___VideoEncoding = VideoEncoding
-@typing_extensions.final
+@typing.final
class AudioEncoding(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -741,13 +1073,14 @@ class AudioEncoding(google.protobuf.message.Message):
def __init__(
self,
*,
- max_bitrate: builtins.int = ...,
+ max_bitrate: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["max_bitrate", b"max_bitrate"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["max_bitrate", b"max_bitrate"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["max_bitrate", b"max_bitrate"]) -> None: ...
global___AudioEncoding = AudioEncoding
-@typing_extensions.final
+@typing.final
class TrackPublishOptions(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -758,55 +1091,67 @@ class TrackPublishOptions(google.protobuf.message.Message):
RED_FIELD_NUMBER: builtins.int
SIMULCAST_FIELD_NUMBER: builtins.int
SOURCE_FIELD_NUMBER: builtins.int
- @property
- def video_encoding(self) -> global___VideoEncoding:
- """encodings are optional"""
- @property
- def audio_encoding(self) -> global___AudioEncoding: ...
+ STREAM_FIELD_NUMBER: builtins.int
+ PRECONNECT_BUFFER_FIELD_NUMBER: builtins.int
+ PACKET_TRAILER_FEATURES_FIELD_NUMBER: builtins.int
video_codec: video_frame_pb2.VideoCodec.ValueType
dtx: builtins.bool
red: builtins.bool
simulcast: builtins.bool
source: track_pb2.TrackSource.ValueType
+ stream: builtins.str
+ preconnect_buffer: builtins.bool
+ @property
+ def video_encoding(self) -> global___VideoEncoding:
+ """encodings are optional"""
+
+ @property
+ def audio_encoding(self) -> global___AudioEncoding: ...
+ @property
+ def packet_trailer_features(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[track_pb2.PacketTrailerFeature.ValueType]: ...
def __init__(
self,
*,
video_encoding: global___VideoEncoding | None = ...,
audio_encoding: global___AudioEncoding | None = ...,
- video_codec: video_frame_pb2.VideoCodec.ValueType = ...,
- dtx: builtins.bool = ...,
- red: builtins.bool = ...,
- simulcast: builtins.bool = ...,
- source: track_pb2.TrackSource.ValueType = ...,
- ) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["audio_encoding", b"audio_encoding", "video_encoding", b"video_encoding"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["audio_encoding", b"audio_encoding", "dtx", b"dtx", "red", b"red", "simulcast", b"simulcast", "source", b"source", "video_codec", b"video_codec", "video_encoding", b"video_encoding"]) -> None: ...
+ video_codec: video_frame_pb2.VideoCodec.ValueType | None = ...,
+ dtx: builtins.bool | None = ...,
+ red: builtins.bool | None = ...,
+ simulcast: builtins.bool | None = ...,
+ source: track_pb2.TrackSource.ValueType | None = ...,
+ stream: builtins.str | None = ...,
+ preconnect_buffer: builtins.bool | None = ...,
+ packet_trailer_features: collections.abc.Iterable[track_pb2.PacketTrailerFeature.ValueType] | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["audio_encoding", b"audio_encoding", "dtx", b"dtx", "preconnect_buffer", b"preconnect_buffer", "red", b"red", "simulcast", b"simulcast", "source", b"source", "stream", b"stream", "video_codec", b"video_codec", "video_encoding", b"video_encoding"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["audio_encoding", b"audio_encoding", "dtx", b"dtx", "packet_trailer_features", b"packet_trailer_features", "preconnect_buffer", b"preconnect_buffer", "red", b"red", "simulcast", b"simulcast", "source", b"source", "stream", b"stream", "video_codec", b"video_codec", "video_encoding", b"video_encoding"]) -> None: ...
global___TrackPublishOptions = TrackPublishOptions
-@typing_extensions.final
+@typing.final
class IceServer(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
URLS_FIELD_NUMBER: builtins.int
USERNAME_FIELD_NUMBER: builtins.int
PASSWORD_FIELD_NUMBER: builtins.int
- @property
- def urls(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ...
username: builtins.str
password: builtins.str
+ @property
+ def urls(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ...
def __init__(
self,
*,
urls: collections.abc.Iterable[builtins.str] | None = ...,
- username: builtins.str = ...,
- password: builtins.str = ...,
+ username: builtins.str | None = ...,
+ password: builtins.str | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["password", b"password", "urls", b"urls", "username", b"username"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["password", b"password", "username", b"username"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["password", b"password", "urls", b"urls", "username", b"username"]) -> None: ...
global___IceServer = IceServer
-@typing_extensions.final
+@typing.final
class RtcConfig(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -818,6 +1163,7 @@ class RtcConfig(google.protobuf.message.Message):
@property
def ice_servers(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___IceServer]:
"""empty fallback to default"""
+
def __init__(
self,
*,
@@ -825,16 +1171,12 @@ class RtcConfig(google.protobuf.message.Message):
continual_gathering_policy: global___ContinualGatheringPolicy.ValueType | None = ...,
ice_servers: collections.abc.Iterable[global___IceServer] | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_continual_gathering_policy", b"_continual_gathering_policy", "_ice_transport_type", b"_ice_transport_type", "continual_gathering_policy", b"continual_gathering_policy", "ice_transport_type", b"ice_transport_type"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_continual_gathering_policy", b"_continual_gathering_policy", "_ice_transport_type", b"_ice_transport_type", "continual_gathering_policy", b"continual_gathering_policy", "ice_servers", b"ice_servers", "ice_transport_type", b"ice_transport_type"]) -> None: ...
- @typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_continual_gathering_policy", b"_continual_gathering_policy"]) -> typing_extensions.Literal["continual_gathering_policy"] | None: ...
- @typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_ice_transport_type", b"_ice_transport_type"]) -> typing_extensions.Literal["ice_transport_type"] | None: ...
+ def HasField(self, field_name: typing.Literal["continual_gathering_policy", b"continual_gathering_policy", "ice_transport_type", b"ice_transport_type"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["continual_gathering_policy", b"continual_gathering_policy", "ice_servers", b"ice_servers", "ice_transport_type", b"ice_transport_type"]) -> None: ...
global___RtcConfig = RtcConfig
-@typing_extensions.final
+@typing.final
class RoomOptions(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -844,35 +1186,44 @@ class RoomOptions(google.protobuf.message.Message):
E2EE_FIELD_NUMBER: builtins.int
RTC_CONFIG_FIELD_NUMBER: builtins.int
JOIN_RETRIES_FIELD_NUMBER: builtins.int
+ ENCRYPTION_FIELD_NUMBER: builtins.int
+ SINGLE_PEER_CONNECTION_FIELD_NUMBER: builtins.int
+ CONNECT_TIMEOUT_MS_FIELD_NUMBER: builtins.int
auto_subscribe: builtins.bool
adaptive_stream: builtins.bool
dynacast: builtins.bool
+ join_retries: builtins.int
+ single_peer_connection: builtins.bool
+ """use single peer connection for both publish/subscribe (default: false)"""
+ connect_timeout_ms: builtins.int
+ """timeout in milliseconds for each signal connection attempt (default: 5000)"""
@property
def e2ee(self) -> e2ee_pb2.E2eeOptions: ...
@property
def rtc_config(self) -> global___RtcConfig:
"""allow to setup a custom RtcConfiguration"""
- join_retries: builtins.int
+
+ @property
+ def encryption(self) -> e2ee_pb2.E2eeOptions: ...
def __init__(
self,
*,
- auto_subscribe: builtins.bool = ...,
- adaptive_stream: builtins.bool = ...,
- dynacast: builtins.bool = ...,
+ auto_subscribe: builtins.bool | None = ...,
+ adaptive_stream: builtins.bool | None = ...,
+ dynacast: builtins.bool | None = ...,
e2ee: e2ee_pb2.E2eeOptions | None = ...,
rtc_config: global___RtcConfig | None = ...,
- join_retries: builtins.int = ...,
+ join_retries: builtins.int | None = ...,
+ encryption: e2ee_pb2.E2eeOptions | None = ...,
+ single_peer_connection: builtins.bool | None = ...,
+ connect_timeout_ms: builtins.int | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_e2ee", b"_e2ee", "_rtc_config", b"_rtc_config", "e2ee", b"e2ee", "rtc_config", b"rtc_config"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_e2ee", b"_e2ee", "_rtc_config", b"_rtc_config", "adaptive_stream", b"adaptive_stream", "auto_subscribe", b"auto_subscribe", "dynacast", b"dynacast", "e2ee", b"e2ee", "join_retries", b"join_retries", "rtc_config", b"rtc_config"]) -> None: ...
- @typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_e2ee", b"_e2ee"]) -> typing_extensions.Literal["e2ee"] | None: ...
- @typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_rtc_config", b"_rtc_config"]) -> typing_extensions.Literal["rtc_config"] | None: ...
+ def HasField(self, field_name: typing.Literal["adaptive_stream", b"adaptive_stream", "auto_subscribe", b"auto_subscribe", "connect_timeout_ms", b"connect_timeout_ms", "dynacast", b"dynacast", "e2ee", b"e2ee", "encryption", b"encryption", "join_retries", b"join_retries", "rtc_config", b"rtc_config", "single_peer_connection", b"single_peer_connection"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["adaptive_stream", b"adaptive_stream", "auto_subscribe", b"auto_subscribe", "connect_timeout_ms", b"connect_timeout_ms", "dynacast", b"dynacast", "e2ee", b"e2ee", "encryption", b"encryption", "join_retries", b"join_retries", "rtc_config", b"rtc_config", "single_peer_connection", b"single_peer_connection"]) -> None: ...
global___RoomOptions = RoomOptions
-@typing_extensions.final
+@typing.final
class TranscriptionSegment(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -881,25 +1232,29 @@ class TranscriptionSegment(google.protobuf.message.Message):
START_TIME_FIELD_NUMBER: builtins.int
END_TIME_FIELD_NUMBER: builtins.int
FINAL_FIELD_NUMBER: builtins.int
+ LANGUAGE_FIELD_NUMBER: builtins.int
id: builtins.str
text: builtins.str
start_time: builtins.int
end_time: builtins.int
final: builtins.bool
+ language: builtins.str
def __init__(
self,
*,
- id: builtins.str = ...,
- text: builtins.str = ...,
- start_time: builtins.int = ...,
- end_time: builtins.int = ...,
- final: builtins.bool = ...,
+ id: builtins.str | None = ...,
+ text: builtins.str | None = ...,
+ start_time: builtins.int | None = ...,
+ end_time: builtins.int | None = ...,
+ final: builtins.bool | None = ...,
+ language: builtins.str | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["end_time", b"end_time", "final", b"final", "id", b"id", "start_time", b"start_time", "text", b"text"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["end_time", b"end_time", "final", b"final", "id", b"id", "language", b"language", "start_time", b"start_time", "text", b"text"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["end_time", b"end_time", "final", b"final", "id", b"id", "language", b"language", "start_time", b"start_time", "text", b"text"]) -> None: ...
global___TranscriptionSegment = TranscriptionSegment
-@typing_extensions.final
+@typing.final
class BufferInfo(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -910,14 +1265,15 @@ class BufferInfo(google.protobuf.message.Message):
def __init__(
self,
*,
- data_ptr: builtins.int = ...,
- data_len: builtins.int = ...,
+ data_ptr: builtins.int | None = ...,
+ data_len: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["data_len", b"data_len", "data_ptr", b"data_ptr"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["data_len", b"data_len", "data_ptr", b"data_ptr"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["data_len", b"data_len", "data_ptr", b"data_ptr"]) -> None: ...
global___BufferInfo = BufferInfo
-@typing_extensions.final
+@typing.final
class OwnedBuffer(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -933,12 +1289,12 @@ class OwnedBuffer(google.protobuf.message.Message):
handle: handle_pb2.FfiOwnedHandle | None = ...,
data: global___BufferInfo | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["data", b"data", "handle", b"handle"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["data", b"data", "handle", b"handle"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["data", b"data", "handle", b"handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["data", b"data", "handle", b"handle"]) -> None: ...
global___OwnedBuffer = OwnedBuffer
-@typing_extensions.final
+@typing.final
class RoomEvent(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -947,6 +1303,7 @@ class RoomEvent(google.protobuf.message.Message):
PARTICIPANT_DISCONNECTED_FIELD_NUMBER: builtins.int
LOCAL_TRACK_PUBLISHED_FIELD_NUMBER: builtins.int
LOCAL_TRACK_UNPUBLISHED_FIELD_NUMBER: builtins.int
+ LOCAL_TRACK_SUBSCRIBED_FIELD_NUMBER: builtins.int
TRACK_PUBLISHED_FIELD_NUMBER: builtins.int
TRACK_UNPUBLISHED_FIELD_NUMBER: builtins.int
TRACK_SUBSCRIBED_FIELD_NUMBER: builtins.int
@@ -956,8 +1313,10 @@ class RoomEvent(google.protobuf.message.Message):
TRACK_UNMUTED_FIELD_NUMBER: builtins.int
ACTIVE_SPEAKERS_CHANGED_FIELD_NUMBER: builtins.int
ROOM_METADATA_CHANGED_FIELD_NUMBER: builtins.int
+ ROOM_SID_CHANGED_FIELD_NUMBER: builtins.int
PARTICIPANT_METADATA_CHANGED_FIELD_NUMBER: builtins.int
PARTICIPANT_NAME_CHANGED_FIELD_NUMBER: builtins.int
+ PARTICIPANT_ATTRIBUTES_CHANGED_FIELD_NUMBER: builtins.int
CONNECTION_QUALITY_CHANGED_FIELD_NUMBER: builtins.int
CONNECTION_STATE_CHANGED_FIELD_NUMBER: builtins.int
DISCONNECTED_FIELD_NUMBER: builtins.int
@@ -966,6 +1325,23 @@ class RoomEvent(google.protobuf.message.Message):
E2EE_STATE_CHANGED_FIELD_NUMBER: builtins.int
EOS_FIELD_NUMBER: builtins.int
DATA_PACKET_RECEIVED_FIELD_NUMBER: builtins.int
+ TRANSCRIPTION_RECEIVED_FIELD_NUMBER: builtins.int
+ CHAT_MESSAGE_FIELD_NUMBER: builtins.int
+ STREAM_HEADER_RECEIVED_FIELD_NUMBER: builtins.int
+ STREAM_CHUNK_RECEIVED_FIELD_NUMBER: builtins.int
+ STREAM_TRAILER_RECEIVED_FIELD_NUMBER: builtins.int
+ DATA_CHANNEL_LOW_THRESHOLD_CHANGED_FIELD_NUMBER: builtins.int
+ BYTE_STREAM_OPENED_FIELD_NUMBER: builtins.int
+ TEXT_STREAM_OPENED_FIELD_NUMBER: builtins.int
+ ROOM_UPDATED_FIELD_NUMBER: builtins.int
+ MOVED_FIELD_NUMBER: builtins.int
+ PARTICIPANTS_UPDATED_FIELD_NUMBER: builtins.int
+ PARTICIPANT_ENCRYPTION_STATUS_CHANGED_FIELD_NUMBER: builtins.int
+ PARTICIPANT_PERMISSION_CHANGED_FIELD_NUMBER: builtins.int
+ TOKEN_REFRESHED_FIELD_NUMBER: builtins.int
+ PARTICIPANT_ACTIVE_FIELD_NUMBER: builtins.int
+ DATA_TRACK_PUBLISHED_FIELD_NUMBER: builtins.int
+ DATA_TRACK_UNPUBLISHED_FIELD_NUMBER: builtins.int
room_handle: builtins.int
@property
def participant_connected(self) -> global___ParticipantConnected: ...
@@ -976,6 +1352,8 @@ class RoomEvent(google.protobuf.message.Message):
@property
def local_track_unpublished(self) -> global___LocalTrackUnpublished: ...
@property
+ def local_track_subscribed(self) -> global___LocalTrackSubscribed: ...
+ @property
def track_published(self) -> global___TrackPublished: ...
@property
def track_unpublished(self) -> global___TrackUnpublished: ...
@@ -994,16 +1372,21 @@ class RoomEvent(google.protobuf.message.Message):
@property
def room_metadata_changed(self) -> global___RoomMetadataChanged: ...
@property
+ def room_sid_changed(self) -> global___RoomSidChanged: ...
+ @property
def participant_metadata_changed(self) -> global___ParticipantMetadataChanged: ...
@property
def participant_name_changed(self) -> global___ParticipantNameChanged: ...
@property
+ def participant_attributes_changed(self) -> global___ParticipantAttributesChanged: ...
+ @property
def connection_quality_changed(self) -> global___ConnectionQualityChanged: ...
@property
def connection_state_changed(self) -> global___ConnectionStateChanged: ...
@property
def disconnected(self) -> global___Disconnected:
- """Connected connected = 20;"""
+ """Connected connected = 21;"""
+
@property
def reconnecting(self) -> global___Reconnecting: ...
@property
@@ -1013,16 +1396,62 @@ class RoomEvent(google.protobuf.message.Message):
@property
def eos(self) -> global___RoomEOS:
"""The stream of room events has ended"""
+
@property
def data_packet_received(self) -> global___DataPacketReceived: ...
+ @property
+ def transcription_received(self) -> global___TranscriptionReceived: ...
+ @property
+ def chat_message(self) -> global___ChatMessageReceived: ...
+ @property
+ def stream_header_received(self) -> global___DataStreamHeaderReceived:
+ """Data stream (low level)"""
+
+ @property
+ def stream_chunk_received(self) -> global___DataStreamChunkReceived: ...
+ @property
+ def stream_trailer_received(self) -> global___DataStreamTrailerReceived: ...
+ @property
+ def data_channel_low_threshold_changed(self) -> global___DataChannelBufferedAmountLowThresholdChanged: ...
+ @property
+ def byte_stream_opened(self) -> global___ByteStreamOpened:
+ """Data stream (high level)"""
+
+ @property
+ def text_stream_opened(self) -> global___TextStreamOpened: ...
+ @property
+ def room_updated(self) -> global___RoomInfo:
+ """Room info updated"""
+
+ @property
+ def moved(self) -> global___RoomInfo:
+ """Participant moved to new room"""
+
+ @property
+ def participants_updated(self) -> global___ParticipantsUpdated:
+ """carry over all participant info updates, including sid"""
+
+ @property
+ def participant_encryption_status_changed(self) -> global___ParticipantEncryptionStatusChanged: ...
+ @property
+ def participant_permission_changed(self) -> global___ParticipantPermissionChanged: ...
+ @property
+ def token_refreshed(self) -> global___TokenRefreshed: ...
+ @property
+ def participant_active(self) -> global___ParticipantActive: ...
+ @property
+ def data_track_published(self) -> global___DataTrackPublished: ...
+ @property
+ def data_track_unpublished(self) -> global___DataTrackUnpublished: ...
def __init__(
self,
*,
- room_handle: builtins.int = ...,
+ room_handle: builtins.int | None = ...,
participant_connected: global___ParticipantConnected | None = ...,
participant_disconnected: global___ParticipantDisconnected | None = ...,
local_track_published: global___LocalTrackPublished | None = ...,
local_track_unpublished: global___LocalTrackUnpublished | None = ...,
+ local_track_subscribed: global___LocalTrackSubscribed | None = ...,
track_published: global___TrackPublished | None = ...,
track_unpublished: global___TrackUnpublished | None = ...,
track_subscribed: global___TrackSubscribed | None = ...,
@@ -1032,8 +1461,10 @@ class RoomEvent(google.protobuf.message.Message):
track_unmuted: global___TrackUnmuted | None = ...,
active_speakers_changed: global___ActiveSpeakersChanged | None = ...,
room_metadata_changed: global___RoomMetadataChanged | None = ...,
+ room_sid_changed: global___RoomSidChanged | None = ...,
participant_metadata_changed: global___ParticipantMetadataChanged | None = ...,
participant_name_changed: global___ParticipantNameChanged | None = ...,
+ participant_attributes_changed: global___ParticipantAttributesChanged | None = ...,
connection_quality_changed: global___ConnectionQualityChanged | None = ...,
connection_state_changed: global___ConnectionStateChanged | None = ...,
disconnected: global___Disconnected | None = ...,
@@ -1042,35 +1473,80 @@ class RoomEvent(google.protobuf.message.Message):
e2ee_state_changed: global___E2eeStateChanged | None = ...,
eos: global___RoomEOS | None = ...,
data_packet_received: global___DataPacketReceived | None = ...,
- ) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["active_speakers_changed", b"active_speakers_changed", "connection_quality_changed", b"connection_quality_changed", "connection_state_changed", b"connection_state_changed", "data_packet_received", b"data_packet_received", "disconnected", b"disconnected", "e2ee_state_changed", b"e2ee_state_changed", "eos", b"eos", "local_track_published", b"local_track_published", "local_track_unpublished", b"local_track_unpublished", "message", b"message", "participant_connected", b"participant_connected", "participant_disconnected", b"participant_disconnected", "participant_metadata_changed", b"participant_metadata_changed", "participant_name_changed", b"participant_name_changed", "reconnected", b"reconnected", "reconnecting", b"reconnecting", "room_metadata_changed", b"room_metadata_changed", "track_muted", b"track_muted", "track_published", b"track_published", "track_subscribed", b"track_subscribed", "track_subscription_failed", b"track_subscription_failed", "track_unmuted", b"track_unmuted", "track_unpublished", b"track_unpublished", "track_unsubscribed", b"track_unsubscribed"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["active_speakers_changed", b"active_speakers_changed", "connection_quality_changed", b"connection_quality_changed", "connection_state_changed", b"connection_state_changed", "data_packet_received", b"data_packet_received", "disconnected", b"disconnected", "e2ee_state_changed", b"e2ee_state_changed", "eos", b"eos", "local_track_published", b"local_track_published", "local_track_unpublished", b"local_track_unpublished", "message", b"message", "participant_connected", b"participant_connected", "participant_disconnected", b"participant_disconnected", "participant_metadata_changed", b"participant_metadata_changed", "participant_name_changed", b"participant_name_changed", "reconnected", b"reconnected", "reconnecting", b"reconnecting", "room_handle", b"room_handle", "room_metadata_changed", b"room_metadata_changed", "track_muted", b"track_muted", "track_published", b"track_published", "track_subscribed", b"track_subscribed", "track_subscription_failed", b"track_subscription_failed", "track_unmuted", b"track_unmuted", "track_unpublished", b"track_unpublished", "track_unsubscribed", b"track_unsubscribed"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["message", b"message"]) -> typing_extensions.Literal["participant_connected", "participant_disconnected", "local_track_published", "local_track_unpublished", "track_published", "track_unpublished", "track_subscribed", "track_unsubscribed", "track_subscription_failed", "track_muted", "track_unmuted", "active_speakers_changed", "room_metadata_changed", "participant_metadata_changed", "participant_name_changed", "connection_quality_changed", "connection_state_changed", "disconnected", "reconnecting", "reconnected", "e2ee_state_changed", "eos", "data_packet_received"] | None: ...
+ transcription_received: global___TranscriptionReceived | None = ...,
+ chat_message: global___ChatMessageReceived | None = ...,
+ stream_header_received: global___DataStreamHeaderReceived | None = ...,
+ stream_chunk_received: global___DataStreamChunkReceived | None = ...,
+ stream_trailer_received: global___DataStreamTrailerReceived | None = ...,
+ data_channel_low_threshold_changed: global___DataChannelBufferedAmountLowThresholdChanged | None = ...,
+ byte_stream_opened: global___ByteStreamOpened | None = ...,
+ text_stream_opened: global___TextStreamOpened | None = ...,
+ room_updated: global___RoomInfo | None = ...,
+ moved: global___RoomInfo | None = ...,
+ participants_updated: global___ParticipantsUpdated | None = ...,
+ participant_encryption_status_changed: global___ParticipantEncryptionStatusChanged | None = ...,
+ participant_permission_changed: global___ParticipantPermissionChanged | None = ...,
+ token_refreshed: global___TokenRefreshed | None = ...,
+ participant_active: global___ParticipantActive | None = ...,
+ data_track_published: global___DataTrackPublished | None = ...,
+ data_track_unpublished: global___DataTrackUnpublished | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["active_speakers_changed", b"active_speakers_changed", "byte_stream_opened", b"byte_stream_opened", "chat_message", b"chat_message", "connection_quality_changed", b"connection_quality_changed", "connection_state_changed", b"connection_state_changed", "data_channel_low_threshold_changed", b"data_channel_low_threshold_changed", "data_packet_received", b"data_packet_received", "data_track_published", b"data_track_published", "data_track_unpublished", b"data_track_unpublished", "disconnected", b"disconnected", "e2ee_state_changed", b"e2ee_state_changed", "eos", b"eos", "local_track_published", b"local_track_published", "local_track_subscribed", b"local_track_subscribed", "local_track_unpublished", b"local_track_unpublished", "message", b"message", "moved", b"moved", "participant_active", b"participant_active", "participant_attributes_changed", b"participant_attributes_changed", "participant_connected", b"participant_connected", "participant_disconnected", b"participant_disconnected", "participant_encryption_status_changed", b"participant_encryption_status_changed", "participant_metadata_changed", b"participant_metadata_changed", "participant_name_changed", b"participant_name_changed", "participant_permission_changed", b"participant_permission_changed", "participants_updated", b"participants_updated", "reconnected", b"reconnected", "reconnecting", b"reconnecting", "room_handle", b"room_handle", "room_metadata_changed", b"room_metadata_changed", "room_sid_changed", b"room_sid_changed", "room_updated", b"room_updated", "stream_chunk_received", b"stream_chunk_received", "stream_header_received", b"stream_header_received", "stream_trailer_received", b"stream_trailer_received", "text_stream_opened", b"text_stream_opened", "token_refreshed", b"token_refreshed", "track_muted", b"track_muted", "track_published", b"track_published", "track_subscribed", b"track_subscribed", "track_subscription_failed", b"track_subscription_failed", "track_unmuted", b"track_unmuted", "track_unpublished", b"track_unpublished", "track_unsubscribed", b"track_unsubscribed", "transcription_received", b"transcription_received"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["active_speakers_changed", b"active_speakers_changed", "byte_stream_opened", b"byte_stream_opened", "chat_message", b"chat_message", "connection_quality_changed", b"connection_quality_changed", "connection_state_changed", b"connection_state_changed", "data_channel_low_threshold_changed", b"data_channel_low_threshold_changed", "data_packet_received", b"data_packet_received", "data_track_published", b"data_track_published", "data_track_unpublished", b"data_track_unpublished", "disconnected", b"disconnected", "e2ee_state_changed", b"e2ee_state_changed", "eos", b"eos", "local_track_published", b"local_track_published", "local_track_subscribed", b"local_track_subscribed", "local_track_unpublished", b"local_track_unpublished", "message", b"message", "moved", b"moved", "participant_active", b"participant_active", "participant_attributes_changed", b"participant_attributes_changed", "participant_connected", b"participant_connected", "participant_disconnected", b"participant_disconnected", "participant_encryption_status_changed", b"participant_encryption_status_changed", "participant_metadata_changed", b"participant_metadata_changed", "participant_name_changed", b"participant_name_changed", "participant_permission_changed", b"participant_permission_changed", "participants_updated", b"participants_updated", "reconnected", b"reconnected", "reconnecting", b"reconnecting", "room_handle", b"room_handle", "room_metadata_changed", b"room_metadata_changed", "room_sid_changed", b"room_sid_changed", "room_updated", b"room_updated", "stream_chunk_received", b"stream_chunk_received", "stream_header_received", b"stream_header_received", "stream_trailer_received", b"stream_trailer_received", "text_stream_opened", b"text_stream_opened", "token_refreshed", b"token_refreshed", "track_muted", b"track_muted", "track_published", b"track_published", "track_subscribed", b"track_subscribed", "track_subscription_failed", b"track_subscription_failed", "track_unmuted", b"track_unmuted", "track_unpublished", b"track_unpublished", "track_unsubscribed", b"track_unsubscribed", "transcription_received", b"transcription_received"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["message", b"message"]) -> typing.Literal["participant_connected", "participant_disconnected", "local_track_published", "local_track_unpublished", "local_track_subscribed", "track_published", "track_unpublished", "track_subscribed", "track_unsubscribed", "track_subscription_failed", "track_muted", "track_unmuted", "active_speakers_changed", "room_metadata_changed", "room_sid_changed", "participant_metadata_changed", "participant_name_changed", "participant_attributes_changed", "connection_quality_changed", "connection_state_changed", "disconnected", "reconnecting", "reconnected", "e2ee_state_changed", "eos", "data_packet_received", "transcription_received", "chat_message", "stream_header_received", "stream_chunk_received", "stream_trailer_received", "data_channel_low_threshold_changed", "byte_stream_opened", "text_stream_opened", "room_updated", "moved", "participants_updated", "participant_encryption_status_changed", "participant_permission_changed", "token_refreshed", "participant_active", "data_track_published", "data_track_unpublished"] | None: ...
global___RoomEvent = RoomEvent
-@typing_extensions.final
+@typing.final
class RoomInfo(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
SID_FIELD_NUMBER: builtins.int
NAME_FIELD_NUMBER: builtins.int
METADATA_FIELD_NUMBER: builtins.int
+ LOSSY_DC_BUFFERED_AMOUNT_LOW_THRESHOLD_FIELD_NUMBER: builtins.int
+ RELIABLE_DC_BUFFERED_AMOUNT_LOW_THRESHOLD_FIELD_NUMBER: builtins.int
+ EMPTY_TIMEOUT_FIELD_NUMBER: builtins.int
+ DEPARTURE_TIMEOUT_FIELD_NUMBER: builtins.int
+ MAX_PARTICIPANTS_FIELD_NUMBER: builtins.int
+ CREATION_TIME_FIELD_NUMBER: builtins.int
+ NUM_PARTICIPANTS_FIELD_NUMBER: builtins.int
+ NUM_PUBLISHERS_FIELD_NUMBER: builtins.int
+ ACTIVE_RECORDING_FIELD_NUMBER: builtins.int
sid: builtins.str
name: builtins.str
metadata: builtins.str
+ lossy_dc_buffered_amount_low_threshold: builtins.int
+ reliable_dc_buffered_amount_low_threshold: builtins.int
+ empty_timeout: builtins.int
+ departure_timeout: builtins.int
+ max_participants: builtins.int
+ creation_time: builtins.int
+ num_participants: builtins.int
+ num_publishers: builtins.int
+ active_recording: builtins.bool
def __init__(
self,
*,
- sid: builtins.str = ...,
- name: builtins.str = ...,
- metadata: builtins.str = ...,
- ) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["metadata", b"metadata", "name", b"name", "sid", b"sid"]) -> None: ...
+ sid: builtins.str | None = ...,
+ name: builtins.str | None = ...,
+ metadata: builtins.str | None = ...,
+ lossy_dc_buffered_amount_low_threshold: builtins.int | None = ...,
+ reliable_dc_buffered_amount_low_threshold: builtins.int | None = ...,
+ empty_timeout: builtins.int | None = ...,
+ departure_timeout: builtins.int | None = ...,
+ max_participants: builtins.int | None = ...,
+ creation_time: builtins.int | None = ...,
+ num_participants: builtins.int | None = ...,
+ num_publishers: builtins.int | None = ...,
+ active_recording: builtins.bool | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["active_recording", b"active_recording", "creation_time", b"creation_time", "departure_timeout", b"departure_timeout", "empty_timeout", b"empty_timeout", "lossy_dc_buffered_amount_low_threshold", b"lossy_dc_buffered_amount_low_threshold", "max_participants", b"max_participants", "metadata", b"metadata", "name", b"name", "num_participants", b"num_participants", "num_publishers", b"num_publishers", "reliable_dc_buffered_amount_low_threshold", b"reliable_dc_buffered_amount_low_threshold", "sid", b"sid"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["active_recording", b"active_recording", "creation_time", b"creation_time", "departure_timeout", b"departure_timeout", "empty_timeout", b"empty_timeout", "lossy_dc_buffered_amount_low_threshold", b"lossy_dc_buffered_amount_low_threshold", "max_participants", b"max_participants", "metadata", b"metadata", "name", b"name", "num_participants", b"num_participants", "num_publishers", b"num_publishers", "reliable_dc_buffered_amount_low_threshold", b"reliable_dc_buffered_amount_low_threshold", "sid", b"sid"]) -> None: ...
global___RoomInfo = RoomInfo
-@typing_extensions.final
+@typing.final
class OwnedRoom(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -1086,12 +1562,28 @@ class OwnedRoom(google.protobuf.message.Message):
handle: handle_pb2.FfiOwnedHandle | None = ...,
info: global___RoomInfo | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["handle", b"handle", "info", b"info"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["handle", b"handle", "info", b"info"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> None: ...
global___OwnedRoom = OwnedRoom
-@typing_extensions.final
+@typing.final
+class ParticipantsUpdated(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ PARTICIPANTS_FIELD_NUMBER: builtins.int
+ @property
+ def participants(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[participant_pb2.ParticipantInfo]: ...
+ def __init__(
+ self,
+ *,
+ participants: collections.abc.Iterable[participant_pb2.ParticipantInfo] | None = ...,
+ ) -> None: ...
+ def ClearField(self, field_name: typing.Literal["participants", b"participants"]) -> None: ...
+
+global___ParticipantsUpdated = ParticipantsUpdated
+
+@typing.final
class ParticipantConnected(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -1103,27 +1595,47 @@ class ParticipantConnected(google.protobuf.message.Message):
*,
info: participant_pb2.OwnedParticipant | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["info", b"info"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["info", b"info"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["info", b"info"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["info", b"info"]) -> None: ...
global___ParticipantConnected = ParticipantConnected
-@typing_extensions.final
+@typing.final
+class ParticipantActive(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: builtins.int
+ participant_identity: builtins.str
+ def __init__(
+ self,
+ *,
+ participant_identity: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["participant_identity", b"participant_identity"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["participant_identity", b"participant_identity"]) -> None: ...
+
+global___ParticipantActive = ParticipantActive
+
+@typing.final
class ParticipantDisconnected(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
- PARTICIPANT_SID_FIELD_NUMBER: builtins.int
- participant_sid: builtins.str
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: builtins.int
+ DISCONNECT_REASON_FIELD_NUMBER: builtins.int
+ participant_identity: builtins.str
+ disconnect_reason: participant_pb2.DisconnectReason.ValueType
def __init__(
self,
*,
- participant_sid: builtins.str = ...,
+ participant_identity: builtins.str | None = ...,
+ disconnect_reason: participant_pb2.DisconnectReason.ValueType | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["participant_sid", b"participant_sid"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["disconnect_reason", b"disconnect_reason", "participant_identity", b"participant_identity"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["disconnect_reason", b"disconnect_reason", "participant_identity", b"participant_identity"]) -> None: ...
global___ParticipantDisconnected = ParticipantDisconnected
-@typing_extensions.final
+@typing.final
class LocalTrackPublished(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -1135,13 +1647,14 @@ class LocalTrackPublished(google.protobuf.message.Message):
def __init__(
self,
*,
- track_sid: builtins.str = ...,
+ track_sid: builtins.str | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["track_sid", b"track_sid"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["track_sid", b"track_sid"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["track_sid", b"track_sid"]) -> None: ...
global___LocalTrackPublished = LocalTrackPublished
-@typing_extensions.final
+@typing.final
class LocalTrackUnpublished(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -1150,51 +1663,69 @@ class LocalTrackUnpublished(google.protobuf.message.Message):
def __init__(
self,
*,
- publication_sid: builtins.str = ...,
+ publication_sid: builtins.str | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["publication_sid", b"publication_sid"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["publication_sid", b"publication_sid"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["publication_sid", b"publication_sid"]) -> None: ...
global___LocalTrackUnpublished = LocalTrackUnpublished
-@typing_extensions.final
+@typing.final
+class LocalTrackSubscribed(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ TRACK_SID_FIELD_NUMBER: builtins.int
+ track_sid: builtins.str
+ def __init__(
+ self,
+ *,
+ track_sid: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["track_sid", b"track_sid"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["track_sid", b"track_sid"]) -> None: ...
+
+global___LocalTrackSubscribed = LocalTrackSubscribed
+
+@typing.final
class TrackPublished(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
- PARTICIPANT_SID_FIELD_NUMBER: builtins.int
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: builtins.int
PUBLICATION_FIELD_NUMBER: builtins.int
- participant_sid: builtins.str
+ participant_identity: builtins.str
@property
def publication(self) -> track_pb2.OwnedTrackPublication: ...
def __init__(
self,
*,
- participant_sid: builtins.str = ...,
+ participant_identity: builtins.str | None = ...,
publication: track_pb2.OwnedTrackPublication | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["publication", b"publication"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["participant_sid", b"participant_sid", "publication", b"publication"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["participant_identity", b"participant_identity", "publication", b"publication"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["participant_identity", b"participant_identity", "publication", b"publication"]) -> None: ...
global___TrackPublished = TrackPublished
-@typing_extensions.final
+@typing.final
class TrackUnpublished(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
- PARTICIPANT_SID_FIELD_NUMBER: builtins.int
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: builtins.int
PUBLICATION_SID_FIELD_NUMBER: builtins.int
- participant_sid: builtins.str
+ participant_identity: builtins.str
publication_sid: builtins.str
def __init__(
self,
*,
- participant_sid: builtins.str = ...,
- publication_sid: builtins.str = ...,
+ participant_identity: builtins.str | None = ...,
+ publication_sid: builtins.str | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["participant_sid", b"participant_sid", "publication_sid", b"publication_sid"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["participant_identity", b"participant_identity", "publication_sid", b"publication_sid"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["participant_identity", b"participant_identity", "publication_sid", b"publication_sid"]) -> None: ...
global___TrackUnpublished = TrackUnpublished
-@typing_extensions.final
+@typing.final
class TrackSubscribed(google.protobuf.message.Message):
"""Publication isn't needed for subscription events on the FFI
The FFI will retrieve the publication using the Track sid
@@ -1202,134 +1733,139 @@ class TrackSubscribed(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
- PARTICIPANT_SID_FIELD_NUMBER: builtins.int
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: builtins.int
TRACK_FIELD_NUMBER: builtins.int
- participant_sid: builtins.str
+ participant_identity: builtins.str
@property
def track(self) -> track_pb2.OwnedTrack: ...
def __init__(
self,
*,
- participant_sid: builtins.str = ...,
+ participant_identity: builtins.str | None = ...,
track: track_pb2.OwnedTrack | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["track", b"track"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["participant_sid", b"participant_sid", "track", b"track"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["participant_identity", b"participant_identity", "track", b"track"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["participant_identity", b"participant_identity", "track", b"track"]) -> None: ...
global___TrackSubscribed = TrackSubscribed
-@typing_extensions.final
+@typing.final
class TrackUnsubscribed(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
- PARTICIPANT_SID_FIELD_NUMBER: builtins.int
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: builtins.int
TRACK_SID_FIELD_NUMBER: builtins.int
- participant_sid: builtins.str
+ participant_identity: builtins.str
"""The FFI language can dispose/remove the VideoSink here"""
track_sid: builtins.str
def __init__(
self,
*,
- participant_sid: builtins.str = ...,
- track_sid: builtins.str = ...,
+ participant_identity: builtins.str | None = ...,
+ track_sid: builtins.str | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["participant_sid", b"participant_sid", "track_sid", b"track_sid"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["participant_identity", b"participant_identity", "track_sid", b"track_sid"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["participant_identity", b"participant_identity", "track_sid", b"track_sid"]) -> None: ...
global___TrackUnsubscribed = TrackUnsubscribed
-@typing_extensions.final
+@typing.final
class TrackSubscriptionFailed(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
- PARTICIPANT_SID_FIELD_NUMBER: builtins.int
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: builtins.int
TRACK_SID_FIELD_NUMBER: builtins.int
ERROR_FIELD_NUMBER: builtins.int
- participant_sid: builtins.str
+ participant_identity: builtins.str
track_sid: builtins.str
error: builtins.str
def __init__(
self,
*,
- participant_sid: builtins.str = ...,
- track_sid: builtins.str = ...,
- error: builtins.str = ...,
+ participant_identity: builtins.str | None = ...,
+ track_sid: builtins.str | None = ...,
+ error: builtins.str | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["error", b"error", "participant_sid", b"participant_sid", "track_sid", b"track_sid"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["error", b"error", "participant_identity", b"participant_identity", "track_sid", b"track_sid"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["error", b"error", "participant_identity", b"participant_identity", "track_sid", b"track_sid"]) -> None: ...
global___TrackSubscriptionFailed = TrackSubscriptionFailed
-@typing_extensions.final
+@typing.final
class TrackMuted(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
- PARTICIPANT_SID_FIELD_NUMBER: builtins.int
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: builtins.int
TRACK_SID_FIELD_NUMBER: builtins.int
- participant_sid: builtins.str
+ participant_identity: builtins.str
track_sid: builtins.str
def __init__(
self,
*,
- participant_sid: builtins.str = ...,
- track_sid: builtins.str = ...,
+ participant_identity: builtins.str | None = ...,
+ track_sid: builtins.str | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["participant_sid", b"participant_sid", "track_sid", b"track_sid"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["participant_identity", b"participant_identity", "track_sid", b"track_sid"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["participant_identity", b"participant_identity", "track_sid", b"track_sid"]) -> None: ...
global___TrackMuted = TrackMuted
-@typing_extensions.final
+@typing.final
class TrackUnmuted(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
- PARTICIPANT_SID_FIELD_NUMBER: builtins.int
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: builtins.int
TRACK_SID_FIELD_NUMBER: builtins.int
- participant_sid: builtins.str
+ participant_identity: builtins.str
track_sid: builtins.str
def __init__(
self,
*,
- participant_sid: builtins.str = ...,
- track_sid: builtins.str = ...,
+ participant_identity: builtins.str | None = ...,
+ track_sid: builtins.str | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["participant_sid", b"participant_sid", "track_sid", b"track_sid"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["participant_identity", b"participant_identity", "track_sid", b"track_sid"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["participant_identity", b"participant_identity", "track_sid", b"track_sid"]) -> None: ...
global___TrackUnmuted = TrackUnmuted
-@typing_extensions.final
+@typing.final
class E2eeStateChanged(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
- PARTICIPANT_SID_FIELD_NUMBER: builtins.int
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: builtins.int
STATE_FIELD_NUMBER: builtins.int
- participant_sid: builtins.str
+ participant_identity: builtins.str
"""Using sid instead of identity for ffi communication"""
state: e2ee_pb2.EncryptionState.ValueType
def __init__(
self,
*,
- participant_sid: builtins.str = ...,
- state: e2ee_pb2.EncryptionState.ValueType = ...,
+ participant_identity: builtins.str | None = ...,
+ state: e2ee_pb2.EncryptionState.ValueType | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["participant_sid", b"participant_sid", "state", b"state"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["participant_identity", b"participant_identity", "state", b"state"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["participant_identity", b"participant_identity", "state", b"state"]) -> None: ...
global___E2eeStateChanged = E2eeStateChanged
-@typing_extensions.final
+@typing.final
class ActiveSpeakersChanged(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
- PARTICIPANT_SIDS_FIELD_NUMBER: builtins.int
+ PARTICIPANT_IDENTITIES_FIELD_NUMBER: builtins.int
@property
- def participant_sids(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ...
+ def participant_identities(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ...
def __init__(
self,
*,
- participant_sids: collections.abc.Iterable[builtins.str] | None = ...,
+ participant_identities: collections.abc.Iterable[builtins.str] | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["participant_sids", b"participant_sids"]) -> None: ...
+ def ClearField(self, field_name: typing.Literal["participant_identities", b"participant_identities"]) -> None: ...
global___ActiveSpeakersChanged = ActiveSpeakersChanged
-@typing_extensions.final
+@typing.final
class RoomMetadataChanged(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -1338,88 +1874,221 @@ class RoomMetadataChanged(google.protobuf.message.Message):
def __init__(
self,
*,
- metadata: builtins.str = ...,
+ metadata: builtins.str | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["metadata", b"metadata"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["metadata", b"metadata"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["metadata", b"metadata"]) -> None: ...
global___RoomMetadataChanged = RoomMetadataChanged
-@typing_extensions.final
+@typing.final
+class RoomSidChanged(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ SID_FIELD_NUMBER: builtins.int
+ sid: builtins.str
+ def __init__(
+ self,
+ *,
+ sid: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["sid", b"sid"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["sid", b"sid"]) -> None: ...
+
+global___RoomSidChanged = RoomSidChanged
+
+@typing.final
class ParticipantMetadataChanged(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
- PARTICIPANT_SID_FIELD_NUMBER: builtins.int
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: builtins.int
METADATA_FIELD_NUMBER: builtins.int
- participant_sid: builtins.str
+ participant_identity: builtins.str
metadata: builtins.str
def __init__(
self,
*,
- participant_sid: builtins.str = ...,
- metadata: builtins.str = ...,
+ participant_identity: builtins.str | None = ...,
+ metadata: builtins.str | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["metadata", b"metadata", "participant_sid", b"participant_sid"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["metadata", b"metadata", "participant_identity", b"participant_identity"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["metadata", b"metadata", "participant_identity", b"participant_identity"]) -> None: ...
global___ParticipantMetadataChanged = ParticipantMetadataChanged
-@typing_extensions.final
+@typing.final
+class ParticipantAttributesChanged(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: builtins.int
+ ATTRIBUTES_FIELD_NUMBER: builtins.int
+ CHANGED_ATTRIBUTES_FIELD_NUMBER: builtins.int
+ participant_identity: builtins.str
+ @property
+ def attributes(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___AttributesEntry]: ...
+ @property
+ def changed_attributes(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___AttributesEntry]: ...
+ def __init__(
+ self,
+ *,
+ participant_identity: builtins.str | None = ...,
+ attributes: collections.abc.Iterable[global___AttributesEntry] | None = ...,
+ changed_attributes: collections.abc.Iterable[global___AttributesEntry] | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["participant_identity", b"participant_identity"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["attributes", b"attributes", "changed_attributes", b"changed_attributes", "participant_identity", b"participant_identity"]) -> None: ...
+
+global___ParticipantAttributesChanged = ParticipantAttributesChanged
+
+@typing.final
+class ParticipantEncryptionStatusChanged(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: builtins.int
+ IS_ENCRYPTED_FIELD_NUMBER: builtins.int
+ participant_identity: builtins.str
+ is_encrypted: builtins.bool
+ def __init__(
+ self,
+ *,
+ participant_identity: builtins.str | None = ...,
+ is_encrypted: builtins.bool | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["is_encrypted", b"is_encrypted", "participant_identity", b"participant_identity"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["is_encrypted", b"is_encrypted", "participant_identity", b"participant_identity"]) -> None: ...
+
+global___ParticipantEncryptionStatusChanged = ParticipantEncryptionStatusChanged
+
+@typing.final
class ParticipantNameChanged(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
- PARTICIPANT_SID_FIELD_NUMBER: builtins.int
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: builtins.int
NAME_FIELD_NUMBER: builtins.int
- participant_sid: builtins.str
+ participant_identity: builtins.str
name: builtins.str
def __init__(
self,
*,
- participant_sid: builtins.str = ...,
- name: builtins.str = ...,
+ participant_identity: builtins.str | None = ...,
+ name: builtins.str | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["name", b"name", "participant_sid", b"participant_sid"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["name", b"name", "participant_identity", b"participant_identity"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["name", b"name", "participant_identity", b"participant_identity"]) -> None: ...
global___ParticipantNameChanged = ParticipantNameChanged
-@typing_extensions.final
+@typing.final
+class ParticipantPermissionChanged(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: builtins.int
+ PERMISSION_FIELD_NUMBER: builtins.int
+ participant_identity: builtins.str
+ @property
+ def permission(self) -> participant_pb2.ParticipantPermission: ...
+ def __init__(
+ self,
+ *,
+ participant_identity: builtins.str | None = ...,
+ permission: participant_pb2.ParticipantPermission | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["participant_identity", b"participant_identity", "permission", b"permission"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["participant_identity", b"participant_identity", "permission", b"permission"]) -> None: ...
+
+global___ParticipantPermissionChanged = ParticipantPermissionChanged
+
+@typing.final
class ConnectionQualityChanged(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
- PARTICIPANT_SID_FIELD_NUMBER: builtins.int
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: builtins.int
QUALITY_FIELD_NUMBER: builtins.int
- participant_sid: builtins.str
+ participant_identity: builtins.str
quality: global___ConnectionQuality.ValueType
def __init__(
self,
*,
- participant_sid: builtins.str = ...,
- quality: global___ConnectionQuality.ValueType = ...,
+ participant_identity: builtins.str | None = ...,
+ quality: global___ConnectionQuality.ValueType | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["participant_sid", b"participant_sid", "quality", b"quality"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["participant_identity", b"participant_identity", "quality", b"quality"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["participant_identity", b"participant_identity", "quality", b"quality"]) -> None: ...
global___ConnectionQualityChanged = ConnectionQualityChanged
-@typing_extensions.final
+@typing.final
class UserPacket(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
DATA_FIELD_NUMBER: builtins.int
TOPIC_FIELD_NUMBER: builtins.int
+ topic: builtins.str
@property
def data(self) -> global___OwnedBuffer: ...
- topic: builtins.str
def __init__(
self,
*,
data: global___OwnedBuffer | None = ...,
topic: builtins.str | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_topic", b"_topic", "data", b"data", "topic", b"topic"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_topic", b"_topic", "data", b"data", "topic", b"topic"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_topic", b"_topic"]) -> typing_extensions.Literal["topic"] | None: ...
+ def HasField(self, field_name: typing.Literal["data", b"data", "topic", b"topic"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["data", b"data", "topic", b"topic"]) -> None: ...
global___UserPacket = UserPacket
-@typing_extensions.final
+@typing.final
+class ChatMessage(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ID_FIELD_NUMBER: builtins.int
+ TIMESTAMP_FIELD_NUMBER: builtins.int
+ MESSAGE_FIELD_NUMBER: builtins.int
+ EDIT_TIMESTAMP_FIELD_NUMBER: builtins.int
+ DELETED_FIELD_NUMBER: builtins.int
+ GENERATED_FIELD_NUMBER: builtins.int
+ id: builtins.str
+ timestamp: builtins.int
+ message: builtins.str
+ edit_timestamp: builtins.int
+ deleted: builtins.bool
+ generated: builtins.bool
+ def __init__(
+ self,
+ *,
+ id: builtins.str | None = ...,
+ timestamp: builtins.int | None = ...,
+ message: builtins.str | None = ...,
+ edit_timestamp: builtins.int | None = ...,
+ deleted: builtins.bool | None = ...,
+ generated: builtins.bool | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["deleted", b"deleted", "edit_timestamp", b"edit_timestamp", "generated", b"generated", "id", b"id", "message", b"message", "timestamp", b"timestamp"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["deleted", b"deleted", "edit_timestamp", b"edit_timestamp", "generated", b"generated", "id", b"id", "message", b"message", "timestamp", b"timestamp"]) -> None: ...
+
+global___ChatMessage = ChatMessage
+
+@typing.final
+class ChatMessageReceived(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ MESSAGE_FIELD_NUMBER: builtins.int
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: builtins.int
+ participant_identity: builtins.str
+ @property
+ def message(self) -> global___ChatMessage: ...
+ def __init__(
+ self,
+ *,
+ message: global___ChatMessage | None = ...,
+ participant_identity: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["message", b"message", "participant_identity", b"participant_identity"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["message", b"message", "participant_identity", b"participant_identity"]) -> None: ...
+
+global___ChatMessageReceived = ChatMessageReceived
+
+@typing.final
class SipDTMF(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -1430,29 +2099,25 @@ class SipDTMF(google.protobuf.message.Message):
def __init__(
self,
*,
- code: builtins.int = ...,
+ code: builtins.int | None = ...,
digit: builtins.str | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_digit", b"_digit", "digit", b"digit"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_digit", b"_digit", "code", b"code", "digit", b"digit"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_digit", b"_digit"]) -> typing_extensions.Literal["digit"] | None: ...
+ def HasField(self, field_name: typing.Literal["code", b"code", "digit", b"digit"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["code", b"code", "digit", b"digit"]) -> None: ...
global___SipDTMF = SipDTMF
-@typing_extensions.final
+@typing.final
class DataPacketReceived(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
KIND_FIELD_NUMBER: builtins.int
PARTICIPANT_IDENTITY_FIELD_NUMBER: builtins.int
- PARTICIPANT_SID_FIELD_NUMBER: builtins.int
USER_FIELD_NUMBER: builtins.int
SIP_DTMF_FIELD_NUMBER: builtins.int
kind: global___DataPacketKind.ValueType
participant_identity: builtins.str
"""Can be empty if the data is sent a server SDK"""
- participant_sid: builtins.str
- """Can be empty if the data is sent a server SDK"""
@property
def user(self) -> global___UserPacket: ...
@property
@@ -1460,22 +2125,41 @@ class DataPacketReceived(google.protobuf.message.Message):
def __init__(
self,
*,
- kind: global___DataPacketKind.ValueType = ...,
- participant_identity: builtins.str = ...,
- participant_sid: builtins.str | None = ...,
+ kind: global___DataPacketKind.ValueType | None = ...,
+ participant_identity: builtins.str | None = ...,
user: global___UserPacket | None = ...,
sip_dtmf: global___SipDTMF | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_participant_sid", b"_participant_sid", "participant_sid", b"participant_sid", "sip_dtmf", b"sip_dtmf", "user", b"user", "value", b"value"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_participant_sid", b"_participant_sid", "kind", b"kind", "participant_identity", b"participant_identity", "participant_sid", b"participant_sid", "sip_dtmf", b"sip_dtmf", "user", b"user", "value", b"value"]) -> None: ...
- @typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_participant_sid", b"_participant_sid"]) -> typing_extensions.Literal["participant_sid"] | None: ...
- @typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["value", b"value"]) -> typing_extensions.Literal["user", "sip_dtmf"] | None: ...
+ def HasField(self, field_name: typing.Literal["kind", b"kind", "participant_identity", b"participant_identity", "sip_dtmf", b"sip_dtmf", "user", b"user", "value", b"value"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["kind", b"kind", "participant_identity", b"participant_identity", "sip_dtmf", b"sip_dtmf", "user", b"user", "value", b"value"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["value", b"value"]) -> typing.Literal["user", "sip_dtmf"] | None: ...
global___DataPacketReceived = DataPacketReceived
-@typing_extensions.final
+@typing.final
+class TranscriptionReceived(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: builtins.int
+ TRACK_SID_FIELD_NUMBER: builtins.int
+ SEGMENTS_FIELD_NUMBER: builtins.int
+ participant_identity: builtins.str
+ track_sid: builtins.str
+ @property
+ def segments(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___TranscriptionSegment]: ...
+ def __init__(
+ self,
+ *,
+ participant_identity: builtins.str | None = ...,
+ track_sid: builtins.str | None = ...,
+ segments: collections.abc.Iterable[global___TranscriptionSegment] | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["participant_identity", b"participant_identity", "track_sid", b"track_sid"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["participant_identity", b"participant_identity", "segments", b"segments", "track_sid", b"track_sid"]) -> None: ...
+
+global___TranscriptionReceived = TranscriptionReceived
+
+@typing.final
class ConnectionStateChanged(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -1484,13 +2168,14 @@ class ConnectionStateChanged(google.protobuf.message.Message):
def __init__(
self,
*,
- state: global___ConnectionState.ValueType = ...,
+ state: global___ConnectionState.ValueType | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["state", b"state"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["state", b"state"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["state", b"state"]) -> None: ...
global___ConnectionStateChanged = ConnectionStateChanged
-@typing_extensions.final
+@typing.final
class Connected(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -1500,17 +2185,23 @@ class Connected(google.protobuf.message.Message):
global___Connected = Connected
-@typing_extensions.final
+@typing.final
class Disconnected(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
+ REASON_FIELD_NUMBER: builtins.int
+ reason: participant_pb2.DisconnectReason.ValueType
def __init__(
self,
+ *,
+ reason: participant_pb2.DisconnectReason.ValueType | None = ...,
) -> None: ...
+ def HasField(self, field_name: typing.Literal["reason", b"reason"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["reason", b"reason"]) -> None: ...
global___Disconnected = Disconnected
-@typing_extensions.final
+@typing.final
class Reconnecting(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -1520,7 +2211,7 @@ class Reconnecting(google.protobuf.message.Message):
global___Reconnecting = Reconnecting
-@typing_extensions.final
+@typing.final
class Reconnected(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -1530,7 +2221,23 @@ class Reconnected(google.protobuf.message.Message):
global___Reconnected = Reconnected
-@typing_extensions.final
+@typing.final
+class TokenRefreshed(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ TOKEN_FIELD_NUMBER: builtins.int
+ token: builtins.str
+ def __init__(
+ self,
+ *,
+ token: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["token", b"token"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["token", b"token"]) -> None: ...
+
+global___TokenRefreshed = TokenRefreshed
+
+@typing.final
class RoomEOS(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -1539,3 +2246,601 @@ class RoomEOS(google.protobuf.message.Message):
) -> None: ...
global___RoomEOS = RoomEOS
+
+@typing.final
+class DataStream(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ class _OperationType:
+ ValueType = typing.NewType("ValueType", builtins.int)
+ V: typing_extensions.TypeAlias = ValueType
+
+ class _OperationTypeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[DataStream._OperationType.ValueType], builtins.type):
+ DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
+ CREATE: DataStream._OperationType.ValueType # 0
+ UPDATE: DataStream._OperationType.ValueType # 1
+ DELETE: DataStream._OperationType.ValueType # 2
+ REACTION: DataStream._OperationType.ValueType # 3
+
+ class OperationType(_OperationType, metaclass=_OperationTypeEnumTypeWrapper):
+ """enum for operation types (specific to TextHeader)"""
+
+ CREATE: DataStream.OperationType.ValueType # 0
+ UPDATE: DataStream.OperationType.ValueType # 1
+ DELETE: DataStream.OperationType.ValueType # 2
+ REACTION: DataStream.OperationType.ValueType # 3
+
+ @typing.final
+ class TextHeader(google.protobuf.message.Message):
+ """header properties specific to text streams"""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ OPERATION_TYPE_FIELD_NUMBER: builtins.int
+ VERSION_FIELD_NUMBER: builtins.int
+ REPLY_TO_STREAM_ID_FIELD_NUMBER: builtins.int
+ ATTACHED_STREAM_IDS_FIELD_NUMBER: builtins.int
+ GENERATED_FIELD_NUMBER: builtins.int
+ operation_type: global___DataStream.OperationType.ValueType
+ version: builtins.int
+ """Optional: Version for updates/edits"""
+ reply_to_stream_id: builtins.str
+ """Optional: Reply to specific message"""
+ generated: builtins.bool
+ """true if the text has been generated by an agent from a participant's audio transcription"""
+ @property
+ def attached_stream_ids(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]:
+ """file attachments for text streams"""
+
+ def __init__(
+ self,
+ *,
+ operation_type: global___DataStream.OperationType.ValueType | None = ...,
+ version: builtins.int | None = ...,
+ reply_to_stream_id: builtins.str | None = ...,
+ attached_stream_ids: collections.abc.Iterable[builtins.str] | None = ...,
+ generated: builtins.bool | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["generated", b"generated", "operation_type", b"operation_type", "reply_to_stream_id", b"reply_to_stream_id", "version", b"version"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["attached_stream_ids", b"attached_stream_ids", "generated", b"generated", "operation_type", b"operation_type", "reply_to_stream_id", b"reply_to_stream_id", "version", b"version"]) -> None: ...
+
+ @typing.final
+ class ByteHeader(google.protobuf.message.Message):
+ """header properties specific to byte or file streams"""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ NAME_FIELD_NUMBER: builtins.int
+ name: builtins.str
+ def __init__(
+ self,
+ *,
+ name: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["name", b"name"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["name", b"name"]) -> None: ...
+
+ @typing.final
+ class Header(google.protobuf.message.Message):
+ """main DataStream.Header that contains a oneof for specific headers"""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ @typing.final
+ class AttributesEntry(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ KEY_FIELD_NUMBER: builtins.int
+ VALUE_FIELD_NUMBER: builtins.int
+ key: builtins.str
+ value: builtins.str
+ def __init__(
+ self,
+ *,
+ key: builtins.str | None = ...,
+ value: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> None: ...
+
+ STREAM_ID_FIELD_NUMBER: builtins.int
+ TIMESTAMP_FIELD_NUMBER: builtins.int
+ MIME_TYPE_FIELD_NUMBER: builtins.int
+ TOPIC_FIELD_NUMBER: builtins.int
+ TOTAL_LENGTH_FIELD_NUMBER: builtins.int
+ ATTRIBUTES_FIELD_NUMBER: builtins.int
+ TEXT_HEADER_FIELD_NUMBER: builtins.int
+ BYTE_HEADER_FIELD_NUMBER: builtins.int
+ stream_id: builtins.str
+ """unique identifier for this data stream"""
+ timestamp: builtins.int
+ """using int64 for Unix timestamp"""
+ mime_type: builtins.str
+ topic: builtins.str
+ total_length: builtins.int
+ """only populated for finite streams, if it's a stream of unknown size this stays empty"""
+ @property
+ def attributes(self) -> google.protobuf.internal.containers.ScalarMap[builtins.str, builtins.str]:
+ """user defined attributes map that can carry additional info"""
+
+ @property
+ def text_header(self) -> global___DataStream.TextHeader: ...
+ @property
+ def byte_header(self) -> global___DataStream.ByteHeader: ...
+ def __init__(
+ self,
+ *,
+ stream_id: builtins.str | None = ...,
+ timestamp: builtins.int | None = ...,
+ mime_type: builtins.str | None = ...,
+ topic: builtins.str | None = ...,
+ total_length: builtins.int | None = ...,
+ attributes: collections.abc.Mapping[builtins.str, builtins.str] | None = ...,
+ text_header: global___DataStream.TextHeader | None = ...,
+ byte_header: global___DataStream.ByteHeader | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["byte_header", b"byte_header", "content_header", b"content_header", "mime_type", b"mime_type", "stream_id", b"stream_id", "text_header", b"text_header", "timestamp", b"timestamp", "topic", b"topic", "total_length", b"total_length"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["attributes", b"attributes", "byte_header", b"byte_header", "content_header", b"content_header", "mime_type", b"mime_type", "stream_id", b"stream_id", "text_header", b"text_header", "timestamp", b"timestamp", "topic", b"topic", "total_length", b"total_length"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["content_header", b"content_header"]) -> typing.Literal["text_header", "byte_header"] | None: ...
+
+ @typing.final
+ class Chunk(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ STREAM_ID_FIELD_NUMBER: builtins.int
+ CHUNK_INDEX_FIELD_NUMBER: builtins.int
+ CONTENT_FIELD_NUMBER: builtins.int
+ VERSION_FIELD_NUMBER: builtins.int
+ IV_FIELD_NUMBER: builtins.int
+ stream_id: builtins.str
+ """unique identifier for this data stream to map it to the correct header"""
+ chunk_index: builtins.int
+ content: builtins.bytes
+ """content as binary (bytes)"""
+ version: builtins.int
+ """a version indicating that this chunk_index has been retroactively modified and the original one needs to be replaced"""
+ iv: builtins.bytes
+ """optional, initialization vector for AES-GCM encryption"""
+ def __init__(
+ self,
+ *,
+ stream_id: builtins.str | None = ...,
+ chunk_index: builtins.int | None = ...,
+ content: builtins.bytes | None = ...,
+ version: builtins.int | None = ...,
+ iv: builtins.bytes | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["chunk_index", b"chunk_index", "content", b"content", "iv", b"iv", "stream_id", b"stream_id", "version", b"version"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["chunk_index", b"chunk_index", "content", b"content", "iv", b"iv", "stream_id", b"stream_id", "version", b"version"]) -> None: ...
+
+ @typing.final
+ class Trailer(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ @typing.final
+ class AttributesEntry(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ KEY_FIELD_NUMBER: builtins.int
+ VALUE_FIELD_NUMBER: builtins.int
+ key: builtins.str
+ value: builtins.str
+ def __init__(
+ self,
+ *,
+ key: builtins.str | None = ...,
+ value: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> None: ...
+
+ STREAM_ID_FIELD_NUMBER: builtins.int
+ REASON_FIELD_NUMBER: builtins.int
+ ATTRIBUTES_FIELD_NUMBER: builtins.int
+ stream_id: builtins.str
+ """unique identifier for this data stream"""
+ reason: builtins.str
+ """reason why the stream was closed (could contain "error" / "interrupted" / empty for expected end)"""
+ @property
+ def attributes(self) -> google.protobuf.internal.containers.ScalarMap[builtins.str, builtins.str]:
+ """finalizing updates for the stream, can also include additional insights for errors or endTime for transcription"""
+
+ def __init__(
+ self,
+ *,
+ stream_id: builtins.str | None = ...,
+ reason: builtins.str | None = ...,
+ attributes: collections.abc.Mapping[builtins.str, builtins.str] | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["reason", b"reason", "stream_id", b"stream_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["attributes", b"attributes", "reason", b"reason", "stream_id", b"stream_id"]) -> None: ...
+
+ def __init__(
+ self,
+ ) -> None: ...
+
+global___DataStream = DataStream
+
+@typing.final
+class DataStreamHeaderReceived(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: builtins.int
+ HEADER_FIELD_NUMBER: builtins.int
+ participant_identity: builtins.str
+ @property
+ def header(self) -> global___DataStream.Header: ...
+ def __init__(
+ self,
+ *,
+ participant_identity: builtins.str | None = ...,
+ header: global___DataStream.Header | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["header", b"header", "participant_identity", b"participant_identity"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["header", b"header", "participant_identity", b"participant_identity"]) -> None: ...
+
+global___DataStreamHeaderReceived = DataStreamHeaderReceived
+
+@typing.final
+class DataStreamChunkReceived(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: builtins.int
+ CHUNK_FIELD_NUMBER: builtins.int
+ participant_identity: builtins.str
+ @property
+ def chunk(self) -> global___DataStream.Chunk: ...
+ def __init__(
+ self,
+ *,
+ participant_identity: builtins.str | None = ...,
+ chunk: global___DataStream.Chunk | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["chunk", b"chunk", "participant_identity", b"participant_identity"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["chunk", b"chunk", "participant_identity", b"participant_identity"]) -> None: ...
+
+global___DataStreamChunkReceived = DataStreamChunkReceived
+
+@typing.final
+class DataStreamTrailerReceived(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: builtins.int
+ TRAILER_FIELD_NUMBER: builtins.int
+ participant_identity: builtins.str
+ @property
+ def trailer(self) -> global___DataStream.Trailer: ...
+ def __init__(
+ self,
+ *,
+ participant_identity: builtins.str | None = ...,
+ trailer: global___DataStream.Trailer | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["participant_identity", b"participant_identity", "trailer", b"trailer"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["participant_identity", b"participant_identity", "trailer", b"trailer"]) -> None: ...
+
+global___DataStreamTrailerReceived = DataStreamTrailerReceived
+
+@typing.final
+class SendStreamHeaderRequest(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ LOCAL_PARTICIPANT_HANDLE_FIELD_NUMBER: builtins.int
+ HEADER_FIELD_NUMBER: builtins.int
+ DESTINATION_IDENTITIES_FIELD_NUMBER: builtins.int
+ SENDER_IDENTITY_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
+ local_participant_handle: builtins.int
+ sender_identity: builtins.str
+ request_async_id: builtins.int
+ @property
+ def header(self) -> global___DataStream.Header: ...
+ @property
+ def destination_identities(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ...
+ def __init__(
+ self,
+ *,
+ local_participant_handle: builtins.int | None = ...,
+ header: global___DataStream.Header | None = ...,
+ destination_identities: collections.abc.Iterable[builtins.str] | None = ...,
+ sender_identity: builtins.str | None = ...,
+ request_async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["header", b"header", "local_participant_handle", b"local_participant_handle", "request_async_id", b"request_async_id", "sender_identity", b"sender_identity"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["destination_identities", b"destination_identities", "header", b"header", "local_participant_handle", b"local_participant_handle", "request_async_id", b"request_async_id", "sender_identity", b"sender_identity"]) -> None: ...
+
+global___SendStreamHeaderRequest = SendStreamHeaderRequest
+
+@typing.final
+class SendStreamChunkRequest(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ LOCAL_PARTICIPANT_HANDLE_FIELD_NUMBER: builtins.int
+ CHUNK_FIELD_NUMBER: builtins.int
+ DESTINATION_IDENTITIES_FIELD_NUMBER: builtins.int
+ SENDER_IDENTITY_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
+ local_participant_handle: builtins.int
+ sender_identity: builtins.str
+ request_async_id: builtins.int
+ @property
+ def chunk(self) -> global___DataStream.Chunk: ...
+ @property
+ def destination_identities(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ...
+ def __init__(
+ self,
+ *,
+ local_participant_handle: builtins.int | None = ...,
+ chunk: global___DataStream.Chunk | None = ...,
+ destination_identities: collections.abc.Iterable[builtins.str] | None = ...,
+ sender_identity: builtins.str | None = ...,
+ request_async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["chunk", b"chunk", "local_participant_handle", b"local_participant_handle", "request_async_id", b"request_async_id", "sender_identity", b"sender_identity"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["chunk", b"chunk", "destination_identities", b"destination_identities", "local_participant_handle", b"local_participant_handle", "request_async_id", b"request_async_id", "sender_identity", b"sender_identity"]) -> None: ...
+
+global___SendStreamChunkRequest = SendStreamChunkRequest
+
+@typing.final
+class SendStreamTrailerRequest(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ LOCAL_PARTICIPANT_HANDLE_FIELD_NUMBER: builtins.int
+ TRAILER_FIELD_NUMBER: builtins.int
+ DESTINATION_IDENTITIES_FIELD_NUMBER: builtins.int
+ SENDER_IDENTITY_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
+ local_participant_handle: builtins.int
+ sender_identity: builtins.str
+ request_async_id: builtins.int
+ @property
+ def trailer(self) -> global___DataStream.Trailer: ...
+ @property
+ def destination_identities(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ...
+ def __init__(
+ self,
+ *,
+ local_participant_handle: builtins.int | None = ...,
+ trailer: global___DataStream.Trailer | None = ...,
+ destination_identities: collections.abc.Iterable[builtins.str] | None = ...,
+ sender_identity: builtins.str | None = ...,
+ request_async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["local_participant_handle", b"local_participant_handle", "request_async_id", b"request_async_id", "sender_identity", b"sender_identity", "trailer", b"trailer"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["destination_identities", b"destination_identities", "local_participant_handle", b"local_participant_handle", "request_async_id", b"request_async_id", "sender_identity", b"sender_identity", "trailer", b"trailer"]) -> None: ...
+
+global___SendStreamTrailerRequest = SendStreamTrailerRequest
+
+@typing.final
+class SendStreamHeaderResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
+
+global___SendStreamHeaderResponse = SendStreamHeaderResponse
+
+@typing.final
+class SendStreamChunkResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
+
+global___SendStreamChunkResponse = SendStreamChunkResponse
+
+@typing.final
+class SendStreamTrailerResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
+
+global___SendStreamTrailerResponse = SendStreamTrailerResponse
+
+@typing.final
+class SendStreamHeaderCallback(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ ERROR_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ error: builtins.str
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ error: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> None: ...
+
+global___SendStreamHeaderCallback = SendStreamHeaderCallback
+
+@typing.final
+class SendStreamChunkCallback(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ ERROR_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ error: builtins.str
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ error: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> None: ...
+
+global___SendStreamChunkCallback = SendStreamChunkCallback
+
+@typing.final
+class SendStreamTrailerCallback(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ ERROR_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ error: builtins.str
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ error: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> None: ...
+
+global___SendStreamTrailerCallback = SendStreamTrailerCallback
+
+@typing.final
+class SetDataChannelBufferedAmountLowThresholdRequest(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ LOCAL_PARTICIPANT_HANDLE_FIELD_NUMBER: builtins.int
+ THRESHOLD_FIELD_NUMBER: builtins.int
+ KIND_FIELD_NUMBER: builtins.int
+ local_participant_handle: builtins.int
+ threshold: builtins.int
+ kind: global___DataPacketKind.ValueType
+ def __init__(
+ self,
+ *,
+ local_participant_handle: builtins.int | None = ...,
+ threshold: builtins.int | None = ...,
+ kind: global___DataPacketKind.ValueType | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["kind", b"kind", "local_participant_handle", b"local_participant_handle", "threshold", b"threshold"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["kind", b"kind", "local_participant_handle", b"local_participant_handle", "threshold", b"threshold"]) -> None: ...
+
+global___SetDataChannelBufferedAmountLowThresholdRequest = SetDataChannelBufferedAmountLowThresholdRequest
+
+@typing.final
+class SetDataChannelBufferedAmountLowThresholdResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ def __init__(
+ self,
+ ) -> None: ...
+
+global___SetDataChannelBufferedAmountLowThresholdResponse = SetDataChannelBufferedAmountLowThresholdResponse
+
+@typing.final
+class DataChannelBufferedAmountLowThresholdChanged(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ KIND_FIELD_NUMBER: builtins.int
+ THRESHOLD_FIELD_NUMBER: builtins.int
+ kind: global___DataPacketKind.ValueType
+ threshold: builtins.int
+ def __init__(
+ self,
+ *,
+ kind: global___DataPacketKind.ValueType | None = ...,
+ threshold: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["kind", b"kind", "threshold", b"threshold"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["kind", b"kind", "threshold", b"threshold"]) -> None: ...
+
+global___DataChannelBufferedAmountLowThresholdChanged = DataChannelBufferedAmountLowThresholdChanged
+
+@typing.final
+class ByteStreamOpened(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ READER_FIELD_NUMBER: builtins.int
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: builtins.int
+ participant_identity: builtins.str
+ @property
+ def reader(self) -> data_stream_pb2.OwnedByteStreamReader: ...
+ def __init__(
+ self,
+ *,
+ reader: data_stream_pb2.OwnedByteStreamReader | None = ...,
+ participant_identity: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["participant_identity", b"participant_identity", "reader", b"reader"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["participant_identity", b"participant_identity", "reader", b"reader"]) -> None: ...
+
+global___ByteStreamOpened = ByteStreamOpened
+
+@typing.final
+class TextStreamOpened(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ READER_FIELD_NUMBER: builtins.int
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: builtins.int
+ participant_identity: builtins.str
+ @property
+ def reader(self) -> data_stream_pb2.OwnedTextStreamReader: ...
+ def __init__(
+ self,
+ *,
+ reader: data_stream_pb2.OwnedTextStreamReader | None = ...,
+ participant_identity: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["participant_identity", b"participant_identity", "reader", b"reader"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["participant_identity", b"participant_identity", "reader", b"reader"]) -> None: ...
+
+global___TextStreamOpened = TextStreamOpened
+
+@typing.final
+class DataTrackPublished(google.protobuf.message.Message):
+ """A remote participant published a data track."""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ TRACK_FIELD_NUMBER: builtins.int
+ @property
+ def track(self) -> data_track_pb2.OwnedRemoteDataTrack: ...
+ def __init__(
+ self,
+ *,
+ track: data_track_pb2.OwnedRemoteDataTrack | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["track", b"track"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["track", b"track"]) -> None: ...
+
+global___DataTrackPublished = DataTrackPublished
+
+@typing.final
+class DataTrackUnpublished(google.protobuf.message.Message):
+ """A remote participant unpublished a data track."""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ SID_FIELD_NUMBER: builtins.int
+ sid: builtins.str
+ """SID of the track that was unpublished."""
+ def __init__(
+ self,
+ *,
+ sid: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["sid", b"sid"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["sid", b"sid"]) -> None: ...
+
+global___DataTrackUnpublished = DataTrackUnpublished
diff --git a/livekit-rtc/livekit/rtc/_proto/rpc_pb2.py b/livekit-rtc/livekit/rtc/_proto/rpc_pb2.py
new file mode 100644
index 00000000..c7211917
--- /dev/null
+++ b/livekit-rtc/livekit/rtc/_proto/rpc_pb2.py
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: rpc.proto
+# Protobuf Python Version: 4.25.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\trpc.proto\x12\rlivekit.proto\"7\n\x08RpcError\x12\x0c\n\x04\x63ode\x18\x01 \x02(\r\x12\x0f\n\x07message\x18\x02 \x02(\t\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\t\"\xab\x01\n\x11PerformRpcRequest\x12 \n\x18local_participant_handle\x18\x01 \x02(\x04\x12\x1c\n\x14\x64\x65stination_identity\x18\x02 \x02(\t\x12\x0e\n\x06method\x18\x03 \x02(\t\x12\x0f\n\x07payload\x18\x04 \x02(\t\x12\x1b\n\x13response_timeout_ms\x18\x05 \x01(\r\x12\x18\n\x10request_async_id\x18\x06 \x01(\x04\"L\n\x18RegisterRpcMethodRequest\x12 \n\x18local_participant_handle\x18\x01 \x02(\x04\x12\x0e\n\x06method\x18\x02 \x02(\t\"N\n\x1aUnregisterRpcMethodRequest\x12 \n\x18local_participant_handle\x18\x01 \x02(\x04\x12\x0e\n\x06method\x18\x02 \x02(\t\"\x96\x01\n\"RpcMethodInvocationResponseRequest\x12 \n\x18local_participant_handle\x18\x01 \x02(\x04\x12\x15\n\rinvocation_id\x18\x02 \x02(\x04\x12\x0f\n\x07payload\x18\x03 \x01(\t\x12&\n\x05\x65rror\x18\x04 \x01(\x0b\x32\x17.livekit.proto.RpcError\"&\n\x12PerformRpcResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"\x1b\n\x19RegisterRpcMethodResponse\"\x1d\n\x1bUnregisterRpcMethodResponse\"4\n#RpcMethodInvocationResponseResponse\x12\r\n\x05\x65rror\x18\x01 \x01(\t\"_\n\x12PerformRpcCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12\x0f\n\x07payload\x18\x02 \x01(\t\x12&\n\x05\x65rror\x18\x03 \x01(\x0b\x32\x17.livekit.proto.RpcError\"\xbe\x01\n\x18RpcMethodInvocationEvent\x12 \n\x18local_participant_handle\x18\x01 \x02(\x04\x12\x15\n\rinvocation_id\x18\x02 \x02(\x04\x12\x0e\n\x06method\x18\x03 \x02(\t\x12\x12\n\nrequest_id\x18\x04 \x02(\t\x12\x17\n\x0f\x63\x61ller_identity\x18\x05 \x02(\t\x12\x0f\n\x07payload\x18\x06 \x02(\t\x12\x1b\n\x13response_timeout_ms\x18\x07 \x02(\rB\x10\xaa\x02\rLiveKit.Proto')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'rpc_pb2', _globals)
+if _descriptor._USE_C_DESCRIPTORS == False:
+ _globals['DESCRIPTOR']._options = None
+ _globals['DESCRIPTOR']._serialized_options = b'\252\002\rLiveKit.Proto'
+ _globals['_RPCERROR']._serialized_start=28
+ _globals['_RPCERROR']._serialized_end=83
+ _globals['_PERFORMRPCREQUEST']._serialized_start=86
+ _globals['_PERFORMRPCREQUEST']._serialized_end=257
+ _globals['_REGISTERRPCMETHODREQUEST']._serialized_start=259
+ _globals['_REGISTERRPCMETHODREQUEST']._serialized_end=335
+ _globals['_UNREGISTERRPCMETHODREQUEST']._serialized_start=337
+ _globals['_UNREGISTERRPCMETHODREQUEST']._serialized_end=415
+ _globals['_RPCMETHODINVOCATIONRESPONSEREQUEST']._serialized_start=418
+ _globals['_RPCMETHODINVOCATIONRESPONSEREQUEST']._serialized_end=568
+ _globals['_PERFORMRPCRESPONSE']._serialized_start=570
+ _globals['_PERFORMRPCRESPONSE']._serialized_end=608
+ _globals['_REGISTERRPCMETHODRESPONSE']._serialized_start=610
+ _globals['_REGISTERRPCMETHODRESPONSE']._serialized_end=637
+ _globals['_UNREGISTERRPCMETHODRESPONSE']._serialized_start=639
+ _globals['_UNREGISTERRPCMETHODRESPONSE']._serialized_end=668
+ _globals['_RPCMETHODINVOCATIONRESPONSERESPONSE']._serialized_start=670
+ _globals['_RPCMETHODINVOCATIONRESPONSERESPONSE']._serialized_end=722
+ _globals['_PERFORMRPCCALLBACK']._serialized_start=724
+ _globals['_PERFORMRPCCALLBACK']._serialized_end=819
+ _globals['_RPCMETHODINVOCATIONEVENT']._serialized_start=822
+ _globals['_RPCMETHODINVOCATIONEVENT']._serialized_end=1012
+# @@protoc_insertion_point(module_scope)
diff --git a/livekit-rtc/livekit/rtc/_proto/rpc_pb2.pyi b/livekit-rtc/livekit/rtc/_proto/rpc_pb2.pyi
new file mode 100644
index 00000000..bbed4217
--- /dev/null
+++ b/livekit-rtc/livekit/rtc/_proto/rpc_pb2.pyi
@@ -0,0 +1,258 @@
+"""
+@generated by mypy-protobuf. Do not edit manually!
+isort:skip_file
+Copyright 2025 LiveKit, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import builtins
+import google.protobuf.descriptor
+import google.protobuf.message
+import typing
+
+DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
+
+@typing.final
+class RpcError(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ CODE_FIELD_NUMBER: builtins.int
+ MESSAGE_FIELD_NUMBER: builtins.int
+ DATA_FIELD_NUMBER: builtins.int
+ code: builtins.int
+ message: builtins.str
+ data: builtins.str
+ def __init__(
+ self,
+ *,
+ code: builtins.int | None = ...,
+ message: builtins.str | None = ...,
+ data: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["code", b"code", "data", b"data", "message", b"message"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["code", b"code", "data", b"data", "message", b"message"]) -> None: ...
+
+global___RpcError = RpcError
+
+@typing.final
+class PerformRpcRequest(google.protobuf.message.Message):
+ """FFI Requests"""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ LOCAL_PARTICIPANT_HANDLE_FIELD_NUMBER: builtins.int
+ DESTINATION_IDENTITY_FIELD_NUMBER: builtins.int
+ METHOD_FIELD_NUMBER: builtins.int
+ PAYLOAD_FIELD_NUMBER: builtins.int
+ RESPONSE_TIMEOUT_MS_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
+ local_participant_handle: builtins.int
+ destination_identity: builtins.str
+ method: builtins.str
+ payload: builtins.str
+ response_timeout_ms: builtins.int
+ request_async_id: builtins.int
+ def __init__(
+ self,
+ *,
+ local_participant_handle: builtins.int | None = ...,
+ destination_identity: builtins.str | None = ...,
+ method: builtins.str | None = ...,
+ payload: builtins.str | None = ...,
+ response_timeout_ms: builtins.int | None = ...,
+ request_async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["destination_identity", b"destination_identity", "local_participant_handle", b"local_participant_handle", "method", b"method", "payload", b"payload", "request_async_id", b"request_async_id", "response_timeout_ms", b"response_timeout_ms"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["destination_identity", b"destination_identity", "local_participant_handle", b"local_participant_handle", "method", b"method", "payload", b"payload", "request_async_id", b"request_async_id", "response_timeout_ms", b"response_timeout_ms"]) -> None: ...
+
+global___PerformRpcRequest = PerformRpcRequest
+
+@typing.final
+class RegisterRpcMethodRequest(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ LOCAL_PARTICIPANT_HANDLE_FIELD_NUMBER: builtins.int
+ METHOD_FIELD_NUMBER: builtins.int
+ local_participant_handle: builtins.int
+ method: builtins.str
+ def __init__(
+ self,
+ *,
+ local_participant_handle: builtins.int | None = ...,
+ method: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["local_participant_handle", b"local_participant_handle", "method", b"method"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["local_participant_handle", b"local_participant_handle", "method", b"method"]) -> None: ...
+
+global___RegisterRpcMethodRequest = RegisterRpcMethodRequest
+
+@typing.final
+class UnregisterRpcMethodRequest(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ LOCAL_PARTICIPANT_HANDLE_FIELD_NUMBER: builtins.int
+ METHOD_FIELD_NUMBER: builtins.int
+ local_participant_handle: builtins.int
+ method: builtins.str
+ def __init__(
+ self,
+ *,
+ local_participant_handle: builtins.int | None = ...,
+ method: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["local_participant_handle", b"local_participant_handle", "method", b"method"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["local_participant_handle", b"local_participant_handle", "method", b"method"]) -> None: ...
+
+global___UnregisterRpcMethodRequest = UnregisterRpcMethodRequest
+
+@typing.final
+class RpcMethodInvocationResponseRequest(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ LOCAL_PARTICIPANT_HANDLE_FIELD_NUMBER: builtins.int
+ INVOCATION_ID_FIELD_NUMBER: builtins.int
+ PAYLOAD_FIELD_NUMBER: builtins.int
+ ERROR_FIELD_NUMBER: builtins.int
+ local_participant_handle: builtins.int
+ invocation_id: builtins.int
+ payload: builtins.str
+ @property
+ def error(self) -> global___RpcError: ...
+ def __init__(
+ self,
+ *,
+ local_participant_handle: builtins.int | None = ...,
+ invocation_id: builtins.int | None = ...,
+ payload: builtins.str | None = ...,
+ error: global___RpcError | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["error", b"error", "invocation_id", b"invocation_id", "local_participant_handle", b"local_participant_handle", "payload", b"payload"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["error", b"error", "invocation_id", b"invocation_id", "local_participant_handle", b"local_participant_handle", "payload", b"payload"]) -> None: ...
+
+global___RpcMethodInvocationResponseRequest = RpcMethodInvocationResponseRequest
+
+@typing.final
+class PerformRpcResponse(google.protobuf.message.Message):
+ """FFI Responses"""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
+
+global___PerformRpcResponse = PerformRpcResponse
+
+@typing.final
+class RegisterRpcMethodResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ def __init__(
+ self,
+ ) -> None: ...
+
+global___RegisterRpcMethodResponse = RegisterRpcMethodResponse
+
+@typing.final
+class UnregisterRpcMethodResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ def __init__(
+ self,
+ ) -> None: ...
+
+global___UnregisterRpcMethodResponse = UnregisterRpcMethodResponse
+
+@typing.final
+class RpcMethodInvocationResponseResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ERROR_FIELD_NUMBER: builtins.int
+ error: builtins.str
+ def __init__(
+ self,
+ *,
+ error: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["error", b"error"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["error", b"error"]) -> None: ...
+
+global___RpcMethodInvocationResponseResponse = RpcMethodInvocationResponseResponse
+
+@typing.final
+class PerformRpcCallback(google.protobuf.message.Message):
+ """FFI Callbacks"""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ASYNC_ID_FIELD_NUMBER: builtins.int
+ PAYLOAD_FIELD_NUMBER: builtins.int
+ ERROR_FIELD_NUMBER: builtins.int
+ async_id: builtins.int
+ payload: builtins.str
+ @property
+ def error(self) -> global___RpcError: ...
+ def __init__(
+ self,
+ *,
+ async_id: builtins.int | None = ...,
+ payload: builtins.str | None = ...,
+ error: global___RpcError | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error", "payload", b"payload"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error", "payload", b"payload"]) -> None: ...
+
+global___PerformRpcCallback = PerformRpcCallback
+
+@typing.final
+class RpcMethodInvocationEvent(google.protobuf.message.Message):
+ """FFI Events"""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ LOCAL_PARTICIPANT_HANDLE_FIELD_NUMBER: builtins.int
+ INVOCATION_ID_FIELD_NUMBER: builtins.int
+ METHOD_FIELD_NUMBER: builtins.int
+ REQUEST_ID_FIELD_NUMBER: builtins.int
+ CALLER_IDENTITY_FIELD_NUMBER: builtins.int
+ PAYLOAD_FIELD_NUMBER: builtins.int
+ RESPONSE_TIMEOUT_MS_FIELD_NUMBER: builtins.int
+ local_participant_handle: builtins.int
+ invocation_id: builtins.int
+ method: builtins.str
+ request_id: builtins.str
+ caller_identity: builtins.str
+ payload: builtins.str
+ response_timeout_ms: builtins.int
+ def __init__(
+ self,
+ *,
+ local_participant_handle: builtins.int | None = ...,
+ invocation_id: builtins.int | None = ...,
+ method: builtins.str | None = ...,
+ request_id: builtins.str | None = ...,
+ caller_identity: builtins.str | None = ...,
+ payload: builtins.str | None = ...,
+ response_timeout_ms: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["caller_identity", b"caller_identity", "invocation_id", b"invocation_id", "local_participant_handle", b"local_participant_handle", "method", b"method", "payload", b"payload", "request_id", b"request_id", "response_timeout_ms", b"response_timeout_ms"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["caller_identity", b"caller_identity", "invocation_id", b"invocation_id", "local_participant_handle", b"local_participant_handle", "method", b"method", "payload", b"payload", "request_id", b"request_id", "response_timeout_ms", b"response_timeout_ms"]) -> None: ...
+
+global___RpcMethodInvocationEvent = RpcMethodInvocationEvent
diff --git a/livekit-rtc/livekit/rtc/_proto/stats_pb2.py b/livekit-rtc/livekit/rtc/_proto/stats_pb2.py
index 8c68ca21..ce7b411c 100644
--- a/livekit-rtc/livekit/rtc/_proto/stats_pb2.py
+++ b/livekit-rtc/livekit/rtc/_proto/stats_pb2.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: stats.proto
-# Protobuf Python Version: 4.25.3
+# Protobuf Python Version: 4.25.1
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
@@ -14,7 +14,7 @@
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0bstats.proto\x12\rlivekit.proto\"\xd9\x17\n\x08RtcStats\x12.\n\x05\x63odec\x18\x03 \x01(\x0b\x32\x1d.livekit.proto.RtcStats.CodecH\x00\x12\x39\n\x0binbound_rtp\x18\x04 \x01(\x0b\x32\".livekit.proto.RtcStats.InboundRtpH\x00\x12;\n\x0coutbound_rtp\x18\x05 \x01(\x0b\x32#.livekit.proto.RtcStats.OutboundRtpH\x00\x12\x46\n\x12remote_inbound_rtp\x18\x06 \x01(\x0b\x32(.livekit.proto.RtcStats.RemoteInboundRtpH\x00\x12H\n\x13remote_outbound_rtp\x18\x07 \x01(\x0b\x32).livekit.proto.RtcStats.RemoteOutboundRtpH\x00\x12;\n\x0cmedia_source\x18\x08 \x01(\x0b\x32#.livekit.proto.RtcStats.MediaSourceH\x00\x12=\n\rmedia_playout\x18\t \x01(\x0b\x32$.livekit.proto.RtcStats.MediaPlayoutH\x00\x12\x41\n\x0fpeer_connection\x18\n \x01(\x0b\x32&.livekit.proto.RtcStats.PeerConnectionH\x00\x12;\n\x0c\x64\x61ta_channel\x18\x0b \x01(\x0b\x32#.livekit.proto.RtcStats.DataChannelH\x00\x12\x36\n\ttransport\x18\x0c \x01(\x0b\x32!.livekit.proto.RtcStats.TransportH\x00\x12?\n\x0e\x63\x61ndidate_pair\x18\r \x01(\x0b\x32%.livekit.proto.RtcStats.CandidatePairH\x00\x12\x41\n\x0flocal_candidate\x18\x0e \x01(\x0b\x32&.livekit.proto.RtcStats.LocalCandidateH\x00\x12\x43\n\x10remote_candidate\x18\x0f \x01(\x0b\x32\'.livekit.proto.RtcStats.RemoteCandidateH\x00\x12:\n\x0b\x63\x65rtificate\x18\x10 \x01(\x0b\x32#.livekit.proto.RtcStats.CertificateH\x00\x12.\n\x05track\x18\x11 \x01(\x0b\x32\x1d.livekit.proto.RtcStats.TrackH\x00\x1a[\n\x05\x43odec\x12(\n\x03rtc\x18\x01 \x01(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12(\n\x05\x63odec\x18\x02 \x01(\x0b\x32\x19.livekit.proto.CodecStats\x1a\xd5\x01\n\nInboundRtp\x12(\n\x03rtc\x18\x01 \x01(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12-\n\x06stream\x18\x02 \x01(\x0b\x32\x1d.livekit.proto.RtpStreamStats\x12\x37\n\x08received\x18\x03 \x01(\x0b\x32%.livekit.proto.ReceivedRtpStreamStats\x12\x35\n\x07inbound\x18\x04 \x01(\x0b\x32$.livekit.proto.InboundRtpStreamStats\x1a\xd0\x01\n\x0bOutboundRtp\x12(\n\x03rtc\x18\x01 \x01(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12-\n\x06stream\x18\x02 \x01(\x0b\x32\x1d.livekit.proto.RtpStreamStats\x12/\n\x04sent\x18\x03 \x01(\x0b\x32!.livekit.proto.SentRtpStreamStats\x12\x37\n\x08outbound\x18\x04 \x01(\x0b\x32%.livekit.proto.OutboundRtpStreamStats\x1a\xe8\x01\n\x10RemoteInboundRtp\x12(\n\x03rtc\x18\x01 \x01(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12-\n\x06stream\x18\x02 \x01(\x0b\x32\x1d.livekit.proto.RtpStreamStats\x12\x37\n\x08received\x18\x03 \x01(\x0b\x32%.livekit.proto.ReceivedRtpStreamStats\x12\x42\n\x0eremote_inbound\x18\x04 \x01(\x0b\x32*.livekit.proto.RemoteInboundRtpStreamStats\x1a\xe3\x01\n\x11RemoteOutboundRtp\x12(\n\x03rtc\x18\x01 \x01(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12-\n\x06stream\x18\x02 \x01(\x0b\x32\x1d.livekit.proto.RtpStreamStats\x12/\n\x04sent\x18\x03 \x01(\x0b\x32!.livekit.proto.SentRtpStreamStats\x12\x44\n\x0fremote_outbound\x18\x04 \x01(\x0b\x32+.livekit.proto.RemoteOutboundRtpStreamStats\x1a\xc8\x01\n\x0bMediaSource\x12(\n\x03rtc\x18\x01 \x01(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12/\n\x06source\x18\x02 \x01(\x0b\x32\x1f.livekit.proto.MediaSourceStats\x12.\n\x05\x61udio\x18\x03 \x01(\x0b\x32\x1f.livekit.proto.AudioSourceStats\x12.\n\x05video\x18\x04 \x01(\x0b\x32\x1f.livekit.proto.VideoSourceStats\x1aq\n\x0cMediaPlayout\x12(\n\x03rtc\x18\x01 \x01(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12\x37\n\raudio_playout\x18\x02 \x01(\x0b\x32 .livekit.proto.AudioPlayoutStats\x1aj\n\x0ePeerConnection\x12(\n\x03rtc\x18\x01 \x01(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12.\n\x02pc\x18\x02 \x01(\x0b\x32\".livekit.proto.PeerConnectionStats\x1a\x64\n\x0b\x44\x61taChannel\x12(\n\x03rtc\x18\x01 \x01(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12+\n\x02\x64\x63\x18\x02 \x01(\x0b\x32\x1f.livekit.proto.DataChannelStats\x1ag\n\tTransport\x12(\n\x03rtc\x18\x01 \x01(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12\x30\n\ttransport\x18\x02 \x01(\x0b\x32\x1d.livekit.proto.TransportStats\x1at\n\rCandidatePair\x12(\n\x03rtc\x18\x01 \x01(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12\x39\n\x0e\x63\x61ndidate_pair\x18\x02 \x01(\x0b\x32!.livekit.proto.CandidatePairStats\x1ao\n\x0eLocalCandidate\x12(\n\x03rtc\x18\x01 \x01(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12\x33\n\tcandidate\x18\x02 \x01(\x0b\x32 .livekit.proto.IceCandidateStats\x1ap\n\x0fRemoteCandidate\x12(\n\x03rtc\x18\x01 \x01(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12\x33\n\tcandidate\x18\x02 \x01(\x0b\x32 .livekit.proto.IceCandidateStats\x1am\n\x0b\x43\x65rtificate\x12(\n\x03rtc\x18\x01 \x01(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12\x34\n\x0b\x63\x65rtificate\x18\x02 \x01(\x0b\x32\x1f.livekit.proto.CertificateStats\x1a\x07\n\x05TrackB\x07\n\x05stats\"-\n\x0cRtcStatsData\x12\n\n\x02id\x18\x01 \x01(\t\x12\x11\n\ttimestamp\x18\x02 \x01(\x03\"\x88\x01\n\nCodecStats\x12\x14\n\x0cpayload_type\x18\x01 \x01(\r\x12\x14\n\x0ctransport_id\x18\x02 \x01(\t\x12\x11\n\tmime_type\x18\x03 \x01(\t\x12\x12\n\nclock_rate\x18\x04 \x01(\r\x12\x10\n\x08\x63hannels\x18\x05 \x01(\r\x12\x15\n\rsdp_fmtp_line\x18\x06 \x01(\t\"T\n\x0eRtpStreamStats\x12\x0c\n\x04ssrc\x18\x01 \x01(\r\x12\x0c\n\x04kind\x18\x02 \x01(\t\x12\x14\n\x0ctransport_id\x18\x03 \x01(\t\x12\x10\n\x08\x63odec_id\x18\x04 \x01(\t\"X\n\x16ReceivedRtpStreamStats\x12\x18\n\x10packets_received\x18\x01 \x01(\x04\x12\x14\n\x0cpackets_lost\x18\x02 \x01(\x03\x12\x0e\n\x06jitter\x18\x03 \x01(\x01\"\x82\x0c\n\x15InboundRtpStreamStats\x12\x18\n\x10track_identifier\x18\x01 \x01(\t\x12\x0b\n\x03mid\x18\x02 \x01(\t\x12\x11\n\tremote_id\x18\x03 \x01(\t\x12\x16\n\x0e\x66rames_decoded\x18\x04 \x01(\r\x12\x1a\n\x12key_frames_decoded\x18\x05 \x01(\r\x12\x17\n\x0f\x66rames_rendered\x18\x06 \x01(\r\x12\x16\n\x0e\x66rames_dropped\x18\x07 \x01(\r\x12\x13\n\x0b\x66rame_width\x18\x08 \x01(\r\x12\x14\n\x0c\x66rame_height\x18\t \x01(\r\x12\x19\n\x11\x66rames_per_second\x18\n \x01(\x01\x12\x0e\n\x06qp_sum\x18\x0b \x01(\x04\x12\x19\n\x11total_decode_time\x18\x0c \x01(\x01\x12\x1f\n\x17total_inter_frame_delay\x18\r \x01(\x01\x12\'\n\x1ftotal_squared_inter_frame_delay\x18\x0e \x01(\x01\x12\x13\n\x0bpause_count\x18\x0f \x01(\r\x12\x1c\n\x14total_pause_duration\x18\x10 \x01(\x01\x12\x14\n\x0c\x66reeze_count\x18\x11 \x01(\r\x12\x1d\n\x15total_freeze_duration\x18\x12 \x01(\x01\x12&\n\x1elast_packet_received_timestamp\x18\x13 \x01(\x01\x12\x1d\n\x15header_bytes_received\x18\x14 \x01(\x04\x12\x19\n\x11packets_discarded\x18\x15 \x01(\x04\x12\x1a\n\x12\x66\x65\x63_bytes_received\x18\x16 \x01(\x04\x12\x1c\n\x14\x66\x65\x63_packets_received\x18\x17 \x01(\x04\x12\x1d\n\x15\x66\x65\x63_packets_discarded\x18\x18 \x01(\x04\x12\x16\n\x0e\x62ytes_received\x18\x19 \x01(\x04\x12\x12\n\nnack_count\x18\x1a \x01(\r\x12\x11\n\tfir_count\x18\x1b \x01(\r\x12\x11\n\tpli_count\x18\x1c \x01(\r\x12\x1e\n\x16total_processing_delay\x18\x1d \x01(\x01\x12#\n\x1b\x65stimated_playout_timestamp\x18\x1e \x01(\x01\x12\x1b\n\x13jitter_buffer_delay\x18\x1f \x01(\x01\x12\"\n\x1ajitter_buffer_target_delay\x18 \x01(\x01\x12#\n\x1bjitter_buffer_emitted_count\x18! \x01(\x04\x12#\n\x1bjitter_buffer_minimum_delay\x18\" \x01(\x01\x12\x1e\n\x16total_samples_received\x18# \x01(\x04\x12\x19\n\x11\x63oncealed_samples\x18$ \x01(\x04\x12 \n\x18silent_concealed_samples\x18% \x01(\x04\x12\x1a\n\x12\x63oncealment_events\x18& \x01(\x04\x12)\n!inserted_samples_for_deceleration\x18\' \x01(\x04\x12(\n removed_samples_for_acceleration\x18( \x01(\x04\x12\x13\n\x0b\x61udio_level\x18) \x01(\x01\x12\x1a\n\x12total_audio_energy\x18* \x01(\x01\x12\x1e\n\x16total_samples_duration\x18+ \x01(\x01\x12\x17\n\x0f\x66rames_received\x18, \x01(\x04\x12\x1e\n\x16\x64\x65\x63oder_implementation\x18- \x01(\t\x12\x12\n\nplayout_id\x18. \x01(\t\x12\x1f\n\x17power_efficient_decoder\x18/ \x01(\x08\x12.\n&frames_assembled_from_multiple_packets\x18\x30 \x01(\x04\x12\x1b\n\x13total_assembly_time\x18\x31 \x01(\x01\x12&\n\x1eretransmitted_packets_received\x18\x32 \x01(\x04\x12$\n\x1cretransmitted_bytes_received\x18\x33 \x01(\x04\x12\x10\n\x08rtx_ssrc\x18\x34 \x01(\r\x12\x10\n\x08\x66\x65\x63_ssrc\x18\x35 \x01(\r\">\n\x12SentRtpStreamStats\x12\x14\n\x0cpackets_sent\x18\x01 \x01(\x04\x12\x12\n\nbytes_sent\x18\x02 \x01(\x04\"\xd1\x07\n\x16OutboundRtpStreamStats\x12\x0b\n\x03mid\x18\x01 \x01(\t\x12\x17\n\x0fmedia_source_id\x18\x02 \x01(\t\x12\x11\n\tremote_id\x18\x03 \x01(\t\x12\x0b\n\x03rid\x18\x04 \x01(\t\x12\x19\n\x11header_bytes_sent\x18\x05 \x01(\x04\x12\"\n\x1aretransmitted_packets_sent\x18\x06 \x01(\x04\x12 \n\x18retransmitted_bytes_sent\x18\x07 \x01(\x04\x12\x10\n\x08rtx_ssrc\x18\x08 \x01(\r\x12\x16\n\x0etarget_bitrate\x18\t \x01(\x01\x12\"\n\x1atotal_encoded_bytes_target\x18\n \x01(\x04\x12\x13\n\x0b\x66rame_width\x18\x0b \x01(\r\x12\x14\n\x0c\x66rame_height\x18\x0c \x01(\r\x12\x19\n\x11\x66rames_per_second\x18\r \x01(\x01\x12\x13\n\x0b\x66rames_sent\x18\x0e \x01(\r\x12\x18\n\x10huge_frames_sent\x18\x0f \x01(\r\x12\x16\n\x0e\x66rames_encoded\x18\x10 \x01(\r\x12\x1a\n\x12key_frames_encoded\x18\x11 \x01(\r\x12\x0e\n\x06qp_sum\x18\x12 \x01(\x04\x12\x19\n\x11total_encode_time\x18\x13 \x01(\x01\x12\x1f\n\x17total_packet_send_delay\x18\x14 \x01(\x01\x12I\n\x19quality_limitation_reason\x18\x15 \x01(\x0e\x32&.livekit.proto.QualityLimitationReason\x12k\n\x1cquality_limitation_durations\x18\x16 \x03(\x0b\x32\x45.livekit.proto.OutboundRtpStreamStats.QualityLimitationDurationsEntry\x12-\n%quality_limitation_resolution_changes\x18\x17 \x01(\r\x12\x12\n\nnack_count\x18\x18 \x01(\r\x12\x11\n\tfir_count\x18\x19 \x01(\r\x12\x11\n\tpli_count\x18\x1a \x01(\r\x12\x1e\n\x16\x65ncoder_implementation\x18\x1b \x01(\t\x12\x1f\n\x17power_efficient_encoder\x18\x1c \x01(\x08\x12\x0e\n\x06\x61\x63tive\x18\x1d \x01(\x08\x12\x18\n\x10scalibility_mode\x18\x1e \x01(\t\x1a\x41\n\x1fQualityLimitationDurationsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x01:\x02\x38\x01\"\xa4\x01\n\x1bRemoteInboundRtpStreamStats\x12\x10\n\x08local_id\x18\x01 \x01(\t\x12\x17\n\x0fround_trip_time\x18\x02 \x01(\x01\x12\x1d\n\x15total_round_trip_time\x18\x03 \x01(\x01\x12\x15\n\rfraction_lost\x18\x04 \x01(\x01\x12$\n\x1cround_trip_time_measurements\x18\x05 \x01(\x04\"\xbe\x01\n\x1cRemoteOutboundRtpStreamStats\x12\x10\n\x08local_id\x18\x01 \x01(\t\x12\x18\n\x10remote_timestamp\x18\x02 \x01(\x01\x12\x14\n\x0creports_sent\x18\x03 \x01(\x04\x12\x17\n\x0fround_trip_time\x18\x04 \x01(\x01\x12\x1d\n\x15total_round_trip_time\x18\x05 \x01(\x01\x12$\n\x1cround_trip_time_measurements\x18\x06 \x01(\x04\":\n\x10MediaSourceStats\x12\x18\n\x10track_identifier\x18\x01 \x01(\t\x12\x0c\n\x04kind\x18\x02 \x01(\t\"\xa2\x02\n\x10\x41udioSourceStats\x12\x13\n\x0b\x61udio_level\x18\x01 \x01(\x01\x12\x1a\n\x12total_audio_energy\x18\x02 \x01(\x01\x12\x1e\n\x16total_samples_duration\x18\x03 \x01(\x01\x12\x18\n\x10\x65\x63ho_return_loss\x18\x04 \x01(\x01\x12$\n\x1c\x65\x63ho_return_loss_enhancement\x18\x05 \x01(\x01\x12 \n\x18\x64ropped_samples_duration\x18\x06 \x01(\x01\x12\x1e\n\x16\x64ropped_samples_events\x18\x07 \x01(\r\x12\x1b\n\x13total_capture_delay\x18\x08 \x01(\x01\x12\x1e\n\x16total_samples_captured\x18\t \x01(\x04\"\\\n\x10VideoSourceStats\x12\r\n\x05width\x18\x01 \x01(\r\x12\x0e\n\x06height\x18\x02 \x01(\r\x12\x0e\n\x06\x66rames\x18\x03 \x01(\r\x12\x19\n\x11\x66rames_per_second\x18\x04 \x01(\x01\"\xc5\x01\n\x11\x41udioPlayoutStats\x12\x0c\n\x04kind\x18\x01 \x01(\t\x12$\n\x1csynthesized_samples_duration\x18\x02 \x01(\x01\x12\"\n\x1asynthesized_samples_events\x18\x03 \x01(\r\x12\x1e\n\x16total_samples_duration\x18\x04 \x01(\x01\x12\x1b\n\x13total_playout_delay\x18\x05 \x01(\x01\x12\x1b\n\x13total_samples_count\x18\x06 \x01(\x04\"Q\n\x13PeerConnectionStats\x12\x1c\n\x14\x64\x61ta_channels_opened\x18\x01 \x01(\r\x12\x1c\n\x14\x64\x61ta_channels_closed\x18\x02 \x01(\r\"\xf1\x01\n\x10\x44\x61taChannelStats\x12\r\n\x05label\x18\x01 \x01(\t\x12\x10\n\x08protocol\x18\x02 \x01(\t\x12\x1f\n\x17\x64\x61ta_channel_identifier\x18\x03 \x01(\x05\x12\x33\n\x05state\x18\x04 \x01(\x0e\x32\x1f.livekit.proto.DataChannelStateH\x00\x88\x01\x01\x12\x15\n\rmessages_sent\x18\x05 \x01(\r\x12\x12\n\nbytes_sent\x18\x06 \x01(\x04\x12\x19\n\x11messages_received\x18\x07 \x01(\r\x12\x16\n\x0e\x62ytes_received\x18\x08 \x01(\x04\x42\x08\n\x06_state\"\xc3\x04\n\x0eTransportStats\x12\x14\n\x0cpackets_sent\x18\x01 \x01(\x04\x12\x18\n\x10packets_received\x18\x02 \x01(\x04\x12\x12\n\nbytes_sent\x18\x03 \x01(\x04\x12\x16\n\x0e\x62ytes_received\x18\x04 \x01(\x04\x12(\n\x08ice_role\x18\x05 \x01(\x0e\x32\x16.livekit.proto.IceRole\x12#\n\x1bice_local_username_fragment\x18\x06 \x01(\t\x12:\n\ndtls_state\x18\x07 \x01(\x0e\x32!.livekit.proto.DtlsTransportStateH\x00\x88\x01\x01\x12\x38\n\tice_state\x18\x08 \x01(\x0e\x32 .livekit.proto.IceTransportStateH\x01\x88\x01\x01\x12\"\n\x1aselected_candidate_pair_id\x18\t \x01(\t\x12\x1c\n\x14local_certificate_id\x18\n \x01(\t\x12\x1d\n\x15remote_certificate_id\x18\x0b \x01(\t\x12\x13\n\x0btls_version\x18\x0c \x01(\t\x12\x13\n\x0b\x64tls_cipher\x18\r \x01(\t\x12*\n\tdtls_role\x18\x0e \x01(\x0e\x32\x17.livekit.proto.DtlsRole\x12\x13\n\x0bsrtp_cipher\x18\x0f \x01(\t\x12\'\n\x1fselected_candidate_pair_changes\x18\x10 \x01(\rB\r\n\x0b_dtls_stateB\x0c\n\n_ice_state\"\xb3\x05\n\x12\x43\x61ndidatePairStats\x12\x14\n\x0ctransport_id\x18\x01 \x01(\t\x12\x1a\n\x12local_candidate_id\x18\x02 \x01(\t\x12\x1b\n\x13remote_candidate_id\x18\x03 \x01(\t\x12\x38\n\x05state\x18\x04 \x01(\x0e\x32$.livekit.proto.IceCandidatePairStateH\x00\x88\x01\x01\x12\x11\n\tnominated\x18\x05 \x01(\x08\x12\x14\n\x0cpackets_sent\x18\x06 \x01(\x04\x12\x18\n\x10packets_received\x18\x07 \x01(\x04\x12\x12\n\nbytes_sent\x18\x08 \x01(\x04\x12\x16\n\x0e\x62ytes_received\x18\t \x01(\x04\x12\"\n\x1alast_packet_sent_timestamp\x18\n \x01(\x01\x12&\n\x1elast_packet_received_timestamp\x18\x0b \x01(\x01\x12\x1d\n\x15total_round_trip_time\x18\x0c \x01(\x01\x12\x1f\n\x17\x63urrent_round_trip_time\x18\r \x01(\x01\x12\"\n\x1a\x61vailable_outgoing_bitrate\x18\x0e \x01(\x01\x12\"\n\x1a\x61vailable_incoming_bitrate\x18\x0f \x01(\x01\x12\x19\n\x11requests_received\x18\x10 \x01(\x04\x12\x15\n\rrequests_sent\x18\x11 \x01(\x04\x12\x1a\n\x12responses_received\x18\x12 \x01(\x04\x12\x16\n\x0eresponses_sent\x18\x13 \x01(\x04\x12\x1d\n\x15\x63onsent_requests_sent\x18\x14 \x01(\x04\x12!\n\x19packets_discarded_on_send\x18\x15 \x01(\r\x12\x1f\n\x17\x62ytes_discarded_on_send\x18\x16 \x01(\x04\x42\x08\n\x06_state\"\xcb\x03\n\x11IceCandidateStats\x12\x14\n\x0ctransport_id\x18\x01 \x01(\t\x12\x0f\n\x07\x61\x64\x64ress\x18\x02 \x01(\t\x12\x0c\n\x04port\x18\x03 \x01(\x05\x12\x10\n\x08protocol\x18\x04 \x01(\t\x12<\n\x0e\x63\x61ndidate_type\x18\x05 \x01(\x0e\x32\x1f.livekit.proto.IceCandidateTypeH\x00\x88\x01\x01\x12\x10\n\x08priority\x18\x06 \x01(\x05\x12\x0b\n\x03url\x18\x07 \x01(\t\x12\x46\n\x0erelay_protocol\x18\x08 \x01(\x0e\x32).livekit.proto.IceServerTransportProtocolH\x01\x88\x01\x01\x12\x12\n\nfoundation\x18\t \x01(\t\x12\x17\n\x0frelated_address\x18\n \x01(\t\x12\x14\n\x0crelated_port\x18\x0b \x01(\x05\x12\x19\n\x11username_fragment\x18\x0c \x01(\t\x12\x39\n\x08tcp_type\x18\r \x01(\x0e\x32\".livekit.proto.IceTcpCandidateTypeH\x02\x88\x01\x01\x42\x11\n\x0f_candidate_typeB\x11\n\x0f_relay_protocolB\x0b\n\t_tcp_type\"\x81\x01\n\x10\x43\x65rtificateStats\x12\x13\n\x0b\x66ingerprint\x18\x01 \x01(\t\x12\x1d\n\x15\x66ingerprint_algorithm\x18\x02 \x01(\t\x12\x1a\n\x12\x62\x61se64_certificate\x18\x03 \x01(\t\x12\x1d\n\x15issuer_certificate_id\x18\x04 \x01(\t*Q\n\x10\x44\x61taChannelState\x12\x11\n\rDC_CONNECTING\x10\x00\x12\x0b\n\x07\x44\x43_OPEN\x10\x01\x12\x0e\n\nDC_CLOSING\x10\x02\x12\r\n\tDC_CLOSED\x10\x03*r\n\x17QualityLimitationReason\x12\x13\n\x0fLIMITATION_NONE\x10\x00\x12\x12\n\x0eLIMITATION_CPU\x10\x01\x12\x18\n\x14LIMITATION_BANDWIDTH\x10\x02\x12\x14\n\x10LIMITATION_OTHER\x10\x03*C\n\x07IceRole\x12\x0f\n\x0bICE_UNKNOWN\x10\x00\x12\x13\n\x0fICE_CONTROLLING\x10\x01\x12\x12\n\x0eICE_CONTROLLED\x10\x02*\x9f\x01\n\x12\x44tlsTransportState\x12\x16\n\x12\x44TLS_TRANSPORT_NEW\x10\x00\x12\x1d\n\x19\x44TLS_TRANSPORT_CONNECTING\x10\x01\x12\x1c\n\x18\x44TLS_TRANSPORT_CONNECTED\x10\x02\x12\x19\n\x15\x44TLS_TRANSPORT_CLOSED\x10\x03\x12\x19\n\x15\x44TLS_TRANSPORT_FAILED\x10\x04*\xd4\x01\n\x11IceTransportState\x12\x15\n\x11ICE_TRANSPORT_NEW\x10\x00\x12\x1a\n\x16ICE_TRANSPORT_CHECKING\x10\x01\x12\x1b\n\x17ICE_TRANSPORT_CONNECTED\x10\x02\x12\x1b\n\x17ICE_TRANSPORT_COMPLETED\x10\x03\x12\x1e\n\x1aICE_TRANSPORT_DISCONNECTED\x10\x04\x12\x18\n\x14ICE_TRANSPORT_FAILED\x10\x05\x12\x18\n\x14ICE_TRANSPORT_CLOSED\x10\x06*>\n\x08\x44tlsRole\x12\x0f\n\x0b\x44TLS_CLIENT\x10\x00\x12\x0f\n\x0b\x44TLS_SERVER\x10\x01\x12\x10\n\x0c\x44TLS_UNKNOWN\x10\x02*u\n\x15IceCandidatePairState\x12\x0f\n\x0bPAIR_FROZEN\x10\x00\x12\x10\n\x0cPAIR_WAITING\x10\x01\x12\x14\n\x10PAIR_IN_PROGRESS\x10\x02\x12\x0f\n\x0bPAIR_FAILED\x10\x03\x12\x12\n\x0ePAIR_SUCCEEDED\x10\x04*=\n\x10IceCandidateType\x12\x08\n\x04HOST\x10\x00\x12\t\n\x05SRFLX\x10\x01\x12\t\n\x05PRFLX\x10\x02\x12\t\n\x05RELAY\x10\x03*U\n\x1aIceServerTransportProtocol\x12\x11\n\rTRANSPORT_UDP\x10\x00\x12\x11\n\rTRANSPORT_TCP\x10\x01\x12\x11\n\rTRANSPORT_TLS\x10\x02*T\n\x13IceTcpCandidateType\x12\x14\n\x10\x43\x41NDIDATE_ACTIVE\x10\x00\x12\x15\n\x11\x43\x41NDIDATE_PASSIVE\x10\x01\x12\x10\n\x0c\x43\x41NDIDATE_SO\x10\x02\x42\x10\xaa\x02\rLiveKit.Protob\x06proto3')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0bstats.proto\x12\rlivekit.proto\"\xeb\x18\n\x08RtcStats\x12.\n\x05\x63odec\x18\x03 \x01(\x0b\x32\x1d.livekit.proto.RtcStats.CodecH\x00\x12\x39\n\x0binbound_rtp\x18\x04 \x01(\x0b\x32\".livekit.proto.RtcStats.InboundRtpH\x00\x12;\n\x0coutbound_rtp\x18\x05 \x01(\x0b\x32#.livekit.proto.RtcStats.OutboundRtpH\x00\x12\x46\n\x12remote_inbound_rtp\x18\x06 \x01(\x0b\x32(.livekit.proto.RtcStats.RemoteInboundRtpH\x00\x12H\n\x13remote_outbound_rtp\x18\x07 \x01(\x0b\x32).livekit.proto.RtcStats.RemoteOutboundRtpH\x00\x12;\n\x0cmedia_source\x18\x08 \x01(\x0b\x32#.livekit.proto.RtcStats.MediaSourceH\x00\x12=\n\rmedia_playout\x18\t \x01(\x0b\x32$.livekit.proto.RtcStats.MediaPlayoutH\x00\x12\x41\n\x0fpeer_connection\x18\n \x01(\x0b\x32&.livekit.proto.RtcStats.PeerConnectionH\x00\x12;\n\x0c\x64\x61ta_channel\x18\x0b \x01(\x0b\x32#.livekit.proto.RtcStats.DataChannelH\x00\x12\x36\n\ttransport\x18\x0c \x01(\x0b\x32!.livekit.proto.RtcStats.TransportH\x00\x12?\n\x0e\x63\x61ndidate_pair\x18\r \x01(\x0b\x32%.livekit.proto.RtcStats.CandidatePairH\x00\x12\x41\n\x0flocal_candidate\x18\x0e \x01(\x0b\x32&.livekit.proto.RtcStats.LocalCandidateH\x00\x12\x43\n\x10remote_candidate\x18\x0f \x01(\x0b\x32\'.livekit.proto.RtcStats.RemoteCandidateH\x00\x12:\n\x0b\x63\x65rtificate\x18\x10 \x01(\x0b\x32#.livekit.proto.RtcStats.CertificateH\x00\x12\x30\n\x06stream\x18\x11 \x01(\x0b\x32\x1e.livekit.proto.RtcStats.StreamH\x00\x12.\n\x05track\x18\x12 \x01(\x0b\x32\x1d.livekit.proto.RtcStats.TrackH\x00\x1a[\n\x05\x43odec\x12(\n\x03rtc\x18\x01 \x02(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12(\n\x05\x63odec\x18\x02 \x02(\x0b\x32\x19.livekit.proto.CodecStats\x1a\xd5\x01\n\nInboundRtp\x12(\n\x03rtc\x18\x01 \x02(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12-\n\x06stream\x18\x02 \x02(\x0b\x32\x1d.livekit.proto.RtpStreamStats\x12\x37\n\x08received\x18\x03 \x02(\x0b\x32%.livekit.proto.ReceivedRtpStreamStats\x12\x35\n\x07inbound\x18\x04 \x02(\x0b\x32$.livekit.proto.InboundRtpStreamStats\x1a\xd0\x01\n\x0bOutboundRtp\x12(\n\x03rtc\x18\x01 \x02(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12-\n\x06stream\x18\x02 \x02(\x0b\x32\x1d.livekit.proto.RtpStreamStats\x12/\n\x04sent\x18\x03 \x02(\x0b\x32!.livekit.proto.SentRtpStreamStats\x12\x37\n\x08outbound\x18\x04 \x02(\x0b\x32%.livekit.proto.OutboundRtpStreamStats\x1a\xe8\x01\n\x10RemoteInboundRtp\x12(\n\x03rtc\x18\x01 \x02(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12-\n\x06stream\x18\x02 \x02(\x0b\x32\x1d.livekit.proto.RtpStreamStats\x12\x37\n\x08received\x18\x03 \x02(\x0b\x32%.livekit.proto.ReceivedRtpStreamStats\x12\x42\n\x0eremote_inbound\x18\x04 \x02(\x0b\x32*.livekit.proto.RemoteInboundRtpStreamStats\x1a\xe3\x01\n\x11RemoteOutboundRtp\x12(\n\x03rtc\x18\x01 \x02(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12-\n\x06stream\x18\x02 \x02(\x0b\x32\x1d.livekit.proto.RtpStreamStats\x12/\n\x04sent\x18\x03 \x02(\x0b\x32!.livekit.proto.SentRtpStreamStats\x12\x44\n\x0fremote_outbound\x18\x04 \x02(\x0b\x32+.livekit.proto.RemoteOutboundRtpStreamStats\x1a\xc8\x01\n\x0bMediaSource\x12(\n\x03rtc\x18\x01 \x02(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12/\n\x06source\x18\x02 \x02(\x0b\x32\x1f.livekit.proto.MediaSourceStats\x12.\n\x05\x61udio\x18\x03 \x02(\x0b\x32\x1f.livekit.proto.AudioSourceStats\x12.\n\x05video\x18\x04 \x02(\x0b\x32\x1f.livekit.proto.VideoSourceStats\x1aq\n\x0cMediaPlayout\x12(\n\x03rtc\x18\x01 \x02(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12\x37\n\raudio_playout\x18\x02 \x02(\x0b\x32 .livekit.proto.AudioPlayoutStats\x1aj\n\x0ePeerConnection\x12(\n\x03rtc\x18\x01 \x02(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12.\n\x02pc\x18\x02 \x02(\x0b\x32\".livekit.proto.PeerConnectionStats\x1a\x64\n\x0b\x44\x61taChannel\x12(\n\x03rtc\x18\x01 \x02(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12+\n\x02\x64\x63\x18\x02 \x02(\x0b\x32\x1f.livekit.proto.DataChannelStats\x1ag\n\tTransport\x12(\n\x03rtc\x18\x01 \x02(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12\x30\n\ttransport\x18\x02 \x02(\x0b\x32\x1d.livekit.proto.TransportStats\x1at\n\rCandidatePair\x12(\n\x03rtc\x18\x01 \x02(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12\x39\n\x0e\x63\x61ndidate_pair\x18\x02 \x02(\x0b\x32!.livekit.proto.CandidatePairStats\x1ao\n\x0eLocalCandidate\x12(\n\x03rtc\x18\x01 \x02(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12\x33\n\tcandidate\x18\x02 \x02(\x0b\x32 .livekit.proto.IceCandidateStats\x1ap\n\x0fRemoteCandidate\x12(\n\x03rtc\x18\x01 \x02(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12\x33\n\tcandidate\x18\x02 \x02(\x0b\x32 .livekit.proto.IceCandidateStats\x1am\n\x0b\x43\x65rtificate\x12(\n\x03rtc\x18\x01 \x02(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12\x34\n\x0b\x63\x65rtificate\x18\x02 \x02(\x0b\x32\x1f.livekit.proto.CertificateStats\x1a^\n\x06Stream\x12(\n\x03rtc\x18\x01 \x02(\x0b\x32\x1b.livekit.proto.RtcStatsData\x12*\n\x06stream\x18\x02 \x02(\x0b\x32\x1a.livekit.proto.StreamStats\x1a\x07\n\x05TrackB\x07\n\x05stats\"-\n\x0cRtcStatsData\x12\n\n\x02id\x18\x01 \x02(\t\x12\x11\n\ttimestamp\x18\x02 \x02(\x03\"\x88\x01\n\nCodecStats\x12\x14\n\x0cpayload_type\x18\x01 \x02(\r\x12\x14\n\x0ctransport_id\x18\x02 \x02(\t\x12\x11\n\tmime_type\x18\x03 \x02(\t\x12\x12\n\nclock_rate\x18\x04 \x02(\r\x12\x10\n\x08\x63hannels\x18\x05 \x02(\r\x12\x15\n\rsdp_fmtp_line\x18\x06 \x02(\t\"T\n\x0eRtpStreamStats\x12\x0c\n\x04ssrc\x18\x01 \x02(\r\x12\x0c\n\x04kind\x18\x02 \x02(\t\x12\x14\n\x0ctransport_id\x18\x03 \x02(\t\x12\x10\n\x08\x63odec_id\x18\x04 \x02(\t\"X\n\x16ReceivedRtpStreamStats\x12\x18\n\x10packets_received\x18\x01 \x02(\x04\x12\x14\n\x0cpackets_lost\x18\x02 \x02(\x03\x12\x0e\n\x06jitter\x18\x03 \x02(\x01\"\x82\x0c\n\x15InboundRtpStreamStats\x12\x18\n\x10track_identifier\x18\x01 \x02(\t\x12\x0b\n\x03mid\x18\x02 \x02(\t\x12\x11\n\tremote_id\x18\x03 \x02(\t\x12\x16\n\x0e\x66rames_decoded\x18\x04 \x02(\r\x12\x1a\n\x12key_frames_decoded\x18\x05 \x02(\r\x12\x17\n\x0f\x66rames_rendered\x18\x06 \x02(\r\x12\x16\n\x0e\x66rames_dropped\x18\x07 \x02(\r\x12\x13\n\x0b\x66rame_width\x18\x08 \x02(\r\x12\x14\n\x0c\x66rame_height\x18\t \x02(\r\x12\x19\n\x11\x66rames_per_second\x18\n \x02(\x01\x12\x0e\n\x06qp_sum\x18\x0b \x02(\x04\x12\x19\n\x11total_decode_time\x18\x0c \x02(\x01\x12\x1f\n\x17total_inter_frame_delay\x18\r \x02(\x01\x12\'\n\x1ftotal_squared_inter_frame_delay\x18\x0e \x02(\x01\x12\x13\n\x0bpause_count\x18\x0f \x02(\r\x12\x1c\n\x14total_pause_duration\x18\x10 \x02(\x01\x12\x14\n\x0c\x66reeze_count\x18\x11 \x02(\r\x12\x1d\n\x15total_freeze_duration\x18\x12 \x02(\x01\x12&\n\x1elast_packet_received_timestamp\x18\x13 \x02(\x01\x12\x1d\n\x15header_bytes_received\x18\x14 \x02(\x04\x12\x19\n\x11packets_discarded\x18\x15 \x02(\x04\x12\x1a\n\x12\x66\x65\x63_bytes_received\x18\x16 \x02(\x04\x12\x1c\n\x14\x66\x65\x63_packets_received\x18\x17 \x02(\x04\x12\x1d\n\x15\x66\x65\x63_packets_discarded\x18\x18 \x02(\x04\x12\x16\n\x0e\x62ytes_received\x18\x19 \x02(\x04\x12\x12\n\nnack_count\x18\x1a \x02(\r\x12\x11\n\tfir_count\x18\x1b \x02(\r\x12\x11\n\tpli_count\x18\x1c \x02(\r\x12\x1e\n\x16total_processing_delay\x18\x1d \x02(\x01\x12#\n\x1b\x65stimated_playout_timestamp\x18\x1e \x02(\x01\x12\x1b\n\x13jitter_buffer_delay\x18\x1f \x02(\x01\x12\"\n\x1ajitter_buffer_target_delay\x18 \x02(\x01\x12#\n\x1bjitter_buffer_emitted_count\x18! \x02(\x04\x12#\n\x1bjitter_buffer_minimum_delay\x18\" \x02(\x01\x12\x1e\n\x16total_samples_received\x18# \x02(\x04\x12\x19\n\x11\x63oncealed_samples\x18$ \x02(\x04\x12 \n\x18silent_concealed_samples\x18% \x02(\x04\x12\x1a\n\x12\x63oncealment_events\x18& \x02(\x04\x12)\n!inserted_samples_for_deceleration\x18\' \x02(\x04\x12(\n removed_samples_for_acceleration\x18( \x02(\x04\x12\x13\n\x0b\x61udio_level\x18) \x02(\x01\x12\x1a\n\x12total_audio_energy\x18* \x02(\x01\x12\x1e\n\x16total_samples_duration\x18+ \x02(\x01\x12\x17\n\x0f\x66rames_received\x18, \x02(\x04\x12\x1e\n\x16\x64\x65\x63oder_implementation\x18- \x02(\t\x12\x12\n\nplayout_id\x18. \x02(\t\x12\x1f\n\x17power_efficient_decoder\x18/ \x02(\x08\x12.\n&frames_assembled_from_multiple_packets\x18\x30 \x02(\x04\x12\x1b\n\x13total_assembly_time\x18\x31 \x02(\x01\x12&\n\x1eretransmitted_packets_received\x18\x32 \x02(\x04\x12$\n\x1cretransmitted_bytes_received\x18\x33 \x02(\x04\x12\x10\n\x08rtx_ssrc\x18\x34 \x02(\r\x12\x10\n\x08\x66\x65\x63_ssrc\x18\x35 \x02(\r\">\n\x12SentRtpStreamStats\x12\x14\n\x0cpackets_sent\x18\x01 \x02(\x04\x12\x12\n\nbytes_sent\x18\x02 \x02(\x04\"\xd1\x07\n\x16OutboundRtpStreamStats\x12\x0b\n\x03mid\x18\x01 \x02(\t\x12\x17\n\x0fmedia_source_id\x18\x02 \x02(\t\x12\x11\n\tremote_id\x18\x03 \x02(\t\x12\x0b\n\x03rid\x18\x04 \x02(\t\x12\x19\n\x11header_bytes_sent\x18\x05 \x02(\x04\x12\"\n\x1aretransmitted_packets_sent\x18\x06 \x02(\x04\x12 \n\x18retransmitted_bytes_sent\x18\x07 \x02(\x04\x12\x10\n\x08rtx_ssrc\x18\x08 \x02(\r\x12\x16\n\x0etarget_bitrate\x18\t \x02(\x01\x12\"\n\x1atotal_encoded_bytes_target\x18\n \x02(\x04\x12\x13\n\x0b\x66rame_width\x18\x0b \x02(\r\x12\x14\n\x0c\x66rame_height\x18\x0c \x02(\r\x12\x19\n\x11\x66rames_per_second\x18\r \x02(\x01\x12\x13\n\x0b\x66rames_sent\x18\x0e \x02(\r\x12\x18\n\x10huge_frames_sent\x18\x0f \x02(\r\x12\x16\n\x0e\x66rames_encoded\x18\x10 \x02(\r\x12\x1a\n\x12key_frames_encoded\x18\x11 \x02(\r\x12\x0e\n\x06qp_sum\x18\x12 \x02(\x04\x12\x19\n\x11total_encode_time\x18\x13 \x02(\x01\x12\x1f\n\x17total_packet_send_delay\x18\x14 \x02(\x01\x12I\n\x19quality_limitation_reason\x18\x15 \x02(\x0e\x32&.livekit.proto.QualityLimitationReason\x12k\n\x1cquality_limitation_durations\x18\x16 \x03(\x0b\x32\x45.livekit.proto.OutboundRtpStreamStats.QualityLimitationDurationsEntry\x12-\n%quality_limitation_resolution_changes\x18\x17 \x02(\r\x12\x12\n\nnack_count\x18\x18 \x02(\r\x12\x11\n\tfir_count\x18\x19 \x02(\r\x12\x11\n\tpli_count\x18\x1a \x02(\r\x12\x1e\n\x16\x65ncoder_implementation\x18\x1b \x02(\t\x12\x1f\n\x17power_efficient_encoder\x18\x1c \x02(\x08\x12\x0e\n\x06\x61\x63tive\x18\x1d \x02(\x08\x12\x18\n\x10scalability_mode\x18\x1e \x02(\t\x1a\x41\n\x1fQualityLimitationDurationsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x01:\x02\x38\x01\"\xa4\x01\n\x1bRemoteInboundRtpStreamStats\x12\x10\n\x08local_id\x18\x01 \x02(\t\x12\x17\n\x0fround_trip_time\x18\x02 \x02(\x01\x12\x1d\n\x15total_round_trip_time\x18\x03 \x02(\x01\x12\x15\n\rfraction_lost\x18\x04 \x02(\x01\x12$\n\x1cround_trip_time_measurements\x18\x05 \x02(\x04\"\xbe\x01\n\x1cRemoteOutboundRtpStreamStats\x12\x10\n\x08local_id\x18\x01 \x02(\t\x12\x18\n\x10remote_timestamp\x18\x02 \x02(\x01\x12\x14\n\x0creports_sent\x18\x03 \x02(\x04\x12\x17\n\x0fround_trip_time\x18\x04 \x02(\x01\x12\x1d\n\x15total_round_trip_time\x18\x05 \x02(\x01\x12$\n\x1cround_trip_time_measurements\x18\x06 \x02(\x04\":\n\x10MediaSourceStats\x12\x18\n\x10track_identifier\x18\x01 \x02(\t\x12\x0c\n\x04kind\x18\x02 \x02(\t\"\xa2\x02\n\x10\x41udioSourceStats\x12\x13\n\x0b\x61udio_level\x18\x01 \x02(\x01\x12\x1a\n\x12total_audio_energy\x18\x02 \x02(\x01\x12\x1e\n\x16total_samples_duration\x18\x03 \x02(\x01\x12\x18\n\x10\x65\x63ho_return_loss\x18\x04 \x02(\x01\x12$\n\x1c\x65\x63ho_return_loss_enhancement\x18\x05 \x02(\x01\x12 \n\x18\x64ropped_samples_duration\x18\x06 \x02(\x01\x12\x1e\n\x16\x64ropped_samples_events\x18\x07 \x02(\r\x12\x1b\n\x13total_capture_delay\x18\x08 \x02(\x01\x12\x1e\n\x16total_samples_captured\x18\t \x02(\x04\"\\\n\x10VideoSourceStats\x12\r\n\x05width\x18\x01 \x02(\r\x12\x0e\n\x06height\x18\x02 \x02(\r\x12\x0e\n\x06\x66rames\x18\x03 \x02(\r\x12\x19\n\x11\x66rames_per_second\x18\x04 \x02(\x01\"\xc5\x01\n\x11\x41udioPlayoutStats\x12\x0c\n\x04kind\x18\x01 \x02(\t\x12$\n\x1csynthesized_samples_duration\x18\x02 \x02(\x01\x12\"\n\x1asynthesized_samples_events\x18\x03 \x02(\r\x12\x1e\n\x16total_samples_duration\x18\x04 \x02(\x01\x12\x1b\n\x13total_playout_delay\x18\x05 \x02(\x01\x12\x1b\n\x13total_samples_count\x18\x06 \x02(\x04\"Q\n\x13PeerConnectionStats\x12\x1c\n\x14\x64\x61ta_channels_opened\x18\x01 \x02(\r\x12\x1c\n\x14\x64\x61ta_channels_closed\x18\x02 \x02(\r\"\xe2\x01\n\x10\x44\x61taChannelStats\x12\r\n\x05label\x18\x01 \x02(\t\x12\x10\n\x08protocol\x18\x02 \x02(\t\x12\x1f\n\x17\x64\x61ta_channel_identifier\x18\x03 \x02(\x05\x12.\n\x05state\x18\x04 \x01(\x0e\x32\x1f.livekit.proto.DataChannelState\x12\x15\n\rmessages_sent\x18\x05 \x02(\r\x12\x12\n\nbytes_sent\x18\x06 \x02(\x04\x12\x19\n\x11messages_received\x18\x07 \x02(\r\x12\x16\n\x0e\x62ytes_received\x18\x08 \x02(\x04\"\x9c\x04\n\x0eTransportStats\x12\x14\n\x0cpackets_sent\x18\x01 \x02(\x04\x12\x18\n\x10packets_received\x18\x02 \x02(\x04\x12\x12\n\nbytes_sent\x18\x03 \x02(\x04\x12\x16\n\x0e\x62ytes_received\x18\x04 \x02(\x04\x12(\n\x08ice_role\x18\x05 \x02(\x0e\x32\x16.livekit.proto.IceRole\x12#\n\x1bice_local_username_fragment\x18\x06 \x02(\t\x12\x35\n\ndtls_state\x18\x07 \x01(\x0e\x32!.livekit.proto.DtlsTransportState\x12\x33\n\tice_state\x18\x08 \x01(\x0e\x32 .livekit.proto.IceTransportState\x12\"\n\x1aselected_candidate_pair_id\x18\t \x02(\t\x12\x1c\n\x14local_certificate_id\x18\n \x02(\t\x12\x1d\n\x15remote_certificate_id\x18\x0b \x02(\t\x12\x13\n\x0btls_version\x18\x0c \x02(\t\x12\x13\n\x0b\x64tls_cipher\x18\r \x02(\t\x12*\n\tdtls_role\x18\x0e \x02(\x0e\x32\x17.livekit.proto.DtlsRole\x12\x13\n\x0bsrtp_cipher\x18\x0f \x02(\t\x12\'\n\x1fselected_candidate_pair_changes\x18\x10 \x02(\r\"\xa4\x05\n\x12\x43\x61ndidatePairStats\x12\x14\n\x0ctransport_id\x18\x01 \x02(\t\x12\x1a\n\x12local_candidate_id\x18\x02 \x02(\t\x12\x1b\n\x13remote_candidate_id\x18\x03 \x02(\t\x12\x33\n\x05state\x18\x04 \x01(\x0e\x32$.livekit.proto.IceCandidatePairState\x12\x11\n\tnominated\x18\x05 \x02(\x08\x12\x14\n\x0cpackets_sent\x18\x06 \x02(\x04\x12\x18\n\x10packets_received\x18\x07 \x02(\x04\x12\x12\n\nbytes_sent\x18\x08 \x02(\x04\x12\x16\n\x0e\x62ytes_received\x18\t \x02(\x04\x12\"\n\x1alast_packet_sent_timestamp\x18\n \x02(\x01\x12&\n\x1elast_packet_received_timestamp\x18\x0b \x02(\x01\x12\x1d\n\x15total_round_trip_time\x18\x0c \x02(\x01\x12\x1f\n\x17\x63urrent_round_trip_time\x18\r \x02(\x01\x12\"\n\x1a\x61vailable_outgoing_bitrate\x18\x0e \x02(\x01\x12\"\n\x1a\x61vailable_incoming_bitrate\x18\x0f \x02(\x01\x12\x19\n\x11requests_received\x18\x10 \x02(\x04\x12\x15\n\rrequests_sent\x18\x11 \x02(\x04\x12\x1a\n\x12responses_received\x18\x12 \x02(\x04\x12\x16\n\x0eresponses_sent\x18\x13 \x02(\x04\x12\x1d\n\x15\x63onsent_requests_sent\x18\x14 \x02(\x04\x12!\n\x19packets_discarded_on_send\x18\x15 \x02(\r\x12\x1f\n\x17\x62ytes_discarded_on_send\x18\x16 \x02(\x04\"\x89\x03\n\x11IceCandidateStats\x12\x14\n\x0ctransport_id\x18\x01 \x02(\t\x12\x0f\n\x07\x61\x64\x64ress\x18\x02 \x02(\t\x12\x0c\n\x04port\x18\x03 \x02(\x05\x12\x10\n\x08protocol\x18\x04 \x02(\t\x12\x37\n\x0e\x63\x61ndidate_type\x18\x05 \x01(\x0e\x32\x1f.livekit.proto.IceCandidateType\x12\x10\n\x08priority\x18\x06 \x02(\x05\x12\x0b\n\x03url\x18\x07 \x02(\t\x12\x41\n\x0erelay_protocol\x18\x08 \x01(\x0e\x32).livekit.proto.IceServerTransportProtocol\x12\x12\n\nfoundation\x18\t \x02(\t\x12\x17\n\x0frelated_address\x18\n \x02(\t\x12\x14\n\x0crelated_port\x18\x0b \x02(\x05\x12\x19\n\x11username_fragment\x18\x0c \x02(\t\x12\x34\n\x08tcp_type\x18\r \x01(\x0e\x32\".livekit.proto.IceTcpCandidateType\"\x81\x01\n\x10\x43\x65rtificateStats\x12\x13\n\x0b\x66ingerprint\x18\x01 \x02(\t\x12\x1d\n\x15\x66ingerprint_algorithm\x18\x02 \x02(\t\x12\x1a\n\x12\x62\x61se64_certificate\x18\x03 \x02(\t\x12\x1d\n\x15issuer_certificate_id\x18\x04 \x02(\t\"4\n\x0bStreamStats\x12\n\n\x02id\x18\x01 \x02(\t\x12\x19\n\x11stream_identifier\x18\x02 \x02(\t*Q\n\x10\x44\x61taChannelState\x12\x11\n\rDC_CONNECTING\x10\x00\x12\x0b\n\x07\x44\x43_OPEN\x10\x01\x12\x0e\n\nDC_CLOSING\x10\x02\x12\r\n\tDC_CLOSED\x10\x03*r\n\x17QualityLimitationReason\x12\x13\n\x0fLIMITATION_NONE\x10\x00\x12\x12\n\x0eLIMITATION_CPU\x10\x01\x12\x18\n\x14LIMITATION_BANDWIDTH\x10\x02\x12\x14\n\x10LIMITATION_OTHER\x10\x03*C\n\x07IceRole\x12\x0f\n\x0bICE_UNKNOWN\x10\x00\x12\x13\n\x0fICE_CONTROLLING\x10\x01\x12\x12\n\x0eICE_CONTROLLED\x10\x02*\x9f\x01\n\x12\x44tlsTransportState\x12\x16\n\x12\x44TLS_TRANSPORT_NEW\x10\x00\x12\x1d\n\x19\x44TLS_TRANSPORT_CONNECTING\x10\x01\x12\x1c\n\x18\x44TLS_TRANSPORT_CONNECTED\x10\x02\x12\x19\n\x15\x44TLS_TRANSPORT_CLOSED\x10\x03\x12\x19\n\x15\x44TLS_TRANSPORT_FAILED\x10\x04*\xd4\x01\n\x11IceTransportState\x12\x15\n\x11ICE_TRANSPORT_NEW\x10\x00\x12\x1a\n\x16ICE_TRANSPORT_CHECKING\x10\x01\x12\x1b\n\x17ICE_TRANSPORT_CONNECTED\x10\x02\x12\x1b\n\x17ICE_TRANSPORT_COMPLETED\x10\x03\x12\x1e\n\x1aICE_TRANSPORT_DISCONNECTED\x10\x04\x12\x18\n\x14ICE_TRANSPORT_FAILED\x10\x05\x12\x18\n\x14ICE_TRANSPORT_CLOSED\x10\x06*>\n\x08\x44tlsRole\x12\x0f\n\x0b\x44TLS_CLIENT\x10\x00\x12\x0f\n\x0b\x44TLS_SERVER\x10\x01\x12\x10\n\x0c\x44TLS_UNKNOWN\x10\x02*u\n\x15IceCandidatePairState\x12\x0f\n\x0bPAIR_FROZEN\x10\x00\x12\x10\n\x0cPAIR_WAITING\x10\x01\x12\x14\n\x10PAIR_IN_PROGRESS\x10\x02\x12\x0f\n\x0bPAIR_FAILED\x10\x03\x12\x12\n\x0ePAIR_SUCCEEDED\x10\x04*=\n\x10IceCandidateType\x12\x08\n\x04HOST\x10\x00\x12\t\n\x05SRFLX\x10\x01\x12\t\n\x05PRFLX\x10\x02\x12\t\n\x05RELAY\x10\x03*U\n\x1aIceServerTransportProtocol\x12\x11\n\rTRANSPORT_UDP\x10\x00\x12\x11\n\rTRANSPORT_TCP\x10\x01\x12\x11\n\rTRANSPORT_TLS\x10\x02*T\n\x13IceTcpCandidateType\x12\x14\n\x10\x43\x41NDIDATE_ACTIVE\x10\x00\x12\x15\n\x11\x43\x41NDIDATE_PASSIVE\x10\x01\x12\x10\n\x0c\x43\x41NDIDATE_SO\x10\x02\x42\x10\xaa\x02\rLiveKit.Proto')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -24,96 +24,100 @@
_globals['DESCRIPTOR']._serialized_options = b'\252\002\rLiveKit.Proto'
_globals['_OUTBOUNDRTPSTREAMSTATS_QUALITYLIMITATIONDURATIONSENTRY']._options = None
_globals['_OUTBOUNDRTPSTREAMSTATS_QUALITYLIMITATIONDURATIONSENTRY']._serialized_options = b'8\001'
- _globals['_DATACHANNELSTATE']._serialized_start=9217
- _globals['_DATACHANNELSTATE']._serialized_end=9298
- _globals['_QUALITYLIMITATIONREASON']._serialized_start=9300
- _globals['_QUALITYLIMITATIONREASON']._serialized_end=9414
- _globals['_ICEROLE']._serialized_start=9416
- _globals['_ICEROLE']._serialized_end=9483
- _globals['_DTLSTRANSPORTSTATE']._serialized_start=9486
- _globals['_DTLSTRANSPORTSTATE']._serialized_end=9645
- _globals['_ICETRANSPORTSTATE']._serialized_start=9648
- _globals['_ICETRANSPORTSTATE']._serialized_end=9860
- _globals['_DTLSROLE']._serialized_start=9862
- _globals['_DTLSROLE']._serialized_end=9924
- _globals['_ICECANDIDATEPAIRSTATE']._serialized_start=9926
- _globals['_ICECANDIDATEPAIRSTATE']._serialized_end=10043
- _globals['_ICECANDIDATETYPE']._serialized_start=10045
- _globals['_ICECANDIDATETYPE']._serialized_end=10106
- _globals['_ICESERVERTRANSPORTPROTOCOL']._serialized_start=10108
- _globals['_ICESERVERTRANSPORTPROTOCOL']._serialized_end=10193
- _globals['_ICETCPCANDIDATETYPE']._serialized_start=10195
- _globals['_ICETCPCANDIDATETYPE']._serialized_end=10279
+ _globals['_DATACHANNELSTATE']._serialized_start=9282
+ _globals['_DATACHANNELSTATE']._serialized_end=9363
+ _globals['_QUALITYLIMITATIONREASON']._serialized_start=9365
+ _globals['_QUALITYLIMITATIONREASON']._serialized_end=9479
+ _globals['_ICEROLE']._serialized_start=9481
+ _globals['_ICEROLE']._serialized_end=9548
+ _globals['_DTLSTRANSPORTSTATE']._serialized_start=9551
+ _globals['_DTLSTRANSPORTSTATE']._serialized_end=9710
+ _globals['_ICETRANSPORTSTATE']._serialized_start=9713
+ _globals['_ICETRANSPORTSTATE']._serialized_end=9925
+ _globals['_DTLSROLE']._serialized_start=9927
+ _globals['_DTLSROLE']._serialized_end=9989
+ _globals['_ICECANDIDATEPAIRSTATE']._serialized_start=9991
+ _globals['_ICECANDIDATEPAIRSTATE']._serialized_end=10108
+ _globals['_ICECANDIDATETYPE']._serialized_start=10110
+ _globals['_ICECANDIDATETYPE']._serialized_end=10171
+ _globals['_ICESERVERTRANSPORTPROTOCOL']._serialized_start=10173
+ _globals['_ICESERVERTRANSPORTPROTOCOL']._serialized_end=10258
+ _globals['_ICETCPCANDIDATETYPE']._serialized_start=10260
+ _globals['_ICETCPCANDIDATETYPE']._serialized_end=10344
_globals['_RTCSTATS']._serialized_start=31
- _globals['_RTCSTATS']._serialized_end=3064
- _globals['_RTCSTATS_CODEC']._serialized_start=974
- _globals['_RTCSTATS_CODEC']._serialized_end=1065
- _globals['_RTCSTATS_INBOUNDRTP']._serialized_start=1068
- _globals['_RTCSTATS_INBOUNDRTP']._serialized_end=1281
- _globals['_RTCSTATS_OUTBOUNDRTP']._serialized_start=1284
- _globals['_RTCSTATS_OUTBOUNDRTP']._serialized_end=1492
- _globals['_RTCSTATS_REMOTEINBOUNDRTP']._serialized_start=1495
- _globals['_RTCSTATS_REMOTEINBOUNDRTP']._serialized_end=1727
- _globals['_RTCSTATS_REMOTEOUTBOUNDRTP']._serialized_start=1730
- _globals['_RTCSTATS_REMOTEOUTBOUNDRTP']._serialized_end=1957
- _globals['_RTCSTATS_MEDIASOURCE']._serialized_start=1960
- _globals['_RTCSTATS_MEDIASOURCE']._serialized_end=2160
- _globals['_RTCSTATS_MEDIAPLAYOUT']._serialized_start=2162
- _globals['_RTCSTATS_MEDIAPLAYOUT']._serialized_end=2275
- _globals['_RTCSTATS_PEERCONNECTION']._serialized_start=2277
- _globals['_RTCSTATS_PEERCONNECTION']._serialized_end=2383
- _globals['_RTCSTATS_DATACHANNEL']._serialized_start=2385
- _globals['_RTCSTATS_DATACHANNEL']._serialized_end=2485
- _globals['_RTCSTATS_TRANSPORT']._serialized_start=2487
- _globals['_RTCSTATS_TRANSPORT']._serialized_end=2590
- _globals['_RTCSTATS_CANDIDATEPAIR']._serialized_start=2592
- _globals['_RTCSTATS_CANDIDATEPAIR']._serialized_end=2708
- _globals['_RTCSTATS_LOCALCANDIDATE']._serialized_start=2710
- _globals['_RTCSTATS_LOCALCANDIDATE']._serialized_end=2821
- _globals['_RTCSTATS_REMOTECANDIDATE']._serialized_start=2823
- _globals['_RTCSTATS_REMOTECANDIDATE']._serialized_end=2935
- _globals['_RTCSTATS_CERTIFICATE']._serialized_start=2937
- _globals['_RTCSTATS_CERTIFICATE']._serialized_end=3046
- _globals['_RTCSTATS_TRACK']._serialized_start=3048
- _globals['_RTCSTATS_TRACK']._serialized_end=3055
- _globals['_RTCSTATSDATA']._serialized_start=3066
- _globals['_RTCSTATSDATA']._serialized_end=3111
- _globals['_CODECSTATS']._serialized_start=3114
- _globals['_CODECSTATS']._serialized_end=3250
- _globals['_RTPSTREAMSTATS']._serialized_start=3252
- _globals['_RTPSTREAMSTATS']._serialized_end=3336
- _globals['_RECEIVEDRTPSTREAMSTATS']._serialized_start=3338
- _globals['_RECEIVEDRTPSTREAMSTATS']._serialized_end=3426
- _globals['_INBOUNDRTPSTREAMSTATS']._serialized_start=3429
- _globals['_INBOUNDRTPSTREAMSTATS']._serialized_end=4967
- _globals['_SENTRTPSTREAMSTATS']._serialized_start=4969
- _globals['_SENTRTPSTREAMSTATS']._serialized_end=5031
- _globals['_OUTBOUNDRTPSTREAMSTATS']._serialized_start=5034
- _globals['_OUTBOUNDRTPSTREAMSTATS']._serialized_end=6011
- _globals['_OUTBOUNDRTPSTREAMSTATS_QUALITYLIMITATIONDURATIONSENTRY']._serialized_start=5946
- _globals['_OUTBOUNDRTPSTREAMSTATS_QUALITYLIMITATIONDURATIONSENTRY']._serialized_end=6011
- _globals['_REMOTEINBOUNDRTPSTREAMSTATS']._serialized_start=6014
- _globals['_REMOTEINBOUNDRTPSTREAMSTATS']._serialized_end=6178
- _globals['_REMOTEOUTBOUNDRTPSTREAMSTATS']._serialized_start=6181
- _globals['_REMOTEOUTBOUNDRTPSTREAMSTATS']._serialized_end=6371
- _globals['_MEDIASOURCESTATS']._serialized_start=6373
- _globals['_MEDIASOURCESTATS']._serialized_end=6431
- _globals['_AUDIOSOURCESTATS']._serialized_start=6434
- _globals['_AUDIOSOURCESTATS']._serialized_end=6724
- _globals['_VIDEOSOURCESTATS']._serialized_start=6726
- _globals['_VIDEOSOURCESTATS']._serialized_end=6818
- _globals['_AUDIOPLAYOUTSTATS']._serialized_start=6821
- _globals['_AUDIOPLAYOUTSTATS']._serialized_end=7018
- _globals['_PEERCONNECTIONSTATS']._serialized_start=7020
- _globals['_PEERCONNECTIONSTATS']._serialized_end=7101
- _globals['_DATACHANNELSTATS']._serialized_start=7104
- _globals['_DATACHANNELSTATS']._serialized_end=7345
- _globals['_TRANSPORTSTATS']._serialized_start=7348
- _globals['_TRANSPORTSTATS']._serialized_end=7927
- _globals['_CANDIDATEPAIRSTATS']._serialized_start=7930
- _globals['_CANDIDATEPAIRSTATS']._serialized_end=8621
- _globals['_ICECANDIDATESTATS']._serialized_start=8624
- _globals['_ICECANDIDATESTATS']._serialized_end=9083
- _globals['_CERTIFICATESTATS']._serialized_start=9086
- _globals['_CERTIFICATESTATS']._serialized_end=9215
+ _globals['_RTCSTATS']._serialized_end=3210
+ _globals['_RTCSTATS_CODEC']._serialized_start=1024
+ _globals['_RTCSTATS_CODEC']._serialized_end=1115
+ _globals['_RTCSTATS_INBOUNDRTP']._serialized_start=1118
+ _globals['_RTCSTATS_INBOUNDRTP']._serialized_end=1331
+ _globals['_RTCSTATS_OUTBOUNDRTP']._serialized_start=1334
+ _globals['_RTCSTATS_OUTBOUNDRTP']._serialized_end=1542
+ _globals['_RTCSTATS_REMOTEINBOUNDRTP']._serialized_start=1545
+ _globals['_RTCSTATS_REMOTEINBOUNDRTP']._serialized_end=1777
+ _globals['_RTCSTATS_REMOTEOUTBOUNDRTP']._serialized_start=1780
+ _globals['_RTCSTATS_REMOTEOUTBOUNDRTP']._serialized_end=2007
+ _globals['_RTCSTATS_MEDIASOURCE']._serialized_start=2010
+ _globals['_RTCSTATS_MEDIASOURCE']._serialized_end=2210
+ _globals['_RTCSTATS_MEDIAPLAYOUT']._serialized_start=2212
+ _globals['_RTCSTATS_MEDIAPLAYOUT']._serialized_end=2325
+ _globals['_RTCSTATS_PEERCONNECTION']._serialized_start=2327
+ _globals['_RTCSTATS_PEERCONNECTION']._serialized_end=2433
+ _globals['_RTCSTATS_DATACHANNEL']._serialized_start=2435
+ _globals['_RTCSTATS_DATACHANNEL']._serialized_end=2535
+ _globals['_RTCSTATS_TRANSPORT']._serialized_start=2537
+ _globals['_RTCSTATS_TRANSPORT']._serialized_end=2640
+ _globals['_RTCSTATS_CANDIDATEPAIR']._serialized_start=2642
+ _globals['_RTCSTATS_CANDIDATEPAIR']._serialized_end=2758
+ _globals['_RTCSTATS_LOCALCANDIDATE']._serialized_start=2760
+ _globals['_RTCSTATS_LOCALCANDIDATE']._serialized_end=2871
+ _globals['_RTCSTATS_REMOTECANDIDATE']._serialized_start=2873
+ _globals['_RTCSTATS_REMOTECANDIDATE']._serialized_end=2985
+ _globals['_RTCSTATS_CERTIFICATE']._serialized_start=2987
+ _globals['_RTCSTATS_CERTIFICATE']._serialized_end=3096
+ _globals['_RTCSTATS_STREAM']._serialized_start=3098
+ _globals['_RTCSTATS_STREAM']._serialized_end=3192
+ _globals['_RTCSTATS_TRACK']._serialized_start=3194
+ _globals['_RTCSTATS_TRACK']._serialized_end=3201
+ _globals['_RTCSTATSDATA']._serialized_start=3212
+ _globals['_RTCSTATSDATA']._serialized_end=3257
+ _globals['_CODECSTATS']._serialized_start=3260
+ _globals['_CODECSTATS']._serialized_end=3396
+ _globals['_RTPSTREAMSTATS']._serialized_start=3398
+ _globals['_RTPSTREAMSTATS']._serialized_end=3482
+ _globals['_RECEIVEDRTPSTREAMSTATS']._serialized_start=3484
+ _globals['_RECEIVEDRTPSTREAMSTATS']._serialized_end=3572
+ _globals['_INBOUNDRTPSTREAMSTATS']._serialized_start=3575
+ _globals['_INBOUNDRTPSTREAMSTATS']._serialized_end=5113
+ _globals['_SENTRTPSTREAMSTATS']._serialized_start=5115
+ _globals['_SENTRTPSTREAMSTATS']._serialized_end=5177
+ _globals['_OUTBOUNDRTPSTREAMSTATS']._serialized_start=5180
+ _globals['_OUTBOUNDRTPSTREAMSTATS']._serialized_end=6157
+ _globals['_OUTBOUNDRTPSTREAMSTATS_QUALITYLIMITATIONDURATIONSENTRY']._serialized_start=6092
+ _globals['_OUTBOUNDRTPSTREAMSTATS_QUALITYLIMITATIONDURATIONSENTRY']._serialized_end=6157
+ _globals['_REMOTEINBOUNDRTPSTREAMSTATS']._serialized_start=6160
+ _globals['_REMOTEINBOUNDRTPSTREAMSTATS']._serialized_end=6324
+ _globals['_REMOTEOUTBOUNDRTPSTREAMSTATS']._serialized_start=6327
+ _globals['_REMOTEOUTBOUNDRTPSTREAMSTATS']._serialized_end=6517
+ _globals['_MEDIASOURCESTATS']._serialized_start=6519
+ _globals['_MEDIASOURCESTATS']._serialized_end=6577
+ _globals['_AUDIOSOURCESTATS']._serialized_start=6580
+ _globals['_AUDIOSOURCESTATS']._serialized_end=6870
+ _globals['_VIDEOSOURCESTATS']._serialized_start=6872
+ _globals['_VIDEOSOURCESTATS']._serialized_end=6964
+ _globals['_AUDIOPLAYOUTSTATS']._serialized_start=6967
+ _globals['_AUDIOPLAYOUTSTATS']._serialized_end=7164
+ _globals['_PEERCONNECTIONSTATS']._serialized_start=7166
+ _globals['_PEERCONNECTIONSTATS']._serialized_end=7247
+ _globals['_DATACHANNELSTATS']._serialized_start=7250
+ _globals['_DATACHANNELSTATS']._serialized_end=7476
+ _globals['_TRANSPORTSTATS']._serialized_start=7479
+ _globals['_TRANSPORTSTATS']._serialized_end=8019
+ _globals['_CANDIDATEPAIRSTATS']._serialized_start=8022
+ _globals['_CANDIDATEPAIRSTATS']._serialized_end=8698
+ _globals['_ICECANDIDATESTATS']._serialized_start=8701
+ _globals['_ICECANDIDATESTATS']._serialized_end=9094
+ _globals['_CERTIFICATESTATS']._serialized_start=9097
+ _globals['_CERTIFICATESTATS']._serialized_end=9226
+ _globals['_STREAMSTATS']._serialized_start=9228
+ _globals['_STREAMSTATS']._serialized_end=9280
# @@protoc_insertion_point(module_scope)
diff --git a/livekit-rtc/livekit/rtc/_proto/stats_pb2.pyi b/livekit-rtc/livekit/rtc/_proto/stats_pb2.pyi
index 82b8ef4b..a77c233e 100644
--- a/livekit-rtc/livekit/rtc/_proto/stats_pb2.pyi
+++ b/livekit-rtc/livekit/rtc/_proto/stats_pb2.pyi
@@ -1,7 +1,7 @@
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
-Copyright 2023 LiveKit, Inc.
+Copyright 2025 LiveKit, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
+
import builtins
import collections.abc
import google.protobuf.descriptor
@@ -223,11 +224,11 @@ CANDIDATE_PASSIVE: IceTcpCandidateType.ValueType # 1
CANDIDATE_SO: IceTcpCandidateType.ValueType # 2
global___IceTcpCandidateType = IceTcpCandidateType
-@typing_extensions.final
+@typing.final
class RtcStats(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
- @typing_extensions.final
+ @typing.final
class Codec(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -243,10 +244,10 @@ class RtcStats(google.protobuf.message.Message):
rtc: global___RtcStatsData | None = ...,
codec: global___CodecStats | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["codec", b"codec", "rtc", b"rtc"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["codec", b"codec", "rtc", b"rtc"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["codec", b"codec", "rtc", b"rtc"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["codec", b"codec", "rtc", b"rtc"]) -> None: ...
- @typing_extensions.final
+ @typing.final
class InboundRtp(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -270,10 +271,10 @@ class RtcStats(google.protobuf.message.Message):
received: global___ReceivedRtpStreamStats | None = ...,
inbound: global___InboundRtpStreamStats | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["inbound", b"inbound", "received", b"received", "rtc", b"rtc", "stream", b"stream"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["inbound", b"inbound", "received", b"received", "rtc", b"rtc", "stream", b"stream"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["inbound", b"inbound", "received", b"received", "rtc", b"rtc", "stream", b"stream"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["inbound", b"inbound", "received", b"received", "rtc", b"rtc", "stream", b"stream"]) -> None: ...
- @typing_extensions.final
+ @typing.final
class OutboundRtp(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -297,10 +298,10 @@ class RtcStats(google.protobuf.message.Message):
sent: global___SentRtpStreamStats | None = ...,
outbound: global___OutboundRtpStreamStats | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["outbound", b"outbound", "rtc", b"rtc", "sent", b"sent", "stream", b"stream"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["outbound", b"outbound", "rtc", b"rtc", "sent", b"sent", "stream", b"stream"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["outbound", b"outbound", "rtc", b"rtc", "sent", b"sent", "stream", b"stream"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["outbound", b"outbound", "rtc", b"rtc", "sent", b"sent", "stream", b"stream"]) -> None: ...
- @typing_extensions.final
+ @typing.final
class RemoteInboundRtp(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -324,10 +325,10 @@ class RtcStats(google.protobuf.message.Message):
received: global___ReceivedRtpStreamStats | None = ...,
remote_inbound: global___RemoteInboundRtpStreamStats | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["received", b"received", "remote_inbound", b"remote_inbound", "rtc", b"rtc", "stream", b"stream"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["received", b"received", "remote_inbound", b"remote_inbound", "rtc", b"rtc", "stream", b"stream"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["received", b"received", "remote_inbound", b"remote_inbound", "rtc", b"rtc", "stream", b"stream"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["received", b"received", "remote_inbound", b"remote_inbound", "rtc", b"rtc", "stream", b"stream"]) -> None: ...
- @typing_extensions.final
+ @typing.final
class RemoteOutboundRtp(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -351,10 +352,10 @@ class RtcStats(google.protobuf.message.Message):
sent: global___SentRtpStreamStats | None = ...,
remote_outbound: global___RemoteOutboundRtpStreamStats | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["remote_outbound", b"remote_outbound", "rtc", b"rtc", "sent", b"sent", "stream", b"stream"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["remote_outbound", b"remote_outbound", "rtc", b"rtc", "sent", b"sent", "stream", b"stream"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["remote_outbound", b"remote_outbound", "rtc", b"rtc", "sent", b"sent", "stream", b"stream"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["remote_outbound", b"remote_outbound", "rtc", b"rtc", "sent", b"sent", "stream", b"stream"]) -> None: ...
- @typing_extensions.final
+ @typing.final
class MediaSource(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -378,10 +379,10 @@ class RtcStats(google.protobuf.message.Message):
audio: global___AudioSourceStats | None = ...,
video: global___VideoSourceStats | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["audio", b"audio", "rtc", b"rtc", "source", b"source", "video", b"video"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["audio", b"audio", "rtc", b"rtc", "source", b"source", "video", b"video"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["audio", b"audio", "rtc", b"rtc", "source", b"source", "video", b"video"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["audio", b"audio", "rtc", b"rtc", "source", b"source", "video", b"video"]) -> None: ...
- @typing_extensions.final
+ @typing.final
class MediaPlayout(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -397,10 +398,10 @@ class RtcStats(google.protobuf.message.Message):
rtc: global___RtcStatsData | None = ...,
audio_playout: global___AudioPlayoutStats | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["audio_playout", b"audio_playout", "rtc", b"rtc"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["audio_playout", b"audio_playout", "rtc", b"rtc"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["audio_playout", b"audio_playout", "rtc", b"rtc"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["audio_playout", b"audio_playout", "rtc", b"rtc"]) -> None: ...
- @typing_extensions.final
+ @typing.final
class PeerConnection(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -416,10 +417,10 @@ class RtcStats(google.protobuf.message.Message):
rtc: global___RtcStatsData | None = ...,
pc: global___PeerConnectionStats | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["pc", b"pc", "rtc", b"rtc"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["pc", b"pc", "rtc", b"rtc"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["pc", b"pc", "rtc", b"rtc"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["pc", b"pc", "rtc", b"rtc"]) -> None: ...
- @typing_extensions.final
+ @typing.final
class DataChannel(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -435,10 +436,10 @@ class RtcStats(google.protobuf.message.Message):
rtc: global___RtcStatsData | None = ...,
dc: global___DataChannelStats | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["dc", b"dc", "rtc", b"rtc"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["dc", b"dc", "rtc", b"rtc"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["dc", b"dc", "rtc", b"rtc"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["dc", b"dc", "rtc", b"rtc"]) -> None: ...
- @typing_extensions.final
+ @typing.final
class Transport(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -454,10 +455,10 @@ class RtcStats(google.protobuf.message.Message):
rtc: global___RtcStatsData | None = ...,
transport: global___TransportStats | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["rtc", b"rtc", "transport", b"transport"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["rtc", b"rtc", "transport", b"transport"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["rtc", b"rtc", "transport", b"transport"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["rtc", b"rtc", "transport", b"transport"]) -> None: ...
- @typing_extensions.final
+ @typing.final
class CandidatePair(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -473,10 +474,10 @@ class RtcStats(google.protobuf.message.Message):
rtc: global___RtcStatsData | None = ...,
candidate_pair: global___CandidatePairStats | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["candidate_pair", b"candidate_pair", "rtc", b"rtc"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["candidate_pair", b"candidate_pair", "rtc", b"rtc"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["candidate_pair", b"candidate_pair", "rtc", b"rtc"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["candidate_pair", b"candidate_pair", "rtc", b"rtc"]) -> None: ...
- @typing_extensions.final
+ @typing.final
class LocalCandidate(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -492,10 +493,10 @@ class RtcStats(google.protobuf.message.Message):
rtc: global___RtcStatsData | None = ...,
candidate: global___IceCandidateStats | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["candidate", b"candidate", "rtc", b"rtc"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["candidate", b"candidate", "rtc", b"rtc"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["candidate", b"candidate", "rtc", b"rtc"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["candidate", b"candidate", "rtc", b"rtc"]) -> None: ...
- @typing_extensions.final
+ @typing.final
class RemoteCandidate(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -511,10 +512,10 @@ class RtcStats(google.protobuf.message.Message):
rtc: global___RtcStatsData | None = ...,
candidate: global___IceCandidateStats | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["candidate", b"candidate", "rtc", b"rtc"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["candidate", b"candidate", "rtc", b"rtc"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["candidate", b"candidate", "rtc", b"rtc"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["candidate", b"candidate", "rtc", b"rtc"]) -> None: ...
- @typing_extensions.final
+ @typing.final
class Certificate(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -530,10 +531,29 @@ class RtcStats(google.protobuf.message.Message):
rtc: global___RtcStatsData | None = ...,
certificate: global___CertificateStats | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["certificate", b"certificate", "rtc", b"rtc"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["certificate", b"certificate", "rtc", b"rtc"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["certificate", b"certificate", "rtc", b"rtc"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["certificate", b"certificate", "rtc", b"rtc"]) -> None: ...
+
+ @typing.final
+ class Stream(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
- @typing_extensions.final
+ RTC_FIELD_NUMBER: builtins.int
+ STREAM_FIELD_NUMBER: builtins.int
+ @property
+ def rtc(self) -> global___RtcStatsData: ...
+ @property
+ def stream(self) -> global___StreamStats: ...
+ def __init__(
+ self,
+ *,
+ rtc: global___RtcStatsData | None = ...,
+ stream: global___StreamStats | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["rtc", b"rtc", "stream", b"stream"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["rtc", b"rtc", "stream", b"stream"]) -> None: ...
+
+ @typing.final
class Track(google.protobuf.message.Message):
"""Deprecated"""
@@ -557,6 +577,7 @@ class RtcStats(google.protobuf.message.Message):
LOCAL_CANDIDATE_FIELD_NUMBER: builtins.int
REMOTE_CANDIDATE_FIELD_NUMBER: builtins.int
CERTIFICATE_FIELD_NUMBER: builtins.int
+ STREAM_FIELD_NUMBER: builtins.int
TRACK_FIELD_NUMBER: builtins.int
@property
def codec(self) -> global___RtcStats.Codec: ...
@@ -587,6 +608,8 @@ class RtcStats(google.protobuf.message.Message):
@property
def certificate(self) -> global___RtcStats.Certificate: ...
@property
+ def stream(self) -> global___RtcStats.Stream: ...
+ @property
def track(self) -> global___RtcStats.Track: ...
def __init__(
self,
@@ -605,15 +628,16 @@ class RtcStats(google.protobuf.message.Message):
local_candidate: global___RtcStats.LocalCandidate | None = ...,
remote_candidate: global___RtcStats.RemoteCandidate | None = ...,
certificate: global___RtcStats.Certificate | None = ...,
+ stream: global___RtcStats.Stream | None = ...,
track: global___RtcStats.Track | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["candidate_pair", b"candidate_pair", "certificate", b"certificate", "codec", b"codec", "data_channel", b"data_channel", "inbound_rtp", b"inbound_rtp", "local_candidate", b"local_candidate", "media_playout", b"media_playout", "media_source", b"media_source", "outbound_rtp", b"outbound_rtp", "peer_connection", b"peer_connection", "remote_candidate", b"remote_candidate", "remote_inbound_rtp", b"remote_inbound_rtp", "remote_outbound_rtp", b"remote_outbound_rtp", "stats", b"stats", "track", b"track", "transport", b"transport"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["candidate_pair", b"candidate_pair", "certificate", b"certificate", "codec", b"codec", "data_channel", b"data_channel", "inbound_rtp", b"inbound_rtp", "local_candidate", b"local_candidate", "media_playout", b"media_playout", "media_source", b"media_source", "outbound_rtp", b"outbound_rtp", "peer_connection", b"peer_connection", "remote_candidate", b"remote_candidate", "remote_inbound_rtp", b"remote_inbound_rtp", "remote_outbound_rtp", b"remote_outbound_rtp", "stats", b"stats", "track", b"track", "transport", b"transport"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["stats", b"stats"]) -> typing_extensions.Literal["codec", "inbound_rtp", "outbound_rtp", "remote_inbound_rtp", "remote_outbound_rtp", "media_source", "media_playout", "peer_connection", "data_channel", "transport", "candidate_pair", "local_candidate", "remote_candidate", "certificate", "track"] | None: ...
+ def HasField(self, field_name: typing.Literal["candidate_pair", b"candidate_pair", "certificate", b"certificate", "codec", b"codec", "data_channel", b"data_channel", "inbound_rtp", b"inbound_rtp", "local_candidate", b"local_candidate", "media_playout", b"media_playout", "media_source", b"media_source", "outbound_rtp", b"outbound_rtp", "peer_connection", b"peer_connection", "remote_candidate", b"remote_candidate", "remote_inbound_rtp", b"remote_inbound_rtp", "remote_outbound_rtp", b"remote_outbound_rtp", "stats", b"stats", "stream", b"stream", "track", b"track", "transport", b"transport"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["candidate_pair", b"candidate_pair", "certificate", b"certificate", "codec", b"codec", "data_channel", b"data_channel", "inbound_rtp", b"inbound_rtp", "local_candidate", b"local_candidate", "media_playout", b"media_playout", "media_source", b"media_source", "outbound_rtp", b"outbound_rtp", "peer_connection", b"peer_connection", "remote_candidate", b"remote_candidate", "remote_inbound_rtp", b"remote_inbound_rtp", "remote_outbound_rtp", b"remote_outbound_rtp", "stats", b"stats", "stream", b"stream", "track", b"track", "transport", b"transport"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["stats", b"stats"]) -> typing.Literal["codec", "inbound_rtp", "outbound_rtp", "remote_inbound_rtp", "remote_outbound_rtp", "media_source", "media_playout", "peer_connection", "data_channel", "transport", "candidate_pair", "local_candidate", "remote_candidate", "certificate", "stream", "track"] | None: ...
global___RtcStats = RtcStats
-@typing_extensions.final
+@typing.final
class RtcStatsData(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -624,14 +648,15 @@ class RtcStatsData(google.protobuf.message.Message):
def __init__(
self,
*,
- id: builtins.str = ...,
- timestamp: builtins.int = ...,
+ id: builtins.str | None = ...,
+ timestamp: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["id", b"id", "timestamp", b"timestamp"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["id", b"id", "timestamp", b"timestamp"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["id", b"id", "timestamp", b"timestamp"]) -> None: ...
global___RtcStatsData = RtcStatsData
-@typing_extensions.final
+@typing.final
class CodecStats(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -650,18 +675,19 @@ class CodecStats(google.protobuf.message.Message):
def __init__(
self,
*,
- payload_type: builtins.int = ...,
- transport_id: builtins.str = ...,
- mime_type: builtins.str = ...,
- clock_rate: builtins.int = ...,
- channels: builtins.int = ...,
- sdp_fmtp_line: builtins.str = ...,
+ payload_type: builtins.int | None = ...,
+ transport_id: builtins.str | None = ...,
+ mime_type: builtins.str | None = ...,
+ clock_rate: builtins.int | None = ...,
+ channels: builtins.int | None = ...,
+ sdp_fmtp_line: builtins.str | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["channels", b"channels", "clock_rate", b"clock_rate", "mime_type", b"mime_type", "payload_type", b"payload_type", "sdp_fmtp_line", b"sdp_fmtp_line", "transport_id", b"transport_id"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["channels", b"channels", "clock_rate", b"clock_rate", "mime_type", b"mime_type", "payload_type", b"payload_type", "sdp_fmtp_line", b"sdp_fmtp_line", "transport_id", b"transport_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["channels", b"channels", "clock_rate", b"clock_rate", "mime_type", b"mime_type", "payload_type", b"payload_type", "sdp_fmtp_line", b"sdp_fmtp_line", "transport_id", b"transport_id"]) -> None: ...
global___CodecStats = CodecStats
-@typing_extensions.final
+@typing.final
class RtpStreamStats(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -676,16 +702,17 @@ class RtpStreamStats(google.protobuf.message.Message):
def __init__(
self,
*,
- ssrc: builtins.int = ...,
- kind: builtins.str = ...,
- transport_id: builtins.str = ...,
- codec_id: builtins.str = ...,
+ ssrc: builtins.int | None = ...,
+ kind: builtins.str | None = ...,
+ transport_id: builtins.str | None = ...,
+ codec_id: builtins.str | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["codec_id", b"codec_id", "kind", b"kind", "ssrc", b"ssrc", "transport_id", b"transport_id"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["codec_id", b"codec_id", "kind", b"kind", "ssrc", b"ssrc", "transport_id", b"transport_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["codec_id", b"codec_id", "kind", b"kind", "ssrc", b"ssrc", "transport_id", b"transport_id"]) -> None: ...
global___RtpStreamStats = RtpStreamStats
-@typing_extensions.final
+@typing.final
class ReceivedRtpStreamStats(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -698,15 +725,16 @@ class ReceivedRtpStreamStats(google.protobuf.message.Message):
def __init__(
self,
*,
- packets_received: builtins.int = ...,
- packets_lost: builtins.int = ...,
- jitter: builtins.float = ...,
+ packets_received: builtins.int | None = ...,
+ packets_lost: builtins.int | None = ...,
+ jitter: builtins.float | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["jitter", b"jitter", "packets_lost", b"packets_lost", "packets_received", b"packets_received"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["jitter", b"jitter", "packets_lost", b"packets_lost", "packets_received", b"packets_received"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["jitter", b"jitter", "packets_lost", b"packets_lost", "packets_received", b"packets_received"]) -> None: ...
global___ReceivedRtpStreamStats = ReceivedRtpStreamStats
-@typing_extensions.final
+@typing.final
class InboundRtpStreamStats(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -819,65 +847,66 @@ class InboundRtpStreamStats(google.protobuf.message.Message):
def __init__(
self,
*,
- track_identifier: builtins.str = ...,
- mid: builtins.str = ...,
- remote_id: builtins.str = ...,
- frames_decoded: builtins.int = ...,
- key_frames_decoded: builtins.int = ...,
- frames_rendered: builtins.int = ...,
- frames_dropped: builtins.int = ...,
- frame_width: builtins.int = ...,
- frame_height: builtins.int = ...,
- frames_per_second: builtins.float = ...,
- qp_sum: builtins.int = ...,
- total_decode_time: builtins.float = ...,
- total_inter_frame_delay: builtins.float = ...,
- total_squared_inter_frame_delay: builtins.float = ...,
- pause_count: builtins.int = ...,
- total_pause_duration: builtins.float = ...,
- freeze_count: builtins.int = ...,
- total_freeze_duration: builtins.float = ...,
- last_packet_received_timestamp: builtins.float = ...,
- header_bytes_received: builtins.int = ...,
- packets_discarded: builtins.int = ...,
- fec_bytes_received: builtins.int = ...,
- fec_packets_received: builtins.int = ...,
- fec_packets_discarded: builtins.int = ...,
- bytes_received: builtins.int = ...,
- nack_count: builtins.int = ...,
- fir_count: builtins.int = ...,
- pli_count: builtins.int = ...,
- total_processing_delay: builtins.float = ...,
- estimated_playout_timestamp: builtins.float = ...,
- jitter_buffer_delay: builtins.float = ...,
- jitter_buffer_target_delay: builtins.float = ...,
- jitter_buffer_emitted_count: builtins.int = ...,
- jitter_buffer_minimum_delay: builtins.float = ...,
- total_samples_received: builtins.int = ...,
- concealed_samples: builtins.int = ...,
- silent_concealed_samples: builtins.int = ...,
- concealment_events: builtins.int = ...,
- inserted_samples_for_deceleration: builtins.int = ...,
- removed_samples_for_acceleration: builtins.int = ...,
- audio_level: builtins.float = ...,
- total_audio_energy: builtins.float = ...,
- total_samples_duration: builtins.float = ...,
- frames_received: builtins.int = ...,
- decoder_implementation: builtins.str = ...,
- playout_id: builtins.str = ...,
- power_efficient_decoder: builtins.bool = ...,
- frames_assembled_from_multiple_packets: builtins.int = ...,
- total_assembly_time: builtins.float = ...,
- retransmitted_packets_received: builtins.int = ...,
- retransmitted_bytes_received: builtins.int = ...,
- rtx_ssrc: builtins.int = ...,
- fec_ssrc: builtins.int = ...,
+ track_identifier: builtins.str | None = ...,
+ mid: builtins.str | None = ...,
+ remote_id: builtins.str | None = ...,
+ frames_decoded: builtins.int | None = ...,
+ key_frames_decoded: builtins.int | None = ...,
+ frames_rendered: builtins.int | None = ...,
+ frames_dropped: builtins.int | None = ...,
+ frame_width: builtins.int | None = ...,
+ frame_height: builtins.int | None = ...,
+ frames_per_second: builtins.float | None = ...,
+ qp_sum: builtins.int | None = ...,
+ total_decode_time: builtins.float | None = ...,
+ total_inter_frame_delay: builtins.float | None = ...,
+ total_squared_inter_frame_delay: builtins.float | None = ...,
+ pause_count: builtins.int | None = ...,
+ total_pause_duration: builtins.float | None = ...,
+ freeze_count: builtins.int | None = ...,
+ total_freeze_duration: builtins.float | None = ...,
+ last_packet_received_timestamp: builtins.float | None = ...,
+ header_bytes_received: builtins.int | None = ...,
+ packets_discarded: builtins.int | None = ...,
+ fec_bytes_received: builtins.int | None = ...,
+ fec_packets_received: builtins.int | None = ...,
+ fec_packets_discarded: builtins.int | None = ...,
+ bytes_received: builtins.int | None = ...,
+ nack_count: builtins.int | None = ...,
+ fir_count: builtins.int | None = ...,
+ pli_count: builtins.int | None = ...,
+ total_processing_delay: builtins.float | None = ...,
+ estimated_playout_timestamp: builtins.float | None = ...,
+ jitter_buffer_delay: builtins.float | None = ...,
+ jitter_buffer_target_delay: builtins.float | None = ...,
+ jitter_buffer_emitted_count: builtins.int | None = ...,
+ jitter_buffer_minimum_delay: builtins.float | None = ...,
+ total_samples_received: builtins.int | None = ...,
+ concealed_samples: builtins.int | None = ...,
+ silent_concealed_samples: builtins.int | None = ...,
+ concealment_events: builtins.int | None = ...,
+ inserted_samples_for_deceleration: builtins.int | None = ...,
+ removed_samples_for_acceleration: builtins.int | None = ...,
+ audio_level: builtins.float | None = ...,
+ total_audio_energy: builtins.float | None = ...,
+ total_samples_duration: builtins.float | None = ...,
+ frames_received: builtins.int | None = ...,
+ decoder_implementation: builtins.str | None = ...,
+ playout_id: builtins.str | None = ...,
+ power_efficient_decoder: builtins.bool | None = ...,
+ frames_assembled_from_multiple_packets: builtins.int | None = ...,
+ total_assembly_time: builtins.float | None = ...,
+ retransmitted_packets_received: builtins.int | None = ...,
+ retransmitted_bytes_received: builtins.int | None = ...,
+ rtx_ssrc: builtins.int | None = ...,
+ fec_ssrc: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["audio_level", b"audio_level", "bytes_received", b"bytes_received", "concealed_samples", b"concealed_samples", "concealment_events", b"concealment_events", "decoder_implementation", b"decoder_implementation", "estimated_playout_timestamp", b"estimated_playout_timestamp", "fec_bytes_received", b"fec_bytes_received", "fec_packets_discarded", b"fec_packets_discarded", "fec_packets_received", b"fec_packets_received", "fec_ssrc", b"fec_ssrc", "fir_count", b"fir_count", "frame_height", b"frame_height", "frame_width", b"frame_width", "frames_assembled_from_multiple_packets", b"frames_assembled_from_multiple_packets", "frames_decoded", b"frames_decoded", "frames_dropped", b"frames_dropped", "frames_per_second", b"frames_per_second", "frames_received", b"frames_received", "frames_rendered", b"frames_rendered", "freeze_count", b"freeze_count", "header_bytes_received", b"header_bytes_received", "inserted_samples_for_deceleration", b"inserted_samples_for_deceleration", "jitter_buffer_delay", b"jitter_buffer_delay", "jitter_buffer_emitted_count", b"jitter_buffer_emitted_count", "jitter_buffer_minimum_delay", b"jitter_buffer_minimum_delay", "jitter_buffer_target_delay", b"jitter_buffer_target_delay", "key_frames_decoded", b"key_frames_decoded", "last_packet_received_timestamp", b"last_packet_received_timestamp", "mid", b"mid", "nack_count", b"nack_count", "packets_discarded", b"packets_discarded", "pause_count", b"pause_count", "playout_id", b"playout_id", "pli_count", b"pli_count", "power_efficient_decoder", b"power_efficient_decoder", "qp_sum", b"qp_sum", "remote_id", b"remote_id", "removed_samples_for_acceleration", b"removed_samples_for_acceleration", "retransmitted_bytes_received", b"retransmitted_bytes_received", "retransmitted_packets_received", b"retransmitted_packets_received", "rtx_ssrc", b"rtx_ssrc", "silent_concealed_samples", b"silent_concealed_samples", "total_assembly_time", b"total_assembly_time", "total_audio_energy", b"total_audio_energy", "total_decode_time", b"total_decode_time", "total_freeze_duration", b"total_freeze_duration", "total_inter_frame_delay", b"total_inter_frame_delay", "total_pause_duration", b"total_pause_duration", "total_processing_delay", b"total_processing_delay", "total_samples_duration", b"total_samples_duration", "total_samples_received", b"total_samples_received", "total_squared_inter_frame_delay", b"total_squared_inter_frame_delay", "track_identifier", b"track_identifier"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["audio_level", b"audio_level", "bytes_received", b"bytes_received", "concealed_samples", b"concealed_samples", "concealment_events", b"concealment_events", "decoder_implementation", b"decoder_implementation", "estimated_playout_timestamp", b"estimated_playout_timestamp", "fec_bytes_received", b"fec_bytes_received", "fec_packets_discarded", b"fec_packets_discarded", "fec_packets_received", b"fec_packets_received", "fec_ssrc", b"fec_ssrc", "fir_count", b"fir_count", "frame_height", b"frame_height", "frame_width", b"frame_width", "frames_assembled_from_multiple_packets", b"frames_assembled_from_multiple_packets", "frames_decoded", b"frames_decoded", "frames_dropped", b"frames_dropped", "frames_per_second", b"frames_per_second", "frames_received", b"frames_received", "frames_rendered", b"frames_rendered", "freeze_count", b"freeze_count", "header_bytes_received", b"header_bytes_received", "inserted_samples_for_deceleration", b"inserted_samples_for_deceleration", "jitter_buffer_delay", b"jitter_buffer_delay", "jitter_buffer_emitted_count", b"jitter_buffer_emitted_count", "jitter_buffer_minimum_delay", b"jitter_buffer_minimum_delay", "jitter_buffer_target_delay", b"jitter_buffer_target_delay", "key_frames_decoded", b"key_frames_decoded", "last_packet_received_timestamp", b"last_packet_received_timestamp", "mid", b"mid", "nack_count", b"nack_count", "packets_discarded", b"packets_discarded", "pause_count", b"pause_count", "playout_id", b"playout_id", "pli_count", b"pli_count", "power_efficient_decoder", b"power_efficient_decoder", "qp_sum", b"qp_sum", "remote_id", b"remote_id", "removed_samples_for_acceleration", b"removed_samples_for_acceleration", "retransmitted_bytes_received", b"retransmitted_bytes_received", "retransmitted_packets_received", b"retransmitted_packets_received", "rtx_ssrc", b"rtx_ssrc", "silent_concealed_samples", b"silent_concealed_samples", "total_assembly_time", b"total_assembly_time", "total_audio_energy", b"total_audio_energy", "total_decode_time", b"total_decode_time", "total_freeze_duration", b"total_freeze_duration", "total_inter_frame_delay", b"total_inter_frame_delay", "total_pause_duration", b"total_pause_duration", "total_processing_delay", b"total_processing_delay", "total_samples_duration", b"total_samples_duration", "total_samples_received", b"total_samples_received", "total_squared_inter_frame_delay", b"total_squared_inter_frame_delay", "track_identifier", b"track_identifier"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["audio_level", b"audio_level", "bytes_received", b"bytes_received", "concealed_samples", b"concealed_samples", "concealment_events", b"concealment_events", "decoder_implementation", b"decoder_implementation", "estimated_playout_timestamp", b"estimated_playout_timestamp", "fec_bytes_received", b"fec_bytes_received", "fec_packets_discarded", b"fec_packets_discarded", "fec_packets_received", b"fec_packets_received", "fec_ssrc", b"fec_ssrc", "fir_count", b"fir_count", "frame_height", b"frame_height", "frame_width", b"frame_width", "frames_assembled_from_multiple_packets", b"frames_assembled_from_multiple_packets", "frames_decoded", b"frames_decoded", "frames_dropped", b"frames_dropped", "frames_per_second", b"frames_per_second", "frames_received", b"frames_received", "frames_rendered", b"frames_rendered", "freeze_count", b"freeze_count", "header_bytes_received", b"header_bytes_received", "inserted_samples_for_deceleration", b"inserted_samples_for_deceleration", "jitter_buffer_delay", b"jitter_buffer_delay", "jitter_buffer_emitted_count", b"jitter_buffer_emitted_count", "jitter_buffer_minimum_delay", b"jitter_buffer_minimum_delay", "jitter_buffer_target_delay", b"jitter_buffer_target_delay", "key_frames_decoded", b"key_frames_decoded", "last_packet_received_timestamp", b"last_packet_received_timestamp", "mid", b"mid", "nack_count", b"nack_count", "packets_discarded", b"packets_discarded", "pause_count", b"pause_count", "playout_id", b"playout_id", "pli_count", b"pli_count", "power_efficient_decoder", b"power_efficient_decoder", "qp_sum", b"qp_sum", "remote_id", b"remote_id", "removed_samples_for_acceleration", b"removed_samples_for_acceleration", "retransmitted_bytes_received", b"retransmitted_bytes_received", "retransmitted_packets_received", b"retransmitted_packets_received", "rtx_ssrc", b"rtx_ssrc", "silent_concealed_samples", b"silent_concealed_samples", "total_assembly_time", b"total_assembly_time", "total_audio_energy", b"total_audio_energy", "total_decode_time", b"total_decode_time", "total_freeze_duration", b"total_freeze_duration", "total_inter_frame_delay", b"total_inter_frame_delay", "total_pause_duration", b"total_pause_duration", "total_processing_delay", b"total_processing_delay", "total_samples_duration", b"total_samples_duration", "total_samples_received", b"total_samples_received", "total_squared_inter_frame_delay", b"total_squared_inter_frame_delay", "track_identifier", b"track_identifier"]) -> None: ...
global___InboundRtpStreamStats = InboundRtpStreamStats
-@typing_extensions.final
+@typing.final
class SentRtpStreamStats(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -888,18 +917,19 @@ class SentRtpStreamStats(google.protobuf.message.Message):
def __init__(
self,
*,
- packets_sent: builtins.int = ...,
- bytes_sent: builtins.int = ...,
+ packets_sent: builtins.int | None = ...,
+ bytes_sent: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["bytes_sent", b"bytes_sent", "packets_sent", b"packets_sent"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["bytes_sent", b"bytes_sent", "packets_sent", b"packets_sent"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["bytes_sent", b"bytes_sent", "packets_sent", b"packets_sent"]) -> None: ...
global___SentRtpStreamStats = SentRtpStreamStats
-@typing_extensions.final
+@typing.final
class OutboundRtpStreamStats(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
- @typing_extensions.final
+ @typing.final
class QualityLimitationDurationsEntry(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -910,10 +940,11 @@ class OutboundRtpStreamStats(google.protobuf.message.Message):
def __init__(
self,
*,
- key: builtins.str = ...,
- value: builtins.float = ...,
+ key: builtins.str | None = ...,
+ value: builtins.float | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["key", b"key", "value", b"value"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> None: ...
MID_FIELD_NUMBER: builtins.int
MEDIA_SOURCE_ID_FIELD_NUMBER: builtins.int
@@ -944,7 +975,7 @@ class OutboundRtpStreamStats(google.protobuf.message.Message):
ENCODER_IMPLEMENTATION_FIELD_NUMBER: builtins.int
POWER_EFFICIENT_ENCODER_FIELD_NUMBER: builtins.int
ACTIVE_FIELD_NUMBER: builtins.int
- SCALIBILITY_MODE_FIELD_NUMBER: builtins.int
+ SCALABILITY_MODE_FIELD_NUMBER: builtins.int
mid: builtins.str
media_source_id: builtins.str
remote_id: builtins.str
@@ -966,8 +997,6 @@ class OutboundRtpStreamStats(google.protobuf.message.Message):
total_encode_time: builtins.float
total_packet_send_delay: builtins.float
quality_limitation_reason: global___QualityLimitationReason.ValueType
- @property
- def quality_limitation_durations(self) -> google.protobuf.internal.containers.ScalarMap[builtins.str, builtins.float]: ...
quality_limitation_resolution_changes: builtins.int
nack_count: builtins.int
fir_count: builtins.int
@@ -975,46 +1004,49 @@ class OutboundRtpStreamStats(google.protobuf.message.Message):
encoder_implementation: builtins.str
power_efficient_encoder: builtins.bool
active: builtins.bool
- scalibility_mode: builtins.str
+ scalability_mode: builtins.str
+ @property
+ def quality_limitation_durations(self) -> google.protobuf.internal.containers.ScalarMap[builtins.str, builtins.float]: ...
def __init__(
self,
*,
- mid: builtins.str = ...,
- media_source_id: builtins.str = ...,
- remote_id: builtins.str = ...,
- rid: builtins.str = ...,
- header_bytes_sent: builtins.int = ...,
- retransmitted_packets_sent: builtins.int = ...,
- retransmitted_bytes_sent: builtins.int = ...,
- rtx_ssrc: builtins.int = ...,
- target_bitrate: builtins.float = ...,
- total_encoded_bytes_target: builtins.int = ...,
- frame_width: builtins.int = ...,
- frame_height: builtins.int = ...,
- frames_per_second: builtins.float = ...,
- frames_sent: builtins.int = ...,
- huge_frames_sent: builtins.int = ...,
- frames_encoded: builtins.int = ...,
- key_frames_encoded: builtins.int = ...,
- qp_sum: builtins.int = ...,
- total_encode_time: builtins.float = ...,
- total_packet_send_delay: builtins.float = ...,
- quality_limitation_reason: global___QualityLimitationReason.ValueType = ...,
+ mid: builtins.str | None = ...,
+ media_source_id: builtins.str | None = ...,
+ remote_id: builtins.str | None = ...,
+ rid: builtins.str | None = ...,
+ header_bytes_sent: builtins.int | None = ...,
+ retransmitted_packets_sent: builtins.int | None = ...,
+ retransmitted_bytes_sent: builtins.int | None = ...,
+ rtx_ssrc: builtins.int | None = ...,
+ target_bitrate: builtins.float | None = ...,
+ total_encoded_bytes_target: builtins.int | None = ...,
+ frame_width: builtins.int | None = ...,
+ frame_height: builtins.int | None = ...,
+ frames_per_second: builtins.float | None = ...,
+ frames_sent: builtins.int | None = ...,
+ huge_frames_sent: builtins.int | None = ...,
+ frames_encoded: builtins.int | None = ...,
+ key_frames_encoded: builtins.int | None = ...,
+ qp_sum: builtins.int | None = ...,
+ total_encode_time: builtins.float | None = ...,
+ total_packet_send_delay: builtins.float | None = ...,
+ quality_limitation_reason: global___QualityLimitationReason.ValueType | None = ...,
quality_limitation_durations: collections.abc.Mapping[builtins.str, builtins.float] | None = ...,
- quality_limitation_resolution_changes: builtins.int = ...,
- nack_count: builtins.int = ...,
- fir_count: builtins.int = ...,
- pli_count: builtins.int = ...,
- encoder_implementation: builtins.str = ...,
- power_efficient_encoder: builtins.bool = ...,
- active: builtins.bool = ...,
- scalibility_mode: builtins.str = ...,
+ quality_limitation_resolution_changes: builtins.int | None = ...,
+ nack_count: builtins.int | None = ...,
+ fir_count: builtins.int | None = ...,
+ pli_count: builtins.int | None = ...,
+ encoder_implementation: builtins.str | None = ...,
+ power_efficient_encoder: builtins.bool | None = ...,
+ active: builtins.bool | None = ...,
+ scalability_mode: builtins.str | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["active", b"active", "encoder_implementation", b"encoder_implementation", "fir_count", b"fir_count", "frame_height", b"frame_height", "frame_width", b"frame_width", "frames_encoded", b"frames_encoded", "frames_per_second", b"frames_per_second", "frames_sent", b"frames_sent", "header_bytes_sent", b"header_bytes_sent", "huge_frames_sent", b"huge_frames_sent", "key_frames_encoded", b"key_frames_encoded", "media_source_id", b"media_source_id", "mid", b"mid", "nack_count", b"nack_count", "pli_count", b"pli_count", "power_efficient_encoder", b"power_efficient_encoder", "qp_sum", b"qp_sum", "quality_limitation_durations", b"quality_limitation_durations", "quality_limitation_reason", b"quality_limitation_reason", "quality_limitation_resolution_changes", b"quality_limitation_resolution_changes", "remote_id", b"remote_id", "retransmitted_bytes_sent", b"retransmitted_bytes_sent", "retransmitted_packets_sent", b"retransmitted_packets_sent", "rid", b"rid", "rtx_ssrc", b"rtx_ssrc", "scalibility_mode", b"scalibility_mode", "target_bitrate", b"target_bitrate", "total_encode_time", b"total_encode_time", "total_encoded_bytes_target", b"total_encoded_bytes_target", "total_packet_send_delay", b"total_packet_send_delay"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["active", b"active", "encoder_implementation", b"encoder_implementation", "fir_count", b"fir_count", "frame_height", b"frame_height", "frame_width", b"frame_width", "frames_encoded", b"frames_encoded", "frames_per_second", b"frames_per_second", "frames_sent", b"frames_sent", "header_bytes_sent", b"header_bytes_sent", "huge_frames_sent", b"huge_frames_sent", "key_frames_encoded", b"key_frames_encoded", "media_source_id", b"media_source_id", "mid", b"mid", "nack_count", b"nack_count", "pli_count", b"pli_count", "power_efficient_encoder", b"power_efficient_encoder", "qp_sum", b"qp_sum", "quality_limitation_reason", b"quality_limitation_reason", "quality_limitation_resolution_changes", b"quality_limitation_resolution_changes", "remote_id", b"remote_id", "retransmitted_bytes_sent", b"retransmitted_bytes_sent", "retransmitted_packets_sent", b"retransmitted_packets_sent", "rid", b"rid", "rtx_ssrc", b"rtx_ssrc", "scalability_mode", b"scalability_mode", "target_bitrate", b"target_bitrate", "total_encode_time", b"total_encode_time", "total_encoded_bytes_target", b"total_encoded_bytes_target", "total_packet_send_delay", b"total_packet_send_delay"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["active", b"active", "encoder_implementation", b"encoder_implementation", "fir_count", b"fir_count", "frame_height", b"frame_height", "frame_width", b"frame_width", "frames_encoded", b"frames_encoded", "frames_per_second", b"frames_per_second", "frames_sent", b"frames_sent", "header_bytes_sent", b"header_bytes_sent", "huge_frames_sent", b"huge_frames_sent", "key_frames_encoded", b"key_frames_encoded", "media_source_id", b"media_source_id", "mid", b"mid", "nack_count", b"nack_count", "pli_count", b"pli_count", "power_efficient_encoder", b"power_efficient_encoder", "qp_sum", b"qp_sum", "quality_limitation_durations", b"quality_limitation_durations", "quality_limitation_reason", b"quality_limitation_reason", "quality_limitation_resolution_changes", b"quality_limitation_resolution_changes", "remote_id", b"remote_id", "retransmitted_bytes_sent", b"retransmitted_bytes_sent", "retransmitted_packets_sent", b"retransmitted_packets_sent", "rid", b"rid", "rtx_ssrc", b"rtx_ssrc", "scalability_mode", b"scalability_mode", "target_bitrate", b"target_bitrate", "total_encode_time", b"total_encode_time", "total_encoded_bytes_target", b"total_encoded_bytes_target", "total_packet_send_delay", b"total_packet_send_delay"]) -> None: ...
global___OutboundRtpStreamStats = OutboundRtpStreamStats
-@typing_extensions.final
+@typing.final
class RemoteInboundRtpStreamStats(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -1031,17 +1063,18 @@ class RemoteInboundRtpStreamStats(google.protobuf.message.Message):
def __init__(
self,
*,
- local_id: builtins.str = ...,
- round_trip_time: builtins.float = ...,
- total_round_trip_time: builtins.float = ...,
- fraction_lost: builtins.float = ...,
- round_trip_time_measurements: builtins.int = ...,
+ local_id: builtins.str | None = ...,
+ round_trip_time: builtins.float | None = ...,
+ total_round_trip_time: builtins.float | None = ...,
+ fraction_lost: builtins.float | None = ...,
+ round_trip_time_measurements: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["fraction_lost", b"fraction_lost", "local_id", b"local_id", "round_trip_time", b"round_trip_time", "round_trip_time_measurements", b"round_trip_time_measurements", "total_round_trip_time", b"total_round_trip_time"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["fraction_lost", b"fraction_lost", "local_id", b"local_id", "round_trip_time", b"round_trip_time", "round_trip_time_measurements", b"round_trip_time_measurements", "total_round_trip_time", b"total_round_trip_time"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["fraction_lost", b"fraction_lost", "local_id", b"local_id", "round_trip_time", b"round_trip_time", "round_trip_time_measurements", b"round_trip_time_measurements", "total_round_trip_time", b"total_round_trip_time"]) -> None: ...
global___RemoteInboundRtpStreamStats = RemoteInboundRtpStreamStats
-@typing_extensions.final
+@typing.final
class RemoteOutboundRtpStreamStats(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -1060,18 +1093,19 @@ class RemoteOutboundRtpStreamStats(google.protobuf.message.Message):
def __init__(
self,
*,
- local_id: builtins.str = ...,
- remote_timestamp: builtins.float = ...,
- reports_sent: builtins.int = ...,
- round_trip_time: builtins.float = ...,
- total_round_trip_time: builtins.float = ...,
- round_trip_time_measurements: builtins.int = ...,
+ local_id: builtins.str | None = ...,
+ remote_timestamp: builtins.float | None = ...,
+ reports_sent: builtins.int | None = ...,
+ round_trip_time: builtins.float | None = ...,
+ total_round_trip_time: builtins.float | None = ...,
+ round_trip_time_measurements: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["local_id", b"local_id", "remote_timestamp", b"remote_timestamp", "reports_sent", b"reports_sent", "round_trip_time", b"round_trip_time", "round_trip_time_measurements", b"round_trip_time_measurements", "total_round_trip_time", b"total_round_trip_time"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["local_id", b"local_id", "remote_timestamp", b"remote_timestamp", "reports_sent", b"reports_sent", "round_trip_time", b"round_trip_time", "round_trip_time_measurements", b"round_trip_time_measurements", "total_round_trip_time", b"total_round_trip_time"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["local_id", b"local_id", "remote_timestamp", b"remote_timestamp", "reports_sent", b"reports_sent", "round_trip_time", b"round_trip_time", "round_trip_time_measurements", b"round_trip_time_measurements", "total_round_trip_time", b"total_round_trip_time"]) -> None: ...
global___RemoteOutboundRtpStreamStats = RemoteOutboundRtpStreamStats
-@typing_extensions.final
+@typing.final
class MediaSourceStats(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -1082,14 +1116,15 @@ class MediaSourceStats(google.protobuf.message.Message):
def __init__(
self,
*,
- track_identifier: builtins.str = ...,
- kind: builtins.str = ...,
+ track_identifier: builtins.str | None = ...,
+ kind: builtins.str | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["kind", b"kind", "track_identifier", b"track_identifier"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["kind", b"kind", "track_identifier", b"track_identifier"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["kind", b"kind", "track_identifier", b"track_identifier"]) -> None: ...
global___MediaSourceStats = MediaSourceStats
-@typing_extensions.final
+@typing.final
class AudioSourceStats(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -1114,21 +1149,22 @@ class AudioSourceStats(google.protobuf.message.Message):
def __init__(
self,
*,
- audio_level: builtins.float = ...,
- total_audio_energy: builtins.float = ...,
- total_samples_duration: builtins.float = ...,
- echo_return_loss: builtins.float = ...,
- echo_return_loss_enhancement: builtins.float = ...,
- dropped_samples_duration: builtins.float = ...,
- dropped_samples_events: builtins.int = ...,
- total_capture_delay: builtins.float = ...,
- total_samples_captured: builtins.int = ...,
+ audio_level: builtins.float | None = ...,
+ total_audio_energy: builtins.float | None = ...,
+ total_samples_duration: builtins.float | None = ...,
+ echo_return_loss: builtins.float | None = ...,
+ echo_return_loss_enhancement: builtins.float | None = ...,
+ dropped_samples_duration: builtins.float | None = ...,
+ dropped_samples_events: builtins.int | None = ...,
+ total_capture_delay: builtins.float | None = ...,
+ total_samples_captured: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["audio_level", b"audio_level", "dropped_samples_duration", b"dropped_samples_duration", "dropped_samples_events", b"dropped_samples_events", "echo_return_loss", b"echo_return_loss", "echo_return_loss_enhancement", b"echo_return_loss_enhancement", "total_audio_energy", b"total_audio_energy", "total_capture_delay", b"total_capture_delay", "total_samples_captured", b"total_samples_captured", "total_samples_duration", b"total_samples_duration"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["audio_level", b"audio_level", "dropped_samples_duration", b"dropped_samples_duration", "dropped_samples_events", b"dropped_samples_events", "echo_return_loss", b"echo_return_loss", "echo_return_loss_enhancement", b"echo_return_loss_enhancement", "total_audio_energy", b"total_audio_energy", "total_capture_delay", b"total_capture_delay", "total_samples_captured", b"total_samples_captured", "total_samples_duration", b"total_samples_duration"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["audio_level", b"audio_level", "dropped_samples_duration", b"dropped_samples_duration", "dropped_samples_events", b"dropped_samples_events", "echo_return_loss", b"echo_return_loss", "echo_return_loss_enhancement", b"echo_return_loss_enhancement", "total_audio_energy", b"total_audio_energy", "total_capture_delay", b"total_capture_delay", "total_samples_captured", b"total_samples_captured", "total_samples_duration", b"total_samples_duration"]) -> None: ...
global___AudioSourceStats = AudioSourceStats
-@typing_extensions.final
+@typing.final
class VideoSourceStats(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -1143,16 +1179,17 @@ class VideoSourceStats(google.protobuf.message.Message):
def __init__(
self,
*,
- width: builtins.int = ...,
- height: builtins.int = ...,
- frames: builtins.int = ...,
- frames_per_second: builtins.float = ...,
+ width: builtins.int | None = ...,
+ height: builtins.int | None = ...,
+ frames: builtins.int | None = ...,
+ frames_per_second: builtins.float | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["frames", b"frames", "frames_per_second", b"frames_per_second", "height", b"height", "width", b"width"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["frames", b"frames", "frames_per_second", b"frames_per_second", "height", b"height", "width", b"width"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["frames", b"frames", "frames_per_second", b"frames_per_second", "height", b"height", "width", b"width"]) -> None: ...
global___VideoSourceStats = VideoSourceStats
-@typing_extensions.final
+@typing.final
class AudioPlayoutStats(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -1171,18 +1208,19 @@ class AudioPlayoutStats(google.protobuf.message.Message):
def __init__(
self,
*,
- kind: builtins.str = ...,
- synthesized_samples_duration: builtins.float = ...,
- synthesized_samples_events: builtins.int = ...,
- total_samples_duration: builtins.float = ...,
- total_playout_delay: builtins.float = ...,
- total_samples_count: builtins.int = ...,
+ kind: builtins.str | None = ...,
+ synthesized_samples_duration: builtins.float | None = ...,
+ synthesized_samples_events: builtins.int | None = ...,
+ total_samples_duration: builtins.float | None = ...,
+ total_playout_delay: builtins.float | None = ...,
+ total_samples_count: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["kind", b"kind", "synthesized_samples_duration", b"synthesized_samples_duration", "synthesized_samples_events", b"synthesized_samples_events", "total_playout_delay", b"total_playout_delay", "total_samples_count", b"total_samples_count", "total_samples_duration", b"total_samples_duration"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["kind", b"kind", "synthesized_samples_duration", b"synthesized_samples_duration", "synthesized_samples_events", b"synthesized_samples_events", "total_playout_delay", b"total_playout_delay", "total_samples_count", b"total_samples_count", "total_samples_duration", b"total_samples_duration"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["kind", b"kind", "synthesized_samples_duration", b"synthesized_samples_duration", "synthesized_samples_events", b"synthesized_samples_events", "total_playout_delay", b"total_playout_delay", "total_samples_count", b"total_samples_count", "total_samples_duration", b"total_samples_duration"]) -> None: ...
global___AudioPlayoutStats = AudioPlayoutStats
-@typing_extensions.final
+@typing.final
class PeerConnectionStats(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -1193,14 +1231,15 @@ class PeerConnectionStats(google.protobuf.message.Message):
def __init__(
self,
*,
- data_channels_opened: builtins.int = ...,
- data_channels_closed: builtins.int = ...,
+ data_channels_opened: builtins.int | None = ...,
+ data_channels_closed: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["data_channels_closed", b"data_channels_closed", "data_channels_opened", b"data_channels_opened"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["data_channels_closed", b"data_channels_closed", "data_channels_opened", b"data_channels_opened"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["data_channels_closed", b"data_channels_closed", "data_channels_opened", b"data_channels_opened"]) -> None: ...
global___PeerConnectionStats = PeerConnectionStats
-@typing_extensions.final
+@typing.final
class DataChannelStats(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -1223,22 +1262,21 @@ class DataChannelStats(google.protobuf.message.Message):
def __init__(
self,
*,
- label: builtins.str = ...,
- protocol: builtins.str = ...,
- data_channel_identifier: builtins.int = ...,
+ label: builtins.str | None = ...,
+ protocol: builtins.str | None = ...,
+ data_channel_identifier: builtins.int | None = ...,
state: global___DataChannelState.ValueType | None = ...,
- messages_sent: builtins.int = ...,
- bytes_sent: builtins.int = ...,
- messages_received: builtins.int = ...,
- bytes_received: builtins.int = ...,
+ messages_sent: builtins.int | None = ...,
+ bytes_sent: builtins.int | None = ...,
+ messages_received: builtins.int | None = ...,
+ bytes_received: builtins.int | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_state", b"_state", "state", b"state"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_state", b"_state", "bytes_received", b"bytes_received", "bytes_sent", b"bytes_sent", "data_channel_identifier", b"data_channel_identifier", "label", b"label", "messages_received", b"messages_received", "messages_sent", b"messages_sent", "protocol", b"protocol", "state", b"state"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_state", b"_state"]) -> typing_extensions.Literal["state"] | None: ...
+ def HasField(self, field_name: typing.Literal["bytes_received", b"bytes_received", "bytes_sent", b"bytes_sent", "data_channel_identifier", b"data_channel_identifier", "label", b"label", "messages_received", b"messages_received", "messages_sent", b"messages_sent", "protocol", b"protocol", "state", b"state"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["bytes_received", b"bytes_received", "bytes_sent", b"bytes_sent", "data_channel_identifier", b"data_channel_identifier", "label", b"label", "messages_received", b"messages_received", "messages_sent", b"messages_sent", "protocol", b"protocol", "state", b"state"]) -> None: ...
global___DataChannelStats = DataChannelStats
-@typing_extensions.final
+@typing.final
class TransportStats(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -1277,33 +1315,29 @@ class TransportStats(google.protobuf.message.Message):
def __init__(
self,
*,
- packets_sent: builtins.int = ...,
- packets_received: builtins.int = ...,
- bytes_sent: builtins.int = ...,
- bytes_received: builtins.int = ...,
- ice_role: global___IceRole.ValueType = ...,
- ice_local_username_fragment: builtins.str = ...,
+ packets_sent: builtins.int | None = ...,
+ packets_received: builtins.int | None = ...,
+ bytes_sent: builtins.int | None = ...,
+ bytes_received: builtins.int | None = ...,
+ ice_role: global___IceRole.ValueType | None = ...,
+ ice_local_username_fragment: builtins.str | None = ...,
dtls_state: global___DtlsTransportState.ValueType | None = ...,
ice_state: global___IceTransportState.ValueType | None = ...,
- selected_candidate_pair_id: builtins.str = ...,
- local_certificate_id: builtins.str = ...,
- remote_certificate_id: builtins.str = ...,
- tls_version: builtins.str = ...,
- dtls_cipher: builtins.str = ...,
- dtls_role: global___DtlsRole.ValueType = ...,
- srtp_cipher: builtins.str = ...,
- selected_candidate_pair_changes: builtins.int = ...,
+ selected_candidate_pair_id: builtins.str | None = ...,
+ local_certificate_id: builtins.str | None = ...,
+ remote_certificate_id: builtins.str | None = ...,
+ tls_version: builtins.str | None = ...,
+ dtls_cipher: builtins.str | None = ...,
+ dtls_role: global___DtlsRole.ValueType | None = ...,
+ srtp_cipher: builtins.str | None = ...,
+ selected_candidate_pair_changes: builtins.int | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_dtls_state", b"_dtls_state", "_ice_state", b"_ice_state", "dtls_state", b"dtls_state", "ice_state", b"ice_state"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_dtls_state", b"_dtls_state", "_ice_state", b"_ice_state", "bytes_received", b"bytes_received", "bytes_sent", b"bytes_sent", "dtls_cipher", b"dtls_cipher", "dtls_role", b"dtls_role", "dtls_state", b"dtls_state", "ice_local_username_fragment", b"ice_local_username_fragment", "ice_role", b"ice_role", "ice_state", b"ice_state", "local_certificate_id", b"local_certificate_id", "packets_received", b"packets_received", "packets_sent", b"packets_sent", "remote_certificate_id", b"remote_certificate_id", "selected_candidate_pair_changes", b"selected_candidate_pair_changes", "selected_candidate_pair_id", b"selected_candidate_pair_id", "srtp_cipher", b"srtp_cipher", "tls_version", b"tls_version"]) -> None: ...
- @typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_dtls_state", b"_dtls_state"]) -> typing_extensions.Literal["dtls_state"] | None: ...
- @typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_ice_state", b"_ice_state"]) -> typing_extensions.Literal["ice_state"] | None: ...
+ def HasField(self, field_name: typing.Literal["bytes_received", b"bytes_received", "bytes_sent", b"bytes_sent", "dtls_cipher", b"dtls_cipher", "dtls_role", b"dtls_role", "dtls_state", b"dtls_state", "ice_local_username_fragment", b"ice_local_username_fragment", "ice_role", b"ice_role", "ice_state", b"ice_state", "local_certificate_id", b"local_certificate_id", "packets_received", b"packets_received", "packets_sent", b"packets_sent", "remote_certificate_id", b"remote_certificate_id", "selected_candidate_pair_changes", b"selected_candidate_pair_changes", "selected_candidate_pair_id", b"selected_candidate_pair_id", "srtp_cipher", b"srtp_cipher", "tls_version", b"tls_version"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["bytes_received", b"bytes_received", "bytes_sent", b"bytes_sent", "dtls_cipher", b"dtls_cipher", "dtls_role", b"dtls_role", "dtls_state", b"dtls_state", "ice_local_username_fragment", b"ice_local_username_fragment", "ice_role", b"ice_role", "ice_state", b"ice_state", "local_certificate_id", b"local_certificate_id", "packets_received", b"packets_received", "packets_sent", b"packets_sent", "remote_certificate_id", b"remote_certificate_id", "selected_candidate_pair_changes", b"selected_candidate_pair_changes", "selected_candidate_pair_id", b"selected_candidate_pair_id", "srtp_cipher", b"srtp_cipher", "tls_version", b"tls_version"]) -> None: ...
global___TransportStats = TransportStats
-@typing_extensions.final
+@typing.final
class CandidatePairStats(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -1354,36 +1388,35 @@ class CandidatePairStats(google.protobuf.message.Message):
def __init__(
self,
*,
- transport_id: builtins.str = ...,
- local_candidate_id: builtins.str = ...,
- remote_candidate_id: builtins.str = ...,
+ transport_id: builtins.str | None = ...,
+ local_candidate_id: builtins.str | None = ...,
+ remote_candidate_id: builtins.str | None = ...,
state: global___IceCandidatePairState.ValueType | None = ...,
- nominated: builtins.bool = ...,
- packets_sent: builtins.int = ...,
- packets_received: builtins.int = ...,
- bytes_sent: builtins.int = ...,
- bytes_received: builtins.int = ...,
- last_packet_sent_timestamp: builtins.float = ...,
- last_packet_received_timestamp: builtins.float = ...,
- total_round_trip_time: builtins.float = ...,
- current_round_trip_time: builtins.float = ...,
- available_outgoing_bitrate: builtins.float = ...,
- available_incoming_bitrate: builtins.float = ...,
- requests_received: builtins.int = ...,
- requests_sent: builtins.int = ...,
- responses_received: builtins.int = ...,
- responses_sent: builtins.int = ...,
- consent_requests_sent: builtins.int = ...,
- packets_discarded_on_send: builtins.int = ...,
- bytes_discarded_on_send: builtins.int = ...,
+ nominated: builtins.bool | None = ...,
+ packets_sent: builtins.int | None = ...,
+ packets_received: builtins.int | None = ...,
+ bytes_sent: builtins.int | None = ...,
+ bytes_received: builtins.int | None = ...,
+ last_packet_sent_timestamp: builtins.float | None = ...,
+ last_packet_received_timestamp: builtins.float | None = ...,
+ total_round_trip_time: builtins.float | None = ...,
+ current_round_trip_time: builtins.float | None = ...,
+ available_outgoing_bitrate: builtins.float | None = ...,
+ available_incoming_bitrate: builtins.float | None = ...,
+ requests_received: builtins.int | None = ...,
+ requests_sent: builtins.int | None = ...,
+ responses_received: builtins.int | None = ...,
+ responses_sent: builtins.int | None = ...,
+ consent_requests_sent: builtins.int | None = ...,
+ packets_discarded_on_send: builtins.int | None = ...,
+ bytes_discarded_on_send: builtins.int | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_state", b"_state", "state", b"state"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_state", b"_state", "available_incoming_bitrate", b"available_incoming_bitrate", "available_outgoing_bitrate", b"available_outgoing_bitrate", "bytes_discarded_on_send", b"bytes_discarded_on_send", "bytes_received", b"bytes_received", "bytes_sent", b"bytes_sent", "consent_requests_sent", b"consent_requests_sent", "current_round_trip_time", b"current_round_trip_time", "last_packet_received_timestamp", b"last_packet_received_timestamp", "last_packet_sent_timestamp", b"last_packet_sent_timestamp", "local_candidate_id", b"local_candidate_id", "nominated", b"nominated", "packets_discarded_on_send", b"packets_discarded_on_send", "packets_received", b"packets_received", "packets_sent", b"packets_sent", "remote_candidate_id", b"remote_candidate_id", "requests_received", b"requests_received", "requests_sent", b"requests_sent", "responses_received", b"responses_received", "responses_sent", b"responses_sent", "state", b"state", "total_round_trip_time", b"total_round_trip_time", "transport_id", b"transport_id"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_state", b"_state"]) -> typing_extensions.Literal["state"] | None: ...
+ def HasField(self, field_name: typing.Literal["available_incoming_bitrate", b"available_incoming_bitrate", "available_outgoing_bitrate", b"available_outgoing_bitrate", "bytes_discarded_on_send", b"bytes_discarded_on_send", "bytes_received", b"bytes_received", "bytes_sent", b"bytes_sent", "consent_requests_sent", b"consent_requests_sent", "current_round_trip_time", b"current_round_trip_time", "last_packet_received_timestamp", b"last_packet_received_timestamp", "last_packet_sent_timestamp", b"last_packet_sent_timestamp", "local_candidate_id", b"local_candidate_id", "nominated", b"nominated", "packets_discarded_on_send", b"packets_discarded_on_send", "packets_received", b"packets_received", "packets_sent", b"packets_sent", "remote_candidate_id", b"remote_candidate_id", "requests_received", b"requests_received", "requests_sent", b"requests_sent", "responses_received", b"responses_received", "responses_sent", b"responses_sent", "state", b"state", "total_round_trip_time", b"total_round_trip_time", "transport_id", b"transport_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["available_incoming_bitrate", b"available_incoming_bitrate", "available_outgoing_bitrate", b"available_outgoing_bitrate", "bytes_discarded_on_send", b"bytes_discarded_on_send", "bytes_received", b"bytes_received", "bytes_sent", b"bytes_sent", "consent_requests_sent", b"consent_requests_sent", "current_round_trip_time", b"current_round_trip_time", "last_packet_received_timestamp", b"last_packet_received_timestamp", "last_packet_sent_timestamp", b"last_packet_sent_timestamp", "local_candidate_id", b"local_candidate_id", "nominated", b"nominated", "packets_discarded_on_send", b"packets_discarded_on_send", "packets_received", b"packets_received", "packets_sent", b"packets_sent", "remote_candidate_id", b"remote_candidate_id", "requests_received", b"requests_received", "requests_sent", b"requests_sent", "responses_received", b"responses_received", "responses_sent", b"responses_sent", "state", b"state", "total_round_trip_time", b"total_round_trip_time", "transport_id", b"transport_id"]) -> None: ...
global___CandidatePairStats = CandidatePairStats
-@typing_extensions.final
+@typing.final
class IceCandidateStats(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -1416,32 +1449,26 @@ class IceCandidateStats(google.protobuf.message.Message):
def __init__(
self,
*,
- transport_id: builtins.str = ...,
- address: builtins.str = ...,
- port: builtins.int = ...,
- protocol: builtins.str = ...,
+ transport_id: builtins.str | None = ...,
+ address: builtins.str | None = ...,
+ port: builtins.int | None = ...,
+ protocol: builtins.str | None = ...,
candidate_type: global___IceCandidateType.ValueType | None = ...,
- priority: builtins.int = ...,
- url: builtins.str = ...,
+ priority: builtins.int | None = ...,
+ url: builtins.str | None = ...,
relay_protocol: global___IceServerTransportProtocol.ValueType | None = ...,
- foundation: builtins.str = ...,
- related_address: builtins.str = ...,
- related_port: builtins.int = ...,
- username_fragment: builtins.str = ...,
+ foundation: builtins.str | None = ...,
+ related_address: builtins.str | None = ...,
+ related_port: builtins.int | None = ...,
+ username_fragment: builtins.str | None = ...,
tcp_type: global___IceTcpCandidateType.ValueType | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_candidate_type", b"_candidate_type", "_relay_protocol", b"_relay_protocol", "_tcp_type", b"_tcp_type", "candidate_type", b"candidate_type", "relay_protocol", b"relay_protocol", "tcp_type", b"tcp_type"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_candidate_type", b"_candidate_type", "_relay_protocol", b"_relay_protocol", "_tcp_type", b"_tcp_type", "address", b"address", "candidate_type", b"candidate_type", "foundation", b"foundation", "port", b"port", "priority", b"priority", "protocol", b"protocol", "related_address", b"related_address", "related_port", b"related_port", "relay_protocol", b"relay_protocol", "tcp_type", b"tcp_type", "transport_id", b"transport_id", "url", b"url", "username_fragment", b"username_fragment"]) -> None: ...
- @typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_candidate_type", b"_candidate_type"]) -> typing_extensions.Literal["candidate_type"] | None: ...
- @typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_relay_protocol", b"_relay_protocol"]) -> typing_extensions.Literal["relay_protocol"] | None: ...
- @typing.overload
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_tcp_type", b"_tcp_type"]) -> typing_extensions.Literal["tcp_type"] | None: ...
+ def HasField(self, field_name: typing.Literal["address", b"address", "candidate_type", b"candidate_type", "foundation", b"foundation", "port", b"port", "priority", b"priority", "protocol", b"protocol", "related_address", b"related_address", "related_port", b"related_port", "relay_protocol", b"relay_protocol", "tcp_type", b"tcp_type", "transport_id", b"transport_id", "url", b"url", "username_fragment", b"username_fragment"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["address", b"address", "candidate_type", b"candidate_type", "foundation", b"foundation", "port", b"port", "priority", b"priority", "protocol", b"protocol", "related_address", b"related_address", "related_port", b"related_port", "relay_protocol", b"relay_protocol", "tcp_type", b"tcp_type", "transport_id", b"transport_id", "url", b"url", "username_fragment", b"username_fragment"]) -> None: ...
global___IceCandidateStats = IceCandidateStats
-@typing_extensions.final
+@typing.final
class CertificateStats(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -1456,11 +1483,32 @@ class CertificateStats(google.protobuf.message.Message):
def __init__(
self,
*,
- fingerprint: builtins.str = ...,
- fingerprint_algorithm: builtins.str = ...,
- base64_certificate: builtins.str = ...,
- issuer_certificate_id: builtins.str = ...,
+ fingerprint: builtins.str | None = ...,
+ fingerprint_algorithm: builtins.str | None = ...,
+ base64_certificate: builtins.str | None = ...,
+ issuer_certificate_id: builtins.str | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["base64_certificate", b"base64_certificate", "fingerprint", b"fingerprint", "fingerprint_algorithm", b"fingerprint_algorithm", "issuer_certificate_id", b"issuer_certificate_id"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["base64_certificate", b"base64_certificate", "fingerprint", b"fingerprint", "fingerprint_algorithm", b"fingerprint_algorithm", "issuer_certificate_id", b"issuer_certificate_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["base64_certificate", b"base64_certificate", "fingerprint", b"fingerprint", "fingerprint_algorithm", b"fingerprint_algorithm", "issuer_certificate_id", b"issuer_certificate_id"]) -> None: ...
global___CertificateStats = CertificateStats
+
+@typing.final
+class StreamStats(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ID_FIELD_NUMBER: builtins.int
+ STREAM_IDENTIFIER_FIELD_NUMBER: builtins.int
+ id: builtins.str
+ stream_identifier: builtins.str
+ """required int64 timestamp = 3;"""
+ def __init__(
+ self,
+ *,
+ id: builtins.str | None = ...,
+ stream_identifier: builtins.str | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["id", b"id", "stream_identifier", b"stream_identifier"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["id", b"id", "stream_identifier", b"stream_identifier"]) -> None: ...
+
+global___StreamStats = StreamStats
diff --git a/livekit-rtc/livekit/rtc/_proto/track_pb2.py b/livekit-rtc/livekit/rtc/_proto/track_pb2.py
index 5e483bc5..562a267c 100644
--- a/livekit-rtc/livekit/rtc/_proto/track_pb2.py
+++ b/livekit-rtc/livekit/rtc/_proto/track_pb2.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: track.proto
-# Protobuf Python Version: 4.25.3
+# Protobuf Python Version: 4.25.1
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
@@ -17,7 +17,7 @@
from . import stats_pb2 as stats__pb2
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0btrack.proto\x12\rlivekit.proto\x1a\ne2ee.proto\x1a\x0chandle.proto\x1a\x0bstats.proto\">\n\x17\x43reateVideoTrackRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x15\n\rsource_handle\x18\x02 \x01(\x04\"D\n\x18\x43reateVideoTrackResponse\x12(\n\x05track\x18\x01 \x01(\x0b\x32\x19.livekit.proto.OwnedTrack\">\n\x17\x43reateAudioTrackRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x15\n\rsource_handle\x18\x02 \x01(\x04\"D\n\x18\x43reateAudioTrackResponse\x12(\n\x05track\x18\x01 \x01(\x0b\x32\x19.livekit.proto.OwnedTrack\"\'\n\x0fGetStatsRequest\x12\x14\n\x0ctrack_handle\x18\x01 \x01(\x04\"$\n\x10GetStatsResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x01(\x04\"j\n\x10GetStatsCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x01(\x04\x12\x12\n\x05\x65rror\x18\x02 \x01(\tH\x00\x88\x01\x01\x12&\n\x05stats\x18\x03 \x03(\x0b\x32\x17.livekit.proto.RtcStatsB\x08\n\x06_error\"\x0c\n\nTrackEvent\"\xa3\x02\n\x14TrackPublicationInfo\x12\x0b\n\x03sid\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12&\n\x04kind\x18\x03 \x01(\x0e\x32\x18.livekit.proto.TrackKind\x12*\n\x06source\x18\x04 \x01(\x0e\x32\x1a.livekit.proto.TrackSource\x12\x13\n\x0bsimulcasted\x18\x05 \x01(\x08\x12\r\n\x05width\x18\x06 \x01(\r\x12\x0e\n\x06height\x18\x07 \x01(\r\x12\x11\n\tmime_type\x18\x08 \x01(\t\x12\r\n\x05muted\x18\t \x01(\x08\x12\x0e\n\x06remote\x18\n \x01(\x08\x12\x36\n\x0f\x65ncryption_type\x18\x0b \x01(\x0e\x32\x1d.livekit.proto.EncryptionType\"y\n\x15OwnedTrackPublication\x12-\n\x06handle\x18\x01 \x01(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12\x31\n\x04info\x18\x02 \x01(\x0b\x32#.livekit.proto.TrackPublicationInfo\"\x9f\x01\n\tTrackInfo\x12\x0b\n\x03sid\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12&\n\x04kind\x18\x03 \x01(\x0e\x32\x18.livekit.proto.TrackKind\x12\x30\n\x0cstream_state\x18\x04 \x01(\x0e\x32\x1a.livekit.proto.StreamState\x12\r\n\x05muted\x18\x05 \x01(\x08\x12\x0e\n\x06remote\x18\x06 \x01(\x08\"c\n\nOwnedTrack\x12-\n\x06handle\x18\x01 \x01(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12&\n\x04info\x18\x02 \x01(\x0b\x32\x18.livekit.proto.TrackInfo*=\n\tTrackKind\x12\x10\n\x0cKIND_UNKNOWN\x10\x00\x12\x0e\n\nKIND_AUDIO\x10\x01\x12\x0e\n\nKIND_VIDEO\x10\x02*\x81\x01\n\x0bTrackSource\x12\x12\n\x0eSOURCE_UNKNOWN\x10\x00\x12\x11\n\rSOURCE_CAMERA\x10\x01\x12\x15\n\x11SOURCE_MICROPHONE\x10\x02\x12\x16\n\x12SOURCE_SCREENSHARE\x10\x03\x12\x1c\n\x18SOURCE_SCREENSHARE_AUDIO\x10\x04*D\n\x0bStreamState\x12\x11\n\rSTATE_UNKNOWN\x10\x00\x12\x10\n\x0cSTATE_ACTIVE\x10\x01\x12\x10\n\x0cSTATE_PAUSED\x10\x02\x42\x10\xaa\x02\rLiveKit.Protob\x06proto3')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0btrack.proto\x12\rlivekit.proto\x1a\ne2ee.proto\x1a\x0chandle.proto\x1a\x0bstats.proto\">\n\x17\x43reateVideoTrackRequest\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x15\n\rsource_handle\x18\x02 \x02(\x04\"D\n\x18\x43reateVideoTrackResponse\x12(\n\x05track\x18\x01 \x02(\x0b\x32\x19.livekit.proto.OwnedTrack\">\n\x17\x43reateAudioTrackRequest\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x15\n\rsource_handle\x18\x02 \x02(\x04\"D\n\x18\x43reateAudioTrackResponse\x12(\n\x05track\x18\x01 \x02(\x0b\x32\x19.livekit.proto.OwnedTrack\"A\n\x0fGetStatsRequest\x12\x14\n\x0ctrack_handle\x18\x01 \x02(\x04\x12\x18\n\x10request_async_id\x18\x02 \x01(\x04\"$\n\x10GetStatsResponse\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\"[\n\x10GetStatsCallback\x12\x10\n\x08\x61sync_id\x18\x01 \x02(\x04\x12\r\n\x05\x65rror\x18\x02 \x01(\t\x12&\n\x05stats\x18\x03 \x03(\x0b\x32\x17.livekit.proto.RtcStats\"\x0c\n\nTrackEvent\"\xa3\x03\n\x14TrackPublicationInfo\x12\x0b\n\x03sid\x18\x01 \x02(\t\x12\x0c\n\x04name\x18\x02 \x02(\t\x12&\n\x04kind\x18\x03 \x02(\x0e\x32\x18.livekit.proto.TrackKind\x12*\n\x06source\x18\x04 \x02(\x0e\x32\x1a.livekit.proto.TrackSource\x12\x13\n\x0bsimulcasted\x18\x05 \x02(\x08\x12\r\n\x05width\x18\x06 \x02(\r\x12\x0e\n\x06height\x18\x07 \x02(\r\x12\x11\n\tmime_type\x18\x08 \x02(\t\x12\r\n\x05muted\x18\t \x02(\x08\x12\x0e\n\x06remote\x18\n \x02(\x08\x12\x36\n\x0f\x65ncryption_type\x18\x0b \x02(\x0e\x32\x1d.livekit.proto.EncryptionType\x12\x38\n\x0e\x61udio_features\x18\x0c \x03(\x0e\x32 .livekit.proto.AudioTrackFeature\x12\x44\n\x17packet_trailer_features\x18\r \x03(\x0e\x32#.livekit.proto.PacketTrailerFeature\"y\n\x15OwnedTrackPublication\x12-\n\x06handle\x18\x01 \x02(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12\x31\n\x04info\x18\x02 \x02(\x0b\x32#.livekit.proto.TrackPublicationInfo\"\x9f\x01\n\tTrackInfo\x12\x0b\n\x03sid\x18\x01 \x02(\t\x12\x0c\n\x04name\x18\x02 \x02(\t\x12&\n\x04kind\x18\x03 \x02(\x0e\x32\x18.livekit.proto.TrackKind\x12\x30\n\x0cstream_state\x18\x04 \x02(\x0e\x32\x1a.livekit.proto.StreamState\x12\r\n\x05muted\x18\x05 \x02(\x08\x12\x0e\n\x06remote\x18\x06 \x02(\x08\"c\n\nOwnedTrack\x12-\n\x06handle\x18\x01 \x02(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12&\n\x04info\x18\x02 \x02(\x0b\x32\x18.livekit.proto.TrackInfo\";\n\x15LocalTrackMuteRequest\x12\x14\n\x0ctrack_handle\x18\x01 \x02(\x04\x12\x0c\n\x04mute\x18\x02 \x02(\x08\"\'\n\x16LocalTrackMuteResponse\x12\r\n\x05muted\x18\x01 \x02(\x08\"A\n\x18\x45nableRemoteTrackRequest\x12\x14\n\x0ctrack_handle\x18\x01 \x02(\x04\x12\x0f\n\x07\x65nabled\x18\x02 \x02(\x08\",\n\x19\x45nableRemoteTrackResponse\x12\x0f\n\x07\x65nabled\x18\x01 \x02(\x08\"\xac\x01\n&SetTrackSubscriptionPermissionsRequest\x12 \n\x18local_participant_handle\x18\x01 \x02(\x04\x12 \n\x18\x61ll_participants_allowed\x18\x02 \x02(\x08\x12>\n\x0bpermissions\x18\x03 \x03(\x0b\x32).livekit.proto.ParticipantTrackPermission\"i\n\x1aParticipantTrackPermission\x12\x1c\n\x14participant_identity\x18\x01 \x02(\t\x12\x11\n\tallow_all\x18\x02 \x01(\x08\x12\x1a\n\x12\x61llowed_track_sids\x18\x03 \x03(\t\")\n\'SetTrackSubscriptionPermissionsResponse*=\n\tTrackKind\x12\x10\n\x0cKIND_UNKNOWN\x10\x00\x12\x0e\n\nKIND_AUDIO\x10\x01\x12\x0e\n\nKIND_VIDEO\x10\x02*\x81\x01\n\x0bTrackSource\x12\x12\n\x0eSOURCE_UNKNOWN\x10\x00\x12\x11\n\rSOURCE_CAMERA\x10\x01\x12\x15\n\x11SOURCE_MICROPHONE\x10\x02\x12\x16\n\x12SOURCE_SCREENSHARE\x10\x03\x12\x1c\n\x18SOURCE_SCREENSHARE_AUDIO\x10\x04*D\n\x0bStreamState\x12\x11\n\rSTATE_UNKNOWN\x10\x00\x12\x10\n\x0cSTATE_ACTIVE\x10\x01\x12\x10\n\x0cSTATE_PAUSED\x10\x02*\xbd\x01\n\x11\x41udioTrackFeature\x12\r\n\tTF_STEREO\x10\x00\x12\r\n\tTF_NO_DTX\x10\x01\x12\x18\n\x14TF_AUTO_GAIN_CONTROL\x10\x02\x12\x18\n\x14TF_ECHO_CANCELLATION\x10\x03\x12\x18\n\x14TF_NOISE_SUPPRESSION\x10\x04\x12\"\n\x1eTF_ENHANCED_NOISE_CANCELLATION\x10\x05\x12\x18\n\x14TF_PRECONNECT_BUFFER\x10\x06*@\n\x14PacketTrailerFeature\x12\x16\n\x12PTF_USER_TIMESTAMP\x10\x00\x12\x10\n\x0cPTF_FRAME_ID\x10\x01\x42\x10\xaa\x02\rLiveKit.Proto')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -25,12 +25,16 @@
if _descriptor._USE_C_DESCRIPTORS == False:
_globals['DESCRIPTOR']._options = None
_globals['DESCRIPTOR']._serialized_options = b'\252\002\rLiveKit.Proto'
- _globals['_TRACKKIND']._serialized_start=1218
- _globals['_TRACKKIND']._serialized_end=1279
- _globals['_TRACKSOURCE']._serialized_start=1282
- _globals['_TRACKSOURCE']._serialized_end=1411
- _globals['_STREAMSTATE']._serialized_start=1413
- _globals['_STREAMSTATE']._serialized_end=1481
+ _globals['_TRACKKIND']._serialized_start=1897
+ _globals['_TRACKKIND']._serialized_end=1958
+ _globals['_TRACKSOURCE']._serialized_start=1961
+ _globals['_TRACKSOURCE']._serialized_end=2090
+ _globals['_STREAMSTATE']._serialized_start=2092
+ _globals['_STREAMSTATE']._serialized_end=2160
+ _globals['_AUDIOTRACKFEATURE']._serialized_start=2163
+ _globals['_AUDIOTRACKFEATURE']._serialized_end=2352
+ _globals['_PACKETTRAILERFEATURE']._serialized_start=2354
+ _globals['_PACKETTRAILERFEATURE']._serialized_end=2418
_globals['_CREATEVIDEOTRACKREQUEST']._serialized_start=69
_globals['_CREATEVIDEOTRACKREQUEST']._serialized_end=131
_globals['_CREATEVIDEOTRACKRESPONSE']._serialized_start=133
@@ -40,19 +44,33 @@
_globals['_CREATEAUDIOTRACKRESPONSE']._serialized_start=267
_globals['_CREATEAUDIOTRACKRESPONSE']._serialized_end=335
_globals['_GETSTATSREQUEST']._serialized_start=337
- _globals['_GETSTATSREQUEST']._serialized_end=376
- _globals['_GETSTATSRESPONSE']._serialized_start=378
- _globals['_GETSTATSRESPONSE']._serialized_end=414
- _globals['_GETSTATSCALLBACK']._serialized_start=416
- _globals['_GETSTATSCALLBACK']._serialized_end=522
- _globals['_TRACKEVENT']._serialized_start=524
- _globals['_TRACKEVENT']._serialized_end=536
- _globals['_TRACKPUBLICATIONINFO']._serialized_start=539
- _globals['_TRACKPUBLICATIONINFO']._serialized_end=830
- _globals['_OWNEDTRACKPUBLICATION']._serialized_start=832
- _globals['_OWNEDTRACKPUBLICATION']._serialized_end=953
- _globals['_TRACKINFO']._serialized_start=956
- _globals['_TRACKINFO']._serialized_end=1115
- _globals['_OWNEDTRACK']._serialized_start=1117
- _globals['_OWNEDTRACK']._serialized_end=1216
+ _globals['_GETSTATSREQUEST']._serialized_end=402
+ _globals['_GETSTATSRESPONSE']._serialized_start=404
+ _globals['_GETSTATSRESPONSE']._serialized_end=440
+ _globals['_GETSTATSCALLBACK']._serialized_start=442
+ _globals['_GETSTATSCALLBACK']._serialized_end=533
+ _globals['_TRACKEVENT']._serialized_start=535
+ _globals['_TRACKEVENT']._serialized_end=547
+ _globals['_TRACKPUBLICATIONINFO']._serialized_start=550
+ _globals['_TRACKPUBLICATIONINFO']._serialized_end=969
+ _globals['_OWNEDTRACKPUBLICATION']._serialized_start=971
+ _globals['_OWNEDTRACKPUBLICATION']._serialized_end=1092
+ _globals['_TRACKINFO']._serialized_start=1095
+ _globals['_TRACKINFO']._serialized_end=1254
+ _globals['_OWNEDTRACK']._serialized_start=1256
+ _globals['_OWNEDTRACK']._serialized_end=1355
+ _globals['_LOCALTRACKMUTEREQUEST']._serialized_start=1357
+ _globals['_LOCALTRACKMUTEREQUEST']._serialized_end=1416
+ _globals['_LOCALTRACKMUTERESPONSE']._serialized_start=1418
+ _globals['_LOCALTRACKMUTERESPONSE']._serialized_end=1457
+ _globals['_ENABLEREMOTETRACKREQUEST']._serialized_start=1459
+ _globals['_ENABLEREMOTETRACKREQUEST']._serialized_end=1524
+ _globals['_ENABLEREMOTETRACKRESPONSE']._serialized_start=1526
+ _globals['_ENABLEREMOTETRACKRESPONSE']._serialized_end=1570
+ _globals['_SETTRACKSUBSCRIPTIONPERMISSIONSREQUEST']._serialized_start=1573
+ _globals['_SETTRACKSUBSCRIPTIONPERMISSIONSREQUEST']._serialized_end=1745
+ _globals['_PARTICIPANTTRACKPERMISSION']._serialized_start=1747
+ _globals['_PARTICIPANTTRACKPERMISSION']._serialized_end=1852
+ _globals['_SETTRACKSUBSCRIPTIONPERMISSIONSRESPONSE']._serialized_start=1854
+ _globals['_SETTRACKSUBSCRIPTIONPERMISSIONSRESPONSE']._serialized_end=1895
# @@protoc_insertion_point(module_scope)
diff --git a/livekit-rtc/livekit/rtc/_proto/track_pb2.pyi b/livekit-rtc/livekit/rtc/_proto/track_pb2.pyi
index 2a687298..6b81c596 100644
--- a/livekit-rtc/livekit/rtc/_proto/track_pb2.pyi
+++ b/livekit-rtc/livekit/rtc/_proto/track_pb2.pyi
@@ -1,7 +1,7 @@
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
-Copyright 2023 LiveKit, Inc.
+Copyright 2025 LiveKit, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
+
import builtins
import collections.abc
from . import e2ee_pb2
@@ -89,7 +90,49 @@ STATE_ACTIVE: StreamState.ValueType # 1
STATE_PAUSED: StreamState.ValueType # 2
global___StreamState = StreamState
-@typing_extensions.final
+class _AudioTrackFeature:
+ ValueType = typing.NewType("ValueType", builtins.int)
+ V: typing_extensions.TypeAlias = ValueType
+
+class _AudioTrackFeatureEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_AudioTrackFeature.ValueType], builtins.type):
+ DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
+ TF_STEREO: _AudioTrackFeature.ValueType # 0
+ TF_NO_DTX: _AudioTrackFeature.ValueType # 1
+ TF_AUTO_GAIN_CONTROL: _AudioTrackFeature.ValueType # 2
+ TF_ECHO_CANCELLATION: _AudioTrackFeature.ValueType # 3
+ TF_NOISE_SUPPRESSION: _AudioTrackFeature.ValueType # 4
+ TF_ENHANCED_NOISE_CANCELLATION: _AudioTrackFeature.ValueType # 5
+ TF_PRECONNECT_BUFFER: _AudioTrackFeature.ValueType # 6
+ """client will buffer audio once available and send it to the server via bytes stream once connected"""
+
+class AudioTrackFeature(_AudioTrackFeature, metaclass=_AudioTrackFeatureEnumTypeWrapper): ...
+
+TF_STEREO: AudioTrackFeature.ValueType # 0
+TF_NO_DTX: AudioTrackFeature.ValueType # 1
+TF_AUTO_GAIN_CONTROL: AudioTrackFeature.ValueType # 2
+TF_ECHO_CANCELLATION: AudioTrackFeature.ValueType # 3
+TF_NOISE_SUPPRESSION: AudioTrackFeature.ValueType # 4
+TF_ENHANCED_NOISE_CANCELLATION: AudioTrackFeature.ValueType # 5
+TF_PRECONNECT_BUFFER: AudioTrackFeature.ValueType # 6
+"""client will buffer audio once available and send it to the server via bytes stream once connected"""
+global___AudioTrackFeature = AudioTrackFeature
+
+class _PacketTrailerFeature:
+ ValueType = typing.NewType("ValueType", builtins.int)
+ V: typing_extensions.TypeAlias = ValueType
+
+class _PacketTrailerFeatureEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_PacketTrailerFeature.ValueType], builtins.type):
+ DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
+ PTF_USER_TIMESTAMP: _PacketTrailerFeature.ValueType # 0
+ PTF_FRAME_ID: _PacketTrailerFeature.ValueType # 1
+
+class PacketTrailerFeature(_PacketTrailerFeature, metaclass=_PacketTrailerFeatureEnumTypeWrapper): ...
+
+PTF_USER_TIMESTAMP: PacketTrailerFeature.ValueType # 0
+PTF_FRAME_ID: PacketTrailerFeature.ValueType # 1
+global___PacketTrailerFeature = PacketTrailerFeature
+
+@typing.final
class CreateVideoTrackRequest(google.protobuf.message.Message):
"""Create a new VideoTrack from a VideoSource"""
@@ -102,14 +145,15 @@ class CreateVideoTrackRequest(google.protobuf.message.Message):
def __init__(
self,
*,
- name: builtins.str = ...,
- source_handle: builtins.int = ...,
+ name: builtins.str | None = ...,
+ source_handle: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["name", b"name", "source_handle", b"source_handle"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["name", b"name", "source_handle", b"source_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["name", b"name", "source_handle", b"source_handle"]) -> None: ...
global___CreateVideoTrackRequest = CreateVideoTrackRequest
-@typing_extensions.final
+@typing.final
class CreateVideoTrackResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -121,12 +165,12 @@ class CreateVideoTrackResponse(google.protobuf.message.Message):
*,
track: global___OwnedTrack | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["track", b"track"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["track", b"track"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["track", b"track"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["track", b"track"]) -> None: ...
global___CreateVideoTrackResponse = CreateVideoTrackResponse
-@typing_extensions.final
+@typing.final
class CreateAudioTrackRequest(google.protobuf.message.Message):
"""Create a new AudioTrack from a AudioSource"""
@@ -139,14 +183,15 @@ class CreateAudioTrackRequest(google.protobuf.message.Message):
def __init__(
self,
*,
- name: builtins.str = ...,
- source_handle: builtins.int = ...,
+ name: builtins.str | None = ...,
+ source_handle: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["name", b"name", "source_handle", b"source_handle"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["name", b"name", "source_handle", b"source_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["name", b"name", "source_handle", b"source_handle"]) -> None: ...
global___CreateAudioTrackRequest = CreateAudioTrackRequest
-@typing_extensions.final
+@typing.final
class CreateAudioTrackResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -158,27 +203,31 @@ class CreateAudioTrackResponse(google.protobuf.message.Message):
*,
track: global___OwnedTrack | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["track", b"track"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["track", b"track"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["track", b"track"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["track", b"track"]) -> None: ...
global___CreateAudioTrackResponse = CreateAudioTrackResponse
-@typing_extensions.final
+@typing.final
class GetStatsRequest(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
TRACK_HANDLE_FIELD_NUMBER: builtins.int
+ REQUEST_ASYNC_ID_FIELD_NUMBER: builtins.int
track_handle: builtins.int
+ request_async_id: builtins.int
def __init__(
self,
*,
- track_handle: builtins.int = ...,
+ track_handle: builtins.int | None = ...,
+ request_async_id: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["track_handle", b"track_handle"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["request_async_id", b"request_async_id", "track_handle", b"track_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["request_async_id", b"request_async_id", "track_handle", b"track_handle"]) -> None: ...
global___GetStatsRequest = GetStatsRequest
-@typing_extensions.final
+@typing.final
class GetStatsResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -187,13 +236,14 @@ class GetStatsResponse(google.protobuf.message.Message):
def __init__(
self,
*,
- async_id: builtins.int = ...,
+ async_id: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["async_id", b"async_id"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id"]) -> None: ...
global___GetStatsResponse = GetStatsResponse
-@typing_extensions.final
+@typing.final
class GetStatsCallback(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -207,17 +257,16 @@ class GetStatsCallback(google.protobuf.message.Message):
def __init__(
self,
*,
- async_id: builtins.int = ...,
+ async_id: builtins.int | None = ...,
error: builtins.str | None = ...,
stats: collections.abc.Iterable[stats_pb2.RtcStats] | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_error", b"_error", "error", b"error"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_error", b"_error", "async_id", b"async_id", "error", b"error", "stats", b"stats"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_error", b"_error"]) -> typing_extensions.Literal["error"] | None: ...
+ def HasField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["async_id", b"async_id", "error", b"error", "stats", b"stats"]) -> None: ...
global___GetStatsCallback = GetStatsCallback
-@typing_extensions.final
+@typing.final
class TrackEvent(google.protobuf.message.Message):
"""
Track
@@ -231,7 +280,7 @@ class TrackEvent(google.protobuf.message.Message):
global___TrackEvent = TrackEvent
-@typing_extensions.final
+@typing.final
class TrackPublicationInfo(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -246,6 +295,8 @@ class TrackPublicationInfo(google.protobuf.message.Message):
MUTED_FIELD_NUMBER: builtins.int
REMOTE_FIELD_NUMBER: builtins.int
ENCRYPTION_TYPE_FIELD_NUMBER: builtins.int
+ AUDIO_FEATURES_FIELD_NUMBER: builtins.int
+ PACKET_TRAILER_FEATURES_FIELD_NUMBER: builtins.int
sid: builtins.str
name: builtins.str
kind: global___TrackKind.ValueType
@@ -257,26 +308,33 @@ class TrackPublicationInfo(google.protobuf.message.Message):
muted: builtins.bool
remote: builtins.bool
encryption_type: e2ee_pb2.EncryptionType.ValueType
+ @property
+ def audio_features(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[global___AudioTrackFeature.ValueType]: ...
+ @property
+ def packet_trailer_features(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[global___PacketTrailerFeature.ValueType]: ...
def __init__(
self,
*,
- sid: builtins.str = ...,
- name: builtins.str = ...,
- kind: global___TrackKind.ValueType = ...,
- source: global___TrackSource.ValueType = ...,
- simulcasted: builtins.bool = ...,
- width: builtins.int = ...,
- height: builtins.int = ...,
- mime_type: builtins.str = ...,
- muted: builtins.bool = ...,
- remote: builtins.bool = ...,
- encryption_type: e2ee_pb2.EncryptionType.ValueType = ...,
+ sid: builtins.str | None = ...,
+ name: builtins.str | None = ...,
+ kind: global___TrackKind.ValueType | None = ...,
+ source: global___TrackSource.ValueType | None = ...,
+ simulcasted: builtins.bool | None = ...,
+ width: builtins.int | None = ...,
+ height: builtins.int | None = ...,
+ mime_type: builtins.str | None = ...,
+ muted: builtins.bool | None = ...,
+ remote: builtins.bool | None = ...,
+ encryption_type: e2ee_pb2.EncryptionType.ValueType | None = ...,
+ audio_features: collections.abc.Iterable[global___AudioTrackFeature.ValueType] | None = ...,
+ packet_trailer_features: collections.abc.Iterable[global___PacketTrailerFeature.ValueType] | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["encryption_type", b"encryption_type", "height", b"height", "kind", b"kind", "mime_type", b"mime_type", "muted", b"muted", "name", b"name", "remote", b"remote", "sid", b"sid", "simulcasted", b"simulcasted", "source", b"source", "width", b"width"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["encryption_type", b"encryption_type", "height", b"height", "kind", b"kind", "mime_type", b"mime_type", "muted", b"muted", "name", b"name", "remote", b"remote", "sid", b"sid", "simulcasted", b"simulcasted", "source", b"source", "width", b"width"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["audio_features", b"audio_features", "encryption_type", b"encryption_type", "height", b"height", "kind", b"kind", "mime_type", b"mime_type", "muted", b"muted", "name", b"name", "packet_trailer_features", b"packet_trailer_features", "remote", b"remote", "sid", b"sid", "simulcasted", b"simulcasted", "source", b"source", "width", b"width"]) -> None: ...
global___TrackPublicationInfo = TrackPublicationInfo
-@typing_extensions.final
+@typing.final
class OwnedTrackPublication(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -292,12 +350,12 @@ class OwnedTrackPublication(google.protobuf.message.Message):
handle: handle_pb2.FfiOwnedHandle | None = ...,
info: global___TrackPublicationInfo | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["handle", b"handle", "info", b"info"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["handle", b"handle", "info", b"info"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> None: ...
global___OwnedTrackPublication = OwnedTrackPublication
-@typing_extensions.final
+@typing.final
class TrackInfo(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -316,18 +374,19 @@ class TrackInfo(google.protobuf.message.Message):
def __init__(
self,
*,
- sid: builtins.str = ...,
- name: builtins.str = ...,
- kind: global___TrackKind.ValueType = ...,
- stream_state: global___StreamState.ValueType = ...,
- muted: builtins.bool = ...,
- remote: builtins.bool = ...,
+ sid: builtins.str | None = ...,
+ name: builtins.str | None = ...,
+ kind: global___TrackKind.ValueType | None = ...,
+ stream_state: global___StreamState.ValueType | None = ...,
+ muted: builtins.bool | None = ...,
+ remote: builtins.bool | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["kind", b"kind", "muted", b"muted", "name", b"name", "remote", b"remote", "sid", b"sid", "stream_state", b"stream_state"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["kind", b"kind", "muted", b"muted", "name", b"name", "remote", b"remote", "sid", b"sid", "stream_state", b"stream_state"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["kind", b"kind", "muted", b"muted", "name", b"name", "remote", b"remote", "sid", b"sid", "stream_state", b"stream_state"]) -> None: ...
global___TrackInfo = TrackInfo
-@typing_extensions.final
+@typing.final
class OwnedTrack(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -343,7 +402,141 @@ class OwnedTrack(google.protobuf.message.Message):
handle: handle_pb2.FfiOwnedHandle | None = ...,
info: global___TrackInfo | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["handle", b"handle", "info", b"info"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["handle", b"handle", "info", b"info"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> None: ...
global___OwnedTrack = OwnedTrack
+
+@typing.final
+class LocalTrackMuteRequest(google.protobuf.message.Message):
+ """Mute/UnMute a track"""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ TRACK_HANDLE_FIELD_NUMBER: builtins.int
+ MUTE_FIELD_NUMBER: builtins.int
+ track_handle: builtins.int
+ mute: builtins.bool
+ def __init__(
+ self,
+ *,
+ track_handle: builtins.int | None = ...,
+ mute: builtins.bool | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["mute", b"mute", "track_handle", b"track_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["mute", b"mute", "track_handle", b"track_handle"]) -> None: ...
+
+global___LocalTrackMuteRequest = LocalTrackMuteRequest
+
+@typing.final
+class LocalTrackMuteResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ MUTED_FIELD_NUMBER: builtins.int
+ muted: builtins.bool
+ def __init__(
+ self,
+ *,
+ muted: builtins.bool | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["muted", b"muted"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["muted", b"muted"]) -> None: ...
+
+global___LocalTrackMuteResponse = LocalTrackMuteResponse
+
+@typing.final
+class EnableRemoteTrackRequest(google.protobuf.message.Message):
+ """Enable/Disable a remote track"""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ TRACK_HANDLE_FIELD_NUMBER: builtins.int
+ ENABLED_FIELD_NUMBER: builtins.int
+ track_handle: builtins.int
+ enabled: builtins.bool
+ def __init__(
+ self,
+ *,
+ track_handle: builtins.int | None = ...,
+ enabled: builtins.bool | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["enabled", b"enabled", "track_handle", b"track_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["enabled", b"enabled", "track_handle", b"track_handle"]) -> None: ...
+
+global___EnableRemoteTrackRequest = EnableRemoteTrackRequest
+
+@typing.final
+class EnableRemoteTrackResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ ENABLED_FIELD_NUMBER: builtins.int
+ enabled: builtins.bool
+ def __init__(
+ self,
+ *,
+ enabled: builtins.bool | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["enabled", b"enabled"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["enabled", b"enabled"]) -> None: ...
+
+global___EnableRemoteTrackResponse = EnableRemoteTrackResponse
+
+@typing.final
+class SetTrackSubscriptionPermissionsRequest(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ LOCAL_PARTICIPANT_HANDLE_FIELD_NUMBER: builtins.int
+ ALL_PARTICIPANTS_ALLOWED_FIELD_NUMBER: builtins.int
+ PERMISSIONS_FIELD_NUMBER: builtins.int
+ local_participant_handle: builtins.int
+ all_participants_allowed: builtins.bool
+ @property
+ def permissions(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___ParticipantTrackPermission]: ...
+ def __init__(
+ self,
+ *,
+ local_participant_handle: builtins.int | None = ...,
+ all_participants_allowed: builtins.bool | None = ...,
+ permissions: collections.abc.Iterable[global___ParticipantTrackPermission] | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["all_participants_allowed", b"all_participants_allowed", "local_participant_handle", b"local_participant_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["all_participants_allowed", b"all_participants_allowed", "local_participant_handle", b"local_participant_handle", "permissions", b"permissions"]) -> None: ...
+
+global___SetTrackSubscriptionPermissionsRequest = SetTrackSubscriptionPermissionsRequest
+
+@typing.final
+class ParticipantTrackPermission(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ PARTICIPANT_IDENTITY_FIELD_NUMBER: builtins.int
+ ALLOW_ALL_FIELD_NUMBER: builtins.int
+ ALLOWED_TRACK_SIDS_FIELD_NUMBER: builtins.int
+ participant_identity: builtins.str
+ """The participant identity this permission applies to."""
+ allow_all: builtins.bool
+ """Grant permission to all all tracks. Takes precedence over allowedTrackSids."""
+ @property
+ def allowed_track_sids(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]:
+ """List of track sids to grant permission to."""
+
+ def __init__(
+ self,
+ *,
+ participant_identity: builtins.str | None = ...,
+ allow_all: builtins.bool | None = ...,
+ allowed_track_sids: collections.abc.Iterable[builtins.str] | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["allow_all", b"allow_all", "participant_identity", b"participant_identity"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["allow_all", b"allow_all", "allowed_track_sids", b"allowed_track_sids", "participant_identity", b"participant_identity"]) -> None: ...
+
+global___ParticipantTrackPermission = ParticipantTrackPermission
+
+@typing.final
+class SetTrackSubscriptionPermissionsResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ def __init__(
+ self,
+ ) -> None: ...
+
+global___SetTrackSubscriptionPermissionsResponse = SetTrackSubscriptionPermissionsResponse
diff --git a/livekit-rtc/livekit/rtc/_proto/track_publication_pb2.py b/livekit-rtc/livekit/rtc/_proto/track_publication_pb2.py
new file mode 100644
index 00000000..e9eba74e
--- /dev/null
+++ b/livekit-rtc/livekit/rtc/_proto/track_publication_pb2.py
@@ -0,0 +1,39 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: track_publication.proto
+# Protobuf Python Version: 4.25.1
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x17track_publication.proto\x12\rlivekit.proto\"X\n#EnableRemoteTrackPublicationRequest\x12 \n\x18track_publication_handle\x18\x01 \x02(\x04\x12\x0f\n\x07\x65nabled\x18\x02 \x02(\x08\"&\n$EnableRemoteTrackPublicationResponse\"o\n,UpdateRemoteTrackPublicationDimensionRequest\x12 \n\x18track_publication_handle\x18\x01 \x02(\x04\x12\r\n\x05width\x18\x02 \x02(\r\x12\x0e\n\x06height\x18\x03 \x02(\r\"/\n-UpdateRemoteTrackPublicationDimensionResponse\"y\n\'SetRemoteTrackPublicationQualityRequest\x12 \n\x18track_publication_handle\x18\x01 \x02(\x04\x12,\n\x07quality\x18\x02 \x02(\x0e\x32\x1b.livekit.proto.VideoQuality\"*\n(SetRemoteTrackPublicationQualityResponse*W\n\x0cVideoQuality\x12\x15\n\x11VIDEO_QUALITY_LOW\x10\x00\x12\x18\n\x14VIDEO_QUALITY_MEDIUM\x10\x01\x12\x16\n\x12VIDEO_QUALITY_HIGH\x10\x02\x42\x10\xaa\x02\rLiveKit.Proto')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'track_publication_pb2', _globals)
+if _descriptor._USE_C_DESCRIPTORS == False:
+ _globals['DESCRIPTOR']._options = None
+ _globals['DESCRIPTOR']._serialized_options = b'\252\002\rLiveKit.Proto'
+ _globals['_VIDEOQUALITY']._serialized_start=501
+ _globals['_VIDEOQUALITY']._serialized_end=588
+ _globals['_ENABLEREMOTETRACKPUBLICATIONREQUEST']._serialized_start=42
+ _globals['_ENABLEREMOTETRACKPUBLICATIONREQUEST']._serialized_end=130
+ _globals['_ENABLEREMOTETRACKPUBLICATIONRESPONSE']._serialized_start=132
+ _globals['_ENABLEREMOTETRACKPUBLICATIONRESPONSE']._serialized_end=170
+ _globals['_UPDATEREMOTETRACKPUBLICATIONDIMENSIONREQUEST']._serialized_start=172
+ _globals['_UPDATEREMOTETRACKPUBLICATIONDIMENSIONREQUEST']._serialized_end=283
+ _globals['_UPDATEREMOTETRACKPUBLICATIONDIMENSIONRESPONSE']._serialized_start=285
+ _globals['_UPDATEREMOTETRACKPUBLICATIONDIMENSIONRESPONSE']._serialized_end=332
+ _globals['_SETREMOTETRACKPUBLICATIONQUALITYREQUEST']._serialized_start=334
+ _globals['_SETREMOTETRACKPUBLICATIONQUALITYREQUEST']._serialized_end=455
+ _globals['_SETREMOTETRACKPUBLICATIONQUALITYRESPONSE']._serialized_start=457
+ _globals['_SETREMOTETRACKPUBLICATIONQUALITYRESPONSE']._serialized_end=499
+# @@protoc_insertion_point(module_scope)
diff --git a/livekit-rtc/livekit/rtc/_proto/track_publication_pb2.pyi b/livekit-rtc/livekit/rtc/_proto/track_publication_pb2.pyi
new file mode 100644
index 00000000..9e70c7b4
--- /dev/null
+++ b/livekit-rtc/livekit/rtc/_proto/track_publication_pb2.pyi
@@ -0,0 +1,145 @@
+"""
+@generated by mypy-protobuf. Do not edit manually!
+isort:skip_file
+Copyright 2025 LiveKit, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import builtins
+import google.protobuf.descriptor
+import google.protobuf.internal.enum_type_wrapper
+import google.protobuf.message
+import sys
+import typing
+
+if sys.version_info >= (3, 10):
+ import typing as typing_extensions
+else:
+ import typing_extensions
+
+DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
+
+class _VideoQuality:
+ ValueType = typing.NewType("ValueType", builtins.int)
+ V: typing_extensions.TypeAlias = ValueType
+
+class _VideoQualityEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_VideoQuality.ValueType], builtins.type):
+ DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
+ VIDEO_QUALITY_LOW: _VideoQuality.ValueType # 0
+ VIDEO_QUALITY_MEDIUM: _VideoQuality.ValueType # 1
+ VIDEO_QUALITY_HIGH: _VideoQuality.ValueType # 2
+
+class VideoQuality(_VideoQuality, metaclass=_VideoQualityEnumTypeWrapper):
+ """Video quality for simulcasted tracks."""
+
+VIDEO_QUALITY_LOW: VideoQuality.ValueType # 0
+VIDEO_QUALITY_MEDIUM: VideoQuality.ValueType # 1
+VIDEO_QUALITY_HIGH: VideoQuality.ValueType # 2
+global___VideoQuality = VideoQuality
+
+@typing.final
+class EnableRemoteTrackPublicationRequest(google.protobuf.message.Message):
+ """Enable/Disable a remote track publication"""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ TRACK_PUBLICATION_HANDLE_FIELD_NUMBER: builtins.int
+ ENABLED_FIELD_NUMBER: builtins.int
+ track_publication_handle: builtins.int
+ enabled: builtins.bool
+ def __init__(
+ self,
+ *,
+ track_publication_handle: builtins.int | None = ...,
+ enabled: builtins.bool | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["enabled", b"enabled", "track_publication_handle", b"track_publication_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["enabled", b"enabled", "track_publication_handle", b"track_publication_handle"]) -> None: ...
+
+global___EnableRemoteTrackPublicationRequest = EnableRemoteTrackPublicationRequest
+
+@typing.final
+class EnableRemoteTrackPublicationResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ def __init__(
+ self,
+ ) -> None: ...
+
+global___EnableRemoteTrackPublicationResponse = EnableRemoteTrackPublicationResponse
+
+@typing.final
+class UpdateRemoteTrackPublicationDimensionRequest(google.protobuf.message.Message):
+ """update a remote track publication dimension"""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ TRACK_PUBLICATION_HANDLE_FIELD_NUMBER: builtins.int
+ WIDTH_FIELD_NUMBER: builtins.int
+ HEIGHT_FIELD_NUMBER: builtins.int
+ track_publication_handle: builtins.int
+ width: builtins.int
+ height: builtins.int
+ def __init__(
+ self,
+ *,
+ track_publication_handle: builtins.int | None = ...,
+ width: builtins.int | None = ...,
+ height: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["height", b"height", "track_publication_handle", b"track_publication_handle", "width", b"width"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["height", b"height", "track_publication_handle", b"track_publication_handle", "width", b"width"]) -> None: ...
+
+global___UpdateRemoteTrackPublicationDimensionRequest = UpdateRemoteTrackPublicationDimensionRequest
+
+@typing.final
+class UpdateRemoteTrackPublicationDimensionResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ def __init__(
+ self,
+ ) -> None: ...
+
+global___UpdateRemoteTrackPublicationDimensionResponse = UpdateRemoteTrackPublicationDimensionResponse
+
+@typing.final
+class SetRemoteTrackPublicationQualityRequest(google.protobuf.message.Message):
+ """For tracks that support simulcasting, adjust subscribed quality."""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ TRACK_PUBLICATION_HANDLE_FIELD_NUMBER: builtins.int
+ QUALITY_FIELD_NUMBER: builtins.int
+ track_publication_handle: builtins.int
+ quality: global___VideoQuality.ValueType
+ def __init__(
+ self,
+ *,
+ track_publication_handle: builtins.int | None = ...,
+ quality: global___VideoQuality.ValueType | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["quality", b"quality", "track_publication_handle", b"track_publication_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["quality", b"quality", "track_publication_handle", b"track_publication_handle"]) -> None: ...
+
+global___SetRemoteTrackPublicationQualityRequest = SetRemoteTrackPublicationQualityRequest
+
+@typing.final
+class SetRemoteTrackPublicationQualityResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ def __init__(
+ self,
+ ) -> None: ...
+
+global___SetRemoteTrackPublicationQualityResponse = SetRemoteTrackPublicationQualityResponse
diff --git a/livekit-rtc/livekit/rtc/_proto/video_frame_pb2.py b/livekit-rtc/livekit/rtc/_proto/video_frame_pb2.py
index 5af87d6a..6ff10dde 100644
--- a/livekit-rtc/livekit/rtc/_proto/video_frame_pb2.py
+++ b/livekit-rtc/livekit/rtc/_proto/video_frame_pb2.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: video_frame.proto
-# Protobuf Python Version: 4.25.3
+# Protobuf Python Version: 4.25.1
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
@@ -13,9 +13,10 @@
from . import handle_pb2 as handle__pb2
+from . import track_pb2 as track__pb2
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11video_frame.proto\x12\rlivekit.proto\x1a\x0chandle.proto\"\xb5\x01\n\x15NewVideoStreamRequest\x12\x14\n\x0ctrack_handle\x18\x01 \x01(\x04\x12,\n\x04type\x18\x02 \x01(\x0e\x32\x1e.livekit.proto.VideoStreamType\x12\x33\n\x06\x66ormat\x18\x03 \x01(\x0e\x32\x1e.livekit.proto.VideoBufferTypeH\x00\x88\x01\x01\x12\x18\n\x10normalize_stride\x18\x04 \x01(\x08\x42\t\n\x07_format\"I\n\x16NewVideoStreamResponse\x12/\n\x06stream\x18\x01 \x01(\x0b\x32\x1f.livekit.proto.OwnedVideoStream\"\x7f\n\x15NewVideoSourceRequest\x12,\n\x04type\x18\x01 \x01(\x0e\x32\x1e.livekit.proto.VideoSourceType\x12\x38\n\nresolution\x18\x02 \x01(\x0b\x32$.livekit.proto.VideoSourceResolution\"I\n\x16NewVideoSourceResponse\x12/\n\x06source\x18\x01 \x01(\x0b\x32\x1f.livekit.proto.OwnedVideoSource\"\xa7\x01\n\x18\x43\x61ptureVideoFrameRequest\x12\x15\n\rsource_handle\x18\x01 \x01(\x04\x12.\n\x06\x62uffer\x18\x02 \x01(\x0b\x32\x1e.livekit.proto.VideoBufferInfo\x12\x14\n\x0ctimestamp_us\x18\x03 \x01(\x03\x12.\n\x08rotation\x18\x04 \x01(\x0e\x32\x1c.livekit.proto.VideoRotation\"\x1b\n\x19\x43\x61ptureVideoFrameResponse\"\x87\x01\n\x13VideoConvertRequest\x12\x0e\n\x06\x66lip_y\x18\x01 \x01(\x08\x12.\n\x06\x62uffer\x18\x02 \x01(\x0b\x32\x1e.livekit.proto.VideoBufferInfo\x12\x30\n\x08\x64st_type\x18\x03 \x01(\x0e\x32\x1e.livekit.proto.VideoBufferType\"e\n\x14VideoConvertResponse\x12\x12\n\x05\x65rror\x18\x01 \x01(\tH\x00\x88\x01\x01\x12/\n\x06\x62uffer\x18\x02 \x01(\x0b\x32\x1f.livekit.proto.OwnedVideoBufferB\x08\n\x06_error\"D\n\x0fVideoResolution\x12\r\n\x05width\x18\x01 \x01(\r\x12\x0e\n\x06height\x18\x02 \x01(\r\x12\x12\n\nframe_rate\x18\x03 \x01(\x01\"\x83\x02\n\x0fVideoBufferInfo\x12,\n\x04type\x18\x01 \x01(\x0e\x32\x1e.livekit.proto.VideoBufferType\x12\r\n\x05width\x18\x02 \x01(\r\x12\x0e\n\x06height\x18\x03 \x01(\r\x12\x10\n\x08\x64\x61ta_ptr\x18\x04 \x01(\x04\x12\x0e\n\x06stride\x18\x06 \x01(\r\x12@\n\ncomponents\x18\x07 \x03(\x0b\x32,.livekit.proto.VideoBufferInfo.ComponentInfo\x1a?\n\rComponentInfo\x12\x10\n\x08\x64\x61ta_ptr\x18\x01 \x01(\x04\x12\x0e\n\x06stride\x18\x02 \x01(\r\x12\x0c\n\x04size\x18\x03 \x01(\r\"o\n\x10OwnedVideoBuffer\x12-\n\x06handle\x18\x01 \x01(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12,\n\x04info\x18\x02 \x01(\x0b\x32\x1e.livekit.proto.VideoBufferInfo\"?\n\x0fVideoStreamInfo\x12,\n\x04type\x18\x01 \x01(\x0e\x32\x1e.livekit.proto.VideoStreamType\"o\n\x10OwnedVideoStream\x12-\n\x06handle\x18\x01 \x01(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12,\n\x04info\x18\x02 \x01(\x0b\x32\x1e.livekit.proto.VideoStreamInfo\"\x9f\x01\n\x10VideoStreamEvent\x12\x15\n\rstream_handle\x18\x01 \x01(\x04\x12;\n\x0e\x66rame_received\x18\x02 \x01(\x0b\x32!.livekit.proto.VideoFrameReceivedH\x00\x12,\n\x03\x65os\x18\x03 \x01(\x0b\x32\x1d.livekit.proto.VideoStreamEOSH\x00\x42\t\n\x07message\"\x8b\x01\n\x12VideoFrameReceived\x12/\n\x06\x62uffer\x18\x01 \x01(\x0b\x32\x1f.livekit.proto.OwnedVideoBuffer\x12\x14\n\x0ctimestamp_us\x18\x02 \x01(\x03\x12.\n\x08rotation\x18\x03 \x01(\x0e\x32\x1c.livekit.proto.VideoRotation\"\x10\n\x0eVideoStreamEOS\"6\n\x15VideoSourceResolution\x12\r\n\x05width\x18\x01 \x01(\r\x12\x0e\n\x06height\x18\x02 \x01(\r\"?\n\x0fVideoSourceInfo\x12,\n\x04type\x18\x01 \x01(\x0e\x32\x1e.livekit.proto.VideoSourceType\"o\n\x10OwnedVideoSource\x12-\n\x06handle\x18\x01 \x01(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12,\n\x04info\x18\x02 \x01(\x0b\x32\x1e.livekit.proto.VideoSourceInfo*1\n\nVideoCodec\x12\x07\n\x03VP8\x10\x00\x12\x08\n\x04H264\x10\x01\x12\x07\n\x03\x41V1\x10\x02\x12\x07\n\x03VP9\x10\x03*l\n\rVideoRotation\x12\x14\n\x10VIDEO_ROTATION_0\x10\x00\x12\x15\n\x11VIDEO_ROTATION_90\x10\x01\x12\x16\n\x12VIDEO_ROTATION_180\x10\x02\x12\x16\n\x12VIDEO_ROTATION_270\x10\x03*\x81\x01\n\x0fVideoBufferType\x12\x08\n\x04RGBA\x10\x00\x12\x08\n\x04\x41\x42GR\x10\x01\x12\x08\n\x04\x41RGB\x10\x02\x12\x08\n\x04\x42GRA\x10\x03\x12\t\n\x05RGB24\x10\x04\x12\x08\n\x04I420\x10\x05\x12\t\n\x05I420A\x10\x06\x12\x08\n\x04I422\x10\x07\x12\x08\n\x04I444\x10\x08\x12\x08\n\x04I010\x10\t\x12\x08\n\x04NV12\x10\n*Y\n\x0fVideoStreamType\x12\x17\n\x13VIDEO_STREAM_NATIVE\x10\x00\x12\x16\n\x12VIDEO_STREAM_WEBGL\x10\x01\x12\x15\n\x11VIDEO_STREAM_HTML\x10\x02**\n\x0fVideoSourceType\x12\x17\n\x13VIDEO_SOURCE_NATIVE\x10\x00\x42\x10\xaa\x02\rLiveKit.Protob\x06proto3')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11video_frame.proto\x12\rlivekit.proto\x1a\x0chandle.proto\x1a\x0btrack.proto\"\xc0\x01\n\x15NewVideoStreamRequest\x12\x14\n\x0ctrack_handle\x18\x01 \x02(\x04\x12,\n\x04type\x18\x02 \x02(\x0e\x32\x1e.livekit.proto.VideoStreamType\x12.\n\x06\x66ormat\x18\x03 \x01(\x0e\x32\x1e.livekit.proto.VideoBufferType\x12\x18\n\x10normalize_stride\x18\x04 \x01(\x08\x12\x19\n\x11queue_size_frames\x18\x05 \x01(\r\"I\n\x16NewVideoStreamResponse\x12/\n\x06stream\x18\x01 \x02(\x0b\x32\x1f.livekit.proto.OwnedVideoStream\"\x84\x02\n!VideoStreamFromParticipantRequest\x12\x1a\n\x12participant_handle\x18\x01 \x02(\x04\x12,\n\x04type\x18\x02 \x02(\x0e\x32\x1e.livekit.proto.VideoStreamType\x12\x30\n\x0ctrack_source\x18\x03 \x02(\x0e\x32\x1a.livekit.proto.TrackSource\x12.\n\x06\x66ormat\x18\x04 \x01(\x0e\x32\x1e.livekit.proto.VideoBufferType\x12\x18\n\x10normalize_stride\x18\x05 \x01(\x08\x12\x19\n\x11queue_size_frames\x18\x06 \x01(\r\"U\n\"VideoStreamFromParticipantResponse\x12/\n\x06stream\x18\x01 \x02(\x0b\x32\x1f.livekit.proto.OwnedVideoStream\"\x96\x01\n\x15NewVideoSourceRequest\x12,\n\x04type\x18\x01 \x02(\x0e\x32\x1e.livekit.proto.VideoSourceType\x12\x38\n\nresolution\x18\x02 \x02(\x0b\x32$.livekit.proto.VideoSourceResolution\x12\x15\n\ris_screencast\x18\x03 \x01(\x08\"I\n\x16NewVideoSourceResponse\x12/\n\x06source\x18\x01 \x02(\x0b\x32\x1f.livekit.proto.OwnedVideoSource\"\xd7\x01\n\x18\x43\x61ptureVideoFrameRequest\x12\x15\n\rsource_handle\x18\x01 \x02(\x04\x12.\n\x06\x62uffer\x18\x02 \x02(\x0b\x32\x1e.livekit.proto.VideoBufferInfo\x12\x14\n\x0ctimestamp_us\x18\x03 \x02(\x03\x12.\n\x08rotation\x18\x04 \x02(\x0e\x32\x1c.livekit.proto.VideoRotation\x12.\n\x08metadata\x18\x05 \x01(\x0b\x32\x1c.livekit.proto.FrameMetadata\"\x1b\n\x19\x43\x61ptureVideoFrameResponse\"\x87\x01\n\x13VideoConvertRequest\x12\x0e\n\x06\x66lip_y\x18\x01 \x01(\x08\x12.\n\x06\x62uffer\x18\x02 \x02(\x0b\x32\x1e.livekit.proto.VideoBufferInfo\x12\x30\n\x08\x64st_type\x18\x03 \x02(\x0e\x32\x1e.livekit.proto.VideoBufferType\"e\n\x14VideoConvertResponse\x12\x0f\n\x05\x65rror\x18\x01 \x01(\tH\x00\x12\x31\n\x06\x62uffer\x18\x02 \x01(\x0b\x32\x1f.livekit.proto.OwnedVideoBufferH\x00\x42\t\n\x07message\"D\n\x0fVideoResolution\x12\r\n\x05width\x18\x01 \x02(\r\x12\x0e\n\x06height\x18\x02 \x02(\r\x12\x12\n\nframe_rate\x18\x03 \x02(\x01\"\x83\x02\n\x0fVideoBufferInfo\x12,\n\x04type\x18\x01 \x02(\x0e\x32\x1e.livekit.proto.VideoBufferType\x12\r\n\x05width\x18\x02 \x02(\r\x12\x0e\n\x06height\x18\x03 \x02(\r\x12\x10\n\x08\x64\x61ta_ptr\x18\x04 \x02(\x04\x12\x0e\n\x06stride\x18\x06 \x01(\r\x12@\n\ncomponents\x18\x07 \x03(\x0b\x32,.livekit.proto.VideoBufferInfo.ComponentInfo\x1a?\n\rComponentInfo\x12\x10\n\x08\x64\x61ta_ptr\x18\x01 \x02(\x04\x12\x0e\n\x06stride\x18\x02 \x02(\r\x12\x0c\n\x04size\x18\x03 \x02(\r\"o\n\x10OwnedVideoBuffer\x12-\n\x06handle\x18\x01 \x02(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12,\n\x04info\x18\x02 \x02(\x0b\x32\x1e.livekit.proto.VideoBufferInfo\"9\n\rFrameMetadata\x12\x16\n\x0euser_timestamp\x18\x01 \x01(\x04\x12\x10\n\x08\x66rame_id\x18\x02 \x01(\r\"?\n\x0fVideoStreamInfo\x12,\n\x04type\x18\x01 \x02(\x0e\x32\x1e.livekit.proto.VideoStreamType\"o\n\x10OwnedVideoStream\x12-\n\x06handle\x18\x01 \x02(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12,\n\x04info\x18\x02 \x02(\x0b\x32\x1e.livekit.proto.VideoStreamInfo\"\x9f\x01\n\x10VideoStreamEvent\x12\x15\n\rstream_handle\x18\x01 \x02(\x04\x12;\n\x0e\x66rame_received\x18\x02 \x01(\x0b\x32!.livekit.proto.VideoFrameReceivedH\x00\x12,\n\x03\x65os\x18\x03 \x01(\x0b\x32\x1d.livekit.proto.VideoStreamEOSH\x00\x42\t\n\x07message\"\xbb\x01\n\x12VideoFrameReceived\x12/\n\x06\x62uffer\x18\x01 \x02(\x0b\x32\x1f.livekit.proto.OwnedVideoBuffer\x12\x14\n\x0ctimestamp_us\x18\x02 \x02(\x03\x12.\n\x08rotation\x18\x03 \x02(\x0e\x32\x1c.livekit.proto.VideoRotation\x12.\n\x08metadata\x18\x04 \x01(\x0b\x32\x1c.livekit.proto.FrameMetadata\"\x10\n\x0eVideoStreamEOS\"6\n\x15VideoSourceResolution\x12\r\n\x05width\x18\x01 \x02(\r\x12\x0e\n\x06height\x18\x02 \x02(\r\"?\n\x0fVideoSourceInfo\x12,\n\x04type\x18\x01 \x02(\x0e\x32\x1e.livekit.proto.VideoSourceType\"o\n\x10OwnedVideoSource\x12-\n\x06handle\x18\x01 \x02(\x0b\x32\x1d.livekit.proto.FfiOwnedHandle\x12,\n\x04info\x18\x02 \x02(\x0b\x32\x1e.livekit.proto.VideoSourceInfo*;\n\nVideoCodec\x12\x07\n\x03VP8\x10\x00\x12\x08\n\x04H264\x10\x01\x12\x07\n\x03\x41V1\x10\x02\x12\x07\n\x03VP9\x10\x03\x12\x08\n\x04H265\x10\x04*l\n\rVideoRotation\x12\x14\n\x10VIDEO_ROTATION_0\x10\x00\x12\x15\n\x11VIDEO_ROTATION_90\x10\x01\x12\x16\n\x12VIDEO_ROTATION_180\x10\x02\x12\x16\n\x12VIDEO_ROTATION_270\x10\x03*\x81\x01\n\x0fVideoBufferType\x12\x08\n\x04RGBA\x10\x00\x12\x08\n\x04\x41\x42GR\x10\x01\x12\x08\n\x04\x41RGB\x10\x02\x12\x08\n\x04\x42GRA\x10\x03\x12\t\n\x05RGB24\x10\x04\x12\x08\n\x04I420\x10\x05\x12\t\n\x05I420A\x10\x06\x12\x08\n\x04I422\x10\x07\x12\x08\n\x04I444\x10\x08\x12\x08\n\x04I010\x10\t\x12\x08\n\x04NV12\x10\n*Y\n\x0fVideoStreamType\x12\x17\n\x13VIDEO_STREAM_NATIVE\x10\x00\x12\x16\n\x12VIDEO_STREAM_WEBGL\x10\x01\x12\x15\n\x11VIDEO_STREAM_HTML\x10\x02**\n\x0fVideoSourceType\x12\x17\n\x13VIDEO_SOURCE_NATIVE\x10\x00\x42\x10\xaa\x02\rLiveKit.Proto')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -23,54 +24,60 @@
if _descriptor._USE_C_DESCRIPTORS == False:
_globals['DESCRIPTOR']._options = None
_globals['DESCRIPTOR']._serialized_options = b'\252\002\rLiveKit.Proto'
- _globals['_VIDEOCODEC']._serialized_start=2132
- _globals['_VIDEOCODEC']._serialized_end=2181
- _globals['_VIDEOROTATION']._serialized_start=2183
- _globals['_VIDEOROTATION']._serialized_end=2291
- _globals['_VIDEOBUFFERTYPE']._serialized_start=2294
- _globals['_VIDEOBUFFERTYPE']._serialized_end=2423
- _globals['_VIDEOSTREAMTYPE']._serialized_start=2425
- _globals['_VIDEOSTREAMTYPE']._serialized_end=2514
- _globals['_VIDEOSOURCETYPE']._serialized_start=2516
- _globals['_VIDEOSOURCETYPE']._serialized_end=2558
- _globals['_NEWVIDEOSTREAMREQUEST']._serialized_start=51
- _globals['_NEWVIDEOSTREAMREQUEST']._serialized_end=232
- _globals['_NEWVIDEOSTREAMRESPONSE']._serialized_start=234
- _globals['_NEWVIDEOSTREAMRESPONSE']._serialized_end=307
- _globals['_NEWVIDEOSOURCEREQUEST']._serialized_start=309
- _globals['_NEWVIDEOSOURCEREQUEST']._serialized_end=436
- _globals['_NEWVIDEOSOURCERESPONSE']._serialized_start=438
- _globals['_NEWVIDEOSOURCERESPONSE']._serialized_end=511
- _globals['_CAPTUREVIDEOFRAMEREQUEST']._serialized_start=514
- _globals['_CAPTUREVIDEOFRAMEREQUEST']._serialized_end=681
- _globals['_CAPTUREVIDEOFRAMERESPONSE']._serialized_start=683
- _globals['_CAPTUREVIDEOFRAMERESPONSE']._serialized_end=710
- _globals['_VIDEOCONVERTREQUEST']._serialized_start=713
- _globals['_VIDEOCONVERTREQUEST']._serialized_end=848
- _globals['_VIDEOCONVERTRESPONSE']._serialized_start=850
- _globals['_VIDEOCONVERTRESPONSE']._serialized_end=951
- _globals['_VIDEORESOLUTION']._serialized_start=953
- _globals['_VIDEORESOLUTION']._serialized_end=1021
- _globals['_VIDEOBUFFERINFO']._serialized_start=1024
- _globals['_VIDEOBUFFERINFO']._serialized_end=1283
- _globals['_VIDEOBUFFERINFO_COMPONENTINFO']._serialized_start=1220
- _globals['_VIDEOBUFFERINFO_COMPONENTINFO']._serialized_end=1283
- _globals['_OWNEDVIDEOBUFFER']._serialized_start=1285
- _globals['_OWNEDVIDEOBUFFER']._serialized_end=1396
- _globals['_VIDEOSTREAMINFO']._serialized_start=1398
- _globals['_VIDEOSTREAMINFO']._serialized_end=1461
- _globals['_OWNEDVIDEOSTREAM']._serialized_start=1463
- _globals['_OWNEDVIDEOSTREAM']._serialized_end=1574
- _globals['_VIDEOSTREAMEVENT']._serialized_start=1577
- _globals['_VIDEOSTREAMEVENT']._serialized_end=1736
- _globals['_VIDEOFRAMERECEIVED']._serialized_start=1739
- _globals['_VIDEOFRAMERECEIVED']._serialized_end=1878
- _globals['_VIDEOSTREAMEOS']._serialized_start=1880
- _globals['_VIDEOSTREAMEOS']._serialized_end=1896
- _globals['_VIDEOSOURCERESOLUTION']._serialized_start=1898
- _globals['_VIDEOSOURCERESOLUTION']._serialized_end=1952
- _globals['_VIDEOSOURCEINFO']._serialized_start=1954
- _globals['_VIDEOSOURCEINFO']._serialized_end=2017
- _globals['_OWNEDVIDEOSOURCE']._serialized_start=2019
- _globals['_OWNEDVIDEOSOURCE']._serialized_end=2130
+ _globals['_VIDEOCODEC']._serialized_start=2685
+ _globals['_VIDEOCODEC']._serialized_end=2744
+ _globals['_VIDEOROTATION']._serialized_start=2746
+ _globals['_VIDEOROTATION']._serialized_end=2854
+ _globals['_VIDEOBUFFERTYPE']._serialized_start=2857
+ _globals['_VIDEOBUFFERTYPE']._serialized_end=2986
+ _globals['_VIDEOSTREAMTYPE']._serialized_start=2988
+ _globals['_VIDEOSTREAMTYPE']._serialized_end=3077
+ _globals['_VIDEOSOURCETYPE']._serialized_start=3079
+ _globals['_VIDEOSOURCETYPE']._serialized_end=3121
+ _globals['_NEWVIDEOSTREAMREQUEST']._serialized_start=64
+ _globals['_NEWVIDEOSTREAMREQUEST']._serialized_end=256
+ _globals['_NEWVIDEOSTREAMRESPONSE']._serialized_start=258
+ _globals['_NEWVIDEOSTREAMRESPONSE']._serialized_end=331
+ _globals['_VIDEOSTREAMFROMPARTICIPANTREQUEST']._serialized_start=334
+ _globals['_VIDEOSTREAMFROMPARTICIPANTREQUEST']._serialized_end=594
+ _globals['_VIDEOSTREAMFROMPARTICIPANTRESPONSE']._serialized_start=596
+ _globals['_VIDEOSTREAMFROMPARTICIPANTRESPONSE']._serialized_end=681
+ _globals['_NEWVIDEOSOURCEREQUEST']._serialized_start=684
+ _globals['_NEWVIDEOSOURCEREQUEST']._serialized_end=834
+ _globals['_NEWVIDEOSOURCERESPONSE']._serialized_start=836
+ _globals['_NEWVIDEOSOURCERESPONSE']._serialized_end=909
+ _globals['_CAPTUREVIDEOFRAMEREQUEST']._serialized_start=912
+ _globals['_CAPTUREVIDEOFRAMEREQUEST']._serialized_end=1127
+ _globals['_CAPTUREVIDEOFRAMERESPONSE']._serialized_start=1129
+ _globals['_CAPTUREVIDEOFRAMERESPONSE']._serialized_end=1156
+ _globals['_VIDEOCONVERTREQUEST']._serialized_start=1159
+ _globals['_VIDEOCONVERTREQUEST']._serialized_end=1294
+ _globals['_VIDEOCONVERTRESPONSE']._serialized_start=1296
+ _globals['_VIDEOCONVERTRESPONSE']._serialized_end=1397
+ _globals['_VIDEORESOLUTION']._serialized_start=1399
+ _globals['_VIDEORESOLUTION']._serialized_end=1467
+ _globals['_VIDEOBUFFERINFO']._serialized_start=1470
+ _globals['_VIDEOBUFFERINFO']._serialized_end=1729
+ _globals['_VIDEOBUFFERINFO_COMPONENTINFO']._serialized_start=1666
+ _globals['_VIDEOBUFFERINFO_COMPONENTINFO']._serialized_end=1729
+ _globals['_OWNEDVIDEOBUFFER']._serialized_start=1731
+ _globals['_OWNEDVIDEOBUFFER']._serialized_end=1842
+ _globals['_FRAMEMETADATA']._serialized_start=1844
+ _globals['_FRAMEMETADATA']._serialized_end=1901
+ _globals['_VIDEOSTREAMINFO']._serialized_start=1903
+ _globals['_VIDEOSTREAMINFO']._serialized_end=1966
+ _globals['_OWNEDVIDEOSTREAM']._serialized_start=1968
+ _globals['_OWNEDVIDEOSTREAM']._serialized_end=2079
+ _globals['_VIDEOSTREAMEVENT']._serialized_start=2082
+ _globals['_VIDEOSTREAMEVENT']._serialized_end=2241
+ _globals['_VIDEOFRAMERECEIVED']._serialized_start=2244
+ _globals['_VIDEOFRAMERECEIVED']._serialized_end=2431
+ _globals['_VIDEOSTREAMEOS']._serialized_start=2433
+ _globals['_VIDEOSTREAMEOS']._serialized_end=2449
+ _globals['_VIDEOSOURCERESOLUTION']._serialized_start=2451
+ _globals['_VIDEOSOURCERESOLUTION']._serialized_end=2505
+ _globals['_VIDEOSOURCEINFO']._serialized_start=2507
+ _globals['_VIDEOSOURCEINFO']._serialized_end=2570
+ _globals['_OWNEDVIDEOSOURCE']._serialized_start=2572
+ _globals['_OWNEDVIDEOSOURCE']._serialized_end=2683
# @@protoc_insertion_point(module_scope)
diff --git a/livekit-rtc/livekit/rtc/_proto/video_frame_pb2.pyi b/livekit-rtc/livekit/rtc/_proto/video_frame_pb2.pyi
index 393bb975..e4df4b99 100644
--- a/livekit-rtc/livekit/rtc/_proto/video_frame_pb2.pyi
+++ b/livekit-rtc/livekit/rtc/_proto/video_frame_pb2.pyi
@@ -1,7 +1,7 @@
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
-Copyright 2023 LiveKit, Inc.
+Copyright 2025 LiveKit, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
+
import builtins
import collections.abc
import google.protobuf.descriptor
@@ -23,6 +24,7 @@ import google.protobuf.internal.enum_type_wrapper
import google.protobuf.message
from . import handle_pb2
import sys
+from . import track_pb2
import typing
if sys.version_info >= (3, 10):
@@ -42,6 +44,7 @@ class _VideoCodecEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._Enu
H264: _VideoCodec.ValueType # 1
AV1: _VideoCodec.ValueType # 2
VP9: _VideoCodec.ValueType # 3
+ H265: _VideoCodec.ValueType # 4
class VideoCodec(_VideoCodec, metaclass=_VideoCodecEnumTypeWrapper): ...
@@ -49,6 +52,7 @@ VP8: VideoCodec.ValueType # 0
H264: VideoCodec.ValueType # 1
AV1: VideoCodec.ValueType # 2
VP9: VideoCodec.ValueType # 3
+H265: VideoCodec.ValueType # 4
global___VideoCodec = VideoCodec
class _VideoRotation:
@@ -88,7 +92,10 @@ class _VideoBufferTypeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper
I010: _VideoBufferType.ValueType # 9
NV12: _VideoBufferType.ValueType # 10
-class VideoBufferType(_VideoBufferType, metaclass=_VideoBufferTypeEnumTypeWrapper): ...
+class VideoBufferType(_VideoBufferType, metaclass=_VideoBufferTypeEnumTypeWrapper):
+ """Values of this enum must not be changed
+ It is used to serialize a rtc.VideoFrame on Python
+ """
RGBA: VideoBufferType.ValueType # 0
ABGR: VideoBufferType.ValueType # 1
@@ -136,7 +143,7 @@ class VideoSourceType(_VideoSourceType, metaclass=_VideoSourceTypeEnumTypeWrappe
VIDEO_SOURCE_NATIVE: VideoSourceType.ValueType # 0
global___VideoSourceType = VideoSourceType
-@typing_extensions.final
+@typing.final
class NewVideoStreamRequest(google.protobuf.message.Message):
"""Create a new VideoStream
VideoStream is used to receive video frames from a track
@@ -148,27 +155,38 @@ class NewVideoStreamRequest(google.protobuf.message.Message):
TYPE_FIELD_NUMBER: builtins.int
FORMAT_FIELD_NUMBER: builtins.int
NORMALIZE_STRIDE_FIELD_NUMBER: builtins.int
+ QUEUE_SIZE_FRAMES_FIELD_NUMBER: builtins.int
track_handle: builtins.int
type: global___VideoStreamType.ValueType
format: global___VideoBufferType.ValueType
"""Get the frame on a specific format"""
normalize_stride: builtins.bool
"""if true, stride will be set to width/chroma_width"""
+ queue_size_frames: builtins.int
+ """Maximum number of queued WebRTC sink frames on the receive path. Omit this
+ field to use the default bounded queue size of 1 frame. Set it to 0 to
+ request unbounded buffering.
+
+ If your application consumes both audio and video, keep the queue sizing
+ strategy coordinated across both streams. Using a much larger queue, or
+ unbounded buffering, for only one of them can increase end-to-end latency
+ for that stream and cause audio/video drift.
+ """
def __init__(
self,
*,
- track_handle: builtins.int = ...,
- type: global___VideoStreamType.ValueType = ...,
+ track_handle: builtins.int | None = ...,
+ type: global___VideoStreamType.ValueType | None = ...,
format: global___VideoBufferType.ValueType | None = ...,
- normalize_stride: builtins.bool = ...,
+ normalize_stride: builtins.bool | None = ...,
+ queue_size_frames: builtins.int | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_format", b"_format", "format", b"format"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_format", b"_format", "format", b"format", "normalize_stride", b"normalize_stride", "track_handle", b"track_handle", "type", b"type"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_format", b"_format"]) -> typing_extensions.Literal["format"] | None: ...
+ def HasField(self, field_name: typing.Literal["format", b"format", "normalize_stride", b"normalize_stride", "queue_size_frames", b"queue_size_frames", "track_handle", b"track_handle", "type", b"type"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["format", b"format", "normalize_stride", b"normalize_stride", "queue_size_frames", b"queue_size_frames", "track_handle", b"track_handle", "type", b"type"]) -> None: ...
global___NewVideoStreamRequest = NewVideoStreamRequest
-@typing_extensions.final
+@typing.final
class NewVideoStreamResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -180,12 +198,71 @@ class NewVideoStreamResponse(google.protobuf.message.Message):
*,
stream: global___OwnedVideoStream | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["stream", b"stream"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["stream", b"stream"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["stream", b"stream"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["stream", b"stream"]) -> None: ...
global___NewVideoStreamResponse = NewVideoStreamResponse
-@typing_extensions.final
+@typing.final
+class VideoStreamFromParticipantRequest(google.protobuf.message.Message):
+ """Request a video stream from a participant"""
+
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ PARTICIPANT_HANDLE_FIELD_NUMBER: builtins.int
+ TYPE_FIELD_NUMBER: builtins.int
+ TRACK_SOURCE_FIELD_NUMBER: builtins.int
+ FORMAT_FIELD_NUMBER: builtins.int
+ NORMALIZE_STRIDE_FIELD_NUMBER: builtins.int
+ QUEUE_SIZE_FRAMES_FIELD_NUMBER: builtins.int
+ participant_handle: builtins.int
+ type: global___VideoStreamType.ValueType
+ track_source: track_pb2.TrackSource.ValueType
+ format: global___VideoBufferType.ValueType
+ normalize_stride: builtins.bool
+ queue_size_frames: builtins.int
+ """Maximum number of queued WebRTC sink frames on the receive path. Omit this
+ field to use the default bounded queue size of 1 frame. Set it to 0 to
+ request unbounded buffering.
+
+ If your application consumes both audio and video, keep the queue sizing
+ strategy coordinated across both streams. Using a much larger queue, or
+ unbounded buffering, for only one of them can increase end-to-end latency
+ for that stream and cause audio/video drift.
+ """
+ def __init__(
+ self,
+ *,
+ participant_handle: builtins.int | None = ...,
+ type: global___VideoStreamType.ValueType | None = ...,
+ track_source: track_pb2.TrackSource.ValueType | None = ...,
+ format: global___VideoBufferType.ValueType | None = ...,
+ normalize_stride: builtins.bool | None = ...,
+ queue_size_frames: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["format", b"format", "normalize_stride", b"normalize_stride", "participant_handle", b"participant_handle", "queue_size_frames", b"queue_size_frames", "track_source", b"track_source", "type", b"type"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["format", b"format", "normalize_stride", b"normalize_stride", "participant_handle", b"participant_handle", "queue_size_frames", b"queue_size_frames", "track_source", b"track_source", "type", b"type"]) -> None: ...
+
+global___VideoStreamFromParticipantRequest = VideoStreamFromParticipantRequest
+
+@typing.final
+class VideoStreamFromParticipantResponse(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ STREAM_FIELD_NUMBER: builtins.int
+ @property
+ def stream(self) -> global___OwnedVideoStream: ...
+ def __init__(
+ self,
+ *,
+ stream: global___OwnedVideoStream | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["stream", b"stream"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["stream", b"stream"]) -> None: ...
+
+global___VideoStreamFromParticipantResponse = VideoStreamFromParticipantResponse
+
+@typing.final
class NewVideoSourceRequest(google.protobuf.message.Message):
"""Create a new VideoSource
VideoSource is used to send video frame to a track
@@ -195,24 +272,28 @@ class NewVideoSourceRequest(google.protobuf.message.Message):
TYPE_FIELD_NUMBER: builtins.int
RESOLUTION_FIELD_NUMBER: builtins.int
+ IS_SCREENCAST_FIELD_NUMBER: builtins.int
type: global___VideoSourceType.ValueType
+ is_screencast: builtins.bool
@property
def resolution(self) -> global___VideoSourceResolution:
"""Used to determine which encodings to use + simulcast layers
Most of the time it corresponds to the source resolution
"""
+
def __init__(
self,
*,
- type: global___VideoSourceType.ValueType = ...,
+ type: global___VideoSourceType.ValueType | None = ...,
resolution: global___VideoSourceResolution | None = ...,
+ is_screencast: builtins.bool | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["resolution", b"resolution"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["resolution", b"resolution", "type", b"type"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["is_screencast", b"is_screencast", "resolution", b"resolution", "type", b"type"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["is_screencast", b"is_screencast", "resolution", b"resolution", "type", b"type"]) -> None: ...
global___NewVideoSourceRequest = NewVideoSourceRequest
-@typing_extensions.final
+@typing.final
class NewVideoSourceResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -224,12 +305,12 @@ class NewVideoSourceResponse(google.protobuf.message.Message):
*,
source: global___OwnedVideoSource | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["source", b"source"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["source", b"source"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["source", b"source"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["source", b"source"]) -> None: ...
global___NewVideoSourceResponse = NewVideoSourceResponse
-@typing_extensions.final
+@typing.final
class CaptureVideoFrameRequest(google.protobuf.message.Message):
"""Push a frame to a VideoSource"""
@@ -239,26 +320,30 @@ class CaptureVideoFrameRequest(google.protobuf.message.Message):
BUFFER_FIELD_NUMBER: builtins.int
TIMESTAMP_US_FIELD_NUMBER: builtins.int
ROTATION_FIELD_NUMBER: builtins.int
+ METADATA_FIELD_NUMBER: builtins.int
source_handle: builtins.int
- @property
- def buffer(self) -> global___VideoBufferInfo: ...
timestamp_us: builtins.int
"""In microseconds"""
rotation: global___VideoRotation.ValueType
+ @property
+ def buffer(self) -> global___VideoBufferInfo: ...
+ @property
+ def metadata(self) -> global___FrameMetadata: ...
def __init__(
self,
*,
- source_handle: builtins.int = ...,
+ source_handle: builtins.int | None = ...,
buffer: global___VideoBufferInfo | None = ...,
- timestamp_us: builtins.int = ...,
- rotation: global___VideoRotation.ValueType = ...,
+ timestamp_us: builtins.int | None = ...,
+ rotation: global___VideoRotation.ValueType | None = ...,
+ metadata: global___FrameMetadata | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["buffer", b"buffer"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["buffer", b"buffer", "rotation", b"rotation", "source_handle", b"source_handle", "timestamp_us", b"timestamp_us"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["buffer", b"buffer", "metadata", b"metadata", "rotation", b"rotation", "source_handle", b"source_handle", "timestamp_us", b"timestamp_us"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["buffer", b"buffer", "metadata", b"metadata", "rotation", b"rotation", "source_handle", b"source_handle", "timestamp_us", b"timestamp_us"]) -> None: ...
global___CaptureVideoFrameRequest = CaptureVideoFrameRequest
-@typing_extensions.final
+@typing.final
class CaptureVideoFrameResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -268,7 +353,7 @@ class CaptureVideoFrameResponse(google.protobuf.message.Message):
global___CaptureVideoFrameResponse = CaptureVideoFrameResponse
-@typing_extensions.final
+@typing.final
class VideoConvertRequest(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -276,22 +361,22 @@ class VideoConvertRequest(google.protobuf.message.Message):
BUFFER_FIELD_NUMBER: builtins.int
DST_TYPE_FIELD_NUMBER: builtins.int
flip_y: builtins.bool
+ dst_type: global___VideoBufferType.ValueType
@property
def buffer(self) -> global___VideoBufferInfo: ...
- dst_type: global___VideoBufferType.ValueType
def __init__(
self,
*,
- flip_y: builtins.bool = ...,
+ flip_y: builtins.bool | None = ...,
buffer: global___VideoBufferInfo | None = ...,
- dst_type: global___VideoBufferType.ValueType = ...,
+ dst_type: global___VideoBufferType.ValueType | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["buffer", b"buffer"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["buffer", b"buffer", "dst_type", b"dst_type", "flip_y", b"flip_y"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["buffer", b"buffer", "dst_type", b"dst_type", "flip_y", b"flip_y"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["buffer", b"buffer", "dst_type", b"dst_type", "flip_y", b"flip_y"]) -> None: ...
global___VideoConvertRequest = VideoConvertRequest
-@typing_extensions.final
+@typing.final
class VideoConvertResponse(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -306,13 +391,13 @@ class VideoConvertResponse(google.protobuf.message.Message):
error: builtins.str | None = ...,
buffer: global___OwnedVideoBuffer | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_error", b"_error", "buffer", b"buffer", "error", b"error"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_error", b"_error", "buffer", b"buffer", "error", b"error"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["_error", b"_error"]) -> typing_extensions.Literal["error"] | None: ...
+ def HasField(self, field_name: typing.Literal["buffer", b"buffer", "error", b"error", "message", b"message"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["buffer", b"buffer", "error", b"error", "message", b"message"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["message", b"message"]) -> typing.Literal["error", "buffer"] | None: ...
global___VideoConvertResponse = VideoConvertResponse
-@typing_extensions.final
+@typing.final
class VideoResolution(google.protobuf.message.Message):
"""
VideoFrame buffers
@@ -329,19 +414,20 @@ class VideoResolution(google.protobuf.message.Message):
def __init__(
self,
*,
- width: builtins.int = ...,
- height: builtins.int = ...,
- frame_rate: builtins.float = ...,
+ width: builtins.int | None = ...,
+ height: builtins.int | None = ...,
+ frame_rate: builtins.float | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["frame_rate", b"frame_rate", "height", b"height", "width", b"width"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["frame_rate", b"frame_rate", "height", b"height", "width", b"width"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["frame_rate", b"frame_rate", "height", b"height", "width", b"width"]) -> None: ...
global___VideoResolution = VideoResolution
-@typing_extensions.final
+@typing.final
class VideoBufferInfo(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
- @typing_extensions.final
+ @typing.final
class ComponentInfo(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -354,11 +440,12 @@ class VideoBufferInfo(google.protobuf.message.Message):
def __init__(
self,
*,
- data_ptr: builtins.int = ...,
- stride: builtins.int = ...,
- size: builtins.int = ...,
+ data_ptr: builtins.int | None = ...,
+ stride: builtins.int | None = ...,
+ size: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["data_ptr", b"data_ptr", "size", b"size", "stride", b"stride"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["data_ptr", b"data_ptr", "size", b"size", "stride", b"stride"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["data_ptr", b"data_ptr", "size", b"size", "stride", b"stride"]) -> None: ...
TYPE_FIELD_NUMBER: builtins.int
WIDTH_FIELD_NUMBER: builtins.int
@@ -377,18 +464,19 @@ class VideoBufferInfo(google.protobuf.message.Message):
def __init__(
self,
*,
- type: global___VideoBufferType.ValueType = ...,
- width: builtins.int = ...,
- height: builtins.int = ...,
- data_ptr: builtins.int = ...,
- stride: builtins.int = ...,
+ type: global___VideoBufferType.ValueType | None = ...,
+ width: builtins.int | None = ...,
+ height: builtins.int | None = ...,
+ data_ptr: builtins.int | None = ...,
+ stride: builtins.int | None = ...,
components: collections.abc.Iterable[global___VideoBufferInfo.ComponentInfo] | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["components", b"components", "data_ptr", b"data_ptr", "height", b"height", "stride", b"stride", "type", b"type", "width", b"width"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["data_ptr", b"data_ptr", "height", b"height", "stride", b"stride", "type", b"type", "width", b"width"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["components", b"components", "data_ptr", b"data_ptr", "height", b"height", "stride", b"stride", "type", b"type", "width", b"width"]) -> None: ...
global___VideoBufferInfo = VideoBufferInfo
-@typing_extensions.final
+@typing.final
class OwnedVideoBuffer(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -404,12 +492,31 @@ class OwnedVideoBuffer(google.protobuf.message.Message):
handle: handle_pb2.FfiOwnedHandle | None = ...,
info: global___VideoBufferInfo | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["handle", b"handle", "info", b"info"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["handle", b"handle", "info", b"info"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> None: ...
global___OwnedVideoBuffer = OwnedVideoBuffer
-@typing_extensions.final
+@typing.final
+class FrameMetadata(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ USER_TIMESTAMP_FIELD_NUMBER: builtins.int
+ FRAME_ID_FIELD_NUMBER: builtins.int
+ user_timestamp: builtins.int
+ frame_id: builtins.int
+ def __init__(
+ self,
+ *,
+ user_timestamp: builtins.int | None = ...,
+ frame_id: builtins.int | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing.Literal["frame_id", b"frame_id", "user_timestamp", b"user_timestamp"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["frame_id", b"frame_id", "user_timestamp", b"user_timestamp"]) -> None: ...
+
+global___FrameMetadata = FrameMetadata
+
+@typing.final
class VideoStreamInfo(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -418,13 +525,14 @@ class VideoStreamInfo(google.protobuf.message.Message):
def __init__(
self,
*,
- type: global___VideoStreamType.ValueType = ...,
+ type: global___VideoStreamType.ValueType | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["type", b"type"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["type", b"type"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["type", b"type"]) -> None: ...
global___VideoStreamInfo = VideoStreamInfo
-@typing_extensions.final
+@typing.final
class OwnedVideoStream(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -440,12 +548,12 @@ class OwnedVideoStream(google.protobuf.message.Message):
handle: handle_pb2.FfiOwnedHandle | None = ...,
info: global___VideoStreamInfo | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["handle", b"handle", "info", b"info"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["handle", b"handle", "info", b"info"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> None: ...
global___OwnedVideoStream = OwnedVideoStream
-@typing_extensions.final
+@typing.final
class VideoStreamEvent(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -460,41 +568,45 @@ class VideoStreamEvent(google.protobuf.message.Message):
def __init__(
self,
*,
- stream_handle: builtins.int = ...,
+ stream_handle: builtins.int | None = ...,
frame_received: global___VideoFrameReceived | None = ...,
eos: global___VideoStreamEOS | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["eos", b"eos", "frame_received", b"frame_received", "message", b"message"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["eos", b"eos", "frame_received", b"frame_received", "message", b"message", "stream_handle", b"stream_handle"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["message", b"message"]) -> typing_extensions.Literal["frame_received", "eos"] | None: ...
+ def HasField(self, field_name: typing.Literal["eos", b"eos", "frame_received", b"frame_received", "message", b"message", "stream_handle", b"stream_handle"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["eos", b"eos", "frame_received", b"frame_received", "message", b"message", "stream_handle", b"stream_handle"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing.Literal["message", b"message"]) -> typing.Literal["frame_received", "eos"] | None: ...
global___VideoStreamEvent = VideoStreamEvent
-@typing_extensions.final
+@typing.final
class VideoFrameReceived(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
BUFFER_FIELD_NUMBER: builtins.int
TIMESTAMP_US_FIELD_NUMBER: builtins.int
ROTATION_FIELD_NUMBER: builtins.int
- @property
- def buffer(self) -> global___OwnedVideoBuffer: ...
+ METADATA_FIELD_NUMBER: builtins.int
timestamp_us: builtins.int
"""In microseconds"""
rotation: global___VideoRotation.ValueType
+ @property
+ def buffer(self) -> global___OwnedVideoBuffer: ...
+ @property
+ def metadata(self) -> global___FrameMetadata: ...
def __init__(
self,
*,
buffer: global___OwnedVideoBuffer | None = ...,
- timestamp_us: builtins.int = ...,
- rotation: global___VideoRotation.ValueType = ...,
+ timestamp_us: builtins.int | None = ...,
+ rotation: global___VideoRotation.ValueType | None = ...,
+ metadata: global___FrameMetadata | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["buffer", b"buffer"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["buffer", b"buffer", "rotation", b"rotation", "timestamp_us", b"timestamp_us"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["buffer", b"buffer", "metadata", b"metadata", "rotation", b"rotation", "timestamp_us", b"timestamp_us"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["buffer", b"buffer", "metadata", b"metadata", "rotation", b"rotation", "timestamp_us", b"timestamp_us"]) -> None: ...
global___VideoFrameReceived = VideoFrameReceived
-@typing_extensions.final
+@typing.final
class VideoStreamEOS(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -504,7 +616,7 @@ class VideoStreamEOS(google.protobuf.message.Message):
global___VideoStreamEOS = VideoStreamEOS
-@typing_extensions.final
+@typing.final
class VideoSourceResolution(google.protobuf.message.Message):
"""
VideoSource
@@ -519,14 +631,15 @@ class VideoSourceResolution(google.protobuf.message.Message):
def __init__(
self,
*,
- width: builtins.int = ...,
- height: builtins.int = ...,
+ width: builtins.int | None = ...,
+ height: builtins.int | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["height", b"height", "width", b"width"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["height", b"height", "width", b"width"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["height", b"height", "width", b"width"]) -> None: ...
global___VideoSourceResolution = VideoSourceResolution
-@typing_extensions.final
+@typing.final
class VideoSourceInfo(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -535,13 +648,14 @@ class VideoSourceInfo(google.protobuf.message.Message):
def __init__(
self,
*,
- type: global___VideoSourceType.ValueType = ...,
+ type: global___VideoSourceType.ValueType | None = ...,
) -> None: ...
- def ClearField(self, field_name: typing_extensions.Literal["type", b"type"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["type", b"type"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["type", b"type"]) -> None: ...
global___VideoSourceInfo = VideoSourceInfo
-@typing_extensions.final
+@typing.final
class OwnedVideoSource(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -557,7 +671,7 @@ class OwnedVideoSource(google.protobuf.message.Message):
handle: handle_pb2.FfiOwnedHandle | None = ...,
info: global___VideoSourceInfo | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["handle", b"handle", "info", b"info"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["handle", b"handle", "info", b"info"]) -> None: ...
+ def HasField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing.Literal["handle", b"handle", "info", b"info"]) -> None: ...
global___OwnedVideoSource = OwnedVideoSource
diff --git a/livekit-rtc/livekit/rtc/_utils.py b/livekit-rtc/livekit/rtc/_utils.py
index a5231e71..bbaad0e1 100644
--- a/livekit-rtc/livekit/rtc/_utils.py
+++ b/livekit-rtc/livekit/rtc/_utils.py
@@ -17,7 +17,7 @@
from collections import deque
import ctypes
import random
-from typing import Callable, Generic, List, TypeVar
+from typing import Callable, Generator, Generic, List, TypeVar, Union
logger = logging.getLogger("livekit")
@@ -40,11 +40,36 @@ def task_done_logger(task: asyncio.Task) -> None:
return
-def get_address(data: memoryview) -> int:
- """Get the address of a buffer using ctypes"""
- nbytes = data.nbytes
- buffer = (ctypes.c_int8 * nbytes).from_buffer(data)
- return ctypes.addressof(buffer)
+def _ensure_compatible_buffer(
+ data: Union[bytes, bytearray, memoryview],
+) -> Union[bytes, bytearray, memoryview]:
+ """Validate and normalize a buffer for FFI use.
+
+ Sliced memoryviews are materialized because get_address cannot
+ reliably resolve their offset for all buffer types.
+ """
+ if isinstance(data, memoryview):
+ if not data.contiguous:
+ raise ValueError("memoryview must be contiguous")
+ if data.nbytes != len(data.obj): # type: ignore[arg-type]
+ return bytearray(data) if not data.readonly else bytes(data)
+ elif not isinstance(data, (bytes, bytearray)):
+ raise TypeError(f"expected bytes, bytearray, or memoryview, got {type(data)}")
+ return data
+
+
+def get_address(data: Union[bytes, bytearray, memoryview]) -> int:
+ if isinstance(data, memoryview):
+ if not data.readonly:
+ return ctypes.addressof(ctypes.c_char.from_buffer(data))
+ data = data.obj # type: ignore[assignment]
+ if isinstance(data, bytearray):
+ return ctypes.addressof(ctypes.c_char.from_buffer(data))
+ if isinstance(data, bytes):
+ addr = ctypes.cast(ctypes.c_char_p(data), ctypes.c_void_p).value
+ assert addr is not None
+ return addr
+ raise TypeError(f"expected bytes, bytearray, or memoryview, got {type(data)}")
T = TypeVar("T")
@@ -58,7 +83,7 @@ def __init__(self, capacity: int = 0) -> None:
def put(self, item: T) -> None:
if self._capacity > 0 and len(self._queue) == self._capacity:
- self._queue.pop()
+ self._queue.popleft()
self._queue.append(item)
self._event.set()
@@ -130,3 +155,16 @@ def generate_random_base62(length=12):
"""
global _base62_characters
return "".join(random.choice(_base62_characters) for _ in range(length))
+
+
+# adapted from https://stackoverflow.com/a/6043797
+def split_utf8(s: str, n: int) -> Generator[bytes, None, None]:
+ """Split UTF-8 s into chunks of maximum length n."""
+ encoded = s.encode()
+ while len(encoded) > n:
+ k = n
+ while (encoded[k] & 0xC0) == 0x80:
+ k -= 1
+ yield encoded[:k]
+ encoded = encoded[k:]
+ yield encoded
diff --git a/livekit-rtc/livekit/rtc/apm.py b/livekit-rtc/livekit/rtc/apm.py
new file mode 100644
index 00000000..9fda2ce9
--- /dev/null
+++ b/livekit-rtc/livekit/rtc/apm.py
@@ -0,0 +1,119 @@
+from __future__ import annotations
+
+from ._ffi_client import FfiClient, FfiHandle
+from ._proto import ffi_pb2 as proto_ffi
+from ._utils import get_address
+from .audio_frame import AudioFrame
+
+
+class AudioProcessingModule:
+ """
+ Provides WebRTC audio processing capabilities including echo cancellation, noise suppression,
+ high-pass filtering, and gain control.
+ """
+
+ def __init__(
+ self,
+ *,
+ echo_cancellation: bool = False,
+ noise_suppression: bool = False,
+ high_pass_filter: bool = False,
+ auto_gain_control: bool = False,
+ ) -> None:
+ """
+ Initialize an AudioProcessingModule instance with the specified audio processing features.
+
+ Args:
+ echo_cancellation (bool, optional): Whether to enable echo cancellation.
+ noise_suppression (bool, optional): Whether to enable noise suppression.
+ high_pass_filter (bool, optional): Whether to enable a high-pass filter.
+ auto_gain_control (bool, optional): Whether to enable auto gain control.
+ """
+ req = proto_ffi.FfiRequest()
+ req.new_apm.echo_canceller_enabled = echo_cancellation
+ req.new_apm.noise_suppression_enabled = noise_suppression
+ req.new_apm.high_pass_filter_enabled = high_pass_filter
+ req.new_apm.gain_controller_enabled = auto_gain_control
+
+ resp = FfiClient.instance.request(req)
+ self._ffi_handle = FfiHandle(resp.new_apm.apm.handle.id)
+
+ def process_stream(self, data: AudioFrame) -> None:
+ """
+ Process the provided audio frame using the configured audio processing features.
+
+ The input audio frame is modified in-place (if applicable) by the underlying audio
+ processing module (e.g., echo cancellation, noise suppression, etc.).
+
+ Important:
+ Audio frames must be exactly 10 ms in duration.
+ """
+ if isinstance(data._data, bytes) or (
+ isinstance(data._data, memoryview) and data._data.readonly
+ ):
+ data._data = bytearray(data._data)
+
+ req = proto_ffi.FfiRequest()
+ req.apm_process_stream.apm_handle = self._ffi_handle.handle
+ req.apm_process_stream.data_ptr = get_address(data._data)
+ req.apm_process_stream.size = len(data._data)
+ req.apm_process_stream.sample_rate = data.sample_rate
+ req.apm_process_stream.num_channels = data.num_channels
+
+ resp = FfiClient.instance.request(req)
+
+ if resp.apm_process_stream.error:
+ raise RuntimeError(resp.apm_process_stream.error)
+
+ def process_reverse_stream(self, data: AudioFrame) -> None:
+ """
+ Process the reverse audio frame (typically used for echo cancellation in a full-duplex setup).
+
+ In an echo cancellation scenario, this method is used to process the "far-end" audio
+ prior to mixing or feeding it into the echo canceller. Like `process_stream`, the
+ input audio frame is modified in-place by the underlying processing module.
+
+ Important:
+ Audio frames must be exactly 10 ms in duration.
+ """
+ if isinstance(data._data, bytes) or (
+ isinstance(data._data, memoryview) and data._data.readonly
+ ):
+ data._data = bytearray(data._data)
+
+ req = proto_ffi.FfiRequest()
+ req.apm_process_reverse_stream.apm_handle = self._ffi_handle.handle
+ req.apm_process_reverse_stream.data_ptr = get_address(data._data)
+ req.apm_process_reverse_stream.size = len(data._data)
+ req.apm_process_reverse_stream.sample_rate = data.sample_rate
+ req.apm_process_reverse_stream.num_channels = data.num_channels
+
+ resp = FfiClient.instance.request(req)
+
+ if resp.apm_process_reverse_stream.error:
+ raise RuntimeError(resp.apm_process_reverse_stream.error)
+
+ def set_stream_delay_ms(self, delay_ms: int) -> None:
+ """
+ This must be called if and only if echo processing is enabled.
+
+ Sets the `delay` in ms between `process_reverse_stream()` receiving a far-end
+ frame and `process_stream()` receiving a near-end frame containing the
+ corresponding echo. On the client-side this can be expressed as
+ delay = (t_render - t_analyze) + (t_process - t_capture)
+ where,
+ - t_analyze is the time a frame is passed to `process_reverse_stream()` and
+ t_render is the time the first sample of the same frame is rendered by
+ the audio hardware.
+ - t_capture is the time the first sample of a frame is captured by the
+ audio hardware and t_process is the time the same frame is passed to
+ `process_stream()`.
+ """
+ req = proto_ffi.FfiRequest()
+ req.apm_set_stream_delay.apm_handle = self._ffi_handle.handle
+ req.apm_set_stream_delay.delay_ms = delay_ms
+
+ resp = FfiClient.instance.request(req)
+
+ if resp.apm_set_stream_delay.error:
+ raise RuntimeError(resp.apm_set_stream_delay.error)
diff --git a/livekit-rtc/livekit/rtc/audio_filter.py b/livekit-rtc/livekit/rtc/audio_filter.py
new file mode 100644
index 00000000..a6ec7296
--- /dev/null
+++ b/livekit-rtc/livekit/rtc/audio_filter.py
@@ -0,0 +1,23 @@
+from typing import Optional, List
+
+from ._ffi_client import FfiClient
+from ._proto import ffi_pb2 as proto_ffi
+
+
+class AudioFilter:
+ def __init__(self, module_id: str, path: str, dependencies: Optional[List[str]] = None) -> None:
+ self._path = path
+
+ req = proto_ffi.FfiRequest()
+ req.load_audio_filter_plugin.module_id = module_id
+ req.load_audio_filter_plugin.plugin_path = path
+ req.load_audio_filter_plugin.dependencies[:] = (
+ dependencies if dependencies is not None else []
+ )
+
+ resp = FfiClient.instance.request(req)
+
+ if resp.load_audio_filter_plugin.error:
+ raise Exception(
+ f"failed to initialize audio filter #{resp.load_audio_filter_plugin.error}"
+ )
diff --git a/livekit-rtc/livekit/rtc/audio_frame.py b/livekit-rtc/livekit/rtc/audio_frame.py
index 956bb5e0..ab2b7ebd 100644
--- a/livekit-rtc/livekit/rtc/audio_frame.py
+++ b/livekit-rtc/livekit/rtc/audio_frame.py
@@ -13,37 +13,80 @@
# limitations under the License.
import ctypes
-from ._ffi_client import FfiHandle, FfiClient
+from ._ffi_client import FfiHandle
from ._proto import audio_frame_pb2 as proto_audio
-from ._proto import ffi_pb2 as proto_ffi
-from ._utils import get_address
-from typing import Union
+from ._utils import _ensure_compatible_buffer, get_address
+from typing import Any, Union
class AudioFrame:
+ """
+ A class that represents a frame of audio data with specific properties such as sample rate,
+ number of channels, and samples per channel.
+
+ The format of the audio data is 16-bit signed integers (int16) interleaved by channel.
+ """
+
def __init__(
self,
data: Union[bytes, bytearray, memoryview],
sample_rate: int,
num_channels: int,
samples_per_channel: int,
+ *,
+ userdata: Union[dict[str, Any], None] = None,
) -> None:
- if len(data) < num_channels * samples_per_channel * ctypes.sizeof(
- ctypes.c_int16
- ):
+ """
+ Initialize an AudioFrame instance.
+
+ Args:
+ data (Union[bytes, bytearray, memoryview]): The raw audio data, which must be at least
+ `num_channels * samples_per_channel * sizeof(int16)` bytes long.
+ sample_rate (int): The sample rate of the audio in Hz.
+ num_channels (int): The number of audio channels (e.g., 1 for mono, 2 for stereo).
+ samples_per_channel (int): The number of samples per channel.
+
+ Raises:
+ ValueError: If the length of `data` is smaller than the required size.
+ """
+ if isinstance(data, memoryview):
+ data = data.cast("B")
+
+ data = _ensure_compatible_buffer(data)
+
+ min_size = num_channels * samples_per_channel * ctypes.sizeof(ctypes.c_int16)
+ data_len = len(data)
+
+ if data_len < min_size:
raise ValueError(
"data length must be >= num_channels * samples_per_channel * sizeof(int16)"
)
- self._data = bytearray(data)
+ if data_len % ctypes.sizeof(ctypes.c_int16) != 0:
+ # can happen if data is bigger than needed
+ raise ValueError("data length must be a multiple of sizeof(int16)")
+
+ self._data = data
+
self._sample_rate = sample_rate
self._num_channels = num_channels
self._samples_per_channel = samples_per_channel
+ self._userdata = {} if userdata is None else userdata
@staticmethod
- def create(
- sample_rate: int, num_channels: int, samples_per_channel: int
- ) -> "AudioFrame":
+ def create(sample_rate: int, num_channels: int, samples_per_channel: int) -> "AudioFrame":
+ """
+ Create a new empty AudioFrame instance with specified sample rate, number of channels,
+ and samples per channel.
+
+ Args:
+ sample_rate (int): The sample rate of the audio in Hz.
+ num_channels (int): The number of audio channels (e.g., 1 for mono, 2 for stereo).
+ samples_per_channel (int): The number of samples per channel.
+
+ Returns:
+ AudioFrame: A new AudioFrame instance with uninitialized (zeroed) data.
+ """
size = num_channels * samples_per_channel * ctypes.sizeof(ctypes.c_int16)
data = bytearray(size)
return AudioFrame(data, sample_rate, num_channels, samples_per_channel)
@@ -54,49 +97,146 @@ def _from_owned_info(owned_info: proto_audio.OwnedAudioFrameBuffer) -> "AudioFra
size = info.num_channels * info.samples_per_channel
cdata = (ctypes.c_int16 * size).from_address(info.data_ptr)
data = bytearray(cdata)
- FfiHandle(owned_info.handle.id)
- return AudioFrame(
- data, info.sample_rate, info.num_channels, info.samples_per_channel
- )
-
- def remix_and_resample(self, sample_rate: int, num_channels: int) -> "AudioFrame":
- """Resample the audio frame to the given sample rate and number of channels."""
-
- req = proto_ffi.FfiRequest()
- req.new_audio_resampler.CopyFrom(proto_audio.NewAudioResamplerRequest())
-
- resp = FfiClient.instance.request(req)
- resampler_handle = FfiHandle(resp.new_audio_resampler.resampler.handle.id)
-
- resample_req = proto_ffi.FfiRequest()
- resample_req.remix_and_resample.resampler_handle = resampler_handle.handle
- resample_req.remix_and_resample.buffer.CopyFrom(self._proto_info())
- resample_req.remix_and_resample.sample_rate = sample_rate
- resample_req.remix_and_resample.num_channels = num_channels
-
- resp = FfiClient.instance.request(resample_req)
- return AudioFrame._from_owned_info(resp.remix_and_resample.buffer)
+ FfiHandle(owned_info.handle.id).dispose()
+ return AudioFrame(data, info.sample_rate, info.num_channels, info.samples_per_channel)
def _proto_info(self) -> proto_audio.AudioFrameBufferInfo:
audio_info = proto_audio.AudioFrameBufferInfo()
- audio_info.data_ptr = get_address(memoryview(self._data))
+ audio_info.data_ptr = get_address(self._data)
audio_info.sample_rate = self.sample_rate
audio_info.num_channels = self.num_channels
audio_info.samples_per_channel = self.samples_per_channel
return audio_info
+ @property
+ def userdata(self) -> dict[str, Any]:
+ """
+ Returns the user data associated with the audio frame.
+ """
+ return self._userdata
+
@property
def data(self) -> memoryview:
- return memoryview(self._data).cast("h")
+ """
+ Returns a memory view of the audio data as 16-bit signed integers.
+
+ Returns:
+ memoryview: A memory view of the audio data.
+ """
+ return memoryview(self._data).cast("B").cast("h")
@property
def sample_rate(self) -> int:
+ """
+ Returns the sample rate of the audio frame.
+
+ Returns:
+ int: The sample rate in Hz.
+ """
return self._sample_rate
@property
def num_channels(self) -> int:
+ """
+ Returns the number of channels in the audio frame.
+
+ Returns:
+ int: The number of audio channels (e.g., 1 for mono, 2 for stereo).
+ """
return self._num_channels
@property
def samples_per_channel(self) -> int:
+ """
+ Returns the number of samples per channel.
+
+ Returns:
+ int: The number of samples per channel.
+ """
return self._samples_per_channel
+
+ @property
+ def duration(self) -> float:
+ """
+ Returns the duration of the audio frame in seconds.
+
+ Returns:
+ float: The duration in seconds.
+ """
+ return self.samples_per_channel / self.sample_rate
+
+ def to_wav_bytes(self) -> bytes:
+ """
+ Convert the audio frame data to a WAV-formatted byte stream.
+
+ Returns:
+ bytes: The audio data encoded in WAV format.
+ """
+ import wave
+ import io
+
+ with io.BytesIO() as wav_file:
+ with wave.open(wav_file, "wb") as wav:
+ wav.setnchannels(self.num_channels)
+ wav.setsampwidth(2)
+ wav.setframerate(self.sample_rate)
+ wav.writeframes(self._data)
+
+ return wav_file.getvalue()
+
+ def __repr__(self) -> str:
+ return (
+ f"rtc.AudioFrame(sample_rate={self.sample_rate}, "
+ f"num_channels={self.num_channels}, "
+ f"samples_per_channel={self.samples_per_channel}, "
+ f"duration={self.duration:.3f})"
+ )
+
+ @classmethod
+ def __get_pydantic_core_schema__(cls, *_: Any):
+ from pydantic_core import core_schema
+ import base64
+
+ def validate_audio_frame(value: Any) -> "AudioFrame":
+ if isinstance(value, AudioFrame):
+ return value
+
+ if isinstance(value, tuple):
+ value = value[0]
+
+ if isinstance(value, dict):
+ return AudioFrame(
+ data=base64.b64decode(value["data"]),
+ sample_rate=value["sample_rate"],
+ num_channels=value["num_channels"],
+ samples_per_channel=value["samples_per_channel"],
+ )
+
+ raise TypeError("Invalid type for AudioFrame")
+
+ return core_schema.json_or_python_schema(
+ json_schema=core_schema.chain_schema(
+ [
+ core_schema.model_fields_schema(
+ {
+ "data": core_schema.model_field(core_schema.str_schema()),
+ "sample_rate": core_schema.model_field(core_schema.int_schema()),
+ "num_channels": core_schema.model_field(core_schema.int_schema()),
+ "samples_per_channel": core_schema.model_field(
+ core_schema.int_schema()
+ ),
+ },
+ ),
+ core_schema.no_info_plain_validator_function(validate_audio_frame),
+ ]
+ ),
+ python_schema=core_schema.no_info_plain_validator_function(validate_audio_frame),
+ serialization=core_schema.plain_serializer_function_ser_schema(
+ lambda instance: {
+ "data": base64.b64encode(instance.data).decode("utf-8"),
+ "sample_rate": instance.sample_rate,
+ "num_channels": instance.num_channels,
+ "samples_per_channel": instance.samples_per_channel,
+ }
+ ),
+ )
diff --git a/livekit-rtc/livekit/rtc/audio_mixer.py b/livekit-rtc/livekit/rtc/audio_mixer.py
new file mode 100644
index 00000000..e2f28c6b
--- /dev/null
+++ b/livekit-rtc/livekit/rtc/audio_mixer.py
@@ -0,0 +1,200 @@
+import asyncio
+import numpy as np
+import contextlib
+from dataclasses import dataclass
+from typing import AsyncIterator, Optional
+from .audio_frame import AudioFrame
+from .log import logger
+
+_Stream = AsyncIterator[AudioFrame]
+
+
+@dataclass
+class _Contribution:
+ stream: _Stream
+ data: np.ndarray
+ buffer: np.ndarray
+ had_data: bool
+ exhausted: bool
+
+
+class AudioMixer:
+ def __init__(
+ self,
+ sample_rate: int,
+ num_channels: int,
+ *,
+ blocksize: int = 0,
+ stream_timeout_ms: int = 100,
+ capacity: int = 100,
+ ) -> None:
+ """
+ Initialize the AudioMixer.
+
+ The mixer accepts multiple async audio streams and mixes them into a single output stream.
+ Each output frame is generated with a fixed chunk size determined by the blocksize (in samples).
+ If blocksize is not provided (or 0), it defaults to 100ms.
+
+ Each input stream is processed in parallel, accumulating audio data until at least one chunk
+ of samples is available. If an input stream does not provide data within the specified timeout,
+ a warning is logged. The mixer can be closed immediately
+ (dropping unconsumed frames) or allowed to flush remaining data using end_input().
+
+ Args:
+ sample_rate (int): The audio sample rate in Hz.
+ num_channels (int): The number of audio channels.
+ blocksize (int, optional): The size of the audio block (in samples) for mixing. If not provided,
+ defaults to sample_rate // 10.
+ stream_timeout_ms (int, optional): The maximum wait time in milliseconds for each stream to provide
+ audio data before timing out. Defaults to 100 ms.
+ capacity (int, optional): The maximum number of mixed frames to store in the output queue.
+ Defaults to 100.
+ """
+ self._streams: set[_Stream] = set()
+ self._buffers: dict[_Stream, np.ndarray] = {}
+ self._sample_rate: int = sample_rate
+ self._num_channels: int = num_channels
+ self._chunk_size: int = blocksize if blocksize > 0 else int(sample_rate // 10)
+ self._stream_timeout_ms: int = stream_timeout_ms
+ self._queue: asyncio.Queue[Optional[AudioFrame]] = asyncio.Queue(maxsize=capacity)
+ # _ending signals that no new streams will be added,
+ # but we continue processing until all streams are exhausted.
+ self._ending: bool = False
+ self._mixer_task: asyncio.Task = asyncio.create_task(self._mixer())
+
+ def add_stream(self, stream: AsyncIterator[AudioFrame]) -> None:
+ """
+ Add an audio stream to the mixer.
+
+ The stream is added to the internal set of streams and an empty buffer is initialized for it,
+ if not already present.
+
+ Args:
+ stream (AsyncIterator[AudioFrame]): An async iterator that produces AudioFrame objects.
+ """
+ if self._ending:
+ raise RuntimeError("Cannot add stream after mixer has been closed")
+
+ self._streams.add(stream)
+ if stream not in self._buffers:
+ self._buffers[stream] = np.empty((0, self._num_channels), dtype=np.int16)
+
+ def remove_stream(self, stream: AsyncIterator[AudioFrame]) -> None:
+ """
+ Remove an audio stream from the mixer.
+
+ This method removes the specified stream and its associated buffer from the mixer.
+
+ Args:
+ stream (AsyncIterator[AudioFrame]): The audio stream to remove.
+ """
+ self._streams.discard(stream)
+ self._buffers.pop(stream, None)
+
+ def __aiter__(self) -> "AudioMixer":
+ return self
+
+ async def __anext__(self) -> AudioFrame:
+ item = await self._queue.get()
+ if item is None:
+ raise StopAsyncIteration
+ return item
+
+ async def aclose(self) -> None:
+ """
+ Immediately stop mixing and close the mixer.
+
+ This cancels the mixing task, and any unconsumed output in the queue may be dropped.
+ """
+ self._ending = True
+ self._mixer_task.cancel()
+ with contextlib.suppress(asyncio.CancelledError):
+ await self._mixer_task
+
+ def end_input(self) -> None:
+ """
+ Signal that no more streams will be added.
+
+ This method marks the mixer as closed so that it flushes any remaining buffered output before ending.
+ Note that existing streams will still be processed until exhausted.
+ """
+ self._ending = True
+
+ async def _mixer(self) -> None:
+ while True:
+ # If we're in ending mode and there are no more streams, exit.
+ if self._ending and not self._streams:
+ break
+
+ if not self._streams:
+ await asyncio.sleep(0.01)
+ continue
+
+ tasks = [
+ self._get_contribution(
+ stream,
+ self._buffers.get(stream, np.empty((0, self._num_channels), dtype=np.int16)),
+ )
+ for stream in list(self._streams)
+ ]
+ results = await asyncio.gather(*tasks, return_exceptions=True)
+ contributions = []
+ any_data = False
+ removals = []
+ for contrib in results:
+ if not isinstance(contrib, _Contribution):
+ continue
+
+ contributions.append(contrib.data.astype(np.float32))
+ self._buffers[contrib.stream] = contrib.buffer
+ if contrib.had_data:
+ any_data = True
+ if contrib.exhausted and contrib.buffer.shape[0] == 0:
+ removals.append(contrib.stream)
+
+ for stream in removals:
+ self.remove_stream(stream)
+
+ if not any_data:
+ await asyncio.sleep(0.001)
+ continue
+
+ mixed = np.sum(np.stack(contributions, axis=0), axis=0)
+ mixed = np.clip(mixed, -32768, 32767).astype(np.int16)
+ frame = AudioFrame(
+ mixed.tobytes(), self._sample_rate, self._num_channels, self._chunk_size
+ )
+ await self._queue.put(frame)
+
+ await self._queue.put(None)
+
+ async def _get_contribution(
+ self, stream: AsyncIterator[AudioFrame], buf: np.ndarray
+ ) -> _Contribution:
+ had_data = buf.shape[0] > 0
+ exhausted = False
+ while buf.shape[0] < self._chunk_size and not exhausted:
+ try:
+ frame = await asyncio.wait_for(
+ stream.__anext__(), timeout=self._stream_timeout_ms / 1000
+ )
+ except asyncio.TimeoutError:
+ logger.warning(f"AudioMixer: stream {stream} timeout, ignoring")
+ break
+ except StopAsyncIteration:
+ exhausted = True
+ break
+ new_data = np.frombuffer(frame.data.tobytes(), dtype=np.int16).reshape(
+ -1, self._num_channels
+ )
+ buf = np.concatenate((buf, new_data), axis=0) if buf.size else new_data
+ had_data = True
+ if buf.shape[0] >= self._chunk_size:
+ contrib, buf = buf[: self._chunk_size], buf[self._chunk_size :]
+ else:
+ pad = np.zeros((self._chunk_size - buf.shape[0], self._num_channels), dtype=np.int16)
+ contrib, buf = (
+ np.concatenate((buf, pad), axis=0),
+ np.empty((0, self._num_channels), dtype=np.int16),
+ )
+ return _Contribution(stream, contrib, buf, had_data, exhausted)
diff --git a/livekit-rtc/livekit/rtc/audio_resampler.py b/livekit-rtc/livekit/rtc/audio_resampler.py
new file mode 100644
index 00000000..4d4c02c5
--- /dev/null
+++ b/livekit-rtc/livekit/rtc/audio_resampler.py
@@ -0,0 +1,174 @@
+from __future__ import annotations
+
+import ctypes
+from enum import Enum, unique
+
+from ._proto import audio_frame_pb2 as proto_audio_frame
+from ._ffi_client import FfiClient, FfiHandle
+from ._proto import ffi_pb2 as proto_ffi
+from ._utils import get_address
+from .audio_frame import AudioFrame
+
+
+@unique
+class AudioResamplerQuality(str, Enum):
+ QUICK = "quick"
+ LOW = "low"
+ MEDIUM = "medium"
+ HIGH = "high"
+ VERY_HIGH = "very_high"
+
+
+class AudioResampler:
+ """
+ A class for resampling audio data from one sample rate to another.
+
+ `AudioResampler` provides functionality to resample audio data from an input sample rate to an output
+ sample rate using the Sox resampling library. It supports multiple channels and configurable resampling quality.
+ """
+
+ def __init__(
+ self,
+ input_rate: int,
+ output_rate: int,
+ *,
+ num_channels: int = 1,
+ quality: AudioResamplerQuality = AudioResamplerQuality.MEDIUM,
+ ) -> None:
+ """
+ Initialize an `AudioResampler` instance for resampling audio data.
+
+ Args:
+ input_rate (int): The sample rate of the input audio data (in Hz).
+ output_rate (int): The desired sample rate of the output audio data (in Hz).
+ num_channels (int, optional): The number of audio channels (e.g., 1 for mono, 2 for stereo). Defaults to 1.
+ quality (AudioResamplerQuality, optional): The quality setting for the resampler. Can be one of the
+ `AudioResamplerQuality` enum values: `QUICK`, `LOW`, `MEDIUM`, `HIGH`, `VERY_HIGH`. Higher quality settings
+ result in better audio quality but require more processing power. Defaults to `AudioResamplerQuality.MEDIUM`.
+
+ Raises:
+ Exception: If there is an error creating the resampler.
+ """
+ self._input_rate = input_rate
+ self._output_rate = output_rate
+ self._num_channels = num_channels
+
+ req = proto_ffi.FfiRequest()
+ req.new_sox_resampler.input_rate = input_rate
+ req.new_sox_resampler.output_rate = output_rate
+ req.new_sox_resampler.num_channels = num_channels
+ req.new_sox_resampler.quality_recipe = _to_proto_quality(quality)
+
+ # not exposed for now
+ req.new_sox_resampler.input_data_type = (
+ proto_audio_frame.SoxResamplerDataType.SOXR_DATATYPE_INT16I
+ )
+ req.new_sox_resampler.output_data_type = (
+ proto_audio_frame.SoxResamplerDataType.SOXR_DATATYPE_INT16I
+ )
+ req.new_sox_resampler.flags = 0 # default
+
+ resp = FfiClient.instance.request(req)
+
+ if resp.new_sox_resampler.error:
+ raise Exception(resp.new_sox_resampler.error)
+
+ self._ffi_handle = FfiHandle(resp.new_sox_resampler.resampler.handle.id)
+
+ def push(self, data: bytearray | AudioFrame) -> list[AudioFrame]:
+ """
+ Push audio data into the resampler and retrieve any available resampled data.
+
+ This method accepts audio data, resamples it according to the configured input and output rates,
+ and returns any resampled data that is available after processing the input.
+
+ Args:
+ data (bytearray | AudioFrame): The audio data to resample. This can be a `bytearray` containing
+ raw audio bytes in int16le format or an `AudioFrame` object.
+
+ Returns:
+ list[AudioFrame]: A list of `AudioFrame` objects containing the resampled audio data.
+ The list may be empty if no output data is available yet.
+
+ Raises:
+ Exception: If there is an error during resampling.
+ """
+ bdata = data if isinstance(data, bytearray) else data.data.cast("b")
+ if not bdata:
+ return []
+
+ req = proto_ffi.FfiRequest()
+ req.push_sox_resampler.resampler_handle = self._ffi_handle.handle
+ req.push_sox_resampler.data_ptr = get_address(memoryview(bdata))
+ req.push_sox_resampler.size = len(bdata)
+
+ resp = FfiClient.instance.request(req)
+
+ if resp.push_sox_resampler.error:
+ raise Exception(resp.push_sox_resampler.error)
+
+ if not resp.push_sox_resampler.output_ptr:
+ return []
+
+ cdata = (ctypes.c_int8 * resp.push_sox_resampler.size).from_address(
+ resp.push_sox_resampler.output_ptr
+ )
+ output_data = bytearray(cdata)
+ return [
+ AudioFrame(
+ output_data,
+ self._output_rate,
+ self._num_channels,
+ len(output_data) // (self._num_channels * ctypes.sizeof(ctypes.c_int16)),
+ )
+ ]
+
+ def flush(self) -> list[AudioFrame]:
+ """
+ Flush any remaining audio data through the resampler and retrieve the resampled data.
+
+ This method should be called when no more input data will be provided to ensure that all internal
+ buffers are processed and all resampled data is output.
+
+ Returns:
+ list[AudioFrame]: A list of `AudioFrame` objects containing the remaining resampled audio data after flushing.
+ The list may be empty if no output data remains.
+
+ Raises:
+ Exception: If there is an error during flushing.
+ """
+ req = proto_ffi.FfiRequest()
+ req.flush_sox_resampler.resampler_handle = self._ffi_handle.handle
+
+ resp = FfiClient.instance.request(req)
+
+ if not resp.flush_sox_resampler.output_ptr:
+ return []
+
+ cdata = (ctypes.c_int8 * resp.flush_sox_resampler.size).from_address(
+ resp.flush_sox_resampler.output_ptr
+ )
+ output_data = bytearray(cdata)
+ return [
+ AudioFrame(
+ output_data,
+ self._output_rate,
+ self._num_channels,
+ len(output_data) // (self._num_channels * ctypes.sizeof(ctypes.c_int16)),
+ )
+ ]
+
+
+def _to_proto_quality(
+ quality: AudioResamplerQuality,
+) -> proto_audio_frame.SoxQualityRecipe.ValueType:
+ if quality == AudioResamplerQuality.QUICK:
+ return proto_audio_frame.SoxQualityRecipe.SOXR_QUALITY_QUICK
+ elif quality == AudioResamplerQuality.LOW:
+ return proto_audio_frame.SoxQualityRecipe.SOXR_QUALITY_LOW
+ elif quality == AudioResamplerQuality.MEDIUM:
+ return proto_audio_frame.SoxQualityRecipe.SOXR_QUALITY_MEDIUM
+ elif quality == AudioResamplerQuality.HIGH:
+ return proto_audio_frame.SoxQualityRecipe.SOXR_QUALITY_HIGH
+ elif quality == AudioResamplerQuality.VERY_HIGH:
+ return proto_audio_frame.SoxQualityRecipe.SOXR_QUALITY_VERYHIGH
diff --git a/livekit-rtc/livekit/rtc/audio_source.py b/livekit-rtc/livekit/rtc/audio_source.py
index 4419062a..63cc1a5d 100644
--- a/livekit-rtc/livekit/rtc/audio_source.py
+++ b/livekit-rtc/livekit/rtc/audio_source.py
@@ -12,6 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+from __future__ import annotations
+
+import time
+import asyncio
+
from ._ffi_client import FfiHandle, FfiClient
from ._proto import audio_frame_pb2 as proto_audio_frame
from ._proto import ffi_pb2 as proto_ffi
@@ -19,50 +24,158 @@
class AudioSource:
- def __init__(self, sample_rate: int, num_channels: int) -> None:
- req = proto_ffi.FfiRequest()
- req.new_audio_source.type = (
- proto_audio_frame.AudioSourceType.AUDIO_SOURCE_NATIVE
- )
- req.new_audio_source.sample_rate = sample_rate
- req.new_audio_source.num_channels = num_channels
+ """
+ Represents a real-time audio source with an internal audio queue.
+
+ The `AudioSource` class allows you to push audio frames into a real-time audio
+ source, managing an internal queue of audio data up to a maximum duration defined
+ by `queue_size_ms`. It supports asynchronous operations to capture audio frames
+ and to wait for the playback of all queued audio data.
+ """
+ def __init__(
+ self,
+ sample_rate: int,
+ num_channels: int,
+ queue_size_ms: int = 1000,
+ loop: asyncio.AbstractEventLoop | None = None,
+ ) -> None:
+ """
+ Initializes a new instance of the audio source.
+
+ Args:
+ sample_rate (int): The sample rate of the audio source in Hz.
+ num_channels (int): The number of audio channels.
+ queue_size_ms (int, optional): The buffer size of the audio queue in milliseconds.
+ Defaults to 1000 ms.
+ loop (asyncio.AbstractEventLoop, optional): The event loop to use. Defaults to
+ `asyncio.get_event_loop()`.
+ """
self._sample_rate = sample_rate
self._num_channels = num_channels
+ self._loop = loop or asyncio.get_event_loop()
+
+ req = proto_ffi.FfiRequest()
+ req.new_audio_source.type = proto_audio_frame.AudioSourceType.AUDIO_SOURCE_NATIVE
+ req.new_audio_source.sample_rate = sample_rate
+ req.new_audio_source.num_channels = num_channels
+ req.new_audio_source.queue_size_ms = queue_size_ms
resp = FfiClient.instance.request(req)
self._info = resp.new_audio_source.source
self._ffi_handle = FfiHandle(self._info.handle.id)
+ self._last_capture = 0.0
+ self._q_size = 0.0
+ self._join_handle: asyncio.TimerHandle | None = None
+ self._join_fut: asyncio.Future[None] | None = None
+
@property
def sample_rate(self) -> int:
+ """The sample rate of the audio source in Hz."""
return self._sample_rate
@property
def num_channels(self) -> int:
+ """The number of audio channels."""
return self._num_channels
- async def capture_frame(self, frame: AudioFrame) -> None:
- """Captures an AudioFrame.
+ @property
+ def queued_duration(self) -> float:
+ """The current duration (in seconds) of audio data queued for playback."""
+ return max(self._q_size - time.monotonic() + self._last_capture, 0.0)
- Used to push new audio data into the published Track. Audio data will
- be pushed in chunks of 10ms. It'll return only when all of the data in
- the buffer has been pushed.
+ def clear_queue(self) -> None:
+ """
+ Clears the internal audio queue, discarding all buffered audio data.
+
+ This method immediately removes all audio data currently queued for playback,
+ effectively resetting the audio source's buffer. Any audio frames that have been
+ captured but not yet played will be discarded. This is useful in scenarios where
+ you need to stop playback abruptly or prevent outdated audio data from being played.
"""
req = proto_ffi.FfiRequest()
+ req.clear_audio_buffer.source_handle = self._ffi_handle.handle
+ _ = FfiClient.instance.request(req)
+ self._release_waiter()
+
+ async def capture_frame(self, frame: AudioFrame) -> None:
+ """
+ Captures an `AudioFrame` and queues it for playback.
+
+ This method is used to push new audio data into the audio source. The audio data
+ will be processed and queued. If the size of the audio frame exceeds the internal
+ queue size, the method will wait until there is enough space in the queue to
+ accommodate the frame. The method returns only when all of the data in the buffer
+ has been pushed.
+ Args:
+ frame (AudioFrame): The audio frame to capture and queue.
+
+ Raises:
+ Exception: If there is an error during frame capture.
+ """
+
+ if frame.samples_per_channel == 0 or self._ffi_handle.disposed:
+ return
+
+ now = time.monotonic()
+ elapsed = 0.0 if self._last_capture == 0.0 else now - self._last_capture
+ self._q_size += frame.samples_per_channel / self.sample_rate - elapsed
+ self._last_capture = now
+
+ if self._join_handle:
+ self._join_handle.cancel()
+
+ if self._join_fut is None:
+ self._join_fut = self._loop.create_future()
+
+ self._join_handle = self._loop.call_later(self._q_size, self._release_waiter)
+
+ req = proto_ffi.FfiRequest()
req.capture_audio_frame.source_handle = self._ffi_handle.handle
req.capture_audio_frame.buffer.CopyFrom(frame._proto_info())
- queue = FfiClient.instance.queue.subscribe()
+ queue = FfiClient.instance.queue.subscribe(loop=self._loop)
try:
resp = FfiClient.instance.request(req)
- cb = await queue.wait_for(
- lambda e: e.capture_audio_frame.async_id
- == resp.capture_audio_frame.async_id
+ cb: proto_ffi.FfiEvent = await queue.wait_for(
+ lambda e: e.capture_audio_frame.async_id == resp.capture_audio_frame.async_id
)
finally:
FfiClient.instance.queue.unsubscribe(queue)
if cb.capture_audio_frame.error:
raise Exception(cb.capture_audio_frame.error)
+
+ async def wait_for_playout(self) -> None:
+ """
+ Waits for the audio source to finish playing out all audio data.
+
+ This method ensures that all queued audio data has been played out before returning.
+ It can be used to synchronize events after audio playback or to ensure that the
+ audio queue is empty.
+ """
+
+ if self._join_fut is None:
+ return
+
+ await asyncio.shield(self._join_fut)
+
+ def _release_waiter(self) -> None:
+ if self._join_fut is None:
+ return # could be None when clear_queue is called
+
+ if not self._join_fut.done():
+ self._join_fut.set_result(None)
+
+ self._last_capture = 0.0
+ self._q_size = 0.0
+ self._join_fut = None
+
+ async def aclose(self) -> None:
+ """Close the audio source
+
+ This method cleans up resources associated with the audio source.
+ """
+ self._ffi_handle.dispose()
diff --git a/livekit-rtc/livekit/rtc/audio_stream.py b/livekit-rtc/livekit/rtc/audio_stream.py
index 0a275a35..0f949d40 100644
--- a/livekit-rtc/livekit/rtc/audio_stream.py
+++ b/livekit-rtc/livekit/rtc/audio_stream.py
@@ -12,79 +12,312 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+from __future__ import annotations
+
import asyncio
-from typing import Optional
+import json
+from dataclasses import dataclass
+from typing import Any, AsyncIterator, Optional
-from ._ffi_client import FfiHandle, FfiClient
+from ._ffi_client import FfiClient, FfiHandle
from ._proto import audio_frame_pb2 as proto_audio_frame
from ._proto import ffi_pb2 as proto_ffi
+from ._proto.track_pb2 import TrackSource
from ._utils import RingQueue, task_done_logger
from .audio_frame import AudioFrame
+from .log import logger
+from .participant import Participant
from .track import Track
-from dataclasses import dataclass
+from .frame_processor import FrameProcessor
@dataclass
class AudioFrameEvent:
+ """An event representing a received audio frame.
+
+ Attributes:
+ frame (AudioFrame): The received audio frame.
+ """
+
frame: AudioFrame
+@dataclass
+class NoiseCancellationOptions:
+ module_id: str
+ options: dict[str, Any]
+
+
class AudioStream:
- """AudioStream is a stream of audio frames received from a RemoteTrack."""
+ """An asynchronous audio stream for receiving audio frames from a participant or track.
+
+ The `AudioStream` class provides an asynchronous iterator over audio frames received from
+ a specific track or participant. It allows you to receive audio frames in real-time with
+ customizable sample rates and channel configurations.
+ """
def __init__(
self,
track: Track,
loop: Optional[asyncio.AbstractEventLoop] = None,
capacity: int = 0,
+ sample_rate: int = 48000,
+ num_channels: int = 1,
+ frame_size_ms: int | None = None,
+ noise_cancellation: Optional[NoiseCancellationOptions | FrameProcessor[AudioFrame]] = None,
+ **kwargs,
) -> None:
- self._track = track
- self._loop = loop or asyncio.get_event_loop()
- self._ffi_queue = FfiClient.instance.queue.subscribe(self._loop)
- self._queue: RingQueue[AudioFrameEvent] = RingQueue(capacity)
+ """Initialize an `AudioStream` instance.
- req = proto_ffi.FfiRequest()
- new_audio_stream = req.new_audio_stream
- new_audio_stream.track_handle = track._ffi_handle.handle
- new_audio_stream.type = proto_audio_frame.AudioStreamType.AUDIO_STREAM_NATIVE
- resp = FfiClient.instance.request(req)
+ Args:
+ track (Optional[Track]): The audio track from which to receive audio. If not provided,
+ you must specify `participant` and `track_source` in `kwargs`.
+ loop (Optional[asyncio.AbstractEventLoop], optional): The event loop to use.
+ Defaults to the current event loop.
+ capacity (int, optional): The capacity of the internal frame queue. Defaults to 0 (unbounded).
+ sample_rate (int, optional): The sample rate for the audio stream in Hz.
+ Defaults to 48000.
+ num_channels (int, optional): The number of audio channels. Defaults to 1.
+ noise_cancellation (Optional[NoiseCancellationOptions | FrameProcessor[AudioFrame]], optional):
+ If noise cancellation is used, pass a `NoiseCancellationOptions` or `FrameProcessor[AudioFrame]` instance
+ created by the noise cancellation module.
+
+ Example:
+ ```python
+ audio_stream = AudioStream(
+ track=audio_track,
+ sample_rate=44100,
+ num_channels=2,
+ )
- stream_info = resp.new_audio_stream.stream
- self._ffi_handle = FfiHandle(stream_info.handle.id)
- self._info = stream_info
+ audio_stream = AudioStream.from_track(
+ track=audio_track,
+ sample_rate=44100,
+ num_channels=2,
+ )
+ ```
+ """
+ self._track: Track | None = track
+ self._sample_rate = sample_rate
+ self._num_channels = num_channels
+ self._frame_size_ms = frame_size_ms
+ self._loop = loop or asyncio.get_event_loop()
+ # Only subscribe to audio_stream_event to avoid unnecessary memory allocations
+ # from other event types (room_event, track_event, etc.)
+ self._ffi_queue = FfiClient.instance.queue.subscribe(
+ self._loop,
+ filter_fn=lambda e: e.WhichOneof("message") == "audio_stream_event",
+ )
+ self._queue: RingQueue[AudioFrameEvent | None] = RingQueue(capacity)
+
+ self._audio_filter_module: str | None = None
+ self._audio_filter_options: dict[str, Any] | None = None
+ self._processor: FrameProcessor[AudioFrame] | None = None
+ if isinstance(noise_cancellation, NoiseCancellationOptions):
+ self._audio_filter_module = noise_cancellation.module_id
+ self._audio_filter_options = noise_cancellation.options
+ elif isinstance(noise_cancellation, FrameProcessor):
+ self._processor = noise_cancellation
self._task = self._loop.create_task(self._run())
self._task.add_done_callback(task_done_logger)
+ stream: Any = None
+ if "participant" in kwargs:
+ stream = self._create_owned_stream_from_participant(
+ participant=kwargs["participant"], track_source=kwargs["track_source"]
+ )
+ else:
+ stream = self._create_owned_stream()
+ self._ffi_handle = FfiHandle(stream.handle.id)
+ self._info = stream.info
+
+ @classmethod
+ def from_participant(
+ cls,
+ *,
+ participant: Participant,
+ track_source: TrackSource.ValueType,
+ loop: Optional[asyncio.AbstractEventLoop] = None,
+ capacity: int = 0,
+ sample_rate: int = 48000,
+ num_channels: int = 1,
+ frame_size_ms: int | None = None,
+ noise_cancellation: Optional[NoiseCancellationOptions | FrameProcessor[AudioFrame]] = None,
+ ) -> AudioStream:
+ """Create an `AudioStream` from a participant's audio track.
+
+ Args:
+ participant (Participant): The participant from whom to receive audio.
+ track_source (TrackSource.ValueType): The source of the audio track (e.g., microphone, screen share).
+ loop (Optional[asyncio.AbstractEventLoop], optional): The event loop to use. Defaults to the current event loop.
+ capacity (int, optional): The capacity of the internal frame queue. Defaults to 0 (unbounded).
+ sample_rate (int, optional): The sample rate for the audio stream in Hz. Defaults to 48000.
+ num_channels (int, optional): The number of audio channels. Defaults to 1.
+ noise_cancellation (Optional[NoiseCancellationOptions], optional):
+ If noise cancellation is used, pass a `NoiseCancellationOptions` instance
+ created by the noise cancellation module.
+
+ Returns:
+ AudioStream: An instance of `AudioStream` that can be used to receive audio frames.
+
+ Example:
+ ```python
+ audio_stream = AudioStream.from_participant(
+ participant=participant,
+ track_source=TrackSource.MICROPHONE,
+ sample_rate=24000,
+ num_channels=1,
+ )
+ ```
+ """
+ return AudioStream(
+ participant=participant,
+ track_source=track_source,
+ loop=loop,
+ capacity=capacity,
+ track=None, # type: ignore
+ sample_rate=sample_rate,
+ num_channels=num_channels,
+ noise_cancellation=noise_cancellation,
+ frame_size_ms=frame_size_ms,
+ )
+
+ @classmethod
+ def from_track(
+ cls,
+ *,
+ track: Track,
+ loop: Optional[asyncio.AbstractEventLoop] = None,
+ capacity: int = 0,
+ sample_rate: int = 48000,
+ num_channels: int = 1,
+ frame_size_ms: int | None = None,
+ noise_cancellation: Optional[NoiseCancellationOptions | FrameProcessor[AudioFrame]] = None,
+ ) -> AudioStream:
+ """Create an `AudioStream` from an existing audio track.
+
+ Args:
+ track (Track): The audio track from which to receive audio.
+ loop (Optional[asyncio.AbstractEventLoop], optional): The event loop to use. Defaults to the current event loop.
+ capacity (int, optional): The capacity of the internal frame queue. Defaults to 0 (unbounded).
+ sample_rate (int, optional): The sample rate for the audio stream in Hz. Defaults to 48000.
+ num_channels (int, optional): The number of audio channels. Defaults to 1.
+ noise_cancellation (Optional[NoiseCancellationOptions], optional):
+ If noise cancellation is used, pass a `NoiseCancellationOptions` instance
+ created by the noise cancellation module.
+
+ Returns:
+ AudioStream: An instance of `AudioStream` that can be used to receive audio frames.
+
+ Example:
+ ```python
+ audio_stream = AudioStream.from_track(
+ track=audio_track,
+ sample_rate=44100,
+ num_channels=2,
+ )
+ ```
+ """
+ return AudioStream(
+ track=track,
+ loop=loop,
+ capacity=capacity,
+ sample_rate=sample_rate,
+ num_channels=num_channels,
+ noise_cancellation=noise_cancellation,
+ frame_size_ms=frame_size_ms,
+ )
+
def __del__(self) -> None:
FfiClient.instance.queue.unsubscribe(self._ffi_queue)
+ def _create_owned_stream(self) -> Any:
+ assert self._track is not None
+ req = proto_ffi.FfiRequest()
+ new_audio_stream = req.new_audio_stream
+ new_audio_stream.track_handle = self._track._ffi_handle.handle
+ new_audio_stream.sample_rate = self._sample_rate
+ new_audio_stream.num_channels = self._num_channels
+ new_audio_stream.queue_size_frames = 0
+ if self._frame_size_ms:
+ new_audio_stream.frame_size_ms = self._frame_size_ms
+ new_audio_stream.type = proto_audio_frame.AudioStreamType.AUDIO_STREAM_NATIVE
+ if self._audio_filter_module is not None:
+ new_audio_stream.audio_filter_module_id = self._audio_filter_module
+ if self._audio_filter_options is not None:
+ new_audio_stream.audio_filter_options = json.dumps(self._audio_filter_options)
+ resp = FfiClient.instance.request(req)
+ return resp.new_audio_stream.stream
+
+ def _create_owned_stream_from_participant(
+ self, participant: Participant, track_source: TrackSource.ValueType
+ ) -> Any:
+ req = proto_ffi.FfiRequest()
+ audio_stream_from_participant = req.audio_stream_from_participant
+ audio_stream_from_participant.participant_handle = participant._ffi_handle.handle
+ audio_stream_from_participant.sample_rate = self._sample_rate
+ audio_stream_from_participant.num_channels = self._num_channels
+ audio_stream_from_participant.queue_size_frames = 0
+ audio_stream_from_participant.type = proto_audio_frame.AudioStreamType.AUDIO_STREAM_NATIVE
+ audio_stream_from_participant.track_source = track_source
+ if self._frame_size_ms:
+ audio_stream_from_participant.frame_size_ms = self._frame_size_ms
+
+ if self._audio_filter_module is not None:
+ audio_stream_from_participant.audio_filter_module_id = self._audio_filter_module
+ if self._audio_filter_options is not None:
+ audio_stream_from_participant.audio_filter_options = json.dumps(
+ self._audio_filter_options
+ )
+ resp = FfiClient.instance.request(req)
+ return resp.audio_stream_from_participant.stream
+
async def _run(self):
while True:
event = await self._ffi_queue.wait_for(self._is_event)
- audio_event = event.audio_stream_event
+ audio_event: proto_audio_frame.AudioStreamEvent = event.audio_stream_event
if audio_event.HasField("frame_received"):
owned_buffer_info = audio_event.frame_received.frame
frame = AudioFrame._from_owned_info(owned_buffer_info)
+ if self._processor is not None and self._processor.enabled:
+ try:
+ frame = self._processor._process(frame)
+ except Exception:
+ logger.warning(
+ "Frame processing failed, passing through original frame",
+ exc_info=True,
+ )
event = AudioFrameEvent(frame)
self._queue.put(event)
elif audio_event.HasField("eos"):
+ self._queue.put(None)
break
FfiClient.instance.queue.unsubscribe(self._ffi_queue)
async def aclose(self) -> None:
+ """Asynchronously close the audio stream.
+
+ This method cleans up resources associated with the audio stream and waits for
+ any pending operations to complete.
+ """
self._ffi_handle.dispose()
await self._task
- def __aiter__(self) -> "AudioStream":
- return self
-
def _is_event(self, e: proto_ffi.FfiEvent) -> bool:
return e.audio_stream_event.stream_handle == self._ffi_handle.handle
+ def __aiter__(self) -> AsyncIterator[AudioFrameEvent]:
+ return self
+
async def __anext__(self) -> AudioFrameEvent:
if self._task.done():
raise StopAsyncIteration
- return await self._queue.get()
+
+ item = await self._queue.get()
+ if item is None:
+ raise StopAsyncIteration
+
+ return item
diff --git a/livekit-rtc/livekit/rtc/chat.py b/livekit-rtc/livekit/rtc/chat.py
deleted file mode 100644
index 5bcae348..00000000
--- a/livekit-rtc/livekit/rtc/chat.py
+++ /dev/null
@@ -1,138 +0,0 @@
-# Copyright 2023 LiveKit, Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from dataclasses import dataclass, field
-from datetime import datetime
-import json
-import logging
-from typing import Any, Callable, Dict, Literal, Optional
-
-from .room import Room, Participant, DataPacket
-from ._event_emitter import EventEmitter
-from ._proto.room_pb2 import DataPacketKind
-from ._utils import generate_random_base62
-
-_CHAT_TOPIC = "lk-chat-topic"
-_CHAT_UPDATE_TOPIC = "lk-chat-update-topic"
-
-EventTypes = Literal["message_received",]
-
-
-class ChatManager(EventEmitter[EventTypes]):
- """A utility class that sends and receives chat messages in the active session.
-
- It implements LiveKit Chat Protocol, and serializes data to/from JSON data packets.
- """
-
- def __init__(self, room: Room):
- super().__init__()
- self._lp = room.local_participant
- self._room = room
-
- room.on("data_received", self._on_data_received)
-
- def close(self):
- self._room.off("data_received", self._on_data_received)
-
- async def send_message(self, message: str) -> "ChatMessage":
- """Send a chat message to the end user using LiveKit Chat Protocol.
-
- Args:
- message (str): the message to send
-
- Returns:
- ChatMessage: the message that was sent
- """
- msg = ChatMessage(
- message=message,
- is_local=True,
- participant=self._lp,
- )
- await self._lp.publish_data(
- payload=json.dumps(msg.asjsondict()),
- kind=DataPacketKind.KIND_RELIABLE,
- topic=_CHAT_TOPIC,
- )
- return msg
-
- async def update_message(self, message: "ChatMessage"):
- """Update a chat message that was previously sent.
-
- If message.deleted is set to True, we'll signal to remote participants that the message
- should be deleted.
- """
- await self._lp.publish_data(
- payload=json.dumps(message.asjsondict()),
- kind=DataPacketKind.KIND_RELIABLE,
- topic=_CHAT_UPDATE_TOPIC,
- )
-
- def on_message(self, callback: Callable[["ChatMessage"], None]):
- """Register a callback to be called when a chat message is received from the end user."""
- self._callback = callback
-
- def _on_data_received(self, dp: DataPacket):
- # handle both new and updates the same way, as long as the ID is in there
- # the user can decide how to replace the previous message
- if dp.topic == _CHAT_TOPIC or dp.topic == _CHAT_UPDATE_TOPIC:
- try:
- parsed = json.loads(dp.data)
- msg = ChatMessage.from_jsondict(parsed)
- if dp.participant:
- msg.participant = dp.participant
- self.emit("message_received", msg)
- except Exception as e:
- logging.warning("failed to parse chat message: %s", e, exc_info=e)
-
-
-@dataclass
-class ChatMessage:
- message: Optional[str] = None
- id: str = field(default_factory=generate_random_base62)
- timestamp: datetime = field(default_factory=datetime.now)
- deleted: bool = field(default=False)
-
- # These fields are not part of the wire protocol. They are here to provide
- # context for the application.
- participant: Optional[Participant] = None
- is_local: bool = field(default=False)
-
- @classmethod
- def from_jsondict(cls, d: Dict[str, Any]) -> "ChatMessage":
- # older version of the protocol didn't contain a message ID, so we'll create one
- id = d.get("id") or generate_random_base62()
- timestamp = datetime.now()
- if d.get("timestamp"):
- timestamp = datetime.fromtimestamp(d.get("timestamp", 0) / 1000.0)
- msg = cls(
- id=id,
- timestamp=timestamp,
- )
- msg.update_from_jsondict(d)
- return msg
-
- def update_from_jsondict(self, d: Dict[str, Any]) -> None:
- self.message = d.get("message")
- self.deleted = d.get("deleted", False)
-
- def asjsondict(self):
- """Returns a JSON serializable dictionary representation of the message."""
- d = {
- "id": self.id,
- "message": self.message,
- "timestamp": int(self.timestamp.timestamp() * 1000),
- }
- if self.deleted:
- d["deleted"] = True
- return d
diff --git a/livekit-rtc/livekit/rtc/data_stream.py b/livekit-rtc/livekit/rtc/data_stream.py
new file mode 100644
index 00000000..beb806f4
--- /dev/null
+++ b/livekit-rtc/livekit/rtc/data_stream.py
@@ -0,0 +1,357 @@
+# Copyright 2023 LiveKit, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import annotations
+
+import asyncio
+import uuid
+import datetime
+from collections.abc import Callable
+from dataclasses import dataclass
+from typing import AsyncIterator, Optional, Dict, List
+from ._proto.room_pb2 import DataStream as proto_DataStream
+from ._proto import ffi_pb2 as proto_ffi
+from ._proto import room_pb2 as proto_room
+from ._ffi_client import FfiClient
+from ._utils import split_utf8
+from typing import TYPE_CHECKING
+
+
+if TYPE_CHECKING:
+ from .participant import LocalParticipant
+
+STREAM_CHUNK_SIZE = 15_000
+
+
+@dataclass
+class BaseStreamInfo:
+ stream_id: str
+ mime_type: str
+ topic: str
+ timestamp: int
+ size: Optional[int]
+ attributes: Optional[Dict[str, str]] # Optional for the attributes dictionary
+
+
+@dataclass
+class TextStreamInfo(BaseStreamInfo):
+ attachments: List[str]
+
+
+class TextStreamReader:
+ def __init__(
+ self,
+ header: proto_DataStream.Header,
+ ) -> None:
+ self._header = header
+ self._info = TextStreamInfo(
+ stream_id=header.stream_id,
+ mime_type=header.mime_type,
+ topic=header.topic,
+ timestamp=header.timestamp,
+ size=header.total_length,
+ attributes=dict(header.attributes),
+ attachments=list(header.text_header.attached_stream_ids),
+ )
+ self._queue: asyncio.Queue[proto_DataStream.Chunk | None] = asyncio.Queue()
+
+ async def _on_chunk_update(self, chunk: proto_DataStream.Chunk):
+ await self._queue.put(chunk)
+
+ async def _on_stream_close(self, trailer: proto_DataStream.Trailer):
+ self.info.attributes = self.info.attributes or {}
+ self.info.attributes.update(trailer.attributes)
+ await self._queue.put(None)
+
+ def __aiter__(self) -> AsyncIterator[str]:
+ return self
+
+ async def __anext__(self) -> str:
+ item = await self._queue.get()
+ if item is None:
+ raise StopAsyncIteration
+ decodedStr = item.content.decode()
+ return decodedStr
+
+ @property
+ def info(self) -> TextStreamInfo:
+ return self._info
+
+ async def read_all(self) -> str:
+ final_string = ""
+ async for chunk in self:
+ final_string += chunk
+ return final_string
+
+
+@dataclass
+class ByteStreamInfo(BaseStreamInfo):
+ name: str
+
+
+class ByteStreamReader:
+ def __init__(self, header: proto_DataStream.Header, capacity: int = 0) -> None:
+ self._header = header
+ self._info = ByteStreamInfo(
+ stream_id=header.stream_id,
+ mime_type=header.mime_type,
+ topic=header.topic,
+ timestamp=header.timestamp,
+ size=header.total_length,
+ attributes=dict(header.attributes),
+ name=header.byte_header.name,
+ )
+ self._queue: asyncio.Queue[proto_DataStream.Chunk | None] = asyncio.Queue(capacity)
+
+ async def _on_chunk_update(self, chunk: proto_DataStream.Chunk):
+ await self._queue.put(chunk)
+
+ async def _on_stream_close(self, trailer: proto_DataStream.Trailer):
+ self.info.attributes = self.info.attributes or {}
+ self.info.attributes.update(trailer.attributes)
+ await self._queue.put(None)
+
+ def __aiter__(self) -> AsyncIterator[bytes]:
+ return self
+
+ async def __anext__(self) -> bytes:
+ item = await self._queue.get()
+ if item is None:
+ raise StopAsyncIteration
+
+ return item.content
+
+ @property
+ def info(self) -> ByteStreamInfo:
+ return self._info
+
+
+class BaseStreamWriter:
+ def __init__(
+ self,
+ local_participant: LocalParticipant,
+ topic: str = "",
+ attributes: Optional[Dict[str, str]] = {},
+ stream_id: str | None = None,
+ total_size: int | None = None,
+ mime_type: str = "",
+ destination_identities: Optional[List[str]] = None,
+ sender_identity: str | None = None,
+ ):
+ self._local_participant = local_participant
+ if stream_id is None:
+ stream_id = str(uuid.uuid4())
+ timestamp = int(datetime.datetime.now().timestamp() * 1000)
+ self._header = proto_DataStream.Header(
+ stream_id=stream_id,
+ timestamp=timestamp,
+ mime_type=mime_type,
+ topic=topic,
+ attributes=attributes,
+ total_length=total_size,
+ )
+ self._next_chunk_index: int = 0
+ self._destination_identities = destination_identities
+ self._sender_identity = sender_identity or self._local_participant.identity
+ self._closed = False
+
+ async def _send_header(self):
+ req = proto_ffi.FfiRequest(
+ send_stream_header=proto_room.SendStreamHeaderRequest(
+ header=self._header,
+ local_participant_handle=self._local_participant._ffi_handle.handle,
+ destination_identities=self._destination_identities,
+ sender_identity=self._sender_identity,
+ )
+ )
+
+ queue = FfiClient.instance.queue.subscribe()
+ try:
+ resp = FfiClient.instance.request(req)
+ cb: proto_ffi.FfiEvent = await queue.wait_for(
+ lambda e: e.send_stream_header.async_id == resp.send_stream_header.async_id
+ )
+ finally:
+ FfiClient.instance.queue.unsubscribe(queue)
+
+ if cb.send_stream_header.error:
+ raise ConnectionError(cb.send_stream_header.error)
+
+ async def _send_chunk(self, chunk: proto_DataStream.Chunk):
+ if self._closed:
+ raise RuntimeError(f"Cannot send chunk after stream is closed: {chunk}")
+ req = proto_ffi.FfiRequest(
+ send_stream_chunk=proto_room.SendStreamChunkRequest(
+ chunk=chunk,
+ local_participant_handle=self._local_participant._ffi_handle.handle,
+ sender_identity=self._local_participant.identity,
+ destination_identities=self._destination_identities,
+ )
+ )
+
+ queue = FfiClient.instance.queue.subscribe()
+ try:
+ resp = FfiClient.instance.request(req)
+ cb: proto_ffi.FfiEvent = await queue.wait_for(
+ lambda e: e.send_stream_chunk.async_id == resp.send_stream_chunk.async_id
+ )
+ finally:
+ FfiClient.instance.queue.unsubscribe(queue)
+
+ if cb.send_stream_chunk.error:
+ raise ConnectionError(cb.send_stream_chunk.error)
+
+ async def _send_trailer(self, trailer: proto_DataStream.Trailer):
+ req = proto_ffi.FfiRequest(
+ send_stream_trailer=proto_room.SendStreamTrailerRequest(
+ trailer=trailer,
+ local_participant_handle=self._local_participant._ffi_handle.handle,
+ sender_identity=self._local_participant.identity,
+ )
+ )
+
+ queue = FfiClient.instance.queue.subscribe()
+ try:
+ resp = FfiClient.instance.request(req)
+ cb: proto_ffi.FfiEvent = await queue.wait_for(
+ lambda e: e.send_stream_trailer.async_id == resp.send_stream_trailer.async_id
+ )
+ finally:
+ FfiClient.instance.queue.unsubscribe(queue)
+
+ if cb.send_stream_chunk.error:
+ raise ConnectionError(cb.send_stream_trailer.error)
+
+ async def aclose(self, *, reason: str = "", attributes: Optional[Dict[str, str]] = None):
+ if self._closed:
+ raise RuntimeError("Stream already closed")
+ self._closed = True
+ await self._send_trailer(
+ trailer=proto_DataStream.Trailer(
+ stream_id=self._header.stream_id, reason=reason, attributes=attributes
+ )
+ )
+
+
+class TextStreamWriter(BaseStreamWriter):
+ def __init__(
+ self,
+ local_participant: LocalParticipant,
+ *,
+ topic: str = "",
+ attributes: Optional[Dict[str, str]] = {},
+ stream_id: str | None = None,
+ total_size: int | None = None,
+ reply_to_id: str | None = None,
+ destination_identities: Optional[List[str]] = None,
+ sender_identity: str | None = None,
+ ) -> None:
+ super().__init__(
+ local_participant,
+ topic,
+ attributes,
+ stream_id,
+ total_size,
+ mime_type="text/plain",
+ destination_identities=destination_identities,
+ sender_identity=sender_identity,
+ )
+ self._header.text_header.operation_type = proto_DataStream.OperationType.CREATE
+ if reply_to_id:
+ self._header.text_header.reply_to_stream_id = reply_to_id
+ self._info = TextStreamInfo(
+ stream_id=self._header.stream_id,
+ mime_type=self._header.mime_type,
+ topic=self._header.topic,
+ timestamp=self._header.timestamp,
+ size=self._header.total_length,
+ attributes=dict(self._header.attributes),
+ attachments=list(self._header.text_header.attached_stream_ids),
+ )
+ self._write_lock = asyncio.Lock()
+
+ async def write(self, text: str):
+ async with self._write_lock:
+ for chunk in split_utf8(text, STREAM_CHUNK_SIZE):
+ content = chunk
+ chunk_index = self._next_chunk_index
+ self._next_chunk_index += 1
+ chunk_msg = proto_DataStream.Chunk(
+ stream_id=self._header.stream_id,
+ chunk_index=chunk_index,
+ content=content,
+ )
+ await self._send_chunk(chunk_msg)
+
+ @property
+ def info(self) -> TextStreamInfo:
+ return self._info
+
+
+class ByteStreamWriter(BaseStreamWriter):
+ def __init__(
+ self,
+ local_participant: LocalParticipant,
+ *,
+ name: str,
+ topic: str = "",
+ attributes: Optional[Dict[str, str]] = None,
+ stream_id: str | None = None,
+ total_size: int | None = None,
+ mime_type: str = "application/octet-stream",
+ destination_identities: Optional[List[str]] = None,
+ ) -> None:
+ super().__init__(
+ local_participant,
+ topic,
+ attributes,
+ stream_id,
+ total_size,
+ mime_type=mime_type,
+ destination_identities=destination_identities,
+ )
+ self._header.byte_header.name = name
+ self._info = ByteStreamInfo(
+ stream_id=self._header.stream_id,
+ mime_type=self._header.mime_type,
+ topic=self._header.topic,
+ timestamp=self._header.timestamp,
+ size=self._header.total_length,
+ attributes=dict(self._header.attributes),
+ name=self._header.byte_header.name,
+ )
+ self._write_lock = asyncio.Lock()
+
+ async def write(self, data: bytes):
+ async with self._write_lock:
+ chunked_data = [
+ data[i : i + STREAM_CHUNK_SIZE] for i in range(0, len(data), STREAM_CHUNK_SIZE)
+ ]
+
+ for chunk in chunked_data:
+ chunk_msg = proto_DataStream.Chunk(
+ stream_id=self._header.stream_id,
+ chunk_index=self._next_chunk_index,
+ content=chunk,
+ )
+ await self._send_chunk(chunk_msg)
+ self._next_chunk_index += 1
+
+ @property
+ def info(self) -> ByteStreamInfo:
+ return self._info
+
+
+TextStreamHandler = Callable[[TextStreamReader, str], None]
+ByteStreamHandler = Callable[[ByteStreamReader, str], None]
diff --git a/livekit-rtc/livekit/rtc/data_track.py b/livekit-rtc/livekit/rtc/data_track.py
new file mode 100644
index 00000000..2fb26b71
--- /dev/null
+++ b/livekit-rtc/livekit/rtc/data_track.py
@@ -0,0 +1,273 @@
+# Copyright 2023 LiveKit, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import annotations
+
+from dataclasses import dataclass
+from typing import AsyncIterator, Optional
+
+from ._ffi_client import FfiClient, FfiHandle
+from ._proto import ffi_pb2 as proto_ffi
+from ._proto import data_track_pb2 as proto_data_track
+
+
+class SubscribeDataTrackError(Exception):
+ """An error that can occur when subscribing to a data track."""
+
+ def __init__(self, message: str) -> None:
+ self.message = message
+
+
+class PushFrameError(Exception):
+ """Frame could not be pushed to a data track.
+
+ Pushing a frame can fail for several reasons:
+
+ - The track has been unpublished by the local participant or SFU
+ - The room is no longer connected
+ - Frames are being pushed too fast
+ """
+
+ def __init__(self, message: str) -> None:
+ self.message = message
+
+
+@dataclass
+class DataTrackInfo:
+ """Information about a published data track."""
+
+ sid: str
+ """Unique track identifier assigned by the SFU.
+
+ This identifier may change if a reconnect occurs. Use ``name`` if a
+ stable identifier is needed.
+ """
+
+ name: str
+ """Name of the track assigned by the publisher."""
+
+ uses_e2ee: bool
+ """Whether or not frames sent on the track use end-to-end encryption."""
+
+
+@dataclass
+class DataTrackFrame:
+ """A frame published on a data track, consisting of a payload and optional metadata."""
+
+ payload: bytes
+ """The frame's payload."""
+
+ user_timestamp: Optional[int] = None
+ """The frame's user timestamp, if one is associated."""
+
+
+class LocalDataTrack:
+ """Data track published by the local participant."""
+
+ def __init__(self, owned_info: proto_data_track.OwnedLocalDataTrack) -> None:
+ self._info = DataTrackInfo(
+ sid=owned_info.info.sid,
+ name=owned_info.info.name,
+ uses_e2ee=owned_info.info.uses_e2ee,
+ )
+ self._ffi_handle = FfiHandle(owned_info.handle.id)
+
+ @property
+ def info(self) -> DataTrackInfo:
+ """Information about the data track."""
+ return self._info
+
+ def try_push(self, frame: DataTrackFrame) -> None:
+ """Try pushing a frame to subscribers of the track.
+
+ See :class:`DataTrackFrame` for how to construct a frame and attach metadata.
+
+ Args:
+ frame: The data track frame to send.
+
+ Raises:
+ PushFrameError: If the push fails.
+ """
+ proto_frame = proto_data_track.DataTrackFrame(payload=bytes(frame.payload))
+ if frame.user_timestamp is not None:
+ proto_frame.user_timestamp = frame.user_timestamp
+
+ req = proto_ffi.FfiRequest()
+ req.local_data_track_try_push.track_handle = self._ffi_handle.handle
+ req.local_data_track_try_push.frame.CopyFrom(proto_frame)
+
+ resp = FfiClient.instance.request(req)
+ if resp.local_data_track_try_push.HasField("error"):
+ raise PushFrameError(resp.local_data_track_try_push.error.message)
+
+ def is_published(self) -> bool:
+ """Whether or not the track is still published."""
+ req = proto_ffi.FfiRequest()
+ req.local_data_track_is_published.track_handle = self._ffi_handle.handle
+
+ resp = FfiClient.instance.request(req)
+ return resp.local_data_track_is_published.is_published
+
+ async def unpublish(self) -> None:
+ """Unpublishes the track."""
+ req = proto_ffi.FfiRequest()
+ req.local_data_track_unpublish.track_handle = self._ffi_handle.handle
+ FfiClient.instance.request(req)
+
+ def __repr__(self) -> str:
+ return f"rtc.LocalDataTrack(sid={self._info.sid}, name={self._info.name})"
+
+
+class RemoteDataTrack:
+ """Data track published by a remote participant."""
+
+ def __init__(self, owned_info: proto_data_track.OwnedRemoteDataTrack) -> None:
+ self._info = DataTrackInfo(
+ sid=owned_info.info.sid,
+ name=owned_info.info.name,
+ uses_e2ee=owned_info.info.uses_e2ee,
+ )
+ self._ffi_handle = FfiHandle(owned_info.handle.id)
+ self._publisher_identity = owned_info.publisher_identity
+
+ @property
+ def info(self) -> DataTrackInfo:
+ """Information about the data track."""
+ return self._info
+
+ @property
+ def publisher_identity(self) -> str:
+ """Identity of the participant who published the track."""
+ return self._publisher_identity
+
+ def subscribe(self, *, buffer_size: Optional[int] = None) -> DataTrackStream:
+ """Subscribes to the data track to receive frames.
+
+ Args:
+ buffer_size: Maximum number of received frames to buffer internally.
+ When ``None``, the default buffer size is used.
+ Zero is not a valid buffer size; if a value of zero is provided, it will be clamped to one.
+
+ Returns a :class:`DataTrackStream` that yields
+ :class:`DataTrackFrame` instances as they arrive. If the
+ subscription encounters an error, it is raised as
+ :class:`SubscribeDataTrackError` when iteration ends.
+ """
+ opts = proto_data_track.DataTrackSubscribeOptions()
+ if buffer_size is not None:
+ opts.buffer_size = buffer_size
+
+ req = proto_ffi.FfiRequest()
+ req.subscribe_data_track.track_handle = self._ffi_handle.handle
+ req.subscribe_data_track.options.CopyFrom(opts)
+
+ resp = FfiClient.instance.request(req)
+ return DataTrackStream(resp.subscribe_data_track.stream)
+
+ def is_published(self) -> bool:
+ """Whether or not the track is still published."""
+ req = proto_ffi.FfiRequest()
+ req.remote_data_track_is_published.track_handle = self._ffi_handle.handle
+
+ resp = FfiClient.instance.request(req)
+ return resp.remote_data_track_is_published.is_published
+
+ def __repr__(self) -> str:
+ return (
+ f"rtc.RemoteDataTrack(sid={self._info.sid}, name={self._info.name}, "
+ f"publisher_identity={self._publisher_identity})"
+ )
+
+
+class DataTrackStream:
+ """An active subscription to a remote data track.
+
+ Use as an async iterator to receive frames::
+
+ stream = remote_track.subscribe()
+ async for frame in stream:
+ process(frame.payload)
+
+ Dropping or closing the stream unsubscribes from the track.
+
+ If subscribing to the track fails, :class:`SubscribeDataTrackError`
+ is raised when iteration ends instead of a normal ``StopAsyncIteration``.
+ """
+
+ def __init__(self, owned_info: proto_data_track.OwnedDataTrackStream) -> None:
+ self._ffi_handle = FfiHandle(owned_info.handle.id)
+ handle_id = owned_info.handle.id
+
+ self._queue = FfiClient.instance.queue.subscribe(
+ filter_fn=lambda e: (
+ e.WhichOneof("message") == "data_track_stream_event"
+ and e.data_track_stream_event.stream_handle == handle_id
+ ),
+ )
+ self._closed = False
+
+ async def read(self) -> Optional[DataTrackFrame]:
+ """Read a single frame, or ``None`` if the stream has ended."""
+ try:
+ return await self.__anext__()
+ except StopAsyncIteration:
+ return None
+
+ def __aiter__(self) -> AsyncIterator[DataTrackFrame]:
+ return self
+
+ async def __anext__(self) -> DataTrackFrame:
+ if self._closed:
+ raise StopAsyncIteration
+
+ self._send_read_request()
+ event: proto_ffi.FfiEvent = await self._queue.get()
+ stream_event = event.data_track_stream_event
+ detail = stream_event.WhichOneof("detail")
+
+ if detail == "frame_received":
+ proto_frame = stream_event.frame_received.frame
+ user_ts: Optional[int] = None
+ if proto_frame.HasField("user_timestamp"):
+ user_ts = proto_frame.user_timestamp
+ return DataTrackFrame(
+ payload=proto_frame.payload,
+ user_timestamp=user_ts,
+ )
+ elif detail == "eos":
+ self._close()
+ if stream_event.eos.HasField("error"):
+ raise SubscribeDataTrackError(stream_event.eos.error)
+ raise StopAsyncIteration
+ else:
+ self._close()
+ raise StopAsyncIteration
+
+ def _send_read_request(self) -> None:
+ req = proto_ffi.FfiRequest()
+ req.data_track_stream_read.stream_handle = self._ffi_handle.handle
+ FfiClient.instance.request(req)
+
+ def _close(self) -> None:
+ if not self._closed:
+ self._closed = True
+ FfiClient.instance.queue.unsubscribe(self._queue)
+
+ def close(self) -> None:
+ """Explicitly close the subscription and unsubscribe."""
+ self._close()
+ self._ffi_handle.dispose()
+
+ async def aclose(self) -> None:
+ self.close()
diff --git a/livekit-rtc/livekit/rtc/e2ee.py b/livekit-rtc/livekit/rtc/e2ee.py
index 3b296bd0..0258c157 100644
--- a/livekit-rtc/livekit/rtc/e2ee.py
+++ b/livekit-rtc/livekit/rtc/e2ee.py
@@ -22,6 +22,7 @@
DEFAULT_RATCHET_SALT = b"LKFrameEncryptionKey"
DEFAULT_RATCHET_WINDOW_SIZE = 16
DEFAULT_FAILURE_TOLERANCE = -1
+DEFAULT_KEY_RING_SIZE = 16
@dataclass
@@ -30,6 +31,10 @@ class KeyProviderOptions:
ratchet_salt: bytes = DEFAULT_RATCHET_SALT
ratchet_window_size: int = DEFAULT_RATCHET_WINDOW_SIZE
failure_tolerance: int = DEFAULT_FAILURE_TOLERANCE
+ key_ring_size: int = DEFAULT_KEY_RING_SIZE
+ key_derivation_function: proto_e2ee.KeyDerivationFunction.ValueType = (
+ proto_e2ee.KeyDerivationFunction.PBKDF2
+ )
@dataclass
@@ -48,6 +53,17 @@ def options(self) -> KeyProviderOptions:
return self._options
def set_shared_key(self, key: bytes, key_index: int) -> None:
+ """Sets the shared encryption key.
+
+ Parameters:
+ key (bytes): The new shared key.
+ key_index (int): The index of the key.
+
+ Example:
+ ```python
+ key_provider.set_shared_key(b"my_shared_key", key_index=1)
+ ```
+ """
req = proto_ffi.FfiRequest()
req.e2ee.room_handle = self._room_handle
req.e2ee.set_shared_key.key_index = key_index
@@ -55,6 +71,19 @@ def set_shared_key(self, key: bytes, key_index: int) -> None:
FfiClient.instance.request(req)
def export_shared_key(self, key_index: int) -> bytes:
+ """Exports the shared encryption key.
+
+ Parameters:
+ key_index (int): The index of the key to export.
+
+ Returns:
+ bytes: The exported shared key.
+
+ Example:
+ ```python
+ key = key_provider.export_shared_key(key_index=1)
+ ```
+ """
req = proto_ffi.FfiRequest()
req.e2ee.room_handle = self._room_handle
req.e2ee.get_shared_key.key_index = key_index
@@ -63,6 +92,19 @@ def export_shared_key(self, key_index: int) -> bytes:
return key
def ratchet_shared_key(self, key_index: int) -> bytes:
+ """Ratchets the shared encryption key to a new key.
+
+ Parameters:
+ key_index (int): The index of the key to ratchet.
+
+ Returns:
+ bytes: The new ratcheted shared key.
+
+ Example:
+ ```python
+ new_key = key_provider.ratchet_shared_key(key_index=1)
+ ```
+ """
req = proto_ffi.FfiRequest()
req.e2ee.room_handle = self._room_handle
req.e2ee.ratchet_shared_key.key_index = key_index
@@ -73,6 +115,18 @@ def ratchet_shared_key(self, key_index: int) -> bytes:
return new_key
def set_key(self, participant_identity: str, key: bytes, key_index: int) -> None:
+ """Sets the encryption key for a specific participant.
+
+ Parameters:
+ participant_identity (str): The identity of the participant.
+ key (bytes): The encryption key to set.
+ key_index (int): The index of the key.
+
+ Example:
+ ```python
+ key_provider.set_key("participant123", b"participant_key", key_index=2)
+ ```
+ """
req = proto_ffi.FfiRequest()
req.e2ee.room_handle = self._room_handle
req.e2ee.set_key.participant_identity = participant_identity
@@ -83,6 +137,20 @@ def set_key(self, participant_identity: str, key: bytes, key_index: int) -> None
FfiClient.instance.request(req)
def export_key(self, participant_identity: str, key_index: int) -> bytes:
+ """Exports the encryption key for a specific participant.
+
+ Parameters:
+ participant_identity (str): The identity of the participant.
+ key_index (int): The index of the key to export.
+
+ Returns:
+ bytes: The exported key.
+
+ Example:
+ ```python
+ key = key_provider.export_key("participant123", key_index=2)
+ ```
+ """
req = proto_ffi.FfiRequest()
req.e2ee.room_handle = self._room_handle
req.e2ee.get_key.participant_identity = participant_identity
@@ -92,6 +160,20 @@ def export_key(self, participant_identity: str, key_index: int) -> bytes:
return key
def ratchet_key(self, participant_identity: str, key_index: int) -> bytes:
+ """Ratchets the encryption key for a specific participant to a new key.
+
+ Parameters:
+ participant_identity (str): The identity of the participant.
+ key_index (int): The index of the key to ratchet.
+
+ Returns:
+ bytes: The new ratcheted key.
+
+ Example:
+ ```python
+ new_key = key_provider.ratchet_key("participant123", key_index=2)
+ ```
+ """
req = proto_ffi.FfiRequest()
req.e2ee.room_handle = self._room_handle
req.e2ee.ratchet_key.participant_identity = participant_identity
@@ -103,9 +185,7 @@ def ratchet_key(self, participant_identity: str, key_index: int) -> bytes:
class FrameCryptor:
- def __init__(
- self, room_handle: int, participant_identity: str, key_index: int, enabled: bool
- ):
+ def __init__(self, room_handle: int, participant_identity: str, key_index: int, enabled: bool):
self._room_handle = room_handle
self._enabled = enabled
self._participant_identity = participant_identity
@@ -124,6 +204,16 @@ def enabled(self) -> bool:
return self._enabled
def set_enabled(self, enabled: bool) -> None:
+ """Enables or disables frame encryption.
+
+ Parameters:
+ enabled (bool): True to enable, False to disable.
+
+ Example:
+ ```python
+ frame_cryptor.set_enabled(True)
+ ```
+ """
self._enabled = enabled
req = proto_ffi.FfiRequest()
req.e2ee.room_handle = self._room_handle
@@ -132,6 +222,16 @@ def set_enabled(self, enabled: bool) -> None:
FfiClient.instance.request(req)
def set_key_index(self, key_index: int) -> None:
+ """Sets the key index for encryption/decryption.
+
+ Parameters:
+ key_index (int): The new key index.
+
+ Example:
+ ```python
+ frame_cryptor.set_key_index(3)
+ ```
+ """
self._key_index = key_index
req = proto_ffi.FfiRequest()
req.e2ee.room_handle = self._room_handle
@@ -147,9 +247,7 @@ def __init__(self, room_handle: int, options: Optional[E2EEOptions]):
self._enabled = options is not None
if options is not None:
- self._key_provider = KeyProvider(
- self._room_handle, options.key_provider_options
- )
+ self._key_provider = KeyProvider(self._room_handle, options.key_provider_options)
@property
def key_provider(self) -> Optional[KeyProvider]:
@@ -160,6 +258,16 @@ def enabled(self) -> bool:
return self._enabled
def set_enabled(self, enabled: bool) -> None:
+ """Enables or disables end-to-end encryption.
+
+ Parameters:
+ enabled (bool): True to enable, False to disable.
+
+ Example:
+ ```python
+ e2ee_manager.set_enabled(True)
+ ```
+ """
self._enabled = enabled
req = proto_ffi.FfiRequest()
req.e2ee.room_handle = self._room_handle
@@ -167,6 +275,18 @@ def set_enabled(self, enabled: bool) -> None:
FfiClient.instance.request(req)
def frame_cryptors(self) -> List[FrameCryptor]:
+ """Retrieves the list of frame cryptors for participants.
+
+ Returns:
+ List[FrameCryptor]: A list of FrameCryptor instances.
+
+ Example:
+ ```python
+ cryptors = e2ee_manager.frame_cryptors()
+ for cryptor in cryptors:
+ print(cryptor.participant_identity)
+ ```
+ """
req = proto_ffi.FfiRequest()
req.e2ee.room_handle = self._room_handle
diff --git a/livekit-rtc/livekit/rtc/event_emitter.py b/livekit-rtc/livekit/rtc/event_emitter.py
new file mode 100644
index 00000000..c2fabae5
--- /dev/null
+++ b/livekit-rtc/livekit/rtc/event_emitter.py
@@ -0,0 +1,200 @@
+import inspect
+import asyncio
+from typing import Callable, Dict, Set, Optional, Generic, TypeVar
+
+from .log import logger
+
+T_contra = TypeVar("T_contra", contravariant=True)
+
+
+class EventEmitter(Generic[T_contra]):
+ def __init__(self) -> None:
+ """
+ Initialize a new instance of EventEmitter.
+ """
+ self._events: Dict[T_contra, Set[Callable]] = dict()
+
+ def emit(self, event: T_contra, *args) -> None:
+ """
+ Trigger all callbacks associated with the given event.
+
+ Args:
+ event (T): The event to emit.
+ *args: Positional arguments to pass to the callbacks.
+
+ Example:
+ Basic usage of emit:
+
+ ```python
+ emitter = EventEmitter[str]()
+
+ def greet(name):
+ print(f"Hello, {name}!")
+
+ emitter.on('greet', greet)
+ emitter.emit('greet', 'Alice') # Output: Hello, Alice!
+ ```
+ """
+ if event in self._events:
+ callables = self._events[event].copy()
+ for callback in callables:
+ try:
+ sig = inspect.signature(callback)
+ params = sig.parameters.values()
+
+ has_varargs = any(p.kind == p.VAR_POSITIONAL for p in params)
+ if has_varargs:
+ callback(*args)
+ else:
+ positional_params = [
+ p
+ for p in params
+ if p.kind in (p.POSITIONAL_ONLY, p.POSITIONAL_OR_KEYWORD)
+ ]
+ num_params = len(positional_params)
+ num_args = min(len(args), num_params)
+ callback_args = args[:num_args]
+
+ callback(*callback_args)
+ except TypeError:
+ raise
+ except Exception:
+ logger.exception(f"failed to emit event {event}")
+
+ def once(self, event: T_contra, callback: Optional[Callable] = None) -> Callable:
+ """
+ Register a callback to be called only once when the event is emitted.
+
+ If a callback is provided, it registers the callback directly.
+ If no callback is provided, it returns a decorator for use with function definitions.
+
+ Args:
+ event (T): The event to listen for.
+ callback (Callable, optional): The callback to register. Defaults to None.
+
+ Returns:
+ Callable: The registered callback or a decorator if callback is None.
+
+ Example:
+ Using once with a direct callback:
+
+ ```python
+ emitter = EventEmitter[str]()
+
+ def greet_once(name):
+ print(f"Hello once, {name}!")
+
+ emitter.once('greet', greet_once)
+ emitter.emit('greet', 'Bob') # Output: Hello once, Bob!
+ emitter.emit('greet', 'Bob') # No output, callback was removed after first call
+ ```
+
+ Using once as a decorator:
+
+ ```python
+ emitter = EventEmitter[str]()
+
+ @emitter.once('greet')
+ def greet_once(name):
+ print(f"Hello once, {name}!")
+
+ emitter.emit('greet', 'Bob') # Output: Hello once, Bob!
+ emitter.emit('greet', 'Bob') # No output
+ ```
+ """
+ if callback is not None:
+
+ def once_callback(*args, **kwargs):
+ self.off(event, once_callback)
+ callback(*args, **kwargs)
+
+ return self.on(event, once_callback)
+ else:
+
+ def decorator(callback: Callable) -> Callable:
+ self.once(event, callback)
+ return callback
+
+ return decorator
+
+ def on(self, event: T_contra, callback: Optional[Callable] = None) -> Callable:
+ """
+ Register a callback to be called whenever the event is emitted.
+
+ If a callback is provided, it registers the callback directly.
+ If no callback is provided, it returns a decorator for use with function definitions.
+
+ Args:
+ event (T): The event to listen for.
+ callback (Callable, optional): The callback to register. Defaults to None.
+
+ Returns:
+ Callable: The registered callback or a decorator if callback is None.
+
+ Example:
+ Using on with a direct callback:
+
+ ```python
+ emitter = EventEmitter[str]()
+
+ def greet(name):
+ print(f"Hello, {name}!")
+
+ emitter.on('greet', greet)
+ emitter.emit('greet', 'Charlie') # Output: Hello, Charlie!
+ ```
+
+ Using on as a decorator:
+
+ ```python
+ emitter = EventEmitter[str]()
+
+ @emitter.on('greet')
+ def greet(name):
+ print(f"Hello, {name}!")
+
+ emitter.emit('greet', 'Charlie') # Output: Hello, Charlie!
+ ```
+ """
+ if callback is not None:
+ if asyncio.iscoroutinefunction(callback):
+ raise ValueError(
+ "Cannot register an async callback with `.on()`. Use `asyncio.create_task` within your synchronous callback instead."
+ )
+
+ if event not in self._events:
+ self._events[event] = set()
+ self._events[event].add(callback)
+ return callback
+ else:
+
+ def decorator(callback: Callable) -> Callable:
+ self.on(event, callback)
+ return callback
+
+ return decorator
+
+ def off(self, event: T_contra, callback: Callable) -> None:
+ """
+ Unregister a callback from an event.
+
+ Args:
+ event (T): The event to stop listening to.
+ callback (Callable): The callback to remove.
+
+ Example:
+ Removing a callback:
+
+ ```python
+ emitter = EventEmitter[str]()
+
+ def greet(name):
+ print(f"Hello, {name}!")
+
+ emitter.on('greet', greet)
+ emitter.off('greet', greet)
+ emitter.emit('greet', 'Dave') # No output, callback was removed
+ ```
+ """
+ if event in self._events:
+ self._events[event].discard(callback)
diff --git a/livekit-rtc/livekit/rtc/frame_processor.py b/livekit-rtc/livekit/rtc/frame_processor.py
new file mode 100644
index 00000000..b8cc542e
--- /dev/null
+++ b/livekit-rtc/livekit/rtc/frame_processor.py
@@ -0,0 +1,33 @@
+from abc import ABC, abstractmethod
+from typing import Generic, TypeVar, Union
+from .audio_frame import AudioFrame
+from .video_frame import VideoFrame
+
+
+T = TypeVar("T", bound=Union[AudioFrame, VideoFrame])
+
+
+class FrameProcessor(Generic[T], ABC):
+ @property
+ @abstractmethod
+ def enabled(self) -> bool: ...
+
+ @enabled.setter
+ @abstractmethod
+ def enabled(self, value: bool) -> None: ...
+
+ def _on_stream_info_updated(
+ self,
+ *,
+ room_name: str,
+ participant_identity: str,
+ publication_sid: str,
+ ) -> None: ...
+
+ def _on_credentials_updated(self, *, token: str, url: str) -> None: ...
+
+ @abstractmethod
+ def _process(self, frame: T) -> T: ...
+
+ @abstractmethod
+ def _close(self) -> None: ...
diff --git a/livekit-rtc/livekit/rtc/jupyter.py b/livekit-rtc/livekit/rtc/jupyter.py
new file mode 100644
index 00000000..f6a3b689
--- /dev/null
+++ b/livekit-rtc/livekit/rtc/jupyter.py
@@ -0,0 +1,68 @@
+from __future__ import annotations
+
+import sys
+import atexit
+import contextlib
+import html
+from IPython.core.display import HTML
+from IPython.display import display
+from importlib.resources import as_file, files
+
+_resource_stack = contextlib.ExitStack()
+atexit.register(_resource_stack.close)
+
+
+def room_html(url: str, token: str, *, width: str, height: str) -> HTML:
+ """
+ Generate the HTML needed to embed a LiveKit room.
+
+ Args:
+ url (str): The LiveKit room URL.
+ token (str): The LiveKit join token.
+
+ Important:
+ The returned HTML contains the provided `url` and `token` values directly.
+ Avoid using sensitive tokens in public notebooks (e.g., tokens with long expiration times).
+ """
+ token_placeholder = "##livekit-token-placeholder##"
+ url_placeholder = "##livekit-url-placeholder##"
+
+ index_path = files("livekit.rtc.resources") / "jupyter-html" / "index.html"
+ index_path = _resource_stack.enter_context(as_file(index_path))
+
+ # turns out that directly replacing the URL/token is necessary, as Colab or Jupyter comms become
+ # unreliable when the main thread is busy/blocked.
+ # it also avoid the need to use --expose-app-in-browser when starting jupyter notebook
+ html_text = index_path.read_text()
+ html_text = html_text.replace(token_placeholder, token)
+ html_text = html_text.replace(url_placeholder, url)
+
+ IN_COLAB = "google.colab" in sys.modules
+
+ # Colab output already runs inside an iframe, so we don’t need to create an additional one.
+ # It also injects code into this iframe to handle microphone usage, so we need to preserve it.
+ if not IN_COLAB:
+ escaped_content = html.escape(html_text, quote=True)
+ # the extra space in the iframe_html is to avoid IPython suggesting to use IFrame instead.
+ # it isn't possible in our case, as we need to use srcdoc.
+ html_text = (
+ f' '
+ )
+
+ return HTML(html_text)
+
+
+def display_room(url: str, token: str, *, width: str = "100%", height: str = "110px") -> None:
+ """
+ Display a LiveKit room in a Jupyter notebook or Google Colab.
+
+ Args:
+ url (str): The LiveKit room URL.
+ token (str): The LiveKit join token.
+
+ Important:
+ The rendered HTML will include the provided `url` and `token` in plain text.
+ Avoid using sensitive tokens in public notebooks (e.g., tokens with long expiration times).
+ """
+ display(room_html(url, token, width=width, height=height))
diff --git a/livekit-rtc/livekit/rtc/log.py b/livekit-rtc/livekit/rtc/log.py
new file mode 100644
index 00000000..72c505f8
--- /dev/null
+++ b/livekit-rtc/livekit/rtc/log.py
@@ -0,0 +1,3 @@
+import logging
+
+logger = logging.getLogger("livekit")
diff --git a/livekit-rtc/livekit/rtc/media_devices.py b/livekit-rtc/livekit/rtc/media_devices.py
new file mode 100644
index 00000000..4958a9de
--- /dev/null
+++ b/livekit-rtc/livekit/rtc/media_devices.py
@@ -0,0 +1,595 @@
+# Copyright 2025 LiveKit, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import annotations
+
+import asyncio
+from dataclasses import dataclass
+from typing import TYPE_CHECKING, Any, AsyncIterator, Optional
+
+import numpy as np
+import threading
+
+if TYPE_CHECKING:
+ import sounddevice as sd # type: ignore[import-not-found, import-untyped]
+
+from . import AudioSource
+from .audio_frame import AudioFrame
+from .apm import AudioProcessingModule
+from .audio_mixer import AudioMixer
+from .audio_stream import AudioStream
+from .track import Track
+
+"""
+Media device helpers built on top of the `sounddevice` library.
+
+This module provides a small, Pythonic helper around native audio I/O for
+LiveKit RTC usage:
+
+- Capture the default audio input device and feed frames into `rtc.AudioSource`.
+- Optionally enable audio processing via `rtc.AudioProcessingModule` (AEC,
+ noise suppression, high-pass filter, AGC). Frames are processed in 10 ms
+ chunks as required by APM.
+- Play arbitrary audio frames to the default speaker. When AEC is enabled on
+ the input, the `OutputPlayer` can feed the APM reverse stream so echo
+ cancellation has access to render (speaker) audio.
+
+Notes on AEC wiring:
+- AEC requires feeding both capture (mic) and reverse (speaker) paths into
+ the same APM instance. This module does not automatically capture output from
+ other players. To enable AEC, the output player feeds APM's reverse stream
+ and we set stream delays derived from PortAudio timing.
+"""
+
+
+DEFAULT_SAMPLE_RATE = 48000
+DEFAULT_CHANNELS = 1
+FRAME_SAMPLES = 480 # 10 ms at 48 kHz
+BLOCKSIZE = 4800 # 100 ms I/O buffer size for sounddevice
+
+
+class _AudioStreamIterator:
+ """Adapter to convert AudioStream (AsyncIterator[AudioFrameEvent]) to AsyncIterator[AudioFrame].
+
+ This adapter wraps an AudioStream and extracts the frame from each AudioFrameEvent,
+ making it compatible with AudioMixer which expects AsyncIterator[AudioFrame].
+ """
+
+ def __init__(self, audio_stream: AudioStream) -> None:
+ self._audio_stream = audio_stream
+
+ def __aiter__(self) -> AsyncIterator[AudioFrame]:
+ return self
+
+ async def __anext__(self) -> AudioFrame:
+ event = await self._audio_stream.__anext__()
+ return event.frame
+
+ async def aclose(self) -> None:
+ await self._audio_stream.aclose()
+
+
+def _ensure_loop(loop: Optional[asyncio.AbstractEventLoop]) -> asyncio.AbstractEventLoop:
+ return loop or asyncio.get_event_loop()
+
+
+class _APMDelayEstimator:
+ """Thread-safe store for last known output (render) delay in seconds.
+
+ The sounddevice callbacks are invoked on PortAudio's threads. This helper allows
+ sharing the latest output delay measurement with the input callback so we can set
+ APM's combined stream delay (render + capture).
+ """
+
+ def __init__(self) -> None:
+ self._lock = threading.Lock()
+ self._output_delay_sec: float = 0.0
+
+ def set_output_delay(self, delay_sec: float) -> None:
+ with self._lock:
+ self._output_delay_sec = float(delay_sec)
+
+ def get_output_delay(self) -> float:
+ with self._lock:
+ return self._output_delay_sec
+
+
+@dataclass
+class InputCapture:
+ """Holds resources for an active audio input capture.
+
+ Attributes:
+ source: `rtc.AudioSource` that receives captured frames. This can be
+ published as a `LocalAudioTrack`.
+ input_stream: Underlying `sounddevice.InputStream`.
+ task: Async task that drains a queue and calls `source.capture_frame`.
+ apm: Optional `rtc.AudioProcessingModule` used to process 10 ms frames
+ (AEC, NS, HPF, AGC). When performing echo cancellation, pass this
+ instance to `open_output_player` so reverse frames are provided.
+ delay_estimator: Internal helper used to combine capture and render delays.
+ """
+
+ source: AudioSource
+ input_stream: "sd.InputStream"
+ task: asyncio.Task
+ apm: Optional[AudioProcessingModule]
+ delay_estimator: Optional[_APMDelayEstimator]
+
+ async def aclose(self) -> None:
+ """Stop capture and close underlying resources."""
+ if self.task and not self.task.done():
+ self.task.cancel()
+ try:
+ await self.task
+ except asyncio.CancelledError:
+ pass
+ try:
+ self.input_stream.stop()
+ self.input_stream.close()
+ except Exception:
+ pass
+
+
+class OutputPlayer:
+ """Simple audio output helper using `sounddevice.OutputStream`.
+
+ When `apm_for_reverse` is provided, this player will feed the same PCM it
+ renders (in 10 ms frames) into the APM reverse path so that echo
+ cancellation can correlate mic input with speaker output.
+
+ The OutputPlayer includes an internal `AudioMixer` for convenient multi-track
+ playback. Use `add_track()` and `remove_track()` to dynamically manage tracks,
+ then call `start()` to begin playback.
+ """
+
+ def __init__(
+ self,
+ *,
+ sample_rate: int = DEFAULT_SAMPLE_RATE,
+ num_channels: int = DEFAULT_CHANNELS,
+ blocksize: int = BLOCKSIZE,
+ apm_for_reverse: Optional[AudioProcessingModule] = None,
+ output_device: Optional[int] = None,
+ delay_estimator: Optional[_APMDelayEstimator] = None,
+ ) -> None:
+ import sounddevice as sd # type: ignore[import-not-found, import-untyped]
+
+ self._sample_rate = sample_rate
+ self._num_channels = num_channels
+ self._blocksize = blocksize
+ self._apm = apm_for_reverse
+ self._buffer = bytearray()
+ self._buffer_lock = asyncio.Lock()
+ self._play_task: Optional[asyncio.Task] = None
+ self._running = False
+ self._delay_estimator = delay_estimator
+
+ # Internal mixer for add_track/remove_track API
+ self._mixer: Optional[AudioMixer] = None
+ self._track_streams: dict[
+ str, tuple[AudioStream, _AudioStreamIterator]
+ ] = {} # track.sid -> (AudioStream, adapter)
+
+ def _callback(outdata: np.ndarray, frame_count: int, time_info: Any, status: Any) -> None:
+ # Pull PCM int16 from buffer; zero if not enough
+ bytes_needed = frame_count * 2
+ # Important: Do not take asyncio locks in realtime callbacks. We keep the
+ # critical section minimal and tolerate occasional underruns.
+ available = len(self._buffer)
+ if available >= bytes_needed:
+ chunk = self._buffer[:bytes_needed]
+ outdata[:, 0] = np.frombuffer(chunk, dtype=np.int16, count=frame_count)
+ del self._buffer[:bytes_needed]
+ elif available > 0:
+ outdata[: available // 2, 0] = np.frombuffer(
+ self._buffer[:available], dtype=np.int16, count=available // 2
+ )
+ outdata[available // 2 :, 0] = 0
+ del self._buffer[:available]
+ else:
+ outdata.fill(0)
+
+ # Measure render (output) delay: time until DAC from current callback time
+ try:
+ output_delay_sec = float(time_info.outputBufferDacTime - time_info.currentTime)
+ if self._delay_estimator is not None:
+ self._delay_estimator.set_output_delay(output_delay_sec)
+ except Exception:
+ pass
+
+ if self._apm is not None:
+ # Feed reverse stream in 10 ms frames for AEC
+ num_chunks = frame_count // FRAME_SAMPLES
+ for i in range(num_chunks):
+ start = i * FRAME_SAMPLES
+ end = start + FRAME_SAMPLES
+ if end > frame_count:
+ break
+ render_chunk = outdata[start:end, 0]
+ render_frame = AudioFrame(
+ render_chunk.tobytes(), self._sample_rate, 1, FRAME_SAMPLES
+ )
+ try:
+ self._apm.process_reverse_stream(render_frame)
+ except Exception:
+ # Ignore reverse stream errors in callback
+ pass
+
+ self._stream = sd.OutputStream(
+ callback=_callback,
+ dtype="int16",
+ channels=num_channels,
+ device=output_device,
+ samplerate=sample_rate,
+ blocksize=blocksize,
+ )
+
+ async def add_track(self, track: Track) -> None:
+ """Add an audio track to the internal mixer for playback.
+
+ This creates an `AudioStream` from the track and adds it to the internal
+ mixer. The mixer is created lazily on first track addition. Call `start()`
+ to begin playback of all added tracks.
+
+ Args:
+ track: The audio track to add (typically from a remote participant).
+
+ Raises:
+ ValueError: If the track is not an audio track or has already been added.
+ """
+ if track.sid in self._track_streams:
+ raise ValueError(f"Track {track.sid} already added to player")
+
+ # Create mixer on first track addition
+ if self._mixer is None:
+ self._mixer = AudioMixer(sample_rate=self._sample_rate, num_channels=self._num_channels)
+
+ # Create audio stream for this track
+ stream = AudioStream(track, sample_rate=self._sample_rate, num_channels=self._num_channels)
+ # Wrap the stream with an adapter to convert AudioFrameEvent to AudioFrame
+ stream_iterator = _AudioStreamIterator(stream)
+
+ self._track_streams[track.sid] = (stream, stream_iterator)
+ self._mixer.add_stream(stream_iterator)
+
+ async def remove_track(self, track: Track) -> None:
+ """Remove an audio track from the internal mixer.
+
+ This removes the track's stream from the mixer and closes it.
+
+ Args:
+ track: The audio track to remove.
+ """
+ entry = self._track_streams.pop(track.sid, None)
+ if entry is None:
+ return
+
+ stream, stream_iterator = entry
+ if self._mixer is not None:
+ try:
+ self._mixer.remove_stream(stream_iterator)
+ except Exception:
+ pass
+
+ try:
+ await stream.aclose()
+ except Exception:
+ pass
+
+ async def start(self) -> None:
+ """Start playback of all tracks in the internal mixer.
+
+ This begins a background task that consumes frames from the internal mixer
+ and sends them to the output device. Tracks can be added or removed
+ dynamically using `add_track()` and `remove_track()`.
+
+ Raises:
+ RuntimeError: If playback is already started or no mixer is available.
+ """
+ if self._play_task is not None and not self._play_task.done():
+ raise RuntimeError("Playback already started")
+
+ if self._mixer is None:
+ self._mixer = AudioMixer(sample_rate=self._sample_rate, num_channels=self._num_channels)
+
+ async def _playback_loop():
+ """Internal playback loop that consumes frames from the mixer."""
+ self._running = True
+ self._stream.start()
+ try:
+ async for frame in self._mixer:
+ if not self._running:
+ break
+ # Append raw PCM bytes for callback consumption
+ self._buffer.extend(frame.data.tobytes())
+ finally:
+ self._running = False
+ try:
+ self._stream.stop()
+ self._stream.close()
+ except Exception:
+ pass
+
+ self._play_task = asyncio.create_task(_playback_loop())
+
+ async def aclose(self) -> None:
+ """Stop playback and close the output stream.
+
+ This also cleans up all added tracks and the internal mixer.
+ """
+ self._running = False
+
+ # Cancel playback task if running
+ if self._play_task is not None and not self._play_task.done():
+ self._play_task.cancel()
+ try:
+ await self._play_task
+ except asyncio.CancelledError:
+ pass
+
+ # Clean up all track streams
+ for stream, _ in list(self._track_streams.values()):
+ try:
+ await stream.aclose()
+ except Exception:
+ pass
+ self._track_streams.clear()
+
+ # Close mixer
+ if self._mixer is not None:
+ try:
+ await self._mixer.aclose()
+ except Exception:
+ pass
+ self._mixer = None
+
+ # Close output stream
+ try:
+ self._stream.stop()
+ self._stream.close()
+ except Exception:
+ pass
+
+
+class MediaDevices:
+ """High-level interface to native audio devices.
+
+ - Device enumeration helpers.
+ - Audio input capture into `rtc.AudioSource` with optional APM processing.
+ - Audio output player that can feed APM reverse stream for AEC.
+
+ Design notes:
+ - APM operates on 10 ms frames; this module slices input/output audio into
+ `FRAME_SAMPLES` for processing calls.
+ - For AEC to be effective, render audio that could leak back into the mic
+ should be played through `OutputPlayer` with the same `apm` instance.
+ - Timing alignment: this helper does not attempt to set device latency on
+ APM; for most setups the default behavior is acceptable.
+ """
+
+ def __init__(
+ self,
+ *,
+ loop: Optional[asyncio.AbstractEventLoop] = None,
+ input_sample_rate: int = DEFAULT_SAMPLE_RATE,
+ output_sample_rate: int = DEFAULT_SAMPLE_RATE,
+ num_channels: int = DEFAULT_CHANNELS,
+ blocksize: int = BLOCKSIZE,
+ ) -> None:
+ self._loop = _ensure_loop(loop)
+ self._in_sr = input_sample_rate
+ self._out_sr = output_sample_rate
+ self._channels = num_channels
+ self._blocksize = blocksize
+ self._delay_estimator: Optional[_APMDelayEstimator] = None
+ self._apm: Optional[AudioProcessingModule] = None
+
+ # Device enumeration
+ def list_input_devices(self) -> list[dict[str, Any]]:
+ """List available input devices.
+
+ Returns a list of dictionaries with the `sounddevice` metadata and an
+ added `index` key corresponding to the device index.
+ """
+ import sounddevice as sd # type: ignore[import-not-found, import-untyped]
+
+ devices = sd.query_devices()
+ result: list[dict[str, Any]] = []
+ for idx, dev in enumerate(devices):
+ if dev.get("max_input_channels", 0) > 0:
+ result.append({"index": idx, **dev})
+ return result
+
+ def list_output_devices(self) -> list[dict[str, Any]]:
+ """List available output devices with indices."""
+ import sounddevice as sd # type: ignore[import-not-found, import-untyped]
+
+ devices = sd.query_devices()
+ result: list[dict[str, Any]] = []
+ for idx, dev in enumerate(devices):
+ if dev.get("max_output_channels", 0) > 0:
+ result.append({"index": idx, **dev})
+ return result
+
+ def default_input_device(self) -> Optional[int]:
+ """Return the default input device index (or None)."""
+ import sounddevice as sd # type: ignore[import-not-found, import-untyped]
+
+ dev = sd.default.device
+ return dev[0] if isinstance(dev, (list, tuple)) else None
+
+ def default_output_device(self) -> Optional[int]:
+ """Return the default output device index (or None)."""
+ import sounddevice as sd # type: ignore[import-not-found, import-untyped]
+
+ dev = sd.default.device
+ return dev[1] if isinstance(dev, (list, tuple)) else None
+
+ # Capture / Playback
+ def open_input(
+ self,
+ *,
+ enable_aec: bool = True,
+ noise_suppression: bool = True,
+ high_pass_filter: bool = True,
+ auto_gain_control: bool = True,
+ input_device: Optional[int] = None,
+ queue_capacity: int = 50,
+ input_channel_index: Optional[int] = None,
+ ) -> InputCapture:
+ """Open the default (or chosen) audio input device and start capture.
+
+ Frames are sliced into 10 ms chunks. If any processing option is enabled,
+ an `AudioProcessingModule` is created and applied to each frame before it
+ is queued for `AudioSource.capture_frame`.
+
+ To enable AEC end-to-end, call `open_output()` after opening the input
+ device. The output player will automatically use the input's APM for
+ reverse stream processing, enabling echo cancellation.
+
+ Args:
+ enable_aec: Enable acoustic echo cancellation.
+ noise_suppression: Enable noise suppression.
+ high_pass_filter: Enable high-pass filtering.
+ auto_gain_control: Enable automatic gain control.
+ input_device: Optional input device index (default system device if None).
+ queue_capacity: Max queued frames between callback and async pump.
+ input_channel_index: Optional zero-based device channel to capture. If provided,
+ only that channel is opened (via sounddevice mapping) and used as mono input.
+
+ Returns:
+ InputCapture: Holder with `source`, `apm`, and `aclose()`.
+ """
+ import sounddevice as sd # type: ignore[import-not-found, import-untyped]
+
+ loop = self._loop
+ source = AudioSource(self._in_sr, self._channels, loop=loop)
+ apm: Optional[AudioProcessingModule] = None
+ if enable_aec or noise_suppression or high_pass_filter or auto_gain_control:
+ apm = AudioProcessingModule(
+ echo_cancellation=enable_aec,
+ noise_suppression=noise_suppression,
+ high_pass_filter=high_pass_filter,
+ auto_gain_control=auto_gain_control,
+ )
+ delay_estimator: Optional[_APMDelayEstimator] = (
+ _APMDelayEstimator() if apm is not None else None
+ )
+ # Store the shared estimator and APM on the device helper so the output player can reuse them
+ self._delay_estimator = delay_estimator
+ self._apm = apm
+
+ # Queue from callback to async task
+ q: asyncio.Queue[AudioFrame] = asyncio.Queue(maxsize=queue_capacity)
+
+ def _input_callback(
+ indata: np.ndarray, frame_count: int, time_info: Any, status: Any
+ ) -> None:
+ # Slice into 10 ms frames, optionally APM, enqueue for async capture
+ # Compute input (capture) delay using PortAudio timing; combine with last
+ # measured output delay to provide APM stream delay in milliseconds.
+ if apm is not None:
+ try:
+ input_delay_sec = float(time_info.currentTime - time_info.inputBufferAdcTime)
+ output_delay_sec = (
+ float(delay_estimator.get_output_delay()) if delay_estimator else 0.0
+ )
+ total_delay_ms = int(max((input_delay_sec + output_delay_sec) * 1000.0, 0.0))
+ try:
+ apm.set_stream_delay_ms(total_delay_ms)
+ except Exception:
+ pass
+ except Exception:
+ pass
+ num_frames = frame_count // FRAME_SAMPLES
+ for i in range(num_frames):
+ start = i * FRAME_SAMPLES
+ end = start + FRAME_SAMPLES
+ if end > frame_count:
+ break
+ chunk = indata[start:end, 0]
+ frame = AudioFrame(
+ data=chunk.tobytes(),
+ samples_per_channel=FRAME_SAMPLES,
+ sample_rate=self._in_sr,
+ num_channels=self._channels,
+ )
+ if apm is not None:
+ try:
+ apm.process_stream(frame)
+ except Exception:
+ # Continue even if APM processing fails
+ pass
+ try:
+ # Non-blocking: drop if full
+ if not q.full():
+ loop.call_soon_threadsafe(q.put_nowait, frame)
+ except Exception:
+ pass
+
+ # Note: input_channel_index is currently not used as sounddevice mapping
+ # parameter is not supported in all versions.
+ input_stream = sd.InputStream(
+ callback=_input_callback,
+ dtype="int16",
+ channels=self._channels,
+ device=input_device,
+ samplerate=self._in_sr,
+ blocksize=self._blocksize,
+ )
+ input_stream.start()
+
+ async def _pump() -> None:
+ # Drain queue into AudioSource
+ while True:
+ try:
+ frame = await q.get()
+ except asyncio.CancelledError:
+ break
+ try:
+ await source.capture_frame(frame)
+ except Exception:
+ # Ignore capture errors to keep the pump alive
+ pass
+
+ task = asyncio.create_task(_pump())
+ return InputCapture(
+ source=source,
+ input_stream=input_stream,
+ task=task,
+ apm=apm,
+ delay_estimator=delay_estimator,
+ )
+
+ def open_output(
+ self,
+ *,
+ output_device: Optional[int] = None,
+ ) -> OutputPlayer:
+ """Create an `OutputPlayer` for rendering and (optionally) AEC reverse.
+
+ If an input device was opened with AEC enabled, the output player will
+ automatically feed the APM's reverse stream for echo cancellation.
+
+ Args:
+ output_device: Optional output device index (default system device if None).
+ """
+ return OutputPlayer(
+ sample_rate=self._out_sr,
+ num_channels=self._channels,
+ blocksize=self._blocksize,
+ apm_for_reverse=self._apm,
+ output_device=output_device,
+ delay_estimator=self._delay_estimator,
+ )
diff --git a/livekit-rtc/livekit/rtc/participant.py b/livekit-rtc/livekit/rtc/participant.py
index 7d7351f9..150477d5 100644
--- a/livekit-rtc/livekit/rtc/participant.py
+++ b/livekit-rtc/livekit/rtc/participant.py
@@ -15,18 +15,26 @@
from __future__ import annotations
import ctypes
-from typing import List, Union
+import asyncio
+import datetime
+import os
+import mimetypes
+import aiofiles
+from typing import List, Union, Callable, Dict, Awaitable, Optional, Mapping, cast, TypeVar
+from abc import abstractmethod, ABC
from ._ffi_client import FfiClient, FfiHandle
from ._proto import ffi_pb2 as proto_ffi
from ._proto import participant_pb2 as proto_participant
from ._proto.room_pb2 import (
- DataPacketKind,
TrackPublishOptions,
)
from ._proto.room_pb2 import (
TranscriptionSegment as ProtoTranscriptionSegment,
)
+from ._proto.track_pb2 import (
+ ParticipantTrackPermission,
+)
from ._utils import BroadcastQueue
from .track import LocalTrack
from .track_publication import (
@@ -35,6 +43,19 @@
TrackPublication,
)
from .transcription import Transcription
+from .rpc import RpcError
+from ._proto.rpc_pb2 import RpcMethodInvocationResponseRequest
+from .log import logger
+
+from .rpc import RpcInvocationData
+from .data_stream import (
+ TextStreamWriter,
+ ByteStreamWriter,
+ ByteStreamInfo,
+ STREAM_CHUNK_SIZE,
+)
+from .data_track import LocalDataTrack
+from ._proto import data_track_pb2 as proto_data_track
class PublishTrackError(Exception):
@@ -52,16 +73,33 @@ def __init__(self, message: str) -> None:
self.message = message
+class PublishDTMFError(Exception):
+ def __init__(self, message: str) -> None:
+ self.message = message
+
+
class PublishTranscriptionError(Exception):
def __init__(self, message: str) -> None:
self.message = message
-class Participant:
+class PublishDataTrackError(Exception):
+ def __init__(self, message: str) -> None:
+ self.message = message
+
+
+class Participant(ABC):
def __init__(self, owned_info: proto_participant.OwnedParticipant) -> None:
self._info = owned_info.info
self._ffi_handle = FfiHandle(owned_info.handle.id)
- self.tracks: dict[str, TrackPublication] = {}
+
+ @property
+ @abstractmethod
+ def track_publications(self) -> Mapping[str, TrackPublication]:
+ """
+ A dictionary of track publications associated with the participant.
+ """
+ ...
@property
def sid(self) -> str:
@@ -79,8 +117,69 @@ def identity(self) -> str:
def metadata(self) -> str:
return self._info.metadata
+ @property
+ def attributes(self) -> dict[str, str]:
+ """Custom attributes associated with the participant."""
+ return dict(self._info.attributes)
+
+ @property
+ def kind(self) -> proto_participant.ParticipantKind.ValueType:
+ """Participant's kind (e.g., regular participant, ingress, egress, sip, agent)."""
+ return self._info.kind
+
+ @property
+ def state(self) -> proto_participant.ParticipantState.ValueType:
+ """Participant's connection state (joining, joined, active, disconnected)."""
+ return self._info.state
+
+ @property
+ def joined_at(self) -> datetime.datetime | None:
+ """Timestamp of when the participant joined the room, or None if not yet joined."""
+ if self._info.joined_at == 0:
+ return None
+ return datetime.datetime.fromtimestamp(
+ self._info.joined_at / 1000, tz=datetime.timezone.utc
+ )
+
+ @property
+ def permissions(self) -> proto_participant.ParticipantPermission:
+ """The participant's permissions within the room."""
+ return self._info.permission
+
+ @property
+ def disconnect_reason(
+ self,
+ ) -> Optional[proto_participant.DisconnectReason.ValueType]:
+ """Reason for the participant's disconnection.
+
+ Returns one of DisconnectReasons or None if the participant isn't disconnected. Common reasons are:
+ - CLIENT_INITIATED - the client initiated the disconnect
+ - DUPLICATE_IDENTITY - another participant with the same identity has joined the room
+ - SERVER_SHUTDOWN - the server instance is shutting down
+ - PARTICIPANT_REMOVED - RoomService.RemoveParticipant was called
+ - ROOM_DELETED - RoomService.DeleteRoom was called
+ - STATE_MISMATCH - the client is attempting to resume a session, but server is not aware of it
+ - JOIN_FAILURE - client was unable to connect fully
+
+ When dialing a participant via SIP, you may see the following reasons:
+ - USER_UNAVAILABLE - SIP callee did not respond in time
+ - USER_REJECTED - SIP callee rejected the call (busy)
+ - SIP_TRUNK_FAILURE - SIP protocol failure or unexpected response
+ """
+ if self._info.disconnect_reason == proto_participant.DisconnectReason.UNKNOWN_REASON:
+ return None
+ return self._info.disconnect_reason
+
+
+RpcHandler = Callable[["RpcInvocationData"], Union[Awaitable[Optional[str]], Optional[str]]]
+F = TypeVar(
+ "F", bound=Callable[[RpcInvocationData], Union[Awaitable[Optional[str]], Optional[str]]]
+)
+
class LocalParticipant(Participant):
+ """Represents the local participant in a room."""
+
def __init__(
self,
room_queue: BroadcastQueue[proto_ffi.FfiEvent],
@@ -88,15 +187,36 @@ def __init__(
) -> None:
super().__init__(owned_info)
self._room_queue = room_queue
- self.tracks: dict[str, LocalTrackPublication] = {} # type: ignore
+ self._track_publications: dict[str, LocalTrackPublication] = {} # type: ignore
+ self._rpc_handlers: Dict[str, RpcHandler] = {}
+
+ @property
+ def track_publications(self) -> Mapping[str, LocalTrackPublication]:
+ """
+ A dictionary of track publications associated with the participant.
+ """
+ return self._track_publications
async def publish_data(
self,
payload: Union[bytes, str],
- kind: DataPacketKind.ValueType = DataPacketKind.KIND_RELIABLE,
- destination_sids: List[Union[str, "RemoteParticipant"]] = [],
+ *,
+ reliable: bool = True,
+ destination_identities: List[str] = [],
topic: str = "",
) -> None:
+ """
+ Publish arbitrary data to the room.
+
+ Args:
+ payload (Union[bytes, str]): The data to publish.
+ reliable (bool, optional): Whether to send reliably or not. Defaults to True.
+ destination_identities (List[str], optional): List of participant identities to send to. Defaults to [].
+ topic (str, optional): The topic under which to publish the data. Defaults to "".
+
+ Raises:
+ PublishDataError: If there is an error in publishing data.
+ """
if isinstance(payload, str):
payload = payload.encode("utf-8")
@@ -107,22 +227,14 @@ async def publish_data(
req.publish_data.local_participant_handle = self._ffi_handle.handle
req.publish_data.data_ptr = ctypes.addressof(cdata)
req.publish_data.data_len = data_len
- req.publish_data.kind = kind
+ req.publish_data.reliable = reliable
req.publish_data.topic = topic
-
- sids = []
- for p in destination_sids:
- if isinstance(p, RemoteParticipant):
- sids.append(p.sid)
- else:
- sids.append(p)
-
- req.publish_data.destination_sids.extend(sids)
+ req.publish_data.destination_identities.extend(destination_identities)
queue = FfiClient.instance.queue.subscribe()
try:
resp = FfiClient.instance.request(req)
- cb = await queue.wait_for(
+ cb: proto_ffi.FfiEvent = await queue.wait_for(
lambda e: e.publish_data.async_id == resp.publish_data.async_id
)
finally:
@@ -131,7 +243,44 @@ async def publish_data(
if cb.publish_data.error:
raise PublishDataError(cb.publish_data.error)
+ async def publish_dtmf(self, *, code: int, digit: str) -> None:
+ """
+ Publish SIP DTMF message.
+
+ Args:
+ code (int): DTMF code.
+ digit (str): DTMF digit.
+
+ Raises:
+ PublishDTMFError: If there is an error in publishing SIP DTMF message.
+ """
+ req = proto_ffi.FfiRequest()
+ req.publish_sip_dtmf.local_participant_handle = self._ffi_handle.handle
+ req.publish_sip_dtmf.code = code
+ req.publish_sip_dtmf.digit = digit
+
+ queue = FfiClient.instance.queue.subscribe()
+ try:
+ resp = FfiClient.instance.request(req)
+ cb: proto_ffi.FfiEvent = await queue.wait_for(
+ lambda e: e.publish_sip_dtmf.async_id == resp.publish_sip_dtmf.async_id
+ )
+ finally:
+ FfiClient.instance.queue.unsubscribe(queue)
+
+ if cb.publish_sip_dtmf.error:
+ raise PublishDTMFError(cb.publish_sip_dtmf.error)
+
async def publish_transcription(self, transcription: Transcription) -> None:
+ """
+ Publish transcription data to the room.
+
+ Args:
+ transcription (Transcription): The transcription data to publish.
+
+ Raises:
+ PublishTranscriptionError: If there is an error in publishing transcription.
+ """
req = proto_ffi.FfiRequest()
proto_segments = [
ProtoTranscriptionSegment(
@@ -140,6 +289,7 @@ async def publish_transcription(self, transcription: Transcription) -> None:
start_time=s.start_time,
end_time=s.end_time,
final=s.final,
+ language=s.language,
)
for s in transcription.segments
]
@@ -147,15 +297,13 @@ async def publish_transcription(self, transcription: Transcription) -> None:
req.publish_transcription.local_participant_handle = self._ffi_handle.handle
req.publish_transcription.participant_identity = transcription.participant_identity
req.publish_transcription.segments.extend(proto_segments)
- req.publish_transcription.track_id = transcription.track_id
- req.publish_transcription.language = transcription.language
+ req.publish_transcription.track_id = transcription.track_sid
# fmt: on
queue = FfiClient.instance.queue.subscribe()
try:
resp = FfiClient.instance.request(req)
- cb = await queue.wait_for(
- lambda e: e.publish_transcription.async_id
- == resp.publish_transcription.async_id
+ cb: proto_ffi.FfiEvent = await queue.wait_for(
+ lambda e: e.publish_transcription.async_id == resp.publish_transcription.async_id
)
finally:
FfiClient.instance.queue.unsubscribe(queue)
@@ -163,39 +311,438 @@ async def publish_transcription(self, transcription: Transcription) -> None:
if cb.publish_transcription.error:
raise PublishTranscriptionError(cb.publish_transcription.error)
- async def update_metadata(self, metadata: str) -> None:
+ async def perform_rpc(
+ self,
+ *,
+ destination_identity: str,
+ method: str,
+ payload: str,
+ response_timeout: Optional[float] = None,
+ ) -> str:
+ """
+ Initiate an RPC call to a remote participant.
+
+ Args:
+ destination_identity (str): The `identity` of the destination participant
+ method (str): The method name to call
+ payload (str): The method payload
+ response_timeout (Optional[float]): Timeout for receiving a response after initial connection
+
+ Returns:
+ str: The response payload
+
+ Raises:
+ RpcError: On failure. Details in `message`.
+ """
+ req = proto_ffi.FfiRequest()
+ req.perform_rpc.local_participant_handle = self._ffi_handle.handle
+ req.perform_rpc.destination_identity = destination_identity
+ req.perform_rpc.method = method
+ req.perform_rpc.payload = payload
+ if response_timeout is not None:
+ req.perform_rpc.response_timeout_ms = int(response_timeout * 1000)
+
+ queue = FfiClient.instance.queue.subscribe()
+ try:
+ resp = FfiClient.instance.request(req)
+ cb = await queue.wait_for(lambda e: e.perform_rpc.async_id == resp.perform_rpc.async_id)
+ finally:
+ FfiClient.instance.queue.unsubscribe(queue)
+
+ if cb.perform_rpc.HasField("error"):
+ raise RpcError._from_proto(cb.perform_rpc.error)
+
+ return cb.perform_rpc.payload
+
+ def register_rpc_method(
+ self,
+ method_name: str,
+ handler: Optional[F] = None,
+ ) -> Union[F, Callable[[F], F]]:
+ """
+ Establishes the participant as a receiver for calls of the specified RPC method.
+ Can be used either as a decorator or a regular method.
+
+ The handler will receive one argument of type `RpcInvocationData` and should return a string response which will be forwarded back to the caller.
+
+ The handler may be synchronous or asynchronous.
+
+ If unable to respond within `response_timeout`, the caller will hang up and receive an error on their side.
+
+ You may raise errors of type `RpcError` in the handler, and they will be forwarded to the caller.
+
+ Other errors raised in your handler will be caught and forwarded to the caller as "1500 Application Error".
+
+ Args:
+ method_name (str): The name of the indicated RPC method.
+ handler (Optional[Callable]): Handler to be invoked whenever an RPC request for this method is received. Omit this argument to use the decorator syntax.
+
+ Returns:
+ None (when used as a decorator it returns the decorator function)
+
+ Example:
+ # As a decorator:
+ @room.local_participant.register_rpc_method("greet")
+ async def greet_handler(data: RpcInvocationData) -> str:
+ print(f"Received greeting from {data.caller_identity}: {data.payload}")
+ return f"Hello, {data.caller_identity}!"
+
+ # As a regular method:
+ async def greet_handler(data: RpcInvocationData) -> str:
+ print(f"Received greeting from {data.caller_identity}: {data.payload}")
+ return f"Hello, {data.caller_identity}!"
+
+ room.local_participant.register_rpc_method('greet', greet_handler)
+ """
+
+ def register(handler_func: F) -> F:
+ self._rpc_handlers[method_name] = handler_func
+ req = proto_ffi.FfiRequest()
+ req.register_rpc_method.local_participant_handle = self._ffi_handle.handle
+ req.register_rpc_method.method = method_name
+ FfiClient.instance.request(req)
+ return handler_func
+
+ if handler is not None:
+ return register(handler)
+ else:
+ return register
+
+ def unregister_rpc_method(self, method: str) -> None:
+ """
+ Unregisters a previously registered RPC method.
+
+ Args:
+ method (str): The name of the RPC method to unregister
+ """
+ self._rpc_handlers.pop(method, None)
+
+ req = proto_ffi.FfiRequest()
+ req.unregister_rpc_method.local_participant_handle = self._ffi_handle.handle
+ req.unregister_rpc_method.method = method
+
+ FfiClient.instance.request(req)
+
+ def set_track_subscription_permissions(
+ self,
+ *,
+ allow_all_participants: bool,
+ participant_permissions: Optional[List[ParticipantTrackPermission]] = None,
+ ) -> None:
+ """
+ Set the track subscription permissions for the local participant.
+
+ Args:
+ allow_all_participants (bool): Whether to allow all participants to subscribe to this participant's tracks.
+ participant_permissions (List[ParticipantTrackPermission]): Participant-specific track subscription permissions, ignored if `allow_all_participants` is True.
+ """
+ if participant_permissions is None:
+ participant_permissions = []
+
+ req = proto_ffi.FfiRequest()
+ req.set_track_subscription_permissions.local_participant_handle = self._ffi_handle.handle
+ req.set_track_subscription_permissions.all_participants_allowed = allow_all_participants
+ req.set_track_subscription_permissions.permissions.extend(participant_permissions)
+ FfiClient.instance.request(req)
+
+ async def _handle_rpc_method_invocation(
+ self,
+ invocation_id: int,
+ method: str,
+ request_id: str,
+ caller_identity: str,
+ payload: str,
+ response_timeout: float,
+ ) -> None:
+ response_error: Optional[RpcError] = None
+ response_payload: Optional[str] = None
+
+ params = RpcInvocationData(request_id, caller_identity, payload, response_timeout)
+
+ handler = self._rpc_handlers.get(method)
+
+ if not handler:
+ response_error = RpcError._built_in(RpcError.ErrorCode.UNSUPPORTED_METHOD)
+ else:
+ try:
+ if asyncio.iscoroutinefunction(handler):
+ try:
+ response_payload = await asyncio.wait_for(
+ handler(params), timeout=response_timeout
+ )
+ except asyncio.TimeoutError:
+ raise RpcError._built_in(RpcError.ErrorCode.RESPONSE_TIMEOUT)
+ except asyncio.CancelledError:
+ raise RpcError._built_in(RpcError.ErrorCode.RECIPIENT_DISCONNECTED)
+ else:
+ response_payload = cast(Optional[str], handler(params))
+ except RpcError as error:
+ response_error = error
+ except Exception:
+ logger.exception(
+ f"Uncaught error returned by RPC handler for {method}. "
+ "Returning APPLICATION_ERROR instead. "
+ )
+ response_error = RpcError._built_in(RpcError.ErrorCode.APPLICATION_ERROR)
+
+ req = proto_ffi.FfiRequest(
+ rpc_method_invocation_response=RpcMethodInvocationResponseRequest(
+ local_participant_handle=self._ffi_handle.handle,
+ invocation_id=invocation_id,
+ error=response_error._to_proto() if response_error else None,
+ payload=response_payload,
+ )
+ )
+
+ res = FfiClient.instance.request(req)
+
+ if res.rpc_method_invocation_response.error:
+ err = res.rpc_method_invocation_response.error
+ logger.error(f"error sending rpc method invocation response: {err}")
+
+ async def set_metadata(self, metadata: str) -> None:
+ """
+ Set the metadata for the local participant.
+
+ Note: this requires `canUpdateOwnMetadata` permission.
+
+ Args:
+ metadata (str): The new metadata.
+ """
req = proto_ffi.FfiRequest()
- req.update_local_metadata.local_participant_handle = self._ffi_handle.handle
- req.update_local_metadata.metadata = metadata
+ req.set_local_metadata.local_participant_handle = self._ffi_handle.handle
+ req.set_local_metadata.metadata = metadata
queue = FfiClient.instance.queue.subscribe()
try:
resp = FfiClient.instance.request(req)
await queue.wait_for(
- lambda e: e.update_local_metadata.async_id
- == resp.update_local_metadata.async_id
+ lambda e: e.set_local_metadata.async_id == resp.set_local_metadata.async_id
)
finally:
FfiClient.instance.queue.unsubscribe(queue)
- async def update_name(self, name: str) -> None:
+ async def set_name(self, name: str) -> None:
+ """
+ Set the name for the local participant.
+
+ Note: this requires `canUpdateOwnMetadata` permission.
+
+ Args:
+ name (str): The new name.
+ """
+ req = proto_ffi.FfiRequest()
+ req.set_local_name.local_participant_handle = self._ffi_handle.handle
+ req.set_local_name.name = name
+
+ queue = FfiClient.instance.queue.subscribe()
+ try:
+ resp = FfiClient.instance.request(req)
+ await queue.wait_for(
+ lambda e: e.set_local_name.async_id == resp.set_local_name.async_id
+ )
+ finally:
+ FfiClient.instance.queue.unsubscribe(queue)
+
+ async def set_attributes(self, attributes: dict[str, str]) -> None:
+ """
+ Set custom attributes for the local participant.
+
+ Note: this requires `canUpdateOwnMetadata` permission.
+
+ Args:
+ attributes (dict[str, str]): A dictionary of attributes to set.
+ """
req = proto_ffi.FfiRequest()
- req.update_local_name.local_participant_handle = self._ffi_handle.handle
- req.update_local_name.name = name
+ req.set_local_attributes.local_participant_handle = self._ffi_handle.handle
+ existing_attributes = {
+ entry.key: entry.value for entry in req.set_local_attributes.attributes
+ }
+ existing_attributes.update(attributes)
+
+ for key, value in existing_attributes.items():
+ entry = req.set_local_attributes.attributes.add()
+ entry.key = key
+ entry.value = value
queue = FfiClient.instance.queue.subscribe()
try:
resp = FfiClient.instance.request(req)
await queue.wait_for(
- lambda e: e.update_local_name.async_id
- == resp.update_local_name.async_id
+ lambda e: e.set_local_attributes.async_id == resp.set_local_attributes.async_id
+ )
+ finally:
+ FfiClient.instance.queue.unsubscribe(queue)
+
+ async def stream_text(
+ self,
+ *,
+ destination_identities: Optional[List[str]] = None,
+ topic: str = "",
+ attributes: Optional[Dict[str, str]] = None,
+ stream_id: str | None = None,
+ reply_to_id: str | None = None,
+ total_size: int | None = None,
+ sender_identity: str | None = None,
+ ) -> TextStreamWriter:
+ """
+ Returns a TextStreamWriter that allows to write individual chunks of text to a text stream.
+ In most cases where you want to simply send a text message use send_text() instead.
+ """
+ writer = TextStreamWriter(
+ self,
+ topic=topic,
+ attributes=attributes,
+ reply_to_id=reply_to_id,
+ destination_identities=destination_identities,
+ total_size=total_size,
+ stream_id=stream_id,
+ sender_identity=sender_identity,
+ )
+
+ await writer._send_header()
+
+ return writer
+
+ async def send_text(
+ self,
+ text: str,
+ *,
+ destination_identities: Optional[List[str]] = None,
+ topic: str = "",
+ attributes: Optional[Dict[str, str]] = None,
+ reply_to_id: str | None = None,
+ ):
+ total_size = len(text.encode())
+ writer = await self.stream_text(
+ destination_identities=destination_identities,
+ topic=topic,
+ attributes=attributes,
+ reply_to_id=reply_to_id,
+ total_size=total_size,
+ )
+
+ await writer.write(text)
+ await writer.aclose()
+
+ return writer.info
+
+ async def stream_bytes(
+ self,
+ name: str,
+ *,
+ total_size: int | None = None,
+ mime_type: str = "application/octet-stream",
+ attributes: Optional[Dict[str, str]] = None,
+ stream_id: str | None = None,
+ destination_identities: Optional[List[str]] = None,
+ topic: str = "",
+ ) -> ByteStreamWriter:
+ """
+ Returns a ByteStreamWriter that allows to write individual chunks of bytes to a byte stream.
+ In cases where you want to simply send a file from the file system use send_file() instead.
+ """
+ writer = ByteStreamWriter(
+ self,
+ name=name,
+ attributes=attributes,
+ total_size=total_size,
+ stream_id=stream_id,
+ mime_type=mime_type,
+ destination_identities=destination_identities,
+ topic=topic,
+ )
+
+ await writer._send_header()
+
+ return writer
+
+ async def send_file(
+ self,
+ file_path: str,
+ *,
+ topic: str = "",
+ destination_identities: Optional[List[str]] = None,
+ attributes: Optional[Dict[str, str]] = None,
+ stream_id: str | None = None,
+ ) -> ByteStreamInfo:
+ file_size = os.path.getsize(file_path)
+ file_name = os.path.basename(file_path)
+ mime_type, _ = mimetypes.guess_type(file_path)
+ if mime_type is None:
+ mime_type = "application/octet-stream" # Fallback MIME type for unknown files
+
+ writer: ByteStreamWriter = await self.stream_bytes(
+ name=file_name,
+ total_size=file_size,
+ mime_type=mime_type,
+ attributes=attributes,
+ stream_id=stream_id,
+ destination_identities=destination_identities,
+ topic=topic,
+ )
+
+ async with aiofiles.open(file_path, "rb") as f:
+ while bytes := await f.read(STREAM_CHUNK_SIZE):
+ await writer.write(bytes)
+ await writer.aclose()
+
+ return writer.info
+
+ async def publish_data_track(
+ self,
+ *,
+ name: str,
+ ) -> LocalDataTrack:
+ """Publishes a data track.
+
+ Args:
+ name: The track name used to identify the track to other participants.
+ Must not be empty and must be unique per publisher.
+
+ Returns:
+ The published data track. Use :meth:`LocalDataTrack.try_push` to
+ send data frames on the track.
+
+ Raises:
+ PublishDataTrackError: If there is an error publishing the data track.
+ """
+ proto_opts = proto_data_track.DataTrackOptions(name=name)
+
+ req = proto_ffi.FfiRequest()
+ req.publish_data_track.local_participant_handle = self._ffi_handle.handle
+ req.publish_data_track.options.CopyFrom(proto_opts)
+
+ queue = FfiClient.instance.queue.subscribe()
+ try:
+ resp = FfiClient.instance.request(req)
+ cb: proto_ffi.FfiEvent = await queue.wait_for(
+ lambda e: e.publish_data_track.async_id == resp.publish_data_track.async_id
)
finally:
FfiClient.instance.queue.unsubscribe(queue)
+ if cb.publish_data_track.HasField("error"):
+ raise PublishDataTrackError(cb.publish_data_track.error.message)
+
+ return LocalDataTrack(cb.publish_data_track.track)
+
async def publish_track(
self, track: LocalTrack, options: TrackPublishOptions = TrackPublishOptions()
) -> LocalTrackPublication:
+ """
+ Publish a local track to the room.
+
+ Args:
+ track (LocalTrack): The track to publish.
+ options (TrackPublishOptions, optional): Options for publishing the track.
+
+ Returns:
+ LocalTrackPublication: The publication of the published track.
+
+ Raises:
+ PublishTrackError: If there is an error in publishing the track.
+ """
req = proto_ffi.FfiRequest()
req.publish_track.track_handle = track._ffi_handle.handle
req.publish_track.local_participant_handle = self._ffi_handle.handle
@@ -204,7 +751,7 @@ async def publish_track(
queue = self._room_queue.subscribe()
try:
resp = FfiClient.instance.request(req)
- cb = await queue.wait_for(
+ cb: proto_ffi.FfiEvent = await queue.wait_for(
lambda e: e.publish_track.async_id == resp.publish_track.async_id
)
@@ -212,9 +759,9 @@ async def publish_track(
raise PublishTrackError(cb.publish_track.error)
track_publication = LocalTrackPublication(cb.publish_track.publication)
- track_publication.track = track
+ track_publication._track = track
track._info.sid = track_publication.sid
- self.tracks[track_publication.sid] = track_publication
+ self._track_publications[track_publication.sid] = track_publication
queue.task_done()
return track_publication
@@ -222,28 +769,51 @@ async def publish_track(
self._room_queue.unsubscribe(queue)
async def unpublish_track(self, track_sid: str) -> None:
+ """
+ Unpublish a track from the room.
+
+ Args:
+ track_sid (str): The SID of the track to unpublish.
+
+ Raises:
+ UnpublishTrackError: If there is an error in unpublishing the track.
+ """
req = proto_ffi.FfiRequest()
req.unpublish_track.local_participant_handle = self._ffi_handle.handle
req.unpublish_track.track_sid = track_sid
+ req.unpublish_track.stop_on_unpublish = True
queue = self._room_queue.subscribe()
try:
resp = FfiClient.instance.request(req)
- cb = await queue.wait_for(
+ cb: proto_ffi.FfiEvent = await queue.wait_for(
lambda e: e.unpublish_track.async_id == resp.unpublish_track.async_id
)
if cb.unpublish_track.error:
raise UnpublishTrackError(cb.unpublish_track.error)
- publication = self.tracks.pop(track_sid)
- publication.track = None
+ publication = self._track_publications.pop(track_sid)
+ publication._track = None
queue.task_done()
finally:
self._room_queue.unsubscribe(queue)
+ def __repr__(self) -> str:
+ return f"rtc.LocalParticipant(sid={self.sid}, identity={self.identity}, name={self.name})"
+
class RemoteParticipant(Participant):
def __init__(self, owned_info: proto_participant.OwnedParticipant) -> None:
super().__init__(owned_info)
- self.tracks: dict[str, RemoteTrackPublication] = {} # type: ignore
+ self._track_publications: dict[str, RemoteTrackPublication] = {} # type: ignore
+
+ @property
+ def track_publications(self) -> Mapping[str, RemoteTrackPublication]:
+ """
+ A dictionary of track publications associated with the participant.
+ """
+ return self._track_publications
+
+ def __repr__(self) -> str:
+ return f"rtc.RemoteParticipant(sid={self.sid}, identity={self.identity}, name={self.name})"
diff --git a/livekit-rtc/livekit/rtc/resources/.gitattributes b/livekit-rtc/livekit/rtc/resources/.gitattributes
new file mode 100644
index 00000000..c27efeb3
--- /dev/null
+++ b/livekit-rtc/livekit/rtc/resources/.gitattributes
@@ -0,0 +1 @@
+jupyter-html/* linguist-generated=true
\ No newline at end of file
diff --git a/livekit-rtc/livekit/rtc/resources/jupyter-html/index.html b/livekit-rtc/livekit/rtc/resources/jupyter-html/index.html
new file mode 100644
index 00000000..6e35aa15
--- /dev/null
+++ b/livekit-rtc/livekit/rtc/resources/jupyter-html/index.html
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+ Vite + React + TS
+
+
+
+
+
+
+
diff --git a/livekit-rtc/livekit/rtc/room.py b/livekit-rtc/livekit/rtc/room.py
index 2221eb41..5afdf77e 100644
--- a/livekit-rtc/livekit/rtc/room.py
+++ b/livekit-rtc/livekit/rtc/room.py
@@ -11,31 +11,48 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
+from __future__ import annotations
+import datetime
import asyncio
import ctypes
import logging
from dataclasses import dataclass, field
-from typing import Dict, Literal, Optional
+from typing import Callable, Dict, Literal, Optional, cast, Mapping
+import warnings
-from ._event_emitter import EventEmitter
+from .event_emitter import EventEmitter
from ._ffi_client import FfiClient, FfiHandle
from ._proto import ffi_pb2 as proto_ffi
from ._proto import participant_pb2 as proto_participant
from ._proto import room_pb2 as proto_room
+from ._proto import stats_pb2 as proto_stats
+from ._proto.participant_pb2 import DisconnectReason
from ._proto.room_pb2 import ConnectionState
from ._proto.track_pb2 import TrackKind
+from ._proto.rpc_pb2 import RpcMethodInvocationEvent
from ._utils import BroadcastQueue
from .e2ee import E2EEManager, E2EEOptions
from .participant import LocalParticipant, Participant, RemoteParticipant
from .track import RemoteAudioTrack, RemoteVideoTrack
-from .track_publication import RemoteTrackPublication
+from .track_publication import RemoteTrackPublication, TrackPublication
+from .transcription import TranscriptionSegment
+from .data_stream import (
+ TextStreamReader,
+ ByteStreamReader,
+ TextStreamHandler,
+ ByteStreamHandler,
+)
+from .data_track import RemoteDataTrack
+
EventTypes = Literal[
"participant_connected",
"participant_disconnected",
+ "participant_active",
"local_track_published",
"local_track_unpublished",
+ "local_track_subscribed",
"track_published",
"track_unpublished",
"track_subscribed",
@@ -47,15 +64,24 @@
"room_metadata_changed",
"participant_metadata_changed",
"participant_name_changed",
+ "participant_attributes_changed",
"connection_quality_changed",
+ "participant_encryption_status_changed",
+ "participant_permissions_changed",
"data_received",
"sip_dtmf_received",
+ "transcription_received",
"e2ee_state_changed",
"connection_state_changed",
"connected",
"disconnected",
"reconnecting",
"reconnected",
+ "room_updated",
+ "moved",
+ "token_refreshed",
+ "data_track_published",
+ "data_track_unpublished",
]
@@ -64,37 +90,59 @@ class RtcConfiguration:
ice_transport_type: proto_room.IceTransportType.ValueType = (
proto_room.IceTransportType.TRANSPORT_ALL
)
+ """Specifies the type of ICE transport to be used (e.g., all, relay, etc.)."""
continual_gathering_policy: proto_room.ContinualGatheringPolicy.ValueType = (
proto_room.ContinualGatheringPolicy.GATHER_CONTINUALLY
)
+ """Policy for continual gathering of ICE candidates."""
ice_servers: list[proto_room.IceServer] = field(default_factory=list)
+ """List of ICE servers for STUN/TURN. When empty, it uses the default ICE servers provided by
+ the SFU."""
@dataclass
class RoomOptions:
auto_subscribe: bool = True
+ """Automatically subscribe to tracks when participants join."""
dynacast: bool = False
- e2ee: Optional[E2EEOptions] = None
- rtc_config: Optional[RtcConfiguration] = None
+ e2ee: E2EEOptions | None = None
+ """Deprecated, use `encryption` field instead"""
+ encryption: E2EEOptions | None = None
+ """Options for end-to-end encryption."""
+ rtc_config: RtcConfiguration | None = None
+ """WebRTC-related configuration."""
+ connect_timeout: float | None = None
+ """Timeout in seconds for each signal connection attempt. When None, uses the default (5s)."""
+ single_peer_connection: bool | None = None
+ """Use a single peer connection for both publish and subscribe. When None, uses the default (false)."""
@dataclass
class DataPacket:
data: bytes
+ """The payload of the data packet."""
kind: proto_room.DataPacketKind.ValueType
- participant: Optional[RemoteParticipant] = (
- None # None when the data has been sent by a server SDK
- )
- topic: Optional[str] = None
+ """Type of the data packet (e.g., RELIABLE, LOSSY)."""
+ participant: RemoteParticipant | None
+ """Participant who sent the data. None when sent by a server SDK."""
+ topic: str | None = None
+ """Topic associated with the data packet."""
@dataclass
class SipDTMF:
code: int
+ """DTMF code corresponding to the digit."""
digit: str
- participant: Optional[RemoteParticipant] = (
- None # None when the data has been sent by a server SDK
- )
+ """DTMF digit sent."""
+ participant: RemoteParticipant | None = None
+ """Participant who sent the DTMF digit. None when sent by a server SDK."""
+
+
+@dataclass
+class RtcStats:
+ publisher_stats: list[proto_stats.RtcStats]
+ subscriber_stats: list[proto_stats.RtcStats]
class ConnectError(Exception):
@@ -103,47 +151,293 @@ def __init__(self, message: str):
class Room(EventEmitter[EventTypes]):
- def __init__(self, loop: Optional[asyncio.AbstractEventLoop] = None) -> None:
+ def __init__(
+ self,
+ loop: Optional[asyncio.AbstractEventLoop] = None,
+ ) -> None:
+ """Initializes a new Room instance.
+
+ Parameters:
+ loop (Optional[asyncio.AbstractEventLoop]): The event loop to use. If not provided, the default event loop is used.
+ """
super().__init__()
self._ffi_handle: Optional[FfiHandle] = None
self._loop = loop or asyncio.get_event_loop()
self._room_queue = BroadcastQueue[proto_ffi.FfiEvent]()
self._info = proto_room.RoomInfo()
+ self._rpc_invocation_tasks: set[asyncio.Task] = set()
+ self._data_stream_tasks: set[asyncio.Task] = set()
+
+ self._remote_participants: Dict[str, RemoteParticipant] = {}
+ self._connection_state = ConnectionState.CONN_DISCONNECTED
+ self._first_sid_future = asyncio.Future[str]()
+ self._local_participant: LocalParticipant | None = None
+
+ self._text_stream_readers: Dict[str, TextStreamReader] = {}
+ self._byte_stream_readers: Dict[str, ByteStreamReader] = {}
+ self._text_stream_handlers: Dict[str, TextStreamHandler] = {}
+ self._byte_stream_handlers: Dict[str, ByteStreamHandler] = {}
- self.participants: Dict[str, RemoteParticipant] = {}
- self.participants_by_identity: Dict[str, RemoteParticipant] = {}
- self.connection_state = ConnectionState.CONN_DISCONNECTED
+ self._token: str | None = None
+ self._server_url: str | None = None
def __del__(self) -> None:
if self._ffi_handle is not None:
FfiClient.instance.queue.unsubscribe(self._ffi_queue)
@property
- def sid(self) -> str:
- return self._info.sid
+ async def sid(self) -> str:
+ """Asynchronously retrieves the session ID (SID) of the room.
+
+ Returns:
+ str: The session ID of the room.
+ """
+ if self._info.sid:
+ return self._info.sid
+
+ return await self._first_sid_future
+
+ @property
+ def local_participant(self) -> LocalParticipant:
+ """Gets the local participant in the room.
+
+ Returns:
+ LocalParticipant: The local participant in the room.
+ """
+ if self._local_participant is None:
+ raise Exception("cannot access local participant before connecting")
+
+ return self._local_participant
+
+ @property
+ def connection_state(self) -> ConnectionState.ValueType:
+ """Gets the connection state of the room.
+
+ Returns:
+ ConnectionState: The connection state of the room.
+ """
+ return self._connection_state
+
+ @property
+ def remote_participants(self) -> Mapping[str, RemoteParticipant]:
+ """Gets the remote participants in the room.
+
+ Returns:
+ dict[str, RemoteParticipant]: A dictionary of remote participants indexed by their
+ identity.
+ """
+ return self._remote_participants
@property
def name(self) -> str:
+ """Gets the name of the room.
+
+ Returns:
+ str: The name of the room.
+ """
return self._info.name
@property
def metadata(self) -> str:
+ """Gets the metadata associated with the room.
+
+ Returns:
+ str: The metadata of the room.
+ """
return self._info.metadata
@property
def e2ee_manager(self) -> E2EEManager:
+ """Gets the end-to-end encryption (E2EE) manager for the room.
+
+ Returns:
+ E2EEManager: The E2EE manager instance.
+ """
return self._e2ee_manager
+ @property
+ def num_participants(self) -> int:
+ """Gets the number of participants in the room.
+ This value is updated periodically, and is eventually consistent.
+
+ Returns:
+ int: The number of participants in the room.
+ """
+ return self._info.num_participants
+
+ @property
+ def num_publishers(self) -> int:
+ """Gets the number of publishers in the room.
+ This value is updated periodically, and is eventually consistent.
+
+ Returns:
+ int: The number of publishers in the room.
+ """
+ return self._info.num_publishers
+
+ @property
+ def creation_time(self) -> datetime.datetime:
+ """Time when the room was created.
+
+ Returns:
+ datetime.datetime: The creation time of the room.
+ """
+ return datetime.datetime.fromtimestamp(
+ self._info.creation_time / 1000, datetime.timezone.utc
+ )
+
+ @property
+ def is_recording(self) -> bool:
+ """Whether the room is actively recording.
+
+ Returns:
+ bool: True if actively recording, False otherwise.
+ """
+ return self._info.active_recording
+
+ @property
+ def departure_timeout(self) -> float:
+ """Amount of time to hold the room open after the last standard participant leaves.
+
+ Returns:
+ float: The departure timeout of the room.
+ """
+ return float(self._info.departure_timeout)
+
+ @property
+ def empty_timeout(self) -> float:
+ """Amount of time to keep the room open if no participants join.
+
+ Returns:
+ float: The empty timeout of the room.
+ """
+ return float(self._info.empty_timeout)
+
def isconnected(self) -> bool:
+ """Checks if the room is currently connected.
+
+ Returns:
+ bool: True if connected, False otherwise.
+ """
return (
self._ffi_handle is not None
- and self.connection_state != ConnectionState.CONN_DISCONNECTED
+ and self._connection_state != ConnectionState.CONN_DISCONNECTED
)
- async def connect(
- self, url: str, token: str, options: RoomOptions = RoomOptions()
- ) -> None:
+ def on(self, event: EventTypes, callback: Optional[Callable] = None) -> Callable:
+ """Registers an event handler for a specific event type.
+
+ Parameters:
+ event (EventTypes): The name of the event to listen for.
+ callback (Callable): The function to call when the event occurs.
+
+ Returns:
+ Callable: The registered callback function.
+
+ Available events:
+ - **"participant_connected"**: Called when a new participant joins the room.
+ - Arguments: `participant` (RemoteParticipant)
+ - **"participant_disconnected"**: Called when a participant leaves the room.
+ - Arguments: `participant` (RemoteParticipant)
+ - **"participant_active"**: Called when a remote participant becomes active and is ready to receive data messages.
+ - Arguments: `participant` (RemoteParticipant)
+ - **"local_track_published"**: Called when a local track is published.
+ - Arguments: `publication` (LocalTrackPublication), `track` (Track)
+ - **"local_track_unpublished"**: Called when a local track is unpublished.
+ - Arguments: `publication` (LocalTrackPublication)
+ - **"local_track_subscribed"**: Called when a local track is subscribed.
+ - Arguments: `track` (Track)
+ - **"track_published"**: Called when a remote participant publishes a track.
+ - Arguments: `publication` (RemoteTrackPublication), `participant` (RemoteParticipant)
+ - **"track_unpublished"**: Called when a remote participant unpublishes a track.
+ - Arguments: `publication` (RemoteTrackPublication), `participant` (RemoteParticipant)
+ - **"track_subscribed"**: Called when a track is subscribed.
+ - Arguments: `track` (Track), `publication` (RemoteTrackPublication), `participant` (RemoteParticipant)
+ - **"track_unsubscribed"**: Called when a track is unsubscribed.
+ - Arguments: `track` (Track), `publication` (RemoteTrackPublication), `participant` (RemoteParticipant)
+ - **"track_subscription_failed"**: Called when a track subscription fails.
+ - Arguments: `participant` (RemoteParticipant), `track_sid` (str), `error` (str)
+ - **"track_muted"**: Called when a track is muted.
+ - Arguments: `participant` (Participant), `publication` (TrackPublication)
+ - **"track_unmuted"**: Called when a track is unmuted.
+ - Arguments: `participant` (Participant), `publication` (TrackPublication)
+ - **"active_speakers_changed"**: Called when the list of active speakers changes.
+ - Arguments: `speakers` (list[Participant])
+ - **"room_metadata_changed"**: Called when the room's metadata is updated.
+ - Arguments: `old_metadata` (str), `new_metadata` (str)
+ - **"participant_metadata_changed"**: Called when a participant's metadata is updated.
+ - Arguments: `participant` (Participant), `old_metadata` (str), `new_metadata` (str)
+ - **"participant_name_changed"**: Called when a participant's name is changed.
+ - Arguments: `participant` (Participant), `old_name` (str), `new_name` (str)
+ - **"participant_attributes_changed"**: Called when a participant's attributes change.
+ - Arguments: `changed_attributes` (dict), `participant` (Participant)
+ - **"participant_encryption_status_changed"**: Called when a participant's encryption status changes.
+ - Arguments `is_encrypted` (bool), `participant` (Participant)
+ - **"connection_quality_changed"**: Called when a participant's connection quality changes.
+ - Arguments: `participant` (Participant), `quality` (ConnectionQuality)
+ - **"transcription_received"**: Called when a transcription is received.
+ - Arguments: `segments` (list[TranscriptionSegment]), `participant` (Participant), `publication` (TrackPublication)
+ - **"data_received"**: Called when data is received.
+ - Arguments: `data_packet` (DataPacket)
+ - **"sip_dtmf_received"**: Called when a SIP DTMF signal is received.
+ - Arguments: `sip_dtmf` (SipDTMF)
+ - **"e2ee_state_changed"**: Called when a participant's E2EE state changes.
+ - Arguments: `participant` (Participant), `state` (EncryptionState)
+ - **"connection_state_changed"**: Called when the room's connection state changes.
+ - Arguments: `connection_state` (ConnectionState)
+ - **"connected"**: Called when the room is successfully connected.
+ - Arguments: None
+ - **"disconnected"**: Called when the room is disconnected.
+ - Arguments: `reason` (DisconnectReason)
+ - **"reconnecting"**: Called when the room is attempting to reconnect.
+ - Arguments: None
+ - **"reconnected"**: Called when the room has successfully reconnected.
+ - Arguments: None
+ - **"room_updated"**: Called when any information about the room is updated.
+ - Arguments: None
+ - **"moved"**: Called when the participant has been moved to another room.
+ - Arguments: None
+ - **"data_track_published"**: Called when a remote participant publishes a data track.
+ - Arguments: `track` (RemoteDataTrack)
+ - **"data_track_unpublished"**: Called when a remote participant unpublishes a data track.
+ - Arguments: `sid` (str)
+
+ Example:
+ ```python
+ def on_participant_connected(participant):
+ print(f"Participant connected: {participant.identity}")
+
+ room.on("participant_connected", on_participant_connected)
+ ```
+ """
+ return super().on(event, callback)
+
+ async def connect(self, url: str, token: str, options: RoomOptions = RoomOptions()) -> None:
+ """Connects to a LiveKit room using the specified URL and token.
+
+ Parameters:
+ url (str): The WebSocket URL of the LiveKit server to connect to.
+ token (str): The access token for authentication and authorization.
+ options (RoomOptions, optional): Additional options for the room connection.
+
+ Raises:
+ ConnectError: If the connection fails.
+
+ Example:
+ ```python
+ room = Room()
+
+ # Listen for events before connecting to the room
+ @room.on("participant_connected")
+ def on_participant_connected(participant):
+ print(f"Participant connected: {participant.identity}")
+
+ await room.connect("ws://localhost:7880", "your_token")
+ ```
+ """
+ self._server_url = url
+ self._token = token
req = proto_ffi.FfiRequest()
req.connect.url = url
req.connect.token = token
@@ -152,7 +446,19 @@ async def connect(
req.connect.options.auto_subscribe = options.auto_subscribe
req.connect.options.dynacast = options.dynacast
+ if options.connect_timeout is not None:
+ req.connect.options.connect_timeout_ms = int(options.connect_timeout * 1000)
+
+ if options.single_peer_connection is not None:
+ req.connect.options.single_peer_connection = options.single_peer_connection
+
if options.e2ee:
+ warnings.warn(
+ "options.e2ee is deprecated, use options.encryption instead",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+
req.connect.options.e2ee.encryption_type = options.e2ee.encryption_type
req.connect.options.e2ee.key_provider_options.shared_key = (
options.e2ee.key_provider_options.shared_key # type: ignore
@@ -166,6 +472,33 @@ async def connect(
req.connect.options.e2ee.key_provider_options.ratchet_window_size = (
options.e2ee.key_provider_options.ratchet_window_size
)
+ req.connect.options.e2ee.key_provider_options.key_ring_size = (
+ options.e2ee.key_provider_options.key_ring_size
+ )
+ req.connect.options.e2ee.key_provider_options.key_derivation_function = (
+ options.e2ee.key_provider_options.key_derivation_function
+ )
+
+ if options.encryption:
+ req.connect.options.encryption.encryption_type = options.encryption.encryption_type
+ req.connect.options.encryption.key_provider_options.shared_key = (
+ options.encryption.key_provider_options.shared_key # type: ignore
+ )
+ req.connect.options.encryption.key_provider_options.ratchet_salt = (
+ options.encryption.key_provider_options.ratchet_salt
+ )
+ req.connect.options.encryption.key_provider_options.failure_tolerance = (
+ options.encryption.key_provider_options.failure_tolerance
+ )
+ req.connect.options.encryption.key_provider_options.ratchet_window_size = (
+ options.encryption.key_provider_options.ratchet_window_size
+ )
+ req.connect.options.encryption.key_provider_options.key_ring_size = (
+ options.encryption.key_provider_options.key_ring_size
+ )
+ req.connect.options.encryption.key_provider_options.key_derivation_function = (
+ options.encryption.key_provider_options.key_derivation_function
+ )
if options.rtc_config:
req.connect.options.rtc_config.ice_transport_type = (
@@ -174,9 +507,7 @@ async def connect(
req.connect.options.rtc_config.continual_gathering_policy = (
options.rtc_config.continual_gathering_policy
) # type: ignore
- req.connect.options.rtc_config.ice_servers.extend(
- options.rtc_config.ice_servers
- )
+ req.connect.options.rtc_config.ice_servers.extend(options.rtc_config.ice_servers)
# subscribe before connecting so we don't miss any events
self._ffi_queue = FfiClient.instance.queue.subscribe(self._loop)
@@ -184,7 +515,7 @@ async def connect(
queue = FfiClient.instance.queue.subscribe()
try:
resp = FfiClient.instance.request(req)
- cb = await queue.wait_for(
+ cb: proto_ffi.FfiEvent = await queue.wait_for(
lambda e: e.connect.async_id == resp.connect.async_id
)
finally:
@@ -194,52 +525,114 @@ async def connect(
FfiClient.instance.queue.unsubscribe(self._ffi_queue)
raise ConnectError(cb.connect.error)
- self._ffi_handle = FfiHandle(cb.connect.room.handle.id)
+ self._ffi_handle = FfiHandle(cb.connect.result.room.handle.id)
- self._e2ee_manager = E2EEManager(self._ffi_handle.handle, options.e2ee)
+ self._e2ee_manager = E2EEManager(
+ self._ffi_handle.handle, options.encryption or options.e2ee
+ )
- self._info = cb.connect.room.info
- self.connection_state = ConnectionState.CONN_CONNECTED
+ self._info = cb.connect.result.room.info
+ self._connection_state = ConnectionState.CONN_CONNECTED
- self.local_participant = LocalParticipant(
- self._room_queue, cb.connect.local_participant
+ self._local_participant = LocalParticipant(
+ self._room_queue, cb.connect.result.local_participant
)
- for pt in cb.connect.participants:
+ for pt in cb.connect.result.participants:
rp = self._create_remote_participant(pt.participant)
# add the initial remote participant tracks
for owned_publication_info in pt.publications:
publication = RemoteTrackPublication(owned_publication_info)
- rp.tracks[publication.sid] = publication
+ rp._track_publications[publication.sid] = publication
# start listening to room events
self._task = self._loop.create_task(self._listen_task())
- async def disconnect(self) -> None:
+ async def get_rtc_stats(self) -> RtcStats:
if not self.isconnected():
- return
+ raise RuntimeError("the room isn't connected")
req = proto_ffi.FfiRequest()
- req.disconnect.room_handle = self._ffi_handle.handle # type: ignore
+ req.get_session_stats.room_handle = self._ffi_handle.handle # type: ignore
queue = FfiClient.instance.queue.subscribe()
try:
resp = FfiClient.instance.request(req)
- await queue.wait_for(
- lambda e: e.disconnect.async_id == resp.disconnect.async_id
+ cb: proto_ffi.FfiEvent = await queue.wait_for(
+ lambda e: e.get_session_stats.async_id == resp.get_session_stats.async_id
)
finally:
FfiClient.instance.queue.unsubscribe(queue)
+ if cb.get_session_stats.error:
+ raise RuntimeError(cb.get_session_stats.error)
+
+ publisher_stats = list(cb.get_session_stats.result.publisher_stats)
+ subscriber_stats = list(cb.get_session_stats.result.subscriber_stats)
+
+ return RtcStats(publisher_stats=publisher_stats, subscriber_stats=subscriber_stats)
+
+ def register_byte_stream_handler(self, topic: str, handler: ByteStreamHandler):
+ existing_handler = self._byte_stream_handlers.get(topic)
+ if existing_handler is None:
+ self._byte_stream_handlers[topic] = handler
+ else:
+ raise ValueError("byte stream handler for topic '%s' already set" % topic)
+
+ def unregister_byte_stream_handler(self, topic: str):
+ if self._byte_stream_handlers.get(topic):
+ self._byte_stream_handlers.pop(topic)
+
+ def register_text_stream_handler(self, topic: str, handler: TextStreamHandler):
+ existing_handler = self._text_stream_handlers.get(topic)
+ if existing_handler is None:
+ self._text_stream_handlers[topic] = handler
+ else:
+ raise ValueError("text stream handler for topic '%s' already set" % topic)
+
+ def unregister_text_stream_handler(self, topic: str):
+ if self._text_stream_handlers.get(topic):
+ self._text_stream_handlers.pop(topic)
+
+ async def disconnect(
+ self, *, reason: DisconnectReason.ValueType = DisconnectReason.CLIENT_INITIATED
+ ) -> None:
+ """Disconnects from the room."""
+ if not self.isconnected():
+ return
+
+ await self._drain_rpc_invocation_tasks()
+ await self._drain_data_stream_tasks()
+
+ req = proto_ffi.FfiRequest()
+ req.disconnect.room_handle = self._ffi_handle.handle # type: ignore
+ req.disconnect.reason = reason # type: ignore
+ queue = FfiClient.instance.queue.subscribe()
+ try:
+ resp = FfiClient.instance.request(req)
+ await queue.wait_for(lambda e: e.disconnect.async_id == resp.disconnect.async_id)
+ finally:
+ FfiClient.instance.queue.unsubscribe(queue)
+
await self._task
FfiClient.instance.queue.unsubscribe(self._ffi_queue)
+ # we should manually flip the state, since the connection could have been torn down before
+ # the callbacks were processed
+ if self._connection_state != ConnectionState.CONN_DISCONNECTED:
+ self.local_participant._info.disconnect_reason = reason
+ self._connection_state = ConnectionState.CONN_DISCONNECTED
+ self.emit("connection_state_changed", self._connection_state)
+ self.emit("disconnected", reason)
+
async def _listen_task(self) -> None:
# listen to incoming room events
while True:
event = await self._ffi_queue.get()
- if event.room_event.room_handle == self._ffi_handle.handle: # type: ignore
+ if event.WhichOneof("message") == "rpc_method_invocation":
+ self._on_rpc_method_invocation(event.rpc_method_invocation)
+ elif event.room_event.room_handle == self._ffi_handle.handle: # type: ignore
if event.room_event.HasField("eos"):
break
@@ -257,67 +650,93 @@ async def _listen_task(self) -> None:
self._room_queue.put_nowait(event)
await self._room_queue.join()
+ # Clean up any pending RPC invocation tasks
+ await self._drain_rpc_invocation_tasks()
+ await self._drain_data_stream_tasks()
+
+ def _on_rpc_method_invocation(self, rpc_invocation: RpcMethodInvocationEvent):
+ if self._local_participant is None:
+ return
+
+ if rpc_invocation.local_participant_handle == self._local_participant._ffi_handle.handle:
+ task = self._loop.create_task(
+ self._local_participant._handle_rpc_method_invocation(
+ rpc_invocation.invocation_id,
+ rpc_invocation.method,
+ rpc_invocation.request_id,
+ rpc_invocation.caller_identity,
+ rpc_invocation.payload,
+ rpc_invocation.response_timeout_ms / 1000.0,
+ )
+ )
+ self._rpc_invocation_tasks.add(task)
+ task.add_done_callback(self._rpc_invocation_tasks.discard)
+
def _on_room_event(self, event: proto_room.RoomEvent):
which = event.WhichOneof("message")
if which == "participant_connected":
- rparticipant = self._create_remote_participant(
- event.participant_connected.info
- )
+ rparticipant = self._create_remote_participant(event.participant_connected.info)
self.emit("participant_connected", rparticipant)
elif which == "participant_disconnected":
- sid = event.participant_disconnected.participant_sid
- rparticipant = self.participants.pop(sid)
- self.participants_by_identity.pop(rparticipant.identity)
+ identity = event.participant_disconnected.participant_identity
+ rparticipant = self._remote_participants.pop(identity)
+ rparticipant._info.disconnect_reason = event.participant_disconnected.disconnect_reason
self.emit("participant_disconnected", rparticipant)
+ elif which == "participant_active":
+ rp = self._retrieve_remote_participant(event.participant_active.participant_identity)
+ if rp:
+ rp._info.state = proto_participant.PARTICIPANT_STATE_ACTIVE
+ self.emit("participant_active", rp)
elif which == "local_track_published":
sid = event.local_track_published.track_sid
- lpublication = self.local_participant.tracks[sid]
- track = lpublication.track
- self.emit("local_track_published", lpublication, track)
+ lpublication = self.local_participant.track_publications[sid]
+ ltrack = lpublication.track
+ self.emit("local_track_published", lpublication, ltrack)
elif which == "local_track_unpublished":
sid = event.local_track_unpublished.publication_sid
- lpublication = self.local_participant.tracks[sid]
+ lpublication = self.local_participant.track_publications[sid]
self.emit("local_track_unpublished", lpublication)
+ elif which == "local_track_subscribed":
+ sid = event.local_track_subscribed.track_sid
+ lpublication = self.local_participant.track_publications[sid]
+ lpublication._first_subscription.set_result(None)
+ self.emit("local_track_subscribed", lpublication.track)
elif which == "track_published":
- rparticipant = self.participants[event.track_published.participant_sid]
+ rparticipant = self._remote_participants[event.track_published.participant_identity]
rpublication = RemoteTrackPublication(event.track_published.publication)
- rparticipant.tracks[rpublication.sid] = rpublication
+ rparticipant._track_publications[rpublication.sid] = rpublication
self.emit("track_published", rpublication, rparticipant)
elif which == "track_unpublished":
- rparticipant = self.participants[event.track_unpublished.participant_sid]
- rpublication = rparticipant.tracks.pop(
+ rparticipant = self._remote_participants[event.track_unpublished.participant_identity]
+ rpublication = rparticipant._track_publications.pop(
event.track_unpublished.publication_sid
)
self.emit("track_unpublished", rpublication, rparticipant)
elif which == "track_subscribed":
owned_track_info = event.track_subscribed.track
track_info = owned_track_info.info
- rparticipant = self.participants[event.track_subscribed.participant_sid]
- rpublication = rparticipant.tracks[track_info.sid]
- rpublication.subscribed = True
+ rparticipant = self._remote_participants[event.track_subscribed.participant_identity]
+ rpublication = rparticipant.track_publications[track_info.sid]
+ rpublication._subscribed = True
if track_info.kind == TrackKind.KIND_VIDEO:
remote_video_track = RemoteVideoTrack(owned_track_info)
- rpublication.track = remote_video_track
- self.emit(
- "track_subscribed", remote_video_track, rpublication, rparticipant
- )
+ rpublication._track = remote_video_track
+ self.emit("track_subscribed", remote_video_track, rpublication, rparticipant)
elif track_info.kind == TrackKind.KIND_AUDIO:
remote_audio_track = RemoteAudioTrack(owned_track_info)
- rpublication.track = remote_audio_track
- self.emit(
- "track_subscribed", remote_audio_track, rpublication, rparticipant
- )
+ rpublication._track = remote_audio_track
+ self.emit("track_subscribed", remote_audio_track, rpublication, rparticipant)
elif which == "track_unsubscribed":
- sid = event.track_unsubscribed.participant_sid
- rparticipant = self.participants[sid]
- rpublication = rparticipant.tracks[event.track_unsubscribed.track_sid]
- track = rpublication.track
- rpublication.track = None
- rpublication.subscribed = False
- self.emit("track_unsubscribed", track, rpublication, rparticipant)
+ identity = event.track_unsubscribed.participant_identity
+ rparticipant = self._remote_participants[identity]
+ rpublication = rparticipant.track_publications[event.track_unsubscribed.track_sid]
+ rtrack = rpublication.track
+ rpublication._track = None
+ rpublication._subscribed = False
+ self.emit("track_unsubscribed", rtrack, rpublication, rparticipant)
elif which == "track_subscription_failed":
- sid = event.track_subscription_failed.participant_sid
- rparticipant = self.participants[sid]
+ identity = event.track_subscription_failed.participant_identity
+ rparticipant = self._remote_participants[identity]
error = event.track_subscription_failed.error
self.emit(
"track_subscription_failed",
@@ -326,20 +745,22 @@ def _on_room_event(self, event: proto_room.RoomEvent):
error,
)
elif which == "track_muted":
- sid = event.track_muted.participant_sid
+ identity = event.track_muted.participant_identity
# TODO: pass participant identity
- participant = self._retrieve_participant(sid, "")
- publication = participant.tracks[event.track_muted.track_sid]
+ participant = self._retrieve_participant(identity)
+ assert isinstance(participant, Participant)
+ publication = participant.track_publications[event.track_muted.track_sid]
publication._info.muted = True
if publication.track:
publication.track._info.muted = True
self.emit("track_muted", participant, publication)
elif which == "track_unmuted":
- sid = event.track_unmuted.participant_sid
+ identity = event.track_unmuted.participant_identity
# TODO: pass participant identity
- participant = self._retrieve_participant(sid, "")
- publication = participant.tracks[event.track_unmuted.track_sid]
+ participant = self._retrieve_participant(identity)
+ assert isinstance(participant, Participant)
+ publication = participant.track_publications[event.track_unmuted.track_sid]
publication._info.muted = False
if publication.track:
publication.track._info.muted = False
@@ -348,18 +769,26 @@ def _on_room_event(self, event: proto_room.RoomEvent):
elif which == "active_speakers_changed":
speakers: list[Participant] = []
# TODO: pass participant identity
- for sid in event.active_speakers_changed.participant_sids:
- speakers.append(self._retrieve_participant(sid, ""))
+ for identity in event.active_speakers_changed.participant_identities:
+ participant = self._retrieve_participant(identity)
+ assert isinstance(participant, Participant)
+ speakers.append(participant)
self.emit("active_speakers_changed", speakers)
elif which == "room_metadata_changed":
old_metadata = self.metadata
self._info.metadata = event.room_metadata_changed.metadata
self.emit("room_metadata_changed", old_metadata, self.metadata)
+ elif which == "room_sid_changed":
+ if not self._info.sid:
+ self._first_sid_future.set_result(event.room_sid_changed.sid)
+ self._info.sid = event.room_sid_changed.sid
+ # This is an internal event, not exposed to users
elif which == "participant_metadata_changed":
- sid = event.participant_metadata_changed.participant_sid
+ identity = event.participant_metadata_changed.participant_identity
# TODO: pass participant identity
- participant = self._retrieve_participant(sid, "")
+ participant = self._retrieve_participant(identity)
+ assert isinstance(participant, Participant)
old_metadata = participant.metadata
participant._info.metadata = event.participant_metadata_changed.metadata
self.emit(
@@ -369,23 +798,73 @@ def _on_room_event(self, event: proto_room.RoomEvent):
participant.metadata,
)
elif which == "participant_name_changed":
- sid = event.participant_name_changed.participant_sid
- # TODO: pass participant identity
- participant = self._retrieve_participant(sid, "")
+ identity = event.participant_name_changed.participant_identity
+ participant = self._retrieve_participant(identity)
+ assert isinstance(participant, Participant)
old_name = participant.name
participant._info.name = event.participant_name_changed.name
+ self.emit("participant_name_changed", participant, old_name, participant.name)
+ elif which == "participant_attributes_changed":
+ identity = event.participant_attributes_changed.participant_identity
+ attributes = event.participant_attributes_changed.attributes
+ changed_attributes = dict(
+ (entry.key, entry.value)
+ for entry in event.participant_attributes_changed.changed_attributes
+ )
+ participant = self._retrieve_participant(identity)
+ assert isinstance(participant, Participant)
+ participant._info.attributes.clear()
+ participant._info.attributes.update((entry.key, entry.value) for entry in attributes)
self.emit(
- "participant_name_changed", participant, old_name, participant.name
+ "participant_attributes_changed",
+ changed_attributes,
+ participant,
+ )
+ elif which == "participant_encryption_status_changed":
+ identity = event.participant_encryption_status_changed.participant_identity
+ participant = self._retrieve_participant(identity)
+ self.emit(
+ "participant_encryption_status_changed",
+ participant,
+ event.participant_encryption_status_changed.is_encrypted,
+ )
+ elif which == "participant_permissions_changed":
+ identity = event.participant_permission_changed.participant_identity
+ participant = self._retrieve_participant(identity)
+ assert isinstance(participant, Participant)
+ participant._info.permission.CopyFrom(event.participant_permission_changed.permission)
+ self.emit(
+ "participant_permissions_changed",
+ participant,
+ participant.permissions,
)
elif which == "connection_quality_changed":
- sid = event.connection_quality_changed.participant_sid
+ identity = event.connection_quality_changed.participant_identity
# TODO: pass participant identity
- participant = self._retrieve_participant(sid, "")
+ participant = self._retrieve_participant(identity)
self.emit(
"connection_quality_changed",
participant,
event.connection_quality_changed.quality,
)
+ elif which == "transcription_received":
+ transcription = event.transcription_received
+ segments = [
+ TranscriptionSegment(
+ id=s.id,
+ text=s.text,
+ final=s.final,
+ start_time=s.start_time,
+ end_time=s.end_time,
+ language=s.language,
+ )
+ for s in transcription.segments
+ ]
+ part = self._retrieve_participant(transcription.participant_identity)
+ pub: TrackPublication | None = None
+ if part:
+ pub = part.track_publications.get(transcription.track_sid)
+ self.emit("transcription_received", segments, part, pub)
elif which == "data_packet_received":
packet = event.data_packet_received
which_val = packet.WhichOneof("value")
@@ -398,9 +877,10 @@ def _on_room_event(self, event: proto_room.RoomEvent):
).contents
data = bytes(native_data)
- FfiHandle(owned_buffer_info.handle.id)
- rparticipant = self._retrieve_remote_participant(
- packet.participant_sid, packet.participant_identity
+ FfiHandle(owned_buffer_info.handle.id).dispose()
+ rparticipant = cast(
+ RemoteParticipant,
+ self._retrieve_remote_participant(packet.participant_identity),
)
self.emit(
"data_received",
@@ -412,8 +892,9 @@ def _on_room_event(self, event: proto_room.RoomEvent):
),
)
elif which_val == "sip_dtmf":
- rparticipant = self._retrieve_remote_participant(
- packet.participant_sid, packet.participant_identity
+ rparticipant = cast(
+ RemoteParticipant,
+ self._retrieve_remote_participant(packet.participant_identity),
)
self.emit(
"sip_dtmf_received",
@@ -423,57 +904,151 @@ def _on_room_event(self, event: proto_room.RoomEvent):
participant=rparticipant,
),
)
-
elif which == "e2ee_state_changed":
- sid = event.e2ee_state_changed.participant_sid
+ identity = event.e2ee_state_changed.participant_identity
e2ee_state = event.e2ee_state_changed.state
# TODO: pass participant identity
- self.emit(
- "e2ee_state_changed", self._retrieve_participant(sid, ""), e2ee_state
- )
+ self.emit("e2ee_state_changed", self._retrieve_participant(identity), e2ee_state)
elif which == "connection_state_changed":
connection_state = event.connection_state_changed.state
- self.connection_state = connection_state
+ self._connection_state = connection_state
self.emit("connection_state_changed", connection_state)
- elif which == "connected":
- self.emit("connected")
elif which == "disconnected":
- self.emit("disconnected")
+ self.emit("disconnected", event.disconnected.reason)
elif which == "reconnecting":
self.emit("reconnecting")
elif which == "reconnected":
self.emit("reconnected")
+ elif which == "stream_header_received":
+ self._handle_stream_header(
+ event.stream_header_received.header,
+ event.stream_header_received.participant_identity,
+ )
+ elif which == "stream_chunk_received":
+ task = asyncio.create_task(self._handle_stream_chunk(event.stream_chunk_received.chunk))
+ self._data_stream_tasks.add(task)
+ task.add_done_callback(self._data_stream_tasks.discard)
- def _retrieve_remote_participant(
- self, sid: str, identity: str
- ) -> RemoteParticipant:
- """Retrieve a remote participant by sid or identity"""
- participant = None
- if identity:
- participant = self.participants_by_identity[identity]
- if not participant:
- participant = self.participants[sid]
- return participant
+ elif which == "stream_trailer_received":
+ task = asyncio.create_task(
+ self._handle_stream_trailer(event.stream_trailer_received.trailer)
+ )
+ self._data_stream_tasks.add(task)
+ task.add_done_callback(self._data_stream_tasks.discard)
+
+ elif which == "room_updated":
+ self._info = event.room_updated
+ self.emit("room_updated")
+
+ elif which == "moved":
+ self._info = event.moved
+ self.emit("moved")
+
+ elif which == "participants_updated":
+ for info in event.participants_updated.participants:
+ participant = self._retrieve_participant(info.identity)
+ if participant:
+ participant._info = info
- def _retrieve_participant(self, sid: str, identity: str) -> Participant:
- """Retrieve a participant by sid or identity,
- returns the LocalParticipant if sid or identity matches"""
+ elif which == "token_refreshed":
+ self._token = event.token_refreshed.token
+ self.emit("token_refreshed")
+
+ elif which == "data_track_published":
+ remote_data_track = RemoteDataTrack(event.data_track_published.track)
+ self.emit("data_track_published", remote_data_track)
+
+ elif which == "data_track_unpublished":
+ self.emit("data_track_unpublished", event.data_track_unpublished.sid)
+
+ def _handle_stream_header(
+ self, header: proto_room.DataStream.Header, participant_identity: str
+ ):
+ stream_type = header.WhichOneof("content_header")
+ if stream_type == "text_header":
+ text_stream_handler = self._text_stream_handlers.get(header.topic)
+ if text_stream_handler is None:
+ logging.info(
+ "ignoring text stream with topic '%s', no callback attached",
+ header.topic,
+ )
+ return
+
+ text_reader = TextStreamReader(header)
+ self._text_stream_readers[header.stream_id] = text_reader
+ text_stream_handler(text_reader, participant_identity)
+ elif stream_type == "byte_header":
+ byte_stream_handler = self._byte_stream_handlers.get(header.topic)
+ if byte_stream_handler is None:
+ logging.info(
+ "ignoring byte stream with topic '%s', no callback attached",
+ header.topic,
+ )
+ return
+
+ byte_reader = ByteStreamReader(header)
+ self._byte_stream_readers[header.stream_id] = byte_reader
+ byte_stream_handler(byte_reader, participant_identity)
+ else:
+ logging.warning("received unknown header type, %s", stream_type)
+ pass
+
+ async def _handle_stream_chunk(self, chunk: proto_room.DataStream.Chunk):
+ text_reader = self._text_stream_readers.get(chunk.stream_id)
+ file_reader = self._byte_stream_readers.get(chunk.stream_id)
+
+ if text_reader:
+ await text_reader._on_chunk_update(chunk)
+ elif file_reader:
+ await file_reader._on_chunk_update(chunk)
+
+ async def _handle_stream_trailer(self, trailer: proto_room.DataStream.Trailer):
+ text_reader = self._text_stream_readers.get(trailer.stream_id)
+ file_reader = self._byte_stream_readers.get(trailer.stream_id)
+
+ if text_reader:
+ await text_reader._on_stream_close(trailer)
+ self._text_stream_readers.pop(trailer.stream_id)
+ elif file_reader:
+ await file_reader._on_stream_close(trailer)
+ self._byte_stream_readers.pop(trailer.stream_id)
+
+ async def _drain_rpc_invocation_tasks(self) -> None:
+ if self._rpc_invocation_tasks:
+ for task in self._rpc_invocation_tasks:
+ task.cancel()
+ await asyncio.gather(*self._rpc_invocation_tasks, return_exceptions=True)
+
+ async def _drain_data_stream_tasks(self) -> None:
+ if self._data_stream_tasks:
+ for task in self._data_stream_tasks:
+ task.cancel()
+ await asyncio.gather(*self._data_stream_tasks, return_exceptions=True)
+
+ def _retrieve_remote_participant(self, identity: str) -> Optional[RemoteParticipant]:
+ """Retrieve a remote participant by identity"""
+ return self._remote_participants.get(identity, None)
+
+ def _retrieve_participant(self, identity: str) -> Optional[Participant]:
+ """Retrieve a local or remote participant by identity"""
if identity and identity == self.local_participant.identity:
return self.local_participant
- if sid and sid == self.local_participant.sid:
- return self.local_participant
- else:
- return self._retrieve_remote_participant(sid, identity)
+
+ return self._retrieve_remote_participant(identity)
def _create_remote_participant(
self, owned_info: proto_participant.OwnedParticipant
) -> RemoteParticipant:
- if owned_info.info.sid in self.participants:
- raise Exception("participant already exists")
- if owned_info.info.identity in self.participants_by_identity:
+ if owned_info.info.identity in self._remote_participants:
raise Exception("participant already exists")
participant = RemoteParticipant(owned_info)
- self.participants[participant.sid] = participant
- self.participants_by_identity[participant.identity] = participant
+ self._remote_participants[participant.identity] = participant
return participant
+
+ def __repr__(self) -> str:
+ sid = "unknown"
+ if self._first_sid_future.done():
+ sid = self._first_sid_future.result()
+
+ return f"rtc.Room(sid={sid}, name={self.name}, metadata={self.metadata}, connection_state={ConnectionState.Name(self._connection_state)})"
diff --git a/livekit-rtc/livekit/rtc/rpc.py b/livekit-rtc/livekit/rtc/rpc.py
new file mode 100644
index 00000000..02a5b7f4
--- /dev/null
+++ b/livekit-rtc/livekit/rtc/rpc.py
@@ -0,0 +1,122 @@
+# Copyright 2023 LiveKit, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from typing import Optional, Dict, Union, ClassVar
+from enum import IntEnum
+from ._proto import rpc_pb2 as proto_rpc
+from dataclasses import dataclass
+
+
+@dataclass
+class RpcInvocationData:
+ """Data passed to method handler for incoming RPC invocations
+
+ Attributes:
+ request_id (str): The unique request ID. Will match at both sides of the call, useful for debugging or logging.
+ caller_identity (str): The unique participant identity of the caller.
+ payload (str): The payload of the request. User-definable format, typically JSON.
+ response_timeout (float): The maximum time the caller will wait for a response.
+ """
+
+ request_id: str
+ caller_identity: str
+ payload: str
+ response_timeout: float
+
+
+class RpcError(Exception):
+ """
+ Specialized error handling for RPC methods.
+
+ Instances of this type, when thrown in a method handler, will have their `message`
+ serialized and sent across the wire. The caller will receive an equivalent error on the other side.
+
+ Built-in errors are included (codes 1001-1999) but developers may use the code, message, and data fields to create their own errors.
+ """
+
+ class ErrorCode(IntEnum):
+ APPLICATION_ERROR = 1500
+ CONNECTION_TIMEOUT = 1501
+ RESPONSE_TIMEOUT = 1502
+ RECIPIENT_DISCONNECTED = 1503
+ RESPONSE_PAYLOAD_TOO_LARGE = 1504
+ SEND_FAILED = 1505
+
+ UNSUPPORTED_METHOD = 1400
+ RECIPIENT_NOT_FOUND = 1401
+ REQUEST_PAYLOAD_TOO_LARGE = 1402
+ UNSUPPORTED_SERVER = 1403
+ UNSUPPORTED_VERSION = 1404
+
+ ErrorMessage: ClassVar[Dict[ErrorCode, str]] = {
+ ErrorCode.APPLICATION_ERROR: "Application error in method handler",
+ ErrorCode.CONNECTION_TIMEOUT: "Connection timeout",
+ ErrorCode.RESPONSE_TIMEOUT: "Response timeout",
+ ErrorCode.RECIPIENT_DISCONNECTED: "Recipient disconnected",
+ ErrorCode.RESPONSE_PAYLOAD_TOO_LARGE: "Response payload too large",
+ ErrorCode.SEND_FAILED: "Failed to send",
+ ErrorCode.UNSUPPORTED_METHOD: "Method not supported at destination",
+ ErrorCode.RECIPIENT_NOT_FOUND: "Recipient not found",
+ ErrorCode.REQUEST_PAYLOAD_TOO_LARGE: "Request payload too large",
+ ErrorCode.UNSUPPORTED_SERVER: "RPC not supported by server",
+ ErrorCode.UNSUPPORTED_VERSION: "Unsupported RPC version",
+ }
+
+ def __init__(
+ self,
+ code: Union[int, "RpcError.ErrorCode"],
+ message: str,
+ data: Optional[str] = None,
+ ):
+ """
+ Creates an error object with the given code and message, plus an optional data payload.
+
+ If thrown in an RPC method handler, the error will be sent back to the caller.
+
+ Args:
+ code (int): Your error code (Error codes 1001-1999 are reserved for built-in errors)
+ message (str): A readable error message.
+ data (Optional[str]): Optional additional data associated with the error (JSON recommended)
+ """
+ super().__init__(message)
+ self._code = code
+ self._message = message
+ self._data = data
+
+ @property
+ def code(self) -> int:
+ """Error code value. Codes 1001-1999 are reserved for built-in errors (see RpcError.ErrorCode for their meanings)."""
+ return self._code
+
+ @property
+ def message(self) -> str:
+ """A readable error message."""
+ return self._message
+
+ @property
+ def data(self) -> Optional[str]:
+ """Optional additional data associated with the error (JSON recommended)."""
+ return self._data
+
+ @classmethod
+ def _from_proto(cls, proto: proto_rpc.RpcError) -> "RpcError":
+ return cls(proto.code, proto.message, proto.data)
+
+ def _to_proto(self) -> proto_rpc.RpcError:
+ return proto_rpc.RpcError(code=self.code, message=self.message, data=self.data)
+
+ @classmethod
+ def _built_in(cls, code: "RpcError.ErrorCode", data: Optional[str] = None) -> "RpcError":
+ message = cls.ErrorMessage[code]
+ return cls(code, message, data)
diff --git a/livekit-rtc/livekit/rtc/synchronizer.py b/livekit-rtc/livekit/rtc/synchronizer.py
new file mode 100644
index 00000000..8c5f6347
--- /dev/null
+++ b/livekit-rtc/livekit/rtc/synchronizer.py
@@ -0,0 +1,202 @@
+import asyncio
+import logging
+import time
+from collections import deque
+from typing import Optional, Union
+
+from .video_frame import VideoFrame
+from .audio_frame import AudioFrame
+from .audio_source import AudioSource
+from .video_source import VideoSource
+
+
+logger = logging.getLogger(__name__)
+
+
+class AVSynchronizer:
+ """Synchronize audio and video capture.
+
+ Usage:
+ av_sync = AVSynchronizer(
+ audio_source=audio_source,
+ video_source=video_source,
+ video_fps=video_fps,
+ )
+
+ async for video_frame, audio_frame in video_generator:
+ await av_sync.push(video_frame)
+ await av_sync.push(audio_frame)
+ """
+
+ def __init__(
+ self,
+ *,
+ audio_source: AudioSource,
+ video_source: VideoSource,
+ video_fps: float,
+ video_queue_size_ms: float = 100,
+ _max_delay_tolerance_ms: float = 300,
+ ):
+ self._audio_source = audio_source
+ self._video_source = video_source
+ self._video_fps = video_fps
+ self._video_queue_size_ms = video_queue_size_ms
+ self._max_delay_tolerance_ms = _max_delay_tolerance_ms
+
+ self._stopped = False
+ # the time of the last video/audio frame captured
+ self._last_video_time: float = 0
+ self._last_audio_time: float = 0
+
+ self._video_queue_max_size = int(self._video_fps * self._video_queue_size_ms / 1000)
+ if self._video_queue_size_ms > 0:
+ # ensure queue is bounded if queue size is specified
+ self._video_queue_max_size = max(1, self._video_queue_max_size)
+
+ self._video_queue = asyncio.Queue[tuple[VideoFrame, Optional[float]]](
+ maxsize=self._video_queue_max_size
+ )
+ self._fps_controller = _FPSController(
+ expected_fps=self._video_fps,
+ max_delay_tolerance_ms=self._max_delay_tolerance_ms,
+ )
+ self._capture_video_task = asyncio.create_task(self._capture_video())
+
+ async def push(
+ self, frame: Union[VideoFrame, AudioFrame], timestamp: Optional[float] = None
+ ) -> None:
+ """Push a frame to the synchronizer
+
+ Args:
+ frame: The video or audio frame to push.
+ timestamp: (optional) The timestamp of the frame, for logging purposes for now.
+ For AudioFrame, it should be the end time of the frame.
+ """
+ if isinstance(frame, AudioFrame):
+ await self._audio_source.capture_frame(frame)
+ if timestamp is not None:
+ self._last_audio_time = timestamp
+ return
+
+ await self._video_queue.put((frame, timestamp))
+
+ async def clear_queue(self) -> None:
+ self._audio_source.clear_queue()
+ while not self._video_queue.empty():
+ await self._video_queue.get()
+ self._video_queue.task_done()
+
+ async def wait_for_playout(self) -> None:
+ """Wait until all video and audio frames are played out."""
+ await asyncio.gather(
+ self._audio_source.wait_for_playout(),
+ self._video_queue.join(),
+ )
+
+ def reset(self) -> None:
+ self._fps_controller.reset()
+
+ async def _capture_video(self) -> None:
+ while not self._stopped:
+ frame, timestamp = await self._video_queue.get()
+ async with self._fps_controller:
+ self._video_source.capture_frame(frame)
+ if timestamp is not None:
+ self._last_video_time = timestamp
+ self._video_queue.task_done()
+
+ async def aclose(self) -> None:
+ self._stopped = True
+ if self._capture_video_task:
+ self._capture_video_task.cancel()
+
+ @property
+ def actual_fps(self) -> float:
+ return self._fps_controller.actual_fps
+
+ @property
+ def last_video_time(self) -> float:
+ """The time of the last video frame captured"""
+ return self._last_video_time
+
+ @property
+ def last_audio_time(self) -> float:
+ """The time of the last audio frame played out"""
+ return self._last_audio_time - self._audio_source.queued_duration
+
+
+class _FPSController:
+ def __init__(self, *, expected_fps: float, max_delay_tolerance_ms: float = 300) -> None:
+ """Controls frame rate by adjusting sleep time based on actual FPS.
+
+ Usage:
+ async with _FPSController(expected_fps=30):
+ # process frame
+ pass
+
+ Args:
+ expected_fps: Target frames per second
+ max_delay_tolerance_ms: Maximum delay tolerance in milliseconds
+ """
+ self._expected_fps = expected_fps
+ self._frame_interval = 1.0 / expected_fps
+ self._max_delay_tolerance_secs = max_delay_tolerance_ms / 1000
+
+ self._next_frame_time: Optional[float] = None
+ self._fps_calc_winsize = max(2, int(1.0 * expected_fps))
+ self._send_timestamps: deque[float] = deque(maxlen=self._fps_calc_winsize)
+
+ async def __aenter__(self) -> None:
+ await self.wait_next_process()
+
+ async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
+ self.after_process()
+
+ def reset(self) -> None:
+ self._next_frame_time = None
+ self._send_timestamps.clear()
+
+ async def wait_next_process(self) -> None:
+ """Wait until it's time for the next frame.
+
+ Adjusts sleep time based on actual FPS to maintain target rate.
+ """
+ current_time = time.perf_counter()
+
+ # initialize the next frame time
+ if self._next_frame_time is None:
+ self._next_frame_time = current_time
+
+ # calculate sleep time
+ sleep_time = self._next_frame_time - current_time
+ if sleep_time > 0:
+ await asyncio.sleep(sleep_time)
+ else:
+ # check if significantly behind schedule
+ if -sleep_time > self._max_delay_tolerance_secs:
+ logger.warning(f"Frame capture was behind schedule for {-sleep_time * 1000:.2f} ms")
+ self._next_frame_time = time.perf_counter()
+
+ def after_process(self) -> None:
+ """Update timing information after processing a frame."""
+ assert self._next_frame_time is not None, "wait_next_process must be called first"
+
+ # update timing information
+ self._send_timestamps.append(time.perf_counter())
+
+ # calculate next frame time
+ self._next_frame_time += self._frame_interval
+
+ @property
+ def expected_fps(self) -> float:
+ return self._expected_fps
+
+ @property
+ def actual_fps(self) -> float:
+ """Get current average FPS."""
+ if len(self._send_timestamps) < 2:
+ return 0
+
+ return (len(self._send_timestamps) - 1) / (
+ self._send_timestamps[-1] - self._send_timestamps[0]
+ )
diff --git a/livekit-rtc/livekit/rtc/track.py b/livekit-rtc/livekit/rtc/track.py
index abfe1adc..8a6fe692 100644
--- a/livekit-rtc/livekit/rtc/track.py
+++ b/livekit-rtc/livekit/rtc/track.py
@@ -55,7 +55,7 @@ async def get_stats(self) -> List[proto_stats.RtcStats]:
queue = FfiClient.instance.queue.subscribe()
try:
resp = FfiClient.instance.request(req)
- cb = await queue.wait_for(
+ cb: proto_ffi.FfiEvent = await queue.wait_for(
lambda e: e.get_stats.async_id == resp.get_stats.async_id
)
finally:
@@ -80,6 +80,23 @@ def create_audio_track(name: str, source: "AudioSource") -> "LocalAudioTrack":
resp = FfiClient.instance.request(req)
return LocalAudioTrack(resp.create_audio_track.track)
+ def mute(self):
+ req = proto_ffi.FfiRequest()
+ req.local_track_mute.track_handle = self._ffi_handle.handle
+ req.local_track_mute.mute = True
+ FfiClient.instance.request(req)
+ self._info.muted = True
+
+ def unmute(self):
+ req = proto_ffi.FfiRequest()
+ req.local_track_mute.track_handle = self._ffi_handle.handle
+ req.local_track_mute.mute = False
+ FfiClient.instance.request(req)
+ self._info.muted = False
+
+ def __repr__(self) -> str:
+ return f"rtc.LocalAudioTrack(sid={self.sid}, name={self.name})"
+
class LocalVideoTrack(Track):
def __init__(self, info: proto_track.OwnedTrack):
@@ -94,16 +111,39 @@ def create_video_track(name: str, source: "VideoSource") -> "LocalVideoTrack":
resp = FfiClient.instance.request(req)
return LocalVideoTrack(resp.create_video_track.track)
+ def mute(self):
+ req = proto_ffi.FfiRequest()
+ req.local_track_mute.track_handle = self._ffi_handle.handle
+ req.local_track_mute.mute = True
+ FfiClient.instance.request(req)
+ self._info.muted = True
+
+ def unmute(self):
+ req = proto_ffi.FfiRequest()
+ req.local_track_mute.track_handle = self._ffi_handle.handle
+ req.local_track_mute.mute = False
+ FfiClient.instance.request(req)
+ self._info.muted = False
+
+ def __repr__(self) -> str:
+ return f"rtc.LocalVideoTrack(sid={self.sid}, name={self.name})"
+
class RemoteAudioTrack(Track):
def __init__(self, info: proto_track.OwnedTrack):
super().__init__(info)
+ def __repr__(self) -> str:
+ return f"rtc.RemoteAudioTrack(sid={self.sid}, name={self.name})"
+
class RemoteVideoTrack(Track):
def __init__(self, info: proto_track.OwnedTrack):
super().__init__(info)
+ def __repr__(self) -> str:
+ return f"rtc.RemoteVideoTrack(sid={self.sid}, name={self.name})"
+
LocalTrack = Union[LocalVideoTrack, LocalAudioTrack]
RemoteTrack = Union[RemoteVideoTrack, RemoteAudioTrack]
diff --git a/livekit-rtc/livekit/rtc/track_publication.py b/livekit-rtc/livekit/rtc/track_publication.py
index 104acda8..5095841c 100644
--- a/livekit-rtc/livekit/rtc/track_publication.py
+++ b/livekit-rtc/livekit/rtc/track_publication.py
@@ -12,21 +12,26 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from typing import Optional
+from typing import List, Optional, cast
+import asyncio
from ._ffi_client import FfiHandle, FfiClient
from ._proto import e2ee_pb2 as proto_e2ee
from ._proto import ffi_pb2 as proto_ffi
from ._proto import track_pb2 as proto_track
-from .track import Track
+from .track import Track, LocalTrack, RemoteTrack
class TrackPublication:
def __init__(self, owned_info: proto_track.OwnedTrackPublication):
self._info = owned_info.info
- self.track: Optional[Track] = None
+ self._track: Optional[Track] = None
self._ffi_handle = FfiHandle(owned_info.handle.id)
+ @property
+ def track(self) -> Optional[Track]:
+ return self._track
+
@property
def sid(self) -> str:
return self._info.sid
@@ -67,19 +72,45 @@ def muted(self) -> bool:
def encryption_type(self) -> proto_e2ee.EncryptionType.ValueType:
return self._info.encryption_type
+ @property
+ def audio_features(self) -> List[proto_track.AudioTrackFeature.ValueType]:
+ return list(self._info.audio_features)
+
class LocalTrackPublication(TrackPublication):
def __init__(self, owned_info: proto_track.OwnedTrackPublication):
super().__init__(owned_info)
+ self._first_subscription: asyncio.Future[None] = asyncio.Future()
+
+ @property
+ def track(self) -> Optional[LocalTrack]:
+ return cast(Optional[LocalTrack], self._track)
+
+ async def wait_for_subscription(self) -> None:
+ await asyncio.shield(self._first_subscription)
+
+ def __repr__(self) -> str:
+ return f"rtc.LocalTrackPublication(sid={self.sid}, name={self.name}, kind={self.kind}, source={self.source})"
class RemoteTrackPublication(TrackPublication):
def __init__(self, owned_info: proto_track.OwnedTrackPublication):
super().__init__(owned_info)
- self.subscribed = False
+ self._subscribed = False
+
+ @property
+ def track(self) -> Optional[RemoteTrack]:
+ return cast(Optional[RemoteTrack], self._track)
+
+ @property
+ def subscribed(self) -> bool:
+ return self._subscribed
def set_subscribed(self, subscribed: bool):
req = proto_ffi.FfiRequest()
req.set_subscribed.subscribe = subscribed
req.set_subscribed.publication_handle = self._ffi_handle.handle
FfiClient.instance.request(req)
+
+ def __repr__(self) -> str:
+ return f"rtc.RemoteTrackPublication(sid={self.sid}, name={self.name}, kind={self.kind}, source={self.source})"
diff --git a/livekit-rtc/livekit/rtc/transcription.py b/livekit-rtc/livekit/rtc/transcription.py
index 3694e0d0..7403f6bd 100644
--- a/livekit-rtc/livekit/rtc/transcription.py
+++ b/livekit-rtc/livekit/rtc/transcription.py
@@ -5,9 +5,8 @@
@dataclass
class Transcription:
participant_identity: str
- track_id: str
+ track_sid: str
segments: List["TranscriptionSegment"]
- language: str
@dataclass
@@ -16,4 +15,5 @@ class TranscriptionSegment:
text: str
start_time: int
end_time: int
+ language: str
final: bool
diff --git a/livekit-rtc/livekit/rtc/utils.py b/livekit-rtc/livekit/rtc/utils.py
new file mode 100644
index 00000000..55f7d991
--- /dev/null
+++ b/livekit-rtc/livekit/rtc/utils.py
@@ -0,0 +1,138 @@
+from __future__ import annotations
+
+from typing import AsyncIterator
+
+from .audio_frame import AudioFrame
+
+
+__all__ = ["combine_audio_frames", "sine_wave_generator"]
+
+
+def combine_audio_frames(buffer: AudioFrame | list[AudioFrame]) -> AudioFrame:
+ """
+ Combines one or more `rtc.AudioFrame` objects into a single `rtc.AudioFrame`.
+
+ This function concatenates the audio data from multiple frames, ensuring that
+ all frames have the same sample rate and number of channels. It efficiently
+ merges the data by preallocating the necessary memory and copying the frame
+ data without unnecessary reallocations.
+
+ Args:
+ buffer: A single `rtc.AudioFrame` or a list of `rtc.AudioFrame`
+ objects to be combined.
+
+ Returns:
+ rtc.AudioFrame: A new `rtc.AudioFrame` containing the combined audio data.
+
+ Raises:
+ ValueError: If the buffer is empty.
+ ValueError: If frames have differing sample rates.
+ ValueError: If frames have differing numbers of channels.
+
+ Example:
+ >>> frame1 = rtc.AudioFrame(
+ ... data=b"\x01\x02", sample_rate=48000, num_channels=2, samples_per_channel=1
+ ... )
+ >>> frame2 = rtc.AudioFrame(
+ ... data=b"\x03\x04", sample_rate=48000, num_channels=2, samples_per_channel=1
+ ... )
+ >>> combined_frame = combine_audio_frames([frame1, frame2])
+ >>> combined_frame.data
+ b'\x01\x02\x03\x04'
+ >>> combined_frame.sample_rate
+ 48000
+ >>> combined_frame.num_channels
+ 2
+ >>> combined_frame.samples_per_channel
+ 2
+ """
+ if not isinstance(buffer, list):
+ return buffer
+
+ if not buffer:
+ raise ValueError("buffer is empty")
+
+ sample_rate = buffer[0].sample_rate
+ num_channels = buffer[0].num_channels
+
+ total_data_length = 0
+ total_samples_per_channel = 0
+
+ for frame in buffer:
+ if frame.sample_rate != sample_rate:
+ raise ValueError(
+ f"Sample rate mismatch: expected {sample_rate}, got {frame.sample_rate}"
+ )
+
+ if frame.num_channels != num_channels:
+ raise ValueError(
+ f"Channel count mismatch: expected {num_channels}, got {frame.num_channels}"
+ )
+
+ total_data_length += len(frame.data)
+ total_samples_per_channel += frame.samples_per_channel
+
+ data = bytearray(total_data_length)
+ offset = 0
+ for frame in buffer:
+ frame_data = frame.data.cast("b")
+ data[offset : offset + len(frame_data)] = frame_data
+ offset += len(frame_data)
+
+ return AudioFrame(
+ data=data,
+ sample_rate=sample_rate,
+ num_channels=num_channels,
+ samples_per_channel=total_samples_per_channel,
+ )
+
+
+async def sine_wave_generator(
+ freq: float,
+ duration: float,
+ sample_rate: int = 48000,
+ amplitude: float = 0.3,
+) -> AsyncIterator[AudioFrame]:
+ """
+ Generate sine wave audio frames.
+
+ Useful for testing audio pipelines and generating test signals.
+
+ Args:
+ freq: Frequency of the sine wave in Hz.
+ duration: Duration of the audio in seconds.
+ sample_rate: Sample rate in Hz (default: 48000).
+ amplitude: Amplitude of the sine wave, range [0.0, 1.0] (default: 0.3).
+
+ Yields:
+ AudioFrame: Audio frames containing sine wave data.
+
+ Example:
+ >>> import asyncio
+ >>> async def generate_audio():
+ ... async for frame in sine_wave_generator(440, 1.0):
+ ... print(f"Generated frame with {frame.samples_per_channel} samples")
+ >>> asyncio.run(generate_audio())
+ """
+ try:
+ import numpy as np
+ except ImportError:
+ raise ImportError(
+ "numpy is required for sine_wave_generator. Install it with: pip install numpy"
+ )
+
+ blocksize = sample_rate // 10
+ total_frames = int((duration * sample_rate) // blocksize)
+ t_frame = np.arange(blocksize) / sample_rate
+
+ for i in range(total_frames):
+ t = t_frame + i * blocksize / sample_rate
+ signal = amplitude * np.sin(2 * np.pi * freq * t)
+ signal_int16 = np.int16(signal * 32767)
+ frame = AudioFrame(
+ signal_int16.tobytes(),
+ sample_rate,
+ 1,
+ blocksize,
+ )
+ yield frame
diff --git a/livekit-rtc/livekit/rtc/version.py b/livekit-rtc/livekit/rtc/version.py
index fee46bd8..bf788263 100644
--- a/livekit-rtc/livekit/rtc/version.py
+++ b/livekit-rtc/livekit/rtc/version.py
@@ -1 +1 @@
-__version__ = "0.11.1"
+__version__ = "1.1.7"
diff --git a/livekit-rtc/livekit/rtc/video_frame.py b/livekit-rtc/livekit/rtc/video_frame.py
index 225243d1..ff0035e8 100644
--- a/livekit-rtc/livekit/rtc/video_frame.py
+++ b/livekit-rtc/livekit/rtc/video_frame.py
@@ -18,10 +18,19 @@
from ._proto import ffi_pb2 as proto
from typing import List, Optional
from ._ffi_client import FfiClient, FfiHandle
-from ._utils import get_address
+from ._utils import _ensure_compatible_buffer, get_address
+
+from typing import Any
class VideoFrame:
+ """
+ Represents a video frame with associated metadata and pixel data.
+
+ This class provides methods to access video frame properties such as width, height,
+ and pixel format, as well as methods for manipulating and converting video frames.
+ """
+
def __init__(
self,
width: int,
@@ -29,25 +38,61 @@ def __init__(
type: proto_video.VideoBufferType.ValueType,
data: Union[bytes, bytearray, memoryview],
) -> None:
+ """
+ Initializes a new VideoFrame instance.
+
+ Args:
+ width (int): The width of the video frame in pixels.
+ height (int): The height of the video frame in pixels.
+ type (proto_video.VideoBufferType.ValueType): The format type of the video frame data
+ (e.g., RGBA, BGRA, RGB24, etc.).
+ data (Union[bytes, bytearray, memoryview]): The raw pixel data for the video frame.
+ """
+ data = _ensure_compatible_buffer(data)
+
self._width = width
self._height = height
self._type = type
- self._data = bytearray(data)
+ self._data = data
@property
def width(self) -> int:
+ """
+ Returns the width of the video frame in pixels.
+
+ Returns:
+ int: The width of the video frame.
+ """
return self._width
@property
def height(self) -> int:
+ """
+ Returns the height of the video frame in pixels.
+
+ Returns:
+ int: The height of the video frame.
+ """
return self._height
@property
def type(self) -> proto_video.VideoBufferType.ValueType:
+ """
+ Returns the height of the video frame in pixels.
+
+ Returns:
+ int: The height of the video frame.
+ """
return self._type
@property
def data(self) -> memoryview:
+ """
+ Returns a memoryview of the raw pixel data for the video frame.
+
+ Returns:
+ memoryview: The raw pixel data of the video frame as a memoryview object.
+ """
return memoryview(self._data)
@staticmethod
@@ -62,19 +107,18 @@ def _from_owned_info(owned_info: proto_video.OwnedVideoBuffer) -> "VideoFrame":
type=info.type,
data=data,
)
- FfiHandle(owned_info.handle.id)
+ FfiHandle(owned_info.handle.id).dispose()
return frame
def _proto_info(self) -> proto_video.VideoBufferInfo:
info = proto_video.VideoBufferInfo()
addr = get_address(self.data)
- info.components.extend(
- _get_plane_infos(addr, self.type, self.width, self.height)
- )
+ info.components.extend(_get_plane_infos(addr, self.type, self.width, self.height))
info.width = self.width
info.height = self.height
info.type = self.type
info.data_ptr = addr
+ info.stride = 0
if self.type in [
proto_video.VideoBufferType.ARGB,
@@ -89,9 +133,20 @@ def _proto_info(self) -> proto_video.VideoBufferInfo:
return info
def get_plane(self, plane_nth: int) -> Optional[memoryview]:
- plane_infos = _get_plane_infos(
- get_address(self.data), self.type, self.width, self.height
- )
+ """
+ Returns the memoryview of a specific plane in the video frame, based on its index.
+
+ Some video formats (e.g., I420, NV12) contain multiple planes (Y, U, V channels).
+ This method allows access to individual planes by index.
+
+ Args:
+ plane_nth (int): The index of the plane to retrieve (starting from 0).
+
+ Returns:
+ Optional[memoryview]: A memoryview of the specified plane's data, or None if
+ the index is out of bounds for the format.
+ """
+ plane_infos = _get_plane_infos(get_address(self.data), self.type, self.width, self.height)
if plane_nth >= len(plane_infos):
return None
@@ -102,6 +157,39 @@ def get_plane(self, plane_nth: int) -> Optional[memoryview]:
def convert(
self, type: proto_video.VideoBufferType.ValueType, *, flip_y: bool = False
) -> "VideoFrame":
+ """
+ Converts the current video frame to a different format type, optionally flipping
+ the frame vertically.
+
+ Args:
+ type (proto_video.VideoBufferType.ValueType): The target format type to convert to
+ (e.g., RGBA, I420).
+ flip_y (bool, optional): If True, the frame will be flipped vertically. Defaults to False.
+
+ Returns:
+ VideoFrame: A new VideoFrame object in the specified format.
+
+ Raises:
+ Exception: If the conversion isn't supported.
+
+ Example:
+ Convert a frame from RGBA to I420 format:
+
+ >>> frame = VideoFrame(width=1920, height=1080, type=proto_video.VideoBufferType.RGBA, data=raw_data)
+ >>> converted_frame = frame.convert(proto_video.VideoBufferType.I420)
+ >>> print(converted_frame.type)
+ VideoBufferType.I420
+
+ Example:
+ Convert a frame from BGRA to RGB24 format and flip it vertically:
+
+ >>> frame = VideoFrame(width=1280, height=720, type=proto_video.VideoBufferType.BGRA, data=raw_data)
+ >>> converted_frame = frame.convert(proto_video.VideoBufferType.RGB24, flip_y=True)
+ >>> print(converted_frame.type)
+ VideoBufferType.RGB24
+ >>> print(converted_frame.width, converted_frame.height)
+ 1280 720
+ """
req = proto.FfiRequest()
req.video_convert.flip_y = flip_y
req.video_convert.dst_type = type
@@ -112,6 +200,56 @@ def convert(
return VideoFrame._from_owned_info(resp.video_convert.buffer)
+ def __repr__(self) -> str:
+ return f"rtc.VideoFrame(width={self.width}, height={self.height}, type={proto_video.VideoBufferType.Name(self.type)})"
+
+ @classmethod
+ def __get_pydantic_core_schema__(cls, *_: Any):
+ from pydantic_core import core_schema
+ import base64
+
+ def validate_video_frame(value: Any) -> "VideoFrame":
+ if isinstance(value, VideoFrame):
+ return value
+
+ if isinstance(value, tuple):
+ value = value[0]
+
+ if isinstance(value, dict):
+ return VideoFrame(
+ width=value["width"],
+ height=value["height"],
+ type=proto_video.VideoBufferType.Value(value["type"]),
+ data=base64.b64decode(value["data"]),
+ )
+
+ raise TypeError("Invalid type for VideoFrame")
+
+ return core_schema.json_or_python_schema(
+ json_schema=core_schema.chain_schema(
+ [
+ core_schema.model_fields_schema(
+ {
+ "width": core_schema.model_field(core_schema.int_schema()),
+ "height": core_schema.model_field(core_schema.int_schema()),
+ "type": core_schema.model_field(core_schema.str_schema()),
+ "data": core_schema.model_field(core_schema.str_schema()),
+ },
+ ),
+ core_schema.no_info_plain_validator_function(validate_video_frame),
+ ]
+ ),
+ python_schema=core_schema.no_info_plain_validator_function(validate_video_frame),
+ serialization=core_schema.plain_serializer_function_ser_schema(
+ lambda instance: {
+ "width": instance.width,
+ "height": instance.height,
+ "type": proto_video.VideoBufferType.Name(instance.type),
+ "data": base64.b64encode(instance.data).decode("utf-8"),
+ }
+ ),
+ )
+
def _component_info(
data_ptr: int, stride: int, size: int
@@ -123,11 +261,9 @@ def _component_info(
return cmpt
-def _get_plane_length(
- type: proto_video.VideoBufferType.ValueType, width: int, height: int
-) -> int:
+def _get_plane_length(type: proto_video.VideoBufferType.ValueType, width: int, height: int) -> int:
"""
- Return the size in bytes of a participar video buffer type based on its size (This ignore the strides)
+ Return the size in bytes of a participant video buffer type based on its size (This ignores the strides)
"""
if type in [
proto_video.VideoBufferType.ARGB,
@@ -169,32 +305,22 @@ def _get_plane_infos(
chroma_width = (width + 1) // 2
chroma_height = (height + 1) // 2
y = _component_info(addr, width, width * height)
- u = _component_info(
- y.data_ptr + y.size, chroma_width, chroma_width * chroma_height
- )
- v = _component_info(
- u.data_ptr + u.size, chroma_width, chroma_width * chroma_height
- )
+ u = _component_info(y.data_ptr + y.size, chroma_width, chroma_width * chroma_height)
+ v = _component_info(u.data_ptr + u.size, chroma_width, chroma_width * chroma_height)
return [y, u, v]
elif type == proto_video.VideoBufferType.I420A:
chroma_width = (width + 1) // 2
chroma_height = (height + 1) // 2
y = _component_info(addr, width, width * height)
- u = _component_info(
- y.data_ptr + y.size, chroma_width, chroma_width * chroma_height
- )
- v = _component_info(
- u.data_ptr + u.size, chroma_width, chroma_width * chroma_height
- )
+ u = _component_info(y.data_ptr + y.size, chroma_width, chroma_width * chroma_height)
+ v = _component_info(u.data_ptr + u.size, chroma_width, chroma_width * chroma_height)
a = _component_info(v.data_ptr + v.size, width, width * height)
return [y, u, v, a]
elif type == proto_video.VideoBufferType.I422:
chroma_width = (width + 1) // 2
y = _component_info(addr, width, width * height)
u = _component_info(y.data_ptr + y.size, chroma_width, chroma_width * height)
- v = _component_info(
- u.data_ptr + u.size + u.size, chroma_width, chroma_width * height
- )
+ v = _component_info(u.data_ptr + u.size + u.size, chroma_width, chroma_width * height)
return [y, u, v]
elif type == proto_video.VideoBufferType.I444:
y = _component_info(addr, width, width * height)
@@ -205,12 +331,8 @@ def _get_plane_infos(
chroma_width = (width + 1) // 2
chroma_height = (height + 1) // 2
y = _component_info(addr, width * 2, width * height * 2)
- u = _component_info(
- y.data_ptr + y.size, chroma_width * 2, chroma_width * chroma_height * 2
- )
- v = _component_info(
- u.data_ptr + u.size, chroma_width * 2, chroma_width * chroma_height * 2
- )
+ u = _component_info(y.data_ptr + y.size, chroma_width * 2, chroma_width * chroma_height * 2)
+ v = _component_info(u.data_ptr + u.size, chroma_width * 2, chroma_width * chroma_height * 2)
return [y, u, v]
elif type == proto_video.VideoBufferType.NV12:
chroma_width = (width + 1) // 2
diff --git a/livekit-rtc/livekit/rtc/video_source.py b/livekit-rtc/livekit/rtc/video_source.py
index 377f39f9..be3b3635 100644
--- a/livekit-rtc/livekit/rtc/video_source.py
+++ b/livekit-rtc/livekit/rtc/video_source.py
@@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+from __future__ import annotations
+
from ._ffi_client import FfiHandle, FfiClient
from ._proto import ffi_pb2 as proto_ffi
from ._proto import video_frame_pb2 as proto_video
@@ -19,11 +21,32 @@
class VideoSource:
- def __init__(self, width: int, height: int) -> None:
+ def __init__(self, width: int, height: int, *, is_screencast: bool = False) -> None:
+ """
+ Create a new video source.
+
+ Args:
+ width (int): Initial width of the video source.
+ height (int): Initial height of the video source.
+ is_screencast (bool, optional): Optimize the WebRTC pipeline for screen content.
+ Defaults to False.
+
+ When True, WebRTC will:
+
+ - Maintain resolution under congestion by dropping frames instead of
+ downscaling (keeps text crisp)
+ - Disable quality scaling and denoising to preserve text/UI readability
+ - Guarantee a minimum 1200 kbps bitrate floor
+ - Enable zero-hertz mode, stopping frame transmission when the screen
+ is static to save bandwidth
+ - Set content type to screen, adjusting encoder configuration throughout
+ the pipeline (VP9 inter-layer prediction, simulcast layer allocation, etc.)
+ """
req = proto_ffi.FfiRequest()
req.new_video_source.type = proto_video.VideoSourceType.VIDEO_SOURCE_NATIVE
req.new_video_source.resolution.width = width
req.new_video_source.resolution.height = height
+ req.new_video_source.is_screencast = is_screencast
resp = FfiClient.instance.request(req)
self._info = resp.new_video_source.source
@@ -42,3 +65,6 @@ def capture_frame(
req.capture_video_frame.rotation = rotation
req.capture_video_frame.timestamp_us = timestamp_us
FfiClient.instance.request(req)
+
+ async def aclose(self) -> None:
+ self._ffi_handle.dispose()
diff --git a/livekit-rtc/livekit/rtc/video_stream.py b/livekit-rtc/livekit/rtc/video_stream.py
index 5daf7e6b..f1e8eb5d 100644
--- a/livekit-rtc/livekit/rtc/video_stream.py
+++ b/livekit-rtc/livekit/rtc/video_stream.py
@@ -12,14 +12,18 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+from __future__ import annotations
+
import asyncio
from dataclasses import dataclass
-from typing import Optional
+from typing import Any, AsyncIterator, Optional
-from ._ffi_client import FfiHandle, FfiClient
+from ._ffi_client import FfiClient, FfiHandle
from ._proto import ffi_pb2 as proto_ffi
from ._proto import video_frame_pb2 as proto_video_frame
+from ._proto.track_pb2 import TrackSource
from ._utils import RingQueue, task_done_logger
+from .participant import Participant
from .track import Track
from .video_frame import VideoFrame
@@ -37,34 +41,100 @@ class VideoStream:
def __init__(
self,
track: Track,
- *,
loop: Optional[asyncio.AbstractEventLoop] = None,
capacity: int = 0,
format: Optional[proto_video_frame.VideoBufferType.ValueType] = None,
+ **kwargs,
) -> None:
- self._track = track
self._loop = loop or asyncio.get_event_loop()
- self._ffi_queue = FfiClient.instance.queue.subscribe(self._loop)
- self._queue: RingQueue[VideoFrameEvent] = RingQueue(capacity)
+ # Only subscribe to video_stream_event to avoid unnecessary memory allocations
+ # from other event types (room_event, track_event, etc.)
+ self._ffi_queue = FfiClient.instance.queue.subscribe(
+ self._loop,
+ filter_fn=lambda e: e.WhichOneof("message") == "video_stream_event",
+ )
+ self._queue: RingQueue[VideoFrameEvent | None] = RingQueue(capacity)
+ self._track: Track | None = track
+ self._format = format
+ self._capacity = capacity
+ self._format = format
+ stream: Any = None
+ if "participant" in kwargs:
+ stream = self._create_owned_stream_from_participant(
+ participant=kwargs["participant"], track_source=kwargs["track_source"]
+ )
+ else:
+ stream = self._create_owned_stream()
+
+ self._ffi_handle = FfiHandle(stream.handle.id)
+ self._info = stream.info
+
+ self._task = self._loop.create_task(self._run())
+ self._task.add_done_callback(task_done_logger)
+ @classmethod
+ def from_participant(
+ cls,
+ *,
+ participant: Participant,
+ track_source: TrackSource.ValueType,
+ loop: Optional[asyncio.AbstractEventLoop] = None,
+ format: Optional[proto_video_frame.VideoBufferType.ValueType] = None,
+ capacity: int = 0,
+ ) -> VideoStream:
+ return VideoStream(
+ participant=participant,
+ track_source=track_source,
+ loop=loop,
+ capacity=capacity,
+ format=format,
+ track=None, # type: ignore
+ )
+
+ @classmethod
+ def from_track(
+ cls,
+ *,
+ track: Track,
+ loop: Optional[asyncio.AbstractEventLoop] = None,
+ format: Optional[proto_video_frame.VideoBufferType.ValueType] = None,
+ capacity: int = 0,
+ ) -> VideoStream:
+ return VideoStream(
+ track=track,
+ loop=loop,
+ capacity=capacity,
+ format=format,
+ )
+
+ def __del__(self) -> None:
+ FfiClient.instance.queue.unsubscribe(self._ffi_queue)
+
+ def _create_owned_stream(self) -> Any:
+ assert self._track is not None
req = proto_ffi.FfiRequest()
new_video_stream = req.new_video_stream
- new_video_stream.track_handle = track._ffi_handle.handle
+ new_video_stream.track_handle = self._track._ffi_handle.handle
new_video_stream.type = proto_video_frame.VideoStreamType.VIDEO_STREAM_NATIVE
- if format is not None:
- new_video_stream.format = format
+ if self._format is not None:
+ new_video_stream.format = self._format
new_video_stream.normalize_stride = True
-
resp = FfiClient.instance.request(req)
+ return resp.new_video_stream.stream
- stream_info = resp.new_video_stream.stream
- self._ffi_handle = FfiHandle(stream_info.handle.id)
- self._info = stream_info.info
- self._task = self._loop.create_task(self._run())
- self._task.add_done_callback(task_done_logger)
-
- def __del__(self) -> None:
- FfiClient.instance.queue.unsubscribe(self._ffi_queue)
+ def _create_owned_stream_from_participant(
+ self, participant: Participant, track_source: TrackSource.ValueType
+ ) -> Any:
+ req = proto_ffi.FfiRequest()
+ video_stream_from_participant = req.video_stream_from_participant
+ video_stream_from_participant.participant_handle = participant._ffi_handle.handle
+ video_stream_from_participant.type = proto_video_frame.VideoStreamType.VIDEO_STREAM_NATIVE
+ video_stream_from_participant.track_source = track_source
+ video_stream_from_participant.normalize_stride = True
+ if self._format is not None:
+ video_stream_from_participant.format = self._format
+ resp = FfiClient.instance.request(req)
+ return resp.video_stream_from_participant.stream
async def _run(self) -> None:
while True:
@@ -91,13 +161,18 @@ async def aclose(self) -> None:
self._ffi_handle.dispose()
await self._task
- def __aiter__(self) -> "VideoStream":
- return self
-
def _is_event(self, e: proto_ffi.FfiEvent) -> bool:
return e.video_stream_event.stream_handle == self._ffi_handle.handle
+ def __aiter__(self) -> AsyncIterator[VideoFrameEvent]:
+ return self
+
async def __anext__(self) -> VideoFrameEvent:
if self._task.done():
raise StopAsyncIteration
- return await self._queue.get()
+
+ item = await self._queue.get()
+ if item is None:
+ raise StopAsyncIteration
+
+ return item
diff --git a/livekit-rtc/pyproject.toml b/livekit-rtc/pyproject.toml
index e975c873..5ba944dd 100644
--- a/livekit-rtc/pyproject.toml
+++ b/livekit-rtc/pyproject.toml
@@ -1,22 +1,72 @@
[build-system]
requires = [
- "setuptools>=42",
+ "setuptools>=61",
"wheel",
"requests",
]
build-backend = "setuptools.build_meta"
+[project]
+name = "livekit"
+dynamic = ["version"]
+description = "Python Real-time SDK for LiveKit"
+readme = "README.md"
+requires-python = ">=3.9.0"
+license = "Apache-2.0"
+keywords = ["webrtc", "realtime", "audio", "video", "livekit"]
+authors = [
+ { name = "LiveKit", email = "support@livekit.io" }
+]
+classifiers = [
+ "Intended Audience :: Developers",
+ "Topic :: Multimedia :: Sound/Audio",
+ "Topic :: Multimedia :: Video",
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
+ "Programming Language :: Python :: 3 :: Only",
+]
+dependencies = [
+ "protobuf>=4.25.0",
+ "types-protobuf>=3",
+ "aiofiles>=24",
+ "numpy>=1.26",
+]
+
+[project.urls]
+Documentation = "https://docs.livekit.io"
+Website = "https://livekit.io/"
+Source = "https://github.com/livekit/python-sdks/"
+
+[tool.setuptools.dynamic]
+version = { attr = "livekit.rtc.version.__version__" }
+
+[tool.setuptools.packages.find]
+include = ["livekit.*"]
+
+[tool.setuptools.package-data]
+"livekit.rtc" = ["_proto/*.py", "py.typed", "*.pyi", "**/*.pyi"]
+"livekit.rtc.resources" = [
+ "*.so",
+ "*.dylib",
+ "*.dll",
+ "LICENSE.md",
+ "*.h",
+ "jupyter-html/index.html",
+]
+
[tool.cibuildwheel]
build = "cp39-*"
-skip = "*-musllinux_*" # not supported (libwebrtc is using glibc)
-
+skip = "*-musllinux_*" # not supported (libwebrtc requires glibc)
before-build = "pip install requests && python rust-sdks/download_ffi.py --output livekit/rtc/resources"
-manylinux-x86_64-image = "manylinux_2_28"
-manylinux-i686-image = "manylinux_2_28"
-manylinux-aarch64-image = "manylinux_2_28"
-manylinux-ppc64le-image = "manylinux_2_28"
-manylinux-s390x-image = "manylinux_2_28"
-manylinux-pypy_x86_64-image = "manylinux_2_28"
-manylinux-pypy_i686-image = "manylinux_2_28"
-manylinux-pypy_aarch64-image = "manylinux_2_28"
+# macOS deployment targets must match the FFI binaries (see rust-sdks/.github/workflows/ffi-builds.yml)
+# x86_64 supports macOS 10.15+, arm64 requires macOS 11.0+
+[[tool.cibuildwheel.overrides]]
+select = "*macosx_x86_64"
+environment = { MACOSX_DEPLOYMENT_TARGET = "10.15" }
+
+[[tool.cibuildwheel.overrides]]
+select = "*macosx_arm64"
+environment = { MACOSX_DEPLOYMENT_TARGET = "11.0" }
diff --git a/livekit-rtc/rust-sdks b/livekit-rtc/rust-sdks
index ea0bc400..b885d475 160000
--- a/livekit-rtc/rust-sdks
+++ b/livekit-rtc/rust-sdks
@@ -1 +1 @@
-Subproject commit ea0bc40093ebcc7d308b2c4e8d088340557bdf46
+Subproject commit b885d475538ace130ea6884d615556863b2f0a44
diff --git a/livekit-rtc/setup.py b/livekit-rtc/setup.py
index 8c5e8d44..279e8a19 100644
--- a/livekit-rtc/setup.py
+++ b/livekit-rtc/setup.py
@@ -12,60 +12,66 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+"""Custom setup.py for platform-specific wheel tagging.
+
+This file exists solely to customize the wheel platform tag. All package metadata
+is defined in pyproject.toml.
+
+The native FFI libraries (.so/.dylib/.dll) require specific platform tags that
+respect MACOSX_DEPLOYMENT_TARGET and ARCHFLAGS environment variables set by
+cibuildwheel, rather than using sysconfig.get_platform() which returns Python's
+compile-time values.
+"""
+
import os
-import pathlib
-from typing import Any, Dict
+import platform
+import sys
import setuptools # type: ignore
-import setuptools.command.build_py # type: ignore
from wheel.bdist_wheel import bdist_wheel as _bdist_wheel # type: ignore
-from wheel.bdist_wheel import get_platform # type: ignore
-here = pathlib.Path(__file__).parent.resolve()
-about: Dict[Any, Any] = {}
-with open(os.path.join(here, "livekit", "rtc", "version.py"), "r") as f:
- exec(f.read(), about)
+
+def get_platform_tag():
+ """Get the wheel platform tag for the current/target platform."""
+ if sys.platform == "darwin":
+ # Get deployment target from environment (set by cibuildwheel) or fall back
+ target = os.environ.get("MACOSX_DEPLOYMENT_TARGET")
+ if not target:
+ target = platform.mac_ver()[0]
+ parts = target.split(".")
+ target = f"{parts[0]}.{parts[1] if len(parts) > 1 else '0'}"
+
+ version_tag = target.replace(".", "_")
+
+ # Check ARCHFLAGS for cross-compilation (cibuildwheel sets this)
+ archflags = os.environ.get("ARCHFLAGS", "")
+ if "-arch arm64" in archflags:
+ arch = "arm64"
+ elif "-arch x86_64" in archflags:
+ arch = "x86_64"
+ else:
+ arch = platform.machine()
+
+ return f"macosx_{version_tag}_{arch}"
+ elif sys.platform == "linux":
+ return f"linux_{platform.machine()}"
+ elif sys.platform == "win32":
+ arch = platform.machine()
+ if arch == "AMD64":
+ arch = "amd64"
+ return f"win_{arch}"
+ else:
+ return f"{platform.system().lower()}_{platform.machine()}"
class bdist_wheel(_bdist_wheel):
def finalize_options(self):
- self.plat_name = get_platform(None) # force a platform tag
+ self.plat_name = get_platform_tag()
_bdist_wheel.finalize_options(self)
setuptools.setup(
- name="livekit",
- version=about["__version__"],
- description="Python Real-time SDK for LiveKit",
- long_description=(here / "README.md").read_text(encoding="utf-8"),
- long_description_content_type="text/markdown",
- url="https://github.com/livekit/python-sdks",
cmdclass={
"bdist_wheel": bdist_wheel,
},
- classifiers=[
- "Intended Audience :: Developers",
- "License :: OSI Approved :: Apache Software License",
- "Topic :: Multimedia :: Sound/Audio",
- "Topic :: Multimedia :: Video",
- "Topic :: Scientific/Engineering :: Artificial Intelligence",
- "Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.9",
- "Programming Language :: Python :: 3.10",
- "Programming Language :: Python :: 3 :: Only",
- ],
- keywords=["webrtc", "realtime", "audio", "video", "livekit"],
- license="Apache-2.0",
- packages=setuptools.find_namespace_packages(include=["livekit.*"]),
- python_requires=">=3.9.0",
- install_requires=["protobuf>=3", "types-protobuf>=3"],
- package_data={
- "livekit.rtc": ["_proto/*.py", "py.typed", "*.pyi", "**/*.pyi"],
- "livekit.rtc.resources": ["*.so", "*.dylib", "*.dll", "LICENSE.md", "*.h"],
- },
- project_urls={
- "Documentation": "https://docs.livekit.io",
- "Website": "https://livekit.io/",
- "Source": "https://github.com/livekit/python-sdks/",
- },
)
diff --git a/livekit-rtc/tests/__init__.py b/livekit-rtc/tests/__init__.py
new file mode 100644
index 00000000..c75e2bef
--- /dev/null
+++ b/livekit-rtc/tests/__init__.py
@@ -0,0 +1,13 @@
+# Copyright 2026 LiveKit, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/livekit-rtc/tests/test_chat.py b/livekit-rtc/tests/test_chat.py
deleted file mode 100644
index 161bf9be..00000000
--- a/livekit-rtc/tests/test_chat.py
+++ /dev/null
@@ -1,32 +0,0 @@
-from datetime import datetime
-import json
-
-from livekit.rtc import ChatMessage
-
-
-def test_message_basics():
- msg = ChatMessage()
- assert msg.id is not None, "message id should be set"
- assert msg.timestamp is not None, "timestamp should be set"
- assert msg.timestamp.day == datetime.now().day, "timestamp should be today"
- assert len(msg.id) > 5, "message id should be long enough"
-
-
-def test_message_serialization():
- msg = ChatMessage(
- message="hello",
- )
- data = msg.asjsondict()
- msg2 = ChatMessage.from_jsondict(json.loads(json.dumps(data)))
- assert msg2.message == msg.message, "message should be the same"
- assert msg2.id == msg.id, "id should be the same"
- assert int(msg2.timestamp.timestamp() / 1000) == int(
- msg.timestamp.timestamp() / 1000
- ), "timestamp should be the same"
- assert not msg2.deleted, "not deleted"
-
- # deletion is handled
- msg.deleted = True
- data = msg.asjsondict()
- msg2 = ChatMessage.from_jsondict(json.loads(json.dumps(data)))
- assert msg2.deleted, "should be deleted"
diff --git a/livekit-rtc/tests/test_e2ee.py b/livekit-rtc/tests/test_e2ee.py
new file mode 100644
index 00000000..cf931c43
--- /dev/null
+++ b/livekit-rtc/tests/test_e2ee.py
@@ -0,0 +1,202 @@
+# Copyright 2026 LiveKit, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Unit tests for E2EE functionality."""
+
+
+class TestKeyProviderOptions:
+ """Tests for KeyProviderOptions dataclass."""
+
+ def test_default_values(self):
+ """Test that KeyProviderOptions has correct default values."""
+ from livekit.rtc.e2ee import (
+ KeyProviderOptions,
+ DEFAULT_RATCHET_SALT,
+ DEFAULT_RATCHET_WINDOW_SIZE,
+ DEFAULT_FAILURE_TOLERANCE,
+ DEFAULT_KEY_RING_SIZE,
+ )
+ from livekit.rtc._proto import e2ee_pb2 as proto_e2ee
+
+ options = KeyProviderOptions()
+
+ assert options.shared_key is None
+ assert options.ratchet_salt == DEFAULT_RATCHET_SALT
+ assert options.ratchet_window_size == DEFAULT_RATCHET_WINDOW_SIZE
+ assert options.failure_tolerance == DEFAULT_FAILURE_TOLERANCE
+ assert options.key_ring_size == DEFAULT_KEY_RING_SIZE
+ assert options.key_derivation_function == proto_e2ee.KeyDerivationFunction.PBKDF2
+
+ def test_custom_values(self):
+ """Test KeyProviderOptions with custom values."""
+ from livekit.rtc.e2ee import KeyProviderOptions
+ from livekit.rtc._proto import e2ee_pb2 as proto_e2ee
+
+ options = KeyProviderOptions(
+ shared_key=b"my-secret-key",
+ ratchet_salt=b"custom-salt",
+ ratchet_window_size=32,
+ failure_tolerance=5,
+ key_ring_size=8,
+ key_derivation_function=proto_e2ee.KeyDerivationFunction.HKDF,
+ )
+
+ assert options.shared_key == b"my-secret-key"
+ assert options.ratchet_salt == b"custom-salt"
+ assert options.ratchet_window_size == 32
+ assert options.failure_tolerance == 5
+ assert options.key_ring_size == 8
+ assert options.key_derivation_function == proto_e2ee.KeyDerivationFunction.HKDF
+
+ def test_various_key_lengths(self):
+ """Test that shared_key accepts various lengths."""
+ from livekit.rtc.e2ee import KeyProviderOptions
+
+ # Short key
+ options_short = KeyProviderOptions(shared_key=b"short")
+ assert options_short.shared_key == b"short"
+
+ # Medium key
+ options_medium = KeyProviderOptions(shared_key=b"medium-length-key-here")
+ assert options_medium.shared_key == b"medium-length-key-here"
+
+ # Long key
+ long_key = b"a" * 256
+ options_long = KeyProviderOptions(shared_key=long_key)
+ assert options_long.shared_key == long_key
+
+ # Binary key
+ binary_key = bytes(range(256))
+ options_binary = KeyProviderOptions(shared_key=binary_key)
+ assert options_binary.shared_key == binary_key
+
+
+class TestE2EEOptions:
+ """Tests for E2EEOptions dataclass."""
+
+ def test_default_values(self):
+ """Test E2EEOptions default values."""
+ from livekit.rtc.e2ee import E2EEOptions, KeyProviderOptions
+ from livekit.rtc._proto import e2ee_pb2 as proto_e2ee
+
+ options = E2EEOptions()
+
+ assert isinstance(options.key_provider_options, KeyProviderOptions)
+ assert options.encryption_type == proto_e2ee.EncryptionType.GCM
+
+ def test_with_shared_key(self):
+ """Test E2EEOptions with a shared key."""
+ from livekit.rtc.e2ee import E2EEOptions, KeyProviderOptions
+
+ key_options = KeyProviderOptions(shared_key=b"test-key")
+ options = E2EEOptions(key_provider_options=key_options)
+
+ assert options.key_provider_options.shared_key == b"test-key"
+
+
+class TestProtoMessageBuilding:
+ """Tests for proto message building with E2EE options."""
+
+ def test_proto_key_provider_options_fields(self):
+ """Test that proto KeyProviderOptions has all required fields."""
+ from livekit.rtc._proto import e2ee_pb2 as proto_e2ee
+
+ proto_options = proto_e2ee.KeyProviderOptions()
+
+ # Set all fields that should be present
+ proto_options.shared_key = b"test-key"
+ proto_options.ratchet_window_size = 16
+ proto_options.ratchet_salt = b"LKFrameEncryptionKey"
+ proto_options.failure_tolerance = -1
+ proto_options.key_ring_size = 16
+ proto_options.key_derivation_function = proto_e2ee.KeyDerivationFunction.PBKDF2
+
+ # Verify fields are set correctly
+ assert proto_options.shared_key == b"test-key"
+ assert proto_options.ratchet_window_size == 16
+ assert proto_options.ratchet_salt == b"LKFrameEncryptionKey"
+ assert proto_options.failure_tolerance == -1
+ assert proto_options.key_ring_size == 16
+ assert proto_options.key_derivation_function == proto_e2ee.KeyDerivationFunction.PBKDF2
+
+ def test_proto_serialization(self):
+ """Test that proto message can be serialized without errors."""
+ from livekit.rtc._proto import e2ee_pb2 as proto_e2ee
+
+ proto_options = proto_e2ee.KeyProviderOptions()
+ proto_options.ratchet_window_size = 16
+ proto_options.ratchet_salt = b"LKFrameEncryptionKey"
+ proto_options.failure_tolerance = -1
+ proto_options.key_ring_size = 16
+ proto_options.key_derivation_function = proto_e2ee.KeyDerivationFunction.PBKDF2
+
+ # This should not raise an EncodeError
+ serialized = proto_options.SerializeToString()
+ assert len(serialized) > 0
+
+ # Verify we can deserialize it back
+ parsed = proto_e2ee.KeyProviderOptions()
+ parsed.ParseFromString(serialized)
+ assert parsed.key_ring_size == 16
+ assert parsed.key_derivation_function == proto_e2ee.KeyDerivationFunction.PBKDF2
+
+ def test_e2ee_options_proto_serialization(self):
+ """Test full E2eeOptions proto serialization."""
+ from livekit.rtc._proto import e2ee_pb2 as proto_e2ee
+
+ e2ee_opts = proto_e2ee.E2eeOptions()
+ e2ee_opts.encryption_type = proto_e2ee.EncryptionType.GCM
+ e2ee_opts.key_provider_options.shared_key = b"my-shared-key"
+ e2ee_opts.key_provider_options.ratchet_window_size = 16
+ e2ee_opts.key_provider_options.ratchet_salt = b"LKFrameEncryptionKey"
+ e2ee_opts.key_provider_options.failure_tolerance = -1
+ e2ee_opts.key_provider_options.key_ring_size = 16
+ e2ee_opts.key_provider_options.key_derivation_function = (
+ proto_e2ee.KeyDerivationFunction.PBKDF2
+ )
+
+ # This should not raise an EncodeError
+ serialized = e2ee_opts.SerializeToString()
+ assert len(serialized) > 0
+
+
+class TestPublicExports:
+ """Tests for public API exports."""
+
+ def test_key_derivation_function_exported(self):
+ """Test that KeyDerivationFunction is exported from the package."""
+ from livekit.rtc import KeyDerivationFunction
+
+ # Verify enum values are accessible
+ assert KeyDerivationFunction.PBKDF2 == 0
+ assert KeyDerivationFunction.HKDF == 1
+
+ def test_encryption_type_exported(self):
+ """Test that EncryptionType is exported from the package."""
+ from livekit.rtc import EncryptionType
+
+ assert EncryptionType.NONE == 0
+ assert EncryptionType.GCM == 1
+ assert EncryptionType.CUSTOM == 2
+
+ def test_e2ee_classes_exported(self):
+ """Test that E2EE classes are exported from the package."""
+ from livekit.rtc import E2EEOptions, KeyProviderOptions
+
+ # Should be able to instantiate without errors
+ key_opts = KeyProviderOptions()
+ e2ee_opts = E2EEOptions()
+
+ assert key_opts is not None
+ assert e2ee_opts is not None
diff --git a/makefile b/makefile
new file mode 100644
index 00000000..f58b7f88
--- /dev/null
+++ b/makefile
@@ -0,0 +1,314 @@
+.PHONY: help bootstrap install format format-check lint lint-fix check type-check clean build \
+ build-rtc build-wheel generate-proto download-ffi status doctor
+
+# Colors for output
+CYAN := \033[36m
+GREEN := \033[32m
+YELLOW := \033[33m
+RED := \033[31m
+RESET := \033[0m
+BOLD := \033[1m
+
+# Paths (computed as absolute paths)
+MAKEFILE_DIR := $(shell pwd)
+PYTHON_RTC := $(MAKEFILE_DIR)/livekit-rtc
+PYTHON_API := $(MAKEFILE_DIR)/livekit-api
+PYTHON_PROTOCOL := $(MAKEFILE_DIR)/livekit-protocol
+RUST_SUBMODULE := $(MAKEFILE_DIR)/livekit-rtc/rust-sdks
+
+# Platform and architecture auto-detection
+ARCH := $(shell uname -m)
+OS := $(shell uname -s | tr A-Z a-z)
+
+# Default target
+.DEFAULT_GOAL := help
+
+help: ## Show this help message
+ @echo "$(BOLD)$(CYAN)Available targets:$(RESET)"
+ @echo ""
+ @echo "$(BOLD)Development Workflows:$(RESET)"
+ @grep -E '^(bootstrap|build-rtc|build-wheel|download-ffi|status|doctor):.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " $(CYAN)%-20s$(RESET) %s\n", $$1, $$2}'
+ @echo ""
+ @echo "$(BOLD)Code Quality:$(RESET)"
+ @grep -E '^(format|format-check|lint|lint-fix|type-check|check):.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " $(CYAN)%-20s$(RESET) %s\n", $$1, $$2}'
+ @echo ""
+ @echo "$(BOLD)Other:$(RESET)"
+ @grep -E '^(install|clean|build):.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " $(CYAN)%-20s$(RESET) %s\n", $$1, $$2}'
+
+install: ## Install all dependencies with dev extras
+ @echo "$(BOLD)$(CYAN)Installing dependencies...$(RESET)"
+ @uv sync --all-extras --dev
+ @echo "$(BOLD)$(GREEN)✓ Dependencies installed$(RESET)"
+
+format: ## Format code with ruff
+ @echo "$(BOLD)$(CYAN)Formatting code...$(RESET)"
+ @uv run ruff format .
+ @echo "$(BOLD)$(GREEN)✓ Code formatted$(RESET)"
+
+format-check: ## Check code formatting without making changes
+ @echo "$(BOLD)$(CYAN)Checking code formatting...$(RESET)"
+ @if uv run ruff format --check .; then \
+ echo "$(BOLD)$(GREEN)✓ Code formatting is correct$(RESET)"; \
+ else \
+ echo "$(BOLD)$(RED)✗ Code formatting issues found. Run 'make format' to fix.$(RESET)"; \
+ exit 1; \
+ fi
+
+lint: ## Run ruff linter
+ @echo "$(BOLD)$(CYAN)Running linter...$(RESET)"
+ @if uv run ruff check .; then \
+ echo "$(BOLD)$(GREEN)✓ No linting issues found$(RESET)"; \
+ else \
+ echo "$(BOLD)$(RED)✗ Linting issues found$(RESET)"; \
+ exit 1; \
+ fi
+
+lint-fix: ## Run ruff linter and fix issues automatically
+ @echo "$(BOLD)$(CYAN)Running linter with auto-fix...$(RESET)"
+ @uv run ruff check --fix .
+ @echo "$(BOLD)$(GREEN)✓ Linting complete$(RESET)"
+
+type-check: ## Run mypy type checker
+ @echo "$(BOLD)$(CYAN)Running type checker...$(RESET)"
+ @uv pip install pip 2>/dev/null || true
+ @if uv run mypy --install-types --non-interactive \
+ -p livekit.rtc \
+ -p livekit.api \
+ -p livekit.protocol; then \
+ echo "$(BOLD)$(GREEN)✓ Type checking passed$(RESET)"; \
+ else \
+ echo "$(BOLD)$(RED)✗ Type checking failed$(RESET)"; \
+ exit 1; \
+ fi
+
+check: format-check lint type-check ## Run all checks (format, lint, type-check)
+ @echo "$(BOLD)$(GREEN)✓ All checks passed!$(RESET)"
+
+# ============================================
+# Development Workflows
+# ============================================
+
+download-ffi: ## Download pre-built FFI artifacts for livekit-rtc
+ @echo "$(BOLD)$(CYAN)📦 Downloading FFI artifacts...$(RESET)"
+ @set -e; \
+ DETECTED_ARCH="$(ARCH)"; \
+ DETECTED_OS="$(OS)"; \
+ if [ "$$DETECTED_ARCH" = "aarch64" ]; then \
+ PLATFORM_ARCH="arm64"; \
+ else \
+ PLATFORM_ARCH="$$DETECTED_ARCH"; \
+ fi; \
+ if [ "$$DETECTED_OS" = "darwin" ]; then \
+ PLATFORM_OS="macos"; \
+ else \
+ PLATFORM_OS="$$DETECTED_OS"; \
+ fi; \
+ echo "$(CYAN) Platform: $$PLATFORM_OS-$$PLATFORM_ARCH$(RESET)"; \
+ cd $(PYTHON_RTC) && python rust-sdks/download_ffi.py --platform "$$PLATFORM_OS" --arch "$$PLATFORM_ARCH" --output livekit/rtc/resources; \
+ echo "$(BOLD)$(GREEN)✅ FFI artifacts downloaded$(RESET)"
+
+build-rtc: ## Build livekit-ffi from local rust-sdks and generate proto
+ @echo "$(BOLD)$(CYAN)🦀 Building livekit-ffi from source...$(RESET)"
+ @set -e; \
+ if [ ! -d "$(RUST_SUBMODULE)" ]; then \
+ echo "$(BOLD)$(RED)✗ Error: rust-sdks submodule not found at $(RUST_SUBMODULE)$(RESET)"; \
+ exit 1; \
+ fi; \
+ echo "$(CYAN)🦀 Building livekit-ffi...$(RESET)"; \
+ cd $(RUST_SUBMODULE) && cargo build --release -p livekit-ffi; \
+ echo "$(CYAN)📝 Generating protobuf FFI protocol...$(RESET)"; \
+ cd $(PYTHON_RTC) && ./generate_proto.sh; \
+ RUST_LIB_DIR="$$(cd $(RUST_SUBMODULE) && pwd)/target/release"; \
+ if [ "$(OS)" = "darwin" ]; then \
+ RUST_LIB_PATH="$$RUST_LIB_DIR/liblivekit_ffi.dylib"; \
+ elif [ "$(OS)" = "linux" ]; then \
+ RUST_LIB_PATH="$$RUST_LIB_DIR/liblivekit_ffi.so"; \
+ else \
+ RUST_LIB_PATH="$$RUST_LIB_DIR/livekit_ffi.dll"; \
+ fi; \
+ echo "$(BOLD)$(GREEN)✅ Built livekit-ffi from source$(RESET)"; \
+ echo ""; \
+ echo "$(BOLD)$(YELLOW)📋 To use the local rust lib, export the following:$(RESET)"; \
+ echo "$(BOLD) export LIVEKIT_LIB_PATH=$$RUST_LIB_PATH$(RESET)"
+
+build-wheel: ## Build wheel for a package (usage: make build-wheel PACKAGE=livekit-rtc)
+ @echo "$(BOLD)$(CYAN)📦 Building wheel...$(RESET)"
+ @set -e; \
+ if [ -z "$(PACKAGE)" ]; then \
+ echo "$(BOLD)$(RED)✗ Error: PACKAGE parameter is required$(RESET)"; \
+ echo "$(YELLOW)Usage: make build-wheel PACKAGE=$(RESET)"; \
+ echo "$(YELLOW)Available packages: livekit-rtc, livekit-api, livekit-protocol$(RESET)"; \
+ exit 1; \
+ fi; \
+ PACKAGE_PATH="$(MAKEFILE_DIR)/$(PACKAGE)"; \
+ if [ ! -d "$$PACKAGE_PATH" ]; then \
+ echo "$(BOLD)$(RED)✗ Error: Package directory not found: $$PACKAGE_PATH$(RESET)"; \
+ exit 1; \
+ fi; \
+ if [ ! -f "$$PACKAGE_PATH/pyproject.toml" ]; then \
+ echo "$(BOLD)$(RED)✗ Error: pyproject.toml not found in $$PACKAGE_PATH$(RESET)"; \
+ exit 1; \
+ fi; \
+ echo "$(CYAN) Package: $(PACKAGE)$(RESET)"; \
+ echo "$(CYAN) Building in: $$PACKAGE_PATH$(RESET)"; \
+ cd "$$PACKAGE_PATH" && uv build --out-dir ./dist; \
+ echo "$(BOLD)$(GREEN)✅ Wheel built successfully$(RESET)"; \
+ echo "$(CYAN) Output: $$PACKAGE_PATH/dist/$(RESET)"
+
+status: ## Show current development environment status
+ @echo "$(BOLD)$(CYAN)📍 Current status:$(RESET)"
+ @echo ""
+ @set -e; \
+ echo "$(BOLD)📦 Packages:$(RESET)"; \
+ for pkg in livekit livekit-api livekit-protocol; do \
+ SHOW_OUTPUT=$$(uv pip show $$pkg 2>/dev/null || echo ""); \
+ if [ -z "$$SHOW_OUTPUT" ]; then \
+ echo " $$pkg: NOT INSTALLED"; \
+ elif echo "$$SHOW_OUTPUT" | grep -q "Editable project location:"; then \
+ VERSION=$$(echo "$$SHOW_OUTPUT" | grep "^Version:" | awk '{print $$2}'); \
+ LOCATION=$$(echo "$$SHOW_OUTPUT" | grep "Editable project location:" | cut -d' ' -f4-); \
+ echo " $$pkg: LOCAL (editable) v$$VERSION"; \
+ echo " path: $$LOCATION"; \
+ else \
+ VERSION=$$(echo "$$SHOW_OUTPUT" | grep "^Version:" | awk '{print $$2}'); \
+ echo " $$pkg: PyPI v$$VERSION"; \
+ fi; \
+ done; \
+ echo ""; \
+ echo "$(BOLD)🦀 FFI Status:$(RESET)"; \
+ if [ -n "$$LIVEKIT_LIB_PATH" ]; then \
+ if [ -f "$$LIVEKIT_LIB_PATH" ]; then \
+ echo " FFI: CUSTOM (from LIVEKIT_LIB_PATH env var)"; \
+ echo " path: $$LIVEKIT_LIB_PATH"; \
+ else \
+ echo " FFI: CUSTOM (LIVEKIT_LIB_PATH set but file not found)"; \
+ echo " path: $$LIVEKIT_LIB_PATH"; \
+ fi; \
+ else \
+ FFI_PATH="$(PYTHON_RTC)/livekit/rtc/resources"; \
+ if [ -d "$$FFI_PATH" ] && { [ -f "$$FFI_PATH/liblivekit_ffi.dylib" ] || [ -f "$$FFI_PATH/liblivekit_ffi.so" ] || [ -f "$$FFI_PATH/livekit_ffi.dll" ]; }; then \
+ RUST_SUBMODULE_DIR="$$(cd $(RUST_SUBMODULE) 2>/dev/null && pwd || echo "")"; \
+ CARGO_TOML_PATH="$$RUST_SUBMODULE_DIR/livekit-ffi/Cargo.toml"; \
+ if [ -f "$$CARGO_TOML_PATH" ]; then \
+ FFI_VERSION=$$(grep '^version = ' "$$CARGO_TOML_PATH" | head -1 | sed 's/.*"\(.*\)".*/\1/'); \
+ echo " FFI: PRE-BUILT ARTIFACTS (v$$FFI_VERSION)"; \
+ else \
+ echo " FFI: PRE-BUILT ARTIFACTS"; \
+ fi; \
+ else \
+ echo " FFI: NOT AVAILABLE (run 'make download-ffi')"; \
+ fi; \
+ fi
+
+doctor: ## Check development environment health
+ @echo "$(BOLD)$(CYAN)🏥 Running diagnostics...$(RESET)"
+ @echo ""
+ @ISSUES=0; \
+ echo "$(BOLD)📦 Required Tools:$(RESET)"; \
+ if command -v uv &> /dev/null; then \
+ UV_VERSION=$$(uv --version 2>&1 | head -1); \
+ echo " ✓ uv: $$UV_VERSION"; \
+ else \
+ echo " ✗ uv: NOT FOUND"; \
+ ISSUES=$$((ISSUES + 1)); \
+ fi; \
+ if command -v python &> /dev/null; then \
+ PYTHON_VERSION=$$(python --version 2>&1); \
+ echo " ✓ python: $$PYTHON_VERSION"; \
+ else \
+ echo " ✗ python: NOT FOUND"; \
+ ISSUES=$$((ISSUES + 1)); \
+ fi; \
+ if command -v cargo &> /dev/null; then \
+ CARGO_VERSION=$$(cargo --version 2>&1); \
+ echo " ✓ cargo: $$CARGO_VERSION"; \
+ else \
+ echo " ⚠ cargo: NOT FOUND (required for 'make build-rtc')"; \
+ fi; \
+ if command -v git &> /dev/null; then \
+ GIT_VERSION=$$(git --version 2>&1); \
+ echo " ✓ git: $$GIT_VERSION"; \
+ else \
+ echo " ✗ git: NOT FOUND"; \
+ ISSUES=$$((ISSUES + 1)); \
+ fi; \
+ echo ""; \
+ echo "$(BOLD)📂 Repository Structure:$(RESET)"; \
+ REPO_ROOT=$$(cd $(MAKEFILE_DIR) && git rev-parse --show-toplevel 2>/dev/null || echo ""); \
+ if [ -n "$$REPO_ROOT" ]; then \
+ BRANCH=$$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown"); \
+ COMMIT=$$(git rev-parse --short HEAD 2>/dev/null || echo "unknown"); \
+ echo " ✓ python-sdks: $$REPO_ROOT"; \
+ echo " Branch: $$BRANCH @ $$COMMIT"; \
+ fi; \
+ if [ -d "$(PYTHON_RTC)" ]; then \
+ echo " ✓ livekit-rtc: $(PYTHON_RTC)"; \
+ else \
+ echo " ✗ livekit-rtc: NOT FOUND"; \
+ ISSUES=$$((ISSUES + 1)); \
+ fi; \
+ if [ -d "$(PYTHON_API)" ]; then \
+ echo " ✓ livekit-api: $(PYTHON_API)"; \
+ else \
+ echo " ✗ livekit-api: NOT FOUND"; \
+ ISSUES=$$((ISSUES + 1)); \
+ fi; \
+ if [ -d "$(PYTHON_PROTOCOL)" ]; then \
+ echo " ✓ livekit-protocol: $(PYTHON_PROTOCOL)"; \
+ else \
+ echo " ✗ livekit-protocol: NOT FOUND"; \
+ ISSUES=$$((ISSUES + 1)); \
+ fi; \
+ if [ -d "$(RUST_SUBMODULE)" ]; then \
+ echo " ✓ rust-sdks: $(RUST_SUBMODULE)"; \
+ if [ -e "$(RUST_SUBMODULE)/.git" ]; then \
+ RUST_BRANCH=$$(cd $(RUST_SUBMODULE) && git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown"); \
+ RUST_COMMIT=$$(cd $(RUST_SUBMODULE) && git rev-parse --short HEAD 2>/dev/null || echo "unknown"); \
+ echo " Branch: $$RUST_BRANCH @ $$RUST_COMMIT"; \
+ fi; \
+ else \
+ echo " ⚠ rust-sdks: NOT FOUND (needed for 'make build-rtc')"; \
+ fi; \
+ echo ""; \
+ echo "$(BOLD)🔍 Current Configuration:$(RESET)"; \
+ if [ -d ".venv" ]; then \
+ echo " ✓ Virtual environment: .venv exists"; \
+ else \
+ echo " ⚠ Virtual environment: .venv not found (run 'make install')"; \
+ fi; \
+ for pkg in livekit livekit-api livekit-protocol; do \
+ SHOW_OUTPUT=$$(uv pip show $$pkg 2>/dev/null || echo ""); \
+ if [ -z "$$SHOW_OUTPUT" ]; then \
+ echo " ✗ $$pkg: NOT INSTALLED"; \
+ elif echo "$$SHOW_OUTPUT" | grep -q "Editable project location:"; then \
+ VERSION=$$(echo "$$SHOW_OUTPUT" | grep "^Version:" | awk '{print $$2}'); \
+ echo " ✓ $$pkg: LOCAL (editable) v$$VERSION"; \
+ else \
+ VERSION=$$(echo "$$SHOW_OUTPUT" | grep "^Version:" | awk '{print $$2}'); \
+ echo " ✓ $$pkg: PyPI v$$VERSION"; \
+ fi; \
+ done; \
+ if [ -n "$$LIVEKIT_LIB_PATH" ]; then \
+ if [ -f "$$LIVEKIT_LIB_PATH" ]; then \
+ echo " ✓ FFI: Custom build from LIVEKIT_LIB_PATH"; \
+ else \
+ echo " ✗ FFI: LIVEKIT_LIB_PATH set but file not found: $$LIVEKIT_LIB_PATH"; \
+ ISSUES=$$((ISSUES + 1)); \
+ fi; \
+ fi; \
+ echo ""; \
+ if [ $$ISSUES -eq 0 ]; then \
+ echo "$(BOLD)$(GREEN)✅ All checks passed! Environment is healthy.$(RESET)"; \
+ else \
+ echo "$(BOLD)$(RED)⚠️ Found $$ISSUES issue(s). Please fix the errors above.$(RESET)"; \
+ exit 1; \
+ fi
+
+bootstrap: ## Sync repo, deps, and assets to a working dev state (safe to re-run)
+ @echo "$(BOLD)$(CYAN)🔄 Syncing development environment...$(RESET)"
+ @git submodule update --init --recursive
+ @git lfs install
+ @git lfs pull
+ @$(MAKE) install
+ @$(MAKE) download-ffi
+ @echo "$(BOLD)$(GREEN)✓ Sync complete$(RESET)"
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 00000000..467a9a7e
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,77 @@
+[project]
+name = "python-sdks"
+version = "0.1.0"
+description = "LiveKit Python SDKs monorepo"
+requires-python = ">=3.9"
+dependencies = ["livekit", "livekit-api", "livekit-protocol"]
+
+[tool.uv.workspace]
+members = ["livekit-rtc", "livekit-api", "livekit-protocol"]
+
+[tool.uv.sources]
+livekit = { workspace = true }
+livekit-api = { workspace = true }
+livekit-protocol = { workspace = true }
+
+[dependency-groups]
+dev = [
+ # Linting and type checking
+ "ruff>=0.8.5",
+ "mypy>=1.13.0",
+ "types-aiofiles>=24",
+ "ipython>=8.0.0",
+ # Testing
+ "pytest>=8.3.4",
+ "pytest-asyncio>=0.24.0",
+ # Build and packaging
+ "requests",
+ "wheel",
+ "twine",
+ "auditwheel; sys_platform == 'linux'",
+ "cibuildwheel",
+ # Additional dependencies
+ "matplotlib",
+ "pydantic",
+ "numpy",
+]
+
+[tool.ruff]
+line-length = 100
+target-version = "py39"
+exclude = [".github"]
+
+[tool.ruff.lint]
+select = [
+ "E", # pycodestyle errors
+ "W", # pycodestyle warnings
+ "F", # pyflakes
+ "I", # isort
+ "B", # flake8-bugbear
+ "C4", # flake8-comprehensions
+ "UP", # pyupgrade
+]
+ignore = ["E501"]
+
+[tool.ruff.lint.isort]
+combine-as-imports = true
+known-first-party = ["livekit"]
+
+[tool.ruff.lint.pydocstyle]
+convention = "google"
+
+
+[tool.pytest.ini_options]
+testpaths = ["tests"]
+asyncio_mode = "auto"
+asyncio_default_fixture_loop_scope = "function"
+addopts = ["--import-mode=importlib", "--ignore=examples"]
+
+
+[tool.mypy]
+exclude = "(build|setup\\.py|livekit-rtc/rust-sdks.*)"
+namespace_packages = true
+explicit_package_bases = true
+mypy_path = "livekit-protocol:livekit-api:livekit-rtc"
+strict = false # TODO re-enable strict checking
+disallow_any_generics = false
+plugins = ["pydantic.mypy"]
diff --git a/renovate.json b/renovate.json
new file mode 100644
index 00000000..28e8d0f6
--- /dev/null
+++ b/renovate.json
@@ -0,0 +1,17 @@
+{
+ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
+ "extends": ["config:base", "helpers:pinGitHubActionDigests"],
+ "minimumReleaseAge": "2 weeks",
+ "commitBody": "Generated by renovateBot",
+ "packageRules": [
+ {
+ "matchManagers": ["github-actions"],
+ "groupName": "github workflows"
+ },
+ {
+ "matchManagers": ["pip_requirements", "pip_setup", "pep621"],
+ "groupName": "python deps",
+ "schedule": ["before 9am on monday"]
+ }
+ ]
+}
diff --git a/ruff.toml b/ruff.toml
index c1dc76a4..8d44a7dc 100644
--- a/ruff.toml
+++ b/ruff.toml
@@ -3,7 +3,7 @@ exclude = [
"livekit-protocol/livekit/protocol"
]
-line-length = 88
+line-length = 100
indent-width = 4
target-version = "py39"
diff --git a/livekit-api/tests/test_access_token.py b/tests/api/test_access_token.py
similarity index 52%
rename from livekit-api/tests/test_access_token.py
rename to tests/api/test_access_token.py
index 76c986a6..48835ea1 100644
--- a/livekit-api/tests/test_access_token.py
+++ b/tests/api/test_access_token.py
@@ -2,6 +2,8 @@
import pytest # type: ignore
from livekit.api import AccessToken, TokenVerifier, VideoGrants, SIPGrants
+from livekit.protocol.room import RoomConfiguration
+from livekit.protocol.agent_dispatch import RoomAgentDispatch
TEST_API_KEY = "myapikey"
TEST_API_SECRET = "thiskeyistotallyunsafe"
@@ -17,6 +19,7 @@ def test_verify_token():
.with_metadata("test_metadata")
.with_grants(grants)
.with_sip_grants(sip)
+ .with_attributes({"key1": "value1", "key2": "value2"})
.to_jwt()
)
@@ -27,15 +30,53 @@ def test_verify_token():
assert claims.metadata == "test_metadata"
assert claims.video == grants
assert claims.sip == sip
+ assert claims.attributes["key1"] == "value1"
+ assert claims.attributes["key2"] == "value2"
-def test_verify_token_invalid():
+def test_agent_config():
token = (
AccessToken(TEST_API_KEY, TEST_API_SECRET)
.with_identity("test_identity")
+ .with_grants(VideoGrants(room_join=True, room="test_room"))
+ .with_room_config(
+ RoomConfiguration(
+ agents=[RoomAgentDispatch(agent_name="test-agent")],
+ ),
+ )
.to_jwt()
)
+ token_verifier = TokenVerifier(TEST_API_KEY, TEST_API_SECRET)
+ claims = token_verifier.verify(token)
+ # Verify the decoded claims match
+ assert claims.room_config.agents[0].agent_name == "test-agent"
+
+ # Split token into header.payload.signature
+ parts = token.split(".")
+ import base64
+ import json
+
+ # Decode the payload (middle part)
+ payload = parts[1]
+ # Add padding if needed
+ padding = len(payload) % 4
+ if padding:
+ payload += "=" * (4 - padding)
+ decoded = base64.b64decode(payload)
+ payload_json = json.loads(decoded)
+ print(decoded)
+
+ # Verify the room_config and agents were encoded correctly
+ assert "roomConfig" in payload_json
+ assert "agents" in payload_json["roomConfig"]
+ assert len(payload_json["roomConfig"]["agents"]) == 1
+ assert payload_json["roomConfig"]["agents"][0]["agentName"] == "test-agent"
+
+
+def test_verify_token_invalid():
+ token = AccessToken(TEST_API_KEY, TEST_API_SECRET).with_identity("test_identity").to_jwt()
+
token_verifier = TokenVerifier(TEST_API_KEY, "invalid_secret")
with pytest.raises(Exception):
token_verifier.verify(token)
diff --git a/livekit-api/tests/test_webhook.py b/tests/api/test_webhook.py
similarity index 100%
rename from livekit-api/tests/test_webhook.py
rename to tests/api/test_webhook.py
diff --git a/tests/rtc/fixtures/.gitattributes b/tests/rtc/fixtures/.gitattributes
new file mode 100644
index 00000000..d899f655
--- /dev/null
+++ b/tests/rtc/fixtures/.gitattributes
@@ -0,0 +1 @@
+*.wav filter=lfs diff=lfs merge=lfs -text
diff --git a/tests/rtc/fixtures/test_audio.wav b/tests/rtc/fixtures/test_audio.wav
new file mode 100644
index 00000000..70e28398
--- /dev/null
+++ b/tests/rtc/fixtures/test_audio.wav
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ac5cba8b2477ab55c9bc5f95faffcd3d9b9ad4e6a01d79308fbe6eeef733ce80
+size 534606
diff --git a/tests/rtc/fixtures/test_echo_capture.wav b/tests/rtc/fixtures/test_echo_capture.wav
new file mode 100644
index 00000000..14035d71
--- /dev/null
+++ b/tests/rtc/fixtures/test_echo_capture.wav
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:90626c2c532dfb8313ae52501a9500f1c90235570aab8ff1367e7f91fb697a7e
+size 970796
diff --git a/tests/rtc/fixtures/test_echo_render.wav b/tests/rtc/fixtures/test_echo_render.wav
new file mode 100644
index 00000000..3d061ce6
--- /dev/null
+++ b/tests/rtc/fixtures/test_echo_render.wav
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:cf50f57f00fa941ab612c57c24a28811b93c878d3c98edcb4a8f21508aa8e566
+size 970796
diff --git a/tests/rtc/fixtures/test_processed.wav b/tests/rtc/fixtures/test_processed.wav
new file mode 100644
index 00000000..c8520e86
--- /dev/null
+++ b/tests/rtc/fixtures/test_processed.wav
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8a48eb2f6a2143b4bc6adfe306983637f628fffc9d550c60b4ebcecd506d6245
+size 971564
diff --git a/tests/rtc/test_agc.py b/tests/rtc/test_agc.py
new file mode 100644
index 00000000..fb2f5df1
--- /dev/null
+++ b/tests/rtc/test_agc.py
@@ -0,0 +1,60 @@
+import os
+import wave
+import numpy as np
+
+from livekit.rtc import AudioProcessingModule, AudioFrame
+
+FIXTURES_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "fixtures")
+
+
+def test_agc_modifies_audio():
+ num_channels = 1
+
+ input_wav = os.path.join(FIXTURES_DIR, "test_audio.wav")
+ output_wav = os.path.join(FIXTURES_DIR, "test_processed.wav")
+
+ apm = AudioProcessingModule(auto_gain_control=True)
+
+ any_frame_modified = False
+
+ with wave.open(input_wav, "rb") as wf_in:
+ assert wf_in.getnchannels() == num_channels, "Input file must be mono."
+ sample_rate = wf_in.getframerate()
+ sampwidth = wf_in.getsampwidth()
+ frames_per_chunk = sample_rate // 100
+
+ with wave.open(output_wav, "wb") as wf_out:
+ wf_out.setnchannels(num_channels)
+ wf_out.setsampwidth(sampwidth)
+ wf_out.setframerate(sample_rate)
+
+ while True:
+ raw_bytes = wf_in.readframes(frames_per_chunk)
+ if not raw_bytes:
+ break
+
+ data = np.frombuffer(raw_bytes, dtype=np.int16)
+ if len(data) < frames_per_chunk:
+ data = np.pad(data, (0, frames_per_chunk - len(data)))
+
+ original = data.copy()
+
+ frame = AudioFrame(
+ data=data.tobytes(),
+ sample_rate=sample_rate,
+ num_channels=num_channels,
+ samples_per_channel=frames_per_chunk,
+ )
+
+ apm.process_stream(frame)
+
+ processed = np.frombuffer(frame.data, dtype=np.int16)
+ if not np.array_equal(original, processed):
+ any_frame_modified = True
+
+ wf_out.writeframes(frame.data.tobytes())
+
+ assert any_frame_modified, (
+ "APM did not modify any audio frames — processing may be a no-op. "
+ "With AGC enabled, output should differ from input."
+ )
diff --git a/tests/rtc/test_apm.py b/tests/rtc/test_apm.py
new file mode 100644
index 00000000..94795e3c
--- /dev/null
+++ b/tests/rtc/test_apm.py
@@ -0,0 +1,80 @@
+import os
+import wave
+import numpy as np
+
+from livekit.rtc import AudioProcessingModule, AudioFrame
+
+# Test fixture directory
+FIXTURES_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "fixtures")
+
+
+def test_audio_processing():
+ sample_rate = 48000
+ num_channels = 1
+ frames_per_chunk = sample_rate // 100
+
+ capture_wav = os.path.join(FIXTURES_DIR, "test_echo_capture.wav")
+ render_wav = os.path.join(FIXTURES_DIR, "test_echo_render.wav")
+ output_wav = os.path.join(FIXTURES_DIR, "test_processed.wav")
+
+ # Initialize APM with echo cancellation enabled
+ apm = AudioProcessingModule(
+ echo_cancellation=True,
+ noise_suppression=True,
+ high_pass_filter=True,
+ auto_gain_control=True,
+ )
+ print("APM Internal Handle:", apm._ffi_handle)
+
+ with (
+ wave.open(capture_wav, "rb") as wf_in_cap,
+ wave.open(render_wav, "rb") as wf_in_rend,
+ wave.open(output_wav, "wb") as wf_out,
+ ):
+ assert wf_in_cap.getnchannels() == num_channels, "Capture file must be mono."
+ assert wf_in_rend.getnchannels() == num_channels, "Render file must be mono."
+ assert wf_in_cap.getframerate() == sample_rate, "Capture file must be 48 kHz."
+ assert wf_in_rend.getframerate() == sample_rate, "Render file must be 48 kHz."
+
+ sampwidth = wf_in_cap.getsampwidth()
+ wf_out.setnchannels(num_channels)
+ wf_out.setsampwidth(sampwidth)
+ wf_out.setframerate(sample_rate)
+
+ while True:
+ capture_bytes = wf_in_cap.readframes(frames_per_chunk)
+ render_bytes = wf_in_rend.readframes(frames_per_chunk)
+
+ if not capture_bytes and not render_bytes:
+ break
+
+ # Convert bytes to numpy arrays
+ capture_data = np.frombuffer(capture_bytes, dtype=np.int16)
+ render_data = np.frombuffer(render_bytes, dtype=np.int16)
+
+ # Pad if necessary
+ if len(capture_data) < frames_per_chunk:
+ capture_data = np.pad(capture_data, (0, frames_per_chunk - len(capture_data)))
+ if len(render_data) < frames_per_chunk:
+ render_data = np.pad(render_data, (0, frames_per_chunk - len(render_data)))
+
+ capture_frame = AudioFrame(
+ data=capture_data.tobytes(),
+ sample_rate=sample_rate,
+ num_channels=num_channels,
+ samples_per_channel=frames_per_chunk,
+ )
+ render_frame = AudioFrame(
+ data=render_data.tobytes(),
+ sample_rate=sample_rate,
+ num_channels=num_channels,
+ samples_per_channel=frames_per_chunk,
+ )
+
+ # Process both streams
+ apm.process_reverse_stream(render_frame)
+ apm.process_stream(capture_frame)
+
+ wf_out.writeframes(capture_frame.data.tobytes())
+
+ print("Done! Processed audio saved to:", output_wav)
diff --git a/tests/rtc/test_e2e.py b/tests/rtc/test_e2e.py
new file mode 100644
index 00000000..6935d3c6
--- /dev/null
+++ b/tests/rtc/test_e2e.py
@@ -0,0 +1,530 @@
+"""
+End-to-end tests for LiveKit RTC library.
+
+These tests verify core functionality of the LiveKit RTC library including:
+- Publishing and subscribing to audio & data tracks
+- Audio stream consumption and energy verification
+- Room lifecycle events (connect, disconnect, track publish/unpublish)
+- Connection state transitions
+
+Requirements:
+- LIVEKIT_URL: LiveKit server URL
+- LIVEKIT_API_KEY: API key for authentication
+- LIVEKIT_API_SECRET: API secret for authentication
+
+Tests will be skipped if these environment variables are not set.
+
+Usage:
+ pytest test_e2e.py -v
+"""
+
+import asyncio
+import os
+import time
+import uuid
+from typing import Callable, TypeVar
+import numpy as np
+import pytest
+
+from livekit import rtc, api
+from livekit.rtc.utils import sine_wave_generator
+
+
+SAMPLE_RATE = 48000
+T = TypeVar("T")
+
+
+async def assert_eventually(
+ condition: Callable[[], T],
+ timeout: float = 5.0,
+ interval: float = 0.1,
+ message: str = "Condition not met within timeout",
+) -> T:
+ """
+ Poll a condition until it becomes truthy or timeout is reached.
+ Returns immediately once condition is satisfied.
+ """
+ deadline = asyncio.get_event_loop().time() + timeout
+ last_result = None
+
+ while asyncio.get_event_loop().time() < deadline:
+ last_result = condition()
+ if last_result:
+ return last_result
+ await asyncio.sleep(interval)
+
+ raise AssertionError(f"{message} (last result: {last_result})")
+
+
+def skip_if_no_credentials():
+ required_vars = ["LIVEKIT_URL", "LIVEKIT_API_KEY", "LIVEKIT_API_SECRET"]
+ missing = [var for var in required_vars if not os.getenv(var)]
+ return pytest.mark.skipif(
+ bool(missing), reason=f"Missing environment variables: {', '.join(missing)}"
+ )
+
+
+def create_token(identity: str, room_name: str) -> str:
+ return (
+ api.AccessToken()
+ .with_identity(identity)
+ .with_name(identity)
+ .with_grants(
+ api.VideoGrants(
+ room_join=True,
+ room=room_name,
+ )
+ )
+ .to_jwt()
+ )
+
+
+def unique_room_name(base: str) -> str:
+ return f"{base}-{uuid.uuid4().hex[:8]}"
+
+
+@pytest.mark.asyncio
+@skip_if_no_credentials()
+async def test_publish_track():
+ """Test that a published track can be subscribed by another participant"""
+ room_name = unique_room_name("test-publish-track")
+ url = os.getenv("LIVEKIT_URL")
+
+ publisher_room = rtc.Room()
+ subscriber_room = rtc.Room()
+
+ publisher_token = create_token("publisher", room_name)
+ subscriber_token = create_token("subscriber", room_name)
+
+ track_published_event = asyncio.Event()
+ track_subscribed_event = asyncio.Event()
+ subscribed_track = None
+
+ @subscriber_room.on("track_published")
+ def on_track_published(
+ publication: rtc.RemoteTrackPublication, participant: rtc.RemoteParticipant
+ ):
+ track_published_event.set()
+
+ @subscriber_room.on("track_subscribed")
+ def on_track_subscribed(
+ track: rtc.Track,
+ publication: rtc.RemoteTrackPublication,
+ participant: rtc.RemoteParticipant,
+ ):
+ nonlocal subscribed_track
+ if track.kind == rtc.TrackKind.KIND_AUDIO:
+ subscribed_track = track
+ track_subscribed_event.set()
+
+ try:
+ await subscriber_room.connect(url, subscriber_token)
+ await publisher_room.connect(url, publisher_token)
+
+ source = rtc.AudioSource(SAMPLE_RATE, 1)
+ track = rtc.LocalAudioTrack.create_audio_track("test-audio", source)
+ options = rtc.TrackPublishOptions()
+ options.source = rtc.TrackSource.SOURCE_MICROPHONE
+ publication = await publisher_room.local_participant.publish_track(track, options)
+
+ assert publication is not None
+ assert publication.sid is not None
+
+ await asyncio.wait_for(track_published_event.wait(), timeout=5.0)
+ await asyncio.wait_for(track_subscribed_event.wait(), timeout=5.0)
+
+ assert subscribed_track is not None
+ assert isinstance(subscribed_track, rtc.RemoteAudioTrack)
+
+ finally:
+ await publisher_room.disconnect()
+ await subscriber_room.disconnect()
+
+
+@pytest.mark.asyncio
+@skip_if_no_credentials()
+async def test_audio_stream_subscribe():
+ """Test that published audio can be consumed and has similar energy levels"""
+ room_name = unique_room_name("test-audio-stream")
+ url = os.getenv("LIVEKIT_URL")
+
+ publisher_room = rtc.Room()
+ subscriber_room = rtc.Room()
+
+ publisher_token = create_token("audio-publisher", room_name)
+ subscriber_token = create_token("audio-subscriber", room_name)
+
+ track_subscribed_event = asyncio.Event()
+ subscribed_track = None
+
+ @subscriber_room.on("track_subscribed")
+ def on_track_subscribed(
+ track: rtc.Track,
+ publication: rtc.RemoteTrackPublication,
+ participant: rtc.RemoteParticipant,
+ ):
+ nonlocal subscribed_track
+ if track.kind == rtc.TrackKind.KIND_AUDIO:
+ subscribed_track = track
+ track_subscribed_event.set()
+
+ try:
+ await subscriber_room.connect(url, subscriber_token)
+ await publisher_room.connect(url, publisher_token)
+
+ source = rtc.AudioSource(SAMPLE_RATE, 1)
+ track = rtc.LocalAudioTrack.create_audio_track("sine-wave", source)
+ options = rtc.TrackPublishOptions()
+ options.source = rtc.TrackSource.SOURCE_MICROPHONE
+ await publisher_room.local_participant.publish_track(track, options)
+ target_duration = 5.0
+
+ published_energy = []
+
+ async def publish_audio():
+ async for frame in sine_wave_generator(440, target_duration, SAMPLE_RATE):
+ data = np.frombuffer(frame.data.tobytes(), dtype=np.int16)
+ energy = np.mean(np.abs(data.astype(np.float32)))
+ published_energy.append(energy)
+ await source.capture_frame(frame)
+
+ publish_task = asyncio.create_task(publish_audio())
+
+ await asyncio.wait_for(track_subscribed_event.wait(), timeout=5.0)
+ assert subscribed_track is not None
+
+ audio_stream = rtc.AudioStream(
+ subscribed_track,
+ sample_rate=SAMPLE_RATE,
+ num_channels=1,
+ )
+
+ received_frames = []
+ target_frames = int(target_duration * SAMPLE_RATE / 480)
+
+ frame_count = 0
+ async for event in audio_stream:
+ frame = event.frame
+ data = np.frombuffer(frame.data, dtype=np.int16)
+ received_frames.append(data)
+ frame_count += 1
+ if frame_count >= target_frames:
+ break
+
+ await audio_stream.aclose()
+ await publish_task
+
+ assert len(received_frames) > 0, "No audio frames were received"
+
+ received_energy = []
+ for data in received_frames:
+ energy = np.mean(np.abs(data.astype(np.float32)))
+ received_energy.append(energy)
+
+ avg_received_energy = np.mean(received_energy)
+ avg_published_energy = np.mean(published_energy)
+
+ assert avg_received_energy > 0, "Received audio has no energy"
+ assert avg_published_energy > 0, "Published audio has no energy"
+ assert (
+ avg_received_energy > avg_published_energy * 0.9
+ and avg_received_energy < avg_published_energy * 1.1
+ ), "Received audio energy is not within range"
+
+ finally:
+ await publisher_room.disconnect()
+ await subscriber_room.disconnect()
+
+
+@pytest.mark.asyncio
+@skip_if_no_credentials()
+async def test_room_lifecycle_events():
+ """Test that room lifecycle and track events are fired properly"""
+ room_name = unique_room_name("test-lifecycle-events")
+ url = os.getenv("LIVEKIT_URL")
+
+ room1 = rtc.Room()
+ room2 = rtc.Room()
+
+ token1 = create_token("participant-1", room_name)
+ token2 = create_token("participant-2", room_name)
+
+ events = {
+ "disconnected": [],
+ "participant_connected": [],
+ "participant_disconnected": [],
+ "local_track_published": [],
+ "local_track_unpublished": [],
+ "track_published": [],
+ "track_unpublished": [],
+ "track_subscribed": [],
+ "track_unsubscribed": [],
+ "room_updated": [],
+ "connection_state_changed": [],
+ }
+
+ @room1.on("disconnected")
+ def on_room1_disconnected(reason):
+ events["disconnected"].append("room1")
+
+ @room1.on("participant_connected")
+ def on_room1_participant_connected(participant: rtc.RemoteParticipant):
+ events["participant_connected"].append(f"room1-{participant.identity}")
+
+ @room1.on("participant_disconnected")
+ def on_room1_participant_disconnected(participant: rtc.RemoteParticipant):
+ events["participant_disconnected"].append(f"room1-{participant.identity}")
+
+ @room1.on("local_track_published")
+ def on_room1_local_track_published(publication: rtc.LocalTrackPublication, track):
+ events["local_track_published"].append(f"room1-{publication.sid}")
+
+ @room1.on("local_track_unpublished")
+ def on_room1_local_track_unpublished(publication: rtc.LocalTrackPublication):
+ events["local_track_unpublished"].append(f"room1-{publication.sid}")
+
+ @room1.on("room_updated")
+ def on_room1_room_updated():
+ events["room_updated"].append("room1")
+
+ @room1.on("connection_state_changed")
+ def on_room1_connection_state_changed(state: rtc.ConnectionState):
+ events["connection_state_changed"].append(f"room1-{state}")
+
+ @room2.on("track_published")
+ def on_room2_track_published(
+ publication: rtc.RemoteTrackPublication, participant: rtc.RemoteParticipant
+ ):
+ events["track_published"].append(f"room2-{publication.sid}")
+
+ @room2.on("track_subscribed")
+ def on_room2_track_subscribed(
+ track: rtc.Track,
+ publication: rtc.RemoteTrackPublication,
+ participant: rtc.RemoteParticipant,
+ ):
+ events["track_subscribed"].append(f"room2-{publication.sid}")
+
+ @room2.on("track_unpublished")
+ def on_room2_track_unpublished(
+ publication: rtc.RemoteTrackPublication, participant: rtc.RemoteParticipant
+ ):
+ events["track_unpublished"].append(f"room2-{publication.sid}")
+
+ try:
+ await room1.connect(url, token1)
+
+ await assert_eventually(
+ lambda: (
+ len(events["connection_state_changed"]) > 0
+ and events["connection_state_changed"][-1]
+ == f"room1-{rtc.ConnectionState.CONN_CONNECTED}"
+ ),
+ message="room1 connection_state_changed event not fired or did not reach CONN_CONNECTED state",
+ )
+
+ await room2.connect(url, token2)
+
+ await assert_eventually(
+ lambda: "room1-participant-2" in events["participant_connected"],
+ message="room1 did not receive participant_connected for participant-2",
+ )
+ await assert_eventually(
+ lambda: room2.remote_participants.get("participant-1") is not None,
+ message="room2 did not see participant-1",
+ )
+
+ source = rtc.AudioSource(SAMPLE_RATE, 1)
+ track = rtc.LocalAudioTrack.create_audio_track("test-track", source)
+ options = rtc.TrackPublishOptions()
+ options.source = rtc.TrackSource.SOURCE_MICROPHONE
+ publication = await room1.local_participant.publish_track(track, options)
+
+ await assert_eventually(
+ lambda: len(events["local_track_published"]) > 0,
+ message="local_track_published event not fired",
+ )
+ await assert_eventually(
+ lambda: any("room2" in e for e in events["track_published"]),
+ message="room2 did not receive track_published",
+ )
+ await assert_eventually(
+ lambda: len(events["track_subscribed"]) > 0, message="track_subscribed event not fired"
+ )
+
+ await room1.local_participant.unpublish_track(publication.sid)
+
+ await assert_eventually(
+ lambda: len(events["local_track_unpublished"]) > 0,
+ message="local_track_unpublished event not fired",
+ )
+ await assert_eventually(
+ lambda: len(events["track_unpublished"]) > 0,
+ message="track_unpublished event not fired",
+ )
+
+ await room2.disconnect()
+
+ await assert_eventually(
+ lambda: "room1-participant-2" in events["participant_disconnected"],
+ message="participant_disconnected not fired for participant-2",
+ )
+
+ await room1.disconnect()
+
+ await assert_eventually(
+ lambda: (
+ lambda: (
+ len(events["connection_state_changed"]) > 0
+ and events["connection_state_changed"][-1]
+ == f"room1-{rtc.ConnectionState.CONN_DISCONNECTED}"
+ )
+ ),
+ message="room1 disconnected event not fired",
+ )
+
+ print("\nEvent Summary:")
+ for event_type, event_list in events.items():
+ if event_list:
+ print(f" {event_type}: {len(event_list)} events")
+
+ finally:
+ if room1.isconnected():
+ await room1.disconnect()
+ if room2.isconnected():
+ await room2.disconnect()
+
+
+@pytest.mark.asyncio
+@skip_if_no_credentials()
+async def test_connection_state_transitions():
+ """Test that connection state transitions work correctly"""
+ room_name = unique_room_name("test-connection-state")
+ url = os.getenv("LIVEKIT_URL")
+
+ room = rtc.Room()
+ token = create_token("state-test", room_name)
+
+ states = []
+
+ @room.on("connection_state_changed")
+ def on_state_changed(state: rtc.ConnectionState):
+ states.append(state)
+
+ try:
+ assert room.connection_state == rtc.ConnectionState.CONN_DISCONNECTED
+
+ await room.connect(url, token)
+
+ await assert_eventually(
+ lambda: room.connection_state == rtc.ConnectionState.CONN_CONNECTED,
+ message="Room did not reach CONN_CONNECTED state",
+ )
+ await assert_eventually(
+ lambda: rtc.ConnectionState.CONN_CONNECTED in states,
+ message="CONN_CONNECTED state not in state change events",
+ )
+
+ await room.disconnect()
+
+ await assert_eventually(
+ lambda: room.connection_state == rtc.ConnectionState.CONN_DISCONNECTED,
+ message="Room did not reach CONN_DISCONNECTED state after disconnect",
+ )
+
+ finally:
+ if room.isconnected():
+ await room.disconnect()
+
+
+@pytest.mark.asyncio
+@skip_if_no_credentials()
+@pytest.mark.skipif(
+ os.getenv("RUN_DATA_TRACK_TESTS") != "1",
+ reason="SFU support requires data tracks support to be enabled via config; remove once this is no longer the case.",
+)
+async def test_data_track():
+ """Test that a published data track delivers frames with correct payloads and timestamps."""
+ FRAME_COUNT = 5
+ PAYLOAD_SIZE = 64
+
+ TRACK_NAME = "test-track"
+ PUBLISHER_IDENTITY = "dt-publisher"
+ SUBSCRIBER_IDENTITY = "dt-subscriber"
+
+ room_name = unique_room_name("test-data-track")
+ url = os.getenv("LIVEKIT_URL")
+
+ publisher_room = rtc.Room()
+ subscriber_room = rtc.Room()
+
+ publisher_token = create_token(PUBLISHER_IDENTITY, room_name)
+ subscriber_token = create_token(SUBSCRIBER_IDENTITY, room_name)
+
+ remote_track_event = asyncio.Event()
+ remote_track = None
+ unpublished_event = asyncio.Event()
+ unpublished_sid = None
+
+ @subscriber_room.on("data_track_published")
+ def on_data_track_published(track: rtc.RemoteDataTrack):
+ nonlocal remote_track
+ remote_track = track
+ remote_track_event.set()
+
+ @subscriber_room.on("data_track_unpublished")
+ def on_data_track_unpublished(sid: str):
+ nonlocal unpublished_sid
+ unpublished_sid = sid
+ unpublished_event.set()
+
+ try:
+ await subscriber_room.connect(url, subscriber_token)
+ await publisher_room.connect(url, publisher_token)
+
+ local_track = await publisher_room.local_participant.publish_data_track(name=TRACK_NAME)
+ assert local_track.info.sid is not None
+ assert local_track.info.name == TRACK_NAME
+ assert local_track.is_published()
+
+ await asyncio.wait_for(remote_track_event.wait(), timeout=10.0)
+ assert remote_track is not None
+ assert remote_track.info.name == TRACK_NAME
+ assert remote_track.publisher_identity == PUBLISHER_IDENTITY
+ assert remote_track.is_published()
+
+ stream = remote_track.subscribe()
+
+ async def push_frames():
+ for i in range(FRAME_COUNT):
+ frame = rtc.DataTrackFrame(
+ payload=bytes([i] * PAYLOAD_SIZE),
+ user_timestamp=int(time.time() * 1000),
+ )
+ local_track.try_push(frame)
+ await asyncio.sleep(0.1)
+ await local_track.unpublish()
+
+ async def publish_and_receive():
+ push_task = asyncio.create_task(push_frames())
+ recv_count = 0
+ async for frame in stream:
+ first_byte = frame.payload[0]
+ assert all(b == first_byte for b in frame.payload), "Payload bytes are not uniform"
+ assert len(frame.payload) == PAYLOAD_SIZE
+ assert frame.user_timestamp is not None
+ latency = (int(time.time() * 1000) - frame.user_timestamp) / 1000.0
+ assert latency < 5.0, f"Timestamp latency too high: {latency}"
+ recv_count += 1
+ await push_task
+ return recv_count
+
+ recv_count = await asyncio.wait_for(publish_and_receive(), timeout=10.0)
+ assert recv_count > 0, "No frames were received"
+
+ await asyncio.wait_for(unpublished_event.wait(), timeout=5.0)
+ assert unpublished_sid == local_track.info.sid
+
+ finally:
+ await publisher_room.disconnect()
+ await subscriber_room.disconnect()
diff --git a/tests/rtc/test_emitter.py b/tests/rtc/test_emitter.py
new file mode 100644
index 00000000..830feb3a
--- /dev/null
+++ b/tests/rtc/test_emitter.py
@@ -0,0 +1,104 @@
+from livekit.rtc import EventEmitter
+from typing import Literal
+import pytest
+
+
+def test_events():
+ EventTypes = Literal["connected", "reconnected", "disconnected"]
+ emitter = EventEmitter[EventTypes]()
+
+ connected_calls = []
+
+ @emitter.once("connected")
+ def on_connected():
+ connected_calls.append(True)
+
+ emitter.emit("connected")
+ emitter.emit("connected")
+ assert len(connected_calls) == 1
+
+ emitter.emit("unknown_event") # type: ignore
+
+ reconnected_calls = []
+
+ @emitter.on("reconnected")
+ def on_reconnected():
+ reconnected_calls.append(True)
+
+ emitter.emit("reconnected")
+ emitter.emit("reconnected")
+ assert len(reconnected_calls) == 2
+
+ disconnected_calls = []
+
+ @emitter.on("disconnected")
+ def on_disconnected():
+ disconnected_calls.append(True)
+
+ @emitter.on("disconnected")
+ def on_disconnected_another():
+ disconnected_calls.append(True)
+
+ emitter.emit("disconnected")
+ emitter.emit("disconnected")
+ emitter.off("disconnected", on_disconnected)
+ emitter.emit("disconnected")
+ assert len(disconnected_calls) == 5
+
+
+def test_args():
+ EventTypes = Literal["whatever"]
+
+ emitter = EventEmitter[EventTypes]()
+
+ calls = []
+
+ @emitter.on("whatever")
+ def on_whatever(first, second, third):
+ calls.append((first, second, third))
+
+ emitter.emit("whatever", 1, 2, 3)
+ emitter.emit("whatever", 1, 2, 3, 4, 5) # only 3 arguments will be passed
+
+ assert calls == [(1, 2, 3), (1, 2, 3)]
+
+ with pytest.raises(TypeError):
+ emitter.emit("whatever", 1, 2)
+
+
+def test_varargs():
+ EventTypes = Literal["whatever"]
+
+ emitter = EventEmitter[EventTypes]()
+
+ calls = []
+
+ @emitter.on("whatever")
+ def on_whatever_varargs(*args):
+ calls.append(args)
+
+ emitter.emit("whatever", 1, 2, 3, 4, 5)
+ emitter.emit("whatever", 1, 2)
+
+ assert calls == [(1, 2, 3, 4, 5), (1, 2)]
+
+
+def test_throw():
+ EventTypes = Literal["error"]
+
+ emitter = EventEmitter[EventTypes]()
+
+ calls = []
+
+ @emitter.on("error")
+ def on_error():
+ calls.append(True)
+ raise ValueError("error")
+
+ @emitter.on("error")
+ def on_error_another():
+ calls.append(True)
+
+ emitter.emit("error")
+
+ assert len(calls) == 2
diff --git a/tests/rtc/test_ffi_queue.py b/tests/rtc/test_ffi_queue.py
new file mode 100644
index 00000000..329018db
--- /dev/null
+++ b/tests/rtc/test_ffi_queue.py
@@ -0,0 +1,259 @@
+# Copyright 2023 LiveKit, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Tests for FfiQueue filter_fn functionality.
+
+These tests verify the filter_fn feature of FfiQueue.
+FfiQueue can be imported without loading the native FFI library.
+"""
+
+import asyncio
+from dataclasses import dataclass
+
+import pytest
+
+from livekit.rtc._ffi_client import FfiQueue
+
+
+@dataclass
+class MockFfiEvent:
+ """Mock FFI event with WhichOneof support."""
+
+ _message_type: str
+
+ def WhichOneof(self, field: str) -> str:
+ return self._message_type
+
+
+class TestFfiQueueFilterFn:
+ """Test suite for FfiQueue filter_fn functionality."""
+
+ @pytest.fixture
+ def event_loop(self):
+ """Create event loop for tests."""
+ loop = asyncio.new_event_loop()
+ yield loop
+ loop.close()
+
+ def test_subscribe_without_filter_receives_all_events(self, event_loop):
+ """Subscriber without filter_fn receives all events."""
+ queue = FfiQueue()
+ sub = queue.subscribe(event_loop, filter_fn=None)
+
+ events = [
+ MockFfiEvent("room_event"),
+ MockFfiEvent("audio_stream_event"),
+ MockFfiEvent("video_stream_event"),
+ MockFfiEvent("track_event"),
+ ]
+
+ for event in events:
+ queue.put(event)
+
+ event_loop.run_until_complete(asyncio.sleep(0.01))
+
+ received = []
+ while not sub.empty():
+ received.append(sub.get_nowait())
+
+ assert len(received) == 4
+
+ def test_subscribe_with_filter_receives_only_matching_events(self, event_loop):
+ """Subscriber with filter_fn only receives matching events."""
+ queue = FfiQueue()
+ sub = queue.subscribe(
+ event_loop,
+ filter_fn=lambda e: e.WhichOneof("message") == "audio_stream_event",
+ )
+
+ events = [
+ MockFfiEvent("room_event"),
+ MockFfiEvent("audio_stream_event"),
+ MockFfiEvent("video_stream_event"),
+ MockFfiEvent("audio_stream_event"),
+ MockFfiEvent("track_event"),
+ ]
+
+ for event in events:
+ queue.put(event)
+
+ event_loop.run_until_complete(asyncio.sleep(0.01))
+
+ received = []
+ while not sub.empty():
+ received.append(sub.get_nowait())
+
+ assert len(received) == 2
+ assert all(e._message_type == "audio_stream_event" for e in received)
+
+ def test_multiple_subscribers_different_filters(self, event_loop):
+ """Multiple subscribers can have different filters."""
+ queue = FfiQueue()
+
+ sub_audio = queue.subscribe(
+ event_loop,
+ filter_fn=lambda e: e.WhichOneof("message") == "audio_stream_event",
+ )
+ sub_video = queue.subscribe(
+ event_loop,
+ filter_fn=lambda e: e.WhichOneof("message") == "video_stream_event",
+ )
+ sub_all = queue.subscribe(event_loop, filter_fn=None)
+
+ events = [
+ MockFfiEvent("room_event"),
+ MockFfiEvent("audio_stream_event"),
+ MockFfiEvent("video_stream_event"),
+ MockFfiEvent("audio_stream_event"),
+ ]
+
+ for event in events:
+ queue.put(event)
+
+ event_loop.run_until_complete(asyncio.sleep(0.01))
+
+ audio_count = 0
+ while not sub_audio.empty():
+ sub_audio.get_nowait()
+ audio_count += 1
+
+ video_count = 0
+ while not sub_video.empty():
+ sub_video.get_nowait()
+ video_count += 1
+
+ all_count = 0
+ while not sub_all.empty():
+ sub_all.get_nowait()
+ all_count += 1
+
+ assert audio_count == 2
+ assert video_count == 1
+ assert all_count == 4
+
+ def test_filter_with_multiple_event_types(self, event_loop):
+ """Filter can match multiple event types."""
+ queue = FfiQueue()
+ sub = queue.subscribe(
+ event_loop,
+ filter_fn=lambda e: (
+ e.WhichOneof("message") in {"audio_stream_event", "video_stream_event"}
+ ),
+ )
+
+ events = [
+ MockFfiEvent("room_event"),
+ MockFfiEvent("audio_stream_event"),
+ MockFfiEvent("video_stream_event"),
+ MockFfiEvent("track_event"),
+ ]
+
+ for event in events:
+ queue.put(event)
+
+ event_loop.run_until_complete(asyncio.sleep(0.01))
+
+ received = []
+ while not sub.empty():
+ received.append(sub.get_nowait())
+
+ assert len(received) == 2
+ types = {e._message_type for e in received}
+ assert types == {"audio_stream_event", "video_stream_event"}
+
+ def test_unsubscribe_works_with_filtered_subscriber(self, event_loop):
+ """Unsubscribe correctly removes filtered subscriber."""
+ queue = FfiQueue()
+ sub = queue.subscribe(
+ event_loop,
+ filter_fn=lambda e: e.WhichOneof("message") == "audio_stream_event",
+ )
+
+ queue.put(MockFfiEvent("audio_stream_event"))
+ event_loop.run_until_complete(asyncio.sleep(0.01))
+
+ assert not sub.empty()
+
+ queue.unsubscribe(sub)
+
+ while not sub.empty():
+ sub.get_nowait()
+
+ queue.put(MockFfiEvent("audio_stream_event"))
+ event_loop.run_until_complete(asyncio.sleep(0.01))
+
+ assert sub.empty()
+
+ def test_filter_error_delivers_item(self, event_loop):
+ """If filter_fn raises, item is still delivered."""
+ queue = FfiQueue()
+
+ def bad_filter(e):
+ raise ValueError("oops")
+
+ sub = queue.subscribe(event_loop, filter_fn=bad_filter)
+
+ queue.put(MockFfiEvent("audio_stream_event"))
+ event_loop.run_until_complete(asyncio.sleep(0.01))
+
+ # Item should be delivered despite filter error
+ received = []
+ while not sub.empty():
+ received.append(sub.get_nowait())
+
+ assert len(received) == 1
+
+
+class TestFfiQueueMemoryReduction:
+ """Test that filtering actually reduces object creation."""
+
+ @pytest.fixture
+ def event_loop(self):
+ loop = asyncio.new_event_loop()
+ yield loop
+ loop.close()
+
+ def test_filtering_reduces_callback_calls(self, event_loop):
+ """Verify filtering prevents call_soon_threadsafe for non-matching events."""
+ queue = FfiQueue()
+
+ # Create 10 subscribers, each only wants audio events
+ subscribers = []
+ for _ in range(10):
+ sub = queue.subscribe(
+ event_loop,
+ filter_fn=lambda e: e.WhichOneof("message") == "audio_stream_event",
+ )
+ subscribers.append(sub)
+
+ # Generate 1000 events, only 5% are audio
+ events = []
+ for i in range(1000):
+ if i < 50:
+ events.append(MockFfiEvent("audio_stream_event"))
+ else:
+ events.append(MockFfiEvent("room_event"))
+
+ for event in events:
+ queue.put(event)
+
+ event_loop.run_until_complete(asyncio.sleep(0.1))
+
+ # Each subscriber should have received only 50 events (not 1000)
+ for sub in subscribers:
+ count = 0
+ while not sub.empty():
+ sub.get_nowait()
+ count += 1
+ assert count == 50
diff --git a/tests/rtc/test_import.py b/tests/rtc/test_import.py
new file mode 100644
index 00000000..f6934f19
--- /dev/null
+++ b/tests/rtc/test_import.py
@@ -0,0 +1,9 @@
+"""Smoke test: import the SDK and initialize the FFI library."""
+
+
+def test_import_and_ffi_initialize():
+ from livekit import rtc # noqa: F401
+ from livekit.rtc._ffi_client import FfiClient
+
+ # accessing .instance triggers livekit_ffi_initialize
+ assert FfiClient.instance is not None
diff --git a/tests/rtc/test_mixer.py b/tests/rtc/test_mixer.py
new file mode 100644
index 00000000..1ab75f4b
--- /dev/null
+++ b/tests/rtc/test_mixer.py
@@ -0,0 +1,58 @@
+# type: ignore
+
+import numpy as np
+import pytest
+
+from livekit.rtc import AudioMixer
+from livekit.rtc.utils import sine_wave_generator
+
+SAMPLE_RATE = 48000
+BLOCKSIZE = SAMPLE_RATE // 10
+
+
+@pytest.mark.asyncio
+async def test_mixer_two_sine_waves():
+ """
+ Test that mixing two sine waves (440Hz and 880Hz) produces an output
+ containing both frequency components.
+ """
+ duration = 1.0
+ mixer = AudioMixer(
+ sample_rate=SAMPLE_RATE,
+ num_channels=1,
+ blocksize=BLOCKSIZE,
+ stream_timeout_ms=100,
+ capacity=100,
+ )
+ stream1 = sine_wave_generator(440, duration, SAMPLE_RATE)
+ stream2 = sine_wave_generator(880, duration, SAMPLE_RATE)
+ mixer.add_stream(stream1)
+ mixer.add_stream(stream2)
+ mixer.end_input()
+
+ mixed_signals = []
+ async for frame in mixer:
+ data = np.frombuffer(frame.data.tobytes(), dtype=np.int16)
+ mixed_signals.append(data)
+
+ await mixer.aclose()
+
+ if not mixed_signals:
+ pytest.fail("No frames were produced by the mixer.")
+
+ mixed_signal = np.concatenate(mixed_signals)
+
+ # Use FFT to analyze frequency components.
+ fft = np.fft.rfft(mixed_signal)
+ freqs = np.fft.rfftfreq(len(mixed_signal), 1 / SAMPLE_RATE)
+ magnitude = np.abs(fft)
+
+ # Identify peak frequencies. We'll pick the 5 highest peaks.
+ peak_indices = np.argsort(magnitude)[-5:]
+ peak_freqs = freqs[peak_indices]
+
+ print("Peak frequencies:", peak_freqs)
+
+ # Assert that the peaks include 440Hz and 880Hz (with a tolerance of ±5 Hz)
+ assert any(np.isclose(peak_freqs, 440, atol=5)), f"Expected 440 Hz in peaks, got: {peak_freqs}"
+ assert any(np.isclose(peak_freqs, 880, atol=5)), f"Expected 880 Hz in peaks, got: {peak_freqs}"
diff --git a/tests/rtc/test_resampler.py b/tests/rtc/test_resampler.py
new file mode 100644
index 00000000..25079da8
--- /dev/null
+++ b/tests/rtc/test_resampler.py
@@ -0,0 +1,66 @@
+from livekit.rtc import AudioResampler, AudioResamplerQuality
+import time
+import wave
+import os
+
+# Test fixture directory
+FIXTURES_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "fixtures")
+
+
+def test_audio_resampler():
+ wav_file_path = os.path.join(FIXTURES_DIR, "test_audio.wav")
+
+ # Open the wave file
+ with wave.open(wav_file_path, "rb") as wf_in:
+ n_channels = wf_in.getnchannels()
+ sampwidth = wf_in.getsampwidth()
+ n_frames = wf_in.getnframes()
+ audio_data = bytearray(wf_in.readframes(n_frames))
+
+ if sampwidth != 2:
+ raise ValueError(f"Expected 16-bit PCM data, but got {sampwidth * 8}-bit.")
+
+ qualities = [
+ AudioResamplerQuality.QUICK,
+ AudioResamplerQuality.LOW,
+ AudioResamplerQuality.MEDIUM,
+ AudioResamplerQuality.HIGH,
+ AudioResamplerQuality.VERY_HIGH,
+ ]
+
+ for quality in qualities:
+ total_time = 0
+ nb_runs = 20
+ output_frames = []
+ for i in range(nb_runs):
+ output_frames = []
+ resampler = AudioResampler(44100, 8000, quality=quality)
+
+ start_time = time.perf_counter()
+
+ chunk_size = 1024 * n_channels * sampwidth
+ output_frames = []
+ for i in range(0, len(audio_data), chunk_size):
+ chunk = audio_data[i : i + chunk_size]
+ frames = resampler.push(bytearray(chunk))
+ output_frames.extend(frames)
+
+ frames = resampler.flush()
+ output_frames.extend(frames)
+
+ end_time = time.perf_counter()
+ total_time += end_time - start_time
+
+ total_time = total_time * 1000
+ print(f"Quality: {quality}, Average time: {total_time / nb_runs:.2f}ms")
+
+ output_data = b""
+
+ for frame in output_frames:
+ output_data += frame.data
+
+ with wave.open(f"audio_resampled_{quality.name}.wav", "wb") as wf_out:
+ wf_out.setnchannels(n_channels)
+ wf_out.setsampwidth(sampwidth)
+ wf_out.setframerate(8000)
+ wf_out.writeframes(output_data)
diff --git a/uv.lock b/uv.lock
new file mode 100644
index 00000000..edd7c251
--- /dev/null
+++ b/uv.lock
@@ -0,0 +1,3769 @@
+version = 1
+revision = 3
+requires-python = ">=3.9"
+resolution-markers = [
+ "python_full_version >= '3.11'",
+ "python_full_version == '3.10.*'",
+ "python_full_version < '3.10'",
+]
+
+[manifest]
+members = [
+ "livekit",
+ "livekit-api",
+ "livekit-protocol",
+ "python-sdks",
+]
+
+[[package]]
+name = "aiofiles"
+version = "25.1.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/41/c3/534eac40372d8ee36ef40df62ec129bee4fdb5ad9706e58a29be53b2c970/aiofiles-25.1.0.tar.gz", hash = "sha256:a8d728f0a29de45dc521f18f07297428d56992a742f0cd2701ba86e44d23d5b2", size = 46354, upload-time = "2025-10-09T20:51:04.358Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl", hash = "sha256:abe311e527c862958650f9438e859c1fa7568a141b22abcd015e120e86a85695", size = 14668, upload-time = "2025-10-09T20:51:03.174Z" },
+]
+
+[[package]]
+name = "aiohappyeyeballs"
+version = "2.6.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" },
+]
+
+[[package]]
+name = "aiohttp"
+version = "3.13.5"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "aiohappyeyeballs" },
+ { name = "aiosignal" },
+ { name = "async-timeout", marker = "python_full_version < '3.11'" },
+ { name = "attrs" },
+ { name = "frozenlist" },
+ { name = "multidict" },
+ { name = "propcache" },
+ { name = "yarl" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/77/9a/152096d4808df8e4268befa55fba462f440f14beab85e8ad9bf990516918/aiohttp-3.13.5.tar.gz", hash = "sha256:9d98cc980ecc96be6eb4c1994ce35d28d8b1f5e5208a23b421187d1209dbb7d1", size = 7858271, upload-time = "2026-03-31T22:01:03.343Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/bd/85/cebc47ee74d8b408749073a1a46c6fcba13d170dc8af7e61996c6c9394ac/aiohttp-3.13.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:02222e7e233295f40e011c1b00e3b0bd451f22cf853a0304c3595633ee47da4b", size = 750547, upload-time = "2026-03-31T21:56:30.024Z" },
+ { url = "https://files.pythonhosted.org/packages/05/98/afd308e35b9d3d8c9ec54c0918f1d722c86dc17ddfec272fcdbcce5a3124/aiohttp-3.13.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bace460460ed20614fa6bc8cb09966c0b8517b8c58ad8046828c6078d25333b5", size = 503535, upload-time = "2026-03-31T21:56:31.935Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/4d/926c183e06b09d5270a309eb50fbde7b09782bfd305dec1e800f329834fb/aiohttp-3.13.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f546a4dc1e6a5edbb9fd1fd6ad18134550e096a5a43f4ad74acfbd834fc6670", size = 497830, upload-time = "2026-03-31T21:56:33.654Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/d6/f47d1c690f115a5c2a5e8938cce4a232a5be9aac5c5fb2647efcbbbda333/aiohttp-3.13.5-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c86969d012e51b8e415a8c6ce96f7857d6a87d6207303ab02d5d11ef0cad2274", size = 1682474, upload-time = "2026-03-31T21:56:35.513Z" },
+ { url = "https://files.pythonhosted.org/packages/01/44/056fd37b1bb52eac760303e5196acc74d9d546631b035704ae5927f7b4ac/aiohttp-3.13.5-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b6f6cd1560c5fa427e3b6074bb24d2c64e225afbb7165008903bd42e4e33e28a", size = 1655259, upload-time = "2026-03-31T21:56:37.843Z" },
+ { url = "https://files.pythonhosted.org/packages/91/9f/78eb1a20c1c28ae02f6a3c0f4d7b0dcc66abce5290cadd53d78ce3084175/aiohttp-3.13.5-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:636bc362f0c5bbc7372bc3ae49737f9e3030dbce469f0f422c8f38079780363d", size = 1736204, upload-time = "2026-03-31T21:56:39.822Z" },
+ { url = "https://files.pythonhosted.org/packages/de/6c/d20d7de23f0b52b8c1d9e2033b2db1ac4dacbb470bb74c56de0f5f86bb4f/aiohttp-3.13.5-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6a7cbeb06d1070f1d14895eeeed4dac5913b22d7b456f2eb969f11f4b3993796", size = 1826198, upload-time = "2026-03-31T21:56:41.378Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/86/a6f3ff1fd795f49545a7c74b2c92f62729135d73e7e4055bf74da5a26c82/aiohttp-3.13.5-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bca9ef7517fd7874a1a08970ae88f497bf5c984610caa0bf40bd7e8450852b95", size = 1681329, upload-time = "2026-03-31T21:56:43.374Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/68/84cd3dab6b7b4f3e6fe9459a961acb142aaab846417f6e8905110d7027e5/aiohttp-3.13.5-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:019a67772e034a0e6b9b17c13d0a8fe56ad9fb150fc724b7f3ffd3724288d9e5", size = 1560023, upload-time = "2026-03-31T21:56:45.031Z" },
+ { url = "https://files.pythonhosted.org/packages/41/2c/db61b64b0249e30f954a65ab4cb4970ced57544b1de2e3c98ee5dc24165f/aiohttp-3.13.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f34ecee82858e41dd217734f0c41a532bd066bcaab636ad830f03a30b2a96f2a", size = 1652372, upload-time = "2026-03-31T21:56:47.075Z" },
+ { url = "https://files.pythonhosted.org/packages/25/6f/e96988a6c982d047810c772e28c43c64c300c943b0ed5c1c0c4ce1e1027c/aiohttp-3.13.5-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:4eac02d9af4813ee289cd63a361576da36dba57f5a1ab36377bc2600db0cbb73", size = 1662031, upload-time = "2026-03-31T21:56:48.835Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/26/a56feace81f3d347b4052403a9d03754a0ab23f7940780dada0849a38c92/aiohttp-3.13.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4beac52e9fe46d6abf98b0176a88154b742e878fdf209d2248e99fcdf73cd297", size = 1708118, upload-time = "2026-03-31T21:56:50.833Z" },
+ { url = "https://files.pythonhosted.org/packages/78/6e/b6173a8ff03d01d5e1a694bc06764b5dad1df2d4ed8f0ceec12bb3277936/aiohttp-3.13.5-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:c180f480207a9b2475f2b8d8bd7204e47aec952d084b2a2be58a782ffcf96074", size = 1548667, upload-time = "2026-03-31T21:56:52.81Z" },
+ { url = "https://files.pythonhosted.org/packages/16/13/13296ffe2c132d888b3fe2c195c8b9c0c24c89c3fa5cc2c44464dc23b22e/aiohttp-3.13.5-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2837fb92951564d6339cedae4a7231692aa9f73cbc4fb2e04263b96844e03b4e", size = 1724490, upload-time = "2026-03-31T21:56:54.541Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/b4/1f1c287f4a79782ef36e5a6e62954c85343bc30470d862d30bd5f26c9fa2/aiohttp-3.13.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d9010032a0b9710f58012a1e9c222528763d860ba2ee1422c03473eab47703e7", size = 1667109, upload-time = "2026-03-31T21:56:56.21Z" },
+ { url = "https://files.pythonhosted.org/packages/ef/42/8461a2aaf60a8f4ea4549a4056be36b904b0eb03d97ca9a8a2604681a500/aiohttp-3.13.5-cp310-cp310-win32.whl", hash = "sha256:7c4b6668b2b2b9027f209ddf647f2a4407784b5d88b8be4efcc72036f365baf9", size = 439478, upload-time = "2026-03-31T21:56:58.292Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/71/06956304cb5ee439dfe8d86e1b2e70088bd88ed1ced1f42fb29e5d855f0e/aiohttp-3.13.5-cp310-cp310-win_amd64.whl", hash = "sha256:cd3db5927bf9167d5a6157ddb2f036f6b6b0ad001ac82355d43e97a4bde76d76", size = 462047, upload-time = "2026-03-31T21:57:00.257Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/f5/a20c4ac64aeaef1679e25c9983573618ff765d7aa829fa2b84ae7573169e/aiohttp-3.13.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ab7229b6f9b5c1ba4910d6c41a9eb11f543eadb3f384df1b4c293f4e73d44d6", size = 757513, upload-time = "2026-03-31T21:57:02.146Z" },
+ { url = "https://files.pythonhosted.org/packages/75/0a/39fa6c6b179b53fcb3e4b3d2b6d6cad0180854eda17060c7218540102bef/aiohttp-3.13.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8f14c50708bb156b3a3ca7230b3d820199d56a48e3af76fa21c2d6087190fe3d", size = 506748, upload-time = "2026-03-31T21:57:04.275Z" },
+ { url = "https://files.pythonhosted.org/packages/87/ec/e38ce072e724fd7add6243613f8d1810da084f54175353d25ccf9f9c7e5a/aiohttp-3.13.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e7d2f8616f0ff60bd332022279011776c3ac0faa0f1b463f7bb12326fbc97a1c", size = 501673, upload-time = "2026-03-31T21:57:06.208Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/ba/3bc7525d7e2beaa11b309a70d48b0d3cfc3c2089ec6a7d0820d59c657053/aiohttp-3.13.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2567b72e1ffc3ab25510db43f355b29eeada56c0a622e58dcdb19530eb0a3cb", size = 1763757, upload-time = "2026-03-31T21:57:07.882Z" },
+ { url = "https://files.pythonhosted.org/packages/5e/ab/e87744cf18f1bd78263aba24924d4953b41086bd3a31d22452378e9028a0/aiohttp-3.13.5-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fb0540c854ac9c0c5ad495908fdfd3e332d553ec731698c0e29b1877ba0d2ec6", size = 1720152, upload-time = "2026-03-31T21:57:09.946Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/f3/ed17a6f2d742af17b50bae2d152315ed1b164b07a5fd5cc1754d99e4dfa5/aiohttp-3.13.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c9883051c6972f58bfc4ebb2116345ee2aa151178e99c3f2b2bbe2af712abd13", size = 1818010, upload-time = "2026-03-31T21:57:12.157Z" },
+ { url = "https://files.pythonhosted.org/packages/53/06/ecbc63dc937192e2a5cb46df4d3edb21deb8225535818802f210a6ea5816/aiohttp-3.13.5-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2294172ce08a82fb7c7273485895de1fa1186cc8294cfeb6aef4af42ad261174", size = 1907251, upload-time = "2026-03-31T21:57:14.023Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/a5/0521aa32c1ddf3aa1e71dcc466be0b7db2771907a13f18cddaa45967d97b/aiohttp-3.13.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3a807cabd5115fb55af198b98178997a5e0e57dead43eb74a93d9c07d6d4a7dc", size = 1759969, upload-time = "2026-03-31T21:57:16.146Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/78/a38f8c9105199dd3b9706745865a8a59d0041b6be0ca0cc4b2ccf1bab374/aiohttp-3.13.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:aa6d0d932e0f39c02b80744273cd5c388a2d9bc07760a03164f229c8e02662f6", size = 1616871, upload-time = "2026-03-31T21:57:17.856Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/41/27392a61ead8ab38072105c71aa44ff891e71653fe53d576a7067da2b4e8/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:60869c7ac4aaabe7110f26499f3e6e5696eae98144735b12a9c3d9eae2b51a49", size = 1739844, upload-time = "2026-03-31T21:57:19.679Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/55/5564e7ae26d94f3214250009a0b1c65a0c6af4bf88924ccb6fdab901de28/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:26d2f8546f1dfa75efa50c3488215a903c0168d253b75fba4210f57ab77a0fb8", size = 1731969, upload-time = "2026-03-31T21:57:22.006Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/c5/705a3929149865fc941bcbdd1047b238e4a72bcb215a9b16b9d7a2e8d992/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1162a1492032c82f14271e831c8f4b49f2b6078f4f5fc74de2c912fa225d51d", size = 1795193, upload-time = "2026-03-31T21:57:24.256Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/19/edabed62f718d02cff7231ca0db4ef1c72504235bc467f7b67adb1679f48/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:8b14eb3262fad0dc2f89c1a43b13727e709504972186ff6a99a3ecaa77102b6c", size = 1606477, upload-time = "2026-03-31T21:57:26.364Z" },
+ { url = "https://files.pythonhosted.org/packages/de/fc/76f80ef008675637d88d0b21584596dc27410a990b0918cb1e5776545b5b/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:ca9ac61ac6db4eb6c2a0cd1d0f7e1357647b638ccc92f7e9d8d133e71ed3c6ac", size = 1813198, upload-time = "2026-03-31T21:57:28.316Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/67/5b3ac26b80adb20ea541c487f73730dc8fa107d632c998f25bbbab98fcda/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7996023b2ed59489ae4762256c8516df9820f751cf2c5da8ed2fb20ee50abab3", size = 1752321, upload-time = "2026-03-31T21:57:30.549Z" },
+ { url = "https://files.pythonhosted.org/packages/88/06/e4a2e49255ea23fa4feeb5ab092d90240d927c15e47b5b5c48dff5a9ce29/aiohttp-3.13.5-cp311-cp311-win32.whl", hash = "sha256:77dfa48c9f8013271011e51c00f8ada19851f013cde2c48fca1ba5e0caf5bb06", size = 439069, upload-time = "2026-03-31T21:57:32.388Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/43/8c7163a596dab4f8be12c190cf467a1e07e4734cf90eebb39f7f5d53fc6a/aiohttp-3.13.5-cp311-cp311-win_amd64.whl", hash = "sha256:d3a4834f221061624b8887090637db9ad4f61752001eae37d56c52fddade2dc8", size = 462859, upload-time = "2026-03-31T21:57:34.455Z" },
+ { url = "https://files.pythonhosted.org/packages/be/6f/353954c29e7dcce7cf00280a02c75f30e133c00793c7a2ed3776d7b2f426/aiohttp-3.13.5-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:023ecba036ddd840b0b19bf195bfae970083fd7024ce1ac22e9bba90464620e9", size = 748876, upload-time = "2026-03-31T21:57:36.319Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/1b/428a7c64687b3b2e9cd293186695affc0e1e54a445d0361743b231f11066/aiohttp-3.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:15c933ad7920b7d9a20de151efcd05a6e38302cbf0e10c9b2acb9a42210a2416", size = 499557, upload-time = "2026-03-31T21:57:38.236Z" },
+ { url = "https://files.pythonhosted.org/packages/29/47/7be41556bfbb6917069d6a6634bb7dd5e163ba445b783a90d40f5ac7e3a7/aiohttp-3.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ab2899f9fa2f9f741896ebb6fa07c4c883bfa5c7f2ddd8cf2aafa86fa981b2d2", size = 500258, upload-time = "2026-03-31T21:57:39.923Z" },
+ { url = "https://files.pythonhosted.org/packages/67/84/c9ecc5828cb0b3695856c07c0a6817a99d51e2473400f705275a2b3d9239/aiohttp-3.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a60eaa2d440cd4707696b52e40ed3e2b0f73f65be07fd0ef23b6b539c9c0b0b4", size = 1749199, upload-time = "2026-03-31T21:57:41.938Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/d3/3c6d610e66b495657622edb6ae7c7fd31b2e9086b4ec50b47897ad6042a9/aiohttp-3.13.5-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:55b3bdd3292283295774ab585160c4004f4f2f203946997f49aac032c84649e9", size = 1721013, upload-time = "2026-03-31T21:57:43.904Z" },
+ { url = "https://files.pythonhosted.org/packages/49/a0/24409c12217456df0bae7babe3b014e460b0b38a8e60753d6cb339f6556d/aiohttp-3.13.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c2b2355dc094e5f7d45a7bb262fe7207aa0460b37a0d87027dcf21b5d890e7d5", size = 1781501, upload-time = "2026-03-31T21:57:46.285Z" },
+ { url = "https://files.pythonhosted.org/packages/98/9d/b65ec649adc5bccc008b0957a9a9c691070aeac4e41cea18559fef49958b/aiohttp-3.13.5-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b38765950832f7d728297689ad78f5f2cf79ff82487131c4d26fe6ceecdc5f8e", size = 1878981, upload-time = "2026-03-31T21:57:48.734Z" },
+ { url = "https://files.pythonhosted.org/packages/57/d8/8d44036d7eb7b6a8ec4c5494ea0c8c8b94fbc0ed3991c1a7adf230df03bf/aiohttp-3.13.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b18f31b80d5a33661e08c89e202edabf1986e9b49c42b4504371daeaa11b47c1", size = 1767934, upload-time = "2026-03-31T21:57:51.171Z" },
+ { url = "https://files.pythonhosted.org/packages/31/04/d3f8211f273356f158e3464e9e45484d3fb8c4ce5eb2f6fe9405c3273983/aiohttp-3.13.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:33add2463dde55c4f2d9635c6ab33ce154e5ecf322bd26d09af95c5f81cfa286", size = 1566671, upload-time = "2026-03-31T21:57:53.326Z" },
+ { url = "https://files.pythonhosted.org/packages/41/db/073e4ebe00b78e2dfcacff734291651729a62953b48933d765dc513bf798/aiohttp-3.13.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:327cc432fdf1356fb4fbc6fe833ad4e9f6aacb71a8acaa5f1855e4b25910e4a9", size = 1705219, upload-time = "2026-03-31T21:57:55.385Z" },
+ { url = "https://files.pythonhosted.org/packages/48/45/7dfba71a2f9fd97b15c95c06819de7eb38113d2cdb6319669195a7d64270/aiohttp-3.13.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:7c35b0bf0b48a70b4cb4fc5d7bed9b932532728e124874355de1a0af8ec4bc88", size = 1743049, upload-time = "2026-03-31T21:57:57.341Z" },
+ { url = "https://files.pythonhosted.org/packages/18/71/901db0061e0f717d226386a7f471bb59b19566f2cae5f0d93874b017271f/aiohttp-3.13.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:df23d57718f24badef8656c49743e11a89fd6f5358fa8a7b96e728fda2abf7d3", size = 1749557, upload-time = "2026-03-31T21:57:59.626Z" },
+ { url = "https://files.pythonhosted.org/packages/08/d5/41eebd16066e59cd43728fe74bce953d7402f2b4ddfdfef2c0e9f17ca274/aiohttp-3.13.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:02e048037a6501a5ec1f6fc9736135aec6eb8a004ce48838cb951c515f32c80b", size = 1558931, upload-time = "2026-03-31T21:58:01.972Z" },
+ { url = "https://files.pythonhosted.org/packages/30/e6/4a799798bf05740e66c3a1161079bda7a3dd8e22ca392481d7a7f9af82a6/aiohttp-3.13.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:31cebae8b26f8a615d2b546fee45d5ffb76852ae6450e2a03f42c9102260d6fe", size = 1774125, upload-time = "2026-03-31T21:58:04.007Z" },
+ { url = "https://files.pythonhosted.org/packages/84/63/7749337c90f92bc2cb18f9560d67aa6258c7060d1397d21529b8004fcf6f/aiohttp-3.13.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:888e78eb5ca55a615d285c3c09a7a91b42e9dd6fc699b166ebd5dee87c9ccf14", size = 1732427, upload-time = "2026-03-31T21:58:06.337Z" },
+ { url = "https://files.pythonhosted.org/packages/98/de/cf2f44ff98d307e72fb97d5f5bbae3bfcb442f0ea9790c0bf5c5c2331404/aiohttp-3.13.5-cp312-cp312-win32.whl", hash = "sha256:8bd3ec6376e68a41f9f95f5ed170e2fcf22d4eb27a1f8cb361d0508f6e0557f3", size = 433534, upload-time = "2026-03-31T21:58:08.712Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/ca/eadf6f9c8fa5e31d40993e3db153fb5ed0b11008ad5d9de98a95045bed84/aiohttp-3.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:110e448e02c729bcebb18c60b9214a87ba33bac4a9fa5e9a5f139938b56c6cb1", size = 460446, upload-time = "2026-03-31T21:58:10.945Z" },
+ { url = "https://files.pythonhosted.org/packages/78/e9/d76bf503005709e390122d34e15256b88f7008e246c4bdbe915cd4f1adce/aiohttp-3.13.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5029cc80718bbd545123cd8fe5d15025eccaaaace5d0eeec6bd556ad6163d61", size = 742930, upload-time = "2026-03-31T21:58:13.155Z" },
+ { url = "https://files.pythonhosted.org/packages/57/00/4b7b70223deaebd9bb85984d01a764b0d7bd6526fcdc73cca83bcbe7243e/aiohttp-3.13.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4bb6bf5811620003614076bdc807ef3b5e38244f9d25ca5fe888eaccea2a9832", size = 496927, upload-time = "2026-03-31T21:58:15.073Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/f5/0fb20fb49f8efdcdce6cd8127604ad2c503e754a8f139f5e02b01626523f/aiohttp-3.13.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a84792f8631bf5a94e52d9cc881c0b824ab42717165a5579c760b830d9392ac9", size = 497141, upload-time = "2026-03-31T21:58:17.009Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/86/b7c870053e36a94e8951b803cb5b909bfbc9b90ca941527f5fcafbf6b0fa/aiohttp-3.13.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:57653eac22c6a4c13eb22ecf4d673d64a12f266e72785ab1c8b8e5940d0e8090", size = 1732476, upload-time = "2026-03-31T21:58:18.925Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/e5/4e161f84f98d80c03a238671b4136e6530453d65262867d989bbe78244d0/aiohttp-3.13.5-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5e5f7debc7a57af53fdf5c5009f9391d9f4c12867049d509bf7bb164a6e295b", size = 1706507, upload-time = "2026-03-31T21:58:21.094Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/56/ea11a9f01518bd5a2a2fcee869d248c4b8a0cfa0bb13401574fa31adf4d4/aiohttp-3.13.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c719f65bebcdf6716f10e9eff80d27567f7892d8988c06de12bbbd39307c6e3a", size = 1773465, upload-time = "2026-03-31T21:58:23.159Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/40/333ca27fb74b0383f17c90570c748f7582501507307350a79d9f9f3c6eb1/aiohttp-3.13.5-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d97f93fdae594d886c5a866636397e2bcab146fd7a132fd6bb9ce182224452f8", size = 1873523, upload-time = "2026-03-31T21:58:25.59Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/d2/e2f77eef1acb7111405433c707dc735e63f67a56e176e72e9e7a2cd3f493/aiohttp-3.13.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3df334e39d4c2f899a914f1dba283c1aadc311790733f705182998c6f7cae665", size = 1754113, upload-time = "2026-03-31T21:58:27.624Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/56/3f653d7f53c89669301ec9e42c95233e2a0c0a6dd051269e6e678db4fdb0/aiohttp-3.13.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fe6970addfea9e5e081401bcbadf865d2b6da045472f58af08427e108d618540", size = 1562351, upload-time = "2026-03-31T21:58:29.918Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/a6/9b3e91eb8ae791cce4ee736da02211c85c6f835f1bdfac0594a8a3b7018c/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7becdf835feff2f4f335d7477f121af787e3504b48b449ff737afb35869ba7bb", size = 1693205, upload-time = "2026-03-31T21:58:32.214Z" },
+ { url = "https://files.pythonhosted.org/packages/98/fc/bfb437a99a2fcebd6b6eaec609571954de2ed424f01c352f4b5504371dd3/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:676e5651705ad5d8a70aeb8eb6936c436d8ebbd56e63436cb7dd9bb36d2a9a46", size = 1730618, upload-time = "2026-03-31T21:58:34.728Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/b6/c8534862126191a034f68153194c389addc285a0f1347d85096d349bbc15/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:9b16c653d38eb1a611cc898c41e76859ca27f119d25b53c12875fd0474ae31a8", size = 1745185, upload-time = "2026-03-31T21:58:36.909Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/93/4ca8ee2ef5236e2707e0fd5fecb10ce214aee1ff4ab307af9c558bda3b37/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:999802d5fa0389f58decd24b537c54aa63c01c3219ce17d1214cbda3c2b22d2d", size = 1557311, upload-time = "2026-03-31T21:58:39.38Z" },
+ { url = "https://files.pythonhosted.org/packages/57/ae/76177b15f18c5f5d094f19901d284025db28eccc5ae374d1d254181d33f4/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:ec707059ee75732b1ba130ed5f9580fe10ff75180c812bc267ded039db5128c6", size = 1773147, upload-time = "2026-03-31T21:58:41.476Z" },
+ { url = "https://files.pythonhosted.org/packages/01/a4/62f05a0a98d88af59d93b7fcac564e5f18f513cb7471696ac286db970d6a/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2d6d44a5b48132053c2f6cd5c8cb14bc67e99a63594e336b0f2af81e94d5530c", size = 1730356, upload-time = "2026-03-31T21:58:44.049Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/85/fc8601f59dfa8c9523808281f2da571f8b4699685f9809a228adcc90838d/aiohttp-3.13.5-cp313-cp313-win32.whl", hash = "sha256:329f292ed14d38a6c4c435e465f48bebb47479fd676a0411936cc371643225cc", size = 432637, upload-time = "2026-03-31T21:58:46.167Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/1b/ac685a8882896acf0f6b31d689e3792199cfe7aba37969fa91da63a7fa27/aiohttp-3.13.5-cp313-cp313-win_amd64.whl", hash = "sha256:69f571de7500e0557801c0b51f4780482c0ec5fe2ac851af5a92cfce1af1cb83", size = 458896, upload-time = "2026-03-31T21:58:48.119Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/ce/46572759afc859e867a5bc8ec3487315869013f59281ce61764f76d879de/aiohttp-3.13.5-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:eb4639f32fd4a9904ab8fb45bf3383ba71137f3d9d4ba25b3b3f3109977c5b8c", size = 745721, upload-time = "2026-03-31T21:58:50.229Z" },
+ { url = "https://files.pythonhosted.org/packages/13/fe/8a2efd7626dbe6049b2ef8ace18ffda8a4dfcbe1bcff3ac30c0c7575c20b/aiohttp-3.13.5-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:7e5dc4311bd5ac493886c63cbf76ab579dbe4641268e7c74e48e774c74b6f2be", size = 497663, upload-time = "2026-03-31T21:58:52.232Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/91/cc8cc78a111826c54743d88651e1687008133c37e5ee615fee9b57990fac/aiohttp-3.13.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:756c3c304d394977519824449600adaf2be0ccee76d206ee339c5e76b70ded25", size = 499094, upload-time = "2026-03-31T21:58:54.566Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/33/a8362cb15cf16a3af7e86ed11962d5cd7d59b449202dc576cdc731310bde/aiohttp-3.13.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecc26751323224cf8186efcf7fbcbc30f4e1d8c7970659daf25ad995e4032a56", size = 1726701, upload-time = "2026-03-31T21:58:56.864Z" },
+ { url = "https://files.pythonhosted.org/packages/45/0c/c091ac5c3a17114bd76cbf85d674650969ddf93387876cf67f754204bd77/aiohttp-3.13.5-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10a75acfcf794edf9d8db50e5a7ec5fc818b2a8d3f591ce93bc7b1210df016d2", size = 1683360, upload-time = "2026-03-31T21:58:59.072Z" },
+ { url = "https://files.pythonhosted.org/packages/23/73/bcee1c2b79bc275e964d1446c55c54441a461938e70267c86afaae6fba27/aiohttp-3.13.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0f7a18f258d124cd678c5fe072fe4432a4d5232b0657fca7c1847f599233c83a", size = 1773023, upload-time = "2026-03-31T21:59:01.776Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/ef/720e639df03004fee2d869f771799d8c23046dec47d5b81e396c7cda583a/aiohttp-3.13.5-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:df6104c009713d3a89621096f3e3e88cc323fd269dbd7c20afe18535094320be", size = 1853795, upload-time = "2026-03-31T21:59:04.568Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/c9/989f4034fb46841208de7aeeac2c6d8300745ab4f28c42f629ba77c2d916/aiohttp-3.13.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:241a94f7de7c0c3b616627aaad530fe2cb620084a8b144d3be7b6ecfe95bae3b", size = 1730405, upload-time = "2026-03-31T21:59:07.221Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/75/ee1fd286ca7dc599d824b5651dad7b3be7ff8d9a7e7b3fe9820d9180f7db/aiohttp-3.13.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c974fb66180e58709b6fc402846f13791240d180b74de81d23913abe48e96d94", size = 1558082, upload-time = "2026-03-31T21:59:09.484Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/20/1e9e6650dfc436340116b7aa89ff8cb2bbdf0abc11dfaceaad8f74273a10/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:6e27ea05d184afac78aabbac667450c75e54e35f62238d44463131bd3f96753d", size = 1692346, upload-time = "2026-03-31T21:59:12.068Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/40/8ebc6658d48ea630ac7903912fe0dd4e262f0e16825aa4c833c56c9f1f56/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a79a6d399cef33a11b6f004c67bb07741d91f2be01b8d712d52c75711b1e07c7", size = 1698891, upload-time = "2026-03-31T21:59:14.552Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/78/ea0ae5ec8ba7a5c10bdd6e318f1ba5e76fcde17db8275188772afc7917a4/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c632ce9c0b534fbe25b52c974515ed674937c5b99f549a92127c85f771a78772", size = 1742113, upload-time = "2026-03-31T21:59:17.068Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/66/9d308ed71e3f2491be1acb8769d96c6f0c47d92099f3bc9119cada27b357/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:fceedde51fbd67ee2bcc8c0b33d0126cc8b51ef3bbde2f86662bd6d5a6f10ec5", size = 1553088, upload-time = "2026-03-31T21:59:19.541Z" },
+ { url = "https://files.pythonhosted.org/packages/da/a6/6cc25ed8dfc6e00c90f5c6d126a98e2cf28957ad06fa1036bd34b6f24a2c/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f92995dfec9420bb69ae629abf422e516923ba79ba4403bc750d94fb4a6c68c1", size = 1757976, upload-time = "2026-03-31T21:59:22.311Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/2b/cce5b0ffe0de99c83e5e36d8f828e4161e415660a9f3e58339d07cce3006/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20ae0ff08b1f2c8788d6fb85afcb798654ae6ba0b747575f8562de738078457b", size = 1712444, upload-time = "2026-03-31T21:59:24.635Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/cf/9e1795b4160c58d29421eafd1a69c6ce351e2f7c8d3c6b7e4ca44aea1a5b/aiohttp-3.13.5-cp314-cp314-win32.whl", hash = "sha256:b20df693de16f42b2472a9c485e1c948ee55524786a0a34345511afdd22246f3", size = 438128, upload-time = "2026-03-31T21:59:27.291Z" },
+ { url = "https://files.pythonhosted.org/packages/22/4d/eaedff67fc805aeba4ba746aec891b4b24cebb1a7d078084b6300f79d063/aiohttp-3.13.5-cp314-cp314-win_amd64.whl", hash = "sha256:f85c6f327bf0b8c29da7d93b1cabb6363fb5e4e160a32fa241ed2dce21b73162", size = 464029, upload-time = "2026-03-31T21:59:29.429Z" },
+ { url = "https://files.pythonhosted.org/packages/79/11/c27d9332ee20d68dd164dc12a6ecdef2e2e35ecc97ed6cf0d2442844624b/aiohttp-3.13.5-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:1efb06900858bb618ff5cee184ae2de5828896c448403d51fb633f09e109be0a", size = 778758, upload-time = "2026-03-31T21:59:31.547Z" },
+ { url = "https://files.pythonhosted.org/packages/04/fb/377aead2e0a3ba5f09b7624f702a964bdf4f08b5b6728a9799830c80041e/aiohttp-3.13.5-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:fee86b7c4bd29bdaf0d53d14739b08a106fdda809ca5fe032a15f52fae5fe254", size = 512883, upload-time = "2026-03-31T21:59:34.098Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/a6/aa109a33671f7a5d3bd78b46da9d852797c5e665bfda7d6b373f56bff2ec/aiohttp-3.13.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:20058e23909b9e65f9da62b396b77dfa95965cbe840f8def6e572538b1d32e36", size = 516668, upload-time = "2026-03-31T21:59:36.497Z" },
+ { url = "https://files.pythonhosted.org/packages/79/b3/ca078f9f2fa9563c36fb8ef89053ea2bb146d6f792c5104574d49d8acb63/aiohttp-3.13.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cf20a8d6868cb15a73cab329ffc07291ba8c22b1b88176026106ae39aa6df0f", size = 1883461, upload-time = "2026-03-31T21:59:38.723Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/e3/a7ad633ca1ca497b852233a3cce6906a56c3225fb6d9217b5e5e60b7419d/aiohttp-3.13.5-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:330f5da04c987f1d5bdb8ae189137c77139f36bd1cb23779ca1a354a4b027800", size = 1747661, upload-time = "2026-03-31T21:59:41.187Z" },
+ { url = "https://files.pythonhosted.org/packages/33/b9/cd6fe579bed34a906d3d783fe60f2fa297ef55b27bb4538438ee49d4dc41/aiohttp-3.13.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f1cbf0c7926d315c3c26c2da41fd2b5d2fe01ac0e157b78caefc51a782196cf", size = 1863800, upload-time = "2026-03-31T21:59:43.84Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/3f/2c1e2f5144cefa889c8afd5cf431994c32f3b29da9961698ff4e3811b79a/aiohttp-3.13.5-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:53fc049ed6390d05423ba33103ded7281fe897cf97878f369a527070bd95795b", size = 1958382, upload-time = "2026-03-31T21:59:46.187Z" },
+ { url = "https://files.pythonhosted.org/packages/66/1d/f31ec3f1013723b3babe3609e7f119c2c2fb6ef33da90061a705ef3e1bc8/aiohttp-3.13.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:898703aa2667e3c5ca4c54ca36cd73f58b7a38ef87a5606414799ebce4d3fd3a", size = 1803724, upload-time = "2026-03-31T21:59:48.656Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/b4/57712dfc6f1542f067daa81eb61da282fab3e6f1966fca25db06c4fc62d5/aiohttp-3.13.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0494a01ca9584eea1e5fbd6d748e61ecff218c51b576ee1999c23db7066417d8", size = 1640027, upload-time = "2026-03-31T21:59:51.284Z" },
+ { url = "https://files.pythonhosted.org/packages/25/3c/734c878fb43ec083d8e31bf029daae1beafeae582d1b35da234739e82ee7/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6cf81fe010b8c17b09495cbd15c1d35afbc8fb405c0c9cf4738e5ae3af1d65be", size = 1806644, upload-time = "2026-03-31T21:59:53.753Z" },
+ { url = "https://files.pythonhosted.org/packages/20/a5/f671e5cbec1c21d044ff3078223f949748f3a7f86b14e34a365d74a5d21f/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:c564dd5f09ddc9d8f2c2d0a301cd30a79a2cc1b46dd1a73bef8f0038863d016b", size = 1791630, upload-time = "2026-03-31T21:59:56.239Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/63/fb8d0ad63a0b8a99be97deac8c04dacf0785721c158bdf23d679a87aa99e/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:2994be9f6e51046c4f864598fd9abeb4fba6e88f0b2152422c9666dcd4aea9c6", size = 1809403, upload-time = "2026-03-31T21:59:59.103Z" },
+ { url = "https://files.pythonhosted.org/packages/59/0c/bfed7f30662fcf12206481c2aac57dedee43fe1c49275e85b3a1e1742294/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:157826e2fa245d2ef46c83ea8a5faf77ca19355d278d425c29fda0beb3318037", size = 1634924, upload-time = "2026-03-31T22:00:02.116Z" },
+ { url = "https://files.pythonhosted.org/packages/17/d6/fd518d668a09fd5a3319ae5e984d4d80b9a4b3df4e21c52f02251ef5a32e/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:a8aca50daa9493e9e13c0f566201a9006f080e7c50e5e90d0b06f53146a54500", size = 1836119, upload-time = "2026-03-31T22:00:04.756Z" },
+ { url = "https://files.pythonhosted.org/packages/78/b7/15fb7a9d52e112a25b621c67b69c167805cb1f2ab8f1708a5c490d1b52fe/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3b13560160d07e047a93f23aaa30718606493036253d5430887514715b67c9d9", size = 1772072, upload-time = "2026-03-31T22:00:07.494Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/df/57ba7f0c4a553fc2bd8b6321df236870ec6fd64a2a473a8a13d4f733214e/aiohttp-3.13.5-cp314-cp314t-win32.whl", hash = "sha256:9a0f4474b6ea6818b41f82172d799e4b3d29e22c2c520ce4357856fced9af2f8", size = 471819, upload-time = "2026-03-31T22:00:10.277Z" },
+ { url = "https://files.pythonhosted.org/packages/62/29/2f8418269e46454a26171bfdd6a055d74febf32234e474930f2f60a17145/aiohttp-3.13.5-cp314-cp314t-win_amd64.whl", hash = "sha256:18a2f6c1182c51baa1d28d68fea51513cb2a76612f038853c0ad3c145423d3d9", size = 505441, upload-time = "2026-03-31T22:00:12.791Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/a5/630bc484695d4a1342bbae85fb8689bf979106525684fc88f05b397324ad/aiohttp-3.13.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:347542f0ea3f95b2a955ee6656461fa1c776e401ac50ebce055a6c38454a0adf", size = 752872, upload-time = "2026-03-31T22:00:15.553Z" },
+ { url = "https://files.pythonhosted.org/packages/cd/b8/6a19dda37fda94a9ebefb3c1ae0ff419ac7fbf4fb40750e992829fc13614/aiohttp-3.13.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:178c7b5e62b454c2bc790786e6058c3cc968613b4419251b478c153a4aec32b1", size = 504582, upload-time = "2026-03-31T22:00:18.191Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/34/8413eafee3421ade2d6ce9e7c0da1213e1d7f0049be09dcdc342b03a39ba/aiohttp-3.13.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af545c2cffdb0967a96b6249e6f5f7b0d92cdfd267f9d5238d5b9ca63e8edb10", size = 499094, upload-time = "2026-03-31T22:00:21.118Z" },
+ { url = "https://files.pythonhosted.org/packages/da/cf/c6f97006093d1e8ca40fbab843ff49ec7725ab668f0714dd1cb702c62cbd/aiohttp-3.13.5-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:206b7b3ef96e4ce211754f0cd003feb28b7d81f0ad26b8d077a5d5161436067f", size = 1669505, upload-time = "2026-03-31T22:00:24.01Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/27/3b2288e66dcec8b04771b2bee3909f70e4072bea995cde5ab7e775e73ddc/aiohttp-3.13.5-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ee5e86776273de1795947d17bddd6bb19e0365fd2af4289c0d2c5454b6b1d36b", size = 1648928, upload-time = "2026-03-31T22:00:27.001Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/7f/605d766887594a88dcc27a19663499c7c5e13e7aa87f129b763765a2ee63/aiohttp-3.13.5-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:95d14ca7abefde230f7639ec136ade282655431fd5db03c343b19dda72dd1643", size = 1731800, upload-time = "2026-03-31T22:00:29.603Z" },
+ { url = "https://files.pythonhosted.org/packages/71/94/5a878e728e30699d22b118f1a6ad576ab6fff9eb2c6fc8a7faa9376a1c3e/aiohttp-3.13.5-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:912d4b6af530ddb1338a66229dac3a25ff11d4448be3ec3d6340583995f56031", size = 1824247, upload-time = "2026-03-31T22:00:32.139Z" },
+ { url = "https://files.pythonhosted.org/packages/37/99/84b448291e9996bb83bf4fad3a71a9786d542f19c50a3ff0531bfaba6fac/aiohttp-3.13.5-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e999f0c88a458c836d5fb521814e92ed2172c649200336a6df514987c1488258", size = 1670742, upload-time = "2026-03-31T22:00:34.788Z" },
+ { url = "https://files.pythonhosted.org/packages/14/a8/d8d5d1ab6d29a4a3bdb9db31f161e338bfdf6638f6574ea8380f1d4a243c/aiohttp-3.13.5-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:39380e12bd1f2fdab4285b6e055ad48efbaed5c836433b142ed4f5b9be71036a", size = 1562474, upload-time = "2026-03-31T22:00:37.623Z" },
+ { url = "https://files.pythonhosted.org/packages/92/e8/bd889697916f10b65524422c61b4eeaf919eb35a170290cccb680cbe4eb4/aiohttp-3.13.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9efcc0f11d850cefcafdd9275b9576ad3bfb539bed96807663b32ad99c4d4b88", size = 1642235, upload-time = "2026-03-31T22:00:40.541Z" },
+ { url = "https://files.pythonhosted.org/packages/60/42/3f1928107131f1413a5972ace14ddcd5364968e9bd7b3ad71272defafc9c/aiohttp-3.13.5-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:147b4f501d0292077f29d5268c16bb7c864a1f054d7001c4c1812c0421ea1ed0", size = 1655397, upload-time = "2026-03-31T22:00:43.167Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/79/c4bbcf4cac3a4715a326e49720ccdc3a4b5e14a367c5029eae7727d06029/aiohttp-3.13.5-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:d147004fede1b12f6013a6dbb2a26a986a671a03c6ea740ddc76500e5f1c399f", size = 1703509, upload-time = "2026-03-31T22:00:45.908Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/e6/32d245876f211a7308a7d5437707f9296b1f9837a2888a407ed04e61321c/aiohttp-3.13.5-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:9277145d36a01653863899c665243871434694bcc3431922c3b35c978061bdb8", size = 1550098, upload-time = "2026-03-31T22:00:49.48Z" },
+ { url = "https://files.pythonhosted.org/packages/db/62/ab0f1304def56ce2356e6fbb9f0b024d6544010351430070f48f53b89e0a/aiohttp-3.13.5-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4e704c52438f66fdd89588346183d898bb42167cf88f8b7ff1c0f9fc957c348f", size = 1724326, upload-time = "2026-03-31T22:00:52.165Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/9a/aab4469689024046220ea438aa020ea2ae04cd1dd71aea3057e094f8c357/aiohttp-3.13.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a8a4d3427e8de1312ddf309cc482186466c79895b3a139fed3259fc01dfa9a5b", size = 1658824, upload-time = "2026-03-31T22:00:55.122Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/98/bcc35d4db687acabf06d41f561a99fa88bca145292513388c858d99b72c5/aiohttp-3.13.5-cp39-cp39-win32.whl", hash = "sha256:6f497a6876aa4b1a102b04996ce4c1170c7040d83faa9387dd921c16e30d5c83", size = 440302, upload-time = "2026-03-31T22:00:57.673Z" },
+ { url = "https://files.pythonhosted.org/packages/25/61/b0203c2ef6bd268fca0eda142f0efbba7cbebd7ad38f7bb01dd31c2ff68e/aiohttp-3.13.5-cp39-cp39-win_amd64.whl", hash = "sha256:cb979826071c0986a5f08333a36104153478ce6018c58cba7f9caddaf63d5d67", size = 463076, upload-time = "2026-03-31T22:01:00.264Z" },
+]
+
+[[package]]
+name = "aiosignal"
+version = "1.4.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "frozenlist" },
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" },
+]
+
+[[package]]
+name = "annotated-types"
+version = "0.7.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
+]
+
+[[package]]
+name = "asttokens"
+version = "3.0.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308, upload-time = "2025-11-15T16:43:48.578Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047, upload-time = "2025-11-15T16:43:16.109Z" },
+]
+
+[[package]]
+name = "async-timeout"
+version = "5.0.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274, upload-time = "2024-11-06T16:41:39.6Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" },
+]
+
+[[package]]
+name = "attrs"
+version = "25.4.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" },
+]
+
+[[package]]
+name = "auditwheel"
+version = "6.4.2"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version < '3.10'",
+]
+dependencies = [
+ { name = "packaging", marker = "python_full_version < '3.10'" },
+ { name = "pyelftools", marker = "python_full_version < '3.10'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/26/a0/8d998628f1d899420a621fcd7b46825cb96f23b5b52c2b93f4f814ae9c59/auditwheel-6.4.2.tar.gz", hash = "sha256:b7a61afc9183b6b5c661de59ca586f9c7200445a409c58cdf2049d6f71636d51", size = 4694856, upload-time = "2025-07-27T07:14:33.527Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d6/66/d790dc341d93c80e1ee61f2580177d7ee2e3e16dc100c36889b8bd176acf/auditwheel-6.4.2-py3-none-any.whl", hash = "sha256:4302ae79dcff242e799a37173cfeeae727d0924843eca4b3f622d3bcb28de2db", size = 50876, upload-time = "2025-07-27T07:13:27.565Z" },
+]
+
+[[package]]
+name = "auditwheel"
+version = "6.6.0"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version >= '3.11'",
+ "python_full_version == '3.10.*'",
+]
+dependencies = [
+ { name = "packaging", marker = "python_full_version >= '3.10'" },
+ { name = "pyelftools", marker = "python_full_version >= '3.10'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/7b/ed/342df5a75589103d72402dcdd88d7b8cc2df338fbc39042ce1b3ac008960/auditwheel-6.6.0.tar.gz", hash = "sha256:277f3b315ad0b04df0a2be2d126c3fd39930bc265df0f9589d78c970ff06f52b", size = 4663481, upload-time = "2026-01-04T14:34:21.577Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b0/c2/bb8ba1cec816fa356e19da83c59bfd4ac34dba1ae41eb7622c18f4b1d48d/auditwheel-6.6.0-py3-none-any.whl", hash = "sha256:3e8479856ca582625b5457204cbb62d1614d3bc7e760ee307c04c34c912ebcad", size = 59184, upload-time = "2026-01-04T14:34:19.932Z" },
+]
+
+[[package]]
+name = "backports-asyncio-runner"
+version = "1.2.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/8e/ff/70dca7d7cb1cbc0edb2c6cc0c38b65cba36cccc491eca64cabd5fe7f8670/backports_asyncio_runner-1.2.0.tar.gz", hash = "sha256:a5aa7b2b7d8f8bfcaa2b57313f70792df84e32a2a746f585213373f900b42162", size = 69893, upload-time = "2025-07-02T02:27:15.685Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl", hash = "sha256:0da0a936a8aeb554eccb426dc55af3ba63bcdc69fa1a600b5bb305413a4477b5", size = 12313, upload-time = "2025-07-02T02:27:14.263Z" },
+]
+
+[[package]]
+name = "backports-tarfile"
+version = "1.2.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/86/72/cd9b395f25e290e633655a100af28cb253e4393396264a98bd5f5951d50f/backports_tarfile-1.2.0.tar.gz", hash = "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991", size = 86406, upload-time = "2024-05-28T17:01:54.731Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b9/fa/123043af240e49752f1c4bd24da5053b6bd00cad78c2be53c0d1e8b975bc/backports.tarfile-1.2.0-py3-none-any.whl", hash = "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34", size = 30181, upload-time = "2024-05-28T17:01:53.112Z" },
+]
+
+[[package]]
+name = "bashlex"
+version = "0.18"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/76/60/aae0bb54f9af5e0128ba90eb83d8d0d506ee8f0475c4fdda3deeda20b1d2/bashlex-0.18.tar.gz", hash = "sha256:5bb03a01c6d5676338c36fd1028009c8ad07e7d61d8a1ce3f513b7fff52796ee", size = 68742, upload-time = "2023-01-18T15:21:26.402Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f4/be/6985abb1011fda8a523cfe21ed9629e397d6e06fb5bae99750402b25c95b/bashlex-0.18-py2.py3-none-any.whl", hash = "sha256:91d73a23a3e51711919c1c899083890cdecffc91d8c088942725ac13e9dcfffa", size = 69539, upload-time = "2023-01-18T15:21:24.167Z" },
+]
+
+[[package]]
+name = "bracex"
+version = "2.6"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/63/9a/fec38644694abfaaeca2798b58e276a8e61de49e2e37494ace423395febc/bracex-2.6.tar.gz", hash = "sha256:98f1347cd77e22ee8d967a30ad4e310b233f7754dbf31ff3fceb76145ba47dc7", size = 26642, upload-time = "2025-06-22T19:12:31.254Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9d/2a/9186535ce58db529927f6cf5990a849aa9e052eea3e2cfefe20b9e1802da/bracex-2.6-py3-none-any.whl", hash = "sha256:0b0049264e7340b3ec782b5cb99beb325f36c3782a32e36e876452fd49a09952", size = 11508, upload-time = "2025-06-22T19:12:29.781Z" },
+]
+
+[[package]]
+name = "build"
+version = "1.4.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama", marker = "python_full_version >= '3.11' and os_name == 'nt'" },
+ { name = "packaging", marker = "python_full_version >= '3.11'" },
+ { name = "pyproject-hooks", marker = "python_full_version >= '3.11'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/42/18/94eaffda7b329535d91f00fe605ab1f1e5cd68b2074d03f255c7d250687d/build-1.4.0.tar.gz", hash = "sha256:f1b91b925aa322be454f8330c6fb48b465da993d1e7e7e6fa35027ec49f3c936", size = 50054, upload-time = "2026-01-08T16:41:47.696Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c5/0d/84a4380f930db0010168e0aa7b7a8fed9ba1835a8fbb1472bc6d0201d529/build-1.4.0-py3-none-any.whl", hash = "sha256:6a07c1b8eb6f2b311b96fcbdbce5dab5fe637ffda0fd83c9cac622e927501596", size = 24141, upload-time = "2026-01-08T16:41:46.453Z" },
+]
+
+[[package]]
+name = "certifi"
+version = "2026.2.25"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/af/2d/7bf41579a8986e348fa033a31cdd0e4121114f6bce2457e8876010b092dd/certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7", size = 155029, upload-time = "2026-02-25T02:54:17.342Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684, upload-time = "2026-02-25T02:54:15.766Z" },
+]
+
+[[package]]
+name = "cffi"
+version = "2.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pycparser", version = "2.23", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' and implementation_name != 'PyPy'" },
+ { name = "pycparser", version = "3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' and implementation_name != 'PyPy'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811, upload-time = "2025-09-08T23:22:12.267Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402, upload-time = "2025-09-08T23:22:13.455Z" },
+ { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475, upload-time = "2025-09-08T23:22:17.427Z" },
+ { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829, upload-time = "2025-09-08T23:22:19.069Z" },
+ { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211, upload-time = "2025-09-08T23:22:20.588Z" },
+ { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036, upload-time = "2025-09-08T23:22:22.143Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" },
+ { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" },
+ { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" },
+ { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" },
+ { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" },
+ { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" },
+ { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" },
+ { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" },
+ { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" },
+ { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/13/c92e36358fbcc39cf0962e83223c9522154ee8630e1df7c0b3a39a8124e2/cffi-2.0.0-cp39-cp39-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:4647afc2f90d1ddd33441e5b0e85b16b12ddec4fca55f0d9671fef036ecca27c", size = 208813, upload-time = "2025-09-08T23:23:51.263Z" },
+ { url = "https://files.pythonhosted.org/packages/15/12/a7a79bd0df4c3bff744b2d7e52cc1b68d5e7e427b384252c42366dc1ecbc/cffi-2.0.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3f4d46d8b35698056ec29bca21546e1551a205058ae1a181d871e278b0b28165", size = 216498, upload-time = "2025-09-08T23:23:52.494Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/74/cc4096ce66f5939042ae094e2e96f53426a979864aa1f96a621ad128be27/cffi-2.0.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:61d028e90346df14fedc3d1e5441df818d095f3b87d286825dfcbd6459b7ef63", size = 216548, upload-time = "2025-09-08T23:23:56.506Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/be/f6424d1dc46b1091ffcc8964fa7c0ab0cd36839dd2761b49c90481a6ba1b/cffi-2.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0f6084a0ea23d05d20c3edcda20c3d006f9b6f3fefeac38f59262e10cef47ee2", size = 218897, upload-time = "2025-09-08T23:23:57.825Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/e0/dda537c2309817edf60109e39265f24f24aa7f050767e22c98c53fe7f48b/cffi-2.0.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1cd13c99ce269b3ed80b417dcd591415d3372bcac067009b6e0f59c7d4015e65", size = 211249, upload-time = "2025-09-08T23:23:59.139Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/e7/7c769804eb75e4c4b35e658dba01de1640a351a9653c3d49ca89d16ccc91/cffi-2.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:89472c9762729b5ae1ad974b777416bfda4ac5642423fa93bd57a09204712322", size = 218041, upload-time = "2025-09-08T23:24:00.496Z" },
+]
+
+[[package]]
+name = "charset-normalizer"
+version = "3.4.4"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/1f/b8/6d51fc1d52cbd52cd4ccedd5b5b2f0f6a11bbf6765c782298b0f3e808541/charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d", size = 209709, upload-time = "2025-10-14T04:40:11.385Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/af/1f9d7f7faafe2ddfb6f72a2e07a548a629c61ad510fe60f9630309908fef/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8", size = 148814, upload-time = "2025-10-14T04:40:13.135Z" },
+ { url = "https://files.pythonhosted.org/packages/79/3d/f2e3ac2bbc056ca0c204298ea4e3d9db9b4afe437812638759db2c976b5f/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad", size = 144467, upload-time = "2025-10-14T04:40:14.728Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/85/1bf997003815e60d57de7bd972c57dc6950446a3e4ccac43bc3070721856/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8", size = 162280, upload-time = "2025-10-14T04:40:16.14Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/8e/6aa1952f56b192f54921c436b87f2aaf7c7a7c3d0d1a765547d64fd83c13/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d", size = 159454, upload-time = "2025-10-14T04:40:17.567Z" },
+ { url = "https://files.pythonhosted.org/packages/36/3b/60cbd1f8e93aa25d1c669c649b7a655b0b5fb4c571858910ea9332678558/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313", size = 153609, upload-time = "2025-10-14T04:40:19.08Z" },
+ { url = "https://files.pythonhosted.org/packages/64/91/6a13396948b8fd3c4b4fd5bc74d045f5637d78c9675585e8e9fbe5636554/charset_normalizer-3.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e", size = 151849, upload-time = "2025-10-14T04:40:20.607Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/7a/59482e28b9981d105691e968c544cc0df3b7d6133152fb3dcdc8f135da7a/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93", size = 151586, upload-time = "2025-10-14T04:40:21.719Z" },
+ { url = "https://files.pythonhosted.org/packages/92/59/f64ef6a1c4bdd2baf892b04cd78792ed8684fbc48d4c2afe467d96b4df57/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0", size = 145290, upload-time = "2025-10-14T04:40:23.069Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/63/3bf9f279ddfa641ffa1962b0db6a57a9c294361cc2f5fcac997049a00e9c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84", size = 163663, upload-time = "2025-10-14T04:40:24.17Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/09/c9e38fc8fa9e0849b172b581fd9803bdf6e694041127933934184e19f8c3/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e", size = 151964, upload-time = "2025-10-14T04:40:25.368Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/d1/d28b747e512d0da79d8b6a1ac18b7ab2ecfd81b2944c4c710e166d8dd09c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db", size = 161064, upload-time = "2025-10-14T04:40:26.806Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/9a/31d62b611d901c3b9e5500c36aab0ff5eb442043fb3a1c254200d3d397d9/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6", size = 155015, upload-time = "2025-10-14T04:40:28.284Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/f3/107e008fa2bff0c8b9319584174418e5e5285fef32f79d8ee6a430d0039c/charset_normalizer-3.4.4-cp310-cp310-win32.whl", hash = "sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f", size = 99792, upload-time = "2025-10-14T04:40:29.613Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/66/e396e8a408843337d7315bab30dbf106c38966f1819f123257f5520f8a96/charset_normalizer-3.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d", size = 107198, upload-time = "2025-10-14T04:40:30.644Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/58/01b4f815bf0312704c267f2ccb6e5d42bcc7752340cd487bc9f8c3710597/charset_normalizer-3.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69", size = 100262, upload-time = "2025-10-14T04:40:32.108Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/27/c6491ff4954e58a10f69ad90aca8a1b6fe9c5d3c6f380907af3c37435b59/charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8", size = 206988, upload-time = "2025-10-14T04:40:33.79Z" },
+ { url = "https://files.pythonhosted.org/packages/94/59/2e87300fe67ab820b5428580a53cad894272dbb97f38a7a814a2a1ac1011/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0", size = 147324, upload-time = "2025-10-14T04:40:34.961Z" },
+ { url = "https://files.pythonhosted.org/packages/07/fb/0cf61dc84b2b088391830f6274cb57c82e4da8bbc2efeac8c025edb88772/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3", size = 142742, upload-time = "2025-10-14T04:40:36.105Z" },
+ { url = "https://files.pythonhosted.org/packages/62/8b/171935adf2312cd745d290ed93cf16cf0dfe320863ab7cbeeae1dcd6535f/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc", size = 160863, upload-time = "2025-10-14T04:40:37.188Z" },
+ { url = "https://files.pythonhosted.org/packages/09/73/ad875b192bda14f2173bfc1bc9a55e009808484a4b256748d931b6948442/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897", size = 157837, upload-time = "2025-10-14T04:40:38.435Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/fc/de9cce525b2c5b94b47c70a4b4fb19f871b24995c728e957ee68ab1671ea/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381", size = 151550, upload-time = "2025-10-14T04:40:40.053Z" },
+ { url = "https://files.pythonhosted.org/packages/55/c2/43edd615fdfba8c6f2dfbd459b25a6b3b551f24ea21981e23fb768503ce1/charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815", size = 149162, upload-time = "2025-10-14T04:40:41.163Z" },
+ { url = "https://files.pythonhosted.org/packages/03/86/bde4ad8b4d0e9429a4e82c1e8f5c659993a9a863ad62c7df05cf7b678d75/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0", size = 150019, upload-time = "2025-10-14T04:40:42.276Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/86/a151eb2af293a7e7bac3a739b81072585ce36ccfb4493039f49f1d3cae8c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161", size = 143310, upload-time = "2025-10-14T04:40:43.439Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/fe/43dae6144a7e07b87478fdfc4dbe9efd5defb0e7ec29f5f58a55aeef7bf7/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4", size = 162022, upload-time = "2025-10-14T04:40:44.547Z" },
+ { url = "https://files.pythonhosted.org/packages/80/e6/7aab83774f5d2bca81f42ac58d04caf44f0cc2b65fc6db2b3b2e8a05f3b3/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89", size = 149383, upload-time = "2025-10-14T04:40:46.018Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/e8/b289173b4edae05c0dde07f69f8db476a0b511eac556dfe0d6bda3c43384/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569", size = 159098, upload-time = "2025-10-14T04:40:47.081Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/df/fe699727754cae3f8478493c7f45f777b17c3ef0600e28abfec8619eb49c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224", size = 152991, upload-time = "2025-10-14T04:40:48.246Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/86/584869fe4ddb6ffa3bd9f491b87a01568797fb9bd8933f557dba9771beaf/charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a", size = 99456, upload-time = "2025-10-14T04:40:49.376Z" },
+ { url = "https://files.pythonhosted.org/packages/65/f6/62fdd5feb60530f50f7e38b4f6a1d5203f4d16ff4f9f0952962c044e919a/charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016", size = 106978, upload-time = "2025-10-14T04:40:50.844Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/9d/0710916e6c82948b3be62d9d398cb4fcf4e97b56d6a6aeccd66c4b2f2bd5/charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1", size = 99969, upload-time = "2025-10-14T04:40:52.272Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" },
+ { url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" },
+ { url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497, upload-time = "2025-10-14T04:40:57.217Z" },
+ { url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240, upload-time = "2025-10-14T04:40:58.358Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471, upload-time = "2025-10-14T04:40:59.468Z" },
+ { url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864, upload-time = "2025-10-14T04:41:00.623Z" },
+ { url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647, upload-time = "2025-10-14T04:41:01.754Z" },
+ { url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110, upload-time = "2025-10-14T04:41:03.231Z" },
+ { url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839, upload-time = "2025-10-14T04:41:04.715Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667, upload-time = "2025-10-14T04:41:05.827Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535, upload-time = "2025-10-14T04:41:06.938Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816, upload-time = "2025-10-14T04:41:08.101Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694, upload-time = "2025-10-14T04:41:09.23Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131, upload-time = "2025-10-14T04:41:10.467Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390, upload-time = "2025-10-14T04:41:11.915Z" },
+ { url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" },
+ { url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" },
+ { url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" },
+ { url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" },
+ { url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" },
+ { url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" },
+ { url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" },
+ { url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779, upload-time = "2025-10-14T04:41:37.229Z" },
+ { url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035, upload-time = "2025-10-14T04:41:38.368Z" },
+ { url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542, upload-time = "2025-10-14T04:41:39.862Z" },
+ { url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524, upload-time = "2025-10-14T04:41:41.319Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395, upload-time = "2025-10-14T04:41:42.539Z" },
+ { url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680, upload-time = "2025-10-14T04:41:43.661Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045, upload-time = "2025-10-14T04:41:44.821Z" },
+ { url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687, upload-time = "2025-10-14T04:41:46.442Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014, upload-time = "2025-10-14T04:41:47.631Z" },
+ { url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044, upload-time = "2025-10-14T04:41:48.81Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" },
+ { url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" },
+ { url = "https://files.pythonhosted.org/packages/46/7c/0c4760bccf082737ca7ab84a4c2034fcc06b1f21cf3032ea98bd6feb1725/charset_normalizer-3.4.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a9768c477b9d7bd54bc0c86dbaebdec6f03306675526c9927c0e8a04e8f94af9", size = 209609, upload-time = "2025-10-14T04:42:10.922Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/a4/69719daef2f3d7f1819de60c9a6be981b8eeead7542d5ec4440f3c80e111/charset_normalizer-3.4.4-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1bee1e43c28aa63cb16e5c14e582580546b08e535299b8b6158a7c9c768a1f3d", size = 149029, upload-time = "2025-10-14T04:42:12.38Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/21/8d4e1d6c1e6070d3672908b8e4533a71b5b53e71d16828cc24d0efec564c/charset_normalizer-3.4.4-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fd44c878ea55ba351104cb93cc85e74916eb8fa440ca7903e57575e97394f608", size = 144580, upload-time = "2025-10-14T04:42:13.549Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/0a/a616d001b3f25647a9068e0b9199f697ce507ec898cacb06a0d5a1617c99/charset_normalizer-3.4.4-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0f04b14ffe5fdc8c4933862d8306109a2c51e0704acfa35d51598eb45a1e89fc", size = 162340, upload-time = "2025-10-14T04:42:14.892Z" },
+ { url = "https://files.pythonhosted.org/packages/85/93/060b52deb249a5450460e0585c88a904a83aec474ab8e7aba787f45e79f2/charset_normalizer-3.4.4-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:cd09d08005f958f370f539f186d10aec3377d55b9eeb0d796025d4886119d76e", size = 159619, upload-time = "2025-10-14T04:42:16.676Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/21/0274deb1cc0632cd587a9a0ec6b4674d9108e461cb4cd40d457adaeb0564/charset_normalizer-3.4.4-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4fe7859a4e3e8457458e2ff592f15ccb02f3da787fcd31e0183879c3ad4692a1", size = 153980, upload-time = "2025-10-14T04:42:17.917Z" },
+ { url = "https://files.pythonhosted.org/packages/28/2b/e3d7d982858dccc11b31906976323d790dded2017a0572f093ff982d692f/charset_normalizer-3.4.4-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fa09f53c465e532f4d3db095e0c55b615f010ad81803d383195b6b5ca6cbf5f3", size = 152174, upload-time = "2025-10-14T04:42:19.018Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/ff/4a269f8e35f1e58b2df52c131a1fa019acb7ef3f8697b7d464b07e9b492d/charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7fa17817dc5625de8a027cb8b26d9fefa3ea28c8253929b8d6649e705d2835b6", size = 151666, upload-time = "2025-10-14T04:42:20.171Z" },
+ { url = "https://files.pythonhosted.org/packages/da/c9/ec39870f0b330d58486001dd8e532c6b9a905f5765f58a6f8204926b4a93/charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:5947809c8a2417be3267efc979c47d76a079758166f7d43ef5ae8e9f92751f88", size = 145550, upload-time = "2025-10-14T04:42:21.324Z" },
+ { url = "https://files.pythonhosted.org/packages/75/8f/d186ab99e40e0ed9f82f033d6e49001701c81244d01905dd4a6924191a30/charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:4902828217069c3c5c71094537a8e623f5d097858ac6ca8252f7b4d10b7560f1", size = 163721, upload-time = "2025-10-14T04:42:22.46Z" },
+ { url = "https://files.pythonhosted.org/packages/96/b1/6047663b9744df26a7e479ac1e77af7134b1fcf9026243bb48ee2d18810f/charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:7c308f7e26e4363d79df40ca5b2be1c6ba9f02bdbccfed5abddb7859a6ce72cf", size = 152127, upload-time = "2025-10-14T04:42:23.712Z" },
+ { url = "https://files.pythonhosted.org/packages/59/78/e5a6eac9179f24f704d1be67d08704c3c6ab9f00963963524be27c18ed87/charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:2c9d3c380143a1fedbff95a312aa798578371eb29da42106a29019368a475318", size = 161175, upload-time = "2025-10-14T04:42:24.87Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/43/0e626e42d54dd2f8dd6fc5e1c5ff00f05fbca17cb699bedead2cae69c62f/charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:cb01158d8b88ee68f15949894ccc6712278243d95f344770fa7593fa2d94410c", size = 155375, upload-time = "2025-10-14T04:42:27.246Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/91/d9615bf2e06f35e4997616ff31248c3657ed649c5ab9d35ea12fce54e380/charset_normalizer-3.4.4-cp39-cp39-win32.whl", hash = "sha256:2677acec1a2f8ef614c6888b5b4ae4060cc184174a938ed4e8ef690e15d3e505", size = 99692, upload-time = "2025-10-14T04:42:28.425Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/a9/6c040053909d9d1ef4fcab45fddec083aedc9052c10078339b47c8573ea8/charset_normalizer-3.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:f8e160feb2aed042cd657a72acc0b481212ed28b1b9a95c0cee1621b524e1966", size = 107192, upload-time = "2025-10-14T04:42:29.482Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/c6/4fa536b2c0cd3edfb7ccf8469fa0f363ea67b7213a842b90909ca33dd851/charset_normalizer-3.4.4-cp39-cp39-win_arm64.whl", hash = "sha256:b5d84d37db046c5ca74ee7bb47dd6cbc13f80665fdde3e8040bdd3fb015ecb50", size = 100220, upload-time = "2025-10-14T04:42:30.632Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" },
+]
+
+[[package]]
+name = "cibuildwheel"
+version = "2.23.3"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version == '3.10.*'",
+ "python_full_version < '3.10'",
+]
+dependencies = [
+ { name = "bashlex", marker = "python_full_version < '3.11'" },
+ { name = "bracex", marker = "python_full_version < '3.11'" },
+ { name = "certifi", marker = "python_full_version < '3.11'" },
+ { name = "dependency-groups", marker = "python_full_version < '3.11'" },
+ { name = "filelock", version = "3.19.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "filelock", version = "3.24.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" },
+ { name = "packaging", marker = "python_full_version < '3.11'" },
+ { name = "platformdirs", version = "4.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "platformdirs", version = "4.9.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" },
+ { name = "tomli", marker = "python_full_version < '3.11'" },
+ { name = "typing-extensions", marker = "python_full_version < '3.11'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/50/f5/2c06c8229e291e121cb26ed2efa1ba5d89053a93631d8f1d795f2dacabb8/cibuildwheel-2.23.3.tar.gz", hash = "sha256:d85dd15b7eb81711900d8129e67efb32b12f99cc00fc271ab060fa6270c38397", size = 295383, upload-time = "2025-04-26T10:41:28.258Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/17/8e/127e75e087c0a55903deb447a938e97935c6a56bfd20e6070bcc26c06d1b/cibuildwheel-2.23.3-py3-none-any.whl", hash = "sha256:0fa40073ae23a56d5f995d8405e82c1206049999bb89b92aa0835ee62ab8a891", size = 91792, upload-time = "2025-04-26T10:41:26.148Z" },
+]
+
+[[package]]
+name = "cibuildwheel"
+version = "3.3.1"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version >= '3.11'",
+]
+dependencies = [
+ { name = "bashlex", marker = "python_full_version >= '3.11'" },
+ { name = "bracex", marker = "python_full_version >= '3.11'" },
+ { name = "build", marker = "python_full_version >= '3.11'" },
+ { name = "certifi", marker = "python_full_version >= '3.11'" },
+ { name = "dependency-groups", marker = "python_full_version >= '3.11'" },
+ { name = "filelock", version = "3.24.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
+ { name = "humanize", marker = "python_full_version >= '3.11'" },
+ { name = "packaging", marker = "python_full_version >= '3.11'" },
+ { name = "patchelf", marker = "(python_full_version >= '3.11' and platform_machine == 'aarch64' and sys_platform == 'darwin') or (python_full_version >= '3.11' and platform_machine == 'arm64' and sys_platform == 'darwin') or (python_full_version >= '3.11' and platform_machine == 'x86_64' and sys_platform == 'darwin') or (python_full_version >= '3.11' and platform_machine == 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.11' and platform_machine == 'arm64' and sys_platform == 'linux') or (python_full_version >= '3.11' and platform_machine == 'x86_64' and sys_platform == 'linux')" },
+ { name = "platformdirs", version = "4.9.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
+ { name = "pyelftools", marker = "python_full_version >= '3.11'" },
+ { name = "wheel", marker = "python_full_version >= '3.11'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/cb/8c/61b0cca8be7eef6af32b0c0e62f78dc8c91572ea8870bc6c4d061f259832/cibuildwheel-3.3.1.tar.gz", hash = "sha256:ae6eafe6f7ed3bab38919e08bf3eb92085f6387c5f7a746b40cc4775a8462f9a", size = 358374, upload-time = "2026-01-05T19:58:17.606Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/73/5c/3b6689ae5c8a720c275f9832c2d1611a2a1f445bfb16701a13f5f604af5c/cibuildwheel-3.3.1-py3-none-any.whl", hash = "sha256:6d3c387e77c5850819294863eeee4e57fb7e8ecdf87b7412e763222c16e26424", size = 127164, upload-time = "2026-01-05T19:58:16.338Z" },
+]
+
+[[package]]
+name = "colorama"
+version = "0.4.6"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
+]
+
+[[package]]
+name = "contourpy"
+version = "1.3.0"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version < '3.10'",
+]
+dependencies = [
+ { name = "numpy", version = "2.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/f5/f6/31a8f28b4a2a4fa0e01085e542f3081ab0588eff8e589d39d775172c9792/contourpy-1.3.0.tar.gz", hash = "sha256:7ffa0db17717a8ffb127efd0c95a4362d996b892c2904db72428d5b52e1938a4", size = 13464370, upload-time = "2024-08-27T21:00:03.328Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/6c/e0/be8dcc796cfdd96708933e0e2da99ba4bb8f9b2caa9d560a50f3f09a65f3/contourpy-1.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:880ea32e5c774634f9fcd46504bf9f080a41ad855f4fef54f5380f5133d343c7", size = 265366, upload-time = "2024-08-27T20:50:09.947Z" },
+ { url = "https://files.pythonhosted.org/packages/50/d6/c953b400219443535d412fcbbc42e7a5e823291236bc0bb88936e3cc9317/contourpy-1.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:76c905ef940a4474a6289c71d53122a4f77766eef23c03cd57016ce19d0f7b42", size = 249226, upload-time = "2024-08-27T20:50:16.1Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/b4/6fffdf213ffccc28483c524b9dad46bb78332851133b36ad354b856ddc7c/contourpy-1.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92f8557cbb07415a4d6fa191f20fd9d2d9eb9c0b61d1b2f52a8926e43c6e9af7", size = 308460, upload-time = "2024-08-27T20:50:22.536Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/6c/118fc917b4050f0afe07179a6dcbe4f3f4ec69b94f36c9e128c4af480fb8/contourpy-1.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:36f965570cff02b874773c49bfe85562b47030805d7d8360748f3eca570f4cab", size = 347623, upload-time = "2024-08-27T20:50:28.806Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/a4/30ff110a81bfe3abf7b9673284d21ddce8cc1278f6f77393c91199da4c90/contourpy-1.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cacd81e2d4b6f89c9f8a5b69b86490152ff39afc58a95af002a398273e5ce589", size = 317761, upload-time = "2024-08-27T20:50:35.126Z" },
+ { url = "https://files.pythonhosted.org/packages/99/e6/d11966962b1aa515f5586d3907ad019f4b812c04e4546cc19ebf62b5178e/contourpy-1.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69375194457ad0fad3a839b9e29aa0b0ed53bb54db1bfb6c3ae43d111c31ce41", size = 322015, upload-time = "2024-08-27T20:50:40.318Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/e3/182383743751d22b7b59c3c753277b6aee3637049197624f333dac5b4c80/contourpy-1.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a52040312b1a858b5e31ef28c2e865376a386c60c0e248370bbea2d3f3b760d", size = 1262672, upload-time = "2024-08-27T20:50:55.643Z" },
+ { url = "https://files.pythonhosted.org/packages/78/53/974400c815b2e605f252c8fb9297e2204347d1755a5374354ee77b1ea259/contourpy-1.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3faeb2998e4fcb256542e8a926d08da08977f7f5e62cf733f3c211c2a5586223", size = 1321688, upload-time = "2024-08-27T20:51:11.293Z" },
+ { url = "https://files.pythonhosted.org/packages/52/29/99f849faed5593b2926a68a31882af98afbeac39c7fdf7de491d9c85ec6a/contourpy-1.3.0-cp310-cp310-win32.whl", hash = "sha256:36e0cff201bcb17a0a8ecc7f454fe078437fa6bda730e695a92f2d9932bd507f", size = 171145, upload-time = "2024-08-27T20:51:15.2Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/97/3f89bba79ff6ff2b07a3cbc40aa693c360d5efa90d66e914f0ff03b95ec7/contourpy-1.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:87ddffef1dbe5e669b5c2440b643d3fdd8622a348fe1983fad7a0f0ccb1cd67b", size = 216019, upload-time = "2024-08-27T20:51:19.365Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/1f/9375917786cb39270b0ee6634536c0e22abf225825602688990d8f5c6c19/contourpy-1.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0fa4c02abe6c446ba70d96ece336e621efa4aecae43eaa9b030ae5fb92b309ad", size = 266356, upload-time = "2024-08-27T20:51:24.146Z" },
+ { url = "https://files.pythonhosted.org/packages/05/46/9256dd162ea52790c127cb58cfc3b9e3413a6e3478917d1f811d420772ec/contourpy-1.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:834e0cfe17ba12f79963861e0f908556b2cedd52e1f75e6578801febcc6a9f49", size = 250915, upload-time = "2024-08-27T20:51:28.683Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/5d/3056c167fa4486900dfbd7e26a2fdc2338dc58eee36d490a0ed3ddda5ded/contourpy-1.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbc4c3217eee163fa3984fd1567632b48d6dfd29216da3ded3d7b844a8014a66", size = 310443, upload-time = "2024-08-27T20:51:33.675Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/c2/1a612e475492e07f11c8e267ea5ec1ce0d89971be496c195e27afa97e14a/contourpy-1.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4865cd1d419e0c7a7bf6de1777b185eebdc51470800a9f42b9e9decf17762081", size = 348548, upload-time = "2024-08-27T20:51:39.322Z" },
+ { url = "https://files.pythonhosted.org/packages/45/cf/2c2fc6bb5874158277b4faf136847f0689e1b1a1f640a36d76d52e78907c/contourpy-1.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:303c252947ab4b14c08afeb52375b26781ccd6a5ccd81abcdfc1fafd14cf93c1", size = 319118, upload-time = "2024-08-27T20:51:44.717Z" },
+ { url = "https://files.pythonhosted.org/packages/03/33/003065374f38894cdf1040cef474ad0546368eea7e3a51d48b8a423961f8/contourpy-1.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:637f674226be46f6ba372fd29d9523dd977a291f66ab2a74fbeb5530bb3f445d", size = 323162, upload-time = "2024-08-27T20:51:49.683Z" },
+ { url = "https://files.pythonhosted.org/packages/42/80/e637326e85e4105a802e42959f56cff2cd39a6b5ef68d5d9aee3ea5f0e4c/contourpy-1.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:76a896b2f195b57db25d6b44e7e03f221d32fe318d03ede41f8b4d9ba1bff53c", size = 1265396, upload-time = "2024-08-27T20:52:04.926Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/3b/8cbd6416ca1bbc0202b50f9c13b2e0b922b64be888f9d9ee88e6cfabfb51/contourpy-1.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e1fd23e9d01591bab45546c089ae89d926917a66dceb3abcf01f6105d927e2cb", size = 1324297, upload-time = "2024-08-27T20:52:21.843Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/2c/021a7afaa52fe891f25535506cc861c30c3c4e5a1c1ce94215e04b293e72/contourpy-1.3.0-cp311-cp311-win32.whl", hash = "sha256:d402880b84df3bec6eab53cd0cf802cae6a2ef9537e70cf75e91618a3801c20c", size = 171808, upload-time = "2024-08-27T20:52:25.163Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/2f/804f02ff30a7fae21f98198828d0857439ec4c91a96e20cf2d6c49372966/contourpy-1.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:6cb6cc968059db9c62cb35fbf70248f40994dfcd7aa10444bbf8b3faeb7c2d67", size = 217181, upload-time = "2024-08-27T20:52:29.13Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/92/8e0bbfe6b70c0e2d3d81272b58c98ac69ff1a4329f18c73bd64824d8b12e/contourpy-1.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:570ef7cf892f0afbe5b2ee410c507ce12e15a5fa91017a0009f79f7d93a1268f", size = 267838, upload-time = "2024-08-27T20:52:33.911Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/04/33351c5d5108460a8ce6d512307690b023f0cfcad5899499f5c83b9d63b1/contourpy-1.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:da84c537cb8b97d153e9fb208c221c45605f73147bd4cadd23bdae915042aad6", size = 251549, upload-time = "2024-08-27T20:52:39.179Z" },
+ { url = "https://files.pythonhosted.org/packages/51/3d/aa0fe6ae67e3ef9f178389e4caaaa68daf2f9024092aa3c6032e3d174670/contourpy-1.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0be4d8425bfa755e0fd76ee1e019636ccc7c29f77a7c86b4328a9eb6a26d0639", size = 303177, upload-time = "2024-08-27T20:52:44.789Z" },
+ { url = "https://files.pythonhosted.org/packages/56/c3/c85a7e3e0cab635575d3b657f9535443a6f5d20fac1a1911eaa4bbe1aceb/contourpy-1.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9c0da700bf58f6e0b65312d0a5e695179a71d0163957fa381bb3c1f72972537c", size = 341735, upload-time = "2024-08-27T20:52:51.05Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/8d/20f7a211a7be966a53f474bc90b1a8202e9844b3f1ef85f3ae45a77151ee/contourpy-1.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eb8b141bb00fa977d9122636b16aa67d37fd40a3d8b52dd837e536d64b9a4d06", size = 314679, upload-time = "2024-08-27T20:52:58.473Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/be/524e377567defac0e21a46e2a529652d165fed130a0d8a863219303cee18/contourpy-1.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3634b5385c6716c258d0419c46d05c8aa7dc8cb70326c9a4fb66b69ad2b52e09", size = 320549, upload-time = "2024-08-27T20:53:06.593Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/96/fdb2552a172942d888915f3a6663812e9bc3d359d53dafd4289a0fb462f0/contourpy-1.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0dce35502151b6bd35027ac39ba6e5a44be13a68f55735c3612c568cac3805fd", size = 1263068, upload-time = "2024-08-27T20:53:23.442Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/25/632eab595e3140adfa92f1322bf8915f68c932bac468e89eae9974cf1c00/contourpy-1.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:aea348f053c645100612b333adc5983d87be69acdc6d77d3169c090d3b01dc35", size = 1322833, upload-time = "2024-08-27T20:53:39.243Z" },
+ { url = "https://files.pythonhosted.org/packages/73/e3/69738782e315a1d26d29d71a550dbbe3eb6c653b028b150f70c1a5f4f229/contourpy-1.3.0-cp312-cp312-win32.whl", hash = "sha256:90f73a5116ad1ba7174341ef3ea5c3150ddf20b024b98fb0c3b29034752c8aeb", size = 172681, upload-time = "2024-08-27T20:53:43.05Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/89/9830ba00d88e43d15e53d64931e66b8792b46eb25e2050a88fec4a0df3d5/contourpy-1.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:b11b39aea6be6764f84360fce6c82211a9db32a7c7de8fa6dd5397cf1d079c3b", size = 218283, upload-time = "2024-08-27T20:53:47.232Z" },
+ { url = "https://files.pythonhosted.org/packages/53/a1/d20415febfb2267af2d7f06338e82171824d08614084714fb2c1dac9901f/contourpy-1.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3e1c7fa44aaae40a2247e2e8e0627f4bea3dd257014764aa644f319a5f8600e3", size = 267879, upload-time = "2024-08-27T20:53:51.597Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/45/5a28a3570ff6218d8bdfc291a272a20d2648104815f01f0177d103d985e1/contourpy-1.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:364174c2a76057feef647c802652f00953b575723062560498dc7930fc9b1cb7", size = 251573, upload-time = "2024-08-27T20:53:55.659Z" },
+ { url = "https://files.pythonhosted.org/packages/39/1c/d3f51540108e3affa84f095c8b04f0aa833bb797bc8baa218a952a98117d/contourpy-1.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32b238b3b3b649e09ce9aaf51f0c261d38644bdfa35cbaf7b263457850957a84", size = 303184, upload-time = "2024-08-27T20:54:00.225Z" },
+ { url = "https://files.pythonhosted.org/packages/00/56/1348a44fb6c3a558c1a3a0cd23d329d604c99d81bf5a4b58c6b71aab328f/contourpy-1.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d51fca85f9f7ad0b65b4b9fe800406d0d77017d7270d31ec3fb1cc07358fdea0", size = 340262, upload-time = "2024-08-27T20:54:05.234Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/23/00d665ba67e1bb666152131da07e0f24c95c3632d7722caa97fb61470eca/contourpy-1.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:732896af21716b29ab3e988d4ce14bc5133733b85956316fb0c56355f398099b", size = 313806, upload-time = "2024-08-27T20:54:09.889Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/42/3cf40f7040bb8362aea19af9a5fb7b32ce420f645dd1590edcee2c657cd5/contourpy-1.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d73f659398a0904e125280836ae6f88ba9b178b2fed6884f3b1f95b989d2c8da", size = 319710, upload-time = "2024-08-27T20:54:14.536Z" },
+ { url = "https://files.pythonhosted.org/packages/05/32/f3bfa3fc083b25e1a7ae09197f897476ee68e7386e10404bdf9aac7391f0/contourpy-1.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c6c7c2408b7048082932cf4e641fa3b8ca848259212f51c8c59c45aa7ac18f14", size = 1264107, upload-time = "2024-08-27T20:54:29.735Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/1e/1019d34473a736664f2439542b890b2dc4c6245f5c0d8cdfc0ccc2cab80c/contourpy-1.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f317576606de89da6b7e0861cf6061f6146ead3528acabff9236458a6ba467f8", size = 1322458, upload-time = "2024-08-27T20:54:45.507Z" },
+ { url = "https://files.pythonhosted.org/packages/22/85/4f8bfd83972cf8909a4d36d16b177f7b8bdd942178ea4bf877d4a380a91c/contourpy-1.3.0-cp313-cp313-win32.whl", hash = "sha256:31cd3a85dbdf1fc002280c65caa7e2b5f65e4a973fcdf70dd2fdcb9868069294", size = 172643, upload-time = "2024-08-27T20:55:52.754Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/4a/fb3c83c1baba64ba90443626c228ca14f19a87c51975d3b1de308dd2cf08/contourpy-1.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:4553c421929ec95fb07b3aaca0fae668b2eb5a5203d1217ca7c34c063c53d087", size = 218301, upload-time = "2024-08-27T20:55:56.509Z" },
+ { url = "https://files.pythonhosted.org/packages/76/65/702f4064f397821fea0cb493f7d3bc95a5d703e20954dce7d6d39bacf378/contourpy-1.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:345af746d7766821d05d72cb8f3845dfd08dd137101a2cb9b24de277d716def8", size = 278972, upload-time = "2024-08-27T20:54:50.347Z" },
+ { url = "https://files.pythonhosted.org/packages/80/85/21f5bba56dba75c10a45ec00ad3b8190dbac7fd9a8a8c46c6116c933e9cf/contourpy-1.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3bb3808858a9dc68f6f03d319acd5f1b8a337e6cdda197f02f4b8ff67ad2057b", size = 263375, upload-time = "2024-08-27T20:54:54.909Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/64/084c86ab71d43149f91ab3a4054ccf18565f0a8af36abfa92b1467813ed6/contourpy-1.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:420d39daa61aab1221567b42eecb01112908b2cab7f1b4106a52caaec8d36973", size = 307188, upload-time = "2024-08-27T20:55:00.184Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/ff/d61a4c288dc42da0084b8d9dc2aa219a850767165d7d9a9c364ff530b509/contourpy-1.3.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4d63ee447261e963af02642ffcb864e5a2ee4cbfd78080657a9880b8b1868e18", size = 345644, upload-time = "2024-08-27T20:55:05.673Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/aa/00d2313d35ec03f188e8f0786c2fc61f589306e02fdc158233697546fd58/contourpy-1.3.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:167d6c890815e1dac9536dca00828b445d5d0df4d6a8c6adb4a7ec3166812fa8", size = 317141, upload-time = "2024-08-27T20:55:11.047Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/6a/b5242c8cb32d87f6abf4f5e3044ca397cb1a76712e3fa2424772e3ff495f/contourpy-1.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:710a26b3dc80c0e4febf04555de66f5fd17e9cf7170a7b08000601a10570bda6", size = 323469, upload-time = "2024-08-27T20:55:15.914Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/a6/73e929d43028a9079aca4bde107494864d54f0d72d9db508a51ff0878593/contourpy-1.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:75ee7cb1a14c617f34a51d11fa7524173e56551646828353c4af859c56b766e2", size = 1260894, upload-time = "2024-08-27T20:55:31.553Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/1e/1e726ba66eddf21c940821df8cf1a7d15cb165f0682d62161eaa5e93dae1/contourpy-1.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:33c92cdae89ec5135d036e7218e69b0bb2851206077251f04a6c4e0e21f03927", size = 1314829, upload-time = "2024-08-27T20:55:47.837Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/e3/b9f72758adb6ef7397327ceb8b9c39c75711affb220e4f53c745ea1d5a9a/contourpy-1.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a11077e395f67ffc2c44ec2418cfebed032cd6da3022a94fc227b6faf8e2acb8", size = 265518, upload-time = "2024-08-27T20:56:01.333Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/22/19f5b948367ab5260fb41d842c7a78dae645603881ea6bc39738bcfcabf6/contourpy-1.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e8134301d7e204c88ed7ab50028ba06c683000040ede1d617298611f9dc6240c", size = 249350, upload-time = "2024-08-27T20:56:05.432Z" },
+ { url = "https://files.pythonhosted.org/packages/26/76/0c7d43263dd00ae21a91a24381b7e813d286a3294d95d179ef3a7b9fb1d7/contourpy-1.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e12968fdfd5bb45ffdf6192a590bd8ddd3ba9e58360b29683c6bb71a7b41edca", size = 309167, upload-time = "2024-08-27T20:56:10.034Z" },
+ { url = "https://files.pythonhosted.org/packages/96/3b/cadff6773e89f2a5a492c1a8068e21d3fccaf1a1c1df7d65e7c8e3ef60ba/contourpy-1.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fd2a0fc506eccaaa7595b7e1418951f213cf8255be2600f1ea1b61e46a60c55f", size = 348279, upload-time = "2024-08-27T20:56:15.41Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/86/158cc43aa549d2081a955ab11c6bdccc7a22caacc2af93186d26f5f48746/contourpy-1.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4cfb5c62ce023dfc410d6059c936dcf96442ba40814aefbfa575425a3a7f19dc", size = 318519, upload-time = "2024-08-27T20:56:21.813Z" },
+ { url = "https://files.pythonhosted.org/packages/05/11/57335544a3027e9b96a05948c32e566328e3a2f84b7b99a325b7a06d2b06/contourpy-1.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68a32389b06b82c2fdd68276148d7b9275b5f5cf13e5417e4252f6d1a34f72a2", size = 321922, upload-time = "2024-08-27T20:56:26.983Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/e3/02114f96543f4a1b694333b92a6dcd4f8eebbefcc3a5f3bbb1316634178f/contourpy-1.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:94e848a6b83da10898cbf1311a815f770acc9b6a3f2d646f330d57eb4e87592e", size = 1258017, upload-time = "2024-08-27T20:56:42.246Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/3b/bfe4c81c6d5881c1c643dde6620be0b42bf8aab155976dd644595cfab95c/contourpy-1.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:d78ab28a03c854a873787a0a42254a0ccb3cb133c672f645c9f9c8f3ae9d0800", size = 1316773, upload-time = "2024-08-27T20:56:58.58Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/17/c52d2970784383cafb0bd918b6fb036d98d96bbf0bc1befb5d1e31a07a70/contourpy-1.3.0-cp39-cp39-win32.whl", hash = "sha256:81cb5ed4952aae6014bc9d0421dec7c5835c9c8c31cdf51910b708f548cf58e5", size = 171353, upload-time = "2024-08-27T20:57:02.718Z" },
+ { url = "https://files.pythonhosted.org/packages/53/23/db9f69676308e094d3c45f20cc52e12d10d64f027541c995d89c11ad5c75/contourpy-1.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:14e262f67bd7e6eb6880bc564dcda30b15e351a594657e55b7eec94b6ef72843", size = 211817, upload-time = "2024-08-27T20:57:06.328Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/09/60e486dc2b64c94ed33e58dcfb6f808192c03dfc5574c016218b9b7680dc/contourpy-1.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fe41b41505a5a33aeaed2a613dccaeaa74e0e3ead6dd6fd3a118fb471644fd6c", size = 261886, upload-time = "2024-08-27T20:57:10.863Z" },
+ { url = "https://files.pythonhosted.org/packages/19/20/b57f9f7174fcd439a7789fb47d764974ab646fa34d1790551de386457a8e/contourpy-1.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eca7e17a65f72a5133bdbec9ecf22401c62bcf4821361ef7811faee695799779", size = 311008, upload-time = "2024-08-27T20:57:15.588Z" },
+ { url = "https://files.pythonhosted.org/packages/74/fc/5040d42623a1845d4f17a418e590fd7a79ae8cb2bad2b2f83de63c3bdca4/contourpy-1.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:1ec4dc6bf570f5b22ed0d7efba0dfa9c5b9e0431aeea7581aa217542d9e809a4", size = 215690, upload-time = "2024-08-27T20:57:19.321Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/24/dc3dcd77ac7460ab7e9d2b01a618cb31406902e50e605a8d6091f0a8f7cc/contourpy-1.3.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:00ccd0dbaad6d804ab259820fa7cb0b8036bda0686ef844d24125d8287178ce0", size = 261894, upload-time = "2024-08-27T20:57:23.873Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/db/531642a01cfec39d1682e46b5457b07cf805e3c3c584ec27e2a6223f8f6c/contourpy-1.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ca947601224119117f7c19c9cdf6b3ab54c5726ef1d906aa4a69dfb6dd58102", size = 311099, upload-time = "2024-08-27T20:57:28.58Z" },
+ { url = "https://files.pythonhosted.org/packages/38/1e/94bda024d629f254143a134eead69e21c836429a2a6ce82209a00ddcb79a/contourpy-1.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c6ec93afeb848a0845a18989da3beca3eec2c0f852322efe21af1931147d12cb", size = 215838, upload-time = "2024-08-27T20:57:32.913Z" },
+]
+
+[[package]]
+name = "contourpy"
+version = "1.3.2"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version == '3.10.*'",
+]
+dependencies = [
+ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54", size = 13466130, upload-time = "2025-04-15T17:47:53.79Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/12/a3/da4153ec8fe25d263aa48c1a4cbde7f49b59af86f0b6f7862788c60da737/contourpy-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba38e3f9f330af820c4b27ceb4b9c7feee5fe0493ea53a8720f4792667465934", size = 268551, upload-time = "2025-04-15T17:34:46.581Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/6c/330de89ae1087eb622bfca0177d32a7ece50c3ef07b28002de4757d9d875/contourpy-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc41ba0714aa2968d1f8674ec97504a8f7e334f48eeacebcaa6256213acb0989", size = 253399, upload-time = "2025-04-15T17:34:51.427Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/bd/20c6726b1b7f81a8bee5271bed5c165f0a8e1f572578a9d27e2ccb763cb2/contourpy-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9be002b31c558d1ddf1b9b415b162c603405414bacd6932d031c5b5a8b757f0d", size = 312061, upload-time = "2025-04-15T17:34:55.961Z" },
+ { url = "https://files.pythonhosted.org/packages/22/fc/a9665c88f8a2473f823cf1ec601de9e5375050f1958cbb356cdf06ef1ab6/contourpy-1.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8d2e74acbcba3bfdb6d9d8384cdc4f9260cae86ed9beee8bd5f54fee49a430b9", size = 351956, upload-time = "2025-04-15T17:35:00.992Z" },
+ { url = "https://files.pythonhosted.org/packages/25/eb/9f0a0238f305ad8fb7ef42481020d6e20cf15e46be99a1fcf939546a177e/contourpy-1.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e259bced5549ac64410162adc973c5e2fb77f04df4a439d00b478e57a0e65512", size = 320872, upload-time = "2025-04-15T17:35:06.177Z" },
+ { url = "https://files.pythonhosted.org/packages/32/5c/1ee32d1c7956923202f00cf8d2a14a62ed7517bdc0ee1e55301227fc273c/contourpy-1.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad687a04bc802cbe8b9c399c07162a3c35e227e2daccf1668eb1f278cb698631", size = 325027, upload-time = "2025-04-15T17:35:11.244Z" },
+ { url = "https://files.pythonhosted.org/packages/83/bf/9baed89785ba743ef329c2b07fd0611d12bfecbedbdd3eeecf929d8d3b52/contourpy-1.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cdd22595308f53ef2f891040ab2b93d79192513ffccbd7fe19be7aa773a5e09f", size = 1306641, upload-time = "2025-04-15T17:35:26.701Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/cc/74e5e83d1e35de2d28bd97033426b450bc4fd96e092a1f7a63dc7369b55d/contourpy-1.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b4f54d6a2defe9f257327b0f243612dd051cc43825587520b1bf74a31e2f6ef2", size = 1374075, upload-time = "2025-04-15T17:35:43.204Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/42/17f3b798fd5e033b46a16f8d9fcb39f1aba051307f5ebf441bad1ecf78f8/contourpy-1.3.2-cp310-cp310-win32.whl", hash = "sha256:f939a054192ddc596e031e50bb13b657ce318cf13d264f095ce9db7dc6ae81c0", size = 177534, upload-time = "2025-04-15T17:35:46.554Z" },
+ { url = "https://files.pythonhosted.org/packages/54/ec/5162b8582f2c994721018d0c9ece9dc6ff769d298a8ac6b6a652c307e7df/contourpy-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:c440093bbc8fc21c637c03bafcbef95ccd963bc6e0514ad887932c18ca2a759a", size = 221188, upload-time = "2025-04-15T17:35:50.064Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/b9/ede788a0b56fc5b071639d06c33cb893f68b1178938f3425debebe2dab78/contourpy-1.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6a37a2fb93d4df3fc4c0e363ea4d16f83195fc09c891bc8ce072b9d084853445", size = 269636, upload-time = "2025-04-15T17:35:54.473Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/75/3469f011d64b8bbfa04f709bfc23e1dd71be54d05b1b083be9f5b22750d1/contourpy-1.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b7cd50c38f500bbcc9b6a46643a40e0913673f869315d8e70de0438817cb7773", size = 254636, upload-time = "2025-04-15T17:35:58.283Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/2f/95adb8dae08ce0ebca4fd8e7ad653159565d9739128b2d5977806656fcd2/contourpy-1.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6658ccc7251a4433eebd89ed2672c2ed96fba367fd25ca9512aa92a4b46c4f1", size = 313053, upload-time = "2025-04-15T17:36:03.235Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/a6/8ccf97a50f31adfa36917707fe39c9a0cbc24b3bbb58185577f119736cc9/contourpy-1.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:70771a461aaeb335df14deb6c97439973d253ae70660ca085eec25241137ef43", size = 352985, upload-time = "2025-04-15T17:36:08.275Z" },
+ { url = "https://files.pythonhosted.org/packages/1d/b6/7925ab9b77386143f39d9c3243fdd101621b4532eb126743201160ffa7e6/contourpy-1.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65a887a6e8c4cd0897507d814b14c54a8c2e2aa4ac9f7686292f9769fcf9a6ab", size = 323750, upload-time = "2025-04-15T17:36:13.29Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/f3/20c5d1ef4f4748e52d60771b8560cf00b69d5c6368b5c2e9311bcfa2a08b/contourpy-1.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3859783aefa2b8355697f16642695a5b9792e7a46ab86da1118a4a23a51a33d7", size = 326246, upload-time = "2025-04-15T17:36:18.329Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/e5/9dae809e7e0b2d9d70c52b3d24cba134dd3dad979eb3e5e71f5df22ed1f5/contourpy-1.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:eab0f6db315fa4d70f1d8ab514e527f0366ec021ff853d7ed6a2d33605cf4b83", size = 1308728, upload-time = "2025-04-15T17:36:33.878Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/4a/0058ba34aeea35c0b442ae61a4f4d4ca84d6df8f91309bc2d43bb8dd248f/contourpy-1.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d91a3ccc7fea94ca0acab82ceb77f396d50a1f67412efe4c526f5d20264e6ecd", size = 1375762, upload-time = "2025-04-15T17:36:51.295Z" },
+ { url = "https://files.pythonhosted.org/packages/09/33/7174bdfc8b7767ef2c08ed81244762d93d5c579336fc0b51ca57b33d1b80/contourpy-1.3.2-cp311-cp311-win32.whl", hash = "sha256:1c48188778d4d2f3d48e4643fb15d8608b1d01e4b4d6b0548d9b336c28fc9b6f", size = 178196, upload-time = "2025-04-15T17:36:55.002Z" },
+ { url = "https://files.pythonhosted.org/packages/5e/fe/4029038b4e1c4485cef18e480b0e2cd2d755448bb071eb9977caac80b77b/contourpy-1.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:5ebac872ba09cb8f2131c46b8739a7ff71de28a24c869bcad554477eb089a878", size = 222017, upload-time = "2025-04-15T17:36:58.576Z" },
+ { url = "https://files.pythonhosted.org/packages/34/f7/44785876384eff370c251d58fd65f6ad7f39adce4a093c934d4a67a7c6b6/contourpy-1.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4caf2bcd2969402bf77edc4cb6034c7dd7c0803213b3523f111eb7460a51b8d2", size = 271580, upload-time = "2025-04-15T17:37:03.105Z" },
+ { url = "https://files.pythonhosted.org/packages/93/3b/0004767622a9826ea3d95f0e9d98cd8729015768075d61f9fea8eeca42a8/contourpy-1.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:82199cb78276249796419fe36b7386bd8d2cc3f28b3bc19fe2454fe2e26c4c15", size = 255530, upload-time = "2025-04-15T17:37:07.026Z" },
+ { url = "https://files.pythonhosted.org/packages/e7/bb/7bd49e1f4fa805772d9fd130e0d375554ebc771ed7172f48dfcd4ca61549/contourpy-1.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:106fab697af11456fcba3e352ad50effe493a90f893fca6c2ca5c033820cea92", size = 307688, upload-time = "2025-04-15T17:37:11.481Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/97/e1d5dbbfa170725ef78357a9a0edc996b09ae4af170927ba8ce977e60a5f/contourpy-1.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d14f12932a8d620e307f715857107b1d1845cc44fdb5da2bc8e850f5ceba9f87", size = 347331, upload-time = "2025-04-15T17:37:18.212Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/66/e69e6e904f5ecf6901be3dd16e7e54d41b6ec6ae3405a535286d4418ffb4/contourpy-1.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:532fd26e715560721bb0d5fc7610fce279b3699b018600ab999d1be895b09415", size = 318963, upload-time = "2025-04-15T17:37:22.76Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/32/b8a1c8965e4f72482ff2d1ac2cd670ce0b542f203c8e1d34e7c3e6925da7/contourpy-1.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b383144cf2d2c29f01a1e8170f50dacf0eac02d64139dcd709a8ac4eb3cfe", size = 323681, upload-time = "2025-04-15T17:37:33.001Z" },
+ { url = "https://files.pythonhosted.org/packages/30/c6/12a7e6811d08757c7162a541ca4c5c6a34c0f4e98ef2b338791093518e40/contourpy-1.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c49f73e61f1f774650a55d221803b101d966ca0c5a2d6d5e4320ec3997489441", size = 1308674, upload-time = "2025-04-15T17:37:48.64Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/8a/bebe5a3f68b484d3a2b8ffaf84704b3e343ef1addea528132ef148e22b3b/contourpy-1.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3d80b2c0300583228ac98d0a927a1ba6a2ba6b8a742463c564f1d419ee5b211e", size = 1380480, upload-time = "2025-04-15T17:38:06.7Z" },
+ { url = "https://files.pythonhosted.org/packages/34/db/fcd325f19b5978fb509a7d55e06d99f5f856294c1991097534360b307cf1/contourpy-1.3.2-cp312-cp312-win32.whl", hash = "sha256:90df94c89a91b7362e1142cbee7568f86514412ab8a2c0d0fca72d7e91b62912", size = 178489, upload-time = "2025-04-15T17:38:10.338Z" },
+ { url = "https://files.pythonhosted.org/packages/01/c8/fadd0b92ffa7b5eb5949bf340a63a4a496a6930a6c37a7ba0f12acb076d6/contourpy-1.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:8c942a01d9163e2e5cfb05cb66110121b8d07ad438a17f9e766317bcb62abf73", size = 223042, upload-time = "2025-04-15T17:38:14.239Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/61/5673f7e364b31e4e7ef6f61a4b5121c5f170f941895912f773d95270f3a2/contourpy-1.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:de39db2604ae755316cb5967728f4bea92685884b1e767b7c24e983ef5f771cb", size = 271630, upload-time = "2025-04-15T17:38:19.142Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/66/a40badddd1223822c95798c55292844b7e871e50f6bfd9f158cb25e0bd39/contourpy-1.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3f9e896f447c5c8618f1edb2bafa9a4030f22a575ec418ad70611450720b5b08", size = 255670, upload-time = "2025-04-15T17:38:23.688Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/c7/cf9fdee8200805c9bc3b148f49cb9482a4e3ea2719e772602a425c9b09f8/contourpy-1.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71e2bd4a1c4188f5c2b8d274da78faab884b59df20df63c34f74aa1813c4427c", size = 306694, upload-time = "2025-04-15T17:38:28.238Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/e7/ccb9bec80e1ba121efbffad7f38021021cda5be87532ec16fd96533bb2e0/contourpy-1.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de425af81b6cea33101ae95ece1f696af39446db9682a0b56daaa48cfc29f38f", size = 345986, upload-time = "2025-04-15T17:38:33.502Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/49/ca13bb2da90391fa4219fdb23b078d6065ada886658ac7818e5441448b78/contourpy-1.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:977e98a0e0480d3fe292246417239d2d45435904afd6d7332d8455981c408b85", size = 318060, upload-time = "2025-04-15T17:38:38.672Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/65/5245ce8c548a8422236c13ffcdcdada6a2a812c361e9e0c70548bb40b661/contourpy-1.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:434f0adf84911c924519d2b08fc10491dd282b20bdd3fa8f60fd816ea0b48841", size = 322747, upload-time = "2025-04-15T17:38:43.712Z" },
+ { url = "https://files.pythonhosted.org/packages/72/30/669b8eb48e0a01c660ead3752a25b44fdb2e5ebc13a55782f639170772f9/contourpy-1.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c66c4906cdbc50e9cba65978823e6e00b45682eb09adbb78c9775b74eb222422", size = 1308895, upload-time = "2025-04-15T17:39:00.224Z" },
+ { url = "https://files.pythonhosted.org/packages/05/5a/b569f4250decee6e8d54498be7bdf29021a4c256e77fe8138c8319ef8eb3/contourpy-1.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8b7fc0cd78ba2f4695fd0a6ad81a19e7e3ab825c31b577f384aa9d7817dc3bef", size = 1379098, upload-time = "2025-04-15T17:43:29.649Z" },
+ { url = "https://files.pythonhosted.org/packages/19/ba/b227c3886d120e60e41b28740ac3617b2f2b971b9f601c835661194579f1/contourpy-1.3.2-cp313-cp313-win32.whl", hash = "sha256:15ce6ab60957ca74cff444fe66d9045c1fd3e92c8936894ebd1f3eef2fff075f", size = 178535, upload-time = "2025-04-15T17:44:44.532Z" },
+ { url = "https://files.pythonhosted.org/packages/12/6e/2fed56cd47ca739b43e892707ae9a13790a486a3173be063681ca67d2262/contourpy-1.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e1578f7eafce927b168752ed7e22646dad6cd9bca673c60bff55889fa236ebf9", size = 223096, upload-time = "2025-04-15T17:44:48.194Z" },
+ { url = "https://files.pythonhosted.org/packages/54/4c/e76fe2a03014a7c767d79ea35c86a747e9325537a8b7627e0e5b3ba266b4/contourpy-1.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0475b1f6604896bc7c53bb070e355e9321e1bc0d381735421a2d2068ec56531f", size = 285090, upload-time = "2025-04-15T17:43:34.084Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/e2/5aba47debd55d668e00baf9651b721e7733975dc9fc27264a62b0dd26eb8/contourpy-1.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c85bb486e9be652314bb5b9e2e3b0d1b2e643d5eec4992c0fbe8ac71775da739", size = 268643, upload-time = "2025-04-15T17:43:38.626Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/37/cd45f1f051fe6230f751cc5cdd2728bb3a203f5619510ef11e732109593c/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:745b57db7758f3ffc05a10254edd3182a2a83402a89c00957a8e8a22f5582823", size = 310443, upload-time = "2025-04-15T17:43:44.522Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/a2/36ea6140c306c9ff6dd38e3bcec80b3b018474ef4d17eb68ceecd26675f4/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:970e9173dbd7eba9b4e01aab19215a48ee5dd3f43cef736eebde064a171f89a5", size = 349865, upload-time = "2025-04-15T17:43:49.545Z" },
+ { url = "https://files.pythonhosted.org/packages/95/b7/2fc76bc539693180488f7b6cc518da7acbbb9e3b931fd9280504128bf956/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6c4639a9c22230276b7bffb6a850dfc8258a2521305e1faefe804d006b2e532", size = 321162, upload-time = "2025-04-15T17:43:54.203Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/10/76d4f778458b0aa83f96e59d65ece72a060bacb20cfbee46cf6cd5ceba41/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc829960f34ba36aad4302e78eabf3ef16a3a100863f0d4eeddf30e8a485a03b", size = 327355, upload-time = "2025-04-15T17:44:01.025Z" },
+ { url = "https://files.pythonhosted.org/packages/43/a3/10cf483ea683f9f8ab096c24bad3cce20e0d1dd9a4baa0e2093c1c962d9d/contourpy-1.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d32530b534e986374fc19eaa77fcb87e8a99e5431499949b828312bdcd20ac52", size = 1307935, upload-time = "2025-04-15T17:44:17.322Z" },
+ { url = "https://files.pythonhosted.org/packages/78/73/69dd9a024444489e22d86108e7b913f3528f56cfc312b5c5727a44188471/contourpy-1.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e298e7e70cf4eb179cc1077be1c725b5fd131ebc81181bf0c03525c8abc297fd", size = 1372168, upload-time = "2025-04-15T17:44:33.43Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/1b/96d586ccf1b1a9d2004dd519b25fbf104a11589abfd05484ff12199cca21/contourpy-1.3.2-cp313-cp313t-win32.whl", hash = "sha256:d0e589ae0d55204991450bb5c23f571c64fe43adaa53f93fc902a84c96f52fe1", size = 189550, upload-time = "2025-04-15T17:44:37.092Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/e6/6000d0094e8a5e32ad62591c8609e269febb6e4db83a1c75ff8868b42731/contourpy-1.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:78e9253c3de756b3f6a5174d024c4835acd59eb3f8e2ca13e775dbffe1558f69", size = 238214, upload-time = "2025-04-15T17:44:40.827Z" },
+ { url = "https://files.pythonhosted.org/packages/33/05/b26e3c6ecc05f349ee0013f0bb850a761016d89cec528a98193a48c34033/contourpy-1.3.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fd93cc7f3139b6dd7aab2f26a90dde0aa9fc264dbf70f6740d498a70b860b82c", size = 265681, upload-time = "2025-04-15T17:44:59.314Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/25/ac07d6ad12affa7d1ffed11b77417d0a6308170f44ff20fa1d5aa6333f03/contourpy-1.3.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:107ba8a6a7eec58bb475329e6d3b95deba9440667c4d62b9b6063942b61d7f16", size = 315101, upload-time = "2025-04-15T17:45:04.165Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/4d/5bb3192bbe9d3f27e3061a6a8e7733c9120e203cb8515767d30973f71030/contourpy-1.3.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ded1706ed0c1049224531b81128efbd5084598f18d8a2d9efae833edbd2b40ad", size = 220599, upload-time = "2025-04-15T17:45:08.456Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/c0/91f1215d0d9f9f343e4773ba6c9b89e8c0cc7a64a6263f21139da639d848/contourpy-1.3.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5f5964cdad279256c084b69c3f412b7801e15356b16efa9d78aa974041903da0", size = 266807, upload-time = "2025-04-15T17:45:15.535Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/79/6be7e90c955c0487e7712660d6cead01fa17bff98e0ea275737cc2bc8e71/contourpy-1.3.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49b65a95d642d4efa8f64ba12558fcb83407e58a2dfba9d796d77b63ccfcaff5", size = 318729, upload-time = "2025-04-15T17:45:20.166Z" },
+ { url = "https://files.pythonhosted.org/packages/87/68/7f46fb537958e87427d98a4074bcde4b67a70b04900cfc5ce29bc2f556c1/contourpy-1.3.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:8c5acb8dddb0752bf252e01a3035b21443158910ac16a3b0d20e7fed7d534ce5", size = 221791, upload-time = "2025-04-15T17:45:24.794Z" },
+]
+
+[[package]]
+name = "contourpy"
+version = "1.3.3"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version >= '3.11'",
+]
+dependencies = [
+ { name = "numpy", version = "2.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174, upload-time = "2025-07-26T12:03:12.549Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/91/2e/c4390a31919d8a78b90e8ecf87cd4b4c4f05a5b48d05ec17db8e5404c6f4/contourpy-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:709a48ef9a690e1343202916450bc48b9e51c049b089c7f79a267b46cffcdaa1", size = 288773, upload-time = "2025-07-26T12:01:02.277Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/44/c4b0b6095fef4dc9c420e041799591e3b63e9619e3044f7f4f6c21c0ab24/contourpy-1.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:23416f38bfd74d5d28ab8429cc4d63fa67d5068bd711a85edb1c3fb0c3e2f381", size = 270149, upload-time = "2025-07-26T12:01:04.072Z" },
+ { url = "https://files.pythonhosted.org/packages/30/2e/dd4ced42fefac8470661d7cb7e264808425e6c5d56d175291e93890cce09/contourpy-1.3.3-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:929ddf8c4c7f348e4c0a5a3a714b5c8542ffaa8c22954862a46ca1813b667ee7", size = 329222, upload-time = "2025-07-26T12:01:05.688Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/74/cc6ec2548e3d276c71389ea4802a774b7aa3558223b7bade3f25787fafc2/contourpy-1.3.3-cp311-cp311-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9e999574eddae35f1312c2b4b717b7885d4edd6cb46700e04f7f02db454e67c1", size = 377234, upload-time = "2025-07-26T12:01:07.054Z" },
+ { url = "https://files.pythonhosted.org/packages/03/b3/64ef723029f917410f75c09da54254c5f9ea90ef89b143ccadb09df14c15/contourpy-1.3.3-cp311-cp311-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0bf67e0e3f482cb69779dd3061b534eb35ac9b17f163d851e2a547d56dba0a3a", size = 380555, upload-time = "2025-07-26T12:01:08.801Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/4b/6157f24ca425b89fe2eb7e7be642375711ab671135be21e6faa100f7448c/contourpy-1.3.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:51e79c1f7470158e838808d4a996fa9bac72c498e93d8ebe5119bc1e6becb0db", size = 355238, upload-time = "2025-07-26T12:01:10.319Z" },
+ { url = "https://files.pythonhosted.org/packages/98/56/f914f0dd678480708a04cfd2206e7c382533249bc5001eb9f58aa693e200/contourpy-1.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:598c3aaece21c503615fd59c92a3598b428b2f01bfb4b8ca9c4edeecc2438620", size = 1326218, upload-time = "2025-07-26T12:01:12.659Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/d7/4a972334a0c971acd5172389671113ae82aa7527073980c38d5868ff1161/contourpy-1.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:322ab1c99b008dad206d406bb61d014cf0174df491ae9d9d0fac6a6fda4f977f", size = 1392867, upload-time = "2025-07-26T12:01:15.533Z" },
+ { url = "https://files.pythonhosted.org/packages/75/3e/f2cc6cd56dc8cff46b1a56232eabc6feea52720083ea71ab15523daab796/contourpy-1.3.3-cp311-cp311-win32.whl", hash = "sha256:fd907ae12cd483cd83e414b12941c632a969171bf90fc937d0c9f268a31cafff", size = 183677, upload-time = "2025-07-26T12:01:17.088Z" },
+ { url = "https://files.pythonhosted.org/packages/98/4b/9bd370b004b5c9d8045c6c33cf65bae018b27aca550a3f657cdc99acdbd8/contourpy-1.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:3519428f6be58431c56581f1694ba8e50626f2dd550af225f82fb5f5814d2a42", size = 225234, upload-time = "2025-07-26T12:01:18.256Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/b6/71771e02c2e004450c12b1120a5f488cad2e4d5b590b1af8bad060360fe4/contourpy-1.3.3-cp311-cp311-win_arm64.whl", hash = "sha256:15ff10bfada4bf92ec8b31c62bf7c1834c244019b4a33095a68000d7075df470", size = 193123, upload-time = "2025-07-26T12:01:19.848Z" },
+ { url = "https://files.pythonhosted.org/packages/be/45/adfee365d9ea3d853550b2e735f9d66366701c65db7855cd07621732ccfc/contourpy-1.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b08a32ea2f8e42cf1d4be3169a98dd4be32bafe4f22b6c4cb4ba810fa9e5d2cb", size = 293419, upload-time = "2025-07-26T12:01:21.16Z" },
+ { url = "https://files.pythonhosted.org/packages/53/3e/405b59cfa13021a56bba395a6b3aca8cec012b45bf177b0eaf7a202cde2c/contourpy-1.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:556dba8fb6f5d8742f2923fe9457dbdd51e1049c4a43fd3986a0b14a1d815fc6", size = 273979, upload-time = "2025-07-26T12:01:22.448Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/1c/a12359b9b2ca3a845e8f7f9ac08bdf776114eb931392fcad91743e2ea17b/contourpy-1.3.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92d9abc807cf7d0e047b95ca5d957cf4792fcd04e920ca70d48add15c1a90ea7", size = 332653, upload-time = "2025-07-26T12:01:24.155Z" },
+ { url = "https://files.pythonhosted.org/packages/63/12/897aeebfb475b7748ea67b61e045accdfcf0d971f8a588b67108ed7f5512/contourpy-1.3.3-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2e8faa0ed68cb29af51edd8e24798bb661eac3bd9f65420c1887b6ca89987c8", size = 379536, upload-time = "2025-07-26T12:01:25.91Z" },
+ { url = "https://files.pythonhosted.org/packages/43/8a/a8c584b82deb248930ce069e71576fc09bd7174bbd35183b7943fb1064fd/contourpy-1.3.3-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:626d60935cf668e70a5ce6ff184fd713e9683fb458898e4249b63be9e28286ea", size = 384397, upload-time = "2025-07-26T12:01:27.152Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/8f/ec6289987824b29529d0dfda0d74a07cec60e54b9c92f3c9da4c0ac732de/contourpy-1.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d00e655fcef08aba35ec9610536bfe90267d7ab5ba944f7032549c55a146da1", size = 362601, upload-time = "2025-07-26T12:01:28.808Z" },
+ { url = "https://files.pythonhosted.org/packages/05/0a/a3fe3be3ee2dceb3e615ebb4df97ae6f3828aa915d3e10549ce016302bd1/contourpy-1.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:451e71b5a7d597379ef572de31eeb909a87246974d960049a9848c3bc6c41bf7", size = 1331288, upload-time = "2025-07-26T12:01:31.198Z" },
+ { url = "https://files.pythonhosted.org/packages/33/1d/acad9bd4e97f13f3e2b18a3977fe1b4a37ecf3d38d815333980c6c72e963/contourpy-1.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:459c1f020cd59fcfe6650180678a9993932d80d44ccde1fa1868977438f0b411", size = 1403386, upload-time = "2025-07-26T12:01:33.947Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/8f/5847f44a7fddf859704217a99a23a4f6417b10e5ab1256a179264561540e/contourpy-1.3.3-cp312-cp312-win32.whl", hash = "sha256:023b44101dfe49d7d53932be418477dba359649246075c996866106da069af69", size = 185018, upload-time = "2025-07-26T12:01:35.64Z" },
+ { url = "https://files.pythonhosted.org/packages/19/e8/6026ed58a64563186a9ee3f29f41261fd1828f527dd93d33b60feca63352/contourpy-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:8153b8bfc11e1e4d75bcb0bff1db232f9e10b274e0929de9d608027e0d34ff8b", size = 226567, upload-time = "2025-07-26T12:01:36.804Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/e2/f05240d2c39a1ed228d8328a78b6f44cd695f7ef47beb3e684cf93604f86/contourpy-1.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:07ce5ed73ecdc4a03ffe3e1b3e3c1166db35ae7584be76f65dbbe28a7791b0cc", size = 193655, upload-time = "2025-07-26T12:01:37.999Z" },
+ { url = "https://files.pythonhosted.org/packages/68/35/0167aad910bbdb9599272bd96d01a9ec6852f36b9455cf2ca67bd4cc2d23/contourpy-1.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:177fb367556747a686509d6fef71d221a4b198a3905fe824430e5ea0fda54eb5", size = 293257, upload-time = "2025-07-26T12:01:39.367Z" },
+ { url = "https://files.pythonhosted.org/packages/96/e4/7adcd9c8362745b2210728f209bfbcf7d91ba868a2c5f40d8b58f54c509b/contourpy-1.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d002b6f00d73d69333dac9d0b8d5e84d9724ff9ef044fd63c5986e62b7c9e1b1", size = 274034, upload-time = "2025-07-26T12:01:40.645Z" },
+ { url = "https://files.pythonhosted.org/packages/73/23/90e31ceeed1de63058a02cb04b12f2de4b40e3bef5e082a7c18d9c8ae281/contourpy-1.3.3-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:348ac1f5d4f1d66d3322420f01d42e43122f43616e0f194fc1c9f5d830c5b286", size = 334672, upload-time = "2025-07-26T12:01:41.942Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/93/b43d8acbe67392e659e1d984700e79eb67e2acb2bd7f62012b583a7f1b55/contourpy-1.3.3-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:655456777ff65c2c548b7c454af9c6f33f16c8884f11083244b5819cc214f1b5", size = 381234, upload-time = "2025-07-26T12:01:43.499Z" },
+ { url = "https://files.pythonhosted.org/packages/46/3b/bec82a3ea06f66711520f75a40c8fc0b113b2a75edb36aa633eb11c4f50f/contourpy-1.3.3-cp313-cp313-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:644a6853d15b2512d67881586bd03f462c7ab755db95f16f14d7e238f2852c67", size = 385169, upload-time = "2025-07-26T12:01:45.219Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/32/e0f13a1c5b0f8572d0ec6ae2f6c677b7991fafd95da523159c19eff0696a/contourpy-1.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4debd64f124ca62069f313a9cb86656ff087786016d76927ae2cf37846b006c9", size = 362859, upload-time = "2025-07-26T12:01:46.519Z" },
+ { url = "https://files.pythonhosted.org/packages/33/71/e2a7945b7de4e58af42d708a219f3b2f4cff7386e6b6ab0a0fa0033c49a9/contourpy-1.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a15459b0f4615b00bbd1e91f1b9e19b7e63aea7483d03d804186f278c0af2659", size = 1332062, upload-time = "2025-07-26T12:01:48.964Z" },
+ { url = "https://files.pythonhosted.org/packages/12/fc/4e87ac754220ccc0e807284f88e943d6d43b43843614f0a8afa469801db0/contourpy-1.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca0fdcd73925568ca027e0b17ab07aad764be4706d0a925b89227e447d9737b7", size = 1403932, upload-time = "2025-07-26T12:01:51.979Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/2e/adc197a37443f934594112222ac1aa7dc9a98faf9c3842884df9a9d8751d/contourpy-1.3.3-cp313-cp313-win32.whl", hash = "sha256:b20c7c9a3bf701366556e1b1984ed2d0cedf999903c51311417cf5f591d8c78d", size = 185024, upload-time = "2025-07-26T12:01:53.245Z" },
+ { url = "https://files.pythonhosted.org/packages/18/0b/0098c214843213759692cc638fce7de5c289200a830e5035d1791d7a2338/contourpy-1.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:1cadd8b8969f060ba45ed7c1b714fe69185812ab43bd6b86a9123fe8f99c3263", size = 226578, upload-time = "2025-07-26T12:01:54.422Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/9a/2f6024a0c5995243cd63afdeb3651c984f0d2bc727fd98066d40e141ad73/contourpy-1.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:fd914713266421b7536de2bfa8181aa8c699432b6763a0ea64195ebe28bff6a9", size = 193524, upload-time = "2025-07-26T12:01:55.73Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/b3/f8a1a86bd3298513f500e5b1f5fd92b69896449f6cab6a146a5d52715479/contourpy-1.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:88df9880d507169449d434c293467418b9f6cbe82edd19284aa0409e7fdb933d", size = 306730, upload-time = "2025-07-26T12:01:57.051Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/11/4780db94ae62fc0c2053909b65dc3246bd7cecfc4f8a20d957ad43aa4ad8/contourpy-1.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d06bb1f751ba5d417047db62bca3c8fde202b8c11fb50742ab3ab962c81e8216", size = 287897, upload-time = "2025-07-26T12:01:58.663Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/15/e59f5f3ffdd6f3d4daa3e47114c53daabcb18574a26c21f03dc9e4e42ff0/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e4e6b05a45525357e382909a4c1600444e2a45b4795163d3b22669285591c1ae", size = 326751, upload-time = "2025-07-26T12:02:00.343Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/81/03b45cfad088e4770b1dcf72ea78d3802d04200009fb364d18a493857210/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ab3074b48c4e2cf1a960e6bbeb7f04566bf36b1861d5c9d4d8ac04b82e38ba20", size = 375486, upload-time = "2025-07-26T12:02:02.128Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/ba/49923366492ffbdd4486e970d421b289a670ae8cf539c1ea9a09822b371a/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c3d53c796f8647d6deb1abe867daeb66dcc8a97e8455efa729516b997b8ed99", size = 388106, upload-time = "2025-07-26T12:02:03.615Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/52/5b00ea89525f8f143651f9f03a0df371d3cbd2fccd21ca9b768c7a6500c2/contourpy-1.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50ed930df7289ff2a8d7afeb9603f8289e5704755c7e5c3bbd929c90c817164b", size = 352548, upload-time = "2025-07-26T12:02:05.165Z" },
+ { url = "https://files.pythonhosted.org/packages/32/1d/a209ec1a3a3452d490f6b14dd92e72280c99ae3d1e73da74f8277d4ee08f/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4feffb6537d64b84877da813a5c30f1422ea5739566abf0bd18065ac040e120a", size = 1322297, upload-time = "2025-07-26T12:02:07.379Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/9e/46f0e8ebdd884ca0e8877e46a3f4e633f6c9c8c4f3f6e72be3fe075994aa/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2b7e9480ffe2b0cd2e787e4df64270e3a0440d9db8dc823312e2c940c167df7e", size = 1391023, upload-time = "2025-07-26T12:02:10.171Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/70/f308384a3ae9cd2209e0849f33c913f658d3326900d0ff5d378d6a1422d2/contourpy-1.3.3-cp313-cp313t-win32.whl", hash = "sha256:283edd842a01e3dcd435b1c5116798d661378d83d36d337b8dde1d16a5fc9ba3", size = 196157, upload-time = "2025-07-26T12:02:11.488Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/dd/880f890a6663b84d9e34a6f88cded89d78f0091e0045a284427cb6b18521/contourpy-1.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:87acf5963fc2b34825e5b6b048f40e3635dd547f590b04d2ab317c2619ef7ae8", size = 240570, upload-time = "2025-07-26T12:02:12.754Z" },
+ { url = "https://files.pythonhosted.org/packages/80/99/2adc7d8ffead633234817ef8e9a87115c8a11927a94478f6bb3d3f4d4f7d/contourpy-1.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:3c30273eb2a55024ff31ba7d052dde990d7d8e5450f4bbb6e913558b3d6c2301", size = 199713, upload-time = "2025-07-26T12:02:14.4Z" },
+ { url = "https://files.pythonhosted.org/packages/72/8b/4546f3ab60f78c514ffb7d01a0bd743f90de36f0019d1be84d0a708a580a/contourpy-1.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fde6c716d51c04b1c25d0b90364d0be954624a0ee9d60e23e850e8d48353d07a", size = 292189, upload-time = "2025-07-26T12:02:16.095Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/e1/3542a9cb596cadd76fcef413f19c79216e002623158befe6daa03dbfa88c/contourpy-1.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:cbedb772ed74ff5be440fa8eee9bd49f64f6e3fc09436d9c7d8f1c287b121d77", size = 273251, upload-time = "2025-07-26T12:02:17.524Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/71/f93e1e9471d189f79d0ce2497007731c1e6bf9ef6d1d61b911430c3db4e5/contourpy-1.3.3-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22e9b1bd7a9b1d652cd77388465dc358dafcd2e217d35552424aa4f996f524f5", size = 335810, upload-time = "2025-07-26T12:02:18.9Z" },
+ { url = "https://files.pythonhosted.org/packages/91/f9/e35f4c1c93f9275d4e38681a80506b5510e9327350c51f8d4a5a724d178c/contourpy-1.3.3-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a22738912262aa3e254e4f3cb079a95a67132fc5a063890e224393596902f5a4", size = 382871, upload-time = "2025-07-26T12:02:20.418Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/71/47b512f936f66a0a900d81c396a7e60d73419868fba959c61efed7a8ab46/contourpy-1.3.3-cp314-cp314-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:afe5a512f31ee6bd7d0dda52ec9864c984ca3d66664444f2d72e0dc4eb832e36", size = 386264, upload-time = "2025-07-26T12:02:21.916Z" },
+ { url = "https://files.pythonhosted.org/packages/04/5f/9ff93450ba96b09c7c2b3f81c94de31c89f92292f1380261bd7195bea4ea/contourpy-1.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f64836de09927cba6f79dcd00fdd7d5329f3fccc633468507079c829ca4db4e3", size = 363819, upload-time = "2025-07-26T12:02:23.759Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/a6/0b185d4cc480ee494945cde102cb0149ae830b5fa17bf855b95f2e70ad13/contourpy-1.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1fd43c3be4c8e5fd6e4f2baeae35ae18176cf2e5cced681cca908addf1cdd53b", size = 1333650, upload-time = "2025-07-26T12:02:26.181Z" },
+ { url = "https://files.pythonhosted.org/packages/43/d7/afdc95580ca56f30fbcd3060250f66cedbde69b4547028863abd8aa3b47e/contourpy-1.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6afc576f7b33cf00996e5c1102dc2a8f7cc89e39c0b55df93a0b78c1bd992b36", size = 1404833, upload-time = "2025-07-26T12:02:28.782Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/e2/366af18a6d386f41132a48f033cbd2102e9b0cf6345d35ff0826cd984566/contourpy-1.3.3-cp314-cp314-win32.whl", hash = "sha256:66c8a43a4f7b8df8b71ee1840e4211a3c8d93b214b213f590e18a1beca458f7d", size = 189692, upload-time = "2025-07-26T12:02:30.128Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/c2/57f54b03d0f22d4044b8afb9ca0e184f8b1afd57b4f735c2fa70883dc601/contourpy-1.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:cf9022ef053f2694e31d630feaacb21ea24224be1c3ad0520b13d844274614fd", size = 232424, upload-time = "2025-07-26T12:02:31.395Z" },
+ { url = "https://files.pythonhosted.org/packages/18/79/a9416650df9b525737ab521aa181ccc42d56016d2123ddcb7b58e926a42c/contourpy-1.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:95b181891b4c71de4bb404c6621e7e2390745f887f2a026b2d99e92c17892339", size = 198300, upload-time = "2025-07-26T12:02:32.956Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/42/38c159a7d0f2b7b9c04c64ab317042bb6952b713ba875c1681529a2932fe/contourpy-1.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:33c82d0138c0a062380332c861387650c82e4cf1747aaa6938b9b6516762e772", size = 306769, upload-time = "2025-07-26T12:02:34.2Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/6c/26a8205f24bca10974e77460de68d3d7c63e282e23782f1239f226fcae6f/contourpy-1.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ea37e7b45949df430fe649e5de8351c423430046a2af20b1c1961cae3afcda77", size = 287892, upload-time = "2025-07-26T12:02:35.807Z" },
+ { url = "https://files.pythonhosted.org/packages/66/06/8a475c8ab718ebfd7925661747dbb3c3ee9c82ac834ccb3570be49d129f4/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d304906ecc71672e9c89e87c4675dc5c2645e1f4269a5063b99b0bb29f232d13", size = 326748, upload-time = "2025-07-26T12:02:37.193Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/a3/c5ca9f010a44c223f098fccd8b158bb1cb287378a31ac141f04730dc49be/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca658cd1a680a5c9ea96dc61cdbae1e85c8f25849843aa799dfd3cb370ad4fbe", size = 375554, upload-time = "2025-07-26T12:02:38.894Z" },
+ { url = "https://files.pythonhosted.org/packages/80/5b/68bd33ae63fac658a4145088c1e894405e07584a316738710b636c6d0333/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ab2fd90904c503739a75b7c8c5c01160130ba67944a7b77bbf36ef8054576e7f", size = 388118, upload-time = "2025-07-26T12:02:40.642Z" },
+ { url = "https://files.pythonhosted.org/packages/40/52/4c285a6435940ae25d7410a6c36bda5145839bc3f0beb20c707cda18b9d2/contourpy-1.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7301b89040075c30e5768810bc96a8e8d78085b47d8be6e4c3f5a0b4ed478a0", size = 352555, upload-time = "2025-07-26T12:02:42.25Z" },
+ { url = "https://files.pythonhosted.org/packages/24/ee/3e81e1dd174f5c7fefe50e85d0892de05ca4e26ef1c9a59c2a57e43b865a/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2a2a8b627d5cc6b7c41a4beff6c5ad5eb848c88255fda4a8745f7e901b32d8e4", size = 1322295, upload-time = "2025-07-26T12:02:44.668Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/b2/6d913d4d04e14379de429057cd169e5e00f6c2af3bb13e1710bcbdb5da12/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fd6ec6be509c787f1caf6b247f0b1ca598bef13f4ddeaa126b7658215529ba0f", size = 1391027, upload-time = "2025-07-26T12:02:47.09Z" },
+ { url = "https://files.pythonhosted.org/packages/93/8a/68a4ec5c55a2971213d29a9374913f7e9f18581945a7a31d1a39b5d2dfe5/contourpy-1.3.3-cp314-cp314t-win32.whl", hash = "sha256:e74a9a0f5e3fff48fb5a7f2fd2b9b70a3fe014a67522f79b7cca4c0c7e43c9ae", size = 202428, upload-time = "2025-07-26T12:02:48.691Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/96/fd9f641ffedc4fa3ace923af73b9d07e869496c9cc7a459103e6e978992f/contourpy-1.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:13b68d6a62db8eafaebb8039218921399baf6e47bf85006fd8529f2a08ef33fc", size = 250331, upload-time = "2025-07-26T12:02:50.137Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/8c/469afb6465b853afff216f9528ffda78a915ff880ed58813ba4faf4ba0b6/contourpy-1.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:b7448cb5a725bb1e35ce88771b86fba35ef418952474492cf7c764059933ff8b", size = 203831, upload-time = "2025-07-26T12:02:51.449Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/29/8dcfe16f0107943fa92388c23f6e05cff0ba58058c4c95b00280d4c75a14/contourpy-1.3.3-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:cd5dfcaeb10f7b7f9dc8941717c6c2ade08f587be2226222c12b25f0483ed497", size = 278809, upload-time = "2025-07-26T12:02:52.74Z" },
+ { url = "https://files.pythonhosted.org/packages/85/a9/8b37ef4f7dafeb335daee3c8254645ef5725be4d9c6aa70b50ec46ef2f7e/contourpy-1.3.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:0c1fc238306b35f246d61a1d416a627348b5cf0648648a031e14bb8705fcdfe8", size = 261593, upload-time = "2025-07-26T12:02:54.037Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/59/ebfb8c677c75605cc27f7122c90313fd2f375ff3c8d19a1694bda74aaa63/contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:70f9aad7de812d6541d29d2bbf8feb22ff7e1c299523db288004e3157ff4674e", size = 302202, upload-time = "2025-07-26T12:02:55.947Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/37/21972a15834d90bfbfb009b9d004779bd5a07a0ec0234e5ba8f64d5736f4/contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5ed3657edf08512fc3fe81b510e35c2012fbd3081d2e26160f27ca28affec989", size = 329207, upload-time = "2025-07-26T12:02:57.468Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/58/bd257695f39d05594ca4ad60df5bcb7e32247f9951fd09a9b8edb82d1daa/contourpy-1.3.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:3d1a3799d62d45c18bafd41c5fa05120b96a28079f2393af559b843d1a966a77", size = 225315, upload-time = "2025-07-26T12:02:58.801Z" },
+]
+
+[[package]]
+name = "cryptography"
+version = "46.0.5"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
+ { name = "typing-extensions", marker = "python_full_version < '3.11'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/60/04/ee2a9e8542e4fa2773b81771ff8349ff19cdd56b7258a0cc442639052edb/cryptography-46.0.5.tar.gz", hash = "sha256:abace499247268e3757271b2f1e244b36b06f8515cf27c4d49468fc9eb16e93d", size = 750064, upload-time = "2026-02-10T19:18:38.255Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ff/9e/6b4397a3e3d15123de3b1806ef342522393d50736c13b20ec4c9ea6693a6/cryptography-46.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c18ff11e86df2e28854939acde2d003f7984f721eba450b56a200ad90eeb0e6b", size = 4275637, upload-time = "2026-02-10T19:17:10.53Z" },
+ { url = "https://files.pythonhosted.org/packages/63/e7/471ab61099a3920b0c77852ea3f0ea611c9702f651600397ac567848b897/cryptography-46.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d7e3d356b8cd4ea5aff04f129d5f66ebdc7b6f8eae802b93739ed520c47c79b", size = 4424742, upload-time = "2026-02-10T19:17:12.388Z" },
+ { url = "https://files.pythonhosted.org/packages/37/53/a18500f270342d66bf7e4d9f091114e31e5ee9e7375a5aba2e85a91e0044/cryptography-46.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:50bfb6925eff619c9c023b967d5b77a54e04256c4281b0e21336a130cd7fc263", size = 4277528, upload-time = "2026-02-10T19:17:13.853Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/e7/237155ae19a9023de7e30ec64e5d99a9431a567407ac21170a046d22a5a3/cryptography-46.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ee190460e2fbe447175cda91b88b84ae8322a104fc27766ad09428754a618ed", size = 4456855, upload-time = "2026-02-10T19:17:17.221Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/87/fc628a7ad85b81206738abbd213b07702bcbdada1dd43f72236ef3cffbb5/cryptography-46.0.5-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:f145bba11b878005c496e93e257c1e88f154d278d2638e6450d17e0f31e558d2", size = 3984635, upload-time = "2026-02-10T19:17:18.792Z" },
+ { url = "https://files.pythonhosted.org/packages/84/29/65b55622bde135aedf4565dc509d99b560ee4095e56989e815f8fd2aa910/cryptography-46.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:e9251e3be159d1020c4030bd2e5f84d6a43fe54b6c19c12f51cde9542a2817b2", size = 4277038, upload-time = "2026-02-10T19:17:20.256Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/1a/c1ba8fead184d6e3d5afcf03d569acac5ad063f3ac9fb7258af158f7e378/cryptography-46.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4c3341037c136030cb46e4b1e17b7418ea4cbd9dd207e4a6f3b2b24e0d4ac731", size = 4456482, upload-time = "2026-02-10T19:17:25.133Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/e5/3fb22e37f66827ced3b902cf895e6a6bc1d095b5b26be26bd13c441fdf19/cryptography-46.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:890bcb4abd5a2d3f852196437129eb3667d62630333aacc13dfd470fad3aaa82", size = 4405497, upload-time = "2026-02-10T19:17:26.66Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/df/9d58bb32b1121a8a2f27383fabae4d63080c7ca60b9b5c88be742be04ee7/cryptography-46.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80a8d7bfdf38f87ca30a5391c0c9ce4ed2926918e017c29ddf643d0ed2778ea1", size = 4667819, upload-time = "2026-02-10T19:17:28.569Z" },
+ { url = "https://files.pythonhosted.org/packages/67/c8/581a6702e14f0898a0848105cbefd20c058099e2c2d22ef4e476dfec75d7/cryptography-46.0.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5be7bf2fb40769e05739dd0046e7b26f9d4670badc7b032d6ce4db64dddc0678", size = 4265728, upload-time = "2026-02-10T19:17:35.569Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/4a/ba1a65ce8fc65435e5a849558379896c957870dd64fecea97b1ad5f46a37/cryptography-46.0.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe346b143ff9685e40192a4960938545c699054ba11d4f9029f94751e3f71d87", size = 4408287, upload-time = "2026-02-10T19:17:36.938Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/67/8ffdbf7b65ed1ac224d1c2df3943553766914a8ca718747ee3871da6107e/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:c69fd885df7d089548a42d5ec05be26050ebcd2283d89b3d30676eb32ff87dee", size = 4270291, upload-time = "2026-02-10T19:17:38.748Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/02/cfe39181b02419bbbbcf3abdd16c1c5c8541f03ca8bda240debc467d5a12/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:1abfdb89b41c3be0365328a410baa9df3ff8a9110fb75e7b52e66803ddabc9a9", size = 4442199, upload-time = "2026-02-10T19:17:41.789Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/96/2fcaeb4873e536cf71421a388a6c11b5bc846e986b2b069c79363dc1648e/cryptography-46.0.5-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:d66e421495fdb797610a08f43b05269e0a5ea7f5e652a89bfd5a7d3c1dee3648", size = 3960131, upload-time = "2026-02-10T19:17:43.379Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/d2/b27631f401ddd644e94c5cf33c9a4069f72011821cf3dc7309546b0642a0/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:4e817a8920bfbcff8940ecfd60f23d01836408242b30f1a708d93198393a80b4", size = 4270072, upload-time = "2026-02-10T19:17:45.481Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/b9/cf73ddf8ef1164330eb0b199a589103c363afa0cf794218c24d524a58eab/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:a3d1fae9863299076f05cb8a778c467578262fae09f9dc0ee9b12eb4268ce663", size = 4441741, upload-time = "2026-02-10T19:17:48.661Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/eb/eee00b28c84c726fe8fa0158c65afe312d9c3b78d9d01daf700f1f6e37ff/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c4143987a42a2397f2fc3b4d7e3a7d313fbe684f67ff443999e803dd75a76826", size = 4396728, upload-time = "2026-02-10T19:17:50.058Z" },
+ { url = "https://files.pythonhosted.org/packages/65/f4/6bc1a9ed5aef7145045114b75b77c2a8261b4d38717bd8dea111a63c3442/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7d731d4b107030987fd61a7f8ab512b25b53cef8f233a97379ede116f30eb67d", size = 4652001, upload-time = "2026-02-10T19:17:51.54Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/04/c85bdeab78c8bc77b701bf0d9bdcf514c044e18a46dcff330df5448631b0/cryptography-46.0.5-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1f30a86d2757199cb2d56e48cce14deddf1f9c95f1ef1b64ee91ea43fe2e18", size = 4275349, upload-time = "2026-02-10T19:17:58.419Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/32/9b87132a2f91ee7f5223b091dc963055503e9b442c98fc0b8a5ca765fab0/cryptography-46.0.5-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:039917b0dc418bb9f6edce8a906572d69e74bd330b0b3fea4f79dab7f8ddd235", size = 4420667, upload-time = "2026-02-10T19:18:00.619Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/a6/a7cb7010bec4b7c5692ca6f024150371b295ee1c108bdc1c400e4c44562b/cryptography-46.0.5-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ba2a27ff02f48193fc4daeadf8ad2590516fa3d0adeeb34336b96f7fa64c1e3a", size = 4276980, upload-time = "2026-02-10T19:18:02.379Z" },
+ { url = "https://files.pythonhosted.org/packages/37/19/e1b8f964a834eddb44fa1b9a9976f4e414cbb7aa62809b6760c8803d22d1/cryptography-46.0.5-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ce58ba46e1bc2aac4f7d9290223cead56743fa6ab94a5d53292ffaac6a91614", size = 4453674, upload-time = "2026-02-10T19:18:05.588Z" },
+ { url = "https://files.pythonhosted.org/packages/db/ed/db15d3956f65264ca204625597c410d420e26530c4e2943e05a0d2f24d51/cryptography-46.0.5-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:420d0e909050490d04359e7fdb5ed7e667ca5c3c402b809ae2563d7e66a92229", size = 3978801, upload-time = "2026-02-10T19:18:07.167Z" },
+ { url = "https://files.pythonhosted.org/packages/41/e2/df40a31d82df0a70a0daf69791f91dbb70e47644c58581d654879b382d11/cryptography-46.0.5-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:582f5fcd2afa31622f317f80426a027f30dc792e9c80ffee87b993200ea115f1", size = 4276755, upload-time = "2026-02-10T19:18:09.813Z" },
+ { url = "https://files.pythonhosted.org/packages/99/0f/a3076874e9c88ecb2ecc31382f6e7c21b428ede6f55aafa1aa272613e3cd/cryptography-46.0.5-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:a3d507bb6a513ca96ba84443226af944b0f7f47dcc9a399d110cd6146481d24c", size = 4452794, upload-time = "2026-02-10T19:18:12.914Z" },
+ { url = "https://files.pythonhosted.org/packages/02/ef/ffeb542d3683d24194a38f66ca17c0a4b8bf10631feef44a7ef64e631b1a/cryptography-46.0.5-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9f16fbdf4da055efb21c22d81b89f155f02ba420558db21288b3d0035bafd5f4", size = 4404160, upload-time = "2026-02-10T19:18:14.375Z" },
+ { url = "https://files.pythonhosted.org/packages/96/93/682d2b43c1d5f1406ed048f377c0fc9fc8f7b0447a478d5c65ab3d3a66eb/cryptography-46.0.5-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ced80795227d70549a411a4ab66e8ce307899fad2220ce5ab2f296e687eacde9", size = 4667123, upload-time = "2026-02-10T19:18:15.886Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/6f/6cc6cc9955caa6eaf83660b0da2b077c7fe8ff9950a3c5e45d605038d439/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bc84e875994c3b445871ea7181d424588171efec3e185dced958dad9e001950a", size = 4218321, upload-time = "2026-02-10T19:18:22.349Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/5d/c4da701939eeee699566a6c1367427ab91a8b7088cc2328c09dbee940415/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:2ae6971afd6246710480e3f15824ed3029a60fc16991db250034efd0b9fb4356", size = 4381786, upload-time = "2026-02-10T19:18:24.529Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/97/a538654732974a94ff96c1db621fa464f455c02d4bb7d2652f4edc21d600/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:d861ee9e76ace6cf36a6a89b959ec08e7bc2493ee39d07ffe5acb23ef46d27da", size = 4217990, upload-time = "2026-02-10T19:18:25.957Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/11/7e500d2dd3ba891197b9efd2da5454b74336d64a7cc419aa7327ab74e5f6/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:2b7a67c9cd56372f3249b39699f2ad479f6991e62ea15800973b956f4b73e257", size = 4381252, upload-time = "2026-02-10T19:18:27.496Z" },
+]
+
+[[package]]
+name = "cycler"
+version = "0.12.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" },
+]
+
+[[package]]
+name = "decorator"
+version = "5.2.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" },
+]
+
+[[package]]
+name = "dependency-groups"
+version = "1.3.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "packaging" },
+ { name = "tomli", marker = "python_full_version < '3.11'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/62/55/f054de99871e7beb81935dea8a10b90cd5ce42122b1c3081d5282fdb3621/dependency_groups-1.3.1.tar.gz", hash = "sha256:78078301090517fd938c19f64a53ce98c32834dfe0dee6b88004a569a6adfefd", size = 10093, upload-time = "2025-05-02T00:34:29.452Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/99/c7/d1ec24fb280caa5a79b6b950db565dab30210a66259d17d5bb2b3a9f878d/dependency_groups-1.3.1-py3-none-any.whl", hash = "sha256:51aeaa0dfad72430fcfb7bcdbefbd75f3792e5919563077f30bc0d73f4493030", size = 8664, upload-time = "2025-05-02T00:34:27.085Z" },
+]
+
+[[package]]
+name = "docutils"
+version = "0.22.4"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ae/b6/03bb70946330e88ffec97aefd3ea75ba575cb2e762061e0e62a213befee8/docutils-0.22.4.tar.gz", hash = "sha256:4db53b1fde9abecbb74d91230d32ab626d94f6badfc575d6db9194a49df29968", size = 2291750, upload-time = "2025-12-18T19:00:26.443Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/02/10/5da547df7a391dcde17f59520a231527b8571e6f46fc8efb02ccb370ab12/docutils-0.22.4-py3-none-any.whl", hash = "sha256:d0013f540772d1420576855455d050a2180186c91c15779301ac2ccb3eeb68de", size = 633196, upload-time = "2025-12-18T19:00:18.077Z" },
+]
+
+[[package]]
+name = "exceptiongroup"
+version = "1.3.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions", marker = "python_full_version < '3.11'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" },
+]
+
+[[package]]
+name = "executing"
+version = "2.2.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488, upload-time = "2025-09-01T09:48:10.866Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" },
+]
+
+[[package]]
+name = "filelock"
+version = "3.19.1"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version < '3.10'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/40/bb/0ab3e58d22305b6f5440629d20683af28959bf793d98d11950e305c1c326/filelock-3.19.1.tar.gz", hash = "sha256:66eda1888b0171c998b35be2bcc0f6d75c388a7ce20c3f3f37aa8e96c2dddf58", size = 17687, upload-time = "2025-08-14T16:56:03.016Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/42/14/42b2651a2f46b022ccd948bca9f2d5af0fd8929c4eec235b8d6d844fbe67/filelock-3.19.1-py3-none-any.whl", hash = "sha256:d38e30481def20772f5baf097c122c3babc4fcdb7e14e57049eb9d88c6dc017d", size = 15988, upload-time = "2025-08-14T16:56:01.633Z" },
+]
+
+[[package]]
+name = "filelock"
+version = "3.24.3"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version >= '3.11'",
+ "python_full_version == '3.10.*'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/73/92/a8e2479937ff39185d20dd6a851c1a63e55849e447a55e798cc2e1f49c65/filelock-3.24.3.tar.gz", hash = "sha256:011a5644dc937c22699943ebbfc46e969cdde3e171470a6e40b9533e5a72affa", size = 37935, upload-time = "2026-02-19T00:48:20.543Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9c/0f/5d0c71a1aefeb08efff26272149e07ab922b64f46c63363756224bd6872e/filelock-3.24.3-py3-none-any.whl", hash = "sha256:426e9a4660391f7f8a810d71b0555bce9008b0a1cc342ab1f6947d37639e002d", size = 24331, upload-time = "2026-02-19T00:48:18.465Z" },
+]
+
+[[package]]
+name = "fonttools"
+version = "4.60.2"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version < '3.10'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/3e/c4/db6a7b5eb0656534c3aa2596c2c5e18830d74f1b9aa5aa8a7dff63a0b11d/fonttools-4.60.2.tar.gz", hash = "sha256:d29552e6b155ebfc685b0aecf8d429cb76c14ab734c22ef5d3dea6fdf800c92c", size = 3562254, upload-time = "2025-12-09T13:38:11.835Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ab/de/9e10a99fb3070accb8884886a41a4ce54e49bf2fa4fc63f48a6cf2061713/fonttools-4.60.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4e36fadcf7e8ca6e34d490eef86ed638d6fd9c55d2f514b05687622cfc4a7050", size = 2850403, upload-time = "2025-12-09T13:35:53.14Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/40/d5b369d1073b134f600a94a287e13b5bdea2191ba6347d813fa3da00e94a/fonttools-4.60.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6e500fc9c04bee749ceabfc20cb4903f6981c2139050d85720ea7ada61b75d5c", size = 2398629, upload-time = "2025-12-09T13:35:56.471Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/b5/123819369aaf99d1e4dc49f1de1925d4edc7379114d15a56a7dd2e9d56e6/fonttools-4.60.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22efea5e784e1d1cd8d7b856c198e360a979383ebc6dea4604743b56da1cbc34", size = 4893471, upload-time = "2025-12-09T13:35:58.927Z" },
+ { url = "https://files.pythonhosted.org/packages/24/29/f8f8acccb9716b899be4be45e9ce770d6aa76327573863e68448183091b0/fonttools-4.60.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:677aa92d84d335e4d301d8ba04afca6f575316bc647b6782cb0921943fcb6343", size = 4854686, upload-time = "2025-12-09T13:36:01.767Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/0d/f3f51d7519f44f2dd5c9a60d7cd41185ebcee4348f073e515a3a93af15ff/fonttools-4.60.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:edd49d3defbf35476e78b61ff737ff5efea811acff68d44233a95a5a48252334", size = 4871233, upload-time = "2025-12-09T13:36:06.094Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/3f/4d4fd47d3bc40ab4d76718555185f8adffb5602ea572eac4bbf200c47d22/fonttools-4.60.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:126839492b69cecc5baf2bddcde60caab2ffafd867bbae2a88463fce6078ca3a", size = 4988936, upload-time = "2025-12-09T13:36:08.42Z" },
+ { url = "https://files.pythonhosted.org/packages/01/6f/83bbdefa43f2c3ae206fd8c4b9a481f3c913eef871b1ce9a453069239e39/fonttools-4.60.2-cp310-cp310-win32.whl", hash = "sha256:ffcab6f5537136046ca902ed2491ab081ba271b07591b916289b7c27ff845f96", size = 2278044, upload-time = "2025-12-09T13:36:10.641Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/04/7d9a137e919d6c9ef26704b7f7b2580d9cfc5139597588227aacebc0e3b7/fonttools-4.60.2-cp310-cp310-win_amd64.whl", hash = "sha256:9c68b287c7ffcd29dd83b5f961004b2a54a862a88825d52ea219c6220309ba45", size = 2326522, upload-time = "2025-12-09T13:36:12.981Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/80/b7693d37c02417e162cc83cdd0b19a4f58be82c638b5d4ce4de2dae050c4/fonttools-4.60.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a2aed0a7931401b3875265717a24c726f87ecfedbb7b3426c2ca4d2812e281ae", size = 2847809, upload-time = "2025-12-09T13:36:14.884Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/9a/9c2c13bf8a6496ac21607d704e74e9cc68ebf23892cf924c9a8b5c7566b9/fonttools-4.60.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dea6868e9d2b816c9076cfea77754686f3c19149873bdbc5acde437631c15df1", size = 2397302, upload-time = "2025-12-09T13:36:17.151Z" },
+ { url = "https://files.pythonhosted.org/packages/56/f6/ce38ff6b2d2d58f6fd981d32f3942365bfa30eadf2b47d93b2d48bf6097f/fonttools-4.60.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2fa27f34950aa1fe0f0b1abe25eed04770a3b3b34ad94e5ace82cc341589678a", size = 5054418, upload-time = "2025-12-09T13:36:19.062Z" },
+ { url = "https://files.pythonhosted.org/packages/88/06/5353bea128ff39e857c31de3dd605725b4add956badae0b31bc9a50d4c8e/fonttools-4.60.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:13a53d479d187b09bfaa4a35ffcbc334fc494ff355f0a587386099cb66674f1e", size = 5031652, upload-time = "2025-12-09T13:36:21.206Z" },
+ { url = "https://files.pythonhosted.org/packages/71/05/ebca836437f6ebd57edd6428e7eff584e683ff0556ddb17d62e3b731f46c/fonttools-4.60.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fac5e921d3bd0ca3bb8517dced2784f0742bc8ca28579a68b139f04ea323a779", size = 5030321, upload-time = "2025-12-09T13:36:23.515Z" },
+ { url = "https://files.pythonhosted.org/packages/57/f9/eb9d2a2ce30c99f840c1cc3940729a970923cf39d770caf88909d98d516b/fonttools-4.60.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:648f4f9186fd7f1f3cd57dbf00d67a583720d5011feca67a5e88b3a491952cfb", size = 5154255, upload-time = "2025-12-09T13:36:25.879Z" },
+ { url = "https://files.pythonhosted.org/packages/08/a2/088b6ceba8272a9abb629d3c08f9c1e35e5ce42db0ccfe0c1f9f03e60d1d/fonttools-4.60.2-cp311-cp311-win32.whl", hash = "sha256:3274e15fad871bead5453d5ce02658f6d0c7bc7e7021e2a5b8b04e2f9e40da1a", size = 2276300, upload-time = "2025-12-09T13:36:27.772Z" },
+ { url = "https://files.pythonhosted.org/packages/de/2f/8e4c3d908cc5dade7bb1316ce48589f6a24460c1056fd4b8db51f1fa309a/fonttools-4.60.2-cp311-cp311-win_amd64.whl", hash = "sha256:91d058d5a483a1525b367803abb69de0923fbd45e1f82ebd000f5c8aa65bc78e", size = 2327574, upload-time = "2025-12-09T13:36:30.89Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/30/530c9eddcd1c39219dc0aaede2b5a4c8ab80e0bb88d1b3ffc12944c4aac3/fonttools-4.60.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e0164b7609d2b5c5dd4e044b8085b7bd7ca7363ef8c269a4ab5b5d4885a426b2", size = 2847196, upload-time = "2025-12-09T13:36:33.262Z" },
+ { url = "https://files.pythonhosted.org/packages/19/2f/4077a482836d5bbe3bc9dac1c004d02ee227cf04ed62b0a2dfc41d4f0dfd/fonttools-4.60.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1dd3d9574fc595c1e97faccae0f264dc88784ddf7fbf54c939528378bacc0033", size = 2395842, upload-time = "2025-12-09T13:36:35.47Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/05/aae5bb99c5398f8ed4a8b784f023fd9dd3568f0bd5d5b21e35b282550f11/fonttools-4.60.2-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:98d0719f1b11c2817307d2da2e94296a3b2a3503f8d6252a101dca3ee663b917", size = 4949713, upload-time = "2025-12-09T13:36:37.874Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/37/49067349fc78ff0efbf09fadefe80ddf41473ca8f8a25400e3770da38328/fonttools-4.60.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9d3ea26957dd07209f207b4fff64c702efe5496de153a54d3b91007ec28904dd", size = 4999907, upload-time = "2025-12-09T13:36:39.853Z" },
+ { url = "https://files.pythonhosted.org/packages/16/31/d0f11c758bd0db36b664c92a0f9dfdcc2d7313749aa7d6629805c6946f21/fonttools-4.60.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1ee301273b0850f3a515299f212898f37421f42ff9adfc341702582ca5073c13", size = 4939717, upload-time = "2025-12-09T13:36:43.075Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/bc/1cff0d69522e561bf1b99bee7c3911c08c25e919584827c3454a64651ce9/fonttools-4.60.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c6eb4694cc3b9c03b7c01d65a9cf35b577f21aa6abdbeeb08d3114b842a58153", size = 5089205, upload-time = "2025-12-09T13:36:45.468Z" },
+ { url = "https://files.pythonhosted.org/packages/05/e6/fb174f0069b7122e19828c551298bfd34fdf9480535d2a6ac2ed37afacd3/fonttools-4.60.2-cp312-cp312-win32.whl", hash = "sha256:57f07b616c69c244cc1a5a51072eeef07dddda5ebef9ca5c6e9cf6d59ae65b70", size = 2264674, upload-time = "2025-12-09T13:36:49.238Z" },
+ { url = "https://files.pythonhosted.org/packages/75/57/6552ffd6b582d3e6a9f01780c5275e6dfff1e70ca146101733aa1c12a129/fonttools-4.60.2-cp312-cp312-win_amd64.whl", hash = "sha256:310035802392f1fe5a7cf43d76f6ff4a24c919e4c72c0352e7b8176e2584b8a0", size = 2314701, upload-time = "2025-12-09T13:36:51.09Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/e4/8381d0ca6b6c6c484660b03517ec5b5b81feeefca3808726dece36c652a9/fonttools-4.60.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2bb5fd231e56ccd7403212636dcccffc96c5ae0d6f9e4721fa0a32cb2e3ca432", size = 2842063, upload-time = "2025-12-09T13:36:53.468Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/2c/4367117ee8ff4f4374787a1222da0bd413d80cf3522111f727a7b8f80d1d/fonttools-4.60.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:536b5fab7b6fec78ccf59b5c59489189d9d0a8b0d3a77ed1858be59afb096696", size = 2393792, upload-time = "2025-12-09T13:36:55.742Z" },
+ { url = "https://files.pythonhosted.org/packages/49/b7/a76b6dffa193869e54e32ca2f9abb0d0e66784bc8a24e6f86eb093015481/fonttools-4.60.2-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6b9288fc38252ac86a9570f19313ecbc9ff678982e0f27c757a85f1f284d3400", size = 4924020, upload-time = "2025-12-09T13:36:58.229Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/4e/0078200e2259f0061c86a74075f507d64c43dd2ab38971956a5c0012d344/fonttools-4.60.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:93fcb420791d839ef592eada2b69997c445d0ce9c969b5190f2e16828ec10607", size = 4980070, upload-time = "2025-12-09T13:37:00.311Z" },
+ { url = "https://files.pythonhosted.org/packages/85/1f/d87c85a11cb84852c975251581862681e4a0c1c3bd456c648792203f311b/fonttools-4.60.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7916a381b094db4052ac284255186aebf74c5440248b78860cb41e300036f598", size = 4921411, upload-time = "2025-12-09T13:37:02.345Z" },
+ { url = "https://files.pythonhosted.org/packages/75/c0/7efad650f5ed8e317c2633133ef3c64917e7adf2e4e2940c798f5d57ec6e/fonttools-4.60.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:58c8c393d5e16b15662cfc2d988491940458aa87894c662154f50c7b49440bef", size = 5063465, upload-time = "2025-12-09T13:37:04.836Z" },
+ { url = "https://files.pythonhosted.org/packages/18/a8/750518c4f8cdd79393b386bc81226047ade80239e58c6c9f5dbe1fdd8ea1/fonttools-4.60.2-cp313-cp313-win32.whl", hash = "sha256:19c6e0afd8b02008caa0aa08ab896dfce5d0bcb510c49b2c499541d5cb95a963", size = 2263443, upload-time = "2025-12-09T13:37:06.762Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/22/026c60376f165981f80a0e90bd98a79ae3334e9d89a3d046c4d2e265c724/fonttools-4.60.2-cp313-cp313-win_amd64.whl", hash = "sha256:6a500dc59e11b2338c2dba1f8cf11a4ae8be35ec24af8b2628b8759a61457b76", size = 2313800, upload-time = "2025-12-09T13:37:08.713Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/ab/7cf1f5204e1366ddf9dc5cdc2789b571feb9eebcee0e3463c3f457df5f52/fonttools-4.60.2-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:9387c532acbe323bbf2a920f132bce3c408a609d5f9dcfc6532fbc7e37f8ccbb", size = 2841690, upload-time = "2025-12-09T13:37:10.696Z" },
+ { url = "https://files.pythonhosted.org/packages/00/3c/0bf83c6f863cc8b934952567fa2bf737cfcec8fc4ffb59b3f93820095f89/fonttools-4.60.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:e6f1c824185b5b8fb681297f315f26ae55abb0d560c2579242feea8236b1cfef", size = 2392191, upload-time = "2025-12-09T13:37:12.954Z" },
+ { url = "https://files.pythonhosted.org/packages/00/f0/40090d148b8907fbea12e9bdf1ff149f30cdf1769e3b2c3e0dbf5106b88d/fonttools-4.60.2-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:55a3129d1e4030b1a30260f1b32fe76781b585fb2111d04a988e141c09eb6403", size = 4873503, upload-time = "2025-12-09T13:37:15.142Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/e0/d8b13f99e58b8c293781288ba62fe634f1f0697c9c4c0ae104d3215f3a10/fonttools-4.60.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b196e63753abc33b3b97a6fd6de4b7c4fef5552c0a5ba5e562be214d1e9668e0", size = 4968493, upload-time = "2025-12-09T13:37:18.272Z" },
+ { url = "https://files.pythonhosted.org/packages/46/c5/960764d12c92bc225f02401d3067048cb7b282293d9e48e39fe2b0ec38a9/fonttools-4.60.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:de76c8d740fb55745f3b154f0470c56db92ae3be27af8ad6c2e88f1458260c9a", size = 4920015, upload-time = "2025-12-09T13:37:20.334Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/ab/839d8caf253d1eef3653ef4d34427d0326d17a53efaec9eb04056b670fff/fonttools-4.60.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6ba6303225c95998c9fda2d410aa792c3d2c1390a09df58d194b03e17583fa25", size = 5031165, upload-time = "2025-12-09T13:37:23.57Z" },
+ { url = "https://files.pythonhosted.org/packages/de/bf/3bc862796a6841cbe0725bb5512d272239b809dba631a4b0301df885e62d/fonttools-4.60.2-cp314-cp314-win32.whl", hash = "sha256:0a89728ce10d7c816fedaa5380c06d2793e7a8a634d7ce16810e536c22047384", size = 2267526, upload-time = "2025-12-09T13:37:25.821Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/a1/c1909cacf00c76dc37b4743451561fbaaf7db4172c22a6d9394081d114c3/fonttools-4.60.2-cp314-cp314-win_amd64.whl", hash = "sha256:fa8446e6ab8bd778b82cb1077058a2addba86f30de27ab9cc18ed32b34bc8667", size = 2319096, upload-time = "2025-12-09T13:37:28.058Z" },
+ { url = "https://files.pythonhosted.org/packages/29/b3/f66e71433f08e3a931b2b31a665aeed17fcc5e6911fc73529c70a232e421/fonttools-4.60.2-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:4063bc81ac5a4137642865cb63dd270e37b3cd1f55a07c0d6e41d072699ccca2", size = 2925167, upload-time = "2025-12-09T13:37:30.348Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/13/eeb491ff743594bbd0bee6e49422c03a59fe9c49002d3cc60eeb77414285/fonttools-4.60.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:ebfdb66fa69732ed604ab8e2a0431e6deff35e933a11d73418cbc7823d03b8e1", size = 2430923, upload-time = "2025-12-09T13:37:32.817Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/e5/db609f785e460796e53c4dbc3874a5f4948477f27beceb5e2d24b2537666/fonttools-4.60.2-cp314-cp314t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:50b10b3b1a72d1d54c61b0e59239e1a94c0958f4a06a1febf97ce75388dd91a4", size = 4877729, upload-time = "2025-12-09T13:37:35.858Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/d6/85e4484dd4bfb03fee7bd370d65888cccbd3dee2681ee48c869dd5ccb23f/fonttools-4.60.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:beae16891a13b4a2ddec9b39b4de76092a3025e4d1c82362e3042b62295d5e4d", size = 5096003, upload-time = "2025-12-09T13:37:37.862Z" },
+ { url = "https://files.pythonhosted.org/packages/30/49/1a98e44b71030b83d2046f981373b80571868259d98e6dae7bc20099dac6/fonttools-4.60.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:522f017fdb3766fd5d2d321774ef351cc6ce88ad4e6ac9efe643e4a2b9d528db", size = 4974410, upload-time = "2025-12-09T13:37:40.166Z" },
+ { url = "https://files.pythonhosted.org/packages/42/07/d6f775d950ee8a841012472c7303f8819423d8cc3b4530915de7265ebfa2/fonttools-4.60.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:82cceceaf9c09a965a75b84a4b240dd3768e596ffb65ef53852681606fe7c9ba", size = 5002036, upload-time = "2025-12-09T13:37:42.639Z" },
+ { url = "https://files.pythonhosted.org/packages/73/f6/ba6458f83ce1a9f8c3b17bd8f7b8a2205a126aac1055796b7e7cfebbd38f/fonttools-4.60.2-cp314-cp314t-win32.whl", hash = "sha256:bbfbc918a75437fe7e6d64d1b1e1f713237df1cf00f3a36dedae910b2ba01cee", size = 2330985, upload-time = "2025-12-09T13:37:45.157Z" },
+ { url = "https://files.pythonhosted.org/packages/91/24/fea0ba4d3a32d4ed1103a1098bfd99dc78b5fe3bb97202920744a37b73dc/fonttools-4.60.2-cp314-cp314t-win_amd64.whl", hash = "sha256:0e5cd9b0830f6550d58c84f3ab151a9892b50c4f9d538c5603c0ce6fff2eb3f1", size = 2396226, upload-time = "2025-12-09T13:37:47.355Z" },
+ { url = "https://files.pythonhosted.org/packages/55/ae/a6d9446cb258d3fe87e311c2d7bacf8e8da3e5809fbdc3a8306db4f6b14e/fonttools-4.60.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a3c75b8b42f7f93906bdba9eb1197bb76aecbe9a0a7cf6feec75f7605b5e8008", size = 2857184, upload-time = "2025-12-09T13:37:49.96Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/f3/1b41d0b6a8b908aa07f652111155dd653ebbf0b3385e66562556c5206685/fonttools-4.60.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0f86c8c37bc0ec0b9c141d5e90c717ff614e93c187f06d80f18c7057097f71bc", size = 2401877, upload-time = "2025-12-09T13:37:52.307Z" },
+ { url = "https://files.pythonhosted.org/packages/71/57/048fd781680c38b05c5463657d0d95d5f2391a51972176e175c01de29d42/fonttools-4.60.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fe905403fe59683b0e9a45f234af2866834376b8821f34633b1c76fb731b6311", size = 4878073, upload-time = "2025-12-09T13:37:56.477Z" },
+ { url = "https://files.pythonhosted.org/packages/45/bb/363364f052a893cebd3d449588b21244a9d873620fda03ad92702d2e1bc7/fonttools-4.60.2-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:38ce703b60a906e421e12d9e3a7f064883f5e61bb23e8961f4be33cfe578500b", size = 4835385, upload-time = "2025-12-09T13:37:58.882Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/38/e392bb930b2436287e6021672345db26441bf1f85f1e98f8b9784334e41d/fonttools-4.60.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9e810c06f3e79185cecf120e58b343ea5a89b54dd695fd644446bcf8c026da5e", size = 4853084, upload-time = "2025-12-09T13:38:01.578Z" },
+ { url = "https://files.pythonhosted.org/packages/65/60/0d77faeaecf7a3276a8a6dc49e2274357e6b3ed6a1774e2fdb2a7f142db0/fonttools-4.60.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:38faec8cc1d12122599814d15a402183f5123fb7608dac956121e7c6742aebc5", size = 4971144, upload-time = "2025-12-09T13:38:03.748Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/c7/6d3ac3afbcd598631bce24c3ecb919e7d0644a82fea8ddc4454312fc0be6/fonttools-4.60.2-cp39-cp39-win32.whl", hash = "sha256:80a45cf7bf659acb7b36578f300231873daba67bd3ca8cce181c73f861f14a37", size = 1499411, upload-time = "2025-12-09T13:38:05.586Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/1c/9dedf6420e23f9fa630bb97941839dddd2e1e57d1b2b85a902378dbe0bd2/fonttools-4.60.2-cp39-cp39-win_amd64.whl", hash = "sha256:c355d5972071938e1b1e0f5a1df001f68ecf1a62f34a3407dc8e0beccf052501", size = 1547943, upload-time = "2025-12-09T13:38:07.604Z" },
+ { url = "https://files.pythonhosted.org/packages/79/6c/10280af05b44fafd1dff69422805061fa1af29270bc52dce031ac69540bf/fonttools-4.60.2-py3-none-any.whl", hash = "sha256:73cf92eeda67cf6ff10c8af56fc8f4f07c1647d989a979be9e388a49be26552a", size = 1144610, upload-time = "2025-12-09T13:38:09.5Z" },
+]
+
+[[package]]
+name = "fonttools"
+version = "4.61.1"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version >= '3.11'",
+ "python_full_version == '3.10.*'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ec/ca/cf17b88a8df95691275a3d77dc0a5ad9907f328ae53acbe6795da1b2f5ed/fonttools-4.61.1.tar.gz", hash = "sha256:6675329885c44657f826ef01d9e4fb33b9158e9d93c537d84ad8399539bc6f69", size = 3565756, upload-time = "2025-12-12T17:31:24.246Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5b/94/8a28707adb00bed1bf22dac16ccafe60faf2ade353dcb32c3617ee917307/fonttools-4.61.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c7db70d57e5e1089a274cbb2b1fd635c9a24de809a231b154965d415d6c6d24", size = 2854799, upload-time = "2025-12-12T17:29:27.5Z" },
+ { url = "https://files.pythonhosted.org/packages/94/93/c2e682faaa5ee92034818d8f8a8145ae73eb83619600495dcf8503fa7771/fonttools-4.61.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5fe9fd43882620017add5eabb781ebfbc6998ee49b35bd7f8f79af1f9f99a958", size = 2403032, upload-time = "2025-12-12T17:29:30.115Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/62/1748f7e7e1ee41aa52279fd2e3a6d0733dc42a673b16932bad8e5d0c8b28/fonttools-4.61.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8db08051fc9e7d8bc622f2112511b8107d8f27cd89e2f64ec45e9825e8288da", size = 4897863, upload-time = "2025-12-12T17:29:32.535Z" },
+ { url = "https://files.pythonhosted.org/packages/69/69/4ca02ee367d2c98edcaeb83fc278d20972502ee071214ad9d8ca85e06080/fonttools-4.61.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a76d4cb80f41ba94a6691264be76435e5f72f2cb3cab0b092a6212855f71c2f6", size = 4859076, upload-time = "2025-12-12T17:29:34.907Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/f5/660f9e3cefa078861a7f099107c6d203b568a6227eef163dd173bfc56bdc/fonttools-4.61.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a13fc8aeb24bad755eea8f7f9d409438eb94e82cf86b08fe77a03fbc8f6a96b1", size = 4875623, upload-time = "2025-12-12T17:29:37.33Z" },
+ { url = "https://files.pythonhosted.org/packages/63/d1/9d7c5091d2276ed47795c131c1bf9316c3c1ab2789c22e2f59e0572ccd38/fonttools-4.61.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b846a1fcf8beadeb9ea4f44ec5bdde393e2f1569e17d700bfc49cd69bde75881", size = 4993327, upload-time = "2025-12-12T17:29:39.781Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/2d/28def73837885ae32260d07660a052b99f0aa00454867d33745dfe49dbf0/fonttools-4.61.1-cp310-cp310-win32.whl", hash = "sha256:78a7d3ab09dc47ac1a363a493e6112d8cabed7ba7caad5f54dbe2f08676d1b47", size = 1502180, upload-time = "2025-12-12T17:29:42.217Z" },
+ { url = "https://files.pythonhosted.org/packages/63/fa/bfdc98abb4dd2bd491033e85e3ba69a2313c850e759a6daa014bc9433b0f/fonttools-4.61.1-cp310-cp310-win_amd64.whl", hash = "sha256:eff1ac3cc66c2ac7cda1e64b4e2f3ffef474b7335f92fc3833fc632d595fcee6", size = 1550654, upload-time = "2025-12-12T17:29:44.564Z" },
+ { url = "https://files.pythonhosted.org/packages/69/12/bf9f4eaa2fad039356cc627587e30ed008c03f1cebd3034376b5ee8d1d44/fonttools-4.61.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c6604b735bb12fef8e0efd5578c9fb5d3d8532d5001ea13a19cddf295673ee09", size = 2852213, upload-time = "2025-12-12T17:29:46.675Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/49/4138d1acb6261499bedde1c07f8c2605d1d8f9d77a151e5507fd3ef084b6/fonttools-4.61.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5ce02f38a754f207f2f06557523cd39a06438ba3aafc0639c477ac409fc64e37", size = 2401689, upload-time = "2025-12-12T17:29:48.769Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/fe/e6ce0fe20a40e03aef906af60aa87668696f9e4802fa283627d0b5ed777f/fonttools-4.61.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:77efb033d8d7ff233385f30c62c7c79271c8885d5c9657d967ede124671bbdfb", size = 5058809, upload-time = "2025-12-12T17:29:51.701Z" },
+ { url = "https://files.pythonhosted.org/packages/79/61/1ca198af22f7dd22c17ab86e9024ed3c06299cfdb08170640e9996d501a0/fonttools-4.61.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:75c1a6dfac6abd407634420c93864a1e274ebc1c7531346d9254c0d8f6ca00f9", size = 5036039, upload-time = "2025-12-12T17:29:53.659Z" },
+ { url = "https://files.pythonhosted.org/packages/99/cc/fa1801e408586b5fce4da9f5455af8d770f4fc57391cd5da7256bb364d38/fonttools-4.61.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0de30bfe7745c0d1ffa2b0b7048fb7123ad0d71107e10ee090fa0b16b9452e87", size = 5034714, upload-time = "2025-12-12T17:29:55.592Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/aa/b7aeafe65adb1b0a925f8f25725e09f078c635bc22754f3fecb7456955b0/fonttools-4.61.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:58b0ee0ab5b1fc9921eccfe11d1435added19d6494dde14e323f25ad2bc30c56", size = 5158648, upload-time = "2025-12-12T17:29:57.861Z" },
+ { url = "https://files.pythonhosted.org/packages/99/f9/08ea7a38663328881384c6e7777bbefc46fd7d282adfd87a7d2b84ec9d50/fonttools-4.61.1-cp311-cp311-win32.whl", hash = "sha256:f79b168428351d11e10c5aeb61a74e1851ec221081299f4cf56036a95431c43a", size = 2280681, upload-time = "2025-12-12T17:29:59.943Z" },
+ { url = "https://files.pythonhosted.org/packages/07/ad/37dd1ae5fa6e01612a1fbb954f0927681f282925a86e86198ccd7b15d515/fonttools-4.61.1-cp311-cp311-win_amd64.whl", hash = "sha256:fe2efccb324948a11dd09d22136fe2ac8a97d6c1347cf0b58a911dcd529f66b7", size = 2331951, upload-time = "2025-12-12T17:30:02.254Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/16/7decaa24a1bd3a70c607b2e29f0adc6159f36a7e40eaba59846414765fd4/fonttools-4.61.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f3cb4a569029b9f291f88aafc927dd53683757e640081ca8c412781ea144565e", size = 2851593, upload-time = "2025-12-12T17:30:04.225Z" },
+ { url = "https://files.pythonhosted.org/packages/94/98/3c4cb97c64713a8cf499b3245c3bf9a2b8fd16a3e375feff2aed78f96259/fonttools-4.61.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41a7170d042e8c0024703ed13b71893519a1a6d6e18e933e3ec7507a2c26a4b2", size = 2400231, upload-time = "2025-12-12T17:30:06.47Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/37/82dbef0f6342eb01f54bca073ac1498433d6ce71e50c3c3282b655733b31/fonttools-4.61.1-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:10d88e55330e092940584774ee5e8a6971b01fc2f4d3466a1d6c158230880796", size = 4954103, upload-time = "2025-12-12T17:30:08.432Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/44/f3aeac0fa98e7ad527f479e161aca6c3a1e47bb6996b053d45226fe37bf2/fonttools-4.61.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:15acc09befd16a0fb8a8f62bc147e1a82817542d72184acca9ce6e0aeda9fa6d", size = 5004295, upload-time = "2025-12-12T17:30:10.56Z" },
+ { url = "https://files.pythonhosted.org/packages/14/e8/7424ced75473983b964d09f6747fa09f054a6d656f60e9ac9324cf40c743/fonttools-4.61.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e6bcdf33aec38d16508ce61fd81838f24c83c90a1d1b8c68982857038673d6b8", size = 4944109, upload-time = "2025-12-12T17:30:12.874Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/8b/6391b257fa3d0b553d73e778f953a2f0154292a7a7a085e2374b111e5410/fonttools-4.61.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5fade934607a523614726119164ff621e8c30e8fa1ffffbbd358662056ba69f0", size = 5093598, upload-time = "2025-12-12T17:30:15.79Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/71/fd2ea96cdc512d92da5678a1c98c267ddd4d8c5130b76d0f7a80f9a9fde8/fonttools-4.61.1-cp312-cp312-win32.whl", hash = "sha256:75da8f28eff26defba42c52986de97b22106cb8f26515b7c22443ebc9c2d3261", size = 2269060, upload-time = "2025-12-12T17:30:18.058Z" },
+ { url = "https://files.pythonhosted.org/packages/80/3b/a3e81b71aed5a688e89dfe0e2694b26b78c7d7f39a5ffd8a7d75f54a12a8/fonttools-4.61.1-cp312-cp312-win_amd64.whl", hash = "sha256:497c31ce314219888c0e2fce5ad9178ca83fe5230b01a5006726cdf3ac9f24d9", size = 2319078, upload-time = "2025-12-12T17:30:22.862Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/cf/00ba28b0990982530addb8dc3e9e6f2fa9cb5c20df2abdda7baa755e8fe1/fonttools-4.61.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8c56c488ab471628ff3bfa80964372fc13504ece601e0d97a78ee74126b2045c", size = 2846454, upload-time = "2025-12-12T17:30:24.938Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/ca/468c9a8446a2103ae645d14fee3f610567b7042aba85031c1c65e3ef7471/fonttools-4.61.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dc492779501fa723b04d0ab1f5be046797fee17d27700476edc7ee9ae535a61e", size = 2398191, upload-time = "2025-12-12T17:30:27.343Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/4b/d67eedaed19def5967fade3297fed8161b25ba94699efc124b14fb68cdbc/fonttools-4.61.1-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:64102ca87e84261419c3747a0d20f396eb024bdbeb04c2bfb37e2891f5fadcb5", size = 4928410, upload-time = "2025-12-12T17:30:29.771Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/8d/6fb3494dfe61a46258cd93d979cf4725ded4eb46c2a4ca35e4490d84daea/fonttools-4.61.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c1b526c8d3f615a7b1867f38a9410849c8f4aef078535742198e942fba0e9bd", size = 4984460, upload-time = "2025-12-12T17:30:32.073Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/f1/a47f1d30b3dc00d75e7af762652d4cbc3dff5c2697a0dbd5203c81afd9c3/fonttools-4.61.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:41ed4b5ec103bd306bb68f81dc166e77409e5209443e5773cb4ed837bcc9b0d3", size = 4925800, upload-time = "2025-12-12T17:30:34.339Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/01/e6ae64a0981076e8a66906fab01539799546181e32a37a0257b77e4aa88b/fonttools-4.61.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b501c862d4901792adaec7c25b1ecc749e2662543f68bb194c42ba18d6eec98d", size = 5067859, upload-time = "2025-12-12T17:30:36.593Z" },
+ { url = "https://files.pythonhosted.org/packages/73/aa/28e40b8d6809a9b5075350a86779163f074d2b617c15d22343fce81918db/fonttools-4.61.1-cp313-cp313-win32.whl", hash = "sha256:4d7092bb38c53bbc78e9255a59158b150bcdc115a1e3b3ce0b5f267dc35dd63c", size = 2267821, upload-time = "2025-12-12T17:30:38.478Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/59/453c06d1d83dc0951b69ef692d6b9f1846680342927df54e9a1ca91c6f90/fonttools-4.61.1-cp313-cp313-win_amd64.whl", hash = "sha256:21e7c8d76f62ab13c9472ccf74515ca5b9a761d1bde3265152a6dc58700d895b", size = 2318169, upload-time = "2025-12-12T17:30:40.951Z" },
+ { url = "https://files.pythonhosted.org/packages/32/8f/4e7bf82c0cbb738d3c2206c920ca34ca74ef9dabde779030145d28665104/fonttools-4.61.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:fff4f534200a04b4a36e7ae3cb74493afe807b517a09e99cb4faa89a34ed6ecd", size = 2846094, upload-time = "2025-12-12T17:30:43.511Z" },
+ { url = "https://files.pythonhosted.org/packages/71/09/d44e45d0a4f3a651f23a1e9d42de43bc643cce2971b19e784cc67d823676/fonttools-4.61.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d9203500f7c63545b4ce3799319fe4d9feb1a1b89b28d3cb5abd11b9dd64147e", size = 2396589, upload-time = "2025-12-12T17:30:45.681Z" },
+ { url = "https://files.pythonhosted.org/packages/89/18/58c64cafcf8eb677a99ef593121f719e6dcbdb7d1c594ae5a10d4997ca8a/fonttools-4.61.1-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fa646ecec9528bef693415c79a86e733c70a4965dd938e9a226b0fc64c9d2e6c", size = 4877892, upload-time = "2025-12-12T17:30:47.709Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/ec/9e6b38c7ba1e09eb51db849d5450f4c05b7e78481f662c3b79dbde6f3d04/fonttools-4.61.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:11f35ad7805edba3aac1a3710d104592df59f4b957e30108ae0ba6c10b11dd75", size = 4972884, upload-time = "2025-12-12T17:30:49.656Z" },
+ { url = "https://files.pythonhosted.org/packages/5e/87/b5339da8e0256734ba0dbbf5b6cdebb1dd79b01dc8c270989b7bcd465541/fonttools-4.61.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b931ae8f62db78861b0ff1ac017851764602288575d65b8e8ff1963fed419063", size = 4924405, upload-time = "2025-12-12T17:30:51.735Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/47/e3409f1e1e69c073a3a6fd8cb886eb18c0bae0ee13db2c8d5e7f8495e8b7/fonttools-4.61.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b148b56f5de675ee16d45e769e69f87623a4944f7443850bf9a9376e628a89d2", size = 5035553, upload-time = "2025-12-12T17:30:54.823Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/b6/1f6600161b1073a984294c6c031e1a56ebf95b6164249eecf30012bb2e38/fonttools-4.61.1-cp314-cp314-win32.whl", hash = "sha256:9b666a475a65f4e839d3d10473fad6d47e0a9db14a2f4a224029c5bfde58ad2c", size = 2271915, upload-time = "2025-12-12T17:30:57.913Z" },
+ { url = "https://files.pythonhosted.org/packages/52/7b/91e7b01e37cc8eb0e1f770d08305b3655e4f002fc160fb82b3390eabacf5/fonttools-4.61.1-cp314-cp314-win_amd64.whl", hash = "sha256:4f5686e1fe5fce75d82d93c47a438a25bf0d1319d2843a926f741140b2b16e0c", size = 2323487, upload-time = "2025-12-12T17:30:59.804Z" },
+ { url = "https://files.pythonhosted.org/packages/39/5c/908ad78e46c61c3e3ed70c3b58ff82ab48437faf84ec84f109592cabbd9f/fonttools-4.61.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:e76ce097e3c57c4bcb67c5aa24a0ecdbd9f74ea9219997a707a4061fbe2707aa", size = 2929571, upload-time = "2025-12-12T17:31:02.574Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/41/975804132c6dea64cdbfbaa59f3518a21c137a10cccf962805b301ac6ab2/fonttools-4.61.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:9cfef3ab326780c04d6646f68d4b4742aae222e8b8ea1d627c74e38afcbc9d91", size = 2435317, upload-time = "2025-12-12T17:31:04.974Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/5a/aef2a0a8daf1ebaae4cfd83f84186d4a72ee08fd6a8451289fcd03ffa8a4/fonttools-4.61.1-cp314-cp314t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a75c301f96db737e1c5ed5fd7d77d9c34466de16095a266509e13da09751bd19", size = 4882124, upload-time = "2025-12-12T17:31:07.456Z" },
+ { url = "https://files.pythonhosted.org/packages/80/33/d6db3485b645b81cea538c9d1c9219d5805f0877fda18777add4671c5240/fonttools-4.61.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:91669ccac46bbc1d09e9273546181919064e8df73488ea087dcac3e2968df9ba", size = 5100391, upload-time = "2025-12-12T17:31:09.732Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/d6/675ba631454043c75fcf76f0ca5463eac8eb0666ea1d7badae5fea001155/fonttools-4.61.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c33ab3ca9d3ccd581d58e989d67554e42d8d4ded94ab3ade3508455fe70e65f7", size = 4978800, upload-time = "2025-12-12T17:31:11.681Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/33/d3ec753d547a8d2bdaedd390d4a814e8d5b45a093d558f025c6b990b554c/fonttools-4.61.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:664c5a68ec406f6b1547946683008576ef8b38275608e1cee6c061828171c118", size = 5006426, upload-time = "2025-12-12T17:31:13.764Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/40/cc11f378b561a67bea850ab50063366a0d1dd3f6d0a30ce0f874b0ad5664/fonttools-4.61.1-cp314-cp314t-win32.whl", hash = "sha256:aed04cabe26f30c1647ef0e8fbb207516fd40fe9472e9439695f5c6998e60ac5", size = 2335377, upload-time = "2025-12-12T17:31:16.49Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/ff/c9a2b66b39f8628531ea58b320d66d951267c98c6a38684daa8f50fb02f8/fonttools-4.61.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2180f14c141d2f0f3da43f3a81bc8aa4684860f6b0e6f9e165a4831f24e6a23b", size = 2400613, upload-time = "2025-12-12T17:31:18.769Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/4e/ce75a57ff3aebf6fc1f4e9d508b8e5810618a33d900ad6c19eb30b290b97/fonttools-4.61.1-py3-none-any.whl", hash = "sha256:17d2bf5d541add43822bcf0c43d7d847b160c9bb01d15d5007d84e2217aaa371", size = 1148996, upload-time = "2025-12-12T17:31:21.03Z" },
+]
+
+[[package]]
+name = "frozenlist"
+version = "1.8.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/83/4a/557715d5047da48d54e659203b9335be7bfaafda2c3f627b7c47e0b3aaf3/frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011", size = 86230, upload-time = "2025-10-06T05:35:23.699Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/fb/c85f9fed3ea8fe8740e5b46a59cc141c23b842eca617da8876cfce5f760e/frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565", size = 49621, upload-time = "2025-10-06T05:35:25.341Z" },
+ { url = "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad", size = 49889, upload-time = "2025-10-06T05:35:26.797Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/ed/c7895fd2fde7f3ee70d248175f9b6cdf792fb741ab92dc59cd9ef3bd241b/frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2", size = 219464, upload-time = "2025-10-06T05:35:28.254Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/83/4d587dccbfca74cb8b810472392ad62bfa100bf8108c7223eb4c4fa2f7b3/frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186", size = 221649, upload-time = "2025-10-06T05:35:29.454Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/c6/fd3b9cd046ec5fff9dab66831083bc2077006a874a2d3d9247dea93ddf7e/frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e", size = 219188, upload-time = "2025-10-06T05:35:30.951Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/80/6693f55eb2e085fc8afb28cf611448fb5b90e98e068fa1d1b8d8e66e5c7d/frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450", size = 231748, upload-time = "2025-10-06T05:35:32.101Z" },
+ { url = "https://files.pythonhosted.org/packages/97/d6/e9459f7c5183854abd989ba384fe0cc1a0fb795a83c033f0571ec5933ca4/frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef", size = 236351, upload-time = "2025-10-06T05:35:33.834Z" },
+ { url = "https://files.pythonhosted.org/packages/97/92/24e97474b65c0262e9ecd076e826bfd1d3074adcc165a256e42e7b8a7249/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4", size = 218767, upload-time = "2025-10-06T05:35:35.205Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/bf/dc394a097508f15abff383c5108cb8ad880d1f64a725ed3b90d5c2fbf0bb/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff", size = 235887, upload-time = "2025-10-06T05:35:36.354Z" },
+ { url = "https://files.pythonhosted.org/packages/40/90/25b201b9c015dbc999a5baf475a257010471a1fa8c200c843fd4abbee725/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c", size = 228785, upload-time = "2025-10-06T05:35:37.949Z" },
+ { url = "https://files.pythonhosted.org/packages/84/f4/b5bc148df03082f05d2dd30c089e269acdbe251ac9a9cf4e727b2dbb8a3d/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f", size = 230312, upload-time = "2025-10-06T05:35:39.178Z" },
+ { url = "https://files.pythonhosted.org/packages/db/4b/87e95b5d15097c302430e647136b7d7ab2398a702390cf4c8601975709e7/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7", size = 217650, upload-time = "2025-10-06T05:35:40.377Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/70/78a0315d1fea97120591a83e0acd644da638c872f142fd72a6cebee825f3/frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a", size = 39659, upload-time = "2025-10-06T05:35:41.863Z" },
+ { url = "https://files.pythonhosted.org/packages/66/aa/3f04523fb189a00e147e60c5b2205126118f216b0aa908035c45336e27e4/frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6", size = 43837, upload-time = "2025-10-06T05:35:43.205Z" },
+ { url = "https://files.pythonhosted.org/packages/39/75/1135feecdd7c336938bd55b4dc3b0dfc46d85b9be12ef2628574b28de776/frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e", size = 39989, upload-time = "2025-10-06T05:35:44.596Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/03/077f869d540370db12165c0aa51640a873fb661d8b315d1d4d67b284d7ac/frozenlist-1.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:09474e9831bc2b2199fad6da3c14c7b0fbdd377cce9d3d77131be28906cb7d84", size = 86912, upload-time = "2025-10-06T05:35:45.98Z" },
+ { url = "https://files.pythonhosted.org/packages/df/b5/7610b6bd13e4ae77b96ba85abea1c8cb249683217ef09ac9e0ae93f25a91/frozenlist-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17c883ab0ab67200b5f964d2b9ed6b00971917d5d8a92df149dc2c9779208ee9", size = 50046, upload-time = "2025-10-06T05:35:47.009Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/ef/0e8f1fe32f8a53dd26bdd1f9347efe0778b0fddf62789ea683f4cc7d787d/frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa47e444b8ba08fffd1c18e8cdb9a75db1b6a27f17507522834ad13ed5922b93", size = 50119, upload-time = "2025-10-06T05:35:48.38Z" },
+ { url = "https://files.pythonhosted.org/packages/11/b1/71a477adc7c36e5fb628245dfbdea2166feae310757dea848d02bd0689fd/frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2552f44204b744fba866e573be4c1f9048d6a324dfe14475103fd51613eb1d1f", size = 231067, upload-time = "2025-10-06T05:35:49.97Z" },
+ { url = "https://files.pythonhosted.org/packages/45/7e/afe40eca3a2dc19b9904c0f5d7edfe82b5304cb831391edec0ac04af94c2/frozenlist-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:957e7c38f250991e48a9a73e6423db1bb9dd14e722a10f6b8bb8e16a0f55f695", size = 233160, upload-time = "2025-10-06T05:35:51.729Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/aa/7416eac95603ce428679d273255ffc7c998d4132cfae200103f164b108aa/frozenlist-1.8.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8585e3bb2cdea02fc88ffa245069c36555557ad3609e83be0ec71f54fd4abb52", size = 228544, upload-time = "2025-10-06T05:35:53.246Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/3d/2a2d1f683d55ac7e3875e4263d28410063e738384d3adc294f5ff3d7105e/frozenlist-1.8.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:edee74874ce20a373d62dc28b0b18b93f645633c2943fd90ee9d898550770581", size = 243797, upload-time = "2025-10-06T05:35:54.497Z" },
+ { url = "https://files.pythonhosted.org/packages/78/1e/2d5565b589e580c296d3bb54da08d206e797d941a83a6fdea42af23be79c/frozenlist-1.8.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c9a63152fe95756b85f31186bddf42e4c02c6321207fd6601a1c89ebac4fe567", size = 247923, upload-time = "2025-10-06T05:35:55.861Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/c3/65872fcf1d326a7f101ad4d86285c403c87be7d832b7470b77f6d2ed5ddc/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6db2185db9be0a04fecf2f241c70b63b1a242e2805be291855078f2b404dd6b", size = 230886, upload-time = "2025-10-06T05:35:57.399Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/76/ac9ced601d62f6956f03cc794f9e04c81719509f85255abf96e2510f4265/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f4be2e3d8bc8aabd566f8d5b8ba7ecc09249d74ba3c9ed52e54dc23a293f0b92", size = 245731, upload-time = "2025-10-06T05:35:58.563Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/49/ecccb5f2598daf0b4a1415497eba4c33c1e8ce07495eb07d2860c731b8d5/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c8d1634419f39ea6f5c427ea2f90ca85126b54b50837f31497f3bf38266e853d", size = 241544, upload-time = "2025-10-06T05:35:59.719Z" },
+ { url = "https://files.pythonhosted.org/packages/53/4b/ddf24113323c0bbcc54cb38c8b8916f1da7165e07b8e24a717b4a12cbf10/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1a7fa382a4a223773ed64242dbe1c9c326ec09457e6b8428efb4118c685c3dfd", size = 241806, upload-time = "2025-10-06T05:36:00.959Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/fb/9b9a084d73c67175484ba2789a59f8eebebd0827d186a8102005ce41e1ba/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:11847b53d722050808926e785df837353bd4d75f1d494377e59b23594d834967", size = 229382, upload-time = "2025-10-06T05:36:02.22Z" },
+ { url = "https://files.pythonhosted.org/packages/95/a3/c8fb25aac55bf5e12dae5c5aa6a98f85d436c1dc658f21c3ac73f9fa95e5/frozenlist-1.8.0-cp311-cp311-win32.whl", hash = "sha256:27c6e8077956cf73eadd514be8fb04d77fc946a7fe9f7fe167648b0b9085cc25", size = 39647, upload-time = "2025-10-06T05:36:03.409Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/f5/603d0d6a02cfd4c8f2a095a54672b3cf967ad688a60fb9faf04fc4887f65/frozenlist-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac913f8403b36a2c8610bbfd25b8013488533e71e62b4b4adce9c86c8cea905b", size = 44064, upload-time = "2025-10-06T05:36:04.368Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/16/c2c9ab44e181f043a86f9a8f84d5124b62dbcb3a02c0977ec72b9ac1d3e0/frozenlist-1.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:d4d3214a0f8394edfa3e303136d0575eece0745ff2b47bd2cb2e66dd92d4351a", size = 39937, upload-time = "2025-10-06T05:36:05.669Z" },
+ { url = "https://files.pythonhosted.org/packages/69/29/948b9aa87e75820a38650af445d2ef2b6b8a6fab1a23b6bb9e4ef0be2d59/frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1", size = 87782, upload-time = "2025-10-06T05:36:06.649Z" },
+ { url = "https://files.pythonhosted.org/packages/64/80/4f6e318ee2a7c0750ed724fa33a4bdf1eacdc5a39a7a24e818a773cd91af/frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b", size = 50594, upload-time = "2025-10-06T05:36:07.69Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4", size = 50448, upload-time = "2025-10-06T05:36:08.78Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/bd/d91c5e39f490a49df14320f4e8c80161cfcce09f1e2cde1edd16a551abb3/frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383", size = 242411, upload-time = "2025-10-06T05:36:09.801Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/83/f61505a05109ef3293dfb1ff594d13d64a2324ac3482be2cedc2be818256/frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4", size = 243014, upload-time = "2025-10-06T05:36:11.394Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/cb/cb6c7b0f7d4023ddda30cf56b8b17494eb3a79e3fda666bf735f63118b35/frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8", size = 234909, upload-time = "2025-10-06T05:36:12.598Z" },
+ { url = "https://files.pythonhosted.org/packages/31/c5/cd7a1f3b8b34af009fb17d4123c5a778b44ae2804e3ad6b86204255f9ec5/frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b", size = 250049, upload-time = "2025-10-06T05:36:14.065Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/01/2f95d3b416c584a1e7f0e1d6d31998c4a795f7544069ee2e0962a4b60740/frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52", size = 256485, upload-time = "2025-10-06T05:36:15.39Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/03/024bf7720b3abaebcff6d0793d73c154237b85bdf67b7ed55e5e9596dc9a/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29", size = 237619, upload-time = "2025-10-06T05:36:16.558Z" },
+ { url = "https://files.pythonhosted.org/packages/69/fa/f8abdfe7d76b731f5d8bd217827cf6764d4f1d9763407e42717b4bed50a0/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3", size = 250320, upload-time = "2025-10-06T05:36:17.821Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/3c/b051329f718b463b22613e269ad72138cc256c540f78a6de89452803a47d/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143", size = 246820, upload-time = "2025-10-06T05:36:19.046Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/ae/58282e8f98e444b3f4dd42448ff36fa38bef29e40d40f330b22e7108f565/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608", size = 250518, upload-time = "2025-10-06T05:36:20.763Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/96/007e5944694d66123183845a106547a15944fbbb7154788cbf7272789536/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa", size = 239096, upload-time = "2025-10-06T05:36:22.129Z" },
+ { url = "https://files.pythonhosted.org/packages/66/bb/852b9d6db2fa40be96f29c0d1205c306288f0684df8fd26ca1951d461a56/frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf", size = 39985, upload-time = "2025-10-06T05:36:23.661Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/af/38e51a553dd66eb064cdf193841f16f077585d4d28394c2fa6235cb41765/frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746", size = 44591, upload-time = "2025-10-06T05:36:24.958Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/06/1dc65480ab147339fecc70797e9c2f69d9cea9cf38934ce08df070fdb9cb/frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd", size = 40102, upload-time = "2025-10-06T05:36:26.333Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/40/0832c31a37d60f60ed79e9dfb5a92e1e2af4f40a16a29abcc7992af9edff/frozenlist-1.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8d92f1a84bb12d9e56f818b3a746f3efba93c1b63c8387a73dde655e1e42282a", size = 85717, upload-time = "2025-10-06T05:36:27.341Z" },
+ { url = "https://files.pythonhosted.org/packages/30/ba/b0b3de23f40bc55a7057bd38434e25c34fa48e17f20ee273bbde5e0650f3/frozenlist-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96153e77a591c8adc2ee805756c61f59fef4cf4073a9275ee86fe8cba41241f7", size = 49651, upload-time = "2025-10-06T05:36:28.855Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f21f00a91358803399890ab167098c131ec2ddd5f8f5fd5fe9c9f2c6fcd91e40", size = 49417, upload-time = "2025-10-06T05:36:29.877Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/4e/e4691508f9477ce67da2015d8c00acd751e6287739123113a9fca6f1604e/frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb30f9626572a76dfe4293c7194a09fb1fe93ba94c7d4f720dfae3b646b45027", size = 234391, upload-time = "2025-10-06T05:36:31.301Z" },
+ { url = "https://files.pythonhosted.org/packages/40/76/c202df58e3acdf12969a7895fd6f3bc016c642e6726aa63bd3025e0fc71c/frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaa352d7047a31d87dafcacbabe89df0aa506abb5b1b85a2fb91bc3faa02d822", size = 233048, upload-time = "2025-10-06T05:36:32.531Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/c0/8746afb90f17b73ca5979c7a3958116e105ff796e718575175319b5bb4ce/frozenlist-1.8.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:03ae967b4e297f58f8c774c7eabcce57fe3c2434817d4385c50661845a058121", size = 226549, upload-time = "2025-10-06T05:36:33.706Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/eb/4c7eefc718ff72f9b6c4893291abaae5fbc0c82226a32dcd8ef4f7a5dbef/frozenlist-1.8.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6292f1de555ffcc675941d65fffffb0a5bcd992905015f85d0592201793e0e5", size = 239833, upload-time = "2025-10-06T05:36:34.947Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/4e/e5c02187cf704224f8b21bee886f3d713ca379535f16893233b9d672ea71/frozenlist-1.8.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29548f9b5b5e3460ce7378144c3010363d8035cea44bc0bf02d57f5a685e084e", size = 245363, upload-time = "2025-10-06T05:36:36.534Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/96/cb85ec608464472e82ad37a17f844889c36100eed57bea094518bf270692/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ec3cc8c5d4084591b4237c0a272cc4f50a5b03396a47d9caaf76f5d7b38a4f11", size = 229314, upload-time = "2025-10-06T05:36:38.582Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/6f/4ae69c550e4cee66b57887daeebe006fe985917c01d0fff9caab9883f6d0/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:517279f58009d0b1f2e7c1b130b377a349405da3f7621ed6bfae50b10adf20c1", size = 243365, upload-time = "2025-10-06T05:36:40.152Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/58/afd56de246cf11780a40a2c28dc7cbabbf06337cc8ddb1c780a2d97e88d8/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db1e72ede2d0d7ccb213f218df6a078a9c09a7de257c2fe8fcef16d5925230b1", size = 237763, upload-time = "2025-10-06T05:36:41.355Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/36/cdfaf6ed42e2644740d4a10452d8e97fa1c062e2a8006e4b09f1b5fd7d63/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b4dec9482a65c54a5044486847b8a66bf10c9cb4926d42927ec4e8fd5db7fed8", size = 240110, upload-time = "2025-10-06T05:36:42.716Z" },
+ { url = "https://files.pythonhosted.org/packages/03/a8/9ea226fbefad669f11b52e864c55f0bd57d3c8d7eb07e9f2e9a0b39502e1/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:21900c48ae04d13d416f0e1e0c4d81f7931f73a9dfa0b7a8746fb2fe7dd970ed", size = 233717, upload-time = "2025-10-06T05:36:44.251Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/0b/1b5531611e83ba7d13ccc9988967ea1b51186af64c42b7a7af465dcc9568/frozenlist-1.8.0-cp313-cp313-win32.whl", hash = "sha256:8b7b94a067d1c504ee0b16def57ad5738701e4ba10cec90529f13fa03c833496", size = 39628, upload-time = "2025-10-06T05:36:45.423Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/cf/174c91dbc9cc49bc7b7aab74d8b734e974d1faa8f191c74af9b7e80848e6/frozenlist-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:878be833caa6a3821caf85eb39c5ba92d28e85df26d57afb06b35b2efd937231", size = 43882, upload-time = "2025-10-06T05:36:46.796Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/17/502cd212cbfa96eb1388614fe39a3fc9ab87dbbe042b66f97acb57474834/frozenlist-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:44389d135b3ff43ba8cc89ff7f51f5a0bb6b63d829c8300f79a2fe4fe61bcc62", size = 39676, upload-time = "2025-10-06T05:36:47.8Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/5c/3bbfaa920dfab09e76946a5d2833a7cbdf7b9b4a91c714666ac4855b88b4/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e25ac20a2ef37e91c1b39938b591457666a0fa835c7783c3a8f33ea42870db94", size = 89235, upload-time = "2025-10-06T05:36:48.78Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/d6/f03961ef72166cec1687e84e8925838442b615bd0b8854b54923ce5b7b8a/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07cdca25a91a4386d2e76ad992916a85038a9b97561bf7a3fd12d5d9ce31870c", size = 50742, upload-time = "2025-10-06T05:36:49.837Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/bb/a6d12b7ba4c3337667d0e421f7181c82dda448ce4e7ad7ecd249a16fa806/frozenlist-1.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e0c11f2cc6717e0a741f84a527c52616140741cd812a50422f83dc31749fb52", size = 51725, upload-time = "2025-10-06T05:36:50.851Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/71/d1fed0ffe2c2ccd70b43714c6cab0f4188f09f8a67a7914a6b46ee30f274/frozenlist-1.8.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b3210649ee28062ea6099cfda39e147fa1bc039583c8ee4481cb7811e2448c51", size = 284533, upload-time = "2025-10-06T05:36:51.898Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/1f/fb1685a7b009d89f9bf78a42d94461bc06581f6e718c39344754a5d9bada/frozenlist-1.8.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581ef5194c48035a7de2aefc72ac6539823bb71508189e5de01d60c9dcd5fa65", size = 292506, upload-time = "2025-10-06T05:36:53.101Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/3b/b991fe1612703f7e0d05c0cf734c1b77aaf7c7d321df4572e8d36e7048c8/frozenlist-1.8.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3ef2d026f16a2b1866e1d86fc4e1291e1ed8a387b2c333809419a2f8b3a77b82", size = 274161, upload-time = "2025-10-06T05:36:54.309Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/ec/c5c618767bcdf66e88945ec0157d7f6c4a1322f1473392319b7a2501ded7/frozenlist-1.8.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5500ef82073f599ac84d888e3a8c1f77ac831183244bfd7f11eaa0289fb30714", size = 294676, upload-time = "2025-10-06T05:36:55.566Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/ce/3934758637d8f8a88d11f0585d6495ef54b2044ed6ec84492a91fa3b27aa/frozenlist-1.8.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50066c3997d0091c411a66e710f4e11752251e6d2d73d70d8d5d4c76442a199d", size = 300638, upload-time = "2025-10-06T05:36:56.758Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/4f/a7e4d0d467298f42de4b41cbc7ddaf19d3cfeabaf9ff97c20c6c7ee409f9/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5c1c8e78426e59b3f8005e9b19f6ff46e5845895adbde20ece9218319eca6506", size = 283067, upload-time = "2025-10-06T05:36:57.965Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/48/c7b163063d55a83772b268e6d1affb960771b0e203b632cfe09522d67ea5/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:eefdba20de0d938cec6a89bd4d70f346a03108a19b9df4248d3cf0d88f1b0f51", size = 292101, upload-time = "2025-10-06T05:36:59.237Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/d0/2366d3c4ecdc2fd391e0afa6e11500bfba0ea772764d631bbf82f0136c9d/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cf253e0e1c3ceb4aaff6df637ce033ff6535fb8c70a764a8f46aafd3d6ab798e", size = 289901, upload-time = "2025-10-06T05:37:00.811Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/94/daff920e82c1b70e3618a2ac39fbc01ae3e2ff6124e80739ce5d71c9b920/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:032efa2674356903cd0261c4317a561a6850f3ac864a63fc1583147fb05a79b0", size = 289395, upload-time = "2025-10-06T05:37:02.115Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/20/bba307ab4235a09fdcd3cc5508dbabd17c4634a1af4b96e0f69bfe551ebd/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6da155091429aeba16851ecb10a9104a108bcd32f6c1642867eadaee401c1c41", size = 283659, upload-time = "2025-10-06T05:37:03.711Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/00/04ca1c3a7a124b6de4f8a9a17cc2fcad138b4608e7a3fc5877804b8715d7/frozenlist-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b", size = 43492, upload-time = "2025-10-06T05:37:04.915Z" },
+ { url = "https://files.pythonhosted.org/packages/59/5e/c69f733a86a94ab10f68e496dc6b7e8bc078ebb415281d5698313e3af3a1/frozenlist-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888", size = 48034, upload-time = "2025-10-06T05:37:06.343Z" },
+ { url = "https://files.pythonhosted.org/packages/16/6c/be9d79775d8abe79b05fa6d23da99ad6e7763a1d080fbae7290b286093fd/frozenlist-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042", size = 41749, upload-time = "2025-10-06T05:37:07.431Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/c8/85da824b7e7b9b6e7f7705b2ecaf9591ba6f79c1177f324c2735e41d36a2/frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0", size = 86127, upload-time = "2025-10-06T05:37:08.438Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/e8/a1185e236ec66c20afd72399522f142c3724c785789255202d27ae992818/frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f", size = 49698, upload-time = "2025-10-06T05:37:09.48Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/93/72b1736d68f03fda5fdf0f2180fb6caaae3894f1b854d006ac61ecc727ee/frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c", size = 49749, upload-time = "2025-10-06T05:37:10.569Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/b2/fabede9fafd976b991e9f1b9c8c873ed86f202889b864756f240ce6dd855/frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2", size = 231298, upload-time = "2025-10-06T05:37:11.993Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/3b/d9b1e0b0eed36e70477ffb8360c49c85c8ca8ef9700a4e6711f39a6e8b45/frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8", size = 232015, upload-time = "2025-10-06T05:37:13.194Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/94/be719d2766c1138148564a3960fc2c06eb688da592bdc25adcf856101be7/frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686", size = 225038, upload-time = "2025-10-06T05:37:14.577Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/09/6712b6c5465f083f52f50cf74167b92d4ea2f50e46a9eea0523d658454ae/frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e", size = 240130, upload-time = "2025-10-06T05:37:15.781Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/d4/cd065cdcf21550b54f3ce6a22e143ac9e4836ca42a0de1022da8498eac89/frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a", size = 242845, upload-time = "2025-10-06T05:37:17.037Z" },
+ { url = "https://files.pythonhosted.org/packages/62/c3/f57a5c8c70cd1ead3d5d5f776f89d33110b1addae0ab010ad774d9a44fb9/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128", size = 229131, upload-time = "2025-10-06T05:37:18.221Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/52/232476fe9cb64f0742f3fde2b7d26c1dac18b6d62071c74d4ded55e0ef94/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f", size = 240542, upload-time = "2025-10-06T05:37:19.771Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/85/07bf3f5d0fb5414aee5f47d33c6f5c77bfe49aac680bfece33d4fdf6a246/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7", size = 237308, upload-time = "2025-10-06T05:37:20.969Z" },
+ { url = "https://files.pythonhosted.org/packages/11/99/ae3a33d5befd41ac0ca2cc7fd3aa707c9c324de2e89db0e0f45db9a64c26/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30", size = 238210, upload-time = "2025-10-06T05:37:22.252Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/60/b1d2da22f4970e7a155f0adde9b1435712ece01b3cd45ba63702aea33938/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7", size = 231972, upload-time = "2025-10-06T05:37:23.5Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/ab/945b2f32de889993b9c9133216c068b7fcf257d8595a0ac420ac8677cab0/frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806", size = 40536, upload-time = "2025-10-06T05:37:25.581Z" },
+ { url = "https://files.pythonhosted.org/packages/59/ad/9caa9b9c836d9ad6f067157a531ac48b7d36499f5036d4141ce78c230b1b/frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0", size = 44330, upload-time = "2025-10-06T05:37:26.928Z" },
+ { url = "https://files.pythonhosted.org/packages/82/13/e6950121764f2676f43534c555249f57030150260aee9dcf7d64efda11dd/frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b", size = 40627, upload-time = "2025-10-06T05:37:28.075Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/c7/43200656ecc4e02d3f8bc248df68256cd9572b3f0017f0a0c4e93440ae23/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d", size = 89238, upload-time = "2025-10-06T05:37:29.373Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/29/55c5f0689b9c0fb765055629f472c0de484dcaf0acee2f7707266ae3583c/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed", size = 50738, upload-time = "2025-10-06T05:37:30.792Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930", size = 51739, upload-time = "2025-10-06T05:37:32.127Z" },
+ { url = "https://files.pythonhosted.org/packages/62/1c/3d8622e60d0b767a5510d1d3cf21065b9db874696a51ea6d7a43180a259c/frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c", size = 284186, upload-time = "2025-10-06T05:37:33.21Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/14/aa36d5f85a89679a85a1d44cd7a6657e0b1c75f61e7cad987b203d2daca8/frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24", size = 292196, upload-time = "2025-10-06T05:37:36.107Z" },
+ { url = "https://files.pythonhosted.org/packages/05/23/6bde59eb55abd407d34f77d39a5126fb7b4f109a3f611d3929f14b700c66/frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37", size = 273830, upload-time = "2025-10-06T05:37:37.663Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/3f/22cff331bfad7a8afa616289000ba793347fcd7bc275f3b28ecea2a27909/frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a", size = 294289, upload-time = "2025-10-06T05:37:39.261Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/89/5b057c799de4838b6c69aa82b79705f2027615e01be996d2486a69ca99c4/frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2", size = 300318, upload-time = "2025-10-06T05:37:43.213Z" },
+ { url = "https://files.pythonhosted.org/packages/30/de/2c22ab3eb2a8af6d69dc799e48455813bab3690c760de58e1bf43b36da3e/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef", size = 282814, upload-time = "2025-10-06T05:37:45.337Z" },
+ { url = "https://files.pythonhosted.org/packages/59/f7/970141a6a8dbd7f556d94977858cfb36fa9b66e0892c6dd780d2219d8cd8/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe", size = 291762, upload-time = "2025-10-06T05:37:46.657Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/15/ca1adae83a719f82df9116d66f5bb28bb95557b3951903d39135620ef157/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8", size = 289470, upload-time = "2025-10-06T05:37:47.946Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/83/dca6dc53bf657d371fbc88ddeb21b79891e747189c5de990b9dfff2ccba1/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a", size = 289042, upload-time = "2025-10-06T05:37:49.499Z" },
+ { url = "https://files.pythonhosted.org/packages/96/52/abddd34ca99be142f354398700536c5bd315880ed0a213812bc491cff5e4/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e", size = 283148, upload-time = "2025-10-06T05:37:50.745Z" },
+ { url = "https://files.pythonhosted.org/packages/af/d3/76bd4ed4317e7119c2b7f57c3f6934aba26d277acc6309f873341640e21f/frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df", size = 44676, upload-time = "2025-10-06T05:37:52.222Z" },
+ { url = "https://files.pythonhosted.org/packages/89/76/c615883b7b521ead2944bb3480398cbb07e12b7b4e4d073d3752eb721558/frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd", size = 49451, upload-time = "2025-10-06T05:37:53.425Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/a3/5982da14e113d07b325230f95060e2169f5311b1017ea8af2a29b374c289/frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79", size = 42507, upload-time = "2025-10-06T05:37:54.513Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/59/ae5cdac87a00962122ea37bb346d41b66aec05f9ce328fa2b9e216f8967b/frozenlist-1.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d8b7138e5cd0647e4523d6685b0eac5d4be9a184ae9634492f25c6eb38c12a47", size = 86967, upload-time = "2025-10-06T05:37:55.607Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/10/17059b2db5a032fd9323c41c39e9d1f5f9d0c8f04d1e4e3e788573086e61/frozenlist-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a6483e309ca809f1efd154b4d37dc6d9f61037d6c6a81c2dc7a15cb22c8c5dca", size = 49984, upload-time = "2025-10-06T05:37:57.049Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/de/ad9d82ca8e5fa8f0c636e64606553c79e2b859ad253030b62a21fe9986f5/frozenlist-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1b9290cf81e95e93fdf90548ce9d3c1211cf574b8e3f4b3b7cb0537cf2227068", size = 50240, upload-time = "2025-10-06T05:37:58.145Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/45/3dfb7767c2a67d123650122b62ce13c731b6c745bc14424eea67678b508c/frozenlist-1.8.0-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:59a6a5876ca59d1b63af8cd5e7ffffb024c3dc1e9cf9301b21a2e76286505c95", size = 219472, upload-time = "2025-10-06T05:37:59.239Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/bf/5bf23d913a741b960d5c1dac7c1985d8a2a1d015772b2d18ea168b08e7ff/frozenlist-1.8.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6dc4126390929823e2d2d9dc79ab4046ed74680360fc5f38b585c12c66cdf459", size = 221531, upload-time = "2025-10-06T05:38:00.521Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/03/27ec393f3b55860859f4b74cdc8c2a4af3dbf3533305e8eacf48a4fd9a54/frozenlist-1.8.0-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:332db6b2563333c5671fecacd085141b5800cb866be16d5e3eb15a2086476675", size = 219211, upload-time = "2025-10-06T05:38:01.842Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/ad/0fd00c404fa73fe9b169429e9a972d5ed807973c40ab6b3cf9365a33d360/frozenlist-1.8.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9ff15928d62a0b80bb875655c39bf517938c7d589554cbd2669be42d97c2cb61", size = 231775, upload-time = "2025-10-06T05:38:03.384Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/c3/86962566154cb4d2995358bc8331bfc4ea19d07db1a96f64935a1607f2b6/frozenlist-1.8.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7bf6cdf8e07c8151fba6fe85735441240ec7f619f935a5205953d58009aef8c6", size = 236631, upload-time = "2025-10-06T05:38:04.609Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/9e/6ffad161dbd83782d2c66dc4d378a9103b31770cb1e67febf43aea42d202/frozenlist-1.8.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:48e6d3f4ec5c7273dfe83ff27c91083c6c9065af655dc2684d2c200c94308bb5", size = 218632, upload-time = "2025-10-06T05:38:05.917Z" },
+ { url = "https://files.pythonhosted.org/packages/58/b2/4677eee46e0a97f9b30735e6ad0bf6aba3e497986066eb68807ac85cf60f/frozenlist-1.8.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:1a7607e17ad33361677adcd1443edf6f5da0ce5e5377b798fba20fae194825f3", size = 235967, upload-time = "2025-10-06T05:38:07.614Z" },
+ { url = "https://files.pythonhosted.org/packages/05/f3/86e75f8639c5a93745ca7addbbc9de6af56aebb930d233512b17e46f6493/frozenlist-1.8.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:5a3a935c3a4e89c733303a2d5a7c257ea44af3a56c8202df486b7f5de40f37e1", size = 228799, upload-time = "2025-10-06T05:38:08.845Z" },
+ { url = "https://files.pythonhosted.org/packages/30/00/39aad3a7f0d98f5eb1d99a3c311215674ed87061aecee7851974b335c050/frozenlist-1.8.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:940d4a017dbfed9daf46a3b086e1d2167e7012ee297fef9e1c545c4d022f5178", size = 230566, upload-time = "2025-10-06T05:38:10.52Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/4d/aa144cac44568d137846ddc4d5210fb5d9719eb1d7ec6fa2728a54b5b94a/frozenlist-1.8.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b9be22a69a014bc47e78072d0ecae716f5eb56c15238acca0f43d6eb8e4a5bda", size = 217715, upload-time = "2025-10-06T05:38:11.832Z" },
+ { url = "https://files.pythonhosted.org/packages/64/4c/8f665921667509d25a0dd72540513bc86b356c95541686f6442a3283019f/frozenlist-1.8.0-cp39-cp39-win32.whl", hash = "sha256:1aa77cb5697069af47472e39612976ed05343ff2e84a3dcf15437b232cbfd087", size = 39933, upload-time = "2025-10-06T05:38:13.061Z" },
+ { url = "https://files.pythonhosted.org/packages/79/bd/bcc926f87027fad5e59926ff12d136e1082a115025d33c032d1cd69ab377/frozenlist-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:7398c222d1d405e796970320036b1b563892b65809d9e5261487bb2c7f7b5c6a", size = 44121, upload-time = "2025-10-06T05:38:14.572Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/07/9c2e4eb7584af4b705237b971b89a4155a8e57599c4483a131a39256a9a0/frozenlist-1.8.0-cp39-cp39-win_arm64.whl", hash = "sha256:b4f3b365f31c6cd4af24545ca0a244a53688cad8834e32f56831c4923b50a103", size = 40312, upload-time = "2025-10-06T05:38:15.699Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" },
+]
+
+[[package]]
+name = "humanize"
+version = "4.15.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ba/66/a3921783d54be8a6870ac4ccffcd15c4dc0dd7fcce51c6d63b8c63935276/humanize-4.15.0.tar.gz", hash = "sha256:1dd098483eb1c7ee8e32eb2e99ad1910baefa4b75c3aff3a82f4d78688993b10", size = 83599, upload-time = "2025-12-20T20:16:13.19Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c5/7b/bca5613a0c3b542420cf92bd5e5fb8ebd5435ce1011a091f66bb7693285e/humanize-4.15.0-py3-none-any.whl", hash = "sha256:b1186eb9f5a9749cd9cb8565aee77919dd7c8d076161cf44d70e59e3301e1769", size = 132203, upload-time = "2025-12-20T20:16:11.67Z" },
+]
+
+[[package]]
+name = "id"
+version = "1.6.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "urllib3" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/6d/04/c2156091427636080787aac190019dc64096e56a23b7364d3c1764ee3a06/id-1.6.1.tar.gz", hash = "sha256:d0732d624fb46fd4e7bc4e5152f00214450953b9e772c182c1c22964def1a069", size = 18088, upload-time = "2026-02-04T16:19:41.26Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/42/77/de194443bf38daed9452139e960c632b0ef9f9a5dd9ce605fdf18ca9f1b1/id-1.6.1-py3-none-any.whl", hash = "sha256:f5ec41ed2629a508f5d0988eda142e190c9c6da971100612c4de9ad9f9b237ca", size = 14689, upload-time = "2026-02-04T16:19:40.051Z" },
+]
+
+[[package]]
+name = "idna"
+version = "3.11"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" },
+]
+
+[[package]]
+name = "importlib-metadata"
+version = "8.7.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "zipp" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/f3/49/3b30cad09e7771a4982d9975a8cbf64f00d4a1ececb53297f1d9a7be1b10/importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb", size = 57107, upload-time = "2025-12-21T10:00:19.278Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151", size = 27865, upload-time = "2025-12-21T10:00:18.329Z" },
+]
+
+[[package]]
+name = "importlib-resources"
+version = "6.5.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "zipp", marker = "python_full_version < '3.10'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/cf/8c/f834fbf984f691b4f7ff60f50b514cc3de5cc08abfc3295564dd89c5e2e7/importlib_resources-6.5.2.tar.gz", hash = "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c", size = 44693, upload-time = "2025-01-03T18:51:56.698Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a4/ed/1f1afb2e9e7f38a545d628f864d562a5ae64fe6f7a10e28ffb9b185b4e89/importlib_resources-6.5.2-py3-none-any.whl", hash = "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec", size = 37461, upload-time = "2025-01-03T18:51:54.306Z" },
+]
+
+[[package]]
+name = "iniconfig"
+version = "2.1.0"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version < '3.10'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" },
+]
+
+[[package]]
+name = "iniconfig"
+version = "2.3.0"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version >= '3.11'",
+ "python_full_version == '3.10.*'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
+]
+
+[[package]]
+name = "ipython"
+version = "8.18.1"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version < '3.10'",
+]
+dependencies = [
+ { name = "colorama", marker = "python_full_version < '3.10' and sys_platform == 'win32'" },
+ { name = "decorator", marker = "python_full_version < '3.10'" },
+ { name = "exceptiongroup", marker = "python_full_version < '3.10'" },
+ { name = "jedi", marker = "python_full_version < '3.10'" },
+ { name = "matplotlib-inline", marker = "python_full_version < '3.10'" },
+ { name = "pexpect", marker = "python_full_version < '3.10' and sys_platform != 'win32'" },
+ { name = "prompt-toolkit", marker = "python_full_version < '3.10'" },
+ { name = "pygments", marker = "python_full_version < '3.10'" },
+ { name = "stack-data", marker = "python_full_version < '3.10'" },
+ { name = "traitlets", marker = "python_full_version < '3.10'" },
+ { name = "typing-extensions", marker = "python_full_version < '3.10'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/b1/b9/3ba6c45a6df813c09a48bac313c22ff83efa26cbb55011218d925a46e2ad/ipython-8.18.1.tar.gz", hash = "sha256:ca6f079bb33457c66e233e4580ebfc4128855b4cf6370dddd73842a9563e8a27", size = 5486330, upload-time = "2023-11-27T09:58:34.596Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/47/6b/d9fdcdef2eb6a23f391251fde8781c38d42acd82abe84d054cb74f7863b0/ipython-8.18.1-py3-none-any.whl", hash = "sha256:e8267419d72d81955ec1177f8a29aaa90ac80ad647499201119e2f05e99aa397", size = 808161, upload-time = "2023-11-27T09:58:30.538Z" },
+]
+
+[[package]]
+name = "ipython"
+version = "8.38.0"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version == '3.10.*'",
+]
+dependencies = [
+ { name = "colorama", marker = "python_full_version == '3.10.*' and sys_platform == 'win32'" },
+ { name = "decorator", marker = "python_full_version == '3.10.*'" },
+ { name = "exceptiongroup", marker = "python_full_version == '3.10.*'" },
+ { name = "jedi", marker = "python_full_version == '3.10.*'" },
+ { name = "matplotlib-inline", marker = "python_full_version == '3.10.*'" },
+ { name = "pexpect", marker = "python_full_version == '3.10.*' and sys_platform != 'emscripten' and sys_platform != 'win32'" },
+ { name = "prompt-toolkit", marker = "python_full_version == '3.10.*'" },
+ { name = "pygments", marker = "python_full_version == '3.10.*'" },
+ { name = "stack-data", marker = "python_full_version == '3.10.*'" },
+ { name = "traitlets", marker = "python_full_version == '3.10.*'" },
+ { name = "typing-extensions", marker = "python_full_version == '3.10.*'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/e5/61/1810830e8b93c72dcd3c0f150c80a00c3deb229562d9423807ec92c3a539/ipython-8.38.0.tar.gz", hash = "sha256:9cfea8c903ce0867cc2f23199ed8545eb741f3a69420bfcf3743ad1cec856d39", size = 5513996, upload-time = "2026-01-05T10:59:06.901Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9f/df/db59624f4c71b39717c423409950ac3f2c8b2ce4b0aac843112c7fb3f721/ipython-8.38.0-py3-none-any.whl", hash = "sha256:750162629d800ac65bb3b543a14e7a74b0e88063eac9b92124d4b2aa3f6d8e86", size = 831813, upload-time = "2026-01-05T10:59:04.239Z" },
+]
+
+[[package]]
+name = "ipython"
+version = "9.10.0"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version >= '3.11'",
+]
+dependencies = [
+ { name = "colorama", marker = "python_full_version >= '3.11' and sys_platform == 'win32'" },
+ { name = "decorator", marker = "python_full_version >= '3.11'" },
+ { name = "ipython-pygments-lexers", marker = "python_full_version >= '3.11'" },
+ { name = "jedi", marker = "python_full_version >= '3.11'" },
+ { name = "matplotlib-inline", marker = "python_full_version >= '3.11'" },
+ { name = "pexpect", marker = "python_full_version >= '3.11' and sys_platform != 'emscripten' and sys_platform != 'win32'" },
+ { name = "prompt-toolkit", marker = "python_full_version >= '3.11'" },
+ { name = "pygments", marker = "python_full_version >= '3.11'" },
+ { name = "stack-data", marker = "python_full_version >= '3.11'" },
+ { name = "traitlets", marker = "python_full_version >= '3.11'" },
+ { name = "typing-extensions", marker = "python_full_version == '3.11.*'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a6/60/2111715ea11f39b1535bed6024b7dec7918b71e5e5d30855a5b503056b50/ipython-9.10.0.tar.gz", hash = "sha256:cd9e656be97618a0676d058134cd44e6dc7012c0e5cb36a9ce96a8c904adaf77", size = 4426526, upload-time = "2026-02-02T10:00:33.594Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3d/aa/898dec789a05731cd5a9f50605b7b44a72bd198fd0d4528e11fc610177cc/ipython-9.10.0-py3-none-any.whl", hash = "sha256:c6ab68cc23bba8c7e18e9b932797014cc61ea7fd6f19de180ab9ba73e65ee58d", size = 622774, upload-time = "2026-02-02T10:00:31.503Z" },
+]
+
+[[package]]
+name = "ipython-pygments-lexers"
+version = "1.1.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pygments", marker = "python_full_version >= '3.11'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" },
+]
+
+[[package]]
+name = "jaraco-classes"
+version = "3.4.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "more-itertools" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/06/c0/ed4a27bc5571b99e3cff68f8a9fa5b56ff7df1c2251cc715a652ddd26402/jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd", size = 11780, upload-time = "2024-03-31T07:27:36.643Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790", size = 6777, upload-time = "2024-03-31T07:27:34.792Z" },
+]
+
+[[package]]
+name = "jaraco-context"
+version = "6.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "backports-tarfile", marker = "python_full_version < '3.12'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/cb/9c/a788f5bb29c61e456b8ee52ce76dbdd32fd72cd73dd67bc95f42c7a8d13c/jaraco_context-6.1.0.tar.gz", hash = "sha256:129a341b0a85a7db7879e22acd66902fda67882db771754574338898b2d5d86f", size = 15850, upload-time = "2026-01-13T02:53:53.847Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/8d/48/aa685dbf1024c7bd82bede569e3a85f82c32fd3d79ba5fea578f0159571a/jaraco_context-6.1.0-py3-none-any.whl", hash = "sha256:a43b5ed85815223d0d3cfdb6d7ca0d2bc8946f28f30b6f3216bda070f68badda", size = 7065, upload-time = "2026-01-13T02:53:53.031Z" },
+]
+
+[[package]]
+name = "jaraco-functools"
+version = "4.4.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "more-itertools" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/0f/27/056e0638a86749374d6f57d0b0db39f29509cce9313cf91bdc0ac4d91084/jaraco_functools-4.4.0.tar.gz", hash = "sha256:da21933b0417b89515562656547a77b4931f98176eb173644c0d35032a33d6bb", size = 19943, upload-time = "2025-12-21T09:29:43.6Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fd/c4/813bb09f0985cb21e959f21f2464169eca882656849adf727ac7bb7e1767/jaraco_functools-4.4.0-py3-none-any.whl", hash = "sha256:9eec1e36f45c818d9bf307c8948eb03b2b56cd44087b3cdc989abca1f20b9176", size = 10481, upload-time = "2025-12-21T09:29:42.27Z" },
+]
+
+[[package]]
+name = "jedi"
+version = "0.19.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "parso" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" },
+]
+
+[[package]]
+name = "jeepney"
+version = "0.9.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/7b/6f/357efd7602486741aa73ffc0617fb310a29b588ed0fd69c2399acbb85b0c/jeepney-0.9.0.tar.gz", hash = "sha256:cf0e9e845622b81e4a28df94c40345400256ec608d0e55bb8a3feaa9163f5732", size = 106758, upload-time = "2025-02-27T18:51:01.684Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl", hash = "sha256:97e5714520c16fc0a45695e5365a2e11b81ea79bba796e26f9f1d178cb182683", size = 49010, upload-time = "2025-02-27T18:51:00.104Z" },
+]
+
+[[package]]
+name = "keyring"
+version = "25.7.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "importlib-metadata", marker = "python_full_version < '3.12'" },
+ { name = "jaraco-classes" },
+ { name = "jaraco-context" },
+ { name = "jaraco-functools" },
+ { name = "jeepney", marker = "sys_platform == 'linux'" },
+ { name = "pywin32-ctypes", marker = "sys_platform == 'win32'" },
+ { name = "secretstorage", version = "3.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' and sys_platform == 'linux'" },
+ { name = "secretstorage", version = "3.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' and sys_platform == 'linux'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/43/4b/674af6ef2f97d56f0ab5153bf0bfa28ccb6c3ed4d1babf4305449668807b/keyring-25.7.0.tar.gz", hash = "sha256:fe01bd85eb3f8fb3dd0405defdeac9a5b4f6f0439edbb3149577f244a2e8245b", size = 63516, upload-time = "2025-11-16T16:26:09.482Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl", hash = "sha256:be4a0b195f149690c166e850609a477c532ddbfbaed96a404d4e43f8d5e2689f", size = 39160, upload-time = "2025-11-16T16:26:08.402Z" },
+]
+
+[[package]]
+name = "kiwisolver"
+version = "1.4.7"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version < '3.10'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/85/4d/2255e1c76304cbd60b48cee302b66d1dde4468dc5b1160e4b7cb43778f2a/kiwisolver-1.4.7.tar.gz", hash = "sha256:9893ff81bd7107f7b685d3017cc6583daadb4fc26e4a888350df530e41980a60", size = 97286, upload-time = "2024-09-04T09:39:44.302Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/97/14/fc943dd65268a96347472b4fbe5dcc2f6f55034516f80576cd0dd3a8930f/kiwisolver-1.4.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8a9c83f75223d5e48b0bc9cb1bf2776cf01563e00ade8775ffe13b0b6e1af3a6", size = 122440, upload-time = "2024-09-04T09:03:44.9Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/46/e68fed66236b69dd02fcdb506218c05ac0e39745d696d22709498896875d/kiwisolver-1.4.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:58370b1ffbd35407444d57057b57da5d6549d2d854fa30249771775c63b5fe17", size = 65758, upload-time = "2024-09-04T09:03:46.582Z" },
+ { url = "https://files.pythonhosted.org/packages/ef/fa/65de49c85838681fc9cb05de2a68067a683717321e01ddafb5b8024286f0/kiwisolver-1.4.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aa0abdf853e09aff551db11fce173e2177d00786c688203f52c87ad7fcd91ef9", size = 64311, upload-time = "2024-09-04T09:03:47.973Z" },
+ { url = "https://files.pythonhosted.org/packages/42/9c/cc8d90f6ef550f65443bad5872ffa68f3dee36de4974768628bea7c14979/kiwisolver-1.4.7-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8d53103597a252fb3ab8b5845af04c7a26d5e7ea8122303dd7a021176a87e8b9", size = 1637109, upload-time = "2024-09-04T09:03:49.281Z" },
+ { url = "https://files.pythonhosted.org/packages/55/91/0a57ce324caf2ff5403edab71c508dd8f648094b18cfbb4c8cc0fde4a6ac/kiwisolver-1.4.7-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:88f17c5ffa8e9462fb79f62746428dd57b46eb931698e42e990ad63103f35e6c", size = 1617814, upload-time = "2024-09-04T09:03:51.444Z" },
+ { url = "https://files.pythonhosted.org/packages/12/5d/c36140313f2510e20207708adf36ae4919416d697ee0236b0ddfb6fd1050/kiwisolver-1.4.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a9ca9c710d598fd75ee5de59d5bda2684d9db36a9f50b6125eaea3969c2599", size = 1400881, upload-time = "2024-09-04T09:03:53.357Z" },
+ { url = "https://files.pythonhosted.org/packages/56/d0/786e524f9ed648324a466ca8df86298780ef2b29c25313d9a4f16992d3cf/kiwisolver-1.4.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f4d742cb7af1c28303a51b7a27aaee540e71bb8e24f68c736f6f2ffc82f2bf05", size = 1512972, upload-time = "2024-09-04T09:03:55.082Z" },
+ { url = "https://files.pythonhosted.org/packages/67/5a/77851f2f201e6141d63c10a0708e996a1363efaf9e1609ad0441b343763b/kiwisolver-1.4.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e28c7fea2196bf4c2f8d46a0415c77a1c480cc0724722f23d7410ffe9842c407", size = 1444787, upload-time = "2024-09-04T09:03:56.588Z" },
+ { url = "https://files.pythonhosted.org/packages/06/5f/1f5eaab84355885e224a6fc8d73089e8713dc7e91c121f00b9a1c58a2195/kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e968b84db54f9d42046cf154e02911e39c0435c9801681e3fc9ce8a3c4130278", size = 2199212, upload-time = "2024-09-04T09:03:58.557Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/28/9152a3bfe976a0ae21d445415defc9d1cd8614b2910b7614b30b27a47270/kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0c18ec74c0472de033e1bebb2911c3c310eef5649133dd0bedf2a169a1b269e5", size = 2346399, upload-time = "2024-09-04T09:04:00.178Z" },
+ { url = "https://files.pythonhosted.org/packages/26/f6/453d1904c52ac3b400f4d5e240ac5fec25263716723e44be65f4d7149d13/kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8f0ea6da6d393d8b2e187e6a5e3fb81f5862010a40c3945e2c6d12ae45cfb2ad", size = 2308688, upload-time = "2024-09-04T09:04:02.216Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/9a/d4968499441b9ae187e81745e3277a8b4d7c60840a52dc9d535a7909fac3/kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:f106407dda69ae456dd1227966bf445b157ccc80ba0dff3802bb63f30b74e895", size = 2445493, upload-time = "2024-09-04T09:04:04.571Z" },
+ { url = "https://files.pythonhosted.org/packages/07/c9/032267192e7828520dacb64dfdb1d74f292765f179e467c1cba97687f17d/kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:84ec80df401cfee1457063732d90022f93951944b5b58975d34ab56bb150dfb3", size = 2262191, upload-time = "2024-09-04T09:04:05.969Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/ad/db0aedb638a58b2951da46ddaeecf204be8b4f5454df020d850c7fa8dca8/kiwisolver-1.4.7-cp310-cp310-win32.whl", hash = "sha256:71bb308552200fb2c195e35ef05de12f0c878c07fc91c270eb3d6e41698c3bcc", size = 46644, upload-time = "2024-09-04T09:04:07.408Z" },
+ { url = "https://files.pythonhosted.org/packages/12/ca/d0f7b7ffbb0be1e7c2258b53554efec1fd652921f10d7d85045aff93ab61/kiwisolver-1.4.7-cp310-cp310-win_amd64.whl", hash = "sha256:44756f9fd339de0fb6ee4f8c1696cfd19b2422e0d70b4cefc1cc7f1f64045a8c", size = 55877, upload-time = "2024-09-04T09:04:08.869Z" },
+ { url = "https://files.pythonhosted.org/packages/97/6c/cfcc128672f47a3e3c0d918ecb67830600078b025bfc32d858f2e2d5c6a4/kiwisolver-1.4.7-cp310-cp310-win_arm64.whl", hash = "sha256:78a42513018c41c2ffd262eb676442315cbfe3c44eed82385c2ed043bc63210a", size = 48347, upload-time = "2024-09-04T09:04:10.106Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/44/77429fa0a58f941d6e1c58da9efe08597d2e86bf2b2cce6626834f49d07b/kiwisolver-1.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d2b0e12a42fb4e72d509fc994713d099cbb15ebf1103545e8a45f14da2dfca54", size = 122442, upload-time = "2024-09-04T09:04:11.432Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/20/8c75caed8f2462d63c7fd65e16c832b8f76cda331ac9e615e914ee80bac9/kiwisolver-1.4.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2a8781ac3edc42ea4b90bc23e7d37b665d89423818e26eb6df90698aa2287c95", size = 65762, upload-time = "2024-09-04T09:04:12.468Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/98/fe010f15dc7230f45bc4cf367b012d651367fd203caaa992fd1f5963560e/kiwisolver-1.4.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:46707a10836894b559e04b0fd143e343945c97fd170d69a2d26d640b4e297935", size = 64319, upload-time = "2024-09-04T09:04:13.635Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/1b/b5d618f4e58c0675654c1e5051bcf42c776703edb21c02b8c74135541f60/kiwisolver-1.4.7-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef97b8df011141c9b0f6caf23b29379f87dd13183c978a30a3c546d2c47314cb", size = 1334260, upload-time = "2024-09-04T09:04:14.878Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/01/946852b13057a162a8c32c4c8d2e9ed79f0bb5d86569a40c0b5fb103e373/kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ab58c12a2cd0fc769089e6d38466c46d7f76aced0a1f54c77652446733d2d02", size = 1426589, upload-time = "2024-09-04T09:04:16.514Z" },
+ { url = "https://files.pythonhosted.org/packages/70/d1/c9f96df26b459e15cf8a965304e6e6f4eb291e0f7a9460b4ad97b047561e/kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:803b8e1459341c1bb56d1c5c010406d5edec8a0713a0945851290a7930679b51", size = 1541080, upload-time = "2024-09-04T09:04:18.322Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/73/2686990eb8b02d05f3de759d6a23a4ee7d491e659007dd4c075fede4b5d0/kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9a9e8a507420fe35992ee9ecb302dab68550dedc0da9e2880dd88071c5fb052", size = 1470049, upload-time = "2024-09-04T09:04:20.266Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/4b/2db7af3ed3af7c35f388d5f53c28e155cd402a55432d800c543dc6deb731/kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18077b53dc3bb490e330669a99920c5e6a496889ae8c63b58fbc57c3d7f33a18", size = 1426376, upload-time = "2024-09-04T09:04:22.419Z" },
+ { url = "https://files.pythonhosted.org/packages/05/83/2857317d04ea46dc5d115f0df7e676997bbd968ced8e2bd6f7f19cfc8d7f/kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6af936f79086a89b3680a280c47ea90b4df7047b5bdf3aa5c524bbedddb9e545", size = 2222231, upload-time = "2024-09-04T09:04:24.526Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/b5/866f86f5897cd4ab6d25d22e403404766a123f138bd6a02ecb2cdde52c18/kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3abc5b19d24af4b77d1598a585b8a719beb8569a71568b66f4ebe1fb0449460b", size = 2368634, upload-time = "2024-09-04T09:04:25.899Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/ee/73de8385403faba55f782a41260210528fe3273d0cddcf6d51648202d6d0/kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:933d4de052939d90afbe6e9d5273ae05fb836cc86c15b686edd4b3560cc0ee36", size = 2329024, upload-time = "2024-09-04T09:04:28.523Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/e7/cd101d8cd2cdfaa42dc06c433df17c8303d31129c9fdd16c0ea37672af91/kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:65e720d2ab2b53f1f72fb5da5fb477455905ce2c88aaa671ff0a447c2c80e8e3", size = 2468484, upload-time = "2024-09-04T09:04:30.547Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/72/84f09d45a10bc57a40bb58b81b99d8f22b58b2040c912b7eb97ebf625bf2/kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3bf1ed55088f214ba6427484c59553123fdd9b218a42bbc8c6496d6754b1e523", size = 2284078, upload-time = "2024-09-04T09:04:33.218Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/d4/71828f32b956612dc36efd7be1788980cb1e66bfb3706e6dec9acad9b4f9/kiwisolver-1.4.7-cp311-cp311-win32.whl", hash = "sha256:4c00336b9dd5ad96d0a558fd18a8b6f711b7449acce4c157e7343ba92dd0cf3d", size = 46645, upload-time = "2024-09-04T09:04:34.371Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/65/d43e9a20aabcf2e798ad1aff6c143ae3a42cf506754bcb6a7ed8259c8425/kiwisolver-1.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:929e294c1ac1e9f615c62a4e4313ca1823ba37326c164ec720a803287c4c499b", size = 56022, upload-time = "2024-09-04T09:04:35.786Z" },
+ { url = "https://files.pythonhosted.org/packages/35/b3/9f75a2e06f1b4ca00b2b192bc2b739334127d27f1d0625627ff8479302ba/kiwisolver-1.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:e33e8fbd440c917106b237ef1a2f1449dfbb9b6f6e1ce17c94cd6a1e0d438376", size = 48536, upload-time = "2024-09-04T09:04:37.525Z" },
+ { url = "https://files.pythonhosted.org/packages/97/9c/0a11c714cf8b6ef91001c8212c4ef207f772dd84540104952c45c1f0a249/kiwisolver-1.4.7-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:5360cc32706dab3931f738d3079652d20982511f7c0ac5711483e6eab08efff2", size = 121808, upload-time = "2024-09-04T09:04:38.637Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/d8/0fe8c5f5d35878ddd135f44f2af0e4e1d379e1c7b0716f97cdcb88d4fd27/kiwisolver-1.4.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:942216596dc64ddb25adb215c3c783215b23626f8d84e8eff8d6d45c3f29f75a", size = 65531, upload-time = "2024-09-04T09:04:39.694Z" },
+ { url = "https://files.pythonhosted.org/packages/80/c5/57fa58276dfdfa612241d640a64ca2f76adc6ffcebdbd135b4ef60095098/kiwisolver-1.4.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:48b571ecd8bae15702e4f22d3ff6a0f13e54d3d00cd25216d5e7f658242065ee", size = 63894, upload-time = "2024-09-04T09:04:41.6Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/e9/26d3edd4c4ad1c5b891d8747a4f81b1b0aba9fb9721de6600a4adc09773b/kiwisolver-1.4.7-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad42ba922c67c5f219097b28fae965e10045ddf145d2928bfac2eb2e17673640", size = 1369296, upload-time = "2024-09-04T09:04:42.886Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/67/3f4850b5e6cffb75ec40577ddf54f7b82b15269cc5097ff2e968ee32ea7d/kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:612a10bdae23404a72941a0fc8fa2660c6ea1217c4ce0dbcab8a8f6543ea9e7f", size = 1461450, upload-time = "2024-09-04T09:04:46.284Z" },
+ { url = "https://files.pythonhosted.org/packages/52/be/86cbb9c9a315e98a8dc6b1d23c43cffd91d97d49318854f9c37b0e41cd68/kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e838bba3a3bac0fe06d849d29772eb1afb9745a59710762e4ba3f4cb8424483", size = 1579168, upload-time = "2024-09-04T09:04:47.91Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/00/65061acf64bd5fd34c1f4ae53f20b43b0a017a541f242a60b135b9d1e301/kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:22f499f6157236c19f4bbbd472fa55b063db77a16cd74d49afe28992dff8c258", size = 1507308, upload-time = "2024-09-04T09:04:49.465Z" },
+ { url = "https://files.pythonhosted.org/packages/21/e4/c0b6746fd2eb62fe702118b3ca0cb384ce95e1261cfada58ff693aeec08a/kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693902d433cf585133699972b6d7c42a8b9f8f826ebcaf0132ff55200afc599e", size = 1464186, upload-time = "2024-09-04T09:04:50.949Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/0f/529d0a9fffb4d514f2782c829b0b4b371f7f441d61aa55f1de1c614c4ef3/kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4e77f2126c3e0b0d055f44513ed349038ac180371ed9b52fe96a32aa071a5107", size = 2247877, upload-time = "2024-09-04T09:04:52.388Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/e1/66603ad779258843036d45adcbe1af0d1a889a07af4635f8b4ec7dccda35/kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:657a05857bda581c3656bfc3b20e353c232e9193eb167766ad2dc58b56504948", size = 2404204, upload-time = "2024-09-04T09:04:54.385Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/61/de5fb1ca7ad1f9ab7970e340a5b833d735df24689047de6ae71ab9d8d0e7/kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4bfa75a048c056a411f9705856abfc872558e33c055d80af6a380e3658766038", size = 2352461, upload-time = "2024-09-04T09:04:56.307Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/d2/0edc00a852e369827f7e05fd008275f550353f1f9bcd55db9363d779fc63/kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:34ea1de54beef1c104422d210c47c7d2a4999bdecf42c7b5718fbe59a4cac383", size = 2501358, upload-time = "2024-09-04T09:04:57.922Z" },
+ { url = "https://files.pythonhosted.org/packages/84/15/adc15a483506aec6986c01fb7f237c3aec4d9ed4ac10b756e98a76835933/kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:90da3b5f694b85231cf93586dad5e90e2d71b9428f9aad96952c99055582f520", size = 2314119, upload-time = "2024-09-04T09:04:59.332Z" },
+ { url = "https://files.pythonhosted.org/packages/36/08/3a5bb2c53c89660863a5aa1ee236912269f2af8762af04a2e11df851d7b2/kiwisolver-1.4.7-cp312-cp312-win32.whl", hash = "sha256:18e0cca3e008e17fe9b164b55735a325140a5a35faad8de92dd80265cd5eb80b", size = 46367, upload-time = "2024-09-04T09:05:00.804Z" },
+ { url = "https://files.pythonhosted.org/packages/19/93/c05f0a6d825c643779fc3c70876bff1ac221f0e31e6f701f0e9578690d70/kiwisolver-1.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:58cb20602b18f86f83a5c87d3ee1c766a79c0d452f8def86d925e6c60fbf7bfb", size = 55884, upload-time = "2024-09-04T09:05:01.924Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/f9/3828d8f21b6de4279f0667fb50a9f5215e6fe57d5ec0d61905914f5b6099/kiwisolver-1.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:f5a8b53bdc0b3961f8b6125e198617c40aeed638b387913bf1ce78afb1b0be2a", size = 48528, upload-time = "2024-09-04T09:05:02.983Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/06/7da99b04259b0f18b557a4effd1b9c901a747f7fdd84cf834ccf520cb0b2/kiwisolver-1.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2e6039dcbe79a8e0f044f1c39db1986a1b8071051efba3ee4d74f5b365f5226e", size = 121913, upload-time = "2024-09-04T09:05:04.072Z" },
+ { url = "https://files.pythonhosted.org/packages/97/f5/b8a370d1aa593c17882af0a6f6755aaecd643640c0ed72dcfd2eafc388b9/kiwisolver-1.4.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a1ecf0ac1c518487d9d23b1cd7139a6a65bc460cd101ab01f1be82ecf09794b6", size = 65627, upload-time = "2024-09-04T09:05:05.119Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/fc/6c0374f7503522539e2d4d1b497f5ebad3f8ed07ab51aed2af988dd0fb65/kiwisolver-1.4.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7ab9ccab2b5bd5702ab0803676a580fffa2aa178c2badc5557a84cc943fcf750", size = 63888, upload-time = "2024-09-04T09:05:06.191Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/3e/0b7172793d0f41cae5c923492da89a2ffcd1adf764c16159ca047463ebd3/kiwisolver-1.4.7-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f816dd2277f8d63d79f9c8473a79fe54047bc0467754962840782c575522224d", size = 1369145, upload-time = "2024-09-04T09:05:07.919Z" },
+ { url = "https://files.pythonhosted.org/packages/77/92/47d050d6f6aced2d634258123f2688fbfef8ded3c5baf2c79d94d91f1f58/kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf8bcc23ceb5a1b624572a1623b9f79d2c3b337c8c455405ef231933a10da379", size = 1461448, upload-time = "2024-09-04T09:05:10.01Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/1b/8f80b18e20b3b294546a1adb41701e79ae21915f4175f311a90d042301cf/kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dea0bf229319828467d7fca8c7c189780aa9ff679c94539eed7532ebe33ed37c", size = 1578750, upload-time = "2024-09-04T09:05:11.598Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/fe/fe8e72f3be0a844f257cadd72689c0848c6d5c51bc1d60429e2d14ad776e/kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c06a4c7cf15ec739ce0e5971b26c93638730090add60e183530d70848ebdd34", size = 1507175, upload-time = "2024-09-04T09:05:13.22Z" },
+ { url = "https://files.pythonhosted.org/packages/39/fa/cdc0b6105d90eadc3bee525fecc9179e2b41e1ce0293caaf49cb631a6aaf/kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:913983ad2deb14e66d83c28b632fd35ba2b825031f2fa4ca29675e665dfecbe1", size = 1463963, upload-time = "2024-09-04T09:05:15.925Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/5c/0c03c4e542720c6177d4f408e56d1c8315899db72d46261a4e15b8b33a41/kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5337ec7809bcd0f424c6b705ecf97941c46279cf5ed92311782c7c9c2026f07f", size = 2248220, upload-time = "2024-09-04T09:05:17.434Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/ee/55ef86d5a574f4e767df7da3a3a7ff4954c996e12d4fbe9c408170cd7dcc/kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4c26ed10c4f6fa6ddb329a5120ba3b6db349ca192ae211e882970bfc9d91420b", size = 2404463, upload-time = "2024-09-04T09:05:18.997Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/6d/73ad36170b4bff4825dc588acf4f3e6319cb97cd1fb3eb04d9faa6b6f212/kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c619b101e6de2222c1fcb0531e1b17bbffbe54294bfba43ea0d411d428618c27", size = 2352842, upload-time = "2024-09-04T09:05:21.299Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/16/fa531ff9199d3b6473bb4d0f47416cdb08d556c03b8bc1cccf04e756b56d/kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:073a36c8273647592ea332e816e75ef8da5c303236ec0167196793eb1e34657a", size = 2501635, upload-time = "2024-09-04T09:05:23.588Z" },
+ { url = "https://files.pythonhosted.org/packages/78/7e/aa9422e78419db0cbe75fb86d8e72b433818f2e62e2e394992d23d23a583/kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3ce6b2b0231bda412463e152fc18335ba32faf4e8c23a754ad50ffa70e4091ee", size = 2314556, upload-time = "2024-09-04T09:05:25.907Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/b2/15f7f556df0a6e5b3772a1e076a9d9f6c538ce5f05bd590eca8106508e06/kiwisolver-1.4.7-cp313-cp313-win32.whl", hash = "sha256:f4c9aee212bc89d4e13f58be11a56cc8036cabad119259d12ace14b34476fd07", size = 46364, upload-time = "2024-09-04T09:05:27.184Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/db/32e897e43a330eee8e4770bfd2737a9584b23e33587a0812b8e20aac38f7/kiwisolver-1.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:8a3ec5aa8e38fc4c8af308917ce12c536f1c88452ce554027e55b22cbbfbff76", size = 55887, upload-time = "2024-09-04T09:05:28.372Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/a4/df2bdca5270ca85fd25253049eb6708d4127be2ed0e5c2650217450b59e9/kiwisolver-1.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:76c8094ac20ec259471ac53e774623eb62e6e1f56cd8690c67ce6ce4fcb05650", size = 48530, upload-time = "2024-09-04T09:05:30.225Z" },
+ { url = "https://files.pythonhosted.org/packages/11/88/37ea0ea64512997b13d69772db8dcdc3bfca5442cda3a5e4bb943652ee3e/kiwisolver-1.4.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3f9362ecfca44c863569d3d3c033dbe8ba452ff8eed6f6b5806382741a1334bd", size = 122449, upload-time = "2024-09-04T09:05:55.311Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/45/5a5c46078362cb3882dcacad687c503089263c017ca1241e0483857791eb/kiwisolver-1.4.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e8df2eb9b2bac43ef8b082e06f750350fbbaf2887534a5be97f6cf07b19d9583", size = 65757, upload-time = "2024-09-04T09:05:56.906Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/be/a6ae58978772f685d48dd2e84460937761c53c4bbd84e42b0336473d9775/kiwisolver-1.4.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f32d6edbc638cde7652bd690c3e728b25332acbadd7cad670cc4a02558d9c417", size = 64312, upload-time = "2024-09-04T09:05:58.384Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/04/18ef6f452d311e1e1eb180c9bf5589187fa1f042db877e6fe443ef10099c/kiwisolver-1.4.7-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e2e6c39bd7b9372b0be21456caab138e8e69cc0fc1190a9dfa92bd45a1e6e904", size = 1626966, upload-time = "2024-09-04T09:05:59.855Z" },
+ { url = "https://files.pythonhosted.org/packages/21/b1/40655f6c3fa11ce740e8a964fa8e4c0479c87d6a7944b95af799c7a55dfe/kiwisolver-1.4.7-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dda56c24d869b1193fcc763f1284b9126550eaf84b88bbc7256e15028f19188a", size = 1607044, upload-time = "2024-09-04T09:06:02.16Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/93/af67dbcfb9b3323bbd2c2db1385a7139d8f77630e4a37bb945b57188eb2d/kiwisolver-1.4.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79849239c39b5e1fd906556c474d9b0439ea6792b637511f3fe3a41158d89ca8", size = 1391879, upload-time = "2024-09-04T09:06:03.908Z" },
+ { url = "https://files.pythonhosted.org/packages/40/6f/d60770ef98e77b365d96061d090c0cd9e23418121c55fff188fa4bdf0b54/kiwisolver-1.4.7-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5e3bc157fed2a4c02ec468de4ecd12a6e22818d4f09cde2c31ee3226ffbefab2", size = 1504751, upload-time = "2024-09-04T09:06:05.58Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/3a/5f38667d313e983c432f3fcd86932177519ed8790c724e07d77d1de0188a/kiwisolver-1.4.7-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3da53da805b71e41053dc670f9a820d1157aae77b6b944e08024d17bcd51ef88", size = 1436990, upload-time = "2024-09-04T09:06:08.126Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/3b/1520301a47326e6a6043b502647e42892be33b3f051e9791cc8bb43f1a32/kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8705f17dfeb43139a692298cb6637ee2e59c0194538153e83e9ee0c75c2eddde", size = 2191122, upload-time = "2024-09-04T09:06:10.345Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/c4/eb52da300c166239a2233f1f9c4a1b767dfab98fae27681bfb7ea4873cb6/kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:82a5c2f4b87c26bb1a0ef3d16b5c4753434633b83d365cc0ddf2770c93829e3c", size = 2338126, upload-time = "2024-09-04T09:06:12.321Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/cb/42b92fd5eadd708dd9107c089e817945500685f3437ce1fd387efebc6d6e/kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce8be0466f4c0d585cdb6c1e2ed07232221df101a4c6f28821d2aa754ca2d9e2", size = 2298313, upload-time = "2024-09-04T09:06:14.562Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/eb/be25aa791fe5fc75a8b1e0c965e00f942496bc04635c9aae8035f6b76dcd/kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:409afdfe1e2e90e6ee7fc896f3df9a7fec8e793e58bfa0d052c8a82f99c37abb", size = 2437784, upload-time = "2024-09-04T09:06:16.767Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/22/30a66be7f3368d76ff95689e1c2e28d382383952964ab15330a15d8bfd03/kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5b9c3f4ee0b9a439d2415012bd1b1cc2df59e4d6a9939f4d669241d30b414327", size = 2253988, upload-time = "2024-09-04T09:06:18.705Z" },
+ { url = "https://files.pythonhosted.org/packages/35/d3/5f2ecb94b5211c8a04f218a76133cc8d6d153b0f9cd0b45fad79907f0689/kiwisolver-1.4.7-cp39-cp39-win32.whl", hash = "sha256:a79ae34384df2b615eefca647a2873842ac3b596418032bef9a7283675962644", size = 46980, upload-time = "2024-09-04T09:06:20.106Z" },
+ { url = "https://files.pythonhosted.org/packages/ef/17/cd10d020578764ea91740204edc6b3236ed8106228a46f568d716b11feb2/kiwisolver-1.4.7-cp39-cp39-win_amd64.whl", hash = "sha256:cf0438b42121a66a3a667de17e779330fc0f20b0d97d59d2f2121e182b0505e4", size = 55847, upload-time = "2024-09-04T09:06:21.407Z" },
+ { url = "https://files.pythonhosted.org/packages/91/84/32232502020bd78d1d12be7afde15811c64a95ed1f606c10456db4e4c3ac/kiwisolver-1.4.7-cp39-cp39-win_arm64.whl", hash = "sha256:764202cc7e70f767dab49e8df52c7455e8de0df5d858fa801a11aa0d882ccf3f", size = 48494, upload-time = "2024-09-04T09:06:22.648Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/59/741b79775d67ab67ced9bb38552da688c0305c16e7ee24bba7a2be253fb7/kiwisolver-1.4.7-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:94252291e3fe68001b1dd747b4c0b3be12582839b95ad4d1b641924d68fd4643", size = 59491, upload-time = "2024-09-04T09:06:24.188Z" },
+ { url = "https://files.pythonhosted.org/packages/58/cc/fb239294c29a5656e99e3527f7369b174dd9cc7c3ef2dea7cb3c54a8737b/kiwisolver-1.4.7-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5b7dfa3b546da08a9f622bb6becdb14b3e24aaa30adba66749d38f3cc7ea9706", size = 57648, upload-time = "2024-09-04T09:06:25.559Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/ef/2f009ac1f7aab9f81efb2d837301d255279d618d27b6015780115ac64bdd/kiwisolver-1.4.7-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd3de6481f4ed8b734da5df134cd5a6a64fe32124fe83dde1e5b5f29fe30b1e6", size = 84257, upload-time = "2024-09-04T09:06:27.038Z" },
+ { url = "https://files.pythonhosted.org/packages/81/e1/c64f50987f85b68b1c52b464bb5bf73e71570c0f7782d626d1eb283ad620/kiwisolver-1.4.7-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a91b5f9f1205845d488c928e8570dcb62b893372f63b8b6e98b863ebd2368ff2", size = 80906, upload-time = "2024-09-04T09:06:28.48Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/71/1687c5c0a0be2cee39a5c9c389e546f9c6e215e46b691d00d9f646892083/kiwisolver-1.4.7-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40fa14dbd66b8b8f470d5fc79c089a66185619d31645f9b0773b88b19f7223c4", size = 79951, upload-time = "2024-09-04T09:06:29.966Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/8b/d7497df4a1cae9367adf21665dd1f896c2a7aeb8769ad77b662c5e2bcce7/kiwisolver-1.4.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:eb542fe7933aa09d8d8f9d9097ef37532a7df6497819d16efe4359890a2f417a", size = 55715, upload-time = "2024-09-04T09:06:31.489Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/df/ce37d9b26f07ab90880923c94d12a6ff4d27447096b4c849bfc4339ccfdf/kiwisolver-1.4.7-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:8b01aac285f91ca889c800042c35ad3b239e704b150cfd3382adfc9dcc780e39", size = 58666, upload-time = "2024-09-04T09:06:43.756Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/d3/e4b04f43bc629ac8e186b77b2b1a251cdfa5b7610fa189dc0db622672ce6/kiwisolver-1.4.7-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:48be928f59a1f5c8207154f935334d374e79f2b5d212826307d072595ad76a2e", size = 57088, upload-time = "2024-09-04T09:06:45.406Z" },
+ { url = "https://files.pythonhosted.org/packages/30/1c/752df58e2d339e670a535514d2db4fe8c842ce459776b8080fbe08ebb98e/kiwisolver-1.4.7-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f37cfe618a117e50d8c240555331160d73d0411422b59b5ee217843d7b693608", size = 84321, upload-time = "2024-09-04T09:06:47.557Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/f8/fe6484e847bc6e238ec9f9828089fb2c0bb53f2f5f3a79351fde5b565e4f/kiwisolver-1.4.7-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:599b5c873c63a1f6ed7eead644a8a380cfbdf5db91dcb6f85707aaab213b1674", size = 80776, upload-time = "2024-09-04T09:06:49.235Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/57/d7163c0379f250ef763aba85330a19feefb5ce6cb541ade853aaba881524/kiwisolver-1.4.7-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:801fa7802e5cfabe3ab0c81a34c323a319b097dfb5004be950482d882f3d7225", size = 79984, upload-time = "2024-09-04T09:06:51.336Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/95/4a103776c265d13b3d2cd24fb0494d4e04ea435a8ef97e1b2c026d43250b/kiwisolver-1.4.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0c6c43471bc764fad4bc99c5c2d6d16a676b1abf844ca7c8702bdae92df01ee0", size = 55811, upload-time = "2024-09-04T09:06:53.078Z" },
+]
+
+[[package]]
+name = "kiwisolver"
+version = "1.4.9"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version >= '3.11'",
+ "python_full_version == '3.10.*'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/5c/3c/85844f1b0feb11ee581ac23fe5fce65cd049a200c1446708cc1b7f922875/kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d", size = 97564, upload-time = "2025-08-10T21:27:49.279Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c6/5d/8ce64e36d4e3aac5ca96996457dcf33e34e6051492399a3f1fec5657f30b/kiwisolver-1.4.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b4b4d74bda2b8ebf4da5bd42af11d02d04428b2c32846e4c2c93219df8a7987b", size = 124159, upload-time = "2025-08-10T21:25:35.472Z" },
+ { url = "https://files.pythonhosted.org/packages/96/1e/22f63ec454874378175a5f435d6ea1363dd33fb2af832c6643e4ccea0dc8/kiwisolver-1.4.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fb3b8132019ea572f4611d770991000d7f58127560c4889729248eb5852a102f", size = 66578, upload-time = "2025-08-10T21:25:36.73Z" },
+ { url = "https://files.pythonhosted.org/packages/41/4c/1925dcfff47a02d465121967b95151c82d11027d5ec5242771e580e731bd/kiwisolver-1.4.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84fd60810829c27ae375114cd379da1fa65e6918e1da405f356a775d49a62bcf", size = 65312, upload-time = "2025-08-10T21:25:37.658Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/42/0f333164e6307a0687d1eb9ad256215aae2f4bd5d28f4653d6cd319a3ba3/kiwisolver-1.4.9-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b78efa4c6e804ecdf727e580dbb9cba85624d2e1c6b5cb059c66290063bd99a9", size = 1628458, upload-time = "2025-08-10T21:25:39.067Z" },
+ { url = "https://files.pythonhosted.org/packages/86/b6/2dccb977d651943995a90bfe3495c2ab2ba5cd77093d9f2318a20c9a6f59/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4efec7bcf21671db6a3294ff301d2fc861c31faa3c8740d1a94689234d1b415", size = 1225640, upload-time = "2025-08-10T21:25:40.489Z" },
+ { url = "https://files.pythonhosted.org/packages/50/2b/362ebd3eec46c850ccf2bfe3e30f2fc4c008750011f38a850f088c56a1c6/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:90f47e70293fc3688b71271100a1a5453aa9944a81d27ff779c108372cf5567b", size = 1244074, upload-time = "2025-08-10T21:25:42.221Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/bb/f09a1e66dab8984773d13184a10a29fe67125337649d26bdef547024ed6b/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8fdca1def57a2e88ef339de1737a1449d6dbf5fab184c54a1fca01d541317154", size = 1293036, upload-time = "2025-08-10T21:25:43.801Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/01/11ecf892f201cafda0f68fa59212edaea93e96c37884b747c181303fccd1/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9cf554f21be770f5111a1690d42313e140355e687e05cf82cb23d0a721a64a48", size = 2175310, upload-time = "2025-08-10T21:25:45.045Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/5f/bfe11d5b934f500cc004314819ea92427e6e5462706a498c1d4fc052e08f/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fc1795ac5cd0510207482c3d1d3ed781143383b8cfd36f5c645f3897ce066220", size = 2270943, upload-time = "2025-08-10T21:25:46.393Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/de/259f786bf71f1e03e73d87e2db1a9a3bcab64d7b4fd780167123161630ad/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:ccd09f20ccdbbd341b21a67ab50a119b64a403b09288c27481575105283c1586", size = 2440488, upload-time = "2025-08-10T21:25:48.074Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/76/c989c278faf037c4d3421ec07a5c452cd3e09545d6dae7f87c15f54e4edf/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:540c7c72324d864406a009d72f5d6856f49693db95d1fbb46cf86febef873634", size = 2246787, upload-time = "2025-08-10T21:25:49.442Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/55/c2898d84ca440852e560ca9f2a0d28e6e931ac0849b896d77231929900e7/kiwisolver-1.4.9-cp310-cp310-win_amd64.whl", hash = "sha256:ede8c6d533bc6601a47ad4046080d36b8fc99f81e6f1c17b0ac3c2dc91ac7611", size = 73730, upload-time = "2025-08-10T21:25:51.102Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/09/486d6ac523dd33b80b368247f238125d027964cfacb45c654841e88fb2ae/kiwisolver-1.4.9-cp310-cp310-win_arm64.whl", hash = "sha256:7b4da0d01ac866a57dd61ac258c5607b4cd677f63abaec7b148354d2b2cdd536", size = 65036, upload-time = "2025-08-10T21:25:52.063Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/ab/c80b0d5a9d8a1a65f4f815f2afff9798b12c3b9f31f1d304dd233dd920e2/kiwisolver-1.4.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:eb14a5da6dc7642b0f3a18f13654847cd8b7a2550e2645a5bda677862b03ba16", size = 124167, upload-time = "2025-08-10T21:25:53.403Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/c0/27fe1a68a39cf62472a300e2879ffc13c0538546c359b86f149cc19f6ac3/kiwisolver-1.4.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:39a219e1c81ae3b103643d2aedb90f1ef22650deb266ff12a19e7773f3e5f089", size = 66579, upload-time = "2025-08-10T21:25:54.79Z" },
+ { url = "https://files.pythonhosted.org/packages/31/a2/a12a503ac1fd4943c50f9822678e8015a790a13b5490354c68afb8489814/kiwisolver-1.4.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2405a7d98604b87f3fc28b1716783534b1b4b8510d8142adca34ee0bc3c87543", size = 65309, upload-time = "2025-08-10T21:25:55.76Z" },
+ { url = "https://files.pythonhosted.org/packages/66/e1/e533435c0be77c3f64040d68d7a657771194a63c279f55573188161e81ca/kiwisolver-1.4.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:dc1ae486f9abcef254b5618dfb4113dd49f94c68e3e027d03cf0143f3f772b61", size = 1435596, upload-time = "2025-08-10T21:25:56.861Z" },
+ { url = "https://files.pythonhosted.org/packages/67/1e/51b73c7347f9aabdc7215aa79e8b15299097dc2f8e67dee2b095faca9cb0/kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a1f570ce4d62d718dce3f179ee78dac3b545ac16c0c04bb363b7607a949c0d1", size = 1246548, upload-time = "2025-08-10T21:25:58.246Z" },
+ { url = "https://files.pythonhosted.org/packages/21/aa/72a1c5d1e430294f2d32adb9542719cfb441b5da368d09d268c7757af46c/kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb27e7b78d716c591e88e0a09a2139c6577865d7f2e152488c2cc6257f460872", size = 1263618, upload-time = "2025-08-10T21:25:59.857Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/af/db1509a9e79dbf4c260ce0cfa3903ea8945f6240e9e59d1e4deb731b1a40/kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:15163165efc2f627eb9687ea5f3a28137217d217ac4024893d753f46bce9de26", size = 1317437, upload-time = "2025-08-10T21:26:01.105Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/f2/3ea5ee5d52abacdd12013a94130436e19969fa183faa1e7c7fbc89e9a42f/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bdee92c56a71d2b24c33a7d4c2856bd6419d017e08caa7802d2963870e315028", size = 2195742, upload-time = "2025-08-10T21:26:02.675Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/9b/1efdd3013c2d9a2566aa6a337e9923a00590c516add9a1e89a768a3eb2fc/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:412f287c55a6f54b0650bd9b6dce5aceddb95864a1a90c87af16979d37c89771", size = 2290810, upload-time = "2025-08-10T21:26:04.009Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/e5/cfdc36109ae4e67361f9bc5b41323648cb24a01b9ade18784657e022e65f/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2c93f00dcba2eea70af2be5f11a830a742fe6b579a1d4e00f47760ef13be247a", size = 2461579, upload-time = "2025-08-10T21:26:05.317Z" },
+ { url = "https://files.pythonhosted.org/packages/62/86/b589e5e86c7610842213994cdea5add00960076bef4ae290c5fa68589cac/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f117e1a089d9411663a3207ba874f31be9ac8eaa5b533787024dc07aeb74f464", size = 2268071, upload-time = "2025-08-10T21:26:06.686Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/c6/f8df8509fd1eee6c622febe54384a96cfaf4d43bf2ccec7a0cc17e4715c9/kiwisolver-1.4.9-cp311-cp311-win_amd64.whl", hash = "sha256:be6a04e6c79819c9a8c2373317d19a96048e5a3f90bec587787e86a1153883c2", size = 73840, upload-time = "2025-08-10T21:26:07.94Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/2d/16e0581daafd147bc11ac53f032a2b45eabac897f42a338d0a13c1e5c436/kiwisolver-1.4.9-cp311-cp311-win_arm64.whl", hash = "sha256:0ae37737256ba2de764ddc12aed4956460277f00c4996d51a197e72f62f5eec7", size = 65159, upload-time = "2025-08-10T21:26:09.048Z" },
+ { url = "https://files.pythonhosted.org/packages/86/c9/13573a747838aeb1c76e3267620daa054f4152444d1f3d1a2324b78255b5/kiwisolver-1.4.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ac5a486ac389dddcc5bef4f365b6ae3ffff2c433324fb38dd35e3fab7c957999", size = 123686, upload-time = "2025-08-10T21:26:10.034Z" },
+ { url = "https://files.pythonhosted.org/packages/51/ea/2ecf727927f103ffd1739271ca19c424d0e65ea473fbaeea1c014aea93f6/kiwisolver-1.4.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f2ba92255faa7309d06fe44c3a4a97efe1c8d640c2a79a5ef728b685762a6fd2", size = 66460, upload-time = "2025-08-10T21:26:11.083Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/5a/51f5464373ce2aeb5194508298a508b6f21d3867f499556263c64c621914/kiwisolver-1.4.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a2899935e724dd1074cb568ce7ac0dce28b2cd6ab539c8e001a8578eb106d14", size = 64952, upload-time = "2025-08-10T21:26:12.058Z" },
+ { url = "https://files.pythonhosted.org/packages/70/90/6d240beb0f24b74371762873e9b7f499f1e02166a2d9c5801f4dbf8fa12e/kiwisolver-1.4.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f6008a4919fdbc0b0097089f67a1eb55d950ed7e90ce2cc3e640abadd2757a04", size = 1474756, upload-time = "2025-08-10T21:26:13.096Z" },
+ { url = "https://files.pythonhosted.org/packages/12/42/f36816eaf465220f683fb711efdd1bbf7a7005a2473d0e4ed421389bd26c/kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:67bb8b474b4181770f926f7b7d2f8c0248cbcb78b660fdd41a47054b28d2a752", size = 1276404, upload-time = "2025-08-10T21:26:14.457Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/64/bc2de94800adc830c476dce44e9b40fd0809cddeef1fde9fcf0f73da301f/kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2327a4a30d3ee07d2fbe2e7933e8a37c591663b96ce42a00bc67461a87d7df77", size = 1294410, upload-time = "2025-08-10T21:26:15.73Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/42/2dc82330a70aa8e55b6d395b11018045e58d0bb00834502bf11509f79091/kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7a08b491ec91b1d5053ac177afe5290adacf1f0f6307d771ccac5de30592d198", size = 1343631, upload-time = "2025-08-10T21:26:17.045Z" },
+ { url = "https://files.pythonhosted.org/packages/22/fd/f4c67a6ed1aab149ec5a8a401c323cee7a1cbe364381bb6c9c0d564e0e20/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d8fc5c867c22b828001b6a38d2eaeb88160bf5783c6cb4a5e440efc981ce286d", size = 2224963, upload-time = "2025-08-10T21:26:18.737Z" },
+ { url = "https://files.pythonhosted.org/packages/45/aa/76720bd4cb3713314677d9ec94dcc21ced3f1baf4830adde5bb9b2430a5f/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3b3115b2581ea35bb6d1f24a4c90af37e5d9b49dcff267eeed14c3893c5b86ab", size = 2321295, upload-time = "2025-08-10T21:26:20.11Z" },
+ { url = "https://files.pythonhosted.org/packages/80/19/d3ec0d9ab711242f56ae0dc2fc5d70e298bb4a1f9dfab44c027668c673a1/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:858e4c22fb075920b96a291928cb7dea5644e94c0ee4fcd5af7e865655e4ccf2", size = 2487987, upload-time = "2025-08-10T21:26:21.49Z" },
+ { url = "https://files.pythonhosted.org/packages/39/e9/61e4813b2c97e86b6fdbd4dd824bf72d28bcd8d4849b8084a357bc0dd64d/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ed0fecd28cc62c54b262e3736f8bb2512d8dcfdc2bcf08be5f47f96bf405b145", size = 2291817, upload-time = "2025-08-10T21:26:22.812Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/41/85d82b0291db7504da3c2defe35c9a8a5c9803a730f297bd823d11d5fb77/kiwisolver-1.4.9-cp312-cp312-win_amd64.whl", hash = "sha256:f68208a520c3d86ea51acf688a3e3002615a7f0238002cccc17affecc86a8a54", size = 73895, upload-time = "2025-08-10T21:26:24.37Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/92/5f3068cf15ee5cb624a0c7596e67e2a0bb2adee33f71c379054a491d07da/kiwisolver-1.4.9-cp312-cp312-win_arm64.whl", hash = "sha256:2c1a4f57df73965f3f14df20b80ee29e6a7930a57d2d9e8491a25f676e197c60", size = 64992, upload-time = "2025-08-10T21:26:25.732Z" },
+ { url = "https://files.pythonhosted.org/packages/31/c1/c2686cda909742ab66c7388e9a1a8521a59eb89f8bcfbee28fc980d07e24/kiwisolver-1.4.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5d0432ccf1c7ab14f9949eec60c5d1f924f17c037e9f8b33352fa05799359b8", size = 123681, upload-time = "2025-08-10T21:26:26.725Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/f0/f44f50c9f5b1a1860261092e3bc91ecdc9acda848a8b8c6abfda4a24dd5c/kiwisolver-1.4.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efb3a45b35622bb6c16dbfab491a8f5a391fe0e9d45ef32f4df85658232ca0e2", size = 66464, upload-time = "2025-08-10T21:26:27.733Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/7a/9d90a151f558e29c3936b8a47ac770235f436f2120aca41a6d5f3d62ae8d/kiwisolver-1.4.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1a12cf6398e8a0a001a059747a1cbf24705e18fe413bc22de7b3d15c67cffe3f", size = 64961, upload-time = "2025-08-10T21:26:28.729Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/e9/f218a2cb3a9ffbe324ca29a9e399fa2d2866d7f348ec3a88df87fc248fc5/kiwisolver-1.4.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b67e6efbf68e077dd71d1a6b37e43e1a99d0bff1a3d51867d45ee8908b931098", size = 1474607, upload-time = "2025-08-10T21:26:29.798Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/28/aac26d4c882f14de59041636292bc838db8961373825df23b8eeb807e198/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5656aa670507437af0207645273ccdfee4f14bacd7f7c67a4306d0dcaeaf6eed", size = 1276546, upload-time = "2025-08-10T21:26:31.401Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/ad/8bfc1c93d4cc565e5069162f610ba2f48ff39b7de4b5b8d93f69f30c4bed/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bfc08add558155345129c7803b3671cf195e6a56e7a12f3dde7c57d9b417f525", size = 1294482, upload-time = "2025-08-10T21:26:32.721Z" },
+ { url = "https://files.pythonhosted.org/packages/da/f1/6aca55ff798901d8ce403206d00e033191f63d82dd708a186e0ed2067e9c/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:40092754720b174e6ccf9e845d0d8c7d8e12c3d71e7fc35f55f3813e96376f78", size = 1343720, upload-time = "2025-08-10T21:26:34.032Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/91/eed031876c595c81d90d0f6fc681ece250e14bf6998c3d7c419466b523b7/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:497d05f29a1300d14e02e6441cf0f5ee81c1ff5a304b0d9fb77423974684e08b", size = 2224907, upload-time = "2025-08-10T21:26:35.824Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/ec/4d1925f2e49617b9cca9c34bfa11adefad49d00db038e692a559454dfb2e/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdd1a81a1860476eb41ac4bc1e07b3f07259e6d55bbf739b79c8aaedcf512799", size = 2321334, upload-time = "2025-08-10T21:26:37.534Z" },
+ { url = "https://files.pythonhosted.org/packages/43/cb/450cd4499356f68802750c6ddc18647b8ea01ffa28f50d20598e0befe6e9/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e6b93f13371d341afee3be9f7c5964e3fe61d5fa30f6a30eb49856935dfe4fc3", size = 2488313, upload-time = "2025-08-10T21:26:39.191Z" },
+ { url = "https://files.pythonhosted.org/packages/71/67/fc76242bd99f885651128a5d4fa6083e5524694b7c88b489b1b55fdc491d/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d75aa530ccfaa593da12834b86a0724f58bff12706659baa9227c2ccaa06264c", size = 2291970, upload-time = "2025-08-10T21:26:40.828Z" },
+ { url = "https://files.pythonhosted.org/packages/75/bd/f1a5d894000941739f2ae1b65a32892349423ad49c2e6d0771d0bad3fae4/kiwisolver-1.4.9-cp313-cp313-win_amd64.whl", hash = "sha256:dd0a578400839256df88c16abddf9ba14813ec5f21362e1fe65022e00c883d4d", size = 73894, upload-time = "2025-08-10T21:26:42.33Z" },
+ { url = "https://files.pythonhosted.org/packages/95/38/dce480814d25b99a391abbddadc78f7c117c6da34be68ca8b02d5848b424/kiwisolver-1.4.9-cp313-cp313-win_arm64.whl", hash = "sha256:d4188e73af84ca82468f09cadc5ac4db578109e52acb4518d8154698d3a87ca2", size = 64995, upload-time = "2025-08-10T21:26:43.889Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/37/7d218ce5d92dadc5ebdd9070d903e0c7cf7edfe03f179433ac4d13ce659c/kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:5a0f2724dfd4e3b3ac5a82436a8e6fd16baa7d507117e4279b660fe8ca38a3a1", size = 126510, upload-time = "2025-08-10T21:26:44.915Z" },
+ { url = "https://files.pythonhosted.org/packages/23/b0/e85a2b48233daef4b648fb657ebbb6f8367696a2d9548a00b4ee0eb67803/kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1b11d6a633e4ed84fc0ddafd4ebfd8ea49b3f25082c04ad12b8315c11d504dc1", size = 67903, upload-time = "2025-08-10T21:26:45.934Z" },
+ { url = "https://files.pythonhosted.org/packages/44/98/f2425bc0113ad7de24da6bb4dae1343476e95e1d738be7c04d31a5d037fd/kiwisolver-1.4.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61874cdb0a36016354853593cffc38e56fc9ca5aa97d2c05d3dcf6922cd55a11", size = 66402, upload-time = "2025-08-10T21:26:47.101Z" },
+ { url = "https://files.pythonhosted.org/packages/98/d8/594657886df9f34c4177cc353cc28ca7e6e5eb562d37ccc233bff43bbe2a/kiwisolver-1.4.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:60c439763a969a6af93b4881db0eed8fadf93ee98e18cbc35bc8da868d0c4f0c", size = 1582135, upload-time = "2025-08-10T21:26:48.665Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/c6/38a115b7170f8b306fc929e166340c24958347308ea3012c2b44e7e295db/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92a2f997387a1b79a75e7803aa7ded2cfbe2823852ccf1ba3bcf613b62ae3197", size = 1389409, upload-time = "2025-08-10T21:26:50.335Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/3b/e04883dace81f24a568bcee6eb3001da4ba05114afa622ec9b6fafdc1f5e/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a31d512c812daea6d8b3be3b2bfcbeb091dbb09177706569bcfc6240dcf8b41c", size = 1401763, upload-time = "2025-08-10T21:26:51.867Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/80/20ace48e33408947af49d7d15c341eaee69e4e0304aab4b7660e234d6288/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:52a15b0f35dad39862d376df10c5230155243a2c1a436e39eb55623ccbd68185", size = 1453643, upload-time = "2025-08-10T21:26:53.592Z" },
+ { url = "https://files.pythonhosted.org/packages/64/31/6ce4380a4cd1f515bdda976a1e90e547ccd47b67a1546d63884463c92ca9/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a30fd6fdef1430fd9e1ba7b3398b5ee4e2887783917a687d86ba69985fb08748", size = 2330818, upload-time = "2025-08-10T21:26:55.051Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/e9/3f3fcba3bcc7432c795b82646306e822f3fd74df0ee81f0fa067a1f95668/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cc9617b46837c6468197b5945e196ee9ca43057bb7d9d1ae688101e4e1dddf64", size = 2419963, upload-time = "2025-08-10T21:26:56.421Z" },
+ { url = "https://files.pythonhosted.org/packages/99/43/7320c50e4133575c66e9f7dadead35ab22d7c012a3b09bb35647792b2a6d/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:0ab74e19f6a2b027ea4f845a78827969af45ce790e6cb3e1ebab71bdf9f215ff", size = 2594639, upload-time = "2025-08-10T21:26:57.882Z" },
+ { url = "https://files.pythonhosted.org/packages/65/d6/17ae4a270d4a987ef8a385b906d2bdfc9fce502d6dc0d3aea865b47f548c/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dba5ee5d3981160c28d5490f0d1b7ed730c22470ff7f6cc26cfcfaacb9896a07", size = 2391741, upload-time = "2025-08-10T21:26:59.237Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/8f/8f6f491d595a9e5912971f3f863d81baddccc8a4d0c3749d6a0dd9ffc9df/kiwisolver-1.4.9-cp313-cp313t-win_arm64.whl", hash = "sha256:0749fd8f4218ad2e851e11cc4dc05c7cbc0cbc4267bdfdb31782e65aace4ee9c", size = 68646, upload-time = "2025-08-10T21:27:00.52Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/32/6cc0fbc9c54d06c2969faa9c1d29f5751a2e51809dd55c69055e62d9b426/kiwisolver-1.4.9-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:9928fe1eb816d11ae170885a74d074f57af3a0d65777ca47e9aeb854a1fba386", size = 123806, upload-time = "2025-08-10T21:27:01.537Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/dd/2bfb1d4a4823d92e8cbb420fe024b8d2167f72079b3bb941207c42570bdf/kiwisolver-1.4.9-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d0005b053977e7b43388ddec89fa567f43d4f6d5c2c0affe57de5ebf290dc552", size = 66605, upload-time = "2025-08-10T21:27:03.335Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/69/00aafdb4e4509c2ca6064646cba9cd4b37933898f426756adb2cb92ebbed/kiwisolver-1.4.9-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2635d352d67458b66fd0667c14cb1d4145e9560d503219034a18a87e971ce4f3", size = 64925, upload-time = "2025-08-10T21:27:04.339Z" },
+ { url = "https://files.pythonhosted.org/packages/43/dc/51acc6791aa14e5cb6d8a2e28cefb0dc2886d8862795449d021334c0df20/kiwisolver-1.4.9-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:767c23ad1c58c9e827b649a9ab7809fd5fd9db266a9cf02b0e926ddc2c680d58", size = 1472414, upload-time = "2025-08-10T21:27:05.437Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/bb/93fa64a81db304ac8a246f834d5094fae4b13baf53c839d6bb6e81177129/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72d0eb9fba308b8311685c2268cf7d0a0639a6cd027d8128659f72bdd8a024b4", size = 1281272, upload-time = "2025-08-10T21:27:07.063Z" },
+ { url = "https://files.pythonhosted.org/packages/70/e6/6df102916960fb8d05069d4bd92d6d9a8202d5a3e2444494e7cd50f65b7a/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f68e4f3eeca8fb22cc3d731f9715a13b652795ef657a13df1ad0c7dc0e9731df", size = 1298578, upload-time = "2025-08-10T21:27:08.452Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/47/e142aaa612f5343736b087864dbaebc53ea8831453fb47e7521fa8658f30/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d84cd4061ae292d8ac367b2c3fa3aad11cb8625a95d135fe93f286f914f3f5a6", size = 1345607, upload-time = "2025-08-10T21:27:10.125Z" },
+ { url = "https://files.pythonhosted.org/packages/54/89/d641a746194a0f4d1a3670fb900d0dbaa786fb98341056814bc3f058fa52/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a60ea74330b91bd22a29638940d115df9dc00af5035a9a2a6ad9399ffb4ceca5", size = 2230150, upload-time = "2025-08-10T21:27:11.484Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/6b/5ee1207198febdf16ac11f78c5ae40861b809cbe0e6d2a8d5b0b3044b199/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ce6a3a4e106cf35c2d9c4fa17c05ce0b180db622736845d4315519397a77beaf", size = 2325979, upload-time = "2025-08-10T21:27:12.917Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/ff/b269eefd90f4ae14dcc74973d5a0f6d28d3b9bb1afd8c0340513afe6b39a/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:77937e5e2a38a7b48eef0585114fe7930346993a88060d0bf886086d2aa49ef5", size = 2491456, upload-time = "2025-08-10T21:27:14.353Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/d4/10303190bd4d30de547534601e259a4fbf014eed94aae3e5521129215086/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:24c175051354f4a28c5d6a31c93906dc653e2bf234e8a4bbfb964892078898ce", size = 2294621, upload-time = "2025-08-10T21:27:15.808Z" },
+ { url = "https://files.pythonhosted.org/packages/28/e0/a9a90416fce5c0be25742729c2ea52105d62eda6c4be4d803c2a7be1fa50/kiwisolver-1.4.9-cp314-cp314-win_amd64.whl", hash = "sha256:0763515d4df10edf6d06a3c19734e2566368980d21ebec439f33f9eb936c07b7", size = 75417, upload-time = "2025-08-10T21:27:17.436Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/10/6949958215b7a9a264299a7db195564e87900f709db9245e4ebdd3c70779/kiwisolver-1.4.9-cp314-cp314-win_arm64.whl", hash = "sha256:0e4e2bf29574a6a7b7f6cb5fa69293b9f96c928949ac4a53ba3f525dffb87f9c", size = 66582, upload-time = "2025-08-10T21:27:18.436Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/79/60e53067903d3bc5469b369fe0dfc6b3482e2133e85dae9daa9527535991/kiwisolver-1.4.9-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d976bbb382b202f71c67f77b0ac11244021cfa3f7dfd9e562eefcea2df711548", size = 126514, upload-time = "2025-08-10T21:27:19.465Z" },
+ { url = "https://files.pythonhosted.org/packages/25/d1/4843d3e8d46b072c12a38c97c57fab4608d36e13fe47d47ee96b4d61ba6f/kiwisolver-1.4.9-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2489e4e5d7ef9a1c300a5e0196e43d9c739f066ef23270607d45aba368b91f2d", size = 67905, upload-time = "2025-08-10T21:27:20.51Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/ae/29ffcbd239aea8b93108de1278271ae764dfc0d803a5693914975f200596/kiwisolver-1.4.9-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e2ea9f7ab7fbf18fffb1b5434ce7c69a07582f7acc7717720f1d69f3e806f90c", size = 66399, upload-time = "2025-08-10T21:27:21.496Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/ae/d7ba902aa604152c2ceba5d352d7b62106bedbccc8e95c3934d94472bfa3/kiwisolver-1.4.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b34e51affded8faee0dfdb705416153819d8ea9250bbbf7ea1b249bdeb5f1122", size = 1582197, upload-time = "2025-08-10T21:27:22.604Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/41/27c70d427eddb8bc7e4f16420a20fefc6f480312122a59a959fdfe0445ad/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8aacd3d4b33b772542b2e01beb50187536967b514b00003bdda7589722d2a64", size = 1390125, upload-time = "2025-08-10T21:27:24.036Z" },
+ { url = "https://files.pythonhosted.org/packages/41/42/b3799a12bafc76d962ad69083f8b43b12bf4fe78b097b12e105d75c9b8f1/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7cf974dd4e35fa315563ac99d6287a1024e4dc2077b8a7d7cd3d2fb65d283134", size = 1402612, upload-time = "2025-08-10T21:27:25.773Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/b5/a210ea073ea1cfaca1bb5c55a62307d8252f531beb364e18aa1e0888b5a0/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:85bd218b5ecfbee8c8a82e121802dcb519a86044c9c3b2e4aef02fa05c6da370", size = 1453990, upload-time = "2025-08-10T21:27:27.089Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/ce/a829eb8c033e977d7ea03ed32fb3c1781b4fa0433fbadfff29e39c676f32/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0856e241c2d3df4efef7c04a1e46b1936b6120c9bcf36dd216e3acd84bc4fb21", size = 2331601, upload-time = "2025-08-10T21:27:29.343Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/4b/b5e97eb142eb9cd0072dacfcdcd31b1c66dc7352b0f7c7255d339c0edf00/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9af39d6551f97d31a4deebeac6f45b156f9755ddc59c07b402c148f5dbb6482a", size = 2422041, upload-time = "2025-08-10T21:27:30.754Z" },
+ { url = "https://files.pythonhosted.org/packages/40/be/8eb4cd53e1b85ba4edc3a9321666f12b83113a178845593307a3e7891f44/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:bb4ae2b57fc1d8cbd1cf7b1d9913803681ffa903e7488012be5b76dedf49297f", size = 2594897, upload-time = "2025-08-10T21:27:32.803Z" },
+ { url = "https://files.pythonhosted.org/packages/99/dd/841e9a66c4715477ea0abc78da039832fbb09dac5c35c58dc4c41a407b8a/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:aedff62918805fb62d43a4aa2ecd4482c380dc76cd31bd7c8878588a61bd0369", size = 2391835, upload-time = "2025-08-10T21:27:34.23Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/28/4b2e5c47a0da96896fdfdb006340ade064afa1e63675d01ea5ac222b6d52/kiwisolver-1.4.9-cp314-cp314t-win_amd64.whl", hash = "sha256:1fa333e8b2ce4d9660f2cda9c0e1b6bafcfb2457a9d259faa82289e73ec24891", size = 79988, upload-time = "2025-08-10T21:27:35.587Z" },
+ { url = "https://files.pythonhosted.org/packages/80/be/3578e8afd18c88cdf9cb4cffde75a96d2be38c5a903f1ed0ceec061bd09e/kiwisolver-1.4.9-cp314-cp314t-win_arm64.whl", hash = "sha256:4a48a2ce79d65d363597ef7b567ce3d14d68783d2b2263d98db3d9477805ba32", size = 70260, upload-time = "2025-08-10T21:27:36.606Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/63/fde392691690f55b38d5dd7b3710f5353bf7a8e52de93a22968801ab8978/kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4d1d9e582ad4d63062d34077a9a1e9f3c34088a2ec5135b1f7190c07cf366527", size = 60183, upload-time = "2025-08-10T21:27:37.669Z" },
+ { url = "https://files.pythonhosted.org/packages/27/b1/6aad34edfdb7cced27f371866f211332bba215bfd918ad3322a58f480d8b/kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:deed0c7258ceb4c44ad5ec7d9918f9f14fd05b2be86378d86cf50e63d1e7b771", size = 58675, upload-time = "2025-08-10T21:27:39.031Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/1a/23d855a702bb35a76faed5ae2ba3de57d323f48b1f6b17ee2176c4849463/kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0a590506f303f512dff6b7f75fd2fd18e16943efee932008fe7140e5fa91d80e", size = 80277, upload-time = "2025-08-10T21:27:40.129Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/5b/5239e3c2b8fb5afa1e8508f721bb77325f740ab6994d963e61b2b7abcc1e/kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e09c2279a4d01f099f52d5c4b3d9e208e91edcbd1a175c9662a8b16e000fece9", size = 77994, upload-time = "2025-08-10T21:27:41.181Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/1c/5d4d468fb16f8410e596ed0eac02d2c68752aa7dc92997fe9d60a7147665/kiwisolver-1.4.9-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c9e7cdf45d594ee04d5be1b24dd9d49f3d1590959b2271fb30b5ca2b262c00fb", size = 73744, upload-time = "2025-08-10T21:27:42.254Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/0f/36d89194b5a32c054ce93e586d4049b6c2c22887b0eb229c61c68afd3078/kiwisolver-1.4.9-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:720e05574713db64c356e86732c0f3c5252818d05f9df320f0ad8380641acea5", size = 60104, upload-time = "2025-08-10T21:27:43.287Z" },
+ { url = "https://files.pythonhosted.org/packages/52/ba/4ed75f59e4658fd21fe7dde1fee0ac397c678ec3befba3fe6482d987af87/kiwisolver-1.4.9-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:17680d737d5335b552994a2008fab4c851bcd7de33094a82067ef3a576ff02fa", size = 58592, upload-time = "2025-08-10T21:27:44.314Z" },
+ { url = "https://files.pythonhosted.org/packages/33/01/a8ea7c5ea32a9b45ceeaee051a04c8ed4320f5add3c51bfa20879b765b70/kiwisolver-1.4.9-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:85b5352f94e490c028926ea567fc569c52ec79ce131dadb968d3853e809518c2", size = 80281, upload-time = "2025-08-10T21:27:45.369Z" },
+ { url = "https://files.pythonhosted.org/packages/da/e3/dbd2ecdce306f1d07a1aaf324817ee993aab7aee9db47ceac757deabafbe/kiwisolver-1.4.9-pp311-pypy311_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:464415881e4801295659462c49461a24fb107c140de781d55518c4b80cb6790f", size = 78009, upload-time = "2025-08-10T21:27:46.376Z" },
+ { url = "https://files.pythonhosted.org/packages/da/e9/0d4add7873a73e462aeb45c036a2dead2562b825aa46ba326727b3f31016/kiwisolver-1.4.9-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:fb940820c63a9590d31d88b815e7a3aa5915cad3ce735ab45f0c730b39547de1", size = 73929, upload-time = "2025-08-10T21:27:48.236Z" },
+]
+
+[[package]]
+name = "librt"
+version = "0.8.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/56/9c/b4b0c54d84da4a94b37bd44151e46d5e583c9534c7e02250b961b1b6d8a8/librt-0.8.1.tar.gz", hash = "sha256:be46a14693955b3bd96014ccbdb8339ee8c9346fbe11c1b78901b55125f14c73", size = 177471, upload-time = "2026-02-17T16:13:06.101Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7c/5f/63f5fa395c7a8a93558c0904ba8f1c8d1b997ca6a3de61bc7659970d66bf/librt-0.8.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:81fd938344fecb9373ba1b155968c8a329491d2ce38e7ddb76f30ffb938f12dc", size = 65697, upload-time = "2026-02-17T16:11:06.903Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/e0/0472cf37267b5920eff2f292ccfaede1886288ce35b7f3203d8de00abfe6/librt-0.8.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5db05697c82b3a2ec53f6e72b2ed373132b0c2e05135f0696784e97d7f5d48e7", size = 68376, upload-time = "2026-02-17T16:11:08.395Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/be/8bd1359fdcd27ab897cd5963294fa4a7c83b20a8564678e4fd12157e56a5/librt-0.8.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d56bc4011975f7460bea7b33e1ff425d2f1adf419935ff6707273c77f8a4ada6", size = 197084, upload-time = "2026-02-17T16:11:09.774Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/fe/163e33fdd091d0c2b102f8a60cc0a61fd730ad44e32617cd161e7cd67a01/librt-0.8.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5cdc0f588ff4b663ea96c26d2a230c525c6fc62b28314edaaaca8ed5af931ad0", size = 207337, upload-time = "2026-02-17T16:11:11.311Z" },
+ { url = "https://files.pythonhosted.org/packages/01/99/f85130582f05dcf0c8902f3d629270231d2f4afdfc567f8305a952ac7f14/librt-0.8.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:97c2b54ff6717a7a563b72627990bec60d8029df17df423f0ed37d56a17a176b", size = 219980, upload-time = "2026-02-17T16:11:12.499Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/54/cb5e4d03659e043a26c74e08206412ac9a3742f0477d96f9761a55313b5f/librt-0.8.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8f1125e6bbf2f1657d9a2f3ccc4a2c9b0c8b176965bb565dd4d86be67eddb4b6", size = 212921, upload-time = "2026-02-17T16:11:14.484Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/81/a3a01e4240579c30f3487f6fed01eb4bc8ef0616da5b4ebac27ca19775f3/librt-0.8.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8f4bb453f408137d7581be309b2fbc6868a80e7ef60c88e689078ee3a296ae71", size = 221381, upload-time = "2026-02-17T16:11:17.459Z" },
+ { url = "https://files.pythonhosted.org/packages/08/b0/fc2d54b4b1c6fb81e77288ff31ff25a2c1e62eaef4424a984f228839717b/librt-0.8.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c336d61d2fe74a3195edc1646d53ff1cddd3a9600b09fa6ab75e5514ba4862a7", size = 216714, upload-time = "2026-02-17T16:11:19.197Z" },
+ { url = "https://files.pythonhosted.org/packages/96/96/85daa73ffbd87e1fb287d7af6553ada66bf25a2a6b0de4764344a05469f6/librt-0.8.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:eb5656019db7c4deacf0c1a55a898c5bb8f989be904597fcb5232a2f4828fa05", size = 214777, upload-time = "2026-02-17T16:11:20.443Z" },
+ { url = "https://files.pythonhosted.org/packages/12/9c/c3aa7a2360383f4bf4f04d98195f2739a579128720c603f4807f006a4225/librt-0.8.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c25d9e338d5bed46c1632f851babf3d13c78f49a225462017cf5e11e845c5891", size = 237398, upload-time = "2026-02-17T16:11:22.083Z" },
+ { url = "https://files.pythonhosted.org/packages/61/19/d350ea89e5274665185dabc4bbb9c3536c3411f862881d316c8b8e00eb66/librt-0.8.1-cp310-cp310-win32.whl", hash = "sha256:aaab0e307e344cb28d800957ef3ec16605146ef0e59e059a60a176d19543d1b7", size = 54285, upload-time = "2026-02-17T16:11:23.27Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/d6/45d587d3d41c112e9543a0093d883eb57a24a03e41561c127818aa2a6bcc/librt-0.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:56e04c14b696300d47b3bc5f1d10a00e86ae978886d0cee14e5714fafb5df5d2", size = 61352, upload-time = "2026-02-17T16:11:24.207Z" },
+ { url = "https://files.pythonhosted.org/packages/1d/01/0e748af5e4fee180cf7cd12bd12b0513ad23b045dccb2a83191bde82d168/librt-0.8.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:681dc2451d6d846794a828c16c22dc452d924e9f700a485b7ecb887a30aad1fd", size = 65315, upload-time = "2026-02-17T16:11:25.152Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/4d/7184806efda571887c798d573ca4134c80ac8642dcdd32f12c31b939c595/librt-0.8.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3b4350b13cc0e6f5bec8fa7caf29a8fb8cdc051a3bae45cfbfd7ce64f009965", size = 68021, upload-time = "2026-02-17T16:11:26.129Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/88/c3c52d2a5d5101f28d3dc89298444626e7874aa904eed498464c2af17627/librt-0.8.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ac1e7817fd0ed3d14fd7c5df91daed84c48e4c2a11ee99c0547f9f62fdae13da", size = 194500, upload-time = "2026-02-17T16:11:27.177Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/5d/6fb0a25b6a8906e85b2c3b87bee1d6ed31510be7605b06772f9374ca5cb3/librt-0.8.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:747328be0c5b7075cde86a0e09d7a9196029800ba75a1689332348e998fb85c0", size = 205622, upload-time = "2026-02-17T16:11:28.242Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/a6/8006ae81227105476a45691f5831499e4d936b1c049b0c1feb17c11b02d1/librt-0.8.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f0af2bd2bc204fa27f3d6711d0f360e6b8c684a035206257a81673ab924aa11e", size = 218304, upload-time = "2026-02-17T16:11:29.344Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/19/60e07886ad16670aae57ef44dada41912c90906a6fe9f2b9abac21374748/librt-0.8.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d480de377f5b687b6b1bc0c0407426da556e2a757633cc7e4d2e1a057aa688f3", size = 211493, upload-time = "2026-02-17T16:11:30.445Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/cf/f666c89d0e861d05600438213feeb818c7514d3315bae3648b1fc145d2b6/librt-0.8.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d0ee06b5b5291f609ddb37b9750985b27bc567791bc87c76a569b3feed8481ac", size = 219129, upload-time = "2026-02-17T16:11:32.021Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/ef/f1bea01e40b4a879364c031476c82a0dc69ce068daad67ab96302fed2d45/librt-0.8.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9e2c6f77b9ad48ce5603b83b7da9ee3e36b3ab425353f695cba13200c5d96596", size = 213113, upload-time = "2026-02-17T16:11:33.192Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/80/cdab544370cc6bc1b72ea369525f547a59e6938ef6863a11ab3cd24759af/librt-0.8.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:439352ba9373f11cb8e1933da194dcc6206daf779ff8df0ed69c5e39113e6a99", size = 212269, upload-time = "2026-02-17T16:11:34.373Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/9c/48d6ed8dac595654f15eceab2035131c136d1ae9a1e3548e777bb6dbb95d/librt-0.8.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:82210adabbc331dbb65d7868b105185464ef13f56f7f76688565ad79f648b0fe", size = 234673, upload-time = "2026-02-17T16:11:36.063Z" },
+ { url = "https://files.pythonhosted.org/packages/16/01/35b68b1db517f27a01be4467593292eb5315def8900afad29fabf56304ba/librt-0.8.1-cp311-cp311-win32.whl", hash = "sha256:52c224e14614b750c0a6d97368e16804a98c684657c7518752c356834fff83bb", size = 54597, upload-time = "2026-02-17T16:11:37.544Z" },
+ { url = "https://files.pythonhosted.org/packages/71/02/796fe8f02822235966693f257bf2c79f40e11337337a657a8cfebba5febc/librt-0.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:c00e5c884f528c9932d278d5c9cbbea38a6b81eb62c02e06ae53751a83a4d52b", size = 61733, upload-time = "2026-02-17T16:11:38.691Z" },
+ { url = "https://files.pythonhosted.org/packages/28/ad/232e13d61f879a42a4e7117d65e4984bb28371a34bb6fb9ca54ec2c8f54e/librt-0.8.1-cp311-cp311-win_arm64.whl", hash = "sha256:f7cdf7f26c2286ffb02e46d7bac56c94655540b26347673bea15fa52a6af17e9", size = 52273, upload-time = "2026-02-17T16:11:40.308Z" },
+ { url = "https://files.pythonhosted.org/packages/95/21/d39b0a87ac52fc98f621fb6f8060efb017a767ebbbac2f99fbcbc9ddc0d7/librt-0.8.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a28f2612ab566b17f3698b0da021ff9960610301607c9a5e8eaca62f5e1c350a", size = 66516, upload-time = "2026-02-17T16:11:41.604Z" },
+ { url = "https://files.pythonhosted.org/packages/69/f1/46375e71441c43e8ae335905e069f1c54febee63a146278bcee8782c84fd/librt-0.8.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:60a78b694c9aee2a0f1aaeaa7d101cf713e92e8423a941d2897f4fa37908dab9", size = 68634, upload-time = "2026-02-17T16:11:43.268Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/33/c510de7f93bf1fa19e13423a606d8189a02624a800710f6e6a0a0f0784b3/librt-0.8.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:758509ea3f1eba2a57558e7e98f4659d0ea7670bff49673b0dde18a3c7e6c0eb", size = 198941, upload-time = "2026-02-17T16:11:44.28Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/36/e725903416409a533d92398e88ce665476f275081d0d7d42f9c4951999e5/librt-0.8.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:039b9f2c506bd0ab0f8725aa5ba339c6f0cd19d3b514b50d134789809c24285d", size = 209991, upload-time = "2026-02-17T16:11:45.462Z" },
+ { url = "https://files.pythonhosted.org/packages/30/7a/8d908a152e1875c9f8eac96c97a480df425e657cdb47854b9efaa4998889/librt-0.8.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bb54f1205a3a6ab41a6fd71dfcdcbd278670d3a90ca502a30d9da583105b6f7", size = 224476, upload-time = "2026-02-17T16:11:46.542Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/b8/a22c34f2c485b8903a06f3fe3315341fe6876ef3599792344669db98fcff/librt-0.8.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:05bd41cdee35b0c59c259f870f6da532a2c5ca57db95b5f23689fcb5c9e42440", size = 217518, upload-time = "2026-02-17T16:11:47.746Z" },
+ { url = "https://files.pythonhosted.org/packages/79/6f/5c6fea00357e4f82ba44f81dbfb027921f1ab10e320d4a64e1c408d035d9/librt-0.8.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:adfab487facf03f0d0857b8710cf82d0704a309d8ffc33b03d9302b4c64e91a9", size = 225116, upload-time = "2026-02-17T16:11:49.298Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/a0/95ced4e7b1267fe1e2720a111685bcddf0e781f7e9e0ce59d751c44dcfe5/librt-0.8.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:153188fe98a72f206042be10a2c6026139852805215ed9539186312d50a8e972", size = 217751, upload-time = "2026-02-17T16:11:50.49Z" },
+ { url = "https://files.pythonhosted.org/packages/93/c2/0517281cb4d4101c27ab59472924e67f55e375bc46bedae94ac6dc6e1902/librt-0.8.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:dd3c41254ee98604b08bd5b3af5bf0a89740d4ee0711de95b65166bf44091921", size = 218378, upload-time = "2026-02-17T16:11:51.783Z" },
+ { url = "https://files.pythonhosted.org/packages/43/e8/37b3ac108e8976888e559a7b227d0ceac03c384cfd3e7a1c2ee248dbae79/librt-0.8.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e0d138c7ae532908cbb342162b2611dbd4d90c941cd25ab82084aaf71d2c0bd0", size = 241199, upload-time = "2026-02-17T16:11:53.561Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/5b/35812d041c53967fedf551a39399271bbe4257e681236a2cf1a69c8e7fa1/librt-0.8.1-cp312-cp312-win32.whl", hash = "sha256:43353b943613c5d9c49a25aaffdba46f888ec354e71e3529a00cca3f04d66a7a", size = 54917, upload-time = "2026-02-17T16:11:54.758Z" },
+ { url = "https://files.pythonhosted.org/packages/de/d1/fa5d5331b862b9775aaf2a100f5ef86854e5d4407f71bddf102f4421e034/librt-0.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:ff8baf1f8d3f4b6b7257fcb75a501f2a5499d0dda57645baa09d4d0d34b19444", size = 62017, upload-time = "2026-02-17T16:11:55.748Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/7c/c614252f9acda59b01a66e2ddfd243ed1c7e1deab0293332dfbccf862808/librt-0.8.1-cp312-cp312-win_arm64.whl", hash = "sha256:0f2ae3725904f7377e11cc37722d5d401e8b3d5851fb9273d7f4fe04f6b3d37d", size = 52441, upload-time = "2026-02-17T16:11:56.801Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/3c/f614c8e4eaac7cbf2bbdf9528790b21d89e277ee20d57dc6e559c626105f/librt-0.8.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7e6bad1cd94f6764e1e21950542f818a09316645337fd5ab9a7acc45d99a8f35", size = 66529, upload-time = "2026-02-17T16:11:57.809Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/96/5836544a45100ae411eda07d29e3d99448e5258b6e9c8059deb92945f5c2/librt-0.8.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cf450f498c30af55551ba4f66b9123b7185362ec8b625a773b3d39aa1a717583", size = 68669, upload-time = "2026-02-17T16:11:58.843Z" },
+ { url = "https://files.pythonhosted.org/packages/06/53/f0b992b57af6d5531bf4677d75c44f095f2366a1741fb695ee462ae04b05/librt-0.8.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:eca45e982fa074090057132e30585a7e8674e9e885d402eae85633e9f449ce6c", size = 199279, upload-time = "2026-02-17T16:11:59.862Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/ad/4848cc16e268d14280d8168aee4f31cea92bbd2b79ce33d3e166f2b4e4fc/librt-0.8.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c3811485fccfda840861905b8c70bba5ec094e02825598bb9d4ca3936857a04", size = 210288, upload-time = "2026-02-17T16:12:00.954Z" },
+ { url = "https://files.pythonhosted.org/packages/52/05/27fdc2e95de26273d83b96742d8d3b7345f2ea2bdbd2405cc504644f2096/librt-0.8.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e4af413908f77294605e28cfd98063f54b2c790561383971d2f52d113d9c363", size = 224809, upload-time = "2026-02-17T16:12:02.108Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/d0/78200a45ba3240cb042bc597d6f2accba9193a2c57d0356268cbbe2d0925/librt-0.8.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5212a5bd7fae98dae95710032902edcd2ec4dc994e883294f75c857b83f9aba0", size = 218075, upload-time = "2026-02-17T16:12:03.631Z" },
+ { url = "https://files.pythonhosted.org/packages/af/72/a210839fa74c90474897124c064ffca07f8d4b347b6574d309686aae7ca6/librt-0.8.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e692aa2d1d604e6ca12d35e51fdc36f4cda6345e28e36374579f7ef3611b3012", size = 225486, upload-time = "2026-02-17T16:12:04.725Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/c1/a03cc63722339ddbf087485f253493e2b013039f5b707e8e6016141130fa/librt-0.8.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4be2a5c926b9770c9e08e717f05737a269b9d0ebc5d2f0060f0fe3fe9ce47acb", size = 218219, upload-time = "2026-02-17T16:12:05.828Z" },
+ { url = "https://files.pythonhosted.org/packages/58/f5/fff6108af0acf941c6f274a946aea0e484bd10cd2dc37610287ce49388c5/librt-0.8.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fd1a720332ea335ceb544cf0a03f81df92abd4bb887679fd1e460976b0e6214b", size = 218750, upload-time = "2026-02-17T16:12:07.09Z" },
+ { url = "https://files.pythonhosted.org/packages/71/67/5a387bfef30ec1e4b4f30562c8586566faf87e47d696768c19feb49e3646/librt-0.8.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2af9e01e0ef80d95ae3c720be101227edae5f2fe7e3dc63d8857fadfc5a1d", size = 241624, upload-time = "2026-02-17T16:12:08.43Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/be/24f8502db11d405232ac1162eb98069ca49c3306c1d75c6ccc61d9af8789/librt-0.8.1-cp313-cp313-win32.whl", hash = "sha256:086a32dbb71336627e78cc1d6ee305a68d038ef7d4c39aaff41ae8c9aa46e91a", size = 54969, upload-time = "2026-02-17T16:12:09.633Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/73/c9fdf6cb2a529c1a092ce769a12d88c8cca991194dfe641b6af12fa964d2/librt-0.8.1-cp313-cp313-win_amd64.whl", hash = "sha256:e11769a1dbda4da7b00a76cfffa67aa47cfa66921d2724539eee4b9ede780b79", size = 62000, upload-time = "2026-02-17T16:12:10.632Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/97/68f80ca3ac4924f250cdfa6e20142a803e5e50fca96ef5148c52ee8c10ea/librt-0.8.1-cp313-cp313-win_arm64.whl", hash = "sha256:924817ab3141aca17893386ee13261f1d100d1ef410d70afe4389f2359fea4f0", size = 52495, upload-time = "2026-02-17T16:12:11.633Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/6a/907ef6800f7bca71b525a05f1839b21f708c09043b1c6aa77b6b827b3996/librt-0.8.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6cfa7fe54fd4d1f47130017351a959fe5804bda7a0bc7e07a2cdbc3fdd28d34f", size = 66081, upload-time = "2026-02-17T16:12:12.766Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/18/25e991cd5640c9fb0f8d91b18797b29066b792f17bf8493da183bf5caabe/librt-0.8.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:228c2409c079f8c11fb2e5d7b277077f694cb93443eb760e00b3b83cb8b3176c", size = 68309, upload-time = "2026-02-17T16:12:13.756Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/36/46820d03f058cfb5a9de5940640ba03165ed8aded69e0733c417bb04df34/librt-0.8.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7aae78ab5e3206181780e56912d1b9bb9f90a7249ce12f0e8bf531d0462dd0fc", size = 196804, upload-time = "2026-02-17T16:12:14.818Z" },
+ { url = "https://files.pythonhosted.org/packages/59/18/5dd0d3b87b8ff9c061849fbdb347758d1f724b9a82241aa908e0ec54ccd0/librt-0.8.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:172d57ec04346b047ca6af181e1ea4858086c80bdf455f61994c4aa6fc3f866c", size = 206907, upload-time = "2026-02-17T16:12:16.513Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/96/ef04902aad1424fd7299b62d1890e803e6ab4018c3044dca5922319c4b97/librt-0.8.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6b1977c4ea97ce5eb7755a78fae68d87e4102e4aaf54985e8b56806849cc06a3", size = 221217, upload-time = "2026-02-17T16:12:17.906Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/ff/7e01f2dda84a8f5d280637a2e5827210a8acca9a567a54507ef1c75b342d/librt-0.8.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:10c42e1f6fd06733ef65ae7bebce2872bcafd8d6e6b0a08fe0a05a23b044fb14", size = 214622, upload-time = "2026-02-17T16:12:19.108Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/8c/5b093d08a13946034fed57619742f790faf77058558b14ca36a6e331161e/librt-0.8.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4c8dfa264b9193c4ee19113c985c95f876fae5e51f731494fc4e0cf594990ba7", size = 221987, upload-time = "2026-02-17T16:12:20.331Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/cc/86b0b3b151d40920ad45a94ce0171dec1aebba8a9d72bb3fa00c73ab25dd/librt-0.8.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:01170b6729a438f0dedc4a26ed342e3dc4f02d1000b4b19f980e1877f0c297e6", size = 215132, upload-time = "2026-02-17T16:12:21.54Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/be/8588164a46edf1e69858d952654e216a9a91174688eeefb9efbb38a9c799/librt-0.8.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:7b02679a0d783bdae30d443025b94465d8c3dc512f32f5b5031f93f57ac32071", size = 215195, upload-time = "2026-02-17T16:12:23.073Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/f2/0b9279bea735c734d69344ecfe056c1ba211694a72df10f568745c899c76/librt-0.8.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:190b109bb69592a3401fe1ffdea41a2e73370ace2ffdc4a0e8e2b39cdea81b78", size = 237946, upload-time = "2026-02-17T16:12:24.275Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/cc/5f2a34fbc8aeb35314a3641f9956fa9051a947424652fad9882be7a97949/librt-0.8.1-cp314-cp314-win32.whl", hash = "sha256:e70a57ecf89a0f64c24e37f38d3fe217a58169d2fe6ed6d70554964042474023", size = 50689, upload-time = "2026-02-17T16:12:25.766Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/76/cd4d010ab2147339ca2b93e959c3686e964edc6de66ddacc935c325883d7/librt-0.8.1-cp314-cp314-win_amd64.whl", hash = "sha256:7e2f3edca35664499fbb36e4770650c4bd4a08abc1f4458eab9df4ec56389730", size = 57875, upload-time = "2026-02-17T16:12:27.465Z" },
+ { url = "https://files.pythonhosted.org/packages/84/0f/2143cb3c3ca48bd3379dcd11817163ca50781927c4537345d608b5045998/librt-0.8.1-cp314-cp314-win_arm64.whl", hash = "sha256:0d2f82168e55ddefd27c01c654ce52379c0750ddc31ee86b4b266bcf4d65f2a3", size = 48058, upload-time = "2026-02-17T16:12:28.556Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/0e/9b23a87e37baf00311c3efe6b48d6b6c168c29902dfc3f04c338372fd7db/librt-0.8.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2c74a2da57a094bd48d03fa5d196da83d2815678385d2978657499063709abe1", size = 68313, upload-time = "2026-02-17T16:12:29.659Z" },
+ { url = "https://files.pythonhosted.org/packages/db/9a/859c41e5a4f1c84200a7d2b92f586aa27133c8243b6cac9926f6e54d01b9/librt-0.8.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a355d99c4c0d8e5b770313b8b247411ed40949ca44e33e46a4789b9293a907ee", size = 70994, upload-time = "2026-02-17T16:12:31.516Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/28/10605366ee599ed34223ac2bf66404c6fb59399f47108215d16d5ad751a8/librt-0.8.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2eb345e8b33fb748227409c9f1233d4df354d6e54091f0e8fc53acdb2ffedeb7", size = 220770, upload-time = "2026-02-17T16:12:33.294Z" },
+ { url = "https://files.pythonhosted.org/packages/af/8d/16ed8fd452dafae9c48d17a6bc1ee3e818fd40ef718d149a8eff2c9f4ea2/librt-0.8.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9be2f15e53ce4e83cc08adc29b26fb5978db62ef2a366fbdf716c8a6c8901040", size = 235409, upload-time = "2026-02-17T16:12:35.443Z" },
+ { url = "https://files.pythonhosted.org/packages/89/1b/7bdf3e49349c134b25db816e4a3db6b94a47ac69d7d46b1e682c2c4949be/librt-0.8.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:785ae29c1f5c6e7c2cde2c7c0e148147f4503da3abc5d44d482068da5322fd9e", size = 246473, upload-time = "2026-02-17T16:12:36.656Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/8a/91fab8e4fd2a24930a17188c7af5380eb27b203d72101c9cc000dbdfd95a/librt-0.8.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1d3a7da44baf692f0c6aeb5b2a09c5e6fc7a703bca9ffa337ddd2e2da53f7732", size = 238866, upload-time = "2026-02-17T16:12:37.849Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/e0/c45a098843fc7c07e18a7f8a24ca8496aecbf7bdcd54980c6ca1aaa79a8e/librt-0.8.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5fc48998000cbc39ec0d5311312dda93ecf92b39aaf184c5e817d5d440b29624", size = 250248, upload-time = "2026-02-17T16:12:39.445Z" },
+ { url = "https://files.pythonhosted.org/packages/82/30/07627de23036640c952cce0c1fe78972e77d7d2f8fd54fa5ef4554ff4a56/librt-0.8.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:e96baa6820280077a78244b2e06e416480ed859bbd8e5d641cf5742919d8beb4", size = 240629, upload-time = "2026-02-17T16:12:40.889Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/c1/55bfe1ee3542eba055616f9098eaf6eddb966efb0ca0f44eaa4aba327307/librt-0.8.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:31362dbfe297b23590530007062c32c6f6176f6099646bb2c95ab1b00a57c382", size = 239615, upload-time = "2026-02-17T16:12:42.446Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/39/191d3d28abc26c9099b19852e6c99f7f6d400b82fa5a4e80291bd3803e19/librt-0.8.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cc3656283d11540ab0ea01978378e73e10002145117055e03722417aeab30994", size = 263001, upload-time = "2026-02-17T16:12:43.627Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/eb/7697f60fbe7042ab4e88f4ee6af496b7f222fffb0a4e3593ef1f29f81652/librt-0.8.1-cp314-cp314t-win32.whl", hash = "sha256:738f08021b3142c2918c03692608baed43bc51144c29e35807682f8070ee2a3a", size = 51328, upload-time = "2026-02-17T16:12:45.148Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/72/34bf2eb7a15414a23e5e70ecb9440c1d3179f393d9349338a91e2781c0fb/librt-0.8.1-cp314-cp314t-win_amd64.whl", hash = "sha256:89815a22daf9c51884fb5dbe4f1ef65ee6a146e0b6a8df05f753e2e4a9359bf4", size = 58722, upload-time = "2026-02-17T16:12:46.85Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/c8/d148e041732d631fc76036f8b30fae4e77b027a1e95b7a84bb522481a940/librt-0.8.1-cp314-cp314t-win_arm64.whl", hash = "sha256:bf512a71a23504ed08103a13c941f763db13fb11177beb3d9244c98c29fb4a61", size = 48755, upload-time = "2026-02-17T16:12:47.943Z" },
+ { url = "https://files.pythonhosted.org/packages/01/1f/c7d8b66a3ca3ca3ed8ded4b32c96ee58a45920ebbbaa934355c74adcc33e/librt-0.8.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3dff3d3ca8db20e783b1bc7de49c0a2ab0b8387f31236d6a026597d07fcd68ac", size = 65990, upload-time = "2026-02-17T16:12:48.972Z" },
+ { url = "https://files.pythonhosted.org/packages/56/be/ee9ba1730052313d08457f19beaa1b878619978863fba09b40aed5b5c123/librt-0.8.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:08eec3a1fc435f0d09c87b6bf1ec798986a3544f446b864e4099633a56fcd9ed", size = 68640, upload-time = "2026-02-17T16:12:50.24Z" },
+ { url = "https://files.pythonhosted.org/packages/81/27/b7309298b96f7690cec3ceee38004c1a7f60fcd96d952d3ac344a1e3e8b3/librt-0.8.1-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e3f0a41487fd5fad7e760b9e8a90e251e27c2816fbc2cff36a22a0e6bcbbd9dd", size = 196099, upload-time = "2026-02-17T16:12:52.788Z" },
+ { url = "https://files.pythonhosted.org/packages/10/48/160a5aacdcb21824b10a52378c39e88c46a29bb31efdaf3910dd1f9b670e/librt-0.8.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bacdb58d9939d95cc557b4dbaa86527c9db2ac1ed76a18bc8d26f6dc8647d851", size = 206663, upload-time = "2026-02-17T16:12:55.017Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/65/33dd1d8caabb7c6805d87d095b143417dc96b0277c06ffa0508361422c82/librt-0.8.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b6d7ab1f01aa753188605b09a51faa44a3327400b00b8cce424c71910fc0a128", size = 219318, upload-time = "2026-02-17T16:12:56.145Z" },
+ { url = "https://files.pythonhosted.org/packages/09/d4/353805aa6181c7950a2462bd6e855366eeca21a501f375228d72a51547df/librt-0.8.1-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4998009e7cb9e896569f4be7004f09d0ed70d386fa99d42b6d363f6d200501ac", size = 212191, upload-time = "2026-02-17T16:12:57.326Z" },
+ { url = "https://files.pythonhosted.org/packages/06/08/725b3f304d61eba56c713c251fb833a06d84bf93381caad5152366f5d2bb/librt-0.8.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2cc68eeeef5e906839c7bb0815748b5b0a974ec27125beefc0f942715785b551", size = 220672, upload-time = "2026-02-17T16:12:58.497Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/55/e8cdf04145872b3b97cb9b68287b22d1c08348227063f305aec11a3e6ce7/librt-0.8.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0bf69d79a23f4f40b8673a947a234baeeb133b5078b483b7297c5916539cf5d5", size = 216172, upload-time = "2026-02-17T16:12:59.751Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/d8/23b1c6592d2422dd6829c672f45b1f1c257f219926b0d216fedb572d0184/librt-0.8.1-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:22b46eabd76c1986ee7d231b0765ad387d7673bbd996aa0d0d054b38ac65d8f6", size = 214116, upload-time = "2026-02-17T16:13:01.056Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/92/2b44fd3cc3313f44e43bdbb41343735b568fa675fa351642b408ee48d418/librt-0.8.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:237796479f4d0637d6b9cbcb926ff424a97735e68ade6facf402df4ec93375ed", size = 236664, upload-time = "2026-02-17T16:13:02.314Z" },
+ { url = "https://files.pythonhosted.org/packages/00/23/92313ecdab80e142d8ea10e8dfa6297694359dbaacc9e81679bdc8cbceb6/librt-0.8.1-cp39-cp39-win32.whl", hash = "sha256:4beb04b8c66c6ae62f8c1e0b2f097c1ebad9295c929a8d5286c05eae7c2fc7dc", size = 54368, upload-time = "2026-02-17T16:13:03.549Z" },
+ { url = "https://files.pythonhosted.org/packages/68/36/18f6e768afad6b55a690d38427c53251b69b7ba8795512730fd2508b31a9/librt-0.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:64548cde61b692dc0dc379f4b5f59a2f582c2ebe7890d09c1ae3b9e66fa015b7", size = 61507, upload-time = "2026-02-17T16:13:04.556Z" },
+]
+
+[[package]]
+name = "livekit"
+source = { editable = "livekit-rtc" }
+dependencies = [
+ { name = "aiofiles" },
+ { name = "numpy", version = "2.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" },
+ { name = "numpy", version = "2.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
+ { name = "protobuf", version = "6.33.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "protobuf", version = "7.34.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "types-protobuf", version = "6.32.1.20251210", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "types-protobuf", version = "6.32.1.20260221", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+]
+
+[package.metadata]
+requires-dist = [
+ { name = "aiofiles", specifier = ">=24" },
+ { name = "numpy", specifier = ">=1.26" },
+ { name = "protobuf", specifier = ">=4.25.0" },
+ { name = "types-protobuf", specifier = ">=3" },
+]
+
+[[package]]
+name = "livekit-api"
+source = { editable = "livekit-api" }
+dependencies = [
+ { name = "aiohttp" },
+ { name = "livekit-protocol" },
+ { name = "protobuf", version = "6.33.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "protobuf", version = "7.34.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "pyjwt" },
+ { name = "types-protobuf", version = "6.32.1.20251210", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "types-protobuf", version = "6.32.1.20260221", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+]
+
+[package.metadata]
+requires-dist = [
+ { name = "aiohttp", specifier = ">=3.9.0" },
+ { name = "livekit-protocol", editable = "livekit-protocol" },
+ { name = "protobuf", specifier = ">=4" },
+ { name = "pyjwt", specifier = ">=2.0.0" },
+ { name = "types-protobuf", specifier = ">=4" },
+]
+
+[[package]]
+name = "livekit-protocol"
+source = { editable = "livekit-protocol" }
+dependencies = [
+ { name = "protobuf", version = "6.33.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "protobuf", version = "7.34.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "types-protobuf", version = "6.32.1.20251210", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "types-protobuf", version = "6.32.1.20260221", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+]
+
+[package.metadata]
+requires-dist = [
+ { name = "protobuf", specifier = ">=4" },
+ { name = "types-protobuf", specifier = ">=4" },
+]
+
+[[package]]
+name = "markdown-it-py"
+version = "3.0.0"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version < '3.10'",
+]
+dependencies = [
+ { name = "mdurl", marker = "python_full_version < '3.10'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" },
+]
+
+[[package]]
+name = "markdown-it-py"
+version = "4.0.0"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version >= '3.11'",
+ "python_full_version == '3.10.*'",
+]
+dependencies = [
+ { name = "mdurl", marker = "python_full_version >= '3.10'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" },
+]
+
+[[package]]
+name = "matplotlib"
+version = "3.9.4"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version < '3.10'",
+]
+dependencies = [
+ { name = "contourpy", version = "1.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "cycler", marker = "python_full_version < '3.10'" },
+ { name = "fonttools", version = "4.60.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "importlib-resources", marker = "python_full_version < '3.10'" },
+ { name = "kiwisolver", version = "1.4.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "numpy", version = "2.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "packaging", marker = "python_full_version < '3.10'" },
+ { name = "pillow", version = "11.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "pyparsing", marker = "python_full_version < '3.10'" },
+ { name = "python-dateutil", marker = "python_full_version < '3.10'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/df/17/1747b4154034befd0ed33b52538f5eb7752d05bb51c5e2a31470c3bc7d52/matplotlib-3.9.4.tar.gz", hash = "sha256:1e00e8be7393cbdc6fedfa8a6fba02cf3e83814b285db1c60b906a023ba41bc3", size = 36106529, upload-time = "2024-12-13T05:56:34.184Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7e/94/27d2e2c30d54b56c7b764acc1874a909e34d1965a427fc7092bb6a588b63/matplotlib-3.9.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:c5fdd7abfb706dfa8d307af64a87f1a862879ec3cd8d0ec8637458f0885b9c50", size = 7885089, upload-time = "2024-12-13T05:54:24.224Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/25/828273307e40a68eb8e9df832b6b2aaad075864fdc1de4b1b81e40b09e48/matplotlib-3.9.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d89bc4e85e40a71d1477780366c27fb7c6494d293e1617788986f74e2a03d7ff", size = 7770600, upload-time = "2024-12-13T05:54:27.214Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/65/f841a422ec994da5123368d76b126acf4fc02ea7459b6e37c4891b555b83/matplotlib-3.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ddf9f3c26aae695c5daafbf6b94e4c1a30d6cd617ba594bbbded3b33a1fcfa26", size = 8200138, upload-time = "2024-12-13T05:54:29.497Z" },
+ { url = "https://files.pythonhosted.org/packages/07/06/272aca07a38804d93b6050813de41ca7ab0e29ba7a9dd098e12037c919a9/matplotlib-3.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18ebcf248030173b59a868fda1fe42397253f6698995b55e81e1f57431d85e50", size = 8312711, upload-time = "2024-12-13T05:54:34.396Z" },
+ { url = "https://files.pythonhosted.org/packages/98/37/f13e23b233c526b7e27ad61be0a771894a079e0f7494a10d8d81557e0e9a/matplotlib-3.9.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:974896ec43c672ec23f3f8c648981e8bc880ee163146e0312a9b8def2fac66f5", size = 9090622, upload-time = "2024-12-13T05:54:36.808Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/8c/b1f5bd2bd70e60f93b1b54c4d5ba7a992312021d0ddddf572f9a1a6d9348/matplotlib-3.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:4598c394ae9711cec135639374e70871fa36b56afae17bdf032a345be552a88d", size = 7828211, upload-time = "2024-12-13T05:54:40.596Z" },
+ { url = "https://files.pythonhosted.org/packages/74/4b/65be7959a8fa118a3929b49a842de5b78bb55475236fcf64f3e308ff74a0/matplotlib-3.9.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d4dd29641d9fb8bc4492420c5480398dd40a09afd73aebe4eb9d0071a05fbe0c", size = 7894430, upload-time = "2024-12-13T05:54:44.049Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/18/80f70d91896e0a517b4a051c3fd540daa131630fd75e02e250365353b253/matplotlib-3.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30e5b22e8bcfb95442bf7d48b0d7f3bdf4a450cbf68986ea45fca3d11ae9d099", size = 7780045, upload-time = "2024-12-13T05:54:46.414Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/73/ccb381026e3238c5c25c3609ba4157b2d1a617ec98d65a8b4ee4e1e74d02/matplotlib-3.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bb0030d1d447fd56dcc23b4c64a26e44e898f0416276cac1ebc25522e0ac249", size = 8209906, upload-time = "2024-12-13T05:54:49.459Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/33/1648da77b74741c89f5ea95cbf42a291b4b364f2660b316318811404ed97/matplotlib-3.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aca90ed222ac3565d2752b83dbb27627480d27662671e4d39da72e97f657a423", size = 8322873, upload-time = "2024-12-13T05:54:53.066Z" },
+ { url = "https://files.pythonhosted.org/packages/57/d3/8447ba78bc6593c9044c372d1609f8ea10fb1e071e7a9e0747bea74fc16c/matplotlib-3.9.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a181b2aa2906c608fcae72f977a4a2d76e385578939891b91c2550c39ecf361e", size = 9099566, upload-time = "2024-12-13T05:54:55.522Z" },
+ { url = "https://files.pythonhosted.org/packages/23/e1/4f0e237bf349c02ff9d1b6e7109f1a17f745263809b9714a8576dc17752b/matplotlib-3.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:1f6882828231eca17f501c4dcd98a05abb3f03d157fbc0769c6911fe08b6cfd3", size = 7838065, upload-time = "2024-12-13T05:54:58.337Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/2b/c918bf6c19d6445d1cefe3d2e42cb740fb997e14ab19d4daeb6a7ab8a157/matplotlib-3.9.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:dfc48d67e6661378a21c2983200a654b72b5c5cdbd5d2cf6e5e1ece860f0cc70", size = 7891131, upload-time = "2024-12-13T05:55:02.837Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/e5/b4e8fc601ca302afeeabf45f30e706a445c7979a180e3a978b78b2b681a4/matplotlib-3.9.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:47aef0fab8332d02d68e786eba8113ffd6f862182ea2999379dec9e237b7e483", size = 7776365, upload-time = "2024-12-13T05:55:05.158Z" },
+ { url = "https://files.pythonhosted.org/packages/99/06/b991886c506506476e5d83625c5970c656a491b9f80161458fed94597808/matplotlib-3.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fba1f52c6b7dc764097f52fd9ab627b90db452c9feb653a59945de16752e965f", size = 8200707, upload-time = "2024-12-13T05:55:09.48Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/e2/556b627498cb27e61026f2d1ba86a78ad1b836fef0996bef5440e8bc9559/matplotlib-3.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:173ac3748acaac21afcc3fa1633924609ba1b87749006bc25051c52c422a5d00", size = 8313761, upload-time = "2024-12-13T05:55:12.95Z" },
+ { url = "https://files.pythonhosted.org/packages/58/ff/165af33ec766ff818306ea88e91f9f60d2a6ed543be1eb122a98acbf3b0d/matplotlib-3.9.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:320edea0cadc07007765e33f878b13b3738ffa9745c5f707705692df70ffe0e0", size = 9095284, upload-time = "2024-12-13T05:55:16.199Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/8b/3d0c7a002db3b1ed702731c2a9a06d78d035f1f2fb0fb936a8e43cc1e9f4/matplotlib-3.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:a4a4cfc82330b27042a7169533da7991e8789d180dd5b3daeaee57d75cd5a03b", size = 7841160, upload-time = "2024-12-13T05:55:19.991Z" },
+ { url = "https://files.pythonhosted.org/packages/49/b1/999f89a7556d101b23a2f0b54f1b6e140d73f56804da1398f2f0bc0924bc/matplotlib-3.9.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:37eeffeeca3c940985b80f5b9a7b95ea35671e0e7405001f249848d2b62351b6", size = 7891499, upload-time = "2024-12-13T05:55:22.142Z" },
+ { url = "https://files.pythonhosted.org/packages/87/7b/06a32b13a684977653396a1bfcd34d4e7539c5d55c8cbfaa8ae04d47e4a9/matplotlib-3.9.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3e7465ac859ee4abcb0d836137cd8414e7bb7ad330d905abced457217d4f0f45", size = 7776802, upload-time = "2024-12-13T05:55:25.947Z" },
+ { url = "https://files.pythonhosted.org/packages/65/87/ac498451aff739e515891bbb92e566f3c7ef31891aaa878402a71f9b0910/matplotlib-3.9.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4c12302c34afa0cf061bea23b331e747e5e554b0fa595c96e01c7b75bc3b858", size = 8200802, upload-time = "2024-12-13T05:55:28.461Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/6b/9eb761c00e1cb838f6c92e5f25dcda3f56a87a52f6cb8fdfa561e6cf6a13/matplotlib-3.9.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b8c97917f21b75e72108b97707ba3d48f171541a74aa2a56df7a40626bafc64", size = 8313880, upload-time = "2024-12-13T05:55:30.965Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/a2/c8eaa600e2085eec7e38cbbcc58a30fc78f8224939d31d3152bdafc01fd1/matplotlib-3.9.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0229803bd7e19271b03cb09f27db76c918c467aa4ce2ae168171bc67c3f508df", size = 9094637, upload-time = "2024-12-13T05:55:33.701Z" },
+ { url = "https://files.pythonhosted.org/packages/71/1f/c6e1daea55b7bfeb3d84c6cb1abc449f6a02b181e7e2a5e4db34c3afb793/matplotlib-3.9.4-cp313-cp313-win_amd64.whl", hash = "sha256:7c0d8ef442ebf56ff5e206f8083d08252ee738e04f3dc88ea882853a05488799", size = 7841311, upload-time = "2024-12-13T05:55:36.737Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/3a/2757d3f7d388b14dd48f5a83bea65b6d69f000e86b8f28f74d86e0d375bd/matplotlib-3.9.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a04c3b00066a688834356d196136349cb32f5e1003c55ac419e91585168b88fb", size = 7919989, upload-time = "2024-12-13T05:55:39.024Z" },
+ { url = "https://files.pythonhosted.org/packages/24/28/f5077c79a4f521589a37fe1062d6a6ea3534e068213f7357e7cfffc2e17a/matplotlib-3.9.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:04c519587f6c210626741a1e9a68eefc05966ede24205db8982841826af5871a", size = 7809417, upload-time = "2024-12-13T05:55:42.412Z" },
+ { url = "https://files.pythonhosted.org/packages/36/c8/c523fd2963156692916a8eb7d4069084cf729359f7955cf09075deddfeaf/matplotlib-3.9.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:308afbf1a228b8b525fcd5cec17f246bbbb63b175a3ef6eb7b4d33287ca0cf0c", size = 8226258, upload-time = "2024-12-13T05:55:47.259Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/88/499bf4b8fa9349b6f5c0cf4cead0ebe5da9d67769129f1b5651e5ac51fbc/matplotlib-3.9.4-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddb3b02246ddcffd3ce98e88fed5b238bc5faff10dbbaa42090ea13241d15764", size = 8335849, upload-time = "2024-12-13T05:55:49.763Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/9f/20a4156b9726188646a030774ee337d5ff695a965be45ce4dbcb9312c170/matplotlib-3.9.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8a75287e9cb9eee48cb79ec1d806f75b29c0fde978cb7223a1f4c5848d696041", size = 9102152, upload-time = "2024-12-13T05:55:51.997Z" },
+ { url = "https://files.pythonhosted.org/packages/10/11/237f9c3a4e8d810b1759b67ff2da7c32c04f9c80aa475e7beb36ed43a8fb/matplotlib-3.9.4-cp313-cp313t-win_amd64.whl", hash = "sha256:488deb7af140f0ba86da003e66e10d55ff915e152c78b4b66d231638400b1965", size = 7896987, upload-time = "2024-12-13T05:55:55.941Z" },
+ { url = "https://files.pythonhosted.org/packages/56/eb/501b465c9fef28f158e414ea3a417913dc2ac748564c7ed41535f23445b4/matplotlib-3.9.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:3c3724d89a387ddf78ff88d2a30ca78ac2b4c89cf37f2db4bd453c34799e933c", size = 7885919, upload-time = "2024-12-13T05:55:59.66Z" },
+ { url = "https://files.pythonhosted.org/packages/da/36/236fbd868b6c91309a5206bd90c3f881f4f44b2d997cd1d6239ef652f878/matplotlib-3.9.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d5f0a8430ffe23d7e32cfd86445864ccad141797f7d25b7c41759a5b5d17cfd7", size = 7771486, upload-time = "2024-12-13T05:56:04.264Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/4b/105caf2d54d5ed11d9f4335398f5103001a03515f2126c936a752ccf1461/matplotlib-3.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bb0141a21aef3b64b633dc4d16cbd5fc538b727e4958be82a0e1c92a234160e", size = 8201838, upload-time = "2024-12-13T05:56:06.792Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/a7/bb01188fb4013d34d274caf44a2f8091255b0497438e8b6c0a7c1710c692/matplotlib-3.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57aa235109e9eed52e2c2949db17da185383fa71083c00c6c143a60e07e0888c", size = 8314492, upload-time = "2024-12-13T05:56:09.964Z" },
+ { url = "https://files.pythonhosted.org/packages/33/19/02e1a37f7141fc605b193e927d0a9cdf9dc124a20b9e68793f4ffea19695/matplotlib-3.9.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b18c600061477ccfdd1e6fd050c33d8be82431700f3452b297a56d9ed7037abb", size = 9092500, upload-time = "2024-12-13T05:56:13.55Z" },
+ { url = "https://files.pythonhosted.org/packages/57/68/c2feb4667adbf882ffa4b3e0ac9967f848980d9f8b5bebd86644aa67ce6a/matplotlib-3.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:ef5f2d1b67d2d2145ff75e10f8c008bfbf71d45137c4b648c87193e7dd053eac", size = 7822962, upload-time = "2024-12-13T05:56:16.358Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/22/2ef6a364cd3f565442b0b055e0599744f1e4314ec7326cdaaa48a4d864d7/matplotlib-3.9.4-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:44e0ed786d769d85bc787b0606a53f2d8d2d1d3c8a2608237365e9121c1a338c", size = 7877995, upload-time = "2024-12-13T05:56:18.805Z" },
+ { url = "https://files.pythonhosted.org/packages/87/b8/2737456e566e9f4d94ae76b8aa0d953d9acb847714f9a7ad80184474f5be/matplotlib-3.9.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:09debb9ce941eb23ecdbe7eab972b1c3e0276dcf01688073faff7b0f61d6c6ca", size = 7769300, upload-time = "2024-12-13T05:56:21.315Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/1f/e709c6ec7b5321e6568769baa288c7178e60a93a9da9e682b39450da0e29/matplotlib-3.9.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bcc53cf157a657bfd03afab14774d54ba73aa84d42cfe2480c91bd94873952db", size = 8313423, upload-time = "2024-12-13T05:56:26.719Z" },
+ { url = "https://files.pythonhosted.org/packages/5e/b6/5a1f868782cd13f053a679984e222007ecff654a9bfbac6b27a65f4eeb05/matplotlib-3.9.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ad45da51be7ad02387801fd154ef74d942f49fe3fcd26a64c94842ba7ec0d865", size = 7854624, upload-time = "2024-12-13T05:56:29.359Z" },
+]
+
+[[package]]
+name = "matplotlib"
+version = "3.10.8"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version >= '3.11'",
+ "python_full_version == '3.10.*'",
+]
+dependencies = [
+ { name = "contourpy", version = "1.3.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" },
+ { name = "contourpy", version = "1.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
+ { name = "cycler", marker = "python_full_version >= '3.10'" },
+ { name = "fonttools", version = "4.61.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "kiwisolver", version = "1.4.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" },
+ { name = "numpy", version = "2.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
+ { name = "packaging", marker = "python_full_version >= '3.10'" },
+ { name = "pillow", version = "12.1.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "pyparsing", marker = "python_full_version >= '3.10'" },
+ { name = "python-dateutil", marker = "python_full_version >= '3.10'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/8a/76/d3c6e3a13fe484ebe7718d14e269c9569c4eb0020a968a327acb3b9a8fe6/matplotlib-3.10.8.tar.gz", hash = "sha256:2299372c19d56bcd35cf05a2738308758d32b9eaed2371898d8f5bd33f084aa3", size = 34806269, upload-time = "2025-12-10T22:56:51.155Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/58/be/a30bd917018ad220c400169fba298f2bb7003c8ccbc0c3e24ae2aacad1e8/matplotlib-3.10.8-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:00270d217d6b20d14b584c521f810d60c5c78406dc289859776550df837dcda7", size = 8239828, upload-time = "2025-12-10T22:55:02.313Z" },
+ { url = "https://files.pythonhosted.org/packages/58/27/ca01e043c4841078e82cf6e80a6993dfecd315c3d79f5f3153afbb8e1ec6/matplotlib-3.10.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37b3c1cc42aa184b3f738cfa18c1c1d72fd496d85467a6cf7b807936d39aa656", size = 8128050, upload-time = "2025-12-10T22:55:04.997Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/aa/7ab67f2b729ae6a91bcf9dcac0affb95fb8c56f7fd2b2af894ae0b0cf6fa/matplotlib-3.10.8-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ee40c27c795bda6a5292e9cff9890189d32f7e3a0bf04e0e3c9430c4a00c37df", size = 8700452, upload-time = "2025-12-10T22:55:07.47Z" },
+ { url = "https://files.pythonhosted.org/packages/73/ae/2d5817b0acee3c49b7e7ccfbf5b273f284957cc8e270adf36375db353190/matplotlib-3.10.8-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a48f2b74020919552ea25d222d5cc6af9ca3f4eb43a93e14d068457f545c2a17", size = 9534928, upload-time = "2025-12-10T22:55:10.566Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/5b/8e66653e9f7c39cb2e5cab25fce4810daffa2bff02cbf5f3077cea9e942c/matplotlib-3.10.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f254d118d14a7f99d616271d6c3c27922c092dac11112670b157798b89bf4933", size = 9586377, upload-time = "2025-12-10T22:55:12.362Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/e2/fd0bbadf837f81edb0d208ba8f8cb552874c3b16e27cb91a31977d90875d/matplotlib-3.10.8-cp310-cp310-win_amd64.whl", hash = "sha256:f9b587c9c7274c1613a30afabf65a272114cd6cdbe67b3406f818c79d7ab2e2a", size = 8128127, upload-time = "2025-12-10T22:55:14.436Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/86/de7e3a1cdcfc941483af70609edc06b83e7c8a0e0dc9ac325200a3f4d220/matplotlib-3.10.8-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6be43b667360fef5c754dda5d25a32e6307a03c204f3c0fc5468b78fa87b4160", size = 8251215, upload-time = "2025-12-10T22:55:16.175Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/14/baad3222f424b19ce6ad243c71de1ad9ec6b2e4eb1e458a48fdc6d120401/matplotlib-3.10.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a2b336e2d91a3d7006864e0990c83b216fcdca64b5a6484912902cef87313d78", size = 8139625, upload-time = "2025-12-10T22:55:17.712Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/a0/7024215e95d456de5883e6732e708d8187d9753a21d32f8ddb3befc0c445/matplotlib-3.10.8-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:efb30e3baaea72ce5928e32bab719ab4770099079d66726a62b11b1ef7273be4", size = 8712614, upload-time = "2025-12-10T22:55:20.8Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/f4/b8347351da9a5b3f41e26cf547252d861f685c6867d179a7c9d60ad50189/matplotlib-3.10.8-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d56a1efd5bfd61486c8bc968fa18734464556f0fb8e51690f4ac25d85cbbbbc2", size = 9540997, upload-time = "2025-12-10T22:55:23.258Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/c0/c7b914e297efe0bc36917bf216b2acb91044b91e930e878ae12981e461e5/matplotlib-3.10.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:238b7ce5717600615c895050239ec955d91f321c209dd110db988500558e70d6", size = 9596825, upload-time = "2025-12-10T22:55:25.217Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/d3/a4bbc01c237ab710a1f22b4da72f4ff6d77eb4c7735ea9811a94ae239067/matplotlib-3.10.8-cp311-cp311-win_amd64.whl", hash = "sha256:18821ace09c763ec93aef5eeff087ee493a24051936d7b9ebcad9662f66501f9", size = 8135090, upload-time = "2025-12-10T22:55:27.162Z" },
+ { url = "https://files.pythonhosted.org/packages/89/dd/a0b6588f102beab33ca6f5218b31725216577b2a24172f327eaf6417d5c9/matplotlib-3.10.8-cp311-cp311-win_arm64.whl", hash = "sha256:bab485bcf8b1c7d2060b4fcb6fc368a9e6f4cd754c9c2fea281f4be21df394a2", size = 8012377, upload-time = "2025-12-10T22:55:29.185Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/67/f997cdcbb514012eb0d10cd2b4b332667997fb5ebe26b8d41d04962fa0e6/matplotlib-3.10.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:64fcc24778ca0404ce0cb7b6b77ae1f4c7231cdd60e6778f999ee05cbd581b9a", size = 8260453, upload-time = "2025-12-10T22:55:30.709Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/65/07d5f5c7f7c994f12c768708bd2e17a4f01a2b0f44a1c9eccad872433e2e/matplotlib-3.10.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b9a5ca4ac220a0cdd1ba6bcba3608547117d30468fefce49bb26f55c1a3d5c58", size = 8148321, upload-time = "2025-12-10T22:55:33.265Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/f3/c5195b1ae57ef85339fd7285dfb603b22c8b4e79114bae5f4f0fcf688677/matplotlib-3.10.8-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3ab4aabc72de4ff77b3ec33a6d78a68227bf1123465887f9905ba79184a1cc04", size = 8716944, upload-time = "2025-12-10T22:55:34.922Z" },
+ { url = "https://files.pythonhosted.org/packages/00/f9/7638f5cc82ec8a7aa005de48622eecc3ed7c9854b96ba15bd76b7fd27574/matplotlib-3.10.8-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:24d50994d8c5816ddc35411e50a86ab05f575e2530c02752e02538122613371f", size = 9550099, upload-time = "2025-12-10T22:55:36.789Z" },
+ { url = "https://files.pythonhosted.org/packages/57/61/78cd5920d35b29fd2a0fe894de8adf672ff52939d2e9b43cb83cd5ce1bc7/matplotlib-3.10.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:99eefd13c0dc3b3c1b4d561c1169e65fe47aab7b8158754d7c084088e2329466", size = 9613040, upload-time = "2025-12-10T22:55:38.715Z" },
+ { url = "https://files.pythonhosted.org/packages/30/4e/c10f171b6e2f44d9e3a2b96efa38b1677439d79c99357600a62cc1e9594e/matplotlib-3.10.8-cp312-cp312-win_amd64.whl", hash = "sha256:dd80ecb295460a5d9d260df63c43f4afbdd832d725a531f008dad1664f458adf", size = 8142717, upload-time = "2025-12-10T22:55:41.103Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/76/934db220026b5fef85f45d51a738b91dea7d70207581063cd9bd8fafcf74/matplotlib-3.10.8-cp312-cp312-win_arm64.whl", hash = "sha256:3c624e43ed56313651bc18a47f838b60d7b8032ed348911c54906b130b20071b", size = 8012751, upload-time = "2025-12-10T22:55:42.684Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/b9/15fd5541ef4f5b9a17eefd379356cf12175fe577424e7b1d80676516031a/matplotlib-3.10.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3f2e409836d7f5ac2f1c013110a4d50b9f7edc26328c108915f9075d7d7a91b6", size = 8261076, upload-time = "2025-12-10T22:55:44.648Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/a0/2ba3473c1b66b9c74dc7107c67e9008cb1782edbe896d4c899d39ae9cf78/matplotlib-3.10.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:56271f3dac49a88d7fca5060f004d9d22b865f743a12a23b1e937a0be4818ee1", size = 8148794, upload-time = "2025-12-10T22:55:46.252Z" },
+ { url = "https://files.pythonhosted.org/packages/75/97/a471f1c3eb1fd6f6c24a31a5858f443891d5127e63a7788678d14e249aea/matplotlib-3.10.8-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a0a7f52498f72f13d4a25ea70f35f4cb60642b466cbb0a9be951b5bc3f45a486", size = 8718474, upload-time = "2025-12-10T22:55:47.864Z" },
+ { url = "https://files.pythonhosted.org/packages/01/be/cd478f4b66f48256f42927d0acbcd63a26a893136456cd079c0cc24fbabf/matplotlib-3.10.8-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:646d95230efb9ca614a7a594d4fcacde0ac61d25e37dd51710b36477594963ce", size = 9549637, upload-time = "2025-12-10T22:55:50.048Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/7c/8dc289776eae5109e268c4fb92baf870678dc048a25d4ac903683b86d5bf/matplotlib-3.10.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f89c151aab2e2e23cb3fe0acad1e8b82841fd265379c4cecd0f3fcb34c15e0f6", size = 9613678, upload-time = "2025-12-10T22:55:52.21Z" },
+ { url = "https://files.pythonhosted.org/packages/64/40/37612487cc8a437d4dd261b32ca21fe2d79510fe74af74e1f42becb1bdb8/matplotlib-3.10.8-cp313-cp313-win_amd64.whl", hash = "sha256:e8ea3e2d4066083e264e75c829078f9e149fa119d27e19acd503de65e0b13149", size = 8142686, upload-time = "2025-12-10T22:55:54.253Z" },
+ { url = "https://files.pythonhosted.org/packages/66/52/8d8a8730e968185514680c2a6625943f70269509c3dcfc0dcf7d75928cb8/matplotlib-3.10.8-cp313-cp313-win_arm64.whl", hash = "sha256:c108a1d6fa78a50646029cb6d49808ff0fc1330fda87fa6f6250c6b5369b6645", size = 8012917, upload-time = "2025-12-10T22:55:56.268Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/27/51fe26e1062f298af5ef66343d8ef460e090a27fea73036c76c35821df04/matplotlib-3.10.8-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:ad3d9833a64cf48cc4300f2b406c3d0f4f4724a91c0bd5640678a6ba7c102077", size = 8305679, upload-time = "2025-12-10T22:55:57.856Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/1e/4de865bc591ac8e3062e835f42dd7fe7a93168d519557837f0e37513f629/matplotlib-3.10.8-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:eb3823f11823deade26ce3b9f40dcb4a213da7a670013929f31d5f5ed1055b22", size = 8198336, upload-time = "2025-12-10T22:55:59.371Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/cb/2f7b6e75fb4dce87ef91f60cac4f6e34f4c145ab036a22318ec837971300/matplotlib-3.10.8-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d9050fee89a89ed57b4fb2c1bfac9a3d0c57a0d55aed95949eedbc42070fea39", size = 8731653, upload-time = "2025-12-10T22:56:01.032Z" },
+ { url = "https://files.pythonhosted.org/packages/46/b3/bd9c57d6ba670a37ab31fb87ec3e8691b947134b201f881665b28cc039ff/matplotlib-3.10.8-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b44d07310e404ba95f8c25aa5536f154c0a8ec473303535949e52eb71d0a1565", size = 9561356, upload-time = "2025-12-10T22:56:02.95Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/3d/8b94a481456dfc9dfe6e39e93b5ab376e50998cddfd23f4ae3b431708f16/matplotlib-3.10.8-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:0a33deb84c15ede243aead39f77e990469fff93ad1521163305095b77b72ce4a", size = 9614000, upload-time = "2025-12-10T22:56:05.411Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/cd/bc06149fe5585ba800b189a6a654a75f1f127e8aab02fd2be10df7fa500c/matplotlib-3.10.8-cp313-cp313t-win_amd64.whl", hash = "sha256:3a48a78d2786784cc2413e57397981fb45c79e968d99656706018d6e62e57958", size = 8220043, upload-time = "2025-12-10T22:56:07.551Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/de/b22cf255abec916562cc04eef457c13e58a1990048de0c0c3604d082355e/matplotlib-3.10.8-cp313-cp313t-win_arm64.whl", hash = "sha256:15d30132718972c2c074cd14638c7f4592bd98719e2308bccea40e0538bc0cb5", size = 8062075, upload-time = "2025-12-10T22:56:09.178Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/43/9c0ff7a2f11615e516c3b058e1e6e8f9614ddeca53faca06da267c48345d/matplotlib-3.10.8-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b53285e65d4fa4c86399979e956235deb900be5baa7fc1218ea67fbfaeaadd6f", size = 8262481, upload-time = "2025-12-10T22:56:10.885Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/ca/e8ae28649fcdf039fda5ef554b40a95f50592a3c47e6f7270c9561c12b07/matplotlib-3.10.8-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:32f8dce744be5569bebe789e46727946041199030db8aeb2954d26013a0eb26b", size = 8151473, upload-time = "2025-12-10T22:56:12.377Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/6f/009d129ae70b75e88cbe7e503a12a4c0670e08ed748a902c2568909e9eb5/matplotlib-3.10.8-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4cf267add95b1c88300d96ca837833d4112756045364f5c734a2276038dae27d", size = 9553896, upload-time = "2025-12-10T22:56:14.432Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/26/4221a741eb97967bc1fd5e4c52b9aa5a91b2f4ec05b59f6def4d820f9df9/matplotlib-3.10.8-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2cf5bd12cecf46908f286d7838b2abc6c91cda506c0445b8223a7c19a00df008", size = 9824193, upload-time = "2025-12-10T22:56:16.29Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/f3/3abf75f38605772cf48a9daf5821cd4f563472f38b4b828c6fba6fa6d06e/matplotlib-3.10.8-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:41703cc95688f2516b480f7f339d8851a6035f18e100ee6a32bc0b8536a12a9c", size = 9615444, upload-time = "2025-12-10T22:56:18.155Z" },
+ { url = "https://files.pythonhosted.org/packages/93/a5/de89ac80f10b8dc615807ee1133cd99ac74082581196d4d9590bea10690d/matplotlib-3.10.8-cp314-cp314-win_amd64.whl", hash = "sha256:83d282364ea9f3e52363da262ce32a09dfe241e4080dcedda3c0db059d3c1f11", size = 8272719, upload-time = "2025-12-10T22:56:20.366Z" },
+ { url = "https://files.pythonhosted.org/packages/69/ce/b006495c19ccc0a137b48083168a37bd056392dee02f87dba0472f2797fe/matplotlib-3.10.8-cp314-cp314-win_arm64.whl", hash = "sha256:2c1998e92cd5999e295a731bcb2911c75f597d937341f3030cc24ef2733d78a8", size = 8144205, upload-time = "2025-12-10T22:56:22.239Z" },
+ { url = "https://files.pythonhosted.org/packages/68/d9/b31116a3a855bd313c6fcdb7226926d59b041f26061c6c5b1be66a08c826/matplotlib-3.10.8-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:b5a2b97dbdc7d4f353ebf343744f1d1f1cca8aa8bfddb4262fcf4306c3761d50", size = 8305785, upload-time = "2025-12-10T22:56:24.218Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/90/6effe8103f0272685767ba5f094f453784057072f49b393e3ea178fe70a5/matplotlib-3.10.8-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3f5c3e4da343bba819f0234186b9004faba952cc420fbc522dc4e103c1985908", size = 8198361, upload-time = "2025-12-10T22:56:26.787Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/65/a73188711bea603615fc0baecca1061429ac16940e2385433cc778a9d8e7/matplotlib-3.10.8-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f62550b9a30afde8c1c3ae450e5eb547d579dd69b25c2fc7a1c67f934c1717a", size = 9561357, upload-time = "2025-12-10T22:56:28.953Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/3d/b5c5d5d5be8ce63292567f0e2c43dde9953d3ed86ac2de0a72e93c8f07a1/matplotlib-3.10.8-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:495672de149445ec1b772ff2c9ede9b769e3cb4f0d0aa7fa730d7f59e2d4e1c1", size = 9823610, upload-time = "2025-12-10T22:56:31.455Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/4b/e7beb6bbd49f6bae727a12b270a2654d13c397576d25bd6786e47033300f/matplotlib-3.10.8-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:595ba4d8fe983b88f0eec8c26a241e16d6376fe1979086232f481f8f3f67494c", size = 9614011, upload-time = "2025-12-10T22:56:33.85Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/e6/76f2813d31f032e65f6f797e3f2f6e4aab95b65015924b1c51370395c28a/matplotlib-3.10.8-cp314-cp314t-win_amd64.whl", hash = "sha256:25d380fe8b1dc32cf8f0b1b448470a77afb195438bafdf1d858bfb876f3edf7b", size = 8362801, upload-time = "2025-12-10T22:56:36.107Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/49/d651878698a0b67f23aa28e17f45a6d6dd3d3f933fa29087fa4ce5947b5a/matplotlib-3.10.8-cp314-cp314t-win_arm64.whl", hash = "sha256:113bb52413ea508ce954a02c10ffd0d565f9c3bc7f2eddc27dfe1731e71c7b5f", size = 8192560, upload-time = "2025-12-10T22:56:38.008Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/43/31d59500bb950b0d188e149a2e552040528c13d6e3d6e84d0cccac593dcd/matplotlib-3.10.8-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:f97aeb209c3d2511443f8797e3e5a569aebb040d4f8bc79aa3ee78a8fb9e3dd8", size = 8237252, upload-time = "2025-12-10T22:56:39.529Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/2c/615c09984f3c5f907f51c886538ad785cf72e0e11a3225de2c0f9442aecc/matplotlib-3.10.8-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fb061f596dad3a0f52b60dc6a5dec4a0c300dec41e058a7efe09256188d170b7", size = 8124693, upload-time = "2025-12-10T22:56:41.758Z" },
+ { url = "https://files.pythonhosted.org/packages/91/e1/2757277a1c56041e1fc104b51a0f7b9a4afc8eb737865d63cababe30bc61/matplotlib-3.10.8-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:12d90df9183093fcd479f4172ac26b322b1248b15729cb57f42f71f24c7e37a3", size = 8702205, upload-time = "2025-12-10T22:56:43.415Z" },
+ { url = "https://files.pythonhosted.org/packages/04/30/3afaa31c757f34b7725ab9d2ba8b48b5e89c2019c003e7d0ead143aabc5a/matplotlib-3.10.8-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6da7c2ce169267d0d066adcf63758f0604aa6c3eebf67458930f9d9b79ad1db1", size = 8249198, upload-time = "2025-12-10T22:56:45.584Z" },
+ { url = "https://files.pythonhosted.org/packages/48/2f/6334aec331f57485a642a7c8be03cb286f29111ae71c46c38b363230063c/matplotlib-3.10.8-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:9153c3292705be9f9c64498a8872118540c3f4123d1a1c840172edf262c8be4a", size = 8136817, upload-time = "2025-12-10T22:56:47.339Z" },
+ { url = "https://files.pythonhosted.org/packages/73/e4/6d6f14b2a759c622f191b2d67e9075a3f56aaccb3be4bb9bb6890030d0a0/matplotlib-3.10.8-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ae029229a57cd1e8fe542485f27e7ca7b23aa9e8944ddb4985d0bc444f1eca2", size = 8713867, upload-time = "2025-12-10T22:56:48.954Z" },
+]
+
+[[package]]
+name = "matplotlib-inline"
+version = "0.2.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "traitlets" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c7/74/97e72a36efd4ae2bccb3463284300f8953f199b5ffbc04cbbb0ec78f74b1/matplotlib_inline-0.2.1.tar.gz", hash = "sha256:e1ee949c340d771fc39e241ea75683deb94762c8fa5f2927ec57c83c4dffa9fe", size = 8110, upload-time = "2025-10-23T09:00:22.126Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/af/33/ee4519fa02ed11a94aef9559552f3b17bb863f2ecfe1a35dc7f548cde231/matplotlib_inline-0.2.1-py3-none-any.whl", hash = "sha256:d56ce5156ba6085e00a9d54fead6ed29a9c47e215cd1bba2e976ef39f5710a76", size = 9516, upload-time = "2025-10-23T09:00:20.675Z" },
+]
+
+[[package]]
+name = "mdurl"
+version = "0.1.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
+]
+
+[[package]]
+name = "more-itertools"
+version = "10.8.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ea/5d/38b681d3fce7a266dd9ab73c66959406d565b3e85f21d5e66e1181d93721/more_itertools-10.8.0.tar.gz", hash = "sha256:f638ddf8a1a0d134181275fb5d58b086ead7c6a72429ad725c67503f13ba30bd", size = 137431, upload-time = "2025-09-02T15:23:11.018Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl", hash = "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b", size = 69667, upload-time = "2025-09-02T15:23:09.635Z" },
+]
+
+[[package]]
+name = "multidict"
+version = "6.7.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions", marker = "python_full_version < '3.11'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/1a/c2/c2d94cbe6ac1753f3fc980da97b3d930efe1da3af3c9f5125354436c073d/multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d", size = 102010, upload-time = "2026-01-26T02:46:45.979Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/84/0b/19348d4c98980c4851d2f943f8ebafdece2ae7ef737adcfa5994ce8e5f10/multidict-6.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c93c3db7ea657dd4637d57e74ab73de31bccefe144d3d4ce370052035bc85fb5", size = 77176, upload-time = "2026-01-26T02:42:59.784Z" },
+ { url = "https://files.pythonhosted.org/packages/ef/04/9de3f8077852e3d438215c81e9b691244532d2e05b4270e89ce67b7d103c/multidict-6.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:974e72a2474600827abaeda71af0c53d9ebbc3c2eb7da37b37d7829ae31232d8", size = 44996, upload-time = "2026-01-26T02:43:01.674Z" },
+ { url = "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdea2e7b2456cfb6694fb113066fd0ec7ea4d67e3a35e1f4cbeea0b448bf5872", size = 44631, upload-time = "2026-01-26T02:43:03.169Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/7f/0e3b1390ae772f27501199996b94b52ceeb64fe6f9120a32c6c3f6b781be/multidict-6.7.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17207077e29342fdc2c9a82e4b306f1127bf1ea91f8b71e02d4798a70bb99991", size = 242561, upload-time = "2026-01-26T02:43:04.733Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/f4/8719f4f167586af317b69dd3e90f913416c91ca610cac79a45c53f590312/multidict-6.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4f49cb5661344764e4c7c7973e92a47a59b8fc19b6523649ec9dc4960e58a03", size = 242223, upload-time = "2026-01-26T02:43:06.695Z" },
+ { url = "https://files.pythonhosted.org/packages/47/ab/7c36164cce64a6ad19c6d9a85377b7178ecf3b89f8fd589c73381a5eedfd/multidict-6.7.1-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a9fc4caa29e2e6ae408d1c450ac8bf19892c5fca83ee634ecd88a53332c59981", size = 222322, upload-time = "2026-01-26T02:43:08.472Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/79/a25add6fb38035b5337bc5734f296d9afc99163403bbcf56d4170f97eb62/multidict-6.7.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c5f0c21549ab432b57dcc82130f388d84ad8179824cc3f223d5e7cfbfd4143f6", size = 254005, upload-time = "2026-01-26T02:43:10.127Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/7b/64a87cf98e12f756fc8bd444b001232ffff2be37288f018ad0d3f0aae931/multidict-6.7.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7dfb78d966b2c906ae1d28ccf6e6712a3cd04407ee5088cd276fe8cb42186190", size = 251173, upload-time = "2026-01-26T02:43:11.731Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/ac/b605473de2bb404e742f2cc3583d12aedb2352a70e49ae8fce455b50c5aa/multidict-6.7.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9b0d9b91d1aa44db9c1f1ecd0d9d2ae610b2f4f856448664e01a3b35899f3f92", size = 243273, upload-time = "2026-01-26T02:43:13.063Z" },
+ { url = "https://files.pythonhosted.org/packages/03/65/11492d6a0e259783720f3bc1d9ea55579a76f1407e31ed44045c99542004/multidict-6.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dd96c01a9dcd4889dcfcf9eb5544ca0c77603f239e3ffab0524ec17aea9a93ee", size = 238956, upload-time = "2026-01-26T02:43:14.843Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/a7/7ee591302af64e7c196fb63fe856c788993c1372df765102bd0448e7e165/multidict-6.7.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:067343c68cd6612d375710f895337b3a98a033c94f14b9a99eff902f205424e2", size = 233477, upload-time = "2026-01-26T02:43:16.025Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/99/c109962d58756c35fd9992fed7f2355303846ea2ff054bb5f5e9d6b888de/multidict-6.7.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5884a04f4ff56c6120f6ccf703bdeb8b5079d808ba604d4d53aec0d55dc33568", size = 243615, upload-time = "2026-01-26T02:43:17.84Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/5f/1973e7c771c86e93dcfe1c9cc55a5481b610f6614acfc28c0d326fe6bfad/multidict-6.7.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8affcf1c98b82bc901702eb73b6947a1bfa170823c153fe8a47b5f5f02e48e40", size = 249930, upload-time = "2026-01-26T02:43:19.06Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/a5/f170fc2268c3243853580203378cd522446b2df632061e0a5409817854c7/multidict-6.7.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0d17522c37d03e85c8098ec8431636309b2682cf12e58f4dbc76121fb50e4962", size = 243807, upload-time = "2026-01-26T02:43:20.286Z" },
+ { url = "https://files.pythonhosted.org/packages/de/01/73856fab6d125e5bc652c3986b90e8699a95e84b48d72f39ade6c0e74a8c/multidict-6.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:24c0cf81544ca5e17cfcb6e482e7a82cd475925242b308b890c9452a074d4505", size = 239103, upload-time = "2026-01-26T02:43:21.508Z" },
+ { url = "https://files.pythonhosted.org/packages/e7/46/f1220bd9944d8aa40d8ccff100eeeee19b505b857b6f603d6078cb5315b0/multidict-6.7.1-cp310-cp310-win32.whl", hash = "sha256:d82dd730a95e6643802f4454b8fdecdf08667881a9c5670db85bc5a56693f122", size = 41416, upload-time = "2026-01-26T02:43:22.703Z" },
+ { url = "https://files.pythonhosted.org/packages/68/00/9b38e272a770303692fc406c36e1a4c740f401522d5787691eb38a8925a8/multidict-6.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cf37cbe5ced48d417ba045aca1b21bafca67489452debcde94778a576666a1df", size = 46022, upload-time = "2026-01-26T02:43:23.77Z" },
+ { url = "https://files.pythonhosted.org/packages/64/65/d8d42490c02ee07b6bbe00f7190d70bb4738b3cce7629aaf9f213ef730dd/multidict-6.7.1-cp310-cp310-win_arm64.whl", hash = "sha256:59bc83d3f66b41dac1e7460aac1d196edc70c9ba3094965c467715a70ecb46db", size = 43238, upload-time = "2026-01-26T02:43:24.882Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/f1/a90635c4f88fb913fbf4ce660b83b7445b7a02615bda034b2f8eb38fd597/multidict-6.7.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ff981b266af91d7b4b3793ca3382e53229088d193a85dfad6f5f4c27fc73e5d", size = 76626, upload-time = "2026-01-26T02:43:26.485Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/9b/267e64eaf6fc637a15b35f5de31a566634a2740f97d8d094a69d34f524a4/multidict-6.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:844c5bca0b5444adb44a623fb0a1310c2f4cd41f402126bb269cd44c9b3f3e1e", size = 44706, upload-time = "2026-01-26T02:43:27.607Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/a4/d45caf2b97b035c57267791ecfaafbd59c68212004b3842830954bb4b02e/multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f2a0a924d4c2e9afcd7ec64f9de35fcd96915149b2216e1cb2c10a56df483855", size = 44356, upload-time = "2026-01-26T02:43:28.661Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/d2/0a36c8473f0cbaeadd5db6c8b72d15bbceeec275807772bfcd059bef487d/multidict-6.7.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8be1802715a8e892c784c0197c2ace276ea52702a0ede98b6310c8f255a5afb3", size = 244355, upload-time = "2026-01-26T02:43:31.165Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/16/8c65be997fd7dd311b7d39c7b6e71a0cb449bad093761481eccbbe4b42a2/multidict-6.7.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e2d2ed645ea29f31c4c7ea1552fcfd7cb7ba656e1eafd4134a6620c9f5fdd9e", size = 246433, upload-time = "2026-01-26T02:43:32.581Z" },
+ { url = "https://files.pythonhosted.org/packages/01/fb/4dbd7e848d2799c6a026ec88ad39cf2b8416aa167fcc903baa55ecaa045c/multidict-6.7.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:95922cee9a778659e91db6497596435777bd25ed116701a4c034f8e46544955a", size = 225376, upload-time = "2026-01-26T02:43:34.417Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/8a/4a3a6341eac3830f6053062f8fbc9a9e54407c80755b3f05bc427295c2d0/multidict-6.7.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6b83cabdc375ffaaa15edd97eb7c0c672ad788e2687004990074d7d6c9b140c8", size = 257365, upload-time = "2026-01-26T02:43:35.741Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/a2/dd575a69c1aa206e12d27d0770cdf9b92434b48a9ef0cd0d1afdecaa93c4/multidict-6.7.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:38fb49540705369bab8484db0689d86c0a33a0a9f2c1b197f506b71b4b6c19b0", size = 254747, upload-time = "2026-01-26T02:43:36.976Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/56/21b27c560c13822ed93133f08aa6372c53a8e067f11fbed37b4adcdac922/multidict-6.7.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:439cbebd499f92e9aa6793016a8acaa161dfa749ae86d20960189f5398a19144", size = 246293, upload-time = "2026-01-26T02:43:38.258Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/a4/23466059dc3854763423d0ad6c0f3683a379d97673b1b89ec33826e46728/multidict-6.7.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6d3bc717b6fe763b8be3f2bee2701d3c8eb1b2a8ae9f60910f1b2860c82b6c49", size = 242962, upload-time = "2026-01-26T02:43:40.034Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/67/51dd754a3524d685958001e8fa20a0f5f90a6a856e0a9dcabff69be3dbb7/multidict-6.7.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:619e5a1ac57986dbfec9f0b301d865dddf763696435e2962f6d9cf2fdff2bb71", size = 237360, upload-time = "2026-01-26T02:43:41.752Z" },
+ { url = "https://files.pythonhosted.org/packages/64/3f/036dfc8c174934d4b55d86ff4f978e558b0e585cef70cfc1ad01adc6bf18/multidict-6.7.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0b38ebffd9be37c1170d33bc0f36f4f262e0a09bc1aac1c34c7aa51a7293f0b3", size = 245940, upload-time = "2026-01-26T02:43:43.042Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/20/6214d3c105928ebc353a1c644a6ef1408bc5794fcb4f170bb524a3c16311/multidict-6.7.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:10ae39c9cfe6adedcdb764f5e8411d4a92b055e35573a2eaa88d3323289ef93c", size = 253502, upload-time = "2026-01-26T02:43:44.371Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/e2/c653bc4ae1be70a0f836b82172d643fcf1dade042ba2676ab08ec08bff0f/multidict-6.7.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:25167cc263257660290fba06b9318d2026e3c910be240a146e1f66dd114af2b0", size = 247065, upload-time = "2026-01-26T02:43:45.745Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/11/a854b4154cd3bd8b1fd375e8a8ca9d73be37610c361543d56f764109509b/multidict-6.7.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:128441d052254f42989ef98b7b6a6ecb1e6f708aa962c7984235316db59f50fa", size = 241870, upload-time = "2026-01-26T02:43:47.054Z" },
+ { url = "https://files.pythonhosted.org/packages/13/bf/9676c0392309b5fdae322333d22a829715b570edb9baa8016a517b55b558/multidict-6.7.1-cp311-cp311-win32.whl", hash = "sha256:d62b7f64ffde3b99d06b707a280db04fb3855b55f5a06df387236051d0668f4a", size = 41302, upload-time = "2026-01-26T02:43:48.753Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/68/f16a3a8ba6f7b6dc92a1f19669c0810bd2c43fc5a02da13b1cbf8e253845/multidict-6.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:bdbf9f3b332abd0cdb306e7c2113818ab1e922dc84b8f8fd06ec89ed2a19ab8b", size = 45981, upload-time = "2026-01-26T02:43:49.921Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/ad/9dd5305253fa00cd3c7555dbef69d5bf4133debc53b87ab8d6a44d411665/multidict-6.7.1-cp311-cp311-win_arm64.whl", hash = "sha256:b8c990b037d2fff2f4e33d3f21b9b531c5745b33a49a7d6dbe7a177266af44f6", size = 43159, upload-time = "2026-01-26T02:43:51.635Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/9c/f20e0e2cf80e4b2e4b1c365bf5fe104ee633c751a724246262db8f1a0b13/multidict-6.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a90f75c956e32891a4eda3639ce6dd86e87105271f43d43442a3aedf3cddf172", size = 76893, upload-time = "2026-01-26T02:43:52.754Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/cf/18ef143a81610136d3da8193da9d80bfe1cb548a1e2d1c775f26b23d024a/multidict-6.7.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fccb473e87eaa1382689053e4a4618e7ba7b9b9b8d6adf2027ee474597128cd", size = 45456, upload-time = "2026-01-26T02:43:53.893Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/65/1caac9d4cd32e8433908683446eebc953e82d22b03d10d41a5f0fefe991b/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0fa96985700739c4c7853a43c0b3e169360d6855780021bfc6d0f1ce7c123e7", size = 43872, upload-time = "2026-01-26T02:43:55.041Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/3b/d6bd75dc4f3ff7c73766e04e705b00ed6dbbaccf670d9e05a12b006f5a21/multidict-6.7.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cb2a55f408c3043e42b40cc8eecd575afa27b7e0b956dfb190de0f8499a57a53", size = 251018, upload-time = "2026-01-26T02:43:56.198Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/80/c959c5933adedb9ac15152e4067c702a808ea183a8b64cf8f31af8ad3155/multidict-6.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb0ce7b2a32d09892b3dd6cc44877a0d02a33241fafca5f25c8b6b62374f8b75", size = 258883, upload-time = "2026-01-26T02:43:57.499Z" },
+ { url = "https://files.pythonhosted.org/packages/86/85/7ed40adafea3d4f1c8b916e3b5cc3a8e07dfcdcb9cd72800f4ed3ca1b387/multidict-6.7.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c3a32d23520ee37bf327d1e1a656fec76a2edd5c038bf43eddfa0572ec49c60b", size = 242413, upload-time = "2026-01-26T02:43:58.755Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/57/b8565ff533e48595503c785f8361ff9a4fde4d67de25c207cd0ba3befd03/multidict-6.7.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9c90fed18bffc0189ba814749fdcc102b536e83a9f738a9003e569acd540a733", size = 268404, upload-time = "2026-01-26T02:44:00.216Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/50/9810c5c29350f7258180dfdcb2e52783a0632862eb334c4896ac717cebcb/multidict-6.7.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:da62917e6076f512daccfbbde27f46fed1c98fee202f0559adec8ee0de67f71a", size = 269456, upload-time = "2026-01-26T02:44:02.202Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/8d/5e5be3ced1d12966fefb5c4ea3b2a5b480afcea36406559442c6e31d4a48/multidict-6.7.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bfde23ef6ed9db7eaee6c37dcec08524cb43903c60b285b172b6c094711b3961", size = 256322, upload-time = "2026-01-26T02:44:03.56Z" },
+ { url = "https://files.pythonhosted.org/packages/31/6e/d8a26d81ac166a5592782d208dd90dfdc0a7a218adaa52b45a672b46c122/multidict-6.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3758692429e4e32f1ba0df23219cd0b4fc0a52f476726fff9337d1a57676a582", size = 253955, upload-time = "2026-01-26T02:44:04.845Z" },
+ { url = "https://files.pythonhosted.org/packages/59/4c/7c672c8aad41534ba619bcd4ade7a0dc87ed6b8b5c06149b85d3dd03f0cd/multidict-6.7.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:398c1478926eca669f2fd6a5856b6de9c0acf23a2cb59a14c0ba5844fa38077e", size = 251254, upload-time = "2026-01-26T02:44:06.133Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/bd/84c24de512cbafbdbc39439f74e967f19570ce7924e3007174a29c348916/multidict-6.7.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c102791b1c4f3ab36ce4101154549105a53dc828f016356b3e3bcae2e3a039d3", size = 252059, upload-time = "2026-01-26T02:44:07.518Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/ba/f5449385510825b73d01c2d4087bf6d2fccc20a2d42ac34df93191d3dd03/multidict-6.7.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a088b62bd733e2ad12c50dad01b7d0166c30287c166e137433d3b410add807a6", size = 263588, upload-time = "2026-01-26T02:44:09.382Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/11/afc7c677f68f75c84a69fe37184f0f82fce13ce4b92f49f3db280b7e92b3/multidict-6.7.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3d51ff4785d58d3f6c91bdbffcb5e1f7ddfda557727043aa20d20ec4f65e324a", size = 259642, upload-time = "2026-01-26T02:44:10.73Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/17/ebb9644da78c4ab36403739e0e6e0e30ebb135b9caf3440825001a0bddcb/multidict-6.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc5907494fccf3e7d3f94f95c91d6336b092b5fc83811720fae5e2765890dfba", size = 251377, upload-time = "2026-01-26T02:44:12.042Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/a4/840f5b97339e27846c46307f2530a2805d9d537d8b8bd416af031cad7fa0/multidict-6.7.1-cp312-cp312-win32.whl", hash = "sha256:28ca5ce2fd9716631133d0e9a9b9a745ad7f60bac2bccafb56aa380fc0b6c511", size = 41887, upload-time = "2026-01-26T02:44:14.245Z" },
+ { url = "https://files.pythonhosted.org/packages/80/31/0b2517913687895f5904325c2069d6a3b78f66cc641a86a2baf75a05dcbb/multidict-6.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcee94dfbd638784645b066074b338bc9cc155d4b4bffa4adce1615c5a426c19", size = 46053, upload-time = "2026-01-26T02:44:15.371Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/5b/aba28e4ee4006ae4c7df8d327d31025d760ffa992ea23812a601d226e682/multidict-6.7.1-cp312-cp312-win_arm64.whl", hash = "sha256:ba0a9fb644d0c1a2194cf7ffb043bd852cea63a57f66fbd33959f7dae18517bf", size = 43307, upload-time = "2026-01-26T02:44:16.852Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/22/929c141d6c0dba87d3e1d38fbdf1ba8baba86b7776469f2bc2d3227a1e67/multidict-6.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2b41f5fed0ed563624f1c17630cb9941cf2309d4df00e494b551b5f3e3d67a23", size = 76174, upload-time = "2026-01-26T02:44:18.509Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/75/bc704ae15fee974f8fccd871305e254754167dce5f9e42d88a2def741a1d/multidict-6.7.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84e61e3af5463c19b67ced91f6c634effb89ef8bfc5ca0267f954451ed4bb6a2", size = 45116, upload-time = "2026-01-26T02:44:19.745Z" },
+ { url = "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:935434b9853c7c112eee7ac891bc4cb86455aa631269ae35442cb316790c1445", size = 43524, upload-time = "2026-01-26T02:44:21.571Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/3c/414842ef8d5a1628d68edee29ba0e5bcf235dbfb3ccd3ea303a7fe8c72ff/multidict-6.7.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:432feb25a1cb67fe82a9680b4d65fb542e4635cb3166cd9c01560651ad60f177", size = 249368, upload-time = "2026-01-26T02:44:22.803Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/32/befed7f74c458b4a525e60519fe8d87eef72bb1e99924fa2b0f9d97a221e/multidict-6.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e82d14e3c948952a1a85503817e038cba5905a3352de76b9a465075d072fba23", size = 256952, upload-time = "2026-01-26T02:44:24.306Z" },
+ { url = "https://files.pythonhosted.org/packages/03/d6/c878a44ba877f366630c860fdf74bfb203c33778f12b6ac274936853c451/multidict-6.7.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4cfb48c6ea66c83bcaaf7e4dfa7ec1b6bbcf751b7db85a328902796dfde4c060", size = 240317, upload-time = "2026-01-26T02:44:25.772Z" },
+ { url = "https://files.pythonhosted.org/packages/68/49/57421b4d7ad2e9e60e25922b08ceb37e077b90444bde6ead629095327a6f/multidict-6.7.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1d540e51b7e8e170174555edecddbd5538105443754539193e3e1061864d444d", size = 267132, upload-time = "2026-01-26T02:44:27.648Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/fe/ec0edd52ddbcea2a2e89e174f0206444a61440b40f39704e64dc807a70bd/multidict-6.7.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:273d23f4b40f3dce4d6c8a821c741a86dec62cded82e1175ba3d99be128147ed", size = 268140, upload-time = "2026-01-26T02:44:29.588Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/73/6e1b01cbeb458807aa0831742232dbdd1fa92bfa33f52a3f176b4ff3dc11/multidict-6.7.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d624335fd4fa1c08a53f8b4be7676ebde19cd092b3895c421045ca87895b429", size = 254277, upload-time = "2026-01-26T02:44:30.902Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/b2/5fb8c124d7561a4974c342bc8c778b471ebbeb3cc17df696f034a7e9afe7/multidict-6.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:12fad252f8b267cc75b66e8fc51b3079604e8d43a75428ffe193cd9e2195dfd6", size = 252291, upload-time = "2026-01-26T02:44:32.31Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/96/51d4e4e06bcce92577fcd488e22600bd38e4fd59c20cb49434d054903bd2/multidict-6.7.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:03ede2a6ffbe8ef936b92cb4529f27f42be7f56afcdab5ab739cd5f27fb1cbf9", size = 250156, upload-time = "2026-01-26T02:44:33.734Z" },
+ { url = "https://files.pythonhosted.org/packages/db/6b/420e173eec5fba721a50e2a9f89eda89d9c98fded1124f8d5c675f7a0c0f/multidict-6.7.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:90efbcf47dbe33dcf643a1e400d67d59abeac5db07dc3f27d6bdeae497a2198c", size = 249742, upload-time = "2026-01-26T02:44:35.222Z" },
+ { url = "https://files.pythonhosted.org/packages/44/a3/ec5b5bd98f306bc2aa297b8c6f11a46714a56b1e6ef5ebda50a4f5d7c5fb/multidict-6.7.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c4b9bfc148f5a91be9244d6264c53035c8a0dcd2f51f1c3c6e30e30ebaa1c84", size = 262221, upload-time = "2026-01-26T02:44:36.604Z" },
+ { url = "https://files.pythonhosted.org/packages/cd/f7/e8c0d0da0cd1e28d10e624604e1a36bcc3353aaebdfdc3a43c72bc683a12/multidict-6.7.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:401c5a650f3add2472d1d288c26deebc540f99e2fb83e9525007a74cd2116f1d", size = 258664, upload-time = "2026-01-26T02:44:38.008Z" },
+ { url = "https://files.pythonhosted.org/packages/52/da/151a44e8016dd33feed44f730bd856a66257c1ee7aed4f44b649fb7edeb3/multidict-6.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:97891f3b1b3ffbded884e2916cacf3c6fc87b66bb0dde46f7357404750559f33", size = 249490, upload-time = "2026-01-26T02:44:39.386Z" },
+ { url = "https://files.pythonhosted.org/packages/87/af/a3b86bf9630b732897f6fc3f4c4714b90aa4361983ccbdcd6c0339b21b0c/multidict-6.7.1-cp313-cp313-win32.whl", hash = "sha256:e1c5988359516095535c4301af38d8a8838534158f649c05dd1050222321bcb3", size = 41695, upload-time = "2026-01-26T02:44:41.318Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/35/e994121b0e90e46134673422dd564623f93304614f5d11886b1b3e06f503/multidict-6.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:960c83bf01a95b12b08fd54324a4eb1d5b52c88932b5cba5d6e712bb3ed12eb5", size = 45884, upload-time = "2026-01-26T02:44:42.488Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/61/42d3e5dbf661242a69c97ea363f2d7b46c567da8eadef8890022be6e2ab0/multidict-6.7.1-cp313-cp313-win_arm64.whl", hash = "sha256:563fe25c678aaba333d5399408f5ec3c383ca5b663e7f774dd179a520b8144df", size = 43122, upload-time = "2026-01-26T02:44:43.664Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/b3/e6b21c6c4f314bb956016b0b3ef2162590a529b84cb831c257519e7fde44/multidict-6.7.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:c76c4bec1538375dad9d452d246ca5368ad6e1c9039dadcf007ae59c70619ea1", size = 83175, upload-time = "2026-01-26T02:44:44.894Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/76/23ecd2abfe0957b234f6c960f4ade497f55f2c16aeb684d4ecdbf1c95791/multidict-6.7.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:57b46b24b5d5ebcc978da4ec23a819a9402b4228b8a90d9c656422b4bdd8a963", size = 48460, upload-time = "2026-01-26T02:44:46.106Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/57/a0ed92b23f3a042c36bc4227b72b97eca803f5f1801c1ab77c8a212d455e/multidict-6.7.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e954b24433c768ce78ab7929e84ccf3422e46deb45a4dc9f93438f8217fa2d34", size = 46930, upload-time = "2026-01-26T02:44:47.278Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/66/02ec7ace29162e447f6382c495dc95826bf931d3818799bbef11e8f7df1a/multidict-6.7.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3bd231490fa7217cc832528e1cd8752a96f0125ddd2b5749390f7c3ec8721b65", size = 242582, upload-time = "2026-01-26T02:44:48.604Z" },
+ { url = "https://files.pythonhosted.org/packages/58/18/64f5a795e7677670e872673aca234162514696274597b3708b2c0d276cce/multidict-6.7.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:253282d70d67885a15c8a7716f3a73edf2d635793ceda8173b9ecc21f2fb8292", size = 250031, upload-time = "2026-01-26T02:44:50.544Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/ed/e192291dbbe51a8290c5686f482084d31bcd9d09af24f63358c3d42fd284/multidict-6.7.1-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0b4c48648d7649c9335cf1927a8b87fa692de3dcb15faa676c6a6f1f1aabda43", size = 228596, upload-time = "2026-01-26T02:44:51.951Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/7e/3562a15a60cf747397e7f2180b0a11dc0c38d9175a650e75fa1b4d325e15/multidict-6.7.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:98bc624954ec4d2c7cb074b8eefc2b5d0ce7d482e410df446414355d158fe4ca", size = 257492, upload-time = "2026-01-26T02:44:53.902Z" },
+ { url = "https://files.pythonhosted.org/packages/24/02/7d0f9eae92b5249bb50ac1595b295f10e263dd0078ebb55115c31e0eaccd/multidict-6.7.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1b99af4d9eec0b49927b4402bcbb58dea89d3e0db8806a4086117019939ad3dd", size = 255899, upload-time = "2026-01-26T02:44:55.316Z" },
+ { url = "https://files.pythonhosted.org/packages/00/e3/9b60ed9e23e64c73a5cde95269ef1330678e9c6e34dd4eb6b431b85b5a10/multidict-6.7.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6aac4f16b472d5b7dc6f66a0d49dd57b0e0902090be16594dc9ebfd3d17c47e7", size = 247970, upload-time = "2026-01-26T02:44:56.783Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/06/538e58a63ed5cfb0bd4517e346b91da32fde409d839720f664e9a4ae4f9d/multidict-6.7.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:21f830fe223215dffd51f538e78c172ed7c7f60c9b96a2bf05c4848ad49921c3", size = 245060, upload-time = "2026-01-26T02:44:58.195Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/2f/d743a3045a97c895d401e9bd29aaa09b94f5cbdf1bd561609e5a6c431c70/multidict-6.7.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f5dd81c45b05518b9aa4da4aa74e1c93d715efa234fd3e8a179df611cc85e5f4", size = 235888, upload-time = "2026-01-26T02:44:59.57Z" },
+ { url = "https://files.pythonhosted.org/packages/38/83/5a325cac191ab28b63c52f14f1131f3b0a55ba3b9aa65a6d0bf2a9b921a0/multidict-6.7.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:eb304767bca2bb92fb9c5bd33cedc95baee5bb5f6c88e63706533a1c06ad08c8", size = 243554, upload-time = "2026-01-26T02:45:01.054Z" },
+ { url = "https://files.pythonhosted.org/packages/20/1f/9d2327086bd15da2725ef6aae624208e2ef828ed99892b17f60c344e57ed/multidict-6.7.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c9035dde0f916702850ef66460bc4239d89d08df4d02023a5926e7446724212c", size = 252341, upload-time = "2026-01-26T02:45:02.484Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/2c/2a1aa0280cf579d0f6eed8ee5211c4f1730bd7e06c636ba2ee6aafda302e/multidict-6.7.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:af959b9beeb66c822380f222f0e0a1889331597e81f1ded7f374f3ecb0fd6c52", size = 246391, upload-time = "2026-01-26T02:45:03.862Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/03/7ca022ffc36c5a3f6e03b179a5ceb829be9da5783e6fe395f347c0794680/multidict-6.7.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:41f2952231456154ee479651491e94118229844dd7226541788be783be2b5108", size = 243422, upload-time = "2026-01-26T02:45:05.296Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/1d/b31650eab6c5778aceed46ba735bd97f7c7d2f54b319fa916c0f96e7805b/multidict-6.7.1-cp313-cp313t-win32.whl", hash = "sha256:df9f19c28adcb40b6aae30bbaa1478c389efd50c28d541d76760199fc1037c32", size = 47770, upload-time = "2026-01-26T02:45:06.754Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/5b/2d2d1d522e51285bd61b1e20df8f47ae1a9d80839db0b24ea783b3832832/multidict-6.7.1-cp313-cp313t-win_amd64.whl", hash = "sha256:d54ecf9f301853f2c5e802da559604b3e95bb7a3b01a9c295c6ee591b9882de8", size = 53109, upload-time = "2026-01-26T02:45:08.044Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/a3/cc409ba012c83ca024a308516703cf339bdc4b696195644a7215a5164a24/multidict-6.7.1-cp313-cp313t-win_arm64.whl", hash = "sha256:5a37ca18e360377cfda1d62f5f382ff41f2b8c4ccb329ed974cc2e1643440118", size = 45573, upload-time = "2026-01-26T02:45:09.349Z" },
+ { url = "https://files.pythonhosted.org/packages/91/cc/db74228a8be41884a567e88a62fd589a913708fcf180d029898c17a9a371/multidict-6.7.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8f333ec9c5eb1b7105e3b84b53141e66ca05a19a605368c55450b6ba208cb9ee", size = 75190, upload-time = "2026-01-26T02:45:10.651Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/22/492f2246bb5b534abd44804292e81eeaf835388901f0c574bac4eeec73c5/multidict-6.7.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a407f13c188f804c759fc6a9f88286a565c242a76b27626594c133b82883b5c2", size = 44486, upload-time = "2026-01-26T02:45:11.938Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/4f/733c48f270565d78b4544f2baddc2fb2a245e5a8640254b12c36ac7ac68e/multidict-6.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0e161ddf326db5577c3a4cc2d8648f81456e8a20d40415541587a71620d7a7d1", size = 43219, upload-time = "2026-01-26T02:45:14.346Z" },
+ { url = "https://files.pythonhosted.org/packages/24/bb/2c0c2287963f4259c85e8bcbba9182ced8d7fca65c780c38e99e61629d11/multidict-6.7.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1e3a8bb24342a8201d178c3b4984c26ba81a577c80d4d525727427460a50c22d", size = 245132, upload-time = "2026-01-26T02:45:15.712Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/f9/44d4b3064c65079d2467888794dea218d1601898ac50222ab8a9a8094460/multidict-6.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97231140a50f5d447d3164f994b86a0bed7cd016e2682f8650d6a9158e14fd31", size = 252420, upload-time = "2026-01-26T02:45:17.293Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/13/78f7275e73fa17b24c9a51b0bd9d73ba64bb32d0ed51b02a746eb876abe7/multidict-6.7.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6b10359683bd8806a200fd2909e7c8ca3a7b24ec1d8132e483d58e791d881048", size = 233510, upload-time = "2026-01-26T02:45:19.356Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/25/8167187f62ae3cbd52da7893f58cb036b47ea3fb67138787c76800158982/multidict-6.7.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:283ddac99f7ac25a4acadbf004cb5ae34480bbeb063520f70ce397b281859362", size = 264094, upload-time = "2026-01-26T02:45:20.834Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/e7/69a3a83b7b030cf283fb06ce074a05a02322359783424d7edf0f15fe5022/multidict-6.7.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:538cec1e18c067d0e6103aa9a74f9e832904c957adc260e61cd9d8cf0c3b3d37", size = 260786, upload-time = "2026-01-26T02:45:22.818Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/3b/8ec5074bcfc450fe84273713b4b0a0dd47c0249358f5d82eb8104ffe2520/multidict-6.7.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eee46ccb30ff48a1e35bb818cc90846c6be2b68240e42a78599166722cea709", size = 248483, upload-time = "2026-01-26T02:45:24.368Z" },
+ { url = "https://files.pythonhosted.org/packages/48/5a/d5a99e3acbca0e29c5d9cba8f92ceb15dce78bab963b308ae692981e3a5d/multidict-6.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa263a02f4f2dd2d11a7b1bb4362aa7cb1049f84a9235d31adf63f30143469a0", size = 248403, upload-time = "2026-01-26T02:45:25.982Z" },
+ { url = "https://files.pythonhosted.org/packages/35/48/e58cd31f6c7d5102f2a4bf89f96b9cf7e00b6c6f3d04ecc44417c00a5a3c/multidict-6.7.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2e1425e2f99ec5bd36c15a01b690a1a2456209c5deed58f95469ffb46039ccbb", size = 240315, upload-time = "2026-01-26T02:45:27.487Z" },
+ { url = "https://files.pythonhosted.org/packages/94/33/1cd210229559cb90b6786c30676bb0c58249ff42f942765f88793b41fdce/multidict-6.7.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:497394b3239fc6f0e13a78a3e1b61296e72bf1c5f94b4c4eb80b265c37a131cd", size = 245528, upload-time = "2026-01-26T02:45:28.991Z" },
+ { url = "https://files.pythonhosted.org/packages/64/f2/6e1107d226278c876c783056b7db43d800bb64c6131cec9c8dfb6903698e/multidict-6.7.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:233b398c29d3f1b9676b4b6f75c518a06fcb2ea0b925119fb2c1bc35c05e1601", size = 258784, upload-time = "2026-01-26T02:45:30.503Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/c1/11f664f14d525e4a1b5327a82d4de61a1db604ab34c6603bb3c2cc63ad34/multidict-6.7.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:93b1818e4a6e0930454f0f2af7dfce69307ca03cdcfb3739bf4d91241967b6c1", size = 251980, upload-time = "2026-01-26T02:45:32.603Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/9f/75a9ac888121d0c5bbd4ecf4eead45668b1766f6baabfb3b7f66a410e231/multidict-6.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f33dc2a3abe9249ea5d8360f969ec7f4142e7ac45ee7014d8f8d5acddf178b7b", size = 243602, upload-time = "2026-01-26T02:45:34.043Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/e7/50bf7b004cc8525d80dbbbedfdc7aed3e4c323810890be4413e589074032/multidict-6.7.1-cp314-cp314-win32.whl", hash = "sha256:3ab8b9d8b75aef9df299595d5388b14530839f6422333357af1339443cff777d", size = 40930, upload-time = "2026-01-26T02:45:36.278Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/bf/52f25716bbe93745595800f36fb17b73711f14da59ed0bb2eba141bc9f0f/multidict-6.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:5e01429a929600e7dab7b166062d9bb54a5eed752384c7384c968c2afab8f50f", size = 45074, upload-time = "2026-01-26T02:45:37.546Z" },
+ { url = "https://files.pythonhosted.org/packages/97/ab/22803b03285fa3a525f48217963da3a65ae40f6a1b6f6cf2768879e208f9/multidict-6.7.1-cp314-cp314-win_arm64.whl", hash = "sha256:4885cb0e817aef5d00a2e8451d4665c1808378dc27c2705f1bf4ef8505c0d2e5", size = 42471, upload-time = "2026-01-26T02:45:38.889Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/6d/f9293baa6146ba9507e360ea0292b6422b016907c393e2f63fc40ab7b7b5/multidict-6.7.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0458c978acd8e6ea53c81eefaddbbee9c6c5e591f41b3f5e8e194780fe026581", size = 82401, upload-time = "2026-01-26T02:45:40.254Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/68/53b5494738d83558d87c3c71a486504d8373421c3e0dbb6d0db48ad42ee0/multidict-6.7.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c0abd12629b0af3cf590982c0b413b1e7395cd4ec026f30986818ab95bfaa94a", size = 48143, upload-time = "2026-01-26T02:45:41.635Z" },
+ { url = "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:14525a5f61d7d0c94b368a42cff4c9a4e7ba2d52e2672a7b23d84dc86fb02b0c", size = 46507, upload-time = "2026-01-26T02:45:42.99Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/fc/6800d0e5b3875568b4083ecf5f310dcf91d86d52573160834fb4bfcf5e4f/multidict-6.7.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17307b22c217b4cf05033dabefe68255a534d637c6c9b0cc8382718f87be4262", size = 239358, upload-time = "2026-01-26T02:45:44.376Z" },
+ { url = "https://files.pythonhosted.org/packages/41/75/4ad0973179361cdf3a113905e6e088173198349131be2b390f9fa4da5fc6/multidict-6.7.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a7e590ff876a3eaf1c02a4dfe0724b6e69a9e9de6d8f556816f29c496046e59", size = 246884, upload-time = "2026-01-26T02:45:47.167Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/9c/095bb28b5da139bd41fb9a5d5caff412584f377914bd8787c2aa98717130/multidict-6.7.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5fa6a95dfee63893d80a34758cd0e0c118a30b8dcb46372bf75106c591b77889", size = 225878, upload-time = "2026-01-26T02:45:48.698Z" },
+ { url = "https://files.pythonhosted.org/packages/07/d0/c0a72000243756e8f5a277b6b514fa005f2c73d481b7d9e47cd4568aa2e4/multidict-6.7.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a0543217a6a017692aa6ae5cc39adb75e587af0f3a82288b1492eb73dd6cc2a4", size = 253542, upload-time = "2026-01-26T02:45:50.164Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/6b/f69da15289e384ecf2a68837ec8b5ad8c33e973aa18b266f50fe55f24b8c/multidict-6.7.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f99fe611c312b3c1c0ace793f92464d8cd263cc3b26b5721950d977b006b6c4d", size = 252403, upload-time = "2026-01-26T02:45:51.779Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/76/b9669547afa5a1a25cd93eaca91c0da1c095b06b6d2d8ec25b713588d3a1/multidict-6.7.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9004d8386d133b7e6135679424c91b0b854d2d164af6ea3f289f8f2761064609", size = 244889, upload-time = "2026-01-26T02:45:53.27Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/a9/a50d2669e506dad33cfc45b5d574a205587b7b8a5f426f2fbb2e90882588/multidict-6.7.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e628ef0e6859ffd8273c69412a2465c4be4a9517d07261b33334b5ec6f3c7489", size = 241982, upload-time = "2026-01-26T02:45:54.919Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/bb/1609558ad8b456b4827d3c5a5b775c93b87878fd3117ed3db3423dfbce1b/multidict-6.7.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:841189848ba629c3552035a6a7f5bf3b02eb304e9fea7492ca220a8eda6b0e5c", size = 232415, upload-time = "2026-01-26T02:45:56.981Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/59/6f61039d2aa9261871e03ab9dc058a550d240f25859b05b67fd70f80d4b3/multidict-6.7.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ce1bbd7d780bb5a0da032e095c951f7014d6b0a205f8318308140f1a6aba159e", size = 240337, upload-time = "2026-01-26T02:45:58.698Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/29/fdc6a43c203890dc2ae9249971ecd0c41deaedfe00d25cb6564b2edd99eb/multidict-6.7.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b26684587228afed0d50cf804cc71062cc9c1cdf55051c4c6345d372947b268c", size = 248788, upload-time = "2026-01-26T02:46:00.862Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/14/a153a06101323e4cf086ecee3faadba52ff71633d471f9685c42e3736163/multidict-6.7.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9f9af11306994335398293f9958071019e3ab95e9a707dc1383a35613f6abcb9", size = 242842, upload-time = "2026-01-26T02:46:02.824Z" },
+ { url = "https://files.pythonhosted.org/packages/41/5f/604ae839e64a4a6efc80db94465348d3b328ee955e37acb24badbcd24d83/multidict-6.7.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b4938326284c4f1224178a560987b6cf8b4d38458b113d9b8c1db1a836e640a2", size = 240237, upload-time = "2026-01-26T02:46:05.898Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/60/c3a5187bf66f6fb546ff4ab8fb5a077cbdd832d7b1908d4365c7f74a1917/multidict-6.7.1-cp314-cp314t-win32.whl", hash = "sha256:98655c737850c064a65e006a3df7c997cd3b220be4ec8fe26215760b9697d4d7", size = 48008, upload-time = "2026-01-26T02:46:07.468Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/f7/addf1087b860ac60e6f382240f64fb99f8bfb532bb06f7c542b83c29ca61/multidict-6.7.1-cp314-cp314t-win_amd64.whl", hash = "sha256:497bde6223c212ba11d462853cfa4f0ae6ef97465033e7dc9940cdb3ab5b48e5", size = 53542, upload-time = "2026-01-26T02:46:08.809Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/81/4629d0aa32302ef7b2ec65c75a728cc5ff4fa410c50096174c1632e70b3e/multidict-6.7.1-cp314-cp314t-win_arm64.whl", hash = "sha256:2bbd113e0d4af5db41d5ebfe9ccaff89de2120578164f86a5d17d5a576d1e5b2", size = 44719, upload-time = "2026-01-26T02:46:11.146Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/ee/74525ebe3eb5fddcd6735fc03cbea3feeed4122b53bc798ac32d297ac9ae/multidict-6.7.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:65573858d27cdeaca41893185677dc82395159aa28875a8867af66532d413a8f", size = 77107, upload-time = "2026-01-26T02:46:12.608Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/9a/ce8744e777a74b3050b1bf56be3eed1053b3457302ea055f1ea437200a23/multidict-6.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c524c6fb8fc342793708ab111c4dbc90ff9abd568de220432500e47e990c0358", size = 44943, upload-time = "2026-01-26T02:46:14.016Z" },
+ { url = "https://files.pythonhosted.org/packages/83/9c/1d2a283d9c6f31e260cb6c2fccadc3edcf6c4c14ee0929cd2af4d2606dd7/multidict-6.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:aa23b001d968faef416ff70dc0f1ab045517b9b42a90edd3e9bcdb06479e31d5", size = 44603, upload-time = "2026-01-26T02:46:15.391Z" },
+ { url = "https://files.pythonhosted.org/packages/87/9d/3b186201671583d8e8d6d79c07481a5aafd0ba7575e3d8566baec80c1e82/multidict-6.7.1-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6704fa2b7453b2fb121740555fa1ee20cd98c4d011120caf4d2b8d4e7c76eec0", size = 240573, upload-time = "2026-01-26T02:46:16.783Z" },
+ { url = "https://files.pythonhosted.org/packages/42/7d/a52f5d4d0754311d1ac78478e34dff88de71259a8585e05ee14e5f877caf/multidict-6.7.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:121a34e5bfa410cdf2c8c49716de160de3b1dbcd86b49656f5681e4543bcd1a8", size = 240106, upload-time = "2026-01-26T02:46:18.432Z" },
+ { url = "https://files.pythonhosted.org/packages/84/9f/d80118e6c30ff55b7d171bdc5520aad4b9626e657520b8d7c8ca8c2fad12/multidict-6.7.1-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:026d264228bcd637d4e060844e39cdc60f86c479e463d49075dedc21b18fbbe0", size = 219418, upload-time = "2026-01-26T02:46:20.526Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/bd/896e60b3457f194de77c7de64f9acce9f75da0518a5230ce1df534f6747b/multidict-6.7.1-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0e697826df7eb63418ee190fd06ce9f1803593bb4b9517d08c60d9b9a7f69d8f", size = 252124, upload-time = "2026-01-26T02:46:22.157Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/de/ba6b30447c36a37078d0ba604aa12c1a52887af0c355236ca6e0a9d5286f/multidict-6.7.1-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bb08271280173720e9fea9ede98e5231defcbad90f1624bea26f32ec8a956e2f", size = 249402, upload-time = "2026-01-26T02:46:23.718Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/b2/50a383c96230e432895a2fd3bcfe1b65785899598259d871d5de6b93180c/multidict-6.7.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c6b3228e1d80af737b72925ce5fb4daf5a335e49cd7ab77ed7b9fdfbf58c526e", size = 240346, upload-time = "2026-01-26T02:46:25.393Z" },
+ { url = "https://files.pythonhosted.org/packages/89/37/16d391fd8da544b1489306e38a46785fa41dd0f0ef766837ed7d4676dde0/multidict-6.7.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3943debf0fbb57bdde5901695c11094a9a36723e5c03875f87718ee15ca2f4d2", size = 237010, upload-time = "2026-01-26T02:46:27.408Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/24/3152ee026eda86d5d3e3685182911e6951af7a016579da931080ce6ac9ad/multidict-6.7.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:98c5787b0a0d9a41d9311eae44c3b76e6753def8d8870ab501320efe75a6a5f8", size = 232018, upload-time = "2026-01-26T02:46:29.941Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/1f/48d3c27a72be7fd23a55d8847193c459959bf35a5bb5844530dab00b739b/multidict-6.7.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:08ccb2a6dc72009093ebe7f3f073e5ec5964cba9a706fa94b1a1484039b87941", size = 241498, upload-time = "2026-01-26T02:46:32.052Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/45/413643ae2952d0decdf6c1250f86d08a43e143271441e81027e38d598bd7/multidict-6.7.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb351f72c26dc9abe338ca7294661aa22969ad8ffe7ef7d5541d19f368dc854a", size = 247957, upload-time = "2026-01-26T02:46:33.666Z" },
+ { url = "https://files.pythonhosted.org/packages/50/f8/f1d0ac23df15e0470776388bdb261506f63af1f81d28bacb5e262d6e12b6/multidict-6.7.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ac1c665bad8b5d762f5f85ebe4d94130c26965f11de70c708c75671297c776de", size = 241651, upload-time = "2026-01-26T02:46:35.7Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/c9/1a2a18f383cf129add66b6c36b75c3911a7ba95cf26cb141482de085cc12/multidict-6.7.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fa6609d0364f4f6f58351b4659a1f3e0e898ba2a8c5cac04cb2c7bc556b0bc5", size = 236371, upload-time = "2026-01-26T02:46:37.37Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/aa/77d87e3fca31325b87e0eb72d5fe9a7472dcb51391a42df7ac1f3842f6c0/multidict-6.7.1-cp39-cp39-win32.whl", hash = "sha256:6f77ce314a29263e67adadc7e7c1bc699fcb3a305059ab973d038f87caa42ed0", size = 41426, upload-time = "2026-01-26T02:46:39.026Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/b3/e8863e6a2da15a9d7e98976ff402e871b7352c76566df6c18d0378e0d9cf/multidict-6.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:f537b55778cd3cbee430abe3131255d3a78202e0f9ea7ffc6ada893a4bcaeea4", size = 46180, upload-time = "2026-01-26T02:46:40.422Z" },
+ { url = "https://files.pythonhosted.org/packages/93/d3/dd4fa951ad5b5fa216bf30054d705683d13405eea7459833d78f31b74c9c/multidict-6.7.1-cp39-cp39-win_arm64.whl", hash = "sha256:749aa54f578f2e5f439538706a475aa844bfa8ef75854b1401e6e528e4937cf9", size = 43231, upload-time = "2026-01-26T02:46:41.945Z" },
+ { url = "https://files.pythonhosted.org/packages/81/08/7036c080d7117f28a4af526d794aab6a84463126db031b007717c1a6676e/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56", size = 12319, upload-time = "2026-01-26T02:46:44.004Z" },
+]
+
+[[package]]
+name = "mypy"
+version = "1.19.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "librt", marker = "platform_python_implementation != 'PyPy'" },
+ { name = "mypy-extensions" },
+ { name = "pathspec" },
+ { name = "tomli", marker = "python_full_version < '3.11'" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/f5/db/4efed9504bc01309ab9c2da7e352cc223569f05478012b5d9ece38fd44d2/mypy-1.19.1.tar.gz", hash = "sha256:19d88bb05303fe63f71dd2c6270daca27cb9401c4ca8255fe50d1d920e0eb9ba", size = 3582404, upload-time = "2025-12-15T05:03:48.42Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2f/63/e499890d8e39b1ff2df4c0c6ce5d371b6844ee22b8250687a99fd2f657a8/mypy-1.19.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f05aa3d375b385734388e844bc01733bd33c644ab48e9684faa54e5389775ec", size = 13101333, upload-time = "2025-12-15T05:03:03.28Z" },
+ { url = "https://files.pythonhosted.org/packages/72/4b/095626fc136fba96effc4fd4a82b41d688ab92124f8c4f7564bffe5cf1b0/mypy-1.19.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:022ea7279374af1a5d78dfcab853fe6a536eebfda4b59deab53cd21f6cd9f00b", size = 12164102, upload-time = "2025-12-15T05:02:33.611Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/5b/952928dd081bf88a83a5ccd49aaecfcd18fd0d2710c7ff07b8fb6f7032b9/mypy-1.19.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee4c11e460685c3e0c64a4c5de82ae143622410950d6be863303a1c4ba0e36d6", size = 12765799, upload-time = "2025-12-15T05:03:28.44Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/0d/93c2e4a287f74ef11a66fb6d49c7a9f05e47b0a4399040e6719b57f500d2/mypy-1.19.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de759aafbae8763283b2ee5869c7255391fbc4de3ff171f8f030b5ec48381b74", size = 13522149, upload-time = "2025-12-15T05:02:36.011Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/0e/33a294b56aaad2b338d203e3a1d8b453637ac36cb278b45005e0901cf148/mypy-1.19.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ab43590f9cd5108f41aacf9fca31841142c786827a74ab7cc8a2eacb634e09a1", size = 13810105, upload-time = "2025-12-15T05:02:40.327Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/fd/3e82603a0cb66b67c5e7abababce6bf1a929ddf67bf445e652684af5c5a0/mypy-1.19.1-cp310-cp310-win_amd64.whl", hash = "sha256:2899753e2f61e571b3971747e302d5f420c3fd09650e1951e99f823bc3089dac", size = 10057200, upload-time = "2025-12-15T05:02:51.012Z" },
+ { url = "https://files.pythonhosted.org/packages/ef/47/6b3ebabd5474d9cdc170d1342fbf9dddc1b0ec13ec90bf9004ee6f391c31/mypy-1.19.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d8dfc6ab58ca7dda47d9237349157500468e404b17213d44fc1cb77bce532288", size = 13028539, upload-time = "2025-12-15T05:03:44.129Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/a6/ac7c7a88a3c9c54334f53a941b765e6ec6c4ebd65d3fe8cdcfbe0d0fd7db/mypy-1.19.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e3f276d8493c3c97930e354b2595a44a21348b320d859fb4a2b9f66da9ed27ab", size = 12083163, upload-time = "2025-12-15T05:03:37.679Z" },
+ { url = "https://files.pythonhosted.org/packages/67/af/3afa9cf880aa4a2c803798ac24f1d11ef72a0c8079689fac5cfd815e2830/mypy-1.19.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2abb24cf3f17864770d18d673c85235ba52456b36a06b6afc1e07c1fdcd3d0e6", size = 12687629, upload-time = "2025-12-15T05:02:31.526Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/46/20f8a7114a56484ab268b0ab372461cb3a8f7deed31ea96b83a4e4cfcfca/mypy-1.19.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a009ffa5a621762d0c926a078c2d639104becab69e79538a494bcccb62cc0331", size = 13436933, upload-time = "2025-12-15T05:03:15.606Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/f8/33b291ea85050a21f15da910002460f1f445f8007adb29230f0adea279cb/mypy-1.19.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f7cee03c9a2e2ee26ec07479f38ea9c884e301d42c6d43a19d20fb014e3ba925", size = 13661754, upload-time = "2025-12-15T05:02:26.731Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/a3/47cbd4e85bec4335a9cd80cf67dbc02be21b5d4c9c23ad6b95d6c5196bac/mypy-1.19.1-cp311-cp311-win_amd64.whl", hash = "sha256:4b84a7a18f41e167f7995200a1d07a4a6810e89d29859df936f1c3923d263042", size = 10055772, upload-time = "2025-12-15T05:03:26.179Z" },
+ { url = "https://files.pythonhosted.org/packages/06/8a/19bfae96f6615aa8a0604915512e0289b1fad33d5909bf7244f02935d33a/mypy-1.19.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a8174a03289288c1f6c46d55cef02379b478bfbc8e358e02047487cad44c6ca1", size = 13206053, upload-time = "2025-12-15T05:03:46.622Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/34/3e63879ab041602154ba2a9f99817bb0c85c4df19a23a1443c8986e4d565/mypy-1.19.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffcebe56eb09ff0c0885e750036a095e23793ba6c2e894e7e63f6d89ad51f22e", size = 12219134, upload-time = "2025-12-15T05:03:24.367Z" },
+ { url = "https://files.pythonhosted.org/packages/89/cc/2db6f0e95366b630364e09845672dbee0cbf0bbe753a204b29a944967cd9/mypy-1.19.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b64d987153888790bcdb03a6473d321820597ab8dd9243b27a92153c4fa50fd2", size = 12731616, upload-time = "2025-12-15T05:02:44.725Z" },
+ { url = "https://files.pythonhosted.org/packages/00/be/dd56c1fd4807bc1eba1cf18b2a850d0de7bacb55e158755eb79f77c41f8e/mypy-1.19.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c35d298c2c4bba75feb2195655dfea8124d855dfd7343bf8b8c055421eaf0cf8", size = 13620847, upload-time = "2025-12-15T05:03:39.633Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/42/332951aae42b79329f743bf1da088cd75d8d4d9acc18fbcbd84f26c1af4e/mypy-1.19.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:34c81968774648ab5ac09c29a375fdede03ba253f8f8287847bd480782f73a6a", size = 13834976, upload-time = "2025-12-15T05:03:08.786Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/63/e7493e5f90e1e085c562bb06e2eb32cae27c5057b9653348d38b47daaecc/mypy-1.19.1-cp312-cp312-win_amd64.whl", hash = "sha256:b10e7c2cd7870ba4ad9b2d8a6102eb5ffc1f16ca35e3de6bfa390c1113029d13", size = 10118104, upload-time = "2025-12-15T05:03:10.834Z" },
+ { url = "https://files.pythonhosted.org/packages/de/9f/a6abae693f7a0c697dbb435aac52e958dc8da44e92e08ba88d2e42326176/mypy-1.19.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e3157c7594ff2ef1634ee058aafc56a82db665c9438fd41b390f3bde1ab12250", size = 13201927, upload-time = "2025-12-15T05:02:29.138Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/a4/45c35ccf6e1c65afc23a069f50e2c66f46bd3798cbe0d680c12d12935caa/mypy-1.19.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdb12f69bcc02700c2b47e070238f42cb87f18c0bc1fc4cdb4fb2bc5fd7a3b8b", size = 12206730, upload-time = "2025-12-15T05:03:01.325Z" },
+ { url = "https://files.pythonhosted.org/packages/05/bb/cdcf89678e26b187650512620eec8368fded4cfd99cfcb431e4cdfd19dec/mypy-1.19.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f859fb09d9583a985be9a493d5cfc5515b56b08f7447759a0c5deaf68d80506e", size = 12724581, upload-time = "2025-12-15T05:03:20.087Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/32/dd260d52babf67bad8e6770f8e1102021877ce0edea106e72df5626bb0ec/mypy-1.19.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9a6538e0415310aad77cb94004ca6482330fece18036b5f360b62c45814c4ef", size = 13616252, upload-time = "2025-12-15T05:02:49.036Z" },
+ { url = "https://files.pythonhosted.org/packages/71/d0/5e60a9d2e3bd48432ae2b454b7ef2b62a960ab51292b1eda2a95edd78198/mypy-1.19.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:da4869fc5e7f62a88f3fe0b5c919d1d9f7ea3cef92d3689de2823fd27e40aa75", size = 13840848, upload-time = "2025-12-15T05:02:55.95Z" },
+ { url = "https://files.pythonhosted.org/packages/98/76/d32051fa65ecf6cc8c6610956473abdc9b4c43301107476ac03559507843/mypy-1.19.1-cp313-cp313-win_amd64.whl", hash = "sha256:016f2246209095e8eda7538944daa1d60e1e8134d98983b9fc1e92c1fc0cb8dd", size = 10135510, upload-time = "2025-12-15T05:02:58.438Z" },
+ { url = "https://files.pythonhosted.org/packages/de/eb/b83e75f4c820c4247a58580ef86fcd35165028f191e7e1ba57128c52782d/mypy-1.19.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:06e6170bd5836770e8104c8fdd58e5e725cfeb309f0a6c681a811f557e97eac1", size = 13199744, upload-time = "2025-12-15T05:03:30.823Z" },
+ { url = "https://files.pythonhosted.org/packages/94/28/52785ab7bfa165f87fcbb61547a93f98bb20e7f82f90f165a1f69bce7b3d/mypy-1.19.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:804bd67b8054a85447c8954215a906d6eff9cabeabe493fb6334b24f4bfff718", size = 12215815, upload-time = "2025-12-15T05:02:42.323Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/c6/bdd60774a0dbfb05122e3e925f2e9e846c009e479dcec4821dad881f5b52/mypy-1.19.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:21761006a7f497cb0d4de3d8ef4ca70532256688b0523eee02baf9eec895e27b", size = 12740047, upload-time = "2025-12-15T05:03:33.168Z" },
+ { url = "https://files.pythonhosted.org/packages/32/2a/66ba933fe6c76bd40d1fe916a83f04fed253152f451a877520b3c4a5e41e/mypy-1.19.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:28902ee51f12e0f19e1e16fbe2f8f06b6637f482c459dd393efddd0ec7f82045", size = 13601998, upload-time = "2025-12-15T05:03:13.056Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/da/5055c63e377c5c2418760411fd6a63ee2b96cf95397259038756c042574f/mypy-1.19.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:481daf36a4c443332e2ae9c137dfee878fcea781a2e3f895d54bd3002a900957", size = 13807476, upload-time = "2025-12-15T05:03:17.977Z" },
+ { url = "https://files.pythonhosted.org/packages/cd/09/4ebd873390a063176f06b0dbf1f7783dd87bd120eae7727fa4ae4179b685/mypy-1.19.1-cp314-cp314-win_amd64.whl", hash = "sha256:8bb5c6f6d043655e055be9b542aa5f3bdd30e4f3589163e85f93f3640060509f", size = 10281872, upload-time = "2025-12-15T05:03:05.549Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/f7/88436084550ca9af5e610fa45286be04c3b63374df3e021c762fe8c4369f/mypy-1.19.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7bcfc336a03a1aaa26dfce9fff3e287a3ba99872a157561cbfcebe67c13308e3", size = 13102606, upload-time = "2025-12-15T05:02:46.833Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/a5/43dfad311a734b48a752790571fd9e12d61893849a01bff346a54011957f/mypy-1.19.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b7951a701c07ea584c4fe327834b92a30825514c868b1f69c30445093fdd9d5a", size = 12164496, upload-time = "2025-12-15T05:03:41.947Z" },
+ { url = "https://files.pythonhosted.org/packages/88/f0/efbfa391395cce2f2771f937e0620cfd185ec88f2b9cd88711028a768e96/mypy-1.19.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b13cfdd6c87fc3efb69ea4ec18ef79c74c3f98b4e5498ca9b85ab3b2c2329a67", size = 12772068, upload-time = "2025-12-15T05:02:53.689Z" },
+ { url = "https://files.pythonhosted.org/packages/25/05/58b3ba28f5aed10479e899a12d2120d582ba9fa6288851b20bf1c32cbb4f/mypy-1.19.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f28f99c824ecebcdaa2e55d82953e38ff60ee5ec938476796636b86afa3956e", size = 13520385, upload-time = "2025-12-15T05:02:38.328Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/a0/c006ccaff50b31e542ae69b92fe7e2f55d99fba3a55e01067dd564325f85/mypy-1.19.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c608937067d2fc5a4dd1a5ce92fd9e1398691b8c5d012d66e1ddd430e9244376", size = 13796221, upload-time = "2025-12-15T05:03:22.147Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/ff/8bdb051cd710f01b880472241bd36b3f817a8e1c5d5540d0b761675b6de2/mypy-1.19.1-cp39-cp39-win_amd64.whl", hash = "sha256:409088884802d511ee52ca067707b90c883426bd95514e8cfda8281dc2effe24", size = 10055456, upload-time = "2025-12-15T05:03:35.169Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/f4/4ce9a05ce5ded1de3ec1c1d96cf9f9504a04e54ce0ed55cfa38619a32b8d/mypy-1.19.1-py3-none-any.whl", hash = "sha256:f1235f5ea01b7db5468d53ece6aaddf1ad0b88d9e7462b86ef96fe04995d7247", size = 2471239, upload-time = "2025-12-15T05:03:07.248Z" },
+]
+
+[[package]]
+name = "mypy-extensions"
+version = "1.1.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" },
+]
+
+[[package]]
+name = "nh3"
+version = "0.3.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/cc/37/ab55eb2b05e334ff9a1ad52c556ace1f9c20a3f63613a165d384d5387657/nh3-0.3.3.tar.gz", hash = "sha256:185ed41b88c910b9ca8edc89ca3b4be688a12cb9de129d84befa2f74a0039fee", size = 18968, upload-time = "2026-02-14T09:35:15.664Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e7/a4/834f0ebd80844ce67e1bdb011d6f844f61cdb4c1d7cdc56a982bc054cc00/nh3-0.3.3-cp314-cp314t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:21b058cd20d9f0919421a820a2843fdb5e1749c0bf57a6247ab8f4ba6723c9fc", size = 1428680, upload-time = "2026-02-14T09:34:33.015Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/1a/a7d72e750f74c6b71befbeebc4489579fe783466889d41f32e34acde0b6b/nh3-0.3.3-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4400a73c2a62859e769f9d36d1b5a7a5c65c4179d1dddd2f6f3095b2db0cbfc", size = 799003, upload-time = "2026-02-14T09:34:35.108Z" },
+ { url = "https://files.pythonhosted.org/packages/58/d5/089eb6d65da139dc2223b83b2627e00872eccb5e1afdf5b1d76eb6ad3fcc/nh3-0.3.3-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1ef87f8e916321a88b45f2d597f29bd56e560ed4568a50f0f1305afab86b7189", size = 846818, upload-time = "2026-02-14T09:34:37Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/c6/44a0b65fc7b213a3a725f041ef986534b100e58cd1a2e00f0fd3c9603893/nh3-0.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a446eae598987f49ee97ac2f18eafcce4e62e7574bd1eb23782e4702e54e217d", size = 1012537, upload-time = "2026-02-14T09:34:38.515Z" },
+ { url = "https://files.pythonhosted.org/packages/94/3a/91bcfcc0a61b286b8b25d39e288b9c0ba91c3290d402867d1cd705169844/nh3-0.3.3-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:0d5eb734a78ac364af1797fef718340a373f626a9ff6b4fb0b4badf7927e7b81", size = 1095435, upload-time = "2026-02-14T09:34:40.022Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/fd/4617a19d80cf9f958e65724ff5e97bc2f76f2f4c5194c740016606c87bd1/nh3-0.3.3-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:92a958e6f6d0100e025a5686aafd67e3c98eac67495728f8bb64fbeb3e474493", size = 1056344, upload-time = "2026-02-14T09:34:41.469Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/7d/5bcbbc56e71b7dda7ef1d6008098da9c5426d6334137ef32bb2b9c496984/nh3-0.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9ed40cf8449a59a03aa465114fedce1ff7ac52561688811d047917cc878b19ca", size = 1034533, upload-time = "2026-02-14T09:34:43.313Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/9c/054eff8a59a8b23b37f0f4ac84cdd688ee84cf5251664c0e14e5d30a8a67/nh3-0.3.3-cp314-cp314t-win32.whl", hash = "sha256:b50c3770299fb2a7c1113751501e8878d525d15160a4c05194d7fe62b758aad8", size = 608305, upload-time = "2026-02-14T09:34:44.622Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/b0/64667b8d522c7b859717a02b1a66ba03b529ca1df623964e598af8db1ed5/nh3-0.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:21a63ccb18ddad3f784bb775955839b8b80e347e597726f01e43ca1abcc5c808", size = 620633, upload-time = "2026-02-14T09:34:46.069Z" },
+ { url = "https://files.pythonhosted.org/packages/91/b5/ae9909e4ddfd86ee076c4d6d62ba69e9b31061da9d2f722936c52df8d556/nh3-0.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:f508ddd4e2433fdcb78c790fc2d24e3a349ba775e5fa904af89891321d4844a3", size = 607027, upload-time = "2026-02-14T09:34:47.91Z" },
+ { url = "https://files.pythonhosted.org/packages/13/3e/aef8cf8e0419b530c95e96ae93a5078e9b36c1e6613eeb1df03a80d5194e/nh3-0.3.3-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e8ee96156f7dfc6e30ecda650e480c5ae0a7d38f0c6fafc3c1c655e2500421d9", size = 1448640, upload-time = "2026-02-14T09:34:49.316Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/43/d2011a4f6c0272cb122eeff40062ee06bb2b6e57eabc3a5e057df0d582df/nh3-0.3.3-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45fe0d6a607264910daec30360c8a3b5b1500fd832d21b2da608256287bcb92d", size = 839405, upload-time = "2026-02-14T09:34:50.779Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/f3/965048510c1caf2a34ed04411a46a04a06eb05563cd06f1aa57b71eb2bc8/nh3-0.3.3-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5bc1d4b30ba1ba896669d944b6003630592665974bd11a3dc2f661bde92798a7", size = 825849, upload-time = "2026-02-14T09:34:52.622Z" },
+ { url = "https://files.pythonhosted.org/packages/78/99/b4bbc6ad16329d8db2c2c320423f00b549ca3b129c2b2f9136be2606dbb0/nh3-0.3.3-cp38-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:f433a2dd66545aad4a720ad1b2150edcdca75bfff6f4e6f378ade1ec138d5e77", size = 1068303, upload-time = "2026-02-14T09:34:54.179Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/34/3420d97065aab1b35f3e93ce9c96c8ebd423ce86fe84dee3126790421a2a/nh3-0.3.3-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52e973cb742e95b9ae1b35822ce23992428750f4b46b619fe86eba4205255b30", size = 1029316, upload-time = "2026-02-14T09:34:56.186Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/9a/99eda757b14e596fdb2ca5f599a849d9554181aa899274d0d183faef4493/nh3-0.3.3-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4c730617bdc15d7092dcc0469dc2826b914c8f874996d105b4bc3842a41c1cd9", size = 919944, upload-time = "2026-02-14T09:34:57.886Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/84/c0dc75c7fb596135f999e59a410d9f45bdabb989f1cb911f0016d22b747b/nh3-0.3.3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e98fa3dbfd54e25487e36ba500bc29bca3a4cab4ffba18cfb1a35a2d02624297", size = 811461, upload-time = "2026-02-14T09:34:59.65Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/ec/b1bf57cab6230eec910e4863528dc51dcf21b57aaf7c88ee9190d62c9185/nh3-0.3.3-cp38-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:3a62b8ae7c235481715055222e54c682422d0495a5c73326807d4e44c5d14691", size = 840360, upload-time = "2026-02-14T09:35:01.444Z" },
+ { url = "https://files.pythonhosted.org/packages/37/5e/326ae34e904dde09af1de51219a611ae914111f0970f2f111f4f0188f57e/nh3-0.3.3-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fc305a2264868ec8fa16548296f803d8fd9c1fa66cd28b88b605b1bd06667c0b", size = 859872, upload-time = "2026-02-14T09:35:03.348Z" },
+ { url = "https://files.pythonhosted.org/packages/09/38/7eba529ce17ab4d3790205da37deabb4cb6edcba15f27b8562e467f2fc97/nh3-0.3.3-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:90126a834c18af03bfd6ff9a027bfa6bbf0e238527bc780a24de6bd7cc1041e2", size = 1023550, upload-time = "2026-02-14T09:35:04.829Z" },
+ { url = "https://files.pythonhosted.org/packages/05/a2/556fdecd37c3681b1edee2cf795a6799c6ed0a5551b2822636960d7e7651/nh3-0.3.3-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:24769a428e9e971e4ccfb24628f83aaa7dc3c8b41b130c8ddc1835fa1c924489", size = 1105212, upload-time = "2026-02-14T09:35:06.821Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/e3/5db0b0ad663234967d83702277094687baf7c498831a2d3ad3451c11770f/nh3-0.3.3-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:b7a18ee057761e455d58b9d31445c3e4b2594cff4ddb84d2e331c011ef46f462", size = 1069970, upload-time = "2026-02-14T09:35:08.504Z" },
+ { url = "https://files.pythonhosted.org/packages/79/b2/2ea21b79c6e869581ce5f51549b6e185c4762233591455bf2a326fb07f3b/nh3-0.3.3-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5a4b2c1f3e6f3cbe7048e17f4fefad3f8d3e14cc0fd08fb8599e0d5653f6b181", size = 1047588, upload-time = "2026-02-14T09:35:09.911Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/92/2e434619e658c806d9c096eed2cdff9a883084299b7b19a3f0824eb8e63d/nh3-0.3.3-cp38-abi3-win32.whl", hash = "sha256:e974850b131fdffa75e7ad8e0d9c7a855b96227b093417fdf1bd61656e530f37", size = 616179, upload-time = "2026-02-14T09:35:11.366Z" },
+ { url = "https://files.pythonhosted.org/packages/73/88/1ce287ef8649dc51365b5094bd3713b76454838140a32ab4f8349973883c/nh3-0.3.3-cp38-abi3-win_amd64.whl", hash = "sha256:2efd17c0355d04d39e6d79122b42662277ac10a17ea48831d90b46e5ef7e4fc0", size = 631159, upload-time = "2026-02-14T09:35:12.77Z" },
+ { url = "https://files.pythonhosted.org/packages/31/f1/b4835dbde4fb06f29db89db027576d6014081cd278d9b6751facc3e69e43/nh3-0.3.3-cp38-abi3-win_arm64.whl", hash = "sha256:b838e619f483531483d26d889438e53a880510e832d2aafe73f93b7b1ac2bce2", size = 616645, upload-time = "2026-02-14T09:35:14.062Z" },
+]
+
+[[package]]
+name = "numpy"
+version = "2.0.2"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version < '3.10'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a9/75/10dd1f8116a8b796cb2c737b674e02d02e80454bda953fa7e65d8c12b016/numpy-2.0.2.tar.gz", hash = "sha256:883c987dee1880e2a864ab0dc9892292582510604156762362d9326444636e78", size = 18902015, upload-time = "2024-08-26T20:19:40.945Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/21/91/3495b3237510f79f5d81f2508f9f13fea78ebfdf07538fc7444badda173d/numpy-2.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:51129a29dbe56f9ca83438b706e2e69a39892b5eda6cedcb6b0c9fdc9b0d3ece", size = 21165245, upload-time = "2024-08-26T20:04:14.625Z" },
+ { url = "https://files.pythonhosted.org/packages/05/33/26178c7d437a87082d11019292dce6d3fe6f0e9026b7b2309cbf3e489b1d/numpy-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f15975dfec0cf2239224d80e32c3170b1d168335eaedee69da84fbe9f1f9cd04", size = 13738540, upload-time = "2024-08-26T20:04:36.784Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/31/cc46e13bf07644efc7a4bf68df2df5fb2a1a88d0cd0da9ddc84dc0033e51/numpy-2.0.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:8c5713284ce4e282544c68d1c3b2c7161d38c256d2eefc93c1d683cf47683e66", size = 5300623, upload-time = "2024-08-26T20:04:46.491Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/16/7bfcebf27bb4f9d7ec67332ffebee4d1bf085c84246552d52dbb548600e7/numpy-2.0.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:becfae3ddd30736fe1889a37f1f580e245ba79a5855bff5f2a29cb3ccc22dd7b", size = 6901774, upload-time = "2024-08-26T20:04:58.173Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/a3/561c531c0e8bf082c5bef509d00d56f82e0ea7e1e3e3a7fc8fa78742a6e5/numpy-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2da5960c3cf0df7eafefd806d4e612c5e19358de82cb3c343631188991566ccd", size = 13907081, upload-time = "2024-08-26T20:05:19.098Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/66/f7177ab331876200ac7563a580140643d1179c8b4b6a6b0fc9838de2a9b8/numpy-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:496f71341824ed9f3d2fd36cf3ac57ae2e0165c143b55c3a035ee219413f3318", size = 19523451, upload-time = "2024-08-26T20:05:47.479Z" },
+ { url = "https://files.pythonhosted.org/packages/25/7f/0b209498009ad6453e4efc2c65bcdf0ae08a182b2b7877d7ab38a92dc542/numpy-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a61ec659f68ae254e4d237816e33171497e978140353c0c2038d46e63282d0c8", size = 19927572, upload-time = "2024-08-26T20:06:17.137Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/df/2619393b1e1b565cd2d4c4403bdd979621e2c4dea1f8532754b2598ed63b/numpy-2.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d731a1c6116ba289c1e9ee714b08a8ff882944d4ad631fd411106a30f083c326", size = 14400722, upload-time = "2024-08-26T20:06:39.16Z" },
+ { url = "https://files.pythonhosted.org/packages/22/ad/77e921b9f256d5da36424ffb711ae79ca3f451ff8489eeca544d0701d74a/numpy-2.0.2-cp310-cp310-win32.whl", hash = "sha256:984d96121c9f9616cd33fbd0618b7f08e0cfc9600a7ee1d6fd9b239186d19d97", size = 6472170, upload-time = "2024-08-26T20:06:50.361Z" },
+ { url = "https://files.pythonhosted.org/packages/10/05/3442317535028bc29cf0c0dd4c191a4481e8376e9f0db6bcf29703cadae6/numpy-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:c7b0be4ef08607dd04da4092faee0b86607f111d5ae68036f16cc787e250a131", size = 15905558, upload-time = "2024-08-26T20:07:13.881Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/cf/034500fb83041aa0286e0fb16e7c76e5c8b67c0711bb6e9e9737a717d5fe/numpy-2.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:49ca4decb342d66018b01932139c0961a8f9ddc7589611158cb3c27cbcf76448", size = 21169137, upload-time = "2024-08-26T20:07:45.345Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/d9/32de45561811a4b87fbdee23b5797394e3d1504b4a7cf40c10199848893e/numpy-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:11a76c372d1d37437857280aa142086476136a8c0f373b2e648ab2c8f18fb195", size = 13703552, upload-time = "2024-08-26T20:08:06.666Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/ca/2f384720020c7b244d22508cb7ab23d95f179fcfff33c31a6eeba8d6c512/numpy-2.0.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:807ec44583fd708a21d4a11d94aedf2f4f3c3719035c76a2bbe1fe8e217bdc57", size = 5298957, upload-time = "2024-08-26T20:08:15.83Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/78/a3e4f9fb6aa4e6fdca0c5428e8ba039408514388cf62d89651aade838269/numpy-2.0.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8cafab480740e22f8d833acefed5cc87ce276f4ece12fdaa2e8903db2f82897a", size = 6905573, upload-time = "2024-08-26T20:08:27.185Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/72/cfc3a1beb2caf4efc9d0b38a15fe34025230da27e1c08cc2eb9bfb1c7231/numpy-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a15f476a45e6e5a3a79d8a14e62161d27ad897381fecfa4a09ed5322f2085669", size = 13914330, upload-time = "2024-08-26T20:08:48.058Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/a8/c17acf65a931ce551fee11b72e8de63bf7e8a6f0e21add4c937c83563538/numpy-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13e689d772146140a252c3a28501da66dfecd77490b498b168b501835041f951", size = 19534895, upload-time = "2024-08-26T20:09:16.536Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/86/8767f3d54f6ae0165749f84648da9dcc8cd78ab65d415494962c86fac80f/numpy-2.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9ea91dfb7c3d1c56a0e55657c0afb38cf1eeae4544c208dc465c3c9f3a7c09f9", size = 19937253, upload-time = "2024-08-26T20:09:46.263Z" },
+ { url = "https://files.pythonhosted.org/packages/df/87/f76450e6e1c14e5bb1eae6836478b1028e096fd02e85c1c37674606ab752/numpy-2.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c1c9307701fec8f3f7a1e6711f9089c06e6284b3afbbcd259f7791282d660a15", size = 14414074, upload-time = "2024-08-26T20:10:08.483Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/ca/0f0f328e1e59f73754f06e1adfb909de43726d4f24c6a3f8805f34f2b0fa/numpy-2.0.2-cp311-cp311-win32.whl", hash = "sha256:a392a68bd329eafac5817e5aefeb39038c48b671afd242710b451e76090e81f4", size = 6470640, upload-time = "2024-08-26T20:10:19.732Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/57/3a3f14d3a759dcf9bf6e9eda905794726b758819df4663f217d658a58695/numpy-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:286cd40ce2b7d652a6f22efdfc6d1edf879440e53e76a75955bc0c826c7e64dc", size = 15910230, upload-time = "2024-08-26T20:10:43.413Z" },
+ { url = "https://files.pythonhosted.org/packages/45/40/2e117be60ec50d98fa08c2f8c48e09b3edea93cfcabd5a9ff6925d54b1c2/numpy-2.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:df55d490dea7934f330006d0f81e8551ba6010a5bf035a249ef61a94f21c500b", size = 20895803, upload-time = "2024-08-26T20:11:13.916Z" },
+ { url = "https://files.pythonhosted.org/packages/46/92/1b8b8dee833f53cef3e0a3f69b2374467789e0bb7399689582314df02651/numpy-2.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8df823f570d9adf0978347d1f926b2a867d5608f434a7cff7f7908c6570dcf5e", size = 13471835, upload-time = "2024-08-26T20:11:34.779Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/19/e2793bde475f1edaea6945be141aef6c8b4c669b90c90a300a8954d08f0a/numpy-2.0.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9a92ae5c14811e390f3767053ff54eaee3bf84576d99a2456391401323f4ec2c", size = 5038499, upload-time = "2024-08-26T20:11:43.902Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/ff/ddf6dac2ff0dd50a7327bcdba45cb0264d0e96bb44d33324853f781a8f3c/numpy-2.0.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:a842d573724391493a97a62ebbb8e731f8a5dcc5d285dfc99141ca15a3302d0c", size = 6633497, upload-time = "2024-08-26T20:11:55.09Z" },
+ { url = "https://files.pythonhosted.org/packages/72/21/67f36eac8e2d2cd652a2e69595a54128297cdcb1ff3931cfc87838874bd4/numpy-2.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05e238064fc0610c840d1cf6a13bf63d7e391717d247f1bf0318172e759e692", size = 13621158, upload-time = "2024-08-26T20:12:14.95Z" },
+ { url = "https://files.pythonhosted.org/packages/39/68/e9f1126d757653496dbc096cb429014347a36b228f5a991dae2c6b6cfd40/numpy-2.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0123ffdaa88fa4ab64835dcbde75dcdf89c453c922f18dced6e27c90d1d0ec5a", size = 19236173, upload-time = "2024-08-26T20:12:44.049Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/e9/1f5333281e4ebf483ba1c888b1d61ba7e78d7e910fdd8e6499667041cc35/numpy-2.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:96a55f64139912d61de9137f11bf39a55ec8faec288c75a54f93dfd39f7eb40c", size = 19634174, upload-time = "2024-08-26T20:13:13.634Z" },
+ { url = "https://files.pythonhosted.org/packages/71/af/a469674070c8d8408384e3012e064299f7a2de540738a8e414dcfd639996/numpy-2.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec9852fb39354b5a45a80bdab5ac02dd02b15f44b3804e9f00c556bf24b4bded", size = 14099701, upload-time = "2024-08-26T20:13:34.851Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/3d/08ea9f239d0e0e939b6ca52ad403c84a2bce1bde301a8eb4888c1c1543f1/numpy-2.0.2-cp312-cp312-win32.whl", hash = "sha256:671bec6496f83202ed2d3c8fdc486a8fc86942f2e69ff0e986140339a63bcbe5", size = 6174313, upload-time = "2024-08-26T20:13:45.653Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/b5/4ac39baebf1fdb2e72585c8352c56d063b6126be9fc95bd2bb5ef5770c20/numpy-2.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:cfd41e13fdc257aa5778496b8caa5e856dc4896d4ccf01841daee1d96465467a", size = 15606179, upload-time = "2024-08-26T20:14:08.786Z" },
+ { url = "https://files.pythonhosted.org/packages/43/c1/41c8f6df3162b0c6ffd4437d729115704bd43363de0090c7f913cfbc2d89/numpy-2.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9059e10581ce4093f735ed23f3b9d283b9d517ff46009ddd485f1747eb22653c", size = 21169942, upload-time = "2024-08-26T20:14:40.108Z" },
+ { url = "https://files.pythonhosted.org/packages/39/bc/fd298f308dcd232b56a4031fd6ddf11c43f9917fbc937e53762f7b5a3bb1/numpy-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:423e89b23490805d2a5a96fe40ec507407b8ee786d66f7328be214f9679df6dd", size = 13711512, upload-time = "2024-08-26T20:15:00.985Z" },
+ { url = "https://files.pythonhosted.org/packages/96/ff/06d1aa3eeb1c614eda245c1ba4fb88c483bee6520d361641331872ac4b82/numpy-2.0.2-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:2b2955fa6f11907cf7a70dab0d0755159bca87755e831e47932367fc8f2f2d0b", size = 5306976, upload-time = "2024-08-26T20:15:10.876Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/98/121996dcfb10a6087a05e54453e28e58694a7db62c5a5a29cee14c6e047b/numpy-2.0.2-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:97032a27bd9d8988b9a97a8c4d2c9f2c15a81f61e2f21404d7e8ef00cb5be729", size = 6906494, upload-time = "2024-08-26T20:15:22.055Z" },
+ { url = "https://files.pythonhosted.org/packages/15/31/9dffc70da6b9bbf7968f6551967fc21156207366272c2a40b4ed6008dc9b/numpy-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e795a8be3ddbac43274f18588329c72939870a16cae810c2b73461c40718ab1", size = 13912596, upload-time = "2024-08-26T20:15:42.452Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/14/78635daab4b07c0930c919d451b8bf8c164774e6a3413aed04a6d95758ce/numpy-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b258c385842546006213344c50655ff1555a9338e2e5e02a0756dc3e803dd", size = 19526099, upload-time = "2024-08-26T20:16:11.048Z" },
+ { url = "https://files.pythonhosted.org/packages/26/4c/0eeca4614003077f68bfe7aac8b7496f04221865b3a5e7cb230c9d055afd/numpy-2.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fec9451a7789926bcf7c2b8d187292c9f93ea30284802a0ab3f5be8ab36865d", size = 19932823, upload-time = "2024-08-26T20:16:40.171Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/46/ea25b98b13dccaebddf1a803f8c748680d972e00507cd9bc6dcdb5aa2ac1/numpy-2.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9189427407d88ff25ecf8f12469d4d39d35bee1db5d39fc5c168c6f088a6956d", size = 14404424, upload-time = "2024-08-26T20:17:02.604Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/a6/177dd88d95ecf07e722d21008b1b40e681a929eb9e329684d449c36586b2/numpy-2.0.2-cp39-cp39-win32.whl", hash = "sha256:905d16e0c60200656500c95b6b8dca5d109e23cb24abc701d41c02d74c6b3afa", size = 6476809, upload-time = "2024-08-26T20:17:13.553Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/2b/7fc9f4e7ae5b507c1a3a21f0f15ed03e794c1242ea8a242ac158beb56034/numpy-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:a3f4ab0caa7f053f6797fcd4e1e25caee367db3112ef2b6ef82d749530768c73", size = 15911314, upload-time = "2024-08-26T20:17:36.72Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/3b/df5a870ac6a3be3a86856ce195ef42eec7ae50d2a202be1f5a4b3b340e14/numpy-2.0.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7f0a0c6f12e07fa94133c8a67404322845220c06a9e80e85999afe727f7438b8", size = 21025288, upload-time = "2024-08-26T20:18:07.732Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/97/51af92f18d6f6f2d9ad8b482a99fb74e142d71372da5d834b3a2747a446e/numpy-2.0.2-pp39-pypy39_pp73-macosx_14_0_x86_64.whl", hash = "sha256:312950fdd060354350ed123c0e25a71327d3711584beaef30cdaa93320c392d4", size = 6762793, upload-time = "2024-08-26T20:18:19.125Z" },
+ { url = "https://files.pythonhosted.org/packages/12/46/de1fbd0c1b5ccaa7f9a005b66761533e2f6a3e560096682683a223631fe9/numpy-2.0.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26df23238872200f63518dd2aa984cfca675d82469535dc7162dc2ee52d9dd5c", size = 19334885, upload-time = "2024-08-26T20:18:47.237Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/dc/d330a6faefd92b446ec0f0dfea4c3207bb1fef3c4771d19cf4543efd2c78/numpy-2.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a46288ec55ebbd58947d31d72be2c63cbf839f0a63b49cb755022310792a3385", size = 15828784, upload-time = "2024-08-26T20:19:11.19Z" },
+]
+
+[[package]]
+name = "numpy"
+version = "2.2.6"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version == '3.10.*'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/76/21/7d2a95e4bba9dc13d043ee156a356c0a8f0c6309dff6b21b4d71a073b8a8/numpy-2.2.6.tar.gz", hash = "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd", size = 20276440, upload-time = "2025-05-17T22:38:04.611Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9a/3e/ed6db5be21ce87955c0cbd3009f2803f59fa08df21b5df06862e2d8e2bdd/numpy-2.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb", size = 21165245, upload-time = "2025-05-17T21:27:58.555Z" },
+ { url = "https://files.pythonhosted.org/packages/22/c2/4b9221495b2a132cc9d2eb862e21d42a009f5a60e45fc44b00118c174bff/numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90", size = 14360048, upload-time = "2025-05-17T21:28:21.406Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/77/dc2fcfc66943c6410e2bf598062f5959372735ffda175b39906d54f02349/numpy-2.2.6-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:37e990a01ae6ec7fe7fa1c26c55ecb672dd98b19c3d0e1d1f326fa13cb38d163", size = 5340542, upload-time = "2025-05-17T21:28:30.931Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/4f/1cb5fdc353a5f5cc7feb692db9b8ec2c3d6405453f982435efc52561df58/numpy-2.2.6-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:5a6429d4be8ca66d889b7cf70f536a397dc45ba6faeb5f8c5427935d9592e9cf", size = 6878301, upload-time = "2025-05-17T21:28:41.613Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/17/96a3acd228cec142fcb8723bd3cc39c2a474f7dcf0a5d16731980bcafa95/numpy-2.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efd28d4e9cd7d7a8d39074a4d44c63eda73401580c5c76acda2ce969e0a38e83", size = 14297320, upload-time = "2025-05-17T21:29:02.78Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/63/3de6a34ad7ad6646ac7d2f55ebc6ad439dbbf9c4370017c50cf403fb19b5/numpy-2.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc7b73d02efb0e18c000e9ad8b83480dfcd5dfd11065997ed4c6747470ae8915", size = 16801050, upload-time = "2025-05-17T21:29:27.675Z" },
+ { url = "https://files.pythonhosted.org/packages/07/b6/89d837eddef52b3d0cec5c6ba0456c1bf1b9ef6a6672fc2b7873c3ec4e2e/numpy-2.2.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74d4531beb257d2c3f4b261bfb0fc09e0f9ebb8842d82a7b4209415896adc680", size = 15807034, upload-time = "2025-05-17T21:29:51.102Z" },
+ { url = "https://files.pythonhosted.org/packages/01/c8/dc6ae86e3c61cfec1f178e5c9f7858584049b6093f843bca541f94120920/numpy-2.2.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8fc377d995680230e83241d8a96def29f204b5782f371c532579b4f20607a289", size = 18614185, upload-time = "2025-05-17T21:30:18.703Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/c5/0064b1b7e7c89137b471ccec1fd2282fceaae0ab3a9550f2568782d80357/numpy-2.2.6-cp310-cp310-win32.whl", hash = "sha256:b093dd74e50a8cba3e873868d9e93a85b78e0daf2e98c6797566ad8044e8363d", size = 6527149, upload-time = "2025-05-17T21:30:29.788Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/dd/4b822569d6b96c39d1215dbae0582fd99954dcbcf0c1a13c61783feaca3f/numpy-2.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:f0fd6321b839904e15c46e0d257fdd101dd7f530fe03fd6359c1ea63738703f3", size = 12904620, upload-time = "2025-05-17T21:30:48.994Z" },
+ { url = "https://files.pythonhosted.org/packages/da/a8/4f83e2aa666a9fbf56d6118faaaf5f1974d456b1823fda0a176eff722839/numpy-2.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f9f1adb22318e121c5c69a09142811a201ef17ab257a1e66ca3025065b7f53ae", size = 21176963, upload-time = "2025-05-17T21:31:19.36Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/2b/64e1affc7972decb74c9e29e5649fac940514910960ba25cd9af4488b66c/numpy-2.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c820a93b0255bc360f53eca31a0e676fd1101f673dda8da93454a12e23fc5f7a", size = 14406743, upload-time = "2025-05-17T21:31:41.087Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/9f/0121e375000b5e50ffdd8b25bf78d8e1a5aa4cca3f185d41265198c7b834/numpy-2.2.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3d70692235e759f260c3d837193090014aebdf026dfd167834bcba43e30c2a42", size = 5352616, upload-time = "2025-05-17T21:31:50.072Z" },
+ { url = "https://files.pythonhosted.org/packages/31/0d/b48c405c91693635fbe2dcd7bc84a33a602add5f63286e024d3b6741411c/numpy-2.2.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:481b49095335f8eed42e39e8041327c05b0f6f4780488f61286ed3c01368d491", size = 6889579, upload-time = "2025-05-17T21:32:01.712Z" },
+ { url = "https://files.pythonhosted.org/packages/52/b8/7f0554d49b565d0171eab6e99001846882000883998e7b7d9f0d98b1f934/numpy-2.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b64d8d4d17135e00c8e346e0a738deb17e754230d7e0810ac5012750bbd85a5a", size = 14312005, upload-time = "2025-05-17T21:32:23.332Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/dd/2238b898e51bd6d389b7389ffb20d7f4c10066d80351187ec8e303a5a475/numpy-2.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba10f8411898fc418a521833e014a77d3ca01c15b0c6cdcce6a0d2897e6dbbdf", size = 16821570, upload-time = "2025-05-17T21:32:47.991Z" },
+ { url = "https://files.pythonhosted.org/packages/83/6c/44d0325722cf644f191042bf47eedad61c1e6df2432ed65cbe28509d404e/numpy-2.2.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd48227a919f1bafbdda0583705e547892342c26fb127219d60a5c36882609d1", size = 15818548, upload-time = "2025-05-17T21:33:11.728Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/9d/81e8216030ce66be25279098789b665d49ff19eef08bfa8cb96d4957f422/numpy-2.2.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9551a499bf125c1d4f9e250377c1ee2eddd02e01eac6644c080162c0c51778ab", size = 18620521, upload-time = "2025-05-17T21:33:39.139Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/fd/e19617b9530b031db51b0926eed5345ce8ddc669bb3bc0044b23e275ebe8/numpy-2.2.6-cp311-cp311-win32.whl", hash = "sha256:0678000bb9ac1475cd454c6b8c799206af8107e310843532b04d49649c717a47", size = 6525866, upload-time = "2025-05-17T21:33:50.273Z" },
+ { url = "https://files.pythonhosted.org/packages/31/0a/f354fb7176b81747d870f7991dc763e157a934c717b67b58456bc63da3df/numpy-2.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:e8213002e427c69c45a52bbd94163084025f533a55a59d6f9c5b820774ef3303", size = 12907455, upload-time = "2025-05-17T21:34:09.135Z" },
+ { url = "https://files.pythonhosted.org/packages/82/5d/c00588b6cf18e1da539b45d3598d3557084990dcc4331960c15ee776ee41/numpy-2.2.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff", size = 20875348, upload-time = "2025-05-17T21:34:39.648Z" },
+ { url = "https://files.pythonhosted.org/packages/66/ee/560deadcdde6c2f90200450d5938f63a34b37e27ebff162810f716f6a230/numpy-2.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c", size = 14119362, upload-time = "2025-05-17T21:35:01.241Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/65/4baa99f1c53b30adf0acd9a5519078871ddde8d2339dc5a7fde80d9d87da/numpy-2.2.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3", size = 5084103, upload-time = "2025-05-17T21:35:10.622Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/89/e5a34c071a0570cc40c9a54eb472d113eea6d002e9ae12bb3a8407fb912e/numpy-2.2.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282", size = 6625382, upload-time = "2025-05-17T21:35:21.414Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/35/8c80729f1ff76b3921d5c9487c7ac3de9b2a103b1cd05e905b3090513510/numpy-2.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87", size = 14018462, upload-time = "2025-05-17T21:35:42.174Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/3d/1e1db36cfd41f895d266b103df00ca5b3cbe965184df824dec5c08c6b803/numpy-2.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249", size = 16527618, upload-time = "2025-05-17T21:36:06.711Z" },
+ { url = "https://files.pythonhosted.org/packages/61/c6/03ed30992602c85aa3cd95b9070a514f8b3c33e31124694438d88809ae36/numpy-2.2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49", size = 15505511, upload-time = "2025-05-17T21:36:29.965Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/25/5761d832a81df431e260719ec45de696414266613c9ee268394dd5ad8236/numpy-2.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de", size = 18313783, upload-time = "2025-05-17T21:36:56.883Z" },
+ { url = "https://files.pythonhosted.org/packages/57/0a/72d5a3527c5ebffcd47bde9162c39fae1f90138c961e5296491ce778e682/numpy-2.2.6-cp312-cp312-win32.whl", hash = "sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4", size = 6246506, upload-time = "2025-05-17T21:37:07.368Z" },
+ { url = "https://files.pythonhosted.org/packages/36/fa/8c9210162ca1b88529ab76b41ba02d433fd54fecaf6feb70ef9f124683f1/numpy-2.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2", size = 12614190, upload-time = "2025-05-17T21:37:26.213Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/5c/6657823f4f594f72b5471f1db1ab12e26e890bb2e41897522d134d2a3e81/numpy-2.2.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0811bb762109d9708cca4d0b13c4f67146e3c3b7cf8d34018c722adb2d957c84", size = 20867828, upload-time = "2025-05-17T21:37:56.699Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/9e/14520dc3dadf3c803473bd07e9b2bd1b69bc583cb2497b47000fed2fa92f/numpy-2.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:287cc3162b6f01463ccd86be154f284d0893d2b3ed7292439ea97eafa8170e0b", size = 14143006, upload-time = "2025-05-17T21:38:18.291Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/06/7e96c57d90bebdce9918412087fc22ca9851cceaf5567a45c1f404480e9e/numpy-2.2.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:f1372f041402e37e5e633e586f62aa53de2eac8d98cbfb822806ce4bbefcb74d", size = 5076765, upload-time = "2025-05-17T21:38:27.319Z" },
+ { url = "https://files.pythonhosted.org/packages/73/ed/63d920c23b4289fdac96ddbdd6132e9427790977d5457cd132f18e76eae0/numpy-2.2.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:55a4d33fa519660d69614a9fad433be87e5252f4b03850642f88993f7b2ca566", size = 6617736, upload-time = "2025-05-17T21:38:38.141Z" },
+ { url = "https://files.pythonhosted.org/packages/85/c5/e19c8f99d83fd377ec8c7e0cf627a8049746da54afc24ef0a0cb73d5dfb5/numpy-2.2.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f92729c95468a2f4f15e9bb94c432a9229d0d50de67304399627a943201baa2f", size = 14010719, upload-time = "2025-05-17T21:38:58.433Z" },
+ { url = "https://files.pythonhosted.org/packages/19/49/4df9123aafa7b539317bf6d342cb6d227e49f7a35b99c287a6109b13dd93/numpy-2.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bc23a79bfabc5d056d106f9befb8d50c31ced2fbc70eedb8155aec74a45798f", size = 16526072, upload-time = "2025-05-17T21:39:22.638Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/6c/04b5f47f4f32f7c2b0e7260442a8cbcf8168b0e1a41ff1495da42f42a14f/numpy-2.2.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3143e4451880bed956e706a3220b4e5cf6172ef05fcc397f6f36a550b1dd868", size = 15503213, upload-time = "2025-05-17T21:39:45.865Z" },
+ { url = "https://files.pythonhosted.org/packages/17/0a/5cd92e352c1307640d5b6fec1b2ffb06cd0dabe7d7b8227f97933d378422/numpy-2.2.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4f13750ce79751586ae2eb824ba7e1e8dba64784086c98cdbbcc6a42112ce0d", size = 18316632, upload-time = "2025-05-17T21:40:13.331Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/3b/5cba2b1d88760ef86596ad0f3d484b1cbff7c115ae2429678465057c5155/numpy-2.2.6-cp313-cp313-win32.whl", hash = "sha256:5beb72339d9d4fa36522fc63802f469b13cdbe4fdab4a288f0c441b74272ebfd", size = 6244532, upload-time = "2025-05-17T21:43:46.099Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/3b/d58c12eafcb298d4e6d0d40216866ab15f59e55d148a5658bb3132311fcf/numpy-2.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c", size = 12610885, upload-time = "2025-05-17T21:44:05.145Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/9e/4bf918b818e516322db999ac25d00c75788ddfd2d2ade4fa66f1f38097e1/numpy-2.2.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0bca768cd85ae743b2affdc762d617eddf3bcf8724435498a1e80132d04879e6", size = 20963467, upload-time = "2025-05-17T21:40:44Z" },
+ { url = "https://files.pythonhosted.org/packages/61/66/d2de6b291507517ff2e438e13ff7b1e2cdbdb7cb40b3ed475377aece69f9/numpy-2.2.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fc0c5673685c508a142ca65209b4e79ed6740a4ed6b2267dbba90f34b0b3cfda", size = 14225144, upload-time = "2025-05-17T21:41:05.695Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/25/480387655407ead912e28ba3a820bc69af9adf13bcbe40b299d454ec011f/numpy-2.2.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5bd4fc3ac8926b3819797a7c0e2631eb889b4118a9898c84f585a54d475b7e40", size = 5200217, upload-time = "2025-05-17T21:41:15.903Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/4a/6e313b5108f53dcbf3aca0c0f3e9c92f4c10ce57a0a721851f9785872895/numpy-2.2.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:fee4236c876c4e8369388054d02d0e9bb84821feb1a64dd59e137e6511a551f8", size = 6712014, upload-time = "2025-05-17T21:41:27.321Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/30/172c2d5c4be71fdf476e9de553443cf8e25feddbe185e0bd88b096915bcc/numpy-2.2.6-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1dda9c7e08dc141e0247a5b8f49cf05984955246a327d4c48bda16821947b2f", size = 14077935, upload-time = "2025-05-17T21:41:49.738Z" },
+ { url = "https://files.pythonhosted.org/packages/12/fb/9e743f8d4e4d3c710902cf87af3512082ae3d43b945d5d16563f26ec251d/numpy-2.2.6-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f447e6acb680fd307f40d3da4852208af94afdfab89cf850986c3ca00562f4fa", size = 16600122, upload-time = "2025-05-17T21:42:14.046Z" },
+ { url = "https://files.pythonhosted.org/packages/12/75/ee20da0e58d3a66f204f38916757e01e33a9737d0b22373b3eb5a27358f9/numpy-2.2.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:389d771b1623ec92636b0786bc4ae56abafad4a4c513d36a55dce14bd9ce8571", size = 15586143, upload-time = "2025-05-17T21:42:37.464Z" },
+ { url = "https://files.pythonhosted.org/packages/76/95/bef5b37f29fc5e739947e9ce5179ad402875633308504a52d188302319c8/numpy-2.2.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8e9ace4a37db23421249ed236fdcdd457d671e25146786dfc96835cd951aa7c1", size = 18385260, upload-time = "2025-05-17T21:43:05.189Z" },
+ { url = "https://files.pythonhosted.org/packages/09/04/f2f83279d287407cf36a7a8053a5abe7be3622a4363337338f2585e4afda/numpy-2.2.6-cp313-cp313t-win32.whl", hash = "sha256:038613e9fb8c72b0a41f025a7e4c3f0b7a1b5d768ece4796b674c8f3fe13efff", size = 6377225, upload-time = "2025-05-17T21:43:16.254Z" },
+ { url = "https://files.pythonhosted.org/packages/67/0e/35082d13c09c02c011cf21570543d202ad929d961c02a147493cb0c2bdf5/numpy-2.2.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6031dd6dfecc0cf9f668681a37648373bddd6421fff6c66ec1624eed0180ee06", size = 12771374, upload-time = "2025-05-17T21:43:35.479Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/3b/d94a75f4dbf1ef5d321523ecac21ef23a3cd2ac8b78ae2aac40873590229/numpy-2.2.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0b605b275d7bd0c640cad4e5d30fa701a8d59302e127e5f79138ad62762c3e3d", size = 21040391, upload-time = "2025-05-17T21:44:35.948Z" },
+ { url = "https://files.pythonhosted.org/packages/17/f4/09b2fa1b58f0fb4f7c7963a1649c64c4d315752240377ed74d9cd878f7b5/numpy-2.2.6-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:7befc596a7dc9da8a337f79802ee8adb30a552a94f792b9c9d18c840055907db", size = 6786754, upload-time = "2025-05-17T21:44:47.446Z" },
+ { url = "https://files.pythonhosted.org/packages/af/30/feba75f143bdc868a1cc3f44ccfa6c4b9ec522b36458e738cd00f67b573f/numpy-2.2.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce47521a4754c8f4593837384bd3424880629f718d87c5d44f8ed763edd63543", size = 16643476, upload-time = "2025-05-17T21:45:11.871Z" },
+ { url = "https://files.pythonhosted.org/packages/37/48/ac2a9584402fb6c0cd5b5d1a91dcf176b15760130dd386bbafdbfe3640bf/numpy-2.2.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d042d24c90c41b54fd506da306759e06e568864df8ec17ccc17e9e884634fd00", size = 12812666, upload-time = "2025-05-17T21:45:31.426Z" },
+]
+
+[[package]]
+name = "numpy"
+version = "2.4.2"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version >= '3.11'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/57/fd/0005efbd0af48e55eb3c7208af93f2862d4b1a56cd78e84309a2d959208d/numpy-2.4.2.tar.gz", hash = "sha256:659a6107e31a83c4e33f763942275fd278b21d095094044eb35569e86a21ddae", size = 20723651, upload-time = "2026-01-31T23:13:10.135Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d3/44/71852273146957899753e69986246d6a176061ea183407e95418c2aa4d9a/numpy-2.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e7e88598032542bd49af7c4747541422884219056c268823ef6e5e89851c8825", size = 16955478, upload-time = "2026-01-31T23:10:25.623Z" },
+ { url = "https://files.pythonhosted.org/packages/74/41/5d17d4058bd0cd96bcbd4d9ff0fb2e21f52702aab9a72e4a594efa18692f/numpy-2.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7edc794af8b36ca37ef5fcb5e0d128c7e0595c7b96a2318d1badb6fcd8ee86b1", size = 14965467, upload-time = "2026-01-31T23:10:28.186Z" },
+ { url = "https://files.pythonhosted.org/packages/49/48/fb1ce8136c19452ed15f033f8aee91d5defe515094e330ce368a0647846f/numpy-2.4.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:6e9f61981ace1360e42737e2bae58b27bf28a1b27e781721047d84bd754d32e7", size = 5475172, upload-time = "2026-01-31T23:10:30.848Z" },
+ { url = "https://files.pythonhosted.org/packages/40/a9/3feb49f17bbd1300dd2570432961f5c8a4ffeff1db6f02c7273bd020a4c9/numpy-2.4.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:cb7bbb88aa74908950d979eeaa24dbdf1a865e3c7e45ff0121d8f70387b55f73", size = 6805145, upload-time = "2026-01-31T23:10:32.352Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/39/fdf35cbd6d6e2fcad42fcf85ac04a85a0d0fbfbf34b30721c98d602fd70a/numpy-2.4.2-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4f069069931240b3fc703f1e23df63443dbd6390614c8c44a87d96cd0ec81eb1", size = 15966084, upload-time = "2026-01-31T23:10:34.502Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/46/6fa4ea94f1ddf969b2ee941290cca6f1bfac92b53c76ae5f44afe17ceb69/numpy-2.4.2-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c02ef4401a506fb60b411467ad501e1429a3487abca4664871d9ae0b46c8ba32", size = 16899477, upload-time = "2026-01-31T23:10:37.075Z" },
+ { url = "https://files.pythonhosted.org/packages/09/a1/2a424e162b1a14a5bd860a464ab4e07513916a64ab1683fae262f735ccd2/numpy-2.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2653de5c24910e49c2b106499803124dde62a5a1fe0eedeaecf4309a5f639390", size = 17323429, upload-time = "2026-01-31T23:10:39.704Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/a2/73014149ff250628df72c58204822ac01d768697913881aacf839ff78680/numpy-2.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1ae241bbfc6ae276f94a170b14785e561cb5e7f626b6688cf076af4110887413", size = 18635109, upload-time = "2026-01-31T23:10:41.924Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/0c/73e8be2f1accd56df74abc1c5e18527822067dced5ec0861b5bb882c2ce0/numpy-2.4.2-cp311-cp311-win32.whl", hash = "sha256:df1b10187212b198dd45fa943d8985a3c8cf854aed4923796e0e019e113a1bda", size = 6237915, upload-time = "2026-01-31T23:10:45.26Z" },
+ { url = "https://files.pythonhosted.org/packages/76/ae/e0265e0163cf127c24c3969d29f1c4c64551a1e375d95a13d32eab25d364/numpy-2.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:b9c618d56a29c9cb1c4da979e9899be7578d2e0b3c24d52079c166324c9e8695", size = 12607972, upload-time = "2026-01-31T23:10:47.021Z" },
+ { url = "https://files.pythonhosted.org/packages/29/a5/c43029af9b8014d6ea157f192652c50042e8911f4300f8f6ed3336bf437f/numpy-2.4.2-cp311-cp311-win_arm64.whl", hash = "sha256:47c5a6ed21d9452b10227e5e8a0e1c22979811cad7dcc19d8e3e2fb8fa03f1a3", size = 10485763, upload-time = "2026-01-31T23:10:50.087Z" },
+ { url = "https://files.pythonhosted.org/packages/51/6e/6f394c9c77668153e14d4da83bcc247beb5952f6ead7699a1a2992613bea/numpy-2.4.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:21982668592194c609de53ba4933a7471880ccbaadcc52352694a59ecc860b3a", size = 16667963, upload-time = "2026-01-31T23:10:52.147Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/f8/55483431f2b2fd015ae6ed4fe62288823ce908437ed49db5a03d15151678/numpy-2.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40397bda92382fcec844066efb11f13e1c9a3e2a8e8f318fb72ed8b6db9f60f1", size = 14693571, upload-time = "2026-01-31T23:10:54.789Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/20/18026832b1845cdc82248208dd929ca14c9d8f2bac391f67440707fff27c/numpy-2.4.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:b3a24467af63c67829bfaa61eecf18d5432d4f11992688537be59ecd6ad32f5e", size = 5203469, upload-time = "2026-01-31T23:10:57.343Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/33/2eb97c8a77daaba34eaa3fa7241a14ac5f51c46a6bd5911361b644c4a1e2/numpy-2.4.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:805cc8de9fd6e7a22da5aed858e0ab16be5a4db6c873dde1d7451c541553aa27", size = 6550820, upload-time = "2026-01-31T23:10:59.429Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/91/b97fdfd12dc75b02c44e26c6638241cc004d4079a0321a69c62f51470c4c/numpy-2.4.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d82351358ffbcdcd7b686b90742a9b86632d6c1c051016484fa0b326a0a1548", size = 15663067, upload-time = "2026-01-31T23:11:01.291Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/c6/a18e59f3f0b8071cc85cbc8d80cd02d68aa9710170b2553a117203d46936/numpy-2.4.2-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e35d3e0144137d9fdae62912e869136164534d64a169f86438bc9561b6ad49f", size = 16619782, upload-time = "2026-01-31T23:11:03.669Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/83/9751502164601a79e18847309f5ceec0b1446d7b6aa12305759b72cf98b2/numpy-2.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:adb6ed2ad29b9e15321d167d152ee909ec73395901b70936f029c3bc6d7f4460", size = 17013128, upload-time = "2026-01-31T23:11:05.913Z" },
+ { url = "https://files.pythonhosted.org/packages/61/c4/c4066322256ec740acc1c8923a10047818691d2f8aec254798f3dd90f5f2/numpy-2.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8906e71fd8afcb76580404e2a950caef2685df3d2a57fe82a86ac8d33cc007ba", size = 18345324, upload-time = "2026-01-31T23:11:08.248Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/af/6157aa6da728fa4525a755bfad486ae7e3f76d4c1864138003eb84328497/numpy-2.4.2-cp312-cp312-win32.whl", hash = "sha256:ec055f6dae239a6299cace477b479cca2fc125c5675482daf1dd886933a1076f", size = 5960282, upload-time = "2026-01-31T23:11:10.497Z" },
+ { url = "https://files.pythonhosted.org/packages/92/0f/7ceaaeaacb40567071e94dbf2c9480c0ae453d5bb4f52bea3892c39dc83c/numpy-2.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:209fae046e62d0ce6435fcfe3b1a10537e858249b3d9b05829e2a05218296a85", size = 12314210, upload-time = "2026-01-31T23:11:12.176Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/a3/56c5c604fae6dd40fa2ed3040d005fca97e91bd320d232ac9931d77ba13c/numpy-2.4.2-cp312-cp312-win_arm64.whl", hash = "sha256:fbde1b0c6e81d56f5dccd95dd4a711d9b95df1ae4009a60887e56b27e8d903fa", size = 10220171, upload-time = "2026-01-31T23:11:14.684Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/22/815b9fe25d1d7ae7d492152adbc7226d3eff731dffc38fe970589fcaaa38/numpy-2.4.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:25f2059807faea4b077a2b6837391b5d830864b3543627f381821c646f31a63c", size = 16663696, upload-time = "2026-01-31T23:11:17.516Z" },
+ { url = "https://files.pythonhosted.org/packages/09/f0/817d03a03f93ba9c6c8993de509277d84e69f9453601915e4a69554102a1/numpy-2.4.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bd3a7a9f5847d2fb8c2c6d1c862fa109c31a9abeca1a3c2bd5a64572955b2979", size = 14688322, upload-time = "2026-01-31T23:11:19.883Z" },
+ { url = "https://files.pythonhosted.org/packages/da/b4/f805ab79293c728b9a99438775ce51885fd4f31b76178767cfc718701a39/numpy-2.4.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:8e4549f8a3c6d13d55041925e912bfd834285ef1dd64d6bc7d542583355e2e98", size = 5198157, upload-time = "2026-01-31T23:11:22.375Z" },
+ { url = "https://files.pythonhosted.org/packages/74/09/826e4289844eccdcd64aac27d13b0fd3f32039915dd5b9ba01baae1f436c/numpy-2.4.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:aea4f66ff44dfddf8c2cffd66ba6538c5ec67d389285292fe428cb2c738c8aef", size = 6546330, upload-time = "2026-01-31T23:11:23.958Z" },
+ { url = "https://files.pythonhosted.org/packages/19/fb/cbfdbfa3057a10aea5422c558ac57538e6acc87ec1669e666d32ac198da7/numpy-2.4.2-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c3cd545784805de05aafe1dde61752ea49a359ccba9760c1e5d1c88a93bbf2b7", size = 15660968, upload-time = "2026-01-31T23:11:25.713Z" },
+ { url = "https://files.pythonhosted.org/packages/04/dc/46066ce18d01645541f0186877377b9371b8fa8017fa8262002b4ef22612/numpy-2.4.2-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d0d9b7c93578baafcbc5f0b83eaf17b79d345c6f36917ba0c67f45226911d499", size = 16607311, upload-time = "2026-01-31T23:11:28.117Z" },
+ { url = "https://files.pythonhosted.org/packages/14/d9/4b5adfc39a43fa6bf918c6d544bc60c05236cc2f6339847fc5b35e6cb5b0/numpy-2.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f74f0f7779cc7ae07d1810aab8ac6b1464c3eafb9e283a40da7309d5e6e48fbb", size = 17012850, upload-time = "2026-01-31T23:11:30.888Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/20/adb6e6adde6d0130046e6fdfb7675cc62bc2f6b7b02239a09eb58435753d/numpy-2.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c7ac672d699bf36275c035e16b65539931347d68b70667d28984c9fb34e07fa7", size = 18334210, upload-time = "2026-01-31T23:11:33.214Z" },
+ { url = "https://files.pythonhosted.org/packages/78/0e/0a73b3dff26803a8c02baa76398015ea2a5434d9b8265a7898a6028c1591/numpy-2.4.2-cp313-cp313-win32.whl", hash = "sha256:8e9afaeb0beff068b4d9cd20d322ba0ee1cecfb0b08db145e4ab4dd44a6b5110", size = 5958199, upload-time = "2026-01-31T23:11:35.385Z" },
+ { url = "https://files.pythonhosted.org/packages/43/bc/6352f343522fcb2c04dbaf94cb30cca6fd32c1a750c06ad6231b4293708c/numpy-2.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:7df2de1e4fba69a51c06c28f5a3de36731eb9639feb8e1cf7e4a7b0daf4cf622", size = 12310848, upload-time = "2026-01-31T23:11:38.001Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/8d/6da186483e308da5da1cc6918ce913dcfe14ffde98e710bfeff2a6158d4e/numpy-2.4.2-cp313-cp313-win_arm64.whl", hash = "sha256:0fece1d1f0a89c16b03442eae5c56dc0be0c7883b5d388e0c03f53019a4bfd71", size = 10221082, upload-time = "2026-01-31T23:11:40.392Z" },
+ { url = "https://files.pythonhosted.org/packages/25/a1/9510aa43555b44781968935c7548a8926274f815de42ad3997e9e83680dd/numpy-2.4.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5633c0da313330fd20c484c78cdd3f9b175b55e1a766c4a174230c6b70ad8262", size = 14815866, upload-time = "2026-01-31T23:11:42.495Z" },
+ { url = "https://files.pythonhosted.org/packages/36/30/6bbb5e76631a5ae46e7923dd16ca9d3f1c93cfa8d4ed79a129814a9d8db3/numpy-2.4.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d9f64d786b3b1dd742c946c42d15b07497ed14af1a1f3ce840cce27daa0ce913", size = 5325631, upload-time = "2026-01-31T23:11:44.7Z" },
+ { url = "https://files.pythonhosted.org/packages/46/00/3a490938800c1923b567b3a15cd17896e68052e2145d8662aaf3e1ffc58f/numpy-2.4.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:b21041e8cb6a1eb5312dd1d2f80a94d91efffb7a06b70597d44f1bd2dfc315ab", size = 6646254, upload-time = "2026-01-31T23:11:46.341Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/e9/fac0890149898a9b609caa5af7455a948b544746e4b8fe7c212c8edd71f8/numpy-2.4.2-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:00ab83c56211a1d7c07c25e3217ea6695e50a3e2f255053686b081dc0b091a82", size = 15720138, upload-time = "2026-01-31T23:11:48.082Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/5c/08887c54e68e1e28df53709f1893ce92932cc6f01f7c3d4dc952f61ffd4e/numpy-2.4.2-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fb882da679409066b4603579619341c6d6898fc83a8995199d5249f986e8e8f", size = 16655398, upload-time = "2026-01-31T23:11:50.293Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/89/253db0fa0e66e9129c745e4ef25631dc37d5f1314dad2b53e907b8538e6d/numpy-2.4.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:66cb9422236317f9d44b67b4d18f44efe6e9c7f8794ac0462978513359461554", size = 17079064, upload-time = "2026-01-31T23:11:52.927Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/d5/cbade46ce97c59c6c3da525e8d95b7abe8a42974a1dc5c1d489c10433e88/numpy-2.4.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:0f01dcf33e73d80bd8dc0f20a71303abbafa26a19e23f6b68d1aa9990af90257", size = 18379680, upload-time = "2026-01-31T23:11:55.22Z" },
+ { url = "https://files.pythonhosted.org/packages/40/62/48f99ae172a4b63d981babe683685030e8a3df4f246c893ea5c6ef99f018/numpy-2.4.2-cp313-cp313t-win32.whl", hash = "sha256:52b913ec40ff7ae845687b0b34d8d93b60cb66dcee06996dd5c99f2fc9328657", size = 6082433, upload-time = "2026-01-31T23:11:58.096Z" },
+ { url = "https://files.pythonhosted.org/packages/07/38/e054a61cfe48ad9f1ed0d188e78b7e26859d0b60ef21cd9de4897cdb5326/numpy-2.4.2-cp313-cp313t-win_amd64.whl", hash = "sha256:5eea80d908b2c1f91486eb95b3fb6fab187e569ec9752ab7d9333d2e66bf2d6b", size = 12451181, upload-time = "2026-01-31T23:11:59.782Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/a4/a05c3a6418575e185dd84d0b9680b6bb2e2dc3e4202f036b7b4e22d6e9dc/numpy-2.4.2-cp313-cp313t-win_arm64.whl", hash = "sha256:fd49860271d52127d61197bb50b64f58454e9f578cb4b2c001a6de8b1f50b0b1", size = 10290756, upload-time = "2026-01-31T23:12:02.438Z" },
+ { url = "https://files.pythonhosted.org/packages/18/88/b7df6050bf18fdcfb7046286c6535cabbdd2064a3440fca3f069d319c16e/numpy-2.4.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:444be170853f1f9d528428eceb55f12918e4fda5d8805480f36a002f1415e09b", size = 16663092, upload-time = "2026-01-31T23:12:04.521Z" },
+ { url = "https://files.pythonhosted.org/packages/25/7a/1fee4329abc705a469a4afe6e69b1ef7e915117747886327104a8493a955/numpy-2.4.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d1240d50adff70c2a88217698ca844723068533f3f5c5fa6ee2e3220e3bdb000", size = 14698770, upload-time = "2026-01-31T23:12:06.96Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/0b/f9e49ba6c923678ad5bc38181c08ac5e53b7a5754dbca8e581aa1a56b1ff/numpy-2.4.2-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:7cdde6de52fb6664b00b056341265441192d1291c130e99183ec0d4b110ff8b1", size = 5208562, upload-time = "2026-01-31T23:12:09.632Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/12/d7de8f6f53f9bb76997e5e4c069eda2051e3fe134e9181671c4391677bb2/numpy-2.4.2-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:cda077c2e5b780200b6b3e09d0b42205a3d1c68f30c6dceb90401c13bff8fe74", size = 6543710, upload-time = "2026-01-31T23:12:11.969Z" },
+ { url = "https://files.pythonhosted.org/packages/09/63/c66418c2e0268a31a4cf8a8b512685748200f8e8e8ec6c507ce14e773529/numpy-2.4.2-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d30291931c915b2ab5717c2974bb95ee891a1cf22ebc16a8006bd59cd210d40a", size = 15677205, upload-time = "2026-01-31T23:12:14.33Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/6c/7f237821c9642fb2a04d2f1e88b4295677144ca93285fd76eff3bcba858d/numpy-2.4.2-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bba37bc29d4d85761deed3954a1bc62be7cf462b9510b51d367b769a8c8df325", size = 16611738, upload-time = "2026-01-31T23:12:16.525Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/a7/39c4cdda9f019b609b5c473899d87abff092fc908cfe4d1ecb2fcff453b0/numpy-2.4.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b2f0073ed0868db1dcd86e052d37279eef185b9c8db5bf61f30f46adac63c909", size = 17028888, upload-time = "2026-01-31T23:12:19.306Z" },
+ { url = "https://files.pythonhosted.org/packages/da/b3/e84bb64bdfea967cc10950d71090ec2d84b49bc691df0025dddb7c26e8e3/numpy-2.4.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7f54844851cdb630ceb623dcec4db3240d1ac13d4990532446761baede94996a", size = 18339556, upload-time = "2026-01-31T23:12:21.816Z" },
+ { url = "https://files.pythonhosted.org/packages/88/f5/954a291bc1192a27081706862ac62bb5920fbecfbaa302f64682aa90beed/numpy-2.4.2-cp314-cp314-win32.whl", hash = "sha256:12e26134a0331d8dbd9351620f037ec470b7c75929cb8a1537f6bfe411152a1a", size = 6006899, upload-time = "2026-01-31T23:12:24.14Z" },
+ { url = "https://files.pythonhosted.org/packages/05/cb/eff72a91b2efdd1bc98b3b8759f6a1654aa87612fc86e3d87d6fe4f948c4/numpy-2.4.2-cp314-cp314-win_amd64.whl", hash = "sha256:068cdb2d0d644cdb45670810894f6a0600797a69c05f1ac478e8d31670b8ee75", size = 12443072, upload-time = "2026-01-31T23:12:26.33Z" },
+ { url = "https://files.pythonhosted.org/packages/37/75/62726948db36a56428fce4ba80a115716dc4fad6a3a4352487f8bb950966/numpy-2.4.2-cp314-cp314-win_arm64.whl", hash = "sha256:6ed0be1ee58eef41231a5c943d7d1375f093142702d5723ca2eb07db9b934b05", size = 10494886, upload-time = "2026-01-31T23:12:28.488Z" },
+ { url = "https://files.pythonhosted.org/packages/36/2f/ee93744f1e0661dc267e4b21940870cabfae187c092e1433b77b09b50ac4/numpy-2.4.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:98f16a80e917003a12c0580f97b5f875853ebc33e2eaa4bccfc8201ac6869308", size = 14818567, upload-time = "2026-01-31T23:12:30.709Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/24/6535212add7d76ff938d8bdc654f53f88d35cddedf807a599e180dcb8e66/numpy-2.4.2-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:20abd069b9cda45874498b245c8015b18ace6de8546bf50dfa8cea1696ed06ef", size = 5328372, upload-time = "2026-01-31T23:12:32.962Z" },
+ { url = "https://files.pythonhosted.org/packages/5e/9d/c48f0a035725f925634bf6b8994253b43f2047f6778a54147d7e213bc5a7/numpy-2.4.2-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:e98c97502435b53741540a5717a6749ac2ada901056c7db951d33e11c885cc7d", size = 6649306, upload-time = "2026-01-31T23:12:34.797Z" },
+ { url = "https://files.pythonhosted.org/packages/81/05/7c73a9574cd4a53a25907bad38b59ac83919c0ddc8234ec157f344d57d9a/numpy-2.4.2-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:da6cad4e82cb893db4b69105c604d805e0c3ce11501a55b5e9f9083b47d2ffe8", size = 15722394, upload-time = "2026-01-31T23:12:36.565Z" },
+ { url = "https://files.pythonhosted.org/packages/35/fa/4de10089f21fc7d18442c4a767ab156b25c2a6eaf187c0db6d9ecdaeb43f/numpy-2.4.2-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e4424677ce4b47fe73c8b5556d876571f7c6945d264201180db2dc34f676ab5", size = 16653343, upload-time = "2026-01-31T23:12:39.188Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/f9/d33e4ffc857f3763a57aa85650f2e82486832d7492280ac21ba9efda80da/numpy-2.4.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2b8f157c8a6f20eb657e240f8985cc135598b2b46985c5bccbde7616dc9c6b1e", size = 17078045, upload-time = "2026-01-31T23:12:42.041Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/b8/54bdb43b6225badbea6389fa038c4ef868c44f5890f95dd530a218706da3/numpy-2.4.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5daf6f3914a733336dab21a05cdec343144600e964d2fcdabaac0c0269874b2a", size = 18380024, upload-time = "2026-01-31T23:12:44.331Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/55/6e1a61ded7af8df04016d81b5b02daa59f2ea9252ee0397cb9f631efe9e5/numpy-2.4.2-cp314-cp314t-win32.whl", hash = "sha256:8c50dd1fc8826f5b26a5ee4d77ca55d88a895f4e4819c7ecc2a9f5905047a443", size = 6153937, upload-time = "2026-01-31T23:12:47.229Z" },
+ { url = "https://files.pythonhosted.org/packages/45/aa/fa6118d1ed6d776b0983f3ceac9b1a5558e80df9365b1c3aa6d42bf9eee4/numpy-2.4.2-cp314-cp314t-win_amd64.whl", hash = "sha256:fcf92bee92742edd401ba41135185866f7026c502617f422eb432cfeca4fe236", size = 12631844, upload-time = "2026-01-31T23:12:48.997Z" },
+ { url = "https://files.pythonhosted.org/packages/32/0a/2ec5deea6dcd158f254a7b372fb09cfba5719419c8d66343bab35237b3fb/numpy-2.4.2-cp314-cp314t-win_arm64.whl", hash = "sha256:1f92f53998a17265194018d1cc321b2e96e900ca52d54c7c77837b71b9465181", size = 10565379, upload-time = "2026-01-31T23:12:51.345Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/f8/50e14d36d915ef64d8f8bc4a087fc8264d82c785eda6711f80ab7e620335/numpy-2.4.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:89f7268c009bc492f506abd6f5265defa7cb3f7487dc21d357c3d290add45082", size = 16833179, upload-time = "2026-01-31T23:12:53.5Z" },
+ { url = "https://files.pythonhosted.org/packages/17/17/809b5cad63812058a8189e91a1e2d55a5a18fd04611dbad244e8aeae465c/numpy-2.4.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6dee3bb76aa4009d5a912180bf5b2de012532998d094acee25d9cb8dee3e44a", size = 14889755, upload-time = "2026-01-31T23:12:55.933Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/ea/181b9bcf7627fc8371720316c24db888dcb9829b1c0270abf3d288b2e29b/numpy-2.4.2-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:cd2bd2bbed13e213d6b55dc1d035a4f91748a7d3edc9480c13898b0353708920", size = 5399500, upload-time = "2026-01-31T23:12:58.671Z" },
+ { url = "https://files.pythonhosted.org/packages/33/9f/413adf3fc955541ff5536b78fcf0754680b3c6d95103230252a2c9408d23/numpy-2.4.2-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:cf28c0c1d4c4bf00f509fa7eb02c58d7caf221b50b467bcb0d9bbf1584d5c821", size = 6714252, upload-time = "2026-01-31T23:13:00.518Z" },
+ { url = "https://files.pythonhosted.org/packages/91/da/643aad274e29ccbdf42ecd94dafe524b81c87bcb56b83872d54827f10543/numpy-2.4.2-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e04ae107ac591763a47398bb45b568fc38f02dbc4aa44c063f67a131f99346cb", size = 15797142, upload-time = "2026-01-31T23:13:02.219Z" },
+ { url = "https://files.pythonhosted.org/packages/66/27/965b8525e9cb5dc16481b30a1b3c21e50c7ebf6e9dbd48d0c4d0d5089c7e/numpy-2.4.2-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:602f65afdef699cda27ec0b9224ae5dc43e328f4c24c689deaf77133dbee74d0", size = 16727979, upload-time = "2026-01-31T23:13:04.62Z" },
+ { url = "https://files.pythonhosted.org/packages/de/e5/b7d20451657664b07986c2f6e3be564433f5dcaf3482d68eaecd79afaf03/numpy-2.4.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:be71bf1edb48ebbbf7f6337b5bfd2f895d1902f6335a5830b20141fc126ffba0", size = 12502577, upload-time = "2026-01-31T23:13:07.08Z" },
+]
+
+[[package]]
+name = "packaging"
+version = "26.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" },
+]
+
+[[package]]
+name = "parso"
+version = "0.8.6"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/81/76/a1e769043c0c0c9fe391b702539d594731a4362334cdf4dc25d0c09761e7/parso-0.8.6.tar.gz", hash = "sha256:2b9a0332696df97d454fa67b81618fd69c35a7b90327cbe6ba5c92d2c68a7bfd", size = 401621, upload-time = "2026-02-09T15:45:24.425Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b6/61/fae042894f4296ec49e3f193aff5d7c18440da9e48102c3315e1bc4519a7/parso-0.8.6-py2.py3-none-any.whl", hash = "sha256:2c549f800b70a5c4952197248825584cb00f033b29c692671d3bf08bf380baff", size = 106894, upload-time = "2026-02-09T15:45:21.391Z" },
+]
+
+[[package]]
+name = "patchelf"
+version = "0.17.2.4"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/2c/a3/fdd3fa938c864aa2f11dd0b7f08befeda983d2dcdee44da493c6977a653f/patchelf-0.17.2.4.tar.gz", hash = "sha256:970ee5cd8af33e5ea2099510b2f9013fa1b8d5cd763bf3fd3961281c18101a09", size = 149629, upload-time = "2025-07-23T21:16:32.071Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b1/a7/8c4f86c78ec03db954d05fd9c57a114cc3a172a2d3e4a8b949cd5ff89471/patchelf-0.17.2.4-py3-none-macosx_10_9_universal2.whl", hash = "sha256:343bb1b94e959f9070ca9607453b04390e36bbaa33c88640b989cefad0aa049e", size = 184436, upload-time = "2025-07-23T21:16:20.578Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/19/f7821ef31aab01fa7dc8ebe697ece88ec4f7a0fdd3155dab2dfee4b00e5c/patchelf-0.17.2.4-py3-none-manylinux1_x86_64.manylinux_2_5_x86_64.musllinux_1_1_x86_64.whl", hash = "sha256:d9b35ebfada70c02679ad036407d9724ffe1255122ba4ac5e4be5868618a5689", size = 482846, upload-time = "2025-07-23T21:16:23.73Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/50/107fea848ecfd851d473b079cab79107487d72c4c3cdb25b9d2603a24ca2/patchelf-0.17.2.4-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:2931a1b5b85f3549661898af7bf746afbda7903c7c9a967cfc998a3563f84fad", size = 477811, upload-time = "2025-07-23T21:16:25.145Z" },
+]
+
+[[package]]
+name = "pathspec"
+version = "1.0.4"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/fa/36/e27608899f9b8d4dff0617b2d9ab17ca5608956ca44461ac14ac48b44015/pathspec-1.0.4.tar.gz", hash = "sha256:0210e2ae8a21a9137c0d470578cb0e595af87edaa6ebf12ff176f14a02e0e645", size = 131200, upload-time = "2026-01-27T03:59:46.938Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723", size = 55206, upload-time = "2026-01-27T03:59:45.137Z" },
+]
+
+[[package]]
+name = "pexpect"
+version = "4.9.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "ptyprocess" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" },
+]
+
+[[package]]
+name = "pillow"
+version = "11.3.0"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version < '3.10'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/d0d6dea55cd152ce3d6767bb38a8fc10e33796ba4ba210cbab9354b6d238/pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523", size = 47113069, upload-time = "2025-07-01T09:16:30.666Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/4c/5d/45a3553a253ac8763f3561371432a90bdbe6000fbdcf1397ffe502aa206c/pillow-11.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b9c17fd4ace828b3003dfd1e30bff24863e0eb59b535e8f80194d9cc7ecf860", size = 5316554, upload-time = "2025-07-01T09:13:39.342Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/c8/67c12ab069ef586a25a4a79ced553586748fad100c77c0ce59bb4983ac98/pillow-11.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:65dc69160114cdd0ca0f35cb434633c75e8e7fad4cf855177a05bf38678f73ad", size = 4686548, upload-time = "2025-07-01T09:13:41.835Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/bd/6741ebd56263390b382ae4c5de02979af7f8bd9807346d068700dd6d5cf9/pillow-11.3.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7107195ddc914f656c7fc8e4a5e1c25f32e9236ea3ea860f257b0436011fddd0", size = 5859742, upload-time = "2025-07-03T13:09:47.439Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/0b/c412a9e27e1e6a829e6ab6c2dca52dd563efbedf4c9c6aa453d9a9b77359/pillow-11.3.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc3e831b563b3114baac7ec2ee86819eb03caa1a2cef0b481a5675b59c4fe23b", size = 7633087, upload-time = "2025-07-03T13:09:51.796Z" },
+ { url = "https://files.pythonhosted.org/packages/59/9d/9b7076aaf30f5dd17e5e5589b2d2f5a5d7e30ff67a171eb686e4eecc2adf/pillow-11.3.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f1f182ebd2303acf8c380a54f615ec883322593320a9b00438eb842c1f37ae50", size = 5963350, upload-time = "2025-07-01T09:13:43.865Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/16/1a6bf01fb622fb9cf5c91683823f073f053005c849b1f52ed613afcf8dae/pillow-11.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4445fa62e15936a028672fd48c4c11a66d641d2c05726c7ec1f8ba6a572036ae", size = 6631840, upload-time = "2025-07-01T09:13:46.161Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/e6/6ff7077077eb47fde78739e7d570bdcd7c10495666b6afcd23ab56b19a43/pillow-11.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:71f511f6b3b91dd543282477be45a033e4845a40278fa8dcdbfdb07109bf18f9", size = 6074005, upload-time = "2025-07-01T09:13:47.829Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/3a/b13f36832ea6d279a697231658199e0a03cd87ef12048016bdcc84131601/pillow-11.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:040a5b691b0713e1f6cbe222e0f4f74cd233421e105850ae3b3c0ceda520f42e", size = 6708372, upload-time = "2025-07-01T09:13:52.145Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/e4/61b2e1a7528740efbc70b3d581f33937e38e98ef3d50b05007267a55bcb2/pillow-11.3.0-cp310-cp310-win32.whl", hash = "sha256:89bd777bc6624fe4115e9fac3352c79ed60f3bb18651420635f26e643e3dd1f6", size = 6277090, upload-time = "2025-07-01T09:13:53.915Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/d3/60c781c83a785d6afbd6a326ed4d759d141de43aa7365725cbcd65ce5e54/pillow-11.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:19d2ff547c75b8e3ff46f4d9ef969a06c30ab2d4263a9e287733aa8b2429ce8f", size = 6985988, upload-time = "2025-07-01T09:13:55.699Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/28/4f4a0203165eefb3763939c6789ba31013a2e90adffb456610f30f613850/pillow-11.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:819931d25e57b513242859ce1876c58c59dc31587847bf74cfe06b2e0cb22d2f", size = 2422899, upload-time = "2025-07-01T09:13:57.497Z" },
+ { url = "https://files.pythonhosted.org/packages/db/26/77f8ed17ca4ffd60e1dcd220a6ec6d71210ba398cfa33a13a1cd614c5613/pillow-11.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1cd110edf822773368b396281a2293aeb91c90a2db00d78ea43e7e861631b722", size = 5316531, upload-time = "2025-07-01T09:13:59.203Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/39/ee475903197ce709322a17a866892efb560f57900d9af2e55f86db51b0a5/pillow-11.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c412fddd1b77a75aa904615ebaa6001f169b26fd467b4be93aded278266b288", size = 4686560, upload-time = "2025-07-01T09:14:01.101Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/90/442068a160fd179938ba55ec8c97050a612426fae5ec0a764e345839f76d/pillow-11.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1aa4de119a0ecac0a34a9c8bde33f34022e2e8f99104e47a3ca392fd60e37d", size = 5870978, upload-time = "2025-07-03T13:09:55.638Z" },
+ { url = "https://files.pythonhosted.org/packages/13/92/dcdd147ab02daf405387f0218dcf792dc6dd5b14d2573d40b4caeef01059/pillow-11.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:91da1d88226663594e3f6b4b8c3c8d85bd504117d043740a8e0ec449087cc494", size = 7641168, upload-time = "2025-07-03T13:10:00.37Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/db/839d6ba7fd38b51af641aa904e2960e7a5644d60ec754c046b7d2aee00e5/pillow-11.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:643f189248837533073c405ec2f0bb250ba54598cf80e8c1e043381a60632f58", size = 5973053, upload-time = "2025-07-01T09:14:04.491Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/2f/d7675ecae6c43e9f12aa8d58b6012683b20b6edfbdac7abcb4e6af7a3784/pillow-11.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:106064daa23a745510dabce1d84f29137a37224831d88eb4ce94bb187b1d7e5f", size = 6640273, upload-time = "2025-07-01T09:14:06.235Z" },
+ { url = "https://files.pythonhosted.org/packages/45/ad/931694675ede172e15b2ff03c8144a0ddaea1d87adb72bb07655eaffb654/pillow-11.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd8ff254faf15591e724dc7c4ddb6bf4793efcbe13802a4ae3e863cd300b493e", size = 6082043, upload-time = "2025-07-01T09:14:07.978Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/04/ba8f2b11fc80d2dd462d7abec16351b45ec99cbbaea4387648a44190351a/pillow-11.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:932c754c2d51ad2b2271fd01c3d121daaa35e27efae2a616f77bf164bc0b3e94", size = 6715516, upload-time = "2025-07-01T09:14:10.233Z" },
+ { url = "https://files.pythonhosted.org/packages/48/59/8cd06d7f3944cc7d892e8533c56b0acb68399f640786313275faec1e3b6f/pillow-11.3.0-cp311-cp311-win32.whl", hash = "sha256:b4b8f3efc8d530a1544e5962bd6b403d5f7fe8b9e08227c6b255f98ad82b4ba0", size = 6274768, upload-time = "2025-07-01T09:14:11.921Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/cc/29c0f5d64ab8eae20f3232da8f8571660aa0ab4b8f1331da5c2f5f9a938e/pillow-11.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:1a992e86b0dd7aeb1f053cd506508c0999d710a8f07b4c791c63843fc6a807ac", size = 6986055, upload-time = "2025-07-01T09:14:13.623Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/df/90bd886fabd544c25addd63e5ca6932c86f2b701d5da6c7839387a076b4a/pillow-11.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:30807c931ff7c095620fe04448e2c2fc673fcbb1ffe2a7da3fb39613489b1ddd", size = 2423079, upload-time = "2025-07-01T09:14:15.268Z" },
+ { url = "https://files.pythonhosted.org/packages/40/fe/1bc9b3ee13f68487a99ac9529968035cca2f0a51ec36892060edcc51d06a/pillow-11.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4", size = 5278800, upload-time = "2025-07-01T09:14:17.648Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/32/7e2ac19b5713657384cec55f89065fb306b06af008cfd87e572035b27119/pillow-11.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69", size = 4686296, upload-time = "2025-07-01T09:14:19.828Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/1e/b9e12bbe6e4c2220effebc09ea0923a07a6da1e1f1bfbc8d7d29a01ce32b/pillow-11.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb76541cba2f958032d79d143b98a3a6b3ea87f0959bbe256c0b5e416599fd5d", size = 5871726, upload-time = "2025-07-03T13:10:04.448Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/33/e9200d2bd7ba00dc3ddb78df1198a6e80d7669cce6c2bdbeb2530a74ec58/pillow-11.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67172f2944ebba3d4a7b54f2e95c786a3a50c21b88456329314caaa28cda70f6", size = 7644652, upload-time = "2025-07-03T13:10:10.391Z" },
+ { url = "https://files.pythonhosted.org/packages/41/f1/6f2427a26fc683e00d985bc391bdd76d8dd4e92fac33d841127eb8fb2313/pillow-11.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7", size = 5977787, upload-time = "2025-07-01T09:14:21.63Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/c9/06dd4a38974e24f932ff5f98ea3c546ce3f8c995d3f0985f8e5ba48bba19/pillow-11.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024", size = 6645236, upload-time = "2025-07-01T09:14:23.321Z" },
+ { url = "https://files.pythonhosted.org/packages/40/e7/848f69fb79843b3d91241bad658e9c14f39a32f71a301bcd1d139416d1be/pillow-11.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809", size = 6086950, upload-time = "2025-07-01T09:14:25.237Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/1a/7cff92e695a2a29ac1958c2a0fe4c0b2393b60aac13b04a4fe2735cad52d/pillow-11.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d", size = 6723358, upload-time = "2025-07-01T09:14:27.053Z" },
+ { url = "https://files.pythonhosted.org/packages/26/7d/73699ad77895f69edff76b0f332acc3d497f22f5d75e5360f78cbcaff248/pillow-11.3.0-cp312-cp312-win32.whl", hash = "sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149", size = 6275079, upload-time = "2025-07-01T09:14:30.104Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/ce/e7dfc873bdd9828f3b6e5c2bbb74e47a98ec23cc5c74fc4e54462f0d9204/pillow-11.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d", size = 6986324, upload-time = "2025-07-01T09:14:31.899Z" },
+ { url = "https://files.pythonhosted.org/packages/16/8f/b13447d1bf0b1f7467ce7d86f6e6edf66c0ad7cf44cf5c87a37f9bed9936/pillow-11.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542", size = 2423067, upload-time = "2025-07-01T09:14:33.709Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/93/0952f2ed8db3a5a4c7a11f91965d6184ebc8cd7cbb7941a260d5f018cd2d/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd", size = 2128328, upload-time = "2025-07-01T09:14:35.276Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/e8/100c3d114b1a0bf4042f27e0f87d2f25e857e838034e98ca98fe7b8c0a9c/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8", size = 2170652, upload-time = "2025-07-01T09:14:37.203Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/86/3f758a28a6e381758545f7cdb4942e1cb79abd271bea932998fc0db93cb6/pillow-11.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f", size = 2227443, upload-time = "2025-07-01T09:14:39.344Z" },
+ { url = "https://files.pythonhosted.org/packages/01/f4/91d5b3ffa718df2f53b0dc109877993e511f4fd055d7e9508682e8aba092/pillow-11.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c", size = 5278474, upload-time = "2025-07-01T09:14:41.843Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/0e/37d7d3eca6c879fbd9dba21268427dffda1ab00d4eb05b32923d4fbe3b12/pillow-11.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd", size = 4686038, upload-time = "2025-07-01T09:14:44.008Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/b0/3426e5c7f6565e752d81221af9d3676fdbb4f352317ceafd42899aaf5d8a/pillow-11.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e", size = 5864407, upload-time = "2025-07-03T13:10:15.628Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/c1/c6c423134229f2a221ee53f838d4be9d82bab86f7e2f8e75e47b6bf6cd77/pillow-11.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1", size = 7639094, upload-time = "2025-07-03T13:10:21.857Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/c9/09e6746630fe6372c67c648ff9deae52a2bc20897d51fa293571977ceb5d/pillow-11.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805", size = 5973503, upload-time = "2025-07-01T09:14:45.698Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/1c/a2a29649c0b1983d3ef57ee87a66487fdeb45132df66ab30dd37f7dbe162/pillow-11.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8", size = 6642574, upload-time = "2025-07-01T09:14:47.415Z" },
+ { url = "https://files.pythonhosted.org/packages/36/de/d5cc31cc4b055b6c6fd990e3e7f0f8aaf36229a2698501bcb0cdf67c7146/pillow-11.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2", size = 6084060, upload-time = "2025-07-01T09:14:49.636Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/ea/502d938cbaeec836ac28a9b730193716f0114c41325db428e6b280513f09/pillow-11.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b", size = 6721407, upload-time = "2025-07-01T09:14:51.962Z" },
+ { url = "https://files.pythonhosted.org/packages/45/9c/9c5e2a73f125f6cbc59cc7087c8f2d649a7ae453f83bd0362ff7c9e2aee2/pillow-11.3.0-cp313-cp313-win32.whl", hash = "sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3", size = 6273841, upload-time = "2025-07-01T09:14:54.142Z" },
+ { url = "https://files.pythonhosted.org/packages/23/85/397c73524e0cd212067e0c969aa245b01d50183439550d24d9f55781b776/pillow-11.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51", size = 6978450, upload-time = "2025-07-01T09:14:56.436Z" },
+ { url = "https://files.pythonhosted.org/packages/17/d2/622f4547f69cd173955194b78e4d19ca4935a1b0f03a302d655c9f6aae65/pillow-11.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580", size = 2423055, upload-time = "2025-07-01T09:14:58.072Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/80/a8a2ac21dda2e82480852978416cfacd439a4b490a501a288ecf4fe2532d/pillow-11.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e", size = 5281110, upload-time = "2025-07-01T09:14:59.79Z" },
+ { url = "https://files.pythonhosted.org/packages/44/d6/b79754ca790f315918732e18f82a8146d33bcd7f4494380457ea89eb883d/pillow-11.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d", size = 4689547, upload-time = "2025-07-01T09:15:01.648Z" },
+ { url = "https://files.pythonhosted.org/packages/49/20/716b8717d331150cb00f7fdd78169c01e8e0c219732a78b0e59b6bdb2fd6/pillow-11.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced", size = 5901554, upload-time = "2025-07-03T13:10:27.018Z" },
+ { url = "https://files.pythonhosted.org/packages/74/cf/a9f3a2514a65bb071075063a96f0a5cf949c2f2fce683c15ccc83b1c1cab/pillow-11.3.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c", size = 7669132, upload-time = "2025-07-03T13:10:33.01Z" },
+ { url = "https://files.pythonhosted.org/packages/98/3c/da78805cbdbee9cb43efe8261dd7cc0b4b93f2ac79b676c03159e9db2187/pillow-11.3.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8", size = 6005001, upload-time = "2025-07-01T09:15:03.365Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/fa/ce044b91faecf30e635321351bba32bab5a7e034c60187fe9698191aef4f/pillow-11.3.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59", size = 6668814, upload-time = "2025-07-01T09:15:05.655Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/51/90f9291406d09bf93686434f9183aba27b831c10c87746ff49f127ee80cb/pillow-11.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe", size = 6113124, upload-time = "2025-07-01T09:15:07.358Z" },
+ { url = "https://files.pythonhosted.org/packages/cd/5a/6fec59b1dfb619234f7636d4157d11fb4e196caeee220232a8d2ec48488d/pillow-11.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c", size = 6747186, upload-time = "2025-07-01T09:15:09.317Z" },
+ { url = "https://files.pythonhosted.org/packages/49/6b/00187a044f98255225f172de653941e61da37104a9ea60e4f6887717e2b5/pillow-11.3.0-cp313-cp313t-win32.whl", hash = "sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788", size = 6277546, upload-time = "2025-07-01T09:15:11.311Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/5c/6caaba7e261c0d75bab23be79f1d06b5ad2a2ae49f028ccec801b0e853d6/pillow-11.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31", size = 6985102, upload-time = "2025-07-01T09:15:13.164Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/7e/b623008460c09a0cb38263c93b828c666493caee2eb34ff67f778b87e58c/pillow-11.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e", size = 2424803, upload-time = "2025-07-01T09:15:15.695Z" },
+ { url = "https://files.pythonhosted.org/packages/73/f4/04905af42837292ed86cb1b1dabe03dce1edc008ef14c473c5c7e1443c5d/pillow-11.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d9da3df5f9ea2a89b81bb6087177fb1f4d1c7146d583a3fe5c672c0d94e55e12", size = 5278520, upload-time = "2025-07-01T09:15:17.429Z" },
+ { url = "https://files.pythonhosted.org/packages/41/b0/33d79e377a336247df6348a54e6d2a2b85d644ca202555e3faa0cf811ecc/pillow-11.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0b275ff9b04df7b640c59ec5a3cb113eefd3795a8df80bac69646ef699c6981a", size = 4686116, upload-time = "2025-07-01T09:15:19.423Z" },
+ { url = "https://files.pythonhosted.org/packages/49/2d/ed8bc0ab219ae8768f529597d9509d184fe8a6c4741a6864fea334d25f3f/pillow-11.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0743841cabd3dba6a83f38a92672cccbd69af56e3e91777b0ee7f4dba4385632", size = 5864597, upload-time = "2025-07-03T13:10:38.404Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/3d/b932bb4225c80b58dfadaca9d42d08d0b7064d2d1791b6a237f87f661834/pillow-11.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2465a69cf967b8b49ee1b96d76718cd98c4e925414ead59fdf75cf0fd07df673", size = 7638246, upload-time = "2025-07-03T13:10:44.987Z" },
+ { url = "https://files.pythonhosted.org/packages/09/b5/0487044b7c096f1b48f0d7ad416472c02e0e4bf6919541b111efd3cae690/pillow-11.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41742638139424703b4d01665b807c6468e23e699e8e90cffefe291c5832b027", size = 5973336, upload-time = "2025-07-01T09:15:21.237Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/2d/524f9318f6cbfcc79fbc004801ea6b607ec3f843977652fdee4857a7568b/pillow-11.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93efb0b4de7e340d99057415c749175e24c8864302369e05914682ba642e5d77", size = 6642699, upload-time = "2025-07-01T09:15:23.186Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/d2/a9a4f280c6aefedce1e8f615baaa5474e0701d86dd6f1dede66726462bbd/pillow-11.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7966e38dcd0fa11ca390aed7c6f20454443581d758242023cf36fcb319b1a874", size = 6083789, upload-time = "2025-07-01T09:15:25.1Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/54/86b0cd9dbb683a9d5e960b66c7379e821a19be4ac5810e2e5a715c09a0c0/pillow-11.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:98a9afa7b9007c67ed84c57c9e0ad86a6000da96eaa638e4f8abe5b65ff83f0a", size = 6720386, upload-time = "2025-07-01T09:15:27.378Z" },
+ { url = "https://files.pythonhosted.org/packages/e7/95/88efcaf384c3588e24259c4203b909cbe3e3c2d887af9e938c2022c9dd48/pillow-11.3.0-cp314-cp314-win32.whl", hash = "sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214", size = 6370911, upload-time = "2025-07-01T09:15:29.294Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/cc/934e5820850ec5eb107e7b1a72dd278140731c669f396110ebc326f2a503/pillow-11.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:a418486160228f64dd9e9efcd132679b7a02a5f22c982c78b6fc7dab3fefb635", size = 7117383, upload-time = "2025-07-01T09:15:31.128Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/e9/9c0a616a71da2a5d163aa37405e8aced9a906d574b4a214bede134e731bc/pillow-11.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:155658efb5e044669c08896c0c44231c5e9abcaadbc5cd3648df2f7c0b96b9a6", size = 2511385, upload-time = "2025-07-01T09:15:33.328Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/33/c88376898aff369658b225262cd4f2659b13e8178e7534df9e6e1fa289f6/pillow-11.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:59a03cdf019efbfeeed910bf79c7c93255c3d54bc45898ac2a4140071b02b4ae", size = 5281129, upload-time = "2025-07-01T09:15:35.194Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/70/d376247fb36f1844b42910911c83a02d5544ebd2a8bad9efcc0f707ea774/pillow-11.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f8a5827f84d973d8636e9dc5764af4f0cf2318d26744b3d902931701b0d46653", size = 4689580, upload-time = "2025-07-01T09:15:37.114Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/1c/537e930496149fbac69efd2fc4329035bbe2e5475b4165439e3be9cb183b/pillow-11.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ee92f2fd10f4adc4b43d07ec5e779932b4eb3dbfbc34790ada5a6669bc095aa6", size = 5902860, upload-time = "2025-07-03T13:10:50.248Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/57/80f53264954dcefeebcf9dae6e3eb1daea1b488f0be8b8fef12f79a3eb10/pillow-11.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c96d333dcf42d01f47b37e0979b6bd73ec91eae18614864622d9b87bbd5bbf36", size = 7670694, upload-time = "2025-07-03T13:10:56.432Z" },
+ { url = "https://files.pythonhosted.org/packages/70/ff/4727d3b71a8578b4587d9c276e90efad2d6fe0335fd76742a6da08132e8c/pillow-11.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c96f993ab8c98460cd0c001447bff6194403e8b1d7e149ade5f00594918128b", size = 6005888, upload-time = "2025-07-01T09:15:39.436Z" },
+ { url = "https://files.pythonhosted.org/packages/05/ae/716592277934f85d3be51d7256f3636672d7b1abfafdc42cf3f8cbd4b4c8/pillow-11.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41342b64afeba938edb034d122b2dda5db2139b9a4af999729ba8818e0056477", size = 6670330, upload-time = "2025-07-01T09:15:41.269Z" },
+ { url = "https://files.pythonhosted.org/packages/e7/bb/7fe6cddcc8827b01b1a9766f5fdeb7418680744f9082035bdbabecf1d57f/pillow-11.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:068d9c39a2d1b358eb9f245ce7ab1b5c3246c7c8c7d9ba58cfa5b43146c06e50", size = 6114089, upload-time = "2025-07-01T09:15:43.13Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/f5/06bfaa444c8e80f1a8e4bff98da9c83b37b5be3b1deaa43d27a0db37ef84/pillow-11.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a1bc6ba083b145187f648b667e05a2534ecc4b9f2784c2cbe3089e44868f2b9b", size = 6748206, upload-time = "2025-07-01T09:15:44.937Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/77/bc6f92a3e8e6e46c0ca78abfffec0037845800ea38c73483760362804c41/pillow-11.3.0-cp314-cp314t-win32.whl", hash = "sha256:118ca10c0d60b06d006be10a501fd6bbdfef559251ed31b794668ed569c87e12", size = 6377370, upload-time = "2025-07-01T09:15:46.673Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/82/3a721f7d69dca802befb8af08b7c79ebcab461007ce1c18bd91a5d5896f9/pillow-11.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8924748b688aa210d79883357d102cd64690e56b923a186f35a82cbc10f997db", size = 7121500, upload-time = "2025-07-01T09:15:48.512Z" },
+ { url = "https://files.pythonhosted.org/packages/89/c7/5572fa4a3f45740eaab6ae86fcdf7195b55beac1371ac8c619d880cfe948/pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa", size = 2512835, upload-time = "2025-07-01T09:15:50.399Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/8e/9c089f01677d1264ab8648352dcb7773f37da6ad002542760c80107da816/pillow-11.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:48d254f8a4c776de343051023eb61ffe818299eeac478da55227d96e241de53f", size = 5316478, upload-time = "2025-07-01T09:15:52.209Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/a9/5749930caf674695867eb56a581e78eb5f524b7583ff10b01b6e5048acb3/pillow-11.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7aee118e30a4cf54fdd873bd3a29de51e29105ab11f9aad8c32123f58c8f8081", size = 4686522, upload-time = "2025-07-01T09:15:54.162Z" },
+ { url = "https://files.pythonhosted.org/packages/43/46/0b85b763eb292b691030795f9f6bb6fcaf8948c39413c81696a01c3577f7/pillow-11.3.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:23cff760a9049c502721bdb743a7cb3e03365fafcdfc2ef9784610714166e5a4", size = 5853376, upload-time = "2025-07-03T13:11:01.066Z" },
+ { url = "https://files.pythonhosted.org/packages/5e/c6/1a230ec0067243cbd60bc2dad5dc3ab46a8a41e21c15f5c9b52b26873069/pillow-11.3.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6359a3bc43f57d5b375d1ad54a0074318a0844d11b76abccf478c37c986d3cfc", size = 7626020, upload-time = "2025-07-03T13:11:06.479Z" },
+ { url = "https://files.pythonhosted.org/packages/63/dd/f296c27ffba447bfad76c6a0c44c1ea97a90cb9472b9304c94a732e8dbfb/pillow-11.3.0-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:092c80c76635f5ecb10f3f83d76716165c96f5229addbd1ec2bdbbda7d496e06", size = 5956732, upload-time = "2025-07-01T09:15:56.111Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/a0/98a3630f0b57f77bae67716562513d3032ae70414fcaf02750279c389a9e/pillow-11.3.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cadc9e0ea0a2431124cde7e1697106471fc4c1da01530e679b2391c37d3fbb3a", size = 6624404, upload-time = "2025-07-01T09:15:58.245Z" },
+ { url = "https://files.pythonhosted.org/packages/de/e6/83dfba5646a290edd9a21964da07674409e410579c341fc5b8f7abd81620/pillow-11.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6a418691000f2a418c9135a7cf0d797c1bb7d9a485e61fe8e7722845b95ef978", size = 6067760, upload-time = "2025-07-01T09:16:00.003Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/41/15ab268fe6ee9a2bc7391e2bbb20a98d3974304ab1a406a992dcb297a370/pillow-11.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:97afb3a00b65cc0804d1c7abddbf090a81eaac02768af58cbdcaaa0a931e0b6d", size = 6700534, upload-time = "2025-07-01T09:16:02.29Z" },
+ { url = "https://files.pythonhosted.org/packages/64/79/6d4f638b288300bed727ff29f2a3cb63db054b33518a95f27724915e3fbc/pillow-11.3.0-cp39-cp39-win32.whl", hash = "sha256:ea944117a7974ae78059fcc1800e5d3295172bb97035c0c1d9345fca1419da71", size = 6277091, upload-time = "2025-07-01T09:16:04.4Z" },
+ { url = "https://files.pythonhosted.org/packages/46/05/4106422f45a05716fd34ed21763f8ec182e8ea00af6e9cb05b93a247361a/pillow-11.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:e5c5858ad8ec655450a7c7df532e9842cf8df7cc349df7225c60d5d348c8aada", size = 6986091, upload-time = "2025-07-01T09:16:06.342Z" },
+ { url = "https://files.pythonhosted.org/packages/63/c6/287fd55c2c12761d0591549d48885187579b7c257bef0c6660755b0b59ae/pillow-11.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:6abdbfd3aea42be05702a8dd98832329c167ee84400a1d1f61ab11437f1717eb", size = 2422632, upload-time = "2025-07-01T09:16:08.142Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/8b/209bd6b62ce8367f47e68a218bffac88888fdf2c9fcf1ecadc6c3ec1ebc7/pillow-11.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3cee80663f29e3843b68199b9d6f4f54bd1d4a6b59bdd91bceefc51238bcb967", size = 5270556, upload-time = "2025-07-01T09:16:09.961Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/e6/231a0b76070c2cfd9e260a7a5b504fb72da0a95279410fa7afd99d9751d6/pillow-11.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b5f56c3f344f2ccaf0dd875d3e180f631dc60a51b314295a3e681fe8cf851fbe", size = 4654625, upload-time = "2025-07-01T09:16:11.913Z" },
+ { url = "https://files.pythonhosted.org/packages/13/f4/10cf94fda33cb12765f2397fc285fa6d8eb9c29de7f3185165b702fc7386/pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e67d793d180c9df62f1f40aee3accca4829d3794c95098887edc18af4b8b780c", size = 4874207, upload-time = "2025-07-03T13:11:10.201Z" },
+ { url = "https://files.pythonhosted.org/packages/72/c9/583821097dc691880c92892e8e2d41fe0a5a3d6021f4963371d2f6d57250/pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d000f46e2917c705e9fb93a3606ee4a819d1e3aa7a9b442f6444f07e77cf5e25", size = 6583939, upload-time = "2025-07-03T13:11:15.68Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/8e/5c9d410f9217b12320efc7c413e72693f48468979a013ad17fd690397b9a/pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:527b37216b6ac3a12d7838dc3bd75208ec57c1c6d11ef01902266a5a0c14fc27", size = 4957166, upload-time = "2025-07-01T09:16:13.74Z" },
+ { url = "https://files.pythonhosted.org/packages/62/bb/78347dbe13219991877ffb3a91bf09da8317fbfcd4b5f9140aeae020ad71/pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:be5463ac478b623b9dd3937afd7fb7ab3d79dd290a28e2b6df292dc75063eb8a", size = 5581482, upload-time = "2025-07-01T09:16:16.107Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/28/1000353d5e61498aaeaaf7f1e4b49ddb05f2c6575f9d4f9f914a3538b6e1/pillow-11.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:8dc70ca24c110503e16918a658b869019126ecfe03109b754c402daff12b3d9f", size = 6984596, upload-time = "2025-07-01T09:16:18.07Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/e3/6fa84033758276fb31da12e5fb66ad747ae83b93c67af17f8c6ff4cc8f34/pillow-11.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7c8ec7a017ad1bd562f93dbd8505763e688d388cde6e4a010ae1486916e713e6", size = 5270566, upload-time = "2025-07-01T09:16:19.801Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/ee/e8d2e1ab4892970b561e1ba96cbd59c0d28cf66737fc44abb2aec3795a4e/pillow-11.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:9ab6ae226de48019caa8074894544af5b53a117ccb9d3b3dcb2871464c829438", size = 4654618, upload-time = "2025-07-01T09:16:21.818Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/6d/17f80f4e1f0761f02160fc433abd4109fa1548dcfdca46cfdadaf9efa565/pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fe27fb049cdcca11f11a7bfda64043c37b30e6b91f10cb5bab275806c32f6ab3", size = 4874248, upload-time = "2025-07-03T13:11:20.738Z" },
+ { url = "https://files.pythonhosted.org/packages/de/5f/c22340acd61cef960130585bbe2120e2fd8434c214802f07e8c03596b17e/pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:465b9e8844e3c3519a983d58b80be3f668e2a7a5db97f2784e7079fbc9f9822c", size = 6583963, upload-time = "2025-07-03T13:11:26.283Z" },
+ { url = "https://files.pythonhosted.org/packages/31/5e/03966aedfbfcbb4d5f8aa042452d3361f325b963ebbadddac05b122e47dd/pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5418b53c0d59b3824d05e029669efa023bbef0f3e92e75ec8428f3799487f361", size = 4957170, upload-time = "2025-07-01T09:16:23.762Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/2d/e082982aacc927fc2cab48e1e731bdb1643a1406acace8bed0900a61464e/pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:504b6f59505f08ae014f724b6207ff6222662aab5cc9542577fb084ed0676ac7", size = 5581505, upload-time = "2025-07-01T09:16:25.593Z" },
+ { url = "https://files.pythonhosted.org/packages/34/e7/ae39f538fd6844e982063c3a5e4598b8ced43b9633baa3a85ef33af8c05c/pillow-11.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c84d689db21a1c397d001aa08241044aa2069e7587b398c8cc63020390b1c1b8", size = 6984598, upload-time = "2025-07-01T09:16:27.732Z" },
+]
+
+[[package]]
+name = "pillow"
+version = "12.1.1"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version >= '3.11'",
+ "python_full_version == '3.10.*'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/1f/42/5c74462b4fd957fcd7b13b04fb3205ff8349236ea74c7c375766d6c82288/pillow-12.1.1.tar.gz", hash = "sha256:9ad8fa5937ab05218e2b6a4cff30295ad35afd2f83ac592e68c0d871bb0fdbc4", size = 46980264, upload-time = "2026-02-11T04:23:07.146Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/1d/30/5bd3d794762481f8c8ae9c80e7b76ecea73b916959eb587521358ef0b2f9/pillow-12.1.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1f1625b72740fdda5d77b4def688eb8fd6490975d06b909fd19f13f391e077e0", size = 5304099, upload-time = "2026-02-11T04:20:06.13Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/c1/aab9e8f3eeb4490180e357955e15c2ef74b31f64790ff356c06fb6cf6d84/pillow-12.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:178aa072084bd88ec759052feca8e56cbb14a60b39322b99a049e58090479713", size = 4657880, upload-time = "2026-02-11T04:20:09.291Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/0a/9879e30d56815ad529d3985aeff5af4964202425c27261a6ada10f7cbf53/pillow-12.1.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b66e95d05ba806247aaa1561f080abc7975daf715c30780ff92a20e4ec546e1b", size = 6222587, upload-time = "2026-02-11T04:20:10.82Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/5f/a1b72ff7139e4f89014e8d451442c74a774d5c43cd938fb0a9f878576b37/pillow-12.1.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:89c7e895002bbe49cdc5426150377cbbc04767d7547ed145473f496dfa40408b", size = 8027678, upload-time = "2026-02-11T04:20:12.455Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/c2/c7cb187dac79a3d22c3ebeae727abee01e077c8c7d930791dc592f335153/pillow-12.1.1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a5cbdcddad0af3da87cb16b60d23648bc3b51967eb07223e9fed77a82b457c4", size = 6335777, upload-time = "2026-02-11T04:20:14.441Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/7b/f9b09a7804ec7336effb96c26d37c29d27225783dc1501b7d62dcef6ae25/pillow-12.1.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9f51079765661884a486727f0729d29054242f74b46186026582b4e4769918e4", size = 7027140, upload-time = "2026-02-11T04:20:16.387Z" },
+ { url = "https://files.pythonhosted.org/packages/98/b2/2fa3c391550bd421b10849d1a2144c44abcd966daadd2f7c12e19ea988c4/pillow-12.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:99c1506ea77c11531d75e3a412832a13a71c7ebc8192ab9e4b2e355555920e3e", size = 6449855, upload-time = "2026-02-11T04:20:18.554Z" },
+ { url = "https://files.pythonhosted.org/packages/96/ff/9caf4b5b950c669263c39e96c78c0d74a342c71c4f43fd031bb5cb7ceac9/pillow-12.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:36341d06738a9f66c8287cf8b876d24b18db9bd8740fa0672c74e259ad408cff", size = 7151329, upload-time = "2026-02-11T04:20:20.646Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/f8/4b24841f582704da675ca535935bccb32b00a6da1226820845fac4a71136/pillow-12.1.1-cp310-cp310-win32.whl", hash = "sha256:6c52f062424c523d6c4db85518774cc3d50f5539dd6eed32b8f6229b26f24d40", size = 6325574, upload-time = "2026-02-11T04:20:22.43Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/f9/9f6b01c0881d7036063aa6612ef04c0e2cad96be21325a1e92d0203f8e91/pillow-12.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:c6008de247150668a705a6338156efb92334113421ceecf7438a12c9a12dab23", size = 7032347, upload-time = "2026-02-11T04:20:23.932Z" },
+ { url = "https://files.pythonhosted.org/packages/79/13/c7922edded3dcdaf10c59297540b72785620abc0538872c819915746757d/pillow-12.1.1-cp310-cp310-win_arm64.whl", hash = "sha256:1a9b0ee305220b392e1124a764ee4265bd063e54a751a6b62eff69992f457fa9", size = 2453457, upload-time = "2026-02-11T04:20:25.392Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/46/5da1ec4a5171ee7bf1a0efa064aba70ba3d6e0788ce3f5acd1375d23c8c0/pillow-12.1.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:e879bb6cd5c73848ef3b2b48b8af9ff08c5b71ecda8048b7dd22d8a33f60be32", size = 5304084, upload-time = "2026-02-11T04:20:27.501Z" },
+ { url = "https://files.pythonhosted.org/packages/78/93/a29e9bc02d1cf557a834da780ceccd54e02421627200696fcf805ebdc3fb/pillow-12.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:365b10bb9417dd4498c0e3b128018c4a624dc11c7b97d8cc54effe3b096f4c38", size = 4657866, upload-time = "2026-02-11T04:20:29.827Z" },
+ { url = "https://files.pythonhosted.org/packages/13/84/583a4558d492a179d31e4aae32eadce94b9acf49c0337c4ce0b70e0a01f2/pillow-12.1.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d4ce8e329c93845720cd2014659ca67eac35f6433fd3050393d85f3ecef0dad5", size = 6232148, upload-time = "2026-02-11T04:20:31.329Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/e2/53c43334bbbb2d3b938978532fbda8e62bb6e0b23a26ce8592f36bcc4987/pillow-12.1.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc354a04072b765eccf2204f588a7a532c9511e8b9c7f900e1b64e3e33487090", size = 8038007, upload-time = "2026-02-11T04:20:34.225Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/a6/3d0e79c8a9d58150dd98e199d7c1c56861027f3829a3a60b3c2784190180/pillow-12.1.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7e7976bf1910a8116b523b9f9f58bf410f3e8aa330cd9a2bb2953f9266ab49af", size = 6345418, upload-time = "2026-02-11T04:20:35.858Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/c8/46dfeac5825e600579157eea177be43e2f7ff4a99da9d0d0a49533509ac5/pillow-12.1.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:597bd9c8419bc7c6af5604e55847789b69123bbe25d65cc6ad3012b4f3c98d8b", size = 7034590, upload-time = "2026-02-11T04:20:37.91Z" },
+ { url = "https://files.pythonhosted.org/packages/af/bf/e6f65d3db8a8bbfeaf9e13cc0417813f6319863a73de934f14b2229ada18/pillow-12.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2c1fc0f2ca5f96a3c8407e41cca26a16e46b21060fe6d5b099d2cb01412222f5", size = 6458655, upload-time = "2026-02-11T04:20:39.496Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/c2/66091f3f34a25894ca129362e510b956ef26f8fb67a0e6417bc5744e56f1/pillow-12.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:578510d88c6229d735855e1f278aa305270438d36a05031dfaae5067cc8eb04d", size = 7159286, upload-time = "2026-02-11T04:20:41.139Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/5a/24bc8eb526a22f957d0cec6243146744966d40857e3d8deb68f7902ca6c1/pillow-12.1.1-cp311-cp311-win32.whl", hash = "sha256:7311c0a0dcadb89b36b7025dfd8326ecfa36964e29913074d47382706e516a7c", size = 6328663, upload-time = "2026-02-11T04:20:43.184Z" },
+ { url = "https://files.pythonhosted.org/packages/31/03/bef822e4f2d8f9d7448c133d0a18185d3cce3e70472774fffefe8b0ed562/pillow-12.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:fbfa2a7c10cc2623f412753cddf391c7f971c52ca40a3f65dc5039b2939e8563", size = 7031448, upload-time = "2026-02-11T04:20:44.696Z" },
+ { url = "https://files.pythonhosted.org/packages/49/70/f76296f53610bd17b2e7d31728b8b7825e3ac3b5b3688b51f52eab7c0818/pillow-12.1.1-cp311-cp311-win_arm64.whl", hash = "sha256:b81b5e3511211631b3f672a595e3221252c90af017e399056d0faabb9538aa80", size = 2453651, upload-time = "2026-02-11T04:20:46.243Z" },
+ { url = "https://files.pythonhosted.org/packages/07/d3/8df65da0d4df36b094351dce696f2989bec731d4f10e743b1c5f4da4d3bf/pillow-12.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ab323b787d6e18b3d91a72fc99b1a2c28651e4358749842b8f8dfacd28ef2052", size = 5262803, upload-time = "2026-02-11T04:20:47.653Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/71/5026395b290ff404b836e636f51d7297e6c83beceaa87c592718747e670f/pillow-12.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:adebb5bee0f0af4909c30db0d890c773d1a92ffe83da908e2e9e720f8edf3984", size = 4657601, upload-time = "2026-02-11T04:20:49.328Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/2e/1001613d941c67442f745aff0f7cc66dd8df9a9c084eb497e6a543ee6f7e/pillow-12.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bb66b7cc26f50977108790e2456b7921e773f23db5630261102233eb355a3b79", size = 6234995, upload-time = "2026-02-11T04:20:51.032Z" },
+ { url = "https://files.pythonhosted.org/packages/07/26/246ab11455b2549b9233dbd44d358d033a2f780fa9007b61a913c5b2d24e/pillow-12.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aee2810642b2898bb187ced9b349e95d2a7272930796e022efaf12e99dccd293", size = 8045012, upload-time = "2026-02-11T04:20:52.882Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/8b/07587069c27be7535ac1fe33874e32de118fbd34e2a73b7f83436a88368c/pillow-12.1.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a0b1cd6232e2b618adcc54d9882e4e662a089d5768cd188f7c245b4c8c44a397", size = 6349638, upload-time = "2026-02-11T04:20:54.444Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/79/6df7b2ee763d619cda2fb4fea498e5f79d984dae304d45a8999b80d6cf5c/pillow-12.1.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7aac39bcf8d4770d089588a2e1dd111cbaa42df5a94be3114222057d68336bd0", size = 7041540, upload-time = "2026-02-11T04:20:55.97Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/5e/2ba19e7e7236d7529f4d873bdaf317a318896bac289abebd4bb00ef247f0/pillow-12.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ab174cd7d29a62dd139c44bf74b698039328f45cb03b4596c43473a46656b2f3", size = 6462613, upload-time = "2026-02-11T04:20:57.542Z" },
+ { url = "https://files.pythonhosted.org/packages/03/03/31216ec124bb5c3dacd74ce8efff4cc7f52643653bad4825f8f08c697743/pillow-12.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:339ffdcb7cbeaa08221cd401d517d4b1fe7a9ed5d400e4a8039719238620ca35", size = 7166745, upload-time = "2026-02-11T04:20:59.196Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/e7/7c4552d80052337eb28653b617eafdef39adfb137c49dd7e831b8dc13bc5/pillow-12.1.1-cp312-cp312-win32.whl", hash = "sha256:5d1f9575a12bed9e9eedd9a4972834b08c97a352bd17955ccdebfeca5913fa0a", size = 6328823, upload-time = "2026-02-11T04:21:01.385Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/17/688626d192d7261bbbf98846fc98995726bddc2c945344b65bec3a29d731/pillow-12.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:21329ec8c96c6e979cd0dfd29406c40c1d52521a90544463057d2aaa937d66a6", size = 7033367, upload-time = "2026-02-11T04:21:03.536Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/fe/a0ef1f73f939b0eca03ee2c108d0043a87468664770612602c63266a43c4/pillow-12.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:af9a332e572978f0218686636610555ae3defd1633597be015ed50289a03c523", size = 2453811, upload-time = "2026-02-11T04:21:05.116Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/11/6db24d4bd7685583caeae54b7009584e38da3c3d4488ed4cd25b439de486/pillow-12.1.1-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:d242e8ac078781f1de88bf823d70c1a9b3c7950a44cdf4b7c012e22ccbcd8e4e", size = 4062689, upload-time = "2026-02-11T04:21:06.804Z" },
+ { url = "https://files.pythonhosted.org/packages/33/c0/ce6d3b1fe190f0021203e0d9b5b99e57843e345f15f9ef22fcd43842fd21/pillow-12.1.1-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:02f84dfad02693676692746df05b89cf25597560db2857363a208e393429f5e9", size = 4138535, upload-time = "2026-02-11T04:21:08.452Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/c6/d5eb6a4fb32a3f9c21a8c7613ec706534ea1cf9f4b3663e99f0d83f6fca8/pillow-12.1.1-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:e65498daf4b583091ccbb2556c7000abf0f3349fcd57ef7adc9a84a394ed29f6", size = 3601364, upload-time = "2026-02-11T04:21:10.194Z" },
+ { url = "https://files.pythonhosted.org/packages/14/a1/16c4b823838ba4c9c52c0e6bbda903a3fe5a1bdbf1b8eb4fff7156f3e318/pillow-12.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c6db3b84c87d48d0088943bf33440e0c42370b99b1c2a7989216f7b42eede60", size = 5262561, upload-time = "2026-02-11T04:21:11.742Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/ad/ad9dc98ff24f485008aa5cdedaf1a219876f6f6c42a4626c08bc4e80b120/pillow-12.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8b7e5304e34942bf62e15184219a7b5ad4ff7f3bb5cca4d984f37df1a0e1aee2", size = 4657460, upload-time = "2026-02-11T04:21:13.786Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/1b/f1a4ea9a895b5732152789326202a82464d5254759fbacae4deea3069334/pillow-12.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:18e5bddd742a44b7e6b1e773ab5db102bd7a94c32555ba656e76d319d19c3850", size = 6232698, upload-time = "2026-02-11T04:21:15.949Z" },
+ { url = "https://files.pythonhosted.org/packages/95/f4/86f51b8745070daf21fd2e5b1fe0eb35d4db9ca26e6d58366562fb56a743/pillow-12.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc44ef1f3de4f45b50ccf9136999d71abb99dca7706bc75d222ed350b9fd2289", size = 8041706, upload-time = "2026-02-11T04:21:17.723Z" },
+ { url = "https://files.pythonhosted.org/packages/29/9b/d6ecd956bb1266dd1045e995cce9b8d77759e740953a1c9aad9502a0461e/pillow-12.1.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5a8eb7ed8d4198bccbd07058416eeec51686b498e784eda166395a23eb99138e", size = 6346621, upload-time = "2026-02-11T04:21:19.547Z" },
+ { url = "https://files.pythonhosted.org/packages/71/24/538bff45bde96535d7d998c6fed1a751c75ac7c53c37c90dc2601b243893/pillow-12.1.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:47b94983da0c642de92ced1702c5b6c292a84bd3a8e1d1702ff923f183594717", size = 7038069, upload-time = "2026-02-11T04:21:21.378Z" },
+ { url = "https://files.pythonhosted.org/packages/94/0e/58cb1a6bc48f746bc4cb3adb8cabff73e2742c92b3bf7a220b7cf69b9177/pillow-12.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:518a48c2aab7ce596d3bf79d0e275661b846e86e4d0e7dec34712c30fe07f02a", size = 6460040, upload-time = "2026-02-11T04:21:23.148Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/57/9045cb3ff11eeb6c1adce3b2d60d7d299d7b273a2e6c8381a524abfdc474/pillow-12.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a550ae29b95c6dc13cf69e2c9dc5747f814c54eeb2e32d683e5e93af56caa029", size = 7164523, upload-time = "2026-02-11T04:21:25.01Z" },
+ { url = "https://files.pythonhosted.org/packages/73/f2/9be9cb99f2175f0d4dbadd6616ce1bf068ee54a28277ea1bf1fbf729c250/pillow-12.1.1-cp313-cp313-win32.whl", hash = "sha256:a003d7422449f6d1e3a34e3dd4110c22148336918ddbfc6a32581cd54b2e0b2b", size = 6332552, upload-time = "2026-02-11T04:21:27.238Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/eb/b0834ad8b583d7d9d42b80becff092082a1c3c156bb582590fcc973f1c7c/pillow-12.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:344cf1e3dab3be4b1fa08e449323d98a2a3f819ad20f4b22e77a0ede31f0faa1", size = 7040108, upload-time = "2026-02-11T04:21:29.462Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/7d/fc09634e2aabdd0feabaff4a32f4a7d97789223e7c2042fd805ea4b4d2c2/pillow-12.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:5c0dd1636633e7e6a0afe7bf6a51a14992b7f8e60de5789018ebbdfae55b040a", size = 2453712, upload-time = "2026-02-11T04:21:31.072Z" },
+ { url = "https://files.pythonhosted.org/packages/19/2a/b9d62794fc8a0dd14c1943df68347badbd5511103e0d04c035ffe5cf2255/pillow-12.1.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0330d233c1a0ead844fc097a7d16c0abff4c12e856c0b325f231820fee1f39da", size = 5264880, upload-time = "2026-02-11T04:21:32.865Z" },
+ { url = "https://files.pythonhosted.org/packages/26/9d/e03d857d1347fa5ed9247e123fcd2a97b6220e15e9cb73ca0a8d91702c6e/pillow-12.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5dae5f21afb91322f2ff791895ddd8889e5e947ff59f71b46041c8ce6db790bc", size = 4660616, upload-time = "2026-02-11T04:21:34.97Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/ec/8a6d22afd02570d30954e043f09c32772bfe143ba9285e2fdb11284952cd/pillow-12.1.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2e0c664be47252947d870ac0d327fea7e63985a08794758aa8af5b6cb6ec0c9c", size = 6269008, upload-time = "2026-02-11T04:21:36.623Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/1d/6d875422c9f28a4a361f495a5f68d9de4a66941dc2c619103ca335fa6446/pillow-12.1.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:691ab2ac363b8217f7d31b3497108fb1f50faab2f75dfb03284ec2f217e87bf8", size = 8073226, upload-time = "2026-02-11T04:21:38.585Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/cd/134b0b6ee5eda6dc09e25e24b40fdafe11a520bc725c1d0bbaa5e00bf95b/pillow-12.1.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e9e8064fb1cc019296958595f6db671fba95209e3ceb0c4734c9baf97de04b20", size = 6380136, upload-time = "2026-02-11T04:21:40.562Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/a9/7628f013f18f001c1b98d8fffe3452f306a70dc6aba7d931019e0492f45e/pillow-12.1.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:472a8d7ded663e6162dafdf20015c486a7009483ca671cece7a9279b512fcb13", size = 7067129, upload-time = "2026-02-11T04:21:42.521Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/f8/66ab30a2193b277785601e82ee2d49f68ea575d9637e5e234faaa98efa4c/pillow-12.1.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:89b54027a766529136a06cfebeecb3a04900397a3590fd252160b888479517bf", size = 6491807, upload-time = "2026-02-11T04:21:44.22Z" },
+ { url = "https://files.pythonhosted.org/packages/da/0b/a877a6627dc8318fdb84e357c5e1a758c0941ab1ddffdafd231983788579/pillow-12.1.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:86172b0831b82ce4f7877f280055892b31179e1576aa00d0df3bb1bbf8c3e524", size = 7190954, upload-time = "2026-02-11T04:21:46.114Z" },
+ { url = "https://files.pythonhosted.org/packages/83/43/6f732ff85743cf746b1361b91665d9f5155e1483817f693f8d57ea93147f/pillow-12.1.1-cp313-cp313t-win32.whl", hash = "sha256:44ce27545b6efcf0fdbdceb31c9a5bdea9333e664cda58a7e674bb74608b3986", size = 6336441, upload-time = "2026-02-11T04:21:48.22Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/44/e865ef3986611bb75bfabdf94a590016ea327833f434558801122979cd0e/pillow-12.1.1-cp313-cp313t-win_amd64.whl", hash = "sha256:a285e3eb7a5a45a2ff504e31f4a8d1b12ef62e84e5411c6804a42197c1cf586c", size = 7045383, upload-time = "2026-02-11T04:21:50.015Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/c6/f4fb24268d0c6908b9f04143697ea18b0379490cb74ba9e8d41b898bd005/pillow-12.1.1-cp313-cp313t-win_arm64.whl", hash = "sha256:cc7d296b5ea4d29e6570dabeaed58d31c3fea35a633a69679fb03d7664f43fb3", size = 2456104, upload-time = "2026-02-11T04:21:51.633Z" },
+ { url = "https://files.pythonhosted.org/packages/03/d0/bebb3ffbf31c5a8e97241476c4cf8b9828954693ce6744b4a2326af3e16b/pillow-12.1.1-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:417423db963cb4be8bac3fc1204fe61610f6abeed1580a7a2cbb2fbda20f12af", size = 4062652, upload-time = "2026-02-11T04:21:53.19Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/c0/0e16fb0addda4851445c28f8350d8c512f09de27bbb0d6d0bbf8b6709605/pillow-12.1.1-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:b957b71c6b2387610f556a7eb0828afbe40b4a98036fc0d2acfa5a44a0c2036f", size = 4138823, upload-time = "2026-02-11T04:22:03.088Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/fb/6170ec655d6f6bb6630a013dd7cf7bc218423d7b5fa9071bf63dc32175ae/pillow-12.1.1-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:097690ba1f2efdeb165a20469d59d8bb03c55fb6621eb2041a060ae8ea3e9642", size = 3601143, upload-time = "2026-02-11T04:22:04.909Z" },
+ { url = "https://files.pythonhosted.org/packages/59/04/dc5c3f297510ba9a6837cbb318b87dd2b8f73eb41a43cc63767f65cb599c/pillow-12.1.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:2815a87ab27848db0321fb78c7f0b2c8649dee134b7f2b80c6a45c6831d75ccd", size = 5266254, upload-time = "2026-02-11T04:22:07.656Z" },
+ { url = "https://files.pythonhosted.org/packages/05/30/5db1236b0d6313f03ebf97f5e17cda9ca060f524b2fcc875149a8360b21c/pillow-12.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f7ed2c6543bad5a7d5530eb9e78c53132f93dfa44a28492db88b41cdab885202", size = 4657499, upload-time = "2026-02-11T04:22:09.613Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/18/008d2ca0eb612e81968e8be0bbae5051efba24d52debf930126d7eaacbba/pillow-12.1.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:652a2c9ccfb556235b2b501a3a7cf3742148cd22e04b5625c5fe057ea3e3191f", size = 6232137, upload-time = "2026-02-11T04:22:11.434Z" },
+ { url = "https://files.pythonhosted.org/packages/70/f1/f14d5b8eeb4b2cd62b9f9f847eb6605f103df89ef619ac68f92f748614ea/pillow-12.1.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d6e4571eedf43af33d0fc233a382a76e849badbccdf1ac438841308652a08e1f", size = 8042721, upload-time = "2026-02-11T04:22:13.321Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/d6/17824509146e4babbdabf04d8171491fa9d776f7061ff6e727522df9bd03/pillow-12.1.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b574c51cf7d5d62e9be37ba446224b59a2da26dc4c1bb2ecbe936a4fb1a7cb7f", size = 6347798, upload-time = "2026-02-11T04:22:15.449Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/ee/c85a38a9ab92037a75615aba572c85ea51e605265036e00c5b67dfafbfe2/pillow-12.1.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a37691702ed687799de29a518d63d4682d9016932db66d4e90c345831b02fb4e", size = 7039315, upload-time = "2026-02-11T04:22:17.24Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/f3/bc8ccc6e08a148290d7523bde4d9a0d6c981db34631390dc6e6ec34cacf6/pillow-12.1.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f95c00d5d6700b2b890479664a06e754974848afaae5e21beb4d83c106923fd0", size = 6462360, upload-time = "2026-02-11T04:22:19.111Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/ab/69a42656adb1d0665ab051eec58a41f169ad295cf81ad45406963105408f/pillow-12.1.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:559b38da23606e68681337ad74622c4dbba02254fc9cb4488a305dd5975c7eeb", size = 7165438, upload-time = "2026-02-11T04:22:21.041Z" },
+ { url = "https://files.pythonhosted.org/packages/02/46/81f7aa8941873f0f01d4b55cc543b0a3d03ec2ee30d617a0448bf6bd6dec/pillow-12.1.1-cp314-cp314-win32.whl", hash = "sha256:03edcc34d688572014ff223c125a3f77fb08091e4607e7745002fc214070b35f", size = 6431503, upload-time = "2026-02-11T04:22:22.833Z" },
+ { url = "https://files.pythonhosted.org/packages/40/72/4c245f7d1044b67affc7f134a09ea619d4895333d35322b775b928180044/pillow-12.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:50480dcd74fa63b8e78235957d302d98d98d82ccbfac4c7e12108ba9ecbdba15", size = 7176748, upload-time = "2026-02-11T04:22:24.64Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/ad/8a87bdbe038c5c698736e3348af5c2194ffb872ea52f11894c95f9305435/pillow-12.1.1-cp314-cp314-win_arm64.whl", hash = "sha256:5cb1785d97b0c3d1d1a16bc1d710c4a0049daefc4935f3a8f31f827f4d3d2e7f", size = 2544314, upload-time = "2026-02-11T04:22:26.685Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/9d/efd18493f9de13b87ede7c47e69184b9e859e4427225ea962e32e56a49bc/pillow-12.1.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:1f90cff8aa76835cba5769f0b3121a22bd4eb9e6884cfe338216e557a9a548b8", size = 5268612, upload-time = "2026-02-11T04:22:29.884Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/f1/4f42eb2b388eb2ffc660dcb7f7b556c1015c53ebd5f7f754965ef997585b/pillow-12.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1f1be78ce9466a7ee64bfda57bdba0f7cc499d9794d518b854816c41bf0aa4e9", size = 4660567, upload-time = "2026-02-11T04:22:31.799Z" },
+ { url = "https://files.pythonhosted.org/packages/01/54/df6ef130fa43e4b82e32624a7b821a2be1c5653a5fdad8469687a7db4e00/pillow-12.1.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:42fc1f4677106188ad9a55562bbade416f8b55456f522430fadab3cef7cd4e60", size = 6269951, upload-time = "2026-02-11T04:22:33.921Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/48/618752d06cc44bb4aae8ce0cd4e6426871929ed7b46215638088270d9b34/pillow-12.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:98edb152429ab62a1818039744d8fbb3ccab98a7c29fc3d5fcef158f3f1f68b7", size = 8074769, upload-time = "2026-02-11T04:22:35.877Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/bd/f1d71eb39a72fa088d938655afba3e00b38018d052752f435838961127d8/pillow-12.1.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d470ab1178551dd17fdba0fef463359c41aaa613cdcd7ff8373f54be629f9f8f", size = 6381358, upload-time = "2026-02-11T04:22:37.698Z" },
+ { url = "https://files.pythonhosted.org/packages/64/ef/c784e20b96674ed36a5af839305f55616f8b4f8aa8eeccf8531a6e312243/pillow-12.1.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6408a7b064595afcab0a49393a413732a35788f2a5092fdc6266952ed67de586", size = 7068558, upload-time = "2026-02-11T04:22:39.597Z" },
+ { url = "https://files.pythonhosted.org/packages/73/cb/8059688b74422ae61278202c4e1ad992e8a2e7375227be0a21c6b87ca8d5/pillow-12.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5d8c41325b382c07799a3682c1c258469ea2ff97103c53717b7893862d0c98ce", size = 6493028, upload-time = "2026-02-11T04:22:42.73Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/da/e3c008ed7d2dd1f905b15949325934510b9d1931e5df999bb15972756818/pillow-12.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c7697918b5be27424e9ce568193efd13d925c4481dd364e43f5dff72d33e10f8", size = 7191940, upload-time = "2026-02-11T04:22:44.543Z" },
+ { url = "https://files.pythonhosted.org/packages/01/4a/9202e8d11714c1fc5951f2e1ef362f2d7fbc595e1f6717971d5dd750e969/pillow-12.1.1-cp314-cp314t-win32.whl", hash = "sha256:d2912fd8114fc5545aa3a4b5576512f64c55a03f3ebcca4c10194d593d43ea36", size = 6438736, upload-time = "2026-02-11T04:22:46.347Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/ca/cbce2327eb9885476b3957b2e82eb12c866a8b16ad77392864ad601022ce/pillow-12.1.1-cp314-cp314t-win_amd64.whl", hash = "sha256:4ceb838d4bd9dab43e06c363cab2eebf63846d6a4aeaea283bbdfd8f1a8ed58b", size = 7182894, upload-time = "2026-02-11T04:22:48.114Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/d2/de599c95ba0a973b94410477f8bf0b6f0b5e67360eb89bcb1ad365258beb/pillow-12.1.1-cp314-cp314t-win_arm64.whl", hash = "sha256:7b03048319bfc6170e93bd60728a1af51d3dd7704935feb228c4d4faab35d334", size = 2546446, upload-time = "2026-02-11T04:22:50.342Z" },
+ { url = "https://files.pythonhosted.org/packages/56/11/5d43209aa4cb58e0cc80127956ff1796a68b928e6324bbf06ef4db34367b/pillow-12.1.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:600fd103672b925fe62ed08e0d874ea34d692474df6f4bf7ebe148b30f89f39f", size = 5228606, upload-time = "2026-02-11T04:22:52.106Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/d5/3b005b4e4fda6698b371fa6c21b097d4707585d7db99e98d9b0b87ac612a/pillow-12.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:665e1b916b043cef294bc54d47bf02d87e13f769bc4bc5fa225a24b3a6c5aca9", size = 4622321, upload-time = "2026-02-11T04:22:53.827Z" },
+ { url = "https://files.pythonhosted.org/packages/df/36/ed3ea2d594356fd8037e5a01f6156c74bc8d92dbb0fa60746cc96cabb6e8/pillow-12.1.1-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:495c302af3aad1ca67420ddd5c7bd480c8867ad173528767d906428057a11f0e", size = 5247579, upload-time = "2026-02-11T04:22:56.094Z" },
+ { url = "https://files.pythonhosted.org/packages/54/9a/9cc3e029683cf6d20ae5085da0dafc63148e3252c2f13328e553aaa13cfb/pillow-12.1.1-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8fd420ef0c52c88b5a035a0886f367748c72147b2b8f384c9d12656678dfdfa9", size = 6989094, upload-time = "2026-02-11T04:22:58.288Z" },
+ { url = "https://files.pythonhosted.org/packages/00/98/fc53ab36da80b88df0967896b6c4b4cd948a0dc5aa40a754266aa3ae48b3/pillow-12.1.1-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f975aa7ef9684ce7e2c18a3aa8f8e2106ce1e46b94ab713d156b2898811651d3", size = 5313850, upload-time = "2026-02-11T04:23:00.554Z" },
+ { url = "https://files.pythonhosted.org/packages/30/02/00fa585abfd9fe9d73e5f6e554dc36cc2b842898cbfc46d70353dae227f8/pillow-12.1.1-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8089c852a56c2966cf18835db62d9b34fef7ba74c726ad943928d494fa7f4735", size = 5963343, upload-time = "2026-02-11T04:23:02.934Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/26/c56ce33ca856e358d27fda9676c055395abddb82c35ac0f593877ed4562e/pillow-12.1.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:cb9bb857b2d057c6dfc72ac5f3b44836924ba15721882ef103cecb40d002d80e", size = 7029880, upload-time = "2026-02-11T04:23:04.783Z" },
+]
+
+[[package]]
+name = "platformdirs"
+version = "4.4.0"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version < '3.10'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/23/e8/21db9c9987b0e728855bd57bff6984f67952bea55d6f75e055c46b5383e8/platformdirs-4.4.0.tar.gz", hash = "sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf", size = 21634, upload-time = "2025-08-26T14:32:04.268Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/40/4b/2028861e724d3bd36227adfa20d3fd24c3fc6d52032f4a93c133be5d17ce/platformdirs-4.4.0-py3-none-any.whl", hash = "sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85", size = 18654, upload-time = "2025-08-26T14:32:02.735Z" },
+]
+
+[[package]]
+name = "platformdirs"
+version = "4.9.2"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version >= '3.11'",
+ "python_full_version == '3.10.*'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/1b/04/fea538adf7dbbd6d186f551d595961e564a3b6715bdf276b477460858672/platformdirs-4.9.2.tar.gz", hash = "sha256:9a33809944b9db043ad67ca0db94b14bf452cc6aeaac46a88ea55b26e2e9d291", size = 28394, upload-time = "2026-02-16T03:56:10.574Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/48/31/05e764397056194206169869b50cf2fee4dbbbc71b344705b9c0d878d4d8/platformdirs-4.9.2-py3-none-any.whl", hash = "sha256:9170634f126f8efdae22fb58ae8a0eaa86f38365bc57897a6c4f781d1f5875bd", size = 21168, upload-time = "2026-02-16T03:56:08.891Z" },
+]
+
+[[package]]
+name = "pluggy"
+version = "1.6.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
+]
+
+[[package]]
+name = "prompt-toolkit"
+version = "3.0.52"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "wcwidth" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" },
+]
+
+[[package]]
+name = "propcache"
+version = "0.4.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442, upload-time = "2025-10-08T19:49:02.291Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3c/0e/934b541323035566a9af292dba85a195f7b78179114f2c6ebb24551118a9/propcache-0.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c2d1fa3201efaf55d730400d945b5b3ab6e672e100ba0f9a409d950ab25d7db", size = 79534, upload-time = "2025-10-08T19:46:02.083Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/6b/db0d03d96726d995dc7171286c6ba9d8d14251f37433890f88368951a44e/propcache-0.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1eb2994229cc8ce7fe9b3db88f5465f5fd8651672840b2e426b88cdb1a30aac8", size = 45526, upload-time = "2025-10-08T19:46:03.884Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/c3/82728404aea669e1600f304f2609cde9e665c18df5a11cdd57ed73c1dceb/propcache-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:66c1f011f45a3b33d7bcb22daed4b29c0c9e2224758b6be00686731e1b46f925", size = 47263, upload-time = "2025-10-08T19:46:05.405Z" },
+ { url = "https://files.pythonhosted.org/packages/df/1b/39313ddad2bf9187a1432654c38249bab4562ef535ef07f5eb6eb04d0b1b/propcache-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9a52009f2adffe195d0b605c25ec929d26b36ef986ba85244891dee3b294df21", size = 201012, upload-time = "2025-10-08T19:46:07.165Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/01/f1d0b57d136f294a142acf97f4ed58c8e5b974c21e543000968357115011/propcache-0.4.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5d4e2366a9c7b837555cf02fb9be2e3167d333aff716332ef1b7c3a142ec40c5", size = 209491, upload-time = "2025-10-08T19:46:08.909Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/c8/038d909c61c5bb039070b3fb02ad5cccdb1dde0d714792e251cdb17c9c05/propcache-0.4.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9d2b6caef873b4f09e26ea7e33d65f42b944837563a47a94719cc3544319a0db", size = 215319, upload-time = "2025-10-08T19:46:10.7Z" },
+ { url = "https://files.pythonhosted.org/packages/08/57/8c87e93142b2c1fa2408e45695205a7ba05fb5db458c0bf5c06ba0e09ea6/propcache-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b16ec437a8c8a965ecf95739448dd938b5c7f56e67ea009f4300d8df05f32b7", size = 196856, upload-time = "2025-10-08T19:46:12.003Z" },
+ { url = "https://files.pythonhosted.org/packages/42/df/5615fec76aa561987a534759b3686008a288e73107faa49a8ae5795a9f7a/propcache-0.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:296f4c8ed03ca7476813fe666c9ea97869a8d7aec972618671b33a38a5182ef4", size = 193241, upload-time = "2025-10-08T19:46:13.495Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/21/62949eb3a7a54afe8327011c90aca7e03547787a88fb8bd9726806482fea/propcache-0.4.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1f0978529a418ebd1f49dad413a2b68af33f85d5c5ca5c6ca2a3bed375a7ac60", size = 190552, upload-time = "2025-10-08T19:46:14.938Z" },
+ { url = "https://files.pythonhosted.org/packages/30/ee/ab4d727dd70806e5b4de96a798ae7ac6e4d42516f030ee60522474b6b332/propcache-0.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fd138803047fb4c062b1c1dd95462f5209456bfab55c734458f15d11da288f8f", size = 200113, upload-time = "2025-10-08T19:46:16.695Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/0b/38b46208e6711b016aa8966a3ac793eee0d05c7159d8342aa27fc0bc365e/propcache-0.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8c9b3cbe4584636d72ff556d9036e0c9317fa27b3ac1f0f558e7e84d1c9c5900", size = 200778, upload-time = "2025-10-08T19:46:18.023Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/81/5abec54355ed344476bee711e9f04815d4b00a311ab0535599204eecc257/propcache-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f93243fdc5657247533273ac4f86ae106cc6445a0efacb9a1bfe982fcfefd90c", size = 193047, upload-time = "2025-10-08T19:46:19.449Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/b6/1f237c04e32063cb034acd5f6ef34ef3a394f75502e72703545631ab1ef6/propcache-0.4.1-cp310-cp310-win32.whl", hash = "sha256:a0ee98db9c5f80785b266eb805016e36058ac72c51a064040f2bc43b61101cdb", size = 38093, upload-time = "2025-10-08T19:46:20.643Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/67/354aac4e0603a15f76439caf0427781bcd6797f370377f75a642133bc954/propcache-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:1cdb7988c4e5ac7f6d175a28a9aa0c94cb6f2ebe52756a3c0cda98d2809a9e37", size = 41638, upload-time = "2025-10-08T19:46:21.935Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/e1/74e55b9fd1a4c209ff1a9a824bf6c8b3d1fc5a1ac3eabe23462637466785/propcache-0.4.1-cp310-cp310-win_arm64.whl", hash = "sha256:d82ad62b19645419fe79dd63b3f9253e15b30e955c0170e5cebc350c1844e581", size = 38229, upload-time = "2025-10-08T19:46:23.368Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/d4/4e2c9aaf7ac2242b9358f98dccd8f90f2605402f5afeff6c578682c2c491/propcache-0.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:60a8fda9644b7dfd5dece8c61d8a85e271cb958075bfc4e01083c148b61a7caf", size = 80208, upload-time = "2025-10-08T19:46:24.597Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/21/d7b68e911f9c8e18e4ae43bdbc1e1e9bbd971f8866eb81608947b6f585ff/propcache-0.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c30b53e7e6bda1d547cabb47c825f3843a0a1a42b0496087bb58d8fedf9f41b5", size = 45777, upload-time = "2025-10-08T19:46:25.733Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/1d/11605e99ac8ea9435651ee71ab4cb4bf03f0949586246476a25aadfec54a/propcache-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6918ecbd897443087a3b7cd978d56546a812517dcaaca51b49526720571fa93e", size = 47647, upload-time = "2025-10-08T19:46:27.304Z" },
+ { url = "https://files.pythonhosted.org/packages/58/1a/3c62c127a8466c9c843bccb503d40a273e5cc69838805f322e2826509e0d/propcache-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d902a36df4e5989763425a8ab9e98cd8ad5c52c823b34ee7ef307fd50582566", size = 214929, upload-time = "2025-10-08T19:46:28.62Z" },
+ { url = "https://files.pythonhosted.org/packages/56/b9/8fa98f850960b367c4b8fe0592e7fc341daa7a9462e925228f10a60cf74f/propcache-0.4.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a9695397f85973bb40427dedddf70d8dc4a44b22f1650dd4af9eedf443d45165", size = 221778, upload-time = "2025-10-08T19:46:30.358Z" },
+ { url = "https://files.pythonhosted.org/packages/46/a6/0ab4f660eb59649d14b3d3d65c439421cf2f87fe5dd68591cbe3c1e78a89/propcache-0.4.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2bb07ffd7eaad486576430c89f9b215f9e4be68c4866a96e97db9e97fead85dc", size = 228144, upload-time = "2025-10-08T19:46:32.607Z" },
+ { url = "https://files.pythonhosted.org/packages/52/6a/57f43e054fb3d3a56ac9fc532bc684fc6169a26c75c353e65425b3e56eef/propcache-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd6f30fdcf9ae2a70abd34da54f18da086160e4d7d9251f81f3da0ff84fc5a48", size = 210030, upload-time = "2025-10-08T19:46:33.969Z" },
+ { url = "https://files.pythonhosted.org/packages/40/e2/27e6feebb5f6b8408fa29f5efbb765cd54c153ac77314d27e457a3e993b7/propcache-0.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fc38cba02d1acba4e2869eef1a57a43dfbd3d49a59bf90dda7444ec2be6a5570", size = 208252, upload-time = "2025-10-08T19:46:35.309Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/f8/91c27b22ccda1dbc7967f921c42825564fa5336a01ecd72eb78a9f4f53c2/propcache-0.4.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:67fad6162281e80e882fb3ec355398cf72864a54069d060321f6cd0ade95fe85", size = 202064, upload-time = "2025-10-08T19:46:36.993Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/26/7f00bd6bd1adba5aafe5f4a66390f243acab58eab24ff1a08bebb2ef9d40/propcache-0.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f10207adf04d08bec185bae14d9606a1444715bc99180f9331c9c02093e1959e", size = 212429, upload-time = "2025-10-08T19:46:38.398Z" },
+ { url = "https://files.pythonhosted.org/packages/84/89/fd108ba7815c1117ddca79c228f3f8a15fc82a73bca8b142eb5de13b2785/propcache-0.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e9b0d8d0845bbc4cfcdcbcdbf5086886bc8157aa963c31c777ceff7846c77757", size = 216727, upload-time = "2025-10-08T19:46:39.732Z" },
+ { url = "https://files.pythonhosted.org/packages/79/37/3ec3f7e3173e73f1d600495d8b545b53802cbf35506e5732dd8578db3724/propcache-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:981333cb2f4c1896a12f4ab92a9cc8f09ea664e9b7dbdc4eff74627af3a11c0f", size = 205097, upload-time = "2025-10-08T19:46:41.025Z" },
+ { url = "https://files.pythonhosted.org/packages/61/b0/b2631c19793f869d35f47d5a3a56fb19e9160d3c119f15ac7344fc3ccae7/propcache-0.4.1-cp311-cp311-win32.whl", hash = "sha256:f1d2f90aeec838a52f1c1a32fe9a619fefd5e411721a9117fbf82aea638fe8a1", size = 38084, upload-time = "2025-10-08T19:46:42.693Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/78/6cce448e2098e9f3bfc91bb877f06aa24b6ccace872e39c53b2f707c4648/propcache-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:364426a62660f3f699949ac8c621aad6977be7126c5807ce48c0aeb8e7333ea6", size = 41637, upload-time = "2025-10-08T19:46:43.778Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/e9/754f180cccd7f51a39913782c74717c581b9cc8177ad0e949f4d51812383/propcache-0.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:e53f3a38d3510c11953f3e6a33f205c6d1b001129f972805ca9b42fc308bc239", size = 38064, upload-time = "2025-10-08T19:46:44.872Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/0f/f17b1b2b221d5ca28b4b876e8bb046ac40466513960646bda8e1853cdfa2/propcache-0.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e153e9cd40cc8945138822807139367f256f89c6810c2634a4f6902b52d3b4e2", size = 80061, upload-time = "2025-10-08T19:46:46.075Z" },
+ { url = "https://files.pythonhosted.org/packages/76/47/8ccf75935f51448ba9a16a71b783eb7ef6b9ee60f5d14c7f8a8a79fbeed7/propcache-0.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cd547953428f7abb73c5ad82cbb32109566204260d98e41e5dfdc682eb7f8403", size = 46037, upload-time = "2025-10-08T19:46:47.23Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/b6/5c9a0e42df4d00bfb4a3cbbe5cf9f54260300c88a0e9af1f47ca5ce17ac0/propcache-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f048da1b4f243fc44f205dfd320933a951b8d89e0afd4c7cacc762a8b9165207", size = 47324, upload-time = "2025-10-08T19:46:48.384Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/d3/6c7ee328b39a81ee877c962469f1e795f9db87f925251efeb0545e0020d0/propcache-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec17c65562a827bba85e3872ead335f95405ea1674860d96483a02f5c698fa72", size = 225505, upload-time = "2025-10-08T19:46:50.055Z" },
+ { url = "https://files.pythonhosted.org/packages/01/5d/1c53f4563490b1d06a684742cc6076ef944bc6457df6051b7d1a877c057b/propcache-0.4.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:405aac25c6394ef275dee4c709be43745d36674b223ba4eb7144bf4d691b7367", size = 230242, upload-time = "2025-10-08T19:46:51.815Z" },
+ { url = "https://files.pythonhosted.org/packages/20/e1/ce4620633b0e2422207c3cb774a0ee61cac13abc6217763a7b9e2e3f4a12/propcache-0.4.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0013cb6f8dde4b2a2f66903b8ba740bdfe378c943c4377a200551ceb27f379e4", size = 238474, upload-time = "2025-10-08T19:46:53.208Z" },
+ { url = "https://files.pythonhosted.org/packages/46/4b/3aae6835b8e5f44ea6a68348ad90f78134047b503765087be2f9912140ea/propcache-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15932ab57837c3368b024473a525e25d316d8353016e7cc0e5ba9eb343fbb1cf", size = 221575, upload-time = "2025-10-08T19:46:54.511Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/a5/8a5e8678bcc9d3a1a15b9a29165640d64762d424a16af543f00629c87338/propcache-0.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:031dce78b9dc099f4c29785d9cf5577a3faf9ebf74ecbd3c856a7b92768c3df3", size = 216736, upload-time = "2025-10-08T19:46:56.212Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/63/b7b215eddeac83ca1c6b934f89d09a625aa9ee4ba158338854c87210cc36/propcache-0.4.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ab08df6c9a035bee56e31af99be621526bd237bea9f32def431c656b29e41778", size = 213019, upload-time = "2025-10-08T19:46:57.595Z" },
+ { url = "https://files.pythonhosted.org/packages/57/74/f580099a58c8af587cac7ba19ee7cb418506342fbbe2d4a4401661cca886/propcache-0.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4d7af63f9f93fe593afbf104c21b3b15868efb2c21d07d8732c0c4287e66b6a6", size = 220376, upload-time = "2025-10-08T19:46:59.067Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/ee/542f1313aff7eaf19c2bb758c5d0560d2683dac001a1c96d0774af799843/propcache-0.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cfc27c945f422e8b5071b6e93169679e4eb5bf73bbcbf1ba3ae3a83d2f78ebd9", size = 226988, upload-time = "2025-10-08T19:47:00.544Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/18/9c6b015dd9c6930f6ce2229e1f02fb35298b847f2087ea2b436a5bfa7287/propcache-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:35c3277624a080cc6ec6f847cbbbb5b49affa3598c4535a0a4682a697aaa5c75", size = 215615, upload-time = "2025-10-08T19:47:01.968Z" },
+ { url = "https://files.pythonhosted.org/packages/80/9e/e7b85720b98c45a45e1fca6a177024934dc9bc5f4d5dd04207f216fc33ed/propcache-0.4.1-cp312-cp312-win32.whl", hash = "sha256:671538c2262dadb5ba6395e26c1731e1d52534bfe9ae56d0b5573ce539266aa8", size = 38066, upload-time = "2025-10-08T19:47:03.503Z" },
+ { url = "https://files.pythonhosted.org/packages/54/09/d19cff2a5aaac632ec8fc03737b223597b1e347416934c1b3a7df079784c/propcache-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:cb2d222e72399fcf5890d1d5cc1060857b9b236adff2792ff48ca2dfd46c81db", size = 41655, upload-time = "2025-10-08T19:47:04.973Z" },
+ { url = "https://files.pythonhosted.org/packages/68/ab/6b5c191bb5de08036a8c697b265d4ca76148efb10fa162f14af14fb5f076/propcache-0.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:204483131fb222bdaaeeea9f9e6c6ed0cac32731f75dfc1d4a567fc1926477c1", size = 37789, upload-time = "2025-10-08T19:47:06.077Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/df/6d9c1b6ac12b003837dde8a10231a7344512186e87b36e855bef32241942/propcache-0.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:43eedf29202c08550aac1d14e0ee619b0430aaef78f85864c1a892294fbc28cf", size = 77750, upload-time = "2025-10-08T19:47:07.648Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/e8/677a0025e8a2acf07d3418a2e7ba529c9c33caf09d3c1f25513023c1db56/propcache-0.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d62cdfcfd89ccb8de04e0eda998535c406bf5e060ffd56be6c586cbcc05b3311", size = 44780, upload-time = "2025-10-08T19:47:08.851Z" },
+ { url = "https://files.pythonhosted.org/packages/89/a4/92380f7ca60f99ebae761936bc48a72a639e8a47b29050615eef757cb2a7/propcache-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cae65ad55793da34db5f54e4029b89d3b9b9490d8abe1b4c7ab5d4b8ec7ebf74", size = 46308, upload-time = "2025-10-08T19:47:09.982Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/48/c5ac64dee5262044348d1d78a5f85dd1a57464a60d30daee946699963eb3/propcache-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:333ddb9031d2704a301ee3e506dc46b1fe5f294ec198ed6435ad5b6a085facfe", size = 208182, upload-time = "2025-10-08T19:47:11.319Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/0c/cd762dd011a9287389a6a3eb43aa30207bde253610cca06824aeabfe9653/propcache-0.4.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fd0858c20f078a32cf55f7e81473d96dcf3b93fd2ccdb3d40fdf54b8573df3af", size = 211215, upload-time = "2025-10-08T19:47:13.146Z" },
+ { url = "https://files.pythonhosted.org/packages/30/3e/49861e90233ba36890ae0ca4c660e95df565b2cd15d4a68556ab5865974e/propcache-0.4.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:678ae89ebc632c5c204c794f8dab2837c5f159aeb59e6ed0539500400577298c", size = 218112, upload-time = "2025-10-08T19:47:14.913Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/8b/544bc867e24e1bd48f3118cecd3b05c694e160a168478fa28770f22fd094/propcache-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d472aeb4fbf9865e0c6d622d7f4d54a4e101a89715d8904282bb5f9a2f476c3f", size = 204442, upload-time = "2025-10-08T19:47:16.277Z" },
+ { url = "https://files.pythonhosted.org/packages/50/a6/4282772fd016a76d3e5c0df58380a5ea64900afd836cec2c2f662d1b9bb3/propcache-0.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4d3df5fa7e36b3225954fba85589da77a0fe6a53e3976de39caf04a0db4c36f1", size = 199398, upload-time = "2025-10-08T19:47:17.962Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/ec/d8a7cd406ee1ddb705db2139f8a10a8a427100347bd698e7014351c7af09/propcache-0.4.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ee17f18d2498f2673e432faaa71698032b0127ebf23ae5974eeaf806c279df24", size = 196920, upload-time = "2025-10-08T19:47:19.355Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/6c/f38ab64af3764f431e359f8baf9e0a21013e24329e8b85d2da32e8ed07ca/propcache-0.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:580e97762b950f993ae618e167e7be9256b8353c2dcd8b99ec100eb50f5286aa", size = 203748, upload-time = "2025-10-08T19:47:21.338Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/e3/fa846bd70f6534d647886621388f0a265254d30e3ce47e5c8e6e27dbf153/propcache-0.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:501d20b891688eb8e7aa903021f0b72d5a55db40ffaab27edefd1027caaafa61", size = 205877, upload-time = "2025-10-08T19:47:23.059Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/39/8163fc6f3133fea7b5f2827e8eba2029a0277ab2c5beee6c1db7b10fc23d/propcache-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a0bd56e5b100aef69bd8562b74b46254e7c8812918d3baa700c8a8009b0af66", size = 199437, upload-time = "2025-10-08T19:47:24.445Z" },
+ { url = "https://files.pythonhosted.org/packages/93/89/caa9089970ca49c7c01662bd0eeedfe85494e863e8043565aeb6472ce8fe/propcache-0.4.1-cp313-cp313-win32.whl", hash = "sha256:bcc9aaa5d80322bc2fb24bb7accb4a30f81e90ab8d6ba187aec0744bc302ad81", size = 37586, upload-time = "2025-10-08T19:47:25.736Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/ab/f76ec3c3627c883215b5c8080debb4394ef5a7a29be811f786415fc1e6fd/propcache-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:381914df18634f5494334d201e98245c0596067504b9372d8cf93f4bb23e025e", size = 40790, upload-time = "2025-10-08T19:47:26.847Z" },
+ { url = "https://files.pythonhosted.org/packages/59/1b/e71ae98235f8e2ba5004d8cb19765a74877abf189bc53fc0c80d799e56c3/propcache-0.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:8873eb4460fd55333ea49b7d189749ecf6e55bf85080f11b1c4530ed3034cba1", size = 37158, upload-time = "2025-10-08T19:47:27.961Z" },
+ { url = "https://files.pythonhosted.org/packages/83/ce/a31bbdfc24ee0dcbba458c8175ed26089cf109a55bbe7b7640ed2470cfe9/propcache-0.4.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:92d1935ee1f8d7442da9c0c4fa7ac20d07e94064184811b685f5c4fada64553b", size = 81451, upload-time = "2025-10-08T19:47:29.445Z" },
+ { url = "https://files.pythonhosted.org/packages/25/9c/442a45a470a68456e710d96cacd3573ef26a1d0a60067e6a7d5e655621ed/propcache-0.4.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:473c61b39e1460d386479b9b2f337da492042447c9b685f28be4f74d3529e566", size = 46374, upload-time = "2025-10-08T19:47:30.579Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/bf/b1d5e21dbc3b2e889ea4327044fb16312a736d97640fb8b6aa3f9c7b3b65/propcache-0.4.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c0ef0aaafc66fbd87842a3fe3902fd889825646bc21149eafe47be6072725835", size = 48396, upload-time = "2025-10-08T19:47:31.79Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/04/5b4c54a103d480e978d3c8a76073502b18db0c4bc17ab91b3cb5092ad949/propcache-0.4.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95393b4d66bfae908c3ca8d169d5f79cd65636ae15b5e7a4f6e67af675adb0e", size = 275950, upload-time = "2025-10-08T19:47:33.481Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/c1/86f846827fb969c4b78b0af79bba1d1ea2156492e1b83dea8b8a6ae27395/propcache-0.4.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c07fda85708bc48578467e85099645167a955ba093be0a2dcba962195676e859", size = 273856, upload-time = "2025-10-08T19:47:34.906Z" },
+ { url = "https://files.pythonhosted.org/packages/36/1d/fc272a63c8d3bbad6878c336c7a7dea15e8f2d23a544bda43205dfa83ada/propcache-0.4.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:af223b406d6d000830c6f65f1e6431783fc3f713ba3e6cc8c024d5ee96170a4b", size = 280420, upload-time = "2025-10-08T19:47:36.338Z" },
+ { url = "https://files.pythonhosted.org/packages/07/0c/01f2219d39f7e53d52e5173bcb09c976609ba30209912a0680adfb8c593a/propcache-0.4.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a78372c932c90ee474559c5ddfffd718238e8673c340dc21fe45c5b8b54559a0", size = 263254, upload-time = "2025-10-08T19:47:37.692Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/18/cd28081658ce597898f0c4d174d4d0f3c5b6d4dc27ffafeef835c95eb359/propcache-0.4.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:564d9f0d4d9509e1a870c920a89b2fec951b44bf5ba7d537a9e7c1ccec2c18af", size = 261205, upload-time = "2025-10-08T19:47:39.659Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/71/1f9e22eb8b8316701c2a19fa1f388c8a3185082607da8e406a803c9b954e/propcache-0.4.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:17612831fda0138059cc5546f4d12a2aacfb9e47068c06af35c400ba58ba7393", size = 247873, upload-time = "2025-10-08T19:47:41.084Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/65/3d4b61f36af2b4eddba9def857959f1016a51066b4f1ce348e0cf7881f58/propcache-0.4.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:41a89040cb10bd345b3c1a873b2bf36413d48da1def52f268a055f7398514874", size = 262739, upload-time = "2025-10-08T19:47:42.51Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/42/26746ab087faa77c1c68079b228810436ccd9a5ce9ac85e2b7307195fd06/propcache-0.4.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e35b88984e7fa64aacecea39236cee32dd9bd8c55f57ba8a75cf2399553f9bd7", size = 263514, upload-time = "2025-10-08T19:47:43.927Z" },
+ { url = "https://files.pythonhosted.org/packages/94/13/630690fe201f5502d2403dd3cfd451ed8858fe3c738ee88d095ad2ff407b/propcache-0.4.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f8b465489f927b0df505cbe26ffbeed4d6d8a2bbc61ce90eb074ff129ef0ab1", size = 257781, upload-time = "2025-10-08T19:47:45.448Z" },
+ { url = "https://files.pythonhosted.org/packages/92/f7/1d4ec5841505f423469efbfc381d64b7b467438cd5a4bbcbb063f3b73d27/propcache-0.4.1-cp313-cp313t-win32.whl", hash = "sha256:2ad890caa1d928c7c2965b48f3a3815c853180831d0e5503d35cf00c472f4717", size = 41396, upload-time = "2025-10-08T19:47:47.202Z" },
+ { url = "https://files.pythonhosted.org/packages/48/f0/615c30622316496d2cbbc29f5985f7777d3ada70f23370608c1d3e081c1f/propcache-0.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:f7ee0e597f495cf415bcbd3da3caa3bd7e816b74d0d52b8145954c5e6fd3ff37", size = 44897, upload-time = "2025-10-08T19:47:48.336Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/ca/6002e46eccbe0e33dcd4069ef32f7f1c9e243736e07adca37ae8c4830ec3/propcache-0.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:929d7cbe1f01bb7baffb33dc14eb5691c95831450a26354cd210a8155170c93a", size = 39789, upload-time = "2025-10-08T19:47:49.876Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/5c/bca52d654a896f831b8256683457ceddd490ec18d9ec50e97dfd8fc726a8/propcache-0.4.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3f7124c9d820ba5548d431afb4632301acf965db49e666aa21c305cbe8c6de12", size = 78152, upload-time = "2025-10-08T19:47:51.051Z" },
+ { url = "https://files.pythonhosted.org/packages/65/9b/03b04e7d82a5f54fb16113d839f5ea1ede58a61e90edf515f6577c66fa8f/propcache-0.4.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c0d4b719b7da33599dfe3b22d3db1ef789210a0597bc650b7cee9c77c2be8c5c", size = 44869, upload-time = "2025-10-08T19:47:52.594Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/fa/89a8ef0468d5833a23fff277b143d0573897cf75bd56670a6d28126c7d68/propcache-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9f302f4783709a78240ebc311b793f123328716a60911d667e0c036bc5dcbded", size = 46596, upload-time = "2025-10-08T19:47:54.073Z" },
+ { url = "https://files.pythonhosted.org/packages/86/bd/47816020d337f4a746edc42fe8d53669965138f39ee117414c7d7a340cfe/propcache-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c80ee5802e3fb9ea37938e7eecc307fb984837091d5fd262bb37238b1ae97641", size = 206981, upload-time = "2025-10-08T19:47:55.715Z" },
+ { url = "https://files.pythonhosted.org/packages/df/f6/c5fa1357cc9748510ee55f37173eb31bfde6d94e98ccd9e6f033f2fc06e1/propcache-0.4.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ed5a841e8bb29a55fb8159ed526b26adc5bdd7e8bd7bf793ce647cb08656cdf4", size = 211490, upload-time = "2025-10-08T19:47:57.499Z" },
+ { url = "https://files.pythonhosted.org/packages/80/1e/e5889652a7c4a3846683401a48f0f2e5083ce0ec1a8a5221d8058fbd1adf/propcache-0.4.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:55c72fd6ea2da4c318e74ffdf93c4fe4e926051133657459131a95c846d16d44", size = 215371, upload-time = "2025-10-08T19:47:59.317Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/f2/889ad4b2408f72fe1a4f6a19491177b30ea7bf1a0fd5f17050ca08cfc882/propcache-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8326e144341460402713f91df60ade3c999d601e7eb5ff8f6f7862d54de0610d", size = 201424, upload-time = "2025-10-08T19:48:00.67Z" },
+ { url = "https://files.pythonhosted.org/packages/27/73/033d63069b57b0812c8bd19f311faebeceb6ba31b8f32b73432d12a0b826/propcache-0.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:060b16ae65bc098da7f6d25bf359f1f31f688384858204fe5d652979e0015e5b", size = 197566, upload-time = "2025-10-08T19:48:02.604Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/89/ce24f3dc182630b4e07aa6d15f0ff4b14ed4b9955fae95a0b54c58d66c05/propcache-0.4.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:89eb3fa9524f7bec9de6e83cf3faed9d79bffa560672c118a96a171a6f55831e", size = 193130, upload-time = "2025-10-08T19:48:04.499Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/24/ef0d5fd1a811fb5c609278d0209c9f10c35f20581fcc16f818da959fc5b4/propcache-0.4.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:dee69d7015dc235f526fe80a9c90d65eb0039103fe565776250881731f06349f", size = 202625, upload-time = "2025-10-08T19:48:06.213Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/02/98ec20ff5546f68d673df2f7a69e8c0d076b5abd05ca882dc7ee3a83653d/propcache-0.4.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5558992a00dfd54ccbc64a32726a3357ec93825a418a401f5cc67df0ac5d9e49", size = 204209, upload-time = "2025-10-08T19:48:08.432Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/87/492694f76759b15f0467a2a93ab68d32859672b646aa8a04ce4864e7932d/propcache-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c9b822a577f560fbd9554812526831712c1436d2c046cedee4c3796d3543b144", size = 197797, upload-time = "2025-10-08T19:48:09.968Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/36/66367de3575db1d2d3f3d177432bd14ee577a39d3f5d1b3d5df8afe3b6e2/propcache-0.4.1-cp314-cp314-win32.whl", hash = "sha256:ab4c29b49d560fe48b696cdcb127dd36e0bc2472548f3bf56cc5cb3da2b2984f", size = 38140, upload-time = "2025-10-08T19:48:11.232Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/2a/a758b47de253636e1b8aef181c0b4f4f204bf0dd964914fb2af90a95b49b/propcache-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:5a103c3eb905fcea0ab98be99c3a9a5ab2de60228aa5aceedc614c0281cf6153", size = 41257, upload-time = "2025-10-08T19:48:12.707Z" },
+ { url = "https://files.pythonhosted.org/packages/34/5e/63bd5896c3fec12edcbd6f12508d4890d23c265df28c74b175e1ef9f4f3b/propcache-0.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:74c1fb26515153e482e00177a1ad654721bf9207da8a494a0c05e797ad27b992", size = 38097, upload-time = "2025-10-08T19:48:13.923Z" },
+ { url = "https://files.pythonhosted.org/packages/99/85/9ff785d787ccf9bbb3f3106f79884a130951436f58392000231b4c737c80/propcache-0.4.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:824e908bce90fb2743bd6b59db36eb4f45cd350a39637c9f73b1c1ea66f5b75f", size = 81455, upload-time = "2025-10-08T19:48:15.16Z" },
+ { url = "https://files.pythonhosted.org/packages/90/85/2431c10c8e7ddb1445c1f7c4b54d886e8ad20e3c6307e7218f05922cad67/propcache-0.4.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2b5e7db5328427c57c8e8831abda175421b709672f6cfc3d630c3b7e2146393", size = 46372, upload-time = "2025-10-08T19:48:16.424Z" },
+ { url = "https://files.pythonhosted.org/packages/01/20/b0972d902472da9bcb683fa595099911f4d2e86e5683bcc45de60dd05dc3/propcache-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6f6ff873ed40292cd4969ef5310179afd5db59fdf055897e282485043fc80ad0", size = 48411, upload-time = "2025-10-08T19:48:17.577Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/e3/7dc89f4f21e8f99bad3d5ddb3a3389afcf9da4ac69e3deb2dcdc96e74169/propcache-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49a2dc67c154db2c1463013594c458881a069fcf98940e61a0569016a583020a", size = 275712, upload-time = "2025-10-08T19:48:18.901Z" },
+ { url = "https://files.pythonhosted.org/packages/20/67/89800c8352489b21a8047c773067644e3897f02ecbbd610f4d46b7f08612/propcache-0.4.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:005f08e6a0529984491e37d8dbc3dd86f84bd78a8ceb5fa9a021f4c48d4984be", size = 273557, upload-time = "2025-10-08T19:48:20.762Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/a1/b52b055c766a54ce6d9c16d9aca0cad8059acd9637cdf8aa0222f4a026ef/propcache-0.4.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5c3310452e0d31390da9035c348633b43d7e7feb2e37be252be6da45abd1abcc", size = 280015, upload-time = "2025-10-08T19:48:22.592Z" },
+ { url = "https://files.pythonhosted.org/packages/48/c8/33cee30bd890672c63743049f3c9e4be087e6780906bfc3ec58528be59c1/propcache-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c3c70630930447f9ef1caac7728c8ad1c56bc5015338b20fed0d08ea2480b3a", size = 262880, upload-time = "2025-10-08T19:48:23.947Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/b1/8f08a143b204b418285c88b83d00edbd61afbc2c6415ffafc8905da7038b/propcache-0.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8e57061305815dfc910a3634dcf584f08168a8836e6999983569f51a8544cd89", size = 260938, upload-time = "2025-10-08T19:48:25.656Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/12/96e4664c82ca2f31e1c8dff86afb867348979eb78d3cb8546a680287a1e9/propcache-0.4.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:521a463429ef54143092c11a77e04056dd00636f72e8c45b70aaa3140d639726", size = 247641, upload-time = "2025-10-08T19:48:27.207Z" },
+ { url = "https://files.pythonhosted.org/packages/18/ed/e7a9cfca28133386ba52278136d42209d3125db08d0a6395f0cba0c0285c/propcache-0.4.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:120c964da3fdc75e3731aa392527136d4ad35868cc556fd09bb6d09172d9a367", size = 262510, upload-time = "2025-10-08T19:48:28.65Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/76/16d8bf65e8845dd62b4e2b57444ab81f07f40caa5652b8969b87ddcf2ef6/propcache-0.4.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:d8f353eb14ee3441ee844ade4277d560cdd68288838673273b978e3d6d2c8f36", size = 263161, upload-time = "2025-10-08T19:48:30.133Z" },
+ { url = "https://files.pythonhosted.org/packages/e7/70/c99e9edb5d91d5ad8a49fa3c1e8285ba64f1476782fed10ab251ff413ba1/propcache-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ab2943be7c652f09638800905ee1bab2c544e537edb57d527997a24c13dc1455", size = 257393, upload-time = "2025-10-08T19:48:31.567Z" },
+ { url = "https://files.pythonhosted.org/packages/08/02/87b25304249a35c0915d236575bc3574a323f60b47939a2262b77632a3ee/propcache-0.4.1-cp314-cp314t-win32.whl", hash = "sha256:05674a162469f31358c30bcaa8883cb7829fa3110bf9c0991fe27d7896c42d85", size = 42546, upload-time = "2025-10-08T19:48:32.872Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/ef/3c6ecf8b317aa982f309835e8f96987466123c6e596646d4e6a1dfcd080f/propcache-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:990f6b3e2a27d683cb7602ed6c86f15ee6b43b1194736f9baaeb93d0016633b1", size = 46259, upload-time = "2025-10-08T19:48:34.226Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/2d/346e946d4951f37eca1e4f55be0f0174c52cd70720f84029b02f296f4a38/propcache-0.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ecef2343af4cc68e05131e45024ba34f6095821988a9d0a02aa7c73fcc448aa9", size = 40428, upload-time = "2025-10-08T19:48:35.441Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/01/0ebaec9003f5d619a7475165961f8e3083cf8644d704b60395df3601632d/propcache-0.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3d233076ccf9e450c8b3bc6720af226b898ef5d051a2d145f7d765e6e9f9bcff", size = 80277, upload-time = "2025-10-08T19:48:36.647Z" },
+ { url = "https://files.pythonhosted.org/packages/34/58/04af97ac586b4ef6b9026c3fd36ee7798b737a832f5d3440a4280dcebd3a/propcache-0.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:357f5bb5c377a82e105e44bd3d52ba22b616f7b9773714bff93573988ef0a5fb", size = 45865, upload-time = "2025-10-08T19:48:37.859Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/19/b65d98ae21384518b291d9939e24a8aeac4fdb5101b732576f8f7540e834/propcache-0.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cbc3b6dfc728105b2a57c06791eb07a94229202ea75c59db644d7d496b698cac", size = 47636, upload-time = "2025-10-08T19:48:39.038Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/0f/317048c6d91c356c7154dca5af019e6effeb7ee15fa6a6db327cc19e12b4/propcache-0.4.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:182b51b421f0501952d938dc0b0eb45246a5b5153c50d42b495ad5fb7517c888", size = 201126, upload-time = "2025-10-08T19:48:40.774Z" },
+ { url = "https://files.pythonhosted.org/packages/71/69/0b2a7a5a6ee83292b4b997dbd80549d8ce7d40b6397c1646c0d9495f5a85/propcache-0.4.1-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4b536b39c5199b96fc6245eb5fb796c497381d3942f169e44e8e392b29c9ebcc", size = 209837, upload-time = "2025-10-08T19:48:42.167Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/92/c699ac495a6698df6e497fc2de27af4b6ace10d8e76528357ce153722e45/propcache-0.4.1-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:db65d2af507bbfbdcedb254a11149f894169d90488dd3e7190f7cdcb2d6cd57a", size = 215578, upload-time = "2025-10-08T19:48:43.56Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/ee/14de81c5eb02c0ee4f500b4e39c4e1bd0677c06e72379e6ab18923c773fc/propcache-0.4.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd2dbc472da1f772a4dae4fa24be938a6c544671a912e30529984dd80400cd88", size = 197187, upload-time = "2025-10-08T19:48:45.309Z" },
+ { url = "https://files.pythonhosted.org/packages/1d/94/48dce9aaa6d8dd5a0859bad75158ec522546d4ac23f8e2f05fac469477dd/propcache-0.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:daede9cd44e0f8bdd9e6cc9a607fc81feb80fae7a5fc6cecaff0e0bb32e42d00", size = 193478, upload-time = "2025-10-08T19:48:47.743Z" },
+ { url = "https://files.pythonhosted.org/packages/60/b5/0516b563e801e1ace212afde869a0596a0d7115eec0b12d296d75633fb29/propcache-0.4.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:71b749281b816793678ae7f3d0d84bd36e694953822eaad408d682efc5ca18e0", size = 190650, upload-time = "2025-10-08T19:48:49.373Z" },
+ { url = "https://files.pythonhosted.org/packages/24/89/e0f7d4a5978cd56f8cd67735f74052f257dc471ec901694e430f0d1572fe/propcache-0.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:0002004213ee1f36cfb3f9a42b5066100c44276b9b72b4e1504cddd3d692e86e", size = 200251, upload-time = "2025-10-08T19:48:51.4Z" },
+ { url = "https://files.pythonhosted.org/packages/06/7d/a1fac863d473876ed4406c914f2e14aa82d2f10dd207c9e16fc383cc5a24/propcache-0.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:fe49d0a85038f36ba9e3ffafa1103e61170b28e95b16622e11be0a0ea07c6781", size = 200919, upload-time = "2025-10-08T19:48:53.227Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/4e/f86a256ff24944cf5743e4e6c6994e3526f6acfcfb55e21694c2424f758c/propcache-0.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:99d43339c83aaf4d32bda60928231848eee470c6bda8d02599cc4cebe872d183", size = 193211, upload-time = "2025-10-08T19:48:55.027Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/3f/3fbad5f4356b068f1b047d300a6ff2c66614d7030f078cd50be3fec04228/propcache-0.4.1-cp39-cp39-win32.whl", hash = "sha256:a129e76735bc792794d5177069691c3217898b9f5cee2b2661471e52ffe13f19", size = 38314, upload-time = "2025-10-08T19:48:56.792Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/45/d78d136c3a3d215677abb886785aae744da2c3005bcb99e58640c56529b1/propcache-0.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:948dab269721ae9a87fd16c514a0a2c2a1bdb23a9a61b969b0f9d9ee2968546f", size = 41912, upload-time = "2025-10-08T19:48:57.995Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/2a/b0632941f25139f4e58450b307242951f7c2717a5704977c6d5323a800af/propcache-0.4.1-cp39-cp39-win_arm64.whl", hash = "sha256:5fd37c406dd6dc85aa743e214cef35dc54bbdd1419baac4f6ae5e5b1a2976938", size = 38450, upload-time = "2025-10-08T19:48:59.349Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" },
+]
+
+[[package]]
+name = "protobuf"
+version = "6.33.5"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version < '3.10'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ba/25/7c72c307aafc96fa87062aa6291d9f7c94836e43214d43722e86037aac02/protobuf-6.33.5.tar.gz", hash = "sha256:6ddcac2a081f8b7b9642c09406bc6a4290128fce5f471cddd165960bb9119e5c", size = 444465, upload-time = "2026-01-29T21:51:33.494Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b1/79/af92d0a8369732b027e6d6084251dd8e782c685c72da161bd4a2e00fbabb/protobuf-6.33.5-cp310-abi3-win32.whl", hash = "sha256:d71b040839446bac0f4d162e758bea99c8251161dae9d0983a3b88dee345153b", size = 425769, upload-time = "2026-01-29T21:51:21.751Z" },
+ { url = "https://files.pythonhosted.org/packages/55/75/bb9bc917d10e9ee13dee8607eb9ab963b7cf8be607c46e7862c748aa2af7/protobuf-6.33.5-cp310-abi3-win_amd64.whl", hash = "sha256:3093804752167bcab3998bec9f1048baae6e29505adaf1afd14a37bddede533c", size = 437118, upload-time = "2026-01-29T21:51:24.022Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/6b/e48dfc1191bc5b52950246275bf4089773e91cb5ba3592621723cdddca62/protobuf-6.33.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:a5cb85982d95d906df1e2210e58f8e4f1e3cdc088e52c921a041f9c9a0386de5", size = 427766, upload-time = "2026-01-29T21:51:25.413Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/b1/c79468184310de09d75095ed1314b839eb2f72df71097db9d1404a1b2717/protobuf-6.33.5-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:9b71e0281f36f179d00cbcb119cb19dec4d14a81393e5ea220f64b286173e190", size = 324638, upload-time = "2026-01-29T21:51:26.423Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/f5/65d838092fd01c44d16037953fd4c2cc851e783de9b8f02b27ec4ffd906f/protobuf-6.33.5-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:8afa18e1d6d20af15b417e728e9f60f3aa108ee76f23c3b2c07a2c3b546d3afd", size = 339411, upload-time = "2026-01-29T21:51:27.446Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/53/a9443aa3ca9ba8724fdfa02dd1887c1bcd8e89556b715cfbacca6b63dbec/protobuf-6.33.5-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:cbf16ba3350fb7b889fca858fb215967792dc125b35c7976ca4818bee3521cf0", size = 323465, upload-time = "2026-01-29T21:51:28.925Z" },
+ { url = "https://files.pythonhosted.org/packages/08/60/84d5f6dcda9165e4d6a56ac8433c9f40a8906bf2966150b8a0cfde097d78/protobuf-6.33.5-cp39-cp39-win32.whl", hash = "sha256:a3157e62729aafb8df6da2c03aa5c0937c7266c626ce11a278b6eb7963c4e37c", size = 425892, upload-time = "2026-01-29T21:51:30.382Z" },
+ { url = "https://files.pythonhosted.org/packages/68/19/33d7dc2dc84439587fa1e21e1c0026c01ad2af0a62f58fd54002a7546307/protobuf-6.33.5-cp39-cp39-win_amd64.whl", hash = "sha256:8f04fa32763dcdb4973d537d6b54e615cc61108c7cb38fe59310c3192d29510a", size = 437137, upload-time = "2026-01-29T21:51:31.456Z" },
+ { url = "https://files.pythonhosted.org/packages/57/bf/2086963c69bdac3d7cff1cc7ff79b8ce5ea0bec6797a017e1be338a46248/protobuf-6.33.5-py3-none-any.whl", hash = "sha256:69915a973dd0f60f31a08b8318b73eab2bd6a392c79184b3612226b0a3f8ec02", size = 170687, upload-time = "2026-01-29T21:51:32.557Z" },
+]
+
+[[package]]
+name = "protobuf"
+version = "7.34.0"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version >= '3.11'",
+ "python_full_version == '3.10.*'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/f2/00/04a2ab36b70a52d0356852979e08b44edde0435f2115dc66e25f2100f3ab/protobuf-7.34.0.tar.gz", hash = "sha256:3871a3df67c710aaf7bb8d214cc997342e63ceebd940c8c7fc65c9b3d697591a", size = 454726, upload-time = "2026-02-27T00:30:25.421Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/13/c4/6322ab5c8f279c4c358bc14eb8aefc0550b97222a39f04eb3c1af7a830fa/protobuf-7.34.0-cp310-abi3-macosx_10_9_universal2.whl", hash = "sha256:8e329966799f2c271d5e05e236459fe1cbfdb8755aaa3b0914fa60947ddea408", size = 429248, upload-time = "2026-02-27T00:30:14.924Z" },
+ { url = "https://files.pythonhosted.org/packages/45/99/b029bbbc61e8937545da5b79aa405ab2d9cf307a728f8c9459ad60d7a481/protobuf-7.34.0-cp310-abi3-manylinux2014_aarch64.whl", hash = "sha256:9d7a5005fb96f3c1e64f397f91500b0eb371b28da81296ae73a6b08a5b76cdd6", size = 325753, upload-time = "2026-02-27T00:30:17.247Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/79/09f02671eb75b251c5550a1c48e7b3d4b0623efd7c95a15a50f6f9fc1e2e/protobuf-7.34.0-cp310-abi3-manylinux2014_s390x.whl", hash = "sha256:4a72a8ec94e7a9f7ef7fe818ed26d073305f347f8b3b5ba31e22f81fd85fca02", size = 340200, upload-time = "2026-02-27T00:30:18.672Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/57/89727baef7578897af5ed166735ceb315819f1c184da8c3441271dbcfde7/protobuf-7.34.0-cp310-abi3-manylinux2014_x86_64.whl", hash = "sha256:964cf977e07f479c0697964e83deda72bcbc75c3badab506fb061b352d991b01", size = 324268, upload-time = "2026-02-27T00:30:20.088Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/3e/38ff2ddee5cc946f575c9d8cc822e34bde205cf61acf8099ad88ef19d7d2/protobuf-7.34.0-cp310-abi3-win32.whl", hash = "sha256:f791ec509707a1d91bd02e07df157e75e4fb9fbdad12a81b7396201ec244e2e3", size = 426628, upload-time = "2026-02-27T00:30:21.555Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/71/7c32eaf34a61a1bae1b62a2ac4ffe09b8d1bb0cf93ad505f42040023db89/protobuf-7.34.0-cp310-abi3-win_amd64.whl", hash = "sha256:9f9079f1dde4e32342ecbd1c118d76367090d4aaa19da78230c38101c5b3dd40", size = 437901, upload-time = "2026-02-27T00:30:22.836Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/e7/14dc9366696dcb53a413449881743426ed289d687bcf3d5aee4726c32ebb/protobuf-7.34.0-py3-none-any.whl", hash = "sha256:e3b914dd77fa33fa06ab2baa97937746ab25695f389869afdf03e81f34e45dc7", size = 170716, upload-time = "2026-02-27T00:30:23.994Z" },
+]
+
+[[package]]
+name = "ptyprocess"
+version = "0.7.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" },
+]
+
+[[package]]
+name = "pure-eval"
+version = "0.2.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" },
+]
+
+[[package]]
+name = "pycparser"
+version = "2.23"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version < '3.10'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" },
+]
+
+[[package]]
+name = "pycparser"
+version = "3.0"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version >= '3.11'",
+ "python_full_version == '3.10.*'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" },
+]
+
+[[package]]
+name = "pydantic"
+version = "2.12.5"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "annotated-types" },
+ { name = "pydantic-core" },
+ { name = "typing-extensions" },
+ { name = "typing-inspection" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591, upload-time = "2025-11-26T15:11:46.471Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload-time = "2025-11-26T15:11:44.605Z" },
+]
+
+[[package]]
+name = "pydantic-core"
+version = "2.41.5"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c6/90/32c9941e728d564b411d574d8ee0cf09b12ec978cb22b294995bae5549a5/pydantic_core-2.41.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146", size = 2107298, upload-time = "2025-11-04T13:39:04.116Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/a8/61c96a77fe28993d9a6fb0f4127e05430a267b235a124545d79fea46dd65/pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2", size = 1901475, upload-time = "2025-11-04T13:39:06.055Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/b6/338abf60225acc18cdc08b4faef592d0310923d19a87fba1faf05af5346e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5921a4d3ca3aee735d9fd163808f5e8dd6c6972101e4adbda9a4667908849b97", size = 1918815, upload-time = "2025-11-04T13:39:10.41Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/1c/2ed0433e682983d8e8cba9c8d8ef274d4791ec6a6f24c58935b90e780e0a/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25c479382d26a2a41b7ebea1043564a937db462816ea07afa8a44c0866d52f9", size = 2065567, upload-time = "2025-11-04T13:39:12.244Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/24/cf84974ee7d6eae06b9e63289b7b8f6549d416b5c199ca2d7ce13bbcf619/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f547144f2966e1e16ae626d8ce72b4cfa0caedc7fa28052001c94fb2fcaa1c52", size = 2230442, upload-time = "2025-11-04T13:39:13.962Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/21/4e287865504b3edc0136c89c9c09431be326168b1eb7841911cbc877a995/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f52298fbd394f9ed112d56f3d11aabd0d5bd27beb3084cc3d8ad069483b8941", size = 2350956, upload-time = "2025-11-04T13:39:15.889Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/76/7727ef2ffa4b62fcab916686a68a0426b9b790139720e1934e8ba797e238/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:100baa204bb412b74fe285fb0f3a385256dad1d1879f0a5cb1499ed2e83d132a", size = 2068253, upload-time = "2025-11-04T13:39:17.403Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/8c/a4abfc79604bcb4c748e18975c44f94f756f08fb04218d5cb87eb0d3a63e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:05a2c8852530ad2812cb7914dc61a1125dc4e06252ee98e5638a12da6cc6fb6c", size = 2177050, upload-time = "2025-11-04T13:39:19.351Z" },
+ { url = "https://files.pythonhosted.org/packages/67/b1/de2e9a9a79b480f9cb0b6e8b6ba4c50b18d4e89852426364c66aa82bb7b3/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29452c56df2ed968d18d7e21f4ab0ac55e71dc59524872f6fc57dcf4a3249ed2", size = 2147178, upload-time = "2025-11-04T13:39:21Z" },
+ { url = "https://files.pythonhosted.org/packages/16/c1/dfb33f837a47b20417500efaa0378adc6635b3c79e8369ff7a03c494b4ac/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:d5160812ea7a8a2ffbe233d8da666880cad0cbaf5d4de74ae15c313213d62556", size = 2341833, upload-time = "2025-11-04T13:39:22.606Z" },
+ { url = "https://files.pythonhosted.org/packages/47/36/00f398642a0f4b815a9a558c4f1dca1b4020a7d49562807d7bc9ff279a6c/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df3959765b553b9440adfd3c795617c352154e497a4eaf3752555cfb5da8fc49", size = 2321156, upload-time = "2025-11-04T13:39:25.843Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/70/cad3acd89fde2010807354d978725ae111ddf6d0ea46d1ea1775b5c1bd0c/pydantic_core-2.41.5-cp310-cp310-win32.whl", hash = "sha256:1f8d33a7f4d5a7889e60dc39856d76d09333d8a6ed0f5f1190635cbec70ec4ba", size = 1989378, upload-time = "2025-11-04T13:39:27.92Z" },
+ { url = "https://files.pythonhosted.org/packages/76/92/d338652464c6c367e5608e4488201702cd1cbb0f33f7b6a85a60fe5f3720/pydantic_core-2.41.5-cp310-cp310-win_amd64.whl", hash = "sha256:62de39db01b8d593e45871af2af9e497295db8d73b085f6bfd0b18c83c70a8f9", size = 2013622, upload-time = "2025-11-04T13:39:29.848Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/72/74a989dd9f2084b3d9530b0915fdda64ac48831c30dbf7c72a41a5232db8/pydantic_core-2.41.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a3a52f6156e73e7ccb0f8cced536adccb7042be67cb45f9562e12b319c119da6", size = 2105873, upload-time = "2025-11-04T13:39:31.373Z" },
+ { url = "https://files.pythonhosted.org/packages/12/44/37e403fd9455708b3b942949e1d7febc02167662bf1a7da5b78ee1ea2842/pydantic_core-2.41.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7f3bf998340c6d4b0c9a2f02d6a400e51f123b59565d74dc60d252ce888c260b", size = 1899826, upload-time = "2025-11-04T13:39:32.897Z" },
+ { url = "https://files.pythonhosted.org/packages/33/7f/1d5cab3ccf44c1935a359d51a8a2a9e1a654b744b5e7f80d41b88d501eec/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:378bec5c66998815d224c9ca994f1e14c0c21cb95d2f52b6021cc0b2a58f2a5a", size = 1917869, upload-time = "2025-11-04T13:39:34.469Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/6a/30d94a9674a7fe4f4744052ed6c5e083424510be1e93da5bc47569d11810/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7b576130c69225432866fe2f4a469a85a54ade141d96fd396dffcf607b558f8", size = 2063890, upload-time = "2025-11-04T13:39:36.053Z" },
+ { url = "https://files.pythonhosted.org/packages/50/be/76e5d46203fcb2750e542f32e6c371ffa9b8ad17364cf94bb0818dbfb50c/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6cb58b9c66f7e4179a2d5e0f849c48eff5c1fca560994d6eb6543abf955a149e", size = 2229740, upload-time = "2025-11-04T13:39:37.753Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/ee/fed784df0144793489f87db310a6bbf8118d7b630ed07aa180d6067e653a/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88942d3a3dff3afc8288c21e565e476fc278902ae4d6d134f1eeda118cc830b1", size = 2350021, upload-time = "2025-11-04T13:39:40.94Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/be/8fed28dd0a180dca19e72c233cbf58efa36df055e5b9d90d64fd1740b828/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f31d95a179f8d64d90f6831d71fa93290893a33148d890ba15de25642c5d075b", size = 2066378, upload-time = "2025-11-04T13:39:42.523Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/3b/698cf8ae1d536a010e05121b4958b1257f0b5522085e335360e53a6b1c8b/pydantic_core-2.41.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1df3d34aced70add6f867a8cf413e299177e0c22660cc767218373d0779487b", size = 2175761, upload-time = "2025-11-04T13:39:44.553Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/ba/15d537423939553116dea94ce02f9c31be0fa9d0b806d427e0308ec17145/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4009935984bd36bd2c774e13f9a09563ce8de4abaa7226f5108262fa3e637284", size = 2146303, upload-time = "2025-11-04T13:39:46.238Z" },
+ { url = "https://files.pythonhosted.org/packages/58/7f/0de669bf37d206723795f9c90c82966726a2ab06c336deba4735b55af431/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:34a64bc3441dc1213096a20fe27e8e128bd3ff89921706e83c0b1ac971276594", size = 2340355, upload-time = "2025-11-04T13:39:48.002Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/de/e7482c435b83d7e3c3ee5ee4451f6e8973cff0eb6007d2872ce6383f6398/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c9e19dd6e28fdcaa5a1de679aec4141f691023916427ef9bae8584f9c2fb3b0e", size = 2319875, upload-time = "2025-11-04T13:39:49.705Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/e6/8c9e81bb6dd7560e33b9053351c29f30c8194b72f2d6932888581f503482/pydantic_core-2.41.5-cp311-cp311-win32.whl", hash = "sha256:2c010c6ded393148374c0f6f0bf89d206bf3217f201faa0635dcd56bd1520f6b", size = 1987549, upload-time = "2025-11-04T13:39:51.842Z" },
+ { url = "https://files.pythonhosted.org/packages/11/66/f14d1d978ea94d1bc21fc98fcf570f9542fe55bfcc40269d4e1a21c19bf7/pydantic_core-2.41.5-cp311-cp311-win_amd64.whl", hash = "sha256:76ee27c6e9c7f16f47db7a94157112a2f3a00e958bc626e2f4ee8bec5c328fbe", size = 2011305, upload-time = "2025-11-04T13:39:53.485Z" },
+ { url = "https://files.pythonhosted.org/packages/56/d8/0e271434e8efd03186c5386671328154ee349ff0354d83c74f5caaf096ed/pydantic_core-2.41.5-cp311-cp311-win_arm64.whl", hash = "sha256:4bc36bbc0b7584de96561184ad7f012478987882ebf9f9c389b23f432ea3d90f", size = 1972902, upload-time = "2025-11-04T13:39:56.488Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/5d/5f6c63eebb5afee93bcaae4ce9a898f3373ca23df3ccaef086d0233a35a7/pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7", size = 2110990, upload-time = "2025-11-04T13:39:58.079Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0", size = 1896003, upload-time = "2025-11-04T13:39:59.956Z" },
+ { url = "https://files.pythonhosted.org/packages/68/b8/a01b53cb0e59139fbc9e4fda3e9724ede8de279097179be4ff31f1abb65a/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69", size = 1919200, upload-time = "2025-11-04T13:40:02.241Z" },
+ { url = "https://files.pythonhosted.org/packages/38/de/8c36b5198a29bdaade07b5985e80a233a5ac27137846f3bc2d3b40a47360/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75", size = 2052578, upload-time = "2025-11-04T13:40:04.401Z" },
+ { url = "https://files.pythonhosted.org/packages/00/b5/0e8e4b5b081eac6cb3dbb7e60a65907549a1ce035a724368c330112adfdd/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05", size = 2208504, upload-time = "2025-11-04T13:40:06.072Z" },
+ { url = "https://files.pythonhosted.org/packages/77/56/87a61aad59c7c5b9dc8caad5a41a5545cba3810c3e828708b3d7404f6cef/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc", size = 2335816, upload-time = "2025-11-04T13:40:07.835Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/76/941cc9f73529988688a665a5c0ecff1112b3d95ab48f81db5f7606f522d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c", size = 2075366, upload-time = "2025-11-04T13:40:09.804Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/43/ebef01f69baa07a482844faaa0a591bad1ef129253ffd0cdaa9d8a7f72d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5", size = 2171698, upload-time = "2025-11-04T13:40:12.004Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/87/41f3202e4193e3bacfc2c065fab7706ebe81af46a83d3e27605029c1f5a6/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c", size = 2132603, upload-time = "2025-11-04T13:40:13.868Z" },
+ { url = "https://files.pythonhosted.org/packages/49/7d/4c00df99cb12070b6bccdef4a195255e6020a550d572768d92cc54dba91a/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294", size = 2329591, upload-time = "2025-11-04T13:40:15.672Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/6a/ebf4b1d65d458f3cda6a7335d141305dfa19bdc61140a884d165a8a1bbc7/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1", size = 2319068, upload-time = "2025-11-04T13:40:17.532Z" },
+ { url = "https://files.pythonhosted.org/packages/49/3b/774f2b5cd4192d5ab75870ce4381fd89cf218af999515baf07e7206753f0/pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d", size = 1985908, upload-time = "2025-11-04T13:40:19.309Z" },
+ { url = "https://files.pythonhosted.org/packages/86/45/00173a033c801cacf67c190fef088789394feaf88a98a7035b0e40d53dc9/pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815", size = 2020145, upload-time = "2025-11-04T13:40:21.548Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/22/91fbc821fa6d261b376a3f73809f907cec5ca6025642c463d3488aad22fb/pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3", size = 1976179, upload-time = "2025-11-04T13:40:23.393Z" },
+ { url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403, upload-time = "2025-11-04T13:40:25.248Z" },
+ { url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206, upload-time = "2025-11-04T13:40:27.099Z" },
+ { url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307, upload-time = "2025-11-04T13:40:29.806Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", size = 2063258, upload-time = "2025-11-04T13:40:33.544Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", size = 2214917, upload-time = "2025-11-04T13:40:35.479Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", size = 2332186, upload-time = "2025-11-04T13:40:37.436Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164, upload-time = "2025-11-04T13:40:40.289Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146, upload-time = "2025-11-04T13:40:42.809Z" },
+ { url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788, upload-time = "2025-11-04T13:40:44.752Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload-time = "2025-11-04T13:40:46.66Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852, upload-time = "2025-11-04T13:40:48.575Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679, upload-time = "2025-11-04T13:40:50.619Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766, upload-time = "2025-11-04T13:40:52.631Z" },
+ { url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005, upload-time = "2025-11-04T13:40:54.734Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/28/46b7c5c9635ae96ea0fbb779e271a38129df2550f763937659ee6c5dbc65/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a", size = 2119622, upload-time = "2025-11-04T13:40:56.68Z" },
+ { url = "https://files.pythonhosted.org/packages/74/1a/145646e5687e8d9a1e8d09acb278c8535ebe9e972e1f162ed338a622f193/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14", size = 1891725, upload-time = "2025-11-04T13:40:58.807Z" },
+ { url = "https://files.pythonhosted.org/packages/23/04/e89c29e267b8060b40dca97bfc64a19b2a3cf99018167ea1677d96368273/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1", size = 1915040, upload-time = "2025-11-04T13:41:00.853Z" },
+ { url = "https://files.pythonhosted.org/packages/84/a3/15a82ac7bd97992a82257f777b3583d3e84bdb06ba6858f745daa2ec8a85/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66", size = 2063691, upload-time = "2025-11-04T13:41:03.504Z" },
+ { url = "https://files.pythonhosted.org/packages/74/9b/0046701313c6ef08c0c1cf0e028c67c770a4e1275ca73131563c5f2a310a/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869", size = 2213897, upload-time = "2025-11-04T13:41:05.804Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/cd/6bac76ecd1b27e75a95ca3a9a559c643b3afcd2dd62086d4b7a32a18b169/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2", size = 2333302, upload-time = "2025-11-04T13:41:07.809Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/d2/ef2074dc020dd6e109611a8be4449b98cd25e1b9b8a303c2f0fca2f2bcf7/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375", size = 2064877, upload-time = "2025-11-04T13:41:09.827Z" },
+ { url = "https://files.pythonhosted.org/packages/18/66/e9db17a9a763d72f03de903883c057b2592c09509ccfe468187f2a2eef29/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553", size = 2180680, upload-time = "2025-11-04T13:41:12.379Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/9e/3ce66cebb929f3ced22be85d4c2399b8e85b622db77dad36b73c5387f8f8/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90", size = 2138960, upload-time = "2025-11-04T13:41:14.627Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/62/205a998f4327d2079326b01abee48e502ea739d174f0a89295c481a2272e/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07", size = 2339102, upload-time = "2025-11-04T13:41:16.868Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/0d/f05e79471e889d74d3d88f5bd20d0ed189ad94c2423d81ff8d0000aab4ff/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb", size = 2326039, upload-time = "2025-11-04T13:41:18.934Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/e1/e08a6208bb100da7e0c4b288eed624a703f4d129bde2da475721a80cab32/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23", size = 1995126, upload-time = "2025-11-04T13:41:21.418Z" },
+ { url = "https://files.pythonhosted.org/packages/48/5d/56ba7b24e9557f99c9237e29f5c09913c81eeb2f3217e40e922353668092/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf", size = 2015489, upload-time = "2025-11-04T13:41:24.076Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/bb/f7a190991ec9e3e0ba22e4993d8755bbc4a32925c0b5b42775c03e8148f9/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0", size = 1977288, upload-time = "2025-11-04T13:41:26.33Z" },
+ { url = "https://files.pythonhosted.org/packages/92/ed/77542d0c51538e32e15afe7899d79efce4b81eee631d99850edc2f5e9349/pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a", size = 2120255, upload-time = "2025-11-04T13:41:28.569Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3", size = 1863760, upload-time = "2025-11-04T13:41:31.055Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/f0/e5e6b99d4191da102f2b0eb9687aaa7f5bea5d9964071a84effc3e40f997/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c", size = 1878092, upload-time = "2025-11-04T13:41:33.21Z" },
+ { url = "https://files.pythonhosted.org/packages/71/48/36fb760642d568925953bcc8116455513d6e34c4beaa37544118c36aba6d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612", size = 2053385, upload-time = "2025-11-04T13:41:35.508Z" },
+ { url = "https://files.pythonhosted.org/packages/20/25/92dc684dd8eb75a234bc1c764b4210cf2646479d54b47bf46061657292a8/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d", size = 2218832, upload-time = "2025-11-04T13:41:37.732Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/09/f53e0b05023d3e30357d82eb35835d0f6340ca344720a4599cd663dca599/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9", size = 2327585, upload-time = "2025-11-04T13:41:40Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660", size = 2041078, upload-time = "2025-11-04T13:41:42.323Z" },
+ { url = "https://files.pythonhosted.org/packages/cd/13/2e215f17f0ef326fc72afe94776edb77525142c693767fc347ed6288728d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9", size = 2173914, upload-time = "2025-11-04T13:41:45.221Z" },
+ { url = "https://files.pythonhosted.org/packages/02/7a/f999a6dcbcd0e5660bc348a3991c8915ce6599f4f2c6ac22f01d7a10816c/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3", size = 2129560, upload-time = "2025-11-04T13:41:47.474Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf", size = 2329244, upload-time = "2025-11-04T13:41:49.992Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/02/3c562f3a51afd4d88fff8dffb1771b30cfdfd79befd9883ee094f5b6c0d8/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470", size = 2331955, upload-time = "2025-11-04T13:41:54.079Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" },
+ { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" },
+ { url = "https://files.pythonhosted.org/packages/54/db/160dffb57ed9a3705c4cbcbff0ac03bdae45f1ca7d58ab74645550df3fbd/pydantic_core-2.41.5-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:8bfeaf8735be79f225f3fefab7f941c712aaca36f1128c9d7e2352ee1aa87bdf", size = 2107999, upload-time = "2025-11-04T13:42:03.885Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/7d/88e7de946f60d9263cc84819f32513520b85c0f8322f9b8f6e4afc938383/pydantic_core-2.41.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:346285d28e4c8017da95144c7f3acd42740d637ff41946af5ce6e5e420502dd5", size = 1929745, upload-time = "2025-11-04T13:42:06.075Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/c2/aef51e5b283780e85e99ff19db0f05842d2d4a8a8cd15e63b0280029b08f/pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a75dafbf87d6276ddc5b2bf6fae5254e3d0876b626eb24969a574fff9149ee5d", size = 1920220, upload-time = "2025-11-04T13:42:08.457Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/97/492ab10f9ac8695cd76b2fdb24e9e61f394051df71594e9bcc891c9f586e/pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7b93a4d08587e2b7e7882de461e82b6ed76d9026ce91ca7915e740ecc7855f60", size = 2067296, upload-time = "2025-11-04T13:42:10.817Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/23/984149650e5269c59a2a4c41d234a9570adc68ab29981825cfaf4cfad8f4/pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8465ab91a4bd96d36dde3263f06caa6a8a6019e4113f24dc753d79a8b3a3f82", size = 2231548, upload-time = "2025-11-04T13:42:13.843Z" },
+ { url = "https://files.pythonhosted.org/packages/71/0c/85bcbb885b9732c28bec67a222dbed5ed2d77baee1f8bba2002e8cd00c5c/pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:299e0a22e7ae2b85c1a57f104538b2656e8ab1873511fd718a1c1c6f149b77b5", size = 2362571, upload-time = "2025-11-04T13:42:16.208Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/4a/412d2048be12c334003e9b823a3fa3d038e46cc2d64dd8aab50b31b65499/pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:707625ef0983fcfb461acfaf14de2067c5942c6bb0f3b4c99158bed6fedd3cf3", size = 2068175, upload-time = "2025-11-04T13:42:18.911Z" },
+ { url = "https://files.pythonhosted.org/packages/73/f4/c58b6a776b502d0a5540ad02e232514285513572060f0d78f7832ca3c98b/pydantic_core-2.41.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f41eb9797986d6ebac5e8edff36d5cef9de40def462311b3eb3eeded1431e425", size = 2177203, upload-time = "2025-11-04T13:42:22.578Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/ae/f06ea4c7e7a9eead3d165e7623cd2ea0cb788e277e4f935af63fc98fa4e6/pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0384e2e1021894b1ff5a786dbf94771e2986ebe2869533874d7e43bc79c6f504", size = 2148191, upload-time = "2025-11-04T13:42:24.89Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/57/25a11dcdc656bf5f8b05902c3c2934ac3ea296257cc4a3f79a6319e61856/pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:f0cd744688278965817fd0839c4a4116add48d23890d468bc436f78beb28abf5", size = 2343907, upload-time = "2025-11-04T13:42:27.683Z" },
+ { url = "https://files.pythonhosted.org/packages/96/82/e33d5f4933d7a03327c0c43c65d575e5919d4974ffc026bc917a5f7b9f61/pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:753e230374206729bf0a807954bcc6c150d3743928a73faffee51ac6557a03c3", size = 2322174, upload-time = "2025-11-04T13:42:30.776Z" },
+ { url = "https://files.pythonhosted.org/packages/81/45/4091be67ce9f469e81656f880f3506f6a5624121ec5eb3eab37d7581897d/pydantic_core-2.41.5-cp39-cp39-win32.whl", hash = "sha256:873e0d5b4fb9b89ef7c2d2a963ea7d02879d9da0da8d9d4933dee8ee86a8b460", size = 1990353, upload-time = "2025-11-04T13:42:33.111Z" },
+ { url = "https://files.pythonhosted.org/packages/44/8a/a98aede18db6e9cd5d66bcacd8a409fcf8134204cdede2e7de35c5a2c5ef/pydantic_core-2.41.5-cp39-cp39-win_amd64.whl", hash = "sha256:e4f4a984405e91527a0d62649ee21138f8e3d0ef103be488c1dc11a80d7f184b", size = 2015698, upload-time = "2025-11-04T13:42:35.484Z" },
+ { url = "https://files.pythonhosted.org/packages/11/72/90fda5ee3b97e51c494938a4a44c3a35a9c96c19bba12372fb9c634d6f57/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034", size = 2115441, upload-time = "2025-11-04T13:42:39.557Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/53/8942f884fa33f50794f119012dc6a1a02ac43a56407adaac20463df8e98f/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c", size = 1930291, upload-time = "2025-11-04T13:42:42.169Z" },
+ { url = "https://files.pythonhosted.org/packages/79/c8/ecb9ed9cd942bce09fc888ee960b52654fbdbede4ba6c2d6e0d3b1d8b49c/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2", size = 1948632, upload-time = "2025-11-04T13:42:44.564Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/1b/687711069de7efa6af934e74f601e2a4307365e8fdc404703afc453eab26/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad", size = 2138905, upload-time = "2025-11-04T13:42:47.156Z" },
+ { url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495, upload-time = "2025-11-04T13:42:49.689Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388, upload-time = "2025-11-04T13:42:52.215Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879, upload-time = "2025-11-04T13:42:56.483Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017, upload-time = "2025-11-04T13:42:59.471Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/b0/1a2aa41e3b5a4ba11420aba2d091b2d17959c8d1519ece3627c371951e73/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b5819cd790dbf0c5eb9f82c73c16b39a65dd6dd4d1439dcdea7816ec9adddab8", size = 2103351, upload-time = "2025-11-04T13:43:02.058Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/ee/31b1f0020baaf6d091c87900ae05c6aeae101fa4e188e1613c80e4f1ea31/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5a4e67afbc95fa5c34cf27d9089bca7fcab4e51e57278d710320a70b956d1b9a", size = 1925363, upload-time = "2025-11-04T13:43:05.159Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/89/ab8e86208467e467a80deaca4e434adac37b10a9d134cd2f99b28a01e483/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ece5c59f0ce7d001e017643d8d24da587ea1f74f6993467d85ae8a5ef9d4f42b", size = 2135615, upload-time = "2025-11-04T13:43:08.116Z" },
+ { url = "https://files.pythonhosted.org/packages/99/0a/99a53d06dd0348b2008f2f30884b34719c323f16c3be4e6cc1203b74a91d/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16f80f7abe3351f8ea6858914ddc8c77e02578544a0ebc15b4c2e1a0e813b0b2", size = 2175369, upload-time = "2025-11-04T13:43:12.49Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/94/30ca3b73c6d485b9bb0bc66e611cff4a7138ff9736b7e66bcf0852151636/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:33cb885e759a705b426baada1fe68cbb0a2e68e34c5d0d0289a364cf01709093", size = 2144218, upload-time = "2025-11-04T13:43:15.431Z" },
+ { url = "https://files.pythonhosted.org/packages/87/57/31b4f8e12680b739a91f472b5671294236b82586889ef764b5fbc6669238/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:c8d8b4eb992936023be7dee581270af5c6e0697a8559895f527f5b7105ecd36a", size = 2329951, upload-time = "2025-11-04T13:43:18.062Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/73/3c2c8edef77b8f7310e6fb012dbc4b8551386ed575b9eb6fb2506e28a7eb/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:242a206cd0318f95cd21bdacff3fcc3aab23e79bba5cac3db5a841c9ef9c6963", size = 2318428, upload-time = "2025-11-04T13:43:20.679Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/02/8559b1f26ee0d502c74f9cca5c0d2fd97e967e083e006bbbb4e97f3a043a/pydantic_core-2.41.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d3a978c4f57a597908b7e697229d996d77a6d3c94901e9edee593adada95ce1a", size = 2147009, upload-time = "2025-11-04T13:43:23.286Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/9b/1b3f0e9f9305839d7e84912f9e8bfbd191ed1b1ef48083609f0dabde978c/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b2379fa7ed44ddecb5bfe4e48577d752db9fc10be00a6b7446e9663ba143de26", size = 2101980, upload-time = "2025-11-04T13:43:25.97Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/ed/d71fefcb4263df0da6a85b5d8a7508360f2f2e9b3bf5814be9c8bccdccc1/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:266fb4cbf5e3cbd0b53669a6d1b039c45e3ce651fd5442eff4d07c2cc8d66808", size = 1923865, upload-time = "2025-11-04T13:43:28.763Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/3a/626b38db460d675f873e4444b4bb030453bbe7b4ba55df821d026a0493c4/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58133647260ea01e4d0500089a8c4f07bd7aa6ce109682b1426394988d8aaacc", size = 2134256, upload-time = "2025-11-04T13:43:31.71Z" },
+ { url = "https://files.pythonhosted.org/packages/83/d9/8412d7f06f616bbc053d30cb4e5f76786af3221462ad5eee1f202021eb4e/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:287dad91cfb551c363dc62899a80e9e14da1f0e2b6ebde82c806612ca2a13ef1", size = 2174762, upload-time = "2025-11-04T13:43:34.744Z" },
+ { url = "https://files.pythonhosted.org/packages/55/4c/162d906b8e3ba3a99354e20faa1b49a85206c47de97a639510a0e673f5da/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:03b77d184b9eb40240ae9fd676ca364ce1085f203e1b1256f8ab9984dca80a84", size = 2143141, upload-time = "2025-11-04T13:43:37.701Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/f2/f11dd73284122713f5f89fc940f370d035fa8e1e078d446b3313955157fe/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:a668ce24de96165bb239160b3d854943128f4334822900534f2fe947930e5770", size = 2330317, upload-time = "2025-11-04T13:43:40.406Z" },
+ { url = "https://files.pythonhosted.org/packages/88/9d/b06ca6acfe4abb296110fb1273a4d848a0bfb2ff65f3ee92127b3244e16b/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f14f8f046c14563f8eb3f45f499cc658ab8d10072961e07225e507adb700e93f", size = 2316992, upload-time = "2025-11-04T13:43:43.602Z" },
+ { url = "https://files.pythonhosted.org/packages/36/c7/cfc8e811f061c841d7990b0201912c3556bfeb99cdcb7ed24adc8d6f8704/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51", size = 2145302, upload-time = "2025-11-04T13:43:46.64Z" },
+]
+
+[[package]]
+name = "pyelftools"
+version = "0.32"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/b9/ab/33968940b2deb3d92f5b146bc6d4009a5f95d1d06c148ea2f9ee965071af/pyelftools-0.32.tar.gz", hash = "sha256:6de90ee7b8263e740c8715a925382d4099b354f29ac48ea40d840cf7aa14ace5", size = 15047199, upload-time = "2025-02-19T14:20:05.549Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/af/43/700932c4f0638c3421177144a2e86448c0d75dbaee2c7936bda3f9fd0878/pyelftools-0.32-py3-none-any.whl", hash = "sha256:013df952a006db5e138b1edf6d8a68ecc50630adbd0d83a2d41e7f846163d738", size = 188525, upload-time = "2025-02-19T14:19:59.919Z" },
+]
+
+[[package]]
+name = "pygments"
+version = "2.19.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
+]
+
+[[package]]
+name = "pyjwt"
+version = "2.12.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions", marker = "python_full_version < '3.11'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c2/27/a3b6e5bf6ff856d2509292e95c8f57f0df7017cf5394921fc4e4ef40308a/pyjwt-2.12.1.tar.gz", hash = "sha256:c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b", size = 102564, upload-time = "2026-03-13T19:27:37.25Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e5/7a/8dd906bd22e79e47397a61742927f6747fe93242ef86645ee9092e610244/pyjwt-2.12.1-py3-none-any.whl", hash = "sha256:28ca37c070cad8ba8cd9790cd940535d40274d22f80ab87f3ac6a713e6e8454c", size = 29726, upload-time = "2026-03-13T19:27:35.677Z" },
+]
+
+[[package]]
+name = "pyparsing"
+version = "3.3.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload-time = "2026-01-21T03:57:59.36Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" },
+]
+
+[[package]]
+name = "pyproject-hooks"
+version = "1.2.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/e7/82/28175b2414effca1cdac8dc99f76d660e7a4fb0ceefa4b4ab8f5f6742925/pyproject_hooks-1.2.0.tar.gz", hash = "sha256:1e859bd5c40fae9448642dd871adf459e5e2084186e8d2c2a79a824c970da1f8", size = 19228, upload-time = "2024-09-29T09:24:13.293Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl", hash = "sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913", size = 10216, upload-time = "2024-09-29T09:24:11.978Z" },
+]
+
+[[package]]
+name = "pytest"
+version = "8.4.2"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version < '3.10'",
+]
+dependencies = [
+ { name = "colorama", marker = "python_full_version < '3.10' and sys_platform == 'win32'" },
+ { name = "exceptiongroup", marker = "python_full_version < '3.10'" },
+ { name = "iniconfig", version = "2.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "packaging", marker = "python_full_version < '3.10'" },
+ { name = "pluggy", marker = "python_full_version < '3.10'" },
+ { name = "pygments", marker = "python_full_version < '3.10'" },
+ { name = "tomli", marker = "python_full_version < '3.10'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" },
+]
+
+[[package]]
+name = "pytest"
+version = "9.0.3"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version >= '3.11'",
+ "python_full_version == '3.10.*'",
+]
+dependencies = [
+ { name = "colorama", marker = "python_full_version >= '3.10' and sys_platform == 'win32'" },
+ { name = "exceptiongroup", marker = "python_full_version == '3.10.*'" },
+ { name = "iniconfig", version = "2.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "packaging", marker = "python_full_version >= '3.10'" },
+ { name = "pluggy", marker = "python_full_version >= '3.10'" },
+ { name = "pygments", marker = "python_full_version >= '3.10'" },
+ { name = "tomli", marker = "python_full_version == '3.10.*'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/7d/0d/549bd94f1a0a402dc8cf64563a117c0f3765662e2e668477624baeec44d5/pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c", size = 1572165, upload-time = "2026-04-07T17:16:18.027Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9", size = 375249, upload-time = "2026-04-07T17:16:16.13Z" },
+]
+
+[[package]]
+name = "pytest-asyncio"
+version = "1.2.0"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version < '3.10'",
+]
+dependencies = [
+ { name = "backports-asyncio-runner", marker = "python_full_version < '3.10'" },
+ { name = "pytest", version = "8.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "typing-extensions", marker = "python_full_version < '3.10'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/42/86/9e3c5f48f7b7b638b216e4b9e645f54d199d7abbbab7a64a13b4e12ba10f/pytest_asyncio-1.2.0.tar.gz", hash = "sha256:c609a64a2a8768462d0c99811ddb8bd2583c33fd33cf7f21af1c142e824ffb57", size = 50119, upload-time = "2025-09-12T07:33:53.816Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl", hash = "sha256:8e17ae5e46d8e7efe51ab6494dd2010f4ca8dae51652aa3c8d55acf50bfb2e99", size = 15095, upload-time = "2025-09-12T07:33:52.639Z" },
+]
+
+[[package]]
+name = "pytest-asyncio"
+version = "1.3.0"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version >= '3.11'",
+ "python_full_version == '3.10.*'",
+]
+dependencies = [
+ { name = "backports-asyncio-runner", marker = "python_full_version == '3.10.*'" },
+ { name = "pytest", version = "9.0.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "typing-extensions", marker = "python_full_version >= '3.10' and python_full_version < '3.13'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/90/2c/8af215c0f776415f3590cac4f9086ccefd6fd463befeae41cd4d3f193e5a/pytest_asyncio-1.3.0.tar.gz", hash = "sha256:d7f52f36d231b80ee124cd216ffb19369aa168fc10095013c6b014a34d3ee9e5", size = 50087, upload-time = "2025-11-10T16:07:47.256Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e5/35/f8b19922b6a25bc0880171a2f1a003eaeb93657475193ab516fd87cac9da/pytest_asyncio-1.3.0-py3-none-any.whl", hash = "sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5", size = 15075, upload-time = "2025-11-10T16:07:45.537Z" },
+]
+
+[[package]]
+name = "python-dateutil"
+version = "2.9.0.post0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "six" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" },
+]
+
+[[package]]
+name = "python-sdks"
+version = "0.1.0"
+source = { virtual = "." }
+dependencies = [
+ { name = "livekit" },
+ { name = "livekit-api" },
+ { name = "livekit-protocol" },
+]
+
+[package.dev-dependencies]
+dev = [
+ { name = "auditwheel", version = "6.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' and sys_platform == 'linux'" },
+ { name = "auditwheel", version = "6.6.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' and sys_platform == 'linux'" },
+ { name = "cibuildwheel", version = "2.23.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
+ { name = "cibuildwheel", version = "3.3.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
+ { name = "ipython", version = "8.18.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "ipython", version = "8.38.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" },
+ { name = "ipython", version = "9.10.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
+ { name = "matplotlib", version = "3.9.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "matplotlib", version = "3.10.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "mypy" },
+ { name = "numpy", version = "2.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" },
+ { name = "numpy", version = "2.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
+ { name = "pydantic" },
+ { name = "pytest", version = "8.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "pytest", version = "9.0.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "pytest-asyncio", version = "1.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "pytest-asyncio", version = "1.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "requests" },
+ { name = "ruff" },
+ { name = "twine" },
+ { name = "types-aiofiles" },
+ { name = "wheel" },
+]
+
+[package.metadata]
+requires-dist = [
+ { name = "livekit", editable = "livekit-rtc" },
+ { name = "livekit-api", editable = "livekit-api" },
+ { name = "livekit-protocol", editable = "livekit-protocol" },
+]
+
+[package.metadata.requires-dev]
+dev = [
+ { name = "auditwheel", marker = "sys_platform == 'linux'" },
+ { name = "cibuildwheel" },
+ { name = "ipython", specifier = ">=8.0.0" },
+ { name = "matplotlib" },
+ { name = "mypy", specifier = ">=1.13.0" },
+ { name = "numpy" },
+ { name = "pydantic" },
+ { name = "pytest", specifier = ">=8.3.4" },
+ { name = "pytest-asyncio", specifier = ">=0.24.0" },
+ { name = "requests" },
+ { name = "ruff", specifier = ">=0.8.5" },
+ { name = "twine" },
+ { name = "types-aiofiles", specifier = ">=24" },
+ { name = "wheel" },
+]
+
+[[package]]
+name = "pywin32-ctypes"
+version = "0.2.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/85/9f/01a1a99704853cb63f253eea009390c88e7131c67e66a0a02099a8c917cb/pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755", size = 29471, upload-time = "2024-08-14T10:15:34.626Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8", size = 30756, upload-time = "2024-08-14T10:15:33.187Z" },
+]
+
+[[package]]
+name = "readme-renderer"
+version = "44.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "docutils" },
+ { name = "nh3" },
+ { name = "pygments" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/5a/a9/104ec9234c8448c4379768221ea6df01260cd6c2ce13182d4eac531c8342/readme_renderer-44.0.tar.gz", hash = "sha256:8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1", size = 32056, upload-time = "2024-07-08T15:00:57.805Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e1/67/921ec3024056483db83953ae8e48079ad62b92db7880013ca77632921dd0/readme_renderer-44.0-py3-none-any.whl", hash = "sha256:2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151", size = 13310, upload-time = "2024-07-08T15:00:56.577Z" },
+]
+
+[[package]]
+name = "requests"
+version = "2.32.5"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "certifi" },
+ { name = "charset-normalizer" },
+ { name = "idna" },
+ { name = "urllib3" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" },
+]
+
+[[package]]
+name = "requests-toolbelt"
+version = "1.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "requests" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", size = 206888, upload-time = "2023-05-01T04:11:33.229Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", size = 54481, upload-time = "2023-05-01T04:11:28.427Z" },
+]
+
+[[package]]
+name = "rfc3986"
+version = "2.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/85/40/1520d68bfa07ab5a6f065a186815fb6610c86fe957bc065754e47f7b0840/rfc3986-2.0.0.tar.gz", hash = "sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c", size = 49026, upload-time = "2022-01-10T00:52:30.832Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ff/9a/9afaade874b2fa6c752c36f1548f718b5b83af81ed9b76628329dab81c1b/rfc3986-2.0.0-py2.py3-none-any.whl", hash = "sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd", size = 31326, upload-time = "2022-01-10T00:52:29.594Z" },
+]
+
+[[package]]
+name = "rich"
+version = "14.3.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "markdown-it-py", version = "3.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "markdown-it-py", version = "4.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "pygments" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/b3/c6/f3b320c27991c46f43ee9d856302c70dc2d0fb2dba4842ff739d5f46b393/rich-14.3.3.tar.gz", hash = "sha256:b8daa0b9e4eef54dd8cf7c86c03713f53241884e814f4e2f5fb342fe520f639b", size = 230582, upload-time = "2026-02-19T17:23:12.474Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl", hash = "sha256:793431c1f8619afa7d3b52b2cdec859562b950ea0d4b6b505397612db8d5362d", size = 310458, upload-time = "2026-02-19T17:23:13.732Z" },
+]
+
+[[package]]
+name = "ruff"
+version = "0.15.4"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/da/31/d6e536cdebb6568ae75a7f00e4b4819ae0ad2640c3604c305a0428680b0c/ruff-0.15.4.tar.gz", hash = "sha256:3412195319e42d634470cc97aa9803d07e9d5c9223b99bcb1518f0c725f26ae1", size = 4569550, upload-time = "2026-02-26T20:04:14.959Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f2/82/c11a03cfec3a4d26a0ea1e571f0f44be5993b923f905eeddfc397c13d360/ruff-0.15.4-py3-none-linux_armv6l.whl", hash = "sha256:a1810931c41606c686bae8b5b9a8072adac2f611bb433c0ba476acba17a332e0", size = 10453333, upload-time = "2026-02-26T20:04:20.093Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/5d/6a1f271f6e31dffb31855996493641edc3eef8077b883eaf007a2f1c2976/ruff-0.15.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5a1632c66672b8b4d3e1d1782859e98d6e0b4e70829530666644286600a33992", size = 10853356, upload-time = "2026-02-26T20:04:05.808Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/d8/0fab9f8842b83b1a9c2bf81b85063f65e93fb512e60effa95b0be49bfc54/ruff-0.15.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a4386ba2cd6c0f4ff75252845906acc7c7c8e1ac567b7bc3d373686ac8c222ba", size = 10187434, upload-time = "2026-02-26T20:03:54.656Z" },
+ { url = "https://files.pythonhosted.org/packages/85/cc/cc220fd9394eff5db8d94dec199eec56dd6c9f3651d8869d024867a91030/ruff-0.15.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2496488bdfd3732747558b6f95ae427ff066d1fcd054daf75f5a50674411e75", size = 10535456, upload-time = "2026-02-26T20:03:52.738Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/0f/bced38fa5cf24373ec767713c8e4cadc90247f3863605fb030e597878661/ruff-0.15.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3f1c4893841ff2d54cbda1b2860fa3260173df5ddd7b95d370186f8a5e66a4ac", size = 10287772, upload-time = "2026-02-26T20:04:08.138Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/90/58a1802d84fed15f8f281925b21ab3cecd813bde52a8ca033a4de8ab0e7a/ruff-0.15.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:820b8766bd65503b6c30aaa6331e8ef3a6e564f7999c844e9a547c40179e440a", size = 11049051, upload-time = "2026-02-26T20:04:03.53Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/ac/b7ad36703c35f3866584564dc15f12f91cb1a26a897dc2fd13d7cb3ae1af/ruff-0.15.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9fb74bab47139c1751f900f857fa503987253c3ef89129b24ed375e72873e85", size = 11890494, upload-time = "2026-02-26T20:04:10.497Z" },
+ { url = "https://files.pythonhosted.org/packages/93/3d/3eb2f47a39a8b0da99faf9c54d3eb24720add1e886a5309d4d1be73a6380/ruff-0.15.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f80c98765949c518142b3a50a5db89343aa90f2c2bf7799de9986498ae6176db", size = 11326221, upload-time = "2026-02-26T20:04:12.84Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/90/bf134f4c1e5243e62690e09d63c55df948a74084c8ac3e48a88468314da6/ruff-0.15.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:451a2e224151729b3b6c9ffb36aed9091b2996fe4bdbd11f47e27d8f2e8888ec", size = 11168459, upload-time = "2026-02-26T20:04:00.969Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/e5/a64d27688789b06b5d55162aafc32059bb8c989c61a5139a36e1368285eb/ruff-0.15.4-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a8f157f2e583c513c4f5f896163a93198297371f34c04220daf40d133fdd4f7f", size = 11104366, upload-time = "2026-02-26T20:03:48.099Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/f6/32d1dcb66a2559763fc3027bdd65836cad9eb09d90f2ed6a63d8e9252b02/ruff-0.15.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:917cc68503357021f541e69b35361c99387cdbbf99bd0ea4aa6f28ca99ff5338", size = 10510887, upload-time = "2026-02-26T20:03:45.771Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/92/22d1ced50971c5b6433aed166fcef8c9343f567a94cf2b9d9089f6aa80fe/ruff-0.15.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e9737c8161da79fd7cfec19f1e35620375bd8b2a50c3e77fa3d2c16f574105cc", size = 10285939, upload-time = "2026-02-26T20:04:22.42Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/f4/7c20aec3143837641a02509a4668fb146a642fd1211846634edc17eb5563/ruff-0.15.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:291258c917539e18f6ba40482fe31d6f5ac023994ee11d7bdafd716f2aab8a68", size = 10765471, upload-time = "2026-02-26T20:03:58.924Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/09/6d2f7586f09a16120aebdff8f64d962d7c4348313c77ebb29c566cefc357/ruff-0.15.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:3f83c45911da6f2cd5936c436cf86b9f09f09165f033a99dcf7477e34041cbc3", size = 11263382, upload-time = "2026-02-26T20:04:24.424Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/fa/2ef715a1cd329ef47c1a050e10dee91a9054b7ce2fcfdd6a06d139afb7ec/ruff-0.15.4-py3-none-win32.whl", hash = "sha256:65594a2d557d4ee9f02834fcdf0a28daa8b3b9f6cb2cb93846025a36db47ef22", size = 10506664, upload-time = "2026-02-26T20:03:50.56Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/a8/c688ef7e29983976820d18710f955751d9f4d4eb69df658af3d006e2ba3e/ruff-0.15.4-py3-none-win_amd64.whl", hash = "sha256:04196ad44f0df220c2ece5b0e959c2f37c777375ec744397d21d15b50a75264f", size = 11651048, upload-time = "2026-02-26T20:04:17.191Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/0a/9e1be9035b37448ce2e68c978f0591da94389ade5a5abafa4cf99985d1b2/ruff-0.15.4-py3-none-win_arm64.whl", hash = "sha256:60d5177e8cfc70e51b9c5fad936c634872a74209f934c1e79107d11787ad5453", size = 10966776, upload-time = "2026-02-26T20:03:56.908Z" },
+]
+
+[[package]]
+name = "secretstorage"
+version = "3.3.3"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version < '3.10'",
+]
+dependencies = [
+ { name = "cryptography", marker = "python_full_version < '3.10'" },
+ { name = "jeepney", marker = "python_full_version < '3.10'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/53/a4/f48c9d79cb507ed1373477dbceaba7401fd8a23af63b837fa61f1dcd3691/SecretStorage-3.3.3.tar.gz", hash = "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77", size = 19739, upload-time = "2022-08-13T16:22:46.976Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/54/24/b4293291fa1dd830f353d2cb163295742fa87f179fcc8a20a306a81978b7/SecretStorage-3.3.3-py3-none-any.whl", hash = "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99", size = 15221, upload-time = "2022-08-13T16:22:44.457Z" },
+]
+
+[[package]]
+name = "secretstorage"
+version = "3.5.0"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version >= '3.11'",
+ "python_full_version == '3.10.*'",
+]
+dependencies = [
+ { name = "cryptography", marker = "python_full_version >= '3.10'" },
+ { name = "jeepney", marker = "python_full_version >= '3.10'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/1c/03/e834bcd866f2f8a49a85eaff47340affa3bfa391ee9912a952a1faa68c7b/secretstorage-3.5.0.tar.gz", hash = "sha256:f04b8e4689cbce351744d5537bf6b1329c6fc68f91fa666f60a380edddcd11be", size = 19884, upload-time = "2025-11-23T19:02:53.191Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b7/46/f5af3402b579fd5e11573ce652019a67074317e18c1935cc0b4ba9b35552/secretstorage-3.5.0-py3-none-any.whl", hash = "sha256:0ce65888c0725fcb2c5bc0fdb8e5438eece02c523557ea40ce0703c266248137", size = 15554, upload-time = "2025-11-23T19:02:51.545Z" },
+]
+
+[[package]]
+name = "six"
+version = "1.17.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
+]
+
+[[package]]
+name = "stack-data"
+version = "0.6.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "asttokens" },
+ { name = "executing" },
+ { name = "pure-eval" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" },
+]
+
+[[package]]
+name = "tomli"
+version = "2.4.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/82/30/31573e9457673ab10aa432461bee537ce6cef177667deca369efb79df071/tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c", size = 17477, upload-time = "2026-01-11T11:22:38.165Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3c/d9/3dc2289e1f3b32eb19b9785b6a006b28ee99acb37d1d47f78d4c10e28bf8/tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867", size = 153663, upload-time = "2026-01-11T11:21:45.27Z" },
+ { url = "https://files.pythonhosted.org/packages/51/32/ef9f6845e6b9ca392cd3f64f9ec185cc6f09f0a2df3db08cbe8809d1d435/tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9", size = 148469, upload-time = "2026-01-11T11:21:46.873Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/c2/506e44cce89a8b1b1e047d64bd495c22c9f71f21e05f380f1a950dd9c217/tomli-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95", size = 236039, upload-time = "2026-01-11T11:21:48.503Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/40/e1b65986dbc861b7e986e8ec394598187fa8aee85b1650b01dd925ca0be8/tomli-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76", size = 243007, upload-time = "2026-01-11T11:21:49.456Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/6f/6e39ce66b58a5b7ae572a0f4352ff40c71e8573633deda43f6a379d56b3e/tomli-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d", size = 240875, upload-time = "2026-01-11T11:21:50.755Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/ad/cb089cb190487caa80204d503c7fd0f4d443f90b95cf4ef5cf5aa0f439b0/tomli-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576", size = 246271, upload-time = "2026-01-11T11:21:51.81Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/63/69125220e47fd7a3a27fd0de0c6398c89432fec41bc739823bcc66506af6/tomli-2.4.0-cp311-cp311-win32.whl", hash = "sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a", size = 96770, upload-time = "2026-01-11T11:21:52.647Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/0d/a22bb6c83f83386b0008425a6cd1fa1c14b5f3dd4bad05e98cf3dbbf4a64/tomli-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa", size = 107626, upload-time = "2026-01-11T11:21:53.459Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/6d/77be674a3485e75cacbf2ddba2b146911477bd887dda9d8c9dfb2f15e871/tomli-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614", size = 94842, upload-time = "2026-01-11T11:21:54.831Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/43/7389a1869f2f26dba52404e1ef13b4784b6b37dac93bac53457e3ff24ca3/tomli-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1", size = 154894, upload-time = "2026-01-11T11:21:56.07Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/05/2f9bf110b5294132b2edf13fe6ca6ae456204f3d749f623307cbb7a946f2/tomli-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8", size = 149053, upload-time = "2026-01-11T11:21:57.467Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/41/1eda3ca1abc6f6154a8db4d714a4d35c4ad90adc0bcf700657291593fbf3/tomli-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a", size = 243481, upload-time = "2026-01-11T11:21:58.661Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/6d/02ff5ab6c8868b41e7d4b987ce2b5f6a51d3335a70aa144edd999e055a01/tomli-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1", size = 251720, upload-time = "2026-01-11T11:22:00.178Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/57/0405c59a909c45d5b6f146107c6d997825aa87568b042042f7a9c0afed34/tomli-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b", size = 247014, upload-time = "2026-01-11T11:22:01.238Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/0e/2e37568edd944b4165735687cbaf2fe3648129e440c26d02223672ee0630/tomli-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51", size = 251820, upload-time = "2026-01-11T11:22:02.727Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/1c/ee3b707fdac82aeeb92d1a113f803cf6d0f37bdca0849cb489553e1f417a/tomli-2.4.0-cp312-cp312-win32.whl", hash = "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729", size = 97712, upload-time = "2026-01-11T11:22:03.777Z" },
+ { url = "https://files.pythonhosted.org/packages/69/13/c07a9177d0b3bab7913299b9278845fc6eaaca14a02667c6be0b0a2270c8/tomli-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da", size = 108296, upload-time = "2026-01-11T11:22:04.86Z" },
+ { url = "https://files.pythonhosted.org/packages/18/27/e267a60bbeeee343bcc279bb9e8fbed0cbe224bc7b2a3dc2975f22809a09/tomli-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3", size = 94553, upload-time = "2026-01-11T11:22:05.854Z" },
+ { url = "https://files.pythonhosted.org/packages/34/91/7f65f9809f2936e1f4ce6268ae1903074563603b2a2bd969ebbda802744f/tomli-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84d081fbc252d1b6a982e1870660e7330fb8f90f676f6e78b052ad4e64714bf0", size = 154915, upload-time = "2026-01-11T11:22:06.703Z" },
+ { url = "https://files.pythonhosted.org/packages/20/aa/64dd73a5a849c2e8f216b755599c511badde80e91e9bc2271baa7b2cdbb1/tomli-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9a08144fa4cba33db5255f9b74f0b89888622109bd2776148f2597447f92a94e", size = 149038, upload-time = "2026-01-11T11:22:07.56Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/8a/6d38870bd3d52c8d1505ce054469a73f73a0fe62c0eaf5dddf61447e32fa/tomli-2.4.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c73add4bb52a206fd0c0723432db123c0c75c280cbd67174dd9d2db228ebb1b4", size = 242245, upload-time = "2026-01-11T11:22:08.344Z" },
+ { url = "https://files.pythonhosted.org/packages/59/bb/8002fadefb64ab2669e5b977df3f5e444febea60e717e755b38bb7c41029/tomli-2.4.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fb2945cbe303b1419e2706e711b7113da57b7db31ee378d08712d678a34e51e", size = 250335, upload-time = "2026-01-11T11:22:09.951Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/3d/4cdb6f791682b2ea916af2de96121b3cb1284d7c203d97d92d6003e91c8d/tomli-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bbb1b10aa643d973366dc2cb1ad94f99c1726a02343d43cbc011edbfac579e7c", size = 245962, upload-time = "2026-01-11T11:22:11.27Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/4a/5f25789f9a460bd858ba9756ff52d0830d825b458e13f754952dd15fb7bb/tomli-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4cbcb367d44a1f0c2be408758b43e1ffb5308abe0ea222897d6bfc8e8281ef2f", size = 250396, upload-time = "2026-01-11T11:22:12.325Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/2f/b73a36fea58dfa08e8b3a268750e6853a6aac2a349241a905ebd86f3047a/tomli-2.4.0-cp313-cp313-win32.whl", hash = "sha256:7d49c66a7d5e56ac959cb6fc583aff0651094ec071ba9ad43df785abc2320d86", size = 97530, upload-time = "2026-01-11T11:22:13.865Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/af/ca18c134b5d75de7e8dc551c5234eaba2e8e951f6b30139599b53de9c187/tomli-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:3cf226acb51d8f1c394c1b310e0e0e61fecdd7adcb78d01e294ac297dd2e7f87", size = 108227, upload-time = "2026-01-11T11:22:15.224Z" },
+ { url = "https://files.pythonhosted.org/packages/22/c3/b386b832f209fee8073c8138ec50f27b4460db2fdae9ffe022df89a57f9b/tomli-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:d20b797a5c1ad80c516e41bc1fb0443ddb5006e9aaa7bda2d71978346aeb9132", size = 94748, upload-time = "2026-01-11T11:22:16.009Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/c4/84047a97eb1004418bc10bdbcfebda209fca6338002eba2dc27cc6d13563/tomli-2.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:26ab906a1eb794cd4e103691daa23d95c6919cc2fa9160000ac02370cc9dd3f6", size = 154725, upload-time = "2026-01-11T11:22:17.269Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/5d/d39038e646060b9d76274078cddf146ced86dc2b9e8bbf737ad5983609a0/tomli-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:20cedb4ee43278bc4f2fee6cb50daec836959aadaf948db5172e776dd3d993fc", size = 148901, upload-time = "2026-01-11T11:22:18.287Z" },
+ { url = "https://files.pythonhosted.org/packages/73/e5/383be1724cb30f4ce44983d249645684a48c435e1cd4f8b5cded8a816d3c/tomli-2.4.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39b0b5d1b6dd03684b3fb276407ebed7090bbec989fa55838c98560c01113b66", size = 243375, upload-time = "2026-01-11T11:22:19.154Z" },
+ { url = "https://files.pythonhosted.org/packages/31/f0/bea80c17971c8d16d3cc109dc3585b0f2ce1036b5f4a8a183789023574f2/tomli-2.4.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a26d7ff68dfdb9f87a016ecfd1e1c2bacbe3108f4e0f8bcd2228ef9a766c787d", size = 250639, upload-time = "2026-01-11T11:22:20.168Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/8f/2853c36abbb7608e3f945d8a74e32ed3a74ee3a1f468f1ffc7d1cb3abba6/tomli-2.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:20ffd184fb1df76a66e34bd1b36b4a4641bd2b82954befa32fe8163e79f1a702", size = 246897, upload-time = "2026-01-11T11:22:21.544Z" },
+ { url = "https://files.pythonhosted.org/packages/49/f0/6c05e3196ed5337b9fe7ea003e95fd3819a840b7a0f2bf5a408ef1dad8ed/tomli-2.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75c2f8bbddf170e8effc98f5e9084a8751f8174ea6ccf4fca5398436e0320bc8", size = 254697, upload-time = "2026-01-11T11:22:23.058Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/f5/2922ef29c9f2951883525def7429967fc4d8208494e5ab524234f06b688b/tomli-2.4.0-cp314-cp314-win32.whl", hash = "sha256:31d556d079d72db7c584c0627ff3a24c5d3fb4f730221d3444f3efb1b2514776", size = 98567, upload-time = "2026-01-11T11:22:24.033Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/31/22b52e2e06dd2a5fdbc3ee73226d763b184ff21fc24e20316a44ccc4d96b/tomli-2.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:43e685b9b2341681907759cf3a04e14d7104b3580f808cfde1dfdb60ada85475", size = 108556, upload-time = "2026-01-11T11:22:25.378Z" },
+ { url = "https://files.pythonhosted.org/packages/48/3d/5058dff3255a3d01b705413f64f4306a141a8fd7a251e5a495e3f192a998/tomli-2.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:3d895d56bd3f82ddd6faaff993c275efc2ff38e52322ea264122d72729dca2b2", size = 96014, upload-time = "2026-01-11T11:22:26.138Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/4e/75dab8586e268424202d3a1997ef6014919c941b50642a1682df43204c22/tomli-2.4.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5b5807f3999fb66776dbce568cc9a828544244a8eb84b84b9bafc080c99597b9", size = 163339, upload-time = "2026-01-11T11:22:27.143Z" },
+ { url = "https://files.pythonhosted.org/packages/06/e3/b904d9ab1016829a776d97f163f183a48be6a4deb87304d1e0116a349519/tomli-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c084ad935abe686bd9c898e62a02a19abfc9760b5a79bc29644463eaf2840cb0", size = 159490, upload-time = "2026-01-11T11:22:28.399Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/5a/fc3622c8b1ad823e8ea98a35e3c632ee316d48f66f80f9708ceb4f2a0322/tomli-2.4.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f2e3955efea4d1cfbcb87bc321e00dc08d2bcb737fd1d5e398af111d86db5df", size = 269398, upload-time = "2026-01-11T11:22:29.345Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/33/62bd6152c8bdd4c305ad9faca48f51d3acb2df1f8791b1477d46ff86e7f8/tomli-2.4.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e0fe8a0b8312acf3a88077a0802565cb09ee34107813bba1c7cd591fa6cfc8d", size = 276515, upload-time = "2026-01-11T11:22:30.327Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/ff/ae53619499f5235ee4211e62a8d7982ba9e439a0fb4f2f351a93d67c1dd2/tomli-2.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:413540dce94673591859c4c6f794dfeaa845e98bf35d72ed59636f869ef9f86f", size = 273806, upload-time = "2026-01-11T11:22:32.56Z" },
+ { url = "https://files.pythonhosted.org/packages/47/71/cbca7787fa68d4d0a9f7072821980b39fbb1b6faeb5f5cf02f4a5559fa28/tomli-2.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0dc56fef0e2c1c470aeac5b6ca8cc7b640bb93e92d9803ddaf9ea03e198f5b0b", size = 281340, upload-time = "2026-01-11T11:22:33.505Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/00/d595c120963ad42474cf6ee7771ad0d0e8a49d0f01e29576ee9195d9ecdf/tomli-2.4.0-cp314-cp314t-win32.whl", hash = "sha256:d878f2a6707cc9d53a1be1414bbb419e629c3d6e67f69230217bb663e76b5087", size = 108106, upload-time = "2026-01-11T11:22:34.451Z" },
+ { url = "https://files.pythonhosted.org/packages/de/69/9aa0c6a505c2f80e519b43764f8b4ba93b5a0bbd2d9a9de6e2b24271b9a5/tomli-2.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2add28aacc7425117ff6364fe9e06a183bb0251b03f986df0e78e974047571fd", size = 120504, upload-time = "2026-01-11T11:22:35.764Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/9f/f1668c281c58cfae01482f7114a4b88d345e4c140386241a1a24dcc9e7bc/tomli-2.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2b1e3b80e1d5e52e40e9b924ec43d81570f0e7d09d11081b797bc4692765a3d4", size = 99561, upload-time = "2026-01-11T11:22:36.624Z" },
+ { url = "https://files.pythonhosted.org/packages/23/d1/136eb2cb77520a31e1f64cbae9d33ec6df0d78bdf4160398e86eec8a8754/tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a", size = 14477, upload-time = "2026-01-11T11:22:37.446Z" },
+]
+
+[[package]]
+name = "traitlets"
+version = "5.14.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621, upload-time = "2024-04-19T11:11:49.746Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" },
+]
+
+[[package]]
+name = "twine"
+version = "6.2.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "id" },
+ { name = "importlib-metadata", marker = "python_full_version < '3.10'" },
+ { name = "keyring", marker = "platform_machine != 'ppc64le' and platform_machine != 's390x'" },
+ { name = "packaging" },
+ { name = "readme-renderer" },
+ { name = "requests" },
+ { name = "requests-toolbelt" },
+ { name = "rfc3986" },
+ { name = "rich" },
+ { name = "urllib3" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/e0/a8/949edebe3a82774c1ec34f637f5dd82d1cf22c25e963b7d63771083bbee5/twine-6.2.0.tar.gz", hash = "sha256:e5ed0d2fd70c9959770dce51c8f39c8945c574e18173a7b81802dab51b4b75cf", size = 172262, upload-time = "2025-09-04T15:43:17.255Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3a/7a/882d99539b19b1490cac5d77c67338d126e4122c8276bf640e411650c830/twine-6.2.0-py3-none-any.whl", hash = "sha256:418ebf08ccda9a8caaebe414433b0ba5e25eb5e4a927667122fbe8f829f985d8", size = 42727, upload-time = "2025-09-04T15:43:15.994Z" },
+]
+
+[[package]]
+name = "types-aiofiles"
+version = "25.1.0.20251011"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/84/6c/6d23908a8217e36704aa9c79d99a620f2fdd388b66a4b7f72fbc6b6ff6c6/types_aiofiles-25.1.0.20251011.tar.gz", hash = "sha256:1c2b8ab260cb3cd40c15f9d10efdc05a6e1e6b02899304d80dfa0410e028d3ff", size = 14535, upload-time = "2025-10-11T02:44:51.237Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/71/0f/76917bab27e270bb6c32addd5968d69e558e5b6f7fb4ac4cbfa282996a96/types_aiofiles-25.1.0.20251011-py3-none-any.whl", hash = "sha256:8ff8de7f9d42739d8f0dadcceeb781ce27cd8d8c4152d4a7c52f6b20edb8149c", size = 14338, upload-time = "2025-10-11T02:44:50.054Z" },
+]
+
+[[package]]
+name = "types-protobuf"
+version = "6.32.1.20251210"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version < '3.10'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c2/59/c743a842911887cd96d56aa8936522b0cd5f7a7f228c96e81b59fced45be/types_protobuf-6.32.1.20251210.tar.gz", hash = "sha256:c698bb3f020274b1a2798ae09dc773728ce3f75209a35187bd11916ebfde6763", size = 63900, upload-time = "2025-12-10T03:14:25.451Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/aa/43/58e75bac4219cbafee83179505ff44cae3153ec279be0e30583a73b8f108/types_protobuf-6.32.1.20251210-py3-none-any.whl", hash = "sha256:2641f78f3696822a048cfb8d0ff42ccd85c25f12f871fbebe86da63793692140", size = 77921, upload-time = "2025-12-10T03:14:24.477Z" },
+]
+
+[[package]]
+name = "types-protobuf"
+version = "6.32.1.20260221"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version >= '3.11'",
+ "python_full_version == '3.10.*'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/5f/e2/9aa4a3b2469508bd7b4e2ae11cbedaf419222a09a1b94daffcd5efca4023/types_protobuf-6.32.1.20260221.tar.gz", hash = "sha256:6d5fb060a616bfb076cbb61b4b3c3969f5fc8bec5810f9a2f7e648ee5cbcbf6e", size = 64408, upload-time = "2026-02-21T03:55:13.916Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2e/e8/1fd38926f9cf031188fbc5a96694203ea6f24b0e34bd64a225ec6f6291ba/types_protobuf-6.32.1.20260221-py3-none-any.whl", hash = "sha256:da7cdd947975964a93c30bfbcc2c6841ee646b318d3816b033adc2c4eb6448e4", size = 77956, upload-time = "2026-02-21T03:55:12.894Z" },
+]
+
+[[package]]
+name = "typing-extensions"
+version = "4.15.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
+]
+
+[[package]]
+name = "typing-inspection"
+version = "0.4.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" },
+]
+
+[[package]]
+name = "urllib3"
+version = "2.6.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" },
+]
+
+[[package]]
+name = "wcwidth"
+version = "0.6.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/35/a2/8e3becb46433538a38726c948d3399905a4c7cabd0df578ede5dc51f0ec2/wcwidth-0.6.0.tar.gz", hash = "sha256:cdc4e4262d6ef9a1a57e018384cbeb1208d8abbc64176027e2c2455c81313159", size = 159684, upload-time = "2026-02-06T19:19:40.919Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/68/5a/199c59e0a824a3db2b89c5d2dade7ab5f9624dbf6448dc291b46d5ec94d3/wcwidth-0.6.0-py3-none-any.whl", hash = "sha256:1a3a1e510b553315f8e146c54764f4fb6264ffad731b3d78088cdb1478ffbdad", size = 94189, upload-time = "2026-02-06T19:19:39.646Z" },
+]
+
+[[package]]
+name = "wheel"
+version = "0.46.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "packaging" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/89/24/a2eb353a6edac9a0303977c4cb048134959dd2a51b48a269dfc9dde00c8a/wheel-0.46.3.tar.gz", hash = "sha256:e3e79874b07d776c40bd6033f8ddf76a7dad46a7b8aa1b2787a83083519a1803", size = 60605, upload-time = "2026-01-22T12:39:49.136Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/87/22/b76d483683216dde3d67cba61fb2444be8d5be289bf628c13fc0fd90e5f9/wheel-0.46.3-py3-none-any.whl", hash = "sha256:4b399d56c9d9338230118d705d9737a2a468ccca63d5e813e2a4fc7815d8bc4d", size = 30557, upload-time = "2026-01-22T12:39:48.099Z" },
+]
+
+[[package]]
+name = "yarl"
+version = "1.22.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "idna" },
+ { name = "multidict" },
+ { name = "propcache" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169, upload-time = "2025-10-06T14:12:55.963Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d1/43/a2204825342f37c337f5edb6637040fa14e365b2fcc2346960201d457579/yarl-1.22.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c7bd6683587567e5a49ee6e336e0612bec8329be1b7d4c8af5687dcdeb67ee1e", size = 140517, upload-time = "2025-10-06T14:08:42.494Z" },
+ { url = "https://files.pythonhosted.org/packages/44/6f/674f3e6f02266428c56f704cd2501c22f78e8b2eeb23f153117cc86fb28a/yarl-1.22.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5cdac20da754f3a723cceea5b3448e1a2074866406adeb4ef35b469d089adb8f", size = 93495, upload-time = "2025-10-06T14:08:46.2Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/12/5b274d8a0f30c07b91b2f02cba69152600b47830fcfb465c108880fcee9c/yarl-1.22.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07a524d84df0c10f41e3ee918846e1974aba4ec017f990dc735aad487a0bdfdf", size = 94400, upload-time = "2025-10-06T14:08:47.855Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/7f/df1b6949b1fa1aa9ff6de6e2631876ad4b73c4437822026e85d8acb56bb1/yarl-1.22.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1b329cb8146d7b736677a2440e422eadd775d1806a81db2d4cded80a48efc1a", size = 347545, upload-time = "2025-10-06T14:08:49.683Z" },
+ { url = "https://files.pythonhosted.org/packages/84/09/f92ed93bd6cd77872ab6c3462df45ca45cd058d8f1d0c9b4f54c1704429f/yarl-1.22.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:75976c6945d85dbb9ee6308cd7ff7b1fb9409380c82d6119bd778d8fcfe2931c", size = 319598, upload-time = "2025-10-06T14:08:51.215Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/97/ac3f3feae7d522cf7ccec3d340bb0b2b61c56cb9767923df62a135092c6b/yarl-1.22.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:80ddf7a5f8c86cb3eb4bc9028b07bbbf1f08a96c5c0bc1244be5e8fefcb94147", size = 363893, upload-time = "2025-10-06T14:08:53.144Z" },
+ { url = "https://files.pythonhosted.org/packages/06/49/f3219097403b9c84a4d079b1d7bda62dd9b86d0d6e4428c02d46ab2c77fc/yarl-1.22.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d332fc2e3c94dad927f2112395772a4e4fedbcf8f80efc21ed7cdfae4d574fdb", size = 371240, upload-time = "2025-10-06T14:08:55.036Z" },
+ { url = "https://files.pythonhosted.org/packages/35/9f/06b765d45c0e44e8ecf0fe15c9eacbbde342bb5b7561c46944f107bfb6c3/yarl-1.22.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0cf71bf877efeac18b38d3930594c0948c82b64547c1cf420ba48722fe5509f6", size = 346965, upload-time = "2025-10-06T14:08:56.722Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/69/599e7cea8d0fcb1694323b0db0dda317fa3162f7b90166faddecf532166f/yarl-1.22.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:663e1cadaddae26be034a6ab6072449a8426ddb03d500f43daf952b74553bba0", size = 342026, upload-time = "2025-10-06T14:08:58.563Z" },
+ { url = "https://files.pythonhosted.org/packages/95/6f/9dfd12c8bc90fea9eab39832ee32ea48f8e53d1256252a77b710c065c89f/yarl-1.22.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6dcbb0829c671f305be48a7227918cfcd11276c2d637a8033a99a02b67bf9eda", size = 335637, upload-time = "2025-10-06T14:09:00.506Z" },
+ { url = "https://files.pythonhosted.org/packages/57/2e/34c5b4eb9b07e16e873db5b182c71e5f06f9b5af388cdaa97736d79dd9a6/yarl-1.22.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f0d97c18dfd9a9af4490631905a3f131a8e4c9e80a39353919e2cfed8f00aedc", size = 359082, upload-time = "2025-10-06T14:09:01.936Z" },
+ { url = "https://files.pythonhosted.org/packages/31/71/fa7e10fb772d273aa1f096ecb8ab8594117822f683bab7d2c5a89914c92a/yarl-1.22.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:437840083abe022c978470b942ff832c3940b2ad3734d424b7eaffcd07f76737", size = 357811, upload-time = "2025-10-06T14:09:03.445Z" },
+ { url = "https://files.pythonhosted.org/packages/26/da/11374c04e8e1184a6a03cf9c8f5688d3e5cec83ed6f31ad3481b3207f709/yarl-1.22.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a899cbd98dce6f5d8de1aad31cb712ec0a530abc0a86bd6edaa47c1090138467", size = 351223, upload-time = "2025-10-06T14:09:05.401Z" },
+ { url = "https://files.pythonhosted.org/packages/82/8f/e2d01f161b0c034a30410e375e191a5d27608c1f8693bab1a08b089ca096/yarl-1.22.0-cp310-cp310-win32.whl", hash = "sha256:595697f68bd1f0c1c159fcb97b661fc9c3f5db46498043555d04805430e79bea", size = 82118, upload-time = "2025-10-06T14:09:11.148Z" },
+ { url = "https://files.pythonhosted.org/packages/62/46/94c76196642dbeae634c7a61ba3da88cd77bed875bf6e4a8bed037505aa6/yarl-1.22.0-cp310-cp310-win_amd64.whl", hash = "sha256:cb95a9b1adaa48e41815a55ae740cfda005758104049a640a398120bf02515ca", size = 86852, upload-time = "2025-10-06T14:09:12.958Z" },
+ { url = "https://files.pythonhosted.org/packages/af/af/7df4f179d3b1a6dcb9a4bd2ffbc67642746fcafdb62580e66876ce83fff4/yarl-1.22.0-cp310-cp310-win_arm64.whl", hash = "sha256:b85b982afde6df99ecc996990d4ad7ccbdbb70e2a4ba4de0aecde5922ba98a0b", size = 82012, upload-time = "2025-10-06T14:09:14.664Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/27/5ab13fc84c76a0250afd3d26d5936349a35be56ce5785447d6c423b26d92/yarl-1.22.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ab72135b1f2db3fed3997d7e7dc1b80573c67138023852b6efb336a5eae6511", size = 141607, upload-time = "2025-10-06T14:09:16.298Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/a1/d065d51d02dc02ce81501d476b9ed2229d9a990818332242a882d5d60340/yarl-1.22.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:669930400e375570189492dc8d8341301578e8493aec04aebc20d4717f899dd6", size = 94027, upload-time = "2025-10-06T14:09:17.786Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/da/8da9f6a53f67b5106ffe902c6fa0164e10398d4e150d85838b82f424072a/yarl-1.22.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:792a2af6d58177ef7c19cbf0097aba92ca1b9cb3ffdd9c7470e156c8f9b5e028", size = 94963, upload-time = "2025-10-06T14:09:19.662Z" },
+ { url = "https://files.pythonhosted.org/packages/68/fe/2c1f674960c376e29cb0bec1249b117d11738db92a6ccc4a530b972648db/yarl-1.22.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ea66b1c11c9150f1372f69afb6b8116f2dd7286f38e14ea71a44eee9ec51b9d", size = 368406, upload-time = "2025-10-06T14:09:21.402Z" },
+ { url = "https://files.pythonhosted.org/packages/95/26/812a540e1c3c6418fec60e9bbd38e871eaba9545e94fa5eff8f4a8e28e1e/yarl-1.22.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3e2daa88dc91870215961e96a039ec73e4937da13cf77ce17f9cad0c18df3503", size = 336581, upload-time = "2025-10-06T14:09:22.98Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/f5/5777b19e26fdf98563985e481f8be3d8a39f8734147a6ebf459d0dab5a6b/yarl-1.22.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba440ae430c00eee41509353628600212112cd5018d5def7e9b05ea7ac34eb65", size = 388924, upload-time = "2025-10-06T14:09:24.655Z" },
+ { url = "https://files.pythonhosted.org/packages/86/08/24bd2477bd59c0bbd994fe1d93b126e0472e4e3df5a96a277b0a55309e89/yarl-1.22.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e6438cc8f23a9c1478633d216b16104a586b9761db62bfacb6425bac0a36679e", size = 392890, upload-time = "2025-10-06T14:09:26.617Z" },
+ { url = "https://files.pythonhosted.org/packages/46/00/71b90ed48e895667ecfb1eaab27c1523ee2fa217433ed77a73b13205ca4b/yarl-1.22.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c52a6e78aef5cf47a98ef8e934755abf53953379b7d53e68b15ff4420e6683d", size = 365819, upload-time = "2025-10-06T14:09:28.544Z" },
+ { url = "https://files.pythonhosted.org/packages/30/2d/f715501cae832651d3282387c6a9236cd26bd00d0ff1e404b3dc52447884/yarl-1.22.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3b06bcadaac49c70f4c88af4ffcfbe3dc155aab3163e75777818092478bcbbe7", size = 363601, upload-time = "2025-10-06T14:09:30.568Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/f9/a678c992d78e394e7126ee0b0e4e71bd2775e4334d00a9278c06a6cce96a/yarl-1.22.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:6944b2dc72c4d7f7052683487e3677456050ff77fcf5e6204e98caf785ad1967", size = 358072, upload-time = "2025-10-06T14:09:32.528Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/d1/b49454411a60edb6fefdcad4f8e6dbba7d8019e3a508a1c5836cba6d0781/yarl-1.22.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d5372ca1df0f91a86b047d1277c2aaf1edb32d78bbcefffc81b40ffd18f027ed", size = 385311, upload-time = "2025-10-06T14:09:34.634Z" },
+ { url = "https://files.pythonhosted.org/packages/87/e5/40d7a94debb8448c7771a916d1861d6609dddf7958dc381117e7ba36d9e8/yarl-1.22.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:51af598701f5299012b8416486b40fceef8c26fc87dc6d7d1f6fc30609ea0aa6", size = 381094, upload-time = "2025-10-06T14:09:36.268Z" },
+ { url = "https://files.pythonhosted.org/packages/35/d8/611cc282502381ad855448643e1ad0538957fc82ae83dfe7762c14069e14/yarl-1.22.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b266bd01fedeffeeac01a79ae181719ff848a5a13ce10075adbefc8f1daee70e", size = 370944, upload-time = "2025-10-06T14:09:37.872Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/df/fadd00fb1c90e1a5a8bd731fa3d3de2e165e5a3666a095b04e31b04d9cb6/yarl-1.22.0-cp311-cp311-win32.whl", hash = "sha256:a9b1ba5610a4e20f655258d5a1fdc7ebe3d837bb0e45b581398b99eb98b1f5ca", size = 81804, upload-time = "2025-10-06T14:09:39.359Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/f7/149bb6f45f267cb5c074ac40c01c6b3ea6d8a620d34b337f6321928a1b4d/yarl-1.22.0-cp311-cp311-win_amd64.whl", hash = "sha256:078278b9b0b11568937d9509b589ee83ef98ed6d561dfe2020e24a9fd08eaa2b", size = 86858, upload-time = "2025-10-06T14:09:41.068Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/13/88b78b93ad3f2f0b78e13bfaaa24d11cbc746e93fe76d8c06bf139615646/yarl-1.22.0-cp311-cp311-win_arm64.whl", hash = "sha256:b6a6f620cfe13ccec221fa312139135166e47ae169f8253f72a0abc0dae94376", size = 81637, upload-time = "2025-10-06T14:09:42.712Z" },
+ { url = "https://files.pythonhosted.org/packages/75/ff/46736024fee3429b80a165a732e38e5d5a238721e634ab41b040d49f8738/yarl-1.22.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e340382d1afa5d32b892b3ff062436d592ec3d692aeea3bef3a5cfe11bbf8c6f", size = 142000, upload-time = "2025-10-06T14:09:44.631Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/9a/b312ed670df903145598914770eb12de1bac44599549b3360acc96878df8/yarl-1.22.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f1e09112a2c31ffe8d80be1b0988fa6a18c5d5cad92a9ffbb1c04c91bfe52ad2", size = 94338, upload-time = "2025-10-06T14:09:46.372Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/f5/0601483296f09c3c65e303d60c070a5c19fcdbc72daa061e96170785bc7d/yarl-1.22.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:939fe60db294c786f6b7c2d2e121576628468f65453d86b0fe36cb52f987bd74", size = 94909, upload-time = "2025-10-06T14:09:48.648Z" },
+ { url = "https://files.pythonhosted.org/packages/60/41/9a1fe0b73dbcefce72e46cf149b0e0a67612d60bfc90fb59c2b2efdfbd86/yarl-1.22.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1651bf8e0398574646744c1885a41198eba53dc8a9312b954073f845c90a8df", size = 372940, upload-time = "2025-10-06T14:09:50.089Z" },
+ { url = "https://files.pythonhosted.org/packages/17/7a/795cb6dfee561961c30b800f0ed616b923a2ec6258b5def2a00bf8231334/yarl-1.22.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b8a0588521a26bf92a57a1705b77b8b59044cdceccac7151bd8d229e66b8dedb", size = 345825, upload-time = "2025-10-06T14:09:52.142Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/93/a58f4d596d2be2ae7bab1a5846c4d270b894958845753b2c606d666744d3/yarl-1.22.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:42188e6a615c1a75bcaa6e150c3fe8f3e8680471a6b10150c5f7e83f47cc34d2", size = 386705, upload-time = "2025-10-06T14:09:54.128Z" },
+ { url = "https://files.pythonhosted.org/packages/61/92/682279d0e099d0e14d7fd2e176bd04f48de1484f56546a3e1313cd6c8e7c/yarl-1.22.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f6d2cb59377d99718913ad9a151030d6f83ef420a2b8f521d94609ecc106ee82", size = 396518, upload-time = "2025-10-06T14:09:55.762Z" },
+ { url = "https://files.pythonhosted.org/packages/db/0f/0d52c98b8a885aeda831224b78f3be7ec2e1aa4a62091f9f9188c3c65b56/yarl-1.22.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50678a3b71c751d58d7908edc96d332af328839eea883bb554a43f539101277a", size = 377267, upload-time = "2025-10-06T14:09:57.958Z" },
+ { url = "https://files.pythonhosted.org/packages/22/42/d2685e35908cbeaa6532c1fc73e89e7f2efb5d8a7df3959ea8e37177c5a3/yarl-1.22.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e8fbaa7cec507aa24ea27a01456e8dd4b6fab829059b69844bd348f2d467124", size = 365797, upload-time = "2025-10-06T14:09:59.527Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/83/cf8c7bcc6355631762f7d8bdab920ad09b82efa6b722999dfb05afa6cfac/yarl-1.22.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:433885ab5431bc3d3d4f2f9bd15bfa1614c522b0f1405d62c4f926ccd69d04fa", size = 365535, upload-time = "2025-10-06T14:10:01.139Z" },
+ { url = "https://files.pythonhosted.org/packages/25/e1/5302ff9b28f0c59cac913b91fe3f16c59a033887e57ce9ca5d41a3a94737/yarl-1.22.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:b790b39c7e9a4192dc2e201a282109ed2985a1ddbd5ac08dc56d0e121400a8f7", size = 382324, upload-time = "2025-10-06T14:10:02.756Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/cd/4617eb60f032f19ae3a688dc990d8f0d89ee0ea378b61cac81ede3e52fae/yarl-1.22.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:31f0b53913220599446872d757257be5898019c85e7971599065bc55065dc99d", size = 383803, upload-time = "2025-10-06T14:10:04.552Z" },
+ { url = "https://files.pythonhosted.org/packages/59/65/afc6e62bb506a319ea67b694551dab4a7e6fb7bf604e9bd9f3e11d575fec/yarl-1.22.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a49370e8f711daec68d09b821a34e1167792ee2d24d405cbc2387be4f158b520", size = 374220, upload-time = "2025-10-06T14:10:06.489Z" },
+ { url = "https://files.pythonhosted.org/packages/e7/3d/68bf18d50dc674b942daec86a9ba922d3113d8399b0e52b9897530442da2/yarl-1.22.0-cp312-cp312-win32.whl", hash = "sha256:70dfd4f241c04bd9239d53b17f11e6ab672b9f1420364af63e8531198e3f5fe8", size = 81589, upload-time = "2025-10-06T14:10:09.254Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/9a/6ad1a9b37c2f72874f93e691b2e7ecb6137fb2b899983125db4204e47575/yarl-1.22.0-cp312-cp312-win_amd64.whl", hash = "sha256:8884d8b332a5e9b88e23f60bb166890009429391864c685e17bd73a9eda9105c", size = 87213, upload-time = "2025-10-06T14:10:11.369Z" },
+ { url = "https://files.pythonhosted.org/packages/44/c5/c21b562d1680a77634d748e30c653c3ca918beb35555cff24986fff54598/yarl-1.22.0-cp312-cp312-win_arm64.whl", hash = "sha256:ea70f61a47f3cc93bdf8b2f368ed359ef02a01ca6393916bc8ff877427181e74", size = 81330, upload-time = "2025-10-06T14:10:13.112Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/f3/d67de7260456ee105dc1d162d43a019ecad6b91e2f51809d6cddaa56690e/yarl-1.22.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8dee9c25c74997f6a750cd317b8ca63545169c098faee42c84aa5e506c819b53", size = 139980, upload-time = "2025-10-06T14:10:14.601Z" },
+ { url = "https://files.pythonhosted.org/packages/01/88/04d98af0b47e0ef42597b9b28863b9060bb515524da0a65d5f4db160b2d5/yarl-1.22.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:01e73b85a5434f89fc4fe27dcda2aff08ddf35e4d47bbbea3bdcd25321af538a", size = 93424, upload-time = "2025-10-06T14:10:16.115Z" },
+ { url = "https://files.pythonhosted.org/packages/18/91/3274b215fd8442a03975ce6bee5fe6aa57a8326b29b9d3d56234a1dca244/yarl-1.22.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:22965c2af250d20c873cdbee8ff958fb809940aeb2e74ba5f20aaf6b7ac8c70c", size = 93821, upload-time = "2025-10-06T14:10:17.993Z" },
+ { url = "https://files.pythonhosted.org/packages/61/3a/caf4e25036db0f2da4ca22a353dfeb3c9d3c95d2761ebe9b14df8fc16eb0/yarl-1.22.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4f15793aa49793ec8d1c708ab7f9eded1aa72edc5174cae703651555ed1b601", size = 373243, upload-time = "2025-10-06T14:10:19.44Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/9e/51a77ac7516e8e7803b06e01f74e78649c24ee1021eca3d6a739cb6ea49c/yarl-1.22.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5542339dcf2747135c5c85f68680353d5cb9ffd741c0f2e8d832d054d41f35a", size = 342361, upload-time = "2025-10-06T14:10:21.124Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/f8/33b92454789dde8407f156c00303e9a891f1f51a0330b0fad7c909f87692/yarl-1.22.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5c401e05ad47a75869c3ab3e35137f8468b846770587e70d71e11de797d113df", size = 387036, upload-time = "2025-10-06T14:10:22.902Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/9a/c5db84ea024f76838220280f732970aa4ee154015d7f5c1bfb60a267af6f/yarl-1.22.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:243dda95d901c733f5b59214d28b0120893d91777cb8aa043e6ef059d3cddfe2", size = 397671, upload-time = "2025-10-06T14:10:24.523Z" },
+ { url = "https://files.pythonhosted.org/packages/11/c9/cd8538dc2e7727095e0c1d867bad1e40c98f37763e6d995c1939f5fdc7b1/yarl-1.22.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bec03d0d388060058f5d291a813f21c011041938a441c593374da6077fe21b1b", size = 377059, upload-time = "2025-10-06T14:10:26.406Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/b9/ab437b261702ced75122ed78a876a6dec0a1b0f5e17a4ac7a9a2482d8abe/yarl-1.22.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0748275abb8c1e1e09301ee3cf90c8a99678a4e92e4373705f2a2570d581273", size = 365356, upload-time = "2025-10-06T14:10:28.461Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/9d/8e1ae6d1d008a9567877b08f0ce4077a29974c04c062dabdb923ed98e6fe/yarl-1.22.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:47fdb18187e2a4e18fda2c25c05d8251a9e4a521edaed757fef033e7d8498d9a", size = 361331, upload-time = "2025-10-06T14:10:30.541Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/5a/09b7be3905962f145b73beb468cdd53db8aa171cf18c80400a54c5b82846/yarl-1.22.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c7044802eec4524fde550afc28edda0dd5784c4c45f0be151a2d3ba017daca7d", size = 382590, upload-time = "2025-10-06T14:10:33.352Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/7f/59ec509abf90eda5048b0bc3e2d7b5099dffdb3e6b127019895ab9d5ef44/yarl-1.22.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:139718f35149ff544caba20fce6e8a2f71f1e39b92c700d8438a0b1d2a631a02", size = 385316, upload-time = "2025-10-06T14:10:35.034Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/84/891158426bc8036bfdfd862fabd0e0fa25df4176ec793e447f4b85cf1be4/yarl-1.22.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e1b51bebd221006d3d2f95fbe124b22b247136647ae5dcc8c7acafba66e5ee67", size = 374431, upload-time = "2025-10-06T14:10:37.76Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/49/03da1580665baa8bef5e8ed34c6df2c2aca0a2f28bf397ed238cc1bbc6f2/yarl-1.22.0-cp313-cp313-win32.whl", hash = "sha256:d3e32536234a95f513bd374e93d717cf6b2231a791758de6c509e3653f234c95", size = 81555, upload-time = "2025-10-06T14:10:39.649Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/ee/450914ae11b419eadd067c6183ae08381cfdfcb9798b90b2b713bbebddda/yarl-1.22.0-cp313-cp313-win_amd64.whl", hash = "sha256:47743b82b76d89a1d20b83e60d5c20314cbd5ba2befc9cda8f28300c4a08ed4d", size = 86965, upload-time = "2025-10-06T14:10:41.313Z" },
+ { url = "https://files.pythonhosted.org/packages/98/4d/264a01eae03b6cf629ad69bae94e3b0e5344741e929073678e84bf7a3e3b/yarl-1.22.0-cp313-cp313-win_arm64.whl", hash = "sha256:5d0fcda9608875f7d052eff120c7a5da474a6796fe4d83e152e0e4d42f6d1a9b", size = 81205, upload-time = "2025-10-06T14:10:43.167Z" },
+ { url = "https://files.pythonhosted.org/packages/88/fc/6908f062a2f77b5f9f6d69cecb1747260831ff206adcbc5b510aff88df91/yarl-1.22.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:719ae08b6972befcba4310e49edb1161a88cdd331e3a694b84466bd938a6ab10", size = 146209, upload-time = "2025-10-06T14:10:44.643Z" },
+ { url = "https://files.pythonhosted.org/packages/65/47/76594ae8eab26210b4867be6f49129861ad33da1f1ebdf7051e98492bf62/yarl-1.22.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:47d8a5c446df1c4db9d21b49619ffdba90e77c89ec6e283f453856c74b50b9e3", size = 95966, upload-time = "2025-10-06T14:10:46.554Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/ce/05e9828a49271ba6b5b038b15b3934e996980dd78abdfeb52a04cfb9467e/yarl-1.22.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cfebc0ac8333520d2d0423cbbe43ae43c8838862ddb898f5ca68565e395516e9", size = 97312, upload-time = "2025-10-06T14:10:48.007Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/c5/7dffad5e4f2265b29c9d7ec869c369e4223166e4f9206fc2243ee9eea727/yarl-1.22.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4398557cbf484207df000309235979c79c4356518fd5c99158c7d38203c4da4f", size = 361967, upload-time = "2025-10-06T14:10:49.997Z" },
+ { url = "https://files.pythonhosted.org/packages/50/b2/375b933c93a54bff7fc041e1a6ad2c0f6f733ffb0c6e642ce56ee3b39970/yarl-1.22.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2ca6fd72a8cd803be290d42f2dec5cdcd5299eeb93c2d929bf060ad9efaf5de0", size = 323949, upload-time = "2025-10-06T14:10:52.004Z" },
+ { url = "https://files.pythonhosted.org/packages/66/50/bfc2a29a1d78644c5a7220ce2f304f38248dc94124a326794e677634b6cf/yarl-1.22.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca1f59c4e1ab6e72f0a23c13fca5430f889634166be85dbf1013683e49e3278e", size = 361818, upload-time = "2025-10-06T14:10:54.078Z" },
+ { url = "https://files.pythonhosted.org/packages/46/96/f3941a46af7d5d0f0498f86d71275696800ddcdd20426298e572b19b91ff/yarl-1.22.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c5010a52015e7c70f86eb967db0f37f3c8bd503a695a49f8d45700144667708", size = 372626, upload-time = "2025-10-06T14:10:55.767Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/42/8b27c83bb875cd89448e42cd627e0fb971fa1675c9ec546393d18826cb50/yarl-1.22.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d7672ecf7557476642c88497c2f8d8542f8e36596e928e9bcba0e42e1e7d71f", size = 341129, upload-time = "2025-10-06T14:10:57.985Z" },
+ { url = "https://files.pythonhosted.org/packages/49/36/99ca3122201b382a3cf7cc937b95235b0ac944f7e9f2d5331d50821ed352/yarl-1.22.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3b7c88eeef021579d600e50363e0b6ee4f7f6f728cd3486b9d0f3ee7b946398d", size = 346776, upload-time = "2025-10-06T14:10:59.633Z" },
+ { url = "https://files.pythonhosted.org/packages/85/b4/47328bf996acd01a4c16ef9dcd2f59c969f495073616586f78cd5f2efb99/yarl-1.22.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f4afb5c34f2c6fecdcc182dfcfc6af6cccf1aa923eed4d6a12e9d96904e1a0d8", size = 334879, upload-time = "2025-10-06T14:11:01.454Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/ad/b77d7b3f14a4283bffb8e92c6026496f6de49751c2f97d4352242bba3990/yarl-1.22.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:59c189e3e99a59cf8d83cbb31d4db02d66cda5a1a4374e8a012b51255341abf5", size = 350996, upload-time = "2025-10-06T14:11:03.452Z" },
+ { url = "https://files.pythonhosted.org/packages/81/c8/06e1d69295792ba54d556f06686cbd6a7ce39c22307100e3fb4a2c0b0a1d/yarl-1.22.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:5a3bf7f62a289fa90f1990422dc8dff5a458469ea71d1624585ec3a4c8d6960f", size = 356047, upload-time = "2025-10-06T14:11:05.115Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/b8/4c0e9e9f597074b208d18cef227d83aac36184bfbc6eab204ea55783dbc5/yarl-1.22.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:de6b9a04c606978fdfe72666fa216ffcf2d1a9f6a381058d4378f8d7b1e5de62", size = 342947, upload-time = "2025-10-06T14:11:08.137Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/e5/11f140a58bf4c6ad7aca69a892bff0ee638c31bea4206748fc0df4ebcb3a/yarl-1.22.0-cp313-cp313t-win32.whl", hash = "sha256:1834bb90991cc2999f10f97f5f01317f99b143284766d197e43cd5b45eb18d03", size = 86943, upload-time = "2025-10-06T14:11:10.284Z" },
+ { url = "https://files.pythonhosted.org/packages/31/74/8b74bae38ed7fe6793d0c15a0c8207bbb819cf287788459e5ed230996cdd/yarl-1.22.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff86011bd159a9d2dfc89c34cfd8aff12875980e3bd6a39ff097887520e60249", size = 93715, upload-time = "2025-10-06T14:11:11.739Z" },
+ { url = "https://files.pythonhosted.org/packages/69/66/991858aa4b5892d57aef7ee1ba6b4d01ec3b7eb3060795d34090a3ca3278/yarl-1.22.0-cp313-cp313t-win_arm64.whl", hash = "sha256:7861058d0582b847bc4e3a4a4c46828a410bca738673f35a29ba3ca5db0b473b", size = 83857, upload-time = "2025-10-06T14:11:13.586Z" },
+ { url = "https://files.pythonhosted.org/packages/46/b3/e20ef504049f1a1c54a814b4b9bed96d1ac0e0610c3b4da178f87209db05/yarl-1.22.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:34b36c2c57124530884d89d50ed2c1478697ad7473efd59cfd479945c95650e4", size = 140520, upload-time = "2025-10-06T14:11:15.465Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/04/3532d990fdbab02e5ede063676b5c4260e7f3abea2151099c2aa745acc4c/yarl-1.22.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:0dd9a702591ca2e543631c2a017e4a547e38a5c0f29eece37d9097e04a7ac683", size = 93504, upload-time = "2025-10-06T14:11:17.106Z" },
+ { url = "https://files.pythonhosted.org/packages/11/63/ff458113c5c2dac9a9719ac68ee7c947cb621432bcf28c9972b1c0e83938/yarl-1.22.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:594fcab1032e2d2cc3321bb2e51271e7cd2b516c7d9aee780ece81b07ff8244b", size = 94282, upload-time = "2025-10-06T14:11:19.064Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/bc/315a56aca762d44a6aaaf7ad253f04d996cb6b27bad34410f82d76ea8038/yarl-1.22.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3d7a87a78d46a2e3d5b72587ac14b4c16952dd0887dbb051451eceac774411e", size = 372080, upload-time = "2025-10-06T14:11:20.996Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/3f/08e9b826ec2e099ea6e7c69a61272f4f6da62cb5b1b63590bb80ca2e4a40/yarl-1.22.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:852863707010316c973162e703bddabec35e8757e67fcb8ad58829de1ebc8590", size = 338696, upload-time = "2025-10-06T14:11:22.847Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/9f/90360108e3b32bd76789088e99538febfea24a102380ae73827f62073543/yarl-1.22.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:131a085a53bfe839a477c0845acf21efc77457ba2bcf5899618136d64f3303a2", size = 387121, upload-time = "2025-10-06T14:11:24.889Z" },
+ { url = "https://files.pythonhosted.org/packages/98/92/ab8d4657bd5b46a38094cfaea498f18bb70ce6b63508fd7e909bd1f93066/yarl-1.22.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:078a8aefd263f4d4f923a9677b942b445a2be970ca24548a8102689a3a8ab8da", size = 394080, upload-time = "2025-10-06T14:11:27.307Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/e7/d8c5a7752fef68205296201f8ec2bf718f5c805a7a7e9880576c67600658/yarl-1.22.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bca03b91c323036913993ff5c738d0842fc9c60c4648e5c8d98331526df89784", size = 372661, upload-time = "2025-10-06T14:11:29.387Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/2e/f4d26183c8db0bb82d491b072f3127fb8c381a6206a3a56332714b79b751/yarl-1.22.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:68986a61557d37bb90d3051a45b91fa3d5c516d177dfc6dd6f2f436a07ff2b6b", size = 364645, upload-time = "2025-10-06T14:11:31.423Z" },
+ { url = "https://files.pythonhosted.org/packages/80/7c/428e5812e6b87cd00ee8e898328a62c95825bf37c7fa87f0b6bb2ad31304/yarl-1.22.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4792b262d585ff0dff6bcb787f8492e40698443ec982a3568c2096433660c694", size = 355361, upload-time = "2025-10-06T14:11:33.055Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/2a/249405fd26776f8b13c067378ef4d7dd49c9098d1b6457cdd152a99e96a9/yarl-1.22.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ebd4549b108d732dba1d4ace67614b9545b21ece30937a63a65dd34efa19732d", size = 381451, upload-time = "2025-10-06T14:11:35.136Z" },
+ { url = "https://files.pythonhosted.org/packages/67/a8/fb6b1adbe98cf1e2dd9fad71003d3a63a1bc22459c6e15f5714eb9323b93/yarl-1.22.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f87ac53513d22240c7d59203f25cc3beac1e574c6cd681bbfd321987b69f95fd", size = 383814, upload-time = "2025-10-06T14:11:37.094Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/f9/3aa2c0e480fb73e872ae2814c43bc1e734740bb0d54e8cb2a95925f98131/yarl-1.22.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:22b029f2881599e2f1b06f8f1db2ee63bd309e2293ba2d566e008ba12778b8da", size = 370799, upload-time = "2025-10-06T14:11:38.83Z" },
+ { url = "https://files.pythonhosted.org/packages/50/3c/af9dba3b8b5eeb302f36f16f92791f3ea62e3f47763406abf6d5a4a3333b/yarl-1.22.0-cp314-cp314-win32.whl", hash = "sha256:6a635ea45ba4ea8238463b4f7d0e721bad669f80878b7bfd1f89266e2ae63da2", size = 82990, upload-time = "2025-10-06T14:11:40.624Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/30/ac3a0c5bdc1d6efd1b41fa24d4897a4329b3b1e98de9449679dd327af4f0/yarl-1.22.0-cp314-cp314-win_amd64.whl", hash = "sha256:0d6e6885777af0f110b0e5d7e5dda8b704efed3894da26220b7f3d887b839a79", size = 88292, upload-time = "2025-10-06T14:11:42.578Z" },
+ { url = "https://files.pythonhosted.org/packages/df/0a/227ab4ff5b998a1b7410abc7b46c9b7a26b0ca9e86c34ba4b8d8bc7c63d5/yarl-1.22.0-cp314-cp314-win_arm64.whl", hash = "sha256:8218f4e98d3c10d683584cb40f0424f4b9fd6e95610232dd75e13743b070ee33", size = 82888, upload-time = "2025-10-06T14:11:44.863Z" },
+ { url = "https://files.pythonhosted.org/packages/06/5e/a15eb13db90abd87dfbefb9760c0f3f257ac42a5cac7e75dbc23bed97a9f/yarl-1.22.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:45c2842ff0e0d1b35a6bf1cd6c690939dacb617a70827f715232b2e0494d55d1", size = 146223, upload-time = "2025-10-06T14:11:46.796Z" },
+ { url = "https://files.pythonhosted.org/packages/18/82/9665c61910d4d84f41a5bf6837597c89e665fa88aa4941080704645932a9/yarl-1.22.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d947071e6ebcf2e2bee8fce76e10faca8f7a14808ca36a910263acaacef08eca", size = 95981, upload-time = "2025-10-06T14:11:48.845Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/9a/2f65743589809af4d0a6d3aa749343c4b5f4c380cc24a8e94a3c6625a808/yarl-1.22.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:334b8721303e61b00019474cc103bdac3d7b1f65e91f0bfedeec2d56dfe74b53", size = 97303, upload-time = "2025-10-06T14:11:50.897Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/ab/5b13d3e157505c43c3b43b5a776cbf7b24a02bc4cccc40314771197e3508/yarl-1.22.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e7ce67c34138a058fd092f67d07a72b8e31ff0c9236e751957465a24b28910c", size = 361820, upload-time = "2025-10-06T14:11:52.549Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/76/242a5ef4677615cf95330cfc1b4610e78184400699bdda0acb897ef5e49a/yarl-1.22.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d77e1b2c6d04711478cb1c4ab90db07f1609ccf06a287d5607fcd90dc9863acf", size = 323203, upload-time = "2025-10-06T14:11:54.225Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/96/475509110d3f0153b43d06164cf4195c64d16999e0c7e2d8a099adcd6907/yarl-1.22.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4647674b6150d2cae088fc07de2738a84b8bcedebef29802cf0b0a82ab6face", size = 363173, upload-time = "2025-10-06T14:11:56.069Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/66/59db471aecfbd559a1fd48aedd954435558cd98c7d0da8b03cc6c140a32c/yarl-1.22.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efb07073be061c8f79d03d04139a80ba33cbd390ca8f0297aae9cce6411e4c6b", size = 373562, upload-time = "2025-10-06T14:11:58.783Z" },
+ { url = "https://files.pythonhosted.org/packages/03/1f/c5d94abc91557384719da10ff166b916107c1b45e4d0423a88457071dd88/yarl-1.22.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e51ac5435758ba97ad69617e13233da53908beccc6cfcd6c34bbed8dcbede486", size = 339828, upload-time = "2025-10-06T14:12:00.686Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/97/aa6a143d3afba17b6465733681c70cf175af89f76ec8d9286e08437a7454/yarl-1.22.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:33e32a0dd0c8205efa8e83d04fc9f19313772b78522d1bdc7d9aed706bfd6138", size = 347551, upload-time = "2025-10-06T14:12:02.628Z" },
+ { url = "https://files.pythonhosted.org/packages/43/3c/45a2b6d80195959239a7b2a8810506d4eea5487dce61c2a3393e7fc3c52e/yarl-1.22.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:bf4a21e58b9cde0e401e683ebd00f6ed30a06d14e93f7c8fd059f8b6e8f87b6a", size = 334512, upload-time = "2025-10-06T14:12:04.871Z" },
+ { url = "https://files.pythonhosted.org/packages/86/a0/c2ab48d74599c7c84cb104ebd799c5813de252bea0f360ffc29d270c2caa/yarl-1.22.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:e4b582bab49ac33c8deb97e058cd67c2c50dac0dd134874106d9c774fd272529", size = 352400, upload-time = "2025-10-06T14:12:06.624Z" },
+ { url = "https://files.pythonhosted.org/packages/32/75/f8919b2eafc929567d3d8411f72bdb1a2109c01caaab4ebfa5f8ffadc15b/yarl-1.22.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0b5bcc1a9c4839e7e30b7b30dd47fe5e7e44fb7054ec29b5bb8d526aa1041093", size = 357140, upload-time = "2025-10-06T14:12:08.362Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/72/6a85bba382f22cf78add705d8c3731748397d986e197e53ecc7835e76de7/yarl-1.22.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c0232bce2170103ec23c454e54a57008a9a72b5d1c3105dc2496750da8cfa47c", size = 341473, upload-time = "2025-10-06T14:12:10.994Z" },
+ { url = "https://files.pythonhosted.org/packages/35/18/55e6011f7c044dc80b98893060773cefcfdbf60dfefb8cb2f58b9bacbd83/yarl-1.22.0-cp314-cp314t-win32.whl", hash = "sha256:8009b3173bcd637be650922ac455946197d858b3630b6d8787aa9e5c4564533e", size = 89056, upload-time = "2025-10-06T14:12:13.317Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/86/0f0dccb6e59a9e7f122c5afd43568b1d31b8ab7dda5f1b01fb5c7025c9a9/yarl-1.22.0-cp314-cp314t-win_amd64.whl", hash = "sha256:9fb17ea16e972c63d25d4a97f016d235c78dd2344820eb35bc034bc32012ee27", size = 96292, upload-time = "2025-10-06T14:12:15.398Z" },
+ { url = "https://files.pythonhosted.org/packages/48/b7/503c98092fb3b344a179579f55814b613c1fbb1c23b3ec14a7b008a66a6e/yarl-1.22.0-cp314-cp314t-win_arm64.whl", hash = "sha256:9f6d73c1436b934e3f01df1e1b21ff765cd1d28c77dfb9ace207f746d4610ee1", size = 85171, upload-time = "2025-10-06T14:12:16.935Z" },
+ { url = "https://files.pythonhosted.org/packages/94/fd/6480106702a79bcceda5fd9c63cb19a04a6506bd5ce7fd8d9b63742f0021/yarl-1.22.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3aa27acb6de7a23785d81557577491f6c38a5209a254d1191519d07d8fe51748", size = 141301, upload-time = "2025-10-06T14:12:19.01Z" },
+ { url = "https://files.pythonhosted.org/packages/42/e1/6d95d21b17a93e793e4ec420a925fe1f6a9342338ca7a563ed21129c0990/yarl-1.22.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:af74f05666a5e531289cb1cc9c883d1de2088b8e5b4de48004e5ca8a830ac859", size = 93864, upload-time = "2025-10-06T14:12:21.05Z" },
+ { url = "https://files.pythonhosted.org/packages/32/58/b8055273c203968e89808413ea4c984988b6649baabf10f4522e67c22d2f/yarl-1.22.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:62441e55958977b8167b2709c164c91a6363e25da322d87ae6dd9c6019ceecf9", size = 94706, upload-time = "2025-10-06T14:12:23.287Z" },
+ { url = "https://files.pythonhosted.org/packages/18/91/d7bfbc28a88c2895ecd0da6a874def0c147de78afc52c773c28e1aa233a3/yarl-1.22.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b580e71cac3f8113d3135888770903eaf2f507e9421e5697d6ee6d8cd1c7f054", size = 347100, upload-time = "2025-10-06T14:12:28.527Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/e8/37a1e7b99721c0564b1fc7b0a4d1f595ef6fb8060d82ca61775b644185f7/yarl-1.22.0-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e81fda2fb4a07eda1a2252b216aa0df23ebcd4d584894e9612e80999a78fd95b", size = 318902, upload-time = "2025-10-06T14:12:30.528Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/ef/34724449d7ef2db4f22df644f2dac0b8a275d20f585e526937b3ae47b02d/yarl-1.22.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:99b6fc1d55782461b78221e95fc357b47ad98b041e8e20f47c1411d0aacddc60", size = 363302, upload-time = "2025-10-06T14:12:32.295Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/04/88a39a5dad39889f192cce8d66cc4c58dbeca983e83f9b6bf23822a7ed91/yarl-1.22.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:088e4e08f033db4be2ccd1f34cf29fe994772fb54cfe004bbf54db320af56890", size = 370816, upload-time = "2025-10-06T14:12:34.01Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/1f/5e895e547129413f56c76be2c3ce4b96c797d2d0ff3e16a817d9269b12e6/yarl-1.22.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e4e1f6f0b4da23e61188676e3ed027ef0baa833a2e633c29ff8530800edccba", size = 346465, upload-time = "2025-10-06T14:12:35.977Z" },
+ { url = "https://files.pythonhosted.org/packages/11/13/a750e9fd6f9cc9ed3a52a70fe58ffe505322f0efe0d48e1fd9ffe53281f5/yarl-1.22.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:84fc3ec96fce86ce5aa305eb4aa9358279d1aa644b71fab7b8ed33fe3ba1a7ca", size = 341506, upload-time = "2025-10-06T14:12:37.788Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/67/bb6024de76e7186611ebe626aec5b71a2d2ecf9453e795f2dbd80614784c/yarl-1.22.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:5dbeefd6ca588b33576a01b0ad58aa934bc1b41ef89dee505bf2932b22ddffba", size = 335030, upload-time = "2025-10-06T14:12:39.775Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/be/50b38447fd94a7992996a62b8b463d0579323fcfc08c61bdba949eef8a5d/yarl-1.22.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:14291620375b1060613f4aab9ebf21850058b6b1b438f386cc814813d901c60b", size = 358560, upload-time = "2025-10-06T14:12:41.547Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/89/c020b6f547578c4e3dbb6335bf918f26e2f34ad0d1e515d72fd33ac0c635/yarl-1.22.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:a4fcfc8eb2c34148c118dfa02e6427ca278bfd0f3df7c5f99e33d2c0e81eae3e", size = 357290, upload-time = "2025-10-06T14:12:43.861Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/52/c49a619ee35a402fa3a7019a4fa8d26878fec0d1243f6968bbf516789578/yarl-1.22.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:029866bde8d7b0878b9c160e72305bbf0a7342bcd20b9999381704ae03308dc8", size = 350700, upload-time = "2025-10-06T14:12:46.868Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/c9/f5042d87777bf6968435f04a2bbb15466b2f142e6e47fa4f34d1a3f32f0c/yarl-1.22.0-cp39-cp39-win32.whl", hash = "sha256:4dcc74149ccc8bba31ce1944acee24813e93cfdee2acda3c172df844948ddf7b", size = 82323, upload-time = "2025-10-06T14:12:48.633Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/58/d00f7cad9eba20c4eefac2682f34661d1d1b3a942fc0092eb60e78cfb733/yarl-1.22.0-cp39-cp39-win_amd64.whl", hash = "sha256:10619d9fdee46d20edc49d3479e2f8269d0779f1b031e6f7c2aa1c76be04b7ed", size = 87145, upload-time = "2025-10-06T14:12:50.241Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/a3/70904f365080780d38b919edd42d224b8c4ce224a86950d2eaa2a24366ad/yarl-1.22.0-cp39-cp39-win_arm64.whl", hash = "sha256:dd7afd3f8b0bfb4e0d9fc3c31bfe8a4ec7debe124cfd90619305def3c8ca8cd2", size = 82173, upload-time = "2025-10-06T14:12:51.869Z" },
+ { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814, upload-time = "2025-10-06T14:12:53.872Z" },
+]
+
+[[package]]
+name = "zipp"
+version = "3.23.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" },
+]