Skip to content

Commit adfedca

Browse files
authored
updated AVSynchronizer readme (livekit#326)
1 parent c0b1e1c commit adfedca

File tree

3 files changed

+39
-12
lines changed

3 files changed

+39
-12
lines changed

examples/video-stream/README.md

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,25 @@ await av_sync.push(audio_frame)
2222
## Examples
2323

2424
### 1. Video File Playback (`video_play.py`)
25-
Shows how to stream video and audio from separate sources while maintaining sync:
2625

27-
- Reads video and audio streams separately from a media file
26+
Demonstrates synchronizing video and audio from separate sources while maintaining sync:
27+
28+
- Reads video and audio streams separately from a media file (using `av` library)
2829
- Uses separate tasks to push video and audio frames to the synchronizer
2930
- Since the streams are continuous, a larger `queue_size_ms` can be used, though this will increase memory usage
3031

31-
### 2. Audio Visualization (`audio_wave.py`)
32+
#### Usage:
33+
34+
```bash
35+
python video_play.py <room-name> </path/to/video>
36+
```
37+
38+
### 2. Audio Visualization (`audio_wave.py`)
39+
3240
Demonstrates generating video based on audio input:
3341

3442
- Generates audio frames with alternating sine waves and silence
35-
- Creates video frames visualizing the audio waveform
43+
- Creates video frames visualizing the audio waveform (using `cv2` library)
3644
- Shows how to handle cases with and without audio:
3745
- When audio is present: Push synchronized video and audio frames
3846
- During silence: Push only video frames

examples/video-stream/audio_wave.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import numpy as np
1111
from livekit import rtc, api
12+
import sys
1213

1314
try:
1415
import cv2
@@ -218,15 +219,15 @@ def _np_to_video_frame(image: np.ndarray) -> rtc.VideoFrame:
218219
yield video_frame, sub_audio_frame
219220

220221

221-
async def main(room: rtc.Room):
222+
async def main(room: rtc.Room, room_name: str):
222223
token = (
223224
api.AccessToken()
224225
.with_identity("python-publisher")
225226
.with_name("Python Publisher")
226227
.with_grants(
227228
api.VideoGrants(
228229
room_join=True,
229-
room="room-ysBA-Q0hM",
230+
room=room_name,
230231
agent=True,
231232
)
232233
)
@@ -303,14 +304,19 @@ async def main(room: rtc.Room):
303304
handlers=[logging.FileHandler("audio_wave.log"), logging.StreamHandler()],
304305
)
305306

307+
if len(sys.argv) != 2:
308+
print("Usage: python audio_wave.py <room-name>")
309+
sys.exit(1)
310+
311+
room_name = sys.argv[1]
306312
loop = asyncio.get_event_loop()
307313
room = rtc.Room(loop=loop)
308314

309315
async def cleanup():
310316
await room.disconnect()
311317
loop.stop()
312318

313-
asyncio.ensure_future(main(room))
319+
asyncio.ensure_future(main(room, room_name))
314320
for signal in [signal.SIGINT, signal.SIGTERM]:
315321
loop.add_signal_handler(signal, lambda: asyncio.ensure_future(cleanup()))
316322

examples/video-stream/video_play.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from dataclasses import dataclass
44
from pathlib import Path
55
from typing import AsyncIterable, Union
6+
import sys
67

78
import numpy as np
89
import os
@@ -92,15 +93,15 @@ async def aclose(self) -> None:
9293
self._audio_container.close()
9394

9495

95-
async def main(room: rtc.Room):
96+
async def main(room: rtc.Room, room_name: str, media_path: str):
9697
token = (
9798
api.AccessToken()
9899
.with_identity("python-publisher")
99100
.with_name("Python Publisher")
100101
.with_grants(
101102
api.VideoGrants(
102103
room_join=True,
103-
room="my-room",
104+
room=room_name,
104105
)
105106
)
106107
.to_jwt()
@@ -116,7 +117,6 @@ async def main(room: rtc.Room):
116117
return
117118

118119
# Create media streamer
119-
media_path = "/path/to/video.mp4"
120120
streamer = MediaFileStreamer(media_path)
121121
media_info = streamer.info
122122

@@ -137,7 +137,13 @@ async def main(room: rtc.Room):
137137
audio_track = rtc.LocalAudioTrack.create_audio_track("audio", audio_source)
138138

139139
# Publish tracks
140-
video_options = rtc.TrackPublishOptions(source=rtc.TrackSource.SOURCE_CAMERA)
140+
video_options = rtc.TrackPublishOptions(
141+
source=rtc.TrackSource.SOURCE_CAMERA,
142+
video_encoding=rtc.VideoEncoding(
143+
max_framerate=30,
144+
max_bitrate=5_000_000,
145+
),
146+
)
141147
audio_options = rtc.TrackPublishOptions(source=rtc.TrackSource.SOURCE_MICROPHONE)
142148

143149
await room.local_participant.publish_track(video_track, video_options)
@@ -183,14 +189,21 @@ async def _push_frames(
183189
handlers=[logging.FileHandler("video_play.log"), logging.StreamHandler()],
184190
)
185191

192+
if len(sys.argv) != 3:
193+
print("Usage: python video_play.py <room-name> </path/to/video>")
194+
sys.exit(1)
195+
196+
room_name = sys.argv[1]
197+
media_path = sys.argv[2]
198+
186199
loop = asyncio.get_event_loop()
187200
room = rtc.Room(loop=loop)
188201

189202
async def cleanup():
190203
await room.disconnect()
191204
loop.stop()
192205

193-
asyncio.ensure_future(main(room))
206+
asyncio.ensure_future(main(room, room_name, media_path))
194207
for signal in [signal.SIGINT, signal.SIGTERM]:
195208
loop.add_signal_handler(signal, lambda: asyncio.ensure_future(cleanup()))
196209

0 commit comments

Comments
 (0)