Release the notification sound's audio stream when idle#271
Conversation
The notification and un-mute sounds are played by SoundEffect objects that live for the whole launcher session. A SoundEffect opens a PulseAudio playback stream when it is created and holds it for its entire lifetime, so these streams never close, the audio sink never suspends, module-suspend-on-idle never fires, and the audio power rail stays awake - a constant standby battery drain. Add a small OneShotSound component that plays each sound on a freshly created SoundEffect and destroys it once playback ends, so the stream is open only while the sound is actually playing and the sink can suspend again at idle. It keeps the SoundEffect API (source, volume, play()), so the two call sites only swap the type and drop the now-unused QtMultimedia import.
fcbe5c3 to
42dd3d3
Compare
|
Verified on my pixel watch 2 LTE, with asteroidOS on it. |
The launcher no longer routes its notification/un-mute sounds through ngf - it plays them on a transient SoundEffect (OneShotSound) instead - so this sound-only ngf event is no longer triggered by anything. Remove the dead carry. See the asteroid-launcher OneShotSound change (AsteroidOS/asteroid-launcher#271). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ngf one Replace the carried ngf patch with the transient-SoundEffect approach (OneShotSound): it keeps the sound in Qt - idiomatic for AsteroidOS, where ngf is haptics/LED only - and needs no meta-asteroid ngfd event. Build-verified and on-device-verified on aurora (sound plays; stream is transient; sink suspends at idle with no persistent stream). Temporary carry until upstream merges (AsteroidOS/asteroid-launcher#271). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| @@ -0,0 +1,43 @@ | |||
| // Plays a sound once on a short-lived SoundEffect that is destroyed when | |||
| // playback ends, so the audio sink can suspend at idle. Drop-in for SoundEffect. | |||
There was a problem hiding this comment.
I would be more explicit in this comment that this is a hack that was specifically introduced to work around battery life issues appearing due to how QtMultimedia handles the pulseaudio connection on Qt6. In a few years we'll have forgotten why this is here and maybe QtMultimedia would have changed how it works.
Apart from that, I took some time to think about it and I'm ok with this approach yes. Let's do that instead of ngfd calls. This is one less dependency on ngfd to worry about.
moWerk
left a comment
There was a problem hiding this comment.
Hi @stianlaa, thank you for digging into this, and for a really clean writeup on a first PR. The standby drain you found is real, and your analysis of it is correct: a session-long SoundEffect keeps its PulseAudio stream open, the sink never suspends, and that costs battery. This PR does address that, and your on-device check backs it up.
Very good work.
The one thing we need to flag is scope.
This PR is linked to #342, and that issue is specifically about the notification sound playing chopped, sliced into short fragments with gaps. We took some time to test that directly on hardware (a beluga) rather than reason about it, and the two videos attached show the A/B: with OneShotSound the notification and unmute sounds still chop exactly as they do today, while an ngf-based playback plays the same wav gaplessly. So this change fixes the drain but not the chop that the issue is linked to, because the chop lives in QSoundEffect's Qt6 playback itself and survives regardless of how long-lived the object is.
The interesting twist is that your earlier, self-closed #270 (plus meta-asteroid#279) actually solved both halves at once: routing through ngf gives a full playback pipeline, which plays gaplessly, and the stream is released the same way, so the drain goes too.
Moving off that idea toward a pure-Qt route was a very reasonable instinct and i made my attempts to fix it from that side too.
Fewer nokia dependencies is a real goal for us, but it turns out to solve the chop we would need the ngfd playback path.
So rather than us landing a separate fix, we would much rather encourage you to solve rest of the way, since the groundwork is already yours.
Would you be up for reopening or rebasing a new PR on your #270 and meta-asteroid#279 approach? That closes #342 fully, drain and chop together, and keeps the credit where it belongs. Happy to help test it on device again when you do.
Here is the OneShotSound sadly still chopping:
video_2026-07-05_14-49-35.mp4
And here is the notification piggy backed onto the vibration/hapticsToggle, copying the code form your earlier PRs:
video_2026-07-05_14-49-51.mp4
Happy to hear 🥳 Its the least I can do to help out with some adjustments for details I come across in my explorations, I think AsteroidOS is a great initative and I'd like to help it thrive. My initial hunch was that my ngf-based playback approach would be introducing unnecessary dependencies, so a more pure Qt fix seemed more appealing. But that was before you told me about the choppiness that the ngf approach apparently fixes 😄 I'll reopen and rebase as you suggest - thanks for the testing and the excellent feedback. Hopefully I'll have time to look at this within the next couple of days. |
|
Mhh also asteroid-settings and asteroid-alarmclock's presenter would be affected by the same issue and would benefit from using ngf rather than qtmultimedia |
|
Closing in favour of the reopened #270 + AsteroidOS/meta-asteroid#279, per the review discussion. Thanks @moWerk for the beluga A/B testing and videos, and @FlorentRevest for the review! |
Hi folks! First PR to asteroidOS, so be kind, I appreciate pointers and input if you have them 😄
The notification and un-mute sounds are played by SoundEffect objects that live for the whole launcher session. A SoundEffect opens a PulseAudio playback stream when it is created and holds it for its entire lifetime, so these streams never close, the audio sink never suspends, module-suspend-on-idle never fires, and the audio power rail stays awake, a constant standby battery drain.
I will verify on-device (Pixel Watch 2, MACHINE=aurora) that both the notification and un-mute sounds still play and
that the audio sink suspends at idle afterwards, and report back here before this is ready to merge. Flagging now for early feedback on the approach.