From 92f45728144f4c9fffd5fc489f06e9ac59c46546 Mon Sep 17 00:00:00 2001 From: codestation Date: Sun, 25 Aug 2013 01:40:14 -0430 Subject: [PATCH] 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. --- README.md | 11 ++-- avdecoder.cpp | 26 ++++---- avdecoder.h | 11 ++-- baseworker.cpp | 30 ++++----- baseworker.h | 9 +-- capability.cpp | 2 +- capability.h | 18 ++++-- clientmanager.cpp | 75 +++++++++++++++++++++++ clientmanager.h | 37 +++++++++++ cmabroadcast.cpp | 30 ++++----- cmabroadcast.h | 2 +- cmaclient.cpp | 152 ++++++++++++++++++++++++---------------------- cmaclient.h | 26 ++++---- cmaevent.cpp | 148 +++++++++++++++++++++++++------------------- cmaevent.h | 20 ++++-- cmaobject.cpp | 2 +- cmaobject.h | 2 - cmarootobject.cpp | 112 +++++++++++++++++----------------- cmarootobject.h | 2 - configwidget.cpp | 46 +++++++------- database.cpp | 38 ++++++------ database.h | 4 +- main.cpp | 15 ++++- mainwidget.cpp | 68 +++++---------------- mainwidget.h | 12 +--- qcma.pro | 6 +- sforeader.cpp | 2 +- sforeader.h | 4 +- utils.h | 24 +++++--- 29 files changed, 523 insertions(+), 411 deletions(-) create mode 100644 clientmanager.cpp create mode 100644 clientmanager.h diff --git a/README.md b/README.md index 5947192..2dde4cc 100644 --- a/README.md +++ b/README.md @@ -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/) diff --git a/avdecoder.cpp b/avdecoder.cpp index db401f5..bee18bc 100644 --- a/avdecoder.cpp +++ b/avdecoder.cpp @@ -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); diff --git a/avdecoder.h b/avdecoder.h index be4c567..7459056 100644 --- a/avdecoder.h +++ b/avdecoder.h @@ -27,9 +27,10 @@ extern "C" { #include #include #include -#include } +#include + class AVDecoder { public: @@ -46,10 +47,10 @@ public: class AvInit { public: - AvInit() - { - av_register_all(); - } + AvInit() + { + av_register_all(); + } }; static AvInit init; diff --git a/baseworker.cpp b/baseworker.cpp index 48abfed..38cc8e7 100644 --- a/baseworker.cpp +++ b/baseworker.cpp @@ -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() +{ +} diff --git a/baseworker.h b/baseworker.h index 8c8f915..af94ca5 100644 --- a/baseworker.h +++ b/baseworker.h @@ -31,18 +31,19 @@ public: explicit BaseWorker(QObject *parent = 0); void start(const char *thread_name = NULL); + bool wait(); private: QThread *thread; - + signals: void finished(); +public slots: + virtual void onFinished(); + protected slots: virtual void process() = 0; - -private slots: - virtual void onFinished(); }; #endif // BASEWORKER_H diff --git a/capability.cpp b/capability.cpp index ac5182c..fdbd8ce 100644 --- a/capability.cpp +++ b/capability.cpp @@ -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(); diff --git a/capability.h b/capability.h index ada79a1..066ec47 100644 --- a/capability.h +++ b/capability.h @@ -20,9 +20,7 @@ #ifndef CAPABILITY_H #define CAPABILITY_H -extern "C" { #include -} 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(); diff --git a/clientmanager.cpp b/clientmanager.cpp new file mode 100644 index 0000000..d2a99b4 --- /dev/null +++ b/clientmanager.cpp @@ -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(); +} diff --git a/clientmanager.h b/clientmanager.h new file mode 100644 index 0000000..5ca2069 --- /dev/null +++ b/clientmanager.h @@ -0,0 +1,37 @@ +#ifndef CLIENTMANAGER_H +#define CLIENTMANAGER_H + +#include "database.h" + +#include +#include + +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 diff --git a/cmabroadcast.cpp b/cmabroadcast.cpp index a125489..21993f9 100644 --- a/cmabroadcast.cpp +++ b/cmabroadcast.cpp @@ -28,13 +28,13 @@ #include 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'); } diff --git a/cmabroadcast.h b/cmabroadcast.h index e997650..fae9b34 100644 --- a/cmabroadcast.h +++ b/cmabroadcast.h @@ -31,7 +31,7 @@ class CmaBroadcast : public QObject Q_OBJECT public: explicit CmaBroadcast(QObject *parent = 0); - + private: void replyBroadcast(const QByteArray &datagram); diff --git a/cmaclient.cpp b/cmaclient.cpp index 80f0f33..df6356a 100644 --- a/cmaclient.cpp +++ b/cmaclient.cpp @@ -23,7 +23,7 @@ #include "cmaevent.h" #include "utils.h" -#include "QApplication" +#include #include #include #include @@ -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; +} + diff --git a/cmaclient.h b/cmaclient.h index dbe9827..2de9aa4 100644 --- a/cmaclient.h +++ b/cmaclient.h @@ -24,47 +24,47 @@ #include "cmabroadcast.h" #include "cmaobject.h" #include "database.h" +#include "cmaevent.h" #include +#include #include -#include -extern "C" { #include -} 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 diff --git a/cmaevent.cpp b/cmaevent.cpp index 473ba0a..b80c8fd 100644 --- a/cmaevent.cpp +++ b/cmaevent.cpp @@ -7,16 +7,59 @@ #include #include -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); diff --git a/cmaevent.h b/cmaevent.h index 993226f..fc3cff2 100644 --- a/cmaevent.h +++ b/cmaevent.h @@ -6,6 +6,7 @@ #include "baseworker.h" #include +#include #include @@ -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 diff --git a/cmaobject.cpp b/cmaobject.cpp index 159846c..07b505f 100644 --- a/cmaobject.cpp +++ b/cmaobject.cpp @@ -129,7 +129,7 @@ void CMAObject::initObject(const QFileInfo &file) // create additional metadata if(MASK_SET(metadata.dataType, SaveData | Folder)) { metadata.data.saveData.dirName = strdup(metadata.name); - metadata.data.saveData.statusType = 1; + metadata.data.saveData.statusType = 1; loadSfoMetadata(file.absoluteFilePath()); } else if(MASK_SET(metadata.dataType, Music | File)) { metadata.data.music.fileName = strdup(metadata.name); diff --git a/cmaobject.h b/cmaobject.h index ccff70e..47011b8 100644 --- a/cmaobject.h +++ b/cmaobject.h @@ -23,9 +23,7 @@ #include #include -extern "C" { #include -} #define OHFI_OFFSET 1000 diff --git a/cmarootobject.cpp b/cmarootobject.cpp index 8d88e57..872d1b5 100644 --- a/cmarootobject.cpp +++ b/cmarootobject.cpp @@ -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; } } diff --git a/cmarootobject.h b/cmarootobject.h index 5b1d1a2..51ae8df 100644 --- a/cmarootobject.h +++ b/cmarootobject.h @@ -24,9 +24,7 @@ #include -extern "C" { #include -} class CMARootObject : public CMAObject { diff --git a/configwidget.cpp b/configwidget.cpp index 2f225bd..3827d4a 100644 --- a/configwidget.cpp +++ b/configwidget.cpp @@ -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; @@ -144,7 +144,7 @@ void ConfigWidget::savePath(QSettings &settings, const QLineEdit *edit, const QS void ConfigWidget::accept() { - QSettings settings; + QSettings settings; savePath(settings, ui->photoPath, "photoPath"); savePath(settings, ui->musicPath, "musicPath"); savePath(settings, ui->videoPath, "videoPath"); diff --git a/database.cpp b/database.cpp index e492898..0e42bed 100644 --- a/database.cpp +++ b/database.cpp @@ -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; } diff --git a/database.h b/database.h index cb47ff8..e74348d 100644 --- a/database.h +++ b/database.h @@ -27,9 +27,7 @@ #include #include -extern "C" { #include -} class Database : public QObject { @@ -77,7 +75,7 @@ private: bool checkFileType(const QString path, int ohfi_root); void dumpMetadataList(const metadata_t *p_head); - map_list object_list; + map_list object_list; signals: void finished(); diff --git a/main.cpp b/main.cpp index 4a4f1ed..1f8825e 100644 --- a/main.cpp +++ b/main.cpp @@ -17,6 +17,10 @@ * along with this program. If not, see . */ +#ifndef Q_OS_WIN32 +#include +#endif + #include #include @@ -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) diff --git a/mainwidget.cpp b/mainwidget.cpp index d465e57..57b1e47 100644 --- a/mainwidget.cpp +++ b/mainwidget.cpp @@ -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) diff --git a/mainwidget.h b/mainwidget.h index e756a97..f52cb26 100644 --- a/mainwidget.h +++ b/mainwidget.h @@ -21,18 +21,14 @@ #define MAINWIDGET_H #include "configwidget.h" +#include "clientmanager.h" #include "cmaclient.h" #include #include #include -extern "C" { #include -} - - -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(); }; diff --git a/qcma.pro b/qcma.pro index d345017..99b2e8b 100644 --- a/qcma.pro +++ b/qcma.pro @@ -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 diff --git a/sforeader.cpp b/sforeader.cpp index 170aa35..76737b3 100644 --- a/sforeader.cpp +++ b/sforeader.cpp @@ -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; diff --git a/sforeader.h b/sforeader.h index 639f5a3..e387aa2 100644 --- a/sforeader.h +++ b/sforeader.h @@ -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; diff --git a/utils.h b/utils.h index 3484eec..4026ac0 100644 --- a/utils.h +++ b/utils.h @@ -24,21 +24,25 @@ #include #include -extern "C" { #include -} // 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);