File indexing completed on 2025-01-19 04:23:47

0001 /***************************************************************************
0002    SPDX-FileCopyrightText: 2014 (c) Sujith Haridasan <sujith.haridasan@kdemail.net>
0003    SPDX-FileCopyrightText: 2014 (c) Ashish Madeti <ashishmadeti@gmail.com>
0004    SPDX-FileCopyrightText: 2016 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr>
0005 
0006    SPDX-License-Identifier: GPL-3.0-or-later
0007  ***************************************************************************/
0008 
0009 #include "mediaplayer2player.h"
0010 #include "mpris2.h"
0011 
0012 #include "../../services/local/player.h"
0013 #include "../../services/local/playlist.h"
0014 
0015 #include <QCryptographicHash>
0016 #include <QDBusConnection>
0017 #include <QDBusMessage>
0018 #include <QStringList>
0019 
0020 #include "utils/bae.h"
0021 #include <MauiKit3/Core/fmh.h>
0022 
0023 static const double MAX_RATE = 1.0;
0024 static const double MIN_RATE = 1.0;
0025 
0026 MediaPlayer2Player::MediaPlayer2Player(Playlist *playListControler, Player *audioPlayer, bool showProgressOnTaskBar, QObject *parent)
0027     : QDBusAbstractAdaptor(parent)
0028     , m_playListControler(playListControler)
0029     , m_audioPlayer(audioPlayer)
0030     , mProgressIndicatorSignal(QDBusMessage::createSignal(QStringLiteral("/org/maui/vvave"), QStringLiteral("com.canonical.Unity.LauncherEntry"), QStringLiteral("Update")))
0031     , mShowProgressOnTaskBar(showProgressOnTaskBar)
0032 {
0033     if (!m_playListControler) {
0034         return;
0035     }
0036 
0037     connect(m_playListControler, &Playlist::currentIndexChanged, this, &MediaPlayer2Player::playerSourceChanged, Qt::QueuedConnection);
0038     connect(m_playListControler, &Playlist::canPlayChanged, this, &MediaPlayer2Player::playControlEnabledChanged);
0039     connect(m_playListControler, &Playlist::canPlayChanged, this, &MediaPlayer2Player::skipBackwardControlEnabledChanged);
0040     connect(m_playListControler, &Playlist::canPlayChanged, this, &MediaPlayer2Player::skipForwardControlEnabledChanged);
0041     connect(m_audioPlayer, &Player::stateChanged, this, &MediaPlayer2Player::playerPlaybackStateChanged);
0042     connect(m_audioPlayer, &Player::stateChanged, this, &MediaPlayer2Player::playerIsSeekableChanged);
0043 //    connect(m_audioPlayer, &Player::posChanged, this, &MediaPlayer2Player::audioPositionChanged);
0044     connect(m_audioPlayer, &Player::durationChanged, this, &MediaPlayer2Player::audioDurationChanged);
0045     connect(m_audioPlayer, &Player::volumeChanged, this, &MediaPlayer2Player::playerVolumeChanged);
0046 
0047     m_volume = m_audioPlayer->getVolume() / 100;
0048     m_canPlay = m_playListControler->canPlay();
0049     signalPropertiesChange(QStringLiteral("Volume"), Volume());
0050 
0051     m_mediaPlayerPresent = 1;
0052 }
0053 
0054 MediaPlayer2Player::~MediaPlayer2Player() = default;
0055 
0056 QString MediaPlayer2Player::PlaybackStatus() const
0057 {
0058     QString result;
0059 
0060     if (!m_playListControler) {
0061         result = QStringLiteral("Stopped");
0062         return result;
0063     }
0064 
0065     if (m_audioPlayer->getState() == QMediaPlayer::StoppedState) {
0066         result = QStringLiteral("Stopped");
0067     } else if (m_audioPlayer->getState() == QMediaPlayer::PlayingState) {
0068         result = QStringLiteral("Playing");
0069     } else {
0070         result = QStringLiteral("Paused");
0071     }
0072 
0073     if (mShowProgressOnTaskBar) {
0074         QVariantMap parameters;
0075 
0076         if (m_audioPlayer->getState() == QMediaPlayer::StoppedState || m_audioPlayer->getDuration() == 0) {
0077             parameters.insert(QStringLiteral("progress-visible"), false);
0078             parameters.insert(QStringLiteral("progress"), 0);
0079         } else {
0080             parameters.insert(QStringLiteral("progress-visible"), true);
0081             parameters.insert(QStringLiteral("progress"), qRound(static_cast<double>(m_position / m_audioPlayer->getDuration())) / 1000.0);
0082         }
0083 
0084         mProgressIndicatorSignal.setArguments({QStringLiteral("application://org.maui.vvave.desktop"), parameters});
0085 
0086         QDBusConnection::sessionBus().send(mProgressIndicatorSignal);
0087     }
0088 
0089     return result;
0090 }
0091 
0092 bool MediaPlayer2Player::CanGoNext() const
0093 {
0094     return m_canGoNext;
0095 }
0096 
0097 void MediaPlayer2Player::Next()
0098 {
0099     emit next();
0100 
0101     if (m_playListControler) {
0102         m_playListControler->next();
0103     }
0104 }
0105 
0106 bool MediaPlayer2Player::CanGoPrevious() const
0107 {
0108     return m_canGoPrevious;
0109 }
0110 
0111 void MediaPlayer2Player::Previous()
0112 {
0113     emit previous();
0114 
0115     if (m_playListControler) {
0116         m_playListControler->previous();
0117     }
0118 }
0119 
0120 bool MediaPlayer2Player::CanPause() const
0121 {
0122     return m_canPlay;
0123 }
0124 
0125 void MediaPlayer2Player::Pause()
0126 {
0127     if (m_playListControler) {
0128         m_audioPlayer->pause();
0129     }
0130 }
0131 
0132 void MediaPlayer2Player::PlayPause()
0133 {
0134     emit playPause();
0135 
0136     if (m_playListControler) {
0137         m_audioPlayer->pause();
0138     }
0139 }
0140 
0141 void MediaPlayer2Player::Stop()
0142 {
0143     emit stop();
0144 
0145     if (m_playListControler) {
0146         m_audioPlayer->stop();
0147     }
0148 }
0149 
0150 bool MediaPlayer2Player::CanPlay() const
0151 {
0152     return m_canPlay;
0153 }
0154 
0155 void MediaPlayer2Player::Play()
0156 {
0157     if (m_playListControler) {
0158         m_audioPlayer->play();
0159     }
0160 }
0161 
0162 double MediaPlayer2Player::Volume() const
0163 {
0164     return m_volume;
0165 }
0166 
0167 void MediaPlayer2Player::setVolume(double volume)
0168 {
0169     m_volume = qBound(0.0, volume, 1.0);
0170     emit volumeChanged(m_volume);
0171 
0172     m_audioPlayer->setVolume(100 * m_volume);
0173 
0174     signalPropertiesChange(QStringLiteral("Volume"), Volume());
0175 }
0176 
0177 QVariantMap MediaPlayer2Player::Metadata() const
0178 {
0179     return m_metadata;
0180 }
0181 
0182 qlonglong MediaPlayer2Player::Position() const
0183 {
0184     return m_position;
0185 }
0186 
0187 void MediaPlayer2Player::setPropertyPosition(int newPositionInMs)
0188 {
0189     m_position = qlonglong(newPositionInMs) * 1000;
0190 
0191     Q_EMIT Seeked(m_position);
0192 
0193     /* only sent new progress when it has advanced more than 1 %
0194      * to limit DBus traffic
0195      */
0196     const auto incrementalProgress = static_cast<double>(newPositionInMs - mPreviousProgressPosition) / m_audioPlayer->getDuration();
0197     if (mShowProgressOnTaskBar && (incrementalProgress > 0.01 || incrementalProgress < 0)) {
0198         mPreviousProgressPosition = newPositionInMs;
0199         QVariantMap parameters;
0200         parameters.insert(QStringLiteral("progress-visible"), true);
0201         parameters.insert(QStringLiteral("progress"), static_cast<double>(newPositionInMs) / m_audioPlayer->getDuration());
0202 
0203         mProgressIndicatorSignal.setArguments({QStringLiteral("application://org.maui.vvave.desktop"), parameters});
0204 
0205         QDBusConnection::sessionBus().send(mProgressIndicatorSignal);
0206     }
0207 }
0208 
0209 double MediaPlayer2Player::Rate() const
0210 {
0211     return m_rate;
0212 }
0213 
0214 void MediaPlayer2Player::setRate(double newRate)
0215 {
0216     if (newRate <= 0.0001 && newRate >= -0.0001) {
0217         Pause();
0218     } else {
0219         m_rate = qBound(MinimumRate(), newRate, MaximumRate());
0220         emit rateChanged(m_rate);
0221 
0222         signalPropertiesChange(QStringLiteral("Rate"), Rate());
0223     }
0224 }
0225 
0226 double MediaPlayer2Player::MinimumRate() const
0227 {
0228     return MIN_RATE;
0229 }
0230 
0231 double MediaPlayer2Player::MaximumRate() const
0232 {
0233     return MAX_RATE;
0234 }
0235 
0236 bool MediaPlayer2Player::CanSeek() const
0237 {
0238     return m_playerIsSeekableChanged;
0239 }
0240 
0241 bool MediaPlayer2Player::CanControl() const
0242 {
0243     return true;
0244 }
0245 
0246 void MediaPlayer2Player::Seek(qlonglong Offset)
0247 {
0248     if (mediaPlayerPresent()) {
0249         auto offset = (m_position + Offset) / 1000;
0250         m_audioPlayer->setPos(int(offset));
0251     }
0252 }
0253 
0254 void MediaPlayer2Player::emitSeeked(int pos)
0255 {
0256     emit Seeked(qlonglong(pos) * 1000);
0257 }
0258 
0259 void MediaPlayer2Player::SetPosition(const QDBusObjectPath &trackId, qlonglong pos)
0260 {
0261     if (trackId.path() == m_currentTrackId) {
0262         m_audioPlayer->setPos(int(pos / 1000));
0263     }
0264 }
0265 
0266 void MediaPlayer2Player::OpenUri(const QString &uri)
0267 {
0268     Q_UNUSED(uri);
0269 }
0270 
0271 void MediaPlayer2Player::playerSourceChanged()
0272 {
0273     if (!m_playListControler) {
0274         return;
0275     }
0276 
0277     setCurrentTrack(m_playListControler->currentIndex());
0278 }
0279 
0280 void MediaPlayer2Player::playControlEnabledChanged()
0281 {
0282     if (!m_playListControler) {
0283         return;
0284     }
0285 
0286     m_canPlay = m_playListControler->canPlay();
0287 
0288     signalPropertiesChange(QStringLiteral("CanPause"), CanPause());
0289     signalPropertiesChange(QStringLiteral("CanPlay"), CanPlay());
0290 
0291     emit canPauseChanged();
0292     emit canPlayChanged();
0293 }
0294 
0295 void MediaPlayer2Player::skipBackwardControlEnabledChanged()
0296 {
0297     if (!m_playListControler) {
0298         return;
0299     }
0300 
0301     m_canGoPrevious = m_playListControler->canGoPrevious();
0302 
0303     signalPropertiesChange(QStringLiteral("CanGoPrevious"), CanGoPrevious());
0304     emit canGoPreviousChanged();
0305 }
0306 
0307 void MediaPlayer2Player::skipForwardControlEnabledChanged()
0308 {
0309     if (!m_playListControler) {
0310         return;
0311     }
0312 
0313     m_canGoNext = m_playListControler->canGoNext();
0314 
0315     signalPropertiesChange(QStringLiteral("CanGoNext"), CanGoNext());
0316     emit canGoNextChanged();
0317 }
0318 
0319 void MediaPlayer2Player::playerPlaybackStateChanged()
0320 {
0321     signalPropertiesChange(QStringLiteral("PlaybackStatus"), PlaybackStatus());
0322     emit playbackStatusChanged();
0323 
0324     playerIsSeekableChanged();
0325 }
0326 
0327 void MediaPlayer2Player::playerIsSeekableChanged()
0328 {
0329     m_playerIsSeekableChanged = m_audioPlayer->getState() == QMediaPlayer::State::PausedState || m_audioPlayer->getState() == QMediaPlayer::State::PlayingState;
0330 
0331     signalPropertiesChange(QStringLiteral("CanSeek"), CanSeek());
0332     emit canSeekChanged();
0333 }
0334 
0335 void MediaPlayer2Player::audioPositionChanged()
0336 {
0337     setPropertyPosition(static_cast<int>(m_audioPlayer->getPos()));
0338 }
0339 
0340 void MediaPlayer2Player::audioDurationChanged()
0341 {
0342     m_metadata = getMetadataOfCurrentTrack();
0343     signalPropertiesChange(QStringLiteral("Metadata"), Metadata());
0344 
0345     skipBackwardControlEnabledChanged();
0346     skipForwardControlEnabledChanged();
0347     playerPlaybackStateChanged();
0348     playerIsSeekableChanged();
0349     setPropertyPosition(static_cast<int>(m_audioPlayer->getPos()));
0350 }
0351 
0352 void MediaPlayer2Player::playerVolumeChanged()
0353 {
0354     setVolume(m_audioPlayer->getVolume() / 100.0);
0355 }
0356 
0357 int MediaPlayer2Player::currentTrack() const
0358 {
0359     return m_playListControler->currentIndex();
0360 }
0361 
0362 void MediaPlayer2Player::setCurrentTrack(int newTrackPosition)
0363 {
0364     m_currentTrack = m_playListControler->currentTrack().value("url").toString();
0365     m_currentTrackId = QDBusObjectPath(QLatin1String("/org/maui/vvave/playlist/") + QString::number(newTrackPosition)).path();
0366 
0367     emit currentTrackChanged();
0368 
0369     m_metadata = getMetadataOfCurrentTrack();
0370     signalPropertiesChange(QStringLiteral("Metadata"), Metadata());
0371 }
0372 
0373 QVariantMap MediaPlayer2Player::getMetadataOfCurrentTrack()
0374 {
0375     auto result = QVariantMap();
0376 
0377     if (m_currentTrackId.isEmpty()) {
0378         return {};
0379     }
0380 
0381     result[QStringLiteral("mpris:trackid")] = QVariant::fromValue<QDBusObjectPath>(QDBusObjectPath(m_currentTrackId));
0382     result[QStringLiteral("mpris:length")] = qlonglong(m_audioPlayer->getDuration()) * 1000;
0383     // convert milli-seconds into micro-seconds
0384 
0385     auto track = m_playListControler->currentTrack();
0386     result[QStringLiteral("xesam:title")] = track["title"].toString();
0387     result[QStringLiteral("xesam:url")] = track["url"].toString();
0388 
0389     result[QStringLiteral("xesam:album")] = track["album"].toString();
0390     ;
0391 
0392     result[QStringLiteral("xesam:artist")] = QStringList{track["artist"].toString()};
0393 
0394 FMH::MODEL data{{FMH::MODEL_KEY::ARTIST, track["artist"].toString()}, {FMH::MODEL_KEY::ALBUM, track["album"].toString()}};
0395 
0396 if (BAE::artworkCache(data, FMH::MODEL_KEY::ALBUM))
0397 {
0398     result[QStringLiteral("mpris:artUrl")] =  QUrl(data[FMH::MODEL_KEY::ARTWORK]).toString();
0399 }
0400 
0401 return result;
0402 }
0403 
0404 int MediaPlayer2Player::mediaPlayerPresent() const
0405 {
0406     return m_mediaPlayerPresent;
0407 }
0408 
0409 bool MediaPlayer2Player::showProgressOnTaskBar() const
0410 {
0411     return mShowProgressOnTaskBar;
0412 }
0413 
0414 void MediaPlayer2Player::setShowProgressOnTaskBar(bool value)
0415 {
0416     mShowProgressOnTaskBar = value;
0417 
0418     QVariantMap parameters;
0419 
0420     if (!mShowProgressOnTaskBar || m_audioPlayer->getState() == QMediaPlayer::StoppedState || m_audioPlayer->getDuration() == 0) {
0421         parameters.insert(QStringLiteral("progress-visible"), false);
0422         parameters.insert(QStringLiteral("progress"), 0);
0423     } else {
0424         parameters.insert(QStringLiteral("progress-visible"), true);
0425         parameters.insert(QStringLiteral("progress"), qRound(static_cast<double>(m_position / m_audioPlayer->getDuration())) / 1000.0);
0426     }
0427 
0428     mProgressIndicatorSignal.setArguments({QStringLiteral("application://org.maui.vvave.desktop"), parameters});
0429 
0430     QDBusConnection::sessionBus().send(mProgressIndicatorSignal);
0431 }
0432 
0433 void MediaPlayer2Player::setMediaPlayerPresent(int status)
0434 {
0435     if (m_mediaPlayerPresent != status) {
0436         m_mediaPlayerPresent = status;
0437         emit mediaPlayerPresentChanged();
0438 
0439         signalPropertiesChange(QStringLiteral("CanGoNext"), CanGoNext());
0440         signalPropertiesChange(QStringLiteral("CanGoPrevious"), CanGoPrevious());
0441         signalPropertiesChange(QStringLiteral("CanPause"), CanPause());
0442         signalPropertiesChange(QStringLiteral("CanPlay"), CanPlay());
0443         emit canGoNextChanged();
0444         emit canGoPreviousChanged();
0445         emit canPauseChanged();
0446         emit canPlayChanged();
0447     }
0448 }
0449 
0450 void MediaPlayer2Player::signalPropertiesChange(const QString &property, const QVariant &value)
0451 {
0452     QVariantMap properties;
0453     properties[property] = value;
0454     const int ifaceIndex = metaObject()->indexOfClassInfo("D-Bus Interface");
0455     QDBusMessage msg = QDBusMessage::createSignal(QStringLiteral("/org/mpris/MediaPlayer2"), QStringLiteral("org.freedesktop.DBus.Properties"), QStringLiteral("PropertiesChanged"));
0456 
0457     msg << QLatin1String(metaObject()->classInfo(ifaceIndex).value());
0458     msg << properties;
0459     msg << QStringList();
0460 
0461     QDBusConnection::sessionBus().send(msg);
0462 }
0463 
0464 #include "moc_mediaplayer2player.cpp"