preferences.cpp 20.8 KB
Newer Older
1
/*
2
 *  Copyright (C) 2004-2019 Savoir-faire Linux Inc.
3
 *
4
 *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
5
 *  Author: Philippe Gorley <philippe.gorley@savoirfairelinux.com>
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
19
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
20 21
 */

22 23 24 25
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

26
#include "preferences.h"
27
#include "logger.h"
28
#include "audio/audiolayer.h"
29
#if HAVE_OPENSL
Adrien Béraud's avatar
Adrien Béraud committed
30 31
#include "audio/opensl/opensllayer.h"
#else
32
#if HAVE_ALSA
33
#include "audio/alsa/alsalayer.h"
34
#endif
35 36 37
#if HAVE_JACK
#include "audio/jack/jacklayer.h"
#endif
38
#if HAVE_PULSE
39
#include "audio/pulseaudio/pulselayer.h"
40
#endif
41
#if HAVE_COREAUDIO
42 43
#ifdef __APPLE__
#include <TargetConditionals.h>
44
#endif
45 46 47 48 49 50
#if TARGET_OS_IOS
#include "audio/coreaudio/ios/corelayer.h"
#else
#include "audio/coreaudio/osx/corelayer.h"
#endif /* TARGET_OS_IOS */
#endif /* HAVE_COREAUDIO */
Edric Milaret's avatar
Edric Milaret committed
51 52 53
#if HAVE_PORTAUDIO
#include "audio/portaudio/portaudiolayer.h"
#endif
54
#endif /* HAVE_OPENSL */
55

Adrien Béraud's avatar
Adrien Béraud committed
56
#ifdef ENABLE_VIDEO
57
#include "client/videomanager.h"
58
#endif
59

60 61
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
62
#include <yaml-cpp/yaml.h>
63 64
#pragma GCC diagnostic pop

65
#include "config/yamlparser.h"
66
#include "hooks/urlhook.h"
67
#include "sip/sip_utils.h"
68
#include <sstream>
69
#include <algorithm>
Edric Milaret's avatar
Edric Milaret committed
70
#include <stdexcept>
71
#include "fileutils.h"
72
#include "string_utils.h"
73

Adrien Béraud's avatar
Adrien Béraud committed
74
namespace jami {
75 76 77

using yaml_utils::parseValue;

78
constexpr const char * const Preferences::CONFIG_LABEL;
79
const char * const Preferences::DFT_ZONE = "North America";
80
const char * const Preferences::REGISTRATION_EXPIRE_KEY = "registrationexpire";
81

82
// general preferences
83 84 85 86 87 88 89 90 91
static constexpr const char* ORDER_KEY {"order"};
static constexpr const char* AUDIO_API_KEY {"audioApi"};
static constexpr const char* HISTORY_LIMIT_KEY {"historyLimit"};
static constexpr const char* RINGING_TIMEOUT {"ringingTimeout"};
static constexpr const char* HISTORY_MAX_CALLS_KEY {"historyMaxCalls"};
static constexpr const char* ZONE_TONE_CHOICE_KEY {"zoneToneChoice"};
static constexpr const char* PORT_NUM_KEY {"portNum"};
static constexpr const char* SEARCH_BAR_DISPLAY_KEY {"searchBarDisplay"};
static constexpr const char* MD5_HASH_KEY {"md5Hash"};
92 93

// voip preferences
94
constexpr const char * const VoipPreference::CONFIG_LABEL;
95 96 97 98 99
static constexpr const char* PLAY_DTMF_KEY {"playDtmf"};
static constexpr const char* PLAY_TONES_KEY {"playTones"};
static constexpr const char* PULSE_LENGTH_KEY {"pulseLength"};
static constexpr const char* SYMMETRIC_RTP_KEY {"symmetric"};
static constexpr const char* ZID_FILE_KEY {"zidFile"};
100 101

// hooks preferences
102
constexpr const char * const HookPreference::CONFIG_LABEL;
103 104 105 106 107
static constexpr const char* NUMBER_ADD_PREFIX_KEY {"numberAddPrefix"};
static constexpr const char* NUMBER_ENABLED_KEY {"numberEnabled"};
static constexpr const char* SIP_ENABLED_KEY {"sipEnabled"};
static constexpr const char* URL_COMMAND_KEY {"urlCommand"};
static constexpr const char* URL_SIP_FIELD_KEY {"urlSipField"};
108 109

// audio preferences
110
constexpr const char * const AudioPreference::CONFIG_LABEL;
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
static constexpr const char* ALSAMAP_KEY {"alsa"};
static constexpr const char* PULSEMAP_KEY {"pulse"};
static constexpr const char* CARDIN_KEY {"cardIn"};
static constexpr const char* CARDOUT_KEY {"cardOut"};
static constexpr const char* CARDRING_KEY {"cardRing"};
static constexpr const char* PLUGIN_KEY {"plugin"};
static constexpr const char* SMPLRATE_KEY {"smplRate"};
static constexpr const char* DEVICE_PLAYBACK_KEY {"devicePlayback"};
static constexpr const char* DEVICE_RECORD_KEY {"deviceRecord"};
static constexpr const char* DEVICE_RINGTONE_KEY {"deviceRingtone"};
static constexpr const char* RECORDPATH_KEY {"recordPath"};
static constexpr const char* ALWAYS_RECORDING_KEY {"alwaysRecording"};
static constexpr const char* VOLUMEMIC_KEY {"volumeMic"};
static constexpr const char* VOLUMESPKR_KEY {"volumeSpkr"};
static constexpr const char* NOISE_REDUCE_KEY {"noiseReduce"};
static constexpr const char* AGC_KEY {"automaticGainControl"};
static constexpr const char* CAPTURE_MUTED_KEY {"captureMuted"};
static constexpr const char* PLAYBACK_MUTED_KEY {"playbackMuted"};
129 130

// shortcut preferences
131
constexpr const char * const ShortcutPreferences::CONFIG_LABEL;
132 133 134 135 136
static constexpr const char* HANGUP_SHORT_KEY {"hangUp"};
static constexpr const char* PICKUP_SHORT_KEY {"pickUp"};
static constexpr const char* POPUP_SHORT_KEY {"popupWindow"};
static constexpr const char* TOGGLE_HOLD_SHORT_KEY {"toggleHold"};
static constexpr const char* TOGGLE_PICKUP_HANGUP_SHORT_KEY {"togglePickupHangup"};
137

Adrien Béraud's avatar
Adrien Béraud committed
138
#ifdef ENABLE_VIDEO
139 140
// video preferences
constexpr const char * const VideoPreferences::CONFIG_LABEL;
141 142
static constexpr const char* DECODING_ACCELERATED_KEY {"decodingAccelerated"};
static constexpr const char* ENCODING_ACCELERATED_KEY {"encodingAccelerated"};
143 144
static constexpr const char* RECORD_PREVIEW_KEY {"recordPreview"};
static constexpr const char* RECORD_QUALITY_KEY {"recordQuality"};
145
#endif
146

Adrien Béraud's avatar
Adrien Béraud committed
147
static constexpr int PULSE_LENGTH_DEFAULT {250}; /** Default DTMF length */
148
#ifndef _MSC_VER
149
static constexpr const char* ALSA_DFT_CARD {"0"};          /** Default sound card index */
150
#else
151
static constexpr const char* ALSA_DFT_CARD {"-1"};         /** Default sound card index (Portaudio) */
152 153
#endif // _MSC_VER

154

155 156
Preferences::Preferences() :
    accountOrder_("")
157
    , historyLimit_(0)
158
    , historyMaxCalls_(20)
159
    , ringingTimeout_(30)
160 161
    , zoneToneChoice_(DFT_ZONE) // DFT_ZONE
    , registrationExpire_(180)
162
    , portNum_(sip_utils::DEFAULT_SIP_PORT)
163 164 165
    , searchBarDisplay_(true)
    , md5Hash_(false)
{}
166

167 168
void Preferences::verifyAccountOrder(const std::vector<std::string> &accountIDs)
{
169 170
    std::vector<std::string> tokens;
    std::string token;
171 172 173 174 175 176 177 178 179
    bool drop = false;

    for (const auto c : accountOrder_) {
        if (c != '/') {
            token += c;
        } else {
            if (find(accountIDs.begin(), accountIDs.end(), token) != accountIDs.end())
                tokens.push_back(token);
            else {
Adrien Béraud's avatar
Adrien Béraud committed
180
                JAMI_DBG("Dropping nonexistent account %s", token.c_str());
181 182 183 184 185 186 187 188 189 190 191 192 193
                drop = true;
            }
            token.clear();
        }
    }

    if (drop) {
        accountOrder_.clear();
        for (const auto &t : tokens)
            accountOrder_ += t + "/";
    }
}

194 195 196 197 198 199 200 201 202
void Preferences::addAccount(const std::string &newAccountID)
{
    // Add the newly created account in the account order list
    if (not accountOrder_.empty())
        accountOrder_.insert(0, newAccountID + "/");
    else
        accountOrder_ = newAccountID + "/";
}

203 204 205 206 207 208 209 210
void Preferences::removeAccount(const std::string &oldAccountID)
{
    // include the slash since we don't want to remove a partial match
    const size_t start = accountOrder_.find(oldAccountID + "/");
    if (start != std::string::npos)
        accountOrder_.erase(start, oldAccountID.length() + 1);
}

211
void Preferences::serialize(YAML::Emitter &out) const
212
{
213 214 215
    out << YAML::Key << CONFIG_LABEL << YAML::Value << YAML::BeginMap;

    out << YAML::Key << HISTORY_LIMIT_KEY << YAML::Value << historyLimit_;
216
    out << YAML::Key << RINGING_TIMEOUT << YAML::Value << ringingTimeout_;
217 218 219 220 221 222 223 224
    out << YAML::Key << HISTORY_MAX_CALLS_KEY << YAML::Value << historyMaxCalls_;
    out << YAML::Key << MD5_HASH_KEY << YAML::Value << md5Hash_;
    out << YAML::Key << ORDER_KEY << YAML::Value << accountOrder_;
    out << YAML::Key << PORT_NUM_KEY << YAML::Value << portNum_;
    out << YAML::Key << REGISTRATION_EXPIRE_KEY << YAML::Value << registrationExpire_;
    out << YAML::Key << SEARCH_BAR_DISPLAY_KEY << YAML::Value << searchBarDisplay_;
    out << YAML::Key << ZONE_TONE_CHOICE_KEY << YAML::Value << zoneToneChoice_;
    out << YAML::EndMap;
225 226
}

227
void Preferences::unserialize(const YAML::Node &in)
228
{
229 230 231 232
    const auto &node = in[CONFIG_LABEL];

    parseValue(node, ORDER_KEY, accountOrder_);
    parseValue(node, HISTORY_LIMIT_KEY, historyLimit_);
233
    parseValue(node, RINGING_TIMEOUT, ringingTimeout_);
234 235 236 237 238 239
    parseValue(node, HISTORY_MAX_CALLS_KEY, historyMaxCalls_);
    parseValue(node, ZONE_TONE_CHOICE_KEY, zoneToneChoice_);
    parseValue(node, REGISTRATION_EXPIRE_KEY, registrationExpire_);
    parseValue(node, PORT_NUM_KEY, portNum_);
    parseValue(node, SEARCH_BAR_DISPLAY_KEY, searchBarDisplay_);
    parseValue(node, MD5_HASH_KEY, md5Hash_);
240 241
}

242 243
VoipPreference::VoipPreference() :
    playDtmf_(true)
244
    , playTones_(true)
Adrien Béraud's avatar
Adrien Béraud committed
245
    , pulseLength_(PULSE_LENGTH_DEFAULT)
246
    , symmetricRtp_(true)
247
{}
248

249
void VoipPreference::serialize(YAML::Emitter &out) const
250
{
251 252 253 254 255 256 257
    out << YAML::Key << CONFIG_LABEL << YAML::Value << YAML::BeginMap;
    out << YAML::Key << PLAY_DTMF_KEY << YAML::Value << playDtmf_;
    out << YAML::Key << PLAY_TONES_KEY << YAML::Value << playTones_;
    out << YAML::Key << PULSE_LENGTH_KEY << YAML::Value << pulseLength_;
    out << YAML::Key << SYMMETRIC_RTP_KEY << YAML::Value << symmetricRtp_;
    out << YAML::Key << ZID_FILE_KEY << YAML::Value << zidFile_;
    out << YAML::EndMap;
258 259
}

260
void VoipPreference::unserialize(const YAML::Node &in)
261
{
262 263 264 265 266 267
    const auto &node = in[CONFIG_LABEL];
    parseValue(node, PLAY_DTMF_KEY, playDtmf_);
    parseValue(node, PLAY_TONES_KEY, playTones_);
    parseValue(node, PULSE_LENGTH_KEY, pulseLength_);
    parseValue(node, SYMMETRIC_RTP_KEY, symmetricRtp_);
    parseValue(node, ZID_FILE_KEY, zidFile_);
268
}
269

270 271
HookPreference::HookPreference()
    : numberAddPrefix_("")
272 273 274
    , numberEnabled_(false)
    , sipEnabled_(false)
    , urlCommand_("x-www-browser")
275
    , urlSipField_("X-ring-url")
276
{}
277

278 279
HookPreference::HookPreference(const std::map<std::string, std::string> &settings)
    : numberAddPrefix_(settings.find("PHONE_NUMBER_HOOK_ADD_PREFIX")->second)
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
    , numberEnabled_(settings.find("PHONE_NUMBER_HOOK_ENABLED")->second == "true")
    , sipEnabled_(settings.find("URLHOOK_SIP_ENABLED")->second == "true")
    , urlCommand_(settings.find("URLHOOK_COMMAND")->second)
    , urlSipField_(settings.find("URLHOOK_SIP_FIELD")->second)
{}

std::map<std::string, std::string> HookPreference::toMap() const
{
    std::map<std::string, std::string> settings;
    settings["PHONE_NUMBER_HOOK_ADD_PREFIX"] = numberAddPrefix_;
    settings["PHONE_NUMBER_HOOK_ENABLED"] = numberEnabled_ ? "true" : "false";
    settings["URLHOOK_SIP_ENABLED"] = sipEnabled_ ? "true" : "false";
    settings["URLHOOK_COMMAND"] = urlCommand_;
    settings["URLHOOK_SIP_FIELD"] = urlSipField_;

    return settings;
}

298
void HookPreference::serialize(YAML::Emitter &out) const
299
{
300 301 302 303 304 305
    out << YAML::Key << CONFIG_LABEL << YAML::Value << YAML::BeginMap;
    out << YAML::Key << NUMBER_ADD_PREFIX_KEY << YAML::Value << numberAddPrefix_;
    out << YAML::Key << SIP_ENABLED_KEY << YAML::Value << sipEnabled_;
    out << YAML::Key << URL_COMMAND_KEY << YAML::Value << urlCommand_;
    out << YAML::Key << URL_SIP_FIELD_KEY << YAML::Value << urlSipField_;
    out << YAML::EndMap;
306 307
}

308
void HookPreference::unserialize(const YAML::Node &in)
309
{
310 311 312 313 314 315
    const auto &node = in[CONFIG_LABEL];

    parseValue(node, NUMBER_ADD_PREFIX_KEY, numberAddPrefix_);
    parseValue(node, SIP_ENABLED_KEY, sipEnabled_);
    parseValue(node, URL_COMMAND_KEY, urlCommand_);
    parseValue(node, URL_SIP_FIELD_KEY, urlSipField_);
316 317
}

318
void HookPreference::runHook(pjsip_msg *msg)
319
{
320
    if (sipEnabled_) {
321
        const std::string header(sip_utils::fetchHeaderValue(msg, urlSipField_));
322 323
        UrlHook::runAction(urlCommand_, header);
    }
324 325
}

326
AudioPreference::AudioPreference() :
327
    audioApi_(PULSEAUDIO_API_STR)
328 329 330 331 332 333 334 335
    , alsaCardin_(atoi(ALSA_DFT_CARD))
    , alsaCardout_(atoi(ALSA_DFT_CARD))
    , alsaCardring_(atoi(ALSA_DFT_CARD))
    , alsaPlugin_("default")
    , alsaSmplrate_(44100)
    , pulseDevicePlayback_("")
    , pulseDeviceRecord_("")
    , pulseDeviceRingtone_("")
336
    , recordpath_("")
337
    , alwaysRecording_(false)
338 339
    , volumemic_(1.0)
    , volumespkr_(1.0)
340 341
    , denoise_(false)
    , agcEnabled_(false)
342
    , captureMuted_(false)
343
    , playbackMuted_(false)
344
{}
345

346
#if HAVE_ALSA
347 348 349

static const int ALSA_DFT_CARD_ID = 0; // Index of the default soundcard

350
static void
351
checkSoundCard(int &card, DeviceType type)
352
{
353
    if (not AlsaLayer::soundCardIndexExists(card, type)) {
Adrien Béraud's avatar
Adrien Béraud committed
354
        JAMI_WARN(" Card with index %d doesn't exist or is unusable.", card);
355
        card = ALSA_DFT_CARD_ID;
356
    }
357
}
358
#endif
359

360 361
AudioLayer*
AudioPreference::createAudioLayer()
362
{
363
#if HAVE_OPENSL
364
    return new OpenSLLayer(*this);
365 366 367 368
#else

#if HAVE_JACK
    if (audioApi_ == JACK_API_STR) {
369 370
        try {
            if (auto ret = system("jack_lsp > /dev/null"))
371
                throw std::runtime_error("Error running jack_lsp: " + std::to_string(ret));
372 373
            return new JackLayer(*this);
        } catch (const std::runtime_error& e) {
Adrien Béraud's avatar
Adrien Béraud committed
374
            JAMI_ERR("%s", e.what());
375
#if HAVE_PULSE
376
            audioApi_ = PULSEAUDIO_API_STR;
377
#elif HAVE_ALSA
378
            audioApi_ = ALSA_API_STR;
379
#elif HAVE_COREAUDIO
380
            audioApi_ = COREAUDIO_API_STR;
Edric Milaret's avatar
Edric Milaret committed
381
#elif HAVE_PORTAUDIO
382
            audioApi_ = PORTAUDIO_API_STR;
383
#else
384 385
            throw;
#endif // HAVE_PULSE
386 387
        }
    }
388
#endif // HAVE_JACK
389

Tristan Matthews's avatar
Tristan Matthews committed
390
#if HAVE_PULSE
391

392
    if (audioApi_ == PULSEAUDIO_API_STR) {
393
        try {
394
            return new PulseLayer(*this);
395
        } catch (const std::runtime_error &e) {
Adrien Béraud's avatar
Adrien Béraud committed
396
            JAMI_WARN("Could not create pulseaudio layer, falling back to ALSA");
397
        }
398
    }
399

400 401 402
#endif

#if HAVE_ALSA
403

404
    audioApi_ = ALSA_API_STR;
405 406 407
    checkSoundCard(alsaCardin_, DeviceType::CAPTURE);
    checkSoundCard(alsaCardout_, DeviceType::PLAYBACK);
    checkSoundCard(alsaCardring_, DeviceType::RINGTONE);
408

409
    return new AlsaLayer(*this);
410 411 412 413 414
#endif

#if HAVE_COREAUDIO
    audioApi_ = COREAUDIO_API_STR;
    try {
415
        return new CoreLayer(*this);
416
    } catch (const std::runtime_error &e) {
Adrien Béraud's avatar
Adrien Béraud committed
417
        JAMI_WARN("Could not create coreaudio layer. There will be no sound.");
418
    }
419
    return NULL;
420
#endif
421

Edric Milaret's avatar
Edric Milaret committed
422 423 424 425 426
#if HAVE_PORTAUDIO
    audioApi_ = PORTAUDIO_API_STR;
    try {
        return new PortAudioLayer(*this);
    } catch (const std::runtime_error &e) {
Adrien Béraud's avatar
Adrien Béraud committed
427
        JAMI_WARN("Could not create PortAudio layer. There will be no sound.");
Edric Milaret's avatar
Edric Milaret committed
428 429 430
    }
    return nullptr;
#endif
431
#endif // HAVE_OPENSL
432

Adrien Béraud's avatar
Adrien Béraud committed
433
    JAMI_WARN("No audio layer provided");
434
    return nullptr;
435
}
436

437
void AudioPreference::serialize(YAML::Emitter &out) const
438
{
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461
    out << YAML::Key << CONFIG_LABEL << YAML::Value << YAML::BeginMap;
    // alsa submap
    out << YAML::Key << ALSAMAP_KEY << YAML::Value << YAML::BeginMap;
    out << YAML::Key << CARDIN_KEY << YAML::Value << alsaCardin_;
    out << YAML::Key << CARDOUT_KEY << YAML::Value << alsaCardout_;
    out << YAML::Key << CARDRING_KEY << YAML::Value << alsaCardring_;
    out << YAML::Key << PLUGIN_KEY << YAML::Value << alsaPlugin_;
    out << YAML::Key << SMPLRATE_KEY << YAML::Value << alsaSmplrate_;
    out << YAML::EndMap;

    // common options
    out << YAML::Key << ALWAYS_RECORDING_KEY << YAML::Value << alwaysRecording_;
    out << YAML::Key << AUDIO_API_KEY << YAML::Value << audioApi_;
    out << YAML::Key << AGC_KEY << YAML::Value << agcEnabled_;
    out << YAML::Key << CAPTURE_MUTED_KEY << YAML::Value << captureMuted_;
    out << YAML::Key << NOISE_REDUCE_KEY << YAML::Value << denoise_;
    out << YAML::Key << PLAYBACK_MUTED_KEY << YAML::Value << playbackMuted_;

    // pulse submap
    out << YAML::Key << PULSEMAP_KEY << YAML::Value << YAML::BeginMap;
    out << YAML::Key << DEVICE_PLAYBACK_KEY << YAML::Value << pulseDevicePlayback_;
    out << YAML::Key << DEVICE_RECORD_KEY << YAML::Value << pulseDeviceRecord_;
    out << YAML::Key << DEVICE_RINGTONE_KEY << YAML::Value << pulseDeviceRingtone_;
462
    out << YAML::EndMap;
463 464 465 466 467 468 469

    // more common options!
    out << YAML::Key << RECORDPATH_KEY << YAML::Value << recordpath_;
    out << YAML::Key << VOLUMEMIC_KEY << YAML::Value << volumemic_;
    out << YAML::Key << VOLUMESPKR_KEY << YAML::Value << volumespkr_;

    out << YAML::EndMap;
470 471
}

472 473 474
bool
AudioPreference::setRecordPath(const std::string &r)
{
475 476 477
    std::string path = fileutils::expand_path(r);
    if (fileutils::isDirectoryWritable(path)) {
        recordpath_ = path;
478 479
        return true;
    } else {
Adrien Béraud's avatar
Adrien Béraud committed
480
        JAMI_ERR("%s is not writable, cannot be the recording path", path.c_str());
481 482 483 484
        return false;
    }
}

485
void AudioPreference::unserialize(const YAML::Node &in)
486
{
487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515
    const auto &node = in[CONFIG_LABEL];

    // alsa submap
    const auto &alsa = node[ALSAMAP_KEY];

    parseValue(alsa, CARDIN_KEY, alsaCardin_);
    parseValue(alsa, CARDOUT_KEY, alsaCardout_);
    parseValue(alsa, CARDRING_KEY, alsaCardring_);
    parseValue(alsa, PLUGIN_KEY, alsaPlugin_);
    parseValue(alsa, SMPLRATE_KEY, alsaSmplrate_);

    // common options
    parseValue(node, ALWAYS_RECORDING_KEY, alwaysRecording_);
    parseValue(node, AUDIO_API_KEY, audioApi_);
    parseValue(node, AGC_KEY, agcEnabled_);
    parseValue(node, CAPTURE_MUTED_KEY, captureMuted_);
    parseValue(node, NOISE_REDUCE_KEY, denoise_);
    parseValue(node, PLAYBACK_MUTED_KEY, playbackMuted_);

    // pulse submap
    const auto &pulse = node[PULSEMAP_KEY];
    parseValue(pulse, DEVICE_PLAYBACK_KEY, pulseDevicePlayback_);
    parseValue(pulse, DEVICE_RECORD_KEY, pulseDeviceRecord_);
    parseValue(pulse, DEVICE_RINGTONE_KEY, pulseDeviceRingtone_);

    // more common options!
    parseValue(node, RECORDPATH_KEY, recordpath_);
    parseValue(node, VOLUMEMIC_KEY, volumemic_);
    parseValue(node, VOLUMESPKR_KEY, volumespkr_);
516
}
517

518 519 520
ShortcutPreferences::ShortcutPreferences() : hangup_(), pickup_(), popup_(),
    toggleHold_(), togglePickupHangup_() {}

521
std::map<std::string, std::string> ShortcutPreferences::getShortcuts() const
522
{
Julien Bonjean's avatar
Julien Bonjean committed
523
    std::map<std::string, std::string> shortcutsMap;
524

525 526 527 528 529
    shortcutsMap[HANGUP_SHORT_KEY] = hangup_;
    shortcutsMap[PICKUP_SHORT_KEY] = pickup_;
    shortcutsMap[POPUP_SHORT_KEY] = popup_;
    shortcutsMap[TOGGLE_HOLD_SHORT_KEY] = toggleHold_;
    shortcutsMap[TOGGLE_PICKUP_HANGUP_SHORT_KEY] = togglePickupHangup_;
530

Julien Bonjean's avatar
Julien Bonjean committed
531
    return shortcutsMap;
532 533
}

534
void ShortcutPreferences::setShortcuts(std::map<std::string, std::string> map)
535
{
536 537 538 539 540
    hangup_ = map[HANGUP_SHORT_KEY];
    pickup_ = map[PICKUP_SHORT_KEY];
    popup_ = map[POPUP_SHORT_KEY];
    toggleHold_ = map[TOGGLE_HOLD_SHORT_KEY];
    togglePickupHangup_ = map[TOGGLE_PICKUP_HANGUP_SHORT_KEY];
541 542 543
}


544
void ShortcutPreferences::serialize(YAML::Emitter &out) const
545
{
546 547 548 549 550 551 552
    out << YAML::Key << CONFIG_LABEL << YAML::Value << YAML::BeginMap;
    out << YAML::Key << HANGUP_SHORT_KEY << YAML::Value << hangup_;
    out << YAML::Key << PICKUP_SHORT_KEY << YAML::Value << pickup_;
    out << YAML::Key << POPUP_SHORT_KEY << YAML::Value << popup_;
    out << YAML::Key << TOGGLE_HOLD_SHORT_KEY << YAML::Value << toggleHold_;
    out << YAML::Key << TOGGLE_PICKUP_HANGUP_SHORT_KEY << YAML::Value << togglePickupHangup_;
    out << YAML::EndMap;
553 554
}

555
void ShortcutPreferences::unserialize(const YAML::Node &in)
556
{
557 558 559 560 561 562 563
    const auto &node = in[CONFIG_LABEL];

    parseValue(node, HANGUP_SHORT_KEY, hangup_);
    parseValue(node, PICKUP_SHORT_KEY, pickup_);
    parseValue(node, POPUP_SHORT_KEY, popup_);
    parseValue(node, TOGGLE_HOLD_SHORT_KEY, toggleHold_);
    parseValue(node, TOGGLE_PICKUP_HANGUP_SHORT_KEY, togglePickupHangup_);
564
}
565

Adrien Béraud's avatar
Adrien Béraud committed
566
#ifdef ENABLE_VIDEO
567
VideoPreferences::VideoPreferences()
568
    : decodingAccelerated_(true)
569
    , encodingAccelerated_(false)
570 571
    , recordPreview_(true)
    , recordQuality_(0)
572 573 574
{
}

575
void VideoPreferences::serialize(YAML::Emitter &out) const
576 577
{
    out << YAML::Key << CONFIG_LABEL << YAML::Value << YAML::BeginMap;
578 579
    out << YAML::Key << RECORD_PREVIEW_KEY << YAML::Value << recordPreview_;
    out << YAML::Key << RECORD_QUALITY_KEY << YAML::Value << recordQuality_;
580
#ifdef RING_ACCEL
581
    out << YAML::Key << DECODING_ACCELERATED_KEY << YAML::Value << decodingAccelerated_;
582
    out << YAML::Key << ENCODING_ACCELERATED_KEY << YAML::Value << encodingAccelerated_;
583
#endif
584 585 586 587 588 589
    getVideoDeviceMonitor().serialize(out);
    out << YAML::EndMap;
}

void VideoPreferences::unserialize(const YAML::Node &in)
{
590
    // values may or may not be present
591
    const auto &node = in[CONFIG_LABEL];
592 593 594 595 596 597 598
    try {
        parseValue(node, RECORD_PREVIEW_KEY, recordPreview_);
        parseValue(node, RECORD_QUALITY_KEY, recordQuality_);
    } catch (...) {
        recordPreview_ = true;
        recordQuality_ = 0;
    }
599
#ifdef RING_ACCEL
600 601
    try {
        parseValue(node, DECODING_ACCELERATED_KEY, decodingAccelerated_);
602 603 604 605 606
        parseValue(node, ENCODING_ACCELERATED_KEY, encodingAccelerated_);
    } catch (...) {
        decodingAccelerated_ = true;
        encodingAccelerated_ = false;
    }
607
#endif
608
    getVideoDeviceMonitor().unserialize(in);
609
}
Adrien Béraud's avatar
Adrien Béraud committed
610
#endif // ENABLE_VIDEO
611

Adrien Béraud's avatar
Adrien Béraud committed
612
} // namespace jami