Commit ae7c912a authored by Andreas Traczyk's avatar Andreas Traczyk Committed by Adrien Béraud

video device: add unique id field for platforms that use path

With v4l2, the serialized device attribute currently named "id"
corresponds to the member "input" of the DeviceParams structure which
is used as a path. Ideally, the attribute should be called "uid" in
DeviceParams, serialized accordingly, and "input" should hold the
path or string required to open the device.

On linux, the "uid" should be something like: VID+PID+serial.

Considering the current broken state of device settings in the config,
migration on linux should be done by simply wiping the existing
entries.

Change-Id: I539330d33fdc8fc9c395469b330b9ce96f963958
parent 8250a249
......@@ -253,8 +253,10 @@ Conference::attach()
#endif
setState(State::ACTIVE_ATTACHED);
} else {
JAMI_WARN("Invalid conference state in attach participant: current \"%s\" - expected \"%s\"",
getStateStr(), "ACTIVE_DETACHED");
JAMI_WARN(
"Invalid conference state in attach participant: current \"%s\" - expected \"%s\"",
getStateStr(),
"ACTIVE_DETACHED");
}
}
......@@ -272,16 +274,17 @@ Conference::detach()
#endif
setState(State::ACTIVE_DETACHED);
} else {
JAMI_WARN("Invalid conference state in detach participant: current \"%s\" - expected \"%s\"",
getStateStr(), "ACTIVE_ATTACHED");
JAMI_WARN(
"Invalid conference state in detach participant: current \"%s\" - expected \"%s\"",
getStateStr(),
"ACTIVE_ATTACHED");
}
}
void
Conference::bindParticipant(const std::string& participant_id)
{
JAMI_INFO("Bind participant %s to conference %s",
participant_id.c_str(), id_.c_str());
JAMI_INFO("Bind participant %s to conference %s", participant_id.c_str(), id_.c_str());
auto& rbPool = Manager::instance().getRingBufferPool();
......
......@@ -54,8 +54,8 @@
#define DIR_SEPARATOR_STR_ESC "\\/" // Escaped directory separator string
#else
#define mode_t unsigned
#define DIR_SEPARATOR_STR "\\" // Directory separator string
#define DIR_SEPARATOR_CH '\\' // Directory separator char
#define DIR_SEPARATOR_STR "\\" // Directory separator string
#define DIR_SEPARATOR_CH '\\' // Directory separator char
#define DIR_SEPARATOR_STR_ESC "//*" // Escaped directory separator string
#endif
......
......@@ -1295,7 +1295,7 @@ JamiAccount::loadAccount(const std::string& archive_password,
Migration::setState(getAccountID(), Migration::State::SUCCESS);
}
if (not info.photo.empty() or not displayName_.empty())
if (not info.photo.empty() or not displayName_.empty())
emitSignal<DRing::ConfigurationSignal::AccountProfileReceived>(getAccountID(),
displayName_,
info.photo);
......
......@@ -1392,13 +1392,11 @@ Manager::addMainParticipant(const std::string& conference_id)
if (auto conf = getConferenceFromID(conference_id)) {
pimpl_->addMainParticipant(*conf);
JAMI_DBG("Successfully added main participant to conference %s",
conference_id.c_str());
JAMI_DBG("Successfully added main participant to conference %s", conference_id.c_str());
return true;
} else
JAMI_WARN("Failed to add main participant to conference %s",
conference_id.c_str());
return false;
JAMI_WARN("Failed to add main participant to conference %s", conference_id.c_str());
return false;
}
std::shared_ptr<Call>
......@@ -1834,8 +1832,7 @@ Manager::incomingCallsWaiting()
void
Manager::incomingCall(Call& call, const std::string& accountId)
{
JAMI_INFO("Incoming call %s on account %s)",
call.getCallId().c_str(), accountId.c_str());
JAMI_INFO("Incoming call %s on account %s)", call.getCallId().c_str(), accountId.c_str());
stopTone();
const std::string callID(call.getCallId());
......
......@@ -37,8 +37,9 @@ constexpr static auto NEWPARAMS_TIMEOUT = std::chrono::milliseconds(1000);
*/
struct DeviceParams
{
std::string name {};
std::string input {}; // Device path (e.g. /dev/video0)
std::string name {}; // friendly name (e.g. Logitech BRIO)
std::string input {}; // Device path (e.g. /dev/video0)
std::string unique_id {}; // unique id (e.g. 046d082d8A8B667F)
std::string format {};
unsigned width {}, height {};
rational<double> framerate {};
......
......@@ -172,6 +172,7 @@ VideoDeviceImpl::getDeviceParams() const
ss1 << fmt_->ring_format;
ss1 >> params.format;
params.unique_id = name;
params.name = name;
params.input = name;
params.channel = 0;
......@@ -194,11 +195,11 @@ VideoDeviceImpl::setDeviceParams(const DeviceParams& params)
rate_.real());
}
VideoDevice::VideoDevice(const std::string& path,
VideoDevice::VideoDevice(const std::string& id,
const std::vector<std::map<std::string, std::string>>&)
: deviceImpl_(new VideoDeviceImpl(path))
: deviceImpl_(new VideoDeviceImpl(id))
{
id_ = path;
id_ = id;
name = deviceImpl_->name;
}
......
......@@ -112,6 +112,7 @@ VideoDeviceImpl::getDeviceParams() const
{
DeviceParams params;
params.name = [[avDevice_ localizedName] UTF8String];
params.unique_id = id;
params.input = id;
params.framerate = rate_;
params.format = "avfoundation";
......
......@@ -127,9 +127,10 @@ public:
/**
* @throw std::runtime_error
*/
VideoDeviceImpl(const std::string& path);
VideoDeviceImpl(const std::string& id, const std::string& path);
std::string id;
std::string unique_id;
std::string path;
std::string name;
std::vector<std::string> getChannelList() const;
......@@ -433,15 +434,16 @@ VideoV4l2Channel::getSize(VideoSize s) const
return sizes_.front();
}
VideoDeviceImpl::VideoDeviceImpl(const string& path)
: id(path)
VideoDeviceImpl::VideoDeviceImpl(const string& id, const std::string& path)
: unique_id(id)
, path(path)
, name()
, channels_()
, channel_(-1, "")
, size_(-1, -1)
, rate_(-1, 1, 0)
{
int fd = open(id.c_str(), O_RDWR);
int fd = open(path.c_str(), O_RDWR);
if (fd == -1)
throw std::runtime_error("could not open device");
......@@ -550,7 +552,8 @@ VideoDeviceImpl::getDeviceParams() const
{
DeviceParams params;
params.name = name;
params.input = id;
params.unique_id = unique_id;
params.input = path;
params.format = "video4linux2";
params.channel_name = channel_.name;
params.channel = channel_.idx;
......@@ -574,11 +577,13 @@ VideoDeviceImpl::setDeviceParams(const DeviceParams& params)
}
}
VideoDevice::VideoDevice(const std::string& path,
const std::vector<std::map<std::string, std::string>>&)
: deviceImpl_(new VideoDeviceImpl(path))
VideoDevice::VideoDevice(const std::string& id,
const std::vector<std::map<std::string, std::string>>& devInfo)
: id_(id)
{
id_ = path;
deviceImpl_ = std::make_shared<VideoDeviceImpl>(id,
devInfo.empty() ? id
: devInfo.at(0).at("devPath"));
name = deviceImpl_->name;
}
......
......@@ -65,6 +65,8 @@ public:
void start();
std::map<std::string, std::string> currentPathToId_ {};
private:
NON_COPYABLE(VideoDeviceMonitorImpl);
......@@ -79,6 +81,36 @@ private:
bool probing_;
};
std::string
getDeviceString(udev* udev, const std::string& dev_path)
{
std::string unique_device_string;
struct stat statbuf;
if (stat(dev_path.c_str(), &statbuf) < 0) {
return {};
}
auto type = S_ISBLK(statbuf.st_mode) ? 'b' : S_ISCHR(statbuf.st_mode) ? 'c' : 0;
auto opened_dev = udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
auto dev = opened_dev;
while (dev != nullptr) {
auto serial = udev_device_get_sysattr_value(dev, "serial");
if (nullptr == serial) {
dev = udev_device_get_parent(dev);
} else {
unique_device_string += udev_device_get_sysattr_value(dev, "idVendor");
unique_device_string += udev_device_get_sysattr_value(dev, "idProduct");
unique_device_string += serial;
break;
}
}
if (opened_dev) {
udev_device_unref(opened_dev);
}
return unique_device_string;
}
static int
is_v4l2(struct udev_device* dev)
{
......@@ -130,13 +162,20 @@ VideoDeviceMonitorImpl::VideoDeviceMonitorImpl(VideoDeviceMonitor* monitor)
struct udev_device* dev = udev_device_new_from_syspath(udev_, path);
if (is_v4l2(dev)) {
const char* devpath = udev_device_get_devnode(dev);
if (devpath) {
try {
monitor_->addDevice(string(devpath));
} catch (const std::runtime_error& e) {
JAMI_ERR("%s", e.what());
}
const char* path = udev_device_get_devnode(dev);
if (path && std::string(path).find("/dev") != 0) {
// udev_device_get_devnode will fail
continue;
}
auto unique_name = getDeviceString(udev_, path);
JAMI_DBG("udev: adding device with id %s", unique_name.c_str());
std::map<std::string, std::string> info = {{"devPath", path}};
std::vector<std::map<std::string, std::string>> devInfo = {info};
try {
monitor_->addDevice(unique_name, &devInfo);
currentPathToId_.emplace(path, unique_name);
} catch (const std::runtime_error& e) {
JAMI_ERR("%s", e.what());
}
}
udev_device_unref(dev);
......@@ -208,23 +247,37 @@ VideoDeviceMonitorImpl::run()
break;
case 1: {
udev_device* dev = udev_monitor_receive_device(udev_mon_);
if (!is_v4l2(dev)) {
udev_device_unref(dev);
break;
}
const char* node = udev_device_get_devnode(dev);
const char* action = udev_device_get_action(dev);
if (!strcmp(action, "add")) {
JAMI_DBG("udev: adding %s", node);
try {
monitor_->addDevice(node);
} catch (const std::runtime_error& e) {
JAMI_ERR("%s", e.what());
if (is_v4l2(dev)) {
const char* path = udev_device_get_devnode(dev);
if (path && std::string(path).find("/dev") != 0) {
// udev_device_get_devnode will fail
break;
}
auto unique_name = getDeviceString(udev_, path);
const char* action = udev_device_get_action(dev);
if (!strcmp(action, "add")) {
JAMI_DBG("udev: adding device with id %s", unique_name.c_str());
std::map<std::string, std::string> info = {{"devPath", path}};
std::vector<std::map<std::string, std::string>> devInfo = {info};
try {
monitor_->addDevice(unique_name, &devInfo);
currentPathToId_.emplace(path, unique_name);
} catch (const std::runtime_error& e) {
JAMI_ERR("%s", e.what());
}
} else if (!strcmp(action, "remove")) {
auto it = currentPathToId_.find(path);
if (it != currentPathToId_.end()) {
JAMI_DBG("udev: removing %s", it->second.c_str());
monitor_->removeDevice(it->second);
currentPathToId_.erase(it);
} else {
// In case of fallback
JAMI_DBG("udev: removing %s", path);
monitor_->removeDevice(path);
}
}
} else if (!strcmp(action, "remove")) {
JAMI_DBG("udev: removing %s", node);
monitor_->removeDevice(string(node));
}
udev_device_unref(dev);
break;
......
......@@ -85,7 +85,11 @@ extractString(const std::map<std::string, std::string>& settings, const std::str
VideoSettings::VideoSettings(const std::map<std::string, std::string>& settings)
{
name = extractString(settings, "name");
id = extractString(settings, "id");
unique_id = extractString(settings, "id");
input = extractString(settings, "input");
if (input.empty()) {
input = unique_id;
}
channel = extractString(settings, "channel");
video_size = extractString(settings, "size");
framerate = extractString(settings, "rate");
......@@ -95,7 +99,8 @@ std::map<std::string, std::string>
VideoSettings::to_map() const
{
return {{"name", name},
{"id", id},
{"id", unique_id},
{"input", input},
{"size", video_size},
{"channel", channel},
{"rate", framerate}};
......@@ -111,7 +116,8 @@ convert<jami::video::VideoSettings>::encode(const jami::video::VideoSettings& rh
{
Node node;
node["name"] = rhs.name;
node["id"] = rhs.id;
node["id"] = rhs.unique_id;
node["input"] = rhs.input;
node["video_size"] = rhs.video_size;
node["channel"] = rhs.channel;
node["framerate"] = rhs.framerate;
......@@ -126,7 +132,8 @@ convert<jami::video::VideoSettings>::decode(const Node& node, jami::video::Video
return false;
}
rhs.name = node["name"].as<std::string>();
rhs.id = node["id"].as<std::string>();
rhs.unique_id = node["id"].as<std::string>();
rhs.input = node["input"].as<std::string>();
rhs.video_size = node["video_size"].as<std::string>();
rhs.channel = node["channel"].as<std::string>();
rhs.framerate = node["framerate"].as<std::string>();
......
......@@ -99,7 +99,8 @@ struct VideoSettings
std::map<std::string, std::string> to_map() const;
std::string id {};
std::string unique_id {};
std::string input {};
std::string name {};
std::string channel {};
std::string video_size {};
......
......@@ -146,7 +146,8 @@ public:
auto params = getDeviceParams();
VideoSettings settings;
settings.name = name.empty() ? params.name : name;
settings.id = params.input;
settings.unique_id = params.unique_id;
settings.input = params.input;
settings.channel = params.channel_name;
settings.video_size = sizeToString(params.width, params.height);
settings.framerate = jami::to_string(params.framerate.real());
......@@ -164,7 +165,8 @@ public:
{
DeviceParams params {};
params.name = settings.name;
params.input = settings.id;
params.input = settings.input;
params.unique_id = settings.unique_id;
params.channel_name = settings.channel;
auto size = sizeFromString(settings.channel, settings.video_size);
params.width = size.first;
......@@ -231,7 +233,7 @@ private:
void setDeviceParams(const DeviceParams&);
/*
* The device node, e.g. "/dev/video0".
* The device node, e.g. "046d082dF41A2B3F".
*/
std::string id_ {};
......
......@@ -53,8 +53,9 @@ VideoDeviceMonitor::getDeviceList() const
std::lock_guard<std::mutex> l(lock_);
vector<string> ids;
ids.reserve(devices_.size());
for (const auto& dev : devices_)
for (const auto& dev : devices_) {
ids.emplace_back(dev.getDeviceId());
}
return ids;
}
......@@ -91,7 +92,7 @@ VideoDeviceMonitor::applySettings(const string& id, const VideoSettings& setting
return;
iter->applySettings(settings);
auto it = findPreferencesById(settings.id);
auto it = findPreferencesById(settings.unique_id);
if (it != preferences_.end())
(*it) = settings;
}
......@@ -263,7 +264,7 @@ vector<VideoSettings>::iterator
VideoDeviceMonitor::findPreferencesById(const string& id)
{
for (auto it = preferences_.begin(); it != preferences_.end(); ++it)
if (it->id.find(id) != std::string::npos)
if (it->unique_id.find(id) != std::string::npos)
return it;
return preferences_.end();
}
......@@ -271,7 +272,7 @@ VideoDeviceMonitor::findPreferencesById(const string& id)
void
VideoDeviceMonitor::overwritePreferences(const VideoSettings& settings)
{
auto it = findPreferencesById(settings.id);
auto it = findPreferencesById(settings.unique_id);
if (it != preferences_.end())
preferences_.erase(it);
preferences_.emplace_back(settings);
......@@ -294,16 +295,16 @@ VideoDeviceMonitor::unserialize(const YAML::Node& in)
const auto& devices = node["devices"];
for (const auto& dev : devices) {
VideoSettings pref = dev.as<VideoSettings>();
if (pref.id.empty())
if (pref.unique_id.empty())
continue; // discard malformed section
overwritePreferences(pref);
auto itd = findDeviceById(pref.id);
auto itd = findDeviceById(pref.unique_id);
if (itd != devices_.end())
itd->applySettings(pref);
}
// Restore the default device if present, or select the first one
const string prefId = preferences_.empty() ? "" : preferences_[0].id;
const string prefId = preferences_.empty() ? "" : preferences_[0].unique_id;
const string firstId = devices_.empty() ? "" : devices_[0].getDeviceId();
const auto devIter = findDeviceById(prefId);
if (devIter != devices_.end()) {
......
......@@ -62,6 +62,7 @@ public:
void addDevice(const std::string& node,
const std::vector<std::map<std::string, std::string>>* devInfo = nullptr);
void removeDevice(const std::string& node);
void removeDeviceViaInput(const std::string& path);
/**
* Params for libav
......
......@@ -69,10 +69,10 @@ extern "C" {
#define PLUGIN_OLD_VERSION 200 /* Plugin already installed with a newer version */
#ifdef WIN32
#define LIB_TYPE ".dll"
#define LIB_TYPE ".dll"
#define LIB_PREFIX ""
#else
#define LIB_TYPE ".so"
#define LIB_TYPE ".so"
#define LIB_PREFIX "lib"
#endif
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment