// Copyright 2023 LiveKit, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto2";

package livekit.proto;
option csharp_namespace = "LiveKit.Proto";

import "e2ee.proto";
import "handle.proto";
import "participant.proto";
import "track.proto";
import "video_frame.proto";
import "stats.proto";

// Connect to a new LiveKit room
message ConnectRequest {
  required string url = 1;
  required string token = 2;
  required RoomOptions options = 3;
}
message ConnectResponse {
  required uint64 async_id = 1;
}
message ConnectCallback {
  message ParticipantWithTracks {
    required OwnedParticipant participant = 1;

    // TrackInfo are not needed here, if we're subscribed to a track, the FfiServer will send
    // a TrackSubscribed event
    repeated OwnedTrackPublication publications = 2;
  }

  message Result {
    required OwnedRoom room = 1;
    required OwnedParticipant local_participant = 2;
    repeated ParticipantWithTracks participants = 3;
  }

  required uint64 async_id = 1;
  oneof message {
    string error = 2;
    Result result = 3;
  }
  
}

// Disconnect from the a room
message DisconnectRequest { required uint64 room_handle = 1; }
message DisconnectResponse { required uint64 async_id = 1; }
message DisconnectCallback { required uint64 async_id = 1; }

// Publish a track to the room
message PublishTrackRequest {
  required uint64 local_participant_handle = 1;
  required uint64 track_handle = 2;
  required TrackPublishOptions options = 3;
}
message PublishTrackResponse {
  required uint64 async_id = 1;
}
message PublishTrackCallback {
  required uint64 async_id = 1;
  oneof message {
    string error = 2;
    OwnedTrackPublication publication = 3;
  }
 
}

// Unpublish a track from the room
message UnpublishTrackRequest {
  required uint64 local_participant_handle = 1;
  required string track_sid = 2;
  required bool stop_on_unpublish = 3;
}
message UnpublishTrackResponse {
  required uint64 async_id = 1;
}
message UnpublishTrackCallback {
  required uint64 async_id = 1;
  optional string error = 2;
}

// Publish data to other participants
message PublishDataRequest {
  required uint64 local_participant_handle = 1;
  required uint64 data_ptr = 2;
  required uint64 data_len = 3;
  required bool reliable = 4;
  repeated string destination_sids = 5 [deprecated=true];
  optional string topic = 6;
  repeated string destination_identities = 7;
}
message PublishDataResponse {
  required uint64 async_id = 1;
}
message PublishDataCallback {
  required uint64 async_id = 1;
  optional string error = 2;
}

// Publish transcription messages to room
message PublishTranscriptionRequest {
  required uint64 local_participant_handle = 1;
  required string participant_identity = 2;
  required string track_id = 3;
  repeated TranscriptionSegment segments = 4;
}
message PublishTranscriptionResponse {
  required uint64 async_id = 1;
}
message PublishTranscriptionCallback {
  required uint64 async_id = 1;
  optional string error = 2;
}

// Publish Sip DTMF messages to other participants
message PublishSipDtmfRequest {
  required uint64 local_participant_handle = 1;
  required uint32 code = 2;
  required string digit = 3;
  repeated string destination_identities = 4;
}
message PublishSipDtmfResponse {
  required uint64 async_id = 1;
}
message PublishSipDtmfCallback {
  required uint64 async_id = 1;
  optional string error = 2;
}

// Change the local participant's metadata
message SetLocalMetadataRequest {
  required uint64 local_participant_handle = 1;
  required string metadata = 2;
}
message SetLocalMetadataResponse {
  required uint64 async_id = 1;
}
message SetLocalMetadataCallback {
  required uint64 async_id = 1;
  optional string error = 2;
}

message SendChatMessageRequest {
  required uint64 local_participant_handle = 1;
  required string message = 2;
  repeated string destination_identities = 3;
  optional string sender_identity = 4;
}
message EditChatMessageRequest {
  required uint64 local_participant_handle = 1;
  required string edit_text = 2;
  required ChatMessage original_message = 3;
  repeated string destination_identities = 4;
  optional string sender_identity = 5;
}
message SendChatMessageResponse {
  required uint64 async_id = 1;
}
message SendChatMessageCallback {
  required uint64 async_id = 1;
  oneof message {
    string error = 2;
    ChatMessage chat_message = 3;
  }
}

// Change the local participant's attributes
message SetLocalAttributesRequest {
  required uint64 local_participant_handle = 1;
  repeated AttributesEntry attributes = 2;
}

message AttributesEntry {
  required string key = 1;
  required string value = 2;
}

message SetLocalAttributesResponse {
  required uint64 async_id = 1;
}
message SetLocalAttributesCallback {
  required uint64 async_id = 1;
  optional string error = 2;
}

// Change the local participant's name
message SetLocalNameRequest {
  required uint64 local_participant_handle = 1;
  required string name = 2;
}
message SetLocalNameResponse {
  required uint64 async_id = 1;
}
message SetLocalNameCallback {
  required uint64 async_id = 1;
  optional string error = 2;
}

// Change the "desire" to subs2ribe to a track
message SetSubscribedRequest {
  required bool subscribe = 1;
  required uint64 publication_handle = 2;
}
message SetSubscribedResponse {}

message GetSessionStatsRequest {
  required uint64 room_handle = 1;
}
message GetSessionStatsResponse {
  required uint64 async_id = 1;
}
message GetSessionStatsCallback {
  message Result {
    repeated RtcStats publisher_stats = 1;
    repeated RtcStats subscriber_stats = 2;
  }

  required uint64 async_id = 1;

  oneof message {
    string error = 2;
    Result result = 3;
  }
}

//
// Options
//

message VideoEncoding {
  required uint64 max_bitrate = 1;
  required double max_framerate = 2;
}

message AudioEncoding {
  required uint64 max_bitrate = 1;
}

message TrackPublishOptions {
  // encodings are optional
  optional VideoEncoding video_encoding = 1;
  optional AudioEncoding audio_encoding = 2;
  optional VideoCodec video_codec = 3;
  optional bool dtx = 4;
  optional bool red = 5;
  optional bool simulcast = 6;
  optional TrackSource source = 7;
  optional string stream = 8;
}

enum IceTransportType {
  TRANSPORT_RELAY = 0;
  TRANSPORT_NOHOST = 1;
  TRANSPORT_ALL = 2;
}

enum ContinualGatheringPolicy {
  GATHER_ONCE = 0;
  GATHER_CONTINUALLY = 1;
}

message IceServer {
  repeated string urls = 1;
  optional string username = 2;
  optional string password = 3;
}

message RtcConfig {
  optional IceTransportType ice_transport_type = 1;
  optional ContinualGatheringPolicy continual_gathering_policy = 2;
  repeated IceServer ice_servers = 3; // empty fallback to default
}

message RoomOptions {
  optional bool auto_subscribe = 1;
  optional bool adaptive_stream = 2;
  optional bool dynacast = 3;
  optional E2eeOptions e2ee = 4;
  optional RtcConfig rtc_config = 5; // allow to setup a custom RtcConfiguration
  optional uint32 join_retries = 6;
}

//
// Room
//

enum ConnectionQuality {
  QUALITY_POOR = 0;
  QUALITY_GOOD = 1;
  QUALITY_EXCELLENT = 2;
  QUALITY_LOST = 3;
}

enum ConnectionState {
  CONN_DISCONNECTED = 0;
  CONN_CONNECTED = 1;
  CONN_RECONNECTING = 2;
}

enum DataPacketKind {
  KIND_LOSSY = 0;
  KIND_RELIABLE = 1;
}

enum DisconnectReason {
  UNKNOWN_REASON = 0;
  // the client initiated the disconnect
  CLIENT_INITIATED = 1;
  // another participant with the same identity has joined the room
  DUPLICATE_IDENTITY = 2;
  // the server instance is shutting down
  SERVER_SHUTDOWN = 3;
  // RoomService.RemoveParticipant was called
  PARTICIPANT_REMOVED = 4;
  // RoomService.DeleteRoom was called
  ROOM_DELETED = 5;
  // the client is attempting to resume a session, but server is not aware of it
  STATE_MISMATCH = 6;
  // client was unable to connect fully
  JOIN_FAILURE = 7;
  // Cloud-only, the server requested Participant to migrate the connection elsewhere
  MIGRATION = 8;
  // the signal websocket was closed unexpectedly
  SIGNAL_CLOSE = 9;
  // the room was closed, due to all Standard and Ingress participants having left
  ROOM_CLOSED = 10;
}

message TranscriptionSegment {
  required string id = 1;
  required string text = 2;
  required uint64 start_time = 3;
  required uint64 end_time = 4;
  required bool final = 5;
  required string language = 6;
}

message BufferInfo {
  required uint64 data_ptr = 1;
  required uint64 data_len = 2;
}

message OwnedBuffer {
  required FfiOwnedHandle handle = 1;
  required BufferInfo data = 2;
}

message RoomEvent {
  required uint64 room_handle = 1;
  oneof message {
    ParticipantConnected participant_connected = 2;
    ParticipantDisconnected participant_disconnected = 3;
    LocalTrackPublished local_track_published = 4;
    LocalTrackUnpublished local_track_unpublished = 5;
    LocalTrackSubscribed local_track_subscribed = 6;
    TrackPublished track_published = 7;
    TrackUnpublished track_unpublished = 8;
    TrackSubscribed track_subscribed = 9;
    TrackUnsubscribed track_unsubscribed = 10;
    TrackSubscriptionFailed track_subscription_failed = 11;
    TrackMuted track_muted = 12;
    TrackUnmuted track_unmuted = 13;
    ActiveSpeakersChanged active_speakers_changed = 14;
    RoomMetadataChanged room_metadata_changed = 15;
    RoomSidChanged room_sid_changed = 16;
    ParticipantMetadataChanged participant_metadata_changed = 17;
    ParticipantNameChanged participant_name_changed = 18;
    ParticipantAttributesChanged participant_attributes_changed = 19;
    ConnectionQualityChanged connection_quality_changed = 20;
    ConnectionStateChanged connection_state_changed = 21;
    // Connected connected = 21;
    Disconnected disconnected = 22;
    Reconnecting reconnecting = 23;
    Reconnected reconnected = 24;
    E2eeStateChanged e2ee_state_changed = 25;
    RoomEOS eos = 26; // The stream of room events has ended
    DataPacketReceived data_packet_received = 27;
    TranscriptionReceived transcription_received = 28;
    ChatMessageReceived chat_message = 29;
  }
}

message RoomInfo {
  optional string sid = 1;
  required string name = 2;
  required string metadata = 3;
}

message OwnedRoom {
  required FfiOwnedHandle handle = 1;
  required RoomInfo info = 2;
}

message ParticipantConnected { required OwnedParticipant info = 1; }

message ParticipantDisconnected { 
  required string participant_identity = 1;
}

message LocalTrackPublished {
  // The TrackPublicationInfo comes from the PublishTrack response
  // and the FfiClient musts wait for it before firing this event
  required string track_sid = 1;
}

message LocalTrackUnpublished {
  required string publication_sid = 1;
}

message LocalTrackSubscribed {
  required string track_sid = 2;
}

message TrackPublished {
  required string participant_identity = 1;
  required OwnedTrackPublication publication = 2;
}

message TrackUnpublished {
  required string participant_identity = 1;
  required string publication_sid = 2;
}

// Publication isn't needed for subscription events on the FFI
// The FFI will retrieve the publication using the Track sid
message TrackSubscribed {
  required string participant_identity = 1;
  required OwnedTrack track = 2;
}

message TrackUnsubscribed {
  // The FFI language can dispose/remove the VideoSink here
  required string participant_identity = 1;
  required string track_sid = 2;
}

message TrackSubscriptionFailed {
  required string participant_identity = 1;
  required string track_sid = 2;
  required string error = 3;
}

message TrackMuted {
  required string participant_identity = 1;
  required string track_sid = 2;
}

message TrackUnmuted {
  required string participant_identity = 1;
  required string track_sid = 2;
}

message E2eeStateChanged {
  required string participant_identity = 1; // Using sid instead of identity for ffi communication
  required EncryptionState state = 2;
}

message ActiveSpeakersChanged { repeated string participant_identities = 1; }

message RoomMetadataChanged { 
  required string metadata = 1;
}

message RoomSidChanged {
  required string sid = 1;
}

message ParticipantMetadataChanged { 
  required string participant_identity = 1;
  required string metadata = 2;
}

message ParticipantAttributesChanged {
  required string participant_identity = 1;
  repeated AttributesEntry attributes = 2;
  repeated AttributesEntry changed_attributes = 3;
}

message ParticipantNameChanged { 
  required string participant_identity = 1;
  required string name = 2;
}

message ConnectionQualityChanged {
  required string participant_identity = 1;
  required ConnectionQuality quality = 2;
}

message UserPacket {
  required OwnedBuffer data = 1;
  optional string topic = 2;
}

message ChatMessage {
  required string id = 1;
  required int64 timestamp = 2;
  required string message = 3;
  optional int64 edit_timestamp = 4;
  optional bool deleted = 5;
  optional bool generated = 6;
}

message ChatMessageReceived {
  required ChatMessage message = 1;
  required string participant_identity = 2;
}

message SipDTMF {
  required uint32 code = 1;
  optional string digit = 2;
}

message DataPacketReceived {
  required DataPacketKind kind = 1;
  required string participant_identity = 2; // Can be empty if the data is sent a server SDK
  oneof value {
    UserPacket user = 4;
    SipDTMF sip_dtmf = 5;
  }
}

message TranscriptionReceived {
  optional string participant_identity = 1;
  optional string track_sid = 2;
  repeated TranscriptionSegment segments = 3;
}

message ConnectionStateChanged { required ConnectionState state = 1; }

message Connected {}
message Disconnected {
  required DisconnectReason reason = 1;
}
message Reconnecting {}
message Reconnected {}

message RoomEOS {}

