From ba02a5c46a7780897fd1e8b4166e6fd0c2539ebf Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 15 Apr 2021 18:21:27 +0400 Subject: [PATCH] Resolve video chat participants by unknown ssrcs. --- .../SourceFiles/calls/calls_group_call.cpp | 63 +++++++++++++------ Telegram/SourceFiles/calls/calls_group_call.h | 2 + Telegram/SourceFiles/data/data_group_call.cpp | 55 +++++++++++++--- Telegram/SourceFiles/data/data_group_call.h | 6 +- 4 files changed, 96 insertions(+), 30 deletions(-) diff --git a/Telegram/SourceFiles/calls/calls_group_call.cpp b/Telegram/SourceFiles/calls/calls_group_call.cpp index e730af122..32b2da0d0 100644 --- a/Telegram/SourceFiles/calls/calls_group_call.cpp +++ b/Telegram/SourceFiles/calls/calls_group_call.cpp @@ -80,6 +80,7 @@ constexpr auto kPlayConnectingEach = crl::time(1056) + 2 * crl::time(1000); struct VideoParams { tgcalls::GroupParticipantDescription description; + base::flat_set videoSsrcs; uint32 hash = 0; }; @@ -148,7 +149,11 @@ std::shared_ptr ParseVideoParams( if (existing && existing->hash == hash) { return existing; } - const auto data = existing ? existing : std::make_shared(); + // We don't reuse existing pointer, that way we can compare pointers + // to see if anything was changed in video params. + const auto data = /*existing + ? existing + : */std::make_shared(); data->hash = hash; auto error = QJsonParseError{ 0, QJsonParseError::NoError }; @@ -181,7 +186,9 @@ std::shared_ptr ParseVideoParams( const auto list = inner.value("sources").toArray(); sources.reserve(list.size()); for (const auto &source : list) { - sources.push_back(uint32_t(source.toDouble())); + const auto ssrc = uint32_t(source.toDouble()); + sources.push_back(ssrc); + data->videoSsrcs.emplace(ssrc); } } data->description.videoSourceGroups.push_back({ @@ -209,16 +216,13 @@ std::shared_ptr ParseVideoParams( } auto parameters = std::vector>(); { - const auto list = inner.value("parameters").toArray(); + const auto list = inner.value("parameters").toObject(); parameters.reserve(list.size()); - for (const auto ¶meter : list) { - const auto inside = parameter.toObject(); - for (auto i = inside.begin(); i != inside.end(); ++i) { - parameters.push_back({ - i.key().toStdString(), - i.value().toString().toStdString(), - }); - } + for (auto i = list.begin(); i != list.end(); ++i) { + parameters.push_back({ + i.key().toStdString(), + i.value().toString().toStdString(), + }); } } data->description.videoPayloadTypes.push_back({ @@ -244,6 +248,14 @@ std::shared_ptr ParseVideoParams( return data; } +const base::flat_set &VideoSourcesFromParams( + const std::shared_ptr ¶ms) { + static const auto kEmpty = base::flat_set(); + return (params && !params->videoSsrcs.empty()) + ? params->videoSsrcs + : kEmpty; +} + GroupCall::LoadPartTask::LoadPartTask( base::weak_ptr call, int64 time, @@ -544,13 +556,18 @@ void GroupCall::join(const MTPInputGroupCall &inputCall) { const auto &now = *update.now; const auto &was = update.was; const auto volumeChanged = was - ? (was->volume != now.volume || was->mutedByMe != now.mutedByMe) + ? (was->volume != now.volume + || was->mutedByMe != now.mutedByMe) : (now.volume != Group::kDefaultVolume || now.mutedByMe); - if (now.videoParams) { - auto participants = std::vector(); - participants.push_back(now.videoParams->description); - participants.back().audioSsrc = now.ssrc; - _instance->addParticipants(std::move(participants)); + if (now.videoParams + && now.ssrc + && (!was + || was->videoParams != now.videoParams + || was->ssrc != now.ssrc) + && (now.peer != _joinAs) + && (_instanceMode != InstanceMode::None)) { + prepareParticipantForAdding(now); + addPreparedParticipantsDelayed(); } if (volumeChanged) { @@ -1113,6 +1130,8 @@ void GroupCall::handlePossibleCreateOrJoinResponse( } setInstanceMode(InstanceMode::Rtc); _instance->setJoinResponsePayload(payload, {}); + + addParticipantsToInstance(); }); } @@ -1143,6 +1162,11 @@ void GroupCall::prepareParticipantForAdding( auto &added = _preparedParticipants.back(); added.audioSsrc = participant.ssrc; _unresolvedSsrcs.remove(added.audioSsrc); + for (const auto &group : added.videoSourceGroups) { + for (const auto ssrc : group.ssrcs) { + _unresolvedSsrcs.remove(ssrc); + } + } } void GroupCall::addPreparedParticipants() { @@ -1499,7 +1523,10 @@ void GroupCall::requestParticipantsInformation( const auto &existing = real->participants(); for (const auto ssrc : ssrcs) { - const auto participantPeer = real->participantPeerBySsrc(ssrc); + const auto byAudio = real->participantPeerByAudioSsrc(ssrc); + const auto participantPeer = byAudio + ? byAudio + : real->participantPeerByVideoSsrc(ssrc); if (!participantPeer) { _unresolvedSsrcs.emplace(ssrc); continue; diff --git a/Telegram/SourceFiles/calls/calls_group_call.h b/Telegram/SourceFiles/calls/calls_group_call.h index f2b7972aa..917ca84b7 100644 --- a/Telegram/SourceFiles/calls/calls_group_call.h +++ b/Telegram/SourceFiles/calls/calls_group_call.h @@ -79,6 +79,8 @@ struct VideoParams; [[nodiscard]] std::shared_ptr ParseVideoParams( const QByteArray &json, const std::shared_ptr &existing); +[[nodiscard]] const base::flat_set &VideoSourcesFromParams( + const std::shared_ptr ¶ms); class GroupCall final : public base::has_weak_ptr { public: diff --git a/Telegram/SourceFiles/data/data_group_call.cpp b/Telegram/SourceFiles/data/data_group_call.cpp index c590b54f7..061a7fe7b 100644 --- a/Telegram/SourceFiles/data/data_group_call.cpp +++ b/Telegram/SourceFiles/data/data_group_call.cpp @@ -186,9 +186,18 @@ bool GroupCall::participantsLoaded() const { return _allParticipantsLoaded; } -PeerData *GroupCall::participantPeerBySsrc(uint32 ssrc) const { - const auto i = _participantPeerBySsrc.find(ssrc); - return (i != end(_participantPeerBySsrc)) ? i->second.get() : nullptr; +PeerData *GroupCall::participantPeerByAudioSsrc(uint32 ssrc) const { + const auto i = _participantPeerByAudioSsrc.find(ssrc); + return (i != end(_participantPeerByAudioSsrc)) + ? i->second.get() + : nullptr; +} + +PeerData *GroupCall::participantPeerByVideoSsrc(uint32 ssrc) const { + const auto i = _participantPeerByVideoSsrc.find(ssrc); + return (i != end(_participantPeerByVideoSsrc)) + ? i->second.get() + : nullptr; } rpl::producer<> GroupCall::participantsSliceAdded() { @@ -295,7 +304,8 @@ void GroupCall::processFullCallFields(const MTPphone_GroupCall &call) { data.vcall().match([&](const MTPDgroupCall &data) { _participants.clear(); _speakingByActiveFinishes.clear(); - _participantPeerBySsrc.clear(); + _participantPeerByAudioSsrc.clear(); + _participantPeerByVideoSsrc.clear(); _allParticipantsLoaded = false; applyParticipantsSlice( @@ -488,7 +498,11 @@ void GroupCall::applyParticipantsSlice( auto update = ParticipantUpdate{ .was = *i, }; - _participantPeerBySsrc.erase(i->ssrc); + _participantPeerByAudioSsrc.erase(i->ssrc); + const auto &all = VideoSourcesFromParams(i->videoParams); + for (const auto ssrc : all) { + _participantPeerByVideoSsrc.erase(ssrc); + } _speakingByActiveFinishes.remove(participantPeer); _participants.erase(i); if (sliceSource != ApplySliceSource::SliceLoaded) { @@ -557,18 +571,39 @@ void GroupCall::applyParticipantsSlice( .onlyMinLoaded = onlyMinLoaded, }; if (i == end(_participants)) { - _participantPeerBySsrc.emplace(value.ssrc, participantPeer); + _participantPeerByAudioSsrc.emplace( + value.ssrc, + participantPeer); + const auto &all = VideoSourcesFromParams(value.videoParams); + for (const auto ssrc : all) { + _participantPeerByVideoSsrc.emplace( + ssrc, + participantPeer); + } _participants.push_back(value); if (const auto user = participantPeer->asUser()) { _peer->owner().unregisterInvitedToCallUser(_id, user); } } else { if (i->ssrc != value.ssrc) { - _participantPeerBySsrc.erase(i->ssrc); - _participantPeerBySsrc.emplace( + _participantPeerByAudioSsrc.erase(i->ssrc); + _participantPeerByAudioSsrc.emplace( value.ssrc, participantPeer); } + if (i->videoParams != value.videoParams) { + const auto &old = VideoSourcesFromParams(i->videoParams); + for (const auto ssrc : old) { + _participantPeerByVideoSsrc.erase(ssrc); + } + const auto &now = VideoSourcesFromParams( + value.videoParams); + for (const auto ssrc : now) { + _participantPeerByVideoSsrc.emplace( + ssrc, + participantPeer); + } + } *i = value; } if (data.is_just_joined()) { @@ -592,8 +627,8 @@ void GroupCall::applyLastSpoke( uint32 ssrc, LastSpokeTimes when, crl::time now) { - const auto i = _participantPeerBySsrc.find(ssrc); - if (i == end(_participantPeerBySsrc)) { + const auto i = _participantPeerByAudioSsrc.find(ssrc); + if (i == end(_participantPeerByAudioSsrc)) { _unknownSpokenSsrcs[ssrc] = when; requestUnknownParticipants(); return; diff --git a/Telegram/SourceFiles/data/data_group_call.h b/Telegram/SourceFiles/data/data_group_call.h index c2dd507d2..747b43b50 100644 --- a/Telegram/SourceFiles/data/data_group_call.h +++ b/Telegram/SourceFiles/data/data_group_call.h @@ -102,7 +102,8 @@ public: -> const std::vector &; void requestParticipants(); [[nodiscard]] bool participantsLoaded() const; - [[nodiscard]] PeerData *participantPeerBySsrc(uint32 ssrc) const; + [[nodiscard]] PeerData *participantPeerByAudioSsrc(uint32 ssrc) const; + [[nodiscard]] PeerData *participantPeerByVideoSsrc(uint32 ssrc) const; [[nodiscard]] rpl::producer<> participantsSliceAdded(); [[nodiscard]] rpl::producer participantUpdated() const; @@ -181,7 +182,8 @@ private: std::optional _savedFull; std::vector _participants; - base::flat_map> _participantPeerBySsrc; + base::flat_map> _participantPeerByAudioSsrc; + base::flat_map> _participantPeerByVideoSsrc; base::flat_map, crl::time> _speakingByActiveFinishes; base::Timer _speakingByActiveFinishTimer; QString _nextOffset;