mirror of https://github.com/jetkvm/kvm.git
Fix USB Audio Gadget sample rate constraints
USB Audio Gadget (hw:1,0) hardware only supports 48kHz for both capture and playback due to configfs p_srate/c_srate being hardcoded. This commit ensures both audio paths respect this hardware limitation: - Output path: Force 48kHz when using hw:1,0, allow configurable rates for HDMI - Input path: Always use 48kHz regardless of UI configuration - Calculate frame size dynamically based on actual sample rate used Also removes redundant comments that don't add debugging or maintainability value.
This commit is contained in:
parent
57baa14ee6
commit
2040db6094
6
audio.go
6
audio.go
|
|
@ -49,28 +49,24 @@ func initAudio() {
|
|||
func getAudioConfig() audio.AudioConfig {
|
||||
cfg := audio.DefaultAudioConfig()
|
||||
|
||||
// Apply bitrate (64-256 kbps)
|
||||
if config.AudioBitrate >= 64 && config.AudioBitrate <= 256 {
|
||||
cfg.Bitrate = uint16(config.AudioBitrate)
|
||||
} else if config.AudioBitrate != 0 {
|
||||
audioLogger.Warn().Int("bitrate", config.AudioBitrate).Msg("Invalid audio bitrate, using default")
|
||||
}
|
||||
|
||||
// Apply complexity (0-10)
|
||||
if config.AudioComplexity >= 0 && config.AudioComplexity <= 10 {
|
||||
cfg.Complexity = uint8(config.AudioComplexity)
|
||||
} else if config.AudioComplexity != 0 {
|
||||
audioLogger.Warn().Int("complexity", config.AudioComplexity).Msg("Invalid audio complexity, using default")
|
||||
}
|
||||
|
||||
// Apply buffer periods (2-24)
|
||||
if config.AudioBufferPeriods >= 2 && config.AudioBufferPeriods <= 24 {
|
||||
cfg.BufferPeriods = uint8(config.AudioBufferPeriods)
|
||||
} else if config.AudioBufferPeriods != 0 {
|
||||
audioLogger.Warn().Int("buffer_periods", config.AudioBufferPeriods).Msg("Invalid buffer periods, using default")
|
||||
}
|
||||
|
||||
// Apply sample rate (Opus supports: 8k, 12k, 16k, 24k, 48k)
|
||||
switch config.AudioSampleRate {
|
||||
case 8000, 12000, 16000, 24000, 48000:
|
||||
cfg.SampleRate = uint32(config.AudioSampleRate)
|
||||
|
|
@ -80,7 +76,6 @@ func getAudioConfig() audio.AudioConfig {
|
|||
}
|
||||
}
|
||||
|
||||
// Apply packet loss percentage (0-100)
|
||||
if config.AudioPacketLossPerc >= 0 && config.AudioPacketLossPerc <= 100 {
|
||||
cfg.PacketLossPerc = uint8(config.AudioPacketLossPerc)
|
||||
} else if config.AudioPacketLossPerc != 0 {
|
||||
|
|
@ -118,7 +113,6 @@ func startAudio() error {
|
|||
inputErr = startInputAudioUnderMutex(getAlsaDevice("usb"))
|
||||
}
|
||||
|
||||
// Simplified error handling - both errors are worth reporting
|
||||
if outputErr != nil || inputErr != nil {
|
||||
if outputErr != nil && inputErr != nil {
|
||||
return fmt.Errorf("audio start failed - output: %w, input: %v", outputErr, inputErr)
|
||||
|
|
|
|||
|
|
@ -83,7 +83,13 @@ func (c *CgoSource) Connect() error {
|
|||
func (c *CgoSource) connectOutput() error {
|
||||
os.Setenv("ALSA_CAPTURE_DEVICE", c.alsaDevice)
|
||||
|
||||
frameSize := uint16(c.config.SampleRate * 20 / 1000)
|
||||
// USB Audio Gadget (hw:1,0) only supports 48kHz
|
||||
// For HDMI (hw:0,0), use configured sample rate
|
||||
sampleRate := c.config.SampleRate
|
||||
if c.alsaDevice == "hw:1,0" {
|
||||
sampleRate = 48000
|
||||
}
|
||||
frameSize := uint16(sampleRate * 20 / 1000)
|
||||
|
||||
c.logger.Debug().
|
||||
Uint16("bitrate_kbps", c.config.Bitrate).
|
||||
|
|
@ -91,7 +97,7 @@ func (c *CgoSource) connectOutput() error {
|
|||
Bool("dtx", c.config.DTXEnabled).
|
||||
Bool("fec", c.config.FECEnabled).
|
||||
Uint8("buffer_periods", c.config.BufferPeriods).
|
||||
Uint32("sample_rate", c.config.SampleRate).
|
||||
Uint32("sample_rate", sampleRate).
|
||||
Uint16("frame_size", frameSize).
|
||||
Uint8("packet_loss_perc", c.config.PacketLossPerc).
|
||||
Msg("Initializing audio capture")
|
||||
|
|
@ -99,7 +105,7 @@ func (c *CgoSource) connectOutput() error {
|
|||
C.update_audio_constants(
|
||||
C.uint(uint32(c.config.Bitrate)*1000),
|
||||
C.uchar(c.config.Complexity),
|
||||
C.uint(c.config.SampleRate),
|
||||
C.uint(sampleRate),
|
||||
C.uchar(2),
|
||||
C.ushort(frameSize),
|
||||
C.ushort(1500),
|
||||
|
|
@ -125,10 +131,13 @@ func (c *CgoSource) connectOutput() error {
|
|||
func (c *CgoSource) connectInput() error {
|
||||
os.Setenv("ALSA_PLAYBACK_DEVICE", c.alsaDevice)
|
||||
|
||||
frameSize := uint16(c.config.SampleRate * 20 / 1000)
|
||||
// USB Audio Gadget (hw:1,0) is hardcoded to 48kHz in usbgadget/config.go
|
||||
// Always use 48kHz for input path regardless of UI configuration
|
||||
const inputSampleRate = 48000
|
||||
frameSize := uint16(inputSampleRate * 20 / 1000)
|
||||
|
||||
C.update_audio_decoder_constants(
|
||||
C.uint(c.config.SampleRate),
|
||||
C.uint(inputSampleRate),
|
||||
C.uchar(1),
|
||||
C.ushort(frameSize),
|
||||
C.ushort(1500),
|
||||
|
|
|
|||
|
|
@ -20,18 +20,15 @@ interface AudioConfigResult {
|
|||
packet_loss_perc: number;
|
||||
}
|
||||
|
||||
// UI display defaults - used to mark default options in dropdown menus
|
||||
// Note: These should match backend defaults in config.go, but are fetched dynamically from API
|
||||
const AUDIO_DEFAULTS = {
|
||||
bitrate: 192,
|
||||
complexity: 8,
|
||||
packetLossPerc: 20, // Backend default is 20, not 0
|
||||
packetLossPerc: 20,
|
||||
} as const;
|
||||
|
||||
export default function SettingsAudioRoute() {
|
||||
const { send } = useJsonRpc();
|
||||
|
||||
// Helper function to handle RPC errors consistently
|
||||
const handleRpcError = (resp: JsonRpcResponse, defaultMsg?: string) => {
|
||||
if ("error" in resp) {
|
||||
notifications.error(String(resp.error.data || defaultMsg || m.unknown_error()));
|
||||
|
|
@ -64,7 +61,6 @@ export default function SettingsAudioRoute() {
|
|||
} = useSettingsStore();
|
||||
|
||||
useEffect(() => {
|
||||
// Load boolean settings
|
||||
send("getAudioOutputEnabled", {}, (resp: JsonRpcResponse) => {
|
||||
if ("error" in resp) return;
|
||||
setAudioOutputEnabled(resp.result as boolean);
|
||||
|
|
@ -80,7 +76,6 @@ export default function SettingsAudioRoute() {
|
|||
setAudioOutputSource(resp.result as string);
|
||||
});
|
||||
|
||||
// Load complex audio configuration
|
||||
send("getAudioConfig", {}, (resp: JsonRpcResponse) => {
|
||||
if ("error" in resp) return;
|
||||
const config = resp.result as AudioConfigResult;
|
||||
|
|
@ -137,7 +132,6 @@ export default function SettingsAudioRoute() {
|
|||
});
|
||||
};
|
||||
|
||||
// Create a configuration object from current state
|
||||
const getCurrentConfig = () => ({
|
||||
bitrate: audioBitrate,
|
||||
complexity: audioComplexity,
|
||||
|
|
|
|||
Loading…
Reference in New Issue