Commit 4a7c8591 authored by Albert  Babí Oller's avatar Albert Babí Oller Committed by Albert Babí Oller

conference: separate local and moderator mute logic

Change-Id: I6683925e37a06893a88a5fb8b4285dcee4d2e676
parent d1065ab4
/*!
/*
* Copyright (C) 2020 by Savoir-faire Linux
* Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>
* Author: Anthony Léonard <anthony.leonard@savoirfairelinux.com>
......@@ -256,6 +256,46 @@ CallAdapter::shouldShowPreview(bool force)
return shouldShowPreview;
}
QJsonObject
CallAdapter::fillParticipantData(QMap<QString, QString> participant)
{
QJsonObject data;
data["x"] = participant["x"].toInt();
data["y"] = participant["y"].toInt();
data["w"] = participant["w"].toInt();
data["h"] = participant["h"].toInt();
data["uri"] = participant["uri"];
data["active"] = participant["active"] == "true";
data["videoMuted"] = participant["videoMuted"] == "true";
data["audioLocalMuted"] = participant["audioLocalMuted"] == "true";
data["audioModeratorMuted"] = participant["audioModeratorMuted"] == "true";
auto bestName = participant["uri"];
auto& accInfo = LRCInstance::accountModel().getAccountInfo(accountId_);
data["isLocal"] = false;
if (bestName == accInfo.profileInfo.uri) {
bestName = tr("me");
data["isLocal"] = true;
if (participant["videoMuted"] == "true")
data["avatar"] = accInfo.profileInfo.avatar;
} else {
try {
auto& contact = LRCInstance::getCurrentAccountInfo()
.contactModel->getContact(participant["uri"]);
bestName = LRCInstance::getCurrentAccountInfo()
.contactModel->bestNameForContact(participant["uri"]);
if (participant["videoMuted"] == "true")
data["avatar"] = contact.profileInfo.avatar;
} catch (...) {
}
}
data["bestName"] = bestName;
return data;
}
QVariantList
CallAdapter::getConferencesInfos()
{
......@@ -268,28 +308,7 @@ CallAdapter::getConferencesInfos()
try {
auto call = LRCInstance::getCurrentCallModel()->getCall(callId);
for (const auto& participant : call.participantsInfos) {
QJsonObject data;
data["x"] = participant["x"].toInt();
data["y"] = participant["y"].toInt();
data["w"] = participant["w"].toInt();
data["h"] = participant["h"].toInt();
data["uri"] = participant["uri"];
data["active"] = participant["active"] == "true";
auto bestName = participant["uri"];
auto& accInfo = LRCInstance::accountModel().getAccountInfo(accountId_);
data["isLocal"] = false;
if (bestName == accInfo.profileInfo.uri) {
bestName = tr("me");
data["isLocal"] = true;
} else {
try {
bestName = LRCInstance::getCurrentAccountInfo()
.contactModel->bestNameForContact(participant["uri"]);
} catch (...) {
}
}
data["bestName"] = bestName;
QJsonObject data = fillParticipantData(participant);
map.push_back(QVariant(data));
}
return map;
......@@ -338,54 +357,12 @@ CallAdapter::connectCallModel(const QString& accountId)
auto& callModel = accInfo.callModel;
auto call = callModel->getCall(confId);
const auto& convInfo = LRCInstance::getConversationFromCallId(confId);
bool currentMuted = false;
if (!convInfo.uid.isEmpty()) {
// Convert to QML
QVariantList map;
for (const auto& participant : call.participantsInfos) {
QJsonObject data;
data["x"] = participant["x"].toInt();
data["y"] = participant["y"].toInt();
data["w"] = participant["w"].toInt();
data["h"] = participant["h"].toInt();
data["uri"] = participant["uri"];
data["active"] = participant["active"] == "true";
data["videoMuted"] = participant["videoMuted"] == "true";
data["audioMuted"] = participant["audioMuted"] == "true";
auto bestName = participant["uri"];
data["isLocal"] = false;
auto& accInfo = LRCInstance::accountModel().getAccountInfo(accountId_);
if (bestName == accInfo.profileInfo.uri) {
bestName = tr("me");
data["isLocal"] = true;
currentMuted = participant["audioMuted"] == "true";
if (participant["videoMuted"] == "true")
data["avatar"] = accInfo.profileInfo.avatar;
} else {
try {
auto& contact = LRCInstance::getCurrentAccountInfo()
.contactModel->getContact(participant["uri"]);
bestName = LRCInstance::getCurrentAccountInfo()
.contactModel->bestNameForContact(participant["uri"]);
if (participant["videoMuted"] == "true")
data["avatar"] = contact.profileInfo.avatar;
} catch (...) {
}
}
data["bestName"] = bestName;
QJsonObject data = fillParticipantData(participant);
map.push_back(QVariant(data));
}
// Link local mute to conference mute
const auto& convInfo = LRCInstance::getConversationFromConvUid(convUid_);
if (!convInfo.uid.isEmpty()) {
auto call = LRCInstance::getCallInfoForConversation(convInfo);
if (call) {
if (currentMuted != call->audioMuted) {
muteThisCallToggle();
updateCallOverlay(convInfo);
}
}
updateCallOverlay(convInfo);
}
emit updateParticipantsInfos(map, accountId, confId);
}
......@@ -772,8 +749,8 @@ CallAdapter::muteParticipant(const QString& uri, const bool state)
}
}
bool
CallAdapter::isMuted(const QString& uri) const
CallAdapter::MuteStates
CallAdapter::getMuteState(const QString& uri) const
{
const auto& convInfo = LRCInstance::getConversationFromConvUid(convUid_);
auto* callModel = LRCInstance::getAccountInfo(accountId_).callModel.get();
......@@ -781,17 +758,27 @@ CallAdapter::isMuted(const QString& uri) const
try {
auto call = callModel->getCall(confId);
if (call.participantsInfos.size() == 0) {
return false;
return MuteStates::UNMUTED;
} else {
for (const auto& participant : call.participantsInfos) {
if (participant["uri"] == uri)
return participant["audioMuted"] == "true";
if (participant["uri"] == uri) {
if (participant["audioLocalMuted"] == "true") {
if (participant["audioModeratorMuted"] == "true") {
return MuteStates::BOTH_MUTED;
} else {
return MuteStates::LOCAL_MUTED;
}
} else if (participant["audioModeratorMuted"] == "true") {
return MuteStates::MODERATOR_MUTED;
}
return MuteStates::UNMUTED;
}
}
}
return false;
return MuteStates::UNMUTED;
} catch (...) {
}
return false;
return MuteStates::UNMUTED;
}
void
......
......@@ -33,6 +33,9 @@ class CallAdapter final : public QmlAdapterBase
Q_OBJECT
public:
enum MuteStates { UNMUTED, LOCAL_MUTED, MODERATOR_MUTED, BOTH_MUTED };
Q_ENUM(MuteStates)
explicit CallAdapter(QObject* parent = nullptr);
~CallAdapter() = default;
......@@ -68,7 +71,7 @@ public:
Q_INVOKABLE bool isRecordingThisCall();
Q_INVOKABLE QVariantList getConferencesInfos();
Q_INVOKABLE void muteParticipant(const QString& uri, const bool state);
Q_INVOKABLE bool isMuted(const QString& uri) const;
Q_INVOKABLE MuteStates getMuteState(const QString& uri) const;
Q_INVOKABLE void hangupParticipant(const QString& uri);
Q_INVOKABLE void updateCall(const QString& convUid = {},
const QString& accountId = {},
......@@ -106,6 +109,7 @@ public slots:
private:
bool shouldShowPreview(bool force);
void showNotification(const QString& accountId, const QString& convUid);
QJsonObject fillParticipantData(QMap<QString, QString> participant);
/*
* Current conf/call info.
......
......@@ -45,6 +45,8 @@ Rectangle {
property bool participantIsHost: false
property bool participantIsModerator: false
property bool participantIsMuted: false
property bool participantIsLocalMuted: false
property bool participantIsModeratorMuted: false
// TODO: try to use AvatarImage as well
function setAvatar(avatar) {
......@@ -67,9 +69,16 @@ Rectangle {
overlayMenu.showSetModerator = isHost && !isLocal && !participantIsModerator
overlayMenu.showUnsetModerator = isHost && !isLocal && participantIsModerator
participantIsMuted = CallAdapter.isMuted(overlayMenu.uri)
overlayMenu.showMute = isModerator && !participantIsMuted
overlayMenu.showUnmute = isModerator && participantIsMuted && isLocal
var muteState = CallAdapter.getMuteState(overlayMenu.uri)
var isLocalMuted = muteState === CallAdapter.LOCAL_MUTED
|| muteState === CallAdapter.BOTH_MUTED
var isModeratorMuted = muteState === CallAdapter.MODERATOR_MUTED
|| muteState === CallAdapter.BOTH_MUTED
participantIsMuted = isLocalMuted || isModeratorMuted
overlayMenu.showModeratorMute = isModerator && !isModeratorMuted
overlayMenu.showModeratorUnmute = isModerator && isModeratorMuted
overlayMenu.showMaximize = isModerator && showMax
overlayMenu.showMinimize = isModerator && showMin
overlayMenu.showHangup = isModerator && !isLocal && !participantIsHost
......@@ -78,7 +87,7 @@ Rectangle {
color: "transparent"
z: 1
// Participant header with moderator / mute indicators
// Participant header with host, moderator and mute indicators
Rectangle {
id: participantIndicators
width: indicatorsRowLayout.width
......
......@@ -43,8 +43,8 @@ Rectangle {
property string bestName: ""
property bool showSetModerator: false
property bool showUnsetModerator: false
property bool showMute: false
property bool showUnmute: false
property bool showModeratorMute: false
property bool showModeratorUnmute: false
property bool showMaximize: false
property bool showMinimize: false
property bool showHangup: false
......@@ -135,7 +135,7 @@ Rectangle {
PushButton {
id: toggleMute
visible: showMute || showUnmute
visible: showModeratorMute || showModeratorUnmute
Layout.preferredWidth: buttonPreferredSize
Layout.preferredHeight: buttonPreferredSize
preferredSize: 16
......@@ -144,12 +144,12 @@ Rectangle {
hoveredColor: JamiTheme.buttonConferenceHovered
pressedColor: JamiTheme.buttonConferencePressed
source: showMute? "qrc:/images/icons/mic-24px.svg"
: "qrc:/images/icons/mic_off-24px.svg"
source: showModeratorMute? "qrc:/images/icons/mic-24px.svg"
: "qrc:/images/icons/mic_off-24px.svg"
imageColor: hovered? JamiTheme.darkGreyColor
: JamiTheme.whiteColor
onClicked: CallAdapter.muteParticipant(uri, showMute)
onClicked: CallAdapter.muteParticipant(uri, showModeratorMute)
onHoveredChanged: toggleParticipantToolTip.visible = hovered
Text {
......@@ -157,8 +157,8 @@ Rectangle {
visible: false
width: parent.width
text: showMute? JamiStrings.muteParticipant
: JamiStrings.unmuteParticipant
text: showModeratorMute? JamiStrings.muteParticipant
: JamiStrings.unmuteParticipant
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignTop
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment