mirror of
https://gitlab.steamos.cloud/holo/steamos-manager.git
synced 2025-07-05 14:10:34 -04:00
Add screenreader support to steamos-manager.
Add ScreenReader1 interface to xml to enable/disable using screen reader. Implements getting and setting pitch, rate, volume, enabled. Restarts orca when any of the above properties are changed. Load values from orca user-settings.conf Use systemd unit to start/stop/restart orca.
This commit is contained in:
parent
b926dbd50b
commit
4fd9ccdd2e
6 changed files with 432 additions and 0 deletions
25
Cargo.lock
generated
25
Cargo.lock
generated
|
@ -437,6 +437,12 @@ dependencies = [
|
||||||
"either",
|
"either",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
|
@ -725,6 +731,12 @@ version = "1.0.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
|
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "1.0.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.219"
|
version = "1.0.219"
|
||||||
|
@ -745,6 +757,18 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.140"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"memchr",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_repr"
|
name = "serde_repr"
|
||||||
version = "0.1.20"
|
version = "0.1.20"
|
||||||
|
@ -815,6 +839,7 @@ dependencies = [
|
||||||
"num_enum",
|
"num_enum",
|
||||||
"regex",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"strum",
|
"strum",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
|
|
@ -19,6 +19,7 @@ nix = { version = "0.30", default-features = false, features = ["fs", "poll", "s
|
||||||
num_enum = "0.7"
|
num_enum = "0.7"
|
||||||
regex = "1"
|
regex = "1"
|
||||||
serde = { version = "1.0", default-features = false, features = ["derive"] }
|
serde = { version = "1.0", default-features = false, features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
||||||
strum = { version = "0.27", features = ["derive"] }
|
strum = { version = "0.27", features = ["derive"] }
|
||||||
tempfile = "3"
|
tempfile = "3"
|
||||||
tokio = { version = "1", default-features = false, features = ["fs", "io-std", "io-util", "macros", "process", "rt-multi-thread", "signal", "sync"] }
|
tokio = { version = "1", default-features = false, features = ["fs", "io-std", "io-util", "macros", "process", "rt-multi-thread", "signal", "sync"] }
|
||||||
|
|
|
@ -298,6 +298,40 @@
|
||||||
|
|
||||||
</interface>
|
</interface>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
com.steampowered.SteamOSManager1.ScreenReader1
|
||||||
|
@short_description: Optional interface for managing a screen reader.
|
||||||
|
-->
|
||||||
|
<interface name="com.steampowered.SteamOSManager1.ScreenReader1">
|
||||||
|
<!--
|
||||||
|
Enabled
|
||||||
|
|
||||||
|
True if screen reader is enabled, false otherwise.
|
||||||
|
-->
|
||||||
|
<property name="Enabled" type="b" access="readwrite"/>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Rate
|
||||||
|
|
||||||
|
The rate of speech output. Valid values are 0 for slowest to 100 for fastest.
|
||||||
|
-->
|
||||||
|
<property name="Rate" type="d" access="readwrite"/>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Pitch
|
||||||
|
|
||||||
|
The pitch for speech output. Valid values are 0.0 for lowest, and 10.0 for highest.
|
||||||
|
-->
|
||||||
|
<property name="Pitch" type="d" access="readwrite"/>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Volume
|
||||||
|
|
||||||
|
The volume for speech output. Valid values ar 0.0 for off, 10.0 for highest.
|
||||||
|
-->
|
||||||
|
<property name="Volume" type="d" access="readwrite"/>
|
||||||
|
</interface>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
com.steampowered.SteamOSManager1.Storage1
|
com.steampowered.SteamOSManager1.Storage1
|
||||||
@short_description: Optional interface for managing storage devices
|
@short_description: Optional interface for managing storage devices
|
||||||
|
|
|
@ -25,6 +25,7 @@ mod job;
|
||||||
mod manager;
|
mod manager;
|
||||||
mod platform;
|
mod platform;
|
||||||
mod process;
|
mod process;
|
||||||
|
mod screenreader;
|
||||||
mod sls;
|
mod sls;
|
||||||
mod systemd;
|
mod systemd;
|
||||||
mod udev;
|
mod udev;
|
||||||
|
|
|
@ -31,6 +31,7 @@ use crate::power::{
|
||||||
get_gpu_clocks, get_gpu_clocks_range, get_gpu_performance_level, get_gpu_power_profile,
|
get_gpu_clocks, get_gpu_clocks_range, get_gpu_performance_level, get_gpu_power_profile,
|
||||||
get_max_charge_level, get_platform_profile, tdp_limit_manager, TdpManagerCommand,
|
get_max_charge_level, get_platform_profile, tdp_limit_manager, TdpManagerCommand,
|
||||||
};
|
};
|
||||||
|
use crate::screenreader::OrcaManager;
|
||||||
use crate::wifi::{
|
use crate::wifi::{
|
||||||
get_wifi_backend, get_wifi_power_management_state, list_wifi_interfaces, WifiBackend,
|
get_wifi_backend, get_wifi_power_management_state, list_wifi_interfaces, WifiBackend,
|
||||||
};
|
};
|
||||||
|
@ -153,6 +154,10 @@ struct PerformanceProfile1 {
|
||||||
tdp_limit_manager: UnboundedSender<TdpManagerCommand>,
|
tdp_limit_manager: UnboundedSender<TdpManagerCommand>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ScreenReader1 {
|
||||||
|
screen_reader: OrcaManager<'static>,
|
||||||
|
}
|
||||||
|
|
||||||
struct Storage1 {
|
struct Storage1 {
|
||||||
proxy: Proxy<'static>,
|
proxy: Proxy<'static>,
|
||||||
job_manager: UnboundedSender<JobManagerCommand>,
|
job_manager: UnboundedSender<JobManagerCommand>,
|
||||||
|
@ -618,6 +623,80 @@ impl PerformanceProfile1 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ScreenReader1 {
|
||||||
|
async fn new(connection: &Connection) -> Result<ScreenReader1> {
|
||||||
|
let screen_reader = OrcaManager::new(connection).await?;
|
||||||
|
Ok(ScreenReader1 { screen_reader })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[interface(name = "com.steampowered.SteamOSManager1.ScreenReader1")]
|
||||||
|
impl ScreenReader1 {
|
||||||
|
#[zbus(property)]
|
||||||
|
async fn enabled(&self) -> fdo::Result<bool> {
|
||||||
|
match self.screen_reader.enabled().await {
|
||||||
|
Ok(enabled) => Ok(enabled),
|
||||||
|
Err(e) => Err(to_zbus_fdo_error(e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[zbus(property)]
|
||||||
|
async fn set_enabled(&mut self, enabled: bool) -> fdo::Result<()> {
|
||||||
|
self.screen_reader
|
||||||
|
.set_enabled(enabled)
|
||||||
|
.await
|
||||||
|
.map_err(to_zbus_fdo_error)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[zbus(property)]
|
||||||
|
async fn rate(&self) -> fdo::Result<f64> {
|
||||||
|
match self.screen_reader.rate().await {
|
||||||
|
Ok(rate) => Ok(rate),
|
||||||
|
Err(e) => Err(to_zbus_fdo_error(e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[zbus(property)]
|
||||||
|
async fn set_rate(&mut self, rate: f64) -> fdo::Result<()> {
|
||||||
|
self.screen_reader
|
||||||
|
.set_rate(rate)
|
||||||
|
.await
|
||||||
|
.map_err(to_zbus_fdo_error)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[zbus(property)]
|
||||||
|
async fn pitch(&self) -> fdo::Result<f64> {
|
||||||
|
match self.screen_reader.pitch().await {
|
||||||
|
Ok(pitch) => Ok(pitch),
|
||||||
|
Err(e) => Err(to_zbus_fdo_error(e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[zbus(property)]
|
||||||
|
async fn set_pitch(&mut self, pitch: f64) -> fdo::Result<()> {
|
||||||
|
self.screen_reader
|
||||||
|
.set_pitch(pitch)
|
||||||
|
.await
|
||||||
|
.map_err(to_zbus_fdo_error)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[zbus(property)]
|
||||||
|
async fn volume(&self) -> fdo::Result<f64> {
|
||||||
|
match self.screen_reader.volume().await {
|
||||||
|
Ok(volume) => Ok(volume),
|
||||||
|
Err(e) => Err(to_zbus_fdo_error(e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[zbus(property)]
|
||||||
|
async fn set_volume(&mut self, volume: f64) -> fdo::Result<()> {
|
||||||
|
self.screen_reader
|
||||||
|
.set_volume(volume)
|
||||||
|
.await
|
||||||
|
.map_err(to_zbus_fdo_error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[interface(name = "com.steampowered.SteamOSManager1.Storage1")]
|
#[interface(name = "com.steampowered.SteamOSManager1.Storage1")]
|
||||||
impl Storage1 {
|
impl Storage1 {
|
||||||
async fn format_device(
|
async fn format_device(
|
||||||
|
@ -919,6 +998,7 @@ pub(crate) async fn create_interfaces(
|
||||||
proxy: proxy.clone(),
|
proxy: proxy.clone(),
|
||||||
channel: daemon,
|
channel: daemon,
|
||||||
};
|
};
|
||||||
|
let screen_reader = ScreenReader1::new(&session).await?;
|
||||||
let wifi_debug = WifiDebug1 {
|
let wifi_debug = WifiDebug1 {
|
||||||
proxy: proxy.clone(),
|
proxy: proxy.clone(),
|
||||||
};
|
};
|
||||||
|
@ -971,6 +1051,8 @@ pub(crate) async fn create_interfaces(
|
||||||
|
|
||||||
object_server.at(MANAGER_PATH, manager2).await?;
|
object_server.at(MANAGER_PATH, manager2).await?;
|
||||||
|
|
||||||
|
object_server.at(MANAGER_PATH, screen_reader).await?;
|
||||||
|
|
||||||
if steam_deck_variant().await.unwrap_or_default() == SteamDeckVariant::Galileo {
|
if steam_deck_variant().await.unwrap_or_default() == SteamDeckVariant::Galileo {
|
||||||
object_server.at(MANAGER_PATH, wifi_debug).await?;
|
object_server.at(MANAGER_PATH, wifi_debug).await?;
|
||||||
}
|
}
|
||||||
|
|
289
src/screenreader.rs
Normal file
289
src/screenreader.rs
Normal file
|
@ -0,0 +1,289 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2025 Collabora Ltd.
|
||||||
|
* Copyright © 2025 Valve Software
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Read;
|
||||||
|
use std::io::Write;
|
||||||
|
//use std::process::{Child, Command};
|
||||||
|
use serde_json::{json, Value};
|
||||||
|
use std::process::Command;
|
||||||
|
use tracing::{info, warn};
|
||||||
|
use zbus::Connection;
|
||||||
|
|
||||||
|
use crate::systemd::SystemdUnit;
|
||||||
|
|
||||||
|
const ORCA_SETTINGS: &str = "/home/deck/.local/share/orca/user-settings.conf";
|
||||||
|
const PITCH_SETTING: &str = "average-pitch";
|
||||||
|
const RATE_SETTING: &str = "rate";
|
||||||
|
const VOLUME_SETTING: &str = "gain";
|
||||||
|
|
||||||
|
pub(crate) struct OrcaManager<'dbus> {
|
||||||
|
orca_unit: SystemdUnit<'dbus>,
|
||||||
|
rate: f64,
|
||||||
|
pitch: f64,
|
||||||
|
volume: f64,
|
||||||
|
enabled: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'dbus> OrcaManager<'dbus> {
|
||||||
|
pub async fn new(connection: &Connection) -> Result<OrcaManager<'dbus>> {
|
||||||
|
let mut manager = OrcaManager {
|
||||||
|
orca_unit: SystemdUnit::new(connection.clone(), "orca.service").await?,
|
||||||
|
rate: 1.0,
|
||||||
|
pitch: 1.0,
|
||||||
|
volume: 1.0,
|
||||||
|
enabled: true,
|
||||||
|
};
|
||||||
|
manager.load_values()?;
|
||||||
|
Ok(manager)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn enabled(&self) -> Result<bool> {
|
||||||
|
// Check if screen reader is enabled
|
||||||
|
Ok(self.enabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn set_enabled(&mut self, enable: bool) -> std::io::Result<()> {
|
||||||
|
// Set screen reader enabled based on value of enable
|
||||||
|
if enable {
|
||||||
|
// Enable screen reader gsettings
|
||||||
|
let _ = Command::new("gsettings")
|
||||||
|
.args([
|
||||||
|
"set",
|
||||||
|
"org.gnome.desktop.a11y.applications",
|
||||||
|
"screen-reader-enabled",
|
||||||
|
"true",
|
||||||
|
])
|
||||||
|
.spawn();
|
||||||
|
// Set orca enabled also
|
||||||
|
let _setting_result = self.set_orca_enabled(true);
|
||||||
|
let _result = self.restart_orca().await;
|
||||||
|
} else {
|
||||||
|
// Disable screen reader gsettings
|
||||||
|
let _ = Command::new("gsettings")
|
||||||
|
.args([
|
||||||
|
"set",
|
||||||
|
"org.gnome.desktop.a11y.applications",
|
||||||
|
"screen-reader-enabled",
|
||||||
|
"false",
|
||||||
|
])
|
||||||
|
.spawn();
|
||||||
|
// Set orca disabled also
|
||||||
|
let _setting_result = self.set_orca_enabled(false);
|
||||||
|
// Stop orca
|
||||||
|
let _result = self.stop_orca().await;
|
||||||
|
}
|
||||||
|
self.enabled = enable;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn pitch(&self) -> Result<f64> {
|
||||||
|
Ok(self.pitch)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn set_pitch(&mut self, pitch: f64) -> Result<()> {
|
||||||
|
info!("set_pitch called with {:?}", pitch);
|
||||||
|
|
||||||
|
let result = self.set_orca_option(PITCH_SETTING.to_owned(), pitch);
|
||||||
|
match result {
|
||||||
|
Ok(_) => {
|
||||||
|
self.pitch = pitch;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(_) => Err(anyhow!("Unable to set orca pitch value")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn rate(&self) -> Result<f64> {
|
||||||
|
Ok(self.rate)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn set_rate(&mut self, rate: f64) -> Result<()> {
|
||||||
|
info!("set_rate called with {:?}", rate);
|
||||||
|
|
||||||
|
let result = self.set_orca_option(RATE_SETTING.to_owned(), rate);
|
||||||
|
match result {
|
||||||
|
Ok(_) => {
|
||||||
|
self.rate = rate;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(_) => Err(anyhow!("Unable to set orca rate")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn volume(&self) -> Result<f64> {
|
||||||
|
Ok(self.volume)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn set_volume(&mut self, volume: f64) -> Result<()> {
|
||||||
|
info!("set_volume called with {:?}", volume);
|
||||||
|
|
||||||
|
let result = self.set_orca_option(VOLUME_SETTING.to_owned(), volume);
|
||||||
|
match result {
|
||||||
|
Ok(_) => {
|
||||||
|
self.volume = volume;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(_) => Err(anyhow!("Unable to set orca volume")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_orca_enabled(&mut self, enabled: bool) -> Result<()> {
|
||||||
|
// Change json file
|
||||||
|
let mut file = File::open(ORCA_SETTINGS)?;
|
||||||
|
let mut data = String::new();
|
||||||
|
file.read_to_string(&mut data)?;
|
||||||
|
|
||||||
|
let mut json: Value = serde_json::from_str(&data)?;
|
||||||
|
|
||||||
|
if let Some(general) = json.get_mut("general") {
|
||||||
|
if let Some(enable_speech) = general.get_mut("enableSpeech") {
|
||||||
|
*enable_speech = json!(&enabled);
|
||||||
|
} else {
|
||||||
|
warn!("No enabledSpeech value in general in orca settings");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn!("No general section in orca settings");
|
||||||
|
}
|
||||||
|
|
||||||
|
data = serde_json::to_string_pretty(&json)?;
|
||||||
|
|
||||||
|
let mut out_file = File::create(ORCA_SETTINGS)?;
|
||||||
|
match out_file.write_all(&data.into_bytes()) {
|
||||||
|
Ok(_) => {
|
||||||
|
self.enabled = enabled;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(_) => Err(anyhow!("Unable to write orca settings file")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_values(&mut self) -> Result<()> {
|
||||||
|
info!("Loading orca values from user-settings.conf");
|
||||||
|
let mut file = File::open(ORCA_SETTINGS)?;
|
||||||
|
let mut data = String::new();
|
||||||
|
file.read_to_string(&mut data)?;
|
||||||
|
|
||||||
|
let json: Value = serde_json::from_str(&data)?;
|
||||||
|
|
||||||
|
if let Some(profiles) = json.get("profiles") {
|
||||||
|
if let Some(default_profile) = profiles.get("default") {
|
||||||
|
if let Some(voices) = default_profile.get("voices") {
|
||||||
|
if let Some(default_voice) = voices.get("default") {
|
||||||
|
if let Some(pitch) = default_voice.get(PITCH_SETTING.to_owned()) {
|
||||||
|
self.pitch = pitch
|
||||||
|
.as_f64()
|
||||||
|
.expect("Unable to convert orca pitch setting to float value");
|
||||||
|
} else {
|
||||||
|
warn!("Unable to load default pitch from orca user-settings.conf");
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(rate) = default_voice.get(RATE_SETTING.to_owned()) {
|
||||||
|
self.rate = rate
|
||||||
|
.as_f64()
|
||||||
|
.expect("Unable to convert orca rate setting to float value");
|
||||||
|
} else {
|
||||||
|
warn!("Unable to load default voice rate from orca user-settings.conf");
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(volume) = default_voice.get(VOLUME_SETTING.to_owned()) {
|
||||||
|
self.volume = volume
|
||||||
|
.as_f64()
|
||||||
|
.expect("Unable to convert orca volume value to float value");
|
||||||
|
} else {
|
||||||
|
warn!(
|
||||||
|
"Unable to load default voice volume from orca user-settings.conf"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn!("Orca user-settings.conf missing default voice");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn!("Orca user-settings.conf missing voices list");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn!("Orca user-settings.conf missing default profile");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn!("Orca user-settings.conf missing profiles");
|
||||||
|
}
|
||||||
|
info!(
|
||||||
|
"Done loading orca user-settings.conf, values: Rate: {:?}, Pitch: {:?}, Volume: {:?}",
|
||||||
|
self.rate, self.pitch, self.volume
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_orca_option(&self, option: String, value: f64) -> Result<()> {
|
||||||
|
// Verify option is one we know about
|
||||||
|
// Verify value is in range
|
||||||
|
// Change json file
|
||||||
|
let mut file = File::open(ORCA_SETTINGS)?;
|
||||||
|
let mut data = String::new();
|
||||||
|
file.read_to_string(&mut data)?;
|
||||||
|
|
||||||
|
let mut json: Value = serde_json::from_str(&data)?;
|
||||||
|
|
||||||
|
if let Some(profiles) = json.get_mut("profiles") {
|
||||||
|
if let Some(default_profile) = profiles.get_mut("default") {
|
||||||
|
if let Some(voices) = default_profile.get_mut("voices") {
|
||||||
|
if let Some(default_voice) = voices.get_mut("default") {
|
||||||
|
if let Some(mut_option) = default_voice.get_mut(&option) {
|
||||||
|
*mut_option = json!(value);
|
||||||
|
} else {
|
||||||
|
let object = default_voice.as_object_mut().ok_or(anyhow!(
|
||||||
|
"Unable to generate mutable object for adding {:?} with value {:?}",
|
||||||
|
&option,
|
||||||
|
value
|
||||||
|
))?;
|
||||||
|
object.insert(option, json!(value));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn!(
|
||||||
|
"No default voice in voices list to set {:?} to {:?} in",
|
||||||
|
&option, value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn!(
|
||||||
|
"No voices in default profile to set {:?} to {:?} in",
|
||||||
|
&option, value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn!("No default profile to set {:?} to {:?} in", &option, value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn!("No profiles in orca user-settings.conf to modify");
|
||||||
|
}
|
||||||
|
|
||||||
|
data = serde_json::to_string_pretty(&json)?;
|
||||||
|
|
||||||
|
let mut out_file = File::create(ORCA_SETTINGS)?;
|
||||||
|
match out_file.write_all(&data.into_bytes()) {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(_) => Err(anyhow!("Unable to write orca settings file")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn restart_orca(&self) -> Result<()> {
|
||||||
|
info!("Restarting orca...");
|
||||||
|
let _result = self.orca_unit.restart().await;
|
||||||
|
info!("Done restarting orca...");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn stop_orca(&self) -> Result<()> {
|
||||||
|
// Stop orca user unit
|
||||||
|
info!("Stopping orca...");
|
||||||
|
let _result = self.orca_unit.stop().await;
|
||||||
|
info!("Done stopping orca...");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue