Rewrite voice chat members list management.

This commit is contained in:
John Preston 2021-03-17 20:05:18 +04:00
parent d392633b90
commit db7b61a77b
7 changed files with 252 additions and 188 deletions

View file

@ -543,7 +543,7 @@ void GroupCall::applyMeInCallLocally() {
| Flag::f_volume_by_admin // Self volume can only be set by admin. | Flag::f_volume_by_admin // Self volume can only be set by admin.
| ((muted() != MuteState::Active) ? Flag::f_muted : Flag(0)) | ((muted() != MuteState::Active) ? Flag::f_muted : Flag(0))
| (raisedHandRating > 0 ? Flag::f_raise_hand_rating : Flag(0)); | (raisedHandRating > 0 ? Flag::f_raise_hand_rating : Flag(0));
call->applyUpdateChecked( call->applyLocalUpdate(
MTP_updateGroupCallParticipants( MTP_updateGroupCallParticipants(
inputCall(), inputCall(),
MTP_vector<MTPGroupCallParticipant>( MTP_vector<MTPGroupCallParticipant>(
@ -588,7 +588,7 @@ void GroupCall::applyParticipantLocally(
| (participant->raisedHandRating | (participant->raisedHandRating
? Flag::f_raise_hand_rating ? Flag::f_raise_hand_rating
: Flag(0)); : Flag(0));
_peer->groupCall()->applyUpdateChecked( _peer->groupCall()->applyLocalUpdate(
MTP_updateGroupCallParticipants( MTP_updateGroupCallParticipants(
inputCall(), inputCall(),
MTP_vector<MTPGroupCallParticipant>( MTP_vector<MTPGroupCallParticipant>(

View file

@ -354,8 +354,6 @@ private:
rpl::event_stream<VolumeRequest> _changeVolumeRequests; rpl::event_stream<VolumeRequest> _changeVolumeRequests;
rpl::event_stream<not_null<PeerData*>> _kickParticipantRequests; rpl::event_stream<not_null<PeerData*>> _kickParticipantRequests;
rpl::variable<int> _fullCount = 1; rpl::variable<int> _fullCount = 1;
rpl::variable<int> _fullCountMin = 0;
rpl::variable<int> _fullCountMax = std::numeric_limits<int>::max();
not_null<QWidget*> _menuParent; not_null<QWidget*> _menuParent;
base::unique_qptr<Ui::PopupMenu> _menu; base::unique_qptr<Ui::PopupMenu> _menu;
@ -954,19 +952,11 @@ void MembersController::setupListChangeViewers(not_null<GroupCall*> call) {
delegate()->peerListRefreshRows(); delegate()->peerListRefreshRows();
}); });
if (const auto row = findRow(event.wasJoinAs)) { if (const auto row = findRow(event.wasJoinAs)) {
if (row->state() != Row::State::Invited) {
if (const auto min = _fullCountMin.current()) {
_fullCountMin = min - 1;
}
}
removeRow(row); removeRow(row);
} }
if (findRow(event.nowJoinAs)) { if (findRow(event.nowJoinAs)) {
return; return;
} else if (auto row = createRowForMe()) { } else if (auto row = createRowForMe()) {
if (row->state() != Row::State::Invited) {
_fullCountMin = _fullCountMin.current() + 1;
}
delegate()->peerListAppendRow(std::move(row)); delegate()->peerListAppendRow(std::move(row));
} }
}, _lifetime); }, _lifetime);
@ -976,13 +966,7 @@ void MembersController::subscribeToChanges(not_null<Data::GroupCall*> real) {
_realCallRawValue = real; _realCallRawValue = real;
_realId = real->id(); _realId = real->id();
_fullCount = rpl::combine( _fullCount = real->fullCountValue();
real->fullCountValue(),
_fullCountMin.value(),
_fullCountMax.value()
) | rpl::map([](int value, int min, int max) {
return std::max(std::clamp(value, min, max), 1);
});
real->participantsSliceAdded( real->participantsSliceAdded(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
@ -1003,9 +987,6 @@ void MembersController::subscribeToChanges(not_null<Data::GroupCall*> real) {
if (isMe(participantPeer)) { if (isMe(participantPeer)) {
updateRow(row, nullptr); updateRow(row, nullptr);
} else { } else {
if (const auto min = _fullCountMin.current()) {
_fullCountMin = min - 1;
}
removeRow(row); removeRow(row);
delegate()->peerListRefreshRows(); delegate()->peerListRefreshRows();
} }
@ -1044,11 +1025,9 @@ void MembersController::updateRow(
const std::optional<Data::GroupCall::Participant> &was, const std::optional<Data::GroupCall::Participant> &was,
const Data::GroupCall::Participant &now) { const Data::GroupCall::Participant &now) {
auto reorderIfInvitedBeforeIndex = 0; auto reorderIfInvitedBeforeIndex = 0;
auto countChange = 0;
if (const auto row = findRow(now.peer)) { if (const auto row = findRow(now.peer)) {
if (row->state() == Row::State::Invited) { if (row->state() == Row::State::Invited) {
reorderIfInvitedBeforeIndex = row->absoluteIndex(); reorderIfInvitedBeforeIndex = row->absoluteIndex();
countChange = 1;
} }
updateRow(row, &now); updateRow(row, &now);
if ((now.speaking && (!was || !was->speaking)) if ((now.speaking && (!was || !was->speaking))
@ -1064,7 +1043,6 @@ void MembersController::updateRow(
delegate()->peerListAppendRow(std::move(row)); delegate()->peerListAppendRow(std::move(row));
} }
delegate()->peerListRefreshRows(); delegate()->peerListRefreshRows();
countChange = 1;
} }
static constexpr auto kInvited = Row::State::Invited; static constexpr auto kInvited = Row::State::Invited;
const auto reorder = [&] { const auto reorder = [&] {
@ -1081,13 +1059,6 @@ void MembersController::updateRow(
return static_cast<const Row&>(row).state() != kInvited; return static_cast<const Row&>(row).state() != kInvited;
}); });
} }
if (countChange) {
const auto fullCountMin = _fullCountMin.current() + countChange;
if (_fullCountMax.current() < fullCountMin) {
_fullCountMax = fullCountMin;
}
_fullCountMin = fullCountMin;
}
} }
bool MembersController::allRowsAboveAreSpeaking(not_null<Row*> row) const { bool MembersController::allRowsAboveAreSpeaking(not_null<Row*> row) const {
@ -1206,7 +1177,7 @@ void MembersController::checkRowPosition(not_null<Row*> row) {
}; };
delegate()->peerListSortRows(_peer->canManageGroupCall() delegate()->peerListSortRows(_peer->canManageGroupCall()
? makeComparator(projForAdmin) ? makeComparator(projForAdmin)
: makeComparator(projForAdmin)); : makeComparator(projForOther));
} }
void MembersController::updateRow( void MembersController::updateRow(
@ -1243,11 +1214,6 @@ void MembersController::updateRow(
_soundingAnimation.stop(); _soundingAnimation.stop();
} }
if (!participant && wasInChat) {
if (const auto min = _fullCountMin.current()) {
_fullCountMin = min - 1;
}
}
delegate()->peerListUpdateRow(row); delegate()->peerListUpdateRow(row);
} }
@ -1293,7 +1259,6 @@ void MembersController::prepare() {
; real && call && real->id() == call->id()) { ; real && call && real->id() == call->id()) {
prepareRows(real); prepareRows(real);
} else if (auto row = createRowForMe()) { } else if (auto row = createRowForMe()) {
_fullCountMin = (row->state() == Row::State::Invited) ? 0 : 1;
delegate()->peerListAppendRow(std::move(row)); delegate()->peerListAppendRow(std::move(row));
delegate()->peerListRefreshRows(); delegate()->peerListRefreshRows();
} }
@ -1314,7 +1279,6 @@ void MembersController::prepareRows(not_null<Data::GroupCall*> real) {
auto foundMe = false; auto foundMe = false;
auto changed = false; auto changed = false;
const auto &participants = real->participants(); const auto &participants = real->participants();
auto fullCountMin = 0;
auto count = delegate()->peerListFullRowsCount(); auto count = delegate()->peerListFullRowsCount();
for (auto i = 0; i != count;) { for (auto i = 0; i != count;) {
auto row = delegate()->peerListRowAt(i); auto row = delegate()->peerListRowAt(i);
@ -1329,7 +1293,6 @@ void MembersController::prepareRows(not_null<Data::GroupCall*> real) {
participantPeer, participantPeer,
&Data::GroupCall::Participant::peer); &Data::GroupCall::Participant::peer);
if (contains) { if (contains) {
++fullCountMin;
++i; ++i;
} else { } else {
changed = true; changed = true;
@ -1348,9 +1311,6 @@ void MembersController::prepareRows(not_null<Data::GroupCall*> real) {
? createRow(*i) ? createRow(*i)
: createRowForMe(); : createRowForMe();
if (row) { if (row) {
if (row->state() != Row::State::Invited) {
++fullCountMin;
}
changed = true; changed = true;
delegate()->peerListAppendRow(std::move(row)); delegate()->peerListAppendRow(std::move(row));
} }
@ -1358,20 +1318,12 @@ void MembersController::prepareRows(not_null<Data::GroupCall*> real) {
} }
for (const auto &participant : participants) { for (const auto &participant : participants) {
if (auto row = createRow(participant)) { if (auto row = createRow(participant)) {
++fullCountMin;
changed = true; changed = true;
delegate()->peerListAppendRow(std::move(row)); delegate()->peerListAppendRow(std::move(row));
} }
} }
if (changed) { if (changed) {
delegate()->peerListRefreshRows(); delegate()->peerListRefreshRows();
if (_fullCountMax.current() < fullCountMin) {
_fullCountMax = fullCountMin;
}
_fullCountMin = fullCountMin;
if (real->participantsLoaded()) {
_fullCountMax = fullCountMin;
}
} }
} }

View file

@ -1132,7 +1132,9 @@ void Panel::refreshTitle() {
widget(), widget(),
tr::lng_group_call_members( tr::lng_group_call_members(
lt_count_decimal, lt_count_decimal,
_members->fullCountValue() | tr::to_count()), _members->fullCountValue() | rpl::map([](int value) {
return (value > 0) ? float64(value) : 1.;
})),
st::groupCallSubtitleLabel); st::groupCallSubtitleLabel);
_subtitle->show(); _subtitle->show();
_subtitle->setAttribute(Qt::WA_TransparentForMouseEvents); _subtitle->setAttribute(Qt::WA_TransparentForMouseEvents);

View file

@ -323,9 +323,9 @@ void Instance::handleUpdate(
}, [&](const MTPDupdatePhoneCallSignalingData &data) { }, [&](const MTPDupdatePhoneCallSignalingData &data) {
handleSignalingData(session, data); handleSignalingData(session, data);
}, [&](const MTPDupdateGroupCall &data) { }, [&](const MTPDupdateGroupCall &data) {
handleGroupCallUpdate(session, data.vcall()); handleGroupCallUpdate(session, update);
}, [&](const MTPDupdateGroupCallParticipants &data) { }, [&](const MTPDupdateGroupCallParticipants &data) {
handleGroupCallUpdate(session, data); handleGroupCallUpdate(session, update);
}, [](const auto &) { }, [](const auto &) {
Unexpected("Update type in Calls::Instance::handleUpdate."); Unexpected("Update type in Calls::Instance::handleUpdate.");
}); });
@ -410,33 +410,45 @@ void Instance::handleCallUpdate(
void Instance::handleGroupCallUpdate( void Instance::handleGroupCallUpdate(
not_null<Main::Session*> session, not_null<Main::Session*> session,
const MTPGroupCall &call) { const MTPUpdate &update) {
const auto callId = call.match([](const auto &data) { const auto callId = update.match([](const MTPDupdateGroupCall &data) {
return data.vcall().match([](const auto &data) {
return data.vid().v; return data.vid().v;
}); });
}, [](const MTPDupdateGroupCallParticipants &data) {
return data.vcall().match([&](const MTPDinputGroupCall &data) {
return data.vid().v;
});
}, [](const auto &) -> uint64 {
Unexpected("Type in Instance::handleGroupCallUpdate.");
});
if (const auto existing = session->data().groupCall(callId)) { if (const auto existing = session->data().groupCall(callId)) {
existing->applyUpdate(call); existing->enqueueUpdate(update);
} } else {
if (_currentGroupCall applyGroupCallUpdateChecked(session, update);
&& (&_currentGroupCall->peer()->session() == session)) {
_currentGroupCall->handleUpdate(call);
} }
} }
void Instance::handleGroupCallUpdate( void Instance::applyGroupCallUpdateChecked(
not_null<Main::Session*> session, not_null<Main::Session*> session,
const MTPDupdateGroupCallParticipants &update) { const MTPUpdate &update) {
const auto callId = update.vcall().match([](const auto &data) { if (!_currentGroupCall
|| (&_currentGroupCall->peer()->session() != session)) {
return;
}
update.match([&](const MTPDupdateGroupCall &data) {
_currentGroupCall->handleUpdate(data.vcall());
}, [&](const MTPDupdateGroupCallParticipants &data) {
const auto callId = data.vcall().match([](const auto &data) {
return data.vid().v; return data.vid().v;
}); });
if (const auto existing = session->data().groupCall(callId)) { if (_currentGroupCall->id() == callId) {
existing->applyUpdate(update); _currentGroupCall->handleUpdate(data);
}
if (_currentGroupCall
&& (&_currentGroupCall->peer()->session() == session)
&& (_currentGroupCall->id() == callId)) {
_currentGroupCall->handleUpdate(update);
} }
}, [](const auto &) {
Unexpected("Type in Instance::applyGroupCallUpdateChecked.");
});
} }
void Instance::handleSignalingData( void Instance::handleSignalingData(

View file

@ -50,6 +50,12 @@ public:
void handleUpdate( void handleUpdate(
not_null<Main::Session*> session, not_null<Main::Session*> session,
const MTPUpdate &update); const MTPUpdate &update);
// Called by Data::GroupCall when it is appropriate by the 'version'.
void applyGroupCallUpdateChecked(
not_null<Main::Session*> session,
const MTPUpdate &update);
void showInfoPanel(not_null<Call*> call); void showInfoPanel(not_null<Call*> call);
void showInfoPanel(not_null<GroupCall*> call); void showInfoPanel(not_null<GroupCall*> call);
[[nodiscard]] Call *currentCall() const; [[nodiscard]] Call *currentCall() const;
@ -130,10 +136,7 @@ private:
const MTPDupdatePhoneCallSignalingData &data); const MTPDupdatePhoneCallSignalingData &data);
void handleGroupCallUpdate( void handleGroupCallUpdate(
not_null<Main::Session*> session, not_null<Main::Session*> session,
const MTPGroupCall &call); const MTPUpdate &update);
void handleGroupCallUpdate(
not_null<Main::Session*> session,
const MTPDupdateGroupCallParticipants &update);
DhConfig _dhConfig; DhConfig _dhConfig;

View file

@ -22,9 +22,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Data { namespace Data {
namespace { namespace {
constexpr auto kRequestPerPage = 30; constexpr auto kRequestPerPage = 50;
constexpr auto kSpeakingAfterActive = crl::time(6000); constexpr auto kSpeakingAfterActive = crl::time(6000);
constexpr auto kActiveAfterJoined = crl::time(1000); constexpr auto kActiveAfterJoined = crl::time(1000);
constexpr auto kWaitForUpdatesTimeout = 3 * crl::time(1000);
} // namespace } // namespace
@ -35,6 +36,7 @@ GroupCall::GroupCall(
: _id(id) : _id(id)
, _accessHash(accessHash) , _accessHash(accessHash)
, _peer(peer) , _peer(peer)
, _reloadByQueuedUpdatesTimer([=] { reload(); })
, _speakingByActiveFinishTimer([=] { checkFinishSpeakingByActive(); }) { , _speakingByActiveFinishTimer([=] { checkFinishSpeakingByActive(); }) {
} }
@ -71,10 +73,7 @@ auto GroupCall::participants() const
void GroupCall::requestParticipants() { void GroupCall::requestParticipants() {
if (_participantsRequestId || _reloadRequestId) { if (_participantsRequestId || _reloadRequestId) {
return; return;
} else if (_participants.size() >= _fullCount.current() && _allReceived) { } else if (_allParticipantsLoaded) {
return;
} else if (_allReceived) {
reload();
return; return;
} }
_participantsRequestId = api().request(MTPphone_GetGroupParticipants( _participantsRequestId = api().request(MTPphone_GetGroupParticipants(
@ -91,26 +90,29 @@ void GroupCall::requestParticipants() {
applyParticipantsSlice( applyParticipantsSlice(
data.vparticipants().v, data.vparticipants().v,
ApplySliceSource::SliceLoaded); ApplySliceSource::SliceLoaded);
_fullCount = data.vcount().v; setServerParticipantsCount(data.vcount().v);
if (!_allReceived if (data.vparticipants().v.isEmpty()) {
&& (data.vparticipants().v.size() < kRequestPerPage)) { _allParticipantsLoaded = true;
_allReceived = true;
} }
if (_allReceived) { computeParticipantsCount();
_fullCount = _participants.size();
}
});
_participantsSliceAdded.fire({}); _participantsSliceAdded.fire({});
_participantsRequestId = 0; _participantsRequestId = 0;
changePeerEmptyCallFlag(); processQueuedUpdates();
});
}).fail([=](const MTP::Error &error) { }).fail([=](const MTP::Error &error) {
_fullCount = _participants.size(); setServerParticipantsCount(_participants.size());
_allReceived = true; _allParticipantsLoaded = true;
computeParticipantsCount();
_participantsRequestId = 0; _participantsRequestId = 0;
changePeerEmptyCallFlag(); processQueuedUpdates();
}).send(); }).send();
} }
void GroupCall::setServerParticipantsCount(int count) {
_serverParticipantsCount = count;
changePeerEmptyCallFlag();
}
void GroupCall::changePeerEmptyCallFlag() { void GroupCall::changePeerEmptyCallFlag() {
const auto chat = _peer->asChat(); const auto chat = _peer->asChat();
const auto channel = _peer->asChannel(); const auto channel = _peer->asChannel();
@ -118,7 +120,7 @@ void GroupCall::changePeerEmptyCallFlag() {
constexpr auto channelFlag = MTPDchannel::Flag::f_call_not_empty; constexpr auto channelFlag = MTPDchannel::Flag::f_call_not_empty;
if (_peer->groupCall() != this) { if (_peer->groupCall() != this) {
return; return;
} else if (fullCount() > 0) { } else if (_serverParticipantsCount > 0) {
if (chat && !(chat->flags() & chatFlag)) { if (chat && !(chat->flags() & chatFlag)) {
chat->addFlags(chatFlag); chat->addFlags(chatFlag);
chat->session().changes().peerUpdated( chat->session().changes().peerUpdated(
@ -152,7 +154,7 @@ rpl::producer<int> GroupCall::fullCountValue() const {
} }
bool GroupCall::participantsLoaded() const { bool GroupCall::participantsLoaded() const {
return _allReceived; return _allParticipantsLoaded;
} }
PeerData *GroupCall::participantPeerBySsrc(uint32 ssrc) const { PeerData *GroupCall::participantPeerBySsrc(uint32 ssrc) const {
@ -169,35 +171,42 @@ auto GroupCall::participantUpdated() const
return _participantUpdates.events(); return _participantUpdates.events();
} }
void GroupCall::applyUpdate(const MTPGroupCall &update) { void GroupCall::enqueueUpdate(const MTPUpdate &update) {
applyCall(update, false); update.match([&](const MTPDupdateGroupCall &updateData) {
updateData.vcall().match([&](const MTPDgroupCall &data) {
const auto version = data.vversion().v;
if (!_version || _version == version) {
applyUpdate(update);
} else if (_version < version) {
_queuedUpdates.emplace(std::pair{ version, false }, update);
}
}, [&](const MTPDgroupCallDiscarded &data) {
applyUpdate(update);
});
}, [&](const MTPDupdateGroupCallParticipants &updateData) {
const auto version = updateData.vversion().v;
const auto proj = [](const MTPGroupCallParticipant &data) {
return data.match([&](const MTPDgroupCallParticipant &data) {
return data.is_versioned();
});
};
const auto increment = ranges::contains(
updateData.vparticipants().v,
true,
proj);
const auto required = increment ? (version - 1) : version;
if (_version == required) {
applyUpdate(update);
} else if (_version < required) {
_queuedUpdates.emplace(std::pair{ version, increment }, update);
}
}, [](const auto &) {
Unexpected("Type in GroupCall::enqueueUpdate.");
});
processQueuedUpdates();
} }
void GroupCall::applyCall(const MTPGroupCall &call, bool force) { void GroupCall::discard() {
call.match([&](const MTPDgroupCall &data) {
if (!_version) {
_version = data.vversion().v;
}
const auto title = qs(data.vtitle().value_or_empty());
const auto recordDate = data.vrecord_start_date().value_or_empty();
const auto changed = (_joinMuted != data.is_join_muted())
|| (_fullCount.current() != data.vparticipants_count().v)
|| (_canChangeJoinMuted != data.is_can_change_join_muted())
|| (_title.current() != title)
|| (_recordStartDate.current() != recordDate);
if (!force && !changed) {
return;
} else if (!force && _version > data.vversion().v) {
reload();
return;
}
_joinMuted = data.is_join_muted();
_canChangeJoinMuted = data.is_can_change_join_muted();
_fullCount = data.vparticipants_count().v;
_title = title;
_recordStartDate = recordDate;
changePeerEmptyCallFlag();
}, [&](const MTPDgroupCallDiscarded &data) {
const auto id = _id; const auto id = _id;
const auto peer = _peer; const auto peer = _peer;
crl::on_main(&peer->session(), [=] { crl::on_main(&peer->session(), [=] {
@ -209,23 +218,131 @@ void GroupCall::applyCall(const MTPGroupCall &call, bool force) {
} }
} }
}); });
});
} }
void GroupCall::processFullCall(const MTPphone_GroupCall &call) { void GroupCall::processFullCall(const MTPphone_GroupCall &call) {
call.match([&](const MTPDphone_groupCall &data) { call.match([&](const MTPDphone_groupCall &data) {
_peer->owner().processUsers(data.vusers()); _peer->owner().processUsers(data.vusers());
_peer->owner().processChats(data.vchats()); _peer->owner().processChats(data.vchats());
const auto &participants = data.vparticipants().v;
const auto nextOffset = qs(data.vparticipants_next_offset());
data.vcall().match([&](const MTPDgroupCall &data) {
if (data.vversion().v == _version
&& data.vparticipants_count().v == _serverParticipantsCount
&& (_serverParticipantsCount >= _participants.size())
&& (!_allParticipantsLoaded
|| _serverParticipantsCount == _participants.size())) {
return;
}
_participants.clear(); _participants.clear();
_speakingByActiveFinishes.clear(); _speakingByActiveFinishes.clear();
_participantPeerBySsrc.clear(); _participantPeerBySsrc.clear();
_allParticipantsLoaded = false;
applyParticipantsSlice(
participants,
ApplySliceSource::SliceLoaded);
_nextOffset = nextOffset;
applyCallFields(data);
_participantsSliceAdded.fire({});
}, [&](const MTPDgroupCallDiscarded &data) {
discard();
});
processQueuedUpdates();
});
}
void GroupCall::applyCallFields(const MTPDgroupCall &data) {
_version = data.vversion().v;
if (!_version) {
LOG(("API Error: Got zero version in groupCall."));
_version = 1;
}
_joinMuted = data.is_join_muted();
_canChangeJoinMuted = data.is_can_change_join_muted();
setServerParticipantsCount(data.vparticipants_count().v);
changePeerEmptyCallFlag();
_title = qs(data.vtitle().value_or_empty());
_recordStartDate = data.vrecord_start_date().value_or_empty();
_allParticipantsLoaded
= (_serverParticipantsCount == _participants.size());
computeParticipantsCount();
processQueuedUpdates();
}
void GroupCall::applyLocalUpdate(
const MTPDupdateGroupCallParticipants &update) {
applyParticipantsSlice(
update.vparticipants().v,
ApplySliceSource::UpdateReceived);
}
void GroupCall::applyUpdate(const MTPUpdate &update) {
update.match([&](const MTPDupdateGroupCall &data) {
data.vcall().match([&](const MTPDgroupCall &data) {
applyCallFields(data);
}, [&](const MTPDgroupCallDiscarded &data) {
discard();
});
}, [&](const MTPDupdateGroupCallParticipants &data) {
_version = data.vversion().v;
if (!_version) {
LOG(("API Error: "
"Got zero version in updateGroupCallParticipants."));
_version = 1;
}
applyParticipantsSlice( applyParticipantsSlice(
data.vparticipants().v, data.vparticipants().v,
ApplySliceSource::SliceLoaded); ApplySliceSource::UpdateReceived);
applyCall(data.vcall(), true); }, [](const auto &) {
_allReceived = (_fullCount.current() == _participants.size()); Unexpected("Type in GroupCall::processQueuedUpdates.");
_participantsSliceAdded.fire({});
}); });
Core::App().calls().applyGroupCallUpdateChecked(
&_peer->session(),
update);
}
void GroupCall::processQueuedUpdates() {
if (!_version) {
return;
}
const auto size = _queuedUpdates.size();
while (!_queuedUpdates.empty()) {
const auto &entry = _queuedUpdates.front();
const auto version = entry.first.first;
const auto versionIncremented = entry.first.second;
if ((version < _version)
|| (version == _version && versionIncremented)) {
_queuedUpdates.erase(_queuedUpdates.begin());
} else if (version == _version
|| (version == _version + 1 && versionIncremented)) {
const auto update = entry.second;
_queuedUpdates.erase(_queuedUpdates.begin());
applyUpdate(update);
} else {
break;
}
}
if (_queuedUpdates.empty()) {
const auto server = _serverParticipantsCount;
const auto local = int(_participants.size());
if (server < local
|| (_allParticipantsLoaded && server > local)) {
reload();
}
} else if (_queuedUpdates.size() != size
|| !_reloadByQueuedUpdatesTimer.isActive()) {
_reloadByQueuedUpdatesTimer.callOnce(kWaitForUpdatesTimeout);
}
}
void GroupCall::computeParticipantsCount() {
_fullCount = _allParticipantsLoaded
? int(_participants.size())
: std::max(int(_participants.size()), _serverParticipantsCount);
} }
void GroupCall::reload() { void GroupCall::reload() {
@ -235,6 +352,10 @@ void GroupCall::reload() {
api().request(_participantsRequestId).cancel(); api().request(_participantsRequestId).cancel();
_participantsRequestId = 0; _participantsRequestId = 0;
} }
_queuedUpdates.clear();
_reloadByQueuedUpdatesTimer.cancel();
_reloadRequestId = api().request( _reloadRequestId = api().request(
MTPphone_GetGroupCall(input()) MTPphone_GetGroupCall(input())
).done([=](const MTPphone_GroupCall &result) { ).done([=](const MTPphone_GroupCall &result) {
@ -252,7 +373,6 @@ void GroupCall::applyParticipantsSlice(
const auto now = base::unixtime::now(); const auto now = base::unixtime::now();
const auto speakingAfterActive = TimeId(kSpeakingAfterActive / 1000); const auto speakingAfterActive = TimeId(kSpeakingAfterActive / 1000);
auto changedCount = _fullCount.current();
for (const auto &participant : list) { for (const auto &participant : list) {
participant.match([&](const MTPDgroupCallParticipant &data) { participant.match([&](const MTPDgroupCallParticipant &data) {
const auto participantPeerId = peerFromMTP(data.vpeer()); const auto participantPeerId = peerFromMTP(data.vpeer());
@ -274,8 +394,8 @@ void GroupCall::applyParticipantsSlice(
_participantUpdates.fire(std::move(update)); _participantUpdates.fire(std::move(update));
} }
} }
if (changedCount > _participants.size()) { if (_serverParticipantsCount > 0) {
--changedCount; --_serverParticipantsCount;
} }
return; return;
} }
@ -338,7 +458,7 @@ void GroupCall::applyParticipantsSlice(
*i = value; *i = value;
} }
if (data.is_just_joined()) { if (data.is_just_joined()) {
++changedCount; ++_serverParticipantsCount;
} }
if (sliceSource != ApplySliceSource::SliceLoaded) { if (sliceSource != ApplySliceSource::SliceLoaded) {
_participantUpdates.fire({ _participantUpdates.fire({
@ -349,8 +469,8 @@ void GroupCall::applyParticipantsSlice(
}); });
} }
if (sliceSource == ApplySliceSource::UpdateReceived) { if (sliceSource == ApplySliceSource::UpdateReceived) {
_fullCount = changedCount;
changePeerEmptyCallFlag(); changePeerEmptyCallFlag();
computeParticipantsCount();
} }
} }
@ -542,6 +662,7 @@ void GroupCall::requestUnknownParticipants() {
).done([=](const MTPphone_GroupParticipants &result) { ).done([=](const MTPphone_GroupParticipants &result) {
result.match([&](const MTPDphone_groupParticipants &data) { result.match([&](const MTPDphone_groupParticipants &data) {
_peer->owner().processUsers(data.vusers()); _peer->owner().processUsers(data.vusers());
_peer->owner().processChats(data.vchats());
applyParticipantsSlice( applyParticipantsSlice(
data.vparticipants().v, data.vparticipants().v,
ApplySliceSource::UnknownLoaded); ApplySliceSource::UnknownLoaded);
@ -605,41 +726,6 @@ bool GroupCall::inCall() const {
&& (current->state() == Calls::GroupCall::State::Joined); && (current->state() == Calls::GroupCall::State::Joined);
} }
void GroupCall::applyUpdate(const MTPDupdateGroupCallParticipants &update) {
const auto version = update.vversion().v;
const auto applyUpdate = [&] {
if (version < _version) {
return false;
}
auto versionShouldIncrement = false;
for (const auto &participant : update.vparticipants().v) {
const auto versioned = participant.match([&](
const MTPDgroupCallParticipant &data) {
return data.is_versioned();
});
if (versioned) {
versionShouldIncrement = true;
break;
}
}
return versionShouldIncrement
? (version == _version + 1)
: (version == _version);
}();
if (!applyUpdate) {
return;
}
_version = version;
applyUpdateChecked(update);
}
void GroupCall::applyUpdateChecked(
const MTPDupdateGroupCallParticipants &update) {
applyParticipantsSlice(
update.vparticipants().v,
ApplySliceSource::UpdateReceived);
}
void GroupCall::setJoinMutedLocally(bool muted) { void GroupCall::setJoinMutedLocally(bool muted) {
_joinMuted = muted; _joinMuted = muted;
} }

View file

@ -82,10 +82,10 @@ public:
[[nodiscard]] rpl::producer<> participantsSliceAdded(); [[nodiscard]] rpl::producer<> participantsSliceAdded();
[[nodiscard]] rpl::producer<ParticipantUpdate> participantUpdated() const; [[nodiscard]] rpl::producer<ParticipantUpdate> participantUpdated() const;
void applyUpdate(const MTPGroupCall &update); void enqueueUpdate(const MTPUpdate &update);
void applyUpdate(const MTPDupdateGroupCallParticipants &update); void applyLocalUpdate(
void applyUpdateChecked(
const MTPDupdateGroupCallParticipants &update); const MTPDupdateGroupCallParticipants &update);
void applyLastSpoke(uint32 ssrc, LastSpokeTimes when, crl::time now); void applyLastSpoke(uint32 ssrc, LastSpokeTimes when, crl::time now);
void applyActiveUpdate( void applyActiveUpdate(
PeerId participantPeerId, PeerId participantPeerId,
@ -113,14 +113,19 @@ private:
}; };
[[nodiscard]] ApiWrap &api() const; [[nodiscard]] ApiWrap &api() const;
void discard();
[[nodiscard]] bool inCall() const; [[nodiscard]] bool inCall() const;
void applyCall(const MTPGroupCall &call, bool force);
void applyParticipantsSlice( void applyParticipantsSlice(
const QVector<MTPGroupCallParticipant> &list, const QVector<MTPGroupCallParticipant> &list,
ApplySliceSource sliceSource); ApplySliceSource sliceSource);
void requestUnknownParticipants(); void requestUnknownParticipants();
void changePeerEmptyCallFlag(); void changePeerEmptyCallFlag();
void checkFinishSpeakingByActive(); void checkFinishSpeakingByActive();
void applyCallFields(const MTPDgroupCall &data);
void applyUpdate(const MTPUpdate &update);
void setServerParticipantsCount(int count);
void computeParticipantsCount();
void processQueuedUpdates();
const uint64 _id = 0; const uint64 _id = 0;
const uint64 _accessHash = 0; const uint64 _accessHash = 0;
@ -131,11 +136,15 @@ private:
mtpRequestId _reloadRequestId = 0; mtpRequestId _reloadRequestId = 0;
rpl::variable<QString> _title; rpl::variable<QString> _title;
base::flat_map<std::pair<int,bool>, MTPUpdate> _queuedUpdates;
base::Timer _reloadByQueuedUpdatesTimer;
std::vector<Participant> _participants; std::vector<Participant> _participants;
base::flat_map<uint32, not_null<PeerData*>> _participantPeerBySsrc; base::flat_map<uint32, not_null<PeerData*>> _participantPeerBySsrc;
base::flat_map<not_null<PeerData*>, crl::time> _speakingByActiveFinishes; base::flat_map<not_null<PeerData*>, crl::time> _speakingByActiveFinishes;
base::Timer _speakingByActiveFinishTimer; base::Timer _speakingByActiveFinishTimer;
QString _nextOffset; QString _nextOffset;
int _serverParticipantsCount = 0;
rpl::variable<int> _fullCount = 0; rpl::variable<int> _fullCount = 0;
rpl::variable<TimeId> _recordStartDate = 0; rpl::variable<TimeId> _recordStartDate = 0;
@ -148,7 +157,7 @@ private:
bool _joinMuted = false; bool _joinMuted = false;
bool _canChangeJoinMuted = true; bool _canChangeJoinMuted = true;
bool _allReceived = false; bool _allParticipantsLoaded = false;
}; };