2010-11-21 16:13:26 +01:00
|
|
|
/* This file is part of Clementine.
|
|
|
|
Copyright 2010, David Sansome <me@davidsansome.com>
|
|
|
|
|
|
|
|
Clementine is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
Clementine is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2012-10-11 15:38:51 +02:00
|
|
|
#include "mpris2.h"
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
2010-11-21 16:13:26 +01:00
|
|
|
#include "config.h"
|
2010-12-04 23:27:58 +01:00
|
|
|
#include "mpris_common.h"
|
2011-01-08 16:31:14 +01:00
|
|
|
#include "mpris1.h"
|
2012-02-12 14:41:50 +01:00
|
|
|
#include "core/application.h"
|
2011-04-22 18:50:29 +02:00
|
|
|
#include "core/logging.h"
|
2010-11-21 16:13:26 +01:00
|
|
|
#include "core/mpris2_player.h"
|
2012-10-11 15:38:51 +02:00
|
|
|
#include "core/mpris2_playlists.h"
|
2010-11-21 16:13:26 +01:00
|
|
|
#include "core/mpris2_root.h"
|
|
|
|
#include "core/mpris2_tracklist.h"
|
|
|
|
#include "core/player.h"
|
2011-11-28 14:51:35 +01:00
|
|
|
#include "core/timeconstants.h"
|
2012-02-13 21:44:04 +01:00
|
|
|
#include "covers/currentartloader.h"
|
2010-12-04 23:27:58 +01:00
|
|
|
#include "engines/enginebase.h"
|
2010-12-05 12:39:06 +01:00
|
|
|
#include "playlist/playlist.h"
|
2010-11-21 16:13:26 +01:00
|
|
|
#include "playlist/playlistmanager.h"
|
|
|
|
#include "playlist/playlistsequence.h"
|
|
|
|
#include "ui/mainwindow.h"
|
|
|
|
|
|
|
|
#include <QApplication>
|
|
|
|
#include <QDBusConnection>
|
2011-01-08 16:31:14 +01:00
|
|
|
#include <QtConcurrentRun>
|
2010-11-21 16:13:26 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
QDBusArgument& operator<<(QDBusArgument& arg, const MprisPlaylist& playlist) {
|
2012-10-11 15:38:51 +02:00
|
|
|
arg.beginStructure();
|
|
|
|
arg << playlist.id << playlist.name << playlist.icon;
|
|
|
|
arg.endStructure();
|
|
|
|
return arg;
|
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
const QDBusArgument& operator>>(const QDBusArgument& arg,
|
|
|
|
MprisPlaylist& playlist) {
|
2012-10-11 15:38:51 +02:00
|
|
|
arg.beginStructure();
|
|
|
|
arg >> playlist.id >> playlist.name >> playlist.icon;
|
|
|
|
arg.endStructure();
|
|
|
|
return arg;
|
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
QDBusArgument& operator<<(QDBusArgument& arg, const MaybePlaylist& playlist) {
|
2012-10-11 15:38:51 +02:00
|
|
|
arg.beginStructure();
|
|
|
|
arg << playlist.valid;
|
|
|
|
arg << playlist.playlist;
|
|
|
|
arg.endStructure();
|
|
|
|
return arg;
|
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
const QDBusArgument& operator>>(const QDBusArgument& arg,
|
|
|
|
MaybePlaylist& playlist) {
|
2012-10-11 15:38:51 +02:00
|
|
|
arg.beginStructure();
|
|
|
|
arg >> playlist.valid >> playlist.playlist;
|
|
|
|
arg.endStructure();
|
|
|
|
return arg;
|
|
|
|
}
|
2010-11-21 16:13:26 +01:00
|
|
|
|
2010-12-04 23:27:58 +01:00
|
|
|
namespace mpris {
|
2010-11-21 16:13:26 +01:00
|
|
|
|
2010-12-04 23:27:58 +01:00
|
|
|
const char* Mpris2::kMprisObjectPath = "/org/mpris/MediaPlayer2";
|
|
|
|
const char* Mpris2::kServiceName = "org.mpris.MediaPlayer2.clementine";
|
|
|
|
const char* Mpris2::kFreedesktopPath = "org.freedesktop.DBus.Properties";
|
|
|
|
|
2012-02-13 21:44:04 +01:00
|
|
|
Mpris2::Mpris2(Application* app, Mpris1* mpris1, QObject* parent)
|
2014-02-07 16:34:20 +01:00
|
|
|
: QObject(parent), app_(app), mpris1_(mpris1) {
|
2010-11-21 16:13:26 +01:00
|
|
|
new Mpris2Root(this);
|
|
|
|
new Mpris2TrackList(this);
|
|
|
|
new Mpris2Player(this);
|
2012-10-11 15:38:51 +02:00
|
|
|
new Mpris2Playlists(this);
|
2010-11-21 16:13:26 +01:00
|
|
|
|
2011-02-23 20:31:12 +01:00
|
|
|
if (!QDBusConnection::sessionBus().registerService(kServiceName)) {
|
2014-02-07 16:34:20 +01:00
|
|
|
qLog(Warning) << "Failed to register" << QString(kServiceName)
|
|
|
|
<< "on the session bus";
|
2011-02-23 20:31:12 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-11-21 16:13:26 +01:00
|
|
|
QDBusConnection::sessionBus().registerObject(kMprisObjectPath, this);
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
connect(app_->current_art_loader(), SIGNAL(ArtLoaded(Song, QString, QImage)),
|
|
|
|
SLOT(ArtLoaded(Song, QString)));
|
2010-12-04 23:27:58 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
connect(app_->player()->engine(), SIGNAL(StateChanged(Engine::State)),
|
|
|
|
SLOT(EngineStateChanged(Engine::State)));
|
2012-02-12 14:41:50 +01:00
|
|
|
connect(app_->player(), SIGNAL(VolumeChanged(int)), SLOT(VolumeChanged()));
|
|
|
|
connect(app_->player(), SIGNAL(Seeked(qlonglong)), SIGNAL(Seeked(qlonglong)));
|
2010-12-13 00:20:41 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
connect(app_->playlist_manager(), SIGNAL(PlaylistManagerInitialized()),
|
|
|
|
SLOT(PlaylistManagerInitialized()));
|
|
|
|
connect(app_->playlist_manager(), SIGNAL(CurrentSongChanged(Song)),
|
|
|
|
SLOT(CurrentSongChanged(Song)));
|
|
|
|
connect(app_->playlist_manager(), SIGNAL(PlaylistChanged(Playlist*)),
|
|
|
|
SLOT(PlaylistChanged(Playlist*)));
|
|
|
|
connect(app_->playlist_manager(), SIGNAL(CurrentChanged(Playlist*)),
|
|
|
|
SLOT(PlaylistCollectionChanged(Playlist*)));
|
2010-12-04 23:27:58 +01:00
|
|
|
}
|
|
|
|
|
2010-12-13 00:20:41 +01:00
|
|
|
// when PlaylistManager gets it ready, we connect PlaylistSequence with this
|
|
|
|
void Mpris2::PlaylistManagerInitialized() {
|
2014-02-07 16:34:20 +01:00
|
|
|
connect(app_->playlist_manager()->sequence(),
|
|
|
|
SIGNAL(ShuffleModeChanged(PlaylistSequence::ShuffleMode)),
|
2010-12-13 00:20:41 +01:00
|
|
|
SLOT(ShuffleModeChanged()));
|
2014-02-07 16:34:20 +01:00
|
|
|
connect(app_->playlist_manager()->sequence(),
|
|
|
|
SIGNAL(RepeatModeChanged(PlaylistSequence::RepeatMode)),
|
2010-12-13 00:20:41 +01:00
|
|
|
SLOT(RepeatModeChanged()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Mpris2::EngineStateChanged(Engine::State newState) {
|
2014-02-07 16:34:20 +01:00
|
|
|
if (newState != Engine::Playing && newState != Engine::Paused) {
|
|
|
|
last_metadata_ = QVariantMap();
|
2010-12-13 00:20:41 +01:00
|
|
|
EmitNotification("Metadata");
|
|
|
|
}
|
|
|
|
|
|
|
|
EmitNotification("PlaybackStatus", PlaybackStatus(newState));
|
2010-12-04 23:27:58 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void Mpris2::VolumeChanged() { EmitNotification("Volume"); }
|
2010-11-21 16:13:26 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void Mpris2::ShuffleModeChanged() { EmitNotification("Shuffle"); }
|
2010-12-13 00:20:41 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void Mpris2::RepeatModeChanged() { EmitNotification("LoopStatus"); }
|
2010-12-13 00:20:41 +01:00
|
|
|
|
2010-12-04 23:27:58 +01:00
|
|
|
void Mpris2::EmitNotification(const QString& name, const QVariant& val) {
|
2013-11-19 00:13:45 +01:00
|
|
|
EmitNotification(name, val, "org.mpris.MediaPlayer2.Player");
|
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void Mpris2::EmitNotification(const QString& name, const QVariant& val,
|
|
|
|
const QString& mprisEntity) {
|
2010-11-21 16:13:26 +01:00
|
|
|
QDBusMessage msg = QDBusMessage::createSignal(
|
2014-02-07 16:34:20 +01:00
|
|
|
kMprisObjectPath, kFreedesktopPath, "PropertiesChanged");
|
2010-11-21 16:13:26 +01:00
|
|
|
QVariantMap map;
|
|
|
|
map.insert(name, val);
|
2014-02-07 16:34:20 +01:00
|
|
|
QVariantList args = QVariantList() << mprisEntity << map << QStringList();
|
2010-11-21 16:13:26 +01:00
|
|
|
msg.setArguments(args);
|
|
|
|
QDBusConnection::sessionBus().send(msg);
|
|
|
|
}
|
|
|
|
|
2010-12-04 23:27:58 +01:00
|
|
|
void Mpris2::EmitNotification(const QString& name) {
|
2010-11-21 16:13:26 +01:00
|
|
|
QVariant value;
|
2014-02-07 16:34:20 +01:00
|
|
|
if (name == "PlaybackStatus")
|
|
|
|
value = PlaybackStatus();
|
|
|
|
else if (name == "LoopStatus")
|
|
|
|
value = LoopStatus();
|
|
|
|
else if (name == "Shuffle")
|
|
|
|
value = Shuffle();
|
|
|
|
else if (name == "Metadata")
|
|
|
|
value = Metadata();
|
|
|
|
else if (name == "Volume")
|
|
|
|
value = Volume();
|
|
|
|
else if (name == "Position")
|
|
|
|
value = Position();
|
|
|
|
|
|
|
|
if (value.isValid()) EmitNotification(name, value);
|
2010-11-21 16:13:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------Root Interface--------------------------//
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
bool Mpris2::CanQuit() const { return true; }
|
2010-11-21 16:13:26 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
bool Mpris2::CanRaise() const { return true; }
|
2010-11-21 16:13:26 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
bool Mpris2::HasTrackList() const { return true; }
|
2010-11-21 16:13:26 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
QString Mpris2::Identity() const { return QCoreApplication::applicationName(); }
|
2010-11-21 16:13:26 +01:00
|
|
|
|
2011-01-06 20:29:54 +01:00
|
|
|
QString Mpris2::DesktopEntryAbsolutePath() const {
|
2010-11-21 16:13:26 +01:00
|
|
|
QStringList xdg_data_dirs = QString(getenv("XDG_DATA_DIRS")).split(":");
|
|
|
|
xdg_data_dirs.append("/usr/local/share/");
|
|
|
|
xdg_data_dirs.append("/usr/share/");
|
|
|
|
|
2014-02-10 14:29:07 +01:00
|
|
|
for (const QString& directory : xdg_data_dirs) {
|
2014-02-07 16:34:20 +01:00
|
|
|
QString path = QString("%1/applications/%2.desktop").arg(
|
|
|
|
directory, QApplication::applicationName().toLower());
|
|
|
|
if (QFile::exists(path)) return path;
|
2010-11-21 16:13:26 +01:00
|
|
|
}
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
2011-01-06 20:29:54 +01:00
|
|
|
QString Mpris2::DesktopEntry() const {
|
|
|
|
return QApplication::applicationName().toLower();
|
|
|
|
}
|
|
|
|
|
2010-12-04 23:27:58 +01:00
|
|
|
QStringList Mpris2::SupportedUriSchemes() const {
|
2014-02-07 16:34:20 +01:00
|
|
|
static QStringList res = QStringList() << "file"
|
|
|
|
<< "http"
|
|
|
|
<< "cdda"
|
|
|
|
<< "smb"
|
|
|
|
<< "sftp";
|
2010-11-21 16:13:26 +01:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2010-12-04 23:27:58 +01:00
|
|
|
QStringList Mpris2::SupportedMimeTypes() const {
|
2014-02-07 16:34:20 +01:00
|
|
|
static QStringList res = QStringList() << "application/ogg"
|
|
|
|
<< "application/x-ogg"
|
|
|
|
<< "application/x-ogm-audio"
|
|
|
|
<< "audio/aac"
|
|
|
|
<< "audio/mp4"
|
|
|
|
<< "audio/mpeg"
|
|
|
|
<< "audio/mpegurl"
|
|
|
|
<< "audio/ogg"
|
|
|
|
<< "audio/vnd.rn-realaudio"
|
|
|
|
<< "audio/vorbis"
|
|
|
|
<< "audio/x-flac"
|
|
|
|
<< "audio/x-mp3"
|
|
|
|
<< "audio/x-mpeg"
|
|
|
|
<< "audio/x-mpegurl"
|
|
|
|
<< "audio/x-ms-wma"
|
|
|
|
<< "audio/x-musepack"
|
|
|
|
<< "audio/x-oggflac"
|
|
|
|
<< "audio/x-pn-realaudio"
|
|
|
|
<< "audio/x-scpls"
|
|
|
|
<< "audio/x-speex"
|
|
|
|
<< "audio/x-vorbis"
|
|
|
|
<< "audio/x-vorbis+ogg"
|
|
|
|
<< "audio/x-wav"
|
|
|
|
<< "video/x-ms-asf"
|
|
|
|
<< "x-content/audio-player";
|
2010-11-21 16:13:26 +01:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void Mpris2::Raise() { emit RaiseMainWindow(); }
|
2010-11-21 16:13:26 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void Mpris2::Quit() { qApp->quit(); }
|
2010-11-21 16:13:26 +01:00
|
|
|
|
2010-12-04 23:27:58 +01:00
|
|
|
QString Mpris2::PlaybackStatus() const {
|
2012-02-12 14:41:50 +01:00
|
|
|
return PlaybackStatus(app_->player()->GetState());
|
2010-12-13 00:20:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
QString Mpris2::PlaybackStatus(Engine::State state) const {
|
|
|
|
switch (state) {
|
2014-02-07 16:34:20 +01:00
|
|
|
case Engine::Playing:
|
|
|
|
return "Playing";
|
|
|
|
case Engine::Paused:
|
|
|
|
return "Paused";
|
|
|
|
default:
|
|
|
|
return "Stopped";
|
2010-11-21 16:13:26 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-04 23:27:58 +01:00
|
|
|
QString Mpris2::LoopStatus() const {
|
2012-08-17 15:35:24 +02:00
|
|
|
if (!app_->playlist_manager()->sequence()) {
|
|
|
|
return "None";
|
|
|
|
}
|
2014-02-07 16:34:20 +01:00
|
|
|
|
2012-02-12 14:41:50 +01:00
|
|
|
switch (app_->playlist_manager()->sequence()->repeat_mode()) {
|
2010-11-21 16:13:26 +01:00
|
|
|
case PlaylistSequence::Repeat_Album:
|
2014-02-07 16:34:20 +01:00
|
|
|
case PlaylistSequence::Repeat_Playlist:
|
|
|
|
return "Playlist";
|
|
|
|
case PlaylistSequence::Repeat_Track:
|
|
|
|
return "Track";
|
|
|
|
default:
|
|
|
|
return "None";
|
2010-11-21 16:13:26 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-04 23:27:58 +01:00
|
|
|
void Mpris2::SetLoopStatus(const QString& value) {
|
2010-12-05 12:39:06 +01:00
|
|
|
PlaylistSequence::RepeatMode mode = PlaylistSequence::Repeat_Off;
|
|
|
|
|
2010-11-21 16:13:26 +01:00
|
|
|
if (value == "None") {
|
2010-12-05 12:39:06 +01:00
|
|
|
mode = PlaylistSequence::Repeat_Off;
|
2010-11-21 16:13:26 +01:00
|
|
|
} else if (value == "Track") {
|
2010-12-05 12:39:06 +01:00
|
|
|
mode = PlaylistSequence::Repeat_Track;
|
2010-11-21 16:13:26 +01:00
|
|
|
} else if (value == "Playlist") {
|
2010-12-05 12:39:06 +01:00
|
|
|
mode = PlaylistSequence::Repeat_Playlist;
|
2010-11-21 16:13:26 +01:00
|
|
|
}
|
2010-12-05 12:39:06 +01:00
|
|
|
|
2012-02-12 14:41:50 +01:00
|
|
|
app_->playlist_manager()->active()->sequence()->SetRepeatMode(mode);
|
2010-11-21 16:13:26 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
double Mpris2::Rate() const { return 1.0; }
|
2010-11-21 16:13:26 +01:00
|
|
|
|
2010-12-13 00:20:41 +01:00
|
|
|
void Mpris2::SetRate(double rate) {
|
2014-02-07 16:34:20 +01:00
|
|
|
if (rate == 0) {
|
2011-02-19 19:24:05 +01:00
|
|
|
if (mpris1_->player()) {
|
|
|
|
mpris1_->player()->Pause();
|
|
|
|
}
|
2010-12-13 00:20:41 +01:00
|
|
|
}
|
2010-11-21 16:13:26 +01:00
|
|
|
}
|
|
|
|
|
2010-12-04 23:27:58 +01:00
|
|
|
bool Mpris2::Shuffle() const {
|
2011-02-19 19:24:05 +01:00
|
|
|
if (mpris1_->player()) {
|
|
|
|
return mpris1_->player()->GetStatus().random;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
2010-11-21 16:13:26 +01:00
|
|
|
}
|
|
|
|
|
2010-12-04 23:27:58 +01:00
|
|
|
void Mpris2::SetShuffle(bool value) {
|
2011-02-19 19:24:05 +01:00
|
|
|
if (mpris1_->tracklist()) {
|
|
|
|
mpris1_->tracklist()->SetRandom(value);
|
|
|
|
}
|
2010-11-21 16:13:26 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
QVariantMap Mpris2::Metadata() const { return last_metadata_; }
|
2010-11-21 16:13:26 +01:00
|
|
|
|
2010-12-05 12:39:06 +01:00
|
|
|
QString Mpris2::current_track_id() const {
|
2011-02-19 19:24:05 +01:00
|
|
|
if (!mpris1_->tracklist()) {
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
return QString("/org/mpris/MediaPlayer2/Track/%1")
|
|
|
|
.arg(QString::number(mpris1_->tracklist()->GetCurrentTrack()));
|
2010-12-05 12:39:06 +01:00
|
|
|
}
|
|
|
|
|
2010-12-13 00:20:41 +01:00
|
|
|
// We send Metadata change notification as soon as the process of
|
|
|
|
// changing song starts...
|
2014-02-07 16:34:20 +01:00
|
|
|
void Mpris2::CurrentSongChanged(const Song& song) { ArtLoaded(song, ""); }
|
2010-12-13 00:20:41 +01:00
|
|
|
|
|
|
|
// ... and we add the cover information later, when it's available.
|
2010-12-04 23:27:58 +01:00
|
|
|
void Mpris2::ArtLoaded(const Song& song, const QString& art_uri) {
|
2010-11-21 16:13:26 +01:00
|
|
|
last_metadata_ = QVariantMap();
|
2011-10-16 22:57:53 +02:00
|
|
|
song.ToXesam(&last_metadata_);
|
2010-11-21 16:13:26 +01:00
|
|
|
|
2010-12-04 23:27:58 +01:00
|
|
|
using mpris::AddMetadata;
|
2010-12-05 12:39:06 +01:00
|
|
|
AddMetadata("mpris:trackid", current_track_id(), &last_metadata_);
|
2011-10-16 22:57:53 +02:00
|
|
|
|
2010-12-13 00:20:41 +01:00
|
|
|
if (song.rating() != -1.0) {
|
|
|
|
AddMetadata("rating", song.rating() * 5, &last_metadata_);
|
|
|
|
}
|
2010-12-04 23:27:58 +01:00
|
|
|
if (!art_uri.isEmpty()) {
|
|
|
|
AddMetadata("mpris:artUrl", art_uri, &last_metadata_);
|
2010-11-21 16:13:26 +01:00
|
|
|
}
|
|
|
|
|
2013-01-01 21:54:50 +01:00
|
|
|
AddMetadata("year", song.year(), &last_metadata_);
|
|
|
|
AddMetadata("bitrate", song.bitrate(), &last_metadata_);
|
|
|
|
|
2010-12-04 23:27:58 +01:00
|
|
|
EmitNotification("Metadata", last_metadata_);
|
2010-11-21 16:13:26 +01:00
|
|
|
}
|
|
|
|
|
2010-12-04 23:27:58 +01:00
|
|
|
double Mpris2::Volume() const {
|
2011-02-19 19:24:05 +01:00
|
|
|
if (mpris1_->player()) {
|
|
|
|
return double(mpris1_->player()->VolumeGet()) / 100;
|
|
|
|
} else {
|
|
|
|
return 0.0;
|
|
|
|
}
|
2010-11-21 16:13:26 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void Mpris2::SetVolume(double value) { app_->player()->SetVolume(value * 100); }
|
2010-11-21 16:13:26 +01:00
|
|
|
|
2010-12-04 23:27:58 +01:00
|
|
|
qlonglong Mpris2::Position() const {
|
2012-02-12 14:41:50 +01:00
|
|
|
return app_->player()->engine()->position_nanosec() / kNsecPerUsec;
|
2010-11-21 16:13:26 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
double Mpris2::MaximumRate() const { return 1.0; }
|
2010-11-21 16:13:26 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
double Mpris2::MinimumRate() const { return 1.0; }
|
2010-11-21 16:13:26 +01:00
|
|
|
|
2010-12-04 23:27:58 +01:00
|
|
|
bool Mpris2::CanGoNext() const {
|
2011-02-19 19:24:05 +01:00
|
|
|
if (mpris1_->player()) {
|
|
|
|
return mpris1_->player()->GetCaps() & CAN_GO_NEXT;
|
|
|
|
} else {
|
|
|
|
return true;
|
|
|
|
}
|
2010-11-21 16:13:26 +01:00
|
|
|
}
|
|
|
|
|
2010-12-04 23:27:58 +01:00
|
|
|
bool Mpris2::CanGoPrevious() const {
|
2011-02-19 19:24:05 +01:00
|
|
|
if (mpris1_->player()) {
|
|
|
|
return mpris1_->player()->GetCaps() & CAN_GO_PREV;
|
|
|
|
} else {
|
|
|
|
return true;
|
|
|
|
}
|
2010-11-21 16:13:26 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
bool Mpris2::CanPlay() const { return mpris1_->player()->GetCaps() & CAN_PLAY; }
|
2010-11-21 16:13:26 +01:00
|
|
|
|
2010-12-13 00:20:41 +01:00
|
|
|
// This one's a bit different than MPRIS 1 - we want this to be true even when
|
2011-02-23 20:31:12 +01:00
|
|
|
// the song is already paused or stopped.
|
2010-12-04 23:27:58 +01:00
|
|
|
bool Mpris2::CanPause() const {
|
2011-02-19 19:24:05 +01:00
|
|
|
if (mpris1_->player()) {
|
2014-02-07 16:34:20 +01:00
|
|
|
return mpris1_->player()->GetCaps() & CAN_PAUSE ||
|
|
|
|
PlaybackStatus() == "Paused" || PlaybackStatus() == "Stopped";
|
2011-02-19 19:24:05 +01:00
|
|
|
} else {
|
|
|
|
return true;
|
|
|
|
}
|
2010-11-21 16:13:26 +01:00
|
|
|
}
|
|
|
|
|
2010-12-04 23:27:58 +01:00
|
|
|
bool Mpris2::CanSeek() const {
|
2011-02-19 19:24:05 +01:00
|
|
|
if (mpris1_->player()) {
|
|
|
|
return mpris1_->player()->GetCaps() & CAN_SEEK;
|
|
|
|
} else {
|
|
|
|
return true;
|
|
|
|
}
|
2010-11-21 16:13:26 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
bool Mpris2::CanControl() const { return true; }
|
2010-11-21 16:13:26 +01:00
|
|
|
|
2010-12-04 23:27:58 +01:00
|
|
|
void Mpris2::Next() {
|
2014-02-07 16:34:20 +01:00
|
|
|
if (CanGoNext()) {
|
2012-02-12 14:41:50 +01:00
|
|
|
app_->player()->Next();
|
2010-12-15 16:50:22 +01:00
|
|
|
}
|
2010-11-21 16:13:26 +01:00
|
|
|
}
|
|
|
|
|
2010-12-04 23:27:58 +01:00
|
|
|
void Mpris2::Previous() {
|
2014-02-07 16:34:20 +01:00
|
|
|
if (CanGoPrevious()) {
|
2012-02-12 14:41:50 +01:00
|
|
|
app_->player()->Previous();
|
2010-12-15 16:50:22 +01:00
|
|
|
}
|
2010-11-21 16:13:26 +01:00
|
|
|
}
|
|
|
|
|
2010-12-04 23:27:58 +01:00
|
|
|
void Mpris2::Pause() {
|
2014-02-07 16:34:20 +01:00
|
|
|
if (CanPause() && app_->player()->GetState() != Engine::Paused) {
|
2012-02-12 14:41:50 +01:00
|
|
|
app_->player()->Pause();
|
2010-12-15 16:50:22 +01:00
|
|
|
}
|
2010-11-21 16:13:26 +01:00
|
|
|
}
|
|
|
|
|
2010-12-04 23:27:58 +01:00
|
|
|
void Mpris2::PlayPause() {
|
2011-02-23 20:31:12 +01:00
|
|
|
if (CanPause()) {
|
2012-02-12 14:41:50 +01:00
|
|
|
app_->player()->PlayPause();
|
2011-02-23 20:31:12 +01:00
|
|
|
}
|
2010-11-21 16:13:26 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void Mpris2::Stop() { app_->player()->Stop(); }
|
2010-11-21 16:13:26 +01:00
|
|
|
|
2010-12-04 23:27:58 +01:00
|
|
|
void Mpris2::Play() {
|
2014-02-07 16:34:20 +01:00
|
|
|
if (CanPlay()) {
|
2012-02-12 14:41:50 +01:00
|
|
|
app_->player()->Play();
|
2010-12-15 16:50:22 +01:00
|
|
|
}
|
2010-11-21 16:13:26 +01:00
|
|
|
}
|
|
|
|
|
2010-12-04 23:27:58 +01:00
|
|
|
void Mpris2::Seek(qlonglong offset) {
|
2014-02-07 16:34:20 +01:00
|
|
|
if (CanSeek()) {
|
|
|
|
app_->player()->SeekTo(app_->player()->engine()->position_nanosec() /
|
|
|
|
kNsecPerSec +
|
|
|
|
offset / kUsecPerSec);
|
2010-12-15 16:50:22 +01:00
|
|
|
}
|
2010-11-21 16:13:26 +01:00
|
|
|
}
|
|
|
|
|
2010-12-04 23:27:58 +01:00
|
|
|
void Mpris2::SetPosition(const QDBusObjectPath& trackId, qlonglong offset) {
|
2010-12-15 16:50:22 +01:00
|
|
|
if (CanSeek() && trackId.path() == current_track_id() && offset >= 0) {
|
2011-02-14 20:34:37 +01:00
|
|
|
offset *= kNsecPerUsec;
|
2010-12-05 12:39:06 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
if (offset <
|
|
|
|
app_->player()->GetCurrentItem()->Metadata().length_nanosec()) {
|
2012-02-12 14:41:50 +01:00
|
|
|
app_->player()->SeekTo(offset / kNsecPerSec);
|
2010-12-15 16:50:22 +01:00
|
|
|
}
|
|
|
|
}
|
2010-11-21 16:13:26 +01:00
|
|
|
}
|
|
|
|
|
2010-12-05 12:39:06 +01:00
|
|
|
void Mpris2::OpenUri(const QString& uri) {
|
2011-02-19 19:24:05 +01:00
|
|
|
if (mpris1_->tracklist()) {
|
|
|
|
mpris1_->tracklist()->AddTrack(uri, true);
|
|
|
|
}
|
2010-11-21 16:13:26 +01:00
|
|
|
}
|
|
|
|
|
2010-12-04 23:27:58 +01:00
|
|
|
TrackIds Mpris2::Tracks() const {
|
2014-02-07 16:34:20 +01:00
|
|
|
// TODO
|
2010-11-21 16:13:26 +01:00
|
|
|
return TrackIds();
|
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
bool Mpris2::CanEditTracks() const { return false; }
|
2010-11-21 16:13:26 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
TrackMetadata Mpris2::GetTracksMetadata(const TrackIds& tracks) const {
|
|
|
|
// TODO
|
2010-11-21 16:13:26 +01:00
|
|
|
return TrackMetadata();
|
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void Mpris2::AddTrack(const QString& uri, const QDBusObjectPath& afterTrack,
|
|
|
|
bool setAsCurrent) {
|
|
|
|
// TODO
|
2010-11-21 16:13:26 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void Mpris2::RemoveTrack(const QDBusObjectPath& trackId) {
|
|
|
|
// TODO
|
2010-11-21 16:13:26 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void Mpris2::GoTo(const QDBusObjectPath& trackId) {
|
|
|
|
// TODO
|
2010-11-21 16:13:26 +01:00
|
|
|
}
|
2010-12-04 23:27:58 +01:00
|
|
|
|
2012-10-11 15:38:51 +02:00
|
|
|
quint32 Mpris2::PlaylistCount() const {
|
|
|
|
return app_->playlist_manager()->GetAllPlaylists().size();
|
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
QStringList Mpris2::Orderings() const { return QStringList() << "User"; }
|
2012-10-11 15:38:51 +02:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
QDBusObjectPath MakePlaylistPath(int id) {
|
2014-02-07 16:34:20 +01:00
|
|
|
return QDBusObjectPath(
|
|
|
|
QString("/org/mpris/MediaPlayer2/Playlists/%1").arg(id));
|
2012-10-11 15:38:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MaybePlaylist Mpris2::ActivePlaylist() const {
|
|
|
|
MaybePlaylist maybe_playlist;
|
|
|
|
Playlist* current_playlist = app_->playlist_manager()->current();
|
|
|
|
maybe_playlist.valid = current_playlist;
|
|
|
|
if (!current_playlist) {
|
|
|
|
return maybe_playlist;
|
|
|
|
}
|
|
|
|
|
|
|
|
maybe_playlist.playlist.id = MakePlaylistPath(current_playlist->id());
|
|
|
|
maybe_playlist.playlist.name =
|
|
|
|
app_->playlist_manager()->GetPlaylistName(current_playlist->id());
|
|
|
|
return maybe_playlist;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Mpris2::ActivatePlaylist(const QDBusObjectPath& playlist_id) {
|
|
|
|
QStringList split_path = playlist_id.path().split('/');
|
|
|
|
qLog(Debug) << Q_FUNC_INFO << playlist_id.path() << split_path;
|
|
|
|
if (split_path.isEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
bool ok = false;
|
|
|
|
int p = split_path.last().toInt(&ok);
|
|
|
|
if (!ok) {
|
|
|
|
return;
|
|
|
|
}
|
2013-11-16 19:52:14 +01:00
|
|
|
if (!app_->playlist_manager()->IsPlaylistOpen(p)) {
|
|
|
|
qLog(Error) << "Playlist isn't opened!";
|
|
|
|
return;
|
|
|
|
}
|
2012-10-11 15:38:51 +02:00
|
|
|
app_->playlist_manager()->SetActivePlaylist(p);
|
|
|
|
app_->player()->Next();
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Support sort orders.
|
2014-02-07 16:34:20 +01:00
|
|
|
MprisPlaylistList Mpris2::GetPlaylists(quint32 index, quint32 max_count,
|
|
|
|
const QString& order,
|
|
|
|
bool reverse_order) {
|
2012-10-11 15:38:51 +02:00
|
|
|
MprisPlaylistList ret;
|
2014-02-10 14:29:07 +01:00
|
|
|
for (Playlist* p : app_->playlist_manager()->GetAllPlaylists()) {
|
2012-10-11 15:38:51 +02:00
|
|
|
MprisPlaylist mpris_playlist;
|
|
|
|
mpris_playlist.id = MakePlaylistPath(p->id());
|
|
|
|
mpris_playlist.name = app_->playlist_manager()->GetPlaylistName(p->id());
|
|
|
|
ret << mpris_playlist;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (reverse_order) {
|
|
|
|
std::reverse(ret.begin(), ret.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret.mid(index, max_count);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Mpris2::PlaylistChanged(Playlist* playlist) {
|
|
|
|
MprisPlaylist mpris_playlist;
|
|
|
|
mpris_playlist.id = MakePlaylistPath(playlist->id());
|
2014-02-07 16:34:20 +01:00
|
|
|
mpris_playlist.name =
|
|
|
|
app_->playlist_manager()->GetPlaylistName(playlist->id());
|
2012-10-11 15:38:51 +02:00
|
|
|
emit PlaylistChanged(mpris_playlist);
|
|
|
|
}
|
|
|
|
|
2013-11-22 20:52:14 +01:00
|
|
|
void Mpris2::PlaylistCollectionChanged(Playlist* playlist) {
|
2013-11-19 00:13:45 +01:00
|
|
|
EmitNotification("PlaylistCount", "", "org.mpris.MediaPlayer2.Playlists");
|
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
} // namespace mpris
|