use anyhow::Result;
use serde::{Deserialize, Serialize};
use std::process::Command;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AudioDevice {
pub id: String,
pub name: String,
pub is_default: bool,
}
pub fn get_volume() -> Result<u32> {
#[cfg(target_os = "windows")]
{
let output = Command::new("powershell")
.args(["-Command", "(Get-AudioDevice -PlaybackVolume).Volume"])
.output();
if let Ok(output) = output {
if let Ok(vol_str) = String::from_utf8(output.stdout) {
if let Ok(vol) = vol_str.trim().parse::<f64>() {
return Ok((vol * 100.0) as u32);
}
}
}
Ok(50) }
#[cfg(not(target_os = "windows"))]
{
Ok(50) }
}
#[cfg(target_os = "windows")]
pub fn set_volume(volume: u32) -> Result<()> {
let volume = volume.clamp(0, 100);
let volume_f = volume as f64 / 100.0;
let _ = Command::new("powershell")
.args([
"-Command",
&format!("Set-AudioDevice -PlaybackVolume {}", volume_f),
])
.output();
Ok(())
}
#[cfg(not(target_os = "windows"))]
pub fn set_volume(volume: u32) -> Result<()> {
let _ = volume;
Ok(())
}
pub fn volume_up(delta: u32) -> Result<()> {
let current = get_volume()?;
set_volume(current + delta)
}
pub fn volume_down(delta: u32) -> Result<()> {
let current = get_volume()?;
set_volume(current.saturating_sub(delta))
}
#[cfg(target_os = "windows")]
pub fn mute() -> Result<()> {
let _ = Command::new("powershell")
.args([
"-Command",
"(New-Object -ComObject WScript.Shell).SendKeys([char]173)",
])
.output();
Ok(())
}
#[cfg(not(target_os = "windows"))]
pub fn mute() -> Result<()> {
Ok(())
}
#[cfg(target_os = "windows")]
pub fn unmute() -> Result<()> {
let _ = Command::new("powershell")
.args([
"-Command",
"(New-Object -ComObject WScript.Shell).SendKeys([char]173)",
])
.output();
Ok(())
}
#[cfg(not(target_os = "windows"))]
pub fn unmute() -> Result<()> {
Ok(())
}
#[cfg(target_os = "windows")]
pub fn list_output_devices() -> Result<Vec<AudioDevice>> {
let output = Command::new("powershell")
.args([
"-Command",
"Get-AudioDevice -List | ForEach-Object { $_.FriendlyName }",
])
.output();
let mut devices = vec![AudioDevice {
id: "default".to_string(),
name: "Default Output Device".to_string(),
is_default: true,
}];
if let Ok(output) = output {
if let Ok(devices_str) = String::from_utf8(output.stdout) {
for (i, line) in devices_str.lines().enumerate() {
if !line.is_empty() {
devices.push(AudioDevice {
id: format!("device_{}", i),
name: line.to_string(),
is_default: false,
});
}
}
}
}
Ok(devices)
}
#[cfg(not(target_os = "windows"))]
pub fn list_output_devices() -> Result<Vec<AudioDevice>> {
Ok(vec![
AudioDevice {
id: "default".to_string(),
name: "Default Output Device".to_string(),
is_default: true,
},
AudioDevice {
id: "speakers".to_string(),
name: "Speakers".to_string(),
is_default: false,
},
AudioDevice {
id: "headphones".to_string(),
name: "Headphones".to_string(),
is_default: false,
},
])
}
#[cfg(target_os = "windows")]
pub fn set_output_device(device_id: &str) -> Result<()> {
let _ = Command::new("powershell")
.args(["-Command", &format!("Set-AudioDevice -Index {}", device_id)])
.output();
Ok(())
}
#[cfg(not(target_os = "windows"))]
pub fn set_output_device(device_id: &str) -> Result<()> {
let _ = device_id;
Ok(())
}
#[cfg(target_os = "windows")]
pub fn list_input_devices() -> Result<Vec<AudioDevice>> {
let output = Command::new("powershell")
.args([
"-Command",
"Get-AudioDevice -List -Recording | ForEach-Object { $_.FriendlyName }",
])
.output();
let mut devices = vec![AudioDevice {
id: "default".to_string(),
name: "Default Microphone".to_string(),
is_default: true,
}];
if let Ok(output) = output {
if let Ok(devices_str) = String::from_utf8(output.stdout) {
for (i, line) in devices_str.lines().enumerate() {
if !line.is_empty() {
devices.push(AudioDevice {
id: format!("mic_{}", i),
name: line.to_string(),
is_default: false,
});
}
}
}
}
Ok(devices)
}
#[cfg(not(target_os = "windows"))]
pub fn list_input_devices() -> Result<Vec<AudioDevice>> {
Ok(vec![
AudioDevice {
id: "default".to_string(),
name: "Default Microphone".to_string(),
is_default: true,
},
AudioDevice {
id: "mic".to_string(),
name: "Microphone Array".to_string(),
is_default: false,
},
])
}
#[cfg(target_os = "windows")]
pub fn set_input_volume(volume: u32) -> Result<()> {
let volume = volume.clamp(0, 100);
let volume_f = volume as f64 / 100.0;
let _ = Command::new("powershell")
.args([
"-Command",
&format!("Set-AudioDevice -RecordingVolume {}", volume_f),
])
.output();
Ok(())
}
#[cfg(not(target_os = "windows"))]
pub fn set_input_volume(volume: u32) -> Result<()> {
let _ = volume;
Ok(())
}