/* -*- 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()); }