mirror of https://github.com/jetkvm/kvm.git
feat(audio): add real-time USB audio config updates and validation
- Add audio device change listener in UI to update USB config - Implement audio configuration validation before enabling USB audio - Broadcast audio device change events for all state changes
This commit is contained in:
parent
c89d678963
commit
d1c192bf8b
55
jsonrpc.go
55
jsonrpc.go
|
@ -908,7 +908,38 @@ func updateUsbRelatedConfig() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validateAudioConfiguration checks if audio functionality can be enabled
|
||||||
|
func validateAudioConfiguration(enabled bool) error {
|
||||||
|
if !enabled {
|
||||||
|
return nil // Disabling audio is always allowed
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if audio supervisor is available
|
||||||
|
if audioSupervisor == nil {
|
||||||
|
return fmt.Errorf("audio supervisor not initialized - audio functionality not available")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if ALSA devices are available by attempting to list them
|
||||||
|
// This is a basic check to ensure the system has audio capabilities
|
||||||
|
if _, err := os.Stat("/proc/asound/cards"); os.IsNotExist(err) {
|
||||||
|
return fmt.Errorf("no ALSA sound cards detected - audio hardware not available")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if USB gadget audio function is supported
|
||||||
|
if _, err := os.Stat("/sys/kernel/config/usb_gadget"); os.IsNotExist(err) {
|
||||||
|
return fmt.Errorf("USB gadget configfs not available - cannot enable USB audio")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func rpcSetUsbDevices(usbDevices usbgadget.Devices) error {
|
func rpcSetUsbDevices(usbDevices usbgadget.Devices) error {
|
||||||
|
// Validate audio configuration before proceeding
|
||||||
|
if err := validateAudioConfiguration(usbDevices.Audio); err != nil {
|
||||||
|
logger.Warn().Err(err).Msg("audio configuration validation failed")
|
||||||
|
return fmt.Errorf("audio validation failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Check if audio state is changing
|
// Check if audio state is changing
|
||||||
previousAudioEnabled := config.UsbDevices != nil && config.UsbDevices.Audio
|
previousAudioEnabled := config.UsbDevices != nil && config.UsbDevices.Audio
|
||||||
newAudioEnabled := usbDevices.Audio
|
newAudioEnabled := usbDevices.Audio
|
||||||
|
@ -984,6 +1015,11 @@ func rpcSetUsbDevices(usbDevices usbgadget.Devices) error {
|
||||||
broadcaster.BroadcastAudioDeviceChanged(true, "usb_reconfiguration")
|
broadcaster.BroadcastAudioDeviceChanged(true, "usb_reconfiguration")
|
||||||
logger.Info().Msg("broadcasted audio device change event after USB reconfiguration")
|
logger.Info().Msg("broadcasted audio device change event after USB reconfiguration")
|
||||||
}
|
}
|
||||||
|
} else if previousAudioEnabled != newAudioEnabled {
|
||||||
|
// Broadcast audio device change event for disabling audio
|
||||||
|
broadcaster := audio.GetAudioEventBroadcaster()
|
||||||
|
broadcaster.BroadcastAudioDeviceChanged(newAudioEnabled, "usb_reconfiguration")
|
||||||
|
logger.Info().Bool("enabled", newAudioEnabled).Msg("broadcasted audio device change event after USB reconfiguration")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -1000,6 +1036,11 @@ func rpcSetUsbDeviceState(device string, enabled bool) error {
|
||||||
case "massStorage":
|
case "massStorage":
|
||||||
config.UsbDevices.MassStorage = enabled
|
config.UsbDevices.MassStorage = enabled
|
||||||
case "audio":
|
case "audio":
|
||||||
|
// Validate audio configuration before proceeding
|
||||||
|
if err := validateAudioConfiguration(enabled); err != nil {
|
||||||
|
logger.Warn().Err(err).Msg("audio device state validation failed")
|
||||||
|
return fmt.Errorf("audio validation failed: %w", err)
|
||||||
|
}
|
||||||
// Handle audio process management
|
// Handle audio process management
|
||||||
if !enabled {
|
if !enabled {
|
||||||
// Stop audio processes when audio is disabled
|
// Stop audio processes when audio is disabled
|
||||||
|
@ -1047,11 +1088,15 @@ func rpcSetUsbDeviceState(device string, enabled bool) error {
|
||||||
if err := audioSupervisor.Start(); err != nil {
|
if err := audioSupervisor.Start(); err != nil {
|
||||||
logger.Error().Err(err).Msg("failed to start audio supervisor")
|
logger.Error().Err(err).Msg("failed to start audio supervisor")
|
||||||
} else {
|
} else {
|
||||||
// Broadcast audio device change event to notify WebRTC session
|
// Broadcast audio device change event to notify WebRTC session
|
||||||
broadcaster := audio.GetAudioEventBroadcaster()
|
broadcaster := audio.GetAudioEventBroadcaster()
|
||||||
broadcaster.BroadcastAudioDeviceChanged(true, "device_enabled")
|
broadcaster.BroadcastAudioDeviceChanged(true, "device_enabled")
|
||||||
logger.Info().Msg("broadcasted audio device change event after enabling audio device")
|
logger.Info().Msg("broadcasted audio device change event after enabling audio device")
|
||||||
}
|
}
|
||||||
|
// Always broadcast the audio device change event regardless of enable/disable
|
||||||
|
broadcaster := audio.GetAudioEventBroadcaster()
|
||||||
|
broadcaster.BroadcastAudioDeviceChanged(enabled, "device_state_changed")
|
||||||
|
logger.Info().Bool("enabled", enabled).Msg("broadcasted audio device state change event")
|
||||||
}
|
}
|
||||||
config.UsbDevices.Audio = enabled
|
config.UsbDevices.Audio = enabled
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
|
|
||||||
import { JsonRpcResponse, useJsonRpc } from "./useJsonRpc";
|
import { JsonRpcResponse, useJsonRpc } from "./useJsonRpc";
|
||||||
|
import { useAudioEvents } from "./useAudioEvents";
|
||||||
|
|
||||||
export interface UsbDeviceConfig {
|
export interface UsbDeviceConfig {
|
||||||
keyboard: boolean;
|
keyboard: boolean;
|
||||||
|
@ -35,6 +36,15 @@ export function useUsbDeviceConfig() {
|
||||||
});
|
});
|
||||||
}, [send]);
|
}, [send]);
|
||||||
|
|
||||||
|
// Listen for audio device changes to update USB config in real-time
|
||||||
|
const handleAudioDeviceChanged = useCallback(() => {
|
||||||
|
console.log('[useUsbDeviceConfig] Audio device changed, refetching USB config');
|
||||||
|
fetchUsbDeviceConfig();
|
||||||
|
}, [fetchUsbDeviceConfig]);
|
||||||
|
|
||||||
|
// Subscribe to audio events for real-time updates
|
||||||
|
useAudioEvents(handleAudioDeviceChanged);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchUsbDeviceConfig();
|
fetchUsbDeviceConfig();
|
||||||
}, [fetchUsbDeviceConfig]);
|
}, [fetchUsbDeviceConfig]);
|
||||||
|
|
Loading…
Reference in New Issue