Improve Venmic Usability (#504)
This commit is contained in:
parent
8eaa5206b9
commit
2649598361
8 changed files with 127 additions and 59 deletions
|
@ -27,7 +27,7 @@
|
||||||
"arrpc": "github:OpenAsar/arrpc#98879cae0565e6fce34e4cb6f544bf42c6a7e7c8"
|
"arrpc": "github:OpenAsar/arrpc#98879cae0565e6fce34e4cb6f544bf42c6a7e7c8"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@vencord/venmic": "^3.4.1"
|
"@vencord/venmic": "^3.4.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@fal-works/esbuild-plugin-global-externals": "^2.1.2",
|
"@fal-works/esbuild-plugin-global-externals": "^2.1.2",
|
||||||
|
|
|
@ -11,8 +11,8 @@ dependencies:
|
||||||
|
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@vencord/venmic':
|
'@vencord/venmic':
|
||||||
specifier: ^3.4.1
|
specifier: ^3.4.2
|
||||||
version: 3.4.1
|
version: 3.4.2
|
||||||
|
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@fal-works/esbuild-plugin-global-externals':
|
'@fal-works/esbuild-plugin-global-externals':
|
||||||
|
@ -1000,8 +1000,8 @@ packages:
|
||||||
type-fest: 3.13.1
|
type-fest: 3.13.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@vencord/venmic@3.4.1:
|
/@vencord/venmic@3.4.2:
|
||||||
resolution: {integrity: sha512-PkMXx53nxiYBLWxiMRaBjBm8aTTJTcueKsMZ0v35TtIQ93yfuSzfCilDFLs3kYz1uQHArTaI9IGQykgmSfe/2w==}
|
resolution: {integrity: sha512-nwGjarof1wVvecGksGONfb+PduhY4gSuHTm39LktiQayHS69+yv4lepq4k1lxZzjOgFTy5VXfmJqxt+BpqoUUQ==}
|
||||||
engines: {node: '>=14.15'}
|
engines: {node: '>=14.15'}
|
||||||
os: [linux]
|
os: [linux]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
|
|
|
@ -4,17 +4,58 @@
|
||||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { PatchBay } from "@vencord/venmic";
|
import type { PatchBay as PatchBayType } from "@vencord/venmic";
|
||||||
import { app, ipcMain } from "electron";
|
import { app, ipcMain } from "electron";
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
import { IpcEvents } from "shared/IpcEvents";
|
import { IpcEvents } from "shared/IpcEvents";
|
||||||
import { STATIC_DIR } from "shared/paths";
|
import { STATIC_DIR } from "shared/paths";
|
||||||
|
|
||||||
type LinkData = Parameters<PatchBay["link"]>[0];
|
type LinkData = Parameters<PatchBayType["link"]>[0];
|
||||||
|
|
||||||
|
let PatchBay: typeof PatchBayType | undefined;
|
||||||
|
let patchBayInstance: PatchBayType | undefined;
|
||||||
|
|
||||||
|
let imported = false;
|
||||||
let initialized = false;
|
let initialized = false;
|
||||||
let patchBay: import("@vencord/venmic").PatchBay | undefined;
|
|
||||||
let isGlibcxxToOld = false;
|
let hasPipewirePulse = false;
|
||||||
|
let isGlibCxxOutdated = false;
|
||||||
|
|
||||||
|
function importVenmic() {
|
||||||
|
if (imported) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
imported = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
PatchBay = (require(join(STATIC_DIR, `dist/venmic-${process.arch}.node`)) as typeof import("@vencord/venmic"))
|
||||||
|
.PatchBay;
|
||||||
|
|
||||||
|
hasPipewirePulse = PatchBay.hasPipeWire();
|
||||||
|
} catch (e: any) {
|
||||||
|
console.error("Failed to import venmic", e);
|
||||||
|
isGlibCxxOutdated = (e?.stack || e?.message || "").toLowerCase().includes("glibc");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function obtainVenmic() {
|
||||||
|
if (!imported) {
|
||||||
|
importVenmic();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PatchBay && !initialized) {
|
||||||
|
initialized = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
patchBayInstance = new PatchBay();
|
||||||
|
} catch (e: any) {
|
||||||
|
console.error("Failed to instantiate venmic", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return patchBayInstance;
|
||||||
|
}
|
||||||
|
|
||||||
function getRendererAudioServicePid() {
|
function getRendererAudioServicePid() {
|
||||||
return (
|
return (
|
||||||
|
@ -25,33 +66,17 @@ function getRendererAudioServicePid() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function obtainVenmic() {
|
|
||||||
if (!initialized) {
|
|
||||||
initialized = true;
|
|
||||||
try {
|
|
||||||
const { PatchBay } = require(
|
|
||||||
join(STATIC_DIR, `dist/venmic-${process.arch}.node`)
|
|
||||||
) as typeof import("@vencord/venmic");
|
|
||||||
patchBay = new PatchBay();
|
|
||||||
} catch (e: any) {
|
|
||||||
console.error("Failed to initialise venmic. Make sure you're using pipewire", e);
|
|
||||||
isGlibcxxToOld = (e?.stack || e?.message || "").toLowerCase().includes("glibc");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return patchBay;
|
|
||||||
}
|
|
||||||
|
|
||||||
ipcMain.handle(IpcEvents.VIRT_MIC_LIST, () => {
|
ipcMain.handle(IpcEvents.VIRT_MIC_LIST, () => {
|
||||||
const audioPid = getRendererAudioServicePid();
|
const audioPid = getRendererAudioServicePid();
|
||||||
|
|
||||||
const list = obtainVenmic()
|
const list = obtainVenmic()
|
||||||
?.list()
|
?.list()
|
||||||
.filter(s => s["application.process.id"] !== audioPid)
|
.filter(s => s["application.process.id"] !== audioPid)
|
||||||
.map(s => s["application.name"]);
|
.map(s => s["application.name"]);
|
||||||
|
|
||||||
return list
|
const uniqueTargets = [...new Set(list)];
|
||||||
? { ok: true, targets: [...new Set(list)] } // Remove duplicates
|
|
||||||
: { ok: false, isGlibcxxToOld };
|
return list ? { ok: true, targets: uniqueTargets, hasPipewirePulse } : { ok: false, isGlibCxxOutdated };
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle(IpcEvents.VIRT_MIC_START, (_, targets: string[], workaround?: boolean) => {
|
ipcMain.handle(IpcEvents.VIRT_MIC_START, (_, targets: string[], workaround?: boolean) => {
|
||||||
|
|
|
@ -62,7 +62,9 @@ export const VesktopNative = {
|
||||||
/** only available on Linux. */
|
/** only available on Linux. */
|
||||||
virtmic: {
|
virtmic: {
|
||||||
list: () =>
|
list: () =>
|
||||||
invoke<{ ok: false; isGlibcxxToOld: boolean } | { ok: true; targets: string[] }>(IpcEvents.VIRT_MIC_LIST),
|
invoke<
|
||||||
|
{ ok: false; isGlibCxxOutdated: boolean } | { ok: true; targets: string[]; hasPipewirePulse: boolean }
|
||||||
|
>(IpcEvents.VIRT_MIC_LIST),
|
||||||
start: (targets: string[], workaround?: boolean) => invoke<void>(IpcEvents.VIRT_MIC_START, targets, workaround),
|
start: (targets: string[], workaround?: boolean) => invoke<void>(IpcEvents.VIRT_MIC_START, targets, workaround),
|
||||||
startSystem: (workaround?: boolean, onlyDefaultSpeakers?: boolean) =>
|
startSystem: (workaround?: boolean, onlyDefaultSpeakers?: boolean) =>
|
||||||
invoke<void>(IpcEvents.VIRT_MIC_START_SYSTEM, workaround, onlyDefaultSpeakers),
|
invoke<void>(IpcEvents.VIRT_MIC_START_SYSTEM, workaround, onlyDefaultSpeakers),
|
||||||
|
|
|
@ -331,9 +331,13 @@ function AudioSourcePickerLinux({
|
||||||
setOnlyDefaultSpeakers(b: boolean): void;
|
setOnlyDefaultSpeakers(b: boolean): void;
|
||||||
}) {
|
}) {
|
||||||
const [sources, _, loading] = useAwaiter(() => VesktopNative.virtmic.list(), {
|
const [sources, _, loading] = useAwaiter(() => VesktopNative.virtmic.list(), {
|
||||||
fallbackValue: { ok: true, targets: [] }
|
fallbackValue: { ok: true, targets: [], hasPipewirePulse: true }
|
||||||
});
|
});
|
||||||
|
|
||||||
const allSources = sources.ok ? ["None", "Entire System", ...sources.targets] : null;
|
const allSources = sources.ok ? ["None", "Entire System", ...sources.targets] : null;
|
||||||
|
const hasPipewirePulse = sources.ok ? sources.hasPipewirePulse : true;
|
||||||
|
|
||||||
|
const [ignorePulseWarning, setIgnorePulseWarning] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -345,32 +349,38 @@ function AudioSourcePickerLinux({
|
||||||
<Forms.FormTitle>Audio Source</Forms.FormTitle>
|
<Forms.FormTitle>Audio Source</Forms.FormTitle>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!sources.ok &&
|
{!sources.ok && sources.isGlibCxxOutdated && (
|
||||||
(sources.isGlibcxxToOld ? (
|
|
||||||
<Forms.FormText>
|
<Forms.FormText>
|
||||||
Failed to retrieve Audio Sources because your C++ library is too old to run venmic. If you
|
Failed to retrieve Audio Sources because your C++ library is too old to run
|
||||||
would like to stream with Audio, see{" "}
|
<a href="https://github.com/Vencord/venmic" target="_blank">
|
||||||
<a
|
venmic
|
||||||
href="https://gist.github.com/Vendicated/b655044ffbb16b2716095a448c6d827a"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
this guide
|
|
||||||
</a>
|
</a>
|
||||||
|
. See{" "}
|
||||||
|
<a href="https://gist.github.com/Vendicated/b655044ffbb16b2716095a448c6d827a" target="_blank">
|
||||||
|
this guide
|
||||||
|
</a>{" "}
|
||||||
|
for possible solutions.
|
||||||
</Forms.FormText>
|
</Forms.FormText>
|
||||||
) : (
|
)}
|
||||||
<Forms.FormText>
|
|
||||||
Failed to retrieve Audio Sources. If you would like to stream with Audio, make sure you're
|
|
||||||
using Pipewire, not Pulseaudio
|
|
||||||
</Forms.FormText>
|
|
||||||
))}
|
|
||||||
|
|
||||||
{allSources && (
|
{hasPipewirePulse || ignorePulseWarning ? (
|
||||||
|
allSources && (
|
||||||
<Select
|
<Select
|
||||||
options={allSources.map(s => ({ label: s, value: s, default: s === "None" }))}
|
options={allSources.map(s => ({ label: s, value: s, default: s === "None" }))}
|
||||||
isSelected={s => s === audioSource}
|
isSelected={s => s === audioSource}
|
||||||
select={setAudioSource}
|
select={setAudioSource}
|
||||||
serialize={String}
|
serialize={String}
|
||||||
/>
|
/>
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
<Text variant="text-sm/normal">
|
||||||
|
Could not find pipewire-pulse. This usually means that you do not run pipewire as your main
|
||||||
|
audio-server. <br />
|
||||||
|
You can still continue, however, please beware that you can only share audio of apps that are
|
||||||
|
running under pipewire.
|
||||||
|
<br />
|
||||||
|
<a onClick={() => setIgnorePulseWarning(true)}>I know what I'm doing</a>
|
||||||
|
</Text>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Forms.FormDivider className={Margins.top16 + " " + Margins.bottom16} />
|
<Forms.FormDivider className={Margins.top16 + " " + Margins.bottom16} />
|
||||||
|
|
24
src/renderer/patches/hideSwitchDevice.tsx
Normal file
24
src/renderer/patches/hideSwitchDevice.tsx
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0
|
||||||
|
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||||
|
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { addPatch } from "./shared";
|
||||||
|
|
||||||
|
addPatch({
|
||||||
|
patches: [
|
||||||
|
{
|
||||||
|
find: "lastOutputSystemDevice.justChanged",
|
||||||
|
replacement: {
|
||||||
|
// eslint-disable-next-line no-useless-escape
|
||||||
|
match: /(\i)\.default\.getState\(\).neverShowModal/,
|
||||||
|
replace: "$& || $self.shouldIgnore($1)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
shouldIgnore(state: any) {
|
||||||
|
return Object.keys(state?.default?.lastDeviceConnected ?? {})?.[0] === "vencord-screen-share";
|
||||||
|
}
|
||||||
|
});
|
|
@ -7,6 +7,7 @@
|
||||||
// TODO: Possibly auto generate glob if we have more patches in the future
|
// TODO: Possibly auto generate glob if we have more patches in the future
|
||||||
import "./enableNotificationsByDefault";
|
import "./enableNotificationsByDefault";
|
||||||
import "./platformClass";
|
import "./platformClass";
|
||||||
|
import "./hideSwitchDevice";
|
||||||
import "./screenShareFixes";
|
import "./screenShareFixes";
|
||||||
import "./spellCheck";
|
import "./spellCheck";
|
||||||
import "./windowsTitleBar";
|
import "./windowsTitleBar";
|
||||||
|
|
|
@ -11,11 +11,12 @@ import { isLinux } from "renderer/utils";
|
||||||
const logger = new Logger("VesktopStreamFixes");
|
const logger = new Logger("VesktopStreamFixes");
|
||||||
|
|
||||||
if (isLinux) {
|
if (isLinux) {
|
||||||
const original = navigator.mediaDevices.getDisplayMedia;
|
const originalMedia = navigator.mediaDevices.getDisplayMedia;
|
||||||
|
const originalDevices = navigator.mediaDevices.enumerateDevices;
|
||||||
|
|
||||||
async function getVirtmic() {
|
async function getVirtmic() {
|
||||||
try {
|
try {
|
||||||
const devices = await navigator.mediaDevices.enumerateDevices();
|
const devices = await originalDevices();
|
||||||
const audioDevice = devices.find(({ label }) => label === "vencord-screen-share");
|
const audioDevice = devices.find(({ label }) => label === "vencord-screen-share");
|
||||||
return audioDevice?.deviceId;
|
return audioDevice?.deviceId;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -23,8 +24,13 @@ if (isLinux) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
navigator.mediaDevices.enumerateDevices = async function () {
|
||||||
|
const result = await originalDevices.call(this);
|
||||||
|
return result.filter(x => x.label !== "vencord-screen-share");
|
||||||
|
};
|
||||||
|
|
||||||
navigator.mediaDevices.getDisplayMedia = async function (opts) {
|
navigator.mediaDevices.getDisplayMedia = async function (opts) {
|
||||||
const stream = await original.call(this, opts);
|
const stream = await originalMedia.call(this, opts);
|
||||||
const id = await getVirtmic();
|
const id = await getVirtmic();
|
||||||
|
|
||||||
const frameRate = Number(currentSettings?.fps);
|
const frameRate = Number(currentSettings?.fps);
|
||||||
|
|
Loading…
Reference in a new issue