mirror of https://github.com/KDE/kasts.git
Initial copy and adaptation of MPRIS2 from elisa (WIP)
This MPRIS2 implementation compiles without errors, but is not yet instantiated within the application itself. To be continued...
This commit is contained in:
parent
7e39d83f90
commit
593934bc4f
|
@ -13,6 +13,9 @@ add_executable(alligator
|
|||
datamanager.cpp
|
||||
audiomanager.cpp
|
||||
powermanagementinterface.cpp
|
||||
mpris2/mpris2.cpp
|
||||
mpris2/mediaplayer2.cpp
|
||||
mpris2/mediaplayer2player.cpp
|
||||
resources.qrc
|
||||
)
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ AudioManager::AudioManager(QObject *parent) : QObject(parent), d(std::make_uniqu
|
|||
{
|
||||
connect(&d->m_player, &QMediaPlayer::mutedChanged, this, &AudioManager::playerMutedChanged);
|
||||
connect(&d->m_player, &QMediaPlayer::volumeChanged, this, &AudioManager::playerVolumeChanged);
|
||||
//connect(&d->m_player, &QMediaPlayer::mediaChanged, this, &AudioManager::sourceChanged);
|
||||
connect(&d->m_player, &QMediaPlayer::mediaChanged, this, &AudioManager::sourceChanged);
|
||||
connect(&d->m_player, &QMediaPlayer::mediaStatusChanged, this, &AudioManager::statusChanged);
|
||||
connect(&d->m_player, &QMediaPlayer::mediaStatusChanged, this, &AudioManager::mediaStatusChanged);
|
||||
connect(&d->m_player, &QMediaPlayer::stateChanged, this, &AudioManager::playbackStateChanged);
|
||||
|
@ -50,8 +50,6 @@ AudioManager::AudioManager(QObject *parent) : QObject(parent), d(std::make_uniqu
|
|||
// Check if an entry was playing when the program was shut down and restore it
|
||||
if (SettingsManager::self()->lastPlayingEntry() != QStringLiteral("none"))
|
||||
setEntry(DataManager::instance().getEntry(SettingsManager::self()->lastPlayingEntry()));
|
||||
//SettingsManager.lastPlayingEntry !== "none" ? DataManager.getEntry(SettingsManager.lastPlayingEntry) : undefined
|
||||
|
||||
}
|
||||
|
||||
AudioManager::~AudioManager()
|
||||
|
@ -82,12 +80,10 @@ qreal AudioManager::volume() const
|
|||
return userVolume * 100.0;
|
||||
}
|
||||
|
||||
/*
|
||||
QUrl AudioManager::source() const
|
||||
{
|
||||
return d->m_player.media().request().url();
|
||||
}
|
||||
*/
|
||||
|
||||
QMediaPlayer::Error AudioManager::error() const
|
||||
{
|
||||
|
@ -113,6 +109,11 @@ bool AudioManager::seekable() const
|
|||
return d->m_player.isSeekable();
|
||||
}
|
||||
|
||||
bool AudioManager::canPlay() const
|
||||
{
|
||||
return (d->m_entry != nullptr);
|
||||
}
|
||||
|
||||
QMediaPlayer::State AudioManager::playbackState() const
|
||||
{
|
||||
return d->m_player.state();
|
||||
|
@ -161,6 +162,7 @@ void AudioManager::setEntry(Entry* entry)
|
|||
d->m_player.pause();
|
||||
d->lockPositionSaving = false;
|
||||
Q_EMIT entryChanged(entry);
|
||||
Q_EMIT playerCanPlayChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -234,6 +236,17 @@ void AudioManager::seek(qint64 position)
|
|||
d->m_player.setPosition(position);
|
||||
}
|
||||
|
||||
void AudioManager::next()
|
||||
{
|
||||
qDebug() << "Skip to next track";
|
||||
// TODO: to be implemented
|
||||
}
|
||||
|
||||
void AudioManager::previous()
|
||||
{
|
||||
qDebug() << "Back to previous track";
|
||||
// TODO: to be implemented
|
||||
}
|
||||
void AudioManager::mediaStatusChanged()
|
||||
{
|
||||
qDebug() << "AudioManager::mediaStatusChanged" << d->m_player.mediaStatus();
|
||||
|
|
|
@ -97,7 +97,7 @@ public:
|
|||
|
||||
[[nodiscard]] qreal volume() const;
|
||||
|
||||
//[[nodiscard]] QUrl source() const;
|
||||
[[nodiscard]] QUrl source() const;
|
||||
|
||||
[[nodiscard]] QMediaPlayer::MediaStatus status() const;
|
||||
|
||||
|
@ -113,6 +113,8 @@ public:
|
|||
|
||||
[[nodiscard]] bool seekable() const;
|
||||
|
||||
[[nodiscard]] bool canPlay() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
|
||||
void playerOpenChanged(bool state);
|
||||
|
@ -123,7 +125,7 @@ Q_SIGNALS:
|
|||
|
||||
void volumeChanged();
|
||||
|
||||
//void sourceChanged();
|
||||
void sourceChanged();
|
||||
|
||||
void statusChanged(QMediaPlayer::MediaStatus status);
|
||||
|
||||
|
@ -145,6 +147,8 @@ Q_SIGNALS:
|
|||
|
||||
void stopped();
|
||||
|
||||
void playerCanPlayChanged();
|
||||
|
||||
public Q_SLOTS:
|
||||
|
||||
void setEntry(Entry* entry);
|
||||
|
@ -155,7 +159,7 @@ public Q_SLOTS:
|
|||
|
||||
void setVolume(qreal volume);
|
||||
|
||||
//void setSource(const QUrl &source);
|
||||
//void setSource(const QUrl &source); //source should only be set by audiomanager itself
|
||||
|
||||
void setPosition(qint64 position);
|
||||
|
||||
|
@ -169,6 +173,10 @@ public Q_SLOTS:
|
|||
|
||||
void seek(qint64 position);
|
||||
|
||||
void previous(); //TODO: implement canPrevious and canNext member functions and re-use them in MPRIS and playercontrol
|
||||
|
||||
void next();
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
void mediaStatusChanged();
|
||||
|
|
|
@ -285,6 +285,11 @@ int DataManager::queueCount() const
|
|||
return m_queuemap.count();
|
||||
}
|
||||
|
||||
QStringList DataManager::getQueue() const
|
||||
{
|
||||
return m_queuemap;
|
||||
}
|
||||
|
||||
bool DataManager::entryInQueue(const QString &feedurl, const QString &id) const
|
||||
{
|
||||
Q_UNUSED(feedurl);
|
||||
|
|
|
@ -40,6 +40,7 @@ public:
|
|||
|
||||
Entry* getQueueEntry(int const &index) const;
|
||||
int queueCount() const;
|
||||
QStringList getQueue() const;
|
||||
Q_INVOKABLE bool entryInQueue(const QString &feedurl, const QString &id) const;
|
||||
Q_INVOKABLE void addtoQueue(const QString &feedurl, const QString &id);
|
||||
Q_INVOKABLE void moveQueueItem(const int &from, const int &to);
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2014 (c) Sujith Haridasan <sujith.haridasan@kdemail.net>
|
||||
* SPDX-FileCopyrightText: 2014 (c) Ashish Madeti <ashishmadeti@gmail.com>
|
||||
* SPDX-FileCopyrightText: 2016 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "mediaplayer2.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include <KCoreAddons/KAboutData>
|
||||
|
||||
MediaPlayer2::MediaPlayer2(QObject* parent)
|
||||
: QDBusAbstractAdaptor(parent)
|
||||
{
|
||||
}
|
||||
|
||||
MediaPlayer2::~MediaPlayer2()
|
||||
= default;
|
||||
|
||||
bool MediaPlayer2::CanQuit() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MediaPlayer2::CanRaise() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool MediaPlayer2::HasTrackList() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void MediaPlayer2::Quit()
|
||||
{
|
||||
QCoreApplication::quit();
|
||||
}
|
||||
|
||||
void MediaPlayer2::Raise()
|
||||
{
|
||||
emit raisePlayer();
|
||||
}
|
||||
|
||||
QString MediaPlayer2::Identity() const
|
||||
{
|
||||
return KAboutData::applicationData().displayName();
|
||||
}
|
||||
|
||||
QString MediaPlayer2::DesktopEntry() const
|
||||
{
|
||||
return KAboutData::applicationData().desktopFileName();
|
||||
}
|
||||
|
||||
QStringList MediaPlayer2::SupportedUriSchemes() const
|
||||
{
|
||||
return QStringList() << QStringLiteral("file");
|
||||
}
|
||||
|
||||
QStringList MediaPlayer2::SupportedMimeTypes() const
|
||||
{
|
||||
// KService::Ptr app = KService::serviceByDesktopName(KCmdLineArgs::aboutData()->appName());
|
||||
|
||||
// if (app) {
|
||||
// return app->mimeTypes();
|
||||
// }
|
||||
|
||||
return QStringList();
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2014 (c) Sujith Haridasan <sujith.haridasan@kdemail.net>
|
||||
* SPDX-FileCopyrightText: 2014 (c) Ashish Madeti <ashishmadeti@gmail.com>
|
||||
* SPDX-FileCopyrightText: 2016 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDBusAbstractAdaptor>
|
||||
#include <QStringList>
|
||||
|
||||
|
||||
class MediaPlayer2 : public QDBusAbstractAdaptor
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_CLASSINFO("D-Bus Interface", "org.mpris.MediaPlayer2") // Docs: https://specifications.freedesktop.org/mpris-spec/latest/Media_Player.html
|
||||
|
||||
Q_PROPERTY(bool CanQuit READ CanQuit CONSTANT)
|
||||
Q_PROPERTY(bool CanRaise READ CanRaise CONSTANT)
|
||||
Q_PROPERTY(bool HasTrackList READ HasTrackList CONSTANT)
|
||||
|
||||
Q_PROPERTY(QString Identity READ Identity CONSTANT)
|
||||
Q_PROPERTY(QString DesktopEntry READ DesktopEntry CONSTANT)
|
||||
|
||||
Q_PROPERTY(QStringList SupportedUriSchemes READ SupportedUriSchemes CONSTANT)
|
||||
Q_PROPERTY(QStringList SupportedMimeTypes READ SupportedMimeTypes CONSTANT)
|
||||
|
||||
public:
|
||||
explicit MediaPlayer2(QObject* parent = nullptr);
|
||||
~MediaPlayer2() override;
|
||||
|
||||
[[nodiscard]] bool CanQuit() const;
|
||||
[[nodiscard]] bool CanRaise() const;
|
||||
[[nodiscard]] bool HasTrackList() const;
|
||||
|
||||
[[nodiscard]] QString Identity() const;
|
||||
[[nodiscard]] QString DesktopEntry() const;
|
||||
|
||||
[[nodiscard]] QStringList SupportedUriSchemes() const;
|
||||
[[nodiscard]] QStringList SupportedMimeTypes() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void Quit();
|
||||
void Raise();
|
||||
|
||||
Q_SIGNALS:
|
||||
void raisePlayer();
|
||||
|
||||
};
|
|
@ -0,0 +1,456 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2014 (c) Sujith Haridasan <sujith.haridasan@kdemail.net>
|
||||
* SPDX-FileCopyrightText: 2014 (c) Ashish Madeti <ashishmadeti@gmail.com>
|
||||
* SPDX-FileCopyrightText: 2016 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "mediaplayer2player.h"
|
||||
#include "mpris2.h"
|
||||
|
||||
#include "fetcher.h"
|
||||
#include "datamanager.h"
|
||||
#include "audiomanager.h"
|
||||
|
||||
#if defined KF5FileMetaData_FOUND && KF5FileMetaData_FOUND
|
||||
#include <KFileMetaData/EmbeddedImageData>
|
||||
#endif
|
||||
|
||||
#include <QCryptographicHash>
|
||||
#include <QStringList>
|
||||
#include <QDBusMessage>
|
||||
#include <QDBusConnection>
|
||||
|
||||
|
||||
static const double MAX_RATE = 1.0;
|
||||
static const double MIN_RATE = 1.0;
|
||||
|
||||
MediaPlayer2Player::MediaPlayer2Player(AudioManager *audioPlayer, bool showProgressOnTaskBar, QObject* parent)
|
||||
: QDBusAbstractAdaptor(parent), m_audioPlayer(audioPlayer),
|
||||
mProgressIndicatorSignal(QDBusMessage::createSignal(QStringLiteral("/org/kde/alligator"),
|
||||
QStringLiteral("com.canonical.Unity.LauncherEntry"),
|
||||
QStringLiteral("Update"))),
|
||||
mShowProgressOnTaskBar(showProgressOnTaskBar)
|
||||
{
|
||||
connect(m_audioPlayer, &AudioManager::sourceChanged,
|
||||
this, &MediaPlayer2Player::playerSourceChanged, Qt::QueuedConnection);
|
||||
connect(m_audioPlayer, &AudioManager::playerCanPlayChanged,
|
||||
this, &MediaPlayer2Player::playControlEnabledChanged);
|
||||
connect(m_audioPlayer, &AudioManager::sourceChanged,
|
||||
this, &MediaPlayer2Player::skipBackwardControlEnabledChanged);
|
||||
connect(m_audioPlayer, &AudioManager::sourceChanged,
|
||||
this, &MediaPlayer2Player::skipForwardControlEnabledChanged);
|
||||
connect(m_audioPlayer, &AudioManager::playbackStateChanged,
|
||||
this, &MediaPlayer2Player::playerPlaybackStateChanged);
|
||||
connect(m_audioPlayer, &AudioManager::seekableChanged,
|
||||
this, &MediaPlayer2Player::playerIsSeekableChanged);
|
||||
connect(m_audioPlayer, &AudioManager::positionChanged,
|
||||
this, &MediaPlayer2Player::audioPositionChanged);
|
||||
connect(m_audioPlayer, &AudioManager::seek,
|
||||
this, &MediaPlayer2Player::playerSeeked);
|
||||
connect(m_audioPlayer, &AudioManager::durationChanged,
|
||||
this, &MediaPlayer2Player::audioDurationChanged);
|
||||
connect(m_audioPlayer, &AudioManager::volumeChanged,
|
||||
this, &MediaPlayer2Player::playerVolumeChanged);
|
||||
|
||||
m_volume = m_audioPlayer->volume() / 100;
|
||||
m_canPlay = m_audioPlayer->canPlay();
|
||||
signalPropertiesChange(QStringLiteral("Volume"), Volume());
|
||||
|
||||
m_mediaPlayerPresent = 1;
|
||||
}
|
||||
|
||||
MediaPlayer2Player::~MediaPlayer2Player()
|
||||
= default;
|
||||
|
||||
QString MediaPlayer2Player::PlaybackStatus() const
|
||||
{
|
||||
QString result;
|
||||
|
||||
if (m_audioPlayer->playbackState() == QMediaPlayer::StoppedState) {
|
||||
result = QStringLiteral("Stopped");
|
||||
} else if (m_audioPlayer->playbackState() == QMediaPlayer::PlayingState) {
|
||||
result = QStringLiteral("Playing");
|
||||
} else {
|
||||
result = QStringLiteral("Paused");
|
||||
}
|
||||
|
||||
if (mShowProgressOnTaskBar) {
|
||||
QVariantMap parameters;
|
||||
|
||||
if (m_audioPlayer->playbackState() == QMediaPlayer::StoppedState || m_audioPlayer->duration() == 0) {
|
||||
parameters.insert(QStringLiteral("progress-visible"), false);
|
||||
parameters.insert(QStringLiteral("progress"), 0);
|
||||
} else {
|
||||
parameters.insert(QStringLiteral("progress-visible"), true);
|
||||
parameters.insert(QStringLiteral("progress"), qRound(static_cast<double>(m_position / m_audioPlayer->duration())) / 1000.0);
|
||||
}
|
||||
|
||||
mProgressIndicatorSignal.setArguments({QStringLiteral("application://org.kde.alligator.desktop"), parameters});
|
||||
|
||||
QDBusConnection::sessionBus().send(mProgressIndicatorSignal);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool MediaPlayer2Player::CanGoNext() const
|
||||
{
|
||||
return m_canGoNext;
|
||||
}
|
||||
|
||||
void MediaPlayer2Player::Next()
|
||||
{
|
||||
emit next();
|
||||
|
||||
if (m_audioPlayer) {
|
||||
m_audioPlayer->next();
|
||||
}
|
||||
}
|
||||
|
||||
bool MediaPlayer2Player::CanGoPrevious() const
|
||||
{
|
||||
return m_canGoPrevious;
|
||||
}
|
||||
|
||||
|
||||
void MediaPlayer2Player::Previous()
|
||||
{
|
||||
// not implemented
|
||||
}
|
||||
|
||||
bool MediaPlayer2Player::CanPause() const
|
||||
{
|
||||
return m_canPlay;
|
||||
}
|
||||
|
||||
void MediaPlayer2Player::Pause()
|
||||
{
|
||||
if (m_audioPlayer) {
|
||||
m_audioPlayer->pause();
|
||||
}
|
||||
}
|
||||
|
||||
void MediaPlayer2Player::PlayPause()
|
||||
{
|
||||
emit playPause();
|
||||
|
||||
if (m_audioPlayer) {
|
||||
if (m_audioPlayer->playbackState() == QMediaPlayer::State::PausedState)
|
||||
m_audioPlayer->play();
|
||||
else if (m_audioPlayer->playbackState() == QMediaPlayer::State::PlayingState)
|
||||
m_audioPlayer->pause();
|
||||
}
|
||||
}
|
||||
|
||||
void MediaPlayer2Player::Stop()
|
||||
{
|
||||
emit stop();
|
||||
|
||||
// we actually don't really want to stop, because that would reset the player
|
||||
// position, so we pause instead
|
||||
if (m_audioPlayer) {
|
||||
m_audioPlayer->pause();
|
||||
}
|
||||
}
|
||||
|
||||
bool MediaPlayer2Player::CanPlay() const
|
||||
{
|
||||
return m_canPlay;
|
||||
}
|
||||
|
||||
void MediaPlayer2Player::Play()
|
||||
{
|
||||
if (m_audioPlayer) {
|
||||
m_audioPlayer->play();
|
||||
}
|
||||
}
|
||||
|
||||
double MediaPlayer2Player::Volume() const
|
||||
{
|
||||
return m_volume;
|
||||
}
|
||||
|
||||
void MediaPlayer2Player::setVolume(double volume)
|
||||
{
|
||||
m_volume= qBound(0.0, volume, 1.0);
|
||||
emit volumeChanged(m_volume);
|
||||
|
||||
m_audioPlayer->setVolume(100 * m_volume);
|
||||
|
||||
signalPropertiesChange(QStringLiteral("Volume"), Volume());
|
||||
}
|
||||
|
||||
QVariantMap MediaPlayer2Player::Metadata() const
|
||||
{
|
||||
return m_metadata;
|
||||
}
|
||||
|
||||
qlonglong MediaPlayer2Player::Position() const
|
||||
{
|
||||
return m_position;
|
||||
}
|
||||
|
||||
void MediaPlayer2Player::setPropertyPosition(int newPositionInMs)
|
||||
{
|
||||
m_position = qlonglong(newPositionInMs) * 1000;
|
||||
|
||||
/* only send new progress when it has advanced more than 1 %
|
||||
* to limit DBus traffic
|
||||
*/
|
||||
const auto incrementalProgress = static_cast<double>(newPositionInMs - mPreviousProgressPosition) / m_audioPlayer->duration();
|
||||
if (mShowProgressOnTaskBar && (incrementalProgress > 0.01 || incrementalProgress < 0))
|
||||
{
|
||||
mPreviousProgressPosition = newPositionInMs;
|
||||
QVariantMap parameters;
|
||||
parameters.insert(QStringLiteral("progress-visible"), true);
|
||||
parameters.insert(QStringLiteral("progress"), static_cast<double>(newPositionInMs) / m_audioPlayer->duration());
|
||||
|
||||
mProgressIndicatorSignal.setArguments({QStringLiteral("application://org.kde.alligator.desktop"), parameters});
|
||||
|
||||
QDBusConnection::sessionBus().send(mProgressIndicatorSignal);
|
||||
}
|
||||
}
|
||||
|
||||
double MediaPlayer2Player::Rate() const
|
||||
{
|
||||
return m_rate;
|
||||
}
|
||||
|
||||
void MediaPlayer2Player::setRate(double newRate)
|
||||
{
|
||||
if (newRate <= 0.0001 && newRate >= -0.0001) {
|
||||
Pause();
|
||||
} else {
|
||||
m_rate = qBound(MinimumRate(), newRate, MaximumRate());
|
||||
emit rateChanged(m_rate);
|
||||
|
||||
signalPropertiesChange(QStringLiteral("Rate"), Rate());
|
||||
}
|
||||
}
|
||||
|
||||
double MediaPlayer2Player::MinimumRate() const
|
||||
{
|
||||
return MIN_RATE;
|
||||
}
|
||||
|
||||
double MediaPlayer2Player::MaximumRate() const
|
||||
{
|
||||
return MAX_RATE;
|
||||
}
|
||||
|
||||
bool MediaPlayer2Player::CanSeek() const
|
||||
{
|
||||
return m_playerIsSeekableChanged;
|
||||
}
|
||||
|
||||
bool MediaPlayer2Player::CanControl() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void MediaPlayer2Player::Seek(qlonglong Offset)
|
||||
{
|
||||
if (mediaPlayerPresent()) {
|
||||
auto offset = (m_position + Offset) / 1000;
|
||||
m_audioPlayer->seek(int(offset));
|
||||
}
|
||||
}
|
||||
|
||||
void MediaPlayer2Player::SetPosition(const QDBusObjectPath &trackId, qlonglong pos)
|
||||
{
|
||||
if (trackId.path() == m_currentTrackId) {
|
||||
m_audioPlayer->seek(int(pos / 1000));
|
||||
}
|
||||
}
|
||||
|
||||
void MediaPlayer2Player::OpenUri(const QString &uri)
|
||||
{
|
||||
Q_UNUSED(uri);
|
||||
}
|
||||
|
||||
void MediaPlayer2Player::playerSourceChanged()
|
||||
{
|
||||
// TODO: do we need to implement this??
|
||||
//setCurrentTrack(m_audioPlayer->playListPosition());
|
||||
}
|
||||
|
||||
void MediaPlayer2Player::playControlEnabledChanged()
|
||||
{
|
||||
m_canPlay = m_audioPlayer->canPlay();
|
||||
|
||||
signalPropertiesChange(QStringLiteral("CanPause"), CanPause());
|
||||
signalPropertiesChange(QStringLiteral("CanPlay"), CanPlay());
|
||||
|
||||
emit canPauseChanged();
|
||||
emit canPlayChanged();
|
||||
}
|
||||
|
||||
void MediaPlayer2Player::skipBackwardControlEnabledChanged()
|
||||
{
|
||||
m_canGoPrevious = (DataManager::instance().getQueue().indexOf(m_audioPlayer->entry()->id()) > 0);
|
||||
|
||||
signalPropertiesChange(QStringLiteral("CanGoPrevious"), CanGoPrevious());
|
||||
emit canGoPreviousChanged();
|
||||
}
|
||||
|
||||
void MediaPlayer2Player::skipForwardControlEnabledChanged()
|
||||
{
|
||||
m_canGoNext = (DataManager::instance().getQueue().indexOf(m_audioPlayer->entry()->id()) < DataManager::instance().getQueue().count());
|
||||
|
||||
signalPropertiesChange(QStringLiteral("CanGoNext"), CanGoNext());
|
||||
emit canGoNextChanged();
|
||||
}
|
||||
|
||||
void MediaPlayer2Player::playerPlaybackStateChanged()
|
||||
{
|
||||
signalPropertiesChange(QStringLiteral("PlaybackStatus"), PlaybackStatus());
|
||||
emit playbackStatusChanged();
|
||||
|
||||
playerIsSeekableChanged();
|
||||
}
|
||||
|
||||
void MediaPlayer2Player::playerIsSeekableChanged()
|
||||
{
|
||||
m_playerIsSeekableChanged = m_audioPlayer->seekable();
|
||||
|
||||
signalPropertiesChange(QStringLiteral("CanSeek"), CanSeek());
|
||||
emit canSeekChanged();
|
||||
}
|
||||
|
||||
void MediaPlayer2Player::audioPositionChanged()
|
||||
{
|
||||
setPropertyPosition(static_cast<int>(m_audioPlayer->position()));
|
||||
}
|
||||
|
||||
void MediaPlayer2Player::playerSeeked(qint64 position)
|
||||
{
|
||||
Q_EMIT Seeked(position * 1000);
|
||||
}
|
||||
|
||||
void MediaPlayer2Player::audioDurationChanged()
|
||||
{
|
||||
m_metadata = getMetadataOfCurrentTrack();
|
||||
signalPropertiesChange(QStringLiteral("Metadata"), Metadata());
|
||||
|
||||
skipBackwardControlEnabledChanged();
|
||||
skipForwardControlEnabledChanged();
|
||||
playerPlaybackStateChanged();
|
||||
playerIsSeekableChanged();
|
||||
setPropertyPosition(static_cast<int>(m_audioPlayer->position()));
|
||||
}
|
||||
|
||||
void MediaPlayer2Player::playerVolumeChanged()
|
||||
{
|
||||
setVolume(m_audioPlayer->volume() / 100.0);
|
||||
}
|
||||
|
||||
int MediaPlayer2Player::currentTrack() const
|
||||
{
|
||||
return DataManager::instance().getQueue().indexOf(m_audioPlayer->entry()->id());
|
||||
}
|
||||
|
||||
void MediaPlayer2Player::setCurrentTrack(int newTrackPosition)
|
||||
{
|
||||
m_currentTrack = m_audioPlayer->entry()->title();
|
||||
m_currentTrackId = QDBusObjectPath(QLatin1String("/org/kde/alligator/playlist/") + QString::number(newTrackPosition)).path();
|
||||
|
||||
emit currentTrackChanged();
|
||||
|
||||
m_metadata = getMetadataOfCurrentTrack();
|
||||
signalPropertiesChange(QStringLiteral("Metadata"), Metadata());
|
||||
}
|
||||
|
||||
QVariantMap MediaPlayer2Player::getMetadataOfCurrentTrack()
|
||||
{
|
||||
auto result = QVariantMap();
|
||||
|
||||
if (m_currentTrackId.isEmpty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
Entry* entry = m_audioPlayer->entry();
|
||||
|
||||
result[QStringLiteral("mpris:trackid")] = QVariant::fromValue<QDBusObjectPath>(QDBusObjectPath(m_currentTrackId));
|
||||
result[QStringLiteral("mpris:length")] = qlonglong(m_audioPlayer->duration()) * 1000;
|
||||
//convert milli-seconds into micro-seconds
|
||||
if (!entry->title().isEmpty()) {
|
||||
result[QStringLiteral("xesam:title")] = entry->title();
|
||||
}
|
||||
result[QStringLiteral("xesam:url")] = entry->enclosure()->path();
|
||||
if (!entry->feed()->name().isEmpty()) {
|
||||
result[QStringLiteral("xesam:album")] = entry->feed()->name();
|
||||
}
|
||||
if (entry->authors().count() > 0) {
|
||||
QStringList authors;
|
||||
for (auto &author : entry->authors()) authors.append(author->name());
|
||||
result[QStringLiteral("xesam:artist")] = authors;
|
||||
}
|
||||
if (!entry->image().isEmpty()) {
|
||||
result[QStringLiteral("mpris:artUrl")] = Fetcher::instance().imagePath(entry->image());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int MediaPlayer2Player::mediaPlayerPresent() const
|
||||
{
|
||||
return m_mediaPlayerPresent;
|
||||
}
|
||||
|
||||
bool MediaPlayer2Player::showProgressOnTaskBar() const
|
||||
{
|
||||
return mShowProgressOnTaskBar;
|
||||
}
|
||||
|
||||
void MediaPlayer2Player::setShowProgressOnTaskBar(bool value)
|
||||
{
|
||||
mShowProgressOnTaskBar = value;
|
||||
|
||||
QVariantMap parameters;
|
||||
|
||||
if (!mShowProgressOnTaskBar || m_audioPlayer->playbackState() == QMediaPlayer::StoppedState || m_audioPlayer->duration() == 0) {
|
||||
parameters.insert(QStringLiteral("progress-visible"), false);
|
||||
parameters.insert(QStringLiteral("progress"), 0);
|
||||
} else {
|
||||
parameters.insert(QStringLiteral("progress-visible"), true);
|
||||
parameters.insert(QStringLiteral("progress"), qRound(static_cast<double>(m_position / m_audioPlayer->duration())) / 1000.0);
|
||||
}
|
||||
|
||||
mProgressIndicatorSignal.setArguments({QStringLiteral("application://org.kde.alligator.desktop"), parameters});
|
||||
|
||||
QDBusConnection::sessionBus().send(mProgressIndicatorSignal);
|
||||
}
|
||||
|
||||
void MediaPlayer2Player::setMediaPlayerPresent(int status)
|
||||
{
|
||||
if (m_mediaPlayerPresent != status) {
|
||||
m_mediaPlayerPresent = status;
|
||||
emit mediaPlayerPresentChanged();
|
||||
|
||||
signalPropertiesChange(QStringLiteral("CanGoNext"), CanGoNext());
|
||||
signalPropertiesChange(QStringLiteral("CanGoPrevious"), CanGoPrevious());
|
||||
signalPropertiesChange(QStringLiteral("CanPause"), CanPause());
|
||||
signalPropertiesChange(QStringLiteral("CanPlay"), CanPlay());
|
||||
emit canGoNextChanged();
|
||||
emit canGoPreviousChanged();
|
||||
emit canPauseChanged();
|
||||
emit canPlayChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void MediaPlayer2Player::signalPropertiesChange(const QString &property, const QVariant &value)
|
||||
{
|
||||
QVariantMap properties;
|
||||
properties[property] = value;
|
||||
const int ifaceIndex = metaObject()->indexOfClassInfo("D-Bus Interface");
|
||||
QDBusMessage msg = QDBusMessage::createSignal(QStringLiteral("/org/mpris/MediaPlayer2"),
|
||||
QStringLiteral("org.freedesktop.DBus.Properties"), QStringLiteral("PropertiesChanged"));
|
||||
|
||||
msg << QLatin1String(metaObject()->classInfo(ifaceIndex).value());
|
||||
msg << properties;
|
||||
msg << QStringList();
|
||||
|
||||
QDBusConnection::sessionBus().send(msg);
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2014 (c) Sujith Haridasan <sujith.haridasan@kdemail.net>
|
||||
* SPDX-FileCopyrightText: 2014 (c) Ashish Madeti <ashishmadeti@gmail.com>
|
||||
* SPDX-FileCopyrightText: 2016 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDBusAbstractAdaptor>
|
||||
#include <QDBusObjectPath>
|
||||
#include <QDBusMessage>
|
||||
|
||||
class AudioManager;
|
||||
|
||||
class MediaPlayer2Player : public QDBusAbstractAdaptor
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_CLASSINFO("D-Bus Interface", "org.mpris.MediaPlayer2.Player") // Docs: https://specifications.freedesktop.org/mpris-spec/latest/Player_Interface.html
|
||||
|
||||
Q_PROPERTY(QString PlaybackStatus READ PlaybackStatus NOTIFY playbackStatusChanged)
|
||||
Q_PROPERTY(double Rate READ Rate WRITE setRate NOTIFY rateChanged)
|
||||
Q_PROPERTY(QVariantMap Metadata READ Metadata NOTIFY playbackStatusChanged)
|
||||
Q_PROPERTY(double Volume READ Volume WRITE setVolume NOTIFY volumeChanged)
|
||||
Q_PROPERTY(qlonglong Position READ Position WRITE setPropertyPosition NOTIFY playbackStatusChanged)
|
||||
Q_PROPERTY(double MinimumRate READ MinimumRate CONSTANT)
|
||||
Q_PROPERTY(double MaximumRate READ MaximumRate CONSTANT)
|
||||
Q_PROPERTY(bool CanGoNext READ CanGoNext NOTIFY canGoNextChanged)
|
||||
Q_PROPERTY(bool CanGoPrevious READ CanGoPrevious NOTIFY canGoPreviousChanged)
|
||||
Q_PROPERTY(bool CanPlay READ CanPlay NOTIFY canPlayChanged)
|
||||
Q_PROPERTY(bool CanPause READ CanPause NOTIFY canPauseChanged)
|
||||
Q_PROPERTY(bool CanControl READ CanControl NOTIFY canControlChanged)
|
||||
Q_PROPERTY(bool CanSeek READ CanSeek NOTIFY canSeekChanged)
|
||||
Q_PROPERTY(int currentTrack READ currentTrack WRITE setCurrentTrack NOTIFY currentTrackChanged)
|
||||
Q_PROPERTY(int mediaPlayerPresent READ mediaPlayerPresent WRITE setMediaPlayerPresent NOTIFY mediaPlayerPresentChanged)
|
||||
|
||||
public:
|
||||
explicit MediaPlayer2Player(AudioManager *audioPlayer,
|
||||
bool showProgressOnTaskBar,
|
||||
QObject* parent = nullptr);
|
||||
~MediaPlayer2Player() override;
|
||||
|
||||
QString PlaybackStatus() const;
|
||||
double Rate() const;
|
||||
QVariantMap Metadata() const;
|
||||
double Volume() const;
|
||||
qlonglong Position() const;
|
||||
double MinimumRate() const;
|
||||
double MaximumRate() const;
|
||||
bool CanGoNext() const;
|
||||
bool CanGoPrevious() const;
|
||||
bool CanPlay() const;
|
||||
bool CanPause() const;
|
||||
bool CanSeek() const;
|
||||
bool CanControl() const;
|
||||
int currentTrack() const;
|
||||
int mediaPlayerPresent() const;
|
||||
|
||||
bool showProgressOnTaskBar() const;
|
||||
void setShowProgressOnTaskBar(bool value);
|
||||
|
||||
Q_SIGNALS:
|
||||
void Seeked(qlonglong Position);
|
||||
|
||||
void rateChanged(double newRate);
|
||||
void volumeChanged(double newVol);
|
||||
void playbackStatusChanged();
|
||||
void canGoNextChanged();
|
||||
void canGoPreviousChanged();
|
||||
void canPlayChanged();
|
||||
void canPauseChanged();
|
||||
void canControlChanged();
|
||||
void canSeekChanged();
|
||||
void currentTrackChanged();
|
||||
void mediaPlayerPresentChanged();
|
||||
void next();
|
||||
void previous();
|
||||
void playPause();
|
||||
void stop();
|
||||
|
||||
public Q_SLOTS:
|
||||
|
||||
void Next();
|
||||
void Previous();
|
||||
void Pause();
|
||||
void PlayPause();
|
||||
void Stop();
|
||||
void Play();
|
||||
void Seek(qlonglong Offset);
|
||||
void SetPosition(const QDBusObjectPath &trackId, qlonglong pos);
|
||||
void OpenUri(const QString &uri);
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
void playerSourceChanged();
|
||||
|
||||
void playControlEnabledChanged();
|
||||
|
||||
void skipBackwardControlEnabledChanged();
|
||||
|
||||
void skipForwardControlEnabledChanged();
|
||||
|
||||
void playerPlaybackStateChanged();
|
||||
|
||||
void playerIsSeekableChanged();
|
||||
|
||||
void audioPositionChanged();
|
||||
|
||||
void playerSeeked(qint64 position);
|
||||
|
||||
void audioDurationChanged();
|
||||
|
||||
void playerVolumeChanged();
|
||||
|
||||
private:
|
||||
void signalPropertiesChange(const QString &property, const QVariant &value);
|
||||
|
||||
void setMediaPlayerPresent(int status);
|
||||
void setRate(double newRate);
|
||||
void setVolume(double volume);
|
||||
void setPropertyPosition(int newPositionInMs);
|
||||
void setCurrentTrack(int newTrackPosition);
|
||||
|
||||
QVariantMap getMetadataOfCurrentTrack();
|
||||
|
||||
QVariantMap m_metadata;
|
||||
QString m_currentTrack;
|
||||
QString m_currentTrackId;
|
||||
double m_rate = 1.0;
|
||||
double m_volume = 0.0;
|
||||
int m_mediaPlayerPresent = 0;
|
||||
bool m_canPlay = false;
|
||||
bool m_canGoNext = false;
|
||||
bool m_canGoPrevious = false;
|
||||
qlonglong m_position = 0;
|
||||
bool m_playerIsSeekableChanged = false;
|
||||
AudioManager *m_audioPlayer = nullptr;
|
||||
mutable QDBusMessage mProgressIndicatorSignal;
|
||||
int mPreviousProgressPosition = 0;
|
||||
bool mShowProgressOnTaskBar = true;
|
||||
};
|
|
@ -0,0 +1,111 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2014 (c) Sujith Haridasan <sujith.haridasan@kdemail.net>
|
||||
* SPDX-FileCopyrightText: 2014 (c) Ashish Madeti <ashishmadeti@gmail.com>
|
||||
* SPDX-FileCopyrightText: 2016 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "mpris2.h"
|
||||
#include "mediaplayer2.h"
|
||||
#include "mediaplayer2player.h"
|
||||
#include "audiomanager.h"
|
||||
|
||||
#include <QDBusConnection>
|
||||
|
||||
|
||||
#if defined Q_OS_WIN
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
Mpris2::Mpris2(QObject* parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void Mpris2::initDBusService()
|
||||
{
|
||||
QString mspris2Name(QStringLiteral("org.mpris.MediaPlayer2.") + m_playerName);
|
||||
|
||||
bool success = QDBusConnection::sessionBus().registerService(mspris2Name);
|
||||
|
||||
// If the above failed, it's likely because we're not the first instance
|
||||
// or the name is already taken. In that event the MPRIS2 spec wants the
|
||||
// following:
|
||||
if (!success) {
|
||||
#if defined Q_OS_WIN
|
||||
success = QDBusConnection::sessionBus().registerService(mspris2Name + QLatin1String(".instance") + QString::number(GetCurrentProcessId()));
|
||||
#else
|
||||
success = QDBusConnection::sessionBus().registerService(mspris2Name + QLatin1String(".instance") + QString::number(getpid()));
|
||||
#endif
|
||||
}
|
||||
|
||||
if (success) {
|
||||
m_mp2 = std::make_unique<MediaPlayer2>(this);
|
||||
m_mp2p = std::make_unique<MediaPlayer2Player>(m_audioPlayer, mShowProgressOnTaskBar, this);
|
||||
|
||||
QDBusConnection::sessionBus().registerObject(QStringLiteral("/org/mpris/MediaPlayer2"), this, QDBusConnection::ExportAdaptors);
|
||||
|
||||
connect(m_mp2.get(), &MediaPlayer2::raisePlayer, this, &Mpris2::raisePlayer);
|
||||
}
|
||||
}
|
||||
|
||||
Mpris2::~Mpris2()
|
||||
= default;
|
||||
|
||||
QString Mpris2::playerName() const
|
||||
{
|
||||
return m_playerName;
|
||||
}
|
||||
|
||||
AudioManager *Mpris2::audioPlayer() const
|
||||
{
|
||||
return m_audioPlayer;
|
||||
}
|
||||
|
||||
bool Mpris2::showProgressOnTaskBar() const
|
||||
{
|
||||
return mShowProgressOnTaskBar;
|
||||
}
|
||||
|
||||
void Mpris2::setPlayerName(const QString &playerName)
|
||||
{
|
||||
if (m_playerName == playerName) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_playerName = playerName;
|
||||
|
||||
if (m_audioPlayer && !m_playerName.isEmpty()) {
|
||||
if (!m_mp2) {
|
||||
initDBusService();
|
||||
}
|
||||
}
|
||||
|
||||
emit playerNameChanged();
|
||||
}
|
||||
|
||||
void Mpris2::setAudioPlayer(AudioManager *audioPlayer)
|
||||
{
|
||||
if (m_audioPlayer == audioPlayer)
|
||||
return;
|
||||
|
||||
m_audioPlayer = audioPlayer;
|
||||
|
||||
if (m_audioPlayer && !m_playerName.isEmpty()) {
|
||||
if (!m_mp2) {
|
||||
initDBusService();
|
||||
}
|
||||
}
|
||||
|
||||
emit audioPlayerChanged();
|
||||
}
|
||||
|
||||
void Mpris2::setShowProgressOnTaskBar(bool value)
|
||||
{
|
||||
m_mp2p->setShowProgressOnTaskBar(value);
|
||||
mShowProgressOnTaskBar = value;
|
||||
Q_EMIT showProgressOnTaskBarChanged();
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2014 (c) Sujith Haridasan <sujith.haridasan@kdemail.net>
|
||||
* SPDX-FileCopyrightText: 2014 (c) Ashish Madeti <ashishmadeti@gmail.com>
|
||||
* SPDX-FileCopyrightText: 2016 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
#include <memory>
|
||||
|
||||
class MediaPlayer2Player;
|
||||
class MediaPlayer2;
|
||||
class AudioManager;
|
||||
|
||||
class Mpris2 : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString playerName
|
||||
READ playerName
|
||||
WRITE setPlayerName
|
||||
NOTIFY playerNameChanged)
|
||||
|
||||
Q_PROPERTY(AudioManager* audioPlayer
|
||||
READ audioPlayer
|
||||
WRITE setAudioPlayer
|
||||
NOTIFY audioPlayerChanged)
|
||||
|
||||
Q_PROPERTY(bool showProgressOnTaskBar
|
||||
READ showProgressOnTaskBar
|
||||
WRITE setShowProgressOnTaskBar
|
||||
NOTIFY showProgressOnTaskBarChanged)
|
||||
|
||||
public:
|
||||
explicit Mpris2(QObject* parent = nullptr);
|
||||
~Mpris2() override;
|
||||
|
||||
[[nodiscard]] QString playerName() const;
|
||||
|
||||
[[nodiscard]] AudioManager* audioPlayer() const;
|
||||
|
||||
[[nodiscard]] bool showProgressOnTaskBar() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
|
||||
void setPlayerName(const QString &playerName);
|
||||
|
||||
void setAudioPlayer(AudioManager* audioPlayer);
|
||||
|
||||
void setShowProgressOnTaskBar(bool value);
|
||||
|
||||
Q_SIGNALS:
|
||||
void raisePlayer();
|
||||
|
||||
void playerNameChanged();
|
||||
|
||||
void audioPlayerChanged();
|
||||
|
||||
void showProgressOnTaskBarChanged();
|
||||
|
||||
private:
|
||||
|
||||
void initDBusService();
|
||||
|
||||
std::unique_ptr<MediaPlayer2> m_mp2;
|
||||
std::unique_ptr<MediaPlayer2Player> m_mp2p;
|
||||
QString m_playerName;
|
||||
AudioManager* m_audioPlayer = nullptr;
|
||||
bool mShowProgressOnTaskBar = true;
|
||||
};
|
|
@ -199,7 +199,7 @@ Kirigami.Page {
|
|||
icon.width: parent.buttonsize
|
||||
flat: true
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
onClicked: console.log("TODO")
|
||||
onClicked: audio.next()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue