// // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022 // // 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) // #pragma once #include "td/telegram/CallDiscardReason.h" #include "td/telegram/CallId.h" #include "td/telegram/DhConfig.h" #include "td/telegram/files/FileId.h" #include "td/telegram/net/NetQuery.h" #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" #include "td/telegram/UserId.h" #include "td/mtproto/DhHandshake.h" #include "td/actor/actor.h" #include "td/utils/common.h" #include "td/utils/Container.h" #include "td/utils/Promise.h" #include "td/utils/Status.h" #include namespace td { struct CallProtocol { bool udp_p2p{true}; bool udp_reflector{true}; int32 min_layer{65}; int32 max_layer{65}; vector library_versions; CallProtocol() = default; explicit CallProtocol(const td_api::callProtocol &protocol); explicit CallProtocol(const telegram_api::phoneCallProtocol &protocol); tl_object_ptr get_input_phone_call_protocol() const; tl_object_ptr get_call_protocol_object() const; }; struct CallConnection { enum class Type : int32 { Telegram, Webrtc }; Type type; int64 id; string ip; string ipv6; int32 port; // Telegram string peer_tag; bool is_tcp = false; // WebRTC string username; string password; bool supports_turn = false; bool supports_stun = false; explicit CallConnection(const telegram_api::PhoneConnection &connection); tl_object_ptr get_call_server_object() const; }; struct CallState { enum class Type : int32 { Empty, Pending, ExchangingKey, Ready, HangingUp, Discarded, Error } type{Type::Empty}; CallProtocol protocol; vector connections; CallDiscardReason discard_reason{CallDiscardReason::Empty}; bool is_created{false}; bool is_received{false}; bool need_debug_information{false}; bool need_rating{false}; bool need_log{false}; int64 key_fingerprint{0}; string key; string config; vector emojis_fingerprint; bool allow_p2p{false}; Status error; tl_object_ptr get_call_state_object() const; }; class CallActor final : public NetQueryCallback { public: CallActor(CallId call_id, ActorShared<> parent, Promise promise); void create_call(UserId user_id, tl_object_ptr &&input_user, CallProtocol &&protocol, bool is_video, Promise &&promise); void accept_call(CallProtocol &&protocol, Promise promise); void update_call_signaling_data(string data); void send_call_signaling_data(string &&data, Promise promise); void discard_call(bool is_disconnected, int32 duration, bool is_video, int64 connection_id, Promise promise); void rate_call(int32 rating, string comment, vector> &&problems, Promise promise); void send_call_debug_information(string data, Promise promise); void send_call_log(td_api::object_ptr log_file, Promise promise); void update_call(tl_object_ptr call); private: void update_call_inner(tl_object_ptr call); ActorShared<> parent_; Promise call_id_promise_; mtproto::DhHandshake dh_handshake_; std::shared_ptr dh_config_; bool dh_config_query_sent_{false}; bool dh_config_ready_{false}; int32 duration_{0}; int64 connection_id_{0}; enum class State : int32 { Empty, SendRequestQuery, WaitRequestResult, SendAcceptQuery, WaitAcceptResult, SendConfirmQuery, WaitConfirmResult, SendDiscardQuery, WaitDiscardResult, Discarded } state_{State::Empty}; bool is_accepted_{false}; bool is_outgoing_{false}; bool is_video_{false}; UserId user_id_; tl_object_ptr input_user_; CallId local_call_id_; int64 call_id_{0}; bool is_call_id_inited_{false}; bool has_notification_{false}; int64 call_access_hash_{0}; UserId call_admin_user_id_; // UserId call_participant_user_id_; CallState call_state_; bool call_state_need_flush_{false}; bool call_state_has_config_{false}; NetQueryRef request_query_ref_; tl_object_ptr get_input_phone_call(const char *source); bool load_dh_config(); void on_dh_config(Result> r_dh_config, bool dummy); void do_load_dh_config(Promise> promise); Status do_update_call(telegram_api::phoneCallEmpty &call); Status do_update_call(telegram_api::phoneCallWaiting &call); Status do_update_call(telegram_api::phoneCallRequested &call); Status do_update_call(telegram_api::phoneCallAccepted &call); Status do_update_call(telegram_api::phoneCall &call); Status do_update_call(telegram_api::phoneCallDiscarded &call); void send_received_query(); void on_received_query_result(Result r_net_query); void try_send_request_query(); void on_request_query_result(Result r_net_query); void try_send_accept_query(); void on_accept_query_result(Result r_net_query); void try_send_confirm_query(); void on_confirm_query_result(Result r_net_query); void try_send_discard_query(); void on_discard_query_result(Result r_net_query); void on_begin_exchanging_key(); void on_call_discarded(CallDiscardReason reason, bool need_rating, bool need_debug, bool is_video); void on_set_rating_query_result(Result r_net_query); void on_save_debug_query_result(Result r_net_query); void upload_log_file(FileId file_id, Promise &&promise); void on_upload_log_file(FileId file_id, Promise &&promise, tl_object_ptr input_file); void on_upload_log_file_error(FileId file_id, Promise &&promise, Status status); void do_upload_log_file(FileId file_id, tl_object_ptr &&input_file, Promise &&promise); void on_save_log_query_result(FileId file_id, Promise promise, Result r_net_query); void on_get_call_config_result(Result r_net_query); void flush_call_state(); static vector get_emojis_fingerprint(const string &key, const string &g_a); void start_up() final; void loop() final; Container> container_; void on_result(NetQueryPtr query) final; void send_with_promise(NetQueryPtr query, Promise promise); void timeout_expired() final; void hangup() final; void on_error(Status status); }; } // namespace td