├── .clang-format
├── .clang-tidy
├── .eslintrc.cjs
├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ └── bug-report.yml
└── workflows
│ ├── build-container.yml
│ ├── publish.yml
│ ├── server.yml
│ └── test.yml
├── .gitignore
├── .npmignore
├── CMakeLists.txt
├── LICENSE
├── README.md
├── addon
├── CMakeLists.txt
└── addon.cpp
├── cmake
├── FindPulseAudio.cmake
└── cpm.cmake
├── docker
├── Dockerfile
└── build.sh
├── include
└── vencord
│ ├── logger.hpp
│ └── patchbay.hpp
├── lib
├── index.js
├── module.d.ts
└── options.js
├── package.json
├── pnpm-lock.yaml
├── private
├── message.hpp
└── patchbay.impl.hpp
├── server
├── CMakeLists.txt
└── main.cpp
├── src
├── logger.cpp
├── patchbay.cpp
└── patchbay.impl.cpp
└── tests
└── node
└── api.test.js
/.clang-format:
--------------------------------------------------------------------------------
1 | ---
2 | Language: Cpp
3 | InsertNewlineAtEOF: true
4 | AccessModifierOffset: -2
5 | AlignAfterOpenBracket: Align
6 | AlignConsecutiveMacros: false
7 | AlignConsecutiveAssignments:
8 | Enabled: true
9 | AcrossComments: false
10 | AcrossEmptyLines: false
11 | AlignConsecutiveDeclarations: false
12 | AlignEscapedNewlines: Right
13 | AlignOperands: true
14 | AlignTrailingComments: true
15 | AllowAllArgumentsOnNextLine: true
16 | AllowAllConstructorInitializersOnNextLine: true
17 | AllowAllParametersOfDeclarationOnNextLine: true
18 | AllowShortBlocksOnASingleLine: Never
19 | AllowShortCaseLabelsOnASingleLine: false
20 | AllowShortFunctionsOnASingleLine: Empty
21 | AllowShortLambdasOnASingleLine: Inline
22 | AllowShortIfStatementsOnASingleLine: Never
23 | AllowShortLoopsOnASingleLine: false
24 | AlwaysBreakAfterDefinitionReturnType: None
25 | AlwaysBreakAfterReturnType: None
26 | AlwaysBreakBeforeMultilineStrings: false
27 | AlwaysBreakTemplateDeclarations: Yes
28 | BinPackArguments: true
29 | BinPackParameters: true
30 | BraceWrapping:
31 | BeforeLambdaBody: true
32 | AfterCaseLabel: false
33 | AfterClass: true
34 | AfterControlStatement: true
35 | AfterEnum: true
36 | AfterFunction: true
37 | AfterNamespace: true
38 | AfterObjCDeclaration: true
39 | AfterStruct: true
40 | AfterUnion: false
41 | AfterExternBlock: true
42 | BeforeCatch: true
43 | BeforeElse: true
44 | IndentBraces: false
45 | SplitEmptyFunction: true
46 | SplitEmptyRecord: true
47 | SplitEmptyNamespace: true
48 | BreakBeforeBinaryOperators: None
49 | BreakBeforeBraces: Custom
50 | BreakBeforeInheritanceComma: false
51 | BreakInheritanceList: BeforeColon
52 | BreakBeforeTernaryOperators: true
53 | BreakConstructorInitializersBeforeComma: false
54 | BreakConstructorInitializers: BeforeColon
55 | BreakAfterJavaFieldAnnotations: false
56 | BreakStringLiterals: true
57 | ColumnLimit: 120
58 | CompactNamespaces: false
59 | ConstructorInitializerAllOnOneLineOrOnePerLine: false
60 | ConstructorInitializerIndentWidth: 4
61 | ContinuationIndentWidth: 4
62 | Cpp11BracedListStyle: true
63 | DeriveLineEnding: true
64 | DerivePointerAlignment: false
65 | FixNamespaceComments: true
66 | IndentCaseLabels: false
67 | IndentGotoLabels: true
68 | IndentPPDirectives: None
69 | IndentWidth: 4
70 | IndentWrappedFunctionNames: false
71 | KeepEmptyLinesAtTheStartOfBlocks: true
72 | NamespaceIndentation: All
73 | PointerAlignment: Right
74 | ReflowComments: true
75 | SortIncludes: false
76 | SortUsingDeclarations: true
77 | SpaceAfterCStyleCast: false
78 | SpaceAfterLogicalNot: false
79 | SpaceAfterTemplateKeyword: true
80 | SpaceBeforeAssignmentOperators: true
81 | SpaceBeforeCpp11BracedList: false
82 | SpaceBeforeCtorInitializerColon: true
83 | SpaceBeforeInheritanceColon: true
84 | SpaceBeforeParens: ControlStatements
85 | SpaceBeforeRangeBasedForLoopColon: true
86 | SpaceInEmptyBlock: false
87 | SpaceInEmptyParentheses: false
88 | SpacesBeforeTrailingComments: 1
89 | SpacesInAngles: false
90 | SpacesInConditionalStatement: false
91 | SpacesInContainerLiterals: true
92 | SpacesInCStyleCastParentheses: false
93 | SpacesInParentheses: false
94 | SpacesInSquareBrackets: false
95 | SpaceBeforeSquareBrackets: false
96 | Standard: Latest
97 | TabWidth: 4
98 | UseCRLF: false
99 | UseTab: Never
100 |
--------------------------------------------------------------------------------
/.clang-tidy:
--------------------------------------------------------------------------------
1 | ---
2 | Checks: "*,
3 | -abseil-*,
4 | -altera-*,
5 | -android-*,
6 | -fuchsia-*,
7 | -google-*,
8 | -llvm*,
9 | -modernize-use-trailing-return-type,
10 | -zircon-*,
11 | -readability-else-after-return,
12 | -readability-static-accessed-through-instance,
13 | -readability-avoid-const-params-in-decls,
14 | -cppcoreguidelines-non-private-member-variables-in-classes,
15 | -misc-non-private-member-variables-in-classes,
16 | -readability-redundant-access-specifiers,
17 | -cppcoreguidelines-special-member-functions,
18 | -hicpp-special-member-functions,
19 | -readability-implicit-bool-conversion,
20 | -hicpp-explicit-conversions,
21 | -*-magic-numbers,
22 | -readability-named-parameter,
23 | -hicpp-named-parameter,
24 | -readability-identifier-length,
25 | -cppcoreguidelines-owning-memory,
26 | -cppcoreguidelines-pro-type-reinterpret-cast,
27 | -cppcoreguidelines-avoid-non-const-global-variables,
28 | -hicpp-signed-bitwise,
29 | -*-uppercase-literal-suffix,
30 | -*-cognitive-complexity,
31 | -*-multiway-paths-covered,
32 | -*-switch-missing-default-case,
33 | -*-avoid-endl,
34 | -cppcoreguidelines-pro-type-static-cast-downcast,
35 | -misc-header-include-cycle,
36 | -cppcoreguidelines-pro-type-vararg,
37 | -*-member-init,
38 | -bugprone-easily-swappable-parameters,
39 | -hicpp-vararg,
40 | -cppcoreguidelines-pro-bounds-pointer-arithmetic,
41 | -*-dcl21-cpp,
42 | -cert-err58-cpp,
43 | -performance-no-int-to-ptr,
44 | -cppcoreguidelines-interfaces-global-init,
45 | -*-avoid-c-arrays,
46 | -hicpp-no-array-decay
47 | -*-array-to-pointer-decay
48 | "
49 | WarningsAsErrors: ''
50 | HeaderFilterRegex: ''
51 | FormatStyle: none
52 |
--------------------------------------------------------------------------------
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | node: true,
4 | },
5 | extends : ["eslint:recommended"],
6 | parserOptions: {
7 | ecmaVersion: "latest",
8 | sourceType : "module",
9 | },
10 | rules: {
11 | "object-curly-spacing": ["error", "always"],
12 | "brace-style" : ["error", "allman"],
13 | quotes : ["error", "double"],
14 | semi : ["error", "always"],
15 | "linebreak-style" : ["error", "unix"],
16 | indent : ["error", 4],
17 | "no-else-return" : 1,
18 | "space-unary-ops" : 2,
19 | "keyword-spacing" : ["error", {
20 | "before": true,
21 | "after" : true,
22 | }],
23 | "arrow-spacing" : "error",
24 | "comma-spacing" : ["error", { "before": false, "after": true }],
25 | "space-infix-ops" : ["error", { "int32Hint": false }],
26 | "space-before-blocks": ["error", { "functions": "always", "keywords": "always", "classes": "always" }],
27 | "no-multi-spaces" : "error",
28 | "no-trailing-spaces" : "error",
29 | "semi-spacing" : "error",
30 | "key-spacing" : [2, {
31 | "singleLine": {
32 | "beforeColon": false,
33 | "afterColon" : true
34 | },
35 | "multiLine": {
36 | "beforeColon": false,
37 | "afterColon" : true,
38 | "align" : "colon"
39 | }
40 | }]
41 | },
42 | };
43 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: Curve
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
14 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report.yml:
--------------------------------------------------------------------------------
1 | name: 🐛 Bug Report
2 | description: Report a bug in the current version of venmic
3 | labels: ["bug"]
4 | assignees: Curve
5 |
6 | body:
7 | - type: textarea
8 | attributes:
9 | label: ✍️ Bug Description
10 | description: A clear and concise description of what the bug is.
11 | validations:
12 | required: true
13 |
14 | - type: textarea
15 | attributes:
16 | label: 🔁 Steps to reproduce
17 | description: Steps to reproduce the behavior.
18 | validations:
19 | required: true
20 |
21 | - type: textarea
22 | attributes:
23 | label: 🗒️ Debug Output
24 | description: Please dump the contents of the log or stdout here (see https://github.com/Vencord/venmic#-debugging).
25 | validations:
26 | required: true
27 |
28 | - type: textarea
29 | attributes:
30 | label: ❔ Expected behavior
31 | description: A clear and concise description of what you expected to happen.
32 | validations:
33 | required: false
34 |
35 | - type: textarea
36 | attributes:
37 | label: 👀 Screenshots
38 | description: (If applicable) Add screenshots from applications like qpwgraph (https://flathub.org/apps/org.rncbc.qpwgraph) here.
39 | validations:
40 | required: false
41 |
42 | - type: input
43 | attributes:
44 | label: 📦 Vesktop Version
45 | description: Please note the Vesktop version used (can be found in Vesktop -> About Vesktop).
46 | validations:
47 | required: true
48 |
49 | - type: input
50 | attributes:
51 | label: 🖥️ Distribution
52 | description: Please note the distribution you use here as well as it's release if applicable.
53 | validations:
54 | required: false
55 |
56 | - type: checkboxes
57 | attributes:
58 | label: ✅ I confirm that...
59 | description: Please confirm these things by clicking the checkboxes
60 | options:
61 | - label: I have collected all the required information and read all the comments in this document
62 | required: true
63 | - label: I searched for an existing bug report for this issue
64 | required: true
65 | - label: the problem does occur with the reproduction steps I provided
66 | required: true
67 |
--------------------------------------------------------------------------------
/.github/workflows/build-container.yml:
--------------------------------------------------------------------------------
1 | on:
2 | workflow_dispatch:
3 | inputs:
4 | skip-cache:
5 | type: boolean
6 | description: Skip Cache
7 |
8 | name: 🐳 Build & Publish Docker Image
9 |
10 | jobs:
11 | build-container:
12 | strategy:
13 | matrix:
14 | arch: ["arm64", "amd64"]
15 |
16 | runs-on: ubuntu-latest
17 |
18 | steps:
19 | - name: 📥 Checkout
20 | uses: actions/checkout@v4
21 |
22 | - name: 🤖 Setup Qemu
23 | uses: docker/setup-qemu-action@v3
24 | with:
25 | platforms: "arm64"
26 |
27 | - name: 🐋 Setup Buildx
28 | uses: docker/setup-buildx-action@v3
29 |
30 | - name: 🦥 Cache Image
31 | id: cache-image
32 | uses: actions/cache@v4
33 | with:
34 | key: venmic-builder-cache-${{ matrix.arch }}
35 | path: |
36 | docker/venmic-builder-${{ matrix.arch }}.tar
37 |
38 | - name: 🏗️ Build Image
39 | if: steps.cache-image.outputs.cache-hit != 'true' && ${{ github.event.inputs.skip-cache != 'true' }}
40 | run: |
41 | cd docker
42 |
43 | docker buildx build --platform=linux/${{ matrix.arch }} --tag venmic-builder-${{ matrix.arch }} --load .
44 | docker save venmic-builder-${{ matrix.arch }} > venmic-builder-${{ matrix.arch }}.tar
45 |
46 | - name: 🔐 Login
47 | uses: docker/login-action@v3
48 | with:
49 | registry: ghcr.io
50 | username: ${{ github.actor }}
51 | password: ${{ secrets.GITHUB_TOKEN }}
52 |
53 | - name: ♻️ Publish Images
54 | run: |
55 | docker load < docker/venmic-builder-${{ matrix.arch }}.tar
56 | docker image tag venmic-builder-${{ matrix.arch }} ghcr.io/vencord/venmic-builder-${{ matrix.arch }}
57 |
58 | docker push ghcr.io/vencord/venmic-builder-${{ matrix.arch }}:latest
59 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | on:
2 | workflow_dispatch:
3 | inputs:
4 | test:
5 | type: boolean
6 | description: Skip publishing step
7 | fix:
8 | type: boolean
9 | description: Skip build step
10 | reuse:
11 | type: string
12 | description: Workflow to reuse artifacts from
13 | no-tag-check:
14 | type: boolean
15 | description: Skip tag checking step
16 | push:
17 | tags:
18 | - "*"
19 |
20 | name: 🚀 Publish Package
21 |
22 | jobs:
23 | build:
24 | strategy:
25 | matrix:
26 | arch: ["arm64", "amd64"]
27 |
28 | runs-on: ubuntu-latest
29 |
30 | steps:
31 | - name: 📥 Checkout
32 | uses: actions/checkout@v4
33 |
34 | - name: 🤖 Setup Qemu
35 | uses: docker/setup-qemu-action@v3
36 | with:
37 | platforms: "arm64"
38 |
39 | - name: 🏗️ Build Addon
40 | if: ${{ github.event.inputs.fix != 'true' }}
41 | run: |
42 | docker run -v ${{ github.workspace }}:/work --platform linux/${{ matrix.arch }} ghcr.io/vencord/venmic-builder-${{ matrix.arch }}:latest /build.sh
43 |
44 | - name: ♻️ Reuse Artifact
45 | if: ${{ github.event.inputs.fix == 'true' }}
46 | uses: actions/download-artifact@v4
47 | with:
48 | name: addon-${{ matrix.arch }}
49 | path: build/Release
50 | github-token: ${{ secrets.ACTIONS_TOKEN }}
51 | run-id: ${{ github.event.inputs.reuse }}
52 |
53 | - name: 📤 Upload Artifact
54 | uses: actions/upload-artifact@v4
55 | with:
56 | name: addon-${{ matrix.arch }}
57 | path: build/Release
58 |
59 | publish:
60 | needs: [build]
61 | runs-on: ubuntu-latest
62 | container: fedora:38
63 |
64 | steps:
65 | - name: 📥 Checkout
66 | uses: actions/checkout@v4
67 |
68 | - name: 🛑 Check Tag
69 | if: ${{ github.event.inputs.no-tag-check != 'true' }}
70 | run: |
71 | dnf install -y jq
72 | pkg_version="v$(jq -r .version < package.json)"
73 | if [[ "${{ github.ref_name }}" != "$pkg_version" ]]; then
74 | echo "Tag ${{ github.ref_name }} does not match package.json version $pkg_version" >&2
75 | exit 1
76 | fi
77 |
78 | - name: 🍃 Install Node
79 | uses: actions/setup-node@v4
80 | with:
81 | node-version: 16
82 | registry-url: "https://registry.npmjs.org"
83 |
84 | - name: 🍃 Install pnpm
85 | uses: pnpm/action-setup@v3
86 | with:
87 | version: 8
88 | run_install: false
89 |
90 | - name: 🏗️ Setup Dependencies
91 | run: pnpm install --ignore-scripts
92 |
93 | - name: 📦 Download Build (amd64)
94 | uses: actions/download-artifact@v4
95 | with:
96 | name: addon-amd64
97 | path: build/Release
98 |
99 | - name: 🛠️ Prepare Prebuilds (amd64)
100 | run: pnpm pkg-prebuilds-copy --baseDir build/Release --source venmic-addon.node --name=venmic-addon --strip --napi_version=7 --arch=x64
101 |
102 | - name: 📦 Download Build (arm64)
103 | uses: actions/download-artifact@v4
104 | with:
105 | name: addon-arm64
106 | path: build/Release
107 |
108 | - name: 🛠️ Prepare Prebuilds (arm64)
109 | run: pnpm pkg-prebuilds-copy --baseDir build/Release --source venmic-addon.node --name=venmic-addon --strip --napi_version=7 --arch=arm64
110 |
111 | - name: 🛒 Publish
112 | if: ${{ github.event.inputs.test != 'true' }}
113 | run: pnpm publish
114 | env:
115 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
116 |
--------------------------------------------------------------------------------
/.github/workflows/server.yml:
--------------------------------------------------------------------------------
1 | on:
2 | push:
3 | pull_request:
4 |
5 | name: 🏗️ Build Server
6 |
7 | jobs:
8 | build-fedora:
9 | runs-on: ubuntu-latest
10 | container: fedora:38
11 |
12 | steps:
13 | - name: 📥 Checkout
14 | uses: actions/checkout@v4
15 |
16 | - name: 👷 Build Dependencies
17 | run: |
18 | dnf install -y make automake gcc gcc-c++ kernel-devel cmake git
19 | dnf install -y pipewire-devel pipewire-libs pulseaudio-libs-devel pipewire-pulseaudio
20 |
21 | - name: 🔨 Build
22 | run: |
23 | cmake -B build
24 | cmake --build build
25 |
26 | - name: 🚀 Upload Artifact
27 | uses: actions/upload-artifact@v3
28 | with:
29 | name: server-amd64
30 | path: build/server
31 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | on:
2 | push:
3 | pull_request:
4 |
5 | name: 🧪 Test
6 |
7 | jobs:
8 | test-addon:
9 | runs-on: ubuntu-latest
10 | container: archlinux:base-devel
11 |
12 | steps:
13 | - name: 📥 Checkout
14 | uses: actions/checkout@v4
15 |
16 | - name: 👷 Build Dependencies
17 | run: "pacman --noconfirm -Syu base-devel cmake gcc git make pipewire pipewire-pulse"
18 |
19 | - name: 🍃 Install Node
20 | uses: actions/setup-node@v4
21 | with:
22 | node-version: 16
23 |
24 | - name: 🍃 Install pnpm
25 | uses: pnpm/action-setup@v2
26 | with:
27 | version: 8
28 | run_install: false
29 |
30 | - name: 🔨 Build
31 | run: "pnpm install"
32 |
33 | - name: 🧪 Test
34 | run: "pnpm run test"
35 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | prebuilds
3 | build
4 |
5 | .vscode
6 | .cache
7 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | build
3 |
4 | docker
5 | server
6 | tests
7 |
8 | .gitignore
9 | .github
10 |
11 | .clang-*
12 | .eslint*
13 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.21)
2 | project(venmic LANGUAGES CXX VERSION 6.1.0)
3 |
4 | # --------------------------------------------------------------------------------------------------------
5 | # Library options
6 | # --------------------------------------------------------------------------------------------------------
7 |
8 | option(venmic_addon "Build as addon" OFF)
9 | option(venmic_server "Build as rest server" ON)
10 | option(venmic_prefer_remote "Prefer remote packages over local packages" ON)
11 |
12 | # --------------------------------------------------------------------------------------------------------
13 | # Addon and Rest-Server are mutually exclusive
14 | # --------------------------------------------------------------------------------------------------------
15 |
16 | if (venmic_addon)
17 | set(venmic_server OFF)
18 | endif()
19 |
20 | if (venmic_server)
21 | set(venmic_addon OFF)
22 | endif()
23 |
24 | # --------------------------------------------------------------------------------------------------------
25 | # Sync `CPM_DOWNLOAD_ALL` with `venmic_prefer_remote`
26 | # --------------------------------------------------------------------------------------------------------
27 |
28 | if (venmic_prefer_remote)
29 | message(STATUS "[venmic] Avoiding local packages as 'venmic_prefer_remote' is ON")
30 | endif()
31 |
32 | set(CPM_DOWNLOAD_ALL ${venmic_prefer_remote})
33 |
34 | # --------------------------------------------------------------------------------------------------------
35 | # CMake options
36 | # --------------------------------------------------------------------------------------------------------
37 |
38 | set(CMAKE_POSITION_INDEPENDENT_CODE ON)
39 |
40 | # --------------------------------------------------------------------------------------------------------
41 | # Create library
42 | # --------------------------------------------------------------------------------------------------------
43 |
44 | add_library(${PROJECT_NAME})
45 | add_library(vencord::venmic ALIAS ${PROJECT_NAME})
46 |
47 | target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20)
48 | set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 20 CXX_EXTENSIONS OFF CXX_STANDARD_REQUIRED ON)
49 |
50 | if (PROJECT_IS_TOP_LEVEL)
51 | target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic -Werror -pedantic -pedantic-errors -Wfatal-errors)
52 | endif()
53 |
54 | if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
55 | target_compile_options(${PROJECT_NAME} PUBLIC -Wno-attributes=vc::)
56 | else()
57 | target_compile_options(${PROJECT_NAME} PUBLIC -Wno-unknown-attributes)
58 | endif()
59 |
60 | target_compile_options(${PROJECT_NAME} PRIVATE -Wno-missing-field-initializers -Wno-cast-function-type)
61 |
62 | # --------------------------------------------------------------------------------------------------------
63 | # Add source files
64 | # --------------------------------------------------------------------------------------------------------
65 |
66 | file(GLOB src "src/*.cpp")
67 | target_sources(${PROJECT_NAME} PRIVATE ${src})
68 |
69 | # --------------------------------------------------------------------------------------------------------
70 | # Include "include" folder
71 | # --------------------------------------------------------------------------------------------------------
72 |
73 | target_include_directories(${PROJECT_NAME} PUBLIC "include")
74 | target_include_directories(${PROJECT_NAME} PRIVATE "include/vencord" "private")
75 |
76 | # --------------------------------------------------------------------------------------------------------
77 | # Setup compile definitions
78 | # --------------------------------------------------------------------------------------------------------
79 |
80 | target_compile_definitions(${PROJECT_NAME} PUBLIC VENMIC_VERSION="${PROJECT_VERSION}")
81 |
82 | # --------------------------------------------------------------------------------------------------------
83 | # Setup Dependencies
84 | # --------------------------------------------------------------------------------------------------------
85 |
86 | include("cmake/cpm.cmake")
87 |
88 | CPMFindPackage(
89 | NAME rohrkabel
90 | VERSION 7.0
91 | GIT_REPOSITORY "https://github.com/Curve/rohrkabel"
92 | )
93 |
94 | CPMFindPackage(
95 | NAME tl-expected
96 | VERSION 1.1.0
97 | GIT_REPOSITORY "https://github.com/TartanLlama/expected"
98 | )
99 |
100 | CPMFindPackage(
101 | NAME channel
102 | VERSION 2.3
103 | GIT_REPOSITORY "https://github.com/Curve/channel"
104 | )
105 |
106 | CPMFindPackage(
107 | NAME range-v3
108 | GIT_TAG 0.12.0
109 | GIT_REPOSITORY "https://github.com/ericniebler/range-v3"
110 | )
111 |
112 | CPMFindPackage(
113 | NAME glaze
114 | VERSION 2.6.8
115 | GIT_REPOSITORY "https://github.com/stephenberry/glaze"
116 | )
117 |
118 | CPMFindPackage(
119 | NAME spdlog
120 | VERSION 1.14.1
121 | GIT_REPOSITORY "https://github.com/gabime/spdlog"
122 | )
123 |
124 | target_link_libraries(${PROJECT_NAME} PUBLIC cr::rohrkabel tl::expected cr::channel glaze::glaze range-v3::meta spdlog::spdlog)
125 |
126 | # --------------------------------------------------------------------------------------------------------
127 | # Custom Find-Package configurations
128 | # --------------------------------------------------------------------------------------------------------
129 |
130 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
131 |
132 | # --------------------------------------------------------------------------------------------------------
133 | # Link PulseAudio
134 | # --------------------------------------------------------------------------------------------------------
135 |
136 | find_package(PulseAudio)
137 | target_link_libraries(${PROJECT_NAME} PUBLIC PulseAudio::PulseAudio)
138 |
139 | # --------------------------------------------------------------------------------------------------------
140 | # Setup Rest Server
141 | # --------------------------------------------------------------------------------------------------------
142 |
143 | if (venmic_server)
144 | add_subdirectory(server)
145 | endif()
146 |
147 | # --------------------------------------------------------------------------------------------------------
148 | # Setup Node Addon
149 | # --------------------------------------------------------------------------------------------------------
150 |
151 | if (venmic_addon AND NOT CMAKE_JS_VERSION)
152 | message(FATAL_ERROR "[venmic] Please build the addon using CMake.js")
153 | endif()
154 |
155 | if (venmic_addon)
156 | add_subdirectory(addon)
157 | endif()
158 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Mozilla Public License Version 2.0
2 | ==================================
3 |
4 | 1. Definitions
5 | --------------
6 |
7 | 1.1. "Contributor"
8 | means each individual or legal entity that creates, contributes to
9 | the creation of, or owns Covered Software.
10 |
11 | 1.2. "Contributor Version"
12 | means the combination of the Contributions of others (if any) used
13 | by a Contributor and that particular Contributor's Contribution.
14 |
15 | 1.3. "Contribution"
16 | means Covered Software of a particular Contributor.
17 |
18 | 1.4. "Covered Software"
19 | means Source Code Form to which the initial Contributor has attached
20 | the notice in Exhibit A, the Executable Form of such Source Code
21 | Form, and Modifications of such Source Code Form, in each case
22 | including portions thereof.
23 |
24 | 1.5. "Incompatible With Secondary Licenses"
25 | means
26 |
27 | (a) that the initial Contributor has attached the notice described
28 | in Exhibit B to the Covered Software; or
29 |
30 | (b) that the Covered Software was made available under the terms of
31 | version 1.1 or earlier of the License, but not also under the
32 | terms of a Secondary License.
33 |
34 | 1.6. "Executable Form"
35 | means any form of the work other than Source Code Form.
36 |
37 | 1.7. "Larger Work"
38 | means a work that combines Covered Software with other material, in
39 | a separate file or files, that is not Covered Software.
40 |
41 | 1.8. "License"
42 | means this document.
43 |
44 | 1.9. "Licensable"
45 | means having the right to grant, to the maximum extent possible,
46 | whether at the time of the initial grant or subsequently, any and
47 | all of the rights conveyed by this License.
48 |
49 | 1.10. "Modifications"
50 | means any of the following:
51 |
52 | (a) any file in Source Code Form that results from an addition to,
53 | deletion from, or modification of the contents of Covered
54 | Software; or
55 |
56 | (b) any new file in Source Code Form that contains any Covered
57 | Software.
58 |
59 | 1.11. "Patent Claims" of a Contributor
60 | means any patent claim(s), including without limitation, method,
61 | process, and apparatus claims, in any patent Licensable by such
62 | Contributor that would be infringed, but for the grant of the
63 | License, by the making, using, selling, offering for sale, having
64 | made, import, or transfer of either its Contributions or its
65 | Contributor Version.
66 |
67 | 1.12. "Secondary License"
68 | means either the GNU General Public License, Version 2.0, the GNU
69 | Lesser General Public License, Version 2.1, the GNU Affero General
70 | Public License, Version 3.0, or any later versions of those
71 | licenses.
72 |
73 | 1.13. "Source Code Form"
74 | means the form of the work preferred for making modifications.
75 |
76 | 1.14. "You" (or "Your")
77 | means an individual or a legal entity exercising rights under this
78 | License. For legal entities, "You" includes any entity that
79 | controls, is controlled by, or is under common control with You. For
80 | purposes of this definition, "control" means (a) the power, direct
81 | or indirect, to cause the direction or management of such entity,
82 | whether by contract or otherwise, or (b) ownership of more than
83 | fifty percent (50%) of the outstanding shares or beneficial
84 | ownership of such entity.
85 |
86 | 2. License Grants and Conditions
87 | --------------------------------
88 |
89 | 2.1. Grants
90 |
91 | Each Contributor hereby grants You a world-wide, royalty-free,
92 | non-exclusive license:
93 |
94 | (a) under intellectual property rights (other than patent or trademark)
95 | Licensable by such Contributor to use, reproduce, make available,
96 | modify, display, perform, distribute, and otherwise exploit its
97 | Contributions, either on an unmodified basis, with Modifications, or
98 | as part of a Larger Work; and
99 |
100 | (b) under Patent Claims of such Contributor to make, use, sell, offer
101 | for sale, have made, import, and otherwise transfer either its
102 | Contributions or its Contributor Version.
103 |
104 | 2.2. Effective Date
105 |
106 | The licenses granted in Section 2.1 with respect to any Contribution
107 | become effective for each Contribution on the date the Contributor first
108 | distributes such Contribution.
109 |
110 | 2.3. Limitations on Grant Scope
111 |
112 | The licenses granted in this Section 2 are the only rights granted under
113 | this License. No additional rights or licenses will be implied from the
114 | distribution or licensing of Covered Software under this License.
115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a
116 | Contributor:
117 |
118 | (a) for any code that a Contributor has removed from Covered Software;
119 | or
120 |
121 | (b) for infringements caused by: (i) Your and any other third party's
122 | modifications of Covered Software, or (ii) the combination of its
123 | Contributions with other software (except as part of its Contributor
124 | Version); or
125 |
126 | (c) under Patent Claims infringed by Covered Software in the absence of
127 | its Contributions.
128 |
129 | This License does not grant any rights in the trademarks, service marks,
130 | or logos of any Contributor (except as may be necessary to comply with
131 | the notice requirements in Section 3.4).
132 |
133 | 2.4. Subsequent Licenses
134 |
135 | No Contributor makes additional grants as a result of Your choice to
136 | distribute the Covered Software under a subsequent version of this
137 | License (see Section 10.2) or under the terms of a Secondary License (if
138 | permitted under the terms of Section 3.3).
139 |
140 | 2.5. Representation
141 |
142 | Each Contributor represents that the Contributor believes its
143 | Contributions are its original creation(s) or it has sufficient rights
144 | to grant the rights to its Contributions conveyed by this License.
145 |
146 | 2.6. Fair Use
147 |
148 | This License is not intended to limit any rights You have under
149 | applicable copyright doctrines of fair use, fair dealing, or other
150 | equivalents.
151 |
152 | 2.7. Conditions
153 |
154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
155 | in Section 2.1.
156 |
157 | 3. Responsibilities
158 | -------------------
159 |
160 | 3.1. Distribution of Source Form
161 |
162 | All distribution of Covered Software in Source Code Form, including any
163 | Modifications that You create or to which You contribute, must be under
164 | the terms of this License. You must inform recipients that the Source
165 | Code Form of the Covered Software is governed by the terms of this
166 | License, and how they can obtain a copy of this License. You may not
167 | attempt to alter or restrict the recipients' rights in the Source Code
168 | Form.
169 |
170 | 3.2. Distribution of Executable Form
171 |
172 | If You distribute Covered Software in Executable Form then:
173 |
174 | (a) such Covered Software must also be made available in Source Code
175 | Form, as described in Section 3.1, and You must inform recipients of
176 | the Executable Form how they can obtain a copy of such Source Code
177 | Form by reasonable means in a timely manner, at a charge no more
178 | than the cost of distribution to the recipient; and
179 |
180 | (b) You may distribute such Executable Form under the terms of this
181 | License, or sublicense it under different terms, provided that the
182 | license for the Executable Form does not attempt to limit or alter
183 | the recipients' rights in the Source Code Form under this License.
184 |
185 | 3.3. Distribution of a Larger Work
186 |
187 | You may create and distribute a Larger Work under terms of Your choice,
188 | provided that You also comply with the requirements of this License for
189 | the Covered Software. If the Larger Work is a combination of Covered
190 | Software with a work governed by one or more Secondary Licenses, and the
191 | Covered Software is not Incompatible With Secondary Licenses, this
192 | License permits You to additionally distribute such Covered Software
193 | under the terms of such Secondary License(s), so that the recipient of
194 | the Larger Work may, at their option, further distribute the Covered
195 | Software under the terms of either this License or such Secondary
196 | License(s).
197 |
198 | 3.4. Notices
199 |
200 | You may not remove or alter the substance of any license notices
201 | (including copyright notices, patent notices, disclaimers of warranty,
202 | or limitations of liability) contained within the Source Code Form of
203 | the Covered Software, except that You may alter any license notices to
204 | the extent required to remedy known factual inaccuracies.
205 |
206 | 3.5. Application of Additional Terms
207 |
208 | You may choose to offer, and to charge a fee for, warranty, support,
209 | indemnity or liability obligations to one or more recipients of Covered
210 | Software. However, You may do so only on Your own behalf, and not on
211 | behalf of any Contributor. You must make it absolutely clear that any
212 | such warranty, support, indemnity, or liability obligation is offered by
213 | You alone, and You hereby agree to indemnify every Contributor for any
214 | liability incurred by such Contributor as a result of warranty, support,
215 | indemnity or liability terms You offer. You may include additional
216 | disclaimers of warranty and limitations of liability specific to any
217 | jurisdiction.
218 |
219 | 4. Inability to Comply Due to Statute or Regulation
220 | ---------------------------------------------------
221 |
222 | If it is impossible for You to comply with any of the terms of this
223 | License with respect to some or all of the Covered Software due to
224 | statute, judicial order, or regulation then You must: (a) comply with
225 | the terms of this License to the maximum extent possible; and (b)
226 | describe the limitations and the code they affect. Such description must
227 | be placed in a text file included with all distributions of the Covered
228 | Software under this License. Except to the extent prohibited by statute
229 | or regulation, such description must be sufficiently detailed for a
230 | recipient of ordinary skill to be able to understand it.
231 |
232 | 5. Termination
233 | --------------
234 |
235 | 5.1. The rights granted under this License will terminate automatically
236 | if You fail to comply with any of its terms. However, if You become
237 | compliant, then the rights granted under this License from a particular
238 | Contributor are reinstated (a) provisionally, unless and until such
239 | Contributor explicitly and finally terminates Your grants, and (b) on an
240 | ongoing basis, if such Contributor fails to notify You of the
241 | non-compliance by some reasonable means prior to 60 days after You have
242 | come back into compliance. Moreover, Your grants from a particular
243 | Contributor are reinstated on an ongoing basis if such Contributor
244 | notifies You of the non-compliance by some reasonable means, this is the
245 | first time You have received notice of non-compliance with this License
246 | from such Contributor, and You become compliant prior to 30 days after
247 | Your receipt of the notice.
248 |
249 | 5.2. If You initiate litigation against any entity by asserting a patent
250 | infringement claim (excluding declaratory judgment actions,
251 | counter-claims, and cross-claims) alleging that a Contributor Version
252 | directly or indirectly infringes any patent, then the rights granted to
253 | You by any and all Contributors for the Covered Software under Section
254 | 2.1 of this License shall terminate.
255 |
256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all
257 | end user license agreements (excluding distributors and resellers) which
258 | have been validly granted by You or Your distributors under this License
259 | prior to termination shall survive termination.
260 |
261 | ************************************************************************
262 | * *
263 | * 6. Disclaimer of Warranty *
264 | * ------------------------- *
265 | * *
266 | * Covered Software is provided under this License on an "as is" *
267 | * basis, without warranty of any kind, either expressed, implied, or *
268 | * statutory, including, without limitation, warranties that the *
269 | * Covered Software is free of defects, merchantable, fit for a *
270 | * particular purpose or non-infringing. The entire risk as to the *
271 | * quality and performance of the Covered Software is with You. *
272 | * Should any Covered Software prove defective in any respect, You *
273 | * (not any Contributor) assume the cost of any necessary servicing, *
274 | * repair, or correction. This disclaimer of warranty constitutes an *
275 | * essential part of this License. No use of any Covered Software is *
276 | * authorized under this License except under this disclaimer. *
277 | * *
278 | ************************************************************************
279 |
280 | ************************************************************************
281 | * *
282 | * 7. Limitation of Liability *
283 | * -------------------------- *
284 | * *
285 | * Under no circumstances and under no legal theory, whether tort *
286 | * (including negligence), contract, or otherwise, shall any *
287 | * Contributor, or anyone who distributes Covered Software as *
288 | * permitted above, be liable to You for any direct, indirect, *
289 | * special, incidental, or consequential damages of any character *
290 | * including, without limitation, damages for lost profits, loss of *
291 | * goodwill, work stoppage, computer failure or malfunction, or any *
292 | * and all other commercial damages or losses, even if such party *
293 | * shall have been informed of the possibility of such damages. This *
294 | * limitation of liability shall not apply to liability for death or *
295 | * personal injury resulting from such party's negligence to the *
296 | * extent applicable law prohibits such limitation. Some *
297 | * jurisdictions do not allow the exclusion or limitation of *
298 | * incidental or consequential damages, so this exclusion and *
299 | * limitation may not apply to You. *
300 | * *
301 | ************************************************************************
302 |
303 | 8. Litigation
304 | -------------
305 |
306 | Any litigation relating to this License may be brought only in the
307 | courts of a jurisdiction where the defendant maintains its principal
308 | place of business and such litigation shall be governed by laws of that
309 | jurisdiction, without reference to its conflict-of-law provisions.
310 | Nothing in this Section shall prevent a party's ability to bring
311 | cross-claims or counter-claims.
312 |
313 | 9. Miscellaneous
314 | ----------------
315 |
316 | This License represents the complete agreement concerning the subject
317 | matter hereof. If any provision of this License is held to be
318 | unenforceable, such provision shall be reformed only to the extent
319 | necessary to make it enforceable. Any law or regulation which provides
320 | that the language of a contract shall be construed against the drafter
321 | shall not be used to construe this License against a Contributor.
322 |
323 | 10. Versions of the License
324 | ---------------------------
325 |
326 | 10.1. New Versions
327 |
328 | Mozilla Foundation is the license steward. Except as provided in Section
329 | 10.3, no one other than the license steward has the right to modify or
330 | publish new versions of this License. Each version will be given a
331 | distinguishing version number.
332 |
333 | 10.2. Effect of New Versions
334 |
335 | You may distribute the Covered Software under the terms of the version
336 | of the License under which You originally received the Covered Software,
337 | or under the terms of any subsequent version published by the license
338 | steward.
339 |
340 | 10.3. Modified Versions
341 |
342 | If you create software not governed by this License, and you want to
343 | create a new license for such software, you may create and use a
344 | modified version of this License if you rename the license and remove
345 | any references to the name of the license steward (except to note that
346 | such modified license differs from this License).
347 |
348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary
349 | Licenses
350 |
351 | If You choose to distribute Source Code Form that is Incompatible With
352 | Secondary Licenses under the terms of this version of the License, the
353 | notice described in Exhibit B of this License must be attached.
354 |
355 | Exhibit A - Source Code Form License Notice
356 | -------------------------------------------
357 |
358 | This Source Code Form is subject to the terms of the Mozilla Public
359 | License, v. 2.0. If a copy of the MPL was not distributed with this
360 | file, You can obtain one at http://mozilla.org/MPL/2.0/.
361 |
362 | If it is not possible or desirable to put the notice in a particular
363 | file, then You may include the notice in a location (such as a LICENSE
364 | file in a relevant directory) where a recipient would be likely to look
365 | for such a notice.
366 |
367 | You may add additional accurate notices of copyright ownership.
368 |
369 | Exhibit B - "Incompatible With Secondary Licenses" Notice
370 | ---------------------------------------------------------
371 |
372 | This Source Code Form is "Incompatible With Secondary Licenses", as
373 | defined by the Mozilla Public License, v. 2.0.
374 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |
5 |
6 |
7 | venmic - screenshare support for pipewire
8 |
9 |
10 |
11 | > [!WARNING]
12 | > This project is not intended for standalone usage. You need a modified discord client that makes use of this.
13 |
14 | ## 📖 Usage
15 |
16 | _venmic_ can be used as node-module or as a local rest-server.
17 |
18 | The node-module is mainly intended for internal usage by [Vesktop](https://github.com/Vencord/Vesktop).
19 | For a usage example, see the following Vesktop source files:
20 | - [src/main/venmic.ts](https://github.com/Vencord/Vesktop/blob/main/src/main/venmic.ts)
21 | - [src/renderer/patches/screenShareFixes.ts](https://github.com/Vencord/Vesktop/blob/main/src/renderer/patches/screenShareFixes.ts)
22 | - src/renderer/components/ScreenSharePicker.tsx: [1](https://github.com/Vencord/Vesktop/blob/4abae9c7082081dcae667916d9608e23adf688a9/src/renderer/components/ScreenSharePicker.tsx#L109-L115), [2](https://github.com/Vencord/Vesktop/blob/4abae9c7082081dcae667916d9608e23adf688a9/src/renderer/components/ScreenSharePicker.tsx#L253-L256), [3](https://github.com/Vencord/Vesktop/blob/4abae9c7082081dcae667916d9608e23adf688a9/src/renderer/components/ScreenSharePicker.tsx#L94)
23 |
24 | The Rest-Server exposes three simple endpoints
25 | * (POST) `/list`
26 | > List all available applications to share.
27 | > You can optionally define a JSON-Body containing all the props the listed nodes should have (i.e. `["node.name"]`).
28 |
29 | * (POST) `/link`
30 |
31 | Expects a JSON-Body in the following form:
32 |
33 | {
34 | "include":
35 | [
36 | { "node.name": "Firefox" }
37 | ],
38 | "exclude":
39 | [
40 | { "node.name": "Chrome" }
41 | ]
42 | "ignore_devices": true,
43 | "workaround": [{ "node.name": "Chrome" }]
44 | }
45 |
46 |
47 | Depending on wether or not `include` or `exclude` are defined the behavior will change:
48 |
49 | * only `include`
50 | * Links nodes that match given props
51 | * only `exclude`
52 | * Links nodes that do not match given props
53 | * both `include` and `exclude`
54 | * Links all applications that match props in `include` and not those given in `exclude`
55 |
56 | The setting `ignore_devices` is optional and will default to `true`.
57 | When enabled it will prevent hardware-devices like speakers and microphones from being linked to the virtual microphone.
58 |
59 | The setting `only_speakers` is optional and will default to `true`.
60 | When enabled it will prevent linking against nodes that don't play to a speaker.
61 |
62 | The setting `only_default_speakers` is optional and will default to `true`.
63 | When enabled it will prevent linking against nodes that don't play to the default speaker.
64 |
65 | The setting `workaround` is also optional and will default to an empty array.
66 | When set, venmic will redirect the first node that matches all of the specified properties to itself.
67 |
68 |
69 | * (GET) `/unlink`
70 | > Unlinks the currently linked application
71 |
72 | ## 🏗️ Compiling
73 |
74 | * Rest-Server
75 | ```bash
76 | git clone https://github.com/Vencord/linux-virtmic && cd linux-virtmic
77 | cmake -B build && cmake --build build
78 | ```
79 |
80 | * Node-Addon
81 | ```bash
82 | git clone https://github.com/Vencord/linux-virtmic && cd linux-virtmic
83 | pnpm install
84 | ```
85 |
86 | ## 🐛 Debugging
87 |
88 | When reporting an issue please make sure to set the environment variable `VENMIC_ENABLE_LOG`.
89 |
90 | If said variable is set venmic will output a lot of useful information to stdout and a log-file which can be found in `~/.local/state/venmic/venmic.log`.
91 |
92 | It is highly recommended to include this log file in your issue report otherwise we may not be able to help you!
93 |
94 | ## 🤝 Acknowledgements
95 |
96 | * [Curve/rohrkabel](https://github.com/Curve/rohrkabel/)
97 | * [cmake-js](https://github.com/cmake-js/cmake-js)
98 | * [@wwmm](https://github.com/wwmm) for improving compatibility with [EasyEffects](https://github.com/wwmm/easyeffects)
99 |
100 | Kudos to all the developers involved, keep up the great work!
101 |
--------------------------------------------------------------------------------
/addon/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.16)
2 | project(venmic-addon LANGUAGES CXX VERSION 2.0)
3 |
4 | # --------------------------------------------------------------------------------------------------------
5 | # Create library
6 | # --------------------------------------------------------------------------------------------------------
7 |
8 | add_library(${PROJECT_NAME} SHARED)
9 | add_library(vencord::venmic-addon ALIAS ${PROJECT_NAME})
10 |
11 | target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20)
12 | set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "" SUFFIX ".node")
13 | set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 20 CXX_EXTENSIONS OFF CXX_STANDARD_REQUIRED ON)
14 |
15 | if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
16 | target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic -Werror -pedantic -pedantic-errors -Wfatal-errors)
17 | endif()
18 |
19 | target_compile_options(${PROJECT_NAME} PRIVATE -Wno-missing-field-initializers -Wno-cast-function-type)
20 |
21 | # --------------------------------------------------------------------------------------------------------
22 | # Add source files
23 | # --------------------------------------------------------------------------------------------------------
24 |
25 | file(GLOB src "*.cpp")
26 | target_sources(${PROJECT_NAME} PRIVATE ${src})
27 |
28 | # --------------------------------------------------------------------------------------------------------
29 | # Setup Dependencies
30 | # --------------------------------------------------------------------------------------------------------
31 |
32 | include("../cmake/cpm.cmake")
33 |
34 | CPMFindPackage(
35 | NAME range-v3
36 | GIT_TAG 0.12.0
37 | GIT_REPOSITORY "https://github.com/ericniebler/range-v3"
38 | )
39 |
40 | target_link_libraries(${PROJECT_NAME} PUBLIC vencord::venmic range-v3::meta)
41 |
42 | # --------------------------------------------------------------------------------------------------------
43 | # CMake.js related
44 | # --------------------------------------------------------------------------------------------------------
45 |
46 | add_definitions(-DNAPI_VERSION=7)
47 |
48 | target_link_libraries(${PROJECT_NAME} PUBLIC ${CMAKE_JS_LIB})
49 | target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_JS_INC})
50 |
51 | if(MSVC AND CMAKE_JS_NODELIB_DEF AND CMAKE_JS_NODELIB_TARGET)
52 | execute_process(COMMAND ${CMAKE_AR} /def:${CMAKE_JS_NODELIB_DEF} /out:${CMAKE_JS_NODELIB_TARGET} ${CMAKE_STATIC_LINKER_FLAGS})
53 | endif()
54 |
--------------------------------------------------------------------------------
/addon/addon.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include
5 |
6 | #include
7 | #include
8 | #include
9 |
10 | template
11 | std::optional convert(Napi::Value) = delete;
12 |
13 | template <>
14 | std::optional convert(Napi::Value value)
15 | {
16 | if (!value.IsString())
17 | {
18 | return std::nullopt;
19 | }
20 |
21 | return value.ToString();
22 | }
23 |
24 | template <>
25 | std::optional convert(Napi::Value value)
26 | {
27 | if (!value.IsBoolean())
28 | {
29 | return std::nullopt;
30 | }
31 |
32 | return value.ToBoolean();
33 | }
34 |
35 | template <>
36 | std::optional convert(Napi::Value value)
37 | {
38 | if (!value.IsObject())
39 | {
40 | return std::nullopt;
41 | }
42 |
43 | auto object = value.As();
44 | auto rtn = vencord::node{};
45 |
46 | for (const auto &[obj_key, obj_value] : object)
47 | {
48 | auto key = convert(obj_key);
49 | auto value = convert(obj_value);
50 |
51 | if (!key || !value)
52 | {
53 | return std::nullopt;
54 | }
55 |
56 | rtn.emplace(key.value(), value.value());
57 | }
58 |
59 | return rtn;
60 | }
61 |
62 | template
63 | std::optional> to_array(Napi::Value value)
64 | {
65 | if (!value.IsArray())
66 | {
67 | return std::nullopt;
68 | }
69 |
70 | auto array = value.As();
71 |
72 | std::vector rtn;
73 | rtn.reserve(array.Length());
74 |
75 | for (auto i = 0u; array.Length() > i; i++)
76 | {
77 | auto converted = convert(array.Get(i));
78 |
79 | if (!converted)
80 | {
81 | return std::nullopt;
82 | }
83 |
84 | rtn.emplace_back(converted.value());
85 | }
86 |
87 | return rtn;
88 | }
89 |
90 | struct patchbay : public Napi::ObjectWrap
91 | {
92 | patchbay(const Napi::CallbackInfo &info) : Napi::ObjectWrap::ObjectWrap(info)
93 | {
94 | try
95 | {
96 | static_cast(vencord::patchbay::get());
97 | }
98 | catch (std::exception &e)
99 | {
100 | Napi::Error::New(info.Env(), e.what()).ThrowAsJavaScriptException();
101 | }
102 | }
103 |
104 | public:
105 | Napi::Value list(const Napi::CallbackInfo &info) // NOLINT(*-static)
106 | {
107 | auto env = info.Env();
108 |
109 | std::vector props{};
110 |
111 | if (info.Length() == 1 && !info[0].IsUndefined())
112 | {
113 | auto array = to_array(info[0]);
114 |
115 | if (!array)
116 | {
117 | Napi::Error::New(env, "[venmic] expected list of strings").ThrowAsJavaScriptException();
118 | return {};
119 | }
120 |
121 | props = std::move(array.value());
122 | }
123 |
124 | auto list = vencord::patchbay::get().list(props);
125 | auto rtn = Napi::Array::New(env, list.size());
126 |
127 | auto convert = [&](const auto &item)
128 | {
129 | auto rtn = Napi::Object::New(env);
130 |
131 | for (const auto &[key, value] : item)
132 | {
133 | rtn.Set(key, Napi::String::New(env, value));
134 | }
135 |
136 | return rtn;
137 | };
138 | auto add = [&](const auto &item)
139 | {
140 | rtn.Set(item.first, item.second);
141 | };
142 |
143 | ranges::for_each(list //
144 | | ranges::views::transform(convert) //
145 | | ranges::views::enumerate,
146 | add);
147 |
148 | return rtn;
149 | }
150 |
151 | Napi::Value link(const Napi::CallbackInfo &info) // NOLINT(*-static)
152 | {
153 | auto env = info.Env();
154 |
155 | if (info.Length() != 1 || !info[0].IsObject())
156 | {
157 | Napi::Error::New(env, "[venmic] expected link object").ThrowAsJavaScriptException();
158 | return Napi::Boolean::New(env, false);
159 | }
160 |
161 | auto data = info[0].ToObject();
162 |
163 | if (!data.Has("include") && !data.Has("exclude"))
164 | {
165 | Napi::Error::New(env, "[venmic] expected at least one of keys 'include' or 'exclude'")
166 | .ThrowAsJavaScriptException();
167 |
168 | return Napi::Boolean::New(env, false);
169 | }
170 |
171 | auto include = to_array(data.Get("include"));
172 | auto exclude = to_array(data.Get("exclude"));
173 | auto ignore_devices = convert(data.Get("ignore_devices"));
174 | auto only_speakers = convert(data.Get("only_speakers"));
175 | auto only_default_speakers = convert(data.Get("only_default_speakers"));
176 | auto workaround = to_array(data.Get("workaround"));
177 |
178 | if (!include && !exclude)
179 | {
180 | Napi::Error::New(env, "[venmic] expected either 'include' or 'exclude' or both to be present and to be "
181 | "arrays of key-value pairs")
182 | .ThrowAsJavaScriptException();
183 |
184 | return Napi::Boolean::New(env, false);
185 | }
186 |
187 | vencord::patchbay::get().link({
188 | .include = include.value_or(std::vector{}),
189 | .exclude = exclude.value_or(std::vector{}),
190 | .ignore_devices = ignore_devices.value_or(true),
191 | .only_speakers = only_speakers.value_or(true),
192 | .only_default_speakers = only_default_speakers.value_or(true),
193 | .workaround = workaround.value_or(std::vector{}),
194 | });
195 |
196 | return Napi::Boolean::New(env, true);
197 | }
198 |
199 | Napi::Value unlink([[maybe_unused]] const Napi::CallbackInfo &) // NOLINT(*-static)
200 | {
201 | vencord::patchbay::get().unlink();
202 | return {};
203 | }
204 |
205 | static Napi::Value has_pipewire(const Napi::CallbackInfo &info)
206 | {
207 | return Napi::Boolean::New(info.Env(), vencord::patchbay::has_pipewire());
208 | }
209 |
210 | public:
211 | static Napi::Object Init(Napi::Env env, Napi::Object exports)
212 | {
213 | static constexpr auto attributes = static_cast(napi_writable | napi_configurable);
214 |
215 | auto func = DefineClass(env, "PatchBay",
216 | {
217 | InstanceMethod<&patchbay::link>("link", attributes),
218 | InstanceMethod<&patchbay::list>("list", attributes),
219 | InstanceMethod<&patchbay::unlink>("unlink", attributes),
220 | StaticMethod<&patchbay::has_pipewire>("hasPipeWire", attributes),
221 | });
222 |
223 | auto *constructor = new Napi::FunctionReference{Napi::Persistent(func)};
224 |
225 | exports.Set("PatchBay", func);
226 |
227 | env.SetInstanceData(constructor);
228 |
229 | return exports;
230 | }
231 |
232 | static Napi::Object CreateNewItem(const Napi::CallbackInfo &info)
233 | {
234 | auto env = info.Env();
235 | auto *constructor = env.GetInstanceData();
236 |
237 | return constructor->New({});
238 | }
239 | };
240 |
241 | Napi::Object init(Napi::Env env, Napi::Object exports)
242 | {
243 | patchbay::Init(env, exports);
244 | return exports;
245 | }
246 |
247 | // NOLINTNEXTLINE
248 | NODE_API_MODULE(venmic, init);
249 |
--------------------------------------------------------------------------------
/cmake/FindPulseAudio.cmake:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2008 Matthias Kretz
2 | # SPDX-FileCopyrightText: 2009 Marcus Hufgard
3 | #
4 | # SPDX-License-Identifier: BSD-3-Clause
5 |
6 | #[=======================================================================[.rst:
7 | FindPulseAudio
8 | --------------
9 |
10 | Try to locate the PulseAudio library.
11 | If found, this will define the following variables:
12 |
13 | ``PulseAudio_FOUND``
14 | True if the system has the PulseAudio library of at least
15 | the minimum version specified by either the version parameter
16 | to find_package() or the variable PulseAudio_MINIMUM_VERSION
17 | ``PulseAudio_INCLUDE_DIRS``
18 | The PulseAudio include directory
19 | ``PulseAudio_LIBRARIES``
20 | The PulseAudio libraries for linking
21 | ``PulseAudio_MAINLOOP_LIBRARY``
22 | The libraries needed to use PulseAudio Mainloop
23 | ``PulseAudio_VERSION``
24 | The version of PulseAudio that was found
25 | ``PulseAudio_INCLUDE_DIR``
26 | Deprecated, use ``PulseAudio_INCLUDE_DIRS``
27 | ``PulseAudio_LIBRARY``
28 | Deprecated, use ``PulseAudio_LIBRARIES``
29 |
30 | If ``PulseAudio_FOUND`` is TRUE, it will also define the following
31 | imported target:
32 |
33 | ``PulseAudio::PulseAudio``
34 | The PulseAudio library
35 |
36 | Since 5.41.0.
37 | #]=======================================================================]
38 |
39 | # Support PulseAudio_MINIMUM_VERSION for compatibility:
40 | if(NOT PulseAudio_FIND_VERSION)
41 | set(PulseAudio_FIND_VERSION "${PulseAudio_MINIMUM_VERSION}")
42 | endif()
43 |
44 | # the minimum version of PulseAudio we require
45 | if(NOT PulseAudio_FIND_VERSION)
46 | set(PulseAudio_FIND_VERSION "0.9.9")
47 | endif()
48 |
49 | find_package(PkgConfig QUIET)
50 | pkg_check_modules(PC_PulseAudio QUIET libpulse>=${PulseAudio_FIND_VERSION})
51 | pkg_check_modules(PC_PulseAudio_MAINLOOP QUIET libpulse-mainloop-glib)
52 |
53 | find_path(PulseAudio_INCLUDE_DIRS pulse/pulseaudio.h
54 | HINTS
55 | ${PC_PulseAudio_INCLUDEDIR}
56 | ${PC_PulseAudio_INCLUDE_DIRS}
57 | )
58 |
59 | find_library(PulseAudio_LIBRARIES NAMES pulse libpulse
60 | HINTS
61 | ${PC_PulseAudio_LIBDIR}
62 | ${PC_PulseAudio_LIBRARY_DIRS}
63 | )
64 |
65 | find_library(PulseAudio_MAINLOOP_LIBRARY NAMES pulse-mainloop pulse-mainloop-glib libpulse-mainloop-glib
66 | HINTS
67 | ${PC_PulseAudio_LIBDIR}
68 | ${PC_PulseAudio_LIBRARY_DIRS}
69 | )
70 |
71 | # Store the version number in the cache, so we don't have to search every time again:
72 | if (PulseAudio_INCLUDE_DIRS AND NOT PulseAudio_VERSION)
73 |
74 | # get PulseAudio's version from its version.h
75 | file(STRINGS "${PulseAudio_INCLUDE_DIRS}/pulse/version.h" pulse_version_h
76 | REGEX ".*pa_get_headers_version\\(\\).*")
77 | string(REGEX REPLACE ".*pa_get_headers_version\\(\\)\ \\(\"([0-9]+\\.[0-9]+\\.[0-9]+)[^\"]*\"\\).*" "\\1"
78 | _PulseAudio_VERSION "${pulse_version_h}")
79 |
80 | set(PulseAudio_VERSION "${_PulseAudio_VERSION}" CACHE STRING "Version number of PulseAudio" FORCE)
81 | endif()
82 |
83 | # Use the new extended syntax of find_package_handle_standard_args(), which also handles version checking:
84 | include(FindPackageHandleStandardArgs)
85 | find_package_handle_standard_args(PulseAudio REQUIRED_VARS PulseAudio_LIBRARIES PulseAudio_INCLUDE_DIRS
86 | VERSION_VAR PulseAudio_VERSION)
87 |
88 | # Deprecated synonyms
89 | set(PULSEAUDIO_INCLUDE_DIR "${PulseAudio_INCLUDE_DIRS}")
90 | set(PULSEAUDIO_LIBRARY "${PulseAudio_LIBRARIES}")
91 | set(PULSEAUDIO_MAINLOOP_LIBRARY "${PulseAudio_MAINLOOP_LIBRARY}")
92 | set(PULSEAUDIO_FOUND "${PulseAudio_FOUND}")
93 |
94 | if(PulseAudio_FOUND AND NOT TARGET PulseAudio::PulseAudio)
95 | add_library(PulseAudio::PulseAudio UNKNOWN IMPORTED)
96 | set_target_properties(PulseAudio::PulseAudio PROPERTIES
97 | IMPORTED_LOCATION "${PulseAudio_LIBRARIES}"
98 | INTERFACE_INCLUDE_DIRECTORIES "${PulseAudio_INCLUDE_DIRS}")
99 | endif()
100 |
101 | mark_as_advanced(PulseAudio_INCLUDE_DIRS PULSEAUDIO_INCLUDE_DIR
102 | PulseAudio_LIBRARIES PULSEAUDIO_LIBRARY
103 | PulseAudio_MAINLOOP_LIBRARY PULSEAUDIO_MAINLOOP_LIBRARY)
104 |
105 | include(FeatureSummary)
106 | set_package_properties(PulseAudio PROPERTIES
107 | URL "https://www.freedesktop.org/wiki/Software/PulseAudio"
108 | DESCRIPTION "Sound server, for sound stream routing and mixing")
109 |
--------------------------------------------------------------------------------
/cmake/cpm.cmake:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | #
3 | # SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors
4 |
5 | set(CPM_DOWNLOAD_VERSION 0.38.7)
6 | set(CPM_HASH_SUM "83e5eb71b2bbb8b1f2ad38f1950287a057624e385c238f6087f94cdfc44af9c5")
7 |
8 | if(CPM_SOURCE_CACHE)
9 | set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
10 | elseif(DEFINED ENV{CPM_SOURCE_CACHE})
11 | set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
12 | else()
13 | set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
14 | endif()
15 |
16 | # Expand relative path. This is important if the provided path contains a tilde (~)
17 | get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE)
18 |
19 | file(DOWNLOAD
20 | https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
21 | ${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM}
22 | )
23 |
24 | include(${CPM_DOWNLOAD_LOCATION})
25 |
--------------------------------------------------------------------------------
/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | # This Dockerfile describes the base image used for compiling the node addon on different CPU-Architectures
2 |
3 | FROM fedora:38
4 |
5 | # Build dependencies
6 |
7 | RUN dnf install -y make automake gcc gcc-c++ kernel-devel cmake git nodejs libstdc++-static ninja-build
8 | RUN dnf install -y pipewire-devel pipewire-libs pulseaudio-libs-devel pipewire-pulseaudio
9 |
10 | # PNPM
11 |
12 | RUN curl -fsSL https://get.pnpm.io/install.sh | sh -
13 |
14 | # Add build script
15 |
16 | ADD build.sh .
17 |
--------------------------------------------------------------------------------
/docker/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Ensure pnpm is loaded
4 | source /root/.bashrc
5 |
6 | # Let's get to work!
7 | cd /work
8 |
9 | # Export Threads for Make and Ninja
10 | export MAKEFLAGS=-j$(nproc)
11 | export PARALLEL_LEVEL=$(nproc)
12 |
13 | pnpm install --ignore-scripts && pnpm run install
14 |
--------------------------------------------------------------------------------
/include/vencord/logger.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 |
5 | namespace vencord
6 | {
7 | class logger
8 | {
9 | struct impl;
10 |
11 | private:
12 | std::unique_ptr m_impl;
13 |
14 | private:
15 | logger();
16 |
17 | public:
18 | spdlog::logger *operator->() const;
19 |
20 | public:
21 | [[nodiscard]] static logger &get();
22 | };
23 | } // namespace vencord
24 |
--------------------------------------------------------------------------------
/include/vencord/patchbay.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include