thru/
thru.rs

1extern crate easyjack as jack;
2extern crate nix;
3
4use nix::sys::signal;
5use std::sync::atomic;
6use std::thread;
7use std::time::Duration;
8
9// signals are unpleasant (check comments in simple_client example)
10static RUNNING: atomic::AtomicBool = atomic::ATOMIC_BOOL_INIT;
11
12type InputPort  = jack::InputPortHandle<jack::DefaultAudioSample>;
13type OutputPort = jack::OutputPortHandle<jack::DefaultAudioSample>;
14
15struct Connector {
16    inputs: Vec<InputPort>,
17    outputs: Vec<OutputPort>,
18}
19
20impl Connector {
21    pub fn new(inputs: Vec<InputPort>, outputs: Vec<OutputPort>) -> Self {
22        assert_eq!(inputs.len(), outputs.len());
23
24        Connector {
25            inputs: inputs,
26            outputs: outputs
27        }
28    }
29}
30
31impl jack::ProcessHandler for Connector {
32    fn process(&mut self, ctx: &jack::CallbackContext, nframes: jack::NumFrames) -> i32 {
33        // for each of our inputs and outputs, copy the input buffer into the output buffer
34        for index in 0..self.inputs.len() {
35            let i = self.inputs[index].get_read_buffer(nframes, ctx);
36            let o = self.outputs[index].get_write_buffer(nframes, ctx);
37            o.clone_from_slice(i);
38        }
39
40
41        // return 0 so jack lets us keep running
42        0
43    }
44}
45
46extern "C" fn handle_sigint(_: i32) {
47    RUNNING.store(false, atomic::Ordering::SeqCst);
48}
49
50fn main() {
51    // register a signal handler (see comments at top of file)
52    let action = signal::SigAction::new(
53        signal::SigHandler::Handler(handle_sigint),
54        signal::SaFlags::empty(),
55        signal::SigSet::empty());
56
57    unsafe { signal::sigaction(signal::Signal::SIGINT, &action) }.unwrap();
58
59    // set our global atomic to true
60    RUNNING.store(true, atomic::Ordering::SeqCst);
61
62    let mut jack_client =
63        jack::Client::open("testclient", jack::options::NO_START_SERVER).unwrap().0;
64
65    println!("client created named: {}", jack_client.get_name());
66
67    // 2 in, 2 out
68    let input1 = jack_client.register_input_audio_port("input1").unwrap();
69    let input2 = jack_client.register_input_audio_port("input2").unwrap();
70    let output1 = jack_client.register_output_audio_port("output1").unwrap();
71    let output2 = jack_client.register_output_audio_port("output2").unwrap();
72
73    let handler = Connector::new(vec![input1, input2], vec![output1, output2]);
74    jack_client.set_process_handler(handler).unwrap();
75
76    // start everything up
77    jack_client.activate().unwrap();
78
79    // wait to get a SIGINT
80    // jack will do all of its magic in other threads
81    while RUNNING.load(atomic::Ordering::SeqCst) {
82        thread::sleep(Duration::from_millis(1000));
83    }
84
85    // now we can clean everything up
86    // the library doesn't handle this for us because it would be rather confusing, especially
87    // given how the underlying jack api actually works
88    println!("tearing down");
89
90    // closing the client unregisters all of the ports
91    // unregistering the ports after the client is closed is an error
92    jack_client.close().unwrap();
93}