@@ -1,254 +0,0 @@
// VoiceCat control-plane wire format. SOURCE OF TRUTH for the protocol.
// Each TCP/TLS frame is [u32 length][encoded Envelope].
// Media frames (voice) are NOT here — they use a fixed binary header
//
// Extensibility rules: never reuse/renumber tags; new oneof arms and
// fields are additive; gate new features behind capability strings in ClientHello/ServerHello.
syntax = "proto3" ;
package voicecat.v1 ;
// Envelope
message Envelope {
// Nonzero on a request; echoed in the matching response for correlation. 0 = unsolicited.
uint64 request_id = 1 ;
oneof body {
// Session / handshake (tags 10-19)
ClientHello client_hello = 10 ;
ServerHello server_hello = 11 ;
AuthRequest auth_request = 12 ;
AuthResult auth_result = 13 ;
Disconnect disconnect = 14 ;
Ping ping = 15 ;
Pong pong = 16 ;
// State sync (20-29)
ServerStateSnapshot server_state = 20 ;
ChannelEvent channel_event = 21 ;
UserEvent user_event = 22 ;
SubscribeRequest subscribe = 23 ;
// Channel operations (30-39)
JoinChannelRequest join_channel = 30 ;
JoinChannelResult join_channel_result = 31 ;
LeaveChannelRequest leave_channel = 32 ;
CreateChannelRequest create_channel = 33 ;
EditChannelRequest edit_channel = 34 ;
DeleteChannelRequest delete_channel = 35 ;
MoveUserRequest move_user = 36 ;
GenericResult generic_result = 37 ;
// Voice signaling, media is on UDP (40-49)
StreamAnnounce stream_announce = 40 ;
StreamAnnounceResult stream_announce_result = 41 ;
StreamStop stream_stop = 42 ;
StreamStateUpdate stream_state = 43 ;
UdpBinding udp_binding = 44 ;
SubscribeVoiceRequest subscribe_voice = 45 ;
UnsubscribeVoiceRequest unsubscribe_voice = 46 ;
VoiceSubscriptionResult voice_subscription_result = 47 ;
// Text (50-59)
TextMessage text_message = 50 ;
TextMessageAck text_message_ack = 51 ;
TypingIndicator typing = 52 ;
// Moderation / permissions (60-69)
KickRequest kick = 60 ;
BanRequest ban = 61 ;
SetPermissionRequest set_permission = 62 ;
ServerMuteRequest server_mute = 63 ;
// Admin account management. privileged; accounts are admin-provisioned (70-79)
CreateAccountRequest create_account = 70 ;
ResetPasswordRequest reset_password = 71 ;
DeleteAccountRequest delete_account = 72 ;
ListAccountsRequest list_accounts = 73 ;
ListAccountsResult list_accounts_result = 74 ;
// Future families: file transfer = 100– 109. Extension escape hatch = 200+.
Extension extension = 200 ;
}
}
// Enums
enum ChannelType { CHANNEL_PERMANENT = 0 ; CHANNEL_TEMPORARY = 1 ; }
enum ChannelMode { MODE_MONO = 0 ; MODE_STEREO = 1 ; }
enum StreamKind { STREAM_MIC = 0 ; STREAM_SCREEN_AUDIO = 1 ; STREAM_AUX_DEVICE = 2 ; }
enum TextScope { TEXT_CHANNEL = 0 ; TEXT_PRIVATE = 1 ; TEXT_SERVER = 2 ; }
enum OpusApplication { OPUS_VOIP = 0 ; OPUS_AUDIO = 1 ; OPUS_LOWDELAY = 2 ; }
// Common types
message AudioConfig {
uint32 codec = 1 ; // 0 = OPUS
ChannelMode mode = 2 ;
uint32 sample_rate = 3 ;
uint32 bitrate_bps = 4 ;
uint32 frame_ms = 5 ; // 2.5/5/10/20/40/60
OpusApplication application = 6 ;
bool fec = 7 ;
uint32 expected_packet_loss = 8 ; // %
bool dtx = 9 ;
uint32 complexity = 10 ; // 0..10
bool dred = 11 ; // Deep REDundancy (Opus 1.6)
}
message StreamInfo {
uint32 stream_id = 1 ; // unique within the user
uint32 ssrc = 2 ; // media-plane id assigned by server
StreamKind kind = 3 ;
AudioConfig audio = 4 ;
string label = 5 ;
}
message Channel {
uint32 id = 1 ;
uint32 parent_id = 2 ; // 0 = root
string name = 3 ;
string topic = 4 ;
bool password_protected = 5 ;
uint32 max_users = 6 ;
ChannelType type = 7 ;
AudioConfig audio = 8 ;
int32 order = 9 ;
}
message User {
uint32 id = 1 ;
string nickname = 2 ;
bool is_guest = 3 ;
uint32 channel_id = 4 ;
bool self_mic_muted = 5 ;
bool self_deafened = 6 ;
bool server_muted = 7 ;
repeated StreamInfo streams = 8 ;
bool server_deafened = 9 ; // server-imposed deafen
bool voice_subscribed = 10 ; // true when the user is on the voice plane (hears + can send)
}
message Permissions {
bool can_create_temp_channel = 1 ;
bool can_kick = 2 ;
bool can_ban = 3 ;
bool can_move_users = 4 ;
bool can_admin_accounts = 5 ;
bool is_admin = 6 ;
}
// Session / handshake
message ClientHello {
uint32 proto_version = 1 ;
repeated string features = 2 ; // "opus", "fec", "screen-audio", ...
string client_name = 3 ;
string client_version = 4 ;
string preferred_locale = 5 ;
}
message ServerHello {
uint32 proto_version = 1 ;
repeated string features = 2 ;
string server_name = 3 ;
string server_version = 4 ;
repeated string auth_methods = 5 ; // "guest", "password"
uint32 udp_port = 6 ;
bytes server_identity_fingerprint = 7 ; // Ed25519 fp for TOFU
}
message GuestAuth { string nickname = 1 ; }
message PasswordAuth { string username = 1 ; string password = 2 ; }
message AuthRequest {
oneof method {
GuestAuth guest = 1 ;
PasswordAuth password = 2 ;
}
}
message AuthResult {
bool ok = 1 ;
string error = 2 ;
uint64 session_id = 3 ;
User self = 4 ;
Permissions permissions = 5 ;
bytes udp_token = 6 ; // bind the UDP 5-tuple with this
}
message Disconnect { uint32 code = 1 ; string reason = 2 ; }
message Ping { uint64 nonce = 1 ; }
message Pong { uint64 nonce = 1 ; }
// State sync
message ServerStateSnapshot {
repeated Channel channels = 1 ;
repeated User users = 2 ;
}
message ChannelEvent {
enum Kind { CREATED = 0 ; UPDATED = 1 ; DELETED = 2 ; }
Kind kind = 1 ;
Channel channel = 2 ;
uint32 deleted_id = 3 ;
}
message UserEvent {
enum Kind { JOINED = 0 ; LEFT = 1 ; UPDATED = 2 ; }
Kind kind = 1 ;
User user = 2 ;
uint32 left_id = 3 ;
string reason = 4 ; // kick/ban reason for LEFT events
}
message SubscribeRequest { repeated uint32 channel_ids = 1 ; bool presence = 2 ; }
// Channel operations
message JoinChannelRequest { uint32 channel_id = 1 ; string password = 2 ; }
message JoinChannelResult {
bool ok = 1 ; string error = 2 ;
uint32 channel_id = 3 ;
repeated User members = 4 ;
AudioConfig audio = 5 ; // authoritative channel Opus params
}
message LeaveChannelRequest { }
message CreateChannelRequest { Channel channel = 1 ; string password = 2 ; }
message EditChannelRequest { Channel channel = 1 ; string password = 2 ; }
message DeleteChannelRequest { uint32 channel_id = 1 ; }
message MoveUserRequest { uint32 user_id = 1 ; uint32 channel_id = 2 ; }
message GenericResult { bool ok = 1 ; uint32 code = 2 ; string message = 3 ; }
// Voice signaling
message StreamAnnounce { StreamKind kind = 1 ; AudioConfig requested_audio = 2 ; string label = 3 ; }
message StreamAnnounceResult { bool ok = 1 ; string error = 2 ; uint32 stream_id = 3 ; uint32 ssrc = 4 ; AudioConfig effective_audio = 5 ; }
message StreamStop { uint32 stream_id = 1 ; }
message StreamStateUpdate { uint32 user_id = 1 ; uint32 stream_id = 2 ; bool muted = 3 ; bool talking = 4 ; }
message UdpBinding { bytes udp_token = 1 ; bool ack = 2 ; }
message SubscribeVoiceRequest { }
message UnsubscribeVoiceRequest { }
message VoiceSubscriptionResult { bool ok = 1 ; string error = 2 ; bool subscribed = 3 ; }
// Text
message TextMessage {
TextScope scope = 1 ;
uint32 target_id = 2 ; // channel_id or user_id per scope
uint32 sender_id = 3 ; // set by server on relay
string body = 4 ; // UTF-8, server-bounded length
uint64 sent_at_unix_ms = 5 ; // server timestamp on relay
string client_msg_id = 6 ; // echoed in ack (dedup)
}
message TextMessageAck { string client_msg_id = 1 ; bool ok = 2 ; }
message TypingIndicator { TextScope scope = 1 ; uint32 target_id = 2 ; uint32 user_id = 3 ; }
// Moderation / permissions
message KickRequest { uint32 user_id = 1 ; string reason = 2 ; }
message BanRequest { uint32 user_id = 1 ; string reason = 2 ; uint64 expires_unix_ms = 3 ; }
message SetPermissionRequest { uint32 user_id = 1 ; Permissions permissions = 2 ; }
message ServerMuteRequest { uint32 user_id = 1 ; bool muted = 2 ; bool deafened = 3 ; }
// Admin account management
message CreateAccountRequest { string username = 1 ; string password = 2 ; }
message ResetPasswordRequest { string username = 1 ; string new_password = 2 ; }
message DeleteAccountRequest { string username = 1 ; }
message ListAccountsRequest { }
message AccountEntry { string username = 1 ; bool is_admin = 2 ; uint64 created_at_unix_ms = 3 ; uint64 last_login_unix_ms = 4 ; }
message ListAccountsResult { repeated AccountEntry accounts = 1 ; }
// Extension escape hatch
message Extension { string ns = 1 ; bytes payload = 2 ; }