linphone-desktop/linphone-app/src/components/participant/ParticipantDeviceListModel.cpp
Julien Wadel c664d0cc49 The feature of connecting multi devices on the same account is not supported by the video conference.
- Part fix previews for this case.

Fix download text for outgoing files after the restart of the application.


Update SDK to 5.2.88
2023-07-26 16:51:28 +02:00

314 lines
12 KiB
C++

/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include <QQmlApplicationEngine>
#include <algorithm>
#include "app/App.hpp"
#include "ParticipantDeviceListModel.hpp"
#include "utils/Utils.hpp"
#include "components/Components.hpp"
// =============================================================================
ParticipantDeviceListModel::ParticipantDeviceListModel (std::shared_ptr<linphone::Participant> participant, QObject *parent) : ProxyListModel(parent) {
std::list<std::shared_ptr<linphone::ParticipantDevice>> devices = participant->getDevices() ;
mCallModel = nullptr;
for(auto device : devices){
auto deviceModel = ParticipantDeviceModel::create(mCallModel, device, isMe(device));
connect(this, &ParticipantDeviceListModel::securityLevelChanged, deviceModel.get(), &ParticipantDeviceModel::onSecurityLevelChanged);
connect(deviceModel.get(), &ParticipantDeviceModel::isSpeakingChanged, this, &ParticipantDeviceListModel::onParticipantDeviceSpeaking);
mList << deviceModel;
}
mInitialized = true;
}
ParticipantDeviceListModel::ParticipantDeviceListModel (CallModel * callModel, QObject *parent) : ProxyListModel(parent) {
if(callModel && callModel->isConference()) {
mCallModel = callModel;
connect(mCallModel, &CallModel::conferenceModelChanged, this, &ParticipantDeviceListModel::onConferenceModelChanged);
initConferenceModel();
}
}
ParticipantDeviceListModel::~ParticipantDeviceListModel(){
}
void ParticipantDeviceListModel::initConferenceModel(){
if(!mInitialized && mCallModel){
auto conferenceModel = mCallModel->getConferenceSharedModel();
if(conferenceModel){
updateDevices(conferenceModel->getConference()->getMe()->getDevices(), true);
updateDevices(conferenceModel->getConference()->getParticipantDeviceList(), false);
qDebug() << "Conference have " << mList.size() << " devices";
connect(conferenceModel.get(), &ConferenceModel::activeSpeakerParticipantDevice, this, &ParticipantDeviceListModel::onActiveSpeakerParticipantDevice);
connect(conferenceModel.get(), &ConferenceModel::participantAdded, this, &ParticipantDeviceListModel::onParticipantAdded);
connect(conferenceModel.get(), &ConferenceModel::participantRemoved, this, &ParticipantDeviceListModel::onParticipantRemoved);
connect(conferenceModel.get(), &ConferenceModel::participantDeviceAdded, this, &ParticipantDeviceListModel::onParticipantDeviceAdded);
connect(conferenceModel.get(), &ConferenceModel::participantDeviceRemoved, this, &ParticipantDeviceListModel::onParticipantDeviceRemoved);
connect(conferenceModel.get(), &ConferenceModel::conferenceStateChanged, this, &ParticipantDeviceListModel::onConferenceStateChanged);
connect(conferenceModel.get(), &ConferenceModel::participantDeviceMediaCapabilityChanged, this, &ParticipantDeviceListModel::onParticipantDeviceMediaCapabilityChanged);
connect(conferenceModel.get(), &ConferenceModel::participantDeviceMediaAvailabilityChanged, this, &ParticipantDeviceListModel::onParticipantDeviceMediaAvailabilityChanged);
connect(conferenceModel.get(), &ConferenceModel::participantDeviceIsSpeakingChanged, this, &ParticipantDeviceListModel::onParticipantDeviceIsSpeakingChanged);
mActiveSpeaker = get(conferenceModel->getConference()->getActiveSpeakerParticipantDevice());
mInitialized = true;
}
}
}
void ParticipantDeviceListModel::updateDevices(std::shared_ptr<linphone::Participant> participant){
std::list<std::shared_ptr<linphone::ParticipantDevice>> devices = participant->getDevices() ;
bool meAdded = false;
beginResetModel();
qDebug() << "Update devices from participant";
mList.clear();
for(auto device : devices){
bool addMe = isMe(device);
auto deviceModel = ParticipantDeviceModel::create(mCallModel, device, addMe);
connect(this, &ParticipantDeviceListModel::securityLevelChanged, deviceModel.get(), &ParticipantDeviceModel::onSecurityLevelChanged);
connect(deviceModel.get(), &ParticipantDeviceModel::isSpeakingChanged, this, &ParticipantDeviceListModel::onParticipantDeviceSpeaking);
mList << deviceModel;
if( addMe)
meAdded = true;
}
endResetModel();
if( meAdded)
emit meChanged();
}
void ParticipantDeviceListModel::updateDevices(const std::list<std::shared_ptr<linphone::ParticipantDevice>>& devices, const bool& isMe){
for(auto device : devices){
add(device);
}
}
bool ParticipantDeviceListModel::add(std::shared_ptr<linphone::ParticipantDevice> deviceToAdd){
auto deviceToAddAddr = deviceToAdd->getAddress();
int row = 0;
qDebug() << "Adding device " << deviceToAdd->getAddress()->asString().c_str();
for(auto item : mList) {
auto deviceModel = item.objectCast<ParticipantDeviceModel>();
if(deviceModel->getDevice() == deviceToAdd) {
qDebug() << "Device already exist. Send video update event";
deviceModel->updateVideoEnabled();
return false;
}else if(deviceToAddAddr->equal(deviceModel->getDevice()->getAddress())){// Address is the same (same device) but the model is using another linphone object. Replace it.
qDebug() << "Replacing device : Device exists but the model is using another linphone object.";
deviceModel->updateVideoEnabled();
removeRow(row);
break;
}
++row;
}
bool addMe = isMe(deviceToAdd);
auto deviceModel = ParticipantDeviceModel::create(mCallModel, deviceToAdd, addMe);
connect(this, &ParticipantDeviceListModel::securityLevelChanged, deviceModel.get(), &ParticipantDeviceModel::onSecurityLevelChanged);
connect(deviceModel.get(), &ParticipantDeviceModel::isSpeakingChanged, this, &ParticipantDeviceListModel::onParticipantDeviceSpeaking);
ProxyListModel::add<ParticipantDeviceModel>(deviceModel);
qDebug() << "Device added. Count=" << mList.count();
QStringList debugDevices;
for(auto i : mList){
auto item = i.objectCast<ParticipantDeviceModel>();
debugDevices.push_back( item->getAddress());
}
qDebug() << debugDevices.join("\n");
if( addMe){
qDebug() << "Added a me device";
emit meChanged();
}else if(mList.size() == 1 || (mList.size() == 2 && isMe(mList.front().objectCast<ParticipantDeviceModel>()->getDevice()))){
mActiveSpeaker = mList.back().objectCast<ParticipantDeviceModel>();
emit activeSpeakerChanged();
}
return true;
}
bool ParticipantDeviceListModel::remove(std::shared_ptr<const linphone::ParticipantDevice> deviceToRemove){
int row = 0;
for(auto item : mList){
auto device = item.objectCast<ParticipantDeviceModel>();
if( device->getDevice() == deviceToRemove){
device->updateVideoEnabled();
removeRow(row);
return true;
}else
++row;
}
return false;
}
QSharedPointer<ParticipantDeviceModel> ParticipantDeviceListModel::get(std::shared_ptr<const linphone::ParticipantDevice> deviceToGet, int * index){
int row = 0;
for(auto item : mList){
auto device = item.objectCast<ParticipantDeviceModel>();
if( device->getDevice() == deviceToGet){
if(index)
*index = row;
return device;
}else
++row;
}
return nullptr;
}
QSharedPointer<ParticipantDeviceModel> ParticipantDeviceListModel::getMe(int * index)const{
int row = 0;
for(auto item : mList){
auto device = item.objectCast<ParticipantDeviceModel>();
if( device->isMe() && device->isLocal()){
if(index)
*index = row;
return device;
}else
++row;
}
return nullptr;
}
ParticipantDeviceModel* ParticipantDeviceListModel::getActiveSpeakerModel() const{
return mActiveSpeaker.get();
}
bool ParticipantDeviceListModel::isMe(std::shared_ptr<linphone::ParticipantDevice> deviceToCheck)const{
if(mCallModel){
auto devices = mCallModel->getConferenceSharedModel()->getConference()->getMe()->getDevices();
auto deviceToCheckAddress = deviceToCheck->getAddress();
for(auto device : devices){
if(deviceToCheckAddress == device->getAddress())
return true;
}
}
return false;
}
bool ParticipantDeviceListModel::isMeAlone() const{
for(auto item : mList){
auto device = item.objectCast<ParticipantDeviceModel>();
if( !isMe(device->getDevice()))
return false;
}
return true;
}
void ParticipantDeviceListModel::onConferenceModelChanged (){
if(!mInitialized){
initConferenceModel();
}
}
void ParticipantDeviceListModel::onSecurityLevelChanged(std::shared_ptr<const linphone::Address> device){
emit securityLevelChanged(device);
}
//----------------------------------------------------------------------------------------------------------
void ParticipantDeviceListModel::onParticipantAdded(const std::shared_ptr<const linphone::Participant> & participant){
std::list<std::shared_ptr<linphone::ParticipantDevice>> devices = participant->getDevices() ;
if(devices.size() == 0)
qDebug() << "Participant has no device. It will not be added : " << participant->getAddress()->asString().c_str();
else
for(auto device : devices)
add(device);
}
void ParticipantDeviceListModel::onParticipantRemoved(const std::shared_ptr<const linphone::Participant> & participant){
std::list<std::shared_ptr<linphone::ParticipantDevice>> devices = participant->getDevices() ;
for(auto device : devices)
remove(device);
}
void ParticipantDeviceListModel::onParticipantDeviceAdded(const std::shared_ptr<const linphone::ParticipantDevice> & participantDevice){
qDebug() << "Adding new device : " << mList.count();
auto conferenceModel = mCallModel->getConferenceSharedModel();
std::list<std::shared_ptr<linphone::ParticipantDevice>> devices;
for(int i = 0 ; i < 2 ; ++i){
if( i == 0)
devices = conferenceModel->getConference()->getParticipantDeviceList();// Active devices.
else
devices = conferenceModel->getConference()->getMe()->getDevices();
for(auto realParticipantDevice : devices){
if( realParticipantDevice == participantDevice){
add(realParticipantDevice);
return;
}
}
}
qDebug() << "No participant device found from linphone::ParticipantDevice at onParticipantDeviceAdded";
}
void ParticipantDeviceListModel::onParticipantDeviceRemoved(const std::shared_ptr<const linphone::ParticipantDevice> & participantDevice){
qDebug() << "Removing participant device : " << mList.count();
if(!remove(participantDevice))
qDebug() << "No participant device found from linphone::ParticipantDevice at onParticipantDeviceRemoved";
}
void ParticipantDeviceListModel::onConferenceStateChanged(linphone::Conference::State newState){
if(newState == linphone::Conference::State::Created){
if(mCallModel && mCallModel->isConference()) {
auto conferenceModel = mCallModel->getConferenceSharedModel();
updateDevices(conferenceModel->getConference()->getMe()->getDevices(), true);
updateDevices(conferenceModel->getConference()->getParticipantDeviceList(), false);
}
emit conferenceCreated();
}
}
void ParticipantDeviceListModel::onParticipantDeviceMediaCapabilityChanged(const std::shared_ptr<const linphone::ParticipantDevice> & participantDevice){
auto device = get(participantDevice);
if(device)
device->updateVideoEnabled();
else
onParticipantDeviceAdded(participantDevice);
device = get(participantDevice);
if( device && device->isMe()){ // Capability change for me. Update all videos.
for(auto item : mList) {
auto device = item.objectCast<ParticipantDeviceModel>();
device->updateVideoEnabled();
}
}
}
void ParticipantDeviceListModel::onParticipantDeviceMediaAvailabilityChanged(const std::shared_ptr<const linphone::ParticipantDevice> & participantDevice){
auto device = get(participantDevice);
if(device)
device->updateVideoEnabled();
else
onParticipantDeviceAdded(participantDevice);
}
void ParticipantDeviceListModel::onActiveSpeakerParticipantDevice(const std::shared_ptr<const linphone::ParticipantDevice>& participantDevice){
auto device = get(participantDevice);
if( device){
mActiveSpeaker = device;
emit activeSpeakerChanged();
}
}
void ParticipantDeviceListModel::onParticipantDeviceIsSpeakingChanged(const std::shared_ptr<const linphone::ParticipantDevice> & participantDevice, bool isSpeaking){
auto device = get(participantDevice);
if( device)
emit participantSpeaking(device.get());
}
void ParticipantDeviceListModel::onParticipantDeviceSpeaking(){
}