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);