add linux audio screensharing (#130)

Co-authored-by: V <vendicated@riseup.net>
Co-authored-by: kaitlynkitty <87152313+kaitlynkittyy@users.noreply.github.com>
Co-authored-by: Curve <fynnbwdt@gmail.com>
This commit is contained in:
V
2023-10-21 22:15:55 +02:00
committed by GitHub
parent 841cdcf672
commit 573a953a2f
16 changed files with 690 additions and 173 deletions

View File

@@ -4,6 +4,8 @@
* Copyright (c) 2023 Vendicated and Vencord contributors
*/
if (process.platform === "linux") import("./virtmic");
import { execFile } from "child_process";
import { app, dialog, RelaunchOptions, session, shell } from "electron";
import { mkdirSync, readFileSync, watch } from "fs";

View File

@@ -10,6 +10,9 @@ import { IpcEvents } from "shared/IpcEvents";
import { handle } from "./utils/ipcWrappers";
const isWayland =
process.platform === "linux" && (process.env.XDG_SESSION_TYPE === "wayland" || !!process.env.WAYLAND_DISPLAY);
export function registerScreenShareHandler() {
handle(IpcEvents.CAPTURER_GET_LARGE_THUMBNAIL, async (_, id: string) => {
const sources = await desktopCapturer.getSources({
@@ -23,17 +26,19 @@ export function registerScreenShareHandler() {
});
session.defaultSession.setDisplayMediaRequestHandler(async (request, callback) => {
const sources = await desktopCapturer.getSources({
types: ["window", "screen"],
thumbnailSize: {
width: 176,
height: 99
}
});
// request full resolution on wayland right away because we always only end up with one result anyway
const width = isWayland ? 1920 : 176;
const sources = await desktopCapturer
.getSources({
types: ["window", "screen"],
thumbnailSize: {
width,
height: width * (9 / 16)
}
})
.catch(err => console.error("Error during screenshare picker", err));
const isWayland =
process.platform === "linux" &&
(process.env.XDG_SESSION_TYPE === "wayland" || !!process.env.WAYLAND_DISPLAY);
if (!sources) return callback({});
const data = sources.map(({ id, name, thumbnail }) => ({
id,
@@ -43,14 +48,26 @@ export function registerScreenShareHandler() {
if (isWayland) {
const video = data[0];
callback(video ? { video } : {});
if (video) {
const stream = await request.frame
.executeJavaScript(
`Vesktop.Components.ScreenShare.openScreenSharePicker(${JSON.stringify([video])},true)`
)
.catch(() => null);
if (stream === null) return callback({});
}
callback(video ? { video: sources[0] } : {});
return;
}
const choice = await request.frame
.executeJavaScript(`Vesktop.Components.ScreenShare.openScreenSharePicker(${JSON.stringify(data)})`)
.then(e => e as StreamPick)
.catch(() => null);
.catch(e => {
console.error("Error during screenshare picker", e);
return null;
});
if (!choice) return callback({});

66
src/main/virtmic.ts Normal file
View File

@@ -0,0 +1,66 @@
/*
* 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 { app, ipcMain } from "electron";
import { join } from "path";
import { IpcEvents } from "shared/IpcEvents";
import { STATIC_DIR } from "shared/paths";
let initialized = false;
let patchBay: import("@vencord/venmic").PatchBay | undefined;
function getRendererAudioServicePid() {
return (
app
.getAppMetrics()
.find(proc => proc.name === "Audio Service")
?.pid?.toString() ?? "owo"
);
}
function obtainVenmic() {
if (!initialized) {
initialized = true;
try {
const { PatchBay } = require(join(STATIC_DIR, "dist/venmic.node")) as typeof import("@vencord/venmic");
patchBay = new PatchBay();
} catch (e) {
console.error("Failed to initialise venmic. Make sure you're using pipewire", e);
}
}
return patchBay;
}
ipcMain.handle(IpcEvents.VIRT_MIC_LIST, () => {
const audioPid = getRendererAudioServicePid();
return obtainVenmic()
?.list()
.filter(s => s["application.process.id"] !== audioPid)
.map(s => s["application.name"]);
});
ipcMain.handle(
IpcEvents.VIRT_MIC_START,
(_, target: string) =>
obtainVenmic()?.link({
key: "application.name",
value: target,
mode: "include"
})
);
ipcMain.handle(
IpcEvents.VIRT_MIC_START_SYSTEM,
() =>
obtainVenmic()?.link({
key: "application.process.id",
value: getRendererAudioServicePid(),
mode: "exclude"
})
);
ipcMain.handle(IpcEvents.VIRT_MIC_STOP, () => obtainVenmic()?.unlink());