From 2225e56906da30b164e3c184be30b036a7aa0445 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 30 Apr 2021 19:53:39 +0300 Subject: [PATCH] Add startGroupCallScreenSharing. --- td/generate/scheme/td_api.tl | 7 +- td/telegram/GroupCallManager.cpp | 131 +++++++++++++++++++++++++++++-- td/telegram/GroupCallManager.h | 15 +++- td/telegram/Td.cpp | 15 ++++ td/telegram/Td.h | 2 + td/telegram/UpdatesManager.cpp | 22 +++++- td/telegram/UpdatesManager.h | 2 + td/telegram/cli.cpp | 13 ++- 8 files changed, 189 insertions(+), 18 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 11e97e677..853135f6c 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4612,15 +4612,18 @@ startScheduledGroupCall group_call_id:int32 = Ok; //@group_call_id Group call identifier @enabled_start_notification New value of the enabled_start_notification setting toggleGroupCallEnabledStartNotification group_call_id:int32 enabled_start_notification:Bool = Ok; -//@description Joins an active group call +//@description Joins an active group call. Returns join response payload for tgcalls //@group_call_id Group call identifier //@participant_id Identifier of a group call participant, which will be used to join the call; voice chats only //@audio_source Caller audio synchronization source identifier; received from tgcalls -//@payload Group join payload; received from tgcalls +//@payload Group call join payload; received from tgcalls //@is_muted True, if the user's microphone is muted //@invite_hash If non-empty, invite hash to be used to join the group call without being muted by administrators joinGroupCall group_call_id:int32 participant_id:MessageSender audio_source:int32 payload:string is_muted:Bool invite_hash:string = Text; +//@description Starts screen sharing in a joined group call. Returns join response payload for tgcalls @group_call_id Group call identifier @payload Group call join payload; received from tgcalls +startGroupCallScreenSharing group_call_id:int32 payload:string = Text; + //@description Sets group call title. Requires groupCall.can_be_managed group call flag @group_call_id Group call identifier @title New group call title; 1-64 characters setGroupCallTitle group_call_id:int32 title:string = Ok; diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index ce432c23d..881a33fb8 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -404,6 +404,41 @@ class JoinGroupCallQuery : public Td::ResultHandler { } }; +class JoinGroupCallPresentationQuery : public Td::ResultHandler { + InputGroupCallId input_group_call_id_; + uint64 generation_ = 0; + + public: + NetQueryRef send(InputGroupCallId input_group_call_id, const string &payload, uint64 generation) { + input_group_call_id_ = input_group_call_id; + generation_ = generation; + + auto query = G()->net_query_creator().create(telegram_api::phone_joinGroupCallPresentation( + input_group_call_id.get_input_group_call(), make_tl_object(payload))); + auto join_query_ref = query.get_weak(); + send_query(std::move(query)); + return join_query_ref; + } + + void on_result(uint64 id, BufferSlice packet) override { + auto result_ptr = fetch_result(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 JoinGroupCallPresentationQuery with generation " << generation_ << ": " + << to_string(ptr); + td->group_call_manager_->process_join_group_call_presentation_response(input_group_call_id_, generation_, + std::move(ptr), Status::OK()); + } + + void on_error(uint64 id, Status status) override { + td->group_call_manager_->process_join_group_call_presentation_response(input_group_call_id_, generation_, nullptr, + std::move(status)); + } +}; + class EditGroupCallTitleQuery : public Td::ResultHandler { Promise promise_; @@ -2170,6 +2205,22 @@ int32 GroupCallManager::cancel_join_group_call_request(InputGroupCallId input_gr return audio_source; } +int32 GroupCallManager::cancel_join_group_call_presentation_request(InputGroupCallId input_group_call_id) { + auto it = pending_join_presentation_requests_.find(input_group_call_id); + if (it == pending_join_presentation_requests_.end()) { + return 0; + } + + 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")); + auto audio_source = it->second->audio_source; + pending_join_presentation_requests_.erase(it); + return audio_source; +} + void GroupCallManager::get_group_call_stream_segment(GroupCallId group_call_id, int64 time_offset, int32 scale, Promise &&promise) { if (G()->close_flag()) { @@ -2279,7 +2330,7 @@ void GroupCallManager::start_scheduled_group_call(GroupCallId group_call_id, Pro } void GroupCallManager::join_group_call(GroupCallId group_call_id, DialogId as_dialog_id, int32 audio_source, - const string &payload, bool is_muted, const string &invite_hash, + string &&payload, bool is_muted, const string &invite_hash, Promise &&promise) { TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id)); @@ -2382,6 +2433,49 @@ void GroupCallManager::join_group_call(GroupCallId group_call_id, DialogId as_di try_load_group_call_administrators(input_group_call_id, group_call->dialog_id); } +void GroupCallManager::start_group_call_screen_sharing(GroupCallId group_call_id, string &&payload, + 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); + CHECK(group_call != nullptr); + if (!group_call->is_inited || !group_call->is_active) { + return promise.set_error(Status::Error(400, "GROUPCALL_JOIN_MISSING")); + } + if (!group_call->is_joined || group_call->is_being_left) { + if (is_group_call_being_joined(input_group_call_id) || group_call->need_rejoin) { + group_call->after_join.push_back( + PromiseCreator::lambda([actor_id = actor_id(this), group_call_id, payload = std::move(payload), + promise = std::move(promise)](Result &&result) mutable { + if (result.is_error()) { + promise.set_error(Status::Error(400, "GROUPCALL_JOIN_MISSING")); + } else { + send_closure(actor_id, &GroupCallManager::start_group_call_screen_sharing, group_call_id, + std::move(payload), std::move(promise)); + } + })); + return; + } + return promise.set_error(Status::Error(400, "GROUPCALL_JOIN_MISSING")); + } + + cancel_join_group_call_presentation_request(input_group_call_id); + + auto generation = ++join_group_request_generation_; + auto &request = pending_join_presentation_requests_[input_group_call_id]; + request = make_unique(); + request->generation = generation; + request->promise = std::move(promise); + + request->query_ref = + td_->create_handler()->send(input_group_call_id, payload, generation); + + bool need_update = false; + if (group_call->is_inited && need_update) { + send_update_group_call(group_call, "start_group_call_screen_sharing"); + } +} + void GroupCallManager::try_load_group_call_administrators(InputGroupCallId input_group_call_id, DialogId dialog_id) { if (!dialog_id.is_valid() || !need_group_call_participants(input_group_call_id) || can_manage_group_calls(dialog_id).is_error()) { @@ -2455,6 +2549,29 @@ void GroupCallManager::process_join_group_call_response(InputGroupCallId input_g })); } +void GroupCallManager::process_join_group_call_presentation_response(InputGroupCallId input_group_call_id, + uint64 generation, + tl_object_ptr &&updates, + Status status) { + auto it = pending_join_presentation_requests_.find(input_group_call_id); + if (it == pending_join_presentation_requests_.end() || it->second->generation != generation) { + LOG(INFO) << "Ignore JoinGroupCallPresentationQuery response with " << input_group_call_id << " and generation " + << generation; + return; + } + auto promise = std::move(it->second->promise); + pending_join_presentation_requests_.erase(it); + + string params = UpdatesManager::extract_join_group_call_presentation_params(updates.get()); + if (params.empty()) { + return promise.set_error( + Status::Error(500, "Wrong start group call screen sharing response received: parameters are missing")); + } + td_->updates_manager_->on_get_updates( + std::move(updates), PromiseCreator::lambda([params = std::move(params), promise = std::move(promise)]( + Unit) mutable { promise.set_value(std::move(params)); })); +} + bool GroupCallManager::on_join_group_call_response(InputGroupCallId input_group_call_id, string json_response) { auto it = pending_join_requests_.find(input_group_call_id); if (it == pending_join_requests_.end()) { @@ -3459,11 +3576,11 @@ void GroupCallManager::discard_group_call(GroupCallId group_call_id, Promisecreate_handler(std::move(promise))->send(input_group_call_id); } -void GroupCallManager::on_update_group_call_connection(bool is_presentation, string &&connection_params) { - if (!pending_group_call_join_params_[is_presentation].empty()) { - LOG(ERROR) << "Receive duplicate connection params for " << (is_presentation ? "pesentation" : "video"); +void GroupCallManager::on_update_group_call_connection(string &&connection_params) { + if (!pending_group_call_join_params_.empty()) { + LOG(ERROR) << "Receive duplicate connection params"; } - pending_group_call_join_params_[is_presentation] = std::move(connection_params); + pending_group_call_join_params_ = std::move(connection_params); } void GroupCallManager::on_update_group_call(tl_object_ptr group_call_ptr, DialogId dialog_id) { @@ -3602,8 +3719,8 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptr &&promise); - void join_group_call(GroupCallId group_call_id, DialogId as_dialog_id, int32 audio_source, const string &payload, + void join_group_call(GroupCallId group_call_id, DialogId as_dialog_id, int32 audio_source, string &&payload, bool is_muted, const string &invite_hash, Promise &&promise); + void start_group_call_screen_sharing(GroupCallId group_call_id, string &&payload, Promise &&promise); + void set_group_call_title(GroupCallId group_call_id, string title, Promise &&promise); void toggle_group_call_start_subscribed(GroupCallId group_call_id, bool start_subscribed, Promise &&promise); @@ -102,7 +104,7 @@ class GroupCallManager : public Actor { void on_update_dialog_about(DialogId dialog_id, const string &about, bool from_server); - void on_update_group_call_connection(bool is_presentation, string &&connection_params); + void on_update_group_call_connection(string &&connection_params); void on_update_group_call(tl_object_ptr group_call_ptr, DialogId dialog_id); @@ -120,6 +122,9 @@ class GroupCallManager : public Actor { void process_join_group_call_response(InputGroupCallId input_group_call_id, uint64 generation, tl_object_ptr &&updates, Promise &&promise); + void process_join_group_call_presentation_response(InputGroupCallId input_group_call_id, uint64 generation, + tl_object_ptr &&updates, Status status); + private: struct GroupCall; struct GroupCallParticipants; @@ -229,6 +234,8 @@ class GroupCallManager : public Actor { int32 cancel_join_group_call_request(InputGroupCallId input_group_call_id); + int32 cancel_join_group_call_presentation_request(InputGroupCallId input_group_call_id); + bool on_join_group_call_response(InputGroupCallId input_group_call_id, string json_response); void finish_join_group_call(InputGroupCallId input_group_call_id, uint64 generation, Status error); @@ -325,7 +332,7 @@ class GroupCallManager : public Actor { std::unordered_map, InputGroupCallIdHash> group_calls_; - string pending_group_call_join_params_[2]; + string pending_group_call_join_params_; std::unordered_map, InputGroupCallIdHash> group_call_participants_; @@ -337,6 +344,8 @@ class GroupCallManager : public Actor { load_group_call_queries_; std::unordered_map, InputGroupCallIdHash> pending_join_requests_; + std::unordered_map, InputGroupCallIdHash> + pending_join_presentation_requests_; uint64 join_group_request_generation_ = 0; uint64 toggle_recording_generation_ = 0; diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 0bf146813..5e3f7d886 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -6035,6 +6035,21 @@ void Td::on_request(uint64 id, td_api::joinGroupCall &request) { request.invite_hash_, std::move(query_promise)); } +void Td::on_request(uint64 id, td_api::startGroupCallScreenSharing &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.payload_); + CREATE_REQUEST_PROMISE(); + auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(make_tl_object(result.move_as_ok())); + } + }); + group_call_manager_->start_group_call_screen_sharing(GroupCallId(request.group_call_id_), std::move(request.payload_), + std::move(query_promise)); +} + void Td::on_request(uint64 id, td_api::setGroupCallTitle &request) { CHECK_IS_USER(); CLEAN_INPUT_STRING(request.title_); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index d426c5c8d..3400e0872 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -715,6 +715,8 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, td_api::joinGroupCall &request); + void on_request(uint64 id, td_api::startGroupCallScreenSharing &request); + void on_request(uint64 id, td_api::setGroupCallTitle &request); void on_request(uint64 id, const td_api::toggleGroupCallMuteNewParticipants &request); diff --git a/td/telegram/UpdatesManager.cpp b/td/telegram/UpdatesManager.cpp index c7d3d0c5f..3c54678b1 100644 --- a/td/telegram/UpdatesManager.cpp +++ b/td/telegram/UpdatesManager.cpp @@ -1031,6 +1031,20 @@ vector UpdatesManager::get_update_new_group_call_ids(const tel return input_group_call_ids; } +string UpdatesManager::extract_join_group_call_presentation_params(telegram_api::Updates *updates_ptr) { + auto updates = get_updates(updates_ptr); + for (auto it = updates->begin(); it != updates->end(); ++it) { + auto *update = it->get(); + if (update->get_id() == telegram_api::updateGroupCallConnection::ID && + static_cast(update)->presentation_) { + string result = std::move(static_cast(update)->params_->data_); + updates->erase(it); + return result; + } + } + return string(); +} + vector UpdatesManager::get_update_notify_settings_dialog_ids(const telegram_api::Updates *updates_ptr) { vector dialog_ids; auto updates = get_updates(updates_ptr); @@ -2836,8 +2850,12 @@ void UpdatesManager::on_update(tl_object_ptr update, Promise &&promise) { - send_closure(G()->group_call_manager(), &GroupCallManager::on_update_group_call_connection, update->presentation_, - std::move(update->params_->data_)); + if (update->presentation_) { + LOG(ERROR) << "Receive unexpected updateGroupCallConnection"; + } else { + send_closure(G()->group_call_manager(), &GroupCallManager::on_update_group_call_connection, + std::move(update->params_->data_)); + } promise.set_value(Unit()); } diff --git a/td/telegram/UpdatesManager.h b/td/telegram/UpdatesManager.h index 10c318df8..d83bad7be 100644 --- a/td/telegram/UpdatesManager.h +++ b/td/telegram/UpdatesManager.h @@ -104,6 +104,8 @@ class UpdatesManager : public Actor { static vector get_update_new_group_call_ids(const telegram_api::Updates *updates_ptr); + static string extract_join_group_call_presentation_params(telegram_api::Updates *updates_ptr); + static vector get_update_notify_settings_dialog_ids(const telegram_api::Updates *updates_ptr); static vector get_chat_dialog_ids(const telegram_api::Updates *updates_ptr); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index c4ed33809..91c66dd06 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2691,7 +2691,7 @@ class CliClient final : public Actor { } else if (op == "tgcesn" || op == "tgcesne") { send_request(td_api::make_object(as_group_call_id(args), op == "tgcesne")); - } else if (op == "jgc" || op == "jgcv") { + } else if (op == "jgc" || op == "jgcv" || op == "sgcss") { string group_call_id; string participant_id; string invite_hash; @@ -2711,9 +2711,14 @@ class CliClient final : public Actor { "ietf:params:rtp-hdrext:ssrc-audio-level\"}],\"ssrc-groups\":[{\"sources\":[1,2],\"semantics\":\"SIM\"},{" "\"sources\":[3,4],\"semantics\":\"FID\"}]}"; } - send_request(td_api::make_object(as_group_call_id(group_call_id), - as_message_sender(participant_id), group_call_source_, - std::move(payload), true, invite_hash)); + if (op == "sgcss") { + send_request(td_api::make_object(as_group_call_id(group_call_id), + std::move(payload))); + } else { + send_request(td_api::make_object(as_group_call_id(group_call_id), + as_message_sender(participant_id), group_call_source_, + std::move(payload), true, invite_hash)); + } } else if (op == "sgct") { string chat_id; string title;