mirror of
https://github.com/smartfrigde/armcord.git
synced 2024-08-14 23:56:58 +00:00
[wip] linux audio screenshare
This commit is contained in:
parent
bed9e02059
commit
1a1c549f6c
4 changed files with 290 additions and 22 deletions
65
src/content/js/patchAudio.js
Normal file
65
src/content/js/patchAudio.js
Normal file
|
@ -0,0 +1,65 @@
|
|||
navigator.mediaDevices.getDisplayMedia = getDisplayMedia;
|
||||
// ==UserScript==
|
||||
// @name Screenshare with Audio
|
||||
// @namespace https://github.com/edisionnano
|
||||
// @version 0.4
|
||||
// @updateURL https://openuserjs.org/meta/samantas5855/Screenshare_with_Audio.meta.js
|
||||
// @description Screenshare with Audio on Discord
|
||||
// @author Guest271314 and Samantas5855
|
||||
// @match https://*.discord.com/*
|
||||
// @icon https://www.google.com/s2/favicons?domain=discord.com
|
||||
// @grant none
|
||||
// @license MIT
|
||||
// ==/UserScript==
|
||||
|
||||
/* jshint esversion: 8 */
|
||||
|
||||
navigator.mediaDevices.chromiumGetDisplayMedia = navigator.mediaDevices.getDisplayMedia;
|
||||
|
||||
const getAudioDevice = async (nameOfAudioDevice) => {
|
||||
await navigator.mediaDevices.getUserMedia({
|
||||
audio: true
|
||||
});
|
||||
await new Promise((r) => setTimeout(r, 1000));
|
||||
let devices = await navigator.mediaDevices.enumerateDevices();
|
||||
let audioDevice = devices.find(({label}) => label === nameOfAudioDevice);
|
||||
return audioDevice;
|
||||
};
|
||||
|
||||
const getDisplayMedia = async () => {
|
||||
var id;
|
||||
try {
|
||||
let myDiscordAudioSink = await getAudioDevice("screenshareAudio");
|
||||
id = myDiscordAudioSink.deviceId;
|
||||
} catch (error) {
|
||||
id = "default";
|
||||
}
|
||||
let captureSystemAudioStream = await navigator.mediaDevices.getUserMedia({
|
||||
audio: {
|
||||
// We add our audio constraints here, to get a list of supported constraints use navigator.mediaDevices.getSupportedConstraints();
|
||||
// We must capture a microphone, we use default since its the only deviceId that is the same for every Chromium user
|
||||
deviceId: {
|
||||
exact: id
|
||||
},
|
||||
// We want auto gain control, noise cancellation and noise suppression disabled so that our stream won't sound bad
|
||||
autoGainControl: false,
|
||||
echoCancellation: false,
|
||||
noiseSuppression: false
|
||||
// By default Chromium sets channel count for audio devices to 1, we want it to be stereo in case we find a way for Discord to accept stereo screenshare too
|
||||
//channelCount: 2,
|
||||
// You can set more audio constraints here, bellow are some examples
|
||||
//latency: 0,
|
||||
//sampleRate: 48000,
|
||||
//sampleSize: 16,
|
||||
//volume: 1.0
|
||||
}
|
||||
});
|
||||
let [track] = captureSystemAudioStream.getAudioTracks();
|
||||
const gdm = await navigator.mediaDevices.chromiumGetDisplayMedia({
|
||||
video: true,
|
||||
audio: true
|
||||
});
|
||||
gdm.addTrack(track);
|
||||
return gdm;
|
||||
};
|
||||
navigator.mediaDevices.getDisplayMedia = getDisplayMedia;
|
79
src/screenshare/audio.ts
Normal file
79
src/screenshare/audio.ts
Normal file
|
@ -0,0 +1,79 @@
|
|||
import {spawn} from "child_process";
|
||||
import fs from "fs";
|
||||
import {app} from "electron";
|
||||
import path from "path";
|
||||
|
||||
// quick and dirty way for audio screenshare on Linux
|
||||
// please PR a better non-shell solution that isn't a dependency mess
|
||||
//src https://github.com/edisionnano/Screenshare-with-audio-on-Discord-with-Linux
|
||||
interface SinkInput {
|
||||
id: string;
|
||||
properties: Record<string, string>;
|
||||
}
|
||||
|
||||
const parseSinkInputs = (input: string): SinkInput[] => {
|
||||
const regex = /Sink Input #(\d+)\n([\s\S]+?)(?=\nSink Input #|\n{2,}|$)/g;
|
||||
const result: SinkInput[] = [];
|
||||
let match;
|
||||
|
||||
while ((match = regex.exec(input))) {
|
||||
const sinkInput: SinkInput = {
|
||||
id: match[1],
|
||||
properties: {}
|
||||
};
|
||||
|
||||
const propertiesRegex = /(\w+)\s*=\s*"([^"]*)"/g;
|
||||
let propertiesMatch;
|
||||
|
||||
while ((propertiesMatch = propertiesRegex.exec(match[2]))) {
|
||||
sinkInput.properties[propertiesMatch[1]] = propertiesMatch[2];
|
||||
}
|
||||
|
||||
result.push(sinkInput);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
export function createVirtualDevice(sinkInput: number) {
|
||||
var script = `
|
||||
SINK_NAME=armcord
|
||||
export LC_ALL=C
|
||||
DEFAULT_OUTPUT=$(pactl info|sed -n -e 's/^.*Default Sink: //p')
|
||||
pactl load-module module-null-sink sink_name=$SINK_NAME
|
||||
pactl move-sink-input ${sinkInput} $SINK_NAME
|
||||
pactl load-module module-loopback source=$SINK_NAME.monitor sink=$DEFAULT_OUTPUT
|
||||
if pactl info|grep -w "PipeWire">/dev/null; then
|
||||
nohup pw-loopback --capture-props='node.target='$SINK_NAME --playback-props='media.class=Audio/Source node.name=virtmic node.description="virtmic"' >/dev/null &
|
||||
else
|
||||
pactl load-module module-remap-source master=$SINK_NAME.monitor source_name=virtmic source_properties=device.description=virtmic
|
||||
fi`;
|
||||
let scriptPath = path.join(app.getPath("temp"), "/", "script.sh");
|
||||
spawn("chmod +x " + scriptPath);
|
||||
fs.writeFileSync(scriptPath, script, "utf-8");
|
||||
const exec = spawn(scriptPath);
|
||||
}
|
||||
|
||||
export function isAudioSupported(): boolean {
|
||||
const pactl = spawn("pactl");
|
||||
|
||||
pactl.on("close", (code) => {
|
||||
if (code == 0) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
export function getSinks() {
|
||||
const pactl = spawn("pactl list sink-inputs");
|
||||
|
||||
pactl.stderr.on("data", (data) => {
|
||||
console.log(data);
|
||||
return parseSinkInputs(data);
|
||||
});
|
||||
pactl.on("close", (code) => {
|
||||
if (code !== 0) {
|
||||
throw Error("Couldn't get list of available apps for audio stream");
|
||||
}
|
||||
});
|
||||
}
|
|
@ -1,10 +1,18 @@
|
|||
import {BrowserWindow, desktopCapturer, ipcMain, session} from "electron";
|
||||
import path from "path";
|
||||
import {iconPath} from "../main";
|
||||
import {getSinks, isAudioSupported} from "./audio";
|
||||
let capturerWindow: BrowserWindow;
|
||||
function registerCustomHandler(): void {
|
||||
session.defaultSession.setDisplayMediaRequestHandler(async (request, callback) => {
|
||||
console.log(request);
|
||||
if (process.platform == "linux") {
|
||||
let isAudio = isAudioSupported();
|
||||
if (isAudio) {
|
||||
console.log("audio supported");
|
||||
getSinks();
|
||||
}
|
||||
}
|
||||
const sources = await desktopCapturer.getSources({
|
||||
types: ["screen", "window"]
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue