diff --git a/Telegram/SourceFiles/calls/calls_group_call.cpp b/Telegram/SourceFiles/calls/calls_group_call.cpp index bdbdfd3bc4..526a958f51 100644 --- a/Telegram/SourceFiles/calls/calls_group_call.cpp +++ b/Telegram/SourceFiles/calls/calls_group_call.cpp @@ -111,45 +111,7 @@ void GroupCall::join(const MTPInputGroupCall &inputCall) { _id = data.vid().v; _accessHash = data.vaccess_hash().v; createAndStartController(); - const auto weak = base::make_weak(this); - _instance->emitJoinPayload([=](tgcalls::GroupJoinPayload payload) { - crl::on_main(weak, [=, payload = std::move(payload)]{ - auto fingerprints = QJsonArray(); - for (const auto print : payload.fingerprints) { - auto object = QJsonObject(); - object.insert("hash", QString::fromStdString(print.hash)); - object.insert("setup", QString::fromStdString(print.setup)); - object.insert( - "fingerprint", - QString::fromStdString(print.fingerprint)); - fingerprints.push_back(object); - } - - auto root = QJsonObject(); - const auto ssrc = payload.ssrc; - root.insert("ufrag", QString::fromStdString(payload.ufrag)); - root.insert("pwd", QString::fromStdString(payload.pwd)); - root.insert("fingerprints", fingerprints); - root.insert("ssrc", double(payload.ssrc)); - - const auto json = QJsonDocument(root).toJson( - QJsonDocument::Compact); - _api.request(MTPphone_JoinGroupCall( - MTP_flags(_muted.current() - ? MTPphone_JoinGroupCall::Flag::f_muted - : MTPphone_JoinGroupCall::Flag(0)), - inputCall, - MTP_dataJSON(MTP_bytes(json)) - )).done([=](const MTPUpdates &updates) { - _mySsrc = ssrc; - setState(State::Joined); - - _channel->session().api().applyUpdates(updates); - }).fail([=](const RPCError &error) { - int a = error.code(); - }).send(); - }); - }); + rejoin(); }); _channel->setCall(inputCall); @@ -161,6 +123,56 @@ void GroupCall::join(const MTPInputGroupCall &inputCall) { }, _lifetime); } +void GroupCall::rejoin() { + Expects(_state.current() == State::Joining); + + _mySsrc = 0; + const auto weak = base::make_weak(this); + _instance->emitJoinPayload([=](tgcalls::GroupJoinPayload payload) { + crl::on_main(weak, [=, payload = std::move(payload)]{ + auto fingerprints = QJsonArray(); + for (const auto print : payload.fingerprints) { + auto object = QJsonObject(); + object.insert("hash", QString::fromStdString(print.hash)); + object.insert("setup", QString::fromStdString(print.setup)); + object.insert( + "fingerprint", + QString::fromStdString(print.fingerprint)); + fingerprints.push_back(object); + } + + auto root = QJsonObject(); + const auto ssrc = payload.ssrc; + root.insert("ufrag", QString::fromStdString(payload.ufrag)); + root.insert("pwd", QString::fromStdString(payload.pwd)); + root.insert("fingerprints", fingerprints); + root.insert("ssrc", double(payload.ssrc)); + + const auto json = QJsonDocument(root).toJson( + QJsonDocument::Compact); + const auto muted = _muted.current(); + _api.request(MTPphone_JoinGroupCall( + MTP_flags(muted + ? MTPphone_JoinGroupCall::Flag::f_muted + : MTPphone_JoinGroupCall::Flag(0)), + inputCall(), + MTP_dataJSON(MTP_bytes(json)) + )).done([=](const MTPUpdates &updates) { + _mySsrc = ssrc; + setState(State::Joined); + + if (_muted.current() != muted) { + sendMutedUpdate(); + } + + _channel->session().api().applyUpdates(updates); + }).fail([=](const RPCError &error) { + int a = error.code(); + }).send(); + }); + }); +} + void GroupCall::checkParticipants() { if (!joined()) { return; @@ -226,23 +238,19 @@ void GroupCall::finish(FinishType type) { void GroupCall::setMuted(bool mute) { _muted = mute; - if (_instance) { - _instance->setIsMuted(mute); - } } -bool GroupCall::handleUpdate(const MTPGroupCall &call) { +void GroupCall::handleUpdate(const MTPGroupCall &call) { return call.match([&](const MTPDgroupCall &data) { if (_acceptFields) { - if (_instance || _id) { - return false; + if (!_instance && !_id) { + join(MTP_inputGroupCall(data.vid(), data.vaccess_hash())); } - join(MTP_inputGroupCall(data.vid(), data.vaccess_hash())); - return true; + return; } else if (_id != data.vid().v || _accessHash != data.vaccess_hash().v || !_instance) { - return false; + return; } if (const auto params = data.vparams()) { params->match([&](const MTPDdataJSON &data) { @@ -301,15 +309,39 @@ bool GroupCall::handleUpdate(const MTPGroupCall &call) { checkParticipants(); }); } - return true; }, [&](const MTPDgroupCallDiscarded &data) { - if (data.vid().v != _id) { - return false; + if (data.vid().v == _id) { + _mySsrc = 0; + hangup(); } - return true; }); } +void GroupCall::handleUpdate(const MTPDupdateGroupCallParticipants &data) { + const auto state = _state.current(); + if (state != State::Joined) { + return; + } + + const auto self = _channel->session().userId(); + for (const auto &participant : data.vparticipants().v) { + participant.match([&](const MTPDgroupCallParticipant &data) { + if (data.vuser_id().v != self) { + return; + } + if (data.is_left() && data.vsource().v == _mySsrc) { + // I was removed from the call, rejoin. + setState(State::Joining); + rejoin(); + } else if (!data.is_left() && data.vsource().v != _mySsrc) { + // I joined from another device, hangup. + _mySsrc = 0; + hangup(); + } + }); + } +} + void GroupCall::createAndStartController() { using AudioLevels = std::vector>; @@ -341,11 +373,37 @@ void GroupCall::createAndStartController() { _instance = std::make_unique( std::move(descriptor)); - const auto raw = _instance.get(); - raw->setIsMuted(_muted.current()); + _muted.value( + ) | rpl::start_with_next([=](bool muted) { + if (_instance) { + _instance->setIsMuted(muted); + } + if (_mySsrc) { + sendMutedUpdate(); + } + }, _lifetime); //raw->setAudioOutputDuckingEnabled(settings.callAudioDuckingEnabled()); } +void GroupCall::sendMutedUpdate() { + _api.request(_updateMuteRequestId).cancel(); + _updateMuteRequestId = _api.request(MTPphone_EditGroupCallMember( + MTP_flags(_muted.current() + ? MTPphone_EditGroupCallMember::Flag::f_muted + : MTPphone_EditGroupCallMember::Flag(0)), + inputCall(), + MTP_inputUserSelf() + )).done([=](const MTPUpdates &result) { + _channel->session().api().applyUpdates(result); + }).fail([=](const RPCError &error) { + if (error.type() == u"GROUP_CALL_FORBIDDEN"_q + && _state.current() == State::Joined) { + setState(State::Joining); + rejoin(); + } + }).send(); +} + void GroupCall::setCurrentAudioDevice(bool input, const QString &deviceId) { if (_instance) { const auto id = deviceId.toStdString(); diff --git a/Telegram/SourceFiles/calls/calls_group_call.h b/Telegram/SourceFiles/calls/calls_group_call.h index 23424ef2d7..88553c26e6 100644 --- a/Telegram/SourceFiles/calls/calls_group_call.h +++ b/Telegram/SourceFiles/calls/calls_group_call.h @@ -43,7 +43,8 @@ public: void start(); void hangup(); void join(const MTPInputGroupCall &inputCall); - bool handleUpdate(const MTPGroupCall &call); + void handleUpdate(const MTPGroupCall &call); + void handleUpdate(const MTPDupdateGroupCallParticipants &data); void setMuted(bool mute); [[nodiscard]] bool muted() const { @@ -95,6 +96,8 @@ private: void setState(State state); void finish(FinishType type); + void sendMutedUpdate(); + void rejoin(); [[nodiscard]] MTPInputGroupCall inputCall() const; @@ -109,6 +112,7 @@ private: uint64 _id = 0; uint64 _accessHash = 0; uint32 _mySsrc = 0; + mtpRequestId _updateMuteRequestId = 0; std::unique_ptr _instance; diff --git a/Telegram/SourceFiles/calls/calls_group_members.cpp b/Telegram/SourceFiles/calls/calls_group_members.cpp index 39278f7999..1c851be9f4 100644 --- a/Telegram/SourceFiles/calls/calls_group_members.cpp +++ b/Telegram/SourceFiles/calls/calls_group_members.cpp @@ -246,6 +246,8 @@ void MembersController::prepareRows() { auto user = row->peer()->asUser(); if (user->isSelf()) { foundSelf = true; + ++i; + continue; } const auto contains = ranges::contains( participants, @@ -303,11 +305,7 @@ base::unique_qptr MembersController::rowContextMenu( Expects(row->peer()->isUser()); const auto user = row->peer()->asUser(); - auto result = base::make_unique_q(parent); - //result->addAction( // #TODO calls - // tr::lng_context_view_profile(tr::now), - // crl::guard(this, [=] { _navigation->showPeerInfo(user); })); - return result; + return nullptr; } bool MembersController::appendRow(not_null user) { diff --git a/Telegram/SourceFiles/calls/calls_instance.cpp b/Telegram/SourceFiles/calls/calls_instance.cpp index bbcabf1064..af760b9f29 100644 --- a/Telegram/SourceFiles/calls/calls_instance.cpp +++ b/Telegram/SourceFiles/calls/calls_instance.cpp @@ -393,6 +393,9 @@ void Instance::handleGroupCallUpdate( if (const auto existing = session->data().groupCall(callId)) { existing->applyUpdate(update); } + if (_currentGroupCall) { + _currentGroupCall->handleUpdate(update); + } } void Instance::handleSignalingData(