|
| 1 | +import asyncio |
| 2 | +import colorsys |
| 3 | +import logging |
| 4 | +from signal import SIGINT, SIGTERM |
| 5 | + |
| 6 | +import numpy as np |
| 7 | + |
| 8 | +import livekit |
| 9 | + |
| 10 | +URL = 'ws://localhost:7880' |
| 11 | +TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE5MDY2MTMyODgsImlzcyI6IkFQSVRzRWZpZFpqclFvWSIsIm5hbWUiOiJuYXRpdmUiLCJuYmYiOjE2NzI2MTMyODgsInN1YiI6Im5hdGl2ZSIsInZpZGVvIjp7InJvb20iOiJ0ZXN0Iiwicm9vbUFkbWluIjp0cnVlLCJyb29tQ3JlYXRlIjp0cnVlLCJyb29tSm9pbiI6dHJ1ZSwicm9vbUxpc3QiOnRydWV9fQ.uSNIangMRu8jZD5mnRYoCHjcsQWCrJXgHCs0aNIgBFY' # noqa |
| 12 | + |
| 13 | + |
| 14 | +async def publish_frames(source: livekit.VideoSource): |
| 15 | + argb_frame = livekit.ArgbFrame( |
| 16 | + livekit.VideoFormatType.FORMAT_ARGB, 1280, 720) |
| 17 | + |
| 18 | + arr = np.ctypeslib.as_array(argb_frame.data) |
| 19 | + |
| 20 | + framerate = 1 / 30 |
| 21 | + hue = 0.0 |
| 22 | + |
| 23 | + while True: |
| 24 | + frame = livekit.VideoFrame( |
| 25 | + 0, livekit.VideoRotation.VIDEO_ROTATION_0, argb_frame.to_i420()) |
| 26 | + |
| 27 | + rgb = colorsys.hsv_to_rgb(hue, 1.0, 1.0) |
| 28 | + rgb = [(x * 255) for x in rgb] # type: ignore |
| 29 | + |
| 30 | + argb_color = np.array(rgb + [255], dtype=np.uint8) |
| 31 | + arr.flat[::4] = argb_color[0] |
| 32 | + arr.flat[1::4] = argb_color[1] |
| 33 | + arr.flat[2::4] = argb_color[2] |
| 34 | + arr.flat[3::4] = argb_color[3] |
| 35 | + |
| 36 | + source.capture_frame(frame) |
| 37 | + |
| 38 | + hue += framerate/3 # 3s for a full cycle |
| 39 | + if hue >= 1.0: |
| 40 | + hue = 0.0 |
| 41 | + |
| 42 | + try: |
| 43 | + await asyncio.sleep(framerate) |
| 44 | + except asyncio.CancelledError: |
| 45 | + break |
| 46 | + |
| 47 | + |
| 48 | +async def main(): |
| 49 | + room = livekit.Room() |
| 50 | + |
| 51 | + @room.listens_to("e2ee_state_changed") |
| 52 | + def on_e2ee_state_changed(participant: livekit.Participant, |
| 53 | + state: livekit.E2eeState) -> None: |
| 54 | + logging.info("e2ee state changed: %s %s", participant.identity, state) |
| 55 | + |
| 56 | + logging.info("connecting to %s", URL) |
| 57 | + try: |
| 58 | + e2ee_options = livekit.E2EEOptions() |
| 59 | + e2ee_options.key_provider_options.shared_key = b"abcdef" # this is our e2ee key |
| 60 | + |
| 61 | + await room.connect(URL, TOKEN, options=livekit.RoomOptions( |
| 62 | + auto_subscribe=True, |
| 63 | + e2ee=e2ee_options |
| 64 | + )) |
| 65 | + |
| 66 | + logging.info("connected to room %s", room.name) |
| 67 | + except livekit.ConnectError as e: |
| 68 | + logging.error("failed to connect to the room: %s", e) |
| 69 | + return False |
| 70 | + |
| 71 | + source = livekit.VideoSource() |
| 72 | + source_task = asyncio.create_task(publish_frames(source)) |
| 73 | + |
| 74 | + track = livekit.LocalVideoTrack.create_video_track("hue", source) |
| 75 | + options = livekit.TrackPublishOptions() |
| 76 | + options.source = livekit.TrackSource.SOURCE_CAMERA |
| 77 | + publication = await room.local_participant.publish_track(track, options) |
| 78 | + logging.info("published track %s", publication.sid) |
| 79 | + |
| 80 | + try: |
| 81 | + await room.run() |
| 82 | + except asyncio.CancelledError: |
| 83 | + logging.info("closing the room") |
| 84 | + source_task.cancel() |
| 85 | + await source_task |
| 86 | + await room.disconnect() |
| 87 | + |
| 88 | + |
| 89 | +if __name__ == "__main__": |
| 90 | + logging.basicConfig(level=logging.INFO, handlers=[ |
| 91 | + logging.FileHandler("publish_hue.log"), logging.StreamHandler()]) |
| 92 | + |
| 93 | + loop = asyncio.get_event_loop() |
| 94 | + main_task = asyncio.ensure_future(main()) |
| 95 | + for signal in [SIGINT, SIGTERM]: |
| 96 | + loop.add_signal_handler(signal, main_task.cancel) |
| 97 | + try: |
| 98 | + loop.run_until_complete(main_task) |
| 99 | + finally: |
| 100 | + loop.close() |
0 commit comments