diff --git a/Telegram/SourceFiles/calls/calls_instance.cpp b/Telegram/SourceFiles/calls/calls_instance.cpp index 2cb521d116..145869b109 100644 --- a/Telegram/SourceFiles/calls/calls_instance.cpp +++ b/Telegram/SourceFiles/calls/calls_instance.cpp @@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mtproto/mtproto_dh_utils.h" #include "core/application.h" #include "core/core_settings.h" +#include "main/session/session_show.h" #include "main/main_session.h" #include "main/main_account.h" #include "apiwrap.h" @@ -237,14 +238,20 @@ void Instance::startOrJoinGroupCall( } void Instance::startOrJoinConferenceCall(StartConferenceInfo args) { - const auto migrationInfo = (args.migrating && _currentCallPanel) + Expects(args.call || (args.migrating && args.show)); + + const auto migrationInfo = (args.migrating + && args.call + && _currentCallPanel) ? _currentCallPanel->migrationInfo() : ConferencePanelMigration(); - if (!args.migrating) { + if (args.call && !args.migrating) { destroyCurrentCall(); } - const auto session = &args.call->peer()->session(); + const auto session = args.show + ? &args.show->session() + : &args.call->session(); auto call = std::make_unique(_delegate.get(), args); const auto raw = call.get(); @@ -253,20 +260,46 @@ void Instance::startOrJoinConferenceCall(StartConferenceInfo args) { destroyGroupCall(raw); }, raw->lifetime()); + if (args.call) { + _currentGroupCallPanel = std::make_unique( + raw, + migrationInfo); + _currentGroupCall = std::move(call); + _currentGroupCallChanges.fire_copy(raw); + if (args.migrating) { + destroyCurrentCall(args.call.get(), args.linkSlug); + } + } else { + if (const auto was = base::take(_migratingGroupCall)) { + destroyGroupCall(was.get()); + } + _migratingGroupCall = std::move(call); + } +} + +void Instance::migratedConferenceReady( + not_null call, + StartConferenceInfo args) { + if (_migratingGroupCall.get() != call) { + return; + } + const auto migrationInfo = _currentCallPanel + ? _currentCallPanel->migrationInfo() + : ConferencePanelMigration(); _currentGroupCallPanel = std::make_unique( - raw, + call, migrationInfo); - _currentGroupCall = std::move(call); - _currentGroupCallChanges.fire_copy(raw); + _currentGroupCall = std::move(_migratingGroupCall); + _currentGroupCallChanges.fire_copy(call); + const auto real = call->conferenceCall().get(); + const auto link = real->conferenceInviteLink(); + const auto slug = Group::ExtractConferenceSlug(link); if (!args.invite.empty()) { _currentGroupCallPanel->migrationInviteUsers(std::move(args.invite)); - } else if (args.sharingLink && !args.linkSlug.isEmpty()) { + } else if (args.sharingLink) { _currentGroupCallPanel->migrationShowShareLink(); } - - if (args.migrating) { - destroyCurrentCall(args.call.get(), args.linkSlug); - } + destroyCurrentCall(real, slug); } void Instance::confirmLeaveCurrent( @@ -428,6 +461,8 @@ void Instance::destroyGroupCall(not_null call) { LOG(("Calls::Instance doesn't prevent quit any more.")); } Core::App().quitPreventFinished(); + } else if (_migratingGroupCall.get() == call) { + base::take(_migratingGroupCall); } } @@ -658,12 +693,14 @@ void Instance::handleCallUpdate( void Instance::handleGroupCallUpdate( not_null session, const MTPUpdate &update) { - if (_currentGroupCall - && (&_currentGroupCall->peer()->session() == session)) { + const auto groupCall = _currentGroupCall + ? _currentGroupCall.get() + : _migratingGroupCall.get(); + if (groupCall && (&groupCall->peer()->session() == session)) { update.match([&](const MTPDupdateGroupCall &data) { - _currentGroupCall->handlePossibleCreateOrJoinResponse(data); + groupCall->handlePossibleCreateOrJoinResponse(data); }, [&](const MTPDupdateGroupCallConnection &data) { - _currentGroupCall->handlePossibleCreateOrJoinResponse(data); + groupCall->handlePossibleCreateOrJoinResponse(data); }, [](const auto &) { }); } @@ -692,10 +729,8 @@ void Instance::handleGroupCallUpdate( }); if (update.type() == mtpc_updateGroupCallChainBlocks) { const auto existing = session->data().groupCall(callId); - if (existing - && _currentGroupCall - && _currentGroupCall->lookupReal() == existing) { - _currentGroupCall->handleUpdate(update); + if (existing && groupCall && groupCall->lookupReal() == existing) { + groupCall->handleUpdate(update); } } else if (const auto existing = session->data().groupCall(callId)) { existing->enqueueUpdate(update); @@ -707,9 +742,11 @@ void Instance::handleGroupCallUpdate( void Instance::applyGroupCallUpdateChecked( not_null session, const MTPUpdate &update) { - if (_currentGroupCall - && (&_currentGroupCall->peer()->session() == session)) { - _currentGroupCall->handleUpdate(update); + const auto groupCall = _currentGroupCall + ? _currentGroupCall.get() + : _migratingGroupCall.get(); + if (groupCall && (&groupCall->peer()->session() == session)) { + groupCall->handleUpdate(update); } } @@ -761,6 +798,7 @@ void Instance::destroyCurrentCall( } } } + base::take(_migratingGroupCall); } bool Instance::hasVisiblePanel(Main::Session *session) const { diff --git a/Telegram/SourceFiles/calls/calls_instance.h b/Telegram/SourceFiles/calls/calls_instance.h index 1157c777a0..e42bf32af4 100644 --- a/Telegram/SourceFiles/calls/calls_instance.h +++ b/Telegram/SourceFiles/calls/calls_instance.h @@ -86,6 +86,9 @@ public: not_null peer, StartGroupCallArgs args); void startOrJoinConferenceCall(StartConferenceInfo args); + void migratedConferenceReady( + not_null call, + StartConferenceInfo args); void showStartWithRtmp( std::shared_ptr show, not_null peer); @@ -200,6 +203,7 @@ private: std::unique_ptr _currentCallPanel; std::unique_ptr _currentGroupCall; + std::unique_ptr _migratingGroupCall; rpl::event_stream _currentGroupCallChanges; std::unique_ptr _currentGroupCallPanel; diff --git a/Telegram/SourceFiles/calls/calls_panel.cpp b/Telegram/SourceFiles/calls/calls_panel.cpp index 7abf76b029..7f35109fc1 100644 --- a/Telegram/SourceFiles/calls/calls_panel.cpp +++ b/Telegram/SourceFiles/calls/calls_panel.cpp @@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "calls/group/calls_group_invite_controller.h" #include "calls/ui/calls_device_menu.h" #include "calls/calls_emoji_fingerprint.h" +#include "calls/calls_instance.h" #include "calls/calls_signal_bars.h" #include "calls/calls_userpic.h" #include "calls/calls_video_bubble.h" @@ -359,20 +360,16 @@ void Panel::initControls() { } *creating = true; const auto sharingLink = users.empty(); - Group::MakeConferenceCall({ + Core::App().calls().startOrJoinConferenceCall({ .show = sessionShow(), - .finished = [=](bool) { *creating = false; }, - .joining = true, - .info = { - .invite = std::move(users), - .sharingLink = sharingLink, - .migrating = true, - .muted = call->muted(), - .videoCapture = (call->isSharingVideo() - ? call->peekVideoCapture() - : nullptr), - .videoCaptureScreenId = call->screenSharingDeviceId(), - }, + .invite = std::move(users), + .sharingLink = sharingLink, + .migrating = true, + .muted = call->muted(), + .videoCapture = (call->isSharingVideo() + ? call->peekVideoCapture() + : nullptr), + .videoCaptureScreenId = call->screenSharingDeviceId(), }); }; const auto invite = crl::guard(call, [=]( diff --git a/Telegram/SourceFiles/calls/group/calls_group_call.cpp b/Telegram/SourceFiles/calls/group/calls_group_call.cpp index 5f27e80ca5..56d690b771 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_call.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_call.cpp @@ -8,6 +8,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "calls/group/calls_group_call.h" #include "calls/group/calls_group_common.h" +#include "calls/calls_instance.h" +#include "main/session/session_show.h" #include "main/main_app_config.h" #include "main/main_session.h" #include "api/api_send_progress.h" @@ -578,9 +580,11 @@ GroupCall::GroupCall( not_null delegate, StartConferenceInfo info) : GroupCall(delegate, Group::JoinInfo{ - .peer = info.call->peer(), - .joinAs = info.call->peer(), -}, info, info.call->input()) { + .peer = info.call ? info.call->peer() : info.show->session().user(), + .joinAs = info.call ? info.call->peer() : info.show->session().user(), +}, info, info.call + ? info.call->input() + : MTP_inputGroupCall(MTP_long(0), MTP_long(0))) { } GroupCall::GroupCall( @@ -590,7 +594,6 @@ GroupCall::GroupCall( const MTPInputGroupCall &inputCall) : _delegate(delegate) , _conferenceCall(std::move(conference.call)) -, _e2e(std::move(conference.e2e)) , _peer(join.peer) , _history(_peer->owner().history(_peer)) , _api(&_peer->session().mtp()) @@ -602,7 +605,6 @@ GroupCall::GroupCall( , _rtmpUrl(join.rtmpInfo.url) , _rtmpKey(join.rtmpInfo.key) , _canManage(Data::CanManageGroupCallValue(_peer)) -, _id(inputCall.c_inputGroupCall().vid().v) , _scheduleDate(join.scheduleDate) , _lastSpokeCheckTimer([=] { checkLastSpoke(); }) , _checkJoinedTimer([=] { checkJoined(); }) @@ -627,6 +629,8 @@ GroupCall::GroupCall( , _listenersHidden(join.rtmp) , _rtmp(join.rtmp) , _rtmpVolume(Group::kDefaultVolume) { + applyInputCall(inputCall); + _muted.value( ) | rpl::combine_previous( ) | rpl::start_with_next([=](MuteState previous, MuteState state) { @@ -658,7 +662,7 @@ GroupCall::GroupCall( if (!canManage() && real->joinMuted()) { _muted = MuteState::ForceMuted; } - } else { + } else if (!conference.migrating) { _peer->session().changes().peerFlagsValue( _peer, Data::PeerUpdate::Flag::GroupCall @@ -678,19 +682,19 @@ GroupCall::GroupCall( setupMediaDevices(); setupOutgoingVideo(); - if (_conferenceCall) { - setupConferenceCall(); - if (conference.migrating) { - if (!conference.muted) { - setMuted(MuteState::Active); - } - _migratedConferenceInfo = std::make_shared( - std::move(conference)); + if (_conferenceCall || conference.migrating) { + setupConference(); + } + if (conference.migrating) { + if (!conference.muted) { + setMuted(MuteState::Active); } + _migratedConferenceInfo = std::make_shared( + std::move(conference)); } - if (_id) { - this->join(inputCall); + if (_id || (!_conferenceCall && _migratedConferenceInfo)) { + initialJoin(); } else { start(join.scheduleDate, join.rtmp); } @@ -703,6 +707,7 @@ void GroupCall::processMigration(StartConferenceInfo conference) { if (!conference.videoCapture) { return; } + fillActiveVideoEndpoints(); const auto weak = base::make_weak(this); if (!conference.videoCaptureScreenId.isEmpty()) { _screenCapture = std::move(conference.videoCapture); @@ -741,7 +746,7 @@ GroupCall::~GroupCall() { } } -void GroupCall::setupConferenceCall() { +void GroupCall::setupConference() { if (!_e2e) { _e2e = std::make_shared( TdE2E::MakeUserId(_peer->session().user())); @@ -755,10 +760,24 @@ void GroupCall::setupConferenceCall() { sendOutboundBlock(std::move(block)); }, _lifetime); + _e2e->failures() | rpl::start_with_next([=] { + LOG(("TdE2E: Got failure!")); + hangup(); + }, _lifetime); + + if (_conferenceCall) { + setupConferenceCall(); + } +} + +void GroupCall::setupConferenceCall() { + Expects(_conferenceCall != nullptr && _e2e != nullptr); + _conferenceCall->staleParticipantIds( ) | rpl::start_with_next([=](const base::flat_set &staleIds) { removeConferenceParticipants(staleIds, true); }, _lifetime); + _e2e->participantsSetValue( ) | rpl::start_with_next([=](const TdE2E::ParticipantsSet &set) { auto users = base::flat_set(); @@ -768,11 +787,6 @@ void GroupCall::setupConferenceCall() { } _conferenceCall->setParticipantsWithAccess(std::move(users)); }, _lifetime); - - _e2e->failures() | rpl::start_with_next([=] { - LOG(("TdE2E: Got failure!")); - hangup(); - }, _lifetime); } void GroupCall::removeConferenceParticipants( @@ -917,7 +931,7 @@ void GroupCall::setScheduledDate(TimeId date) { const auto was = _scheduleDate; _scheduleDate = date; if (was && !date) { - join(inputCall()); + initialJoin(); } } @@ -1171,7 +1185,7 @@ bool GroupCall::rtmp() const { } bool GroupCall::conference() const { - return _conferenceCall != nullptr; + return _conferenceCall || _migratedConferenceInfo; } bool GroupCall::listenersHidden() const { @@ -1234,31 +1248,40 @@ void GroupCall::start(TimeId scheduleDate, bool rtmp) { MTPstring(), // title MTP_int(scheduleDate) )).done([=](const MTPUpdates &result) { + _createRequestId = 0; _reloadedStaleCall = true; _acceptFields = true; _peer->session().api().applyUpdates(result); _acceptFields = false; }).fail([=](const MTP::Error &error) { + _createRequestId = 0; LOG(("Call Error: Could not create, error: %1" ).arg(error.type())); hangup(); }).send(); } -void GroupCall::join(const MTPInputGroupCall &inputCall) { +void GroupCall::applyInputCall(const MTPInputGroupCall &inputCall) { inputCall.match([&](const MTPDinputGroupCall &data) { _id = data.vid().v; _accessHash = data.vaccess_hash().v; }, [&](const auto &) { Unexpected("slug/msg in GroupCall::join."); }); - setState(_scheduleDate ? State::Waiting : State::Joining); +} +void GroupCall::initialJoin() { + setState(_scheduleDate ? State::Waiting : State::Joining); if (_scheduleDate) { return; } rejoin(); + if (_id) { + initialJoinRequested(); + } +} +void GroupCall::initialJoinRequested() { using Update = Data::GroupCall::ParticipantUpdate; const auto real = lookupReal(); Assert(real != nullptr); @@ -1283,10 +1306,10 @@ void GroupCall::join(const MTPInputGroupCall &inputCall) { _peer->session().updates().addActiveChat( _peerStream.events_starting_with_copy(_peer)); _canManage = Data::CanManageGroupCallValue(_peer); - SubscribeToMigration(_peer, _lifetime, [=](not_null group) { - _peer = group; + SubscribeToMigration(_peer, _lifetime, [=](not_null peer) { + _peer = peer; _canManage = Data::CanManageGroupCallValue(_peer); - _peerStream.fire_copy(group); + _peerStream.fire_copy(peer); }); } @@ -1499,7 +1522,7 @@ void GroupCall::rejoin(not_null as) { && state() != State::Joined && state() != State::Connecting) { return; - } else if (_joinState.action != JoinAction::None) { + } else if (_joinState.action != JoinAction::None || _createRequestId) { return; } @@ -1529,7 +1552,11 @@ void GroupCall::rejoin(not_null as) { }; LOG(("Call Info: Join payload received, joining with ssrc: %1." ).arg(_joinState.payload.ssrc)); - sendJoinRequest(); + if (!_conferenceCall && _migratedConferenceInfo) { + startConference(); + } else { + sendJoinRequest(); + } }); }); } @@ -1540,7 +1567,7 @@ void GroupCall::sendJoinRequest() { checkNextJoinAction(); return; } - auto joinBlock = _e2e ? _e2e->makeJoinBlock().data : QByteArray(); + const auto joinBlock = _e2e ? _e2e->makeJoinBlock().data : QByteArray(); if (_e2e && joinBlock.isEmpty()) { _joinState.finish(); LOG(("Call Error: Could not generate join block.")); @@ -1554,12 +1581,8 @@ void GroupCall::sendJoinRequest() { const auto flags = (wasMuteState != MuteState::Active ? Flag::f_muted : Flag(0)) - | (_joinHash.isEmpty() - ? Flag(0) - : Flag::f_invite_hash) - | (wasVideoStopped - ? Flag::f_video_stopped - : Flag(0)) + | (_joinHash.isEmpty() ? Flag(0) : Flag::f_invite_hash) + | (wasVideoStopped ? Flag::f_video_stopped : Flag(0)) | (_e2e ? (Flag::f_public_key | Flag::f_block) : Flag()); _api.request(MTPphone_JoinGroupCall( MTP_flags(flags), @@ -1570,74 +1593,15 @@ void GroupCall::sendJoinRequest() { MTP_bytes(joinBlock), MTP_dataJSON(MTP_bytes(_joinState.payload.json)) )).done([=]( - const MTPUpdates &updates, + const MTPUpdates &result, const MTP::Response &response) { - _serverTimeMs = TimestampInMsFromMsgId(response.outerMsgId); - _serverTimeMsGotAt = crl::now(); - - _joinState.finish(_joinState.payload.ssrc); - _mySsrcs.emplace(_joinState.ssrc); - - setState((_instanceState.current() - == InstanceState::Disconnected) - ? State::Connecting - : State::Joined); - applyMeInCallLocally(); - maybeSendMutedUpdate(wasMuteState); - _peer->session().api().applyUpdates(updates); - applyQueuedSelfUpdates(); - checkFirstTimeJoined(); - _screenJoinState.nextActionPending = true; - checkNextJoinAction(); - if (wasVideoStopped == isSharingCamera()) { - sendSelfUpdate(SendUpdateType::CameraStopped); - } - if (isCameraPaused()) { - sendSelfUpdate(SendUpdateType::CameraPaused); - } - sendPendingSelfUpdates(); - if (!_reloadedStaleCall - && _state.current() != State::Joining) { - if (const auto real = lookupReal()) { - _reloadedStaleCall = true; - real->reloadIfStale(); - } - } - if (_e2e) { - _e2e->joined(); - if (!_pendingOutboundBlock.isEmpty()) { - sendOutboundBlock(base::take(_pendingOutboundBlock)); - } - } - if (const auto once = base::take(_migratedConferenceInfo)) { - processMigration(*once); - } - for (const auto &callback : base::take(_rejoinedCallbacks)) { - callback(); - } + joinDone( + TimestampInMsFromMsgId(response.outerMsgId), + result, + wasMuteState, + wasVideoStopped); }).fail([=](const MTP::Error &error) { - const auto type = error.type(); - if (_e2e) { - if (type == u"BLOCK_INVALID"_q - || type.startsWith(u"CONF_WRITE_CHAIN_INVALID"_q)) { - refreshLastBlockAndJoin(); - return; - } - } - _joinState.finish(); - - LOG(("Call Error: Could not join, error: %1").arg(type)); - - if (type == u"GROUPCALL_SSRC_DUPLICATE_MUCH") { - rejoin(); - return; - } - - hangup(); - Ui::Toast::Show((type == u"GROUPCALL_FORBIDDEN"_q - || type == u"GROUPCALL_INVALID"_q) - ? tr::lng_confcall_not_accessible(tr::now) - : type); + joinFail(error.type()); }).send(); } @@ -1685,6 +1649,144 @@ void GroupCall::refreshLastBlockAndJoin() { }).send(); } +void GroupCall::startConference() { + Expects(_e2e != nullptr && _migratedConferenceInfo != nullptr); + + const auto joinBlock = _e2e->makeJoinBlock().data; + Assert(!joinBlock.isEmpty()); + + const auto wasMuteState = muted(); + const auto wasVideoStopped = !isSharingCamera(); + using Flag = MTPphone_CreateConferenceCall::Flag; + const auto flags = Flag::f_join + | Flag::f_public_key + | Flag::f_block + | Flag::f_params + | ((wasMuteState != MuteState::Active) ? Flag::f_muted : Flag(0)) + | (wasVideoStopped ? Flag::f_video_stopped : Flag(0)); + _createRequestId = _api.request(MTPphone_CreateConferenceCall( + MTP_flags(flags), + MTP_int(base::RandomValue()), + TdE2E::PublicKeyToMTP(_e2e->myKey()), + MTP_bytes(joinBlock), + MTP_dataJSON(MTP_bytes(_joinState.payload.json)) + )).done([=]( + const MTPUpdates &result, + const MTP::Response &response) { + _createRequestId = 0; + _conferenceCall = _peer->owner().sharedConferenceCallFind(result); + if (!_conferenceCall) { + joinFail(u"Call not found!"_q); + return; + } + applyInputCall(_conferenceCall->input()); + initialJoinRequested(); + joinDone( + TimestampInMsFromMsgId(response.outerMsgId), + result, + wasMuteState, + wasVideoStopped, + true); + }).fail([=](const MTP::Error &error) { + _createRequestId = 0; + LOG(("Call Error: Could not create, error: %1" + ).arg(error.type())); + hangup(); + }).send(); +} + +void GroupCall::joinDone( + int64 serverTimeMs, + const MTPUpdates &result, + MuteState wasMuteState, + bool wasVideoStopped, + bool justCreated) { + Expects(!justCreated || _migratedConferenceInfo != nullptr); + + _serverTimeMs = serverTimeMs; + _serverTimeMsGotAt = crl::now(); + + _joinState.finish(_joinState.payload.ssrc); + _mySsrcs.emplace(_joinState.ssrc); + + setState((_instanceState.current() + == InstanceState::Disconnected) + ? State::Connecting + : State::Joined); + applyMeInCallLocally(); + maybeSendMutedUpdate(wasMuteState); + + _peer->session().api().applyUpdates(result); + + if (justCreated) { + subscribeToReal(_conferenceCall.get()); + setupConferenceCall(); + _conferenceLinkSlug = Group::ExtractConferenceSlug( + _conferenceCall->conferenceInviteLink()); + Core::App().calls().migratedConferenceReady( + this, + *_migratedConferenceInfo); + } + + applyQueuedSelfUpdates(); + checkFirstTimeJoined(); + _screenJoinState.nextActionPending = true; + checkNextJoinAction(); + if (wasVideoStopped == isSharingCamera()) { + sendSelfUpdate(SendUpdateType::CameraStopped); + } + if (isCameraPaused()) { + sendSelfUpdate(SendUpdateType::CameraPaused); + } + sendPendingSelfUpdates(); + if (!_reloadedStaleCall + && _state.current() != State::Joining) { + if (const auto real = lookupReal()) { + _reloadedStaleCall = true; + real->reloadIfStale(); + } + } + if (_e2e) { + _e2e->joined(); + if (!_pendingOutboundBlock.isEmpty()) { + sendOutboundBlock(base::take(_pendingOutboundBlock)); + } + } + if (const auto once = base::take(_migratedConferenceInfo)) { + processMigration(*once); + } + for (const auto &callback : base::take(_rejoinedCallbacks)) { + callback(); + } +} + +void GroupCall::joinFail(const QString &error) { + if (_e2e) { + if (error == u"BLOCK_INVALID"_q + || error.startsWith(u"CONF_WRITE_CHAIN_INVALID"_q)) { + if (_id) { + refreshLastBlockAndJoin(); + } else { + hangup(); + } + return; + } + } + _joinState.finish(); + LOG(("Call Error: Could not join, error: %1").arg(error)); + + if (_id && error == u"GROUPCALL_SSRC_DUPLICATE_MUCH") { + rejoin(); + return; + } + + hangup(); + Ui::Toast::Show((error == u"GROUPCALL_FORBIDDEN"_q + || error == u"GROUPCALL_INVALID"_q) + ? tr::lng_confcall_not_accessible(tr::now) + : error); +} + void GroupCall::requestSubchainBlocks(int subchain, int height) { Expects(subchain >= 0 && subchain < kSubChainsCount); @@ -2168,7 +2270,8 @@ void GroupCall::handlePossibleCreateOrJoinResponse( } else { Unexpected("Peer type in GroupCall::join."); } - join(input); + applyInputCall(input); + initialJoin(); } return; } else if (_id != data.vid().v || !_instance) { @@ -3768,7 +3871,6 @@ void GroupCall::editParticipant( }).send(); } - void GroupCall::inviteToConference( InviteRequest request, Fn()> resultAddress, diff --git a/Telegram/SourceFiles/calls/group/calls_group_call.h b/Telegram/SourceFiles/calls/group/calls_group_call.h index 7b29f357c3..236290a189 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_call.h +++ b/Telegram/SourceFiles/calls/group/calls_group_call.h @@ -263,12 +263,15 @@ public: [[nodiscard]] rpl::producer> real() const; [[nodiscard]] rpl::producer emojiHashValue() const; + void applyInputCall(const MTPInputGroupCall &inputCall); + void startConference(); void start(TimeId scheduleDate, bool rtmp); void hangup(); void discard(); void rejoinAs(Group::JoinInfo info); void rejoinWithHash(const QString &hash); - void join(const MTPInputGroupCall &inputCall); + void initialJoin(); + void initialJoinRequested(); void handleUpdate(const MTPUpdate &update); void handlePossibleCreateOrJoinResponse(const MTPDupdateGroupCall &data); void handlePossibleCreateOrJoinResponse( @@ -292,6 +295,14 @@ public: bool emitShareScreenError(); bool emitShareCameraError(); + void joinDone( + int64 serverTimeMs, + const MTPUpdates &result, + MuteState wasMuteState, + bool wasVideoStopped, + bool justCreated = false); + void joinFail(const QString &error); + [[nodiscard]] rpl::producer errors() const { return _errors.events(); } @@ -610,6 +621,7 @@ private: void setupMediaDevices(); void setupOutgoingVideo(); + void setupConference(); void setupConferenceCall(); void setScreenEndpoint(std::string endpoint); void setCameraEndpoint(std::string endpoint); @@ -635,7 +647,7 @@ private: [[nodiscard]] MTPInputGroupCall inputCallSafe() const; const not_null _delegate; - const std::shared_ptr _conferenceCall; + std::shared_ptr _conferenceCall; std::shared_ptr _e2e; QByteArray _pendingOutboundBlock; std::shared_ptr _migratedConferenceInfo; diff --git a/Telegram/SourceFiles/calls/group/calls_group_common.cpp b/Telegram/SourceFiles/calls/group/calls_group_common.cpp index a1db17f0a7..1b98ad2306 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_common.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_common.cpp @@ -18,6 +18,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_group_call.h" #include "data/data_session.h" #include "info/bot/starref/info_bot_starref_common.h" +#include "tde2e/tde2e_api.h" +#include "tde2e/tde2e_integration.h" #include "ui/boxes/boost_box.h" #include "ui/widgets/buttons.h" #include "ui/widgets/labels.h" @@ -41,24 +43,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include namespace Calls::Group { -namespace { - -[[nodiscard]] QString ExtractConferenceSlug(const QString &link) { - const auto local = Core::TryConvertUrlToLocal(link); - const auto parts1 = QStringView(local).split('#'); - if (!parts1.isEmpty()) { - const auto parts2 = parts1.front().split('&'); - if (!parts2.isEmpty()) { - const auto parts3 = parts2.front().split(u"slug="_q); - if (parts3.size() > 1) { - return parts3.back().toString(); - } - } - } - return QString(); -} - -} // namespace object_ptr ScreenSharingPrivacyRequestBox() { #ifdef Q_OS_MAC @@ -468,32 +452,13 @@ void MakeConferenceCall(ConferenceFactoryArgs &&args) { MTPbytes(), // block MTPDataJSON() // params )).done([=](const MTPUpdates &result) { - session->api().applyUpdates(result); - const auto updates = result.match([&](const MTPDupdates &data) { - return &data.vupdates().v; - }, [&](const MTPDupdatesCombined &data) { - return &data.vupdates().v; - }, [](const auto &) { - return (const QVector*)nullptr; - }); - if (!updates) { + auto call = session->data().sharedConferenceCallFind(result); + if (!call) { fail(u"Call not found!"_q); return; } - auto call = std::shared_ptr(); - for (const auto &update : *updates) { - update.match([&](const MTPDupdateGroupCall &data) { - data.vcall().match([&](const auto &data) { - call = session->data().sharedConferenceCall( - data.vid().v, - data.vaccess_hash().v); - call->enqueueUpdate(update); - }); - }, [](const auto &) {}); - if (call) { - break; - } - } + session->api().applyUpdates(result); + const auto link = call ? call->conferenceInviteLink() : QString(); if (link.isEmpty()) { fail(u"Call link not found!"_q); @@ -521,4 +486,19 @@ void MakeConferenceCall(ConferenceFactoryArgs &&args) { }).send(); } +QString ExtractConferenceSlug(const QString &link) { + const auto local = Core::TryConvertUrlToLocal(link); + const auto parts1 = QStringView(local).split('#'); + if (!parts1.isEmpty()) { + const auto parts2 = parts1.front().split('&'); + if (!parts2.isEmpty()) { + const auto parts3 = parts2.front().split(u"slug="_q); + if (parts3.size() > 1) { + return parts3.back().toString(); + } + } + } + return QString(); +} + } // namespace Calls::Group diff --git a/Telegram/SourceFiles/calls/group/calls_group_common.h b/Telegram/SourceFiles/calls/group/calls_group_common.h index 8407791535..0afe320964 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_common.h +++ b/Telegram/SourceFiles/calls/group/calls_group_common.h @@ -64,8 +64,8 @@ struct InviteResult { }; struct StartConferenceInfo { + std::shared_ptr show; std::shared_ptr call; - std::shared_ptr e2e; QString linkSlug; MsgId joinMessageId; std::vector invite; @@ -195,4 +195,6 @@ struct ConferenceFactoryArgs { }; void MakeConferenceCall(ConferenceFactoryArgs &&args); +[[nodiscard]] QString ExtractConferenceSlug(const QString &link); + } // namespace Calls::Group diff --git a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp index b55e375891..fd70aa6e69 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp @@ -376,6 +376,8 @@ void Panel::initWindow() { _window->setControlsStyle(st::groupCallTitle); _window->togglePowerSaveBlocker(true); + + uiShow()->hideLayer(anim::type::instant); } void Panel::initWidget() { @@ -927,7 +929,6 @@ Fn Panel::shareConferenceLinkCallback() { } void Panel::migrationShowShareLink() { - uiShow()->hideLayer(anim::type::instant); ShowConferenceCallLinkBox( sessionShow(), _call->conferenceCall(), diff --git a/Telegram/SourceFiles/data/data_group_call.cpp b/Telegram/SourceFiles/data/data_group_call.cpp index cb4b06cb32..05ee4bc787 100644 --- a/Telegram/SourceFiles/data/data_group_call.cpp +++ b/Telegram/SourceFiles/data/data_group_call.cpp @@ -374,6 +374,7 @@ auto GroupCall::staleParticipantIds() const } void GroupCall::enqueueUpdate(const MTPUpdate &update) { + const auto initial = !_version; update.match([&](const MTPDupdateGroupCall &updateData) { updateData.vcall().match([&](const MTPDgroupCall &data) { const auto version = data.vversion().v; @@ -427,7 +428,7 @@ void GroupCall::enqueueUpdate(const MTPUpdate &update) { }, [](const auto &) { Unexpected("Type in GroupCall::enqueueUpdate."); }); - processQueuedUpdates(); + processQueuedUpdates(initial); } void GroupCall::discard(const MTPDgroupCallDiscarded &data) { @@ -562,7 +563,7 @@ void GroupCall::applyEnqueuedUpdate(const MTPUpdate &update) { Core::App().calls().applyGroupCallUpdateChecked(&session(), update); } -void GroupCall::processQueuedUpdates() { +void GroupCall::processQueuedUpdates(bool initial) { if (!_version || _applyingQueuedUpdates) { return; } @@ -574,7 +575,13 @@ void GroupCall::processQueuedUpdates() { const auto type = entry.first.second; const auto incremented = (type == QueuedType::VersionedParticipant); if ((version < _version) - || (version == _version && incremented)) { + || (version == _version && incremented && !initial)) { + // There is a case for a new conference call we receive: + // - updateGroupCall, version = 2 + // - updateGroupCallParticipants, version = 2, versioned + // In case we were joining together with creation, + // in that case we don't want to skip the participants update, + // so we pass the `initial` flag specifically for that case. _queuedUpdates.erase(_queuedUpdates.begin()); } else if (version == _version || (version == _version + 1 && incremented)) { diff --git a/Telegram/SourceFiles/data/data_group_call.h b/Telegram/SourceFiles/data/data_group_call.h index f335e84680..20c5b08f8a 100644 --- a/Telegram/SourceFiles/data/data_group_call.h +++ b/Telegram/SourceFiles/data/data_group_call.h @@ -215,7 +215,7 @@ private: void applyEnqueuedUpdate(const MTPUpdate &update); void setServerParticipantsCount(int count); void computeParticipantsCount(); - void processQueuedUpdates(); + void processQueuedUpdates(bool initial = false); void processFullCallUsersChats(const MTPphone_GroupCall &call); void processFullCallFields(const MTPphone_GroupCall &call); [[nodiscard]] bool requestParticipantsAfterReload( diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 6bc8eaca38..78974d85e3 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -1159,6 +1159,36 @@ std::shared_ptr Session::sharedConferenceCall( return result; } +std::shared_ptr Session::sharedConferenceCallFind( + const MTPUpdates &response) { + const auto list = response.match([&](const MTPDupdates &data) { + return &data.vupdates().v; + }, [&](const MTPDupdatesCombined &data) { + return &data.vupdates().v; + }, [](const auto &) { + return (const QVector*)nullptr; + }); + const auto empty = std::shared_ptr(); + if (!list) { + return empty; + } + for (const auto &update : *list) { + const auto call = update.match([&](const MTPDupdateGroupCall &data) { + return data.vcall().match([&](const MTPDgroupCall &data) { + return data.is_conference() + ? sharedConferenceCall( + data.vid().v, + data.vaccess_hash().v) + : nullptr; + }, [&](const auto &) { return empty; }); + }, [&](const auto &) { return empty; }); + if (call) { + return call; + } + } + return empty; +} + void Session::watchForOffline(not_null user, TimeId now) { if (!now) { now = base::unixtime::now(); diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index bb810a7e37..d46290d775 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -235,6 +235,8 @@ public: [[nodiscard]] std::shared_ptr sharedConferenceCall( CallId id, uint64 accessHash); + [[nodiscard]] std::shared_ptr sharedConferenceCallFind( + const MTPUpdates &response); void watchForOffline(not_null user, TimeId now = 0); void maybeStopWatchForOffline(not_null user); diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index d35e50f0b4..9ca1596b89 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -882,7 +882,7 @@ void SessionNavigation::resolveConferenceCall( data.vaccess_hash().v); call->processFullCall(result); const auto join = [=](Fn close) { - const auto &appConfig = call->peer()->session().appConfig(); + const auto &appConfig = call->session().appConfig(); const auto conferenceLimit = appConfig.confcallSizeLimit(); if (call->fullCount() >= conferenceLimit) { showToast(tr::lng_confcall_participants_limit(tr::now));