diff --git a/CMakeLists.txt b/CMakeLists.txt index 63b8ad0..e1acc7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.21) -project(venmic LANGUAGES CXX VERSION 3.1.0) +project(venmic LANGUAGES CXX VERSION 3.2.0) # -------------------------------------------------------------------------------------------------------- # Library options @@ -99,7 +99,7 @@ CPMFindPackage( CPMFindPackage( NAME glaze - VERSION 1.9.7 + VERSION 2.0.2 GIT_REPOSITORY "https://github.com/stephenberry/glaze" ) diff --git a/addon/addon.cpp b/addon/addon.cpp index 8756a04..7301f72 100644 --- a/addon/addon.cpp +++ b/addon/addon.cpp @@ -21,6 +21,17 @@ std::optional convert(Napi::Value value) return value.ToString(); } +template <> +std::optional convert(Napi::Value value) +{ + if (!value.IsBoolean()) + { + return std::nullopt; + } + + return value.ToBoolean(); +} + template <> std::optional convert(Napi::Value value) { @@ -148,8 +159,9 @@ struct patchbay : public Napi::ObjectWrap return Napi::Boolean::New(env, false); } - auto include = to_array(data.Get("include")); - auto exclude = to_array(data.Get("exclude")); + auto include = to_array(data.Get("include")); + auto exclude = to_array(data.Get("exclude")); + auto ignore_devices = convert(data.Get("ignore_devices")); if (!include && !exclude) { @@ -160,8 +172,11 @@ struct patchbay : public Napi::ObjectWrap return Napi::Boolean::New(env, false); } - vencord::patchbay::get().link(include.value_or(std::vector{}), - exclude.value_or(std::vector{})); + vencord::patchbay::get().link({ + .include = include.value_or(std::vector{}), + .exclude = exclude.value_or(std::vector{}), + .ignore_devices = ignore_devices.value_or(true), + }); return Napi::Boolean::New(env, true); } diff --git a/include/vencord/patchbay.hpp b/include/vencord/patchbay.hpp index 3b1bf4e..7be3ef7 100644 --- a/include/vencord/patchbay.hpp +++ b/include/vencord/patchbay.hpp @@ -13,6 +13,15 @@ namespace vencord std::string value; }; + struct link_options + { + std::vector include; + std::vector exclude; + + public: + bool ignore_devices{true}; + }; + using node = std::map; class patchbay @@ -29,7 +38,7 @@ namespace vencord patchbay(); public: - void link(std::vector include, std::vector exclude); + void link(link_options options); public: void unlink(); diff --git a/lib/module.d.ts b/lib/module.d.ts index 3912432..be87d5e 100644 --- a/lib/module.d.ts +++ b/lib/module.d.ts @@ -16,7 +16,7 @@ export class PatchBay unlink(): void; list(props?: T[]): Record, string>[]; - link(data: {include: Prop[], exclude: Prop[]}): boolean; + link(data: {include: Prop[], exclude: Prop[], ignore_devices?: boolean}): boolean; static hasPipeWire(): boolean; } diff --git a/package.json b/package.json index 3d75c74..ce5b052 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "private": false, "license": "MIT", "author": "Curve (https://github.com/Curve)", - "version": "3.1.0", + "version": "3.2.0", "main": "./lib/index.js", "types": "./lib/module.d.ts", "scripts": { diff --git a/private/message.hpp b/private/message.hpp index c4a68e9..77bd212 100644 --- a/private/message.hpp +++ b/private/message.hpp @@ -1,4 +1,5 @@ #pragma once + #include "patchbay.hpp" #include @@ -15,12 +16,6 @@ namespace vencord std::vector props; }; - struct set_target - { - std::vector include; - std::vector exclude; - }; - struct unset_target { }; @@ -34,6 +29,6 @@ namespace vencord bool success{true}; }; - using pw_recipe = pw::recipe; + using pw_recipe = pw::recipe; using cr_recipe = cr::recipe, ready>; } // namespace vencord diff --git a/private/patchbay.impl.hpp b/private/patchbay.impl.hpp index eb37f7f..1583969 100644 --- a/private/patchbay.impl.hpp +++ b/private/patchbay.impl.hpp @@ -1,4 +1,5 @@ #pragma once + #include "patchbay.hpp" #include "message.hpp" @@ -36,11 +37,10 @@ namespace vencord std::unique_ptr receiver; private: - std::vector include; - std::vector exclude; + link_options options; private: - std::unique_ptr mic; + std::unique_ptr virt_mic; std::optional speaker; std::multimap created; diff --git a/server/main.cpp b/server/main.cpp index 091afb1..79f8708 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -4,12 +4,6 @@ #include #include -struct targets -{ - std::vector include; - std::vector exclude; -}; - template <> struct glz::meta { @@ -18,10 +12,12 @@ struct glz::meta }; template <> -struct glz::meta +struct glz::meta { - using T = targets; - static constexpr auto value = object("include", &T::include, "exclude", &T::exclude); + using T = vencord::link_options; + static constexpr auto value = object("exclude", &T::exclude, // + "include", &T::include, // + "ignore_devices", &T::ignore_devices); }; int main(int argc, char **args) @@ -63,7 +59,7 @@ int main(int argc, char **args) server.Post("/link", [](const auto &req, auto &response) { - targets parsed; + vencord::link_options parsed; auto error = glz::read(parsed, req.body); @@ -73,7 +69,7 @@ int main(int argc, char **args) return; } - patchbay::get().link(parsed.include, parsed.exclude); + patchbay::get().link(std::move(parsed)); response.status = 200; }); diff --git a/src/patchbay.cpp b/src/patchbay.cpp index e44132e..fffd018 100644 --- a/src/patchbay.cpp +++ b/src/patchbay.cpp @@ -13,12 +13,10 @@ namespace vencord patchbay::patchbay() : m_impl(std::make_unique()) {} - void patchbay::link(std::vector include, std::vector exclude) + void patchbay::link(link_options options) { - const auto request = set_target{std::move(include), std::move(exclude)}; - m_impl->sender->send(request); - - logger::get()->trace(R"([patchbay] (link) request: "{}")", glz::write_json(request)); + m_impl->sender->send(std::move(options)); + logger::get()->trace(R"([patchbay] (link) request: "{}")", glz::write_json(options)); } void patchbay::unlink() diff --git a/src/patchbay.impl.cpp b/src/patchbay.impl.cpp index 8460c12..2a1e5ad 100644 --- a/src/patchbay.impl.cpp +++ b/src/patchbay.impl.cpp @@ -7,11 +7,10 @@ #include #include -#include - -#include #include +#include + namespace vencord { struct pw_metadata_name @@ -65,14 +64,14 @@ namespace vencord core->update(); } - mic = std::make_unique(std::move(*node)); + virt_mic = std::make_unique(std::move(*node)); } void patchbay::impl::relink(std::uint32_t id) { created.erase(id); - if (!mic) + if (!virt_mic) { return; } @@ -82,16 +81,23 @@ namespace vencord return; } - if (id == mic->id()) + if (id == virt_mic->id()) { - logger::get()->warn("[patchbay] (relink) prevented link to self", id, mic->id()); + logger::get()->warn("[patchbay] (relink) prevented link to self", id, virt_mic->id()); return; } - logger::get()->debug("[patchbay] (relink) linking {} [with mic = {}]", id, mic->id()); - auto &target = nodes[id]; - auto &source = nodes[mic->id()]; + + if (options.ignore_devices && !target.info.props["device.id"].empty()) + { + logger::get()->warn("[patchbay] (relink) prevented link to device", id, virt_mic->id()); + return; + } + + logger::get()->debug("[patchbay] (relink) linking {} [with mic = {}]", id, virt_mic->id()); + + auto &source = nodes[virt_mic->id()]; auto is_output = [](const auto &item) { @@ -275,7 +281,7 @@ namespace vencord void patchbay::impl::on_link(std::uint32_t id) { - if (!include.empty() || !speaker) + if (!options.include.empty() || !speaker) { return; } @@ -297,7 +303,7 @@ namespace vencord return output.info.props[prop.key] == prop.value; }; - if (ranges::any_of(exclude, match)) + if (ranges::any_of(options.exclude, match)) { return; } @@ -317,7 +323,7 @@ namespace vencord speaker->id = id; } - if (include.empty()) + if (options.include.empty()) { return; } @@ -327,13 +333,13 @@ namespace vencord return info.props[prop.key] == prop.value; }; - if (ranges::any_of(exclude, match)) + if (ranges::any_of(options.exclude, match)) { logger::get()->debug("[patchbay] (on_node) {} is excluded", id); return; } - if (!ranges::any_of(include, match)) + if (!ranges::any_of(options.include, match)) { logger::get()->debug("[patchbay] (on_node) {} is not included", id); return; @@ -392,17 +398,16 @@ namespace vencord } template <> - void patchbay::impl::receive([[maybe_unused]] cr_recipe::sender &, set_target &req) + void patchbay::impl::receive([[maybe_unused]] cr_recipe::sender &, link_options &req) { - if (!mic) + if (!virt_mic) { create_mic(); } created.clear(); - include = std::move(req.include); - exclude = std::move(req.exclude); + options = std::move(req); for (const auto &[id, info] : nodes) { @@ -418,12 +423,8 @@ namespace vencord template <> void patchbay::impl::receive([[maybe_unused]] cr_recipe::sender &, [[maybe_unused]] unset_target &) { - include.clear(); - exclude.clear(); - created.clear(); - - mic.reset(); + virt_mic.reset(); } template <> diff --git a/tests/node/api.test.js b/tests/node/api.test.js index 7cac44d..4f2f588 100644 --- a/tests/node/api.test.js +++ b/tests/node/api.test.js @@ -25,15 +25,16 @@ assert.throws(() => patchbay.list([10]), /expected list of strings/ig); assert.throws(() => patchbay.link(10), /expected link object/ig); -assert.throws(() => patchbay.link({ }), /'include' and 'exclude'/ig); -assert.throws(() => patchbay.link({ a: "A", b: "B", c: "C" }), /'include' and 'exclude'/ig); -assert.throws(() => patchbay.link({ key: "node.name", value: "Firefox", mode: "gibberish" }), /'include' and 'exclude'/ig); +assert.throws(() => patchbay.link({ }), /'include' or 'exclude'/ig); +assert.throws(() => patchbay.link({ a: "A", b: "B", c: "C" }), /'include' or 'exclude'/ig); +assert.throws(() => patchbay.link({ key: "node.name", value: "Firefox", mode: "gibberish" }), /'include' or 'exclude'/ig); assert.throws(() => patchbay.link({ include: "Firefox" }), /key-value/ig); assert.throws(() => patchbay.link({ include: {} }), /key-value/ig); assert.doesNotThrow(() => patchbay.link({ include: [{ key: "node.name", value: "Firefox" }] })); assert.doesNotThrow(() => patchbay.link({ exclude: [{ key: "node.name", value: "Firefox" }] })); +assert.doesNotThrow(() => patchbay.link({ exclude: [{ key: "node.name", value: "Firefox" }], ignore_devices: true })); assert.doesNotThrow(() => patchbay.link({ include: [{ key: "node.name", value: "Firefox" }], exclude: [{ key: "object.id", value: "100" }] })); assert.doesNotThrow(() => patchbay.unlink());