mirror of https://github.com/jetkvm/kvm.git
Fix: linting errors
This commit is contained in:
parent
a9a1082bcc
commit
3a28105f56
|
@ -14,19 +14,19 @@ import (
|
|||
// AdaptiveBufferConfig holds configuration for adaptive buffer sizing
|
||||
type AdaptiveBufferConfig struct {
|
||||
// Buffer size limits (in frames)
|
||||
MinBufferSize int
|
||||
MaxBufferSize int
|
||||
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
|
||||
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
|
||||
TargetLatency time.Duration
|
||||
MaxLatency time.Duration
|
||||
|
||||
// Adaptation parameters
|
||||
AdaptationInterval time.Duration
|
||||
|
@ -37,13 +37,13 @@ type AdaptiveBufferConfig struct {
|
|||
func DefaultAdaptiveBufferConfig() AdaptiveBufferConfig {
|
||||
return AdaptiveBufferConfig{
|
||||
// Conservative buffer sizes for 256MB RAM constraint
|
||||
MinBufferSize: 3, // Minimum 3 frames (slightly higher for stability)
|
||||
MaxBufferSize: 20, // Maximum 20 frames (increased for high load scenarios)
|
||||
DefaultBufferSize: 6, // Default 6 frames (increased for better stability)
|
||||
MinBufferSize: 3, // Minimum 3 frames (slightly higher for stability)
|
||||
MaxBufferSize: 20, // Maximum 20 frames (increased for high load scenarios)
|
||||
DefaultBufferSize: 6, // Default 6 frames (increased for better stability)
|
||||
|
||||
// CPU thresholds optimized for single-core ARM Cortex A7 under load
|
||||
LowCPUThreshold: 20.0, // Below 20% CPU
|
||||
HighCPUThreshold: 60.0, // Above 60% CPU (lowered to be more responsive)
|
||||
LowCPUThreshold: 20.0, // Below 20% CPU
|
||||
HighCPUThreshold: 60.0, // Above 60% CPU (lowered to be more responsive)
|
||||
|
||||
// Memory thresholds for 256MB total RAM
|
||||
LowMemoryThreshold: 35.0, // Below 35% memory usage
|
||||
|
@ -55,7 +55,7 @@ func DefaultAdaptiveBufferConfig() AdaptiveBufferConfig {
|
|||
|
||||
// Adaptation settings
|
||||
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)
|
||||
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)
|
||||
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
|
||||
|
@ -79,7 +79,7 @@ type AdaptiveBufferManager struct {
|
|||
wg sync.WaitGroup
|
||||
|
||||
// Metrics tracking
|
||||
lastAdaptation time.Time
|
||||
lastAdaptation time.Time
|
||||
mutex sync.RWMutex
|
||||
}
|
||||
|
||||
|
@ -90,12 +90,12 @@ func NewAdaptiveBufferManager(config AdaptiveBufferConfig) *AdaptiveBufferManage
|
|||
return &AdaptiveBufferManager{
|
||||
currentInputBufferSize: int64(config.DefaultBufferSize),
|
||||
currentOutputBufferSize: int64(config.DefaultBufferSize),
|
||||
config: config,
|
||||
logger: logging.GetDefaultLogger().With().Str("component", "adaptive-buffer").Logger(),
|
||||
processMonitor: GetProcessMonitor(),
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
lastAdaptation: time.Now(),
|
||||
config: config,
|
||||
logger: logging.GetDefaultLogger().With().Str("component", "adaptive-buffer").Logger(),
|
||||
processMonitor: GetProcessMonitor(),
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
lastAdaptation: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -179,7 +179,7 @@ func (abm *AdaptiveBufferManager) adaptBufferSizes() {
|
|||
}
|
||||
|
||||
// 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
|
||||
|
||||
atomic.StoreInt64(&abm.systemCPUPercent, int64(systemCPU*100))
|
||||
|
@ -303,13 +303,13 @@ func (abm *AdaptiveBufferManager) GetStats() map[string]interface{} {
|
|||
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)) / 100,
|
||||
"input_buffer_size": abm.GetInputBufferSize(),
|
||||
"output_buffer_size": abm.GetOutputBufferSize(),
|
||||
"average_latency_ms": float64(atomic.LoadInt64(&abm.averageLatency)) / 1e6,
|
||||
"system_cpu_percent": float64(atomic.LoadInt64(&abm.systemCPUPercent)) / 100,
|
||||
"system_memory_percent": float64(atomic.LoadInt64(&abm.systemMemoryPercent)) / 100,
|
||||
"adaptation_count": atomic.LoadInt64(&abm.adaptationCount),
|
||||
"last_adaptation": lastAdaptation,
|
||||
"adaptation_count": atomic.LoadInt64(&abm.adaptationCount),
|
||||
"last_adaptation": lastAdaptation,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,28 +27,25 @@ type AdaptiveOptimizer struct {
|
|||
|
||||
// Configuration
|
||||
config OptimizerConfig
|
||||
mutex sync.RWMutex
|
||||
}
|
||||
|
||||
// OptimizerConfig holds configuration for the adaptive optimizer
|
||||
type OptimizerConfig struct {
|
||||
MaxOptimizationLevel int // Maximum optimization level (0-10)
|
||||
CooldownPeriod time.Duration // Minimum time between optimizations
|
||||
Aggressiveness float64 // How aggressively to optimize (0.0-1.0)
|
||||
RollbackThreshold time.Duration // Latency threshold to rollback optimizations
|
||||
StabilityPeriod time.Duration // Time to wait for stability after optimization
|
||||
CooldownPeriod time.Duration // Minimum time between optimizations
|
||||
Aggressiveness float64 // How aggressively to optimize (0.0-1.0)
|
||||
RollbackThreshold time.Duration // Latency threshold to rollback optimizations
|
||||
StabilityPeriod time.Duration // Time to wait for stability after optimization
|
||||
}
|
||||
|
||||
|
||||
|
||||
// DefaultOptimizerConfig returns a sensible default configuration
|
||||
func DefaultOptimizerConfig() OptimizerConfig {
|
||||
return OptimizerConfig{
|
||||
MaxOptimizationLevel: 8,
|
||||
CooldownPeriod: 30 * time.Second,
|
||||
Aggressiveness: 0.7,
|
||||
RollbackThreshold: 300 * time.Millisecond,
|
||||
StabilityPeriod: 10 * time.Second,
|
||||
CooldownPeriod: 30 * time.Second,
|
||||
Aggressiveness: 0.7,
|
||||
RollbackThreshold: 300 * time.Millisecond,
|
||||
StabilityPeriod: 10 * time.Second,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,8 +62,6 @@ func NewAdaptiveOptimizer(latencyMonitor *LatencyMonitor, bufferManager *Adaptiv
|
|||
cancel: cancel,
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Register as latency monitor callback
|
||||
latencyMonitor.AddOptimizationCallback(optimizer.handleLatencyOptimization)
|
||||
|
||||
|
@ -89,7 +84,6 @@ func (ao *AdaptiveOptimizer) Stop() {
|
|||
|
||||
// initializeStrategies sets up the available optimization strategies
|
||||
|
||||
|
||||
// handleLatencyOptimization is called when latency optimization is needed
|
||||
func (ao *AdaptiveOptimizer) handleLatencyOptimization(metrics LatencyMetrics) error {
|
||||
currentLevel := atomic.LoadInt64(&ao.optimizationLevel)
|
||||
|
@ -185,7 +179,9 @@ func (ao *AdaptiveOptimizer) checkStability() {
|
|||
currentLevel := int(atomic.LoadInt64(&ao.optimizationLevel))
|
||||
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.decreaseOptimization(currentLevel - 1)
|
||||
if err := ao.decreaseOptimization(currentLevel - 1); err != nil {
|
||||
ao.logger.Error().Err(err).Msg("Failed to decrease optimization level")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,15 +7,15 @@ import (
|
|||
|
||||
type AudioBufferPool struct {
|
||||
// Atomic fields MUST be first for ARM32 alignment (int64 fields need 8-byte alignment)
|
||||
currentSize int64 // Current pool size (atomic)
|
||||
hitCount int64 // Pool hit counter (atomic)
|
||||
missCount int64 // Pool miss counter (atomic)
|
||||
currentSize int64 // Current pool size (atomic)
|
||||
hitCount int64 // Pool hit counter (atomic)
|
||||
missCount int64 // Pool miss counter (atomic)
|
||||
|
||||
// Other fields
|
||||
pool sync.Pool
|
||||
bufferSize int
|
||||
maxPoolSize int
|
||||
mutex sync.RWMutex
|
||||
pool sync.Pool
|
||||
bufferSize int
|
||||
maxPoolSize int
|
||||
mutex sync.RWMutex
|
||||
// Memory optimization fields
|
||||
preallocated []*[]byte // Pre-allocated buffers for immediate use
|
||||
preallocSize int // Number of pre-allocated buffers
|
||||
|
@ -33,8 +33,8 @@ func NewAudioBufferPool(bufferSize int) *AudioBufferPool {
|
|||
}
|
||||
|
||||
return &AudioBufferPool{
|
||||
bufferSize: bufferSize,
|
||||
maxPoolSize: 100, // Limit pool size to prevent excessive memory usage
|
||||
bufferSize: bufferSize,
|
||||
maxPoolSize: 100, // Limit pool size to prevent excessive memory usage
|
||||
preallocated: preallocated,
|
||||
preallocSize: preallocSize,
|
||||
pool: sync.Pool{
|
||||
|
@ -59,7 +59,7 @@ func (p *AudioBufferPool) Get() []byte {
|
|||
|
||||
// Try sync.Pool next
|
||||
if buf := p.pool.Get(); buf != nil {
|
||||
bufSlice := buf.([]byte)
|
||||
bufPtr := buf.(*[]byte)
|
||||
// Update pool size counter when retrieving from pool
|
||||
p.mutex.Lock()
|
||||
if p.currentSize > 0 {
|
||||
|
@ -67,7 +67,7 @@ func (p *AudioBufferPool) Get() []byte {
|
|||
}
|
||||
p.mutex.Unlock()
|
||||
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
|
||||
|
@ -102,7 +102,7 @@ func (p *AudioBufferPool) Put(buf []byte) {
|
|||
}
|
||||
|
||||
// Return to sync.Pool
|
||||
p.pool.Put(resetBuf)
|
||||
p.pool.Put(&resetBuf)
|
||||
|
||||
// Update pool size counter
|
||||
p.mutex.Lock()
|
||||
|
@ -173,15 +173,15 @@ type AudioBufferPoolDetailedStats struct {
|
|||
|
||||
// GetAudioBufferPoolStats returns statistics about the audio buffer pools
|
||||
type AudioBufferPoolStats struct {
|
||||
FramePoolSize int64
|
||||
FramePoolMax int
|
||||
ControlPoolSize int64
|
||||
ControlPoolMax int
|
||||
FramePoolSize int64
|
||||
FramePoolMax int
|
||||
ControlPoolSize int64
|
||||
ControlPoolMax int
|
||||
// Enhanced statistics
|
||||
FramePoolHitRate float64
|
||||
ControlPoolHitRate float64
|
||||
FramePoolDetails AudioBufferPoolDetailedStats
|
||||
ControlPoolDetails AudioBufferPoolDetailedStats
|
||||
FramePoolHitRate float64
|
||||
ControlPoolHitRate float64
|
||||
FramePoolDetails AudioBufferPoolDetailedStats
|
||||
ControlPoolDetails AudioBufferPoolDetailedStats
|
||||
}
|
||||
|
||||
func GetAudioBufferPoolStats() AudioBufferPoolStats {
|
||||
|
@ -200,13 +200,13 @@ func GetAudioBufferPoolStats() AudioBufferPoolStats {
|
|||
controlDetails := audioControlPool.GetPoolStats()
|
||||
|
||||
return AudioBufferPoolStats{
|
||||
FramePoolSize: frameSize,
|
||||
FramePoolMax: frameMax,
|
||||
ControlPoolSize: controlSize,
|
||||
ControlPoolMax: controlMax,
|
||||
FramePoolHitRate: frameDetails.HitRate,
|
||||
ControlPoolHitRate: controlDetails.HitRate,
|
||||
FramePoolDetails: frameDetails,
|
||||
ControlPoolDetails: controlDetails,
|
||||
FramePoolSize: frameSize,
|
||||
FramePoolMax: frameMax,
|
||||
ControlPoolSize: controlSize,
|
||||
ControlPoolMax: controlMax,
|
||||
FramePoolHitRate: frameDetails.HitRate,
|
||||
ControlPoolHitRate: controlDetails.HitRate,
|
||||
FramePoolDetails: frameDetails,
|
||||
ControlPoolDetails: controlDetails,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,18 +49,18 @@ type InputIPCMessage struct {
|
|||
// OptimizedIPCMessage represents an optimized message with pre-allocated buffers
|
||||
type OptimizedIPCMessage struct {
|
||||
header [headerSize]byte // Pre-allocated header buffer
|
||||
data []byte // Reusable data buffer
|
||||
msg InputIPCMessage // Embedded message
|
||||
data []byte // Reusable data buffer
|
||||
msg InputIPCMessage // Embedded message
|
||||
}
|
||||
|
||||
// MessagePool manages a pool of reusable messages to reduce allocations
|
||||
type MessagePool struct {
|
||||
// Atomic fields MUST be first for ARM32 alignment (int64 fields need 8-byte alignment)
|
||||
hitCount int64 // Pool hit counter (atomic)
|
||||
missCount int64 // Pool miss counter (atomic)
|
||||
hitCount int64 // Pool hit counter (atomic)
|
||||
missCount int64 // Pool miss counter (atomic)
|
||||
|
||||
// Other fields
|
||||
pool chan *OptimizedIPCMessage
|
||||
pool chan *OptimizedIPCMessage
|
||||
// Memory optimization fields
|
||||
preallocated []*OptimizedIPCMessage // Pre-allocated messages for immediate use
|
||||
preallocSize int // Number of pre-allocated messages
|
||||
|
@ -73,32 +73,37 @@ var globalMessagePool = &MessagePool{
|
|||
pool: make(chan *OptimizedIPCMessage, messagePoolSize),
|
||||
}
|
||||
|
||||
// Initialize the message pool with pre-allocated messages
|
||||
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)
|
||||
var messagePoolInitOnce sync.Once
|
||||
|
||||
// Pre-allocate messages to reduce initial allocation overhead
|
||||
for i := 0; i < preallocSize; i++ {
|
||||
msg := &OptimizedIPCMessage{
|
||||
data: make([]byte, 0, maxFrameSize),
|
||||
}
|
||||
globalMessagePool.preallocated = append(globalMessagePool.preallocated, msg)
|
||||
}
|
||||
// initializeMessagePool initializes the message pool with pre-allocated messages
|
||||
func initializeMessagePool() {
|
||||
messagePoolInitOnce.Do(func() {
|
||||
// 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)
|
||||
|
||||
// Fill the channel pool with remaining messages
|
||||
for i := preallocSize; i < messagePoolSize; i++ {
|
||||
globalMessagePool.pool <- &OptimizedIPCMessage{
|
||||
data: make([]byte, 0, maxFrameSize),
|
||||
// Pre-allocate messages to reduce initial allocation overhead
|
||||
for i := 0; i < preallocSize; i++ {
|
||||
msg := &OptimizedIPCMessage{
|
||||
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
|
||||
func (mp *MessagePool) Get() *OptimizedIPCMessage {
|
||||
initializeMessagePool()
|
||||
// First try pre-allocated messages for fastest access
|
||||
mp.mutex.Lock()
|
||||
if len(mp.preallocated) > 0 {
|
||||
|
|
|
@ -16,13 +16,13 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
outputMagicNumber uint32 = 0x4A4B4F55 // "JKOU" (JetKVM Output)
|
||||
outputSocketName = "audio_output.sock"
|
||||
outputMaxFrameSize = 4096 // Maximum Opus frame size
|
||||
outputWriteTimeout = 10 * time.Millisecond // Non-blocking write timeout (increased for high load)
|
||||
outputMaxDroppedFrames = 50 // Maximum consecutive dropped frames
|
||||
outputHeaderSize = 17 // Fixed header size: 4+1+4+8 bytes
|
||||
outputMessagePoolSize = 128 // Pre-allocated message pool size
|
||||
outputMagicNumber uint32 = 0x4A4B4F55 // "JKOU" (JetKVM Output)
|
||||
outputSocketName = "audio_output.sock"
|
||||
outputMaxFrameSize = 4096 // Maximum Opus frame size
|
||||
outputWriteTimeout = 10 * time.Millisecond // Non-blocking write timeout (increased for high load)
|
||||
outputMaxDroppedFrames = 50 // Maximum consecutive dropped frames
|
||||
outputHeaderSize = 17 // Fixed header size: 4+1+4+8 bytes
|
||||
outputMessagePoolSize = 128 // Pre-allocated message pool size
|
||||
)
|
||||
|
||||
// OutputMessageType represents the type of IPC message
|
||||
|
@ -101,10 +101,9 @@ var globalOutputMessagePool = NewOutputMessagePool(outputMessagePoolSize)
|
|||
|
||||
type AudioServer struct {
|
||||
// Atomic fields must be first for proper alignment on ARM
|
||||
bufferSize int64 // Current buffer size (atomic)
|
||||
processingTime int64 // Average processing time in nanoseconds (atomic)
|
||||
droppedFrames int64 // Dropped frames counter (atomic)
|
||||
totalFrames int64 // Total frames counter (atomic)
|
||||
bufferSize int64 // Current buffer size (atomic)
|
||||
droppedFrames int64 // Dropped frames counter (atomic)
|
||||
totalFrames int64 // Total frames counter (atomic)
|
||||
|
||||
listener net.Listener
|
||||
conn net.Conn
|
||||
|
@ -117,7 +116,7 @@ type AudioServer struct {
|
|||
wg sync.WaitGroup // Wait group for goroutine coordination
|
||||
|
||||
// Latency monitoring
|
||||
latencyMonitor *LatencyMonitor
|
||||
latencyMonitor *LatencyMonitor
|
||||
adaptiveOptimizer *AdaptiveOptimizer
|
||||
}
|
||||
|
||||
|
@ -216,7 +215,10 @@ func (s *AudioServer) startProcessorGoroutine() {
|
|||
case msg := <-s.messageChan:
|
||||
// Process message (currently just frame sending)
|
||||
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:
|
||||
return
|
||||
|
|
|
@ -30,7 +30,7 @@ type LatencyMonitor struct {
|
|||
|
||||
// Optimization callbacks
|
||||
optimizationCallbacks []OptimizationCallback
|
||||
mutex sync.RWMutex
|
||||
mutex sync.RWMutex
|
||||
|
||||
// Performance tracking
|
||||
latencyHistory []LatencyMeasurement
|
||||
|
@ -39,12 +39,12 @@ type LatencyMonitor struct {
|
|||
|
||||
// LatencyConfig holds configuration for latency monitoring
|
||||
type LatencyConfig struct {
|
||||
TargetLatency time.Duration // Target latency to maintain
|
||||
MaxLatency time.Duration // Maximum acceptable latency
|
||||
TargetLatency time.Duration // Target latency to maintain
|
||||
MaxLatency time.Duration // Maximum acceptable latency
|
||||
OptimizationInterval time.Duration // How often to run optimization
|
||||
HistorySize int // Number of latency measurements to keep
|
||||
JitterThreshold time.Duration // Jitter threshold for optimization
|
||||
AdaptiveThreshold float64 // Threshold for adaptive adjustments (0.0-1.0)
|
||||
HistorySize int // Number of latency measurements to keep
|
||||
JitterThreshold time.Duration // Jitter threshold for optimization
|
||||
AdaptiveThreshold float64 // Threshold for adaptive adjustments (0.0-1.0)
|
||||
}
|
||||
|
||||
// LatencyMeasurement represents a single latency measurement
|
||||
|
@ -83,11 +83,11 @@ const (
|
|||
func DefaultLatencyConfig() LatencyConfig {
|
||||
return LatencyConfig{
|
||||
TargetLatency: 50 * time.Millisecond,
|
||||
MaxLatency: 200 * time.Millisecond,
|
||||
MaxLatency: 200 * time.Millisecond,
|
||||
OptimizationInterval: 5 * time.Second,
|
||||
HistorySize: 100,
|
||||
JitterThreshold: 20 * time.Millisecond,
|
||||
AdaptiveThreshold: 0.8, // Trigger optimization when 80% above target
|
||||
HistorySize: 100,
|
||||
JitterThreshold: 20 * time.Millisecond,
|
||||
AdaptiveThreshold: 0.8, // Trigger optimization when 80% above target
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,17 +13,17 @@ import (
|
|||
// MemoryMetrics provides comprehensive memory allocation statistics
|
||||
type MemoryMetrics struct {
|
||||
// Runtime memory statistics
|
||||
RuntimeStats RuntimeMemoryStats `json:"runtime_stats"`
|
||||
RuntimeStats RuntimeMemoryStats `json:"runtime_stats"`
|
||||
// Audio buffer pool statistics
|
||||
BufferPools AudioBufferPoolStats `json:"buffer_pools"`
|
||||
BufferPools AudioBufferPoolStats `json:"buffer_pools"`
|
||||
// Zero-copy frame pool statistics
|
||||
ZeroCopyPool ZeroCopyFramePoolStats `json:"zero_copy_pool"`
|
||||
ZeroCopyPool ZeroCopyFramePoolStats `json:"zero_copy_pool"`
|
||||
// Message pool statistics
|
||||
MessagePool MessagePoolStats `json:"message_pool"`
|
||||
MessagePool MessagePoolStats `json:"message_pool"`
|
||||
// Batch processor statistics
|
||||
BatchProcessor BatchProcessorMemoryStats `json:"batch_processor,omitempty"`
|
||||
BatchProcessor BatchProcessorMemoryStats `json:"batch_processor,omitempty"`
|
||||
// Collection timestamp
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
}
|
||||
|
||||
// RuntimeMemoryStats provides Go runtime memory statistics
|
||||
|
@ -59,10 +59,10 @@ type RuntimeMemoryStats struct {
|
|||
|
||||
// BatchProcessorMemoryStats provides batch processor memory statistics
|
||||
type BatchProcessorMemoryStats struct {
|
||||
Initialized bool `json:"initialized"`
|
||||
Running bool `json:"running"`
|
||||
Stats BatchAudioStats `json:"stats"`
|
||||
BufferPool AudioBufferPoolDetailedStats `json:"buffer_pool,omitempty"`
|
||||
Initialized bool `json:"initialized"`
|
||||
Running bool `json:"running"`
|
||||
Stats BatchAudioStats `json:"stats"`
|
||||
BufferPool AudioBufferPoolDetailedStats `json:"buffer_pool,omitempty"`
|
||||
}
|
||||
|
||||
// GetBatchAudioProcessor is defined in batch_audio.go
|
||||
|
|
|
@ -13,7 +13,7 @@ type MicrophoneContentionManager struct {
|
|||
cooldownNanos int64
|
||||
operationID int64
|
||||
|
||||
lockPtr unsafe.Pointer
|
||||
lockPtr unsafe.Pointer
|
||||
}
|
||||
|
||||
func NewMicrophoneContentionManager(cooldown time.Duration) *MicrophoneContentionManager {
|
||||
|
|
|
@ -61,9 +61,9 @@ func NewOutputStreamer() (*OutputStreamer, error) {
|
|||
bufferPool: NewAudioBufferPool(MaxAudioFrameSize), // Use existing buffer pool
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
batchSize: initialBatchSize, // Use adaptive batch size
|
||||
processingChan: make(chan []byte, 500), // Large buffer for smooth processing
|
||||
statsInterval: 5 * time.Second, // Statistics every 5 seconds
|
||||
batchSize: initialBatchSize, // Use adaptive batch size
|
||||
processingChan: make(chan []byte, 500), // Large buffer for smooth processing
|
||||
statsInterval: 5 * time.Second, // Statistics every 5 seconds
|
||||
lastStatsTime: time.Now().UnixNano(),
|
||||
}, nil
|
||||
}
|
||||
|
@ -85,9 +85,9 @@ func (s *OutputStreamer) Start() error {
|
|||
|
||||
// Start multiple goroutines for optimal performance
|
||||
s.wg.Add(3)
|
||||
go s.streamLoop() // Main streaming loop
|
||||
go s.processingLoop() // Frame processing loop
|
||||
go s.statisticsLoop() // Performance monitoring loop
|
||||
go s.streamLoop() // Main streaming loop
|
||||
go s.processingLoop() // Frame processing loop
|
||||
go s.statisticsLoop() // Performance monitoring loop
|
||||
|
||||
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)
|
||||
if _, err := s.client.ReceiveFrame(); err != nil {
|
||||
if s.client.IsConnected() {
|
||||
|
@ -260,13 +260,13 @@ func (s *OutputStreamer) GetDetailedStats() map[string]interface{} {
|
|||
processingTime := atomic.LoadInt64(&s.processingTime)
|
||||
|
||||
stats := map[string]interface{}{
|
||||
"processed_frames": processed,
|
||||
"dropped_frames": dropped,
|
||||
"processed_frames": processed,
|
||||
"dropped_frames": dropped,
|
||||
"avg_processing_time_ns": processingTime,
|
||||
"batch_size": s.batchSize,
|
||||
"channel_buffer_size": cap(s.processingChan),
|
||||
"channel_current_size": len(s.processingChan),
|
||||
"connected": s.client.IsConnected(),
|
||||
"batch_size": s.batchSize,
|
||||
"channel_buffer_size": cap(s.processingChan),
|
||||
"channel_current_size": len(s.processingChan),
|
||||
"connected": s.client.IsConnected(),
|
||||
}
|
||||
|
||||
if processed+dropped > 0 {
|
||||
|
|
|
@ -36,14 +36,14 @@ const (
|
|||
|
||||
// PriorityScheduler manages thread priorities for audio processing
|
||||
type PriorityScheduler struct {
|
||||
logger zerolog.Logger
|
||||
logger zerolog.Logger
|
||||
enabled bool
|
||||
}
|
||||
|
||||
// NewPriorityScheduler creates a new priority scheduler
|
||||
func NewPriorityScheduler() *PriorityScheduler {
|
||||
return &PriorityScheduler{
|
||||
logger: logging.GetDefaultLogger().With().Str("component", "priority-scheduler").Logger(),
|
||||
logger: logging.GetDefaultLogger().With().Str("component", "priority-scheduler").Logger(),
|
||||
enabled: true,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,14 +20,14 @@ type ZeroCopyAudioFrame struct {
|
|||
// ZeroCopyFramePool manages reusable zero-copy audio frames
|
||||
type ZeroCopyFramePool struct {
|
||||
// Atomic fields MUST be first for ARM32 alignment (int64 fields need 8-byte alignment)
|
||||
counter int64 // Frame counter (atomic)
|
||||
hitCount int64 // Pool hit counter (atomic)
|
||||
missCount int64 // Pool miss counter (atomic)
|
||||
counter int64 // Frame counter (atomic)
|
||||
hitCount int64 // Pool hit counter (atomic)
|
||||
missCount int64 // Pool miss counter (atomic)
|
||||
|
||||
// Other fields
|
||||
pool sync.Pool
|
||||
maxSize int
|
||||
mutex sync.RWMutex
|
||||
pool sync.Pool
|
||||
maxSize int
|
||||
mutex sync.RWMutex
|
||||
// Memory optimization fields
|
||||
preallocated []*ZeroCopyAudioFrame // Pre-allocated frames for immediate use
|
||||
preallocSize int // Number of pre-allocated frames
|
||||
|
|
10
webrtc.go
10
webrtc.go
|
@ -30,12 +30,12 @@ type Session struct {
|
|||
AudioInputManager *audio.AudioInputManager
|
||||
shouldUmountVirtualMedia bool
|
||||
// Microphone operation throttling
|
||||
micCooldown time.Duration
|
||||
micCooldown time.Duration
|
||||
// Audio frame processing
|
||||
audioFrameChan chan []byte
|
||||
audioStopChan chan struct{}
|
||||
audioWg sync.WaitGroup
|
||||
rpcQueue chan webrtc.DataChannelMessage
|
||||
audioFrameChan chan []byte
|
||||
audioStopChan chan struct{}
|
||||
audioWg sync.WaitGroup
|
||||
rpcQueue chan webrtc.DataChannelMessage
|
||||
}
|
||||
|
||||
type SessionConfig struct {
|
||||
|
|
Loading…
Reference in New Issue