From c0d241d0b4944520fe364d9ee8e6d3bbc849e694 Mon Sep 17 00:00:00 2001 From: Gonzalo Exequiel Pedone Date: Sat, 19 Jun 2021 13:45:59 -0300 Subject: [PATCH] Allow setting a custom device ID (issue #18). --- Manager/src/cmdparser.cpp | 9 ++++++- VCamUtils/src/ipcbridge.h | 3 ++- cmio/PlatformUtils/src/preferences.cpp | 31 ++++++++++++++++++++++--- cmio/PlatformUtils/src/preferences.h | 4 +++- cmio/VCamIPC/src/ipcbridge.mm | 5 ++-- dshow/PlatformUtils/src/preferences.cpp | 30 ++++++++++++++++++++++-- dshow/PlatformUtils/src/preferences.h | 4 +++- dshow/VCamIPC/src/ipcbridge.cpp | 5 ++-- dshow/VirtualCamera/src/pin.cpp | 2 +- 9 files changed, 79 insertions(+), 14 deletions(-) diff --git a/Manager/src/cmdparser.cpp b/Manager/src/cmdparser.cpp index 00bcf13..9504c1c 100644 --- a/Manager/src/cmdparser.cpp +++ b/Manager/src/cmdparser.cpp @@ -191,6 +191,10 @@ AkVCam::CmdParser::CmdParser() "DESCRIPTION", "Add a new device.", AKVCAM_BIND_FUNC(CmdParserPrivate::addDevice)); + this->addFlags("add-device", + {"-i", "--id"}, + "DEVICEID", + "Create device as DEVICEID."); this->addCommand("remove-device", "DEVICE", "Remove a device.", @@ -843,6 +847,8 @@ int AkVCam::CmdParserPrivate::showDevices(const StringMap &flags, if (devices.empty()) return 0; + std::sort(devices.begin(), devices.end()); + if (this->m_parseable) { for (auto &device: devices) std::cout << device << std::endl; @@ -875,7 +881,8 @@ int AkVCam::CmdParserPrivate::addDevice(const StringMap &flags, return -1; } - auto deviceId = this->m_ipcBridge.addDevice(args[1]); + auto deviceId = this->flagValue(flags, "add-device", "-i"); + deviceId = this->m_ipcBridge.addDevice(args[1], deviceId); if (deviceId.empty()) { std::cerr << "Failed to create device." << std::endl; diff --git a/VCamUtils/src/ipcbridge.h b/VCamUtils/src/ipcbridge.h index 7a66843..fe73ce1 100644 --- a/VCamUtils/src/ipcbridge.h +++ b/VCamUtils/src/ipcbridge.h @@ -145,7 +145,8 @@ namespace AkVCam /* Server */ - std::string addDevice(const std::string &description); + std::string addDevice(const std::string &description, + const std::string &deviceId={}); void removeDevice(const std::string &deviceId); void addFormat(const std::string &deviceId, const VideoFormat &format, diff --git a/cmio/PlatformUtils/src/preferences.cpp b/cmio/PlatformUtils/src/preferences.cpp index cb6a05e..a6bb29e 100644 --- a/cmio/PlatformUtils/src/preferences.cpp +++ b/cmio/PlatformUtils/src/preferences.cpp @@ -285,10 +285,20 @@ void AkVCam::Preferences::sync() kCFPreferencesAnyHost); } -std::string AkVCam::Preferences::addDevice(const std::string &description) +std::string AkVCam::Preferences::addDevice(const std::string &description, + const std::string &deviceId) { AkLogFunction(); - auto path = createDevicePath(); + std::string path; + + if (deviceId.empty()) + path = createDevicePath(); + else if (!idDeviceIdTaken(deviceId)) + path = deviceId; + + if (path.empty()) + return {}; + int cameraIndex = readInt("cameras"); write("cameras", cameraIndex + 1); write("cameras." @@ -388,6 +398,21 @@ size_t AkVCam::Preferences::camerasCount() return size_t(nCameras); } +bool AkVCam::Preferences::idDeviceIdTaken(const std::string &deviceId) +{ + AkLogFunction(); + + // List device paths in use. + std::vector cameraPaths; + + for (size_t i = 0; i < camerasCount(); i++) + cameraPaths.push_back(cameraPath(i)); + + return std::find(cameraPaths.begin(), + cameraPaths.end(), + deviceId) != cameraPaths.end(); +} + std::string AkVCam::Preferences::createDevicePath() { AkLogFunction(); @@ -401,7 +426,7 @@ std::string AkVCam::Preferences::createDevicePath() const int maxId = 64; for (int i = 0; i < maxId; i++) { - /* There are no rules for device paths in Windows. Just append an + /* There are no rules for device paths in Mac. Just append an * incremental index to a common prefix. */ auto path = CMIO_PLUGIN_DEVICE_PREFIX + std::to_string(i); diff --git a/cmio/PlatformUtils/src/preferences.h b/cmio/PlatformUtils/src/preferences.h index 3488969..16fceae 100644 --- a/cmio/PlatformUtils/src/preferences.h +++ b/cmio/PlatformUtils/src/preferences.h @@ -51,7 +51,8 @@ namespace AkVCam void move(const std::string &keyFrom, const std::string &keyTo); void moveAll(const std::string &keyFrom, const std::string &keyTo); void sync(); - std::string addDevice(const std::string &description); + std::string addDevice(const std::string &description, + const std::string &deviceId); std::string addCamera(const std::string &description, const std::vector &formats); std::string addCamera(const std::string &path, @@ -59,6 +60,7 @@ namespace AkVCam const std::vector &formats); void removeCamera(const std::string &path); size_t camerasCount(); + bool idDeviceIdTaken(const std::string &deviceId); std::string createDevicePath(); int cameraFromPath(const std::string &path); bool cameraExists(const std::string &path); diff --git a/cmio/VCamIPC/src/ipcbridge.mm b/cmio/VCamIPC/src/ipcbridge.mm index cced474..396209b 100644 --- a/cmio/VCamIPC/src/ipcbridge.mm +++ b/cmio/VCamIPC/src/ipcbridge.mm @@ -582,11 +582,12 @@ std::string AkVCam::IpcBridge::clientExe(uint64_t pid) const return {path}; } -std::string AkVCam::IpcBridge::addDevice(const std::string &description) +std::string AkVCam::IpcBridge::addDevice(const std::string &description, + const std::string &deviceId) { AkLogFunction(); - return Preferences::addDevice(description); + return Preferences::addDevice(description, deviceId); } void AkVCam::IpcBridge::removeDevice(const std::string &deviceId) diff --git a/dshow/PlatformUtils/src/preferences.cpp b/dshow/PlatformUtils/src/preferences.cpp index 4c53953..003b01a 100644 --- a/dshow/PlatformUtils/src/preferences.cpp +++ b/dshow/PlatformUtils/src/preferences.cpp @@ -223,10 +223,16 @@ bool AkVCam::Preferences::move(const std::string &keyFrom, return ok; } -std::string AkVCam::Preferences::addDevice(const std::string &description) +std::string AkVCam::Preferences::addDevice(const std::string &description, + const std::string &deviceId) { AkLogFunction(); - auto path = createDevicePath(); + std::string path; + + if (deviceId.empty()) + path = createDevicePath(); + else if (!idDeviceIdTaken(deviceId)) + path = deviceId; if (path.empty()) return {}; @@ -336,6 +342,26 @@ size_t AkVCam::Preferences::camerasCount() return size_t(nCameras); } +bool AkVCam::Preferences::idDeviceIdTaken(const std::string &deviceId) +{ + AkLogFunction(); + + // List device paths in use. + std::vector cameraPaths; + + for (size_t i = 0; i < camerasCount(); i++) + cameraPaths.push_back(cameraPath(i)); + + // List device CLSIDs in use. + auto cameraClsids = listAllCameras(); + + auto clsid = createClsidFromStr(deviceId); + auto pit = std::find(cameraPaths.begin(), cameraPaths.end(), deviceId); + auto cit = std::find(cameraClsids.begin(), cameraClsids.end(), clsid); + + return pit != cameraPaths.end() || cit != cameraClsids.end(); +} + std::string AkVCam::Preferences::createDevicePath() { AkLogFunction(); diff --git a/dshow/PlatformUtils/src/preferences.h b/dshow/PlatformUtils/src/preferences.h index 55bb82c..113902f 100644 --- a/dshow/PlatformUtils/src/preferences.h +++ b/dshow/PlatformUtils/src/preferences.h @@ -55,7 +55,8 @@ namespace AkVCam bool move(const std::string &keyFrom, const std::string &keyTo, bool global=false); - std::string addDevice(const std::string &description); + std::string addDevice(const std::string &description, + const std::string &deviceId); std::string addCamera(const std::string &description, const std::vector &formats); std::string addCamera(const std::string &path, @@ -63,6 +64,7 @@ namespace AkVCam const std::vector &formats); bool removeCamera(const std::string &path); size_t camerasCount(); + bool idDeviceIdTaken(const std::string &deviceId); std::string createDevicePath(); int cameraFromCLSID(const CLSID &clsid); int cameraFromPath(const std::string &path); diff --git a/dshow/VCamIPC/src/ipcbridge.cpp b/dshow/VCamIPC/src/ipcbridge.cpp index 3fb10d7..3b00052 100644 --- a/dshow/VCamIPC/src/ipcbridge.cpp +++ b/dshow/VCamIPC/src/ipcbridge.cpp @@ -568,11 +568,12 @@ std::string AkVCam::IpcBridge::clientExe(uint64_t pid) const return exe; } -std::string AkVCam::IpcBridge::addDevice(const std::string &description) +std::string AkVCam::IpcBridge::addDevice(const std::string &description, + const std::string &deviceId) { AkLogFunction(); - return Preferences::addDevice(description); + return Preferences::addDevice(description, deviceId); } void AkVCam::IpcBridge::removeDevice(const std::string &deviceId) diff --git a/dshow/VirtualCamera/src/pin.cpp b/dshow/VirtualCamera/src/pin.cpp index 0a26a2a..6bc03aa 100644 --- a/dshow/VirtualCamera/src/pin.cpp +++ b/dshow/VirtualCamera/src/pin.cpp @@ -295,7 +295,7 @@ void AkVCam::Pin::frameReady(const VideoFrame &frame) void AkVCam::Pin::setPicture(const std::string &picture) { AkLogFunction(); - AkLogDebug() << "Picture: " << picture; + AkLogDebug() << "Picture: " << picture << std::endl; this->d->m_testFrame = loadPicture(picture); this->d->updateTestFrame(); this->d->m_mutex.lock();