Packages

An Elixir client for LiveKit, providing tools for interacting with LiveKit servers, including access token generation, room management, and webhook verification.

Current section

Files

Jump to
livekitex lib livekitex room_service.ex
Raw

lib/livekitex/room_service.ex

defmodule Livekitex.RoomService do
@behaviour Livekitex.RoomServiceBehaviour
@moduledoc """
Provides functionality to interact with the LiveKit RoomService API using Twirp.
"""
alias Livekitex.AccessToken
alias Livekitex.Grants
alias Livekitex.TwirpUtils
alias Livekitex.RoomServiceClient
require Logger
defstruct api_key: nil,
api_secret: nil,
host: "localhost",
port: 7880,
client: nil
@type t :: %__MODULE__{
api_key: String.t(),
api_secret: String.t(),
host: String.t(),
port: integer(),
client: Tesla.Client.t() | nil
}
@doc """
Creates a new RoomService client.
## Parameters
- `api_key`: The API key for your LiveKit project.
- `api_secret`: The API secret for your LiveKit project.
- `options`: A keyword list of options.
- `host`: The host of the LiveKit server. Defaults to "localhost".
- `port`: The port of the LiveKit server. Defaults to 7880.
## Examples
iex> Livekitex.RoomService.create("api_key", "api_secret")
%Livekitex.RoomService{
api_key: "api_key",
api_secret: "api_secret",
host: "localhost",
port: 7880
}
"""
def create(api_key, api_secret, options \\ []) do
%__MODULE__{
api_key: api_key,
api_secret: api_secret,
host: Keyword.get(options, :host, "localhost"),
port: Keyword.get(options, :port, 7880)
}
end
@doc """
Creates a new room.
## Parameters
- `room_service`: The RoomService client.
- `name`: The name of the room.
- `options`: A keyword list of options.
- `empty_timeout`: Room timeout when empty (seconds)
- `departure_timeout`: Timeout after participant departure (seconds)
- `max_participants`: Maximum number of participants
- `metadata`: Room metadata
- `min_playout_delay`: Minimum playout delay (ms)
- `max_playout_delay`: Maximum playout delay (ms)
- `sync_streams`: Whether to sync streams
## Examples
iex> room_service = Livekitex.RoomService.create("devkey", "secret")
iex> Livekitex.RoomService.create_room(room_service, "test-room")
{:ok, %Livekitex.Room{}}
"""
def create_room(%__MODULE__{} = room_service, name, options \\ []) do
with {:ok, client} <- ensure_client(room_service),
{:ok, token} <- create_room_token(room_service),
request <- build_create_room_request(name, options) do
case RoomServiceClient.create_room(client, request, token) do
{:ok, proto_room} ->
{:ok, TwirpUtils.proto_to_room(proto_room)}
error ->
TwirpUtils.handle_twirp_response(error)
end
end
end
@doc """
Deletes a room.
## Parameters
- `room_service`: The RoomService client.
- `room_name`: The name of the room to delete.
## Examples
iex> room_service = Livekitex.RoomService.create("devkey", "secret")
iex> Livekitex.RoomService.delete_room(room_service, "test-room")
:ok
"""
def delete_room(%__MODULE__{} = room_service, room_name) do
with {:ok, client} <- ensure_client(room_service),
{:ok, token} <- create_room_token(room_service),
request <- %Livekit.DeleteRoomRequest{room: room_name} do
case RoomServiceClient.delete_room(client, request, token) do
{:ok, _response} -> :ok
error -> TwirpUtils.handle_twirp_response(error)
end
end
end
@doc """
Lists all rooms.
## Parameters
- `room_service`: The RoomService client.
- `options`: A keyword list of options.
- `names`: List of specific room names to filter by
## Examples
iex> room_service = Livekitex.RoomService.create("devkey", "secret")
iex> Livekitex.RoomService.list_rooms(room_service)
{:ok, []}
"""
def list_rooms(%__MODULE__{} = room_service, options \\ []) do
with {:ok, client} <- ensure_client(room_service),
{:ok, token} <- create_room_list_token(room_service),
request <- %Livekit.ListRoomsRequest{names: Keyword.get(options, :names, [])} do
case RoomServiceClient.list_rooms(client, request, token) do
{:ok, %Livekit.ListRoomsResponse{rooms: rooms}} ->
{:ok, Enum.map(rooms, &TwirpUtils.proto_to_room/1)}
error ->
TwirpUtils.handle_twirp_response(error)
end
end
end
@doc """
Lists participants in a room.
## Parameters
- `room_service`: The RoomService client.
- `room_name`: The name of the room.
## Examples
iex> room_service = Livekitex.RoomService.create("devkey", "secret")
iex> Livekitex.RoomService.list_participants(room_service, "test-room")
{:ok, []}
"""
def list_participants(%__MODULE__{} = room_service, room_name) do
with {:ok, client} <- ensure_client(room_service),
{:ok, token} <- create_room_admin_token(room_service, room_name),
request <- %Livekit.ListParticipantsRequest{room: room_name} do
case RoomServiceClient.list_participants(client, request, token) do
{:ok, %Livekit.ListParticipantsResponse{participants: participants}} ->
{:ok, Enum.map(participants, &TwirpUtils.proto_to_participant/1)}
error ->
TwirpUtils.handle_twirp_response(error)
end
end
end
@doc """
Removes a participant from a room.
## Parameters
- `room_service`: The RoomService client.
- `room_name`: The name of the room.
- `identity`: The identity of the participant to remove.
## Examples
iex> room_service = Livekitex.RoomService.create("devkey", "secret")
iex> Livekitex.RoomService.remove_participant(room_service, "test-room", "user123")
:ok
"""
def remove_participant(%__MODULE__{} = room_service, room_name, identity) do
with {:ok, client} <- ensure_client(room_service),
{:ok, token} <- create_room_admin_token(room_service, room_name),
request <- %Livekit.RoomParticipantIdentity{room: room_name, identity: identity} do
case RoomServiceClient.remove_participant(client, request, token) do
{:ok, _response} -> :ok
error -> TwirpUtils.handle_twirp_response(error)
end
end
end
@doc """
Mutes or unmutes a published track.
## Parameters
- `room_service`: The RoomService client.
- `room_name`: The name of the room.
- `identity`: The identity of the participant.
- `track_sid`: The SID of the track to mute/unmute.
- `muted`: Whether to mute (true) or unmute (false) the track.
## Examples
iex> room_service = Livekitex.RoomService.create("devkey", "secret")
iex> Livekitex.RoomService.mute_published_track(room_service, "test-room", "user123", "track_sid", true)
{:ok, %{}}
"""
def mute_published_track(%__MODULE__{} = room_service, room_name, identity, track_sid, muted) do
with {:ok, client} <- ensure_client(room_service),
{:ok, token} <- create_room_admin_token(room_service, room_name),
request <- %Livekit.MuteRoomTrackRequest{
room: room_name,
identity: identity,
track_sid: track_sid,
muted: muted
} do
case RoomServiceClient.mute_published_track(client, request, token) do
{:ok, %Livekit.MuteRoomTrackResponse{track: track}} ->
{:ok, TwirpUtils.proto_to_track(track)}
error ->
TwirpUtils.handle_twirp_response(error)
end
end
end
# Private helper functions
defp ensure_client(%__MODULE__{client: nil} = room_service) do
base_url = "http://#{room_service.host}:#{room_service.port}"
client = TwirpUtils.create_client(base_url)
{:ok, client}
end
defp ensure_client(%__MODULE__{client: client}), do: {:ok, client}
defp create_room_token(%__MODULE__{api_key: api_key, api_secret: api_secret}) do
video_grant = %Grants.VideoGrant{room_create: true}
grants = %Grants.ClaimGrant{video: video_grant}
api_key
|> AccessToken.create(api_secret, grants: grants)
|> AccessToken.set_video_grant(video_grant)
|> AccessToken.to_jwt()
|> case do
{:ok, jwt, _claims} -> {:ok, jwt}
error -> error
end
end
defp create_room_list_token(%__MODULE__{api_key: api_key, api_secret: api_secret}) do
video_grant = %Grants.VideoGrant{room_list: true}
grants = %Grants.ClaimGrant{video: video_grant}
api_key
|> AccessToken.create(api_secret, grants: grants)
|> AccessToken.set_video_grant(video_grant)
|> AccessToken.to_jwt()
|> case do
{:ok, jwt, _claims} -> {:ok, jwt}
error -> error
end
end
defp create_room_admin_token(%__MODULE__{api_key: api_key, api_secret: api_secret}, room_name) do
video_grant = %Grants.VideoGrant{room_admin: true, room: room_name}
grants = %Grants.ClaimGrant{video: video_grant}
api_key
|> AccessToken.create(api_secret, grants: grants)
|> AccessToken.set_video_grant(video_grant)
|> AccessToken.to_jwt()
|> case do
{:ok, jwt, _claims} -> {:ok, jwt}
error -> error
end
end
defp build_create_room_request(name, options) do
%Livekit.CreateRoomRequest{
name: name,
empty_timeout: Keyword.get(options, :empty_timeout),
departure_timeout: Keyword.get(options, :departure_timeout),
max_participants: Keyword.get(options, :max_participants),
metadata: Keyword.get(options, :metadata),
min_playout_delay: Keyword.get(options, :min_playout_delay),
max_playout_delay: Keyword.get(options, :max_playout_delay),
sync_streams: Keyword.get(options, :sync_streams)
}
end
end