# chanora_bridge Typed Flutter/Rust bridge — schema-controlled DTOs for commands, results, and events. Backed by `flutter_rust_bridge` 2.x per DEC-014. ## Architecture - **`api` module** — all public functions exposed to Dart. Each function runs on a shared tokio runtime and delegates to `chanora_core::ChanoraSession`. Input/output types are owned primitives or `String`s — no backend types cross the boundary (SAD-067, SDD-079). - **`frb_generated`** — auto-generated `flutter_rust_bridge` glue. Contains `unsafe` for the FFI boundary; hand-written code must not use `unsafe`. - **`android_init`** (Android only) — NDK context initialization - **`permission_jni`** (Android only) — JNI hook for Android permission state changes (SDD-106) ### DTO pattern Every Dart-facing type is a `Bridge*` DTO with primitive fields. `From` impls convert between bridge DTOs and `chanora_core` types. Most types do not carry `serde` derives — FRB generates its own SSE encoders/decoders. ### Event streaming `BridgeEvent` enum is streamed to Dart via FRB's `StreamSink`. Events include: Connected, Disconnected, Lost, Reconnecting, ChatMessage, VoiceState, AudioStarted/Stopped, ClientJoined/Left/Moved/Updated, ChannelAdded/Removed/Updated, PttCapability, PermissionState, ServerActivity, InterruptionState, AudioRouteChanged. ## Public API Summary ### Commands (api.rs) | Command | Description | |---|---| | `bridge_init()` | One-time init: logging, panic hook | | `connect(host, nickname, password)` | Connect to a server | | `disconnect()` | Clean disconnect | | `snapshot()` | Refresh server state | | `client_profile(client_id)` | Rich profile for one client | | `is_connected()` | Connection check | | `prefetch_server(host)` | Warm server resolution | | `voice_join(channel_id, password)` | Join voice channel | | `voice_leave()` | Leave voice channel | | `set_transmit_mode(mode)` | Ptt/Continuous/VoiceActivity | | `get_transmit_mode()` | Read current mode | | `set_hard_mute(muted)` | Hard-mute clamp | | `set_ptt(active)` | Manual PTT press/release | | `set_ptt_binding(input_class, platform_key)` | Bind a PTT key | | `ptt_descriptor()` | Current PTT capability | | `get_ptt_binding()` | Persisted PTT binding | | `set_release_tail_ms(ms)` | Release-tail config | | `get_release_tail_ms()` | Read release-tail | | `move_to_channel(channel_id, password)` | Move to a channel | | `set_input_muted(muted)` / `set_output_muted(muted)` | Server-side mute | | `set_output_gain(gain)` | Master volume | | `set_client_volume(client_id, volume)` | Per-client volume | | `send_chat_message(message, target)` | Send text | | `set_audio_processing_config(config)` | P1 audio processing | | `get_audio_processing_config()` | Read P1 config | | `audio_processing_stats()` | P1 telemetry | | `enable_audio_debug_wav_dump(enabled)` | WAV dump toggle | | `set_vad_model_path(path)` | Silero model path | | `set_input_device(id)` / `set_output_device(id)` | Device selection | | `export_diagnostics()` | Redacted export bundle (includes network stats) | | `audio_stats()` | Audio subsystem statistics | | `input_level_stream()` | Mic level metering stream | | `events_stream()` | Bridge event stream | | `log_file_path_str()` | Log file path for platform | | `init_storage()` / `init_cache()` | Storage/cache initialization | | `set_ios_voice_processing_mode(mode)` | iOS audio processing mode | | `set_audio_output_route(route)` | Audio output route selection | | `list_audio_devices()` | Enumerate audio devices | | `list_bookmarks()` / `add_bookmark` / `update_bookmark` / `delete_bookmark` | Bookmark CRUD | | `download_avatar(hash, uid)` / `download_icon(id)` | Avatar/icon download | | `clear_file_cache()` / `file_cache_size()` | Cache management | | `handle_route_change(route)` | iOS audio route change | | `handle_media_services_reset_with_route(route_class)` | iOS media reset | | `handle_interruption_began()` / `handle_interruption_ended(should_resume)` | iOS interruption | | `lifecycle_event(state)` | Platform lifecycle | ### Bridge DTOs `BridgeSnapshot`, `BridgeChannel`, `BridgeClient`, `BridgeClientProfile`, `BridgeAudioStats`, `BridgeAudioProcessingConfig`, `BridgeAudioProcessingStats`, `BridgeAudioRoute`, `BridgeTransmitMode`, `BridgePttInputClass`, `BridgePttDescriptor`, `BridgePttBinding`, `BridgeMessageTarget`, `BridgeBookmark`, `PermissionStateKind`, `BridgeError`. ## Platform notes - Cannot use `#![forbid(unsafe_code)]` because FRB-generated glue legitimately uses `unsafe` for the FFI boundary. - Android: includes `android_init` and `permission_jni` modules gated behind `cfg(target_os = "android")`. - iOS: route-change and interruption handlers are synchronous (`#[frb(sync)]`), dispatched to the tokio runtime via an ordered channel.