Reimplemented broadcaster so it can send 503 when a connection is in
place. Removed qcma/cmaserver class and reimplemented them in cmaclient. Make sure that the scanned files are sorted by filename. Implement filters so the database doesn't pick up unsupported formats. Implement album cover display for album listing in the vita. Fixed bug with streaming of pictures in wireless mode. Some code refactoring.
This commit is contained in:
@@ -52,7 +52,10 @@ bool DeviceCapability::exchangeInfo(vita_device_t *device)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
VitaMTP_Data_Free_Capability(vita_capabilities); // TODO: Use this data
|
// TODO: vitamtp needs to send the full metadata info to know the expected format
|
||||||
|
// of thumbnails, for example. Until then lets discard the received info.
|
||||||
|
|
||||||
|
VitaMTP_Data_Free_Capability(vita_capabilities);
|
||||||
// Send the host's capabilities
|
// Send the host's capabilities
|
||||||
capability_info_t *pc_capabilities = generate_pc_capability_info();
|
capability_info_t *pc_capabilities = generate_pc_capability_info();
|
||||||
|
|
||||||
|
101
cmabroadcast.cpp
Normal file
101
cmabroadcast.cpp
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Codestation
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* (at your option) 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "cmabroadcast.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QHostInfo>
|
||||||
|
#include <QMutexLocker>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <QUuid>
|
||||||
|
|
||||||
|
#include <vitamtp.h>
|
||||||
|
|
||||||
|
const QString CmaBroadcast::broadcast_reply =
|
||||||
|
"%1\r\n"
|
||||||
|
"host-id:%2\r\n"
|
||||||
|
"host-type:%3\r\n"
|
||||||
|
"host-name:%4\r\n"
|
||||||
|
"host-mtp-protocol-version:%5\r\n"
|
||||||
|
"host-request-port:%6\r\n"
|
||||||
|
"host-wireless-protocol-version:%7\r\n";
|
||||||
|
|
||||||
|
const char *CmaBroadcast::broadcast_query = "SRCH * HTTP/1.1\r\n";
|
||||||
|
|
||||||
|
const char *CmaBroadcast::broadcast_ok = "HTTP/1.1 200 OK";
|
||||||
|
const char *CmaBroadcast::broadcast_unavailable = "HTTP/1.1 503 NG";
|
||||||
|
|
||||||
|
CmaBroadcast::CmaBroadcast(QObject *parent) :
|
||||||
|
QObject(parent)
|
||||||
|
{
|
||||||
|
QSettings settings;
|
||||||
|
// generate a GUID if doesn't exist yet in settings
|
||||||
|
uuid = settings.value("guid").toString();
|
||||||
|
if(uuid.isEmpty()) {
|
||||||
|
uuid = QUuid::createUuid().toString();
|
||||||
|
settings.setValue("guid", uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
hostname = QHostInfo::localHostName();
|
||||||
|
setAvailable();
|
||||||
|
|
||||||
|
socket = new QUdpSocket(this);
|
||||||
|
socket->bind(QHostAddress::Any, QCMA_REQUEST_PORT);
|
||||||
|
connect(socket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CmaBroadcast::readPendingDatagrams()
|
||||||
|
{
|
||||||
|
if(socket->hasPendingDatagrams()) {
|
||||||
|
QByteArray datagram;
|
||||||
|
datagram.resize(socket->pendingDatagramSize());
|
||||||
|
|
||||||
|
QHostAddress sender;
|
||||||
|
quint16 senderPort;
|
||||||
|
|
||||||
|
socket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
|
||||||
|
|
||||||
|
if(datagram.contains(broadcast_query)) {
|
||||||
|
QMutexLocker locker(&mutex);
|
||||||
|
socket->writeDatagram(reply.toUtf8(), sender, senderPort);
|
||||||
|
} else {
|
||||||
|
qWarning("Unknown request: %.*s\n", datagram.length(), datagram.constData());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CmaBroadcast::setAvailable()
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&mutex);
|
||||||
|
reply = broadcast_reply
|
||||||
|
.arg(broadcast_ok, uuid, "win", hostname)
|
||||||
|
.arg(VITAMTP_PROTOCOL_MAX_VERSION, 8, 10, QChar('0'))
|
||||||
|
.arg(QCMA_REQUEST_PORT)
|
||||||
|
.arg(VITAMTP_WIRELESS_MAX_VERSION, 8, 10, QChar('0'));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CmaBroadcast::setUnavailable()
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&mutex);
|
||||||
|
reply = broadcast_reply
|
||||||
|
.arg(broadcast_unavailable, uuid, "win", hostname)
|
||||||
|
.arg(VITAMTP_PROTOCOL_MAX_VERSION, 8, 10, QChar('0'))
|
||||||
|
.arg(QCMA_REQUEST_PORT)
|
||||||
|
.arg(VITAMTP_WIRELESS_MAX_VERSION, 8, 10, QChar('0'));
|
||||||
|
}
|
56
cmabroadcast.h
Normal file
56
cmabroadcast.h
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Codestation
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* (at your option) 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CMABROADCAST_H
|
||||||
|
#define CMABROADCAST_H
|
||||||
|
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QUdpSocket>
|
||||||
|
|
||||||
|
#define QCMA_REQUEST_PORT 9309
|
||||||
|
|
||||||
|
class CmaBroadcast : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit CmaBroadcast(QObject *parent = 0);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void replyBroadcast(const QByteArray &datagram);
|
||||||
|
|
||||||
|
QMutex mutex;
|
||||||
|
QString uuid;
|
||||||
|
QString reply;
|
||||||
|
QString hostname;
|
||||||
|
QUdpSocket *socket;
|
||||||
|
static const QString broadcast_reply;
|
||||||
|
static const char *broadcast_query;
|
||||||
|
static const char *broadcast_ok;
|
||||||
|
static const char *broadcast_unavailable;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void setAvailable();
|
||||||
|
void setUnavailable();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void readPendingDatagrams();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CMABROADCAST_H
|
219
cmaclient.cpp
219
cmaclient.cpp
@@ -1,7 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Codestation
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* (at your option) 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "cmaclient.h"
|
#include "cmaclient.h"
|
||||||
#include "capability.h"
|
#include "capability.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include "wirelessworker.h"
|
||||||
|
|
||||||
|
#include "QApplication"
|
||||||
#include <QBuffer>
|
#include <QBuffer>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
@@ -10,55 +31,76 @@
|
|||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
const metadata_t CmaClient::g_thumbmeta = {0, 0, 0, NULL, NULL, 0, 0, 0, Thumbnail, {{18, 144, 80, 0, 1, 1.0f, 2}}, NULL};
|
#include <MediaInfo/MediaInfo.h>
|
||||||
|
#include <MediaInfo/File__Analyse_Automatic.h>
|
||||||
|
|
||||||
|
metadata_t CmaClient::g_thumbmeta = {0, 0, 0, NULL, NULL, 0, 0, 0, Thumbnail, {{18, 144, 80, 0, 1, 1.0f, 2}}, NULL};
|
||||||
|
|
||||||
CmaClient::CmaClient(QObject *parent) :
|
CmaClient::CmaClient(QObject *parent) :
|
||||||
BaseWorker(parent)
|
BaseWorker(parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CmaClient::CmaClient(Database *database, vita_device_t *device, QObject *parent) :
|
vita_device_t *CmaClient::getDeviceConnection()
|
||||||
BaseWorker(parent), db(database), device(device)
|
|
||||||
{
|
{
|
||||||
}
|
int num_tries = 0;
|
||||||
|
vita_device_t *vita;
|
||||||
|
typedef BroadcastSignal BS;
|
||||||
|
|
||||||
CmaClient::~CmaClient()
|
while(active) {
|
||||||
{
|
vita = VitaMTP_Get_First_USB_Vita();
|
||||||
if(device) {
|
if(vita || !active) {
|
||||||
close();
|
break;
|
||||||
|
}
|
||||||
|
qDebug("No Vita detected via USB, attempt %i", ++num_tries);
|
||||||
|
vita = VitaMTP_Get_First_Wireless_Vita(&BS::info, 0, 2, BS::deviceRegistered, BS::generatePin);
|
||||||
|
if(vita || !active) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
qDebug("No Vita detected via wireless, attempt %i", ++num_tries);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void CmaClient::close()
|
return vita;
|
||||||
{
|
|
||||||
VitaMTP_SendHostStatus(device, VITA_HOST_STATUS_EndConnection);
|
|
||||||
VitaMTP_Release_Device(device);
|
|
||||||
device = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CmaClient::process()
|
void CmaClient::process()
|
||||||
{
|
{
|
||||||
qDebug("Vita connected: id %s", VitaMTP_Get_Identification(device));
|
qDebug() << "Starting CmaClient:" << QThread::currentThreadId();
|
||||||
|
|
||||||
|
connect(&broadcast, SIGNAL(receivedPin(int)), this, SIGNAL(receivedPin(int)));
|
||||||
|
|
||||||
|
active = true;
|
||||||
|
|
||||||
|
while(active) {
|
||||||
|
|
||||||
|
if((device = getDeviceConnection()) == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
broadcast.setUnavailable();
|
||||||
|
qDebug("Vita connected: id %s", VitaMTP_Get_Identification(device));
|
||||||
DeviceCapability *vita_info = new DeviceCapability();
|
DeviceCapability *vita_info = new DeviceCapability();
|
||||||
|
|
||||||
if(!vita_info->exchangeInfo(device)) {
|
if(!vita_info->exchangeInfo(device)) {
|
||||||
qCritical("Error while exchanging info with the vita");
|
qCritical("Error while exchanging info with the vita");
|
||||||
close();
|
close();
|
||||||
|
broadcast.setAvailable();
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Conection successful, inform the user
|
// Conection successful, inform the user
|
||||||
emit deviceConnected(QString(tr("Connected to ")) + vita_info->getOnlineId());
|
emit deviceConnected(QString(tr("Connected to ")) + vita_info->getOnlineId());
|
||||||
connected = true;
|
connected = true;
|
||||||
enterEventLoop();
|
enterEventLoop();
|
||||||
|
broadcast.setAvailable();
|
||||||
|
}
|
||||||
|
emit finished();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CmaClient::enterEventLoop()
|
void CmaClient::enterEventLoop()
|
||||||
{
|
{
|
||||||
vita_event_t event;
|
vita_event_t event;
|
||||||
|
|
||||||
qDebug() << "From listener:"<< QThread::currentThreadId();
|
qDebug("Starting event loop");
|
||||||
|
|
||||||
while(connected) {
|
while(connected) {
|
||||||
if(VitaMTP_Read_Event(device, &event) < 0) {
|
if(VitaMTP_Read_Event(device, &event) < 0) {
|
||||||
@@ -134,9 +176,10 @@ void CmaClient::enterEventLoop()
|
|||||||
default:
|
default:
|
||||||
vitaEventUnimplementated(&event, event.Param1);
|
vitaEventUnimplementated(&event, event.Param1);
|
||||||
}
|
}
|
||||||
|
qDebug("Ended event, code: 0x%x, id: %d", event.Code, event.Param1);
|
||||||
}
|
}
|
||||||
qDebug() << "Finished event thread for:" << QThread::currentThreadId();
|
qDebug("Finished event thread");
|
||||||
emit finished();
|
emit deviceDisconnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
quint16 CmaClient::processAllObjects(CMAObject *parent, quint32 handle)
|
quint16 CmaClient::processAllObjects(CMAObject *parent, quint32 handle)
|
||||||
@@ -154,12 +197,12 @@ quint16 CmaClient::processAllObjects(CMAObject *parent, quint32 handle)
|
|||||||
return PTP_RC_VITA_Invalid_Data;
|
return PTP_RC_VITA_Invalid_Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
CMAObject *object = db->pathToObject(remote_meta.name, parent->metadata.ohfi);
|
CMAObject *object = db.pathToObject(remote_meta.name, parent->metadata.ohfi);
|
||||||
|
|
||||||
if(object) {
|
if(object) {
|
||||||
qDebug("Deleting %s", object->path.toStdString().c_str());
|
qDebug("Deleting %s", object->path.toStdString().c_str());
|
||||||
removeRecursively(object->path);
|
removeRecursively(object->path);
|
||||||
db->remove(object);
|
db.remove(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
QDir dir(parent->path);
|
QDir dir(parent->path);
|
||||||
@@ -188,7 +231,7 @@ quint16 CmaClient::processAllObjects(CMAObject *parent, quint32 handle)
|
|||||||
object = new CMAObject(parent);
|
object = new CMAObject(parent);
|
||||||
object->initObject(info);
|
object->initObject(info);
|
||||||
object->metadata.handle = remote_meta.handle;
|
object->metadata.handle = remote_meta.handle;
|
||||||
db->append(parent->metadata.ohfi, object);
|
db.append(parent->metadata.ohfi, object);
|
||||||
free(remote_meta.name);
|
free(remote_meta.name);
|
||||||
|
|
||||||
qDebug("Added object %s with OHFI %i to database", object->metadata.path, object->metadata.ohfi);
|
qDebug("Added object %s with OHFI %i to database", object->metadata.path, object->metadata.ohfi);
|
||||||
@@ -199,7 +242,7 @@ quint16 CmaClient::processAllObjects(CMAObject *parent, quint32 handle)
|
|||||||
|
|
||||||
if(ret != PTP_RC_OK) {
|
if(ret != PTP_RC_OK) {
|
||||||
qDebug("Deleteting object with OHFI %d", object->metadata.ohfi);
|
qDebug("Deleteting object with OHFI %d", object->metadata.ohfi);
|
||||||
db->remove(object);
|
db.remove(object);
|
||||||
free(data.fileData);
|
free(data.fileData);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -221,9 +264,9 @@ void CmaClient::vitaEventGetTreatObject(vita_event_t *event, int eventId)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QMutexLocker locker(&db->mutex);
|
QMutexLocker locker(&db.mutex);
|
||||||
|
|
||||||
CMAObject *parent = db->ohfiToObject(treatObject.ohfiParent);
|
CMAObject *parent = db.ohfiToObject(treatObject.ohfiParent);
|
||||||
|
|
||||||
if(parent == NULL) {
|
if(parent == NULL) {
|
||||||
qWarning("Cannot find parent OHFI %d", treatObject.ohfiParent);
|
qWarning("Cannot find parent OHFI %d", treatObject.ohfiParent);
|
||||||
@@ -244,14 +287,14 @@ void CmaClient::vitaEventSendCopyConfirmationInfo(vita_event_t *event, int event
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QMutexLocker locker(&db->mutex);
|
QMutexLocker locker(&db.mutex);
|
||||||
|
|
||||||
quint64 size = 0;
|
quint64 size = 0;
|
||||||
|
|
||||||
for(quint32 i = 0; i < info->count; i++) {
|
for(quint32 i = 0; i < info->count; i++) {
|
||||||
CMAObject *object;
|
CMAObject *object;
|
||||||
|
|
||||||
if((object = db->ohfiToObject(info->ohfi[i])) == NULL) {
|
if((object = db.ohfiToObject(info->ohfi[i])) == NULL) {
|
||||||
qWarning("Cannot find OHFI %d", info->ohfi[i]);
|
qWarning("Cannot find OHFI %d", info->ohfi[i]);
|
||||||
free(info);
|
free(info);
|
||||||
return;
|
return;
|
||||||
@@ -279,9 +322,9 @@ void CmaClient::vitaEventSendObjectMetadataItems(vita_event_t *event, int eventI
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QMutexLocker locker(&db->mutex);
|
QMutexLocker locker(&db.mutex);
|
||||||
|
|
||||||
CMAObject *object = db->ohfiToObject(ohfi);
|
CMAObject *object = db.ohfiToObject(ohfi);
|
||||||
|
|
||||||
if(object == NULL) {
|
if(object == NULL) {
|
||||||
qWarning("Cannot find OHFI %d in database", ohfi);
|
qWarning("Cannot find OHFI %d in database", ohfi);
|
||||||
@@ -324,10 +367,10 @@ void CmaClient::vitaEventSendNumOfObject(vita_event_t *event, int eventId)
|
|||||||
{
|
{
|
||||||
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
|
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
|
||||||
|
|
||||||
QMutexLocker locker(&db->mutex);
|
QMutexLocker locker(&db.mutex);
|
||||||
|
|
||||||
uint ohfi = event->Param2;
|
uint ohfi = event->Param2;
|
||||||
int items = db->filterObjects(ohfi, NULL);
|
int items = db.filterObjects(ohfi, NULL);
|
||||||
|
|
||||||
if(VitaMTP_SendNumOfObject(device, eventId, items) != PTP_RC_OK) {
|
if(VitaMTP_SendNumOfObject(device, eventId, items) != PTP_RC_OK) {
|
||||||
qWarning("Error occured receiving object count for OHFI parent %d", ohfi);
|
qWarning("Error occured receiving object count for OHFI parent %d", ohfi);
|
||||||
@@ -347,10 +390,10 @@ void CmaClient::vitaEventSendObjectMetadata(vita_event_t *event, int eventId)
|
|||||||
qWarning("GetBrowseInfo failed");
|
qWarning("GetBrowseInfo failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QMutexLocker locker(&db->mutex);
|
QMutexLocker locker(&db.mutex);
|
||||||
|
|
||||||
metadata_t *meta;
|
metadata_t *meta;
|
||||||
int count = db->filterObjects(browse.ohfiParent, &meta); // if meta is null, will return empty XML
|
int count = db.filterObjects(browse.ohfiParent, &meta); // if meta is null, will return empty XML
|
||||||
qDebug("Sending %i metadata filtered objects for OHFI %d", count, browse.ohfiParent);
|
qDebug("Sending %i metadata filtered objects for OHFI %d", count, browse.ohfiParent);
|
||||||
|
|
||||||
if(VitaMTP_SendObjectMetadata(device, eventId, meta) != PTP_RC_OK) { // send all objects with OHFI parent
|
if(VitaMTP_SendObjectMetadata(device, eventId, meta) != PTP_RC_OK) { // send all objects with OHFI parent
|
||||||
@@ -366,10 +409,12 @@ void CmaClient::vitaEventSendObject(vita_event_t *event, int eventId)
|
|||||||
|
|
||||||
int ohfi = event->Param2;
|
int ohfi = event->Param2;
|
||||||
|
|
||||||
QMutexLocker locker(&db->mutex);
|
QMutexLocker locker(&db.mutex);
|
||||||
|
|
||||||
|
qDebug("Searching object with OHFI %d", ohfi);
|
||||||
|
|
||||||
Database::find_data iters;
|
Database::find_data iters;
|
||||||
if(!db->find(ohfi, iters)) {
|
if(!db.find(ohfi, iters)) {
|
||||||
qWarning("Failed to find OHFI %d", ohfi);
|
qWarning("Failed to find OHFI %d", ohfi);
|
||||||
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI);
|
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI);
|
||||||
return;
|
return;
|
||||||
@@ -379,6 +424,7 @@ void CmaClient::vitaEventSendObject(vita_event_t *event, int eventId)
|
|||||||
CMAObject *object = *iters.it;
|
CMAObject *object = *iters.it;
|
||||||
CMAObject *start = object;
|
CMAObject *start = object;
|
||||||
uint parentHandle = event->Param3;
|
uint parentHandle = event->Param3;
|
||||||
|
bool send_folder = object->metadata.dataType & Folder;
|
||||||
uint handle;
|
uint handle;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@@ -415,12 +461,22 @@ void CmaClient::vitaEventSendObject(vita_event_t *event, int eventId)
|
|||||||
}
|
}
|
||||||
|
|
||||||
object->metadata.handle = handle;
|
object->metadata.handle = handle;
|
||||||
|
|
||||||
|
if(object->metadata.dataType & File) {
|
||||||
file.unmap(data);
|
file.unmap(data);
|
||||||
object = *iters.it++;
|
}
|
||||||
|
|
||||||
|
// break early if only a file needs to be sent
|
||||||
|
if(!send_folder) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
object = *++iters.it;
|
||||||
|
|
||||||
} while(iters.it != iters.end && object->metadata.ohfiParent >= OHFI_OFFSET); // get everything under this "folder"
|
} while(iters.it != iters.end && object->metadata.ohfiParent >= OHFI_OFFSET); // get everything under this "folder"
|
||||||
|
|
||||||
VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, handle);
|
VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, handle);
|
||||||
|
|
||||||
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Data); // TODO: Send thumbnail
|
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Data); // TODO: Send thumbnail
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -488,9 +544,9 @@ void CmaClient::vitaEventSendObjectStatus(vita_event_t *event, int eventId)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QMutexLocker locker(&db->mutex);
|
QMutexLocker locker(&db.mutex);
|
||||||
|
|
||||||
CMAObject *object = db->pathToObject(objectstatus.title, objectstatus.ohfiRoot);
|
CMAObject *object = db.pathToObject(objectstatus.title, objectstatus.ohfiRoot);
|
||||||
|
|
||||||
if(object == NULL) { // not in database, don't return metadata
|
if(object == NULL) { // not in database, don't return metadata
|
||||||
qDebug("Object %s not in database (OHFI: %i). Sending OK response for non-existence", objectstatus.title, objectstatus.ohfiRoot);
|
qDebug("Object %s not in database (OHFI: %i). Sending OK response for non-existence", objectstatus.title, objectstatus.ohfiRoot);
|
||||||
@@ -514,10 +570,10 @@ void CmaClient::vitaEventSendObjectThumb(vita_event_t *event, int eventId)
|
|||||||
{
|
{
|
||||||
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
|
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
|
||||||
|
|
||||||
QMutexLocker locker(&db->mutex);
|
QMutexLocker locker(&db.mutex);
|
||||||
|
|
||||||
int ohfi = event->Param2;
|
int ohfi = event->Param2;
|
||||||
CMAObject *object = db->ohfiToObject(ohfi);
|
CMAObject *object = db.ohfiToObject(ohfi);
|
||||||
|
|
||||||
if(object == NULL) {
|
if(object == NULL) {
|
||||||
qWarning("Cannot find OHFI %d in database.", ohfi);
|
qWarning("Cannot find OHFI %d in database.", ohfi);
|
||||||
@@ -525,34 +581,13 @@ void CmaClient::vitaEventSendObjectThumb(vita_event_t *event, int eventId)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray data;
|
QByteArray data = getThumbnail(object->path, object->metadata.dataType, &g_thumbmeta);
|
||||||
|
|
||||||
if(MASK_SET(object->metadata.dataType, SaveData)) {
|
if(data.size() == 0) {
|
||||||
QString thumbpath = QDir(object->path).absoluteFilePath("ICON0.PNG");
|
qWarning("Cannot find/read thumbnail for %s", object->path.toStdString().c_str());
|
||||||
qDebug("Sending savedata thumbnail from %s", thumbpath.toStdString().c_str());
|
|
||||||
|
|
||||||
QFile file(thumbpath);
|
|
||||||
if(!file.open(QIODevice::ReadOnly)) {
|
|
||||||
qWarning("Cannot find thumbnail %s", thumbpath.toStdString().c_str());
|
|
||||||
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Data);
|
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
data = file.readAll();
|
|
||||||
|
|
||||||
} else {
|
|
||||||
QImage img;
|
|
||||||
if(!MASK_SET(object->metadata.dataType, Photo) || !img.load(object->path)) {
|
|
||||||
qWarning("Thumbnail sending for the file %s is not supported", object->metadata.path);
|
|
||||||
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
qDebug("Creating thumbnail of %s", object->metadata.name);
|
|
||||||
|
|
||||||
QBuffer buffer(&data);
|
|
||||||
buffer.open(QIODevice::WriteOnly);
|
|
||||||
QImage result = img.scaled(256, 256, Qt::KeepAspectRatio, Qt::FastTransformation);
|
|
||||||
result.save(&buffer, "JPEG");
|
|
||||||
}
|
|
||||||
|
|
||||||
// workaround for the vitamtp locale bug
|
// workaround for the vitamtp locale bug
|
||||||
char *locale = strdup(setlocale(LC_ALL, NULL));
|
char *locale = strdup(setlocale(LC_ALL, NULL));
|
||||||
@@ -573,10 +608,10 @@ void CmaClient::vitaEventDeleteObject(vita_event_t *event, int eventId)
|
|||||||
{
|
{
|
||||||
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
|
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
|
||||||
|
|
||||||
QMutexLocker locker(&db->mutex);
|
QMutexLocker locker(&db.mutex);
|
||||||
|
|
||||||
int ohfi = event->Param2;
|
int ohfi = event->Param2;
|
||||||
CMAObject *object = db->ohfiToObject(ohfi);
|
CMAObject *object = db.ohfiToObject(ohfi);
|
||||||
|
|
||||||
if(object == NULL) {
|
if(object == NULL) {
|
||||||
qWarning("OHFI %d not found", ohfi);
|
qWarning("OHFI %d not found", ohfi);
|
||||||
@@ -586,7 +621,7 @@ void CmaClient::vitaEventDeleteObject(vita_event_t *event, int eventId)
|
|||||||
|
|
||||||
qDebug("Deleting %s, OHFI: %i", object->metadata.path, object->metadata.ohfi);
|
qDebug("Deleting %s, OHFI: %i", object->metadata.path, object->metadata.ohfi);
|
||||||
removeRecursively(object->path);
|
removeRecursively(object->path);
|
||||||
db->remove(object);
|
db.remove(object);
|
||||||
|
|
||||||
VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
|
VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
|
||||||
}
|
}
|
||||||
@@ -603,10 +638,12 @@ void CmaClient::vitaEventGetSettingInfo(vita_event_t *event, int eventId)
|
|||||||
|
|
||||||
qDebug("Current account id: %s", settingsinfo->current_account.accountId);
|
qDebug("Current account id: %s", settingsinfo->current_account.accountId);
|
||||||
|
|
||||||
db->setUUID(settingsinfo->current_account.accountId);
|
|
||||||
|
|
||||||
|
if(QSettings().value("lastAccountId").toString() != settingsinfo->current_account.accountId) {
|
||||||
|
db.setUUID(settingsinfo->current_account.accountId);
|
||||||
// set the database to be updated ASAP
|
// set the database to be updated ASAP
|
||||||
emit refreshDatabase();
|
emit refreshDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
// free all the information
|
// free all the information
|
||||||
VitaMTP_Data_Free_Settings(settingsinfo);
|
VitaMTP_Data_Free_Settings(settingsinfo);
|
||||||
@@ -660,9 +697,9 @@ void CmaClient::vitaEventSendPartOfObject(vita_event_t *event, int eventId)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QMutexLocker locker(&db->mutex);
|
QMutexLocker locker(&db.mutex);
|
||||||
|
|
||||||
CMAObject *object = db->ohfiToObject(part_init.ohfi);
|
CMAObject *object = db.ohfiToObject(part_init.ohfi);
|
||||||
|
|
||||||
if(object == NULL) {
|
if(object == NULL) {
|
||||||
qWarning("Cannot find object for OHFI %d", part_init.ohfi);
|
qWarning("Cannot find object for OHFI %d", part_init.ohfi);
|
||||||
@@ -700,9 +737,9 @@ void CmaClient::vitaEventOperateObject(vita_event_t *event, int eventId)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QMutexLocker locker(&db->mutex);
|
QMutexLocker locker(&db.mutex);
|
||||||
|
|
||||||
CMAObject *root = db->ohfiToObject(operateobject.ohfi);
|
CMAObject *root = db.ohfiToObject(operateobject.ohfi);
|
||||||
|
|
||||||
// end for renaming only
|
// end for renaming only
|
||||||
if(root == NULL) {
|
if(root == NULL) {
|
||||||
@@ -721,7 +758,7 @@ void CmaClient::vitaEventOperateObject(vita_event_t *event, int eventId)
|
|||||||
} else {
|
} else {
|
||||||
CMAObject *newobj = new CMAObject(root);
|
CMAObject *newobj = new CMAObject(root);
|
||||||
newobj->initObject(QFileInfo(dir, operateobject.title));
|
newobj->initObject(QFileInfo(dir, operateobject.title));
|
||||||
db->append(operateobject.ohfi, newobj);
|
db.append(operateobject.ohfi, newobj);
|
||||||
qDebug("Created folder %s with OHFI %d under parent %s", newobj->metadata.path, newobj->metadata.ohfi, root->metadata.path);
|
qDebug("Created folder %s with OHFI %d under parent %s", newobj->metadata.path, newobj->metadata.ohfi, root->metadata.path);
|
||||||
VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, newobj->metadata.ohfi);
|
VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, newobj->metadata.ohfi);
|
||||||
}
|
}
|
||||||
@@ -737,7 +774,7 @@ void CmaClient::vitaEventOperateObject(vita_event_t *event, int eventId)
|
|||||||
} else {
|
} else {
|
||||||
CMAObject *newobj = new CMAObject(root);
|
CMAObject *newobj = new CMAObject(root);
|
||||||
newobj->initObject(file);
|
newobj->initObject(file);
|
||||||
db->append(root->metadata.ohfi, newobj);
|
db.append(root->metadata.ohfi, newobj);
|
||||||
qDebug("Created file %s with OHFI %d under parent %s", newobj->metadata.path, newobj->metadata.ohfi, root->metadata.path);
|
qDebug("Created file %s with OHFI %d under parent %s", newobj->metadata.path, newobj->metadata.ohfi, root->metadata.path);
|
||||||
VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, newobj->metadata.ohfi);
|
VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, newobj->metadata.ohfi);
|
||||||
}
|
}
|
||||||
@@ -752,7 +789,7 @@ void CmaClient::vitaEventOperateObject(vita_event_t *event, int eventId)
|
|||||||
//rename the current object
|
//rename the current object
|
||||||
root->rename(operateobject.title);
|
root->rename(operateobject.title);
|
||||||
Database::find_data iters;
|
Database::find_data iters;
|
||||||
db->find(root->metadata.ohfi, iters);
|
db.find(root->metadata.ohfi, iters);
|
||||||
|
|
||||||
// rename the rest of the list only if has the renamed parent in some part of the chain
|
// rename the rest of the list only if has the renamed parent in some part of the chain
|
||||||
while(iters.it != iters.end) {
|
while(iters.it != iters.end) {
|
||||||
@@ -796,8 +833,8 @@ void CmaClient::vitaEventGetPartOfObject(vita_event_t *event, int eventId)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QMutexLocker locker(&db->mutex);
|
QMutexLocker locker(&db.mutex);
|
||||||
CMAObject *object = db->ohfiToObject(part_init.ohfi);
|
CMAObject *object = db.ohfiToObject(part_init.ohfi);
|
||||||
|
|
||||||
if(object == NULL) {
|
if(object == NULL) {
|
||||||
qWarning("Cannot find OHFI %d", part_init.ohfi);
|
qWarning("Cannot find OHFI %d", part_init.ohfi);
|
||||||
@@ -828,10 +865,10 @@ void CmaClient::vitaEventSendStorageSize(vita_event_t *event, int eventId)
|
|||||||
{
|
{
|
||||||
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
|
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
|
||||||
|
|
||||||
QMutexLocker locker(&db->mutex);
|
QMutexLocker locker(&db.mutex);
|
||||||
|
|
||||||
int ohfi = event->Param2;
|
int ohfi = event->Param2;
|
||||||
CMAObject *object = db->ohfiToObject(ohfi);
|
CMAObject *object = db.ohfiToObject(ohfi);
|
||||||
|
|
||||||
if(object == NULL) {
|
if(object == NULL) {
|
||||||
qWarning("Error: Cannot find OHFI %d", ohfi);
|
qWarning("Error: Cannot find OHFI %d", ohfi);
|
||||||
@@ -882,9 +919,9 @@ void CmaClient::vitaEventCheckExistance(vita_event_t *event, int eventId)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QMutexLocker locker(&db->mutex);
|
QMutexLocker locker(&db.mutex);
|
||||||
|
|
||||||
CMAObject *object = db->pathToObject(existance.name, 0);
|
CMAObject *object = db.pathToObject(existance.name, 0);
|
||||||
|
|
||||||
if(object == NULL) {
|
if(object == NULL) {
|
||||||
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Different_Object);
|
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Different_Object);
|
||||||
@@ -894,3 +931,23 @@ void CmaClient::vitaEventCheckExistance(vita_event_t *event, int eventId)
|
|||||||
|
|
||||||
VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
|
VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CmaClient::close()
|
||||||
|
{
|
||||||
|
VitaMTP_SendHostStatus(device, VITA_HOST_STATUS_EndConnection);
|
||||||
|
VitaMTP_Release_Device(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CmaClient::stop()
|
||||||
|
{
|
||||||
|
active = false;
|
||||||
|
connected = false;
|
||||||
|
waitCondition.wakeAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
CmaClient::~CmaClient()
|
||||||
|
{
|
||||||
|
if(device) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
36
cmaclient.h
36
cmaclient.h
@@ -1,12 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Codestation
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* (at your option) 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef CMACLIENT_H
|
#ifndef CMACLIENT_H
|
||||||
#define CMACLIENT_H
|
#define CMACLIENT_H
|
||||||
|
|
||||||
#include "baseworker.h"
|
#include "baseworker.h"
|
||||||
|
#include "cmabroadcast.h"
|
||||||
#include "cmaobject.h"
|
#include "cmaobject.h"
|
||||||
#include "database.h"
|
#include "database.h"
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QWaitCondition>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <vitamtp.h>
|
#include <vitamtp.h>
|
||||||
@@ -17,11 +38,13 @@ class CmaClient : public BaseWorker
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit CmaClient(QObject *parent = 0);
|
explicit CmaClient(QObject *parent = 0);
|
||||||
explicit CmaClient(Database *database, vita_device_t *device, QObject *parent = 0);
|
|
||||||
~CmaClient();
|
~CmaClient();
|
||||||
|
|
||||||
|
Database db;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void enterEventLoop();
|
void enterEventLoop();
|
||||||
|
vita_device_t *getDeviceConnection();
|
||||||
|
|
||||||
uint16_t processAllObjects(CMAObject *parent, uint32_t handle);
|
uint16_t processAllObjects(CMAObject *parent, uint32_t handle);
|
||||||
void vitaEventSendObject(vita_event_t *event, int eventId);
|
void vitaEventSendObject(vita_event_t *event, int eventId);
|
||||||
@@ -46,18 +69,23 @@ private:
|
|||||||
void vitaEventSendNPAccountInfo(vita_event_t *event, int eventId);
|
void vitaEventSendNPAccountInfo(vita_event_t *event, int eventId);
|
||||||
void vitaEventRequestTerminate(vita_event_t *event, int eventId);
|
void vitaEventRequestTerminate(vita_event_t *event, int eventId);
|
||||||
|
|
||||||
Database *db;
|
QWaitCondition waitCondition;
|
||||||
|
CmaBroadcast broadcast;
|
||||||
vita_device_t *device;
|
vita_device_t *device;
|
||||||
|
volatile bool active;
|
||||||
volatile bool connected;
|
volatile bool connected;
|
||||||
static const metadata_t g_thumbmeta;
|
static metadata_t g_thumbmeta;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
void receivedPin(int);
|
||||||
|
void deviceDetected();
|
||||||
void deviceConnected(QString);
|
void deviceConnected(QString);
|
||||||
|
void deviceDisconnected();
|
||||||
void refreshDatabase();
|
void refreshDatabase();
|
||||||
void terminate();
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void close();
|
void close();
|
||||||
|
void stop();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void process();
|
void process();
|
||||||
|
@@ -38,9 +38,12 @@ void CMARootObject::initObject(const QString &path)
|
|||||||
metadata.dataType = Music;
|
metadata.dataType = Music;
|
||||||
this->path = path;
|
this->path = path;
|
||||||
num_filters = 1;
|
num_filters = 1;
|
||||||
filters = new metadata_t[1];
|
filters = new metadata_t[2];
|
||||||
//createFilter(&filters[0], "Folders", VITA_DIR_TYPE_MASK_MUSIC | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_PLAYLISTS);
|
//createFilter(&filters[0], "Artists", VITA_DIR_TYPE_MASK_MUSIC | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_ARTISTS);
|
||||||
createFilter(&filters[0], "All", VITA_DIR_TYPE_MASK_MUSIC | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_SONGS);
|
createFilter(&filters[0], "Albums", VITA_DIR_TYPE_MASK_MUSIC | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_ALBUMS);
|
||||||
|
createFilter(&filters[1], "All", VITA_DIR_TYPE_MASK_MUSIC | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_SONGS);
|
||||||
|
//createFilter(&filters[3], "Genres", VITA_DIR_TYPE_MASK_MUSIC | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_GENRES);
|
||||||
|
//createFilter(&filters[4], "Playlists", VITA_DIR_TYPE_MASK_MUSIC | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_PLAYLISTS);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VITA_OHFI_PHOTO:
|
case VITA_OHFI_PHOTO:
|
||||||
@@ -119,6 +122,7 @@ void CMARootObject::createFilter(metadata_t *filter, const char *name, int type)
|
|||||||
filter->size = 0;
|
filter->size = 0;
|
||||||
filter->dataType = static_cast<DataType>(Folder | Special);
|
filter->dataType = static_cast<DataType>(Folder | Special);
|
||||||
filter->next_metadata = NULL;
|
filter->next_metadata = NULL;
|
||||||
|
qDebug("Added filter %s to database with OHFI %d (%s)", name, filter->ohfi, metadata.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CMARootObject::getFilters(metadata_t **p_head)
|
int CMARootObject::getFilters(metadata_t **p_head)
|
||||||
|
@@ -1,72 +0,0 @@
|
|||||||
#include "cmaserver.h"
|
|
||||||
#include "wirelessworker.h"
|
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QHostInfo>
|
|
||||||
#include <QMutex>
|
|
||||||
#include <QSettings>
|
|
||||||
|
|
||||||
CmaServer::CmaServer(QObject *parent) :
|
|
||||||
QObject(parent), num_retries(0)
|
|
||||||
{
|
|
||||||
strcpy(hostname, QHostInfo::localHostName().toStdString().c_str());
|
|
||||||
BroadcastSignal::info.name = hostname;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CmaServer::listen()
|
|
||||||
{
|
|
||||||
QThread *thread = new QThread();
|
|
||||||
if(QSettings().value("wireless", false).toBool()) {
|
|
||||||
connect(&timer, SIGNAL(timeout()), this, SLOT(connectWireless()));
|
|
||||||
broadcast.start();
|
|
||||||
timer.setSingleShot(true);
|
|
||||||
} else {
|
|
||||||
timer.setSingleShot(false);
|
|
||||||
connect(&timer, SIGNAL(timeout()), this, SLOT(connectUsb()));
|
|
||||||
}
|
|
||||||
moveToThread(thread);
|
|
||||||
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
|
|
||||||
timer.start(2000);
|
|
||||||
thread->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CmaServer::connectUsb()
|
|
||||||
{
|
|
||||||
qDebug() << "From connectUsb: "<< QThread::currentThreadId();
|
|
||||||
|
|
||||||
vita_device_t *vita = VitaMTP_Get_First_USB_Vita();
|
|
||||||
if(vita) {
|
|
||||||
qDebug("Detected PS Vita via USB");
|
|
||||||
timer.stop();
|
|
||||||
emit newConnection(vita);
|
|
||||||
} else {
|
|
||||||
qDebug("No PS Vita found. Attempt %d", ++num_retries);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CmaServer::connectWireless()
|
|
||||||
{
|
|
||||||
typedef BroadcastSignal BS;
|
|
||||||
|
|
||||||
qDebug() << "From connectWireless: "<< QThread::currentThreadId();
|
|
||||||
|
|
||||||
vita_device_t *vita = VitaMTP_Get_First_Wireless_Vita(&BS::info, 0, 0, BS::deviceRegistered, BS::generatePin);
|
|
||||||
if(vita) {
|
|
||||||
qDebug("Detected PS Vita in wireless mode");
|
|
||||||
emit newConnection(vita);
|
|
||||||
} else {
|
|
||||||
qDebug("PS Vita couldn't be detected. Attempt %d", ++num_retries);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CmaServer::continueProcess()
|
|
||||||
{
|
|
||||||
qDebug("Restarting CmaServer thread");
|
|
||||||
num_retries = 0;
|
|
||||||
timer.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CmaServer::stopProcess()
|
|
||||||
{
|
|
||||||
timer.stop();
|
|
||||||
}
|
|
45
cmaserver.h
45
cmaserver.h
@@ -1,45 +0,0 @@
|
|||||||
#ifndef CMASERVER_H
|
|
||||||
#define CMASERVER_H
|
|
||||||
|
|
||||||
#include "wirelessworker.h"
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#include <vitamtp.h>
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <limits.h>
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QTimer>
|
|
||||||
#include <QThread>
|
|
||||||
#include <QWaitCondition>
|
|
||||||
|
|
||||||
class CmaServer : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit CmaServer(QObject *parent = 0);
|
|
||||||
void listen();
|
|
||||||
void close();
|
|
||||||
|
|
||||||
int num_retries;
|
|
||||||
QTimer timer;
|
|
||||||
QThread *thread;
|
|
||||||
char hostname[256];
|
|
||||||
BroadcastSignal broadcast;
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void newConnection(vita_device_t *);
|
|
||||||
void createdPin(int);
|
|
||||||
void finished();
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void continueProcess();
|
|
||||||
void stopProcess();
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void connectWireless();
|
|
||||||
void connectUsb();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // CMASERVER_H
|
|
91
database.cpp
91
database.cpp
@@ -27,9 +27,14 @@
|
|||||||
|
|
||||||
#define OHFI_OFFSET 1000
|
#define OHFI_OFFSET 1000
|
||||||
|
|
||||||
|
const QStringList Database::image_types = QStringList() << "jpg" << "jpeg" << "png" << "tif" << "tiff" << "bmp" << "gif" << "mpo";
|
||||||
|
const QStringList Database::audio_types = QStringList() << "mp3" << "mp4" << "wav";
|
||||||
|
const QStringList Database::video_types = QStringList() << "mp4";
|
||||||
|
|
||||||
Database::Database(QObject *parent) :
|
Database::Database(QObject *parent) :
|
||||||
QObject(parent), mutex(QMutex::Recursive)
|
QObject(parent), mutex(QMutex::Recursive)
|
||||||
{
|
{
|
||||||
|
CMARootObject::uuid = QSettings().value("lastAccountId", "ffffffffffffffff").toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
Database::~Database()
|
Database::~Database()
|
||||||
@@ -40,6 +45,7 @@ Database::~Database()
|
|||||||
void Database::setUUID(const QString uuid)
|
void Database::setUUID(const QString uuid)
|
||||||
{
|
{
|
||||||
CMARootObject::uuid = uuid;
|
CMARootObject::uuid = uuid;
|
||||||
|
QSettings().setValue("lastAccountId", uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Database::create()
|
int Database::create()
|
||||||
@@ -75,12 +81,13 @@ int Database::create()
|
|||||||
case VITA_OHFI_PSPSAVE:
|
case VITA_OHFI_PSPSAVE:
|
||||||
case VITA_OHFI_PSXAPP:
|
case VITA_OHFI_PSXAPP:
|
||||||
case VITA_OHFI_PSMAPP:
|
case VITA_OHFI_PSMAPP:
|
||||||
|
|
||||||
obj->initObject(settings.value("appsPath").toString());
|
obj->initObject(settings.value("appsPath").toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
root_list list;
|
root_list list;
|
||||||
list << obj;
|
list << obj;
|
||||||
total_objects += scanRootDirectory(list);
|
total_objects += recursiveScanRootDirectory(list, obj, ohfi_array[i]);
|
||||||
object_list[ohfi_array[i]] = list;
|
object_list[ohfi_array[i]] = list;
|
||||||
}
|
}
|
||||||
return total_objects;
|
return total_objects;
|
||||||
@@ -95,7 +102,7 @@ CMAObject *Database::getParent(CMAObject *last_dir, const QString ¤t_path)
|
|||||||
return last_dir;
|
return last_dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Database::scanRootDirectory(root_list &list)
|
int Database::scanRootDirectory(root_list &list, int ohfi_type)
|
||||||
{
|
{
|
||||||
int total_objects = 0;
|
int total_objects = 0;
|
||||||
CMAObject *last_dir = list.first();
|
CMAObject *last_dir = list.first();
|
||||||
@@ -105,8 +112,16 @@ int Database::scanRootDirectory(root_list &list)
|
|||||||
|
|
||||||
while(it.hasNext()) {
|
while(it.hasNext()) {
|
||||||
it.next();
|
it.next();
|
||||||
CMAObject *obj = new CMAObject(getParent(last_dir, it.fileInfo().path()));
|
QFileInfo info = it.fileInfo();
|
||||||
obj->initObject(it.fileInfo());
|
|
||||||
|
if(info.isFile() && !checkFileType(info.absoluteFilePath(), ohfi_type)) {
|
||||||
|
//qDebug("Excluding %s from database", info.absoluteFilePath().toStdString().c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
CMAObject *obj = new CMAObject(getParent(last_dir, info.path()));
|
||||||
|
obj->initObject(info);
|
||||||
|
qDebug("Added %s to database with OHFI %d", obj->metadata.name, obj->metadata.ohfi);
|
||||||
list << obj;
|
list << obj;
|
||||||
|
|
||||||
if(obj->metadata.dataType & Folder) {
|
if(obj->metadata.dataType & Folder) {
|
||||||
@@ -118,6 +133,33 @@ int Database::scanRootDirectory(root_list &list)
|
|||||||
return total_objects;
|
return total_objects;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Database::recursiveScanRootDirectory(root_list &list, CMAObject *parent, int ohfi_type)
|
||||||
|
{
|
||||||
|
int total_objects = 0;
|
||||||
|
|
||||||
|
QDir dir(parent->path);
|
||||||
|
dir.setSorting(QDir::Name | QDir::DirsFirst);
|
||||||
|
QFileInfoList qsl = dir.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot);
|
||||||
|
|
||||||
|
foreach(const QFileInfo &info, qsl) {
|
||||||
|
if(info.isFile() && !checkFileType(info.absoluteFilePath(), ohfi_type)) {
|
||||||
|
//qDebug("Excluding %s from database", info.absoluteFilePath().toStdString().c_str());>
|
||||||
|
} else {
|
||||||
|
CMAObject *obj = new CMAObject(parent);
|
||||||
|
obj->initObject(info);
|
||||||
|
qDebug("Added %s to database with OHFI %d", obj->metadata.name, obj->metadata.ohfi);
|
||||||
|
list << obj;
|
||||||
|
if(info.isDir()) {
|
||||||
|
total_objects += recursiveScanRootDirectory(list, obj, ohfi_type);
|
||||||
|
} else {
|
||||||
|
total_objects++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return total_objects;
|
||||||
|
}
|
||||||
|
|
||||||
void Database::destroy()
|
void Database::destroy()
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&mutex);
|
QMutexLocker locker(&mutex);
|
||||||
@@ -282,6 +324,14 @@ int Database::acceptFilteredObject(const CMAObject *parent, const CMAObject *cur
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Database::dumpMetadataList(const metadata_t *p_head)
|
||||||
|
{
|
||||||
|
while(p_head) {
|
||||||
|
qDebug("Metadata: %s with OHFI %d", p_head->name, p_head->ohfi);
|
||||||
|
p_head = p_head->next_metadata;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int Database::filterObjects(int ohfiParent, metadata_t **p_head)
|
int Database::filterObjects(int ohfiParent, metadata_t **p_head)
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&mutex);
|
QMutexLocker locker(&mutex);
|
||||||
@@ -330,5 +380,38 @@ int Database::filterObjects(int ohfiParent, metadata_t **p_head)
|
|||||||
*p_head = temp.next_metadata;
|
*p_head = temp.next_metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(p_head) {
|
||||||
|
dumpMetadataList(*p_head);
|
||||||
|
}
|
||||||
return numObjects;
|
return numObjects;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Database::checkFileType(const QString path, int ohfi_root)
|
||||||
|
{
|
||||||
|
switch(ohfi_root) {
|
||||||
|
case VITA_OHFI_MUSIC:
|
||||||
|
foreach(const QString &ext, audio_types) {
|
||||||
|
if(path.endsWith(ext, Qt::CaseInsensitive)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VITA_OHFI_PHOTO:
|
||||||
|
foreach(const QString &ext, image_types) {
|
||||||
|
if(path.endsWith(ext, Qt::CaseInsensitive)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VITA_OHFI_VIDEO:
|
||||||
|
foreach(const QString &ext, video_types) {
|
||||||
|
if(path.endsWith(ext, Qt::CaseInsensitive)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@@ -62,13 +62,20 @@ private:
|
|||||||
typedef QList<CMAObject *> root_list;
|
typedef QList<CMAObject *> root_list;
|
||||||
typedef QMap<int, root_list> map_list;
|
typedef QMap<int, root_list> map_list;
|
||||||
|
|
||||||
int scanRootDirectory(root_list &list);
|
static const QStringList audio_types;
|
||||||
|
static const QStringList image_types;
|
||||||
|
static const QStringList video_types;
|
||||||
|
|
||||||
|
int scanRootDirectory(root_list &list,int ohfi_type);
|
||||||
|
int recursiveScanRootDirectory(root_list &list, CMAObject *parent, int ohfi_type);
|
||||||
bool hasFilter(const CMARootObject *object,int ohfi);
|
bool hasFilter(const CMARootObject *object,int ohfi);
|
||||||
bool removeInternal(root_list &list, const CMAObject *obj);
|
bool removeInternal(root_list &list, const CMAObject *obj);
|
||||||
bool findInternal(const root_list &list, int ohfi, find_data &data);
|
bool findInternal(const root_list &list, int ohfi, find_data &data);
|
||||||
CMAObject *getParent(CMAObject *last_dir, const QString ¤t_path);
|
CMAObject *getParent(CMAObject *last_dir, const QString ¤t_path);
|
||||||
CMAObject *pathToObjectInternal(const root_list &list, const char *path);
|
CMAObject *pathToObjectInternal(const root_list &list, const char *path);
|
||||||
static bool lessThanComparator(const CMAObject *a, const CMAObject *b);
|
static bool lessThanComparator(const CMAObject *a, const CMAObject *b);
|
||||||
|
bool checkFileType(const QString path, int ohfi_root);
|
||||||
|
void dumpMetadataList(const metadata_t *p_head);
|
||||||
|
|
||||||
map_list object_list;
|
map_list object_list;
|
||||||
|
|
||||||
|
4
main.cpp
4
main.cpp
@@ -43,8 +43,6 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
SingleApplication app(argc, argv);
|
SingleApplication app(argc, argv);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if(!app.arguments().contains("--with-debug")) {
|
if(!app.arguments().contains("--with-debug")) {
|
||||||
VitaMTP_Set_Logging(VitaMTP_NONE);
|
VitaMTP_Set_Logging(VitaMTP_NONE);
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||||
@@ -56,7 +54,7 @@ int main(int argc, char *argv[])
|
|||||||
VitaMTP_Set_Logging(VitaMTP_VERBOSE);
|
VitaMTP_Set_Logging(VitaMTP_VERBOSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug()<<"From main thread: "<<QThread::currentThreadId();
|
qDebug() << "From main thread: "<< QThread::currentThreadId();
|
||||||
|
|
||||||
// set the organization/application for QSettings to work properly
|
// set the organization/application for QSettings to work properly
|
||||||
app.setOrganizationName("qcma");
|
app.setOrganizationName("qcma");
|
||||||
|
@@ -28,6 +28,7 @@
|
|||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <QSettings>
|
||||||
|
|
||||||
const QStringList MainWidget::path_list = QStringList() << "photoPath" << "musicPath" << "videoPath" << "appsPath" << "urlPath";
|
const QStringList MainWidget::path_list = QStringList() << "photoPath" << "musicPath" << "videoPath" << "appsPath" << "urlPath";
|
||||||
|
|
||||||
@@ -64,34 +65,22 @@ void MainWidget::dialogResult(int result)
|
|||||||
|
|
||||||
void MainWidget::startServer()
|
void MainWidget::startServer()
|
||||||
{
|
{
|
||||||
connect(&server, SIGNAL(newConnection(vita_device_t *)), this, SLOT(startClient(vita_device_t*)));
|
qDebug("Starting cma event loop");
|
||||||
connect(&server, SIGNAL(createdPin(int)), this, SLOT(showPin(int)));
|
clientLoop.start();
|
||||||
//connect(&server, SIGNAL(finished()), qApp, SLOT(quit()));
|
}
|
||||||
|
|
||||||
qDebug("Starting cma server");
|
void MainWidget::stopServer()
|
||||||
server.listen();
|
{
|
||||||
|
clientLoop.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::refreshDatabase()
|
void MainWidget::refreshDatabase()
|
||||||
{
|
{
|
||||||
db.mutex.lock();
|
clientLoop.db.mutex.lock();
|
||||||
db.destroy();
|
clientLoop.db.destroy();
|
||||||
int count = db.create();
|
int count = clientLoop.db.create();
|
||||||
qDebug("Indexed %i elements in the database", count);
|
qDebug("Added %i entries to the database", count);
|
||||||
db.mutex.unlock();
|
clientLoop.db.mutex.unlock();
|
||||||
}
|
|
||||||
|
|
||||||
void MainWidget::startClient(vita_device_t *device)
|
|
||||||
{
|
|
||||||
server.stopProcess();
|
|
||||||
qDebug() << "From startClient: "<< QThread::currentThreadId();
|
|
||||||
qDebug("Starting new client connection");
|
|
||||||
CmaClient *client = new CmaClient(&db, device);
|
|
||||||
connect(client, SIGNAL(deviceConnected(QString)), this, SLOT(receiveMessage(QString)));
|
|
||||||
connect(client, SIGNAL(deviceConnected(QString)), this, SLOT(setTrayTooltip(QString)));
|
|
||||||
connect(client, SIGNAL(refreshDatabase()), this, SLOT(refreshDatabase()));
|
|
||||||
connect(client, SIGNAL(finished()), &server, SLOT(continueProcess()));
|
|
||||||
client->start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::deviceDisconnect()
|
void MainWidget::deviceDisconnect()
|
||||||
@@ -103,6 +92,12 @@ void MainWidget::deviceDisconnect()
|
|||||||
void MainWidget::connectSignals()
|
void MainWidget::connectSignals()
|
||||||
{
|
{
|
||||||
connect(&dialog, SIGNAL(finished(int)), this, SLOT(dialogResult(int)));
|
connect(&dialog, SIGNAL(finished(int)), this, SLOT(dialogResult(int)));
|
||||||
|
connect(&clientLoop, SIGNAL(receivedPin(int)), this, SLOT(showPin(int)));
|
||||||
|
connect(&clientLoop, SIGNAL(deviceConnected(QString)), this, SLOT(receiveMessage(QString)));
|
||||||
|
connect(&clientLoop, SIGNAL(deviceConnected(QString)), this, SLOT(setTrayTooltip(QString)));
|
||||||
|
connect(&clientLoop, SIGNAL(deviceDisconnected()), this, SLOT(deviceDisconnect()));
|
||||||
|
connect(&clientLoop, SIGNAL(refreshDatabase()), this, SLOT(refreshDatabase()));
|
||||||
|
connect(&clientLoop, SIGNAL(finished()), qApp, SLOT(quit()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::showPin(int pin)
|
void MainWidget::showPin(int pin)
|
||||||
@@ -115,6 +110,7 @@ void MainWidget::prepareApplication()
|
|||||||
connectSignals();
|
connectSignals();
|
||||||
createTrayIcon();
|
createTrayIcon();
|
||||||
checkSettings();
|
checkSettings();
|
||||||
|
refreshDatabase();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::setTrayTooltip(QString message)
|
void MainWidget::setTrayTooltip(QString message)
|
||||||
@@ -153,7 +149,7 @@ void MainWidget::createTrayIcon()
|
|||||||
|
|
||||||
connect(options, SIGNAL(triggered()), &dialog, SLOT(open()));
|
connect(options, SIGNAL(triggered()), &dialog, SLOT(open()));
|
||||||
//connect(reload, SIGNAL(triggered()), &CmaWorker, SLOT(allowRefresh()), Qt::DirectConnection);
|
//connect(reload, SIGNAL(triggered()), &CmaWorker, SLOT(allowRefresh()), Qt::DirectConnection);
|
||||||
connect(quit, SIGNAL(triggered()), qApp, SLOT(quit()));
|
connect(quit, SIGNAL(triggered()), this, SLOT(stopServer()));
|
||||||
connect(wireless, SIGNAL(triggered()), this, SLOT(toggleWireless()));
|
connect(wireless, SIGNAL(triggered()), this, SLOT(toggleWireless()));
|
||||||
|
|
||||||
QMenu *trayIconMenu = new QMenu(this);
|
QMenu *trayIconMenu = new QMenu(this);
|
||||||
|
@@ -21,8 +21,7 @@
|
|||||||
#define MAINWIDGET_H
|
#define MAINWIDGET_H
|
||||||
|
|
||||||
#include "configwidget.h"
|
#include "configwidget.h"
|
||||||
#include "cmaserver.h"
|
#include "cmaclient.h"
|
||||||
#include "database.h"
|
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
@@ -56,8 +55,7 @@ private:
|
|||||||
QAction *reload;
|
QAction *reload;
|
||||||
QAction *options;
|
QAction *options;
|
||||||
QAction *wireless;
|
QAction *wireless;
|
||||||
Database db;
|
CmaClient clientLoop;
|
||||||
CmaServer server;
|
|
||||||
const static QStringList path_list;
|
const static QStringList path_list;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
@@ -67,9 +65,9 @@ private slots:
|
|||||||
void setTrayTooltip(QString message);
|
void setTrayTooltip(QString message);
|
||||||
void toggleWireless();
|
void toggleWireless();
|
||||||
void showPin(int pin);
|
void showPin(int pin);
|
||||||
void startClient(vita_device_t *device);
|
|
||||||
void refreshDatabase();
|
void refreshDatabase();
|
||||||
void startServer();
|
void startServer();
|
||||||
|
void stopServer();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MAINWIDGET_H
|
#endif // MAINWIDGET_H
|
||||||
|
18
qcma.pro
18
qcma.pro
@@ -25,8 +25,8 @@ SOURCES += main.cpp \
|
|||||||
singleapplication.cpp \
|
singleapplication.cpp \
|
||||||
baseworker.cpp \
|
baseworker.cpp \
|
||||||
sforeader.cpp \
|
sforeader.cpp \
|
||||||
cmaserver.cpp \
|
cmaclient.cpp \
|
||||||
cmaclient.cpp
|
cmabroadcast.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
wirelessworker.h \
|
wirelessworker.h \
|
||||||
@@ -40,11 +40,11 @@ HEADERS += \
|
|||||||
singleapplication.h \
|
singleapplication.h \
|
||||||
baseworker.h \
|
baseworker.h \
|
||||||
sforeader.h \
|
sforeader.h \
|
||||||
cmaserver.h \
|
cmaclient.h \
|
||||||
cmaclient.h
|
cmabroadcast.h
|
||||||
|
|
||||||
CONFIG += link_pkgconfig
|
CONFIG += link_pkgconfig
|
||||||
PKGCONFIG += libvitamtp libmediainfo
|
PKGCONFIG += libmediainfo
|
||||||
|
|
||||||
QMAKE_CXXFLAGS += -Wno-write-strings -Wall
|
QMAKE_CXXFLAGS += -Wno-write-strings -Wall
|
||||||
|
|
||||||
@@ -57,3 +57,11 @@ OTHER_FILES += \
|
|||||||
|
|
||||||
FORMS += \
|
FORMS += \
|
||||||
configwidget.ui
|
configwidget.ui
|
||||||
|
|
||||||
|
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../../usr/lib/release/ -lvitamtp
|
||||||
|
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../../usr/lib/debug/ -lvitamtp
|
||||||
|
else:unix: LIBS += $$PWD/../../../../usr/lib/libvitamtp.a -lusb-1.0 -lxml2
|
||||||
|
|
||||||
|
INCLUDEPATH += $$PWD/../../../../usr/include
|
||||||
|
DEPENDPATH += $$PWD/../../../../usr/include
|
||||||
|
|
||||||
|
89
utils.cpp
89
utils.cpp
@@ -19,19 +19,20 @@
|
|||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
#include <QBuffer>
|
||||||
|
#include <QDebug>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#include <vitamtp.h>
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#else
|
#else
|
||||||
#include <sys/statvfs.h>
|
#include <sys/statvfs.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <MediaInfo/MediaInfo.h>
|
||||||
|
#include <MediaInfo/File__Analyse_Automatic.h>
|
||||||
|
|
||||||
bool getDiskSpace(const QString &dir, quint64 *free, quint64 *total)
|
bool getDiskSpace(const QString &dir, quint64 *free, quint64 *total)
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN32
|
||||||
@@ -79,3 +80,83 @@ bool removeRecursively(const QString &dirName)
|
|||||||
return result;
|
return result;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QByteArray findFolderAlbumArt(const QString path, metadata_t *metadata)
|
||||||
|
{
|
||||||
|
QByteArray data;
|
||||||
|
QDir folder(path);
|
||||||
|
|
||||||
|
QStringList files = folder.entryList(QDir::Files | QDir::Readable);
|
||||||
|
const QStringList cover_list = QStringList() << "album" << "cover" << "front";
|
||||||
|
const QStringList ext_list = QStringList() << "jpg" << "jpeg" << "png" << "gif";
|
||||||
|
|
||||||
|
foreach(const QString &file, files) {
|
||||||
|
foreach(const QString &cover, cover_list) {
|
||||||
|
foreach(const QString &ext, ext_list) {
|
||||||
|
if(file.compare(QString("%1.%2").arg(cover, ext), Qt::CaseInsensitive) == 0) {
|
||||||
|
qDebug() << "Trying to load album art from" << folder.absoluteFilePath(file);
|
||||||
|
QImage img;
|
||||||
|
if(img.load(folder.absoluteFilePath(file))) {
|
||||||
|
QBuffer buffer(&data);
|
||||||
|
buffer.open(QIODevice::WriteOnly);
|
||||||
|
QImage result = img.scaled(256, 250, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||||
|
result.save(&buffer, "JPEG");
|
||||||
|
metadata->data.thumbnail.width = result.width();
|
||||||
|
metadata->data.thumbnail.height = result.height();
|
||||||
|
}
|
||||||
|
// only try with the first match
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray getThumbnail(const QString &path, DataType type, metadata_t *metadata)
|
||||||
|
{
|
||||||
|
QByteArray data;
|
||||||
|
|
||||||
|
if(MASK_SET(type, SaveData)) {
|
||||||
|
QFile file(QDir(path).absoluteFilePath("ICON0.PNG"));
|
||||||
|
|
||||||
|
if(file.open(QIODevice::ReadOnly)) {
|
||||||
|
data = file.readAll();
|
||||||
|
}
|
||||||
|
} else if(MASK_SET(type, Photo)) {
|
||||||
|
QImage img;
|
||||||
|
|
||||||
|
if(img.load(path)) {
|
||||||
|
QBuffer buffer(&data);
|
||||||
|
buffer.open(QIODevice::WriteOnly);
|
||||||
|
QImage result = img.scaled(213, 120, Qt::KeepAspectRatio, Qt::FastTransformation);
|
||||||
|
result.save(&buffer, "JPEG");
|
||||||
|
metadata->data.thumbnail.width = result.width();
|
||||||
|
metadata->data.thumbnail.height = result.height();
|
||||||
|
}
|
||||||
|
} else if(MASK_SET(type, Music)) {
|
||||||
|
if(MASK_SET(type, Folder)) {
|
||||||
|
// TODO: try to load an album cover from one of the audio files.
|
||||||
|
data = findFolderAlbumArt(path, metadata);
|
||||||
|
} else {
|
||||||
|
MediaInfoLib::MediaInfo media;
|
||||||
|
|
||||||
|
if(media.Open(path.toStdWString())) {
|
||||||
|
QString base64 = QString::fromStdWString(media.Get(MediaInfoLib::Stream_General, 0, MediaInfoLib::General_Cover_Data));
|
||||||
|
QImage img;
|
||||||
|
|
||||||
|
if(base64.size() > 0 && img.loadFromData(QByteArray::fromBase64(base64.toUtf8()))) {
|
||||||
|
QBuffer buffer(&data);
|
||||||
|
buffer.open(QIODevice::WriteOnly);
|
||||||
|
// use smooth transformation for the ambum art since is important to display correctly
|
||||||
|
QImage result = img.scaled(256, 256, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||||
|
result.save(&buffer, "JPEG");
|
||||||
|
metadata->data.thumbnail.width = result.width();
|
||||||
|
metadata->data.thumbnail.height = result.height();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//TODO: implement thumbnails for videos
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
6
utils.h
6
utils.h
@@ -20,9 +20,14 @@
|
|||||||
#ifndef UTILS_H
|
#ifndef UTILS_H
|
||||||
#define UTILS_H
|
#define UTILS_H
|
||||||
|
|
||||||
|
#include <QByteArray>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <vitamtp.h>
|
||||||
|
}
|
||||||
|
|
||||||
// Qt4 doesn't have public methods for Thread::*sleep
|
// Qt4 doesn't have public methods for Thread::*sleep
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||||
typedef QThread Sleeper;
|
typedef QThread Sleeper;
|
||||||
@@ -38,5 +43,6 @@
|
|||||||
|
|
||||||
bool removeRecursively(const QString &dirName);
|
bool removeRecursively(const QString &dirName);
|
||||||
bool getDiskSpace(const QString &dir, quint64 *free, quint64 *total);
|
bool getDiskSpace(const QString &dir, quint64 *free, quint64 *total);
|
||||||
|
QByteArray getThumbnail(const QString &path, DataType type, metadata_t *metadata);
|
||||||
|
|
||||||
#endif // UTILS_H
|
#endif // UTILS_H
|
||||||
|
@@ -35,6 +35,8 @@ BroadcastSignal::BroadcastSignal(QObject *parent) :
|
|||||||
qsrand(QTime::currentTime().msec());
|
qsrand(QTime::currentTime().msec());
|
||||||
this_object = this;
|
this_object = this;
|
||||||
started = false;
|
started = false;
|
||||||
|
strcpy(hostname, QHostInfo::localHostName().toStdString().c_str());
|
||||||
|
BroadcastSignal::info.name = hostname;
|
||||||
}
|
}
|
||||||
|
|
||||||
BroadcastSignal::~BroadcastSignal()
|
BroadcastSignal::~BroadcastSignal()
|
||||||
@@ -54,7 +56,7 @@ int BroadcastSignal::generatePin(wireless_vita_info_t *info, int *p_err)
|
|||||||
int pin = qrand() % 100000000;
|
int pin = qrand() % 100000000;
|
||||||
qDebug("Your registration PIN for %s is: %08d", info->name, pin);
|
qDebug("Your registration PIN for %s is: %08d", info->name, pin);
|
||||||
*p_err = 0;
|
*p_err = 0;
|
||||||
emit this_object->createdPin(pin);
|
emit this_object->receivedPin(pin);
|
||||||
return pin;
|
return pin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -45,11 +45,12 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
volatile bool started;
|
volatile bool started;
|
||||||
|
char hostname[256];
|
||||||
//used to emit a signal from a static method
|
//used to emit a signal from a static method
|
||||||
static BroadcastSignal *this_object;
|
static BroadcastSignal *this_object;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void createdPin(int);
|
void receivedPin(int);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void stopBroadcast();
|
void stopBroadcast();
|
||||||
|
Reference in New Issue
Block a user