diff --git a/Telegram/SourceFiles/calls/calls_call.cpp b/Telegram/SourceFiles/calls/calls_call.cpp index ec27eb5f24..29dce419fa 100644 --- a/Telegram/SourceFiles/calls/calls_call.cpp +++ b/Telegram/SourceFiles/calls/calls_call.cpp @@ -437,20 +437,24 @@ void Call::acceptConferenceInvite() { const auto limit = 5; const auto messageId = _conferenceInviteMsgId; const auto session = &_user->session(); + auto info = StartConferenceInfo{ + .joinMessageId = messageId, + .migrating = true, + .muted = muted(), + .videoCapture = isSharingVideo() ? _videoCapture : nullptr, + .videoCaptureScreenId = screenSharingDeviceId(), + }; session->api().request(MTPphone_GetGroupCall( MTP_inputGroupCallInviteMessage(MTP_int(messageId.bare)), MTP_int(limit) - )).done([session, messageId](const MTPphone_GroupCall &result) { + )).done([session, messageId, info](const MTPphone_GroupCall &result) { result.data().vcall().match([&](const auto &data) { - const auto call = session->data().sharedConferenceCall( + auto copy = info; + copy.call = session->data().sharedConferenceCall( data.vid().v, data.vaccess_hash().v); - call->processFullCall(result); - Core::App().calls().startOrJoinConferenceCall({ - .call = call, - .joinMessageId = messageId, - .migrating = true, - }); + copy.call->processFullCall(result); + Core::App().calls().startOrJoinConferenceCall(std::move(copy)); }); }).fail(crl::guard(this, [=](const MTP::Error &error) { handleRequestError(error.type()); @@ -561,7 +565,8 @@ void Call::setupOutgoingVideo() { _videoOutgoing->setState(Webrtc::VideoState::Inactive); } else if (_state.current() != State::Established && (state != Webrtc::VideoState::Inactive) - && (started == Webrtc::VideoState::Inactive)) { + && (started == Webrtc::VideoState::Inactive) + && !conferenceInvite()) { _errors.fire({ ErrorType::NotStartedCall }); _videoOutgoing->setState(Webrtc::VideoState::Inactive); } else if (state != Webrtc::VideoState::Inactive @@ -1451,6 +1456,11 @@ void Call::toggleScreenSharing(std::optional uniqueId) { _videoOutgoing->setState(Webrtc::VideoState::Active); } +auto Call::peekVideoCapture() const +-> std::shared_ptr { + return _videoCapture; +} + auto Call::playbackDeviceIdValue() const -> rpl::producer { return _playbackDeviceId.value(); diff --git a/Telegram/SourceFiles/calls/calls_call.h b/Telegram/SourceFiles/calls/calls_call.h index 90a8eed489..8675d54338 100644 --- a/Telegram/SourceFiles/calls/calls_call.h +++ b/Telegram/SourceFiles/calls/calls_call.h @@ -247,6 +247,8 @@ public: [[nodiscard]] QString screenSharingDeviceId() const; void toggleCameraSharing(bool enabled); void toggleScreenSharing(std::optional uniqueId); + [[nodiscard]] auto peekVideoCapture() const + -> std::shared_ptr; [[nodiscard]] auto playbackDeviceIdValue() const -> rpl::producer; diff --git a/Telegram/SourceFiles/calls/calls_instance.cpp b/Telegram/SourceFiles/calls/calls_instance.cpp index d3eb954eb0..eb622b6bc3 100644 --- a/Telegram/SourceFiles/calls/calls_instance.cpp +++ b/Telegram/SourceFiles/calls/calls_instance.cpp @@ -235,20 +235,13 @@ void Instance::startOrJoinGroupCall( }); } -void Instance::startOrJoinConferenceCall(StartConferenceCallArgs args) { +void Instance::startOrJoinConferenceCall(StartConferenceInfo args) { destroyCurrentCall( args.migrating ? args.call.get() : nullptr, args.migrating ? args.linkSlug : QString()); const auto session = &args.call->peer()->session(); - auto call = std::make_unique( - _delegate.get(), - Calls::Group::ConferenceInfo{ - .call = std::move(args.call), - .e2e = std::move(args.e2e), - .linkSlug = args.linkSlug, - .joinMessageId = args.joinMessageId, - }); + auto call = std::make_unique(_delegate.get(), args); const auto raw = call.get(); session->account().sessionChanges( diff --git a/Telegram/SourceFiles/calls/calls_instance.h b/Telegram/SourceFiles/calls/calls_instance.h index 1c46af7a77..65088d9495 100644 --- a/Telegram/SourceFiles/calls/calls_instance.h +++ b/Telegram/SourceFiles/calls/calls_instance.h @@ -45,10 +45,6 @@ namespace tgcalls { class VideoCaptureInterface; } // namespace tgcalls -namespace TdE2E { -class Call; -} // namespace TdE2E - namespace Calls { class Call; @@ -57,6 +53,7 @@ class GroupCall; class Panel; struct DhConfig; struct InviteRequest; +struct StartConferenceInfo; struct StartGroupCallArgs { enum class JoinConfirm { @@ -69,15 +66,6 @@ struct StartGroupCallArgs { bool scheduleNeeded = false; }; -struct StartConferenceCallArgs { - std::shared_ptr call; - std::shared_ptr e2e; - QString linkSlug; - MsgId joinMessageId; - std::vector invite; - bool migrating = false; -}; - struct ConferenceInviteMessages { base::flat_set incoming; base::flat_set outgoing; @@ -97,7 +85,7 @@ public: std::shared_ptr show, not_null peer, StartGroupCallArgs args); - void startOrJoinConferenceCall(StartConferenceCallArgs args); + void startOrJoinConferenceCall(StartConferenceInfo args); void showStartWithRtmp( std::shared_ptr show, not_null peer); diff --git a/Telegram/SourceFiles/calls/calls_panel.cpp b/Telegram/SourceFiles/calls/calls_panel.cpp index 0d0628f371..ab2605faa9 100644 --- a/Telegram/SourceFiles/calls/calls_panel.cpp +++ b/Telegram/SourceFiles/calls/calls_panel.cpp @@ -477,9 +477,16 @@ void Panel::initControls() { Group::MakeConferenceCall({ .show = uiShow(), .finished = finish, - .invite = std::move(users), .joining = true, - .migrating = true, + .info = { + .invite = std::move(users), + .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 dbb7298671..89d177146d 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_call.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_call.cpp @@ -58,13 +58,10 @@ constexpr auto kMaxMediumQualities = 16; // 4 Fulls or 16 Mediums. constexpr auto kShortPollChainBlocksPerRequest = 50; [[nodiscard]] const Data::GroupCallParticipant *LookupParticipant( - not_null peer, - CallId id, + not_null call, not_null participantPeer) { - const auto call = peer->groupCall(); - return (id && call && call->id() == id) - ? call->participantByPeer(participantPeer) - : nullptr; + const auto real = call->lookupReal(); + return real ? real->participantByPeer(participantPeer) : nullptr; } [[nodiscard]] double TimestampFromMsgId(mtpMsgId msgId) { @@ -578,7 +575,7 @@ GroupCall::GroupCall( GroupCall::GroupCall( not_null delegate, - Group::ConferenceInfo info) + StartConferenceInfo info) : GroupCall(delegate, Group::JoinInfo{ .peer = info.call->peer(), .joinAs = info.call->peer(), @@ -588,7 +585,7 @@ GroupCall::GroupCall( GroupCall::GroupCall( not_null delegate, Group::JoinInfo join, - Group::ConferenceInfo conference, + StartConferenceInfo conference, const MTPInputGroupCall &inputCall) : _delegate(delegate) , _conferenceCall(std::move(conference.call)) @@ -682,6 +679,13 @@ GroupCall::GroupCall( setupOutgoingVideo(); if (_conferenceCall) { setupConferenceCall(); + if (conference.migrating) { + if (!conference.muted) { + setMuted(MuteState::Active); + } + _migratedConferenceInfo = std::make_shared( + std::move(conference)); + } } if (_id) { @@ -694,6 +698,40 @@ GroupCall::GroupCall( } } +void GroupCall::processMigration(StartConferenceInfo conference) { + if (!conference.videoCapture) { + return; + } + const auto weak = base::make_weak(this); + if (!conference.videoCaptureScreenId.isEmpty()) { + _screenCapture = std::move(conference.videoCapture); + _screenDeviceId = conference.videoCaptureScreenId; + _screenCapture->setOnFatalError([=] { + crl::on_main(weak, [=] { + emitShareScreenError(Error::ScreenFailed); + }); + }); + _screenCapture->setOnPause([=](bool paused) { + crl::on_main(weak, [=] { + if (isSharingScreen()) { + _screenState = paused + ? Webrtc::VideoState::Paused + : Webrtc::VideoState::Active; + } + }); + }); + _screenState = Webrtc::VideoState::Active; + } else { + _cameraCapture = std::move(conference.videoCapture); + _cameraCapture->setOnFatalError([=] { + crl::on_main(weak, [=] { + emitShareCameraError(Error::CameraFailed); + }); + }); + _cameraState = Webrtc::VideoState::Active; + } +} + GroupCall::~GroupCall() { destroyScreencast(); destroyController(); @@ -1578,6 +1616,9 @@ void GroupCall::sendJoinRequest() { sendOutboundBlock(base::take(_pendingOutboundBlock)); } } + if (const auto once = base::take(_migratedConferenceInfo)) { + processMigration(*once); + } }).fail([=](const MTP::Error &error) { const auto type = error.type(); if (_e2e) { @@ -1885,7 +1926,7 @@ void GroupCall::applyParticipantLocally( not_null participantPeer, bool mute, std::optional volume) { - const auto participant = LookupParticipant(_peer, _id, participantPeer); + const auto participant = LookupParticipant(this, participantPeer); if (!participant || !participant->ssrc) { return; } @@ -2370,7 +2411,7 @@ void GroupCall::applyOtherParticipantUpdate( } const auto participantPeer = _peer->owner().peer( peerFromMTP(data.vpeer())); - if (!LookupParticipant(_peer, _id, participantPeer)) { + if (!LookupParticipant(this, participantPeer)) { return; } _otherParticipantStateValue.fire(Group::ParticipantState{ @@ -3686,7 +3727,7 @@ void GroupCall::editParticipant( not_null participantPeer, bool mute, std::optional volume) { - const auto participant = LookupParticipant(_peer, _id, participantPeer); + const auto participant = LookupParticipant(this, participantPeer); if (!participant) { return; } diff --git a/Telegram/SourceFiles/calls/group/calls_group_call.h b/Telegram/SourceFiles/calls/group/calls_group_call.h index 2b5be388fb..80bce2fb9f 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_call.h +++ b/Telegram/SourceFiles/calls/group/calls_group_call.h @@ -62,6 +62,7 @@ enum class Error; struct InviteRequest; struct InviteResult; +struct StartConferenceInfo; enum class MuteState { Active, @@ -225,9 +226,7 @@ public: not_null delegate, Group::JoinInfo info, const MTPInputGroupCall &inputCall); - GroupCall( - not_null delegate, - Group::ConferenceInfo info); + GroupCall(not_null delegate, StartConferenceInfo info); ~GroupCall(); [[nodiscard]] CallId id() const { @@ -505,7 +504,7 @@ private: GroupCall( not_null delegate, Group::JoinInfo join, - Group::ConferenceInfo conference, + StartConferenceInfo conference, const MTPInputGroupCall &inputCall); void broadcastPartStart(std::shared_ptr task); @@ -620,6 +619,8 @@ private: void markTrackPaused(const VideoEndpoint &endpoint, bool paused); void markTrackShown(const VideoEndpoint &endpoint, bool shown); + void processMigration(StartConferenceInfo conference); + [[nodiscard]] int activeVideoSendersCount() const; [[nodiscard]] MTPInputGroupCall inputCall() const; @@ -629,6 +630,7 @@ private: const std::shared_ptr _conferenceCall; std::shared_ptr _e2e; QByteArray _pendingOutboundBlock; + std::shared_ptr _migratedConferenceInfo; not_null _peer; // Can change in legacy group migration. rpl::event_stream _peerStream; diff --git a/Telegram/SourceFiles/calls/group/calls_group_common.cpp b/Telegram/SourceFiles/calls/group/calls_group_common.cpp index e1ac887e00..94c330e2d4 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_common.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_common.cpp @@ -392,7 +392,7 @@ void ExportConferenceCallLink( std::shared_ptr call, ConferenceCallLinkArgs &&args) { const auto session = &show->session(); - const auto invite = std::move(args.invite); + const auto info = std::move(args.info); const auto finished = std::move(args.finished); using Flag = MTPphone_ExportGroupCallInvite::Flag; @@ -403,12 +403,10 @@ void ExportConferenceCallLink( const auto link = qs(result.data().vlink()); if (args.joining) { if (auto slug = ExtractConferenceSlug(link); !slug.isEmpty()) { - Core::App().calls().startOrJoinConferenceCall({ - .call = call, - .linkSlug = std::move(slug), - .invite = invite, - .migrating = args.migrating, - }); + auto copy = info; + copy.call = call; + copy.linkSlug = std::move(slug); + Core::App().calls().startOrJoinConferenceCall(info); } if (const auto onstack = finished) { finished(QString()); @@ -435,8 +433,7 @@ void MakeConferenceCall(ConferenceFactoryArgs &&args) { const auto show = std::move(args.show); const auto finished = std::move(args.finished); const auto joining = args.joining; - const auto migrating = args.migrating; - const auto invite = std::move(args.invite); + const auto info = std::move(args.info); const auto session = &show->session(); session->api().request(MTPphone_CreateConferenceCall( MTP_int(base::RandomValue()) @@ -449,9 +446,8 @@ void MakeConferenceCall(ConferenceFactoryArgs &&args) { Calls::Group::ExportConferenceCallLink(show, call, { .initial = true, .joining = joining, - .migrating = migrating, .finished = finished, - .invite = invite, + .info = info, }); }); }).fail([=](const MTP::Error &error) { diff --git a/Telegram/SourceFiles/calls/group/calls_group_common.h b/Telegram/SourceFiles/calls/group/calls_group_common.h index 63ab74dd89..ed050f479c 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_common.h +++ b/Telegram/SourceFiles/calls/group/calls_group_common.h @@ -37,6 +37,10 @@ namespace TdE2E { class Call; } // namespace TdE2E +namespace tgcalls { +class VideoCaptureInterface; +} // namespace tgcalls + namespace Window { class SessionController; } // namespace Window @@ -47,12 +51,25 @@ struct InviteRequest { not_null user; bool video = false; }; + struct InviteResult { std::vector> invited; std::vector> alreadyIn; std::vector> privacyRestricted; }; +struct StartConferenceInfo { + std::shared_ptr call; + std::shared_ptr e2e; + QString linkSlug; + MsgId joinMessageId; + std::vector invite; + bool migrating = false; + bool muted = false; + std::shared_ptr videoCapture; + QString videoCaptureScreenId; +}; + } // namespace Calls namespace Calls::Group { @@ -101,13 +118,6 @@ struct JoinInfo { bool rtmp = false; }; -struct ConferenceInfo { - std::shared_ptr call; - std::shared_ptr e2e; - QString linkSlug; - MsgId joinMessageId; -}; - enum class PanelMode { Default, Wide, @@ -158,9 +168,8 @@ struct ConferenceCallLinkStyleOverrides { struct ConferenceCallLinkArgs { bool initial = false; bool joining = false; - bool migrating = false; Fn finished; - std::vector invite; + StartConferenceInfo info; ConferenceCallLinkStyleOverrides st; }; void ShowConferenceCallLinkBox( @@ -177,9 +186,8 @@ void ExportConferenceCallLink( struct ConferenceFactoryArgs { std::shared_ptr show; Fn finished; - std::vector invite; bool joining = false; - bool migrating = false; + StartConferenceInfo info; }; void MakeConferenceCall(ConferenceFactoryArgs &&args);