jarikomppa / soloud

Free, easy, portable audio engine for games
http://soloud-audio.com
Other
1.76k stars 279 forks source link

Multithreading? #269

Open questor opened 4 years ago

questor commented 4 years ago

Hi. I'm using soloud in one of my hobby projects and like it. But today I had a strange crash and looked under the hood and wondered how multithreading is handled in the engine. I have own management-informations inside of my gui-widgets (I'm using dearimgui with a node editing widget) and got a strange crash. I've found that the audio-playback is handled inside an extra thread which in turn calls my audio-generation-callback, but inside an extra thread which means my code of controlling the audio generation and the audio-generation itself has to be multithreading-safe (which I could have noticed earlier because there is no audio-processing-like call in the mainloop, but ok). I've looked what the examples are doing, but I couldn't find any syncronization handling and wondered if you assume it's safe all the time or if it simply can not happen? I looked at the speech generation plugin and it seems it's also not syncronizing anything? (I would have expected syncronization at least when you change parameters of a currently playing instance).

And it would help if you mention it somewhere in the docs that it's important that you do syncronization if you provide an own callback.

Or do I miss something completely? Btw: I had the crash in 64bit ubuntu using alsa.

jarikomppa commented 4 years ago

Generally speaking, there's not a lot of multithreading in soloud itself to speak of (yet).

Conceptually there's just two threads: the audio thread and the application thread.

The audio backends tend to have their audio threads, which then call SoLoud to do the mixing. Sometimes, like with SDL, we don't even know there's another thread. With winmm I'm under the impression that it's not exactly another thread, but kinda is... Other audio backends have explicit threads that SoLoud sees.

Anyway, to answer your actual question, there's the audio thread mutex which is locked whenever SoLoud's internal data is to be changed. SoLoud only ever calls one audio source (audio producer) at a time currently. There's plans to move the audio source processing to several worker threads but I haven't gotten around to doing that as of yet. You can search the source code for lockAudioMutex_internal and unlockAudioMutex_internal calls to see that there's quite a lot of that going on.

On Wed, May 6, 2020 at 4:31 PM kai notifications@github.com wrote:

Hi. I'm using soloud in one of my hobby projects and like it. But today I had a strange crash and looked under the hood and wondered how multithreading is handled in the engine. I have own management-informations inside of my gui-widgets (I'm using dearimgui with a node editing widget) and got a strange crash. I've found that the audio-playback is handled inside an extra thread which in turn calls my audio-generation-callback, but inside an extra thread which means my code of controlling the audio generation and the audio-generation itself has to be multithreading-safe (which I could have noticed earlier because there is no audio-processing-like call in the mainloop, but ok). I've looked what the examples are doing, but I couldn't find any syncronization handling and wondered if you assume it's safe all the time or if it simply can not happen? I looked at the speech generation plugin and it seems it's also not syncronizing anything? (I would have expected syncronization at least when you change parameters of a currently playing instance).

And it would help if you mention it somewhere in the docs that it's important that you do syncronization if you provide an own callback.

Or do I miss something completely? Btw: I had the crash in 64bit ubuntu using alsa.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/jarikomppa/soloud/issues/269, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABCD6R2KR2DQOFTDRF45KKLRQFRDJANCNFSM4M2OJAFA .

questor commented 4 years ago

I've found the audio-mutex-lock, but as I understand this is internal. I'm talking more about the application side of audio programming, from my understanding the application mainloop and the audio generation loop which are running both in different threads depending on the setup.

Let's do a simple example to get to my point: in the mainloop is the imgui rendering and handling of synth parameters and the audio-processing-thread which uses the parameters to generate the audio signal. And both might (or might not when I understand your examplanation about backends correctly) run in the same thread or in different threads. and the access to these parameters need (from my understanding) syncronization because both threads access the values. (After a quick search might be this: https://github.com/jarikomppa/soloud/blob/master/src/audiosource/speech/soloud_speech.cpp#57 the mSynth variable which is used from the application and from the audio thread)

I don't want to blame the library or you, just understand the design behind the api and the library and a possible solution for my hobby project. Thanks for taking your time to help me!

jarikomppa commented 4 years ago

The mSynth in the file you pointed at is a member of the audio source instance which is never accessed by the application thread.

One way to get information from an audio source instance is to use the getInfo function, which also uses the audio thread mutex.

If you need thread synchronization in your own code, you should do so through the normal thread programming ways, i.e, introduce mutexes and/or other locks where needed, or possibly use atomic operations to avoid locks.

On Wed, May 6, 2020 at 11:09 PM kai notifications@github.com wrote:

I've found the audio-mutex-lock, but as I understand this is internal. I'm talking more about the application side of audio programming, from my understanding the application mainloop and the audio generation loop which are running both in different threads depending on the setup.

Let's do a simple example to get to my point: in the mainloop is the imgui rendering and handling of synth parameters and the audio-processing-thread which uses the parameters to generate the audio signal. And both might (or might not when I understand your examplanation about backends correctly) run in the same thread or in different threads. and the access to these parameters need (from my understanding) syncronization because both threads access the values. (After a quick search might be this:

https://github.com/jarikomppa/soloud/blob/master/src/audiosource/speech/soloud_speech.cpp#57 the mSynth variable which is used from the application and from the audio thread)

I don't want to blame the library or you, just understand the design behind the api and the library and a possible solution for my hobby project. Thanks for taking your time to help me!

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/jarikomppa/soloud/issues/269#issuecomment-624863475, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABCD6R2SZH3CRV2CKFE4SATRQG7YDANCNFSM4M2OJAFA .

questor commented 4 years ago

okay, thanks for the clarification. Can I propose to add a special paragraph at http://sol.gfxile.net/soloud/newsoundsources.html that this may run in an extra thread and needs to be threadsafe if it's modified when it is already playing a sound? Thanks! You can close the ticket.