Clementine-audio-player-Mac.../src/core/mpris2.cpp

396 lines
11 KiB
C++

/* 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/>.
*/
#include "config.h"
#include "mpris.h"
#include "mpris2.h"
#include "core/albumcoverloader.h"
#include "core/mpris2_player.h"
#include "core/mpris2_root.h"
#include "core/mpris2_tracklist.h"
#include "core/player.h"
#include "playlist/playlistmanager.h"
#include "playlist/playlistsequence.h"
#include "ui/mainwindow.h"
#include <QApplication>
#include <QDBusConnection>
#ifdef HAVE_LIBINDICATE
# include <qindicateserver.h>
#endif
const char* MPRIS2::kMprisObjectPath = "/org/mpris/MediaPlayer2";
const char* MPRIS2::kServiceName = "org.mpris.MediaPlayer2.clementine";
const char* MPRIS2::kFreedesktopPath = "org.freedesktop.DBus.Properties";
MPRIS2::MPRIS2(MainWindow* main_window, Player* player, QObject* parent)
: QObject(parent),
cover_loader_(new BackgroundThreadImplementation<AlbumCoverLoader, AlbumCoverLoader>(this)),
art_request_id_(0),
ui_(main_window),
player_(player)
{
cover_loader_->Start();
connect(cover_loader_, SIGNAL(Initialised()), SLOT(Initialised()));
new Mpris2Root(this);
new Mpris2TrackList(this);
new Mpris2Player(this);
QDBusConnection::sessionBus().registerService(kServiceName);
QDBusConnection::sessionBus().registerObject(kMprisObjectPath, this);
#ifdef HAVE_LIBINDICATE
QIndicate::Server* indicate_server = QIndicate::Server::defaultInstance();
indicate_server->setType("music.clementine");
indicate_server->setDesktopFile(DesktopEntry());
indicate_server->show();
#endif
}
void MPRIS2::emitNotification(const QString& name, const QVariant& val) {
QDBusMessage msg = QDBusMessage::createSignal(
kMprisObjectPath, kFreedesktopPath, "PropertiesChanged");
QVariantMap map;
map.insert(name, val);
QVariantList args = QVariantList()
<< "org.mpris.MediaPlayer2.Player"
<< map
<< QStringList();
msg.setArguments(args);
QDBusConnection::sessionBus().send(msg);
}
void MPRIS2::emitNotification(const QString& name) {
QVariant value;
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);
}
//------------------Root Interface--------------------------//
bool MPRIS2::CanQuit() const {
return true;
}
bool MPRIS2::CanRaise() const {
return true;
}
bool MPRIS2::HasTrackList() const {
return true;
}
QString MPRIS2::Identity() const {
return QString("%1 %2").arg(
QCoreApplication::applicationName(),
QCoreApplication::applicationVersion());
}
QString MPRIS2::DesktopEntry() const {
QStringList xdg_data_dirs = QString(getenv("XDG_DATA_DIRS")).split(":");
xdg_data_dirs.append("/usr/local/share/");
xdg_data_dirs.append("/usr/share/");
foreach (const QString& directory, xdg_data_dirs) {
QString path = QString("%1/applications/%2.desktop").
arg(directory, QApplication::applicationName().toLower());
if (QFile::exists(path))
return path;
}
return QString();
}
QStringList MPRIS2::SupportedUriSchemes() const {
static QStringList res = QStringList()
<< "file"
<< "http"
<< "cdda"
<< "smb"
<< "sftp";
return res;
}
QStringList MPRIS2::SupportedMimeTypes() const {
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";
return res;
}
void MPRIS2::Raise() {
ui_->show();
ui_->activateWindow();
}
void MPRIS2::Quit() {
qApp->quit();
}
QString MPRIS2::PlaybackStatus() const {
switch (player_->GetState()) {
case Engine::Playing: return "Playing";
case Engine::Paused: return "Paused";
default: return "Stopped";
}
}
QString MPRIS2::LoopStatus() const {
switch (player_->GetPlaylists()->sequence()->repeat_mode()) {
case PlaylistSequence::Repeat_Album:
case PlaylistSequence::Repeat_Playlist: return "Playlist";
case PlaylistSequence::Repeat_Track: return "Track";
default: return "None";
}
}
void MPRIS2::SetLoopStatus(const QString& value) {
if (value == "None") {
player_->SetLoop(PlaylistSequence::Repeat_Off);
} else if (value == "Track") {
player_->SetLoop(PlaylistSequence::Repeat_Track);
} else if (value == "Playlist") {
player_->SetLoop(PlaylistSequence::Repeat_Playlist);
}
emitNotification("LoopStatus", value);
}
double MPRIS2::Rate() const {
return 1.0;
}
void MPRIS2::SetRate(double) {
// Do nothing
}
bool MPRIS2::Shuffle() const {
return player_->GetPlaylists()->sequence()->shuffle_mode() !=
PlaylistSequence::Shuffle_Off;
}
void MPRIS2::SetShuffle(bool value) {
player_->SetRandom(value);
emitNotification("Shuffle", value);
}
QVariantMap MPRIS2::Metadata() const {
return last_metadata_;
}
void MPRIS2::UpdateMetadata(PlaylistItemPtr item) {
last_metadata_ = QVariantMap();
// Load the cover art
art_request_item_ = item;
art_request_id_ = cover_loader_->Worker()->LoadImageAsync(item->Metadata());
}
void MPRIS2::Initialised() {
cover_loader_->Worker()->SetPadOutputImage(true);
cover_loader_->Worker()->SetDefaultOutputImage(QImage(":nocover.png"));
connect(cover_loader_->Worker().get(), SIGNAL(ImageLoaded(quint64,QImage)),
SLOT(TempArtLoaded(quint64,QImage)));
}
void MPRIS2::TempArtLoaded(quint64 id, const QImage& image) {
if (id != art_request_id_ || !art_request_item_)
return;
art_request_id_ = 0;
last_metadata_ = QVariantMap();
Song song = art_request_item_->Metadata();
QString track_id = QString("/org/mpris/MediaPlayer2/Track/%1").
arg(QString::number(player_->GetCurrentTrack()));
using metadata::AddMetadata;
AddMetadata("mpris:trackid", track_id, &last_metadata_);
AddMetadata("xesam:url", art_request_item_->Url().toString(), &last_metadata_);
AddMetadata("xesam:title", song.PrettyTitle(), &last_metadata_);
AddMetadata("xesam:artist", QStringList() << song.artist(), &last_metadata_);
AddMetadata("xesam:album", song.album(), &last_metadata_);
AddMetadata("xesam:albumArtist", song.albumartist(), &last_metadata_);
AddMetadata("mpris:length", song.length()*1e6, &last_metadata_);
AddMetadata("xesam:trackNumber", song.track(), &last_metadata_);
AddMetadata("xesam:genre", song.genre(), &last_metadata_);
AddMetadata("xesam:discNumber", song.disc(), &last_metadata_);
AddMetadata("xesam:comment", song.comment(), &last_metadata_);
AddMetadata("xesam:contentCreated", QDateTime(QDate(song.year(),1,1)), &last_metadata_);
AddMetadata("xesam:audioBPM", song.bpm(), &last_metadata_);
AddMetadata("xesam:composer", song.composer(), &last_metadata_);
if (!image.isNull()) {
temp_art_.reset(new QTemporaryFile(QDir::tempPath() + "/clementine-art-XXXXXX.jpg"));
temp_art_->open();
image.save(temp_art_->fileName(), "JPEG");
AddMetadata("mpris:artUrl", "file://" + temp_art_->fileName(), &last_metadata_);
}
emitNotification("Metadata", last_metadata_);
art_request_item_.reset();
}
double MPRIS2::Volume() const {
return player_->VolumeGet() / 100;
}
void MPRIS2::SetVolume(double value) {
player_->SetVolume(value * 100);
emitNotification("Volume",value);
}
qlonglong MPRIS2::Position() const {
return player_->PositionGet() * 1e6;
}
double MPRIS2::MaximumRate() const {
return 1.0;
}
double MPRIS2::MinimumRate() const {
return 1.0;
}
bool MPRIS2::CanGoNext() const {
return true;
}
bool MPRIS2::CanGoPrevious() const {
return true;
}
bool MPRIS2::CanPlay() const {
return true;
}
bool MPRIS2::CanPause() const {
return true;
}
bool MPRIS2::CanSeek() const {
return true;
}
bool MPRIS2::CanControl() const {
return true;
}
void MPRIS2::Next() {
player_->Next();
emitNotification("PlaybackStatus",PlaybackStatus());
emitNotification("Metadata",Metadata());
}
void MPRIS2::Previous() {
player_->Previous();
emitNotification("PlaybackStatus",PlaybackStatus());
emitNotification("Metadata",Metadata());
}
void MPRIS2::Pause() {
player_->Pause();
emitNotification("PlaybackStatus",PlaybackStatus());
emitNotification("Metadata",Metadata());
}
void MPRIS2::PlayPause() {
player_->PlayPause();
emitNotification("PlaybackStatus",PlaybackStatus());
emitNotification("Metadata",Metadata());
}
void MPRIS2::Stop() {
player_->Stop();
emitNotification("PlaybackStatus",PlaybackStatus());
emitNotification("Metadata",Metadata());
}
void MPRIS2::Play() {
player_->Play();
emitNotification("PlaybackStatus",PlaybackStatus());
emitNotification("Metadata",Metadata());
}
void MPRIS2::Seek(qlonglong offset) {
player_->Seek(offset*1e6);
}
void MPRIS2::SetPosition(const QDBusObjectPath& trackId, qlonglong offset) {
//TODO
}
void MPRIS2::OpenUri(const QString &uri) {
player_->AddTrack(uri,true);
}
TrackIds MPRIS2::Tracks() const {
//TODO
return TrackIds();
}
bool MPRIS2::CanEditTracks() const {
return false;
}
TrackMetadata MPRIS2::GetTracksMetadata(const TrackIds &tracks) const {
//TODO
return TrackMetadata();
}
void MPRIS2::AddTrack(const QString &uri, const QDBusObjectPath &afterTrack, bool setAsCurrent) {
//TODO
}
void MPRIS2::RemoveTrack(const QDBusObjectPath &trackId) {
//TODO
}
void MPRIS2::GoTo(const QDBusObjectPath &trackId) {
//TODO
}