/* * 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 . */ #include "ParticipantDeviceList.hpp" #include "core/App.hpp" #include "core/participant/ParticipantCore.hpp" #include #include DEFINE_ABSTRACT_OBJECT(ParticipantDeviceList) QSharedPointer ParticipantDeviceList::create(const std::shared_ptr &participant) { auto model = QSharedPointer(new ParticipantDeviceList(participant), &QObject::deleteLater); model->moveToThread(App::getInstance()->thread()); model->setSelf(model); return model; } QSharedPointer ParticipantDeviceList::create() { auto model = QSharedPointer(new ParticipantDeviceList(), &QObject::deleteLater); model->moveToThread(App::getInstance()->thread()); model->setSelf(model); return model; } ParticipantDeviceList::ParticipantDeviceList(const std::shared_ptr &participant, QObject *parent) : ListProxy(parent) { std::list> devices = participant->getDevices(); for (auto device : devices) { auto deviceModel = ParticipantDeviceCore::create(device, isMe(device)); // connect(this, &ParticipantDeviceList::securityLevelChanged, deviceModel.get(), // &ParticipantDeviceCore::onSecurityLevelChanged); connect(deviceModel.get(), &ParticipantDeviceCore::isSpeakingChanged, this, &ParticipantDeviceList::onParticipantDeviceSpeaking); mList << deviceModel; } mInitialized = true; } ParticipantDeviceList::ParticipantDeviceList(QObject *parent) { mustBeInMainThread(getClassName()); } // ParticipantDeviceList::ParticipantDeviceList(CallModel *callModel, QObject *parent) : ProxyListModel(parent) { // if (callModel && callModel->isConference()) { // mCallModel = callModel; // connect(mCallModel, &CallModel::conferenceModelChanged, this, &ParticipantDeviceList::onConferenceModelChanged); // initConferenceModel(); // } // } ParticipantDeviceList::~ParticipantDeviceList() { mustBeInMainThread(getClassName()); } void ParticipantDeviceList::setSelf(QSharedPointer me) { } void ParticipantDeviceList::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, // &ParticipantDeviceList::onActiveSpeakerParticipantDevice); // connect(conferenceModel.get(), &ConferenceModel::participantAdded, this, // &ParticipantDeviceList::onParticipantAdded); // connect(conferenceModel.get(), &ConferenceModel::participantRemoved, this, // &ParticipantDeviceList::onParticipantRemoved); // connect(conferenceModel.get(), &ConferenceModel::participantDeviceAdded, this, // &ParticipantDeviceList::onParticipantDeviceAdded); // connect(conferenceModel.get(), &ConferenceModel::participantDeviceRemoved, this, // &ParticipantDeviceList::onParticipantDeviceRemoved); // connect(conferenceModel.get(), &ConferenceModel::conferenceStateChanged, this, // &ParticipantDeviceList::onConferenceStateChanged); // connect(conferenceModel.get(), &ConferenceModel::participantDeviceMediaCapabilityChanged, this, // &ParticipantDeviceList::onParticipantDeviceMediaCapabilityChanged); // connect(conferenceModel.get(), &ConferenceModel::participantDeviceMediaAvailabilityChanged, this, // &ParticipantDeviceList::onParticipantDeviceMediaAvailabilityChanged); // connect(conferenceModel.get(), &ConferenceModel::participantDeviceIsSpeakingChanged, this, // &ParticipantDeviceList::onParticipantDeviceIsSpeakingChanged); // mActiveSpeaker = get(conferenceModel->getConference()->getActiveSpeakerParticipantDevice()); // mInitialized = true; // } // } } void ParticipantDeviceList::updateDevices(std::shared_ptr participant) { std::list> devices = participant->getDevices(); bool meAdded = false; beginResetModel(); qDebug() << "Update devices from participant"; mList.clear(); for (auto device : devices) { bool addMe = isMe(device); auto deviceModel = ParticipantDeviceCore::create(device, addMe); // connect(this, &ParticipantDeviceList::securityLevelChanged, deviceModel.get(), // &ParticipantDeviceCore::onSecurityLevelChanged); connect(deviceModel.get(), &ParticipantDeviceCore::isSpeakingChanged, this, &ParticipantDeviceList::onParticipantDeviceSpeaking); mList << deviceModel; if (addMe) meAdded = true; } endResetModel(); if (meAdded) emit meChanged(); } void ParticipantDeviceList::updateDevices(const std::list> &devices, const bool &isMe) { for (auto device : devices) { add(device); } } bool ParticipantDeviceList::add(const QSharedPointer &deviceToAdd) { auto deviceToAddAddr = deviceToAdd->getAddress(); int row = 0; qDebug() << "Adding device " << deviceToAdd->getAddress(); for (auto item : mList) { auto deviceCore = item.objectCast(); if (deviceCore == deviceToAdd) { qDebug() << "Device already exist. Send video update event"; // deviceCore->updateVideoEnabled(); return false; } else if (deviceToAddAddr == deviceCore->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."; // deviceCore->updateVideoEnabled(); removeRow(row); break; } ++row; } bool addMe = isMe(deviceToAdd); auto deviceModel = ParticipantDeviceCore::create(deviceToAdd, addMe); // connect(this, &ParticipantDeviceList::securityLevelChanged, deviceModel.get(), // &ParticipantDeviceCore::onSecurityLevelChanged); connect(deviceModel.get(), &ParticipantDeviceCore::isSpeakingChanged, this, &ParticipantDeviceList::onParticipantDeviceSpeaking); ListProxy::add(deviceModel); qDebug() << "Device added. Count=" << mList.count(); QStringList debugDevices; for (auto i : mList) { auto item = i.objectCast(); 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()->getDevice()))) { mActiveSpeaker = mList.back().objectCast(); emit activeSpeakerChanged(); } return true; } bool ParticipantDeviceList::remove(std::shared_ptr deviceToRemove) { int row = 0; for (auto item : mList) { auto device = item.objectCast(); if (device->getDevice() == deviceToRemove) { // device->updateVideoEnabled(); removeRow(row); return true; } else ++row; } return false; } QSharedPointer ParticipantDeviceList::get(std::shared_ptr deviceToGet, int *index) { int row = 0; for (auto item : mList) { auto device = item.objectCast(); if (device->getDevice() == deviceToGet) { if (index) *index = row; return device; } else ++row; } return nullptr; } QSharedPointer ParticipantDeviceList::getMe(int *index) const { int row = 0; for (auto item : mList) { auto device = item.objectCast(); if (device->isMe() && device->isLocal()) { if (index) *index = row; return device; } else ++row; } return nullptr; } ParticipantDeviceCore *ParticipantDeviceList::getActiveSpeakerModel() const { return mActiveSpeaker.get(); } bool ParticipantDeviceList::isMe(std::shared_ptr 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 ParticipantDeviceList::isMeAlone() const { for (auto item : mList) { auto device = item.objectCast(); if (!isMe(device->getDevice())) return false; } return true; } void ParticipantDeviceList::onConferenceModelChanged() { if (!mInitialized) { initConferenceModel(); } } void ParticipantDeviceList::onSecurityLevelChanged(std::shared_ptr device) { emit securityLevelChanged(device); } //---------------------------------------------------------------------------------------------------------- void ParticipantDeviceList::onParticipantAdded(const std::shared_ptr &participant) { std::list> 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 ParticipantDeviceList::onParticipantRemoved(const std::shared_ptr &participant) { std::list> devices = participant->getDevices(); for (auto device : devices) remove(device); } void ParticipantDeviceList::onParticipantDeviceAdded( const std::shared_ptr &participantDevice) { qDebug() << "Adding new device : " << mList.count(); // auto conferenceModel = mCallModel->getConferenceSharedModel(); std::list> 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 ParticipantDeviceList::onParticipantDeviceRemoved( const std::shared_ptr &participantDevice) { qDebug() << "Removing participant device : " << mList.count(); if (!remove(participantDevice)) qDebug() << "No participant device found from linphone::ParticipantDevice at onParticipantDeviceRemoved"; } void ParticipantDeviceList::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 ParticipantDeviceList::onParticipantDeviceMediaCapabilityChanged( const std::shared_ptr &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(); // device->updateVideoEnabled(); // } // } } void ParticipantDeviceList::onParticipantDeviceMediaAvailabilityChanged( const std::shared_ptr &participantDevice) { // auto device = get(participantDevice); // if (device) device->updateVideoEnabled(); // else onParticipantDeviceAdded(participantDevice); } void ParticipantDeviceList::onActiveSpeakerParticipantDevice( const std::shared_ptr &participantDevice) { // auto device = get(participantDevice); // if (device) { // mActiveSpeaker = device; // emit activeSpeakerChanged(); // } } void ParticipantDeviceList::onParticipantDeviceIsSpeakingChanged( const std::shared_ptr &participantDevice, bool isSpeaking) { auto device = get(participantDevice); if (device) emit participantSpeaking(device.get()); } void ParticipantDeviceList::onParticipantDeviceSpeaking() { }