tdlight/td/telegram/GroupCallManager.cpp

1108 lines
44 KiB
C++
Raw Normal View History

2020-11-26 11:47:20 +01:00
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include "td/telegram/GroupCallManager.h"
2020-12-04 10:44:09 +01:00
#include "td/telegram/AuthManager.h"
2020-11-26 11:47:20 +01:00
#include "td/telegram/ContactsManager.h"
#include "td/telegram/Global.h"
#include "td/telegram/MessagesManager.h"
2020-11-26 12:32:29 +01:00
#include "td/telegram/misc.h"
2020-11-26 15:33:28 +01:00
#include "td/telegram/net/NetQuery.h"
2020-11-26 11:47:20 +01:00
#include "td/telegram/Td.h"
#include "td/telegram/UpdatesManager.h"
2020-11-26 12:32:29 +01:00
#include "td/utils/JsonBuilder.h"
2020-11-26 11:47:20 +01:00
#include "td/utils/Random.h"
2020-12-06 08:40:26 +01:00
#include <utility>
2020-11-26 11:47:20 +01:00
namespace td {
class CreateGroupCallQuery : public Td::ResultHandler {
Promise<InputGroupCallId> promise_;
ChannelId channel_id_;
public:
explicit CreateGroupCallQuery(Promise<InputGroupCallId> &&promise) : promise_(std::move(promise)) {
}
void send(ChannelId channel_id) {
channel_id_ = channel_id;
auto input_channel = td->contacts_manager_->get_input_channel(channel_id);
CHECK(input_channel != nullptr);
send_query(G()->net_query_creator().create(
telegram_api::phone_createGroupCall(std::move(input_channel), Random::secure_int32())));
}
void on_result(uint64 id, BufferSlice packet) override {
auto result_ptr = fetch_result<telegram_api::phone_createGroupCall>(packet);
if (result_ptr.is_error()) {
return on_error(id, result_ptr.move_as_error());
}
auto ptr = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for CreateGroupCallQuery: " << to_string(ptr);
auto group_call_ids = td->updates_manager_->get_update_new_group_call_ids(ptr.get());
if (group_call_ids.size() != 1) {
LOG(ERROR) << "Receive wrong CreateGroupCallQuery response " << to_string(ptr);
return on_error(id, Status::Error(500, "Receive wrong response"));
}
td->updates_manager_->on_get_updates(std::move(ptr));
// TODO set promise after updates are processed
promise_.set_value(std::move(group_call_ids[0]));
}
void on_error(uint64 id, Status status) override {
td->contacts_manager_->on_get_channel_error(channel_id_, status, "CreateGroupCallQuery");
promise_.set_error(std::move(status));
}
};
2020-12-03 00:00:46 +01:00
class GetGroupCallQuery : public Td::ResultHandler {
Promise<tl_object_ptr<telegram_api::phone_groupCall>> promise_;
public:
explicit GetGroupCallQuery(Promise<tl_object_ptr<telegram_api::phone_groupCall>> &&promise)
: promise_(std::move(promise)) {
}
2020-12-03 17:52:50 +01:00
void send(InputGroupCallId input_group_call_id) {
send_query(
G()->net_query_creator().create(telegram_api::phone_getGroupCall(input_group_call_id.get_input_group_call())));
2020-12-03 00:00:46 +01:00
}
void on_result(uint64 id, BufferSlice packet) override {
auto result_ptr = fetch_result<telegram_api::phone_getGroupCall>(packet);
if (result_ptr.is_error()) {
return on_error(id, result_ptr.move_as_error());
}
auto ptr = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for GetGroupCallQuery: " << to_string(ptr);
promise_.set_value(std::move(ptr));
}
void on_error(uint64 id, Status status) override {
promise_.set_error(std::move(status));
}
};
2020-11-26 12:32:29 +01:00
class JoinGroupCallQuery : public Td::ResultHandler {
Promise<Unit> promise_;
2020-12-03 17:52:50 +01:00
InputGroupCallId input_group_call_id_;
2020-11-26 12:32:29 +01:00
uint64 generation_ = 0;
public:
explicit JoinGroupCallQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
2020-12-03 17:52:50 +01:00
NetQueryRef send(InputGroupCallId input_group_call_id, const string &payload, bool is_muted, uint64 generation) {
input_group_call_id_ = input_group_call_id;
2020-11-26 12:32:29 +01:00
generation_ = generation;
int32 flags = 0;
if (is_muted) {
flags |= telegram_api::phone_joinGroupCall::MUTED_MASK;
}
2020-11-26 15:33:28 +01:00
auto query = G()->net_query_creator().create(
2020-12-03 17:52:50 +01:00
telegram_api::phone_joinGroupCall(flags, false /*ignored*/, input_group_call_id.get_input_group_call(),
2020-11-26 15:33:28 +01:00
make_tl_object<telegram_api::dataJSON>(payload)));
auto join_query_ref = query.get_weak();
send_query(std::move(query));
return join_query_ref;
2020-11-26 12:32:29 +01:00
}
void on_result(uint64 id, BufferSlice packet) override {
auto result_ptr = fetch_result<telegram_api::phone_joinGroupCall>(packet);
if (result_ptr.is_error()) {
return on_error(id, result_ptr.move_as_error());
}
2020-12-03 17:52:50 +01:00
td->group_call_manager_->process_join_group_call_response(input_group_call_id_, generation_,
result_ptr.move_as_ok(), std::move(promise_));
2020-11-26 12:32:29 +01:00
}
void on_error(uint64 id, Status status) override {
promise_.set_error(std::move(status));
}
};
class ToggleGroupCallSettingsQuery : public Td::ResultHandler {
Promise<Unit> promise_;
public:
explicit ToggleGroupCallSettingsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
2020-12-03 17:52:50 +01:00
void send(int32 flags, InputGroupCallId input_group_call_id, bool join_muted) {
send_query(G()->net_query_creator().create(
2020-12-03 17:52:50 +01:00
telegram_api::phone_toggleGroupCallSettings(flags, input_group_call_id.get_input_group_call(), join_muted)));
}
void on_result(uint64 id, BufferSlice packet) override {
auto result_ptr = fetch_result<telegram_api::phone_toggleGroupCallSettings>(packet);
if (result_ptr.is_error()) {
return on_error(id, result_ptr.move_as_error());
}
auto ptr = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for ToggleGroupCallSettingsQuery: " << to_string(ptr);
td->updates_manager_->on_get_updates(std::move(ptr));
// TODO set promise after updates are processed
promise_.set_value(Unit());
}
void on_error(uint64 id, Status status) override {
promise_.set_error(std::move(status));
}
};
2020-11-27 13:22:19 +01:00
class InviteToGroupCallQuery : public Td::ResultHandler {
Promise<Unit> promise_;
public:
explicit InviteToGroupCallQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
2020-12-03 17:52:50 +01:00
void send(InputGroupCallId input_group_call_id, vector<tl_object_ptr<telegram_api::InputUser>> input_users) {
2020-11-27 13:22:19 +01:00
send_query(G()->net_query_creator().create(
2020-12-03 17:52:50 +01:00
telegram_api::phone_inviteToGroupCall(input_group_call_id.get_input_group_call(), std::move(input_users))));
2020-11-27 13:22:19 +01:00
}
void on_result(uint64 id, BufferSlice packet) override {
auto result_ptr = fetch_result<telegram_api::phone_inviteToGroupCall>(packet);
if (result_ptr.is_error()) {
return on_error(id, result_ptr.move_as_error());
}
auto ptr = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for InviteToGroupCallQuery: " << to_string(ptr);
td->updates_manager_->on_get_updates(std::move(ptr));
// TODO set promise after updates are processed
promise_.set_value(Unit());
}
void on_error(uint64 id, Status status) override {
promise_.set_error(std::move(status));
}
};
class EditGroupCallMemberQuery : public Td::ResultHandler {
Promise<Unit> promise_;
public:
explicit EditGroupCallMemberQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
2020-12-03 17:52:50 +01:00
void send(InputGroupCallId input_group_call_id, UserId user_id, bool is_muted) {
auto input_user = td->contacts_manager_->get_input_user(user_id);
CHECK(input_user != nullptr);
int32 flags = 0;
if (is_muted) {
flags |= telegram_api::phone_editGroupCallMember::MUTED_MASK;
}
send_query(G()->net_query_creator().create(telegram_api::phone_editGroupCallMember(
2020-12-03 17:52:50 +01:00
flags, false /*ignored*/, input_group_call_id.get_input_group_call(), std::move(input_user))));
}
void on_result(uint64 id, BufferSlice packet) override {
auto result_ptr = fetch_result<telegram_api::phone_editGroupCallMember>(packet);
if (result_ptr.is_error()) {
return on_error(id, result_ptr.move_as_error());
}
auto ptr = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for EditGroupCallMemberQuery: " << to_string(ptr);
td->updates_manager_->on_get_updates(std::move(ptr));
// TODO set promise after updates are processed
promise_.set_value(Unit());
}
void on_error(uint64 id, Status status) override {
promise_.set_error(std::move(status));
}
};
2020-11-27 15:07:12 +01:00
class CheckGroupCallQuery : public Td::ResultHandler {
Promise<Unit> promise_;
public:
explicit CheckGroupCallQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
2020-12-03 17:52:50 +01:00
void send(InputGroupCallId input_group_call_id, int32 source) {
2020-11-27 15:07:12 +01:00
send_query(G()->net_query_creator().create(
2020-12-03 17:52:50 +01:00
telegram_api::phone_checkGroupCall(input_group_call_id.get_input_group_call(), source)));
2020-11-27 15:07:12 +01:00
}
void on_result(uint64 id, BufferSlice packet) override {
auto result_ptr = fetch_result<telegram_api::phone_checkGroupCall>(packet);
if (result_ptr.is_error()) {
return on_error(id, result_ptr.move_as_error());
}
bool success = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for CheckGroupCallQuery: " << success;
if (success) {
promise_.set_value(Unit());
} else {
promise_.set_error(Status::Error(400, "GROUP_CALL_JOIN_MISSING"));
2020-11-27 15:07:12 +01:00
}
}
void on_error(uint64 id, Status status) override {
promise_.set_error(std::move(status));
}
};
2020-11-26 11:47:20 +01:00
class LeaveGroupCallQuery : public Td::ResultHandler {
Promise<Unit> promise_;
public:
explicit LeaveGroupCallQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
2020-12-03 17:52:50 +01:00
void send(InputGroupCallId input_group_call_id, int32 source) {
2020-11-26 11:47:20 +01:00
send_query(G()->net_query_creator().create(
2020-12-03 17:52:50 +01:00
telegram_api::phone_leaveGroupCall(input_group_call_id.get_input_group_call(), source)));
2020-11-26 11:47:20 +01:00
}
void on_result(uint64 id, BufferSlice packet) override {
auto result_ptr = fetch_result<telegram_api::phone_leaveGroupCall>(packet);
if (result_ptr.is_error()) {
return on_error(id, result_ptr.move_as_error());
}
auto ptr = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for LeaveGroupCallQuery: " << to_string(ptr);
td->updates_manager_->on_get_updates(std::move(ptr));
// TODO set promise after updates are processed
promise_.set_value(Unit());
}
void on_error(uint64 id, Status status) override {
promise_.set_error(std::move(status));
}
};
class DiscardGroupCallQuery : public Td::ResultHandler {
Promise<Unit> promise_;
public:
explicit DiscardGroupCallQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
2020-12-03 17:52:50 +01:00
void send(InputGroupCallId input_group_call_id) {
send_query(G()->net_query_creator().create(
telegram_api::phone_discardGroupCall(input_group_call_id.get_input_group_call())));
2020-11-26 11:47:20 +01:00
}
void on_result(uint64 id, BufferSlice packet) override {
auto result_ptr = fetch_result<telegram_api::phone_discardGroupCall>(packet);
if (result_ptr.is_error()) {
return on_error(id, result_ptr.move_as_error());
}
auto ptr = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for DiscardGroupCallQuery: " << to_string(ptr);
td->updates_manager_->on_get_updates(std::move(ptr));
// TODO set promise after updates are processed
promise_.set_value(Unit());
}
void on_error(uint64 id, Status status) override {
promise_.set_error(std::move(status));
}
};
struct GroupCallManager::GroupCall {
2020-12-03 17:52:50 +01:00
GroupCallId group_call_id;
2020-12-04 10:40:51 +01:00
ChannelId channel_id;
2020-12-03 17:52:50 +01:00
bool is_inited = false;
2020-11-26 11:47:20 +01:00
bool is_active = false;
bool is_joined = false;
bool is_speaking = false;
bool mute_new_members = false;
bool allowed_change_mute_new_members = false;
2020-11-26 11:47:20 +01:00
int32 member_count = 0;
int32 version = -1;
int32 duration = 0;
int32 source = 0;
2020-11-26 11:47:20 +01:00
};
2020-12-06 08:40:26 +01:00
struct GroupCallManager::GroupCallRecentSpeakers {
2020-12-06 19:18:12 +01:00
mutable vector<std::pair<UserId, int32>> users; // user + time; sorted by time
mutable bool is_changed = true;
mutable vector<int32> last_sent_user_ids;
2020-12-06 08:40:26 +01:00
};
2020-11-26 15:33:28 +01:00
struct GroupCallManager::PendingJoinRequest {
NetQueryRef query_ref;
uint64 generation = 0;
int32 source = 0;
2020-11-26 15:33:28 +01:00
Promise<td_api::object_ptr<td_api::groupCallJoinResponse>> promise;
};
2020-11-26 11:47:20 +01:00
GroupCallManager::GroupCallManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) {
pending_send_speaking_action_timeout_.set_callback(on_pending_send_speaking_action_timeout_callback);
pending_send_speaking_action_timeout_.set_callback_data(static_cast<void *>(this));
recent_speaker_update_timeout_.set_callback(on_recent_speaker_update_timeout_callback);
recent_speaker_update_timeout_.set_callback_data(static_cast<void *>(this));
2020-11-26 11:47:20 +01:00
}
2020-11-26 16:02:18 +01:00
GroupCallManager::~GroupCallManager() = default;
2020-11-26 11:47:20 +01:00
void GroupCallManager::tear_down() {
parent_.reset();
}
void GroupCallManager::on_pending_send_speaking_action_timeout_callback(void *group_call_manager_ptr,
int64 group_call_id_int) {
if (G()->close_flag()) {
return;
}
auto group_call_manager = static_cast<GroupCallManager *>(group_call_manager_ptr);
send_closure_later(group_call_manager->actor_id(group_call_manager),
&GroupCallManager::on_send_speaking_action_timeout,
GroupCallId(narrow_cast<int32>(group_call_id_int)));
}
void GroupCallManager::on_send_speaking_action_timeout(GroupCallId group_call_id) {
if (G()->close_flag()) {
return;
}
LOG(INFO) << "Receive send_speaking_action timeout in " << group_call_id;
auto input_group_call_id = get_input_group_call_id(group_call_id).move_as_ok();
auto *group_call = get_group_call(input_group_call_id);
CHECK(group_call != nullptr && group_call->is_inited && group_call->channel_id.is_valid());
if (!group_call->is_joined || !group_call->is_speaking) {
return;
}
2020-12-06 08:40:26 +01:00
on_user_speaking_in_group_call(group_call_id, td_->contacts_manager_->get_my_id(), G()->unix_time());
pending_send_speaking_action_timeout_.add_timeout_in(group_call_id.get(), 4.0);
td_->messages_manager_->send_dialog_action(DialogId(group_call->channel_id), MessageId(),
DialogAction::get_speaking_action(), Promise<Unit>());
}
void GroupCallManager::on_recent_speaker_update_timeout_callback(void *group_call_manager_ptr,
int64 group_call_id_int) {
if (G()->close_flag()) {
return;
}
auto group_call_manager = static_cast<GroupCallManager *>(group_call_manager_ptr);
send_closure_later(group_call_manager->actor_id(group_call_manager),
&GroupCallManager::on_recent_speaker_update_timeout,
GroupCallId(narrow_cast<int32>(group_call_id_int)));
}
void GroupCallManager::on_recent_speaker_update_timeout(GroupCallId group_call_id) {
if (G()->close_flag()) {
return;
}
LOG(INFO) << "Receive recent speaker update timeout in " << group_call_id;
auto input_group_call_id = get_input_group_call_id(group_call_id).move_as_ok();
auto *group_call = get_group_call(input_group_call_id);
CHECK(group_call != nullptr && group_call->is_inited);
auto &recent_speakers = group_call_recent_speakers_[group_call_id];
CHECK(recent_speakers != nullptr);
if (!recent_speakers->is_changed) {
2020-12-06 19:18:12 +01:00
if (recent_speakers->users.empty()) {
return;
}
if (recent_speakers->users.back().second >= G()->unix_time() - RECENT_SPEAKER_TIMEOUT) {
// reset timeout
auto next_timeout = recent_speakers->users.back().second + RECENT_SPEAKER_TIMEOUT - G()->unix_time() + 1;
recent_speaker_update_timeout_.add_timeout_in(group_call_id.get(), next_timeout);
return;
}
}
send_closure(G()->td(), &Td::send_update, get_update_group_call_object(group_call));
}
2020-12-04 10:40:51 +01:00
GroupCallId GroupCallManager::get_group_call_id(InputGroupCallId input_group_call_id, ChannelId channel_id) {
if (td_->auth_manager_->is_bot() || !input_group_call_id.is_valid()) {
2020-12-04 10:44:09 +01:00
return GroupCallId();
}
2020-12-04 10:40:51 +01:00
return add_group_call(input_group_call_id, channel_id)->group_call_id;
2020-11-26 11:47:20 +01:00
}
2020-12-03 17:52:50 +01:00
Result<InputGroupCallId> GroupCallManager::get_input_group_call_id(GroupCallId group_call_id) {
if (!group_call_id.is_valid()) {
return Status::Error(400, "Invalid group call identifier specified");
}
if (group_call_id.get() <= 0 || group_call_id.get() > max_group_call_id_.get()) {
return Status::Error(400, "Wrong group call identifier specified");
}
CHECK(static_cast<size_t>(group_call_id.get()) <= input_group_call_ids_.size());
auto input_group_call_id = input_group_call_ids_[group_call_id.get() - 1];
LOG(DEBUG) << "Found " << input_group_call_id;
return input_group_call_id;
2020-12-03 17:52:50 +01:00
}
GroupCallId GroupCallManager::get_next_group_call_id(InputGroupCallId input_group_call_id) {
max_group_call_id_ = GroupCallId(max_group_call_id_.get() + 1);
input_group_call_ids_.push_back(input_group_call_id);
return max_group_call_id_;
}
2020-12-04 10:40:51 +01:00
GroupCallManager::GroupCall *GroupCallManager::add_group_call(InputGroupCallId input_group_call_id,
ChannelId channel_id) {
2020-12-04 10:44:09 +01:00
CHECK(!td_->auth_manager_->is_bot());
2020-12-03 17:52:50 +01:00
auto &group_call = group_calls_[input_group_call_id];
if (group_call == nullptr) {
group_call = make_unique<GroupCall>();
group_call->group_call_id = get_next_group_call_id(input_group_call_id);
LOG(INFO) << "Add " << input_group_call_id << " from " << channel_id << " as " << group_call->group_call_id;
2020-12-03 17:52:50 +01:00
}
2020-12-04 10:40:51 +01:00
if (!group_call->channel_id.is_valid()) {
group_call->channel_id = channel_id;
}
2020-12-03 17:52:50 +01:00
return group_call.get();
}
const GroupCallManager::GroupCall *GroupCallManager::get_group_call(InputGroupCallId input_group_call_id) const {
auto it = group_calls_.find(input_group_call_id);
2020-12-03 00:00:46 +01:00
if (it == group_calls_.end()) {
return nullptr;
} else {
return it->second.get();
}
}
2020-12-03 17:52:50 +01:00
GroupCallManager::GroupCall *GroupCallManager::get_group_call(InputGroupCallId input_group_call_id) {
auto it = group_calls_.find(input_group_call_id);
2020-12-03 00:00:46 +01:00
if (it == group_calls_.end()) {
return nullptr;
} else {
return it->second.get();
}
}
2020-12-03 17:52:50 +01:00
void GroupCallManager::create_voice_chat(ChannelId channel_id, Promise<InputGroupCallId> &&promise) {
td_->create_handler<CreateGroupCallQuery>(std::move(promise))->send(channel_id);
}
void GroupCallManager::get_group_call(GroupCallId group_call_id,
2020-12-03 00:00:46 +01:00
Promise<td_api::object_ptr<td_api::groupCall>> &&promise) {
2020-12-03 17:52:50 +01:00
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) {
return promise.set_value(get_group_call_object(group_call));
2020-12-03 00:00:46 +01:00
}
2020-12-03 17:52:50 +01:00
reload_group_call(input_group_call_id, std::move(promise));
2020-12-03 00:00:46 +01:00
}
2020-12-03 17:52:50 +01:00
void GroupCallManager::reload_group_call(InputGroupCallId input_group_call_id,
2020-12-03 00:00:46 +01:00
Promise<td_api::object_ptr<td_api::groupCall>> &&promise) {
2020-12-03 17:52:50 +01:00
auto &queries = load_group_call_queries_[input_group_call_id];
2020-12-03 00:00:46 +01:00
queries.push_back(std::move(promise));
if (queries.size() == 1) {
2020-12-03 17:52:50 +01:00
auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), input_group_call_id](
Result<tl_object_ptr<telegram_api::phone_groupCall>> &&result) {
send_closure(actor_id, &GroupCallManager::finish_get_group_call, input_group_call_id, std::move(result));
});
td_->create_handler<GetGroupCallQuery>(std::move(query_promise))->send(input_group_call_id);
2020-12-03 00:00:46 +01:00
}
}
2020-12-03 17:52:50 +01:00
void GroupCallManager::finish_get_group_call(InputGroupCallId input_group_call_id,
2020-12-03 00:00:46 +01:00
Result<tl_object_ptr<telegram_api::phone_groupCall>> &&result) {
2020-12-03 17:52:50 +01:00
auto it = load_group_call_queries_.find(input_group_call_id);
2020-12-03 00:00:46 +01:00
CHECK(it != load_group_call_queries_.end());
CHECK(!it->second.empty());
auto promises = std::move(it->second);
load_group_call_queries_.erase(it);
if (result.is_ok()) {
td_->contacts_manager_->on_get_users(std::move(result.ok_ref()->users_), "finish_get_group_call");
2020-12-04 10:40:51 +01:00
auto call_id = update_group_call(result.ok()->call_, ChannelId());
2020-12-03 17:52:50 +01:00
if (call_id != input_group_call_id) {
LOG(ERROR) << "Expected " << input_group_call_id << ", but received " << to_string(result.ok());
2020-12-03 00:00:46 +01:00
result = Status::Error(500, "Receive another group call");
}
}
if (result.is_error()) {
for (auto &promise : promises) {
promise.set_error(result.error().clone());
}
return;
}
2020-12-03 17:52:50 +01:00
auto group_call = get_group_call(input_group_call_id);
2020-12-03 00:00:46 +01:00
for (auto &promise : promises) {
2020-12-03 17:52:50 +01:00
promise.set_value(get_group_call_object(group_call));
2020-12-03 00:00:46 +01:00
}
}
2020-12-03 17:52:50 +01:00
void GroupCallManager::join_group_call(GroupCallId group_call_id,
2020-11-26 12:32:29 +01:00
td_api::object_ptr<td_api::groupCallPayload> &&payload, int32 source,
bool is_muted,
Promise<td_api::object_ptr<td_api::groupCallJoinResponse>> &&promise) {
2020-12-03 17:52:50 +01:00
TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id));
if (pending_join_requests_.count(input_group_call_id)) {
auto it = pending_join_requests_.find(input_group_call_id);
2020-11-26 12:32:29 +01:00
CHECK(it != pending_join_requests_.end());
2020-11-26 15:33:28 +01:00
CHECK(it->second != nullptr);
if (!it->second->query_ref.empty()) {
cancel_query(it->second->query_ref);
}
it->second->promise.set_error(Status::Error(200, "Cancelled by another joinGroupCall request"));
2020-11-26 12:32:29 +01:00
pending_join_requests_.erase(it);
}
if (payload == nullptr) {
return promise.set_error(Status::Error(400, "Payload must be non-empty"));
}
if (!clean_input_string(payload->ufrag_)) {
return promise.set_error(Status::Error(400, "Payload ufrag must be encoded in UTF-8"));
}
if (!clean_input_string(payload->pwd_)) {
return promise.set_error(Status::Error(400, "Payload pwd must be encoded in UTF-8"));
}
for (auto &fingerprint : payload->fingerprints_) {
if (fingerprint == nullptr) {
return promise.set_error(Status::Error(400, "Payload fingerprint must be non-empty"));
}
if (!clean_input_string(fingerprint->hash_)) {
return promise.set_error(Status::Error(400, "Fingerprint hash must be encoded in UTF-8"));
}
if (!clean_input_string(fingerprint->setup_)) {
return promise.set_error(Status::Error(400, "Fingerprint setup must be encoded in UTF-8"));
}
if (!clean_input_string(fingerprint->fingerprint_)) {
return promise.set_error(Status::Error(400, "Fingerprint must be encoded in UTF-8"));
}
}
auto json_payload = json_encode<string>(json_object([&payload, source](auto &o) {
o("ufrag", payload->ufrag_);
o("pwd", payload->pwd_);
o("fingerprints", json_array(payload->fingerprints_,
[](const td_api::object_ptr<td_api::groupCallPayloadFingerprint> &fingerprint) {
return json_object([&fingerprint](auto &o) {
o("hash", fingerprint->hash_);
o("setup", fingerprint->setup_);
o("fingerprint", fingerprint->fingerprint_);
});
}));
o("ssrc", source);
}));
2020-11-27 13:31:00 +01:00
auto generation = ++join_group_request_generation_;
2020-12-03 17:52:50 +01:00
auto &request = pending_join_requests_[input_group_call_id];
2020-11-26 15:33:28 +01:00
request = make_unique<PendingJoinRequest>();
request->generation = generation;
request->source = source;
2020-11-26 15:33:28 +01:00
request->promise = std::move(promise);
2020-11-26 12:32:29 +01:00
auto query_promise =
2020-12-03 17:52:50 +01:00
PromiseCreator::lambda([actor_id = actor_id(this), generation, input_group_call_id](Result<Unit> &&result) {
2020-11-26 12:32:29 +01:00
CHECK(result.is_error());
2020-12-03 17:52:50 +01:00
send_closure(actor_id, &GroupCallManager::finish_join_group_call, input_group_call_id, generation,
2020-11-26 12:32:29 +01:00
result.move_as_error());
});
2020-11-26 15:33:28 +01:00
request->query_ref = td_->create_handler<JoinGroupCallQuery>(std::move(query_promise))
2020-12-03 17:52:50 +01:00
->send(input_group_call_id, json_payload, is_muted, generation);
2020-11-26 12:32:29 +01:00
}
2020-12-03 17:52:50 +01:00
void GroupCallManager::process_join_group_call_response(InputGroupCallId input_group_call_id, uint64 generation,
2020-11-26 12:32:29 +01:00
tl_object_ptr<telegram_api::Updates> &&updates,
Promise<Unit> &&promise) {
2020-12-03 17:52:50 +01:00
auto it = pending_join_requests_.find(input_group_call_id);
2020-11-26 15:33:28 +01:00
if (it == pending_join_requests_.end() || it->second->generation != generation) {
2020-12-03 17:52:50 +01:00
LOG(INFO) << "Ignore JoinGroupCallQuery response with " << input_group_call_id << " and generation " << generation;
2020-11-26 12:32:29 +01:00
return;
}
LOG(INFO) << "Receive result for JoinGroupCallQuery: " << to_string(updates);
td_->updates_manager_->on_get_updates(std::move(updates));
promise.set_error(Status::Error(500, "Wrong join response received"));
}
Result<td_api::object_ptr<td_api::groupCallJoinResponse>> GroupCallManager::get_group_call_join_response_object(
string json_response) {
auto r_value = json_decode(json_response);
if (r_value.is_error()) {
return Status::Error("Can't parse JSON object");
}
auto value = r_value.move_as_ok();
if (value.type() != JsonValue::Type::Object) {
return Status::Error("Expected an Object");
}
auto &value_object = value.get_object();
TRY_RESULT(transport, get_json_object_field(value_object, "transport", JsonValue::Type::Object, false));
CHECK(transport.type() == JsonValue::Type::Object);
auto &transport_object = transport.get_object();
TRY_RESULT(candidates, get_json_object_field(transport_object, "candidates", JsonValue::Type::Array, false));
TRY_RESULT(fingerprints, get_json_object_field(transport_object, "fingerprints", JsonValue::Type::Array, false));
TRY_RESULT(ufrag, get_json_object_string_field(transport_object, "ufrag", false));
TRY_RESULT(pwd, get_json_object_string_field(transport_object, "pwd", false));
// skip "xmlns", "rtcp-mux"
vector<td_api::object_ptr<td_api::groupCallPayloadFingerprint>> fingerprints_object;
for (auto &fingerprint : fingerprints.get_array()) {
if (fingerprint.type() != JsonValue::Type::Object) {
return Status::Error("Expected JSON object as fingerprint");
}
auto &fingerprint_object = fingerprint.get_object();
TRY_RESULT(hash, get_json_object_string_field(fingerprint_object, "hash", false));
TRY_RESULT(setup, get_json_object_string_field(fingerprint_object, "setup", false));
TRY_RESULT(fingerprint_value, get_json_object_string_field(fingerprint_object, "fingerprint", false));
fingerprints_object.push_back(
td_api::make_object<td_api::groupCallPayloadFingerprint>(hash, setup, fingerprint_value));
}
vector<td_api::object_ptr<td_api::groupCallJoinResponseCandidate>> candidates_object;
for (auto &candidate : candidates.get_array()) {
if (candidate.type() != JsonValue::Type::Object) {
return Status::Error("Expected JSON object as candidate");
}
auto &candidate_object = candidate.get_object();
TRY_RESULT(port, get_json_object_string_field(candidate_object, "port", false));
TRY_RESULT(protocol, get_json_object_string_field(candidate_object, "protocol", false));
TRY_RESULT(network, get_json_object_string_field(candidate_object, "network", false));
TRY_RESULT(generation, get_json_object_string_field(candidate_object, "generation", false));
TRY_RESULT(id, get_json_object_string_field(candidate_object, "id", false));
TRY_RESULT(component, get_json_object_string_field(candidate_object, "component", false));
TRY_RESULT(foundation, get_json_object_string_field(candidate_object, "foundation", false));
TRY_RESULT(priority, get_json_object_string_field(candidate_object, "priority", false));
TRY_RESULT(ip, get_json_object_string_field(candidate_object, "ip", false));
TRY_RESULT(type, get_json_object_string_field(candidate_object, "type", false));
TRY_RESULT(tcp_type, get_json_object_string_field(candidate_object, "tcptype"));
TRY_RESULT(rel_addr, get_json_object_string_field(candidate_object, "rel-addr"));
TRY_RESULT(rel_port, get_json_object_string_field(candidate_object, "rel-port"));
candidates_object.push_back(td_api::make_object<td_api::groupCallJoinResponseCandidate>(
port, protocol, network, generation, id, component, foundation, priority, ip, type, tcp_type, rel_addr,
rel_port));
}
auto payload = td_api::make_object<td_api::groupCallPayload>(ufrag, pwd, std::move(fingerprints_object));
return td_api::make_object<td_api::groupCallJoinResponse>(std::move(payload), std::move(candidates_object));
}
2020-12-06 12:33:15 +01:00
bool GroupCallManager::on_join_group_call_response(InputGroupCallId input_group_call_id, string json_response) {
2020-12-03 17:52:50 +01:00
auto it = pending_join_requests_.find(input_group_call_id);
2020-11-26 12:32:29 +01:00
if (it == pending_join_requests_.end()) {
2020-12-06 12:33:15 +01:00
return false;
2020-11-26 12:32:29 +01:00
}
2020-11-26 15:33:28 +01:00
CHECK(it->second != nullptr);
2020-11-26 12:32:29 +01:00
auto result = get_group_call_join_response_object(std::move(json_response));
2020-12-06 12:33:15 +01:00
bool need_update = false;
2020-11-26 12:32:29 +01:00
if (result.is_error()) {
LOG(ERROR) << "Failed to parse join response JSON object: " << result.error().message();
2020-11-26 15:33:28 +01:00
it->second->promise.set_error(Status::Error(500, "Receive invalid join group call response payload"));
2020-11-26 12:32:29 +01:00
} else {
auto group_call = get_group_call(input_group_call_id);
CHECK(group_call != nullptr);
group_call->is_joined = true;
group_call->source = it->second->source;
2020-11-26 15:33:28 +01:00
it->second->promise.set_value(result.move_as_ok());
2020-12-06 12:33:15 +01:00
need_update = true;
2020-11-26 12:32:29 +01:00
}
pending_join_requests_.erase(it);
2020-12-06 12:33:15 +01:00
return need_update;
2020-11-26 12:32:29 +01:00
}
2020-12-03 17:52:50 +01:00
void GroupCallManager::finish_join_group_call(InputGroupCallId input_group_call_id, uint64 generation, Status error) {
2020-11-26 12:32:29 +01:00
CHECK(error.is_error());
2020-12-03 17:52:50 +01:00
auto it = pending_join_requests_.find(input_group_call_id);
2020-11-27 13:31:00 +01:00
if (it == pending_join_requests_.end() || (generation != 0 && it->second->generation != generation)) {
2020-11-26 12:32:29 +01:00
return;
}
2020-11-26 15:33:28 +01:00
it->second->promise.set_error(std::move(error));
2020-11-26 12:32:29 +01:00
pending_join_requests_.erase(it);
}
2020-12-03 17:52:50 +01:00
void GroupCallManager::toggle_group_call_mute_new_members(GroupCallId group_call_id, bool mute_new_members,
Promise<Unit> &&promise) {
2020-12-03 17:52:50 +01:00
TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id));
int32 flags = telegram_api::phone_toggleGroupCallSettings::JOIN_MUTED_MASK;
2020-12-03 17:52:50 +01:00
td_->create_handler<ToggleGroupCallSettingsQuery>(std::move(promise))
->send(flags, input_group_call_id, mute_new_members);
}
2020-12-03 17:52:50 +01:00
void GroupCallManager::invite_group_call_members(GroupCallId group_call_id, vector<UserId> &&user_ids,
2020-11-29 13:41:03 +01:00
Promise<Unit> &&promise) {
2020-12-03 17:52:50 +01:00
TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id));
2020-11-29 13:41:03 +01:00
vector<tl_object_ptr<telegram_api::InputUser>> input_users;
auto my_user_id = td_->contacts_manager_->get_my_id();
for (auto user_id : user_ids) {
auto input_user = td_->contacts_manager_->get_input_user(user_id);
if (input_user == nullptr) {
return promise.set_error(Status::Error(400, "User not found"));
}
if (user_id == my_user_id) {
// can't invite self
continue;
}
input_users.push_back(std::move(input_user));
2020-11-27 13:22:19 +01:00
}
2020-11-29 13:41:03 +01:00
if (input_users.empty()) {
return promise.set_value(Unit());
}
2020-12-03 17:52:50 +01:00
td_->create_handler<InviteToGroupCallQuery>(std::move(promise))->send(input_group_call_id, std::move(input_users));
2020-11-27 13:22:19 +01:00
}
void GroupCallManager::set_group_call_member_is_speaking(GroupCallId group_call_id, int32 source, bool is_speaking,
Promise<Unit> &&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_value(Unit());
}
if (group_call->source == source) {
if (!group_call->channel_id.is_valid()) {
return promise.set_value(Unit());
}
if (group_call->is_speaking != is_speaking) {
group_call->is_speaking = is_speaking;
if (is_speaking) {
pending_send_speaking_action_timeout_.add_timeout_in(group_call_id.get(), 0.0);
}
}
return promise.set_value(Unit());
}
2020-12-06 08:40:26 +01:00
if (is_speaking) {
// TODO convert source to user_id
// on_user_speaking_in_group_call(group_call_id, user_id, G()->unix_time());
}
// TODO update member list by others speaking actions
promise.set_value(Unit());
}
2020-12-03 17:52:50 +01:00
void GroupCallManager::toggle_group_call_member_is_muted(GroupCallId group_call_id, UserId user_id, bool is_muted,
2020-11-29 13:41:03 +01:00
Promise<Unit> &&promise) {
2020-12-03 17:52:50 +01:00
TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id));
if (!td_->contacts_manager_->have_input_user(user_id)) {
return promise.set_error(Status::Error(400, "Have no access to the user"));
}
2020-12-03 17:52:50 +01:00
td_->create_handler<EditGroupCallMemberQuery>(std::move(promise))->send(input_group_call_id, user_id, is_muted);
}
void GroupCallManager::check_group_call_is_joined(GroupCallId group_call_id, Promise<Unit> &&promise) {
2020-12-03 17:52:50 +01:00
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);
2020-12-06 12:33:15 +01:00
if (group_call == nullptr || !group_call->is_inited) {
return promise.set_error(Status::Error(400, "GROUP_CALL_JOIN_MISSING"));
}
2020-12-06 12:33:15 +01:00
if (!group_call->is_active || !group_call->is_joined) {
return promise.set_value(Unit());
}
auto source = group_call->source;
auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), input_group_call_id, source,
promise = std::move(promise)](Result<Unit> &&result) mutable {
if (result.is_error() && result.error().message() == "GROUP_CALL_JOIN_MISSING") {
send_closure(actor_id, &GroupCallManager::on_group_call_left, input_group_call_id, source);
2020-12-06 12:33:15 +01:00
result = Unit();
}
promise.set_result(std::move(result));
});
td_->create_handler<CheckGroupCallQuery>(std::move(query_promise))->send(input_group_call_id, source);
2020-11-27 15:07:12 +01:00
}
void GroupCallManager::leave_group_call(GroupCallId group_call_id, Promise<Unit> &&promise) {
2020-12-03 17:52:50 +01:00
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"));
}
auto source = group_call->source;
auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), input_group_call_id, source,
promise = std::move(promise)](Result<Unit> &&result) mutable {
if (result.is_ok()) {
send_closure(actor_id, &GroupCallManager::on_group_call_left, input_group_call_id, source);
}
promise.set_result(std::move(result));
});
td_->create_handler<LeaveGroupCallQuery>(std::move(query_promise))->send(input_group_call_id, source);
}
void GroupCallManager::on_group_call_left(InputGroupCallId input_group_call_id, int32 source) {
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;
2020-12-06 12:33:15 +01:00
send_closure(G()->td(), &Td::send_update, get_update_group_call_object(group_call));
}
2020-11-26 11:47:20 +01:00
}
2020-12-03 17:52:50 +01:00
void GroupCallManager::discard_group_call(GroupCallId group_call_id, Promise<Unit> &&promise) {
TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id));
td_->create_handler<DiscardGroupCallQuery>(std::move(promise))->send(input_group_call_id);
2020-11-26 11:47:20 +01:00
}
2020-12-04 10:40:51 +01:00
void GroupCallManager::on_update_group_call(tl_object_ptr<telegram_api::GroupCall> group_call_ptr,
ChannelId channel_id) {
2020-12-04 10:44:09 +01:00
if (td_->auth_manager_->is_bot()) {
LOG(ERROR) << "Receive " << to_string(group_call_ptr);
return;
}
2020-12-04 10:40:51 +01:00
if (!channel_id.is_valid()) {
LOG(ERROR) << "Receive " << to_string(group_call_ptr) << " in invalid " << channel_id;
channel_id = ChannelId();
}
auto call_id = update_group_call(group_call_ptr, channel_id);
2020-11-26 11:47:20 +01:00
if (call_id.is_valid()) {
LOG(INFO) << "Update " << call_id;
} else {
LOG(ERROR) << "Receive invalid " << to_string(group_call_ptr);
}
}
2020-12-04 10:40:51 +01:00
InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptr<telegram_api::GroupCall> &group_call_ptr,
ChannelId channel_id) {
2020-11-26 11:47:20 +01:00
CHECK(group_call_ptr != nullptr);
InputGroupCallId call_id;
GroupCall call;
2020-12-03 17:52:50 +01:00
call.is_inited = true;
2020-12-04 10:40:51 +01:00
string join_params;
2020-11-26 11:47:20 +01:00
switch (group_call_ptr->get_id()) {
case telegram_api::groupCall::ID: {
auto group_call = static_cast<const telegram_api::groupCall *>(group_call_ptr.get());
call_id = InputGroupCallId(group_call->id_, group_call->access_hash_);
call.is_active = true;
call.mute_new_members = group_call->join_muted_;
call.allowed_change_mute_new_members = group_call->can_change_join_muted_;
2020-11-26 11:47:20 +01:00
call.member_count = group_call->participants_count_;
call.version = group_call->version_;
2020-11-26 12:32:29 +01:00
if (group_call->params_ != nullptr) {
join_params = std::move(group_call->params_->data_);
2020-11-26 12:32:29 +01:00
}
2020-11-26 11:47:20 +01:00
break;
}
case telegram_api::groupCallDiscarded::ID: {
auto group_call = static_cast<const telegram_api::groupCallDiscarded *>(group_call_ptr.get());
call_id = InputGroupCallId(group_call->id_, group_call->access_hash_);
call.duration = group_call->duration_;
2020-11-27 13:31:00 +01:00
finish_join_group_call(call_id, 0, Status::Error(400, "Group call ended"));
2020-11-26 11:47:20 +01:00
break;
}
default:
UNREACHABLE();
}
if (!call_id.is_valid() || call.member_count < 0) {
return {};
}
bool need_update = false;
2020-12-04 10:40:51 +01:00
auto *group_call = add_group_call(call_id, channel_id);
call.channel_id = channel_id.is_valid() ? channel_id : group_call->channel_id;
2020-12-03 17:52:50 +01:00
if (!group_call->is_inited) {
call.group_call_id = group_call->group_call_id;
2020-11-26 11:47:20 +01:00
*group_call = std::move(call);
need_update = true;
} else {
if (!group_call->is_active) {
// never update ended calls
} else if (!call.is_active) {
// always update to an ended call, droping also is_joined and is_speaking flags
2020-11-26 11:47:20 +01:00
*group_call = std::move(call);
need_update = true;
if (group_call->channel_id.is_valid()) {
td_->contacts_manager_->on_update_channel_group_call(group_call->channel_id, false, false);
}
2020-11-26 11:47:20 +01:00
} else {
auto mute_flags_changed = call.mute_new_members != group_call->mute_new_members ||
call.allowed_change_mute_new_members != group_call->allowed_change_mute_new_members;
2020-11-26 11:47:20 +01:00
if (call.version > group_call->version) {
if (group_call->channel_id.is_valid()) {
td_->contacts_manager_->on_update_channel_group_call(group_call->channel_id, true, call.member_count == 0);
}
need_update = call.member_count != group_call->member_count || mute_flags_changed;
2020-11-26 11:47:20 +01:00
*group_call = std::move(call);
} else if (call.version == group_call->version) {
if (mute_flags_changed) {
group_call->mute_new_members = call.mute_new_members;
group_call->allowed_change_mute_new_members = call.allowed_change_mute_new_members;
need_update = true;
}
2020-11-26 11:47:20 +01:00
}
}
}
2020-12-06 08:40:26 +01:00
if (!group_call->is_active && group_call_recent_speakers_.erase(group_call->group_call_id) != 0) {
need_update = true;
}
2020-12-04 10:40:51 +01:00
if (!group_call->channel_id.is_valid()) {
group_call->channel_id = channel_id;
}
if (!join_params.empty()) {
2020-12-06 12:33:15 +01:00
need_update |= on_join_group_call_response(call_id, std::move(join_params));
}
2020-11-26 11:47:20 +01:00
if (need_update) {
2020-12-03 17:52:50 +01:00
send_closure(G()->td(), &Td::send_update, get_update_group_call_object(group_call));
2020-11-26 11:47:20 +01:00
}
return call_id;
}
2020-12-06 08:40:26 +01:00
void GroupCallManager::on_user_speaking_in_group_call(GroupCallId group_call_id, UserId user_id, int32 date) {
2020-12-06 19:18:12 +01:00
if (date < G()->unix_time() - RECENT_SPEAKER_TIMEOUT) {
return;
}
2020-12-06 08:40:26 +01:00
auto input_group_call_id = get_input_group_call_id(group_call_id).move_as_ok();
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 = group_call_recent_speakers_[group_call_id];
if (recent_speakers == nullptr) {
recent_speakers = make_unique<GroupCallRecentSpeakers>();
}
for (size_t i = 0; i < recent_speakers->users.size(); i++) {
if (recent_speakers->users[i].first == user_id) {
if (recent_speakers->users[i].second >= date) {
return;
}
recent_speakers->users[i].second = date;
bool is_updated = false;
while (i > 0 && recent_speakers->users[i - 1].second < date) {
std::swap(recent_speakers->users[i - 1], recent_speakers->users[i]);
i--;
is_updated = true;
}
if (is_updated) {
on_group_call_recent_speakers_updated(group_call, recent_speakers.get());
2020-12-06 08:40:26 +01:00
}
return;
}
}
td_->contacts_manager_->get_user_id_object(user_id, "on_user_speaking_in_group_call");
for (size_t i = 0; i < recent_speakers->users.size(); i++) {
if (recent_speakers->users[i].second <= date) {
recent_speakers->users.insert(recent_speakers->users.begin() + i, {user_id, date});
}
}
static constexpr size_t MAX_RECENT_SPEAKERS = 3;
if (recent_speakers->users.size() > MAX_RECENT_SPEAKERS) {
recent_speakers->users.pop_back();
}
on_group_call_recent_speakers_updated(group_call, recent_speakers.get());
2020-12-06 08:40:26 +01:00
}
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) {
2020-12-06 08:40:26 +01:00
return;
}
recent_speakers->is_changed = true;
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);
2020-12-06 08:40:26 +01:00
}
tl_object_ptr<td_api::groupCall> GroupCallManager::get_group_call_object(const GroupCall *group_call,
bool for_update) const {
2020-11-26 11:47:20 +01:00
CHECK(group_call != nullptr);
2020-12-03 17:52:50 +01:00
CHECK(group_call->is_inited);
2020-12-06 08:40:26 +01:00
vector<int32> recent_speaker_user_ids;
auto recent_speakers_it = group_call_recent_speakers_.find(group_call->group_call_id);
if (recent_speakers_it != group_call_recent_speakers_.end()) {
2020-12-06 19:18:12 +01:00
auto *recent_speakers = recent_speakers_it->second.get();
CHECK(recent_speakers != nullptr);
while (!recent_speakers->users.empty() &&
recent_speakers->users.back().second < G()->unix_time() - RECENT_SPEAKER_TIMEOUT) {
recent_speakers->users.pop_back();
}
for (auto &recent_speaker : recent_speakers->users) {
2020-12-06 08:40:26 +01:00
recent_speaker_user_ids.push_back(recent_speaker.first.get());
}
2020-12-06 19:18:12 +01:00
if (recent_speakers->is_changed) {
recent_speakers->is_changed = false;
recent_speaker_update_timeout_.cancel_timeout(group_call->group_call_id.get());
}
2020-12-06 19:18:12 +01:00
if (!recent_speakers->users.empty()) {
auto next_timeout = recent_speakers->users.back().second + RECENT_SPEAKER_TIMEOUT - G()->unix_time() + 1;
recent_speaker_update_timeout_.add_timeout_in(group_call->group_call_id.get(), next_timeout);
}
if (recent_speakers->last_sent_user_ids != recent_speaker_user_ids) {
recent_speakers->last_sent_user_ids = recent_speaker_user_ids;
if (!for_update) {
// the change must be received through update first
send_closure(G()->td(), &Td::send_update, get_update_group_call_object(group_call));
}
}
2020-12-06 08:40:26 +01:00
}
2020-12-03 17:52:50 +01:00
return td_api::make_object<td_api::groupCall>(group_call->group_call_id.get(), group_call->is_active,
2020-12-06 12:33:15 +01:00
group_call->is_joined, group_call->member_count,
std::move(recent_speaker_user_ids), group_call->mute_new_members,
group_call->allowed_change_mute_new_members, group_call->duration);
2020-11-26 11:47:20 +01:00
}
2020-12-06 08:40:26 +01:00
tl_object_ptr<td_api::updateGroupCall> GroupCallManager::get_update_group_call_object(
const GroupCall *group_call) const {
return td_api::make_object<td_api::updateGroupCall>(get_group_call_object(group_call, true));
2020-11-26 11:47:20 +01:00
}
} // namespace td