PDA

View Full Version : QMediaPlaylist loop doesn't work in console



Kaguro
22nd June 2020, 00:36
Sorry if my qustion is lame, but i am new in Qt. So, I have a console application in QT, and i use c++. I would like to create a text-based mini game and i need some background music. I used QMediaPlayer QT class for this, and it worked... but i realise i can not loop the music. I found another QT Class for this the QMediaPlaylist. But the loop function did not work (it played just once). I tried it in a maindwindow application and if i used in the mainwindow.cpp it worked fine. And i dont know why, and where is my fault? I tried this way:

main.cpp


int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Menu();

return a.exec();
}

menu.cpp


Menu::Menu(QObject *parent) : QObject(parent)
{
///...........
this->mp = new MediaPlay();
mp->PlayMusic("backgroundmusic.mp3");
///...........
}

Mediaplay.cpp


MediaPlay::MediaPlay(QObject *parent) : QObject(parent)
{

}

void MediaPlay::PlayMusic(QString name)
{
this->playlist = new QMediaPlaylist(this);
this->settings = new QSettings(QDir::currentPath() + "/settings.ini", QSettings::IniFormat);
playlist->addMedia(QUrl::fromLocalFile(".//res//"+name));
playlist->setPlaybackMode(QMediaPlaylist::PlaybackMode::Loop );

this->player = new QMediaPlayer(this);
player->setVolume(settings->value("iVolume").toInt());
player->setPlaylist(playlist);
player->play();
}

void MediaPlay::SetVolume(int valume)
{
settings->setValue("iVolume",valume);
player->setVolume(valume);
}

/------
I have an exit function in Menu class. In the exit function i call "qApp->quit();"
and then not close the console, it sarts playing the background music in loop... but why?

ChrisW67
22nd June 2020, 06:24
When you had it in a GUI app at what point in time was the Menu object created?

It is quite posible that the the event loop needs to be running before the player starts playing (or maybe before creation).

Kaguro
22nd June 2020, 14:26
When you had it in a GUI app at what point in time was the Menu object created?

It is quite posible that the the event loop needs to be running before the player starts playing (or maybe before creation).

when i tried in the gui application i didn't create menu object so i just use the player in this way:
mainwindow.cpp


#include "mainwindow.h"
#include <QtMultimedia/QtMultimedia>

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
this->playlist = new QMediaPlaylist(this);
playlist->addMedia(QUrl::fromLocalFile("kula.mp3"));
playlist->setPlaybackMode(QMediaPlaylist::PlaybackMode::Loop );

this->player = new QMediaPlayer(this);
player->setPlaylist(playlist);
player->play();
}

MainWindow::~MainWindow()
{
//delete ui;
}


mainwindow.h


#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QtMultimedia/QMediaPlaylist>
#include <QtMultimedia/QMediaPlayer>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();

QMediaPlaylist *playlist;
QMediaPlayer *player ;

private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

and i didn't touch the main.cpp...
hmm and how can i create the event loop for this problem? (I didn't create event loop before)
btw really thanks to your help!! :)

d_stranz
22nd June 2020, 16:51
Are you sure the path you are building in PlayMusic() actually points to the correct location of your np3 file? Put in a qDebug() statement or two to print the absolute path to the file (QDir::absolutePath()) and see if that's where your file is actually located. (Note that absolutePath() does not verify that the file exists, it just turns "." and ".." relative paths into the fully-expanded path).

When you run your app in Qt Creator and when you run it standalone, quite often your working directory is not the same and not where you think it is.

Kaguro
22nd June 2020, 17:29
Are you sure the path you are building in PlayMusic() actually points to the correct location of your np3 file? Put in a qDebug() statement or two to print the absolute path to the file (QDir::absolutePath()) and see if that's where your file is actually located. (Note that absolutePath() does not verify that the file exists, it just turns "." and ".." relative paths into the fully-expanded path).

When you run your app in Qt Creator and when you run it standalone, quite often your working directory is not the same and not where you think it is.

yeah i understand what you say... but the problem is not the reach the file, because in the console application (which I want to achieve) play the music, but just once, not in the loop. And when i quit the application (just in the menu class) and the return a.exec(); execute and not close the app.. start the music in loop. And when i tried it in the gui application (as I showed above) its work perfectly. So the path is fine.

d_stranz
22nd June 2020, 21:46
I am not sure I understand what you are trying to do. In your Menu constructor, you are creating a MediaPlay instance with no parent. This means that the instance is not owned by the Menu class, but is a top-level QObject owned by the app itself. So when your Menu class goes out of scope, the MediaPlay instance is still valid.

In line 11 of Mediaplay.cpp, you tell the media player to loop. (setPlaybackMode())

So what I think is happening is that the QMediaPlayer instance is still "alive" even though your app has exited, so the music continues to play in a loop. It is possible that the QMediaPlayer sets up its own event loop to play music, so even though the main event loop has exited (a.exec() ends), the media player's loop is still running.

So try this: In the Menu constructor, pass "this" to the constructor for MediaPlay and see if that makes a difference.

Kaguro
23rd June 2020, 00:06
i dont really get it, i try to do this? :


Menu::Menu(QObject *parent) : QObject(parent)
{
this->mp = new MediaPlay(this);
mp->PlayMusic("backgroundmusic.mp3");
}

and the problem could be that my mediaplay class constructor dont have any parents?
btw, my problem is not that the music plays in a loop when i try to quit from the program ( i can play around that a simple return 0) I just dont get it why this happen.
MY Problem is when i start the program and call my menu constructor...


Menu::Menu(QObject *parent) : QObject(parent)
{
///...........
this->mp = new MediaPlay();
mp->PlayMusic("backgroundmusic.mp3");
///...........
}

... than plays the music but just once not in the loop .. dont repeat the music when finished :(
so i want loop in my background music but this way it's only play once :(

d_stranz
23rd June 2020, 18:57
I think you need to create a simple program that shows the problem and post the -complete- code here (all classes, all methods, not just pieces). If your console program is simple, then just post that.

It is really hard to understand from your description what is happening. You said your Menu class calls qApp->quit(). Where, when? If you are doing that, then why are you surprised if the music stops?

And you said this in your first post:


I have an exit function in Menu class. In the exit function i call "qApp->quit();"
and then not close the console, it starts playing the background music in loop... but why?

and this in your last post:


... then plays the music but just once not in the loop .. don't repeat the music when finished

So which is it? Does it loop or not?

Kaguro
23rd June 2020, 20:31
I think you need to create a simple program that shows the problem and post the -complete- code here (all classes, all methods, not just pieces). If your console program is simple, then just post that.

It is really hard to understand from your description what is happening. You said your Menu class calls qApp->quit(). Where, when? If you are doing that, then why are you surprised if the music stops?

And you said this in your first post:



and this in your last post:



So which is it? Does it loop or not?


Sorry for my bad english but i said the same first and last time too.
The most importent is the main.cpp:


int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);

Menu();
return a.exec();
}

SO, I mentioned that, when i call the qApp->quit() in the Menu class. Menu object is over jump to the "return a.exec();" and in this line starts the Music loop in the correct way BUT ITS NOT THE PROBLEM because
i can handel it (but i mentioned it cuze its interesting.. its working the great why but its wrong place where start the loop in the correct way).
BUT, What i want to achive is when i call the menu constructor and i start the music in the loop. But what happens the music is just ONCE playing. This point where i want the loop.

If u still dont get it, i try to introduce it with code in a simple way. btw i really thank to you to try to help me :) I am really sad it still dosn't work :(

ChrisW67
24th June 2020, 09:39
Here is a single-file, stripped down version of your program:

QT -= gui
QT += multimedia
CONFIG += c++11 console
CONFIG -= app_bundle
DEFINES += QT_DEPRECATED_WARNINGS

SOURCES += main.cpp



#include <QCoreApplication>
#include <QMediaPlayer>
#include <QMediaPlaylist>

class MediaPlay: public QObject {
Q_OBJECT
public:
MediaPlay(QObject *parent = nullptr) : QObject(parent) { }

void PlayMusic(QString name) {
playlist = new QMediaPlaylist(this);
playlist->addMedia(QUrl::fromLocalFile("/tmp/untitled/res/"+name));
playlist->setPlaybackMode(QMediaPlaylist::PlaybackMode::Loop );

player = new QMediaPlayer(this);
player->setVolume(50);
player->setPlaylist(playlist);
player->play();
}

private:
QMediaPlayer *player;
QMediaPlaylist *playlist;
};

class Menu: public QObject {
Q_OBJECT
public:
Menu(QObject *parent = nullptr) : QObject(parent)
{
mp = new MediaPlay(this);
mp->PlayMusic("backgroundmusic.mp3");
}
private:
MediaPlay *mp;
};

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Menu menu;
return a.exec();
}

#include "main.moc"

This compiles and runs as expected on Qt 5.15 under Linux.

I removed the settings stuff because QDir::currentPath() will almost certainly not be where you expect at all times.

Change the absolute path to your MP3 and try this.

Kaguro
24th June 2020, 15:59
Here is a single-file, stripped down version of your program:

QT -= gui
QT += multimedia
CONFIG += c++11 console
CONFIG -= app_bundle
DEFINES += QT_DEPRECATED_WARNINGS

SOURCES += main.cpp



#include <QCoreApplication>
#include <QMediaPlayer>
#include <QMediaPlaylist>

class MediaPlay: public QObject {
Q_OBJECT
public:
MediaPlay(QObject *parent = nullptr) : QObject(parent) { }

void PlayMusic(QString name) {
playlist = new QMediaPlaylist(this);
playlist->addMedia(QUrl::fromLocalFile("/tmp/untitled/res/"+name));
playlist->setPlaybackMode(QMediaPlaylist::PlaybackMode::Loop );

player = new QMediaPlayer(this);
player->setVolume(50);
player->setPlaylist(playlist);
player->play();
}

private:
QMediaPlayer *player;
QMediaPlaylist *playlist;
};

class Menu: public QObject {
Q_OBJECT
public:
Menu(QObject *parent = nullptr) : QObject(parent)
{
mp = new MediaPlay(this);
mp->PlayMusic("backgroundmusic.mp3");
}
private:
MediaPlay *mp;
};

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Menu menu;
return a.exec();
}

#include "main.moc"

This compiles and runs as expected on Qt 5.15 under Linux.

I removed the settings stuff because QDir::currentPath() will almost certainly not be where you expect at all times.

Change the absolute path to your MP3 and try this.



okaaay its working!!!!! :))) YOU ARE MY HERO thank you a lot!! Any idea my version why was wrong? Thnak you again! :)

Kaguro
25th June 2020, 02:03
Here is a single-file, stripped down version of your program:

QT -= gui
QT += multimedia
CONFIG += c++11 console
CONFIG -= app_bundle
DEFINES += QT_DEPRECATED_WARNINGS

SOURCES += main.cpp



#include <QCoreApplication>
#include <QMediaPlayer>
#include <QMediaPlaylist>

class MediaPlay: public QObject {
Q_OBJECT
public:
MediaPlay(QObject *parent = nullptr) : QObject(parent) { }

void PlayMusic(QString name) {
playlist = new QMediaPlaylist(this);
playlist->addMedia(QUrl::fromLocalFile("/tmp/untitled/res/"+name));
playlist->setPlaybackMode(QMediaPlaylist::PlaybackMode::Loop );

player = new QMediaPlayer(this);
player->setVolume(50);
player->setPlaylist(playlist);
player->play();
}

private:
QMediaPlayer *player;
QMediaPlaylist *playlist;
};

class Menu: public QObject {
Q_OBJECT
public:
Menu(QObject *parent = nullptr) : QObject(parent)
{
mp = new MediaPlay(this);
mp->PlayMusic("backgroundmusic.mp3");
}
private:
MediaPlay *mp;
};

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Menu menu;
return a.exec();
}

#include "main.moc"

This compiles and runs as expected on Qt 5.15 under Linux.

I removed the settings stuff because QDir::currentPath() will almost certainly not be where you expect at all times.

Change the absolute path to your MP3 and try this.


It's woking, but i have one more question... i realize when i am waiting for an input so "int input; cin >> input;" and the music is stop :( any advice?

d_stranz
25th June 2020, 20:36
It's woking, but i have one more question... i realize when i am waiting for an input so "int input; cin >> input;" and the music is stop any advice?

"cin >> input;" is basically a blocking operation. It stops your program and waits for the user to type something. When the user hits Return, it puts the text into the variable and resumes execution. A console program has only one thread, so if that thread is blocked, everything is blocked.

There is a way around this, by creating a socket connection to stdin and using Qt's event loop to listen for input on that socket. See this post. (https://gist.github.com/gjorquera/2576569) Since the media player and socket both use the event loop, this lets both run at the same time and the event loop will handle both of them.