Files
-rpi-sendspin/third_party/sendspin-go/docs/CODE_REVIEW_FIXES.md

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 uses audio.Max24Bit and audio.Min24Bit
  • internal/server/test_tone_source.go - Test tone generation uses max24bit constant

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.