2020-06-02 15:37:45 +00:00
|
|
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
|
|
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
|
|
|
*
|
|
|
|
* akvirtualcamera 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.
|
|
|
|
*
|
|
|
|
* akvirtualcamera 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 akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
* Web-Site: http://webcamoid.github.io/
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <iostream>
|
|
|
|
#include <map>
|
|
|
|
#include <memory>
|
|
|
|
#include <mutex>
|
|
|
|
#include <string>
|
|
|
|
#include <thread>
|
|
|
|
#include <vector>
|
|
|
|
#include <windows.h>
|
2021-06-16 19:49:23 +00:00
|
|
|
#include <psapi.h>
|
2020-06-02 15:37:45 +00:00
|
|
|
#include <shellapi.h>
|
|
|
|
#include <sddl.h>
|
|
|
|
|
|
|
|
#include "service.h"
|
|
|
|
#include "PlatformUtils/src/messageserver.h"
|
2021-02-06 04:45:40 +00:00
|
|
|
#include "PlatformUtils/src/preferences.h"
|
2021-02-19 22:52:28 +00:00
|
|
|
#include "VCamUtils/src/videoformat.h"
|
|
|
|
#include "VCamUtils/src/videoframe.h"
|
2020-06-02 15:37:45 +00:00
|
|
|
#include "VCamUtils/src/timer.h"
|
2020-10-06 16:07:27 +00:00
|
|
|
#include "VCamUtils/src/logger.h"
|
2020-06-02 15:37:45 +00:00
|
|
|
|
|
|
|
namespace AkVCam
|
|
|
|
{
|
2021-06-16 19:49:23 +00:00
|
|
|
struct PeerInfo
|
|
|
|
{
|
|
|
|
std::string pipeName;
|
|
|
|
uint64_t pid {0};
|
|
|
|
bool isVCam {false};
|
|
|
|
};
|
|
|
|
|
2020-06-02 15:37:45 +00:00
|
|
|
struct AssistantDevice
|
|
|
|
{
|
|
|
|
std::string broadcaster;
|
|
|
|
std::vector<std::string> listeners;
|
|
|
|
};
|
|
|
|
|
2021-06-16 19:49:23 +00:00
|
|
|
typedef std::map<std::string, PeerInfo> AssistantPeers;
|
2020-06-02 15:37:45 +00:00
|
|
|
typedef std::map<std::string, AssistantDevice> DeviceConfigs;
|
|
|
|
|
|
|
|
class ServicePrivate
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
SERVICE_STATUS m_status;
|
|
|
|
SERVICE_STATUS_HANDLE m_statusHandler;
|
|
|
|
MessageServer m_messageServer;
|
2021-06-16 19:49:23 +00:00
|
|
|
AssistantPeers m_peers;
|
2020-06-02 15:37:45 +00:00
|
|
|
DeviceConfigs m_deviceConfigs;
|
|
|
|
Timer m_timer;
|
|
|
|
std::mutex m_peerMutex;
|
|
|
|
|
|
|
|
ServicePrivate();
|
2021-02-06 04:45:40 +00:00
|
|
|
inline static uint64_t id();
|
2020-06-02 15:37:45 +00:00
|
|
|
static void stateChanged(void *userData,
|
|
|
|
MessageServer::State state);
|
|
|
|
void sendStatus(DWORD currentState, DWORD exitCode, DWORD wait);
|
2021-06-16 19:49:23 +00:00
|
|
|
static std::vector<uint64_t> systemProcesses();
|
2021-02-06 04:45:40 +00:00
|
|
|
static void checkPeers(void *userData);
|
2020-06-02 15:37:45 +00:00
|
|
|
void removePortByName(const std::string &portName);
|
|
|
|
void releaseDevicesFromPeer(const std::string &portName);
|
|
|
|
void requestPort(Message *message);
|
|
|
|
void addPort(Message *message);
|
|
|
|
void removePort(Message *message);
|
2021-02-06 04:45:40 +00:00
|
|
|
void devicesUpdate(Message *message);
|
2020-06-02 15:37:45 +00:00
|
|
|
void setBroadCasting(Message *message);
|
|
|
|
void frameReady(Message *message);
|
2020-10-02 15:58:39 +00:00
|
|
|
void pictureUpdated(Message *message);
|
2020-06-02 15:37:45 +00:00
|
|
|
void listeners(Message *message);
|
|
|
|
void listener(Message *message);
|
|
|
|
void broadcasting(Message *message);
|
|
|
|
void listenerAdd(Message *message);
|
|
|
|
void listenerRemove(Message *message);
|
2020-10-02 15:58:39 +00:00
|
|
|
void controlsUpdated(Message *message);
|
2021-06-16 19:49:23 +00:00
|
|
|
void clients(Message *message);
|
|
|
|
void client(Message *message);
|
2020-06-02 15:37:45 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
GLOBAL_STATIC(ServicePrivate, servicePrivate)
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD WINAPI controlHandler(DWORD control,
|
|
|
|
DWORD eventType,
|
|
|
|
LPVOID eventData,
|
|
|
|
LPVOID context);
|
|
|
|
BOOL WINAPI controlDebugHandler(DWORD control);
|
|
|
|
|
|
|
|
AkVCam::Service::Service()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
AkVCam::Service::~Service()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL AkVCam::Service::install()
|
|
|
|
{
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogFunction();
|
2020-10-06 23:06:54 +00:00
|
|
|
TCHAR fileName[MAX_PATH];
|
2020-06-02 15:37:45 +00:00
|
|
|
|
|
|
|
if (!GetModuleFileName(nullptr, fileName, MAX_PATH)) {
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogError() << "Can't read module file name" << std::endl;
|
2020-06-02 15:37:45 +00:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto scManager = OpenSCManager(nullptr, nullptr, SC_MANAGER_ALL_ACCESS);
|
|
|
|
|
|
|
|
if (!scManager) {
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogError() << "Can't open SCManager" << std::endl;
|
2020-06-02 15:37:45 +00:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto service =
|
|
|
|
CreateService(scManager,
|
|
|
|
TEXT(DSHOW_PLUGIN_ASSISTANT_NAME),
|
|
|
|
TEXT(DSHOW_PLUGIN_ASSISTANT_DESCRIPTION),
|
|
|
|
SERVICE_ALL_ACCESS,
|
|
|
|
SERVICE_WIN32_OWN_PROCESS,
|
|
|
|
SERVICE_AUTO_START,
|
|
|
|
SERVICE_ERROR_NORMAL,
|
|
|
|
fileName,
|
|
|
|
nullptr,
|
|
|
|
nullptr,
|
|
|
|
nullptr,
|
|
|
|
nullptr,
|
|
|
|
nullptr);
|
|
|
|
|
|
|
|
if (!service) {
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogError() << "Can't create service" << std::endl;
|
2020-06-02 15:37:45 +00:00
|
|
|
CloseServiceHandle(scManager);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add detailed description to the service.
|
|
|
|
SERVICE_DESCRIPTION serviceDescription;
|
2020-10-06 23:06:54 +00:00
|
|
|
TCHAR description[] = TEXT(DSHOW_PLUGIN_DESCRIPTION_EXT);
|
2020-06-02 15:37:45 +00:00
|
|
|
serviceDescription.lpDescription = description;
|
|
|
|
auto result =
|
|
|
|
ChangeServiceConfig2(service,
|
|
|
|
SERVICE_CONFIG_DESCRIPTION,
|
|
|
|
&serviceDescription);
|
|
|
|
|
|
|
|
// Configure the service so it will restart if fail.
|
2020-10-06 23:06:54 +00:00
|
|
|
TCHAR rebootMsg[] = TEXT("Service failed restarting...");
|
2020-06-02 15:37:45 +00:00
|
|
|
|
|
|
|
std::vector<SC_ACTION> actions {
|
|
|
|
{SC_ACTION_RESTART, 5000}
|
|
|
|
};
|
|
|
|
|
|
|
|
SERVICE_FAILURE_ACTIONS failureActions {
|
|
|
|
INFINITE,
|
|
|
|
rebootMsg,
|
|
|
|
nullptr,
|
|
|
|
DWORD(actions.size()),
|
|
|
|
actions.data()
|
|
|
|
};
|
|
|
|
|
|
|
|
result =
|
|
|
|
ChangeServiceConfig2(service,
|
|
|
|
SERVICE_CONFIG_FAILURE_ACTIONS,
|
|
|
|
&failureActions);
|
|
|
|
|
|
|
|
// Run the service
|
|
|
|
StartService(service, 0, nullptr);
|
|
|
|
CloseServiceHandle(service);
|
|
|
|
CloseServiceHandle(scManager);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AkVCam::Service::uninstall()
|
|
|
|
{
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogFunction();
|
2020-06-02 15:37:45 +00:00
|
|
|
auto scManager = OpenSCManager(nullptr, nullptr, SC_MANAGER_ALL_ACCESS);
|
|
|
|
|
|
|
|
if (!scManager) {
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogError() << "Can't open SCManager" << std::endl;
|
2020-06-02 15:37:45 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto sevice = OpenService(scManager,
|
|
|
|
TEXT(DSHOW_PLUGIN_ASSISTANT_NAME),
|
|
|
|
SERVICE_ALL_ACCESS);
|
|
|
|
|
|
|
|
if (sevice) {
|
|
|
|
if (ControlService(sevice,
|
|
|
|
SERVICE_CONTROL_STOP,
|
|
|
|
&servicePrivate()->m_status)) {
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogInfo() << "Stopping service" << std::endl;
|
2020-06-02 15:37:45 +00:00
|
|
|
|
|
|
|
do {
|
|
|
|
Sleep(1000);
|
|
|
|
QueryServiceStatus(sevice, &servicePrivate()->m_status);
|
|
|
|
} while(servicePrivate()->m_status.dwCurrentState != SERVICE_STOPPED);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!DeleteService(sevice)) {
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogError() << "Delete service failed" << std::endl;
|
2020-06-02 15:37:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CloseServiceHandle(sevice);
|
|
|
|
} else {
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogError() << "Can't open service" << std::endl;
|
2020-06-02 15:37:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CloseServiceHandle(scManager);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AkVCam::Service::debug()
|
|
|
|
{
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogFunction();
|
2020-06-02 15:37:45 +00:00
|
|
|
SetConsoleCtrlHandler(controlDebugHandler, TRUE);
|
|
|
|
servicePrivate()->m_messageServer.start(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AkVCam::Service::showHelp(int argc, char **argv)
|
|
|
|
{
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogFunction();
|
2020-10-02 15:58:39 +00:00
|
|
|
UNUSED(argc);
|
2020-06-02 15:37:45 +00:00
|
|
|
|
|
|
|
auto programName = strrchr(argv[0], '\\');
|
|
|
|
|
|
|
|
if (!programName)
|
|
|
|
programName = strrchr(argv[0], '/');
|
|
|
|
|
|
|
|
if (!programName)
|
|
|
|
programName = argv[0];
|
|
|
|
else
|
|
|
|
programName++;
|
|
|
|
|
|
|
|
std::cout << "Usage: " << programName << " [options]" << std::endl;
|
|
|
|
std::cout << std::endl;
|
|
|
|
std::cout << "Webcamoid virtual camera server." << std::endl;
|
|
|
|
std::cout << std::endl;
|
|
|
|
std::cout << "Options:" << std::endl;
|
|
|
|
std::cout << std::endl;
|
|
|
|
std::cout << "\t-i, --install\tInstall the service." << std::endl;
|
|
|
|
std::cout << "\t-u, --uninstall\tUnistall the service." << std::endl;
|
|
|
|
std::cout << "\t-d, --debug\tDebug the service." << std::endl;
|
|
|
|
std::cout << "\t-h, --help\tShow this help." << std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
AkVCam::ServicePrivate::ServicePrivate()
|
|
|
|
{
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogFunction();
|
2020-06-02 15:37:45 +00:00
|
|
|
|
|
|
|
this->m_status = {
|
|
|
|
SERVICE_WIN32_OWN_PROCESS,
|
|
|
|
SERVICE_STOPPED,
|
|
|
|
0,
|
|
|
|
NO_ERROR,
|
|
|
|
NO_ERROR,
|
|
|
|
0,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
this->m_statusHandler = nullptr;
|
2020-10-06 23:06:54 +00:00
|
|
|
this->m_messageServer.setPipeName("\\\\.\\pipe\\" DSHOW_PLUGIN_ASSISTANT_NAME);
|
2020-06-02 15:37:45 +00:00
|
|
|
this->m_messageServer.setHandlers({
|
2020-10-02 15:58:39 +00:00
|
|
|
{AKVCAM_ASSISTANT_MSG_FRAME_READY , AKVCAM_BIND_FUNC(ServicePrivate::frameReady) },
|
|
|
|
{AKVCAM_ASSISTANT_MSG_PICTURE_UPDATED , AKVCAM_BIND_FUNC(ServicePrivate::pictureUpdated) },
|
|
|
|
{AKVCAM_ASSISTANT_MSG_REQUEST_PORT , AKVCAM_BIND_FUNC(ServicePrivate::requestPort) },
|
|
|
|
{AKVCAM_ASSISTANT_MSG_ADD_PORT , AKVCAM_BIND_FUNC(ServicePrivate::addPort) },
|
|
|
|
{AKVCAM_ASSISTANT_MSG_REMOVE_PORT , AKVCAM_BIND_FUNC(ServicePrivate::removePort) },
|
2021-02-06 04:45:40 +00:00
|
|
|
{AKVCAM_ASSISTANT_MSG_DEVICE_UPDATE , AKVCAM_BIND_FUNC(ServicePrivate::devicesUpdate) },
|
2020-10-02 15:58:39 +00:00
|
|
|
{AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_ADD , AKVCAM_BIND_FUNC(ServicePrivate::listenerAdd) },
|
|
|
|
{AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_REMOVE , AKVCAM_BIND_FUNC(ServicePrivate::listenerRemove) },
|
|
|
|
{AKVCAM_ASSISTANT_MSG_DEVICE_LISTENERS , AKVCAM_BIND_FUNC(ServicePrivate::listeners) },
|
|
|
|
{AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER , AKVCAM_BIND_FUNC(ServicePrivate::listener) },
|
|
|
|
{AKVCAM_ASSISTANT_MSG_DEVICE_BROADCASTING , AKVCAM_BIND_FUNC(ServicePrivate::broadcasting) },
|
|
|
|
{AKVCAM_ASSISTANT_MSG_DEVICE_SETBROADCASTING , AKVCAM_BIND_FUNC(ServicePrivate::setBroadCasting)},
|
|
|
|
{AKVCAM_ASSISTANT_MSG_DEVICE_CONTROLS_UPDATED, AKVCAM_BIND_FUNC(ServicePrivate::controlsUpdated)},
|
2021-06-16 19:49:23 +00:00
|
|
|
{AKVCAM_ASSISTANT_MSG_CLIENTS , AKVCAM_BIND_FUNC(ServicePrivate::clients) },
|
|
|
|
{AKVCAM_ASSISTANT_MSG_CLIENT , AKVCAM_BIND_FUNC(ServicePrivate::client) },
|
2020-06-02 15:37:45 +00:00
|
|
|
});
|
2021-06-16 19:49:23 +00:00
|
|
|
this->m_timer.setInterval(5000);
|
2020-06-02 15:37:45 +00:00
|
|
|
this->m_timer.connectTimeout(this, &ServicePrivate::checkPeers);
|
2021-02-06 04:45:40 +00:00
|
|
|
this->m_timer.start();
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t AkVCam::ServicePrivate::id()
|
|
|
|
{
|
|
|
|
static uint64_t id = 0;
|
|
|
|
|
|
|
|
return id++;
|
2020-06-02 15:37:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void AkVCam::ServicePrivate::stateChanged(void *userData,
|
|
|
|
MessageServer::State state)
|
|
|
|
{
|
2020-10-02 15:58:39 +00:00
|
|
|
UNUSED(userData);
|
2020-06-02 15:37:45 +00:00
|
|
|
|
|
|
|
switch (state) {
|
|
|
|
case MessageServer::StateAboutToStart:
|
|
|
|
AkVCam::servicePrivate()->sendStatus(SERVICE_START_PENDING, NO_ERROR, 3000);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MessageServer::StateStarted:
|
|
|
|
AkVCam::servicePrivate()->sendStatus(SERVICE_RUNNING, NO_ERROR, 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MessageServer::StateAboutToStop:
|
|
|
|
AkVCam::servicePrivate()->sendStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MessageServer::StateStopped:
|
|
|
|
AkVCam::servicePrivate()->sendStatus(SERVICE_STOPPED, NO_ERROR, 0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AkVCam::ServicePrivate::sendStatus(DWORD currentState,
|
|
|
|
DWORD exitCode,
|
|
|
|
DWORD wait)
|
|
|
|
{
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogFunction();
|
2020-06-02 15:37:45 +00:00
|
|
|
this->m_status.dwControlsAccepted =
|
|
|
|
currentState == SERVICE_START_PENDING? 0: SERVICE_ACCEPT_STOP;
|
|
|
|
this->m_status.dwCurrentState = currentState;
|
|
|
|
this->m_status.dwWin32ExitCode = exitCode;
|
|
|
|
this->m_status.dwWaitHint = wait;
|
|
|
|
|
|
|
|
if (currentState == SERVICE_RUNNING || currentState == SERVICE_STOPPED)
|
|
|
|
this->m_status.dwCheckPoint = 0;
|
|
|
|
else
|
|
|
|
this->m_status.dwCheckPoint++;
|
|
|
|
|
|
|
|
SetServiceStatus(this->m_statusHandler, &this->m_status);
|
|
|
|
}
|
|
|
|
|
2021-06-16 19:49:23 +00:00
|
|
|
std::vector<uint64_t> AkVCam::ServicePrivate::systemProcesses()
|
|
|
|
{
|
|
|
|
std::vector<uint64_t> pids;
|
|
|
|
|
|
|
|
const DWORD nElements = 4096;
|
|
|
|
DWORD process[nElements];
|
|
|
|
memset(process, 0, nElements * sizeof(DWORD));
|
|
|
|
DWORD needed = 0;
|
|
|
|
|
|
|
|
if (!EnumProcesses(process, nElements * sizeof(DWORD), &needed))
|
|
|
|
return {};
|
|
|
|
|
|
|
|
size_t nProcess = needed / sizeof(DWORD);
|
|
|
|
|
|
|
|
for (size_t i = 0; i < nProcess; i++)
|
|
|
|
if (process[i] > 0)
|
|
|
|
pids.push_back(process[i]);
|
|
|
|
|
|
|
|
return pids;
|
|
|
|
}
|
|
|
|
|
2021-02-06 04:45:40 +00:00
|
|
|
void AkVCam::ServicePrivate::checkPeers(void *userData)
|
2020-06-02 15:37:45 +00:00
|
|
|
{
|
2021-02-06 04:45:40 +00:00
|
|
|
AkLogFunction();
|
|
|
|
auto self = reinterpret_cast<ServicePrivate *>(userData);
|
|
|
|
std::vector<std::string> deadPeers;
|
2021-06-16 19:49:23 +00:00
|
|
|
auto pids = systemProcesses();
|
2020-06-02 15:37:45 +00:00
|
|
|
|
2021-02-06 04:45:40 +00:00
|
|
|
self->m_peerMutex.lock();
|
|
|
|
|
2021-06-16 19:49:23 +00:00
|
|
|
for (auto &peer: self->m_peers) {
|
|
|
|
auto it = std::find(pids.begin(), pids.end(), peer.second.pid);
|
2021-02-06 04:45:40 +00:00
|
|
|
|
2021-06-16 19:49:23 +00:00
|
|
|
if (it == pids.end())
|
|
|
|
deadPeers.push_back(peer.first);
|
2021-02-06 04:45:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
self->m_peerMutex.unlock();
|
|
|
|
|
|
|
|
for (auto &port: deadPeers) {
|
|
|
|
AkLogWarning() << port << " died, removing..." << std::endl;
|
|
|
|
self->removePortByName(port);
|
|
|
|
}
|
2020-06-02 15:37:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void AkVCam::ServicePrivate::removePortByName(const std::string &portName)
|
|
|
|
{
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogFunction();
|
2021-02-06 04:45:40 +00:00
|
|
|
AkLogDebug() << "Port: " << portName << std::endl;
|
2020-06-02 15:37:45 +00:00
|
|
|
|
|
|
|
this->m_peerMutex.lock();
|
|
|
|
|
2021-06-16 19:49:23 +00:00
|
|
|
for (auto &peer: this->m_peers)
|
2021-02-06 04:45:40 +00:00
|
|
|
if (peer.first == portName) {
|
2021-06-16 19:49:23 +00:00
|
|
|
this->m_peers.erase(portName);
|
2020-06-02 15:37:45 +00:00
|
|
|
|
|
|
|
break;
|
2021-02-06 04:45:40 +00:00
|
|
|
}
|
2020-06-02 15:37:45 +00:00
|
|
|
|
|
|
|
this->m_peerMutex.unlock();
|
|
|
|
this->releaseDevicesFromPeer(portName);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AkVCam::ServicePrivate::releaseDevicesFromPeer(const std::string &portName)
|
|
|
|
{
|
2021-02-06 04:45:40 +00:00
|
|
|
AkLogFunction();
|
|
|
|
|
2020-06-02 15:37:45 +00:00
|
|
|
for (auto &config: this->m_deviceConfigs)
|
|
|
|
if (config.second.broadcaster == portName) {
|
|
|
|
config.second.broadcaster.clear();
|
|
|
|
|
|
|
|
Message message;
|
|
|
|
message.messageId = AKVCAM_ASSISTANT_MSG_DEVICE_SETBROADCASTING;
|
|
|
|
message.dataSize = sizeof(MsgBroadcasting);
|
|
|
|
auto data = messageData<MsgBroadcasting>(&message);
|
|
|
|
memcpy(data->device,
|
|
|
|
config.first.c_str(),
|
|
|
|
(std::min<size_t>)(config.first.size(), MAX_STRING));
|
|
|
|
this->m_peerMutex.lock();
|
|
|
|
|
2021-06-16 19:49:23 +00:00
|
|
|
for (auto &peer: this->m_peers)
|
|
|
|
MessageServer::sendMessage(peer.second.pipeName, &message);
|
2020-06-02 15:37:45 +00:00
|
|
|
|
|
|
|
this->m_peerMutex.unlock();
|
|
|
|
} else {
|
|
|
|
auto it = std::find(config.second.listeners.begin(),
|
|
|
|
config.second.listeners.end(),
|
|
|
|
portName);
|
|
|
|
|
|
|
|
if (it != config.second.listeners.end())
|
|
|
|
config.second.listeners.erase(it);
|
|
|
|
}
|
2021-02-06 04:45:40 +00:00
|
|
|
|
|
|
|
AkLogInfo() << portName << " released." << std::endl;
|
2020-06-02 15:37:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void AkVCam::ServicePrivate::requestPort(AkVCam::Message *message)
|
|
|
|
{
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogFunction();
|
2020-06-02 15:37:45 +00:00
|
|
|
|
|
|
|
auto data = messageData<MsgRequestPort>(message);
|
2020-10-02 15:58:39 +00:00
|
|
|
std::string portName = AKVCAM_ASSISTANT_CLIENT_NAME;
|
2020-06-02 15:37:45 +00:00
|
|
|
portName += std::to_string(this->id());
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogInfo() << "Returning Port: " << portName << std::endl;
|
2020-06-02 15:37:45 +00:00
|
|
|
memcpy(data->port,
|
|
|
|
portName.c_str(),
|
|
|
|
(std::min<size_t>)(portName.size(), MAX_STRING));
|
|
|
|
}
|
|
|
|
|
|
|
|
void AkVCam::ServicePrivate::addPort(AkVCam::Message *message)
|
|
|
|
{
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogFunction();
|
2020-06-02 15:37:45 +00:00
|
|
|
|
|
|
|
auto data = messageData<MsgAddPort>(message);
|
|
|
|
std::string portName(data->port);
|
|
|
|
std::string pipeName(data->pipeName);
|
|
|
|
bool ok = true;
|
|
|
|
|
|
|
|
this->m_peerMutex.lock();
|
|
|
|
|
2021-06-16 19:49:23 +00:00
|
|
|
for (auto &peer: this->m_peers)
|
|
|
|
if (peer.first == portName) {
|
2020-06-02 15:37:45 +00:00
|
|
|
ok = false;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ok) {
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogInfo() << "Adding Peer: " << portName << std::endl;
|
2021-06-16 19:49:23 +00:00
|
|
|
PeerInfo peerInfo;
|
|
|
|
peerInfo.pipeName = pipeName;
|
|
|
|
peerInfo.pid = data->pid;
|
|
|
|
peerInfo.isVCam = data->isVCam;
|
|
|
|
this->m_peers[portName] = peerInfo;
|
2020-06-02 15:37:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
this->m_peerMutex.unlock();
|
|
|
|
data->status = ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AkVCam::ServicePrivate::removePort(AkVCam::Message *message)
|
|
|
|
{
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogFunction();
|
2020-06-02 15:37:45 +00:00
|
|
|
|
|
|
|
auto data = messageData<MsgRemovePort>(message);
|
|
|
|
this->removePortByName(data->port);
|
|
|
|
}
|
|
|
|
|
2021-02-06 04:45:40 +00:00
|
|
|
void AkVCam::ServicePrivate::devicesUpdate(AkVCam::Message *message)
|
2020-06-02 15:37:45 +00:00
|
|
|
{
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogFunction();
|
2021-02-06 04:45:40 +00:00
|
|
|
auto data = messageData<MsgDevicesUpdated>(message);
|
|
|
|
DeviceConfigs configs;
|
2020-06-02 15:37:45 +00:00
|
|
|
|
2021-02-06 04:45:40 +00:00
|
|
|
for (size_t i = 0; i < Preferences::camerasCount(); i++) {
|
2021-06-21 21:25:48 +00:00
|
|
|
auto device = Preferences::cameraId(i);
|
2020-06-02 15:37:45 +00:00
|
|
|
|
2021-02-06 04:45:40 +00:00
|
|
|
if (this->m_deviceConfigs.count(device) > 0)
|
|
|
|
configs[device] = this->m_deviceConfigs[device];
|
|
|
|
else
|
|
|
|
configs[device] = {};
|
|
|
|
}
|
2020-06-02 15:37:45 +00:00
|
|
|
|
|
|
|
this->m_peerMutex.lock();
|
2021-02-06 04:45:40 +00:00
|
|
|
this->m_deviceConfigs = configs;
|
2020-06-02 15:37:45 +00:00
|
|
|
|
2021-02-06 04:45:40 +00:00
|
|
|
if (data->propagate)
|
2021-06-16 19:49:23 +00:00
|
|
|
for (auto &peer: this->m_peers)
|
|
|
|
MessageServer::sendMessage(peer.second.pipeName, message);
|
2020-06-02 15:37:45 +00:00
|
|
|
|
|
|
|
this->m_peerMutex.unlock();
|
|
|
|
}
|
|
|
|
|
2021-02-06 04:45:40 +00:00
|
|
|
void AkVCam::ServicePrivate::setBroadCasting(AkVCam::Message *message)
|
2020-06-02 15:37:45 +00:00
|
|
|
{
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogFunction();
|
2021-02-06 04:45:40 +00:00
|
|
|
auto data = messageData<MsgBroadcasting>(message);
|
|
|
|
std::string deviceId(data->device);
|
|
|
|
std::string broadcaster(data->broadcaster);
|
|
|
|
data->status = false;
|
2020-06-02 15:37:45 +00:00
|
|
|
|
2021-02-06 04:45:40 +00:00
|
|
|
if (this->m_deviceConfigs.count(deviceId) > 0)
|
|
|
|
if (this->m_deviceConfigs[deviceId].broadcaster != broadcaster) {
|
|
|
|
AkLogInfo() << "Device: " << deviceId << std::endl;
|
|
|
|
AkLogInfo() << "Broadcaster: " << broadcaster << std::endl;
|
|
|
|
this->m_deviceConfigs[deviceId].broadcaster = broadcaster;
|
|
|
|
data->status = true;
|
2020-06-02 15:37:45 +00:00
|
|
|
|
2021-02-06 04:45:40 +00:00
|
|
|
this->m_peerMutex.lock();
|
|
|
|
|
2021-06-16 19:49:23 +00:00
|
|
|
for (auto &peer: this->m_peers) {
|
2021-02-06 04:45:40 +00:00
|
|
|
Message msg(message);
|
2021-06-16 19:49:23 +00:00
|
|
|
MessageServer::sendMessage(peer.second.pipeName, &msg);
|
2021-02-06 04:45:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
this->m_peerMutex.unlock();
|
|
|
|
}
|
2020-06-02 15:37:45 +00:00
|
|
|
}
|
|
|
|
|
2021-02-06 04:45:40 +00:00
|
|
|
void AkVCam::ServicePrivate::frameReady(AkVCam::Message *message)
|
2020-06-02 15:37:45 +00:00
|
|
|
{
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogFunction();
|
2020-06-02 15:37:45 +00:00
|
|
|
this->m_peerMutex.lock();
|
|
|
|
|
2021-06-16 19:49:23 +00:00
|
|
|
for (auto &peer: this->m_peers)
|
|
|
|
MessageServer::sendMessage(peer.second.pipeName, message);
|
2020-06-02 15:37:45 +00:00
|
|
|
|
|
|
|
this->m_peerMutex.unlock();
|
|
|
|
}
|
|
|
|
|
2021-02-06 04:45:40 +00:00
|
|
|
void AkVCam::ServicePrivate::pictureUpdated(AkVCam::Message *message)
|
2020-06-02 15:37:45 +00:00
|
|
|
{
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogFunction();
|
2020-06-02 15:37:45 +00:00
|
|
|
this->m_peerMutex.lock();
|
|
|
|
|
2021-06-16 19:49:23 +00:00
|
|
|
for (auto &peer: this->m_peers)
|
|
|
|
MessageServer::sendMessage(peer.second.pipeName, message);
|
2020-06-02 15:37:45 +00:00
|
|
|
|
|
|
|
this->m_peerMutex.unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
void AkVCam::ServicePrivate::listeners(AkVCam::Message *message)
|
|
|
|
{
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogFunction();
|
2020-06-02 15:37:45 +00:00
|
|
|
auto data = messageData<MsgListeners>(message);
|
|
|
|
std::string deviceId(data->device);
|
|
|
|
|
|
|
|
if (this->m_deviceConfigs.count(deviceId) < 1)
|
|
|
|
this->m_deviceConfigs[deviceId] = {};
|
|
|
|
|
|
|
|
data->nlistener = this->m_deviceConfigs[deviceId].listeners.size();
|
|
|
|
|
|
|
|
if (data->nlistener > 0) {
|
|
|
|
memcpy(data->listener,
|
|
|
|
this->m_deviceConfigs[deviceId].listeners[0].c_str(),
|
|
|
|
std::min<size_t>(this->m_deviceConfigs[deviceId].listeners[0].size(),
|
|
|
|
MAX_STRING));
|
|
|
|
}
|
|
|
|
|
|
|
|
data->status = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AkVCam::ServicePrivate::listener(AkVCam::Message *message)
|
|
|
|
{
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogFunction();
|
2020-06-02 15:37:45 +00:00
|
|
|
auto data = messageData<MsgListeners>(message);
|
|
|
|
std::string deviceId(data->device);
|
|
|
|
|
|
|
|
if (this->m_deviceConfigs.count(deviceId) < 1)
|
|
|
|
this->m_deviceConfigs[deviceId] = {};
|
|
|
|
|
|
|
|
auto nlistener = this->m_deviceConfigs[deviceId].listeners.size();
|
|
|
|
|
|
|
|
if (data->nlistener >= nlistener) {
|
|
|
|
data->status = false;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(data->listener,
|
|
|
|
this->m_deviceConfigs[deviceId].listeners[data->nlistener].c_str(),
|
|
|
|
std::min<size_t>(this->m_deviceConfigs[deviceId].listeners[data->nlistener].size(),
|
|
|
|
MAX_STRING));
|
|
|
|
|
|
|
|
data->status = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AkVCam::ServicePrivate::broadcasting(AkVCam::Message *message)
|
|
|
|
{
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogFunction();
|
2020-06-02 15:37:45 +00:00
|
|
|
auto data = messageData<MsgBroadcasting>(message);
|
|
|
|
std::string deviceId(data->device);
|
|
|
|
|
|
|
|
if (this->m_deviceConfigs.count(deviceId) < 1)
|
|
|
|
this->m_deviceConfigs[deviceId] = {};
|
|
|
|
|
|
|
|
memcpy(data->broadcaster,
|
|
|
|
this->m_deviceConfigs[deviceId].broadcaster.c_str(),
|
|
|
|
std::min<size_t>(this->m_deviceConfigs[deviceId].broadcaster.size(),
|
|
|
|
MAX_STRING));
|
|
|
|
data->status = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AkVCam::ServicePrivate::listenerAdd(AkVCam::Message *message)
|
|
|
|
{
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogFunction();
|
2020-06-02 15:37:45 +00:00
|
|
|
auto data = messageData<MsgListeners>(message);
|
|
|
|
std::string deviceId(data->device);
|
|
|
|
|
|
|
|
if (this->m_deviceConfigs.count(deviceId) < 1)
|
|
|
|
this->m_deviceConfigs[deviceId] = {};
|
|
|
|
|
|
|
|
auto &listeners = this->m_deviceConfigs[deviceId].listeners;
|
|
|
|
std::string listener(data->listener);
|
|
|
|
auto it = std::find(listeners.begin(), listeners.end(), listener);
|
|
|
|
|
|
|
|
if (it == listeners.end()) {
|
|
|
|
listeners.push_back(listener);
|
|
|
|
data->nlistener = listeners.size();
|
|
|
|
data->status = true;
|
|
|
|
|
|
|
|
this->m_peerMutex.lock();
|
|
|
|
|
2021-06-16 19:49:23 +00:00
|
|
|
for (auto &peer: this->m_peers) {
|
2020-06-02 15:37:45 +00:00
|
|
|
Message msg(message);
|
2021-06-16 19:49:23 +00:00
|
|
|
MessageServer::sendMessage(peer.second.pipeName, &msg);
|
2020-06-02 15:37:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
this->m_peerMutex.unlock();
|
|
|
|
} else {
|
|
|
|
data->nlistener = listeners.size();
|
|
|
|
data->status = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AkVCam::ServicePrivate::listenerRemove(AkVCam::Message *message)
|
|
|
|
{
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogFunction();
|
2020-06-02 15:37:45 +00:00
|
|
|
auto data = messageData<MsgListeners>(message);
|
|
|
|
std::string deviceId(data->device);
|
|
|
|
|
|
|
|
if (this->m_deviceConfigs.count(deviceId) < 1)
|
|
|
|
this->m_deviceConfigs[deviceId] = {};
|
|
|
|
|
|
|
|
auto &listeners = this->m_deviceConfigs[deviceId].listeners;
|
|
|
|
std::string listener(data->listener);
|
|
|
|
auto it = std::find(listeners.begin(), listeners.end(), listener);
|
|
|
|
|
|
|
|
if (it != listeners.end()) {
|
|
|
|
listeners.erase(it);
|
|
|
|
data->nlistener = listeners.size();
|
|
|
|
data->status = true;
|
|
|
|
|
|
|
|
this->m_peerMutex.lock();
|
|
|
|
|
2021-06-16 19:49:23 +00:00
|
|
|
for (auto &peer: this->m_peers) {
|
2020-06-02 15:37:45 +00:00
|
|
|
Message msg(message);
|
2021-06-16 19:49:23 +00:00
|
|
|
MessageServer::sendMessage(peer.second.pipeName, &msg);
|
2020-06-02 15:37:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
this->m_peerMutex.unlock();
|
|
|
|
} else {
|
|
|
|
data->nlistener = listeners.size();
|
|
|
|
data->status = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-02 15:58:39 +00:00
|
|
|
void AkVCam::ServicePrivate::controlsUpdated(AkVCam::Message *message)
|
|
|
|
{
|
|
|
|
AkLogFunction();
|
|
|
|
this->m_peerMutex.lock();
|
|
|
|
|
2021-06-16 19:49:23 +00:00
|
|
|
for (auto &peer: this->m_peers)
|
|
|
|
MessageServer::sendMessage(peer.second.pipeName, message);
|
|
|
|
|
|
|
|
this->m_peerMutex.unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
void AkVCam::ServicePrivate::clients(AkVCam::Message *message)
|
|
|
|
{
|
|
|
|
AkLogFunction();
|
|
|
|
auto data = messageData<MsgClients>(message);
|
|
|
|
this->m_peerMutex.lock();
|
|
|
|
data->nclient = 0;
|
|
|
|
|
|
|
|
for (auto &peer: this->m_peers)
|
|
|
|
if (peer.second.isVCam)
|
|
|
|
data->nclient++;
|
2020-10-02 15:58:39 +00:00
|
|
|
|
2021-06-16 19:49:23 +00:00
|
|
|
data->status = true;
|
2020-10-02 15:58:39 +00:00
|
|
|
this->m_peerMutex.unlock();
|
|
|
|
}
|
|
|
|
|
2021-06-16 19:49:23 +00:00
|
|
|
void AkVCam::ServicePrivate::client(AkVCam::Message *message)
|
|
|
|
{
|
|
|
|
AkLogFunction();
|
|
|
|
auto data = messageData<MsgClients>(message);
|
|
|
|
std::vector<uint64_t> pids;
|
|
|
|
this->m_peerMutex.lock();
|
|
|
|
|
|
|
|
for (auto &peer: this->m_peers) {
|
|
|
|
AkLogDebug() << "PID: " << peer.second.pid << std::endl;
|
|
|
|
AkLogDebug() << "Is vcam: " << peer.second.isVCam << std::endl;
|
|
|
|
|
|
|
|
if (peer.second.isVCam)
|
|
|
|
pids.push_back(peer.second.pid);
|
|
|
|
}
|
|
|
|
|
|
|
|
this->m_peerMutex.unlock();
|
|
|
|
std::sort(pids.begin(), pids.end());
|
|
|
|
|
|
|
|
if (data->nclient >= pids.size()) {
|
|
|
|
data->status = false;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
data->pid = pids[data->nclient];
|
|
|
|
data->status = true;
|
|
|
|
}
|
|
|
|
|
2020-06-02 15:37:45 +00:00
|
|
|
DWORD WINAPI controlHandler(DWORD control,
|
|
|
|
DWORD eventType,
|
|
|
|
LPVOID eventData,
|
|
|
|
LPVOID context)
|
|
|
|
{
|
2020-10-02 15:58:39 +00:00
|
|
|
UNUSED(eventType);
|
|
|
|
UNUSED(eventData);
|
|
|
|
UNUSED(context);
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogFunction();
|
2020-06-02 15:37:45 +00:00
|
|
|
|
|
|
|
DWORD result = ERROR_CALL_NOT_IMPLEMENTED;
|
|
|
|
|
|
|
|
switch (control) {
|
|
|
|
case SERVICE_CONTROL_SHUTDOWN:
|
|
|
|
case SERVICE_CONTROL_STOP:
|
|
|
|
AkVCam::servicePrivate()->sendStatus(SERVICE_STOP_PENDING,
|
|
|
|
NO_ERROR,
|
|
|
|
0);
|
2021-02-06 04:45:40 +00:00
|
|
|
AkVCam::servicePrivate()->m_messageServer.stop(true);
|
2020-06-02 15:37:45 +00:00
|
|
|
result = NO_ERROR;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SERVICE_CONTROL_INTERROGATE:
|
|
|
|
result = NO_ERROR;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto state = AkVCam::servicePrivate()->m_status.dwCurrentState;
|
|
|
|
AkVCam::servicePrivate()->sendStatus(state, NO_ERROR, 0);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI controlDebugHandler(DWORD control)
|
|
|
|
{
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogFunction();
|
2020-06-02 15:37:45 +00:00
|
|
|
|
|
|
|
if (control == CTRL_BREAK_EVENT || control == CTRL_C_EVENT) {
|
2021-02-06 04:45:40 +00:00
|
|
|
AkVCam::servicePrivate()->m_messageServer.stop(true);
|
2020-06-02 15:37:45 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void WINAPI serviceMain(DWORD dwArgc, LPTSTR *lpszArgv)
|
|
|
|
{
|
2020-10-02 15:58:39 +00:00
|
|
|
UNUSED(dwArgc);
|
|
|
|
UNUSED(lpszArgv);
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogFunction();
|
|
|
|
AkLogInfo() << "Setting service control handler" << std::endl;
|
2020-06-02 15:37:45 +00:00
|
|
|
|
|
|
|
AkVCam::servicePrivate()->m_statusHandler =
|
|
|
|
RegisterServiceCtrlHandlerEx(TEXT(DSHOW_PLUGIN_ASSISTANT_NAME),
|
|
|
|
controlHandler,
|
|
|
|
nullptr);
|
|
|
|
|
|
|
|
if (!AkVCam::servicePrivate()->m_statusHandler)
|
|
|
|
return;
|
|
|
|
|
|
|
|
AkVCam::servicePrivate()->sendStatus(SERVICE_START_PENDING, NO_ERROR, 3000);
|
|
|
|
|
2020-06-29 16:17:34 +00:00
|
|
|
AkLogInfo() << "Setting up service" << std::endl;
|
2020-06-02 15:37:45 +00:00
|
|
|
AkVCam::servicePrivate()->m_messageServer
|
|
|
|
.connectStateChanged(AkVCam::servicePrivate(),
|
|
|
|
&AkVCam::ServicePrivate::stateChanged);
|
|
|
|
AkVCam::servicePrivate()->m_messageServer.start(true);
|
|
|
|
}
|