feat: multi-platform bug fixes, Android audio path, and build tooling
Flutter UI fixes: - Fix stale channel badge/speaker when moved by others (derive current channel from ownClientId instead of optimistic local state) - Fix Linux PTT via focused fallback key handler - Distinguish ServerQuery clients with terminal icon in client list - Reduce duplicate current-channel badge display - Prevent PTT key-bind save from permanently closing voice settings - Fix Linux GTK reopen-after-close (quit app on window destroy) - Fix focused PTT: consume key events, release held keys on disconnect/leave-channel/mode/backend changes, suppress stale errors Flutter Rust bridge: - Thread is_server_query flag through protocol→bridge→Dart - Add own_client_id to BridgeSnapshot DTO - Add log_file_path_str() for platform log path queries Rust protocol: - Add ServerQuery test coverage (query_client_type_maps_to_server_query_flag) - Split reqwest TLS: native-tls for desktop/iOS, rustls for Android Rust audio: - Upgrade cpal 0.16→0.17.3 with API adjustments (SampleRate, description()) - Suppress Android-only dead-code warnings (open_log_file, keyring_account) Android build tooling: - tools/build-opus-android.sh: NDK auto-discovery, correct CMake Android variables (ANDROID_ABI, ANDROID_PLATFORM), portable baseline - tools/build-android-rust.sh: build+copy Rust cdylib for arm64-v8a, armeabi-v7a, x86_64 into android/app/src/main/jniLibs/ - Add jniLibs/ to .gitignore Rust bridge: - Guard open_log_file() on non-Android (Android uses logcat)
This commit is contained in:
@@ -15,7 +15,7 @@ thiserror.workspace = true
|
||||
tracing.workspace = true
|
||||
|
||||
# Cross-platform audio I/O (DEC-011.1).
|
||||
cpal = "0.16"
|
||||
cpal = "0.17.3"
|
||||
# Opus encoder. tsclientlib already pulls this; we depend explicitly so
|
||||
# this crate can compile against it without going through tsclientlib.
|
||||
audiopus = "0.3.0-rc.0"
|
||||
@@ -24,19 +24,13 @@ audiopus = "0.3.0-rc.0"
|
||||
# feature. We import the crate just for the AudioHandler type; the
|
||||
# Connection type stays inside chanora_protocol.
|
||||
tsclientlib = { git = "https://github.com/ReSpeak/tsclientlib.git", rev = "04aa2491", default-features = false, features = ["audio"] }
|
||||
# Force the reqwest TLS backend to native-tls (Security.framework on
|
||||
# Apple, SChannel on Windows, system OpenSSL on Linux/BSD) instead of
|
||||
# the rustls + aws-lc-rs combination tsclientlib's `default-tls`
|
||||
# feature would otherwise pick. aws-lc-sys does not cross-compile
|
||||
# cleanly to aarch64-apple-ios, and native-tls is the standard
|
||||
# answer for "TLS that just works on every desktop+mobile platform
|
||||
# without a vendored C dependency". Cargo's feature unification means
|
||||
# this single direct dep applies to the transitive
|
||||
# tsclientlib -> reqwest chain too.
|
||||
reqwest = { version = "0.13", default-features = false, features = ["charset", "http2", "native-tls"] }
|
||||
|
||||
tokio = { version = "1", features = ["sync", "rt", "macros", "time"] }
|
||||
|
||||
[target.'cfg(not(target_os = "android"))'.dependencies]
|
||||
# Desktop/iOS: native TLS maps to the platform TLS backend (Security.framework
|
||||
# on Apple, SChannel on Windows, system OpenSSL on Linux/BSD).
|
||||
reqwest = { version = "0.13", default-features = false, features = ["charset", "http2", "native-tls"] }
|
||||
|
||||
[target.'cfg(target_os = "ios")'.dependencies]
|
||||
# Direct CoreAudio AudioUnit access on iOS (DEC-011.x follow-up).
|
||||
# cpal's iOS backend is unsuitable for VoIP: it opens
|
||||
@@ -59,6 +53,9 @@ tokio = { version = "1", features = ["sync", "rt", "macros", "time"] }
|
||||
coreaudio-rs = "0.14"
|
||||
|
||||
[target.'cfg(target_os = "android")'.dependencies]
|
||||
# Android cross-builds should not pull OpenSSL. Use rustls here while keeping
|
||||
# native-tls for Apple targets where aws-lc/rustls is problematic for iOS.
|
||||
reqwest = { version = "0.13", default-features = false, features = ["charset", "http2", "rustls"] }
|
||||
# JNI bindings to flip Android's AudioManager into MODE_IN_COMMUNICATION
|
||||
# when the voice-comm preset is requested. ndk_context is initialised
|
||||
# by the bridge crate's android_init shim.
|
||||
|
||||
@@ -251,8 +251,8 @@ impl AudioEngine {
|
||||
|
||||
info!(
|
||||
target: "chanora_audio",
|
||||
in_device = %in_dev.name().unwrap_or_default(),
|
||||
out_device = %out_dev.name().unwrap_or_default(),
|
||||
in_device = %in_dev.description().map(|d| d.name().to_owned()).unwrap_or_default(),
|
||||
out_device = %out_dev.description().map(|d| d.name().to_owned()).unwrap_or_default(),
|
||||
"starting audio engine"
|
||||
);
|
||||
|
||||
@@ -270,7 +270,7 @@ impl AudioEngine {
|
||||
Ok(c) => info!(
|
||||
target: "chanora_audio",
|
||||
channels = c.channels(),
|
||||
sample_rate = c.sample_rate().0,
|
||||
sample_rate = c.sample_rate(),
|
||||
sample_format = ?c.sample_format(),
|
||||
"default_input_config reported"
|
||||
),
|
||||
@@ -284,7 +284,7 @@ impl AudioEngine {
|
||||
Ok(c) => info!(
|
||||
target: "chanora_audio",
|
||||
channels = c.channels(),
|
||||
sample_rate = c.sample_rate().0,
|
||||
sample_rate = c.sample_rate(),
|
||||
sample_format = ?c.sample_format(),
|
||||
"default_output_config reported"
|
||||
),
|
||||
@@ -409,7 +409,7 @@ impl AudioEngine {
|
||||
.default_output_config()
|
||||
.map_err(|e| AudioError::StreamConfig(format!("output default: {e}")))?;
|
||||
let out_format = out_cfg.sample_format();
|
||||
let dev_sample_rate = out_cfg.sample_rate().0;
|
||||
let dev_sample_rate = out_cfg.sample_rate();
|
||||
let dev_channels = out_cfg.channels() as usize;
|
||||
// Buffer-size rationale:
|
||||
// * Windows (WASAPI via cpal): the default period is
|
||||
@@ -840,7 +840,7 @@ fn try_open_capture(
|
||||
let in_cfg = in_dev
|
||||
.default_input_config()
|
||||
.map_err(|e| AudioError::StreamConfig(format!("input default: {e}")))?;
|
||||
let in_sample_rate = in_cfg.sample_rate().0;
|
||||
let in_sample_rate = in_cfg.sample_rate();
|
||||
let in_channels = in_cfg.channels() as usize;
|
||||
let in_format = in_cfg.sample_format();
|
||||
// Buffer-size rationale (same shape as the output path):
|
||||
@@ -1339,7 +1339,7 @@ where
|
||||
target: "chanora_audio",
|
||||
error = %e,
|
||||
requested_channels = config.channels,
|
||||
requested_sample_rate = config.sample_rate.0,
|
||||
requested_sample_rate = config.sample_rate,
|
||||
"build_output_stream FAILED"
|
||||
);
|
||||
AudioError::Backend(format!("build_output_stream: {e}"))
|
||||
|
||||
Reference in New Issue
Block a user