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. 100 % of Processor when playing audio.
QtWS25 Last Chance

100 % of Processor when playing audio.

Scheduled Pinned Locked Moved General and Desktop
10 Posts 3 Posters 4.6k 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
    Anticross
    wrote on last edited by
    #1

    I've got a thread where I'm reading data from one buffer and put it to QAudioOutput buffer to play data. I'm using forever loop without sleep. And it loads my CPU on 100% and when I'm doing enithing else on PC(like open files) sound is clipping. So here as look my thread:
    @#ifndef SOUNDTHREAD_H
    #define SOUNDTHREAD_H

    #include <QThread>
    #include <QMutex>
    #include <QWaitCondition>
    #include <QAudioOutput>

    #include "AudioBuffer.h"

    class AudioBuffer;
    class QAudioOutput;

    class SoundThread : public QThread
    {
    Q_OBJECT

    //----------------------------------------------------------------------------------------------
    public: SoundThread(QAudioOutput * out_, AudioBuffer * buf): QThread(){
    m_buf = buf;
    m_out = out_;
    m_buf2 = (AudioBuffer*)(m_out->start());
    }
    //----------------------------------------------------------------------------------------------
    ~SoundThread(){
    m_mutex.lock();

                delete m_buf;
                delete m_buf2;
    
                m_condition.wakeOne();
                m_mutex.unlock();
    
                wait();
         }
    

    //----------------------------------------------------------------------------------------------
    public: void start(){
    QThread::start(QThread::HighPriority);
    }
    //----------------------------------------------------------------------------------------------
    public: void stop(){
    QThread::terminate();
    }
    //----------------------------------------------------------------------------------------------
    public: void run(){
    char* data;
    quint64 len;

    forever
    { 
                    m_mutex.lock();
     len = m_buf->bytesAvailable();
     data = new char[len];
     len = m_buf->readData(data, len);
     m_buf2->writeData(data, len);
     delete data;
                    m_mutex.unlock();
    }
    

    }
    //----------------------------------------------------------------------------------------------
    private:
    AudioBuffer * m_buf;
    AudioBuffer * m_buf2;
    QAudioOutput * m_out;

    QMutex m_mutex;
    QWaitCondition m_condition;
    

    };

    #endif//SOUNDTHREAD_H@

    1 Reply Last reply
    0
    • M Offline
      M Offline
      maxim.prishchepa
      wrote on last edited by
      #2

      try using QThread::sleep() at the forever loop

      Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz).

      1 Reply Last reply
      0
      • A Offline
        A Offline
        Anticross
        wrote on last edited by
        #3

        It's not the best solution, but works. Thanks.

        1 Reply Last reply
        0
        • G Offline
          G Offline
          goetz
          wrote on last edited by
          #4

          You're leaking memory!

          Call

          @
          delete[] data;
          @

          on the data pointer! See "Section 16.11ff of the C++ FAQ":http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.11 for some details.

          Rules: Always use together the following

          • new and delete
          • new[] and delete[]
          • malloc (or friends) and free()

          and never ever mix any of them.

          To your actual problem:

          as QAudioOutput::start() returns an [[Doc:QIODevice]], I assume that class AudioBuffer is an IO device. In that case, run an event loop in your run method and connect to the readyRead() signal. This way you're notified as soon as there's more data to read and you don't need to sleep in your thread.

          Being a QIODevice, you should consider kicking away the char buffer alltogether, but use readAll(), which returns a QByteArray, and write that bytearray to the out buffer.

          Best effort would be to put everything into a QObject based class and use QThread only as a lightweight thread manager instead of subclassing as a worker. See the excellent wiki article on "Threads, Events and QObjects":/wiki/Threads_Events_QObjects about this topic.

          http://www.catb.org/~esr/faqs/smart-questions.html

          1 Reply Last reply
          0
          • A Offline
            A Offline
            Anticross
            wrote on last edited by
            #5

            About readyRead() it seems like it's better then sleep. But on which slot I need to connect readyRead() signal to make forever loop ? Now I'm just using sleep:
            @public: void run(){
            char* data;
            quint64 len = 0;

            forever
            { 
                            m_mutex.lock();
            
             len = m_buf->bytesAvailable();
            
                            if(len != 0)
                            {
                                data = new char[len];
                                len = m_buf->readData(data, len);
            
                                m_buf2->write(data, len);
                                delete[] data;
                            }
            
                            m_mutex.unlock();
                            QThread::usleep(1);
                        }
            

            }@

            1 Reply Last reply
            0
            • A Offline
              A Offline
              Anticross
              wrote on last edited by
              #6

              I made a private slot in QThread:
              @private slots:
              void readMore()
              {
              char* data;
              quint64 len = 0;

                          m_mutex.lock();
              
                          len = m_buf->bytesAvailable();
              
                          if(len != 0)
                          {
                              data = new char[len];
                              len = m_buf->readData(data, len);
              
                              m_buf2->write(data, len);
                              delete[] data;
                          }
              
                          m_mutex.unlock();
                      }@
              

              and replace everything in run() method by this:
              @connect(m_buf,SIGNAL(readyRead()),this,SLOT(readMore()));@
              But I never get inside a slot.

              1 Reply Last reply
              0
              • G Offline
                G Offline
                goetz
                wrote on last edited by
                #7

                Using signal/slot you do not need a foreach loop at all.

                Some outline for your worker class (brain to terminal, not tested):

                soundworker.h (header)

                @
                class SoundWorker : public QObject
                {
                Q_OBJECT

                public:
                // it's good practice to have an optional parent pointer
                // for all QObject based classes!
                SoundWorker(QAudioOutput *out_, AudioBuffer * buf, QObject *parent = 0);

                protected slots:
                void copyInput();

                private:
                AudioBuffer *m_buf;
                AudioBuffer *m_buf2;
                QAudioOutput *m_out;
                };
                @

                soundworker.cpp (implementation)

                @
                SoundWorker::SoundWorker(QAudioOutput *out_, AudioBuffer * buf, QObject *parent)
                : QObject(parent),
                m_buf(buf),
                m_out(out_)
                {
                // never use C style casts in C++!
                // for QObject based classes use qobject_cast
                // otherwise use dynamic_cast or static_cast
                m_buf2 = qobject_cast<AudioBuffer *>(m_out->start());

                connect(m_buf, SIGNAL(readyRead()), this, SLOT(copyInput()));
                

                }

                void SoundWorker::copyInput()
                {
                while(m_buf->bytesAvailable() > 0) {
                QByteArray data = m_buf->readAll();
                m_buf2->write(data);
                // short version:
                // m_buf2->write(m_buf->readAll());
                }
                }
                @

                main.cpp (using it in your other code)

                @
                // put it into a thread like this:
                QThread *soundThread = new QThread(this);
                SoundWorker *worker = new SoundWorker;
                worker->moveToThread(soundThread);
                soundThread->start();
                @

                I've omitted the mutex and some cleanup code (not sure whether that's needed at all!)

                Please do read "Threads, Events and QObjects":/wiki/Threads_Events_QObjects wiki article.

                And after this think hard if your really need a thread at all. The QIODevice classes are asynchronous at all. The SoundWorker object works without a separate thread too.

                http://www.catb.org/~esr/faqs/smart-questions.html

                1 Reply Last reply
                0
                • A Offline
                  A Offline
                  Anticross
                  wrote on last edited by
                  #8

                  OK I made QObject based class:
                  @#ifndef SOUNDCONTROL_H
                  #define SOUNDCONTROL_H

                  #include <QObject>
                  #include <QAudioOutput>
                  #include <QMutex>
                  #include <QWaitCondition>

                  #include "AudioBuffer.h"

                  class AUdioBuffer;

                  class SoundControl : public QObject
                  {
                  Q_OBJECT

                  public:
                  //---------------------------------------------------------------------------------------------
                  SoundControl(QAudioOutput * out_, AudioBuffer * buf): QObject(){
                  m_buf = buf;
                  m_out = out_;
                  m_buf->start();
                  m_buf2 = m_out->start();
                  }
                  //---------------------------------------------------------------------------------------------
                  ~SoundControl(){
                  m_mutex.lock();

                          delete m_buf;
                          delete m_buf2;
                  
                          m_condition.wakeOne();
                          m_mutex.unlock();
                      }
                  

                  //---------------------------------------------------------------------------------------------
                  public slots:
                  void doWork() {
                  char* data;
                  quint64 len = 0;

                                  m_mutex.lock();
                  
                                  len = m_buf->bytesAvailable();
                  
                                  if(len != 0)
                                  {
                                      data = new char[len];
                                      len = m_buf->readData(data, len);
                  
                                      m_buf2->write(data, len);
                                      delete[] data;
                                  }
                  
                                  m_mutex.unlock();
                          }
                  

                  //---------------------------------------------------------------------------------------------
                  private:
                  AudioBuffer * m_buf;
                  QIODevice * m_buf2;
                  QAudioOutput * m_out;

                  QMutex m_mutex;
                  QWaitCondition m_condition;
                  

                  };

                  #endif//SOUNDCONTROL_H@

                  And do this in main thread:
                  @ m_th = new QThread;
                  SoundControl * worker = new SoundControl(m_output, m_buf);
                  QObject::connect(m_buf, SIGNAL(readyRead()), worker, SLOT(doWork()));
                  worker->moveToThread(m_th);
                  m_th->start();@

                  It work's but now the sound "clicks" frequently as when I use QThread::usleep(1);

                  1 Reply Last reply
                  0
                  • A Offline
                    A Offline
                    Anticross
                    wrote on last edited by
                    #9

                    AudioBuffer class described here :http://developer.qt.nokia.com/forums/viewthread/13323 . I see no difference between using qint64 readData(char * data, qint64 len) or realizing readAll method and using it.

                    1 Reply Last reply
                    0
                    • A Offline
                      A Offline
                      Anticross
                      wrote on last edited by
                      #10

                      One more thing: When I minimize some windows in system playback stops for the moment and after minimizing - continues again. So is there a thread problem or any else ?

                      1 Reply Last reply
                      0

                      • Login

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