From 7216627a0116a3e526c09a72c20818116eabc27b Mon Sep 17 00:00:00 2001
From: Robbert van der Helm <mail@robbertvanderhelm.nl>
Date: Tue, 14 Jun 2022 17:49:45 +0200
Subject: [PATCH] Create and connect JACK ports

---
 src/wrapper/standalone/backend.rs      |  1 +
 src/wrapper/standalone/backend/jack.rs | 32 ++++++++++++++++++++++----
 2 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/src/wrapper/standalone/backend.rs b/src/wrapper/standalone/backend.rs
index 6c8e3f29..3fb4bed2 100644
--- a/src/wrapper/standalone/backend.rs
+++ b/src/wrapper/standalone/backend.rs
@@ -13,5 +13,6 @@ pub trait Backend: 'static + Send + Sync {
     /// buffer. This will block until the process callback returns `false`.
     ///
     /// TODO: MIDI
+    /// TODO: Auxiliary inputs and outputs
     fn run(&mut self, cb: impl FnMut(&mut Buffer) -> bool);
 }
diff --git a/src/wrapper/standalone/backend/jack.rs b/src/wrapper/standalone/backend/jack.rs
index 2a600f4b..b159e710 100644
--- a/src/wrapper/standalone/backend/jack.rs
+++ b/src/wrapper/standalone/backend/jack.rs
@@ -1,5 +1,5 @@
 use anyhow::{Context, Result};
-use jack::{Client, ClientOptions};
+use jack::{AudioIn, AudioOut, Client, ClientOptions, Port};
 
 use super::super::config::WrapperConfig;
 use super::Backend;
@@ -9,6 +9,9 @@ use crate::buffer::Buffer;
 pub struct Jack {
     config: WrapperConfig,
     client: Client,
+
+    inputs: Vec<Port<AudioIn>>,
+    outputs: Vec<Port<AudioOut>>,
 }
 
 impl Backend for Jack {
@@ -27,10 +30,31 @@ impl Jack {
             anyhow::bail!("The JACK server returned an error: {status:?}");
         }
 
-        // TODO: Register ports
-        // TODO: Connect output
+        let mut inputs = Vec::new();
+        for port_no in 1..config.input_channels + 1 {
+            inputs.push(client.register_port(&format!("input_{port_no}"), AudioIn)?);
+        }
+
+        let mut outputs = Vec::new();
+        for port_no in 1..config.output_channels + 1 {
+            let port = client.register_port(&format!("output_{port_no}"), AudioOut)?;
+
+            // We don't connect the inputs automatically to avoid feedback loops, but this should be
+            // safe. And if this fails, then that's fine.
+            let system_playback_port_name = &format!("system:playback_{port_no}");
+            let _ = client.connect_ports_by_name(&port.name()?, system_playback_port_name);
+
+            outputs.push(port);
+        }
+
         // TODO: Command line argument to connect the inputs?
 
-        Ok(Self { config, client })
+        Ok(Self {
+            config,
+            client,
+
+            inputs,
+            outputs,
+        })
     }
 }