1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
|
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2026
//
// 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/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 "td/utils/StringBuilder.h"
#include <memory>
namespace td {
class Td;
struct CallProtocol {
bool udp_p2p{true};
bool udp_reflector{true};
int32 min_layer{65};
int32 max_layer{65};
vector<string> library_versions;
CallProtocol() = default;
explicit CallProtocol(const td_api::callProtocol &protocol);
explicit CallProtocol(const telegram_api::phoneCallProtocol &protocol);
telegram_api::object_ptr<telegram_api::phoneCallProtocol> get_input_phone_call_protocol() const;
td_api::object_ptr<td_api::callProtocol> 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<td_api::callServer> get_call_server_object() const;
};
struct CallState {
enum class Type : int32 { Empty, Pending, ExchangingKey, Ready, HangingUp, Discarded, Error } type{Type::Empty};
CallProtocol protocol;
vector<CallConnection> connections;
CallDiscardReason discard_reason;
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<string> emojis_fingerprint;
string custom_parameters;
bool allow_p2p{false};
bool conference_supported{false};
Status error;
tl_object_ptr<td_api::CallState> get_call_state_object() const;
};
class CallActor final : public NetQueryCallback {
public:
CallActor(Td *td, CallId call_id, ActorShared<> parent, Promise<int64> promise);
static int64 get_recent_call_access_hash(int64 call_id);
void create_call(UserId user_id, CallProtocol &&protocol, bool is_video, Promise<CallId> &&promise);
void accept_call(CallProtocol &&protocol, Promise<Unit> promise);
void update_call_signaling_data(string data);
void send_call_signaling_data(string &&data, Promise<Unit> promise);
void discard_call(bool is_disconnected, const string &invite_link, int32 duration, bool is_video, int64 connection_id,
Promise<Unit> promise);
void get_input_phone_call_to_promise(Promise<telegram_api::object_ptr<telegram_api::inputPhoneCall>> &&promise);
void on_set_call_rating();
void on_save_debug_information(bool result);
void on_save_log();
void update_call(tl_object_ptr<telegram_api::PhoneCall> call);
private:
Td *td_;
ActorShared<> parent_;
Promise<int64> call_id_promise_;
mtproto::DhHandshake dh_handshake_;
std::shared_ptr<DhConfig> 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,
Ready,
SendDiscardQuery,
WaitDiscardResult,
Discarded
} state_{State::Empty};
bool is_accepted_{false};
bool is_outgoing_{false};
bool is_video_{false};
UserId user_id_;
CallId local_call_id_;
int64 call_id_{0};
bool is_call_id_inited_{false};
bool is_call_id_saved_{false};
bool has_notification_{false};
int64 call_access_hash_{0};
UserId call_admin_user_id_;
CallState call_state_;
bool call_state_need_flush_{false};
bool call_state_has_config_{false};
NetQueryRef request_query_ref_;
void update_call_inner(tl_object_ptr<telegram_api::phone_phoneCall> call);
tl_object_ptr<telegram_api::inputPhoneCall> get_input_phone_call(const char *source);
bool load_dh_config();
void on_dh_config(Result<std::shared_ptr<DhConfig>> r_dh_config, bool dummy);
void do_load_dh_config(Promise<std::shared_ptr<DhConfig>> promise);
Status do_update_call(const telegram_api::phoneCallEmpty &call);
Status do_update_call(const telegram_api::phoneCallWaiting &call);
Status do_update_call(const telegram_api::phoneCallRequested &call);
Status do_update_call(const telegram_api::phoneCallAccepted &call);
Status do_update_call(telegram_api::phoneCall &call);
Status do_update_call(const telegram_api::phoneCallDiscarded &call);
void on_get_call_id();
void send_received_query();
void on_received_query_result(Result<NetQueryPtr> r_net_query);
void try_send_request_query();
void on_request_query_result(Result<NetQueryPtr> r_net_query);
void try_send_accept_query();
void on_accept_query_result(Result<NetQueryPtr> r_net_query);
void try_send_confirm_query();
void on_confirm_query_result(Result<NetQueryPtr> r_net_query);
void try_send_discard_query();
void on_discard_query_result(Result<NetQueryPtr> 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_get_call_config_result(Result<NetQueryPtr> r_net_query);
void flush_call_state();
static vector<string> get_emojis_fingerprint(const string &key, const string &g_a);
friend StringBuilder &operator<<(StringBuilder &string_builder, const State &state);
void start_up() final;
void loop() final;
Container<Promise<NetQueryPtr>> container_;
void on_result(NetQueryPtr query) final;
void send_with_promise(NetQueryPtr query, Promise<NetQueryPtr> promise);
void timeout_expired() final;
void hangup() final;
void on_error(Status status);
};
} // namespace td
|