.gitmodules 🔗
@@ -1,3 +0,0 @@
-[submodule "crates/live_kit_server/protocol"]
- path = crates/live_kit_server/protocol
- url = https://github.com/livekit/protocol
Marshall Bowers created
This PR vendors the protobuf files from the LiveKit protocol so that we
don't need to have that entire LiveKit protocol repo as a submodule.
---
Eventually I would like to replace this with the
[`livekit-protocol`](https://crates.io/crates/livekit-protocol) crate,
but there is some churn that needs to happen for that.
The main problem is that we're currently on a different version of
`prost` used by `livekit-protocol`, and upgrading our version of `prost`
means that we now need to source `protoc` ourselves (since it is no
longer available to be compiled from source as part of `prost-build`).
Release Notes:
- N/A
.gitmodules | 3
crates/live_kit_server/build.rs | 5
crates/live_kit_server/protocol | 1
crates/live_kit_server/vendored/protocol/README.md | 5
crates/live_kit_server/vendored/protocol/livekit_analytics.proto | 118
crates/live_kit_server/vendored/protocol/livekit_egress.proto | 263
crates/live_kit_server/vendored/protocol/livekit_ingress.proto | 134
crates/live_kit_server/vendored/protocol/livekit_internal.proto | 138
crates/live_kit_server/vendored/protocol/livekit_models.proto | 330
crates/live_kit_server/vendored/protocol/livekit_room.proto | 159
crates/live_kit_server/vendored/protocol/livekit_rpc_internal.proto | 83
crates/live_kit_server/vendored/protocol/livekit_rtc.proto | 301
crates/live_kit_server/vendored/protocol/livekit_webhook.proto | 36
13 files changed, 1,571 insertions(+), 5 deletions(-)
@@ -1,3 +0,0 @@
-[submodule "crates/live_kit_server/protocol"]
- path = crates/live_kit_server/protocol
- url = https://github.com/livekit/protocol
@@ -1,6 +1,9 @@
fn main() {
prost_build::Config::new()
.type_attribute("SendDataResponse", "#[allow(clippy::empty_docs)]")
- .compile_protos(&["protocol/livekit_room.proto"], &["protocol"])
+ .compile_protos(
+ &["vendored/protocol/livekit_room.proto"],
+ &["vendored/protocol"],
+ )
.unwrap();
}
@@ -1 +0,0 @@
-Subproject commit 8645a138fb2ea72c4dab13e739b1f3c9ea29ac84
@@ -0,0 +1,5 @@
+# LiveKit Protocol
+
+This is a vendored copy of the [LiveKit protocol](https://github.com/livekit/protocol).
+
+Vendored at [`8645a138fb2ea72c4dab13e739b1f3c9ea29ac84`](https://github.com/livekit/protocol/tree/8645a138fb2ea72c4dab13e739b1f3c9ea29ac84).
@@ -0,0 +1,118 @@
+syntax = "proto3";
+
+package livekit;
+option go_package = "github.com/livekit/protocol/livekit";
+option csharp_namespace = "LiveKit.Proto";
+option ruby_package = "LiveKit::Proto";
+
+import "google/protobuf/empty.proto";
+import "google/protobuf/timestamp.proto";
+import "livekit_models.proto";
+import "livekit_egress.proto";
+import "livekit_ingress.proto";
+
+service AnalyticsRecorderService {
+ rpc IngestStats(stream AnalyticsStats) returns (google.protobuf.Empty){};
+ rpc IngestEvents(stream AnalyticsEvents) returns (google.protobuf.Empty){};
+}
+
+enum StreamType {
+ UPSTREAM = 0;
+ DOWNSTREAM = 1;
+}
+
+message AnalyticsVideoLayer {
+ int32 layer = 1;
+ uint32 packets = 2;
+ uint64 bytes = 3;
+ uint32 frames = 4;
+}
+
+message AnalyticsStream {
+ uint32 ssrc = 1;
+ uint32 primary_packets = 2;
+ uint64 primary_bytes = 3;
+ uint32 retransmit_packets = 4;
+ uint64 retransmit_bytes = 5;
+ uint32 padding_packets = 6;
+ uint64 padding_bytes = 7;
+ uint32 packets_lost = 8;
+ uint32 frames = 9;
+ uint32 rtt = 10;
+ uint32 jitter = 11;
+ uint32 nacks = 12;
+ uint32 plis = 13;
+ uint32 firs = 14;
+ repeated AnalyticsVideoLayer video_layers = 15;
+}
+
+message AnalyticsStat {
+ string analytics_key = 1;
+ StreamType kind = 2;
+ google.protobuf.Timestamp time_stamp = 3;
+ string node = 4;
+ string room_id = 5;
+ string room_name = 6;
+ string participant_id = 7;
+ string track_id = 8;
+ float score = 9;
+ repeated AnalyticsStream streams = 10;
+ string mime = 11;
+}
+
+message AnalyticsStats {
+ repeated AnalyticsStat stats = 1;
+}
+
+enum AnalyticsEventType {
+ ROOM_CREATED = 0;
+ ROOM_ENDED = 1;
+ PARTICIPANT_JOINED = 2;
+ PARTICIPANT_LEFT = 3;
+ TRACK_PUBLISHED = 4;
+ TRACK_UNPUBLISHED = 5;
+ TRACK_SUBSCRIBED = 6;
+ TRACK_UNSUBSCRIBED = 7;
+ TRACK_PUBLISHED_UPDATE = 10;
+ PARTICIPANT_ACTIVE = 11;
+ EGRESS_STARTED = 12;
+ EGRESS_ENDED = 13;
+ TRACK_MAX_SUBSCRIBED_VIDEO_QUALITY = 14;
+ RECONNECTED = 15;
+ INGRESS_STARTED = 16;
+ INGRESS_ENDED = 17;
+}
+
+message AnalyticsClientMeta {
+ string region = 1;
+ string node = 2;
+ string client_addr = 3;
+ uint32 client_connect_time = 4;
+ // udp, tcp, turn
+ string connection_type = 5;
+}
+
+message AnalyticsEvent {
+ AnalyticsEventType type = 1;
+ google.protobuf.Timestamp timestamp = 2;
+ string room_id = 3;
+ Room room = 4;
+ string participant_id = 5;
+ ParticipantInfo participant = 6;
+ string track_id = 7;
+ TrackInfo track = 8;
+ string analytics_key = 10;
+ ClientInfo client_info = 11;
+ AnalyticsClientMeta client_meta = 12;
+ string egress_id = 13;
+ VideoQuality max_subscribed_video_quality = 14;
+ ParticipantInfo publisher = 15;
+ string mime = 16;
+ EgressInfo egress = 17;
+ IngressInfo ingress = 18;
+
+}
+
+message AnalyticsEvents {
+ repeated AnalyticsEvent events = 1;
+}
@@ -0,0 +1,263 @@
+syntax = "proto3";
+
+package livekit;
+option go_package = "github.com/livekit/protocol/livekit";
+option csharp_namespace = "LiveKit.Proto";
+option ruby_package = "LiveKit::Proto";
+
+service Egress {
+ // start recording or streaming a room, participant, or tracks
+ rpc StartRoomCompositeEgress(RoomCompositeEgressRequest) returns (EgressInfo);
+ rpc StartTrackCompositeEgress(TrackCompositeEgressRequest) returns (EgressInfo);
+ rpc StartTrackEgress(TrackEgressRequest) returns (EgressInfo);
+
+ // update web composite layout
+ rpc UpdateLayout(UpdateLayoutRequest) returns (EgressInfo);
+
+ // add or remove stream endpoints
+ rpc UpdateStream(UpdateStreamRequest) returns (EgressInfo);
+
+ // list available egress
+ rpc ListEgress(ListEgressRequest) returns (ListEgressResponse);
+
+ // stop a recording or stream
+ rpc StopEgress(StopEgressRequest) returns (EgressInfo);
+}
+
+// composite using a web browser
+message RoomCompositeEgressRequest {
+ string room_name = 1; // required
+ string layout = 2; // (optional)
+ bool audio_only = 3; // (default false)
+ bool video_only = 4; // (default false)
+ string custom_base_url = 5; // (default https://recorder.livekit.io)
+ oneof output { // required
+ EncodedFileOutput file = 6;
+ StreamOutput stream = 7;
+ SegmentedFileOutput segments = 10;
+ }
+ oneof options {
+ EncodingOptionsPreset preset = 8; // (default H264_720P_30)
+ EncodingOptions advanced = 9; // (optional)
+ }
+}
+
+// containerize up to one audio and one video track
+message TrackCompositeEgressRequest {
+ string room_name = 1; // required
+ string audio_track_id = 2; // (optional)
+ string video_track_id = 3; // (optional)
+ oneof output { // required
+ EncodedFileOutput file = 4;
+ StreamOutput stream = 5;
+ SegmentedFileOutput segments = 8;
+ }
+ oneof options {
+ EncodingOptionsPreset preset = 6; // (default H264_720P_30)
+ EncodingOptions advanced = 7; // (optional)
+ }
+}
+
+// record tracks individually, without transcoding
+message TrackEgressRequest {
+ string room_name = 1; // required
+ string track_id = 2; // required
+ oneof output { // required
+ DirectFileOutput file = 3;
+ string websocket_url = 4;
+ }
+}
+
+enum EncodedFileType {
+ DEFAULT_FILETYPE = 0; // file type chosen based on codecs
+ MP4 = 1;
+ OGG = 2;
+}
+
+message EncodedFileOutput {
+ EncodedFileType file_type = 1; // (optional)
+ string filepath = 2; // (optional)
+ oneof output { // required
+ S3Upload s3 = 3;
+ GCPUpload gcp = 4;
+ AzureBlobUpload azure = 5;
+ }
+}
+
+// Used to generate HLS segments or other kind of segmented output
+message SegmentedFileOutput {
+ SegmentedFileProtocol protocol = 1; // (optional)
+ string filename_prefix = 2; // (optional)
+ string playlist_name = 3; // (optional)
+ uint32 segment_duration = 4; // (optional)
+ oneof output { // required
+ S3Upload s3 = 5;
+ GCPUpload gcp = 6;
+ AzureBlobUpload azure = 7;
+ }
+}
+
+message DirectFileOutput {
+ string filepath = 1; // (optional)
+ oneof output { // required
+ S3Upload s3 = 2;
+ GCPUpload gcp = 3;
+ AzureBlobUpload azure = 4;
+ }
+}
+
+message S3Upload {
+ string access_key = 1;
+ string secret = 2;
+ string region = 3;
+ string endpoint = 4;
+ string bucket = 5;
+}
+
+message GCPUpload {
+ bytes credentials = 1;
+ string bucket = 2;
+}
+
+message AzureBlobUpload {
+ string account_name = 1;
+ string account_key = 2;
+ string container_name = 3;
+}
+
+enum StreamProtocol {
+ DEFAULT_PROTOCOL = 0; // protocol chosen based on urls
+ RTMP = 1;
+}
+
+enum SegmentedFileProtocol {
+ DEFAULT_SEGMENTED_FILE_PROTOCOL = 0;
+ HLS_PROTOCOL = 1;
+}
+
+message StreamOutput {
+ StreamProtocol protocol = 1; // required
+ repeated string urls = 2; // required
+}
+
+enum AudioCodec {
+ DEFAULT_AC = 0;
+ OPUS = 1;
+ AAC = 2;
+}
+
+enum VideoCodec {
+ DEFAULT_VC = 0;
+ H264_BASELINE = 1;
+ H264_MAIN = 2;
+ H264_HIGH = 3;
+}
+
+message EncodingOptions {
+ int32 width = 1; // (default 1920)
+ int32 height = 2; // (default 1080)
+ int32 depth = 3; // (default 24)
+ int32 framerate = 4; // (default 30)
+ AudioCodec audio_codec = 5; // (default OPUS)
+ int32 audio_bitrate = 6; // (default 128)
+ int32 audio_frequency = 7; // (default 44100)
+ VideoCodec video_codec = 8; // (default H264_MAIN)
+ int32 video_bitrate = 9; // (default 4500)
+}
+
+enum EncodingOptionsPreset {
+ H264_720P_30 = 0; // 1280x720, 30fps, 3000kpbs, H.264_MAIN / OPUS
+ H264_720P_60 = 1; // 1280x720, 60fps, 4500kbps, H.264_MAIN / OPUS
+ H264_1080P_30 = 2; // 1920x1080, 30fps, 4500kbps, H.264_MAIN / OPUS
+ H264_1080P_60 = 3; // 1920x1080, 60fps, 6000kbps, H.264_MAIN / OPUS
+ PORTRAIT_H264_720P_30 = 4; // 720x1280, 30fps, 3000kpbs, H.264_MAIN / OPUS
+ PORTRAIT_H264_720P_60 = 5; // 720x1280, 60fps, 4500kbps, H.264_MAIN / OPUS
+ PORTRAIT_H264_1080P_30 = 6; // 1080x1920, 30fps, 4500kbps, H.264_MAIN / OPUS
+ PORTRAIT_H264_1080P_60 = 7; // 1080x1920, 60fps, 6000kbps, H.264_MAIN / OPUS
+}
+
+message UpdateLayoutRequest {
+ string egress_id = 1;
+ string layout = 2;
+}
+
+message UpdateStreamRequest {
+ string egress_id = 1;
+ repeated string add_output_urls = 2;
+ repeated string remove_output_urls = 3;
+}
+
+message ListEgressRequest {
+ string room_name = 1; // (optional, used to filter results)
+}
+
+message ListEgressResponse {
+ repeated EgressInfo items = 1;
+}
+
+message StopEgressRequest {
+ string egress_id = 1;
+}
+
+enum EgressStatus {
+ EGRESS_STARTING = 0;
+ EGRESS_ACTIVE = 1;
+ EGRESS_ENDING = 2;
+ EGRESS_COMPLETE = 3;
+ EGRESS_FAILED = 4;
+ EGRESS_ABORTED = 5;
+ EGRESS_LIMIT_REACHED = 6;
+}
+
+message EgressInfo {
+ string egress_id = 1;
+ string room_id = 2;
+ string room_name = 13;
+ EgressStatus status = 3;
+ int64 started_at = 10;
+ int64 ended_at = 11;
+ string error = 9;
+ oneof request {
+ RoomCompositeEgressRequest room_composite = 4;
+ TrackCompositeEgressRequest track_composite = 5;
+ TrackEgressRequest track = 6;
+ }
+ oneof result {
+ StreamInfoList stream = 7;
+ FileInfo file = 8;
+ SegmentsInfo segments = 12;
+ }
+}
+
+message StreamInfoList {
+ repeated StreamInfo info = 1;
+}
+
+message StreamInfo {
+ enum Status {
+ ACTIVE = 0;
+ FINISHED = 1;
+ FAILED = 2;
+ }
+
+ string url = 1;
+ int64 started_at = 2;
+ int64 ended_at = 3;
+ int64 duration = 4;
+ Status status = 5;
+}
+
+message FileInfo {
+ string filename = 1;
+ int64 duration = 6;
+ int64 size = 4;
+ string location = 5;
+}
+
+message SegmentsInfo {
+ string playlist_name = 1;
+ int64 duration = 2;
+ int64 size = 3;
+ string playlist_location = 4;
+ int64 segment_count = 5;
+}
@@ -0,0 +1,134 @@
+syntax = "proto3";
+
+package livekit;
+
+import "livekit_models.proto";
+
+option go_package = "github.com/livekit/protocol/livekit";
+option csharp_namespace = "LiveKit.Proto";
+option ruby_package = "LiveKit::Proto";
+
+service Ingress {
+ // Create a new Ingress
+ rpc CreateIngress(CreateIngressRequest) returns (IngressInfo);
+ // Update an existing Ingress. Ingress can only be updated when it's in ENDPOINT_WAITING state.
+ rpc UpdateIngress(UpdateIngressRequest) returns (IngressInfo);
+ rpc ListIngress(ListIngressRequest) returns (ListIngressResponse);
+ rpc DeleteIngress(DeleteIngressRequest) returns (IngressInfo);
+}
+
+message CreateIngressRequest {
+ IngressInput input_type = 1;
+ // User provided identifier for the ingress
+ string name = 2;
+ // room to publish to
+ string room_name = 3;
+ // publish as participant
+ string participant_identity = 4;
+ // name of publishing participant (used for display only)
+ string participant_name = 5;
+ IngressAudioOptions audio = 6;
+ IngressVideoOptions video = 7;
+}
+
+enum IngressInput {
+ RTMP_INPUT = 0;
+ // FILE_INPUT = 1;
+ // SRT_INPUT = 2;
+ // URL_INPUT = 3;
+}
+
+message IngressAudioOptions {
+ string name = 1;
+ TrackSource source = 2;
+ // desired mime_type to publish to room
+ string mime_type = 3;
+ uint32 bitrate = 4;
+ bool disable_dtx = 5;
+ uint32 channels = 6;
+}
+
+message IngressVideoOptions {
+ string name = 1;
+ TrackSource source = 2;
+ // desired mime_type to publish to room
+ string mime_type = 3;
+ // simulcast layers to publish, when empty, it'll pick default simulcast
+ // layers at 1/2 and 1/4 of the dimensions
+ repeated VideoLayer layers = 4;
+}
+
+message IngressInfo {
+ string ingress_id = 1;
+ string name = 2;
+ string stream_key = 3;
+ string url = 4;
+ // for RTMP input, it'll be a rtmp:// URL
+ // for FILE input, it'll be a http:// URL
+ // for SRT input, it'll be a srt:// URL
+ IngressInput input_type = 5;
+ IngressAudioOptions audio = 6;
+ IngressVideoOptions video = 7;
+ string room_name = 8;
+ string participant_identity = 9;
+ string participant_name = 10;
+ bool reusable = 11;
+ IngressState state = 12; // Description of error/stream non compliance and debug info for publisher otherwise (received bitrate, resolution, bandwidth)
+
+ // NEXT_ID: 13
+}
+
+message IngressState {
+ enum Status {
+ ENDPOINT_INACTIVE = 0;
+ ENDPOINT_BUFFERING = 1;
+ ENDPOINT_PUBLISHING = 2;
+ ENDPOINT_ERROR = 3;
+ }
+
+ Status status = 1;
+ string error = 2; // Error/non compliance description if any
+ InputVideoState video = 3;
+ InputAudioState audio = 4;
+ string room_id = 5; // ID of the current/previous room published to
+ int64 started_at = 7;
+ repeated TrackInfo tracks = 6;
+}
+
+message InputVideoState {
+ uint32 mime_type = 1;
+// uint32 bitrate = 2;
+ uint32 width = 3;
+ uint32 height = 4;
+ uint32 framerate = 5;
+}
+
+message InputAudioState {
+ uint32 mime_type = 1;
+// uint32 bitrate = 2;
+ uint32 channels = 3;
+ uint32 sample_rate = 4;
+}
+
+message UpdateIngressRequest {
+ string ingress_id = 1;
+ string name = 2;
+ string room_name = 3;
+ string participant_identity = 4;
+ string participant_name = 5;
+ IngressAudioOptions audio = 6;
+ IngressVideoOptions video = 7;
+}
+
+message ListIngressRequest {
+ // when blank, lists all ingress endpoints
+ string room_name = 1;
+}
+
+message ListIngressResponse {
+ repeated IngressInfo items = 1;
+}
+
+message DeleteIngressRequest {
+ string ingress_id = 1;
+}
@@ -0,0 +1,138 @@
+syntax = "proto3";
+
+package livekit;
+option go_package = "github.com/livekit/protocol/livekit";
+option csharp_namespace = "LiveKit.Proto";
+option ruby_package = "LiveKit::Proto";
+
+// internal protos, not exposed to clients
+import "livekit_models.proto";
+import "livekit_rtc.proto";
+import "livekit_room.proto";
+
+enum NodeType {
+ SERVER = 0;
+ CONTROLLER = 1;
+ MEDIA = 2;
+ TURN = 4;
+}
+
+enum NodeState {
+ STARTING_UP = 0;
+ SERVING = 1;
+ SHUTTING_DOWN = 2;
+}
+
+message Node {
+ string id = 1;
+ string ip = 2;
+ uint32 num_cpus = 3;
+ NodeStats stats = 4;
+ NodeType type = 5;
+ NodeState state = 6;
+ string region = 7;
+}
+
+message NodeStats {
+ // when server was started
+ int64 started_at = 1;
+ // when server last reported its status
+ int64 updated_at = 2;
+
+ // room
+ int32 num_rooms = 3;
+ int32 num_clients = 4;
+ int32 num_tracks_in = 5;
+ int32 num_tracks_out = 6;
+
+ // packet
+ uint64 bytes_in = 7;
+ uint64 bytes_out = 8;
+ uint64 packets_in = 9;
+ uint64 packets_out = 10;
+ uint64 nack_total = 11;
+ float bytes_in_per_sec = 12;
+ float bytes_out_per_sec = 13;
+ float packets_in_per_sec = 14;
+ float packets_out_per_sec = 15;
+ float nack_per_sec = 16;
+
+ // system
+ uint32 num_cpus = 17;
+ float load_avg_last1min = 18;
+ float load_avg_last5min = 19;
+ float load_avg_last15min = 20;
+ float cpu_load = 21;
+ uint32 sys_packets_out = 28;
+ uint32 sys_packets_dropped = 29;
+ float sys_packets_out_per_sec = 30;
+ float sys_packets_dropped_per_sec = 31;
+ float sys_packets_dropped_pct_per_sec = 32;
+
+ // retransmissions
+ uint64 retransmit_bytes_out = 22;
+ uint64 retransmit_packets_out = 23;
+ float retransmit_bytes_out_per_sec = 24;
+ float retransmit_packets_out_per_sec = 25;
+
+ // participant joins
+ uint64 participant_join = 26;
+ float participant_join_per_sec = 27;
+}
+
+// message to RTC nodes
+message RTCNodeMessage {
+ string participant_key = 1;
+ int64 sender_time = 11;
+ string connection_id = 13;
+ oneof message {
+ StartSession start_session = 2;
+ SignalRequest request = 3;
+ // internal messages
+ RoomParticipantIdentity remove_participant = 4;
+ MuteRoomTrackRequest mute_track = 5;
+ UpdateParticipantRequest update_participant = 6;
+ DeleteRoomRequest delete_room = 7;
+ UpdateSubscriptionsRequest update_subscriptions = 8;
+ SendDataRequest send_data = 9;
+ UpdateRoomMetadataRequest update_room_metadata = 10;
+ KeepAlive keep_alive = 12;
+ }
+}
+
+// message to Signal nodes
+message SignalNodeMessage {
+ string connection_id = 1;
+ oneof message {
+ SignalResponse response = 2;
+ EndSession end_session = 3;
+ }
+}
+
+message StartSession {
+ string room_name = 1;
+ string identity = 2;
+ string connection_id = 3;
+ // if a client is reconnecting (i.e. resume instead of restart)
+ bool reconnect = 4;
+ bool auto_subscribe = 9;
+ bool hidden = 10;
+ ClientInfo client = 11;
+ bool recorder = 12;
+ string name = 13;
+ // A user's ClaimGrants serialized in JSON
+ string grants_json = 14;
+ bool adaptive_stream = 15;
+ //if reconnect, client will set current sid
+ string participant_id = 16;
+}
+
+message EndSession {
+}
+
+message RemoveParticipant {
+ string participant_id = 1;
+}
+
+message KeepAlive {
+}
@@ -0,0 +1,330 @@
+syntax = "proto3";
+
+package livekit;
+option go_package = "github.com/livekit/protocol/livekit";
+option csharp_namespace = "LiveKit.Proto";
+option ruby_package = "LiveKit::Proto";
+
+import "google/protobuf/timestamp.proto";
+import "livekit_egress.proto";
+
+message Room {
+ string sid = 1;
+ string name = 2;
+ uint32 empty_timeout = 3;
+ uint32 max_participants = 4;
+ int64 creation_time = 5;
+ string turn_password = 6;
+ repeated Codec enabled_codecs = 7;
+ string metadata = 8;
+ uint32 num_participants = 9;
+ bool active_recording = 10;
+}
+
+// room info that should not be returned to clients
+message RoomInternal {
+ AutoTrackEgress track_egress = 1;
+}
+
+message AutoTrackEgress {
+ string file_prefix = 1;
+ oneof output {
+ S3Upload s3 = 2;
+ GCPUpload gcp = 3;
+ AzureBlobUpload azure = 4;
+ }
+}
+
+message Codec {
+ string mime = 1;
+ string fmtp_line = 2;
+}
+
+message ParticipantPermission {
+ // allow participant to subscribe to other tracks in the room
+ bool can_subscribe = 1;
+ // allow participant to publish new tracks to room
+ bool can_publish = 2;
+ // allow participant to publish data
+ bool can_publish_data = 3;
+ // indicates that it's hidden to others
+ bool hidden = 7;
+ // indicates it's a recorder instance
+ bool recorder = 8;
+}
+
+message ParticipantInfo {
+ enum State {
+ // websocket' connected, but not offered yet
+ JOINING = 0;
+ // server received client offer
+ JOINED = 1;
+ // ICE connectivity established
+ ACTIVE = 2;
+ // WS disconnected
+ DISCONNECTED = 3;
+ }
+ string sid = 1;
+ string identity = 2;
+ State state = 3;
+ repeated TrackInfo tracks = 4;
+ string metadata = 5;
+ // timestamp when participant joined room, in seconds
+ int64 joined_at = 6;
+ string name = 9;
+ uint32 version = 10;
+ ParticipantPermission permission = 11;
+ string region = 12;
+ // indicates the participant has an active publisher connection
+ // and can publish to the server
+ bool is_publisher = 13;
+}
+
+enum TrackType {
+ AUDIO = 0;
+ VIDEO = 1;
+ DATA = 2;
+}
+
+enum TrackSource {
+ UNKNOWN = 0;
+ CAMERA = 1;
+ MICROPHONE = 2;
+ SCREEN_SHARE = 3;
+ SCREEN_SHARE_AUDIO = 4;
+}
+
+message SimulcastCodecInfo {
+ string mime_type = 1;
+ string mid = 2;
+ string cid = 3;
+ repeated VideoLayer layers = 4;
+}
+
+message TrackInfo {
+ string sid = 1;
+ TrackType type = 2;
+ string name = 3;
+ bool muted = 4;
+ // original width of video (unset for audio)
+ // clients may receive a lower resolution version with simulcast
+ uint32 width = 5;
+ // original height of video (unset for audio)
+ uint32 height = 6;
+ // true if track is simulcasted
+ bool simulcast = 7;
+ // true if DTX (Discontinuous Transmission) is disabled for audio
+ bool disable_dtx = 8;
+ // source of media
+ TrackSource source = 9;
+ repeated VideoLayer layers = 10;
+ // mime type of codec
+ string mime_type = 11;
+ string mid = 12;
+ repeated SimulcastCodecInfo codecs = 13;
+}
+
+enum VideoQuality {
+ LOW = 0;
+ MEDIUM = 1;
+ HIGH = 2;
+ OFF = 3;
+}
+
+// provide information about available spatial layers
+message VideoLayer {
+ // for tracks with a single layer, this should be HIGH
+ VideoQuality quality = 1;
+ uint32 width = 2;
+ uint32 height = 3;
+ // target bitrate, server will measure actual
+ uint32 bitrate = 4;
+ uint32 ssrc = 5;
+}
+
+// new DataPacket API
+message DataPacket {
+ enum Kind {
+ RELIABLE = 0;
+ LOSSY = 1;
+ }
+ Kind kind = 1;
+ oneof value {
+ UserPacket user = 2;
+ ActiveSpeakerUpdate speaker = 3;
+ }
+}
+
+message ActiveSpeakerUpdate {
+ repeated SpeakerInfo speakers = 1;
+}
+
+message SpeakerInfo {
+ string sid = 1;
+ // audio level, 0-1.0, 1 is loudest
+ float level = 2;
+ // true if speaker is currently active
+ bool active = 3;
+}
+
+message UserPacket {
+ // participant ID of user that sent the message
+ string participant_sid = 1;
+ // user defined payload
+ bytes payload = 2;
+ // the ID of the participants who will receive the message (the message will be sent to all the people in the room if this variable is empty)
+ repeated string destination_sids = 3;
+}
+
+enum ConnectionQuality {
+ POOR = 0;
+ GOOD = 1;
+ EXCELLENT = 2;
+}
+
+message ParticipantTracks {
+ // participant ID of participant to whom the tracks belong
+ string participant_sid = 1;
+ repeated string track_sids = 2;
+}
+
+// details about the server
+message ServerInfo {
+ enum Edition {
+ Standard = 0;
+ Cloud = 1;
+ }
+ Edition edition = 1;
+ string version = 2;
+ int32 protocol = 3;
+ string region = 4;
+ string node_id = 5;
+ // additional debugging information. sent only if server is in development mode
+ string debug_info = 6;
+}
+
+// details about the client
+message ClientInfo {
+ enum SDK {
+ UNKNOWN = 0;
+ JS = 1;
+ SWIFT = 2;
+ ANDROID = 3;
+ FLUTTER = 4;
+ GO = 5;
+ UNITY = 6;
+ }
+
+ SDK sdk = 1;
+ string version = 2;
+ int32 protocol = 3;
+ string os = 4;
+ string os_version = 5;
+ string device_model = 6;
+ string browser = 7;
+ string browser_version = 8;
+ string address = 9;
+ // wifi, wired, cellular, vpn, empty if not known
+ string network = 10;
+}
+
+// server provided client configuration
+message ClientConfiguration {
+ VideoConfiguration video = 1;
+ VideoConfiguration screen = 2;
+
+ ClientConfigSetting resume_connection = 3;
+ DisabledCodecs disabled_codecs = 4;
+ ClientConfigSetting force_relay = 5;
+}
+
+enum ClientConfigSetting {
+ UNSET = 0;
+ DISABLED = 1;
+ ENABLED = 2;
+}
+
+message VideoConfiguration {
+ ClientConfigSetting hardware_encoder = 1;
+}
+
+message DisabledCodecs {
+ repeated Codec codecs = 1;
+}
+
+enum DisconnectReason {
+ UNKNOWN_REASON = 0;
+ CLIENT_INITIATED = 1;
+ DUPLICATE_IDENTITY = 2;
+ SERVER_SHUTDOWN = 3;
+ PARTICIPANT_REMOVED = 4;
+ ROOM_DELETED = 5;
+ STATE_MISMATCH = 6;
+ JOIN_FAILURE = 7;
+}
+
+message RTPStats {
+ google.protobuf.Timestamp start_time = 1;
+ google.protobuf.Timestamp end_time = 2;
+ double duration = 3;
+
+ uint32 packets = 4;
+ double packet_rate = 5;
+
+ uint64 bytes = 6;
+ uint64 header_bytes = 39;
+ double bitrate = 7;
+
+ uint32 packets_lost = 8;
+ double packet_loss_rate = 9;
+ float packet_loss_percentage = 10;
+
+ uint32 packets_duplicate = 11;
+ double packet_duplicate_rate = 12;
+
+ uint64 bytes_duplicate = 13;
+ uint64 header_bytes_duplicate = 40;
+ double bitrate_duplicate = 14;
+
+ uint32 packets_padding = 15;
+ double packet_padding_rate = 16;
+
+ uint64 bytes_padding = 17;
+ uint64 header_bytes_padding = 41;
+ double bitrate_padding = 18;
+
+ uint32 packets_out_of_order = 19;
+
+ uint32 frames = 20;
+ double frame_rate = 21;
+
+ double jitter_current = 22;
+ double jitter_max = 23;
+
+ map<int32, uint32> gap_histogram = 24;
+
+ uint32 nacks = 25;
+ uint32 nack_acks = 37;
+ uint32 nack_misses = 26;
+ uint32 nack_repeated = 38;
+
+ uint32 plis = 27;
+ google.protobuf.Timestamp last_pli = 28;
+
+ uint32 firs = 29;
+ google.protobuf.Timestamp last_fir = 30;
+
+ uint32 rtt_current = 31;
+ uint32 rtt_max = 32;
+
+ uint32 key_frames = 33;
+ google.protobuf.Timestamp last_key_frame = 34;
+
+ uint32 layer_lock_plis = 35;
+ google.protobuf.Timestamp last_layer_lock_pli = 36;
+}
+
+message TimedVersion {
+ int64 unix_micro = 1;
+ int32 ticks = 2;
+}
@@ -0,0 +1,159 @@
+syntax = "proto3";
+
+package livekit;
+option go_package = "github.com/livekit/protocol/livekit";
+option csharp_namespace = "LiveKit.Proto";
+option ruby_package = "LiveKit::Proto";
+
+import "livekit_models.proto";
+import "livekit_egress.proto";
+
+// Room service that can be performed on any node
+// they are Twirp-based HTTP req/responses
+service RoomService {
+ // Creates a room with settings. Requires `roomCreate` permission.
+ // This method is optional; rooms are automatically created when clients connect to them for the first time.
+ rpc CreateRoom(CreateRoomRequest) returns (Room);
+
+ // List rooms that are active on the server. Requires `roomList` permission.
+ rpc ListRooms(ListRoomsRequest) returns (ListRoomsResponse);
+
+ // Deletes an existing room by name or id. Requires `roomCreate` permission.
+ // DeleteRoom will disconnect all participants that are currently in the room.
+ rpc DeleteRoom(DeleteRoomRequest) returns (DeleteRoomResponse);
+
+ // Lists participants in a room, Requires `roomAdmin`
+ rpc ListParticipants(ListParticipantsRequest) returns (ListParticipantsResponse);
+
+ // Get information on a specific participant, Requires `roomAdmin`
+ rpc GetParticipant(RoomParticipantIdentity) returns (ParticipantInfo);
+
+ // Removes a participant from room. Requires `roomAdmin`
+ rpc RemoveParticipant(RoomParticipantIdentity) returns (RemoveParticipantResponse);
+
+ // Mute/unmute a participant's track, Requires `roomAdmin`
+ rpc MutePublishedTrack(MuteRoomTrackRequest) returns (MuteRoomTrackResponse);
+
+ // Update participant metadata, will cause updates to be broadcasted to everyone in the room. Requires `roomAdmin`
+ rpc UpdateParticipant(UpdateParticipantRequest) returns (ParticipantInfo);
+
+ // Subscribes or unsubscribe a participant from tracks. Requires `roomAdmin`
+ rpc UpdateSubscriptions(UpdateSubscriptionsRequest) returns (UpdateSubscriptionsResponse);
+
+ // Send data over data channel to participants in a room, Requires `roomAdmin`
+ rpc SendData(SendDataRequest) returns (SendDataResponse);
+
+ // Update room metadata, will cause updates to be broadcasted to everyone in the room, Requires `roomAdmin`
+ rpc UpdateRoomMetadata (UpdateRoomMetadataRequest) returns (Room);
+}
+
+message CreateRoomRequest {
+ // name of the room
+ string name = 1;
+ // number of seconds to keep the room open if no one joins
+ uint32 empty_timeout = 2;
+ // limit number of participants that can be in a room
+ uint32 max_participants = 3;
+ // override the node room is allocated to, for debugging
+ string node_id = 4;
+ // metadata of room
+ string metadata = 5;
+ // egress
+ RoomEgress egress = 6;
+}
+
+message RoomEgress {
+ RoomCompositeEgressRequest room = 1;
+ AutoTrackEgress tracks = 2;
+}
+
+message ListRoomsRequest {
+ // when set, will only return rooms with name match
+ repeated string names = 1;
+}
+
+message ListRoomsResponse {
+ repeated Room rooms = 1;
+}
+
+message DeleteRoomRequest {
+ // name of the room
+ string room = 1;
+}
+
+message DeleteRoomResponse {
+}
+
+message ListParticipantsRequest {
+ // name of the room
+ string room = 1;
+}
+
+message ListParticipantsResponse {
+ repeated ParticipantInfo participants = 1;
+}
+
+message RoomParticipantIdentity {
+ // name of the room
+ string room = 1;
+ // identity of the participant
+ string identity = 2;
+}
+
+message RemoveParticipantResponse {
+}
+
+message MuteRoomTrackRequest {
+ // name of the room
+ string room = 1;
+ string identity = 2;
+ // sid of the track to mute
+ string track_sid = 3;
+ // set to true to mute, false to unmute
+ bool muted = 4;
+}
+
+message MuteRoomTrackResponse {
+ TrackInfo track = 1;
+}
+
+message UpdateParticipantRequest {
+ string room = 1;
+ string identity = 2;
+ // metadata to update. skipping updates if left empty
+ string metadata = 3;
+ // set to update the participant's permissions
+ ParticipantPermission permission = 4;
+}
+
+message UpdateSubscriptionsRequest {
+ string room = 1;
+ string identity = 2;
+ // list of sids of tracks
+ repeated string track_sids = 3;
+ // set to true to subscribe, false to unsubscribe from tracks
+ bool subscribe = 4;
+ // list of participants and their tracks
+ repeated ParticipantTracks participant_tracks = 5;
+}
+
+message UpdateSubscriptionsResponse {
+ // empty for now
+}
+
+message SendDataRequest {
+ string room = 1;
+ bytes data = 2;
+ DataPacket.Kind kind = 3;
+ repeated string destination_sids = 4;
+}
+
+message SendDataResponse {
+ //
+}
+
+message UpdateRoomMetadataRequest {
+ string room = 1;
+ // metadata to update. skipping updates if left empty
+ string metadata = 2;
+}
@@ -0,0 +1,83 @@
+syntax = "proto3";
+
+package livekit;
+option go_package = "github.com/livekit/protocol/livekit";
+option csharp_namespace = "LiveKit.Proto";
+option ruby_package = "LiveKit::Proto";
+
+import "livekit_egress.proto";
+import "livekit_ingress.proto";
+
+message StartEgressRequest {
+ // request metadata
+ string egress_id = 1;
+ string request_id = 2;
+ string sender_id = 10;
+ int64 sent_at = 4;
+
+ // request
+ oneof request {
+ RoomCompositeEgressRequest room_composite = 5;
+ TrackCompositeEgressRequest track_composite = 6;
+ TrackEgressRequest track = 7;
+ }
+
+ // connection info
+ string room_id = 3;
+ string token = 8;
+ string ws_url = 9;
+}
+
+message EgressRequest {
+ // request metadata
+ string egress_id = 1;
+ string request_id = 2;
+ string sender_id = 5;
+
+ // request
+ oneof request {
+ UpdateStreamRequest update_stream = 3;
+ StopEgressRequest stop = 4;
+ }
+}
+
+message EgressResponse {
+ EgressInfo info = 1;
+ string error = 2;
+ string request_id = 3;
+}
+
+message IngressRequest {
+ // request metadata
+ string ingress_id = 1;
+ string request_id = 2;
+ string sender_id = 3;
+
+ oneof request {
+ UpdateIngressRequest update = 4;
+ DeleteIngressRequest delete = 5;
+ }
+}
+
+// Query an ingress info from an ingress ID or stream key
+message GetIngressInfoRequest {
+ string ingress_id = 1;
+ string stream_key = 2;
+ string request_id = 3;
+ string sender_id = 4;
+ int64 sent_at = 5;
+}
+
+message IngressResponse {
+ IngressInfo info = 1;
+ string error = 2;
+ string request_id = 3;
+}
+
+message GetIngressInfoResponse {
+ IngressInfo info = 1;
+ string token = 2;
+ string ws_url = 3;
+ string error = 4;
+ string request_id = 5;
+}
@@ -0,0 +1,301 @@
+syntax = "proto3";
+
+package livekit;
+option go_package = "github.com/livekit/protocol/livekit";
+option csharp_namespace = "LiveKit.Proto";
+option ruby_package = "LiveKit::Proto";
+
+import "livekit_models.proto";
+
+message SignalRequest {
+ oneof message {
+ // initial join exchange, for publisher
+ SessionDescription offer = 1;
+ // participant answering publisher offer
+ SessionDescription answer = 2;
+ TrickleRequest trickle = 3;
+ AddTrackRequest add_track = 4;
+ // mute the participant's published tracks
+ MuteTrackRequest mute = 5;
+ // Subscribe or unsubscribe from tracks
+ UpdateSubscription subscription = 6;
+ // Update settings of subscribed tracks
+ UpdateTrackSettings track_setting = 7;
+ // Immediately terminate session
+ LeaveRequest leave = 8;
+ // Set active published layers, deprecated in favor of automatic tracking
+// SetSimulcastLayers simulcast = 9;
+ // Update published video layers
+ UpdateVideoLayers update_layers = 10;
+ // Update subscriber permissions
+ SubscriptionPermission subscription_permission = 11;
+ // sync client's subscribe state to server during reconnect
+ SyncState sync_state = 12;
+ // Simulate conditions, for client validations
+ SimulateScenario simulate = 13;
+ // client triggered ping to server
+ int64 ping = 14;
+ }
+}
+
+message SignalResponse {
+ oneof message {
+ // sent when join is accepted
+ JoinResponse join = 1;
+ // sent when server answers publisher
+ SessionDescription answer = 2;
+ // sent when server is sending subscriber an offer
+ SessionDescription offer = 3;
+ // sent when an ICE candidate is available
+ TrickleRequest trickle = 4;
+ // sent when participants in the room has changed
+ ParticipantUpdate update = 5;
+ // sent to the participant when their track has been published
+ TrackPublishedResponse track_published = 6;
+ // Immediately terminate session
+ LeaveRequest leave = 8;
+ // server initiated mute
+ MuteTrackRequest mute = 9;
+ // indicates changes to speaker status, including when they've gone to not speaking
+ SpeakersChanged speakers_changed = 10;
+ // sent when metadata of the room has changed
+ RoomUpdate room_update = 11;
+ // when connection quality changed
+ ConnectionQualityUpdate connection_quality = 12;
+ // when streamed tracks state changed, used to notify when any of the streams were paused due to
+ // congestion
+ StreamStateUpdate stream_state_update = 13;
+ // when max subscribe quality changed, used by dynamic broadcasting to disable unused layers
+ SubscribedQualityUpdate subscribed_quality_update = 14;
+ // when subscription permission changed
+ SubscriptionPermissionUpdate subscription_permission_update = 15;
+ // update the token the client was using, to prevent an active client from using an expired token
+ string refresh_token = 16;
+ // server initiated track unpublish
+ TrackUnpublishedResponse track_unpublished = 17;
+ // respond to ping
+ int64 pong = 18;
+ }
+}
+
+enum SignalTarget {
+ PUBLISHER = 0;
+ SUBSCRIBER = 1;
+}
+
+message SimulcastCodec {
+ string codec = 1;
+ string cid = 2;
+ bool enable_simulcast_layers = 3;
+}
+
+message AddTrackRequest {
+ // client ID of track, to match it when RTC track is received
+ string cid = 1;
+ string name = 2;
+ TrackType type = 3;
+ // to be deprecated in favor of layers
+ uint32 width = 4;
+ uint32 height = 5;
+ // true to add track and initialize to muted
+ bool muted = 6;
+ // true if DTX (Discontinuous Transmission) is disabled for audio
+ bool disable_dtx = 7;
+ TrackSource source = 8;
+ repeated VideoLayer layers = 9;
+
+ repeated SimulcastCodec simulcast_codecs = 10;
+
+ // server ID of track, publish new codec to exist track
+ string sid = 11;
+}
+
+message TrickleRequest {
+ string candidateInit = 1;
+ SignalTarget target = 2;
+}
+
+message MuteTrackRequest {
+ string sid = 1;
+ bool muted = 2;
+}
+
+message JoinResponse {
+ Room room = 1;
+ ParticipantInfo participant = 2;
+ repeated ParticipantInfo other_participants = 3;
+ // deprecated. use server_info.version instead.
+ string server_version = 4;
+ repeated ICEServer ice_servers = 5;
+ // use subscriber as the primary PeerConnection
+ bool subscriber_primary = 6;
+ // when the current server isn't available, return alternate url to retry connection
+ // when this is set, the other fields will be largely empty
+ string alternative_url = 7;
+ ClientConfiguration client_configuration = 8;
+ // deprecated. use server_info.region instead.
+ string server_region = 9;
+ int32 ping_timeout = 10;
+ int32 ping_interval = 11;
+ ServerInfo server_info = 12;
+}
+
+message TrackPublishedResponse {
+ string cid = 1;
+ TrackInfo track = 2;
+}
+
+message TrackUnpublishedResponse {
+ string track_sid = 1;
+}
+
+message SessionDescription {
+ string type = 1; // "answer" | "offer" | "pranswer" | "rollback"
+ string sdp = 2;
+}
+
+message ParticipantUpdate {
+ repeated ParticipantInfo participants = 1;
+}
+
+message UpdateSubscription {
+ repeated string track_sids = 1;
+ bool subscribe = 2;
+ repeated ParticipantTracks participant_tracks = 3;
+}
+
+message UpdateTrackSettings {
+ repeated string track_sids = 1;
+ // when true, the track is placed in a paused state, with no new data returned
+ bool disabled = 3;
+ // deprecated in favor of width & height
+ VideoQuality quality = 4;
+ // for video, width to receive
+ uint32 width = 5;
+ // for video, height to receive
+ uint32 height = 6;
+}
+
+message LeaveRequest {
+ // sent when server initiates the disconnect due to server-restart
+ // indicates clients should attempt full-reconnect sequence
+ bool can_reconnect = 1;
+ DisconnectReason reason = 2;
+}
+
+// message to indicate published video track dimensions are changing
+message UpdateVideoLayers {
+ string track_sid = 1;
+ repeated VideoLayer layers = 2;
+}
+
+message ICEServer {
+ repeated string urls = 1;
+ string username = 2;
+ string credential = 3;
+}
+
+message SpeakersChanged {
+ repeated SpeakerInfo speakers = 1;
+}
+
+message RoomUpdate {
+ Room room = 1;
+}
+
+message ConnectionQualityInfo {
+ string participant_sid = 1;
+ ConnectionQuality quality = 2;
+ float score = 3;
+}
+
+message ConnectionQualityUpdate {
+ repeated ConnectionQualityInfo updates = 1;
+}
+
+enum StreamState {
+ ACTIVE = 0;
+ PAUSED = 1;
+}
+
+message StreamStateInfo {
+ string participant_sid = 1;
+ string track_sid = 2;
+ StreamState state = 3;
+}
+
+message StreamStateUpdate {
+ repeated StreamStateInfo stream_states = 1;
+}
+
+message SubscribedQuality {
+ VideoQuality quality = 1;
+ bool enabled = 2;
+}
+
+message SubscribedCodec {
+ string codec = 1;
+ repeated SubscribedQuality qualities = 2;
+}
+
+message SubscribedQualityUpdate {
+ string track_sid = 1;
+ repeated SubscribedQuality subscribed_qualities = 2;
+ repeated SubscribedCodec subscribed_codecs = 3;
+}
+
+message TrackPermission {
+ // permission could be granted either by participant sid or identity
+ string participant_sid = 1;
+ bool all_tracks = 2;
+ repeated string track_sids = 3;
+ string participant_identity = 4;
+}
+
+message SubscriptionPermission {
+ bool all_participants = 1;
+ repeated TrackPermission track_permissions = 2;
+}
+
+message SubscriptionPermissionUpdate {
+ string participant_sid = 1;
+ string track_sid = 2;
+ bool allowed = 3;
+}
+
+message SyncState {
+ // last subscribe answer before reconnecting
+ SessionDescription answer = 1;
+ UpdateSubscription subscription = 2;
+ repeated TrackPublishedResponse publish_tracks = 3;
+ repeated DataChannelInfo data_channels = 4;
+ // last received server side offer before reconnecting
+ SessionDescription offer = 5;
+}
+
+message DataChannelInfo {
+ string label = 1;
+ uint32 id = 2;
+ SignalTarget target = 3;
+}
+
+enum CandidateProtocol {
+ UDP = 0;
+ TCP = 1;
+ TLS = 2;
+}
+
+message SimulateScenario {
+ oneof scenario {
+ // simulate N seconds of speaker activity
+ int32 speaker_update = 1;
+ // simulate local node failure
+ bool node_failure = 2;
+ // simulate migration
+ bool migration = 3;
+ // server to send leave
+ bool server_leave = 4;
+ // switch candidate protocol to tcp
+ CandidateProtocol switch_candidate_protocol = 5;
+ }
+}
@@ -0,0 +1,36 @@
+syntax = "proto3";
+
+package livekit;
+option go_package = "github.com/livekit/protocol/livekit";
+option csharp_namespace = "LiveKit.Proto";
+option ruby_package = "LiveKit::Proto";
+
+import "livekit_models.proto";
+import "livekit_egress.proto";
+import "livekit_ingress.proto";
+
+message WebhookEvent {
+ // one of room_started, room_finished, participant_joined, participant_left,
+ // track_published, track_unpublished, egress_started, egress_updated, egress_ended, ingress_started, ingress_ended
+ string event = 1;
+
+ Room room = 2;
+
+ // set when event is participant_* or track_*
+ ParticipantInfo participant = 3;
+
+ // set when event is egress_*
+ EgressInfo egress_info = 9;
+
+ // set when event is ingress_*
+ IngressInfo ingress_info = 10;
+
+ // set when event is track_*
+ TrackInfo track = 8;
+
+ // unique event uuid
+ string id = 6;
+
+ // timestamp in seconds
+ int64 created_at = 7;
+}