calls_instance.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "calls/calls_instance.h"
  8. #include "calls/calls_call.h"
  9. #include "calls/group/calls_group_common.h"
  10. #include "calls/group/calls_choose_join_as.h"
  11. #include "calls/group/calls_group_call.h"
  12. #include "calls/group/calls_group_rtmp.h"
  13. #include "mtproto/mtproto_dh_utils.h"
  14. #include "core/application.h"
  15. #include "core/core_settings.h"
  16. #include "main/main_session.h"
  17. #include "main/main_account.h"
  18. #include "apiwrap.h"
  19. #include "lang/lang_keys.h"
  20. #include "ui/boxes/confirm_box.h"
  21. #include "calls/group/calls_group_call.h"
  22. #include "calls/group/calls_group_panel.h"
  23. #include "calls/calls_call.h"
  24. #include "calls/calls_panel.h"
  25. #include "data/data_user.h"
  26. #include "data/data_group_call.h"
  27. #include "data/data_channel.h"
  28. #include "data/data_chat.h"
  29. #include "data/data_session.h"
  30. #include "media/audio/media_audio_track.h"
  31. #include "platform/platform_specific.h"
  32. #include "ui/toast/toast.h"
  33. #include "base/unixtime.h"
  34. #include "mtproto/mtproto_config.h"
  35. #include "boxes/abstract_box.h" // Ui::show().
  36. #include <tgcalls/VideoCaptureInterface.h>
  37. #include <tgcalls/StaticThreads.h>
  38. namespace Calls {
  39. namespace {
  40. constexpr auto kServerConfigUpdateTimeoutMs = 24 * 3600 * crl::time(1000);
  41. using CallSound = Call::Delegate::CallSound;
  42. using GroupCallSound = GroupCall::Delegate::GroupCallSound;
  43. } // namespace
  44. class Instance::Delegate final
  45. : public Call::Delegate
  46. , public GroupCall::Delegate {
  47. public:
  48. explicit Delegate(not_null<Instance*> instance);
  49. DhConfig getDhConfig() const override;
  50. void callFinished(not_null<Call*> call) override;
  51. void callFailed(not_null<Call*> call) override;
  52. void callRedial(not_null<Call*> call) override;
  53. void callRequestPermissionsOrFail(
  54. Fn<void()> onSuccess,
  55. bool video) override;
  56. void callPlaySound(CallSound sound) override;
  57. auto callGetVideoCapture(
  58. const QString &deviceId,
  59. bool isScreenCapture)
  60. -> std::shared_ptr<tgcalls::VideoCaptureInterface> override;
  61. void groupCallFinished(not_null<GroupCall*> call) override;
  62. void groupCallFailed(not_null<GroupCall*> call) override;
  63. void groupCallRequestPermissionsOrFail(Fn<void()> onSuccess) override;
  64. void groupCallPlaySound(GroupCallSound sound) override;
  65. auto groupCallGetVideoCapture(const QString &deviceId)
  66. -> std::shared_ptr<tgcalls::VideoCaptureInterface> override;
  67. FnMut<void()> groupCallAddAsyncWaiter() override;
  68. private:
  69. const not_null<Instance*> _instance;
  70. };
  71. Instance::Delegate::Delegate(not_null<Instance*> instance)
  72. : _instance(instance) {
  73. }
  74. DhConfig Instance::Delegate::getDhConfig() const {
  75. return *_instance->_cachedDhConfig;
  76. }
  77. void Instance::Delegate::callFinished(not_null<Call*> call) {
  78. crl::on_main(call, [=] {
  79. _instance->destroyCall(call);
  80. });
  81. }
  82. void Instance::Delegate::callFailed(not_null<Call*> call) {
  83. crl::on_main(call, [=] {
  84. _instance->destroyCall(call);
  85. });
  86. }
  87. void Instance::Delegate::callRedial(not_null<Call*> call) {
  88. if (_instance->_currentCall.get() == call) {
  89. _instance->refreshDhConfig();
  90. }
  91. }
  92. void Instance::Delegate::callRequestPermissionsOrFail(
  93. Fn<void()> onSuccess,
  94. bool video) {
  95. _instance->requestPermissionsOrFail(std::move(onSuccess), video);
  96. }
  97. void Instance::Delegate::callPlaySound(CallSound sound) {
  98. _instance->playSoundOnce([&] {
  99. switch (sound) {
  100. case CallSound::Busy: return "call_busy";
  101. case CallSound::Ended: return "call_end";
  102. case CallSound::Connecting: return "call_connect";
  103. }
  104. Unexpected("CallSound in Instance::callPlaySound.");
  105. }());
  106. }
  107. auto Instance::Delegate::callGetVideoCapture(
  108. const QString &deviceId,
  109. bool isScreenCapture)
  110. -> std::shared_ptr<tgcalls::VideoCaptureInterface> {
  111. return _instance->getVideoCapture(deviceId, isScreenCapture);
  112. }
  113. void Instance::Delegate::groupCallFinished(not_null<GroupCall*> call) {
  114. crl::on_main(call, [=] {
  115. _instance->destroyGroupCall(call);
  116. });
  117. }
  118. void Instance::Delegate::groupCallFailed(not_null<GroupCall*> call) {
  119. crl::on_main(call, [=] {
  120. _instance->destroyGroupCall(call);
  121. });
  122. }
  123. void Instance::Delegate::groupCallRequestPermissionsOrFail(
  124. Fn<void()> onSuccess) {
  125. _instance->requestPermissionsOrFail(std::move(onSuccess), false);
  126. }
  127. void Instance::Delegate::groupCallPlaySound(GroupCallSound sound) {
  128. _instance->playSoundOnce([&] {
  129. switch (sound) {
  130. case GroupCallSound::Started: return "group_call_start";
  131. case GroupCallSound::Ended: return "group_call_end";
  132. case GroupCallSound::AllowedToSpeak: return "group_call_allowed";
  133. case GroupCallSound::Connecting: return "group_call_connect";
  134. }
  135. Unexpected("GroupCallSound in Instance::groupCallPlaySound.");
  136. }());
  137. }
  138. auto Instance::Delegate::groupCallGetVideoCapture(const QString &deviceId)
  139. -> std::shared_ptr<tgcalls::VideoCaptureInterface> {
  140. return _instance->getVideoCapture(deviceId, false);
  141. }
  142. FnMut<void()> Instance::Delegate::groupCallAddAsyncWaiter() {
  143. return _instance->addAsyncWaiter();
  144. }
  145. Instance::Instance()
  146. : _delegate(std::make_unique<Delegate>(this))
  147. , _cachedDhConfig(std::make_unique<DhConfig>())
  148. , _chooseJoinAs(std::make_unique<Group::ChooseJoinAsProcess>())
  149. , _startWithRtmp(std::make_unique<Group::StartRtmpProcess>()) {
  150. }
  151. Instance::~Instance() {
  152. destroyCurrentCall();
  153. while (!_asyncWaiters.empty()) {
  154. _asyncWaiters.front()->acquire();
  155. _asyncWaiters.erase(_asyncWaiters.begin());
  156. }
  157. }
  158. void Instance::startOutgoingCall(not_null<UserData*> user, bool video) {
  159. if (activateCurrentCall()) {
  160. return;
  161. }
  162. if (user->callsStatus() == UserData::CallsStatus::Private) {
  163. // Request full user once more to refresh the setting in case it was changed.
  164. user->session().api().requestFullPeer(user);
  165. Ui::show(Ui::MakeInformBox(tr::lng_call_error_not_available(
  166. tr::now,
  167. lt_user,
  168. user->name())));
  169. return;
  170. }
  171. requestPermissionsOrFail(crl::guard(this, [=] {
  172. createCall(user, Call::Type::Outgoing, video);
  173. }), video);
  174. }
  175. void Instance::startOrJoinGroupCall(
  176. std::shared_ptr<Ui::Show> show,
  177. not_null<PeerData*> peer,
  178. StartGroupCallArgs args) {
  179. confirmLeaveCurrent(show, peer, args, [=](StartGroupCallArgs args) {
  180. using JoinConfirm = Calls::StartGroupCallArgs::JoinConfirm;
  181. const auto context = (args.confirm == JoinConfirm::Always)
  182. ? Group::ChooseJoinAsProcess::Context::JoinWithConfirm
  183. : peer->groupCall()
  184. ? Group::ChooseJoinAsProcess::Context::Join
  185. : args.scheduleNeeded
  186. ? Group::ChooseJoinAsProcess::Context::CreateScheduled
  187. : Group::ChooseJoinAsProcess::Context::Create;
  188. _chooseJoinAs->start(peer, context, show, [=](Group::JoinInfo info) {
  189. const auto call = info.peer->groupCall();
  190. info.joinHash = args.joinHash;
  191. if (call) {
  192. info.rtmp = call->rtmp();
  193. }
  194. createGroupCall(
  195. std::move(info),
  196. call ? call->input() : MTP_inputGroupCall({}, {}));
  197. });
  198. });
  199. }
  200. void Instance::confirmLeaveCurrent(
  201. std::shared_ptr<Ui::Show> show,
  202. not_null<PeerData*> peer,
  203. StartGroupCallArgs args,
  204. Fn<void(StartGroupCallArgs)> confirmed) {
  205. using JoinConfirm = Calls::StartGroupCallArgs::JoinConfirm;
  206. auto confirmedArgs = args;
  207. confirmedArgs.confirm = JoinConfirm::None;
  208. const auto askConfirmation = [&](QString text, QString button) {
  209. show->showBox(Ui::MakeConfirmBox({
  210. .text = text,
  211. .confirmed = [=] {
  212. show->hideLayer();
  213. confirmed(confirmedArgs);
  214. },
  215. .confirmText = button,
  216. }));
  217. };
  218. if (args.confirm != JoinConfirm::None && inCall()) {
  219. // Do you want to leave your active voice chat
  220. // to join a voice chat in this group?
  221. askConfirmation(
  222. (peer->isBroadcast()
  223. ? tr::lng_call_leave_to_other_sure_channel
  224. : tr::lng_call_leave_to_other_sure)(tr::now),
  225. tr::lng_call_bar_hangup(tr::now));
  226. } else if (args.confirm != JoinConfirm::None && inGroupCall()) {
  227. const auto now = currentGroupCall()->peer();
  228. if (now == peer) {
  229. activateCurrentCall(args.joinHash);
  230. } else if (currentGroupCall()->scheduleDate()) {
  231. confirmed(confirmedArgs);
  232. } else {
  233. askConfirmation(
  234. ((peer->isBroadcast() && now->isBroadcast())
  235. ? tr::lng_group_call_leave_channel_to_other_sure_channel
  236. : now->isBroadcast()
  237. ? tr::lng_group_call_leave_channel_to_other_sure
  238. : peer->isBroadcast()
  239. ? tr::lng_group_call_leave_to_other_sure_channel
  240. : tr::lng_group_call_leave_to_other_sure)(tr::now),
  241. tr::lng_group_call_leave(tr::now));
  242. }
  243. } else {
  244. confirmed(args);
  245. }
  246. }
  247. void Instance::showStartWithRtmp(
  248. std::shared_ptr<Ui::Show> show,
  249. not_null<PeerData*> peer) {
  250. _startWithRtmp->start(peer, show, [=](Group::JoinInfo info) {
  251. confirmLeaveCurrent(show, peer, {}, [=](auto) {
  252. _startWithRtmp->close();
  253. createGroupCall(std::move(info), MTP_inputGroupCall({}, {}));
  254. });
  255. });
  256. }
  257. not_null<Media::Audio::Track*> Instance::ensureSoundLoaded(
  258. const QString &key) {
  259. const auto i = _tracks.find(key);
  260. if (i != end(_tracks)) {
  261. return i->second.get();
  262. }
  263. const auto result = _tracks.emplace(
  264. key,
  265. Media::Audio::Current().createTrack()).first->second.get();
  266. result->fillFromFile(Core::App().settings().getSoundPath(key));
  267. return result;
  268. }
  269. void Instance::playSoundOnce(const QString &key) {
  270. ensureSoundLoaded(key)->playOnce();
  271. }
  272. void Instance::destroyCall(not_null<Call*> call) {
  273. if (_currentCall.get() == call) {
  274. _currentCallPanel->closeBeforeDestroy();
  275. _currentCallPanel = nullptr;
  276. auto taken = base::take(_currentCall);
  277. _currentCallChanges.fire(nullptr);
  278. taken.reset();
  279. if (Core::Quitting()) {
  280. LOG(("Calls::Instance doesn't prevent quit any more."));
  281. }
  282. Core::App().quitPreventFinished();
  283. }
  284. }
  285. void Instance::createCall(
  286. not_null<UserData*> user,
  287. Call::Type type,
  288. bool isVideo) {
  289. struct Performer final {
  290. explicit Performer(Fn<void(bool, bool, const Performer &)> callback)
  291. : callback(std::move(callback)) {
  292. }
  293. Fn<void(bool, bool, const Performer &)> callback;
  294. };
  295. const auto performer = Performer([=](
  296. bool video,
  297. bool isConfirmed,
  298. const Performer &repeater) {
  299. const auto delegate = _delegate.get();
  300. auto call = std::make_unique<Call>(delegate, user, type, video);
  301. if (isConfirmed) {
  302. call->applyUserConfirmation();
  303. }
  304. const auto raw = call.get();
  305. user->session().account().sessionChanges(
  306. ) | rpl::start_with_next([=] {
  307. destroyCall(raw);
  308. }, raw->lifetime());
  309. if (_currentCall) {
  310. _currentCallPanel->replaceCall(raw);
  311. std::swap(_currentCall, call);
  312. call->hangup();
  313. } else {
  314. _currentCallPanel = std::make_unique<Panel>(raw);
  315. _currentCall = std::move(call);
  316. }
  317. if (raw->state() == Call::State::WaitingUserConfirmation) {
  318. _currentCallPanel->startOutgoingRequests(
  319. ) | rpl::start_with_next([=](bool video) {
  320. repeater.callback(video, true, repeater);
  321. }, raw->lifetime());
  322. } else {
  323. refreshServerConfig(&user->session());
  324. refreshDhConfig();
  325. }
  326. _currentCallChanges.fire_copy(raw);
  327. });
  328. performer.callback(isVideo, false, performer);
  329. }
  330. void Instance::destroyGroupCall(not_null<GroupCall*> call) {
  331. if (_currentGroupCall.get() == call) {
  332. _currentGroupCallPanel->closeBeforeDestroy();
  333. _currentGroupCallPanel = nullptr;
  334. auto taken = base::take(_currentGroupCall);
  335. _currentGroupCallChanges.fire(nullptr);
  336. taken.reset();
  337. if (Core::Quitting()) {
  338. LOG(("Calls::Instance doesn't prevent quit any more."));
  339. }
  340. Core::App().quitPreventFinished();
  341. }
  342. }
  343. void Instance::createGroupCall(
  344. Group::JoinInfo info,
  345. const MTPInputGroupCall &inputCall) {
  346. destroyCurrentCall();
  347. auto call = std::make_unique<GroupCall>(
  348. _delegate.get(),
  349. std::move(info),
  350. inputCall);
  351. const auto raw = call.get();
  352. info.peer->session().account().sessionChanges(
  353. ) | rpl::start_with_next([=] {
  354. destroyGroupCall(raw);
  355. }, raw->lifetime());
  356. _currentGroupCallPanel = std::make_unique<Group::Panel>(raw);
  357. _currentGroupCall = std::move(call);
  358. _currentGroupCallChanges.fire_copy(raw);
  359. }
  360. void Instance::refreshDhConfig() {
  361. Expects(_currentCall != nullptr);
  362. const auto weak = base::make_weak(_currentCall);
  363. _currentCall->user()->session().api().request(MTPmessages_GetDhConfig(
  364. MTP_int(_cachedDhConfig->version),
  365. MTP_int(MTP::ModExpFirst::kRandomPowerSize)
  366. )).done([=](const MTPmessages_DhConfig &result) {
  367. const auto call = weak.get();
  368. const auto random = updateDhConfig(result);
  369. if (!call) {
  370. return;
  371. }
  372. if (!random.empty()) {
  373. Assert(random.size() == MTP::ModExpFirst::kRandomPowerSize);
  374. call->start(random);
  375. } else {
  376. _delegate->callFailed(call);
  377. }
  378. }).fail([=] {
  379. const auto call = weak.get();
  380. if (!call) {
  381. return;
  382. }
  383. _delegate->callFailed(call);
  384. }).send();
  385. }
  386. bytes::const_span Instance::updateDhConfig(
  387. const MTPmessages_DhConfig &data) {
  388. const auto validRandom = [](const QByteArray & random) {
  389. if (random.size() != MTP::ModExpFirst::kRandomPowerSize) {
  390. return false;
  391. }
  392. return true;
  393. };
  394. return data.match([&](const MTPDmessages_dhConfig &data)
  395. -> bytes::const_span {
  396. auto primeBytes = bytes::make_vector(data.vp().v);
  397. if (!MTP::IsPrimeAndGood(primeBytes, data.vg().v)) {
  398. LOG(("API Error: bad p/g received in dhConfig."));
  399. return {};
  400. } else if (!validRandom(data.vrandom().v)) {
  401. return {};
  402. }
  403. _cachedDhConfig->g = data.vg().v;
  404. _cachedDhConfig->p = std::move(primeBytes);
  405. _cachedDhConfig->version = data.vversion().v;
  406. return bytes::make_span(data.vrandom().v);
  407. }, [&](const MTPDmessages_dhConfigNotModified &data)
  408. -> bytes::const_span {
  409. if (!_cachedDhConfig->g || _cachedDhConfig->p.empty()) {
  410. LOG(("API Error: dhConfigNotModified on zero version."));
  411. return {};
  412. } else if (!validRandom(data.vrandom().v)) {
  413. return {};
  414. }
  415. return bytes::make_span(data.vrandom().v);
  416. });
  417. }
  418. void Instance::refreshServerConfig(not_null<Main::Session*> session) {
  419. if (_serverConfigRequestSession) {
  420. return;
  421. }
  422. if (_lastServerConfigUpdateTime
  423. && ((crl::now() - _lastServerConfigUpdateTime)
  424. < kServerConfigUpdateTimeoutMs)) {
  425. return;
  426. }
  427. _serverConfigRequestSession = session;
  428. session->api().request(MTPphone_GetCallConfig(
  429. )).done([=](const MTPDataJSON &result) {
  430. _serverConfigRequestSession = nullptr;
  431. _lastServerConfigUpdateTime = crl::now();
  432. const auto &json = result.c_dataJSON().vdata().v;
  433. UpdateConfig(std::string(json.data(), json.size()));
  434. }).fail([=] {
  435. _serverConfigRequestSession = nullptr;
  436. }).send();
  437. }
  438. void Instance::handleUpdate(
  439. not_null<Main::Session*> session,
  440. const MTPUpdate &update) {
  441. update.match([&](const MTPDupdatePhoneCall &data) {
  442. handleCallUpdate(session, data.vphone_call());
  443. }, [&](const MTPDupdatePhoneCallSignalingData &data) {
  444. handleSignalingData(session, data);
  445. }, [&](const MTPDupdateGroupCall &data) {
  446. handleGroupCallUpdate(session, update);
  447. }, [&](const MTPDupdateGroupCallConnection &data) {
  448. handleGroupCallUpdate(session, update);
  449. }, [&](const MTPDupdateGroupCallParticipants &data) {
  450. handleGroupCallUpdate(session, update);
  451. }, [](const auto &) {
  452. Unexpected("Update type in Calls::Instance::handleUpdate.");
  453. });
  454. }
  455. void Instance::showInfoPanel(not_null<Call*> call) {
  456. if (_currentCall.get() == call) {
  457. _currentCallPanel->showAndActivate();
  458. }
  459. }
  460. void Instance::showInfoPanel(not_null<GroupCall*> call) {
  461. if (_currentGroupCall.get() == call) {
  462. _currentGroupCallPanel->showAndActivate();
  463. }
  464. }
  465. FnMut<void()> Instance::addAsyncWaiter() {
  466. auto semaphore = std::make_unique<crl::semaphore>();
  467. const auto raw = semaphore.get();
  468. const auto weak = base::make_weak(this);
  469. _asyncWaiters.emplace(std::move(semaphore));
  470. return [raw, weak] {
  471. raw->release();
  472. crl::on_main(weak, [raw, weak] {
  473. auto &waiters = weak->_asyncWaiters;
  474. auto wrapped = std::unique_ptr<crl::semaphore>(raw);
  475. const auto i = waiters.find(wrapped);
  476. wrapped.release();
  477. if (i != end(waiters)) {
  478. waiters.erase(i);
  479. }
  480. });
  481. };
  482. }
  483. bool Instance::isSharingScreen() const {
  484. return (_currentCall && _currentCall->isSharingScreen())
  485. || (_currentGroupCall && _currentGroupCall->isSharingScreen());
  486. }
  487. bool Instance::isQuitPrevent() {
  488. if (!_currentCall || _currentCall->isIncomingWaiting()) {
  489. return false;
  490. }
  491. _currentCall->hangup();
  492. if (!_currentCall) {
  493. return false;
  494. }
  495. LOG(("Calls::Instance prevents quit, hanging up a call..."));
  496. return true;
  497. }
  498. void Instance::handleCallUpdate(
  499. not_null<Main::Session*> session,
  500. const MTPPhoneCall &call) {
  501. if (call.type() == mtpc_phoneCallRequested) {
  502. auto &phoneCall = call.c_phoneCallRequested();
  503. auto user = session->data().userLoaded(phoneCall.vadmin_id());
  504. if (!user) {
  505. LOG(("API Error: User not loaded for phoneCallRequested."));
  506. } else if (user->isSelf()) {
  507. LOG(("API Error: Self found in phoneCallRequested."));
  508. } else if (_currentCall
  509. && _currentCall->user() == user
  510. && _currentCall->id() == phoneCall.vid().v) {
  511. // May be a repeated phoneCallRequested update from getDifference.
  512. return;
  513. }
  514. if (inCall()
  515. && _currentCall->type() == Call::Type::Outgoing
  516. && _currentCall->user()->id == session->userPeerId()
  517. && (user->id == _currentCall->user()->session().userPeerId())) {
  518. // Ignore call from the same running app, other account.
  519. return;
  520. }
  521. const auto &config = session->serverConfig();
  522. if (inCall() || inGroupCall() || !user || user->isSelf()) {
  523. const auto flags = phoneCall.is_video()
  524. ? MTPphone_DiscardCall::Flag::f_video
  525. : MTPphone_DiscardCall::Flag(0);
  526. session->api().request(MTPphone_DiscardCall(
  527. MTP_flags(flags),
  528. MTP_inputPhoneCall(phoneCall.vid(), phoneCall.vaccess_hash()),
  529. MTP_int(0),
  530. MTP_phoneCallDiscardReasonBusy(),
  531. MTP_long(0)
  532. )).send();
  533. } else if (phoneCall.vdate().v + (config.callRingTimeoutMs / 1000)
  534. < base::unixtime::now()) {
  535. LOG(("Ignoring too old call."));
  536. } else {
  537. createCall(user, Call::Type::Incoming, phoneCall.is_video());
  538. _currentCall->handleUpdate(call);
  539. }
  540. } else if (!_currentCall
  541. || (&_currentCall->user()->session() != session)
  542. || !_currentCall->handleUpdate(call)) {
  543. DEBUG_LOG(("API Warning: unexpected phone call update %1").arg(call.type()));
  544. }
  545. }
  546. void Instance::handleGroupCallUpdate(
  547. not_null<Main::Session*> session,
  548. const MTPUpdate &update) {
  549. if (_currentGroupCall
  550. && (&_currentGroupCall->peer()->session() == session)) {
  551. update.match([&](const MTPDupdateGroupCall &data) {
  552. _currentGroupCall->handlePossibleCreateOrJoinResponse(data);
  553. }, [&](const MTPDupdateGroupCallConnection &data) {
  554. _currentGroupCall->handlePossibleCreateOrJoinResponse(data);
  555. }, [](const auto &) {
  556. });
  557. }
  558. if (update.type() == mtpc_updateGroupCallConnection) {
  559. return;
  560. }
  561. const auto callId = update.match([](const MTPDupdateGroupCall &data) {
  562. return data.vcall().match([](const auto &data) {
  563. return data.vid().v;
  564. });
  565. }, [](const MTPDupdateGroupCallParticipants &data) {
  566. return data.vcall().match([&](const MTPDinputGroupCall &data) {
  567. return data.vid().v;
  568. });
  569. }, [](const auto &) -> CallId {
  570. Unexpected("Type in Instance::handleGroupCallUpdate.");
  571. });
  572. if (const auto existing = session->data().groupCall(callId)) {
  573. existing->enqueueUpdate(update);
  574. } else {
  575. applyGroupCallUpdateChecked(session, update);
  576. }
  577. }
  578. void Instance::applyGroupCallUpdateChecked(
  579. not_null<Main::Session*> session,
  580. const MTPUpdate &update) {
  581. if (_currentGroupCall
  582. && (&_currentGroupCall->peer()->session() == session)) {
  583. _currentGroupCall->handleUpdate(update);
  584. }
  585. }
  586. void Instance::handleSignalingData(
  587. not_null<Main::Session*> session,
  588. const MTPDupdatePhoneCallSignalingData &data) {
  589. if (!_currentCall
  590. || (&_currentCall->user()->session() != session)
  591. || !_currentCall->handleSignalingData(data)) {
  592. DEBUG_LOG(("API Warning: unexpected call signaling data %1"
  593. ).arg(data.vphone_call_id().v));
  594. }
  595. }
  596. bool Instance::inCall() const {
  597. if (!_currentCall) {
  598. return false;
  599. }
  600. const auto state = _currentCall->state();
  601. return (state != Call::State::Busy)
  602. && (state != Call::State::WaitingUserConfirmation);
  603. }
  604. bool Instance::inGroupCall() const {
  605. if (!_currentGroupCall) {
  606. return false;
  607. }
  608. const auto state = _currentGroupCall->state();
  609. return (state != GroupCall::State::HangingUp)
  610. && (state != GroupCall::State::Ended)
  611. && (state != GroupCall::State::FailedHangingUp)
  612. && (state != GroupCall::State::Failed);
  613. }
  614. void Instance::destroyCurrentCall() {
  615. if (const auto current = currentCall()) {
  616. current->hangup();
  617. if (const auto still = currentCall()) {
  618. destroyCall(still);
  619. }
  620. }
  621. if (const auto current = currentGroupCall()) {
  622. current->hangup();
  623. if (const auto still = currentGroupCall()) {
  624. destroyGroupCall(still);
  625. }
  626. }
  627. }
  628. bool Instance::hasVisiblePanel(Main::Session *session) const {
  629. if (inCall()) {
  630. return _currentCallPanel->isVisible()
  631. && (!session || (&_currentCall->user()->session() == session));
  632. } else if (inGroupCall()) {
  633. return _currentGroupCallPanel->isVisible()
  634. && (!session || (&_currentGroupCall->peer()->session() == session));
  635. }
  636. return false;
  637. }
  638. bool Instance::hasActivePanel(Main::Session *session) const {
  639. if (inCall()) {
  640. return _currentCallPanel->isActive()
  641. && (!session || (&_currentCall->user()->session() == session));
  642. } else if (inGroupCall()) {
  643. return _currentGroupCallPanel->isActive()
  644. && (!session || (&_currentGroupCall->peer()->session() == session));
  645. }
  646. return false;
  647. }
  648. bool Instance::activateCurrentCall(const QString &joinHash) {
  649. if (inCall()) {
  650. _currentCallPanel->showAndActivate();
  651. return true;
  652. } else if (inGroupCall()) {
  653. if (!joinHash.isEmpty()) {
  654. _currentGroupCall->rejoinWithHash(joinHash);
  655. }
  656. _currentGroupCallPanel->showAndActivate();
  657. return true;
  658. }
  659. return false;
  660. }
  661. bool Instance::minimizeCurrentActiveCall() {
  662. if (inCall() && _currentCallPanel->isActive()) {
  663. _currentCallPanel->minimize();
  664. return true;
  665. } else if (inGroupCall() && _currentGroupCallPanel->isActive()) {
  666. _currentGroupCallPanel->minimize();
  667. return true;
  668. }
  669. return false;
  670. }
  671. bool Instance::toggleFullScreenCurrentActiveCall() {
  672. if (inCall() && _currentCallPanel->isActive()) {
  673. _currentCallPanel->toggleFullScreen();
  674. return true;
  675. } else if (inGroupCall() && _currentGroupCallPanel->isActive()) {
  676. _currentGroupCallPanel->toggleFullScreen();
  677. return true;
  678. }
  679. return false;
  680. }
  681. bool Instance::closeCurrentActiveCall() {
  682. if (inGroupCall() && _currentGroupCallPanel->isActive()) {
  683. _currentGroupCallPanel->close();
  684. return true;
  685. }
  686. return false;
  687. }
  688. Call *Instance::currentCall() const {
  689. return _currentCall.get();
  690. }
  691. rpl::producer<Call*> Instance::currentCallValue() const {
  692. return _currentCallChanges.events_starting_with(currentCall());
  693. }
  694. GroupCall *Instance::currentGroupCall() const {
  695. return _currentGroupCall.get();
  696. }
  697. rpl::producer<GroupCall*> Instance::currentGroupCallValue() const {
  698. return _currentGroupCallChanges.events_starting_with(currentGroupCall());
  699. }
  700. void Instance::requestPermissionsOrFail(Fn<void()> onSuccess, bool video) {
  701. using Type = Platform::PermissionType;
  702. requestPermissionOrFail(Type::Microphone, [=] {
  703. auto callback = [=] { crl::on_main(onSuccess); };
  704. if (video) {
  705. requestPermissionOrFail(Type::Camera, std::move(callback));
  706. } else {
  707. callback();
  708. }
  709. });
  710. }
  711. void Instance::requestPermissionOrFail(Platform::PermissionType type, Fn<void()> onSuccess) {
  712. using Status = Platform::PermissionStatus;
  713. const auto status = Platform::GetPermissionStatus(type);
  714. if (status == Status::Granted) {
  715. onSuccess();
  716. } else if (status == Status::CanRequest) {
  717. Platform::RequestPermission(type, crl::guard(this, [=](Status status) {
  718. if (status == Status::Granted) {
  719. crl::on_main(onSuccess);
  720. } else {
  721. if (_currentCall) {
  722. _currentCall->hangup();
  723. }
  724. }
  725. }));
  726. } else {
  727. if (inCall()) {
  728. _currentCall->hangup();
  729. }
  730. if (inGroupCall()) {
  731. _currentGroupCall->hangup();
  732. }
  733. Ui::show(Ui::MakeConfirmBox({
  734. .text = tr::lng_no_mic_permission(),
  735. .confirmed = crl::guard(this, [=](Fn<void()> &&close) {
  736. Platform::OpenSystemSettingsForPermission(type);
  737. close();
  738. }),
  739. .confirmText = tr::lng_menu_settings(),
  740. }));
  741. }
  742. }
  743. std::shared_ptr<tgcalls::VideoCaptureInterface> Instance::getVideoCapture(
  744. std::optional<QString> deviceId,
  745. bool isScreenCapture) {
  746. if (auto result = _videoCapture.lock()) {
  747. if (deviceId) {
  748. result->switchToDevice(
  749. (deviceId->isEmpty()
  750. ? Core::App().settings().cameraDeviceId()
  751. : *deviceId).toStdString(),
  752. isScreenCapture);
  753. }
  754. return result;
  755. }
  756. const auto startDeviceId = (deviceId && !deviceId->isEmpty())
  757. ? *deviceId
  758. : Core::App().settings().cameraDeviceId();
  759. auto result = std::shared_ptr<tgcalls::VideoCaptureInterface>(
  760. tgcalls::VideoCaptureInterface::Create(
  761. tgcalls::StaticThreads::getThreads(),
  762. startDeviceId.toStdString()));
  763. _videoCapture = result;
  764. return result;
  765. }
  766. } // namespace Calls