diff --git a/Service/src/service.cpp b/Service/src/service.cpp index 3beddec..dc5af82 100644 --- a/Service/src/service.cpp +++ b/Service/src/service.cpp @@ -70,46 +70,11 @@ namespace AkVCam std::condition_variable_any m_frameAvailable; std::mutex m_peerMutex; - // Picture update - std::string m_picture; - bool m_pictUpdated {false}; - std::condition_variable_any m_pictureUpdated; - std::mutex m_pictureMutex; - - // Devices update - bool m_devsUpdated {false}; - std::condition_variable_any m_devicesUpdated; - std::mutex m_devicesMutex; - - // Controls update - std::string m_deviceControls; - bool m_devControlsUpdated {false}; - std::condition_variable_any m_deviceControlsUpdated; - std::mutex m_deviceControlsMutex; - ServicePrivate(); static void removeClientById(void *userData, uint64_t clientId); bool clients(uint64_t clientId, const Message &inMessage, Message &outMessage); - bool updateDevices(uint64_t clientId, - const Message &inMessage, - Message &outMessage); - bool devicesUpdated(uint64_t clientId, - const Message &inMessage, - Message &outMessage); - bool updatePicture(uint64_t clientId, - const Message &inMessage, - Message &outMessage); - bool pictureUpdated(uint64_t clientId, - const Message &inMessage, - Message &outMessage); - bool updateControls(uint64_t clientId, - const Message &inMessage, - Message &outMessage); - bool controlsUpdated(uint64_t clientId, - const Message &inMessage, - Message &outMessage); bool broadcast(uint64_t clientId, const Message &inMessage, Message &outMessage); @@ -156,12 +121,6 @@ AkVCam::ServicePrivate::ServicePrivate() this->m_messageServer.setPort(Preferences::servicePort()); this->m_messageServer.subscribe(AKVCAM_SERVICE_MSG_CLIENTS , BIND(ServicePrivate::clients) ); - this->m_messageServer.subscribe(AKVCAM_SERVICE_MSG_UPDATE_PICTURE , BIND(ServicePrivate::updatePicture) ); - this->m_messageServer.subscribe(AKVCAM_SERVICE_MSG_PICTURE_UPDATED , BIND(ServicePrivate::pictureUpdated) ); - this->m_messageServer.subscribe(AKVCAM_SERVICE_MSG_UPDATE_DEVICES , BIND(ServicePrivate::updateDevices) ); - this->m_messageServer.subscribe(AKVCAM_SERVICE_MSG_DEVICES_UPDATED , BIND(ServicePrivate::devicesUpdated) ); - this->m_messageServer.subscribe(AKVCAM_SERVICE_MSG_UPDATE_CONTROLS , BIND(ServicePrivate::updateControls) ); - this->m_messageServer.subscribe(AKVCAM_SERVICE_MSG_CONTROLS_UPDATED, BIND(ServicePrivate::controlsUpdated)); this->m_messageServer.subscribe(AKVCAM_SERVICE_MSG_BROADCAST , BIND(ServicePrivate::broadcast) ); this->m_messageServer.subscribe(AKVCAM_SERVICE_MSG_LISTEN , BIND(ServicePrivate::listen) ); @@ -247,126 +206,6 @@ bool AkVCam::ServicePrivate::clients(uint64_t clientId, return true; } -bool AkVCam::ServicePrivate::updateDevices(uint64_t clientId, - const Message &inMessage, - Message &outMessage) -{ - AkLogFunction(); - UNUSED(clientId); - MsgUpdateDevices updateDevices(inMessage); - - this->m_devicesMutex.lock(); - this->m_devsUpdated = true; - this->m_devicesUpdated.notify_all(); - this->m_devicesMutex.unlock(); - - outMessage = MsgStatus(0, inMessage.queryId()).toMessage(); - - return true; -} - -bool AkVCam::ServicePrivate::devicesUpdated(uint64_t clientId, - const Message &inMessage, - Message &outMessage) -{ - AkLogFunction(); - UNUSED(clientId); - - this->m_devicesMutex.lock(); - - if (!this->m_devsUpdated) - this->m_devicesUpdated.wait_for(this->m_devicesMutex, - std::chrono::seconds(1)); - - outMessage = MsgStatus(this->m_devsUpdated? 0: -1, inMessage.queryId()).toMessage(); - this->m_devsUpdated = false; - this->m_devicesMutex.unlock(); - - return true; -} - -bool AkVCam::ServicePrivate::updatePicture(uint64_t clientId, - const Message &inMessage, - Message &outMessage) -{ - AkLogFunction(); - UNUSED(clientId); - MsgUpdatePicture updatePicture(inMessage); - - this->m_pictureMutex.lock(); - this->m_picture = updatePicture.picture(); - this->m_pictUpdated = true; - this->m_pictureUpdated.notify_all(); - this->m_pictureMutex.unlock(); - - outMessage = MsgStatus(0, inMessage.queryId()).toMessage(); - - return true; -} - -bool AkVCam::ServicePrivate::pictureUpdated(uint64_t clientId, - const Message &inMessage, - Message &outMessage) -{ - AkLogFunction(); - UNUSED(clientId); - - this->m_pictureMutex.lock(); - - if (!this->m_pictUpdated) - this->m_pictureUpdated.wait_for(this->m_pictureMutex, - std::chrono::seconds(1)); - - outMessage = MsgPictureUpdated(this->m_picture, - this->m_pictUpdated, - inMessage.queryId()).toMessage(); - this->m_pictUpdated = false; - this->m_pictureMutex.unlock(); - - return true; -} - -bool AkVCam::ServicePrivate::updateControls(uint64_t clientId, - const Message &inMessage, - Message &outMessage) -{ - AkLogFunction(); - UNUSED(clientId); - MsgUpdateControls updateControls(inMessage); - - this->m_deviceControlsMutex.lock(); - this->m_deviceControls = updateControls.device(); - this->m_devControlsUpdated = true; - this->m_deviceControlsUpdated.notify_all(); - this->m_deviceControlsMutex.unlock(); - - outMessage = MsgStatus(0, inMessage.queryId()).toMessage(); - - return true; -} - -bool AkVCam::ServicePrivate::controlsUpdated(uint64_t clientId, - const Message &inMessage, - Message &outMessage) -{ - AkLogFunction(); - UNUSED(clientId); - - this->m_deviceControlsMutex.lock(); - - if (!this->m_devControlsUpdated) - this->m_deviceControlsUpdated.wait_for(this->m_deviceControlsMutex, - std::chrono::seconds(1)); - - outMessage = MsgControlsUpdated(this->m_deviceControls, - this->m_devControlsUpdated, - inMessage.queryId()).toMessage(); - this->m_devControlsUpdated = false; - this->m_deviceControlsMutex.unlock(); - - return true; -} - bool AkVCam::ServicePrivate::broadcast(uint64_t clientId, const Message &inMessage, Message &outMessage) diff --git a/VCamUtils/src/ipcbridge.h b/VCamUtils/src/ipcbridge.h index 79eeae7..7602b00 100644 --- a/VCamUtils/src/ipcbridge.h +++ b/VCamUtils/src/ipcbridge.h @@ -22,6 +22,7 @@ #include #include +#include #include "videoformattypes.h" #include "videoframetypes.h" @@ -29,6 +30,7 @@ namespace AkVCam { + class IpcBridge; class IpcBridgePrivate; class VideoFormat; class VideoFrame; @@ -53,6 +55,8 @@ namespace AkVCam std::vector menu; }; + using IpcBridgePtr = std::shared_ptr; + class IpcBridge { public: @@ -85,6 +89,7 @@ namespace AkVCam int logLevel() const; void setLogLevel(int logLevel); std::string logPath(const std::string &logName={}) const; + void stopNotifications(); // List available devices. std::vector devices() const; diff --git a/VCamUtils/src/message.cpp b/VCamUtils/src/message.cpp index b212850..b308fab 100644 --- a/VCamUtils/src/message.cpp +++ b/VCamUtils/src/message.cpp @@ -32,12 +32,27 @@ namespace AkVCam int m_id {0}; uint64_t m_queryId {0}; std::vector m_data; + + static uint64_t queryId() + { + static uint64_t akvcamMessagePrivateQueryId = 0; + + return akvcamMessagePrivateQueryId++; + } }; } AkVCam::Message::Message() { this->d = new MessagePrivate; + this->d->m_queryId = MessagePrivate::queryId(); +} + +AkVCam::Message::Message(int id) +{ + this->d = new MessagePrivate; + this->d->m_id = id; + this->d->m_queryId = MessagePrivate::queryId(); } AkVCam::Message::Message(int id, uint64_t queryId) @@ -117,6 +132,12 @@ namespace AkVCam }; } +AkVCam::MsgCommons::MsgCommons() +{ + this->d = new MsgCommonsPrivate; + this->d->m_queryId = MessagePrivate::queryId(); +} + AkVCam::MsgCommons::MsgCommons(uint64_t queryId) { this->d = new MsgCommonsPrivate; @@ -147,6 +168,19 @@ namespace AkVCam }; } +AkVCam::MsgStatus::MsgStatus(): + MsgCommons() +{ + this->d = new MsgStatusPrivate; +} + +AkVCam::MsgStatus::MsgStatus(int status): + MsgCommons() +{ + this->d = new MsgStatusPrivate; + this->d->m_status = status; +} + AkVCam::MsgStatus::MsgStatus(int status, uint64_t queryId): MsgCommons(queryId) { @@ -219,6 +253,28 @@ namespace AkVCam }; } +AkVCam::MsgClients::MsgClients(): + MsgCommons() +{ + this->d = new MsgClientsPrivate; +} + +AkVCam::MsgClients::MsgClients(ClientType clientType): + MsgCommons() +{ + this->d = new MsgClientsPrivate; + this->d->m_clientType = clientType; +} + +AkVCam::MsgClients::MsgClients(ClientType clientType, + const std::vector &clients): + MsgCommons() +{ + this->d = new MsgClientsPrivate; + this->d->m_clientType = clientType; + this->d->m_clients = clients; +} + AkVCam::MsgClients::MsgClients(ClientType clientType, const std::vector &clients, uint64_t queryId): @@ -264,8 +320,10 @@ AkVCam::MsgClients::MsgClients(const Message &message): memcpy(&clientsSize, message.data().data() + offset, sizeof(clientsSize)); offset += sizeof(clientsSize); - this->d->m_clients.resize(clientsSize); - memcpy(this->d->m_clients.data(), message.data().data() + offset, sizeof(uint64_t) * clientsSize); + if (clientsSize > 0) { + this->d->m_clients.resize(clientsSize); + memcpy(this->d->m_clients.data(), message.data().data() + offset, sizeof(uint64_t) * clientsSize); + } } AkVCam::MsgClients::~MsgClients() @@ -301,11 +359,12 @@ AkVCam::Message AkVCam::MsgClients::toMessage() const memcpy(data.data() + offset, &this->d->m_clientType, sizeof(this->d->m_clientType)); offset += sizeof(this->d->m_clientType); - size_t clientsSize = 0; + size_t clientsSize = this->d->m_clients.size(); memcpy(data.data() + offset, &clientsSize, sizeof(clientsSize)); offset += sizeof(clientsSize); - memcpy(data.data() + offset, this->d->m_clients.data(), sizeof(uint64_t) * clientsSize); + if (clientsSize > 0) + memcpy(data.data() + offset, this->d->m_clients.data(), sizeof(uint64_t) * clientsSize); return {AKVCAM_SERVICE_MSG_CLIENTS, this->queryId(), data}; } @@ -322,538 +381,54 @@ const std::vector &AkVCam::MsgClients::clients() const namespace AkVCam { - class MsgUpdateDevicesPrivate - { - public: - }; -} - -AkVCam::MsgUpdateDevices::MsgUpdateDevices(uint64_t queryId): - MsgCommons(queryId) -{ - this->d = new MsgUpdateDevicesPrivate; -} - -AkVCam::MsgUpdateDevices::MsgUpdateDevices(const MsgUpdateDevices &other): - MsgCommons(other.queryId()) -{ - this->d = new MsgUpdateDevicesPrivate; -} - -AkVCam::MsgUpdateDevices::MsgUpdateDevices(const Message &message): - MsgCommons(message.queryId()) -{ - this->d = new MsgUpdateDevicesPrivate; - - if (message.id() != AKVCAM_SERVICE_MSG_UPDATE_DEVICES - || message.data().size() != 0) - return; -} - -AkVCam::MsgUpdateDevices::~MsgUpdateDevices() -{ - delete this->d; -} - -AkVCam::MsgUpdateDevices &AkVCam::MsgUpdateDevices::operator =(const MsgUpdateDevices &other) -{ - if (this != &other) { - this->setQueryId(other.queryId()); - } - - return *this; -} - -bool AkVCam::MsgUpdateDevices::operator ==(const MsgUpdateDevices &other) const -{ - return this->queryId() == other.queryId(); -} - -AkVCam::Message AkVCam::MsgUpdateDevices::toMessage() const -{ - return {AKVCAM_SERVICE_MSG_UPDATE_DEVICES, this->queryId(), {}}; -} - -namespace AkVCam -{ - class MsgDevicesUpdatedPrivate - { - public: - }; -} - -AkVCam::MsgDevicesUpdated::MsgDevicesUpdated(uint64_t queryId): - MsgCommons(queryId) -{ - this->d = new MsgDevicesUpdatedPrivate; -} - -AkVCam::MsgDevicesUpdated::MsgDevicesUpdated(const MsgDevicesUpdated &other): - MsgCommons(other.queryId()) -{ - this->d = new MsgDevicesUpdatedPrivate; -} - -AkVCam::MsgDevicesUpdated::MsgDevicesUpdated(const Message &message): - MsgCommons(message.queryId()) -{ - this->d = new MsgDevicesUpdatedPrivate; - - if (message.id() != AKVCAM_SERVICE_MSG_DEVICES_UPDATED - || message.data().size() != 0) - return; -} - -AkVCam::MsgDevicesUpdated::~MsgDevicesUpdated() -{ - delete this->d; -} - -AkVCam::MsgDevicesUpdated &AkVCam::MsgDevicesUpdated::operator =(const MsgDevicesUpdated &other) -{ - if (this != &other) { - this->setQueryId(other.queryId()); - } - - return *this; -} - -bool AkVCam::MsgDevicesUpdated::operator ==(const MsgDevicesUpdated &other) const -{ - return this->queryId() == other.queryId(); -} - -AkVCam::Message AkVCam::MsgDevicesUpdated::toMessage() const -{ - return {AKVCAM_SERVICE_MSG_DEVICES_UPDATED, this->queryId(), {}}; -} - -namespace AkVCam -{ - class MsgUpdatePicturePrivate - { - public: - std::string m_picture; - }; -} - -AkVCam::MsgUpdatePicture::MsgUpdatePicture(const std::string &picture, - uint64_t queryId): - MsgCommons(queryId) -{ - this->d = new MsgUpdatePicturePrivate; - this->d->m_picture = picture; -} - -AkVCam::MsgUpdatePicture::MsgUpdatePicture(const MsgUpdatePicture &other): - MsgCommons(other.queryId()) -{ - this->d = new MsgUpdatePicturePrivate; - this->d->m_picture = other.d->m_picture; -} - -AkVCam::MsgUpdatePicture::MsgUpdatePicture(const Message &message): - MsgCommons(message.queryId()) -{ - this->d = new MsgUpdatePicturePrivate; - size_t totalSize = 0; - - { - size_t pictureSize = 0; - totalSize += sizeof(size_t); - memcpy(&pictureSize, message.data().data() + totalSize, sizeof(size_t)); - totalSize += pictureSize; - } - - if (message.id() != AKVCAM_SERVICE_MSG_UPDATE_PICTURE - || message.data().size() != totalSize) - return; - - size_t offset = 0; - - size_t pictureSize = 0; - memcpy(&pictureSize, message.data().data() + offset, sizeof(size_t)); - offset += sizeof(size_t); - - this->d->m_picture = {message.data().data() + offset, pictureSize}; -} - -AkVCam::MsgUpdatePicture::~MsgUpdatePicture() -{ - delete this->d; -} - -AkVCam::MsgUpdatePicture &AkVCam::MsgUpdatePicture::operator =(const MsgUpdatePicture &other) -{ - if (this != &other) { - this->d->m_picture = other.d->m_picture; - this->setQueryId(other.queryId()); - } - - return *this; -} - -bool AkVCam::MsgUpdatePicture::operator ==(const MsgUpdatePicture &other) const -{ - return this->d->m_picture == other.d->m_picture - && this->queryId() == other.queryId(); -} - -AkVCam::Message AkVCam::MsgUpdatePicture::toMessage() const -{ - size_t totalSize = sizeof(size_t) - + this->d->m_picture.size(); - std::vector data(totalSize); - size_t offset = 0; - - size_t pictureSize = this->d->m_picture.size(); - memcpy(data.data() + offset, &pictureSize, sizeof(size_t)); - offset += sizeof(size_t); - - memcpy(data.data() + offset, this->d->m_picture.data(), pictureSize); - - return {AKVCAM_SERVICE_MSG_UPDATE_PICTURE, this->queryId(), data}; -} - -const std::string &AkVCam::MsgUpdatePicture::picture() const -{ - return this->d->m_picture; -} - -namespace AkVCam -{ - class MsgPictureUpdatedPrivate - { - public: - std::string m_picture; - bool m_updated {false}; - }; -} - -AkVCam::MsgPictureUpdated::MsgPictureUpdated(const std::string &picture, - bool updated, - uint64_t queryId): - MsgCommons(queryId) -{ - this->d = new MsgPictureUpdatedPrivate; - this->d->m_picture = picture; - this->d->m_updated = updated; -} - -AkVCam::MsgPictureUpdated::MsgPictureUpdated(const MsgPictureUpdated &other): - MsgCommons(other.queryId()) -{ - this->d = new MsgPictureUpdatedPrivate; - this->d->m_picture = other.d->m_picture; - this->d->m_updated = other.d->m_updated; -} - -AkVCam::MsgPictureUpdated::MsgPictureUpdated(const Message &message): - MsgCommons(message.queryId()) -{ - this->d = new MsgPictureUpdatedPrivate; - size_t totalSize = 0; - - { - size_t pictureSize = 0; - totalSize += sizeof(size_t); - memcpy(&pictureSize, message.data().data() + totalSize, sizeof(size_t)); - totalSize += pictureSize; - - totalSize += sizeof(this->d->m_updated); - } - - if (message.id() != AKVCAM_SERVICE_MSG_PICTURE_UPDATED - || message.data().size() != totalSize) - return; - - size_t offset = 0; - - size_t pictureSize = 0; - memcpy(&pictureSize, message.data().data() + offset, sizeof(size_t)); - offset += sizeof(size_t); - - this->d->m_picture = {message.data().data() + offset, pictureSize}; - offset += pictureSize; - - memcpy(&this->d->m_updated, message.data().data() + offset, sizeof(this->d->m_updated)); -} - -AkVCam::MsgPictureUpdated::~MsgPictureUpdated() -{ - delete this->d; -} - -AkVCam::MsgPictureUpdated &AkVCam::MsgPictureUpdated::operator =(const MsgPictureUpdated &other) -{ - if (this != &other) { - this->d->m_picture = other.d->m_picture; - this->d->m_updated = other.d->m_updated; - this->setQueryId(other.queryId()); - } - - return *this; -} - -bool AkVCam::MsgPictureUpdated::operator ==(const MsgPictureUpdated &other) const -{ - return this->d->m_picture == other.d->m_picture - && this->d->m_updated == other.d->m_updated - && this->queryId() == other.queryId(); -} - -AkVCam::Message AkVCam::MsgPictureUpdated::toMessage() const -{ - size_t totalSize = sizeof(size_t) - + this->d->m_picture.size() - + sizeof(this->d->m_updated); - std::vector data(totalSize); - size_t offset = 0; - - size_t pictureSize = this->d->m_picture.size(); - memcpy(data.data() + offset, &pictureSize, sizeof(size_t)); - offset += sizeof(size_t); - - memcpy(data.data() + offset, this->d->m_picture.data(), pictureSize); - offset += pictureSize; - - memcpy(data.data() + offset, &this->d->m_updated, sizeof(this->d->m_updated)); - - return {AKVCAM_SERVICE_MSG_PICTURE_UPDATED, this->queryId(), data}; -} - -const std::string &AkVCam::MsgPictureUpdated::picture() const -{ - return this->d->m_picture; -} - -bool AkVCam::MsgPictureUpdated::updated() const -{ - return this->d->m_updated; -} - -namespace AkVCam -{ - class MsgUpdateControlsPrivate + class MsgFrameReadyPrivate { public: std::string m_device; + VideoFrame m_frame; + bool m_isActive {false}; }; } -AkVCam::MsgUpdateControls::MsgUpdateControls(const std::string &device, - uint64_t queryId): - MsgCommons(queryId) -{ - this->d = new MsgUpdateControlsPrivate; - this->d->m_device = device; -} - -AkVCam::MsgUpdateControls::MsgUpdateControls(const MsgUpdateControls &other): - MsgCommons(other.queryId()) -{ - this->d = new MsgUpdateControlsPrivate; - this->d->m_device = other.d->m_device; -} - -AkVCam::MsgUpdateControls::MsgUpdateControls(const Message &message): - MsgCommons(message.queryId()) -{ - this->d = new MsgUpdateControlsPrivate; - size_t totalSize = 0; - - { - size_t deviceSize = 0; - totalSize += sizeof(size_t); - memcpy(&deviceSize, message.data().data() + totalSize, sizeof(size_t)); - totalSize += deviceSize; - } - - if (message.id() != AKVCAM_SERVICE_MSG_UPDATE_CONTROLS - || message.data().size() != totalSize) - return; - - size_t offset = 0; - - size_t deviceSize = 0; - memcpy(&deviceSize, message.data().data() + offset, sizeof(size_t)); - offset += sizeof(size_t); - - this->d->m_device = {message.data().data() + offset, deviceSize}; -} - -AkVCam::MsgUpdateControls::~MsgUpdateControls() -{ - delete this->d; -} - -AkVCam::MsgUpdateControls &AkVCam::MsgUpdateControls::operator =(const MsgUpdateControls &other) -{ - if (this != &other) { - this->d->m_device = other.d->m_device; - this->setQueryId(other.queryId()); - } - - return *this; -} - -bool AkVCam::MsgUpdateControls::operator ==(const MsgUpdateControls &other) const +AkVCam::MsgFrameReady::MsgFrameReady(): + MsgCommons() { - return this->d->m_device == other.d->m_device - && this->queryId() == other.queryId(); -} - -AkVCam::Message AkVCam::MsgUpdateControls::toMessage() const -{ - size_t totalSize = sizeof(size_t) - + this->d->m_device.size(); - std::vector data(totalSize); - size_t offset = 0; - - size_t deviceSize = this->d->m_device.size(); - memcpy(data.data() + offset, &deviceSize, sizeof(size_t)); - offset += sizeof(size_t); - - memcpy(data.data() + offset, this->d->m_device.data(), deviceSize); - - return {AKVCAM_SERVICE_MSG_UPDATE_CONTROLS, this->queryId(), data}; + this->d = new MsgFrameReadyPrivate; } -const std::string &AkVCam::MsgUpdateControls::device() const +AkVCam::MsgFrameReady::MsgFrameReady(const std::string &device): + MsgCommons() { - return this->d->m_device; + this->d = new MsgFrameReadyPrivate; + this->d->m_device = device; } -namespace AkVCam +AkVCam::MsgFrameReady::MsgFrameReady(const std::string &device, bool isActive): + MsgCommons() { - class MsgControlsUpdatedPrivate - { - public: - std::string m_device; - bool m_updated {false}; - }; + this->d = new MsgFrameReadyPrivate; + this->d->m_device = device; + this->d->m_isActive = isActive; } -AkVCam::MsgControlsUpdated::MsgControlsUpdated(const std::string &device, - bool updated, - uint64_t queryId): +AkVCam::MsgFrameReady::MsgFrameReady(const std::string &device, + bool isActive, + uint64_t queryId): MsgCommons(queryId) { - this->d = new MsgControlsUpdatedPrivate; + this->d = new MsgFrameReadyPrivate; this->d->m_device = device; - this->d->m_updated = updated; -} - -AkVCam::MsgControlsUpdated::MsgControlsUpdated(const MsgControlsUpdated &other): - MsgCommons(other.queryId()) -{ - this->d = new MsgControlsUpdatedPrivate; - this->d->m_device = other.d->m_device; - this->d->m_updated = other.d->m_updated; -} - -AkVCam::MsgControlsUpdated::MsgControlsUpdated(const Message &message): - MsgCommons(message.queryId()) -{ - this->d = new MsgControlsUpdatedPrivate; - size_t totalSize = 0; - - { - size_t deviceSize = 0; - totalSize += sizeof(size_t); - memcpy(&deviceSize, message.data().data() + totalSize, sizeof(size_t)); - totalSize += deviceSize; - - totalSize += sizeof(this->d->m_updated); - } - - if (message.id() != AKVCAM_SERVICE_MSG_CONTROLS_UPDATED - || message.data().size() != totalSize) - return; - - size_t offset = 0; - - size_t deviceSize = 0; - memcpy(&deviceSize, message.data().data() + offset, sizeof(size_t)); - offset += sizeof(size_t); - - this->d->m_device = {message.data().data() + offset, deviceSize}; - offset += deviceSize; - - memcpy(&this->d->m_updated, message.data().data() + offset, sizeof(this->d->m_updated)); -} - -AkVCam::MsgControlsUpdated::~MsgControlsUpdated() -{ - delete this->d; -} - -AkVCam::MsgControlsUpdated &AkVCam::MsgControlsUpdated::operator =(const MsgControlsUpdated &other) -{ - if (this != &other) { - this->d->m_device = other.d->m_device; - this->d->m_updated = other.d->m_updated; - this->setQueryId(other.queryId()); - } - - return *this; -} - -bool AkVCam::MsgControlsUpdated::operator ==(const MsgControlsUpdated &other) const -{ - return this->d->m_device == other.d->m_device - && this->d->m_updated == other.d->m_updated - && this->queryId() == other.queryId(); -} - -AkVCam::Message AkVCam::MsgControlsUpdated::toMessage() const -{ - size_t totalSize = sizeof(size_t) - + this->d->m_device.size() - + sizeof(this->d->m_updated); - std::vector data(totalSize); - size_t offset = 0; - - size_t deviceSize = this->d->m_device.size(); - memcpy(data.data() + offset, &deviceSize, sizeof(size_t)); - offset += sizeof(size_t); - - memcpy(data.data() + offset, this->d->m_device.data(), deviceSize); - offset += deviceSize; - - memcpy(data.data() + offset, &this->d->m_updated, sizeof(this->d->m_updated)); - - return {AKVCAM_SERVICE_MSG_CONTROLS_UPDATED, this->queryId(), data}; -} - -const std::string &AkVCam::MsgControlsUpdated::device() const -{ - return this->d->m_device; -} - -bool AkVCam::MsgControlsUpdated::updated() const -{ - return this->d->m_updated; -} - -namespace AkVCam -{ - class MsgFrameReadyPrivate - { - public: - std::string m_device; - VideoFrame m_frame; - bool m_isActive {false}; - }; + this->d->m_isActive = isActive; } AkVCam::MsgFrameReady::MsgFrameReady(const std::string &device, - bool isActive, - uint64_t queryId): - MsgCommons(queryId) + const VideoFrame &frame, + bool isActive): + MsgCommons() { this->d = new MsgFrameReadyPrivate; this->d->m_device = device; + this->d->m_frame = frame; this->d->m_isActive = isActive; } @@ -912,8 +487,10 @@ AkVCam::MsgFrameReady::MsgFrameReady(const Message &message): memcpy(&deviceSize, message.data().data() + offset, sizeof(size_t)); offset += sizeof(size_t); - this->d->m_device = {message.data().data() + offset, deviceSize}; - offset += deviceSize; + if (deviceSize > 0) { + this->d->m_device = {message.data().data() + offset, deviceSize}; + offset += deviceSize; + } FourCC fourcc = 0; memcpy(&fourcc, message.data().data() + offset, sizeof(fourcc)); @@ -931,9 +508,11 @@ AkVCam::MsgFrameReady::MsgFrameReady(const Message &message): memcpy(&dataSize, message.data().data() + offset, sizeof(size_t)); offset += sizeof(size_t); - this->d->m_frame = {VideoFormat(fourcc, width, height)}; - memcpy(this->d->m_frame.data().data(), message.data().data() + offset, dataSize); - offset += dataSize; + if (dataSize > 0) { + this->d->m_frame = {VideoFormat(fourcc, width, height)}; + memcpy(this->d->m_frame.data().data(), message.data().data() + offset, dataSize); + offset += dataSize; + } memcpy(&this->d->m_isActive, message.data().data() + offset, sizeof(this->d->m_isActive)); } @@ -980,8 +559,10 @@ AkVCam::Message AkVCam::MsgFrameReady::toMessage() const memcpy(data.data() + offset, &deviceSize, sizeof(deviceSize)); offset += sizeof(size_t); - memcpy(data.data() + offset, this->d->m_device.data(), deviceSize); - offset += this->d->m_device.size(); + if (deviceSize > 0) { + memcpy(data.data() + offset, this->d->m_device.data(), deviceSize); + offset += this->d->m_device.size(); + } auto fourcc = this->d->m_frame.format().fourcc(); memcpy(data.data() + offset, &fourcc, sizeof(fourcc)); @@ -999,8 +580,10 @@ AkVCam::Message AkVCam::MsgFrameReady::toMessage() const memcpy(data.data() + offset, &dataSize, sizeof(size_t)); offset += sizeof(size_t); - memcpy(data.data() + offset, this->d->m_frame.data().data(), dataSize); - offset += dataSize; + if (dataSize > 0) { + memcpy(data.data() + offset, this->d->m_frame.data().data(), dataSize); + offset += dataSize; + } memcpy(data.data() + offset, &this->d->m_isActive, sizeof(this->d->m_isActive)); @@ -1028,11 +611,32 @@ namespace AkVCam { public: std::string m_device; - uint64_t m_pid; + uint64_t m_pid {0}; VideoFrame m_frame; }; } +AkVCam::MsgBroadcast::MsgBroadcast(): + MsgCommons() +{ + this->d = new MsgBroadcastPrivate; +} + +AkVCam::MsgBroadcast::MsgBroadcast(const std::string &device): + MsgCommons() +{ + this->d = new MsgBroadcastPrivate; + this->d->m_device = device; +} + +AkVCam::MsgBroadcast::MsgBroadcast(const std::string &device, uint64_t pid): + MsgCommons() +{ + this->d = new MsgBroadcastPrivate; + this->d->m_device = device; + this->d->m_pid = pid; +} + AkVCam::MsgBroadcast::MsgBroadcast(const std::string &device, uint64_t pid, uint64_t queryId): @@ -1043,6 +647,17 @@ AkVCam::MsgBroadcast::MsgBroadcast(const std::string &device, this->d->m_pid = pid; } +AkVCam::MsgBroadcast::MsgBroadcast(const std::string &device, + uint64_t pid, + const VideoFrame &frame): + MsgCommons() +{ + this->d = new MsgBroadcastPrivate; + this->d->m_device = device; + this->d->m_pid = pid; + this->d->m_frame = frame; +} + AkVCam::MsgBroadcast::MsgBroadcast(const std::string &device, uint64_t pid, const VideoFrame &frame, @@ -1097,8 +712,10 @@ AkVCam::MsgBroadcast::MsgBroadcast(const Message &message): memcpy(&deviceSize, message.data().data() + offset, sizeof(size_t)); offset += sizeof(size_t); - this->d->m_device = {message.data().data() + offset, deviceSize}; - offset += deviceSize; + if (deviceSize > 0) { + this->d->m_device = {message.data().data() + offset, deviceSize}; + offset += deviceSize; + } memcpy(&this->d->m_pid, message.data().data() + offset, sizeof(this->d->m_pid)); offset += sizeof(this->d->m_pid); @@ -1119,8 +736,10 @@ AkVCam::MsgBroadcast::MsgBroadcast(const Message &message): memcpy(&dataSize, message.data().data() + offset, sizeof(size_t)); offset += sizeof(size_t); - this->d->m_frame = {VideoFormat(fourcc, width, height)}; - memcpy(this->d->m_frame.data().data(), message.data().data() + offset, dataSize); + if (dataSize > 0) { + this->d->m_frame = {VideoFormat(fourcc, width, height)}; + memcpy(this->d->m_frame.data().data(), message.data().data() + offset, dataSize); + } } AkVCam::MsgBroadcast::~MsgBroadcast() @@ -1165,8 +784,10 @@ AkVCam::Message AkVCam::MsgBroadcast::toMessage() const memcpy(data.data() + offset, &deviceSize, sizeof(size_t)); offset += sizeof(size_t); - memcpy(data.data() + offset, this->d->m_device.data(), deviceSize); - offset += deviceSize; + if (deviceSize > 0) { + memcpy(data.data() + offset, this->d->m_device.data(), deviceSize); + offset += deviceSize; + } memcpy(data.data() + offset, &this->d->m_pid, sizeof(this->d->m_pid)); offset += sizeof(this->d->m_pid); @@ -1187,7 +808,8 @@ AkVCam::Message AkVCam::MsgBroadcast::toMessage() const memcpy(data.data() + offset, &dataSize, sizeof(size_t)); offset += sizeof(size_t); - memcpy(data.data() + offset, this->d->m_frame.data().data(), dataSize); + if (dataSize > 0) + memcpy(data.data() + offset, this->d->m_frame.data().data(), dataSize); return {AKVCAM_SERVICE_MSG_BROADCAST, this->queryId(), data}; } @@ -1213,13 +835,34 @@ namespace AkVCam { public: std::string m_device; - uint64_t m_pid; + uint64_t m_pid {0}; }; } +AkVCam::MsgListen::MsgListen(): + MsgCommons() +{ + this->d = new MsgListenPrivate; +} + +AkVCam::MsgListen::MsgListen(const std::string &device): + MsgCommons() +{ + this->d = new MsgListenPrivate; + this->d->m_device = device; +} + +AkVCam::MsgListen::MsgListen(const std::string &device, uint64_t pid): + MsgCommons() +{ + this->d = new MsgListenPrivate; + this->d->m_device = device; + this->d->m_pid = pid; +} + AkVCam::MsgListen::MsgListen(const std::string &device, - uint64_t pid, - uint64_t queryId): + uint64_t pid, + uint64_t queryId): MsgCommons(queryId) { this->d = new MsgListenPrivate; @@ -1260,8 +903,10 @@ AkVCam::MsgListen::MsgListen(const Message &message): memcpy(&deviceSize, message.data().data() + offset, sizeof(size_t)); offset += sizeof(size_t); - this->d->m_device = {message.data().data() + offset, deviceSize}; - offset += deviceSize; + if (deviceSize > 0) { + this->d->m_device = {message.data().data() + offset, deviceSize}; + offset += deviceSize; + } memcpy(&this->d->m_pid, message.data().data() + offset, sizeof(this->d->m_pid)); } @@ -1301,8 +946,10 @@ AkVCam::Message AkVCam::MsgListen::toMessage() const memcpy(data.data() + offset, &deviceSize, sizeof(size_t)); offset += sizeof(size_t); - memcpy(data.data() + offset, this->d->m_device.data(), deviceSize); - offset += deviceSize; + if (deviceSize > 0) { + memcpy(data.data() + offset, this->d->m_device.data(), deviceSize); + offset += deviceSize; + } memcpy(data.data() + offset, &this->d->m_pid, sizeof(this->d->m_pid)); diff --git a/VCamUtils/src/message.h b/VCamUtils/src/message.h index 6b3383d..473cdc2 100644 --- a/VCamUtils/src/message.h +++ b/VCamUtils/src/message.h @@ -33,7 +33,8 @@ namespace AkVCam { public: Message(); - Message(int id, uint64_t queryId=0); + Message(int id); + Message(int id, uint64_t queryId); Message(int id, uint64_t queryId, const std::vector &data); Message(int id, const std::vector &data); Message(const Message &other); @@ -54,7 +55,8 @@ namespace AkVCam class MsgCommons { public: - MsgCommons(uint64_t queryId=0); + MsgCommons(); + MsgCommons(uint64_t queryId); ~MsgCommons(); uint64_t queryId() const; @@ -71,7 +73,9 @@ namespace AkVCam class MsgStatus: public MsgCommons { public: - MsgStatus(int status=0, uint64_t queryId=0); + MsgStatus(); + MsgStatus(int status); + MsgStatus(int status, uint64_t queryId); MsgStatus(const MsgStatus &other); MsgStatus(const Message &message); ~MsgStatus(); @@ -96,9 +100,13 @@ namespace AkVCam ClientType_VCams, }; - MsgClients(ClientType clientType=ClientType_Any, - const std::vector &clients={}, - uint64_t queryId=0); + MsgClients(); + MsgClients(ClientType clientType); + MsgClients(ClientType clientType, + const std::vector &clients); + MsgClients(ClientType clientType, + const std::vector &clients, + uint64_t queryId); MsgClients(const MsgClients &other); MsgClients(const Message &message); ~MsgClients(); @@ -113,137 +121,25 @@ namespace AkVCam MsgClientsPrivate *d; }; - class MsgUpdateDevicesPrivate; - - class MsgUpdateDevices: public MsgCommons - { - public: - MsgUpdateDevices(uint64_t queryId=0); - MsgUpdateDevices(const MsgUpdateDevices &other); - MsgUpdateDevices(const Message &message); - ~MsgUpdateDevices(); - MsgUpdateDevices &operator =(const MsgUpdateDevices &other); - bool operator ==(const MsgUpdateDevices &other) const; - Message toMessage() const; - - private: - MsgUpdateDevicesPrivate *d; - }; - - class MsgDevicesUpdatedPrivate; - - class MsgDevicesUpdated: public MsgCommons - { - public: - MsgDevicesUpdated(uint64_t queryId=0); - MsgDevicesUpdated(const MsgDevicesUpdated &other); - MsgDevicesUpdated(const Message &message); - ~MsgDevicesUpdated(); - MsgDevicesUpdated &operator =(const MsgDevicesUpdated &other); - bool operator ==(const MsgDevicesUpdated &other) const; - Message toMessage() const; - - private: - MsgDevicesUpdatedPrivate *d; - }; - - class MsgUpdatePicturePrivate; - - class MsgUpdatePicture: public MsgCommons - { - public: - MsgUpdatePicture(const std::string &picture={}, - uint64_t queryId=0); - MsgUpdatePicture(const MsgUpdatePicture &other); - MsgUpdatePicture(const Message &message); - ~MsgUpdatePicture(); - MsgUpdatePicture &operator =(const MsgUpdatePicture &other); - bool operator ==(const MsgUpdatePicture &other) const; - Message toMessage() const; - - const std::string &picture() const; - - private: - MsgUpdatePicturePrivate *d; - }; - - class MsgPictureUpdatedPrivate; - - class MsgPictureUpdated: public MsgCommons - { - public: - MsgPictureUpdated(const std::string &picture={}, - bool updated=false, - uint64_t queryId=0); - MsgPictureUpdated(const MsgPictureUpdated &other); - MsgPictureUpdated(const Message &message); - ~MsgPictureUpdated(); - MsgPictureUpdated &operator =(const MsgPictureUpdated &other); - bool operator ==(const MsgPictureUpdated &other) const; - Message toMessage() const; - - const std::string &picture() const; - bool updated() const; - - private: - MsgPictureUpdatedPrivate *d; - }; - - class MsgUpdateControlsPrivate; - - class MsgUpdateControls: public MsgCommons - { - public: - MsgUpdateControls(const std::string &device={}, - uint64_t queryId=0); - MsgUpdateControls(const MsgUpdateControls &other); - MsgUpdateControls(const Message &message); - ~MsgUpdateControls(); - MsgUpdateControls &operator =(const MsgUpdateControls &other); - bool operator ==(const MsgUpdateControls &other) const; - Message toMessage() const; - - const std::string &device() const; - - private: - MsgUpdateControlsPrivate *d; - }; - - class MsgControlsUpdatedPrivate; - - class MsgControlsUpdated: public MsgCommons - { - public: - MsgControlsUpdated(const std::string &device={}, - bool updated=false, - uint64_t queryId=0); - MsgControlsUpdated(const MsgControlsUpdated &other); - MsgControlsUpdated(const Message &message); - ~MsgControlsUpdated(); - MsgControlsUpdated &operator =(const MsgControlsUpdated &other); - bool operator ==(const MsgControlsUpdated &other) const; - Message toMessage() const; - - const std::string &device() const; - bool updated() const; - - private: - MsgControlsUpdatedPrivate *d; - }; - class MsgFrameReadyPrivate; class VideoFrame; class MsgFrameReady: public MsgCommons { public: - MsgFrameReady(const std::string &device={}, - bool isActive=false, - uint64_t queryId=0); + MsgFrameReady(); + MsgFrameReady(const std::string &device); + MsgFrameReady(const std::string &device, bool isActive); + MsgFrameReady(const std::string &device, + bool isActive, + uint64_t queryId); + MsgFrameReady(const std::string &device, + const VideoFrame &frame, + bool isActive); MsgFrameReady(const std::string &device, const VideoFrame &frame, - bool isActive=false, - uint64_t queryId=0); + bool isActive, + uint64_t queryId); MsgFrameReady(const MsgFrameReady &other); MsgFrameReady(const Message &message); ~MsgFrameReady(); @@ -264,13 +160,19 @@ namespace AkVCam class MsgBroadcast: public MsgCommons { public: - MsgBroadcast(const std::string &device={}, - uint64_t pid=0, - uint64_t queryId=0); + MsgBroadcast(); + MsgBroadcast(const std::string &device); + MsgBroadcast(const std::string &device, uint64_t pid); + MsgBroadcast(const std::string &device, + uint64_t pid, + uint64_t queryId); + MsgBroadcast(const std::string &device, + uint64_t pid, + const VideoFrame &frame); MsgBroadcast(const std::string &device, uint64_t pid, const VideoFrame &frame, - uint64_t queryId=0); + uint64_t queryId); MsgBroadcast(const MsgBroadcast &other); MsgBroadcast(const Message &message); ~MsgBroadcast(); @@ -291,9 +193,12 @@ namespace AkVCam class MsgListen: public MsgCommons { public: - MsgListen(const std::string &device={}, - uint64_t pid=0, - uint64_t queryId=0); + MsgListen(); + MsgListen(const std::string &device); + MsgListen(const std::string &device, uint64_t pid); + MsgListen(const std::string &device, + uint64_t pid, + uint64_t queryId); MsgListen(const MsgListen &other); MsgListen(const Message &message); ~MsgListen(); diff --git a/VCamUtils/src/messageclient.cpp b/VCamUtils/src/messageclient.cpp index c201f2e..c3ad9fe 100644 --- a/VCamUtils/src/messageclient.cpp +++ b/VCamUtils/src/messageclient.cpp @@ -67,6 +67,8 @@ void AkVCam::MessageClient::setPort(uint16_t port) bool AkVCam::MessageClient::isUp(uint16_t port) { + AkLogFunction(); + AkLogDebug() << "Port: " << port << std::endl; auto clientSocket = socket(AF_INET, SOCK_STREAM, 0); if (clientSocket < 0) { @@ -85,7 +87,7 @@ bool AkVCam::MessageClient::isUp(uint16_t port) if (connect(clientSocket, reinterpret_cast(&serverAddress), sizeof(sockaddr_in)) != 0) { - AkLogCritical() << "Failed conneecting to the saocket: " << strerror(errno) << std::endl; + AkLogCritical() << "Failed conneecting to the socket: " << strerror(errno) << std::endl; return false; } @@ -161,6 +163,7 @@ bool AkVCam::MessageClientPrivate::connection(uint16_t port, MessageClient::OutMessageHandler writeData) { AkLogFunction(); + AkLogDebug() << "Port: " << port << std::endl; auto clientSocket = socket(AF_INET, SOCK_STREAM, 0); if (clientSocket < 0) { @@ -184,6 +187,12 @@ bool AkVCam::MessageClientPrivate::connection(uint16_t port, return false; } + auto connectionId = AkVCam::id(); + + this->m_logsMutex.lock(); + AkLogDebug() << "Connection ready: " << connectionId << std::endl; + this->m_logsMutex.unlock(); + bool ok = true; // Send the response @@ -195,6 +204,7 @@ bool AkVCam::MessageClientPrivate::connection(uint16_t port, this->m_logsMutex.lock(); AkLogDebug() << "Send message:" << std::endl; + AkLogDebug() << " Connection ID: " << connectionId << std::endl; AkLogDebug() << " Message ID: " << stringFromMessageId(inMessage.id()) << std::endl; AkLogDebug() << " Query ID: " << inMessage.queryId() << std::endl; AkLogDebug() << " Data size: " << inMessage.data().size() << std::endl; @@ -244,6 +254,7 @@ bool AkVCam::MessageClientPrivate::connection(uint16_t port, this->m_logsMutex.lock(); AkLogDebug() << "Received message:" << std::endl; + AkLogDebug() << " Connection ID: " << connectionId << std::endl; AkLogDebug() << " Message ID: " << stringFromMessageId(messageId) << std::endl; AkLogDebug() << " Query ID: " << queryId << std::endl; AkLogDebug() << " Data size: " << outData.size() << std::endl; @@ -255,6 +266,10 @@ bool AkVCam::MessageClientPrivate::connection(uint16_t port, break; } + this->m_logsMutex.lock(); + AkLogDebug() << "Connection closed: " << connectionId << std::endl; + this->m_logsMutex.unlock(); + Sockets::closeSocket(clientSocket); return ok; diff --git a/VCamUtils/src/messageserver.cpp b/VCamUtils/src/messageserver.cpp index 04a6605..091785e 100644 --- a/VCamUtils/src/messageserver.cpp +++ b/VCamUtils/src/messageserver.cpp @@ -142,7 +142,11 @@ int AkVCam::MessageServer::run() } // Start listening for connected clients - listen(serverSocket, SOMAXCONN); + if (listen(serverSocket, SOMAXCONN) != 0) { + AkLogCritical() << "Failed listening to the socket" << std::endl; + + return -EXIT_FAILURE; + } AkLogInfo() << "Server running at http://localhost:" << this->d->m_port << '/' << std::endl; this->d->m_run = true; @@ -216,8 +220,12 @@ void AkVCam::MessageServerPrivate::connection(SocketType clientSocket, ConnectionThreadPtr connection) { auto clientId = AkVCam::id(); - bool ok = true; + + this->m_logsMutex.lock(); AkLogDebug() << "Client connected: " << clientId << std::endl; + this->m_logsMutex.unlock(); + + bool ok = true; while (connection->run && ok) { int messageId = 0; @@ -237,6 +245,7 @@ void AkVCam::MessageServerPrivate::connection(SocketType clientSocket, this->m_logsMutex.lock(); AkLogDebug() << "Received message:" << std::endl; + AkLogDebug() << " Client ID: " << clientId << std::endl; AkLogDebug() << " Message ID: " << stringFromMessageId(messageId) << std::endl; AkLogDebug() << " Query ID: " << queryId << std::endl; AkLogDebug() << " Data size: " << inData.size() << std::endl; @@ -257,6 +266,7 @@ void AkVCam::MessageServerPrivate::connection(SocketType clientSocket, this->m_logsMutex.lock(); AkLogDebug() << "Send message:" << std::endl; + AkLogDebug() << " Client ID: " << clientId << std::endl; AkLogDebug() << " Message ID: " << stringFromMessageId(outMessage.id()) << std::endl; AkLogDebug() << " Query ID: " << outMessage.queryId() << std::endl; AkLogDebug() << " Data size: " << outMessage.data().size() << std::endl; @@ -273,6 +283,8 @@ void AkVCam::MessageServerPrivate::connection(SocketType clientSocket, } Sockets::closeSocket(clientSocket); + this->m_logsMutex.lock(); AkLogDebug() << "Client disconnected: " << clientId << std::endl; + this->m_logsMutex.unlock(); AKVCAM_EMIT(self, ConnectionClosed, clientId) } diff --git a/VCamUtils/src/servicemsg.h b/VCamUtils/src/servicemsg.h index 7d9d92e..06849db 100644 --- a/VCamUtils/src/servicemsg.h +++ b/VCamUtils/src/servicemsg.h @@ -31,16 +31,4 @@ #define AKVCAM_SERVICE_MSG_BROADCAST 0x201 #define AKVCAM_SERVICE_MSG_LISTEN 0x202 -// Hit messages for updating the cameras in the client side -#define AKVCAM_SERVICE_MSG_UPDATE_DEVICES 0x301 -#define AKVCAM_SERVICE_MSG_DEVICES_UPDATED 0x302 - -// Hit messages for updating the camera controls in the client side -#define AKVCAM_SERVICE_MSG_UPDATE_CONTROLS 0x401 -#define AKVCAM_SERVICE_MSG_CONTROLS_UPDATED 0x402 - -// Hit messages for updating the default picture in the client side -#define AKVCAM_SERVICE_MSG_UPDATE_PICTURE 0x501 -#define AKVCAM_SERVICE_MSG_PICTURE_UPDATED 0x502 - #endif // SERVICEMSG_H diff --git a/VCamUtils/src/timer.cpp b/VCamUtils/src/timer.cpp index e5fb302..7161e48 100644 --- a/VCamUtils/src/timer.cpp +++ b/VCamUtils/src/timer.cpp @@ -45,6 +45,8 @@ AkVCam::Timer::Timer() AkVCam::Timer::~Timer() { + AkLogFunction(); + this->stop(); delete this->d; } @@ -66,6 +68,8 @@ void AkVCam::Timer::setInterval(int msec) void AkVCam::Timer::start() { + AkLogFunction(); + this->stop(); this->d->m_running = true; this->d->m_singleShot = false; @@ -74,6 +78,8 @@ void AkVCam::Timer::start() void AkVCam::Timer::stop() { + AkLogFunction(); + if (!this->d->m_running) return; @@ -83,6 +89,8 @@ void AkVCam::Timer::stop() void AkVCam::Timer::singleShot() { + AkLogFunction(); + this->stop(); this->d->m_running = true; this->d->m_singleShot = true; @@ -91,6 +99,8 @@ void AkVCam::Timer::singleShot() void AkVCam::Timer::singleShot(int msec) { + AkLogFunction(); + this->stop(); this->d->m_running = true; this->d->m_singleShot = true; diff --git a/VCamUtils/src/utils.cpp b/VCamUtils/src/utils.cpp index e0469be..6312d5e 100644 --- a/VCamUtils/src/utils.cpp +++ b/VCamUtils/src/utils.cpp @@ -188,12 +188,12 @@ void AkVCam::move(const std::string &from, const std::string &to) std::ifstream infile(from, std::ios::in | std::ios::binary); std::ofstream outfile(to, std::ios::out | std::ios::binary); outfile << infile.rdbuf(); - std::remove(from.c_str()); + ::remove(from.c_str()); } std::string AkVCam::stringFromMessageId(uint32_t messageId) { - struct + static const struct { uint32_t id; const char *str; @@ -203,22 +203,14 @@ std::string AkVCam::stringFromMessageId(uint32_t messageId) {AKVCAM_SERVICE_MSG_FRAME_READY , "FRAME" }, {AKVCAM_SERVICE_MSG_BROADCAST , "BROADCAST" }, {AKVCAM_SERVICE_MSG_LISTEN , "LISTEN" }, - {AKVCAM_SERVICE_MSG_UPDATE_DEVICES , "UPDATE_DEVICES" }, - {AKVCAM_SERVICE_MSG_DEVICES_UPDATED , "DEVICES_UPDATED" }, - {AKVCAM_SERVICE_MSG_UPDATE_CONTROLS , "UPDATE_CONTROLS" }, - {AKVCAM_SERVICE_MSG_CONTROLS_UPDATED, "CONTROLS_UPDATED"}, - {AKVCAM_SERVICE_MSG_UPDATE_PICTURE , "UPDATE_PICTURE" }, - {AKVCAM_SERVICE_MSG_PICTURE_UPDATED , "PICTURE_UPDATED" }, {0 , nullptr }, }; - auto msg = vcamUtilsClsidToString; - - for (; msg->id; ++msg) + for (auto msg = vcamUtilsClsidToString; msg->id; ++msg) if (msg->id == messageId) return {msg->str}; - return "AKVCAM_SERVICE_MSG_(" + std::to_string(msg->id) + ")"; + return "AKVCAM_SERVICE_MSG_(" + std::to_string(messageId) + ")"; } bool AkVCam::endsWith(const std::string &str, const std::string &sub) diff --git a/VCamUtils/src/videoframe.cpp b/VCamUtils/src/videoframe.cpp index 926b175..1f374e3 100644 --- a/VCamUtils/src/videoframe.cpp +++ b/VCamUtils/src/videoframe.cpp @@ -335,19 +335,30 @@ AkVCam::VideoFrame::~VideoFrame() // http://www.dragonwins.com/domains/getteched/bmp/bmpfileformat.htm bool AkVCam::VideoFrame::load(const std::string &fileName) { - if (fileName.empty()) + AkLogFunction(); + + if (fileName.empty()) { + AkLogCritical() << "The file name is empty" << std::endl; + return false; + } std::ifstream stream(fileName); - if (!stream.is_open()) + if (!stream.is_open()) { + AkLogCritical() << "Failed to open the file" << std::endl; + return false; + } char type[2]; stream.read(type, 2); - if (memcmp(type, "BM", 2) != 0) + if (memcmp(type, "BM", 2) != 0) { + AkLogCritical() << "The file does not have the BMP signature" << std::endl; + return false; + } BmpHeader header {}; stream.read(reinterpret_cast(&header), sizeof(BmpHeader)); @@ -358,8 +369,11 @@ bool AkVCam::VideoFrame::load(const std::string &fileName) int(imageHeader.width), int(imageHeader.height)); - if (format.size() < 1) + if (format.size() < 1) { + AkLogCritical() << "The image size is empty: " << imageHeader.width << "x" << imageHeader.height << std::endl; + return false; + } stream.seekg(header.offBits, std::ios_base::beg); this->d->m_format = format; @@ -369,6 +383,13 @@ bool AkVCam::VideoFrame::load(const std::string &fileName) stream.read(reinterpret_cast(data.data()), imageHeader.sizeImage); + AkLogDebug() << "BMP info:" << std::endl; + AkLogDebug() << " Bits: " << imageHeader.bitCount << std::endl; + AkLogDebug() << " width: " << imageHeader.width << std::endl; + AkLogDebug() << " height: " << imageHeader.height << std::endl; + AkLogDebug() << " Data size: " << imageHeader.sizeImage << std::endl; + AkLogDebug() << "Allocated frame size: " << this->d->m_data.size() << std::endl; + switch (imageHeader.bitCount) { case 24: { VideoFormat bmpFormat(PixelFormatBGR24, @@ -413,6 +434,8 @@ bool AkVCam::VideoFrame::load(const std::string &fileName) } default: + AkLogCritical() << "Invalid bit cout: " << imageHeader.bitCount << std::endl; + this->d->m_format.clear(); this->d->m_data.clear(); diff --git a/cmio/PlatformUtils/src/utils.cpp b/cmio/PlatformUtils/src/utils.cpp index 5006508..d873f0b 100644 --- a/cmio/PlatformUtils/src/utils.cpp +++ b/cmio/PlatformUtils/src/utils.cpp @@ -411,10 +411,20 @@ std::string AkVCam::currentBinaryPath() bool AkVCam::isServiceRunning() { + AkLogFunction(); auto service = locateServicePath(); + AkLogDebug() << "Service path: " << service << std::endl; + AkLogDebug() << "System processes:" << std::endl; for (auto &pid: systemProcesses()) { - if (exePath(pid) == service) + auto path = exePath(pid); + + if (path.empty()) + continue; + + AkLogDebug() << " " << path << std::endl; + + if (path == service) return true; } diff --git a/cmio/VCamIPC/CMakeLists.txt b/cmio/VCamIPC/CMakeLists.txt index 5c0e652..3afda8f 100644 --- a/cmio/VCamIPC/CMakeLists.txt +++ b/cmio/VCamIPC/CMakeLists.txt @@ -19,6 +19,7 @@ cmake_minimum_required(VERSION 3.14) project(VCamIPC_cmio LANGUAGES CXX) +project(VCamIPC_cmio_shared LANGUAGES CXX) include(../../commons.cmake) @@ -31,26 +32,43 @@ set(SOURCES if (APPLE OR FAKE_APPLE) add_library(VCamIPC_cmio STATIC ${SOURCES}) + add_library(VCamIPC_cmio_shared SHARED ${SOURCES}) + set_target_properties(VCamIPC_cmio_shared PROPERTIES + OUTPUT_NAME ${AKVCAM_BRIDGE_NAME} + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${BUILDDIR}/${LIBDIR} + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${BUILDDIR}/${BINDIR} + PREFIX "") else () add_library(VCamIPC_cmio STATIC EXCLUDE_FROM_ALL ${SOURCES}) + add_library(VCamIPC_cmio_shared SHARED EXCLUDE_FROM_ALL ${SOURCES}) endif () add_dependencies(VCamIPC_cmio VCamUtils) +add_dependencies(VCamIPC_cmio_shared VCamUtils) if (APPLE) add_dependencies(VCamIPC_cmio PlatformUtilsObjC_cmio) + add_dependencies(VCamIPC_cmio_shared PlatformUtilsObjC_cmio) endif () target_compile_definitions(VCamIPC_cmio PRIVATE VCAMIPC_LIBRARY) +target_compile_definitions(VCamIPC_cmio_shared PRIVATE VCAMIPC_LIBRARY_SHARED) target_include_directories(VCamIPC_cmio PRIVATE .. ../..) +target_include_directories(VCamIPC_cmio_shared + PRIVATE + .. + ../..) if (FAKE_APPLE) target_include_directories(VCamIPC_cmio PRIVATE ../FakeAPI) + target_include_directories(VCamIPC_cmio_shared + PRIVATE + ../FakeAPI) endif () if (APPLE OR FAKE_APPLE) @@ -68,7 +86,16 @@ target_link_libraries(VCamIPC_cmio VCamUtils ${EXTRA_LIBS} ${EXTRA_OBJC}) +target_link_libraries(VCamIPC_cmio_shared + VCamUtils + ${EXTRA_LIBS} + ${EXTRA_OBJC}) if (FAKE_APPLE) add_definitions(-DFAKE_APPLE) +endif () + add_definitions(-DFAKE_APPLE) + +if (APPLE OR FAKE_APPLE) + install(TARGETS VCamIPC_cmio_shared DESTINATION ${LIBDIR}) endif () diff --git a/cmio/VCamIPC/src/ipcbridge.cpp b/cmio/VCamIPC/src/ipcbridge.cpp index 0eb5334..3ac36e4 100644 --- a/cmio/VCamIPC/src/ipcbridge.cpp +++ b/cmio/VCamIPC/src/ipcbridge.cpp @@ -62,32 +62,6 @@ namespace AkVCam Hack &operator =(const Hack &other); }; - struct Slot - { - std::future messageFuture; - bool run {false}; - - Slot() - { - } - - Slot(std::future &messageFuture) - { - } - - Slot(const Slot &other) - { - - } - - Slot &operator =(const Slot &other) - { - UNUSED(other); - - return *this; - } - }; - struct BroadcastSlot { IpcBridge::StreamType type; @@ -125,24 +99,23 @@ namespace AkVCam IpcBridge *self; MessageClient m_messageClient; std::map m_broadcasts; - std::mutex m_broadcastsMutex; - std::map m_messageSlots; + std::map> m_controlValues; std::vector m_devices; std::string m_picture; + std::mutex m_broadcastsMutex; + std::mutex m_statusMutex; + Timer m_messagesTimer; explicit IpcBridgePrivate(IpcBridge *self); ~IpcBridgePrivate(); bool launchService(); - void connectDeviceControlsMessages(); inline const std::vector &controls() const; // Message handling methods - bool devicesUpdated(const Message &message); - bool pictureUpdated(const Message &message); - bool controlsUpdated(const Message &message); bool frameRequired(const std::string &deviceId, Message &message); bool frameReady(const Message &message); + static void checkStatus(void *userData); // Utility methods bool isRoot() const; @@ -160,19 +133,19 @@ AkVCam::IpcBridge::IpcBridge() { AkLogFunction(); this->d = new IpcBridgePrivate(this); - auto loglevel = AkVCam::Preferences::logLevel(); - AkVCam::Logger::setLogLevel(loglevel); } AkVCam::IpcBridge::~IpcBridge() { + AkLogFunction(); + AkLogDebug() << "Stopping the devices:" << std::endl; + for (auto &device: this->devices()) this->deviceStop(device); - for (auto &slot: this->d->m_messageSlots) { - slot.second.run = false; - slot.second.messageFuture.wait(); - } + this->d->m_messagesTimer.stop(); + + AkLogDebug() << "Bridge Destroyed" << std::endl; delete this->d; } @@ -185,12 +158,7 @@ std::string AkVCam::IpcBridge::picture() const void AkVCam::IpcBridge::setPicture(const std::string &picture) { AkLogFunction(); - - if (picture == Preferences::picture()) - return; - Preferences::setPicture(picture); - this->d->m_messageClient.send(MsgUpdatePicture(picture).toMessage()); } int AkVCam::IpcBridge::logLevel() const @@ -215,6 +183,12 @@ std::string AkVCam::IpcBridge::logPath(const std::string &logName) const return AkVCam::Preferences::readString("logfile", defaultLogFile); } +void AkVCam::IpcBridge::stopNotifications() +{ + AkLogFunction(); + this->d->m_messagesTimer.stop(); +} + std::vector AkVCam::IpcBridge::devices() const { AkLogFunction(); @@ -321,8 +295,6 @@ void AkVCam::IpcBridge::setControls(const std::string &deviceId, if (cameraIndex < 0) return; - bool updated = false; - for (auto &control: this->d->controls()) { auto oldValue = Preferences::cameraControlValue(size_t(cameraIndex), @@ -331,19 +303,12 @@ void AkVCam::IpcBridge::setControls(const std::string &deviceId, if (controls.count(control.id)) { auto newValue = controls.at(control.id); - if (newValue != oldValue) { + if (newValue != oldValue) Preferences::cameraSetControlValue(size_t(cameraIndex), control.id, newValue); - updated = true; - } } } - - if (!updated) - return; - - this->d->m_messageClient.send(MsgUpdateControls(deviceId).toMessage()); } std::vector AkVCam::IpcBridge::clientsPids() const @@ -410,9 +375,7 @@ void AkVCam::IpcBridge::removeFormat(const std::string &deviceId, int index) void AkVCam::IpcBridge::updateDevices() { AkLogFunction(); - - this->d->m_messageClient.send(MsgUpdateDevices().toMessage()); - } +} bool AkVCam::IpcBridge::deviceStart(StreamType type, const std::string &deviceId) @@ -446,7 +409,7 @@ bool AkVCam::IpcBridge::deviceStart(StreamType type, std::placeholders::_1)); } - this->d->m_broadcastsMutex.lock(); + this->d->m_broadcastsMutex.unlock(); return true; } @@ -478,9 +441,12 @@ bool AkVCam::IpcBridge::write(const std::string &deviceId, this->d->m_broadcastsMutex.lock(); - if (this->d->m_broadcasts.count(deviceId) < 1) + if (this->d->m_broadcasts.count(deviceId) < 1) { this->d->m_broadcastsMutex.unlock(); + return false; + } + auto &slot = this->d->m_broadcasts[deviceId]; if (slot.type != StreamType_Input) { @@ -578,21 +544,18 @@ int AkVCam::IpcBridge::execHack(const std::string &hack, AkVCam::IpcBridgePrivate::IpcBridgePrivate(IpcBridge *self): self(self) { + AkLogFunction(); + + auto loglevel = AkVCam::Preferences::logLevel(); + AkVCam::Logger::setLogLevel(loglevel); + if (!this->launchService()) AkLogWarning() << "There was not possible to communicate with the server consider increasing the timeout." << std::endl; this->m_messageClient.setPort(Preferences::servicePort()); - - this->m_messageSlots[AKVCAM_SERVICE_MSG_DEVICES_UPDATED] = {}; - this->m_messageSlots[AKVCAM_SERVICE_MSG_DEVICES_UPDATED].run = true; - this->m_messageSlots[AKVCAM_SERVICE_MSG_DEVICES_UPDATED].messageFuture = - this->m_messageClient.send(MsgDevicesUpdated().toMessage(), AKVCAM_BIND_FUNC(IpcBridgePrivate::devicesUpdated)); - this->m_messageSlots[AKVCAM_SERVICE_MSG_PICTURE_UPDATED] = {}; - this->m_messageSlots[AKVCAM_SERVICE_MSG_PICTURE_UPDATED].run = true; - this->m_messageSlots[AKVCAM_SERVICE_MSG_PICTURE_UPDATED].messageFuture = - this->m_messageClient.send(MsgPictureUpdated().toMessage(), AKVCAM_BIND_FUNC(IpcBridgePrivate::pictureUpdated)); - - this->connectDeviceControlsMessages(); + this->m_messagesTimer.connectTimeout(this, &IpcBridgePrivate::checkStatus); + this->m_messagesTimer.setInterval(1000); + this->m_messagesTimer.start(); } AkVCam::IpcBridgePrivate::~IpcBridgePrivate() @@ -601,20 +564,21 @@ AkVCam::IpcBridgePrivate::~IpcBridgePrivate() bool AkVCam::IpcBridgePrivate::launchService() { - if (!isServiceRunning()) { + AkLogFunction(); + + if (!isServicePortUp()) { AkLogDebug() << "Launching the service" << std::endl; char cmd[4096]; - snprintf(cmd, 4096, "'%s' &", locateServicePath().c_str()); + snprintf(cmd, 4096, "start /b \"\" \"%s\"", locateServicePath().c_str()); system(cmd); } bool ok = false; auto timeout = Preferences::serviceTimeout(); + AkLogDebug() << "Service check Timeout:" << timeout << std::endl; for (int i = 0; i < timeout; ++i) { - ok = isServicePortUp() && isServiceRunning(); - - if (ok) + if (isServicePortUp()) break; std::this_thread::sleep_for(std::chrono::seconds(1));; @@ -623,34 +587,6 @@ bool AkVCam::IpcBridgePrivate::launchService() return ok; } -void AkVCam::IpcBridgePrivate::connectDeviceControlsMessages() -{ - // Remove the old message listeners - std::vector keys; - - for (auto &slot: this->m_messageSlots) - if ((slot.first & 0xffff) == AKVCAM_SERVICE_MSG_CONTROLS_UPDATED) { - slot.second.run = false; - slot.second.messageFuture.wait(); - keys.push_back(slot.first); - } - - for (auto &key: keys) - this->m_messageSlots.erase(key); - - // Add the new ones - int i = 0; - - for (auto &device: self->devices()) { - auto key = (i << 16) | AKVCAM_SERVICE_MSG_CONTROLS_UPDATED; - this->m_messageSlots[key] = {}; - this->m_messageSlots[key].run = true; - this->m_messageSlots[key].messageFuture = - this->m_messageClient.send(MsgControlsUpdated(device).toMessage(), AKVCAM_BIND_FUNC(IpcBridgePrivate::controlsUpdated)); - ++i; - } -} - const std::vector &AkVCam::IpcBridgePrivate::controls() const { static const std::vector scalingMenu { @@ -676,60 +612,6 @@ const std::vector &AkVCam::IpcBridgePrivate::controls() c return controls; } -bool AkVCam::IpcBridgePrivate::devicesUpdated(const Message &message) -{ - UNUSED(message); - AkLogFunction(); - std::vector devices; - auto nCameras = Preferences::camerasCount(); - - for (size_t i = 0; i < nCameras; i++) - devices.push_back(Preferences::cameraId(i)); - - if (this->m_devices != devices) { - this->m_devices = devices; - AKVCAM_EMIT(this->self, DevicesChanged, devices) - } - - return this->m_messageSlots[AKVCAM_SERVICE_MSG_DEVICES_UPDATED].run; -} - -bool AkVCam::IpcBridgePrivate::pictureUpdated(const Message &message) -{ - AkLogFunction(); - auto picture = MsgPictureUpdated(message).picture(); - - if (this->m_picture != picture) { - this->m_picture = picture; - AKVCAM_EMIT(this->self, PictureChanged, picture) - } - - return this->m_messageSlots[AKVCAM_SERVICE_MSG_PICTURE_UPDATED].run; -} - -bool AkVCam::IpcBridgePrivate::controlsUpdated(const Message &message) -{ - AkLogFunction(); - auto deviceId = MsgControlsUpdated(message).device(); - auto cameraIndex = Preferences::cameraFromId(deviceId); - - if (cameraIndex < 0) - return false; - - std::map controls; - - for (auto &control: this->controls()) { - controls[control.id] = - Preferences::cameraControlValue(size_t(cameraIndex), control.id); - AkLogDebug() << control.id << ": " << controls[control.id] << std::endl; - } - - if (!deviceId.empty() && !controls.empty()) - AKVCAM_EMIT(this->self, ControlsChanged, deviceId, controls) - - return this->m_messageSlots[AKVCAM_SERVICE_MSG_CONTROLS_UPDATED].run; -} - bool AkVCam::IpcBridgePrivate::frameRequired(const std::string &deviceId, Message &message) { @@ -791,6 +673,52 @@ bool AkVCam::IpcBridgePrivate::frameReady(const Message &message) return run; } +void AkVCam::IpcBridgePrivate::checkStatus(void *userData) +{ + AkLogFunction(); + auto self = reinterpret_cast(userData); + self->m_statusMutex.lock(); + auto devices = self->self->devices(); + + if (devices != self->m_devices) { + self->m_devices = devices; + AKVCAM_EMIT(self->self, DevicesChanged, devices) + } + + auto picture = self->self->picture(); + + if (picture != self->m_picture) { + self->m_picture = picture; + AKVCAM_EMIT(self->self, PictureChanged, picture) + } + + std::vector removeDevices; + + for (auto &device: self->m_controlValues) + if (std::count(devices.begin(), devices.begin(), device.first) < 1) + removeDevices.push_back(device.first); + + for (auto &device: removeDevices) + self->m_controlValues.erase(device); + + for (auto &device: devices) { + std::map controlValues; + + for (auto &control: self->self->controls(device)) + controlValues[control.id] = control.value; + + if (self->m_controlValues.count(device) < 1) + self->m_controlValues[device] = {}; + + if (controlValues != self->m_controlValues[device]) { + self->m_controlValues[device] = controlValues; + AKVCAM_EMIT(self->self, ControlsChanged, device, controlValues) + } + } + + self->m_statusMutex.unlock(); +} + bool AkVCam::IpcBridgePrivate::isRoot() const { AkLogFunction(); @@ -946,3 +874,10 @@ AkVCam::Hack &AkVCam::Hack::operator =(const Hack &other) return *this; } + +#ifdef VCAMIPC_LIBRARY_SHARED +extern "C" AkVCam::IpcBridgePtr akCreateBridge() +{ + return std::make_shared(); +} +#endif diff --git a/cmio/VirtualCamera/src/device.cpp b/cmio/VirtualCamera/src/device.cpp index 0df3af1..b6adeb5 100644 --- a/cmio/VirtualCamera/src/device.cpp +++ b/cmio/VirtualCamera/src/device.cpp @@ -103,6 +103,7 @@ AkVCam::StreamPtr AkVCam::Device::addStream() { AkLogFunction(); auto stream = StreamPtr(new Stream(false, this)); + stream->setDevice(this); if (stream->createObject() == kCMIOHardwareNoError) { this->m_streams[stream->objectID()] = stream; diff --git a/cmio/VirtualCamera/src/plugininterface.cpp b/cmio/VirtualCamera/src/plugininterface.cpp index 1e7fa5c..9e80e95 100644 --- a/cmio/VirtualCamera/src/plugininterface.cpp +++ b/cmio/VirtualCamera/src/plugininterface.cpp @@ -39,7 +39,7 @@ namespace AkVCam PluginInterface *self; ULONG m_ref; ULONG m_reserved; - IpcBridge m_ipcBridge; + IpcBridgePtr m_ipcBridge; void updateDevices(); static HRESULT QueryInterface(void *self, @@ -136,6 +136,7 @@ AkVCam::PluginInterface::PluginInterface(): this->m_className = "PluginInterface"; this->d = new PluginInterfacePrivate; this->d->self = this; + this->d->m_ipcBridge = std::make_shared(); this->d->pluginInterface = new CMIOHardwarePlugInInterface { // Padding for COM NULL, @@ -170,14 +171,15 @@ AkVCam::PluginInterface::PluginInterface(): this->d->m_ref = 0; this->d->m_reserved = 0; - this->d->m_ipcBridge.connectDevicesChanged(this, &PluginInterface::devicesChanged); - this->d->m_ipcBridge.connectFrameReady(this, &PluginInterface::frameReady); - this->d->m_ipcBridge.connectPictureChanged(this, &PluginInterface::pictureChanged); - this->d->m_ipcBridge.connectControlsChanged(this, &PluginInterface::controlsChanged); + this->d->m_ipcBridge->connectDevicesChanged(this, &PluginInterface::devicesChanged); + this->d->m_ipcBridge->connectFrameReady(this, &PluginInterface::frameReady); + this->d->m_ipcBridge->connectPictureChanged(this, &PluginInterface::pictureChanged); + this->d->m_ipcBridge->connectControlsChanged(this, &PluginInterface::controlsChanged); } AkVCam::PluginInterface::~PluginInterface() { + this->d->m_ipcBridge->stopNotifications(); delete this->d->pluginInterface; delete this->d; } @@ -238,9 +240,9 @@ OSStatus AkVCam::PluginInterface::InitializeWithObjectID(CMIOObjectID objectID) AkLogInfo() << objectID << std::endl; this->m_objectID = objectID; - for (auto &deviceId: this->d->m_ipcBridge.devices()) { - auto description = this->d->m_ipcBridge.description(deviceId); - auto formats = this->d->m_ipcBridge.formats(deviceId); + for (auto &deviceId: this->d->m_ipcBridge->devices()) { + auto description = this->d->m_ipcBridge->description(deviceId); + auto formats = this->d->m_ipcBridge->formats(deviceId); this->createDevice(deviceId, description, formats); } @@ -284,9 +286,9 @@ void AkVCam::PluginInterface::devicesChanged(void *userData, for (auto &deviceId: oldDevices) self->destroyDevice(deviceId); - for (auto &deviceId: self->d->m_ipcBridge.devices()) { - auto description = self->d->m_ipcBridge.description(deviceId); - auto formats = self->d->m_ipcBridge.formats(deviceId); + for (auto &deviceId: self->d->m_ipcBridge->devices()) { + auto description = self->d->m_ipcBridge->description(deviceId); + auto formats = self->d->m_ipcBridge->formats(deviceId); self->createDevice(deviceId, description, formats); } } @@ -399,7 +401,7 @@ bool AkVCam::PluginInterface::createDevice(const std::string &deviceId, if (!stream) goto createDevice_failed; - stream->setBridge(&this->d->m_ipcBridge); + stream->setBridge(this->d->m_ipcBridge); stream->setFormats(formats); stream->properties().setProperty(kCMIOStreamPropertyDirection, 0); diff --git a/cmio/VirtualCamera/src/stream.cpp b/cmio/VirtualCamera/src/stream.cpp index d99c1e7..2c7f5b6 100644 --- a/cmio/VirtualCamera/src/stream.cpp +++ b/cmio/VirtualCamera/src/stream.cpp @@ -27,6 +27,7 @@ #include "stream.h" #include "clock.h" +#include "device.h" #include "PlatformUtils/src/preferences.h" #include "PlatformUtils/src/utils.h" #include "VCamUtils/src/videoformat.h" @@ -39,7 +40,8 @@ namespace AkVCam { public: Stream *self; - IpcBridge *m_bridge {nullptr}; + IpcBridgePtr m_bridge; + Device *m_device {nullptr}; ClockPtr m_clock; UInt64 m_sequence; CMTime m_pts; @@ -157,6 +159,16 @@ OSStatus AkVCam::Stream::registerObject(bool regist) return status; } +AkVCam::Device *AkVCam::Stream::device() const +{ + return this->d->m_device; +} + +void AkVCam::Stream::setDevice(Device *device) +{ + this->d->m_device = device; +} + void AkVCam::Stream::setPicture(const std::string &picture) { AkLogFunction(); @@ -166,7 +178,7 @@ void AkVCam::Stream::setPicture(const std::string &picture) this->d->m_mutex.unlock(); } -void AkVCam::Stream::setBridge(IpcBridge *bridge) +void AkVCam::Stream::setBridge(IpcBridgePtr bridge) { this->d->m_bridge = bridge; } @@ -240,6 +252,10 @@ bool AkVCam::Stream::start() this->d->m_running = this->d->startTimer(); AkLogInfo() << "Running: " << this->d->m_running << std::endl; + if (this->d->m_running && this->d->m_bridge) + this->d->m_bridge->deviceStart(IpcBridge::StreamType_Input, + this->d->m_device->deviceId()); + return this->d->m_running; } @@ -250,6 +266,9 @@ void AkVCam::Stream::stop() if (!this->d->m_running) return; + if (this->d->m_running && this->d->m_bridge) + this->d->m_bridge->deviceStop(this->d->m_device->deviceId()); + this->d->m_running = false; this->d->stopTimer(); this->d->m_currentFrame.clear(); diff --git a/cmio/VirtualCamera/src/stream.h b/cmio/VirtualCamera/src/stream.h index 5d57622..5878e6a 100644 --- a/cmio/VirtualCamera/src/stream.h +++ b/cmio/VirtualCamera/src/stream.h @@ -29,11 +29,12 @@ namespace AkVCam { class StreamPrivate; + class Device; class Stream; class VideoFrame; - typedef std::shared_ptr StreamPtr; - typedef Queue SampleBufferQueue; - typedef QueuePtr SampleBufferQueuePtr; + using StreamPtr = std::shared_ptr; + using SampleBufferQueue = Queue; + using SampleBufferQueuePtr = QueuePtr; class Stream: public Object { @@ -44,7 +45,9 @@ namespace AkVCam OSStatus createObject(); OSStatus registerObject(bool regist=true); - void setBridge(IpcBridge *bridge); + Device *device() const; + void setDevice(Device *device); + void setBridge(IpcBridgePtr bridge); void setFormats(const std::vector &formats); void setFormat(const VideoFormat &format); void setFrameRate(const Fraction &frameRate); diff --git a/commons.cmake b/commons.cmake index ce48805..b60cf35 100644 --- a/commons.cmake +++ b/commons.cmake @@ -49,6 +49,7 @@ add_definitions(-DCOMMONS_APPNAME="${COMMONS_APPNAME}" set(AKVCAM_PLUGIN_NAME AkVirtualCamera) set(AKVCAM_SERVICE_NAME AkVCamAssistant) set(AKVCAM_MANAGER_NAME AkVCamManager) +set(AKVCAM_BRIDGE_NAME AkVCamBridge) set(AKVCAM_DEVICE_PREFIX AkVCamVideoDevice) set(AKVCAM_SERVICEPORT "8226" CACHE STRING "Virtual camera service port") diff --git a/dshow/PlatformUtils/src/utils.cpp b/dshow/PlatformUtils/src/utils.cpp index 97a4e8c..55ed451 100644 --- a/dshow/PlatformUtils/src/utils.cpp +++ b/dshow/PlatformUtils/src/utils.cpp @@ -63,6 +63,8 @@ bool operator <(const CLSID &a, const CLSID &b) std::string AkVCam::locateManagerPath() { + AkLogFunction(); + auto file = pluginInstallPath() + "\\" + currentArchitecture() + "\\" AKVCAM_MANAGER_NAME ".exe"; @@ -76,6 +78,8 @@ std::string AkVCam::locateManagerPath() std::string AkVCam::locateServicePath() { + AkLogFunction(); + auto file = pluginInstallPath() + "\\" + currentArchitecture() + "\\" AKVCAM_SERVICE_NAME ".exe"; @@ -87,6 +91,8 @@ std::string AkVCam::locateServicePath() std::string AkVCam::locatePluginPath() { + AkLogFunction(); + auto file = pluginInstallPath() + "\\" + currentArchitecture() + "\\" AKVCAM_PLUGIN_NAME ".dll"; @@ -1031,10 +1037,14 @@ AkVCam::VideoFrame AkVCam::loadPicture(const std::string &fileName) AkLogFunction(); VideoFrame frame; + AkLogInfo() << "Loading picture: " << fileName << std::endl; + if (frame.load(fileName)) { - AkLogInfo() << "Picture loaded as BMP" << std::endl; + AkLogDebug() << "Picture loaded as BMP" << std::endl; return frame; + } else { + frame = {}; } IWICImagingFactory *imagingFactory = nullptr; @@ -1286,17 +1296,30 @@ std::string AkVCam::currentBinaryPath() bool AkVCam::isServiceRunning() { + AkLogFunction(); auto service = locateServicePath(); + AkLogDebug() << "Service path: " << service << std::endl; + AkLogDebug() << "System processes:" << std::endl; + + for (auto &pid: systemProcesses()) { + auto path = exePath(pid); + + if (path.empty()) + continue; + + AkLogDebug() << " " << path << std::endl; - for (auto &pid: systemProcesses()) - if (exePath(pid) == service) + if (path == service) return true; + } return false; } bool AkVCam::isServicePortUp() { + AkLogFunction(); + return MessageClient::isUp(Preferences::servicePort()); } diff --git a/dshow/VCamIPC/CMakeLists.txt b/dshow/VCamIPC/CMakeLists.txt index 328d8e9..332a30a 100644 --- a/dshow/VCamIPC/CMakeLists.txt +++ b/dshow/VCamIPC/CMakeLists.txt @@ -19,6 +19,7 @@ cmake_minimum_required(VERSION 3.14) project(VCamIPC_dshow LANGUAGES CXX) +project(VCamIPC_dshow_shared LANGUAGES CXX) include(../../commons.cmake) @@ -31,15 +32,27 @@ set(SOURCES if (WIN32) add_library(VCamIPC_dshow STATIC ${SOURCES}) + add_library(VCamIPC_dshow_shared SHARED ${SOURCES}) + set_target_properties(VCamIPC_dshow_shared PROPERTIES + OUTPUT_NAME ${AKVCAM_BRIDGE_NAME} + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${BUILDDIR}/${LIBDIR} + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${BUILDDIR}/${BINDIR} + PREFIX "") else () add_library(VCamIPC_dshow STATIC EXCLUDE_FROM_ALL ${SOURCES}) + add_library(VCamIPC_dshow_shared SHARED EXCLUDE_FROM_ALL ${SOURCES}) endif () add_dependencies(VCamIPC_dshow PlatformUtils_dshow VCamUtils) +add_dependencies(VCamIPC_dshow_shared PlatformUtils_dshow VCamUtils) target_compile_definitions(VCamIPC_dshow PRIVATE VCAMIPC_LIBRARY) +target_compile_definitions(VCamIPC_dshow_shared PRIVATE VCAMIPC_LIBRARY_SHARED) target_include_directories(VCamIPC_dshow PRIVATE .. PRIVATE ../..) +target_include_directories(VCamIPC_dshow_shared + PRIVATE .. + PRIVATE ../..) if (WIN32) set(EXTRA_LIBS @@ -48,6 +61,9 @@ if (WIN32) psapi) endif () -target_link_libraries(VCamIPC_dshow - PlatformUtils_dshow - ${EXTRA_LIBS}) +target_link_libraries(VCamIPC_dshow PlatformUtils_dshow ${EXTRA_LIBS}) +target_link_libraries(VCamIPC_dshow_shared PlatformUtils_dshow ${EXTRA_LIBS}) + +if (WIN32) + install(TARGETS VCamIPC_dshow_shared DESTINATION ${BINDIR}) +endif () diff --git a/dshow/VCamIPC/src/ipcbridge.cpp b/dshow/VCamIPC/src/ipcbridge.cpp index 867c174..470cf94 100644 --- a/dshow/VCamIPC/src/ipcbridge.cpp +++ b/dshow/VCamIPC/src/ipcbridge.cpp @@ -29,6 +29,7 @@ #include "VCamUtils/src/message.h" #include "VCamUtils/src/messageclient.h" #include "VCamUtils/src/servicemsg.h" +#include "VCamUtils/src/timer.h" #include "VCamUtils/src/utils.h" #include "VCamUtils/src/videoformat.h" #include "VCamUtils/src/videoframe.h" @@ -64,32 +65,6 @@ namespace AkVCam Hack &operator =(const Hack &other); }; - struct Slot - { - std::future messageFuture; - bool run {false}; - - Slot() - { - } - - Slot(std::future &messageFuture) - { - } - - Slot(const Slot &other) - { - - } - - Slot &operator =(const Slot &other) - { - UNUSED(other); - - return *this; - } - }; - struct BroadcastSlot { IpcBridge::StreamType type; @@ -127,24 +102,23 @@ namespace AkVCam IpcBridge *self; MessageClient m_messageClient; std::map m_broadcasts; - std::mutex m_broadcastsMutex; - std::map m_messageSlots; + std::map> m_controlValues; std::vector m_devices; std::string m_picture; + std::mutex m_broadcastsMutex; + std::mutex m_statusMutex; + Timer m_messagesTimer; explicit IpcBridgePrivate(IpcBridge *self); ~IpcBridgePrivate(); bool launchService(); - void connectDeviceControlsMessages(); inline const std::vector &controls() const; // Message handling methods - bool devicesUpdated(const Message &message); - bool pictureUpdated(const Message &message); - bool controlsUpdated(const Message &message); bool frameRequired(const std::string &deviceId, Message &message); bool frameReady(const Message &message); + static void checkStatus(void *userData); bool isRoot() const; int exec(const std::vector ¶meters, @@ -160,19 +134,19 @@ AkVCam::IpcBridge::IpcBridge() { AkLogFunction(); this->d = new IpcBridgePrivate(this); - auto loglevel = AkVCam::Preferences::logLevel(); - AkVCam::Logger::setLogLevel(loglevel); } AkVCam::IpcBridge::~IpcBridge() { + AkLogFunction(); + AkLogDebug() << "Stopping the devices:" << std::endl; + for (auto &device: this->devices()) this->deviceStop(device); - for (auto &slot: this->d->m_messageSlots) { - slot.second.run = false; - slot.second.messageFuture.wait(); - } + this->d->m_messagesTimer.stop(); + + AkLogDebug() << "Bridge Destroyed" << std::endl; delete this->d; } @@ -185,12 +159,7 @@ std::string AkVCam::IpcBridge::picture() const void AkVCam::IpcBridge::setPicture(const std::string &picture) { AkLogFunction(); - - if (picture == Preferences::picture()) - return; - Preferences::setPicture(picture); - this->d->m_messageClient.send(MsgUpdatePicture(picture).toMessage()); } int AkVCam::IpcBridge::logLevel() const @@ -215,6 +184,12 @@ std::string AkVCam::IpcBridge::logPath(const std::string &logName) const return AkVCam::Preferences::readString("logfile", defaultLogFile); } +void AkVCam::IpcBridge::stopNotifications() +{ + AkLogFunction(); + this->d->m_messagesTimer.stop(); +} + std::vector AkVCam::IpcBridge::devices() const { AkLogFunction(); @@ -324,8 +299,6 @@ void AkVCam::IpcBridge::setControls(const std::string &deviceId, if (cameraIndex < 0) return; - bool updated = false; - for (auto &control: this->d->controls()) { auto oldValue = Preferences::cameraControlValue(size_t(cameraIndex), @@ -334,19 +307,12 @@ void AkVCam::IpcBridge::setControls(const std::string &deviceId, if (controls.count(control.id)) { auto newValue = controls.at(control.id); - if (newValue != oldValue) { + if (newValue != oldValue) Preferences::cameraSetControlValue(size_t(cameraIndex), control.id, newValue); - updated = true; - } } } - - if (!updated) - return; - - this->d->m_messageClient.send(MsgUpdateControls(deviceId).toMessage()); } std::vector AkVCam::IpcBridge::clientsPids() const @@ -436,8 +402,6 @@ void AkVCam::IpcBridge::updateDevices() AkLogDebug() << "Registering server" << std::endl; auto result = (*registerServer)(); AkLogDebug() << "Server registered with code " << result << std::endl; - this->d->m_messageClient.send(MsgUpdateDevices().toMessage()); - this->d->connectDeviceControlsMessages(); auto lockFileName = tempPath() + "\\akvcam_update.lck"; if (!fileExists(lockFileName)) { @@ -483,7 +447,7 @@ bool AkVCam::IpcBridge::deviceStart(StreamType type, if (type == StreamType_Input) { slot.messageFuture = - this->d->m_messageClient.send([this, &deviceId] (Message &message) -> bool { + this->d->m_messageClient.send([this, deviceId] (Message &message) -> bool { return this->d->frameRequired(deviceId, message); }); } else { @@ -494,7 +458,7 @@ bool AkVCam::IpcBridge::deviceStart(StreamType type, std::placeholders::_1)); } - this->d->m_broadcastsMutex.lock(); + this->d->m_broadcastsMutex.unlock(); return true; } @@ -526,9 +490,12 @@ bool AkVCam::IpcBridge::write(const std::string &deviceId, this->d->m_broadcastsMutex.lock(); - if (this->d->m_broadcasts.count(deviceId) < 1) + if (this->d->m_broadcasts.count(deviceId) < 1) { this->d->m_broadcastsMutex.unlock(); + return false; + } + auto &slot = this->d->m_broadcasts[deviceId]; if (slot.type != StreamType_Input) { @@ -638,30 +605,31 @@ int AkVCam::IpcBridge::execHack(const std::string &hack, AkVCam::IpcBridgePrivate::IpcBridgePrivate(IpcBridge *self): self(self) { + AkLogFunction(); + + auto loglevel = AkVCam::Preferences::logLevel(); + AkVCam::Logger::setLogLevel(loglevel); + if (!this->launchService()) AkLogWarning() << "There was not possible to communicate with the server consider increasing the timeout." << std::endl; this->m_messageClient.setPort(Preferences::servicePort()); - - this->m_messageSlots[AKVCAM_SERVICE_MSG_DEVICES_UPDATED] = {}; - this->m_messageSlots[AKVCAM_SERVICE_MSG_DEVICES_UPDATED].run = true; - this->m_messageSlots[AKVCAM_SERVICE_MSG_DEVICES_UPDATED].messageFuture = - this->m_messageClient.send(MsgDevicesUpdated().toMessage(), AKVCAM_BIND_FUNC(IpcBridgePrivate::devicesUpdated)); - this->m_messageSlots[AKVCAM_SERVICE_MSG_PICTURE_UPDATED] = {}; - this->m_messageSlots[AKVCAM_SERVICE_MSG_PICTURE_UPDATED].run = true; - this->m_messageSlots[AKVCAM_SERVICE_MSG_PICTURE_UPDATED].messageFuture = - this->m_messageClient.send(MsgPictureUpdated().toMessage(), AKVCAM_BIND_FUNC(IpcBridgePrivate::pictureUpdated)); - - this->connectDeviceControlsMessages(); + this->m_messagesTimer.connectTimeout(this, &IpcBridgePrivate::checkStatus); + this->m_messagesTimer.setInterval(1000); + this->m_messagesTimer.start(); } AkVCam::IpcBridgePrivate::~IpcBridgePrivate() { + AkLogFunction(); } bool AkVCam::IpcBridgePrivate::launchService() { - if (!isServiceRunning()) { + AkLogFunction(); + + if (!isServicePortUp()) { + AkLogDebug() << "Launching the service" << std::endl; char cmd[4096]; snprintf(cmd, 4096, "start /b \"\" \"%s\"", locateServicePath().c_str()); system(cmd); @@ -669,11 +637,10 @@ bool AkVCam::IpcBridgePrivate::launchService() bool ok = false; auto timeout = Preferences::serviceTimeout(); + AkLogDebug() << "Service check Timeout:" << timeout << std::endl; for (int i = 0; i < timeout; ++i) { - ok = isServicePortUp() && isServiceRunning(); - - if (ok) + if (isServicePortUp()) break; std::this_thread::sleep_for(std::chrono::seconds(1));; @@ -682,34 +649,6 @@ bool AkVCam::IpcBridgePrivate::launchService() return ok; } -void AkVCam::IpcBridgePrivate::connectDeviceControlsMessages() -{ - // Remove the old message listeners - std::vector keys; - - for (auto &slot: this->m_messageSlots) - if ((slot.first & 0xffff) == AKVCAM_SERVICE_MSG_CONTROLS_UPDATED) { - slot.second.run = false; - slot.second.messageFuture.wait(); - keys.push_back(slot.first); - } - - for (auto &key: keys) - this->m_messageSlots.erase(key); - - // Add the new ones - int i = 0; - - for (auto &device: self->devices()) { - auto key = (i << 16) | AKVCAM_SERVICE_MSG_CONTROLS_UPDATED; - this->m_messageSlots[key] = {}; - this->m_messageSlots[key].run = true; - this->m_messageSlots[key].messageFuture = - this->m_messageClient.send(MsgControlsUpdated(device).toMessage(), AKVCAM_BIND_FUNC(IpcBridgePrivate::controlsUpdated)); - ++i; - } -} - const std::vector &AkVCam::IpcBridgePrivate::controls() const { static const std::vector scalingMenu { @@ -735,60 +674,6 @@ const std::vector &AkVCam::IpcBridgePrivate::controls() c return controls; } -bool AkVCam::IpcBridgePrivate::devicesUpdated(const Message &message) -{ - UNUSED(message); - AkLogFunction(); - std::vector devices; - auto nCameras = Preferences::camerasCount(); - - for (size_t i = 0; i < nCameras; i++) - devices.push_back(Preferences::cameraId(i)); - - if (this->m_devices != devices) { - this->m_devices = devices; - AKVCAM_EMIT(this->self, DevicesChanged, devices) - } - - return this->m_messageSlots[AKVCAM_SERVICE_MSG_DEVICES_UPDATED].run; -} - -bool AkVCam::IpcBridgePrivate::pictureUpdated(const Message &message) -{ - AkLogFunction(); - auto picture = MsgPictureUpdated(message).picture(); - - if (this->m_picture != picture) { - this->m_picture = picture; - AKVCAM_EMIT(this->self, PictureChanged, picture) - } - - return this->m_messageSlots[AKVCAM_SERVICE_MSG_PICTURE_UPDATED].run; -} - -bool AkVCam::IpcBridgePrivate::controlsUpdated(const Message &message) -{ - AkLogFunction(); - auto deviceId = MsgControlsUpdated(message).device(); - auto cameraIndex = Preferences::cameraFromId(deviceId); - - if (cameraIndex < 0) - return false; - - std::map controls; - - for (auto &control: this->controls()) { - controls[control.id] = - Preferences::cameraControlValue(size_t(cameraIndex), control.id); - AkLogDebug() << control.id << ": " << controls[control.id] << std::endl; - } - - if (!deviceId.empty() && !controls.empty()) - AKVCAM_EMIT(this->self, ControlsChanged, deviceId, controls) - - return this->m_messageSlots[AKVCAM_SERVICE_MSG_CONTROLS_UPDATED].run; -} - bool AkVCam::IpcBridgePrivate::frameRequired(const std::string &deviceId, Message &message) { @@ -850,6 +735,52 @@ bool AkVCam::IpcBridgePrivate::frameReady(const Message &message) return run; } +void AkVCam::IpcBridgePrivate::checkStatus(void *userData) +{ + AkLogFunction(); + auto self = reinterpret_cast(userData); + self->m_statusMutex.lock(); + auto devices = self->self->devices(); + + if (devices != self->m_devices) { + self->m_devices = devices; + AKVCAM_EMIT(self->self, DevicesChanged, devices) + } + + auto picture = self->self->picture(); + + if (picture != self->m_picture) { + self->m_picture = picture; + AKVCAM_EMIT(self->self, PictureChanged, picture) + } + + std::vector removeDevices; + + for (auto &device: self->m_controlValues) + if (std::count(devices.begin(), devices.begin(), device.first) < 1) + removeDevices.push_back(device.first); + + for (auto &device: removeDevices) + self->m_controlValues.erase(device); + + for (auto &device: devices) { + std::map controlValues; + + for (auto &control: self->self->controls(device)) + controlValues[control.id] = control.value; + + if (self->m_controlValues.count(device) < 1) + self->m_controlValues[device] = {}; + + if (controlValues != self->m_controlValues[device]) { + self->m_controlValues[device] = controlValues; + AKVCAM_EMIT(self->self, ControlsChanged, device, controlValues) + } + } + + self->m_statusMutex.unlock(); +} + bool AkVCam::IpcBridgePrivate::isRoot() const { AkLogFunction(); @@ -997,3 +928,10 @@ AkVCam::Hack &AkVCam::Hack::operator =(const Hack &other) return *this; } + +#ifdef VCAMIPC_LIBRARY_SHARED +extern "C" AkVCam::IpcBridgePtr akCreateBridge() +{ + return std::make_shared(); +} +#endif diff --git a/dshow/VirtualCamera/src/basefilter.cpp b/dshow/VirtualCamera/src/basefilter.cpp index 36f5bb7..731876d 100644 --- a/dshow/VirtualCamera/src/basefilter.cpp +++ b/dshow/VirtualCamera/src/basefilter.cpp @@ -62,7 +62,7 @@ namespace AkVCam std::string m_vendor; std::string m_filterName; IFilterGraph *m_filterGraph {nullptr}; - IpcBridge m_ipcBridge; + IpcBridgePtr m_ipcBridge; BaseFilterPrivate(BaseFilter *self, const std::string &filterName, @@ -98,6 +98,8 @@ AkVCam::BaseFilter::BaseFilter(const GUID &clsid, AkVCam::BaseFilter::~BaseFilter() { + AkLogFunction(); + delete this->d; } @@ -106,7 +108,9 @@ void AkVCam::BaseFilter::addPin(const std::vector &formats, bool changed) { AkLogFunction(); - this->d->m_pins->addPin(new Pin(this, formats, pinName), changed); + auto pin = new Pin(this, formats, pinName); + pin->setBridge(this->d->m_ipcBridge); + this->d->m_pins->addPin(pin, changed); } void AkVCam::BaseFilter::removePin(IPin *pin, bool changed) @@ -353,18 +357,21 @@ AkVCam::BaseFilterPrivate::BaseFilterPrivate(AkVCam::BaseFilter *self, this->m_videoProcAmp->AddRef(); this->m_referenceClock->AddRef(); - this->m_ipcBridge.connectDevicesChanged(this, - &BaseFilterPrivate::devicesChanged); - this->m_ipcBridge.connectFrameReady(this, - &BaseFilterPrivate::frameReady); - this->m_ipcBridge.connectPictureChanged(this, - &BaseFilterPrivate::pictureChanged); - this->m_ipcBridge.connectControlsChanged(this, - &BaseFilterPrivate::setControls); + this->m_ipcBridge = std::make_shared(); + this->m_ipcBridge->connectDevicesChanged(this, + &BaseFilterPrivate::devicesChanged); + this->m_ipcBridge->connectFrameReady(this, + &BaseFilterPrivate::frameReady); + this->m_ipcBridge->connectPictureChanged(this, + &BaseFilterPrivate::pictureChanged); + this->m_ipcBridge->connectControlsChanged(this, + &BaseFilterPrivate::setControls); } AkVCam::BaseFilterPrivate::~BaseFilterPrivate() { + AkLogFunction(); + this->m_ipcBridge->stopNotifications(); this->m_pins->setBaseFilter(nullptr); this->m_pins->Release(); this->m_videoProcAmp->Release(); @@ -394,6 +401,7 @@ IEnumPins *AkVCam::BaseFilterPrivate::pinsForDevice(const std::string &deviceId) void AkVCam::BaseFilterPrivate::updatePins() { + AkLogFunction(); CLSID clsid; this->self->GetClassID(&clsid); auto cameraIndex = Preferences::cameraFromCLSID(clsid); @@ -403,7 +411,7 @@ void AkVCam::BaseFilterPrivate::updatePins() auto deviceId = Preferences::cameraId(size_t(cameraIndex)); - auto controlsList = this->m_ipcBridge.controls(deviceId); + auto controlsList = this->m_ipcBridge->controls(deviceId); std::map controls; for (auto &control: controlsList) @@ -427,26 +435,20 @@ void AkVCam::BaseFilterPrivate::pictureChanged(void *userData, { AkLogFunction(); auto self = reinterpret_cast(userData); - IEnumPins *pins = nullptr; - self->self->EnumPins(&pins); - - if (pins) { - AkVCamPinCall(pins, setPicture, picture) - pins->Release(); - } + AkVCamDevicePinCall(self->self->deviceId(), self, setPicture, picture) } void AkVCam::BaseFilterPrivate::devicesChanged(void *userData, const std::vector &devices) { + AkLogFunction(); UNUSED(userData); UNUSED(devices); - AkLogFunction(); std::vector handlers; EnumWindows(WNDENUMPROC(AkVCamEnumWindowsProc), LPARAM(&handlers)); for (auto &handler: handlers) - SendMessage(handler, WM_DEVICECHANGE, DBT_DEVNODES_CHANGED, 0); + SendNotifyMessage(handler, WM_DEVICECHANGE, DBT_DEVNODES_CHANGED, 0); } void AkVCam::BaseFilterPrivate::setControls(void *userData, diff --git a/dshow/VirtualCamera/src/pin.cpp b/dshow/VirtualCamera/src/pin.cpp index 9c89e72..68b1bce 100644 --- a/dshow/VirtualCamera/src/pin.cpp +++ b/dshow/VirtualCamera/src/pin.cpp @@ -48,6 +48,7 @@ namespace AkVCam { public: Pin *self; + IpcBridgePtr m_bridge; BaseFilter *m_baseFilter {nullptr}; VideoProcAmp *m_videoProcAmp {nullptr}; std::string m_pinName; @@ -97,6 +98,7 @@ AkVCam::Pin::Pin(BaseFilter *baseFilter, const std::string &pinName): StreamConfig(this) { + AkLogFunction(); this->setParent(this, &IID_IPin); this->d = new PinPrivate; @@ -110,6 +112,8 @@ AkVCam::Pin::Pin(BaseFilter *baseFilter, this->d->m_mediaTypes->AddRef(); auto cameraIndex = Preferences::cameraFromId(baseFilter->deviceId()); + + this->d->m_controlsMutex.lock(); this->d->m_controls["hflip"] = Preferences::cameraControlValue(cameraIndex, "hflip"); this->d->m_controls["vflip"] = @@ -120,11 +124,15 @@ AkVCam::Pin::Pin(BaseFilter *baseFilter, Preferences::cameraControlValue(cameraIndex, "aspect_ratio"); this->d->m_controls["swap_rgb"] = Preferences::cameraControlValue(cameraIndex, "swap_rgb"); + this->d->m_controlsMutex.unlock(); auto picture = Preferences::picture(); - if (!picture.empty()) + if (!picture.empty()) { + this->d->m_mutex.lock(); this->d->m_testFrame = loadPicture(picture); + this->d->m_mutex.unlock(); + } baseFilter->QueryInterface(IID_IAMVideoProcAmp, reinterpret_cast(&this->d->m_videoProcAmp)); @@ -154,6 +162,7 @@ AkVCam::Pin::Pin(BaseFilter *baseFilter, AkVCam::Pin::~Pin() { + AkLogFunction(); this->d->m_mediaTypes->Release(); if (this->d->m_connectedTo) @@ -184,6 +193,11 @@ void AkVCam::Pin::setBaseFilter(BaseFilter *baseFilter) this->d->m_baseFilter = baseFilter; } +void AkVCam::Pin::setBridge(IpcBridgePtr bridge) +{ + this->d->m_bridge = bridge; +} + HRESULT AkVCam::Pin::stateChanged(void *userData, FILTER_STATE state) { auto self = reinterpret_cast(userData); @@ -226,7 +240,14 @@ HRESULT AkVCam::Pin::stateChanged(void *userData, FILTER_STATE state) period, HSEMAPHORE(self->d->m_sendFrameEvent), &self->d->m_adviseCookie); + + if (self->d->m_bridge) + self->d->m_bridge->deviceStart(IpcBridge::StreamType_Input, + self->d->m_baseFilter->deviceId()); } else if (state == State_Stopped) { + if (self->d->m_bridge) + self->d->m_bridge->deviceStop(self->d->m_baseFilter->deviceId()); + self->d->m_running = false; self->d->m_sendFrameThread.join(); auto clock = self->d->m_baseFilter->referenceClock(); diff --git a/dshow/VirtualCamera/src/pin.h b/dshow/VirtualCamera/src/pin.h index 42f0a31..9a1a885 100644 --- a/dshow/VirtualCamera/src/pin.h +++ b/dshow/VirtualCamera/src/pin.h @@ -46,6 +46,7 @@ namespace AkVCam BaseFilter *baseFilter() const; void setBaseFilter(BaseFilter *baseFilter); + void setBridge(IpcBridgePtr bridge); static HRESULT stateChanged(void *userData, FILTER_STATE state); void frameReady(const VideoFrame &frame, bool isActive); void setPicture(const std::string &picture);