wip: AudioEngine pt.2 (rewrite activation sanely)

This commit is contained in:
🪞👃🪞 2024-11-03 04:43:50 +02:00
parent 2303b258f6
commit 746e29aeb3
8 changed files with 104 additions and 106 deletions

View file

@ -1,22 +1,5 @@
use crate::*;
use jack::*;
/// Just run thing with JACK. Returns the activated client.
pub fn jack_run<T, E: Engine>(name: &str, app: &Arc<RwLock<T>>) -> Usually<DynamicAsyncClient>
where
T: Handle<E> + Audio + Send + Sync + 'static,
{
let options = ClientOptions::NO_START_SERVER;
let (client, _status) = Client::new(name, options)?;
let on_event = Notifications(Box::new({
let _app = app.clone();
move|_event|{/* FIXME: this deadlocks: app.lock().unwrap().handle(&event).unwrap(); */}
}) as Box<dyn Fn(JackEvent) + Send + Sync>);
let on_chunk = contrib::ClosureProcessHandler::new(Box::new({
let app = app.clone();
move|c: &Client, s: &ProcessScope|app.write().unwrap().process(c, s)
}) as BoxedAudioHandler);
Ok(client.activate_async(on_event, on_chunk)?)
}
/// Trait for things that wrap a JACK client.
pub trait AudioEngine {
fn activate(
@ -36,10 +19,46 @@ pub trait AudioEngine {
}
/// Wraps [Client] or [DynamicAsyncClient] in place.
pub enum JackClient {
/// Before activation.
Inactive(Client),
/// During activation.
Activating,
/// After activation. Must not be dropped for JACK thread to persist.
Active(DynamicAsyncClient),
}
pub type DynamicAsyncClient = AsyncClient<DynamicNotifications, DynamicAudioHandler>;
pub type DynamicAudioHandler = contrib::ClosureProcessHandler<(), BoxedAudioHandler>;
pub type BoxedAudioHandler = Box<dyn FnMut(&Client, &ProcessScope) -> Control + Send>;
impl JackClient {
pub fn new (name: &str) -> Usually<Self> {
let (client, _) = Client::new(name, ClientOptions::NO_START_SERVER)?;
Ok(Self::Inactive(client))
}
pub fn activate_with <T: Audio + 'static> (
self,
init: impl FnOnce(&Arc<RwLock<JackClient>>)->T
)
-> Usually<Arc<RwLock<T>>>
{
let client = Arc::new(RwLock::new(self));
let target = Arc::new(RwLock::new(init(&client)));
let event = Box::new(move|_|{/*TODO*/}) as Box<dyn Fn(JackEvent) + Send + Sync>;
let events = Notifications(event);
let frame = Box::new({
let target = target.clone();
move|c: &_, s: &_|if let Ok(mut target) = target.write() {
target.process(c, s)
} else {
Control::Quit
}
});
let frames = contrib::ClosureProcessHandler::new(frame as BoxedAudioHandler);
let mut buffer = Self::Activating;
std::mem::swap(&mut*client.write().unwrap(), &mut buffer);
*client.write().unwrap() = Self::Active(Client::from(buffer).activate_async(events, frames)?);
Ok(target)
}
}
impl From<JackClient> for Client {
fn from (jack: JackClient) -> Client {
match jack {
@ -59,23 +78,23 @@ impl AudioEngine for JackClient {
}
fn activate(
self,
mut process: impl FnMut(&Arc<RwLock<Self>>, &Client, &ProcessScope) -> Control + Send + 'static,
mut cb: impl FnMut(&Arc<RwLock<Self>>, &Client, &ProcessScope) -> Control + Send + 'static,
) -> Usually<Arc<RwLock<Self>>>
where
Self: Send + Sync + 'static
{
let client = Client::from(self);
let state = Arc::new(RwLock::new(Self::Activating));
let event = Box::new(move |_| { /*TODO*/ }) as Box<dyn Fn(JackEvent) + Send + Sync>;
let event = Box::new(move|_|{/*TODO*/}) as Box<dyn Fn(JackEvent) + Send + Sync>;
let events = Notifications(event);
let frame = Box::new({let state = state.clone(); move|c: &_, s: &_|process(&state, c, s)});
let frame = Box::new({let state = state.clone(); move|c: &_, s: &_|cb(&state, c, s)});
let frames = contrib::ClosureProcessHandler::new(frame as BoxedAudioHandler);
*state.write().unwrap() = Self::Active(client.activate_async(events, frames)?);
Ok(state)
}
}
/// Trait for things that have a JACK process callback.
pub trait Audio {
pub trait Audio: Send + Sync {
fn process(&mut self, _: &Client, _: &ProcessScope) -> Control {
Control::Continue
}
@ -120,12 +139,6 @@ pub trait AudioComponent<E: Engine>: Component<E> + Audio {
/// All things that implement the required traits can be treated as `AudioComponent`.
impl<E: Engine, W: Component<E> + Audio> AudioComponent<E> for W {}
pub type DynamicAsyncClient = AsyncClient<DynamicNotifications, DynamicAudioHandler>;
pub type DynamicAudioHandler = contrib::ClosureProcessHandler<(), BoxedAudioHandler>;
pub type BoxedAudioHandler = Box<dyn FnMut(&Client, &ProcessScope) -> Control + Send>;
/// `JackDevice` factory. Creates JACK `Client`s, performs port registration
/// and activation, and encapsulates a `AudioComponent` into a `JackDevice`.
pub struct Jack {