diff --git a/config.go b/config.go index 969b12960..32b3b659b 100644 --- a/config.go +++ b/config.go @@ -3,6 +3,7 @@ package kvm import ( "encoding/json" "fmt" + "io" "os" "strconv" "strings" @@ -176,6 +177,7 @@ var ( RelativeMouse: true, Keyboard: true, MassStorage: true, + Audio: true, } ) @@ -260,8 +262,15 @@ func LoadConfig() { defer file.Close() // load and merge the default config with the user config + rawConfig, err := io.ReadAll(file) + if err != nil { + logger.Warn().Err(err).Msg("config file reading failed") + configSuccess.Set(0.0) + return + } + loadedConfig := defaultConfig - if err := json.NewDecoder(file).Decode(&loadedConfig); err != nil { + if err := json.Unmarshal(rawConfig, &loadedConfig); err != nil { logger.Warn().Err(err).Msg("config file JSON parsing failed") configSuccess.Set(0.0) return @@ -274,6 +283,12 @@ func LoadConfig() { if loadedConfig.UsbDevices == nil { loadedConfig.UsbDevices = getDefaultConfig().UsbDevices + } else if !usbDevicesConfigHasAudio(rawConfig) { + loadedConfig.UsbDevices.Audio = defaultUsbDevices.Audio + } + + if !loadedConfig.UsbDevices.Audio { + loadedConfig.AudioEnabled = false } if loadedConfig.NetworkConfig == nil { @@ -322,6 +337,19 @@ func LoadConfig() { logger.Info().Str("path", configPath).Msg("config loaded") } +func usbDevicesConfigHasAudio(rawConfig []byte) bool { + var payload struct { + UsbDevices map[string]json.RawMessage `json:"usb_devices"` + } + + if err := json.Unmarshal(rawConfig, &payload); err != nil || payload.UsbDevices == nil { + return true + } + + _, ok := payload.UsbDevices["audio"] + return ok +} + func SaveConfig() error { return saveConfig(configPath) } diff --git a/internal/usbgadget/config.go b/internal/usbgadget/config.go index e713a4453..6af97b04e 100644 --- a/internal/usbgadget/config.go +++ b/internal/usbgadget/config.go @@ -81,6 +81,8 @@ func (u *UsbGadget) isGadgetConfigItemEnabled(itemKey string) bool { return u.enabledDevices.MassStorage case "serial_console": return u.enabledDevices.SerialConsole + case "audio": + return u.enabledDevices.Audio default: return true } diff --git a/internal/usbgadget/config_test.go b/internal/usbgadget/config_test.go new file mode 100644 index 000000000..9e1bff5db --- /dev/null +++ b/internal/usbgadget/config_test.go @@ -0,0 +1,24 @@ +package usbgadget + +import "testing" + +func TestAudioGadgetConfigFollowsEnabledDevice(t *testing.T) { + u := &UsbGadget{enabledDevices: Devices{Audio: false}} + if u.isGadgetConfigItemEnabled("audio") { + t.Fatal("audio gadget should be disabled when audio device is disabled") + } + + u.enabledDevices.Audio = true + if !u.isGadgetConfigItemEnabled("audio") { + t.Fatal("audio gadget should be enabled when audio device is enabled") + } +} + +func TestBaseGadgetConfigItemsAlwaysEnabled(t *testing.T) { + u := &UsbGadget{} + for _, item := range []string{"base", "base_info", "wake_hid"} { + if !u.isGadgetConfigItemEnabled(item) { + t.Fatalf("%s should always be enabled", item) + } + } +} diff --git a/internal/usbgadget/usbgadget.go b/internal/usbgadget/usbgadget.go index fca810358..bb4a9f98a 100644 --- a/internal/usbgadget/usbgadget.go +++ b/internal/usbgadget/usbgadget.go @@ -21,6 +21,7 @@ type Devices struct { Keyboard bool `json:"keyboard"` MassStorage bool `json:"mass_storage"` SerialConsole bool `json:"serial_console"` + Audio bool `json:"audio"` } // Config is a struct that represents the customizations for a USB gadget. @@ -41,6 +42,7 @@ var defaultUsbGadgetDevices = Devices{ RelativeMouse: true, Keyboard: true, MassStorage: true, + Audio: false, } type KeysDownState struct { diff --git a/jsonrpc.go b/jsonrpc.go index 1b49793cd..7a60656e1 100644 --- a/jsonrpc.go +++ b/jsonrpc.go @@ -380,10 +380,21 @@ func rpcGetAudioConfig() (*AudioConfig, error) { } func rpcSetAudioConfig(params AudioConfig) error { - if config.AudioEnabled == params.Enabled { + enabled := params.Enabled + if enabled && (config.UsbDevices == nil || !config.UsbDevices.Audio) { + enabled = false + } + if config.AudioEnabled == enabled { return nil } - config.AudioEnabled = params.Enabled + config.AudioEnabled = enabled + if !effectiveAudioEnabled() { + stopAudio() + } + if gadget != nil { + gadget.SetGadgetDevices(effectiveUsbDevices()) + return updateUsbRelatedConfig() + } if err := SaveConfig(); err != nil { return fmt.Errorf("failed to save config: %w", err) } @@ -982,8 +993,14 @@ func updateUsbRelatedConfig() error { } func rpcSetUsbDevices(usbDevices usbgadget.Devices) error { + if !usbDevices.Audio { + config.AudioEnabled = false + } config.UsbDevices = &usbDevices - gadget.SetGadgetDevices(config.UsbDevices) + if !effectiveAudioEnabled() { + stopAudio() + } + gadget.SetGadgetDevices(effectiveUsbDevices()) return updateUsbRelatedConfig() } @@ -999,10 +1016,18 @@ func rpcSetUsbDeviceState(device string, enabled bool) error { config.UsbDevices.MassStorage = enabled case "serialConsole": config.UsbDevices.SerialConsole = enabled + case "audio": + config.UsbDevices.Audio = enabled + if !enabled { + config.AudioEnabled = false + } default: return fmt.Errorf("invalid device: %s", device) } - gadget.SetGadgetDevices(config.UsbDevices) + if !effectiveAudioEnabled() { + stopAudio() + } + gadget.SetGadgetDevices(effectiveUsbDevices()) return updateUsbRelatedConfig() } diff --git a/ui/e2e/remote-agent/ra-all.spec.ts b/ui/e2e/remote-agent/ra-all.spec.ts index cc9796569..f3f4c70b4 100644 --- a/ui/e2e/remote-agent/ra-all.spec.ts +++ b/ui/e2e/remote-agent/ra-all.spec.ts @@ -1741,6 +1741,9 @@ test.describe("Remote Host Agent", () => { await freshPage.goto("/", { waitUntil: "networkidle" }); await waitForWebRTCReady(freshPage); + const readyEvents = await waitForKeyboardReady(agent!, freshPage, 15000); + expect(readyEvents.length, "keyboard should work before disconnect test").toBeGreaterThan(0); + await agent!.clearKeyboardEvents(); await sendKeypress(freshPage, 0xe1, true); diff --git a/ui/localization/messages/cy.json b/ui/localization/messages/cy.json index e32f20867..45e61d69e 100644 --- a/ui/localization/messages/cy.json +++ b/ui/localization/messages/cy.json @@ -163,6 +163,8 @@ "audio_enable_title": "Galluogi sain", "audio_page_description": "Ffrydio sain o'r gwesteiwr i'ch porwr", "audio_title": "Sain", + "audio_usb_device_disabled_hint": "Mae USB Audio wedi'i ddiffodd yn Nyfeisiau USB.", + "audio_usb_device_disabled_link": "Galluogwch ef yn y gosodiadau caledwedd.", "auth_authentication_mode": "Dewiswch fodd dilysu", "auth_authentication_mode_error": "Digwyddodd gwall wrth osod y modd dilysu", "auth_authentication_mode_invalid": "Modd dilysu annilys", @@ -973,6 +975,8 @@ "usb_device_description": "Dyfeisiau USB i'w hefelychu ar y cyfrifiadur targed", "usb_device_enable_absolute_mouse_description": "Galluogi Llygoden Absoliwt (Pwyntydd)", "usb_device_enable_absolute_mouse_title": "Galluogi Llygoden Absoliwt (Pwyntydd)", + "usb_device_enable_audio_description": "Caniatáu i JetKVM gyflwyno dyfais sain pan fydd Audio wedi'i alluogi.", + "usb_device_enable_audio_title": "Galluogi USB Audio", "usb_device_enable_keyboard_description": "Galluogi Bysellfwrdd", "usb_device_enable_keyboard_title": "Galluogi Bysellfwrdd", "usb_device_enable_mass_storage_description": "Weithiau efallai y bydd angen ei analluogi i osgoi problemau gyda rhai dyfeisiau", @@ -983,7 +987,7 @@ "usb_device_enable_serial_console_title": "Galluogi Consol Cyfresol USB", "usb_device_failed_load": "Methwyd â llwytho dyfeisiau USB: {error}", "usb_device_failed_set": "Methwyd â gosod dyfeisiau USB: {error}", - "usb_device_keyboard_mouse_and_mass_storage": "Bysellfwrdd, Llygoden a Storfa Dorfol", + "usb_device_keyboard_mouse_mass_storage_and_audio": "Bysellfwrdd, llygoden, storfa dorfol a sain", "usb_device_keyboard_only": "Bysellfwrdd yn Unig", "usb_device_restore_default": "Adfer i'r Rhagosodiad", "usb_device_title": "Dyfais USB", diff --git a/ui/localization/messages/da.json b/ui/localization/messages/da.json index 339e54d93..79db56fe4 100644 --- a/ui/localization/messages/da.json +++ b/ui/localization/messages/da.json @@ -168,6 +168,8 @@ "audio_enable_title": "Aktivér lyd", "audio_page_description": "Stream lyd fra værten til din browser", "audio_title": "Lyd", + "audio_usb_device_disabled_hint": "USB-lyd er slået fra i USB-enheder.", + "audio_usb_device_disabled_link": "Aktivér det i hardwareindstillingerne.", "auth_authentication_mode": "Vælg venligst en godkendelsestilstand", "auth_authentication_mode_error": "Der opstod en fejl under indstilling af godkendelsestilstanden", "auth_authentication_mode_invalid": "Ugyldig godkendelsestilstand", @@ -986,6 +988,8 @@ "usb_device_description": "USB-enheder, der skal emuleres på målcomputeren", "usb_device_enable_absolute_mouse_description": "Aktivér absolut mus (markør)", "usb_device_enable_absolute_mouse_title": "Aktivér absolut mus (markør)", + "usb_device_enable_audio_description": "Tillad JetKVM at vise en lydenhed, når lyd er aktiveret.", + "usb_device_enable_audio_title": "Aktivér USB-lyd", "usb_device_enable_keyboard_description": "Aktivér tastatur", "usb_device_enable_keyboard_title": "Aktivér tastatur", "usb_device_enable_mass_storage_description": "Nogle gange skal det muligvis deaktiveres for at forhindre problemer med bestemte enheder.", @@ -996,7 +1000,7 @@ "usb_device_enable_serial_console_title": "Aktivér USB-seriel konsol", "usb_device_failed_load": "Kunne ikke indlæse USB-enheder: {error}", "usb_device_failed_set": "Kunne ikke indstille USB-enheder: {error}", - "usb_device_keyboard_mouse_and_mass_storage": "Tastatur, mus og masselagring", + "usb_device_keyboard_mouse_mass_storage_and_audio": "Tastatur, mus, masselagring og lyd", "usb_device_keyboard_only": "Kun tastatur", "usb_device_restore_default": "Gendan til standard", "usb_device_title": "USB-enhed", diff --git a/ui/localization/messages/de.json b/ui/localization/messages/de.json index 3f5bfcec2..99fb1a10b 100644 --- a/ui/localization/messages/de.json +++ b/ui/localization/messages/de.json @@ -168,6 +168,8 @@ "audio_enable_title": "Audio aktivieren", "audio_page_description": "Audio vom Host an Ihren Browser streamen", "audio_title": "Audio", + "audio_usb_device_disabled_hint": "USB-Audio ist unter USB-Geräte deaktiviert.", + "audio_usb_device_disabled_link": "Aktivieren Sie es in den Hardware-Einstellungen.", "auth_authentication_mode": "Bitte wählen Sie einen Authentifizierungsmodus", "auth_authentication_mode_error": "Beim Einstellen des Authentifizierungsmodus ist ein Fehler aufgetreten", "auth_authentication_mode_invalid": "Ungültiger Authentifizierungsmodus", @@ -986,6 +988,8 @@ "usb_device_description": "USB-Geräte zum Emulieren auf dem Zielcomputer", "usb_device_enable_absolute_mouse_description": "Absolute Maus (Zeiger) aktivieren", "usb_device_enable_absolute_mouse_title": "Absolute Maus (Zeiger) aktivieren", + "usb_device_enable_audio_description": "JetKVM darf dem Host ein Audiogerät bereitstellen, wenn Audio aktiviert ist.", + "usb_device_enable_audio_title": "USB-Audio aktivieren", "usb_device_enable_keyboard_description": "Tastatur aktivieren", "usb_device_enable_keyboard_title": "Tastatur aktivieren", "usb_device_enable_mass_storage_description": "Manchmal muss es möglicherweise deaktiviert werden, um Probleme mit bestimmten Geräten zu vermeiden", @@ -996,7 +1000,7 @@ "usb_device_enable_serial_console_title": "USB-Serienkonsole aktivieren", "usb_device_failed_load": "USB-Geräte konnten nicht geladen werden: {error}", "usb_device_failed_set": "Fehler beim Festlegen der USB-Geräte: {error}", - "usb_device_keyboard_mouse_and_mass_storage": "Tastatur, Maus und Massenspeicher", + "usb_device_keyboard_mouse_mass_storage_and_audio": "Tastatur, Maus, Massenspeicher und Audio", "usb_device_keyboard_only": "Nur Tastatur", "usb_device_restore_default": "Auf Standard zurücksetzen", "usb_device_title": "USB-Gerät", diff --git a/ui/localization/messages/en.json b/ui/localization/messages/en.json index c3b0d2802..bec0bcdd3 100644 --- a/ui/localization/messages/en.json +++ b/ui/localization/messages/en.json @@ -168,6 +168,8 @@ "audio_enable_title": "Enable Audio", "audio_page_description": "Stream audio from the host to your browser", "audio_title": "Audio", + "audio_usb_device_disabled_hint": "USB Audio is off in USB Devices.", + "audio_usb_device_disabled_link": "Enable it in Hardware settings.", "auth_authentication_mode": "Please select an authentication mode", "auth_authentication_mode_error": "An error occurred while setting the authentication mode", "auth_authentication_mode_invalid": "Invalid authentication mode", @@ -986,6 +988,8 @@ "usb_device_description": "USB devices to emulate on the target computer", "usb_device_enable_absolute_mouse_description": "Enable Absolute Mouse (Pointer)", "usb_device_enable_absolute_mouse_title": "Enable Absolute Mouse (Pointer)", + "usb_device_enable_audio_description": "Allow JetKVM to present an audio device when Audio is enabled.", + "usb_device_enable_audio_title": "Enable USB Audio", "usb_device_enable_keyboard_description": "Enable Keyboard", "usb_device_enable_keyboard_title": "Enable Keyboard", "usb_device_enable_mass_storage_description": "Sometimes it might need to be disabled to prevent issues with certain devices", @@ -996,7 +1000,7 @@ "usb_device_enable_serial_console_title": "Enable USB Serial Console", "usb_device_failed_load": "Failed to load USB devices: {error}", "usb_device_failed_set": "Failed to set USB devices: {error}", - "usb_device_keyboard_mouse_and_mass_storage": "Keyboard, Mouse and Mass Storage", + "usb_device_keyboard_mouse_mass_storage_and_audio": "Keyboard, Mouse, Mass Storage and Audio", "usb_device_keyboard_only": "Keyboard Only", "usb_device_restore_default": "Restore to Default", "usb_device_title": "USB Device", diff --git a/ui/localization/messages/es.json b/ui/localization/messages/es.json index 0f01c3dce..f5339120d 100644 --- a/ui/localization/messages/es.json +++ b/ui/localization/messages/es.json @@ -168,6 +168,8 @@ "audio_enable_title": "Activar audio", "audio_page_description": "Transmita el audio del host a su navegador", "audio_title": "Audio", + "audio_usb_device_disabled_hint": "El audio USB está desactivado en Dispositivos USB.", + "audio_usb_device_disabled_link": "Actívelo en la configuración de hardware.", "auth_authentication_mode": "Por favor seleccione un modo de autenticación", "auth_authentication_mode_error": "Se produjo un error al configurar el modo de autenticación", "auth_authentication_mode_invalid": "Modo de autenticación no válido", @@ -986,6 +988,8 @@ "usb_device_description": "Dispositivos USB para emular en la computadora de destino", "usb_device_enable_absolute_mouse_description": "Habilitar el puntero absoluto del ratón", "usb_device_enable_absolute_mouse_title": "Habilitar el puntero absoluto del ratón", + "usb_device_enable_audio_description": "Permita que JetKVM presente un dispositivo de audio cuando Audio esté activado.", + "usb_device_enable_audio_title": "Activar audio USB", "usb_device_enable_keyboard_description": "Habilitar el teclado", "usb_device_enable_keyboard_title": "Habilitar el teclado", "usb_device_enable_mass_storage_description": "A veces puede ser necesario desactivarlo para evitar problemas con ciertos dispositivos.", @@ -996,7 +1000,7 @@ "usb_device_enable_serial_console_title": "Habilitar consola serie USB", "usb_device_failed_load": "No se pudieron cargar los dispositivos USB: {error}", "usb_device_failed_set": "No se pudieron configurar los dispositivos USB: {error}", - "usb_device_keyboard_mouse_and_mass_storage": "Teclado, ratón y almacenamiento masivo", + "usb_device_keyboard_mouse_mass_storage_and_audio": "Teclado, mouse, almacenamiento masivo y audio", "usb_device_keyboard_only": "Sólo teclado", "usb_device_restore_default": "Restaurar a valores predeterminados", "usb_device_title": "Dispositivo USB", diff --git a/ui/localization/messages/fr.json b/ui/localization/messages/fr.json index f1fe9e147..eeafb3d60 100644 --- a/ui/localization/messages/fr.json +++ b/ui/localization/messages/fr.json @@ -168,6 +168,8 @@ "audio_enable_title": "Activer l'audio", "audio_page_description": "Diffuser l'audio de l'hôte vers votre navigateur", "audio_title": "Audio", + "audio_usb_device_disabled_hint": "L'audio USB est désactivé dans les appareils USB.", + "audio_usb_device_disabled_link": "Activez-le dans les paramètres matériels.", "auth_authentication_mode": "Veuillez sélectionner un mode d'authentification", "auth_authentication_mode_error": "Une erreur s'est produite lors de la définition du mode d'authentification", "auth_authentication_mode_invalid": "Mode d'authentification non valide", @@ -986,6 +988,8 @@ "usb_device_description": "Périphériques USB à émuler sur l'ordinateur cible", "usb_device_enable_absolute_mouse_description": "Activer la souris absolue (pointeur)", "usb_device_enable_absolute_mouse_title": "Activer la souris absolue (pointeur)", + "usb_device_enable_audio_description": "Autoriser JetKVM à exposer un appareil audio à l'hôte lorsque l'audio est activé.", + "usb_device_enable_audio_title": "Activer l'audio USB", "usb_device_enable_keyboard_description": "Activer le clavier", "usb_device_enable_keyboard_title": "Activer le clavier", "usb_device_enable_mass_storage_description": "Parfois, il peut être nécessaire de le désactiver pour éviter des problèmes avec certains appareils", @@ -996,7 +1000,7 @@ "usb_device_enable_serial_console_title": "Activer la console série USB", "usb_device_failed_load": "Échec du chargement des périphériques USB : {error}", "usb_device_failed_set": "Échec de la configuration des périphériques USB : {error}", - "usb_device_keyboard_mouse_and_mass_storage": "Clavier, souris et stockage de masse", + "usb_device_keyboard_mouse_mass_storage_and_audio": "Clavier, souris, stockage de masse et audio", "usb_device_keyboard_only": "Clavier uniquement", "usb_device_restore_default": "Restaurer les paramètres par défaut", "usb_device_title": "périphérique USB", diff --git a/ui/localization/messages/it.json b/ui/localization/messages/it.json index 48c0cb3af..f9ffa5405 100644 --- a/ui/localization/messages/it.json +++ b/ui/localization/messages/it.json @@ -168,6 +168,8 @@ "audio_enable_title": "Abilita audio", "audio_page_description": "Trasmetti l'audio dell'host al browser", "audio_title": "Audio", + "audio_usb_device_disabled_hint": "L'audio USB è disabilitato in Dispositivi USB.", + "audio_usb_device_disabled_link": "Abilitalo nelle impostazioni hardware.", "auth_authentication_mode": "Seleziona una modalità di autenticazione", "auth_authentication_mode_error": "Si è verificato un errore durante l'impostazione della modalità di autenticazione", "auth_authentication_mode_invalid": "Modalità di autenticazione non valida", @@ -986,6 +988,8 @@ "usb_device_description": "Dispositivi USB da emulare sul computer di destinazione", "usb_device_enable_absolute_mouse_description": "Abilita mouse assoluto (puntatore)", "usb_device_enable_absolute_mouse_title": "Abilita mouse assoluto (puntatore)", + "usb_device_enable_audio_description": "Consenti a JetKVM di presentare un dispositivo audio quando l'audio è abilitato.", + "usb_device_enable_audio_title": "Abilita audio USB", "usb_device_enable_keyboard_description": "Abilita tastiera", "usb_device_enable_keyboard_title": "Abilita tastiera", "usb_device_enable_mass_storage_description": "A volte potrebbe essere necessario disattivarlo per evitare problemi con determinati dispositivi", @@ -996,7 +1000,7 @@ "usb_device_enable_serial_console_title": "Abilita console seriale USB", "usb_device_failed_load": "Impossibile caricare i dispositivi USB: {error}", "usb_device_failed_set": "Impossibile impostare i dispositivi USB: {error}", - "usb_device_keyboard_mouse_and_mass_storage": "Tastiera, mouse e memoria di massa", + "usb_device_keyboard_mouse_mass_storage_and_audio": "Tastiera, mouse, archiviazione di massa e audio", "usb_device_keyboard_only": "Solo tastiera", "usb_device_restore_default": "Ripristina impostazioni predefinite", "usb_device_title": "Dispositivo USB", diff --git a/ui/localization/messages/ja.json b/ui/localization/messages/ja.json index 916d1df26..ca305d04a 100644 --- a/ui/localization/messages/ja.json +++ b/ui/localization/messages/ja.json @@ -168,6 +168,8 @@ "audio_enable_title": "オーディオを有効化", "audio_page_description": "ホストの音声をブラウザにストリーミング", "audio_title": "オーディオ", + "audio_usb_device_disabled_hint": "USB オーディオは USB デバイスで無効です。", + "audio_usb_device_disabled_link": "ハードウェア設定で有効にしてください。", "auth_authentication_mode": "認証モードを選択してください", "auth_authentication_mode_error": "認証モードの設定中にエラーが発生しました", "auth_authentication_mode_invalid": "無効な認証モード", @@ -986,6 +988,8 @@ "usb_device_description": "ターゲットコンピュータ上でエミュレートするUSBデバイス", "usb_device_enable_absolute_mouse_description": "絶対座標マウス (ポインター) を有効にする", "usb_device_enable_absolute_mouse_title": "絶対座標マウス (ポインター) を有効化", + "usb_device_enable_audio_description": "オーディオが有効なときに JetKVM がホストへオーディオデバイスを提示できるようにします。", + "usb_device_enable_audio_title": "USB オーディオを有効化", "usb_device_enable_keyboard_description": "キーボードを有効にする", "usb_device_enable_keyboard_title": "キーボードを有効化", "usb_device_enable_mass_storage_description": "特定のデバイスでの問題を防ぐために無効にする必要がある場合があります", @@ -996,7 +1000,7 @@ "usb_device_enable_serial_console_title": "USBシリアルコンソールを有効化", "usb_device_failed_load": "USBデバイスの読み込みに失敗しました: {error}", "usb_device_failed_set": "USBデバイスの設定に失敗しました: {error}", - "usb_device_keyboard_mouse_and_mass_storage": "キーボード、マウス、マスストレージ", + "usb_device_keyboard_mouse_mass_storage_and_audio": "キーボード、マウス、マスストレージ、オーディオ", "usb_device_keyboard_only": "キーボードのみ", "usb_device_restore_default": "デフォルトに戻す", "usb_device_title": "USBデバイス", diff --git a/ui/localization/messages/nb.json b/ui/localization/messages/nb.json index 945631717..205a44309 100644 --- a/ui/localization/messages/nb.json +++ b/ui/localization/messages/nb.json @@ -168,6 +168,8 @@ "audio_enable_title": "Aktiver lyd", "audio_page_description": "Strøm lyd fra verten til nettleseren", "audio_title": "Lyd", + "audio_usb_device_disabled_hint": "USB-lyd er slått av i USB-enheter.", + "audio_usb_device_disabled_link": "Aktiver den i maskinvareinnstillingene.", "auth_authentication_mode": "Vennligst velg en autentiseringsmodus", "auth_authentication_mode_error": "Det oppsto en feil under angivelse av autentiseringsmodus", "auth_authentication_mode_invalid": "Ugyldig autentiseringsmodus", @@ -986,6 +988,8 @@ "usb_device_description": "USB-enheter som skal emuleres på måldatamaskinen", "usb_device_enable_absolute_mouse_description": "Aktiver absolutt mus (peker)", "usb_device_enable_absolute_mouse_title": "Aktiver absolutt mus (peker)", + "usb_device_enable_audio_description": "La JetKVM vise en lydenhet når lyd er aktivert.", + "usb_device_enable_audio_title": "Aktiver USB-lyd", "usb_device_enable_keyboard_description": "Aktiver tastatur", "usb_device_enable_keyboard_title": "Aktiver tastatur", "usb_device_enable_mass_storage_description": "Noen ganger må det kanskje deaktiveres for å forhindre problemer med visse enheter.", @@ -996,7 +1000,7 @@ "usb_device_enable_serial_console_title": "Aktiver USB-seriell konsoll", "usb_device_failed_load": "Klarte ikke å laste inn USB-enheter: {error}", "usb_device_failed_set": "Kunne ikke angi USB-enheter: {error}", - "usb_device_keyboard_mouse_and_mass_storage": "Tastatur, mus og masselagring", + "usb_device_keyboard_mouse_mass_storage_and_audio": "Tastatur, mus, masselagring og lyd", "usb_device_keyboard_only": "Kun tastatur", "usb_device_restore_default": "Gjenopprett til standard", "usb_device_title": "USB-enhet", diff --git a/ui/localization/messages/pt.json b/ui/localization/messages/pt.json index 67dff9009..9f1874a54 100644 --- a/ui/localization/messages/pt.json +++ b/ui/localization/messages/pt.json @@ -168,6 +168,8 @@ "audio_enable_title": "Ativar áudio", "audio_page_description": "Transmita o áudio do host para o navegador", "audio_title": "Áudio", + "audio_usb_device_disabled_hint": "O áudio USB está desativado em Dispositivos USB.", + "audio_usb_device_disabled_link": "Ative-o nas definições de hardware.", "auth_authentication_mode": "Selecione um modo de autenticação", "auth_authentication_mode_error": "Ocorreu um erro ao definir o modo de autenticação", "auth_authentication_mode_invalid": "Modo de autenticação inválido", @@ -986,6 +988,8 @@ "usb_device_description": "Dispositivos USB para emular no computador de destino", "usb_device_enable_absolute_mouse_description": "Ativar Mouse Absoluto (Ponteiro)", "usb_device_enable_absolute_mouse_title": "Ativar Mouse Absoluto (Ponteiro)", + "usb_device_enable_audio_description": "Permita que o JetKVM apresente um dispositivo de áudio quando o áudio estiver ativado.", + "usb_device_enable_audio_title": "Ativar áudio USB", "usb_device_enable_keyboard_description": "Ativar Teclado", "usb_device_enable_keyboard_title": "Ativar Teclado", "usb_device_enable_mass_storage_description": "Às vezes pode ser necessário desativar para evitar problemas com certos dispositivos", @@ -996,7 +1000,7 @@ "usb_device_enable_serial_console_title": "Ativar consola série USB", "usb_device_failed_load": "Falha ao carregar dispositivos USB: {error}", "usb_device_failed_set": "Falha ao definir dispositivos USB: {error}", - "usb_device_keyboard_mouse_and_mass_storage": "Teclado, Mouse e Armazenamento em Massa", + "usb_device_keyboard_mouse_mass_storage_and_audio": "Teclado, rato, armazenamento em massa e áudio", "usb_device_keyboard_only": "Apenas Teclado", "usb_device_restore_default": "Restaurar para Padrão", "usb_device_title": "Dispositivo USB", diff --git a/ui/localization/messages/ru.json b/ui/localization/messages/ru.json index 6b255e2fa..c1571cc8b 100644 --- a/ui/localization/messages/ru.json +++ b/ui/localization/messages/ru.json @@ -168,6 +168,8 @@ "audio_enable_title": "Включить аудио", "audio_page_description": "Передача аудио с хоста в браузер", "audio_title": "Аудио", + "audio_usb_device_disabled_hint": "USB-аудио отключено в USB-устройствах.", + "audio_usb_device_disabled_link": "Включите его в настройках оборудования.", "auth_authentication_mode": "Пожалуйста, выберите режим аутентификации", "auth_authentication_mode_error": "Ошибка при установке режима аутентификации", "auth_authentication_mode_invalid": "Недопустимый режим аутентификации", @@ -986,6 +988,8 @@ "usb_device_description": "USB-устройства для эмуляции на целевом компьютере", "usb_device_enable_absolute_mouse_description": "Включить абсолютную мышь (указатель)", "usb_device_enable_absolute_mouse_title": "Включить абсолютную мышь (указатель)", + "usb_device_enable_audio_description": "Разрешить JetKVM предоставлять хосту аудиоустройство, когда аудио включено.", + "usb_device_enable_audio_title": "Включить USB-аудио", "usb_device_enable_keyboard_description": "Включить клавиатуру", "usb_device_enable_keyboard_title": "Включить клавиатуру", "usb_device_enable_mass_storage_description": "Иногда может потребоваться отключить, чтобы избежать проблем с некоторыми устройствами", @@ -996,7 +1000,7 @@ "usb_device_enable_serial_console_title": "Включить последовательную USB-консоль", "usb_device_failed_load": "Не удалось загрузить USB-устройства: {error}", "usb_device_failed_set": "Не удалось установить USB-устройства: {error}", - "usb_device_keyboard_mouse_and_mass_storage": "Клавиатура, мышь и накопитель", + "usb_device_keyboard_mouse_mass_storage_and_audio": "Клавиатура, мышь, накопитель и аудио", "usb_device_keyboard_only": "Только клавиатура", "usb_device_restore_default": "Восстановить по умолчанию", "usb_device_title": "USB-устройство", diff --git a/ui/localization/messages/sv.json b/ui/localization/messages/sv.json index 28e39aa66..e9c311a48 100644 --- a/ui/localization/messages/sv.json +++ b/ui/localization/messages/sv.json @@ -168,6 +168,8 @@ "audio_enable_title": "Aktivera ljud", "audio_page_description": "Strömma ljud från värden till din webbläsare", "audio_title": "Ljud", + "audio_usb_device_disabled_hint": "USB-ljud är avstängt i USB-enheter.", + "audio_usb_device_disabled_link": "Aktivera det i maskinvaruinställningarna.", "auth_authentication_mode": "Välj ett autentiseringsläge", "auth_authentication_mode_error": "Ett fel uppstod när autentiseringsläget ställdes in", "auth_authentication_mode_invalid": "Ogiltigt autentiseringsläge", @@ -986,6 +988,8 @@ "usb_device_description": "USB-enheter att emulera på måldatorn", "usb_device_enable_absolute_mouse_description": "Aktivera absolut mus (pekare)", "usb_device_enable_absolute_mouse_title": "Aktivera absolut mus (pekare)", + "usb_device_enable_audio_description": "Tillåt JetKVM att visa en ljudenhet när ljud är aktiverat.", + "usb_device_enable_audio_title": "Aktivera USB-ljud", "usb_device_enable_keyboard_description": "Aktivera tangentbord", "usb_device_enable_keyboard_title": "Aktivera tangentbord", "usb_device_enable_mass_storage_description": "Ibland kan det behöva inaktiveras för att förhindra problem med vissa enheter.", @@ -996,7 +1000,7 @@ "usb_device_enable_serial_console_title": "Aktivera USB-seriell konsol", "usb_device_failed_load": "Misslyckades med att ladda USB-enheter: {error}", "usb_device_failed_set": "Misslyckades med att ställa in USB-enheter: {error}", - "usb_device_keyboard_mouse_and_mass_storage": "Tangentbord, mus och masslagring", + "usb_device_keyboard_mouse_mass_storage_and_audio": "Tangentbord, mus, masslagring och ljud", "usb_device_keyboard_only": "Endast tangentbord", "usb_device_restore_default": "Återställ till standard", "usb_device_title": "USB-enhet", diff --git a/ui/localization/messages/zh-tw.json b/ui/localization/messages/zh-tw.json index 8a4991e12..85cd7ae24 100644 --- a/ui/localization/messages/zh-tw.json +++ b/ui/localization/messages/zh-tw.json @@ -168,6 +168,8 @@ "audio_enable_title": "啟用音訊", "audio_page_description": "將主機音訊串流到瀏覽器", "audio_title": "音訊", + "audio_usb_device_disabled_hint": "USB 音訊已在 USB 裝置中關閉。", + "audio_usb_device_disabled_link": "在硬體設定中啟用它。", "auth_authentication_mode": "請選擇驗證模式", "auth_authentication_mode_error": "設定驗證模式時發生錯誤", "auth_authentication_mode_invalid": "無效的驗證模式", @@ -986,6 +988,8 @@ "usb_device_description": "在目標電腦上模擬的 USB 裝置", "usb_device_enable_absolute_mouse_description": "啟用絕對滑鼠 (指標)", "usb_device_enable_absolute_mouse_title": "啟用絕對滑鼠 (指標)", + "usb_device_enable_audio_description": "允許 JetKVM 在啟用音訊時向主機呈現音訊裝置。", + "usb_device_enable_audio_title": "啟用 USB 音訊", "usb_device_enable_keyboard_description": "啟用鍵盤", "usb_device_enable_keyboard_title": "啟用鍵盤", "usb_device_enable_mass_storage_description": "有時可能需要停用它以防止特定裝置的問題", @@ -996,7 +1000,7 @@ "usb_device_enable_serial_console_title": "啟用 USB 序列主控台", "usb_device_failed_load": "載入 USB 裝置失敗:{error}", "usb_device_failed_set": "設定 USB 裝置失敗:{error}", - "usb_device_keyboard_mouse_and_mass_storage": "鍵盤、滑鼠和大量儲存裝置", + "usb_device_keyboard_mouse_mass_storage_and_audio": "鍵盤、滑鼠、大容量儲存和音訊", "usb_device_keyboard_only": "僅鍵盤", "usb_device_restore_default": "還原為預設值", "usb_device_title": "USB 裝置", diff --git a/ui/localization/messages/zh.json b/ui/localization/messages/zh.json index 2ec5b6f83..867d88802 100644 --- a/ui/localization/messages/zh.json +++ b/ui/localization/messages/zh.json @@ -168,6 +168,8 @@ "audio_enable_title": "启用音频", "audio_page_description": "将主机音频流式传输到浏览器", "audio_title": "音频", + "audio_usb_device_disabled_hint": "USB 音频已在 USB 设备中关闭。", + "audio_usb_device_disabled_link": "在硬件设置中启用它。", "auth_authentication_mode": "请选择一种认证模式。", "auth_authentication_mode_error": "设置认证模式时出错。", "auth_authentication_mode_invalid": "无效的认证模式。", @@ -986,6 +988,8 @@ "usb_device_description": "模拟到目标计算机的 USB 设备。", "usb_device_enable_absolute_mouse_description": "启用绝对定位鼠标 (指针)。", "usb_device_enable_absolute_mouse_title": "启用绝对定位鼠标 (指针)", + "usb_device_enable_audio_description": "允许 JetKVM 在启用音频时向主机呈现音频设备。", + "usb_device_enable_audio_title": "启用 USB 音频", "usb_device_enable_keyboard_description": "启用键盘模拟。", "usb_device_enable_keyboard_title": "启用键盘", "usb_device_enable_mass_storage_description": "有时可能需要禁用此项以解决特定设备的兼容性问题。", @@ -996,7 +1000,7 @@ "usb_device_enable_serial_console_title": "启用 USB 串行控制台", "usb_device_failed_load": "加载 USB 设备失败:{error}", "usb_device_failed_set": "设置 USB 设备失败:{error}", - "usb_device_keyboard_mouse_and_mass_storage": "键盘、鼠标和大容量存储", + "usb_device_keyboard_mouse_mass_storage_and_audio": "键盘、鼠标、大容量存储和音频", "usb_device_keyboard_only": "仅键盘", "usb_device_restore_default": "恢复默认", "usb_device_title": "USB 设备", diff --git a/ui/src/components/UsbDeviceSetting.tsx b/ui/src/components/UsbDeviceSetting.tsx index 095912bad..5452922a5 100644 --- a/ui/src/components/UsbDeviceSetting.tsx +++ b/ui/src/components/UsbDeviceSetting.tsx @@ -26,6 +26,7 @@ export interface UsbDeviceConfig { relative_mouse: boolean; mass_storage: boolean; serial_console: boolean; + audio: boolean; } const defaultUsbDeviceConfig: UsbDeviceConfig = { @@ -34,11 +35,12 @@ const defaultUsbDeviceConfig: UsbDeviceConfig = { relative_mouse: true, mass_storage: true, serial_console: false, + audio: true, }; const usbPresets = [ { - label: m.usb_device_keyboard_mouse_and_mass_storage(), + label: m.usb_device_keyboard_mouse_mass_storage_and_audio(), value: "default", config: { keyboard: true, @@ -46,6 +48,7 @@ const usbPresets = [ relative_mouse: true, mass_storage: true, serial_console: false, + audio: true, }, }, { @@ -57,6 +60,7 @@ const usbPresets = [ relative_mouse: false, mass_storage: false, serial_console: false, + audio: false, }, }, { @@ -81,7 +85,10 @@ export function UsbDeviceSetting() { m.usb_device_failed_load({ error: String(resp.error.data || m.unknown_error()) }), ); } else { - const usbConfigState = resp.result as UsbDeviceConfig; + const usbConfigState = { + ...defaultUsbDeviceConfig, + ...(resp.result as UsbDeviceConfig), + }; setUsbDeviceConfig(usbConfigState); setUsbSerialConsoleEnabled(usbConfigState.serial_console); @@ -226,6 +233,17 @@ export function UsbDeviceSetting() { /> +
+ + + +
(null); + const [usbAudioEnabled, setUsbAudioEnabled] = useState(null); useEffect(() => { send("getAudioConfig", {}, (resp: JsonRpcResponse) => { if ("error" in resp) return console.error(resp.error); setEnabled((resp.result as AudioConfig).enabled); }); + + send("getUsbDevices", {}, (resp: JsonRpcResponse) => { + if ("error" in resp) { + console.error(resp.error); + setUsbAudioEnabled(true); + return; + } + setUsbAudioEnabled((resp.result as UsbDeviceConfig).audio !== false); + }); }, [send]); const handleChange = useCallback( @@ -44,20 +60,46 @@ export default function SettingsAudioRoute() { [enabled, send], ); + const audioBlockedByUsb = usbAudioEnabled === false; + return (
- - handleChange(e.target.checked)} - /> - +
+ + handleChange(e.target.checked)} + /> + + {audioBlockedByUsb && ( + +
+
+ +
+ {m.audio_usb_device_disabled_hint()} +
+
+ +
+
+ )} +
); } diff --git a/usb.go b/usb.go index 4e5dc1ab8..843abcabc 100644 --- a/usb.go +++ b/usb.go @@ -10,12 +10,29 @@ import ( var gadget *usbgadget.UsbGadget +func effectiveUsbDevices() *usbgadget.Devices { + if config == nil || config.UsbDevices == nil { + return nil + } + + devices := *config.UsbDevices + devices.Audio = config.AudioEnabled && config.UsbDevices.Audio + return &devices +} + +func effectiveAudioEnabled() bool { + return config != nil && + config.UsbDevices != nil && + config.AudioEnabled && + config.UsbDevices.Audio +} + // initUsbGadget initializes the USB gadget. // call it only after the config is loaded. func initUsbGadget() { gadget = usbgadget.NewUsbGadget( "jetkvm", - config.UsbDevices, + effectiveUsbDevices(), config.UsbConfig, usbLogger, ) diff --git a/webrtc.go b/webrtc.go index 7e438049a..7acd5f1d9 100644 --- a/webrtc.go +++ b/webrtc.go @@ -147,11 +147,11 @@ func negotiateAudioCodec(offerSDP string) string { return "" } -// attachAudioTrack adds an outgoing audio track when the device config has -// audio enabled AND the browser advertised a codec we support. No-op +// attachAudioTrack adds an outgoing audio track when audio is enabled, the USB +// gadget allows audio, and the browser advertised a codec we support. No-op // otherwise; the SDP answer just leaves the audio m-line inactive. func (s *Session) attachAudioTrack(offerSDP string) error { - if !config.AudioEnabled { + if !effectiveAudioEnabled() { webrtcLogger.Debug().Msg("audio disabled by device config") return nil }