Update Venmic to 7.1.0 (#1291)
- Fixes https://github.com/Vencord/venmic/issues/43 - Fixes https://github.com/Vencord/venmic/issues/36 - Fixes https://github.com/Vencord/venmic/issues/34 - Fixes #772
This commit is contained in:
+1
-1
@@ -31,7 +31,7 @@
|
|||||||
"electron-updater": "6.6.2"
|
"electron-updater": "6.6.2"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@vencord/venmic": "^6.1.0"
|
"@vencord/venmic": "^7.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@fal-works/esbuild-plugin-global-externals": "^2.1.2",
|
"@fal-works/esbuild-plugin-global-externals": "^2.1.2",
|
||||||
|
|||||||
Generated
+5
-5
@@ -96,8 +96,8 @@ importers:
|
|||||||
version: 3.7.0
|
version: 3.7.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@vencord/venmic':
|
'@vencord/venmic':
|
||||||
specifier: ^6.1.0
|
specifier: ^7.1.0
|
||||||
version: 6.1.0
|
version: 7.1.0
|
||||||
|
|
||||||
packages/libvesktop:
|
packages/libvesktop:
|
||||||
devDependencies:
|
devDependencies:
|
||||||
@@ -555,8 +555,8 @@ packages:
|
|||||||
'@types/react': 18.3.1
|
'@types/react': 18.3.1
|
||||||
'@types/react-dom': 18.3.1
|
'@types/react-dom': 18.3.1
|
||||||
|
|
||||||
'@vencord/venmic@6.1.0':
|
'@vencord/venmic@7.1.0':
|
||||||
resolution: {integrity: sha512-YiCtzml/W8tYbGhu3jm5jfbbEnl2slKKARNK0jO+8qV979k9eFnfIRTxvhMN/SWq1h8ZNJdXVwvXpffQwq0RuA==}
|
resolution: {integrity: sha512-HQpZoUKGz8j7m1+1BCgE+7B6T/+/IArVO8km7SjsWxe/5+2YblAs0Fwgy9C9XqCCir/u0+F1FMqrQQUX2PATYw==}
|
||||||
engines: {node: '>=14.15'}
|
engines: {node: '>=14.15'}
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
@@ -3317,7 +3317,7 @@ snapshots:
|
|||||||
ts-pattern: 5.9.0
|
ts-pattern: 5.9.0
|
||||||
type-fest: 4.41.0
|
type-fest: 4.41.0
|
||||||
|
|
||||||
'@vencord/venmic@6.1.0':
|
'@vencord/venmic@7.1.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
cmake-js: 7.4.0
|
cmake-js: 7.4.0
|
||||||
node-addon-api: 8.9.0
|
node-addon-api: 8.9.0
|
||||||
|
|||||||
+2
-1
@@ -13,4 +13,5 @@ recursiveInstall: false
|
|||||||
packages:
|
packages:
|
||||||
- packages/*
|
- packages/*
|
||||||
minimumReleaseAgeExclude:
|
minimumReleaseAgeExclude:
|
||||||
- electron
|
- electron
|
||||||
|
- '@vencord/*'
|
||||||
|
|||||||
+38
-48
@@ -66,70 +66,60 @@ function getRendererAudioServicePid() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildLinkData({ include, exclude }: { include?: Node[]; exclude?: Node[] }) {
|
||||||
|
const pid = getRendererAudioServicePid();
|
||||||
|
|
||||||
|
const { mute, ignoreDevices, ignoreInputMedia, ignoreVirtual, workaround, onlySpeakers, onlyDefaultSpeakers } =
|
||||||
|
Settings.store.audio ?? {};
|
||||||
|
|
||||||
|
const data: LinkData = {
|
||||||
|
mute: mute ?? true,
|
||||||
|
include: include ?? [],
|
||||||
|
exclude: exclude ?? [],
|
||||||
|
only_speakers: onlySpeakers,
|
||||||
|
ignore_devices: ignoreDevices,
|
||||||
|
only_default_speakers: onlyDefaultSpeakers
|
||||||
|
};
|
||||||
|
|
||||||
|
data.exclude.push({ "application.process.id": pid });
|
||||||
|
|
||||||
|
if (ignoreInputMedia ?? true) {
|
||||||
|
data.exclude.push({ "media.class": "Stream/Input/Audio" });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ignoreVirtual) {
|
||||||
|
data.exclude.push({ "node.virtual": "true" });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workaround) {
|
||||||
|
data.workaround = [{ "application.process.id": pid, "media.name": "RecordStream" }];
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
ipcMain.handle(IpcEvents.VIRT_MIC_LIST, () => {
|
ipcMain.handle(IpcEvents.VIRT_MIC_LIST, () => {
|
||||||
const audioPid = getRendererAudioServicePid();
|
const audioPid = getRendererAudioServicePid();
|
||||||
|
|
||||||
const { granularSelect } = Settings.store.audio ?? {};
|
const { granularSelect } = Settings.store.audio ?? {};
|
||||||
|
|
||||||
const targets = obtainVenmic()
|
const targets = obtainVenmic()
|
||||||
?.list(granularSelect ? ["node.name"] : undefined)
|
?.list(granularSelect ? [] : ["application.name", "node.name"])
|
||||||
.filter(s => s["application.process.id"] !== audioPid);
|
.filter(s => s["application.process.id"] !== audioPid);
|
||||||
|
|
||||||
return targets ? { ok: true, targets, hasPipewirePulse } : { ok: false, isGlibCxxOutdated };
|
return targets ? { ok: true, targets, hasPipewirePulse } : { ok: false, isGlibCxxOutdated };
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle(IpcEvents.VIRT_MIC_START, (_, include: Node[]) => {
|
ipcMain.handle(IpcEvents.VIRT_MIC_START, (_, include: Node[]) => {
|
||||||
const pid = getRendererAudioServicePid();
|
return obtainVenmic()?.link(buildLinkData({ include }));
|
||||||
const { ignoreDevices, ignoreInputMedia, ignoreVirtual, workaround } = Settings.store.audio ?? {};
|
|
||||||
|
|
||||||
const data: LinkData = {
|
|
||||||
include,
|
|
||||||
exclude: [{ "application.process.id": pid }],
|
|
||||||
ignore_devices: ignoreDevices
|
|
||||||
};
|
|
||||||
|
|
||||||
if (ignoreInputMedia ?? true) {
|
|
||||||
data.exclude.push({ "media.class": "Stream/Input/Audio" });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ignoreVirtual) {
|
|
||||||
data.exclude.push({ "node.virtual": "true" });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (workaround) {
|
|
||||||
data.workaround = [{ "application.process.id": pid, "media.name": "RecordStream" }];
|
|
||||||
}
|
|
||||||
|
|
||||||
return obtainVenmic()?.link(data);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle(IpcEvents.VIRT_MIC_START_SYSTEM, (_, exclude: Node[]) => {
|
ipcMain.handle(IpcEvents.VIRT_MIC_START_SYSTEM, (_, exclude: Node[]) => {
|
||||||
const pid = getRendererAudioServicePid();
|
return obtainVenmic()?.link(buildLinkData({ exclude }));
|
||||||
|
});
|
||||||
|
|
||||||
const { workaround, ignoreDevices, ignoreInputMedia, ignoreVirtual, onlySpeakers, onlyDefaultSpeakers } =
|
ipcMain.handle(IpcEvents.VIRT_MIC_UNMUTE, () => {
|
||||||
Settings.store.audio ?? {};
|
return obtainVenmic()?.unmute();
|
||||||
|
|
||||||
const data: LinkData = {
|
|
||||||
include: [],
|
|
||||||
exclude: [{ "application.process.id": pid }, ...exclude],
|
|
||||||
only_speakers: onlySpeakers,
|
|
||||||
ignore_devices: ignoreDevices,
|
|
||||||
only_default_speakers: onlyDefaultSpeakers
|
|
||||||
};
|
|
||||||
|
|
||||||
if (ignoreInputMedia ?? true) {
|
|
||||||
data.exclude.push({ "media.class": "Stream/Input/Audio" });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ignoreVirtual) {
|
|
||||||
data.exclude.push({ "node.virtual": "true" });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (workaround) {
|
|
||||||
data.workaround = [{ "application.process.id": pid, "media.name": "RecordStream" }];
|
|
||||||
}
|
|
||||||
|
|
||||||
return obtainVenmic()?.link(data);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle(IpcEvents.VIRT_MIC_STOP, () => obtainVenmic()?.unlink());
|
ipcMain.handle(IpcEvents.VIRT_MIC_STOP, () => obtainVenmic()?.unlink());
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ export const VesktopNative = {
|
|||||||
>(IpcEvents.VIRT_MIC_LIST),
|
>(IpcEvents.VIRT_MIC_LIST),
|
||||||
start: (include: Node[]) => invoke<void>(IpcEvents.VIRT_MIC_START, include),
|
start: (include: Node[]) => invoke<void>(IpcEvents.VIRT_MIC_START, include),
|
||||||
startSystem: (exclude: Node[]) => invoke<void>(IpcEvents.VIRT_MIC_START_SYSTEM, exclude),
|
startSystem: (exclude: Node[]) => invoke<void>(IpcEvents.VIRT_MIC_START_SYSTEM, exclude),
|
||||||
|
unmute: () => invoke<void>(IpcEvents.VIRT_MIC_UNMUTE),
|
||||||
stop: () => invoke<void>(IpcEvents.VIRT_MIC_STOP)
|
stop: () => invoke<void>(IpcEvents.VIRT_MIC_STOP)
|
||||||
},
|
},
|
||||||
clipboard: {
|
clipboard: {
|
||||||
|
|||||||
@@ -122,15 +122,25 @@ addPatch({
|
|||||||
|
|
||||||
if (isLinux) {
|
if (isLinux) {
|
||||||
onceReady.then(() => {
|
onceReady.then(() => {
|
||||||
FluxDispatcher.subscribe("STREAM_CLOSE", ({ streamKey }: { streamKey: string }) => {
|
const ownsStream = (streamKey: string) => {
|
||||||
const owner = streamKey.split(":").at(-1);
|
return streamKey.split(":").at(-1) === UserStore.getCurrentUser().id;
|
||||||
|
};
|
||||||
|
|
||||||
if (owner !== UserStore.getCurrentUser().id) {
|
FluxDispatcher.subscribe("STREAM_CLOSE", ({ streamKey }: { streamKey: string }) => {
|
||||||
|
if (!ownsStream(streamKey)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
VesktopNative.virtmic.stop();
|
VesktopNative.virtmic.stop();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
FluxDispatcher.subscribe("STREAM_UPDATE", ({ streamKey }: { streamKey: string }) => {
|
||||||
|
if (!ownsStream(streamKey)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VesktopNative.virtmic.unmute();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,6 +229,13 @@ function AudioSettingsModal({
|
|||||||
</Modals.ModalHeader>
|
</Modals.ModalHeader>
|
||||||
|
|
||||||
<Modals.ModalContent className={cl("modal", "venmic-settings")}>
|
<Modals.ModalContent className={cl("modal", "venmic-settings")}>
|
||||||
|
<FormSwitch
|
||||||
|
title="Initial Mute"
|
||||||
|
description="Fix an initial audio spike caused by chromium."
|
||||||
|
hideBorder
|
||||||
|
onChange={v => (Settings.audio = { ...Settings.audio, mute: v })}
|
||||||
|
value={Settings.audio?.mute ?? true}
|
||||||
|
/>
|
||||||
<FormSwitch
|
<FormSwitch
|
||||||
title="Microphone Workaround"
|
title="Microphone Workaround"
|
||||||
description="Work around an issue that causes the microphone to be shared instead of the correct audio. Only enable if you're experiencing this issue."
|
description="Work around an issue that causes the microphone to be shared instead of the correct audio. Only enable if you're experiencing this issue."
|
||||||
@@ -455,78 +472,61 @@ function isSpecialSource(value?: AudioSource | AudioSources): value is SpecialSo
|
|||||||
return typeof value === "string";
|
return typeof value === "string";
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasMatchingProps(value: Node, other: Node) {
|
|
||||||
return Object.keys(value).every(key => value[key] === other[key]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapToAudioItem(node: AudioSource, granularSelect?: boolean, deviceSelect?: boolean): AudioItem[] {
|
function mapToAudioItem(node: AudioSource, granularSelect?: boolean, deviceSelect?: boolean): AudioItem[] {
|
||||||
if (isSpecialSource(node)) {
|
if (isSpecialSource(node)) {
|
||||||
return [{ name: node, value: node }];
|
return [{ name: node, value: node }];
|
||||||
}
|
}
|
||||||
|
|
||||||
const rtn: AudioItem[] = [];
|
|
||||||
|
|
||||||
const mediaClass = node["media.class"];
|
const mediaClass = node["media.class"];
|
||||||
|
|
||||||
if (mediaClass?.includes("Video") || mediaClass?.includes("Midi")) {
|
if (mediaClass?.includes("Video") || mediaClass?.includes("Midi")) {
|
||||||
return rtn;
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!deviceSelect && node["device.id"]) {
|
if (!deviceSelect && node["device.id"]) {
|
||||||
return rtn;
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const name = node["application.name"];
|
const preferred = ["application.name", "node.description", "node.name", "application.process.binary"] as const;
|
||||||
|
const prop = preferred.find(prop => node[prop]);
|
||||||
|
|
||||||
if (name) {
|
if (!prop) {
|
||||||
rtn.push({ name: name, value: { "application.name": name } });
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const name = node[prop]!;
|
||||||
|
const items: AudioItem[] = [{ name: name, value: { [prop]: name } }];
|
||||||
|
|
||||||
if (!granularSelect) {
|
if (!granularSelect) {
|
||||||
return rtn;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
const rawName = node["node.name"];
|
let granularName = name;
|
||||||
|
const granularProps: Node = { [prop]: name };
|
||||||
|
|
||||||
if (!name) {
|
const append = (name: string, brackets: string) => {
|
||||||
rtn.push({ name: rawName, value: { "node.name": rawName } });
|
const value = node[name];
|
||||||
}
|
|
||||||
|
|
||||||
const binary = node["application.process.binary"];
|
if (!value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!name && binary) {
|
granularName += ` ${brackets[0]}${value}${brackets[1]}`;
|
||||||
rtn.push({ name: binary, value: { "application.process.binary": binary } });
|
granularProps[name] = value;
|
||||||
}
|
};
|
||||||
|
|
||||||
const pid = node["application.process.id"];
|
append("application.process.id", "<>");
|
||||||
|
append("application.process.binary", "()");
|
||||||
|
append("media.name", "[]");
|
||||||
|
|
||||||
const first = rtn[0];
|
items.push({ name: granularName, value: granularProps });
|
||||||
const firstValues = first.value as Node;
|
|
||||||
|
|
||||||
if (pid) {
|
return items;
|
||||||
rtn.push({
|
}
|
||||||
name: `${first.name} (${pid})`,
|
|
||||||
value: { ...firstValues, "application.process.id": pid }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const mediaName = node["media.name"];
|
function hasMatchingProps(value: Node, other: Node) {
|
||||||
|
const keys = Object.keys(value);
|
||||||
if (mediaName) {
|
return keys.length === Object.keys(other).length && keys.every(key => value[key] === other[key]);
|
||||||
rtn.push({
|
|
||||||
name: `${first.name} [${mediaName}]`,
|
|
||||||
value: { ...firstValues, "media.name": mediaName }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mediaClass) {
|
|
||||||
rtn.push({
|
|
||||||
name: `${first.name} [${mediaClass}]`,
|
|
||||||
value: { ...firstValues, "media.class": mediaClass }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return rtn;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function isItemSelected(sources?: AudioSources) {
|
function isItemSelected(sources?: AudioSources) {
|
||||||
@@ -655,9 +655,10 @@ function AudioSourcePickerLinux({
|
|||||||
}))}
|
}))}
|
||||||
isSelected={isItemSelected(includeSources)}
|
isSelected={isItemSelected(includeSources)}
|
||||||
select={updateItems(setIncludeSources, includeSources)}
|
select={updateItems(setIncludeSources, includeSources)}
|
||||||
serialize={String}
|
serialize={JSON.stringify}
|
||||||
popoutPosition="top"
|
popoutPosition="top"
|
||||||
closeOnSelect={false}
|
closeOnSelect={false}
|
||||||
|
renderOptionLabel={o => o.label}
|
||||||
/>
|
/>
|
||||||
</SimpleErrorBoundary>
|
</SimpleErrorBoundary>
|
||||||
</section>
|
</section>
|
||||||
@@ -675,9 +676,10 @@ function AudioSourcePickerLinux({
|
|||||||
}))}
|
}))}
|
||||||
isSelected={isItemSelected(excludeSources)}
|
isSelected={isItemSelected(excludeSources)}
|
||||||
select={updateItems(setExcludeSources, excludeSources)}
|
select={updateItems(setExcludeSources, excludeSources)}
|
||||||
serialize={String}
|
serialize={JSON.stringify}
|
||||||
popoutPosition="top"
|
popoutPosition="top"
|
||||||
closeOnSelect={false}
|
closeOnSelect={false}
|
||||||
|
renderOptionLabel={o => o.label}
|
||||||
/>
|
/>
|
||||||
</SimpleErrorBoundary>
|
</SimpleErrorBoundary>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ export const enum IpcEvents {
|
|||||||
VIRT_MIC_LIST = "VCD_VIRT_MIC_LIST",
|
VIRT_MIC_LIST = "VCD_VIRT_MIC_LIST",
|
||||||
VIRT_MIC_START = "VCD_VIRT_MIC_START",
|
VIRT_MIC_START = "VCD_VIRT_MIC_START",
|
||||||
VIRT_MIC_START_SYSTEM = "VCD_VIRT_MIC_START_ALL",
|
VIRT_MIC_START_SYSTEM = "VCD_VIRT_MIC_START_ALL",
|
||||||
|
VIRT_MIC_UNMUTE = "VCD_VIRT_MIC_UNMUTE",
|
||||||
VIRT_MIC_STOP = "VCD_VIRT_MIC_STOP",
|
VIRT_MIC_STOP = "VCD_VIRT_MIC_STOP",
|
||||||
|
|
||||||
CLIPBOARD_COPY_IMAGE = "VCD_CLIPBOARD_COPY_IMAGE",
|
CLIPBOARD_COPY_IMAGE = "VCD_CLIPBOARD_COPY_IMAGE",
|
||||||
|
|||||||
Vendored
+1
@@ -48,6 +48,7 @@ export interface Settings {
|
|||||||
ignoreDevices?: boolean;
|
ignoreDevices?: boolean;
|
||||||
ignoreInputMedia?: boolean;
|
ignoreInputMedia?: boolean;
|
||||||
|
|
||||||
|
mute?: boolean;
|
||||||
onlySpeakers?: boolean;
|
onlySpeakers?: boolean;
|
||||||
onlyDefaultSpeakers?: boolean;
|
onlyDefaultSpeakers?: boolean;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user