TorizonCore on iMX6 with Qt: Increase ALSA Buffer Size? Getting BUFFER UNDERRUN when playing Audio

Hi Toradex Community,

I’m creating a separate topic from Audio output with TorizonCore - Technical Support - Toradex Community, but could still relate to the last few posts on that thread.

See below the configuration I am currently working with:

  • Apalis iMX6
  • Ixora Carrier Board v1.2
  • TorizonCore v6.1.0 Build 1
  • Custom container with Qt application

Here’s a bit of context:

I was working on outputting sounds to the correct ALSA device, but since the primitives classes of Qt, such as QSound, QSoundEffect and QMediaplayer, attempt to connect to a PulseAudio server by default, a simple play() call wasn’t an option in the case of Torizon images.

I therefore started to work on my own SoundManager with the use of QAudioOutput, QAudio format and QBuffer.

The main portion of my code to play a sound can be seen below. See under the code snippet for a summary.

QFile* m_audioFile;
QAudioOutput* audio;
QBuffer audio_buffer;
QByteArray audio_data;
void SoundManager::playAudio()
{
    m_audioFile = new QFile("/eclipse_qml/startup-sound.wav");
    if(m_audioFile->open(QIODevice::ReadOnly)) {
        m_audioFile->seek(44); // skip wav header
        audio_data = m_audioFile->readAll();
        m_audioFile->close();
  
        audio_buffer.setBuffer(&audio_data);
        audio_buffer.open(QIODevice::ReadOnly);
        qDebug() << "Audio Buffer Size: " << audio_buffer.size();
  
        QAudioFormat format;
        // Set up the format, eg.
        format.setSampleRate(44100);
        format.setChannelCount(2);
        format.setSampleSize(16);
        format.setCodec("audio/pcm");
        format.setByteOrder(QAudioFormat::LittleEndian);
        format.setSampleType(QAudioFormat::SignedInt);
  
        // Fetch Audio Device List
        QList<QAudioDeviceInfo> devices = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput);
        foreach (QAudioDeviceInfo i, devices){
            // Find desired Audio device
            if(i.deviceName() == "sysdefault:CARD=imx6qapalissgtl")
            {
  
                qDebug() << "Attempting to play on device: " << i.deviceName() << Qt::endl;
  
                // Format support check
                if (!i.isFormatSupported(format)) {
                    qDebug() << "Raw audio format not supported by backend, cannot play audio." << Qt::endl;
                    return;
                }
                else{
                    qDebug() << "Format supported" << Qt::endl;
                    // Load source file and play audio
                    
                    audio = new QAudioOutput(i, format, this);
                    connect(audio, SIGNAL(stateChanged(QAudio::State)), this, SLOT(handleStateChanged(QAudio::State)));
  
                    audio->start(&audio_buffer);
                    qDebug() << "Sound Player Started" << Qt::endl;
                    break;
                }
            }
        }
    }
}

Basically, I execute the following:

  1. Read my .wav audio file into a buffer
  2. Setup the audio format supported by the iMX6 desired ALSA sound device
  3. Fetch the Audio Device Info and use it for my QAudioOutput object.
  4. Load and play the sound saved in my buffer.

Executing this works and I can now hear my application sounds.

However, I hear a few audio mishaps, pops and cracks and a bunch of ALSA lib pcm.c:8545:(snd_pcm_recover) underrun occurred messages.

Upon doing some research, I see that for some people playing Audio via QT on Linux ARM usually get this because the ALSA default buffer size isn’t large enough, so data is lost.

So my question is, is there a way on Torizon to help increase this buffer size? I’m posting here since I don’t think this issue is from Qt.

Greetings @anthonyabboud,

So my question is, is there a way on Torizon to help increase this buffer size? I’m posting here since I don’t think this issue is from Qt.

It seems like you can tweak this via /proc/* files as documented here: Alsa Opensrc Org - Independent ALSA and linux audio support site

These files seem to exist on the host outside of the container. Haven’t played around with them too much so I can’t say what the effects will be.

That said, it’s curious that you only get this issue when trying to play in Qt and not when trying to play from the command line. Since I imagine the ALSA buffer would be the same for all of these tasks.

Best Regards,
Jeremias