1 /*
2 This file is part of Telegram Desktop,
3 the official desktop application for the Telegram messaging service.
4 
5 For license and copyright information please follow this link:
6 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
7 */
8 #pragma once
9 
10 #include "base/timer.h"
11 
12 class PeerData;
13 
14 class ApiWrap;
15 
16 namespace Calls {
17 struct ParticipantVideoParams;
18 } // namespace Calls
19 
20 namespace Data {
21 
22 struct LastSpokeTimes {
23 	crl::time anything = 0;
24 	crl::time voice = 0;
25 };
26 
27 struct GroupCallParticipant {
28 	not_null<PeerData*> peer;
29 	std::shared_ptr<Calls::ParticipantVideoParams> videoParams;
30 	TimeId date = 0;
31 	TimeId lastActive = 0;
32 	uint64 raisedHandRating = 0;
33 	uint32 ssrc = 0;
34 	int volume = 0;
35 	bool sounding : 1;
36 	bool speaking : 1;
37 	bool additionalSounding : 1;
38 	bool additionalSpeaking : 1;
39 	bool muted : 1;
40 	bool mutedByMe : 1;
41 	bool canSelfUnmute : 1;
42 	bool onlyMinLoaded : 1;
43 	bool videoJoined = false;
44 	bool applyVolumeFromMin = true;
45 
46 	[[nodiscard]] const std::string &cameraEndpoint() const;
47 	[[nodiscard]] const std::string &screenEndpoint() const;
48 	[[nodiscard]] bool cameraPaused() const;
49 	[[nodiscard]] bool screenPaused() const;
50 };
51 
52 class GroupCall final {
53 public:
54 	GroupCall(
55 		not_null<PeerData*> peer,
56 		CallId id,
57 		CallId accessHash,
58 		TimeId scheduleDate);
59 	~GroupCall();
60 
61 	[[nodiscard]] CallId id() const;
62 	[[nodiscard]] bool loaded() const;
63 	[[nodiscard]] not_null<PeerData*> peer() const;
64 	[[nodiscard]] MTPInputGroupCall input() const;
title()65 	[[nodiscard]] QString title() const {
66 		return _title.current();
67 	}
titleValue()68 	[[nodiscard]] rpl::producer<QString> titleValue() const {
69 		return _title.value();
70 	}
setTitle(const QString & title)71 	void setTitle(const QString &title) {
72 		_title = title;
73 	}
recordStartDate()74 	[[nodiscard]] TimeId recordStartDate() const {
75 		return _recordStartDate.current();
76 	}
recordStartDateValue()77 	[[nodiscard]] rpl::producer<TimeId> recordStartDateValue() const {
78 		return _recordStartDate.value();
79 	}
recordStartDateChanges()80 	[[nodiscard]] rpl::producer<TimeId> recordStartDateChanges() const {
81 		return _recordStartDate.changes();
82 	}
scheduleDate()83 	[[nodiscard]] TimeId scheduleDate() const {
84 		return _scheduleDate.current();
85 	}
scheduleDateValue()86 	[[nodiscard]] rpl::producer<TimeId> scheduleDateValue() const {
87 		return _scheduleDate.value();
88 	}
scheduleDateChanges()89 	[[nodiscard]] rpl::producer<TimeId> scheduleDateChanges() const {
90 		return _scheduleDate.changes();
91 	}
scheduleStartSubscribed()92 	[[nodiscard]] bool scheduleStartSubscribed() const {
93 		return _scheduleStartSubscribed.current();
94 	}
scheduleStartSubscribedValue()95 	[[nodiscard]] rpl::producer<bool> scheduleStartSubscribedValue() const {
96 		return _scheduleStartSubscribed.value();
97 	}
unmutedVideoLimit()98 	[[nodiscard]] int unmutedVideoLimit() const {
99 		return _unmutedVideoLimit.current();
100 	}
recordVideo()101 	[[nodiscard]] bool recordVideo() const {
102 		return _recordVideo.current();
103 	}
104 
105 	void setPeer(not_null<PeerData*> peer);
106 
107 	using Participant = GroupCallParticipant;
108 	struct ParticipantUpdate {
109 		std::optional<Participant> was;
110 		std::optional<Participant> now;
111 	};
112 
113 	static constexpr auto kSoundStatusKeptFor = crl::time(1500);
114 
115 	[[nodiscard]] auto participants() const
116 		-> const std::vector<Participant> &;
117 	void requestParticipants();
118 	[[nodiscard]] bool participantsLoaded() const;
119 	[[nodiscard]] PeerData *participantPeerByAudioSsrc(uint32 ssrc) const;
120 	[[nodiscard]] const Participant *participantByPeer(
121 		not_null<PeerData*> peer) const;
122 	[[nodiscard]] const Participant *participantByEndpoint(
123 		const std::string &endpoint) const;
124 
125 	[[nodiscard]] rpl::producer<> participantsReloaded();
126 	[[nodiscard]] auto participantUpdated() const
127 		-> rpl::producer<ParticipantUpdate>;
128 	[[nodiscard]] auto participantSpeaking() const
129 		-> rpl::producer<not_null<Participant*>>;
130 
131 	void enqueueUpdate(const MTPUpdate &update);
132 	void applyLocalUpdate(
133 		const MTPDupdateGroupCallParticipants &update);
134 
135 	void applyLastSpoke(uint32 ssrc, LastSpokeTimes when, crl::time now);
136 	void applyActiveUpdate(
137 		PeerId participantPeerId,
138 		LastSpokeTimes when,
139 		PeerData *participantPeerLoaded);
140 
141 	void resolveParticipants(const base::flat_set<uint32> &ssrcs);
142 	[[nodiscard]] rpl::producer<
143 		not_null<const base::flat_map<
144 			uint32,
participantsResolved()145 			LastSpokeTimes>*>> participantsResolved() const {
146 		return _participantsResolved.events();
147 	}
148 
149 	[[nodiscard]] int fullCount() const;
150 	[[nodiscard]] rpl::producer<int> fullCountValue() const;
151 
152 	void setInCall();
153 	void reload();
154 	void processFullCall(const MTPphone_GroupCall &call);
155 
156 	void setJoinMutedLocally(bool muted);
157 	[[nodiscard]] bool joinMuted() const;
158 	[[nodiscard]] bool canChangeJoinMuted() const;
159 	[[nodiscard]] bool joinedToTop() const;
160 
161 private:
162 	enum class ApplySliceSource {
163 		FullReloaded,
164 		SliceLoaded,
165 		UnknownLoaded,
166 		UpdateReceived,
167 		UpdateConstructed,
168 	};
169 	enum class QueuedType : uint8 {
170 		VersionedParticipant,
171 		Participant,
172 		Call,
173 	};
174 	[[nodiscard]] ApiWrap &api() const;
175 
176 	void discard(const MTPDgroupCallDiscarded &data);
177 	[[nodiscard]] bool inCall() const;
178 	void applyParticipantsSlice(
179 		const QVector<MTPGroupCallParticipant> &list,
180 		ApplySliceSource sliceSource);
181 	void requestUnknownParticipants();
182 	void changePeerEmptyCallFlag();
183 	void checkFinishSpeakingByActive();
184 	void applyCallFields(const MTPDgroupCall &data);
185 	void applyEnqueuedUpdate(const MTPUpdate &update);
186 	void setServerParticipantsCount(int count);
187 	void computeParticipantsCount();
188 	void processQueuedUpdates();
189 	void processFullCallUsersChats(const MTPphone_GroupCall &call);
190 	void processFullCallFields(const MTPphone_GroupCall &call);
191 	[[nodiscard]] bool requestParticipantsAfterReload(
192 		const MTPphone_GroupCall &call) const;
193 	[[nodiscard]] bool processSavedFullCall();
194 	void finishParticipantsSliceRequest();
195 	[[nodiscard]] Participant *findParticipant(not_null<PeerData*> peer);
196 
197 	const CallId _id = 0;
198 	const CallId _accessHash = 0;
199 
200 	not_null<PeerData*> _peer;
201 	int _version = 0;
202 	mtpRequestId _participantsRequestId = 0;
203 	mtpRequestId _reloadRequestId = 0;
204 	rpl::variable<QString> _title;
205 
206 	base::flat_multi_map<
207 		std::pair<int, QueuedType>,
208 		MTPUpdate> _queuedUpdates;
209 	base::Timer _reloadByQueuedUpdatesTimer;
210 	std::optional<MTPphone_GroupCall> _savedFull;
211 
212 	std::vector<Participant> _participants;
213 	base::flat_map<uint32, not_null<PeerData*>> _participantPeerByAudioSsrc;
214 	base::flat_map<not_null<PeerData*>, crl::time> _speakingByActiveFinishes;
215 	base::Timer _speakingByActiveFinishTimer;
216 	QString _nextOffset;
217 	int _serverParticipantsCount = 0;
218 	rpl::variable<int> _fullCount = 0;
219 	rpl::variable<int> _unmutedVideoLimit = 0;
220 	rpl::variable<bool> _recordVideo = 0;
221 	rpl::variable<TimeId> _recordStartDate = 0;
222 	rpl::variable<TimeId> _scheduleDate = 0;
223 	rpl::variable<bool> _scheduleStartSubscribed = false;
224 
225 	base::flat_map<uint32, LastSpokeTimes> _unknownSpokenSsrcs;
226 	base::flat_map<PeerId, LastSpokeTimes> _unknownSpokenPeerIds;
227 	rpl::event_stream<
228 		not_null<const base::flat_map<
229 			uint32,
230 			LastSpokeTimes>*>> _participantsResolved;
231 	mtpRequestId _unknownParticipantPeersRequestId = 0;
232 
233 	rpl::event_stream<ParticipantUpdate> _participantUpdates;
234 	rpl::event_stream<not_null<Participant*>> _participantSpeaking;
235 	rpl::event_stream<> _participantsReloaded;
236 
237 	bool _joinMuted = false;
238 	bool _canChangeJoinMuted = true;
239 	bool _allParticipantsLoaded = false;
240 	bool _joinedToTop = false;
241 	bool _applyingQueuedUpdates = false;
242 
243 };
244 
245 } // namespace Data
246