66from ._ffi_client import (FfiClient , FfiHandle )
77from typing import TYPE_CHECKING
88import weakref
9+ import ctypes
910import asyncio
10- from livekit import TrackPublishOptions
11+ from livekit import ( TrackPublishOptions , DataPacketKind )
1112
1213if TYPE_CHECKING :
1314 from livekit import (Room , Participant )
@@ -18,6 +19,11 @@ def __init__(self, message: str):
1819 self .message = message
1920
2021
22+ class PublishDataError (Exception ):
23+ def __init__ (self , message : str ):
24+ self .message = message
25+
26+
2127class Participant ():
2228 def __init__ (self , info : proto_participant .ParticipantInfo ):
2329 self ._info = info
@@ -45,6 +51,52 @@ def __init__(self, info: proto_participant.ParticipantInfo, room: weakref.ref['R
4551 super ().__init__ (info )
4652 self ._room = room
4753
54+ async def publish_data (self ,
55+ # TODO(theomonnom): Allow ctypes.Array as payload?
56+ payload : bytes or str ,
57+ kind : DataPacketKind = DataPacketKind .KIND_RELIABLE ,
58+ destination_sids : list [str ] or list ['RemoteParticipant' ] = []):
59+
60+ room = self ._room ()
61+ if room is None :
62+ raise Exception ('room is closed' )
63+
64+ if isinstance (payload , str ):
65+ payload = payload .encode ('utf-8' )
66+
67+ data_len = len (payload )
68+
69+ cdata = (ctypes .c_byte * data_len )(* payload )
70+
71+ sids = []
72+ for p in destination_sids :
73+ if isinstance (p , RemoteParticipant ):
74+ sids .append (p .sid )
75+ else :
76+ sids .append (p )
77+
78+ req = proto_ffi .FfiRequest ()
79+ req .publish_data .room_handle .id = room ._ffi_handle .handle
80+ req .publish_data .data_ptr = ctypes .addressof (cdata )
81+ req .publish_data .data_size = data_len
82+ req .publish_data .kind = kind
83+ req .publish_data .destination_sids .extend (sids )
84+
85+ ffi_client = FfiClient ()
86+ resp = ffi_client .request (req )
87+ future = asyncio .Future ()
88+
89+ @ffi_client .on ('publish_data' )
90+ def on_publish_callback (cb : proto_room .PublishDataCallback ):
91+ if cb .async_id == resp .publish_data .async_id :
92+ future .set_result (cb )
93+ ffi_client .remove_listener (
94+ 'publish_data' , on_publish_callback )
95+
96+ resp : proto_room .PublishDataCallback = await future
97+ if resp .error :
98+ raise PublishDataError (resp .error )
99+
48100 async def publish_track (self , track : Track , options : TrackPublishOptions ) -> TrackPublication :
49101 if not isinstance (track , LocalAudioTrack ) and not isinstance (track , LocalVideoTrack ):
50102 raise Exception ('cannot publish a remote track' )
0 commit comments