diff --git a/.gitignore b/.gitignore index 1756b987..ea0eda1f 100644 --- a/.gitignore +++ b/.gitignore @@ -162,4 +162,6 @@ cython_debug/ # vscode project settings .vscode -.DS_Store \ No newline at end of file +.DS_Store + +docs \ No newline at end of file diff --git a/livekit-api/livekit/api/__init__.py b/livekit-api/livekit/api/__init__.py index 0355cbb4..6debf821 100644 --- a/livekit-api/livekit/api/__init__.py +++ b/livekit-api/livekit/api/__init__.py @@ -12,7 +12,16 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""LiveKit API SDK""" +"""LiveKit Server APIs for Python + +`pip install livekit-api` + +Manage rooms, participants, egress, ingress, SIP, and Agent dispatch. + +Primary entry point is `LiveKitAPI`. + +See https://docs.livekit.io/reference/server/server-apis for more information. +""" # flake8: noqa # re-export packages from protocol @@ -30,3 +39,17 @@ from .access_token import VideoGrants, SIPGrants, AccessToken, TokenVerifier from .webhook import WebhookReceiver from .version import __version__ + +__all__ = [ + "LiveKitAPI", + "room_service", + "egress_service", + "ingress_service", + "sip_service", + "agent_dispatch_service", + "VideoGrants", + "SIPGrants", + "AccessToken", + "TokenVerifier", + "WebhookReceiver", +] diff --git a/livekit-api/livekit/api/agent_dispatch_service.py b/livekit-api/livekit/api/agent_dispatch_service.py index 769bf200..5cdfc1e7 100644 --- a/livekit-api/livekit/api/agent_dispatch_service.py +++ b/livekit-api/livekit/api/agent_dispatch_service.py @@ -1,16 +1,29 @@ import aiohttp from typing import Optional -from livekit.protocol import agent_dispatch as proto_agent_dispatch +from livekit.protocol.agent_dispatch import ( + CreateAgentDispatchRequest, + AgentDispatch, + DeleteAgentDispatchRequest, + ListAgentDispatchRequest, + ListAgentDispatchResponse, +) from ._service import Service from .access_token import VideoGrants SVC = "AgentDispatchService" +"""@private""" class AgentDispatchService(Service): """Manage agent dispatches. Service APIs require roomAdmin permissions. - An easier way to construct this service is via LiveKitAPI.agent_dispatch. + Recommended way to use this service is via `livekit.api.LiveKitAPI`: + + ```python + from livekit import api + lkapi = api.LiveKitAPI() + agent_dispatch = lkapi.agent_dispatch + ``` """ def __init__( @@ -18,9 +31,7 @@ def __init__( ): super().__init__(session, url, api_key, api_secret) - async def create_dispatch( - self, req: proto_agent_dispatch.CreateAgentDispatchRequest - ) -> proto_agent_dispatch.AgentDispatch: + async def create_dispatch(self, req: CreateAgentDispatchRequest) -> AgentDispatch: """Create an explicit dispatch for an agent to join a room. To use explicit dispatch, your agent must be registered with an `agentName`. @@ -36,12 +47,10 @@ async def create_dispatch( "CreateDispatch", req, self._auth_header(VideoGrants(room_admin=True, room=req.room)), - proto_agent_dispatch.AgentDispatch, + AgentDispatch, ) - async def delete_dispatch( - self, dispatch_id: str, room_name: str - ) -> proto_agent_dispatch.AgentDispatch: + async def delete_dispatch(self, dispatch_id: str, room_name: str) -> AgentDispatch: """Delete an explicit dispatch for an agent in a room. Args: @@ -54,17 +63,15 @@ async def delete_dispatch( return await self._client.request( SVC, "DeleteDispatch", - proto_agent_dispatch.DeleteAgentDispatchRequest( + DeleteAgentDispatchRequest( dispatch_id=dispatch_id, room=room_name, ), self._auth_header(VideoGrants(room_admin=True, room=room_name)), - proto_agent_dispatch.AgentDispatch, + AgentDispatch, ) - async def list_dispatch( - self, room_name: str - ) -> list[proto_agent_dispatch.AgentDispatch]: + async def list_dispatch(self, room_name: str) -> list[AgentDispatch]: """List all agent dispatches in a room. Args: @@ -76,15 +83,15 @@ async def list_dispatch( res = await self._client.request( SVC, "ListDispatch", - proto_agent_dispatch.ListAgentDispatchRequest(room=room_name), + ListAgentDispatchRequest(room=room_name), self._auth_header(VideoGrants(room_admin=True, room=room_name)), - proto_agent_dispatch.ListAgentDispatchResponse, + ListAgentDispatchResponse, ) return list(res.agent_dispatches) async def get_dispatch( self, dispatch_id: str, room_name: str - ) -> Optional[proto_agent_dispatch.AgentDispatch]: + ) -> Optional[AgentDispatch]: """Get an Agent dispatch by ID Args: @@ -97,11 +104,9 @@ async def get_dispatch( res = await self._client.request( SVC, "ListDispatch", - proto_agent_dispatch.ListAgentDispatchRequest( - dispatch_id=dispatch_id, room=room_name - ), + ListAgentDispatchRequest(dispatch_id=dispatch_id, room=room_name), self._auth_header(VideoGrants(room_admin=True, room=room_name)), - proto_agent_dispatch.ListAgentDispatchResponse, + ListAgentDispatchResponse, ) if len(res.agent_dispatches) > 0: return res.agent_dispatches[0] diff --git a/livekit-api/livekit/api/egress_service.py b/livekit-api/livekit/api/egress_service.py index a875459b..b5d4984e 100644 --- a/livekit-api/livekit/api/egress_service.py +++ b/livekit-api/livekit/api/egress_service.py @@ -1,112 +1,126 @@ import aiohttp -from livekit.protocol import egress as proto_egress +from livekit.protocol.egress import ( + RoomCompositeEgressRequest, + WebEgressRequest, + ParticipantEgressRequest, + TrackCompositeEgressRequest, + TrackEgressRequest, + UpdateLayoutRequest, + UpdateStreamRequest, + ListEgressRequest, + StopEgressRequest, + EgressInfo, + ListEgressResponse, +) from ._service import Service from .access_token import VideoGrants SVC = "Egress" +"""@private""" class EgressService(Service): + """Client for LiveKit Egress Service API + + Recommended way to use this service is via `livekit.api.LiveKitAPI`: + + ```python + from livekit import api + lkapi = api.LiveKitAPI() + egress = lkapi.egress + ``` + + Also see https://docs.livekit.io/home/egress/overview/ + """ + def __init__( self, session: aiohttp.ClientSession, url: str, api_key: str, api_secret: str ): super().__init__(session, url, api_key, api_secret) async def start_room_composite_egress( - self, start: proto_egress.RoomCompositeEgressRequest - ) -> proto_egress.EgressInfo: + self, start: RoomCompositeEgressRequest + ) -> EgressInfo: return await self._client.request( SVC, "StartRoomCompositeEgress", start, self._auth_header(VideoGrants(room_record=True)), - proto_egress.EgressInfo, + EgressInfo, ) - async def start_web_egress( - self, start: proto_egress.WebEgressRequest - ) -> proto_egress.EgressInfo: + async def start_web_egress(self, start: WebEgressRequest) -> EgressInfo: return await self._client.request( SVC, "StartWebEgress", start, self._auth_header(VideoGrants(room_record=True)), - proto_egress.EgressInfo, + EgressInfo, ) async def start_participant_egress( - self, start: proto_egress.ParticipantEgressRequest - ) -> proto_egress.EgressInfo: + self, start: ParticipantEgressRequest + ) -> EgressInfo: return await self._client.request( SVC, "StartParticipantEgress", start, self._auth_header(VideoGrants(room_record=True)), - proto_egress.EgressInfo, + EgressInfo, ) async def start_track_composite_egress( - self, start: proto_egress.TrackCompositeEgressRequest - ) -> proto_egress.EgressInfo: + self, start: TrackCompositeEgressRequest + ) -> EgressInfo: return await self._client.request( SVC, "StartTrackCompositeEgress", start, self._auth_header(VideoGrants(room_record=True)), - proto_egress.EgressInfo, + EgressInfo, ) - async def start_track_egress( - self, start: proto_egress.TrackEgressRequest - ) -> proto_egress.EgressInfo: + async def start_track_egress(self, start: TrackEgressRequest) -> EgressInfo: return await self._client.request( SVC, "StartTrackEgress", start, self._auth_header(VideoGrants(room_record=True)), - proto_egress.EgressInfo, + EgressInfo, ) - async def update_layout( - self, update: proto_egress.UpdateLayoutRequest - ) -> proto_egress.EgressInfo: + async def update_layout(self, update: UpdateLayoutRequest) -> EgressInfo: return await self._client.request( SVC, "UpdateLayout", update, self._auth_header(VideoGrants(room_record=True)), - proto_egress.EgressInfo, + EgressInfo, ) - async def update_stream( - self, update: proto_egress.UpdateStreamRequest - ) -> proto_egress.EgressInfo: + async def update_stream(self, update: UpdateStreamRequest) -> EgressInfo: return await self._client.request( SVC, "UpdateStream", update, self._auth_header(VideoGrants(room_record=True)), - proto_egress.EgressInfo, + EgressInfo, ) - async def list_egress( - self, list: proto_egress.ListEgressRequest - ) -> proto_egress.ListEgressResponse: + async def list_egress(self, list: ListEgressRequest) -> ListEgressResponse: return await self._client.request( SVC, "ListEgress", list, self._auth_header(VideoGrants(room_record=True)), - proto_egress.ListEgressResponse, + ListEgressResponse, ) - async def stop_egress( - self, stop: proto_egress.StopEgressRequest - ) -> proto_egress.EgressInfo: + async def stop_egress(self, stop: StopEgressRequest) -> EgressInfo: return await self._client.request( SVC, "StopEgress", stop, self._auth_header(VideoGrants(room_record=True)), - proto_egress.EgressInfo, + EgressInfo, ) diff --git a/livekit-api/livekit/api/ingress_service.py b/livekit-api/livekit/api/ingress_service.py index abf691ef..7b658bb8 100644 --- a/livekit-api/livekit/api/ingress_service.py +++ b/livekit-api/livekit/api/ingress_service.py @@ -1,57 +1,70 @@ import aiohttp -from livekit.protocol import ingress as proto_ingress +from livekit.protocol.ingress import ( + CreateIngressRequest, + IngressInfo, + UpdateIngressRequest, + ListIngressRequest, + DeleteIngressRequest, + ListIngressResponse, +) from ._service import Service from .access_token import VideoGrants SVC = "Ingress" +"""@private""" class IngressService(Service): + """Client for LiveKit Ingress Service API + + Recommended way to use this service is via `livekit.api.LiveKitAPI`: + + ```python + from livekit import api + lkapi = api.LiveKitAPI() + ingress = lkapi.ingress + ``` + + Also see https://docs.livekit.io/home/ingress/overview/ + """ + def __init__( self, session: aiohttp.ClientSession, url: str, api_key: str, api_secret: str ): super().__init__(session, url, api_key, api_secret) - async def create_ingress( - self, create: proto_ingress.CreateIngressRequest - ) -> proto_ingress.IngressInfo: + async def create_ingress(self, create: CreateIngressRequest) -> IngressInfo: return await self._client.request( SVC, "CreateIngress", create, self._auth_header(VideoGrants(ingress_admin=True)), - proto_ingress.IngressInfo, + IngressInfo, ) - async def update_ingress( - self, update: proto_ingress.UpdateIngressRequest - ) -> proto_ingress.IngressInfo: + async def update_ingress(self, update: UpdateIngressRequest) -> IngressInfo: return await self._client.request( SVC, "UpdateIngress", update, self._auth_header(VideoGrants(ingress_admin=True)), - proto_ingress.IngressInfo, + IngressInfo, ) - async def list_ingress( - self, list: proto_ingress.ListIngressRequest - ) -> proto_ingress.ListIngressResponse: + async def list_ingress(self, list: ListIngressRequest) -> ListIngressResponse: return await self._client.request( SVC, "ListIngress", list, self._auth_header(VideoGrants(ingress_admin=True)), - proto_ingress.ListIngressResponse, + ListIngressResponse, ) - async def delete_ingress( - self, delete: proto_ingress.DeleteIngressRequest - ) -> proto_ingress.IngressInfo: + async def delete_ingress(self, delete: DeleteIngressRequest) -> IngressInfo: return await self._client.request( SVC, "DeleteIngress", delete, self._auth_header(VideoGrants(ingress_admin=True)), - proto_ingress.IngressInfo, + IngressInfo, ) diff --git a/livekit-api/livekit/api/livekit_api.py b/livekit-api/livekit/api/livekit_api.py index 29834842..63efda02 100644 --- a/livekit-api/livekit/api/livekit_api.py +++ b/livekit-api/livekit/api/livekit_api.py @@ -9,6 +9,19 @@ class LiveKitAPI: + """LiveKit Server API Client + + This class is the main entrypoint, which exposes all services. + + Usage: + + ```python + from livekit import api + lkapi = api.LiveKitAPI() + rooms = await lkapi.room.list_rooms(api.proto_room.ListRoomsRequest(names=['test-room'])) + ``` + """ + def __init__( self, url: Optional[str] = None, @@ -17,6 +30,14 @@ def __init__( *, timeout: aiohttp.ClientTimeout = aiohttp.ClientTimeout(total=60), # 60 seconds ): + """Create a new LiveKitAPI instance. + + Args: + url: LiveKit server URL (read from `LIVEKIT_URL` environment variable if not provided) + api_key: API key (read from `LIVEKIT_API_KEY` environment variable if not provided) + api_secret: API secret (read from `LIVEKIT_API_SECRET` environment variable if not provided) + timeout: Request timeout (default: 60 seconds) + """ url = url or os.getenv("LIVEKIT_URL") api_key = api_key or os.getenv("LIVEKIT_API_KEY") api_secret = api_secret or os.getenv("LIVEKIT_API_SECRET") @@ -37,24 +58,44 @@ def __init__( ) @property - def agent_dispatch(self): + def agent_dispatch(self) -> AgentDispatchService: + """Instance of the AgentDispatchService""" return self._agent_dispatch @property - def room(self): + def room(self) -> RoomService: + """Instance of the RoomService""" return self._room @property - def ingress(self): + def ingress(self) -> IngressService: + """Instance of the IngressService""" return self._ingress @property - def egress(self): + def egress(self) -> EgressService: + """Instance of the EgressService""" return self._egress @property - def sip(self): + def sip(self) -> SipService: + """Instance of the SipService""" return self._sip async def aclose(self): + """Close the API client + + Call this before your application exits or when the API client is no longer needed.""" await self._session.close() + + async def __aenter__(self): + """@private + + Support for `async with`""" + return self + + async def __aexit__(self, exc_type, exc_val, exc_tb): + """@private + + Support for `async with`""" + await self.aclose() diff --git a/livekit-api/livekit/api/room_service.py b/livekit-api/livekit/api/room_service.py index 9c1b197a..353a5ec8 100644 --- a/livekit-api/livekit/api/room_service.py +++ b/livekit-api/livekit/api/room_service.py @@ -1,136 +1,297 @@ import aiohttp -from livekit.protocol import room as proto_room -from livekit.protocol import models as proto_models +from livekit.protocol.room import ( + CreateRoomRequest, + ListRoomsRequest, + DeleteRoomRequest, + ListRoomsResponse, + DeleteRoomResponse, + ListParticipantsRequest, + ListParticipantsResponse, + RoomParticipantIdentity, + MuteRoomTrackRequest, + MuteRoomTrackResponse, + UpdateParticipantRequest, + UpdateSubscriptionsRequest, + SendDataRequest, + SendDataResponse, + UpdateRoomMetadataRequest, + RemoveParticipantResponse, + UpdateSubscriptionsResponse, +) +from livekit.protocol.models import Room, ParticipantInfo from ._service import Service from .access_token import VideoGrants SVC = "RoomService" +"""@private""" class RoomService(Service): + """Client for LiveKit RoomService API + + Recommended way to use this service is via `livekit.api.LiveKitAPI`: + + ```python + from livekit import api + lkapi = api.LiveKitAPI() + room_service = lkapi.room + ``` + + Also see https://docs.livekit.io/home/server/managing-rooms/ and https://docs.livekit.io/home/server/managing-participants/ + """ + def __init__( self, session: aiohttp.ClientSession, url: str, api_key: str, api_secret: str ): super().__init__(session, url, api_key, api_secret) async def create_room( - self, create: proto_room.CreateRoomRequest - ) -> proto_models.Room: + self, + create: CreateRoomRequest, + ) -> Room: + """Creates a new room with specified configuration. + + Args: + create (CreateRoomRequest): arg containing: + - name: str - Unique room name + - empty_timeout: int - Seconds to keep room open if empty + - max_participants: int - Max allowed participants + - metadata: str - Custom room metadata + - egress: RoomEgress - Egress configuration + - min_playout_delay: int - Minimum playout delay in ms + - max_playout_delay: int - Maximum playout delay in ms + - sync_streams: bool - Enable A/V sync for playout delays >200ms + + Returns: + Room: The created room object + """ return await self._client.request( SVC, "CreateRoom", create, self._auth_header(VideoGrants(room_create=True)), - proto_models.Room, + Room, ) - async def list_rooms( - self, list: proto_room.ListRoomsRequest - ) -> proto_room.ListRoomsResponse: + async def list_rooms(self, list: ListRoomsRequest) -> ListRoomsResponse: + """Lists active rooms. + + Args: + list (ListRoomsRequest): arg containing: + - names: list[str] - Optional list of room names to filter by + + Returns: + ListRoomsResponse: + - rooms: list[Room] - List of active Room objects + """ return await self._client.request( SVC, "ListRooms", list, self._auth_header(VideoGrants(room_list=True)), - proto_room.ListRoomsResponse, + ListRoomsResponse, ) - async def delete_room( - self, delete: proto_room.DeleteRoomRequest - ) -> proto_room.DeleteRoomResponse: + async def delete_room(self, delete: DeleteRoomRequest) -> DeleteRoomResponse: + """Deletes a room and disconnects all participants. + + Args: + delete (DeleteRoomRequest): arg containing: + - room: str - Name of room to delete + + Returns: + DeleteRoomResponse: Empty response object + """ return await self._client.request( SVC, "DeleteRoom", delete, self._auth_header(VideoGrants(room_create=True)), - proto_room.DeleteRoomResponse, + DeleteRoomResponse, ) - async def update_room_metadata( - self, update: proto_room.UpdateRoomMetadataRequest - ) -> proto_models.Room: + async def update_room_metadata(self, update: UpdateRoomMetadataRequest) -> Room: + """Updates a room's [metadata](https://docs.livekit.io/home/client/data/room-metadata/). + + Args: + update (UpdateRoomMetadataRequest): arg containing: + - room: str - Name of room to update + - metadata: str - New metadata to set + + Returns: + Room: Updated Room object + """ return await self._client.request( SVC, "UpdateRoomMetadata", update, self._auth_header(VideoGrants(room_admin=True, room=update.room)), - proto_models.Room, + Room, ) async def list_participants( - self, list: proto_room.ListParticipantsRequest - ) -> proto_room.ListParticipantsResponse: + self, list: ListParticipantsRequest + ) -> ListParticipantsResponse: + """Lists all participants in a room. + + Args: + list (ListParticipantsRequest): arg containing: + - room: str - Name of room to list participants from + + Returns: + ListParticipantsResponse: + - participants: list[ParticipantInfo] - List of participant details + """ return await self._client.request( SVC, "ListParticipants", list, self._auth_header(VideoGrants(room_admin=True, room=list.room)), - proto_room.ListParticipantsResponse, + ListParticipantsResponse, ) - async def get_participant( - self, get: proto_room.RoomParticipantIdentity - ) -> proto_models.ParticipantInfo: + async def get_participant(self, get: RoomParticipantIdentity) -> ParticipantInfo: + """Gets details about a specific participant. + + Args: + get (RoomParticipantIdentity): arg containing: + - room: str - Room name + - identity: str - Participant identity to look up + + Returns: + ParticipantInfo: + - sid: str - Participant session ID + - identity: str - Participant identity + - state: int - Connection state + - tracks: list[TrackInfo] - Published tracks + - metadata: str - Participant metadata + - joined_at: int - Join timestamp + - name: str - Display name + - version: int - Protocol version + - permission: ParticipantPermission - Granted permissions + - region: str - Connected region + """ return await self._client.request( SVC, "GetParticipant", get, self._auth_header(VideoGrants(room_admin=True, room=get.room)), - proto_models.ParticipantInfo, + ParticipantInfo, ) async def remove_participant( - self, remove: proto_room.RoomParticipantIdentity - ) -> proto_room.RemoveParticipantResponse: + self, remove: RoomParticipantIdentity + ) -> RemoveParticipantResponse: + """Removes a participant from a room. + + Args: + remove (RoomParticipantIdentity): arg containing: + - room: str - Room name + - identity: str - Identity of participant to remove + + Returns: + RemoveParticipantResponse: Empty response object + """ return await self._client.request( SVC, "RemoveParticipant", remove, self._auth_header(VideoGrants(room_admin=True, room=remove.room)), - proto_room.RemoveParticipantResponse, + RemoveParticipantResponse, ) async def mute_published_track( self, - update: proto_room.MuteRoomTrackRequest, - ) -> proto_room.MuteRoomTrackResponse: + update: MuteRoomTrackRequest, + ) -> MuteRoomTrackResponse: + """Mutes or unmutes a participant's published track. + + Args: + update (MuteRoomTrackRequest): arg containing: + - room: str - Room name + - identity: str - Participant identity + - track_sid: str - Track session ID to mute + - muted: bool - True to mute, False to unmute + + Returns: + MuteRoomTrackResponse containing: + - track: TrackInfo - Updated track information + """ return await self._client.request( SVC, "MutePublishedTrack", update, self._auth_header(VideoGrants(room_admin=True, room=update.room)), - proto_room.MuteRoomTrackResponse, + MuteRoomTrackResponse, ) async def update_participant( - self, update: proto_room.UpdateParticipantRequest - ) -> proto_models.ParticipantInfo: + self, update: UpdateParticipantRequest + ) -> ParticipantInfo: + """Updates a participant's metadata or permissions. + + Args: + update (UpdateParticipantRequest): arg containing: + - room: str - Room name + - identity: str - Participant identity + - metadata: str - New metadata + - permission: ParticipantPermission - New permissions + - name: str - New display name + - attributes: dict[str, str] - Key-value attributes + + Returns: + ParticipantInfo: Updated participant information + """ return await self._client.request( SVC, "UpdateParticipant", update, self._auth_header(VideoGrants(room_admin=True, room=update.room)), - proto_models.ParticipantInfo, + ParticipantInfo, ) async def update_subscriptions( - self, update: proto_room.UpdateSubscriptionsRequest - ) -> proto_room.UpdateSubscriptionsResponse: + self, update: UpdateSubscriptionsRequest + ) -> UpdateSubscriptionsResponse: + """Updates a participant's track subscriptions. + + Args: + update (UpdateSubscriptionsRequest): arg containing: + - room: str - Room name + - identity: str - Participant identity + - track_sids: list[str] - Track session IDs + - subscribe: bool - True to subscribe, False to unsubscribe + - participant_tracks: list[ParticipantTracks] - Participant track mappings + + Returns: + UpdateSubscriptionsResponse: Empty response object + """ return await self._client.request( SVC, "UpdateSubscriptions", update, self._auth_header(VideoGrants(room_admin=True, room=update.room)), - proto_room.UpdateSubscriptionsResponse, + UpdateSubscriptionsResponse, ) - async def send_data( - self, send: proto_room.SendDataRequest - ) -> proto_room.SendDataResponse: + async def send_data(self, send: SendDataRequest) -> SendDataResponse: + """Sends data to participants in a room. + + Args: + send (SendDataRequest): arg containing: + - room: str - Room name + - data: bytes - Data payload to send + - kind: DataPacket.Kind - RELIABLE or LOSSY delivery + - destination_identities: list[str] - Target participant identities + - topic: str - Optional topic for the message + + Returns: + SendDataResponse: Empty response object + """ return await self._client.request( SVC, "SendData", send, self._auth_header(VideoGrants(room_admin=True, room=send.room)), - proto_room.SendDataResponse, + SendDataResponse, ) diff --git a/livekit-api/livekit/api/sip_service.py b/livekit-api/livekit/api/sip_service.py index 6d3f122e..eee8bcff 100644 --- a/livekit-api/livekit/api/sip_service.py +++ b/livekit-api/livekit/api/sip_service.py @@ -1,141 +1,169 @@ import aiohttp -from livekit.protocol import sip as proto_sip +from livekit.protocol.sip import ( + CreateSIPTrunkRequest, + SIPTrunkInfo, + CreateSIPInboundTrunkRequest, + SIPInboundTrunkInfo, + CreateSIPOutboundTrunkRequest, + SIPOutboundTrunkInfo, + ListSIPTrunkRequest, + ListSIPTrunkResponse, + ListSIPInboundTrunkRequest, + ListSIPInboundTrunkResponse, + ListSIPOutboundTrunkRequest, + ListSIPOutboundTrunkResponse, + DeleteSIPTrunkRequest, + SIPDispatchRuleInfo, + CreateSIPDispatchRuleRequest, + ListSIPDispatchRuleRequest, + ListSIPDispatchRuleResponse, + DeleteSIPDispatchRuleRequest, + CreateSIPParticipantRequest, + TransferSIPParticipantRequest, + SIPParticipantInfo, +) from ._service import Service from .access_token import VideoGrants, SIPGrants SVC = "SIP" +"""@private""" class SipService(Service): + """Client for LiveKit SIP Service API + + Recommended way to use this service is via `livekit.api.LiveKitAPI`: + + ```python + from livekit import api + lkapi = api.LiveKitAPI() + sip_service = lkapi.sip + ``` + """ + def __init__( self, session: aiohttp.ClientSession, url: str, api_key: str, api_secret: str ): super().__init__(session, url, api_key, api_secret) - async def create_sip_trunk( - self, create: proto_sip.CreateSIPTrunkRequest - ) -> proto_sip.SIPTrunkInfo: + async def create_sip_trunk(self, create: CreateSIPTrunkRequest) -> SIPTrunkInfo: return await self._client.request( SVC, "CreateSIPTrunk", create, self._auth_header(VideoGrants(), sip=SIPGrants(admin=True)), - proto_sip.SIPTrunkInfo, + SIPTrunkInfo, ) async def create_sip_inbound_trunk( - self, create: proto_sip.CreateSIPInboundTrunkRequest - ) -> proto_sip.SIPInboundTrunkInfo: + self, create: CreateSIPInboundTrunkRequest + ) -> SIPInboundTrunkInfo: return await self._client.request( SVC, "CreateSIPInboundTrunk", create, self._auth_header(VideoGrants(), sip=SIPGrants(admin=True)), - proto_sip.SIPInboundTrunkInfo, + SIPInboundTrunkInfo, ) async def create_sip_outbound_trunk( - self, create: proto_sip.CreateSIPOutboundTrunkRequest - ) -> proto_sip.SIPOutboundTrunkInfo: + self, create: CreateSIPOutboundTrunkRequest + ) -> SIPOutboundTrunkInfo: return await self._client.request( SVC, "CreateSIPOutboundTrunk", create, self._auth_header(VideoGrants(), sip=SIPGrants(admin=True)), - proto_sip.SIPOutboundTrunkInfo, + SIPOutboundTrunkInfo, ) - async def list_sip_trunk( - self, list: proto_sip.ListSIPTrunkRequest - ) -> proto_sip.ListSIPTrunkResponse: + async def list_sip_trunk(self, list: ListSIPTrunkRequest) -> ListSIPTrunkResponse: return await self._client.request( SVC, "ListSIPTrunk", list, self._auth_header(VideoGrants(), sip=SIPGrants(admin=True)), - proto_sip.ListSIPTrunkResponse, + ListSIPTrunkResponse, ) async def list_sip_inbound_trunk( - self, list: proto_sip.ListSIPInboundTrunkRequest - ) -> proto_sip.ListSIPInboundTrunkResponse: + self, list: ListSIPInboundTrunkRequest + ) -> ListSIPInboundTrunkResponse: return await self._client.request( SVC, "ListSIPInboundTrunk", list, self._auth_header(VideoGrants(), sip=SIPGrants(admin=True)), - proto_sip.ListSIPInboundTrunkResponse, + ListSIPInboundTrunkResponse, ) async def list_sip_outbound_trunk( - self, list: proto_sip.ListSIPOutboundTrunkRequest - ) -> proto_sip.ListSIPOutboundTrunkResponse: + self, list: ListSIPOutboundTrunkRequest + ) -> ListSIPOutboundTrunkResponse: return await self._client.request( SVC, "ListSIPOutboundTrunk", list, self._auth_header(VideoGrants(), sip=SIPGrants(admin=True)), - proto_sip.ListSIPOutboundTrunkResponse, + ListSIPOutboundTrunkResponse, ) - async def delete_sip_trunk( - self, delete: proto_sip.DeleteSIPTrunkRequest - ) -> proto_sip.SIPTrunkInfo: + async def delete_sip_trunk(self, delete: DeleteSIPTrunkRequest) -> SIPTrunkInfo: return await self._client.request( SVC, "DeleteSIPTrunk", delete, self._auth_header(VideoGrants(), sip=SIPGrants(admin=True)), - proto_sip.SIPTrunkInfo, + SIPTrunkInfo, ) async def create_sip_dispatch_rule( - self, create: proto_sip.CreateSIPDispatchRuleRequest - ) -> proto_sip.SIPDispatchRuleInfo: + self, create: CreateSIPDispatchRuleRequest + ) -> SIPDispatchRuleInfo: return await self._client.request( SVC, "CreateSIPDispatchRule", create, self._auth_header(VideoGrants(), sip=SIPGrants(admin=True)), - proto_sip.SIPDispatchRuleInfo, + SIPDispatchRuleInfo, ) async def list_sip_dispatch_rule( - self, list: proto_sip.ListSIPDispatchRuleRequest - ) -> proto_sip.ListSIPDispatchRuleResponse: + self, list: ListSIPDispatchRuleRequest + ) -> ListSIPDispatchRuleResponse: return await self._client.request( SVC, "ListSIPDispatchRule", list, self._auth_header(VideoGrants(), sip=SIPGrants(admin=True)), - proto_sip.ListSIPDispatchRuleResponse, + ListSIPDispatchRuleResponse, ) async def delete_sip_dispatch_rule( - self, delete: proto_sip.DeleteSIPDispatchRuleRequest - ) -> proto_sip.SIPDispatchRuleInfo: + self, delete: DeleteSIPDispatchRuleRequest + ) -> SIPDispatchRuleInfo: return await self._client.request( SVC, "DeleteSIPDispatchRule", delete, self._auth_header(VideoGrants(), sip=SIPGrants(admin=True)), - proto_sip.SIPDispatchRuleInfo, + SIPDispatchRuleInfo, ) async def create_sip_participant( - self, create: proto_sip.CreateSIPParticipantRequest - ) -> proto_sip.SIPParticipantInfo: + self, create: CreateSIPParticipantRequest + ) -> SIPParticipantInfo: return await self._client.request( SVC, "CreateSIPParticipant", create, self._auth_header(VideoGrants(), sip=SIPGrants(call=True)), - proto_sip.SIPParticipantInfo, + SIPParticipantInfo, ) async def transfer_sip_participant( - self, transfer: proto_sip.TransferSIPParticipantRequest - ) -> proto_sip.SIPParticipantInfo: + self, transfer: TransferSIPParticipantRequest + ) -> SIPParticipantInfo: return await self._client.request( SVC, "TransferSIPParticipant", @@ -147,5 +175,5 @@ async def transfer_sip_participant( ), sip=SIPGrants(call=True), ), - proto_sip.SIPParticipantInfo, + SIPParticipantInfo, ) diff --git a/livekit-api/livekit/api/webhook.py b/livekit-api/livekit/api/webhook.py index 5dedf048..9f500637 100644 --- a/livekit-api/livekit/api/webhook.py +++ b/livekit-api/livekit/api/webhook.py @@ -1,5 +1,5 @@ from .access_token import TokenVerifier -from livekit.protocol import webhook as proto_webhook +from livekit.protocol.webhook import WebhookEvent from google.protobuf.json_format import Parse import hashlib import base64 @@ -9,7 +9,7 @@ class WebhookReceiver: def __init__(self, token_verifier: TokenVerifier): self._verifier = token_verifier - def receive(self, body: str, auth_token: str) -> proto_webhook.WebhookEvent: + def receive(self, body: str, auth_token: str) -> WebhookEvent: claims = self._verifier.verify(auth_token) if claims.sha256 is None: raise Exception("sha256 was not found in the token") @@ -20,4 +20,4 @@ def receive(self, body: str, auth_token: str) -> proto_webhook.WebhookEvent: if body_hash != claims_hash: raise Exception("hash mismatch") - return Parse(body, proto_webhook.WebhookEvent(), ignore_unknown_fields=True) + return Parse(body, WebhookEvent(), ignore_unknown_fields=True)