feat(voice): harden Android audio and channel joins

This commit is contained in:
Edison Jwa
2026-05-19 01:58:07 +09:00
parent 29a553d4e1
commit 8c253f1d4d
23 changed files with 2948 additions and 363 deletions
+42 -2
View File
@@ -9,8 +9,8 @@ import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
import 'package:freezed_annotation/freezed_annotation.dart' hide protected;
part 'api.freezed.dart';
// These functions are ignored because they are not marked as `pub`: `log_file_path`, `log_sink`, `open_log_file`, `permission_events`, `publish_permission_state`, `runtime`, `session`, `transmit_mode_from_u8`
// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `assert_fields_are_eq`, `clone`, `clone`, `clone`, `clone`, `clone`, `clone`, `clone`, `clone`, `clone`, `clone`, `eq`, `fmt`, `fmt`, `fmt`, `fmt`, `fmt`, `fmt`, `fmt`, `fmt`, `fmt`, `fmt`, `from`, `from`, `from`, `from`, `from`, `from`, `from`, `from`
// These functions are ignored because they are not marked as `pub`: `log_file_path`, `log_sink`, `map_join_error_code`, `map_join_sync_state`, `open_log_file`, `permission_events`, `publish_permission_state`, `runtime`, `session`, `transmit_mode_from_u8`
// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `assert_fields_are_eq`, `assert_fields_are_eq`, `assert_fields_are_eq`, `clone`, `clone`, `clone`, `clone`, `clone`, `clone`, `clone`, `clone`, `clone`, `clone`, `clone`, `clone`, `eq`, `eq`, `eq`, `fmt`, `fmt`, `fmt`, `fmt`, `fmt`, `fmt`, `fmt`, `fmt`, `fmt`, `fmt`, `fmt`, `fmt`, `from`, `from`, `from`, `from`, `from`, `from`, `from`, `from`
// These functions are ignored (category: IgnoreBecauseExplicitAttribute): `from_kotlin_str`, `to_permission_gate`
/// Return the platform-conventional log-file path as a string, or
@@ -454,6 +454,24 @@ sealed class BridgeEvent with _$BridgeEvent {
/// Current release-tail in milliseconds (0..=500).
required int releaseTailMs,
/// Last confirmed authoritative channel id.
BigInt? currentChannelId,
/// Non-authoritative pending join target channel id.
BigInt? pendingTargetChannelId,
/// Whether a new join intent is currently allowed.
required bool canJoin,
/// Whether leave intent is currently allowed.
required bool canLeave,
/// Join projection sync state.
required BridgeVoiceJoinSyncState joinSyncState,
/// Last stable join error code, if any.
BridgeVoiceJoinErrorCode? joinErrorCode,
}) = BridgeEvent_VoiceState;
/// iOS audio interruption state (SDD-101).
@@ -587,6 +605,28 @@ enum BridgeTransmitMode {
voiceActivity,
}
/// Bridge mirror of stable join error/status codes.
enum BridgeVoiceJoinErrorCode {
duplicateSameTargetCoalesced,
joinAlreadyPendingDifferentTarget,
joinDenied,
joinProtocolFailure,
joinNetworkFailure,
joinTimeout,
joinSupersededByLeave,
joinStaleOutcomeIgnored,
joinReconciledDifferentChannel,
joinCommandRejectedBeforeSend,
joinCannotStartWhileSynchronizing,
}
/// Bridge mirror of core join projection sync state.
enum BridgeVoiceJoinSyncState {
ready,
synchronizingInitialSnapshot,
synchronizingReconnect,
}
/// Schema-controlled mirror of the Kotlin
/// `AndroidPermissionRequester.PermissionState` sealed class
/// (SDD-106 §5). Crosses the bridge as an enum so the Dart side can