Added more commands.

This commit is contained in:
Gonzalo Exequiel Pedone 2020-08-10 15:37:33 -03:00
parent 40482cb484
commit 92956cdce2
No known key found for this signature in database
GPG key ID: B8B09E63E9B85BAF
13 changed files with 591 additions and 347 deletions

View file

@ -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);
@ -82,16 +78,20 @@ namespace AkVCam {
int showDevices(const StringMap &flags, const StringVector &args); int showDevices(const StringMap &flags, const StringVector &args);
int addDevice(const StringMap &flags, const StringVector &args); int addDevice(const StringMap &flags, const StringVector &args);
int removeDevice(const StringMap &flags, const StringVector &args); int removeDevice(const StringMap &flags, const StringVector &args);
int removeDevices(const StringMap &flags, const StringVector &args);
int showDeviceType(const StringMap &flags, int showDeviceType(const StringMap &flags,
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);
int addFormat(const StringMap &flags, const StringVector &args); int addFormat(const StringMap &flags, const StringVector &args);
int removeFormat(const StringMap &flags, const StringVector &args); int removeFormat(const StringMap &flags, const StringVector &args);
int update(const StringMap &flags, const StringVector &args); int removeFormats(const StringMap &flags, const StringVector &args);
int update(const StringMap &flags, const StringVector &args);
int loadSettings(const StringMap &flags, const StringVector &args); int loadSettings(const StringMap &flags, const StringVector &args);
int showConnections(const StringMap &flags, int showConnections(const StringMap &flags,
const StringVector &args); const StringVector &args);
@ -99,9 +99,11 @@ namespace AkVCam {
const StringVector &args); const StringVector &args);
int disconnectDevices(const StringMap &flags, int disconnectDevices(const StringMap &flags,
const StringVector &args); const StringVector &args);
int showOptions(const StringMap &flags, const StringVector &args); int showBroadcasters(const StringMap &flags,
int readOption(const StringMap &flags, const StringVector &args); const StringVector &args);
int writeOption(const StringMap &flags, const StringVector &args); int showControls(const StringMap &flags, const StringVector &args);
int readControl(const StringMap &flags, const StringVector &args);
int writeControl(const StringMap &flags, const StringVector &args);
int showClients(const StringMap &flags, const StringVector &args); int showClients(const StringMap &flags, const StringVector &args);
}; };
@ -137,14 +139,22 @@ 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("remove-devices",
"",
"Remove all devices.",
AKVCAM_BIND_FUNC(CmdParserPrivate::removeDevices));
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.",
@ -171,6 +181,10 @@ AkVCam::CmdParser::CmdParser()
"DEVICE INDEX", "DEVICE INDEX",
"Remove device format.", "Remove device format.",
AKVCAM_BIND_FUNC(CmdParserPrivate::removeFormat)); AKVCAM_BIND_FUNC(CmdParserPrivate::removeFormat));
this->addCommand("remove-formats",
"DEVICE",
"Remove all device formats.",
AKVCAM_BIND_FUNC(CmdParserPrivate::removeFormats));
this->addCommand("update", this->addCommand("update",
"", "",
"Update devices.", "Update devices.",
@ -180,29 +194,33 @@ 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("broadcasters",
"DEVICE", "DEVICE",
"Show device options.", "Show devices that sending frames to the device.",
AKVCAM_BIND_FUNC(CmdParserPrivate::showOptions)); AKVCAM_BIND_FUNC(CmdParserPrivate::showBroadcasters));
this->addCommand("get-option", this->addCommand("controls",
"DEVICE OPTION", "DEVICE",
"Read device option.", "Show device controls.",
AKVCAM_BIND_FUNC(CmdParserPrivate::readOption)); AKVCAM_BIND_FUNC(CmdParserPrivate::showControls));
this->addCommand("set-option", this->addCommand("get-control",
"DEVICE OPTION VALUE", "DEVICE CONTROL",
"Write device option value.", "Read device control.",
AKVCAM_BIND_FUNC(CmdParserPrivate::writeOption)); AKVCAM_BIND_FUNC(CmdParserPrivate::readControl));
this->addCommand("set-control",
"DEVICE CONTROL VALUE",
"Write device control value.",
AKVCAM_BIND_FUNC(CmdParserPrivate::writeControl));
this->addCommand("clients", this->addCommand("clients",
"", "",
"Show clients using the camera.", "Show clients using the camera.",
@ -380,13 +398,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 +438,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 +473,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 +585,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 +609,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 +626,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 +638,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,17 +650,17 @@ 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 +710,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;
} }
@ -738,6 +724,19 @@ int AkVCam::CmdParserPrivate::removeDevice(const StringMap &flags,
return 0; return 0;
} }
int AkVCam::CmdParserPrivate::removeDevices(const AkVCam::StringMap &flags,
const AkVCam::StringVector &args)
{
UNUSED(flags);
UNUSED(args);
auto devices = this->m_ipcBridge.devices();
for (auto &device: devices)
this->m_ipcBridge.removeDevice(device);
return 0;
}
int AkVCam::CmdParserPrivate::showDeviceType(const StringMap &flags, int AkVCam::CmdParserPrivate::showDeviceType(const StringMap &flags,
const StringVector &args) const StringVector &args)
{ {
@ -749,11 +748,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 +776,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 +790,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 +854,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 +909,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 +988,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 +997,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;
} }
@ -1000,9 +1028,39 @@ int AkVCam::CmdParserPrivate::removeFormat(const StringMap &flags,
return 0; return 0;
} }
int AkVCam::CmdParserPrivate::removeFormats(const AkVCam::StringMap &flags,
const AkVCam::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;
}
this->m_ipcBridge.setFormats(deviceId, {});
return 0;
}
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,34 +1073,188 @@ 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;
} }
int AkVCam::CmdParserPrivate::showOptions(const StringMap &flags, int AkVCam::CmdParserPrivate::showBroadcasters(const AkVCam::StringMap &flags,
const AkVCam::StringVector &args)
{
UNUSED(flags);
if (args.size() < 2) {
std::cerr << "Not enough arguments." << std::endl;
return -1;
}
auto ouputDevice = args[1];
auto devices = this->m_ipcBridge.devices();
auto it = std::find(devices.begin(), devices.end(), ouputDevice);
if (it == devices.end()) {
std::cerr << ouputDevice << " doesn't exists." << std::endl;
return -1;
}
if (this->m_ipcBridge.deviceType(ouputDevice) != IpcBridge::DeviceTypeOutput) {
std::cerr << ouputDevice << " is not an output." << std::endl;
return -1;
}
std::cout << this->m_ipcBridge.broadcaster(ouputDevice) << std::endl;
return 0;
}
int AkVCam::CmdParserPrivate::showControls(const StringMap &flags,
const StringVector &args) const StringVector &args)
{ {
return 0; return 0;
} }
int AkVCam::CmdParserPrivate::readOption(const StringMap &flags, int AkVCam::CmdParserPrivate::readControl(const StringMap &flags,
const StringVector &args) const StringVector &args)
{ {
return 0; return 0;
} }
int AkVCam::CmdParserPrivate::writeOption(const StringMap &flags, int AkVCam::CmdParserPrivate::writeControl(const StringMap &flags,
const StringVector &args) const StringVector &args)
{ {
return 0; return 0;
@ -1051,6 +1263,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;
} }

View file

@ -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;
@ -134,6 +136,8 @@ namespace AkVCam
// Return supported formats for the device. // Return supported formats for the device.
std::vector<VideoFormat> formats(const std::string &deviceId) const; std::vector<VideoFormat> formats(const std::string &deviceId) const;
void setFormats(const std::string &deviceId,
const std::vector<VideoFormat> &formats);
// Return return the status of the device. // Return return the status of the device.
std::string broadcaster(const std::string &deviceId) const; std::string broadcaster(const std::string &deviceId) const;
@ -172,26 +176,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();

View file

@ -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())

View file

@ -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);
} }

View file

@ -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);

View file

@ -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."
@ -501,6 +511,35 @@ std::vector<AkVCam::VideoFormat> AkVCam::Preferences::cameraFormats(size_t camer
return formats; return formats;
} }
void AkVCam::Preferences::cameraSetFormats(size_t cameraIndex,
const std::vector<AkVCam::VideoFormat> &formats)
{
AkLogFunction();
if (cameraIndex >= camerasCount())
return;
write("cameras."
+ std::to_string(cameraIndex)
+ ".formats",
int(formats.size()));
for (size_t i = 0; i < formats.size(); i++) {
auto &format = formats[i];
auto prefix = "cameras."
+ std::to_string(cameraIndex)
+ ".formats."
+ std::to_string(i);
auto formatStr = VideoFormat::stringFromFourcc(format.fourcc());
write(prefix + ".format", formatStr);
write(prefix + ".width", format.width());
write(prefix + ".height", format.height());
write(prefix + ".fps", format.minimumFrameRate().toString());
}
sync();
}
void AkVCam::Preferences::cameraAddFormat(size_t cameraIndex, void AkVCam::Preferences::cameraAddFormat(size_t cameraIndex,
const AkVCam::VideoFormat &format, const AkVCam::VideoFormat &format,
int index) int index)
@ -537,7 +576,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,32 +610,71 @@ 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;
auto connections = readStringList("cameras."
+ std::to_string(cameraIndex)
+ ".connections");
for (auto &connection: connections) { if (cameraIsInput(cameraIndex)) {
if (connection.empty()) auto connections = readStringList("cameras."
continue; + std::to_string(cameraIndex)
+ ".connections");
size_t pos = 0; for (auto &connection: connections) {
auto outputIndex = std::stoi(connection, &pos); if (connection.empty())
continue;
if (pos == connection.size()) size_t pos = 0;
cameraConnections.push_back(cameraPath(outputIndex)); auto outputIndex = std::stoi(connection, &pos);
if (pos == connection.size())
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);
} }

View file

@ -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,18 +70,24 @@ 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);
std::vector<VideoFormat> cameraFormats(size_t cameraIndex); std::vector<VideoFormat> cameraFormats(size_t cameraIndex);
void cameraSetFormats(size_t cameraIndex,
const std::vector<VideoFormat> &formats);
void cameraFormats(size_t cameraIndex,
const std::vector<VideoFormat> &formats);
void cameraAddFormat(size_t cameraIndex, void cameraAddFormat(size_t cameraIndex,
const VideoFormat &format, const VideoFormat &format,
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);
} }
} }

View file

@ -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;
cstr, auto cstr = new char[maxLen];
CFIndex(len), memset(cstr, 0, maxLen);
kCFStringEncodingUTF8);
if (!CFStringGetCString(CFStringRef(cfType),
cstr,
maxLen,
kCFStringEncodingUTF8)) {
delete [] cstr;
return {};
}
std::string str(cstr, len); std::string str(cstr, len);
delete [] cstr; delete [] cstr;

View file

@ -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,25 @@ 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); void AkVCam::IpcBridge::setFormats(const std::string &deviceId,
xpc_dictionary_set_int64(dictionary, "message", AKVCAM_ASSISTANT_MSG_DEVICE_FORMATS); const std::vector<VideoFormat> &formats)
xpc_dictionary_set_string(dictionary, "device", deviceId.c_str()); {
auto reply = xpc_connection_send_message_with_reply_sync(this->d->m_serverMessagePort, auto cameraIndex = Preferences::cameraFromPath(deviceId);
dictionary);
xpc_release(dictionary);
auto replyType = xpc_get_type(reply);
if (replyType != XPC_TYPE_DICTIONARY) { return Preferences::cameraSetFormats(cameraIndex, formats);
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 +643,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 +678,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()

View file

@ -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(),

View file

@ -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):

View file

@ -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

View 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.