From f2edfa66f0942ab17c6f3649808a7e1297038846 Mon Sep 17 00:00:00 2001 From: Alex P Date: Sat, 20 Sep 2025 00:54:14 +0300 Subject: [PATCH] [WIP] Cleanup: PR Cleanup --- internal/audio/cgo_audio.go | 92 ++++++++++++++----------------------- 1 file changed, 34 insertions(+), 58 deletions(-) diff --git a/internal/audio/cgo_audio.go b/internal/audio/cgo_audio.go index 6b8186bd..4fc0d5f3 100644 --- a/internal/audio/cgo_audio.go +++ b/internal/audio/cgo_audio.go @@ -94,28 +94,25 @@ func cgoAudioInit() error { cache := GetCachedConfig() cache.Update() - // Enable C trace logging if Go audio scope trace level is active - // Enable C trace logging if Go audio scope trace level is active audioLogger := logging.GetSubsystemLogger("audio") loggerTraceEnabled := audioLogger.GetLevel() <= zerolog.TraceLevel // Manual check for audio scope in PION_LOG_TRACE (workaround for logging system bug) - manualTraceEnabled := false - pionTrace := os.Getenv("PION_LOG_TRACE") - if pionTrace != "" { - scopes := strings.Split(strings.ToLower(pionTrace), ",") - for _, scope := range scopes { - if strings.TrimSpace(scope) == "audio" { - manualTraceEnabled = true - break + traceEnabled := loggerTraceEnabled + if !loggerTraceEnabled { + pionTrace := os.Getenv("PION_LOG_TRACE") + if pionTrace != "" { + scopes := strings.Split(strings.ToLower(pionTrace), ",") + for _, scope := range scopes { + if strings.TrimSpace(scope) == "audio" { + traceEnabled = true + break + } } } } - // Use manual check as fallback if logging system fails - traceEnabled := loggerTraceEnabled || manualTraceEnabled - CGOSetTraceLogging(traceEnabled) // Update C constants from cached config (atomic access, no locks) @@ -150,15 +147,17 @@ func cgoAudioClose() { // AudioConfigCache provides a comprehensive caching system for audio configuration type AudioConfigCache struct { - // Atomic int64 fields MUST be first for ARM32 alignment (8-byte alignment required) - minFrameDuration atomic.Int64 // Store as nanoseconds - maxFrameDuration atomic.Int64 // Store as nanoseconds - maxLatency atomic.Int64 // Store as nanoseconds - minMetricsUpdateInterval atomic.Int64 // Store as nanoseconds - maxMetricsUpdateInterval atomic.Int64 // Store as nanoseconds - restartWindow atomic.Int64 // Store as nanoseconds - restartDelay atomic.Int64 // Store as nanoseconds - maxRestartDelay atomic.Int64 // Store as nanoseconds + // All duration fields use int32 by storing as milliseconds for optimal ARM NEON performance + maxMetricsUpdateInterval atomic.Int32 // Store as milliseconds (10s = 10K ms < int32 max) + restartWindow atomic.Int32 // Store as milliseconds (5min = 300K ms < int32 max) + restartDelay atomic.Int32 // Store as milliseconds + maxRestartDelay atomic.Int32 // Store as milliseconds + + // Short-duration fields stored as milliseconds with int32 + minFrameDuration atomic.Int32 // Store as milliseconds (10ms = 10 ms < int32 max) + maxFrameDuration atomic.Int32 // Store as milliseconds (100ms = 100 ms < int32 max) + maxLatency atomic.Int32 // Store as milliseconds (500ms = 500 ms < int32 max) + minMetricsUpdateInterval atomic.Int32 // Store as milliseconds (100ms = 100 ms < int32 max) // Atomic int32 fields for lock-free access to frequently used values minReadEncodeBuffer atomic.Int32 @@ -246,8 +245,16 @@ func (c *AudioConfigCache) Update() { // Update additional validation values c.maxAudioFrameSize.Store(int32(Config.MaxAudioFrameSize)) c.maxChannels.Store(int32(Config.MaxChannels)) - c.minFrameDuration.Store(int64(Config.MinFrameDuration)) - c.maxFrameDuration.Store(int64(Config.MaxFrameDuration)) + + // Store duration fields as milliseconds for int32 optimization + c.minFrameDuration.Store(int32(Config.MinFrameDuration / time.Millisecond)) + c.maxFrameDuration.Store(int32(Config.MaxFrameDuration / time.Millisecond)) + c.maxLatency.Store(int32(Config.MaxLatency / time.Millisecond)) + c.minMetricsUpdateInterval.Store(int32(Config.MinMetricsUpdateInterval / time.Millisecond)) + c.maxMetricsUpdateInterval.Store(int32(Config.MaxMetricsUpdateInterval / time.Millisecond)) + c.restartWindow.Store(int32(Config.RestartWindow / time.Millisecond)) + c.restartDelay.Store(int32(Config.RestartDelay / time.Millisecond)) + c.maxRestartDelay.Store(int32(Config.MaxRestartDelay / time.Millisecond)) c.minOpusBitrate.Store(int32(Config.MinOpusBitrate)) c.maxOpusBitrate.Store(int32(Config.MaxOpusBitrate)) @@ -298,20 +305,6 @@ func (c *AudioConfigCache) GetBufferTooLargeError() error { return c.bufferTooLargeDecodeWrite } -// updateCacheIfNeeded updates cache only if expired to avoid overhead -func updateCacheIfNeeded(cache *AudioConfigCache) { - if cache.initialized.Load() { - cache.mutex.RLock() - cacheExpired := time.Since(cache.lastUpdate) > cache.cacheExpiry - cache.mutex.RUnlock() - if cacheExpired { - cache.Update() - } - } else { - cache.Update() - } -} - func cgoAudioReadEncode(buf []byte) (int, error) { // Minimal buffer validation - assume caller provides correct size if len(buf) == 0 { @@ -410,7 +403,6 @@ func cgoAudioDecodeWrite(buf []byte) (int, error) { return n, nil } - // Error handling with static errors audioDecodeWriteFailures.Add(1) var errMsg string var err error @@ -480,7 +472,7 @@ func ReturnBufferToPool(buf []byte) { // ReadEncodeWithPooledBuffer reads audio data and encodes it using a buffer from the pool func ReadEncodeWithPooledBuffer() ([]byte, int, error) { cache := GetCachedConfig() - updateCacheIfNeeded(cache) + cache.Update() bufferSize := cache.GetMinReadEncodeBuffer() if bufferSize == 0 { @@ -504,7 +496,7 @@ func DecodeWriteWithPooledBuffer(data []byte) (int, error) { } cache := GetCachedConfig() - updateCacheIfNeeded(cache) + cache.Update() maxPacketSize := cache.GetMaxPacketSize() if len(data) > maxPacketSize { @@ -552,18 +544,7 @@ func cgoAudioDecodeWriteWithBuffers(opusData []byte, pcmBuffer []byte) (int, err // Get cached config cache := GetCachedConfig() - // Only update cache if expired - avoid unnecessary overhead - // Use proper locking to avoid race condition - if cache.initialized.Load() { - cache.mutex.RLock() - cacheExpired := time.Since(cache.lastUpdate) > cache.cacheExpiry - cache.mutex.RUnlock() - if cacheExpired { - cache.Update() - } - } else { - cache.Update() - } + cache.Update() // Ensure data doesn't exceed max packet size maxPacketSize := cache.GetMaxPacketSize() @@ -574,8 +555,6 @@ func cgoAudioDecodeWriteWithBuffers(opusData []byte, pcmBuffer []byte) (int, err return 0, newBufferTooLargeError(len(opusData), maxPacketSize) } - // Metrics tracking only - detailed logging handled at application level - // Direct CGO call with minimal overhead - unsafe.Pointer(&slice[0]) is never nil for non-empty slices n := int(C.jetkvm_audio_decode_write(unsafe.Pointer(&opusData[0]), C.int(len(opusData)))) @@ -585,7 +564,6 @@ func cgoAudioDecodeWriteWithBuffers(opusData []byte, pcmBuffer []byte) (int, err return n, nil } - // Handle error cases with static error codes to reduce allocations audioDecodeWriteFailures.Add(1) var errMsg string var err error @@ -608,8 +586,6 @@ func cgoAudioDecodeWriteWithBuffers(opusData []byte, pcmBuffer []byte) (int, err return 0, err } -// Optimized CGO function aliases - use direct function calls to reduce overhead -// These are now direct function aliases instead of variable assignments func CGOAudioInit() error { return cgoAudioInit() } func CGOAudioClose() { cgoAudioClose() } func CGOAudioReadEncode(buf []byte) (int, error) { return cgoAudioReadEncode(buf) }