Skip to content

Release the notification sound's audio stream when idle#271

Closed
stianlaa wants to merge 1 commit into
AsteroidOS:masterfrom
kinwatch:soundeffect-transient-lifetime
Closed

Release the notification sound's audio stream when idle#271
stianlaa wants to merge 1 commit into
AsteroidOS:masterfrom
kinwatch:soundeffect-transient-lifetime

Conversation

@stianlaa

@stianlaa stianlaa commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

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.

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.
@stianlaa
stianlaa force-pushed the soundeffect-transient-lifetime branch from fcbe5c3 to 42dd3d3 Compare June 28, 2026 20:31
@stianlaa

Copy link
Copy Markdown
Contributor Author

Verified on my pixel watch 2 LTE, with asteroidOS on it.

stianlaa added a commit to kinwatch/meta-asteroid that referenced this pull request Jun 28, 2026
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>
stianlaa added a commit to kinwatch/meta-smartwatch that referenced this pull request Jun 28, 2026
…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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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 moWerk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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

@stianlaa

stianlaa commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

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.
..

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.

@FlorentRevest

Copy link
Copy Markdown
Member

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

@stianlaa

stianlaa commented Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

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!

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