Beginnings of remote control support.
This commit is contained in:
parent
45a7780f95
commit
ce65c95580
|
@ -147,6 +147,10 @@ set(SOURCES
|
|||
radio/savedradio.cpp
|
||||
radio/somafmservice.cpp
|
||||
|
||||
remote/httpserver.cpp
|
||||
remote/httpconnection.cpp
|
||||
remote/zeroconf.cpp
|
||||
|
||||
smartplaylists/generator.cpp
|
||||
smartplaylists/generatorinserter.cpp
|
||||
smartplaylists/querygenerator.cpp
|
||||
|
@ -314,6 +318,9 @@ set(HEADERS
|
|||
radio/savedradio.h
|
||||
radio/somafmservice.h
|
||||
|
||||
remote/httpserver.h
|
||||
remote/httpconnection.h
|
||||
|
||||
smartplaylists/generator.h
|
||||
smartplaylists/generatorinserter.h
|
||||
smartplaylists/generatormimedata.h
|
||||
|
@ -513,19 +520,19 @@ if(HAVE_LIBLASTFM)
|
|||
)
|
||||
endif(HAVE_LIBLASTFM)
|
||||
|
||||
# OSDs
|
||||
if(APPLE)
|
||||
list(APPEND SOURCES widgets/osd_mac.mm)
|
||||
list(APPEND SOURCES core/macglobalshortcutbackend.mm)
|
||||
list(APPEND SOURCES devices/macdevicelister.mm)
|
||||
list(APPEND HEADERS devices/macdevicelister.h)
|
||||
list(APPEND SOURCES ui/macsystemtrayicon.mm)
|
||||
list(APPEND HEADERS core/macglobalshortcutbackend.h)
|
||||
list(APPEND HEADERS devices/macdevicelister.h)
|
||||
list(APPEND HEADERS ui/macscreensaver.h)
|
||||
list(APPEND HEADERS ui/macsystemtrayicon.h)
|
||||
list(APPEND HEADERS widgets/maclineedit.h)
|
||||
list(APPEND SOURCES widgets/maclineedit.mm)
|
||||
list(APPEND SOURCES core/macglobalshortcutbackend.mm)
|
||||
list(APPEND SOURCES devices/macdevicelister.mm)
|
||||
list(APPEND SOURCES remote/bonjour.mm)
|
||||
list(APPEND SOURCES ui/macscreensaver.cpp)
|
||||
list(APPEND HEADERS ui/macscreensaver.h)
|
||||
list(APPEND SOURCES ui/macsystemtrayicon.mm)
|
||||
list(APPEND SOURCES widgets/maclineedit.mm)
|
||||
list(APPEND SOURCES widgets/osd_mac.mm)
|
||||
include_directories(${GROWL}/Headers)
|
||||
else(APPLE)
|
||||
if(WIN32)
|
||||
|
|
36
src/main.cpp
36
src/main.cpp
|
@ -38,6 +38,8 @@
|
|||
#include "engines/enginebase.h"
|
||||
#include "library/directory.h"
|
||||
#include "playlist/playlist.h"
|
||||
#include "remote/httpserver.h"
|
||||
#include "remote/zeroconf.h"
|
||||
#include "smartplaylists/generator.h"
|
||||
#include "ui/equalizer.h"
|
||||
#include "ui/iconloader.h"
|
||||
|
@ -111,21 +113,23 @@ int main(int argc, char *argv[]) {
|
|||
// This must go before QApplication initialisation.
|
||||
mac::MacMain();
|
||||
|
||||
// Bump the soft limit for the number of file descriptors from the default of 256 to
|
||||
// the maximum (usually 10240).
|
||||
struct rlimit limit;
|
||||
getrlimit(RLIMIT_NOFILE, &limit);
|
||||
{
|
||||
// Bump the soft limit for the number of file descriptors from the default of 256 to
|
||||
// the maximum (usually 10240).
|
||||
struct rlimit limit;
|
||||
getrlimit(RLIMIT_NOFILE, &limit);
|
||||
|
||||
// getrlimit() lies about the hard limit so we have to check sysctl.
|
||||
int max_fd = 0;
|
||||
size_t len = sizeof(max_fd);
|
||||
sysctlbyname("kern.maxfilesperproc", &max_fd, &len, NULL, 0);
|
||||
// getrlimit() lies about the hard limit so we have to check sysctl.
|
||||
int max_fd = 0;
|
||||
size_t len = sizeof(max_fd);
|
||||
sysctlbyname("kern.maxfilesperproc", &max_fd, &len, NULL, 0);
|
||||
|
||||
limit.rlim_cur = max_fd;
|
||||
int ret = setrlimit(RLIMIT_NOFILE, &limit);
|
||||
limit.rlim_cur = max_fd;
|
||||
int ret = setrlimit(RLIMIT_NOFILE, &limit);
|
||||
|
||||
if (ret == 0) {
|
||||
qDebug() << "Max fd:" << max_fd;
|
||||
if (ret == 0) {
|
||||
qDebug() << "Max fd:" << max_fd;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -269,6 +273,14 @@ int main(int argc, char *argv[]) {
|
|||
// Seed the random number generator
|
||||
srand(time(NULL));
|
||||
|
||||
Zeroconf* zeroconf = Zeroconf::GetZeroconf();
|
||||
if (zeroconf) {
|
||||
HttpServer* server = new HttpServer;
|
||||
server->Listen(QHostAddress::Any, 12345);
|
||||
|
||||
zeroconf->Publish("local", "_clementine._tcp", "Clementine", 12345);
|
||||
}
|
||||
|
||||
// Window
|
||||
MainWindow w;
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef BONJOUR_H
|
||||
#define BONJOUR_H
|
||||
|
||||
#include "zeroconf.h"
|
||||
|
||||
class BonjourWrapper;
|
||||
|
||||
class Bonjour : public Zeroconf {
|
||||
public:
|
||||
Bonjour();
|
||||
virtual ~Bonjour();
|
||||
void Publish(const QString& domain, const QString& type, const QString& name, quint16 port);
|
||||
|
||||
private:
|
||||
BonjourWrapper* wrapper_;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,84 @@
|
|||
#include "bonjour.h"
|
||||
|
||||
#include <QtDebug>
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface NetServicePublicationDelegate : NSObject <NSNetServiceDelegate> {
|
||||
NSMutableArray* services_;
|
||||
}
|
||||
|
||||
- (void)netServiceWillPublish:(NSNetService*)netService;
|
||||
- (void)netService:(NSNetService*)netService
|
||||
didNotPublish:(NSDictionary*)errorDict;
|
||||
- (void)netServiceDidStop:(NSNetService*)netService;
|
||||
|
||||
@end
|
||||
|
||||
@implementation NetServicePublicationDelegate
|
||||
|
||||
- (id)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
services_ = [[NSMutableArray alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[services_ release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)netServiceWillPublish: (NSNetService*)netService {
|
||||
[services_ addObject: netService];
|
||||
qDebug() << Q_FUNC_INFO
|
||||
<< [[netService name] UTF8String];
|
||||
}
|
||||
|
||||
- (void)netService: (NSNetService*)netService didNotPublish: (NSDictionary*)errorDict {
|
||||
[services_ removeObject: netService];
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
NSLog(@"%@", errorDict);
|
||||
}
|
||||
|
||||
- (void)netServiceDidStop: (NSNetService*)netService {
|
||||
[services_ removeObject: netService];
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
class BonjourWrapper {
|
||||
public:
|
||||
BonjourWrapper() {
|
||||
delegate_ = [[NetServicePublicationDelegate alloc] init];
|
||||
}
|
||||
|
||||
NetServicePublicationDelegate* delegate() const { return delegate_; }
|
||||
|
||||
private:
|
||||
NetServicePublicationDelegate* delegate_;
|
||||
};
|
||||
|
||||
#define QSTRING_TO_NSSTRING(x) \
|
||||
[[NSString alloc] initWithUTF8String:x.toUtf8().constData()]
|
||||
|
||||
Bonjour::Bonjour()
|
||||
: wrapper_(new BonjourWrapper) {
|
||||
}
|
||||
|
||||
Bonjour::~Bonjour() {
|
||||
delete wrapper_;
|
||||
}
|
||||
|
||||
void Bonjour::Publish(const QString& domain, const QString& type, const QString& name, quint16 port) {
|
||||
NSNetService* service = [[NSNetService alloc] initWithDomain: QSTRING_TO_NSSTRING(domain)
|
||||
type: QSTRING_TO_NSSTRING(type)
|
||||
name: QSTRING_TO_NSSTRING(name)
|
||||
port: port];
|
||||
if (service) {
|
||||
[service setDelegate: wrapper_->delegate()];
|
||||
[service publish];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
#include "httpconnection.h"
|
||||
|
||||
#include <QStringList>
|
||||
#include <QTcpSocket>
|
||||
|
||||
HttpConnection::HttpConnection(QTcpSocket* socket)
|
||||
: QObject(socket),
|
||||
socket_(socket),
|
||||
state_(WaitingForRequest) {
|
||||
connect(socket_, SIGNAL(readyRead()), SLOT(ReadyRead()));
|
||||
}
|
||||
|
||||
void HttpConnection::ReadyRead() {
|
||||
switch (state_) {
|
||||
case WaitingForRequest:
|
||||
if (socket_->canReadLine()) {
|
||||
QString line = socket_->readLine();
|
||||
if (ParseRequest(line)) {
|
||||
state_ = WaitingForHeaders;
|
||||
} else {
|
||||
state_ = Error;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WaitingForHeaders:
|
||||
while (socket_->canReadLine()) {
|
||||
QByteArray line = socket_->readLine();
|
||||
if (line == "\r\n") {
|
||||
DoRequest();
|
||||
state_ = Finished;
|
||||
} else {
|
||||
// TODO: Parse headers.
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (state_ == Error) {
|
||||
socket_->close();
|
||||
return;
|
||||
}
|
||||
|
||||
if (socket_->canReadLine()) {
|
||||
ReadyRead();
|
||||
}
|
||||
}
|
||||
|
||||
bool HttpConnection::ParseRequest(const QString& line) {
|
||||
QStringList tokens = line.split(' ', QString::SkipEmptyParts);
|
||||
if (tokens.length() != 3) {
|
||||
return false;
|
||||
}
|
||||
const QString& method = tokens[0];
|
||||
if (method != "GET") {
|
||||
return false;
|
||||
}
|
||||
|
||||
method_ = QNetworkAccessManager::GetOperation;
|
||||
path_ = tokens[1];
|
||||
return true;
|
||||
}
|
||||
|
||||
void HttpConnection::DoRequest() {
|
||||
socket_->write("HTTP/1.0 200 OK\r\n");
|
||||
socket_->write("Content-type: application/json\r\n");
|
||||
socket_->write("\r\n");
|
||||
socket_->write("{content:'Hello World!'}");
|
||||
socket_->close();
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef HTTPCONNECTION_H
|
||||
#define HTTPCONNECTION_H
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QString>
|
||||
|
||||
class QTcpSocket;
|
||||
|
||||
class HttpConnection : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
HttpConnection(QTcpSocket* sock);
|
||||
|
||||
private slots:
|
||||
void ReadyRead();
|
||||
|
||||
private:
|
||||
void DoRequest();
|
||||
bool ParseRequest(const QString& line);
|
||||
|
||||
QTcpSocket* socket_;
|
||||
|
||||
enum State {
|
||||
WaitingForRequest,
|
||||
WaitingForHeaders,
|
||||
WaitingForRequestFinish,
|
||||
Finished,
|
||||
Error,
|
||||
} state_;
|
||||
|
||||
QNetworkAccessManager::Operation method_;
|
||||
QString path_;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,28 @@
|
|||
#include "httpserver.h"
|
||||
|
||||
#include <QTcpSocket>
|
||||
|
||||
#include "httpconnection.h"
|
||||
|
||||
HttpServer::HttpServer(QObject* parent)
|
||||
: QObject(parent) {
|
||||
connect(&server_, SIGNAL(newConnection()), SLOT(NewConnection()));
|
||||
}
|
||||
|
||||
bool HttpServer::Listen(const QHostAddress& addr, quint16 port) {
|
||||
return server_.listen(addr, port);
|
||||
}
|
||||
|
||||
void HttpServer::NewConnection() {
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
QTcpSocket* socket = server_.nextPendingConnection();
|
||||
HttpConnection* conn = new HttpConnection(socket);
|
||||
}
|
||||
|
||||
void HttpServer::ReadyRead() {
|
||||
QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender());
|
||||
Q_ASSERT(socket);
|
||||
while (socket->canReadLine()) {
|
||||
QByteArray line = socket->readLine();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef HTTPSERVER_H
|
||||
#define HTTPSERVER_H
|
||||
|
||||
#include <QTcpServer>
|
||||
|
||||
class HttpServer : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
HttpServer(QObject* parent = 0);
|
||||
bool Listen(const QHostAddress& addr, quint16 port);
|
||||
|
||||
private slots:
|
||||
void NewConnection();
|
||||
void ReadyRead();
|
||||
|
||||
private:
|
||||
QTcpServer server_;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,17 @@
|
|||
#include "zeroconf.h"
|
||||
|
||||
#ifdef Q_OS_DARWIN
|
||||
#include "bonjour.h"
|
||||
#endif
|
||||
|
||||
Zeroconf* Zeroconf::instance_ = NULL;
|
||||
|
||||
Zeroconf* Zeroconf::GetZeroconf() {
|
||||
if (!instance_) {
|
||||
#ifdef Q_OS_DARWIN
|
||||
return new Bonjour();
|
||||
#endif
|
||||
}
|
||||
|
||||
return instance_;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef ZEROCONF_H
|
||||
#define ZEROCONF_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
class Zeroconf {
|
||||
public:
|
||||
virtual void Publish(
|
||||
const QString& domain, const QString& type, const QString& name, quint16 port) = 0;
|
||||
|
||||
static Zeroconf* GetZeroconf();
|
||||
|
||||
private:
|
||||
static Zeroconf* instance_;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue