LCOV - code coverage report
Current view: top level - src - account.cpp (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 136 226 60.2 %
Date: 2024-04-25 08:05:53 Functions: 26 37 70.3 %

          Line data    Source code
       1             : /*
       2             :  *  Copyright (C) 2004-2024 Savoir-faire Linux Inc.
       3             :  *
       4             :  *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
       5             :  *  Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
       6             :  *  Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
       7             :  *
       8             :  *  This program is free software; you can redistribute it and/or modify
       9             :  *  it under the terms of the GNU General Public License as published by
      10             :  *  the Free Software Foundation; either version 3 of the License, or
      11             :  *  (at your option) any later version.
      12             :  *
      13             :  *  This program is distributed in the hope that it will be useful,
      14             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :  *  GNU General Public License for more details.
      17             :  *
      18             :  *  You should have received a copy of the GNU General Public License
      19             :  *  along with this program; if not, write to the Free Software
      20             :  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
      21             :  */
      22             : 
      23             : #include "media/media_codec.h"
      24             : #ifdef HAVE_CONFIG_H
      25             : #include "config.h"
      26             : #endif
      27             : #include "account.h"
      28             : 
      29             : #include <algorithm>
      30             : #include <iterator>
      31             : #include <mutex>
      32             : 
      33             : #ifdef ENABLE_VIDEO
      34             : #include "libav_utils.h"
      35             : #endif
      36             : 
      37             : #include "logger.h"
      38             : #include "manager.h"
      39             : 
      40             : #include <opendht/rng.h>
      41             : 
      42             : #include "client/ring_signal.h"
      43             : #include "account_schema.h"
      44             : #include "jami/account_const.h"
      45             : #include "string_utils.h"
      46             : #include "fileutils.h"
      47             : #include "config/yamlparser.h"
      48             : #include "system_codec_container.h"
      49             : 
      50             : #pragma GCC diagnostic push
      51             : #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
      52             : #include <yaml-cpp/yaml.h>
      53             : #pragma GCC diagnostic pop
      54             : 
      55             : #include "compiler_intrinsics.h"
      56             : #include "jami/account_const.h"
      57             : 
      58             : #include <dhtnet/upnp/upnp_control.h>
      59             : #include <dhtnet/ip_utils.h>
      60             : 
      61             : #include <fmt/ranges.h>
      62             : 
      63             : using namespace std::literals;
      64             : 
      65             : namespace jami {
      66             : 
      67             : // For portability, do not specify the absolute file name of the ringtone.
      68             : // Instead, specify its base name to be looked in
      69             : // JAMI_DATADIR/ringtones/, where JAMI_DATADIR is a preprocessor macro denoting
      70             : // the data directory prefix that must be set at build time.
      71             : const std::string Account::DEFAULT_USER_AGENT = Account::getDefaultUserAgent();
      72             : 
      73         799 : Account::Account(const std::string& accountID)
      74         799 :     : rand(Manager::instance().getSeededRandomEngine())
      75         799 :     , accountID_(accountID)
      76        2397 :     , systemCodecContainer_(getSystemCodecContainer())
      77             : {
      78             :     // Initialize the codec order, used when creating a new account
      79         799 :     loadDefaultCodecs();
      80         799 : }
      81             : 
      82         729 : Account::~Account() {}
      83             : 
      84             : void
      85         770 : Account::hangupCalls()
      86             : {
      87         797 :     for (const auto& callId : callSet_.getCallIds())
      88         797 :         Manager::instance().hangupCall(getAccountID(), callId);
      89         770 : }
      90             : 
      91             : void
      92         814 : Account::updateUpnpController()
      93             : {
      94         814 :     std::lock_guard lk {upnp_mtx};
      95             : 
      96         814 :     if (not config().upnpEnabled or not isUsable()) {
      97          69 :         upnpCtrl_.reset();
      98          69 :         return;
      99             :     }
     100             : 
     101             :     // UPNP enabled. Create new controller if needed.
     102         745 :     if (not upnpCtrl_) {
     103         729 :         upnpCtrl_ = std::make_shared<dhtnet::upnp::Controller>(Manager::instance().upnpContext());
     104         729 :         if (not upnpCtrl_) {
     105           0 :             throw std::runtime_error("Failed to create a UPNP Controller instance!");
     106             :         }
     107             :     }
     108         814 : }
     109             : 
     110             : void
     111        5103 : Account::setRegistrationState(RegistrationState state,
     112             :                               int detail_code,
     113             :                               const std::string& detail_str)
     114             : {
     115        5103 :     if (state != registrationState_) {
     116        3666 :         registrationState_ = state;
     117             :         // Notify the client
     118        7332 :         runOnMainThread([accountId = accountID_,
     119             :                          state = mapStateNumberToString(registrationState_),
     120             :                          detail_code,
     121             :                          detail_str,
     122        3666 :                          details = getVolatileAccountDetails()] {
     123        3666 :             emitSignal<libjami::ConfigurationSignal::RegistrationStateChanged>(accountId,
     124        3666 :                                                                              state,
     125             :                                                                              detail_code,
     126        3666 :                                                                              detail_str);
     127             : 
     128        3666 :             emitSignal<libjami::ConfigurationSignal::VolatileDetailsChanged>(accountId, details);
     129        3666 :         });
     130             :     }
     131        5103 : }
     132             : 
     133             : void
     134         799 : Account::loadDefaultCodecs()
     135             : {
     136             :     // default codec are system codecs
     137         799 :     const auto& systemCodecList = systemCodecContainer_->getSystemCodecInfoList();
     138         799 :     accountCodecInfoList_.clear();
     139         799 :     accountCodecInfoList_.reserve(systemCodecList.size());
     140       10387 :     for (const auto& systemCodec : systemCodecList) {
     141             :         // As defined in SDP RFC, only select a codec if it can encode and decode
     142        9588 :         if ((systemCodec->codecType & CODEC_ENCODER_DECODER) != CODEC_ENCODER_DECODER)
     143           0 :             continue;
     144             : 
     145        9588 :         if (systemCodec->mediaType & MEDIA_AUDIO) {
     146        6392 :             accountCodecInfoList_.emplace_back(std::make_shared<SystemAudioCodecInfo>(
     147       12784 :                 *std::static_pointer_cast<SystemAudioCodecInfo>(systemCodec)));
     148             :         }
     149             : 
     150        9588 :         if (systemCodec->mediaType & MEDIA_VIDEO) {
     151        3196 :             accountCodecInfoList_.emplace_back(std::make_shared<SystemVideoCodecInfo>(
     152        6392 :                 *std::static_pointer_cast<SystemVideoCodecInfo>(systemCodec)));
     153             :         }
     154             :     }
     155         799 : }
     156             : 
     157             : void
     158         814 : Account::loadConfig() {
     159         814 :     setActiveCodecs(config_->activeCodecs);
     160           0 :     auto ringtoneDir = fmt::format("{}/{}", JAMI_DATADIR, RINGDIR);
     161         814 :     ringtonePath_ = fileutils::getFullPath(ringtoneDir, config_->ringtonePath);
     162             :     // If the user defined a custom ringtone, the file may not exists
     163             :     // In this case, fallback on the default ringtone path
     164         814 :     if (not std::filesystem::is_regular_file(ringtonePath_)) {
     165        2442 :         JAMI_WARNING("Ringtone {} is not a valid file", ringtonePath_);
     166         814 :         config_->ringtonePath = DEFAULT_RINGTONE_PATH;
     167         814 :         ringtonePath_ = fileutils::getFullPath(ringtoneDir, config_->ringtonePath);
     168             :     }
     169         814 :     updateUpnpController();
     170         814 : }
     171             : 
     172             : void
     173          52 : Account::saveConfig() const
     174             : {
     175          52 :     Manager::instance().saveConfig();
     176          52 : }
     177             : 
     178             : std::map<std::string, std::string>
     179        4605 : Account::getVolatileAccountDetails() const
     180             : {
     181        9210 :     return {{Conf::CONFIG_ACCOUNT_REGISTRATION_STATUS, mapStateNumberToString(registrationState_)},
     182       18420 :             {libjami::Account::VolatileProperties::ACTIVE, active_ ? TRUE_STR : FALSE_STR}};
     183             : }
     184             : 
     185             : bool
     186        1735 : Account::hasActiveCodec(MediaType mediaType) const
     187             : {
     188       21647 :     for (auto& codecIt : accountCodecInfoList_)
     189       20059 :         if ((codecIt->mediaType & mediaType) && codecIt->isActive)
     190         147 :             return true;
     191        1588 :     return false;
     192             : }
     193             : 
     194             : void
     195         814 : Account::setActiveCodecs(const std::vector<unsigned>& list)
     196             : {
     197             :     // first clear the previously stored codecs
     198             :     // TODO: mutex to protect isActive
     199         814 :     setAllCodecsActive(MEDIA_ALL, false);
     200             : 
     201             :     // list contains the ordered payload of active codecs picked by the user for this account
     202             :     // we used the codec vector to save the order.
     203         814 :     uint16_t order = 1;
     204         874 :     for (const auto& item : list) {
     205          60 :         if (auto accCodec = searchCodecById(item, MEDIA_ALL)) {
     206          60 :             accCodec->isActive = true;
     207          60 :             accCodec->order = order;
     208          60 :             ++order;
     209          60 :         }
     210             :     }
     211         814 :     sortCodec();
     212         814 : }
     213             : 
     214             : void
     215         814 : Account::sortCodec()
     216             : {
     217         814 :     std::sort(std::begin(accountCodecInfoList_),
     218         814 :               std::end(accountCodecInfoList_),
     219       18326 :               [](const std::shared_ptr<SystemCodecInfo>& a,
     220       18326 :                  const std::shared_ptr<SystemCodecInfo>& b) { return a->order < b->order; });
     221         814 : }
     222             : 
     223             : std::string
     224        8271 : Account::mapStateNumberToString(RegistrationState state)
     225             : {
     226             : #define CASE_STATE(X) \
     227             :     case RegistrationState::X: \
     228             :         return #X
     229             : 
     230        8271 :     switch (state) {
     231           0 :         CASE_STATE(UNLOADED);
     232        3025 :         CASE_STATE(UNREGISTERED);
     233        1462 :         CASE_STATE(TRYING);
     234        2234 :         CASE_STATE(REGISTERED);
     235           0 :         CASE_STATE(ERROR_GENERIC);
     236           0 :         CASE_STATE(ERROR_AUTH);
     237           0 :         CASE_STATE(ERROR_NETWORK);
     238           0 :         CASE_STATE(ERROR_HOST);
     239           0 :         CASE_STATE(ERROR_SERVICE_UNAVAILABLE);
     240           0 :         CASE_STATE(ERROR_NEED_MIGRATION);
     241        1550 :         CASE_STATE(INITIALIZING);
     242           0 :     default:
     243           0 :         return libjami::Account::States::ERROR_GENERIC;
     244             :     }
     245             : 
     246             : #undef CASE_STATE
     247             : }
     248             : 
     249             : std::vector<unsigned>
     250           0 : Account::getDefaultCodecsId()
     251             : {
     252           0 :     return getSystemCodecContainer()->getSystemCodecInfoIdList(MEDIA_ALL);
     253             : }
     254             : 
     255             : std::map<std::string, std::string>
     256           0 : Account::getDefaultCodecDetails(const unsigned& codecId)
     257             : {
     258           0 :     auto codec = jami::getSystemCodecContainer()->searchCodecById(codecId, jami::MEDIA_ALL);
     259           0 :     if (codec) {
     260           0 :         if (codec->mediaType & jami::MEDIA_AUDIO) {
     261           0 :             auto audioCodec = std::static_pointer_cast<jami::SystemAudioCodecInfo>(codec);
     262           0 :             return audioCodec->getCodecSpecifications();
     263           0 :         }
     264           0 :         if (codec->mediaType & jami::MEDIA_VIDEO) {
     265           0 :             auto videoCodec = std::static_pointer_cast<jami::SystemVideoCodecInfo>(codec);
     266           0 :             return videoCodec->getCodecSpecifications();
     267           0 :         }
     268             :     }
     269           0 :     return {};
     270           0 : }
     271             : 
     272             : /**
     273             :  * Get the UPnP IP (external router) address.
     274             :  * If use UPnP is set to false, the address will be empty.
     275             :  */
     276             : dhtnet::IpAddr
     277           0 : Account::getUPnPIpAddress() const
     278             : {
     279           0 :     std::lock_guard lk(upnp_mtx);
     280           0 :     if (upnpCtrl_)
     281           0 :         return upnpCtrl_->getExternalIP();
     282           0 :     return {};
     283           0 : }
     284             : 
     285             : /**
     286             :  * returns whether or not UPnP is enabled and active_
     287             :  * ie: if it is able to make port mappings
     288             :  */
     289             : bool
     290         568 : Account::getUPnPActive() const
     291             : {
     292         568 :     std::lock_guard lk(upnp_mtx);
     293         568 :     if (upnpCtrl_)
     294         430 :         return upnpCtrl_->isReady();
     295         138 :     return false;
     296         568 : }
     297             : 
     298             : /*
     299             :  * private account codec searching functions
     300             :  *
     301             :  * */
     302             : std::shared_ptr<SystemCodecInfo>
     303          60 : Account::searchCodecById(unsigned codecId, MediaType mediaType)
     304             : {
     305          60 :     if (mediaType != MEDIA_NONE) {
     306         185 :         for (auto& codecIt : accountCodecInfoList_) {
     307         185 :             if ((codecIt->id == codecId)
     308         185 :                 && (codecIt->mediaType & mediaType))
     309          60 :                 return codecIt;
     310             :         }
     311             :     }
     312           0 :     return {};
     313             : }
     314             : 
     315             : std::shared_ptr<SystemCodecInfo>
     316           0 : Account::searchCodecByName(const std::string& name, MediaType mediaType)
     317             : {
     318           0 :     if (mediaType != MEDIA_NONE) {
     319           0 :         for (auto& codecIt : accountCodecInfoList_) {
     320           0 :             if (codecIt->name == name
     321           0 :                 && (codecIt->mediaType & mediaType))
     322           0 :                 return codecIt;
     323             :         }
     324             :     }
     325           0 :     return {};
     326             : }
     327             : 
     328             : std::shared_ptr<SystemCodecInfo>
     329           0 : Account::searchCodecByPayload(unsigned payload, MediaType mediaType)
     330             : {
     331           0 :     if (mediaType != MEDIA_NONE) {
     332           0 :         for (auto& codecIt : accountCodecInfoList_) {
     333           0 :             if ((codecIt->payloadType == payload)
     334           0 :                 && (codecIt->mediaType & mediaType))
     335           0 :                 return codecIt;
     336             :         }
     337             :     }
     338           0 :     return {};
     339             : }
     340             : 
     341             : std::vector<unsigned>
     342         814 : Account::getActiveCodecs(MediaType mediaType) const
     343             : {
     344         814 :     if (mediaType == MEDIA_NONE)
     345           0 :         return {};
     346             : 
     347         814 :     std::vector<unsigned> idList;
     348       10582 :     for (auto& codecIt : accountCodecInfoList_) {
     349        9768 :         if ((codecIt->mediaType & mediaType) && (codecIt->isActive))
     350        2658 :             idList.push_back(codecIt->id);
     351             :     }
     352         814 :     return idList;
     353         814 : }
     354             : 
     355             : std::vector<unsigned>
     356           0 : Account::getAccountCodecInfoIdList(MediaType mediaType) const
     357             : {
     358           0 :     if (mediaType == MEDIA_NONE)
     359           0 :         return {};
     360             : 
     361           0 :     std::vector<unsigned> idList;
     362           0 :     for (auto& codecIt : accountCodecInfoList_) {
     363           0 :         if (codecIt->mediaType & mediaType)
     364           0 :             idList.push_back(codecIt->id);
     365             :     }
     366             : 
     367           0 :     return idList;
     368           0 : }
     369             : 
     370             : void
     371         862 : Account::setAllCodecsActive(MediaType mediaType, bool active)
     372             : {
     373         862 :     if (mediaType == MEDIA_NONE)
     374           0 :         return;
     375       11206 :     for (auto& codecIt : accountCodecInfoList_) {
     376       10344 :         if (codecIt->mediaType & mediaType)
     377       10056 :             codecIt->isActive = active;
     378             :     }
     379             : }
     380             : 
     381             : void
     382        3080 : Account::setCodecActive(unsigned codecId)
     383             : {
     384       40040 :     for (auto& codecIt : accountCodecInfoList_) {
     385       36960 :         if (codecIt->avcodecId == codecId)
     386        2310 :             codecIt->isActive = true;
     387             :     }
     388        3080 : }
     389             : 
     390             : void
     391           0 : Account::setCodecInactive(unsigned codecId)
     392             : {
     393           0 :     for (auto& codecIt : accountCodecInfoList_) {
     394           0 :         if (codecIt->avcodecId == codecId)
     395           0 :             codecIt->isActive = false;
     396             :     }
     397           0 : }
     398             : 
     399             : std::vector<std::shared_ptr<SystemCodecInfo>>
     400         812 : Account::getActiveAccountCodecInfoList(MediaType mediaType) const
     401             : {
     402         812 :     if (mediaType == MEDIA_NONE)
     403           0 :         return {};
     404             : 
     405         812 :     std::vector<std::shared_ptr<SystemCodecInfo>> accountCodecList;
     406       10556 :     for (auto& codecIt : accountCodecInfoList_) {
     407        9744 :         if ((codecIt->mediaType & mediaType) && (codecIt->isActive))
     408        1398 :             accountCodecList.push_back(codecIt);
     409             :     }
     410             : 
     411         812 :     return accountCodecList;
     412         812 : }
     413             : 
     414             : const std::string&
     415       32750 : Account::getUserAgentName()
     416             : {
     417       32750 :     return config_->customUserAgent.empty() ? DEFAULT_USER_AGENT : config_->customUserAgent;
     418             : }
     419             : 
     420             : std::string
     421          44 : Account::getDefaultUserAgent()
     422             : {
     423          88 :     return fmt::format("{:s} {:s} ({:s})", PACKAGE_NAME, libjami::version(), libjami::platform());
     424             : }
     425             : 
     426             : void
     427           0 : Account::addDefaultModerator(const std::string& uri)
     428             : {
     429           0 :     config_->defaultModerators.insert(uri);
     430           0 : }
     431             : 
     432             : void
     433           0 : Account::removeDefaultModerator(const std::string& uri)
     434             : {
     435           0 :     config_->defaultModerators.erase(uri);
     436           0 : }
     437             : 
     438             : bool
     439         859 : Account::meetMinimumRequiredVersion(const std::vector<unsigned>& version,
     440             :                                     const std::vector<unsigned>& minRequiredVersion)
     441             : {
     442         876 :     for (size_t i = 0; i < minRequiredVersion.size(); i++) {
     443         872 :         if (i == version.size() or version[i] < minRequiredVersion[i])
     444           5 :             return false;
     445         867 :         if (version[i] > minRequiredVersion[i])
     446         850 :             return true;
     447             :     }
     448           4 :     return true;
     449             : }
     450             : 
     451             : bool
     452           0 : Account::setPushNotificationConfig(const std::map<std::string, std::string>& data)
     453             : {
     454           0 :     std::lock_guard lock(configurationMutex_);
     455           0 :     auto platform = data.find("platform");
     456           0 :     auto topic = data.find("topic");
     457           0 :     auto token = data.find("token");
     458           0 :     bool changed = false;
     459           0 :     if (platform != data.end() && config_->platform != platform->second) {
     460           0 :         config_->platform = platform->second;
     461           0 :         changed = true;
     462             :     }
     463           0 :     if (topic != data.end() && config_->notificationTopic != topic->second) {
     464           0 :         config_->notificationTopic = topic->second;
     465           0 :         changed = true;
     466             :     }
     467           0 :     if (token != data.end() && config_->deviceKey != token->second) {
     468           0 :         config_->deviceKey = token->second;
     469           0 :         changed = true;
     470             :     }
     471           0 :     if (changed)
     472           0 :         saveConfig();
     473           0 :     return changed;
     474           0 : }
     475             : 
     476             : } // namespace jami

Generated by: LCOV version 1.14