From d7d29156db24c87f1e9f2634fabcf4ba5f79e6e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Blin?= <sebastien.blin@savoirfairelinux.com> Date: Mon, 1 Aug 2022 11:06:32 -0400 Subject: [PATCH] vad: show a drop shadow around talking participants use "voiceActivity" from the conferences informations to show talking participants https://git.jami.net/savoirfairelinux/jami-daemon/-/issues/741 Change-Id: Iaedc61ce485ff03464128b5a17e0a6a0ea9d2c2e --- src/app/callparticipantsmodel.cpp | 3 ++ src/app/callparticipantsmodel.h | 1 + .../mainview/components/OngoingCallPage.qml | 2 +- .../components/ParticipantOverlay.qml | 48 +++++++++++-------- .../mainview/components/ParticipantsLayer.qml | 7 ++- .../ParticipantsLayoutHorizontal.qml | 2 + .../components/ParticipantsLayoutVertical.qml | 2 + src/libclient/api/callparticipantsmodel.h | 5 +- src/libclient/callparticipantsmodel.cpp | 5 +- 9 files changed, 49 insertions(+), 26 deletions(-) diff --git a/src/app/callparticipantsmodel.cpp b/src/app/callparticipantsmodel.cpp index 2a02a98e7..1fd8ace59 100644 --- a/src/app/callparticipantsmodel.cpp +++ b/src/app/callparticipantsmodel.cpp @@ -98,6 +98,9 @@ CallParticipantsModel::data(const QModelIndex& index, int role) const case Role::HandRaised: return QVariant::fromValue( participant.item.value(lrc::api::ParticipantsInfosStrings::HANDRAISED)); + case Role::VoiceActivity: + return QVariant::fromValue( + participant.item.value(lrc::api::ParticipantsInfosStrings::VOICEACTIVITY)); } return QVariant(); } diff --git a/src/app/callparticipantsmodel.h b/src/app/callparticipantsmodel.h index 6fa88be31..b3e1d69bd 100644 --- a/src/app/callparticipantsmodel.h +++ b/src/app/callparticipantsmodel.h @@ -45,6 +45,7 @@ X(IsModerator) \ X(IsLocal) \ X(IsContact) \ + X(VoiceActivity) \ X(HandRaised) namespace CallParticipant { diff --git a/src/app/mainview/components/OngoingCallPage.qml b/src/app/mainview/components/OngoingCallPage.qml index 3674ddc6f..e15bb3b0c 100644 --- a/src/app/mainview/components/OngoingCallPage.qml +++ b/src/app/mainview/components/OngoingCallPage.qml @@ -175,7 +175,7 @@ Rectangle { id: participantsLayer anchors.fill: parent anchors.centerIn: parent - anchors.margins: 3 + anchors.margins: 1 visible: participantsLayer.count !== 0 participantsSide: callOverlay.participantsSide diff --git a/src/app/mainview/components/ParticipantOverlay.qml b/src/app/mainview/components/ParticipantOverlay.qml index 4ce7c5087..1adbc5968 100644 --- a/src/app/mainview/components/ParticipantOverlay.qml +++ b/src/app/mainview/components/ParticipantOverlay.qml @@ -56,6 +56,7 @@ Item { property bool participantIsModeratorMuted: false property bool participantHandIsRaised: false property bool videoMuted: true + property bool voiceActive: false property bool isLocalMuted: true property bool meHost: CallAdapter.isCurrentHost() @@ -90,9 +91,21 @@ Item { } } + Rectangle { + z: -1 + color: JamiTheme.buttonTintedBlue + radius: 10 + visible:voiceActive + width: participantIsActive ? mediaDistRender.contentRect.width + 2 : undefined + height: participantIsActive ? mediaDistRender.contentRect.height + 2 : undefined + anchors.centerIn: participantIsActive ? parent : undefined + anchors.fill: participantIsActive ? undefined : parent + } + VideoView { id: mediaDistRender anchors.fill: parent + anchors.margins: 2 rendererId: root.sinkId crop: !participantIsActive @@ -118,39 +131,33 @@ Item { } } - overlayItems: Rectangle { + overlayItems: Item { id: overlayRect - width: participantIsActive ? mediaDistRender.contentRect.width : undefined - height: participantIsActive ? mediaDistRender.contentRect.height : undefined + width: participantIsActive ? mediaDistRender.contentRect.width - 2 : undefined + height: participantIsActive ? mediaDistRender.contentRect.height - 2 : undefined anchors.centerIn: participantIsActive ? parent : undefined anchors.fill: participantIsActive ? undefined : parent - color: "transparent" - Item { - anchors.fill: parent + HoverHandler { + onPointChanged: { + participantRect.opacity = 1 + fadeOutTimer.restart() + } - HoverHandler { - onPointChanged: { + onHoveredChanged: { + if (overlayMenu.hovered) { participantRect.opacity = 1 fadeOutTimer.restart() + return } - - onHoveredChanged: { - if (overlayMenu.hovered) { - participantRect.opacity = 1 - fadeOutTimer.restart() - return - } - participantRect.opacity = hovered ? 1 : 0 - } + participantRect.opacity = hovered ? 1 : 0 } } - Rectangle { + Item { id: participantRect anchors.fill: parent - color: "transparent" opacity: 0 // Participant buttons for moderation @@ -182,11 +189,10 @@ Item { // - In another participant, if i am not moderator, the mute state is isLocalMuted || participantIsModeratorMuted // - In another participant, if i am moderator, the mute state is isLocalMuted // - In my video, the mute state is isLocalMuted - Rectangle { + Item { id: participantIndicators width: participantRect.width height: shapeHeight - color: "transparent" anchors.bottom: parent.bottom Shape { diff --git a/src/app/mainview/components/ParticipantsLayer.qml b/src/app/mainview/components/ParticipantsLayer.qml index c8a1b01f7..f939deb87 100644 --- a/src/app/mainview/components/ParticipantsLayer.qml +++ b/src/app/mainview/components/ParticipantsLayer.qml @@ -19,8 +19,8 @@ import QtQuick -import QtQuick.Layouts 1.15 -import QtQuick.Controls 2.15 +import QtQuick.Layouts +import QtQuick.Controls import net.jami.Adapters 1.1 import net.jami.Models 1.1 @@ -55,6 +55,8 @@ Item { id: callVideoMedia ParticipantOverlay { + id: overlay + anchors.fill: parent anchors.leftMargin: leftMargin_ @@ -71,6 +73,7 @@ Item { videoMuted: videoMuted_ participantIsActive: active_ isLocalMuted: audioLocalMuted_ + voiceActive: voiceActive_ participantIsModeratorMuted: audioModeratorMuted_ participantHandIsRaised: isHandRaised_ diff --git a/src/app/mainview/components/ParticipantsLayoutHorizontal.qml b/src/app/mainview/components/ParticipantsLayoutHorizontal.qml index 10bc68749..645728ad4 100644 --- a/src/app/mainview/components/ParticipantsLayoutHorizontal.qml +++ b/src/app/mainview/components/ParticipantsLayoutHorizontal.qml @@ -120,6 +120,7 @@ SplitView { property bool audioLocalMuted_: AudioLocalMuted property bool audioModeratorMuted_: AudioModeratorMuted property bool isHandRaised_: HandRaised + property bool voiceActive_: VoiceActivity } } } @@ -307,6 +308,7 @@ SplitView { property bool audioLocalMuted_: AudioLocalMuted property bool audioModeratorMuted_: AudioModeratorMuted property bool isHandRaised_: HandRaised + property bool voiceActive_: VoiceActivity } } } diff --git a/src/app/mainview/components/ParticipantsLayoutVertical.qml b/src/app/mainview/components/ParticipantsLayoutVertical.qml index 307a167c7..8138ea190 100644 --- a/src/app/mainview/components/ParticipantsLayoutVertical.qml +++ b/src/app/mainview/components/ParticipantsLayoutVertical.qml @@ -215,6 +215,7 @@ SplitView { property bool audioLocalMuted_: AudioLocalMuted property bool audioModeratorMuted_: AudioModeratorMuted property bool isHandRaised_: HandRaised + property bool voiceActive_: VoiceActivity } } } @@ -288,6 +289,7 @@ SplitView { property bool audioLocalMuted_: AudioLocalMuted property bool audioModeratorMuted_: AudioModeratorMuted property bool isHandRaised_: HandRaised + property bool voiceActive_: VoiceActivity } } } diff --git a/src/libclient/api/callparticipantsmodel.h b/src/libclient/api/callparticipantsmodel.h index bd92e278f..c51cb1019 100644 --- a/src/libclient/api/callparticipantsmodel.h +++ b/src/libclient/api/callparticipantsmodel.h @@ -52,6 +52,7 @@ const QString AUDIOLOCALMUTED = "audioLocalMuted"; const QString AUDIOMODERATORMUTED = "audioModeratorMuted"; const QString ISMODERATOR = "isModerator"; const QString HANDRAISED = "handRaised"; +const QString VOICEACTIVITY = "voiceActivity"; const QString STREAMID = "sinkId"; // TODO update const QString BESTNAME = "bestName"; const QString ISLOCAL = "isLocal"; @@ -81,6 +82,7 @@ struct ParticipantInfos audioModeratorMuted = infos[ParticipantsInfosStrings::AUDIOMODERATORMUTED] == "true"; isModerator = infos[ParticipantsInfosStrings::ISMODERATOR] == "true"; handRaised = infos[ParticipantsInfosStrings::HANDRAISED] == "true"; + voiceActivity = infos[ParticipantsInfosStrings::VOICEACTIVITY] == "true"; if (infos[ParticipantsInfosStrings::STREAMID].isEmpty()) sinkId = callId + uri + device; @@ -107,6 +109,7 @@ struct ParticipantInfos bool islocal {false}; bool isContact {false}; bool handRaised {false}; + bool voiceActivity {false}; bool operator==(const ParticipantInfos& other) const { @@ -115,7 +118,7 @@ struct ParticipantInfos && audioModeratorMuted == other.audioModeratorMuted && avatar == other.avatar && bestName == other.bestName && isContact == other.isContact && islocal == other.islocal && videoMuted == other.videoMuted - && handRaised == other.handRaised; + && handRaised == other.handRaised && voiceActivity == other.voiceActivity; } }; diff --git a/src/libclient/callparticipantsmodel.cpp b/src/libclient/callparticipantsmodel.cpp index 3ae412abb..523a38ec9 100644 --- a/src/libclient/callparticipantsmodel.cpp +++ b/src/libclient/callparticipantsmodel.cpp @@ -115,7 +115,9 @@ CallParticipants::addParticipant(const ParticipantInfos& participant) 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); + participants_.insert(std::next(participants_.begin(), idx_), + participant.sinkId, + participant); added = true; } else { if (participant == (*it)) @@ -198,6 +200,7 @@ CallParticipants::toQJsonObject(uint index) const ret[ParticipantsInfosStrings::ISLOCAL] = participant->islocal; ret[ParticipantsInfosStrings::ISCONTACT] = participant->isContact; ret[ParticipantsInfosStrings::HANDRAISED] = participant->handRaised; + ret[ParticipantsInfosStrings::VOICEACTIVITY] = participant->voiceActivity; ret[ParticipantsInfosStrings::CALLID] = callId_; return ret; -- GitLab