Handy/src-tauri/src/audio_feedback.rs
2025-08-07 16:53:07 -07:00

106 lines
3.4 KiB
Rust

use crate::settings;
use cpal::traits::{DeviceTrait, HostTrait};
use rodio::OutputStreamBuilder;
use std::fs::File;
use std::io::BufReader;
use std::thread;
use tauri::{AppHandle, Manager};
/// Plays an audio resource from the resources directory.
/// Checks if audio feedback is enabled in settings before playing.
pub fn play_sound(app: &AppHandle, resource_path: &str) {
// Check if audio feedback is enabled
let settings = settings::get_settings(app);
if !settings.audio_feedback {
return;
}
let app_handle = app.clone();
let resource_path = resource_path.to_string();
// Spawn a new thread to play the audio without blocking the main thread
thread::spawn(move || {
// Get the path to the audio file in resources
let audio_path = match app_handle
.path()
.resolve(&resource_path, tauri::path::BaseDirectory::Resource)
{
Ok(path) => path.to_path_buf(),
Err(e) => {
eprintln!(
"Failed to resolve audio file path '{}': {}",
resource_path, e
);
return;
}
};
// Get the selected output device from settings
let settings = settings::get_settings(&app_handle);
let selected_device = settings.selected_output_device.clone();
// Try to play the audio file
if let Err(e) = play_audio_file(&audio_path, selected_device) {
eprintln!("Failed to play sound '{}': {}", resource_path, e);
}
});
}
/// Convenience function to play the recording start sound
pub fn play_recording_start_sound(app: &AppHandle) {
play_sound(app, "resources/rec_start.wav");
}
/// Convenience function to play the recording stop sound
pub fn play_recording_stop_sound(app: &AppHandle) {
play_sound(app, "resources/rec_stop.wav");
}
fn play_audio_file(
path: &std::path::Path,
selected_device: Option<String>,
) -> Result<(), Box<dyn std::error::Error>> {
let stream_builder = if let Some(device_name) = selected_device {
if device_name == "Default" {
println!("Using default device");
// Use default device
OutputStreamBuilder::from_default_device()?
} else {
// Try to find the device by name
let host = cpal::default_host();
let devices = host.output_devices()?;
let mut found_device = None;
for device in devices {
if device.name()? == device_name {
found_device = Some(device);
break;
}
}
match found_device {
Some(device) => OutputStreamBuilder::from_device(device)?,
None => {
eprintln!("Device '{}' not found, using default device", device_name);
OutputStreamBuilder::from_default_device()?
}
}
}
} else {
println!("Using default device");
// Use default device
OutputStreamBuilder::from_default_device()?
};
let stream_handle = stream_builder.open_stream()?;
let mixer = stream_handle.mixer();
// Load the audio file
let file = File::open(path)?;
let buf_reader = BufReader::new(file);
let sink = rodio::play(mixer, buf_reader)?;
sink.sleep_until_end();
Ok(())
}