diff --git a/internal/audio/adaptive_buffer.go b/internal/audio/adaptive_buffer.go deleted file mode 100644 index 4dc30d40..00000000 --- a/internal/audio/adaptive_buffer.go +++ /dev/null @@ -1,447 +0,0 @@ -package audio - -import ( - "context" - "math" - "sync" - "sync/atomic" - "time" - - "github.com/jetkvm/kvm/internal/logging" - "github.com/rs/zerolog" -) - -// AdaptiveBufferConfig holds configuration for the adaptive buffer sizing algorithm. -// -// The adaptive buffer system dynamically adjusts audio buffer sizes based on real-time -// system conditions to optimize the trade-off between latency and stability. The algorithm -// uses multiple factors to make decisions: -// -// 1. System Load Monitoring: -// - CPU usage: High CPU load increases buffer sizes to prevent underruns -// - Memory usage: High memory pressure reduces buffer sizes to conserve RAM -// -// 2. Latency Tracking: -// - Target latency: Optimal latency for the current quality setting -// - Max latency: Hard limit beyond which buffers are aggressively reduced -// -// 3. Adaptation Strategy: -// - Exponential smoothing: Prevents oscillation and provides stable adjustments -// - Discrete steps: Buffer sizes change in fixed increments to avoid instability -// - Hysteresis: Different thresholds for increasing vs decreasing buffer sizes -// -// The algorithm is specifically tuned for embedded ARM systems with limited resources, -// prioritizing stability over absolute minimum latency. -type AdaptiveBufferConfig struct { - // Buffer size limits (in frames) - MinBufferSize int - MaxBufferSize int - DefaultBufferSize int - - // System load thresholds - LowCPUThreshold float64 // Below this, increase buffer size - HighCPUThreshold float64 // Above this, decrease buffer size - LowMemoryThreshold float64 // Below this, increase buffer size - HighMemoryThreshold float64 // Above this, decrease buffer size - - // Latency thresholds (in milliseconds) - TargetLatency time.Duration - MaxLatency time.Duration - - // Adaptation parameters - AdaptationInterval time.Duration - SmoothingFactor float64 // 0.0-1.0, higher = more responsive -} - -// DefaultAdaptiveBufferConfig returns optimized config for JetKVM hardware -func DefaultAdaptiveBufferConfig() AdaptiveBufferConfig { - return AdaptiveBufferConfig{ - // Conservative buffer sizes for 256MB RAM constraint - MinBufferSize: Config.AdaptiveMinBufferSize, - MaxBufferSize: Config.AdaptiveMaxBufferSize, - DefaultBufferSize: Config.AdaptiveDefaultBufferSize, - - // CPU thresholds optimized for single-core ARM Cortex A7 under load - LowCPUThreshold: Config.LowCPUThreshold * 100, // Below 20% CPU - HighCPUThreshold: Config.HighCPUThreshold * 100, // Above 60% CPU (lowered to be more responsive) - - // Memory thresholds for 256MB total RAM - LowMemoryThreshold: Config.LowMemoryThreshold * 100, // Below 35% memory usage - HighMemoryThreshold: Config.HighMemoryThreshold * 100, // Above 75% memory usage (lowered for earlier response) - - // Latency targets - TargetLatency: Config.AdaptiveBufferTargetLatency, // Target 20ms latency - MaxLatency: Config.MaxLatencyThreshold, // Max acceptable latency - - // Adaptation settings - AdaptationInterval: Config.BufferUpdateInterval, // Check every 500ms - SmoothingFactor: Config.SmoothingFactor, // Moderate responsiveness - } -} - -// AdaptiveBufferManager manages dynamic buffer sizing based on system conditions -type AdaptiveBufferManager struct { - // Atomic fields MUST be first for ARM32 alignment (int64 fields need 8-byte alignment) - currentInputBufferSize int64 // Current input buffer size (atomic) - currentOutputBufferSize int64 // Current output buffer size (atomic) - averageLatency int64 // Average latency in nanoseconds (atomic) - systemCPUPercent int64 // System CPU percentage * 100 (atomic) - systemMemoryPercent int64 // System memory percentage * 100 (atomic) - adaptationCount int64 // Metrics tracking (atomic) - - config AdaptiveBufferConfig - logger zerolog.Logger - - // Control channels - ctx context.Context - cancel context.CancelFunc - wg sync.WaitGroup - - // Metrics tracking - lastAdaptation time.Time - mutex sync.RWMutex -} - -// NewAdaptiveBufferManager creates a new adaptive buffer manager -func NewAdaptiveBufferManager(config AdaptiveBufferConfig) *AdaptiveBufferManager { - logger := logging.GetDefaultLogger().With().Str("component", "adaptive-buffer").Logger() - - if err := ValidateAdaptiveBufferConfig(config.MinBufferSize, config.MaxBufferSize, config.DefaultBufferSize); err != nil { - logger.Warn().Err(err).Msg("invalid adaptive buffer config, using defaults") - config = DefaultAdaptiveBufferConfig() - } - - ctx, cancel := context.WithCancel(context.Background()) - - return &AdaptiveBufferManager{ - currentInputBufferSize: int64(config.DefaultBufferSize), - currentOutputBufferSize: int64(config.DefaultBufferSize), - config: config, - logger: logger, - - ctx: ctx, - cancel: cancel, - lastAdaptation: time.Now(), - } -} - -// Start begins the adaptive buffer management -func (abm *AdaptiveBufferManager) Start() { - abm.wg.Add(1) - go abm.adaptationLoop() - abm.logger.Info().Msg("adaptive buffer manager started") -} - -// Stop stops the adaptive buffer management -func (abm *AdaptiveBufferManager) Stop() { - abm.cancel() - abm.wg.Wait() - abm.logger.Info().Msg("adaptive buffer manager stopped") -} - -// GetInputBufferSize returns the current recommended input buffer size -func (abm *AdaptiveBufferManager) GetInputBufferSize() int { - return int(atomic.LoadInt64(&abm.currentInputBufferSize)) -} - -// GetOutputBufferSize returns the current recommended output buffer size -func (abm *AdaptiveBufferManager) GetOutputBufferSize() int { - return int(atomic.LoadInt64(&abm.currentOutputBufferSize)) -} - -// UpdateLatency updates the current latency measurement -func (abm *AdaptiveBufferManager) UpdateLatency(latency time.Duration) { - // Use exponential moving average for latency tracking - // Weight: 90% historical, 10% current (for smoother averaging) - currentAvg := atomic.LoadInt64(&abm.averageLatency) - newLatencyNs := latency.Nanoseconds() - - if currentAvg == 0 { - // First measurement - atomic.StoreInt64(&abm.averageLatency, newLatencyNs) - } else { - // Exponential moving average - newAvg := (currentAvg*9 + newLatencyNs) / 10 - atomic.StoreInt64(&abm.averageLatency, newAvg) - } - - // Log high latency warnings only for truly problematic latencies - // Use a more reasonable threshold: 10ms for audio processing is concerning - highLatencyThreshold := 10 * time.Millisecond - if latency > highLatencyThreshold { - abm.logger.Debug(). - Dur("latency_ms", latency/time.Millisecond). - Dur("threshold_ms", highLatencyThreshold/time.Millisecond). - Msg("High audio processing latency detected") - } -} - -// BoostBuffersForQualityChange immediately increases buffer sizes to handle quality change bursts -// This bypasses the normal adaptive algorithm for emergency situations -func (abm *AdaptiveBufferManager) BoostBuffersForQualityChange() { - // Immediately set buffers to maximum size to handle quality change frame bursts - maxSize := int64(abm.config.MaxBufferSize) - atomic.StoreInt64(&abm.currentInputBufferSize, maxSize) - atomic.StoreInt64(&abm.currentOutputBufferSize, maxSize) - - abm.logger.Info(). - Int("buffer_size", int(maxSize)). - Msg("Boosted buffers to maximum size for quality change") -} - -// adaptationLoop is the main loop that adjusts buffer sizes -func (abm *AdaptiveBufferManager) adaptationLoop() { - defer abm.wg.Done() - - ticker := time.NewTicker(abm.config.AdaptationInterval) - defer ticker.Stop() - - for { - select { - case <-abm.ctx.Done(): - return - case <-ticker.C: - abm.adaptBufferSizes() - } - } -} - -// adaptBufferSizes analyzes system conditions and adjusts buffer sizes -// adaptBufferSizes implements the core adaptive buffer sizing algorithm. -// -// This function uses a multi-factor approach to determine optimal buffer sizes: -// -// Mathematical Model: -// 1. Factor Calculation: -// -// - CPU Factor: Sigmoid function that increases buffer size under high CPU load -// -// - Memory Factor: Inverse relationship that decreases buffer size under memory pressure -// -// - Latency Factor: Exponential decay that aggressively reduces buffers when latency exceeds targets -// -// 2. Combined Factor: -// Combined = (CPU_factor * Memory_factor * Latency_factor) -// This multiplicative approach ensures any single critical factor can override others -// -// 3. Exponential Smoothing: -// New_size = Current_size + smoothing_factor * (Target_size - Current_size) -// This prevents rapid oscillations and provides stable convergence -// -// 4. Discrete Quantization: -// Final sizes are rounded to frame boundaries and clamped to configured limits -// -// The algorithm runs periodically and only applies changes when the adaptation interval -// has elapsed, preventing excessive adjustments that could destabilize the audio pipeline. -func (abm *AdaptiveBufferManager) adaptBufferSizes() { - // Use fixed system metrics for stability - systemCPU := 50.0 // Assume moderate CPU usage - systemMemory := 60.0 // Assume moderate memory usage - - atomic.StoreInt64(&abm.systemCPUPercent, int64(systemCPU*100)) - atomic.StoreInt64(&abm.systemMemoryPercent, int64(systemMemory*100)) - - // Get current latency - currentLatencyNs := atomic.LoadInt64(&abm.averageLatency) - currentLatency := time.Duration(currentLatencyNs) - - // Calculate adaptation factors - cpuFactor := abm.calculateCPUFactor(systemCPU) - memoryFactor := abm.calculateMemoryFactor(systemMemory) - latencyFactor := abm.calculateLatencyFactor(currentLatency) - - // Combine factors with weights (CPU has highest priority for KVM coexistence) - combinedFactor := Config.CPUMemoryWeight*cpuFactor + Config.MemoryWeight*memoryFactor + Config.LatencyWeight*latencyFactor - - // Apply adaptation with smoothing - currentInput := float64(atomic.LoadInt64(&abm.currentInputBufferSize)) - currentOutput := float64(atomic.LoadInt64(&abm.currentOutputBufferSize)) - - // Calculate new buffer sizes - newInputSize := abm.applyAdaptation(currentInput, combinedFactor) - newOutputSize := abm.applyAdaptation(currentOutput, combinedFactor) - - // Update buffer sizes if they changed significantly - adjustmentMade := false - if math.Abs(newInputSize-currentInput) >= 0.5 || math.Abs(newOutputSize-currentOutput) >= 0.5 { - atomic.StoreInt64(&abm.currentInputBufferSize, int64(math.Round(newInputSize))) - atomic.StoreInt64(&abm.currentOutputBufferSize, int64(math.Round(newOutputSize))) - - atomic.AddInt64(&abm.adaptationCount, 1) - abm.mutex.Lock() - abm.lastAdaptation = time.Now() - abm.mutex.Unlock() - adjustmentMade = true - - abm.logger.Debug(). - Float64("cpu_percent", systemCPU). - Float64("memory_percent", systemMemory). - Dur("latency", currentLatency). - Float64("combined_factor", combinedFactor). - Int("new_input_size", int(newInputSize)). - Int("new_output_size", int(newOutputSize)). - Msg("Adapted buffer sizes") - } - - // Update metrics with current state - currentInputSize := int(atomic.LoadInt64(&abm.currentInputBufferSize)) - currentOutputSize := int(atomic.LoadInt64(&abm.currentOutputBufferSize)) - UpdateAdaptiveBufferMetrics(currentInputSize, currentOutputSize, systemCPU, systemMemory, adjustmentMade) -} - -// calculateCPUFactor returns adaptation factor based on CPU usage with threshold validation. -// -// Validation Rules: -// - CPU percentage must be within valid range [0.0, 100.0] -// - Uses LowCPUThreshold and HighCPUThreshold from config for decision boundaries -// - Default thresholds: Low=20.0%, High=80.0% -// -// Adaptation Logic: -// - CPU > HighCPUThreshold: Return -1.0 (decrease buffers to reduce CPU load) -// - CPU < LowCPUThreshold: Return +1.0 (increase buffers for better quality) -// - Between thresholds: Linear interpolation based on distance from midpoint -// -// Returns: Adaptation factor in range [-1.0, +1.0] -// - Negative values: Decrease buffer sizes to reduce CPU usage -// - Positive values: Increase buffer sizes for better audio quality -// - Zero: No adaptation needed -// -// The function ensures CPU-aware buffer management to balance audio quality -// with system performance, preventing CPU starvation of the KVM process. -func (abm *AdaptiveBufferManager) calculateCPUFactor(cpuPercent float64) float64 { - if cpuPercent > abm.config.HighCPUThreshold { - // High CPU: decrease buffers to reduce latency and give CPU to KVM - return -1.0 - } else if cpuPercent < abm.config.LowCPUThreshold { - // Low CPU: increase buffers for better quality - return 1.0 - } - // Medium CPU: linear interpolation - midpoint := (abm.config.HighCPUThreshold + abm.config.LowCPUThreshold) / 2 - return (midpoint - cpuPercent) / (midpoint - abm.config.LowCPUThreshold) -} - -// calculateMemoryFactor returns adaptation factor based on memory usage with threshold validation. -// -// Validation Rules: -// - Memory percentage must be within valid range [0.0, 100.0] -// - Uses LowMemoryThreshold and HighMemoryThreshold from config for decision boundaries -// - Default thresholds: Low=30.0%, High=85.0% -// -// Adaptation Logic: -// - Memory > HighMemoryThreshold: Return -1.0 (decrease buffers to free memory) -// - Memory < LowMemoryThreshold: Return +1.0 (increase buffers for performance) -// - Between thresholds: Linear interpolation based on distance from midpoint -// -// Returns: Adaptation factor in range [-1.0, +1.0] -// - Negative values: Decrease buffer sizes to reduce memory usage -// - Positive values: Increase buffer sizes for better performance -// - Zero: No adaptation needed -// -// The function prevents memory exhaustion while optimizing buffer sizes -// for audio processing performance and system stability. -func (abm *AdaptiveBufferManager) calculateMemoryFactor(memoryPercent float64) float64 { - if memoryPercent > abm.config.HighMemoryThreshold { - // High memory: decrease buffers to free memory - return -1.0 - } else if memoryPercent < abm.config.LowMemoryThreshold { - // Low memory: increase buffers for better performance - return 1.0 - } - // Medium memory: linear interpolation - midpoint := (abm.config.HighMemoryThreshold + abm.config.LowMemoryThreshold) / 2 - return (midpoint - memoryPercent) / (midpoint - abm.config.LowMemoryThreshold) -} - -// calculateLatencyFactor returns adaptation factor based on latency with threshold validation. -// -// Validation Rules: -// - Latency must be non-negative duration -// - Uses TargetLatency and MaxLatency from config for decision boundaries -// - Default thresholds: Target=50ms, Max=200ms -// -// Adaptation Logic: -// - Latency > MaxLatency: Return -1.0 (decrease buffers to reduce latency) -// - Latency < TargetLatency: Return +1.0 (increase buffers for quality) -// - Between thresholds: Linear interpolation based on distance from midpoint -// -// Returns: Adaptation factor in range [-1.0, +1.0] -// - Negative values: Decrease buffer sizes to reduce audio latency -// - Positive values: Increase buffer sizes for better audio quality -// - Zero: Latency is at optimal level -// -// The function balances audio latency with quality, ensuring real-time -// performance while maintaining acceptable audio processing quality. -func (abm *AdaptiveBufferManager) calculateLatencyFactor(latency time.Duration) float64 { - if latency > abm.config.MaxLatency { - // High latency: decrease buffers - return -1.0 - } else if latency < abm.config.TargetLatency { - // Low latency: can increase buffers - return 1.0 - } - // Medium latency: linear interpolation - midLatency := (abm.config.MaxLatency + abm.config.TargetLatency) / 2 - return float64(midLatency-latency) / float64(midLatency-abm.config.TargetLatency) -} - -// applyAdaptation applies the adaptation factor to current buffer size -func (abm *AdaptiveBufferManager) applyAdaptation(currentSize, factor float64) float64 { - // Calculate target size based on factor - var targetSize float64 - if factor > 0 { - // Increase towards max - targetSize = currentSize + factor*(float64(abm.config.MaxBufferSize)-currentSize) - } else { - // Decrease towards min - targetSize = currentSize + factor*(currentSize-float64(abm.config.MinBufferSize)) - } - - // Apply smoothing - newSize := currentSize + abm.config.SmoothingFactor*(targetSize-currentSize) - - // Clamp to valid range - return math.Max(float64(abm.config.MinBufferSize), - math.Min(float64(abm.config.MaxBufferSize), newSize)) -} - -// GetStats returns current adaptation statistics -func (abm *AdaptiveBufferManager) GetStats() map[string]interface{} { - abm.mutex.RLock() - lastAdaptation := abm.lastAdaptation - abm.mutex.RUnlock() - - return 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)) / Config.PercentageMultiplier, - "system_memory_percent": float64(atomic.LoadInt64(&abm.systemMemoryPercent)) / Config.PercentageMultiplier, - "adaptation_count": atomic.LoadInt64(&abm.adaptationCount), - "last_adaptation": lastAdaptation, - } -} - -// Global adaptive buffer manager instance -var globalAdaptiveBufferManager *AdaptiveBufferManager -var adaptiveBufferOnce sync.Once - -// GetAdaptiveBufferManager returns the global adaptive buffer manager instance -func GetAdaptiveBufferManager() *AdaptiveBufferManager { - adaptiveBufferOnce.Do(func() { - globalAdaptiveBufferManager = NewAdaptiveBufferManager(DefaultAdaptiveBufferConfig()) - }) - return globalAdaptiveBufferManager -} - -// StartAdaptiveBuffering starts the global adaptive buffer manager -func StartAdaptiveBuffering() { - GetAdaptiveBufferManager().Start() -} - -// StopAdaptiveBuffering stops the global adaptive buffer manager -func StopAdaptiveBuffering() { - if globalAdaptiveBufferManager != nil { - globalAdaptiveBufferManager.Stop() - } -} diff --git a/internal/audio/core_config_constants.go b/internal/audio/core_config_constants.go index 74a7d0ba..8996a1d1 100644 --- a/internal/audio/core_config_constants.go +++ b/internal/audio/core_config_constants.go @@ -152,11 +152,6 @@ type AudioConfigConstants struct { MemoryFactor float64 LatencyFactor float64 - // Adaptive Buffer Configuration - AdaptiveMinBufferSize int // Minimum buffer size in frames for adaptive buffering - AdaptiveMaxBufferSize int // Maximum buffer size in frames for adaptive buffering - AdaptiveDefaultBufferSize int // Default buffer size in frames for adaptive buffering - // Timing Configuration RetryDelay time.Duration // Retry delay MaxRetryDelay time.Duration // Maximum retry delay @@ -171,22 +166,17 @@ type AudioConfigConstants struct { OutputSupervisorTimeout time.Duration // 5s BatchProcessingDelay time.Duration // 10ms - // Adaptive Buffer Configuration - // LowCPUThreshold defines CPU usage threshold for buffer size reduction. - LowCPUThreshold float64 // 20% CPU threshold for buffer optimization - - // HighCPUThreshold defines CPU usage threshold for buffer size increase. - HighCPUThreshold float64 // 60% CPU threshold - LowMemoryThreshold float64 // 50% memory threshold - HighMemoryThreshold float64 // 75% memory threshold - AdaptiveBufferTargetLatency time.Duration // 20ms target latency - CooldownPeriod time.Duration // 30s cooldown period - RollbackThreshold time.Duration // 300ms rollback threshold + // System threshold configuration for buffer management + LowCPUThreshold float64 // CPU usage threshold for performance optimization + HighCPUThreshold float64 // CPU usage threshold for performance limits + LowMemoryThreshold float64 // 50% memory threshold + HighMemoryThreshold float64 // 75% memory threshold + CooldownPeriod time.Duration // 30s cooldown period + RollbackThreshold time.Duration // 300ms rollback threshold MaxLatencyThreshold time.Duration // 200ms max latency JitterThreshold time.Duration // 20ms jitter threshold LatencyOptimizationInterval time.Duration // 5s optimization interval - LatencyAdaptiveThreshold float64 // 0.8 adaptive threshold MicContentionTimeout time.Duration // 200ms contention timeout PreallocPercentage int // 20% preallocation percentage BackoffStart time.Duration // 50ms initial backoff @@ -199,7 +189,6 @@ type AudioConfigConstants struct { PercentageMultiplier float64 // Multiplier for percentage calculations (100.0) AveragingWeight float64 // Weight for weighted averaging (0.7) ScalingFactor float64 // General scaling factor (1.5) - SmoothingFactor float64 // Smoothing factor for adaptive buffers (0.3) CPUMemoryWeight float64 // Weight for CPU factor in calculations (0.5) MemoryWeight float64 // Weight for memory factor (0.3) LatencyWeight float64 // Weight for latency factor (0.2) @@ -226,19 +215,17 @@ type AudioConfigConstants struct { // IPC Constants IPCInitialBufferFrames int // Initial IPC buffer size (500 frames) - EventTimeoutSeconds int - EventTimeFormatString string - EventSubscriptionDelayMS int - InputProcessingTimeoutMS int - AdaptiveBufferCPUMultiplier int - AdaptiveBufferMemoryMultiplier int - InputSocketName string - OutputSocketName string - AudioInputComponentName string - AudioOutputComponentName string - AudioServerComponentName string - AudioRelayComponentName string - AudioEventsComponentName string + EventTimeoutSeconds int + EventTimeFormatString string + EventSubscriptionDelayMS int + InputProcessingTimeoutMS int + InputSocketName string + OutputSocketName string + AudioInputComponentName string + AudioOutputComponentName string + AudioServerComponentName string + AudioRelayComponentName string + AudioEventsComponentName string TestSocketTimeout time.Duration TestBufferSize int @@ -493,17 +480,11 @@ func DefaultAudioConfig() *AudioConfigConstants { OutputSupervisorTimeout: 5 * time.Second, // Output monitoring timeout BatchProcessingDelay: 5 * time.Millisecond, // Reduced batch processing delay - // Adaptive Buffer Configuration - Optimized for single-core RV1106G3 - LowCPUThreshold: 0.40, // Adjusted for single-core ARM system - HighCPUThreshold: 0.75, // Adjusted for single-core RV1106G3 (current load ~64%) - LowMemoryThreshold: 0.60, - HighMemoryThreshold: 0.85, // Adjusted for 200MB total memory system - AdaptiveBufferTargetLatency: 10 * time.Millisecond, // Aggressive target latency for responsiveness - - // Adaptive Buffer Size Configuration - Optimized for quality change bursts - AdaptiveMinBufferSize: 256, // Further increased minimum to prevent emergency mode - AdaptiveMaxBufferSize: 1024, // Much higher maximum for quality changes - AdaptiveDefaultBufferSize: 512, // Higher default for stability during bursts + // System Load Configuration - Optimized for single-core RV1106G3 + LowCPUThreshold: 0.40, // Adjusted for single-core ARM system + HighCPUThreshold: 0.75, // Adjusted for single-core RV1106G3 (current load ~64%) + LowMemoryThreshold: 0.60, + HighMemoryThreshold: 0.85, // Adjusted for 200MB total memory system CooldownPeriod: 15 * time.Second, // Reduced cooldown period RollbackThreshold: 200 * time.Millisecond, // Lower rollback threshold @@ -511,7 +492,6 @@ func DefaultAudioConfig() *AudioConfigConstants { MaxLatencyThreshold: 150 * time.Millisecond, // Lower max latency threshold JitterThreshold: 15 * time.Millisecond, // Reduced jitter threshold LatencyOptimizationInterval: 3 * time.Second, // More frequent optimization - LatencyAdaptiveThreshold: 0.7, // More aggressive adaptive threshold // Microphone Contention Configuration MicContentionTimeout: 200 * time.Millisecond, @@ -531,7 +511,6 @@ func DefaultAudioConfig() *AudioConfigConstants { AveragingWeight: 0.7, // Weight for smoothing values (70% recent, 30% historical) ScalingFactor: 1.5, // General scaling factor for adaptive adjustments - 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 @@ -548,7 +527,6 @@ func DefaultAudioConfig() *AudioConfigConstants { BatchProcessorFramesPerBatch: 16, // Larger batches for quality changes BatchProcessorTimeout: 20 * time.Millisecond, // Longer timeout for bursts BatchProcessorMaxQueueSize: 64, // Larger queue for quality changes - BatchProcessorAdaptiveThreshold: 0.6, // Lower threshold for faster adaptation BatchProcessorThreadPinningThreshold: 8, // Lower threshold for better performance // Output Streaming Constants - Balanced for stability @@ -572,10 +550,6 @@ func DefaultAudioConfig() *AudioConfigConstants { // Input Processing Constants - Balanced for stability InputProcessingTimeoutMS: 10, // 10ms processing timeout threshold - // Adaptive Buffer Constants - AdaptiveBufferCPUMultiplier: 100, // 100 multiplier for CPU percentage - AdaptiveBufferMemoryMultiplier: 100, // 100 multiplier for memory percentage - // Socket Names InputSocketName: "audio_input.sock", // Socket name for audio input IPC OutputSocketName: "audio_output.sock", // Socket name for audio output IPC diff --git a/internal/audio/core_metrics.go b/internal/audio/core_metrics.go index 3f1932cd..02aa924d 100644 --- a/internal/audio/core_metrics.go +++ b/internal/audio/core_metrics.go @@ -11,42 +11,6 @@ import ( ) var ( - // Adaptive buffer metrics - adaptiveInputBufferSize = promauto.NewGauge( - prometheus.GaugeOpts{ - Name: "jetkvm_adaptive_input_buffer_size_bytes", - Help: "Current adaptive input buffer size in bytes", - }, - ) - - adaptiveOutputBufferSize = promauto.NewGauge( - prometheus.GaugeOpts{ - Name: "jetkvm_adaptive_output_buffer_size_bytes", - Help: "Current adaptive output buffer size in bytes", - }, - ) - - adaptiveBufferAdjustmentsTotal = promauto.NewCounter( - prometheus.CounterOpts{ - Name: "jetkvm_adaptive_buffer_adjustments_total", - Help: "Total number of adaptive buffer size adjustments", - }, - ) - - adaptiveSystemCpuPercent = promauto.NewGauge( - prometheus.GaugeOpts{ - Name: "jetkvm_adaptive_system_cpu_percent", - Help: "System CPU usage percentage used by adaptive buffer manager", - }, - ) - - adaptiveSystemMemoryPercent = promauto.NewGauge( - prometheus.GaugeOpts{ - Name: "jetkvm_adaptive_system_memory_percent", - Help: "System memory usage percentage used by adaptive buffer manager", - }, - ) - // Socket buffer metrics socketBufferSizeGauge = promauto.NewGaugeVec( prometheus.GaugeOpts{ @@ -374,23 +338,6 @@ func UpdateMicrophoneMetrics(metrics UnifiedAudioMetrics) { atomic.StoreInt64(&lastMetricsUpdate, time.Now().Unix()) } -// UpdateAdaptiveBufferMetrics updates Prometheus metrics with adaptive buffer information -func UpdateAdaptiveBufferMetrics(inputBufferSize, outputBufferSize int, cpuPercent, memoryPercent float64, adjustmentMade bool) { - metricsUpdateMutex.Lock() - defer metricsUpdateMutex.Unlock() - - adaptiveInputBufferSize.Set(float64(inputBufferSize)) - adaptiveOutputBufferSize.Set(float64(outputBufferSize)) - adaptiveSystemCpuPercent.Set(cpuPercent) - adaptiveSystemMemoryPercent.Set(memoryPercent) - - if adjustmentMade { - adaptiveBufferAdjustmentsTotal.Inc() - } - - atomic.StoreInt64(&lastMetricsUpdate, time.Now().Unix()) -} - // UpdateSocketBufferMetrics updates socket buffer metrics func UpdateSocketBufferMetrics(component, bufferType string, size, utilization float64, overflowOccurred bool) { metricsUpdateMutex.Lock() diff --git a/internal/audio/core_validation.go b/internal/audio/core_validation.go index d0318a1c..9aff34a0 100644 --- a/internal/audio/core_validation.go +++ b/internal/audio/core_validation.go @@ -154,25 +154,6 @@ func ValidateMetricsInterval(interval time.Duration) error { return nil } -// ValidateAdaptiveBufferConfig validates adaptive buffer configuration -func ValidateAdaptiveBufferConfig(minSize, maxSize, defaultSize int) error { - if minSize <= 0 || maxSize <= 0 || defaultSize <= 0 { - return ErrInvalidBufferSize - } - if minSize >= maxSize { - return ErrInvalidBufferSize - } - if defaultSize < minSize || defaultSize > maxSize { - return ErrInvalidBufferSize - } - // Validate against global limits - maxBuffer := Config.SocketMaxBuffer - if maxSize > maxBuffer { - return ErrInvalidBufferSize - } - return nil -} - // ValidateInputIPCConfig validates input IPC configuration func ValidateInputIPCConfig(sampleRate, channels, frameSize int) error { minSampleRate := Config.MinSampleRate diff --git a/internal/audio/ipc_input.go b/internal/audio/ipc_input.go index a3d944e3..0a27940c 100644 --- a/internal/audio/ipc_input.go +++ b/internal/audio/ipc_input.go @@ -211,8 +211,8 @@ func NewAudioInputServer() (*AudioInputServer, error) { return nil, fmt.Errorf("failed to create unix socket after 3 attempts: %w", err) } - // Get initial buffer size from config - initialBufferSize := int64(Config.AdaptiveDefaultBufferSize) + // Get initial buffer size (512 frames for stability) + initialBufferSize := int64(512) // Ensure minimum buffer size to prevent immediate overflow // Use at least 50 frames to handle burst traffic @@ -1182,7 +1182,7 @@ func (ais *AudioInputServer) startMonitorGoroutine() { atomic.StoreInt64(&ais.processingTime, newAvg) } - // Report latency to adaptive buffer manager + // Report latency for metrics ais.ReportLatency(latency) if err != nil { @@ -1227,10 +1227,10 @@ func (ais *AudioInputServer) GetServerStats() (total, dropped int64, avgProcessi atomic.LoadInt64(&ais.bufferSize) } -// UpdateBufferSize updates the buffer size (now using fixed config values) +// UpdateBufferSize updates the buffer size (now using fixed values) func (ais *AudioInputServer) UpdateBufferSize() { - // Buffer size is now fixed from config - newSize := int64(Config.AdaptiveDefaultBufferSize) + // Buffer size is now fixed at 512 frames for stability + newSize := int64(512) atomic.StoreInt64(&ais.bufferSize, newSize) } diff --git a/internal/audio/quality_presets.go b/internal/audio/quality_presets.go index 89057b9c..18a314aa 100644 --- a/internal/audio/quality_presets.go +++ b/internal/audio/quality_presets.go @@ -3,7 +3,7 @@ // Package audio provides real-time audio processing for JetKVM with low-latency streaming. // -// Key components: output/input pipelines with Opus codec, adaptive buffer management, +// Key components: output/input pipelines with Opus codec, buffer management, // zero-copy frame pools, IPC communication, and process supervision. // // Supports four quality presets (Low/Medium/High/Ultra) with configurable bitrates.