diff --git a/src/app/callparticipantsmodel.cpp b/src/app/callparticipantsmodel.cpp index 2a02a98e7ccb816e1e3de8a4b6a3b007874c22ad..1fd8ace59b2b25a674b2205cf056195b3fb153b0 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 6fa88be319b7052564c8a8894cf669f060b60d33..b3e1d69bd90d1252ebe02dff4d31b2727539b9c6 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 3674ddc6fb42d09ba40ece3da5e5d13b6f79ebe7..e15bb3b0c1e786189a1bd75116fdfe6e8119378c 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 4ce7c5087d05c9e6810c705a7d94b81f5e5afe72..1adbc5968425bfec9cc88a74fefd69665cad8909 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 c8a1b01f7ebb88eb497addb29f9a9d2de462762a..f939deb8797b11e40f09fb2c4875f1363e1fad86 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 10bc6874903a81dfbe3274a35b7f6ac2cb00cbc2..645728ad4e02e23ca5812dac0df49bc00ac741f7 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 307a167c7d7b51ed953d87be40a494bb7281c74d..8138ea19099596b115dadea1fa43ffd994703587 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 bd92e278f6a8d02441b03217c2d701e7d0bda2ba..c51cb10197f4d07fadbeb02985ee4ba82f23b15e 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 3ae412abbffd97519f0bd165c69406b940b6ca2e..523a38ec9b1baf4c2324a019d163d3cee5205fa9 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;