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
|
// Validation Configuration
|
||||||
MaxValidationTime: 5 * time.Second, // 5s maximum validation timeout
|
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
|
FrameSizeTolerance: 512, // 512 bytes frame size tolerance
|
||||||
|
|
||||||
// Device Health Monitoring Configuration
|
// Device Health Monitoring Configuration
|
||||||
|
|
|
@ -83,8 +83,8 @@ func (aim *AudioInputManager) WriteOpusFrame(frame []byte) error {
|
||||||
return nil // Not running, silently drop
|
return nil // Not running, silently drop
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate frame before processing
|
// Use ultra-fast validation for critical audio path
|
||||||
if err := ValidateFrameData(frame); err != nil {
|
if err := ValidateAudioFrameUltraFast(frame); err != nil {
|
||||||
aim.logComponentError(AudioInputManagerComponent, err, "Frame validation failed")
|
aim.logComponentError(AudioInputManagerComponent, err, "Frame validation failed")
|
||||||
return fmt.Errorf("input frame validation failed: %w", err)
|
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
|
return nil // Empty frame, ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate frame data before processing
|
// Use ultra-fast validation for critical audio path
|
||||||
if err := ValidateFrameData(data); err != nil {
|
if err := ValidateAudioFrameUltraFast(data); err != nil {
|
||||||
logger := logging.GetDefaultLogger().With().Str("component", AudioInputServerComponent).Logger()
|
logger := logging.GetDefaultLogger().With().Str("component", AudioInputServerComponent).Logger()
|
||||||
logger.Error().Err(err).Msg("Frame validation failed")
|
logger.Error().Err(err).Msg("Frame validation failed")
|
||||||
return fmt.Errorf("input frame validation failed: %w", err)
|
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
|
// 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 := logging.GetDefaultLogger().With().Str("component", AudioInputClientComponent).Logger()
|
||||||
logger.Error().Err(err).Msg("Frame validation failed")
|
logger.Error().Err(err).Msg("Frame validation failed")
|
||||||
return fmt.Errorf("input frame validation failed: %w", err)
|
return fmt.Errorf("input frame validation failed: %w", err)
|
||||||
|
|
|
@ -103,7 +103,7 @@ func (aim *AudioInputIPCManager) WriteOpusFrame(frame []byte) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate frame data
|
// Validate frame data
|
||||||
if err := ValidateFrameData(frame); err != nil {
|
if err := ValidateAudioFrameUltraFast(frame); err != nil {
|
||||||
atomic.AddInt64(&aim.metrics.FramesDropped, 1)
|
atomic.AddInt64(&aim.metrics.FramesDropped, 1)
|
||||||
aim.logger.Debug().Err(err).Msg("invalid frame data")
|
aim.logger.Debug().Err(err).Msg("invalid frame data")
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -260,8 +260,8 @@ func (s *AudioOutputServer) Close() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AudioOutputServer) SendFrame(frame []byte) error {
|
func (s *AudioOutputServer) SendFrame(frame []byte) error {
|
||||||
// Comprehensive frame validation
|
// Use ultra-fast validation for critical audio path
|
||||||
if err := ValidateFrameData(frame); err != nil {
|
if err := ValidateAudioFrameUltraFast(frame); err != nil {
|
||||||
logger := logging.GetDefaultLogger().With().Str("component", AudioOutputServerComponent).Logger()
|
logger := logging.GetDefaultLogger().With().Str("component", AudioOutputServerComponent).Logger()
|
||||||
logger.Error().Err(err).Msg("Frame validation failed")
|
logger.Error().Err(err).Msg("Frame validation failed")
|
||||||
return fmt.Errorf("output frame validation failed: %w", err)
|
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
|
// forwardToWebRTC forwards a frame to the WebRTC audio track
|
||||||
func (r *AudioRelay) forwardToWebRTC(frame []byte) error {
|
func (r *AudioRelay) forwardToWebRTC(frame []byte) error {
|
||||||
// Validate frame data before processing
|
// Use ultra-fast validation for critical audio path
|
||||||
if err := ValidateFrameData(frame); err != nil {
|
if err := ValidateAudioFrameUltraFast(frame); err != nil {
|
||||||
r.incrementDropped()
|
r.incrementDropped()
|
||||||
r.logger.Debug().Err(err).Msg("invalid frame data in relay")
|
r.logger.Debug().Err(err).Msg("invalid frame data in relay")
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -35,34 +35,6 @@ func ValidateAudioQuality(quality AudioQuality) error {
|
||||||
return nil
|
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
|
// ValidateZeroCopyFrame validates zero-copy audio frame
|
||||||
func ValidateZeroCopyFrame(frame *ZeroCopyAudioFrame) error {
|
func ValidateZeroCopyFrame(frame *ZeroCopyAudioFrame) error {
|
||||||
if frame == nil {
|
if frame == nil {
|
||||||
|
@ -327,6 +299,8 @@ func ValidateAudioConfigConstants(config *AudioConfigConstants) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateAudioFrameFast performs fast validation of audio frame data
|
// 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 {
|
func ValidateAudioFrameFast(data []byte) error {
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return fmt.Errorf("%w: frame data is empty", ErrInvalidFrameData)
|
return fmt.Errorf("%w: frame data is empty", ErrInvalidFrameData)
|
||||||
|
@ -338,6 +312,17 @@ func ValidateAudioFrameFast(data []byte) error {
|
||||||
return nil
|
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
|
// WrapWithMetadata wraps error with metadata for enhanced validation context
|
||||||
func WrapWithMetadata(err error, component, operation string, metadata map[string]interface{}) error {
|
func WrapWithMetadata(err error, component, operation string, metadata map[string]interface{}) error {
|
||||||
if err == nil {
|
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) {
|
func testFrameDataValidation(t *testing.T) {
|
||||||
config := GetConfig()
|
config := GetConfig()
|
||||||
|
|
||||||
// Test nil data
|
|
||||||
err := ValidateFrameData(nil)
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.Contains(t, err.Error(), "frame data is nil")
|
|
||||||
|
|
||||||
// Test empty data
|
// Test empty data
|
||||||
err = ValidateFrameData([]byte{})
|
err := ValidateAudioFrameFast([]byte{})
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Contains(t, err.Error(), "frame data is empty")
|
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
|
// Test data above maximum size
|
||||||
largeData := make([]byte, config.MaxAudioFrameSize+1)
|
largeData := make([]byte, config.MaxAudioFrameSize+1)
|
||||||
err = ValidateFrameData(largeData)
|
err = ValidateAudioFrameFast(largeData)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Contains(t, err.Error(), "exceeds maximum")
|
assert.Contains(t, err.Error(), "exceeds maximum")
|
||||||
|
|
||||||
// Test unaligned data (odd number of bytes for 16-bit samples)
|
// Test valid data
|
||||||
oddData := make([]byte, 1001) // Odd number
|
validData := make([]byte, 1000) // Within bounds
|
||||||
if len(oddData) >= config.MinFrameSize {
|
if len(validData) <= config.MaxAudioFrameSize {
|
||||||
err = ValidateFrameData(oddData)
|
err = ValidateAudioFrameFast(validData)
|
||||||
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)
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue