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:
Alex P 2025-11-21 01:33:38 +02:00
parent 584b9fe3bf
commit 1dfb4ab77f
2 changed files with 21 additions and 17 deletions

View File

@ -1000,7 +1000,7 @@ func rpcGetAudioConfig() (AudioConfigResponse, error) {
}, 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()
if bitrate < 64 || bitrate > 256 {
@ -1012,6 +1012,10 @@ func rpcSetAudioConfig(bitrate int, complexity int, dtxEnabled bool, fecEnabled
if bufferPeriods < 2 || bufferPeriods > 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 {
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.AudioFECEnabled = fecEnabled
config.AudioBufferPeriods = bufferPeriods
config.AudioSampleRate = sampleRate
config.AudioPacketLossPerc = packetLossPerc
return SaveConfig()
@ -1375,7 +1380,7 @@ var rpcHandlers = map[string]RPCHandler{
"setAudioOutputSource": {Func: rpcSetAudioOutputSource, Params: []string{"source"}},
"refreshHdmiConnection": {Func: rpcRefreshHdmiConnection},
"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},
"getAudioInputAutoEnable": {Func: rpcGetAudioInputAutoEnable},
"setAudioInputAutoEnable": {Func: rpcSetAudioInputAutoEnable, Params: []string{"enabled"}},

View File

@ -144,6 +144,7 @@ export default function SettingsAudioRoute() {
dtxEnabled: audioDTXEnabled,
fecEnabled: audioFECEnabled,
bufferPeriods: audioBufferPeriods,
sampleRate: audioSampleRate,
packetLossPerc: audioPacketLossPerc,
});
@ -153,12 +154,12 @@ export default function SettingsAudioRoute() {
send("setAudioConfig", config, (resp: JsonRpcResponse) => {
if (handleRpcError(resp)) return;
// Update all state values from the config
setAudioBitrate(config.bitrate);
setAudioComplexity(config.complexity);
setAudioDTXEnabled(config.dtxEnabled);
setAudioFECEnabled(config.fecEnabled);
setAudioBufferPeriods(config.bufferPeriods);
setAudioSampleRate(config.sampleRate);
setAudioPacketLossPerc(config.packetLossPerc);
notifications.success(m.audio_settings_config_updated());
});
@ -292,20 +293,18 @@ export default function SettingsAudioRoute() {
title={m.audio_settings_sample_rate_title()}
description={m.audio_settings_sample_rate_description()}
>
<div className="text-sm text-gray-700 dark:text-gray-300 font-medium">
{(() => {
const rateMap: Record<number, string> = {
32000: "32 kHz",
44100: "44.1 kHz",
48000: "48 kHz",
96000: "96 kHz"
};
return rateMap[audioSampleRate] || `${audioSampleRate} Hz`;
})()}
<span className="text-xs text-gray-500 dark:text-gray-400 ml-2">
(auto-detected from source)
</span>
</div>
<SelectMenuBasic
size="SM"
value={String(audioSampleRate)}
options={[
{ value: "8000", label: "8 kHz" },
{ value: "12000", label: "12 kHz" },
{ value: "16000", label: "16 kHz" },
{ value: "24000", label: "24 kHz" },
{ value: "48000", label: "48 kHz (default)" },
]}
onChange={(e) => handleAudioConfigChange({ sampleRate: parseInt(e.target.value) })}
/>
</SettingsItem>
<SettingsItem