Added multi-device support for mpris, and current track reporting
This commit is contained in:
parent
7b0bbebc02
commit
2c1d63bf4d
6 changed files with 112 additions and 15 deletions
|
@ -45,7 +45,7 @@ void TcpDeviceLink::dataReceived()
|
||||||
|
|
||||||
if (package.length() < 3) continue;
|
if (package.length() < 3) continue;
|
||||||
|
|
||||||
NetworkPackage np;
|
NetworkPackage np("");
|
||||||
NetworkPackage::unserialize(package,&np);
|
NetworkPackage::unserialize(package,&np);
|
||||||
|
|
||||||
emit receivedPackage(np);
|
emit receivedPackage(np);
|
||||||
|
|
|
@ -49,7 +49,7 @@ void AvahiTcpLinkProvider::newConnection()
|
||||||
|
|
||||||
connect(socket,SIGNAL(readyRead()),this,SLOT(dataReceived()));
|
connect(socket,SIGNAL(readyRead()),this,SLOT(dataReceived()));
|
||||||
|
|
||||||
NetworkPackage np;
|
NetworkPackage np(PACKAGE_TYPE_IDENTITY);
|
||||||
NetworkPackage::createIdentityPackage(&np);
|
NetworkPackage::createIdentityPackage(&np);
|
||||||
int written = socket->write(np.serialize());
|
int written = socket->write(np.serialize());
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ void AvahiTcpLinkProvider::dataReceived()
|
||||||
|
|
||||||
qDebug() << "AvahiTcpLinkProvider received reply:" << data;
|
qDebug() << "AvahiTcpLinkProvider received reply:" << data;
|
||||||
|
|
||||||
NetworkPackage np;
|
NetworkPackage np("");
|
||||||
NetworkPackage::unserialize(data,&np);
|
NetworkPackage::unserialize(data,&np);
|
||||||
|
|
||||||
if (np.version() > 0 && np.type() == PACKAGE_TYPE_IDENTITY) {
|
if (np.version() > 0 && np.type() == PACKAGE_TYPE_IDENTITY) {
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
LoopbackLinkProvider::LoopbackLinkProvider()
|
LoopbackLinkProvider::LoopbackLinkProvider()
|
||||||
|
: identityPackage(PACKAGE_TYPE_IDENTITY)
|
||||||
{
|
{
|
||||||
echoDeviceLink = new EchoDeviceLink("fake", this);
|
echoDeviceLink = new EchoDeviceLink("fake", this);
|
||||||
NetworkPackage::createIdentityPackage(&identityPackage);
|
NetworkPackage::createIdentityPackage(&identityPackage);
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
#include <QStringList>
|
||||||
#include <qjson/parser.h>
|
#include <qjson/parser.h>
|
||||||
#include "default_args.h"
|
#include "default_args.h"
|
||||||
|
|
||||||
|
@ -38,7 +39,6 @@ class NetworkPackage : public QObject
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
NetworkPackage() {};
|
|
||||||
NetworkPackage(QString type);
|
NetworkPackage(QString type);
|
||||||
|
|
||||||
static void unserialize(QByteArray, NetworkPackage*);
|
static void unserialize(QByteArray, NetworkPackage*);
|
||||||
|
@ -52,10 +52,12 @@ public:
|
||||||
int version() const { return mVersion; }
|
int version() const { return mVersion; }
|
||||||
|
|
||||||
//Get and set info from body. Note that id, type and version can not be accessed through these.
|
//Get and set info from body. Note that id, type and version can not be accessed through these.
|
||||||
template<typename T> T get(const QString& property, const T& defaultValue = default_arg<T>::get()) const {
|
template<typename T> T get(const QString& key, const T& defaultValue = default_arg<T>::get()) const {
|
||||||
return mBody.value(property,defaultValue).template value<T>(); //Important note: Awesome template syntax is awesome
|
return mBody.value(key,defaultValue).template value<T>(); //Important note: Awesome template syntax is awesome
|
||||||
}
|
}
|
||||||
template<typename T> void set(const QString& property, const T& value) { mBody[property] = value; }
|
template<typename T> void set(const QString& key, const T& value) { mBody[key] = QVariant(value); }
|
||||||
|
|
||||||
|
bool has(const QString& key) { return mBody.contains(key); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setId(long id) { mId = id; }
|
void setId(long id) { mId = id; }
|
||||||
|
@ -70,5 +72,7 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//Set specialization need this awesome-to-the-max syntax:
|
||||||
|
//template<> inline void NetworkPackage::set<QStringList>(const QString& key, const QStringList& value) { mBody[key] = QVariant(value); }
|
||||||
|
|
||||||
#endif // NETWORKPACKAGE_H
|
#endif // NETWORKPACKAGE_H
|
||||||
|
|
|
@ -29,7 +29,60 @@
|
||||||
|
|
||||||
MprisControlPackageInterface::MprisControlPackageInterface()
|
MprisControlPackageInterface::MprisControlPackageInterface()
|
||||||
{
|
{
|
||||||
//TODO: Emit info read form mpris to the phone
|
|
||||||
|
//Detect new interfaces
|
||||||
|
connect(QDBusConnection::sessionBus().interface(), SIGNAL(serviceOwnerChanged(QString,QString,QString)),
|
||||||
|
this, SLOT(serviceOwnerChanged(QString,QString,QString)));
|
||||||
|
|
||||||
|
//Add existing interfaces
|
||||||
|
QStringList interfaces = QDBusConnection::sessionBus().interface()->registeredServiceNames().value();
|
||||||
|
Q_FOREACH (const QString& iface, interfaces) {
|
||||||
|
if (iface.startsWith("org.mpris.MediaPlayer2")) {
|
||||||
|
addPlayer(iface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void MprisControlPackageInterface::serviceOwnerChanged(const QString &name,
|
||||||
|
const QString &oldOwner,
|
||||||
|
const QString &newOwner)
|
||||||
|
{
|
||||||
|
Q_UNUSED(oldOwner);
|
||||||
|
|
||||||
|
if (name.startsWith("org.mpris.MediaPlayer2")) {
|
||||||
|
|
||||||
|
qDebug() << "Something registered in bus" << name << oldOwner << newOwner;
|
||||||
|
|
||||||
|
if (oldOwner.isEmpty()) {
|
||||||
|
addPlayer(name);
|
||||||
|
} else if (newOwner.isEmpty()) {
|
||||||
|
removePlayer(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MprisControlPackageInterface::addPlayer(const QString& ifaceName)
|
||||||
|
{
|
||||||
|
QDBusInterface interface(ifaceName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2");
|
||||||
|
//TODO: Make this async
|
||||||
|
QString identity = interface.property("Identity").toString();
|
||||||
|
playerList[identity] = ifaceName;
|
||||||
|
qDebug() << "addPlayer" << ifaceName << identity;
|
||||||
|
sendPlayerList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MprisControlPackageInterface::removePlayer(const QString& ifaceName)
|
||||||
|
{
|
||||||
|
playerList.remove(playerList.key(ifaceName));
|
||||||
|
sendPlayerList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MprisControlPackageInterface::sendPlayerList()
|
||||||
|
{
|
||||||
|
NetworkPackage np(PACKAGE_TYPE_MPRIS);
|
||||||
|
np.set("playerList",playerList.keys());
|
||||||
|
sendPackage(np);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MprisControlPackageInterface::receivePackage (const Device& device, const NetworkPackage& np)
|
bool MprisControlPackageInterface::receivePackage (const Device& device, const NetworkPackage& np)
|
||||||
|
@ -38,16 +91,40 @@ bool MprisControlPackageInterface::receivePackage (const Device& device, const N
|
||||||
|
|
||||||
if (np.type() != PACKAGE_TYPE_MPRIS) return false;
|
if (np.type() != PACKAGE_TYPE_MPRIS) return false;
|
||||||
|
|
||||||
QString action = np.get<QString>("action");
|
|
||||||
|
|
||||||
QStringList interfaces = QDBusConnection::sessionBus().interface()->registeredServiceNames().value();
|
QString player = np.get<QString>("player");
|
||||||
Q_FOREACH (const QString& iface, interfaces) {
|
if (!playerList.contains(player)) {
|
||||||
if (iface.startsWith("org.mpris.MediaPlayer2")) {
|
sendPlayerList();
|
||||||
QDBusInterface mprisInterface(iface, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2.Player");
|
return true;
|
||||||
mprisInterface.asyncCall(action);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QDBusInterface mprisInterface(playerList[player], "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2.Player");
|
||||||
|
|
||||||
|
if (np.get<bool>("requestPlayerList")) {
|
||||||
|
sendPlayerList();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString action = np.get<QString>("action");
|
||||||
|
if (!action.isEmpty()) {
|
||||||
|
qDebug() << "Calling action" << action << "in" << playerList[player];
|
||||||
|
mprisInterface.call(action);
|
||||||
|
sendNowPlaying(mprisInterface);
|
||||||
|
} else if (np.get<bool>("requestNowPlaying")) {
|
||||||
|
sendNowPlaying(mprisInterface);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MprisControlPackageInterface::sendNowPlaying(const QDBusInterface& mprisInterface)
|
||||||
|
{
|
||||||
|
QVariantMap nowPlayingMap = mprisInterface.property("Metadata").toMap();
|
||||||
|
QString nowPlaying = nowPlayingMap["xesam:title"].toString();
|
||||||
|
if (nowPlayingMap.contains("xesam:artist")) {
|
||||||
|
nowPlaying = nowPlayingMap["xesam:artist"].toString() + " - " + nowPlaying;
|
||||||
|
}
|
||||||
|
NetworkPackage np(PACKAGE_TYPE_MPRIS);
|
||||||
|
np.set("nowPlaying",nowPlaying);
|
||||||
|
sendPackage(np);
|
||||||
|
}
|
||||||
|
|
|
@ -25,14 +25,29 @@
|
||||||
|
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QDBusArgument>
|
||||||
|
|
||||||
class MprisControlPackageInterface
|
class MprisControlPackageInterface
|
||||||
: public PackageInterface
|
: public PackageInterface
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MprisControlPackageInterface();
|
MprisControlPackageInterface();
|
||||||
virtual bool receivePackage(const Device& device, const NetworkPackage& np);
|
virtual bool receivePackage(const Device& device, const NetworkPackage& np);
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QHash<QString, QString> playerList;
|
||||||
|
void addPlayer(const QString& ifaceName);
|
||||||
|
void removePlayer(const QString& ifaceName);
|
||||||
|
void sendPlayerList();
|
||||||
|
void sendNowPlaying(const QDBusInterface& interface);
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue