Audio output with TorizonCore

Good morning @imeshsps and @jeremias.tx ,

I’ve attempted playing around with other Qt classes and seem to have something almost working.

Instead of using the primitive classes, such as QSound, QSoundEffect and QMediaPlayer, I went on the use QAudioFormat, QAudioOutput and QAudioDeviceInfo.

See below my code snippet of the class I drafted up real quick:

SoundManager.h

#ifndef SOUNDMANAGER_H
#define SOUNDMANAGER_H

#include <QObject>
#include <QAudioOutput>
#include <QAudioFormat>
#include <QFile>

class SoundManager : public QObject
{
    Q_OBJECT
public:   
    static SoundManager* Instance();
    void playAudio();
    
public slots:
    void handleStateChanged(QAudio::State newState);

private:
    explicit SoundManager(QObject *parent = nullptr);
    static SoundManager* m_instance;
    QFile* m_sourceFile;
    QAudioOutput* audio;
};

#endif // SOUNDMANAGER_H

SoundManager.cpp

#include "soundmanager.h"
#include <QDebug>

SoundManager* SoundManager::m_instance = nullptr;

SoundManager::SoundManager(QObject *parent)
    : QObject{parent}
{

}

SoundManager* SoundManager::Instance()
{
    if(!m_instance){
        m_instance = new SoundManager;
    }
    return m_instance;
}

void SoundManager::playAudio()
{
    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;
            QAudioDeviceInfo info(i);
            // Print out supported format by device
            qDebug() << "Supported Byte Orders: " << info.supportedByteOrders() 
            << "Supported Channel Counts: " << info.supportedChannelCounts() 
            << "Supported Codes: " << info.supportedCodecs()
            << "Supported Sample Rates: " << info.supportedSampleRates() 
            << "Supported Sample Sizes: " << info.supportedSampleSizes()
            << "Supported Sample Types: " << info.supportedSampleTypes()
            << Qt::endl;

            // Format support check
            if (!info.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
                m_sourceFile = new QFile("/eclipse_qml/startup-sound.wav");
                audio = new QAudioOutput(i, format, this);
                connect(audio, SIGNAL(stateChanged(QAudio::State)), this, SLOT(handleStateChanged(QAudio::State)));
                m_sourceFile->open(QIODevice::ReadOnly);
                audio->start(m_sourceFile);
                break;
            }
        }
    }
}

void SoundManager::handleStateChanged(QAudio::State newState)
{
    switch (newState) {
        case QAudio::IdleState:
            // Finished playing (no more data)
            audio->stop();
            m_sourceFile->close();
            delete audio;
            break;

        case QAudio::StoppedState:
            if(audio->error() != QAudio::NoError){
                // Error handling
                qDebug() << "Reached Stopped state: " << QString(audio->error()) << Qt::endl;
            }
            break;

        default:       
            break;
    }
}

To figure out the parameters set in QAudioFormat format, I executed the ALSA command line aplay to print out the information and matched them in the code.

Then I iterated through all of my audio devices until I reach the one we’re looking for, in our case it’s sysdefault:CARD=imx6qapalissgtl as @jeremias.tx showed me in one of my previous topic: TorizonCore Setting Audio Levels: No Simple Control detected by Amixer - Technical Support - Toradex Community. For code optimization, I’ll probably move up this device detection on application startup to avoid doing that everytime I want to play a sound.

From there I can simply call SoundManager::Instance()->playAudio(string audioFileName) from anywhere in the code.

I’ve tested with my app startup sound. It works, but there’s a very small amount of pops and cracks I’m hearing, so the quality isn’t as great as playing on command line. I’ll check around on Qt Forums to see if there’s a way to optimize sound quality.

Let me know if you found another method.

Thanks,
Anthony