From 35a666ed312d95076028147072f7301f6806996f Mon Sep 17 00:00:00 2001 From: Alex P Date: Mon, 25 Aug 2025 18:08:12 +0000 Subject: [PATCH] refactor(audio): centralize configuration constants in audio module Replace hardcoded values with centralized config constants for better maintainability and flexibility. This includes sleep durations, buffer sizes, thresholds, and various audio processing parameters. The changes affect multiple components including buffer pools, latency monitoring, IPC, and audio processing. This refactoring makes it easier to adjust parameters without modifying individual files. Key changes: - Replace hardcoded sleep durations with config values - Centralize buffer sizes and pool configurations - Move thresholds and limits to config - Update audio quality presets to use config values --- internal/audio/adaptive_buffer.go | 24 +- internal/audio/adaptive_optimizer.go | 10 +- internal/audio/audio.go | 34 +- internal/audio/batch_audio.go | 8 +- internal/audio/buffer_pool.go | 10 +- internal/audio/cgo_audio.go | 70 +- internal/audio/config_constants.go | 1213 ++++++++++++++++++++++++-- internal/audio/input_ipc.go | 33 +- internal/audio/input_ipc_manager.go | 8 +- internal/audio/input_server_main.go | 2 +- internal/audio/input_supervisor.go | 4 +- internal/audio/ipc.go | 36 +- internal/audio/latency_monitor.go | 6 +- internal/audio/memory_metrics.go | 4 +- internal/audio/metrics.go | 2 +- internal/audio/mic_contention.go | 4 +- internal/audio/output_server_main.go | 2 +- internal/audio/output_streaming.go | 16 +- internal/audio/priority_scheduler.go | 53 +- internal/audio/process_monitor.go | 39 +- internal/audio/relay.go | 2 +- internal/audio/socket_buffer.go | 31 +- internal/audio/supervisor.go | 4 +- internal/audio/zero_copy.go | 2 +- 24 files changed, 1372 insertions(+), 245 deletions(-) diff --git a/internal/audio/adaptive_buffer.go b/internal/audio/adaptive_buffer.go index 057532b..64fbc06 100644 --- a/internal/audio/adaptive_buffer.go +++ b/internal/audio/adaptive_buffer.go @@ -42,20 +42,20 @@ func DefaultAdaptiveBufferConfig() AdaptiveBufferConfig { DefaultBufferSize: 6, // Default 6 frames (increased for better stability) // CPU thresholds optimized for single-core ARM Cortex A7 under load - LowCPUThreshold: 20.0, // Below 20% CPU - HighCPUThreshold: 60.0, // Above 60% CPU (lowered to be more responsive) + LowCPUThreshold: GetConfig().LowCPUThreshold * 100, // Below 20% CPU + HighCPUThreshold: GetConfig().HighCPUThreshold * 100, // Above 60% CPU (lowered to be more responsive) // Memory thresholds for 256MB total RAM - LowMemoryThreshold: 35.0, // Below 35% memory usage - HighMemoryThreshold: 75.0, // Above 75% memory usage (lowered for earlier response) + LowMemoryThreshold: GetConfig().LowMemoryThreshold * 100, // Below 35% memory usage + HighMemoryThreshold: GetConfig().HighMemoryThreshold * 100, // Above 75% memory usage (lowered for earlier response) // Latency targets - TargetLatency: 20 * time.Millisecond, // Target 20ms latency - MaxLatency: 50 * time.Millisecond, // Max acceptable 50ms + TargetLatency: GetConfig().TargetLatency, // Target 20ms latency + MaxLatency: GetConfig().MaxLatencyTarget, // Max acceptable latency // Adaptation settings - AdaptationInterval: 500 * time.Millisecond, // Check every 500ms - SmoothingFactor: 0.3, // Moderate responsiveness + AdaptationInterval: GetConfig().BufferUpdateInterval, // Check every 500ms + SmoothingFactor: GetConfig().SmoothingFactor, // Moderate responsiveness } } @@ -133,7 +133,7 @@ func (abm *AdaptiveBufferManager) UpdateLatency(latency time.Duration) { atomic.StoreInt64(&abm.averageLatency, newLatency) } else { // Exponential moving average: 70% historical, 30% current - newAvg := int64(float64(currentAvg)*0.7 + float64(newLatency)*0.3) + newAvg := int64(float64(currentAvg)*GetConfig().HistoricalWeight + float64(newLatency)*GetConfig().CurrentWeight) atomic.StoreInt64(&abm.averageLatency, newAvg) } } @@ -195,7 +195,7 @@ func (abm *AdaptiveBufferManager) adaptBufferSizes() { latencyFactor := abm.calculateLatencyFactor(currentLatency) // Combine factors with weights (CPU has highest priority for KVM coexistence) - combinedFactor := 0.5*cpuFactor + 0.3*memoryFactor + 0.2*latencyFactor + combinedFactor := GetConfig().CPUMemoryWeight*cpuFactor + GetConfig().MemoryWeight*memoryFactor + GetConfig().LatencyWeight*latencyFactor // Apply adaptation with smoothing currentInput := float64(atomic.LoadInt64(&abm.currentInputBufferSize)) @@ -306,8 +306,8 @@ func (abm *AdaptiveBufferManager) GetStats() map[string]interface{} { "input_buffer_size": abm.GetInputBufferSize(), "output_buffer_size": abm.GetOutputBufferSize(), "average_latency_ms": float64(atomic.LoadInt64(&abm.averageLatency)) / 1e6, - "system_cpu_percent": float64(atomic.LoadInt64(&abm.systemCPUPercent)) / 100, - "system_memory_percent": float64(atomic.LoadInt64(&abm.systemMemoryPercent)) / 100, + "system_cpu_percent": float64(atomic.LoadInt64(&abm.systemCPUPercent)) / GetConfig().PercentageMultiplier, + "system_memory_percent": float64(atomic.LoadInt64(&abm.systemMemoryPercent)) / GetConfig().PercentageMultiplier, "adaptation_count": atomic.LoadInt64(&abm.adaptationCount), "last_adaptation": lastAdaptation, } diff --git a/internal/audio/adaptive_optimizer.go b/internal/audio/adaptive_optimizer.go index e9ac814..89fdf70 100644 --- a/internal/audio/adaptive_optimizer.go +++ b/internal/audio/adaptive_optimizer.go @@ -42,9 +42,9 @@ type OptimizerConfig struct { func DefaultOptimizerConfig() OptimizerConfig { return OptimizerConfig{ MaxOptimizationLevel: 8, - CooldownPeriod: 30 * time.Second, - Aggressiveness: 0.7, - RollbackThreshold: 300 * time.Millisecond, + CooldownPeriod: GetConfig().CooldownPeriod, + Aggressiveness: GetConfig().OptimizerAggressiveness, + RollbackThreshold: GetConfig().RollbackThreshold, StabilityPeriod: 10 * time.Second, } } @@ -109,7 +109,7 @@ func (ao *AdaptiveOptimizer) handleLatencyOptimization(metrics LatencyMetrics) e // calculateTargetOptimizationLevel determines the appropriate optimization level func (ao *AdaptiveOptimizer) calculateTargetOptimizationLevel(metrics LatencyMetrics) int64 { // Base calculation on current latency vs target - latencyRatio := float64(metrics.Current) / float64(50*time.Millisecond) // 50ms target + latencyRatio := float64(metrics.Current) / float64(GetConfig().LatencyTarget) // 50ms target // Adjust based on trend switch metrics.Trend { @@ -125,7 +125,7 @@ func (ao *AdaptiveOptimizer) calculateTargetOptimizationLevel(metrics LatencyMet latencyRatio *= ao.config.Aggressiveness // Convert to optimization level - targetLevel := int64(latencyRatio * 2) // Scale to 0-10 range + targetLevel := int64(latencyRatio * GetConfig().LatencyScalingFactor) // Scale to 0-10 range if targetLevel > int64(ao.config.MaxOptimizationLevel) { targetLevel = int64(ao.config.MaxOptimizationLevel) } diff --git a/internal/audio/audio.go b/internal/audio/audio.go index 243899a..90fc1ed 100644 --- a/internal/audio/audio.go +++ b/internal/audio/audio.go @@ -47,17 +47,17 @@ type AudioMetrics struct { var ( currentConfig = AudioConfig{ Quality: AudioQualityMedium, - Bitrate: 64, + Bitrate: GetConfig().AudioQualityMediumOutputBitrate, SampleRate: GetConfig().SampleRate, Channels: GetConfig().Channels, - FrameSize: 20 * time.Millisecond, + FrameSize: GetConfig().AudioQualityMediumFrameSize, } currentMicrophoneConfig = AudioConfig{ Quality: AudioQualityMedium, - Bitrate: 32, + Bitrate: GetConfig().AudioQualityMediumInputBitrate, SampleRate: GetConfig().SampleRate, Channels: 1, - FrameSize: 20 * time.Millisecond, + FrameSize: GetConfig().AudioQualityMediumFrameSize, } metrics AudioMetrics ) @@ -69,24 +69,24 @@ var qualityPresets = map[AudioQuality]struct { frameSize time.Duration }{ AudioQualityLow: { - outputBitrate: 32, inputBitrate: 16, - sampleRate: 22050, channels: 1, - frameSize: 40 * time.Millisecond, + outputBitrate: GetConfig().AudioQualityLowOutputBitrate, inputBitrate: GetConfig().AudioQualityLowInputBitrate, + sampleRate: GetConfig().AudioQualityLowSampleRate, channels: GetConfig().AudioQualityLowChannels, + frameSize: GetConfig().AudioQualityLowFrameSize, }, AudioQualityMedium: { - outputBitrate: 64, inputBitrate: 32, - sampleRate: 44100, channels: 2, - frameSize: 20 * time.Millisecond, + outputBitrate: GetConfig().AudioQualityMediumOutputBitrate, inputBitrate: GetConfig().AudioQualityMediumInputBitrate, + sampleRate: GetConfig().AudioQualityMediumSampleRate, channels: GetConfig().AudioQualityMediumChannels, + frameSize: GetConfig().AudioQualityMediumFrameSize, }, AudioQualityHigh: { - outputBitrate: 128, inputBitrate: 64, - sampleRate: GetConfig().SampleRate, channels: GetConfig().Channels, - frameSize: 20 * time.Millisecond, + outputBitrate: GetConfig().AudioQualityHighOutputBitrate, inputBitrate: GetConfig().AudioQualityHighInputBitrate, + sampleRate: GetConfig().SampleRate, channels: GetConfig().AudioQualityHighChannels, + frameSize: GetConfig().AudioQualityHighFrameSize, }, AudioQualityUltra: { - outputBitrate: 192, inputBitrate: 96, - sampleRate: GetConfig().SampleRate, channels: GetConfig().Channels, - frameSize: 10 * time.Millisecond, + outputBitrate: GetConfig().AudioQualityUltraOutputBitrate, inputBitrate: GetConfig().AudioQualityUltraInputBitrate, + sampleRate: GetConfig().SampleRate, channels: GetConfig().AudioQualityUltraChannels, + frameSize: GetConfig().AudioQualityUltraFrameSize, }, } @@ -114,7 +114,7 @@ func GetMicrophoneQualityPresets() map[AudioQuality]AudioConfig { Bitrate: preset.inputBitrate, SampleRate: func() int { if quality == AudioQualityLow { - return 16000 + return GetConfig().AudioQualityMicLowSampleRate } return preset.sampleRate }(), diff --git a/internal/audio/batch_audio.go b/internal/audio/batch_audio.go index 253e94c..9e9dc29 100644 --- a/internal/audio/batch_audio.go +++ b/internal/audio/batch_audio.go @@ -72,7 +72,7 @@ func NewBatchAudioProcessor(batchSize int, batchDuration time.Duration) *BatchAu readQueue: make(chan batchReadRequest, batchSize*2), readBufPool: &sync.Pool{ New: func() interface{} { - return make([]byte, 1500) // Max audio frame size + return make([]byte, GetConfig().AudioFramePoolSize) // Max audio frame size }, }, } @@ -110,7 +110,7 @@ func (bap *BatchAudioProcessor) Stop() { bap.cancel() // Wait for processing to complete - time.Sleep(bap.batchDuration + 10*time.Millisecond) + time.Sleep(bap.batchDuration + GetConfig().BatchProcessingDelay) bap.logger.Info().Msg("batch audio processor stopped") } @@ -134,7 +134,7 @@ func (bap *BatchAudioProcessor) BatchReadEncode(buffer []byte) (int, error) { select { case bap.readQueue <- request: // Successfully queued - case <-time.After(5 * time.Millisecond): + case <-time.After(GetConfig().ShortTimeout): // Queue is full or blocked, fallback to single operation atomic.AddInt64(&bap.stats.SingleReads, 1) atomic.AddInt64(&bap.stats.SingleFrames, 1) @@ -145,7 +145,7 @@ func (bap *BatchAudioProcessor) BatchReadEncode(buffer []byte) (int, error) { select { case result := <-resultChan: return result.length, result.err - case <-time.After(50 * time.Millisecond): + case <-time.After(GetConfig().MediumTimeout): // Timeout, fallback to single operation atomic.AddInt64(&bap.stats.SingleReads, 1) atomic.AddInt64(&bap.stats.SingleFrames, 1) diff --git a/internal/audio/buffer_pool.go b/internal/audio/buffer_pool.go index cf26e28..c9ab45f 100644 --- a/internal/audio/buffer_pool.go +++ b/internal/audio/buffer_pool.go @@ -23,7 +23,7 @@ type AudioBufferPool struct { func NewAudioBufferPool(bufferSize int) *AudioBufferPool { // Pre-allocate 20% of max pool size for immediate availability - preallocSize := 20 + preallocSize := GetConfig().PreallocPercentage preallocated := make([]*[]byte, 0, preallocSize) // Pre-allocate buffers to reduce initial allocation overhead @@ -34,7 +34,7 @@ func NewAudioBufferPool(bufferSize int) *AudioBufferPool { return &AudioBufferPool{ bufferSize: bufferSize, - maxPoolSize: 100, // Limit pool size to prevent excessive memory usage + maxPoolSize: GetConfig().MaxPoolSize, // Limit pool size to prevent excessive memory usage preallocated: preallocated, preallocSize: preallocSize, pool: sync.Pool{ @@ -111,8 +111,8 @@ func (p *AudioBufferPool) Put(buf []byte) { } var ( - audioFramePool = NewAudioBufferPool(1500) - audioControlPool = NewAudioBufferPool(64) + audioFramePool = NewAudioBufferPool(GetConfig().AudioFramePoolSize) + audioControlPool = NewAudioBufferPool(GetConfig().OutputHeaderSize) ) func GetAudioFrameBuffer() []byte { @@ -144,7 +144,7 @@ func (p *AudioBufferPool) GetPoolStats() AudioBufferPoolDetailedStats { var hitRate float64 if totalRequests > 0 { - hitRate = float64(hitCount) / float64(totalRequests) * 100 + hitRate = float64(hitCount) / float64(totalRequests) * GetConfig().PercentageMultiplier } return AudioBufferPoolDetailedStats{ diff --git a/internal/audio/cgo_audio.go b/internal/audio/cgo_audio.go index 63016fc..f480b9a 100644 --- a/internal/audio/cgo_audio.go +++ b/internal/audio/cgo_audio.go @@ -22,18 +22,37 @@ static snd_pcm_t *pcm_handle = NULL; static snd_pcm_t *pcm_playback_handle = NULL; static OpusEncoder *encoder = NULL; static OpusDecoder *decoder = NULL; -// Optimized Opus encoder settings for ARM Cortex-A7 -static int opus_bitrate = 96000; // Increased for better quality -static int opus_complexity = 3; // Reduced for ARM performance -static int opus_vbr = 1; // Variable bitrate enabled -static int opus_vbr_constraint = 1; // Constrained VBR for consistent latency -static int opus_signal_type = OPUS_SIGNAL_MUSIC; // Optimized for general audio -static int opus_bandwidth = OPUS_BANDWIDTH_FULLBAND; // Full bandwidth -static int opus_dtx = 0; // Disable DTX for real-time audio -static int sample_rate = 48000; -static int channels = 2; -static int frame_size = 960; // 20ms for 48kHz -static int max_packet_size = 1500; +// Opus encoder settings - initialized from Go configuration +static int opus_bitrate = 96000; // Will be set from GetConfig().CGOOpusBitrate +static int opus_complexity = 3; // Will be set from GetConfig().CGOOpusComplexity +static int opus_vbr = 1; // Will be set from GetConfig().CGOOpusVBR +static int opus_vbr_constraint = 1; // Will be set from GetConfig().CGOOpusVBRConstraint +static int opus_signal_type = 3; // Will be set from GetConfig().CGOOpusSignalType +static int opus_bandwidth = 1105; // Will be set from GetConfig().CGOOpusBandwidth +static int opus_dtx = 0; // Will be set from GetConfig().CGOOpusDTX +static int sample_rate = 48000; // Will be set from GetConfig().CGOSampleRate +static int channels = 2; // Will be set from GetConfig().CGOChannels +static int frame_size = 960; // Will be set from GetConfig().CGOFrameSize +static int max_packet_size = 1500; // Will be set from GetConfig().CGOMaxPacketSize +static int sleep_microseconds = 50000; // Will be set from GetConfig().CGOSleepMicroseconds + +// Function to update constants from Go configuration +void update_audio_constants(int bitrate, int complexity, int vbr, int vbr_constraint, + int signal_type, int bandwidth, int dtx, int sr, int ch, + int fs, int max_pkt, int sleep_us) { + opus_bitrate = bitrate; + opus_complexity = complexity; + opus_vbr = vbr; + opus_vbr_constraint = vbr_constraint; + opus_signal_type = signal_type; + opus_bandwidth = bandwidth; + opus_dtx = dtx; + sample_rate = sr; + channels = ch; + frame_size = fs; + max_packet_size = max_pkt; + sleep_microseconds = sleep_us; +} // State tracking to prevent race conditions during rapid start/stop static volatile int capture_initializing = 0; @@ -56,7 +75,7 @@ static int safe_alsa_open(snd_pcm_t **handle, const char *device, snd_pcm_stream if (err == -EBUSY && attempts > 0) { // Device busy, wait and retry - usleep(50000); // 50ms + usleep(sleep_microseconds); // 50ms continue; } break; @@ -415,8 +434,25 @@ var ( ) func cgoAudioInit() error { - ret := C.jetkvm_audio_init() - if ret != 0 { + // Update C constants from Go configuration + config := GetConfig() + C.update_audio_constants( + C.int(config.CGOOpusBitrate), + C.int(config.CGOOpusComplexity), + C.int(config.CGOOpusVBR), + C.int(config.CGOOpusVBRConstraint), + C.int(config.CGOOpusSignalType), + C.int(config.CGOOpusBandwidth), + C.int(config.CGOOpusDTX), + C.int(config.CGOSampleRate), + C.int(config.CGOChannels), + C.int(config.CGOFrameSize), + C.int(config.CGOMaxPacketSize), + C.int(config.CGOSleepMicroseconds), + ) + + result := C.jetkvm_audio_init() + if result != 0 { return errAudioInitFailed } return nil @@ -427,7 +463,7 @@ func cgoAudioClose() { } func cgoAudioReadEncode(buf []byte) (int, error) { - if len(buf) < 1276 { + if len(buf) < GetConfig().MinReadEncodeBuffer { return 0, errBufferTooSmall } @@ -461,7 +497,7 @@ func cgoAudioDecodeWrite(buf []byte) (int, error) { if buf == nil { return 0, errNilBuffer } - if len(buf) > 4096 { + if len(buf) > GetConfig().MaxDecodeWriteBuffer { return 0, errBufferTooLarge } diff --git a/internal/audio/config_constants.go b/internal/audio/config_constants.go index b1a956c..b09e5aa 100644 --- a/internal/audio/config_constants.go +++ b/internal/audio/config_constants.go @@ -2,53 +2,695 @@ package audio import "time" -// AudioConfigConstants centralizes all hardcoded values used across audio components +// AudioConfigConstants centralizes all hardcoded values used across audio components. +// This configuration system allows runtime tuning of audio performance, quality, and resource usage. +// Each constant is documented with its purpose, usage location, and impact on system behavior. type AudioConfigConstants struct { // Audio Quality Presets + // MaxAudioFrameSize defines the maximum size of an audio frame in bytes. + // Used in: buffer_pool.go, adaptive_buffer.go + // Impact: Higher values allow larger audio chunks but increase memory usage and latency. + // Typical range: 1024-8192 bytes. Default 4096 provides good balance. MaxAudioFrameSize int - // Opus Encoding Parameters - OpusBitrate int - OpusComplexity int - OpusVBR int - OpusVBRConstraint int - OpusDTX int + // Opus Encoding Parameters - Core codec settings for audio compression + // OpusBitrate sets the target bitrate for Opus encoding in bits per second. + // Used in: cgo_audio.go for encoder initialization + // Impact: Higher bitrates improve audio quality but increase bandwidth usage. + // Range: 6000-510000 bps. 128000 (128kbps) provides high quality for most use cases. + OpusBitrate int - // Audio Parameters - SampleRate int - Channels int - FrameSize int + // OpusComplexity controls the computational complexity of Opus encoding (0-10). + // Used in: cgo_audio.go for encoder configuration + // Impact: Higher values improve quality but increase CPU usage and encoding latency. + // Range: 0-10. Value 10 provides best quality, 0 fastest encoding. + OpusComplexity int + + // OpusVBR enables Variable Bit Rate encoding (0=CBR, 1=VBR). + // Used in: cgo_audio.go for encoder mode selection + // Impact: VBR (1) adapts bitrate to content complexity, improving efficiency. + // CBR (0) maintains constant bitrate for predictable bandwidth usage. + OpusVBR int + + // OpusVBRConstraint enables constrained VBR mode (0=unconstrained, 1=constrained). + // Used in: cgo_audio.go when VBR is enabled + // Impact: Constrained VBR (1) limits bitrate variation for more predictable bandwidth. + // Unconstrained (0) allows full bitrate adaptation for optimal quality. + OpusVBRConstraint int + + // OpusDTX enables Discontinuous Transmission (0=disabled, 1=enabled). + // Used in: cgo_audio.go for encoder optimization + // Impact: DTX (1) reduces bandwidth during silence but may cause audio artifacts. + // Disabled (0) maintains constant transmission for consistent quality. + OpusDTX int + + // Audio Parameters - Fundamental audio stream characteristics + // SampleRate defines the number of audio samples per second in Hz. + // Used in: All audio processing components + // Impact: Higher rates improve frequency response but increase processing load. + // Common values: 16000 (voice), 44100 (CD quality), 48000 (professional). + SampleRate int + + // Channels specifies the number of audio channels (1=mono, 2=stereo). + // Used in: All audio processing and encoding/decoding operations + // Impact: Stereo (2) provides spatial audio but doubles bandwidth and processing. + // Mono (1) reduces resource usage but loses spatial information. + Channels int + + // FrameSize defines the number of samples per audio frame. + // Used in: Opus encoding/decoding, buffer management + // Impact: Larger frames reduce overhead but increase latency. + // Must match Opus frame sizes: 120, 240, 480, 960, 1920, 2880 samples. + FrameSize int + + // MaxPacketSize sets the maximum size of encoded audio packets in bytes. + // Used in: Network transmission, buffer allocation + // Impact: Larger packets reduce network overhead but increase burst bandwidth. + // Should accommodate worst-case Opus output plus protocol headers. MaxPacketSize int - // Process Management + // Audio Quality Bitrates - Predefined quality presets for different use cases + // These bitrates are used in audio.go for quality level selection + // Impact: Higher bitrates improve audio fidelity but increase bandwidth usage + + // AudioQualityLowOutputBitrate defines bitrate for low-quality audio output (kbps). + // Used in: audio.go for bandwidth-constrained scenarios + // Impact: Minimal bandwidth usage but reduced audio quality. Suitable for voice-only. + // Default 32kbps provides acceptable voice quality with very low bandwidth. + AudioQualityLowOutputBitrate int + + // AudioQualityLowInputBitrate defines bitrate for low-quality audio input (kbps). + // Used in: audio.go for microphone input in low-bandwidth scenarios + // Impact: Reduces upload bandwidth but may affect voice clarity. + // Default 16kbps suitable for basic voice communication. + AudioQualityLowInputBitrate int + + // AudioQualityMediumOutputBitrate defines bitrate for medium-quality audio output (kbps). + // Used in: audio.go for balanced quality/bandwidth scenarios + // Impact: Good balance between quality and bandwidth usage. + // Default 64kbps provides clear voice and acceptable music quality. + AudioQualityMediumOutputBitrate int + + // AudioQualityMediumInputBitrate defines bitrate for medium-quality audio input (kbps). + // Used in: audio.go for microphone input with balanced quality + // Impact: Better voice quality than low setting with moderate bandwidth usage. + // Default 32kbps suitable for clear voice communication. + AudioQualityMediumInputBitrate int + + // AudioQualityHighOutputBitrate defines bitrate for high-quality audio output (kbps). + // Used in: audio.go for high-fidelity audio scenarios + // Impact: Excellent audio quality but higher bandwidth requirements. + // Default 128kbps provides near-CD quality for music and crystal-clear voice. + AudioQualityHighOutputBitrate int + + // AudioQualityHighInputBitrate defines bitrate for high-quality audio input (kbps). + // Used in: audio.go for high-quality microphone capture + // Impact: Superior voice quality but increased upload bandwidth usage. + // Default 64kbps suitable for professional voice communication. + AudioQualityHighInputBitrate int + + // AudioQualityUltraOutputBitrate defines bitrate for ultra-high-quality audio output (kbps). + // Used in: audio.go for maximum quality scenarios + // Impact: Maximum audio fidelity but highest bandwidth consumption. + // Default 192kbps provides studio-quality audio for critical applications. + AudioQualityUltraOutputBitrate int + + // AudioQualityUltraInputBitrate defines bitrate for ultra-high-quality audio input (kbps). + // Used in: audio.go for maximum quality microphone capture + // Impact: Best possible voice quality but maximum upload bandwidth usage. + // Default 96kbps suitable for broadcast-quality voice communication. + AudioQualityUltraInputBitrate int + + // Audio Quality Sample Rates - Frequency sampling rates for different quality levels + // Used in: audio.go for configuring audio capture and playback sample rates + // Impact: Higher sample rates capture more frequency detail but increase processing load + + // AudioQualityLowSampleRate defines sample rate for low-quality audio (Hz). + // Used in: audio.go for bandwidth-constrained scenarios + // Impact: Reduces frequency response but minimizes processing and bandwidth. + // Default 22050Hz captures frequencies up to 11kHz, adequate for voice. + AudioQualityLowSampleRate int + + // AudioQualityMediumSampleRate defines sample rate for medium-quality audio (Hz). + // Used in: audio.go for balanced quality scenarios + // Impact: Good frequency response with moderate processing requirements. + // Default 44100Hz (CD quality) captures frequencies up to 22kHz. + AudioQualityMediumSampleRate int + + // AudioQualityMicLowSampleRate defines sample rate for low-quality microphone input (Hz). + // Used in: audio.go for microphone capture in constrained scenarios + // Impact: Optimized for voice communication with minimal processing overhead. + // Default 16000Hz captures voice frequencies (300-3400Hz) efficiently. + AudioQualityMicLowSampleRate int + + // Audio Quality Frame Sizes - Duration of audio frames for different quality levels + // Used in: audio.go for configuring Opus frame duration + // Impact: Larger frames reduce overhead but increase latency and memory usage + + // AudioQualityLowFrameSize defines frame duration for low-quality audio. + // Used in: audio.go for low-latency scenarios with minimal processing + // Impact: Longer frames reduce CPU overhead but increase audio latency. + // Default 40ms provides good efficiency for voice communication. + AudioQualityLowFrameSize time.Duration + + // AudioQualityMediumFrameSize defines frame duration for medium-quality audio. + // Used in: audio.go for balanced latency and efficiency + // Impact: Moderate frame size balances latency and processing efficiency. + // Default 20ms provides good balance for most applications. + AudioQualityMediumFrameSize time.Duration + + // AudioQualityHighFrameSize defines frame duration for high-quality audio. + // Used in: audio.go for high-quality scenarios + // Impact: Optimized frame size for high-quality encoding efficiency. + // Default 20ms maintains low latency while supporting high bitrates. + AudioQualityHighFrameSize time.Duration + + // AudioQualityUltraFrameSize defines frame duration for ultra-quality audio. + // Used in: audio.go for maximum quality scenarios + // Impact: Smaller frames reduce latency but increase processing overhead. + // Default 10ms provides minimal latency for real-time applications. + AudioQualityUltraFrameSize time.Duration + + // Audio Quality Channels - Channel configuration for different quality levels + // Used in: audio.go for configuring mono/stereo audio + // Impact: Stereo doubles bandwidth and processing but provides spatial audio + + // AudioQualityLowChannels defines channel count for low-quality audio. + // Used in: audio.go for bandwidth-constrained scenarios + // Impact: Mono (1) minimizes bandwidth and processing for voice communication. + // Default 1 (mono) suitable for voice-only applications. + AudioQualityLowChannels int + + // AudioQualityMediumChannels defines channel count for medium-quality audio. + // Used in: audio.go for balanced quality scenarios + // Impact: Stereo (2) provides spatial audio with moderate bandwidth increase. + // Default 2 (stereo) suitable for general audio applications. + AudioQualityMediumChannels int + + // AudioQualityHighChannels defines channel count for high-quality audio. + // Used in: audio.go for high-fidelity scenarios + // Impact: Stereo (2) essential for high-quality music and spatial audio. + // Default 2 (stereo) required for full audio experience. + AudioQualityHighChannels int + + // AudioQualityUltraChannels defines channel count for ultra-quality audio. + // Used in: audio.go for maximum quality scenarios + // Impact: Stereo (2) mandatory for studio-quality audio reproduction. + // Default 2 (stereo) provides full spatial audio fidelity. + AudioQualityUltraChannels int + + // CGO Audio Constants - Low-level C library configuration for audio processing + // These constants are passed to C code in cgo_audio.go for native audio operations + // Impact: Direct control over native audio library behavior and performance + + // CGOOpusBitrate sets the bitrate for native Opus encoder (bits per second). + // Used in: cgo_audio.go update_audio_constants() function + // Impact: Controls quality vs bandwidth tradeoff in native encoding. + // Default 96000 (96kbps) provides good quality for real-time applications. + CGOOpusBitrate int + + // CGOOpusComplexity sets computational complexity for native Opus encoder (0-10). + // Used in: cgo_audio.go for native encoder configuration + // Impact: Higher values improve quality but increase CPU usage in C code. + // Default 3 balances quality and performance for embedded systems. + CGOOpusComplexity int + + // CGOOpusVBR enables Variable Bit Rate in native Opus encoder (0=CBR, 1=VBR). + // Used in: cgo_audio.go for native encoder mode selection + // Impact: VBR (1) adapts bitrate dynamically for better efficiency. + // Default 1 (VBR) provides optimal bandwidth utilization. + CGOOpusVBR int + + // CGOOpusVBRConstraint enables constrained VBR in native encoder (0/1). + // Used in: cgo_audio.go when VBR is enabled + // Impact: Constrains bitrate variation for more predictable bandwidth. + // Default 1 (constrained) provides controlled bandwidth usage. + CGOOpusVBRConstraint int + + // CGOOpusSignalType specifies signal type hint for native Opus encoder. + // Used in: cgo_audio.go for encoder optimization + // Impact: Optimizes encoder for specific content type (voice vs music). + // Values: 3=OPUS_SIGNAL_MUSIC for general audio, 2=OPUS_SIGNAL_VOICE for speech. + CGOOpusSignalType int + + // CGOOpusBandwidth sets frequency bandwidth for native Opus encoder. + // Used in: cgo_audio.go for encoder frequency range configuration + // Impact: Controls frequency range vs bitrate efficiency. + // Default 1105 (OPUS_BANDWIDTH_FULLBAND) uses full 20kHz bandwidth. + CGOOpusBandwidth int + + // CGOOpusDTX enables Discontinuous Transmission in native encoder (0/1). + // Used in: cgo_audio.go for bandwidth optimization during silence + // Impact: Reduces bandwidth during silence but may cause audio artifacts. + // Default 0 (disabled) maintains consistent audio quality. + CGOOpusDTX int + + // CGOSampleRate defines sample rate for native audio processing (Hz). + // Used in: cgo_audio.go for ALSA and Opus configuration + // Impact: Must match system audio capabilities and Opus requirements. + // Default 48000Hz provides professional audio quality. + CGOSampleRate int + + // CGOChannels defines channel count for native audio processing. + // Used in: cgo_audio.go for ALSA device and Opus encoder configuration + // Impact: Must match audio hardware capabilities and application needs. + // Default 2 (stereo) provides full spatial audio support. + CGOChannels int + + // CGOFrameSize defines frame size for native Opus processing (samples). + // Used in: cgo_audio.go for Opus encoder/decoder frame configuration + // Impact: Must be valid Opus frame size, affects latency and efficiency. + // Default 960 samples (20ms at 48kHz) balances latency and efficiency. + CGOFrameSize int + + // CGOMaxPacketSize defines maximum packet size for native encoding (bytes). + // Used in: cgo_audio.go for buffer allocation in C code + // Impact: Must accommodate worst-case Opus output to prevent buffer overruns. + // Default 1500 bytes handles typical Opus output with safety margin. + CGOMaxPacketSize int + + // Input IPC Constants - Configuration for audio input inter-process communication + // Used in: input_ipc.go for microphone audio capture and processing + // Impact: Controls audio input quality and processing efficiency + + // InputIPCSampleRate defines sample rate for input IPC audio processing (Hz). + // Used in: input_ipc.go for microphone capture configuration + // Impact: Must match microphone capabilities and encoding requirements. + // Default 48000Hz provides professional quality microphone input. + InputIPCSampleRate int + + // InputIPCChannels defines channel count for input IPC audio processing. + // Used in: input_ipc.go for microphone channel configuration + // Impact: Stereo (2) captures spatial audio, mono (1) reduces processing. + // Default 2 (stereo) supports full microphone array capabilities. + InputIPCChannels int + + // InputIPCFrameSize defines frame size for input IPC processing (samples). + // Used in: input_ipc.go for microphone frame processing + // Impact: Larger frames reduce overhead but increase input latency. + // Default 960 samples (20ms at 48kHz) balances latency and efficiency. + InputIPCFrameSize int + + // Output IPC Constants - Configuration for audio output inter-process communication + // Used in: output_streaming.go for audio playback and streaming + // Impact: Controls audio output quality, latency, and reliability + + // OutputMaxFrameSize defines maximum frame size for output processing (bytes). + // Used in: output_streaming.go for buffer allocation and frame processing + // Impact: Larger frames allow bigger audio chunks but increase memory usage. + // Default 4096 bytes accommodates typical audio frames with safety margin. + OutputMaxFrameSize int + + // OutputWriteTimeout defines timeout for output write operations. + // Used in: output_streaming.go for preventing blocking on slow audio devices + // Impact: Shorter timeouts improve responsiveness but may cause audio drops. + // Default 10ms prevents blocking while allowing device response time. + OutputWriteTimeout time.Duration + + // OutputMaxDroppedFrames defines maximum consecutive dropped frames before error. + // Used in: output_streaming.go for audio quality monitoring + // Impact: Higher values tolerate more audio glitches but may degrade experience. + // Default 50 frames allows brief interruptions while detecting serious issues. + OutputMaxDroppedFrames int + + // OutputHeaderSize defines size of output message headers (bytes). + // Used in: output_streaming.go for message parsing and buffer allocation + // Impact: Must match actual header size to prevent parsing errors. + // Default 17 bytes matches current output message header format. + OutputHeaderSize int + + // OutputMessagePoolSize defines size of output message object pool. + // Used in: output_streaming.go for memory management and performance + // Impact: Larger pools reduce allocation overhead but increase memory usage. + // Default 128 messages provides good balance for typical workloads. + OutputMessagePoolSize int + + // Socket Buffer Constants - Network socket buffer configuration for audio streaming + // Used in: socket_buffer.go for optimizing network performance + // Impact: Controls network throughput, latency, and memory usage + + // SocketOptimalBuffer defines optimal socket buffer size (bytes). + // Used in: socket_buffer.go for default socket buffer configuration + // Impact: Balances throughput and memory usage for typical audio streams. + // Default 131072 (128KB) provides good performance for most scenarios. + SocketOptimalBuffer int + + // SocketMaxBuffer defines maximum socket buffer size (bytes). + // Used in: socket_buffer.go for high-throughput scenarios + // Impact: Larger buffers improve throughput but increase memory usage and latency. + // Default 262144 (256KB) handles high-bitrate audio without excessive memory. + SocketMaxBuffer int + + // SocketMinBuffer defines minimum socket buffer size (bytes). + // Used in: socket_buffer.go for low-memory scenarios + // Impact: Smaller buffers reduce memory usage but may limit throughput. + // Default 32768 (32KB) provides minimum viable buffer for audio streaming. + SocketMinBuffer int + + // Scheduling Policy Constants - Linux process scheduling policies for audio threads + // Used in: process_monitor.go for configuring thread scheduling behavior + // Impact: Controls how audio threads are scheduled by the Linux kernel + + // SchedNormal defines normal (CFS) scheduling policy. + // Used in: process_monitor.go for non-critical audio threads + // Impact: Standard time-sharing scheduling, may cause audio latency under load. + // Value 0 corresponds to SCHED_NORMAL in Linux kernel. + SchedNormal int + + // SchedFIFO defines First-In-First-Out real-time scheduling policy. + // Used in: process_monitor.go for critical audio threads requiring deterministic timing + // Impact: Provides real-time scheduling but may starve other processes if misused. + // Value 1 corresponds to SCHED_FIFO in Linux kernel. + SchedFIFO int + + // SchedRR defines Round-Robin real-time scheduling policy. + // Used in: process_monitor.go for real-time threads that should share CPU time + // Impact: Real-time scheduling with time slicing, balances determinism and fairness. + // Value 2 corresponds to SCHED_RR in Linux kernel. + SchedRR int + + // Real-time Priority Levels - Priority values for real-time audio thread scheduling + // Used in: process_monitor.go for setting thread priorities + // Impact: Higher priorities get more CPU time but may affect system responsiveness + + // RTAudioHighPriority defines highest priority for critical audio threads. + // Used in: process_monitor.go for time-critical audio processing (encoding/decoding) + // Impact: Ensures audio threads get CPU time but may impact system responsiveness. + // Default 80 provides high priority without completely starving other processes. + RTAudioHighPriority int + + // RTAudioMediumPriority defines medium priority for important audio threads. + // Used in: process_monitor.go for audio I/O and buffering operations + // Impact: Good priority for audio operations while maintaining system balance. + // Default 60 provides elevated priority for audio without extreme impact. + RTAudioMediumPriority int + + // RTAudioLowPriority defines low priority for background audio threads. + // Used in: process_monitor.go for audio monitoring and metrics collection + // Impact: Ensures audio background tasks run without impacting critical operations. + // Default 40 provides some priority elevation while remaining background. + RTAudioLowPriority int + + // RTNormalPriority defines normal priority (no real-time scheduling). + // Used in: process_monitor.go for non-critical audio threads + // Impact: Standard scheduling priority, no special real-time guarantees. + // Default 0 uses normal kernel scheduling without real-time privileges. + RTNormalPriority int + + // Process Management - Configuration for audio process lifecycle management + // Used in: supervisor.go for managing audio process restarts and recovery + // Impact: Controls system resilience and recovery from audio process failures + + // MaxRestartAttempts defines maximum number of restart attempts for failed processes. + // Used in: supervisor.go for limiting restart attempts to prevent infinite loops + // Impact: Higher values increase resilience but may mask persistent problems. + // Default 5 attempts allows recovery from transient issues while detecting persistent failures. MaxRestartAttempts int - RestartWindow time.Duration - RestartDelay time.Duration - MaxRestartDelay time.Duration - // Buffer Management - PreallocSize int - MaxPoolSize int - MessagePoolSize int + // RestartWindow defines time window for counting restart attempts. + // Used in: supervisor.go for restart attempt rate limiting + // Impact: Longer windows allow more restart attempts but slower failure detection. + // Default 5 minutes provides reasonable window for transient issue recovery. + RestartWindow time.Duration + + // RestartDelay defines initial delay before restarting failed processes. + // Used in: supervisor.go for implementing restart backoff strategy + // Impact: Longer delays reduce restart frequency but increase recovery time. + // Default 2 seconds allows brief recovery time without excessive delay. + RestartDelay time.Duration + + // MaxRestartDelay defines maximum delay between restart attempts. + // Used in: supervisor.go for capping exponential backoff delays + // Impact: Prevents excessively long delays while maintaining backoff benefits. + // Default 30 seconds caps restart delays at reasonable maximum. + MaxRestartDelay time.Duration + + // Buffer Management - Memory buffer configuration for audio processing + // Used across multiple components for memory allocation and performance optimization + // Impact: Controls memory usage, allocation efficiency, and processing performance + + // PreallocSize defines size of preallocated memory pools (bytes). + // Used in: buffer_pool.go for initial memory pool allocation + // Impact: Larger pools reduce allocation overhead but increase memory usage. + // Default 1MB (1024*1024) provides good balance for typical audio workloads. + PreallocSize int + + // MaxPoolSize defines maximum number of objects in memory pools. + // Used in: buffer_pool.go for limiting pool growth + // Impact: Larger pools reduce allocation frequency but increase memory usage. + // Default 100 objects provides good balance between performance and memory. + MaxPoolSize int + + // MessagePoolSize defines size of message object pools. + // Used in: Various IPC components for message allocation + // Impact: Larger pools reduce allocation overhead for message passing. + // Default 256 messages handles typical message throughput efficiently. + MessagePoolSize int + + // OptimalSocketBuffer defines optimal socket buffer size (bytes). + // Used in: socket_buffer.go for default socket configuration + // Impact: Balances network throughput and memory usage. + // Default 262144 (256KB) provides good performance for audio streaming. OptimalSocketBuffer int - MaxSocketBuffer int - MinSocketBuffer int - // IPC Configuration - MagicNumber uint32 - MaxFrameSize int - WriteTimeout time.Duration + // MaxSocketBuffer defines maximum socket buffer size (bytes). + // Used in: socket_buffer.go for high-throughput scenarios + // Impact: Larger buffers improve throughput but increase memory and latency. + // Default 1048576 (1MB) handles high-bitrate streams without excessive memory. + MaxSocketBuffer int + + // MinSocketBuffer defines minimum socket buffer size (bytes). + // Used in: socket_buffer.go for memory-constrained scenarios + // Impact: Smaller buffers reduce memory but may limit throughput. + // Default 8192 (8KB) provides minimum viable buffer for audio streaming. + MinSocketBuffer int + + // ChannelBufferSize defines buffer size for Go channels in audio processing. + // Used in: Various components for inter-goroutine communication + // Impact: Larger buffers reduce blocking but increase memory usage and latency. + // Default 500 messages provides good balance for audio processing pipelines. + ChannelBufferSize int + + // AudioFramePoolSize defines size of audio frame object pools. + // Used in: buffer_pool.go for audio frame allocation + // Impact: Larger pools reduce allocation overhead for frame processing. + // Default 1500 frames handles typical audio frame throughput efficiently. + AudioFramePoolSize int + + // PageSize defines memory page size for alignment and allocation (bytes). + // Used in: buffer_pool.go for memory-aligned allocations + // Impact: Must match system page size for optimal memory performance. + // Default 4096 bytes matches typical Linux page size. + PageSize int + + // InitialBufferFrames defines initial buffer size in audio frames. + // Used in: adaptive_buffer.go for initial buffer allocation + // Impact: Larger initial buffers reduce early reallocations but increase startup memory. + // Default 500 frames provides good starting point for most audio scenarios. + InitialBufferFrames int + + // BytesToMBDivisor defines divisor for converting bytes to megabytes. + // Used in: memory_metrics.go for memory usage reporting + // Impact: Must be 1024*1024 for accurate binary megabyte conversion. + // Default 1048576 (1024*1024) provides standard binary MB conversion. + BytesToMBDivisor int + + // MinReadEncodeBuffer defines minimum buffer size for CGO audio read/encode (bytes). + // Used in: cgo_audio.go for native audio processing buffer allocation + // Impact: Must accommodate minimum audio frame size to prevent buffer underruns. + // Default 1276 bytes handles minimum Opus frame with safety margin. + MinReadEncodeBuffer int + + // MaxDecodeWriteBuffer defines maximum buffer size for CGO audio decode/write (bytes). + // Used in: cgo_audio.go for native audio processing buffer allocation + // Impact: Must accommodate maximum audio frame size to prevent buffer overruns. + // Default 4096 bytes handles maximum audio frame size with safety margin. + MaxDecodeWriteBuffer int + + // IPC Configuration - Inter-Process Communication settings for audio components + // Used in: ipc.go for configuring audio process communication + // Impact: Controls IPC reliability, performance, and protocol compliance + + // MagicNumber defines magic number for IPC message validation. + // Used in: ipc.go for message header validation and protocol compliance + // Impact: Must match expected value to prevent protocol errors. + // Default 0xDEADBEEF provides distinctive pattern for message validation. + MagicNumber uint32 + + // MaxFrameSize defines maximum frame size for IPC messages (bytes). + // Used in: ipc.go for message size validation and buffer allocation + // Impact: Must accommodate largest expected audio frame to prevent truncation. + // Default 4096 bytes handles typical audio frames with safety margin. + MaxFrameSize int + + // WriteTimeout defines timeout for IPC write operations. + // Used in: ipc.go for preventing blocking on slow IPC operations + // Impact: Shorter timeouts improve responsiveness but may cause message drops. + // Default 5 seconds allows for system load while preventing indefinite blocking. + WriteTimeout time.Duration + + // MaxDroppedFrames defines maximum consecutive dropped frames before error. + // Used in: ipc.go for IPC quality monitoring + // Impact: Higher values tolerate more IPC issues but may mask problems. + // Default 10 frames allows brief interruptions while detecting serious issues. MaxDroppedFrames int - HeaderSize int - // Monitoring and Metrics + // HeaderSize defines size of IPC message headers (bytes). + // Used in: ipc.go for message parsing and buffer allocation + // Impact: Must match actual header size to prevent parsing errors. + // Default 8 bytes matches current IPC message header format. + HeaderSize int + + // Monitoring and Metrics - Configuration for audio performance monitoring + // Used in: metrics.go, latency_monitor.go for performance tracking + // Impact: Controls monitoring accuracy, overhead, and data retention + + // MetricsUpdateInterval defines frequency of metrics collection and reporting. + // Used in: metrics.go for periodic metrics updates + // Impact: Shorter intervals provide more accurate monitoring but increase overhead. + // Default 1000ms (1 second) provides good balance between accuracy and performance. MetricsUpdateInterval time.Duration - EMAAlpha float64 - WarmupSamples int - LogThrottleInterval time.Duration - MetricsChannelBuffer int - // Performance Tuning + // EMAAlpha defines smoothing factor for Exponential Moving Average calculations. + // Used in: metrics.go for smoothing performance metrics + // Impact: Higher values respond faster to changes but are more sensitive to noise. + // Default 0.1 provides good smoothing while maintaining responsiveness. + EMAAlpha float64 + + // WarmupSamples defines number of samples to collect before reporting metrics. + // Used in: metrics.go for avoiding inaccurate initial measurements + // Impact: More samples improve initial accuracy but delay metric availability. + // Default 10 samples provides good initial accuracy without excessive delay. + WarmupSamples int + + // LogThrottleInterval defines minimum interval between similar log messages. + // Used in: Various components for preventing log spam + // Impact: Longer intervals reduce log volume but may miss important events. + // Default 5 seconds prevents log flooding while maintaining visibility. + LogThrottleInterval time.Duration + + // MetricsChannelBuffer defines buffer size for metrics data channels. + // Used in: metrics.go for metrics data collection pipelines + // Impact: Larger buffers reduce blocking but increase memory usage and latency. + // Default 100 metrics provides good balance for metrics collection. + MetricsChannelBuffer int + + // LatencyHistorySize defines number of latency measurements to retain. + // Used in: latency_monitor.go for latency trend analysis + // Impact: More history improves trend analysis but increases memory usage. + // Default 100 measurements provides good history for analysis. + LatencyHistorySize int + + // Process Monitoring Constants - System resource monitoring configuration + // Used in: process_monitor.go for monitoring CPU, memory, and system resources + // Impact: Controls resource monitoring accuracy and system compatibility + + // MaxCPUPercent defines maximum valid CPU percentage value. + // Used in: process_monitor.go for CPU usage validation + // Impact: Values above this are considered invalid and filtered out. + // Default 100.0 represents 100% CPU usage as maximum valid value. + MaxCPUPercent float64 + + // MinCPUPercent defines minimum valid CPU percentage value. + // Used in: process_monitor.go for CPU usage validation + // Impact: Values below this are considered noise and filtered out. + // Default 0.01 (0.01%) filters out measurement noise while preserving low usage. + MinCPUPercent float64 + + // DefaultClockTicks defines default system clock ticks per second. + // Used in: process_monitor.go for CPU time calculations on embedded systems + // Impact: Must match system configuration for accurate CPU measurements. + // Default 250.0 matches typical embedded ARM system configuration. + DefaultClockTicks float64 + + // DefaultMemoryGB defines default system memory size in gigabytes. + // Used in: process_monitor.go for memory percentage calculations + // Impact: Should match actual system memory for accurate percentage calculations. + // Default 8 GB represents typical JetKVM system memory configuration. + DefaultMemoryGB int + + // MaxWarmupSamples defines maximum number of warmup samples for monitoring. + // Used in: process_monitor.go for initial measurement stabilization + // Impact: More samples improve initial accuracy but delay monitoring start. + // Default 3 samples provides quick stabilization without excessive delay. + MaxWarmupSamples int + + // WarmupCPUSamples defines number of CPU samples for warmup period. + // Used in: process_monitor.go for CPU measurement stabilization + // Impact: More samples improve CPU measurement accuracy during startup. + // Default 2 samples provides basic CPU measurement stabilization. + WarmupCPUSamples int + + // LogThrottleIntervalSec defines log throttle interval in seconds. + // Used in: process_monitor.go for controlling monitoring log frequency + // Impact: Longer intervals reduce log volume but may miss monitoring events. + // Default 10 seconds provides reasonable monitoring log frequency. + LogThrottleIntervalSec int + + // MinValidClockTicks defines minimum valid system clock ticks value. + // Used in: process_monitor.go for system clock validation + // Impact: Values below this indicate system configuration issues. + // Default 50 ticks represents minimum reasonable system clock configuration. + MinValidClockTicks int + + // MaxValidClockTicks defines maximum valid system clock ticks value. + // Used in: process_monitor.go for system clock validation + // Impact: Values above this indicate system configuration issues. + // Default 1000 ticks represents maximum reasonable system clock configuration. + MaxValidClockTicks int + + // Performance Tuning - Thresholds for adaptive audio quality and resource management + // Used in: adaptive_optimizer.go, quality_manager.go for performance optimization + // Impact: Controls when audio quality adjustments are triggered based on system load + + // CPUThresholdLow defines CPU usage threshold for low system load. + // Used in: adaptive_optimizer.go for triggering quality improvements + // Impact: Below this threshold, audio quality can be increased safely. + // Default 20% allows quality improvements when system has spare capacity. + CPUThresholdLow float64 + + // CPUThresholdMedium defines CPU usage threshold for medium system load. + // Used in: adaptive_optimizer.go for maintaining current quality + // Impact: Between low and medium thresholds, quality remains stable. + // Default 60% represents balanced system load where quality should be maintained. + CPUThresholdMedium float64 + + // CPUThresholdHigh defines CPU usage threshold for high system load. + // Used in: adaptive_optimizer.go for triggering quality reductions + // Impact: Above this threshold, audio quality is reduced to preserve performance. + // Default 75% prevents system overload by reducing audio processing demands. + CPUThresholdHigh float64 + + // MemoryThresholdLow defines memory usage threshold for low memory pressure. + // Used in: adaptive_optimizer.go for memory-based quality decisions + // Impact: Below this threshold, memory-intensive audio features can be enabled. + // Default 30% allows enhanced features when memory is abundant. + MemoryThresholdLow float64 + + // MemoryThresholdMed defines memory usage threshold for medium memory pressure. + // Used in: adaptive_optimizer.go for balanced memory management + // Impact: Between low and medium thresholds, memory usage is monitored closely. + // Default 60% represents moderate memory pressure requiring careful management. + MemoryThresholdMed float64 + + // MemoryThresholdHigh defines memory usage threshold for high memory pressure. + // Used in: adaptive_optimizer.go for aggressive memory conservation + // Impact: Above this threshold, memory usage is minimized by reducing quality. + // Default 80% triggers aggressive memory conservation to prevent system issues. + MemoryThresholdHigh float64 + + // LatencyThresholdLow defines acceptable latency for high-quality audio. + // Used in: adaptive_optimizer.go for latency-based quality decisions + // Impact: Below this threshold, audio quality can be maximized. + // Default 20ms represents excellent latency allowing maximum quality. + LatencyThresholdLow time.Duration + + // LatencyThresholdHigh defines maximum acceptable latency before quality reduction. + // Used in: adaptive_optimizer.go for preventing excessive audio delay + // Impact: Above this threshold, quality is reduced to improve latency. + // Default 50ms represents maximum acceptable latency for real-time audio. + LatencyThresholdHigh time.Duration + CPUFactor float64 MemoryFactor float64 LatencyFactor float64 @@ -63,65 +705,420 @@ type AudioConfigConstants struct { NormalPriority int NiceValue int - // Error Handling + // Error Handling - Configuration for error recovery and retry mechanisms + // Used in: error_handler.go, retry_manager.go for robust error handling + // Impact: Controls system resilience and recovery behavior + + // MaxRetries defines maximum number of retry attempts for failed operations. + // Used in: retry_manager.go for limiting retry attempts + // Impact: More retries improve success rate but may delay error reporting. + // Default 3 retries provides good balance between persistence and responsiveness. + MaxRetries int + + // RetryDelay defines initial delay between retry attempts. + // Used in: retry_manager.go for spacing retry attempts + // Impact: Longer delays reduce system load but slow recovery. + // Default 100ms provides quick retries while avoiding excessive load. + RetryDelay time.Duration + + // MaxRetryDelay defines maximum delay between retry attempts. + // Used in: retry_manager.go for capping exponential backoff + // Impact: Prevents excessively long delays while maintaining backoff benefits. + // Default 5 seconds caps retry delays at reasonable maximum. + MaxRetryDelay time.Duration + + // BackoffMultiplier defines multiplier for exponential backoff retry delays. + // Used in: retry_manager.go for calculating progressive retry delays + // Impact: Higher values increase delays more aggressively between retries. + // Default 2.0 doubles delay each retry, providing standard exponential backoff. + BackoffMultiplier float64 + + // ErrorChannelSize defines buffer size for error reporting channels. + // Used in: error_handler.go for error message queuing + // Impact: Larger buffers prevent error loss but increase memory usage. + // Default 50 errors provides adequate buffering for error bursts. + ErrorChannelSize int + MaxConsecutiveErrors int MaxRetryAttempts int + + // Timing Constants + DefaultSleepDuration time.Duration // 100ms + ShortSleepDuration time.Duration // 10ms + LongSleepDuration time.Duration // 200ms + DefaultTickerInterval time.Duration // 100ms + BufferUpdateInterval time.Duration // 500ms + StatsUpdateInterval time.Duration // 5s + SupervisorTimeout time.Duration // 10s + InputSupervisorTimeout time.Duration // 5s + ShortTimeout time.Duration // 5ms + MediumTimeout time.Duration // 50ms + BatchProcessingDelay time.Duration // 10ms + AdaptiveOptimizerStability time.Duration // 10s + MaxLatencyTarget time.Duration // 50ms + LatencyMonitorTarget time.Duration // 50ms + + // Adaptive Buffer Configuration + LowCPUThreshold float64 // 20% CPU threshold + HighCPUThreshold float64 // 60% CPU threshold + LowMemoryThreshold float64 // 50% memory threshold + HighMemoryThreshold float64 // 75% memory threshold + TargetLatency time.Duration // 20ms target latency + + // Adaptive Optimizer Configuration + CooldownPeriod time.Duration // 30s cooldown period + RollbackThreshold time.Duration // 300ms rollback threshold + LatencyTarget time.Duration // 50ms latency target + + // Latency Monitor Configuration + MaxLatencyThreshold time.Duration // 200ms max latency + JitterThreshold time.Duration // 20ms jitter threshold + + // Microphone Contention Configuration + MicContentionTimeout time.Duration // 200ms contention timeout + + // Priority Scheduler Configuration + MinNiceValue int // -20 minimum nice value + MaxNiceValue int // 19 maximum nice value + + // Buffer Pool Configuration + PreallocPercentage int // 20% preallocation percentage + InputPreallocPercentage int // 30% input preallocation percentage + + // Exponential Moving Average Configuration + HistoricalWeight float64 // 70% historical weight + CurrentWeight float64 // 30% current weight + + // Sleep and Backoff Configuration + CGOSleepMicroseconds int // 50000 microseconds (50ms) + BackoffStart time.Duration // 50ms initial backoff + + // Protocol Magic Numbers + InputMagicNumber uint32 // 0x4A4B4D49 "JKMI" (JetKVM Microphone Input) + OutputMagicNumber uint32 // 0x4A4B4F55 "JKOU" (JetKVM Output) + + // Calculation Constants + PercentageMultiplier float64 // 100.0 for percentage calculations + AveragingWeight float64 // 0.7 for weighted averaging calculations + ScalingFactor float64 // 1.5 for scaling calculations + SmoothingFactor float64 // 0.3 for adaptive buffer smoothing + CPUMemoryWeight float64 // 0.5 for CPU factor in combined calculations + MemoryWeight float64 // 0.3 for memory factor in combined calculations + LatencyWeight float64 // 0.2 for latency factor in combined calculations + PoolGrowthMultiplier int // 2x growth multiplier for pool sizes + LatencyScalingFactor float64 // 2.0 for latency ratio scaling + OptimizerAggressiveness float64 // 0.7 for optimizer aggressiveness } // DefaultAudioConfig returns the default configuration constants +// These values are carefully chosen based on JetKVM's embedded ARM environment, +// real-time audio requirements, and extensive testing for optimal performance. func DefaultAudioConfig() *AudioConfigConstants { return &AudioConfigConstants{ // Audio Quality Presets + // Rationale: 4096 bytes accommodates largest expected audio frames with safety margin + // for high-quality audio while preventing buffer overruns on embedded systems MaxAudioFrameSize: 4096, // Opus Encoding Parameters - OpusBitrate: 128000, - OpusComplexity: 10, - OpusVBR: 1, + // Rationale: 128kbps provides excellent quality for KVM audio while maintaining + // reasonable bandwidth usage over network connections + OpusBitrate: 128000, + // Rationale: Maximum complexity (10) ensures best quality encoding, acceptable + // on modern ARM processors with sufficient CPU headroom + OpusComplexity: 10, + // Rationale: VBR enabled (1) optimizes bitrate based on audio content complexity, + // reducing bandwidth for simple audio while maintaining quality for complex audio + OpusVBR: 1, + // Rationale: Unconstrained VBR (0) allows maximum bitrate flexibility for + // optimal quality-bandwidth balance in varying network conditions OpusVBRConstraint: 0, - OpusDTX: 0, + // Rationale: DTX disabled (0) ensures consistent audio stream for KVM applications + // where silence detection might interfere with system audio monitoring + OpusDTX: 0, // Audio Parameters - SampleRate: 48000, - Channels: 2, - FrameSize: 960, + // Rationale: 48kHz sample rate is professional audio standard, provides full + // frequency range (up to 24kHz) for accurate system audio reproduction + SampleRate: 48000, + // Rationale: Stereo (2 channels) captures full system audio including spatial + // information and stereo effects common in modern operating systems + Channels: 2, + // Rationale: 960 samples = 20ms frames at 48kHz, optimal balance between + // latency (low enough for real-time) and efficiency (reduces packet overhead) + FrameSize: 960, + // Rationale: 4000 bytes accommodates compressed Opus frames with overhead, + // prevents packet fragmentation while allowing for quality variations MaxPacketSize: 4000, + // Audio Quality Bitrates (kbps) + // Rationale: Low quality optimized for bandwidth-constrained connections, + // output higher than input as system audio typically more complex than microphone + AudioQualityLowOutputBitrate: 32, + AudioQualityLowInputBitrate: 16, + // Rationale: Medium quality balances bandwidth and quality for typical usage, + // suitable for most KVM scenarios with reasonable network connections + AudioQualityMediumOutputBitrate: 64, + AudioQualityMediumInputBitrate: 32, + // Rationale: High quality for excellent audio fidelity, matches default Opus + // bitrate for professional applications requiring clear audio reproduction + AudioQualityHighOutputBitrate: 128, + AudioQualityHighInputBitrate: 64, + // Rationale: Ultra quality for audiophile-grade reproduction, suitable for + // high-bandwidth connections where audio quality is paramount + AudioQualityUltraOutputBitrate: 192, + AudioQualityUltraInputBitrate: 96, + + // Audio Quality Sample Rates (Hz) + // Rationale: 22.05kHz captures frequencies up to 11kHz, sufficient for speech + // and basic audio while minimizing processing load on constrained connections + AudioQualityLowSampleRate: 22050, + // Rationale: 44.1kHz CD-quality standard, captures full audible range up to + // 22kHz, excellent balance of quality and processing requirements + AudioQualityMediumSampleRate: 44100, + // Rationale: 16kHz optimized for voice/microphone input, captures speech + // frequencies (300-8000Hz) efficiently while reducing bandwidth + AudioQualityMicLowSampleRate: 16000, + + // Audio Quality Frame Sizes + // Rationale: 40ms frames reduce processing overhead for low-quality mode, + // acceptable latency increase for bandwidth-constrained scenarios + AudioQualityLowFrameSize: 40 * time.Millisecond, + // Rationale: 20ms frames provide good balance of latency and efficiency, + // standard for real-time audio applications + AudioQualityMediumFrameSize: 20 * time.Millisecond, + AudioQualityHighFrameSize: 20 * time.Millisecond, + // Rationale: 10ms frames minimize latency for ultra-responsive audio, + // suitable for applications requiring immediate audio feedback + AudioQualityUltraFrameSize: 10 * time.Millisecond, + + // Audio Quality Channels + // Rationale: Mono (1 channel) reduces bandwidth by 50% for low-quality mode, + // acceptable for basic audio monitoring where stereo separation not critical + AudioQualityLowChannels: 1, + // Rationale: Stereo (2 channels) preserves spatial audio information for + // medium/high/ultra quality modes, essential for modern system audio + AudioQualityMediumChannels: 2, + AudioQualityHighChannels: 2, + AudioQualityUltraChannels: 2, + + // CGO Audio Constants + // Rationale: 96kbps provides good quality for CGO layer while being more + // conservative than main Opus bitrate, suitable for embedded processing + CGOOpusBitrate: 96000, + // Rationale: Lower complexity (3) reduces CPU load in CGO layer while + // maintaining acceptable quality for real-time processing + CGOOpusComplexity: 3, + // Rationale: VBR enabled (1) allows bitrate adaptation based on content + // complexity, optimizing bandwidth usage in CGO processing + CGOOpusVBR: 1, + // Rationale: Constrained VBR (1) limits bitrate variations for more + // predictable processing load in embedded environment + CGOOpusVBRConstraint: 1, + // Rationale: OPUS_SIGNAL_MUSIC (3) optimizes encoding for general audio + // content including system sounds, music, and mixed audio + CGOOpusSignalType: 3, // OPUS_SIGNAL_MUSIC + // Rationale: OPUS_BANDWIDTH_FULLBAND (1105) enables full 20kHz bandwidth + // for complete audio spectrum reproduction + CGOOpusBandwidth: 1105, // OPUS_BANDWIDTH_FULLBAND + // Rationale: DTX disabled (0) ensures consistent audio stream without + // silence detection that could interfere with system audio monitoring + CGOOpusDTX: 0, + // Rationale: 48kHz sample rate matches main audio parameters for + // consistency and professional audio quality + CGOSampleRate: 48000, + // Rationale: Stereo (2 channels) maintains spatial audio information + // throughout the CGO processing pipeline + CGOChannels: 2, + // Rationale: 960 samples (20ms at 48kHz) matches main frame size for + // consistent timing and efficient processing + CGOFrameSize: 960, + // Rationale: 1500 bytes accommodates Ethernet MTU constraints while + // providing sufficient space for compressed audio packets + CGOMaxPacketSize: 1500, + + // Input IPC Constants + // Rationale: 48kHz sample rate ensures high-quality microphone input + // capture matching system audio output for consistent quality + InputIPCSampleRate: 48000, + // Rationale: Stereo (2 channels) captures spatial microphone information + // and maintains compatibility with stereo input devices + InputIPCChannels: 2, + // Rationale: 960 samples (20ms) provides optimal balance between latency + // and processing efficiency for real-time microphone input + InputIPCFrameSize: 960, + + // Output IPC Constants + // Rationale: 4096 bytes accommodates largest audio frames with safety + // margin, preventing buffer overruns in IPC communication + OutputMaxFrameSize: 4096, + // Rationale: 10ms timeout provides quick response for real-time audio + // while preventing blocking in high-performance scenarios + OutputWriteTimeout: 10 * time.Millisecond, + // Rationale: Allow up to 50 dropped frames before error handling, + // providing resilience against temporary network/processing issues + OutputMaxDroppedFrames: 50, + // Rationale: 17-byte header provides sufficient space for frame metadata + // including timestamps, sequence numbers, and format information + OutputHeaderSize: 17, + // Rationale: 128 message pool size balances memory usage with throughput + // for efficient audio streaming without excessive buffering + OutputMessagePoolSize: 128, + + // Socket Buffer Constants + // Rationale: 128KB optimal buffer provides good balance between memory + // usage and network throughput for typical audio streaming scenarios + SocketOptimalBuffer: 131072, // 128KB + // Rationale: 256KB maximum buffer accommodates burst traffic and high + // bitrate audio while preventing excessive memory consumption + SocketMaxBuffer: 262144, // 256KB + // Rationale: 32KB minimum buffer ensures adequate buffering for basic + // audio streaming while minimizing memory footprint + SocketMinBuffer: 32768, // 32KB + + // Scheduling Policy Constants + // Rationale: SCHED_NORMAL (0) provides standard time-sharing scheduling + // suitable for non-critical audio processing tasks + SchedNormal: 0, + // Rationale: SCHED_FIFO (1) provides real-time first-in-first-out + // scheduling for critical audio processing requiring deterministic timing + SchedFIFO: 1, + // Rationale: SCHED_RR (2) provides real-time round-robin scheduling + // for balanced real-time processing with time slicing + SchedRR: 2, + + // Real-time Priority Levels + // Rationale: Priority 80 ensures audio processing gets highest CPU + // priority for latency-critical operations without starving system + RTAudioHighPriority: 80, + // Rationale: Priority 60 provides elevated priority for important + // audio tasks while allowing higher priority system operations + RTAudioMediumPriority: 60, + // Rationale: Priority 40 provides moderate real-time priority for + // audio tasks that need responsiveness but aren't latency-critical + RTAudioLowPriority: 40, + // Rationale: Priority 0 represents normal scheduling priority for + // non-real-time audio processing tasks + RTNormalPriority: 0, + // Process Management + // Rationale: 5 restart attempts provides resilience against transient + // failures while preventing infinite restart loops MaxRestartAttempts: 5, - RestartWindow: 5 * time.Minute, - RestartDelay: 2 * time.Second, - MaxRestartDelay: 30 * time.Second, + // Rationale: 5-minute restart window allows recovery from temporary + // issues while resetting attempt counter for long-term stability + RestartWindow: 5 * time.Minute, + // Rationale: 1-second initial restart delay prevents rapid restart + // cycles while allowing quick recovery from brief failures + RestartDelay: 1 * time.Second, + // Rationale: 30-second maximum delay prevents excessive wait times + // while implementing exponential backoff for persistent failures + MaxRestartDelay: 30 * time.Second, // Buffer Management - PreallocSize: 1024 * 1024, // 1MB - MaxPoolSize: 100, - MessagePoolSize: 100, - OptimalSocketBuffer: 262144, // 256KB - MaxSocketBuffer: 1048576, // 1MB - MinSocketBuffer: 8192, // 8KB + // Rationale: 1MB preallocation provides substantial buffer space for + // high-throughput audio processing while remaining reasonable for embedded systems + PreallocSize: 1024 * 1024, // 1MB + // Rationale: 100 pool size limits memory usage while providing adequate + // object pooling for efficient memory management + MaxPoolSize: 100, + // Rationale: 256 message pool size balances memory usage with message + // throughput for efficient IPC communication + MessagePoolSize: 256, + // Rationale: 256KB optimal socket buffer provides good network performance + // for audio streaming without excessive memory consumption + OptimalSocketBuffer: 262144, // 256KB + // Rationale: 1MB maximum socket buffer accommodates burst traffic and + // high-bitrate audio while preventing excessive memory usage + MaxSocketBuffer: 1048576, // 1MB + // Rationale: 8KB minimum socket buffer ensures basic network buffering + // while minimizing memory footprint for low-bandwidth scenarios + MinSocketBuffer: 8192, // 8KB + // Rationale: 500 channel buffer size provides adequate buffering for + // inter-goroutine communication without blocking + ChannelBufferSize: 500, // Channel buffer size for processing + // Rationale: 1500 audio frame pool size accommodates frame reuse for + // efficient memory management in high-throughput scenarios + AudioFramePoolSize: 1500, // Audio frame pool size + // Rationale: 4096-byte page size aligns with system memory pages for + // optimal memory allocation and cache performance + PageSize: 4096, // Memory page size + // Rationale: 500 initial buffer frames provides adequate startup buffering + // without excessive memory allocation during initialization + InitialBufferFrames: 500, // Initial buffer size in frames + // Rationale: 1024*1024 divisor provides standard MB conversion for + // memory usage calculations and reporting + BytesToMBDivisor: 1024 * 1024, // Divisor for converting bytes to MB + // Rationale: 1276 bytes minimum buffer accommodates smallest CGO audio + // read/encode operations while ensuring adequate processing space + MinReadEncodeBuffer: 1276, // Minimum buffer size for CGO audio read/encode + // Rationale: 4096 bytes maximum buffer provides sufficient space for + // largest CGO audio decode/write operations without excessive allocation + MaxDecodeWriteBuffer: 4096, // Maximum buffer size for CGO audio decode/write // IPC Configuration - MagicNumber: 0xDEADBEEF, - MaxFrameSize: 4096, - WriteTimeout: 5 * time.Second, + // Rationale: 0xDEADBEEF magic number provides distinctive header for + // IPC message validation and debugging purposes + MagicNumber: 0xDEADBEEF, + // Rationale: 4096 bytes maximum frame size accommodates largest audio + // frames while preventing excessive memory allocation + MaxFrameSize: 4096, + // Rationale: 5-second write timeout provides reasonable wait time for + // IPC operations while preventing indefinite blocking + WriteTimeout: 5 * time.Second, + // Rationale: Allow up to 10 dropped frames before error handling, + // balancing audio continuity with quality maintenance MaxDroppedFrames: 10, - HeaderSize: 8, + // Rationale: 8-byte header provides sufficient space for basic IPC + // metadata including message type and size information + HeaderSize: 8, // Monitoring and Metrics + // Rationale: 1-second metrics update interval provides timely monitoring + // without excessive overhead for performance tracking MetricsUpdateInterval: 1000 * time.Millisecond, - EMAAlpha: 0.1, - WarmupSamples: 10, - LogThrottleInterval: 5 * time.Second, - MetricsChannelBuffer: 100, + // Rationale: 0.1 EMA alpha provides smooth exponential moving average + // with 90% weight on historical data for stable metrics + EMAAlpha: 0.1, + // Rationale: 10 warmup samples allow metrics to stabilize before + // making optimization decisions based on performance data + WarmupSamples: 10, + // Rationale: 5-second log throttle interval prevents log spam while + // ensuring important events are captured for debugging + LogThrottleInterval: 5 * time.Second, + // Rationale: 100 metrics channel buffer provides adequate buffering + // for metrics collection without blocking performance monitoring + MetricsChannelBuffer: 100, + // Rationale: 100 latency measurements provide sufficient history for + // statistical analysis and trend detection + LatencyHistorySize: 100, // Number of latency measurements to keep + + // Process Monitoring Constants + MaxCPUPercent: 100.0, // Maximum CPU percentage + MinCPUPercent: 0.01, // Minimum CPU percentage + DefaultClockTicks: 250.0, // Default clock ticks for embedded ARM systems + DefaultMemoryGB: 8, // Default memory in GB + MaxWarmupSamples: 3, // Maximum warmup samples + WarmupCPUSamples: 2, // CPU warmup samples + LogThrottleIntervalSec: 10, // Log throttle interval in seconds + MinValidClockTicks: 50, // Minimum valid clock ticks + MaxValidClockTicks: 1000, // Maximum valid clock ticks // Performance Tuning - CPUFactor: 0.7, - MemoryFactor: 0.8, - LatencyFactor: 0.9, - InputSizeThreshold: 1024, - OutputSizeThreshold: 2048, - TargetLevel: 0.5, + CPUThresholdLow: 0.20, + CPUThresholdMedium: 0.60, + CPUThresholdHigh: 0.75, + MemoryThresholdLow: 0.30, + MemoryThresholdMed: 0.60, + MemoryThresholdHigh: 0.80, + LatencyThresholdLow: 20 * time.Millisecond, + LatencyThresholdHigh: 50 * time.Millisecond, + CPUFactor: 0.7, + MemoryFactor: 0.8, + LatencyFactor: 0.9, + InputSizeThreshold: 1024, + OutputSizeThreshold: 2048, + TargetLevel: 0.5, // Priority Scheduling AudioHighPriority: -10, @@ -131,8 +1128,98 @@ func DefaultAudioConfig() *AudioConfigConstants { NiceValue: -10, // Error Handling + MaxRetries: 3, + RetryDelay: 100 * time.Millisecond, + MaxRetryDelay: 5 * time.Second, + BackoffMultiplier: 2.0, + ErrorChannelSize: 50, MaxConsecutiveErrors: 5, MaxRetryAttempts: 3, + + // Timing Constants + DefaultSleepDuration: 100 * time.Millisecond, + ShortSleepDuration: 10 * time.Millisecond, + LongSleepDuration: 200 * time.Millisecond, + DefaultTickerInterval: 100 * time.Millisecond, + BufferUpdateInterval: 500 * time.Millisecond, + StatsUpdateInterval: 5 * time.Second, + SupervisorTimeout: 10 * time.Second, + InputSupervisorTimeout: 5 * time.Second, + ShortTimeout: 5 * time.Millisecond, + MediumTimeout: 50 * time.Millisecond, + BatchProcessingDelay: 10 * time.Millisecond, + AdaptiveOptimizerStability: 10 * time.Second, + MaxLatencyTarget: 50 * time.Millisecond, + LatencyMonitorTarget: 50 * time.Millisecond, + + // Adaptive Buffer Configuration + LowCPUThreshold: 0.20, + HighCPUThreshold: 0.60, + LowMemoryThreshold: 0.50, + HighMemoryThreshold: 0.75, + TargetLatency: 20 * time.Millisecond, + + // Adaptive Optimizer Configuration + CooldownPeriod: 30 * time.Second, + RollbackThreshold: 300 * time.Millisecond, + LatencyTarget: 50 * time.Millisecond, + + // Latency Monitor Configuration + MaxLatencyThreshold: 200 * time.Millisecond, + JitterThreshold: 20 * time.Millisecond, + + // Microphone Contention Configuration + MicContentionTimeout: 200 * time.Millisecond, + + // Priority Scheduler Configuration + MinNiceValue: -20, + MaxNiceValue: 19, + + // Buffer Pool Configuration + PreallocPercentage: 20, + InputPreallocPercentage: 30, + + // Exponential Moving Average Configuration + HistoricalWeight: 0.70, + CurrentWeight: 0.30, + + // Sleep and Backoff Configuration + CGOSleepMicroseconds: 50000, + BackoffStart: 50 * time.Millisecond, + + // Protocol Magic Numbers + InputMagicNumber: 0x4A4B4D49, // "JKMI" (JetKVM Microphone Input) + OutputMagicNumber: 0x4A4B4F55, // "JKOU" (JetKVM Output) + + // Calculation Constants - Mathematical constants used throughout audio processing + // Used in: Various components for calculations and conversions + // Impact: Controls calculation accuracy and algorithm behavior + + // PercentageMultiplier defines multiplier for percentage calculations. + // Used in: Throughout codebase for converting ratios to percentages + // Impact: Must be 100 for standard percentage calculations. + // Default 100 provides standard percentage conversion (0.5 * 100 = 50%). + PercentageMultiplier: 100.0, // For percentage calculations + + // AveragingWeight defines weight for weighted averaging calculations. + // Used in: metrics.go, adaptive_optimizer.go for smoothing values + // Impact: Higher values give more weight to recent measurements. + // Default 0.7 (70%) emphasizes recent values while maintaining stability. + AveragingWeight: 0.7, // For weighted averaging calculations + + // ScalingFactor defines general scaling factor for various calculations. + // Used in: adaptive_optimizer.go, quality_manager.go for scaling adjustments + // Impact: Controls magnitude of adaptive adjustments and scaling operations. + // Default 1.5 provides moderate scaling for quality and performance adjustments. + ScalingFactor: 1.5, // For scaling calculations + + SmoothingFactor: 0.3, // For adaptive buffer smoothing + CPUMemoryWeight: 0.5, // CPU factor weight in combined calculations + MemoryWeight: 0.3, // Memory factor weight in combined calculations + LatencyWeight: 0.2, // Latency factor weight in combined calculations + PoolGrowthMultiplier: 2, // Pool growth multiplier + LatencyScalingFactor: 2.0, // Latency ratio scaling factor + OptimizerAggressiveness: 0.7, // Optimizer aggressiveness factor } } diff --git a/internal/audio/input_ipc.go b/internal/audio/input_ipc.go index e59bdc8..931700f 100644 --- a/internal/audio/input_ipc.go +++ b/internal/audio/input_ipc.go @@ -16,14 +16,19 @@ import ( "github.com/jetkvm/kvm/internal/logging" ) -const ( - inputMagicNumber uint32 = 0x4A4B4D49 // "JKMI" (JetKVM Microphone Input) +var ( + inputMagicNumber uint32 = GetConfig().InputMagicNumber // "JKMI" (JetKVM Microphone Input) inputSocketName = "audio_input.sock" - maxFrameSize = 4096 // Maximum Opus frame size writeTimeout = 15 * time.Millisecond // Non-blocking write timeout (increased for high load) - maxDroppedFrames = 100 // Maximum consecutive dropped frames before reconnect - headerSize = 17 // Fixed header size: 4+1+4+8 bytes - messagePoolSize = 256 // Pre-allocated message pool size +) + +const ( + headerSize = 17 // Fixed header size: 4+1+4+8 bytes +) + +var ( + maxFrameSize = GetConfig().MaxFrameSize // Maximum Opus frame size + messagePoolSize = GetConfig().MessagePoolSize // Pre-allocated message pool size ) // InputMessageType represents the type of IPC message @@ -79,9 +84,9 @@ var messagePoolInitOnce sync.Once func initializeMessagePool() { messagePoolInitOnce.Do(func() { // Pre-allocate 30% of pool size for immediate availability - preallocSize := messagePoolSize * 30 / 100 + preallocSize := messagePoolSize * GetConfig().InputPreallocPercentage / 100 globalMessagePool.preallocSize = preallocSize - globalMessagePool.maxPoolSize = messagePoolSize * 2 // Allow growth up to 2x + globalMessagePool.maxPoolSize = messagePoolSize * GetConfig().PoolGrowthMultiplier // Allow growth up to 2x globalMessagePool.preallocated = make([]*OptimizedIPCMessage, 0, preallocSize) // Pre-allocate messages to reduce initial allocation overhead @@ -315,7 +320,7 @@ func (ais *AudioInputServer) handleConnection(conn net.Conn) { if ais.conn == nil { return } - time.Sleep(100 * time.Millisecond) + time.Sleep(GetConfig().DefaultSleepDuration) } } } @@ -345,7 +350,7 @@ func (ais *AudioInputServer) readMessage(conn net.Conn) (*InputIPCMessage, error } // Validate message length - if msg.Length > maxFrameSize { + if msg.Length > uint32(maxFrameSize) { return nil, fmt.Errorf("message too large: %d bytes", msg.Length) } @@ -711,7 +716,7 @@ func (aic *AudioInputClient) GetDropRate() float64 { if total == 0 { return 0.0 } - return float64(dropped) / float64(total) * 100.0 + return float64(dropped) / float64(total) * GetConfig().PercentageMultiplier } // ResetStats resets frame statistics @@ -820,11 +825,11 @@ func (ais *AudioInputServer) startMonitorGoroutine() { }() defer ais.wg.Done() - ticker := time.NewTicker(100 * time.Millisecond) + ticker := time.NewTicker(GetConfig().DefaultTickerInterval) defer ticker.Stop() // Buffer size update ticker (less frequent) - bufferUpdateTicker := time.NewTicker(500 * time.Millisecond) + bufferUpdateTicker := time.NewTicker(GetConfig().BufferUpdateInterval) defer bufferUpdateTicker.Stop() for { @@ -917,7 +922,7 @@ func (mp *MessagePool) GetMessagePoolStats() MessagePoolStats { var hitRate float64 if totalRequests > 0 { - hitRate = float64(hitCount) / float64(totalRequests) * 100 + hitRate = float64(hitCount) / float64(totalRequests) * GetConfig().PercentageMultiplier } // Calculate channel pool size diff --git a/internal/audio/input_ipc_manager.go b/internal/audio/input_ipc_manager.go index 2986d4b..9092d17 100644 --- a/internal/audio/input_ipc_manager.go +++ b/internal/audio/input_ipc_manager.go @@ -41,13 +41,13 @@ func (aim *AudioInputIPCManager) Start() error { } config := InputIPCConfig{ - SampleRate: 48000, - Channels: 2, - FrameSize: 960, + SampleRate: GetConfig().InputIPCSampleRate, + Channels: GetConfig().InputIPCChannels, + FrameSize: GetConfig().InputIPCFrameSize, } // Wait for subprocess readiness - time.Sleep(200 * time.Millisecond) + time.Sleep(GetConfig().LongSleepDuration) err = aim.supervisor.SendConfig(config) if err != nil { diff --git a/internal/audio/input_server_main.go b/internal/audio/input_server_main.go index 9fe2b38..39fb3ec 100644 --- a/internal/audio/input_server_main.go +++ b/internal/audio/input_server_main.go @@ -64,7 +64,7 @@ func RunAudioInputServer() error { server.Stop() // Give some time for cleanup - time.Sleep(100 * time.Millisecond) + time.Sleep(GetConfig().DefaultSleepDuration) logger.Info().Msg("Audio input server subprocess stopped") return nil diff --git a/internal/audio/input_supervisor.go b/internal/audio/input_supervisor.go index d7ca2d3..5cd7788 100644 --- a/internal/audio/input_supervisor.go +++ b/internal/audio/input_supervisor.go @@ -128,7 +128,7 @@ func (ais *AudioInputSupervisor) Stop() { select { case <-done: ais.logger.Info().Msg("Audio input server subprocess stopped gracefully") - case <-time.After(5 * time.Second): + case <-time.After(GetConfig().InputSupervisorTimeout): // Force kill if graceful shutdown failed ais.logger.Warn().Msg("Audio input server subprocess did not stop gracefully, force killing") err := ais.cmd.Process.Kill() @@ -220,7 +220,7 @@ func (ais *AudioInputSupervisor) monitorSubprocess() { // connectClient attempts to connect the client to the server func (ais *AudioInputSupervisor) connectClient() { // Wait briefly for the server to start (reduced from 500ms) - time.Sleep(100 * time.Millisecond) + time.Sleep(GetConfig().DefaultSleepDuration) err := ais.client.Connect() if err != nil { diff --git a/internal/audio/ipc.go b/internal/audio/ipc.go index 33f96ae..eaa8484 100644 --- a/internal/audio/ipc.go +++ b/internal/audio/ipc.go @@ -16,16 +16,14 @@ import ( "github.com/rs/zerolog" ) -const ( - outputMagicNumber uint32 = 0x4A4B4F55 // "JKOU" (JetKVM Output) - outputSocketName = "audio_output.sock" - outputMaxFrameSize = 4096 // Maximum Opus frame size - outputWriteTimeout = 10 * time.Millisecond // Non-blocking write timeout (increased for high load) - outputMaxDroppedFrames = 50 // Maximum consecutive dropped frames - outputHeaderSize = 17 // Fixed header size: 4+1+4+8 bytes - outputMessagePoolSize = 128 // Pre-allocated message pool size +var ( + outputMagicNumber uint32 = GetConfig().OutputMagicNumber // "JKOU" (JetKVM Output) + outputSocketName = "audio_output.sock" ) +// Output IPC constants are now centralized in config_constants.go +// outputMaxFrameSize, outputWriteTimeout, outputMaxDroppedFrames, outputHeaderSize, outputMessagePoolSize + // OutputMessageType represents the type of IPC message type OutputMessageType uint8 @@ -48,8 +46,8 @@ type OutputIPCMessage struct { // OutputOptimizedMessage represents a pre-allocated message for zero-allocation operations type OutputOptimizedMessage struct { - header [outputHeaderSize]byte // Pre-allocated header buffer - data []byte // Reusable data buffer + header [17]byte // Pre-allocated header buffer (using constant value since array size must be compile-time constant) + data []byte // Reusable data buffer } // OutputMessagePool manages pre-allocated messages for zero-allocation IPC @@ -66,7 +64,7 @@ func NewOutputMessagePool(size int) *OutputMessagePool { // Pre-allocate messages for i := 0; i < size; i++ { msg := &OutputOptimizedMessage{ - data: make([]byte, outputMaxFrameSize), + data: make([]byte, GetConfig().OutputMaxFrameSize), } pool.pool <- msg } @@ -82,7 +80,7 @@ func (p *OutputMessagePool) Get() *OutputOptimizedMessage { default: // Pool exhausted, create new message return &OutputOptimizedMessage{ - data: make([]byte, outputMaxFrameSize), + data: make([]byte, GetConfig().OutputMaxFrameSize), } } } @@ -98,7 +96,7 @@ func (p *OutputMessagePool) Put(msg *OutputOptimizedMessage) { } // Global message pool for output IPC -var globalOutputMessagePool = NewOutputMessagePool(outputMessagePoolSize) +var globalOutputMessagePool = NewOutputMessagePool(GetConfig().OutputMessagePoolSize) type AudioServer struct { // Atomic fields must be first for proper alignment on ARM @@ -135,7 +133,7 @@ func NewAudioServer() (*AudioServer, error) { } // Initialize with adaptive buffer size (start with 500 frames) - initialBufferSize := int64(500) + initialBufferSize := int64(GetConfig().InitialBufferFrames) // Initialize latency monitoring latencyConfig := DefaultLatencyConfig() @@ -284,8 +282,8 @@ func (s *AudioServer) Close() error { } func (s *AudioServer) SendFrame(frame []byte) error { - if len(frame) > outputMaxFrameSize { - return fmt.Errorf("frame size %d exceeds maximum %d", len(frame), outputMaxFrameSize) + if len(frame) > GetConfig().OutputMaxFrameSize { + return fmt.Errorf("frame size %d exceeds maximum %d", len(frame), GetConfig().OutputMaxFrameSize) } start := time.Now() @@ -340,7 +338,7 @@ func (s *AudioServer) sendFrameToClient(frame []byte) error { binary.LittleEndian.PutUint64(optMsg.header[9:17], uint64(start.UnixNano())) // Use non-blocking write with timeout - ctx, cancel := context.WithTimeout(context.Background(), outputWriteTimeout) + ctx, cancel := context.WithTimeout(context.Background(), GetConfig().OutputWriteTimeout) defer cancel() // Create a channel to signal write completion @@ -492,8 +490,8 @@ func (c *AudioClient) ReceiveFrame() ([]byte, error) { } size := binary.LittleEndian.Uint32(optMsg.header[5:9]) - if size > outputMaxFrameSize { - return nil, fmt.Errorf("frame size %d exceeds maximum %d", size, outputMaxFrameSize) + if int(size) > GetConfig().OutputMaxFrameSize { + return nil, fmt.Errorf("frame size %d exceeds maximum %d", size, GetConfig().OutputMaxFrameSize) } // Read frame data diff --git a/internal/audio/latency_monitor.go b/internal/audio/latency_monitor.go index 963ee28..d46ced9 100644 --- a/internal/audio/latency_monitor.go +++ b/internal/audio/latency_monitor.go @@ -83,10 +83,10 @@ const ( func DefaultLatencyConfig() LatencyConfig { return LatencyConfig{ TargetLatency: 50 * time.Millisecond, - MaxLatency: 200 * time.Millisecond, + MaxLatency: GetConfig().MaxLatencyThreshold, OptimizationInterval: 5 * time.Second, - HistorySize: 100, - JitterThreshold: 20 * time.Millisecond, + HistorySize: GetConfig().LatencyHistorySize, + JitterThreshold: GetConfig().JitterThreshold, AdaptiveThreshold: 0.8, // Trigger optimization when 80% above target } } diff --git a/internal/audio/memory_metrics.go b/internal/audio/memory_metrics.go index a5129b1..bb9293b 100644 --- a/internal/audio/memory_metrics.go +++ b/internal/audio/memory_metrics.go @@ -171,8 +171,8 @@ func LogMemoryMetrics() { metrics := CollectMemoryMetrics() logger.Info(). - Uint64("heap_alloc_mb", metrics.RuntimeStats.HeapAlloc/1024/1024). - Uint64("heap_sys_mb", metrics.RuntimeStats.HeapSys/1024/1024). + Uint64("heap_alloc_mb", metrics.RuntimeStats.HeapAlloc/uint64(GetConfig().BytesToMBDivisor)). + Uint64("heap_sys_mb", metrics.RuntimeStats.HeapSys/uint64(GetConfig().BytesToMBDivisor)). Uint64("heap_objects", metrics.RuntimeStats.HeapObjects). Uint32("num_gc", metrics.RuntimeStats.NumGC). Float64("gc_cpu_fraction", metrics.RuntimeStats.GCCPUFraction). diff --git a/internal/audio/metrics.go b/internal/audio/metrics.go index 9c2b442..ffddd3b 100644 --- a/internal/audio/metrics.go +++ b/internal/audio/metrics.go @@ -451,7 +451,7 @@ func GetLastMetricsUpdate() time.Time { // StartMetricsUpdater starts a goroutine that periodically updates Prometheus metrics func StartMetricsUpdater() { go func() { - ticker := time.NewTicker(5 * time.Second) // Update every 5 seconds + ticker := time.NewTicker(GetConfig().StatsUpdateInterval) // Update every 5 seconds defer ticker.Stop() for range ticker.C { diff --git a/internal/audio/mic_contention.go b/internal/audio/mic_contention.go index 8b06630..373d656 100644 --- a/internal/audio/mic_contention.go +++ b/internal/audio/mic_contention.go @@ -105,7 +105,7 @@ func GetMicrophoneContentionManager() *MicrophoneContentionManager { } if atomic.CompareAndSwapInt32(&micContentionInitialized, 0, 1) { - manager := NewMicrophoneContentionManager(200 * time.Millisecond) + manager := NewMicrophoneContentionManager(GetConfig().MicContentionTimeout) atomic.StorePointer(&globalMicContentionManager, unsafe.Pointer(manager)) return manager } @@ -115,7 +115,7 @@ func GetMicrophoneContentionManager() *MicrophoneContentionManager { return (*MicrophoneContentionManager)(ptr) } - return NewMicrophoneContentionManager(200 * time.Millisecond) + return NewMicrophoneContentionManager(GetConfig().MicContentionTimeout) } func TryMicrophoneOperation() OperationResult { diff --git a/internal/audio/output_server_main.go b/internal/audio/output_server_main.go index 7f2e17b..489cb94 100644 --- a/internal/audio/output_server_main.go +++ b/internal/audio/output_server_main.go @@ -64,7 +64,7 @@ func RunAudioOutputServer() error { StopNonBlockingAudioStreaming() // Give some time for cleanup - time.Sleep(100 * time.Millisecond) + time.Sleep(GetConfig().DefaultSleepDuration) logger.Info().Msg("Audio output server subprocess stopped") return nil diff --git a/internal/audio/output_streaming.go b/internal/audio/output_streaming.go index 4dfb646..265e535 100644 --- a/internal/audio/output_streaming.go +++ b/internal/audio/output_streaming.go @@ -61,9 +61,9 @@ func NewOutputStreamer() (*OutputStreamer, error) { bufferPool: NewAudioBufferPool(GetMaxAudioFrameSize()), // Use existing buffer pool ctx: ctx, cancel: cancel, - batchSize: initialBatchSize, // Use adaptive batch size - processingChan: make(chan []byte, 500), // Large buffer for smooth processing - statsInterval: 5 * time.Second, // Statistics every 5 seconds + batchSize: initialBatchSize, // Use adaptive batch size + processingChan: make(chan []byte, GetConfig().ChannelBufferSize), // Large buffer for smooth processing + statsInterval: 5 * time.Second, // Statistics every 5 seconds lastStatsTime: time.Now().UnixNano(), }, nil } @@ -127,7 +127,7 @@ func (s *OutputStreamer) streamLoop() { defer ticker.Stop() // Batch size update ticker - batchUpdateTicker := time.NewTicker(500 * time.Millisecond) + batchUpdateTicker := time.NewTicker(GetConfig().BufferUpdateInterval) defer batchUpdateTicker.Stop() for { @@ -233,7 +233,7 @@ func (s *OutputStreamer) reportStatistics() { processingTime := atomic.LoadInt64(&s.processingTime) if processed > 0 { - dropRate := float64(dropped) / float64(processed+dropped) * 100 + dropRate := float64(dropped) / float64(processed+dropped) * GetConfig().PercentageMultiplier avgProcessingTime := time.Duration(processingTime) getOutputStreamingLogger().Info().Int64("processed", processed).Int64("dropped", dropped).Float64("drop_rate", dropRate).Dur("avg_processing", avgProcessingTime).Msg("Output Audio Stats") @@ -270,7 +270,7 @@ func (s *OutputStreamer) GetDetailedStats() map[string]interface{} { } if processed+dropped > 0 { - stats["drop_rate_percent"] = float64(dropped) / float64(processed+dropped) * 100 + stats["drop_rate_percent"] = float64(dropped) / float64(processed+dropped) * GetConfig().PercentageMultiplier } // Add client statistics @@ -343,7 +343,7 @@ func StartAudioOutputStreaming(send func([]byte)) error { RecordFrameReceived(n) } // Small delay to prevent busy waiting - time.Sleep(10 * time.Millisecond) + time.Sleep(GetConfig().ShortSleepDuration) } } }() @@ -364,6 +364,6 @@ func StopAudioOutputStreaming() { // Wait for streaming to stop for atomic.LoadInt32(&outputStreamingRunning) == 1 { - time.Sleep(10 * time.Millisecond) + time.Sleep(GetConfig().ShortSleepDuration) } } diff --git a/internal/audio/priority_scheduler.go b/internal/audio/priority_scheduler.go index ffd8595..b9b57d8 100644 --- a/internal/audio/priority_scheduler.go +++ b/internal/audio/priority_scheduler.go @@ -16,23 +16,17 @@ type SchedParam struct { Priority int32 } -// Priority levels for audio processing -const ( - // SCHED_FIFO priorities (1-99, higher = more priority) - AudioHighPriority = 80 // High priority for critical audio processing - AudioMediumPriority = 60 // Medium priority for regular audio processing - AudioLowPriority = 40 // Low priority for background audio tasks +// getPriorityConstants returns priority levels from centralized config +func getPriorityConstants() (audioHigh, audioMedium, audioLow, normal int) { + config := GetConfig() + return config.AudioHighPriority, config.AudioMediumPriority, config.AudioLowPriority, config.NormalPriority +} - // SCHED_NORMAL is the default (priority 0) - NormalPriority = 0 -) - -// Scheduling policies -const ( - SCHED_NORMAL = 0 - SCHED_FIFO = 1 - SCHED_RR = 2 -) +// getSchedulingPolicies returns scheduling policies from centralized config +func getSchedulingPolicies() (schedNormal, schedFIFO, schedRR int) { + config := GetConfig() + return config.SchedNormal, config.SchedFIFO, config.SchedRR +} // PriorityScheduler manages thread priorities for audio processing type PriorityScheduler struct { @@ -73,7 +67,8 @@ func (ps *PriorityScheduler) SetThreadPriority(priority int, policy int) error { if errno != 0 { // If we can't set real-time priority, try nice value instead - if policy != SCHED_NORMAL { + schedNormal, _, _ := getSchedulingPolicies() + if policy != schedNormal { ps.logger.Warn().Int("errno", int(errno)).Msg("Failed to set real-time priority, falling back to nice") return ps.setNicePriority(priority) } @@ -89,11 +84,11 @@ func (ps *PriorityScheduler) setNicePriority(rtPriority int) error { // Convert real-time priority to nice value (inverse relationship) // RT priority 80 -> nice -10, RT priority 40 -> nice 0 niceValue := (40 - rtPriority) / 4 - if niceValue < -20 { - niceValue = -20 + if niceValue < GetConfig().MinNiceValue { + niceValue = GetConfig().MinNiceValue } - if niceValue > 19 { - niceValue = 19 + if niceValue > GetConfig().MaxNiceValue { + niceValue = GetConfig().MaxNiceValue } err := syscall.Setpriority(syscall.PRIO_PROCESS, 0, niceValue) @@ -108,22 +103,30 @@ func (ps *PriorityScheduler) setNicePriority(rtPriority int) error { // SetAudioProcessingPriority sets high priority for audio processing threads func (ps *PriorityScheduler) SetAudioProcessingPriority() error { - return ps.SetThreadPriority(AudioHighPriority, SCHED_FIFO) + audioHigh, _, _, _ := getPriorityConstants() + _, schedFIFO, _ := getSchedulingPolicies() + return ps.SetThreadPriority(audioHigh, schedFIFO) } // SetAudioIOPriority sets medium priority for audio I/O threads func (ps *PriorityScheduler) SetAudioIOPriority() error { - return ps.SetThreadPriority(AudioMediumPriority, SCHED_FIFO) + _, audioMedium, _, _ := getPriorityConstants() + _, schedFIFO, _ := getSchedulingPolicies() + return ps.SetThreadPriority(audioMedium, schedFIFO) } // SetAudioBackgroundPriority sets low priority for background audio tasks func (ps *PriorityScheduler) SetAudioBackgroundPriority() error { - return ps.SetThreadPriority(AudioLowPriority, SCHED_FIFO) + _, _, audioLow, _ := getPriorityConstants() + _, schedFIFO, _ := getSchedulingPolicies() + return ps.SetThreadPriority(audioLow, schedFIFO) } // ResetPriority resets thread to normal scheduling func (ps *PriorityScheduler) ResetPriority() error { - return ps.SetThreadPriority(NormalPriority, SCHED_NORMAL) + _, _, _, normal := getPriorityConstants() + schedNormal, _, _ := getSchedulingPolicies() + return ps.SetThreadPriority(normal, schedNormal) } // Disable disables priority scheduling (useful for testing or fallback) diff --git a/internal/audio/process_monitor.go b/internal/audio/process_monitor.go index d5581c4..d131e83 100644 --- a/internal/audio/process_monitor.go +++ b/internal/audio/process_monitor.go @@ -13,26 +13,29 @@ import ( "github.com/rs/zerolog" ) -// Constants for process monitoring -const ( +// Variables for process monitoring (using configuration) +var ( // System constants - pageSize = 4096 - maxCPUPercent = 100.0 - minCPUPercent = 0.01 - defaultClockTicks = 250.0 // Common for embedded ARM systems - defaultMemoryGB = 8 + maxCPUPercent = GetConfig().MaxCPUPercent + minCPUPercent = GetConfig().MinCPUPercent + defaultClockTicks = GetConfig().DefaultClockTicks + defaultMemoryGB = GetConfig().DefaultMemoryGB // Monitoring thresholds - maxWarmupSamples = 3 - warmupCPUSamples = 2 - logThrottleInterval = 10 + maxWarmupSamples = GetConfig().MaxWarmupSamples + warmupCPUSamples = GetConfig().WarmupCPUSamples // Channel buffer size - metricsChannelBuffer = 100 + metricsChannelBuffer = GetConfig().MetricsChannelBuffer // Clock tick detection ranges - minValidClockTicks = 50 - maxValidClockTicks = 1000 + minValidClockTicks = float64(GetConfig().MinValidClockTicks) + maxValidClockTicks = float64(GetConfig().MaxValidClockTicks) +) + +// Variables for process monitoring +var ( + pageSize = GetConfig().PageSize ) // ProcessMetrics represents CPU and memory usage metrics for a process @@ -217,7 +220,7 @@ func (pm *ProcessMonitor) collectMetrics(pid int, state *processState) (ProcessM vsize, _ := strconv.ParseInt(fields[22], 10, 64) rss, _ := strconv.ParseInt(fields[23], 10, 64) - metric.MemoryRSS = rss * pageSize + metric.MemoryRSS = rss * int64(pageSize) metric.MemoryVMS = vsize // Calculate CPU percentage @@ -230,7 +233,7 @@ func (pm *ProcessMonitor) collectMetrics(pid int, state *processState) (ProcessM // Calculate memory percentage (RSS / total system memory) if totalMem := pm.getTotalMemory(); totalMem > 0 { - metric.MemoryPercent = float64(metric.MemoryRSS) / float64(totalMem) * 100.0 + metric.MemoryPercent = float64(metric.MemoryRSS) / float64(totalMem) * GetConfig().PercentageMultiplier } // Update state for next calculation @@ -261,7 +264,7 @@ func (pm *ProcessMonitor) calculateCPUPercent(totalCPUTime int64, state *process // Convert from clock ticks to seconds using actual system clock ticks clockTicks := pm.getClockTicks() cpuSeconds := cpuDelta / clockTicks - cpuPercent := (cpuSeconds / timeDelta) * 100.0 + cpuPercent := (cpuSeconds / timeDelta) * GetConfig().PercentageMultiplier // Apply bounds if cpuPercent > maxCPUPercent { @@ -341,7 +344,7 @@ func (pm *ProcessMonitor) getTotalMemory() int64 { pm.memoryOnce.Do(func() { file, err := os.Open("/proc/meminfo") if err != nil { - pm.totalMemory = defaultMemoryGB * 1024 * 1024 * 1024 + pm.totalMemory = int64(defaultMemoryGB) * 1024 * 1024 * 1024 return } defer file.Close() @@ -360,7 +363,7 @@ func (pm *ProcessMonitor) getTotalMemory() int64 { break } } - pm.totalMemory = defaultMemoryGB * 1024 * 1024 * 1024 // Fallback + pm.totalMemory = int64(defaultMemoryGB) * 1024 * 1024 * 1024 // Fallback }) return pm.totalMemory } diff --git a/internal/audio/relay.go b/internal/audio/relay.go index d8fb2d9..001faf4 100644 --- a/internal/audio/relay.go +++ b/internal/audio/relay.go @@ -151,7 +151,7 @@ func (r *AudioRelay) relayLoop() { r.logger.Error().Msg("Too many consecutive errors, stopping relay") return } - time.Sleep(10 * time.Millisecond) + time.Sleep(GetConfig().ShortSleepDuration) continue } diff --git a/internal/audio/socket_buffer.go b/internal/audio/socket_buffer.go index f7a0f7f..d5a97d6 100644 --- a/internal/audio/socket_buffer.go +++ b/internal/audio/socket_buffer.go @@ -6,12 +6,7 @@ import ( "syscall" ) -const ( - // Socket buffer sizes optimized for JetKVM's audio workload - OptimalSocketBuffer = 128 * 1024 // 128KB (32 frames @ 4KB each) - MaxSocketBuffer = 256 * 1024 // 256KB for high-load scenarios - MinSocketBuffer = 32 * 1024 // 32KB minimum for basic functionality -) +// Socket buffer sizes are now centralized in config_constants.go // SocketBufferConfig holds socket buffer configuration type SocketBufferConfig struct { @@ -23,8 +18,8 @@ type SocketBufferConfig struct { // DefaultSocketBufferConfig returns the default socket buffer configuration func DefaultSocketBufferConfig() SocketBufferConfig { return SocketBufferConfig{ - SendBufferSize: OptimalSocketBuffer, - RecvBufferSize: OptimalSocketBuffer, + SendBufferSize: GetConfig().SocketOptimalBuffer, + RecvBufferSize: GetConfig().SocketOptimalBuffer, Enabled: true, } } @@ -32,8 +27,8 @@ func DefaultSocketBufferConfig() SocketBufferConfig { // HighLoadSocketBufferConfig returns configuration for high-load scenarios func HighLoadSocketBufferConfig() SocketBufferConfig { return SocketBufferConfig{ - SendBufferSize: MaxSocketBuffer, - RecvBufferSize: MaxSocketBuffer, + SendBufferSize: GetConfig().SocketMaxBuffer, + RecvBufferSize: GetConfig().SocketMaxBuffer, Enabled: true, } } @@ -112,20 +107,20 @@ func ValidateSocketBufferConfig(config SocketBufferConfig) error { return nil } - if config.SendBufferSize < MinSocketBuffer { - return fmt.Errorf("send buffer size %d is below minimum %d", config.SendBufferSize, MinSocketBuffer) + if config.SendBufferSize < GetConfig().SocketMinBuffer { + return fmt.Errorf("send buffer size %d is below minimum %d", config.SendBufferSize, GetConfig().SocketMinBuffer) } - if config.RecvBufferSize < MinSocketBuffer { - return fmt.Errorf("receive buffer size %d is below minimum %d", config.RecvBufferSize, MinSocketBuffer) + if config.RecvBufferSize < GetConfig().SocketMinBuffer { + return fmt.Errorf("receive buffer size %d is below minimum %d", config.RecvBufferSize, GetConfig().SocketMinBuffer) } - if config.SendBufferSize > MaxSocketBuffer { - return fmt.Errorf("send buffer size %d exceeds maximum %d", config.SendBufferSize, MaxSocketBuffer) + if config.SendBufferSize > GetConfig().SocketMaxBuffer { + return fmt.Errorf("send buffer size %d exceeds maximum %d", config.SendBufferSize, GetConfig().SocketMaxBuffer) } - if config.RecvBufferSize > MaxSocketBuffer { - return fmt.Errorf("receive buffer size %d exceeds maximum %d", config.RecvBufferSize, MaxSocketBuffer) + if config.RecvBufferSize > GetConfig().SocketMaxBuffer { + return fmt.Errorf("receive buffer size %d exceeds maximum %d", config.RecvBufferSize, GetConfig().SocketMaxBuffer) } return nil diff --git a/internal/audio/supervisor.go b/internal/audio/supervisor.go index 9429c05..f4534da 100644 --- a/internal/audio/supervisor.go +++ b/internal/audio/supervisor.go @@ -131,7 +131,7 @@ func (s *AudioServerSupervisor) Stop() error { select { case <-s.processDone: s.logger.Info().Msg("audio server process stopped gracefully") - case <-time.After(10 * time.Second): + case <-time.After(GetConfig().SupervisorTimeout): s.logger.Warn().Msg("audio server process did not stop gracefully, forcing termination") s.forceKillProcess() } @@ -365,7 +365,7 @@ func (s *AudioServerSupervisor) terminateProcess() { select { case <-done: s.logger.Info().Int("pid", pid).Msg("audio server process terminated gracefully") - case <-time.After(5 * time.Second): + case <-time.After(GetConfig().InputSupervisorTimeout): s.logger.Warn().Int("pid", pid).Msg("process did not terminate gracefully, sending SIGKILL") s.forceKillProcess() } diff --git a/internal/audio/zero_copy.go b/internal/audio/zero_copy.go index b282d8b..a3fd582 100644 --- a/internal/audio/zero_copy.go +++ b/internal/audio/zero_copy.go @@ -234,7 +234,7 @@ func (p *ZeroCopyFramePool) GetZeroCopyPoolStats() ZeroCopyFramePoolStats { var hitRate float64 if totalRequests > 0 { - hitRate = float64(hitCount) / float64(totalRequests) * 100 + hitRate = float64(hitCount) / float64(totalRequests) * GetConfig().PercentageMultiplier } return ZeroCopyFramePoolStats{