Massively hacky basic integration to tomahawk.
This commit is contained in:
parent
7ca69e009e
commit
48b7dc3501
41
3rdparty/libxrme/connection.cpp
vendored
41
3rdparty/libxrme/connection.cpp
vendored
@ -24,22 +24,29 @@
|
||||
#include <QSocketNotifier>
|
||||
#include <QTimer>
|
||||
#include <QtDebug>
|
||||
#include <QVariant>
|
||||
|
||||
#include <gloox/capabilities.h>
|
||||
#include <gloox/client.h>
|
||||
#include <gloox/connectionlistener.h>
|
||||
#include <gloox/connectiontcpclient.h>
|
||||
#include <gloox/disco.h>
|
||||
#include <gloox/discohandler.h>
|
||||
#include <gloox/loghandler.h>
|
||||
#include <gloox/message.h>
|
||||
#include <gloox/messagehandler.h>
|
||||
#include <gloox/rosterlistener.h>
|
||||
#include <gloox/rostermanager.h>
|
||||
|
||||
#include <qjson/parser.h>
|
||||
|
||||
namespace xrme {
|
||||
|
||||
struct Connection::Private : public gloox::ConnectionListener,
|
||||
public gloox::LogHandler,
|
||||
public gloox::RosterListener,
|
||||
public gloox::DiscoHandler {
|
||||
public gloox::DiscoHandler,
|
||||
public gloox::MessageHandler {
|
||||
Private(Connection* parent)
|
||||
: parent_(parent),
|
||||
server_(kDefaultServer),
|
||||
@ -126,10 +133,13 @@ struct Connection::Private : public gloox::ConnectionListener,
|
||||
void handleDiscoInfo(const gloox::JID&, const gloox::Disco::Info&, int);
|
||||
void handleDiscoItems(const gloox::JID&, const gloox::Disco::Items&, int);
|
||||
void handleDiscoError(const gloox::JID&, const gloox::Error*, int);
|
||||
|
||||
// gloox::MessageHandler
|
||||
void handleMessage(const gloox::Message& message, gloox::MessageSession* session);
|
||||
};
|
||||
|
||||
const char* Connection::Private::kDefaultServer = "talk.google.com";
|
||||
const char* Connection::Private::kDefaultJIDResource = "xrmeagent";
|
||||
const char* Connection::Private::kDefaultJIDResource = "tomahawkxrmeagent";
|
||||
const char* Connection::Private::kDefaultJIDHost = "gmail.com";
|
||||
|
||||
|
||||
@ -245,15 +255,13 @@ bool Connection::Connect() {
|
||||
d->client_->rosterManager()->registerRosterListener(d.data());
|
||||
d->client_->logInstance().registerLogHandler(
|
||||
gloox::LogLevelDebug, gloox::LogAreaAll, d.data());
|
||||
d->client_->registerMessageHandler(d.data());
|
||||
|
||||
// Setup disco
|
||||
d->client_->disco()->setIdentity("client", "bot");
|
||||
d->client_->disco()->setVersion(d->agent_name_.toUtf8().constData(), std::string());
|
||||
d->client_->disco()->addFeature(kXmlnsXrme);
|
||||
|
||||
// Tomahawk support
|
||||
d->client_->disco()->addFeature("tomahawk:player");
|
||||
|
||||
d->media_player_extension_ = new MediaPlayerExtension;
|
||||
d->remote_control_extension_ = new RemoteControlExtension;
|
||||
d->client_->registerStanzaExtension(d->media_player_extension_);
|
||||
@ -265,7 +273,13 @@ bool Connection::Connect() {
|
||||
}
|
||||
|
||||
// Set presence
|
||||
d->client_->setPresence(gloox::Presence::Available, -128);
|
||||
d->client_->setPresence(gloox::Presence::Available, 1);
|
||||
|
||||
// Tomahawk support
|
||||
d->client_->disco()->addFeature("tomahawk:player");
|
||||
gloox::Capabilities* caps = new gloox::Capabilities;
|
||||
caps->setNode("http://tomahawk-player.org/");
|
||||
d->client_->presence().addExtension(caps);
|
||||
|
||||
d->client_->setSASLMechanisms(gloox::SaslMechGoogleToken);
|
||||
|
||||
@ -529,4 +543,19 @@ void Connection::Private::handleDiscoError(
|
||||
}
|
||||
}
|
||||
|
||||
void Connection::Private::handleMessage(const gloox::Message& message, gloox::MessageSession* session) {
|
||||
qDebug() << Q_FUNC_INFO << message.tag()->xml().c_str();
|
||||
const std::string body = message.body();
|
||||
qDebug() << body.c_str();
|
||||
|
||||
QJson::Parser parser;
|
||||
bool ok = false;
|
||||
QVariant result = parser.parse(QByteArray::fromRawData(body.data(), body.size()), &ok);
|
||||
if (ok) {
|
||||
qDebug() << result;
|
||||
|
||||
emit parent_->TomahawkSIPReceived(result);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace xrme
|
||||
|
2
3rdparty/libxrme/connection.h
vendored
2
3rdparty/libxrme/connection.h
vendored
@ -137,6 +137,8 @@ signals:
|
||||
void PeerFound(const xrme::Connection::Peer& peer);
|
||||
void PeerRemoved(const xrme::Connection::Peer& peer);
|
||||
|
||||
void TomahawkSIPReceived(const QVariant& json);
|
||||
|
||||
private slots:
|
||||
void SocketReadyReceive();
|
||||
void CleanupClient();
|
||||
|
@ -941,6 +941,7 @@ if(HAVE_REMOTE)
|
||||
target_link_libraries(clementine_lib ${GLOOX_LIBRARIES})
|
||||
target_link_libraries(clementine_lib xrme)
|
||||
target_link_libraries(clementine_lib portfwd)
|
||||
target_link_libraries(clementine_lib qjson)
|
||||
link_directories(${GLOOX_LIBRARY_DIRS})
|
||||
endif(HAVE_REMOTE)
|
||||
|
||||
|
@ -22,9 +22,14 @@
|
||||
#include "playlist/playlist.h"
|
||||
#include "playlist/playlistmanager.h"
|
||||
|
||||
#include <QDataStream>
|
||||
#include <QHostAddress>
|
||||
#include <QSettings>
|
||||
#include <QTimer>
|
||||
|
||||
#include <qjson/parser.h>
|
||||
#include <qjson/serializer.h>
|
||||
|
||||
Remote::Remote(Player* player, QObject* parent)
|
||||
: QObject(parent),
|
||||
player_(player),
|
||||
@ -44,6 +49,10 @@ Remote::Remote(Player* player, QObject* parent)
|
||||
connect(player_, SIGNAL(Seeked(qlonglong)), SLOT(SetStateChanged()));
|
||||
connect(player_->playlists(), SIGNAL(CurrentSongChanged(Song)), SLOT(SetStateChanged()));
|
||||
|
||||
connect(connection_,
|
||||
SIGNAL(TomahawkSIPReceived(const QVariant&)),
|
||||
SLOT(TomahawkSIPReceived(const QVariant&)));
|
||||
|
||||
ReloadSettings();
|
||||
}
|
||||
|
||||
@ -163,3 +172,266 @@ void Remote::ArtLoaded(const Song&, const QString&, const QImage& image) {
|
||||
last_image_ = image;
|
||||
AlbumArtChanged();
|
||||
}
|
||||
|
||||
void Remote::TomahawkSIPReceived(const QVariant& json) {
|
||||
QVariantMap message = json.toMap();
|
||||
const QString& ip = message["ip"].toString();
|
||||
const QString& key = message["key"].toString();
|
||||
const quint16 port = message["port"].toUInt();
|
||||
const QString& unique_name = message["uniqname"].toString();
|
||||
const bool visible = message["visible"].toBool();
|
||||
|
||||
QTcpSocket* socket = new QTcpSocket(this);
|
||||
socket->connectToHost(ip, port);
|
||||
connect(socket, SIGNAL(connected()), SLOT(TomahawkConnected()));
|
||||
connect(socket, SIGNAL(disconnected()), SLOT(TomahawkDisconnected()));
|
||||
connect(socket, SIGNAL(readyRead()), SLOT(TomahawkReadyRead()));
|
||||
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
|
||||
SLOT(TomahawkError(QAbstractSocket::SocketError)));
|
||||
|
||||
qDebug() << Q_FUNC_INFO << "connecting to" << ip << port;
|
||||
|
||||
TomahawkConnection* connection = new TomahawkConnection;
|
||||
connection->key = key;
|
||||
connection->unique_name = unique_name;
|
||||
connection->visible = visible;
|
||||
connection->num_bytes = -1;
|
||||
tomahawk_connections_[socket] = connection;
|
||||
}
|
||||
|
||||
void Remote::TomahawkConnected() {
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender());
|
||||
Q_ASSERT(socket);
|
||||
|
||||
TomahawkConnection* connection = tomahawk_connections_[socket];
|
||||
|
||||
QVariantMap map;
|
||||
map["conntype"] = "accept-offer";
|
||||
map["key"] = connection->key;
|
||||
map["port"] = 12345;
|
||||
map["nodeid"] = "foobar";
|
||||
map["controlid"] = "foobarbaz";
|
||||
|
||||
QJson::Serializer serialiser;
|
||||
const QByteArray& serialised = serialiser.serialize(map);
|
||||
quint32 length = serialised.length();
|
||||
|
||||
// Send offer acceptance.
|
||||
{
|
||||
QDataStream stream(socket);
|
||||
stream << (quint32)length;
|
||||
stream << (quint8)(128 | 2);
|
||||
stream.writeRawData(serialised.constData(), serialised.length());
|
||||
qDebug() << "now:" << socket->bytesToWrite();
|
||||
}
|
||||
|
||||
{
|
||||
QDataStream stream(socket);
|
||||
stream << (quint32)2;
|
||||
stream << (quint8)(128 | 1);
|
||||
stream.writeRawData("ok", 2);
|
||||
}
|
||||
|
||||
// Send ping.
|
||||
{
|
||||
QDataStream stream(socket);
|
||||
stream << (quint32)0;
|
||||
stream << (quint8)(32);
|
||||
}
|
||||
|
||||
/*
|
||||
{
|
||||
QVariantMap json;
|
||||
json["method"] = "dbsync-offer";
|
||||
json["key"] = "abcdefg";
|
||||
const QByteArray& request = serialiser.serialize(json);
|
||||
QDataStream stream(socket);
|
||||
stream << (quint32)request.length();
|
||||
stream << (quint8)2; // JSON
|
||||
stream.writeRawData(request.constData(), request.length());
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void Remote::TomahawkReadyRead() {
|
||||
QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender());
|
||||
Q_ASSERT(socket);
|
||||
|
||||
TomahawkConnection* connection = tomahawk_connections_[socket];
|
||||
if (connection->num_bytes == -1) {
|
||||
// Expecting header.
|
||||
if (socket->bytesAvailable() >= 5) {
|
||||
QDataStream stream(socket);
|
||||
quint32 size;
|
||||
stream >> size;
|
||||
quint8 flags;
|
||||
stream >> flags;
|
||||
connection->num_bytes = size > 0 ? size : -1;
|
||||
connection->flags = flags;
|
||||
if (flags & 32) {
|
||||
qDebug() << "PING!";
|
||||
}
|
||||
if (connection->num_bytes == -1) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (socket->bytesAvailable() < connection->num_bytes) {
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray data = socket->readAll();
|
||||
connection->num_bytes = -1;
|
||||
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
qDebug() << data;
|
||||
qDebug() << Q_FUNC_INFO << "done";
|
||||
|
||||
if (connection->flags & 2) {
|
||||
QJson::Parser parser;
|
||||
bool ok = false;
|
||||
QVariant json = parser.parse(data, &ok);
|
||||
if (ok) {
|
||||
QVariantMap map = json.toMap();
|
||||
QString method = map["method"].toString();
|
||||
if (method == "dbsync-offer") {
|
||||
qDebug() << "DBSYNC!";
|
||||
TomahawkConnection* db_connection = new TomahawkConnection;
|
||||
db_connection->key = map["key"].toString();
|
||||
db_connection->num_bytes = -1;
|
||||
QTcpSocket* sync_socket = new QTcpSocket(this);
|
||||
sync_socket->connectToHost(socket->peerAddress(), socket->peerPort());
|
||||
connect(sync_socket, SIGNAL(connected()), SLOT(TomahawkDBConnected()));
|
||||
connect(sync_socket, SIGNAL(disconnected()), SLOT(TomahawkDBDisconnected()));
|
||||
connect(sync_socket, SIGNAL(readyRead()), SLOT(TomahawkDBReadyRead()));
|
||||
tomahawk_connections_[sync_socket] = db_connection;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Remote::TomahawkDBConnected() {
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender());
|
||||
Q_ASSERT(socket);
|
||||
|
||||
TomahawkConnection* connection = tomahawk_connections_[socket];
|
||||
|
||||
{
|
||||
QVariantMap request;
|
||||
request["method"] = "accept-offer";
|
||||
request["key"] = connection->key;
|
||||
|
||||
QJson::Serializer serialiser;
|
||||
const QByteArray& json = serialiser.serialize(request);
|
||||
|
||||
QDataStream stream(socket);
|
||||
stream << (quint32)json.length();
|
||||
stream << (quint8)(2);
|
||||
stream.writeRawData(json.constData(), json.length());
|
||||
}
|
||||
|
||||
{
|
||||
QDataStream stream(socket);
|
||||
stream << (quint32)2;
|
||||
stream << (quint8)(128 | 1); // SETUP | RAW
|
||||
stream.writeRawData("ok", 2);
|
||||
}
|
||||
|
||||
{
|
||||
QVariantMap request;
|
||||
request["command"] = "addfiles";
|
||||
QVariantMap file;
|
||||
file["url"] = "http://data.clementine-player.org/rainymood";
|
||||
file["mtime"] = 123456;
|
||||
file["size"] = 1e7;
|
||||
file["hash"] = "abcdefg";
|
||||
file["mimetype"] = "audio/mpeg";
|
||||
file["duration"] = 1000;
|
||||
file["bitrate"] = 128;
|
||||
file["artist"] = "foo";
|
||||
file["album"] = "bar";
|
||||
file["track"] = "Rain!";
|
||||
file["albumpos"] = 1;
|
||||
file["year"] = 2011;
|
||||
QVariantList files;
|
||||
files << file;
|
||||
request["files"] = files;
|
||||
|
||||
QJson::Serializer serialiser;
|
||||
const QByteArray& json = serialiser.serialize(request);
|
||||
|
||||
qDebug() << json;
|
||||
|
||||
QDataStream stream(socket);
|
||||
stream << (quint32)json.length();
|
||||
stream << (quint8)(16 | 2); // DBOP | JSON
|
||||
stream.writeRawData(json.constData(), json.length());
|
||||
}
|
||||
}
|
||||
|
||||
void Remote::TomahawkDBReadyRead() {
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender());
|
||||
Q_ASSERT(socket);
|
||||
|
||||
TomahawkConnection* connection = tomahawk_connections_[socket];
|
||||
if (connection->num_bytes == -1) {
|
||||
// Expecting header.
|
||||
if (socket->bytesAvailable() >= 5) {
|
||||
QDataStream stream(socket);
|
||||
quint32 size;
|
||||
stream >> size;
|
||||
quint8 flags;
|
||||
stream >> flags;
|
||||
connection->num_bytes = size > 0 ? size : -1;
|
||||
connection->flags = flags;
|
||||
if (flags & 32) {
|
||||
qDebug() << "PING!";
|
||||
}
|
||||
if (connection->num_bytes == -1) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (socket->bytesAvailable() < connection->num_bytes) {
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray data = socket->readAll();
|
||||
connection->num_bytes = -1;
|
||||
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
qDebug() << data;
|
||||
qDebug() << Q_FUNC_INFO << "done";
|
||||
|
||||
if (connection->flags & 2) {
|
||||
QJson::Parser parser;
|
||||
bool ok = false;
|
||||
QVariant json = parser.parse(data, &ok);
|
||||
if (ok) {
|
||||
QVariantMap map = json.toMap();
|
||||
qDebug() << map;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Remote::TomahawkDBDisconnected() {
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
}
|
||||
|
||||
void Remote::TomahawkDisconnected() {
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
}
|
||||
|
||||
void Remote::TomahawkError(QAbstractSocket::SocketError error) {
|
||||
qDebug() << Q_FUNC_INFO << error;
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "core/song.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QTcpSocket>
|
||||
|
||||
#include <xrme/connection.h>
|
||||
#include <xrme/mediaplayerinterface.h>
|
||||
@ -59,6 +60,16 @@ private slots:
|
||||
|
||||
void SetStateChanged();
|
||||
|
||||
void TomahawkSIPReceived(const QVariant& json);
|
||||
void TomahawkConnected();
|
||||
void TomahawkDisconnected();
|
||||
void TomahawkReadyRead();
|
||||
void TomahawkError(QAbstractSocket::SocketError);
|
||||
|
||||
void TomahawkDBConnected();
|
||||
void TomahawkDBDisconnected();
|
||||
void TomahawkDBReadyRead();
|
||||
|
||||
private:
|
||||
bool is_configured() const;
|
||||
|
||||
@ -66,6 +77,16 @@ private:
|
||||
Player* player_;
|
||||
xrme::Connection* connection_;
|
||||
|
||||
struct TomahawkConnection {
|
||||
QString key;
|
||||
QString unique_name;
|
||||
bool visible;
|
||||
QTcpSocket* socket;
|
||||
int num_bytes;
|
||||
quint8 flags;
|
||||
};
|
||||
QMap<QTcpSocket*, TomahawkConnection*> tomahawk_connections_;
|
||||
|
||||
QImage last_image_;
|
||||
int retry_count_;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user