fix(android): recover from input stream failures

This commit is contained in:
Edison Jwa
2026-05-20 14:52:34 +09:00
parent bc1bd89424
commit b65cedfa95
2 changed files with 47 additions and 11 deletions
+37 -9
View File
@@ -421,7 +421,7 @@ impl AndroidVoiceUnit {
let input_builder = input_builder.set_callback(input_cb);
let mut input_stream = match input_builder.open_stream() {
Ok(s) => s,
Ok(s) => Some(s),
Err(e) => {
// Input-preset fallback ladder (SDD-112 item 6) X
// Sharing-mode ladder (SDD-112 item 7), explored
@@ -432,14 +432,36 @@ impl AndroidVoiceUnit {
error = ?e,
"android: primary input stream open failed; entering fallback ladder"
);
Self::open_input_fallback(cfg, &event_tx, capture_state.clone())?
match Self::open_input_fallback(cfg, &event_tx, capture_state.clone()) {
Ok(s) => Some(s),
Err(fallback_err) => {
warn!(
target: "chanora_audio",
error = %fallback_err,
"android: input unavailable after all fallbacks; continuing listen-only with output stream"
);
None
}
}
}
};
let input_perf = perf_from_oboe(input_stream.get_performance_mode());
let input_share = share_from_oboe(input_stream.get_sharing_mode());
let input_sample_rate = input_stream.get_sample_rate();
let input_frames_per_burst = input_stream.get_frames_per_burst();
let input_perf = input_stream
.as_ref()
.map(|s| perf_from_oboe(s.get_performance_mode()))
.unwrap_or(AchievedPerformanceMode::None);
let input_share = input_stream
.as_ref()
.map(|s| share_from_oboe(s.get_sharing_mode()))
.unwrap_or(AchievedSharingMode::Shared);
let input_sample_rate = input_stream
.as_ref()
.map(|s| s.get_sample_rate())
.unwrap_or(0);
let input_frames_per_burst = input_stream
.as_mut()
.map(|s| s.get_frames_per_burst())
.unwrap_or(0);
let session_id = None;
warn!(
target: "chanora_audio",
@@ -570,7 +592,7 @@ impl AndroidVoiceUnit {
publish_android_audio_diagnostics(diagnostics);
Ok(Self {
input: Some(input_stream),
input: input_stream,
output: Some(output_stream),
input_perf,
input_share,
@@ -697,8 +719,14 @@ impl AndroidVoiceUnit {
impl MobileVoiceAudioBackend for AndroidVoiceUnit {
fn start(&mut self) -> Result<(), BackendError> {
if let Some(s) = self.input.as_mut() {
s.start()
.map_err(|e| BackendError::LifecycleFailed(format!("input start: {e:?}")))?;
if let Err(e) = s.start() {
warn!(
target: "chanora_audio",
error = ?e,
"android: input start failed; continuing listen-only with output stream"
);
self.input = None;
}
}
if let Some(s) = self.output.as_mut() {
s.start()
+10 -2
View File
@@ -459,10 +459,18 @@ pub async fn connect(
identity: None,
ready_timeout: Duration::from_secs(15),
};
let snap = runtime()
let snap = match runtime()
.spawn(async move { session().connect(cfg).await })
.await
.map_err(|e| task_join_error("connect", e))??;
.map_err(|e| task_join_error("connect", e))?
{
Ok(snap) => snap,
Err(chanora_core::CoreError::AlreadyConnected) => runtime()
.spawn(async { session().snapshot().await })
.await
.map_err(|e| task_join_error("connect.snapshot", e))??,
Err(e) => return Err(e.into()),
};
Ok(snap.into())
}