From 97541d7d3ca20cb3fd1c0da4340011ef6768db45 Mon Sep 17 00:00:00 2001 From: Andre Henriques Date: Fri, 5 Aug 2022 08:25:13 +0100 Subject: [PATCH] Initial commit --- .gitignore | 9 + Cargo.lock | 575 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 12 ++ src/main.rs | 381 ++++++++++++++++++++++++++++++++++ 4 files changed, 977 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a97168d --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +/target +links + + +# Added by cargo +# +# already existing elements were commented out + +#/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..377d089 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,575 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "anyhow" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "bindgen" +version = "0.59.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "clap", + "env_logger", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "which", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-expr" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aacacf4d96c24b2ad6eb8ee6df040e4f27b0d0b39a5710c30091baa830485db" +dependencies = [ + "smallvec", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clang-sys" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a050e2153c5be08febd6734e29298e844fdb0fa21aeddd63b4eb7baa106c69b" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "cookie-factory" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396de984970346b0d9e93d1415082923c679e5ae5c3ee3dcbd104f5610af126b" + +[[package]] +name = "either" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" + +[[package]] +name = "env_logger" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "libloading" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" +dependencies = [ + "cfg-if 1.0.0", + "winapi", +] + +[[package]] +name = "libspa" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8bb02bbc8d550e2f0a31989c61e1ac3c883bab2edee49ffcb5d5ca18266786d" +dependencies = [ + "bitflags", + "cc", + "cookie-factory", + "errno", + "libc", + "libspa-sys", + "nom", + "system-deps", +] + +[[package]] +name = "libspa-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8d2e38d6cdd10d7d78eb0cb409c127cf16da2c296d9623375551e309616d4d" +dependencies = [ + "bindgen", + "system-deps", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nix" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce" +dependencies = [ + "bitflags", + "cc", + "cfg-if 0.1.10", + "libc", + "void", +] + +[[package]] +name = "nom" +version = "7.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "once_cell" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "pipewire" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d80fef8219c37f479f3d62d70167f3daaa90b71a083f7fd88d69e49f05f0ecdc" +dependencies = [ + "anyhow", + "bitflags", + "errno", + "libc", + "libspa", + "libspa-sys", + "once_cell", + "pipewire-sys", + "signal", + "thiserror", +] + +[[package]] +name = "pipewire-autoconnect" +version = "0.1.0" +dependencies = [ + "lazy_static", + "libspa", + "pipewire", + "regex", +] + +[[package]] +name = "pipewire-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6d4262ea1fd3b01786046d1892cc49e9578d872faf8723d95dc7affc810ee4" +dependencies = [ + "bindgen", + "libspa-sys", + "system-deps", +] + +[[package]] +name = "pkg-config" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" + +[[package]] +name = "proc-macro2" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c278e965f1d8cf32d6e0e96de3d3e79712178ae67986d9cf9151f51e95aac89b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "serde" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03" + +[[package]] +name = "shlex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" + +[[package]] +name = "signal" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f6ce83b159ab6984d2419f495134972b48754d13ff2e3f8c998339942b56ed9" +dependencies = [ + "libc", + "nix", +] + +[[package]] +name = "smallvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "syn" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "system-deps" +version = "6.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a45a1c4c9015217e12347f2a411b57ce2c4fc543913b14b6fe40483328e709" +dependencies = [ + "cfg-expr", + "heck", + "pkg-config", + "toml", + "version-compare", +] + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "thiserror" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + +[[package]] +name = "unicode-ident" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" + +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version-compare" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe88247b92c1df6b6de80ddc290f3976dbdf2f5f5d3fd049a9fb598c6dd5ca73" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "which" +version = "4.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae" +dependencies = [ + "either", + "lazy_static", + "libc", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..62490d3 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "pipewire-autoconnect" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +pipewire = "0.5.0" +libspa = "0.5.0" +regex = "1.6.0" +lazy_static = "1.4.0" diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..1f95ff7 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,381 @@ +use std::{cell::RefCell, env, fs, io::BufRead, collections::HashMap}; +use std::vec::Vec; +use std::{cell::RefMut, rc::Rc}; + +use libspa::ReadableDict; +use pipewire::{types::ObjectType, Context, MainLoop}; +use pipewire as pw; +use regex::Regex; + +#[macro_use] +extern crate lazy_static; + +#[derive(Debug)] +struct Port { + id: u32, + name: String, + node: Rc, +} + +#[derive(Debug)] +struct Node { + id: u32, + name: String, +} + +#[derive(Debug)] +struct NodeDef { + name: String, +} + +#[derive(Debug)] +struct PortDef { + node: Rc, + name: String, +} + +#[derive(Debug)] +struct LinkDef { + port_in: Rc, + port_out: Rc, +} + +struct AppState { + ports: Vec>, + nodes: Vec>, + + get_names: bool, + + node_def: Vec>, + link_def: Vec>, + port_def: Vec>, +} + +fn search(v: &[Rc], f: P) -> Option> +where + T: Sized, + P: FnMut(&&Rc) -> bool, +{ + let n = v.iter().filter(f).cloned().collect::>>(); + + if n.len() != 1 { + return None; + } + + Some(n[0].clone()) +} + +impl AppState { + fn new( + node_def: Vec>, + link_def: Vec>, + port_def: Vec>, + get_names: bool, + ) -> AppState { + AppState { + node_def, + link_def, + port_def, + get_names, + ports: Vec::new(), + nodes: Vec::new(), + } + } + + fn try_add_node(&mut self, def: Node) -> bool { + if !self.node_def.iter().any(|a| a.name.eq(&def.name)) { + return false; + }; + + let mut nodes = self + .nodes + .iter() + .filter(|a| !a.name.eq(&def.name)) + .cloned() + .collect::>>(); + + nodes.push(Rc::new(def)); + + self.nodes = nodes; + + true + } + + fn get_node(&self, id: u32) -> Option> { + search(&self.nodes, |a| a.id == id) + } + + fn get_port_by_name(&self, name: String) -> Option> { + search(&self.ports, |a| a.name.eq(&name)) + } + + fn try_add_port(&mut self, id: u32, name: String, node_id: u32) -> bool { + let node = self.get_node(node_id); + + if node.is_none() { + return false; + } + + let node = node.unwrap(); + + if self + .port_def + .iter() + .filter(|a| a.name.eq(&name) && a.node.name.eq(&node.name)) + .count() + != 1 + { + if self.get_names && node.id == node_id { + println!("Port from node {} -> {}: {}", &node.name, id, name); + } + return false; + } + + let mut ports = self + .ports + .iter() + .filter(|a| !(a.name.eq(&name) && a.node.name.eq(&node.name))) + .cloned() + .collect::>>(); + + ports.push(Rc::new(Port { id, name, node })); + + self.ports = ports; + + true + } + + fn create_links(&mut self, port_name: String, core: Rc) { + #[derive(Debug)] + struct TempLink { + port_in: Option>, + port_out: Option>, + } + + self.link_def + .iter() + .filter(|link| (link.port_in.name.eq(&port_name) || link.port_out.name.eq(&port_name))) + .map(|a| TempLink { + port_in: self.get_port_by_name(a.port_in.name.to_string()), + port_out: self.get_port_by_name(a.port_out.name.to_string()), + }).filter(|a| a.port_in.is_some() && a.port_out.is_some()).for_each(|a| { + let port_in = a.port_in.unwrap(); + let port_out = a.port_out.unwrap(); + + println!("Try to created link: [{}]{} -> [{}]{}", port_out.node.name, port_out.name, port_in.node.name, port_in.name); + + // Try to create the link + if core.create_object::( + // The actual name for a link factory might be different for your system, + // you should probably obtain a factory from the registry. + "link-factory", + &pw::properties! { + "link.output.port" => port_out.id.to_string(), + "link.input.port" => port_in.id.to_string(), + "link.output.node" => port_out.node.id.to_string(), + "link.input.node" => port_in.node.id.to_string(), + "object.linger" => "1" + }, + ).is_err() { + println!("Failed to create link"); + } + }); + } +} + +fn deal_with_node( + global_object: &pipewire::registry::GlobalObject, + mut state: RefMut, +) { + if let Some(props) = &global_object.props { + if let (Some(class), Some(name)) = (props.get("media.class"), props.get("node.name")) { + if class.starts_with("Audio") { + if state.get_names { + println!( + "Got Audio device {}: {}({})", + global_object.id, + name, + props.get("node.nick").unwrap_or("") + ); + } + + if state.try_add_node(Node { + id: global_object.id, + name: name.to_string(), + }) { + println!( + "Got {}: {}({})", + global_object.id, + name, + props.get("node.nick").unwrap_or("") + ); + } + } + } + } else { + println!("No props! Skiping id: {:?}", global_object.id); + } +} + +fn deal_with_port( + port: &pipewire::registry::GlobalObject, + mut state: RefMut, + core: Rc, +) { + if let Some(props) = &port.props { + if let (Some(name), Some(node_id)) = (props.get("port.name"), props.get("node.id")) { + if let Ok(node_id) = node_id.parse::() { + if state.try_add_port(port.id, name.to_string(), node_id) { + println!( + "Got port {} for {}", + name, + state.get_node(node_id).unwrap().name + ); + state.create_links(name.to_string(), core) + } + } else { + println!("Clould not parse {}'s node.id({})", name, node_id) + } + } + } else { + println!("No props! Skiping id: {}", port.id); + } +} + +fn help() { + println!("Usage: \n"); + println!("pw-autoconnect \n") +} + +fn parse_file(path: std::path::PathBuf, get_names: bool) -> Result> { + let file = fs::File::open(path)?; + let reader = std::io::BufReader::new(file); + + lazy_static! { + static ref RE: Regex = Regex::new("\\[(?P.*)\\]\\((?P.*)\\)\\s*->\\s*\\[(?P.*)\\]\\((?P.*)\\)").unwrap(); + } + + let mut node_def: HashMap> = HashMap::new(); + let mut port_def: HashMap> = HashMap::new(); + let mut link_def: Vec> = Vec::new(); + + for line in reader.lines() { + let line = line?; + + if RE.is_match(&line) { + let caps = RE.captures(&line).unwrap(); + println!("Found link: [{}]{} -> [{}]{}", &caps["node_out"], &caps["port_out"], &caps["node_in"], &caps["port_in"]); + + let node_out = match node_def.get_mut(&caps["node_out"]) { + Some(node) => node.to_owned(), + None => { + let node = Rc::new(NodeDef {name: caps["node_out"].to_string()}); + node_def.insert(caps["node_out"].to_string(), node.clone()); + node + }, + }; + + let node_in = match node_def.get_mut(&caps["node_in"]) { + Some(node) => node.to_owned(), + None => { + let node = Rc::new(NodeDef {name: caps["node_in"].to_string()}); + node_def.insert(caps["node_in"].to_string(), node.clone()); + node + }, + }; + + let port_out = match port_def.get_mut(&caps["port_out"]) { + Some(port) => port.to_owned(), + None => { + let port = Rc::new(PortDef { node: node_out.clone(), name: caps["port_out"].to_string() } ); + port_def.insert(caps["port_out"].to_string(), port.clone()); + port + }, + }; + + let port_in = match port_def.get_mut(&caps["port_in"]) { + Some(port) => port.to_owned(), + None => { + let port = Rc::new(PortDef { node: node_in.clone(), name: caps["port_in"].to_string() } ); + port_def.insert(caps["port_in"].to_string(), port.clone()); + port + }, + }; + + let link = Rc::new(LinkDef { port_out: port_out.clone(), port_in: port_in.clone() }); + + link_def.push(link) + } else if !line.starts_with('#') { + println!("invalid line: {}", line); + } + } + + let node_def = node_def.values().cloned().collect::>>(); + let port_def = port_def.values().cloned().collect::>>(); + + Ok(AppState::new(node_def, link_def, port_def, get_names)) +} + +fn main() -> Result<(), Box> { + println!("Hello, world!"); + + let mut args = env::args(); + // Skip the current directory + args.next(); + + let mut find_names = false; + + let mut file_name = None; + + for a in args { + if a.eq("-f") { + find_names = true; + continue; + } + + if file_name.is_some() { + println!("File name already exists"); + return Ok(()); + } else { + file_name = Some(a); + } + } + + if file_name.is_none() { + help(); + return Ok(()); + } + + let file_name = file_name.unwrap(); + + let path = std::path::Path::new(&file_name); + + if !path.exists() || !path.is_file() { + println!("File not found does not exists"); + return Ok(()); + } + + // Create DeSized State + + let state = RefCell::new(parse_file(path.to_path_buf(), find_names)?); + + println!("\n\nGot state! Starting up\n\n"); + + let mainloop = MainLoop::new()?; + let context = Context::new(&mainloop)?; + let core = Rc::new(context.connect(None)?); + let registry = core.get_registry()?; + + let _listener = registry + .add_listener_local() + .global(move |global| match global.type_ { + ObjectType::Port => deal_with_port(global, state.borrow_mut(), core.clone()), + ObjectType::Node => deal_with_node(global, state.borrow_mut()), + _ => (), + }) + .register(); + + mainloop.run(); + + Ok(()) +}