Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Playing .WAV files using QBuffer, QAudioOutput and QAudioFormat: Segmentation Fault
QtWS25 Last Chance

Playing .WAV files using QBuffer, QAudioOutput and QAudioFormat: Segmentation Fault

Scheduled Pinned Locked Moved Solved General and Desktop
segfaultsoundqbufferqaudiooutputwav
4 Posts 2 Posters 942 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A Offline
    A Offline
    Anthony Abboud
    wrote on 3 Mar 2023, 16:47 last edited by
    #1

    Hi Qt Community,

    I'm currently working on a Sound Manager for my Embedded System application and initially wrote the following code:

    QFile* m_sourceFile;
    QAudioOutput* audio;
    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;
        }
    }
    

    The code successfully outputs sounds to my correct sound device. However, the quality isn't perfect; I hear a few pops and cracks that I do not hear when using the ALSA aplay command in terminal, so the quality isn't matching.

    From my understanding, these imperfections are because I'm not handling a buffer. Upon some research, I modified my code to looks like this:

    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
            QByteArray audio_data = m_audioFile->readAll();
            m_audioFile->close();
            qDebug() << "Audio_Data ByteArray content: " << audio_data << Qt::endl;
    
            QBuffer* audio_buffer = new QBuffer(&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;
                    }
                }
            }
        }
    }
    
    void SoundManager::handleStateChanged(QAudio::State newState)
    {
        switch (newState) {
            case QAudio::IdleState:
                // Finished playing (no more data)
                qDebug() << "Finished playing, no more data" << Qt::endl;
                audio->stop();
                qDebug() << "Sound Player Stopped" << Qt::endl;
                delete m_audioFile;
                delete audio;
                delete audio_buffer;
                qDebug() << "Freed data" << Qt::endl;
                break;
    
            case QAudio::StoppedState:
                if(audio->error() != QAudio::NoError){
                    // Error handling
                    qDebug() << "Reached Stopped state: " << QString(audio->error()) << Qt::endl;
                }
                break;
    
            default:       
                break;
        }
    }
    

    This last code outputs the following:

    Audio_Data ByteArray content: <Some Hex data followed by a TON of \0x00>
    Audio Buffer Size:  1310780
    Attempting to play on device:  "sysdefault:CARD=imx6qapalissgtl" 
    Format supported 
    Sound Player Started 
    Segmentation fault
    

    In this case, I do not hear anything, and the program seems to crash before the stateChanged signal is triggered.

    It's my first time using QBuffer and QAudioOutput so I'm not too sure what triggered this issue, although I'm thinking it has to do with a memory leak I am not seeing.

    Any help on this is appreciated.

    Thanks in advance,
    Anthony

    1 Reply Last reply
    0
    • C Offline
      C Offline
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on 3 Mar 2023, 16:52 last edited by
      #2

      @Anthony-Abboud said in Playing .WAV files using QBuffer, QAudioOutput and QAudioFormat: Segmentation Fault:

      QBuffer* audio_buffer = new QBuffer(&audio_data);

      Please read the documentation of the QBuffer ctor you're using.

      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
      Visit the Qt Academy at https://academy.qt.io/catalog

      A 1 Reply Last reply 3 Mar 2023, 17:51
      0
      • C Christian Ehrlicher
        3 Mar 2023, 16:52

        @Anthony-Abboud said in Playing .WAV files using QBuffer, QAudioOutput and QAudioFormat: Segmentation Fault:

        QBuffer* audio_buffer = new QBuffer(&audio_data);

        Please read the documentation of the QBuffer ctor you're using.

        A Offline
        A Offline
        Anthony Abboud
        wrote on 3 Mar 2023, 17:51 last edited by
        #3

        Hi @Christian-Ehrlicher ,

        Thanks for the reply!

        Looking at the documentation, I see that the QByteArray data was no longer valid when exiting the function, therefore creating a SegFault from the QBuffer.

        The code now looks like the following:

        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)) {
                // Build QByteArray
                m_audioFile->seek(44); // skip wav header
                audio_data = m_audioFile->readAll();
                m_audioFile->close();
        
                // Set QBuffer with data
                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;
                        }
                    }
                }
            }
        }
        
        void SoundManager::handleStateChanged(QAudio::State newState)
        {
            switch (newState) {
                case QAudio::IdleState:
                    // Finished playing (no more data)
                    qDebug() << "Finished playing, no more data" << Qt::endl;
                    audio->stop();
                    qDebug() << "Sound Player Stopped" << Qt::endl;
                    delete m_audioFile;
                    delete audio;
                    qDebug() << "Freed data" << Qt::endl;
                    break;
        
                case QAudio::StoppedState:
                    if(audio->error() != QAudio::NoError){
                        // Error handling
                        qDebug() << "Reached Stopped state: " << QString(audio->error()) << Qt::endl;
                    }
                    break;
        
                default:       
                    break;
            }
        }
        

        And the sound now outputs. However, I'm still hearing a few pops in the audio file, and the outputs shows the following lines upon playing the sound:

        Audio Buffer Size:  1310780
        Attempting to play on device:  "sysdefault:CARD=imx6qapalissgtl" 
        Format supported 
        Sound Player Started 
        ALSA lib pcm.c:8545:(snd_pcm_recover) underrun occurred
        ALSA lib pcm.c:8545:(snd_pcm_recover) underrun occurred
        ALSA lib pcm.c:8545:(snd_pcm_recover) underrun occurred
        ALSA lib pcm.c:8545:(snd_pcm_recover) underrun occurred
        ALSA lib pcm.c:8545:(snd_pcm_recover) underrun occurred
        ALSA lib pcm.c:8545:(snd_pcm_recover) underrun occurred
        ALSA lib pcm.c:8545:(snd_pcm_recover) underrun occurred
        ALSA lib pcm.c:8545:(snd_pcm_recover) underrun occurred
        ALSA lib pcm.c:8545:(snd_pcm_recover) underrun occurred
        ALSA lib pcm.c:8545:(snd_pcm_recover) underrun occurred
        ALSA lib pcm.c:8545:(snd_pcm_recover) underrun occurred
        ALSA lib pcm.c:8545:(snd_pcm_recover) underrun occurred
        ALSA lib pcm.c:8545:(snd_pcm_recover) underrun occurred
        Finished playing, no more data 
        Sound Player Stopped 
        Freed data 
        
        C 1 Reply Last reply 3 Mar 2023, 17:59
        0
        • A Anthony Abboud
          3 Mar 2023, 17:51

          Hi @Christian-Ehrlicher ,

          Thanks for the reply!

          Looking at the documentation, I see that the QByteArray data was no longer valid when exiting the function, therefore creating a SegFault from the QBuffer.

          The code now looks like the following:

          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)) {
                  // Build QByteArray
                  m_audioFile->seek(44); // skip wav header
                  audio_data = m_audioFile->readAll();
                  m_audioFile->close();
          
                  // Set QBuffer with data
                  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;
                          }
                      }
                  }
              }
          }
          
          void SoundManager::handleStateChanged(QAudio::State newState)
          {
              switch (newState) {
                  case QAudio::IdleState:
                      // Finished playing (no more data)
                      qDebug() << "Finished playing, no more data" << Qt::endl;
                      audio->stop();
                      qDebug() << "Sound Player Stopped" << Qt::endl;
                      delete m_audioFile;
                      delete audio;
                      qDebug() << "Freed data" << Qt::endl;
                      break;
          
                  case QAudio::StoppedState:
                      if(audio->error() != QAudio::NoError){
                          // Error handling
                          qDebug() << "Reached Stopped state: " << QString(audio->error()) << Qt::endl;
                      }
                      break;
          
                  default:       
                      break;
              }
          }
          

          And the sound now outputs. However, I'm still hearing a few pops in the audio file, and the outputs shows the following lines upon playing the sound:

          Audio Buffer Size:  1310780
          Attempting to play on device:  "sysdefault:CARD=imx6qapalissgtl" 
          Format supported 
          Sound Player Started 
          ALSA lib pcm.c:8545:(snd_pcm_recover) underrun occurred
          ALSA lib pcm.c:8545:(snd_pcm_recover) underrun occurred
          ALSA lib pcm.c:8545:(snd_pcm_recover) underrun occurred
          ALSA lib pcm.c:8545:(snd_pcm_recover) underrun occurred
          ALSA lib pcm.c:8545:(snd_pcm_recover) underrun occurred
          ALSA lib pcm.c:8545:(snd_pcm_recover) underrun occurred
          ALSA lib pcm.c:8545:(snd_pcm_recover) underrun occurred
          ALSA lib pcm.c:8545:(snd_pcm_recover) underrun occurred
          ALSA lib pcm.c:8545:(snd_pcm_recover) underrun occurred
          ALSA lib pcm.c:8545:(snd_pcm_recover) underrun occurred
          ALSA lib pcm.c:8545:(snd_pcm_recover) underrun occurred
          ALSA lib pcm.c:8545:(snd_pcm_recover) underrun occurred
          ALSA lib pcm.c:8545:(snd_pcm_recover) underrun occurred
          Finished playing, no more data 
          Sound Player Stopped 
          Freed data 
          
          C Offline
          C Offline
          Christian Ehrlicher
          Lifetime Qt Champion
          wrote on 3 Mar 2023, 17:59 last edited by
          #4

          And the setBuffer() function you use has exact the same problem.

          Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
          Visit the Qt Academy at https://academy.qt.io/catalog

          1 Reply Last reply
          1
          • A Anthony Abboud has marked this topic as solved on 3 Mar 2023, 21:25

          2/4

          3 Mar 2023, 16:52

          • Login

          • Login or register to search.
          2 out of 4
          • First post
            2/4
            Last post
          0
          • Categories
          • Recent
          • Tags
          • Popular
          • Users
          • Groups
          • Search
          • Get Qt Extensions
          • Unsolved