File indexing completed on 2024-05-19 05:38:37

0001 /*
0002     SPDX-FileCopyrightText: 2023 Fushan Wen <qydwhotmail@gmail.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-or-later
0005 */
0006 
0007 #pragma once
0008 
0009 #include <QBindable>
0010 #include <QObject>
0011 
0012 #include <qqmlregistration.h>
0013 
0014 #include "kmpris_export.h"
0015 
0016 class QDBusPendingCallWatcher;
0017 
0018 class OrgFreedesktopDBusPropertiesInterface;
0019 class OrgMprisMediaPlayer2Interface;
0020 class OrgMprisMediaPlayer2PlayerInterface;
0021 
0022 inline constexpr QLatin1String MPRIS2_PATH{"/org/mpris/MediaPlayer2"};
0023 inline constexpr QLatin1String MPRIS2_PREFIX{"org.mpris.MediaPlayer2."};
0024 
0025 namespace LoopStatus
0026 {
0027 QML_ELEMENT
0028 KMPRIS_EXPORT Q_NAMESPACE //
0029     enum KMPRIS_EXPORT Status : std::uint32_t {
0030         Unknown = 0,
0031         None,
0032         Playlist,
0033         Track,
0034     };
0035 KMPRIS_EXPORT Q_ENUM_NS(Status)
0036 }
0037 
0038 namespace ShuffleStatus
0039 {
0040 QML_ELEMENT
0041 KMPRIS_EXPORT Q_NAMESPACE //
0042     enum KMPRIS_EXPORT Status : std::uint32_t {
0043         Unknown = 0,
0044         Off,
0045         On,
0046     };
0047 KMPRIS_EXPORT Q_ENUM_NS(Status)
0048 }
0049 
0050 namespace PlaybackStatus
0051 {
0052 QML_ELEMENT
0053 KMPRIS_EXPORT Q_NAMESPACE //
0054     enum KMPRIS_EXPORT Status : std::uint32_t {
0055         Unknown = 0,
0056         Stopped,
0057         Playing,
0058         Paused,
0059     };
0060 KMPRIS_EXPORT Q_ENUM_NS(Status)
0061 }
0062 
0063 /**
0064  * A class with empty player information
0065  */
0066 class KMPRIS_EXPORT AbstractPlayerContainer : public QObject
0067 {
0068     Q_OBJECT
0069     // From org.mpris.MediaPlayer2.Player
0070     Q_PROPERTY(bool canGoNext READ canGoNext NOTIFY canGoNextChanged)
0071     Q_PROPERTY(bool canGoPrevious READ canGoPrevious NOTIFY canGoPreviousChanged)
0072     Q_PROPERTY(bool canPlay READ canPlay NOTIFY canPlayChanged)
0073     Q_PROPERTY(bool canPause READ canPause NOTIFY canPauseChanged)
0074     Q_PROPERTY(bool canStop READ canStop NOTIFY canStopChanged)
0075     Q_PROPERTY(bool canSeek READ canSeek NOTIFY canSeekChanged)
0076     Q_PROPERTY(bool canControl READ canControl NOTIFY canControlChanged)
0077     Q_PROPERTY(LoopStatus::Status loopStatus READ loopStatus NOTIFY loopStatusChanged)
0078     Q_PROPERTY(double maximumRate READ maximumRate NOTIFY maximumRateChanged)
0079     Q_PROPERTY(double minimumRate READ minimumRate NOTIFY minimumRateChanged)
0080     Q_PROPERTY(PlaybackStatus::Status playbackStatus READ playbackStatus NOTIFY playbackStatusChanged)
0081     Q_PROPERTY(qlonglong position READ position NOTIFY positionChanged)
0082     Q_PROPERTY(double rate READ rate NOTIFY rateChanged)
0083     Q_PROPERTY(ShuffleStatus::Status shuffle READ shuffle NOTIFY shuffleChanged)
0084     Q_PROPERTY(double volume READ volume NOTIFY volumeChanged)
0085 
0086     // From metadata map
0087     Q_PROPERTY(QString track READ track NOTIFY trackChanged)
0088     Q_PROPERTY(QString artist READ artist NOTIFY artistChanged)
0089     Q_PROPERTY(QString artUrl READ artUrl NOTIFY artUrlChanged)
0090     Q_PROPERTY(QString album READ album NOTIFY albumChanged)
0091     Q_PROPERTY(double length READ length NOTIFY lengthChanged)
0092 
0093     /**
0094      * Used to filter p-b-i player
0095      */
0096     Q_PROPERTY(unsigned kdePid READ kdePid NOTIFY kdePidChanged)
0097 
0098     // From org.mpris.MediaPlayer2
0099     Q_PROPERTY(bool canQuit READ canQuit NOTIFY canQuitChanged)
0100     Q_PROPERTY(bool canRaise READ canRaise NOTIFY canRaiseChanged)
0101     Q_PROPERTY(bool canSetFullscreen READ canSetFullscreen NOTIFY canSetFullscreenChanged)
0102     Q_PROPERTY(QStringList supportedMimeTypes READ supportedMimeTypes NOTIFY supportedMimeTypesChanged)
0103     Q_PROPERTY(QStringList supportedUriSchemes READ supportedUriSchemes NOTIFY supportedUriSchemesChanged)
0104     Q_PROPERTY(QString desktopEntry READ desktopEntry NOTIFY desktopEntryChanged)
0105     Q_PROPERTY(QString iconName READ iconName NOTIFY desktopEntryChanged)
0106     Q_PROPERTY(bool fullscreen READ fullscreen NOTIFY fullscreenChanged)
0107     Q_PROPERTY(bool hasTrackList READ hasTrackList NOTIFY hasTrackListChanged)
0108     Q_PROPERTY(QString identity READ identity NOTIFY identityChanged)
0109     Q_PROPERTY(unsigned instancePid READ instancePid CONSTANT)
0110 
0111 public:
0112     explicit AbstractPlayerContainer(QObject *parent = nullptr);
0113     ~AbstractPlayerContainer() override;
0114 
0115     bool canControl() const;
0116     bool canGoNext() const;
0117     bool canGoPrevious() const;
0118     bool canPause() const;
0119     bool canPlay() const;
0120     bool canStop() const;
0121     bool canSeek() const;
0122 
0123     LoopStatus::Status loopStatus() const;
0124 
0125     double maximumRate() const;
0126     double minimumRate() const;
0127     PlaybackStatus::Status playbackStatus() const;
0128 
0129     qlonglong position() const;
0130 
0131     double rate() const;
0132 
0133     ShuffleStatus::Status shuffle() const;
0134 
0135     double volume() const;
0136 
0137     QString track() const;
0138     QString artist() const;
0139     QString artUrl() const;
0140     QString album() const;
0141     double length() const;
0142 
0143     unsigned instancePid() const;
0144     unsigned kdePid() const;
0145 
0146     bool canQuit() const;
0147     bool canRaise() const;
0148     bool canSetFullscreen() const;
0149     QString desktopEntry() const;
0150     bool fullscreen() const;
0151     bool hasTrackList() const;
0152     QString identity() const;
0153     QStringList supportedMimeTypes() const;
0154     QStringList supportedUriSchemes() const;
0155     QString iconName() const;
0156 
0157 Q_SIGNALS:
0158     void canGoNextChanged();
0159     void canGoPreviousChanged();
0160     void canPlayChanged();
0161     void canPauseChanged();
0162     void canStopChanged();
0163     void canSeekChanged();
0164     void canControlChanged();
0165     void loopStatusChanged();
0166     void maximumRateChanged();
0167     void metadataChanged();
0168     void minimumRateChanged();
0169     void playbackStatusChanged();
0170     void positionChanged();
0171     void rateChanged();
0172     void shuffleChanged();
0173     void volumeChanged();
0174 
0175     void trackChanged();
0176     void artistChanged();
0177     void artUrlChanged();
0178     void albumChanged();
0179     void lengthChanged();
0180     void kdePidChanged();
0181 
0182     void canQuitChanged();
0183     void canSetFullscreenChanged();
0184     void canRaiseChanged();
0185     void supportedMimeTypesChanged();
0186     void supportedUriSchemesChanged();
0187     void desktopEntryChanged();
0188     void fullscreenChanged();
0189     void hasTrackListChanged();
0190     void identityChanged();
0191 
0192 protected:
0193     Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(AbstractPlayerContainer, bool, m_canControl, false, &AbstractPlayerContainer::canControlChanged)
0194 
0195     Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(AbstractPlayerContainer, bool, m_canGoNext, false)
0196     Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(AbstractPlayerContainer, bool, m_effectiveCanGoNext, false, &AbstractPlayerContainer::canGoNextChanged)
0197 
0198     Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(AbstractPlayerContainer, bool, m_canGoPrevious, false)
0199     Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(AbstractPlayerContainer, bool, m_effectiveCanGoPrevious, false, &AbstractPlayerContainer::canGoPreviousChanged)
0200 
0201     Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(AbstractPlayerContainer, bool, m_canPlay, false)
0202     Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(AbstractPlayerContainer, bool, m_effectiveCanPlay, false, &AbstractPlayerContainer::canPlayChanged)
0203 
0204     Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(AbstractPlayerContainer, bool, m_canPause, false)
0205     Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(AbstractPlayerContainer, bool, m_effectiveCanPause, false, &AbstractPlayerContainer::canPauseChanged)
0206 
0207     Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(AbstractPlayerContainer, bool, m_canStop, false)
0208     Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(AbstractPlayerContainer, bool, m_effectiveCanStop, false, &AbstractPlayerContainer::canStopChanged)
0209 
0210     Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(AbstractPlayerContainer, bool, m_canSeek, false, &AbstractPlayerContainer::canSeekChanged)
0211     Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(AbstractPlayerContainer, bool, m_effectiveCanSeek, false, &AbstractPlayerContainer::canSeekChanged)
0212 
0213     Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(AbstractPlayerContainer,
0214                                          LoopStatus::Status,
0215                                          m_loopStatus,
0216                                          LoopStatus::Unknown,
0217                                          &AbstractPlayerContainer::loopStatusChanged)
0218     Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(AbstractPlayerContainer,
0219                                          ShuffleStatus::Status,
0220                                          m_shuffle,
0221                                          ShuffleStatus::Unknown,
0222                                          &AbstractPlayerContainer::shuffleChanged)
0223 
0224     // From metadata
0225     Q_OBJECT_BINDABLE_PROPERTY(AbstractPlayerContainer, QString, m_trackId)
0226     Q_OBJECT_BINDABLE_PROPERTY(AbstractPlayerContainer, QString, m_xesamTitle)
0227     Q_OBJECT_BINDABLE_PROPERTY(AbstractPlayerContainer, QString, m_xesamUrl)
0228     Q_OBJECT_BINDABLE_PROPERTY(AbstractPlayerContainer, QString, m_xesamAlbum)
0229     Q_OBJECT_BINDABLE_PROPERTY(AbstractPlayerContainer, QStringList, m_xesamArtist)
0230     Q_OBJECT_BINDABLE_PROPERTY(AbstractPlayerContainer, QStringList, m_xesamAlbumArtist)
0231     Q_OBJECT_BINDABLE_PROPERTY(AbstractPlayerContainer, QString, m_track, &AbstractPlayerContainer::trackChanged)
0232     Q_OBJECT_BINDABLE_PROPERTY(AbstractPlayerContainer, QString, m_artist, &AbstractPlayerContainer::artistChanged)
0233     Q_OBJECT_BINDABLE_PROPERTY(AbstractPlayerContainer, QString, m_artUrl, &AbstractPlayerContainer::artUrlChanged)
0234     Q_OBJECT_BINDABLE_PROPERTY(AbstractPlayerContainer, QString, m_album, &AbstractPlayerContainer::albumChanged)
0235     Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(AbstractPlayerContainer, double, m_length, 0.0, &AbstractPlayerContainer::lengthChanged)
0236 
0237     Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(AbstractPlayerContainer, double, m_minimumRate, 0.0, &AbstractPlayerContainer::minimumRateChanged)
0238     Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(AbstractPlayerContainer, double, m_maximumRate, 0.0, &AbstractPlayerContainer::maximumRateChanged)
0239     Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(AbstractPlayerContainer,
0240                                          PlaybackStatus::Status,
0241                                          m_playbackStatus,
0242                                          PlaybackStatus::Unknown,
0243                                          &AbstractPlayerContainer::playbackStatusChanged)
0244     Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(AbstractPlayerContainer, qlonglong, m_position, 0, &AbstractPlayerContainer::positionChanged)
0245     Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(AbstractPlayerContainer, double, m_rate, 1.0, &AbstractPlayerContainer::rateChanged)
0246     Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(AbstractPlayerContainer, double, m_volume, 0.0, &AbstractPlayerContainer::volumeChanged)
0247 
0248     Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(AbstractPlayerContainer, bool, m_canQuit, false, &AbstractPlayerContainer::canQuitChanged)
0249     Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(AbstractPlayerContainer, bool, m_canRaise, false, &AbstractPlayerContainer::canRaiseChanged)
0250     Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(AbstractPlayerContainer, bool, m_canSetFullscreen, false, &AbstractPlayerContainer::canSetFullscreenChanged)
0251     QStringList m_supportedMimeTypes;
0252     QStringList m_supportedUriSchemes;
0253     QString m_desktopEntry;
0254     Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(AbstractPlayerContainer, bool, m_fullscreen, false, &AbstractPlayerContainer::fullscreenChanged)
0255     Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(AbstractPlayerContainer, bool, m_hasTrackList, false, &AbstractPlayerContainer::hasTrackListChanged)
0256     QString m_identity;
0257 
0258     QString m_iconName;
0259     unsigned m_instancePid = 0;
0260     Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(AbstractPlayerContainer, unsigned, m_kdePid, 0, &AbstractPlayerContainer::kdePidChanged)
0261 };
0262 
0263 /**
0264  * A proxy class for the 3 MPRIS2 D-Bus interfaces
0265  */
0266 class KMPRIS_EXPORT PlayerContainer : public AbstractPlayerContainer
0267 {
0268     Q_OBJECT
0269     QML_ANONYMOUS
0270 
0271     Q_PROPERTY(LoopStatus::Status loopStatus READ loopStatus WRITE setLoopStatus NOTIFY loopStatusChanged)
0272     Q_PROPERTY(qlonglong position READ position WRITE setPosition NOTIFY positionChanged)
0273     Q_PROPERTY(double rate READ rate WRITE setRate NOTIFY rateChanged)
0274     Q_PROPERTY(ShuffleStatus::Status shuffle READ shuffle WRITE setShuffle NOTIFY shuffleChanged)
0275     Q_PROPERTY(double volume READ volume WRITE setVolume NOTIFY volumeChanged)
0276     Q_PROPERTY(bool fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged)
0277     Q_PROPERTY(PlaybackStatus::Status playbackStatus READ playbackStatus WRITE setPlaybackStatus NOTIFY playbackStatusChanged)
0278 
0279 public:
0280     explicit PlayerContainer(const QString &busAddress, QObject *parent = nullptr);
0281     ~PlayerContainer() override;
0282 
0283     QString dbusAddress() const
0284     {
0285         return m_dbusAddress;
0286     }
0287 
0288     void setLoopStatus(LoopStatus::Status value);
0289     void setPosition(qlonglong value);
0290     void setRate(double value);
0291     void setShuffle(ShuffleStatus::Status value);
0292     void setVolume(double value);
0293     void setFullscreen(bool value);
0294     void setPlaybackStatus(PlaybackStatus::Status value);
0295 
0296     Q_INVOKABLE void Next();
0297     Q_INVOKABLE void OpenUri(const QString &Uri);
0298     Q_INVOKABLE void Pause();
0299     Q_INVOKABLE void Play();
0300     Q_INVOKABLE void PlayPause();
0301     Q_INVOKABLE void Previous();
0302     Q_INVOKABLE void Seek(qlonglong Offset);
0303     Q_INVOKABLE void Stop();
0304     Q_INVOKABLE void Quit();
0305     Q_INVOKABLE void Raise();
0306 
0307     void refresh();
0308 
0309     Q_INVOKABLE void updatePosition();
0310     Q_INVOKABLE void changeVolume(double delta, bool showOSD);
0311 
0312 Q_SIGNALS:
0313     void initialFetchFinished(PlayerContainer *container);
0314     void initialFetchFailed(PlayerContainer *container);
0315 
0316 private Q_SLOTS:
0317     void onGetPropsFinished(QDBusPendingCallWatcher *watcher);
0318     void onPropertiesChanged(const QString &interface, const QVariantMap &changedProperties, const QStringList &invalidatedProperties);
0319     void onSeeked(qlonglong position);
0320 
0321 private:
0322     void initBindings();
0323     void updateFromMap(const QVariantMap &map);
0324 
0325     int m_fetchesPending = 0;
0326     QString m_dbusAddress;
0327     OrgFreedesktopDBusPropertiesInterface *m_propsIface = nullptr;
0328     OrgMprisMediaPlayer2PlayerInterface *m_playerIface = nullptr;
0329     OrgMprisMediaPlayer2Interface *m_rootIface = nullptr;
0330 
0331     QPropertyNotifier m_rateNotifier;
0332     QPropertyNotifier m_playbackStatusNotifier;
0333 };