From 7e26e9204119aa13e62f70b27ff9ce777d3d2e4a Mon Sep 17 00:00:00 2001 From: Curve Date: Wed, 24 Jan 2024 21:44:39 +0100 Subject: [PATCH] feat: add redirect-workaround (resolves #15) Much love to @wwmm for this awesome approach <3! --- CMakeLists.txt | 2 +- README.md | 6 +++- addon/addon.cpp | 2 ++ include/vencord/patchbay.hpp | 1 + lib/module.d.ts | 1 + package.json | 2 +- private/patchbay.impl.hpp | 5 +++ server/main.cpp | 7 ++-- src/patchbay.impl.cpp | 70 +++++++++++++++++++++++++++++++----- 9 files changed, 81 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f33dc88..5693a6c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,7 +81,7 @@ include("cmake/cpm.cmake") CPMFindPackage( NAME rohrkabel - VERSION 2.7 + VERSION 3.0 GIT_REPOSITORY "https://github.com/Curve/rohrkabel" ) diff --git a/README.md b/README.md index 0999303..69616e5 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,8 @@ The Rest-Server exposes three simple endpoints [ { "key": "node.name", "value": "Chrome" } ] - "ignore_devices": true + "ignore_devices": true, + "workaround": [{ "key": "node.name", "value": "Chrome" }] } @@ -50,6 +51,9 @@ The Rest-Server exposes three simple endpoints The setting `ignore_devices` is optional and will default to `true`. When enabled it will prevent hardware-devices like speakers and microphones from being linked to the virtual microphone. + + The setting `workaround` is also optional and will default to an empty array. + When set, venmic will redirect the first node that matches the all of the specified properties to itself. * (GET) `/unlink` diff --git a/addon/addon.cpp b/addon/addon.cpp index 7301f72..744533b 100644 --- a/addon/addon.cpp +++ b/addon/addon.cpp @@ -162,6 +162,7 @@ struct patchbay : public Napi::ObjectWrap auto include = to_array(data.Get("include")); auto exclude = to_array(data.Get("exclude")); auto ignore_devices = convert(data.Get("ignore_devices")); + auto workaround = convert(data.Get("workaround")); if (!include && !exclude) { @@ -176,6 +177,7 @@ struct patchbay : public Napi::ObjectWrap .include = include.value_or(std::vector{}), .exclude = exclude.value_or(std::vector{}), .ignore_devices = ignore_devices.value_or(true), + .workaround = workaround, }); return Napi::Boolean::New(env, true); diff --git a/include/vencord/patchbay.hpp b/include/vencord/patchbay.hpp index 7be3ef7..de8a2f6 100644 --- a/include/vencord/patchbay.hpp +++ b/include/vencord/patchbay.hpp @@ -20,6 +20,7 @@ namespace vencord public: bool ignore_devices{true}; + std::vector workaround; }; using node = std::map; diff --git a/lib/module.d.ts b/lib/module.d.ts index c76a315..55d8722 100644 --- a/lib/module.d.ts +++ b/lib/module.d.ts @@ -22,6 +22,7 @@ export interface LinkData exclude: Prop[]; ignore_devices?: boolean; + workaround?: Prop; } diff --git a/package.json b/package.json index c93463e..0421b5e 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "private": false, "license": "MPL-2.0", "author": "Curve (https://github.com/Curve)", - "version": "3.2.3", + "version": "3.3.0", "main": "./lib/index.js", "types": "./lib/module.d.ts", "scripts": { diff --git a/private/patchbay.impl.hpp b/private/patchbay.impl.hpp index 1583969..b6d33ac 100644 --- a/private/patchbay.impl.hpp +++ b/private/patchbay.impl.hpp @@ -52,6 +52,10 @@ namespace vencord std::shared_ptr core; std::shared_ptr registry; + private: + std::unique_ptr metadata; + std::optional lettuce_target; // https://github.com/Vencord/venmic/issues/15 + private: std::atomic_bool should_exit{false}; @@ -63,6 +67,7 @@ namespace vencord private: void create_mic(); + void cleanup(bool); void relink(std::uint32_t); private: diff --git a/server/main.cpp b/server/main.cpp index c15d83e..7cddf15 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -15,9 +15,10 @@ template <> struct glz::meta { using T = vencord::link_options; - static constexpr auto value = object("exclude", &T::exclude, // - "include", &T::include, // - "ignore_devices", &T::ignore_devices); + static constexpr auto value = object("exclude", &T::exclude, // + "include", &T::include, // + "ignore_devices", &T::ignore_devices, // + "workaround", &T::workaround); }; int main(int argc, char **args) diff --git a/src/patchbay.impl.cpp b/src/patchbay.impl.cpp index 2a1e5ad..1451218 100644 --- a/src/patchbay.impl.cpp +++ b/src/patchbay.impl.cpp @@ -20,9 +20,10 @@ namespace vencord patchbay::impl::~impl() { + cleanup(true); should_exit = true; - sender->send(quit{}); + sender->send(quit{}); thread.join(); } @@ -67,6 +68,24 @@ namespace vencord virt_mic = std::make_unique(std::move(*node)); } + void patchbay::impl::cleanup(bool mic) + { + created.clear(); + + if (metadata && lettuce_target) + { + metadata->clear_property(lettuce_target.value(), "target.node"); + metadata->clear_property(lettuce_target.value(), "target.object"); + } + + if (!mic) + { + return; + } + + virt_mic.reset(); + } + void patchbay::impl::relink(std::uint32_t id) { created.erase(id); @@ -165,10 +184,40 @@ namespace vencord nodes[id].info = node.info(); - logger::get()->trace("[patchbay] (add_global) new node: {} (name: \"{}\", app: \"{}\")", node.id(), - props["node.name"], props["application.name"]); + logger::get()->trace(R"([patchbay] (add_global) new node: {} (name: "{}", app: "{}"))", id, props["node.name"], + props["application.name"]); + + if (options.workaround.empty() || !metadata || !virt_mic) + { + return on_node(id); + } + + logger::get()->trace("[patchbay] (add_global) workaround is active ({})", glz::write_json(options.workaround)); + + auto match = [&](const auto &prop) + { + return props[prop.key] == prop.value; + }; + + if (!ranges::all_of(options.workaround, match)) + { + return on_node(id); + } + + const auto serial = virt_mic->info().props["object.serial"]; - on_node(id); + logger::get()->debug("[patchbay] (add_global) applying workaround to {} (mic = {}, serial = {})", id, + virt_mic->id(), serial); + + // https://github.com/Vencord/venmic/issues/13#issuecomment-1884975782 + + metadata->set_property(id, "target.object", "Spa:Id", serial); + metadata->set_property(id, "target.node", "Spa:Id", fmt::format("{}", virt_mic->id())); + + lettuce_target.emplace(id); + options.workaround.clear(); + + core->update(); } template <> @@ -212,13 +261,17 @@ namespace vencord template <> void patchbay::impl::add_global(pw::metadata &data) { - auto props = data.properties(); + auto props = data.properties(); + const auto name = data.props()["metadata.name"]; - if (!props.contains("default.audio.sink")) + if (name != "default") { return; } + metadata = std::make_unique(std::move(data)); + logger::get()->info("[patchbay] (add_global) found metadata: {}", metadata->id()); + auto parsed = glz::read_json(props["default.audio.sink"].value); if (!parsed.has_value()) @@ -405,7 +458,7 @@ namespace vencord create_mic(); } - created.clear(); + cleanup(false); options = std::move(req); @@ -423,8 +476,7 @@ namespace vencord template <> void patchbay::impl::receive([[maybe_unused]] cr_recipe::sender &, [[maybe_unused]] unset_target &) { - created.clear(); - virt_mic.reset(); + cleanup(true); } template <>