mirror of https://github.com/jetkvm/kvm.git
refactor(audio): centralize config constants and update usage
Move hardcoded values to config constants and update all references to use centralized configuration. Includes: - Audio processing timeouts and intervals - CGO sleep durations - Batch processing parameters - Event formatting and timeouts - Process monitor calculations
This commit is contained in:
parent
9e343b3cc7
commit
c5216920b3
|
@ -274,7 +274,8 @@ func GetBatchAudioProcessor() *BatchAudioProcessor {
|
||||||
|
|
||||||
// Initialize on first use
|
// Initialize on first use
|
||||||
if atomic.CompareAndSwapInt32(&batchProcessorInitialized, 0, 1) {
|
if atomic.CompareAndSwapInt32(&batchProcessorInitialized, 0, 1) {
|
||||||
processor := NewBatchAudioProcessor(4, 5*time.Millisecond) // 4 frames per batch, 5ms timeout
|
config := GetConfig()
|
||||||
|
processor := NewBatchAudioProcessor(config.BatchProcessorFramesPerBatch, config.BatchProcessorTimeout)
|
||||||
atomic.StorePointer(&globalBatchProcessor, unsafe.Pointer(processor))
|
atomic.StorePointer(&globalBatchProcessor, unsafe.Pointer(processor))
|
||||||
return processor
|
return processor
|
||||||
}
|
}
|
||||||
|
@ -286,7 +287,8 @@ func GetBatchAudioProcessor() *BatchAudioProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback: create a new processor (should rarely happen)
|
// Fallback: create a new processor (should rarely happen)
|
||||||
return NewBatchAudioProcessor(4, 5*time.Millisecond)
|
config := GetConfig()
|
||||||
|
return NewBatchAudioProcessor(config.BatchProcessorFramesPerBatch, config.BatchProcessorTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnableBatchAudioProcessing enables the global batch processor
|
// EnableBatchAudioProcessing enables the global batch processor
|
||||||
|
|
|
@ -34,7 +34,7 @@ static int sample_rate = 48000; // Will be set from GetConfig().CGOSampl
|
||||||
static int channels = 2; // Will be set from GetConfig().CGOChannels
|
static int channels = 2; // Will be set from GetConfig().CGOChannels
|
||||||
static int frame_size = 960; // Will be set from GetConfig().CGOFrameSize
|
static int frame_size = 960; // Will be set from GetConfig().CGOFrameSize
|
||||||
static int max_packet_size = 1500; // Will be set from GetConfig().CGOMaxPacketSize
|
static int max_packet_size = 1500; // Will be set from GetConfig().CGOMaxPacketSize
|
||||||
static int sleep_microseconds = 50000; // Will be set from GetConfig().CGOSleepMicroseconds
|
static int sleep_microseconds = 1000; // Will be set from GetConfig().CGOUsleepMicroseconds
|
||||||
|
|
||||||
// Function to update constants from Go configuration
|
// Function to update constants from Go configuration
|
||||||
void update_audio_constants(int bitrate, int complexity, int vbr, int vbr_constraint,
|
void update_audio_constants(int bitrate, int complexity, int vbr, int vbr_constraint,
|
||||||
|
@ -244,7 +244,7 @@ int jetkvm_audio_read_encode(void *opus_buf) {
|
||||||
} else if (pcm_rc == -ESTRPIPE) {
|
} else if (pcm_rc == -ESTRPIPE) {
|
||||||
// Device suspended, try to resume
|
// Device suspended, try to resume
|
||||||
while ((err = snd_pcm_resume(pcm_handle)) == -EAGAIN) {
|
while ((err = snd_pcm_resume(pcm_handle)) == -EAGAIN) {
|
||||||
usleep(1000); // 1ms
|
usleep(sleep_microseconds); // Use centralized constant
|
||||||
}
|
}
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
err = snd_pcm_prepare(pcm_handle);
|
err = snd_pcm_prepare(pcm_handle);
|
||||||
|
@ -358,7 +358,7 @@ int jetkvm_audio_decode_write(void *opus_buf, int opus_size) {
|
||||||
} else if (pcm_rc == -ESTRPIPE) {
|
} else if (pcm_rc == -ESTRPIPE) {
|
||||||
// Device suspended, try to resume
|
// Device suspended, try to resume
|
||||||
while ((err = snd_pcm_resume(pcm_playback_handle)) == -EAGAIN) {
|
while ((err = snd_pcm_resume(pcm_playback_handle)) == -EAGAIN) {
|
||||||
usleep(1000); // 1ms
|
usleep(sleep_microseconds); // Use centralized constant
|
||||||
}
|
}
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
err = snd_pcm_prepare(pcm_playback_handle);
|
err = snd_pcm_prepare(pcm_playback_handle);
|
||||||
|
@ -376,7 +376,7 @@ int jetkvm_audio_decode_write(void *opus_buf, int opus_size) {
|
||||||
void jetkvm_audio_playback_close() {
|
void jetkvm_audio_playback_close() {
|
||||||
// Wait for any ongoing operations to complete
|
// Wait for any ongoing operations to complete
|
||||||
while (playback_initializing) {
|
while (playback_initializing) {
|
||||||
usleep(1000); // 1ms
|
usleep(sleep_microseconds); // Use centralized constant
|
||||||
}
|
}
|
||||||
|
|
||||||
// Atomic check and set to prevent double cleanup
|
// Atomic check and set to prevent double cleanup
|
||||||
|
@ -399,7 +399,7 @@ void jetkvm_audio_playback_close() {
|
||||||
void jetkvm_audio_close() {
|
void jetkvm_audio_close() {
|
||||||
// Wait for any ongoing operations to complete
|
// Wait for any ongoing operations to complete
|
||||||
while (capture_initializing) {
|
while (capture_initializing) {
|
||||||
usleep(1000); // 1ms
|
usleep(sleep_microseconds); // Use centralized constant
|
||||||
}
|
}
|
||||||
|
|
||||||
capture_initialized = 0;
|
capture_initialized = 0;
|
||||||
|
@ -448,7 +448,7 @@ func cgoAudioInit() error {
|
||||||
C.int(config.CGOChannels),
|
C.int(config.CGOChannels),
|
||||||
C.int(config.CGOFrameSize),
|
C.int(config.CGOFrameSize),
|
||||||
C.int(config.CGOMaxPacketSize),
|
C.int(config.CGOMaxPacketSize),
|
||||||
C.int(config.CGOSleepMicroseconds),
|
C.int(config.CGOUsleepMicroseconds),
|
||||||
)
|
)
|
||||||
|
|
||||||
result := C.jetkvm_audio_init()
|
result := C.jetkvm_audio_init()
|
||||||
|
|
|
@ -830,6 +830,56 @@ type AudioConfigConstants struct {
|
||||||
PoolGrowthMultiplier int // 2x growth multiplier for pool sizes
|
PoolGrowthMultiplier int // 2x growth multiplier for pool sizes
|
||||||
LatencyScalingFactor float64 // 2.0 for latency ratio scaling
|
LatencyScalingFactor float64 // 2.0 for latency ratio scaling
|
||||||
OptimizerAggressiveness float64 // 0.7 for optimizer aggressiveness
|
OptimizerAggressiveness float64 // 0.7 for optimizer aggressiveness
|
||||||
|
|
||||||
|
// CGO Audio Processing Constants
|
||||||
|
CGOUsleepMicroseconds int // 1000 microseconds (1ms) for CGO usleep calls
|
||||||
|
CGOPCMBufferSize int // 1920 samples for PCM buffer (max 2ch*960)
|
||||||
|
CGONanosecondsPerSecond float64 // 1000000000.0 for nanosecond conversions
|
||||||
|
|
||||||
|
// Frontend Constants
|
||||||
|
FrontendOperationDebounceMS int // 1000ms debounce for frontend operations
|
||||||
|
FrontendSyncDebounceMS int // 1000ms debounce for sync operations
|
||||||
|
FrontendSampleRate int // 48000Hz sample rate for frontend audio
|
||||||
|
FrontendRetryDelayMS int // 500ms retry delay
|
||||||
|
FrontendShortDelayMS int // 200ms short delay
|
||||||
|
FrontendLongDelayMS int // 300ms long delay
|
||||||
|
FrontendSyncDelayMS int // 500ms sync delay
|
||||||
|
FrontendMaxRetryAttempts int // 3 maximum retry attempts
|
||||||
|
FrontendAudioLevelUpdateMS int // 100ms audio level update interval
|
||||||
|
FrontendFFTSize int // 256 FFT size for audio analysis
|
||||||
|
FrontendAudioLevelMax int // 100 maximum audio level
|
||||||
|
FrontendReconnectIntervalMS int // 3000ms reconnect interval
|
||||||
|
FrontendSubscriptionDelayMS int // 100ms subscription delay
|
||||||
|
FrontendDebugIntervalMS int // 5000ms debug interval
|
||||||
|
|
||||||
|
// Process Monitor Constants
|
||||||
|
ProcessMonitorDefaultMemoryGB int // 4GB default memory for fallback
|
||||||
|
ProcessMonitorKBToBytes int // 1024 conversion factor
|
||||||
|
ProcessMonitorDefaultClockHz float64 // 250.0 Hz default for ARM systems
|
||||||
|
ProcessMonitorFallbackClockHz float64 // 1000.0 Hz fallback clock
|
||||||
|
ProcessMonitorTraditionalHz float64 // 100.0 Hz traditional clock
|
||||||
|
|
||||||
|
// Batch Processing Constants
|
||||||
|
BatchProcessorFramesPerBatch int // 4 frames per batch
|
||||||
|
BatchProcessorTimeout time.Duration // 5ms timeout
|
||||||
|
|
||||||
|
// Output Streaming Constants
|
||||||
|
OutputStreamingFrameIntervalMS int // 20ms frame interval (50 FPS)
|
||||||
|
|
||||||
|
// IPC Constants
|
||||||
|
IPCInitialBufferFrames int // 500 frames for initial buffer
|
||||||
|
|
||||||
|
// Event Constants
|
||||||
|
EventTimeoutSeconds int // 2 seconds for event timeout
|
||||||
|
EventTimeFormatString string // "2006-01-02T15:04:05.000Z" time format
|
||||||
|
EventSubscriptionDelayMS int // 100ms subscription delay
|
||||||
|
|
||||||
|
// Input Processing Constants
|
||||||
|
InputProcessingTimeoutMS int // 10ms processing timeout threshold
|
||||||
|
|
||||||
|
// Adaptive Buffer Constants
|
||||||
|
AdaptiveBufferCPUMultiplier int // 100 multiplier for CPU percentage
|
||||||
|
AdaptiveBufferMemoryMultiplier int // 100 multiplier for memory percentage
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultAudioConfig returns the default configuration constants
|
// DefaultAudioConfig returns the default configuration constants
|
||||||
|
@ -1247,6 +1297,56 @@ func DefaultAudioConfig() *AudioConfigConstants {
|
||||||
PoolGrowthMultiplier: 2, // Pool growth multiplier
|
PoolGrowthMultiplier: 2, // Pool growth multiplier
|
||||||
LatencyScalingFactor: 2.0, // Latency ratio scaling factor
|
LatencyScalingFactor: 2.0, // Latency ratio scaling factor
|
||||||
OptimizerAggressiveness: 0.7, // Optimizer aggressiveness factor
|
OptimizerAggressiveness: 0.7, // Optimizer aggressiveness factor
|
||||||
|
|
||||||
|
// CGO Audio Processing Constants
|
||||||
|
CGOUsleepMicroseconds: 1000, // 1000 microseconds (1ms) for CGO usleep calls
|
||||||
|
CGOPCMBufferSize: 1920, // 1920 samples for PCM buffer (max 2ch*960)
|
||||||
|
CGONanosecondsPerSecond: 1000000000.0, // 1000000000.0 for nanosecond conversions
|
||||||
|
|
||||||
|
// Frontend Constants
|
||||||
|
FrontendOperationDebounceMS: 1000, // 1000ms debounce for frontend operations
|
||||||
|
FrontendSyncDebounceMS: 1000, // 1000ms debounce for sync operations
|
||||||
|
FrontendSampleRate: 48000, // 48000Hz sample rate for frontend audio
|
||||||
|
FrontendRetryDelayMS: 500, // 500ms retry delay
|
||||||
|
FrontendShortDelayMS: 200, // 200ms short delay
|
||||||
|
FrontendLongDelayMS: 300, // 300ms long delay
|
||||||
|
FrontendSyncDelayMS: 500, // 500ms sync delay
|
||||||
|
FrontendMaxRetryAttempts: 3, // 3 maximum retry attempts
|
||||||
|
FrontendAudioLevelUpdateMS: 100, // 100ms audio level update interval
|
||||||
|
FrontendFFTSize: 256, // 256 FFT size for audio analysis
|
||||||
|
FrontendAudioLevelMax: 100, // 100 maximum audio level
|
||||||
|
FrontendReconnectIntervalMS: 3000, // 3000ms reconnect interval
|
||||||
|
FrontendSubscriptionDelayMS: 100, // 100ms subscription delay
|
||||||
|
FrontendDebugIntervalMS: 5000, // 5000ms debug interval
|
||||||
|
|
||||||
|
// Process Monitor Constants
|
||||||
|
ProcessMonitorDefaultMemoryGB: 4, // 4GB default memory for fallback
|
||||||
|
ProcessMonitorKBToBytes: 1024, // 1024 conversion factor
|
||||||
|
ProcessMonitorDefaultClockHz: 250.0, // 250.0 Hz default for ARM systems
|
||||||
|
ProcessMonitorFallbackClockHz: 1000.0, // 1000.0 Hz fallback clock
|
||||||
|
ProcessMonitorTraditionalHz: 100.0, // 100.0 Hz traditional clock
|
||||||
|
|
||||||
|
// Batch Processing Constants
|
||||||
|
BatchProcessorFramesPerBatch: 4, // 4 frames per batch
|
||||||
|
BatchProcessorTimeout: 5 * time.Millisecond, // 5ms timeout
|
||||||
|
|
||||||
|
// Output Streaming Constants
|
||||||
|
OutputStreamingFrameIntervalMS: 20, // 20ms frame interval (50 FPS)
|
||||||
|
|
||||||
|
// IPC Constants
|
||||||
|
IPCInitialBufferFrames: 500, // 500 frames for initial buffer
|
||||||
|
|
||||||
|
// Event Constants
|
||||||
|
EventTimeoutSeconds: 2, // 2 seconds for event timeout
|
||||||
|
EventTimeFormatString: "2006-01-02T15:04:05.000Z", // "2006-01-02T15:04:05.000Z" time format
|
||||||
|
EventSubscriptionDelayMS: 100, // 100ms subscription delay
|
||||||
|
|
||||||
|
// Input Processing Constants
|
||||||
|
InputProcessingTimeoutMS: 10, // 10ms processing timeout threshold
|
||||||
|
|
||||||
|
// Adaptive Buffer Constants
|
||||||
|
AdaptiveBufferCPUMultiplier: 100, // 100 multiplier for CPU percentage
|
||||||
|
AdaptiveBufferMemoryMultiplier: 100, // 100 multiplier for memory percentage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -226,7 +226,7 @@ func convertAudioMetricsToEventDataWithLatencyMs(metrics AudioMetrics) AudioMetr
|
||||||
FramesReceived: metrics.FramesReceived,
|
FramesReceived: metrics.FramesReceived,
|
||||||
FramesDropped: metrics.FramesDropped,
|
FramesDropped: metrics.FramesDropped,
|
||||||
BytesProcessed: metrics.BytesProcessed,
|
BytesProcessed: metrics.BytesProcessed,
|
||||||
LastFrameTime: metrics.LastFrameTime.Format("2006-01-02T15:04:05.000Z"),
|
LastFrameTime: metrics.LastFrameTime.Format(GetConfig().EventTimeFormatString),
|
||||||
ConnectionDrops: metrics.ConnectionDrops,
|
ConnectionDrops: metrics.ConnectionDrops,
|
||||||
AverageLatency: fmt.Sprintf("%.1fms", float64(metrics.AverageLatency.Nanoseconds())/1e6),
|
AverageLatency: fmt.Sprintf("%.1fms", float64(metrics.AverageLatency.Nanoseconds())/1e6),
|
||||||
}
|
}
|
||||||
|
@ -238,7 +238,7 @@ func convertAudioInputMetricsToEventDataWithLatencyMs(metrics AudioInputMetrics)
|
||||||
FramesSent: metrics.FramesSent,
|
FramesSent: metrics.FramesSent,
|
||||||
FramesDropped: metrics.FramesDropped,
|
FramesDropped: metrics.FramesDropped,
|
||||||
BytesProcessed: metrics.BytesProcessed,
|
BytesProcessed: metrics.BytesProcessed,
|
||||||
LastFrameTime: metrics.LastFrameTime.Format("2006-01-02T15:04:05.000Z"),
|
LastFrameTime: metrics.LastFrameTime.Format(GetConfig().EventTimeFormatString),
|
||||||
ConnectionDrops: metrics.ConnectionDrops,
|
ConnectionDrops: metrics.ConnectionDrops,
|
||||||
AverageLatency: fmt.Sprintf("%.1fms", float64(metrics.AverageLatency.Nanoseconds())/1e6),
|
AverageLatency: fmt.Sprintf("%.1fms", float64(metrics.AverageLatency.Nanoseconds())/1e6),
|
||||||
}
|
}
|
||||||
|
@ -463,7 +463,7 @@ func (aeb *AudioEventBroadcaster) sendToSubscriber(subscriber *AudioEventSubscri
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(subscriber.ctx, 2*time.Second)
|
ctx, cancel := context.WithTimeout(subscriber.ctx, time.Duration(GetConfig().EventTimeoutSeconds)*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
err := wsjson.Write(ctx, subscriber.conn, event)
|
err := wsjson.Write(ctx, subscriber.conn, event)
|
||||||
|
|
|
@ -80,7 +80,7 @@ func (aim *AudioInputManager) WriteOpusFrame(frame []byte) error {
|
||||||
processingTime := time.Since(startTime)
|
processingTime := time.Since(startTime)
|
||||||
|
|
||||||
// Log high latency warnings
|
// Log high latency warnings
|
||||||
if processingTime > 10*time.Millisecond {
|
if processingTime > time.Duration(GetConfig().InputProcessingTimeoutMS)*time.Millisecond {
|
||||||
aim.logger.Warn().
|
aim.logger.Warn().
|
||||||
Dur("latency_ms", processingTime).
|
Dur("latency_ms", processingTime).
|
||||||
Msg("High audio processing latency detected")
|
Msg("High audio processing latency detected")
|
||||||
|
@ -116,7 +116,7 @@ func (aim *AudioInputManager) WriteOpusFrameZeroCopy(frame *ZeroCopyAudioFrame)
|
||||||
processingTime := time.Since(startTime)
|
processingTime := time.Since(startTime)
|
||||||
|
|
||||||
// Log high latency warnings
|
// Log high latency warnings
|
||||||
if processingTime > 10*time.Millisecond {
|
if processingTime > time.Duration(GetConfig().InputProcessingTimeoutMS)*time.Millisecond {
|
||||||
aim.logger.Warn().
|
aim.logger.Warn().
|
||||||
Dur("latency_ms", processingTime).
|
Dur("latency_ms", processingTime).
|
||||||
Msg("High audio processing latency detected")
|
Msg("High audio processing latency detected")
|
||||||
|
|
|
@ -122,7 +122,7 @@ func (s *OutputStreamer) streamLoop() {
|
||||||
defer runtime.UnlockOSThread()
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
// Adaptive timing for frame reading
|
// Adaptive timing for frame reading
|
||||||
frameInterval := time.Duration(20) * time.Millisecond // 50 FPS base rate
|
frameInterval := time.Duration(GetConfig().OutputStreamingFrameIntervalMS) * time.Millisecond // 50 FPS base rate
|
||||||
ticker := time.NewTicker(frameInterval)
|
ticker := time.NewTicker(frameInterval)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
|
|
@ -316,7 +316,7 @@ func (pm *ProcessMonitor) getClockTicks() float64 {
|
||||||
if len(fields) >= 2 {
|
if len(fields) >= 2 {
|
||||||
if period, err := strconv.ParseInt(fields[1], 10, 64); err == nil && period > 0 {
|
if period, err := strconv.ParseInt(fields[1], 10, 64); err == nil && period > 0 {
|
||||||
// Convert nanoseconds to Hz
|
// Convert nanoseconds to Hz
|
||||||
hz := 1000000000.0 / float64(period)
|
hz := GetConfig().CGONanosecondsPerSecond / float64(period)
|
||||||
if hz >= minValidClockTicks && hz <= maxValidClockTicks {
|
if hz >= minValidClockTicks && hz <= maxValidClockTicks {
|
||||||
pm.clockTicks = hz
|
pm.clockTicks = hz
|
||||||
return
|
return
|
||||||
|
@ -344,7 +344,7 @@ func (pm *ProcessMonitor) getTotalMemory() int64 {
|
||||||
pm.memoryOnce.Do(func() {
|
pm.memoryOnce.Do(func() {
|
||||||
file, err := os.Open("/proc/meminfo")
|
file, err := os.Open("/proc/meminfo")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pm.totalMemory = int64(defaultMemoryGB) * 1024 * 1024 * 1024
|
pm.totalMemory = int64(defaultMemoryGB) * int64(GetConfig().ProcessMonitorKBToBytes) * int64(GetConfig().ProcessMonitorKBToBytes) * int64(GetConfig().ProcessMonitorKBToBytes)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
@ -356,14 +356,14 @@ func (pm *ProcessMonitor) getTotalMemory() int64 {
|
||||||
fields := strings.Fields(line)
|
fields := strings.Fields(line)
|
||||||
if len(fields) >= 2 {
|
if len(fields) >= 2 {
|
||||||
if kb, err := strconv.ParseInt(fields[1], 10, 64); err == nil {
|
if kb, err := strconv.ParseInt(fields[1], 10, 64); err == nil {
|
||||||
pm.totalMemory = kb * 1024
|
pm.totalMemory = kb * int64(GetConfig().ProcessMonitorKBToBytes)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pm.totalMemory = int64(defaultMemoryGB) * 1024 * 1024 * 1024 // Fallback
|
pm.totalMemory = int64(defaultMemoryGB) * int64(GetConfig().ProcessMonitorKBToBytes) * int64(GetConfig().ProcessMonitorKBToBytes) * int64(GetConfig().ProcessMonitorKBToBytes) // Fallback
|
||||||
})
|
})
|
||||||
return pm.totalMemory
|
return pm.totalMemory
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,9 @@ 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)
|
||||||
allocationCount int64 // Total allocations counter (atomic)
|
allocationCount int64 // Total allocations counter (atomic)
|
||||||
|
|
||||||
// Other fields
|
// Other fields
|
||||||
|
@ -94,7 +94,7 @@ func (p *ZeroCopyFramePool) Get() *ZeroCopyAudioFrame {
|
||||||
frame.mutex.Unlock()
|
frame.mutex.Unlock()
|
||||||
return frame
|
return frame
|
||||||
}
|
}
|
||||||
|
|
||||||
// First try pre-allocated frames for fastest access
|
// First try pre-allocated frames for fastest access
|
||||||
p.mutex.Lock()
|
p.mutex.Lock()
|
||||||
if len(p.preallocated) > 0 {
|
if len(p.preallocated) > 0 {
|
||||||
|
|
Loading…
Reference in New Issue