Make the disconnected app flow feel more deliberate with a real bookmark management page, categorized settings navigation, and proper device dropdowns. This moves the UI closer to the Apple-style voice-first layout while leaving unrelated in-progress audio work untouched.
- Use a separate Microphone instance for continuous-mode VAD monitoring
so it no longer races with the transmit capture path.
- Respect selected input device in continuous-mode monitor subscription.
- Make talk-mode and Sonora processing labels clearer in settings UI.
Continuous Talk:
- Voice Activity Detection with energy-based detection
- Smoothing window (5 frames) to avoid false triggers
- Hangover timer (15 frames / 300ms) to keep transmitting during pauses
- Hysteresis: threshold * 0.7 to stop, threshold to start
- Configurable threshold (default 0.005)
Talk Modes:
- Push-to-Talk: hold V key to talk (existing)
- Continuous: mic always on, VAD auto-starts/stops transmission
- Toggle between modes in Settings page
Architecture:
- VoiceActivation struct with state machine (Silent/Speaking/Hangover)
- Subscription monitors mic input in continuous mode
- MicSamples messages feed VAD, which triggers StartContinuous/StopContinuous
- start_transmission/stop_transmission helper functions (shared by PTT and VAD)
- Mic lifecycle managed by subscription (starts on mode enable, stops on disable)
69 tests passing, clippy clean on both builds
Push-to-Talk:
- Hold V key to activate microphone
- cpal input stream captures mono 48kHz f32 samples
- Opus encoder (audiopus) encodes 20ms frames
- Encoded packets sent via SyncConnectionHandle -> con.send_audio()
- End-of-transmission packet sent on PTT release
- Microphone struct for mic lifecycle management
- OpusEncoderState with sample buffering and frame splitting
Audio:
- Replaced opus crate with audiopus (matches tsclientlib)
- Microphone start/stop with device selection
- PTT keyboard event subscription (V key hold/release)
- Audio gated behind 'audio' feature (needs ALSA/cmake)
69 tests passing, clippy clean on both audio and non-audio builds
UI Redesign:
- Custom dark theme with Apple-inspired palette (SIDEBAR_BG, BG_PRIMARY, etc.)
- Rounded cards with subtle shadows and depth
- Styled inputs with focus/hover states
- Styled buttons (primary, secondary, danger, nav, bookmark)
- Proper visual hierarchy with generous whitespace
- Sidebar with dark background, cards with elevated surfaces
Features:
- Bookmark CRUD: add new server, delete existing
- Join channel: click channel in list to move to it
- Settings page with audio device info placeholder
- ServerQuery: configurable command input
- Chat messages with invoker name display
- Channel list shows current channel highlighted
- Client list with mute indicators
- Error display with danger styling
- Identity level progress indicator
Architecture:
- Custom theme module (theme.rs) with all styles
- Bookmark editing form in sidebar
- Channel click handler sends client_move command
- 69 tests passing, clippy clean
Audio:
- Add AudioPlayback with channel-based cpal output (avoids Send issue)
- Add AudioCapture stub with input device enumeration
- Audio gated behind 'audio' feature flag (needs ALSA/cmake)
- list_output_devices() / list_input_devices() for device selection
- StreamItem::Audio packets forwarded via mpsc channel to cpal callback
i18n:
- Replace all Chinese error messages with English in tsdb
- Replace all Chinese comments/doc strings with English in tscore
- All user-facing strings now in English
Build:
- Add Containerfile.build for containerized builds with audio deps
- CMAKE_POLICY_VERSION_MINIMUM=3.5 workaround for audiopus_sys
- tsclientlib audio feature enabled in workspace (needs cmake)
- 69 tests passing, clippy clean on both audio and non-audio builds
- Store SessionHandle in Arc<Mutex> instead of dropping it
- Implement iced subscription with stream::channel to forward SessionEvent
- SendChannelMessage now sends via SessionHandle
- Disconnect sends clientdisconnect command then clears state
- ServerQuery panel now executes 'help' command via QueryClient
- Remove tracing_subscriber to avoid console window on Windows
- Request channel/client lists on connect
- Show connection errors and query responses in UI
- Create iced-app crate with pure Rust GUI using iced 0.13
- Implement server list, connect form, channel/user panels, messaging
- Implement ServerQuery panel for direct server queries
- Add VoiceEngine in tsaudio for decode/buffer/playback pipeline
- Update CI to build iced binary (no frontend build step needed)
- Remove Tauri dependency from workspace
- 69 tests passing across all crates
Voice packet parsing (tscore/protocol/voice.rs):
- VoicePacket and WhisperPacket types with parse/serialize
- Codec type, sample rate, channel count detection
- Tests for roundtrip and error cases
Opus codec (tsaudio/codec.rs):
- Real Opus encoder/decoder with opus crate (behind feature gate)
- 48kHz mono/stereo support
- Encode/decode with proper error handling
Jitter buffer (tsaudio/buffer.rs):
- Sequence number based reordering
- Adaptive output timing (20ms intervals)
- Packet loss handling with fallback to oldest frame
- Tests for basic and reorder scenarios
cpal playback (tsaudio/playback.rs):
- Default output device detection
- f32 and i16 sample format support
- Ring buffer for smooth playback
- Device listing
AudioFrame enhanced with sequence and codec fields.
- Add CommandEvent enum (InitServer, ChannelList, ClientList, TextMessage, etc.)
- Add HandleResult struct with responses and events
- handle_data returns HandleResult instead of Vec<Vec<u8>>
- Session uses HandleResult for real event emission
- Update socket.rs and tests for new return type
- Remove inherent to_string() methods shadowing Display (Command, CommandArgument)
- Fix empty line after doc comment in shared/types.rs
- Use sort_by_key with Reverse instead of sort_by in config.rs
- Remove redundant closures in client.rs
- Fix borrow patterns in ephemeral.rs and keys.rs
- Use abs_diff in resend.rs
- Fix needless Ok/? in tsdb/config.rs
- Allow too_many_arguments for create_message in tsdb/message.rs
- Allow dead_code on placeholder tsaudio structs