Skip to content

Commit 0307cd1

Browse files
authored
e2e test livekit-rtc (#541)
1 parent 24d09f8 commit 0307cd1

File tree

6 files changed

+508
-32
lines changed

6 files changed

+508
-32
lines changed

.github/workflows/tests.yml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,22 @@ jobs:
1414
name: Run tests
1515
runs-on: ubuntu-latest
1616
steps:
17-
- uses: actions/checkout@v4
17+
- uses: actions/checkout@v6
1818
with:
1919
submodules: true
2020
lfs: true
2121

22-
- uses: actions/setup-python@v4
22+
- uses: actions/setup-python@v6
23+
with:
24+
python-version: '3.13'
2325
- name: Run tests
26+
env:
27+
LIVEKIT_URL: ${{ secrets.LIVEKIT_URL }}
28+
LIVEKIT_API_KEY: ${{ secrets.LIVEKIT_API_KEY }}
29+
LIVEKIT_API_SECRET: ${{ secrets.LIVEKIT_API_SECRET }}
2430
run: |
31+
pip3 install -r dev-requirements.txt
2532
python3 ./livekit-rtc/rust-sdks/download_ffi.py --output livekit-rtc/livekit/rtc/resources
2633
pip3 install ./livekit-protocol ./livekit-api ./livekit-rtc
27-
pip3 install -r dev-requirements.txt
2834
pytest . --ignore=livekit-rtc/rust-sdks
35+

livekit-rtc/livekit/rtc/room.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from ._proto import participant_pb2 as proto_participant
2828
from ._proto import room_pb2 as proto_room
2929
from ._proto import stats_pb2 as proto_stats
30+
from ._proto.participant_pb2 import DisconnectReason
3031
from ._proto.room_pb2 import ConnectionState
3132
from ._proto.track_pb2 import TrackKind
3233
from ._proto.rpc_pb2 import RpcMethodInvocationEvent
@@ -581,6 +582,14 @@ async def disconnect(self) -> None:
581582
await self._task
582583
FfiClient.instance.queue.unsubscribe(self._ffi_queue)
583584

585+
# we should manually flip the state, since the connection could have been torn down before
586+
# the callbacks were processed
587+
if self._connection_state != ConnectionState.CONN_DISCONNECTED:
588+
self.local_participant._info.disconnect_reason = DisconnectReason.CLIENT_INITIATED
589+
self._connection_state = ConnectionState.CONN_DISCONNECTED
590+
self.emit("connection_state_changed", self._connection_state)
591+
self.emit("disconnected", DisconnectReason.CLIENT_INITIATED)
592+
584593
async def _listen_task(self) -> None:
585594
# listen to incoming room events
586595
while True:
@@ -853,8 +862,6 @@ def _on_room_event(self, event: proto_room.RoomEvent):
853862
connection_state = event.connection_state_changed.state
854863
self._connection_state = connection_state
855864
self.emit("connection_state_changed", connection_state)
856-
elif which == "connected":
857-
self.emit("connected")
858865
elif which == "disconnected":
859866
self.emit("disconnected", event.disconnected.reason)
860867
elif which == "reconnecting":

livekit-rtc/livekit/rtc/utils.py

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
from __future__ import annotations
22

3+
from typing import AsyncIterator
4+
35
from .audio_frame import AudioFrame
46

57

6-
__all__ = ["combine_audio_frames"]
8+
__all__ = ["combine_audio_frames", "sine_wave_generator"]
79

810

911
def combine_audio_frames(buffer: AudioFrame | list[AudioFrame]) -> AudioFrame:
@@ -83,3 +85,54 @@ def combine_audio_frames(buffer: AudioFrame | list[AudioFrame]) -> AudioFrame:
8385
num_channels=num_channels,
8486
samples_per_channel=total_samples_per_channel,
8587
)
88+
89+
90+
async def sine_wave_generator(
91+
freq: float,
92+
duration: float,
93+
sample_rate: int = 48000,
94+
amplitude: float = 0.3,
95+
) -> AsyncIterator[AudioFrame]:
96+
"""
97+
Generate sine wave audio frames.
98+
99+
Useful for testing audio pipelines and generating test signals.
100+
101+
Args:
102+
freq: Frequency of the sine wave in Hz.
103+
duration: Duration of the audio in seconds.
104+
sample_rate: Sample rate in Hz (default: 48000).
105+
amplitude: Amplitude of the sine wave, range [0.0, 1.0] (default: 0.3).
106+
107+
Yields:
108+
AudioFrame: Audio frames containing sine wave data.
109+
110+
Example:
111+
>>> import asyncio
112+
>>> async def generate_audio():
113+
... async for frame in sine_wave_generator(440, 1.0):
114+
... print(f"Generated frame with {frame.samples_per_channel} samples")
115+
>>> asyncio.run(generate_audio())
116+
"""
117+
try:
118+
import numpy as np
119+
except ImportError:
120+
raise ImportError(
121+
"numpy is required for sine_wave_generator. Install it with: pip install numpy"
122+
)
123+
124+
blocksize = sample_rate // 10
125+
total_frames = int((duration * sample_rate) // blocksize)
126+
t_frame = np.arange(blocksize) / sample_rate
127+
128+
for i in range(total_frames):
129+
t = t_frame + i * blocksize / sample_rate
130+
signal = amplitude * np.sin(2 * np.pi * freq * t)
131+
signal_int16 = np.int16(signal * 32767)
132+
frame = AudioFrame(
133+
signal_int16.tobytes(),
134+
sample_rate,
135+
1,
136+
blocksize,
137+
)
138+
yield frame

livekit-rtc/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ manylinux-pypy_i686-image = "manylinux_2_28"
2222
manylinux-pypy_aarch64-image = "manylinux_2_28"
2323

2424
[tool.cibuildwheel.linux]
25-
before-build = "pip install requests && python rust-sdks/download_ffi.py --output livekit/rtc/resources && yum install -y libX11-devel libXrandr-devel libXext-devel libXfixes-devel libXdamage-devel libXcomposite-devel libXi-devel mesa-libGL-devel || apt install -y xorg-dev"
25+
before-build = "pip install requests && python rust-sdks/download_ffi.py --output livekit/rtc/resources && yum install -y libX11-devel libXrandr-devel libXext-devel libXfixes-devel libXdamage-devel libXcomposite-devel libXi-devel mesa-libGL-devel || apt install -y xorg-dev"

0 commit comments

Comments
 (0)