fix: refine linux voice runtime behavior
This commit is contained in:
@@ -17,11 +17,13 @@
|
||||
//! * `try_select` runs a synchronous portal-version probe on
|
||||
//! the blocking proxy. Failure → `None` → Focused fallback.
|
||||
//! * `start(gate, binding)` spawns a worker tokio task that
|
||||
//! owns an async `zbus::Connection`, calls `CreateSession`,
|
||||
//! then `BindShortcuts` (sentinel id `"chanora-ptt"`). The
|
||||
//! portal opens its own system dialog asking the user to
|
||||
//! pick a key; while the dialog is open the engine continues
|
||||
//! at L0Focused — the audio path is not blocked.
|
||||
//! owns an async `zbus::Connection` and calls `CreateSession`.
|
||||
//! If a binding was already persisted, it also calls
|
||||
//! `BindShortcuts` (sentinel id `"chanora-ptt"`). Otherwise
|
||||
//! `BindShortcuts` waits for the user's explicit Configure
|
||||
//! action, which is when the portal opens its system dialog.
|
||||
//! While the dialog is open the engine continues at L0Focused —
|
||||
//! the audio path is not blocked.
|
||||
//! * Once the user accepts, the task subscribes to
|
||||
//! `Activated`/`Deactivated` signals scoped to the session
|
||||
//! handle and calls `gate.set(true/false)` accordingly.
|
||||
@@ -219,7 +221,7 @@ struct BackendInner {
|
||||
|
||||
enum WorkerCmd {
|
||||
/// Rebind: re-issue `BindShortcuts` on the same session.
|
||||
Rebind,
|
||||
Bind,
|
||||
/// Stop: close the session and exit.
|
||||
Stop,
|
||||
}
|
||||
@@ -296,9 +298,10 @@ impl DesktopPttBackend for LinuxGnomeWaylandBackend {
|
||||
// the bridge's tokio runtime, so this is satisfied.
|
||||
let (cmd_tx, cmd_rx) = mpsc::unbounded_channel();
|
||||
let desc_tx = self.desc_tx.clone();
|
||||
let bind_on_start = binding.input_class != PttInputClass::None;
|
||||
let class_hint = binding.input_class;
|
||||
let worker = tokio::spawn(async move {
|
||||
run_worker(gate, cmd_rx, desc_tx, class_hint).await;
|
||||
run_worker(gate, cmd_rx, desc_tx, class_hint, bind_on_start).await;
|
||||
});
|
||||
// Stash command + worker handles. `try_lock` is fine: the
|
||||
// backend isn't yet shared, and `start` is called once at
|
||||
@@ -350,7 +353,7 @@ impl DesktopPttBackend for LinuxGnomeWaylandBackend {
|
||||
// only — the portal decides the actual binding.
|
||||
if let Ok(inner) = self.inner.try_lock() {
|
||||
if let Some(tx) = inner.cmd_tx.as_ref() {
|
||||
let _ = tx.send(WorkerCmd::Rebind);
|
||||
let _ = tx.send(WorkerCmd::Bind);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
@@ -373,6 +376,7 @@ async fn run_worker(
|
||||
mut cmd_rx: mpsc::UnboundedReceiver<WorkerCmd>,
|
||||
desc_tx: watch::Sender<PttBackendDescriptor>,
|
||||
initial_class_hint: PttInputClass,
|
||||
bind_on_start: bool,
|
||||
) {
|
||||
// Open an async D-Bus session connection. If this fails we
|
||||
// emit a warning and exit; the descriptor stays at L0Focused
|
||||
@@ -417,26 +421,13 @@ async fn run_worker(
|
||||
"linux ptt: portal session created"
|
||||
);
|
||||
|
||||
// Bind the initial shortcut. The portal opens its own dialog.
|
||||
match bind_shortcut(&proxy, &conn, &session_handle).await {
|
||||
Ok(class) => publish_bound(&desc_tx, class.unwrap_or(initial_class_hint)),
|
||||
Err(BindError::Cancelled) => {
|
||||
warn!(
|
||||
target: "chanora_audio",
|
||||
bind_status = "cancelled",
|
||||
"linux ptt: user cancelled BindShortcuts; descriptor stays at L0Focused"
|
||||
);
|
||||
publish_l0(&desc_tx);
|
||||
}
|
||||
Err(BindError::Failed(e)) => {
|
||||
warn!(
|
||||
target: "chanora_audio",
|
||||
bind_status = "failed",
|
||||
error = %e,
|
||||
"linux ptt: BindShortcuts failed; descriptor stays at L0Focused"
|
||||
);
|
||||
publish_l0(&desc_tx);
|
||||
}
|
||||
if bind_on_start {
|
||||
run_bind_shortcut(&proxy, &conn, &session_handle, &desc_tx, initial_class_hint).await;
|
||||
} else {
|
||||
info!(
|
||||
target: "chanora_audio",
|
||||
"linux ptt: portal session ready; waiting for explicit BindShortcuts request"
|
||||
);
|
||||
}
|
||||
|
||||
// Subscribe to Activated / Deactivated signals scoped to the
|
||||
@@ -468,12 +459,8 @@ async fn run_worker(
|
||||
tokio::select! {
|
||||
cmd = cmd_rx.recv() => {
|
||||
match cmd {
|
||||
Some(WorkerCmd::Rebind) => {
|
||||
match bind_shortcut(&proxy, &conn, &session_handle).await {
|
||||
Ok(class) => publish_bound(&desc_tx, class.unwrap_or(initial_class_hint)),
|
||||
Err(BindError::Cancelled) => publish_l0(&desc_tx),
|
||||
Err(BindError::Failed(_)) => publish_l0(&desc_tx),
|
||||
}
|
||||
Some(WorkerCmd::Bind) => {
|
||||
run_bind_shortcut(&proxy, &conn, &session_handle, &desc_tx, initial_class_hint).await;
|
||||
}
|
||||
Some(WorkerCmd::Stop) | None => {
|
||||
// Close the portal session via the
|
||||
@@ -586,6 +573,35 @@ async fn bind_shortcut(
|
||||
Ok(class)
|
||||
}
|
||||
|
||||
async fn run_bind_shortcut(
|
||||
proxy: &GlobalShortcutsProxy<'_>,
|
||||
conn: &AsyncConnection,
|
||||
session_handle: &zbus::zvariant::OwnedObjectPath,
|
||||
desc_tx: &watch::Sender<PttBackendDescriptor>,
|
||||
class_hint: PttInputClass,
|
||||
) {
|
||||
match bind_shortcut(proxy, conn, session_handle).await {
|
||||
Ok(class) => publish_bound(desc_tx, class.unwrap_or(class_hint)),
|
||||
Err(BindError::Cancelled) => {
|
||||
warn!(
|
||||
target: "chanora_audio",
|
||||
bind_status = "cancelled",
|
||||
"linux ptt: user cancelled BindShortcuts; descriptor stays at L0Focused"
|
||||
);
|
||||
publish_l0(desc_tx);
|
||||
}
|
||||
Err(BindError::Failed(e)) => {
|
||||
warn!(
|
||||
target: "chanora_audio",
|
||||
bind_status = "failed",
|
||||
error = %e,
|
||||
"linux ptt: BindShortcuts failed; descriptor stays at L0Focused"
|
||||
);
|
||||
publish_l0(desc_tx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Wait for the `Response` signal on `request_path`. Returns the
|
||||
/// `results` dict on success (response code 0) or an Error
|
||||
/// otherwise.
|
||||
|
||||
Reference in New Issue
Block a user