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;
}
