---
name: Player Audio Fix (NuvioTV Pattern)
description: "Fix ExoPlayer audio for AC-3/E-AC-3/DTS/TrueHD on Android TV — speed-aware audio sink, amplification, playback speed."
version: 1.0.0
---

# Player Audio Fix — NuvioTV Pattern

## Problem
NexStream's ExoPlayer setup didn't handle AC-3/E-AC-3/DTS/TrueHD passthrough correctly when playback speed changes. These codecs require PCM fallback when speed != 1x.

## Root Cause
- No `PlaybackSpeedAwareAudioSink` — default audio sink doesn't handle speed changes for passthrough codecs
- No audio amplification support
- No playback speed control
- `setAudioSink()` requires Media3 1.6+, NexStream uses 1.5.1

## Fix Steps

### 1. Create PlaybackSpeedAwareAudioSink
File: `app/src/main/java/com/nexstream/app/player/PlaybackSpeedAwareAudioSink.kt`

Wraps a default audio sink and switches to PCM fallback when playback speed changes (for passthrough codecs).

### 2. Create GainAudioProcessor
File: `app/src/main/java/com/nexstream/app/player/GainAudioProcessor.kt`

Handles audio amplification (-20dB to +40dB).

### 3. Inject via CustomRenderersFactory
In `PlayerManager.createPlayer()`, override `DefaultRenderersFactory.buildAudioSink()`:

```kotlin
val customRenderersFactory = object : DefaultRenderersFactory(context) {
    override fun buildAudioSink(
        context: Context,
        enableAudioTrackPlaybackParams: Boolean,
        enableFloatOutput: Boolean
    ): AudioSink? {
        return PlaybackSpeedAwareAudioSink(
            DefaultAudioSink.Builder(context)
                .setEnableFloatOutput(enableFloatOutput)
                .setEnableAudioTrackPlaybackParams(enableAudioTrackPlaybackParams)
                .build()
        )
    }
}
```

**Key:** Use `DefaultRenderersFactory.buildAudioSink()` override — NOT `ExoPlayer.Builder.setAudioSink()` (requires Media3 1.6+).

### 4. Add to PlayerViewModel
- `audioAmplificationDb: Int` field in `PlayerUiState`
- `playbackSpeed: Float` field in `PlayerUiState`
- `setAudioAmplificationDb(db: Int)` and `adjustAudioAmplification(delta: Int)` methods
- `setPlaybackSpeed(speed: Float)` and `cyclePlaybackSpeed()` methods

### 5. Wire to MoreMenu UI
Add "Audio Amplification" and "Playback Speed" options to the MoreMenu composable.

## Pitfalls
- **Media3 version:** `setAudioSink()` on `ExoPlayer.Builder` requires Media3 1.6+. NexStream uses 1.5.1 — use `DefaultRenderersFactory.buildAudioSink()` override instead.
- **AudioSink return type:** `buildAudioSink()` returns `AudioSink?` (nullable), not `AudioSink`.
- **Signature:** `buildAudioSink(context, enableAudioTrackPlaybackParams, enableFloatOutput)` — all 3 params required.

## Files Modified
- `PlayerManager.kt` — custom renderers factory injection
- `PlayerViewModel.kt` — audio amplification + speed state/methods
- `PlayerControls.kt` — MoreMenu UI for audio/speed controls
- `PlayerScreen.kt` — pass viewModel to PlayerControls
- NEW: `PlaybackSpeedAwareAudioSink.kt`
- NEW: `GainAudioProcessor.kt`
