use crate::* /// A [AudioComponent] bound to a JACK client and a set of ports. pub struct JackDevice { /// The active JACK client of this device. pub client: DynamicAsyncClient, /// The device state, encapsulated for sharing between threads. pub state: Arc>>>, /// Unowned copies of the device's JACK ports, for connecting to the device. /// The "real" readable/writable `Port`s are owned by the `state`. pub ports: UnownedJackPorts, } impl std::fmt::Debug for JackDevice { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("JackDevice") .field("ports", &self.ports) .finish() } } impl Render for JackDevice { type Engine = E; fn min_size(&self, to: E::Size) -> Perhaps { self.state.read().unwrap().layout(to) } fn render(&self, to: &mut E::Output) -> Usually<()> { self.state.read().unwrap().render(to) } } impl Handle for JackDevice { fn handle(&mut self, from: &E::Input) -> Perhaps { self.state.write().unwrap().handle(from) } } impl Ports for JackDevice { fn audio_ins(&self) -> Usually>> { Ok(self.ports.audio_ins.values().collect()) } fn audio_outs(&self) -> Usually>> { Ok(self.ports.audio_outs.values().collect()) } fn midi_ins(&self) -> Usually>> { Ok(self.ports.midi_ins.values().collect()) } fn midi_outs(&self) -> Usually>> { Ok(self.ports.midi_outs.values().collect()) } } impl JackDevice { /// Returns a locked mutex of the state's contents. pub fn state(&self) -> LockResult>>> { self.state.read() } /// Returns a locked mutex of the state's contents. pub fn state_mut(&self) -> LockResult>>> { self.state.write() } pub fn connect_midi_in(&self, index: usize, port: &Port) -> Usually<()> { Ok(self .client .as_client() .connect_ports(port, self.midi_ins()?[index])?) } pub fn connect_midi_out(&self, index: usize, port: &Port) -> Usually<()> { Ok(self .client .as_client() .connect_ports(self.midi_outs()?[index], port)?) } pub fn connect_audio_in(&self, index: usize, port: &Port) -> Usually<()> { Ok(self .client .as_client() .connect_ports(port, self.audio_ins()?[index])?) } pub fn connect_audio_out(&self, index: usize, port: &Port) -> Usually<()> { Ok(self .client .as_client() .connect_ports(self.audio_outs()?[index], port)?) } } //////////////////////////////////////////////////////////////////////////////////// ///// `JackDevice` factory. Creates JACK `Client`s, performs port registration ///// and activation, and encapsulates a `AudioComponent` into a `JackDevice`. //pub struct Jack { //pub client: Client, //pub midi_ins: Vec, //pub audio_ins: Vec, //pub midi_outs: Vec, //pub audio_outs: Vec, //} //impl Jack { //pub fn new(name: &str) -> Usually { //Ok(Self { //midi_ins: vec![], //audio_ins: vec![], //midi_outs: vec![], //audio_outs: vec![], //client: Client::new(name, ClientOptions::NO_START_SERVER)?.0, //}) //} //pub fn run<'a: 'static, D, E>( //self, //state: impl FnOnce(JackPorts) -> Box, //) -> Usually> //where //D: AudioComponent + Sized + 'static, //E: Engine + 'static, //{ //let owned_ports = JackPorts { //audio_ins: register_ports(&self.client, self.audio_ins, AudioIn::default())?, //audio_outs: register_ports(&self.client, self.audio_outs, AudioOut::default())?, //midi_ins: register_ports(&self.client, self.midi_ins, MidiIn::default())?, //midi_outs: register_ports(&self.client, self.midi_outs, MidiOut::default())?, //}; //let midi_outs = owned_ports //.midi_outs //.values() //.map(|p| Ok(p.name()?)) //.collect::>>()?; //let midi_ins = owned_ports //.midi_ins //.values() //.map(|p| Ok(p.name()?)) //.collect::>>()?; //let audio_outs = owned_ports //.audio_outs //.values() //.map(|p| Ok(p.name()?)) //.collect::>>()?; //let audio_ins = owned_ports //.audio_ins //.values() //.map(|p| Ok(p.name()?)) //.collect::>>()?; //let state = Arc::new(RwLock::new(state(owned_ports) as Box>)); //let client = self.client.activate_async( //Notifications(Box::new({ //let _state = state.clone(); //move |_event| { //// FIXME: this deadlocks ////state.lock().unwrap().handle(&event).unwrap(); //} //}) as Box), //ClosureProcessHandler::new(Box::new({ //let state = state.clone(); //move |c: &Client, s: &ProcessScope| state.write().unwrap().process(c, s) //}) as BoxedAudioHandler), //)?; //Ok(JackDevice { //ports: UnownedJackPorts { //audio_ins: query_ports(&client.as_client(), audio_ins), //audio_outs: query_ports(&client.as_client(), audio_outs), //midi_ins: query_ports(&client.as_client(), midi_ins), //midi_outs: query_ports(&client.as_client(), midi_outs), //}, //client, //state, //}) //} //pub fn audio_in(mut self, name: &str) -> Self { //self.audio_ins.push(name.to_string()); //self //} //pub fn audio_out(mut self, name: &str) -> Self { //self.audio_outs.push(name.to_string()); //self //} //pub fn midi_in(mut self, name: &str) -> Self { //self.midi_ins.push(name.to_string()); //self //} //pub fn midi_out(mut self, name: &str) -> Self { //self.midi_outs.push(name.to_string()); //self //} //} ///// A UI component that may be associated with a JACK client by the `Jack` factory. //pub trait AudioComponent: Component + Audio { ///// Perform type erasure for collecting heterogeneous devices. //fn boxed(self) -> Box> //where //Self: Sized + 'static, //{ //Box::new(self) //} //} ///// All things that implement the required traits can be treated as `AudioComponent`. //impl + Audio> AudioComponent for W {} ///////// /* */