Line data Source code
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 : #ifdef HAVE_CONFIG_H
19 : #include "config.h"
20 : #endif
21 :
22 : #include "preferences.h"
23 : #include "logger.h"
24 : #include "audio/audiolayer.h"
25 :
26 : #if HAVE_AAUDIO
27 : #include "audio/aaudio/aaudiolayer.h"
28 : #else
29 : #if HAVE_ALSA
30 : #include "audio/alsa/alsalayer.h"
31 : #endif
32 : #if HAVE_JACK
33 : #include "audio/jack/jacklayer.h"
34 : #endif
35 : #if HAVE_PULSE
36 : #include "audio/pulseaudio/pulselayer.h"
37 : #endif
38 : #if HAVE_COREAUDIO
39 : #ifdef __APPLE__
40 : #include <TargetConditionals.h>
41 : #endif
42 : #if TARGET_OS_IOS
43 : #include "audio/coreaudio/ios/corelayer.h"
44 : #else
45 : #include "audio/coreaudio/osx/corelayer.h"
46 : #endif /* TARGET_OS_IOS */
47 : #endif /* HAVE_COREAUDIO */
48 : #if HAVE_PORTAUDIO
49 : #include "audio/portaudio/portaudiolayer.h"
50 : #endif
51 : #endif /* HAVE_AAUDIO */
52 :
53 : #ifdef ENABLE_VIDEO
54 : #include "client/videomanager.h"
55 : #endif
56 :
57 : #pragma GCC diagnostic push
58 : #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
59 : #include <yaml-cpp/yaml.h>
60 : #pragma GCC diagnostic pop
61 :
62 : #include "config/yamlparser.h"
63 : #include "connectivity/sip_utils.h"
64 : #include <algorithm>
65 : #include <stdexcept>
66 : #include "fileutils.h"
67 :
68 : namespace jami {
69 :
70 : using yaml_utils::parseValue;
71 :
72 : constexpr const char* const Preferences::CONFIG_LABEL;
73 : const char* const Preferences::DFT_ZONE = "North America";
74 : const char* const Preferences::REGISTRATION_EXPIRE_KEY = "registrationexpire";
75 : constexpr std::string_view DEFAULT_CONFERENCE_RESOLUTION {"1280x720"};
76 :
77 : // general preferences
78 : static constexpr const char* ORDER_KEY {"order"};
79 : static constexpr const char* PENDING_ACCOUNTS_KEY {"pendingAccounts"};
80 : static constexpr const char* AUDIO_API_KEY {"audioApi"};
81 : static constexpr const char* HISTORY_LIMIT_KEY {"historyLimit"};
82 : static constexpr const char* RINGING_TIMEOUT {"ringingTimeout"};
83 : static constexpr const char* HISTORY_MAX_CALLS_KEY {"historyMaxCalls"};
84 : static constexpr const char* ZONE_TONE_CHOICE_KEY {"zoneToneChoice"};
85 : static constexpr const char* PORT_NUM_KEY {"portNum"};
86 : static constexpr const char* SEARCH_BAR_DISPLAY_KEY {"searchBarDisplay"};
87 : static constexpr const char* MD5_HASH_KEY {"md5Hash"};
88 :
89 : // voip preferences
90 : constexpr const char* const VoipPreference::CONFIG_LABEL;
91 : static constexpr const char* PLAY_DTMF_KEY {"playDtmf"};
92 : static constexpr const char* PLAY_TONES_KEY {"playTones"};
93 : static constexpr const char* PULSE_LENGTH_KEY {"pulseLength"};
94 :
95 : // audio preferences
96 : constexpr const char* const AudioPreference::CONFIG_LABEL;
97 : static constexpr const char* ALSAMAP_KEY {"alsa"};
98 : static constexpr const char* PULSEMAP_KEY {"pulse"};
99 : static constexpr const char* PORTAUDIO_KEY {"portaudio"};
100 : static constexpr const char* CARDIN_KEY {"cardIn"};
101 : static constexpr const char* CARDOUT_KEY {"cardOut"};
102 : static constexpr const char* CARLIBJAMI_KEY {"cardRing"};
103 : static constexpr const char* PLUGIN_KEY {"plugin"};
104 : static constexpr const char* SMPLRATE_KEY {"smplRate"};
105 : static constexpr const char* DEVICE_PLAYBACK_KEY {"devicePlayback"};
106 : static constexpr const char* DEVICE_RECORD_KEY {"deviceRecord"};
107 : static constexpr const char* DEVICE_RINGTONE_KEY {"deviceRingtone"};
108 : static constexpr const char* RECORDPATH_KEY {"recordPath"};
109 : static constexpr const char* ALWAYS_RECORDING_KEY {"alwaysRecording"};
110 : static constexpr const char* VOLUMEMIC_KEY {"volumeMic"};
111 : static constexpr const char* VOLUMESPKR_KEY {"volumeSpkr"};
112 : static constexpr const char* AUDIO_PROCESSOR_KEY {"audioProcessor"};
113 : static constexpr const char* NOISE_REDUCE_KEY {"noiseReduce"};
114 : static constexpr const char* AGC_KEY {"automaticGainControl"};
115 : static constexpr const char* CAPTURE_MUTED_KEY {"captureMuted"};
116 : static constexpr const char* PLAYBACK_MUTED_KEY {"playbackMuted"};
117 : static constexpr const char* VAD_KEY {"voiceActivityDetection"};
118 : static constexpr const char* ECHO_CANCEL_KEY {"echoCancel"};
119 :
120 : #ifdef ENABLE_VIDEO
121 : // video preferences
122 : constexpr const char* const VideoPreferences::CONFIG_LABEL;
123 : static constexpr const char* DECODING_ACCELERATED_KEY {"decodingAccelerated"};
124 : static constexpr const char* ENCODING_ACCELERATED_KEY {"encodingAccelerated"};
125 : static constexpr const char* RECORD_PREVIEW_KEY {"recordPreview"};
126 : static constexpr const char* RECORD_QUALITY_KEY {"recordQuality"};
127 : static constexpr const char* CONFERENCE_RESOLUTION_KEY {"conferenceResolution"};
128 : #endif
129 :
130 : #ifdef ENABLE_PLUGIN
131 : // plugin preferences
132 : constexpr const char* const PluginPreferences::CONFIG_LABEL;
133 : static constexpr const char* JAMI_PLUGIN_KEY {"pluginsEnabled"};
134 : static constexpr const char* JAMI_PLUGINS_INSTALLED_KEY {"installedPlugins"};
135 : static constexpr const char* JAMI_PLUGINS_LOADED_KEY {"loadedPlugins"};
136 : #endif
137 :
138 : static constexpr int PULSE_LENGTH_DEFAULT {250}; /** Default DTMF length */
139 : #ifndef _MSC_VER
140 : static constexpr const char* ALSA_DFT_CARD {"0"}; /** Default sound card index */
141 : #else
142 : static constexpr const char* ALSA_DFT_CARD {"-1"}; /** Default sound card index (Portaudio) */
143 : #endif // _MSC_VER
144 :
145 39 : Preferences::Preferences()
146 39 : : accountOrder_("")
147 39 : , historyLimit_(0)
148 39 : , historyMaxCalls_(20)
149 39 : , ringingTimeout_(30)
150 78 : , zoneToneChoice_(DFT_ZONE) // DFT_ZONE
151 39 : , portNum_(sip_utils::DEFAULT_SIP_PORT)
152 39 : , searchBarDisplay_(true)
153 78 : , md5Hash_(false)
154 39 : {}
155 :
156 : void
157 2534 : Preferences::verifyAccountOrder(const std::vector<std::string>& accountIDs)
158 : {
159 2534 : std::vector<std::string> tokens;
160 2534 : std::string token;
161 2534 : bool drop = false;
162 :
163 106148 : for (const auto c : accountOrder_) {
164 103614 : if (c != '/') {
165 97518 : token += c;
166 : } else {
167 6096 : if (find(accountIDs.begin(), accountIDs.end(), token) != accountIDs.end())
168 6092 : tokens.push_back(token);
169 : else {
170 16 : JAMI_LOG("Dropping nonexistent account {}", token);
171 4 : drop = true;
172 : }
173 6096 : token.clear();
174 : }
175 : }
176 :
177 2534 : if (drop) {
178 1 : accountOrder_.clear();
179 2 : for (const auto& t : tokens)
180 1 : accountOrder_ += t + '/';
181 : }
182 2534 : }
183 :
184 : void
185 817 : Preferences::addAccount(const std::string& newAccountID)
186 : {
187 : // Add the newly created account in the account order list
188 817 : if (not accountOrder_.empty())
189 541 : accountOrder_.insert(0, newAccountID + "/");
190 : else
191 276 : accountOrder_ = newAccountID + "/";
192 817 : }
193 :
194 : void
195 817 : Preferences::removeAccount(const std::string& oldAccountID)
196 : {
197 : // include the slash since we don't want to remove a partial match
198 817 : const size_t start = accountOrder_.find(oldAccountID + "/");
199 817 : if (start != std::string::npos)
200 817 : accountOrder_.erase(start, oldAccountID.length() + 1);
201 817 : }
202 :
203 : bool
204 36 : Preferences::isAccountPending(const std::string& accountId) const
205 : {
206 36 : return pendingAccountIds_.count(accountId) > 0;
207 : }
208 :
209 : bool
210 793 : Preferences::addPendingAccountId(const std::string& accountId)
211 : {
212 793 : if (accountId.empty())
213 0 : return false;
214 793 : return pendingAccountIds_.insert(accountId).second;
215 : }
216 :
217 : bool
218 1628 : Preferences::removePendingAccountId(const std::string& accountId)
219 : {
220 1628 : if (accountId.empty())
221 0 : return false;
222 1628 : return pendingAccountIds_.erase(accountId) > 0;
223 : }
224 :
225 : void
226 2534 : Preferences::serialize(YAML::Emitter& out) const
227 : {
228 2534 : out << YAML::Key << CONFIG_LABEL << YAML::Value << YAML::BeginMap;
229 :
230 2534 : out << YAML::Key << HISTORY_LIMIT_KEY << YAML::Value << historyLimit_;
231 2534 : out << YAML::Key << RINGING_TIMEOUT << YAML::Value << ringingTimeout_;
232 2534 : out << YAML::Key << HISTORY_MAX_CALLS_KEY << YAML::Value << historyMaxCalls_;
233 2534 : out << YAML::Key << MD5_HASH_KEY << YAML::Value << md5Hash_;
234 2534 : out << YAML::Key << ORDER_KEY << YAML::Value << accountOrder_;
235 2534 : out << YAML::Key << PORT_NUM_KEY << YAML::Value << portNum_;
236 2534 : out << YAML::Key << SEARCH_BAR_DISPLAY_KEY << YAML::Value << searchBarDisplay_;
237 2534 : out << YAML::Key << ZONE_TONE_CHOICE_KEY << YAML::Value << zoneToneChoice_;
238 2534 : out << YAML::Key << PENDING_ACCOUNTS_KEY << YAML::Value << YAML::BeginSeq;
239 5349 : for (const auto& accountId : pendingAccountIds_)
240 2815 : out << accountId;
241 2534 : out << YAML::EndSeq;
242 2534 : out << YAML::EndMap;
243 2534 : }
244 :
245 : void
246 36 : Preferences::unserialize(const YAML::Node& in)
247 : {
248 36 : const auto& node = in[CONFIG_LABEL];
249 :
250 36 : parseValue(node, ORDER_KEY, accountOrder_);
251 30 : parseValue(node, HISTORY_LIMIT_KEY, historyLimit_);
252 30 : parseValue(node, RINGING_TIMEOUT, ringingTimeout_);
253 30 : parseValue(node, HISTORY_MAX_CALLS_KEY, historyMaxCalls_);
254 30 : parseValue(node, ZONE_TONE_CHOICE_KEY, zoneToneChoice_);
255 30 : parseValue(node, PORT_NUM_KEY, portNum_);
256 30 : parseValue(node, SEARCH_BAR_DISPLAY_KEY, searchBarDisplay_);
257 30 : parseValue(node, MD5_HASH_KEY, md5Hash_);
258 :
259 30 : pendingAccountIds_.clear();
260 30 : if (const auto& pending = node[PENDING_ACCOUNTS_KEY]; pending && pending.IsSequence()) {
261 30 : for (const auto& entry : pending) {
262 : try {
263 0 : pendingAccountIds_.insert(entry.as<std::string>());
264 0 : } catch (const YAML::Exception& e) {
265 0 : JAMI_WARNING("[config] Unable to read pending account id: {}", e.what());
266 0 : }
267 0 : }
268 30 : }
269 36 : }
270 :
271 39 : VoipPreference::VoipPreference()
272 39 : : playDtmf_(true)
273 39 : , playTones_(true)
274 39 : , pulseLength_(PULSE_LENGTH_DEFAULT)
275 39 : {}
276 :
277 : void
278 2534 : VoipPreference::serialize(YAML::Emitter& out) const
279 : {
280 2534 : out << YAML::Key << CONFIG_LABEL << YAML::Value << YAML::BeginMap;
281 2534 : out << YAML::Key << PLAY_DTMF_KEY << YAML::Value << playDtmf_;
282 2534 : out << YAML::Key << PLAY_TONES_KEY << YAML::Value << playTones_;
283 2534 : out << YAML::Key << PULSE_LENGTH_KEY << YAML::Value << pulseLength_;
284 2534 : out << YAML::EndMap;
285 2534 : }
286 :
287 : void
288 30 : VoipPreference::unserialize(const YAML::Node& in)
289 : {
290 30 : const auto& node = in[CONFIG_LABEL];
291 30 : parseValue(node, PLAY_DTMF_KEY, playDtmf_);
292 30 : parseValue(node, PLAY_TONES_KEY, playTones_);
293 30 : parseValue(node, PULSE_LENGTH_KEY, pulseLength_);
294 30 : }
295 :
296 39 : AudioPreference::AudioPreference()
297 39 : : audioApi_(PULSEAUDIO_API_STR)
298 39 : , alsaCardin_(atoi(ALSA_DFT_CARD))
299 39 : , alsaCardout_(atoi(ALSA_DFT_CARD))
300 39 : , alsaCardRingtone_(atoi(ALSA_DFT_CARD))
301 78 : , alsaPlugin_("default")
302 39 : , alsaSmplrate_(44100)
303 78 : , pulseDevicePlayback_("")
304 78 : , pulseDeviceRecord_("")
305 78 : , pulseDeviceRingtone_("")
306 78 : , recordpath_("")
307 39 : , alwaysRecording_(false)
308 39 : , volumemic_(1.0)
309 39 : , volumespkr_(1.0)
310 78 : , audioProcessor_("webrtc")
311 78 : , denoise_("auto")
312 39 : , agcEnabled_(true)
313 39 : , vadEnabled_(true)
314 : #ifdef __linux__
315 78 : , echoCanceller_("audioProcessor")
316 : #else
317 : , echoCanceller_("auto")
318 : #endif // __linux__
319 39 : , captureMuted_(false)
320 78 : , playbackMuted_(false)
321 39 : {}
322 :
323 : #if HAVE_ALSA
324 :
325 : static const int ALSA_DFT_CARD_ID = 0; // Index of the default soundcard
326 :
327 : static void
328 99 : checkSoundCard(int& card, AudioDeviceType type)
329 : {
330 99 : if (not AlsaLayer::soundCardIndexExists(card, type)) {
331 396 : JAMI_WARNING(" Card with index {} doesn't exist or is unusable.", card);
332 99 : card = ALSA_DFT_CARD_ID;
333 : }
334 99 : }
335 : #endif
336 :
337 : AudioLayer*
338 33 : AudioPreference::createAudioLayer()
339 : {
340 : #if HAVE_AAUDIO
341 : return new AAudioLayer(*this);
342 : #else
343 :
344 : #if HAVE_JACK
345 : if (audioApi_ == JACK_API_STR) {
346 : try {
347 : if (auto ret = system("jack_lsp > /dev/null"))
348 : throw std::runtime_error("Error running jack_lsp: " + std::to_string(ret));
349 : return new JackLayer(*this);
350 : } catch (const std::runtime_error& e) {
351 : JAMI_ERROR("{}", e.what());
352 : #if HAVE_PULSE
353 : audioApi_ = PULSEAUDIO_API_STR;
354 : #elif HAVE_ALSA
355 : audioApi_ = ALSA_API_STR;
356 : #elif HAVE_COREAUDIO
357 : audioApi_ = COREAUDIO_API_STR;
358 : #elif HAVE_PORTAUDIO
359 : audioApi_ = PORTAUDIO_API_STR;
360 : #else
361 : throw;
362 : #endif // HAVE_PULSE
363 : }
364 : }
365 : #endif // HAVE_JACK
366 :
367 : #if HAVE_PULSE
368 :
369 33 : if (audioApi_ == PULSEAUDIO_API_STR) {
370 : try {
371 3 : return new PulseLayer(*this);
372 3 : } catch (const std::runtime_error& e) {
373 12 : JAMI_WARNING("Unable to create pulseaudio layer, falling back to ALSA");
374 3 : }
375 : }
376 :
377 : #endif
378 :
379 : #if HAVE_ALSA
380 :
381 33 : audioApi_ = ALSA_API_STR;
382 33 : checkSoundCard(alsaCardin_, AudioDeviceType::CAPTURE);
383 33 : checkSoundCard(alsaCardout_, AudioDeviceType::PLAYBACK);
384 33 : checkSoundCard(alsaCardRingtone_, AudioDeviceType::RINGTONE);
385 :
386 33 : return new AlsaLayer(*this);
387 : #endif
388 :
389 : #if HAVE_COREAUDIO
390 : audioApi_ = COREAUDIO_API_STR;
391 : try {
392 : return new CoreLayer(*this);
393 : } catch (const std::runtime_error& e) {
394 : JAMI_WARNING("Unable to create coreaudio layer. There will be no sound.");
395 : }
396 : return NULL;
397 : #endif
398 :
399 : #if HAVE_PORTAUDIO
400 : audioApi_ = PORTAUDIO_API_STR;
401 : try {
402 : return new PortAudioLayer(*this);
403 : } catch (const std::runtime_error& e) {
404 : JAMI_WARNING("Unable to create PortAudio layer. There will be no sound.");
405 : }
406 : return nullptr;
407 : #endif
408 : #endif // HAVE_AAUDIO
409 :
410 0 : JAMI_WARNING("No audio layer provided");
411 : return nullptr;
412 : }
413 :
414 : std::vector<std::string>
415 0 : AudioPreference::getSupportedAudioManagers()
416 : {
417 : return {
418 : #if HAVE_AAUDIO
419 : AAUDIO_API_STR,
420 : #endif
421 : #if HAVE_ALSA
422 : ALSA_API_STR,
423 : #endif
424 : #if HAVE_PULSE
425 : PULSEAUDIO_API_STR,
426 : #endif
427 : #if HAVE_JACK
428 : JACK_API_STR,
429 : #endif
430 : #if HAVE_COREAUDIO
431 : COREAUDIO_API_STR,
432 : #endif
433 : #if HAVE_PORTAUDIO
434 : PORTAUDIO_API_STR,
435 : #endif
436 0 : };
437 : }
438 :
439 : void
440 2534 : AudioPreference::serialize(YAML::Emitter& out) const
441 : {
442 2534 : out << YAML::Key << CONFIG_LABEL << YAML::Value << YAML::BeginMap;
443 : // alsa submap
444 2534 : out << YAML::Key << ALSAMAP_KEY << YAML::Value << YAML::BeginMap;
445 2534 : out << YAML::Key << CARDIN_KEY << YAML::Value << alsaCardin_;
446 2534 : out << YAML::Key << CARDOUT_KEY << YAML::Value << alsaCardout_;
447 2534 : out << YAML::Key << CARLIBJAMI_KEY << YAML::Value << alsaCardRingtone_;
448 2534 : out << YAML::Key << PLUGIN_KEY << YAML::Value << alsaPlugin_;
449 2534 : out << YAML::Key << SMPLRATE_KEY << YAML::Value << alsaSmplrate_;
450 2534 : out << YAML::EndMap;
451 :
452 : // common options
453 2534 : out << YAML::Key << ALWAYS_RECORDING_KEY << YAML::Value << alwaysRecording_;
454 2534 : out << YAML::Key << AUDIO_API_KEY << YAML::Value << audioApi_;
455 2534 : out << YAML::Key << CAPTURE_MUTED_KEY << YAML::Value << captureMuted_;
456 2534 : out << YAML::Key << PLAYBACK_MUTED_KEY << YAML::Value << playbackMuted_;
457 :
458 : // pulse submap
459 2534 : out << YAML::Key << PULSEMAP_KEY << YAML::Value << YAML::BeginMap;
460 2534 : out << YAML::Key << DEVICE_PLAYBACK_KEY << YAML::Value << pulseDevicePlayback_;
461 2534 : out << YAML::Key << DEVICE_RECORD_KEY << YAML::Value << pulseDeviceRecord_;
462 2534 : out << YAML::Key << DEVICE_RINGTONE_KEY << YAML::Value << pulseDeviceRingtone_;
463 2534 : out << YAML::EndMap;
464 :
465 : // portaudio submap
466 2534 : out << YAML::Key << PORTAUDIO_KEY << YAML::Value << YAML::BeginMap;
467 2534 : out << YAML::Key << DEVICE_PLAYBACK_KEY << YAML::Value << portaudioDevicePlayback_;
468 2534 : out << YAML::Key << DEVICE_RECORD_KEY << YAML::Value << portaudioDeviceRecord_;
469 2534 : out << YAML::Key << DEVICE_RINGTONE_KEY << YAML::Value << portaudioDeviceRingtone_;
470 2534 : out << YAML::EndMap;
471 :
472 : // more common options!
473 2534 : out << YAML::Key << RECORDPATH_KEY << YAML::Value << recordpath_;
474 2534 : out << YAML::Key << VOLUMEMIC_KEY << YAML::Value << volumemic_;
475 2534 : out << YAML::Key << VOLUMESPKR_KEY << YAML::Value << volumespkr_;
476 :
477 : // audio processor options, not in a submap
478 2534 : out << YAML::Key << AUDIO_PROCESSOR_KEY << YAML::Value << audioProcessor_;
479 2534 : out << YAML::Key << AGC_KEY << YAML::Value << agcEnabled_;
480 2534 : out << YAML::Key << VAD_KEY << YAML::Value << vadEnabled_;
481 2534 : out << YAML::Key << NOISE_REDUCE_KEY << YAML::Value << denoise_;
482 2534 : out << YAML::Key << ECHO_CANCEL_KEY << YAML::Value << echoCanceller_;
483 2534 : out << YAML::EndMap;
484 2534 : }
485 :
486 : bool
487 5 : AudioPreference::setRecordPath(const std::string& r)
488 : {
489 5 : std::string path = fileutils::expand_path(r);
490 5 : if (fileutils::isDirectoryWritable(path)) {
491 5 : recordpath_ = path;
492 5 : return true;
493 : } else {
494 0 : JAMI_ERROR("{} is not writable, unable to be the recording path", path);
495 0 : return false;
496 : }
497 5 : }
498 :
499 : void
500 30 : AudioPreference::unserialize(const YAML::Node& in)
501 : {
502 30 : const auto& node = in[CONFIG_LABEL];
503 :
504 : // alsa submap
505 30 : const auto& alsa = node[ALSAMAP_KEY];
506 :
507 30 : parseValue(alsa, CARDIN_KEY, alsaCardin_);
508 30 : parseValue(alsa, CARDOUT_KEY, alsaCardout_);
509 30 : parseValue(alsa, CARLIBJAMI_KEY, alsaCardRingtone_);
510 30 : parseValue(alsa, PLUGIN_KEY, alsaPlugin_);
511 30 : parseValue(alsa, SMPLRATE_KEY, alsaSmplrate_);
512 :
513 : // common options
514 30 : parseValue(node, ALWAYS_RECORDING_KEY, alwaysRecording_);
515 30 : parseValue(node, AUDIO_API_KEY, audioApi_);
516 30 : parseValue(node, AGC_KEY, agcEnabled_);
517 30 : parseValue(node, CAPTURE_MUTED_KEY, captureMuted_);
518 30 : parseValue(node, NOISE_REDUCE_KEY, denoise_);
519 30 : parseValue(node, PLAYBACK_MUTED_KEY, playbackMuted_);
520 :
521 : // pulse submap
522 30 : const auto& pulse = node[PULSEMAP_KEY];
523 30 : parseValue(pulse, DEVICE_PLAYBACK_KEY, pulseDevicePlayback_);
524 30 : parseValue(pulse, DEVICE_RECORD_KEY, pulseDeviceRecord_);
525 30 : parseValue(pulse, DEVICE_RINGTONE_KEY, pulseDeviceRingtone_);
526 :
527 : // portaudio submap
528 30 : const auto& portaudio = node[PORTAUDIO_KEY];
529 30 : parseValue(portaudio, DEVICE_PLAYBACK_KEY, portaudioDevicePlayback_);
530 30 : parseValue(portaudio, DEVICE_RECORD_KEY, portaudioDeviceRecord_);
531 30 : parseValue(portaudio, DEVICE_RINGTONE_KEY, portaudioDeviceRingtone_);
532 :
533 : // more common options!
534 30 : parseValue(node, RECORDPATH_KEY, recordpath_);
535 30 : parseValue(node, VOLUMEMIC_KEY, volumemic_);
536 30 : parseValue(node, VOLUMESPKR_KEY, volumespkr_);
537 30 : parseValue(node, AUDIO_PROCESSOR_KEY, audioProcessor_);
538 30 : parseValue(node, VAD_KEY, vadEnabled_);
539 30 : parseValue(node, ECHO_CANCEL_KEY, echoCanceller_);
540 30 : }
541 :
542 : #ifdef ENABLE_VIDEO
543 39 : VideoPreferences::VideoPreferences()
544 39 : : decodingAccelerated_(true)
545 39 : , encodingAccelerated_(false)
546 39 : , recordPreview_(true)
547 39 : , recordQuality_(0)
548 78 : , conferenceResolution_(DEFAULT_CONFERENCE_RESOLUTION)
549 39 : {}
550 :
551 : void
552 2534 : VideoPreferences::serialize(YAML::Emitter& out) const
553 : {
554 2534 : out << YAML::Key << CONFIG_LABEL << YAML::Value << YAML::BeginMap;
555 2534 : out << YAML::Key << RECORD_PREVIEW_KEY << YAML::Value << recordPreview_;
556 2534 : out << YAML::Key << RECORD_QUALITY_KEY << YAML::Value << recordQuality_;
557 : #ifdef ENABLE_HWACCEL
558 2534 : out << YAML::Key << DECODING_ACCELERATED_KEY << YAML::Value << decodingAccelerated_;
559 2534 : out << YAML::Key << ENCODING_ACCELERATED_KEY << YAML::Value << encodingAccelerated_;
560 : #endif
561 2534 : out << YAML::Key << CONFERENCE_RESOLUTION_KEY << YAML::Value << conferenceResolution_;
562 2534 : if (auto* dm = getVideoDeviceMonitor())
563 2528 : dm->serialize(out);
564 2534 : out << YAML::EndMap;
565 2534 : }
566 :
567 : void
568 30 : VideoPreferences::unserialize(const YAML::Node& in)
569 : {
570 : // values may or may not be present
571 30 : const auto& node = in[CONFIG_LABEL];
572 : try {
573 30 : parseValue(node, RECORD_PREVIEW_KEY, recordPreview_);
574 30 : parseValue(node, RECORD_QUALITY_KEY, recordQuality_);
575 0 : } catch (...) {
576 0 : recordPreview_ = true;
577 0 : recordQuality_ = 0;
578 0 : }
579 : #ifdef ENABLE_HWACCEL
580 : try {
581 30 : parseValue(node, DECODING_ACCELERATED_KEY, decodingAccelerated_);
582 30 : parseValue(node, ENCODING_ACCELERATED_KEY, encodingAccelerated_);
583 0 : } catch (...) {
584 0 : decodingAccelerated_ = true;
585 0 : encodingAccelerated_ = false;
586 0 : }
587 : #endif
588 : try {
589 30 : parseValue(node, CONFERENCE_RESOLUTION_KEY, conferenceResolution_);
590 0 : } catch (...) {
591 0 : conferenceResolution_ = DEFAULT_CONFERENCE_RESOLUTION;
592 0 : }
593 30 : if (auto* dm = getVideoDeviceMonitor())
594 30 : dm->unserialize(in);
595 30 : }
596 : #endif // ENABLE_VIDEO
597 :
598 : #ifdef ENABLE_PLUGIN
599 39 : PluginPreferences::PluginPreferences()
600 39 : : pluginsEnabled_(false)
601 39 : {}
602 :
603 : void
604 2534 : PluginPreferences::serialize(YAML::Emitter& out) const
605 : {
606 2534 : out << YAML::Key << CONFIG_LABEL << YAML::Value << YAML::BeginMap;
607 2534 : out << YAML::Key << JAMI_PLUGIN_KEY << YAML::Value << pluginsEnabled_;
608 2534 : out << YAML::Key << JAMI_PLUGINS_INSTALLED_KEY << YAML::Value << installedPlugins_;
609 2534 : out << YAML::Key << JAMI_PLUGINS_LOADED_KEY << YAML::Value << loadedPlugins_;
610 2534 : out << YAML::EndMap;
611 2534 : }
612 :
613 : void
614 30 : PluginPreferences::unserialize(const YAML::Node& in)
615 : {
616 : // values may or may not be present
617 30 : const auto& node = in[CONFIG_LABEL];
618 : try {
619 30 : parseValue(node, JAMI_PLUGIN_KEY, pluginsEnabled_);
620 0 : } catch (...) {
621 0 : pluginsEnabled_ = false;
622 0 : }
623 :
624 30 : const auto& installedPluginsNode = node[JAMI_PLUGINS_INSTALLED_KEY];
625 : try {
626 30 : installedPlugins_ = yaml_utils::parseVector(installedPluginsNode);
627 0 : } catch (const std::exception& e) {
628 0 : JAMI_WARNING("Couldn't parse vector of installed plugins: {}", e.what());
629 0 : }
630 :
631 30 : const auto& loadedPluginsNode = node[JAMI_PLUGINS_LOADED_KEY];
632 : try {
633 30 : loadedPlugins_ = yaml_utils::parseVector(loadedPluginsNode);
634 0 : } catch (const std::exception& e) {
635 0 : JAMI_WARNING("Couldn't parse vector of loaded plugins: {}", e.what());
636 0 : }
637 30 : }
638 : #endif // ENABLE_PLUGIN
639 :
640 : } // namespace jami
|