mirror of
https://github.com/Vencord/Vesktop.git
synced 2025-02-23 05:35:09 +00:00
feat: allow patching video & audio devices into screen share
This commit is contained in:
parent
5b6c1c6d81
commit
5133e70717
2 changed files with 123 additions and 15 deletions
|
@ -21,6 +21,7 @@ import {
|
||||||
} from "@vencord/types/webpack/common";
|
} from "@vencord/types/webpack/common";
|
||||||
import { Node } from "@vencord/venmic";
|
import { Node } from "@vencord/venmic";
|
||||||
import type { Dispatch, SetStateAction } from "react";
|
import type { Dispatch, SetStateAction } from "react";
|
||||||
|
import { patchOverrideDevices } from "renderer/patches/screenShareFixes";
|
||||||
import { addPatch } from "renderer/patches/shared";
|
import { addPatch } from "renderer/patches/shared";
|
||||||
import { useSettings } from "renderer/settings";
|
import { useSettings } from "renderer/settings";
|
||||||
import { isLinux, isWindows } from "renderer/utils";
|
import { isLinux, isWindows } from "renderer/utils";
|
||||||
|
@ -47,6 +48,8 @@ interface StreamSettings {
|
||||||
resolution: StreamResolution;
|
resolution: StreamResolution;
|
||||||
fps: StreamFps;
|
fps: StreamFps;
|
||||||
audio: boolean;
|
audio: boolean;
|
||||||
|
overrideAudioDevice?: string;
|
||||||
|
overrideVideoDevice?: string;
|
||||||
contentHint?: string;
|
contentHint?: string;
|
||||||
includeSources?: AudioSources;
|
includeSources?: AudioSources;
|
||||||
excludeSources?: AudioSources;
|
excludeSources?: AudioSources;
|
||||||
|
@ -140,6 +143,11 @@ export function openScreenSharePicker(screens: Source[], skipPicker: boolean) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
patchOverrideDevices({
|
||||||
|
audio: v.overrideAudioDevice,
|
||||||
|
video: v.overrideVideoDevice
|
||||||
|
});
|
||||||
|
|
||||||
resolve(v);
|
resolve(v);
|
||||||
}}
|
}}
|
||||||
close={() => {
|
close={() => {
|
||||||
|
@ -325,6 +333,16 @@ function StreamSettings({
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const [audioDevices, , audioDevicesPending] = useAwaiter(
|
||||||
|
() => navigator.mediaDevices.enumerateDevices().then(g => g.filter(d => d.kind === "audioinput")),
|
||||||
|
{ fallbackValue: [] }
|
||||||
|
);
|
||||||
|
|
||||||
|
const [videoDevices, , videoDevicesPending] = useAwaiter(
|
||||||
|
() => navigator.mediaDevices.enumerateDevices().then(g => g.filter(d => d.kind === "videoinput")),
|
||||||
|
{ fallbackValue: [] }
|
||||||
|
);
|
||||||
|
|
||||||
const openSettings = () => {
|
const openSettings = () => {
|
||||||
const key = openModal(props => (
|
const key = openModal(props => (
|
||||||
<AudioSettingsModal
|
<AudioSettingsModal
|
||||||
|
@ -428,6 +446,47 @@ function StreamSettings({
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<Forms.FormTitle>
|
||||||
|
{audioDevicesPending ? "Loading audio devices..." : "Audio devices"}
|
||||||
|
</Forms.FormTitle>
|
||||||
|
<Select
|
||||||
|
options={audioDevices.map(({ label, deviceId }) => ({
|
||||||
|
label,
|
||||||
|
value: deviceId
|
||||||
|
}))}
|
||||||
|
isSelected={d => settings.overrideAudioDevice === d}
|
||||||
|
select={d => {
|
||||||
|
setSettings(v => ({ ...v, overrideAudioDevice: d }));
|
||||||
|
}}
|
||||||
|
serialize={String}
|
||||||
|
popoutPosition="top"
|
||||||
|
closeOnSelect={true}
|
||||||
|
isDisabled={audioDevicesPending}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<Forms.FormTitle>
|
||||||
|
{videoDevicesPending ? "Loading video devices..." : "Video devices"}
|
||||||
|
</Forms.FormTitle>
|
||||||
|
<Select
|
||||||
|
options={videoDevices.map(({ label, deviceId }) => ({
|
||||||
|
label,
|
||||||
|
value: deviceId
|
||||||
|
}))}
|
||||||
|
isSelected={d => settings.overrideVideoDevice === d}
|
||||||
|
select={d => {
|
||||||
|
setSettings(v => ({ ...v, overrideVideoDevice: d }));
|
||||||
|
}}
|
||||||
|
serialize={String}
|
||||||
|
popoutPosition="top"
|
||||||
|
closeOnSelect={true}
|
||||||
|
isDisabled={videoDevicesPending}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
{isWindows && (
|
{isWindows && (
|
||||||
<Switch
|
<Switch
|
||||||
value={settings.audio}
|
value={settings.audio}
|
||||||
|
|
|
@ -10,9 +10,19 @@ import { isLinux } from "renderer/utils";
|
||||||
|
|
||||||
const logger = new Logger("VesktopStreamFixes");
|
const logger = new Logger("VesktopStreamFixes");
|
||||||
|
|
||||||
if (isLinux) {
|
|
||||||
const original = navigator.mediaDevices.getDisplayMedia;
|
const original = navigator.mediaDevices.getDisplayMedia;
|
||||||
|
|
||||||
|
interface OverrideDevices {
|
||||||
|
audio: string | undefined;
|
||||||
|
video: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
let overrideDevices: OverrideDevices = { audio: undefined, video: undefined };
|
||||||
|
|
||||||
|
export const patchOverrideDevices = (newOverrideDevices: OverrideDevices) => {
|
||||||
|
overrideDevices = newOverrideDevices;
|
||||||
|
};
|
||||||
|
|
||||||
async function getVirtmic() {
|
async function getVirtmic() {
|
||||||
try {
|
try {
|
||||||
const devices = await navigator.mediaDevices.enumerateDevices();
|
const devices = await navigator.mediaDevices.enumerateDevices();
|
||||||
|
@ -25,6 +35,45 @@ if (isLinux) {
|
||||||
|
|
||||||
navigator.mediaDevices.getDisplayMedia = async function (opts) {
|
navigator.mediaDevices.getDisplayMedia = async function (opts) {
|
||||||
const stream = await original.call(this, opts);
|
const stream = await original.call(this, opts);
|
||||||
|
|
||||||
|
if (overrideDevices.audio) {
|
||||||
|
const audio = await navigator.mediaDevices.getUserMedia({
|
||||||
|
audio: {
|
||||||
|
deviceId: { exact: overrideDevices.audio },
|
||||||
|
autoGainControl: false,
|
||||||
|
echoCancellation: false,
|
||||||
|
noiseSuppression: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
stream.getAudioTracks().forEach(t => {
|
||||||
|
t.stop();
|
||||||
|
stream.removeTrack(t);
|
||||||
|
});
|
||||||
|
|
||||||
|
audio.getAudioTracks().forEach(t => {
|
||||||
|
stream.addTrack(t);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (overrideDevices.video) {
|
||||||
|
const video = await navigator.mediaDevices.getUserMedia({
|
||||||
|
video: {
|
||||||
|
deviceId: { exact: overrideDevices.video }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
stream.getVideoTracks().forEach(t => {
|
||||||
|
t.stop();
|
||||||
|
stream.removeTrack(t);
|
||||||
|
});
|
||||||
|
|
||||||
|
video.getVideoTracks().forEach(t => {
|
||||||
|
stream.addTrack(t);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLinux) {
|
||||||
const id = await getVirtmic();
|
const id = await getVirtmic();
|
||||||
|
|
||||||
const frameRate = Number(currentSettings?.fps);
|
const frameRate = Number(currentSettings?.fps);
|
||||||
|
@ -63,7 +112,7 @@ if (isLinux) {
|
||||||
});
|
});
|
||||||
audio.getAudioTracks().forEach(t => stream.addTrack(t));
|
audio.getAudioTracks().forEach(t => stream.addTrack(t));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return stream;
|
return stream;
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue