looping problem in phonon audio player-in Qt - c++

A song is set as static in Phonon audio player. The loop works using aboutToFinish(). The problem is that there is a 1 sec delay at the end of the song, then the song repeats.
How can we avoid the delay? I have also stored in a temporary buffer (using QBuffer), for playing it. But it is not giving solution for looping issue.
musicpath="sound/sample.mp3";
Phonon::AudioOutput *audioOutput;
Phonon::VolumeSlider *volumeSlider;
Phonon::MediaObject *mediaObject;
mediaObject = new Phonon::MediaObject(this);
mediaObject->setCurrentSource(Phonon::MediaSource( musicpath));
connect(mediaObject, SIGNAL(aboutToFinish()),mediaObject,SLOT(stop()));
connect(mediaObject, SIGNAL(aboutToFinish()),mediaObject,SLOT(play()));
Phonon::createPath(mediaObject, audioOutput);
volumeSlider->setAudioOutput(audioOutput);
mediaObject->play();

I think best choice is checking for state of video is by using timer with 1 ms and play it if end
timer = new QTimer;
QObject::connect(timer, SIGNAL(timeout()), this, SLOT(timer_overflow()));
timer->start(1);
void MainWindow::timer_overflow()
{
if(ui->videoPlayer->isPaused())
{
video=Phonon::createPlayer(Phonon::VideoCategory,Phonon::MediaSource("video/back);
ui->videoPlayer->load(Phonon::MediaSource("video/background_video.wmv"));
ui->videoPlayer->play();
}
}

Related

How to make a timer that will work in a couple of months?

There is a task to set a timer that will work in a couple of months. I ran into a problem with QTimer::start(int msec) time is specified in int and also in milliseconds. It turns out I can specify 2147483647 milliseconds, which is a little less than a month. I used to use crontab, but I had to abandon it.
Code example:
uint sec_prediction, sec_now, answer;
QDateTime now = QDateTime::currentDateTime();
sec_now = now.toTime_t();
QLocale mylocale(QLocale::English);
qDebug() << mylocale.toString(now, "MMM d hh:mm:ss") << sec_now;
QDateTime payment = QDateTime::currentDateTime();
payment = payment.addMonths(3);
sec_prediction = payment.toTime_t();
qDebug() << mylocale.toString(payment, "MMM d hh:mm:ss") << sec_prediction;
answer = sec_prediction - sec_now;
qDebug() << answer << " - After this time, the timer should start. \n";
QTimer timer;
timer.setSingleShot(true);
connect(&timer, SIGNAL(timeout()), this, SLOT(processQueue()));
timer.start(answer * 1000);
Console output:
"Jan 7 00:42:38" 1673041358
"Apr 7 00:42:38" 1680817358
7776000 - After this time, the timer should start.
QObject::startTimer: Timers cannot have negative intervals
I am using Qt 4.8
Grateful for help
Since you are using c++98 you can use libuv (C library) which supports timers
uv_timer_t timer_req; // Timers invoke the registered callback after a certain
// time has elapsed since the timer was started.
uv_timer_init(loop, &timer_req); // Docs show how to create an event loop
// This call is non blocking but YOU have to make
// sure your program still runs after a month.
uv_timer_start(&timer_req, callback, 5000, 2000);
// here put a month's worth of secs ^^ ^^
// optionally set this to repeat ^^
// After waiting for "interval sesc" your callback runs
I see that Qt4.8 doesn't have the convenient QTimer::CallOnTimeout method, but it provides a QTimer class which is wired a bit differently:
// Create a QTimer, connect its timeout() signal to the
// appropriate slots, and call start(). From then on it
// will emit the timeout() signal at constant intervals.
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
timer->start(1000); // 1000 milliseconds timer.
Shameless plug of my C++ chrono-scheduler library. Using it would look like this:
#include "scheduler.h"
{
bool compensate = true; // a README explains
unsigned nWorkers = 1; // these values in the repo.
// 1. Create a scheduler.
ttt::CallScheduler plan(compensate, nWorkers);
// 2. Add your task.
auto myTask = []{
// You may want to repeat in another month
return ttt::Result::Finish;
};
auto token = plan.add(
myTask, // User tasks are std::function<ttt::Result()>
24h * 30, // Interval for execution or repetition
false); // Whether to immediately queue the task for execution
// 3. Wait a month ....
}
Essentially the scheduler has a pool of threads that:
Register tasks
Execute tasks at the specified intervals
Potentially re-register the tasks if they need re-running
This is the most general solution to the problem of adding ad-hoc as many tasks as you want, with millisecond (and even less) granularity without blocking the caller or the execution context. But the logic found within can be extracted and simplified for your case.

QT "Tick" widget loop

I'm trying to understand the correct way to update a widget at frame-time.
The specific problem I'm trying to solve is to set the remaining time of a timer on a label.
I created and started the timer
MainTimer = new QTimer(this);
MainTimer->setSingleShot(true);
MainTimer->start(5000);
and on the QML I have a label, UI_MainTimerLabel, that I can access through ui->UI_MainTimerLabel->setNum(int).
Since the QTimer doesn't provide a OnTimerUpdate signal or callback method, I suppose I have to create some kind of loop to read the timer's value and set it to the label.
Should I do it through a QThread?
QThread::create([&]() {
while(true)
{
ui->UI_RemainingTimer->setNum(MainTimer->remainingTime());
}
})->start();
(note: I know that this won't work, but it's not a problem since I'm just trying to understand the concept)
Should I use a 0-timed QTimer?
UpdateTimer = new QTimer(this);
//{binding the UpdateTimer end signal to a ui->UI_RemainingTimer->SetNum(MainTimer->RemainingTimer() function}
UpdateTimer->start(0);
Should I use a QEventLoop (but I have yet to fully understand what is their correct usage)?
Should I use a user-created "MyTimerLabel" widget that self-updates (in which virtual overridden method?)?
Or is there some other correct way to manage a frame-time update, that I couldn't understand? (I'm trying to get the general correct approach, not the solving approach of this specific problem, though)
Thanks in advance
Is it necessary to update the GUI at every moment? No, each frame is updated every 30ms so something appropriate is to update half of that time, that is 15 ms. So the second timer is set to that period by calculating the remaining time showing it in the GUI:
#include <QtWidgets>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTimer main_timer;
main_timer.setSingleShot(true);
QTimer update_timer;
QLabel label;
label.setAlignment(Qt::AlignCenter);
label.resize(640, 480);
QObject::connect(&update_timer, &QTimer::timeout, [&main_timer, &update_timer, &label](){
int rem = main_timer.remainingTime();
if(rem <0){
label.setNum(0);
update_timer.stop();
}
else{
label.setNum(rem);
}
});
label.show();
main_timer.start(5000);
update_timer.start(15);
return a.exec();
}

QMediaPlayer crashes when pausing playback

I have a longer wav-file, where I wanted to play smaller parts.
I stored startTime and endTime as qint64 and already loaded the audiofile:
player = new QMediaPlayer;
connect(player, SIGNAL(positionChanged(qint64)), this, SLOT(slotTick(qint64)));
player->setNotifyInterval(10);
player->setMedia(QUrl::fromLocalFile(mediasource));
...
player->setPosition(startTime);
player->play();
I observe the position with the positionChanged Signal andd use the following slot, to stop the playback once the end of the desired part is reached:
void PlayerWidget::slotTick(qint64 time){
if(endTime >= 0 && time >= endTime){
if(player->state() == QMediaPlayer::PlayingState){
player->stop();
}
}
Unfortunately, the program crashes shortly after the player stops. WHat could be the reason
Just had the same issue, and while I don't really know the underlying reason, I managed to somehow intuit a solution that actually works.
Instead of calling player->stop() directly, trigger it with a singleShot QTimer. Python code equivalent: QtCore.QTimer.singleShot(0, player.stop).

Qt change picture on timer

I'm trying to change the image on QLabel in Qt.
At first, I did the basic set image as follows:
void MainWindow::setMainDisplayNew(QString imageName){
QPixmap pix7 = imageName;
QPixmap pix8 = pix7.scaled(QSize(720,480), Qt::KeepAspectRatio);
ui->mainDisplay->setStyleSheet(imageName);
ui->mainDisplay->setPixmap(pix8);
}
Now I want to change this so I can pass 2 arrays. List of images and duration they should appear for and I want the display to show them for the indicated duration.
void MainWindow::setMainDisplay(QString imageName[], int size)
{
for(unsigned int i=0; i<size; i++)
{
QTimer * timer = new QTimer(this);
timer->setSingleShot(true);
connect(timer, &QTimer::timeout, [=](){
setMainDisplayNew(imageName[i]);
timer->deleteLater(); // ensure we cleanup the timer
});
timer->start(3000);
}
}
EDIT
With the help of the responses, I reached the above code. I am sending the 3 images. It is display the final image after 3 seconds and stays as is... Any help?
while(true){
This is your problem. Qt is an event-driven framework. The while(true) prevents events from being processed. Such events include the timeout from the QTimer and updating of the GUI. You need to allow the function to exit.
In addition, you're not cleaning up your timers, so you're leaking memory every time you enter the function (although that's currently only once!). You can clean up with a call to deleteLater.
Using C++ 11, it would be something like this: -
for(int i=0; i<mySize; i++)
{
QTimer * timer = new QTimer(this);
timer->setSingleShot(true);
connect(timer, &QTimer::timeout, [=](){
setMainDisplayNew(imageName[i]);
timer->deleteLater(); // ensure we cleanup the timer
});
timer->start(duration[i]);
}

Something is incorrectly set when try to start new thread

I'm trying to create a "responsive gui", which basically means that I have an app, and on the main window there is a button. After I press this button I want the "progress bar window" to get displayed which will show the progress of the work being done, and of course this work is being done in separate thread.
Unfortunately my approach with starting a new thread in ctor of this progress_bar window doesn't seems to work and I got frozen gui.
Here is the link to this project so you can download it and run without the need for copying and pasting anything: http://www.mediafire.com/?w9b2eilc7t4yux0
Could anyone please tell me what I'm doing wrong and how to fix it?
EDIT
progress_dialog::progress_dialog(QWidget *parent) :
QDialog(parent)
{/*this is this progress dialog which is displayed from main window*/
setupUi(this);
working_thread_ = new Threaded;
connect(working_thread_,SIGNAL(counter_value(int)),progressBar,SLOT(setValue(int)),Qt::QueuedConnection);
working_thread_->start();//HERE I'M STARTING THIS THREAD
}
/*this is run fnc from the threaded class*/
void Threaded::run()
{
unsigned counter = 0;
while(true)
{
emit counter_value(counter);
counter = counter + 1 % 1000000;
}
}
Independently from the fact that tight looping is bad, you should limit the rate at which you make changes to the main GUI thread: the signals from your thread are queued as soon they are emitted on the main thread event loop, and as the GUI can't update that fast, repaint events are queued rather than executed in real time, which freezes the GUI.
And anyways updating the GUI faster than the screen refresh rate is useless.
You could try something like this:
void Threaded::run()
{
QTime time;
time.start();
unsigned counter = 0;
// initial update
emit counter_value(counter);
while(true)
{
counter = (counter + 1) % 1000000;
// 17 ms => ~ 60 fps
if(time.elapsed() > 17) {
emit counter_value(counter);
time.restart();
}
}
}
Do you try to start the thread with a parent object?