Skip to content

[not-merge] fix(audio): apply normalization immediately from YouTube response, reset stale cross-track gain#3905

Open
kairosci wants to merge 3 commits into
MetrolistGroup:mainfrom
kairosci:fix-audio-normalization-timing
Open

[not-merge] fix(audio): apply normalization immediately from YouTube response, reset stale cross-track gain#3905
kairosci wants to merge 3 commits into
MetrolistGroup:mainfrom
kairosci:fix-audio-normalization-timing

Conversation

@kairosci

@kairosci kairosci commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Problem

After PR #3807, transitioning between tracks causes playback to start at full volume — normalization takes ~3 seconds to kick in, even with crossfade disabled.

Cause

Two root causes:

  1. Stale cross-track state retained: In setupAudioNormalization(), when the Room database has no loudness data yet for the new track (first playback), the format == null branch did nothing — keeping the previous track's gain values on the processor. This caused wrong boost/cut to be applied to the new track.

  2. Slow async pipeline: Loudness data fetched from the YouTube response goes through Room→Flow→Combine→coroutine before being applied, adding latency even when the data is already available at stream fetch time.

Solution

  • Reset to neutral on missing data: The format == null branch in setupAudioNormalization() now immediately resets the processor to neutral (enabled=false, gain=null) instead of keeping stale cross-track state. This prevents the previous track's gain from leaking into the new track.

  • Bypass the Room pipeline: New applyNormalizationFromLoudnessData() is called directly from the data source factory right after the YouTube response provides loudness data — applying gain to the VolumeNormalizationAudioProcessor synchronously, before a single audio sample reaches the processor. The Room→Flow→Combine reactive path becomes a secondary convergence mechanism.

Testing

  • assembleFossDebug builds successfully
  • Verified the direct application path is called immediately after format upsert in the data source resolver
  • The reactive combine path remains intact for preference changes and edge cases

Related Issues

Summary by CodeRabbit

  • Bug Fixes

    • Improved audio normalization reliability by safely handling times when loudness/format data isn’t ready, preventing incorrect or stale loudness adjustments.
    • Ensures normalization settings are applied consistently when switching tracks, with special handling to avoid interference during crossfades.
  • Performance & Stability

    • Improved thread-safety for normalization state to prevent race conditions during playback transitions.
    • Refined normalization caching and updates so gains are computed and applied more predictably during streaming.

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

MusicService.kt adds thread-safe normalization state, a loudness-based normalization helper, and revised handling for missing format data, media transitions, and stream-fetch loudness updates.

Changes

MusicService Normalization Changes

Layer / File(s) Summary
Thread-safe fields and import
app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt
Adds ConcurrentHashMap import, switches playerNormalizationProcessors to ConcurrentHashMap, and marks isCrossfading and cachedNormalizationGainMb as @Volatile.
applyNormalizationFromLoudnessData helper
app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt
Adds applyNormalizationFromLoudnessData(loudnessDb, perceptualLoudnessDb) to derive measured LUFS, clamp gain, update cached normalization state, and enable or disable processors.
Setup, fetch, and transition application
app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt
Updates the missing-format branch in setupAudioNormalization(), adds applyCachedAudioNormalizationNow() on media transitions, and conditionally reapplies loudness-derived normalization after stream fetch persistence when not crossfading.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • MetrolistGroup/Metrolist#3807: Modifies the same MusicService loudness and normalization pipeline around setupAudioNormalization() and applyCachedAudioNormalizationNow().
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description check ✅ Passed The description follows the template with Problem, Cause, Solution, Testing, and Related Issues sections filled out.
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.
Title check ✅ Passed The title accurately summarizes the main fix: immediate audio normalization from the YouTube response and resetting stale cross-track gain.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@kairosci

kairosci commented Jun 4, 2026

Copy link
Copy Markdown
Contributor Author

@yarikeua @Bec-de-Xorbin It seems to work, can you test and confirm that it works?

@yarikeua

yarikeua commented Jun 4, 2026

Copy link
Copy Markdown

@kairosci I tested your version and now everything works without delays.

!Update
when I tested with tracks from @Bec-de-Xorbin , the problem persisted

@Bec-de-Xorbin

Copy link
Copy Markdown

@yarikeua @Bec-de-Xorbin It seems to work, can you test and confirm that it works?

Thanks for the quick reaction! Unfortunately no, it still takes ~3 seconds for normalization to kick in.

@Bec-de-Xorbin

Copy link
Copy Markdown

@kairosci I tested your version and now everything works without delays.

Hmm. I'm using Metrolist PR 3905 and when this (https://music.youtube.com/watch?v=i97OkCXwotE) ends and this (https://music.youtube.com/watch?v=dKWfA9LCCOg) begins it takes ~3 seconds to lower volume.

@yarikeua

yarikeua commented Jun 4, 2026

Copy link
Copy Markdown

@kairosci There's a slight delay only when changing the normalization settings, specifically the loudness level. Is this how it should be?

@yarikeua

yarikeua commented Jun 4, 2026

Copy link
Copy Markdown

@kairosci I tested your version and now everything works without delays.

Hmm. I'm using Metrolist PR 3905 and when this (https://music.youtube.com/watch?v=i97OkCXwotE) ends and this (https://music.youtube.com/watch?v=dKWfA9LCCOg) begins it takes ~3 seconds to lower volume.

@Bec-de-Xorbin Yes, you are right, when I tested with these tracks, the problem persisted.

@kairosci kairosci force-pushed the fix-audio-normalization-timing branch from 17c1b46 to 36016fe Compare June 4, 2026 18:11
@kairosci

kairosci commented Jun 4, 2026

Copy link
Copy Markdown
Contributor Author

@yarikeua @Bec-de-Xorbin could you take another look? Thanks

@yarikeua

yarikeua commented Jun 4, 2026

Copy link
Copy Markdown

@kairosci
Screenshot_2026-06-04-21-47-53-32_d800bdcb138acf830d1e1a76bd31f651

@Bec-de-Xorbin

Copy link
Copy Markdown

@kairosci Screenshot_2026-06-04-21-47-53-32_d800bdcb138acf830d1e1a76bd31f651

Yes, this. Not working at all.

@kairosci

kairosci commented Jun 5, 2026

Copy link
Copy Markdown
Contributor Author

@yarikeua @Bec-de-Xorbin could you take another look? Thanks

@yarikeua

yarikeua commented Jun 5, 2026

Copy link
Copy Markdown

@kairosci

@yarikeua @Bec-de-Xorbin could you take another look? Thanks

Same. Not working at all.
Screenshot_2026-06-05-18-11-08-07_d800bdcb138acf830d1e1a76bd31f651

@kairosci

kairosci commented Jun 5, 2026

Copy link
Copy Markdown
Contributor Author

do you have log about this?

@yarikeua

yarikeua commented Jun 5, 2026

Copy link
Copy Markdown

do you have log about this?

@kairosci yes
05_06-18-44-39_288.log

@kairosci

kairosci commented Jun 5, 2026

Copy link
Copy Markdown
Contributor Author

thanks

@yarikeua

yarikeua commented Jun 5, 2026

Copy link
Copy Markdown

@kairosci It works now, but just as it did originally, with a delay of 3-5 seconds.

@kairosci

kairosci commented Jun 5, 2026

Copy link
Copy Markdown
Contributor Author

@yarikeua do you have log also about this?

@yarikeua

yarikeua commented Jun 5, 2026

Copy link
Copy Markdown

@yarikeua do you have log also about this?

@kairosci yes
05_06-23-56-16_058.log

@yarikeua

yarikeua commented Jun 5, 2026

Copy link
Copy Markdown

@kairosci Nothing has changed, only the progress bar is now staying at 0:00 while the track is playing.

@kairosci kairosci force-pushed the fix-audio-normalization-timing branch from 6495f2f to 0502262 Compare June 5, 2026 22:08
@yarikeua

yarikeua commented Jun 5, 2026

Copy link
Copy Markdown

@kairosci After a clean install, the progress bar started working again. The delay is still there.

Record_2026-06-06-01-11-40_d800bdcb138acf830d1e1a76bd31f651.mp4

@kairosci kairosci force-pushed the fix-audio-normalization-timing branch from 0502262 to 29d0896 Compare June 5, 2026 22:16
@kairosci

kairosci commented Jun 5, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai resume

@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Reviews resumed.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
app/src/main/kotlin/com/metrolist/music/playback/audio/VolumeNormalizationAudioProcessor.kt (1)

185-191: 💤 Low value

Remove unused read24Bit function.

This function is now dead code—the 24-bit sample reading logic was inlined directly in the ENCODING_PCM_24BIT branch at lines 104-107.

🧹 Proposed removal
-    private fun read24Bit(buffer: ByteBuffer): Int {
-        val b0 = buffer.get().toInt() and 0xFF
-        val b1 = buffer.get().toInt() and 0xFF
-        val b2 = buffer.get().toInt()
-        return (b2 shl 16) or (b1 shl 8) or b0
-    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@app/src/main/kotlin/com/metrolist/music/playback/audio/VolumeNormalizationAudioProcessor.kt`
around lines 185 - 191, Remove the now-unused helper function read24Bit from
VolumeNormalizationAudioProcessor: locate the private fun read24Bit(buffer:
ByteBuffer) and delete it, and ensure no other references to read24Bit remain
(the 24-bit logic has been inlined in the ENCODING_PCM_24BIT branch), leaving
the class without dead code.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@app/src/main/kotlin/com/metrolist/music/playback/audio/VolumeNormalizationAudioProcessor.kt`:
- Around line 185-191: Remove the now-unused helper function read24Bit from
VolumeNormalizationAudioProcessor: locate the private fun read24Bit(buffer:
ByteBuffer) and delete it, and ensure no other references to read24Bit remain
(the 24-bit logic has been inlined in the ENCODING_PCM_24BIT branch), leaving
the class without dead code.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: be58b35b-af80-4a81-86f3-c7671c34b7e1

📥 Commits

Reviewing files that changed from the base of the PR and between 36016fe and 29d0896.

📒 Files selected for processing (2)
  • app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt
  • app/src/main/kotlin/com/metrolist/music/playback/audio/VolumeNormalizationAudioProcessor.kt

@yarikeua

yarikeua commented Jun 5, 2026

Copy link
Copy Markdown

@kairosci same(

Record_2026-06-06-01-39-08_d800bdcb138acf830d1e1a76bd31f651.mp4

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt (1)

2226-2228: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reset normalization when the FormatEntity row is missing.

This branch still keeps the previous track's gain alive. onMediaItemTransition() calls setupAudioNormalization() before the new row exists, so the next track can start with stale normalization and, if playback is served from the URL/cache path, keep it until some later async update happens.

Suggested fix
                             isFormatNull -> {
-                                Timber.tag(TAG).d("Loudness row not ready yet; keeping cached normalization state")
+                                Timber.tag(TAG).d("Loudness row not ready yet; resetting normalization to neutral")
+                                cachedNormalizationGainMb = null
+                                cachedNormalizationEnabled = false
+                                playerNormalizationProcessors.values.forEach { it.enabled = false }
                             }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt` around
lines 2226 - 2228, The isFormatNull branch in MusicService.kt should clear/reset
the per-track normalization state instead of keeping the previous track's gain;
update the isFormatNull handling inside setupAudioNormalization() (used by
onMediaItemTransition()) to call the normalization reset path (e.g., invoke
whatever method or logic resets normalization state and related fields that
current/previous track normalization uses) so a missing FormatEntity row does
not leave stale gain applied; ensure you reference and reset the same
variables/flags used by the normal setup path so subsequent async updates can
populate fresh values.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt`:
- Around line 2152-2156: The early return guarded by isCrossfading skips
applying the freshly computed track gain to the incoming player's normalization
processor; instead, always cache the new clampedGain and ensure it is applied to
the processor instance for the player being prepared (or to the secondary
ExoPlayer's processor) even during a crossfade: modify the block around
startCrossfade()/isCrossfading so you do not return before calling
playerNormalizationProcessors.values.forEach (or target the specific processor
for the incoming player) to call setTargetGain(clampedGain) and enable the
processor, or alternatively construct the secondary ExoPlayer with normalization
forced neutral until the track-specific loudness arrives.
- Around line 2143-2158: When measuredLufs is null (i.e. no loudness data),
immediately neutralize normalization: set cachedNormalizationGainMb to 0 and
cachedNormalizationEnabled to false, and if not isCrossfading update every
playerNormalizationProcessors entry by calling setTargetGain(0) and setting
enabled = false; if isCrossfading, still update the cached values but return
early as current code does. Locate this logic in MusicService.kt around the
block using targetLufs, measuredLufs, cachedNormalizationGainMb,
cachedNormalizationEnabled, isCrossfading and playerNormalizationProcessors, and
add an else branch handling the null measuredLufs case with the steps above (use
MIN_GAIN_MB/MAX_GAIN_MB only for the normal path where measuredLufs exists).

---

Outside diff comments:
In `@app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt`:
- Around line 2226-2228: The isFormatNull branch in MusicService.kt should
clear/reset the per-track normalization state instead of keeping the previous
track's gain; update the isFormatNull handling inside setupAudioNormalization()
(used by onMediaItemTransition()) to call the normalization reset path (e.g.,
invoke whatever method or logic resets normalization state and related fields
that current/previous track normalization uses) so a missing FormatEntity row
does not leave stale gain applied; ensure you reference and reset the same
variables/flags used by the normal setup path so subsequent async updates can
populate fresh values.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 637f4ca8-4337-4195-a206-ceeeca4b30cf

📥 Commits

Reviewing files that changed from the base of the PR and between 29d0896 and c918658.

📒 Files selected for processing (1)
  • app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt

Comment thread app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt Outdated
Comment thread app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt Outdated
@kairosci kairosci marked this pull request as draft June 6, 2026 13:34
@kairosci

kairosci commented Jun 6, 2026

Copy link
Copy Markdown
Contributor Author

@yarikeua could you take another look? Thanks again

@yarikeua

yarikeua commented Jun 7, 2026

Copy link
Copy Markdown

@yarikeua could you take another look? Thanks again

@kairosci Thank you too. I hope you can fix this.

Record_2026-06-07-09-35-42_d800bdcb138acf830d1e1a76bd31f651.mp4

@kairosci

Copy link
Copy Markdown
Contributor Author

@yarikeua could you take another look? If it's still not working, could you send me the logs? Thanks again!

@yarikeua

Copy link
Copy Markdown

@yarikeua could you take another look? If it's still not working, could you send me the logs? Thanks again!

@kairosci still the same(
15_06-15-20-55_273.log

@kairosci kairosci force-pushed the fix-audio-normalization-timing branch from e7fbada to 3ee06a1 Compare June 15, 2026 21:08
@yarikeua

Copy link
Copy Markdown

@kairosci Good evening, what's the latest? I'm really annoyed by this delay, where the song just screams for the first few seconds before it gets back to normal.

@kairosci kairosci marked this pull request as ready for review June 18, 2026 11:16
@kairosci

Copy link
Copy Markdown
Contributor Author

@yarikeua hi, I think I've fixed it; I'm testing it now, and I can't reproduce the problem.

@kairosci

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt (1)

2273-2304: 💤 Low value

Unused mediaId parameter.

The mediaId parameter is declared but never referenced in the function body. If it's intended for future logging or debugging, consider adding a comment; otherwise, remove it to reduce confusion.

Proposed fix
 private fun applyNormalizationFromLoudnessData(
-    mediaId: String,
     loudnessDb: Double?,
     perceptualLoudnessDb: Double?,
 )

And update the call site accordingly:

-applyNormalizationFromLoudnessData(mediaId, loudnessDb, perceptualLoudnessDb)
+applyNormalizationFromLoudnessData(loudnessDb, perceptualLoudnessDb)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt` around
lines 2273 - 2304, The mediaId parameter in the
applyNormalizationFromLoudnessData function is declared but never used in the
function body. Remove the mediaId parameter from the function signature of
applyNormalizationFromLoudnessData, and then locate and update all call sites
where this function is invoked to remove the mediaId argument being passed to
it.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt`:
- Around line 2273-2304: The mediaId parameter in the
applyNormalizationFromLoudnessData function is declared but never used in the
function body. Remove the mediaId parameter from the function signature of
applyNormalizationFromLoudnessData, and then locate and update all call sites
where this function is invoked to remove the mediaId argument being passed to
it.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f1413f06-daca-4b76-bdc3-f11df74c9456

📥 Commits

Reviewing files that changed from the base of the PR and between da648fa and 3ee06a1.

📒 Files selected for processing (1)
  • app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt

@kairosci

Copy link
Copy Markdown
Contributor Author

@yarikeua click here to download; let me now if it works

@yarikeua

Copy link
Copy Markdown

@yarikeua click here to download; let me now if it works

@kairosci Still the same for me(

Record_2026-06-19-14-18-38_d800bdcb138acf830d1e1a76bd31f651.mp4

@kairosci

kairosci commented Jun 19, 2026

Copy link
Copy Markdown
Contributor Author

I don't understand why I can't reproduce the problem on the songs I listen to.

Do you have the logs?

@yarikeua

yarikeua commented Jun 19, 2026

Copy link
Copy Markdown

I don't understand why I can't reproduce the problem on the songs I listen to.

Do you have the logs?

@kairosci this is the full log
19_06-23-46-37_042.log

@kairosci kairosci marked this pull request as draft June 21, 2026 16:27
@Bec-de-Xorbin

Bec-de-Xorbin commented Jun 23, 2026

Copy link
Copy Markdown

I don't understand why I can't reproduce the problem on the songs I listen to.

Do you have the logs?

Why can't you listen to the two songs I gave as an example? It's clearly noticeable because the first song is quieter and the second is louder. Should I open an issue so somebody else could take a look?

@kairosci kairosci force-pushed the fix-audio-normalization-timing branch from 3ee06a1 to ca96133 Compare June 24, 2026 09:59
@kairosci kairosci marked this pull request as ready for review June 25, 2026 20:27

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt`:
- Around line 4088-4091: Resolve the empty catch blocks by handling the
exceptions explicitly instead of swallowing them in MusicService’s receiver
teardown paths, including the unregisterReceiver(screenStateReceiver) block and
the other similar catch near the widget/receiver cleanup section. Rename
intentionally ignored exceptions to the configured ignored name if they are
truly safe to ignore, or log/report the failure with enough context so detekt no
longer flags EmptyCatchBlock/SwallowedException and teardown problems are
visible.
- Around line 427-430: The cached normalization state is currently global, so a
previous track or resolver update can be applied to the next media item before
setupAudioNormalization() validates the new mediaId. Update the cached state in
MusicService to include the owning mediaId alongside cachedNormalizationGainMb
and cachedNormalizationEnabled, and make applyCachedAudioNormalizationNow() only
apply or restore normalization when that cached mediaId matches
player.currentMediaItem?.mediaId; otherwise neutralize the cache before any
transition path reuses it.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c5ade87c-3bdc-4618-9e79-5ca5e7d51b24

📥 Commits

Reviewing files that changed from the base of the PR and between 3ee06a1 and ca96133.

📒 Files selected for processing (1)
  • app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt`:
- Around line 4088-4091: Resolve the empty catch blocks by handling the
exceptions explicitly instead of swallowing them in MusicService’s receiver
teardown paths, including the unregisterReceiver(screenStateReceiver) block and
the other similar catch near the widget/receiver cleanup section. Rename
intentionally ignored exceptions to the configured ignored name if they are
truly safe to ignore, or log/report the failure with enough context so detekt no
longer flags EmptyCatchBlock/SwallowedException and teardown problems are
visible.
- Around line 427-430: The cached normalization state is currently global, so a
previous track or resolver update can be applied to the next media item before
setupAudioNormalization() validates the new mediaId. Update the cached state in
MusicService to include the owning mediaId alongside cachedNormalizationGainMb
and cachedNormalizationEnabled, and make applyCachedAudioNormalizationNow() only
apply or restore normalization when that cached mediaId matches
player.currentMediaItem?.mediaId; otherwise neutralize the cache before any
transition path reuses it.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c5ade87c-3bdc-4618-9e79-5ca5e7d51b24

📥 Commits

Reviewing files that changed from the base of the PR and between 3ee06a1 and ca96133.

📒 Files selected for processing (1)
  • app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt
🛑 Comments failed to post (2)
app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt (2)

427-430: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Make cached normalization state media-scoped before applying it on transitions.

Line 2556 reapplies the last cached gain before setupAudioNormalization() verifies the new mediaId, but Lines 427-430 only cache gain/enabled globally. If the cache still belongs to the previous track—or a resolver fetch for another item updates it at Lines 3796-3798—the first buffers of the new track can receive the wrong normalization. Store the owning mediaId with the cached state and have applyCachedAudioNormalizationNow() neutralize unless it matches player.currentMediaItem?.mediaId. This is central to the PR’s stale cross-track gain objective.

Also applies to: 2278-2289, 2556-2557, 3796-3798

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt` around
lines 427 - 430, The cached normalization state is currently global, so a
previous track or resolver update can be applied to the next media item before
setupAudioNormalization() validates the new mediaId. Update the cached state in
MusicService to include the owning mediaId alongside cachedNormalizationGainMb
and cachedNormalizationEnabled, and make applyCachedAudioNormalizationNow() only
apply or restore normalization when that cached mediaId matches
player.currentMediaItem?.mediaId; otherwise neutralize the cache before any
transition path reuses it.

4088-4091: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Resolve the detekt empty-catch warnings.

These catches currently swallow exceptions with no signal. Rename intentionally ignored exceptions to the configured ignored name, or log/report recoverable failures so widget/receiver teardown issues are not invisible. Based on static analysis hints, detekt flags these as EmptyCatchBlock/SwallowedException.

Proposed fix
-        } catch (e: Exception) {
+        } catch (_: Exception) {
         }
-            } catch (e: Exception) {
+            } catch (e: Exception) {
+                Timber.tag(TAG).w(e, "Failed to update widgets")
             } finally {

Also applies to: 4494-4495

🧰 Tools
🪛 detekt (1.23.8)

[warning] 4090-4091: Empty catch block detected. If the exception can be safely ignored, name the exception according to one of the exemptions as per the configuration of this rule.

(detekt.empty-blocks.EmptyCatchBlock)


[warning] 4090-4090: The caught exception is swallowed. The original exception could be lost.

(detekt.exceptions.SwallowedException)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt` around
lines 4088 - 4091, Resolve the empty catch blocks by handling the exceptions
explicitly instead of swallowing them in MusicService’s receiver teardown paths,
including the unregisterReceiver(screenStateReceiver) block and the other
similar catch near the widget/receiver cleanup section. Rename intentionally
ignored exceptions to the configured ignored name if they are truly safe to
ignore, or log/report the failure with enough context so detekt no longer flags
EmptyCatchBlock/SwallowedException and teardown problems are visible.

Source: Linters/SAST tools

@kairosci kairosci force-pushed the fix-audio-normalization-timing branch from ca96133 to e2f0913 Compare June 25, 2026 20:48
@kairosci kairosci changed the title fix(audio): apply normalization immediately from YouTube response, reset stale cross-track gain [not-merge] fix(audio): apply normalization immediately from YouTube response, reset stale cross-track gain Jun 25, 2026
…c setupAudioNormalization

- Remove setupAudioNormalization() entirely (async DB-query path)
- Remove loudnessSetupJob/loudnessSetupGeneration fields
- applyNormalizationFromLoudnessData() is now the single entry point
- Data source factory: applies gain immediately from YouTube response (time 0)
- Preference collector: recomputes gain directly from reactive format flow
- Track change: invalidates cache, data source factory sets correct gain before audio starts
@kairosci

Copy link
Copy Markdown
Contributor Author

@Bec-de-Xorbin I’m trying this with your song right now; it seems to be working. Could you have a look at it too? Thanks

@Bec-de-Xorbin

Copy link
Copy Markdown

@Bec-de-Xorbin I’m trying this with your song right now; it seems to be working. Could you have a look at it too? Thanks

Not working.

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.

3 participants