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