/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2020 KylinSoft Co., Ltd.
*
* This program 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
* any later version.
*
* This program 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 this program. If not, see .
*/
#include
#include
#include
#include "mpris-manager.h"
#include
const QString MPRIS_OBJECT_PATH = "/org/mpris/MediaPlayer2";
const QString MPRIS_INTERFACE = "org.mpris.MediaPlayer2.Player";
const QString MPRIS_PREFIX = "org.mpris.MediaPlayer2.";
const QString DBUS_NAME = "org.ukui.SettingsDaemon";
const QString DBUS_PATH = "/org/ukui/SettingsDaemon";
const QString MEDIAKEYS_DBUS_NAME = DBUS_NAME + ".MediaKeys";
const QString MEDIAKEYS_DBUS_PATH = DBUS_PATH + "/MediaKeys";
/* Number of media players supported.
* Correlates to the number of elements in BUS_NAMES */
const int NUM_BUS_NAMES = 16;
/* Names to we want to watch */
const QStringList busNames ={"org.mpris.MediaPlayer2.audacious",
"org.mpris.MediaPlayer2.clementine",
"org.mpris.MediaPlayer2.vlc",
"org.mpris.MediaPlayer2.mpd",
"org.mpris.MediaPlayer2.exaile",
"org.mpris.MediaPlayer2.banshee",
"org.mpris.MediaPlayer2.rhythmbox",
"org.mpris.MediaPlayer2.pragha",
"org.mpris.MediaPlayer2.quodlibet",
"org.mpris.MediaPlayer2.guayadeque",
"org.mpris.MediaPlayer2.amarok",
"org.mpris.MediaPlayer2.nuvolaplayer",
"org.mpris.MediaPlayer2.xbmc",
"org.mpris.MediaPlayer2.xnoise",
"org.mpris.MediaPlayer2.gmusicbrowser",
"org.mpris.MediaPlayer2.spotify",
"org.mpris.MediaPlayer2.KylinVideo",
};
MprisManager* MprisManager::mMprisManager = nullptr;
MprisManager::MprisManager(QObject *parent):QObject(parent)
{
}
MprisManager::~MprisManager()
{
}
bool MprisManager::MprisManagerStart (GError **error)
{
QStringList list;
QDBusConnection conn = QDBusConnection::sessionBus();
QDBusMessage tmpMsg,response ;
mPlayerQuque = new QQueue();
mDbusWatcher = new QDBusServiceWatcher();
mDbusWatcher->setWatchMode(QDBusServiceWatcher::WatchForRegistration |
QDBusServiceWatcher::WatchForUnregistration);
mDbusWatcher->setConnection(conn);
mDbusInterface = new QDBusInterface(DBUS_NAME,MEDIAKEYS_DBUS_PATH,MEDIAKEYS_DBUS_NAME,
conn);
syslog (LOG_DEBUG,"Starting mpris manager");
/* Register all the names we wish to watch.*/
mDbusWatcher->setWatchedServices(busNames);
mDbusWatcher->addWatchedService(DBUS_NAME);
connect(mDbusWatcher,SIGNAL(serviceRegistered(const QString&)),this,SLOT(serviceRegisteredSlot(const QString&)));
connect(mDbusWatcher,SIGNAL(serviceUnregistered(const QString&)),this,SLOT(serviceUnregisteredSlot(const QString&)));
if(!mDbusInterface->isValid()){
syslog(LOG_ERR,"create %s failed",MEDIAKEYS_DBUS_NAME.toLatin1().data());
return false;
}
/** create a dbus method call by QDBusInterface。here we call GrabMediaPlayerKeys(QString) from "org.ukui.SettingsDaemon.MediaKeys",
* you can find it's definition at media-keys mprismanager.cpp
*
* 通过QDBusInterface的方式创建一个dbus方法调用。这里我们调用的方法是来自org.ukui.SettingsDaemon.MediaKeys的
* GrabMediaPlayerKeys(QString), 你可以在media-keys插件内的mprismanager.cpp找到它的定义
*/
response = mDbusInterface->call("GrabMediaPlayerKeys","UsdMpris");
if(QDBusMessage::ErrorMessage == response.ReplyMessage){
syslog(LOG_ERR,"error: %s",response.errorMessage().toLatin1().data());
return false;
}
/** wait signal MediaPlayerKeyPressed() from "org.ukui.SettingsDaemon.MediaKeys"
* you can find it's definition at media-keys mprismanager.h
*
* 等待连接来自于org.ukui.SettingsDaemon.MediaKeys的MediaPlayerKeyPressed()信号
* 你可以在media-keys 插件的 mrpismanager.h文件内找到它的定义
*/
connect(mDbusInterface,SIGNAL(MediaPlayerKeyPressed(QString,QString)),
this,SLOT(keyPressed(QString,QString)));
return true;
}
void MprisManager::MprisManagerStop()
{
syslog (LOG_DEBUG,"Stopping mpris manager");
delete mDbusInterface;
mDbusInterface = nullptr;
delete mDbusWatcher;
mDbusWatcher = nullptr;
mPlayerQuque->clear();
delete mPlayerQuque;
mPlayerQuque = nullptr;
}
MprisManager* MprisManager::MprisManagerNew()
{
if(nullptr == mMprisManager)
mMprisManager = new MprisManager();
return mMprisManager;
}
/** Returns the name of the media player.
* @name if @name=="org.mpris.MediaPlayer2.vlc"
* @return then @return=="vlc"
*/
QString getPlayerName(const QString& name)
{
QString ret_name=name.section(".",3,4);
return ret_name;
}
void MprisManager::serviceRegisteredSlot(const QString& service)
{
QString realPlayername;
syslog (LOG_DEBUG,"MPRIS Name Registered: %s\n", service.toLatin1().data());
if(DBUS_NAME == service){
return;
}else{
/* A media player was just run and should be
* added to the head of @mPlayerQuque.
*/
realPlayername = getPlayerName(service);
mPlayerQuque->push_front(realPlayername);
}
}
/**
* @brief MprisManager::serviceUnregisteredSlot
* if anyone dbus service that from @busNames quit,this func will be called.
* 如果来自于@busNames的任意一个dbus服务关闭,则该函数被执行
* @param service
* for example: @service can be "org.mpris.MediaPlayer2.vlc"
*/
void MprisManager::serviceUnregisteredSlot(const QString& service)
{
QString realPlayername;
syslog (LOG_DEBUG,"MPRIS Name Unregistered: %s\n", service.toLatin1().data());
if(DBUS_NAME == service){
if(nullptr != mDbusInterface){
delete mDbusInterface;
mDbusInterface = nullptr;
}
}else{
/* A media player quit running and should be removed from @mPlayerQueue.
* 一个媒体播放器退出时应当从@mPlayerQueue中移除
*/
realPlayername = getPlayerName(service);
if(mPlayerQuque->contains(realPlayername))
mPlayerQuque->removeOne(realPlayername);
}
}
/**
* @brief MprisManager::keyPressed
* after catch MediaPlayerKeyPressed() signal, this function will be called
* 在接收到MediaPlayerKeyPressed() signal后,这个函数将被调用
* @param application @application=="UsdMpris" is true
* @param operation
* we control media player by @operation value,for example: play 、pause 、stop
* 我们通过@operation的值去控制媒体播放器,如: 播放、暂停、停止
*/
void MprisManager::keyPressed(QString application,QString operation)
{
QString mprisKey = nullptr;
QString mprisHead,mprisName;
QDBusMessage playerMsg,response;
if("UsdMpris" != application)
return;
if(mPlayerQuque->isEmpty())
return;
if("Play" == operation)
mprisKey = "PlayPause";
else if("Pause" == operation)
mprisKey = "Pause";
else if("Previous" == operation)
mprisKey = "Previous";
else if("Next" == operation)
mprisKey = "Next";
else if("Stop" == operation)
mprisKey = "Stop";
if(mprisKey.isNull())
return;
mprisHead = mPlayerQuque->head();
mprisName = MPRIS_PREFIX + mprisHead;
/* create a dbus method call by QDBusMessage, the @mprisName is a member of @busNames
* 通过QDBusMessage的方式创建一个dbus方法调用,@mprisName 来自于 @busNames
*/
playerMsg = QDBusMessage::createMethodCall(mprisName,MPRIS_OBJECT_PATH,MPRIS_INTERFACE,mprisKey);
response = QDBusConnection::sessionBus().call(playerMsg);
if(response.type() == QDBusMessage::ErrorMessage)
syslog(LOG_ERR,"error: %s",response.errorMessage().toLatin1().data());
}