From 11dadebb93186eefe01940a567405e056e0569c9 Mon Sep 17 00:00:00 2001 From: Alex P Date: Mon, 17 Nov 2025 23:56:24 +0200 Subject: [PATCH] Fix: improve EDID compatibility and add audio configuration options - Update default EDID with registered manufacturer ID (Dell) and proper 24-inch display dimensions (52x32cm) for better macOS/OS compatibility - Add configurable sample rate (32/44.1/48/96 kHz) to support different HDMI audio sources - Add packet loss compensation percentage control for FEC overhead tuning - Fix config migration to ensure new audio parameters get defaults for existing configs - Update all language translations for new audio settings --- audio.go | 6 ++ config.go | 19 +++- internal/audio/c/audio.c | 5 +- internal/audio/cgo_source.go | 7 +- internal/audio/source.go | 24 ++--- internal/native/video.go | 3 +- jsonrpc.go | 44 ++++++--- ui/localization/messages/da.json | 4 + ui/localization/messages/de.json | 4 + ui/localization/messages/en.json | 4 + ui/localization/messages/es.json | 4 + ui/localization/messages/fr.json | 4 + ui/localization/messages/it.json | 4 + ui/localization/messages/nb.json | 4 + ui/localization/messages/sv.json | 4 + ui/localization/messages/zh.json | 4 + ui/src/hooks/stores.ts | 8 ++ ui/src/routes/devices.$id.settings.audio.tsx | 93 ++++++++++++++++++-- ui/src/routes/devices.$id.settings.video.tsx | 2 +- 19 files changed, 208 insertions(+), 39 deletions(-) diff --git a/audio.go b/audio.go index c031492e..3306ed7d 100644 --- a/audio.go +++ b/audio.go @@ -53,6 +53,12 @@ func getAudioConfig() audio.AudioConfig { if config.AudioBufferPeriods >= 2 && config.AudioBufferPeriods <= 24 { cfg.BufferPeriods = uint8(config.AudioBufferPeriods) } + if config.AudioSampleRate == 32000 || config.AudioSampleRate == 44100 || config.AudioSampleRate == 48000 || config.AudioSampleRate == 96000 { + cfg.SampleRate = uint32(config.AudioSampleRate) + } + if config.AudioPacketLossPerc >= 0 && config.AudioPacketLossPerc <= 100 { + cfg.PacketLossPerc = uint8(config.AudioPacketLossPerc) + } return cfg } diff --git a/config.go b/config.go index a155c7ee..efc9b46d 100644 --- a/config.go +++ b/config.go @@ -109,12 +109,14 @@ type Config struct { VideoQualityFactor float64 `json:"video_quality_factor"` AudioInputAutoEnable bool `json:"audio_input_auto_enable"` AudioOutputEnabled bool `json:"audio_output_enabled"` - AudioOutputSource string `json:"audio_output_source"` // "hdmi" or "usb" - AudioBitrate int `json:"audio_bitrate"` // kbps (64-256) - AudioComplexity int `json:"audio_complexity"` // 0-10 + AudioOutputSource string `json:"audio_output_source"` // "hdmi" or "usb" + AudioBitrate int `json:"audio_bitrate"` // kbps (64-256) + AudioComplexity int `json:"audio_complexity"` // 0-10 AudioDTXEnabled bool `json:"audio_dtx_enabled"` AudioFECEnabled bool `json:"audio_fec_enabled"` - AudioBufferPeriods int `json:"audio_buffer_periods"` // 2-24 + AudioBufferPeriods int `json:"audio_buffer_periods"` // 2-24 + AudioSampleRate int `json:"audio_sample_rate"` // Hz (32000, 44100, 48000) + AudioPacketLossPerc int `json:"audio_packet_loss_perc"` // 0-100 } func (c *Config) GetDisplayRotation() uint16 { @@ -196,6 +198,8 @@ func getDefaultConfig() Config { AudioDTXEnabled: true, AudioFECEnabled: true, AudioBufferPeriods: 12, + AudioSampleRate: 48000, + AudioPacketLossPerc: 20, } } @@ -275,6 +279,13 @@ func LoadConfig() { loadedConfig.AudioBufferPeriods = defaults.AudioBufferPeriods } + if loadedConfig.AudioSampleRate == 0 { + loadedConfig.AudioSampleRate = getDefaultConfig().AudioSampleRate + } + if loadedConfig.AudioPacketLossPerc == 0 { + loadedConfig.AudioPacketLossPerc = getDefaultConfig().AudioPacketLossPerc + } + // fixup old keyboard layout value if loadedConfig.KeyboardLayout == "en_US" { loadedConfig.KeyboardLayout = "en-US" diff --git a/internal/audio/c/audio.c b/internal/audio/c/audio.c index 276fb251..b446cea0 100644 --- a/internal/audio/c/audio.c +++ b/internal/audio/c/audio.c @@ -88,7 +88,7 @@ int jetkvm_audio_decode_write(void *opus_buf, int opus_size); void update_audio_constants(uint32_t bitrate, uint8_t complexity, uint32_t sr, uint8_t ch, uint16_t fs, uint16_t max_pkt, uint32_t sleep_us, uint8_t max_attempts, uint32_t max_backoff, - uint8_t dtx_enabled, uint8_t fec_enabled, uint8_t buf_periods); + uint8_t dtx_enabled, uint8_t fec_enabled, uint8_t buf_periods, uint8_t pkt_loss_perc); void update_audio_decoder_constants(uint32_t sr, uint8_t ch, uint16_t fs, uint16_t max_pkt, uint32_t sleep_us, uint8_t max_attempts, uint32_t max_backoff, uint8_t buf_periods); @@ -98,7 +98,7 @@ int update_opus_encoder_params(uint32_t bitrate, uint8_t complexity); void update_audio_constants(uint32_t bitrate, uint8_t complexity, uint32_t sr, uint8_t ch, uint16_t fs, uint16_t max_pkt, uint32_t sleep_us, uint8_t max_attempts, uint32_t max_backoff, - uint8_t dtx_enabled, uint8_t fec_enabled, uint8_t buf_periods) { + uint8_t dtx_enabled, uint8_t fec_enabled, uint8_t buf_periods, uint8_t pkt_loss_perc) { opus_bitrate = (bitrate >= 64000 && bitrate <= 256000) ? bitrate : 128000; opus_complexity = (complexity <= 10) ? complexity : 5; sample_rate = sr > 0 ? sr : 48000; @@ -112,6 +112,7 @@ void update_audio_constants(uint32_t bitrate, uint8_t complexity, opus_dtx_enabled = dtx_enabled ? 1 : 0; opus_fec_enabled = fec_enabled ? 1 : 0; buffer_period_count = (buf_periods >= 2 && buf_periods <= 24) ? buf_periods : 12; + opus_packet_loss_perc = (pkt_loss_perc <= 100) ? pkt_loss_perc : 20; } void update_audio_decoder_constants(uint32_t sr, uint8_t ch, uint16_t fs, uint16_t max_pkt, diff --git a/internal/audio/cgo_source.go b/internal/audio/cgo_source.go index 7a874213..24bf854b 100644 --- a/internal/audio/cgo_source.go +++ b/internal/audio/cgo_source.go @@ -91,13 +91,15 @@ func (c *CgoSource) Connect() error { Bool("dtx", c.config.DTXEnabled). Bool("fec", c.config.FECEnabled). Uint8("buffer_periods", c.config.BufferPeriods). + Uint32("sample_rate", c.config.SampleRate). + Uint8("packet_loss_perc", c.config.PacketLossPerc). Str("alsa_device", c.alsaDevice). Msg("Initializing audio capture") C.update_audio_constants( C.uint(uint32(c.config.Bitrate)*1000), C.uchar(c.config.Complexity), - C.uint(48000), + C.uint(c.config.SampleRate), C.uchar(2), C.ushort(960), C.ushort(1500), @@ -107,6 +109,7 @@ func (c *CgoSource) Connect() error { dtx, fec, C.uchar(c.config.BufferPeriods), + C.uchar(c.config.PacketLossPerc), ) rc := C.jetkvm_audio_capture_init() @@ -118,7 +121,7 @@ func (c *CgoSource) Connect() error { os.Setenv("ALSA_PLAYBACK_DEVICE", c.alsaDevice) C.update_audio_decoder_constants( - C.uint(48000), + C.uint(c.config.SampleRate), C.uchar(2), C.ushort(960), C.ushort(1500), diff --git a/internal/audio/source.go b/internal/audio/source.go index 9f7e431c..bdb953d4 100644 --- a/internal/audio/source.go +++ b/internal/audio/source.go @@ -5,20 +5,24 @@ const ( ) type AudioConfig struct { - Bitrate uint16 - Complexity uint8 - BufferPeriods uint8 - DTXEnabled bool - FECEnabled bool + Bitrate uint16 + Complexity uint8 + BufferPeriods uint8 + DTXEnabled bool + FECEnabled bool + SampleRate uint32 + PacketLossPerc uint8 } func DefaultAudioConfig() AudioConfig { return AudioConfig{ - Bitrate: 128, - Complexity: 5, - BufferPeriods: 12, - DTXEnabled: true, - FECEnabled: true, + Bitrate: 128, + Complexity: 5, + BufferPeriods: 12, + DTXEnabled: true, + FECEnabled: true, + SampleRate: 48000, + PacketLossPerc: 20, } } diff --git a/internal/native/video.go b/internal/native/video.go index 7cf6f501..30790f68 100644 --- a/internal/native/video.go +++ b/internal/native/video.go @@ -9,7 +9,8 @@ import ( const sleepModeFile = "/sys/devices/platform/ff470000.i2c/i2c-4/4-000f/sleep_mode" // DefaultEDID is the default EDID (identifies as "JetKVM HDMI" with full TC358743 audio/video capabilities). -const DefaultEDID = "00ffffffffffff002a8b01000100000001230104800000782ec9a05747982712484c00000000d1c081c0a9c0b3000101010101010101083a801871382d40582c450000000000001e011d007251d01e206e28550000000000001e000000fc004a65746b564d2048444d490a20000000fd00187801ff1d000a20202020202001e102032e7229097f070d07070f0707509005040302011f132220111214061507831f000068030c0010003021e2050700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047" +// Updated with 24-inch display dimensions (52x32cm) and Dell manufacturer ID for compatibility. +const DefaultEDID = "00ffffffffffff0010ac01000100000001230104803420782ec9a05747982712484c00000000d1c081c0a9c0b3000101010101010101083a801871382d40582c450000000000001e011d007251d01e206e28550000000000001e000000fc004a65746b564d2048444d490a20000000fd00187801ff1d000a202020202020016602032e7229097f070d07070f0707509005040302011f132220111214061507831f000068030c0010003021e2050700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047" var extraLockTimeout = 5 * time.Second diff --git a/jsonrpc.go b/jsonrpc.go index 8a66570d..65d6ceb5 100644 --- a/jsonrpc.go +++ b/jsonrpc.go @@ -1040,11 +1040,13 @@ func rpcSetAudioOutputSource(source string) error { } type AudioConfigResponse struct { - Bitrate int `json:"bitrate"` - Complexity int `json:"complexity"` - DTXEnabled bool `json:"dtx_enabled"` - FECEnabled bool `json:"fec_enabled"` - BufferPeriods int `json:"buffer_periods"` + Bitrate int `json:"bitrate"` + Complexity int `json:"complexity"` + DTXEnabled bool `json:"dtx_enabled"` + FECEnabled bool `json:"fec_enabled"` + BufferPeriods int `json:"buffer_periods"` + SampleRate int `json:"sample_rate"` + PacketLossPerc int `json:"packet_loss_perc"` } func rpcGetAudioConfig() (AudioConfigResponse, error) { @@ -1057,16 +1059,26 @@ func rpcGetAudioConfig() (AudioConfigResponse, error) { if bufferPeriods < 2 || bufferPeriods > 24 { bufferPeriods = 12 } + sampleRate := config.AudioSampleRate + if sampleRate != 32000 && sampleRate != 44100 && sampleRate != 48000 && sampleRate != 96000 { + sampleRate = 48000 + } + packetLossPerc := config.AudioPacketLossPerc + if packetLossPerc < 0 || packetLossPerc > 100 { + packetLossPerc = 20 + } return AudioConfigResponse{ - Bitrate: bitrate, - Complexity: config.AudioComplexity, - DTXEnabled: config.AudioDTXEnabled, - FECEnabled: config.AudioFECEnabled, - BufferPeriods: bufferPeriods, + Bitrate: bitrate, + Complexity: config.AudioComplexity, + DTXEnabled: config.AudioDTXEnabled, + FECEnabled: config.AudioFECEnabled, + BufferPeriods: bufferPeriods, + SampleRate: sampleRate, + PacketLossPerc: packetLossPerc, }, nil } -func rpcSetAudioConfig(bitrate int, complexity int, dtxEnabled bool, fecEnabled bool, bufferPeriods 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 { @@ -1078,12 +1090,20 @@ 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") } + 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 { + return fmt.Errorf("packet loss percentage must be between 0 and 100") + } config.AudioBitrate = bitrate config.AudioComplexity = complexity config.AudioDTXEnabled = dtxEnabled config.AudioFECEnabled = fecEnabled config.AudioBufferPeriods = bufferPeriods + config.AudioSampleRate = sampleRate + config.AudioPacketLossPerc = packetLossPerc return SaveConfig() } @@ -1434,7 +1454,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"}}, + "setAudioConfig": {Func: rpcSetAudioConfig, Params: []string{"bitrate", "complexity", "dtxEnabled", "fecEnabled", "bufferPeriods", "sampleRate", "packetLossPerc"}}, "restartAudioOutput": {Func: rpcRestartAudioOutput}, "getAudioInputAutoEnable": {Func: rpcGetAudioInputAutoEnable}, "setAudioInputAutoEnable": {Func: rpcSetAudioInputAutoEnable, Params: []string{"enabled"}}, diff --git a/ui/localization/messages/da.json b/ui/localization/messages/da.json index a5bf65fa..277e768c 100644 --- a/ui/localization/messages/da.json +++ b/ui/localization/messages/da.json @@ -88,6 +88,10 @@ "audio_settings_fec_description": "Forbedre lydkvaliteten på tabende forbindelser", "audio_settings_buffer_title": "Bufferperioder", "audio_settings_buffer_description": "ALSA bufferstørrelse (højere = mere stabil, mere latens)", + "audio_settings_sample_rate_title": "Samplingsrate", + "audio_settings_sample_rate_description": "Lydsamplingsfrekven (match HDMI-kilde for bedste kvalitet)", + "audio_settings_packet_loss_title": "Pakketabskompensation", + "audio_settings_packet_loss_description": "FEC overhead-procent (højere = bedre gendannelse, mere båndbredde)", "audio_settings_config_updated": "Lydkonfiguration opdateret", "audio_settings_apply_button": "Anvend indstillinger", "audio_settings_applied": "Lydindstillinger anvendt", diff --git a/ui/localization/messages/de.json b/ui/localization/messages/de.json index d11bf4b4..838fa593 100644 --- a/ui/localization/messages/de.json +++ b/ui/localization/messages/de.json @@ -88,6 +88,10 @@ "audio_settings_fec_description": "Audioqualität bei verlustbehafteten Verbindungen verbessern", "audio_settings_buffer_title": "Pufferperioden", "audio_settings_buffer_description": "ALSA-Puffergröße (höher = stabiler, mehr Latenz)", + "audio_settings_sample_rate_title": "Abtastrate", + "audio_settings_sample_rate_description": "Audio-Abtastfrequenz (HDMI-Quelle anpassen für beste Qualität)", + "audio_settings_packet_loss_title": "Paketverlust-Kompensation", + "audio_settings_packet_loss_description": "FEC-Overhead-Prozentsatz (höher = bessere Wiederherstellung, mehr Bandbreite)", "audio_settings_config_updated": "Audiokonfiguration aktualisiert", "audio_settings_apply_button": "Einstellungen anwenden", "audio_settings_applied": "Audioeinstellungen angewendet", diff --git a/ui/localization/messages/en.json b/ui/localization/messages/en.json index da1bf054..74fc518d 100644 --- a/ui/localization/messages/en.json +++ b/ui/localization/messages/en.json @@ -88,6 +88,10 @@ "audio_settings_fec_description": "Improve audio quality on lossy connections", "audio_settings_buffer_title": "Buffer Periods", "audio_settings_buffer_description": "ALSA buffer size (higher = more stable, more latency)", + "audio_settings_sample_rate_title": "Sample Rate", + "audio_settings_sample_rate_description": "Audio sampling frequency (match HDMI source for best quality)", + "audio_settings_packet_loss_title": "Packet Loss Compensation", + "audio_settings_packet_loss_description": "FEC overhead percentage (higher = better recovery, more bandwidth)", "audio_settings_config_updated": "Audio configuration updated", "audio_settings_apply_button": "Apply Settings", "audio_settings_applied": "Audio settings applied", diff --git a/ui/localization/messages/es.json b/ui/localization/messages/es.json index 265528bc..ae2a38f9 100644 --- a/ui/localization/messages/es.json +++ b/ui/localization/messages/es.json @@ -88,6 +88,10 @@ "audio_settings_fec_description": "Mejorar la calidad de audio en conexiones con pérdida", "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_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_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_config_updated": "Configuración de audio actualizada", "audio_settings_apply_button": "Aplicar configuración", "audio_settings_applied": "Configuración de audio aplicada", diff --git a/ui/localization/messages/fr.json b/ui/localization/messages/fr.json index 22056299..fea60ced 100644 --- a/ui/localization/messages/fr.json +++ b/ui/localization/messages/fr.json @@ -88,6 +88,10 @@ "audio_settings_fec_description": "Améliorer la qualité audio sur les connexions avec perte", "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_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_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_config_updated": "Configuration audio mise à jour", "audio_settings_apply_button": "Appliquer les paramètres", "audio_settings_applied": "Paramètres audio appliqués", diff --git a/ui/localization/messages/it.json b/ui/localization/messages/it.json index 6663b7f2..de9609e8 100644 --- a/ui/localization/messages/it.json +++ b/ui/localization/messages/it.json @@ -88,6 +88,10 @@ "audio_settings_fec_description": "Migliora la qualità audio su connessioni con perdita", "audio_settings_buffer_title": "Periodi Buffer", "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_description": "Frequenza di campionamento audio (abbinare alla sorgente HDMI per la migliore qualità)", + "audio_settings_packet_loss_title": "Compensazione Perdita Pacchetti", + "audio_settings_packet_loss_description": "Percentuale overhead FEC (più alto = migliore recupero, più banda)", "audio_settings_config_updated": "Configurazione audio aggiornata", "audio_settings_apply_button": "Applica impostazioni", "audio_settings_applied": "Impostazioni audio applicate", diff --git a/ui/localization/messages/nb.json b/ui/localization/messages/nb.json index 1f1c414f..ba2f1aa9 100644 --- a/ui/localization/messages/nb.json +++ b/ui/localization/messages/nb.json @@ -88,6 +88,10 @@ "audio_settings_fec_description": "Forbedre lydkvaliteten på tapende tilkoblinger", "audio_settings_buffer_title": "Bufferperioder", "audio_settings_buffer_description": "ALSA bufferstørrelse (høyere = mer stabil, mer latens)", + "audio_settings_sample_rate_title": "Samplingsrate", + "audio_settings_sample_rate_description": "Lydsampleringsfrekvens (match HDMI-kilde for beste kvalitet)", + "audio_settings_packet_loss_title": "Pakketapskompensasjon", + "audio_settings_packet_loss_description": "FEC overhead-prosent (høyere = bedre gjenoppretting, mer båndbredde)", "audio_settings_config_updated": "Lydkonfigurasjon oppdatert", "audio_settings_apply_button": "Bruk innstillinger", "audio_settings_applied": "Lydinnstillinger brukt", diff --git a/ui/localization/messages/sv.json b/ui/localization/messages/sv.json index 4f5cb1b0..d188fd7c 100644 --- a/ui/localization/messages/sv.json +++ b/ui/localization/messages/sv.json @@ -88,6 +88,10 @@ "audio_settings_fec_description": "Förbättra ljudkvaliteten på förlustdrabbade anslutningar", "audio_settings_buffer_title": "Bufferperioder", "audio_settings_buffer_description": "ALSA bufferstorlek (högre = mer stabil, mer latens)", + "audio_settings_sample_rate_title": "Samplingsfrekvens", + "audio_settings_sample_rate_description": "Ljudsamplingsfrekvens (matcha HDMI-källa för bästa kvalitet)", + "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_config_updated": "Ljudkonfiguration uppdaterad", "audio_settings_apply_button": "Tillämpa inställningar", "audio_settings_applied": "Ljudinställningar tillämpade", diff --git a/ui/localization/messages/zh.json b/ui/localization/messages/zh.json index 268a2877..6fb86a4d 100644 --- a/ui/localization/messages/zh.json +++ b/ui/localization/messages/zh.json @@ -88,6 +88,10 @@ "audio_settings_fec_description": "改善有损连接上的音频质量", "audio_settings_buffer_title": "缓冲周期", "audio_settings_buffer_description": "ALSA 缓冲大小(越高 = 越稳定,延迟越高)", + "audio_settings_sample_rate_title": "采样率", + "audio_settings_sample_rate_description": "音频采样频率(匹配 HDMI 源以获得最佳质量)", + "audio_settings_packet_loss_title": "丢包补偿", + "audio_settings_packet_loss_description": "FEC 开销百分比(越高 = 恢复越好,带宽越大)", "audio_settings_config_updated": "音频配置已更新", "audio_settings_apply_button": "应用设置", "audio_settings_applied": "音频设置已应用", diff --git a/ui/src/hooks/stores.ts b/ui/src/hooks/stores.ts index e28713f5..3fb543c4 100644 --- a/ui/src/hooks/stores.ts +++ b/ui/src/hooks/stores.ts @@ -403,6 +403,10 @@ export interface SettingsState { setAudioFECEnabled: (enabled: boolean) => void; audioBufferPeriods: number; setAudioBufferPeriods: (value: number) => void; + audioSampleRate: number; + setAudioSampleRate: (value: number) => void; + audioPacketLossPerc: number; + setAudioPacketLossPerc: (value: number) => void; resetMicrophoneState: () => void; } @@ -472,6 +476,10 @@ export const useSettingsStore = create( setAudioFECEnabled: (enabled: boolean) => set({ audioFECEnabled: enabled }), audioBufferPeriods: 12, setAudioBufferPeriods: (value: number) => set({ audioBufferPeriods: value }), + audioSampleRate: 48000, + setAudioSampleRate: (value: number) => set({ audioSampleRate: value }), + audioPacketLossPerc: 20, + setAudioPacketLossPerc: (value: number) => set({ audioPacketLossPerc: value }), resetMicrophoneState: () => set({ microphoneEnabled: false }), }), diff --git a/ui/src/routes/devices.$id.settings.audio.tsx b/ui/src/routes/devices.$id.settings.audio.tsx index 8d03c8a9..64266f13 100644 --- a/ui/src/routes/devices.$id.settings.audio.tsx +++ b/ui/src/routes/devices.$id.settings.audio.tsx @@ -16,6 +16,8 @@ interface AudioConfigResult { dtx_enabled: boolean; fec_enabled: boolean; buffer_periods: number; + sample_rate: number; + packet_loss_perc: number; } export default function SettingsAudioRoute() { @@ -37,6 +39,10 @@ export default function SettingsAudioRoute() { setAudioFECEnabled, audioBufferPeriods, setAudioBufferPeriods, + audioSampleRate, + setAudioSampleRate, + audioPacketLossPerc, + setAudioPacketLossPerc, } = useSettingsStore(); useEffect(() => { @@ -63,8 +69,10 @@ export default function SettingsAudioRoute() { setAudioDTXEnabled(config.dtx_enabled); setAudioFECEnabled(config.fec_enabled); setAudioBufferPeriods(config.buffer_periods); + setAudioSampleRate(config.sample_rate); + setAudioPacketLossPerc(config.packet_loss_perc); }); - }, [send, setAudioOutputEnabled, setAudioInputAutoEnable, setAudioOutputSource, setAudioBitrate, setAudioComplexity, setAudioDTXEnabled, setAudioFECEnabled, setAudioBufferPeriods]); + }, [send, setAudioOutputEnabled, setAudioInputAutoEnable, setAudioOutputSource, setAudioBitrate, setAudioComplexity, setAudioDTXEnabled, setAudioFECEnabled, setAudioBufferPeriods, setAudioSampleRate, setAudioPacketLossPerc]); const handleAudioOutputEnabledChange = (enabled: boolean) => { send("setAudioOutputEnabled", { enabled }, (resp: JsonRpcResponse) => { @@ -111,11 +119,13 @@ export default function SettingsAudioRoute() { complexity: number, dtxEnabled: boolean, fecEnabled: boolean, - bufferPeriods: number + bufferPeriods: number, + sampleRate: number, + packetLossPerc: number ) => { send( "setAudioConfig", - { bitrate, complexity, dtxEnabled, fecEnabled, bufferPeriods }, + { bitrate, complexity, dtxEnabled, fecEnabled, bufferPeriods, sampleRate, packetLossPerc }, (resp: JsonRpcResponse) => { if ("error" in resp) { notifications.error(String(resp.error.data || m.unknown_error())); @@ -126,6 +136,8 @@ export default function SettingsAudioRoute() { setAudioDTXEnabled(dtxEnabled); setAudioFECEnabled(fecEnabled); setAudioBufferPeriods(bufferPeriods); + setAudioSampleRate(sampleRate); + setAudioPacketLossPerc(packetLossPerc); notifications.success(m.audio_settings_config_updated()); } ); @@ -204,7 +216,9 @@ export default function SettingsAudioRoute() { audioComplexity, audioDTXEnabled, audioFECEnabled, - audioBufferPeriods + audioBufferPeriods, + audioSampleRate, + audioPacketLossPerc ) } /> @@ -230,7 +244,9 @@ export default function SettingsAudioRoute() { parseInt(e.target.value), audioDTXEnabled, audioFECEnabled, - audioBufferPeriods + audioBufferPeriods, + audioSampleRate, + audioPacketLossPerc ) } /> @@ -248,7 +264,9 @@ export default function SettingsAudioRoute() { audioComplexity, e.target.checked, audioFECEnabled, - audioBufferPeriods + audioBufferPeriods, + audioSampleRate, + audioPacketLossPerc ) } /> @@ -266,7 +284,9 @@ export default function SettingsAudioRoute() { audioComplexity, audioDTXEnabled, e.target.checked, - audioBufferPeriods + audioBufferPeriods, + audioSampleRate, + audioPacketLossPerc ) } /> @@ -292,6 +312,65 @@ export default function SettingsAudioRoute() { audioComplexity, audioDTXEnabled, audioFECEnabled, + parseInt(e.target.value), + audioSampleRate, + audioPacketLossPerc + ) + } + /> + + + + + handleAudioConfigChange( + audioBitrate, + audioComplexity, + audioDTXEnabled, + audioFECEnabled, + audioBufferPeriods, + parseInt(e.target.value), + audioPacketLossPerc + ) + } + /> + + + + + handleAudioConfigChange( + audioBitrate, + audioComplexity, + audioDTXEnabled, + audioFECEnabled, + audioBufferPeriods, + audioSampleRate, parseInt(e.target.value) ) } diff --git a/ui/src/routes/devices.$id.settings.video.tsx b/ui/src/routes/devices.$id.settings.video.tsx index 766c3f71..a2834c05 100644 --- a/ui/src/routes/devices.$id.settings.video.tsx +++ b/ui/src/routes/devices.$id.settings.video.tsx @@ -12,7 +12,7 @@ import notifications from "@/notifications"; import { m } from "@localizations/messages.js"; const defaultEdid = - "00ffffffffffff002a8b01000100000001230104800000782ec9a05747982712484c00000000d1c081c0a9c0b3000101010101010101083a801871382d40582c450000000000001e011d007251d01e206e28550000000000001e000000fc004a65744b564d2048444d490a20000000fd00187801ff1d000a20202020202001e102032e7229097f070d07070f0707509005040302011f132220111214061507831f000068030c0010003021e2050700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047"; + "00ffffffffffff0010ac01000100000001230104803420782ec9a05747982712484c00000000d1c081c0a9c0b3000101010101010101083a801871382d40582c450000000000001e011d007251d01e206e28550000000000001e000000fc004a65746b564d2048444d490a20000000fd00187801ff1d000a202020202020016602032e7229097f070d07070f0707509005040302011f132220111214061507831f000068030c0010003021e2050700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047"; const edids = [ { value: defaultEdid,