Very basic camera management commands working.
This commit is contained in:
parent
40482cb484
commit
277e479269
27 changed files with 445 additions and 331 deletions
|
@ -63,10 +63,6 @@ namespace AkVCam {
|
||||||
size_t maxFlagsValueLength(const std::vector<CmdParserFlags> &flags);
|
size_t maxFlagsValueLength(const std::vector<CmdParserFlags> &flags);
|
||||||
size_t maxStringLength(const StringVector &strings);
|
size_t maxStringLength(const StringVector &strings);
|
||||||
size_t maxStringLength(const WStringVector &strings);
|
size_t maxStringLength(const WStringVector &strings);
|
||||||
std::string fill(const std::string &str, size_t maxSize);
|
|
||||||
std::wstring fill(const std::wstring &str, size_t maxSize);
|
|
||||||
std::string join(const StringVector &strings,
|
|
||||||
const std::string &separator);
|
|
||||||
CmdParserCommand *parserCommand(const std::string &command);
|
CmdParserCommand *parserCommand(const std::string &command);
|
||||||
const CmdParserFlags *parserFlag(const std::vector<CmdParserFlags> &cmdFlags,
|
const CmdParserFlags *parserFlag(const std::vector<CmdParserFlags> &cmdFlags,
|
||||||
const std::string &flag);
|
const std::string &flag);
|
||||||
|
@ -86,6 +82,8 @@ namespace AkVCam {
|
||||||
const StringVector &args);
|
const StringVector &args);
|
||||||
int showDeviceDescription(const StringMap &flags,
|
int showDeviceDescription(const StringMap &flags,
|
||||||
const StringVector &args);
|
const StringVector &args);
|
||||||
|
int setDeviceDescription(const StringMap &flags,
|
||||||
|
const StringVector &args);
|
||||||
int showSupportedFormats(const StringMap &flags,
|
int showSupportedFormats(const StringMap &flags,
|
||||||
const StringVector &args);
|
const StringVector &args);
|
||||||
int showFormats(const StringMap &flags, const StringVector &args);
|
int showFormats(const StringMap &flags, const StringVector &args);
|
||||||
|
@ -137,14 +135,18 @@ AkVCam::CmdParser::CmdParser()
|
||||||
"DEVICE",
|
"DEVICE",
|
||||||
"Remove a device.",
|
"Remove a device.",
|
||||||
AKVCAM_BIND_FUNC(CmdParserPrivate::removeDevice));
|
AKVCAM_BIND_FUNC(CmdParserPrivate::removeDevice));
|
||||||
this->addCommand("device-type",
|
this->addCommand("type",
|
||||||
"DEVICE",
|
"DEVICE",
|
||||||
"Show device type.",
|
"Show device type.",
|
||||||
AKVCAM_BIND_FUNC(CmdParserPrivate::showDeviceType));
|
AKVCAM_BIND_FUNC(CmdParserPrivate::showDeviceType));
|
||||||
this->addCommand("device-description",
|
this->addCommand("description",
|
||||||
"DEVICE",
|
"DEVICE",
|
||||||
"Show device description.",
|
"Show device description.",
|
||||||
AKVCAM_BIND_FUNC(CmdParserPrivate::showDeviceDescription));
|
AKVCAM_BIND_FUNC(CmdParserPrivate::showDeviceDescription));
|
||||||
|
this->addCommand("set-description",
|
||||||
|
"DEVICE DESCRIPTION",
|
||||||
|
"Set device description.",
|
||||||
|
AKVCAM_BIND_FUNC(CmdParserPrivate::setDeviceDescription));
|
||||||
this->addCommand("supported-formats",
|
this->addCommand("supported-formats",
|
||||||
"",
|
"",
|
||||||
"Show supported formats.",
|
"Show supported formats.",
|
||||||
|
@ -180,15 +182,15 @@ AkVCam::CmdParser::CmdParser()
|
||||||
"Create devices from a setting file.",
|
"Create devices from a setting file.",
|
||||||
AKVCAM_BIND_FUNC(CmdParserPrivate::loadSettings));
|
AKVCAM_BIND_FUNC(CmdParserPrivate::loadSettings));
|
||||||
this->addCommand("connections",
|
this->addCommand("connections",
|
||||||
"[DEVICE]",
|
"DEVICE",
|
||||||
"Show device connections.",
|
"Show device connections.",
|
||||||
AKVCAM_BIND_FUNC(CmdParserPrivate::showConnections));
|
AKVCAM_BIND_FUNC(CmdParserPrivate::showConnections));
|
||||||
this->addCommand("connect",
|
this->addCommand("connect",
|
||||||
"OUTPUT_DEVICE INPUTDEVICE [INPUT_DEVICE ...]",
|
"INPUT_DEVICE OUTPUTDEVICE [OUTPUT_DEVICE ...]",
|
||||||
"Connect devices.",
|
"Connect devices.",
|
||||||
AKVCAM_BIND_FUNC(CmdParserPrivate::connectDevices));
|
AKVCAM_BIND_FUNC(CmdParserPrivate::connectDevices));
|
||||||
this->addCommand("disconnect",
|
this->addCommand("disconnect",
|
||||||
"OUTPUT_DEVICE INPUTDEVICE",
|
"INPUT_DEVICE OUTPUTDEVICE",
|
||||||
"Disconnect devices.",
|
"Disconnect devices.",
|
||||||
AKVCAM_BIND_FUNC(CmdParserPrivate::disconnectDevices));
|
AKVCAM_BIND_FUNC(CmdParserPrivate::disconnectDevices));
|
||||||
this->addCommand("options",
|
this->addCommand("options",
|
||||||
|
@ -380,13 +382,13 @@ void AkVCam::CmdParserPrivate::printFlags(const std::vector<CmdParserFlags> &cmd
|
||||||
auto maxFlagsValueLen = this->maxFlagsValueLength(cmdFlags);
|
auto maxFlagsValueLen = this->maxFlagsValueLength(cmdFlags);
|
||||||
|
|
||||||
for (auto &flag: cmdFlags) {
|
for (auto &flag: cmdFlags) {
|
||||||
auto allFlags = this->join(flag.flags, ", ");
|
auto allFlags = join(flag.flags, ", ");
|
||||||
std::cout << std::string(spaces.data(), indent)
|
std::cout << std::string(spaces.data(), indent)
|
||||||
<< this->fill(allFlags, maxFlagsLen);
|
<< fill(allFlags, maxFlagsLen);
|
||||||
|
|
||||||
if (maxFlagsValueLen > 0) {
|
if (maxFlagsValueLen > 0) {
|
||||||
std::cout << " "
|
std::cout << " "
|
||||||
<< this->fill(flag.value, maxFlagsValueLen);
|
<< fill(flag.value, maxFlagsValueLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << " "
|
std::cout << " "
|
||||||
|
@ -420,7 +422,7 @@ size_t AkVCam::CmdParserPrivate::maxFlagsLength(const std::vector<CmdParserFlags
|
||||||
size_t length = 0;
|
size_t length = 0;
|
||||||
|
|
||||||
for (auto &flag: flags)
|
for (auto &flag: flags)
|
||||||
length = std::max(this->join(flag.flags, ", ").size(), length);
|
length = std::max(join(flag.flags, ", ").size(), length);
|
||||||
|
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
@ -455,43 +457,6 @@ size_t AkVCam::CmdParserPrivate::maxStringLength(const WStringVector &strings)
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string AkVCam::CmdParserPrivate::fill(const std::string &str,
|
|
||||||
size_t maxSize)
|
|
||||||
{
|
|
||||||
std::stringstream ss;
|
|
||||||
std::vector<char> spaces(maxSize, ' ');
|
|
||||||
ss << str << std::string(spaces.data(), maxSize - str.size());
|
|
||||||
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::wstring AkVCam::CmdParserPrivate::fill(const std::wstring &str, size_t maxSize)
|
|
||||||
{
|
|
||||||
std::wstringstream ss;
|
|
||||||
std::vector<wchar_t> spaces(maxSize, ' ');
|
|
||||||
ss << str << std::wstring(spaces.data(), maxSize - str.size());
|
|
||||||
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string AkVCam::CmdParserPrivate::join(const StringVector &strings,
|
|
||||||
const std::string &separator)
|
|
||||||
{
|
|
||||||
std::stringstream ss;
|
|
||||||
bool append = false;
|
|
||||||
|
|
||||||
for (auto &str: strings) {
|
|
||||||
if (append)
|
|
||||||
ss << separator;
|
|
||||||
else
|
|
||||||
append = true;
|
|
||||||
|
|
||||||
ss << str;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
AkVCam::CmdParserCommand *AkVCam::CmdParserPrivate::parserCommand(const std::string &command)
|
AkVCam::CmdParserCommand *AkVCam::CmdParserPrivate::parserCommand(const std::string &command)
|
||||||
{
|
{
|
||||||
for (auto &cmd: this->m_commands)
|
for (auto &cmd: this->m_commands)
|
||||||
|
@ -604,9 +569,9 @@ int AkVCam::CmdParserPrivate::showHelp(const StringMap &flags,
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
std::cout << " "
|
std::cout << " "
|
||||||
<< this->fill(cmd.command, maxCmdLen)
|
<< fill(cmd.command, maxCmdLen)
|
||||||
<< " "
|
<< " "
|
||||||
<< this->fill(cmd.arguments, maxArgsLen)
|
<< fill(cmd.arguments, maxArgsLen)
|
||||||
<< " "
|
<< " "
|
||||||
<< cmd.helpString << std::endl;
|
<< cmd.helpString << std::endl;
|
||||||
|
|
||||||
|
@ -628,8 +593,13 @@ int AkVCam::CmdParserPrivate::showDevices(const StringMap &flags,
|
||||||
UNUSED(flags);
|
UNUSED(flags);
|
||||||
UNUSED(args);
|
UNUSED(args);
|
||||||
|
|
||||||
|
auto devices = this->m_ipcBridge.devices();
|
||||||
|
|
||||||
|
if (devices.empty())
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (this->m_parseable) {
|
if (this->m_parseable) {
|
||||||
for (auto &device: this->m_ipcBridge.listDevices())
|
for (auto &device: devices)
|
||||||
std::cout << device << std::endl;
|
std::cout << device << std::endl;
|
||||||
} else {
|
} else {
|
||||||
StringVector devicesColumn;
|
StringVector devicesColumn;
|
||||||
|
@ -640,7 +610,7 @@ int AkVCam::CmdParserPrivate::showDevices(const StringMap &flags,
|
||||||
typesColumn.push_back("Type");
|
typesColumn.push_back("Type");
|
||||||
descriptionsColumn.push_back(L"Description");
|
descriptionsColumn.push_back(L"Description");
|
||||||
|
|
||||||
for (auto &device: this->m_ipcBridge.listDevices()) {
|
for (auto &device: devices) {
|
||||||
devicesColumn.push_back(device);
|
devicesColumn.push_back(device);
|
||||||
typesColumn.push_back(this->m_ipcBridge.deviceType(device) == IpcBridge::DeviceTypeInput?
|
typesColumn.push_back(this->m_ipcBridge.deviceType(device) == IpcBridge::DeviceTypeInput?
|
||||||
"Input":
|
"Input":
|
||||||
|
@ -652,11 +622,11 @@ int AkVCam::CmdParserPrivate::showDevices(const StringMap &flags,
|
||||||
auto typesColumnSize = this->maxStringLength(typesColumn);
|
auto typesColumnSize = this->maxStringLength(typesColumn);
|
||||||
auto descriptionsColumnSize = this->maxStringLength(descriptionsColumn);
|
auto descriptionsColumnSize = this->maxStringLength(descriptionsColumn);
|
||||||
|
|
||||||
std::cout << this->fill("Device", devicesColumnSize)
|
std::cout << fill("Device", devicesColumnSize)
|
||||||
<< " | "
|
<< " | "
|
||||||
<< this->fill("Type", typesColumnSize)
|
<< fill("Type", typesColumnSize)
|
||||||
<< " | "
|
<< " | "
|
||||||
<< this->fill("Description", descriptionsColumnSize)
|
<< fill("Description", descriptionsColumnSize)
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
std::cout << std::string("-")
|
std::cout << std::string("-")
|
||||||
* (devicesColumnSize
|
* (devicesColumnSize
|
||||||
|
@ -664,16 +634,16 @@ int AkVCam::CmdParserPrivate::showDevices(const StringMap &flags,
|
||||||
+ descriptionsColumnSize
|
+ descriptionsColumnSize
|
||||||
+ 6) << std::endl;
|
+ 6) << std::endl;
|
||||||
|
|
||||||
for (auto &device: this->m_ipcBridge.listDevices()) {
|
for (auto &device: devices) {
|
||||||
std::string type =
|
std::string type =
|
||||||
this->m_ipcBridge.deviceType(device) == IpcBridge::DeviceTypeInput?
|
this->m_ipcBridge.deviceType(device) == IpcBridge::DeviceTypeInput?
|
||||||
"Input":
|
"Input":
|
||||||
"Output";
|
"Output";
|
||||||
std::cout << this->fill(device, devicesColumnSize)
|
std::cout << fill(device, devicesColumnSize)
|
||||||
<< " | "
|
<< " | "
|
||||||
<< this->fill(type, typesColumnSize)
|
<< fill(type, typesColumnSize)
|
||||||
<< " | ";
|
<< " | ";
|
||||||
std::wcout << this->fill(this->m_ipcBridge.description(device),
|
std::wcout << fill(this->m_ipcBridge.description(device),
|
||||||
descriptionsColumnSize)
|
descriptionsColumnSize)
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
|
@ -724,11 +694,11 @@ int AkVCam::CmdParserPrivate::removeDevice(const StringMap &flags,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto devices = this->m_ipcBridge.listDevices();
|
auto devices = this->m_ipcBridge.devices();
|
||||||
auto it = std::find(devices.begin(), devices.end(), args[1]);
|
auto it = std::find(devices.begin(), devices.end(), args[1]);
|
||||||
|
|
||||||
if (it == devices.end()) {
|
if (it == devices.end()) {
|
||||||
std::cerr << "Device not doesn't exists." << std::endl;
|
std::cerr << "Device doesn't exists." << std::endl;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -749,11 +719,11 @@ int AkVCam::CmdParserPrivate::showDeviceType(const StringMap &flags,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto devices = this->m_ipcBridge.listDevices();
|
auto devices = this->m_ipcBridge.devices();
|
||||||
auto it = std::find(devices.begin(), devices.end(), args[1]);
|
auto it = std::find(devices.begin(), devices.end(), args[1]);
|
||||||
|
|
||||||
if (it == devices.end()) {
|
if (it == devices.end()) {
|
||||||
std::cerr << "Device not doesn't exists." << std::endl;
|
std::cerr << "device doesn't exists." << std::endl;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -777,11 +747,11 @@ int AkVCam::CmdParserPrivate::showDeviceDescription(const StringMap &flags,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto devices = this->m_ipcBridge.listDevices();
|
auto devices = this->m_ipcBridge.devices();
|
||||||
auto it = std::find(devices.begin(), devices.end(), args[1]);
|
auto it = std::find(devices.begin(), devices.end(), args[1]);
|
||||||
|
|
||||||
if (it == devices.end()) {
|
if (it == devices.end()) {
|
||||||
std::cerr << "Device not doesn't exists." << std::endl;
|
std::cerr << "Device doesn't exists." << std::endl;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -791,6 +761,33 @@ int AkVCam::CmdParserPrivate::showDeviceDescription(const StringMap &flags,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int AkVCam::CmdParserPrivate::setDeviceDescription(const AkVCam::StringMap &flags,
|
||||||
|
const AkVCam::StringVector &args)
|
||||||
|
{
|
||||||
|
UNUSED(flags);
|
||||||
|
|
||||||
|
if (args.size() < 3) {
|
||||||
|
std::cerr << "Not enough arguments." << std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto deviceId = args[1];
|
||||||
|
auto devices = this->m_ipcBridge.devices();
|
||||||
|
auto dit = std::find(devices.begin(), devices.end(), args[1]);
|
||||||
|
|
||||||
|
if (dit == devices.end()) {
|
||||||
|
std::cerr << "device doesn't exists." << std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> cv;
|
||||||
|
this->m_ipcBridge.setDescription(deviceId, cv.from_bytes(args[2]));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int AkVCam::CmdParserPrivate::showSupportedFormats(const StringMap &flags,
|
int AkVCam::CmdParserPrivate::showSupportedFormats(const StringMap &flags,
|
||||||
const StringVector &args)
|
const StringVector &args)
|
||||||
{
|
{
|
||||||
|
@ -828,11 +825,11 @@ int AkVCam::CmdParserPrivate::showFormats(const StringMap &flags,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto devices = this->m_ipcBridge.listDevices();
|
auto devices = this->m_ipcBridge.devices();
|
||||||
auto it = std::find(devices.begin(), devices.end(), args[1]);
|
auto it = std::find(devices.begin(), devices.end(), args[1]);
|
||||||
|
|
||||||
if (it == devices.end()) {
|
if (it == devices.end()) {
|
||||||
std::cerr << "Device not doesn't exists." << std::endl;
|
std::cerr << "device doesn't exists." << std::endl;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -883,11 +880,11 @@ int AkVCam::CmdParserPrivate::addFormat(const StringMap &flags,
|
||||||
}
|
}
|
||||||
|
|
||||||
auto deviceId = args[1];
|
auto deviceId = args[1];
|
||||||
auto devices = this->m_ipcBridge.listDevices();
|
auto devices = this->m_ipcBridge.devices();
|
||||||
auto dit = std::find(devices.begin(), devices.end(), args[1]);
|
auto dit = std::find(devices.begin(), devices.end(), args[1]);
|
||||||
|
|
||||||
if (dit == devices.end()) {
|
if (dit == devices.end()) {
|
||||||
std::cerr << "Device not doesn't exists." << std::endl;
|
std::cerr << "device doesn't exists." << std::endl;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -962,6 +959,8 @@ int AkVCam::CmdParserPrivate::addFormat(const StringMap &flags,
|
||||||
int AkVCam::CmdParserPrivate::removeFormat(const StringMap &flags,
|
int AkVCam::CmdParserPrivate::removeFormat(const StringMap &flags,
|
||||||
const StringVector &args)
|
const StringVector &args)
|
||||||
{
|
{
|
||||||
|
UNUSED(flags);
|
||||||
|
|
||||||
if (args.size() < 3) {
|
if (args.size() < 3) {
|
||||||
std::cerr << "Not enough arguments." << std::endl;
|
std::cerr << "Not enough arguments." << std::endl;
|
||||||
|
|
||||||
|
@ -969,11 +968,11 @@ int AkVCam::CmdParserPrivate::removeFormat(const StringMap &flags,
|
||||||
}
|
}
|
||||||
|
|
||||||
auto deviceId = args[1];
|
auto deviceId = args[1];
|
||||||
auto devices = this->m_ipcBridge.listDevices();
|
auto devices = this->m_ipcBridge.devices();
|
||||||
auto dit = std::find(devices.begin(), devices.end(), args[1]);
|
auto dit = std::find(devices.begin(), devices.end(), args[1]);
|
||||||
|
|
||||||
if (dit == devices.end()) {
|
if (dit == devices.end()) {
|
||||||
std::cerr << "Device not doesn't exists." << std::endl;
|
std::cerr << "device doesn't exists." << std::endl;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1003,6 +1002,10 @@ int AkVCam::CmdParserPrivate::removeFormat(const StringMap &flags,
|
||||||
int AkVCam::CmdParserPrivate::update(const StringMap &flags,
|
int AkVCam::CmdParserPrivate::update(const StringMap &flags,
|
||||||
const StringVector &args)
|
const StringVector &args)
|
||||||
{
|
{
|
||||||
|
UNUSED(flags);
|
||||||
|
UNUSED(args);
|
||||||
|
this->m_ipcBridge.update();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1015,18 +1018,140 @@ int AkVCam::CmdParserPrivate::loadSettings(const AkVCam::StringMap &flags,
|
||||||
int AkVCam::CmdParserPrivate::showConnections(const StringMap &flags,
|
int AkVCam::CmdParserPrivate::showConnections(const StringMap &flags,
|
||||||
const StringVector &args)
|
const StringVector &args)
|
||||||
{
|
{
|
||||||
|
UNUSED(flags);
|
||||||
|
|
||||||
|
if (args.size() < 2) {
|
||||||
|
std::cerr << "Not enough arguments." << std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto deviceId = args[1];
|
||||||
|
auto devices = this->m_ipcBridge.devices();
|
||||||
|
auto dit = std::find(devices.begin(), devices.end(), args[1]);
|
||||||
|
|
||||||
|
if (dit == devices.end()) {
|
||||||
|
std::cerr << "device doesn't exists." << std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &connectedDevice: this->m_ipcBridge.connections(deviceId))
|
||||||
|
std::cout << connectedDevice << std::endl;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int AkVCam::CmdParserPrivate::connectDevices(const StringMap &flags,
|
int AkVCam::CmdParserPrivate::connectDevices(const StringMap &flags,
|
||||||
const StringVector &args)
|
const StringVector &args)
|
||||||
{
|
{
|
||||||
|
UNUSED(flags);
|
||||||
|
|
||||||
|
if (args.size() < 3) {
|
||||||
|
std::cerr << "Not enough arguments." << std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto inputDevice = args[1];
|
||||||
|
auto devices = this->m_ipcBridge.devices();
|
||||||
|
auto it = std::find(devices.begin(), devices.end(), inputDevice);
|
||||||
|
|
||||||
|
if (it == devices.end()) {
|
||||||
|
std::cerr << inputDevice << " doesn't exists." << std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->m_ipcBridge.deviceType(inputDevice) != IpcBridge::DeviceTypeInput) {
|
||||||
|
std::cerr << inputDevice << " is not an input." << std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto outputDevices = this->m_ipcBridge.connections(inputDevice);
|
||||||
|
|
||||||
|
for (size_t i = 2; i < args.size(); i++) {
|
||||||
|
auto &outputDevice = args[i];
|
||||||
|
auto it = std::find(devices.begin(), devices.end(), outputDevice);
|
||||||
|
|
||||||
|
if (it == devices.end()) {
|
||||||
|
std::cerr << outputDevice << " doesn't exists." << std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->m_ipcBridge.deviceType(outputDevice) != IpcBridge::DeviceTypeOutput) {
|
||||||
|
std::cerr << outputDevice << " is not an output." << std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cit = std::find(outputDevices.begin(),
|
||||||
|
outputDevices.end(),
|
||||||
|
outputDevice);
|
||||||
|
|
||||||
|
if (cit == outputDevices.end())
|
||||||
|
outputDevices.push_back(outputDevice);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->m_ipcBridge.setConnections(inputDevice, outputDevices);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int AkVCam::CmdParserPrivate::disconnectDevices(const StringMap &flags,
|
int AkVCam::CmdParserPrivate::disconnectDevices(const StringMap &flags,
|
||||||
const StringVector &args)
|
const StringVector &args)
|
||||||
{
|
{
|
||||||
|
UNUSED(flags);
|
||||||
|
|
||||||
|
if (args.size() < 3) {
|
||||||
|
std::cerr << "Not enough arguments." << std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto inputDevice = args[1];
|
||||||
|
auto devices = this->m_ipcBridge.devices();
|
||||||
|
auto it = std::find(devices.begin(), devices.end(), inputDevice);
|
||||||
|
|
||||||
|
if (it == devices.end()) {
|
||||||
|
std::cerr << inputDevice << " doesn't exists." << std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->m_ipcBridge.deviceType(inputDevice) != IpcBridge::DeviceTypeInput) {
|
||||||
|
std::cerr << inputDevice << " is not an input." << std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto outputDevices = this->m_ipcBridge.connections(inputDevice);
|
||||||
|
auto &outputDevice = args[2];
|
||||||
|
auto dit = std::find(devices.begin(), devices.end(), outputDevice);
|
||||||
|
|
||||||
|
if (dit == devices.end()) {
|
||||||
|
std::cerr << outputDevice << " doesn't exists." << std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->m_ipcBridge.deviceType(outputDevice) != IpcBridge::DeviceTypeOutput) {
|
||||||
|
std::cerr << outputDevice << " is not an output." << std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cit = std::find(outputDevices.begin(),
|
||||||
|
outputDevices.end(),
|
||||||
|
outputDevice);
|
||||||
|
|
||||||
|
if (cit == outputDevices.end())
|
||||||
|
outputDevices.push_back(outputDevice);
|
||||||
|
|
||||||
|
this->m_ipcBridge.setConnections(inputDevice, outputDevices);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1051,6 +1176,50 @@ int AkVCam::CmdParserPrivate::writeOption(const StringMap &flags,
|
||||||
int AkVCam::CmdParserPrivate::showClients(const StringMap &flags,
|
int AkVCam::CmdParserPrivate::showClients(const StringMap &flags,
|
||||||
const StringVector &args)
|
const StringVector &args)
|
||||||
{
|
{
|
||||||
|
UNUSED(flags);
|
||||||
|
UNUSED(args);
|
||||||
|
|
||||||
|
auto clients = this->m_ipcBridge.clientsPids();
|
||||||
|
|
||||||
|
if (clients.empty())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (this->m_parseable) {
|
||||||
|
for (auto &pid: clients)
|
||||||
|
std::cout << pid
|
||||||
|
<< " "
|
||||||
|
<< this->m_ipcBridge.clientExe(pid)
|
||||||
|
<< std::endl;
|
||||||
|
} else {
|
||||||
|
StringVector pidsColumn;
|
||||||
|
StringVector exesColumn;
|
||||||
|
|
||||||
|
pidsColumn.push_back("Pid");
|
||||||
|
exesColumn.push_back("Executable");
|
||||||
|
|
||||||
|
for (auto &pid: clients) {
|
||||||
|
pidsColumn.push_back(std::to_string(pid));
|
||||||
|
exesColumn.push_back(this->m_ipcBridge.clientExe(pid));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pidsColumnSize = this->maxStringLength(pidsColumn);
|
||||||
|
auto exesColumnSize = this->maxStringLength(exesColumn);
|
||||||
|
|
||||||
|
std::cout << fill("Pid", pidsColumnSize)
|
||||||
|
<< " | "
|
||||||
|
<< fill("Executable", exesColumnSize)
|
||||||
|
<< std::endl;
|
||||||
|
std::cout << std::string("-")
|
||||||
|
* (pidsColumnSize + exesColumnSize + 4)
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
for (auto &pid: clients)
|
||||||
|
std::cout << fill(std::to_string(pid), pidsColumnSize)
|
||||||
|
<< " | "
|
||||||
|
<< fill(this->m_ipcBridge.clientExe(pid), exesColumnSize)
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -121,10 +121,12 @@ namespace AkVCam
|
||||||
void unregisterPeer();
|
void unregisterPeer();
|
||||||
|
|
||||||
// List available devices.
|
// List available devices.
|
||||||
std::vector<std::string> listDevices() const;
|
std::vector<std::string> devices() const;
|
||||||
|
|
||||||
// Return human readable description of the device.
|
// Return human readable description of the device.
|
||||||
std::wstring description(const std::string &deviceId) const;
|
std::wstring description(const std::string &deviceId) const;
|
||||||
|
void setDescription(const std::string &deviceId,
|
||||||
|
const std::wstring &description);
|
||||||
|
|
||||||
// Output pixel formats supported by the driver.
|
// Output pixel formats supported by the driver.
|
||||||
std::vector<PixelFormat> supportedPixelFormats(DeviceType type) const;
|
std::vector<PixelFormat> supportedPixelFormats(DeviceType type) const;
|
||||||
|
@ -172,26 +174,10 @@ namespace AkVCam
|
||||||
const VideoFormat &format,
|
const VideoFormat &format,
|
||||||
int index=-1);
|
int index=-1);
|
||||||
void removeFormat(const std::string &deviceId, int index);
|
void removeFormat(const std::string &deviceId, int index);
|
||||||
|
void update();
|
||||||
// Create a device definition.
|
std::vector<std::string> connections(const std::string &deviceId);
|
||||||
std::string deviceCreate(const std::wstring &description,
|
void setConnections(const std::string &deviceId,
|
||||||
const std::vector<VideoFormat> &formats,
|
const std::vector<std::string> &connectedDevices);
|
||||||
DeviceType type);
|
|
||||||
|
|
||||||
// Edit a device definition.
|
|
||||||
bool deviceEdit(const std::string &deviceId,
|
|
||||||
const std::wstring &description,
|
|
||||||
const std::vector<VideoFormat> &formats);
|
|
||||||
|
|
||||||
// Change device description.
|
|
||||||
bool changeDescription(const std::string &deviceId,
|
|
||||||
const std::wstring &description);
|
|
||||||
|
|
||||||
// Remove a device definition.
|
|
||||||
bool deviceDestroy(const std::string &deviceId);
|
|
||||||
|
|
||||||
// Remove all device definitions.
|
|
||||||
bool destroyAllDevices();
|
|
||||||
|
|
||||||
void updateDevices();
|
void updateDevices();
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
@ -157,6 +158,39 @@ std::wstring AkVCam::trimmed(const std::wstring &str)
|
||||||
return str.substr(size_t(left), strippedLen);
|
return str.substr(size_t(left), strippedLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string AkVCam::fill(const std::string &str, size_t maxSize)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
std::vector<char> spaces(maxSize, ' ');
|
||||||
|
ss << str << std::string(spaces.data(), maxSize - str.size());
|
||||||
|
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring AkVCam::fill(const std::wstring &str, size_t maxSize)
|
||||||
|
{
|
||||||
|
std::wstringstream ss;
|
||||||
|
std::vector<wchar_t> spaces(maxSize, ' ');
|
||||||
|
ss << str << std::wstring(spaces.data(), maxSize - str.size());
|
||||||
|
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AkVCam::join(const std::vector<std::string> &strs,
|
||||||
|
const std::string &separator)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < strs.size(); i++) {
|
||||||
|
if (i > 0)
|
||||||
|
ss << separator;
|
||||||
|
|
||||||
|
ss << strs[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::string> AkVCam::split(const std::string &str, char separator)
|
std::vector<std::string> AkVCam::split(const std::string &str, char separator)
|
||||||
{
|
{
|
||||||
if (str.empty())
|
if (str.empty())
|
||||||
|
|
|
@ -153,6 +153,10 @@ namespace AkVCam
|
||||||
bool isEqualFile(const std::wstring &file1, const std::wstring &file2);
|
bool isEqualFile(const std::wstring &file1, const std::wstring &file2);
|
||||||
std::string trimmed(const std::string &str);
|
std::string trimmed(const std::string &str);
|
||||||
std::wstring trimmed(const std::wstring &str);
|
std::wstring trimmed(const std::wstring &str);
|
||||||
|
std::string fill(const std::string &str, size_t maxSize);
|
||||||
|
std::wstring fill(const std::wstring &str, size_t maxSize);
|
||||||
|
std::string join(const std::vector<std::string> &strs,
|
||||||
|
const std::string &separator);
|
||||||
std::vector<std::string> split(const std::string &str, char separator);
|
std::vector<std::string> split(const std::string &str, char separator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ int main(int argc, char **argv)
|
||||||
auto loglevel =
|
auto loglevel =
|
||||||
AkVCam::Preferences::readInt("loglevel", AKVCAM_LOGLEVEL_DEFAULT);
|
AkVCam::Preferences::readInt("loglevel", AKVCAM_LOGLEVEL_DEFAULT);
|
||||||
AkVCam::Logger::setLogLevel(loglevel);
|
AkVCam::Logger::setLogLevel(loglevel);
|
||||||
|
AkLogDebug() << "Creating Service: " << CMIO_ASSISTANT_NAME << std::endl;
|
||||||
auto server =
|
auto server =
|
||||||
xpc_connection_create_mach_service(CMIO_ASSISTANT_NAME,
|
xpc_connection_create_mach_service(CMIO_ASSISTANT_NAME,
|
||||||
NULL,
|
NULL,
|
||||||
|
@ -50,6 +51,8 @@ int main(int argc, char **argv)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AkLogDebug() << "Setting up handler" << std::endl;
|
||||||
|
|
||||||
xpc_connection_set_event_handler(server, ^(xpc_object_t event) {
|
xpc_connection_set_event_handler(server, ^(xpc_object_t event) {
|
||||||
auto type = xpc_get_type(event);
|
auto type = xpc_get_type(event);
|
||||||
|
|
||||||
|
@ -70,7 +73,9 @@ int main(int argc, char **argv)
|
||||||
xpc_connection_resume(client);
|
xpc_connection_resume(client);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AkLogDebug() << "Resuming connection" << std::endl;
|
||||||
xpc_connection_resume(server);
|
xpc_connection_resume(server);
|
||||||
|
AkLogDebug() << "Running loop" << std::endl;
|
||||||
CFRunLoopRun();
|
CFRunLoopRun();
|
||||||
xpc_release(server);
|
xpc_release(server);
|
||||||
|
|
||||||
|
|
|
@ -103,6 +103,13 @@ void AkVCam::Preferences::write(const std::string &key, double value)
|
||||||
CFPreferencesSetAppValue(CFStringRef(*cfKey), *cfValue, PREFERENCES_ID);
|
CFPreferencesSetAppValue(CFStringRef(*cfKey), *cfValue, PREFERENCES_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AkVCam::Preferences::write(const std::string &key,
|
||||||
|
std::vector<std::string> &value)
|
||||||
|
{
|
||||||
|
AkLogFunction();
|
||||||
|
write(key, join(value, ","));
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<CFTypeRef> AkVCam::Preferences::read(const std::string &key)
|
std::shared_ptr<CFTypeRef> AkVCam::Preferences::read(const std::string &key)
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
|
@ -418,7 +425,7 @@ std::string AkVCam::Preferences::createDevicePath()
|
||||||
int AkVCam::Preferences::cameraFromPath(const std::string &path)
|
int AkVCam::Preferences::cameraFromPath(const std::string &path)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < camerasCount(); i++)
|
for (size_t i = 0; i < camerasCount(); i++)
|
||||||
if (cameraPath(i) == path && !cameraFormats(i).empty())
|
if (cameraPath(i) == path)
|
||||||
return int(i);
|
return int(i);
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -438,23 +445,26 @@ bool AkVCam::Preferences::cameraIsInput(size_t cameraIndex)
|
||||||
return readBool("cameras." + std::to_string(cameraIndex) + ".isinput");
|
return readBool("cameras." + std::to_string(cameraIndex) + ".isinput");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AkVCam::Preferences::cameraIsInput(const std::string &path)
|
|
||||||
{
|
|
||||||
auto cameraIndex = cameraFromPath(path);
|
|
||||||
|
|
||||||
if (cameraIndex < 0)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
return cameraIsInput(cameraIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::wstring AkVCam::Preferences::cameraDescription(size_t cameraIndex)
|
std::wstring AkVCam::Preferences::cameraDescription(size_t cameraIndex)
|
||||||
{
|
{
|
||||||
|
if (cameraIndex >= camerasCount())
|
||||||
|
return {};
|
||||||
|
|
||||||
return readWString("cameras."
|
return readWString("cameras."
|
||||||
+ std::to_string(cameraIndex)
|
+ std::to_string(cameraIndex)
|
||||||
+ ".description");
|
+ ".description");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AkVCam::Preferences::cameraSetDescription(size_t cameraIndex,
|
||||||
|
const std::wstring &description)
|
||||||
|
{
|
||||||
|
if (cameraIndex >= camerasCount())
|
||||||
|
return;
|
||||||
|
|
||||||
|
write("cameras." + std::to_string(cameraIndex) + ".description",
|
||||||
|
description);
|
||||||
|
}
|
||||||
|
|
||||||
std::string AkVCam::Preferences::cameraPath(size_t cameraIndex)
|
std::string AkVCam::Preferences::cameraPath(size_t cameraIndex)
|
||||||
{
|
{
|
||||||
return readString("cameras."
|
return readString("cameras."
|
||||||
|
@ -537,7 +547,7 @@ void AkVCam::Preferences::cameraRemoveFormat(size_t cameraIndex, int index)
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
|
|
||||||
if (cameraIndex < 0 || !cameraIsInput(cameraIndex))
|
if (!cameraIsInput(cameraIndex))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto formats = cameraFormats(cameraIndex);
|
auto formats = cameraFormats(cameraIndex);
|
||||||
|
@ -571,11 +581,9 @@ void AkVCam::Preferences::cameraRemoveFormat(size_t cameraIndex, int index)
|
||||||
std::vector<std::string> AkVCam::Preferences::cameraConnections(size_t cameraIndex)
|
std::vector<std::string> AkVCam::Preferences::cameraConnections(size_t cameraIndex)
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
|
|
||||||
if (cameraIndex < 0 || !cameraIsInput(cameraIndex))
|
|
||||||
return {};
|
|
||||||
|
|
||||||
std::vector<std::string> cameraConnections;
|
std::vector<std::string> cameraConnections;
|
||||||
|
|
||||||
|
if (cameraIsInput(cameraIndex)) {
|
||||||
auto connections = readStringList("cameras."
|
auto connections = readStringList("cameras."
|
||||||
+ std::to_string(cameraIndex)
|
+ std::to_string(cameraIndex)
|
||||||
+ ".connections");
|
+ ".connections");
|
||||||
|
@ -590,13 +598,54 @@ std::vector<std::string> AkVCam::Preferences::cameraConnections(size_t cameraInd
|
||||||
if (pos == connection.size())
|
if (pos == connection.size())
|
||||||
cameraConnections.push_back(cameraPath(outputIndex));
|
cameraConnections.push_back(cameraPath(outputIndex));
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
for (size_t i = 0; i < camerasCount(); i++)
|
||||||
|
if (cameraIsInput(i)) {
|
||||||
|
auto connections = readStringList("cameras."
|
||||||
|
+ std::to_string(i)
|
||||||
|
+ ".connections");
|
||||||
|
|
||||||
|
for (auto &connection: connections) {
|
||||||
|
if (connection.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
size_t pos = 0;
|
||||||
|
auto outputIndex = std::stoi(connection, &pos);
|
||||||
|
|
||||||
|
if (pos == connection.size() && size_t(outputIndex) == cameraIndex)
|
||||||
|
cameraConnections.push_back(cameraPath(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return cameraConnections;
|
return cameraConnections;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> AkVCam::Preferences::cameraConnections(const std::string &path)
|
void AkVCam::Preferences::cameraSetConnections(size_t cameraIndex,
|
||||||
|
const std::vector<std::string> &connectedDevices)
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
|
|
||||||
return cameraConnections(cameraFromPath(path));
|
if (!cameraIsInput(cameraIndex))
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::vector<std::string> connections;
|
||||||
|
|
||||||
|
for (auto &connection: connectedDevices) {
|
||||||
|
if (connection.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto outputIndex = cameraFromPath(connection);
|
||||||
|
|
||||||
|
if (outputIndex < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (cameraIsInput(outputIndex))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
connections.push_back(std::to_string(outputIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
write("cameras." + std::to_string(cameraIndex) + ".connections",
|
||||||
|
connections);
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ namespace AkVCam
|
||||||
void write(const std::string &key, const std::wstring &value);
|
void write(const std::string &key, const std::wstring &value);
|
||||||
void write(const std::string &key, int value);
|
void write(const std::string &key, int value);
|
||||||
void write(const std::string &key, double value);
|
void write(const std::string &key, double value);
|
||||||
|
void write(const std::string &key, std::vector<std::string> &value);
|
||||||
std::shared_ptr<CFTypeRef> read(const std::string &key);
|
std::shared_ptr<CFTypeRef> read(const std::string &key);
|
||||||
std::string readString(const std::string &key,
|
std::string readString(const std::string &key,
|
||||||
const std::string &defaultValue={});
|
const std::string &defaultValue={});
|
||||||
|
@ -69,8 +70,9 @@ namespace AkVCam
|
||||||
int cameraFromPath(const std::string &path);
|
int cameraFromPath(const std::string &path);
|
||||||
bool cameraExists(const std::string &path);
|
bool cameraExists(const std::string &path);
|
||||||
bool cameraIsInput(size_t cameraIndex);
|
bool cameraIsInput(size_t cameraIndex);
|
||||||
bool cameraIsInput(const std::string &path);
|
|
||||||
std::wstring cameraDescription(size_t cameraIndex);
|
std::wstring cameraDescription(size_t cameraIndex);
|
||||||
|
void cameraSetDescription(size_t cameraIndex,
|
||||||
|
const std::wstring &description);
|
||||||
std::string cameraPath(size_t cameraIndex);
|
std::string cameraPath(size_t cameraIndex);
|
||||||
size_t formatsCount(size_t cameraIndex);
|
size_t formatsCount(size_t cameraIndex);
|
||||||
VideoFormat cameraFormat(size_t cameraIndex, size_t formatIndex);
|
VideoFormat cameraFormat(size_t cameraIndex, size_t formatIndex);
|
||||||
|
@ -80,7 +82,8 @@ namespace AkVCam
|
||||||
int index);
|
int index);
|
||||||
void cameraRemoveFormat(size_t cameraIndex, int index);
|
void cameraRemoveFormat(size_t cameraIndex, int index);
|
||||||
std::vector<std::string> cameraConnections(size_t cameraIndex);
|
std::vector<std::string> cameraConnections(size_t cameraIndex);
|
||||||
std::vector<std::string> cameraConnections(const std::string &path);
|
void cameraSetConnections(size_t cameraIndex,
|
||||||
|
const std::vector<std::string> &connectedDevices);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,11 +82,20 @@ std::string AkVCam::stringFromCFType(CFTypeRef cfType)
|
||||||
if (data)
|
if (data)
|
||||||
return std::string(data, len);
|
return std::string(data, len);
|
||||||
|
|
||||||
auto cstr = new char[len];
|
auto maxLen =
|
||||||
CFStringGetCString(CFStringRef(cfType),
|
CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8) + 1;
|
||||||
|
auto cstr = new char[maxLen];
|
||||||
|
memset(cstr, 0, maxLen);
|
||||||
|
|
||||||
|
if (!CFStringGetCString(CFStringRef(cfType),
|
||||||
cstr,
|
cstr,
|
||||||
CFIndex(len),
|
maxLen,
|
||||||
kCFStringEncodingUTF8);
|
kCFStringEncodingUTF8)) {
|
||||||
|
delete [] cstr;
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
std::string str(cstr, len);
|
std::string str(cstr, len);
|
||||||
delete [] cstr;
|
delete [] cstr;
|
||||||
|
|
||||||
|
|
|
@ -323,38 +323,18 @@ void AkVCam::IpcBridge::unregisterPeer()
|
||||||
this->d->m_portName.clear();
|
this->d->m_portName.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> AkVCam::IpcBridge::listDevices() const
|
std::vector<std::string> AkVCam::IpcBridge::devices() const
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
|
auto nCameras = Preferences::camerasCount();
|
||||||
if (!this->d->m_serverMessagePort)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
auto dictionary = xpc_dictionary_create(nullptr, nullptr, 0);
|
|
||||||
xpc_dictionary_set_int64(dictionary, "message", AKVCAM_ASSISTANT_MSG_DEVICES);
|
|
||||||
auto reply = xpc_connection_send_message_with_reply_sync(this->d->m_serverMessagePort,
|
|
||||||
dictionary);
|
|
||||||
xpc_release(dictionary);
|
|
||||||
auto replyType = xpc_get_type(reply);
|
|
||||||
|
|
||||||
if (replyType != XPC_TYPE_DICTIONARY) {
|
|
||||||
xpc_release(reply);
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto devicesList = xpc_dictionary_get_array(reply, "devices");
|
|
||||||
std::vector<std::string> devices;
|
std::vector<std::string> devices;
|
||||||
|
|
||||||
for (size_t i = 0; i < xpc_array_get_count(devicesList); i++)
|
|
||||||
devices.push_back(xpc_array_get_string(devicesList, i));
|
|
||||||
|
|
||||||
xpc_release(reply);
|
|
||||||
|
|
||||||
AkLogInfo() << "Devices:" << std::endl;
|
AkLogInfo() << "Devices:" << std::endl;
|
||||||
|
|
||||||
for (auto &device: devices)
|
for (size_t i = 0; i < nCameras; i++) {
|
||||||
AkLogInfo() << " " << device << std::endl;
|
auto deviceId = Preferences::cameraPath(i);
|
||||||
|
devices.push_back(deviceId);
|
||||||
|
AkLogInfo() << " " << deviceId << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
return devices;
|
return devices;
|
||||||
}
|
}
|
||||||
|
@ -362,37 +342,24 @@ std::vector<std::string> AkVCam::IpcBridge::listDevices() const
|
||||||
std::wstring AkVCam::IpcBridge::description(const std::string &deviceId) const
|
std::wstring AkVCam::IpcBridge::description(const std::string &deviceId) const
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
|
auto cameraIndex = Preferences::cameraFromPath(deviceId);
|
||||||
|
|
||||||
if (!this->d->m_serverMessagePort)
|
return Preferences::cameraDescription(cameraIndex);
|
||||||
return {};
|
}
|
||||||
|
|
||||||
auto dictionary = xpc_dictionary_create(nullptr, nullptr, 0);
|
void AkVCam::IpcBridge::setDescription(const std::string &deviceId,
|
||||||
xpc_dictionary_set_int64(dictionary, "message", AKVCAM_ASSISTANT_MSG_DEVICE_DESCRIPTION);
|
const std::wstring &description)
|
||||||
xpc_dictionary_set_string(dictionary, "device", deviceId.c_str());
|
{
|
||||||
auto reply = xpc_connection_send_message_with_reply_sync(this->d->m_serverMessagePort,
|
AkLogFunction();
|
||||||
dictionary);
|
auto cameraIndex = Preferences::cameraFromPath(deviceId);
|
||||||
xpc_release(dictionary);
|
|
||||||
auto replyType = xpc_get_type(reply);
|
|
||||||
|
|
||||||
if (replyType != XPC_TYPE_DICTIONARY) {
|
return Preferences::cameraSetDescription(cameraIndex, description);
|
||||||
xpc_release(reply);
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t len = 0;
|
|
||||||
auto data = reinterpret_cast<const wchar_t *>(xpc_dictionary_get_data(reply,
|
|
||||||
"description",
|
|
||||||
&len));
|
|
||||||
std::wstring description(data, len / sizeof(wchar_t));
|
|
||||||
xpc_release(reply);
|
|
||||||
|
|
||||||
return description;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<AkVCam::PixelFormat> AkVCam::IpcBridge::supportedPixelFormats(DeviceType type) const
|
std::vector<AkVCam::PixelFormat> AkVCam::IpcBridge::supportedPixelFormats(DeviceType type) const
|
||||||
{
|
{
|
||||||
UNUSED(type);
|
if (type == DeviceTypeInput)
|
||||||
|
return {PixelFormatRGB24};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
PixelFormatRGB32,
|
PixelFormatRGB32,
|
||||||
|
@ -404,48 +371,17 @@ std::vector<AkVCam::PixelFormat> AkVCam::IpcBridge::supportedPixelFormats(Device
|
||||||
|
|
||||||
AkVCam::PixelFormat AkVCam::IpcBridge::defaultPixelFormat(DeviceType type) const
|
AkVCam::PixelFormat AkVCam::IpcBridge::defaultPixelFormat(DeviceType type) const
|
||||||
{
|
{
|
||||||
UNUSED(type);
|
return type == DeviceTypeInput?
|
||||||
|
PixelFormatRGB24:
|
||||||
return PixelFormatYUY2;
|
PixelFormatYUY2;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<AkVCam::VideoFormat> AkVCam::IpcBridge::formats(const std::string &deviceId) const
|
std::vector<AkVCam::VideoFormat> AkVCam::IpcBridge::formats(const std::string &deviceId) const
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
|
auto cameraIndex = Preferences::cameraFromPath(deviceId);
|
||||||
|
|
||||||
if (!this->d->m_serverMessagePort)
|
return Preferences::cameraFormats(cameraIndex);
|
||||||
return {};
|
|
||||||
|
|
||||||
auto dictionary = xpc_dictionary_create(nullptr, nullptr, 0);
|
|
||||||
xpc_dictionary_set_int64(dictionary, "message", AKVCAM_ASSISTANT_MSG_DEVICE_FORMATS);
|
|
||||||
xpc_dictionary_set_string(dictionary, "device", deviceId.c_str());
|
|
||||||
auto reply = xpc_connection_send_message_with_reply_sync(this->d->m_serverMessagePort,
|
|
||||||
dictionary);
|
|
||||||
xpc_release(dictionary);
|
|
||||||
auto replyType = xpc_get_type(reply);
|
|
||||||
|
|
||||||
if (replyType != XPC_TYPE_DICTIONARY) {
|
|
||||||
xpc_release(reply);
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto formatsList = xpc_dictionary_get_array(reply, "formats");
|
|
||||||
std::vector<VideoFormat> formats;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < xpc_array_get_count(formatsList); i++) {
|
|
||||||
auto format = xpc_array_get_dictionary(formatsList, i);
|
|
||||||
auto fourcc = FourCC(xpc_dictionary_get_uint64(format, "fourcc"));
|
|
||||||
auto width = int(xpc_dictionary_get_int64(format, "width"));
|
|
||||||
auto height = int(xpc_dictionary_get_int64(format, "height"));
|
|
||||||
auto fps = Fraction(xpc_dictionary_get_string(format, "fps"));
|
|
||||||
|
|
||||||
formats.push_back(VideoFormat(fourcc, width, height, {fps}));
|
|
||||||
}
|
|
||||||
|
|
||||||
xpc_release(reply);
|
|
||||||
|
|
||||||
return formats;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string AkVCam::IpcBridge::broadcaster(const std::string &deviceId) const
|
std::string AkVCam::IpcBridge::broadcaster(const std::string &deviceId) const
|
||||||
|
@ -699,7 +635,9 @@ std::string AkVCam::IpcBridge::clientExe(uint64_t pid) const
|
||||||
|
|
||||||
AkVCam::IpcBridge::DeviceType AkVCam::IpcBridge::deviceType(const std::string &deviceId)
|
AkVCam::IpcBridge::DeviceType AkVCam::IpcBridge::deviceType(const std::string &deviceId)
|
||||||
{
|
{
|
||||||
return Preferences::cameraIsInput(deviceId)?
|
auto cameraIndex = Preferences::cameraFromPath(deviceId);
|
||||||
|
|
||||||
|
return Preferences::cameraIsInput(cameraIndex)?
|
||||||
DeviceTypeInput:
|
DeviceTypeInput:
|
||||||
DeviceTypeOutput;
|
DeviceTypeOutput;
|
||||||
}
|
}
|
||||||
|
@ -732,124 +670,31 @@ void AkVCam::IpcBridge::removeFormat(const std::string &deviceId, int index)
|
||||||
index);
|
index);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string AkVCam::IpcBridge::deviceCreate(const std::wstring &description,
|
void AkVCam::IpcBridge::update()
|
||||||
const std::vector<VideoFormat> &formats,
|
|
||||||
DeviceType type)
|
|
||||||
{
|
|
||||||
AkLogFunction();
|
|
||||||
|
|
||||||
if (!this->d->m_serverMessagePort || !this->d->m_messagePort) {
|
|
||||||
this->d->m_error = L"Can't register peer";
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto dictionary = xpc_dictionary_create(nullptr, nullptr, 0);
|
|
||||||
xpc_dictionary_set_int64(dictionary, "message", AKVCAM_ASSISTANT_MSG_DEVICE_CREATE);
|
|
||||||
xpc_dictionary_set_string(dictionary, "port", this->d->m_portName.c_str());
|
|
||||||
xpc_dictionary_set_data(dictionary,
|
|
||||||
"description",
|
|
||||||
description.c_str(),
|
|
||||||
description.size() * sizeof(wchar_t));
|
|
||||||
xpc_dictionary_set_bool(dictionary, "isinput", type == DeviceTypeInput);
|
|
||||||
auto formatsList = xpc_array_create(nullptr, 0);
|
|
||||||
|
|
||||||
for (auto &format: formats) {
|
|
||||||
auto dictFormat = xpc_dictionary_create(nullptr, nullptr, 0);
|
|
||||||
xpc_dictionary_set_uint64(dictFormat, "fourcc", format.fourcc());
|
|
||||||
xpc_dictionary_set_int64(dictFormat, "width", format.width());
|
|
||||||
xpc_dictionary_set_int64(dictFormat, "height", format.height());
|
|
||||||
xpc_dictionary_set_string(dictFormat, "fps", format.minimumFrameRate().toString().c_str());
|
|
||||||
xpc_array_append_value(formatsList, dictFormat);
|
|
||||||
}
|
|
||||||
|
|
||||||
xpc_dictionary_set_value(dictionary, "formats", formatsList);
|
|
||||||
|
|
||||||
auto reply = xpc_connection_send_message_with_reply_sync(this->d->m_serverMessagePort,
|
|
||||||
dictionary);
|
|
||||||
xpc_release(dictionary);
|
|
||||||
auto replyType = xpc_get_type(reply);
|
|
||||||
|
|
||||||
if (replyType != XPC_TYPE_DICTIONARY) {
|
|
||||||
this->d->m_error = L"Can't set virtual camera formats";
|
|
||||||
xpc_release(reply);
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string deviceId(xpc_dictionary_get_string(reply, "device"));
|
|
||||||
xpc_release(reply);
|
|
||||||
|
|
||||||
return deviceId;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AkVCam::IpcBridge::deviceEdit(const std::string &deviceId,
|
|
||||||
const std::wstring &description,
|
|
||||||
const std::vector<VideoFormat> &formats)
|
|
||||||
{
|
|
||||||
AkLogFunction();
|
|
||||||
|
|
||||||
auto type = this->deviceType(deviceId);
|
|
||||||
this->deviceDestroy(deviceId);
|
|
||||||
|
|
||||||
if (this->deviceCreate(description.empty()?
|
|
||||||
L"AvKys Virtual Camera":
|
|
||||||
description,
|
|
||||||
formats,
|
|
||||||
type).empty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AkVCam::IpcBridge::changeDescription(const std::string &deviceId,
|
|
||||||
const std::wstring &description)
|
|
||||||
{
|
|
||||||
AkLogFunction();
|
|
||||||
|
|
||||||
auto formats = this->formats(deviceId);
|
|
||||||
|
|
||||||
if (formats.empty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto type = this->deviceType(deviceId);
|
|
||||||
this->deviceDestroy(deviceId);
|
|
||||||
|
|
||||||
if (this->deviceCreate(description.empty()?
|
|
||||||
L"AvKys Virtual Camera":
|
|
||||||
description,
|
|
||||||
formats,
|
|
||||||
type).empty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AkVCam::IpcBridge::deviceDestroy(const std::string &deviceId)
|
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
|
|
||||||
if (!this->d->m_serverMessagePort)
|
if (!this->d->m_serverMessagePort)
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
auto dictionary = xpc_dictionary_create(nullptr, nullptr, 0);
|
auto dictionary = xpc_dictionary_create(nullptr, nullptr, 0);
|
||||||
xpc_dictionary_set_int64(dictionary, "message", AKVCAM_ASSISTANT_MSG_DEVICE_DESTROY);
|
xpc_dictionary_set_int64(dictionary,
|
||||||
xpc_dictionary_set_string(dictionary, "device", deviceId.c_str());
|
"message",
|
||||||
xpc_connection_send_message(this->d->m_serverMessagePort,
|
AKVCAM_ASSISTANT_MSG_DEVICE_UPDATE);
|
||||||
dictionary);
|
xpc_connection_send_message(this->d->m_serverMessagePort, dictionary);
|
||||||
xpc_release(dictionary);
|
xpc_release(dictionary);
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AkVCam::IpcBridge::destroyAllDevices()
|
std::vector<std::string> AkVCam::IpcBridge::connections(const std::string &deviceId)
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
return Preferences::cameraConnections(Preferences::cameraFromPath(deviceId));
|
||||||
|
}
|
||||||
|
|
||||||
for (auto &device: this->listDevices())
|
void AkVCam::IpcBridge::setConnections(const std::string &deviceId,
|
||||||
this->deviceDestroy(device);
|
const std::vector<std::string> &connectedDevices)
|
||||||
|
{
|
||||||
return true;
|
Preferences::cameraSetConnections(Preferences::cameraFromPath(deviceId),
|
||||||
|
connectedDevices);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AkVCam::IpcBridge::updateDevices()
|
void AkVCam::IpcBridge::updateDevices()
|
||||||
|
|
|
@ -234,7 +234,7 @@ OSStatus AkVCam::PluginInterface::InitializeWithObjectID(CMIOObjectID objectID)
|
||||||
|
|
||||||
this->m_objectID = objectID;
|
this->m_objectID = objectID;
|
||||||
|
|
||||||
for (auto deviceId: this->d->m_ipcBridge.listDevices())
|
for (auto &deviceId: this->d->m_ipcBridge.devices())
|
||||||
this->deviceAdded(this, deviceId);
|
this->deviceAdded(this, deviceId);
|
||||||
|
|
||||||
return kCMIOHardwareNoError;
|
return kCMIOHardwareNoError;
|
||||||
|
@ -301,7 +301,7 @@ void AkVCam::PluginInterface::devicesUpdated(void *userData, void *unused)
|
||||||
for (auto &deviceId: devices)
|
for (auto &deviceId: devices)
|
||||||
self->destroyDevice(deviceId);
|
self->destroyDevice(deviceId);
|
||||||
|
|
||||||
for (auto &deviceId: self->d->m_ipcBridge.listDevices()) {
|
for (auto &deviceId: self->d->m_ipcBridge.devices()) {
|
||||||
auto description = self->d->m_ipcBridge.description(deviceId);
|
auto description = self->d->m_ipcBridge.description(deviceId);
|
||||||
auto formats = self->d->m_ipcBridge.formats(deviceId);
|
auto formats = self->d->m_ipcBridge.formats(deviceId);
|
||||||
auto type = self->d->m_ipcBridge.deviceType(deviceId);
|
auto type = self->d->m_ipcBridge.deviceType(deviceId);
|
||||||
|
@ -315,7 +315,8 @@ void AkVCam::PluginInterface::frameReady(void *userData,
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
auto self = reinterpret_cast<PluginInterface *>(userData);
|
auto self = reinterpret_cast<PluginInterface *>(userData);
|
||||||
auto connections = Preferences::cameraConnections(deviceId);
|
auto cameraIndex = Preferences::cameraFromPath(deviceId);
|
||||||
|
auto connections = Preferences::cameraConnections(cameraIndex);
|
||||||
|
|
||||||
for (auto device: self->m_devices)
|
for (auto device: self->m_devices)
|
||||||
if (std::find(connections.begin(),
|
if (std::find(connections.begin(),
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
isEmpty(CMIO_PLUGINS_DAL_PATH):
|
isEmpty(CMIO_PLUGINS_DAL_PATH):
|
||||||
CMIO_PLUGINS_DAL_PATH = /Library/CoreMediaIO/Plug-Ins/DAL
|
CMIO_PLUGINS_DAL_PATH = /Library/CoreMediaIO/Plug-Ins/DAL
|
||||||
isEmpty(CMIO_DAEMONS_PATH):
|
isEmpty(CMIO_DAEMONS_PATH):
|
||||||
CMIO_DAEMONS_PATH = ~/Library/LaunchAgents
|
CMIO_DAEMONS_PATH = /Library/LaunchAgents
|
||||||
isEmpty(CMIO_PLUGIN_NAME):
|
isEmpty(CMIO_PLUGIN_NAME):
|
||||||
CMIO_PLUGIN_NAME = AkVirtualCamera
|
CMIO_PLUGIN_NAME = AkVirtualCamera
|
||||||
isEmpty(CMIO_PLUGIN_ASSISTANT_NAME):
|
isEmpty(CMIO_PLUGIN_ASSISTANT_NAME):
|
||||||
|
|
|
@ -303,7 +303,7 @@ void AkVCam::IpcBridge::unregisterPeer()
|
||||||
this->d->m_portName.clear();
|
this->d->m_portName.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> AkVCam::IpcBridge::listDevices() const
|
std::vector<std::string> AkVCam::IpcBridge::devices() const
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
std::vector<std::string> devices;
|
std::vector<std::string> devices;
|
||||||
|
@ -649,7 +649,7 @@ bool AkVCam::IpcBridge::needsRestart(Operation operation) const
|
||||||
{
|
{
|
||||||
return operation == OperationDestroyAll
|
return operation == OperationDestroyAll
|
||||||
|| (operation == OperationDestroy
|
|| (operation == OperationDestroy
|
||||||
&& this->listDevices().size() == 1);
|
&& this->devices().size() == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AkVCam::IpcBridge::canApply(AkVCam::IpcBridge::Operation operation) const
|
bool AkVCam::IpcBridge::canApply(AkVCam::IpcBridge::Operation operation) const
|
||||||
|
|
0
ports/ci/appveyor/build.bat
Normal file → Executable file
0
ports/ci/appveyor/build.bat
Normal file → Executable file
0
ports/ci/appveyor/build.sh
Executable file → Normal file
0
ports/ci/appveyor/build.sh
Executable file → Normal file
0
ports/ci/appveyor/deploy.bat
Normal file → Executable file
0
ports/ci/appveyor/deploy.bat
Normal file → Executable file
0
ports/ci/appveyor/deploy.sh
Executable file → Normal file
0
ports/ci/appveyor/deploy.sh
Executable file → Normal file
0
ports/ci/appveyor/install_deps.bat
Normal file → Executable file
0
ports/ci/appveyor/install_deps.bat
Normal file → Executable file
0
ports/ci/appveyor/install_deps.sh
Executable file → Normal file
0
ports/ci/appveyor/install_deps.sh
Executable file → Normal file
0
ports/ci/appveyor/push_artifacts.bat
Normal file → Executable file
0
ports/ci/appveyor/push_artifacts.bat
Normal file → Executable file
0
ports/ci/appveyor/upload.bat
Normal file → Executable file
0
ports/ci/appveyor/upload.bat
Normal file → Executable file
0
ports/ci/travis/build.sh
Executable file → Normal file
0
ports/ci/travis/build.sh
Executable file → Normal file
0
ports/ci/travis/deploy.sh
Executable file → Normal file
0
ports/ci/travis/deploy.sh
Executable file → Normal file
0
ports/ci/travis/install_deps.sh
Executable file → Normal file
0
ports/ci/travis/install_deps.sh
Executable file → Normal file
0
ports/ci/travis/upload.sh
Executable file → Normal file
0
ports/ci/travis/upload.sh
Executable file → Normal file
0
ports/deploy/deploy.py
Executable file → Normal file
0
ports/deploy/deploy.py
Executable file → Normal file
|
@ -23,6 +23,15 @@ Component.prototype.createOperations = function()
|
||||||
"rm",
|
"rm",
|
||||||
"-rf",
|
"-rf",
|
||||||
"/Library/CoreMediaIO/Plug-Ins/DAL/@Name@.plugin");
|
"/Library/CoreMediaIO/Plug-Ins/DAL/@Name@.plugin");
|
||||||
|
|
||||||
|
component.addElevatedOperation("Execute",
|
||||||
|
"chmod",
|
||||||
|
"+x",
|
||||||
|
"@TargetDir@/@Name@.plugin/Contents/Resources/AkVCamAssistant");
|
||||||
|
component.addElevatedOperation("Execute",
|
||||||
|
"chmod",
|
||||||
|
"+x",
|
||||||
|
"@TargetDir@/@Name@.plugin/Contents/Resources/AkVCamManager");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a symlink to the plugin.
|
// Create a symlink to the plugin.
|
||||||
|
|
0
share/TestFrame/TestFrame.py
Executable file → Normal file
0
share/TestFrame/TestFrame.py
Executable file → Normal file
Loading…
Reference in a new issue