Help needed with my C++ ASIO output code: many drivers are crashing internally

Audio Stream Input/Output (ASIO) is a protocol allowing communication between a software application and a computer's sound card.
byuu
Posts: 1
Joined: Tue Jul 18, 2017 9:55 pm

Help needed with my C++ ASIO output code: many drivers are crashing internally

Postby byuu » Thu Jul 20, 2017 11:34 pm

Hello all. I have written an ASIO output driver in C++ for low-latency audio playback in my software.

And while it works great for my Audigy Rx drivers, as well as with ASIO4ALL, it is crashing with many other drivers, including:
* Yamaha Steinberg CI1
* C-Media (CM6631A)
* FL Studio (not a real hardware driver)

The drivers appear to be crashing internally whenever I try to stop/release them, even when I do nothing in response to the callback messages. This takes down my entire application, even though ASIO is running in its own separate thread. I've tried adding lots of Sleep() commands in case the driver couldn't keep up, but to no avail.

Can anyone please help me with how to avoid this? I strongly believe they are vendor driver bugs (a driver should never crash, no matter what inputs you give it, it should return error codes instead), however I may well be using the API wrong. Although I've followed host\sample\hostsample.cpp as closely as possible. Other closed-source ASIO applications seem to work okay, but I can't analyze what they're doing differently for obvious reasons.

Stack trace example:

Image

I am using the direct COM interface, since this is a C++ project.

Initialization code:

Code: Select all

    //_active.classID retrieved from choosing one of HKLM\SOFTWARE\ASIO\*\CLSID entries
    CLSID classID;
    if(CLSIDFromString((LPOLESTR)_active.classID, (LPCLSID)&classID) != S_OK) return false;
    if(CoCreateInstance(classID, 0, CLSCTX_INPROC_SERVER, classID, (void**)&_asio) != S_OK) return false;

    if(!_asio->init((void*)_context)) return false;  //_context is a valid, visible window handle (HWND)
    if(_asio->getSampleRate(&_active.sampleRate) != ASE_OK) return false;
    if(_asio->getChannels(&_active.inputChannels, &_active.outputChannels) != ASE_OK) return false;
    if(_asio->getBufferSize(
      &_active.minimumBufferSize, &_active.maximumBufferSize,
      &_active.preferredBufferSize, &_active.granularity
    ) != ASE_OK) return false;

    _frequency = _active.sampleRate;
    _latency = _latency < _active.minimumBufferSize ? _active.minimumBufferSize : _latency;
    _latency = _latency > _active.maximumBufferSize ? _active.maximumBufferSize : _latency;

    for(auto n : range(_channels)) {
      _channel[n].isInput = false;
      _channel[n].channelNum = n;
      _channel[n].buffers[0] = nullptr;
      _channel[n].buffers[1] = nullptr;
    }
    ASIOCallbacks callbacks;
    callbacks.bufferSwitch = &AudioASIO::_bufferSwitch;
    callbacks.sampleRateDidChange = &AudioASIO::_sampleRateDidChange;
    callbacks.asioMessage = &AudioASIO::_asioMessage;
    callbacks.bufferSwitchTimeInfo = &AudioASIO::_bufferSwitchTimeInfo;
    if(_asio->createBuffers(_channel, _channels, _latency, &callbacks) != ASE_OK) return false;
    if(_asio->getLatencies(&_active.inputLatency, &_active.outputLatency) != ASE_OK) return false;

    ASIOChannelInfo channelInformation = {};
    channelInformation.channel = 0;
    channelInformation.isInput = false;
    if(_asio->getChannelInfo(&channelInformation) != ASE_OK) return false;
    _sampleFormat = channelInformation.type;

    if(_asio->start() != ASE_OK) return false;
    return true;


Termination code:

Code: Select all

    _asio->stop();  //crashes here
    _asio->disposeBuffers();  //if I don't call stop, it crashes here
    _asio->Release();  //if I don't call disposeBuffers, it crashes here

Return to “ASIO”

Who is online

Users browsing this forum: No registered users and 1 guest