Fix background noise not playing after a page refresh#2928
Merged
Conversation
The noise path never resumed a suspended AudioContext, unlike the word path. After a hard refresh the singleton context is fresh and suspended under the browser autoplay policy, so noise.source.start(0) queues silently and the background noise never plays. A lesson restart reused a context that word playback had already resumed, which is why restarting "fixed" it. Resume the context before starting the noise source in startNoiseTask, mirroring the existing handling in setAudioElements and playTask. Adds startNoiseTask coverage: the no-level early return, and that the noise source is created and started when a noise level is present. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replaces the events-array + indexOf ordering check with QUnit's assert.step / assert.verifySteps, which reads the intended sequence declaratively and fails clearly on an out-of-order call. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The context.resume() before source.start(0) introduces an await, so a cancellation (stopNoise) or a resume rejection between creating and starting the source would make the finally call stop() on a node that never started, throwing InvalidStateError and masking the real reason. Track a started flag and only stop when the source actually started. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The service's willDestroy() closes the context on teardown; the running context stub lacked close(), so the test rejected with 'this.context.close is not a function'. Mirrors the stub used in the playback-rate tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Frontend test coverage: 72.7% (+0.11% compared to 72.59% on base) |
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Problem
After refreshing the exercise page, the background noise (шум, played behind the words to simulate a noisy listening environment) doesn't play. Restarting the lesson fixes it.
Root cause
The
AudioServiceis a singleton whoseAudioContextlives for the page's lifetime. Browsers create anAudioContextin thesuspendedstate under the autoplay policy — it only produces sound after an explicitresume().The word-playback path resumes it (
setAudioElementsandplayTaskboth callcontext.resume()on a suspended context). The noise path never does —startNoiseTaskcallsnoise.source.start(0)with no resume. On a hard refresh the context is fresh/suspended when the noise source starts, so it's scheduled but silent. A restart reuses a context that word playback already resumed, which is exactly why restarting "fixes" it.(The
if (!level) returnguard oncurrentExerciseNoiseLevelwas considered and ruled out — it would suppress noise in both flows, so it can't explain the refresh-vs-restart difference.)Fix
Resume the context before starting the noise source in
startNoiseTask, mirroring the existing suspended-state handling insetAudioElements/playTask(same!isTesting()guard).Tests
Adds
startNoiseTaskcoverage: the no-noise-level early return, and that the noise source is created and started when a noise level is present.Verification
lint:types(glint/tsc) andeslintpass clean. The QUnit suite was not run —ember testis broken pre-existing in this repo (aborts on a global./packagemodule error before any test runs).Worth a quick manual check: hard-refresh directly on an exercise with noise, start it, and confirm the background noise plays on the first pass (not only after a restart).
🤖 Generated with Claude Code