mirror of
https://github.com/telegramdesktop/tdesktop
synced 2024-12-31 19:12:17 +00:00
Discard call in case of an error.
Also add a couple of call error messages.
This commit is contained in:
parent
061bd109d2
commit
c78cc331d1
@ -1141,6 +1141,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
"lng_call_error_not_available" = "Sorry, {user} doesn't accept calls.";
|
||||
"lng_call_error_incompatible" = "{user}'s app is using an incompatible protocol. They need to update their app before you can call them.";
|
||||
"lng_call_error_outdated" = "{user}'s app does not support calls. They need to update their app before you can call them.";
|
||||
"lng_call_error_audio_io" = "There seems to be a problem with audio playback on your computer. Please make sure that your computer's speakers and microphone are working and try again.";
|
||||
|
||||
"lng_call_bar_info" = "Show call info";
|
||||
"lng_call_bar_hangup" = "End call";
|
||||
|
@ -93,7 +93,7 @@ void Call::generateModExpFirst(base::const_byte_span randomSeed) {
|
||||
auto first = MTP::CreateModExp(_dhConfig.g, _dhConfig.p, randomSeed);
|
||||
if (first.modexp.empty()) {
|
||||
LOG(("Call Error: Could not compute mod-exp first."));
|
||||
setState(State::Failed);
|
||||
finish(FinishType::Failed);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -121,7 +121,7 @@ void Call::start(base::const_byte_span random) {
|
||||
t_assert(!_dhConfig.p.empty());
|
||||
|
||||
generateModExpFirst(random);
|
||||
if (_state != State::Failed) {
|
||||
if (_state != State::Failed && _state != State::FailedHangingUp) {
|
||||
if (_type == Type::Outgoing) {
|
||||
startOutgoing();
|
||||
} else {
|
||||
@ -136,11 +136,14 @@ void Call::startOutgoing() {
|
||||
setState(State::Requesting);
|
||||
request(MTPphone_RequestCall(_user->inputUser, MTP_int(rand_value<int32>()), MTP_bytes(_gaHash), MTP_phoneCallProtocol(MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p | MTPDphoneCallProtocol::Flag::f_udp_reflector), MTP_int(kMinLayer), MTP_int(kMaxLayer)))).done([this](const MTPphone_PhoneCall &result) {
|
||||
Expects(result.type() == mtpc_phone_phoneCall);
|
||||
|
||||
setState(State::Waiting);
|
||||
|
||||
auto &call = result.c_phone_phoneCall();
|
||||
App::feedUsers(call.vusers);
|
||||
if (call.vphone_call.type() != mtpc_phoneCallWaiting) {
|
||||
LOG(("Call Error: Expected phoneCallWaiting in response to phone.requestCall()"));
|
||||
setState(State::Failed);
|
||||
finish(FinishType::Failed);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -148,10 +151,12 @@ void Call::startOutgoing() {
|
||||
auto &waitingCall = phoneCall.c_phoneCallWaiting();
|
||||
_id = waitingCall.vid.v;
|
||||
_accessHash = waitingCall.vaccess_hash.v;
|
||||
setState(State::Waiting);
|
||||
|
||||
if (_finishAfterRequestingCall) {
|
||||
hangup();
|
||||
if (_finishAfterRequestingCall != FinishType::None) {
|
||||
if (_finishAfterRequestingCall == FinishType::Failed) {
|
||||
finish(_finishAfterRequestingCall);
|
||||
} else {
|
||||
hangup();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -188,7 +193,7 @@ void Call::answer() {
|
||||
App::feedUsers(call.vusers);
|
||||
if (call.vphone_call.type() != mtpc_phoneCallWaiting) {
|
||||
LOG(("Call Error: Expected phoneCallWaiting in response to phone.acceptCall()"));
|
||||
setState(State::Failed);
|
||||
finish(FinishType::Failed);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -218,7 +223,7 @@ void Call::hangup() {
|
||||
auto declined = (_state == State::WaitingIncoming);
|
||||
auto reason = missed ? MTP_phoneCallDiscardReasonMissed() :
|
||||
declined ? MTP_phoneCallDiscardReasonBusy() : MTP_phoneCallDiscardReasonHangup();
|
||||
finish(reason);
|
||||
finish(FinishType::Ended, reason);
|
||||
}
|
||||
}
|
||||
|
||||
@ -282,7 +287,7 @@ bool Call::handleUpdate(const MTPPhoneCall &call) {
|
||||
}
|
||||
if (AuthSession::CurrentUserId() != data.vparticipant_id.v) {
|
||||
LOG(("Call Error: Wrong call participant_id %1, expected %2.").arg(data.vparticipant_id.v).arg(AuthSession::CurrentUserId()));
|
||||
setState(State::Failed);
|
||||
finish(FinishType::Failed);
|
||||
return true;
|
||||
}
|
||||
_id = data.vid.v;
|
||||
@ -291,7 +296,7 @@ bool Call::handleUpdate(const MTPPhoneCall &call) {
|
||||
auto gaHashBytes = bytesFromMTP(data.vg_a_hash);
|
||||
if (gaHashBytes.size() != _gaHash.size()) {
|
||||
LOG(("Call Error: Wrong g_a_hash size %1, expected %2.").arg(gaHashBytes.size()).arg(_gaHash.size()));
|
||||
setState(State::Failed);
|
||||
finish(FinishType::Failed);
|
||||
return true;
|
||||
}
|
||||
base::copy_bytes(gsl::make_span(_gaHash), gaHashBytes);
|
||||
@ -303,7 +308,7 @@ bool Call::handleUpdate(const MTPPhoneCall &call) {
|
||||
return false;
|
||||
}
|
||||
LOG(("Call Error: phoneCallEmpty received."));
|
||||
setState(State::Failed);
|
||||
finish(FinishType::Failed);
|
||||
} return true;
|
||||
|
||||
case mtpc_phoneCallWaiting: {
|
||||
@ -358,7 +363,7 @@ bool Call::handleUpdate(const MTPPhoneCall &call) {
|
||||
}
|
||||
if (_type != Type::Outgoing) {
|
||||
LOG(("Call Error: Unexpected phoneCallAccepted for an incoming call."));
|
||||
setState(State::Failed);
|
||||
finish(FinishType::Failed);
|
||||
} else if (checkCallFields(data)) {
|
||||
confirmAcceptedCall(data);
|
||||
}
|
||||
@ -375,7 +380,7 @@ void Call::confirmAcceptedCall(const MTPDphoneCallAccepted &call) {
|
||||
auto computedAuthKey = MTP::CreateAuthKey(firstBytes, _randomPower, _dhConfig.p);
|
||||
if (computedAuthKey.empty()) {
|
||||
LOG(("Call Error: Could not compute mod-exp final."));
|
||||
setState(State::Failed);
|
||||
finish(FinishType::Failed);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -389,7 +394,7 @@ void Call::confirmAcceptedCall(const MTPDphoneCallAccepted &call) {
|
||||
App::feedUsers(call.vusers);
|
||||
if (call.vphone_call.type() != mtpc_phoneCall) {
|
||||
LOG(("Call Error: Expected phoneCall in response to phone.confirmCall()"));
|
||||
setState(State::Failed);
|
||||
finish(FinishType::Failed);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -405,7 +410,7 @@ void Call::startConfirmedCall(const MTPDphoneCall &call) {
|
||||
auto firstBytes = bytesFromMTP(call.vg_a_or_b);
|
||||
if (_gaHash != openssl::Sha256(firstBytes)) {
|
||||
LOG(("Call Error: Wrong g_a hash received."));
|
||||
setState(State::Failed);
|
||||
finish(FinishType::Failed);
|
||||
return;
|
||||
}
|
||||
_ga = base::byte_vector(firstBytes.begin(), firstBytes.end());
|
||||
@ -413,7 +418,7 @@ void Call::startConfirmedCall(const MTPDphoneCall &call) {
|
||||
auto computedAuthKey = MTP::CreateAuthKey(firstBytes, _randomPower, _dhConfig.p);
|
||||
if (computedAuthKey.empty()) {
|
||||
LOG(("Call Error: Could not compute mod-exp final."));
|
||||
setState(State::Failed);
|
||||
finish(FinishType::Failed);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -504,7 +509,7 @@ void Call::handleControllerStateChange(tgvoip::VoIPController *controller, int s
|
||||
template <typename T>
|
||||
bool Call::checkCallCommonFields(const T &call) {
|
||||
auto checkFailed = [this] {
|
||||
setState(State::Failed);
|
||||
finish(FinishType::Failed);
|
||||
return false;
|
||||
};
|
||||
if (call.vaccess_hash.v != _accessHash) {
|
||||
@ -530,7 +535,7 @@ bool Call::checkCallFields(const MTPDphoneCall &call) {
|
||||
}
|
||||
if (call.vkey_fingerprint.v != _keyFingerprint) {
|
||||
LOG(("Call Error: Wrong call fingerprint."));
|
||||
setState(State::Failed);
|
||||
finish(FinishType::Failed);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -541,6 +546,12 @@ bool Call::checkCallFields(const MTPDphoneCallAccepted &call) {
|
||||
}
|
||||
|
||||
void Call::setState(State state) {
|
||||
if (_state == State::Failed) {
|
||||
return;
|
||||
}
|
||||
if (_state == State::FailedHangingUp && state != State::Failed) {
|
||||
return;
|
||||
}
|
||||
if (_state != state) {
|
||||
_state = state;
|
||||
_stateChanged.notify(state, true);
|
||||
@ -583,31 +594,37 @@ void Call::setState(State state) {
|
||||
}
|
||||
}
|
||||
|
||||
void Call::finish(const MTPPhoneCallDiscardReason &reason) {
|
||||
void Call::finish(FinishType type, const MTPPhoneCallDiscardReason &reason) {
|
||||
Expects(type != FinishType::None);
|
||||
auto finalState = (type == FinishType::Ended) ? State::Ended : State::Failed;
|
||||
auto hangupState = (type == FinishType::Ended) ? State::HangingUp : State::FailedHangingUp;
|
||||
if (_state == State::Requesting) {
|
||||
_finishByTimeoutTimer.call(kHangupTimeoutMs, [this] { setState(State::Ended); });
|
||||
_finishAfterRequestingCall = true;
|
||||
_finishByTimeoutTimer.call(kHangupTimeoutMs, [this, finalState] { setState(finalState); });
|
||||
_finishAfterRequestingCall = type;
|
||||
return;
|
||||
}
|
||||
if (_state == State::HangingUp || _state == State::Ended) {
|
||||
if (_state == State::HangingUp
|
||||
|| _state == State::FailedHangingUp
|
||||
|| _state == State::Ended
|
||||
|| _state == State::Failed) {
|
||||
return;
|
||||
}
|
||||
if (!_id) {
|
||||
setState(State::Ended);
|
||||
setState(finalState);
|
||||
return;
|
||||
}
|
||||
|
||||
setState(State::HangingUp);
|
||||
setState(hangupState);
|
||||
auto duration = getDurationMs() / 1000;
|
||||
auto connectionId = _controller ? _controller->GetPreferredRelayID() : 0;
|
||||
_finishByTimeoutTimer.call(kHangupTimeoutMs, [this] { setState(State::Ended); });
|
||||
request(MTPphone_DiscardCall(MTP_inputPhoneCall(MTP_long(_id), MTP_long(_accessHash)), MTP_int(duration), reason, MTP_long(connectionId))).done([this](const MTPUpdates &result) {
|
||||
_finishByTimeoutTimer.call(kHangupTimeoutMs, [this, finalState] { setState(finalState); });
|
||||
request(MTPphone_DiscardCall(MTP_inputPhoneCall(MTP_long(_id), MTP_long(_accessHash)), MTP_int(duration), reason, MTP_long(connectionId))).done([this, finalState](const MTPUpdates &result) {
|
||||
// This could be destroyed by updates, so we set Ended after
|
||||
// updates being handled, but in a guarded way.
|
||||
InvokeQueued(this, [this] { setState(State::Ended); });
|
||||
InvokeQueued(this, [this, finalState] { setState(finalState); });
|
||||
App::main()->sentUpdatesReceived(result);
|
||||
}).fail([this](const RPCError &error) {
|
||||
setState(State::Ended);
|
||||
}).fail([this, finalState](const RPCError &error) {
|
||||
setState(finalState);
|
||||
}).send();
|
||||
}
|
||||
|
||||
@ -627,14 +644,16 @@ void Call::handleRequestError(const RPCError &error) {
|
||||
} else if (error.type() == qstr("CALL_PROTOCOL_LAYER_INVALID")) {
|
||||
Ui::show(Box<InformBox>(lng_call_error_incompatible(lt_user, App::peerName(_user))));
|
||||
}
|
||||
setState(State::Failed);
|
||||
finish(FinishType::Failed);
|
||||
}
|
||||
|
||||
void Call::handleControllerError(int error) {
|
||||
if (error == TGVOIP_ERROR_INCOMPATIBLE) {
|
||||
Ui::show(Box<InformBox>(lng_call_error_incompatible(lt_user, App::peerName(_user))));
|
||||
} else if (error == TGVOIP_ERROR_AUDIO_IO) {
|
||||
Ui::show(Box<InformBox>(lang(lng_call_error_audio_io)));
|
||||
}
|
||||
setState(State::Failed);
|
||||
finish(FinishType::Failed);
|
||||
}
|
||||
|
||||
void Call::destroyController() {
|
||||
|
@ -87,6 +87,7 @@ public:
|
||||
WaitingInit,
|
||||
WaitingInitAck,
|
||||
Established,
|
||||
FailedHangingUp,
|
||||
Failed,
|
||||
HangingUp,
|
||||
Ended,
|
||||
@ -127,9 +128,14 @@ public:
|
||||
~Call();
|
||||
|
||||
private:
|
||||
enum class FinishType {
|
||||
None,
|
||||
Ended,
|
||||
Failed,
|
||||
};
|
||||
void handleRequestError(const RPCError &error);
|
||||
void handleControllerError(int error);
|
||||
void finish(const MTPPhoneCallDiscardReason &reason);
|
||||
void finish(FinishType type, const MTPPhoneCallDiscardReason &reason = MTP_phoneCallDiscardReasonDisconnect());
|
||||
void startOutgoing();
|
||||
void startIncoming();
|
||||
void startWaitingTrack();
|
||||
@ -154,7 +160,7 @@ private:
|
||||
gsl::not_null<UserData*> _user;
|
||||
Type _type = Type::Outgoing;
|
||||
State _state = State::Starting;
|
||||
bool _finishAfterRequestingCall = false;
|
||||
FinishType _finishAfterRequestingCall = FinishType::None;
|
||||
base::Observable<State> _stateChanged;
|
||||
TimeMs _startTime = 0;
|
||||
base::DelayedCallTimer _finishByTimeoutTimer;
|
||||
|
@ -694,7 +694,10 @@ void Panel::stateChanged(State state) {
|
||||
updateStatusText(state);
|
||||
|
||||
if (_call) {
|
||||
if ((state != State::HangingUp) && (state != State::Ended) && (state != State::Failed)) {
|
||||
if ((state != State::HangingUp)
|
||||
&& (state != State::Ended)
|
||||
&& (state != State::FailedHangingUp)
|
||||
&& (state != State::Failed)) {
|
||||
auto toggleButton = [this](auto &&button, bool visible) {
|
||||
if (isHidden()) {
|
||||
button->toggleFast(visible);
|
||||
@ -765,6 +768,7 @@ void Panel::updateStatusText(State state) {
|
||||
}
|
||||
return lang(lng_call_status_ended);
|
||||
} break;
|
||||
case State::FailedHangingUp:
|
||||
case State::Failed: return lang(lng_call_status_failed);
|
||||
case State::HangingUp: return lang(lng_call_status_hanging);
|
||||
case State::Ended: return lang(lng_call_status_ended);
|
||||
|
Loading…
Reference in New Issue
Block a user