jarikomppa / soloud

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

Crash in mixBus when playing sound because of setInaudibleBehavior() #205

Closed asumagic closed 4 years ago

asumagic commented 5 years ago

SoLoud 2018119 on Arch Linux, 64-bit build, static library using static SDL2.

I tried to port a game's audio to SoLoud due to several issues with the current library we are using. I got most of it working surprisingly easily (nice API!), however I am facing a weird crash issue in the callback thread:

* thread #13, name = 'SDLAudioP2', stop reason = signal SIGSEGV: invalid address (fault address: 0x0)
    frame #0: 0x00007ffff5453f42 libJuxta.so`SoLoud::Soloud::mixBus(this=0x00007ffff7fac068, aBuffer=0x000055555636ef60, aSamplesToRead=1024, aBufferSize=1024, aScratch=0x000055555627a050, aBus=0, aSamplerate=44100, aChannels=2) at soloud.cpp:1403
   1400                                                 int readcount = 0;
   1401                                                 if (!voice->hasEnded() || voice->mFlags & AudioSourceInstance::LOOPING)
   1402                                                 {
-> 1403                                                         readcount = voice->getAudio(voice->mResampleData[0]->mData, SAMPLE_GRANULARITY, SAMPLE_GRANULARITY);
   1404                                                         if (readcount < SAMPLE_GRANULARITY)
   1405                                                         {
   1406                                                                 if (voice->mFlags & AudioSourceInstance::LOOPING)
  * frame #0: 0x00007ffff5453f42 libJuxta.so`SoLoud::Soloud::mixBus(this=0x00007ffff7fac068, aBuffer=0x000055555636ef60, aSamplesToRead=1024, aBufferSize=1024, aScratch=0x000055555627a050, aBus=0, aSamplerate=44100, aChannels=2) at soloud.cpp:1403
    frame #1: 0x00007ffff54555a9 libJuxta.so`SoLoud::Soloud::mix_internal(this=0x00007ffff7fac068, aSamples=1024) at soloud.cpp:1870
    frame #2: 0x00007ffff54558f8 libJuxta.so`SoLoud::Soloud::mix(this=0x00007ffff7fac068, aBuffer=0x000055555626e870, aSamples=1024) at soloud.cpp:1928
    frame #3: 0x00007ffff54a36b0 libJuxta.so`SoLoud::soloud_sdl2static_audiomixer(userdata=0x00007ffff7fac068, stream="��, len=8192) at soloud_sdl2_static.cpp:59
    frame #4: 0x00007ffff4580eee libSDL2-2.0.so.0`___lldb_unnamed_symbol91$$libSDL2-2.0.so.0 + 158
    frame #5: 0x00007ffff45c7f9f libSDL2-2.0.so.0`___lldb_unnamed_symbol1384$$libSDL2-2.0.so.0 + 63
    frame #6: 0x00007ffff464b6ea libSDL2-2.0.so.0`___lldb_unnamed_symbol2634$$libSDL2-2.0.so.0 + 10
    frame #7: 0x00007ffff7697a9d libpthread.so.0`start_thread + 253
    frame #8: 0x00007ffff6f35b23 libc.so.6`__GI___clone + 67

As per LLDB the crash is caused by the access to mData.

The main thread is not currently executing audio related code, and no other user code is interacting with SoLoud outside of the main thread.

When this happens, the (ogg) file is loaded using SoLoud::Wav (on a fresh new object) and then directly played several times at once (because the crash happens just while getting in-game).

Any clue what might be happening?

asumagic commented 5 years ago

It turns out the crash was due to a call to engine.setInaudibleBehavior(sound, true, false);. This was called just after the sound was created. If I have some time I'll try to make a reliable repro.

jarikomppa commented 4 years ago

I think this may have something to do with the mutex mess that got fixed a while ago, as that was related to having enough sounds and setInaudibleBehavior.

mobeenfikree commented 4 years ago

Hi there,

I have just run into the same crash using the latest release (20200207). I also tested against the latest code pulled from master a few days ago, and it also crashes. I'm running on macOS using the CoreAudio backend.

Here's a super simple repro:

#include "soloud.h"
#include "soloud_thread.h"
#include "soloud_wav.h"

int main(int argc, const char * argv[])
{
    const char* wav_filename = "/path/to/file.wav";

    SoLoud::Soloud soloud;
    soloud.init();

    SoLoud::Wav sample;
    sample.load(wav_filename);

    for (int t=0; t<16+1; t++)
    {
        SoundID handle = soloud.play(sample, 1.0f, 0.0f, true);
        soloud.setInaudibleBehavior(handle, true, false);
        soloud.setPause(handle, false);
    }

    while (soloud.getActiveVoiceCount() > 0)
    {
        SoLoud::Thread::sleep(100);
    }

    soloud.deinit();
    return 0;
}

Some notes:

Any idea what the issue might be?

Also, I just want to confirm that I understand this function correctly. The behaviour I want is when there are too many sounds playing at once, the quietest sounds should not be mixed, however they should still be ticked. Is setting (true, false) the correct approach?

Cheers!

mobeenfikree commented 4 years ago

I did a bit of investigation. I don't understand the code well enough to really know what's going on, but here are some notes:

The crash occurs because voice->mResampleData[0] is NULL (worth noting: voice->mResampleData[1] is also NULL).

As I understand it, voice->mResampleData is populated from a pool of buffers in the Soloud core object (Soloud::mResampleData). The size is allocated as mMaxActiveVoices * 2 which makes sense since each active voice needs two buffers to ping-pong between.

It seems like voice->mResampleData is NULL because it can't find a free buffer in the pool. But I'm not sure why it can't find it or where the buffers in the core object are mapped to the voices. If we just want to tick (but not mix) the voice, then we probably don't need a buffer for the voice at all...