131 lines
7.1 KiB
Rust
131 lines
7.1 KiB
Rust
use crate::config::{NetworkMode, RecordingMode};
|
|
use crate::friends::Friend;
|
|
use crate::network::PeerState;
|
|
use crate::presence::{FriendPresence, PresenceMode};
|
|
use iroh::{EndpointAddr, EndpointId};
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum CoreCommand {
|
|
/// Join a room. `ticket` is "create" (or empty) to mint a fresh room, else a
|
|
/// share ticket to join. `room_name` is the creator's chosen cosmetic label
|
|
/// for a NEW room; it's ignored when joining (the label rides in the ticket).
|
|
Join { name: String, ticket: String, room_name: String, input_device: Option<String>, output_device: Option<String>, echo_cancellation: bool, avatar: crate::avatar::Avatar },
|
|
Leave,
|
|
ToggleMute,
|
|
/// Change our avatar (W4) and re-announce it to the room over presence.
|
|
SetAvatar(crate::avatar::Avatar),
|
|
ToggleDeafen,
|
|
SetPttMode(bool),
|
|
SetPttActive(bool),
|
|
SetPeerVolume(EndpointId, f32),
|
|
/// Listener-side per-peer EQ. Local only; never leaves this app instance.
|
|
SetPeerEq(EndpointId, crate::audio::eq::EqSettings),
|
|
/// Listener-side per-peer pan. Local only; never leaves this app instance.
|
|
SetPeerPan(EndpointId, f32),
|
|
/// Locally mute/unmute a peer: when muted, their audio is decoded (so levels
|
|
/// still show) but not mixed into our output.
|
|
SetPeerMuted(EndpointId, bool),
|
|
SetNoiseGateThreshold(f32),
|
|
/// App-internal capture gain (mic), applied before the gate/encode. 1.0 = unity.
|
|
SetInputVolume(f32),
|
|
/// App-internal playback gain on the mixed output. 1.0 = unity.
|
|
SetOutputVolume(f32),
|
|
/// Start/stop a standalone capture-only stream that reports the raw mic
|
|
/// level via [`UiEvent::MicLevel`], for gate calibration outside a call.
|
|
/// Ignored while a room session is active (the in-call meter covers that).
|
|
SetMicMonitor { enabled: bool, input_device: Option<String> },
|
|
/// Set the relay/discovery posture. Takes effect on the next room join,
|
|
/// since the endpoint is (re)built then.
|
|
SetNetworkMode(NetworkMode),
|
|
/// Start/stop recording the call to a local WAV (your mic + the incoming
|
|
/// mix). No-op start if already recording / not in a call.
|
|
SetRecording(bool),
|
|
/// Set what a recording captures (mixed / per-peer stems / both). Takes
|
|
/// effect on the next recording start. Sent at startup from config.
|
|
SetRecordingMode(RecordingMode),
|
|
/// Broadcast a room text-chat message. No-op when not in a call.
|
|
SendChat(String),
|
|
/// Set the pixelpass binary location (config override, empty = use `$PATH`).
|
|
/// Sent at startup so screen-share can resolve the binary.
|
|
SetPixelpassPath(Option<String>),
|
|
/// Start sharing our screen: spawn a pixelpass host and announce its ticket
|
|
/// on our presence so the room can watch. No-op when not in a call.
|
|
StartScreenShare,
|
|
/// Stop sharing our screen: kill the pixelpass host and clear the presence
|
|
/// ticket. No-op when not sharing.
|
|
StopScreenShare,
|
|
/// Watch a peer's screen share: spawn a pixelpass viewer for `ticket` and
|
|
/// open it in a local player.
|
|
ViewShare(String),
|
|
/// Mint a fresh persistent identity (W7), discarding the old one. Takes effect
|
|
/// on the next room join (the endpoint is rebuilt then). The core replies with
|
|
/// an updated [`UiEvent::IdentityStatus`].
|
|
RegenerateIdentity,
|
|
/// Add a friend (W7). Core owns the friends store: it mutates + persists it and
|
|
/// replies with [`UiEvent::FriendsUpdated`]. `addr` seeds `last_addr` if known
|
|
/// (e.g. added from a room). Idempotent — re-adding an existing id is a no-op.
|
|
AddFriend { id: EndpointId, name: String, addr: Option<EndpointAddr> },
|
|
/// Remove a friend by id (W7).
|
|
RemoveFriend(EndpointId),
|
|
/// Locally rename a friend (W7).
|
|
RenameFriend(EndpointId, String),
|
|
/// Set our presence posture (W7). Gates the idle listener (answer friends-only /
|
|
/// invisible) and the outbound ping scheduler (invisible = fully dark). Sent at
|
|
/// startup from config and whenever the user changes it.
|
|
SetPresenceMode(PresenceMode),
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum UiEvent {
|
|
RoomJoined { ticket: String, self_id: String },
|
|
RoomLeft,
|
|
PeerJoined { id: EndpointId, state: PeerState },
|
|
PeerLeft { id: EndpointId },
|
|
PeerConnectionFailed { id: EndpointId },
|
|
PeerUpdated { id: EndpointId, state: PeerState },
|
|
/// Audio link to a peer is being (re)established — show a connecting state.
|
|
PeerConnecting { id: EndpointId },
|
|
/// Audio link to a peer is up and carrying audio.
|
|
PeerConnected { id: EndpointId },
|
|
AudioLevels(Vec<(EndpointId, f32)>),
|
|
/// Raw (pre-gate, pre-mute) normalized RMS of the local mic, `0.0..=1.0`,
|
|
/// for the settings level meter. Throttled to ~10/sec.
|
|
MicLevel(f32),
|
|
/// Call recording started; carries the absolute WAV path being written.
|
|
RecordingStarted { path: String },
|
|
/// Call recording stopped; carries the finished WAV path.
|
|
RecordingStopped { path: String },
|
|
/// A room text-chat message arrived from a peer (never our own — local
|
|
/// messages are echoed by the UI on send). `from` is the sender's node id
|
|
/// string, used to key their avatar (W4).
|
|
ChatMessage { from: String, name: String, text: String },
|
|
/// Our own screen share started; the UI flips the Share button to "Stop".
|
|
ScreenShareStarted,
|
|
/// Our own screen share stopped (or failed to start).
|
|
ScreenShareStopped,
|
|
/// Our node identity (W7): the current node id string, and whether it is
|
|
/// PERSISTED to disk. Sent once at startup and again after a regenerate.
|
|
/// `persisted = false` means the key file couldn't be read/written and we're
|
|
/// running on an ephemeral fallback — a degraded state the UI must surface,
|
|
/// since the id (and thus friend recognition) won't survive the next launch.
|
|
/// `error` carries the reason when degraded, for the UI explainer.
|
|
IdentityStatus { node_id: String, persisted: bool, error: Option<String> },
|
|
/// The friends list (W7), now owned by core. Sent at startup (after load) and
|
|
/// after every add/remove/rename so the GUI renders from this snapshot instead
|
|
/// of owning the store. `read_only` is true when `friends.json` failed to load
|
|
/// (malformed) — the GUI shows a degraded warning and disables edits so we never
|
|
/// overwrite the damaged file (backlog A16).
|
|
FriendsUpdated { friends: Vec<Friend>, read_only: bool },
|
|
/// A friend's live presence from a successful ping reply (W7): online, or in a
|
|
/// joinable gathering (with a one-click ticket). Emitted by the outbound ping
|
|
/// scheduler; absence of a recent event = treat as offline.
|
|
FriendPresence { id: EndpointId, presence: FriendPresence },
|
|
/// The Discoverable time-box elapsed (W7 P6): the core auto-reverted our presence
|
|
/// posture to the carried `mode` (always `Normal`) and stopped publishing. The
|
|
/// GUI must mirror + persist this so its presence picker stops showing
|
|
/// Discoverable. Distinct from a user-driven change so the GUI knows to update
|
|
/// without having issued the command itself.
|
|
PresenceModeReverted { mode: PresenceMode },
|
|
Error(String),
|
|
}
|