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