1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
call.php
См. документацию.
1<?php
2
3namespace Bitrix\Im\Call;
4
5use Bitrix\Im\Call\Integration\EntityFactory;
6use Bitrix\Im\Call\Integration\EntityType;
7use Bitrix\Im\Dialog;
8use Bitrix\Im\Model\AliasTable;
9use Bitrix\Im\Model\CallTable;
10use Bitrix\Im\Model\CallUserTable;
11use Bitrix\Im\V2\Call\CallFactory;
12use Bitrix\Main\ArgumentException;
13use Bitrix\Main\Config\Option;
14use Bitrix\Main\Loader;
15use Bitrix\Main\Type\DateTime;
16use Bitrix\Main\Event;
17use Bitrix\Main\UserTable;
18use Bitrix\Main\Web\JWT;
19use Bitrix\Main\Error;
20use Bitrix\Main\ErrorCollection;
21use Bitrix\Call\Signaling;
22
23class Call
24{
25 public const
26 STATE_NEW = 'new',
27 STATE_INVITING = 'inviting',
28 STATE_ANSWERED = 'answered',
29 STATE_FINISHED = 'finished'
30 ;
31
32 public const
36 ;
37
38 public const
41 ;
42
43 public const
44 PROVIDER_PLAIN = 'Plain',
45 PROVIDER_BITRIX = 'Bitrix',
46 PROVIDER_VOXIMPLANT = 'Voximplant'
47 ;
48
49 protected $id;
50 protected $type;
51 protected int $scheme;
52 protected $initiatorId;
53 protected ?int $actionUserId = null;
54 protected $isPublic = false;
55 protected $publicId;
56 protected $provider;
57 protected $entityType;
58 protected $entityId;
59 protected $parentId;
60 protected $parentUuid;
61 protected $state;
63 protected $startDate;
65 protected $endDate;
66 protected $logUrl;
67 protected $chatId;
68 protected $uuid;
69 protected $secretKey;
70 protected $endpoint;
71
75 protected bool $enableAudioRecord = false;
76
80 protected bool $enableAiAnalyze = false;
81
83
85 protected $users;
86 protected $userData;
87
88 protected ?Signaling $signaling = null;
89
91
95 protected function __construct()
96 {
97 }
98
102 public function getId(): int
103 {
104 return (int)$this->id;
105 }
106
110 public function getType(): int
111 {
112 return (int)$this->type;
113 }
114
118 public function getScheme(): int
119 {
120 return $this->scheme;
121 }
122
126 public function getProvider(): string
127 {
128 return $this->provider;
129 }
130
134 public function getInitiatorId(): int
135 {
136 return $this->initiatorId;
137 }
138
142 public function getActionUserId(): ?int
143 {
144 return $this->actionUserId;
145 }
146
147 //region Errors
148
153 public function addErrors(array $errors): void
154 {
155 if (!$this->errorCollection instanceof ErrorCollection)
156 {
157 $this->errorCollection = new ErrorCollection();
158 }
159 $this->errorCollection->add($errors);
160 }
161
165 public function getErrors(): array
166 {
167 if ($this->errorCollection instanceof ErrorCollection)
168 {
169 return $this->errorCollection->toArray();
170 }
171
172 return [];
173 }
174
180 public function addError(Error $error): void
181 {
182 if (!$this->errorCollection instanceof ErrorCollection)
183 {
184 $this->errorCollection = new ErrorCollection();
185 }
186 $this->errorCollection->add([$error]);
187 }
188
193 public function hasErrors(): bool
194 {
195 if ($this->errorCollection instanceof ErrorCollection)
196 {
197 return !$this->errorCollection->isEmpty();
198 }
199
200 return false;
201 }
202
203 //endregion
204
205 //region Users
206
207 public function setActionUserId(int $byUserId): self
208 {
209 $this->actionUserId = $byUserId;
210 return $this;
211 }
212
217 public function getUser($userId): ?CallUser
218 {
219 $this->loadUsers();
220 return isset($this->users[$userId]) ? $this->users[$userId] : null;
221 }
222
227 public function getUsers(): array
228 {
229 $this->loadUsers();
230 return array_keys($this->users);
231 }
232
237 public function getCallUsers(): array
238 {
239 $this->loadUsers();
240 return $this->users;
241 }
242
247 public function getUserData(): array
248 {
249 if (!isset($this->userData))
250 {
251 $this->userData = $this->prepareUserData($this->getUsers());
252 }
253
254 return $this->userData;
255 }
256
262 {
264 $userRoles = $this->getUserRoles($users);
265 foreach ($userData as $userId => &$user)
266 {
267 $user['role'] = $userRoles[$userId];
268 }
269
270 return $userData;
271 }
272
279 public function getUserRoles(array $users = []): array
280 {
281 if (empty($users))
282 {
283 $users = $this->getUsers();
284 }
285 $userRoles = [];
286
287 $chatOwnerId = (int)$this->getAssociatedEntity()?->getOwnerId();
288 $chatManagerIds = $this->getAssociatedEntity()?->getManagerIds() ?? [];
289 foreach ($users as $userId)
290 {
291 $userId = (int)$userId;
292 $userRoles[$userId] = match (true)
293 {
294 $userId === $chatOwnerId => 'ADMIN',
295 in_array($userId, $chatManagerIds, true) => 'MANAGER',
296 default => 'USER',
297 };
298 }
299
300 return $userRoles;
301 }
302
309 public function hasUser($userId): bool
310 {
311 $this->loadUsers();
312 return isset($this->users[$userId]);
313 }
314
321 public function addUser($newUserId): ?CallUser
322 {
323 $this->loadUsers();
324 if ($this->users[$newUserId])
325 {
326 return $this->users[$newUserId];
327 }
328
329 if (count($this->users) >= $this->getMaxUsers())
330 {
331 return null;
332 }
333
334 $this->users[$newUserId] = CallUser::create([
335 'CALL_ID' => $this->id,
336 'USER_ID' => $newUserId,
337 'STATE' => CallUser::STATE_IDLE,
338 'LAST_SEEN' => null
339 ]);
340 $this->users[$newUserId]->save();
341 unset($this->userData);
342
343 if ($this->associatedEntity)
344 {
345 $this->associatedEntity->onUserAdd($newUserId);
346 }
347
348 return $this->users[$newUserId];
349 }
350
351 public function removeUser($userId): void
352 {
353 $this->loadUsers();
354 if($this->users[$userId])
355 {
356 CallUser::delete($this->id, $userId);
357 unset($this->users[$userId]);
358 unset($this->userData[$userId]);
359 }
360 }
361
368 public function hasActiveUsers(bool $strict = true): bool
369 {
370 $this->loadUsers();
371 $states = [];
372
373 foreach ($this->users as $user)
374 {
375 $userState = $user->getState();
376 $states[$userState] = isset($states[$userState]) ? $states[$userState] + 1 : 1;
377 }
378 if (in_array($this->type, [static::TYPE_PERMANENT, static::TYPE_LANGE]) || !$strict)
379 {
380 return $states[CallUser::STATE_READY] >= 1;
381 }
382
383 return $states[CallUser::STATE_READY] >= 2 || ($states[CallUser::STATE_READY] >= 1 && $states[CallUser::STATE_CALLING] >= 1);
384 }
385
386 //endregion
387
388 public function getSignaling(): Signaling
389 {
390 if (is_null($this->signaling))
391 {
392 $this->signaling = new Signaling($this);
393 }
394
395 return $this->signaling;
396 }
397
401 public function getAssociatedEntity(): ?Integration\AbstractEntity
402 {
404 }
405
413 {
414 $entity = EntityFactory::createEntity($this, $entityType, $entityId);
415 if (!$entity)
416 {
417 throw new ArgumentException("Unknown entity " . $entityType . "; " . $entityId);
418 }
419
420 $this->associatedEntity = $entity;
421 $this->entityType = $entityType;
422 $this->entityId = $entityId;
424 {
425 $this->chatId = $entity->getChatId();
426 }
427 $this->save();
428
429 $this->getSignaling()->sendAssociatedEntityReplaced($this->getCurrentUserId());
430 }
431
438 public function checkAccess($userId): bool
439 {
440 if (in_array($userId, $this->getUsers()))
441 {
442 return true;
443 }
445 {
446 return true;
447 }
448 return false;
449 }
450
454 public function getState(): string
455 {
456 return $this->state;
457 }
458
462 public function getParentId(): ?int
463 {
464 return $this->parentId;
465 }
466
470 public function getParentUuid(): ?string
471 {
472 return $this->parentUuid;
473 }
474
480 public function getChatId(): int
481 {
482 return $this->chatId;
483 }
484
485 public function getUuid()
486 {
487 return $this->uuid;
488 }
489
490 public function getSecretKey()
491 {
492 return $this->secretKey;
493 }
494
495 public function getEndpoint()
496 {
497 return $this->endpoint;
498 }
499
505 public function getStartDate(): DateTime
506 {
507 return $this->startDate;
508 }
509
515 public function getEndDate(): ?DateTime
516 {
517 return $this->endDate;
518 }
519
524 public function getDuration(): int
525 {
526 if ($this->startDate)
527 {
528 $end = $this->endDate ?? new DateTime();
529 return $end->getTimestamp() - $this->startDate->getTimestamp();
530 }
531 return -1;
532 }
533
538 public function autoStartRecording(): bool
539 {
540 // by settings or tariif
541 $enable = false;
542
543 Loader::includeModule('call');
544
545 if (
546 \Bitrix\Call\Integration\AI\CallAISettings::isCallAIEnable()
547 && \Bitrix\Call\Integration\AI\CallAISettings::isAutoStartRecordingEnable()
548 )
549 {
550 // by user limit
551 $minUserCount = (int)\Bitrix\Call\Integration\AI\CallAISettings::getRecordMinUsers();
552 if ($minUserCount > 0)
553 {
554 $userCount = $this->getUserCount();
555 if ($userCount && $userCount >= $minUserCount)
556 {
557 $enable = true;
558 }
559 }
560 }
561
562 return $enable;
563 }
564
565 public function getUserCount(): int
566 {
567 $userCount = 0;
568 if ($this->associatedEntity)
569 {
570 $userCount = count($this->associatedEntity->getUsers());
571 }
572 if (!$userCount && $this->id)
573 {
574 $this->loadUsers();
575 $userCount = count($this->users);
576 }
577
578 return $userCount;
579 }
580
585 public function isAudioRecordEnabled(): bool
586 {
588 }
589
594 public function enableAudioRecord(): self
595 {
596 $this->enableAudioRecord = true;
597 return $this;
598 }
599
604 public function disableAudioRecord(): self
605 {
606 $this->enableAudioRecord = false;
607 return $this;
608 }
609
614 public function isAiAnalyzeEnabled(): bool
615 {
617 }
618
623 public function enableAiAnalyze(): self
624 {
625 $this->enableAiAnalyze = true;
626 return $this;
627 }
628
633 public function disableAiAnalyze(): self
634 {
635 $this->enableAiAnalyze = false;
636 return $this;
637 }
638
639 public function inviteUsers(int $senderId, array $toUserIds, $isLegacyMobile, $video = false, $sendPush = true): void
640 {
641 $this->getSignaling()->sendInvite(
642 $senderId,
643 $toUserIds,
644 $isLegacyMobile,
645 $video,
646 $sendPush
647 );
648 }
649
650 public function sendInviteUsers(
651 int $senderId,
652 array $toUserIds,
653 $isLegacyMobile,
654 $video = false,
655 $sendPush = true,
656 string $sendMode = Signaling::MODE_ALL
657 ): void
658 {
659 foreach ($toUserIds as $toUserId)
660 {
661 $this->getSignaling()->sendCallInviteToUser(
662 $senderId,
663 $toUserId,
664 $isLegacyMobile,
665 $video,
666 $sendPush,
667 $sendMode
668 );
669 }
670 }
671
675 public function updateState($state): bool
676 {
677 if ($this->state == $state)
678 {
679 return false;
680 }
681 $prevState = $this->state;
682 $this->state = $state;
683 $updateResult = CallTable::updateState($this->getId(), $state);
684 if (!$updateResult)
685 {
686 return false;
687 }
688
689 if ($this->associatedEntity)
690 {
691 $this->associatedEntity->onStateChange($state, $prevState);
692 }
693
694 return true;
695 }
696
697 public function setLogUrl(string $logUrl): void
698 {
699 $this->logUrl = $logUrl;
700 }
701
702 public function setEndpoint($endpoint): void
703 {
704 $this->endpoint = $endpoint;
705 }
706
707 public function finish(): void
708 {
709 if ($this->endDate instanceof DateTime)
710 {
711 return;
712 }
713
714 $this->endDate = new DateTime();
715
716 if ($this->updateState(static::STATE_FINISHED))
717 {
718 $this->loadUsers();
719 foreach ($this->users as $callUser)
720 {
721 if ($callUser->getState() === CallUser::STATE_CALLING)
722 {
723 $callUser->updateState(CallUser::STATE_IDLE);
724 }
725 }
726 $this->getSignaling()->sendFinish();
727 $this->saveStat();
728
729 $this->fireCallFinishedEvent();
730 }
731 }
732
737 protected function fireCallStartedEvent(): Event
738 {
739 $event = new Event('call', 'onCallStarted', ['call' => $this]);
740 $event->send();
741
742 return $event;
743 }
744
749 protected function fireCallFinishedEvent(): Event
750 {
751 $event = new Event('call', 'onCallFinished', ['call' => $this]);
752 $event->send();
753
754 return $event;
755 }
756
757 public function getConnectionData(int $userId): ?array
758 {
759 return null;
760 }
761
762 public function toArray($currentUserId = 0, $withSecrets = false): array
763 {
764 $result = [
765 'ID' => $this->id,
766 'TYPE' => $this->type,
767 'SCHEME' => $this->scheme,
768 'INITIATOR_ID' => $this->initiatorId,
769 'IS_PUBLIC' => $this->isPublic ? 'Y' : 'N',
770 'PUBLIC_ID' => $this->publicId,
771 'PROVIDER' => $this->provider,
772 'ENTITY_TYPE' => $this->entityType,
773 'ENTITY_ID' => $this->entityId,
774 'PARENT_ID' => $this->parentId,
775 'PARENT_UUID' => $this->parentUuid,
776 'STATE' => $this->state,
777 'START_DATE' => $this->startDate,
778 'END_DATE' => $this->endDate,
779 'LOG_URL' => $this->logUrl,
780 'CHAT_ID' => $this->chatId,
781 'ASSOCIATED_ENTITY' => ($this->associatedEntity) ? $this->associatedEntity->toArray($currentUserId) : [],
782 'UUID' => $this->uuid,
783 'ENDPOINT' => $this->endpoint,
784 'RECORD_AUDIO' => $this->enableAudioRecord,
785 'AI_ANALYZE' => $this->enableAiAnalyze,
786 ];
787 if ($withSecrets)
788 {
789 $result['SECRET_KEY'] = $this->secretKey;
790 }
791
792 return $result;
793 }
794
795 public function save(): void
796 {
797 $fields = $this->toArray(0, true);
798 unset($fields['ID']);
799
800 if (!$this->id)
801 {
802 $insertResult = CallTable::add($fields);
803 $this->id = $insertResult->getId();
804 }
805 else
806 {
807 CallTable::update($this->id, $fields);
808 }
809 }
810
811 public function makeClone($newProvider = null): Call
812 {
813 $callFields = $this->toArray();
814 $callFields['ID'] = null;
815 $callFields['PUBLIC_ID'] = randString(10);
816 $callFields['STATE'] = static::STATE_NEW;
817 $callFields['PROVIDER'] = $newProvider ?? $callFields['PROVIDER'];
818 $callFields['PARENT_ID'] = $this->id;
819
820 $instance = CallFactory::createWithArray($callFields['PROVIDER'], $callFields);
821 $instance->save();
822
823 $instance->users = [];
824 foreach ($this->getUsers() as $userId)
825 {
827 'CALL_ID' => $instance->id,
828 'USER_ID' => $userId,
829 'STATE' => $instance->users[$userId] ? $instance->users[$userId]->getState() : CallUser::STATE_IDLE,
830 'LAST_SEEN' => null
831 ]);
832 $instance->users[$userId]->save();
833 }
834
835 return $instance;
836 }
837
838 public function createChildCall(
839 string $newUuid,
840 string $entityId,
841 string $newProvider = null,
842 int $scheme = null,
843 int $newInitiator = null,
844 ): Call
845 {
846 $callFields = $this->toArray();
847 $callFields['ID'] = null;
848 $callFields['UUID'] = $newUuid;
849 $callFields['PUBLIC_ID'] = randString(10);
850 $callFields['STATE'] = static::STATE_NEW;
851 $callFields['PROVIDER'] = $newProvider ?? $callFields['PROVIDER'];
852 $callFields['PARENT_ID'] = $this->id;
853 $callFields['PARENT_UUID'] = $this->uuid;
854 if ($scheme)
855 {
856 $callFields['SCHEME'] = $scheme;
857 }
858
859 if ($newInitiator)
860 {
861 $callFields['INITIATOR_ID'] = $newInitiator;
862 }
863
864 $instance = self::createCallInstance($callFields);
865
867 $instance->chatId = (int)$instance->associatedEntity->getChatId();
868 $instance->entityId = $entityId;
869
870 $instance->save();
871
872 $instance->associatedEntity->onCallCreate();
873
874 $instance->users = [];
875 foreach ($this->getUsers() as $userId)
876 {
878 'CALL_ID' => $instance->id,
879 'USER_ID' => $userId,
880 'STATE' => $instance->users[$userId] ? $instance->users[$userId]->getState() : CallUser::STATE_IDLE,
881 'LAST_SEEN' => null
882 ]);
883 $instance->users[$userId]->save();
884 }
885
886 return $instance;
887 }
888
889 protected function loadUsers(): void
890 {
891 if (is_array($this->users))
892 {
893 return;
894 }
895
896 $this->users = [];
897
898 $cursor = CallUserTable::getList(array(
899 'filter' => array(
900 '=CALL_ID' => $this->id
901 )
902 ));
903
904 while($row = $cursor->fetch())
905 {
906 $this->users[$row['USER_ID']] = CallUser::create($row);
907 }
908 }
909
910 protected function saveStat()
911 {
912 $callLength = 0;
913 if ($this->startDate instanceof DateTime && $this->endDate instanceof DateTime)
914 {
915 $callLength = $this->endDate->getTimestamp() - $this->startDate->getTimestamp();
916 }
917 $userCountChat = count($this->users);
918
919 $usersActive = 0;
920 $mobileUsers = 0;
921 $externalUsers = 0;
922 $screenShared = false;
923 $recorded = false;
924 $authTypes = UserTable::getList([
925 'select' => ['ID', 'EXTERNAL_AUTH_ID'],
926 'filter' => ['=ID' => $this->getUsers()]
927 ])->fetchAll();
928 $authTypes = array_column($authTypes, 'EXTERNAL_AUTH_ID', 'ID');
929 foreach ($this->users as $userId => $user)
930 {
931 if ($user->getLastSeen() != null)
932 {
933 $usersActive++;
934 }
935 if ($user->isUaMobile())
936 {
937 $mobileUsers++;
938 }
939 if ($authTypes[$userId] === Auth::AUTH_TYPE)
940 {
941 $externalUsers++;
942 if ($user->getFirstJoined())
943 {
944 $userLateness = $user->getFirstJoined()->getTimestamp() - $this->startDate->getTimestamp();
945 AddEventToStatFile("im", "im_call_finish", $this->id, $userLateness, "user_lateness", $userId);
946 }
947 }
948 if ($user->wasRecorded())
949 {
950 $recorded = true;
951 }
952 if ($user->wasRecorded())
953 {
954 $screenShared = true;
955 }
956 }
957
958 $chatType = null;
959 $finishStatus = 'normal';
960 if ($this->entityType === EntityType::CHAT)
961 {
962 if(is_numeric($this->entityId))
963 {
964 $chatType = 'private';
965 // private chat, entity id === other user id
966 $otherUserState =
967 $this->getUser($this->entityId)
968 ? $this->getUser($this->entityId)->getState()
969 : ''
970 ;
971
972 if ($otherUserState == CallUser::STATE_DECLINED)
973 {
974 $finishStatus = 'declined';
975 }
976 else if ($otherUserState == CallUser::STATE_BUSY)
977 {
978 $finishStatus = 'busy';
979 }
980 else if ($otherUserState == CallUser::STATE_UNAVAILABLE || $otherUserState == CallUser::STATE_CALLING)
981 {
982 $finishStatus = 'unavailable';
983 }
984 }
985 else
986 {
987 $chatId = Dialog::getChatId($this->entityId);
988 $isVideoConf = (bool)AliasTable::getRow([
989 'filter' => ['=ENTITY_ID' => $chatId, '=ENTITY_TYPE' => \Bitrix\Im\Alias::ENTITY_TYPE_VIDEOCONF]
990 ]);
991 $chatType = 'group';
992 }
993 }
994
995 if ($callLength > 30 && $finishStatus === 'normal')
996 {
998 }
999
1000 AddEventToStatFile("im", "im_call_finish", $this->id, $userCountChat, "user_count_chat", 0);
1001 AddEventToStatFile("im", "im_call_finish", $this->id, $usersActive, "user_count_call", 0);
1002 AddEventToStatFile("im", "im_call_finish", $this->id, $mobileUsers, "user_count_mobile", 0);
1003 AddEventToStatFile("im", "im_call_finish", $this->id, $externalUsers, "user_count_external", 0);
1004 AddEventToStatFile("im", "im_call_finish", $this->id, $callLength, "call_length", 0);
1005 AddEventToStatFile("im", "im_call_finish", $this->id, ($screenShared ? "Y" : "N"), "screen_shared", 0);
1006 AddEventToStatFile("im", "im_call_finish", $this->id, ($recorded ? "Y" : "N"), "recorded", 0);
1007 if($chatType)
1008 {
1009 AddEventToStatFile("im","im_call_finish", $this->id, $chatType, "chat_type", 0);
1010 }
1011 if (isset($isVideoConf))
1012 {
1013 AddEventToStatFile("im","im_call_finish", $this->id, ($isVideoConf ? "Y" : "N"), "is_videoconf", 0);
1014 }
1015 AddEventToStatFile("im","im_call_finish", $this->id, $finishStatus, "status", 0);
1016 }
1017
1018 public static function isFeedbackAllowed(): bool
1019 {
1020 if (Loader::includeModule('bitrix24'))
1021 {
1022 return \CBitrix24::getPortalZone() == 'ru';
1023 }
1024
1025 return Option::get('im', 'allow_call_feedback', 'N') === 'Y';
1026 }
1027
1028 public function getMaxUsers(): int
1029 {
1030 return self::getMaxParticipants();
1031 }
1032
1033 public function getLogToken(int $userId = 0, int $ttl = 3600) : string
1034 {
1035 $userId = $userId ?: $this->getCurrentUserId();
1036 if(!$userId)
1037 {
1038 return '';
1039 }
1040
1041 if (Loader::includeModule("bitrix24") && defined('BX24_HOST_NAME'))
1042 {
1043 $portalId = BX24_HOST_NAME;
1044 }
1045 else if (defined('IM_CALL_LOG_HOST'))
1046 {
1047 $portalId = \IM_CALL_LOG_HOST;
1048 }
1049 else
1050 {
1051 return '';
1052 }
1053
1054 $secret = Option::get('im', 'call_log_secret');
1055 if ($secret == '')
1056 {
1057 return '';
1058 }
1059
1060 return JWT::encode(
1061 [
1062 'prt' => $portalId,
1063 'call' => $this->getId(),
1064 'usr' => $userId,
1065 'exp' => (new DateTime())->getTimestamp() + $ttl
1066 ],
1067 $secret
1068 );
1069 }
1070
1071 public static function getLogService() : string
1072 {
1073 return (string)Option::get('im', 'call_log_service');
1074 }
1075
1076 public static function getMaxParticipants(): int
1077 {
1078 if (static::isCallServerEnabled())
1079 {
1080 return static::getMaxCallServerParticipants();
1081 }
1082
1083 return (int)Option::get('call', 'turn_server_max_users');
1084 }
1085
1086 public static function getMaxCallServerParticipants(): int
1087 {
1088 if (Loader::includeModule('bitrix24'))
1089 {
1090 return (int)\Bitrix\Bitrix24\Feature::getVariable('im_max_call_participants');
1091 }
1092 return (int)Option::get('im', 'call_server_max_users');
1093 }
1094
1095 public static function getMaxCallLimit(): int
1096 {
1097 if (!\Bitrix\Main\Loader::includeModule('bitrix24'))
1098 {
1099 return 0;
1100 }
1101
1102 return (int)\Bitrix\Bitrix24\Feature::getVariable('im_call_extensions_limit');
1103 }
1104
1108 public static function createWithEntity(
1109 int $type,
1110 string $provider,
1111 string $entityType,
1112 string $entityId,
1113 int $initiatorId,
1114 ?string $callUuid,
1115 ?int $scheme = null
1116 ): Call
1117 {
1118 $instance = new static();
1119 $instance->type = $type;
1120 $instance->initiatorId = $initiatorId;
1121 $instance->provider = $provider;
1122 $instance->entityType = $entityType;
1123 $instance->entityId = $entityId;
1124 $instance->uuid = !$callUuid && $provider === self::PROVIDER_PLAIN ? Util::generateUUID() : $callUuid;
1125 $instance->startDate = new DateTime();
1126 $instance->publicId = randString(10);
1127 $instance->state = static::STATE_NEW;
1128
1129 Loader::includeModule('call');
1130
1131 if ($scheme && in_array($scheme, [self::SCHEME_CLASSIC, self::SCHEME_JWT], true))
1132 {
1133 $instance->scheme = $scheme;
1134 }
1135 else
1136 {
1137 $instance->scheme = self::SCHEME_CLASSIC;
1138 if (
1139 \Bitrix\Call\Settings::isNewCallsEnabled()
1140 && (
1141 $instance->provider === self::PROVIDER_BITRIX
1142 || ($instance->provider === self::PROVIDER_PLAIN && \Bitrix\Call\Settings::isPlainCallsUseNewScheme())
1143 )
1144 )
1145 {
1146 $instance->scheme = self::SCHEME_JWT;
1147 }
1148 }
1149
1151 $instance->chatId = (int)$instance->associatedEntity->getChatId();
1152
1153 $instance->enableAudioRecord = $instance->autoStartRecording();
1154 $instance->enableAiAnalyze = $instance->enableAudioRecord;
1155
1156 $instance->save();
1157
1158 // todo: remove when the calls are supported in the mobile
1159 $instance->associatedEntity->onCallCreate();
1160
1161 $instance->users = [];
1162 foreach ($instance->associatedEntity->getUsers() as $userId)
1163 {
1165 'CALL_ID' => $instance->id,
1166 'USER_ID' => $userId,
1167 'STATE' => CallUser::STATE_UNAVAILABLE,
1168 'LAST_SEEN' => null
1169 ]);
1170 $instance->users[$userId]->save();
1171 }
1172
1173 $instance->initCall();
1174
1176
1177 return $instance;
1178 }
1179
1180 protected static function sendCreateCallEvent(Call $instance): void
1181 {
1182 $event = new Event(
1183 'im',
1184 'onCallCreate',
1185 [
1186 'id' => $instance->id,
1187 'type' => $instance->type,
1188 'scheme' => $instance->scheme,
1189 'initiatorId' => $instance->initiatorId,
1190 'provider' => $instance->provider,
1191 'entityType' => $instance->entityType,
1192 'entityId' => $instance->entityId,
1193 'startDate' => $instance->startDate,
1194 'publicId' => $instance->publicId,
1195 'chatId' => $instance->chatId,
1196 ]
1197 );
1198 $event->send();
1199 }
1200
1201 protected function initCall(): void
1202 {
1203 if (!Loader::includeModule('call'))
1204 {
1205 return;
1206 }
1207
1208 if ($this->scheme === self::SCHEME_JWT)
1209 {
1210 return;
1211 }
1212
1213 $this->fireCallStartedEvent();
1214 }
1215
1222 public static function createWithArray(array $fields): Call
1223 {
1225
1226 $instance->initCall();
1227
1228 return $instance;
1229 }
1230
1237 public static function createCallInstance(array $fields): Call
1238 {
1239 $instance = new static();
1240
1241 $instance->id = $fields['ID'];
1242 $instance->type = (int)$fields['TYPE'];
1243 $instance->initiatorId = (int)$fields['INITIATOR_ID'];
1244 $instance->isPublic = $fields['IS_PUBLIC'];
1245 $instance->publicId = $fields['PUBLIC_ID'];
1246 $instance->provider = $fields['PROVIDER'];
1247 $instance->entityType = $fields['ENTITY_TYPE'];
1248 $instance->entityId = $fields['ENTITY_ID'];
1249 $instance->startDate = isset($fields['START_DATE']) && $fields['START_DATE'] instanceof DateTime ? $fields['START_DATE'] : null;
1250 $instance->endDate = isset($fields['END_DATE']) && $fields['END_DATE'] instanceof DateTime ? $fields['END_DATE'] : null;
1251 $instance->parentId = (int)$fields['PARENT_ID'] ?: null;
1252 $instance->parentUuid = $fields['PARENT_UUID'] ?: null;
1253 $instance->state = $fields['STATE'];
1254 $instance->logUrl = $fields['LOG_URL'];
1255 $instance->chatId = (int)$fields['CHAT_ID'];
1256 $instance->uuid = $fields['UUID'];
1257 $instance->secretKey = $fields['SECRET_KEY'];
1258 $instance->endpoint = $fields['ENDPOINT'];
1259
1260 $instance->scheme = self::SCHEME_CLASSIC;
1261
1262 Loader::includeModule('call');
1263
1264 if (isset($fields['SCHEME']))
1265 {
1266 $instance->scheme = (int)($fields['SCHEME'] ?: self::SCHEME_CLASSIC);
1267 }
1268 elseif (
1269 \Bitrix\Call\Settings::isNewCallsEnabled()
1270 && (
1271 $instance->provider === self::PROVIDER_BITRIX
1272 || ($instance->provider === self::PROVIDER_PLAIN && \Bitrix\Call\Settings::isPlainCallsUseNewScheme())
1273 )
1274 )
1275 {
1276 $instance->scheme = self::SCHEME_JWT;
1277 }
1278
1279 if ($instance->entityType && $instance->entityId)
1280 {
1281 $instance->associatedEntity = Integration\EntityFactory::createEntity($instance, $instance->entityType, $instance->entityId);
1282 }
1283
1284 if (isset($fields['RECORD_AUDIO']))
1285 {
1286 $instance->enableAudioRecord = ($fields['RECORD_AUDIO'] === 'Y');
1287 }
1288 else
1289 {
1290 $instance->enableAudioRecord = $instance->autoStartRecording();
1291 }
1292
1293 if (isset($fields['AI_ANALYZE']))
1294 {
1295 $instance->enableAiAnalyze = ($fields['AI_ANALYZE'] === 'Y');
1296 }
1297 else
1298 {
1299 $instance->enableAiAnalyze = $instance->enableAudioRecord;
1300 }
1301
1302 return $instance;
1303 }
1304
1305 public static function loadWithId($id): ?Call
1306 {
1307 $row = CallTable::getRowById($id);
1308 if (is_array($row))
1309 {
1310 return static::createWithArray($row);
1311 }
1312
1313 return null;
1314 }
1315
1316 public static function loadWithUuid($uuid): ?Call
1317 {
1318 $row = CallTable::getList([
1319 'select' => ['*'],
1320 'filter' => ['=UUID' => $uuid],
1321 'limit' => 1,
1322 ])->fetch();
1323 if (is_array($row))
1324 {
1325 return static::createWithArray($row);
1326 }
1327
1328 return null;
1329 }
1330
1331 public static function isCallServerEnabled(): bool
1332 {
1333 if (!Loader::includeModule('call'))
1334 {
1335 return false;
1336 }
1337
1338 return (bool)Option::get("im", "call_server_enabled");
1339 }
1340
1341 public static function getTurnServer(): string
1342 {
1343 if (Option::get('call', 'turn_server_self') == 'Y')
1344 {
1345 $turnServer = Option::get('call', 'turn_server');
1346 }
1347 else
1348 {
1349 $region = \Bitrix\Main\Application::getInstance()->getLicense()->getRegion();
1350 if (in_array($region, ['ru', 'by', 'kz']))
1351 {
1352 $turnServer = 'turn.bitrix24.tech';
1353 }
1354 else
1355 {
1356 $turnServer = 'turn.calls.bitrix24.com';
1357 }
1358 }
1359
1360 return $turnServer;
1361 }
1362
1363 public static function isBitrixCallEnabled(): bool
1364 {
1366 }
1367
1368 public static function isIosBetaEnabled(): bool
1369 {
1370 $isEnabled = Option::get('im', 'call_beta_ios', 'N');
1371
1372 return $isEnabled === 'Y';
1373 }
1374
1375 protected function getCurrentUserId() : int
1376 {
1377 return $GLOBALS['USER'] ? (int)$GLOBALS['USER']->getId() : 0;
1378 }
1379
1380 public static function onVoximplantConferenceFinished(Event $event): void
1381 {
1382 $callId = $event->getParameter('CONFERENCE_CALL_ID');
1383 $logUrl = $event->getParameter('LOG_URL');
1384 if (!$logUrl)
1385 {
1386 return;
1387 }
1388
1389 $call = Call::loadWithId($callId);
1390 if (!$call)
1391 {
1392 return;
1393 }
1394 $call->finish();
1395 $call->setLogUrl($logUrl);
1396 $call->save();
1397 }
1398}
if(!is_object($USER)||! $USER->IsAuthorized()) $userId
Определения check_mail.php:18
const ENTITY_TYPE_VIDEOCONF
Определения alias.php:14
const AUTH_TYPE
Определения auth.php:13
Определения call.php:24
int $scheme
Определения call.php:51
Integration AbstractEntity $associatedEntity
Определения call.php:82
const TYPE_INSTANT
Определения call.php:33
addError(Error $error)
Определения call.php:180
getChatId()
Определения call.php:480
saveStat()
Определения call.php:910
getSecretKey()
Определения call.php:490
__construct()
Определения call.php:95
getStartDate()
Определения call.php:505
getUsers()
Определения call.php:227
getId()
Определения call.php:102
setActionUserId(int $byUserId)
Определения call.php:207
getUser($userId)
Определения call.php:217
$parentUuid
Определения call.php:60
getUuid()
Определения call.php:485
inviteUsers(int $senderId, array $toUserIds, $isLegacyMobile, $video=false, $sendPush=true)
Определения call.php:639
addErrors(array $errors)
Определения call.php:153
$entityType
Определения call.php:57
$users
Определения call.php:85
$startDate
Определения call.php:63
Signaling $signaling
Определения call.php:88
getUserRoles(array $users=[])
Определения call.php:279
$isPublic
Определения call.php:54
$endDate
Определения call.php:65
static createWithArray(array $fields)
Определения call.php:1222
isAudioRecordEnabled()
Определения call.php:585
updateState($state)
Определения call.php:675
getCallUsers()
Определения call.php:237
static isIosBetaEnabled()
Определения call.php:1368
static getTurnServer()
Определения call.php:1341
static isBitrixCallEnabled()
Определения call.php:1363
addUser($newUserId)
Определения call.php:321
setLogUrl(string $logUrl)
Определения call.php:697
getLogToken(int $userId=0, int $ttl=3600)
Определения call.php:1033
$logUrl
Определения call.php:66
enableAudioRecord()
Определения call.php:594
static getMaxCallServerParticipants()
Определения call.php:1086
bool $enableAudioRecord
Определения call.php:75
getMaxUsers()
Определения call.php:1028
getEndDate()
Определения call.php:515
loadUsers()
Определения call.php:889
getUserData()
Определения call.php:247
getUserCount()
Определения call.php:565
const PROVIDER_PLAIN
Определения call.php:44
static sendCreateCallEvent(Call $instance)
Определения call.php:1180
int $actionUserId
Определения call.php:53
hasActiveUsers(bool $strict=true)
Определения call.php:368
static createCallInstance(array $fields)
Определения call.php:1237
getErrors()
Определения call.php:165
$publicId
Определения call.php:55
static getLogService()
Определения call.php:1071
const STATE_ANSWERED
Определения call.php:28
getSignaling()
Определения call.php:388
$secretKey
Определения call.php:69
getEndpoint()
Определения call.php:495
static loadWithUuid($uuid)
Определения call.php:1316
getScheme()
Определения call.php:118
finish()
Определения call.php:707
getType()
Определения call.php:110
static isFeedbackAllowed()
Определения call.php:1018
createChildCall(string $newUuid, string $entityId, string $newProvider=null, int $scheme=null, int $newInitiator=null,)
Определения call.php:838
enableAiAnalyze()
Определения call.php:623
static createWithEntity(int $type, string $provider, string $entityType, string $entityId, int $initiatorId, ?string $callUuid, ?int $scheme=null)
Определения call.php:1108
getActionUserId()
Определения call.php:142
makeClone($newProvider=null)
Определения call.php:811
$provider
Определения call.php:56
sendInviteUsers(int $senderId, array $toUserIds, $isLegacyMobile, $video=false, $sendPush=true, string $sendMode=Signaling::MODE_ALL)
Определения call.php:650
toArray($currentUserId=0, $withSecrets=false)
Определения call.php:762
$type
Определения call.php:50
setAssociatedEntity($entityType, $entityId)
Определения call.php:412
initCall()
Определения call.php:1201
const SCHEME_JWT
Определения call.php:40
static getMaxParticipants()
Определения call.php:1076
static onVoximplantConferenceFinished(Event $event)
Определения call.php:1380
const PROVIDER_BITRIX
Определения call.php:45
getParentUuid()
Определения call.php:470
hasErrors()
Определения call.php:193
const TYPE_LANGE
Определения call.php:35
static getMaxCallLimit()
Определения call.php:1095
getDuration()
Определения call.php:524
removeUser($userId)
Определения call.php:351
bool $enableAiAnalyze
Определения call.php:80
setEndpoint($endpoint)
Определения call.php:702
checkAccess($userId)
Определения call.php:438
const TYPE_PERMANENT
Определения call.php:34
getParentId()
Определения call.php:462
hasUser($userId)
Определения call.php:309
isAiAnalyzeEnabled()
Определения call.php:614
fireCallFinishedEvent()
Определения call.php:749
disableAudioRecord()
Определения call.php:604
getProvider()
Определения call.php:126
ErrorCollection $errorCollection
Определения call.php:90
getAssociatedEntity()
Определения call.php:401
const STATE_FINISHED
Определения call.php:29
disableAiAnalyze()
Определения call.php:633
$entityId
Определения call.php:58
const STATE_INVITING
Определения call.php:27
fireCallStartedEvent()
Определения call.php:737
$parentId
Определения call.php:59
getConnectionData(int $userId)
Определения call.php:757
$state
Определения call.php:61
$id
Определения call.php:49
$initiatorId
Определения call.php:52
$uuid
Определения call.php:68
prepareUserData(array $users)
Определения call.php:261
$userData
Определения call.php:86
getCurrentUserId()
Определения call.php:1375
const STATE_NEW
Определения call.php:26
static loadWithId($id)
Определения call.php:1305
$chatId
Определения call.php:67
const PROVIDER_VOXIMPLANT
Определения call.php:46
getInitiatorId()
Определения call.php:134
autoStartRecording()
Определения call.php:538
$endpoint
Определения call.php:70
static isCallServerEnabled()
Определения call.php:1331
getState()
Определения call.php:454
save()
Определения call.php:795
const SCHEME_CLASSIC
Определения call.php:39
const STATE_BUSY
Определения calluser.php:16
const STATE_DECLINED
Определения calluser.php:15
static delete($callId, $userId)
Определения calluser.php:180
const STATE_IDLE
Определения calluser.php:13
const STATE_CALLING
Определения calluser.php:14
const STATE_UNAVAILABLE
Определения calluser.php:12
const STATE_READY
Определения calluser.php:17
static create(array $fields)
Определения calluser.php:28
static createEntity(Call $call, $entityType, $entityId)
Определения entityfactory.php:19
static getUsers(array $idList)
Определения util.php:10
static generateUUID()
Определения util.php:36
static getChatId($dialogId, $userId=null)
Определения dialog.php:93
static incrementCounter(string $code)
Определения limit.php:128
const COUNTER_CALL_SUCCESS
Определения limit.php:6
static getInstance()
Определения application.php:98
Определения error.php:15
Определения event.php:5
static encode($payload, $key, $alg='HS256', $keyId=null, $head=null)
Определения jwt.php:161
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$result
Определения get_property_values.php:14
$entity
$region
Определения .description.php:13
$errors
Определения iblock_catalog_edit.php:74
AddEventToStatFile($module, $action, $tag, $label, $action_type='', $user_id=null)
Определения tools.php:3976
randString($pass_len=10, $pass_chars=false)
Определения tools.php:2154
$user
Определения mysql_to_pgsql.php:33
$GLOBALS['____1690880296']
Определения license.php:1
$event
Определения prolog_after.php:141
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
$instance
Определения ps_b24_final.php:14
</p ></td >< td valign=top style='border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 2.0pt 0cm 2.0pt;height:9.0pt'>< p class=Normal align=center style='margin:0cm;margin-bottom:.0001pt;text-align:center;line-height:normal'>< a name=ТекстовоеПоле54 ></a ><?=($taxRate > count( $arTaxList) > 0) ? $taxRate."%"
Определения waybill.php:936
$error
Определения subscription_card_product.php:20
$fields
Определения yandex_run.php:501