kcat / alure

Alure is a utility library for OpenAL, providing a C++ API and managing common tasks that include file loading, caching, and streaming
zlib License
70 stars 20 forks source link

Crash after playing multiple sources simultaneously #49

Closed edin-m closed 4 months ago

edin-m commented 5 months ago

I'm trying to play the same buffer multiple times (multiple Source) in threads. However on source.destroy() alure crashes.

It crashes on context.cpp:1654 mPlaySources.erase( (iterator outside range)

What am I doing wrong?

Edit: sometimes it actually works, but sometimes crashes.

int main(int argc, char *argv[])
{
    using namespace alure;
    auto handler = std::make_shared<MyMessageHandler>();

    alure::DeviceManager devMgr = alure::DeviceManager::getInstance();

    alure::Device dev;
    if(!dev)
    {
        dev = devMgr.openPlayback();
    }
    std::cout<< "Opened \""<<dev.getName()<<"\"" <<std::endl;

    alure::Context ctx = dev.createContext();
    alure::Context::MakeCurrent(ctx);

    ctx.setMessageHandler(handler);

    const char* sourcefile = "F:\\Projects\\ik3\\ik3\\resources\\audio\\birds.mp3";
    alure::Buffer buffer = ctx.getBuffer(sourcefile);

    auto playFn = [&ctx, &buffer, &sourcefile]() {
        alure::Source source = ctx.createSource();
        source.play(buffer);
        std::cout<< "Playing "<< sourcefile <<" ("
                  << alure::GetSampleTypeName(buffer.getSampleType())<<", "
                  << alure::GetChannelConfigName(buffer.getChannelConfig())<<", "
                  << buffer.getFrequency() << "hz)" <<std::endl;

        while (source.isPlaying())  // crashes here after first source finishes
        {
            auto v = buffer.getSourceCount();
            // std::cout<< "\r "<<source.getSampleOffset()<<" / "<<buffer.getLength() <<std::flush;
            std::cout<< source.getSampleOffset()<<" / "<<buffer.getLength() << " " << v << " " << std::endl;
            std::this_thread::sleep_for(std::chrono::milliseconds(25));
            ctx.update();
        }
        std::cout<<std::endl;
        source.destroy();
    };

    std::thread t1(playFn);

    std::this_thread::sleep_for(std::chrono::milliseconds(1024));

    std::thread t2(playFn);

    t1.join();
    t2.join();

    std::thread t3(playFn);
    t3.join();

    ctx.removeBuffer(buffer);

    alure::Context::MakeCurrent(nullptr);
    ctx.destroy();
    dev.close();

    std::cout << "Success" << std::endl;

    return 0;
}
kcat commented 5 months ago

Unlike OpenAL, as of right now Alure isn't thread-safe. You need a mutex (or some other mutual exclusion method) to ensure multiple threads aren't making calls into Alure at the same time.