From f17fc0b670a1424986c1ba0c94c544238c2331e2 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 9 Jul 2021 12:32:20 +0300 Subject: [PATCH] Support additional audio ssrc. --- .../calls/group/calls_group_call.cpp | 14 +++- .../calls/group/calls_group_call.h | 2 + .../calls/group/calls_group_members.cpp | 66 ++++++++++++++----- .../calls/group/calls_group_members_row.cpp | 17 ++--- .../calls/group/calls_group_members_row.h | 5 -- Telegram/SourceFiles/data/data_group_call.cpp | 65 ++++++++++++++---- Telegram/SourceFiles/data/data_group_call.h | 16 +++-- 7 files changed, 135 insertions(+), 50 deletions(-) diff --git a/Telegram/SourceFiles/calls/group/calls_group_call.cpp b/Telegram/SourceFiles/calls/group/calls_group_call.cpp index e35e39fad..467ab573a 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_call.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_call.cpp @@ -233,10 +233,11 @@ GroupCall::VideoTrack::VideoTrack( struct VideoParams { std::string endpointId; std::vector ssrcGroups; + uint32 additionalSsrc = 0; bool paused = false; [[nodiscard]] bool empty() const { - return endpointId.empty() || ssrcGroups.empty(); + return !additionalSsrc && (endpointId.empty() || ssrcGroups.empty()); } [[nodiscard]] explicit operator bool() const { return !empty(); @@ -255,7 +256,8 @@ struct ParticipantVideoParams { return !was; } return now->match([&](const MTPDgroupCallParticipantVideo &data) { - if (data.is_paused() != was.paused) { + if (data.is_paused() != was.paused + || data.vaudio_source().value_or_empty() != was.additionalSsrc) { return false; } if (gsl::make_span(data.vendpoint().v) @@ -304,6 +306,7 @@ struct ParticipantVideoParams { params->match([&](const MTPDgroupCallParticipantVideo &data) { result.paused = data.is_paused(); result.endpointId = data.vendpoint().v.toStdString(); + result.additionalSsrc = data.vaudio_source().value_or_empty(); const auto &list = data.vsource_groups().v; result.ssrcGroups.reserve(list.size()); for (const auto &group : list) { @@ -343,6 +346,11 @@ bool IsScreenPaused(const std::shared_ptr ¶ms) { return params && params->screen.paused; } +uint32 GetAdditionalAudioSsrc( + const std::shared_ptr ¶ms) { + return params ? params->screen.additionalSsrc : 0; +} + std::shared_ptr ParseVideoParams( const tl::conditional &camera, const tl::conditional &screen, @@ -2763,7 +2771,7 @@ void GroupCall::checkJoined() { MTP_vector(std::move(sources)) )).done([=](const MTPVector &result) { if (!ranges::contains(result.v, MTP_int(_joinState.ssrc))) { - LOG(("Call Info: Rejoin after no _mySsrc in checkGroupCall.")); + LOG(("Call Info: Rejoin after no my ssrc in checkGroupCall.")); _joinState.nextActionPending = true; checkNextJoinAction(); } else { diff --git a/Telegram/SourceFiles/calls/group/calls_group_call.h b/Telegram/SourceFiles/calls/group/calls_group_call.h index 6a4611050..c8eb713dc 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_call.h +++ b/Telegram/SourceFiles/calls/group/calls_group_call.h @@ -169,6 +169,8 @@ struct ParticipantVideoParams; const std::shared_ptr ¶ms); [[nodiscard]] bool IsScreenPaused( const std::shared_ptr ¶ms); +[[nodiscard]] uint32 GetAdditionalAudioSsrc( + const std::shared_ptr ¶ms); class GroupCall final : public base::has_weak_ptr { public: diff --git a/Telegram/SourceFiles/calls/group/calls_group_members.cpp b/Telegram/SourceFiles/calls/group/calls_group_members.cpp index 1d6aa524f..f7e9fd3fd 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_members.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_members.cpp @@ -224,6 +224,7 @@ private: const Data::GroupCallParticipant &now); void updateRow( not_null row, + const std::optional &was, const Data::GroupCallParticipant *participant); void removeRow(not_null row); void updateRowLevel(not_null row, float level); @@ -496,7 +497,7 @@ void Members::Controller::subscribeToChanges(not_null real) { if (!update.now) { if (const auto row = findRow(participantPeer)) { if (isMe(participantPeer)) { - updateRow(row, nullptr); + updateRow(row, update.was, nullptr); } else { removeRow(row); delegate()->peerListRefreshRows(); @@ -596,7 +597,7 @@ void Members::Controller::updateRow( if (row->state() == Row::State::Invited) { reorderIfInvitedBefore = row->absoluteIndex(); } - updateRow(row, &now); + updateRow(row, was, &now); if ((now.speaking && (!was || !was->speaking)) || (now.raisedHandRating != (was ? was->raisedHandRating : 0)) || (!now.canSelfUnmute && was && was->canSelfUnmute)) { @@ -774,17 +775,25 @@ void Members::Controller::checkRowPosition(not_null row) { void Members::Controller::updateRow( not_null row, + const std::optional &was, const Data::GroupCallParticipant *participant) { const auto wasSounding = row->sounding(); - const auto wasSsrc = row->ssrc(); + const auto wasSsrc = was ? was->ssrc : 0; + const auto wasAdditionalSsrc = was + ? GetAdditionalAudioSsrc(was->videoParams) + : 0; row->setSkipLevelUpdate(_skipRowLevelUpdate); row->updateState(participant); const auto nowSounding = row->sounding(); - const auto nowSsrc = row->ssrc(); + const auto nowSsrc = participant ? participant->ssrc : 0; + const auto nowAdditionalSsrc = participant + ? GetAdditionalAudioSsrc(participant->videoParams) + : 0; const auto wasNoSounding = _soundingRowBySsrc.empty(); + if (wasSsrc == nowSsrc) { - if (nowSounding != wasSounding) { + if (nowSsrc && nowSounding != wasSounding) { if (nowSounding) { _soundingRowBySsrc.emplace(nowSsrc, row); } else { @@ -793,11 +802,25 @@ void Members::Controller::updateRow( } } else { _soundingRowBySsrc.remove(wasSsrc); - if (nowSounding) { - Assert(nowSsrc != 0); + if (nowSounding && nowSsrc) { _soundingRowBySsrc.emplace(nowSsrc, row); } } + if (wasAdditionalSsrc == nowAdditionalSsrc) { + if (nowAdditionalSsrc && nowSounding != wasSounding) { + if (nowSounding) { + _soundingRowBySsrc.emplace(nowAdditionalSsrc, row); + } else { + _soundingRowBySsrc.remove(nowAdditionalSsrc); + } + } + } else { + _soundingRowBySsrc.remove(wasAdditionalSsrc); + if (nowSounding && nowAdditionalSsrc) { + _soundingRowBySsrc.emplace(nowAdditionalSsrc, row); + } + } + const auto nowNoSounding = _soundingRowBySsrc.empty(); if (wasNoSounding && !nowNoSounding) { _soundingAnimation.start(); @@ -809,7 +832,14 @@ void Members::Controller::updateRow( } void Members::Controller::removeRow(not_null row) { - _soundingRowBySsrc.remove(row->ssrc()); + // There may be 0, 1 or 2 entries for a row. + for (auto i = begin(_soundingRowBySsrc); i != end(_soundingRowBySsrc);) { + if (i->second == row) { + i = _soundingRowBySsrc.erase(i); + } else { + ++i; + } + } delegate()->peerListRemoveRow(row); } @@ -1343,11 +1373,17 @@ base::unique_qptr Members::Controller::createRowContextMenu( } } } - } - if (real->ssrc() != 0 - && (!isMe(participantPeer) || _peer->canManageGroupCall())) { - addMuteActionsToContextMenu(result, participantPeer, admin, real); + if (participant + && (!isMe(participantPeer) || _peer->canManageGroupCall()) + && (participant->ssrc != 0 + || GetAdditionalAudioSsrc(participant->videoParams) != 0)) { + addMuteActionsToContextMenu( + result, + participantPeer, + admin, + static_cast(row.get())); + } } if (isMe(participantPeer)) { @@ -1545,14 +1581,14 @@ void Members::Controller::addMuteActionsToContextMenu( std::unique_ptr Members::Controller::createRowForMe() { auto result = std::make_unique(this, _call->joinAs()); - updateRow(result.get(), nullptr); + updateRow(result.get(), std::nullopt, nullptr); return result; } std::unique_ptr Members::Controller::createRow( const Data::GroupCallParticipant &participant) { auto result = std::make_unique(this, participant.peer); - updateRow(result.get(), &participant); + updateRow(result.get(), std::nullopt, &participant); return result; } @@ -1562,7 +1598,7 @@ std::unique_ptr Members::Controller::createInvitedRow( return nullptr; } auto result = std::make_unique(this, participantPeer); - updateRow(result.get(), nullptr); + updateRow(result.get(), std::nullopt, nullptr); return result; } diff --git a/Telegram/SourceFiles/calls/group/calls_group_members_row.cpp b/Telegram/SourceFiles/calls/group/calls_group_members_row.cpp index 21743fd03..22e1d21d9 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_members_row.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_members_row.cpp @@ -144,7 +144,6 @@ void MembersRow::setSkipLevelUpdate(bool value) { void MembersRow::updateState( const Data::GroupCallParticipant *participant) { - setSsrc(participant ? participant->ssrc : 0); setVolume(participant ? participant->volume : Group::kDefaultVolume); @@ -155,10 +154,16 @@ void MembersRow::updateState( _mutedByMe = false; _raisedHandRating = 0; } else if (!participant->muted - || (participant->sounding && participant->ssrc != 0)) { + || (participant->sounding && participant->ssrc != 0) + || (participant->additionalSounding + && GetAdditionalAudioSsrc(participant->videoParams) != 0)) { setState(State::Active); - setSounding(participant->sounding && participant->ssrc != 0); - setSpeaking(participant->speaking && participant->ssrc != 0); + setSounding((participant->sounding && participant->ssrc != 0) + || (participant->additionalSounding + && GetAdditionalAudioSsrc(participant->videoParams) != 0)); + setSpeaking((participant->speaking && participant->ssrc != 0) + || (participant->additionalSpeaking + && GetAdditionalAudioSsrc(participant->videoParams) != 0)); _mutedByMe = participant->mutedByMe; _raisedHandRating = 0; } else if (participant->canSelfUnmute) { @@ -283,10 +288,6 @@ void MembersRow::setState(State state) { } } -void MembersRow::setSsrc(uint32 ssrc) { - _ssrc = ssrc; -} - void MembersRow::setVolume(int volume) { _volume = volume; if (_statusIcon) { diff --git a/Telegram/SourceFiles/calls/group/calls_group_members_row.h b/Telegram/SourceFiles/calls/group/calls_group_members_row.h index 314b86703..e5aa2e82c 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_members_row.h +++ b/Telegram/SourceFiles/calls/group/calls_group_members_row.h @@ -85,9 +85,6 @@ public: [[nodiscard]] State state() const { return _state; } - [[nodiscard]] uint32 ssrc() const { - return _ssrc; - } [[nodiscard]] bool sounding() const { return _sounding; } @@ -179,7 +176,6 @@ private: void setSounding(bool sounding); void setSpeaking(bool speaking); void setState(State state); - void setSsrc(uint32 ssrc); void setVolume(int volume); void ensureUserpicCache( @@ -212,7 +208,6 @@ private: QString _aboutText; crl::time _speakingLastTime = 0; uint64 _raisedHandRating = 0; - uint32 _ssrc = 0; int _volume = Group::kDefaultVolume; bool _sounding : 1; bool _speaking : 1; diff --git a/Telegram/SourceFiles/data/data_group_call.cpp b/Telegram/SourceFiles/data/data_group_call.cpp index 116388d79..caee89c25 100644 --- a/Telegram/SourceFiles/data/data_group_call.cpp +++ b/Telegram/SourceFiles/data/data_group_call.cpp @@ -543,6 +543,8 @@ void GroupCall::applyParticipantsSlice( .was = *i, }; _participantPeerByAudioSsrc.erase(i->ssrc); + _participantPeerByAudioSsrc.erase( + GetAdditionalAudioSsrc(i->videoParams)); _speakingByActiveFinishes.remove(participantPeer); _participants.erase(i); if (sliceSource != ApplySliceSource::FullReloaded) { @@ -599,18 +601,33 @@ void GroupCall::applyParticipantsSlice( .raisedHandRating = raisedHandRating, .ssrc = uint32(data.vsource().v), .volume = volume, - .applyVolumeFromMin = applyVolumeFromMin, - .speaking = canSelfUnmute && (was ? was->speaking : false), + .sounding = canSelfUnmute && was && was->sounding, + .speaking = canSelfUnmute && was && was->speaking, + .additionalSounding = (canSelfUnmute + && was + && was->additionalSounding), + .additionalSpeaking = (canSelfUnmute + && was + && was->additionalSpeaking), .muted = data.is_muted(), .mutedByMe = mutedByMe, .canSelfUnmute = canSelfUnmute, .onlyMinLoaded = onlyMinLoaded, .videoJoined = videoJoined, + .applyVolumeFromMin = applyVolumeFromMin, }; if (i == end(_participants)) { - _participantPeerByAudioSsrc.emplace( - value.ssrc, - participantPeer); + if (value.ssrc) { + _participantPeerByAudioSsrc.emplace( + value.ssrc, + participantPeer); + } + if (const auto additional = GetAdditionalAudioSsrc( + value.videoParams)) { + _participantPeerByAudioSsrc.emplace( + additional, + participantPeer); + } _participants.push_back(value); if (const auto user = participantPeer->asUser()) { _peer->owner().unregisterInvitedToCallUser(_id, user); @@ -618,9 +635,22 @@ void GroupCall::applyParticipantsSlice( } else { if (i->ssrc != value.ssrc) { _participantPeerByAudioSsrc.erase(i->ssrc); - _participantPeerByAudioSsrc.emplace( - value.ssrc, - participantPeer); + if (value.ssrc) { + _participantPeerByAudioSsrc.emplace( + value.ssrc, + participantPeer); + } + } + if (GetAdditionalAudioSsrc(i->videoParams) + != GetAdditionalAudioSsrc(value.videoParams)) { + _participantPeerByAudioSsrc.erase( + GetAdditionalAudioSsrc(i->videoParams)); + if (const auto additional = GetAdditionalAudioSsrc( + value.videoParams)) { + _participantPeerByAudioSsrc.emplace( + additional, + participantPeer); + } } *i = value; } @@ -662,11 +692,22 @@ void GroupCall::applyLastSpoke( if (speaking) { _participantSpeaking.fire({ participant }); } - if (participant->sounding != sounding - || participant->speaking != speaking) { + const auto useAdditional = (ssrc != participant->ssrc); + const auto nowSounding = useAdditional + ? participant->additionalSounding + : participant->sounding; + const auto nowSpeaking = useAdditional + ? participant->additionalSpeaking + : participant->speaking; + if (nowSounding != sounding || nowSpeaking != speaking) { const auto was = *participant; - participant->sounding = sounding; - participant->speaking = speaking; + if (useAdditional) { + participant->additionalSounding = sounding; + participant->additionalSpeaking = speaking; + } else { + participant->sounding = sounding; + participant->speaking = speaking; + } _participantUpdates.fire({ .was = was, .now = *participant, diff --git a/Telegram/SourceFiles/data/data_group_call.h b/Telegram/SourceFiles/data/data_group_call.h index 9b38e05b0..cb642abfd 100644 --- a/Telegram/SourceFiles/data/data_group_call.h +++ b/Telegram/SourceFiles/data/data_group_call.h @@ -32,14 +32,16 @@ struct GroupCallParticipant { uint64 raisedHandRating = 0; uint32 ssrc = 0; int volume = 0; - bool applyVolumeFromMin = true; - bool sounding = false; - bool speaking = false; - bool muted = false; - bool mutedByMe = false; - bool canSelfUnmute = false; - bool onlyMinLoaded = false; + bool sounding : 1; + bool speaking : 1; + bool additionalSounding : 1; + bool additionalSpeaking : 1; + bool muted : 1; + bool mutedByMe : 1; + bool canSelfUnmute : 1; + bool onlyMinLoaded : 1; bool videoJoined = false; + bool applyVolumeFromMin = true; [[nodiscard]] const std::string &cameraEndpoint() const; [[nodiscard]] const std::string &screenEndpoint() const;