From 3114ef0b0cb5d50ebed0e96d238f8ee00a8cc270 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 15 Dec 2020 01:08:14 +0300 Subject: [PATCH 01/23] Always build SQLCipher with OMIT_MEMLOCK to significantly increase its performance. --- sqlite/CMakeLists.txt | 2 +- sqlite/sqlite/sqlite3.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sqlite/CMakeLists.txt b/sqlite/CMakeLists.txt index b439b0cd6..319fe0d11 100644 --- a/sqlite/CMakeLists.txt +++ b/sqlite/CMakeLists.txt @@ -37,7 +37,7 @@ target_compile_definitions(tdsqlite PRIVATE #-DSQLITE_OMIT_DEPRECATED # SQLCipher uses deprecated sqlite3_profile #-DSQLITE_OMIT_SHARED_CACHE ) -target_compile_definitions(tdsqlite PRIVATE -DSQLITE_HAS_CODEC -DSQLITE_TEMP_STORE=2 -DSQLITE_ENABLE_FTS5 -DSQLITE_DISABLE_LFS) +target_compile_definitions(tdsqlite PRIVATE -DSQLITE_HAS_CODEC -DSQLITE_TEMP_STORE=2 -DSQLITE_ENABLE_FTS5 -DSQLITE_DISABLE_LFS -DOMIT_MEMLOCK) if (NOT WIN32) target_compile_definitions(tdsqlite PRIVATE -DHAVE_USLEEP -DNDEBUG=1) diff --git a/sqlite/sqlite/sqlite3.c b/sqlite/sqlite/sqlite3.c index 9f5890681..cb15a29a3 100644 --- a/sqlite/sqlite/sqlite3.c +++ b/sqlite/sqlite/sqlite3.c @@ -22555,7 +22555,7 @@ end_of_export: /* #include "sqlcipher.h" */ /* #include "crypto.h" */ -#ifndef OMIT_MEMLOCK +// #ifndef OMIT_MEMLOCK #if defined(__unix__) || defined(__APPLE__) || defined(_AIX) #include #include @@ -22564,7 +22564,7 @@ end_of_export: #elif defined(_WIN32) #include #endif -#endif +// #endif static volatile unsigned int default_flags = DEFAULT_CIPHER_FLAGS; static volatile unsigned char hmac_salt_mask = HMAC_SALT_MASK; From 84012cc6fda83be7eb43527053d6092a0aaaa9d7 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 15 Dec 2020 01:20:56 +0300 Subject: [PATCH 02/23] Build SQLCiper with SQLITE_OMIT_DEPRECATED. --- sqlite/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlite/CMakeLists.txt b/sqlite/CMakeLists.txt index 319fe0d11..30ab83e51 100644 --- a/sqlite/CMakeLists.txt +++ b/sqlite/CMakeLists.txt @@ -34,7 +34,7 @@ target_compile_definitions(tdsqlite PRIVATE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_PROGRESS_CALLBACK - #-DSQLITE_OMIT_DEPRECATED # SQLCipher uses deprecated sqlite3_profile + -DSQLITE_OMIT_DEPRECATED #-DSQLITE_OMIT_SHARED_CACHE ) target_compile_definitions(tdsqlite PRIVATE -DSQLITE_HAS_CODEC -DSQLITE_TEMP_STORE=2 -DSQLITE_ENABLE_FTS5 -DSQLITE_DISABLE_LFS -DOMIT_MEMLOCK) From 37a17476c7d0f7972ee9915fd8d50a72bb698762 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 15 Dec 2020 01:42:16 +0300 Subject: [PATCH 03/23] Update is_speaking field for speaking group call participants. --- td/telegram/GroupCallManager.cpp | 21 +++++++++++++++++---- td/telegram/GroupCallManager.h | 3 ++- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 3c41d1ffb..25ae5c7c7 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1281,7 +1281,7 @@ void GroupCallManager::set_group_call_participant_is_speaking(GroupCallId group_ } else { recursive = true; } - UserId user_id = get_group_call_participant_by_source(input_group_call_id, source); + UserId user_id = set_group_call_participant_is_speaking_by_source(input_group_call_id, source, is_speaking, date); if (!user_id.is_valid()) { if (!recursive) { auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), group_call_id, source, is_speaking, @@ -1318,8 +1318,6 @@ void GroupCallManager::set_group_call_participant_is_speaking(GroupCallId group_ } } - // TODO update participant list by speaking actions - promise.set_value(Unit()); } @@ -1679,7 +1677,8 @@ void GroupCallManager::on_group_call_recent_speakers_updated(const GroupCall *gr recent_speaker_update_timeout_.set_timeout_in(group_call->group_call_id.get(), MAX_RECENT_SPEAKER_UPDATE_DELAY); } -UserId GroupCallManager::get_group_call_participant_by_source(InputGroupCallId input_group_call_id, int32 source) { +UserId GroupCallManager::set_group_call_participant_is_speaking_by_source(InputGroupCallId input_group_call_id, + int32 source, bool is_speaking, int32 date) { auto participants_it = group_call_participants_.find(input_group_call_id); if (participants_it == group_call_participants_.end()) { return UserId(); @@ -1687,6 +1686,20 @@ UserId GroupCallManager::get_group_call_participant_by_source(InputGroupCallId i for (auto &participant : participants_it->second->participants) { if (participant.source == source) { + if (participant.is_speaking != is_speaking) { + participant.is_speaking = is_speaking; + if (is_speaking) { + participant.local_active_date = max(participant.local_active_date, date); + } + auto real_order = participant.get_real_order(); + if (real_order >= participants_it->second->min_order) { + participant.order = real_order; + } + if (participant.order != 0) { + send_update_group_call_participant(input_group_call_id, participant); + } + } + return participant.user_id; } } diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index b82a5f9da..7dc86174e 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -144,7 +144,8 @@ class GroupCallManager : public Actor { void on_group_call_recent_speakers_updated(const GroupCall *group_call, GroupCallRecentSpeakers *recent_speakers); - UserId get_group_call_participant_by_source(InputGroupCallId input_group_call_id, int32 source); + UserId set_group_call_participant_is_speaking_by_source(InputGroupCallId input_group_call_id, int32 source, + bool is_speaking, int32 date); static Result> get_group_call_join_response_object( string json_response); From c63da4b2416a6c4a26138a167e706ac3374626be Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 15 Dec 2020 12:41:26 +0300 Subject: [PATCH 04/23] Add group call participants syncronization. --- td/telegram/GroupCallManager.cpp | 138 +++++++++++++++++++++++++++---- td/telegram/GroupCallManager.h | 4 +- 2 files changed, 123 insertions(+), 19 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 25ae5c7c7..9d70eccd1 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -405,6 +405,7 @@ struct GroupCallManager::GroupCall { bool is_active = false; bool is_joined = false; bool is_speaking = false; + bool syncing_participants = false; bool loaded_all_participants = false; bool mute_new_participants = false; bool allowed_change_mute_new_participants = false; @@ -702,7 +703,7 @@ void GroupCallManager::finish_get_group_call(InputGroupCallId input_group_call_i LOG(ERROR) << "Expected " << input_group_call_id << ", but received " << to_string(result.ok()); result = Status::Error(500, "Receive another group call"); } else { - process_group_call_participants(input_group_call_id, std::move(result.ok_ref()->participants_), true); + process_group_call_participants(input_group_call_id, std::move(result.ok_ref()->participants_), true, false); auto participants_it = group_call_participants_.find(input_group_call_id); if (participants_it != group_call_participants_.end()) { @@ -753,13 +754,32 @@ void GroupCallManager::on_get_group_call_participants( return; } - auto is_empty = participants->participants_.empty(); - process_group_call_participants(input_group_call_id, std::move(participants->participants_), is_load); + bool is_sync = is_load && offset.empty(); + if (is_sync) { + auto group_call = get_group_call(input_group_call_id); + is_sync = group_call->syncing_participants; + if (is_sync) { + group_call->syncing_participants = false; - on_receive_group_call_version(input_group_call_id, participants->version_); + if (group_call->version >= participants->version_) { + LOG(INFO) << "Ignore result of outdated participants sync with version " << participants->version_ << " in " + << input_group_call_id << " from " << group_call->dialog_id << ", because current version is " + << group_call->version; + return; + } + LOG(INFO) << "Finish syncing participants in " << input_group_call_id << " from " << group_call->dialog_id; + group_call->version = participants->version_; + } + } + + auto is_empty = participants->participants_.empty(); + process_group_call_participants(input_group_call_id, std::move(participants->participants_), is_load, is_sync); + + if (!is_sync) { + on_receive_group_call_version(input_group_call_id, participants->version_); + } if (is_load) { - // TODO use count auto participants_it = group_call_participants_.find(input_group_call_id); if (participants_it != group_call_participants_.end()) { CHECK(participants_it->second != nullptr); @@ -768,24 +788,39 @@ void GroupCallManager::on_get_group_call_participants( } } - if (is_empty) { + if (is_empty || is_sync) { bool need_update = false; auto group_call = get_group_call(input_group_call_id); CHECK(group_call != nullptr && group_call->is_inited); - if (!group_call->loaded_all_participants) { + if (is_empty && !group_call->loaded_all_participants) { group_call->loaded_all_participants = true; need_update = true; } - auto real_participant_count = participants_it != group_call_participants_.end() - ? static_cast(participants_it->second->participants.size()) - : 0; + auto real_participant_count = participants->count_; + if (is_empty) { + auto known_participant_count = participants_it != group_call_participants_.end() + ? static_cast(participants_it->second->participants.size()) + : 0; + if (real_participant_count != known_participant_count) { + LOG(ERROR) << "Receive participant count " << real_participant_count << ", but know " + << known_participant_count << " participants in " << input_group_call_id << " from " + << group_call->dialog_id; + real_participant_count = known_participant_count; + } + } if (real_participant_count != group_call->participant_count) { - LOG(ERROR) << "Have participant count " << group_call->participant_count << " instead of " - << real_participant_count << " in " << input_group_call_id; + if (!is_sync) { + LOG(ERROR) << "Have participant count " << group_call->participant_count << " instead of " + << real_participant_count << " in " << input_group_call_id << " from " << group_call->dialog_id; + } group_call->participant_count = real_participant_count; need_update = true; } + if (!is_empty && is_sync && group_call->loaded_all_participants && group_call->participant_count > 50) { + group_call->loaded_all_participants = false; + need_update = true; + } if (need_update) { send_update_group_call(group_call); } @@ -868,7 +903,7 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup group_call->version = version; diff += process_group_call_participants_from_updates(input_group_call_id, std::move(participants)); pending_updates.erase(it); - } else { + } else if (!group_call->syncing_participants) { // found a gap sync_participants_timeout_.add_timeout_in(group_call->group_call_id.get(), 1.0); break; @@ -899,17 +934,51 @@ void GroupCallManager::sync_group_call_participants(InputGroupCallId input_group sync_participants_timeout_.cancel_timeout(group_call->group_call_id.get()); + if (group_call->syncing_participants) { + return; + } + group_call->syncing_participants = true; + LOG(INFO) << "Force participants synchronization in " << input_group_call_id; - // TODO + auto promise = PromiseCreator::lambda([actor_id = actor_id(this), input_group_call_id](Result &&result) { + if (result.is_error()) { + send_closure(actor_id, &GroupCallManager::on_sync_group_call_participants_failed, input_group_call_id); + } + }); + td_->create_handler(std::move(promise))->send(input_group_call_id, string(), 100); +} + +void GroupCallManager::on_sync_group_call_participants_failed(InputGroupCallId input_group_call_id) { + if (G()->close_flag() || !need_group_call_participants(input_group_call_id)) { + return; + } + + auto group_call = get_group_call(input_group_call_id); + CHECK(group_call != nullptr && group_call->is_inited); + CHECK(group_call->syncing_participants); + group_call->syncing_participants = false; + + sync_participants_timeout_.add_timeout_in(group_call->group_call_id.get(), 1.0); } void GroupCallManager::process_group_call_participants( InputGroupCallId input_group_call_id, vector> &&participants, - bool is_load) { + bool is_load, bool is_sync) { if (!need_group_call_participants(input_group_call_id)) { return; } + std::unordered_set old_participant_user_ids; + if (is_sync) { + auto participants_it = group_call_participants_.find(input_group_call_id); + if (participants_it != group_call_participants_.end()) { + CHECK(participants_it->second != nullptr); + for (auto &participant : participants_it->second->participants) { + old_participant_user_ids.insert(participant.user_id); + } + } + } + int64 min_order = std::numeric_limits::max(); for (auto &participant : participants) { GroupCallParticipant group_call_participant(participant); @@ -925,14 +994,44 @@ void GroupCallManager::process_group_call_participants( } else { min_order = real_order; } - process_group_call_participant(input_group_call_id, GroupCallParticipant(participant)); + if (is_sync) { + old_participant_user_ids.erase(group_call_participant.user_id); + } + process_group_call_participant(input_group_call_id, std::move(group_call_participant)); + } + if (is_sync) { + auto participants_it = group_call_participants_.find(input_group_call_id); + if (participants_it != group_call_participants_.end()) { + CHECK(participants_it->second != nullptr); + auto &group_participants = participants_it->second->participants; + for (auto participant_it = group_participants.begin(); participant_it != group_participants.end();) { + auto &participant = *participant_it; + if (old_participant_user_ids.count(participant.user_id) == 0) { + CHECK(participant.order == 0 || participant.order >= min_order); + ++participant_it; + continue; + } + + // not synced user, needs to be deleted + if (participant.order != 0) { + CHECK(participant.order >= participants_it->second->min_order); + participant.order = 0; + send_update_group_call_participant(input_group_call_id, participant); + } + participant_it = group_participants.erase(participant_it); + } + if (participants_it->second->min_order < min_order) { + // if previously known more users, adjust min_order + participants_it->second->min_order = min_order; + } + } } if (is_load) { auto participants_it = group_call_participants_.find(input_group_call_id); if (participants_it != group_call_participants_.end()) { CHECK(participants_it->second != nullptr); - if (participants_it->second->min_order > min_order) { - auto old_min_order = participants_it->second->min_order; + auto old_min_order = participants_it->second->min_order; + if (old_min_order > min_order) { participants_it->second->min_order = min_order; for (auto &participant : participants_it->second->participants) { @@ -1577,6 +1676,9 @@ void GroupCallManager::on_receive_group_call_version(InputGroupCallId input_grou if (version <= group_call->version) { return; } + if (group_call->syncing_participants) { + return; + } // found a gap auto &group_call_participants = group_call_participants_[input_group_call_id]; diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 7dc86174e..e3b27b61e 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -123,9 +123,11 @@ class GroupCallManager : public Actor { void sync_group_call_participants(InputGroupCallId input_group_call_id); + void on_sync_group_call_participants_failed(InputGroupCallId input_group_call_id); + void process_group_call_participants(InputGroupCallId group_call_id, vector> &&participants, - bool is_load); + bool is_load, bool is_sync); int32 process_group_call_participants_from_updates( InputGroupCallId group_call_id, vector> &&participants); From 5268f83538082bd31cbb58746f752fca6150e973 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 15 Dec 2020 13:10:29 +0300 Subject: [PATCH 05/23] Increase chat/channel cache version to reload has_voice_chat flags. --- td/generate/scheme/td_api.tl | 2 +- td/telegram/ContactsManager.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 8a1e55ebd..946190b98 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4365,7 +4365,7 @@ createVoiceChat chat_id:int53 = GroupCallId; //@description Returns information about a group call @group_call_id Group call identifier getGroupCall group_call_id:int32 = GroupCall; -//@description Joins a group call @group_call_id Group call identifier @payload Group join payload, received from tgcalls @source Caller synchronization source identifier; received from tgcalls @is_muted True, if the user's microphone is muted +//@description Joins a group call @group_call_id Group call identifier @payload Group join payload, received from tgcalls. Use null to cancel previous joinGroupCall request @source Caller synchronization source identifier; received from tgcalls @is_muted True, if the user's microphone is muted joinGroupCall group_call_id:int32 payload:groupCallPayload source:int32 is_muted:Bool = GroupCallJoinResponse; //@description Toggles whether new participants of a group call can be unmuted only by administrators of the group call. Requires can_manage_voice_chats rights in the corresponding chat and allowed_change_mute_mew_participants group call flag diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index 9db99e799..79d94ec1e 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -717,7 +717,7 @@ class ContactsManager : public Actor { DialogParticipantStatus status = DialogParticipantStatus::Banned(0); RestrictedRights default_permissions{false, false, false, false, false, false, false, false, false, false, false}; - static constexpr uint32 CACHE_VERSION = 2; + static constexpr uint32 CACHE_VERSION = 3; uint32 cache_version = 0; bool is_active = false; @@ -784,7 +784,7 @@ class ContactsManager : public Actor { int32 date = 0; int32 participant_count = 0; - static constexpr uint32 CACHE_VERSION = 5; + static constexpr uint32 CACHE_VERSION = 6; uint32 cache_version = 0; bool has_linked_channel = false; From c73fc717441b3a8ece95d8c918869f8d038e05da Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 15 Dec 2020 13:28:41 +0300 Subject: [PATCH 06/23] Simplify promo data expires_in handling. --- td/telegram/Td.cpp | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index c81aa106e..615e9be9a 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -3232,17 +3232,17 @@ void Td::on_get_promo_data(Resultget_id()) { case telegram_api::help_promoDataEmpty::ID: { auto promo = telegram_api::move_object_as(promo_data_ptr); - expires = promo->expires_; + expires_at = promo->expires_; messages_manager_->remove_sponsored_dialog(); break; } case telegram_api::help_promoData::ID: { auto promo = telegram_api::move_object_as(promo_data_ptr); - expires = promo->expires_; + expires_at = promo->expires_; bool is_proxy = (promo->flags_ & telegram_api::help_promoData::PROXY_MASK) != 0; messages_manager_->on_get_sponsored_dialog( std::move(promo->peer_), @@ -3254,23 +3254,11 @@ void Td::on_get_promo_data(Resultunix_time(); - } - schedule_get_promo_data(expires); + schedule_get_promo_data(expires_at == 0 ? 0 : expires_at - G()->unix_time()); } void Td::schedule_get_promo_data(int32 expires_in) { - if (expires_in < 0) { - LOG(ERROR) << "Receive wrong expires_in: " << expires_in; - expires_in = 0; - } - if (expires_in != 0 && expires_in < 60) { - expires_in = 60; - } - if (expires_in > 86400) { - expires_in = 86400; - } + expires_in = clamp(expires_in, 60, 86400); if (!close_flag_ && auth_manager_->is_authorized() && !auth_manager_->is_bot()) { LOG(INFO) << "Schedule getPromoData in " << expires_in; alarm_timeout_.set_timeout_in(PROMO_DATA_ALARM_ID, expires_in); From 42f36d2d66eabf167658ca5557dbabdc92ad0bed Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 15 Dec 2020 13:40:04 +0300 Subject: [PATCH 07/23] Improve loadGroupCallPartiicpants documentation. --- td/generate/scheme/td_api.tl | 4 +++- td/telegram/GroupCallManager.cpp | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 946190b98..867684bc6 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4387,7 +4387,9 @@ toggleGroupCallParticipantIsMuted group_call_id:int32 user_id:int32 is_muted:Boo //@description Checks whether a group call is still joined. Should be called every 10 seconds when tgcalls notifies about lost connection with the server @group_call_id Group call identifier checkGroupCallIsJoined group_call_id:int32 = Ok; -//@description Loads more group call participants. The loaded participants will be received through updates @group_call_id Group call identifier @limit Maximum number of participants to load +//@description Loads more group call participants. The loaded participants will be received through updates. Use the field groupCall.loaded_all_participants to check whether all participants has already been loaded +//@group_call_id Group call identifier. The group call must be previously received through getGroupCall and must be joined or being joined +//@limit Maximum number of participants to load loadGroupCallParticipants group_call_id:int32 limit:int32 = Ok; //@description Leaves a group call @group_call_id Group call identifier diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 9d70eccd1..904b6c504 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1465,6 +1465,9 @@ void GroupCallManager::load_group_call_participants(GroupCallId group_call_id, i } auto *group_call = get_group_call(input_group_call_id); CHECK(group_call != nullptr && group_call->is_inited); + if (group_call->loaded_all_participants) { + return promise.set_value(Unit()); + } string next_offset; auto participants_it = group_call_participants_.find(input_group_call_id); From b4e087a2f08706b91b5f6f8e0ecd0cd78d89162a Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 15 Dec 2020 14:04:06 +0300 Subject: [PATCH 08/23] Remove users from recent speakers when they leave the call. --- td/telegram/GroupCallManager.cpp | 25 +++++++++++++++++++++++++ td/telegram/GroupCallManager.h | 2 ++ 2 files changed, 27 insertions(+) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 904b6c504..2cb0b371d 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1079,6 +1079,7 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou if (old_participant.order != 0) { send_update_group_call_participant(input_group_call_id, participant); } + remove_recent_group_call_speaker(input_group_call_id, participant.user_id); participants->participants.erase(participants->participants.begin() + i); return -1; } @@ -1112,6 +1113,7 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou if (participant.joined_date == 0) { // unknown removed participant + remove_recent_group_call_speaker(input_group_call_id, participant.user_id); return -1; } @@ -1768,6 +1770,29 @@ void GroupCallManager::on_user_speaking_in_group_call(GroupCallId group_call_id, on_group_call_recent_speakers_updated(group_call, recent_speakers.get()); } +void GroupCallManager::remove_recent_group_call_speaker(InputGroupCallId input_group_call_id, UserId user_id) { + auto *group_call = get_group_call(input_group_call_id); + if (group_call != nullptr && group_call->is_inited && !group_call->is_active) { + return; + } + + auto recent_speakers_it = group_call_recent_speakers_.find(group_call->group_call_id); + if (recent_speakers_it == group_call_recent_speakers_.end()) { + return; + } + auto &recent_speakers = recent_speakers_it->second; + CHECK(recent_speakers != nullptr); + for (size_t i = 0; i < recent_speakers->users.size(); i++) { + if (recent_speakers->users[i].first == user_id) { + LOG(INFO) << "Remove " << user_id << " from recent speakers in " << input_group_call_id << " from " + << group_call->dialog_id; + recent_speakers->users.erase(recent_speakers->users.begin() + i); + on_group_call_recent_speakers_updated(group_call, recent_speakers.get()); + return; + } + } +} + void GroupCallManager::on_group_call_recent_speakers_updated(const GroupCall *group_call, GroupCallRecentSpeakers *recent_speakers) { if (group_call == nullptr || !group_call->is_inited || recent_speakers->is_changed) { diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index e3b27b61e..fee2e18a2 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -144,6 +144,8 @@ class GroupCallManager : public Actor { void on_receive_group_call_version(InputGroupCallId input_group_call_id, int32 version); + void remove_recent_group_call_speaker(InputGroupCallId input_group_call_id, UserId user_id); + void on_group_call_recent_speakers_updated(const GroupCall *group_call, GroupCallRecentSpeakers *recent_speakers); UserId set_group_call_participant_is_speaking_by_source(InputGroupCallId input_group_call_id, int32 source, From db99c9817d7c935eb867b00d5dd172b0fa1c8e2c Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 15 Dec 2020 14:32:08 +0300 Subject: [PATCH 09/23] Fix group call updating after initialization. --- td/telegram/GroupCallManager.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 2cb0b371d..0b9981455 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1648,13 +1648,13 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrdialog_id.is_valid()) { - td_->messages_manager_->on_update_dialog_group_call(group_call->dialog_id, true, - group_call->participant_count == 0); - } } } } + if (group_call->is_active && group_call->dialog_id.is_valid()) { + td_->messages_manager_->on_update_dialog_group_call(group_call->dialog_id, true, + group_call->participant_count == 0); + } if (!group_call->is_active && group_call_recent_speakers_.erase(group_call->group_call_id) != 0) { need_update = true; } From 1c02363418ccabb2eb8eac863148f49b6368d221 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 15 Dec 2020 14:54:47 +0300 Subject: [PATCH 10/23] Update recent speakers by updateGroupParticipants. --- td/telegram/GroupCallManager.cpp | 16 ++++++++++++++++ td/telegram/GroupCallManager.h | 3 +++ 2 files changed, 19 insertions(+) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 0b9981455..970971aae 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1106,6 +1106,7 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou if (need_update) { send_update_group_call_participant(input_group_call_id, old_participant); } + on_participant_speaking_in_group_call(input_group_call_id, participant); } return 0; } @@ -1128,6 +1129,7 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou if (participants->participants.back().order != 0) { send_update_group_call_participant(input_group_call_id, participants->participants.back()); } + on_participant_speaking_in_group_call(input_group_call_id, participants->participants.back()); return diff; } @@ -1694,6 +1696,20 @@ void GroupCallManager::on_receive_group_call_version(InputGroupCallId input_grou sync_participants_timeout_.add_timeout_in(group_call->group_call_id.get(), 1.0); } +void GroupCallManager::on_participant_speaking_in_group_call(InputGroupCallId input_group_call_id, + const GroupCallParticipant &participant) { + if (participant.active_date < G()->unix_time() - RECENT_SPEAKER_TIMEOUT) { + return; + } + + auto *group_call = get_group_call(input_group_call_id); + if (group_call == nullptr) { + return; + } + + on_user_speaking_in_group_call(group_call->group_call_id, participant.user_id, participant.active_date, true); +} + void GroupCallManager::on_user_speaking_in_group_call(GroupCallId group_call_id, UserId user_id, int32 date, bool recursive) { if (G()->close_flag()) { diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index fee2e18a2..64273f889 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -144,6 +144,9 @@ class GroupCallManager : public Actor { void on_receive_group_call_version(InputGroupCallId input_group_call_id, int32 version); + void on_participant_speaking_in_group_call(InputGroupCallId input_group_call_id, + const GroupCallParticipant &participant); + void remove_recent_group_call_speaker(InputGroupCallId input_group_call_id, UserId user_id); void on_group_call_recent_speakers_updated(const GroupCall *group_call, GroupCallRecentSpeakers *recent_speakers); From ecc1669e5a271e32ec3383798d92fa54824ac161 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 15 Dec 2020 15:17:53 +0300 Subject: [PATCH 11/23] Update recent speakers by received in getGroupCall participants. --- td/telegram/GroupCallManager.cpp | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 970971aae..b9486bf85 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -702,16 +702,6 @@ void GroupCallManager::finish_get_group_call(InputGroupCallId input_group_call_i if (update_group_call(result.ok()->call_, DialogId()) != input_group_call_id) { LOG(ERROR) << "Expected " << input_group_call_id << ", but received " << to_string(result.ok()); result = Status::Error(500, "Receive another group call"); - } else { - process_group_call_participants(input_group_call_id, std::move(result.ok_ref()->participants_), true, false); - - auto participants_it = group_call_participants_.find(input_group_call_id); - if (participants_it != group_call_participants_.end()) { - CHECK(participants_it->second != nullptr); - if (participants_it->second->next_offset.empty()) { - participants_it->second->next_offset = std::move(result.ok_ref()->participants_next_offset_); - } - } } } @@ -722,6 +712,18 @@ void GroupCallManager::finish_get_group_call(InputGroupCallId input_group_call_i return; } + auto call = result.move_as_ok(); + process_group_call_participants(input_group_call_id, std::move(call->participants_), true, false); + if (need_group_call_participants(input_group_call_id)) { + auto participants_it = group_call_participants_.find(input_group_call_id); + if (participants_it != group_call_participants_.end()) { + CHECK(participants_it->second != nullptr); + if (participants_it->second->next_offset.empty()) { + participants_it->second->next_offset = std::move(call->participants_next_offset_); + } + } + } + auto group_call = get_group_call(input_group_call_id); for (auto &promise : promises) { promise.set_value(get_group_call_object(group_call, get_recent_speaker_user_ids(group_call, false))); @@ -965,6 +967,15 @@ void GroupCallManager::process_group_call_participants( InputGroupCallId input_group_call_id, vector> &&participants, bool is_load, bool is_sync) { if (!need_group_call_participants(input_group_call_id)) { + for (auto &participant : participants) { + GroupCallParticipant group_call_participant(participant); + if (!group_call_participant.is_valid()) { + LOG(ERROR) << "Receive invalid " << to_string(participant); + continue; + } + + on_participant_speaking_in_group_call(input_group_call_id, group_call_participant); + } return; } From adca19d4da641e5cb0072e2c016dedd94976fdc6 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 15 Dec 2020 15:40:52 +0300 Subject: [PATCH 12/23] Fix group call version initialization. --- td/telegram/GroupCallManager.cpp | 9 +++++++++ td/telegram/MessagesManager.cpp | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index b9486bf85..0956012ab 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1624,6 +1624,15 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptris_inited) { *group_call = std::move(call); + if (need_group_call_participants(input_group_call_id)) { + // init version + group_call->version = call.version; + if (process_pending_group_call_participant_updates(input_group_call_id)) { + need_update = false; + } + } else { + group_call->version = -1; + } need_update = true; } else { if (!group_call->is_active) { diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 9a8e9519f..ba6389885 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -7970,6 +7970,7 @@ void MessagesManager::remove_dialog_action_bar(DialogId dialog_id, Promise void MessagesManager::repair_dialog_active_group_call_id(DialogId dialog_id) { if (have_input_peer(dialog_id, AccessRights::Read)) { + LOG(INFO) << "Repair active voice chat ID in " << dialog_id; create_actor("RepairChatActiveVoiceChatId", 1.0, PromiseCreator::lambda([actor_id = actor_id(this), dialog_id](Result result) { send_closure(actor_id, &MessagesManager::do_repair_dialog_active_group_call_id, @@ -28977,9 +28978,13 @@ void MessagesManager::on_update_dialog_group_call(DialogId dialog_id, bool has_a return; } + LOG(INFO) << "Update voice chat in " << dialog_id << " with has_active_voice_chat = " << has_active_group_call + << " and is_voice_chat_empty = " << is_group_call_empty; + CHECK(dialog_id.is_valid()); Dialog *d = get_dialog(dialog_id); // must not create the Dialog, because is called from on_get_chat if (d == nullptr) { + LOG(INFO) << "Can't find " << dialog_id; pending_dialog_group_call_updates_[dialog_id] = {has_active_group_call, is_group_call_empty}; return; } @@ -28988,6 +28993,7 @@ void MessagesManager::on_update_dialog_group_call(DialogId dialog_id, bool has_a is_group_call_empty = false; } if (d->has_active_group_call == has_active_group_call && d->is_group_call_empty == is_group_call_empty) { + LOG(INFO) << "Nothing changed in " << dialog_id; return; } From 0d76d53cd551d5df763f542e791c8ce4d90c7970 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 15 Dec 2020 16:06:21 +0300 Subject: [PATCH 13/23] Process updateGroupCallParticipant even don't need participant list. --- td/telegram/GroupCallManager.cpp | 67 ++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 11 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 0956012ab..4099288ab 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -732,7 +732,7 @@ void GroupCallManager::finish_get_group_call(InputGroupCallId input_group_call_i bool GroupCallManager::need_group_call_participants(InputGroupCallId input_group_call_id) const { auto *group_call = get_group_call(input_group_call_id); - if (group_call == nullptr || !group_call->is_inited) { + if (group_call == nullptr || !group_call->is_inited || !group_call->is_active) { return false; } if (group_call->is_joined) { @@ -818,6 +818,11 @@ void GroupCallManager::on_get_group_call_participants( } group_call->participant_count = real_participant_count; need_update = true; + + if (group_call->dialog_id.is_valid()) { + td_->messages_manager_->on_update_dialog_group_call(group_call->dialog_id, group_call->is_active, + group_call->participant_count == 0); + } } if (!is_empty && is_sync && group_call->loaded_all_participants && group_call->participant_count > 50) { group_call->loaded_all_participants = false; @@ -834,7 +839,38 @@ void GroupCallManager::on_update_group_call_participants( InputGroupCallId input_group_call_id, vector> &&participants, int32 version) { if (!need_group_call_participants(input_group_call_id)) { - LOG(INFO) << "Ignore updateGroupCallParticipants in " << input_group_call_id; + int32 diff = 0; + for (auto &group_call_participant : participants) { + GroupCallParticipant participant(group_call_participant); + if (participant.joined_date == 0) { + diff--; + remove_recent_group_call_speaker(input_group_call_id, participant.user_id); + } else { + if (participant.is_just_joined) { + diff++; + } + on_participant_speaking_in_group_call(input_group_call_id, participant); + } + } + + auto group_call = get_group_call(input_group_call_id); + if (group_call != nullptr && group_call->is_inited && group_call->is_active && group_call->version == -1) { + if (diff != 0 && (group_call->participant_count != 0 || diff > 0)) { + group_call->participant_count += diff; + if (group_call->participant_count < 0) { + LOG(ERROR) << "Participant count became negative in " << input_group_call_id << " from " + << group_call->dialog_id; + group_call->participant_count = 0; + } + if (group_call->dialog_id.is_valid()) { + td_->messages_manager_->on_update_dialog_group_call(group_call->dialog_id, true, + group_call->participant_count == 0); + } + send_update_group_call(group_call); + } + } + + LOG(INFO) << "Ignore updateGroupCallParticipants in " << input_group_call_id << " from " << group_call->dialog_id; return; } if (version <= 0) { @@ -875,7 +911,7 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup auto &pending_updates = participants_it->second->pending_updates_; auto group_call = get_group_call(input_group_call_id); CHECK(group_call != nullptr && group_call->is_inited); - if (group_call->version == -1) { + if (group_call->version == -1 || !group_call->is_active) { return false; } @@ -890,9 +926,10 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup if (participant.user_id == td_->contacts_manager_->get_my_id()) { process_group_call_participant(input_group_call_id, std::move(participant)); } + on_participant_speaking_in_group_call(input_group_call_id, participant); } LOG(INFO) << "Ignore already applied updateGroupCallParticipants with version " << version << " in " - << input_group_call_id; + << input_group_call_id << " from " << group_call->dialog_id; pending_updates.erase(it); continue; } @@ -917,10 +954,14 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup if (diff != 0 && (group_call->participant_count != 0 || diff > 0)) { group_call->participant_count += diff; if (group_call->participant_count < 0) { - LOG(ERROR) << "Participant count became negative in " << input_group_call_id; + LOG(ERROR) << "Participant count became negative in " << input_group_call_id << " from " << group_call->dialog_id; group_call->participant_count = 0; } send_update_group_call(group_call); + if (group_call->dialog_id.is_valid()) { + td_->messages_manager_->on_update_dialog_group_call(group_call->dialog_id, true, + group_call->participant_count == 0); + } return true; } return false; @@ -941,7 +982,7 @@ void GroupCallManager::sync_group_call_participants(InputGroupCallId input_group } group_call->syncing_participants = true; - LOG(INFO) << "Force participants synchronization in " << input_group_call_id; + LOG(INFO) << "Force participants synchronization in " << input_group_call_id << " from " << group_call->dialog_id; auto promise = PromiseCreator::lambda([actor_id = actor_id(this), input_group_call_id](Result &&result) { if (result.is_error()) { send_closure(actor_id, &GroupCallManager::on_sync_group_call_participants_failed, input_group_call_id); @@ -1413,7 +1454,8 @@ void GroupCallManager::set_group_call_participant_is_speaking(GroupCallId group_ td_->create_handler(std::move(query_promise)) ->send(input_group_call_id, {}, {source}); } else { - LOG(INFO) << "Failed to find participant with source " << source << " in " << group_call_id; + LOG(INFO) << "Failed to find participant with source " << source << " in " << group_call_id << " from " + << group_call->dialog_id; promise.set_value(Unit()); } return; @@ -1542,7 +1584,7 @@ void GroupCallManager::on_update_group_call(tl_object_ptris_inited || recent_speakers->is_changed) { - LOG(INFO) << "Don't need to send update of recent speakers in " << group_call->group_call_id; + LOG(INFO) << "Don't need to send update of recent speakers in " << group_call->group_call_id << " from " + << group_call->dialog_id; return; } recent_speakers->is_changed = true; - LOG(INFO) << "Schedule update of recent speakers in " << group_call->group_call_id; + LOG(INFO) << "Schedule update of recent speakers in " << group_call->group_call_id << " from " + << group_call->dialog_id; const double MAX_RECENT_SPEAKER_UPDATE_DELAY = 0.5; recent_speaker_update_timeout_.set_timeout_in(group_call->group_call_id.get(), MAX_RECENT_SPEAKER_UPDATE_DELAY); } @@ -1883,7 +1927,8 @@ vector GroupCallManager::get_recent_speaker_user_ids(const GroupCall *gro auto *recent_speakers = recent_speakers_it->second.get(); CHECK(recent_speakers != nullptr); - LOG(INFO) << "Found " << recent_speakers->users.size() << " recent speakers in " << group_call->group_call_id; + LOG(INFO) << "Found " << recent_speakers->users.size() << " recent speakers in " << group_call->group_call_id + << " from " << group_call->dialog_id; while (!recent_speakers->users.empty() && recent_speakers->users.back().second < G()->unix_time() - RECENT_SPEAKER_TIMEOUT) { recent_speakers->users.pop_back(); From 25d1fde98530868a43ae65f2876d74a37bb7530c Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 15 Dec 2020 16:18:43 +0300 Subject: [PATCH 14/23] Add source to send_update_group_call. --- td/telegram/GroupCallManager.cpp | 21 +++++++++++++-------- td/telegram/GroupCallManager.h | 2 +- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 4099288ab..47c8cf52c 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -829,7 +829,7 @@ void GroupCallManager::on_get_group_call_participants( need_update = true; } if (need_update) { - send_update_group_call(group_call); + send_update_group_call(group_call, "on_get_group_call_participants"); } } } @@ -866,7 +866,7 @@ void GroupCallManager::on_update_group_call_participants( td_->messages_manager_->on_update_dialog_group_call(group_call->dialog_id, true, group_call->participant_count == 0); } - send_update_group_call(group_call); + send_update_group_call(group_call, "on_update_group_call_participants"); } } @@ -934,6 +934,8 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup continue; } if (version < group_call->version + static_cast(participants.size())) { + LOG(INFO) << "Receive " << participants.size() << " group call participant updates with version " << version + << ", but current version is " << group_call->version; sync_group_call_participants(input_group_call_id); break; } @@ -944,6 +946,8 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup pending_updates.erase(it); } else if (!group_call->syncing_participants) { // found a gap + LOG(INFO) << "Receive " << participants.size() << " group call participant updates with version " << version + << ", but current version is " << group_call->version; sync_participants_timeout_.add_timeout_in(group_call->group_call_id.get(), 1.0); break; } @@ -957,7 +961,7 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup LOG(ERROR) << "Participant count became negative in " << input_group_call_id << " from " << group_call->dialog_id; group_call->participant_count = 0; } - send_update_group_call(group_call); + send_update_group_call(group_call, "process_pending_group_call_participant_updates"); if (group_call->dialog_id.is_valid()) { td_->messages_manager_->on_update_dialog_group_call(group_call->dialog_id, true, group_call->participant_count == 0); @@ -1562,7 +1566,7 @@ void GroupCallManager::on_group_call_left(InputGroupCallId input_group_call_id, group_call->is_joined = false; group_call->is_speaking = false; group_call->source = 0; - send_update_group_call(group_call); + send_update_group_call(group_call, "on_group_call_left"); try_clear_group_call_participants(input_group_call_id); } @@ -1607,7 +1611,7 @@ void GroupCallManager::try_clear_group_call_participants(InputGroupCallId input_ CHECK(group_call != nullptr && group_call->is_inited); if (group_call->loaded_all_participants) { group_call->loaded_all_participants = false; - send_update_group_call(group_call); + send_update_group_call(group_call, "try_clear_group_call_participants"); } group_call->version = -1; @@ -1726,7 +1730,7 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptr GroupCallManager::get_recent_speaker_user_ids(const GroupCall *gro if (!for_update) { // the change must be received through update first - send_update_group_call(group_call); + send_update_group_call(group_call, "get_recent_speaker_user_ids"); } } return recent_speaker_user_ids; @@ -1981,7 +1985,8 @@ tl_object_ptr GroupCallManager::get_update_g group_call_id.get(), participant.get_group_call_participant_object(td_->contacts_manager_.get())); } -void GroupCallManager::send_update_group_call(const GroupCall *group_call) { +void GroupCallManager::send_update_group_call(const GroupCall *group_call, const char *source) { + LOG(INFO) << "Send update about " << group_call->group_call_id << " from " << source; send_closure(G()->td(), &Td::send_update, get_update_group_call_object(group_call, get_recent_speaker_user_ids(group_call, true))); } diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 64273f889..d1e1b8762 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -170,7 +170,7 @@ class GroupCallManager : public Actor { tl_object_ptr get_update_group_call_participant_object( GroupCallId group_call_id, const GroupCallParticipant &participant); - void send_update_group_call(const GroupCall *group_call); + void send_update_group_call(const GroupCall *group_call, const char *source); void send_update_group_call_participant(GroupCallId group_call_id, const GroupCallParticipant &participant); From f95366a219498b2a447aa7bdad0cb2b57a441878 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 15 Dec 2020 17:06:11 +0300 Subject: [PATCH 15/23] Leave group call when receive corresponding update. --- td/telegram/GroupCallManager.cpp | 64 ++++++++++++++++++++++---------- td/telegram/GroupCallManager.h | 5 +-- 2 files changed, 46 insertions(+), 23 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 47c8cf52c..1e98afd43 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -840,8 +840,16 @@ void GroupCallManager::on_update_group_call_participants( int32 version) { if (!need_group_call_participants(input_group_call_id)) { int32 diff = 0; + bool need_update = false; + auto group_call = get_group_call(input_group_call_id); for (auto &group_call_participant : participants) { GroupCallParticipant participant(group_call_participant); + if (participant.user_id == td_->contacts_manager_->get_my_id() && group_call != nullptr && + group_call->is_inited && group_call->is_joined && + (participant.joined_date == 0) == (participant.source == group_call->source)) { + on_group_call_left_impl(group_call); + need_update = true; + } if (participant.joined_date == 0) { diff--; remove_recent_group_call_speaker(input_group_call_id, participant.user_id); @@ -853,7 +861,6 @@ void GroupCallManager::on_update_group_call_participants( } } - auto group_call = get_group_call(input_group_call_id); if (group_call != nullptr && group_call->is_inited && group_call->is_active && group_call->version == -1) { if (diff != 0 && (group_call->participant_count != 0 || diff > 0)) { group_call->participant_count += diff; @@ -866,9 +873,12 @@ void GroupCallManager::on_update_group_call_participants( td_->messages_manager_->on_update_dialog_group_call(group_call->dialog_id, true, group_call->participant_count == 0); } - send_update_group_call(group_call, "on_update_group_call_participants"); + need_update = true; } } + if (need_update) { + send_update_group_call(group_call, "on_update_group_call_participants"); + } LOG(INFO) << "Ignore updateGroupCallParticipants in " << input_group_call_id << " from " << group_call->dialog_id; return; @@ -916,6 +926,7 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup } int32 diff = 0; + bool is_left = false; while (!pending_updates.empty()) { auto it = pending_updates.begin(); auto version = it->first; @@ -942,7 +953,14 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup if (version == group_call->version + static_cast(participants.size())) { group_call->version = version; - diff += process_group_call_participants_from_updates(input_group_call_id, std::move(participants)); + for (auto &participant : participants) { + GroupCallParticipant group_call_participant(participant); + if (group_call_participant.user_id == td_->contacts_manager_->get_my_id() && group_call->is_joined && + (group_call_participant.joined_date == 0) == (group_call_participant.source == group_call->source)) { + is_left = true; + } + diff += process_group_call_participant(input_group_call_id, std::move(group_call_participant)); + } pending_updates.erase(it); } else if (!group_call->syncing_participants) { // found a gap @@ -955,20 +973,29 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup if (pending_updates.empty()) { sync_participants_timeout_.cancel_timeout(group_call->group_call_id.get()); } + + bool need_update = false; if (diff != 0 && (group_call->participant_count != 0 || diff > 0)) { group_call->participant_count += diff; if (group_call->participant_count < 0) { LOG(ERROR) << "Participant count became negative in " << input_group_call_id << " from " << group_call->dialog_id; group_call->participant_count = 0; } - send_update_group_call(group_call, "process_pending_group_call_participant_updates"); + need_update = true; if (group_call->dialog_id.is_valid()) { td_->messages_manager_->on_update_dialog_group_call(group_call->dialog_id, true, group_call->participant_count == 0); } - return true; } - return false; + if (is_left && group_call->is_joined) { + on_group_call_left_impl(group_call); + need_update = true; + } + if (need_update) { + send_update_group_call(group_call, "process_pending_group_call_participant_updates"); + } + + return need_update; } void GroupCallManager::sync_group_call_participants(InputGroupCallId input_group_call_id) { @@ -1103,15 +1130,6 @@ void GroupCallManager::process_group_call_participants( } } -int32 GroupCallManager::process_group_call_participants_from_updates( - InputGroupCallId input_group_call_id, vector> &&participants) { - int32 diff = 0; - for (auto &participant : participants) { - diff += process_group_call_participant(input_group_call_id, GroupCallParticipant(participant)); - } - return diff; -} - int GroupCallManager::process_group_call_participant(InputGroupCallId input_group_call_id, GroupCallParticipant &&participant) { if (!participant.is_valid()) { @@ -1552,6 +1570,7 @@ void GroupCallManager::leave_group_call(GroupCallId group_call_id, Promise auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), input_group_call_id, source, promise = std::move(promise)](Result &&result) mutable { if (result.is_ok()) { + // just in case send_closure(actor_id, &GroupCallManager::on_group_call_left, input_group_call_id, source); } promise.set_result(std::move(result)); @@ -1563,15 +1582,20 @@ void GroupCallManager::on_group_call_left(InputGroupCallId input_group_call_id, auto *group_call = get_group_call(input_group_call_id); CHECK(group_call != nullptr && group_call->is_inited); if (group_call->is_joined && group_call->source == source) { - group_call->is_joined = false; - group_call->is_speaking = false; - group_call->source = 0; + on_group_call_left_impl(group_call); send_update_group_call(group_call, "on_group_call_left"); - - try_clear_group_call_participants(input_group_call_id); } } +void GroupCallManager::on_group_call_left_impl(GroupCall *group_call) { + CHECK(group_call != nullptr && group_call->is_inited && group_call->is_joined); + group_call->is_joined = false; + group_call->is_speaking = false; + group_call->source = 0; + group_call->loaded_all_participants = false; + try_clear_group_call_participants(get_input_group_call_id(group_call->group_call_id).ok()); +} + void GroupCallManager::discard_group_call(GroupCallId group_call_id, Promise &&promise) { TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id)); td_->create_handler(std::move(promise))->send(input_group_call_id); diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index d1e1b8762..b2f38a8a9 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -129,9 +129,6 @@ class GroupCallManager : public Actor { vector> &&participants, bool is_load, bool is_sync); - int32 process_group_call_participants_from_updates( - InputGroupCallId group_call_id, vector> &&participants); - int process_group_call_participant(InputGroupCallId group_call_id, GroupCallParticipant &&participant); bool on_join_group_call_response(InputGroupCallId input_group_call_id, string json_response); @@ -140,6 +137,8 @@ class GroupCallManager : public Actor { void on_group_call_left(InputGroupCallId input_group_call_id, int32 source); + void on_group_call_left_impl(GroupCall *group_call); + InputGroupCallId update_group_call(const tl_object_ptr &group_call_ptr, DialogId dialog_id); void on_receive_group_call_version(InputGroupCallId input_group_call_id, int32 version); From d022dfdb6212759c25bdf6ad5bb2b7e541fee3a1 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 15 Dec 2020 18:20:44 +0300 Subject: [PATCH 16/23] Add GroupCallManager::can_manage_group_calls method. --- td/telegram/GroupCallManager.cpp | 79 +++++++++++++++++++------------- td/telegram/GroupCallManager.h | 2 + 2 files changed, 48 insertions(+), 33 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 1e98afd43..d34486206 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -591,6 +591,46 @@ GroupCallManager::GroupCall *GroupCallManager::get_group_call(InputGroupCallId i } } +Status GroupCallManager::can_manage_group_calls(DialogId dialog_id) { + switch (dialog_id.get_type()) { + case DialogType::Chat: { + auto chat_id = dialog_id.get_chat_id(); + if (!td_->contacts_manager_->get_chat_permissions(chat_id).can_manage_calls()) { + return Status::Error(400, "Not enough rights in the chat"); + } + break; + } + case DialogType::Channel: { + auto channel_id = dialog_id.get_channel_id(); + switch (td_->contacts_manager_->get_channel_type(channel_id)) { + case ChannelType::Unknown: + return Status::Error(400, "Chat info not found"); + case ChannelType::Megagroup: + // OK + break; + case ChannelType::Broadcast: + return Status::Error(400, "Chat is not a group"); + default: + UNREACHABLE(); + break; + } + if (!td_->contacts_manager_->get_channel_permissions(channel_id).can_manage_calls()) { + return Status::Error(400, "Not enough rights in the chat"); + } + break; + } + case DialogType::User: + case DialogType::SecretChat: + return Status::Error(400, "Chat can't have a voice chat"); + case DialogType::None: + // OK + break; + default: + UNREACHABLE(); + } + return Status::OK(); +} + void GroupCallManager::create_voice_chat(DialogId dialog_id, Promise &&promise) { if (!dialog_id.is_valid()) { return promise.set_error(Status::Error(400, "Invalid chat identifier specified")); @@ -602,39 +642,7 @@ void GroupCallManager::create_voice_chat(DialogId dialog_id, Promisecontacts_manager_->get_chat_permissions(chat_id).can_manage_calls()) { - return promise.set_error(Status::Error(400, "Not enough rights in the chat")); - } - break; - } - case DialogType::Channel: { - auto channel_id = dialog_id.get_channel_id(); - switch (td_->contacts_manager_->get_channel_type(channel_id)) { - case ChannelType::Unknown: - return promise.set_error(Status::Error(400, "Chat info not found")); - case ChannelType::Megagroup: - // OK - break; - case ChannelType::Broadcast: - return promise.set_error(Status::Error(400, "Chat is not a group")); - default: - UNREACHABLE(); - break; - } - if (!td_->contacts_manager_->get_channel_permissions(channel_id).can_manage_calls()) { - return promise.set_error(Status::Error(400, "Not enough rights in the chat")); - } - break; - } - case DialogType::User: - case DialogType::SecretChat: - return promise.set_error(Status::Error(400, "Chat can't have a voice chat")); - default: - UNREACHABLE(); - } + TRY_STATUS_PROMISE(promise, can_manage_group_calls(dialog_id)); auto query_promise = PromiseCreator::lambda( [actor_id = actor_id(this), dialog_id, promise = std::move(promise)](Result result) mutable { @@ -1503,9 +1511,14 @@ void GroupCallManager::toggle_group_call_participant_is_muted(GroupCallId group_ Promise &&promise) { TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id)); + auto *group_call = get_group_call(input_group_call_id); + if (group_call == nullptr || !group_call->is_inited || !group_call->is_active || !group_call->is_joined) { + return promise.set_error(Status::Error(400, "GROUP_CALL_JOIN_MISSING")); + } if (!td_->contacts_manager_->have_input_user(user_id)) { return promise.set_error(Status::Error(400, "Have no access to the user")); } + td_->create_handler(std::move(promise))->send(input_group_call_id, user_id, is_muted); } diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index b2f38a8a9..6630118c3 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -109,6 +109,8 @@ class GroupCallManager : public Actor { const GroupCall *get_group_call(InputGroupCallId input_group_call_id) const; GroupCall *get_group_call(InputGroupCallId input_group_call_id); + Status can_manage_group_calls(DialogId dialog_id); + void on_voice_chat_created(DialogId dialog_id, InputGroupCallId input_group_call_id, Promise &&promise); void reload_group_call(InputGroupCallId input_group_call_id, From 62dc71cbc5b3b54a8c3b3dfb7ff67a95dce58332 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 15 Dec 2020 19:20:03 +0300 Subject: [PATCH 17/23] Add GroupCallManager::update_group_call_dialog method. --- td/telegram/GroupCallManager.cpp | 36 +++++++++++++++----------------- td/telegram/GroupCallManager.h | 2 ++ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index d34486206..da9210ba3 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -827,10 +827,7 @@ void GroupCallManager::on_get_group_call_participants( group_call->participant_count = real_participant_count; need_update = true; - if (group_call->dialog_id.is_valid()) { - td_->messages_manager_->on_update_dialog_group_call(group_call->dialog_id, group_call->is_active, - group_call->participant_count == 0); - } + update_group_call_dialog(group_call, "on_get_group_call_participants"); } if (!is_empty && is_sync && group_call->loaded_all_participants && group_call->participant_count > 50) { group_call->loaded_all_participants = false; @@ -877,10 +874,7 @@ void GroupCallManager::on_update_group_call_participants( << group_call->dialog_id; group_call->participant_count = 0; } - if (group_call->dialog_id.is_valid()) { - td_->messages_manager_->on_update_dialog_group_call(group_call->dialog_id, true, - group_call->participant_count == 0); - } + update_group_call_dialog(group_call, "on_update_group_call_participants"); need_update = true; } } @@ -990,10 +984,7 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup group_call->participant_count = 0; } need_update = true; - if (group_call->dialog_id.is_valid()) { - td_->messages_manager_->on_update_dialog_group_call(group_call->dialog_id, true, - group_call->participant_count == 0); - } + update_group_call_dialog(group_call, "process_pending_group_call_participant_updates"); } if (is_left && group_call->is_joined) { on_group_call_left_impl(group_call); @@ -1519,6 +1510,10 @@ void GroupCallManager::toggle_group_call_participant_is_muted(GroupCallId group_ return promise.set_error(Status::Error(400, "Have no access to the user")); } + if (user_id != td_->contacts_manager_->get_my_id()) { + TRY_STATUS_PROMISE(promise, can_manage_group_calls(group_call->dialog_id)); + } + td_->create_handler(std::move(promise))->send(input_group_call_id, user_id, is_muted); } @@ -1724,9 +1719,6 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrdialog_id.is_valid()) { - td_->messages_manager_->on_update_dialog_group_call(group_call->dialog_id, false, false); - } } else { auto mute_flags_changed = call.mute_new_participants != group_call->mute_new_participants || @@ -1756,10 +1748,7 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptris_active && group_call->dialog_id.is_valid()) { - td_->messages_manager_->on_update_dialog_group_call(group_call->dialog_id, true, - group_call->participant_count == 0); - } + update_group_call_dialog(group_call, "update_group_call"); if (!group_call->is_active && group_call_recent_speakers_.erase(group_call->group_call_id) != 0) { need_update = true; } @@ -1957,6 +1946,15 @@ UserId GroupCallManager::set_group_call_participant_is_speaking_by_source(InputG return UserId(); } +void GroupCallManager::update_group_call_dialog(const GroupCall *group_call, const char *source) { + if (!group_call->dialog_id.is_valid()) { + return; + } + + td_->messages_manager_->on_update_dialog_group_call(group_call->dialog_id, group_call->is_active, + group_call->participant_count == 0); +} + vector GroupCallManager::get_recent_speaker_user_ids(const GroupCall *group_call, bool for_update) { CHECK(group_call != nullptr && group_call->is_inited); diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 6630118c3..5ba88df4f 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -160,6 +160,8 @@ class GroupCallManager : public Actor { void try_clear_group_call_participants(InputGroupCallId input_group_call_id); + void update_group_call_dialog(const GroupCall *group_call, const char *source); + vector get_recent_speaker_user_ids(const GroupCall *group_call, bool for_update); tl_object_ptr get_update_group_call_object(const GroupCall *group_call, From babd4dc35dcfb6ee4ee427bfc38bcf10707e458f Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 15 Dec 2020 19:25:07 +0300 Subject: [PATCH 18/23] Add source to on_update_dialog_group_call. --- td/telegram/ContactsManager.cpp | 8 +++++--- td/telegram/GroupCallManager.cpp | 4 ++-- td/telegram/MessagesManager.cpp | 4 ++-- td/telegram/MessagesManager.h | 3 ++- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 6e0703a80..0c4d634e3 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -13809,7 +13809,8 @@ void ContactsManager::on_chat_update(telegram_api::chat &chat, const char *sourc bool has_active_group_call = (chat.flags_ & CHAT_FLAG_HAS_ACTIVE_GROUP_CALL) != 0; bool is_group_call_empty = (chat.flags_ & CHAT_FLAG_IS_GROUP_CALL_NON_EMPTY) == 0; - td_->messages_manager_->on_update_dialog_group_call(DialogId(chat_id), has_active_group_call, is_group_call_empty); + td_->messages_manager_->on_update_dialog_group_call(DialogId(chat_id), has_active_group_call, is_group_call_empty, + "receive chat"); } void ContactsManager::on_chat_update(telegram_api::chatForbidden &chat, const char *source) { @@ -14002,7 +14003,8 @@ void ContactsManager::on_chat_update(telegram_api::channel &channel, const char bool has_active_group_call = (channel.flags_ & CHANNEL_FLAG_HAS_ACTIVE_GROUP_CALL) != 0; bool is_group_call_empty = (channel.flags_ & CHANNEL_FLAG_IS_GROUP_CALL_NON_EMPTY) == 0; - td_->messages_manager_->on_update_dialog_group_call(DialogId(channel_id), has_active_group_call, is_group_call_empty); + td_->messages_manager_->on_update_dialog_group_call(DialogId(channel_id), has_active_group_call, is_group_call_empty, + "receive channel"); } void ContactsManager::on_chat_update(telegram_api::channelForbidden &channel, const char *source) { @@ -14041,7 +14043,7 @@ void ContactsManager::on_chat_update(telegram_api::channelForbidden &channel, co // on_update_channel_username(c, channel_id, ""); // don't know if channel username is empty, so don't update it tl_object_ptr banned_rights; // == nullptr on_update_channel_default_permissions(c, channel_id, get_restricted_rights(banned_rights)); - td_->messages_manager_->on_update_dialog_group_call(DialogId(channel_id), false, false); + td_->messages_manager_->on_update_dialog_group_call(DialogId(channel_id), false, false, "receive channelForbidden"); bool sign_messages = false; bool is_slow_mode_enabled = false; diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index da9210ba3..7c9573b33 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -665,7 +665,7 @@ void GroupCallManager::on_voice_chat_created(DialogId dialog_id, InputGroupCallI return promise.set_error(Status::Error(500, "Receive invalid group call identifier")); } - td_->messages_manager_->on_update_dialog_group_call(dialog_id, true, true); + td_->messages_manager_->on_update_dialog_group_call(dialog_id, true, true, "on_voice_chat_created"); td_->messages_manager_->on_update_dialog_group_call_id(dialog_id, input_group_call_id); promise.set_value(get_group_call_id(input_group_call_id, dialog_id)); @@ -1952,7 +1952,7 @@ void GroupCallManager::update_group_call_dialog(const GroupCall *group_call, con } td_->messages_manager_->on_update_dialog_group_call(group_call->dialog_id, group_call->is_active, - group_call->participant_count == 0); + group_call->participant_count == 0, source); } vector GroupCallManager::get_recent_speaker_user_ids(const GroupCall *group_call, bool for_update) { diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index ba6389885..a3e06192c 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -28973,13 +28973,13 @@ void MessagesManager::do_set_dialog_folder_id(Dialog *d, FolderId folder_id) { } void MessagesManager::on_update_dialog_group_call(DialogId dialog_id, bool has_active_group_call, - bool is_group_call_empty) { + bool is_group_call_empty, const char *source) { if (td_->auth_manager_->is_bot()) { return; } LOG(INFO) << "Update voice chat in " << dialog_id << " with has_active_voice_chat = " << has_active_group_call - << " and is_voice_chat_empty = " << is_group_call_empty; + << " and is_voice_chat_empty = " << is_group_call_empty << " from " << source; CHECK(dialog_id.is_valid()); Dialog *d = get_dialog(dialog_id); // must not create the Dialog, because is called from on_get_chat diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index e6bf71d34..3f88e1977 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -333,7 +333,8 @@ class MessagesManager : public Actor { void on_update_dialog_folder_id(DialogId dialog_id, FolderId folder_id); - void on_update_dialog_group_call(DialogId dialog_id, bool has_active_group_call, bool is_group_call_empty); + void on_update_dialog_group_call(DialogId dialog_id, bool has_active_group_call, bool is_group_call_empty, + const char *source); void on_update_dialog_group_call_id(DialogId dialog_id, InputGroupCallId input_group_call_id); From f50971625f8e4854c82cb73b8021e4f3fdf0dd72 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 16 Dec 2020 12:53:17 +0300 Subject: [PATCH 19/23] Fix version initialization. --- td/telegram/GroupCallManager.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 7c9573b33..d5b63c22f 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1139,6 +1139,7 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou return 0; } + LOG(INFO) << "Process " << participant << " in " << input_group_call_id; auto &participants = group_call_participants_[input_group_call_id]; if (participants == nullptr) { participants = make_unique(); @@ -1148,7 +1149,7 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou auto &old_participant = participants->participants[i]; if (old_participant.user_id == participant.user_id) { if (participant.joined_date == 0) { - // removed participant + LOG(INFO) << "Remove " << old_participant; if (old_participant.order != 0) { send_update_group_call_participant(input_group_call_id, participant); } @@ -1157,6 +1158,7 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou return -1; } + LOG(INFO) << "Edit " << old_participant; if (participant.joined_date < old_participant.joined_date) { LOG(ERROR) << "Join date of " << participant.user_id << " in " << input_group_call_id << " decreased from " << old_participant.joined_date << " to " << participant.joined_date; @@ -1186,13 +1188,17 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou } if (participant.joined_date == 0) { - // unknown removed participant + LOG(INFO) << "Remove unknown " << participant; remove_recent_group_call_speaker(input_group_call_id, participant.user_id); return -1; } - // unknown added or edited participant int diff = participant.is_just_joined ? 1 : 0; + if (participant.is_just_joined) { + LOG(INFO) << "Add new " << participant; + } else { + LOG(INFO) << "Receive new " << participant; + } auto real_order = participant.get_real_order(); if (real_order >= participants->min_order) { participant.order = real_order; @@ -1601,6 +1607,7 @@ void GroupCallManager::on_group_call_left_impl(GroupCall *group_call) { group_call->is_speaking = false; group_call->source = 0; group_call->loaded_all_participants = false; + group_call->version = -1; try_clear_group_call_participants(get_input_group_call_id(group_call->group_call_id).ok()); } @@ -1641,6 +1648,7 @@ void GroupCallManager::try_clear_group_call_participants(InputGroupCallId input_ auto group_call = get_group_call(input_group_call_id); CHECK(group_call != nullptr && group_call->is_inited); + LOG(INFO) << "Clear participants in " << input_group_call_id << " from " << group_call->dialog_id; if (group_call->loaded_all_participants) { group_call->loaded_all_participants = false; send_update_group_call(group_call, "try_clear_group_call_participants"); @@ -1700,6 +1708,8 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrdialog_id.is_valid()) { group_call->dialog_id = dialog_id; } + LOG(INFO) << "Update " << call.group_call_id << " with " << group_call->participant_count + << " participants and version " << group_call->version; if (!group_call->is_inited) { *group_call = std::move(call); if (need_group_call_participants(input_group_call_id)) { @@ -1734,11 +1744,12 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrparticipant_count) { + LOG(INFO) << "Set " << call.group_call_id << " participant count to " << call.participant_count; group_call->participant_count = call.participant_count; need_update = true; } - if (need_group_call_participants(input_group_call_id)) { - // init version + if (need_group_call_participants(input_group_call_id) && !join_params.empty()) { + LOG(INFO) << "Init " << call.group_call_id << " version to " << call.version; group_call->version = call.version; if (process_pending_group_call_participant_updates(input_group_call_id)) { need_update = false; From 03c22f286669c5c296993491e74cda2d174ee135 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 16 Dec 2020 12:54:56 +0300 Subject: [PATCH 20/23] Add Fernschreiber to list of examples. --- example/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/README.md b/example/README.md index b00d12b55..17ecd1646 100644 --- a/example/README.md +++ b/example/README.md @@ -125,8 +125,8 @@ TDLib has a simple and convenient C++11-interface for sending and receiving requ See [example/cpp](https://github.com/tdlib/td/tree/master/example/cpp) for an example of TDLib usage from C++. [td_example.cpp](https://github.com/tdlib/td/tree/master/example/cpp/td_example.cpp) contains an example of authorization, processing new incoming messages, getting a list of chats and sending a text message. -See also the source code of [Depecher](https://github.com/blacksailer/depecher) – a Telegram app for Sailfish OS, [TELEports](https://gitlab.com/ubports/apps/teleports) – a Qt-client for Ubuntu Touch, or -[tdlib-purple](https://github.com/ars3niy/tdlib-purple) - Telegram plugin for Pidgin, all of which are based on TDLib. +See also the source code of [Fernschreiber](https://github.com/Wunderfitz/harbour-fernschreiber) and [Depecher](https://github.com/blacksailer/depecher) – Telegram apps for Sailfish OS, +[TELEports](https://gitlab.com/ubports/apps/teleports) – a Qt-client for Ubuntu Touch, or [tdlib-purple](https://github.com/ars3niy/tdlib-purple) - Telegram plugin for Pidgin, all of which are based on TDLib. ## Using TDLib in Swift projects From 7fc2e783edc05b47d411aa6b586d8d20ccdf9d66 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 16 Dec 2020 14:04:07 +0300 Subject: [PATCH 21/23] Add groupCall.can_unmute_self. --- td/generate/scheme/td_api.tl | 7 ++++--- td/generate/scheme/td_api.tlo | Bin 191324 -> 191364 bytes td/telegram/GroupCallManager.cpp | 31 +++++++++++++++++++++++++++---- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 867684bc6..9a34f2a5f 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -2070,13 +2070,14 @@ callStateError error:error = CallState; //@id Group call identifier //@is_active True, if the call is active //@is_joined True, if the call is joined +//@can_unmute_self True, if the user can unmute themself //@participant_count Number of participants in the group call //@loaded_all_participants True, if all group call participants are loaded //@recent_speaker_user_ids Identifiers of recently speaking users in the group call //@mute_new_participants True, if only group call administrators can unmute new participants //@allowed_change_mute_new_participants True, if group call administrators can enable or disable mute_new_participants setting //@duration Call duration; for ended calls only -groupCall id:int32 is_active:Bool is_joined:Bool participant_count:int32 loaded_all_participants:Bool recent_speaker_user_ids:vector mute_new_participants:Bool allowed_change_mute_new_participants:Bool duration:int32 = GroupCall; +groupCall id:int32 is_active:Bool is_joined:Bool can_unmute_self:Bool participant_count:int32 loaded_all_participants:Bool recent_speaker_user_ids:vector mute_new_participants:Bool allowed_change_mute_new_participants:Bool duration:int32 = GroupCall; //@description Describes a payload fingerprint for interaction with tgcalls @hash Value of the field hash @setup Value of the field setup @fingerprint Value of the field fingerprint groupCallPayloadFingerprint hash:string setup:string fingerprint:string = GroupCallPayloadFingerprint; @@ -2093,9 +2094,9 @@ groupCallJoinResponseCandidate port:string protocol:string network:string genera groupCallJoinResponse payload:groupCallPayload candidates:vector = GroupCallJoinResponse; //@description Represents a group call participant @user_id Identifier of the user @source User's synchronization source -//@is_speaking True, if the user is speaking as set by setGroupCallParticipantIsSpeaking @is_muted True, if the user is muted @can_self_unmute True, if the user can unmute themself +//@is_speaking True, if the user is speaking as set by setGroupCallParticipantIsSpeaking @is_muted True, if the user is muted @can_unmute_self True, if the user can unmute themself //@order User's order in the group call participant list. The bigger is order, the higher is user in the list. If order is 0, the user must be removed from the participant list -groupCallParticipant user_id:int32 source:int32 is_speaking:Bool is_muted:Bool can_self_unmute:Bool order:int64 = GroupCallParticipant; +groupCallParticipant user_id:int32 source:int32 is_speaking:Bool is_muted:Bool can_unmute_self:Bool order:int64 = GroupCallParticipant; //@class CallProblem @description Describes the exact type of a problem with a call diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index b18f2fdbb5620a02c63fce32454271c07e7a07da..cf6a5c248cc452ae2e512857f5591ea2bc0d6a83 100644 GIT binary patch delta 216 zcmca}jl1PK_XY_e7O8TNlF2ecdsyDRWqPvtj!?!@5s(mPdQpC9fpcO`4g&*N$%ESx zlM8l4Op0dZF3rm=ElG_pPR&W198e^=`Q#3BMzA@XS$2J4Vgnf@l0NyKkQgV3dGnZ% z58LF6DH_xNo?)_|tkA+bz4kGa{NxSAto+G|dGSc5O*$qynYT-N@`pSQuydOK?A`un lFXIO@u<6r3d|~VXi*IlE%9v0Far%Y=3ov85LJpHnJpef9Thagk delta 179 zcmZp<&VA<^_XY_emV{HSuO`a~?O~C)w`JAlJ3<*tMLversion; return; } - LOG(INFO) << "Finish syncing participants in " << input_group_call_id << " from " << group_call->dialog_id; + LOG(INFO) << "Finish syncing participants in " << input_group_call_id << " from " << group_call->dialog_id + << " with version " << participants->version_; group_call->version = participants->version_; } } @@ -1140,6 +1142,16 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou } LOG(INFO) << "Process " << participant << " in " << input_group_call_id; + + if (participant.user_id == td_->contacts_manager_->get_my_id()) { + auto *group_call = get_group_call(input_group_call_id); + CHECK(group_call != nullptr && group_call->is_inited); + if (group_call->is_joined && group_call->is_active && group_call->can_self_unmute != participant.can_self_unmute) { + group_call->can_self_unmute = participant.can_self_unmute; + send_update_group_call(group_call, "process_group_call_participant"); + } + } + auto &participants = group_call_participants_[input_group_call_id]; if (participants == nullptr) { participants = make_unique(); @@ -1518,6 +1530,10 @@ void GroupCallManager::toggle_group_call_participant_is_muted(GroupCallId group_ if (user_id != td_->contacts_manager_->get_my_id()) { TRY_STATUS_PROMISE(promise, can_manage_group_calls(group_call->dialog_id)); + } else { + if (!is_muted && !group_call->can_self_unmute) { + return promise.set_error(Status::Error(400, "Can't unmute self")); + } } td_->create_handler(std::move(promise))->send(input_group_call_id, user_id, is_muted); @@ -1605,6 +1621,7 @@ void GroupCallManager::on_group_call_left_impl(GroupCall *group_call) { CHECK(group_call != nullptr && group_call->is_inited && group_call->is_joined); group_call->is_joined = false; group_call->is_speaking = false; + group_call->can_self_unmute = false; group_call->source = 0; group_call->loaded_all_participants = false; group_call->version = -1; @@ -1705,6 +1722,8 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrgroup_call_id; call.dialog_id = dialog_id.is_valid() ? dialog_id : group_call->dialog_id; + call.can_self_unmute = + call.is_active && (!call.mute_new_participants || can_manage_group_calls(call.dialog_id).is_ok()); if (!group_call->dialog_id.is_valid()) { group_call->dialog_id = dialog_id; } @@ -1750,6 +1769,10 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrcan_self_unmute != call.can_self_unmute) { + group_call->can_self_unmute = call.can_self_unmute; + need_update = true; + } group_call->version = call.version; if (process_pending_group_call_participant_updates(input_group_call_id)) { need_update = false; @@ -2014,9 +2037,9 @@ tl_object_ptr GroupCallManager::get_group_call_object(const G CHECK(group_call->is_inited); return td_api::make_object( - group_call->group_call_id.get(), group_call->is_active, group_call->is_joined, group_call->participant_count, - group_call->loaded_all_participants, std::move(recent_speaker_user_ids), group_call->mute_new_participants, - group_call->allowed_change_mute_new_participants, group_call->duration); + group_call->group_call_id.get(), group_call->is_active, group_call->is_joined, group_call->can_self_unmute, + group_call->participant_count, group_call->loaded_all_participants, std::move(recent_speaker_user_ids), + group_call->mute_new_participants, group_call->allowed_change_mute_new_participants, group_call->duration); } tl_object_ptr GroupCallManager::get_update_group_call_object( From 3681da21d84bdf546fc4a7be60e47eca44a98ac3 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 16 Dec 2020 16:04:27 +0300 Subject: [PATCH 22/23] Automatically close unclosed contours. --- td/telegram/GroupCallManager.cpp | 4 ++-- td/telegram/StickersManager.cpp | 4 ++++ tdnet/td/net/SslStream.cpp | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 2e3f2de18..774809005 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -903,8 +903,8 @@ void GroupCallManager::on_update_group_call_participants( } auto &pending_updates = group_call_participants->pending_updates_[version]; if (!pending_updates.empty()) { - LOG(ERROR) << "Receive duplicate updateGroupCallParticipants with version " << version << " in " - << input_group_call_id; + LOG(INFO) << "Receive duplicate updateGroupCallParticipants with version " << version << " in " + << input_group_call_id; sync_group_call_participants(input_group_call_id); return; } diff --git a/td/telegram/StickersManager.cpp b/td/telegram/StickersManager.cpp index a08fb79bb..c8199d333 100644 --- a/td/telegram/StickersManager.cpp +++ b/td/telegram/StickersManager.cpp @@ -1498,6 +1498,10 @@ vector> StickersManager::get_sticke make_point(last_end_control_point_x, last_end_control_point_y), make_point(x, y))); break; } + case 'm': + case 'M': + pos--; + // falltrough case 'z': case 'Z': if (x != start_x || y != start_y) { diff --git a/tdnet/td/net/SslStream.cpp b/tdnet/td/net/SslStream.cpp index 5f128c015..ed57ebfcc 100644 --- a/tdnet/td/net/SslStream.cpp +++ b/tdnet/td/net/SslStream.cpp @@ -472,7 +472,7 @@ class SslStreamImpl { return 0; } } - /* fall through */ + /* fallthrough */ default: LOG(DEBUG) << "SSL_ERROR Default"; return create_openssl_error(1, "SSL error "); From d165a87b7326669980b9461d29fea56dd46c6a79 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 16 Dec 2020 16:38:06 +0300 Subject: [PATCH 23/23] Reload group call if rights has changed. --- td/telegram/ContactsManager.cpp | 27 ++++++++++++++++++--------- td/telegram/ContactsManager.h | 2 +- td/telegram/GroupCallManager.cpp | 4 +++- td/telegram/GroupCallManager.h | 6 +++--- td/telegram/MessagesManager.cpp | 16 ++++++++++++++++ td/telegram/MessagesManager.h | 2 ++ 6 files changed, 43 insertions(+), 14 deletions(-) diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 0c4d634e3..c3e40f4f6 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -10979,16 +10979,17 @@ void ContactsManager::drop_channel_photos(ChannelId channel_id, bool is_empty, b } } -void ContactsManager::invalidate_channel_full(ChannelId channel_id, bool drop_invite_link, bool drop_slow_mode_delay) { +void ContactsManager::invalidate_channel_full(ChannelId channel_id, bool need_drop_invite_link, + bool need_drop_slow_mode_delay) { LOG(INFO) << "Invalidate supergroup full for " << channel_id; // drop channel full cache auto channel_full = get_channel_full_force(channel_id, "invalidate_channel_full"); if (channel_full != nullptr) { channel_full->expires_at = 0.0; - if (drop_invite_link) { + if (need_drop_invite_link) { on_update_channel_full_invite_link(channel_full, nullptr); } - if (drop_slow_mode_delay && channel_full->slow_mode_delay != 0) { + if (need_drop_slow_mode_delay && channel_full->slow_mode_delay != 0) { channel_full->slow_mode_delay = 0; channel_full->slow_mode_next_send_date = 0; channel_full->is_slow_mode_next_send_date_changed = true; @@ -10996,7 +10997,7 @@ void ContactsManager::invalidate_channel_full(ChannelId channel_id, bool drop_in } update_channel_full(channel_full, channel_id); } - if (drop_invite_link) { + if (need_drop_invite_link) { remove_dialog_access_by_invite_link(DialogId(channel_id)); auto it = dialog_invite_links_.find(DialogId(channel_id)); @@ -11701,7 +11702,8 @@ void ContactsManager::on_update_chat_delete_user(ChatId chat_id, UserId user_id, void ContactsManager::on_update_chat_status(Chat *c, ChatId chat_id, DialogParticipantStatus status) { if (c->status != status) { LOG(INFO) << "Update " << chat_id << " status from " << c->status << " to " << status; - bool drop_invite_link = c->status.is_left() != status.is_left(); + bool need_drop_invite_link = c->status.is_left() != status.is_left(); + bool need_reload_group_call = c->status.can_manage_calls() != status.can_manage_calls(); c->status = status; @@ -11713,12 +11715,15 @@ void ContactsManager::on_update_chat_status(Chat *c, ChatId chat_id, DialogParti drop_chat_full(chat_id); } - if (drop_invite_link) { + if (need_drop_invite_link) { auto it = dialog_invite_links_.find(DialogId(chat_id)); if (it != dialog_invite_links_.end()) { invalidate_invite_link_info(it->second); } } + if (need_reload_group_call) { + td_->messages_manager_->reload_dialog_group_call(DialogId(chat_id)); + } c->is_changed = true; } @@ -12044,9 +12049,10 @@ void ContactsManager::on_channel_status_changed(Channel *c, ChannelId channel_id const DialogParticipantStatus &new_status) { CHECK(c->is_update_supergroup_sent); - bool drop_invite_link = old_status.is_administrator() != new_status.is_administrator() || - old_status.is_member() != new_status.is_member(); - invalidate_channel_full(channel_id, drop_invite_link, !c->is_slow_mode_enabled); + bool need_drop_invite_link = old_status.is_administrator() != new_status.is_administrator() || + old_status.is_member() != new_status.is_member(); + bool need_reload_group_call = old_status.can_manage_calls() != new_status.can_manage_calls(); + invalidate_channel_full(channel_id, need_drop_invite_link, !c->is_slow_mode_enabled); if (old_status.is_creator() != new_status.is_creator()) { for (size_t i = 0; i < 2; i++) { @@ -12057,6 +12063,9 @@ void ContactsManager::on_channel_status_changed(Channel *c, ChannelId channel_id send_get_channel_full_query(nullptr, channel_id, Auto(), "update channel owner"); reload_dialog_administrators(DialogId(channel_id), 0, Auto()); } + if (need_reload_group_call) { + td_->messages_manager_->reload_dialog_group_call(DialogId(channel_id)); + } } void ContactsManager::on_update_channel_default_permissions(Channel *c, ChannelId channel_id, diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index 79d94ec1e..9bee0274c 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -215,7 +215,7 @@ class ContactsManager : public Actor { void speculative_delete_channel_participant(ChannelId channel_id, UserId deleted_user_id, bool by_me); - void invalidate_channel_full(ChannelId channel_id, bool drop_invite_link, bool drop_slow_mode_delay); + void invalidate_channel_full(ChannelId channel_id, bool need_drop_invite_link, bool need_drop_slow_mode_delay); bool on_get_channel_error(ChannelId channel_id, const Status &status, const string &source); diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 774809005..9c85db2d6 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -735,7 +735,9 @@ void GroupCallManager::finish_get_group_call(InputGroupCallId input_group_call_i auto group_call = get_group_call(input_group_call_id); for (auto &promise : promises) { - promise.set_value(get_group_call_object(group_call, get_recent_speaker_user_ids(group_call, false))); + if (promise) { + promise.set_value(get_group_call_object(group_call, get_recent_speaker_user_ids(group_call, false))); + } } } diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 5ba88df4f..bf769b4e5 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -41,6 +41,9 @@ class GroupCallManager : public Actor { void get_group_call(GroupCallId group_call_id, Promise> &&promise); + void reload_group_call(InputGroupCallId input_group_call_id, + Promise> &&promise); + void join_group_call(GroupCallId group_call_id, td_api::object_ptr &&payload, int32 source, bool is_muted, Promise> &&promise); @@ -113,9 +116,6 @@ class GroupCallManager : public Actor { void on_voice_chat_created(DialogId dialog_id, InputGroupCallId input_group_call_id, Promise &&promise); - void reload_group_call(InputGroupCallId input_group_call_id, - Promise> &&promise); - void finish_get_group_call(InputGroupCallId input_group_call_id, Result> &&result); diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index a3e06192c..20cc4c366 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -10651,6 +10651,22 @@ void MessagesManager::delete_dialog(DialogId dialog_id) { close_dialog(d); } +void MessagesManager::reload_dialog_group_call(DialogId dialog_id) { + if (td_->auth_manager_->is_bot()) { + return; + } + + auto d = get_dialog(dialog_id); + if (d == nullptr) { + // nothing to do + return; + } + + if (d->active_group_call_id.is_valid()) { + td_->group_call_manager_->reload_group_call(d->active_group_call_id, Auto()); + } +} + void MessagesManager::read_all_dialog_mentions(DialogId dialog_id, Promise &&promise) { bool is_bot = td_->auth_manager_->is_bot(); if (is_bot) { diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 3f88e1977..d02adddfb 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -397,6 +397,8 @@ class MessagesManager : public Actor { void delete_dialog(DialogId dialog_id); + void reload_dialog_group_call(DialogId dialog_id); + void read_all_dialog_mentions(DialogId dialog_id, Promise &&promise); Status add_recently_found_dialog(DialogId dialog_id) TD_WARN_UNUSED_RESULT;