Skip to content
Snippets Groups Projects
Commit ae7c912a authored by Andreas Traczyk's avatar Andreas Traczyk Committed by Adrien Béraud
Browse files

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
Branches
Tags
No related merge requests found
Showing with 144 additions and 71 deletions
...@@ -253,8 +253,10 @@ Conference::attach() ...@@ -253,8 +253,10 @@ Conference::attach()
#endif #endif
setState(State::ACTIVE_ATTACHED); setState(State::ACTIVE_ATTACHED);
} else { } else {
JAMI_WARN("Invalid conference state in attach participant: current \"%s\" - expected \"%s\"", JAMI_WARN(
getStateStr(), "ACTIVE_DETACHED"); "Invalid conference state in attach participant: current \"%s\" - expected \"%s\"",
getStateStr(),
"ACTIVE_DETACHED");
} }
} }
...@@ -272,16 +274,17 @@ Conference::detach() ...@@ -272,16 +274,17 @@ Conference::detach()
#endif #endif
setState(State::ACTIVE_DETACHED); setState(State::ACTIVE_DETACHED);
} else { } else {
JAMI_WARN("Invalid conference state in detach participant: current \"%s\" - expected \"%s\"", JAMI_WARN(
getStateStr(), "ACTIVE_ATTACHED"); "Invalid conference state in detach participant: current \"%s\" - expected \"%s\"",
getStateStr(),
"ACTIVE_ATTACHED");
} }
} }
void void
Conference::bindParticipant(const std::string& participant_id) Conference::bindParticipant(const std::string& participant_id)
{ {
JAMI_INFO("Bind participant %s to conference %s", JAMI_INFO("Bind participant %s to conference %s", participant_id.c_str(), id_.c_str());
participant_id.c_str(), id_.c_str());
auto& rbPool = Manager::instance().getRingBufferPool(); auto& rbPool = Manager::instance().getRingBufferPool();
......
...@@ -1392,12 +1392,10 @@ Manager::addMainParticipant(const std::string& conference_id) ...@@ -1392,12 +1392,10 @@ Manager::addMainParticipant(const std::string& conference_id)
if (auto conf = getConferenceFromID(conference_id)) { if (auto conf = getConferenceFromID(conference_id)) {
pimpl_->addMainParticipant(*conf); pimpl_->addMainParticipant(*conf);
JAMI_DBG("Successfully added main participant to conference %s", JAMI_DBG("Successfully added main participant to conference %s", conference_id.c_str());
conference_id.c_str());
return true; return true;
} else } else
JAMI_WARN("Failed to add main participant to conference %s", JAMI_WARN("Failed to add main participant to conference %s", conference_id.c_str());
conference_id.c_str());
return false; return false;
} }
...@@ -1834,8 +1832,7 @@ Manager::incomingCallsWaiting() ...@@ -1834,8 +1832,7 @@ Manager::incomingCallsWaiting()
void void
Manager::incomingCall(Call& call, const std::string& accountId) Manager::incomingCall(Call& call, const std::string& accountId)
{ {
JAMI_INFO("Incoming call %s on account %s)", JAMI_INFO("Incoming call %s on account %s)", call.getCallId().c_str(), accountId.c_str());
call.getCallId().c_str(), accountId.c_str());
stopTone(); stopTone();
const std::string callID(call.getCallId()); const std::string callID(call.getCallId());
......
...@@ -37,8 +37,9 @@ constexpr static auto NEWPARAMS_TIMEOUT = std::chrono::milliseconds(1000); ...@@ -37,8 +37,9 @@ constexpr static auto NEWPARAMS_TIMEOUT = std::chrono::milliseconds(1000);
*/ */
struct DeviceParams struct DeviceParams
{ {
std::string name {}; std::string name {}; // friendly name (e.g. Logitech BRIO)
std::string input {}; // Device path (e.g. /dev/video0) std::string input {}; // Device path (e.g. /dev/video0)
std::string unique_id {}; // unique id (e.g. 046d082d8A8B667F)
std::string format {}; std::string format {};
unsigned width {}, height {}; unsigned width {}, height {};
rational<double> framerate {}; rational<double> framerate {};
......
...@@ -172,6 +172,7 @@ VideoDeviceImpl::getDeviceParams() const ...@@ -172,6 +172,7 @@ VideoDeviceImpl::getDeviceParams() const
ss1 << fmt_->ring_format; ss1 << fmt_->ring_format;
ss1 >> params.format; ss1 >> params.format;
params.unique_id = name;
params.name = name; params.name = name;
params.input = name; params.input = name;
params.channel = 0; params.channel = 0;
...@@ -194,11 +195,11 @@ VideoDeviceImpl::setDeviceParams(const DeviceParams& params) ...@@ -194,11 +195,11 @@ VideoDeviceImpl::setDeviceParams(const DeviceParams& params)
rate_.real()); rate_.real());
} }
VideoDevice::VideoDevice(const std::string& path, VideoDevice::VideoDevice(const std::string& id,
const std::vector<std::map<std::string, std::string>>&) const std::vector<std::map<std::string, std::string>>&)
: deviceImpl_(new VideoDeviceImpl(path)) : deviceImpl_(new VideoDeviceImpl(id))
{ {
id_ = path; id_ = id;
name = deviceImpl_->name; name = deviceImpl_->name;
} }
......
...@@ -112,6 +112,7 @@ VideoDeviceImpl::getDeviceParams() const ...@@ -112,6 +112,7 @@ VideoDeviceImpl::getDeviceParams() const
{ {
DeviceParams params; DeviceParams params;
params.name = [[avDevice_ localizedName] UTF8String]; params.name = [[avDevice_ localizedName] UTF8String];
params.unique_id = id;
params.input = id; params.input = id;
params.framerate = rate_; params.framerate = rate_;
params.format = "avfoundation"; params.format = "avfoundation";
......
...@@ -127,9 +127,10 @@ public: ...@@ -127,9 +127,10 @@ public:
/** /**
* @throw std::runtime_error * @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::string name;
std::vector<std::string> getChannelList() const; std::vector<std::string> getChannelList() const;
...@@ -433,15 +434,16 @@ VideoV4l2Channel::getSize(VideoSize s) const ...@@ -433,15 +434,16 @@ VideoV4l2Channel::getSize(VideoSize s) const
return sizes_.front(); return sizes_.front();
} }
VideoDeviceImpl::VideoDeviceImpl(const string& path) VideoDeviceImpl::VideoDeviceImpl(const string& id, const std::string& path)
: id(path) : unique_id(id)
, path(path)
, name() , name()
, channels_() , channels_()
, channel_(-1, "") , channel_(-1, "")
, size_(-1, -1) , size_(-1, -1)
, rate_(-1, 1, 0) , rate_(-1, 1, 0)
{ {
int fd = open(id.c_str(), O_RDWR); int fd = open(path.c_str(), O_RDWR);
if (fd == -1) if (fd == -1)
throw std::runtime_error("could not open device"); throw std::runtime_error("could not open device");
...@@ -550,7 +552,8 @@ VideoDeviceImpl::getDeviceParams() const ...@@ -550,7 +552,8 @@ VideoDeviceImpl::getDeviceParams() const
{ {
DeviceParams params; DeviceParams params;
params.name = name; params.name = name;
params.input = id; params.unique_id = unique_id;
params.input = path;
params.format = "video4linux2"; params.format = "video4linux2";
params.channel_name = channel_.name; params.channel_name = channel_.name;
params.channel = channel_.idx; params.channel = channel_.idx;
...@@ -574,11 +577,13 @@ VideoDeviceImpl::setDeviceParams(const DeviceParams& params) ...@@ -574,11 +577,13 @@ VideoDeviceImpl::setDeviceParams(const DeviceParams& params)
} }
} }
VideoDevice::VideoDevice(const std::string& path, VideoDevice::VideoDevice(const std::string& id,
const std::vector<std::map<std::string, std::string>>&) const std::vector<std::map<std::string, std::string>>& devInfo)
: deviceImpl_(new VideoDeviceImpl(path)) : id_(id)
{ {
id_ = path; deviceImpl_ = std::make_shared<VideoDeviceImpl>(id,
devInfo.empty() ? id
: devInfo.at(0).at("devPath"));
name = deviceImpl_->name; name = deviceImpl_->name;
} }
......
...@@ -65,6 +65,8 @@ public: ...@@ -65,6 +65,8 @@ public:
void start(); void start();
std::map<std::string, std::string> currentPathToId_ {};
private: private:
NON_COPYABLE(VideoDeviceMonitorImpl); NON_COPYABLE(VideoDeviceMonitorImpl);
...@@ -79,6 +81,36 @@ private: ...@@ -79,6 +81,36 @@ private:
bool probing_; 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 static int
is_v4l2(struct udev_device* dev) is_v4l2(struct udev_device* dev)
{ {
...@@ -130,15 +162,22 @@ VideoDeviceMonitorImpl::VideoDeviceMonitorImpl(VideoDeviceMonitor* monitor) ...@@ -130,15 +162,22 @@ VideoDeviceMonitorImpl::VideoDeviceMonitorImpl(VideoDeviceMonitor* monitor)
struct udev_device* dev = udev_device_new_from_syspath(udev_, path); struct udev_device* dev = udev_device_new_from_syspath(udev_, path);
if (is_v4l2(dev)) { if (is_v4l2(dev)) {
const char* devpath = udev_device_get_devnode(dev); const char* path = udev_device_get_devnode(dev);
if (devpath) { 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 { try {
monitor_->addDevice(string(devpath)); monitor_->addDevice(unique_name, &devInfo);
currentPathToId_.emplace(path, unique_name);
} catch (const std::runtime_error& e) { } catch (const std::runtime_error& e) {
JAMI_ERR("%s", e.what()); JAMI_ERR("%s", e.what());
} }
} }
}
udev_device_unref(dev); udev_device_unref(dev);
} }
udev_enumerate_unref(devenum); udev_enumerate_unref(devenum);
...@@ -208,23 +247,37 @@ VideoDeviceMonitorImpl::run() ...@@ -208,23 +247,37 @@ VideoDeviceMonitorImpl::run()
break; break;
case 1: { case 1: {
udev_device* dev = udev_monitor_receive_device(udev_mon_); udev_device* dev = udev_monitor_receive_device(udev_mon_);
if (!is_v4l2(dev)) { if (is_v4l2(dev)) {
udev_device_unref(dev); const char* path = udev_device_get_devnode(dev);
if (path && std::string(path).find("/dev") != 0) {
// udev_device_get_devnode will fail
break; break;
} }
auto unique_name = getDeviceString(udev_, path);
const char* node = udev_device_get_devnode(dev);
const char* action = udev_device_get_action(dev); const char* action = udev_device_get_action(dev);
if (!strcmp(action, "add")) { if (!strcmp(action, "add")) {
JAMI_DBG("udev: adding %s", node); 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 { try {
monitor_->addDevice(node); monitor_->addDevice(unique_name, &devInfo);
currentPathToId_.emplace(path, unique_name);
} catch (const std::runtime_error& e) { } catch (const std::runtime_error& e) {
JAMI_ERR("%s", e.what()); JAMI_ERR("%s", e.what());
} }
} else if (!strcmp(action, "remove")) { } else if (!strcmp(action, "remove")) {
JAMI_DBG("udev: removing %s", node); auto it = currentPathToId_.find(path);
monitor_->removeDevice(string(node)); 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);
}
}
} }
udev_device_unref(dev); udev_device_unref(dev);
break; break;
......
...@@ -85,7 +85,11 @@ extractString(const std::map<std::string, std::string>& settings, const std::str ...@@ -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) VideoSettings::VideoSettings(const std::map<std::string, std::string>& settings)
{ {
name = extractString(settings, "name"); 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"); channel = extractString(settings, "channel");
video_size = extractString(settings, "size"); video_size = extractString(settings, "size");
framerate = extractString(settings, "rate"); framerate = extractString(settings, "rate");
...@@ -95,7 +99,8 @@ std::map<std::string, std::string> ...@@ -95,7 +99,8 @@ std::map<std::string, std::string>
VideoSettings::to_map() const VideoSettings::to_map() const
{ {
return {{"name", name}, return {{"name", name},
{"id", id}, {"id", unique_id},
{"input", input},
{"size", video_size}, {"size", video_size},
{"channel", channel}, {"channel", channel},
{"rate", framerate}}; {"rate", framerate}};
...@@ -111,7 +116,8 @@ convert<jami::video::VideoSettings>::encode(const jami::video::VideoSettings& rh ...@@ -111,7 +116,8 @@ convert<jami::video::VideoSettings>::encode(const jami::video::VideoSettings& rh
{ {
Node node; Node node;
node["name"] = rhs.name; node["name"] = rhs.name;
node["id"] = rhs.id; node["id"] = rhs.unique_id;
node["input"] = rhs.input;
node["video_size"] = rhs.video_size; node["video_size"] = rhs.video_size;
node["channel"] = rhs.channel; node["channel"] = rhs.channel;
node["framerate"] = rhs.framerate; node["framerate"] = rhs.framerate;
...@@ -126,7 +132,8 @@ convert<jami::video::VideoSettings>::decode(const Node& node, jami::video::Video ...@@ -126,7 +132,8 @@ convert<jami::video::VideoSettings>::decode(const Node& node, jami::video::Video
return false; return false;
} }
rhs.name = node["name"].as<std::string>(); 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.video_size = node["video_size"].as<std::string>();
rhs.channel = node["channel"].as<std::string>(); rhs.channel = node["channel"].as<std::string>();
rhs.framerate = node["framerate"].as<std::string>(); rhs.framerate = node["framerate"].as<std::string>();
......
...@@ -99,7 +99,8 @@ struct VideoSettings ...@@ -99,7 +99,8 @@ struct VideoSettings
std::map<std::string, std::string> to_map() const; std::map<std::string, std::string> to_map() const;
std::string id {}; std::string unique_id {};
std::string input {};
std::string name {}; std::string name {};
std::string channel {}; std::string channel {};
std::string video_size {}; std::string video_size {};
......
...@@ -146,7 +146,8 @@ public: ...@@ -146,7 +146,8 @@ public:
auto params = getDeviceParams(); auto params = getDeviceParams();
VideoSettings settings; VideoSettings settings;
settings.name = name.empty() ? params.name : name; 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.channel = params.channel_name;
settings.video_size = sizeToString(params.width, params.height); settings.video_size = sizeToString(params.width, params.height);
settings.framerate = jami::to_string(params.framerate.real()); settings.framerate = jami::to_string(params.framerate.real());
...@@ -164,7 +165,8 @@ public: ...@@ -164,7 +165,8 @@ public:
{ {
DeviceParams params {}; DeviceParams params {};
params.name = settings.name; params.name = settings.name;
params.input = settings.id; params.input = settings.input;
params.unique_id = settings.unique_id;
params.channel_name = settings.channel; params.channel_name = settings.channel;
auto size = sizeFromString(settings.channel, settings.video_size); auto size = sizeFromString(settings.channel, settings.video_size);
params.width = size.first; params.width = size.first;
...@@ -231,7 +233,7 @@ private: ...@@ -231,7 +233,7 @@ private:
void setDeviceParams(const DeviceParams&); void setDeviceParams(const DeviceParams&);
/* /*
* The device node, e.g. "/dev/video0". * The device node, e.g. "046d082dF41A2B3F".
*/ */
std::string id_ {}; std::string id_ {};
......
...@@ -53,8 +53,9 @@ VideoDeviceMonitor::getDeviceList() const ...@@ -53,8 +53,9 @@ VideoDeviceMonitor::getDeviceList() const
std::lock_guard<std::mutex> l(lock_); std::lock_guard<std::mutex> l(lock_);
vector<string> ids; vector<string> ids;
ids.reserve(devices_.size()); ids.reserve(devices_.size());
for (const auto& dev : devices_) for (const auto& dev : devices_) {
ids.emplace_back(dev.getDeviceId()); ids.emplace_back(dev.getDeviceId());
}
return ids; return ids;
} }
...@@ -91,7 +92,7 @@ VideoDeviceMonitor::applySettings(const string& id, const VideoSettings& setting ...@@ -91,7 +92,7 @@ VideoDeviceMonitor::applySettings(const string& id, const VideoSettings& setting
return; return;
iter->applySettings(settings); iter->applySettings(settings);
auto it = findPreferencesById(settings.id); auto it = findPreferencesById(settings.unique_id);
if (it != preferences_.end()) if (it != preferences_.end())
(*it) = settings; (*it) = settings;
} }
...@@ -263,7 +264,7 @@ vector<VideoSettings>::iterator ...@@ -263,7 +264,7 @@ vector<VideoSettings>::iterator
VideoDeviceMonitor::findPreferencesById(const string& id) VideoDeviceMonitor::findPreferencesById(const string& id)
{ {
for (auto it = preferences_.begin(); it != preferences_.end(); ++it) 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 it;
return preferences_.end(); return preferences_.end();
} }
...@@ -271,7 +272,7 @@ VideoDeviceMonitor::findPreferencesById(const string& id) ...@@ -271,7 +272,7 @@ VideoDeviceMonitor::findPreferencesById(const string& id)
void void
VideoDeviceMonitor::overwritePreferences(const VideoSettings& settings) VideoDeviceMonitor::overwritePreferences(const VideoSettings& settings)
{ {
auto it = findPreferencesById(settings.id); auto it = findPreferencesById(settings.unique_id);
if (it != preferences_.end()) if (it != preferences_.end())
preferences_.erase(it); preferences_.erase(it);
preferences_.emplace_back(settings); preferences_.emplace_back(settings);
...@@ -294,16 +295,16 @@ VideoDeviceMonitor::unserialize(const YAML::Node& in) ...@@ -294,16 +295,16 @@ VideoDeviceMonitor::unserialize(const YAML::Node& in)
const auto& devices = node["devices"]; const auto& devices = node["devices"];
for (const auto& dev : devices) { for (const auto& dev : devices) {
VideoSettings pref = dev.as<VideoSettings>(); VideoSettings pref = dev.as<VideoSettings>();
if (pref.id.empty()) if (pref.unique_id.empty())
continue; // discard malformed section continue; // discard malformed section
overwritePreferences(pref); overwritePreferences(pref);
auto itd = findDeviceById(pref.id); auto itd = findDeviceById(pref.unique_id);
if (itd != devices_.end()) if (itd != devices_.end())
itd->applySettings(pref); itd->applySettings(pref);
} }
// Restore the default device if present, or select the first one // 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 string firstId = devices_.empty() ? "" : devices_[0].getDeviceId();
const auto devIter = findDeviceById(prefId); const auto devIter = findDeviceById(prefId);
if (devIter != devices_.end()) { if (devIter != devices_.end()) {
......
...@@ -62,6 +62,7 @@ public: ...@@ -62,6 +62,7 @@ public:
void addDevice(const std::string& node, void addDevice(const std::string& node,
const std::vector<std::map<std::string, std::string>>* devInfo = nullptr); const std::vector<std::map<std::string, std::string>>* devInfo = nullptr);
void removeDevice(const std::string& node); void removeDevice(const std::string& node);
void removeDeviceViaInput(const std::string& path);
/** /**
* Params for libav * Params for libav
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment