Skip to content

fix(playback): break output-route replan loops - #250

Open
blurbery wants to merge 1 commit into
Silo-Server:mainfrom
blurbery:contrib/playback-output-route-loop
Open

fix(playback): break output-route replan loops#250
blurbery wants to merge 1 commit into
Silo-Server:mainfrom
blurbery:contrib/playback-output-route-loop

Conversation

@blurbery

@blurbery blurbery commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

What I changed

I split Android audio output state into two concepts: full runtime state for diagnostics and a stable planning identity for deciding whether playback must be replanned. The planning identity contains the physical sink and HDR, passthrough, and channel capabilities that can change the server recipe. It excludes Spatializer state because the server does not route on that value and Media3 can change it as a consequence of remounting.

The output-route generation now advances only when that planning identity changes. I also retain attempted-plan history when an opaque context ID changes without a material route change, so a callback cannot reopen direct, remux, and transcode routes that already failed.

Why

I traced a live Android session that repeatedly cycled through direct play, remux, and transcode. The server transports were healthy. Media3 remounts triggered Spatializer callbacks, each callback was treated as a new physical output route, and the resulting replan cleared failed-route history. Loop detection therefore never got a stable history to act on.

This removes the false route change at its source. The companion server guard in Silo-Server/silo-server#789 protects already-installed builds that still send the legacy invalidation.

This change addresses route churn only. It does not claim to make an unsupported E-AC-3 Bluetooth path direct-play; the separate server fallback preserves the original video and converts only audio when Android genuinely reports a decoder failure.

Validation

  • Android Builds / Unit tests passed on the production-fork PR.
  • Android Builds / Lint passed on the production-fork PR.
  • Focused tests cover stable planning identity, real capability changes, and preserving fallback history.
  • Local Gradle execution was unavailable because the validation Mac had no Java runtime; GitHub Actions supplied the repository build environment.

Source implementation and production validation: blurbery/silo-android#4.

Related issue: N/A — narrow fix reproduced on a live deployment.

Scope and risk

A real sink, HDR, passthrough, or channel-capability change still advances route generation and replans normally. Only state that cannot affect the server playback recipe is filtered out. No API, schema, configuration, or Android TV product-surface changes are included.

AI Disclosure

  • Tool(s): OpenAI Codex desktop
  • Model(s): gpt-5.6-sol
  • Involvement: AI-assisted; I reproduced the live loop, designed the planning-identity boundary, reviewed the implementation, and validated the deployed server/client interaction
  • Adversarial review: Traced the callback-to-replan path and checked each excluded field against the server planner. Focused tests verify that Spatializer-only drift is ignored while real sink, HDR, passthrough, and channel changes still invalidate the route, and attempted fallback history survives an opaque-token-only change.

Summary by CodeRabbit

  • Bug Fixes

    • Improved audio route change detection by distinguishing meaningful physical or capability changes from spatializer and generation-only updates.
    • Prevented unnecessary playback replanning when output changes do not affect the active route.
    • Preserved fallback history for non-material route updates while restarting it for meaningful output changes.
  • Tests

    • Added coverage for route identity changes, spatializer updates, device capabilities, and fallback-history behavior.

@blurbery

Copy link
Copy Markdown
Contributor Author

Related server playback work: Silo-Server/silo-server#789 guards already-installed clients against false route invalidation, while Silo-Server/silo-server#790 preserves copied video for genuine Android E-AC-3 Bluetooth decoder failures.

@coderabbitai

coderabbitai Bot commented Aug 27, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b486775f-4fc7-4d52-bb7b-8373f4a08bc0

📥 Commits

Reviewing files that changed from the base of the PR and between a071dea and 29c5609.

📒 Files selected for processing (4)
  • android-shared/src/androidMain/kotlin/org/siloserver/silo/common/player/AudioCapabilityManager.kt
  • android-shared/src/androidMain/kotlin/org/siloserver/silo/common/player/PlaybackSessionManager.kt
  • android-shared/src/androidUnitTest/kotlin/org/siloserver/silo/common/player/AudioPlanningRouteIdentityTest.kt
  • android-shared/src/androidUnitTest/kotlin/org/siloserver/silo/common/player/PlaybackSessionManagerStagedReplanTest.kt

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The audio capability manager now tracks planning-relevant route identity separately from spatializer state. Playback replans preserve fallback history for generation-only output changes and reset it when planning-relevant output capabilities change.

Changes

Audio planning route handling

Layer / File(s) Summary
Route identity and capability publication
android-shared/src/androidMain/kotlin/org/siloserver/silo/common/player/AudioCapabilityManager.kt, android-shared/src/androidUnitTest/kotlin/org/siloserver/silo/common/player/AudioPlanningRouteIdentityTest.kt
Adds normalized route identity data. Spatializer state is excluded. Route generation and snapshots use the computed planning identity. Tests cover spatializer changes, device changes, capability changes, and sink-type changes.
Material route change replan handling
android-shared/src/androidMain/kotlin/org/siloserver/silo/common/player/PlaybackSessionManager.kt, android-shared/src/androidUnitTest/kotlin/org/siloserver/silo/common/player/PlaybackSessionManagerStagedReplanTest.kt
Adds planning-route comparison for output contexts. Replans preserve failed-plan history for non-material changes and clear it when the sink type changes. Tests cover both paths.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to 29c56

This PR limits playback replanning to material output capability changes and preserves fallback history across non-material callbacks; no actionable merge-blocking risk remains beyond normal checks and review.

Suggested reviewers: rxwatcher, quick104

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 10 functions across 4 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: preventing repeated playback replans caused by output-route churn.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant