Ring Daemon
Loading...
Searching...
No Matches
video_device_monitor.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2004-2026 Savoir-faire Linux Inc.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18#include <cassert>
19
20#pragma GCC diagnostic push
21#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
22#include <yaml-cpp/yaml.h>
23#pragma GCC diagnostic pop
24
25#include "manager.h"
26#include "media_const.h"
27#include "client/jami_signal.h"
28#include "logger.h"
30
31namespace jami {
32namespace video {
33
34constexpr const char* const VideoDeviceMonitor::CONFIG_LABEL;
35
36using std::map;
37using std::string;
38using std::vector;
39
42{
43 std::lock_guard l(lock_);
45 ids.reserve(devices_.size());
46 for (const auto& dev : devices_) {
47 if (dev.name != DEVICE_DESKTOP)
48 ids.emplace_back(dev.getDeviceId());
49 }
50 return ids;
51}
52
55{
56 std::lock_guard l(lock_);
57 const auto iter = findDeviceById(id);
58 if (iter == devices_.end())
60
61 return iter->getCapabilities();
62}
63
66{
67 std::lock_guard l(lock_);
68
69 const auto prefIter = findPreferencesById(id);
70 if (prefIter == preferences_.end())
71 return VideoSettings();
72
73 return *prefIter;
74}
75
76void
78{
79 std::lock_guard l(lock_);
80 const auto iter = findDeviceById(id);
81
82 if (iter == devices_.end())
83 return;
84
85 iter->applySettings(settings);
86 auto it = findPreferencesById(settings.unique_id);
87 if (it != preferences_.end())
88 (*it) = settings;
89}
90
91string
93{
94 std::lock_guard l(lock_);
95 const auto it = findDeviceById(defaultDevice_);
96 if (it == std::end(devices_) || it->getDeviceId() == DEVICE_DESKTOP)
97 return {};
98 return it->getDeviceId();
99}
100
101std::string
103{
104 std::lock_guard l(lock_);
105 const auto it = findDeviceById(defaultDevice_);
106 if (it == std::end(devices_) || it->getDeviceId() == DEVICE_DESKTOP)
107 return {};
108 static const std::string sep = libjami::Media::VideoProtocolPrefix::SEPARATOR;
109 return libjami::Media::VideoProtocolPrefix::CAMERA + sep + it->getDeviceId();
110}
111
112bool
114{
115 std::lock_guard l(lock_);
116 const auto itDev = findDeviceById(id);
117 if (itDev != devices_.end()) {
118 if (defaultDevice_ == itDev->getDeviceId())
119 return false;
120 defaultDevice_ = itDev->getDeviceId();
121
122 // place it at the begining of the prefs
123 auto itPref = findPreferencesById(itDev->getDeviceId());
124 if (itPref != preferences_.end()) {
125 std::ranges::rotate(preferences_.begin(), itPref, itPref+1);
126 } else {
127 preferences_.insert(preferences_.begin(), itDev->getSettings());
128 }
129 return true;
130 }
131 return false;
132}
133
134void
136{
137 std::lock_guard l(lock_);
138 const auto itd = findDeviceById(id);
139 if (itd != devices_.cend()) {
140 itd->setOrientation(angle);
141 } else {
142 JAMI_WARN("Unable to find device %s to set orientation %d", id.c_str(), angle);
143 }
144}
145
147VideoDeviceMonitor::getDeviceParams(const std::string& id) const
148{
149 std::lock_guard l(lock_);
150 const auto itd = findDeviceById(id);
151 if (itd == devices_.cend())
152 return DeviceParams();
153 return itd->getDeviceParams();
154}
155
156static void
158{
159 std::string suffix;
160 uint64_t number = 2;
161 auto unique = true;
162 for (;; unique = static_cast<bool>(++number)) {
163 for (const auto& s : devices)
164 unique &= static_cast<bool>(s.name.compare(dev.name + suffix));
165 if (unique)
166 return (void) (dev.name += suffix);
167 suffix = " (" + std::to_string(number) + ")";
168 }
169}
170
171static void
178
179bool
180VideoDeviceMonitor::addDevice(const string& id, const std::vector<std::map<std::string, std::string>>& devInfo)
181{
182 try {
183 std::lock_guard l(lock_);
184 if (findDeviceById(id) != devices_.end())
185 return false;
186
187 // instantiate a new unique device
188 VideoDevice dev {id, devInfo};
189
190 if (dev.getChannelList().empty())
191 return false;
192
193 giveUniqueName(dev, devices_);
194
195 // restore its preferences if any, or store the defaults
196 auto it = findPreferencesById(id);
197 if (it != preferences_.end()) {
198 dev.applySettings(*it);
199 } else {
200 dev.applySettings(dev.getDefaultSettings());
201 preferences_.emplace_back(dev.getSettings());
202 }
203
204 // in case there is no default device on a fresh run
205 if (defaultDevice_.empty() && id != DEVICE_DESKTOP)
206 defaultDevice_ = dev.getDeviceId();
207
208 devices_.emplace_back(std::move(dev));
209 } catch (const std::exception& e) {
210 JAMI_ERR("Failed to add device %s: %s", id.c_str(), e.what());
211 return false;
212 }
213 notify();
214 return true;
215}
216
217void
219{
220 {
221 std::lock_guard l(lock_);
222 const auto it = findDeviceById(id);
223 if (it == devices_.end())
224 return;
225
226 devices_.erase(it);
227 if (defaultDevice_.find(id) != std::string::npos) {
228 defaultDevice_.clear();
229 for (const auto& dev : devices_)
230 if (dev.name != DEVICE_DESKTOP) {
231 defaultDevice_ = dev.getDeviceId();
232 break;
233 }
234 }
235 }
236 notify();
237}
238
239vector<VideoDevice>::iterator
240VideoDeviceMonitor::findDeviceById(const string& id)
241{
242 for (auto it = devices_.begin(); it != devices_.end(); ++it)
243 if (it->getDeviceId().find(id) != std::string::npos)
244 return it;
245 return devices_.end();
246}
247
248vector<VideoDevice>::const_iterator
249VideoDeviceMonitor::findDeviceById(const string& id) const
250{
251 for (auto it = devices_.cbegin(); it != devices_.cend(); ++it)
252 if (it->getDeviceId().find(id) != std::string::npos)
253 return it;
254 return devices_.end();
255}
256
257vector<VideoSettings>::iterator
258VideoDeviceMonitor::findPreferencesById(const string& id)
259{
260 for (auto it = preferences_.begin(); it != preferences_.end(); ++it)
261 if (it->unique_id.find(id) != std::string::npos)
262 return it;
263 return preferences_.end();
264}
265
266void
267VideoDeviceMonitor::overwritePreferences(const VideoSettings& settings)
268{
269 auto it = findPreferencesById(settings.unique_id);
270 if (it != preferences_.end())
271 preferences_.erase(it);
272 preferences_.emplace_back(settings);
273}
274
275void
277{
278 std::lock_guard l(lock_);
279 out << YAML::Key << "devices" << YAML::Value << preferences_;
280}
281
282void
284{
285 std::lock_guard l(lock_);
286 const auto& node = in[CONFIG_LABEL];
287
288 /* load the device list from the "video" YAML section */
289 const auto& devices = node["devices"];
290 for (const auto& dev : devices) {
292 if (pref.unique_id.empty())
293 continue; // discard malformed section
294 overwritePreferences(pref);
295 auto itd = findDeviceById(pref.unique_id);
296 if (itd != devices_.end())
297 itd->applySettings(pref);
298 }
299
300 // Restore the default device if present, or select the first one
301 const string prefId = preferences_.empty() ? "" : preferences_[0].unique_id;
302 const auto devIter = findDeviceById(prefId);
303 if (devIter != devices_.end() && prefId != DEVICE_DESKTOP) {
304 defaultDevice_ = devIter->getDeviceId();
305 } else {
306 defaultDevice_.clear();
307 for (const auto& dev : devices_)
308 if (dev.name != DEVICE_DESKTOP) {
309 defaultDevice_ = dev.getDeviceId();
310 break;
311 }
312 }
313}
314
315} // namespace video
316} // namespace jami
static std::atomic_bool initialized
Definition manager.h:108
bool addDevice(const std::string &node, const std::vector< std::map< std::string, std::string > > &devInfo={})
bool setDefaultDevice(const std::string &name)
libjami::VideoCapabilities getCapabilities(const std::string &name) const
DeviceParams getDeviceParams(const std::string &name) const
Params for libav.
void applySettings(const std::string &name, const VideoSettings &settings)
VideoSettings getSettings(const std::string &name)
void setDeviceOrientation(const std::string &id, int angle)
virtual void unserialize(const YAML::Node &in) override
std::vector< std::string > getDeviceList() const
void removeDevice(const std::string &node)
void serialize(YAML::Emitter &out) const override
#define JAMI_ERR(...)
Definition logger.h:230
#define JAMI_WARN(...)
Definition logger.h:229
Definition Address.h:25
static constexpr const char DEVICE_DESKTOP[]
static void giveUniqueName(VideoDevice &dev, const vector< VideoDevice > &devices)
void emitSignal(Args... args)
Definition jami_signal.h:64
static constexpr const char * CAMERA
Definition media_const.h:31
static constexpr const char * SEPARATOR
Definition media_const.h:32
std::map< std::string, std::map< std::string, std::vector< std::string > > > VideoCapabilities
DeviceParams Parameters used by MediaDecoder and MediaEncoder to open a LibAV device/stream.