Very basic camera management commands working.

This commit is contained in:
Gonzalo Exequiel Pedone 2020-08-01 22:01:06 -03:00
parent 40482cb484
commit 277e479269
No known key found for this signature in database
GPG key ID: B8B09E63E9B85BAF
27 changed files with 445 additions and 331 deletions

View file

@ -63,10 +63,6 @@ namespace AkVCam {
size_t maxFlagsValueLength(const std::vector<CmdParserFlags> &flags);
size_t maxStringLength(const StringVector &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);
const CmdParserFlags *parserFlag(const std::vector<CmdParserFlags> &cmdFlags,
const std::string &flag);
@ -86,6 +82,8 @@ namespace AkVCam {
const StringVector &args);
int showDeviceDescription(const StringMap &flags,
const StringVector &args);
int setDeviceDescription(const StringMap &flags,
const StringVector &args);
int showSupportedFormats(const StringMap &flags,
const StringVector &args);
int showFormats(const StringMap &flags, const StringVector &args);
@ -137,14 +135,18 @@ AkVCam::CmdParser::CmdParser()
"DEVICE",
"Remove a device.",
AKVCAM_BIND_FUNC(CmdParserPrivate::removeDevice));
this->addCommand("device-type",
this->addCommand("type",
"DEVICE",
"Show device type.",
AKVCAM_BIND_FUNC(CmdParserPrivate::showDeviceType));
this->addCommand("device-description",
this->addCommand("description",
"DEVICE",
"Show device description.",
AKVCAM_BIND_FUNC(CmdParserPrivate::showDeviceDescription));
this->addCommand("set-description",
"DEVICE DESCRIPTION",
"Set device description.",
AKVCAM_BIND_FUNC(CmdParserPrivate::setDeviceDescription));
this->addCommand("supported-formats",
"",
"Show supported formats.",
@ -180,15 +182,15 @@ AkVCam::CmdParser::CmdParser()
"Create devices from a setting file.",
AKVCAM_BIND_FUNC(CmdParserPrivate::loadSettings));
this->addCommand("connections",
"[DEVICE]",
"DEVICE",
"Show device connections.",
AKVCAM_BIND_FUNC(CmdParserPrivate::showConnections));
this->addCommand("connect",
"OUTPUT_DEVICE INPUTDEVICE [INPUT_DEVICE ...]",
"INPUT_DEVICE OUTPUTDEVICE [OUTPUT_DEVICE ...]",
"Connect devices.",
AKVCAM_BIND_FUNC(CmdParserPrivate::connectDevices));
this->addCommand("disconnect",
"OUTPUT_DEVICE INPUTDEVICE",
"INPUT_DEVICE OUTPUTDEVICE",
"Disconnect devices.",
AKVCAM_BIND_FUNC(CmdParserPrivate::disconnectDevices));
this->addCommand("options",
@ -380,13 +382,13 @@ void AkVCam::CmdParserPrivate::printFlags(const std::vector<CmdParserFlags> &cmd
auto maxFlagsValueLen = this->maxFlagsValueLength(cmdFlags);
for (auto &flag: cmdFlags) {
auto allFlags = this->join(flag.flags, ", ");
auto allFlags = join(flag.flags, ", ");
std::cout << std::string(spaces.data(), indent)
<< this->fill(allFlags, maxFlagsLen);
<< fill(allFlags, maxFlagsLen);
if (maxFlagsValueLen > 0) {
std::cout << " "
<< this->fill(flag.value, maxFlagsValueLen);
<< fill(flag.value, maxFlagsValueLen);
}
std::cout << " "
@ -420,7 +422,7 @@ size_t AkVCam::CmdParserPrivate::maxFlagsLength(const std::vector<CmdParserFlags
size_t length = 0;
for (auto &flag: flags)
length = std::max(this->join(flag.flags, ", ").size(), length);
length = std::max(join(flag.flags, ", ").size(), length);
return length;
}
@ -455,43 +457,6 @@ size_t AkVCam::CmdParserPrivate::maxStringLength(const WStringVector &strings)
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)
{
for (auto &cmd: this->m_commands)
@ -604,9 +569,9 @@ int AkVCam::CmdParserPrivate::showHelp(const StringMap &flags,
continue;
std::cout << " "
<< this->fill(cmd.command, maxCmdLen)
<< fill(cmd.command, maxCmdLen)
<< " "
<< this->fill(cmd.arguments, maxArgsLen)
<< fill(cmd.arguments, maxArgsLen)
<< " "
<< cmd.helpString << std::endl;
@ -628,8 +593,13 @@ int AkVCam::CmdParserPrivate::showDevices(const StringMap &flags,
UNUSED(flags);
UNUSED(args);
auto devices = this->m_ipcBridge.devices();
if (devices.empty())
return 0;
if (this->m_parseable) {
for (auto &device: this->m_ipcBridge.listDevices())
for (auto &device: devices)
std::cout << device << std::endl;
} else {
StringVector devicesColumn;
@ -640,7 +610,7 @@ int AkVCam::CmdParserPrivate::showDevices(const StringMap &flags,
typesColumn.push_back("Type");
descriptionsColumn.push_back(L"Description");
for (auto &device: this->m_ipcBridge.listDevices()) {
for (auto &device: devices) {
devicesColumn.push_back(device);
typesColumn.push_back(this->m_ipcBridge.deviceType(device) == IpcBridge::DeviceTypeInput?
"Input":
@ -652,11 +622,11 @@ int AkVCam::CmdParserPrivate::showDevices(const StringMap &flags,
auto typesColumnSize = this->maxStringLength(typesColumn);
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::cout << std::string("-")
* (devicesColumnSize
@ -664,16 +634,16 @@ int AkVCam::CmdParserPrivate::showDevices(const StringMap &flags,
+ descriptionsColumnSize
+ 6) << std::endl;
for (auto &device: this->m_ipcBridge.listDevices()) {
for (auto &device: devices) {
std::string type =
this->m_ipcBridge.deviceType(device) == IpcBridge::DeviceTypeInput?
"Input":
"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)
<< std::endl;
}
@ -724,11 +694,11 @@ int AkVCam::CmdParserPrivate::removeDevice(const StringMap &flags,
return -1;
}
auto devices = this->m_ipcBridge.listDevices();
auto devices = this->m_ipcBridge.devices();
auto it = std::find(devices.begin(), devices.end(), args[1]);
if (it == devices.end()) {
std::cerr << "Device not doesn't exists." << std::endl;
std::cerr << "Device doesn't exists." << std::endl;
return -1;
}
@ -749,11 +719,11 @@ int AkVCam::CmdParserPrivate::showDeviceType(const StringMap &flags,
return -1;
}
auto devices = this->m_ipcBridge.listDevices();
auto devices = this->m_ipcBridge.devices();
auto it = std::find(devices.begin(), devices.end(), args[1]);
if (it == devices.end()) {
std::cerr << "Device not doesn't exists." << std::endl;
std::cerr << "device doesn't exists." << std::endl;
return -1;
}
@ -777,11 +747,11 @@ int AkVCam::CmdParserPrivate::showDeviceDescription(const StringMap &flags,
return -1;
}
auto devices = this->m_ipcBridge.listDevices();
auto devices = this->m_ipcBridge.devices();
auto it = std::find(devices.begin(), devices.end(), args[1]);
if (it == devices.end()) {
std::cerr << "Device not doesn't exists." << std::endl;
std::cerr << "Device doesn't exists." << std::endl;
return -1;
}
@ -791,6 +761,33 @@ int AkVCam::CmdParserPrivate::showDeviceDescription(const StringMap &flags,
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,
const StringVector &args)
{
@ -828,11 +825,11 @@ int AkVCam::CmdParserPrivate::showFormats(const StringMap &flags,
return -1;
}
auto devices = this->m_ipcBridge.listDevices();
auto devices = this->m_ipcBridge.devices();
auto it = std::find(devices.begin(), devices.end(), args[1]);
if (it == devices.end()) {
std::cerr << "Device not doesn't exists." << std::endl;
std::cerr << "device doesn't exists." << std::endl;
return -1;
}
@ -883,11 +880,11 @@ int AkVCam::CmdParserPrivate::addFormat(const StringMap &flags,
}
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]);
if (dit == devices.end()) {
std::cerr << "Device not doesn't exists." << std::endl;
std::cerr << "device doesn't exists." << std::endl;
return -1;
}
@ -962,6 +959,8 @@ int AkVCam::CmdParserPrivate::addFormat(const StringMap &flags,
int AkVCam::CmdParserPrivate::removeFormat(const StringMap &flags,
const StringVector &args)
{
UNUSED(flags);
if (args.size() < 3) {
std::cerr << "Not enough arguments." << std::endl;
@ -969,11 +968,11 @@ int AkVCam::CmdParserPrivate::removeFormat(const StringMap &flags,
}
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]);
if (dit == devices.end()) {
std::cerr << "Device not doesn't exists." << std::endl;
std::cerr << "device doesn't exists." << std::endl;
return -1;
}
@ -1003,6 +1002,10 @@ int AkVCam::CmdParserPrivate::removeFormat(const StringMap &flags,
int AkVCam::CmdParserPrivate::update(const StringMap &flags,
const StringVector &args)
{
UNUSED(flags);
UNUSED(args);
this->m_ipcBridge.update();
return 0;
}
@ -1015,18 +1018,140 @@ int AkVCam::CmdParserPrivate::loadSettings(const AkVCam::StringMap &flags,
int AkVCam::CmdParserPrivate::showConnections(const StringMap &flags,
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;
}
int AkVCam::CmdParserPrivate::connectDevices(const StringMap &flags,
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;
}
int AkVCam::CmdParserPrivate::disconnectDevices(const StringMap &flags,
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;
}
@ -1051,6 +1176,50 @@ int AkVCam::CmdParserPrivate::writeOption(const StringMap &flags,
int AkVCam::CmdParserPrivate::showClients(const StringMap &flags,
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;
}

View file

@ -121,10 +121,12 @@ namespace AkVCam
void unregisterPeer();
// List available devices.
std::vector<std::string> listDevices() const;
std::vector<std::string> devices() const;
// Return human readable description of the device.
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.
std::vector<PixelFormat> supportedPixelFormats(DeviceType type) const;
@ -172,26 +174,10 @@ namespace AkVCam
const VideoFormat &format,
int index=-1);
void removeFormat(const std::string &deviceId, int index);
// Create a device definition.
std::string deviceCreate(const std::wstring &description,
const std::vector<VideoFormat> &formats,
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 update();
std::vector<std::string> connections(const std::string &deviceId);
void setConnections(const std::string &deviceId,
const std::vector<std::string> &connectedDevices);
void updateDevices();

View file

@ -20,6 +20,7 @@
#include <cstring>
#include <ctime>
#include <fstream>
#include <sstream>
#include "utils.h"
@ -157,6 +158,39 @@ std::wstring AkVCam::trimmed(const std::wstring &str)
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)
{
if (str.empty())

View file

@ -153,6 +153,10 @@ namespace AkVCam
bool isEqualFile(const std::wstring &file1, const std::wstring &file2);
std::string trimmed(const std::string &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);
}

View file

@ -33,6 +33,7 @@ int main(int argc, char **argv)
auto loglevel =
AkVCam::Preferences::readInt("loglevel", AKVCAM_LOGLEVEL_DEFAULT);
AkVCam::Logger::setLogLevel(loglevel);
AkLogDebug() << "Creating Service: " << CMIO_ASSISTANT_NAME << std::endl;
auto server =
xpc_connection_create_mach_service(CMIO_ASSISTANT_NAME,
NULL,
@ -50,6 +51,8 @@ int main(int argc, char **argv)
break;
}
AkLogDebug() << "Setting up handler" << std::endl;
xpc_connection_set_event_handler(server, ^(xpc_object_t event) {
auto type = xpc_get_type(event);
@ -70,7 +73,9 @@ int main(int argc, char **argv)
xpc_connection_resume(client);
});
AkLogDebug() << "Resuming connection" << std::endl;
xpc_connection_resume(server);
AkLogDebug() << "Running loop" << std::endl;
CFRunLoopRun();
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);
}
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)
{
AkLogFunction();
@ -418,7 +425,7 @@ std::string AkVCam::Preferences::createDevicePath()
int AkVCam::Preferences::cameraFromPath(const std::string &path)
{
for (size_t i = 0; i < camerasCount(); i++)
if (cameraPath(i) == path && !cameraFormats(i).empty())
if (cameraPath(i) == path)
return int(i);
return -1;
@ -438,23 +445,26 @@ bool AkVCam::Preferences::cameraIsInput(size_t cameraIndex)
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)
{
if (cameraIndex >= camerasCount())
return {};
return readWString("cameras."
+ std::to_string(cameraIndex)
+ ".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)
{
return readString("cameras."
@ -537,7 +547,7 @@ void AkVCam::Preferences::cameraRemoveFormat(size_t cameraIndex, int index)
{
AkLogFunction();
if (cameraIndex < 0 || !cameraIsInput(cameraIndex))
if (!cameraIsInput(cameraIndex))
return;
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)
{
AkLogFunction();
if (cameraIndex < 0 || !cameraIsInput(cameraIndex))
return {};
std::vector<std::string> cameraConnections;
if (cameraIsInput(cameraIndex)) {
auto connections = readStringList("cameras."
+ std::to_string(cameraIndex)
+ ".connections");
@ -590,13 +598,54 @@ std::vector<std::string> AkVCam::Preferences::cameraConnections(size_t cameraInd
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;
}
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();
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, int 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::string readString(const std::string &key,
const std::string &defaultValue={});
@ -69,8 +70,9 @@ namespace AkVCam
int cameraFromPath(const std::string &path);
bool cameraExists(const std::string &path);
bool cameraIsInput(size_t cameraIndex);
bool cameraIsInput(const std::string &path);
std::wstring cameraDescription(size_t cameraIndex);
void cameraSetDescription(size_t cameraIndex,
const std::wstring &description);
std::string cameraPath(size_t cameraIndex);
size_t formatsCount(size_t cameraIndex);
VideoFormat cameraFormat(size_t cameraIndex, size_t formatIndex);
@ -80,7 +82,8 @@ namespace AkVCam
int index);
void cameraRemoveFormat(size_t cameraIndex, int index);
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)
return std::string(data, len);
auto cstr = new char[len];
CFStringGetCString(CFStringRef(cfType),
auto maxLen =
CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8) + 1;
auto cstr = new char[maxLen];
memset(cstr, 0, maxLen);
if (!CFStringGetCString(CFStringRef(cfType),
cstr,
CFIndex(len),
kCFStringEncodingUTF8);
maxLen,
kCFStringEncodingUTF8)) {
delete [] cstr;
return {};
}
std::string str(cstr, len);
delete [] cstr;

View file

@ -323,38 +323,18 @@ void AkVCam::IpcBridge::unregisterPeer()
this->d->m_portName.clear();
}
std::vector<std::string> AkVCam::IpcBridge::listDevices() const
std::vector<std::string> AkVCam::IpcBridge::devices() const
{
AkLogFunction();
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");
auto nCameras = Preferences::camerasCount();
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;
for (auto &device: devices)
AkLogInfo() << " " << device << std::endl;
for (size_t i = 0; i < nCameras; i++) {
auto deviceId = Preferences::cameraPath(i);
devices.push_back(deviceId);
AkLogInfo() << " " << deviceId << std::endl;
}
return devices;
}
@ -362,37 +342,24 @@ std::vector<std::string> AkVCam::IpcBridge::listDevices() const
std::wstring AkVCam::IpcBridge::description(const std::string &deviceId) const
{
AkLogFunction();
auto cameraIndex = Preferences::cameraFromPath(deviceId);
if (!this->d->m_serverMessagePort)
return {};
return Preferences::cameraDescription(cameraIndex);
}
auto dictionary = xpc_dictionary_create(nullptr, nullptr, 0);
xpc_dictionary_set_int64(dictionary, "message", AKVCAM_ASSISTANT_MSG_DEVICE_DESCRIPTION);
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);
void AkVCam::IpcBridge::setDescription(const std::string &deviceId,
const std::wstring &description)
{
AkLogFunction();
auto cameraIndex = Preferences::cameraFromPath(deviceId);
if (replyType != XPC_TYPE_DICTIONARY) {
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;
return Preferences::cameraSetDescription(cameraIndex, description);
}
std::vector<AkVCam::PixelFormat> AkVCam::IpcBridge::supportedPixelFormats(DeviceType type) const
{
UNUSED(type);
if (type == DeviceTypeInput)
return {PixelFormatRGB24};
return {
PixelFormatRGB32,
@ -404,48 +371,17 @@ std::vector<AkVCam::PixelFormat> AkVCam::IpcBridge::supportedPixelFormats(Device
AkVCam::PixelFormat AkVCam::IpcBridge::defaultPixelFormat(DeviceType type) const
{
UNUSED(type);
return PixelFormatYUY2;
return type == DeviceTypeInput?
PixelFormatRGB24:
PixelFormatYUY2;
}
std::vector<AkVCam::VideoFormat> AkVCam::IpcBridge::formats(const std::string &deviceId) const
{
AkLogFunction();
auto cameraIndex = Preferences::cameraFromPath(deviceId);
if (!this->d->m_serverMessagePort)
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;
return Preferences::cameraFormats(cameraIndex);
}
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)
{
return Preferences::cameraIsInput(deviceId)?
auto cameraIndex = Preferences::cameraFromPath(deviceId);
return Preferences::cameraIsInput(cameraIndex)?
DeviceTypeInput:
DeviceTypeOutput;
}
@ -732,124 +670,31 @@ void AkVCam::IpcBridge::removeFormat(const std::string &deviceId, int index)
index);
}
std::string AkVCam::IpcBridge::deviceCreate(const std::wstring &description,
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)
void AkVCam::IpcBridge::update()
{
AkLogFunction();
if (!this->d->m_serverMessagePort)
return false;
return;
auto dictionary = xpc_dictionary_create(nullptr, nullptr, 0);
xpc_dictionary_set_int64(dictionary, "message", AKVCAM_ASSISTANT_MSG_DEVICE_DESTROY);
xpc_dictionary_set_string(dictionary, "device", deviceId.c_str());
xpc_connection_send_message(this->d->m_serverMessagePort,
dictionary);
xpc_dictionary_set_int64(dictionary,
"message",
AKVCAM_ASSISTANT_MSG_DEVICE_UPDATE);
xpc_connection_send_message(this->d->m_serverMessagePort, 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())
this->deviceDestroy(device);
return true;
void AkVCam::IpcBridge::setConnections(const std::string &deviceId,
const std::vector<std::string> &connectedDevices)
{
Preferences::cameraSetConnections(Preferences::cameraFromPath(deviceId),
connectedDevices);
}
void AkVCam::IpcBridge::updateDevices()

View file

@ -234,7 +234,7 @@ OSStatus AkVCam::PluginInterface::InitializeWithObjectID(CMIOObjectID 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);
return kCMIOHardwareNoError;
@ -301,7 +301,7 @@ void AkVCam::PluginInterface::devicesUpdated(void *userData, void *unused)
for (auto &deviceId: devices)
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 formats = self->d->m_ipcBridge.formats(deviceId);
auto type = self->d->m_ipcBridge.deviceType(deviceId);
@ -315,7 +315,8 @@ void AkVCam::PluginInterface::frameReady(void *userData,
{
AkLogFunction();
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)
if (std::find(connections.begin(),

View file

@ -19,7 +19,7 @@
isEmpty(CMIO_PLUGINS_DAL_PATH):
CMIO_PLUGINS_DAL_PATH = /Library/CoreMediaIO/Plug-Ins/DAL
isEmpty(CMIO_DAEMONS_PATH):
CMIO_DAEMONS_PATH = ~/Library/LaunchAgents
CMIO_DAEMONS_PATH = /Library/LaunchAgents
isEmpty(CMIO_PLUGIN_NAME):
CMIO_PLUGIN_NAME = AkVirtualCamera
isEmpty(CMIO_PLUGIN_ASSISTANT_NAME):

View file

@ -303,7 +303,7 @@ void AkVCam::IpcBridge::unregisterPeer()
this->d->m_portName.clear();
}
std::vector<std::string> AkVCam::IpcBridge::listDevices() const
std::vector<std::string> AkVCam::IpcBridge::devices() const
{
AkLogFunction();
std::vector<std::string> devices;
@ -649,7 +649,7 @@ bool AkVCam::IpcBridge::needsRestart(Operation operation) const
{
return operation == OperationDestroyAll
|| (operation == OperationDestroy
&& this->listDevices().size() == 1);
&& this->devices().size() == 1);
}
bool AkVCam::IpcBridge::canApply(AkVCam::IpcBridge::Operation operation) const

0
ports/ci/appveyor/build.bat Normal file → Executable file
View file

0
ports/ci/appveyor/build.sh Executable file → Normal file
View file

0
ports/ci/appveyor/deploy.bat Normal file → Executable file
View file

0
ports/ci/appveyor/deploy.sh Executable file → Normal file
View file

0
ports/ci/appveyor/install_deps.bat Normal file → Executable file
View file

0
ports/ci/appveyor/install_deps.sh Executable file → Normal file
View file

0
ports/ci/appveyor/push_artifacts.bat Normal file → Executable file
View file

0
ports/ci/appveyor/upload.bat Normal file → Executable file
View file

0
ports/ci/travis/build.sh Executable file → Normal file
View file

0
ports/ci/travis/deploy.sh Executable file → Normal file
View file

0
ports/ci/travis/install_deps.sh Executable file → Normal file
View file

0
ports/ci/travis/upload.sh Executable file → Normal file
View file

0
ports/deploy/deploy.py Executable file → Normal file
View file

View file

@ -23,6 +23,15 @@ Component.prototype.createOperations = function()
"rm",
"-rf",
"/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.

0
share/TestFrame/TestFrame.py Executable file → Normal file
View file