From d93de053e96469dc681abf01da3193414ee0030b Mon Sep 17 00:00:00 2001 From: codestation Date: Mon, 19 Aug 2013 09:46:03 -0430 Subject: [PATCH] Reimplemented broadcaster so it can send 503 when a connection is in place. Removed qcma/cmaserver class and reimplemented them in cmaclient. Make sure that the scanned files are sorted by filename. Implement filters so the database doesn't pick up unsupported formats. Implement album cover display for album listing in the vita. Fixed bug with streaming of pictures in wireless mode. Some code refactoring. --- capability.cpp | 5 +- cmabroadcast.cpp | 101 ++++++++++++++++++ cmabroadcast.h | 56 ++++++++++ cmaclient.cpp | 247 ++++++++++++++++++++++++++++----------------- cmaclient.h | 36 ++++++- cmarootobject.cpp | 10 +- cmaserver.cpp | 72 ------------- cmaserver.h | 45 --------- database.cpp | 91 ++++++++++++++++- database.h | 9 +- main.cpp | 4 +- mainwidget.cpp | 44 ++++---- mainwidget.h | 8 +- qcma.pro | 18 +++- utils.cpp | 89 +++++++++++++++- utils.h | 6 ++ wirelessworker.cpp | 4 +- wirelessworker.h | 5 +- 18 files changed, 581 insertions(+), 269 deletions(-) create mode 100644 cmabroadcast.cpp create mode 100644 cmabroadcast.h delete mode 100644 cmaserver.cpp delete mode 100644 cmaserver.h diff --git a/capability.cpp b/capability.cpp index 3aebed3..ac5182c 100644 --- a/capability.cpp +++ b/capability.cpp @@ -52,7 +52,10 @@ bool DeviceCapability::exchangeInfo(vita_device_t *device) return false; } - VitaMTP_Data_Free_Capability(vita_capabilities); // TODO: Use this data + // TODO: vitamtp needs to send the full metadata info to know the expected format + // of thumbnails, for example. Until then lets discard the received info. + + VitaMTP_Data_Free_Capability(vita_capabilities); // Send the host's capabilities capability_info_t *pc_capabilities = generate_pc_capability_info(); diff --git a/cmabroadcast.cpp b/cmabroadcast.cpp new file mode 100644 index 0000000..91456c1 --- /dev/null +++ b/cmabroadcast.cpp @@ -0,0 +1,101 @@ +/* + * QCMA: Cross-platform content manager assistant for the PS Vita + * + * Copyright (C) 2013 Codestation + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "cmabroadcast.h" + +#include +#include +#include +#include +#include + +#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"; + +const char *CmaBroadcast::broadcast_query = "SRCH * HTTP/1.1\r\n"; + +const char *CmaBroadcast::broadcast_ok = "HTTP/1.1 200 OK"; +const char *CmaBroadcast::broadcast_unavailable = "HTTP/1.1 503 NG"; + +CmaBroadcast::CmaBroadcast(QObject *parent) : + QObject(parent) +{ + QSettings settings; + // generate a GUID if doesn't exist yet in settings + uuid = settings.value("guid").toString(); + if(uuid.isEmpty()) { + uuid = QUuid::createUuid().toString(); + settings.setValue("guid", uuid); + } + + hostname = QHostInfo::localHostName(); + setAvailable(); + + socket = new QUdpSocket(this); + socket->bind(QHostAddress::Any, QCMA_REQUEST_PORT); + connect(socket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams())); +} + +void CmaBroadcast::readPendingDatagrams() +{ + if(socket->hasPendingDatagrams()) { + QByteArray datagram; + datagram.resize(socket->pendingDatagramSize()); + + QHostAddress sender; + quint16 senderPort; + + socket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort); + + if(datagram.contains(broadcast_query)) { + QMutexLocker locker(&mutex); + socket->writeDatagram(reply.toUtf8(), sender, senderPort); + } else { + qWarning("Unknown request: %.*s\n", datagram.length(), datagram.constData()); + } + } +} + +void CmaBroadcast::setAvailable() +{ + QMutexLocker locker(&mutex); + reply = broadcast_reply + .arg(broadcast_ok, uuid, "win", hostname) + .arg(VITAMTP_PROTOCOL_MAX_VERSION, 8, 10, QChar('0')) + .arg(QCMA_REQUEST_PORT) + .arg(VITAMTP_WIRELESS_MAX_VERSION, 8, 10, QChar('0')); +} + +void CmaBroadcast::setUnavailable() +{ + QMutexLocker locker(&mutex); + reply = broadcast_reply + .arg(broadcast_unavailable, uuid, "win", hostname) + .arg(VITAMTP_PROTOCOL_MAX_VERSION, 8, 10, QChar('0')) + .arg(QCMA_REQUEST_PORT) + .arg(VITAMTP_WIRELESS_MAX_VERSION, 8, 10, QChar('0')); +} diff --git a/cmabroadcast.h b/cmabroadcast.h new file mode 100644 index 0000000..a30c98f --- /dev/null +++ b/cmabroadcast.h @@ -0,0 +1,56 @@ +/* + * QCMA: Cross-platform content manager assistant for the PS Vita + * + * Copyright (C) 2013 Codestation + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef CMABROADCAST_H +#define CMABROADCAST_H + +#include +#include +#include + +#define QCMA_REQUEST_PORT 9309 + +class CmaBroadcast : public QObject +{ + Q_OBJECT +public: + explicit CmaBroadcast(QObject *parent = 0); + +private: + void replyBroadcast(const QByteArray &datagram); + + QMutex mutex; + QString uuid; + QString reply; + QString hostname; + QUdpSocket *socket; + static const QString broadcast_reply; + static const char *broadcast_query; + static const char *broadcast_ok; + static const char *broadcast_unavailable; + +public slots: + void setAvailable(); + void setUnavailable(); + +private slots: + void readPendingDatagrams(); +}; + +#endif // CMABROADCAST_H diff --git a/cmaclient.cpp b/cmaclient.cpp index 269d42e..10c6cd0 100644 --- a/cmaclient.cpp +++ b/cmaclient.cpp @@ -1,7 +1,28 @@ +/* + * QCMA: Cross-platform content manager assistant for the PS Vita + * + * Copyright (C) 2013 Codestation + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include "cmaclient.h" #include "capability.h" #include "utils.h" +#include "wirelessworker.h" +#include "QApplication" #include #include #include @@ -10,55 +31,76 @@ #include #include -const metadata_t CmaClient::g_thumbmeta = {0, 0, 0, NULL, NULL, 0, 0, 0, Thumbnail, {{18, 144, 80, 0, 1, 1.0f, 2}}, NULL}; +#include +#include + +metadata_t CmaClient::g_thumbmeta = {0, 0, 0, NULL, NULL, 0, 0, 0, Thumbnail, {{18, 144, 80, 0, 1, 1.0f, 2}}, NULL}; CmaClient::CmaClient(QObject *parent) : BaseWorker(parent) { } -CmaClient::CmaClient(Database *database, vita_device_t *device, QObject *parent) : - BaseWorker(parent), db(database), device(device) +vita_device_t *CmaClient::getDeviceConnection() { -} + int num_tries = 0; + vita_device_t *vita; + typedef BroadcastSignal BS; -CmaClient::~CmaClient() -{ - if(device) { - close(); + while(active) { + vita = VitaMTP_Get_First_USB_Vita(); + if(vita || !active) { + break; + } + qDebug("No Vita detected via USB, attempt %i", ++num_tries); + vita = VitaMTP_Get_First_Wireless_Vita(&BS::info, 0, 2, BS::deviceRegistered, BS::generatePin); + if(vita || !active) { + break; + } + qDebug("No Vita detected via wireless, attempt %i", ++num_tries); } -} -void CmaClient::close() -{ - VitaMTP_SendHostStatus(device, VITA_HOST_STATUS_EndConnection); - VitaMTP_Release_Device(device); - device = NULL; + return vita; } void CmaClient::process() { - qDebug("Vita connected: id %s", VitaMTP_Get_Identification(device)); + qDebug() << "Starting CmaClient:" << QThread::currentThreadId(); - DeviceCapability *vita_info = new DeviceCapability(); + connect(&broadcast, SIGNAL(receivedPin(int)), this, SIGNAL(receivedPin(int))); - if(!vita_info->exchangeInfo(device)) { - qCritical("Error while exchanging info with the vita"); - close(); + active = true; + + while(active) { + + if((device = getDeviceConnection()) == NULL) { + break; + } + broadcast.setUnavailable(); + qDebug("Vita connected: id %s", VitaMTP_Get_Identification(device)); + DeviceCapability *vita_info = new DeviceCapability(); + + if(!vita_info->exchangeInfo(device)) { + qCritical("Error while exchanging info with the vita"); + close(); + broadcast.setAvailable(); + continue; + } + + // Conection successful, inform the user + emit deviceConnected(QString(tr("Connected to ")) + vita_info->getOnlineId()); + connected = true; + enterEventLoop(); + broadcast.setAvailable(); } - - // Conection successful, inform the user - emit deviceConnected(QString(tr("Connected to ")) + vita_info->getOnlineId()); - connected = true; - enterEventLoop(); + emit finished(); } - void CmaClient::enterEventLoop() { vita_event_t event; - qDebug() << "From listener:"<< QThread::currentThreadId(); + qDebug("Starting event loop"); while(connected) { if(VitaMTP_Read_Event(device, &event) < 0) { @@ -134,9 +176,10 @@ void CmaClient::enterEventLoop() default: vitaEventUnimplementated(&event, event.Param1); } + qDebug("Ended event, code: 0x%x, id: %d", event.Code, event.Param1); } - qDebug() << "Finished event thread for:" << QThread::currentThreadId(); - emit finished(); + qDebug("Finished event thread"); + emit deviceDisconnected(); } quint16 CmaClient::processAllObjects(CMAObject *parent, quint32 handle) @@ -154,12 +197,12 @@ quint16 CmaClient::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); @@ -188,7 +231,7 @@ quint16 CmaClient::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); @@ -199,7 +242,7 @@ quint16 CmaClient::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; } @@ -221,9 +264,9 @@ void CmaClient::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); @@ -244,14 +287,14 @@ void CmaClient::vitaEventSendCopyConfirmationInfo(vita_event_t *event, int event 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; @@ -279,9 +322,9 @@ void CmaClient::vitaEventSendObjectMetadataItems(vita_event_t *event, int eventI 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); @@ -324,10 +367,10 @@ void CmaClient::vitaEventSendNumOfObject(vita_event_t *event, int eventId) { qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId); - 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); @@ -347,10 +390,10 @@ void CmaClient::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 @@ -366,10 +409,12 @@ void CmaClient::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; @@ -379,6 +424,7 @@ void CmaClient::vitaEventSendObject(vita_event_t *event, int eventId) CMAObject *object = *iters.it; CMAObject *start = object; uint parentHandle = event->Param3; + bool send_folder = object->metadata.dataType & Folder; uint handle; do { @@ -415,12 +461,22 @@ void CmaClient::vitaEventSendObject(vita_event_t *event, int eventId) } object->metadata.handle = handle; - file.unmap(data); - object = *iters.it++; + + if(object->metadata.dataType & File) { + file.unmap(data); + } + + // break early if only a file needs to be sent + if(!send_folder) { + break; + } + + object = *++iters.it; } while(iters.it != iters.end && object->metadata.ohfiParent >= OHFI_OFFSET); // get everything under this "folder" VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, handle); + VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Data); // TODO: Send thumbnail } @@ -488,9 +544,9 @@ void CmaClient::vitaEventSendObjectStatus(vita_event_t *event, int eventId) return; } - 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); @@ -514,10 +570,10 @@ void CmaClient::vitaEventSendObjectThumb(vita_event_t *event, int eventId) { qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId); - 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); @@ -525,33 +581,12 @@ void CmaClient::vitaEventSendObjectThumb(vita_event_t *event, int eventId) return; } - QByteArray data; + QByteArray data = getThumbnail(object->path, object->metadata.dataType, &g_thumbmeta); - if(MASK_SET(object->metadata.dataType, SaveData)) { - QString thumbpath = QDir(object->path).absoluteFilePath("ICON0.PNG"); - qDebug("Sending savedata thumbnail from %s", thumbpath.toStdString().c_str()); - - QFile file(thumbpath); - if(!file.open(QIODevice::ReadOnly)) { - qWarning("Cannot find thumbnail %s", thumbpath.toStdString().c_str()); - VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Data); - return; - } - data = file.readAll(); - - } else { - QImage img; - if(!MASK_SET(object->metadata.dataType, Photo) || !img.load(object->path)) { - qWarning("Thumbnail sending for the file %s is not supported", object->metadata.path); - VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Data); - return; - } - qDebug("Creating thumbnail of %s", object->metadata.name); - - QBuffer buffer(&data); - buffer.open(QIODevice::WriteOnly); - QImage result = img.scaled(256, 256, Qt::KeepAspectRatio, Qt::FastTransformation); - result.save(&buffer, "JPEG"); + if(data.size() == 0) { + qWarning("Cannot find/read thumbnail for %s", object->path.toStdString().c_str()); + VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Data); + return; } // workaround for the vitamtp locale bug @@ -573,10 +608,10 @@ void CmaClient::vitaEventDeleteObject(vita_event_t *event, int eventId) { qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId); - 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); @@ -586,7 +621,7 @@ void CmaClient::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); } @@ -603,10 +638,12 @@ void CmaClient::vitaEventGetSettingInfo(vita_event_t *event, int eventId) qDebug("Current account id: %s", settingsinfo->current_account.accountId); - db->setUUID(settingsinfo->current_account.accountId); - // set the database to be updated ASAP - emit refreshDatabase(); + if(QSettings().value("lastAccountId").toString() != settingsinfo->current_account.accountId) { + db.setUUID(settingsinfo->current_account.accountId); + // set the database to be updated ASAP + emit refreshDatabase(); + } // free all the information VitaMTP_Data_Free_Settings(settingsinfo); @@ -660,9 +697,9 @@ void CmaClient::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); @@ -700,9 +737,9 @@ void CmaClient::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) { @@ -721,7 +758,7 @@ void CmaClient::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); } @@ -737,7 +774,7 @@ void CmaClient::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); } @@ -752,7 +789,7 @@ void CmaClient::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) { @@ -796,8 +833,8 @@ void CmaClient::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); @@ -828,10 +865,10 @@ void CmaClient::vitaEventSendStorageSize(vita_event_t *event, int eventId) { qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId); - 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); @@ -882,9 +919,9 @@ void CmaClient::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); @@ -894,3 +931,23 @@ void CmaClient::vitaEventCheckExistance(vita_event_t *event, int eventId) VitaMTP_ReportResult(device, eventId, PTP_RC_OK); } + +void CmaClient::close() +{ + VitaMTP_SendHostStatus(device, VITA_HOST_STATUS_EndConnection); + VitaMTP_Release_Device(device); +} + +void CmaClient::stop() +{ + active = false; + connected = false; + waitCondition.wakeAll(); +} + +CmaClient::~CmaClient() +{ + if(device) { + close(); + } +} diff --git a/cmaclient.h b/cmaclient.h index af40560..5b6a5c2 100644 --- a/cmaclient.h +++ b/cmaclient.h @@ -1,12 +1,33 @@ +/* + * QCMA: Cross-platform content manager assistant for the PS Vita + * + * Copyright (C) 2013 Codestation + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #ifndef CMACLIENT_H #define CMACLIENT_H #include "baseworker.h" +#include "cmabroadcast.h" #include "cmaobject.h" #include "database.h" #include #include +#include extern "C" { #include @@ -17,11 +38,13 @@ class CmaClient : public BaseWorker Q_OBJECT public: explicit CmaClient(QObject *parent = 0); - explicit CmaClient(Database *database, vita_device_t *device, QObject *parent = 0); ~CmaClient(); + Database db; + private: void enterEventLoop(); + vita_device_t *getDeviceConnection(); uint16_t processAllObjects(CMAObject *parent, uint32_t handle); void vitaEventSendObject(vita_event_t *event, int eventId); @@ -46,18 +69,23 @@ private: void vitaEventSendNPAccountInfo(vita_event_t *event, int eventId); void vitaEventRequestTerminate(vita_event_t *event, int eventId); - Database *db; + QWaitCondition waitCondition; + CmaBroadcast broadcast; vita_device_t *device; + volatile bool active; volatile bool connected; - static const metadata_t g_thumbmeta; + static metadata_t g_thumbmeta; signals: + void receivedPin(int); + void deviceDetected(); void deviceConnected(QString); + void deviceDisconnected(); void refreshDatabase(); - void terminate(); public slots: void close(); + void stop(); private slots: void process(); diff --git a/cmarootobject.cpp b/cmarootobject.cpp index 999f8b7..afbac7b 100644 --- a/cmarootobject.cpp +++ b/cmarootobject.cpp @@ -38,9 +38,12 @@ void CMARootObject::initObject(const QString &path) metadata.dataType = Music; this->path = path; num_filters = 1; - filters = new metadata_t[1]; - //createFilter(&filters[0], "Folders", VITA_DIR_TYPE_MASK_MUSIC | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_PLAYLISTS); - createFilter(&filters[0], "All", VITA_DIR_TYPE_MASK_MUSIC | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_SONGS); + 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: @@ -119,6 +122,7 @@ void CMARootObject::createFilter(metadata_t *filter, const char *name, int type) filter->size = 0; filter->dataType = static_cast(Folder | Special); filter->next_metadata = NULL; + qDebug("Added filter %s to database with OHFI %d (%s)", name, filter->ohfi, metadata.name); } int CMARootObject::getFilters(metadata_t **p_head) diff --git a/cmaserver.cpp b/cmaserver.cpp deleted file mode 100644 index 2969c53..0000000 --- a/cmaserver.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "cmaserver.h" -#include "wirelessworker.h" - -#include -#include -#include -#include - -CmaServer::CmaServer(QObject *parent) : - QObject(parent), num_retries(0) -{ - strcpy(hostname, QHostInfo::localHostName().toStdString().c_str()); - BroadcastSignal::info.name = hostname; -} - -void CmaServer::listen() -{ - QThread *thread = new QThread(); - if(QSettings().value("wireless", false).toBool()) { - connect(&timer, SIGNAL(timeout()), this, SLOT(connectWireless())); - broadcast.start(); - timer.setSingleShot(true); - } else { - timer.setSingleShot(false); - connect(&timer, SIGNAL(timeout()), this, SLOT(connectUsb())); - } - moveToThread(thread); - connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - timer.start(2000); - thread->start(); -} - -void CmaServer::connectUsb() -{ - qDebug() << "From connectUsb: "<< QThread::currentThreadId(); - - vita_device_t *vita = VitaMTP_Get_First_USB_Vita(); - if(vita) { - qDebug("Detected PS Vita via USB"); - timer.stop(); - emit newConnection(vita); - } else { - qDebug("No PS Vita found. Attempt %d", ++num_retries); - } -} - -void CmaServer::connectWireless() -{ - typedef BroadcastSignal BS; - - qDebug() << "From connectWireless: "<< QThread::currentThreadId(); - - vita_device_t *vita = VitaMTP_Get_First_Wireless_Vita(&BS::info, 0, 0, BS::deviceRegistered, BS::generatePin); - if(vita) { - qDebug("Detected PS Vita in wireless mode"); - emit newConnection(vita); - } else { - qDebug("PS Vita couldn't be detected. Attempt %d", ++num_retries); - } -} - -void CmaServer::continueProcess() -{ - qDebug("Restarting CmaServer thread"); - num_retries = 0; - timer.start(); -} - -void CmaServer::stopProcess() -{ - timer.stop(); -} diff --git a/cmaserver.h b/cmaserver.h deleted file mode 100644 index 95855eb..0000000 --- a/cmaserver.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef CMASERVER_H -#define CMASERVER_H - -#include "wirelessworker.h" - -extern "C" { -#include -} - -#include - -#include -#include -#include -#include - -class CmaServer : public QObject -{ - Q_OBJECT -public: - explicit CmaServer(QObject *parent = 0); - void listen(); - void close(); - - int num_retries; - QTimer timer; - QThread *thread; - char hostname[256]; - BroadcastSignal broadcast; - -signals: - void newConnection(vita_device_t *); - void createdPin(int); - void finished(); - -public slots: - void continueProcess(); - void stopProcess(); - -private slots: - void connectWireless(); - void connectUsb(); -}; - -#endif // CMASERVER_H diff --git a/database.cpp b/database.cpp index 598c75d..d38ef8f 100644 --- a/database.cpp +++ b/database.cpp @@ -27,9 +27,14 @@ #define OHFI_OFFSET 1000 +const QStringList Database::image_types = QStringList() << "jpg" << "jpeg" << "png" << "tif" << "tiff" << "bmp" << "gif" << "mpo"; +const QStringList Database::audio_types = QStringList() << "mp3" << "mp4" << "wav"; +const QStringList Database::video_types = QStringList() << "mp4"; + Database::Database(QObject *parent) : QObject(parent), mutex(QMutex::Recursive) { + CMARootObject::uuid = QSettings().value("lastAccountId", "ffffffffffffffff").toString(); } Database::~Database() @@ -40,6 +45,7 @@ Database::~Database() void Database::setUUID(const QString uuid) { CMARootObject::uuid = uuid; + QSettings().setValue("lastAccountId", uuid); } int Database::create() @@ -75,12 +81,13 @@ int Database::create() case VITA_OHFI_PSPSAVE: case VITA_OHFI_PSXAPP: case VITA_OHFI_PSMAPP: + obj->initObject(settings.value("appsPath").toString()); } root_list list; list << obj; - total_objects += scanRootDirectory(list); + total_objects += recursiveScanRootDirectory(list, obj, ohfi_array[i]); object_list[ohfi_array[i]] = list; } return total_objects; @@ -95,7 +102,7 @@ CMAObject *Database::getParent(CMAObject *last_dir, const QString ¤t_path) return last_dir; } -int Database::scanRootDirectory(root_list &list) +int Database::scanRootDirectory(root_list &list, int ohfi_type) { int total_objects = 0; CMAObject *last_dir = list.first(); @@ -105,8 +112,16 @@ int Database::scanRootDirectory(root_list &list) while(it.hasNext()) { it.next(); - CMAObject *obj = new CMAObject(getParent(last_dir, it.fileInfo().path())); - obj->initObject(it.fileInfo()); + QFileInfo info = it.fileInfo(); + + if(info.isFile() && !checkFileType(info.absoluteFilePath(), ohfi_type)) { + //qDebug("Excluding %s from database", info.absoluteFilePath().toStdString().c_str()); + continue; + } + + CMAObject *obj = new CMAObject(getParent(last_dir, info.path())); + obj->initObject(info); + qDebug("Added %s to database with OHFI %d", obj->metadata.name, obj->metadata.ohfi); list << obj; if(obj->metadata.dataType & Folder) { @@ -118,6 +133,33 @@ int Database::scanRootDirectory(root_list &list) return total_objects; } +int Database::recursiveScanRootDirectory(root_list &list, CMAObject *parent, int ohfi_type) +{ + int total_objects = 0; + + QDir dir(parent->path); + dir.setSorting(QDir::Name | QDir::DirsFirst); + QFileInfoList qsl = dir.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot); + + foreach(const QFileInfo &info, qsl) { + if(info.isFile() && !checkFileType(info.absoluteFilePath(), ohfi_type)) { + //qDebug("Excluding %s from database", info.absoluteFilePath().toStdString().c_str());> + } else { + CMAObject *obj = new CMAObject(parent); + obj->initObject(info); + qDebug("Added %s to database with OHFI %d", obj->metadata.name, obj->metadata.ohfi); + list << obj; + if(info.isDir()) { + total_objects += recursiveScanRootDirectory(list, obj, ohfi_type); + } else { + total_objects++; + } + } + } + + return total_objects; +} + void Database::destroy() { QMutexLocker locker(&mutex); @@ -282,6 +324,14 @@ int Database::acceptFilteredObject(const CMAObject *parent, const CMAObject *cur return result; } +void Database::dumpMetadataList(const metadata_t *p_head) +{ + while(p_head) { + qDebug("Metadata: %s with OHFI %d", p_head->name, p_head->ohfi); + p_head = p_head->next_metadata; + } +} + int Database::filterObjects(int ohfiParent, metadata_t **p_head) { QMutexLocker locker(&mutex); @@ -330,5 +380,38 @@ int Database::filterObjects(int ohfiParent, metadata_t **p_head) *p_head = temp.next_metadata; } + if(p_head) { + dumpMetadataList(*p_head); + } return numObjects; } + +bool Database::checkFileType(const QString path, int ohfi_root) +{ + switch(ohfi_root) { + case VITA_OHFI_MUSIC: + foreach(const QString &ext, audio_types) { + if(path.endsWith(ext, Qt::CaseInsensitive)) { + return true; + } + } + break; + case VITA_OHFI_PHOTO: + foreach(const QString &ext, image_types) { + if(path.endsWith(ext, Qt::CaseInsensitive)) { + return true; + } + } + break; + case VITA_OHFI_VIDEO: + foreach(const QString &ext, video_types) { + if(path.endsWith(ext, Qt::CaseInsensitive)) { + return true; + } + } + break; + default: + return true; + } + return false; +} diff --git a/database.h b/database.h index 40c6744..cb47ff8 100644 --- a/database.h +++ b/database.h @@ -62,13 +62,20 @@ private: typedef QList root_list; typedef QMap map_list; - int scanRootDirectory(root_list &list); + static const QStringList audio_types; + static const QStringList image_types; + static const QStringList video_types; + + int scanRootDirectory(root_list &list,int ohfi_type); + int recursiveScanRootDirectory(root_list &list, CMAObject *parent, int ohfi_type); bool hasFilter(const CMARootObject *object,int ohfi); bool removeInternal(root_list &list, const CMAObject *obj); bool findInternal(const root_list &list, int ohfi, find_data &data); CMAObject *getParent(CMAObject *last_dir, const QString ¤t_path); CMAObject *pathToObjectInternal(const root_list &list, const char *path); static bool lessThanComparator(const CMAObject *a, const CMAObject *b); + bool checkFileType(const QString path, int ohfi_root); + void dumpMetadataList(const metadata_t *p_head); map_list object_list; diff --git a/main.cpp b/main.cpp index 3e48253..4a4f1ed 100644 --- a/main.cpp +++ b/main.cpp @@ -43,8 +43,6 @@ int main(int argc, char *argv[]) SingleApplication app(argc, argv); - - if(!app.arguments().contains("--with-debug")) { VitaMTP_Set_Logging(VitaMTP_NONE); #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) @@ -56,7 +54,7 @@ int main(int argc, char *argv[]) VitaMTP_Set_Logging(VitaMTP_VERBOSE); } - qDebug()<<"From main thread: "< #include #include +#include const QStringList MainWidget::path_list = QStringList() << "photoPath" << "musicPath" << "videoPath" << "appsPath" << "urlPath"; @@ -64,34 +65,22 @@ void MainWidget::dialogResult(int result) void MainWidget::startServer() { - connect(&server, SIGNAL(newConnection(vita_device_t *)), this, SLOT(startClient(vita_device_t*))); - connect(&server, SIGNAL(createdPin(int)), this, SLOT(showPin(int))); - //connect(&server, SIGNAL(finished()), qApp, SLOT(quit())); + qDebug("Starting cma event loop"); + clientLoop.start(); +} - qDebug("Starting cma server"); - server.listen(); +void MainWidget::stopServer() +{ + clientLoop.stop(); } void MainWidget::refreshDatabase() { - db.mutex.lock(); - db.destroy(); - int count = db.create(); - qDebug("Indexed %i elements in the database", count); - db.mutex.unlock(); -} - -void MainWidget::startClient(vita_device_t *device) -{ - server.stopProcess(); - qDebug() << "From startClient: "<< QThread::currentThreadId(); - qDebug("Starting new client connection"); - CmaClient *client = new CmaClient(&db, device); - connect(client, SIGNAL(deviceConnected(QString)), this, SLOT(receiveMessage(QString))); - connect(client, SIGNAL(deviceConnected(QString)), this, SLOT(setTrayTooltip(QString))); - connect(client, SIGNAL(refreshDatabase()), this, SLOT(refreshDatabase())); - connect(client, SIGNAL(finished()), &server, SLOT(continueProcess())); - client->start(); + clientLoop.db.mutex.lock(); + clientLoop.db.destroy(); + int count = clientLoop.db.create(); + qDebug("Added %i entries to the database", count); + clientLoop.db.mutex.unlock(); } void MainWidget::deviceDisconnect() @@ -103,6 +92,12 @@ void MainWidget::deviceDisconnect() void MainWidget::connectSignals() { connect(&dialog, SIGNAL(finished(int)), this, SLOT(dialogResult(int))); + connect(&clientLoop, SIGNAL(receivedPin(int)), this, SLOT(showPin(int))); + connect(&clientLoop, SIGNAL(deviceConnected(QString)), this, SLOT(receiveMessage(QString))); + connect(&clientLoop, SIGNAL(deviceConnected(QString)), this, SLOT(setTrayTooltip(QString))); + connect(&clientLoop, SIGNAL(deviceDisconnected()), this, SLOT(deviceDisconnect())); + connect(&clientLoop, SIGNAL(refreshDatabase()), this, SLOT(refreshDatabase())); + connect(&clientLoop, SIGNAL(finished()), qApp, SLOT(quit())); } void MainWidget::showPin(int pin) @@ -115,6 +110,7 @@ void MainWidget::prepareApplication() connectSignals(); createTrayIcon(); checkSettings(); + refreshDatabase(); } void MainWidget::setTrayTooltip(QString message) @@ -153,7 +149,7 @@ void MainWidget::createTrayIcon() connect(options, SIGNAL(triggered()), &dialog, SLOT(open())); //connect(reload, SIGNAL(triggered()), &CmaWorker, SLOT(allowRefresh()), Qt::DirectConnection); - connect(quit, SIGNAL(triggered()), qApp, SLOT(quit())); + connect(quit, SIGNAL(triggered()), this, SLOT(stopServer())); connect(wireless, SIGNAL(triggered()), this, SLOT(toggleWireless())); QMenu *trayIconMenu = new QMenu(this); diff --git a/mainwidget.h b/mainwidget.h index 3184613..30ad0af 100644 --- a/mainwidget.h +++ b/mainwidget.h @@ -21,8 +21,7 @@ #define MAINWIDGET_H #include "configwidget.h" -#include "cmaserver.h" -#include "database.h" +#include "cmaclient.h" #include #include @@ -56,8 +55,7 @@ private: QAction *reload; QAction *options; QAction *wireless; - Database db; - CmaServer server; + CmaClient clientLoop; const static QStringList path_list; private slots: @@ -67,9 +65,9 @@ private slots: void setTrayTooltip(QString message); void toggleWireless(); void showPin(int pin); - void startClient(vita_device_t *device); void refreshDatabase(); void startServer(); + void stopServer(); }; #endif // MAINWIDGET_H diff --git a/qcma.pro b/qcma.pro index 09522fb..74f3587 100644 --- a/qcma.pro +++ b/qcma.pro @@ -25,8 +25,8 @@ SOURCES += main.cpp \ singleapplication.cpp \ baseworker.cpp \ sforeader.cpp \ - cmaserver.cpp \ - cmaclient.cpp + cmaclient.cpp \ + cmabroadcast.cpp HEADERS += \ wirelessworker.h \ @@ -40,11 +40,11 @@ HEADERS += \ singleapplication.h \ baseworker.h \ sforeader.h \ - cmaserver.h \ - cmaclient.h + cmaclient.h \ + cmabroadcast.h CONFIG += link_pkgconfig -PKGCONFIG += libvitamtp libmediainfo +PKGCONFIG += libmediainfo QMAKE_CXXFLAGS += -Wno-write-strings -Wall @@ -57,3 +57,11 @@ OTHER_FILES += \ FORMS += \ configwidget.ui + +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../../usr/lib/release/ -lvitamtp +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../../usr/lib/debug/ -lvitamtp +else:unix: LIBS += $$PWD/../../../../usr/lib/libvitamtp.a -lusb-1.0 -lxml2 + +INCLUDEPATH += $$PWD/../../../../usr/include +DEPENDPATH += $$PWD/../../../../usr/include + diff --git a/utils.cpp b/utils.cpp index 1cd9559..418425b 100644 --- a/utils.cpp +++ b/utils.cpp @@ -19,19 +19,20 @@ #include "utils.h" +#include +#include #include #include -extern "C" { -#include -} - #ifdef Q_OS_WIN32 #include #else #include #endif +#include +#include + bool getDiskSpace(const QString &dir, quint64 *free, quint64 *total) { #ifdef Q_OS_WIN32 @@ -79,3 +80,83 @@ bool removeRecursively(const QString &dirName) return result; #endif } + +QByteArray findFolderAlbumArt(const QString path, metadata_t *metadata) +{ + QByteArray data; + QDir folder(path); + + QStringList files = folder.entryList(QDir::Files | QDir::Readable); + const QStringList cover_list = QStringList() << "album" << "cover" << "front"; + const QStringList ext_list = QStringList() << "jpg" << "jpeg" << "png" << "gif"; + + foreach(const QString &file, files) { + foreach(const QString &cover, cover_list) { + foreach(const QString &ext, ext_list) { + if(file.compare(QString("%1.%2").arg(cover, ext), Qt::CaseInsensitive) == 0) { + qDebug() << "Trying to load album art from" << folder.absoluteFilePath(file); + QImage img; + if(img.load(folder.absoluteFilePath(file))) { + QBuffer buffer(&data); + buffer.open(QIODevice::WriteOnly); + QImage result = img.scaled(256, 250, Qt::KeepAspectRatio, Qt::SmoothTransformation); + result.save(&buffer, "JPEG"); + metadata->data.thumbnail.width = result.width(); + metadata->data.thumbnail.height = result.height(); + } + // only try with the first match + break; + } + } + } + } + return data; +} + +QByteArray getThumbnail(const QString &path, DataType type, metadata_t *metadata) +{ + QByteArray data; + + if(MASK_SET(type, SaveData)) { + QFile file(QDir(path).absoluteFilePath("ICON0.PNG")); + + if(file.open(QIODevice::ReadOnly)) { + data = file.readAll(); + } + } else if(MASK_SET(type, Photo)) { + QImage img; + + if(img.load(path)) { + QBuffer buffer(&data); + buffer.open(QIODevice::WriteOnly); + QImage result = img.scaled(213, 120, Qt::KeepAspectRatio, Qt::FastTransformation); + result.save(&buffer, "JPEG"); + metadata->data.thumbnail.width = result.width(); + metadata->data.thumbnail.height = result.height(); + } + } else if(MASK_SET(type, Music)) { + if(MASK_SET(type, Folder)) { + // TODO: try to load an album cover from one of the audio files. + data = findFolderAlbumArt(path, metadata); + } else { + MediaInfoLib::MediaInfo media; + + if(media.Open(path.toStdWString())) { + QString base64 = QString::fromStdWString(media.Get(MediaInfoLib::Stream_General, 0, MediaInfoLib::General_Cover_Data)); + QImage img; + + if(base64.size() > 0 && img.loadFromData(QByteArray::fromBase64(base64.toUtf8()))) { + QBuffer buffer(&data); + buffer.open(QIODevice::WriteOnly); + // use smooth transformation for the ambum art since is important to display correctly + QImage result = img.scaled(256, 256, Qt::KeepAspectRatio, Qt::SmoothTransformation); + result.save(&buffer, "JPEG"); + metadata->data.thumbnail.width = result.width(); + metadata->data.thumbnail.height = result.height(); + } + } + } + } + //TODO: implement thumbnails for videos + return data; +} diff --git a/utils.h b/utils.h index 632d22e..3484eec 100644 --- a/utils.h +++ b/utils.h @@ -20,9 +20,14 @@ #ifndef UTILS_H #define UTILS_H +#include #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; @@ -38,5 +43,6 @@ bool removeRecursively(const QString &dirName); bool getDiskSpace(const QString &dir, quint64 *free, quint64 *total); +QByteArray getThumbnail(const QString &path, DataType type, metadata_t *metadata); #endif // UTILS_H diff --git a/wirelessworker.cpp b/wirelessworker.cpp index 1550a48..759e283 100644 --- a/wirelessworker.cpp +++ b/wirelessworker.cpp @@ -35,6 +35,8 @@ BroadcastSignal::BroadcastSignal(QObject *parent) : qsrand(QTime::currentTime().msec()); this_object = this; started = false; + strcpy(hostname, QHostInfo::localHostName().toStdString().c_str()); + BroadcastSignal::info.name = hostname; } BroadcastSignal::~BroadcastSignal() @@ -54,7 +56,7 @@ int BroadcastSignal::generatePin(wireless_vita_info_t *info, int *p_err) int pin = qrand() % 100000000; qDebug("Your registration PIN for %s is: %08d", info->name, pin); *p_err = 0; - emit this_object->createdPin(pin); + emit this_object->receivedPin(pin); return pin; } diff --git a/wirelessworker.h b/wirelessworker.h index 82c602c..9d40c4c 100644 --- a/wirelessworker.h +++ b/wirelessworker.h @@ -44,12 +44,13 @@ public: private: - volatile bool started; + volatile bool started; + char hostname[256]; //used to emit a signal from a static method static BroadcastSignal *this_object; signals: - void createdPin(int); + void receivedPin(int); public slots: void stopBroadcast();