mirror of https://github.com/jetkvm/kvm.git
[WIP] Updates: support in-process mode
This commit is contained in:
parent
0f16e0b11a
commit
9abb2aa026
|
|
@ -351,6 +351,12 @@ export interface SettingsState {
|
|||
setVideoBrightness: (value: number) => void;
|
||||
videoContrast: number;
|
||||
setVideoContrast: (value: number) => void;
|
||||
|
||||
// Audio settings
|
||||
audioOutputSource: string;
|
||||
audioMode: string;
|
||||
audioOutputEnabled: boolean;
|
||||
audioInputEnabled: boolean;
|
||||
}
|
||||
|
||||
export const useSettingsStore = create(
|
||||
|
|
@ -396,6 +402,12 @@ export const useSettingsStore = create(
|
|||
setVideoBrightness: (value: number) => set({ videoBrightness: value }),
|
||||
videoContrast: 1.0,
|
||||
setVideoContrast: (value: number) => set({ videoContrast: value }),
|
||||
|
||||
// Audio settings with defaults
|
||||
audioOutputSource: "usb",
|
||||
audioMode: "subprocess",
|
||||
audioOutputEnabled: true,
|
||||
audioInputEnabled: true,
|
||||
}),
|
||||
{
|
||||
name: "settings",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,174 @@
|
|||
import { useEffect } from "react";
|
||||
|
||||
import { SettingsItem } from "@components/SettingsItem";
|
||||
import { SettingsPageHeader } from "@components/SettingsPageheader";
|
||||
import { useSettingsStore } from "@/hooks/stores";
|
||||
import { JsonRpcResponse, useJsonRpc } from "@/hooks/useJsonRpc";
|
||||
import { SelectMenuBasic } from "@components/SelectMenuBasic";
|
||||
import Checkbox from "@components/Checkbox";
|
||||
|
||||
import notifications from "../notifications";
|
||||
|
||||
export default function SettingsAudioRoute() {
|
||||
const { send } = useJsonRpc();
|
||||
const settings = useSettingsStore();
|
||||
|
||||
// Fetch current audio settings on mount
|
||||
useEffect(() => {
|
||||
send("getAudioOutputSource", {}, (resp: JsonRpcResponse) => {
|
||||
if ("error" in resp) {
|
||||
return;
|
||||
}
|
||||
const source = resp.result as string;
|
||||
settings.audioOutputSource = source;
|
||||
});
|
||||
|
||||
send("getAudioMode", {}, (resp: JsonRpcResponse) => {
|
||||
if ("error" in resp) {
|
||||
return;
|
||||
}
|
||||
const mode = resp.result as string;
|
||||
settings.audioMode = mode;
|
||||
});
|
||||
|
||||
send("getAudioOutputEnabled", {}, (resp: JsonRpcResponse) => {
|
||||
if ("error" in resp) {
|
||||
return;
|
||||
}
|
||||
settings.audioOutputEnabled = resp.result as boolean;
|
||||
});
|
||||
|
||||
send("getAudioInputEnabled", {}, (resp: JsonRpcResponse) => {
|
||||
if ("error" in resp) {
|
||||
return;
|
||||
}
|
||||
settings.audioInputEnabled = resp.result as boolean;
|
||||
});
|
||||
}, [send]);
|
||||
|
||||
const handleAudioOutputSourceChange = (source: string) => {
|
||||
send("setAudioOutputSource", { params: { source } }, (resp: JsonRpcResponse) => {
|
||||
if ("error" in resp) {
|
||||
notifications.error(
|
||||
`Failed to set audio output source: ${resp.error.data || "Unknown error"}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
settings.audioOutputSource = source;
|
||||
notifications.success("Audio output source updated successfully");
|
||||
});
|
||||
};
|
||||
|
||||
const handleAudioModeChange = (mode: string) => {
|
||||
send("setAudioMode", { params: { mode } }, (resp: JsonRpcResponse) => {
|
||||
if ("error" in resp) {
|
||||
notifications.error(
|
||||
`Failed to set audio mode: ${resp.error.data || "Unknown error"}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
settings.audioMode = mode;
|
||||
notifications.success("Audio mode updated successfully. Changes will take effect on next connection.");
|
||||
});
|
||||
};
|
||||
|
||||
const handleAudioOutputEnabledChange = (enabled: boolean) => {
|
||||
send("setAudioOutputEnabled", { params: { enabled } }, (resp: JsonRpcResponse) => {
|
||||
if ("error" in resp) {
|
||||
notifications.error(
|
||||
`Failed to ${enabled ? "enable" : "disable"} audio output: ${resp.error.data || "Unknown error"}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
settings.audioOutputEnabled = enabled;
|
||||
notifications.success(`Audio output ${enabled ? "enabled" : "disabled"} successfully`);
|
||||
});
|
||||
};
|
||||
|
||||
const handleAudioInputEnabledChange = (enabled: boolean) => {
|
||||
send("setAudioInputEnabled", { params: { enabled } }, (resp: JsonRpcResponse) => {
|
||||
if ("error" in resp) {
|
||||
notifications.error(
|
||||
`Failed to ${enabled ? "enable" : "disable"} audio input: ${resp.error.data || "Unknown error"}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
settings.audioInputEnabled = enabled;
|
||||
notifications.success(`Audio input ${enabled ? "enabled" : "disabled"} successfully`);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<SettingsPageHeader
|
||||
title="Audio"
|
||||
description="Configure audio input and output settings for your JetKVM device"
|
||||
/>
|
||||
<div className="space-y-4">
|
||||
<SettingsItem
|
||||
title="Audio Output"
|
||||
description="Enable or disable audio from the remote computer"
|
||||
>
|
||||
<Checkbox
|
||||
checked={settings.audioOutputEnabled || false}
|
||||
onChange={(e) => handleAudioOutputEnabledChange(e.target.checked)}
|
||||
/>
|
||||
</SettingsItem>
|
||||
|
||||
{settings.audioOutputEnabled && (
|
||||
<SettingsItem
|
||||
title="Audio Output Source"
|
||||
description="Select the audio capture device (HDMI or USB)"
|
||||
>
|
||||
<SelectMenuBasic
|
||||
size="SM"
|
||||
label=""
|
||||
value={settings.audioOutputSource || "usb"}
|
||||
options={[
|
||||
{ value: "hdmi", label: "HDMI" },
|
||||
{ value: "usb", label: "USB" },
|
||||
]}
|
||||
onChange={e => {
|
||||
handleAudioOutputSourceChange(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</SettingsItem>
|
||||
)}
|
||||
|
||||
<SettingsItem
|
||||
title="Audio Input"
|
||||
description="Enable or disable microphone audio to the remote computer"
|
||||
>
|
||||
<Checkbox
|
||||
checked={settings.audioInputEnabled || false}
|
||||
onChange={(e) => handleAudioInputEnabledChange(e.target.checked)}
|
||||
/>
|
||||
</SettingsItem>
|
||||
|
||||
<div className="border-t border-slate-200 pt-4 dark:border-slate-700">
|
||||
<h3 className="mb-2 text-sm font-medium">Advanced</h3>
|
||||
<SettingsItem
|
||||
title="Audio Processing Mode"
|
||||
description="In-process mode uses less CPU but subprocess mode provides better isolation"
|
||||
>
|
||||
<SelectMenuBasic
|
||||
size="SM"
|
||||
label=""
|
||||
value={settings.audioMode || "subprocess"}
|
||||
options={[
|
||||
{ value: "subprocess", label: "Subprocess (Recommended)" },
|
||||
{ value: "in-process", label: "In-Process" },
|
||||
]}
|
||||
onChange={e => {
|
||||
handleAudioModeChange(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</SettingsItem>
|
||||
<p className="mt-2 text-xs text-slate-600 dark:text-slate-400">
|
||||
Changing the audio mode will take effect when the next WebRTC connection is established.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import {
|
|||
LuMouse,
|
||||
LuKeyboard,
|
||||
LuVideo,
|
||||
LuVolume2,
|
||||
LuCpu,
|
||||
LuShieldCheck,
|
||||
LuWrench,
|
||||
|
|
@ -168,6 +169,17 @@ export default function SettingsRoute() {
|
|||
</div>
|
||||
</NavLink>
|
||||
</div>
|
||||
<div className="shrink-0">
|
||||
<NavLink
|
||||
to="audio"
|
||||
className={({ isActive }) => (isActive ? "active" : "")}
|
||||
>
|
||||
<div className="flex items-center gap-x-2 rounded-md px-2.5 py-2.5 text-sm transition-colors hover:bg-slate-100 dark:hover:bg-slate-700 in-[.active]:bg-blue-50 in-[.active]:text-blue-700! md:in-[.active]:bg-transparent dark:in-[.active]:bg-blue-900 dark:in-[.active]:text-blue-200! dark:md:in-[.active]:bg-transparent">
|
||||
<LuVolume2 className="h-4 w-4 shrink-0" />
|
||||
<h1>Audio</h1>
|
||||
</div>
|
||||
</NavLink>
|
||||
</div>
|
||||
<div className="shrink-0">
|
||||
<NavLink
|
||||
to="hardware"
|
||||
|
|
|
|||
Loading…
Reference in New Issue