11import asyncio
2- import colorsys
32import logging
43from signal import SIGINT , SIGTERM
54
109URL = 'ws://localhost:7880'
1110TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE5MDY2MTMyODgsImlzcyI6IkFQSVRzRWZpZFpqclFvWSIsIm5hbWUiOiJuYXRpdmUiLCJuYmYiOjE2NzI2MTMyODgsInN1YiI6Im5hdGl2ZSIsInZpZGVvIjp7InJvb20iOiJ0ZXN0Iiwicm9vbUFkbWluIjp0cnVlLCJyb29tQ3JlYXRlIjp0cnVlLCJyb29tSm9pbiI6dHJ1ZSwicm9vbUxpc3QiOnRydWV9fQ.uSNIangMRu8jZD5mnRYoCHjcsQWCrJXgHCs0aNIgBFY' # noqa
1211
12+ # ("livekitrocks") this is our shared key, it must match the one used by your clients
13+ SHARED_KEY = b"livekitrocks"
1314
14- async def publish_frames (source : livekit .VideoSource ):
15- argb_frame = livekit .ArgbFrame (
16- livekit .VideoFormatType .FORMAT_ARGB , 1280 , 720 )
1715
18- arr = np .ctypeslib .as_array (argb_frame .data )
16+ async def draw_cube (source : livekit .VideoSource ):
17+ W , H , MID_W , MID_H = 1280 , 720 , 640 , 360
18+ cube_size = 60
19+ vertices = (np .array ([[- 1 , - 1 , - 1 ], [1 , - 1 , - 1 ], [1 , 1 , - 1 ], [- 1 , 1 , - 1 ],
20+ [- 1 , - 1 , 1 ], [1 , - 1 , 1 ], [1 , 1 , 1 ], [- 1 , 1 , 1 ]]) * cube_size )
21+ edges = [[0 , 1 ], [1 , 2 ], [2 , 3 ], [3 , 0 ], [4 , 5 ], [5 , 6 ],
22+ [6 , 7 ], [7 , 4 ], [0 , 4 ], [1 , 5 ], [2 , 6 ], [3 , 7 ]]
1923
20- framerate = 1 / 30
21- hue = 0.0
24+ frame = livekit .ArgbFrame (livekit .VideoFormatType .FORMAT_ARGB , W , H )
25+ arr = np .ctypeslib .as_array (frame .data )
26+ angle = 0
2227
2328 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-
29+ start_time = asyncio .get_event_loop ().time ()
30+ arr .fill (0 )
31+ rot = np .dot (np .array ([[1 , 0 , 0 ],
32+ [0 , np .cos (angle ), - np .sin (angle )],
33+ [0 , np .sin (angle ), np .cos (angle )]]),
34+ np .array ([[np .cos (angle ), 0 , np .sin (angle )],
35+ [0 , 1 , 0 ],
36+ [- np .sin (angle ), 0 , np .cos (angle )]]))
37+ proj_points = [[int (pt [0 ] / (pt [2 ] / 200 + 1 )), int (pt [1 ] / (pt [2 ] / 200 + 1 ))]
38+ for pt in np .dot (vertices , rot )]
39+
40+ for e in edges :
41+ x1 , y1 , x2 , y2 = * proj_points [e [0 ]], * proj_points [e [1 ]]
42+ for t in np .linspace (0 , 1 , 100 ):
43+ x , y = int (MID_W + (1 - t ) * x1 + t *
44+ x2 ), int (MID_H + (1 - t ) * y1 + t * y2 )
45+ for dx in [- 1 , 0 , 1 ]:
46+ for dy in [- 1 , 0 , 1 ]:
47+ if 0 <= x + dx < W and 0 <= y + dy < H :
48+ idx = (y + dy ) * W * 4 + (x + dx ) * 4
49+ arr [idx :idx + 4 ] = [255 , 255 , 255 , 255 ]
50+
51+ f = livekit .VideoFrame (
52+ 0 , livekit .VideoRotation .VIDEO_ROTATION_0 , frame .to_i420 ())
53+ source .capture_frame (f )
54+ angle += 0.02
55+
56+ code_duration = asyncio .get_event_loop ().time () - start_time
57+ await asyncio .sleep (1 / 30 - code_duration )
58+
59+
60+ async def main (room : livekit .Room ):
5161 @room .listens_to ("e2ee_state_changed" )
5262 def on_e2ee_state_changed (participant : livekit .Participant ,
5363 state : livekit .EncryptionState ) -> None :
@@ -56,7 +66,7 @@ def on_e2ee_state_changed(participant: livekit.Participant,
5666 logging .info ("connecting to %s" , URL )
5767 try :
5868 e2ee_options = livekit .E2EEOptions ()
59- e2ee_options .key_provider_options .shared_key = b"livekitrocks" # this is our e2ee key
69+ e2ee_options .key_provider_options .shared_key = SHARED_KEY
6070
6171 await room .connect (URL , TOKEN , options = livekit .RoomOptions (
6272 auto_subscribe = True ,
@@ -68,33 +78,34 @@ def on_e2ee_state_changed(participant: livekit.Participant,
6878 logging .error ("failed to connect to the room: %s" , e )
6979 return False
7080
81+ # publish a track
7182 source = livekit .VideoSource ()
72- source_task = asyncio .create_task (publish_frames (source ))
73-
74- track = livekit .LocalVideoTrack .create_video_track ("hue" , source )
83+ track = livekit .LocalVideoTrack .create_video_track ("cube" , source )
7584 options = livekit .TrackPublishOptions ()
7685 options .source = livekit .TrackSource .SOURCE_CAMERA
7786 publication = await room .local_participant .publish_track (track , options )
7887 logging .info ("published track %s" , publication .sid )
7988
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-
89+ asyncio .ensure_future (draw_cube (source ))
8890
8991if __name__ == "__main__" :
9092 logging .basicConfig (level = logging .INFO , handlers = [
91- logging .FileHandler ("publish_hue.log" ), logging .StreamHandler ()])
93+ logging .FileHandler ("e2ee.log" ),
94+ logging .StreamHandler ()])
9295
9396 loop = asyncio .get_event_loop ()
94- main_task = asyncio .ensure_future (main ())
97+ room = livekit .Room (loop = loop )
98+
99+ async def cleanup ():
100+ await room .disconnect ()
101+ loop .stop ()
102+
103+ asyncio .ensure_future (main (room ))
95104 for signal in [SIGINT , SIGTERM ]:
96- loop .add_signal_handler (signal , main_task .cancel )
105+ loop .add_signal_handler (
106+ signal , lambda : asyncio .ensure_future (cleanup ()))
107+
97108 try :
98- loop .run_until_complete ( main_task )
109+ loop .run_forever ( )
99110 finally :
100111 loop .close ()
0 commit comments