From 79a361ba43a74d895b2ed28ebdb6913fbff4ee36 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 25 Jun 2020 21:57:36 +0400 Subject: [PATCH] Move call management to Core::App. --- Telegram/SourceFiles/api/api_updates.cpp | 2 +- .../calls/calls_box_controller.cpp | 14 +-- Telegram/SourceFiles/calls/calls_call.cpp | 75 ++++++++-------- Telegram/SourceFiles/calls/calls_call.h | 21 +++-- Telegram/SourceFiles/calls/calls_instance.cpp | 88 +++++++++++-------- Telegram/SourceFiles/calls/calls_instance.h | 34 +++---- Telegram/SourceFiles/calls/calls_panel.cpp | 10 +-- Telegram/SourceFiles/calls/calls_panel.h | 2 +- Telegram/SourceFiles/calls/calls_top_bar.cpp | 3 +- Telegram/SourceFiles/core/application.cpp | 5 +- Telegram/SourceFiles/core/application.h | 13 ++- Telegram/SourceFiles/data/data_changes.h | 3 +- Telegram/SourceFiles/history/history.cpp | 5 +- .../view/history_view_top_bar_widget.cpp | 2 +- .../history/view/media/history_view_call.cpp | 3 +- .../SourceFiles/info/info_wrap_widget.cpp | 3 +- Telegram/SourceFiles/main/main_session.cpp | 1 - Telegram/SourceFiles/main/main_session.h | 9 -- Telegram/SourceFiles/mainwidget.cpp | 22 ++++- Telegram/SourceFiles/mainwidget.h | 1 + .../media/player/media_player_instance.cpp | 21 ++--- .../media/view/media_view_overlay_widget.cpp | 24 +++-- .../SourceFiles/settings/settings_calls.cpp | 10 +-- 23 files changed, 204 insertions(+), 167 deletions(-) diff --git a/Telegram/SourceFiles/api/api_updates.cpp b/Telegram/SourceFiles/api/api_updates.cpp index 1b099628ec..8eb4a07cb9 100644 --- a/Telegram/SourceFiles/api/api_updates.cpp +++ b/Telegram/SourceFiles/api/api_updates.cpp @@ -1721,7 +1721,7 @@ void Updates::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updatePhoneCall: { - session().calls().handleUpdate(update.c_updatePhoneCall()); + Core::App().calls().handleUpdate(&session(), update.c_updatePhoneCall()); } break; case mtpc_updateUserBlocked: { diff --git a/Telegram/SourceFiles/calls/calls_box_controller.cpp b/Telegram/SourceFiles/calls/calls_box_controller.cpp index e7ff96d7f0..5f0cc6dcb7 100644 --- a/Telegram/SourceFiles/calls/calls_box_controller.cpp +++ b/Telegram/SourceFiles/calls/calls_box_controller.cpp @@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_boxes.h" #include "lang/lang_keys.h" #include "ui/effects/ripple_animation.h" +#include "core/application.h" #include "calls/calls_instance.h" #include "history/history.h" #include "history/history_item.h" @@ -18,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/window_session_controller.h" #include "main/main_session.h" #include "data/data_session.h" +#include "data/data_changes.h" #include "data/data_media_types.h" #include "data/data_user.h" #include "app.h" @@ -237,11 +239,11 @@ void BoxController::prepare() { } }, lifetime()); - subscribe(session().calls().newServiceMessage(), [=](FullMsgId msgId) { - if (const auto item = session().data().message(msgId)) { - insertRow(item, InsertWay::Prepend); - } - }); + session().changes().messageUpdates( + Data::MessageUpdate::Flag::CallAdded + ) | rpl::start_with_next([=](const Data::MessageUpdate &update) { + insertRow(update.item, InsertWay::Prepend); + }, lifetime()); delegate()->peerListSetTitle(tr::lng_call_box_title()); setDescriptionText(tr::lng_contacts_loading(tr::now)); @@ -315,7 +317,7 @@ void BoxController::rowActionClicked(not_null row) { auto user = row->peer()->asUser(); Assert(user != nullptr); - user->session().calls().startOutgoingCall(user); + Core::App().calls().startOutgoingCall(user); } void BoxController::receivedCalls(const QVector &result) { diff --git a/Telegram/SourceFiles/calls/calls_call.cpp b/Telegram/SourceFiles/calls/calls_call.cpp index e317b6a38c..0a72867281 100644 --- a/Telegram/SourceFiles/calls/calls_call.cpp +++ b/Telegram/SourceFiles/calls/calls_call.cpp @@ -131,7 +131,8 @@ bool Call::isIncomingWaiting() const { if (type() != Call::Type::Incoming) { return false; } - return (_state == State::Starting) || (_state == State::WaitingIncoming); + return (state() == State::Starting) + || (state() == State::WaitingIncoming); } void Call::start(bytes::const_span random) { @@ -142,13 +143,14 @@ void Call::start(bytes::const_span random) { Assert(!_dhConfig.p.empty()); generateModExpFirst(random); - if (_state == State::Starting || _state == State::Requesting) { + const auto state = _state.current(); + if (state == State::Starting || state == State::Requesting) { if (_type == Type::Outgoing) { startOutgoing(); } else { startIncoming(); } - } else if (_state == State::ExchangingKeys + } else if (state == State::ExchangingKeys && _answerAfterDhConfigReceived) { answer(); } @@ -156,7 +158,7 @@ void Call::start(bytes::const_span random) { void Call::startOutgoing() { Expects(_type == Type::Outgoing); - Expects(_state == State::Requesting); + Expects(_state.current() == State::Requesting); Expects(_gaHash.size() == kSha256Size); _api.request(MTPphone_RequestCall( @@ -206,12 +208,12 @@ void Call::startOutgoing() { void Call::startIncoming() { Expects(_type == Type::Incoming); - Expects(_state == State::Starting); + Expects(_state.current() == State::Starting); _api.request(MTPphone_ReceivedCall( MTP_inputPhoneCall(MTP_long(_id), MTP_long(_accessHash)) )).done([=](const MTPBool &result) { - if (_state == State::Starting) { + if (_state.current() == State::Starting) { setState(State::WaitingIncoming); } }).fail([=](const RPCError &error) { @@ -228,8 +230,9 @@ void Call::answer() { void Call::actuallyAnswer() { Expects(_type == Type::Incoming); - if (_state != State::Starting && _state != State::WaitingIncoming) { - if (_state != State::ExchangingKeys + const auto state = _state.current(); + if (state != State::Starting && state != State::WaitingIncoming) { + if (state != State::ExchangingKeys || !_answerAfterDhConfigReceived) { return; } @@ -280,10 +283,11 @@ crl::time Call::getDurationMs() const { } void Call::hangup() { - if (_state == State::Busy) { + const auto state = _state.current(); + if (state == State::Busy) { _delegate->callFinished(this); } else { - auto missed = (_state == State::Ringing || (_state == State::Waiting && _type == Type::Outgoing)); + auto missed = (state == State::Ringing || (state == State::Waiting && _type == Type::Outgoing)); auto declined = isIncomingWaiting(); auto reason = missed ? MTP_phoneCallDiscardReasonMissed() : declined ? MTP_phoneCallDiscardReasonBusy() : MTP_phoneCallDiscardReasonHangup(); @@ -292,7 +296,7 @@ void Call::hangup() { } void Call::redial() { - if (_state != State::Busy) { + if (_state.current() != State::Busy) { return; } Assert(_controller == nullptr); @@ -384,7 +388,7 @@ bool Call::handleUpdate(const MTPPhoneCall &call) { return false; } if (_type == Type::Outgoing - && _state == State::Waiting + && _state.current() == State::Waiting && data.vreceive_date().value_or_empty() != 0) { const auto &config = _user->session().serverConfig(); _discardByTimeoutTimer.callOnce(config.callRingTimeoutMs); @@ -399,7 +403,7 @@ bool Call::handleUpdate(const MTPPhoneCall &call) { return false; } if (_type == Type::Incoming - && _state == State::ExchangingKeys + && _state.current() == State::ExchangingKeys && !_controller) { startConfirmedCall(data); } @@ -432,7 +436,8 @@ bool Call::handleUpdate(const MTPPhoneCall &call) { } if (reason && reason->type() == mtpc_phoneCallDiscardReasonBusy) { setState(State::Busy); - } else if (_type == Type::Outgoing || _state == State::HangingUp) { + } else if (_type == Type::Outgoing + || _state.current() == State::HangingUp) { setState(State::Ended); } else { setState(State::EndedByOtherDevice); @@ -460,7 +465,7 @@ bool Call::handleUpdate(const MTPPhoneCall &call) { void Call::confirmAcceptedCall(const MTPDphoneCallAccepted &call) { Expects(_type == Type::Outgoing); - if (_state == State::ExchangingKeys + if (_state.current() == State::ExchangingKeys || _controller) { LOG(("Call Warning: Unexpected confirmAcceptedCall.")); return; @@ -710,34 +715,33 @@ bool Call::checkCallFields(const MTPDphoneCallAccepted &call) { } void Call::setState(State state) { - if (_state == State::Failed) { + if (_state.current() == State::Failed) { return; } - if (_state == State::FailedHangingUp && state != State::Failed) { + if (_state.current() == State::FailedHangingUp && state != State::Failed) { return; } - if (_state != state) { + if (_state.current() != state) { _state = state; - _stateChanged.notify(state, true); if (true - && _state != State::Starting - && _state != State::Requesting - && _state != State::Waiting - && _state != State::WaitingIncoming - && _state != State::Ringing) { + && state != State::Starting + && state != State::Requesting + && state != State::Waiting + && state != State::WaitingIncoming + && state != State::Ringing) { _waitingTrack.reset(); } if (false - || _state == State::Ended - || _state == State::EndedByOtherDevice - || _state == State::Failed - || _state == State::Busy) { + || state == State::Ended + || state == State::EndedByOtherDevice + || state == State::Failed + || state == State::Busy) { // Destroy controller before destroying Call Panel, // so that the panel hide animation is smooth. destroyController(); } - switch (_state) { + switch (state) { case State::Established: _startTime = crl::now(); break; @@ -794,16 +798,17 @@ void Call::finish(FinishType type, const MTPPhoneCallDiscardReason &reason) { auto finalState = (type == FinishType::Ended) ? State::Ended : State::Failed; auto hangupState = (type == FinishType::Ended) ? State::HangingUp : State::FailedHangingUp; - if (_state == State::Requesting) { + const auto state = _state.current(); + if (state == State::Requesting) { _finishByTimeoutTimer.call(kHangupTimeoutMs, [this, finalState] { setState(finalState); }); _finishAfterRequestingCall = type; return; } - if (_state == State::HangingUp - || _state == State::FailedHangingUp - || _state == State::EndedByOtherDevice - || _state == State::Ended - || _state == State::Failed) { + if (state == State::HangingUp + || state == State::FailedHangingUp + || state == State::EndedByOtherDevice + || state == State::Ended + || state == State::Failed) { return; } if (!_id) { diff --git a/Telegram/SourceFiles/calls/calls_call.h b/Telegram/SourceFiles/calls/calls_call.h index 2f91c9fe1b..265e74671b 100644 --- a/Telegram/SourceFiles/calls/calls_call.h +++ b/Telegram/SourceFiles/calls/calls_call.h @@ -60,13 +60,13 @@ public: }; Call(not_null delegate, not_null user, Type type); - Type type() const { + [[nodiscard]] Type type() const { return _type; } - not_null user() const { + [[nodiscard]] not_null user() const { return _user; } - bool isIncomingWaiting() const; + [[nodiscard]] bool isIncomingWaiting() const; void start(bytes::const_span random); bool handleUpdate(const MTPPhoneCall &call); @@ -89,10 +89,10 @@ public: Busy, }; State state() const { - return _state; + return _state.current(); } - base::Observable &stateChanged() { - return _stateChanged; + rpl::producer stateValue() const { + return _state.value(); } static constexpr auto kSignalBarStarting = -1; @@ -126,6 +126,10 @@ public: void setAudioVolume(bool input, float level); void setAudioDuckingEnabled(bool enabled); + [[nodiscard]] rpl::lifetime &lifetime() { + return _lifetime; + } + ~Call(); private: @@ -166,10 +170,9 @@ private: not_null _user; MTP::Sender _api; Type _type = Type::Outgoing; - State _state = State::Starting; + rpl::variable _state = State::Starting; FinishType _finishAfterRequestingCall = FinishType::None; bool _answerAfterDhConfigReceived = false; - base::Observable _stateChanged; int _signalBarCount = kSignalBarStarting; base::Observable _signalBarCountChanged; crl::time _startTime = 0; @@ -195,6 +198,8 @@ private: std::unique_ptr _waitingTrack; + rpl::lifetime _lifetime; + }; void UpdateConfig(const std::string &data); diff --git a/Telegram/SourceFiles/calls/calls_instance.cpp b/Telegram/SourceFiles/calls/calls_instance.cpp index ffd3312141..5c700db204 100644 --- a/Telegram/SourceFiles/calls/calls_instance.cpp +++ b/Telegram/SourceFiles/calls/calls_instance.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mtproto/mtproto_dh_utils.h" #include "core/application.h" #include "main/main_session.h" +#include "main/main_account.h" #include "apiwrap.h" #include "lang/lang_keys.h" #include "boxes/confirm_box.h" @@ -32,9 +33,14 @@ constexpr auto kServerConfigUpdateTimeoutMs = 24 * 3600 * crl::time(1000); } // namespace -Instance::Instance(not_null session) -: _session(session) -, _api(&_session->mtp()) { +Instance::Instance() = default; + +Instance::~Instance() { + for (const auto panel : _pendingPanels) { + if (panel) { + delete panel; + } + } } void Instance::startOutgoingCall(not_null user) { @@ -44,8 +50,9 @@ void Instance::startOutgoingCall(not_null user) { } if (user->callsStatus() == UserData::CallsStatus::Private) { // Request full user once more to refresh the setting in case it was changed. - _session->api().requestFullPeer(user); - Ui::show(Box(tr::lng_call_error_not_available(tr::now, lt_user, user->name))); + user->session().api().requestFullPeer(user); + Ui::show(Box( + tr::lng_call_error_not_available(tr::now, lt_user, user->name))); return; } requestMicrophonePermissionOrFail(crl::guard(this, [=] { @@ -101,8 +108,9 @@ void Instance::playSound(Sound sound) { void Instance::destroyCall(not_null call) { if (_currentCall.get() == call) { destroyCurrentPanel(); - _currentCall.reset(); - _currentCallChanged.notify(nullptr, true); + auto taken = base::take(_currentCall); + _currentCallChanges.fire(nullptr); + taken.reset(); if (App::quitting()) { LOG(("Calls::Instance doesn't prevent quit any more.")); @@ -123,17 +131,24 @@ void Instance::destroyCurrentPanel() { } void Instance::createCall(not_null user, Call::Type type) { - auto call = std::make_unique(getCallDelegate(), user, type);; + auto call = std::make_unique(getCallDelegate(), user, type); + const auto raw = call.get(); + + user->session().account().sessionChanges( + ) | rpl::start_with_next([=] { + destroyCall(raw); + }, raw->lifetime()); + if (_currentCall) { - _currentCallPanel->replaceCall(call.get()); + _currentCallPanel->replaceCall(raw); std::swap(_currentCall, call); call->hangup(); } else { - _currentCallPanel = std::make_unique(call.get()); + _currentCallPanel = std::make_unique(raw); _currentCall = std::move(call); } - _currentCallChanged.notify(_currentCall.get(), true); - refreshServerConfig(); + _currentCallChanges.fire_copy(raw); + refreshServerConfig(&user->session()); refreshDhConfig(); } @@ -141,7 +156,7 @@ void Instance::refreshDhConfig() { Expects(_currentCall != nullptr); const auto weak = base::make_weak(_currentCall); - _api.request(MTPmessages_GetDhConfig( + _currentCall->user()->session().api().request(MTPmessages_GetDhConfig( MTP_int(_dhConfig.version), MTP_int(MTP::ModExpFirst::kRandomPowerSize) )).done([=](const MTPmessages_DhConfig &result) { @@ -198,27 +213,32 @@ bytes::const_span Instance::updateDhConfig( }); } -void Instance::refreshServerConfig() { - if (_serverConfigRequestId) { +void Instance::refreshServerConfig(not_null session) { + if (_serverConfigRequestSession) { return; } - if (_lastServerConfigUpdateTime && (crl::now() - _lastServerConfigUpdateTime) < kServerConfigUpdateTimeoutMs) { + if (_lastServerConfigUpdateTime + && ((crl::now() - _lastServerConfigUpdateTime) + < kServerConfigUpdateTimeoutMs)) { return; } - _serverConfigRequestId = _api.request(MTPphone_GetCallConfig( + _serverConfigRequestSession = session; + session->api().request(MTPphone_GetCallConfig( )).done([=](const MTPDataJSON &result) { - _serverConfigRequestId = 0; + _serverConfigRequestSession = nullptr; _lastServerConfigUpdateTime = crl::now(); const auto &json = result.c_dataJSON().vdata().v; UpdateConfig(std::string(json.data(), json.size())); }).fail([=](const RPCError &error) { - _serverConfigRequestId = 0; - }).send(); + _serverConfigRequestSession = nullptr; + }).send(); } -void Instance::handleUpdate(const MTPDupdatePhoneCall& update) { - handleCallUpdate(update.vphone_call()); +void Instance::handleUpdate( + not_null session, + const MTPDupdatePhoneCall& update) { + handleCallUpdate(session, update.vphone_call()); } void Instance::showInfoPanel(not_null call) { @@ -239,18 +259,20 @@ bool Instance::isQuitPrevent() { return true; } -void Instance::handleCallUpdate(const MTPPhoneCall &call) { +void Instance::handleCallUpdate( + not_null session, + const MTPPhoneCall &call) { if (call.type() == mtpc_phoneCallRequested) { auto &phoneCall = call.c_phoneCallRequested(); - auto user = _session->data().userLoaded(phoneCall.vadmin_id().v); + auto user = session->data().userLoaded(phoneCall.vadmin_id().v); if (!user) { LOG(("API Error: User not loaded for phoneCallRequested.")); } else if (user->isSelf()) { LOG(("API Error: Self found in phoneCallRequested.")); } - const auto &config = _session->serverConfig(); + const auto &config = session->serverConfig(); if (alreadyInCall() || !user || user->isSelf()) { - _api.request(MTPphone_DiscardCall( + session->api().request(MTPphone_DiscardCall( MTP_flags(0), MTP_inputPhoneCall(phoneCall.vid(), phoneCall.vaccess_hash()), MTP_int(0), @@ -273,10 +295,14 @@ bool Instance::alreadyInCall() { return (_currentCall && _currentCall->state() != Call::State::Busy); } -Call *Instance::currentCall() { +Call *Instance::currentCall() const { return _currentCall.get(); } +rpl::producer Instance::currentCallValue() const { + return _currentCallChanges.events_starting_with(currentCall()); +} + void Instance::requestMicrophonePermissionOrFail(Fn onSuccess) { Platform::PermissionStatus status=Platform::GetPermissionStatus(Platform::PermissionType::Microphone); if (status==Platform::PermissionStatus::Granted) { @@ -302,12 +328,4 @@ void Instance::requestMicrophonePermissionOrFail(Fn onSuccess) { } } -Instance::~Instance() { - for (auto panel : _pendingPanels) { - if (panel) { - delete panel; - } - } -} - } // namespace Calls diff --git a/Telegram/SourceFiles/calls/calls_instance.h b/Telegram/SourceFiles/calls/calls_instance.h index d8987f4582..92a6ad58a5 100644 --- a/Telegram/SourceFiles/calls/calls_instance.h +++ b/Telegram/SourceFiles/calls/calls_instance.h @@ -29,24 +29,18 @@ class Instance , private base::Subscriber , public base::has_weak_ptr { public: - explicit Instance(not_null session); + Instance(); + ~Instance(); void startOutgoingCall(not_null user); - void handleUpdate(const MTPDupdatePhoneCall &update); + void handleUpdate( + not_null session, + const MTPDupdatePhoneCall &update); void showInfoPanel(not_null call); - Call* currentCall(); + [[nodiscard]] Call *currentCall() const; + [[nodiscard]] rpl::producer currentCallValue() const; - base::Observable ¤tCallChanged() { - return _currentCallChanged; - } - - base::Observable &newServiceMessage() { - return _newServiceMessage; - } - - bool isQuitPrevent(); - - ~Instance(); + [[nodiscard]] bool isQuitPrevent(); private: not_null getCallDelegate() { @@ -66,21 +60,21 @@ private: void requestMicrophonePermissionOrFail(Fn onSuccess) override; void refreshDhConfig(); - void refreshServerConfig(); + void refreshServerConfig(not_null session); bytes::const_span updateDhConfig(const MTPmessages_DhConfig &data); bool alreadyInCall(); - void handleCallUpdate(const MTPPhoneCall &call); - - const not_null _session; - MTP::Sender _api; + void handleCallUpdate( + not_null session, + const MTPPhoneCall &call); DhConfig _dhConfig; crl::time _lastServerConfigUpdateTime = 0; - mtpRequestId _serverConfigRequestId = 0; + base::weak_ptr _serverConfigRequestSession; std::unique_ptr _currentCall; + rpl::event_stream _currentCallChanges; std::unique_ptr _currentCallPanel; base::Observable _currentCallChanged; base::Observable _newServiceMessage; diff --git a/Telegram/SourceFiles/calls/calls_panel.cpp b/Telegram/SourceFiles/calls/calls_panel.cpp index 465799906e..1442e8894d 100644 --- a/Telegram/SourceFiles/calls/calls_panel.cpp +++ b/Telegram/SourceFiles/calls/calls_panel.cpp @@ -405,11 +405,11 @@ void Panel::initControls() { void Panel::reinitControls() { Expects(_call != nullptr); - unsubscribe(base::take(_stateChangedSubscription)); - _stateChangedSubscription = subscribe( - _call->stateChanged(), - [=](State state) { stateChanged(state); }); - stateChanged(_call->state()); + _stateLifetime.destroy(); + _call->stateValue( + ) | rpl::start_with_next([=](State state) { + stateChanged(state); + }, _stateLifetime); _signalBars.create( this, diff --git a/Telegram/SourceFiles/calls/calls_panel.h b/Telegram/SourceFiles/calls/calls_panel.h index a674cb66df..697fe26a31 100644 --- a/Telegram/SourceFiles/calls/calls_panel.h +++ b/Telegram/SourceFiles/calls/calls_panel.h @@ -130,7 +130,7 @@ private: QPoint _dragStartMousePosition; QPoint _dragStartMyPosition; - int _stateChangedSubscription = 0; + rpl::lifetime _stateLifetime; class Button; object_ptr