4.4 KiB
Code Review Fixes - 24-bit Audio Implementation
Date: 2025-10-25
After implementing the 24-bit audio pipeline, I performed a careful code review with "fresh eyes" and found several issues that have been fixed.
Issues Found and Fixed
1. ✅ CRITICAL: Integer Overflow in Volume Control
File: internal/player/output.go
Location: applyVolume() function
Problem:
result[i] = int32(float64(sample) * multiplier)
When applying volume to samples, there was no clipping protection. Samples at max 24-bit range (±8,388,607) multiplied by volume could overflow int32.
Fix:
scaled := int64(float64(sample) * multiplier)
// Clamp to 24-bit range to prevent overflow
if scaled > audio.Max24Bit {
scaled = audio.Max24Bit
} else if scaled < audio.Min24Bit {
scaled = audio.Min24Bit
}
result[i] = int32(scaled)
Impact: Prevents audio distortion and crashes from integer overflow when volume is applied.
2. ✅ Improved Code Clarity: Better Comments
File: internal/server/audio_source.go
Locations: MP3Source, HTTPMP3Source, FFmpegSource Read methods
Problem: Comments were confusing, referring to "int16 = 2 bytes" next to code dealing with int32 arrays.
Before:
numBytes := len(samples) * 2 // int16 = 2 bytes
After:
// Read bytes from decoder (MP3 decoder outputs int16 = 2 bytes per sample)
numBytes := len(samples) * 2
Also added detailed comments for the conversion:
// Left-shift by 8 to convert 16-bit range to 24-bit range
// Example: 32767 (max 16-bit) << 8 = 8388352 (near max 24-bit 8388607)
samples[i] = int32(sample16) << 8
Impact: Makes code intention clearer for future maintainers.
3. ✅ Code Organization: Added 24-bit Constants
File: internal/audio/types.go
Problem: 24-bit range limits were hardcoded as magic numbers throughout the codebase.
Fix:
const (
// 24-bit audio range constants
Max24Bit = 8388607 // 2^23 - 1
Min24Bit = -8388608 // -2^23
)
Updated usages:
internal/player/output.go- Volume clipping now usesaudio.Max24Bitandaudio.Min24Bitinternal/server/test_tone_source.go- Test tone generation usesmax24bitconstant
Impact: Single source of truth for 24-bit range, easier to maintain.
4. ✅ Improved Test Tone Comments
File: internal/server/test_tone_source.go
Before:
pcmValue := int32(sample * 8388607.0 * 0.5) // 50% volume
After:
// Convert to 24-bit PCM (using int32)
// Scale to 24-bit range and apply 50% volume to avoid clipping
const max24bit = 8388607 // 2^23 - 1
pcmValue := int32(sample * max24bit * 0.5)
Impact: Clarifies why 50% volume is used (to prevent clipping on sine wave peaks).
Issues Considered But Not Changed
1. ResampledSource Error Handling
File: internal/server/audio_source.go:511
Code:
outputSamples := r.resampler.Resample(r.inputBuffer[:n], samples)
return outputSamples, nil
Analysis: The resampler returns the number of samples actually written. While we don't explicitly check if it filled the requested amount, this is actually correct behavior - the caller receives the actual count and can handle partial fills. No change needed.
2. FLAC Bit Depth Conversion
File: internal/server/audio_source.go:266-280
Code:
if s.bitDepth == 16 {
samples[samplesRead] = sample << 8
} else if s.bitDepth == 24 {
samples[samplesRead] = sample
} else {
// For other bit depths, scale to 24-bit range
shift := s.bitDepth - 24
if shift > 0 {
samples[samplesRead] = sample >> shift
} else {
samples[samplesRead] = sample << -shift
}
}
Analysis: The FLAC library returns samples as int32 in the native bit depth range. For 16-bit FLAC, the value is already correctly ranged ±32,768, so left-shifting by 8 is correct. For 24-bit, the value is already in the right range. The generic case handles other bit depths (8-bit, 20-bit, etc.). This logic is sound.
Testing
After fixes:
- ✅ Server compiles successfully
- ✅ Player compiles successfully
- ✅ No new warnings or errors
Summary
Total Issues Fixed: 4
- 1 Critical (integer overflow protection)
- 3 Code quality improvements (comments, constants)
Lines Changed: ~30 lines across 4 files
All fixes maintain backward compatibility and improve code robustness without changing the core 24-bit pipeline functionality.