Skip to content

Commit

Permalink
Replaced Soloud with Rodio
Browse files Browse the repository at this point in the history
  • Loading branch information
Raphiiko committed Sep 29, 2024
1 parent 7720506 commit f9da039
Show file tree
Hide file tree
Showing 11 changed files with 428 additions and 111 deletions.
406 changes: 343 additions & 63 deletions src-core/Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ mime_guess = "2.0.4"
substring = "1.4.5"
bytes = "1.4.0"
nalgebra = "0.32.2"
soloud = "1.0.2"
rodio = "0.19.0"
time = "0.3.15"
tauri-plugin-fs-extra = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" }
tauri-plugin-log = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" }
Expand Down
Binary file modified src-core/resources/sounds/notification_bell.ogg
Binary file not shown.
Binary file modified src-core/resources/sounds/notification_block.ogg
Binary file not shown.
Binary file modified src-core/resources/sounds/notification_reverie.ogg
Binary file not shown.
6 changes: 3 additions & 3 deletions src-core/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ fn main() {
.invoke_handler(configure_command_handlers())
.build(tauri::generate_context!())
.expect("An error occurred while running the application")
.run(|handler, event| match event {
.run(|_, event| match event {
// tauri::RunEvent::Exit { .. } => {
// if TELEMETRY_ENABLED.load(Ordering::Relaxed) {
// handler.track_event("app_exited", None);
Expand Down Expand Up @@ -334,8 +334,8 @@ async fn app_setup(app_handle: tauri::AppHandle) {
system_tray::init().await;
// Initialize Image Cache
image_cache::init(cache_dir).await;
// Load sounds
os::load_sounds().await;
// Init sound playback
os::init_sound_playback().await;
// Initialize audio device manager
os::init_audio_device_manager().await;
// Initialize Lighthouse Bluetooth
Expand Down
31 changes: 9 additions & 22 deletions src-core/src/os/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ use super::{
audio_devices::device::AudioDeviceDto,
get_friendly_name_for_windows_power_policy,
models::{Output, WindowsPowerPolicy},
SOLOUD, SOUNDS, VRCHAT_ACTIVE,
VRCHAT_ACTIVE,
};
use log::{error, info};
use soloud::{audio, AudioExt, LoadExt};
use tauri::api::process::{Command, CommandEvent};

#[tauri::command]
Expand All @@ -14,27 +13,15 @@ pub async fn play_sound(name: String, volume: f32) {
if volume == 0.0 {
return;
}
std::thread::spawn(move || {
let mut wav = audio::Wav::default();
{
let sound_data_guard = SOUNDS.lock().unwrap();
let sound_data = sound_data_guard.get(&name).unwrap();
wav.load_mem(sound_data).unwrap();
}
{
let sl = SOLOUD.lock().unwrap();
sl.play_ex(&wav, volume, 0.0, false, unsafe {
soloud::Handle::from_raw(0)
});
}
loop {
std::thread::sleep(std::time::Duration::from_millis(100));
let sl = SOLOUD.lock().unwrap();
if sl.active_voice_count() == 0 {
break;
}
let guard = super::PLAY_SOUND_TX.lock().await;
let tx = match guard.as_ref() {
Some(tx) => tx,
None => {
error!("[Core] Could not play sound, as sound player was not initialized");
return;
}
});
};
let _ = tx.send((name, volume)).await;
}

#[tauri::command]
Expand Down
88 changes: 68 additions & 20 deletions src-core/src/os/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,28 @@ pub mod commands;
mod models;
mod sounds_gen;

use self::audio_devices::manager::AudioDeviceManager;
use lazy_static::lazy_static;
use log::{error, info};
use soloud::*;
use rodio::{source::Source, Decoder};
use rodio::{OutputStream, Sink};
use std::collections::HashMap;
use std::ffi::OsString;
use std::fs::File;
use std::io::BufReader;
use std::os::windows::ffi::OsStringExt;
use std::ptr::null_mut;
use std::slice;
use std::time::Duration;
use tokio::sync::mpsc::Sender;
use tokio::sync::Mutex;
use winapi::shared::guiddef::GUID;
use winapi::shared::minwindef::{DWORD, UCHAR, ULONG};
use winapi::um::powersetting::{PowerGetActiveScheme, PowerSetActiveScheme};
use winapi::um::powrprof::{PowerEnumerate, PowerReadFriendlyName};

use self::audio_devices::manager::AudioDeviceManager;
use lazy_static::lazy_static;

lazy_static! {
static ref SOUNDS: std::sync::Mutex<HashMap<String, Vec<u8>>> =
std::sync::Mutex::new(HashMap::new());
static ref SOLOUD: std::sync::Mutex<Soloud> = std::sync::Mutex::new(Soloud::default().unwrap());
static ref PLAY_SOUND_TX: Mutex<Option<Sender<(String, f32)>>> = Mutex::default();
static ref AUDIO_DEVICE_MANAGER: Mutex<Option<AudioDeviceManager>> = Mutex::default();
static ref VRCHAT_ACTIVE: Mutex<bool> = Mutex::new(false);
static ref MEMORY_WATCHER_ACTIVE: Mutex<bool> = Mutex::new(false);
Expand Down Expand Up @@ -73,19 +74,66 @@ async fn watch_processes() {
}
}

pub async fn load_sounds() {
let mut sounds = SOUNDS.lock().unwrap();
sounds_gen::SOUND_FILES.iter().for_each(|sound| {
sounds.insert(
String::from(*sound),
std::fs::read(format!("resources/sounds/{}.ogg", sound)).expect(
format!(
"Could not find sound file at path: {}",
format!("resources/sounds/{}.ogg", sound).as_str()
)
.as_str(),
),
);
pub async fn init_sound_playback() {
// Create channel
let (tx, mut rx) = tokio::sync::mpsc::channel::<(String, f32)>(32);
*PLAY_SOUND_TX.lock().await = Some(tx);

// Spawn task to play sounds
tokio::task::spawn(async move {
// Load sound files
let mut sounds = HashMap::new();
sounds_gen::SOUND_FILES.iter().for_each(|sound| {
let path = format!("resources/sounds/{}.ogg", sound);
let file = match File::open(path.clone()) {
Ok(f) => f,
Err(e) => {
error!("[Core] Failed to open sound file: {}", e);
return;
}
};
let reader = BufReader::new(file);
let source = match Decoder::new(reader) {
Ok(s) => s.buffered(),
Err(e) => {
error!(
"[Core] Failed to decode sound file at path ({}): {}",
path.clone(),
e
);
return;
}
};
sounds.insert(String::from(*sound), source);
});
// Play sounds when requested
while let Some((sound, volume)) = rx.recv().await {
if let Some(source) = sounds.get(&sound) {
// Initialize output stream
let (_stream, stream_handle) = match OutputStream::try_default() {
Ok((stream, handle)) => (stream, handle),
Err(e) => {
error!("[Core] Failed to initialize audio output stream: {}", e);
return;
}
};
// Play sound
let source = source.clone();
let sink = match Sink::try_new(&stream_handle) {
Ok(s) => s,
Err(e) => {
error!("[Core] Failed to create audio sink: {}", e);
return;
}
};
sink.set_volume(volume);
sink.append(source.clone());
// sink.detach();
sink.sleep_until_end();
} else {
error!("[Core] Sound not found: {}", sound);
}
}
});
}

Expand Down
2 changes: 1 addition & 1 deletion src-ui/app/services/join-notifications.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ export class JoinNotificationsService {
// Send sound
if (val.sound) {
await this.notification.playSound(
'notification_reverie',
'material_alarm_gentle_short_1',
this.config.joinSoundVolume / 100
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@
<app-slider-setting
[unit]="'%'"
[max]="200"
[snapValues]="[50, 100, 150]"
[value]="config.joinSoundVolume"
(valueChange)="setJoinSoundVolume($event)"
></app-slider-setting>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ export class JoinNotificationsViewComponent implements OnInit {
}

async testSound() {
if (this.playingTestSound) return;
await this.notifications.playSound(
'material_alarm_gentle_short_1',
this.config.joinSoundVolume / 100
Expand All @@ -156,7 +157,7 @@ export class JoinNotificationsViewComponent implements OnInit {
this.playingTestSoundTimeout = setTimeout(() => {
this.playingTestSound = false;
this.playingTestSoundTimeout = undefined;
}, 8000);
}, 3000);
}

asJoinNotificationsMode(id: string | undefined) {
Expand Down

0 comments on commit f9da039

Please sign in to comment.