Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Playing audio using thread



  • I am trying to use qthread to play audio.
    My code runs fine for sometime but after a few minutes i get an error saying

    GStreamer-WARNING **: Failed to load plugin '/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstximagesink.so': /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstximagesink.so: cannot open shared object file: Too many open files

    my code is as follows

    audioclass.h

    #ifndef AUDIOCLASS_H
    #define AUDIOCLASS_H
    
    #include <QThread>
    #include <QMediaPlayer>
    
    
    class audioClass : public QThread
    {
    public:
        audioClass();
    
        void playSound(QString audioPath);
    
        void run();
    
    private:
        QMediaPlayer *player;
    };
    
    #endif // AUDIOCLASS_H
    
    

    audioclass.cpp

    #include "audioclass.h"
    
    #include <QMediaPlayer>
    #include <QDebug>
    #include <QMutex>
    #include <QtCore>
    
    QString path = "";
    audioClass::audioClass()
    {
        player = new QMediaPlayer(this);
    }
    
    void audioClass::playSound(QString audioPath)
    {
        path = audioPath;
        run();
    }
    
    void audioClass::run()
    {
    
        QMutex myMutex;
        qDebug() << "Thread started";
        player->setMedia(QUrl::fromLocalFile(path));
        myMutex.lock();
        player->play();
        myMutex.unlock();
        qDebug() << "audio thread" << QThread::currentThread();
    }
    
    

    mainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include <QMediaPlayer>
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = nullptr);
    
        QTimer *mainTimer;
        QTimer *timer1sec;
        void mainTimerInit();
        void timer1secinit();
    
        ~MainWindow();
    
    public slots:
        void mainTimerCallback();
        void timer1seccallback();
    
    private:
        Ui::MainWindow *ui;
        QMediaPlayer *player;
    };
    
    #endif // MAINWINDOW_H
    
    

    mainwindow.cpp

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include "audioclass.h"
    
    #include <QTimer>
    #include <QDebug>
    
    int i = 0;
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::mainTimerInit()
    {
        mainTimer = new QTimer(this);
        connect(mainTimer, SIGNAL(timeout()), this, SLOT(mainTimerCallback()));
        mainTimer->start(5000);
    }
    
    void MainWindow::timer1secinit()
    {
        timer1sec = new QTimer(this);
        connect(timer1sec, SIGNAL(timeout()), this, SLOT(timer1seccallback()));
        timer1sec->start(1000);
    }
    
    void MainWindow::mainTimerCallback()
    {
        audioClass audObj;
        audObj.playSound("/home/fiem/Sound/00_E.mp3");
    
        qDebug() << "Playing audio";
    
    
    }
    
    void MainWindow::timer1seccallback()
    {
        i++;
        qDebug() << "1 sec thread" << QThread::currentThread();
        ui->label->setNum(i);
    }
    
    

    main.cpp

    #include "mainwindow.h"
    #include "audioclass.h"
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.show();
    
        w.timer1secinit();
        w.mainTimerInit();
    
        // Run audio thread
        audioClass audioClassObj;
        audioClassObj.start(QThread::LowPriority);
    
        return a.exec();
    }
    
    

    i have created a thread in audioclass class and i am trying to play audio using the mainwindow.

    Any help would be appreciated.


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    Are you closing all the files you are loading?



  • Shouldn't the audio file close automatically after it is played by the player? Or is there any way to close the audio file? I am not opening the audio file manually using QFile so I did not think about closing that.

    Also i left my program to run overnight and i got these errors as well

    (PAPIS:19650): GStreamer-CRITICAL **: gst_poll_get_read_gpollfd: assertion 'set != NULL' failed

    (PAPIS:19650): GStreamer-CRITICAL **: gst_bus_create_watch: assertion 'bus->priv->poll != NULL' failed

    (PAPIS:19650): GStreamer-CRITICAL **: Creating bus watch failed

    Now the audio is also not playing and the system hangs a little as well.

    I checked the no. of threads in my program and they are as follows

    PID SPID TTY TIME CMD
    19650 19650 ? 00:27:04 PAPIS
    19650 19651 ? 00:00:01 Qt bearer threa
    19650 19652 ? 00:00:05 QDBusConnection
    19650 19653 ? 00:00:02 QXcbEventQueue
    19650 19654 ? 00:00:00 dconf worker
    19650 19655 ? 00:00:00 gmain
    19650 19656 ? 00:00:00 gdbus
    19650 25026 ? 00:00:00 typefind:sink
    19650 25067 ? 00:00:00 id3demux3958:si
    19650 25068 ? 00:00:00 mpegaudioparse3
    19650 25069 ? 00:00:00 aqueue:src
    19650 25070 ? 00:00:00 pool

    I am unable to understand where the problem lies.



  • It may or may not be related but I found leaks last year in the Qt multimedia module (gstreamer as default backend) where it did not close URL based video streams when I would switch between multiple video feeds. The result was that after 20 or 30 stream switches it would quit working. It's possible and probable that this resource leak still exists.



  • I tried using valgrind from qt to check for the memory leaks and the program crashes as soon as it starts. Also i tried to use it through terminal and it shows no leaks and errors.


  • Lifetime Qt Champion

    @Kent-Dorfman Any chance of remembering the version you used ?

    @goshantry What version of Qt are you using ?



  • I still have the project directory so you are in luck:

    From the Makefile Generated by qmake (3.1) (Qt 5.9.4)

    The app was an operator console for an unmanned vehicle. It had four IP cameras and cycling through the feeds or toggling the same feed on and off many times eventually caused the feed to die.



  • @SGaist I am using Qt creator 4.8.1


  • Lifetime Qt Champion

    @goshantry said in Playing audio using thread:

    I am using Qt creator 4.8.1

    The question was what Qt version you're using, not which QtCreator version.



  • @jsulm Sorry for that
    I am using Qt 5.12.0


  • Lifetime Qt Champion

    Can you check with Qt 5.12.1 ?



  • checked with Qt 5.12.1
    I am still facing the same error


  • Lifetime Qt Champion

    @goshantry Is it working properly without threads?



  • After much hit and trial I found that when the program goes into the mainTimerCallback function, it initializes audObj every time. This object gradually takes up the memory. If i block this function my code works fine.

    Any idea as to why this object does not free the memory as soon as this function is completed?

    I tried doing this without QThread and everything works fine

    I also used audObj.deletelater() function but the system shows the same error


  • Lifetime Qt Champion

    Because it's not how memory manager works necessarily.

    By the way, with the code you shown, your QThread doesn't do anything as you call the run method explicitly except for the one in your main.cpp file.

    Also note that your mutex isn't useful as it's local to the run method so it's created each time the method is called.



  • Is there any way to free up memory after an object has been created in Qt or does it automatically frees up memory after the function has been completed?


  • Lifetime Qt Champion

    @goshantry Variables allocated on the stack are freed automatically when the function/method finishes.
    If a variable was allocated on the heap (new) then it is either freed when the parent is deleted (if you're using Qt parent/child feature) or you have to delete it at some point.
    As @SGaist pointed out your mutex is useless the way you're using it...



  • @jsulm I removed that part of my code and created a new function to play audio without thread. Everything works fine and I left to test it for 2 days. Now when I run the free -m command in the terminal it shows only around 250-300 mb remaining out of my 8Gb. The swap memory is also used to a great extent.

    Is this memory because of those objects which I declared with new() or with any object that has been created?

    Also do I use the delete later with every object that i created at the end of the function to release the memory?

    My application is supposed to run for long hours without having to shutdown or restart the system.


  • Lifetime Qt Champion

    @goshantry You release the memory when you don't need it anymore.
    "Also do I use the delete later with every object that i created at the end of the function to release the memory?" - do you mean deleteLater() method?
    You should use Valgrind to analyse where your app is consuming memory.
    "Is this memory because of those objects which I declared with new() or with any object that has been created?" - any of course. Everything in use by your app.
    Can you show the code you're currently using?



  • @jsulm I tried using valgrind in Qt and this is the output which I get everytime

    11:40:37: valgrind --child-silent-after-fork=yes --xml-socket=127.0.0.1:43171 --log-socket=127.0.0.1:46593 --xml=yes --smc-check=stack --tool=memcheck --gen-suppressions=all --track-origins=yes --leak-check=summary --num-callers=25 /home/fiem/workspace/build-PAPIS-Desktop_Qt_5_12_1_GCC_64bit-Debug/PAPIS
    11:41:11: The program has unexpectedly finished.
    11:41:11: Process exited with return value Process crashed
    11:41:11: Analyzing finished.
    

    Also I changed the Audio Playing function to

    // Constructor for class
    pisUser::pisUser(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::pisUser)
    {
        ui->setupUi(this);
        player = new QMediaPlayer(this);
    }
    
    // Function to play audio
    void pisUser::playAudioDirect()
    {
    //    player->deleteLater();
        player->setMedia(QUrl::fromLocalFile(path));
        player->play();               // Play the audio sounds
    }
    

    also player->deleteLater(); always crashes the application no matter where i put it


  • Lifetime Qt Champion

    @goshantry said in Playing audio using thread:

    also player->deleteLater(); always crashes the application no matter where i put it

    That's because player has a parent and parent deletes its children when it is deleted, so you have a double delete. Do not pass "this" to player as parent (or do not call delete later).
    And why do you try to call deleteLater BEFORE you actually use it?! You should do it when you don't need it anymore.
    See https://doc.qt.io/qt-5/objecttrees.html


  • Qt Champions 2020

    AFAIK, QtMM is not designed to use in separate threads (look to QMediaPlayer source code).



  • I was reading about QPointers and I tried the following

    QPointer<QMediaPlayer> player = new QMediaPlayer(this);
    
        //player = new QMediaPlayer(this);
    

    the part which I wrote in comments works fine
    The part with QPointer crashes my application

    It comes in the following function

    void QMediaPlayer::setMedia(const QMediaContent &media, QIODevice *stream)
    {
        Q_D(QMediaPlayer);
        stop();
    
        QMediaContent oldMedia = d->rootMedia;
        d->disconnectPlaylist();
        d->playlist = 0;
        d->rootMedia = media;
        d->nestedPlaylists = 0;
    
        if (oldMedia != media)
            emit mediaChanged(d->rootMedia);
    
        if (media.playlist()) {
            // reset playlist to the 1st item
            media.playlist()->setCurrentIndex(0);
            d->setPlaylist(media.playlist());
        } else {
            d->setMedia(media, stream);
        }
    }
    

    I get the segmentation fault error and the program crashes


  • Lifetime Qt Champion

    @goshantry said in Playing audio using thread:

    I get the segmentation fault error

    Where exactly?



  • @jsulm the current debugger location is on the starting brackets of the setmedia function.


Log in to reply