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"