Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: initial monorepo & server sdk #61

Merged
merged 32 commits into from
Oct 3, 2023
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
3549ee3
wip
theomonnom Sep 14, 2023
21cfcb1
wip
theomonnom Sep 19, 2023
41374dc
Merge branch 'main' into theo/server-sdk
theomonnom Sep 25, 2023
4662a10
Merge branch 'main' into theo/server-sdk
theomonnom Oct 3, 2023
fa4cf2d
better dir structure
theomonnom Oct 3, 2023
b907069
fix examples
theomonnom Oct 3, 2023
5189613
publish workflows
theomonnom Oct 3, 2023
b2c0e50
fix env
theomonnom Oct 3, 2023
17d2a90
attempt 2 to fix
theomonnom Oct 3, 2023
8ce2679
test
theomonnom Oct 3, 2023
79799ba
update submodules
theomonnom Oct 3, 2023
f632361
independant proto
theomonnom Oct 3, 2023
a49a258
fix builds
theomonnom Oct 3, 2023
635ccf0
Update setup.py
theomonnom Oct 3, 2023
28176cd
fix build
theomonnom Oct 3, 2023
75a96b6
better names
theomonnom Oct 3, 2023
c9fecc9
Revert "fix build"
theomonnom Oct 3, 2023
d1c313b
new fix attempt
theomonnom Oct 3, 2023
726dbd7
fix
theomonnom Oct 3, 2023
5c6fa79
fix
theomonnom Oct 3, 2023
8349277
finally?
theomonnom Oct 3, 2023
f3c83bb
fix deprecated
theomonnom Oct 3, 2023
9b36971
fix windows
theomonnom Oct 3, 2023
77258df
test
theomonnom Oct 3, 2023
7d5dd3b
mark generated files to make it easier for diffs
davidzhao Oct 3, 2023
a4a5dea
fix attempt
theomonnom Oct 3, 2023
9441a0f
Merge branch 'theo/server-sdk' of https://github.com/livekit/client-s…
theomonnom Oct 3, 2023
ef37660
correctly upload artifacts
theomonnom Oct 3, 2023
521c650
nit
theomonnom Oct 3, 2023
5b30f05
nit x2
theomonnom Oct 3, 2023
58cff2e
nit x3
theomonnom Oct 3, 2023
229dddd
correctly import everything
theomonnom Oct 3, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
**/*.dll filter=lfs diff=lfs merge=lfs -text
**/*.so filter=lfs diff=lfs merge=lfs -text
**/*.dylib filter=lfs diff=lfs merge=lfs -text
**/*.dylib filter=lfs diff=lfs merge=lfs -text
livekit-api/livekit/api/_proto/** linguist-generated=true
livekit-rtc/livekit/rtc/_proto/** linguist-generated=true
61 changes: 61 additions & 0 deletions .github/workflows/build-api.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: Build API

on:
push:
branches: ["main"]
tags: ["api-v*"]
theomonnom marked this conversation as resolved.
Show resolved Hide resolved
pull_request:
workflow_dispatch:

env:
PACKAGE_DIR: ./livekit-api

jobs:
build_wheels:
name: Build API wheel/sdist
runs-on: ubuntu-latest
defaults:
run:
working-directory: ${{ env.PACKAGE_DIR }}
steps:
- uses: actions/checkout@v3
with:
submodules: true

- uses: actions/setup-python@v4

- name: Build wheel
run: |
pip3 install build wheel
python3 -m build --wheel
env:
CIBW_ARCHS: ${{ matrix.archs }}
CIBW_SKIP: "*-musllinux_*"

- name: Build SDist
run: pipx run build --sdist

- uses: actions/upload-artifact@v3
with:
name: api-release
path: |
dist/*.whl
dist/*.tar.gz

publish:
name: Publish API release
needs: build_wheels
runs-on: ubuntu-latest
permissions:
id-token: write
if: startsWith(github.ref, 'refs/tags/api-v')
steps:
- uses: actions/download-artifact@v3
with:
name: api-release
path: dist

- uses: pypa/gh-action-pypi-publish@release/v1
with:
user: __token__

Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
name: Build
name: Build RTC

on:
push:
branches: ["main"]
tags: ["v*"]
tags: ["rtc-v*"]
pull_request:
theomonnom marked this conversation as resolved.
Show resolved Hide resolved
workflow_dispatch:

env:
PACKAGE_DIR: ./livekit-rtc

jobs:
build_wheels:
name: Build wheels (${{ matrix.archs }})
name: Build RTC wheels (${{ matrix.archs }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
Expand All @@ -24,7 +27,9 @@ jobs:
archs: AMD64 # ignore windows arm64 for now
- os: macos-latest
archs: x86_64 arm64

defaults:
run:
working-directory: ${{ env.PACKAGE_DIR }}
steps:
- uses: actions/checkout@v3
with:
Expand All @@ -39,16 +44,18 @@ jobs:
run: python3 -m cibuildwheel --output-dir dist
env:
CIBW_ARCHS: ${{ matrix.archs }}
CIBW_SKIP: "*-musllinux_*"

- uses: actions/upload-artifact@v3
with:
name: release
name: rtc-release
path: dist/*.whl

make_sdist:
name: Make SDist
name: Make RTC sdist
runs-on: ubuntu-latest
defaults:
run:
working-directory: ${{ env.PACKAGE_DIR }}
steps:
- uses: actions/checkout@v3
with:
Expand All @@ -59,21 +66,20 @@ jobs:

- uses: actions/upload-artifact@v3
with:
name: release
name: rtc-release
path: dist/*.tar.gz

publish:
name: Publish
name: Publish RTC release
needs: [build_wheels, make_sdist]
runs-on: ubuntu-latest
permissions:
id-token: write
# only execute on tag push v1 or workflow_dispatch
if: (github.event_name == 'push' && github.ref_type == 'tag') || github.event_name == 'workflow_dispatch'
if: startsWith(github.ref, 'refs/tags/rtc-v')
steps:
- uses: actions/download-artifact@v3
with:
name: release
name: rtc-release
path: dist

- uses: pypa/gh-action-pypi-publish@release/v1
Expand Down
5 changes: 4 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "client-sdk-rust"]
path = rust-sdks
path = livekit-rtc/rust-sdks
url = https://github.com/livekit/rust-sdks
[submodule "livekit-api/protocol"]
path = livekit-api/protocol
url = https://github.com/livekit/protocol
68 changes: 34 additions & 34 deletions examples/basic_room.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,98 +3,98 @@
from signal import SIGINT, SIGTERM
from typing import Union

import livekit
import livekit.rtc as rtc
theomonnom marked this conversation as resolved.
Show resolved Hide resolved

URL = 'ws://localhost:7880'
TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE5MDY2MTMyODgsImlzcyI6IkFQSVRzRWZpZFpqclFvWSIsIm5hbWUiOiJuYXRpdmUiLCJuYmYiOjE2NzI2MTMyODgsInN1YiI6Im5hdGl2ZSIsInZpZGVvIjp7InJvb20iOiJ0ZXN0Iiwicm9vbUFkbWluIjp0cnVlLCJyb29tQ3JlYXRlIjp0cnVlLCJyb29tSm9pbiI6dHJ1ZSwicm9vbUxpc3QiOnRydWV9fQ.uSNIangMRu8jZD5mnRYoCHjcsQWCrJXgHCs0aNIgBFY' # noqa


async def main(room: livekit.Room) -> None:
async def main(room: rtc.Room) -> None:

@room.listens_to("participant_connected")
def on_participant_connected(participant: livekit.RemoteParticipant) -> None:
def on_participant_connected(participant: rtc.RemoteParticipant) -> None:
logging.info(
"participant connected: %s %s", participant.sid, participant.identity)

@room.listens_to("participant_disconnected")
def on_participant_disconnected(participant: livekit.RemoteParticipant):
def on_participant_disconnected(participant: rtc.RemoteParticipant):
logging.info("participant disconnected: %s %s",
participant.sid, participant.identity)

@room.listens_to("local_track_published")
def on_local_track_published(publication: livekit.LocalTrackPublication,
track: Union[livekit.LocalAudioTrack,
livekit.LocalVideoTrack]):
def on_local_track_published(publication: rtc.LocalTrackPublication,
track: Union[rtc.LocalAudioTrack,
rtc.LocalVideoTrack]):
logging.info("local track published: %s", publication.sid)

@room.listens_to("active_speakers_changed")
def on_active_speakers_changed(speakers: list[livekit.Participant]):
def on_active_speakers_changed(speakers: list[rtc.Participant]):
logging.info("active speakers changed: %s", speakers)

@room.listens_to("local_track_unpublished")
def on_local_track_unpublished(publication: livekit.LocalTrackPublication):
def on_local_track_unpublished(publication: rtc.LocalTrackPublication):
logging.info("local track unpublished: %s", publication.sid)

@room.listens_to("track_published")
def on_track_published(publication: livekit.RemoteTrackPublication,
participant: livekit.RemoteParticipant):
def on_track_published(publication: rtc.RemoteTrackPublication,
participant: rtc.RemoteParticipant):
logging.info("track published: %s from participant %s (%s)",
publication.sid, participant.sid, participant.identity)

@room.listens_to("track_unpublished")
def on_track_unpublished(publication: livekit.RemoteTrackPublication,
participant: livekit.RemoteParticipant):
def on_track_unpublished(publication: rtc.RemoteTrackPublication,
participant: rtc.RemoteParticipant):
logging.info("track unpublished: %s", publication.sid)

@room.listens_to("track_subscribed")
def on_track_subscribed(track: livekit.Track,
publication: livekit.RemoteTrackPublication,
participant: livekit.RemoteParticipant):
def on_track_subscribed(track: rtc.Track,
publication: rtc.RemoteTrackPublication,
participant: rtc.RemoteParticipant):
logging.info("track subscribed: %s", publication.sid)
if track.kind == livekit.TrackKind.KIND_VIDEO:
_video_stream = livekit.VideoStream(track)
if track.kind == rtc.TrackKind.KIND_VIDEO:
_video_stream = rtc.VideoStream(track)
# video_stream is an async iterator that yields VideoFrame
elif track.kind == livekit.TrackKind.KIND_AUDIO:
elif track.kind == rtc.TrackKind.KIND_AUDIO:
print("Subscribed to an Audio Track")
_audio_stream = livekit.AudioStream(track)
_audio_stream = rtc.AudioStream(track)
# audio_stream is an async iterator that yields AudioFrame

@room.listens_to("track_unsubscribed")
def on_track_unsubscribed(track: livekit.Track,
publication: livekit.RemoteTrackPublication,
participant: livekit.RemoteParticipant):
def on_track_unsubscribed(track: rtc.Track,
publication: rtc.RemoteTrackPublication,
participant: rtc.RemoteParticipant):
logging.info("track unsubscribed: %s", publication.sid)

@room.listens_to("track_muted")
def on_track_muted(publication: livekit.RemoteTrackPublication,
participant: livekit.RemoteParticipant):
def on_track_muted(publication: rtc.RemoteTrackPublication,
participant: rtc.RemoteParticipant):
logging.info("track muted: %s", publication.sid)

@room.listens_to("track_unmuted")
def on_track_unmuted(publication: livekit.RemoteTrackPublication,
participant: livekit.RemoteParticipant):
def on_track_unmuted(publication: rtc.RemoteTrackPublication,
participant: rtc.RemoteParticipant):
logging.info("track unmuted: %s", publication.sid)

@room.listens_to("data_received")
def on_data_received(data: bytes,
kind: livekit.DataPacketKind,
participant: livekit.Participant):
kind: rtc.DataPacketKind,
participant: rtc.Participant):
logging.info("received data from %s: %s", participant.identity, data)

@room.listens_to("connection_quality_changed")
def on_connection_quality_changed(participant: livekit.Participant,
quality: livekit.ConnectionQuality):
def on_connection_quality_changed(participant: rtc.Participant,
quality: rtc.ConnectionQuality):
logging.info("connection quality changed for %s", participant.identity)

@room.listens_to("track_subscription_failed")
def on_track_subscription_failed(participant: livekit.RemoteParticipant,
def on_track_subscription_failed(participant: rtc.RemoteParticipant,
track_sid: str,
error: str):
logging.info("track subscription failed: %s %s",
participant.identity, error)

@room.listens_to("connection_state_changed")
def on_connection_state_changed(state: livekit.ConnectionState):
def on_connection_state_changed(state: rtc.ConnectionState):
logging.info("connection state changed: %s", state)

@room.listens_to("connected")
Expand Down Expand Up @@ -127,7 +127,7 @@ def on_reconnected() -> None:
logging.StreamHandler()])

loop = asyncio.get_event_loop()
room = livekit.Room(loop=loop)
room = rtc.Room(loop=loop)

async def cleanup():
await room.disconnect()
Expand Down
37 changes: 18 additions & 19 deletions examples/e2ee.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,24 @@
from signal import SIGINT, SIGTERM

import numpy as np

import livekit
import livekit.rtc as rtc

URL = 'ws://localhost:7880'
TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE5MDY2MTMyODgsImlzcyI6IkFQSVRzRWZpZFpqclFvWSIsIm5hbWUiOiJuYXRpdmUiLCJuYmYiOjE2NzI2MTMyODgsInN1YiI6Im5hdGl2ZSIsInZpZGVvIjp7InJvb20iOiJ0ZXN0Iiwicm9vbUFkbWluIjp0cnVlLCJyb29tQ3JlYXRlIjp0cnVlLCJyb29tSm9pbiI6dHJ1ZSwicm9vbUxpc3QiOnRydWV9fQ.uSNIangMRu8jZD5mnRYoCHjcsQWCrJXgHCs0aNIgBFY' # noqa

# ("livekitrocks") this is our shared key, it must match the one used by your clients
SHARED_KEY = b"livekitrocks"
# ("rtcrocks") this is our shared key, it must match the one used by your clients
theomonnom marked this conversation as resolved.
Show resolved Hide resolved
SHARED_KEY = b"rtcrocks"


async def draw_cube(source: livekit.VideoSource):
async def draw_cube(source: rtc.VideoSource):
W, H, MID_W, MID_H = 1280, 720, 640, 360
cube_size = 60
vertices = (np.array([[-1, -1, -1], [1, -1, -1], [1, 1, -1], [-1, 1, -1],
[-1, -1, 1], [1, -1, 1], [1, 1, 1], [-1, 1, 1]]) * cube_size)
edges = [[0, 1], [1, 2], [2, 3], [3, 0], [4, 5], [5, 6],
[6, 7], [7, 4], [0, 4], [1, 5], [2, 6], [3, 7]]

frame = livekit.ArgbFrame(livekit.VideoFormatType.FORMAT_ARGB, W, H)
frame = rtc.ArgbFrame(livekit.VideoFormatType.FORMAT_ARGB, W, H)
arr = np.ctypeslib.as_array(frame.data)
angle = 0

Expand All @@ -48,41 +47,41 @@ async def draw_cube(source: livekit.VideoSource):
idx = (y + dy) * W * 4 + (x + dx) * 4
arr[idx:idx+4] = [255, 255, 255, 255]

f = livekit.VideoFrame(
0, livekit.VideoRotation.VIDEO_ROTATION_0, frame.to_i420())
f = rtc.VideoFrame(
0, rtc.VideoRotation.VIDEO_ROTATION_0, frame.to_i420())
source.capture_frame(f)
angle += 0.02

code_duration = asyncio.get_event_loop().time() - start_time
await asyncio.sleep(1 / 30 - code_duration)


async def main(room: livekit.Room):
async def main(room: rtc.Room):
@room.listens_to("e2ee_state_changed")
def on_e2ee_state_changed(participant: livekit.Participant,
state: livekit.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)
try:
e2ee_options = livekit.E2EEOptions()
e2ee_options = rtc.E2EEOptions()
e2ee_options.key_provider_options.shared_key = SHARED_KEY

await room.connect(URL, TOKEN, options=livekit.RoomOptions(
await room.connect(URL, TOKEN, options=rtc.RoomOptions(
auto_subscribe=True,
e2ee=e2ee_options
))

logging.info("connected to room %s", room.name)
except livekit.ConnectError as e:
except rtc.ConnectError as e:
logging.error("failed to connect to the room: %s", e)
return False

# publish a track
source = livekit.VideoSource()
track = livekit.LocalVideoTrack.create_video_track("cube", source)
options = livekit.TrackPublishOptions()
options.source = livekit.TrackSource.SOURCE_CAMERA
source = rtc.VideoSource()
track = rtc.LocalVideoTrack.create_video_track("cube", source)
options = rtc.TrackPublishOptions()
options.source = rtc.TrackSource.SOURCE_CAMERA
publication = await room.local_participant.publish_track(track, options)
logging.info("published track %s", publication.sid)

Expand All @@ -94,7 +93,7 @@ def on_e2ee_state_changed(participant: livekit.Participant,
logging.StreamHandler()])

loop = asyncio.get_event_loop()
room = livekit.Room(loop=loop)
room = rtc.Room(loop=loop)

async def cleanup():
await room.disconnect()
Expand Down
Loading
Loading