diff --git a/apps/chanora_flutter/pubspec.yaml b/apps/chanora_flutter/pubspec.yaml index 2c30fbc..9b6ccac 100644 --- a/apps/chanora_flutter/pubspec.yaml +++ b/apps/chanora_flutter/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 1.0.0-rc.8+60 +version: 1.0.0-rc.8+61 environment: sdk: ^3.11.5 diff --git a/crates/chanora_audio/src/engine.rs b/crates/chanora_audio/src/engine.rs index ed6e7ca..dbb762d 100644 --- a/crates/chanora_audio/src/engine.rs +++ b/crates/chanora_audio/src/engine.rs @@ -13,9 +13,14 @@ use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; #[cfg(not(target_os = "ios"))] use cpal::{SampleFormat, SizedSample}; use tokio::sync::mpsc; -use tracing::{debug, error, info, warn}; - +use tracing::{debug, info}; +// `error!` and `warn!` are used only inside the cpal capture / +// playback paths (`build_input_stream`, `build_output_stream`, +// `try_open_capture` log lines). Cfg-gate the imports too so iOS +// builds don't carry an unused-imports warning. #[cfg(not(target_os = "ios"))] +use tracing::{error, warn}; + #[cfg(not(target_os = "ios"))] use audiopus::coder::Encoder as OpusEncoder; #[cfg(not(target_os = "ios"))] @@ -26,9 +31,16 @@ use audiopus::{ use tsclientlib::audio::AudioHandler; -use chanora_protocol::{ - AudioData, CodecType, InboundVoice, OutAudio, OutPacket, -}; +// `AudioData`, `CodecType`, `OutAudio` are referenced only by the +// cpal capture pipeline's Opus encode path (`CaptureState::encode_and_send`). +// `InboundVoice` + `OutPacket` are used by every platform — the +// inbound forwarder task pumps `InboundVoice` into AudioHandler on +// iOS too, and `OutPacket` flows out of the capture pipeline once +// commit 3 lands. Cfg-gate the cpal-only ones to keep iOS warnings +// clean. +#[cfg(not(target_os = "ios"))] +use chanora_protocol::{AudioData, CodecType, OutAudio}; +use chanora_protocol::{InboundVoice, OutPacket}; use crate::AudioError; @@ -641,12 +653,24 @@ impl AudioEngine { // The platform PTT backend is no longer owned by the // engine (SDD-088); its lifecycle is managed by // `chanora_core::ptt::PttController`. The engine only - // needs to abort its watchdog and drop the cpal streams. + // needs to abort its watchdog and drop the audio streams. // Aborting the watchdog cancels its tokio task. self.ptt_watchdog.take(); // Drop the streams, which stops their callback threads. - let _ = self._input_stream.lock().unwrap().take(); - let _ = self._output_stream.lock().unwrap().take(); + // Each platform has a slightly different backend; the + // common contract is that dropping the wrapper stops + // audio. iOS collapses input + output into one + // `IosVoiceUnit` (see `ios_voice_unit.rs`); every other + // platform has separate cpal input + cpal/SDL output. + #[cfg(not(target_os = "ios"))] + { + let _ = self._input_stream.lock().unwrap().take(); + let _ = self._output_stream.lock().unwrap().take(); + } + #[cfg(target_os = "ios")] + { + let _ = self._ios_voice_unit.lock().unwrap().take(); + } info!(target: "chanora_audio", "audio engine stopped"); } diff --git a/crates/chanora_audio/src/ios_voice_unit.rs b/crates/chanora_audio/src/ios_voice_unit.rs index 0a7a867..d5bbf3d 100644 --- a/crates/chanora_audio/src/ios_voice_unit.rs +++ b/crates/chanora_audio/src/ios_voice_unit.rs @@ -75,14 +75,12 @@ //! * AVAudioSession category / mode configuration — Swift owns the //! session (it must be set up before Flutter loads). -use std::sync::atomic::{AtomicBool, AtomicU32, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicU32}; use std::sync::{Arc, Mutex}; +use coreaudio::audio_unit::audio_format::LinearPcmFlags; use coreaudio::audio_unit::render_callback::{self, data}; -use coreaudio::audio_unit::{ - AudioUnit, Element, SampleFormat, Scope, StreamFormat, -}; -use coreaudio::audio_unit::stream_format::LinearPcmFlags; +use coreaudio::audio_unit::{AudioUnit, Element, SampleFormat, Scope, StreamFormat}; use coreaudio::audio_unit::IOType; use tokio::sync::mpsc; use tracing::{info, warn}; @@ -90,7 +88,7 @@ use tsclientlib::audio::AudioHandler; use crate::engine::SessionAudioId; use crate::AudioError; -use chanora_protocol::voice::OutPacket; +use chanora_protocol::OutPacket; /// 20 ms at 48 kHz mono — one Opus frame's worth of samples. /// Aligning the AudioUnit IO buffer to this frame size keeps the