File indexing completed on 2025-01-05 03:57:28

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2017-05-25
0007  * Description : a widget to play audio track.
0008  *
0009  * SPDX-FileCopyrightText: 2017-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #include "audplayerwdg.h"
0016 
0017 // Qt includes
0018 
0019 #include <QGridLayout>
0020 #include <QApplication>
0021 #include <QStyle>
0022 #include <QSlider>
0023 #include <QPushButton>
0024 #include <QLabel>
0025 #include <QIcon>
0026 #include <QTime>
0027 #include <QUrl>
0028 #include <QMessageBox>
0029 
0030 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
0031 
0032 #   include <QAudioOutput>
0033 
0034 #endif
0035 
0036 // KDE includes
0037 
0038 #include <klocalizedstring.h>
0039 
0040 // Local includes
0041 
0042 #include "dexpanderbox.h"
0043 #include "digikam_debug.h"
0044 
0045 namespace Digikam
0046 {
0047 
0048 class Q_DECL_HIDDEN AudPlayerWdg::Private
0049 {
0050 public:
0051 
0052     Private() = default;
0053 
0054 public:
0055 
0056     QString  afile;
0057 
0058 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
0059 
0060     QMediaPlayer* mediaObject = nullptr;
0061 
0062 #else
0063 
0064     DAudioPlayer* mediaObject = nullptr;
0065 
0066 #endif
0067 
0068     QPushButton* playPauseBtn = nullptr;
0069     QPushButton* stopBtn      = nullptr;
0070 
0071     QLabel* elapsedTimeLabel  = nullptr;
0072     QLabel* totalTimeLabel    = nullptr;
0073 
0074     QSlider* volumeWidget     = nullptr;
0075 };
0076 
0077 AudPlayerWdg::AudPlayerWdg(QWidget* const parent)
0078     : QWidget(parent),
0079       d      (new Private)
0080 {
0081 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
0082 
0083     d->mediaObject = new QMediaPlayer(this);
0084     d->mediaObject->setAudioOutput(new QAudioOutput);
0085 
0086     connect(d->mediaObject, SIGNAL(playbackStateChanged(QMediaPlayer::PlaybackState)),
0087             this, SLOT(slotPlayerStateChanged(QMediaPlayer::PlaybackState)));
0088 
0089     connect(d->mediaObject, SIGNAL(errorOccurred(QMediaPlayer::Error,QString)),
0090             this, SLOT(slotPlayerError(QMediaPlayer::Error,QString)));
0091 
0092     connect(d->mediaObject, SIGNAL(positionChanged(qint64)),
0093             this, SLOT(slotTimeUpdaterTimeout(qint64)));
0094 
0095 #else
0096 
0097     d->mediaObject = new DAudioPlayer(this);
0098 
0099     connect(d->mediaObject->player(), SIGNAL(stateChanged(QAVPlayer::State)),
0100             this, SLOT(slotPlayerStateChanged(QAVPlayer::State)));
0101 
0102     connect(d->mediaObject->player(), SIGNAL(errorOccurred(QAVPlayer::Error,QString)),
0103             this, SLOT(slotPlayerError(QAVPlayer::Error,QString)));
0104 
0105     connect(d->mediaObject, SIGNAL(positionChanged(qint64)),
0106             this, SLOT(slotTimeUpdaterTimeout(qint64)));
0107 
0108 #endif
0109 
0110     d->playPauseBtn = new QPushButton(QIcon::fromTheme(QLatin1String("media-playback-start")), QString(), this);
0111     d->stopBtn      = new QPushButton(QIcon::fromTheme(QLatin1String("media-playback-stop")),  QString(), this);
0112 
0113     d->elapsedTimeLabel          = new QLabel(this);
0114     DLineWidget* const separator = new DLineWidget(Qt::Vertical, this);
0115     d->totalTimeLabel            = new QLabel(this);
0116     setZeroTime();
0117 
0118     QLabel* const soundLabel     = new QLabel(this);
0119     soundLabel->setPixmap(QIcon::fromTheme(QLatin1String("speaker")).pixmap(22, 22));
0120 
0121     d->volumeWidget              = new QSlider(Qt::Horizontal, this);
0122     d->volumeWidget->setRange(0, 100);
0123     d->volumeWidget->setValue(100);
0124 
0125     // ----------------------
0126 
0127     QGridLayout* const grid      = new QGridLayout(this);
0128     grid->setContentsMargins(QMargins(0, 0, 0, 0));
0129     grid->setSpacing(qMin(QApplication::style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing),
0130                           QApplication::style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing)));
0131     grid->addWidget(d->playPauseBtn,     0, 0, 1, 1);
0132     grid->addWidget(d->stopBtn,          0, 1, 1, 1);
0133     grid->addWidget(d->elapsedTimeLabel, 0, 2, 1, 1);
0134     grid->addWidget(separator,           0, 3, 1, 1);
0135     grid->addWidget(d->totalTimeLabel,   0, 4, 1, 1);
0136     grid->addWidget(soundLabel,          0, 5, 1, 1);
0137     grid->addWidget(d->volumeWidget,     0, 6, 1, 1);
0138 
0139     // ----------------------
0140 
0141     connect(d->playPauseBtn, SIGNAL(clicked()),
0142             this, SLOT(slotPlay()));
0143 
0144     connect(d->stopBtn, SIGNAL(clicked()),
0145             this, SLOT(slotStop()));
0146 
0147     connect(d->volumeWidget, SIGNAL(valueChanged(int)),
0148             this, SLOT(slotSetVolume(int)));
0149 
0150     slotSetVolume(d->volumeWidget->value());
0151 }
0152 
0153 AudPlayerWdg::~AudPlayerWdg()
0154 {
0155     delete d;
0156 }
0157 
0158 void AudPlayerWdg::setAudioFile(const QString& afile)
0159 {
0160     d->afile = afile;
0161     slotStop();
0162 }
0163 
0164 void AudPlayerWdg::slotSetVolume(int v)
0165 {
0166     if (d->mediaObject->audioOutput())
0167     {
0168 
0169 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
0170 
0171         d->mediaObject->audioOutput()->setVolume(v / 100.0);
0172 
0173 #else
0174 
0175         d->mediaObject->setVolume((qreal)v / 100.0);
0176 
0177 #endif
0178 
0179     }
0180 }
0181 
0182 void AudPlayerWdg::slotPlay()
0183 {
0184     if (!d->mediaObject)
0185     {
0186         qCWarning(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Internal Media Object is null!";
0187 
0188         return;
0189     }
0190 
0191 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
0192 
0193     if ((d->mediaObject->playbackState() != QMediaPlayer::PlayingState) ||
0194         (d->mediaObject->playbackState() == QMediaPlayer::PausedState))
0195 
0196 #else
0197 
0198     if ((d->mediaObject->state() != QAVPlayer::PlayingState) ||
0199         (d->mediaObject->state() == QAVPlayer::PausedState))
0200 
0201 #endif
0202 
0203     {
0204 
0205 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
0206 
0207         if (d->mediaObject->playbackState() != QMediaPlayer::PlayingState)
0208 
0209 #else
0210 
0211         if (d->mediaObject->state() != QAVPlayer::PlayingState)
0212 
0213 #endif
0214 
0215         {
0216             d->mediaObject->setSource(QUrl::fromLocalFile(d->afile));
0217             d->mediaObject->play();
0218             setZeroTime();
0219         }
0220         else
0221         {
0222             d->mediaObject->pause();
0223         }
0224     }
0225     else
0226     {
0227         d->mediaObject->pause();
0228     }
0229 }
0230 
0231 void AudPlayerWdg::slotStop()
0232 {
0233     if (!d->mediaObject)
0234     {
0235         qCWarning(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Internal Media Object is null!";
0236 
0237         return;
0238     }
0239 
0240     d->mediaObject->stop();
0241     setZeroTime();
0242 }
0243 
0244 void AudPlayerWdg::slotTimeUpdaterTimeout(qint64 current)
0245 {
0246 
0247 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
0248 
0249     if (d->mediaObject->error() != QMediaPlayer::NoError)
0250 
0251 #else
0252 
0253     if (d->mediaObject->mediaStatus() == QAVPlayer::InvalidMedia)
0254 
0255 #endif
0256 
0257     {
0258         QMessageBox::warning(qApp->activeWindow(), qApp->applicationName(),
0259                              i18n("An error has occurred while playing: the media is not valid"));
0260         return;
0261     }
0262 
0263     int hours      = (int)(current  / (qint64)(60 * 60 * 1000));
0264     int mins       = (int)((current / (qint64)(60 * 1000)) - (qint64)(hours * 60));
0265     int secs       = (int)((current / (qint64)1000) - (qint64)(hours * 60 + mins * 60));
0266     QTime elapsedTime(hours, mins, secs);
0267 
0268     if (d->mediaObject->duration() > 0)
0269     {
0270         qint64 total  = d->mediaObject->duration();
0271         hours         = (int)(total  / (qint64)(60 * 60 * 1000));
0272         mins          = (int)((total / (qint64)(60 * 1000)) - (qint64)(hours * 60));
0273         secs          = (int)((total / (qint64)1000) - (qint64)(hours * 60 + mins * 60));
0274         QTime totalTime(hours, mins, secs);
0275         d->totalTimeLabel->setText(totalTime.toString(QLatin1String("H:mm:ss")));
0276     }
0277 
0278     d->elapsedTimeLabel->setText(elapsedTime.toString(QLatin1String("H:mm:ss")));
0279 }
0280 
0281 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
0282 
0283 void AudPlayerWdg::slotPlayerError(QMediaPlayer::Error err, const QString& message)
0284 {
0285     if (err != QMediaPlayer::NoError)
0286     {
0287         QMessageBox::warning(qApp->activeWindow(), qApp->applicationName(),
0288                              i18n("An error has occurred while playing: %1", message));
0289     }
0290 }
0291 
0292 void AudPlayerWdg::slotPlayerStateChanged(QMediaPlayer::PlaybackState state)
0293 {
0294     switch (state)
0295     {
0296         case QMediaPlayer::PausedState:
0297         case QMediaPlayer::StoppedState:
0298         {
0299             d->playPauseBtn->setIcon(QIcon::fromTheme(QLatin1String("media-playback-start")));
0300             break;
0301         }
0302 
0303         case QMediaPlayer::PlayingState:
0304         {
0305             d->playPauseBtn->setIcon(QIcon::fromTheme(QLatin1String("media-playback-pause")));
0306             break;
0307         }
0308 
0309         default:
0310         {
0311             break;
0312         }
0313     }
0314 }
0315 
0316 #else
0317 
0318 void AudPlayerWdg::slotPlayerError(QAVPlayer::Error err, const QString& message)
0319 {
0320     if (err != QAVPlayer::NoError)
0321     {
0322         QMessageBox::warning(qApp->activeWindow(), qApp->applicationName(),
0323                              i18n("An error has occurred while playing: %1", message));
0324     }
0325 }
0326 
0327 void AudPlayerWdg::slotPlayerStateChanged(QAVPlayer::State state)
0328 {
0329     switch (state)
0330     {
0331         case QAVPlayer::PausedState:
0332         case QAVPlayer::StoppedState:
0333         {
0334             d->playPauseBtn->setIcon(QIcon::fromTheme(QLatin1String("media-playback-start")));
0335             break;
0336         }
0337 
0338         case QAVPlayer::PlayingState:
0339         {
0340             d->playPauseBtn->setIcon(QIcon::fromTheme(QLatin1String("media-playback-pause")));
0341             break;
0342         }
0343 
0344         default:
0345         {
0346             break;
0347         }
0348     }
0349 }
0350 
0351 #endif
0352 
0353 void AudPlayerWdg::setZeroTime()
0354 {
0355     d->elapsedTimeLabel->setText(QTime(0, 0, 0).toString(QLatin1String("H:mm:ss")));
0356     d->totalTimeLabel->setText(QTime(0, 0, 0).toString(QLatin1String("H:mm:ss")));
0357 }
0358 
0359 } // namespace Digikam
0360 
0361 #include "moc_audplayerwdg.cpp"