[WIP] Simplification: PR Simplification

This commit is contained in:
Alex P 2025-09-16 00:44:26 +03:00
parent ebb79600b0
commit 7ab4a0e41d
6 changed files with 30 additions and 575 deletions

View File

@ -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()
}
}

View File

@ -152,11 +152,6 @@ type AudioConfigConstants struct {
MemoryFactor float64 MemoryFactor float64
LatencyFactor 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 // Timing Configuration
RetryDelay time.Duration // Retry delay RetryDelay time.Duration // Retry delay
MaxRetryDelay time.Duration // Maximum retry delay MaxRetryDelay time.Duration // Maximum retry delay
@ -171,22 +166,17 @@ type AudioConfigConstants struct {
OutputSupervisorTimeout time.Duration // 5s OutputSupervisorTimeout time.Duration // 5s
BatchProcessingDelay time.Duration // 10ms BatchProcessingDelay time.Duration // 10ms
// Adaptive Buffer Configuration // System threshold configuration for buffer management
// LowCPUThreshold defines CPU usage threshold for buffer size reduction. LowCPUThreshold float64 // CPU usage threshold for performance optimization
LowCPUThreshold float64 // 20% CPU threshold for buffer optimization HighCPUThreshold float64 // CPU usage threshold for performance limits
LowMemoryThreshold float64 // 50% memory threshold
// HighCPUThreshold defines CPU usage threshold for buffer size increase. HighMemoryThreshold float64 // 75% memory threshold
HighCPUThreshold float64 // 60% CPU threshold CooldownPeriod time.Duration // 30s cooldown period
LowMemoryThreshold float64 // 50% memory threshold RollbackThreshold time.Duration // 300ms rollback threshold
HighMemoryThreshold float64 // 75% memory threshold
AdaptiveBufferTargetLatency time.Duration // 20ms target latency
CooldownPeriod time.Duration // 30s cooldown period
RollbackThreshold time.Duration // 300ms rollback threshold
MaxLatencyThreshold time.Duration // 200ms max latency MaxLatencyThreshold time.Duration // 200ms max latency
JitterThreshold time.Duration // 20ms jitter threshold JitterThreshold time.Duration // 20ms jitter threshold
LatencyOptimizationInterval time.Duration // 5s optimization interval LatencyOptimizationInterval time.Duration // 5s optimization interval
LatencyAdaptiveThreshold float64 // 0.8 adaptive threshold
MicContentionTimeout time.Duration // 200ms contention timeout MicContentionTimeout time.Duration // 200ms contention timeout
PreallocPercentage int // 20% preallocation percentage PreallocPercentage int // 20% preallocation percentage
BackoffStart time.Duration // 50ms initial backoff BackoffStart time.Duration // 50ms initial backoff
@ -199,7 +189,6 @@ type AudioConfigConstants struct {
PercentageMultiplier float64 // Multiplier for percentage calculations (100.0) PercentageMultiplier float64 // Multiplier for percentage calculations (100.0)
AveragingWeight float64 // Weight for weighted averaging (0.7) AveragingWeight float64 // Weight for weighted averaging (0.7)
ScalingFactor float64 // General scaling factor (1.5) 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) CPUMemoryWeight float64 // Weight for CPU factor in calculations (0.5)
MemoryWeight float64 // Weight for memory factor (0.3) MemoryWeight float64 // Weight for memory factor (0.3)
LatencyWeight float64 // Weight for latency factor (0.2) LatencyWeight float64 // Weight for latency factor (0.2)
@ -226,19 +215,17 @@ type AudioConfigConstants struct {
// IPC Constants // IPC Constants
IPCInitialBufferFrames int // Initial IPC buffer size (500 frames) IPCInitialBufferFrames int // Initial IPC buffer size (500 frames)
EventTimeoutSeconds int EventTimeoutSeconds int
EventTimeFormatString string EventTimeFormatString string
EventSubscriptionDelayMS int EventSubscriptionDelayMS int
InputProcessingTimeoutMS int InputProcessingTimeoutMS int
AdaptiveBufferCPUMultiplier int InputSocketName string
AdaptiveBufferMemoryMultiplier int OutputSocketName string
InputSocketName string AudioInputComponentName string
OutputSocketName string AudioOutputComponentName string
AudioInputComponentName string AudioServerComponentName string
AudioOutputComponentName string AudioRelayComponentName string
AudioServerComponentName string AudioEventsComponentName string
AudioRelayComponentName string
AudioEventsComponentName string
TestSocketTimeout time.Duration TestSocketTimeout time.Duration
TestBufferSize int TestBufferSize int
@ -493,17 +480,11 @@ func DefaultAudioConfig() *AudioConfigConstants {
OutputSupervisorTimeout: 5 * time.Second, // Output monitoring timeout OutputSupervisorTimeout: 5 * time.Second, // Output monitoring timeout
BatchProcessingDelay: 5 * time.Millisecond, // Reduced batch processing delay BatchProcessingDelay: 5 * time.Millisecond, // Reduced batch processing delay
// Adaptive Buffer Configuration - Optimized for single-core RV1106G3 // System Load Configuration - Optimized for single-core RV1106G3
LowCPUThreshold: 0.40, // Adjusted for single-core ARM system LowCPUThreshold: 0.40, // Adjusted for single-core ARM system
HighCPUThreshold: 0.75, // Adjusted for single-core RV1106G3 (current load ~64%) HighCPUThreshold: 0.75, // Adjusted for single-core RV1106G3 (current load ~64%)
LowMemoryThreshold: 0.60, LowMemoryThreshold: 0.60,
HighMemoryThreshold: 0.85, // Adjusted for 200MB total memory system 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
CooldownPeriod: 15 * time.Second, // Reduced cooldown period CooldownPeriod: 15 * time.Second, // Reduced cooldown period
RollbackThreshold: 200 * time.Millisecond, // Lower rollback threshold RollbackThreshold: 200 * time.Millisecond, // Lower rollback threshold
@ -511,7 +492,6 @@ func DefaultAudioConfig() *AudioConfigConstants {
MaxLatencyThreshold: 150 * time.Millisecond, // Lower max latency threshold MaxLatencyThreshold: 150 * time.Millisecond, // Lower max latency threshold
JitterThreshold: 15 * time.Millisecond, // Reduced jitter threshold JitterThreshold: 15 * time.Millisecond, // Reduced jitter threshold
LatencyOptimizationInterval: 3 * time.Second, // More frequent optimization LatencyOptimizationInterval: 3 * time.Second, // More frequent optimization
LatencyAdaptiveThreshold: 0.7, // More aggressive adaptive threshold
// Microphone Contention Configuration // Microphone Contention Configuration
MicContentionTimeout: 200 * time.Millisecond, MicContentionTimeout: 200 * time.Millisecond,
@ -531,7 +511,6 @@ func DefaultAudioConfig() *AudioConfigConstants {
AveragingWeight: 0.7, // Weight for smoothing values (70% recent, 30% historical) AveragingWeight: 0.7, // Weight for smoothing values (70% recent, 30% historical)
ScalingFactor: 1.5, // General scaling factor for adaptive adjustments 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 CPUMemoryWeight: 0.5, // CPU factor weight in combined calculations
MemoryWeight: 0.3, // Memory factor weight in combined calculations MemoryWeight: 0.3, // Memory factor weight in combined calculations
LatencyWeight: 0.2, // Latency 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 BatchProcessorFramesPerBatch: 16, // Larger batches for quality changes
BatchProcessorTimeout: 20 * time.Millisecond, // Longer timeout for bursts BatchProcessorTimeout: 20 * time.Millisecond, // Longer timeout for bursts
BatchProcessorMaxQueueSize: 64, // Larger queue for quality changes BatchProcessorMaxQueueSize: 64, // Larger queue for quality changes
BatchProcessorAdaptiveThreshold: 0.6, // Lower threshold for faster adaptation
BatchProcessorThreadPinningThreshold: 8, // Lower threshold for better performance BatchProcessorThreadPinningThreshold: 8, // Lower threshold for better performance
// Output Streaming Constants - Balanced for stability // Output Streaming Constants - Balanced for stability
@ -572,10 +550,6 @@ func DefaultAudioConfig() *AudioConfigConstants {
// Input Processing Constants - Balanced for stability // Input Processing Constants - Balanced for stability
InputProcessingTimeoutMS: 10, // 10ms processing timeout threshold 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 // Socket Names
InputSocketName: "audio_input.sock", // Socket name for audio input IPC InputSocketName: "audio_input.sock", // Socket name for audio input IPC
OutputSocketName: "audio_output.sock", // Socket name for audio output IPC OutputSocketName: "audio_output.sock", // Socket name for audio output IPC

View File

@ -11,42 +11,6 @@ import (
) )
var ( 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 // Socket buffer metrics
socketBufferSizeGauge = promauto.NewGaugeVec( socketBufferSizeGauge = promauto.NewGaugeVec(
prometheus.GaugeOpts{ prometheus.GaugeOpts{
@ -374,23 +338,6 @@ func UpdateMicrophoneMetrics(metrics UnifiedAudioMetrics) {
atomic.StoreInt64(&lastMetricsUpdate, time.Now().Unix()) 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 // UpdateSocketBufferMetrics updates socket buffer metrics
func UpdateSocketBufferMetrics(component, bufferType string, size, utilization float64, overflowOccurred bool) { func UpdateSocketBufferMetrics(component, bufferType string, size, utilization float64, overflowOccurred bool) {
metricsUpdateMutex.Lock() metricsUpdateMutex.Lock()

View File

@ -154,25 +154,6 @@ func ValidateMetricsInterval(interval time.Duration) error {
return nil 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 // ValidateInputIPCConfig validates input IPC configuration
func ValidateInputIPCConfig(sampleRate, channels, frameSize int) error { func ValidateInputIPCConfig(sampleRate, channels, frameSize int) error {
minSampleRate := Config.MinSampleRate minSampleRate := Config.MinSampleRate

View File

@ -211,8 +211,8 @@ func NewAudioInputServer() (*AudioInputServer, error) {
return nil, fmt.Errorf("failed to create unix socket after 3 attempts: %w", err) return nil, fmt.Errorf("failed to create unix socket after 3 attempts: %w", err)
} }
// Get initial buffer size from config // Get initial buffer size (512 frames for stability)
initialBufferSize := int64(Config.AdaptiveDefaultBufferSize) initialBufferSize := int64(512)
// Ensure minimum buffer size to prevent immediate overflow // Ensure minimum buffer size to prevent immediate overflow
// Use at least 50 frames to handle burst traffic // Use at least 50 frames to handle burst traffic
@ -1182,7 +1182,7 @@ func (ais *AudioInputServer) startMonitorGoroutine() {
atomic.StoreInt64(&ais.processingTime, newAvg) atomic.StoreInt64(&ais.processingTime, newAvg)
} }
// Report latency to adaptive buffer manager // Report latency for metrics
ais.ReportLatency(latency) ais.ReportLatency(latency)
if err != nil { if err != nil {
@ -1227,10 +1227,10 @@ func (ais *AudioInputServer) GetServerStats() (total, dropped int64, avgProcessi
atomic.LoadInt64(&ais.bufferSize) 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() { func (ais *AudioInputServer) UpdateBufferSize() {
// Buffer size is now fixed from config // Buffer size is now fixed at 512 frames for stability
newSize := int64(Config.AdaptiveDefaultBufferSize) newSize := int64(512)
atomic.StoreInt64(&ais.bufferSize, newSize) atomic.StoreInt64(&ais.bufferSize, newSize)
} }

View File

@ -3,7 +3,7 @@
// Package audio provides real-time audio processing for JetKVM with low-latency streaming. // 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. // zero-copy frame pools, IPC communication, and process supervision.
// //
// Supports four quality presets (Low/Medium/High/Ultra) with configurable bitrates. // Supports four quality presets (Low/Medium/High/Ultra) with configurable bitrates.