Skip to content

Commit

Permalink
feat: allow patching video & audio devices into screen share
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanccn committed Dec 4, 2024
1 parent 5b6c1c6 commit 5133e70
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 16 deletions.
59 changes: 59 additions & 0 deletions src/renderer/components/ScreenSharePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
} from "@vencord/types/webpack/common";
import { Node } from "@vencord/venmic";
import type { Dispatch, SetStateAction } from "react";
import { patchOverrideDevices } from "renderer/patches/screenShareFixes";
import { addPatch } from "renderer/patches/shared";
import { useSettings } from "renderer/settings";
import { isLinux, isWindows } from "renderer/utils";
Expand All @@ -47,6 +48,8 @@ interface StreamSettings {
resolution: StreamResolution;
fps: StreamFps;
audio: boolean;
overrideAudioDevice?: string;
overrideVideoDevice?: string;
contentHint?: string;
includeSources?: AudioSources;
excludeSources?: AudioSources;
Expand Down Expand Up @@ -140,6 +143,11 @@ export function openScreenSharePicker(screens: Source[], skipPicker: boolean) {
}
}

patchOverrideDevices({
audio: v.overrideAudioDevice,
video: v.overrideVideoDevice
});

resolve(v);
}}
close={() => {
Expand Down Expand Up @@ -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 key = openModal(props => (
<AudioSettingsModal
Expand Down Expand Up @@ -428,6 +446,47 @@ function StreamSettings({
</p>
</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 && (
<Switch
value={settings.audio}
Expand Down
81 changes: 65 additions & 16 deletions src/renderer/patches/screenShareFixes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,70 @@ import { isLinux } from "renderer/utils";

const logger = new Logger("VesktopStreamFixes");

if (isLinux) {
const original = navigator.mediaDevices.getDisplayMedia;

async function getVirtmic() {
try {
const devices = await navigator.mediaDevices.enumerateDevices();
const audioDevice = devices.find(({ label }) => label === "vencord-screen-share");
return audioDevice?.deviceId;
} catch (error) {
return null;
}
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() {
try {
const devices = await navigator.mediaDevices.enumerateDevices();
const audioDevice = devices.find(({ label }) => label === "vencord-screen-share");
return audioDevice?.deviceId;
} catch (error) {
return null;
}
}

navigator.mediaDevices.getDisplayMedia = async function (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);
});
}

navigator.mediaDevices.getDisplayMedia = async function (opts) {
const stream = await original.call(this, opts);
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 frameRate = Number(currentSettings?.fps);
Expand Down Expand Up @@ -63,7 +112,7 @@ if (isLinux) {
});
audio.getAudioTracks().forEach(t => stream.addTrack(t));
}
}

return stream;
};
}
return stream;
};

0 comments on commit 5133e70

Please sign in to comment.