mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-07 23:53:58 +02:00
Implement fast confcall migration.
This commit is contained in:
parent
2a7aac76d9
commit
c72cf46db7
13 changed files with 366 additions and 191 deletions
|
@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "mtproto/mtproto_dh_utils.h"
|
#include "mtproto/mtproto_dh_utils.h"
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "core/core_settings.h"
|
#include "core/core_settings.h"
|
||||||
|
#include "main/session/session_show.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "main/main_account.h"
|
#include "main/main_account.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
|
@ -237,14 +238,20 @@ void Instance::startOrJoinGroupCall(
|
||||||
}
|
}
|
||||||
|
|
||||||
void Instance::startOrJoinConferenceCall(StartConferenceInfo args) {
|
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()
|
? _currentCallPanel->migrationInfo()
|
||||||
: ConferencePanelMigration();
|
: ConferencePanelMigration();
|
||||||
if (!args.migrating) {
|
if (args.call && !args.migrating) {
|
||||||
destroyCurrentCall();
|
destroyCurrentCall();
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto session = &args.call->peer()->session();
|
const auto session = args.show
|
||||||
|
? &args.show->session()
|
||||||
|
: &args.call->session();
|
||||||
auto call = std::make_unique<GroupCall>(_delegate.get(), args);
|
auto call = std::make_unique<GroupCall>(_delegate.get(), args);
|
||||||
const auto raw = call.get();
|
const auto raw = call.get();
|
||||||
|
|
||||||
|
@ -253,20 +260,46 @@ void Instance::startOrJoinConferenceCall(StartConferenceInfo args) {
|
||||||
destroyGroupCall(raw);
|
destroyGroupCall(raw);
|
||||||
}, raw->lifetime());
|
}, raw->lifetime());
|
||||||
|
|
||||||
|
if (args.call) {
|
||||||
_currentGroupCallPanel = std::make_unique<Group::Panel>(
|
_currentGroupCallPanel = std::make_unique<Group::Panel>(
|
||||||
raw,
|
raw,
|
||||||
migrationInfo);
|
migrationInfo);
|
||||||
_currentGroupCall = std::move(call);
|
_currentGroupCall = std::move(call);
|
||||||
_currentGroupCallChanges.fire_copy(raw);
|
_currentGroupCallChanges.fire_copy(raw);
|
||||||
if (!args.invite.empty()) {
|
|
||||||
_currentGroupCallPanel->migrationInviteUsers(std::move(args.invite));
|
|
||||||
} else if (args.sharingLink && !args.linkSlug.isEmpty()) {
|
|
||||||
_currentGroupCallPanel->migrationShowShareLink();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.migrating) {
|
if (args.migrating) {
|
||||||
destroyCurrentCall(args.call.get(), args.linkSlug);
|
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<GroupCall*> call,
|
||||||
|
StartConferenceInfo args) {
|
||||||
|
if (_migratingGroupCall.get() != call) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto migrationInfo = _currentCallPanel
|
||||||
|
? _currentCallPanel->migrationInfo()
|
||||||
|
: ConferencePanelMigration();
|
||||||
|
_currentGroupCallPanel = std::make_unique<Group::Panel>(
|
||||||
|
call,
|
||||||
|
migrationInfo);
|
||||||
|
_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) {
|
||||||
|
_currentGroupCallPanel->migrationShowShareLink();
|
||||||
|
}
|
||||||
|
destroyCurrentCall(real, slug);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Instance::confirmLeaveCurrent(
|
void Instance::confirmLeaveCurrent(
|
||||||
|
@ -428,6 +461,8 @@ void Instance::destroyGroupCall(not_null<GroupCall*> call) {
|
||||||
LOG(("Calls::Instance doesn't prevent quit any more."));
|
LOG(("Calls::Instance doesn't prevent quit any more."));
|
||||||
}
|
}
|
||||||
Core::App().quitPreventFinished();
|
Core::App().quitPreventFinished();
|
||||||
|
} else if (_migratingGroupCall.get() == call) {
|
||||||
|
base::take(_migratingGroupCall);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -658,12 +693,14 @@ void Instance::handleCallUpdate(
|
||||||
void Instance::handleGroupCallUpdate(
|
void Instance::handleGroupCallUpdate(
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
const MTPUpdate &update) {
|
const MTPUpdate &update) {
|
||||||
if (_currentGroupCall
|
const auto groupCall = _currentGroupCall
|
||||||
&& (&_currentGroupCall->peer()->session() == session)) {
|
? _currentGroupCall.get()
|
||||||
|
: _migratingGroupCall.get();
|
||||||
|
if (groupCall && (&groupCall->peer()->session() == session)) {
|
||||||
update.match([&](const MTPDupdateGroupCall &data) {
|
update.match([&](const MTPDupdateGroupCall &data) {
|
||||||
_currentGroupCall->handlePossibleCreateOrJoinResponse(data);
|
groupCall->handlePossibleCreateOrJoinResponse(data);
|
||||||
}, [&](const MTPDupdateGroupCallConnection &data) {
|
}, [&](const MTPDupdateGroupCallConnection &data) {
|
||||||
_currentGroupCall->handlePossibleCreateOrJoinResponse(data);
|
groupCall->handlePossibleCreateOrJoinResponse(data);
|
||||||
}, [](const auto &) {
|
}, [](const auto &) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -692,10 +729,8 @@ void Instance::handleGroupCallUpdate(
|
||||||
});
|
});
|
||||||
if (update.type() == mtpc_updateGroupCallChainBlocks) {
|
if (update.type() == mtpc_updateGroupCallChainBlocks) {
|
||||||
const auto existing = session->data().groupCall(callId);
|
const auto existing = session->data().groupCall(callId);
|
||||||
if (existing
|
if (existing && groupCall && groupCall->lookupReal() == existing) {
|
||||||
&& _currentGroupCall
|
groupCall->handleUpdate(update);
|
||||||
&& _currentGroupCall->lookupReal() == existing) {
|
|
||||||
_currentGroupCall->handleUpdate(update);
|
|
||||||
}
|
}
|
||||||
} else if (const auto existing = session->data().groupCall(callId)) {
|
} else if (const auto existing = session->data().groupCall(callId)) {
|
||||||
existing->enqueueUpdate(update);
|
existing->enqueueUpdate(update);
|
||||||
|
@ -707,9 +742,11 @@ void Instance::handleGroupCallUpdate(
|
||||||
void Instance::applyGroupCallUpdateChecked(
|
void Instance::applyGroupCallUpdateChecked(
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
const MTPUpdate &update) {
|
const MTPUpdate &update) {
|
||||||
if (_currentGroupCall
|
const auto groupCall = _currentGroupCall
|
||||||
&& (&_currentGroupCall->peer()->session() == session)) {
|
? _currentGroupCall.get()
|
||||||
_currentGroupCall->handleUpdate(update);
|
: _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 {
|
bool Instance::hasVisiblePanel(Main::Session *session) const {
|
||||||
|
|
|
@ -86,6 +86,9 @@ public:
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
StartGroupCallArgs args);
|
StartGroupCallArgs args);
|
||||||
void startOrJoinConferenceCall(StartConferenceInfo args);
|
void startOrJoinConferenceCall(StartConferenceInfo args);
|
||||||
|
void migratedConferenceReady(
|
||||||
|
not_null<GroupCall*> call,
|
||||||
|
StartConferenceInfo args);
|
||||||
void showStartWithRtmp(
|
void showStartWithRtmp(
|
||||||
std::shared_ptr<Ui::Show> show,
|
std::shared_ptr<Ui::Show> show,
|
||||||
not_null<PeerData*> peer);
|
not_null<PeerData*> peer);
|
||||||
|
@ -200,6 +203,7 @@ private:
|
||||||
std::unique_ptr<Panel> _currentCallPanel;
|
std::unique_ptr<Panel> _currentCallPanel;
|
||||||
|
|
||||||
std::unique_ptr<GroupCall> _currentGroupCall;
|
std::unique_ptr<GroupCall> _currentGroupCall;
|
||||||
|
std::unique_ptr<GroupCall> _migratingGroupCall;
|
||||||
rpl::event_stream<GroupCall*> _currentGroupCallChanges;
|
rpl::event_stream<GroupCall*> _currentGroupCallChanges;
|
||||||
std::unique_ptr<Group::Panel> _currentGroupCallPanel;
|
std::unique_ptr<Group::Panel> _currentGroupCallPanel;
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "calls/group/calls_group_invite_controller.h"
|
#include "calls/group/calls_group_invite_controller.h"
|
||||||
#include "calls/ui/calls_device_menu.h"
|
#include "calls/ui/calls_device_menu.h"
|
||||||
#include "calls/calls_emoji_fingerprint.h"
|
#include "calls/calls_emoji_fingerprint.h"
|
||||||
|
#include "calls/calls_instance.h"
|
||||||
#include "calls/calls_signal_bars.h"
|
#include "calls/calls_signal_bars.h"
|
||||||
#include "calls/calls_userpic.h"
|
#include "calls/calls_userpic.h"
|
||||||
#include "calls/calls_video_bubble.h"
|
#include "calls/calls_video_bubble.h"
|
||||||
|
@ -359,11 +360,8 @@ void Panel::initControls() {
|
||||||
}
|
}
|
||||||
*creating = true;
|
*creating = true;
|
||||||
const auto sharingLink = users.empty();
|
const auto sharingLink = users.empty();
|
||||||
Group::MakeConferenceCall({
|
Core::App().calls().startOrJoinConferenceCall({
|
||||||
.show = sessionShow(),
|
.show = sessionShow(),
|
||||||
.finished = [=](bool) { *creating = false; },
|
|
||||||
.joining = true,
|
|
||||||
.info = {
|
|
||||||
.invite = std::move(users),
|
.invite = std::move(users),
|
||||||
.sharingLink = sharingLink,
|
.sharingLink = sharingLink,
|
||||||
.migrating = true,
|
.migrating = true,
|
||||||
|
@ -372,7 +370,6 @@ void Panel::initControls() {
|
||||||
? call->peekVideoCapture()
|
? call->peekVideoCapture()
|
||||||
: nullptr),
|
: nullptr),
|
||||||
.videoCaptureScreenId = call->screenSharingDeviceId(),
|
.videoCaptureScreenId = call->screenSharingDeviceId(),
|
||||||
},
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const auto invite = crl::guard(call, [=](
|
const auto invite = crl::guard(call, [=](
|
||||||
|
|
|
@ -8,6 +8,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "calls/group/calls_group_call.h"
|
#include "calls/group/calls_group_call.h"
|
||||||
|
|
||||||
#include "calls/group/calls_group_common.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_app_config.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "api/api_send_progress.h"
|
#include "api/api_send_progress.h"
|
||||||
|
@ -578,9 +580,11 @@ GroupCall::GroupCall(
|
||||||
not_null<Delegate*> delegate,
|
not_null<Delegate*> delegate,
|
||||||
StartConferenceInfo info)
|
StartConferenceInfo info)
|
||||||
: GroupCall(delegate, Group::JoinInfo{
|
: GroupCall(delegate, Group::JoinInfo{
|
||||||
.peer = info.call->peer(),
|
.peer = info.call ? info.call->peer() : info.show->session().user(),
|
||||||
.joinAs = info.call->peer(),
|
.joinAs = info.call ? info.call->peer() : info.show->session().user(),
|
||||||
}, info, info.call->input()) {
|
}, info, info.call
|
||||||
|
? info.call->input()
|
||||||
|
: MTP_inputGroupCall(MTP_long(0), MTP_long(0))) {
|
||||||
}
|
}
|
||||||
|
|
||||||
GroupCall::GroupCall(
|
GroupCall::GroupCall(
|
||||||
|
@ -590,7 +594,6 @@ GroupCall::GroupCall(
|
||||||
const MTPInputGroupCall &inputCall)
|
const MTPInputGroupCall &inputCall)
|
||||||
: _delegate(delegate)
|
: _delegate(delegate)
|
||||||
, _conferenceCall(std::move(conference.call))
|
, _conferenceCall(std::move(conference.call))
|
||||||
, _e2e(std::move(conference.e2e))
|
|
||||||
, _peer(join.peer)
|
, _peer(join.peer)
|
||||||
, _history(_peer->owner().history(_peer))
|
, _history(_peer->owner().history(_peer))
|
||||||
, _api(&_peer->session().mtp())
|
, _api(&_peer->session().mtp())
|
||||||
|
@ -602,7 +605,6 @@ GroupCall::GroupCall(
|
||||||
, _rtmpUrl(join.rtmpInfo.url)
|
, _rtmpUrl(join.rtmpInfo.url)
|
||||||
, _rtmpKey(join.rtmpInfo.key)
|
, _rtmpKey(join.rtmpInfo.key)
|
||||||
, _canManage(Data::CanManageGroupCallValue(_peer))
|
, _canManage(Data::CanManageGroupCallValue(_peer))
|
||||||
, _id(inputCall.c_inputGroupCall().vid().v)
|
|
||||||
, _scheduleDate(join.scheduleDate)
|
, _scheduleDate(join.scheduleDate)
|
||||||
, _lastSpokeCheckTimer([=] { checkLastSpoke(); })
|
, _lastSpokeCheckTimer([=] { checkLastSpoke(); })
|
||||||
, _checkJoinedTimer([=] { checkJoined(); })
|
, _checkJoinedTimer([=] { checkJoined(); })
|
||||||
|
@ -627,6 +629,8 @@ GroupCall::GroupCall(
|
||||||
, _listenersHidden(join.rtmp)
|
, _listenersHidden(join.rtmp)
|
||||||
, _rtmp(join.rtmp)
|
, _rtmp(join.rtmp)
|
||||||
, _rtmpVolume(Group::kDefaultVolume) {
|
, _rtmpVolume(Group::kDefaultVolume) {
|
||||||
|
applyInputCall(inputCall);
|
||||||
|
|
||||||
_muted.value(
|
_muted.value(
|
||||||
) | rpl::combine_previous(
|
) | rpl::combine_previous(
|
||||||
) | rpl::start_with_next([=](MuteState previous, MuteState state) {
|
) | rpl::start_with_next([=](MuteState previous, MuteState state) {
|
||||||
|
@ -658,7 +662,7 @@ GroupCall::GroupCall(
|
||||||
if (!canManage() && real->joinMuted()) {
|
if (!canManage() && real->joinMuted()) {
|
||||||
_muted = MuteState::ForceMuted;
|
_muted = MuteState::ForceMuted;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (!conference.migrating) {
|
||||||
_peer->session().changes().peerFlagsValue(
|
_peer->session().changes().peerFlagsValue(
|
||||||
_peer,
|
_peer,
|
||||||
Data::PeerUpdate::Flag::GroupCall
|
Data::PeerUpdate::Flag::GroupCall
|
||||||
|
@ -678,8 +682,9 @@ GroupCall::GroupCall(
|
||||||
|
|
||||||
setupMediaDevices();
|
setupMediaDevices();
|
||||||
setupOutgoingVideo();
|
setupOutgoingVideo();
|
||||||
if (_conferenceCall) {
|
if (_conferenceCall || conference.migrating) {
|
||||||
setupConferenceCall();
|
setupConference();
|
||||||
|
}
|
||||||
if (conference.migrating) {
|
if (conference.migrating) {
|
||||||
if (!conference.muted) {
|
if (!conference.muted) {
|
||||||
setMuted(MuteState::Active);
|
setMuted(MuteState::Active);
|
||||||
|
@ -687,10 +692,9 @@ GroupCall::GroupCall(
|
||||||
_migratedConferenceInfo = std::make_shared<StartConferenceInfo>(
|
_migratedConferenceInfo = std::make_shared<StartConferenceInfo>(
|
||||||
std::move(conference));
|
std::move(conference));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (_id) {
|
if (_id || (!_conferenceCall && _migratedConferenceInfo)) {
|
||||||
this->join(inputCall);
|
initialJoin();
|
||||||
} else {
|
} else {
|
||||||
start(join.scheduleDate, join.rtmp);
|
start(join.scheduleDate, join.rtmp);
|
||||||
}
|
}
|
||||||
|
@ -703,6 +707,7 @@ void GroupCall::processMigration(StartConferenceInfo conference) {
|
||||||
if (!conference.videoCapture) {
|
if (!conference.videoCapture) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
fillActiveVideoEndpoints();
|
||||||
const auto weak = base::make_weak(this);
|
const auto weak = base::make_weak(this);
|
||||||
if (!conference.videoCaptureScreenId.isEmpty()) {
|
if (!conference.videoCaptureScreenId.isEmpty()) {
|
||||||
_screenCapture = std::move(conference.videoCapture);
|
_screenCapture = std::move(conference.videoCapture);
|
||||||
|
@ -741,7 +746,7 @@ GroupCall::~GroupCall() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupCall::setupConferenceCall() {
|
void GroupCall::setupConference() {
|
||||||
if (!_e2e) {
|
if (!_e2e) {
|
||||||
_e2e = std::make_shared<TdE2E::Call>(
|
_e2e = std::make_shared<TdE2E::Call>(
|
||||||
TdE2E::MakeUserId(_peer->session().user()));
|
TdE2E::MakeUserId(_peer->session().user()));
|
||||||
|
@ -755,10 +760,24 @@ void GroupCall::setupConferenceCall() {
|
||||||
sendOutboundBlock(std::move(block));
|
sendOutboundBlock(std::move(block));
|
||||||
}, _lifetime);
|
}, _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(
|
_conferenceCall->staleParticipantIds(
|
||||||
) | rpl::start_with_next([=](const base::flat_set<UserId> &staleIds) {
|
) | rpl::start_with_next([=](const base::flat_set<UserId> &staleIds) {
|
||||||
removeConferenceParticipants(staleIds, true);
|
removeConferenceParticipants(staleIds, true);
|
||||||
}, _lifetime);
|
}, _lifetime);
|
||||||
|
|
||||||
_e2e->participantsSetValue(
|
_e2e->participantsSetValue(
|
||||||
) | rpl::start_with_next([=](const TdE2E::ParticipantsSet &set) {
|
) | rpl::start_with_next([=](const TdE2E::ParticipantsSet &set) {
|
||||||
auto users = base::flat_set<UserId>();
|
auto users = base::flat_set<UserId>();
|
||||||
|
@ -768,11 +787,6 @@ void GroupCall::setupConferenceCall() {
|
||||||
}
|
}
|
||||||
_conferenceCall->setParticipantsWithAccess(std::move(users));
|
_conferenceCall->setParticipantsWithAccess(std::move(users));
|
||||||
}, _lifetime);
|
}, _lifetime);
|
||||||
|
|
||||||
_e2e->failures() | rpl::start_with_next([=] {
|
|
||||||
LOG(("TdE2E: Got failure!"));
|
|
||||||
hangup();
|
|
||||||
}, _lifetime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupCall::removeConferenceParticipants(
|
void GroupCall::removeConferenceParticipants(
|
||||||
|
@ -917,7 +931,7 @@ void GroupCall::setScheduledDate(TimeId date) {
|
||||||
const auto was = _scheduleDate;
|
const auto was = _scheduleDate;
|
||||||
_scheduleDate = date;
|
_scheduleDate = date;
|
||||||
if (was && !date) {
|
if (was && !date) {
|
||||||
join(inputCall());
|
initialJoin();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1171,7 +1185,7 @@ bool GroupCall::rtmp() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GroupCall::conference() const {
|
bool GroupCall::conference() const {
|
||||||
return _conferenceCall != nullptr;
|
return _conferenceCall || _migratedConferenceInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GroupCall::listenersHidden() const {
|
bool GroupCall::listenersHidden() const {
|
||||||
|
@ -1234,31 +1248,40 @@ void GroupCall::start(TimeId scheduleDate, bool rtmp) {
|
||||||
MTPstring(), // title
|
MTPstring(), // title
|
||||||
MTP_int(scheduleDate)
|
MTP_int(scheduleDate)
|
||||||
)).done([=](const MTPUpdates &result) {
|
)).done([=](const MTPUpdates &result) {
|
||||||
|
_createRequestId = 0;
|
||||||
_reloadedStaleCall = true;
|
_reloadedStaleCall = true;
|
||||||
_acceptFields = true;
|
_acceptFields = true;
|
||||||
_peer->session().api().applyUpdates(result);
|
_peer->session().api().applyUpdates(result);
|
||||||
_acceptFields = false;
|
_acceptFields = false;
|
||||||
}).fail([=](const MTP::Error &error) {
|
}).fail([=](const MTP::Error &error) {
|
||||||
|
_createRequestId = 0;
|
||||||
LOG(("Call Error: Could not create, error: %1"
|
LOG(("Call Error: Could not create, error: %1"
|
||||||
).arg(error.type()));
|
).arg(error.type()));
|
||||||
hangup();
|
hangup();
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupCall::join(const MTPInputGroupCall &inputCall) {
|
void GroupCall::applyInputCall(const MTPInputGroupCall &inputCall) {
|
||||||
inputCall.match([&](const MTPDinputGroupCall &data) {
|
inputCall.match([&](const MTPDinputGroupCall &data) {
|
||||||
_id = data.vid().v;
|
_id = data.vid().v;
|
||||||
_accessHash = data.vaccess_hash().v;
|
_accessHash = data.vaccess_hash().v;
|
||||||
}, [&](const auto &) {
|
}, [&](const auto &) {
|
||||||
Unexpected("slug/msg in GroupCall::join.");
|
Unexpected("slug/msg in GroupCall::join.");
|
||||||
});
|
});
|
||||||
setState(_scheduleDate ? State::Waiting : State::Joining);
|
}
|
||||||
|
|
||||||
|
void GroupCall::initialJoin() {
|
||||||
|
setState(_scheduleDate ? State::Waiting : State::Joining);
|
||||||
if (_scheduleDate) {
|
if (_scheduleDate) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
rejoin();
|
rejoin();
|
||||||
|
if (_id) {
|
||||||
|
initialJoinRequested();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GroupCall::initialJoinRequested() {
|
||||||
using Update = Data::GroupCall::ParticipantUpdate;
|
using Update = Data::GroupCall::ParticipantUpdate;
|
||||||
const auto real = lookupReal();
|
const auto real = lookupReal();
|
||||||
Assert(real != nullptr);
|
Assert(real != nullptr);
|
||||||
|
@ -1283,10 +1306,10 @@ void GroupCall::join(const MTPInputGroupCall &inputCall) {
|
||||||
_peer->session().updates().addActiveChat(
|
_peer->session().updates().addActiveChat(
|
||||||
_peerStream.events_starting_with_copy(_peer));
|
_peerStream.events_starting_with_copy(_peer));
|
||||||
_canManage = Data::CanManageGroupCallValue(_peer);
|
_canManage = Data::CanManageGroupCallValue(_peer);
|
||||||
SubscribeToMigration(_peer, _lifetime, [=](not_null<ChannelData*> group) {
|
SubscribeToMigration(_peer, _lifetime, [=](not_null<ChannelData*> peer) {
|
||||||
_peer = group;
|
_peer = peer;
|
||||||
_canManage = Data::CanManageGroupCallValue(_peer);
|
_canManage = Data::CanManageGroupCallValue(_peer);
|
||||||
_peerStream.fire_copy(group);
|
_peerStream.fire_copy(peer);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1499,7 +1522,7 @@ void GroupCall::rejoin(not_null<PeerData*> as) {
|
||||||
&& state() != State::Joined
|
&& state() != State::Joined
|
||||||
&& state() != State::Connecting) {
|
&& state() != State::Connecting) {
|
||||||
return;
|
return;
|
||||||
} else if (_joinState.action != JoinAction::None) {
|
} else if (_joinState.action != JoinAction::None || _createRequestId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1529,7 +1552,11 @@ void GroupCall::rejoin(not_null<PeerData*> as) {
|
||||||
};
|
};
|
||||||
LOG(("Call Info: Join payload received, joining with ssrc: %1."
|
LOG(("Call Info: Join payload received, joining with ssrc: %1."
|
||||||
).arg(_joinState.payload.ssrc));
|
).arg(_joinState.payload.ssrc));
|
||||||
|
if (!_conferenceCall && _migratedConferenceInfo) {
|
||||||
|
startConference();
|
||||||
|
} else {
|
||||||
sendJoinRequest();
|
sendJoinRequest();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1540,7 +1567,7 @@ void GroupCall::sendJoinRequest() {
|
||||||
checkNextJoinAction();
|
checkNextJoinAction();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto joinBlock = _e2e ? _e2e->makeJoinBlock().data : QByteArray();
|
const auto joinBlock = _e2e ? _e2e->makeJoinBlock().data : QByteArray();
|
||||||
if (_e2e && joinBlock.isEmpty()) {
|
if (_e2e && joinBlock.isEmpty()) {
|
||||||
_joinState.finish();
|
_joinState.finish();
|
||||||
LOG(("Call Error: Could not generate join block."));
|
LOG(("Call Error: Could not generate join block."));
|
||||||
|
@ -1554,12 +1581,8 @@ void GroupCall::sendJoinRequest() {
|
||||||
const auto flags = (wasMuteState != MuteState::Active
|
const auto flags = (wasMuteState != MuteState::Active
|
||||||
? Flag::f_muted
|
? Flag::f_muted
|
||||||
: Flag(0))
|
: Flag(0))
|
||||||
| (_joinHash.isEmpty()
|
| (_joinHash.isEmpty() ? Flag(0) : Flag::f_invite_hash)
|
||||||
? Flag(0)
|
| (wasVideoStopped ? Flag::f_video_stopped : Flag(0))
|
||||||
: Flag::f_invite_hash)
|
|
||||||
| (wasVideoStopped
|
|
||||||
? Flag::f_video_stopped
|
|
||||||
: Flag(0))
|
|
||||||
| (_e2e ? (Flag::f_public_key | Flag::f_block) : Flag());
|
| (_e2e ? (Flag::f_public_key | Flag::f_block) : Flag());
|
||||||
_api.request(MTPphone_JoinGroupCall(
|
_api.request(MTPphone_JoinGroupCall(
|
||||||
MTP_flags(flags),
|
MTP_flags(flags),
|
||||||
|
@ -1570,74 +1593,15 @@ void GroupCall::sendJoinRequest() {
|
||||||
MTP_bytes(joinBlock),
|
MTP_bytes(joinBlock),
|
||||||
MTP_dataJSON(MTP_bytes(_joinState.payload.json))
|
MTP_dataJSON(MTP_bytes(_joinState.payload.json))
|
||||||
)).done([=](
|
)).done([=](
|
||||||
const MTPUpdates &updates,
|
const MTPUpdates &result,
|
||||||
const MTP::Response &response) {
|
const MTP::Response &response) {
|
||||||
_serverTimeMs = TimestampInMsFromMsgId(response.outerMsgId);
|
joinDone(
|
||||||
_serverTimeMsGotAt = crl::now();
|
TimestampInMsFromMsgId(response.outerMsgId),
|
||||||
|
result,
|
||||||
_joinState.finish(_joinState.payload.ssrc);
|
wasMuteState,
|
||||||
_mySsrcs.emplace(_joinState.ssrc);
|
wasVideoStopped);
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}).fail([=](const MTP::Error &error) {
|
}).fail([=](const MTP::Error &error) {
|
||||||
const auto type = error.type();
|
joinFail(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);
|
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1685,6 +1649,144 @@ void GroupCall::refreshLastBlockAndJoin() {
|
||||||
}).send();
|
}).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<int32>()),
|
||||||
|
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) {
|
void GroupCall::requestSubchainBlocks(int subchain, int height) {
|
||||||
Expects(subchain >= 0 && subchain < kSubChainsCount);
|
Expects(subchain >= 0 && subchain < kSubChainsCount);
|
||||||
|
|
||||||
|
@ -2168,7 +2270,8 @@ void GroupCall::handlePossibleCreateOrJoinResponse(
|
||||||
} else {
|
} else {
|
||||||
Unexpected("Peer type in GroupCall::join.");
|
Unexpected("Peer type in GroupCall::join.");
|
||||||
}
|
}
|
||||||
join(input);
|
applyInputCall(input);
|
||||||
|
initialJoin();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else if (_id != data.vid().v || !_instance) {
|
} else if (_id != data.vid().v || !_instance) {
|
||||||
|
@ -3768,7 +3871,6 @@ void GroupCall::editParticipant(
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void GroupCall::inviteToConference(
|
void GroupCall::inviteToConference(
|
||||||
InviteRequest request,
|
InviteRequest request,
|
||||||
Fn<not_null<InviteResult*>()> resultAddress,
|
Fn<not_null<InviteResult*>()> resultAddress,
|
||||||
|
|
|
@ -263,12 +263,15 @@ public:
|
||||||
[[nodiscard]] rpl::producer<not_null<Data::GroupCall*>> real() const;
|
[[nodiscard]] rpl::producer<not_null<Data::GroupCall*>> real() const;
|
||||||
[[nodiscard]] rpl::producer<QByteArray> emojiHashValue() const;
|
[[nodiscard]] rpl::producer<QByteArray> emojiHashValue() const;
|
||||||
|
|
||||||
|
void applyInputCall(const MTPInputGroupCall &inputCall);
|
||||||
|
void startConference();
|
||||||
void start(TimeId scheduleDate, bool rtmp);
|
void start(TimeId scheduleDate, bool rtmp);
|
||||||
void hangup();
|
void hangup();
|
||||||
void discard();
|
void discard();
|
||||||
void rejoinAs(Group::JoinInfo info);
|
void rejoinAs(Group::JoinInfo info);
|
||||||
void rejoinWithHash(const QString &hash);
|
void rejoinWithHash(const QString &hash);
|
||||||
void join(const MTPInputGroupCall &inputCall);
|
void initialJoin();
|
||||||
|
void initialJoinRequested();
|
||||||
void handleUpdate(const MTPUpdate &update);
|
void handleUpdate(const MTPUpdate &update);
|
||||||
void handlePossibleCreateOrJoinResponse(const MTPDupdateGroupCall &data);
|
void handlePossibleCreateOrJoinResponse(const MTPDupdateGroupCall &data);
|
||||||
void handlePossibleCreateOrJoinResponse(
|
void handlePossibleCreateOrJoinResponse(
|
||||||
|
@ -292,6 +295,14 @@ public:
|
||||||
bool emitShareScreenError();
|
bool emitShareScreenError();
|
||||||
bool emitShareCameraError();
|
bool emitShareCameraError();
|
||||||
|
|
||||||
|
void joinDone(
|
||||||
|
int64 serverTimeMs,
|
||||||
|
const MTPUpdates &result,
|
||||||
|
MuteState wasMuteState,
|
||||||
|
bool wasVideoStopped,
|
||||||
|
bool justCreated = false);
|
||||||
|
void joinFail(const QString &error);
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<Group::Error> errors() const {
|
[[nodiscard]] rpl::producer<Group::Error> errors() const {
|
||||||
return _errors.events();
|
return _errors.events();
|
||||||
}
|
}
|
||||||
|
@ -610,6 +621,7 @@ private:
|
||||||
|
|
||||||
void setupMediaDevices();
|
void setupMediaDevices();
|
||||||
void setupOutgoingVideo();
|
void setupOutgoingVideo();
|
||||||
|
void setupConference();
|
||||||
void setupConferenceCall();
|
void setupConferenceCall();
|
||||||
void setScreenEndpoint(std::string endpoint);
|
void setScreenEndpoint(std::string endpoint);
|
||||||
void setCameraEndpoint(std::string endpoint);
|
void setCameraEndpoint(std::string endpoint);
|
||||||
|
@ -635,7 +647,7 @@ private:
|
||||||
[[nodiscard]] MTPInputGroupCall inputCallSafe() const;
|
[[nodiscard]] MTPInputGroupCall inputCallSafe() const;
|
||||||
|
|
||||||
const not_null<Delegate*> _delegate;
|
const not_null<Delegate*> _delegate;
|
||||||
const std::shared_ptr<Data::GroupCall> _conferenceCall;
|
std::shared_ptr<Data::GroupCall> _conferenceCall;
|
||||||
std::shared_ptr<TdE2E::Call> _e2e;
|
std::shared_ptr<TdE2E::Call> _e2e;
|
||||||
QByteArray _pendingOutboundBlock;
|
QByteArray _pendingOutboundBlock;
|
||||||
std::shared_ptr<StartConferenceInfo> _migratedConferenceInfo;
|
std::shared_ptr<StartConferenceInfo> _migratedConferenceInfo;
|
||||||
|
|
|
@ -18,6 +18,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_group_call.h"
|
#include "data/data_group_call.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "info/bot/starref/info_bot_starref_common.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/boxes/boost_box.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/labels.h"
|
#include "ui/widgets/labels.h"
|
||||||
|
@ -41,24 +43,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include <QtGui/QClipboard>
|
#include <QtGui/QClipboard>
|
||||||
|
|
||||||
namespace Calls::Group {
|
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<Ui::GenericBox> ScreenSharingPrivacyRequestBox() {
|
object_ptr<Ui::GenericBox> ScreenSharingPrivacyRequestBox() {
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
|
@ -468,32 +452,13 @@ void MakeConferenceCall(ConferenceFactoryArgs &&args) {
|
||||||
MTPbytes(), // block
|
MTPbytes(), // block
|
||||||
MTPDataJSON() // params
|
MTPDataJSON() // params
|
||||||
)).done([=](const MTPUpdates &result) {
|
)).done([=](const MTPUpdates &result) {
|
||||||
session->api().applyUpdates(result);
|
auto call = session->data().sharedConferenceCallFind(result);
|
||||||
const auto updates = result.match([&](const MTPDupdates &data) {
|
if (!call) {
|
||||||
return &data.vupdates().v;
|
|
||||||
}, [&](const MTPDupdatesCombined &data) {
|
|
||||||
return &data.vupdates().v;
|
|
||||||
}, [](const auto &) {
|
|
||||||
return (const QVector<MTPUpdate>*)nullptr;
|
|
||||||
});
|
|
||||||
if (!updates) {
|
|
||||||
fail(u"Call not found!"_q);
|
fail(u"Call not found!"_q);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto call = std::shared_ptr<Data::GroupCall>();
|
session->api().applyUpdates(result);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const auto link = call ? call->conferenceInviteLink() : QString();
|
const auto link = call ? call->conferenceInviteLink() : QString();
|
||||||
if (link.isEmpty()) {
|
if (link.isEmpty()) {
|
||||||
fail(u"Call link not found!"_q);
|
fail(u"Call link not found!"_q);
|
||||||
|
@ -521,4 +486,19 @@ void MakeConferenceCall(ConferenceFactoryArgs &&args) {
|
||||||
}).send();
|
}).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
|
} // namespace Calls::Group
|
||||||
|
|
|
@ -64,8 +64,8 @@ struct InviteResult {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StartConferenceInfo {
|
struct StartConferenceInfo {
|
||||||
|
std::shared_ptr<Main::SessionShow> show;
|
||||||
std::shared_ptr<Data::GroupCall> call;
|
std::shared_ptr<Data::GroupCall> call;
|
||||||
std::shared_ptr<TdE2E::Call> e2e;
|
|
||||||
QString linkSlug;
|
QString linkSlug;
|
||||||
MsgId joinMessageId;
|
MsgId joinMessageId;
|
||||||
std::vector<InviteRequest> invite;
|
std::vector<InviteRequest> invite;
|
||||||
|
@ -195,4 +195,6 @@ struct ConferenceFactoryArgs {
|
||||||
};
|
};
|
||||||
void MakeConferenceCall(ConferenceFactoryArgs &&args);
|
void MakeConferenceCall(ConferenceFactoryArgs &&args);
|
||||||
|
|
||||||
|
[[nodiscard]] QString ExtractConferenceSlug(const QString &link);
|
||||||
|
|
||||||
} // namespace Calls::Group
|
} // namespace Calls::Group
|
||||||
|
|
|
@ -376,6 +376,8 @@ void Panel::initWindow() {
|
||||||
|
|
||||||
_window->setControlsStyle(st::groupCallTitle);
|
_window->setControlsStyle(st::groupCallTitle);
|
||||||
_window->togglePowerSaveBlocker(true);
|
_window->togglePowerSaveBlocker(true);
|
||||||
|
|
||||||
|
uiShow()->hideLayer(anim::type::instant);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panel::initWidget() {
|
void Panel::initWidget() {
|
||||||
|
@ -927,7 +929,6 @@ Fn<void()> Panel::shareConferenceLinkCallback() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panel::migrationShowShareLink() {
|
void Panel::migrationShowShareLink() {
|
||||||
uiShow()->hideLayer(anim::type::instant);
|
|
||||||
ShowConferenceCallLinkBox(
|
ShowConferenceCallLinkBox(
|
||||||
sessionShow(),
|
sessionShow(),
|
||||||
_call->conferenceCall(),
|
_call->conferenceCall(),
|
||||||
|
|
|
@ -374,6 +374,7 @@ auto GroupCall::staleParticipantIds() const
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupCall::enqueueUpdate(const MTPUpdate &update) {
|
void GroupCall::enqueueUpdate(const MTPUpdate &update) {
|
||||||
|
const auto initial = !_version;
|
||||||
update.match([&](const MTPDupdateGroupCall &updateData) {
|
update.match([&](const MTPDupdateGroupCall &updateData) {
|
||||||
updateData.vcall().match([&](const MTPDgroupCall &data) {
|
updateData.vcall().match([&](const MTPDgroupCall &data) {
|
||||||
const auto version = data.vversion().v;
|
const auto version = data.vversion().v;
|
||||||
|
@ -427,7 +428,7 @@ void GroupCall::enqueueUpdate(const MTPUpdate &update) {
|
||||||
}, [](const auto &) {
|
}, [](const auto &) {
|
||||||
Unexpected("Type in GroupCall::enqueueUpdate.");
|
Unexpected("Type in GroupCall::enqueueUpdate.");
|
||||||
});
|
});
|
||||||
processQueuedUpdates();
|
processQueuedUpdates(initial);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupCall::discard(const MTPDgroupCallDiscarded &data) {
|
void GroupCall::discard(const MTPDgroupCallDiscarded &data) {
|
||||||
|
@ -562,7 +563,7 @@ void GroupCall::applyEnqueuedUpdate(const MTPUpdate &update) {
|
||||||
Core::App().calls().applyGroupCallUpdateChecked(&session(), update);
|
Core::App().calls().applyGroupCallUpdateChecked(&session(), update);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupCall::processQueuedUpdates() {
|
void GroupCall::processQueuedUpdates(bool initial) {
|
||||||
if (!_version || _applyingQueuedUpdates) {
|
if (!_version || _applyingQueuedUpdates) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -574,7 +575,13 @@ void GroupCall::processQueuedUpdates() {
|
||||||
const auto type = entry.first.second;
|
const auto type = entry.first.second;
|
||||||
const auto incremented = (type == QueuedType::VersionedParticipant);
|
const auto incremented = (type == QueuedType::VersionedParticipant);
|
||||||
if ((version < _version)
|
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());
|
_queuedUpdates.erase(_queuedUpdates.begin());
|
||||||
} else if (version == _version
|
} else if (version == _version
|
||||||
|| (version == _version + 1 && incremented)) {
|
|| (version == _version + 1 && incremented)) {
|
||||||
|
|
|
@ -215,7 +215,7 @@ private:
|
||||||
void applyEnqueuedUpdate(const MTPUpdate &update);
|
void applyEnqueuedUpdate(const MTPUpdate &update);
|
||||||
void setServerParticipantsCount(int count);
|
void setServerParticipantsCount(int count);
|
||||||
void computeParticipantsCount();
|
void computeParticipantsCount();
|
||||||
void processQueuedUpdates();
|
void processQueuedUpdates(bool initial = false);
|
||||||
void processFullCallUsersChats(const MTPphone_GroupCall &call);
|
void processFullCallUsersChats(const MTPphone_GroupCall &call);
|
||||||
void processFullCallFields(const MTPphone_GroupCall &call);
|
void processFullCallFields(const MTPphone_GroupCall &call);
|
||||||
[[nodiscard]] bool requestParticipantsAfterReload(
|
[[nodiscard]] bool requestParticipantsAfterReload(
|
||||||
|
|
|
@ -1159,6 +1159,36 @@ std::shared_ptr<GroupCall> Session::sharedConferenceCall(
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<GroupCall> 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<MTPUpdate>*)nullptr;
|
||||||
|
});
|
||||||
|
const auto empty = std::shared_ptr<GroupCall>();
|
||||||
|
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<UserData*> user, TimeId now) {
|
void Session::watchForOffline(not_null<UserData*> user, TimeId now) {
|
||||||
if (!now) {
|
if (!now) {
|
||||||
now = base::unixtime::now();
|
now = base::unixtime::now();
|
||||||
|
|
|
@ -235,6 +235,8 @@ public:
|
||||||
[[nodiscard]] std::shared_ptr<GroupCall> sharedConferenceCall(
|
[[nodiscard]] std::shared_ptr<GroupCall> sharedConferenceCall(
|
||||||
CallId id,
|
CallId id,
|
||||||
uint64 accessHash);
|
uint64 accessHash);
|
||||||
|
[[nodiscard]] std::shared_ptr<GroupCall> sharedConferenceCallFind(
|
||||||
|
const MTPUpdates &response);
|
||||||
|
|
||||||
void watchForOffline(not_null<UserData*> user, TimeId now = 0);
|
void watchForOffline(not_null<UserData*> user, TimeId now = 0);
|
||||||
void maybeStopWatchForOffline(not_null<UserData*> user);
|
void maybeStopWatchForOffline(not_null<UserData*> user);
|
||||||
|
|
|
@ -882,7 +882,7 @@ void SessionNavigation::resolveConferenceCall(
|
||||||
data.vaccess_hash().v);
|
data.vaccess_hash().v);
|
||||||
call->processFullCall(result);
|
call->processFullCall(result);
|
||||||
const auto join = [=](Fn<void()> close) {
|
const auto join = [=](Fn<void()> close) {
|
||||||
const auto &appConfig = call->peer()->session().appConfig();
|
const auto &appConfig = call->session().appConfig();
|
||||||
const auto conferenceLimit = appConfig.confcallSizeLimit();
|
const auto conferenceLimit = appConfig.confcallSizeLimit();
|
||||||
if (call->fullCount() >= conferenceLimit) {
|
if (call->fullCount() >= conferenceLimit) {
|
||||||
showToast(tr::lng_confcall_participants_limit(tr::now));
|
showToast(tr::lng_confcall_participants_limit(tr::now));
|
||||||
|
|
Loading…
Add table
Reference in a new issue