mirror of https://github.com/jetkvm/kvm.git
Make audio sample rate user-configurable
- Add sample rate dropdown in UI with Opus-supported rates (8k/12k/16k/24k/48kHz) - Add sampleRate parameter to setAudioConfig RPC handler - Validate sample rate is one of the 5 Opus-compatible values - Configuration takes effect on next audio restart (Apply button)
This commit is contained in:
parent
584b9fe3bf
commit
1dfb4ab77f
|
|
@ -1000,7 +1000,7 @@ func rpcGetAudioConfig() (AudioConfigResponse, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func rpcSetAudioConfig(bitrate int, complexity int, dtxEnabled bool, fecEnabled bool, bufferPeriods int, packetLossPerc int) error {
|
func rpcSetAudioConfig(bitrate int, complexity int, dtxEnabled bool, fecEnabled bool, bufferPeriods int, sampleRate int, packetLossPerc int) error {
|
||||||
ensureConfigLoaded()
|
ensureConfigLoaded()
|
||||||
|
|
||||||
if bitrate < 64 || bitrate > 256 {
|
if bitrate < 64 || bitrate > 256 {
|
||||||
|
|
@ -1012,6 +1012,10 @@ func rpcSetAudioConfig(bitrate int, complexity int, dtxEnabled bool, fecEnabled
|
||||||
if bufferPeriods < 2 || bufferPeriods > 24 {
|
if bufferPeriods < 2 || bufferPeriods > 24 {
|
||||||
return fmt.Errorf("buffer periods must be between 2 and 24")
|
return fmt.Errorf("buffer periods must be between 2 and 24")
|
||||||
}
|
}
|
||||||
|
validSampleRates := map[int]bool{8000: true, 12000: true, 16000: true, 24000: true, 48000: true}
|
||||||
|
if !validSampleRates[sampleRate] {
|
||||||
|
return fmt.Errorf("sample rate must be one of: 8000, 12000, 16000, 24000, 48000 Hz")
|
||||||
|
}
|
||||||
if packetLossPerc < 0 || packetLossPerc > 100 {
|
if packetLossPerc < 0 || packetLossPerc > 100 {
|
||||||
return fmt.Errorf("packet loss percentage must be between 0 and 100")
|
return fmt.Errorf("packet loss percentage must be between 0 and 100")
|
||||||
}
|
}
|
||||||
|
|
@ -1021,6 +1025,7 @@ func rpcSetAudioConfig(bitrate int, complexity int, dtxEnabled bool, fecEnabled
|
||||||
config.AudioDTXEnabled = dtxEnabled
|
config.AudioDTXEnabled = dtxEnabled
|
||||||
config.AudioFECEnabled = fecEnabled
|
config.AudioFECEnabled = fecEnabled
|
||||||
config.AudioBufferPeriods = bufferPeriods
|
config.AudioBufferPeriods = bufferPeriods
|
||||||
|
config.AudioSampleRate = sampleRate
|
||||||
config.AudioPacketLossPerc = packetLossPerc
|
config.AudioPacketLossPerc = packetLossPerc
|
||||||
|
|
||||||
return SaveConfig()
|
return SaveConfig()
|
||||||
|
|
@ -1375,7 +1380,7 @@ var rpcHandlers = map[string]RPCHandler{
|
||||||
"setAudioOutputSource": {Func: rpcSetAudioOutputSource, Params: []string{"source"}},
|
"setAudioOutputSource": {Func: rpcSetAudioOutputSource, Params: []string{"source"}},
|
||||||
"refreshHdmiConnection": {Func: rpcRefreshHdmiConnection},
|
"refreshHdmiConnection": {Func: rpcRefreshHdmiConnection},
|
||||||
"getAudioConfig": {Func: rpcGetAudioConfig},
|
"getAudioConfig": {Func: rpcGetAudioConfig},
|
||||||
"setAudioConfig": {Func: rpcSetAudioConfig, Params: []string{"bitrate", "complexity", "dtxEnabled", "fecEnabled", "bufferPeriods", "packetLossPerc"}},
|
"setAudioConfig": {Func: rpcSetAudioConfig, Params: []string{"bitrate", "complexity", "dtxEnabled", "fecEnabled", "bufferPeriods", "sampleRate", "packetLossPerc"}},
|
||||||
"restartAudioOutput": {Func: rpcRestartAudioOutput},
|
"restartAudioOutput": {Func: rpcRestartAudioOutput},
|
||||||
"getAudioInputAutoEnable": {Func: rpcGetAudioInputAutoEnable},
|
"getAudioInputAutoEnable": {Func: rpcGetAudioInputAutoEnable},
|
||||||
"setAudioInputAutoEnable": {Func: rpcSetAudioInputAutoEnable, Params: []string{"enabled"}},
|
"setAudioInputAutoEnable": {Func: rpcSetAudioInputAutoEnable, Params: []string{"enabled"}},
|
||||||
|
|
|
||||||
|
|
@ -144,6 +144,7 @@ export default function SettingsAudioRoute() {
|
||||||
dtxEnabled: audioDTXEnabled,
|
dtxEnabled: audioDTXEnabled,
|
||||||
fecEnabled: audioFECEnabled,
|
fecEnabled: audioFECEnabled,
|
||||||
bufferPeriods: audioBufferPeriods,
|
bufferPeriods: audioBufferPeriods,
|
||||||
|
sampleRate: audioSampleRate,
|
||||||
packetLossPerc: audioPacketLossPerc,
|
packetLossPerc: audioPacketLossPerc,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -153,12 +154,12 @@ export default function SettingsAudioRoute() {
|
||||||
send("setAudioConfig", config, (resp: JsonRpcResponse) => {
|
send("setAudioConfig", config, (resp: JsonRpcResponse) => {
|
||||||
if (handleRpcError(resp)) return;
|
if (handleRpcError(resp)) return;
|
||||||
|
|
||||||
// Update all state values from the config
|
|
||||||
setAudioBitrate(config.bitrate);
|
setAudioBitrate(config.bitrate);
|
||||||
setAudioComplexity(config.complexity);
|
setAudioComplexity(config.complexity);
|
||||||
setAudioDTXEnabled(config.dtxEnabled);
|
setAudioDTXEnabled(config.dtxEnabled);
|
||||||
setAudioFECEnabled(config.fecEnabled);
|
setAudioFECEnabled(config.fecEnabled);
|
||||||
setAudioBufferPeriods(config.bufferPeriods);
|
setAudioBufferPeriods(config.bufferPeriods);
|
||||||
|
setAudioSampleRate(config.sampleRate);
|
||||||
setAudioPacketLossPerc(config.packetLossPerc);
|
setAudioPacketLossPerc(config.packetLossPerc);
|
||||||
notifications.success(m.audio_settings_config_updated());
|
notifications.success(m.audio_settings_config_updated());
|
||||||
});
|
});
|
||||||
|
|
@ -292,20 +293,18 @@ export default function SettingsAudioRoute() {
|
||||||
title={m.audio_settings_sample_rate_title()}
|
title={m.audio_settings_sample_rate_title()}
|
||||||
description={m.audio_settings_sample_rate_description()}
|
description={m.audio_settings_sample_rate_description()}
|
||||||
>
|
>
|
||||||
<div className="text-sm text-gray-700 dark:text-gray-300 font-medium">
|
<SelectMenuBasic
|
||||||
{(() => {
|
size="SM"
|
||||||
const rateMap: Record<number, string> = {
|
value={String(audioSampleRate)}
|
||||||
32000: "32 kHz",
|
options={[
|
||||||
44100: "44.1 kHz",
|
{ value: "8000", label: "8 kHz" },
|
||||||
48000: "48 kHz",
|
{ value: "12000", label: "12 kHz" },
|
||||||
96000: "96 kHz"
|
{ value: "16000", label: "16 kHz" },
|
||||||
};
|
{ value: "24000", label: "24 kHz" },
|
||||||
return rateMap[audioSampleRate] || `${audioSampleRate} Hz`;
|
{ value: "48000", label: "48 kHz (default)" },
|
||||||
})()}
|
]}
|
||||||
<span className="text-xs text-gray-500 dark:text-gray-400 ml-2">
|
onChange={(e) => handleAudioConfigChange({ sampleRate: parseInt(e.target.value) })}
|
||||||
(auto-detected from source)
|
/>
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</SettingsItem>
|
</SettingsItem>
|
||||||
|
|
||||||
<SettingsItem
|
<SettingsItem
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue