LCOV - code coverage report
Current view: top level - src - account.cpp (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 137 226 60.6 %
Date: 2024-11-15 09:04:49 Functions: 26 37 70.3 %

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

Generated by: LCOV version 1.14