mirror of
https://github.com/savoirfairelinux/jami-client-qt.git
synced 2025-12-16 14:41:25 +08:00
conference: fix host-side conference transition to 1:1 call
Detailed reasoning available on GitLab issue page * Implements helper method getFallbackConversationForConference that returns a suitable conversation if a switch should be done * Moves slotConferenceRemoved from ConversationModel to CallModel * slotConferenceRemoved now properly removes conference data and handles conversation switch * Bumps daemon to commit fc3e8806946180ef40edcc2dfd64a5e3bb01878f GitLab: #1569 Change-Id: Ief97833613c3f289a2aeda747cf85a0d39712245
This commit is contained in:
@@ -47,6 +47,8 @@
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
#include <QSize>
|
||||
#include <qlogging.h>
|
||||
#include <qtcoreexports.h>
|
||||
|
||||
// std
|
||||
#include <chrono>
|
||||
@@ -141,6 +143,15 @@ public:
|
||||
QVariantList callAdvancedInformation();
|
||||
MapStringString advancedInformationForCallId(QString callId);
|
||||
|
||||
/**
|
||||
* Get a suitable fallback conversation for when the client should select a new one.
|
||||
* For example if the peer whose conversation was used to host the conference leaves the conference,
|
||||
* we need to pick another conversation to display the conference call.
|
||||
* @param confId the conference id
|
||||
* @return the conversation to use as fallback, nullopt if client does not need to change conversation or if none found
|
||||
*/
|
||||
OptRef<conversation::Info> getFallbackConversationForConference(const QString& confId);
|
||||
|
||||
QStringList getCallIds();
|
||||
|
||||
CallModel::CallInfoMap calls;
|
||||
@@ -226,6 +237,7 @@ public Q_SLOTS:
|
||||
*/
|
||||
void slotConferenceCreated(const QString& accountId, const QString& conversationId, const QString& callId);
|
||||
void slotConferenceChanged(const QString& accountId, const QString& callId, const QString& state);
|
||||
void slotConferenceRemoved(const QString& accountId, const QString& confId);
|
||||
/**
|
||||
* Listen from CallbacksHandler when a voice mail notice is incoming
|
||||
* @param accountId
|
||||
@@ -1007,6 +1019,7 @@ CallModelPimpl::CallModelPimpl(const CallModel& linked,
|
||||
connect(&callbacksHandler, &CallbacksHandler::incomingVCardChunk, this, &CallModelPimpl::slotincomingVCardChunk);
|
||||
connect(&callbacksHandler, &CallbacksHandler::conferenceCreated, this, &CallModelPimpl::slotConferenceCreated);
|
||||
connect(&callbacksHandler, &CallbacksHandler::conferenceChanged, this, &CallModelPimpl::slotConferenceChanged);
|
||||
connect(&callbacksHandler, &CallbacksHandler::conferenceRemoved, this, &CallModelPimpl::slotConferenceRemoved);
|
||||
connect(&callbacksHandler, &CallbacksHandler::voiceMailNotify, this, &CallModelPimpl::slotVoiceMailNotify);
|
||||
connect(&CallManager::instance(),
|
||||
&CallManagerInterface::onConferenceInfosUpdated,
|
||||
@@ -1056,6 +1069,54 @@ CallModelPimpl::advancedInformationForCallId(QString callId)
|
||||
return infoMap;
|
||||
}
|
||||
|
||||
OptRef<conversation::Info>
|
||||
CallModelPimpl::getFallbackConversationForConference(const QString& confId)
|
||||
{
|
||||
if (confId.isEmpty()) {
|
||||
qWarning() << "Empty conference ID provided.";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto currentConversation = linked.owner.conversationModel->getConversationForCallId(confId);
|
||||
if (!currentConversation) {
|
||||
qWarning() << "No conversation found for conference ID:" << confId;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const auto participantsIt = participantsModel.find(confId);
|
||||
if (participantsIt == participantsModel.end()) {
|
||||
qWarning() << "No participants model found for conference ID:" << confId;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const auto participants = participantsIt->second->getParticipants();
|
||||
if (participants.size() <= 1) {
|
||||
qWarning() << "Not enough participants to determine a fallback conversation for conference ID:" << confId;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Check if any participant matches the current conversation
|
||||
// If yes, then no need to switch conversation, so return nullopt
|
||||
for (const auto& participant : participants) {
|
||||
const auto conv = linked.owner.conversationModel->getConversationForPeerUri(participant.uri);
|
||||
if (conv && currentConversation->get().uid == conv->get().uid) {
|
||||
qWarning() << "Current conversation matches a participant. No fallback needed.";
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
OptRef<conversation::Info> fallbackConversation = std::nullopt;
|
||||
for (const auto& participant : participants) {
|
||||
if (participant.uri != linked.owner.profileInfo.uri) {
|
||||
fallbackConversation = linked.owner.conversationModel->getConversationForPeerUri(participant.uri);
|
||||
qWarning() << "Fallback conversation found with URI:" << participant.uri;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return fallbackConversation;
|
||||
}
|
||||
|
||||
QStringList
|
||||
CallModelPimpl::getCallIds()
|
||||
{
|
||||
@@ -1691,6 +1752,81 @@ CallModelPimpl::slotConferenceChanged(const QString& accountId, const QString& c
|
||||
Q_EMIT linked.currentCallChanged(currentCall_);
|
||||
}
|
||||
|
||||
void
|
||||
CallModelPimpl::slotConferenceRemoved(const QString& accountId, const QString& confId)
|
||||
{
|
||||
if (accountId != linked.owner.id || !linked.owner.conversationModel) {
|
||||
return;
|
||||
}
|
||||
auto confIt = calls.find(confId);
|
||||
if (confIt == calls.end() || !confIt->second) {
|
||||
return;
|
||||
}
|
||||
|
||||
qWarning() << "[conf:" << confId
|
||||
<< "] Attempting to transition to 1:1 call. Checking if conversation switch is needed.";
|
||||
|
||||
QString remainingPeerUri;
|
||||
QString remainingCallId;
|
||||
|
||||
auto participantsIt = participantsModel.find(confId);
|
||||
if (participantsIt != participantsModel.end()) {
|
||||
const auto participants = participantsIt->second->getParticipants();
|
||||
// Assuming the participants model is up to date, it should contain all remaining participants in the conference
|
||||
// Which should be 2: the host and the remaining remote peer
|
||||
// Therefore, we look for the participant which is not ourselves
|
||||
qWarning() << "[conf:" << confId << "] Found" << participants.size() << "participants in conference";
|
||||
for (const auto& participant : participants) {
|
||||
if (participant.uri != linked.owner.profileInfo.uri) {
|
||||
remainingPeerUri = participant.uri;
|
||||
try {
|
||||
remainingCallId = linked.getCallFromURI(remainingPeerUri, true).id;
|
||||
} catch (const std::exception& e) {
|
||||
qWarning() << "[conf:" << confId << "] Could not find call for peerUri:" << remainingPeerUri << ":"
|
||||
<< e.what();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qWarning() << "[conf:" << confId << "] Participants model not found for conference";
|
||||
}
|
||||
|
||||
auto currentConversation = linked.owner.conversationModel->getConversationForCallId(confId);
|
||||
auto fallbackConversation = getFallbackConversationForConference(confId);
|
||||
// If we have a fallback conversation, that means the client should switch to it
|
||||
if (fallbackConversation) {
|
||||
if (currentConversation) {
|
||||
currentConversation->get().confId.clear();
|
||||
}
|
||||
auto& targetConv = fallbackConversation->get();
|
||||
targetConv.confId.clear();
|
||||
if (!remainingCallId.isEmpty()) {
|
||||
targetConv.callId = remainingCallId;
|
||||
}
|
||||
qWarning() << "[conf:" << confId << "] Switching to fallback conversation:" << targetConv.uid;
|
||||
linked.owner.conversationModel->selectConversation(targetConv.uid);
|
||||
} else if (currentConversation) {
|
||||
auto& targetConv = currentConversation->get();
|
||||
targetConv.confId.clear();
|
||||
if (!remainingCallId.isEmpty()) {
|
||||
targetConv.callId = remainingCallId;
|
||||
}
|
||||
qWarning() << "[conf:" << confId << "] Staying in current conversation:" << targetConv.uid;
|
||||
} else {
|
||||
qWarning() << "[conf:" << confId << "] No conversation available to update after conference removal";
|
||||
}
|
||||
|
||||
// Now remove the conference from our models and list of calls then update currentCall_
|
||||
participantsModel.erase(confId);
|
||||
calls.erase(confIt);
|
||||
|
||||
currentCall_ = remainingCallId;
|
||||
Q_EMIT linked.currentCallChanged(currentCall_);
|
||||
|
||||
qDebug() << "[conf:" << confId << "] Conference removed, transitioned to callId:" << currentCall_;
|
||||
}
|
||||
|
||||
void
|
||||
CallModelPimpl::onRemoteRecordingChanged(const QString& callId, const QString& peerUri, bool state)
|
||||
{
|
||||
|
||||
@@ -309,12 +309,6 @@ public Q_SLOTS:
|
||||
* @param confId
|
||||
*/
|
||||
void slotCallAddedToConference(const QString& callId, const QString& conversationId, const QString& confId);
|
||||
/**
|
||||
* Listen from CallbacksHandler when a conference is deleted.
|
||||
* @param accountId
|
||||
* @param confId
|
||||
*/
|
||||
void slotConferenceRemoved(const QString& accountId, const QString& confId);
|
||||
/**
|
||||
* Listen for when a contact is composing
|
||||
* @param accountId
|
||||
@@ -1648,10 +1642,6 @@ ConversationModelPimpl::ConversationModelPimpl(const ConversationModel& linked,
|
||||
&lrc::api::CallModel::callAddedToConference,
|
||||
this,
|
||||
&ConversationModelPimpl::slotCallAddedToConference);
|
||||
connect(&callbacksHandler,
|
||||
&CallbacksHandler::conferenceRemoved,
|
||||
this,
|
||||
&ConversationModelPimpl::slotConferenceRemoved);
|
||||
connect(&ConfigurationManager::instance(),
|
||||
&ConfigurationManagerInterface::composingStatusChanged,
|
||||
this,
|
||||
@@ -1793,10 +1783,6 @@ ConversationModelPimpl::~ConversationModelPimpl()
|
||||
&lrc::api::CallModel::callAddedToConference,
|
||||
this,
|
||||
&ConversationModelPimpl::slotCallAddedToConference);
|
||||
disconnect(&callbacksHandler,
|
||||
&CallbacksHandler::conferenceRemoved,
|
||||
this,
|
||||
&ConversationModelPimpl::slotConferenceRemoved);
|
||||
disconnect(&ConfigurationManager::instance(),
|
||||
&ConfigurationManagerInterface::composingStatusChanged,
|
||||
this,
|
||||
@@ -3311,19 +3297,6 @@ ConversationModelPimpl::updateInteractionStatus(const QString& accountId,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ConversationModelPimpl::slotConferenceRemoved(const QString& accountId, const QString& confId)
|
||||
{
|
||||
if (accountId != linked.owner.id)
|
||||
return;
|
||||
// Get conversation
|
||||
for (auto& i : conversations) {
|
||||
if (i.confId == confId) {
|
||||
i.confId = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ConversationModelPimpl::slotComposingStatusChanged(const QString& accountId,
|
||||
const QString& convId,
|
||||
|
||||
Reference in New Issue
Block a user