From f2407147fb8eaf1eb957fb080f15587ab224b1d8 Mon Sep 17 00:00:00 2001 From: Philpax Date: Tue, 12 Sep 2023 17:17:18 +0200 Subject: [PATCH] fix #831 - remove unwraps from world audio systems --- campfire/src/install.rs | 1 + crates/world_audio/src/systems.rs | 288 +++++++++++++----------------- 2 files changed, 123 insertions(+), 166 deletions(-) diff --git a/campfire/src/install.rs b/campfire/src/install.rs index 8f43597f32..d64393b89b 100644 --- a/campfire/src/install.rs +++ b/campfire/src/install.rs @@ -63,6 +63,7 @@ fn install_version(suffix: &str, args: &[&str]) -> anyhow::Result<()> { Ok(()) } +#[allow(unused_mut)] fn ambient_executable_name(suffix: &str) -> String { let mut name = if suffix.is_empty() { "ambient".to_string() diff --git a/crates/world_audio/src/systems.rs b/crates/world_audio/src/systems.rs index 5ddfea5a8a..ec6bca3045 100644 --- a/crates/world_audio/src/systems.rs +++ b/crates/world_audio/src/systems.rs @@ -3,18 +3,18 @@ use std::{io::Cursor, sync::Arc}; use crate::{audio_emitter, audio_listener, hrtf_lib}; use ambient_audio::{hrtf::HrtfLib, AudioFromUrl, Source}; use ambient_audio::{Attenuation, AudioEmitter, AudioListener}; -use ambient_core::transform::local_to_world; use ambient_core::{ asset_cache, async_ecs::async_run, runtime, - transform::{rotation, translation}, + transform::{local_to_world, translation}, }; +use ambient_ecs::EntityId; use ambient_ecs::{ - generated::audio::components::*, generated::hierarchy::components::children, - generated::hierarchy::components::parent, query, SystemGroup, World, + generated::audio::components::*, generated::hierarchy::components::children, query, + SystemGroup, World, }; -use ambient_native_std::{asset_cache::AsyncAssetKeyExt, asset_url::AbsAssetUrl}; +use ambient_native_std::{asset_cache::AsyncAssetKeyExt, asset_url::AbsAssetUrl, unwrap_log_warn}; use glam::{vec4, Mat4}; use parking_lot::Mutex; use std::str::FromStr; @@ -43,81 +43,14 @@ pub fn audio_systems() -> SystemGroup { SystemGroup::new( "audio", vec![ - query((is_spatial_audio_player(), play_now())).to_system(|q, world, qs, _| { - for (audio_player_enitty, _) in q.collect_cloned(world, qs) { - // check if mute_audio is set - let r = world.resource_entity(); - if !world.has_component(r, crate::audio_mixer()) { - continue; + query(audio_url()) + .incl(is_spatial_audio_player()) + .incl(play_now()) + .to_system(|q, world, qs, _| { + for (player, url) in q.collect_cloned(world, qs) { + process_player(world, player, &url); } - - let amp = world.get(audio_player_enitty, amplitude()).unwrap_or(1.0); - let looping = world.get(audio_player_enitty, looping()).unwrap_or(false); - world - .remove_component(audio_player_enitty, play_now()) - .unwrap(); - - let assets = world.resource(asset_cache()).clone(); - let runtime = world.resource(runtime()).clone(); - let async_run = world.resource(async_run()).clone(); - let url = world.get_ref(audio_player_enitty, audio_url()).unwrap(); - let url = AbsAssetUrl::from_str(url) - .unwrap() - .to_download_url(&assets) - .unwrap(); - - runtime.spawn(async move { - - - let track = AudioFromUrl { url: url.clone() }.get(&assets).await; - async_run.run(move |world| { - - let listener_id = world - .get(audio_player_enitty, spatial_audio_listener()) - .unwrap(); - let emitter_id = world - .get(audio_player_enitty, spatial_audio_emitter()) - .unwrap(); - let pos_listener = world.get(listener_id, translation()).unwrap(); - let rot = world.get(listener_id, rotation()).unwrap(); - let pos_emitter = world.get(emitter_id, translation()).unwrap(); - - let listener = Arc::new(Mutex::new(AudioListener::new( - Mat4::from_rotation_translation(rot, pos_listener), - glam::Vec3::X * 0.3, - ))); - let emitter = Arc::new(Mutex::new(AudioEmitter { - amplitude: amp, - attenuation: Attenuation::InversePoly { - quad: 0.1, - lin: 0.0, - constant: 1.0, - }, - pos: pos_emitter, - })); - world - .add_component(emitter_id, audio_emitter(), emitter.clone()) - .unwrap(); - world - .add_component(listener_id, audio_listener(), listener.clone()) - .unwrap(); - - let hrtf_lib = world.resource(hrtf_lib()); - - - - let mixer = world.resource(crate::audio_mixer()); - let source: Box = if looping { - Box::new(track.unwrap().decode().repeat().spatial(hrtf_lib, listener, emitter)) - } else { - Box::new(track.unwrap().decode().spatial(hrtf_lib, listener, emitter)) - }; - let sound = mixer.play(source); - world.add_component(emitter_id, crate::sound_id(), sound.id).unwrap(); - }); - }); - } - }), + }), // Updates the volume of audio emitters in the world query((audio_emitter(), local_to_world())).to_system(|q, world, qs, _| { for (_, (emitter, ltw)) in q.iter(world, qs) { @@ -136,10 +69,10 @@ pub fn audio_systems() -> SystemGroup { |q, world, qs, _| { for (_, (listener, <w)) in q.iter(world, qs) { // check if mute_audio is set - let r = world.resource_entity(); - if !world.has_component(r, crate::audio_mixer()) { - continue; - } + let r = world.resource_entity(); + if !world.has_component(r, crate::audio_mixer()) { + continue; + } let mut listener = listener.lock(); listener.transform = Y_UP_LHS * ltw; } @@ -147,7 +80,6 @@ pub fn audio_systems() -> SystemGroup { ), query(stop_now()).to_system(|q, world, qs, _| { for (playing_entity, _) in q.collect_cloned(world, qs) { - // check if mute_audio is set let r = world.resource_entity(); if !world.has_component(r, crate::audio_mixer()) { @@ -155,38 +87,23 @@ pub fn audio_systems() -> SystemGroup { } let mixer = world.resource(crate::audio_mixer()); - let id = world.get(playing_entity, crate::sound_id()); - if id.is_err() { + let Ok(id) = world.get(playing_entity, crate::sound_id()) else { log::error!("No sound id component on playing entity; cannot stop audio."); continue; - } - mixer.stop(id.unwrap()); + }; + mixer.stop(id); // stopping an emitter is different if world.has_component(playing_entity, audio_emitter()) { - world.remove_component(playing_entity, audio_emitter()).unwrap(); + let _ = world.remove_component(playing_entity, audio_emitter()); continue; } if world.has_component(playing_entity, audio_listener()) { - world.remove_component(playing_entity, audio_listener()).unwrap(); + let _ = world.remove_component(playing_entity, audio_listener()); continue; } - world.remove_component(playing_entity, stop_now()).unwrap(); - let p = world.get(playing_entity, parent()); - if let Ok(parent_entity) = p { - let c = world.get_ref(parent_entity, children()); - if c.is_err() { - log::error!("No children component on parent entity; cannot stop audio."); - continue; - } - let new_children = c - .unwrap() - .iter() - .filter(|&&e| e != playing_entity) - .cloned() - .collect::>(); - world.set(parent_entity, children(), new_children).unwrap(); - world.despawn(playing_entity); - } + let _ = world.remove_component(playing_entity, stop_now()); + + world.despawn(playing_entity); } }), query((playing_sound(), amplitude())).to_system(|q, world, qs, _| { @@ -196,10 +113,9 @@ pub fn audio_systems() -> SystemGroup { if !world.has_component(r, crate::audio_mixer()) { continue; } - let amp_arc = world - .get_mut(playing_entity, crate::amplitude_arc()) - .unwrap(); - *amp_arc.lock() = amp; + if let Ok(amp_arc) = world.get_mut(playing_entity, crate::amplitude_arc()) { + *amp_arc.lock() = amp; + } } }), query((playing_sound(), panning())).to_system(|q, world, qs, _| { @@ -209,10 +125,9 @@ pub fn audio_systems() -> SystemGroup { if !world.has_component(r, crate::audio_mixer()) { continue; } - let pan_arc = world - .get_mut(playing_entity, crate::panning_arc()) - .unwrap(); - *pan_arc.lock() = pan; + if let Ok(pan_arc) = world.get_mut(playing_entity, crate::panning_arc()) { + *pan_arc.lock() = pan; + } } }), query((playing_sound(), onepole_lpf())).to_system(|q, world, qs, _| { @@ -222,42 +137,38 @@ pub fn audio_systems() -> SystemGroup { if !world.has_component(r, crate::audio_mixer()) { continue; } - let freq_arc = world - .get_mut(playing_entity, crate::onepole_arc()) - .unwrap(); - *freq_arc.lock() = freq; + if let Ok(freq_arc) = world.get_mut(playing_entity, crate::onepole_arc()) { + *freq_arc.lock() = freq; + } } }), query((is_audio_player(), play_now(), audio_url())).to_system(|q, world, qs, _| { - for (audio_player_enitty, (_, _, url)) in q.collect_cloned(world, qs) { + for (player, (_, _, url)) in q.collect_cloned(world, qs) { // check if mute_audio is set let r = world.resource_entity(); if !world.has_component(r, crate::audio_mixer()) { continue; } - let amp = world.get(audio_player_enitty, amplitude()).unwrap_or(1.0); - let pan = world.get(audio_player_enitty, panning()).unwrap_or(0.0); - let freq = world - .get(audio_player_enitty, onepole_lpf()) - .unwrap_or(20000.0); - let looping = world.get(audio_player_enitty, looping()).unwrap_or(false); + let amp = world.get(player, amplitude()).unwrap_or(1.0); + let pan = world.get(player, panning()).unwrap_or(0.0); + let freq = world.get(player, onepole_lpf()).unwrap_or(20000.0); + let looping = world.get(player, looping()).unwrap_or(false); - world - .remove_component(audio_player_enitty, play_now()) - .unwrap(); + world.remove_component(player, play_now()).unwrap(); let assets = world.resource(asset_cache()).clone(); let runtime = world.resource(runtime()).clone(); let async_run = world.resource(async_run()).clone(); - let url = AbsAssetUrl::from_str(&url) - .unwrap() - .to_download_url(&assets) - .unwrap(); + let Ok(url) = + AbsAssetUrl::from_str(&url).and_then(|u| u.to_download_url(&assets)) + else { + continue; + }; runtime.spawn(async move { - let track = AudioFromUrl { url: url.clone() }.get(&assets).await; - let track = track.unwrap(); + let track = + unwrap_log_warn!(AudioFromUrl { url: url.clone() }.get(&assets).await); let id_arc = Arc::new(Mutex::new(None)); let id_arc_clone = id_arc.clone(); let count_arc = Arc::new(Mutex::new(None)); @@ -265,22 +176,18 @@ pub fn audio_systems() -> SystemGroup { let sr_arc = Arc::new(Mutex::new(None)); let sr_arc_clone = sr_arc.clone(); async_run.run(move |world| { - let id_vec = world.get_ref(audio_player_enitty, children()); - if id_vec.is_err() { + let Some(id) = world + .get_ref(player, children()) + .ok() + .and_then(|c| c.last()) + .copied() + else { log::error!( "No children component on parent entity; cannot play audio." ); return; - } - let id_vec = id_vec.unwrap(); - if id_vec.is_empty() { - log::error!( - "No children component on parent entity; cannot play audio." - ); - return; - } - let id = id_vec.last().unwrap(); - id_arc.lock().replace(*id); + }; + id_arc.lock().replace(id); let mut t: Box = if looping { Box::new(track.decode().repeat()) @@ -300,14 +207,14 @@ pub fn audio_systems() -> SystemGroup { t = t.onepole(f.clone()); let id = id_arc.lock().unwrap(); - world.add_component(id, crate::amplitude_arc(), a).unwrap(); - world.add_component(id, crate::panning_arc(), p).unwrap(); - world.add_component(id, crate::onepole_arc(), f).unwrap(); + let _ = world.add_component(id, crate::amplitude_arc(), a); + let _ = world.add_component(id, crate::panning_arc(), p); + let _ = world.add_component(id, crate::onepole_arc(), f); let mixer = world.resource(crate::audio_mixer()); let sound = mixer.play(t); - world.add_component(id, crate::sound_id(), sound.id).unwrap(); + let _ = world.add_component(id, crate::sound_id(), sound.id); }); let count = *count_arc_clone.lock(); @@ -316,22 +223,9 @@ pub fn audio_systems() -> SystemGroup { let dur = count as f32 / sr as f32 * 1.001; ambient_sys::time::sleep(std::time::Duration::from_secs_f32(dur)).await; async_run.run(move |world| { - world.despawn(id_arc_clone.lock().unwrap()); - if !world.exists(audio_player_enitty) { - return; - } - let child = world.get_ref(audio_player_enitty, children()); - if child.is_err() { - log::error!("No children component on parent entity; cannot auto stop audio."); - return; + if let Some(id) = id_arc_clone.lock().take() { + world.despawn(id); } - let new_child = child - .unwrap() - .iter() - .filter(|c| *c != &id_arc_clone.lock().unwrap()) - .cloned() - .collect(); - world.set(audio_player_enitty, children(), new_child).unwrap(); }); }; }); @@ -341,6 +235,68 @@ pub fn audio_systems() -> SystemGroup { ) } +fn process_player(world: &mut World, player: EntityId, url: &str) { + // check if mute_audio is set + let r = world.resource_entity(); + if !world.has_component(r, crate::audio_mixer()) { + return; + } + + let amp = world.get(player, amplitude()).unwrap_or(1.0); + let looping = world.get(player, looping()).unwrap_or(false); + world.remove_component(player, play_now()).unwrap(); + + let assets = world.resource(asset_cache()).clone(); + let runtime = world.resource(runtime()).clone(); + let async_run = world.resource(async_run()).clone(); + let url = + unwrap_log_warn!(AbsAssetUrl::from_str(&url).and_then(|u| u.to_download_url(&assets))); + + runtime.spawn(async move { + let track = unwrap_log_warn!(AudioFromUrl { url: url.clone() }.get(&assets).await); + async_run.run(move |world| { + let Ok(listener_id) = world.get(player, spatial_audio_listener()) else { + return; + }; + let Ok(emitter_id) = world.get(player, spatial_audio_emitter()) else { + return; + }; + let Ok(listener_transform) = world.get(listener_id, local_to_world()) else { + return; + }; + + let pos_emitter = world.get(emitter_id, translation()).unwrap(); + + let listener = Arc::new(Mutex::new(AudioListener::new( + listener_transform, + glam::Vec3::X * 0.3, + ))); + let emitter = Arc::new(Mutex::new(AudioEmitter { + amplitude: amp, + attenuation: Attenuation::InversePoly { + quad: 0.1, + lin: 0.0, + constant: 1.0, + }, + pos: pos_emitter, + })); + let _ = world.add_component(emitter_id, audio_emitter(), emitter.clone()); + let _ = world.add_component(listener_id, audio_listener(), listener.clone()); + + let hrtf_lib = world.resource(hrtf_lib()); + + let mixer = world.resource(crate::audio_mixer()); + let source: Box = if looping { + Box::new(track.decode().repeat().spatial(hrtf_lib, listener, emitter)) + } else { + Box::new(track.decode().spatial(hrtf_lib, listener, emitter)) + }; + let sound = mixer.play(source); + let _ = world.add_component(emitter_id, crate::sound_id(), sound.id); + }); + }); +} + pub fn client_systems() -> SystemGroup { SystemGroup::new("audio", vec![Box::new(audio_systems())]) }