Add voice api calls to steamosctl and proxy.

Added listing of screen reader locales.
Added listing of voices for a given locale.
Added getting and setting of voice property.
This commit is contained in:
Jeremy Whiting 2025-06-27 16:52:40 -06:00 committed by Jeremy Whiting
parent 02a15c9295
commit afa0eddf41
5 changed files with 82 additions and 30 deletions

View file

@ -359,6 +359,11 @@
--> -->
<property name="VoiceLocales" type="as" access="read"/> <property name="VoiceLocales" type="as" access="read"/>
<!--
Map of voice names per locale
-->
<property name="VoicesForLocale" type="a{sas}" access="read"/>
<!-- <!--
Trigger Action Trigger Action
@ -386,19 +391,6 @@
<arg type="t" name="timestamp" direction="in"/> <arg type="t" name="timestamp" direction="in"/>
</method> </method>
<!--
Get the voices for a given locale
Get a list of voices for a given locale
@locale: The locale to get the voices for. e.g. en-US
@voices: A list of voice names to present to the user
-->
<method name="GetVoicesForLocale">
<arg type="s" name="locale" direction="in"/>
<arg type="as" name="voices" direction="out"/>
</method>
</interface> </interface>
<!-- <!--

View file

@ -5,7 +5,7 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
use anyhow::Result; use anyhow::{anyhow, Result};
use clap::{ArgAction, Parser, Subcommand}; use clap::{ArgAction, Parser, Subcommand};
use itertools::Itertools; use itertools::Itertools;
use nix::time::{clock_gettime, ClockId}; use nix::time::{clock_gettime, ClockId};
@ -254,6 +254,24 @@ enum Commands {
mode: ScreenReaderMode, mode: ScreenReaderMode,
}, },
/// Get screen reader known locales
GetScreenReaderLocales,
/// Get screen reader voices for given locale
GetScreenReaderVoicesForLocale {
/// Valid locales can be found using get-screen-reader-locales.
locale: String,
},
/// Get screen reader voice
GetScreenReaderVoice,
/// Set screen reader voice
SetScreenReaderVoice {
/// The voice name to use for screen reader. Valid voices can be found using get-screen-reader-voices-for-locale
voice: String,
},
/// Trigger screen reader action /// Trigger screen reader action
TriggerScreenReaderAction { TriggerScreenReaderAction {
/// Valid actions are /// Valid actions are
@ -638,6 +656,34 @@ async fn main() -> Result<()> {
.trigger_action(*action as u32, now.try_into()?) .trigger_action(*action as u32, now.try_into()?)
.await?; .await?;
} }
Commands::GetScreenReaderVoice => {
let proxy = ScreenReader0Proxy::new(&conn).await?;
let voice = proxy.voice().await?;
println!("Voice: {voice}");
}
Commands::SetScreenReaderVoice { voice } => {
let proxy = ScreenReader0Proxy::new(&conn).await?;
proxy.set_voice(voice).await?;
}
Commands::GetScreenReaderLocales => {
let proxy = ScreenReader0Proxy::new(&conn).await?;
let locales = proxy.voice_locales().await?;
println!("Locales:\n");
for locale in locales.into_iter().sorted() {
println!("- {locale}");
}
}
Commands::GetScreenReaderVoicesForLocale { locale } => {
let proxy = ScreenReader0Proxy::new(&conn).await?;
let voice_list = proxy.voices_for_locale().await?;
let voices = voice_list
.get(locale)
.ok_or_else(|| anyhow!("Unable to load voices map"))?;
println!("Voices:\n");
for voice in voices.iter().sorted() {
println!("- {voice}");
}
}
} }
Ok(()) Ok(())

View file

@ -734,6 +734,11 @@ impl ScreenReader0 {
self.screen_reader.get_voice_locales() self.screen_reader.get_voice_locales()
} }
#[zbus(property)]
async fn voices_for_locale(&self) -> HashMap<String, Vec<String>> {
self.screen_reader.get_voices()
}
async fn trigger_action(&mut self, a: u32, timestamp: u64) -> fdo::Result<()> { async fn trigger_action(&mut self, a: u32, timestamp: u64) -> fdo::Result<()> {
let action = match ScreenReaderAction::try_from(a) { let action = match ScreenReaderAction::try_from(a) {
Ok(action) => action, Ok(action) => action,
@ -744,12 +749,6 @@ impl ScreenReader0 {
.await .await
.map_err(to_zbus_fdo_error) .map_err(to_zbus_fdo_error)
} }
async fn get_voices(&self, locale: &str) -> fdo::Result<Vec<String>> {
self.screen_reader
.get_voices(locale)
.ok_or(fdo::Error::Failed(String::from("No voices found")))
}
} }
#[interface(name = "com.steampowered.SteamOSManager1.Storage1")] #[interface(name = "com.steampowered.SteamOSManager1.Storage1")]

View file

@ -19,12 +19,21 @@ use zbus::proxy;
assume_defaults = true assume_defaults = true
)] )]
pub trait ScreenReader0 { pub trait ScreenReader0 {
/// TriggerAction method
fn trigger_action(&self, action: u32, timestamp: u64) -> zbus::Result<()>;
/// Enabled property /// Enabled property
#[zbus(property)] #[zbus(property)]
fn enabled(&self) -> zbus::Result<bool>; fn enabled(&self) -> zbus::Result<bool>;
#[zbus(property)] #[zbus(property)]
fn set_enabled(&self, value: bool) -> zbus::Result<()>; fn set_enabled(&self, value: bool) -> zbus::Result<()>;
/// Mode property
#[zbus(property)]
fn mode(&self) -> zbus::Result<u32>;
#[zbus(property)]
fn set_mode(&self, value: u32) -> zbus::Result<()>;
/// Pitch property /// Pitch property
#[zbus(property)] #[zbus(property)]
fn pitch(&self) -> zbus::Result<f64>; fn pitch(&self) -> zbus::Result<f64>;
@ -37,17 +46,23 @@ pub trait ScreenReader0 {
#[zbus(property)] #[zbus(property)]
fn set_rate(&self, value: f64) -> zbus::Result<()>; fn set_rate(&self, value: f64) -> zbus::Result<()>;
/// Voice property
#[zbus(property)]
fn voice(&self) -> zbus::Result<String>;
#[zbus(property)]
fn set_voice(&self, value: &str) -> zbus::Result<()>;
/// VoiceLocales property
#[zbus(property)]
fn voice_locales(&self) -> zbus::Result<Vec<String>>;
/// VoicesForLocale property
#[zbus(property)]
fn voices_for_locale(&self) -> zbus::Result<std::collections::HashMap<String, Vec<String>>>;
/// Volume property /// Volume property
#[zbus(property)] #[zbus(property)]
fn volume(&self) -> zbus::Result<f64>; fn volume(&self) -> zbus::Result<f64>;
#[zbus(property)] #[zbus(property)]
fn set_volume(&self, value: f64) -> zbus::Result<()>; fn set_volume(&self, value: f64) -> zbus::Result<()>;
/// Mode property
#[zbus(property)]
fn mode(&self) -> zbus::Result<u32>;
#[zbus(property)]
fn set_mode(&self, mode: u32) -> zbus::Result<()>;
fn trigger_action(&self, action: u32, timestamp: u64) -> zbus::Result<()>;
} }

View file

@ -170,8 +170,8 @@ impl<'dbus> OrcaManager<'dbus> {
Ok(()) Ok(())
} }
pub fn get_voices(&self, locale: &str) -> Option<Vec<String>> { pub fn get_voices(&self) -> HashMap<String, Vec<String>> {
self.voices_by_language.get(locale).cloned() self.voices_by_language.clone()
} }
pub fn get_voice_locales(&self) -> Vec<String> { pub fn get_voice_locales(&self) -> Vec<String> {