diff --git a/Telegram/SourceFiles/calls/group/calls_group_call.cpp b/Telegram/SourceFiles/calls/group/calls_group_call.cpp index 2eaba0ca1..cdb02996f 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_call.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_call.cpp @@ -74,6 +74,11 @@ constexpr auto kMaxMediumQualities = 16; // 4 Fulls or 16 Mediums. return msgId / double(1ULL << 32); } +[[nodiscard]] int64 TimestampInMsFromMsgId(mtpMsgId msgId) { + // return (msgId * 1000) / (1ULL << 32); // Almost... But this overflows. + return ((msgId / (1ULL << 10)) * 1000) / (1ULL << 22); +} + [[nodiscard]] uint64 FindLocalRaisedHandRating( const std::vector &list) { const auto i = ranges::max_element( @@ -95,6 +100,41 @@ using JoinClientFields = std::variant< JoinVideoEndpoint, JoinBroadcastStream>; +class RequestCurrentTimeTask final : public tgcalls::BroadcastPartTask { +public: + RequestCurrentTimeTask( + base::weak_ptr call, + Fn done); + + void done(int64 value); + void cancel() override; + +private: + const base::weak_ptr _call; + Fn _done; + QMutex _mutex; + +}; + +RequestCurrentTimeTask::RequestCurrentTimeTask( + base::weak_ptr call, + Fn done) +: _call(call) +, _done(std::move(done)) { +} + +void RequestCurrentTimeTask::done(int64 value) { + QMutexLocker lock(&_mutex); + if (_done) { + base::take(_done)(value); + } +} + +void RequestCurrentTimeTask::cancel() { + QMutexLocker lock(&_mutex); + _done = nullptr; +} + [[nodiscard]] JoinClientFields ParseJoinResponse(const QByteArray &json) { auto error = QJsonParseError{ 0, QJsonParseError::NoError }; const auto document = QJsonDocument::fromJson(json, &error); @@ -1273,7 +1313,12 @@ void GroupCall::rejoin(not_null as) { joinAs()->input, MTP_string(_joinHash), MTP_dataJSON(MTP_bytes(json)) - )).done([=](const MTPUpdates &updates) { + )).done([=]( + const MTPUpdates &updates, + const MTP::Response &response) { + _serverTimeMs = TimestampInMsFromMsgId(response.outerMsgId); + _serverTimeMsGotAt = crl::now(); + _joinState.finish(ssrc); _mySsrcs.emplace(ssrc); @@ -2253,6 +2298,16 @@ bool GroupCall::tryCreateController() { .createAudioDeviceModule = Webrtc::AudioDeviceModuleCreator( settings.callAudioBackend()), .videoCapture = _cameraCapture, + .requestCurrentTime = [=, call = base::make_weak(this)]( + std::function done) { + auto result = std::make_shared( + call, + std::move(done)); + crl::on_main(weak, [=] { + result->done(approximateServerTimeInMs()); + }); + return result; + }, .requestAudioBroadcastPart = [=, call = base::make_weak(this)]( int64_t time, int64_t period, @@ -2499,6 +2554,12 @@ void GroupCall::mediaChannelDescriptionsCancel( } } +int64 GroupCall::approximateServerTimeInMs() const { + Expects(_serverTimeMs != 0); + + return _serverTimeMs + (crl::now() - _serverTimeMsGotAt); +} + void GroupCall::updateRequestedVideoChannels() { _requestedVideoChannelsUpdateScheduled = false; const auto real = lookupReal(); diff --git a/Telegram/SourceFiles/calls/group/calls_group_call.h b/Telegram/SourceFiles/calls/group/calls_group_call.h index 6e9a7887e..8eb509dc5 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_call.h +++ b/Telegram/SourceFiles/calls/group/calls_group_call.h @@ -406,16 +406,6 @@ public: private: class LoadPartTask; class MediaChannelDescriptionsTask; - -public: - void broadcastPartStart(std::shared_ptr task); - void broadcastPartCancel(not_null task); - void mediaChannelDescriptionsStart( - std::shared_ptr task); - void mediaChannelDescriptionsCancel( - not_null task); - -private: using GlobalShortcutValue = base::GlobalShortcutValue; using Error = Group::Error; struct SinkPointer; @@ -464,6 +454,14 @@ private: return true; } + void broadcastPartStart(std::shared_ptr task); + void broadcastPartCancel(not_null task); + void mediaChannelDescriptionsStart( + std::shared_ptr task); + void mediaChannelDescriptionsCancel( + not_null task); + [[nodiscard]] int64 approximateServerTimeInMs() const; + [[nodiscard]] bool mediaChannelDescriptionsFill( not_null task, Fn resolved = nullptr); @@ -571,11 +569,14 @@ private: base::flat_set< std::shared_ptr< MediaChannelDescriptionsTask>, - base::pointer_comparator> _mediaChannelDescriptionses; + base::pointer_comparator< + MediaChannelDescriptionsTask>> _mediaChannelDescriptionses; rpl::variable> _joinAs; std::vector> _possibleJoinAs; QString _joinHash; + int64 _serverTimeMs = 0; + crl::time _serverTimeMsGotAt = 0; rpl::variable _muted = MuteState::Muted; rpl::variable _canManage = false;