calls_group_call.cpp 98 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570
  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/group/calls_group_call.h"
  8. #include "calls/group/calls_group_common.h"
  9. #include "main/main_session.h"
  10. #include "api/api_send_progress.h"
  11. #include "api/api_updates.h"
  12. #include "apiwrap.h"
  13. #include "lang/lang_keys.h"
  14. #include "lang/lang_hardcoded.h"
  15. #include "boxes/peers/edit_participants_box.h" // SubscribeToMigration.
  16. #include "ui/toast/toast.h"
  17. #include "ui/ui_utility.h"
  18. #include "base/unixtime.h"
  19. #include "core/application.h"
  20. #include "core/core_settings.h"
  21. #include "data/data_changes.h"
  22. #include "data/data_user.h"
  23. #include "data/data_chat.h"
  24. #include "data/data_channel.h"
  25. #include "data/data_group_call.h"
  26. #include "data/data_peer_values.h"
  27. #include "data/data_session.h"
  28. #include "base/global_shortcuts.h"
  29. #include "base/random.h"
  30. #include "webrtc/webrtc_video_track.h"
  31. #include "webrtc/webrtc_create_adm.h"
  32. #include "webrtc/webrtc_environment.h"
  33. #include <tgcalls/group/GroupInstanceCustomImpl.h>
  34. #include <tgcalls/VideoCaptureInterface.h>
  35. #include <tgcalls/StaticThreads.h>
  36. #include <QtCore/QJsonDocument>
  37. #include <QtCore/QJsonObject>
  38. #include <QtCore/QJsonArray>
  39. namespace Calls {
  40. namespace {
  41. constexpr auto kMaxInvitePerSlice = 10;
  42. constexpr auto kCheckLastSpokeInterval = crl::time(1000);
  43. constexpr auto kCheckJoinedTimeout = 4 * crl::time(1000);
  44. constexpr auto kUpdateSendActionEach = crl::time(500);
  45. constexpr auto kPlayConnectingEach = crl::time(1056) + 2 * crl::time(1000);
  46. constexpr auto kFixManualLargeVideoDuration = 5 * crl::time(1000);
  47. constexpr auto kFixSpeakingLargeVideoDuration = 3 * crl::time(1000);
  48. constexpr auto kFullAsMediumsCount = 4; // 1 Full is like 4 Mediums.
  49. constexpr auto kMaxMediumQualities = 16; // 4 Fulls or 16 Mediums.
  50. [[nodiscard]] const Data::GroupCallParticipant *LookupParticipant(
  51. not_null<PeerData*> peer,
  52. CallId id,
  53. not_null<PeerData*> participantPeer) {
  54. const auto call = peer->groupCall();
  55. return (id && call && call->id() == id)
  56. ? call->participantByPeer(participantPeer)
  57. : nullptr;
  58. }
  59. [[nodiscard]] double TimestampFromMsgId(mtpMsgId msgId) {
  60. return msgId / double(1ULL << 32);
  61. }
  62. [[nodiscard]] int64 TimestampInMsFromMsgId(mtpMsgId msgId) {
  63. // return (msgId * 1000) / (1ULL << 32); // Almost... But this overflows.
  64. return ((msgId / (1ULL << 10)) * 1000) / (1ULL << 22);
  65. }
  66. [[nodiscard]] uint64 FindLocalRaisedHandRating(
  67. const std::vector<Data::GroupCallParticipant> &list) {
  68. const auto i = ranges::max_element(
  69. list,
  70. ranges::less(),
  71. &Data::GroupCallParticipant::raisedHandRating);
  72. return (i == end(list)) ? 1 : (i->raisedHandRating + 1);
  73. }
  74. struct JoinVideoEndpoint {
  75. std::string id;
  76. };
  77. struct JoinBroadcastStream {
  78. bool rtmp = false;
  79. Group::RtmpInfo rtmpInfo;
  80. };
  81. using JoinClientFields = std::variant<
  82. v::null_t,
  83. JoinVideoEndpoint,
  84. JoinBroadcastStream>;
  85. [[nodiscard]] JoinClientFields ParseJoinResponse(const QByteArray &json) {
  86. auto error = QJsonParseError{ 0, QJsonParseError::NoError };
  87. const auto document = QJsonDocument::fromJson(json, &error);
  88. if (error.error != QJsonParseError::NoError) {
  89. LOG(("API Error: "
  90. "Failed to parse join response params, error: %1."
  91. ).arg(error.errorString()));
  92. return {};
  93. } else if (!document.isObject()) {
  94. LOG(("API Error: "
  95. "Not an object received in join response params."));
  96. return {};
  97. }
  98. if (document.object().value("stream").toBool()) {
  99. return JoinBroadcastStream{
  100. .rtmp = document.object().value("rtmp").toBool(),
  101. .rtmpInfo = {
  102. .url = document.object().value("rtmp_stream_url").toString(),
  103. .key = document.object().value("rtmp_stream_key").toString(),
  104. },
  105. };
  106. }
  107. const auto video = document.object().value("video").toObject();
  108. return JoinVideoEndpoint{
  109. video.value("endpoint").toString().toStdString(),
  110. };
  111. }
  112. [[nodiscard]] const std::string &EmptyString() {
  113. static const auto result = std::string();
  114. return result;
  115. }
  116. } // namespace
  117. class GroupCall::LoadPartTask final : public tgcalls::BroadcastPartTask {
  118. public:
  119. using Quality = tgcalls::VideoChannelDescription::Quality;
  120. LoadPartTask(
  121. base::weak_ptr<GroupCall> call,
  122. int64 time,
  123. int64 period,
  124. Fn<void(tgcalls::BroadcastPart&&)> done);
  125. LoadPartTask(
  126. base::weak_ptr<GroupCall> call,
  127. int64 time,
  128. int64 period,
  129. int32 videoChannel,
  130. Quality videoQuality,
  131. Fn<void(tgcalls::BroadcastPart&&)> done);
  132. [[nodiscard]] int64 time() const {
  133. return _time;
  134. }
  135. [[nodiscard]] int32 scale() const {
  136. return _scale;
  137. }
  138. [[nodiscard]] int32 videoChannel() const {
  139. return _videoChannel;
  140. }
  141. [[nodiscard]] Quality videoQuality() const {
  142. return _videoQuality;
  143. }
  144. void done(tgcalls::BroadcastPart &&part);
  145. void cancel() override;
  146. private:
  147. const base::weak_ptr<GroupCall> _call;
  148. const int64 _time = 0;
  149. const int32 _scale = 0;
  150. const int32 _videoChannel = 0;
  151. const Quality _videoQuality = {};
  152. Fn<void(tgcalls::BroadcastPart &&)> _done;
  153. QMutex _mutex;
  154. };
  155. class GroupCall::MediaChannelDescriptionsTask final
  156. : public tgcalls::RequestMediaChannelDescriptionTask {
  157. public:
  158. MediaChannelDescriptionsTask(
  159. base::weak_ptr<GroupCall> call,
  160. const std::vector<std::uint32_t> &ssrcs,
  161. Fn<void(std::vector<tgcalls::MediaChannelDescription>&&)> done);
  162. [[nodiscard]] base::flat_set<uint32> ssrcs() const;
  163. [[nodiscard]] bool finishWithAdding(
  164. uint32 ssrc,
  165. std::optional<tgcalls::MediaChannelDescription> description,
  166. bool screen = false);
  167. void cancel() override;
  168. private:
  169. const base::weak_ptr<GroupCall> _call;
  170. base::flat_set<uint32> _ssrcs;
  171. base::flat_set<uint32> _cameraAdded;
  172. base::flat_set<uint32> _screenAdded;
  173. std::vector<tgcalls::MediaChannelDescription> _result;
  174. Fn<void(std::vector<tgcalls::MediaChannelDescription>&&)> _done;
  175. QMutex _mutex;
  176. };
  177. class GroupCall::RequestCurrentTimeTask final
  178. : public tgcalls::BroadcastPartTask {
  179. public:
  180. RequestCurrentTimeTask(
  181. base::weak_ptr<GroupCall> call,
  182. Fn<void(int64)> done);
  183. void done(int64 value);
  184. void cancel() override;
  185. private:
  186. const base::weak_ptr<GroupCall> _call;
  187. Fn<void(int64)> _done;
  188. QMutex _mutex;
  189. };
  190. struct GroupCall::SinkPointer {
  191. std::weak_ptr<Webrtc::SinkInterface> data;
  192. };
  193. struct GroupCall::VideoTrack {
  194. VideoTrack(bool paused, bool requireARGB32, not_null<PeerData*> peer);
  195. Webrtc::VideoTrack track;
  196. rpl::variable<QSize> trackSize;
  197. not_null<PeerData*> peer;
  198. rpl::lifetime lifetime;
  199. Group::VideoQuality quality = Group::VideoQuality();
  200. bool shown = false;
  201. };
  202. GroupCall::VideoTrack::VideoTrack(
  203. bool paused,
  204. bool requireARGB32,
  205. not_null<PeerData*> peer)
  206. : track((paused
  207. ? Webrtc::VideoState::Paused
  208. : Webrtc::VideoState::Active),
  209. requireARGB32)
  210. , peer(peer) {
  211. }
  212. [[nodiscard]] bool IsGroupCallAdmin(
  213. not_null<PeerData*> peer,
  214. not_null<PeerData*> participantPeer) {
  215. const auto user = participantPeer->asUser();
  216. if (!user) {
  217. return (peer == participantPeer);
  218. }
  219. if (const auto chat = peer->asChat()) {
  220. return chat->admins.contains(user)
  221. || (chat->creator == peerToUser(user->id));
  222. } else if (const auto group = peer->asChannel()) {
  223. if (const auto mgInfo = group->mgInfo.get()) {
  224. if (mgInfo->creator == user) {
  225. return true;
  226. }
  227. const auto i = mgInfo->lastAdmins.find(user);
  228. if (i == mgInfo->lastAdmins.end()) {
  229. return false;
  230. }
  231. return (i->second.rights.flags & ChatAdminRight::ManageCall);
  232. }
  233. }
  234. return false;
  235. }
  236. bool VideoEndpoint::rtmp() const noexcept {
  237. return (id == Data::RtmpEndpointId());
  238. }
  239. struct VideoParams {
  240. std::string endpointId;
  241. std::vector<tgcalls::MediaSsrcGroup> ssrcGroups;
  242. uint32 additionalSsrc = 0;
  243. bool paused = false;
  244. [[nodiscard]] bool empty() const {
  245. return !additionalSsrc && (endpointId.empty() || ssrcGroups.empty());
  246. }
  247. [[nodiscard]] explicit operator bool() const {
  248. return !empty();
  249. }
  250. };
  251. struct ParticipantVideoParams {
  252. VideoParams camera;
  253. VideoParams screen;
  254. };
  255. [[nodiscard]] bool VideoParamsAreEqual(
  256. const VideoParams &was,
  257. const tl::conditional<MTPGroupCallParticipantVideo> &now) {
  258. if (!now) {
  259. return !was;
  260. }
  261. return now->match([&](const MTPDgroupCallParticipantVideo &data) {
  262. if (data.is_paused() != was.paused
  263. || data.vaudio_source().value_or_empty() != was.additionalSsrc) {
  264. return false;
  265. }
  266. if (gsl::make_span(data.vendpoint().v)
  267. != gsl::make_span(was.endpointId)) {
  268. return false;
  269. }
  270. const auto &list = data.vsource_groups().v;
  271. if (list.size() != was.ssrcGroups.size()) {
  272. return false;
  273. }
  274. auto index = 0;
  275. for (const auto &group : list) {
  276. const auto equal = group.match([&](
  277. const MTPDgroupCallParticipantVideoSourceGroup &data) {
  278. const auto &group = was.ssrcGroups[index++];
  279. if (gsl::make_span(data.vsemantics().v)
  280. != gsl::make_span(group.semantics)) {
  281. return false;
  282. }
  283. const auto list = data.vsources().v;
  284. if (list.size() != group.ssrcs.size()) {
  285. return false;
  286. }
  287. auto i = 0;
  288. for (const auto &ssrc : list) {
  289. if (ssrc.v != group.ssrcs[i++]) {
  290. return false;
  291. }
  292. }
  293. return true;
  294. });
  295. if (!equal) {
  296. return false;
  297. }
  298. }
  299. return true;
  300. });
  301. }
  302. [[nodiscard]] VideoParams ParseVideoParams(
  303. const tl::conditional<MTPGroupCallParticipantVideo> &params) {
  304. if (!params) {
  305. return VideoParams();
  306. }
  307. auto result = VideoParams();
  308. params->match([&](const MTPDgroupCallParticipantVideo &data) {
  309. result.paused = data.is_paused();
  310. result.endpointId = data.vendpoint().v.toStdString();
  311. result.additionalSsrc = data.vaudio_source().value_or_empty();
  312. const auto &list = data.vsource_groups().v;
  313. result.ssrcGroups.reserve(list.size());
  314. for (const auto &group : list) {
  315. group.match([&](
  316. const MTPDgroupCallParticipantVideoSourceGroup &data) {
  317. const auto &list = data.vsources().v;
  318. auto ssrcs = std::vector<uint32_t>();
  319. ssrcs.reserve(list.size());
  320. for (const auto &ssrc : list) {
  321. ssrcs.push_back(ssrc.v);
  322. }
  323. result.ssrcGroups.push_back({
  324. .semantics = data.vsemantics().v.toStdString(),
  325. .ssrcs = std::move(ssrcs),
  326. });
  327. });
  328. }
  329. });
  330. return result;
  331. }
  332. const std::string &GetCameraEndpoint(
  333. const std::shared_ptr<ParticipantVideoParams> &params) {
  334. return params ? params->camera.endpointId : EmptyString();
  335. }
  336. const std::string &GetScreenEndpoint(
  337. const std::shared_ptr<ParticipantVideoParams> &params) {
  338. return params ? params->screen.endpointId : EmptyString();
  339. }
  340. bool IsCameraPaused(const std::shared_ptr<ParticipantVideoParams> &params) {
  341. return params && params->camera.paused;
  342. }
  343. bool IsScreenPaused(const std::shared_ptr<ParticipantVideoParams> &params) {
  344. return params && params->screen.paused;
  345. }
  346. uint32 GetAdditionalAudioSsrc(
  347. const std::shared_ptr<ParticipantVideoParams> &params) {
  348. return params ? params->screen.additionalSsrc : 0;
  349. }
  350. std::shared_ptr<ParticipantVideoParams> ParseVideoParams(
  351. const tl::conditional<MTPGroupCallParticipantVideo> &camera,
  352. const tl::conditional<MTPGroupCallParticipantVideo> &screen,
  353. const std::shared_ptr<ParticipantVideoParams> &existing) {
  354. using namespace tgcalls;
  355. if (!camera && !screen) {
  356. return nullptr;
  357. }
  358. if (existing
  359. && VideoParamsAreEqual(existing->camera, camera)
  360. && VideoParamsAreEqual(existing->screen, screen)) {
  361. return existing;
  362. }
  363. // We don't reuse existing pointer, that way we can compare pointers
  364. // to see if anything was changed in video params.
  365. const auto data = /*existing
  366. ? existing
  367. : */std::make_shared<ParticipantVideoParams>();
  368. data->camera = ParseVideoParams(camera);
  369. data->screen = ParseVideoParams(screen);
  370. return data;
  371. }
  372. GroupCall::LoadPartTask::LoadPartTask(
  373. base::weak_ptr<GroupCall> call,
  374. int64 time,
  375. int64 period,
  376. Fn<void(tgcalls::BroadcastPart&&)> done)
  377. : LoadPartTask(std::move(call), time, period, 0, {}, std::move(done)) {
  378. }
  379. GroupCall::LoadPartTask::LoadPartTask(
  380. base::weak_ptr<GroupCall> call,
  381. int64 time,
  382. int64 period,
  383. int32 videoChannel,
  384. tgcalls::VideoChannelDescription::Quality videoQuality,
  385. Fn<void(tgcalls::BroadcastPart&&)> done)
  386. : _call(std::move(call))
  387. , _time(time ? time : (base::unixtime::now() * int64(1000)))
  388. , _scale([&] {
  389. switch (period) {
  390. case 1000: return 0;
  391. case 500: return 1;
  392. case 250: return 2;
  393. case 125: return 3;
  394. }
  395. Unexpected("Period in LoadPartTask.");
  396. }())
  397. , _videoChannel(videoChannel)
  398. , _videoQuality(videoQuality)
  399. , _done(std::move(done)) {
  400. }
  401. void GroupCall::LoadPartTask::done(tgcalls::BroadcastPart &&part) {
  402. QMutexLocker lock(&_mutex);
  403. if (_done) {
  404. base::take(_done)(std::move(part));
  405. }
  406. }
  407. void GroupCall::LoadPartTask::cancel() {
  408. QMutexLocker lock(&_mutex);
  409. if (!_done) {
  410. return;
  411. }
  412. _done = nullptr;
  413. lock.unlock();
  414. if (_call) {
  415. const auto that = this;
  416. crl::on_main(_call, [weak = _call, that] {
  417. if (const auto strong = weak.get()) {
  418. strong->broadcastPartCancel(that);
  419. }
  420. });
  421. }
  422. }
  423. GroupCall::MediaChannelDescriptionsTask::MediaChannelDescriptionsTask(
  424. base::weak_ptr<GroupCall> call,
  425. const std::vector<std::uint32_t> &ssrcs,
  426. Fn<void(std::vector<tgcalls::MediaChannelDescription>&&)> done)
  427. : _call(std::move(call))
  428. , _ssrcs(ssrcs.begin(), ssrcs.end())
  429. , _done(std::move(done)) {
  430. }
  431. auto GroupCall::MediaChannelDescriptionsTask::ssrcs() const
  432. -> base::flat_set<uint32> {
  433. return _ssrcs;
  434. }
  435. bool GroupCall::MediaChannelDescriptionsTask::finishWithAdding(
  436. uint32 ssrc,
  437. std::optional<tgcalls::MediaChannelDescription> description,
  438. bool screen) {
  439. Expects(_ssrcs.contains(ssrc));
  440. using Type = tgcalls::MediaChannelDescription::Type;
  441. _ssrcs.remove(ssrc);
  442. if (!description) {
  443. } else if (description->type == Type::Audio
  444. || (!screen && _cameraAdded.emplace(description->audioSsrc).second)
  445. || (screen && _screenAdded.emplace(description->audioSsrc).second)) {
  446. _result.push_back(std::move(*description));
  447. }
  448. if (!_ssrcs.empty()) {
  449. return false;
  450. }
  451. QMutexLocker lock(&_mutex);
  452. if (_done) {
  453. base::take(_done)(std::move(_result));
  454. }
  455. return true;
  456. }
  457. void GroupCall::MediaChannelDescriptionsTask::cancel() {
  458. QMutexLocker lock(&_mutex);
  459. if (!_done) {
  460. return;
  461. }
  462. _done = nullptr;
  463. lock.unlock();
  464. if (_call) {
  465. const auto that = this;
  466. crl::on_main(_call, [weak = _call, that] {
  467. if (const auto strong = weak.get()) {
  468. strong->mediaChannelDescriptionsCancel(that);
  469. }
  470. });
  471. }
  472. }
  473. GroupCall::RequestCurrentTimeTask::RequestCurrentTimeTask(
  474. base::weak_ptr<GroupCall> call,
  475. Fn<void(int64)> done)
  476. : _call(call)
  477. , _done(std::move(done)) {
  478. }
  479. void GroupCall::RequestCurrentTimeTask::done(int64 value) {
  480. QMutexLocker lock(&_mutex);
  481. if (_done) {
  482. base::take(_done)(value);
  483. }
  484. }
  485. void GroupCall::RequestCurrentTimeTask::cancel() {
  486. QMutexLocker lock(&_mutex);
  487. _done = nullptr;
  488. }
  489. not_null<PeerData*> GroupCall::TrackPeer(
  490. const std::unique_ptr<VideoTrack> &track) {
  491. return track->peer;
  492. }
  493. not_null<Webrtc::VideoTrack*> GroupCall::TrackPointer(
  494. const std::unique_ptr<VideoTrack> &track) {
  495. return &track->track;
  496. }
  497. rpl::producer<QSize> GroupCall::TrackSizeValue(
  498. const std::unique_ptr<VideoTrack> &track) {
  499. return track->trackSize.value();
  500. }
  501. GroupCall::GroupCall(
  502. not_null<Delegate*> delegate,
  503. Group::JoinInfo info,
  504. const MTPInputGroupCall &inputCall)
  505. : _delegate(delegate)
  506. , _peer(info.peer)
  507. , _history(_peer->owner().history(_peer))
  508. , _api(&_peer->session().mtp())
  509. , _joinAs(info.joinAs)
  510. , _possibleJoinAs(std::move(info.possibleJoinAs))
  511. , _joinHash(info.joinHash)
  512. , _rtmpUrl(info.rtmpInfo.url)
  513. , _rtmpKey(info.rtmpInfo.key)
  514. , _canManage(Data::CanManageGroupCallValue(_peer))
  515. , _id(inputCall.c_inputGroupCall().vid().v)
  516. , _scheduleDate(info.scheduleDate)
  517. , _lastSpokeCheckTimer([=] { checkLastSpoke(); })
  518. , _checkJoinedTimer([=] { checkJoined(); })
  519. , _playbackDeviceId(
  520. &Core::App().mediaDevices(),
  521. Webrtc::DeviceType::Playback,
  522. Webrtc::DeviceIdValueWithFallback(
  523. Core::App().settings().callPlaybackDeviceIdValue(),
  524. Core::App().settings().playbackDeviceIdValue()))
  525. , _captureDeviceId(
  526. &Core::App().mediaDevices(),
  527. Webrtc::DeviceType::Capture,
  528. Webrtc::DeviceIdValueWithFallback(
  529. Core::App().settings().callCaptureDeviceIdValue(),
  530. Core::App().settings().captureDeviceIdValue()))
  531. , _cameraDeviceId(
  532. &Core::App().mediaDevices(),
  533. Webrtc::DeviceType::Camera,
  534. Webrtc::DeviceIdOrDefault(Core::App().settings().cameraDeviceIdValue()))
  535. , _pushToTalkCancelTimer([=] { pushToTalkCancel(); })
  536. , _connectingSoundTimer([=] { playConnectingSoundOnce(); })
  537. , _listenersHidden(info.rtmp)
  538. , _rtmp(info.rtmp)
  539. , _rtmpVolume(Group::kDefaultVolume) {
  540. _muted.value(
  541. ) | rpl::combine_previous(
  542. ) | rpl::start_with_next([=](MuteState previous, MuteState state) {
  543. if (_instance) {
  544. updateInstanceMuteState();
  545. }
  546. if (_joinState.ssrc
  547. && (!_initialMuteStateSent || state == MuteState::Active)) {
  548. _initialMuteStateSent = true;
  549. maybeSendMutedUpdate(previous);
  550. }
  551. }, _lifetime);
  552. _instanceState.value(
  553. ) | rpl::filter([=] {
  554. return _hadJoinedState;
  555. }) | rpl::start_with_next([=](InstanceState state) {
  556. if (state == InstanceState::Disconnected) {
  557. playConnectingSound();
  558. } else {
  559. stopConnectingSound();
  560. }
  561. }, _lifetime);
  562. checkGlobalShortcutAvailability();
  563. if (const auto real = lookupReal()) {
  564. subscribeToReal(real);
  565. if (!canManage() && real->joinMuted()) {
  566. _muted = MuteState::ForceMuted;
  567. }
  568. } else {
  569. _peer->session().changes().peerFlagsValue(
  570. _peer,
  571. Data::PeerUpdate::Flag::GroupCall
  572. ) | rpl::map([=] {
  573. return lookupReal();
  574. }) | rpl::filter([](Data::GroupCall *real) {
  575. return real != nullptr;
  576. }) | rpl::map([](Data::GroupCall *real) {
  577. return not_null{ real };
  578. }) | rpl::take(
  579. 1
  580. ) | rpl::start_with_next([=](not_null<Data::GroupCall*> real) {
  581. subscribeToReal(real);
  582. _realChanges.fire_copy(real);
  583. }, _lifetime);
  584. }
  585. setupMediaDevices();
  586. setupOutgoingVideo();
  587. if (_id) {
  588. join(inputCall);
  589. } else {
  590. start(info.scheduleDate, info.rtmp);
  591. }
  592. if (_scheduleDate) {
  593. saveDefaultJoinAs(joinAs());
  594. }
  595. }
  596. GroupCall::~GroupCall() {
  597. destroyScreencast();
  598. destroyController();
  599. if (!_rtmp) {
  600. Core::App().mediaDevices().setCaptureMuteTracker(this, false);
  601. }
  602. }
  603. bool GroupCall::isSharingScreen() const {
  604. return _isSharingScreen.current();
  605. }
  606. rpl::producer<bool> GroupCall::isSharingScreenValue() const {
  607. return _isSharingScreen.value();
  608. }
  609. bool GroupCall::isScreenPaused() const {
  610. return (_screenState.current() == Webrtc::VideoState::Paused);
  611. }
  612. const std::string &GroupCall::screenSharingEndpoint() const {
  613. return isSharingScreen() ? _screenEndpoint : EmptyString();
  614. }
  615. bool GroupCall::isSharingCamera() const {
  616. return _isSharingCamera.current();
  617. }
  618. rpl::producer<bool> GroupCall::isSharingCameraValue() const {
  619. return _isSharingCamera.value();
  620. }
  621. bool GroupCall::isCameraPaused() const {
  622. return (_cameraState.current() == Webrtc::VideoState::Paused);
  623. }
  624. const std::string &GroupCall::cameraSharingEndpoint() const {
  625. return isSharingCamera() ? _cameraEndpoint : EmptyString();
  626. }
  627. QString GroupCall::screenSharingDeviceId() const {
  628. return isSharingScreen() ? _screenDeviceId : QString();
  629. }
  630. bool GroupCall::screenSharingWithAudio() const {
  631. return isSharingScreen() && _screenWithAudio;
  632. }
  633. bool GroupCall::mutedByAdmin() const {
  634. const auto mute = muted();
  635. return _rtmp
  636. || (mute == MuteState::ForceMuted)
  637. || (mute == MuteState::RaisedHand);
  638. }
  639. bool GroupCall::canManage() const {
  640. return _canManage.current();
  641. }
  642. rpl::producer<bool> GroupCall::canManageValue() const {
  643. return _canManage.value();
  644. }
  645. void GroupCall::toggleVideo(bool active) {
  646. if (!_instance || !_id) {
  647. return;
  648. }
  649. _cameraState = active
  650. ? Webrtc::VideoState::Active
  651. : Webrtc::VideoState::Inactive;
  652. }
  653. void GroupCall::toggleScreenSharing(
  654. std::optional<QString> uniqueId,
  655. bool withAudio) {
  656. if (!_instance || !_id) {
  657. return;
  658. } else if (!uniqueId) {
  659. _screenState = Webrtc::VideoState::Inactive;
  660. return;
  661. }
  662. const auto changed = (_screenDeviceId != *uniqueId);
  663. const auto wasSharing = isSharingScreen();
  664. _screenDeviceId = *uniqueId;
  665. _screenWithAudio = withAudio;
  666. _screenState = Webrtc::VideoState::Active;
  667. if (changed && wasSharing && isSharingScreen()) {
  668. _screenCapture->switchToDevice(uniqueId->toStdString(), true);
  669. }
  670. if (_screenInstance) {
  671. _screenInstance->setIsMuted(!withAudio);
  672. }
  673. }
  674. bool GroupCall::hasVideoWithFrames() const {
  675. return !_shownVideoTracks.empty();
  676. }
  677. rpl::producer<bool> GroupCall::hasVideoWithFramesValue() const {
  678. return _videoStreamShownUpdates.events_starting_with(
  679. VideoStateToggle()
  680. ) | rpl::map([=] {
  681. return hasVideoWithFrames();
  682. }) | rpl::distinct_until_changed();
  683. }
  684. void GroupCall::setScheduledDate(TimeId date) {
  685. const auto was = _scheduleDate;
  686. _scheduleDate = date;
  687. if (was && !date) {
  688. join(inputCall());
  689. }
  690. }
  691. void GroupCall::subscribeToReal(not_null<Data::GroupCall*> real) {
  692. _listenersHidden = real->listenersHidden();
  693. real->scheduleDateValue(
  694. ) | rpl::start_with_next([=](TimeId date) {
  695. setScheduledDate(date);
  696. }, _lifetime);
  697. // Postpone creating video tracks, so that we know if Panel
  698. // supports OpenGL and we don't need ARGB32 frames at all.
  699. Ui::PostponeCall(this, [=] {
  700. if (const auto real = lookupReal()) {
  701. real->participantsReloaded(
  702. ) | rpl::start_with_next([=] {
  703. fillActiveVideoEndpoints();
  704. }, _lifetime);
  705. fillActiveVideoEndpoints();
  706. }
  707. });
  708. using Update = Data::GroupCall::ParticipantUpdate;
  709. real->participantUpdated(
  710. ) | rpl::start_with_next([=](const Update &data) {
  711. const auto regularEndpoint = [&](const std::string &endpoint)
  712. -> const std::string & {
  713. return (endpoint.empty()
  714. || endpoint == _cameraEndpoint
  715. || endpoint == _screenEndpoint)
  716. ? EmptyString()
  717. : endpoint;
  718. };
  719. const auto peer = data.was ? data.was->peer : data.now->peer;
  720. if (peer == joinAs()) {
  721. const auto working = data.now && data.now->videoJoined;
  722. if (videoIsWorking() != working) {
  723. fillActiveVideoEndpoints();
  724. }
  725. return;
  726. }
  727. const auto &wasCameraEndpoint = data.was
  728. ? regularEndpoint(GetCameraEndpoint(data.was->videoParams))
  729. : EmptyString();
  730. const auto &nowCameraEndpoint = data.now
  731. ? regularEndpoint(GetCameraEndpoint(data.now->videoParams))
  732. : EmptyString();
  733. const auto wasCameraPaused = !wasCameraEndpoint.empty()
  734. && IsCameraPaused(data.was->videoParams);
  735. const auto nowCameraPaused = !nowCameraEndpoint.empty()
  736. && IsCameraPaused(data.now->videoParams);
  737. if (wasCameraEndpoint != nowCameraEndpoint) {
  738. markEndpointActive({
  739. VideoEndpointType::Camera,
  740. peer,
  741. nowCameraEndpoint,
  742. }, true, nowCameraPaused);
  743. markEndpointActive({
  744. VideoEndpointType::Camera,
  745. peer,
  746. wasCameraEndpoint,
  747. }, false, false);
  748. } else if (wasCameraPaused != nowCameraPaused) {
  749. markTrackPaused({
  750. VideoEndpointType::Camera,
  751. peer,
  752. nowCameraEndpoint,
  753. }, nowCameraPaused);
  754. }
  755. const auto &wasScreenEndpoint = data.was
  756. ? regularEndpoint(data.was->screenEndpoint())
  757. : EmptyString();
  758. const auto &nowScreenEndpoint = data.now
  759. ? regularEndpoint(data.now->screenEndpoint())
  760. : EmptyString();
  761. const auto wasScreenPaused = !wasScreenEndpoint.empty()
  762. && IsScreenPaused(data.was->videoParams);
  763. const auto nowScreenPaused = !nowScreenEndpoint.empty()
  764. && IsScreenPaused(data.now->videoParams);
  765. if (wasScreenEndpoint != nowScreenEndpoint) {
  766. markEndpointActive({
  767. VideoEndpointType::Screen,
  768. peer,
  769. nowScreenEndpoint,
  770. }, true, nowScreenPaused);
  771. markEndpointActive({
  772. VideoEndpointType::Screen,
  773. peer,
  774. wasScreenEndpoint,
  775. }, false, false);
  776. } else if (wasScreenPaused != nowScreenPaused) {
  777. markTrackPaused({
  778. VideoEndpointType::Screen,
  779. peer,
  780. wasScreenEndpoint,
  781. }, nowScreenPaused);
  782. }
  783. }, _lifetime);
  784. real->participantsResolved(
  785. ) | rpl::start_with_next([=](
  786. not_null<const base::flat_map<
  787. uint32,
  788. Data::LastSpokeTimes>*> ssrcs) {
  789. checkMediaChannelDescriptions([&](uint32 ssrc) {
  790. return ssrcs->contains(ssrc);
  791. });
  792. }, _lifetime);
  793. real->participantSpeaking(
  794. ) | rpl::filter([=] {
  795. return _videoEndpointLarge.current();
  796. }) | rpl::start_with_next([=](not_null<Data::GroupCallParticipant*> p) {
  797. const auto now = crl::now();
  798. if (_videoEndpointLarge.current().peer == p->peer) {
  799. _videoLargeTillTime = std::max(
  800. _videoLargeTillTime,
  801. now + kFixSpeakingLargeVideoDuration);
  802. return;
  803. } else if (videoEndpointPinned() || _videoLargeTillTime > now) {
  804. return;
  805. }
  806. using Type = VideoEndpointType;
  807. const auto &params = p->videoParams;
  808. if (GetCameraEndpoint(params).empty()
  809. && GetScreenEndpoint(params).empty()) {
  810. return;
  811. }
  812. const auto tryEndpoint = [&](Type type, const std::string &id) {
  813. if (id.empty()) {
  814. return false;
  815. }
  816. const auto endpoint = VideoEndpoint{ type, p->peer, id };
  817. if (!shownVideoTracks().contains(endpoint)) {
  818. return false;
  819. }
  820. setVideoEndpointLarge(endpoint);
  821. return true;
  822. };
  823. if (tryEndpoint(Type::Screen, GetScreenEndpoint(params))
  824. || tryEndpoint(Type::Camera, GetCameraEndpoint(params))) {
  825. _videoLargeTillTime = now + kFixSpeakingLargeVideoDuration;
  826. }
  827. }, _lifetime);
  828. }
  829. void GroupCall::checkGlobalShortcutAvailability() {
  830. auto &settings = Core::App().settings();
  831. if (!settings.groupCallPushToTalk()) {
  832. return;
  833. } else if (!base::GlobalShortcutsAllowed()) {
  834. settings.setGroupCallPushToTalk(false);
  835. Core::App().saveSettingsDelayed();
  836. }
  837. }
  838. void GroupCall::setState(State state) {
  839. const auto current = _state.current();
  840. if (current == State::Failed) {
  841. return;
  842. } else if (current == State::Ended && state != State::Failed) {
  843. return;
  844. } else if (current == State::FailedHangingUp && state != State::Failed) {
  845. return;
  846. } else if (current == State::HangingUp
  847. && state != State::Ended
  848. && state != State::Failed) {
  849. return;
  850. }
  851. if (current == state) {
  852. return;
  853. }
  854. _state = state;
  855. if (state == State::Joined) {
  856. stopConnectingSound();
  857. if (const auto call = _peer->groupCall(); call && call->id() == _id) {
  858. call->setInCall();
  859. }
  860. }
  861. if (false
  862. || state == State::Ended
  863. || state == State::Failed) {
  864. // Destroy controller before destroying Call Panel,
  865. // so that the panel hide animation is smooth.
  866. destroyScreencast();
  867. destroyController();
  868. }
  869. switch (state) {
  870. case State::HangingUp:
  871. case State::FailedHangingUp:
  872. stopConnectingSound();
  873. _delegate->groupCallPlaySound(Delegate::GroupCallSound::Ended);
  874. break;
  875. case State::Ended:
  876. stopConnectingSound();
  877. _delegate->groupCallFinished(this);
  878. break;
  879. case State::Failed:
  880. stopConnectingSound();
  881. _delegate->groupCallFailed(this);
  882. break;
  883. case State::Connecting:
  884. if (!_checkJoinedTimer.isActive()) {
  885. _checkJoinedTimer.callOnce(kCheckJoinedTimeout);
  886. }
  887. break;
  888. }
  889. }
  890. void GroupCall::playConnectingSound() {
  891. const auto state = _state.current();
  892. if (_connectingSoundTimer.isActive()
  893. || state == State::HangingUp
  894. || state == State::FailedHangingUp
  895. || state == State::Ended
  896. || state == State::Failed) {
  897. return;
  898. }
  899. playConnectingSoundOnce();
  900. _connectingSoundTimer.callEach(kPlayConnectingEach);
  901. }
  902. void GroupCall::stopConnectingSound() {
  903. _connectingSoundTimer.cancel();
  904. }
  905. void GroupCall::playConnectingSoundOnce() {
  906. _delegate->groupCallPlaySound(Delegate::GroupCallSound::Connecting);
  907. }
  908. bool GroupCall::showChooseJoinAs() const {
  909. return !_rtmp
  910. && ((_possibleJoinAs.size() > 1)
  911. || (_possibleJoinAs.size() == 1
  912. && !_possibleJoinAs.front()->isSelf()));
  913. }
  914. bool GroupCall::scheduleStartSubscribed() const {
  915. if (const auto real = lookupReal()) {
  916. return real->scheduleStartSubscribed();
  917. }
  918. return false;
  919. }
  920. bool GroupCall::rtmp() const {
  921. return _rtmp;
  922. }
  923. bool GroupCall::listenersHidden() const {
  924. return _listenersHidden;
  925. }
  926. bool GroupCall::emptyRtmp() const {
  927. return _emptyRtmp.current();
  928. }
  929. rpl::producer<bool> GroupCall::emptyRtmpValue() const {
  930. return _emptyRtmp.value();
  931. }
  932. int GroupCall::rtmpVolume() const {
  933. return _rtmpVolume;
  934. }
  935. Calls::Group::RtmpInfo GroupCall::rtmpInfo() const {
  936. return { _rtmpUrl, _rtmpKey };
  937. }
  938. void GroupCall::setRtmpInfo(const Calls::Group::RtmpInfo &value) {
  939. _rtmpUrl = value.url;
  940. _rtmpKey = value.key;
  941. }
  942. Data::GroupCall *GroupCall::lookupReal() const {
  943. const auto real = _peer->groupCall();
  944. return (real && real->id() == _id) ? real : nullptr;
  945. }
  946. rpl::producer<not_null<Data::GroupCall*>> GroupCall::real() const {
  947. if (const auto real = lookupReal()) {
  948. return rpl::single(not_null{ real });
  949. }
  950. return _realChanges.events();
  951. }
  952. void GroupCall::start(TimeId scheduleDate, bool rtmp) {
  953. using Flag = MTPphone_CreateGroupCall::Flag;
  954. _createRequestId = _api.request(MTPphone_CreateGroupCall(
  955. MTP_flags((scheduleDate ? Flag::f_schedule_date : Flag(0))
  956. | (rtmp ? Flag::f_rtmp_stream : Flag(0))),
  957. _peer->input,
  958. MTP_int(base::RandomValue<int32>()),
  959. MTPstring(), // title
  960. MTP_int(scheduleDate)
  961. )).done([=](const MTPUpdates &result) {
  962. _reloadedStaleCall = true;
  963. _acceptFields = true;
  964. _peer->session().api().applyUpdates(result);
  965. _acceptFields = false;
  966. }).fail([=](const MTP::Error &error) {
  967. LOG(("Call Error: Could not create, error: %1"
  968. ).arg(error.type()));
  969. hangup();
  970. }).send();
  971. }
  972. void GroupCall::join(const MTPInputGroupCall &inputCall) {
  973. inputCall.match([&](const MTPDinputGroupCall &data) {
  974. _id = data.vid().v;
  975. _accessHash = data.vaccess_hash().v;
  976. });
  977. setState(_scheduleDate ? State::Waiting : State::Joining);
  978. if (_scheduleDate) {
  979. return;
  980. }
  981. rejoin();
  982. using Update = Data::GroupCall::ParticipantUpdate;
  983. const auto real = lookupReal();
  984. Assert(real != nullptr);
  985. real->participantUpdated(
  986. ) | rpl::filter([=](const Update &update) {
  987. return (_instance != nullptr);
  988. }) | rpl::start_with_next([=](const Update &update) {
  989. if (!update.now) {
  990. _instance->removeSsrcs({
  991. update.was->ssrc,
  992. GetAdditionalAudioSsrc(update.was->videoParams),
  993. });
  994. } else if (!_rtmp) {
  995. updateInstanceVolume(update.was, *update.now);
  996. }
  997. }, _lifetime);
  998. _peer->session().updates().addActiveChat(
  999. _peerStream.events_starting_with_copy(_peer));
  1000. SubscribeToMigration(_peer, _lifetime, [=](not_null<ChannelData*> group) {
  1001. _peer = group;
  1002. _canManage = Data::CanManageGroupCallValue(_peer);
  1003. _peerStream.fire_copy(group);
  1004. });
  1005. }
  1006. void GroupCall::setScreenEndpoint(std::string endpoint) {
  1007. if (_screenEndpoint == endpoint) {
  1008. return;
  1009. }
  1010. if (!_screenEndpoint.empty()) {
  1011. markEndpointActive({
  1012. VideoEndpointType::Screen,
  1013. joinAs(),
  1014. _screenEndpoint
  1015. }, false, false);
  1016. }
  1017. _screenEndpoint = std::move(endpoint);
  1018. if (_screenEndpoint.empty()) {
  1019. return;
  1020. }
  1021. if (isSharingScreen()) {
  1022. markEndpointActive({
  1023. VideoEndpointType::Screen,
  1024. joinAs(),
  1025. _screenEndpoint
  1026. }, true, isScreenPaused());
  1027. }
  1028. }
  1029. void GroupCall::setCameraEndpoint(std::string endpoint) {
  1030. if (_cameraEndpoint == endpoint) {
  1031. return;
  1032. }
  1033. if (!_cameraEndpoint.empty()) {
  1034. markEndpointActive({
  1035. VideoEndpointType::Camera,
  1036. joinAs(),
  1037. _cameraEndpoint
  1038. }, false, false);
  1039. }
  1040. _cameraEndpoint = std::move(endpoint);
  1041. if (_cameraEndpoint.empty()) {
  1042. return;
  1043. }
  1044. if (isSharingCamera()) {
  1045. markEndpointActive({
  1046. VideoEndpointType::Camera,
  1047. joinAs(),
  1048. _cameraEndpoint
  1049. }, true, isCameraPaused());
  1050. }
  1051. }
  1052. void GroupCall::addVideoOutput(
  1053. const std::string &endpoint,
  1054. SinkPointer sink) {
  1055. if (_cameraEndpoint == endpoint) {
  1056. if (auto strong = sink.data.lock()) {
  1057. _cameraCapture->setOutput(std::move(strong));
  1058. }
  1059. } else if (_screenEndpoint == endpoint) {
  1060. if (auto strong = sink.data.lock()) {
  1061. _screenCapture->setOutput(std::move(strong));
  1062. }
  1063. } else if (_instance) {
  1064. _instance->addIncomingVideoOutput(endpoint, std::move(sink.data));
  1065. } else {
  1066. _pendingVideoOutputs.emplace(endpoint, std::move(sink));
  1067. }
  1068. }
  1069. void GroupCall::markEndpointActive(
  1070. VideoEndpoint endpoint,
  1071. bool active,
  1072. bool paused) {
  1073. if (!endpoint) {
  1074. return;
  1075. }
  1076. const auto i = _activeVideoTracks.find(endpoint);
  1077. const auto changed = active
  1078. ? (i == end(_activeVideoTracks))
  1079. : (i != end(_activeVideoTracks));
  1080. if (!changed) {
  1081. if (active) {
  1082. markTrackPaused(endpoint, paused);
  1083. }
  1084. return;
  1085. }
  1086. auto shown = false;
  1087. if (active) {
  1088. const auto i = _activeVideoTracks.emplace(
  1089. endpoint,
  1090. std::make_unique<VideoTrack>(
  1091. paused,
  1092. _requireARGB32,
  1093. endpoint.peer)).first;
  1094. const auto track = &i->second->track;
  1095. track->renderNextFrame(
  1096. ) | rpl::start_with_next([=] {
  1097. const auto activeTrack = _activeVideoTracks[endpoint].get();
  1098. const auto size = track->frameSize();
  1099. if (size.isEmpty()) {
  1100. track->markFrameShown();
  1101. } else if (!activeTrack->shown) {
  1102. activeTrack->shown = true;
  1103. markTrackShown(endpoint, true);
  1104. }
  1105. activeTrack->trackSize = size;
  1106. }, i->second->lifetime);
  1107. const auto size = track->frameSize();
  1108. i->second->trackSize = size;
  1109. if (!size.isEmpty() || paused) {
  1110. i->second->shown = true;
  1111. shown = true;
  1112. } else {
  1113. track->stateValue(
  1114. ) | rpl::filter([=](Webrtc::VideoState state) {
  1115. return (state == Webrtc::VideoState::Paused)
  1116. && !_activeVideoTracks[endpoint]->shown;
  1117. }) | rpl::start_with_next([=] {
  1118. _activeVideoTracks[endpoint]->shown = true;
  1119. markTrackShown(endpoint, true);
  1120. }, i->second->lifetime);
  1121. }
  1122. addVideoOutput(i->first.id, { track->sink() });
  1123. } else {
  1124. if (_videoEndpointLarge.current() == endpoint) {
  1125. setVideoEndpointLarge({});
  1126. }
  1127. markTrackShown(endpoint, false);
  1128. markTrackPaused(endpoint, false);
  1129. _activeVideoTracks.erase(i);
  1130. }
  1131. updateRequestedVideoChannelsDelayed();
  1132. _videoStreamActiveUpdates.fire({ endpoint, active });
  1133. if (active) {
  1134. markTrackShown(endpoint, shown);
  1135. markTrackPaused(endpoint, paused);
  1136. }
  1137. }
  1138. void GroupCall::markTrackShown(const VideoEndpoint &endpoint, bool shown) {
  1139. const auto changed = shown
  1140. ? _shownVideoTracks.emplace(endpoint).second
  1141. : _shownVideoTracks.remove(endpoint);
  1142. if (!changed) {
  1143. return;
  1144. }
  1145. _videoStreamShownUpdates.fire_copy({ endpoint, shown });
  1146. if (shown && endpoint.type == VideoEndpointType::Screen) {
  1147. crl::on_main(this, [=] {
  1148. if (_shownVideoTracks.contains(endpoint)) {
  1149. pinVideoEndpoint(endpoint);
  1150. }
  1151. });
  1152. }
  1153. }
  1154. void GroupCall::markTrackPaused(const VideoEndpoint &endpoint, bool paused) {
  1155. if (!endpoint) {
  1156. return;
  1157. }
  1158. const auto i = _activeVideoTracks.find(endpoint);
  1159. Assert(i != end(_activeVideoTracks));
  1160. i->second->track.setState(paused
  1161. ? Webrtc::VideoState::Paused
  1162. : Webrtc::VideoState::Active);
  1163. }
  1164. void GroupCall::rejoin() {
  1165. rejoin(joinAs());
  1166. }
  1167. void GroupCall::rejoinWithHash(const QString &hash) {
  1168. if (!hash.isEmpty() && mutedByAdmin()) {
  1169. _joinHash = hash;
  1170. rejoin();
  1171. }
  1172. }
  1173. void GroupCall::setJoinAs(not_null<PeerData*> as) {
  1174. _joinAs = as;
  1175. if (const auto chat = _peer->asChat()) {
  1176. chat->setGroupCallDefaultJoinAs(joinAs()->id);
  1177. } else if (const auto channel = _peer->asChannel()) {
  1178. channel->setGroupCallDefaultJoinAs(joinAs()->id);
  1179. }
  1180. }
  1181. void GroupCall::saveDefaultJoinAs(not_null<PeerData*> as) {
  1182. setJoinAs(as);
  1183. _api.request(MTPphone_SaveDefaultGroupCallJoinAs(
  1184. _peer->input,
  1185. joinAs()->input
  1186. )).send();
  1187. }
  1188. void GroupCall::rejoin(not_null<PeerData*> as) {
  1189. if (state() != State::Joining
  1190. && state() != State::Joined
  1191. && state() != State::Connecting) {
  1192. return;
  1193. } else if (_joinState.action != JoinAction::None) {
  1194. return;
  1195. }
  1196. if (joinAs() != as) {
  1197. toggleVideo(false);
  1198. toggleScreenSharing(std::nullopt);
  1199. }
  1200. _joinState.action = JoinAction::Joining;
  1201. _joinState.ssrc = 0;
  1202. _initialMuteStateSent = false;
  1203. setState(State::Joining);
  1204. if (!tryCreateController()) {
  1205. setInstanceMode(InstanceMode::None);
  1206. }
  1207. applyMeInCallLocally();
  1208. LOG(("Call Info: Requesting join payload."));
  1209. setJoinAs(as);
  1210. const auto weak = base::make_weak(&_instanceGuard);
  1211. _instance->emitJoinPayload([=](tgcalls::GroupJoinPayload payload) {
  1212. crl::on_main(weak, [=, payload = std::move(payload)] {
  1213. if (state() != State::Joining) {
  1214. _joinState.finish();
  1215. checkNextJoinAction();
  1216. return;
  1217. }
  1218. const auto ssrc = payload.audioSsrc;
  1219. LOG(("Call Info: Join payload received, joining with ssrc: %1."
  1220. ).arg(ssrc));
  1221. const auto json = QByteArray::fromStdString(payload.json);
  1222. const auto wasMuteState = muted();
  1223. const auto wasVideoStopped = !isSharingCamera();
  1224. using Flag = MTPphone_JoinGroupCall::Flag;
  1225. const auto flags = (wasMuteState != MuteState::Active
  1226. ? Flag::f_muted
  1227. : Flag(0))
  1228. | (_joinHash.isEmpty()
  1229. ? Flag(0)
  1230. : Flag::f_invite_hash)
  1231. | (wasVideoStopped
  1232. ? Flag::f_video_stopped
  1233. : Flag(0));
  1234. _api.request(MTPphone_JoinGroupCall(
  1235. MTP_flags(flags),
  1236. inputCall(),
  1237. joinAs()->input,
  1238. MTP_string(_joinHash),
  1239. MTPlong(), // key_fingerprint
  1240. MTP_dataJSON(MTP_bytes(json))
  1241. )).done([=](
  1242. const MTPUpdates &updates,
  1243. const MTP::Response &response) {
  1244. _serverTimeMs = TimestampInMsFromMsgId(response.outerMsgId);
  1245. _serverTimeMsGotAt = crl::now();
  1246. _joinState.finish(ssrc);
  1247. _mySsrcs.emplace(ssrc);
  1248. setState((_instanceState.current()
  1249. == InstanceState::Disconnected)
  1250. ? State::Connecting
  1251. : State::Joined);
  1252. applyMeInCallLocally();
  1253. maybeSendMutedUpdate(wasMuteState);
  1254. _peer->session().api().applyUpdates(updates);
  1255. applyQueuedSelfUpdates();
  1256. checkFirstTimeJoined();
  1257. _screenJoinState.nextActionPending = true;
  1258. checkNextJoinAction();
  1259. if (wasVideoStopped == isSharingCamera()) {
  1260. sendSelfUpdate(SendUpdateType::CameraStopped);
  1261. }
  1262. if (isCameraPaused()) {
  1263. sendSelfUpdate(SendUpdateType::CameraPaused);
  1264. }
  1265. sendPendingSelfUpdates();
  1266. if (!_reloadedStaleCall
  1267. && _state.current() != State::Joining) {
  1268. if (const auto real = lookupReal()) {
  1269. _reloadedStaleCall = true;
  1270. real->reloadIfStale();
  1271. }
  1272. }
  1273. }).fail([=](const MTP::Error &error) {
  1274. _joinState.finish();
  1275. const auto type = error.type();
  1276. LOG(("Call Error: Could not join, error: %1").arg(type));
  1277. if (type == u"GROUPCALL_SSRC_DUPLICATE_MUCH") {
  1278. rejoin();
  1279. return;
  1280. }
  1281. hangup();
  1282. Ui::Toast::Show((type == u"GROUPCALL_FORBIDDEN"_q)
  1283. ? tr::lng_group_not_accessible(tr::now)
  1284. : Lang::Hard::ServerError());
  1285. }).send();
  1286. });
  1287. });
  1288. }
  1289. void GroupCall::checkNextJoinAction() {
  1290. if (_joinState.action != JoinAction::None) {
  1291. return;
  1292. } else if (_joinState.nextActionPending) {
  1293. _joinState.nextActionPending = false;
  1294. const auto state = _state.current();
  1295. if (state != State::HangingUp && state != State::FailedHangingUp) {
  1296. rejoin();
  1297. } else {
  1298. leave();
  1299. }
  1300. } else if (!_joinState.ssrc) {
  1301. rejoin();
  1302. } else if (_screenJoinState.action != JoinAction::None
  1303. || !_screenJoinState.nextActionPending) {
  1304. return;
  1305. } else {
  1306. _screenJoinState.nextActionPending = false;
  1307. if (isSharingScreen()) {
  1308. rejoinPresentation();
  1309. } else {
  1310. leavePresentation();
  1311. }
  1312. }
  1313. }
  1314. void GroupCall::rejoinPresentation() {
  1315. if (!_joinState.ssrc
  1316. || _screenJoinState.action == JoinAction::Joining
  1317. || !isSharingScreen()) {
  1318. return;
  1319. } else if (_screenJoinState.action != JoinAction::None) {
  1320. _screenJoinState.nextActionPending = true;
  1321. return;
  1322. }
  1323. _screenJoinState.action = JoinAction::Joining;
  1324. _screenJoinState.ssrc = 0;
  1325. if (!tryCreateScreencast()) {
  1326. setScreenInstanceMode(InstanceMode::None);
  1327. }
  1328. LOG(("Call Info: Requesting join screen payload."));
  1329. const auto weak = base::make_weak(&_screenInstanceGuard);
  1330. _screenInstance->emitJoinPayload([=](tgcalls::GroupJoinPayload payload) {
  1331. crl::on_main(weak, [=, payload = std::move(payload)]{
  1332. if (!isSharingScreen() || !_joinState.ssrc) {
  1333. _screenJoinState.finish();
  1334. checkNextJoinAction();
  1335. return;
  1336. }
  1337. const auto withMainSsrc = _joinState.ssrc;
  1338. const auto ssrc = payload.audioSsrc;
  1339. LOG(("Call Info: Join screen payload received, ssrc: %1."
  1340. ).arg(ssrc));
  1341. const auto json = QByteArray::fromStdString(payload.json);
  1342. _api.request(
  1343. MTPphone_JoinGroupCallPresentation(
  1344. inputCall(),
  1345. MTP_dataJSON(MTP_bytes(json)))
  1346. ).done([=](const MTPUpdates &updates) {
  1347. _screenJoinState.finish(ssrc);
  1348. _mySsrcs.emplace(ssrc);
  1349. _peer->session().api().applyUpdates(updates);
  1350. checkNextJoinAction();
  1351. if (isScreenPaused()) {
  1352. sendSelfUpdate(SendUpdateType::ScreenPaused);
  1353. }
  1354. sendPendingSelfUpdates();
  1355. }).fail([=](const MTP::Error &error) {
  1356. _screenJoinState.finish();
  1357. const auto type = error.type();
  1358. if (type == u"GROUPCALL_SSRC_DUPLICATE_MUCH") {
  1359. _screenJoinState.nextActionPending = true;
  1360. checkNextJoinAction();
  1361. } else if (type == u"GROUPCALL_JOIN_MISSING"_q
  1362. || type == u"GROUPCALL_FORBIDDEN"_q) {
  1363. if (_joinState.ssrc != withMainSsrc) {
  1364. // We've rejoined, rejoin presentation again.
  1365. _screenJoinState.nextActionPending = true;
  1366. checkNextJoinAction();
  1367. }
  1368. } else {
  1369. LOG(("Call Error: "
  1370. "Could not screen join, error: %1").arg(type));
  1371. _screenState = Webrtc::VideoState::Inactive;
  1372. _errors.fire_copy(mutedByAdmin()
  1373. ? Error::MutedNoScreen
  1374. : Error::ScreenFailed);
  1375. }
  1376. }).send();
  1377. });
  1378. });
  1379. }
  1380. void GroupCall::leavePresentation() {
  1381. destroyScreencast();
  1382. if (!_screenJoinState.ssrc) {
  1383. setScreenEndpoint(std::string());
  1384. return;
  1385. } else if (_screenJoinState.action == JoinAction::Leaving) {
  1386. return;
  1387. } else if (_screenJoinState.action != JoinAction::None) {
  1388. _screenJoinState.nextActionPending = true;
  1389. return;
  1390. }
  1391. _api.request(
  1392. MTPphone_LeaveGroupCallPresentation(inputCall())
  1393. ).done([=](const MTPUpdates &updates) {
  1394. _screenJoinState.finish();
  1395. _peer->session().api().applyUpdates(updates);
  1396. setScreenEndpoint(std::string());
  1397. checkNextJoinAction();
  1398. }).fail([=](const MTP::Error &error) {
  1399. _screenJoinState.finish();
  1400. const auto type = error.type();
  1401. LOG(("Call Error: "
  1402. "Could not screen leave, error: %1").arg(type));
  1403. setScreenEndpoint(std::string());
  1404. checkNextJoinAction();
  1405. }).send();
  1406. }
  1407. void GroupCall::applyMeInCallLocally() {
  1408. const auto real = lookupReal();
  1409. if (!real) {
  1410. return;
  1411. }
  1412. using Flag = MTPDgroupCallParticipant::Flag;
  1413. const auto participant = real->participantByPeer(joinAs());
  1414. const auto date = participant
  1415. ? participant->date
  1416. : base::unixtime::now();
  1417. const auto lastActive = participant
  1418. ? participant->lastActive
  1419. : TimeId(0);
  1420. const auto volume = participant
  1421. ? participant->volume
  1422. : Group::kDefaultVolume;
  1423. const auto canSelfUnmute = !mutedByAdmin();
  1424. const auto raisedHandRating = (muted() != MuteState::RaisedHand)
  1425. ? uint64(0)
  1426. : participant
  1427. ? participant->raisedHandRating
  1428. : FindLocalRaisedHandRating(real->participants());
  1429. const auto flags = (canSelfUnmute ? Flag::f_can_self_unmute : Flag(0))
  1430. | (lastActive ? Flag::f_active_date : Flag(0))
  1431. | (_joinState.ssrc ? Flag(0) : Flag::f_left)
  1432. | (_videoIsWorking.current() ? Flag::f_video_joined : Flag(0))
  1433. | Flag::f_self
  1434. | Flag::f_volume // Without flag the volume is reset to 100%.
  1435. | Flag::f_volume_by_admin // Self volume can only be set by admin.
  1436. | ((muted() != MuteState::Active) ? Flag::f_muted : Flag(0))
  1437. | (raisedHandRating > 0 ? Flag::f_raise_hand_rating : Flag(0));
  1438. real->applyLocalUpdate(
  1439. MTP_updateGroupCallParticipants(
  1440. inputCall(),
  1441. MTP_vector<MTPGroupCallParticipant>(
  1442. 1,
  1443. MTP_groupCallParticipant(
  1444. MTP_flags(flags),
  1445. peerToMTP(joinAs()->id),
  1446. MTP_int(date),
  1447. MTP_int(lastActive),
  1448. MTP_int(_joinState.ssrc),
  1449. MTP_int(volume),
  1450. MTPstring(), // Don't update about text in local updates.
  1451. MTP_long(raisedHandRating),
  1452. MTPGroupCallParticipantVideo(),
  1453. MTPGroupCallParticipantVideo())),
  1454. MTP_int(0)).c_updateGroupCallParticipants());
  1455. }
  1456. void GroupCall::applyParticipantLocally(
  1457. not_null<PeerData*> participantPeer,
  1458. bool mute,
  1459. std::optional<int> volume) {
  1460. const auto participant = LookupParticipant(_peer, _id, participantPeer);
  1461. if (!participant || !participant->ssrc) {
  1462. return;
  1463. }
  1464. const auto canManageCall = canManage();
  1465. const auto isMuted = participant->muted || (mute && canManageCall);
  1466. const auto canSelfUnmute = !canManageCall
  1467. ? participant->canSelfUnmute
  1468. : (!mute || IsGroupCallAdmin(_peer, participantPeer));
  1469. const auto isMutedByYou = mute && !canManageCall;
  1470. using Flag = MTPDgroupCallParticipant::Flag;
  1471. const auto flags = (canSelfUnmute ? Flag::f_can_self_unmute : Flag(0))
  1472. | Flag::f_volume // Without flag the volume is reset to 100%.
  1473. | ((participant->applyVolumeFromMin && !volume)
  1474. ? Flag::f_volume_by_admin
  1475. : Flag(0))
  1476. | (participant->videoJoined ? Flag::f_video_joined : Flag(0))
  1477. | (participant->lastActive ? Flag::f_active_date : Flag(0))
  1478. | (isMuted ? Flag::f_muted : Flag(0))
  1479. | (isMutedByYou ? Flag::f_muted_by_you : Flag(0))
  1480. | (participantPeer == joinAs() ? Flag::f_self : Flag(0))
  1481. | (participant->raisedHandRating
  1482. ? Flag::f_raise_hand_rating
  1483. : Flag(0));
  1484. _peer->groupCall()->applyLocalUpdate(
  1485. MTP_updateGroupCallParticipants(
  1486. inputCall(),
  1487. MTP_vector<MTPGroupCallParticipant>(
  1488. 1,
  1489. MTP_groupCallParticipant(
  1490. MTP_flags(flags),
  1491. peerToMTP(participantPeer->id),
  1492. MTP_int(participant->date),
  1493. MTP_int(participant->lastActive),
  1494. MTP_int(participant->ssrc),
  1495. MTP_int(volume.value_or(participant->volume)),
  1496. MTPstring(), // Don't update about text in local updates.
  1497. MTP_long(participant->raisedHandRating),
  1498. MTPGroupCallParticipantVideo(),
  1499. MTPGroupCallParticipantVideo())),
  1500. MTP_int(0)).c_updateGroupCallParticipants());
  1501. }
  1502. void GroupCall::hangup() {
  1503. finish(FinishType::Ended);
  1504. }
  1505. void GroupCall::discard() {
  1506. if (!_id) {
  1507. _api.request(_createRequestId).cancel();
  1508. hangup();
  1509. return;
  1510. }
  1511. _api.request(MTPphone_DiscardGroupCall(
  1512. inputCall()
  1513. )).done([=](const MTPUpdates &result) {
  1514. // Here 'this' could be destroyed by updates, so we set Ended after
  1515. // updates being handled, but in a guarded way.
  1516. crl::on_main(this, [=] { hangup(); });
  1517. _peer->session().api().applyUpdates(result);
  1518. }).fail([=] {
  1519. hangup();
  1520. }).send();
  1521. }
  1522. void GroupCall::rejoinAs(Group::JoinInfo info) {
  1523. _possibleJoinAs = std::move(info.possibleJoinAs);
  1524. if (info.joinAs == joinAs()) {
  1525. return;
  1526. }
  1527. const auto event = Group::RejoinEvent{
  1528. .wasJoinAs = joinAs(),
  1529. .nowJoinAs = info.joinAs,
  1530. };
  1531. if (_scheduleDate) {
  1532. saveDefaultJoinAs(info.joinAs);
  1533. } else {
  1534. setState(State::Joining);
  1535. rejoin(info.joinAs);
  1536. }
  1537. _rejoinEvents.fire_copy(event);
  1538. }
  1539. void GroupCall::finish(FinishType type) {
  1540. Expects(type != FinishType::None);
  1541. const auto finalState = (type == FinishType::Ended)
  1542. ? State::Ended
  1543. : State::Failed;
  1544. const auto hangupState = (type == FinishType::Ended)
  1545. ? State::HangingUp
  1546. : State::FailedHangingUp;
  1547. const auto state = _state.current();
  1548. if (state == State::HangingUp
  1549. || state == State::FailedHangingUp
  1550. || state == State::Ended
  1551. || state == State::Failed) {
  1552. return;
  1553. } else if (_joinState.action == JoinAction::None && !_joinState.ssrc) {
  1554. setState(finalState);
  1555. return;
  1556. }
  1557. setState(hangupState);
  1558. _joinState.nextActionPending = true;
  1559. checkNextJoinAction();
  1560. }
  1561. void GroupCall::leave() {
  1562. Expects(_joinState.action == JoinAction::None);
  1563. _joinState.action = JoinAction::Leaving;
  1564. const auto finalState = (_state.current() == State::HangingUp)
  1565. ? State::Ended
  1566. : State::Failed;
  1567. // We want to leave request still being sent and processed even if
  1568. // the call is already destroyed.
  1569. const auto session = &_peer->session();
  1570. const auto weak = base::make_weak(this);
  1571. session->api().request(MTPphone_LeaveGroupCall(
  1572. inputCall(),
  1573. MTP_int(base::take(_joinState.ssrc))
  1574. )).done([=](const MTPUpdates &result) {
  1575. // Here 'this' could be destroyed by updates, so we set Ended after
  1576. // updates being handled, but in a guarded way.
  1577. crl::on_main(weak, [=] { setState(finalState); });
  1578. session->api().applyUpdates(result);
  1579. }).fail(crl::guard(weak, [=] {
  1580. setState(finalState);
  1581. })).send();
  1582. }
  1583. void GroupCall::startScheduledNow() {
  1584. if (!lookupReal()) {
  1585. return;
  1586. }
  1587. _api.request(MTPphone_StartScheduledGroupCall(
  1588. inputCall()
  1589. )).done([=](const MTPUpdates &result) {
  1590. _peer->session().api().applyUpdates(result);
  1591. }).send();
  1592. }
  1593. void GroupCall::toggleScheduleStartSubscribed(bool subscribed) {
  1594. if (!lookupReal()) {
  1595. return;
  1596. }
  1597. _api.request(MTPphone_ToggleGroupCallStartSubscription(
  1598. inputCall(),
  1599. MTP_bool(subscribed)
  1600. )).done([=](const MTPUpdates &result) {
  1601. _peer->session().api().applyUpdates(result);
  1602. }).send();
  1603. }
  1604. void GroupCall::setNoiseSuppression(bool enabled) {
  1605. if (_instance) {
  1606. _instance->setIsNoiseSuppressionEnabled(enabled);
  1607. }
  1608. }
  1609. void GroupCall::addVideoOutput(
  1610. const std::string &endpoint,
  1611. not_null<Webrtc::VideoTrack*> track) {
  1612. addVideoOutput(endpoint, { track->sink() });
  1613. }
  1614. void GroupCall::setMuted(MuteState mute) {
  1615. const auto set = [=] {
  1616. const auto was = muted();
  1617. const auto wasSpeaking = (was == MuteState::Active)
  1618. || (was == MuteState::PushToTalk);
  1619. const auto wasMuted = (was == MuteState::Muted)
  1620. || (was == MuteState::PushToTalk);
  1621. const auto wasRaiseHand = (was == MuteState::RaisedHand);
  1622. _muted = mute;
  1623. const auto now = muted();
  1624. const auto nowSpeaking = (now == MuteState::Active)
  1625. || (now == MuteState::PushToTalk);
  1626. const auto nowMuted = (now == MuteState::Muted)
  1627. || (now == MuteState::PushToTalk);
  1628. const auto nowRaiseHand = (now == MuteState::RaisedHand);
  1629. if (wasMuted != nowMuted || wasRaiseHand != nowRaiseHand) {
  1630. applyMeInCallLocally();
  1631. }
  1632. if (mutedByAdmin()) {
  1633. toggleVideo(false);
  1634. toggleScreenSharing(std::nullopt);
  1635. }
  1636. if (wasSpeaking && !nowSpeaking && _joinState.ssrc) {
  1637. _levelUpdates.fire(LevelUpdate{
  1638. .ssrc = _joinState.ssrc,
  1639. .value = 0.f,
  1640. .voice = false,
  1641. .me = true,
  1642. });
  1643. }
  1644. };
  1645. if (mute == MuteState::Active || mute == MuteState::PushToTalk) {
  1646. _delegate->groupCallRequestPermissionsOrFail(crl::guard(this, set));
  1647. } else {
  1648. set();
  1649. }
  1650. }
  1651. void GroupCall::setMutedAndUpdate(MuteState mute) {
  1652. const auto was = muted();
  1653. // Active state is sent from _muted changes,
  1654. // because it may be set delayed, after permissions request, not now.
  1655. const auto send = _initialMuteStateSent && (mute != MuteState::Active);
  1656. setMuted(mute);
  1657. if (send) {
  1658. maybeSendMutedUpdate(was);
  1659. }
  1660. }
  1661. void GroupCall::handlePossibleCreateOrJoinResponse(
  1662. const MTPDupdateGroupCall &data) {
  1663. data.vcall().match([&](const MTPDgroupCall &data) {
  1664. handlePossibleCreateOrJoinResponse(data);
  1665. }, [&](const MTPDgroupCallDiscarded &data) {
  1666. handlePossibleDiscarded(data);
  1667. });
  1668. }
  1669. void GroupCall::handlePossibleCreateOrJoinResponse(
  1670. const MTPDgroupCall &data) {
  1671. if (_acceptFields) {
  1672. if (!_instance && !_id) {
  1673. const auto input = MTP_inputGroupCall(
  1674. data.vid(),
  1675. data.vaccess_hash());
  1676. const auto scheduleDate = data.vschedule_date().value_or_empty();
  1677. const auto rtmp = data.is_rtmp_stream();
  1678. _rtmp = rtmp;
  1679. setScheduledDate(scheduleDate);
  1680. if (const auto chat = _peer->asChat()) {
  1681. chat->setGroupCall(input, scheduleDate, rtmp);
  1682. } else if (const auto group = _peer->asChannel()) {
  1683. group->setGroupCall(input, scheduleDate, rtmp);
  1684. } else {
  1685. Unexpected("Peer type in GroupCall::join.");
  1686. }
  1687. join(input);
  1688. }
  1689. return;
  1690. } else if (_id != data.vid().v || !_instance) {
  1691. return;
  1692. }
  1693. setScheduledDate(data.vschedule_date().value_or_empty());
  1694. if (const auto streamDcId = data.vstream_dc_id()) {
  1695. _broadcastDcId = MTP::BareDcId(streamDcId->v);
  1696. }
  1697. }
  1698. void GroupCall::handlePossibleCreateOrJoinResponse(
  1699. const MTPDupdateGroupCallConnection &data) {
  1700. if (data.is_presentation()) {
  1701. if (!_screenInstance) {
  1702. return;
  1703. }
  1704. setScreenInstanceMode(InstanceMode::Rtc);
  1705. data.vparams().match([&](const MTPDdataJSON &data) {
  1706. const auto json = data.vdata().v;
  1707. const auto response = ParseJoinResponse(json);
  1708. const auto endpoint = std::get_if<JoinVideoEndpoint>(&response);
  1709. if (endpoint) {
  1710. setScreenEndpoint(endpoint->id);
  1711. } else {
  1712. LOG(("Call Error: Bad response for 'presentation' flag."));
  1713. }
  1714. _screenInstance->setJoinResponsePayload(json.toStdString());
  1715. });
  1716. } else {
  1717. if (!_instance) {
  1718. return;
  1719. }
  1720. data.vparams().match([&](const MTPDdataJSON &data) {
  1721. const auto json = data.vdata().v;
  1722. const auto response = ParseJoinResponse(json);
  1723. const auto stream = std::get_if<JoinBroadcastStream>(&response);
  1724. const auto endpoint = std::get_if<JoinVideoEndpoint>(&response);
  1725. if (stream) {
  1726. if (!_broadcastDcId) {
  1727. LOG(("Api Error: Empty stream_dc_id in groupCall."));
  1728. _broadcastDcId = _peer->session().mtp().mainDcId();
  1729. }
  1730. if (stream->rtmp) {
  1731. _rtmp = true;
  1732. _rtmpUrl = stream->rtmpInfo.url;
  1733. _rtmpKey = stream->rtmpInfo.key;
  1734. }
  1735. setInstanceMode(InstanceMode::Stream);
  1736. } else {
  1737. setInstanceMode(InstanceMode::Rtc);
  1738. setCameraEndpoint(endpoint ? endpoint->id : std::string());
  1739. _instance->setJoinResponsePayload(json.toStdString());
  1740. }
  1741. updateRequestedVideoChannels();
  1742. checkMediaChannelDescriptions();
  1743. });
  1744. }
  1745. }
  1746. void GroupCall::handlePossibleDiscarded(const MTPDgroupCallDiscarded &data) {
  1747. if (data.vid().v == _id) {
  1748. LOG(("Call Info: Hangup after groupCallDiscarded."));
  1749. _joinState.finish();
  1750. hangup();
  1751. }
  1752. }
  1753. void GroupCall::checkMediaChannelDescriptions(
  1754. Fn<bool(uint32)> resolved) {
  1755. const auto real = lookupReal();
  1756. if (!real || (_instanceMode == InstanceMode::None)) {
  1757. return;
  1758. }
  1759. for (auto i = begin(_mediaChannelDescriptionses)
  1760. ; i != end(_mediaChannelDescriptionses);) {
  1761. if (mediaChannelDescriptionsFill(i->get(), resolved)) {
  1762. i = _mediaChannelDescriptionses.erase(i);
  1763. } else {
  1764. ++i;
  1765. }
  1766. }
  1767. if (!_unresolvedSsrcs.empty()) {
  1768. real->resolveParticipants(base::take(_unresolvedSsrcs));
  1769. }
  1770. }
  1771. void GroupCall::handleUpdate(const MTPUpdate &update) {
  1772. update.match([&](const MTPDupdateGroupCall &data) {
  1773. handleUpdate(data);
  1774. }, [&](const MTPDupdateGroupCallParticipants &data) {
  1775. handleUpdate(data);
  1776. }, [](const auto &) {
  1777. Unexpected("Type in Instance::applyGroupCallUpdateChecked.");
  1778. });
  1779. }
  1780. void GroupCall::handleUpdate(const MTPDupdateGroupCall &data) {
  1781. data.vcall().match([](const MTPDgroupCall &) {
  1782. }, [&](const MTPDgroupCallDiscarded &data) {
  1783. handlePossibleDiscarded(data);
  1784. });
  1785. }
  1786. void GroupCall::handleUpdate(const MTPDupdateGroupCallParticipants &data) {
  1787. const auto callId = data.vcall().match([](const auto &data) {
  1788. return data.vid().v;
  1789. });
  1790. if (_id != callId) {
  1791. return;
  1792. }
  1793. const auto state = _state.current();
  1794. const auto joined = (state == State::Joined)
  1795. || (state == State::Connecting);
  1796. for (const auto &participant : data.vparticipants().v) {
  1797. participant.match([&](const MTPDgroupCallParticipant &data) {
  1798. const auto isSelf = data.is_self()
  1799. || (data.is_min()
  1800. && peerFromMTP(data.vpeer()) == joinAs()->id);
  1801. if (!isSelf) {
  1802. applyOtherParticipantUpdate(data);
  1803. } else if (joined) {
  1804. applySelfUpdate(data);
  1805. } else {
  1806. _queuedSelfUpdates.push_back(participant);
  1807. }
  1808. });
  1809. }
  1810. }
  1811. void GroupCall::applyQueuedSelfUpdates() {
  1812. const auto weak = base::make_weak(this);
  1813. while (weak
  1814. && !_queuedSelfUpdates.empty()
  1815. && (_state.current() == State::Joined
  1816. || _state.current() == State::Connecting)) {
  1817. const auto update = _queuedSelfUpdates.front();
  1818. _queuedSelfUpdates.erase(_queuedSelfUpdates.begin());
  1819. update.match([&](const MTPDgroupCallParticipant &data) {
  1820. applySelfUpdate(data);
  1821. });
  1822. }
  1823. }
  1824. void GroupCall::applySelfUpdate(const MTPDgroupCallParticipant &data) {
  1825. if (data.is_left()) {
  1826. if (data.vsource().v == _joinState.ssrc) {
  1827. // I was removed from the call, rejoin.
  1828. LOG(("Call Info: "
  1829. "Rejoin after got 'left' with my ssrc."));
  1830. setState(State::Joining);
  1831. rejoin();
  1832. }
  1833. return;
  1834. } else if (data.vsource().v != _joinState.ssrc) {
  1835. const auto ssrc = uint32(data.vsource().v);
  1836. if (!_mySsrcs.contains(ssrc)) {
  1837. // I joined from another device, hangup.
  1838. LOG(("Call Info: "
  1839. "Hangup after '!left' with ssrc %1, my %2."
  1840. ).arg(data.vsource().v
  1841. ).arg(_joinState.ssrc));
  1842. _joinState.finish();
  1843. hangup();
  1844. } else {
  1845. LOG(("Call Info: "
  1846. "Some old 'self' with '!left' and ssrc %1, my %2."
  1847. ).arg(data.vsource().v
  1848. ).arg(_joinState.ssrc));
  1849. }
  1850. return;
  1851. }
  1852. if (data.is_muted() && !data.is_can_self_unmute()) {
  1853. setMuted(data.vraise_hand_rating().value_or_empty()
  1854. ? MuteState::RaisedHand
  1855. : MuteState::ForceMuted);
  1856. } else if (_instanceMode == InstanceMode::Stream) {
  1857. LOG(("Call Info: Rejoin after unforcemute in stream mode."));
  1858. setState(State::Joining);
  1859. rejoin();
  1860. } else if (mutedByAdmin()) {
  1861. setMuted(MuteState::Muted);
  1862. if (!_instanceTransitioning) {
  1863. notifyAboutAllowedToSpeak();
  1864. }
  1865. } else if (data.is_muted() && muted() != MuteState::Muted) {
  1866. setMuted(MuteState::Muted);
  1867. }
  1868. }
  1869. void GroupCall::applyOtherParticipantUpdate(
  1870. const MTPDgroupCallParticipant &data) {
  1871. if (data.is_min()) {
  1872. // No real information about mutedByMe or my custom volume.
  1873. return;
  1874. }
  1875. const auto participantPeer = _peer->owner().peer(
  1876. peerFromMTP(data.vpeer()));
  1877. if (!LookupParticipant(_peer, _id, participantPeer)) {
  1878. return;
  1879. }
  1880. _otherParticipantStateValue.fire(Group::ParticipantState{
  1881. .peer = participantPeer,
  1882. .volume = data.vvolume().value_or_empty(),
  1883. .mutedByMe = data.is_muted_by_you(),
  1884. });
  1885. }
  1886. void GroupCall::setupMediaDevices() {
  1887. _playbackDeviceId.changes() | rpl::filter([=] {
  1888. return _instance && _setDeviceIdCallback;
  1889. }) | rpl::start_with_next([=](const Webrtc::DeviceResolvedId &deviceId) {
  1890. _setDeviceIdCallback(deviceId);
  1891. // Value doesn't matter here, just trigger reading of the new value.
  1892. _instance->setAudioOutputDevice(deviceId.value.toStdString());
  1893. }, _lifetime);
  1894. _captureDeviceId.changes() | rpl::filter([=] {
  1895. return _instance && _setDeviceIdCallback;
  1896. }) | rpl::start_with_next([=](const Webrtc::DeviceResolvedId &deviceId) {
  1897. _setDeviceIdCallback(deviceId);
  1898. // Value doesn't matter here, just trigger reading of the new value.
  1899. _instance->setAudioInputDevice(deviceId.value.toStdString());
  1900. }, _lifetime);
  1901. _cameraDeviceId.changes() | rpl::filter([=] {
  1902. return _cameraCapture != nullptr;
  1903. }) | rpl::start_with_next([=](const Webrtc::DeviceResolvedId &deviceId) {
  1904. _cameraCapture->switchToDevice(deviceId.value.toStdString(), false);
  1905. }, _lifetime);
  1906. if (!_rtmp) {
  1907. _muted.value() | rpl::start_with_next([=](MuteState state) {
  1908. const auto devices = &Core::App().mediaDevices();
  1909. const auto muted = (state != MuteState::Active)
  1910. && (state != MuteState::PushToTalk);
  1911. const auto track = !muted || (state == MuteState::Muted);
  1912. devices->setCaptureMuteTracker(this, track);
  1913. devices->setCaptureMuted(muted);
  1914. }, _lifetime);
  1915. }
  1916. }
  1917. void GroupCall::captureMuteChanged(bool mute) {
  1918. const auto oldState = muted();
  1919. if (mute
  1920. && (oldState == MuteState::ForceMuted
  1921. || oldState == MuteState::RaisedHand
  1922. || oldState == MuteState::Muted)) {
  1923. return;
  1924. } else if (!mute && oldState != MuteState::Muted) {
  1925. return;
  1926. }
  1927. setMutedAndUpdate(mute ? MuteState::Muted : MuteState::Active);
  1928. }
  1929. rpl::producer<Webrtc::DeviceResolvedId> GroupCall::captureMuteDeviceId() {
  1930. return _captureDeviceId.value();
  1931. }
  1932. int GroupCall::activeVideoSendersCount() const {
  1933. auto result = 0;
  1934. for (const auto &[endpoint, track] : _activeVideoTracks) {
  1935. if (endpoint.type == VideoEndpointType::Camera) {
  1936. ++result;
  1937. } else {
  1938. auto sharesCameraToo = false;
  1939. for (const auto &[other, _] : _activeVideoTracks) {
  1940. if (other.type == VideoEndpointType::Camera
  1941. && other.peer == endpoint.peer) {
  1942. sharesCameraToo = true;
  1943. break;
  1944. }
  1945. }
  1946. if (!sharesCameraToo) {
  1947. ++result;
  1948. }
  1949. }
  1950. }
  1951. return result;
  1952. }
  1953. bool GroupCall::emitShareCameraError() {
  1954. const auto emitError = [=](Error error) {
  1955. emitShareCameraError(error);
  1956. return true;
  1957. };
  1958. if (const auto real = lookupReal()
  1959. ; real && activeVideoSendersCount() >= real->unmutedVideoLimit()) {
  1960. return emitError(Error::DisabledNoCamera);
  1961. } else if (!videoIsWorking()) {
  1962. return emitError(Error::DisabledNoCamera);
  1963. } else if (mutedByAdmin()) {
  1964. return emitError(Error::MutedNoCamera);
  1965. } else if (_cameraDeviceId.current().value.isEmpty()) {
  1966. return emitError(Error::NoCamera);
  1967. }
  1968. return false;
  1969. }
  1970. void GroupCall::emitShareCameraError(Error error) {
  1971. _cameraState = Webrtc::VideoState::Inactive;
  1972. if (error == Error::CameraFailed
  1973. && _cameraDeviceId.current().value.isEmpty()) {
  1974. error = Error::NoCamera;
  1975. }
  1976. _errors.fire_copy(error);
  1977. }
  1978. bool GroupCall::emitShareScreenError() {
  1979. const auto emitError = [=](Error error) {
  1980. emitShareScreenError(error);
  1981. return true;
  1982. };
  1983. if (const auto real = lookupReal()
  1984. ; real && activeVideoSendersCount() >= real->unmutedVideoLimit()) {
  1985. return emitError(Error::DisabledNoScreen);
  1986. } else if (!videoIsWorking()) {
  1987. return emitError(Error::DisabledNoScreen);
  1988. } else if (mutedByAdmin()) {
  1989. return emitError(Error::MutedNoScreen);
  1990. }
  1991. return false;
  1992. }
  1993. void GroupCall::emitShareScreenError(Error error) {
  1994. _screenState = Webrtc::VideoState::Inactive;
  1995. _errors.fire_copy(error);
  1996. }
  1997. void GroupCall::setupOutgoingVideo() {
  1998. using Webrtc::VideoState;
  1999. _cameraState.value(
  2000. ) | rpl::combine_previous(
  2001. ) | rpl::filter([=](VideoState previous, VideoState state) {
  2002. // Recursive entrance may happen if error happens when activating.
  2003. return (previous != state);
  2004. }) | rpl::start_with_next([=](VideoState previous, VideoState state) {
  2005. const auto wasActive = (previous != VideoState::Inactive);
  2006. const auto nowPaused = (state == VideoState::Paused);
  2007. const auto nowActive = (state != VideoState::Inactive);
  2008. if (wasActive == nowActive) {
  2009. Assert(wasActive && nowActive);
  2010. sendSelfUpdate(SendUpdateType::CameraPaused);
  2011. markTrackPaused({
  2012. VideoEndpointType::Camera,
  2013. joinAs(),
  2014. _cameraEndpoint
  2015. }, nowPaused);
  2016. return;
  2017. }
  2018. if (nowActive) {
  2019. if (emitShareCameraError()) {
  2020. return;
  2021. } else if (!_cameraCapture) {
  2022. _cameraCapture = _delegate->groupCallGetVideoCapture(
  2023. _cameraDeviceId.current().value);
  2024. if (!_cameraCapture) {
  2025. return emitShareCameraError(Error::CameraFailed);
  2026. }
  2027. const auto weak = base::make_weak(this);
  2028. _cameraCapture->setOnFatalError([=] {
  2029. crl::on_main(weak, [=] {
  2030. emitShareCameraError(Error::CameraFailed);
  2031. });
  2032. });
  2033. } else {
  2034. _cameraCapture->switchToDevice(
  2035. _cameraDeviceId.current().value.toStdString(),
  2036. false);
  2037. }
  2038. if (_instance) {
  2039. _instance->setVideoCapture(_cameraCapture);
  2040. }
  2041. _cameraCapture->setState(tgcalls::VideoState::Active);
  2042. } else if (_cameraCapture) {
  2043. _cameraCapture->setState(tgcalls::VideoState::Inactive);
  2044. }
  2045. _isSharingCamera = nowActive;
  2046. markEndpointActive({
  2047. VideoEndpointType::Camera,
  2048. joinAs(),
  2049. _cameraEndpoint
  2050. }, nowActive, nowPaused);
  2051. sendSelfUpdate(SendUpdateType::CameraStopped);
  2052. applyMeInCallLocally();
  2053. }, _lifetime);
  2054. _screenState.value(
  2055. ) | rpl::combine_previous(
  2056. ) | rpl::filter([=](VideoState previous, VideoState state) {
  2057. // Recursive entrance may happen if error happens when activating.
  2058. return (previous != state);
  2059. }) | rpl::start_with_next([=](VideoState previous, VideoState state) {
  2060. const auto wasActive = (previous != VideoState::Inactive);
  2061. const auto nowPaused = (state == VideoState::Paused);
  2062. const auto nowActive = (state != VideoState::Inactive);
  2063. if (wasActive == nowActive) {
  2064. Assert(wasActive && nowActive);
  2065. sendSelfUpdate(SendUpdateType::ScreenPaused);
  2066. markTrackPaused({
  2067. VideoEndpointType::Screen,
  2068. joinAs(),
  2069. _screenEndpoint
  2070. }, nowPaused);
  2071. return;
  2072. }
  2073. if (nowActive) {
  2074. if (emitShareScreenError()) {
  2075. return;
  2076. } else if (!_screenCapture) {
  2077. _screenCapture = std::shared_ptr<
  2078. tgcalls::VideoCaptureInterface
  2079. >(tgcalls::VideoCaptureInterface::Create(
  2080. tgcalls::StaticThreads::getThreads(),
  2081. _screenDeviceId.toStdString()));
  2082. if (!_screenCapture) {
  2083. return emitShareScreenError(Error::ScreenFailed);
  2084. }
  2085. const auto weak = base::make_weak(this);
  2086. _screenCapture->setOnFatalError([=] {
  2087. crl::on_main(weak, [=] {
  2088. emitShareScreenError(Error::ScreenFailed);
  2089. });
  2090. });
  2091. _screenCapture->setOnPause([=](bool paused) {
  2092. crl::on_main(weak, [=] {
  2093. if (isSharingScreen()) {
  2094. _screenState = paused
  2095. ? VideoState::Paused
  2096. : VideoState::Active;
  2097. }
  2098. });
  2099. });
  2100. } else {
  2101. _screenCapture->switchToDevice(
  2102. _screenDeviceId.toStdString(),
  2103. true);
  2104. }
  2105. if (_screenInstance) {
  2106. _screenInstance->setVideoCapture(_screenCapture);
  2107. }
  2108. _screenCapture->setState(tgcalls::VideoState::Active);
  2109. } else if (_screenCapture) {
  2110. _screenCapture->setState(tgcalls::VideoState::Inactive);
  2111. }
  2112. _isSharingScreen = nowActive;
  2113. markEndpointActive({
  2114. VideoEndpointType::Screen,
  2115. joinAs(),
  2116. _screenEndpoint
  2117. }, nowActive, nowPaused);
  2118. _screenJoinState.nextActionPending = true;
  2119. checkNextJoinAction();
  2120. }, _lifetime);
  2121. }
  2122. void GroupCall::changeTitle(const QString &title) {
  2123. const auto real = lookupReal();
  2124. if (!real || real->title() == title) {
  2125. return;
  2126. }
  2127. _api.request(MTPphone_EditGroupCallTitle(
  2128. inputCall(),
  2129. MTP_string(title)
  2130. )).done([=](const MTPUpdates &result) {
  2131. _peer->session().api().applyUpdates(result);
  2132. _titleChanged.fire({});
  2133. }).send();
  2134. }
  2135. void GroupCall::toggleRecording(
  2136. bool enabled,
  2137. const QString &title,
  2138. bool video,
  2139. bool videoPortrait) {
  2140. const auto real = lookupReal();
  2141. if (!real) {
  2142. return;
  2143. }
  2144. const auto already = (real->recordStartDate() != 0);
  2145. if (already == enabled) {
  2146. return;
  2147. }
  2148. if (!enabled) {
  2149. _recordingStoppedByMe = true;
  2150. }
  2151. using Flag = MTPphone_ToggleGroupCallRecord::Flag;
  2152. _api.request(MTPphone_ToggleGroupCallRecord(
  2153. MTP_flags((enabled ? Flag::f_start : Flag(0))
  2154. | (video ? Flag::f_video : Flag(0))
  2155. | (title.isEmpty() ? Flag(0) : Flag::f_title)),
  2156. inputCall(),
  2157. MTP_string(title),
  2158. MTP_bool(videoPortrait)
  2159. )).done([=](const MTPUpdates &result) {
  2160. _peer->session().api().applyUpdates(result);
  2161. _recordingStoppedByMe = false;
  2162. }).fail([=] {
  2163. _recordingStoppedByMe = false;
  2164. }).send();
  2165. }
  2166. bool GroupCall::tryCreateController() {
  2167. if (_instance) {
  2168. return false;
  2169. }
  2170. const auto &settings = Core::App().settings();
  2171. const auto weak = base::make_weak(&_instanceGuard);
  2172. const auto myLevel = std::make_shared<tgcalls::GroupLevelValue>();
  2173. const auto playbackDeviceIdInitial = _playbackDeviceId.current();
  2174. const auto captureDeviceIdInitial = _captureDeviceId.current();
  2175. const auto saveSetDeviceIdCallback = [=](
  2176. Fn<void(Webrtc::DeviceResolvedId)> setDeviceIdCallback) {
  2177. setDeviceIdCallback(playbackDeviceIdInitial);
  2178. setDeviceIdCallback(captureDeviceIdInitial);
  2179. crl::on_main(weak, [=] {
  2180. _setDeviceIdCallback = std::move(setDeviceIdCallback);
  2181. const auto playback = _playbackDeviceId.current();
  2182. if (_instance && playback != playbackDeviceIdInitial) {
  2183. _setDeviceIdCallback(playback);
  2184. // Value doesn't matter here, just trigger reading of the...
  2185. _instance->setAudioOutputDevice(
  2186. playback.value.toStdString());
  2187. }
  2188. const auto capture = _captureDeviceId.current();
  2189. if (_instance && capture != captureDeviceIdInitial) {
  2190. _setDeviceIdCallback(capture);
  2191. // Value doesn't matter here, just trigger reading of the...
  2192. _instance->setAudioInputDevice(capture.value.toStdString());
  2193. }
  2194. });
  2195. };
  2196. tgcalls::GroupInstanceDescriptor descriptor = {
  2197. .threads = tgcalls::StaticThreads::getThreads(),
  2198. .config = tgcalls::GroupConfig{
  2199. },
  2200. .networkStateUpdated = [=](tgcalls::GroupNetworkState networkState) {
  2201. crl::on_main(weak, [=] { setInstanceConnected(networkState); });
  2202. },
  2203. .audioLevelsUpdated = [=](const tgcalls::GroupLevelsUpdate &data) {
  2204. const auto &updates = data.updates;
  2205. if (updates.empty()) {
  2206. return;
  2207. } else if (updates.size() == 1 && !updates.front().ssrc) {
  2208. const auto &value = updates.front().value;
  2209. // Don't send many 0 while we're muted.
  2210. if (myLevel->level == value.level
  2211. && myLevel->voice == value.voice) {
  2212. return;
  2213. }
  2214. *myLevel = updates.front().value;
  2215. }
  2216. crl::on_main(weak, [=] { audioLevelsUpdated(data); });
  2217. },
  2218. .initialInputDeviceId = captureDeviceIdInitial.value.toStdString(),
  2219. .initialOutputDeviceId = playbackDeviceIdInitial.value.toStdString(),
  2220. .createAudioDeviceModule = Webrtc::AudioDeviceModuleCreator(
  2221. saveSetDeviceIdCallback),
  2222. .videoCapture = _cameraCapture,
  2223. .requestCurrentTime = [=, call = base::make_weak(this)](
  2224. std::function<void(int64_t)> done) {
  2225. auto result = std::make_shared<RequestCurrentTimeTask>(
  2226. call,
  2227. std::move(done));
  2228. crl::on_main(weak, [=] {
  2229. requestCurrentTimeStart(std::move(result));
  2230. });
  2231. return result;
  2232. },
  2233. .requestAudioBroadcastPart = [=, call = base::make_weak(this)](
  2234. int64_t time,
  2235. int64_t period,
  2236. std::function<void(tgcalls::BroadcastPart &&)> done) {
  2237. auto result = std::make_shared<LoadPartTask>(
  2238. call,
  2239. time,
  2240. period,
  2241. std::move(done));
  2242. crl::on_main(weak, [=]() mutable {
  2243. broadcastPartStart(std::move(result));
  2244. });
  2245. return result;
  2246. },
  2247. .requestVideoBroadcastPart = [=, call = base::make_weak(this)](
  2248. int64_t time,
  2249. int64_t period,
  2250. int32_t channel,
  2251. tgcalls::VideoChannelDescription::Quality quality,
  2252. std::function<void(tgcalls::BroadcastPart &&)> done) {
  2253. auto result = std::make_shared<LoadPartTask>(
  2254. call,
  2255. time,
  2256. period,
  2257. channel,
  2258. quality,
  2259. std::move(done));
  2260. crl::on_main(weak, [=]() mutable {
  2261. broadcastPartStart(std::move(result));
  2262. });
  2263. return result;
  2264. },
  2265. .videoContentType = tgcalls::VideoContentType::Generic,
  2266. .initialEnableNoiseSuppression
  2267. = settings.groupCallNoiseSuppression(),
  2268. .requestMediaChannelDescriptions = [=, call = base::make_weak(this)](
  2269. const std::vector<uint32_t> &ssrcs,
  2270. std::function<void(
  2271. std::vector<tgcalls::MediaChannelDescription> &&)> done) {
  2272. auto result = std::make_shared<MediaChannelDescriptionsTask>(
  2273. call,
  2274. ssrcs,
  2275. std::move(done));
  2276. crl::on_main(weak, [=]() mutable {
  2277. mediaChannelDescriptionsStart(std::move(result));
  2278. });
  2279. return result;
  2280. },
  2281. };
  2282. if (Logs::DebugEnabled()) {
  2283. auto callLogFolder = cWorkingDir() + u"DebugLogs"_q;
  2284. auto callLogPath = callLogFolder + u"/last_group_call_log.txt"_q;
  2285. auto callLogNative = QDir::toNativeSeparators(callLogPath);
  2286. descriptor.config.need_log = true;
  2287. #ifdef Q_OS_WIN
  2288. descriptor.config.logPath.data = callLogNative.toStdWString();
  2289. #else // Q_OS_WIN
  2290. const auto callLogUtf = QFile::encodeName(callLogNative);
  2291. descriptor.config.logPath.data.resize(callLogUtf.size());
  2292. ranges::copy(callLogUtf, descriptor.config.logPath.data.begin());
  2293. #endif // Q_OS_WIN
  2294. QFile(callLogPath).remove();
  2295. QDir().mkpath(callLogFolder);
  2296. } else {
  2297. descriptor.config.need_log = false;
  2298. }
  2299. LOG(("Call Info: Creating group instance"));
  2300. _instance = std::make_unique<tgcalls::GroupInstanceCustomImpl>(
  2301. std::move(descriptor));
  2302. updateInstanceMuteState();
  2303. updateInstanceVolumes();
  2304. for (auto &[endpoint, sink] : base::take(_pendingVideoOutputs)) {
  2305. _instance->addIncomingVideoOutput(endpoint, std::move(sink.data));
  2306. }
  2307. //raw->setAudioOutputDuckingEnabled(settings.callAudioDuckingEnabled());
  2308. return true;
  2309. }
  2310. bool GroupCall::tryCreateScreencast() {
  2311. if (_screenInstance) {
  2312. return false;
  2313. }
  2314. const auto weak = base::make_weak(&_screenInstanceGuard);
  2315. tgcalls::GroupInstanceDescriptor descriptor = {
  2316. .threads = tgcalls::StaticThreads::getThreads(),
  2317. .config = tgcalls::GroupConfig{
  2318. .need_log = Logs::DebugEnabled(),
  2319. },
  2320. .networkStateUpdated = [=](tgcalls::GroupNetworkState networkState) {
  2321. crl::on_main(weak, [=] {
  2322. setScreenInstanceConnected(networkState);
  2323. });
  2324. },
  2325. .createAudioDeviceModule = Webrtc::LoopbackAudioDeviceModuleCreator(),
  2326. .videoCapture = _screenCapture,
  2327. .videoContentType = tgcalls::VideoContentType::Screencast,
  2328. };
  2329. LOG(("Call Info: Creating group screen instance"));
  2330. _screenInstance = std::make_unique<tgcalls::GroupInstanceCustomImpl>(
  2331. std::move(descriptor));
  2332. _screenInstance->setIsMuted(!_screenWithAudio);
  2333. return true;
  2334. }
  2335. void GroupCall::broadcastPartStart(std::shared_ptr<LoadPartTask> task) {
  2336. const auto raw = task.get();
  2337. const auto time = raw->time();
  2338. const auto scale = raw->scale();
  2339. const auto videoChannel = raw->videoChannel();
  2340. const auto videoQuality = raw->videoQuality();
  2341. const auto finish = [=](tgcalls::BroadcastPart &&part) {
  2342. raw->done(std::move(part));
  2343. _broadcastParts.erase(raw);
  2344. };
  2345. using Status = tgcalls::BroadcastPart::Status;
  2346. using Quality = tgcalls::VideoChannelDescription::Quality;
  2347. using Flag = MTPDinputGroupCallStream::Flag;
  2348. const auto requestId = _api.request(MTPupload_GetFile(
  2349. MTP_flags(0),
  2350. MTP_inputGroupCallStream(
  2351. MTP_flags(videoChannel
  2352. ? (Flag::f_video_channel | Flag::f_video_quality)
  2353. : Flag(0)),
  2354. inputCall(),
  2355. MTP_long(time),
  2356. MTP_int(scale),
  2357. MTP_int(videoChannel),
  2358. MTP_int((videoQuality == Quality::Full)
  2359. ? 2
  2360. : (videoQuality == Quality::Medium)
  2361. ? 1
  2362. : 0)),
  2363. MTP_long(0),
  2364. MTP_int(128 * 1024)
  2365. )).done([=](
  2366. const MTPupload_File &result,
  2367. const MTP::Response &response) {
  2368. result.match([&](const MTPDupload_file &data) {
  2369. const auto size = data.vbytes().v.size();
  2370. auto bytes = std::vector<uint8_t>(size);
  2371. memcpy(bytes.data(), data.vbytes().v.constData(), size);
  2372. finish({
  2373. .timestampMilliseconds = time,
  2374. .responseTimestamp = TimestampFromMsgId(response.outerMsgId),
  2375. .status = Status::Success,
  2376. .data = std::move(bytes),
  2377. });
  2378. }, [&](const MTPDupload_fileCdnRedirect &data) {
  2379. LOG(("Voice Chat Stream Error: fileCdnRedirect received."));
  2380. finish({
  2381. .timestampMilliseconds = time,
  2382. .responseTimestamp = TimestampFromMsgId(response.outerMsgId),
  2383. .status = Status::ResyncNeeded,
  2384. });
  2385. });
  2386. }).fail([=](const MTP::Error &error, const MTP::Response &response) {
  2387. if (error.type() == u"GROUPCALL_JOIN_MISSING"_q
  2388. || error.type() == u"GROUPCALL_FORBIDDEN"_q) {
  2389. for (const auto &[task, part] : _broadcastParts) {
  2390. _api.request(part.requestId).cancel();
  2391. }
  2392. setState(State::Joining);
  2393. rejoin();
  2394. return;
  2395. }
  2396. const auto status = (MTP::IsFloodError(error)
  2397. || error.type() == u"TIME_TOO_BIG"_q)
  2398. ? Status::NotReady
  2399. : Status::ResyncNeeded;
  2400. finish({
  2401. .timestampMilliseconds = time,
  2402. .responseTimestamp = TimestampFromMsgId(response.outerMsgId),
  2403. .status = status,
  2404. });
  2405. }).handleAllErrors().toDC(
  2406. MTP::groupCallStreamDcId(_broadcastDcId)
  2407. ).send();
  2408. _broadcastParts.emplace(raw, LoadingPart{ std::move(task), requestId });
  2409. }
  2410. void GroupCall::broadcastPartCancel(not_null<LoadPartTask*> task) {
  2411. const auto i = _broadcastParts.find(task);
  2412. if (i != end(_broadcastParts)) {
  2413. _api.request(i->second.requestId).cancel();
  2414. _broadcastParts.erase(i);
  2415. }
  2416. }
  2417. void GroupCall::mediaChannelDescriptionsStart(
  2418. std::shared_ptr<MediaChannelDescriptionsTask> task) {
  2419. const auto real = lookupReal();
  2420. if (!real || (_instanceMode == InstanceMode::None)) {
  2421. for (const auto ssrc : task->ssrcs()) {
  2422. _unresolvedSsrcs.emplace(ssrc);
  2423. }
  2424. _mediaChannelDescriptionses.emplace(std::move(task));
  2425. return;
  2426. }
  2427. if (!mediaChannelDescriptionsFill(task.get())) {
  2428. _mediaChannelDescriptionses.emplace(std::move(task));
  2429. Assert(!_unresolvedSsrcs.empty());
  2430. }
  2431. if (!_unresolvedSsrcs.empty()) {
  2432. real->resolveParticipants(base::take(_unresolvedSsrcs));
  2433. }
  2434. }
  2435. bool GroupCall::mediaChannelDescriptionsFill(
  2436. not_null<MediaChannelDescriptionsTask*> task,
  2437. Fn<bool(uint32)> resolved) {
  2438. using Channel = tgcalls::MediaChannelDescription;
  2439. auto result = false;
  2440. const auto real = lookupReal();
  2441. Assert(real != nullptr);
  2442. for (const auto ssrc : task->ssrcs()) {
  2443. const auto add = [&](
  2444. std::optional<Channel> channel,
  2445. bool screen = false) {
  2446. if (task->finishWithAdding(ssrc, std::move(channel), screen)) {
  2447. result = true;
  2448. }
  2449. };
  2450. if (const auto byAudio = real->participantPeerByAudioSsrc(ssrc)) {
  2451. add(Channel{
  2452. .type = Channel::Type::Audio,
  2453. .audioSsrc = ssrc,
  2454. });
  2455. } else if (!resolved) {
  2456. _unresolvedSsrcs.emplace(ssrc);
  2457. } else if (resolved(ssrc)) {
  2458. add(std::nullopt);
  2459. }
  2460. }
  2461. return result;
  2462. }
  2463. void GroupCall::mediaChannelDescriptionsCancel(
  2464. not_null<MediaChannelDescriptionsTask*> task) {
  2465. const auto i = _mediaChannelDescriptionses.find(task.get());
  2466. if (i != end(_mediaChannelDescriptionses)) {
  2467. _mediaChannelDescriptionses.erase(i);
  2468. }
  2469. }
  2470. void GroupCall::requestCurrentTimeStart(
  2471. std::shared_ptr<RequestCurrentTimeTask> task) {
  2472. if (!_rtmp) {
  2473. task->done(approximateServerTimeInMs());
  2474. return;
  2475. }
  2476. _requestCurrentTimes.emplace(std::move(task));
  2477. if (_requestCurrentTimeRequestId) {
  2478. return;
  2479. }
  2480. const auto finish = [=](int64 value) {
  2481. _requestCurrentTimeRequestId = 0;
  2482. for (const auto &task : base::take(_requestCurrentTimes)) {
  2483. task->done(value);
  2484. }
  2485. };
  2486. _requestCurrentTimeRequestId = _api.request(
  2487. MTPphone_GetGroupCallStreamChannels(inputCall())
  2488. ).done([=](const MTPphone_GroupCallStreamChannels &result) {
  2489. result.match([&](const MTPDphone_groupCallStreamChannels &data) {
  2490. const auto &list = data.vchannels().v;
  2491. const auto empty = list.isEmpty();
  2492. if (!empty) {
  2493. const auto &first = list.front();
  2494. first.match([&](const MTPDgroupCallStreamChannel &data) {
  2495. finish(data.vlast_timestamp_ms().v);
  2496. });
  2497. } else {
  2498. finish(0);
  2499. }
  2500. _emptyRtmp = empty;
  2501. });
  2502. }).fail([=](const MTP::Error &error) {
  2503. finish(0);
  2504. if (error.type() == u"GROUPCALL_JOIN_MISSING"_q
  2505. || error.type() == u"GROUPCALL_FORBIDDEN"_q) {
  2506. for (const auto &[task, part] : _broadcastParts) {
  2507. _api.request(part.requestId).cancel();
  2508. }
  2509. setState(State::Joining);
  2510. rejoin();
  2511. }
  2512. }).handleAllErrors().toDC(
  2513. MTP::groupCallStreamDcId(_broadcastDcId)
  2514. ).send();
  2515. }
  2516. void GroupCall::requestCurrentTimeCancel(
  2517. not_null<RequestCurrentTimeTask*> task) {
  2518. const auto i = _requestCurrentTimes.find(task.get());
  2519. if (i != end(_requestCurrentTimes)) {
  2520. _requestCurrentTimes.erase(i);
  2521. }
  2522. }
  2523. int64 GroupCall::approximateServerTimeInMs() const {
  2524. Expects(_serverTimeMs != 0);
  2525. return _serverTimeMs + (crl::now() - _serverTimeMsGotAt);
  2526. }
  2527. void GroupCall::updateRequestedVideoChannels() {
  2528. _requestedVideoChannelsUpdateScheduled = false;
  2529. const auto real = lookupReal();
  2530. if (!real || !_instance) {
  2531. return;
  2532. }
  2533. auto channels = std::vector<tgcalls::VideoChannelDescription>();
  2534. using Quality = tgcalls::VideoChannelDescription::Quality;
  2535. channels.reserve(_activeVideoTracks.size());
  2536. const auto &camera = cameraSharingEndpoint();
  2537. const auto &screen = screenSharingEndpoint();
  2538. auto mediums = 0;
  2539. auto fullcameras = 0;
  2540. auto fullscreencasts = 0;
  2541. for (const auto &[endpoint, video] : _activeVideoTracks) {
  2542. const auto &endpointId = endpoint.id;
  2543. if (endpointId == camera || endpointId == screen) {
  2544. continue;
  2545. } else if (endpointId == Data::RtmpEndpointId()) {
  2546. channels.push_back({
  2547. .endpointId = endpointId,
  2548. .minQuality = (video->quality == Group::VideoQuality::Full
  2549. ? Quality::Full
  2550. : Quality::Thumbnail),
  2551. .maxQuality = Quality::Full,
  2552. });
  2553. continue;
  2554. }
  2555. const auto participant = real->participantByEndpoint(endpointId);
  2556. const auto params = (participant && participant->ssrc)
  2557. ? participant->videoParams.get()
  2558. : nullptr;
  2559. if (!params) {
  2560. continue;
  2561. }
  2562. const auto min = (video->quality == Group::VideoQuality::Full
  2563. && endpoint.type == VideoEndpointType::Screen)
  2564. ? Quality::Full
  2565. : Quality::Thumbnail;
  2566. const auto max = (video->quality == Group::VideoQuality::Full)
  2567. ? Quality::Full
  2568. : (video->quality == Group::VideoQuality::Medium
  2569. && endpoint.type != VideoEndpointType::Screen)
  2570. ? Quality::Medium
  2571. : Quality::Thumbnail;
  2572. if (max == Quality::Full) {
  2573. if (endpoint.type == VideoEndpointType::Screen) {
  2574. ++fullscreencasts;
  2575. } else {
  2576. ++fullcameras;
  2577. }
  2578. } else if (max == Quality::Medium) {
  2579. ++mediums;
  2580. }
  2581. channels.push_back({
  2582. .audioSsrc = participant->ssrc,
  2583. .endpointId = endpointId,
  2584. .ssrcGroups = (params->camera.endpointId == endpointId
  2585. ? params->camera.ssrcGroups
  2586. : params->screen.ssrcGroups),
  2587. .minQuality = min,
  2588. .maxQuality = max,
  2589. });
  2590. }
  2591. // We limit `count(Full) * kFullAsMediumsCount + count(medium)`.
  2592. //
  2593. // Try to preserve all qualities; If not
  2594. // Try to preserve all screencasts as Full and cameras as Medium; If not
  2595. // Try to preserve all screencasts as Full; If not
  2596. // Try to preserve all cameras as Medium;
  2597. const auto mediumsCount = mediums
  2598. + (fullcameras + fullscreencasts) * kFullAsMediumsCount;
  2599. const auto downgradeSome = (mediumsCount > kMaxMediumQualities);
  2600. const auto downgradeAll = (fullscreencasts * kFullAsMediumsCount)
  2601. > kMaxMediumQualities;
  2602. if (downgradeSome) {
  2603. for (auto &channel : channels) {
  2604. if (channel.maxQuality == Quality::Full) {
  2605. const auto camera = (channel.minQuality != Quality::Full);
  2606. if (camera) {
  2607. channel.maxQuality = Quality::Medium;
  2608. } else if (downgradeAll) {
  2609. channel.maxQuality
  2610. = channel.minQuality
  2611. = Quality::Thumbnail;
  2612. --fullscreencasts;
  2613. }
  2614. }
  2615. }
  2616. mediums += fullcameras;
  2617. fullcameras = 0;
  2618. if (downgradeAll) {
  2619. fullscreencasts = 0;
  2620. }
  2621. }
  2622. if (mediums > kMaxMediumQualities) {
  2623. for (auto &channel : channels) {
  2624. if (channel.maxQuality == Quality::Medium) {
  2625. channel.maxQuality = Quality::Thumbnail;
  2626. }
  2627. }
  2628. }
  2629. _instance->setRequestedVideoChannels(std::move(channels));
  2630. }
  2631. void GroupCall::updateRequestedVideoChannelsDelayed() {
  2632. if (_requestedVideoChannelsUpdateScheduled) {
  2633. return;
  2634. }
  2635. _requestedVideoChannelsUpdateScheduled = true;
  2636. crl::on_main(this, [=] {
  2637. if (_requestedVideoChannelsUpdateScheduled) {
  2638. updateRequestedVideoChannels();
  2639. }
  2640. });
  2641. }
  2642. void GroupCall::fillActiveVideoEndpoints() {
  2643. const auto real = lookupReal();
  2644. Assert(real != nullptr);
  2645. if (_rtmp) {
  2646. _videoIsWorking = true;
  2647. markEndpointActive({
  2648. VideoEndpointType::Screen,
  2649. _peer,
  2650. Data::RtmpEndpointId(),
  2651. }, true, false);
  2652. updateRequestedVideoChannels();
  2653. return;
  2654. }
  2655. const auto me = real->participantByPeer(joinAs());
  2656. if (me && me->videoJoined) {
  2657. _videoIsWorking = true;
  2658. } else {
  2659. _videoIsWorking = false;
  2660. toggleVideo(false);
  2661. toggleScreenSharing(std::nullopt);
  2662. }
  2663. const auto &large = _videoEndpointLarge.current();
  2664. auto largeFound = false;
  2665. auto endpoints = _activeVideoTracks | ranges::views::transform([](
  2666. const auto &pair) {
  2667. return pair.first;
  2668. });
  2669. auto removed = base::flat_set<VideoEndpoint>(
  2670. begin(endpoints),
  2671. end(endpoints));
  2672. const auto feedOne = [&](VideoEndpoint endpoint, bool paused) {
  2673. if (endpoint.empty()) {
  2674. return;
  2675. } else if (endpoint == large) {
  2676. largeFound = true;
  2677. }
  2678. if (removed.remove(endpoint)) {
  2679. markTrackPaused(endpoint, paused);
  2680. } else {
  2681. markEndpointActive(std::move(endpoint), true, paused);
  2682. }
  2683. };
  2684. using Type = VideoEndpointType;
  2685. for (const auto &participant : real->participants()) {
  2686. const auto camera = GetCameraEndpoint(participant.videoParams);
  2687. if (camera != _cameraEndpoint
  2688. && camera != _screenEndpoint
  2689. && participant.peer != joinAs()) {
  2690. const auto paused = IsCameraPaused(participant.videoParams);
  2691. feedOne({ Type::Camera, participant.peer, camera }, paused);
  2692. }
  2693. const auto screen = GetScreenEndpoint(participant.videoParams);
  2694. if (screen != _cameraEndpoint
  2695. && screen != _screenEndpoint
  2696. && participant.peer != joinAs()) {
  2697. const auto paused = IsScreenPaused(participant.videoParams);
  2698. feedOne({ Type::Screen, participant.peer, screen }, paused);
  2699. }
  2700. }
  2701. feedOne(
  2702. { Type::Camera, joinAs(), cameraSharingEndpoint() },
  2703. isCameraPaused());
  2704. feedOne(
  2705. { Type::Screen, joinAs(), screenSharingEndpoint() },
  2706. isScreenPaused());
  2707. if (large && !largeFound) {
  2708. setVideoEndpointLarge({});
  2709. }
  2710. for (const auto &endpoint : removed) {
  2711. markEndpointActive(endpoint, false, false);
  2712. }
  2713. updateRequestedVideoChannels();
  2714. }
  2715. void GroupCall::updateInstanceMuteState() {
  2716. Expects(_instance != nullptr);
  2717. const auto state = muted();
  2718. _instance->setIsMuted(state != MuteState::Active
  2719. && state != MuteState::PushToTalk);
  2720. }
  2721. void GroupCall::updateInstanceVolumes() {
  2722. const auto real = lookupReal();
  2723. if (!real) {
  2724. return;
  2725. }
  2726. if (_rtmp) {
  2727. const auto value = _rtmpVolume / float64(Group::kDefaultVolume);
  2728. _instance->setVolume(1, value);
  2729. } else {
  2730. const auto &participants = real->participants();
  2731. for (const auto &participant : participants) {
  2732. updateInstanceVolume(std::nullopt, participant);
  2733. }
  2734. }
  2735. }
  2736. void GroupCall::updateInstanceVolume(
  2737. const std::optional<Data::GroupCallParticipant> &was,
  2738. const Data::GroupCallParticipant &now) {
  2739. const auto nonDefault = now.mutedByMe
  2740. || (now.volume != Group::kDefaultVolume);
  2741. const auto volumeChanged = was
  2742. ? (was->volume != now.volume || was->mutedByMe != now.mutedByMe)
  2743. : nonDefault;
  2744. const auto additionalSsrc = GetAdditionalAudioSsrc(now.videoParams);
  2745. const auto set = now.ssrc
  2746. && (volumeChanged || (was && was->ssrc != now.ssrc));
  2747. const auto additionalSet = additionalSsrc
  2748. && (volumeChanged
  2749. || (was && (GetAdditionalAudioSsrc(was->videoParams)
  2750. != additionalSsrc)));
  2751. const auto localVolume = now.mutedByMe
  2752. ? 0.
  2753. : (now.volume / float64(Group::kDefaultVolume));
  2754. if (set) {
  2755. _instance->setVolume(now.ssrc, localVolume);
  2756. }
  2757. if (additionalSet) {
  2758. _instance->setVolume(additionalSsrc, localVolume);
  2759. }
  2760. }
  2761. void GroupCall::audioLevelsUpdated(const tgcalls::GroupLevelsUpdate &data) {
  2762. Expects(!data.updates.empty());
  2763. auto check = false;
  2764. auto checkNow = false;
  2765. const auto now = crl::now();
  2766. const auto meMuted = [&] {
  2767. const auto state = muted();
  2768. return (state != MuteState::Active)
  2769. && (state != MuteState::PushToTalk);
  2770. };
  2771. for (const auto &[ssrcOrZero, value] : data.updates) {
  2772. const auto ssrc = ssrcOrZero ? ssrcOrZero : _joinState.ssrc;
  2773. if (!ssrc) {
  2774. continue;
  2775. }
  2776. const auto level = value.level;
  2777. const auto voice = value.voice;
  2778. const auto me = (ssrc == _joinState.ssrc);
  2779. const auto ignore = me && meMuted();
  2780. _levelUpdates.fire(LevelUpdate{
  2781. .ssrc = ssrc,
  2782. .value = ignore ? 0.f : level,
  2783. .voice = (!ignore && voice),
  2784. .me = me,
  2785. });
  2786. if (level <= kSpeakLevelThreshold) {
  2787. continue;
  2788. }
  2789. if (me
  2790. && voice
  2791. && (!_lastSendProgressUpdate
  2792. || _lastSendProgressUpdate + kUpdateSendActionEach < now)) {
  2793. _lastSendProgressUpdate = now;
  2794. _peer->session().sendProgressManager().update(
  2795. _history,
  2796. Api::SendProgressType::Speaking);
  2797. }
  2798. check = true;
  2799. const auto i = _lastSpoke.find(ssrc);
  2800. if (i == _lastSpoke.end()) {
  2801. _lastSpoke.emplace(ssrc, Data::LastSpokeTimes{
  2802. .anything = now,
  2803. .voice = voice ? now : 0,
  2804. });
  2805. checkNow = true;
  2806. } else {
  2807. if ((i->second.anything + kCheckLastSpokeInterval / 3 <= now)
  2808. || (voice
  2809. && i->second.voice + kCheckLastSpokeInterval / 3 <= now)) {
  2810. checkNow = true;
  2811. }
  2812. i->second.anything = now;
  2813. if (voice) {
  2814. i->second.voice = now;
  2815. }
  2816. }
  2817. }
  2818. if (checkNow) {
  2819. checkLastSpoke();
  2820. } else if (check && !_lastSpokeCheckTimer.isActive()) {
  2821. _lastSpokeCheckTimer.callEach(kCheckLastSpokeInterval / 2);
  2822. }
  2823. }
  2824. void GroupCall::checkLastSpoke() {
  2825. const auto real = lookupReal();
  2826. if (!real) {
  2827. return;
  2828. }
  2829. constexpr auto kKeepInListFor = kCheckLastSpokeInterval * 2;
  2830. static_assert(Data::GroupCall::kSoundStatusKeptFor
  2831. <= kKeepInListFor - (kCheckLastSpokeInterval / 3));
  2832. auto hasRecent = false;
  2833. const auto now = crl::now();
  2834. auto list = base::take(_lastSpoke);
  2835. for (auto i = list.begin(); i != list.end();) {
  2836. const auto &[ssrc, when] = *i;
  2837. if (when.anything + kKeepInListFor >= now) {
  2838. hasRecent = true;
  2839. ++i;
  2840. } else {
  2841. i = list.erase(i);
  2842. }
  2843. // Ignore my levels from microphone if I'm already muted.
  2844. if (ssrc != _joinState.ssrc
  2845. || muted() == MuteState::Active
  2846. || muted() == MuteState::PushToTalk) {
  2847. real->applyLastSpoke(ssrc, when, now);
  2848. } else {
  2849. real->applyLastSpoke(ssrc, { crl::time(), crl::time() }, now);
  2850. }
  2851. }
  2852. _lastSpoke = std::move(list);
  2853. if (!hasRecent) {
  2854. _lastSpokeCheckTimer.cancel();
  2855. } else if (!_lastSpokeCheckTimer.isActive()) {
  2856. _lastSpokeCheckTimer.callEach(kCheckLastSpokeInterval / 3);
  2857. }
  2858. }
  2859. void GroupCall::checkJoined() {
  2860. if (state() != State::Connecting || !_id || !_joinState.ssrc) {
  2861. return;
  2862. }
  2863. auto sources = QVector<MTPint>(1, MTP_int(_joinState.ssrc));
  2864. if (_screenJoinState.ssrc) {
  2865. sources.push_back(MTP_int(_screenJoinState.ssrc));
  2866. }
  2867. _api.request(MTPphone_CheckGroupCall(
  2868. inputCall(),
  2869. MTP_vector<MTPint>(std::move(sources))
  2870. )).done([=](const MTPVector<MTPint> &result) {
  2871. if (!ranges::contains(result.v, MTP_int(_joinState.ssrc))) {
  2872. LOG(("Call Info: Rejoin after no my ssrc in checkGroupCall."));
  2873. _joinState.nextActionPending = true;
  2874. checkNextJoinAction();
  2875. } else {
  2876. if (state() == State::Connecting) {
  2877. _checkJoinedTimer.callOnce(kCheckJoinedTimeout);
  2878. }
  2879. if (_screenJoinState.ssrc
  2880. && !ranges::contains(
  2881. result.v,
  2882. MTP_int(_screenJoinState.ssrc))) {
  2883. LOG(("Call Info: "
  2884. "Screen rejoin after _screenSsrc not found."));
  2885. _screenJoinState.nextActionPending = true;
  2886. checkNextJoinAction();
  2887. }
  2888. }
  2889. }).fail([=](const MTP::Error &error) {
  2890. LOG(("Call Info: Full rejoin after error '%1' in checkGroupCall."
  2891. ).arg(error.type()));
  2892. rejoin();
  2893. }).send();
  2894. }
  2895. void GroupCall::setInstanceConnected(
  2896. tgcalls::GroupNetworkState networkState) {
  2897. const auto inTransit = networkState.isTransitioningFromBroadcastToRtc;
  2898. const auto instanceState = !networkState.isConnected
  2899. ? InstanceState::Disconnected
  2900. : inTransit
  2901. ? InstanceState::TransitionToRtc
  2902. : InstanceState::Connected;
  2903. const auto connected = (instanceState != InstanceState::Disconnected);
  2904. if (_instanceState.current() == instanceState
  2905. && _instanceTransitioning == inTransit) {
  2906. return;
  2907. }
  2908. const auto nowCanSpeak = connected
  2909. && _instanceTransitioning
  2910. && !inTransit
  2911. && (muted() == MuteState::Muted);
  2912. _instanceTransitioning = inTransit;
  2913. _instanceState = instanceState;
  2914. if (state() == State::Connecting && connected) {
  2915. setState(State::Joined);
  2916. } else if (state() == State::Joined && !connected) {
  2917. setState(State::Connecting);
  2918. }
  2919. if (nowCanSpeak) {
  2920. notifyAboutAllowedToSpeak();
  2921. }
  2922. if (!_hadJoinedState && state() == State::Joined) {
  2923. checkFirstTimeJoined();
  2924. }
  2925. }
  2926. void GroupCall::setScreenInstanceConnected(
  2927. tgcalls::GroupNetworkState networkState) {
  2928. const auto inTransit = networkState.isTransitioningFromBroadcastToRtc;
  2929. const auto screenInstanceState = !networkState.isConnected
  2930. ? InstanceState::Disconnected
  2931. : inTransit
  2932. ? InstanceState::TransitionToRtc
  2933. : InstanceState::Connected;
  2934. if (_screenInstanceState.current() == screenInstanceState) {
  2935. return;
  2936. }
  2937. _screenInstanceState = screenInstanceState;
  2938. }
  2939. void GroupCall::checkFirstTimeJoined() {
  2940. if (_hadJoinedState || state() != State::Joined) {
  2941. return;
  2942. }
  2943. _hadJoinedState = true;
  2944. applyGlobalShortcutChanges();
  2945. _delegate->groupCallPlaySound(Delegate::GroupCallSound::Started);
  2946. }
  2947. void GroupCall::notifyAboutAllowedToSpeak() {
  2948. if (!_hadJoinedState) {
  2949. return;
  2950. }
  2951. _delegate->groupCallPlaySound(
  2952. Delegate::GroupCallSound::AllowedToSpeak);
  2953. _allowedToSpeakNotifications.fire({});
  2954. }
  2955. void GroupCall::setInstanceMode(InstanceMode mode) {
  2956. Expects(_instance != nullptr);
  2957. _instanceMode = mode;
  2958. using Mode = tgcalls::GroupConnectionMode;
  2959. _instance->setConnectionMode([&] {
  2960. switch (_instanceMode) {
  2961. case InstanceMode::None: return Mode::GroupConnectionModeNone;
  2962. case InstanceMode::Rtc: return Mode::GroupConnectionModeRtc;
  2963. case InstanceMode::Stream: return Mode::GroupConnectionModeBroadcast;
  2964. }
  2965. Unexpected("Mode in GroupCall::setInstanceMode.");
  2966. }(), true, _rtmp);
  2967. }
  2968. void GroupCall::setScreenInstanceMode(InstanceMode mode) {
  2969. Expects(_screenInstance != nullptr);
  2970. _screenInstanceMode = mode;
  2971. using Mode = tgcalls::GroupConnectionMode;
  2972. _screenInstance->setConnectionMode([&] {
  2973. switch (_screenInstanceMode) {
  2974. case InstanceMode::None: return Mode::GroupConnectionModeNone;
  2975. case InstanceMode::Rtc: return Mode::GroupConnectionModeRtc;
  2976. case InstanceMode::Stream: return Mode::GroupConnectionModeBroadcast;
  2977. }
  2978. Unexpected("Mode in GroupCall::setInstanceMode.");
  2979. }(), true, false);
  2980. }
  2981. void GroupCall::maybeSendMutedUpdate(MuteState previous) {
  2982. // Send Active <-> !Active or ForceMuted <-> RaisedHand changes.
  2983. const auto now = muted();
  2984. if ((previous == MuteState::Active && now == MuteState::Muted)
  2985. || (now == MuteState::Active
  2986. && (previous == MuteState::Muted
  2987. || previous == MuteState::PushToTalk))) {
  2988. sendSelfUpdate(SendUpdateType::Mute);
  2989. } else if ((now == MuteState::ForceMuted
  2990. && previous == MuteState::RaisedHand)
  2991. || (now == MuteState::RaisedHand
  2992. && previous == MuteState::ForceMuted)) {
  2993. sendSelfUpdate(SendUpdateType::RaiseHand);
  2994. }
  2995. }
  2996. void GroupCall::sendPendingSelfUpdates() {
  2997. if ((state() != State::Connecting && state() != State::Joined)
  2998. || _selfUpdateRequestId) {
  2999. return;
  3000. }
  3001. const auto updates = {
  3002. SendUpdateType::Mute,
  3003. SendUpdateType::RaiseHand,
  3004. SendUpdateType::CameraStopped,
  3005. SendUpdateType::CameraPaused,
  3006. SendUpdateType::ScreenPaused,
  3007. };
  3008. for (const auto type : updates) {
  3009. if (type == SendUpdateType::ScreenPaused
  3010. && _screenJoinState.action != JoinAction::None) {
  3011. continue;
  3012. }
  3013. if (_pendingSelfUpdates & type) {
  3014. _pendingSelfUpdates &= ~type;
  3015. sendSelfUpdate(type);
  3016. return;
  3017. }
  3018. }
  3019. }
  3020. void GroupCall::sendSelfUpdate(SendUpdateType type) {
  3021. if ((state() != State::Connecting && state() != State::Joined)
  3022. || _selfUpdateRequestId) {
  3023. _pendingSelfUpdates |= type;
  3024. return;
  3025. }
  3026. using Flag = MTPphone_EditGroupCallParticipant::Flag;
  3027. _selfUpdateRequestId = _api.request(MTPphone_EditGroupCallParticipant(
  3028. MTP_flags((type == SendUpdateType::RaiseHand)
  3029. ? Flag::f_raise_hand
  3030. : (type == SendUpdateType::CameraStopped)
  3031. ? Flag::f_video_stopped
  3032. : (type == SendUpdateType::CameraPaused)
  3033. ? Flag::f_video_paused
  3034. : (type == SendUpdateType::ScreenPaused)
  3035. ? Flag::f_presentation_paused
  3036. : Flag::f_muted),
  3037. inputCall(),
  3038. joinAs()->input,
  3039. MTP_bool(muted() != MuteState::Active),
  3040. MTP_int(100000), // volume
  3041. MTP_bool(muted() == MuteState::RaisedHand),
  3042. MTP_bool(!isSharingCamera()),
  3043. MTP_bool(isCameraPaused()),
  3044. MTP_bool(isScreenPaused())
  3045. )).done([=](const MTPUpdates &result) {
  3046. _selfUpdateRequestId = 0;
  3047. _peer->session().api().applyUpdates(result);
  3048. sendPendingSelfUpdates();
  3049. }).fail([=](const MTP::Error &error) {
  3050. _selfUpdateRequestId = 0;
  3051. if (error.type() == u"GROUPCALL_FORBIDDEN"_q) {
  3052. LOG(("Call Info: Rejoin after error '%1' in editGroupCallMember."
  3053. ).arg(error.type()));
  3054. rejoin();
  3055. }
  3056. }).send();
  3057. }
  3058. void GroupCall::pinVideoEndpoint(VideoEndpoint endpoint) {
  3059. _videoEndpointPinned = false;
  3060. if (endpoint) {
  3061. setVideoEndpointLarge(std::move(endpoint));
  3062. _videoEndpointPinned = true;
  3063. }
  3064. }
  3065. void GroupCall::showVideoEndpointLarge(VideoEndpoint endpoint) {
  3066. if (_videoEndpointLarge.current() == endpoint) {
  3067. return;
  3068. }
  3069. _videoEndpointPinned = false;
  3070. setVideoEndpointLarge(std::move(endpoint));
  3071. _videoLargeTillTime = crl::now() + kFixManualLargeVideoDuration;
  3072. }
  3073. void GroupCall::setVideoEndpointLarge(VideoEndpoint endpoint) {
  3074. if (!endpoint) {
  3075. _videoEndpointPinned = false;
  3076. }
  3077. _videoEndpointLarge = endpoint;
  3078. }
  3079. void GroupCall::requestVideoQuality(
  3080. const VideoEndpoint &endpoint,
  3081. Group::VideoQuality quality) {
  3082. if (!endpoint) {
  3083. return;
  3084. }
  3085. const auto i = _activeVideoTracks.find(endpoint);
  3086. if (i == end(_activeVideoTracks) || i->second->quality == quality) {
  3087. return;
  3088. }
  3089. i->second->quality = quality;
  3090. updateRequestedVideoChannelsDelayed();
  3091. }
  3092. void GroupCall::toggleMute(const Group::MuteRequest &data) {
  3093. if (_rtmp) {
  3094. _rtmpVolume = data.mute ? 0 : Group::kDefaultVolume;
  3095. updateInstanceVolumes();
  3096. } else if (data.locallyOnly) {
  3097. applyParticipantLocally(data.peer, data.mute, std::nullopt);
  3098. } else {
  3099. editParticipant(data.peer, data.mute, std::nullopt);
  3100. }
  3101. }
  3102. void GroupCall::changeVolume(const Group::VolumeRequest &data) {
  3103. if (_rtmp) {
  3104. _rtmpVolume = data.volume;
  3105. updateInstanceVolumes();
  3106. } else if (data.locallyOnly) {
  3107. applyParticipantLocally(data.peer, false, data.volume);
  3108. } else {
  3109. editParticipant(data.peer, false, data.volume);
  3110. }
  3111. }
  3112. void GroupCall::editParticipant(
  3113. not_null<PeerData*> participantPeer,
  3114. bool mute,
  3115. std::optional<int> volume) {
  3116. const auto participant = LookupParticipant(_peer, _id, participantPeer);
  3117. if (!participant) {
  3118. return;
  3119. }
  3120. applyParticipantLocally(participantPeer, mute, volume);
  3121. using Flag = MTPphone_EditGroupCallParticipant::Flag;
  3122. const auto flags = Flag::f_muted
  3123. | (volume.has_value() ? Flag::f_volume : Flag(0));
  3124. _api.request(MTPphone_EditGroupCallParticipant(
  3125. MTP_flags(flags),
  3126. inputCall(),
  3127. participantPeer->input,
  3128. MTP_bool(mute),
  3129. MTP_int(std::clamp(volume.value_or(0), 1, Group::kMaxVolume)),
  3130. MTPBool(), // raise_hand
  3131. MTPBool(), // video_muted
  3132. MTPBool(), // video_paused
  3133. MTPBool() // presentation_paused
  3134. )).done([=](const MTPUpdates &result) {
  3135. _peer->session().api().applyUpdates(result);
  3136. }).fail([=](const MTP::Error &error) {
  3137. if (error.type() == u"GROUPCALL_FORBIDDEN"_q) {
  3138. LOG(("Call Info: Rejoin after error '%1' in editGroupCallMember."
  3139. ).arg(error.type()));
  3140. rejoin();
  3141. }
  3142. }).send();
  3143. }
  3144. std::variant<int, not_null<UserData*>> GroupCall::inviteUsers(
  3145. const std::vector<not_null<UserData*>> &users) {
  3146. const auto real = lookupReal();
  3147. if (!real) {
  3148. return 0;
  3149. }
  3150. const auto owner = &_peer->owner();
  3151. auto count = 0;
  3152. auto slice = QVector<MTPInputUser>();
  3153. auto result = std::variant<int, not_null<UserData*>>(0);
  3154. slice.reserve(kMaxInvitePerSlice);
  3155. const auto sendSlice = [&] {
  3156. count += slice.size();
  3157. _api.request(MTPphone_InviteToGroupCall(
  3158. inputCall(),
  3159. MTP_vector<MTPInputUser>(slice)
  3160. )).done([=](const MTPUpdates &result) {
  3161. _peer->session().api().applyUpdates(result);
  3162. }).send();
  3163. slice.clear();
  3164. };
  3165. for (const auto &user : users) {
  3166. if (!count && slice.empty()) {
  3167. result = user;
  3168. }
  3169. owner->registerInvitedToCallUser(_id, _peer, user);
  3170. slice.push_back(user->inputUser);
  3171. if (slice.size() == kMaxInvitePerSlice) {
  3172. sendSlice();
  3173. }
  3174. }
  3175. if (count != 0 || slice.size() != 1) {
  3176. result = int(count + slice.size());
  3177. }
  3178. if (!slice.empty()) {
  3179. sendSlice();
  3180. }
  3181. return result;
  3182. }
  3183. auto GroupCall::ensureGlobalShortcutManager()
  3184. -> std::shared_ptr<GlobalShortcutManager> {
  3185. if (!_shortcutManager) {
  3186. _shortcutManager = base::CreateGlobalShortcutManager();
  3187. }
  3188. return _shortcutManager;
  3189. }
  3190. void GroupCall::applyGlobalShortcutChanges() {
  3191. auto &settings = Core::App().settings();
  3192. if (!settings.groupCallPushToTalk()
  3193. || settings.groupCallPushToTalkShortcut().isEmpty()
  3194. || !base::GlobalShortcutsAvailable()
  3195. || !base::GlobalShortcutsAllowed()) {
  3196. _shortcutManager = nullptr;
  3197. _pushToTalk = nullptr;
  3198. return;
  3199. }
  3200. ensureGlobalShortcutManager();
  3201. const auto shortcut = _shortcutManager->shortcutFromSerialized(
  3202. settings.groupCallPushToTalkShortcut());
  3203. if (!shortcut) {
  3204. settings.setGroupCallPushToTalkShortcut(QByteArray());
  3205. settings.setGroupCallPushToTalk(false);
  3206. Core::App().saveSettingsDelayed();
  3207. _shortcutManager = nullptr;
  3208. _pushToTalk = nullptr;
  3209. return;
  3210. }
  3211. if (_pushToTalk) {
  3212. if (shortcut->serialize() == _pushToTalk->serialize()) {
  3213. return;
  3214. }
  3215. _shortcutManager->stopWatching(_pushToTalk);
  3216. }
  3217. _pushToTalk = shortcut;
  3218. _shortcutManager->startWatching(_pushToTalk, [=](bool pressed) {
  3219. pushToTalk(
  3220. pressed,
  3221. Core::App().settings().groupCallPushToTalkDelay());
  3222. });
  3223. }
  3224. void GroupCall::pushToTalk(bool pressed, crl::time delay) {
  3225. if (mutedByAdmin() || muted() == MuteState::Active) {
  3226. return;
  3227. } else if (pressed) {
  3228. _pushToTalkCancelTimer.cancel();
  3229. setMuted(MuteState::PushToTalk);
  3230. } else if (delay) {
  3231. _pushToTalkCancelTimer.callOnce(delay);
  3232. } else {
  3233. pushToTalkCancel();
  3234. }
  3235. }
  3236. void GroupCall::pushToTalkCancel() {
  3237. _pushToTalkCancelTimer.cancel();
  3238. if (muted() == MuteState::PushToTalk) {
  3239. setMuted(MuteState::Muted);
  3240. }
  3241. }
  3242. void GroupCall::setNotRequireARGB32() {
  3243. _requireARGB32 = false;
  3244. }
  3245. auto GroupCall::otherParticipantStateValue() const
  3246. -> rpl::producer<Group::ParticipantState> {
  3247. return _otherParticipantStateValue.events();
  3248. }
  3249. MTPInputGroupCall GroupCall::inputCall() const {
  3250. Expects(_id != 0);
  3251. return MTP_inputGroupCall(
  3252. MTP_long(_id),
  3253. MTP_long(_accessHash));
  3254. }
  3255. void GroupCall::destroyController() {
  3256. if (_instance) {
  3257. DEBUG_LOG(("Call Info: Destroying call controller.."));
  3258. invalidate_weak_ptrs(&_instanceGuard);
  3259. _instance->stop();
  3260. crl::async([
  3261. instance = base::take(_instance),
  3262. done = _delegate->groupCallAddAsyncWaiter()
  3263. ]() mutable {
  3264. instance = nullptr;
  3265. DEBUG_LOG(("Call Info: Call controller destroyed."));
  3266. done();
  3267. });
  3268. }
  3269. }
  3270. void GroupCall::destroyScreencast() {
  3271. if (_screenInstance) {
  3272. DEBUG_LOG(("Call Info: Destroying call screen controller.."));
  3273. invalidate_weak_ptrs(&_screenInstanceGuard);
  3274. _screenInstance->stop();
  3275. crl::async([
  3276. instance = base::take(_screenInstance),
  3277. done = _delegate->groupCallAddAsyncWaiter()
  3278. ]() mutable {
  3279. instance = nullptr;
  3280. DEBUG_LOG(("Call Info: Call screen controller destroyed."));
  3281. done();
  3282. });
  3283. }
  3284. }
  3285. } // namespace Calls