Skip to content
Snippets Groups Projects
Select Git revision
  • master default protected
  • beta/202506051039
  • beta/202506051002
  • beta/202506041611
  • beta/202506041335
  • beta/202505231812
  • stable/20250523.0
  • nightly/20250523.0
  • nightly/20250515.0
  • nightly/20250510.0
  • nightly/20250509.1
  • nightly/20250509.0
  • stable/20250430.1
  • stable/20250430.0
  • beta/202504301614
  • nightly/20250430.0
  • stable/20250424.1
  • beta/202504241506
  • stable/20250424.0
  • nightly/20250424.1
  • nightly/20250424.0
21 results

callparticipantsmodel.cpp

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    callparticipantsmodel.cpp 7.04 KiB
    /*!
     *   Copyright (C) 2022-2023 Savoir-faire Linux Inc.
     *   Author: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
     *
     *   This library is free software; you can redistribute it and/or
     *   modify it under the terms of the GNU Lesser General Public
     *   License as published by the Free Software Foundation; either
     *   version 2.1 of the License, or (at your option) any later version.
     *
     *   This library 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
     *   Lesser General Public License for more details.
     *
     *   You should have received a copy of the GNU General Public License
     *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
     */
    
    #include "api/callparticipantsmodel.h"
    
    #include "api/account.h"
    #include "api/contactmodel.h"
    #include "api/contact.h"
    #include "api/callmodel.h"
    #include "api/accountmodel.h"
    
    namespace lrc {
    
    namespace api {
    
    CallParticipants::CallParticipants(const VectorMapStringString& infos,
                                       const QString& callId,
                                       const CallModel& linked)
        : linked_(linked)
        , callId_(callId)
    {
        update(infos);
    }
    
    QList<ParticipantInfos>
    CallParticipants::getParticipants() const
    {
        std::lock_guard<std::mutex> lk(participantsMtx_);
        return participants_.values();
    }
    
    void
    CallParticipants::update(const VectorMapStringString& infos)
    {
        std::lock_guard<std::mutex> lk(updateMtx_);
        validMedias_.clear();
        filterCandidates(infos);
        validMedias_.sort();
    
        idx_ = 0;
        QList<QString> keys {};
        {
            std::lock_guard<std::mutex> lk(participantsMtx_);
            keys = participants_.keys();
        }
        for (const auto& key : keys) {
            auto keyIdx = validMedias_.indexOf(key);
            if (keyIdx < 0 || keyIdx >= validMedias_.size())
                removeParticipant(idx_);
            else
                idx_++;
        }
    
        idx_ = 0;
        for (const auto& partMedia : validMedias_) {
            addParticipant(candidates_[partMedia]);
            idx_++;
        }
    
        verifyLayout();
    }
    
    void
    CallParticipants::verifyLayout()
    {
        std::lock_guard<std::mutex> lk(participantsMtx_);
        auto it = std::find_if(participants_.begin(),
                               participants_.end(),
                               [](const lrc::api::ParticipantInfos& participant) -> bool {
                                   return participant.active;
                               });
        auto newLayout = call::Layout::GRID;
        if (it != participants_.end())
            if (participants_.size() == 1)
                newLayout = call::Layout::ONE;
            else
                newLayout = call::Layout::ONE_WITH_SMALL;
        else
            newLayout = call::Layout::GRID;
        if (newLayout != hostLayout_)
            hostLayout_ = newLayout;
    }
    
    void
    CallParticipants::removeParticipant(int index)
    {
        {
            std::lock_guard<std::mutex> lk(participantsMtx_);
            auto it = std::next(participants_.begin(), index);
            participants_.erase(it);
        }
        Q_EMIT linked_.participantRemoved(callId_, idx_);
    }
    
    void
    CallParticipants::addParticipant(const ParticipantInfos& participant)
    {
        bool added {false};
        {
            std::lock_guard<std::mutex> lk(participantsMtx_);
            auto it = participants_.find(participant.sinkId);
            if (it == participants_.end()) {
                participants_.insert(std::next(participants_.begin(), idx_),
                                     participant.sinkId,
                                     participant);
                added = true;
            } else {
                if (participant == (*it))
                    return;
                (*it) = participant;
            }
        }
        if (added)
            Q_EMIT linked_.participantAdded(callId_, idx_);
        else
            Q_EMIT linked_.participantUpdated(callId_, idx_);
    }
    
    void
    CallParticipants::filterCandidates(const VectorMapStringString& infos)
    {
        std::lock_guard<std::mutex> lk(participantsMtx_);
        candidates_.clear();
        for (const auto& candidate : infos) {
            if (!candidate.contains(ParticipantsInfosStrings::URI))
                continue;
            auto peerId = candidate[ParticipantsInfosStrings::URI];
            peerId.truncate(peerId.lastIndexOf("@"));
            if (peerId.isEmpty()) {
                for (const auto& accId : linked_.owner.accountModel->getAccountList()) {
                    try {
                        auto& accountInfo = linked_.owner.accountModel->getAccountInfo(accId);
                        if (accountInfo.callModel->hasCall(callId_)) {
                            peerId = accountInfo.profileInfo.uri;
                        }
                    } catch (...) {
                    }
                }
            }
            auto media = candidate[ParticipantsInfosStrings::STREAMID];
            if (candidate[ParticipantsInfosStrings::W].toInt() != 0
                && candidate[ParticipantsInfosStrings::H].toInt() != 0) {
                validMedias_.append(media);
                candidates_.insert(media, ParticipantInfos(candidate, callId_, peerId));
            }
        }
    }
    
    bool
    CallParticipants::checkModerator(const QString& uri) const
    {
        std::lock_guard<std::mutex> lk(participantsMtx_);
        return std::find_if(participants_.cbegin(),
                            participants_.cend(),
                            [&](auto participant) {
                                return participant.uri == uri && participant.isModerator;
                            })
               != participants_.cend();
    }
    
    QJsonObject
    CallParticipants::toQJsonObject(uint index) const
    {
        std::lock_guard<std::mutex> lk(participantsMtx_);
        if (index >= participants_.size())
            return {};
    
        QJsonObject ret;
        const auto& participant = std::next(participants_.begin(), index);
    
        ret[ParticipantsInfosStrings::URI] = participant->uri;
        ret[ParticipantsInfosStrings::DEVICE] = participant->device;
        ret[ParticipantsInfosStrings::STREAMID] = participant->sinkId;
        ret[ParticipantsInfosStrings::BESTNAME] = participant->bestName;
        ret[ParticipantsInfosStrings::AVATAR] = participant->avatar;
        ret[ParticipantsInfosStrings::ACTIVE] = participant->active;
        ret[ParticipantsInfosStrings::X] = participant->x;
        ret[ParticipantsInfosStrings::Y] = participant->y;
        ret[ParticipantsInfosStrings::WIDTH] = participant->width;
        ret[ParticipantsInfosStrings::HEIGHT] = participant->height;
        ret[ParticipantsInfosStrings::AUDIOLOCALMUTED] = participant->audioLocalMuted;
        ret[ParticipantsInfosStrings::AUDIOMODERATORMUTED] = participant->audioModeratorMuted;
        ret[ParticipantsInfosStrings::VIDEOMUTED] = participant->videoMuted;
        ret[ParticipantsInfosStrings::ISMODERATOR] = participant->isModerator;
        ret[ParticipantsInfosStrings::ISLOCAL] = participant->islocal;
        ret[ParticipantsInfosStrings::ISCONTACT] = participant->isContact;
        ret[ParticipantsInfosStrings::HANDRAISED] = participant->handRaised;
        ret[ParticipantsInfosStrings::VOICEACTIVITY] = participant->voiceActivity;
        ret[ParticipantsInfosStrings::ISRECORDING] = participant->isRecording;
        ret[ParticipantsInfosStrings::CALLID] = callId_;
    
        return ret;
    }
    } // end namespace api
    } // end namespace lrc