thestk/rtaudio

Can't open `RtAudio` object from a different thread

Foaly opened this issue · 6 comments

Foaly commented

Hello!

I think I found a bug in RtAudio, although I am not sure and it might just be undocumented behaviour.

If I instanciate a RtAudio object in one thread and then call openStream on that object from another thread, the connection to the sound card can not be established. I did not read read anywhere that this is not possible, so I am assuming it might be bug. The output I am getting with the following minimal example is:

RtApiAsio::getDeviceInfo: unable to load driver (ASIO MADIface USB).


RtApiAsio::getDeviceInfo: unable to load driver (Realtek ASIO).


RtApiAsio::probeDeviceOpen: unable to load driver (ASIO MADIface USB).

Does anybody have an idea how to fix this? Thank you some much in advance!

Minimal example:

#include <RtAudio.h>

#include <chrono>
#include <thread>


RtAudio audioOutputStream( RtAudio::WINDOWS_ASIO );

int audioCallback(void* /*outputBuffer*/, void* /*inputBuffer*/, unsigned int /*frameCount*/, double /*streamTime*/, RtAudioStreamStatus /*status*/, void* /*userData*/)
{
    return 0;
}

void threadFunction()
{
    constexpr std::size_t sampleRate = 48000;
    unsigned int bufferSize = 512;
    constexpr unsigned int channelCount = 2;
    constexpr RtAudioFormat format = RTAUDIO_FLOAT32;

    RtAudio::StreamParameters outputStreamParams;
    outputStreamParams.deviceId = 0;
    outputStreamParams.nChannels = channelCount;

    try
    {
        audioOutputStream.openStream(&outputStreamParams,
                                     nullptr,
                                     format,
                                     static_cast<unsigned int>(sampleRate),
                                     &bufferSize,
                                     audioCallback);
        audioOutputStream.startStream();
    }
    catch (RtAudioError& e)
    {
        e.printMessage();
    }
}


int main()
{
    using namespace std::chrono_literals;

    std::thread t (threadFunction);

    std::this_thread::sleep_for(3s);

    t.join();
}

I tried this on OS-X and it worked fine. I don't know if it may be an issue with the ASIO API or the configuration on your particular computer.

Foaly commented

Ah forgot to add I am not of macos but on windows 11.

Does it work from same thread?

Foaly commented

@sonoro1234 Yes it does indeed. If my main function in the minimal example above looks like the following everything works as expected and no errors are printed.

int main()
{
    using namespace std::chrono_literals;

    threadFunction();

    std::this_thread::sleep_for(3s);

    audioOutputStream.closeStream();
}

The first example worked for me in Mac OS-X but not in Windows ASIO. I see in the RtApiAsio constructor that it says:
// ASIO cannot run on a multi-threaded apartment. You can call
// CoInitialize beforehand, but it must be for apartment threading
// (in which case, CoInitilialize will return S_FALSE here).
So, this seems to be a limitation of the ASIO API.

Foaly commented

Alright, if it is a limitation of the windows ASIO API, then it would be great if you could add a description of the behaviour to the documentation. I couldn't find anything about it anywhere here: https://www.music.mcgill.ca/~gary/rtaudio/
That would be fantastic! Thank you so much for investigating :)