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

QmediaPlayer does not signal when mp3 (audio only) ends



  • QMediaPlayer EndOfMedia StoppedState mp3 audio QCoreApplication```

    The following short application plays mp3 audio files just fine, but when executed from a command line, I would like the application to block until the mp3 file (whose name is input thru argv[1]) ends. The app as written does not block, but immediately returns control to the console while the process remains running in memory. The process continues after the mp3 sound file has played to the end. The process does not end until it is killed.

    Questions:

    1. Why does QMediaPlayer not signal stoppedState?
    2. Why does QMediaPlayer not signal EndOfMedia?
    3. Is there a way to cause QCoreApplication to block return of the console until the process ends?
    #ifndef PLAYNEXIT_HPP
    #define PLAYNEXIT_HPP
    #include <QMediaPlayer>
    #include <QDebug>
    #include <Protos/qexp.h>
    
    class EXPQCLS playNexit: public QMediaPlayer{
      Q_OBJECT
      public:
       playNexit(QObject *parent = 0) : QMediaPlayer(parent){}
    
       public slots:
        void run(char* filename)
        {
         connect(this,SIGNAL(stateChanged(QMediaPlayer::State state)),this,SLOT(exitWhenStopped()));
         connect(this,SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus status)),this,SLOT(exitWhenStopped()));
         setMedia(QUrl::fromLocalFile(filename));
         setVolume(50);
         play();
         qInfo() << "Playing Media.";
        }
    
        void exitWhenStopped()
        {
         if (this->mediaStatus() ==QMediaPlayer::EndOfMedia)
         {
          qInfo() << "End of Media.";
          emit finished();
         }
         if (this->state()==QMediaPlayer::StoppedState)
         {
          qInfo() << "Stopped State.";
          emit finished();
         }
        }
    
      signals:
       void finished();
    };
    
    #endif // PLAYNEXIT_HPP
    
    
    #include <QtCore>
    #include <QCoreApplication>
    #include "playNexit.hpp"
    int main(int argc, char *argv[])
    {
      QCoreApplication a(argc, argv);
      playNexit pNe;
      QObject::connect(&pNe, &playNexit::finished,
                         &a, &QCoreApplication::quit,
                         Qt::QueuedConnection);
      pNe.run(argv[1]);
      return a.exec();
    }
    

  • Qt Champions 2019

    @Mosquito92 said in QmediaPlayer does not signal when mp3 (audio only) ends:

    connect(this,SIGNAL(stateChanged(QMediaPlayer::State state)),this,SLOT(exitWhenStopped()));

    Remove "state" parameter name from SIGNAL. Same for second connect.
    Better to use new Qt5 connect syntax: https://wiki.qt.io/New_Signal_Slot_Syntax



  • @jsulm Thank you so much for your reply!
    Your suggestion to remove the state variable from the SIGNAL statement made looking for the EndOfMedia signal superfluous, and now the process does stop when the mp3 sound file has finished.

    Is there any way to make QCoreApplication block until the quit is received? (In other words is there a way to alter QCoreApplication so it does not immediately return control to the console)?


  • Lifetime Qt Champion

    Hi,

    If you to do some stuff after exec returns, just store the result of the call, do what you need and then return the value.

        int result = app.exec();
        // add fancy code
        return result; // or some other status code that make sense from your code.
    }
    


  • Thankyou for your reply, but I'm unable to see exactly what to do in this situation. Modified as below, the application generates no errors, and does play an mp3 sound only file to its completion which can take seconds. But the application also returns control of the console immediately (long before the sound file ends and long before main() exits???). I want the app to give control back to the console only after the mp3 has quit playing. Odd as it may seem, that is not what happens, and the mutex (which I thought would block main() from exiting does indeed do that, but it does not keep control from returning to the console almost immediately.

    Here is my main application with the changes described:

    #include <QtCore>
    #include <QCoreApplication> 
    #include "playNexit.hpp"
    
    int main(int argc, char *argv[])
    {
      QCoreApplication a(argc, argv);
      playNexit pNe;
      QMutex mutex;
      QObject::connect(&pNe, &playNexit::finished,
                         &a, &QCoreApplication::quit,
                         Qt::QueuedConnection);
    
      pNe.setMutex(&mutex);
      mutex.lock(); // 1st lock takes the semaphore
      pNe.run(argv[1]);
      a.exec();
      mutex.lock(); // 2nd lock should cause app to block until unlock.
      return 0;
    }
    

    And here is the playNexit class derived from QMediaPlayer:

    #ifndef PLAYNEXIT_HPP
    #define PLAYNEXIT_HPP
    #include <QMutex>
    #include <QMediaPlayer>
    #include <Protos/qexp.h>
    class EXPQCLS playNexit: public QMediaPlayer{
      Q_OBJECT
      public:
       playNexit(QObject *parent = 0) : QMediaPlayer(parent){}
    
       public slots:
        void run(char *filename)
        {
         connect(this,SIGNAL(stateChanged(QMediaPlayer::State)),this,SLOT(exitWhenStopped()));
         setMedia(QUrl::fromLocalFile(filename));
         setVolume(50);
         play();
        }
    
        void exitWhenStopped()
        {
         if (this->state()==QMediaPlayer::StoppedState)
         {
          pMutex->unlock(); // main thread should release 2nd lock?
          emit finished();
         }
        }
    
      signals:
       void finished();
    
      public:
      QMutex *pMutex;
      void setMutex(QMutex *pm)
      {
       pMutex = pm;
      }
    
    };
    
    #endif // PLAYNEXIT_HPP
    
    

    I tried using a QMutex to lock the main after a.exec(), and to have a pointer to the mutex unlock() just before emit finished in the exitwhenStopped() function, but it did not seem to work. This still sounds like the right approach...


  • Lifetime Qt Champion

    That should not be needed.

    Did you check all the states your QMediaPlayer goes through ?


Log in to reply