Make sure that BaseWorker deletes the thread when is finished.

Implemented ClientManager so it can manage the usb and wireless threads.
Impelmented better mutex logic on CmaClient.
Execute the cma events in a different thread so the event listener is
available.
Code refactoring.
Fix memory leaks in threads.
Updated readme.
This commit is contained in:
codestation
2013-08-25 01:40:14 -04:30
parent dfdd79e850
commit 92f4572814
29 changed files with 523 additions and 411 deletions

View File

@@ -16,14 +16,12 @@ official CMA and also offer some features missing in the original one.
* Basic metadata for videos (duration, dimensions, thumbnail).
* Basic metadata for photos (dimensions, thumbnails).
* Easy wireless pairing (show PIN to the user when a Vita is detected).
* Ability to restart the connection if the Vita is reconnected (on test).
* Ability to restart the connection if the Vita is reconnected.
#### TODO:
* Fix remaining bugs with thread synchronizations.
* Remove wireless/usb switch and allow both to run.
* Folder categories for music/videos.
* Complete categories for music.
* SQLite backend for database.
* Fix wireless streaming for music/videos.
* Fix streaming for music.
## Planned features
* **Backup browser**: provide a human readable listing of the games saved on the
@@ -37,7 +35,8 @@ using the wireless streaming feature.
#### Dependencies
* [Qt 4.x or 5.x](http://qt-project.org/)
* [VitaMTP](https://github.com/yifanlu/VitaMTP)
* [VitaMTP](https://github.com/yifanlu/VitaMTP). Use my
[fork](https://github.com/codestation/VitaMTP) until the patches are merged upstream.
* [Libav](http://www.libav.org/)

View File

@@ -209,17 +209,17 @@ QByteArray AVDecoder::getVideoThumbnail(int width, int height)
avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);
SwsContext *sws_ctx = sws_getContext(
pCodecCtx->width,
pCodecCtx->height,
pCodecCtx->pix_fmt,
pCodecCtx->width,
pCodecCtx->height,
PIX_FMT_RGB24,
SWS_BICUBIC,
NULL,
NULL,
NULL
);
pCodecCtx->width,
pCodecCtx->height,
pCodecCtx->pix_fmt,
pCodecCtx->width,
pCodecCtx->height,
PIX_FMT_RGB24,
SWS_BICUBIC,
NULL,
NULL,
NULL
);
if(!sws_ctx) {
avcodec_close(pCodecCtx);
@@ -238,8 +238,8 @@ QByteArray AVDecoder::getVideoThumbnail(int width, int height)
QImage image(pCodecCtx->width, pCodecCtx->height, QImage::Format_RGB888);
for(int y = 0, height = pCodecCtx->height, width = pCodecCtx->width; y < height; y++){
memcpy(image.scanLine(y), pFrameRGB->data[0] + y * pFrameRGB->linesize[0], width * 3);
for(int y = 0, h = pCodecCtx->height, w = pCodecCtx->width; y < h; y++) {
memcpy(image.scanLine(y), pFrameRGB->data[0] + y * pFrameRGB->linesize[0], w * 3);
}
QBuffer imgbuffer(&data);

View File

@@ -27,9 +27,10 @@ extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <vitamtp.h>
}
#include <vitamtp.h>
class AVDecoder
{
public:
@@ -46,10 +47,10 @@ public:
class AvInit
{
public:
AvInit()
{
av_register_all();
}
AvInit()
{
av_register_all();
}
};
static AvInit init;

View File

@@ -25,10 +25,6 @@ BaseWorker::BaseWorker(QObject *parent) :
thread = NULL;
}
void BaseWorker::onFinished()
{
}
void BaseWorker::start(const char *thread_name)
{
thread = new QThread();
@@ -37,25 +33,21 @@ void BaseWorker::start(const char *thread_name)
thread->setObjectName(thread_name);
}
// Move this service to a new thread
this->moveToThread(thread);
// The main loop will be executed when the thread
// signals that it has started.
connect(thread, SIGNAL(started()), this, SLOT(process()));
// Make sure that we notify ourselves when the thread
// is finished in order to correctly clean-up the thread.
connect(thread, SIGNAL(finished()), this, SLOT(onFinished()));
// The thread will quit when the sercives
// signals that it's finished.
connect(this, SIGNAL(finished()), thread, SLOT(quit()));
// The thread will be scheduled for deletion when the
// service signals that it's finished
connect(this, SIGNAL(finished()), this, SLOT(onFinished()));
connect(this, SIGNAL(finished()), thread, SLOT(quit()), Qt::DirectConnection);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
// Start the thread
thread->start();
}
bool BaseWorker::wait()
{
return thread->wait();
}
void BaseWorker::onFinished()
{
}

View File

@@ -31,6 +31,7 @@ public:
explicit BaseWorker(QObject *parent = 0);
void start(const char *thread_name = NULL);
bool wait();
private:
QThread *thread;
@@ -38,11 +39,11 @@ private:
signals:
void finished();
public slots:
virtual void onFinished();
protected slots:
virtual void process() = 0;
private slots:
virtual void onFinished();
};
#endif // BASEWORKER_H

View File

@@ -31,7 +31,7 @@ bool DeviceCapability::exchangeInfo(vita_device_t *device)
if(vita_info.protocolVersion > VITAMTP_PROTOCOL_MAX_VERSION) {
qWarning("Vita wants protocol version %08d while we only support %08d. Attempting to continue.",
vita_info.protocolVersion, VITAMTP_PROTOCOL_MAX_VERSION);
vita_info.protocolVersion, VITAMTP_PROTOCOL_MAX_VERSION);
}
QString hostname = QHostInfo::localHostName();

View File

@@ -20,9 +20,7 @@
#ifndef CAPABILITY_H
#define CAPABILITY_H
extern "C" {
#include <vitamtp.h>
}
class DeviceCapability
{
@@ -31,10 +29,18 @@ public:
bool exchangeInfo(vita_device_t *device);
//TODO: vita_info_t doesn't retrieve this info, update vitamtp to get it
const char *getVersion() { return ""; }
const char *getProtocol() { return ""; }
const char *getOnlineId() { return "PS Vita"; }
const char *getModelInfo() { return ""; }
const char *getVersion() {
return "";
}
const char *getProtocol() {
return "";
}
const char *getOnlineId() {
return "PS Vita";
}
const char *getModelInfo() {
return "";
}
private:
capability_info_t *generate_pc_capability_info();

75
clientmanager.cpp Normal file
View File

@@ -0,0 +1,75 @@
#include "clientmanager.h"
#include "cmaclient.h"
ClientManager::ClientManager(QObject *parent) :
QObject(parent)
{
}
void ClientManager::start()
{
// initializing database for the first use
refreshDatabase();
CmaEvent::db = &db;
thread_count = 2;
qDebug("Starting cma threads");
CmaClient *client;
usb_thread = new QThread();
client = new CmaClient();
usb_thread->setObjectName("usb_thread");
connect(usb_thread, SIGNAL(started()), client, SLOT(connectUsb()));
connect(client, SIGNAL(receivedPin(int)), this, SIGNAL(receivedPin(int)));
connect(client, SIGNAL(finished()), usb_thread, SLOT(quit()), Qt::DirectConnection);
connect(usb_thread, SIGNAL(finished()), usb_thread, SLOT(deleteLater()));
connect(usb_thread, SIGNAL(finished()), this, SLOT(threadStopped()));
connect(usb_thread, SIGNAL(finished()), client, SLOT(deleteLater()));
connect(client, SIGNAL(deviceConnected(QString)), this, SIGNAL(deviceConnected(QString)));
connect(client, SIGNAL(deviceDisconnected()), this, SIGNAL(deviceDisconnected()));
connect(client, SIGNAL(refreshDatabase()), this, SLOT(refreshDatabase()));
client->moveToThread(usb_thread);
usb_thread->start();
wireless_thread = new QThread();
client = new CmaClient();
wireless_thread->setObjectName("wireless_thread");
connect(wireless_thread, SIGNAL(started()), client, SLOT(connectWireless()));
connect(client, SIGNAL(finished()), wireless_thread, SLOT(quit()), Qt::DirectConnection);
connect(wireless_thread, SIGNAL(finished()), wireless_thread, SLOT(deleteLater()));
connect(wireless_thread, SIGNAL(finished()), this, SLOT(threadStopped()));
connect(wireless_thread, SIGNAL(finished()), client, SLOT(deleteLater()));
connect(client, SIGNAL(deviceConnected(QString)), this, SIGNAL(deviceConnected(QString)));
connect(client, SIGNAL(deviceDisconnected()), this, SIGNAL(deviceDisconnected()));
connect(client, SIGNAL(refreshDatabase()), this, SLOT(refreshDatabase()));
client->moveToThread(wireless_thread);
wireless_thread->start();
}
void ClientManager::refreshDatabase()
{
QMutexLocker locker(&db.mutex);
db.destroy();
int count = db.create();
qDebug("Added %i entries to the database", count);
}
void ClientManager::stop()
{
CmaClient::stop();
}
void ClientManager::threadStopped()
{
mutex.lock();
if(--thread_count == 0) {
emit stopped();
}
mutex.unlock();
}

37
clientmanager.h Normal file
View File

@@ -0,0 +1,37 @@
#ifndef CLIENTMANAGER_H
#define CLIENTMANAGER_H
#include "database.h"
#include <QObject>
#include <QThread>
class ClientManager : public QObject
{
Q_OBJECT
public:
explicit ClientManager(QObject *parent = 0);
void start();
void stop();
private:
int thread_count;
QMutex mutex;
Database db;
QThread *usb_thread;
QThread *wireless_thread;
signals:
void deviceConnected(QString);
void deviceDisconnected();
void receivedPin(int);
void stopped();
private slots:
void refreshDatabase();
void threadStopped();
};
#endif // CLIENTMANAGER_H

View File

@@ -28,13 +28,13 @@
#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";
"%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";
@@ -85,10 +85,10 @@ void CmaBroadcast::setAvailable()
QMutexLocker locker(&mutex);
reply.clear();
reply.insert(0, 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')));
.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')));
reply.append('\0');
}
@@ -97,9 +97,9 @@ void CmaBroadcast::setUnavailable()
QMutexLocker locker(&mutex);
reply.clear();
reply.insert(0, 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')));
.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')));
reply.append('\0');
}

View File

@@ -23,7 +23,7 @@
#include "cmaevent.h"
#include "utils.h"
#include "QApplication"
#include <QApplication>
#include <QDateTime>
#include <QDebug>
#include <QDir>
@@ -33,9 +33,12 @@
QMutex CmaClient::mutex;
QMutex CmaClient::runner;
QMutex CmaClient::eloop;
bool CmaClient::is_running = true;
bool CmaClient::event_loop_enabled = true;
QMutex CmaClient::cancel;
QSemaphore CmaClient::sema;
bool CmaClient::is_active = true;
bool CmaClient::in_progress = false;
int CmaClient::is_cancelled = false;
CmaClient *CmaClient::this_object = NULL;
@@ -43,43 +46,28 @@ CmaClient::CmaClient(QObject *parent) :
QObject(parent)
{
this_object = this;
device = NULL;
}
bool CmaClient::isRunning()
{
QMutexLocker locker(&runner);
return is_running;
}
void CmaClient::setRunning(bool state)
{
QMutexLocker locker(&runner);
is_running = state;
}
void CmaClient::connectUsb()
{
vita_device_t *vita;
//int num_tries = 0;
qDebug() << "Starting usb_thread:" << QThread::currentThreadId();
while(isRunning()) {
do {
if((vita = VitaMTP_Get_First_USB_Vita()) !=NULL) {
cancel_wireless = 1;
processNewConnection(vita);
VitaMTP_Close_USB_Vita();
} else {
//qDebug("No Vita detected via USB, attempt %i", +num_tries++);
if(mutex.tryLock()) {
mutex.unlock();
Sleeper::msleep(2000);
} else {
mutex.lock();
mutex.unlock();
//TODO: replace this with an event-driven setup
Sleeper::msleep(2000);
mutex.lock();
if(in_progress) {
sema.acquire();
}
mutex.unlock();
}
}
} while(isActive());
qDebug("Finishing usb_thread");
emit finished();
@@ -88,24 +76,24 @@ void CmaClient::connectUsb()
void CmaClient::connectWireless()
{
vita_device_t *vita;
wireless_host_info_t host;
host.port = QCMA_REQUEST_PORT;
wireless_host_info_t host = {NULL, NULL, NULL, QCMA_REQUEST_PORT};
typedef CmaClient CC;
cancel_wireless = 0;
qDebug() << "Starting wireless_thread:" << QThread::currentThreadId();
while(isRunning()) {
if((vita = VitaMTP_Get_First_Wireless_Vita(&host, 0, &cancel_wireless, CC::deviceRegistered, CC::generatePin)) != NULL) {
do {
if((vita = VitaMTP_Get_First_Wireless_Vita(&host, 0, CC::cancelCallback, CC::deviceRegistered, CC::generatePin)) != NULL) {
processNewConnection(vita);
} else {
qDebug("Wireless listener was cancelled");
// wait until the event loop of the usb thread is finished
Sleeper::msleep(2000);
mutex.lock();
cancel_wireless = 0;
mutex.unlock();
if(in_progress) {
sema.acquire();
}
mutex.unlock();;
}
}
} while(isActive());
qDebug("Finishing wireless_thread");
emit finished();
}
@@ -113,9 +101,9 @@ void CmaClient::connectWireless()
void CmaClient::processNewConnection(vita_device_t *device)
{
QMutexLocker locker(&mutex);
in_progress = true;
broadcast.setUnavailable();
this->device = device;
qDebug("Vita connected: id %s", VitaMTP_Get_Identification(device));
DeviceCapability *vita_info = new DeviceCapability();
@@ -124,10 +112,17 @@ void CmaClient::processNewConnection(vita_device_t *device)
} else {
// Conection successful, inform the user
emit deviceConnected(QString(tr("Connected to ")) + vita_info->getOnlineId());
enterEventLoop();
enterEventLoop(device);
}
VitaMTP_SendHostStatus(device, VITA_HOST_STATUS_EndConnection);
VitaMTP_Release_Device(device);
emit deviceDisconnected();
broadcast.setAvailable();
in_progress = false;
sema.release();
}
int CmaClient::deviceRegistered(const char *deviceid)
@@ -146,54 +141,67 @@ int CmaClient::generatePin(wireless_vita_info_t *info, int *p_err)
return pin;
}
void CmaClient::enterEventLoop()
int CmaClient::cancelCallback()
{
QMutexLocker locker(&cancel);
return is_cancelled;
}
void CmaClient::enterEventLoop(vita_device_t *device)
{
vita_event_t event;
qDebug("Starting event loop");
event_loop_enabled = true;
CmaEvent eventLoop(device);
eventLoop.start("event_thread");
while(isEventLoopEnabled()) {
while(isActive()) {
if(VitaMTP_Read_Event(device, &event) < 0) {
qWarning("Error reading event from Vita.");
break;
}
CmaEvent *vita_event = new CmaEvent(device, event);
connect(vita_event, SIGNAL(finishedEventLoop()), this, SLOT(finishEventLoop()));
connect(vita_event, SIGNAL(refreshDatabase()), this, SIGNAL(refreshDatabase()));
vita_event->start("cma_event");
// do not create a event for this since there aren't more events to read
if(event.Code == PTP_EC_VITA_RequestTerminate) {
qDebug("Terminating event thread");
break;
// this one shuold be processed inmediately
} else if(event.Code == PTP_EC_VITA_RequestCancelTask) {
quint32 eventIdToCancel = event.Param2;
qDebug("Cancelling event %d", eventIdToCancel);
VitaMTP_CancelTask(device, eventIdToCancel);
continue;
}
// the events are processed synchronously except for cancel/terminate
qDebug("Sending new event");
eventLoop.setEvent(event);
}
}
bool CmaClient::isEventLoopEnabled()
{
QMutexLocker locker(&eloop);
return event_loop_enabled;
}
void CmaClient::finishEventLoop()
{
QMutexLocker locker(&eloop);
event_loop_enabled = false;
}
void CmaClient::close()
{
if(device) {
VitaMTP_SendHostStatus(device, VITA_HOST_STATUS_EndConnection);
VitaMTP_Release_Device(device);
device = NULL;
}
eventLoop.stop();
eventLoop.wait();
qDebug("Finishing event loop");
}
void CmaClient::stop()
{
CmaClient::setRunning(false);
CmaClient::finishEventLoop();
CmaClient::setActive(false);
cancel.lock();
is_cancelled = true;
cancel.unlock();
}
CmaClient::~CmaClient()
bool CmaClient::isActive()
{
close();
QMutexLocker locker(&runner);
return is_active;
}
void CmaClient::setActive(bool state)
{
QMutexLocker locker(&runner);
is_active = state;
}

View File

@@ -24,47 +24,47 @@
#include "cmabroadcast.h"
#include "cmaobject.h"
#include "database.h"
#include "cmaevent.h"
#include <QObject>
#include <QSemaphore>
#include <QString>
#include <QWaitCondition>
extern "C" {
#include <vitamtp.h>
}
class CmaClient : public QObject
{
Q_OBJECT
public:
explicit CmaClient(QObject *parent = 0);
~CmaClient();
void launch();
private:
static bool isRunning();
static void setRunning(bool state);
static bool isActive();
static void setActive(bool state);
static bool isEventLoopEnabled();
static void setEventLoop(bool state);
void enterEventLoop();
void enterEventLoop(vita_device_t *device);
void processNewConnection(vita_device_t *device);
static int deviceRegistered(const char *deviceid);
static int generatePin(wireless_vita_info_t *info, int *p_err);
static int cancelCallback();
int cancel_wireless;
CmaBroadcast broadcast;
vita_device_t *device;
static bool event_loop_enabled;
static bool is_running;
static bool is_active;
static bool in_progress;
static int is_cancelled;
static CmaClient *this_object;
static QMutex mutex;
static QMutex runner;
static QMutex eloop;
static QMutex cancel;
static QSemaphore sema;
signals:
void newEvent(vita_event_t event);
void receivedPin(int);
void deviceDetected();
void deviceConnected(QString);
@@ -73,13 +73,11 @@ signals:
void finished();
public slots:
void close();
static void stop();
private slots:
void connectUsb();
void connectWireless();
static void finishEventLoop();
};
#endif // CMACLIENT_H

View File

@@ -7,16 +7,59 @@
#include <QSettings>
#include <QUrl>
Database CmaEvent::db;
Database *CmaEvent::db = NULL;
metadata_t CmaEvent::g_thumbmeta = {0, 0, 0, NULL, NULL, 0, 0, 0, Thumbnail, {{18, 144, 80, 0, 1, 1.0f, 2}}, NULL};
CmaEvent::CmaEvent(vita_device_t *s_device, vita_event_t s_event, QObject *parent) :
BaseWorker(parent), device(s_device), t_event(s_event)
CmaEvent::CmaEvent(vita_device_t *s_device, QObject *parent) :
BaseWorker(parent), device(s_device), is_active(true)
{
}
void CmaEvent::process()
{
qDebug() << "Starting event_thread:" << QThread::currentThreadId();
while(true) {
sema.acquire();
if(!isActive()) {
break;
}
mutex.lock();
processEvent();
mutex.unlock();
}
qDebug("Finishing event_thread");
emit finished();
}
bool CmaEvent::isActive()
{
QMutexLocker locker(&active);
return is_active;
}
void CmaEvent::stop()
{
QMutexLocker locker(&active);
is_active = false;
sema.release();
}
void CmaEvent::setDevice(vita_device_t *device)
{
QMutexLocker locker(&mutex);
this->device = device;
}
void CmaEvent::setEvent(vita_event_t event)
{
mutex.lock();
this->t_event = event;
mutex.unlock();
sema.release();
}
void CmaEvent::processEvent()
{
qDebug() << "Starting event_thread:" << QThread::currentThreadId();
switch(t_event.Code) {
@@ -29,9 +72,6 @@ void CmaEvent::process()
case PTP_EC_VITA_RequestSendObject:
vitaEventSendObject(&t_event, t_event.Param1);
break;
case PTP_EC_VITA_RequestCancelTask: // unimplemented
vitaEventCancelTask(&t_event, t_event.Param1);
break;
case PTP_EC_VITA_RequestSendHttpObjectFromURL:
vitaEventSendHttpObjectFromURL(&t_event, t_event.Param1);
break;
@@ -80,15 +120,10 @@ void CmaEvent::process()
case PTP_EC_VITA_RequestSendNPAccountInfo:
vitaEventSendNPAccountInfo(&t_event, t_event.Param1);
break;
case PTP_EC_VITA_RequestTerminate:
vitaEventRequestTerminate(&t_event, t_event.Param1);
break;
default:
vitaEventUnimplementated(&t_event, t_event.Param1);
}
qDebug("Ended event, code: 0x%x, id: %d", t_event.Code, t_event.Param1);
emit finished();
}
quint16 CmaEvent::processAllObjects(CMAObject *parent, quint32 handle)
@@ -106,12 +141,12 @@ quint16 CmaEvent::processAllObjects(CMAObject *parent, quint32 handle)
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) {
qDebug("Deleting %s", object->path.toStdString().c_str());
removeRecursively(object->path);
db.remove(object);
db->remove(object);
}
QDir dir(parent->path);
@@ -140,7 +175,7 @@ quint16 CmaEvent::processAllObjects(CMAObject *parent, quint32 handle)
object = new CMAObject(parent);
object->initObject(info);
object->metadata.handle = remote_meta.handle;
db.append(parent->metadata.ohfi, object);
db->append(parent->metadata.ohfi, object);
free(remote_meta.name);
qDebug("Added object %s with OHFI %i to database", object->metadata.path, object->metadata.ohfi);
@@ -151,7 +186,7 @@ quint16 CmaEvent::processAllObjects(CMAObject *parent, quint32 handle)
if(ret != PTP_RC_OK) {
qDebug("Deleteting object with OHFI %d", object->metadata.ohfi);
db.remove(object);
db->remove(object);
free(data.fileData);
return ret;
}
@@ -173,9 +208,9 @@ void CmaEvent::vitaEventGetTreatObject(vita_event_t *event, int eventId)
return;
}
QMutexLocker locker(&db.mutex);
QMutexLocker locker(&db->mutex);
CMAObject *parent = db.ohfiToObject(treatObject.ohfiParent);
CMAObject *parent = db->ohfiToObject(treatObject.ohfiParent);
if(parent == NULL) {
qWarning("Cannot find parent OHFI %d", treatObject.ohfiParent);
@@ -196,14 +231,14 @@ void CmaEvent::vitaEventSendCopyConfirmationInfo(vita_event_t *event, int eventI
return;
}
QMutexLocker locker(&db.mutex);
QMutexLocker locker(&db->mutex);
quint64 size = 0;
for(quint32 i = 0; i < info->count; i++) {
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]);
free(info);
return;
@@ -231,9 +266,9 @@ void CmaEvent::vitaEventSendObjectMetadataItems(vita_event_t *event, int eventId
return;
}
QMutexLocker locker(&db.mutex);
QMutexLocker locker(&db->mutex);
CMAObject *object = db.ohfiToObject(ohfi);
CMAObject *object = db->ohfiToObject(ohfi);
if(object == NULL) {
qWarning("Cannot find OHFI %d in database", ohfi);
@@ -259,13 +294,6 @@ void CmaEvent::vitaEventSendNPAccountInfo(vita_event_t *event, int eventId)
qWarning("Event 0x%x unimplemented!", event->Code);
}
void CmaEvent::vitaEventRequestTerminate(vita_event_t *event, int eventId)
{
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
//qWarning("Event 0x%x unimplemented!", event->Code);
emit finishedEventLoop();
}
void CmaEvent::vitaEventUnimplementated(vita_event_t *event, int eventId)
{
qWarning("Unknown event not handled, code: 0x%x, id: %d", event->Code, eventId);
@@ -276,10 +304,10 @@ void CmaEvent::vitaEventSendNumOfObject(vita_event_t *event, int 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;
int items = db.filterObjects(ohfi, NULL);
int items = db->filterObjects(ohfi, NULL);
if(VitaMTP_SendNumOfObject(device, eventId, items) != PTP_RC_OK) {
qWarning("Error occured receiving object count for OHFI parent %d", ohfi);
@@ -299,10 +327,10 @@ void CmaEvent::vitaEventSendObjectMetadata(vita_event_t *event, int eventId)
qWarning("GetBrowseInfo failed");
return;
}
QMutexLocker locker(&db.mutex);
QMutexLocker locker(&db->mutex);
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);
if(VitaMTP_SendObjectMetadata(device, eventId, meta) != PTP_RC_OK) { // send all objects with OHFI parent
@@ -318,12 +346,12 @@ void CmaEvent::vitaEventSendObject(vita_event_t *event, int eventId)
int ohfi = event->Param2;
QMutexLocker locker(&db.mutex);
QMutexLocker locker(&db->mutex);
qDebug("Searching object with OHFI %d", ohfi);
Database::find_data iters;
if(!db.find(ohfi, iters)) {
if(!db->find(ohfi, iters)) {
qWarning("Failed to find OHFI %d", ohfi);
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI);
return;
@@ -363,7 +391,7 @@ void CmaEvent::vitaEventSendObject(vita_event_t *event, int eventId)
qDebug("Sending %s of %lu bytes to device", object->metadata.name, len);
qDebug("OHFI %d with handle 0x%08X", ohfi, parentHandle);
if(VitaMTP_SendObject(device, &parentHandle, &handle, &object->metadata, data) != PTP_RC_OK) {
if(VitaMTP_SendObject(device, &parentHandle, &handle, &object->metadata, data, NULL) != PTP_RC_OK) {
qWarning("Sending of %s failed.", object->metadata.name);
file.unmap(data);
return;
@@ -389,14 +417,6 @@ void CmaEvent::vitaEventSendObject(vita_event_t *event, int eventId)
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Data); // TODO: Send thumbnail
}
void CmaEvent::vitaEventCancelTask(vita_event_t *event, int eventId)
{
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
int eventIdToCancel = event->Param2;
VitaMTP_CancelTask(device, eventIdToCancel);
}
void CmaEvent::vitaEventSendHttpObjectFromURL(vita_event_t *event, int eventId)
{
qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
@@ -451,9 +471,9 @@ void CmaEvent::vitaEventSendObjectStatus(vita_event_t *event, int eventId)
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
qDebug("Object %s not in database (OHFI: %i). Sending OK response for non-existence", objectstatus.title, objectstatus.ohfiRoot);
@@ -477,10 +497,10 @@ void CmaEvent::vitaEventSendObjectThumb(vita_event_t *event, int 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;
CMAObject *object = db.ohfiToObject(ohfi);
CMAObject *object = db->ohfiToObject(ohfi);
if(object == NULL) {
qWarning("Cannot find OHFI %d in database.", ohfi);
@@ -515,10 +535,10 @@ void CmaEvent::vitaEventDeleteObject(vita_event_t *event, int 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;
CMAObject *object = db.ohfiToObject(ohfi);
CMAObject *object = db->ohfiToObject(ohfi);
if(object == NULL) {
qWarning("OHFI %d not found", ohfi);
@@ -528,7 +548,7 @@ void CmaEvent::vitaEventDeleteObject(vita_event_t *event, int eventId)
qDebug("Deleting %s, OHFI: %i", object->metadata.path, object->metadata.ohfi);
removeRecursively(object->path);
db.remove(object);
db->remove(object);
VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
}
@@ -547,7 +567,7 @@ void CmaEvent::vitaEventGetSettingInfo(vita_event_t *event, int eventId)
if(QSettings().value("lastAccountId").toString() != settingsinfo->current_account.accountId) {
db.setUUID(settingsinfo->current_account.accountId);
db->setUUID(settingsinfo->current_account.accountId);
// set the database to be updated ASAP
emit refreshDatabase();
}
@@ -604,9 +624,9 @@ void CmaEvent::vitaEventSendPartOfObject(vita_event_t *event, int eventId)
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) {
qWarning("Cannot find object for OHFI %d", part_init.ohfi);
@@ -644,9 +664,9 @@ void CmaEvent::vitaEventOperateObject(vita_event_t *event, int eventId)
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
if(root == NULL) {
@@ -665,7 +685,7 @@ void CmaEvent::vitaEventOperateObject(vita_event_t *event, int eventId)
} else {
CMAObject *newobj = new CMAObject(root);
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);
VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, newobj->metadata.ohfi);
}
@@ -681,7 +701,7 @@ void CmaEvent::vitaEventOperateObject(vita_event_t *event, int eventId)
} else {
CMAObject *newobj = new CMAObject(root);
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);
VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, newobj->metadata.ohfi);
}
@@ -696,7 +716,7 @@ void CmaEvent::vitaEventOperateObject(vita_event_t *event, int eventId)
//rename the current object
root->rename(operateobject.title);
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
while(iters.it != iters.end) {
@@ -740,8 +760,8 @@ void CmaEvent::vitaEventGetPartOfObject(vita_event_t *event, int eventId)
return;
}
QMutexLocker locker(&db.mutex);
CMAObject *object = db.ohfiToObject(part_init.ohfi);
QMutexLocker locker(&db->mutex);
CMAObject *object = db->ohfiToObject(part_init.ohfi);
if(object == NULL) {
qWarning("Cannot find OHFI %d", part_init.ohfi);
@@ -771,10 +791,10 @@ void CmaEvent::vitaEventSendStorageSize(vita_event_t *event, int 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;
CMAObject *object = db.ohfiToObject(ohfi);
CMAObject *object = db->ohfiToObject(ohfi);
if(object == NULL) {
qWarning("Error: Cannot find OHFI %d", ohfi);
@@ -825,9 +845,9 @@ void CmaEvent::vitaEventCheckExistance(vita_event_t *event, int eventId)
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) {
VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Different_Object);

View File

@@ -6,6 +6,7 @@
#include "baseworker.h"
#include <QObject>
#include <QSemaphore>
#include <vitamtp.h>
@@ -13,16 +14,15 @@ class CmaEvent : public BaseWorker
{
Q_OBJECT
public:
explicit CmaEvent(vita_device_t *s_device, vita_event_t s_event, QObject *parent = 0);
explicit CmaEvent(vita_device_t *s_device, QObject *parent = 0);
static Database db;
static Database *db;
private:
uint16_t processAllObjects(CMAObject *parent, uint32_t handle);
void vitaEventSendObject(vita_event_t *event, int eventId);
void vitaEventSendObjectMetadata(vita_event_t *event, int eventId);
void vitaEventSendNumOfObject(vita_event_t *event, int eventId);
void vitaEventCancelTask(vita_event_t *event, int eventId);
void vitaEventSendHttpObjectFromURL(vita_event_t *event, int eventId);
void vitaEventUnimplementated(vita_event_t *event, int eventId);
void vitaEventSendObjectStatus(vita_event_t *event, int eventId);
@@ -39,10 +39,17 @@ private:
void vitaEventSendCopyConfirmationInfo(vita_event_t *event, int eventId);
void vitaEventSendObjectMetadataItems(vita_event_t *event, int eventId);
void vitaEventSendNPAccountInfo(vita_event_t *event, int eventId);
void vitaEventRequestTerminate(vita_event_t *event, int eventId);
void processEvent();
bool isActive();
void setDevice(vita_device_t *device);
vita_device_t *device;
vita_event_t t_event;
bool is_active;
QMutex mutex;
QMutex active;
QSemaphore sema;
static metadata_t g_thumbmeta;
@@ -53,7 +60,8 @@ signals:
public slots:
void process();
void setEvent(vita_event_t event);
void stop();
};
#endif // CMAEVENT_H

View File

@@ -23,9 +23,7 @@
#include <QFileInfo>
#include <QString>
extern "C" {
#include <vitamtp.h>
}
#define OHFI_OFFSET 1000

View File

@@ -34,70 +34,70 @@ void CMARootObject::initObject(const QString &path)
metadata.type = VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_REGULAR;
switch(root_ohfi) {
case VITA_OHFI_MUSIC:
metadata.dataType = Music;
this->path = path;
num_filters = 2;
filters = new metadata_t[2];
//createFilter(&filters[0], "Artists", VITA_DIR_TYPE_MASK_MUSIC | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_ARTISTS);
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;
case VITA_OHFI_MUSIC:
metadata.dataType = Music;
this->path = path;
num_filters = 2;
filters = new metadata_t[2];
//createFilter(&filters[0], "Artists", VITA_DIR_TYPE_MASK_MUSIC | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_ARTISTS);
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;
case VITA_OHFI_PHOTO:
metadata.dataType = Photo;
this->path = path;
num_filters = 2;
filters = new metadata_t[2];
createFilter(&filters[0], "Folders", VITA_DIR_TYPE_MASK_PHOTO | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_REGULAR);
createFilter(&filters[1], "All", VITA_DIR_TYPE_MASK_PHOTO | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_ALL);
break;
case VITA_OHFI_PHOTO:
metadata.dataType = Photo;
this->path = path;
num_filters = 2;
filters = new metadata_t[2];
createFilter(&filters[0], "Folders", VITA_DIR_TYPE_MASK_PHOTO | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_REGULAR);
createFilter(&filters[1], "All", VITA_DIR_TYPE_MASK_PHOTO | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_ALL);
break;
case VITA_OHFI_VIDEO:
metadata.dataType = Video;
this->path = path;
num_filters = 2;
filters = new metadata_t[2];
createFilter(&filters[0], "Folders", VITA_DIR_TYPE_MASK_VIDEO | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_REGULAR);
createFilter(&filters[1], "All", VITA_DIR_TYPE_MASK_VIDEO | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_ALL);
break;
case VITA_OHFI_VIDEO:
metadata.dataType = Video;
this->path = path;
num_filters = 2;
filters = new metadata_t[2];
createFilter(&filters[0], "Folders", VITA_DIR_TYPE_MASK_VIDEO | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_REGULAR);
createFilter(&filters[1], "All", VITA_DIR_TYPE_MASK_VIDEO | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_ALL);
break;
case VITA_OHFI_VITAAPP:
metadata.dataType = App;
this->path = QDir(QDir(path).absoluteFilePath("APP")).absoluteFilePath(uuid);
num_filters = 0;
break;
case VITA_OHFI_VITAAPP:
metadata.dataType = App;
this->path = QDir(QDir(path).absoluteFilePath("APP")).absoluteFilePath(uuid);
num_filters = 0;
break;
case VITA_OHFI_PSPAPP:
metadata.dataType = App;
this->path = QDir(QDir(path).absoluteFilePath("PGAME")).absoluteFilePath(uuid);
num_filters = 0;
break;
case VITA_OHFI_PSPAPP:
metadata.dataType = App;
this->path = QDir(QDir(path).absoluteFilePath("PGAME")).absoluteFilePath(uuid);
num_filters = 0;
break;
case VITA_OHFI_PSPSAVE:
metadata.dataType = SaveData;
this->path = QDir(QDir(path).absoluteFilePath("PSAVEDATA")).absoluteFilePath(uuid);
num_filters = 0;
break;
case VITA_OHFI_PSPSAVE:
metadata.dataType = SaveData;
this->path = QDir(QDir(path).absoluteFilePath("PSAVEDATA")).absoluteFilePath(uuid);
num_filters = 0;
break;
case VITA_OHFI_PSXAPP:
metadata.dataType = App;
this->path = QDir(QDir(path).absoluteFilePath("PSGAME")).absoluteFilePath(uuid);
num_filters = 0;
break;
case VITA_OHFI_PSXAPP:
metadata.dataType = App;
this->path = QDir(QDir(path).absoluteFilePath("PSGAME")).absoluteFilePath(uuid);
num_filters = 0;
break;
case VITA_OHFI_PSMAPP:
metadata.dataType = App;
this->path = QDir(QDir(path).absoluteFilePath("PSM")).absoluteFilePath(uuid);
num_filters = 0;
break;
case VITA_OHFI_PSMAPP:
metadata.dataType = App;
this->path = QDir(QDir(path).absoluteFilePath("PSM")).absoluteFilePath(uuid);
num_filters = 0;
break;
case VITA_OHFI_BACKUP:
metadata.dataType = App;
this->path = QDir(QDir(path).absoluteFilePath("SYSTEM")).absoluteFilePath(uuid);
num_filters = 0;
case VITA_OHFI_BACKUP:
metadata.dataType = App;
this->path = QDir(QDir(path).absoluteFilePath("SYSTEM")).absoluteFilePath(uuid);
num_filters = 0;
}
}

View File

@@ -24,9 +24,7 @@
#include <QList>
extern "C" {
#include <vitamtp.h>
}
class CMARootObject : public CMAObject
{

View File

@@ -91,33 +91,33 @@ void ConfigWidget::browseBtnPressed(int btn)
QLineEdit *lineedit;
switch(btn) {
case BTN_PHOTO:
lineedit = ui->photoPath;
msg = tr("Select the folder to be used as a photo source");
break;
case BTN_PHOTO:
lineedit = ui->photoPath;
msg = tr("Select the folder to be used as a photo source");
break;
case BTN_MUSIC:
lineedit = ui->musicPath;
msg = tr("Select the folder to be used as a music source");
break;
case BTN_MUSIC:
lineedit = ui->musicPath;
msg = tr("Select the folder to be used as a music source");
break;
case BTN_VIDEO:
lineedit = ui->videoPath;
msg = tr("Select the folder to be used as a video source");
break;
case BTN_VIDEO:
lineedit = ui->videoPath;
msg = tr("Select the folder to be used as a video source");
break;
case BTN_APPS:
lineedit = ui->appPath;
msg = tr("Select the folder to be used to save PS Vita games and backups");
break;
case BTN_APPS:
lineedit = ui->appPath;
msg = tr("Select the folder to be used to save PS Vita games and backups");
break;
case BTN_URL:
lineedit = ui->urlPath;
msg = tr("Select the folder to be used to fetch software updates");
break;
case BTN_URL:
lineedit = ui->urlPath;
msg = tr("Select the folder to be used to fetch software updates");
break;
default:
return;
default:
return;
}
QFileDialog dialog;

View File

@@ -34,7 +34,8 @@ const QStringList Database::video_types = QStringList() << "mp4";
Database::Database(QObject *parent) :
QObject(parent), mutex(QMutex::Recursive)
{
CMARootObject::uuid = QSettings().value("lastAccountId", "ffffffffffffffff").toString();
QString uuid = QSettings().value("lastAccountId", "ffffffffffffffff").toString();
CMARootObject::uuid = uuid;
}
Database::~Database()
@@ -63,26 +64,26 @@ int Database::create()
CMARootObject *obj = new CMARootObject(ohfi_array[i]);
switch(ohfi_array[i]) {
case VITA_OHFI_MUSIC:
obj->initObject(settings.value("musicPath").toString());
break;
case VITA_OHFI_MUSIC:
obj->initObject(settings.value("musicPath").toString());
break;
case VITA_OHFI_PHOTO:
obj->initObject(settings.value("photoPath").toString());
break;
case VITA_OHFI_PHOTO:
obj->initObject(settings.value("photoPath").toString());
break;
case VITA_OHFI_VIDEO:
obj->initObject(settings.value("videoPath").toString());
break;
case VITA_OHFI_VIDEO:
obj->initObject(settings.value("videoPath").toString());
break;
case VITA_OHFI_BACKUP:
case VITA_OHFI_VITAAPP:
case VITA_OHFI_PSPAPP:
case VITA_OHFI_PSPSAVE:
case VITA_OHFI_PSXAPP:
case VITA_OHFI_PSMAPP:
case VITA_OHFI_BACKUP:
case VITA_OHFI_VITAAPP:
case VITA_OHFI_PSPAPP:
case VITA_OHFI_PSPSAVE:
case VITA_OHFI_PSXAPP:
case VITA_OHFI_PSMAPP:
obj->initObject(settings.value("appsPath").toString());
obj->initObject(settings.value("appsPath").toString());
}
root_list list;
@@ -382,9 +383,6 @@ int Database::filterObjects(int ohfiParent, metadata_t **p_head)
*p_head = temp.next_metadata;
}
if(p_head) {
dumpMetadataList(*p_head);
}
return numObjects;
}

View File

@@ -27,9 +27,7 @@
#include <QMutex>
#include <QObject>
extern "C" {
#include <vitamtp.h>
}
class Database : public QObject
{

View File

@@ -17,6 +17,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef Q_OS_WIN32
#include <signal.h>
#endif
#include <QDebug>
#include <QThread>
@@ -31,8 +35,8 @@ void noMessageOutput(QtMsgType type, const QMessageLogContext &, const QString &
void noMessageOutput(QtMsgType type, const char *msg)
{
#endif
Q_UNUSED(type);
Q_UNUSED(msg);
Q_UNUSED(type);
Q_UNUSED(msg);
}
int main(int argc, char *argv[])
@@ -43,6 +47,13 @@ int main(int argc, char *argv[])
SingleApplication app(argc, argv);
#ifndef Q_OS_WIN32
// FIXME: libmtp sends SIGPIPE if a socket write fails crashing the whole app
// the proper fix is to libmtp to handle the cancel properly or ignoring
// SIGPIPE on the socket
signal(SIGPIPE, SIG_IGN);
#endif
if(!app.arguments().contains("--with-debug")) {
VitaMTP_Set_Logging(VitaMTP_NONE);
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)

View File

@@ -49,7 +49,7 @@ void MainWidget::checkSettings()
return;
}
}
startServer();
manager.start();
}
void MainWidget::dialogResult(int result)
@@ -57,55 +57,18 @@ void MainWidget::dialogResult(int result)
if(result == QDialog::Accepted) {
if(first_run) {
first_run = false;
startServer();
manager.start();
}
} else if(first_run) {
qApp->quit();
}
}
void MainWidget::startServer()
{
qDebug("Starting cma threads");
QThread *thread;
CmaClient *client;
thread = new QThread();
client = new CmaClient();
thread->setObjectName("usb_thread");
connect(thread, SIGNAL(started()), client, SLOT(connectUsb()));
connect(client, SIGNAL(receivedPin(int)), this, SLOT(showPin(int)));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), client, SLOT(deleteLater()));
connectClientSignals(client);
client->moveToThread(thread);
thread->start();
thread = new QThread();
client = new CmaClient();
thread->setObjectName("wireless_thread");
connect(thread, SIGNAL(started()), client, SLOT(connectWireless()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), client, SLOT(deleteLater()));
connectClientSignals(client);
client->moveToThread(thread);
thread->start();
}
void MainWidget::stopServer()
{
CmaClient::stop();
qApp->quit();
}
void MainWidget::refreshDatabase()
{
QMutexLocker locker(&CmaEvent::db.mutex);
CmaEvent::db.destroy();
int count = CmaEvent::db.create();
qDebug("Added %i entries to the database", count);
setTrayTooltip(tr("Shutting down..."));
receiveMessage(tr("Stopping QCMA..."));
manager.stop();
}
void MainWidget::deviceDisconnect()
@@ -114,14 +77,6 @@ void MainWidget::deviceDisconnect()
receiveMessage(tr("The device has been disconnected"));
}
void MainWidget::connectClientSignals(CmaClient *client)
{
connect(client, SIGNAL(deviceConnected(QString)), this, SLOT(receiveMessage(QString)));
connect(client, SIGNAL(deviceConnected(QString)), this, SLOT(setTrayTooltip(QString)));
connect(client, SIGNAL(deviceDisconnected()), this, SLOT(deviceDisconnect()));
connect(client, SIGNAL(refreshDatabase()), this, SLOT(refreshDatabase()));
}
void MainWidget::showPin(int pin)
{
receiveMessage(QString(tr("Received PIN: %1").arg(QString::number(pin), 8, QChar('0'))));
@@ -129,10 +84,19 @@ void MainWidget::showPin(int pin)
void MainWidget::prepareApplication()
{
connect(&dialog, SIGNAL(finished(int)), this, SLOT(dialogResult(int)));
connectSignals();
createTrayIcon();
checkSettings();
refreshDatabase();
}
void MainWidget::connectSignals()
{
connect(&dialog, SIGNAL(finished(int)), this, SLOT(dialogResult(int)));
connect(&manager, SIGNAL(stopped()), qApp, SLOT(quit()));
connect(&manager, SIGNAL(receivedPin(int)), this, SLOT(showPin(int)));
connect(&manager, SIGNAL(deviceConnected(QString)), this, SLOT(receiveMessage(QString)));
connect(&manager, SIGNAL(deviceConnected(QString)), this, SLOT(setTrayTooltip(QString)));
connect(&manager, SIGNAL(deviceDisconnected()), this, SLOT(deviceDisconnect()));
}
void MainWidget::setTrayTooltip(QString message)

View File

@@ -21,18 +21,14 @@
#define MAINWIDGET_H
#include "configwidget.h"
#include "clientmanager.h"
#include "cmaclient.h"
#include <QAction>
#include <QWidget>
#include <QSystemTrayIcon>
extern "C" {
#include <vitamtp.h>
}
class QMenu;
class MainWidget : public QWidget
{
@@ -44,9 +40,9 @@ public:
void prepareApplication();
private:
void connectSignals();
void createTrayIcon();
void checkSettings();
void connectClientSignals(CmaClient *client);
bool first_run;
ConfigWidget dialog;
@@ -54,7 +50,7 @@ private:
QAction *quit;
QAction *reload;
QAction *options;
CmaClient clientLoop;
ClientManager manager;
const static QStringList path_list;
private slots:
@@ -63,8 +59,6 @@ private slots:
void receiveMessage(QString message);
void setTrayTooltip(QString message);
void showPin(int pin);
void refreshDatabase();
void startServer();
void stopServer();
};

View File

@@ -27,7 +27,8 @@ SOURCES += main.cpp \
cmaclient.cpp \
cmabroadcast.cpp \
avdecoder.cpp \
cmaevent.cpp
cmaevent.cpp \
clientmanager.cpp
HEADERS += \
capability.h \
@@ -43,7 +44,8 @@ HEADERS += \
cmaclient.h \
cmabroadcast.h \
avdecoder.h \
cmaevent.h
cmaevent.h \
clientmanager.h
CONFIG += link_pkgconfig
PKGCONFIG += libvitamtp libavformat libavcodec libavutil libswscale

View File

@@ -42,7 +42,7 @@ const char *SfoReader::value(const char *key, const char *defaultValue) {
for(uint i = 0; i < header->pair_count; i++) {
const char *curr_key = base_key + index[i].key_offset;
if(strcmp(key, curr_key) == 0) {
return key_offset + header->value_offset + index[i].data_offset;
return key_offset + header->value_offset + index[i].data_offset;
}
}
return defaultValue;

View File

@@ -37,7 +37,7 @@ private:
quint32 value_size;
quint32 value_size_with_padding;
quint32 data_offset;
}__attribute__((packed)) sfo_index;
} __attribute__((packed)) sfo_index;
typedef struct {
char id[4];
@@ -45,7 +45,7 @@ private:
quint32 key_offset;
quint32 value_offset;
quint32 pair_count;
}__attribute__((packed)) sfo_header;
} __attribute__((packed)) sfo_header;
QByteArray data;
const char *key_offset;

24
utils.h
View File

@@ -24,21 +24,25 @@
#include <QString>
#include <QThread>
extern "C" {
#include <vitamtp.h>
}
// Qt4 doesn't have public methods for Thread::*sleep
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
typedef QThread Sleeper;
typedef QThread Sleeper;
#else
class Sleeper : QThread
{
public:
static void sleep(unsigned long secs) { QThread::sleep(secs); }
static void msleep(unsigned long msecs) { QThread::msleep(msecs); }
static void usleep(unsigned long usecs) { QThread::usleep(usecs); }
};
class Sleeper : QThread
{
public:
static void sleep(unsigned long secs) {
QThread::sleep(secs);
}
static void msleep(unsigned long msecs) {
QThread::msleep(msecs);
}
static void usleep(unsigned long usecs) {
QThread::usleep(usecs);
}
};
#endif
bool removeRecursively(const QString &dirName);