5use Bitrix\Call\NotifyService;
19use Bitrix\Call\Settings;
20use Bitrix\Call\Integration\AI\CallAISettings;
39 Loader::includeModule(
'call');
45 $lockName = static::getLockNameWithEntityId($entityType,
$entityId, $currentUserId);
46 if (!Application::getConnection()->lock($lockName, 3))
55 $this->
addError(
new Error(
"Could not get exclusive lock",
"could_not_lock"));
60 if (!$call && $joinExisting)
67 if (CallFactory::hasUserActiveCalls((
int)
$entityId))
69 $chat = ChatFactory::getInstance()->getPrivateChat($currentUserId, (
int)
$entityId);
70 if ($chat->getId() > 0)
72 $notifyService = NotifyService::getInstance();
73 $notifyService->sendOpponentBusyMessage($currentUserId, (
int)
$entityId);
76 $this->
addError(
new Error(
'User is currently busy on another call',
'user_is_busy'));
77 Application::getConnection()->unlock($lockName);
87 if ($call->hasErrors())
90 Application::getConnection()->unlock($lockName);
94 if (!$call->getAssociatedEntity()->checkAccess($currentUserId))
98 $chat = ChatFactory::getInstance()->getPrivateChat($currentUserId, (
int)
$entityId);
99 if ($chat->getId() > 0)
101 $notifyService = NotifyService::getInstance();
102 $notifyService->sendOpponentBusyMessage($currentUserId, (
int)
$entityId);
105 $this->
addError(
new Error(
'User is currently busy on another call',
'user_is_busy'));
106 Application::getConnection()->unlock($lockName);
110 $this->
addError(
new Error(
'You can not access this call',
'access_denied'));
111 Application::getConnection()->unlock($lockName);
115 if (!$call->hasUser($currentUserId))
117 $addedUser = $call->addUser($currentUserId);
121 $this->
addError(
new Error(
"User limit reached",
"user_limit_reached"));
122 Application::getConnection()->unlock($lockName);
133 $call = CallFactory::createWithEntity(
136 entityType: $entityType,
138 initiatorId: $currentUserId,
142 catch (\Throwable $e)
145 Application::getConnection()->unlock($lockName);
149 if ($call->hasErrors())
152 Application::getConnection()->unlock($lockName);
156 if (!$call->getAssociatedEntity()->canStartCall($currentUserId))
158 $this->
addError(
new Error(
"You can not create this call",
'access_denied'));
159 Application::getConnection()->unlock($lockName);
163 $initiator = $call->getUser($currentUserId);
165 'STATE' => CallUser::STATE_READY,
174 "Can't initiate a call. Server error. (" . (
$status ??
"") .
")",
178 Application::getConnection()->unlock($lockName);
182 Application::getConnection()->unlock($lockName);
196 $users = $call->getUsers();
197 $publicChannels = Loader::includeModule(
'pull')
207 'call' => $call->toArray($initiatorId),
208 'connectionData' => $call->getConnectionData($currentUserId),
210 'userData' => $call->prepareUserData($users),
211 'publicChannels' => $publicChannels,
212 'logToken' => $call->getLogToken($currentUserId),
218 if (Settings::isAIServiceEnabled())
221 'serviceEnabled' => Settings::isAIServiceEnabled(),
222 'settingsEnabled' => CallAISettings::isEnableBySettings(),
223 'recordingMinUsers' => CallAISettings::getRecordMinUsers(),
224 'agreementAccepted' => CallAISettings::isAgreementAccepted(),
225 'tariffAvailable' => CallAISettings::isTariffAvailable(),
226 'baasAvailable' => CallAISettings::isBaasServiceHasPackage(),
245 $this->
addError(
new Error(Loc::getMessage(
"IM_REST_CALL_ERROR_CALL_NOT_FOUND"),
"call_not_found"));
252 $this->
addError(
new Error(
"You do not have access to the parent call",
"access_denied"));
256 $childCall = $parentCall->makeClone($newProvider);
257 if ($childCall->hasErrors())
259 $this->
addErrors($childCall->getErrors());
263 $initiator = $childCall->getUser($currentUserId);
264 $initiator->updateState(CallUser::STATE_READY);
265 $initiator->updateLastSeen(
new DateTime());
269 if (!$childCall->hasUser(
$userId))
271 $childCall->addUser(
$userId)?->updateState(CallUser::STATE_CALLING);
275 $users = $childCall->getUsers();
278 'call' => $childCall->toArray(),
279 'connectionData' => $childCall->getConnectionData($currentUserId),
281 'userData' => $childCall->prepareUserData($users),
282 'logToken' => $childCall->getLogToken($currentUserId)
299 return [
'success' =>
false];
302 if ($call->hasErrors())
309 if (!$call->getAssociatedEntity()->checkAccess($currentUserId))
311 $this->
addError(
new Error(
"You can not access this call",
'access_denied'));
315 if (!$call->hasUser($currentUserId))
317 $addedUser = $call->addUser($currentUserId);
320 $this->
addError(
new Error(
"User limit reached",
"user_limit_reached"));
323 $call->getSignaling()->sendUsersJoined($currentUserId, [$currentUserId]);
342 $this->
addError(
new Error(Loc::getMessage(
"IM_REST_CALL_ERROR_CALL_NOT_FOUND"),
"call_not_found"));
349 $this->
addError(
new Error(
"You do not have access to the parent call",
"access_denied"));
353 $call->setActionUserId($currentUserId)->finish();
356 'call' => $call->toArray($currentUserId),
357 'connectionData' => $call->getConnectionData($currentUserId),
358 'logToken' => $call->getLogToken($currentUserId)
372 $this->
addError(
new Error(Loc::getMessage(
"IM_REST_CALL_ERROR_CALL_NOT_FOUND"),
"call_not_found"));
379 $this->
addError(
new Error(
"You do not have access to the parent call",
"access_denied"));
396 public function inviteAction(
int $callId,
array $userIds, $video =
"N", $show =
"Y", $legacyMobile =
"N", $repeated =
"N"): ?bool
398 $isVideo = ($video ===
"Y");
399 $isShow = ($show ===
"Y");
400 $isLegacyMobile = ($legacyMobile ===
"Y");
401 $isRepeated = ($repeated ===
"Y");
402 $userIds = array_map(
'intVal', $userIds);
407 $this->
addError(
new Error(Loc::getMessage(
"IM_REST_CALL_ERROR_CALL_NOT_FOUND"),
"call_not_found"));
417 if ($call->hasErrors())
423 $call->getUser($currentUserId)->update([
425 'IS_MOBILE' => ($isLegacyMobile ?
'Y' :
'N')
428 $lockName = static::getLockNameWithCallId(
'invite', $callId);
429 if (!Application::getConnection()->lock($lockName, static::LOCK_TTL))
431 $this->
addError(
new Error(
"Could not get exclusive lock",
"could_not_lock"));
435 $this->
inviteUsers($call, $userIds, $isLegacyMobile, $isVideo, $isShow, $isRepeated);
437 Application::getConnection()->unlock($lockName);
460 else if ($isRepeated ===
false && $call->getAssociatedEntity())
465 $callUser = $call->getUser(
$userId);
466 if($callUser->getState() != CallUser::STATE_READY)
468 $callUser->updateState(CallUser::STATE_CALLING);
472 if (!empty($existingUsers))
474 $call->getAssociatedEntity()->onExistingUsersInvite($existingUsers);
477 if (
count($usersToInvite) === 0)
479 $this->
addError(
new Error(
"No users to invite",
"empty_users"));
483 $sendPush = $isRepeated !==
true;
495 $allUsers = $call->getUsers();
496 $otherUsers = array_diff($allUsers, $userIds);
497 $call->getSignaling()->sendUsersInvited(
504 if ($call->getState() === \
Bitrix\
Im\
Call\Call::STATE_NEW)
506 $call->updateState(\
Bitrix\
Im\
Call\Call::STATE_INVITING);
520 $this->
addError(
new Error(Loc::getMessage(
"IM_REST_CALL_ERROR_CALL_NOT_FOUND"),
"call_not_found"));
538 public function answerAction(
int $callId, $callInstanceId, $legacyMobile =
"N")
540 $isLegacyMobile = $legacyMobile ===
"Y";
544 $this->
addError(
new Error(Loc::getMessage(
"IM_REST_CALL_ERROR_CALL_NOT_FOUND"),
"call_not_found"));
554 $callUser = $call->getUser($currentUserId);
557 $lockName = static::getLockNameWithCallId(
'user'.$currentUserId, $callId);
558 if (!Application::getConnection()->lock($lockName, static::LOCK_TTL))
560 $this->
addError(
new Error(
"Could not get exclusive lock",
"could_not_lock"));
565 'STATE' => CallUser::STATE_READY,
567 'FIRST_JOINED' => $callUser->getFirstJoined() ?:
new DateTime(),
568 'IS_MOBILE' => $isLegacyMobile ?
'Y' :
'N',
571 Application::getConnection()->unlock($lockName);
574 $call->getSignaling()->sendAnswer($currentUserId, $callInstanceId, $isLegacyMobile);
590 $this->
addError(
new Error(Loc::getMessage(
"IM_REST_CALL_ERROR_CALL_NOT_FOUND"),
"call_not_found"));
599 $callUser = $call->getUser($currentUserId);
602 $this->
addError(
new Error(
"User is not part of the call",
"unknown_call_user"));
606 if ($callUser->getState() === CallUser::STATE_READY)
608 $this->
addError(
new Error(
"Can not decline in {$callUser->getState()} user state",
"wrong_user_state"));
612 $lockName = static::getLockNameWithCallId(
'user'.$currentUserId, $callId);
613 if (!Application::getConnection()->lock($lockName, static::LOCK_TTL))
615 $this->
addError(
new Error(
"Could not get exclusive lock",
"could_not_lock"));
621 $callUser->updateState(CallUser::STATE_BUSY);
625 $callUser->updateState(CallUser::STATE_DECLINED);
627 $callUser->updateLastSeen(
new DateTime());
629 Application::getConnection()->unlock($lockName);
631 $userIds = $call->getUsers();
632 $call->getSignaling()->sendHangup($currentUserId, $userIds, $callInstanceId,
$code);
634 if (!$call->hasActiveUsers())
636 $call->setActionUserId($currentUserId)->finish();
647 public function pingAction(
int $callId, $requestId, $retransmit =
true)
652 $this->
addError(
new Error(Loc::getMessage(
"IM_REST_CALL_ERROR_CALL_NOT_FOUND"),
"call_not_found"));
662 $callUser = $call->getUser($currentUserId);
665 $callUser->updateLastSeen(
new DateTime());
666 if ($callUser->getState() == CallUser::STATE_UNAVAILABLE)
668 $callUser->updateState(CallUser::STATE_IDLE);
673 is_bool($retransmit) && $retransmit===
true
674 || is_string($retransmit) && in_array($retransmit, [
'true',
'Y',
'1'],
true)
677 $call->getSignaling()->sendPing($currentUserId, $requestId);
693 $this->
addError(
new Error(Loc::getMessage(
"IM_REST_CALL_ERROR_CALL_NOT_FOUND"),
"call_not_found"));
703 $callUser = $call->getUser($currentUserId);
707 'SHARED_SCREEN' =>
'Y'
722 $this->
addError(
new Error(Loc::getMessage(
"IM_REST_CALL_ERROR_CALL_NOT_FOUND"),
"call_not_found"));
732 $callUser = $call->getUser($currentUserId);
750 $restart = (bool)$restart;
754 $this->
addError(
new Error(Loc::getMessage(
"IM_REST_CALL_ERROR_CALL_NOT_FOUND"),
"call_not_found"));
764 $callUser = $call->getUser($currentUserId);
767 $callUser->updateLastSeen(
new DateTime());
770 $call->getSignaling()->sendNegotiationNeeded($currentUserId,
$userId, $restart);
787 $this->
addError(
new Error(Loc::getMessage(
"IM_REST_CALL_ERROR_CALL_NOT_FOUND"),
"call_not_found"));
797 $callUser = $call->getUser($currentUserId);
800 $callUser->updateLastSeen(
new DateTime());
803 $call->getSignaling()->sendConnectionOffer($currentUserId,
$userId, $connectionId, $sdp, $userAgent);
821 $this->
addError(
new Error(Loc::getMessage(
"IM_REST_CALL_ERROR_CALL_NOT_FOUND"),
"call_not_found"));
830 $callUser = $call->getUser($currentUserId);
833 $callUser->updateLastSeen(
new DateTime());
836 $call->getSignaling()->sendConnectionAnswer($currentUserId,
$userId, $connectionId, $sdp, $userAgent);
860 $callUser = $call->getUser($currentUserId);
863 $callUser->updateLastSeen(
new DateTime());
866 $call->getSignaling()->sendIceCandidates($currentUserId,
$userId, $connectionId, $candidates);
876 public function hangupAction(
int $callId, $callInstanceId, $retransmit =
true)
881 $this->
addError(
new Error(Loc::getMessage(
"IM_REST_CALL_ERROR_CALL_NOT_FOUND"),
"call_not_found"));
891 $lockName = static::getLockNameWithCallId(
'user'.$currentUserId, $callId);
892 if (!Application::getConnection()->lock($lockName, static::LOCK_TTL))
894 $this->
addError(
new Error(
"Could not get exclusive lock",
"could_not_lock"));
898 $callUser = $call->getUser($currentUserId);
901 $callUser->updateState(CallUser::STATE_IDLE);
902 $callUser->updateLastSeen(
new DateTime());
906 is_bool($retransmit) && $retransmit===
true
907 || is_string($retransmit) && in_array($retransmit, [
'true',
'Y',
'1'],
true)
910 $userIds = $call->getUsers();
911 $call->getSignaling()->sendHangup($currentUserId, $userIds, $callInstanceId);
914 Application::getConnection()->unlock($lockName);
916 if (!$call->hasActiveUsers())
918 $call->setActionUserId($currentUserId)->finish();
932 $this->
addError(
new Error(Loc::getMessage(
"IM_REST_CALL_ERROR_CALL_NOT_FOUND"),
"call_not_found"));
938 $this->
addError(
new Error(
"You do not have access to the parent call",
"access_denied"));
942 $call->setActionUserId($currentUserId)->finish();
945 'call' => $call->toArray($currentUserId),
946 'connectionData' => $call->getConnectionData($currentUserId),
947 'logToken' => $call->getLogToken($currentUserId)
962 $this->
addError(
new Error(Loc::getMessage(
"IM_REST_CALL_ERROR_CALL_NOT_FOUND"),
"call_not_found"));
969 $this->
addError(
new Error(
"You do not have access to the call",
"access_denied"));
975 $allowedUserIds = $call->getUsers();
979 $allowedUserIds = array_filter($userIds,
function(
$userId) use ($call, $currentUserId)
985 if (empty($allowedUserIds))
987 $this->
addError(
new Error(
"Users are not part of the call",
"access_denied"));
991 return $call->prepareUserData($allowedUserIds);
1007 $this->
addError(
new Error(
"Call is not found or you do not have access to the call",
"access_denied"));
1016 $callUser = $call->getUser(
$userId);
1019 $this->
addError(
new Error(
"User is not part of the call",
"unknown_call_user"));
1023 return $callUser->toArray();
1046 AddEventToStatFile(
'im',
'call_connection', $callId, ($connectionStatus ?
'Y' :
'N'));
1051 if (!$call->checkAccess(
$userId))
1053 $this->
addError(
new Error(
"You don't have access to the call " . $call->getId() .
"; (current user id: " .
$userId .
")",
'access_denied'));
1066 return "call_entity_{$entityType}_{$chatId}";
1069 return "call_entity_{$entityType}_{$entityId}";
1075 if (is_string($callId) || is_numeric($callId))
1077 return "{$prefix}_call_{$callId}";
1089 'reportConnectionStatus' => [
if(!Loader::includeModule('messageservice')) $provider
if(!is_object($USER)||! $USER->IsAuthorized()) $userId
static getMaxParticipants()
static isCallServerEnabled()
static getCallWithId(int $id)
pingAction(int $callId, $requestId, $retransmit=true)
connectionAnswerAction(int $callId, int $userId, $connectionId, $sdp, $userAgent)
static getLockNameWithCallId(string $prefix, $callId)
iceCandidateAction(int $callId, int $userId, $connectionId, array $candidates)
negotiationNeededAction(int $callId, int $userId, $restart=false)
tryJoinCallAction($type, $provider, $entityType, $entityId)
connectionOfferAction(int $callId, int $userId, $connectionId, $sdp, $userAgent)
getUserStateAction(int $callId, int $userId=0)
inviteAction(int $callId, array $userIds, $video="N", $show="Y", $legacyMobile="N", $repeated="N")
cancelAction(int $callId)
hangupAction(int $callId, $callInstanceId, $retransmit=true)
getUsersAction(int $callId, array $userIds=[])
createChildCallAction(int $parentId, string $newProvider, array $newUsers)
checkCallAccess(\Bitrix\Im\Call\Call $call, $userId)
interruptAction(int $callId)
onStartRecordAction(int $callId)
onShareScreenAction(int $callId)
inviteUsers(\Bitrix\Im\Call\Call $call, $userIds, $isLegacyMobile, $isVideo, $isShow, $isRepeated)
static getLockNameWithEntityId(string $entityType, $entityId, $currentUserId)
answerAction(int $callId, $callInstanceId, $legacyMobile="N")
reportConnectionStatusAction(int $callId, bool $connectionStatus)
finishAction(int $callId)
createAction(int $type, string $provider, string $entityType, string $entityId, bool $joinExisting=false)
formatCallResponse(\Bitrix\Im\Call\Call $call, int $initiatorId=0, bool $isNew=false)
declineAction(int $callId, $callInstanceId, int $code=603)
static getChatId($dialogId, $userId=null)
static getPublicIds($params=[])
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
if(!is_null($config))($config as $configItem)(! $configItem->isVisible()) $code
AddEventToStatFile($module, $action, $tag, $label, $action_type='', $user_id=null)
</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."%"