fix(android): recover from input stream failures
This commit is contained in:
@@ -421,7 +421,7 @@ impl AndroidVoiceUnit {
|
|||||||
let input_builder = input_builder.set_callback(input_cb);
|
let input_builder = input_builder.set_callback(input_cb);
|
||||||
|
|
||||||
let mut input_stream = match input_builder.open_stream() {
|
let mut input_stream = match input_builder.open_stream() {
|
||||||
Ok(s) => s,
|
Ok(s) => Some(s),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
// Input-preset fallback ladder (SDD-112 item 6) X
|
// Input-preset fallback ladder (SDD-112 item 6) X
|
||||||
// Sharing-mode ladder (SDD-112 item 7), explored
|
// Sharing-mode ladder (SDD-112 item 7), explored
|
||||||
@@ -432,14 +432,36 @@ impl AndroidVoiceUnit {
|
|||||||
error = ?e,
|
error = ?e,
|
||||||
"android: primary input stream open failed; entering fallback ladder"
|
"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_perf = input_stream
|
||||||
let input_share = share_from_oboe(input_stream.get_sharing_mode());
|
.as_ref()
|
||||||
let input_sample_rate = input_stream.get_sample_rate();
|
.map(|s| perf_from_oboe(s.get_performance_mode()))
|
||||||
let input_frames_per_burst = input_stream.get_frames_per_burst();
|
.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;
|
let session_id = None;
|
||||||
warn!(
|
warn!(
|
||||||
target: "chanora_audio",
|
target: "chanora_audio",
|
||||||
@@ -570,7 +592,7 @@ impl AndroidVoiceUnit {
|
|||||||
publish_android_audio_diagnostics(diagnostics);
|
publish_android_audio_diagnostics(diagnostics);
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
input: Some(input_stream),
|
input: input_stream,
|
||||||
output: Some(output_stream),
|
output: Some(output_stream),
|
||||||
input_perf,
|
input_perf,
|
||||||
input_share,
|
input_share,
|
||||||
@@ -697,8 +719,14 @@ impl AndroidVoiceUnit {
|
|||||||
impl MobileVoiceAudioBackend for AndroidVoiceUnit {
|
impl MobileVoiceAudioBackend for AndroidVoiceUnit {
|
||||||
fn start(&mut self) -> Result<(), BackendError> {
|
fn start(&mut self) -> Result<(), BackendError> {
|
||||||
if let Some(s) = self.input.as_mut() {
|
if let Some(s) = self.input.as_mut() {
|
||||||
s.start()
|
if let Err(e) = s.start() {
|
||||||
.map_err(|e| BackendError::LifecycleFailed(format!("input start: {e:?}")))?;
|
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() {
|
if let Some(s) = self.output.as_mut() {
|
||||||
s.start()
|
s.start()
|
||||||
|
|||||||
@@ -459,10 +459,18 @@ pub async fn connect(
|
|||||||
identity: None,
|
identity: None,
|
||||||
ready_timeout: Duration::from_secs(15),
|
ready_timeout: Duration::from_secs(15),
|
||||||
};
|
};
|
||||||
let snap = runtime()
|
let snap = match runtime()
|
||||||
.spawn(async move { session().connect(cfg).await })
|
.spawn(async move { session().connect(cfg).await })
|
||||||
.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())
|
Ok(snap.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user