-
-
Notifications
You must be signed in to change notification settings - Fork 21.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[3.x] Add ability to mute AudioServer. #63458
base: 3.x
Are you sure you want to change the base?
Conversation
9361f25
to
eacfe7f
Compare
21c9bac
to
412a3c5
Compare
Marking as ready for review to get some eyes on this. I'm fully expecting a lot of bikeshedding / possible changes to the design, and this will require testing on all platforms. But it seems well worth doing, as well as throttling CPU in the editor / project manager, it also allows running user apps to play nicely with the OS and turn off audio processing when paused, which may be particularly important on mobile and may be necessary to allow some platforms to suspend. |
I like this approach. Just some background: In 4.x the audio server knows the playback state of almost all audio playback streams. The notable exception is that video players don't use the AudioStreamPlayback API yet, and are still stuck on the old way of registering a callback with the audio server. So if a video player is in the scene, the audio server does not directly know the state of that playback, and therefore doesn't have direct knowledge of whether it can sleep. If a video player is not in the scene, it would be able to choose to sleep whenever there are no playback streams currently playing, or after 10s of that being true, etc. I like the idea of using an indirect way of determining whether sleeping is possible, though. A video player's audio callback may or may not choose to push samples to the AudioServer depending on its pause state, but if it does want to push samples it will need to do so by requesting a pointer to that buffer via Edit: this should also allow this to be backported potentially to 3.6+ which is kind of cool. I don't see anything in here that's specific to 4.0 after a brief review. |
Another upside of doing this is that the editor and project manager will no longer constantly display a "playing audio" icon in the KDE task bar: |
This is actually currently written on 3.x and I'm happy to forward port once we have tested out / bikeshedded a bit, as you say most of the code is shared. The main question in my mind is whether the approach of hot swapping drivers is viable on all platforms (especially in terms of e.g. introducing audio delay or something). If not we could alternatively use more sleeps on some platforms, or an option to pause the audio driver if this exists on a platform, or simply turn off the functionality if problematic on a certain platform. My instincts are that hot swapping the driver should be okay, as it should be the same to the OS as just loading a new app using the audio driver. But I am no expert here. 😁 I suspect we may have to just test as much as possible among the contributors on different platforms, then go for it in a beta / test build and see what happens. Possibly a 3.6 early beta in we have feature freeze on 4.0, but either / both is fine. |
c6a0b9c
to
2a7535d
Compare
Just to note I'm happy to rebase this and port for 4.x. We did discuss in a PR meeting last year but at the time @reduz wasn't convinced of the use case (or implementation, not sure which was the blocker). On the other hand it is especially relevant given the increased use of Godot editor on mobile where battery saving is important, and the needs of Mac users who want their machines to sleep. EDIT: Rebased, and I've removed the mute button from the editor, as it no longer seems necessary now that the editor auto switches between dummy and active driver depending whether there is any audio output. I have backed up the branch with the mute button though. |
2a7535d
to
cedb01f
Compare
This is definitely something we need in the long term, not only for Godot itself but also for non-game applications that only play sound occasionally. (Some games may also do this, such as idle/incremental games.) |
Adds the option to change the audio driver to the Dummy driver and back at runtime, with a set of MuteState flags - Disabled (user control), Silence (period of silence), Focus Loss (when app is not in focus), and Paused (when app is paused). Control for the flags is added for the editor in EditorSettings, and for the project in ProjectSettings. Editor defaults to muted (Dummy driver) when there is no audio output, and automatically switches to active on output. This significantly reduces CPU usage.
cedb01f
to
4a5d495
Compare
Adds the option to change the audio driver to the Dummy driver and back at runtime, with a set of
MuteState
flags - Disabled (user control), Silence (period of silence), Focus Loss (when app is not in focus), and Paused (when app is paused).Control for the flags is added for the editor in EditorSettings, and for the project in ProjectSettings.
Editor defaults to muted (Dummy driver) when there is no audio output, and automatically switches to active on output. This significantly reduces CPU usage.
Fixes #28039
Fixes #55608
May help with #38154
Summary
EditorSettings
) and the running project (inProjectSettings
)Notes
I had noticed that with the
vital_updates_only
redraw option, the biggest CPU hog in the editor was now the audio, even when playing no audio it does a significant amount of processing.There have been various issues / PRs to reduce audio processing but they haven't amounted to much so far, so I had a first look through the audio today, and decided to have a wild stab at this. I'm not very versed in the audio, and am thus far from expert in this area, so the audio maintainers will have to decide whether this type of approach makes any sense. There are probably potential race conditions etc to contend with. Even if this doesn't prove fruitful I hope to spur the audio maintainers to offer such an option.
On my system there are two problems:
Although we can optimize the audio processing code, ultimately it is in a thread which will keep running in a loop unless something stalls it, so we need to look at either sleeping (or increasing existing sleep, I noticed there is a 1ms sleep on some drivers) or pausing or removing threads if not necessary.
Here I have explored using the option to stop the thread, by allowing swapping the driver on the fly to and from the
DummyAudioDriver
.MuteFlags
, which can be toggled at runtime. It will only play the audio when all are unset. The flags are:Disabled
- A user flag.Focus Loss
- Set and cleared when the app gains or loses focus.Paused
- Set when app is paused and resumed.Silence
- To be set when the audio encounters a section of silence, and automatically restart when sound detected again.The sensitivity to each of these flags is controlled by a mask and can be either be set in the
Editor
/ProjectSettings
, or altered at runtime (current defaults: editor is sensitive to all flags, but running projects are only sensitive to thedisabled
andpaused
flag). The idea is that most users will use the default for games, but people making apps might want to override this sensitivity mask.AudioDriverManager
can now be called at runtime to switch between audio drivers, and in this case, theDummy
driver (for muted) and the desired driver (for sound on).init
andfinalizing
multiple times. It seems to work fine so far with Pulse, and Dummy (I had to fix anullptr
issue in Dummy).Results
With the switch, and the
vital_updates_only
redraw option, my CPU usage (percentages of core, rather than whole CPU):Audio on : Godot 7%, PulseAudio 5%
Audio off (dummy) : Godot 2%, PulseAudio 0%
This is 1/6 of the CPU usage. The dummy driver actually still creates a thread which does some processing, although this processing is minimized. I did try removing the dummy thread, but it prevented playbacks progressing, so I've avoided that for now.
Discussion
It has also occurred to me, that given in most cases users might wish to reduce CPU usage in the editor in all areas, we could potentially combine such a setting with the
vital_updates_only
redraw option. This would give one less button. But on the other hand this could be confusing / non obvious.I've also implemented the approach suggested in #45948 (comment) . There is a
Silence
flag, which is set when 10 seconds of silence is detected, and cleared when playing the next sound.Now that the silence flag is implemented and is default in the editor, it no longer seems necessary to have a mute button in the editor. (Although godotengine/godot-proposals#1066 suggests having the mute button also mute any projects that are run from the editor, so maybe we could have it do that, but could be a later PR.)
@Calinou has also suggested allowing switching to the mute mode when the editor loses focus, so I've added this.
There is also the possibility to use the
is_audio_processing_allowed()
to throttle processing inAudioStreamPlayer
s. I haven't done that here to keep the PR as minimal as possible. This would also be different in 4.x (a number of things are different in audio in 4.x I believe, so that would need an independent implementation).An alternative instead of swapping driver might be to prevent heavy processing on the audio driver thread, and increase the sleep to a large value (say 100ms), while using the same logic from this PR.
Bugsquad edit: This closes godotengine/godot-proposals#1066 and partially addresses #54183.