mirror of https://github.com/jetkvm/kvm.git
perf(audio): replace frame validation with ultra-fast version
Use ValidateAudioFrameUltraFast in critical audio paths to reduce processing overhead Reduce minimum frame size to 1 byte to allow smaller frames
This commit is contained in:
parent
e3e7b898b5
commit
25363cef90
|
@ -2388,7 +2388,7 @@ func DefaultAudioConfig() *AudioConfigConstants {
|
|||
|
||||
// Validation Configuration
|
||||
MaxValidationTime: 5 * time.Second, // 5s maximum validation timeout
|
||||
MinFrameSize: 64, // 64 bytes minimum frame size
|
||||
MinFrameSize: 1, // 1 byte minimum frame size (allow small frames)
|
||||
FrameSizeTolerance: 512, // 512 bytes frame size tolerance
|
||||
|
||||
// Device Health Monitoring Configuration
|
||||
|
|
|
@ -83,8 +83,8 @@ func (aim *AudioInputManager) WriteOpusFrame(frame []byte) error {
|
|||
return nil // Not running, silently drop
|
||||
}
|
||||
|
||||
// Validate frame before processing
|
||||
if err := ValidateFrameData(frame); err != nil {
|
||||
// Use ultra-fast validation for critical audio path
|
||||
if err := ValidateAudioFrameUltraFast(frame); err != nil {
|
||||
aim.logComponentError(AudioInputManagerComponent, err, "Frame validation failed")
|
||||
return fmt.Errorf("input frame validation failed: %w", err)
|
||||
}
|
||||
|
|
|
@ -477,8 +477,8 @@ func (ais *AudioInputServer) processOpusFrame(data []byte) error {
|
|||
return nil // Empty frame, ignore
|
||||
}
|
||||
|
||||
// Validate frame data before processing
|
||||
if err := ValidateFrameData(data); err != nil {
|
||||
// Use ultra-fast validation for critical audio path
|
||||
if err := ValidateAudioFrameUltraFast(data); err != nil {
|
||||
logger := logging.GetDefaultLogger().With().Str("component", AudioInputServerComponent).Logger()
|
||||
logger.Error().Err(err).Msg("Frame validation failed")
|
||||
return fmt.Errorf("input frame validation failed: %w", err)
|
||||
|
@ -635,7 +635,7 @@ func (aic *AudioInputClient) SendFrame(frame []byte) error {
|
|||
}
|
||||
|
||||
// Validate frame data before sending
|
||||
if err := ValidateFrameData(frame); err != nil {
|
||||
if err := ValidateAudioFrameUltraFast(frame); err != nil {
|
||||
logger := logging.GetDefaultLogger().With().Str("component", AudioInputClientComponent).Logger()
|
||||
logger.Error().Err(err).Msg("Frame validation failed")
|
||||
return fmt.Errorf("input frame validation failed: %w", err)
|
||||
|
|
|
@ -103,7 +103,7 @@ func (aim *AudioInputIPCManager) WriteOpusFrame(frame []byte) error {
|
|||
}
|
||||
|
||||
// Validate frame data
|
||||
if err := ValidateFrameData(frame); err != nil {
|
||||
if err := ValidateAudioFrameUltraFast(frame); err != nil {
|
||||
atomic.AddInt64(&aim.metrics.FramesDropped, 1)
|
||||
aim.logger.Debug().Err(err).Msg("invalid frame data")
|
||||
return err
|
||||
|
|
|
@ -260,8 +260,8 @@ func (s *AudioOutputServer) Close() error {
|
|||
}
|
||||
|
||||
func (s *AudioOutputServer) SendFrame(frame []byte) error {
|
||||
// Comprehensive frame validation
|
||||
if err := ValidateFrameData(frame); err != nil {
|
||||
// Use ultra-fast validation for critical audio path
|
||||
if err := ValidateAudioFrameUltraFast(frame); err != nil {
|
||||
logger := logging.GetDefaultLogger().With().Str("component", AudioOutputServerComponent).Logger()
|
||||
logger.Error().Err(err).Msg("Frame validation failed")
|
||||
return fmt.Errorf("output frame validation failed: %w", err)
|
||||
|
|
|
@ -170,8 +170,8 @@ func (r *AudioRelay) relayLoop() {
|
|||
|
||||
// forwardToWebRTC forwards a frame to the WebRTC audio track
|
||||
func (r *AudioRelay) forwardToWebRTC(frame []byte) error {
|
||||
// Validate frame data before processing
|
||||
if err := ValidateFrameData(frame); err != nil {
|
||||
// Use ultra-fast validation for critical audio path
|
||||
if err := ValidateAudioFrameUltraFast(frame); err != nil {
|
||||
r.incrementDropped()
|
||||
r.logger.Debug().Err(err).Msg("invalid frame data in relay")
|
||||
return err
|
||||
|
|
|
@ -35,34 +35,6 @@ func ValidateAudioQuality(quality AudioQuality) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ValidateFrameData validates audio frame data with comprehensive boundary checks
|
||||
func ValidateFrameData(data []byte) error {
|
||||
if data == nil {
|
||||
return fmt.Errorf("%w: frame data is nil", ErrInvalidFrameData)
|
||||
}
|
||||
if len(data) == 0 {
|
||||
return fmt.Errorf("%w: frame data is empty", ErrInvalidFrameData)
|
||||
}
|
||||
|
||||
config := GetConfig()
|
||||
// Check minimum frame size
|
||||
if len(data) < config.MinFrameSize {
|
||||
return fmt.Errorf("%w: frame size %d below minimum %d",
|
||||
ErrInvalidFrameSize, len(data), config.MinFrameSize)
|
||||
}
|
||||
// Check maximum frame size
|
||||
if len(data) > config.MaxAudioFrameSize {
|
||||
return fmt.Errorf("%w: frame size %d exceeds maximum %d",
|
||||
ErrInvalidFrameSize, len(data), config.MaxAudioFrameSize)
|
||||
}
|
||||
// Validate frame alignment for audio samples (must be even for 16-bit samples)
|
||||
if len(data)%2 != 0 {
|
||||
return fmt.Errorf("%w: frame size %d not aligned for 16-bit samples",
|
||||
ErrInvalidFrameSize, len(data))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateZeroCopyFrame validates zero-copy audio frame
|
||||
func ValidateZeroCopyFrame(frame *ZeroCopyAudioFrame) error {
|
||||
if frame == nil {
|
||||
|
@ -327,6 +299,8 @@ func ValidateAudioConfigConstants(config *AudioConfigConstants) error {
|
|||
}
|
||||
|
||||
// ValidateAudioFrameFast performs fast validation of audio frame data
|
||||
// ValidateAudioFrameFast provides minimal validation for critical audio processing paths
|
||||
// This function is optimized for performance and only checks essential safety bounds
|
||||
func ValidateAudioFrameFast(data []byte) error {
|
||||
if len(data) == 0 {
|
||||
return fmt.Errorf("%w: frame data is empty", ErrInvalidFrameData)
|
||||
|
@ -338,6 +312,17 @@ func ValidateAudioFrameFast(data []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ValidateAudioFrameUltraFast provides zero-overhead validation for ultra-critical paths
|
||||
// This function only checks for nil/empty data and maximum size to prevent buffer overruns
|
||||
// Use this in hot audio processing loops where every microsecond matters
|
||||
func ValidateAudioFrameUltraFast(data []byte) error {
|
||||
// Only check for catastrophic failures that could crash the system
|
||||
if len(data) == 0 || len(data) > 8192 { // Hard-coded 8KB safety limit
|
||||
return ErrInvalidFrameData
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WrapWithMetadata wraps error with metadata for enhanced validation context
|
||||
func WrapWithMetadata(err error, component, operation string, metadata map[string]interface{}) error {
|
||||
if err == nil {
|
||||
|
|
|
@ -62,46 +62,25 @@ func testAudioQualityValidation(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// testFrameDataValidation tests frame data validation with various edge cases
|
||||
// testFrameDataValidation tests frame data validation with various edge cases using modern validation
|
||||
func testFrameDataValidation(t *testing.T) {
|
||||
config := GetConfig()
|
||||
|
||||
// Test nil data
|
||||
err := ValidateFrameData(nil)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "frame data is nil")
|
||||
|
||||
// Test empty data
|
||||
err = ValidateFrameData([]byte{})
|
||||
err := ValidateAudioFrameFast([]byte{})
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "frame data is empty")
|
||||
|
||||
// Test data below minimum size
|
||||
if config.MinFrameSize > 0 {
|
||||
smallData := make([]byte, config.MinFrameSize-1)
|
||||
err = ValidateFrameData(smallData)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "below minimum")
|
||||
}
|
||||
|
||||
// Test data above maximum size
|
||||
largeData := make([]byte, config.MaxAudioFrameSize+1)
|
||||
err = ValidateFrameData(largeData)
|
||||
err = ValidateAudioFrameFast(largeData)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "exceeds maximum")
|
||||
|
||||
// Test unaligned data (odd number of bytes for 16-bit samples)
|
||||
oddData := make([]byte, 1001) // Odd number
|
||||
if len(oddData) >= config.MinFrameSize {
|
||||
err = ValidateFrameData(oddData)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "not aligned")
|
||||
}
|
||||
|
||||
// Test valid aligned data
|
||||
validData := make([]byte, 1000) // Even number, within bounds
|
||||
if len(validData) >= config.MinFrameSize && len(validData) <= config.MaxAudioFrameSize {
|
||||
err = ValidateFrameData(validData)
|
||||
// Test valid data
|
||||
validData := make([]byte, 1000) // Within bounds
|
||||
if len(validData) <= config.MaxAudioFrameSize {
|
||||
err = ValidateAudioFrameFast(validData)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue