Fix: linting errors

This commit is contained in:
Alex P 2025-08-24 23:36:29 +00:00
parent a9a1082bcc
commit 3a28105f56
15 changed files with 320 additions and 317 deletions

View File

@ -14,19 +14,19 @@ import (
// AdaptiveBufferConfig holds configuration for adaptive buffer sizing // AdaptiveBufferConfig holds configuration for adaptive buffer sizing
type AdaptiveBufferConfig struct { type AdaptiveBufferConfig struct {
// Buffer size limits (in frames) // Buffer size limits (in frames)
MinBufferSize int MinBufferSize int
MaxBufferSize int MaxBufferSize int
DefaultBufferSize int DefaultBufferSize int
// System load thresholds // System load thresholds
LowCPUThreshold float64 // Below this, increase buffer size LowCPUThreshold float64 // Below this, increase buffer size
HighCPUThreshold float64 // Above this, decrease buffer size HighCPUThreshold float64 // Above this, decrease buffer size
LowMemoryThreshold float64 // Below this, increase buffer size LowMemoryThreshold float64 // Below this, increase buffer size
HighMemoryThreshold float64 // Above this, decrease buffer size HighMemoryThreshold float64 // Above this, decrease buffer size
// Latency thresholds (in milliseconds) // Latency thresholds (in milliseconds)
TargetLatency time.Duration TargetLatency time.Duration
MaxLatency time.Duration MaxLatency time.Duration
// Adaptation parameters // Adaptation parameters
AdaptationInterval time.Duration AdaptationInterval time.Duration
@ -37,13 +37,13 @@ type AdaptiveBufferConfig struct {
func DefaultAdaptiveBufferConfig() AdaptiveBufferConfig { func DefaultAdaptiveBufferConfig() AdaptiveBufferConfig {
return AdaptiveBufferConfig{ return AdaptiveBufferConfig{
// Conservative buffer sizes for 256MB RAM constraint // Conservative buffer sizes for 256MB RAM constraint
MinBufferSize: 3, // Minimum 3 frames (slightly higher for stability) MinBufferSize: 3, // Minimum 3 frames (slightly higher for stability)
MaxBufferSize: 20, // Maximum 20 frames (increased for high load scenarios) MaxBufferSize: 20, // Maximum 20 frames (increased for high load scenarios)
DefaultBufferSize: 6, // Default 6 frames (increased for better stability) DefaultBufferSize: 6, // Default 6 frames (increased for better stability)
// CPU thresholds optimized for single-core ARM Cortex A7 under load // CPU thresholds optimized for single-core ARM Cortex A7 under load
LowCPUThreshold: 20.0, // Below 20% CPU LowCPUThreshold: 20.0, // Below 20% CPU
HighCPUThreshold: 60.0, // Above 60% CPU (lowered to be more responsive) HighCPUThreshold: 60.0, // Above 60% CPU (lowered to be more responsive)
// Memory thresholds for 256MB total RAM // Memory thresholds for 256MB total RAM
LowMemoryThreshold: 35.0, // Below 35% memory usage LowMemoryThreshold: 35.0, // Below 35% memory usage
@ -55,7 +55,7 @@ func DefaultAdaptiveBufferConfig() AdaptiveBufferConfig {
// Adaptation settings // Adaptation settings
AdaptationInterval: 500 * time.Millisecond, // Check every 500ms AdaptationInterval: 500 * time.Millisecond, // Check every 500ms
SmoothingFactor: 0.3, // Moderate responsiveness SmoothingFactor: 0.3, // Moderate responsiveness
} }
} }
@ -64,10 +64,10 @@ type AdaptiveBufferManager struct {
// Atomic fields MUST be first for ARM32 alignment (int64 fields need 8-byte alignment) // Atomic fields MUST be first for ARM32 alignment (int64 fields need 8-byte alignment)
currentInputBufferSize int64 // Current input buffer size (atomic) currentInputBufferSize int64 // Current input buffer size (atomic)
currentOutputBufferSize int64 // Current output buffer size (atomic) currentOutputBufferSize int64 // Current output buffer size (atomic)
averageLatency int64 // Average latency in nanoseconds (atomic) averageLatency int64 // Average latency in nanoseconds (atomic)
systemCPUPercent int64 // System CPU percentage * 100 (atomic) systemCPUPercent int64 // System CPU percentage * 100 (atomic)
systemMemoryPercent int64 // System memory percentage * 100 (atomic) systemMemoryPercent int64 // System memory percentage * 100 (atomic)
adaptationCount int64 // Metrics tracking (atomic) adaptationCount int64 // Metrics tracking (atomic)
config AdaptiveBufferConfig config AdaptiveBufferConfig
logger zerolog.Logger logger zerolog.Logger
@ -79,7 +79,7 @@ type AdaptiveBufferManager struct {
wg sync.WaitGroup wg sync.WaitGroup
// Metrics tracking // Metrics tracking
lastAdaptation time.Time lastAdaptation time.Time
mutex sync.RWMutex mutex sync.RWMutex
} }
@ -90,12 +90,12 @@ func NewAdaptiveBufferManager(config AdaptiveBufferConfig) *AdaptiveBufferManage
return &AdaptiveBufferManager{ return &AdaptiveBufferManager{
currentInputBufferSize: int64(config.DefaultBufferSize), currentInputBufferSize: int64(config.DefaultBufferSize),
currentOutputBufferSize: int64(config.DefaultBufferSize), currentOutputBufferSize: int64(config.DefaultBufferSize),
config: config, config: config,
logger: logging.GetDefaultLogger().With().Str("component", "adaptive-buffer").Logger(), logger: logging.GetDefaultLogger().With().Str("component", "adaptive-buffer").Logger(),
processMonitor: GetProcessMonitor(), processMonitor: GetProcessMonitor(),
ctx: ctx, ctx: ctx,
cancel: cancel, cancel: cancel,
lastAdaptation: time.Now(), lastAdaptation: time.Now(),
} }
} }
@ -179,7 +179,7 @@ func (abm *AdaptiveBufferManager) adaptBufferSizes() {
} }
// Store system metrics atomically // Store system metrics atomically
systemCPU := totalCPU // Total CPU across all monitored processes systemCPU := totalCPU // Total CPU across all monitored processes
systemMemory := totalMemory / float64(processCount) // Average memory usage systemMemory := totalMemory / float64(processCount) // Average memory usage
atomic.StoreInt64(&abm.systemCPUPercent, int64(systemCPU*100)) atomic.StoreInt64(&abm.systemCPUPercent, int64(systemCPU*100))
@ -303,13 +303,13 @@ func (abm *AdaptiveBufferManager) GetStats() map[string]interface{} {
abm.mutex.RUnlock() abm.mutex.RUnlock()
return map[string]interface{}{ return map[string]interface{}{
"input_buffer_size": abm.GetInputBufferSize(), "input_buffer_size": abm.GetInputBufferSize(),
"output_buffer_size": abm.GetOutputBufferSize(), "output_buffer_size": abm.GetOutputBufferSize(),
"average_latency_ms": float64(atomic.LoadInt64(&abm.averageLatency)) / 1e6, "average_latency_ms": float64(atomic.LoadInt64(&abm.averageLatency)) / 1e6,
"system_cpu_percent": float64(atomic.LoadInt64(&abm.systemCPUPercent)) / 100, "system_cpu_percent": float64(atomic.LoadInt64(&abm.systemCPUPercent)) / 100,
"system_memory_percent": float64(atomic.LoadInt64(&abm.systemMemoryPercent)) / 100, "system_memory_percent": float64(atomic.LoadInt64(&abm.systemMemoryPercent)) / 100,
"adaptation_count": atomic.LoadInt64(&abm.adaptationCount), "adaptation_count": atomic.LoadInt64(&abm.adaptationCount),
"last_adaptation": lastAdaptation, "last_adaptation": lastAdaptation,
} }
} }

View File

@ -27,28 +27,25 @@ type AdaptiveOptimizer struct {
// Configuration // Configuration
config OptimizerConfig config OptimizerConfig
mutex sync.RWMutex
} }
// OptimizerConfig holds configuration for the adaptive optimizer // OptimizerConfig holds configuration for the adaptive optimizer
type OptimizerConfig struct { type OptimizerConfig struct {
MaxOptimizationLevel int // Maximum optimization level (0-10) MaxOptimizationLevel int // Maximum optimization level (0-10)
CooldownPeriod time.Duration // Minimum time between optimizations CooldownPeriod time.Duration // Minimum time between optimizations
Aggressiveness float64 // How aggressively to optimize (0.0-1.0) Aggressiveness float64 // How aggressively to optimize (0.0-1.0)
RollbackThreshold time.Duration // Latency threshold to rollback optimizations RollbackThreshold time.Duration // Latency threshold to rollback optimizations
StabilityPeriod time.Duration // Time to wait for stability after optimization StabilityPeriod time.Duration // Time to wait for stability after optimization
} }
// DefaultOptimizerConfig returns a sensible default configuration // DefaultOptimizerConfig returns a sensible default configuration
func DefaultOptimizerConfig() OptimizerConfig { func DefaultOptimizerConfig() OptimizerConfig {
return OptimizerConfig{ return OptimizerConfig{
MaxOptimizationLevel: 8, MaxOptimizationLevel: 8,
CooldownPeriod: 30 * time.Second, CooldownPeriod: 30 * time.Second,
Aggressiveness: 0.7, Aggressiveness: 0.7,
RollbackThreshold: 300 * time.Millisecond, RollbackThreshold: 300 * time.Millisecond,
StabilityPeriod: 10 * time.Second, StabilityPeriod: 10 * time.Second,
} }
} }
@ -65,8 +62,6 @@ func NewAdaptiveOptimizer(latencyMonitor *LatencyMonitor, bufferManager *Adaptiv
cancel: cancel, cancel: cancel,
} }
// Register as latency monitor callback // Register as latency monitor callback
latencyMonitor.AddOptimizationCallback(optimizer.handleLatencyOptimization) latencyMonitor.AddOptimizationCallback(optimizer.handleLatencyOptimization)
@ -89,7 +84,6 @@ func (ao *AdaptiveOptimizer) Stop() {
// initializeStrategies sets up the available optimization strategies // initializeStrategies sets up the available optimization strategies
// handleLatencyOptimization is called when latency optimization is needed // handleLatencyOptimization is called when latency optimization is needed
func (ao *AdaptiveOptimizer) handleLatencyOptimization(metrics LatencyMetrics) error { func (ao *AdaptiveOptimizer) handleLatencyOptimization(metrics LatencyMetrics) error {
currentLevel := atomic.LoadInt64(&ao.optimizationLevel) currentLevel := atomic.LoadInt64(&ao.optimizationLevel)
@ -185,7 +179,9 @@ func (ao *AdaptiveOptimizer) checkStability() {
currentLevel := int(atomic.LoadInt64(&ao.optimizationLevel)) currentLevel := int(atomic.LoadInt64(&ao.optimizationLevel))
if currentLevel > 0 { if currentLevel > 0 {
ao.logger.Warn().Dur("current_latency", metrics.Current).Dur("threshold", ao.config.RollbackThreshold).Msg("Rolling back optimizations due to excessive latency") ao.logger.Warn().Dur("current_latency", metrics.Current).Dur("threshold", ao.config.RollbackThreshold).Msg("Rolling back optimizations due to excessive latency")
ao.decreaseOptimization(currentLevel - 1) if err := ao.decreaseOptimization(currentLevel - 1); err != nil {
ao.logger.Error().Err(err).Msg("Failed to decrease optimization level")
}
} }
} }
} }

View File

@ -7,15 +7,15 @@ import (
type AudioBufferPool struct { type AudioBufferPool struct {
// Atomic fields MUST be first for ARM32 alignment (int64 fields need 8-byte alignment) // Atomic fields MUST be first for ARM32 alignment (int64 fields need 8-byte alignment)
currentSize int64 // Current pool size (atomic) currentSize int64 // Current pool size (atomic)
hitCount int64 // Pool hit counter (atomic) hitCount int64 // Pool hit counter (atomic)
missCount int64 // Pool miss counter (atomic) missCount int64 // Pool miss counter (atomic)
// Other fields // Other fields
pool sync.Pool pool sync.Pool
bufferSize int bufferSize int
maxPoolSize int maxPoolSize int
mutex sync.RWMutex mutex sync.RWMutex
// Memory optimization fields // Memory optimization fields
preallocated []*[]byte // Pre-allocated buffers for immediate use preallocated []*[]byte // Pre-allocated buffers for immediate use
preallocSize int // Number of pre-allocated buffers preallocSize int // Number of pre-allocated buffers
@ -33,8 +33,8 @@ func NewAudioBufferPool(bufferSize int) *AudioBufferPool {
} }
return &AudioBufferPool{ return &AudioBufferPool{
bufferSize: bufferSize, bufferSize: bufferSize,
maxPoolSize: 100, // Limit pool size to prevent excessive memory usage maxPoolSize: 100, // Limit pool size to prevent excessive memory usage
preallocated: preallocated, preallocated: preallocated,
preallocSize: preallocSize, preallocSize: preallocSize,
pool: sync.Pool{ pool: sync.Pool{
@ -59,7 +59,7 @@ func (p *AudioBufferPool) Get() []byte {
// Try sync.Pool next // Try sync.Pool next
if buf := p.pool.Get(); buf != nil { if buf := p.pool.Get(); buf != nil {
bufSlice := buf.([]byte) bufPtr := buf.(*[]byte)
// Update pool size counter when retrieving from pool // Update pool size counter when retrieving from pool
p.mutex.Lock() p.mutex.Lock()
if p.currentSize > 0 { if p.currentSize > 0 {
@ -67,7 +67,7 @@ func (p *AudioBufferPool) Get() []byte {
} }
p.mutex.Unlock() p.mutex.Unlock()
atomic.AddInt64(&p.hitCount, 1) atomic.AddInt64(&p.hitCount, 1)
return bufSlice[:0] // Reset length but keep capacity return (*bufPtr)[:0] // Reset length but keep capacity
} }
// Last resort: allocate new buffer // Last resort: allocate new buffer
@ -102,7 +102,7 @@ func (p *AudioBufferPool) Put(buf []byte) {
} }
// Return to sync.Pool // Return to sync.Pool
p.pool.Put(resetBuf) p.pool.Put(&resetBuf)
// Update pool size counter // Update pool size counter
p.mutex.Lock() p.mutex.Lock()
@ -173,15 +173,15 @@ type AudioBufferPoolDetailedStats struct {
// GetAudioBufferPoolStats returns statistics about the audio buffer pools // GetAudioBufferPoolStats returns statistics about the audio buffer pools
type AudioBufferPoolStats struct { type AudioBufferPoolStats struct {
FramePoolSize int64 FramePoolSize int64
FramePoolMax int FramePoolMax int
ControlPoolSize int64 ControlPoolSize int64
ControlPoolMax int ControlPoolMax int
// Enhanced statistics // Enhanced statistics
FramePoolHitRate float64 FramePoolHitRate float64
ControlPoolHitRate float64 ControlPoolHitRate float64
FramePoolDetails AudioBufferPoolDetailedStats FramePoolDetails AudioBufferPoolDetailedStats
ControlPoolDetails AudioBufferPoolDetailedStats ControlPoolDetails AudioBufferPoolDetailedStats
} }
func GetAudioBufferPoolStats() AudioBufferPoolStats { func GetAudioBufferPoolStats() AudioBufferPoolStats {
@ -200,13 +200,13 @@ func GetAudioBufferPoolStats() AudioBufferPoolStats {
controlDetails := audioControlPool.GetPoolStats() controlDetails := audioControlPool.GetPoolStats()
return AudioBufferPoolStats{ return AudioBufferPoolStats{
FramePoolSize: frameSize, FramePoolSize: frameSize,
FramePoolMax: frameMax, FramePoolMax: frameMax,
ControlPoolSize: controlSize, ControlPoolSize: controlSize,
ControlPoolMax: controlMax, ControlPoolMax: controlMax,
FramePoolHitRate: frameDetails.HitRate, FramePoolHitRate: frameDetails.HitRate,
ControlPoolHitRate: controlDetails.HitRate, ControlPoolHitRate: controlDetails.HitRate,
FramePoolDetails: frameDetails, FramePoolDetails: frameDetails,
ControlPoolDetails: controlDetails, ControlPoolDetails: controlDetails,
} }
} }

View File

@ -49,18 +49,18 @@ type InputIPCMessage struct {
// OptimizedIPCMessage represents an optimized message with pre-allocated buffers // OptimizedIPCMessage represents an optimized message with pre-allocated buffers
type OptimizedIPCMessage struct { type OptimizedIPCMessage struct {
header [headerSize]byte // Pre-allocated header buffer header [headerSize]byte // Pre-allocated header buffer
data []byte // Reusable data buffer data []byte // Reusable data buffer
msg InputIPCMessage // Embedded message msg InputIPCMessage // Embedded message
} }
// MessagePool manages a pool of reusable messages to reduce allocations // MessagePool manages a pool of reusable messages to reduce allocations
type MessagePool struct { type MessagePool struct {
// Atomic fields MUST be first for ARM32 alignment (int64 fields need 8-byte alignment) // Atomic fields MUST be first for ARM32 alignment (int64 fields need 8-byte alignment)
hitCount int64 // Pool hit counter (atomic) hitCount int64 // Pool hit counter (atomic)
missCount int64 // Pool miss counter (atomic) missCount int64 // Pool miss counter (atomic)
// Other fields // Other fields
pool chan *OptimizedIPCMessage pool chan *OptimizedIPCMessage
// Memory optimization fields // Memory optimization fields
preallocated []*OptimizedIPCMessage // Pre-allocated messages for immediate use preallocated []*OptimizedIPCMessage // Pre-allocated messages for immediate use
preallocSize int // Number of pre-allocated messages preallocSize int // Number of pre-allocated messages
@ -73,32 +73,37 @@ var globalMessagePool = &MessagePool{
pool: make(chan *OptimizedIPCMessage, messagePoolSize), pool: make(chan *OptimizedIPCMessage, messagePoolSize),
} }
// Initialize the message pool with pre-allocated messages var messagePoolInitOnce sync.Once
func init() {
// Pre-allocate 30% of pool size for immediate availability
preallocSize := messagePoolSize * 30 / 100
globalMessagePool.preallocSize = preallocSize
globalMessagePool.maxPoolSize = messagePoolSize * 2 // Allow growth up to 2x
globalMessagePool.preallocated = make([]*OptimizedIPCMessage, 0, preallocSize)
// Pre-allocate messages to reduce initial allocation overhead // initializeMessagePool initializes the message pool with pre-allocated messages
for i := 0; i < preallocSize; i++ { func initializeMessagePool() {
msg := &OptimizedIPCMessage{ messagePoolInitOnce.Do(func() {
data: make([]byte, 0, maxFrameSize), // Pre-allocate 30% of pool size for immediate availability
} preallocSize := messagePoolSize * 30 / 100
globalMessagePool.preallocated = append(globalMessagePool.preallocated, msg) globalMessagePool.preallocSize = preallocSize
} globalMessagePool.maxPoolSize = messagePoolSize * 2 // Allow growth up to 2x
globalMessagePool.preallocated = make([]*OptimizedIPCMessage, 0, preallocSize)
// Fill the channel pool with remaining messages // Pre-allocate messages to reduce initial allocation overhead
for i := preallocSize; i < messagePoolSize; i++ { for i := 0; i < preallocSize; i++ {
globalMessagePool.pool <- &OptimizedIPCMessage{ msg := &OptimizedIPCMessage{
data: make([]byte, 0, maxFrameSize), data: make([]byte, 0, maxFrameSize),
}
globalMessagePool.preallocated = append(globalMessagePool.preallocated, msg)
} }
}
// Fill the channel pool with remaining messages
for i := preallocSize; i < messagePoolSize; i++ {
globalMessagePool.pool <- &OptimizedIPCMessage{
data: make([]byte, 0, maxFrameSize),
}
}
})
} }
// Get retrieves a message from the pool // Get retrieves a message from the pool
func (mp *MessagePool) Get() *OptimizedIPCMessage { func (mp *MessagePool) Get() *OptimizedIPCMessage {
initializeMessagePool()
// First try pre-allocated messages for fastest access // First try pre-allocated messages for fastest access
mp.mutex.Lock() mp.mutex.Lock()
if len(mp.preallocated) > 0 { if len(mp.preallocated) > 0 {

View File

@ -16,13 +16,13 @@ import (
) )
const ( const (
outputMagicNumber uint32 = 0x4A4B4F55 // "JKOU" (JetKVM Output) outputMagicNumber uint32 = 0x4A4B4F55 // "JKOU" (JetKVM Output)
outputSocketName = "audio_output.sock" outputSocketName = "audio_output.sock"
outputMaxFrameSize = 4096 // Maximum Opus frame size outputMaxFrameSize = 4096 // Maximum Opus frame size
outputWriteTimeout = 10 * time.Millisecond // Non-blocking write timeout (increased for high load) outputWriteTimeout = 10 * time.Millisecond // Non-blocking write timeout (increased for high load)
outputMaxDroppedFrames = 50 // Maximum consecutive dropped frames outputMaxDroppedFrames = 50 // Maximum consecutive dropped frames
outputHeaderSize = 17 // Fixed header size: 4+1+4+8 bytes outputHeaderSize = 17 // Fixed header size: 4+1+4+8 bytes
outputMessagePoolSize = 128 // Pre-allocated message pool size outputMessagePoolSize = 128 // Pre-allocated message pool size
) )
// OutputMessageType represents the type of IPC message // OutputMessageType represents the type of IPC message
@ -101,10 +101,9 @@ var globalOutputMessagePool = NewOutputMessagePool(outputMessagePoolSize)
type AudioServer struct { type AudioServer struct {
// Atomic fields must be first for proper alignment on ARM // Atomic fields must be first for proper alignment on ARM
bufferSize int64 // Current buffer size (atomic) bufferSize int64 // Current buffer size (atomic)
processingTime int64 // Average processing time in nanoseconds (atomic) droppedFrames int64 // Dropped frames counter (atomic)
droppedFrames int64 // Dropped frames counter (atomic) totalFrames int64 // Total frames counter (atomic)
totalFrames int64 // Total frames counter (atomic)
listener net.Listener listener net.Listener
conn net.Conn conn net.Conn
@ -117,7 +116,7 @@ type AudioServer struct {
wg sync.WaitGroup // Wait group for goroutine coordination wg sync.WaitGroup // Wait group for goroutine coordination
// Latency monitoring // Latency monitoring
latencyMonitor *LatencyMonitor latencyMonitor *LatencyMonitor
adaptiveOptimizer *AdaptiveOptimizer adaptiveOptimizer *AdaptiveOptimizer
} }
@ -216,7 +215,10 @@ func (s *AudioServer) startProcessorGoroutine() {
case msg := <-s.messageChan: case msg := <-s.messageChan:
// Process message (currently just frame sending) // Process message (currently just frame sending)
if msg.Type == OutputMessageTypeOpusFrame { if msg.Type == OutputMessageTypeOpusFrame {
s.sendFrameToClient(msg.Data) if err := s.sendFrameToClient(msg.Data); err != nil {
// Log error but continue processing
atomic.AddInt64(&s.droppedFrames, 1)
}
} }
case <-s.stopChan: case <-s.stopChan:
return return

View File

@ -30,7 +30,7 @@ type LatencyMonitor struct {
// Optimization callbacks // Optimization callbacks
optimizationCallbacks []OptimizationCallback optimizationCallbacks []OptimizationCallback
mutex sync.RWMutex mutex sync.RWMutex
// Performance tracking // Performance tracking
latencyHistory []LatencyMeasurement latencyHistory []LatencyMeasurement
@ -39,12 +39,12 @@ type LatencyMonitor struct {
// LatencyConfig holds configuration for latency monitoring // LatencyConfig holds configuration for latency monitoring
type LatencyConfig struct { type LatencyConfig struct {
TargetLatency time.Duration // Target latency to maintain TargetLatency time.Duration // Target latency to maintain
MaxLatency time.Duration // Maximum acceptable latency MaxLatency time.Duration // Maximum acceptable latency
OptimizationInterval time.Duration // How often to run optimization OptimizationInterval time.Duration // How often to run optimization
HistorySize int // Number of latency measurements to keep HistorySize int // Number of latency measurements to keep
JitterThreshold time.Duration // Jitter threshold for optimization JitterThreshold time.Duration // Jitter threshold for optimization
AdaptiveThreshold float64 // Threshold for adaptive adjustments (0.0-1.0) AdaptiveThreshold float64 // Threshold for adaptive adjustments (0.0-1.0)
} }
// LatencyMeasurement represents a single latency measurement // LatencyMeasurement represents a single latency measurement
@ -83,11 +83,11 @@ const (
func DefaultLatencyConfig() LatencyConfig { func DefaultLatencyConfig() LatencyConfig {
return LatencyConfig{ return LatencyConfig{
TargetLatency: 50 * time.Millisecond, TargetLatency: 50 * time.Millisecond,
MaxLatency: 200 * time.Millisecond, MaxLatency: 200 * time.Millisecond,
OptimizationInterval: 5 * time.Second, OptimizationInterval: 5 * time.Second,
HistorySize: 100, HistorySize: 100,
JitterThreshold: 20 * time.Millisecond, JitterThreshold: 20 * time.Millisecond,
AdaptiveThreshold: 0.8, // Trigger optimization when 80% above target AdaptiveThreshold: 0.8, // Trigger optimization when 80% above target
} }
} }

View File

@ -13,17 +13,17 @@ import (
// MemoryMetrics provides comprehensive memory allocation statistics // MemoryMetrics provides comprehensive memory allocation statistics
type MemoryMetrics struct { type MemoryMetrics struct {
// Runtime memory statistics // Runtime memory statistics
RuntimeStats RuntimeMemoryStats `json:"runtime_stats"` RuntimeStats RuntimeMemoryStats `json:"runtime_stats"`
// Audio buffer pool statistics // Audio buffer pool statistics
BufferPools AudioBufferPoolStats `json:"buffer_pools"` BufferPools AudioBufferPoolStats `json:"buffer_pools"`
// Zero-copy frame pool statistics // Zero-copy frame pool statistics
ZeroCopyPool ZeroCopyFramePoolStats `json:"zero_copy_pool"` ZeroCopyPool ZeroCopyFramePoolStats `json:"zero_copy_pool"`
// Message pool statistics // Message pool statistics
MessagePool MessagePoolStats `json:"message_pool"` MessagePool MessagePoolStats `json:"message_pool"`
// Batch processor statistics // Batch processor statistics
BatchProcessor BatchProcessorMemoryStats `json:"batch_processor,omitempty"` BatchProcessor BatchProcessorMemoryStats `json:"batch_processor,omitempty"`
// Collection timestamp // Collection timestamp
Timestamp time.Time `json:"timestamp"` Timestamp time.Time `json:"timestamp"`
} }
// RuntimeMemoryStats provides Go runtime memory statistics // RuntimeMemoryStats provides Go runtime memory statistics
@ -59,10 +59,10 @@ type RuntimeMemoryStats struct {
// BatchProcessorMemoryStats provides batch processor memory statistics // BatchProcessorMemoryStats provides batch processor memory statistics
type BatchProcessorMemoryStats struct { type BatchProcessorMemoryStats struct {
Initialized bool `json:"initialized"` Initialized bool `json:"initialized"`
Running bool `json:"running"` Running bool `json:"running"`
Stats BatchAudioStats `json:"stats"` Stats BatchAudioStats `json:"stats"`
BufferPool AudioBufferPoolDetailedStats `json:"buffer_pool,omitempty"` BufferPool AudioBufferPoolDetailedStats `json:"buffer_pool,omitempty"`
} }
// GetBatchAudioProcessor is defined in batch_audio.go // GetBatchAudioProcessor is defined in batch_audio.go

View File

@ -13,7 +13,7 @@ type MicrophoneContentionManager struct {
cooldownNanos int64 cooldownNanos int64
operationID int64 operationID int64
lockPtr unsafe.Pointer lockPtr unsafe.Pointer
} }
func NewMicrophoneContentionManager(cooldown time.Duration) *MicrophoneContentionManager { func NewMicrophoneContentionManager(cooldown time.Duration) *MicrophoneContentionManager {

View File

@ -61,9 +61,9 @@ func NewOutputStreamer() (*OutputStreamer, error) {
bufferPool: NewAudioBufferPool(MaxAudioFrameSize), // Use existing buffer pool bufferPool: NewAudioBufferPool(MaxAudioFrameSize), // Use existing buffer pool
ctx: ctx, ctx: ctx,
cancel: cancel, cancel: cancel,
batchSize: initialBatchSize, // Use adaptive batch size batchSize: initialBatchSize, // Use adaptive batch size
processingChan: make(chan []byte, 500), // Large buffer for smooth processing processingChan: make(chan []byte, 500), // Large buffer for smooth processing
statsInterval: 5 * time.Second, // Statistics every 5 seconds statsInterval: 5 * time.Second, // Statistics every 5 seconds
lastStatsTime: time.Now().UnixNano(), lastStatsTime: time.Now().UnixNano(),
}, nil }, nil
} }
@ -85,9 +85,9 @@ func (s *OutputStreamer) Start() error {
// Start multiple goroutines for optimal performance // Start multiple goroutines for optimal performance
s.wg.Add(3) s.wg.Add(3)
go s.streamLoop() // Main streaming loop go s.streamLoop() // Main streaming loop
go s.processingLoop() // Frame processing loop go s.processingLoop() // Frame processing loop
go s.statisticsLoop() // Performance monitoring loop go s.statisticsLoop() // Performance monitoring loop
return nil return nil
} }
@ -192,7 +192,7 @@ func (s *OutputStreamer) processingLoop() {
} }
}() }()
for _ = range s.processingChan { for range s.processingChan {
// Process frame (currently just receiving, but can be extended) // Process frame (currently just receiving, but can be extended)
if _, err := s.client.ReceiveFrame(); err != nil { if _, err := s.client.ReceiveFrame(); err != nil {
if s.client.IsConnected() { if s.client.IsConnected() {
@ -260,13 +260,13 @@ func (s *OutputStreamer) GetDetailedStats() map[string]interface{} {
processingTime := atomic.LoadInt64(&s.processingTime) processingTime := atomic.LoadInt64(&s.processingTime)
stats := map[string]interface{}{ stats := map[string]interface{}{
"processed_frames": processed, "processed_frames": processed,
"dropped_frames": dropped, "dropped_frames": dropped,
"avg_processing_time_ns": processingTime, "avg_processing_time_ns": processingTime,
"batch_size": s.batchSize, "batch_size": s.batchSize,
"channel_buffer_size": cap(s.processingChan), "channel_buffer_size": cap(s.processingChan),
"channel_current_size": len(s.processingChan), "channel_current_size": len(s.processingChan),
"connected": s.client.IsConnected(), "connected": s.client.IsConnected(),
} }
if processed+dropped > 0 { if processed+dropped > 0 {

View File

@ -36,14 +36,14 @@ const (
// PriorityScheduler manages thread priorities for audio processing // PriorityScheduler manages thread priorities for audio processing
type PriorityScheduler struct { type PriorityScheduler struct {
logger zerolog.Logger logger zerolog.Logger
enabled bool enabled bool
} }
// NewPriorityScheduler creates a new priority scheduler // NewPriorityScheduler creates a new priority scheduler
func NewPriorityScheduler() *PriorityScheduler { func NewPriorityScheduler() *PriorityScheduler {
return &PriorityScheduler{ return &PriorityScheduler{
logger: logging.GetDefaultLogger().With().Str("component", "priority-scheduler").Logger(), logger: logging.GetDefaultLogger().With().Str("component", "priority-scheduler").Logger(),
enabled: true, enabled: true,
} }
} }

View File

@ -20,14 +20,14 @@ type ZeroCopyAudioFrame struct {
// ZeroCopyFramePool manages reusable zero-copy audio frames // ZeroCopyFramePool manages reusable zero-copy audio frames
type ZeroCopyFramePool struct { type ZeroCopyFramePool struct {
// Atomic fields MUST be first for ARM32 alignment (int64 fields need 8-byte alignment) // Atomic fields MUST be first for ARM32 alignment (int64 fields need 8-byte alignment)
counter int64 // Frame counter (atomic) counter int64 // Frame counter (atomic)
hitCount int64 // Pool hit counter (atomic) hitCount int64 // Pool hit counter (atomic)
missCount int64 // Pool miss counter (atomic) missCount int64 // Pool miss counter (atomic)
// Other fields // Other fields
pool sync.Pool pool sync.Pool
maxSize int maxSize int
mutex sync.RWMutex mutex sync.RWMutex
// Memory optimization fields // Memory optimization fields
preallocated []*ZeroCopyAudioFrame // Pre-allocated frames for immediate use preallocated []*ZeroCopyAudioFrame // Pre-allocated frames for immediate use
preallocSize int // Number of pre-allocated frames preallocSize int // Number of pre-allocated frames

View File

@ -30,12 +30,12 @@ type Session struct {
AudioInputManager *audio.AudioInputManager AudioInputManager *audio.AudioInputManager
shouldUmountVirtualMedia bool shouldUmountVirtualMedia bool
// Microphone operation throttling // Microphone operation throttling
micCooldown time.Duration micCooldown time.Duration
// Audio frame processing // Audio frame processing
audioFrameChan chan []byte audioFrameChan chan []byte
audioStopChan chan struct{} audioStopChan chan struct{}
audioWg sync.WaitGroup audioWg sync.WaitGroup
rpcQueue chan webrtc.DataChannelMessage rpcQueue chan webrtc.DataChannelMessage
} }
type SessionConfig struct { type SessionConfig struct {