add validated audio interleaving
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
package output
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"mxl-player/internal/playback"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidAudioFrame = errors.New("invalid audio frame")
|
||||
ErrAudioPayloadTooSmall = errors.New("audio channel payload is too small")
|
||||
)
|
||||
|
||||
func InterleaveF32(frame playback.AudioFrame) ([]byte, error) {
|
||||
if frame.Channels == 0 ||
|
||||
frame.SampleCount == 0 ||
|
||||
frame.SampleRateNumerator <= 0 ||
|
||||
frame.SampleRateDenominator <= 0 {
|
||||
return nil, ErrInvalidAudioFrame
|
||||
}
|
||||
|
||||
if uint64(len(frame.Samples)) != frame.Channels {
|
||||
return nil, ErrInvalidAudioFrame
|
||||
}
|
||||
|
||||
if frame.SampleCount > ^uint64(0)/4 {
|
||||
return nil, ErrInvalidAudioFrame
|
||||
}
|
||||
bytesPerChannel := frame.SampleCount * 4
|
||||
|
||||
if frame.Channels > ^uint64(0)/bytesPerChannel {
|
||||
return nil, ErrInvalidAudioFrame
|
||||
}
|
||||
totalBytes := frame.Channels * bytesPerChannel
|
||||
|
||||
maxInt := uint64(^uint(0) >> 1)
|
||||
if totalBytes > maxInt {
|
||||
return nil, ErrInvalidAudioFrame
|
||||
}
|
||||
|
||||
for _, samples := range frame.Samples {
|
||||
if bytesPerChannel > uint64(len(samples)) {
|
||||
return nil, ErrAudioPayloadTooSmall
|
||||
}
|
||||
}
|
||||
|
||||
result := make([]byte, int(totalBytes))
|
||||
|
||||
for sample := uint64(0); sample < frame.SampleCount; sample++ {
|
||||
for channel := uint64(0); channel < frame.Channels; channel++ {
|
||||
sourceOffset := sample * 4
|
||||
destinationOffset := (sample*frame.Channels + channel) * 4
|
||||
|
||||
sourceStart := int(sourceOffset)
|
||||
destinationStart := int(destinationOffset)
|
||||
|
||||
copy(
|
||||
result[destinationStart:destinationStart+4],
|
||||
frame.Samples[channel][sourceStart:sourceStart+4],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
Reference in New Issue
Block a user