/* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include "base/timer.h" class PeerData; class ApiWrap; namespace Calls { struct ParticipantVideoParams; } // namespace Calls namespace Data { struct LastSpokeTimes { crl::time anything = 0; crl::time voice = 0; }; struct GroupCallParticipant { not_null peer; std::shared_ptr videoParams; TimeId date = 0; TimeId lastActive = 0; uint64 raisedHandRating = 0; uint32 ssrc = 0; int volume = 0; bool sounding : 1; bool speaking : 1; bool additionalSounding : 1; bool additionalSpeaking : 1; bool muted : 1; bool mutedByMe : 1; bool canSelfUnmute : 1; bool onlyMinLoaded : 1; bool videoJoined = false; bool applyVolumeFromMin = true; [[nodiscard]] const std::string &cameraEndpoint() const; [[nodiscard]] const std::string &screenEndpoint() const; [[nodiscard]] bool cameraPaused() const; [[nodiscard]] bool screenPaused() const; }; class GroupCall final { public: GroupCall( not_null peer, uint64 id, uint64 accessHash, TimeId scheduleDate); ~GroupCall(); [[nodiscard]] uint64 id() const; [[nodiscard]] bool loaded() const; [[nodiscard]] not_null peer() const; [[nodiscard]] MTPInputGroupCall input() const; [[nodiscard]] QString title() const { return _title.current(); } [[nodiscard]] rpl::producer titleValue() const { return _title.value(); } void setTitle(const QString &title) { _title = title; } [[nodiscard]] TimeId recordStartDate() const { return _recordStartDate.current(); } [[nodiscard]] rpl::producer recordStartDateValue() const { return _recordStartDate.value(); } [[nodiscard]] rpl::producer recordStartDateChanges() const { return _recordStartDate.changes(); } [[nodiscard]] TimeId scheduleDate() const { return _scheduleDate.current(); } [[nodiscard]] rpl::producer scheduleDateValue() const { return _scheduleDate.value(); } [[nodiscard]] rpl::producer scheduleDateChanges() const { return _scheduleDate.changes(); } [[nodiscard]] bool scheduleStartSubscribed() const { return _scheduleStartSubscribed.current(); } [[nodiscard]] rpl::producer scheduleStartSubscribedValue() const { return _scheduleStartSubscribed.value(); } [[nodiscard]] int unmutedVideoLimit() const { return _unmutedVideoLimit.current(); } [[nodiscard]] bool recordVideo() const { return _recordVideo.current(); } void setPeer(not_null peer); using Participant = GroupCallParticipant; struct ParticipantUpdate { std::optional was; std::optional now; }; static constexpr auto kSoundStatusKeptFor = crl::time(1500); [[nodiscard]] auto participants() const -> const std::vector &; void requestParticipants(); [[nodiscard]] bool participantsLoaded() const; [[nodiscard]] PeerData *participantPeerByAudioSsrc(uint32 ssrc) const; [[nodiscard]] const Participant *participantByPeer( not_null peer) const; [[nodiscard]] const Participant *participantByEndpoint( const std::string &endpoint) const; [[nodiscard]] rpl::producer<> participantsReloaded(); [[nodiscard]] auto participantUpdated() const -> rpl::producer; [[nodiscard]] auto participantSpeaking() const -> rpl::producer>; void enqueueUpdate(const MTPUpdate &update); void applyLocalUpdate( const MTPDupdateGroupCallParticipants &update); void applyLastSpoke(uint32 ssrc, LastSpokeTimes when, crl::time now); void applyActiveUpdate( PeerId participantPeerId, LastSpokeTimes when, PeerData *participantPeerLoaded); void resolveParticipants(const base::flat_set &ssrcs); [[nodiscard]] rpl::producer< not_null*>> participantsResolved() const { return _participantsResolved.events(); } [[nodiscard]] int fullCount() const; [[nodiscard]] rpl::producer fullCountValue() const; void setInCall(); void reload(); void processFullCall(const MTPphone_GroupCall &call); void setJoinMutedLocally(bool muted); [[nodiscard]] bool joinMuted() const; [[nodiscard]] bool canChangeJoinMuted() const; [[nodiscard]] bool joinedToTop() const; private: enum class ApplySliceSource { FullReloaded, SliceLoaded, UnknownLoaded, UpdateReceived, UpdateConstructed, }; enum class QueuedType : uint8 { VersionedParticipant, Participant, Call, }; [[nodiscard]] ApiWrap &api() const; void discard(const MTPDgroupCallDiscarded &data); [[nodiscard]] bool inCall() const; void applyParticipantsSlice( const QVector &list, ApplySliceSource sliceSource); void requestUnknownParticipants(); void changePeerEmptyCallFlag(); void checkFinishSpeakingByActive(); void applyCallFields(const MTPDgroupCall &data); void applyEnqueuedUpdate(const MTPUpdate &update); void setServerParticipantsCount(int count); void computeParticipantsCount(); void processQueuedUpdates(); void processFullCallUsersChats(const MTPphone_GroupCall &call); void processFullCallFields(const MTPphone_GroupCall &call); [[nodiscard]] bool requestParticipantsAfterReload( const MTPphone_GroupCall &call) const; [[nodiscard]] bool processSavedFullCall(); void finishParticipantsSliceRequest(); [[nodiscard]] Participant *findParticipant(not_null peer); const uint64 _id = 0; const uint64 _accessHash = 0; not_null _peer; int _version = 0; mtpRequestId _participantsRequestId = 0; mtpRequestId _reloadRequestId = 0; rpl::variable _title; base::flat_multi_map< std::pair, MTPUpdate> _queuedUpdates; base::Timer _reloadByQueuedUpdatesTimer; std::optional _savedFull; std::vector _participants; base::flat_map> _participantPeerByAudioSsrc; base::flat_map, crl::time> _speakingByActiveFinishes; base::Timer _speakingByActiveFinishTimer; QString _nextOffset; int _serverParticipantsCount = 0; rpl::variable _fullCount = 0; rpl::variable _unmutedVideoLimit = 0; rpl::variable _recordVideo = 0; rpl::variable _recordStartDate = 0; rpl::variable _scheduleDate = 0; rpl::variable _scheduleStartSubscribed = false; base::flat_map _unknownSpokenSsrcs; base::flat_map _unknownSpokenPeerIds; rpl::event_stream< not_null*>> _participantsResolved; mtpRequestId _unknownParticipantPeersRequestId = 0; rpl::event_stream _participantUpdates; rpl::event_stream> _participantSpeaking; rpl::event_stream<> _participantsReloaded; bool _joinMuted = false; bool _canChangeJoinMuted = true; bool _allParticipantsLoaded = false; bool _joinedToTop = false; bool _applyingQueuedUpdates = false; }; } // namespace Data