Ring Daemon 16.0.0
Loading...
Searching...
No Matches
video_device_monitor.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2004-2025 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 <algorithm>
19#include <cassert>
20#include <sstream>
21
22#pragma GCC diagnostic push
23#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
24#include <yaml-cpp/yaml.h>
25#pragma GCC diagnostic pop
26
27#include "manager.h"
28#include "media_const.h"
29#include "client/videomanager.h"
30#include "client/ring_signal.h"
31#include "config/yamlparser.h"
32#include "logger.h"
34
35namespace jami {
36namespace video {
37
38constexpr const char* const VideoDeviceMonitor::CONFIG_LABEL;
39
40using std::map;
41using std::string;
42using std::vector;
43
46{
47 std::lock_guard l(lock_);
49 ids.reserve(devices_.size());
50 for (const auto& dev : devices_) {
51 if (dev.name != DEVICE_DESKTOP)
52 ids.emplace_back(dev.getDeviceId());
53 }
54 return ids;
55}
56
59{
60 std::lock_guard l(lock_);
61 const auto iter = findDeviceById(id);
62 if (iter == devices_.end())
64
65 return iter->getCapabilities();
66}
67
70{
71 std::lock_guard l(lock_);
72
73 const auto prefIter = findPreferencesById(id);
74 if (prefIter == preferences_.end())
75 return VideoSettings();
76
77 return *prefIter;
78}
79
80void
82{
83 std::lock_guard l(lock_);
84 const auto iter = findDeviceById(id);
85
86 if (iter == devices_.end())
87 return;
88
89 iter->applySettings(settings);
90 auto it = findPreferencesById(settings.unique_id);
91 if (it != preferences_.end())
92 (*it) = settings;
93}
94
95string
97{
98 std::lock_guard l(lock_);
99 const auto it = findDeviceById(defaultDevice_);
100 if (it == std::end(devices_) || it->getDeviceId() == DEVICE_DESKTOP)
101 return {};
102 return it->getDeviceId();
103}
104
105std::string
107{
108 std::lock_guard l(lock_);
109 const auto it = findDeviceById(defaultDevice_);
110 if (it == std::end(devices_) || it->getDeviceId() == DEVICE_DESKTOP)
111 return {};
112 static const std::string sep = libjami::Media::VideoProtocolPrefix::SEPARATOR;
113 return libjami::Media::VideoProtocolPrefix::CAMERA + sep + it->getDeviceId();
114}
115
116bool
118{
119 std::lock_guard l(lock_);
120 const auto itDev = findDeviceById(id);
121 if (itDev != devices_.end()) {
122 if (defaultDevice_ == itDev->getDeviceId())
123 return false;
124 defaultDevice_ = itDev->getDeviceId();
125
126 // place it at the begining of the prefs
127 auto itPref = findPreferencesById(itDev->getDeviceId());
128 if (itPref != preferences_.end()) {
129 auto settings = *itPref;
130 preferences_.erase(itPref);
131 preferences_.insert(preferences_.begin(), settings);
132 } else {
133 preferences_.insert(preferences_.begin(), itDev->getSettings());
134 }
135 return true;
136 }
137 return false;
138}
139
140void
142{
143 std::lock_guard l(lock_);
144 const auto itd = findDeviceById(id);
145 if (itd != devices_.cend()) {
146 itd->setOrientation(angle);
147 } else {
148 JAMI_WARN("Unable to find device %s to set orientation %d", id.c_str(), angle);
149 }
150}
151
153VideoDeviceMonitor::getDeviceParams(const std::string& id) const
154{
155 std::lock_guard l(lock_);
156 const auto itd = findDeviceById(id);
157 if (itd == devices_.cend())
158 return DeviceParams();
159 return itd->getDeviceParams();
160}
161
162static void
164{
165 std::string suffix;
166 uint64_t number = 2;
167 auto unique = true;
168 for (;; unique = static_cast<bool>(++number)) {
169 for (const auto& s : devices)
170 unique &= static_cast<bool>(s.name.compare(dev.name + suffix));
171 if (unique)
172 return (void) (dev.name += suffix);
173 suffix = " (" + std::to_string(number) + ")";
174 }
175}
176
177static void
184
185bool
187 const std::vector<std::map<std::string, std::string>>& devInfo)
188{
189 try {
190 std::lock_guard l(lock_);
191 if (findDeviceById(id) != devices_.end())
192 return false;
193
194 // instantiate a new unique device
195 VideoDevice dev {id, devInfo};
196
197 if (dev.getChannelList().empty())
198 return false;
199
200 giveUniqueName(dev, devices_);
201
202 // restore its preferences if any, or store the defaults
203 auto it = findPreferencesById(id);
204 if (it != preferences_.end()) {
205 dev.applySettings(*it);
206 } else {
207 dev.applySettings(dev.getDefaultSettings());
208 preferences_.emplace_back(dev.getSettings());
209 }
210
211 // in case there is no default device on a fresh run
212 if (defaultDevice_.empty() && id != DEVICE_DESKTOP)
213 defaultDevice_ = dev.getDeviceId();
214
215 devices_.emplace_back(std::move(dev));
216 } catch (const std::exception& e) {
217 JAMI_ERR("Failed to add device %s: %s", id.c_str(), e.what());
218 return false;
219 }
220 notify();
221 return true;
222}
223
224void
226{
227 {
228 std::lock_guard l(lock_);
229 const auto it = findDeviceById(id);
230 if (it == devices_.end())
231 return;
232
233 devices_.erase(it);
234 if (defaultDevice_.find(id) != std::string::npos) {
235 defaultDevice_.clear();
236 for (const auto& dev : devices_)
237 if (dev.name != DEVICE_DESKTOP) {
238 defaultDevice_ = dev.getDeviceId();
239 break;
240 }
241 }
242 }
243 notify();
244}
245
246vector<VideoDevice>::iterator
247VideoDeviceMonitor::findDeviceById(const string& id)
248{
249 for (auto it = devices_.begin(); it != devices_.end(); ++it)
250 if (it->getDeviceId().find(id) != std::string::npos)
251 return it;
252 return devices_.end();
253}
254
255vector<VideoDevice>::const_iterator
256VideoDeviceMonitor::findDeviceById(const string& id) const
257{
258 for (auto it = devices_.cbegin(); it != devices_.cend(); ++it)
259 if (it->getDeviceId().find(id) != std::string::npos)
260 return it;
261 return devices_.end();
262}
263
264vector<VideoSettings>::iterator
265VideoDeviceMonitor::findPreferencesById(const string& id)
266{
267 for (auto it = preferences_.begin(); it != preferences_.end(); ++it)
268 if (it->unique_id.find(id) != std::string::npos)
269 return it;
270 return preferences_.end();
271}
272
273void
274VideoDeviceMonitor::overwritePreferences(const VideoSettings& settings)
275{
276 auto it = findPreferencesById(settings.unique_id);
277 if (it != preferences_.end())
278 preferences_.erase(it);
279 preferences_.emplace_back(settings);
280}
281
282void
284{
285 std::lock_guard l(lock_);
286 out << YAML::Key << "devices" << YAML::Value << preferences_;
287}
288
289void
291{
292 std::lock_guard l(lock_);
293 const auto& node = in[CONFIG_LABEL];
294
295 /* load the device list from the "video" YAML section */
296 const auto& devices = node["devices"];
297 for (const auto& dev : devices) {
299 if (pref.unique_id.empty())
300 continue; // discard malformed section
301 overwritePreferences(pref);
302 auto itd = findDeviceById(pref.unique_id);
303 if (itd != devices_.end())
304 itd->applySettings(pref);
305 }
306
307 // Restore the default device if present, or select the first one
308 const string prefId = preferences_.empty() ? "" : preferences_[0].unique_id;
309 const auto devIter = findDeviceById(prefId);
310 if (devIter != devices_.end() && prefId != DEVICE_DESKTOP) {
311 defaultDevice_ = devIter->getDeviceId();
312 } else {
313 defaultDevice_.clear();
314 for (const auto& dev : devices_)
315 if (dev.name != DEVICE_DESKTOP) {
316 defaultDevice_ = dev.getDeviceId();
317 break;
318 }
319 }
320}
321
322} // namespace video
323} // 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:218
#define JAMI_WARN(...)
Definition logger.h:217
Definition Address.h:25
static constexpr const char DEVICE_DESKTOP[]
static void giveUniqueName(VideoDevice &dev, const vector< VideoDevice > &devices)
void emitSignal(Args... args)
Definition ring_signal.h:64
static constexpr const char * CAMERA
Definition media_const.h:32
static constexpr const char * SEPARATOR
Definition media_const.h:33
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.