Change: make sample rate read-only and auto-detected

The sample rate cannot be configured by users - it's determined by the audio
source (HDMI device or USB gadget client). The previous UI gave the false
impression that users could select a sample rate, but the value was always
overridden by hardware detection.

Changes:
- Convert sample rate UI from dropdown to read-only display
- Show "(auto-detected from source)" label next to the value
- Remove sampleRate parameter from setAudioConfig RPC
- Update translations to clarify auto-detection
- Backend sample rate validation remains for backwards compatibility

The C code now automatically detects and adapts to whatever rate the hardware
supports, creating the Opus encoder/decoder with matching parameters to
eliminate pitch/speed distortion.
This commit is contained in:
Alex P 2025-11-18 00:16:32 +02:00
parent 236291a454
commit 9c57fe86c4
11 changed files with 22 additions and 45 deletions

View File

@ -1078,7 +1078,7 @@ func rpcGetAudioConfig() (AudioConfigResponse, error) {
}, nil }, nil
} }
func rpcSetAudioConfig(bitrate int, complexity int, dtxEnabled bool, fecEnabled bool, bufferPeriods int, sampleRate int, packetLossPerc int) error { func rpcSetAudioConfig(bitrate int, complexity int, dtxEnabled bool, fecEnabled bool, bufferPeriods int, packetLossPerc int) error {
ensureConfigLoaded() ensureConfigLoaded()
if bitrate < 64 || bitrate > 256 { if bitrate < 64 || bitrate > 256 {
@ -1090,9 +1090,6 @@ 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")
} }
if sampleRate != 32000 && sampleRate != 44100 && sampleRate != 48000 && sampleRate != 96000 {
return fmt.Errorf("sample rate must be 32000, 44100, 48000, or 96000 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")
} }
@ -1102,7 +1099,6 @@ 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()
@ -1454,7 +1450,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", "sampleRate", "packetLossPerc"}}, "setAudioConfig": {Func: rpcSetAudioConfig, Params: []string{"bitrate", "complexity", "dtxEnabled", "fecEnabled", "bufferPeriods", "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"}},

View File

@ -89,7 +89,7 @@
"audio_settings_buffer_title": "Bufferperioder", "audio_settings_buffer_title": "Bufferperioder",
"audio_settings_buffer_description": "ALSA bufferstørrelse (højere = mere stabil, mere latens)", "audio_settings_buffer_description": "ALSA bufferstørrelse (højere = mere stabil, mere latens)",
"audio_settings_sample_rate_title": "Samplingsrate", "audio_settings_sample_rate_title": "Samplingsrate",
"audio_settings_sample_rate_description": "Lydsamplingsfrekven (match HDMI-kilde for bedste kvalitet)", "audio_settings_sample_rate_description": "Audio sampling frequency (automatically detected from source)",
"audio_settings_packet_loss_title": "Pakketabskompensation", "audio_settings_packet_loss_title": "Pakketabskompensation",
"audio_settings_packet_loss_description": "FEC overhead-procent (højere = bedre gendannelse, mere båndbredde)", "audio_settings_packet_loss_description": "FEC overhead-procent (højere = bedre gendannelse, mere båndbredde)",
"audio_settings_config_updated": "Lydkonfiguration opdateret", "audio_settings_config_updated": "Lydkonfiguration opdateret",

View File

@ -89,7 +89,7 @@
"audio_settings_buffer_title": "Pufferperioden", "audio_settings_buffer_title": "Pufferperioden",
"audio_settings_buffer_description": "ALSA-Puffergröße (höher = stabiler, mehr Latenz)", "audio_settings_buffer_description": "ALSA-Puffergröße (höher = stabiler, mehr Latenz)",
"audio_settings_sample_rate_title": "Abtastrate", "audio_settings_sample_rate_title": "Abtastrate",
"audio_settings_sample_rate_description": "Audio-Abtastfrequenz (HDMI-Quelle anpassen für beste Qualität)", "audio_settings_sample_rate_description": "Audio sampling frequency (automatically detected from source)",
"audio_settings_packet_loss_title": "Paketverlust-Kompensation", "audio_settings_packet_loss_title": "Paketverlust-Kompensation",
"audio_settings_packet_loss_description": "FEC-Overhead-Prozentsatz (höher = bessere Wiederherstellung, mehr Bandbreite)", "audio_settings_packet_loss_description": "FEC-Overhead-Prozentsatz (höher = bessere Wiederherstellung, mehr Bandbreite)",
"audio_settings_config_updated": "Audiokonfiguration aktualisiert", "audio_settings_config_updated": "Audiokonfiguration aktualisiert",

View File

@ -89,7 +89,7 @@
"audio_settings_buffer_title": "Buffer Periods", "audio_settings_buffer_title": "Buffer Periods",
"audio_settings_buffer_description": "ALSA buffer size (higher = more stable, more latency)", "audio_settings_buffer_description": "ALSA buffer size (higher = more stable, more latency)",
"audio_settings_sample_rate_title": "Sample Rate", "audio_settings_sample_rate_title": "Sample Rate",
"audio_settings_sample_rate_description": "Audio sampling frequency (match HDMI source for best quality)", "audio_settings_sample_rate_description": "Audio sampling frequency (automatically detected from source)",
"audio_settings_packet_loss_title": "Packet Loss Compensation", "audio_settings_packet_loss_title": "Packet Loss Compensation",
"audio_settings_packet_loss_description": "FEC overhead percentage (higher = better recovery, more bandwidth)", "audio_settings_packet_loss_description": "FEC overhead percentage (higher = better recovery, more bandwidth)",
"audio_settings_config_updated": "Audio configuration updated", "audio_settings_config_updated": "Audio configuration updated",

View File

@ -89,7 +89,7 @@
"audio_settings_buffer_title": "Períodos de Buffer", "audio_settings_buffer_title": "Períodos de Buffer",
"audio_settings_buffer_description": "Tamaño del buffer ALSA (mayor = más estable, más latencia)", "audio_settings_buffer_description": "Tamaño del buffer ALSA (mayor = más estable, más latencia)",
"audio_settings_sample_rate_title": "Tasa de Muestreo", "audio_settings_sample_rate_title": "Tasa de Muestreo",
"audio_settings_sample_rate_description": "Frecuencia de muestreo de audio (coincidir con fuente HDMI para mejor calidad)", "audio_settings_sample_rate_description": "Audio sampling frequency (automatically detected from source)",
"audio_settings_packet_loss_title": "Compensación de Pérdida de Paquetes", "audio_settings_packet_loss_title": "Compensación de Pérdida de Paquetes",
"audio_settings_packet_loss_description": "Porcentaje de sobrecarga FEC (mayor = mejor recuperación, más ancho de banda)", "audio_settings_packet_loss_description": "Porcentaje de sobrecarga FEC (mayor = mejor recuperación, más ancho de banda)",
"audio_settings_config_updated": "Configuración de audio actualizada", "audio_settings_config_updated": "Configuración de audio actualizada",

View File

@ -89,7 +89,7 @@
"audio_settings_buffer_title": "Périodes de Tampon", "audio_settings_buffer_title": "Périodes de Tampon",
"audio_settings_buffer_description": "Taille du tampon ALSA (plus élevé = plus stable, plus de latence)", "audio_settings_buffer_description": "Taille du tampon ALSA (plus élevé = plus stable, plus de latence)",
"audio_settings_sample_rate_title": "Fréquence d'Échantillonnage", "audio_settings_sample_rate_title": "Fréquence d'Échantillonnage",
"audio_settings_sample_rate_description": "Fréquence d'échantillonnage audio (correspondre à la source HDMI pour une meilleure qualité)", "audio_settings_sample_rate_description": "Audio sampling frequency (automatically detected from source)",
"audio_settings_packet_loss_title": "Compensation de Perte de Paquets", "audio_settings_packet_loss_title": "Compensation de Perte de Paquets",
"audio_settings_packet_loss_description": "Pourcentage de surcharge FEC (plus élevé = meilleure récupération, plus de bande passante)", "audio_settings_packet_loss_description": "Pourcentage de surcharge FEC (plus élevé = meilleure récupération, plus de bande passante)",
"audio_settings_config_updated": "Configuration audio mise à jour", "audio_settings_config_updated": "Configuration audio mise à jour",

View File

@ -89,7 +89,7 @@
"audio_settings_buffer_title": "Periodi Buffer", "audio_settings_buffer_title": "Periodi Buffer",
"audio_settings_buffer_description": "Dimensione buffer ALSA (più alto = più stabile, più latenza)", "audio_settings_buffer_description": "Dimensione buffer ALSA (più alto = più stabile, più latenza)",
"audio_settings_sample_rate_title": "Frequenza di Campionamento", "audio_settings_sample_rate_title": "Frequenza di Campionamento",
"audio_settings_sample_rate_description": "Frequenza di campionamento audio (abbinare alla sorgente HDMI per la migliore qualità)", "audio_settings_sample_rate_description": "Audio sampling frequency (automatically detected from source)",
"audio_settings_packet_loss_title": "Compensazione Perdita Pacchetti", "audio_settings_packet_loss_title": "Compensazione Perdita Pacchetti",
"audio_settings_packet_loss_description": "Percentuale overhead FEC (più alto = migliore recupero, più banda)", "audio_settings_packet_loss_description": "Percentuale overhead FEC (più alto = migliore recupero, più banda)",
"audio_settings_config_updated": "Configurazione audio aggiornata", "audio_settings_config_updated": "Configurazione audio aggiornata",

View File

@ -89,7 +89,7 @@
"audio_settings_buffer_title": "Bufferperioder", "audio_settings_buffer_title": "Bufferperioder",
"audio_settings_buffer_description": "ALSA bufferstørrelse (høyere = mer stabil, mer latens)", "audio_settings_buffer_description": "ALSA bufferstørrelse (høyere = mer stabil, mer latens)",
"audio_settings_sample_rate_title": "Samplingsrate", "audio_settings_sample_rate_title": "Samplingsrate",
"audio_settings_sample_rate_description": "Lydsampleringsfrekvens (match HDMI-kilde for beste kvalitet)", "audio_settings_sample_rate_description": "Audio sampling frequency (automatically detected from source)",
"audio_settings_packet_loss_title": "Pakketapskompensasjon", "audio_settings_packet_loss_title": "Pakketapskompensasjon",
"audio_settings_packet_loss_description": "FEC overhead-prosent (høyere = bedre gjenoppretting, mer båndbredde)", "audio_settings_packet_loss_description": "FEC overhead-prosent (høyere = bedre gjenoppretting, mer båndbredde)",
"audio_settings_config_updated": "Lydkonfigurasjon oppdatert", "audio_settings_config_updated": "Lydkonfigurasjon oppdatert",

View File

@ -89,7 +89,7 @@
"audio_settings_buffer_title": "Bufferperioder", "audio_settings_buffer_title": "Bufferperioder",
"audio_settings_buffer_description": "ALSA bufferstorlek (högre = mer stabil, mer latens)", "audio_settings_buffer_description": "ALSA bufferstorlek (högre = mer stabil, mer latens)",
"audio_settings_sample_rate_title": "Samplingsfrekvens", "audio_settings_sample_rate_title": "Samplingsfrekvens",
"audio_settings_sample_rate_description": "Ljudsamplingsfrekvens (matcha HDMI-källa för bästa kvalitet)", "audio_settings_sample_rate_description": "Audio sampling frequency (automatically detected from source)",
"audio_settings_packet_loss_title": "Paketförlustkompensation", "audio_settings_packet_loss_title": "Paketförlustkompensation",
"audio_settings_packet_loss_description": "FEC overhead-procent (högre = bättre återställning, mer bandbredd)", "audio_settings_packet_loss_description": "FEC overhead-procent (högre = bättre återställning, mer bandbredd)",
"audio_settings_config_updated": "Ljudkonfiguration uppdaterad", "audio_settings_config_updated": "Ljudkonfiguration uppdaterad",

View File

@ -89,7 +89,7 @@
"audio_settings_buffer_title": "缓冲周期", "audio_settings_buffer_title": "缓冲周期",
"audio_settings_buffer_description": "ALSA 缓冲大小(越高 = 越稳定,延迟越高)", "audio_settings_buffer_description": "ALSA 缓冲大小(越高 = 越稳定,延迟越高)",
"audio_settings_sample_rate_title": "采样率", "audio_settings_sample_rate_title": "采样率",
"audio_settings_sample_rate_description": "音频采样频率(匹配 HDMI 源以获得最佳质量)", "audio_settings_sample_rate_description": "Audio sampling frequency (automatically detected from source)",
"audio_settings_packet_loss_title": "丢包补偿", "audio_settings_packet_loss_title": "丢包补偿",
"audio_settings_packet_loss_description": "FEC 开销百分比(越高 = 恢复越好,带宽越大)", "audio_settings_packet_loss_description": "FEC 开销百分比(越高 = 恢复越好,带宽越大)",
"audio_settings_config_updated": "音频配置已更新", "audio_settings_config_updated": "音频配置已更新",

View File

@ -120,12 +120,11 @@ export default function SettingsAudioRoute() {
dtxEnabled: boolean, dtxEnabled: boolean,
fecEnabled: boolean, fecEnabled: boolean,
bufferPeriods: number, bufferPeriods: number,
sampleRate: number,
packetLossPerc: number packetLossPerc: number
) => { ) => {
send( send(
"setAudioConfig", "setAudioConfig",
{ bitrate, complexity, dtxEnabled, fecEnabled, bufferPeriods, sampleRate, packetLossPerc }, { bitrate, complexity, dtxEnabled, fecEnabled, bufferPeriods, packetLossPerc },
(resp: JsonRpcResponse) => { (resp: JsonRpcResponse) => {
if ("error" in resp) { if ("error" in resp) {
notifications.error(String(resp.error.data || m.unknown_error())); notifications.error(String(resp.error.data || m.unknown_error()));
@ -136,7 +135,6 @@ export default function SettingsAudioRoute() {
setAudioDTXEnabled(dtxEnabled); setAudioDTXEnabled(dtxEnabled);
setAudioFECEnabled(fecEnabled); setAudioFECEnabled(fecEnabled);
setAudioBufferPeriods(bufferPeriods); setAudioBufferPeriods(bufferPeriods);
setAudioSampleRate(sampleRate);
setAudioPacketLossPerc(packetLossPerc); setAudioPacketLossPerc(packetLossPerc);
notifications.success(m.audio_settings_config_updated()); notifications.success(m.audio_settings_config_updated());
} }
@ -217,7 +215,6 @@ export default function SettingsAudioRoute() {
audioDTXEnabled, audioDTXEnabled,
audioFECEnabled, audioFECEnabled,
audioBufferPeriods, audioBufferPeriods,
audioSampleRate,
audioPacketLossPerc audioPacketLossPerc
) )
} }
@ -245,7 +242,6 @@ export default function SettingsAudioRoute() {
audioDTXEnabled, audioDTXEnabled,
audioFECEnabled, audioFECEnabled,
audioBufferPeriods, audioBufferPeriods,
audioSampleRate,
audioPacketLossPerc audioPacketLossPerc
) )
} }
@ -265,7 +261,6 @@ export default function SettingsAudioRoute() {
e.target.checked, e.target.checked,
audioFECEnabled, audioFECEnabled,
audioBufferPeriods, audioBufferPeriods,
audioSampleRate,
audioPacketLossPerc audioPacketLossPerc
) )
} }
@ -285,7 +280,6 @@ export default function SettingsAudioRoute() {
audioDTXEnabled, audioDTXEnabled,
e.target.checked, e.target.checked,
audioBufferPeriods, audioBufferPeriods,
audioSampleRate,
audioPacketLossPerc audioPacketLossPerc
) )
} }
@ -313,7 +307,6 @@ export default function SettingsAudioRoute() {
audioDTXEnabled, audioDTXEnabled,
audioFECEnabled, audioFECEnabled,
parseInt(e.target.value), parseInt(e.target.value),
audioSampleRate,
audioPacketLossPerc audioPacketLossPerc
) )
} }
@ -324,27 +317,16 @@ 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()}
> >
<SelectMenuBasic <div className="text-sm text-gray-700 dark:text-gray-300 font-medium">
size="SM" {audioSampleRate === 32000 && "32 kHz"}
value={String(audioSampleRate)} {audioSampleRate === 44100 && "44.1 kHz"}
options={[ {audioSampleRate === 48000 && "48 kHz"}
{ value: "32000", label: "32 kHz" }, {audioSampleRate === 96000 && "96 kHz"}
{ value: "44100", label: "44.1 kHz" }, {![32000, 44100, 48000, 96000].includes(audioSampleRate) && `${audioSampleRate} Hz`}
{ value: "48000", label: "48 kHz (default)" }, <span className="text-xs text-gray-500 dark:text-gray-400 ml-2">
{ value: "96000", label: "96 kHz" }, (auto-detected from source)
]} </span>
onChange={(e) => </div>
handleAudioConfigChange(
audioBitrate,
audioComplexity,
audioDTXEnabled,
audioFECEnabled,
audioBufferPeriods,
parseInt(e.target.value),
audioPacketLossPerc
)
}
/>
</SettingsItem> </SettingsItem>
<SettingsItem <SettingsItem
@ -370,7 +352,6 @@ export default function SettingsAudioRoute() {
audioDTXEnabled, audioDTXEnabled,
audioFECEnabled, audioFECEnabled,
audioBufferPeriods, audioBufferPeriods,
audioSampleRate,
parseInt(e.target.value) parseInt(e.target.value)
) )
} }