mirror of
https://github.com/jetkvm/kvm.git
synced 2025-09-16 08:38:14 +00:00
Add support for dynamic Opus encoder configuration updates without requiring subprocess restart. This allows quality changes to be applied immediately while maintaining audio stream continuity. Optimize audio quality parameters to reduce CPU load and prevent mouse lag on RV1106 devices. Lower bitrates and complexity while adjusting signal types and bandwidths for better performance. Add build tags for CGO requirements and improve audio input supervisor behavior to check for existing processes before starting new ones.
127 lines
3.9 KiB
Go
127 lines
3.9 KiB
Go
//go:build cgo
|
|
// +build cgo
|
|
|
|
package audio
|
|
|
|
/*
|
|
#cgo pkg-config: alsa
|
|
#cgo LDFLAGS: -lopus
|
|
*/
|
|
import "C"
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"os/signal"
|
|
"strconv"
|
|
"syscall"
|
|
"time"
|
|
|
|
"github.com/jetkvm/kvm/internal/logging"
|
|
)
|
|
|
|
// getEnvInt reads an integer from environment variable with a default value
|
|
func getEnvIntInput(key string, defaultValue int) int {
|
|
if value := os.Getenv(key); value != "" {
|
|
if intValue, err := strconv.Atoi(value); err == nil {
|
|
return intValue
|
|
}
|
|
}
|
|
return defaultValue
|
|
}
|
|
|
|
// parseOpusConfigInput reads OPUS configuration from environment variables
|
|
// with fallback to default config values for input server
|
|
func parseOpusConfigInput() (bitrate, complexity, vbr, signalType, bandwidth, dtx int) {
|
|
// Read configuration from environment variables with config defaults
|
|
bitrate = getEnvIntInput("JETKVM_OPUS_BITRATE", GetConfig().CGOOpusBitrate)
|
|
complexity = getEnvIntInput("JETKVM_OPUS_COMPLEXITY", GetConfig().CGOOpusComplexity)
|
|
vbr = getEnvIntInput("JETKVM_OPUS_VBR", GetConfig().CGOOpusVBR)
|
|
signalType = getEnvIntInput("JETKVM_OPUS_SIGNAL_TYPE", GetConfig().CGOOpusSignalType)
|
|
bandwidth = getEnvIntInput("JETKVM_OPUS_BANDWIDTH", GetConfig().CGOOpusBandwidth)
|
|
dtx = getEnvIntInput("JETKVM_OPUS_DTX", GetConfig().CGOOpusDTX)
|
|
|
|
return bitrate, complexity, vbr, signalType, bandwidth, dtx
|
|
}
|
|
|
|
// applyOpusConfigInput applies OPUS configuration to the global config for input server
|
|
func applyOpusConfigInput(bitrate, complexity, vbr, signalType, bandwidth, dtx int) {
|
|
config := GetConfig()
|
|
config.CGOOpusBitrate = bitrate
|
|
config.CGOOpusComplexity = complexity
|
|
config.CGOOpusVBR = vbr
|
|
config.CGOOpusSignalType = signalType
|
|
config.CGOOpusBandwidth = bandwidth
|
|
config.CGOOpusDTX = dtx
|
|
}
|
|
|
|
// RunAudioInputServer runs the audio input server subprocess
|
|
// This should be called from main() when the subprocess is detected
|
|
func RunAudioInputServer() error {
|
|
logger := logging.GetDefaultLogger().With().Str("component", "audio-input-server").Logger()
|
|
logger.Debug().Msg("audio input server subprocess starting")
|
|
|
|
// Parse OPUS configuration from environment variables
|
|
bitrate, complexity, vbr, signalType, bandwidth, dtx := parseOpusConfigInput()
|
|
applyOpusConfigInput(bitrate, complexity, vbr, signalType, bandwidth, dtx)
|
|
|
|
// Initialize validation cache for optimal performance
|
|
InitValidationCache()
|
|
|
|
// Start adaptive buffer management for optimal performance
|
|
StartAdaptiveBuffering()
|
|
defer StopAdaptiveBuffering()
|
|
|
|
// Initialize CGO audio playback (optional for input server)
|
|
// This is used for audio loopback/monitoring features
|
|
err := CGOAudioPlaybackInit()
|
|
if err != nil {
|
|
logger.Warn().Err(err).Msg("failed to initialize CGO audio playback - audio monitoring disabled")
|
|
// Continue without playback - input functionality doesn't require it
|
|
} else {
|
|
defer CGOAudioPlaybackClose()
|
|
logger.Debug().Msg("CGO audio playback initialized successfully")
|
|
}
|
|
|
|
// Create and start the IPC server
|
|
server, err := NewAudioInputServer()
|
|
if err != nil {
|
|
logger.Error().Err(err).Msg("failed to create audio input server")
|
|
return err
|
|
}
|
|
defer server.Close()
|
|
|
|
err = server.Start()
|
|
if err != nil {
|
|
logger.Error().Err(err).Msg("failed to start audio input server")
|
|
return err
|
|
}
|
|
|
|
logger.Debug().Msg("audio input server started, waiting for connections")
|
|
|
|
// Set up signal handling for graceful shutdown
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
sigChan := make(chan os.Signal, 1)
|
|
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
|
|
|
// Wait for shutdown signal
|
|
select {
|
|
case sig := <-sigChan:
|
|
logger.Info().Str("signal", sig.String()).Msg("received shutdown signal")
|
|
case <-ctx.Done():
|
|
logger.Debug().Msg("context cancelled")
|
|
}
|
|
|
|
// Graceful shutdown
|
|
logger.Debug().Msg("shutting down audio input server")
|
|
server.Stop()
|
|
|
|
// Give some time for cleanup
|
|
time.Sleep(GetConfig().DefaultSleepDuration)
|
|
|
|
logger.Debug().Msg("audio input server subprocess stopped")
|
|
return nil
|
|
}
|