@nethesis/phone-island 1.1.6 → 1.1.8-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/dist/components/AlertView/index.js +1 -1
  2. package/dist/components/AlertView/index.js.map +1 -1
  3. package/dist/components/AudioPlayerView/PlayerFooterActions.js +1 -1
  4. package/dist/components/AudioPlayerView/PlayerFooterActions.js.map +1 -1
  5. package/dist/components/AudioPlayerView/Progress.js +1 -1
  6. package/dist/components/AudioPlayerView/Progress.js.map +1 -1
  7. package/dist/components/AudioPlayerView/index.js +1 -1
  8. package/dist/components/AudioPlayerView/index.js.map +1 -1
  9. package/dist/components/Button.js +1 -1
  10. package/dist/components/Button.js.map +1 -1
  11. package/dist/components/CallView/Actions.js +1 -1
  12. package/dist/components/CallView/Actions.js.map +1 -1
  13. package/dist/components/CallView/Number.js +1 -1
  14. package/dist/components/CallView/Number.js.map +1 -1
  15. package/dist/components/CallView/index.js +1 -1
  16. package/dist/components/CallView/index.js.map +1 -1
  17. package/dist/components/ConferenceView/index.js +1 -1
  18. package/dist/components/ConferenceView/index.js.map +1 -1
  19. package/dist/components/ContactView/ContactListView.js +1 -1
  20. package/dist/components/ContactView/ContactListView.js.map +1 -1
  21. package/dist/components/ContactView/TransferActions.js +1 -1
  22. package/dist/components/ContactView/TransferActions.js.map +1 -1
  23. package/dist/components/CustomThemedTooltip.js.map +1 -1
  24. package/dist/components/Events.js +1 -1
  25. package/dist/components/Events.js.map +1 -1
  26. package/dist/components/Hangup.js +1 -1
  27. package/dist/components/Hangup.js.map +1 -1
  28. package/dist/components/Island.js +1 -1
  29. package/dist/components/Island.js.map +1 -1
  30. package/dist/components/IslandDrag.js +1 -1
  31. package/dist/components/IslandDrag.js.map +1 -1
  32. package/dist/components/IslandMotion.js +1 -1
  33. package/dist/components/IslandMotion.js.map +1 -1
  34. package/dist/components/KeypadView/Actions.js +1 -1
  35. package/dist/components/KeypadView/Actions.js.map +1 -1
  36. package/dist/components/KeypadView/index.js +1 -1
  37. package/dist/components/KeypadView/index.js.map +1 -1
  38. package/dist/components/PhysicalRecorderView/index.js +1 -1
  39. package/dist/components/PhysicalRecorderView/index.js.map +1 -1
  40. package/dist/components/RecorderView/Actions.js +1 -1
  41. package/dist/components/RecorderView/Actions.js.map +1 -1
  42. package/dist/components/SettingsView/AudioView.js +1 -1
  43. package/dist/components/SettingsView/AudioView.js.map +1 -1
  44. package/dist/components/SettingsView/MicrophoneView.js +1 -1
  45. package/dist/components/SettingsView/MicrophoneView.js.map +1 -1
  46. package/dist/components/SettingsView/ThemeView.js +1 -1
  47. package/dist/components/SettingsView/ThemeView.js.map +1 -1
  48. package/dist/components/SettingsView/VideoInputView.js +1 -1
  49. package/dist/components/SettingsView/VideoInputView.js.map +1 -1
  50. package/dist/components/SideView/hooks/useSideViewLogic.js +1 -1
  51. package/dist/components/SideView/hooks/useSideViewLogic.js.map +1 -1
  52. package/dist/components/Socket.js +1 -1
  53. package/dist/components/Socket.js.map +1 -1
  54. package/dist/components/StreamingAnswerView/index.js +1 -1
  55. package/dist/components/StreamingAnswerView/index.js.map +1 -1
  56. package/dist/components/StreamingImage/index.js +1 -1
  57. package/dist/components/StreamingImage/index.js.map +1 -1
  58. package/dist/components/StreamingUnlock/index.js +2 -0
  59. package/dist/components/StreamingUnlock/index.js.map +1 -0
  60. package/dist/components/StreamingVideo/index.js +2 -0
  61. package/dist/components/StreamingVideo/index.js.map +1 -0
  62. package/dist/components/SwitchInputView/DropdownContent.js +1 -1
  63. package/dist/components/SwitchInputView/DropdownContent.js.map +1 -1
  64. package/dist/components/SwitchInputView/Index.js +1 -1
  65. package/dist/components/TranscriptionView/TranscriptionView.js +1 -1
  66. package/dist/components/TranscriptionView/TranscriptionView.js.map +1 -1
  67. package/dist/components/TransferButton.js +1 -1
  68. package/dist/components/TransferButton.js.map +1 -1
  69. package/dist/components/VideoView/index.js +1 -1
  70. package/dist/components/VideoView/index.js.map +1 -1
  71. package/dist/components/WebRTC.js +1 -1
  72. package/dist/components/WebRTC.js.map +1 -1
  73. package/dist/events/CallEvents.js +1 -1
  74. package/dist/events/CallEvents.js.map +1 -1
  75. package/dist/events/PlayerEvents.js +1 -1
  76. package/dist/events/PlayerEvents.js.map +1 -1
  77. package/dist/events/RecorderEvents.js +1 -1
  78. package/dist/events/RecorderEvents.js.map +1 -1
  79. package/dist/events/SocketEvents.js +1 -1
  80. package/dist/events/SocketEvents.js.map +1 -1
  81. package/dist/index.css +1 -1
  82. package/dist/lib/darkTheme.js +1 -1
  83. package/dist/lib/darkTheme.js.map +1 -1
  84. package/dist/lib/devices/devices.js +1 -1
  85. package/dist/lib/devices/devices.js.map +1 -1
  86. package/dist/lib/island/island.js +1 -1
  87. package/dist/lib/island/island.js.map +1 -1
  88. package/dist/lib/phone/call.js +1 -1
  89. package/dist/lib/phone/call.js.map +1 -1
  90. package/dist/lib/phone/video.js +1 -1
  91. package/dist/lib/phone/video.js.map +1 -1
  92. package/dist/lib/storage/local_storage.js +1 -1
  93. package/dist/lib/storage/local_storage.js.map +1 -1
  94. package/dist/lib/streaming/streamingVideo.js +2 -0
  95. package/dist/lib/streaming/streamingVideo.js.map +1 -0
  96. package/dist/lib/streaming/whepPlayer.js +2 -0
  97. package/dist/lib/streaming/whepPlayer.js.map +1 -0
  98. package/dist/models/currentCall.js +1 -1
  99. package/dist/models/currentCall.js.map +1 -1
  100. package/dist/models/island.js +1 -1
  101. package/dist/models/island.js.map +1 -1
  102. package/dist/models/motions.js +1 -1
  103. package/dist/models/motions.js.map +1 -1
  104. package/dist/models/streaming.js +1 -1
  105. package/dist/models/streaming.js.map +1 -1
  106. package/dist/node_modules/@fortawesome/free-solid-svg-icons/index.mjs.js +1 -1
  107. package/dist/node_modules/@fortawesome/free-solid-svg-icons/index.mjs.js.map +1 -1
  108. package/dist/node_modules/tslib/tslib.es6.js +1 -1
  109. package/dist/node_modules/tslib/tslib.es6.js.map +1 -1
  110. package/dist/package.json.js +1 -1
  111. package/dist/public/locales/en/translation.json.js +1 -1
  112. package/dist/public/locales/it/translation.json.js +1 -1
  113. package/dist/services/user.js +1 -1
  114. package/dist/services/user.js.map +1 -1
  115. package/dist/utils/customHooks/useStreamingAspectRatio.js +2 -0
  116. package/dist/utils/customHooks/useStreamingAspectRatio.js.map +1 -0
  117. package/dist/utils/customHooks/useStreamingContentHeight.js +2 -0
  118. package/dist/utils/customHooks/useStreamingContentHeight.js.map +1 -0
  119. package/dist/utils/customHooks/useStreamingVideo.js +2 -0
  120. package/dist/utils/customHooks/useStreamingVideo.js.map +1 -0
  121. package/dist/utils/streaming/previewSize.js +2 -0
  122. package/dist/utils/streaming/previewSize.js.map +1 -0
  123. package/dist/utils/streaming/streamingUtils.js +1 -1
  124. package/dist/utils/streaming/streamingUtils.js.map +1 -1
  125. package/dist/utils/streaming/videoSource.js +2 -0
  126. package/dist/utils/streaming/videoSource.js.map +1 -0
  127. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"call.js","sources":["../../../src/lib/phone/call.ts"],"sourcesContent":["// Copyright (C) 2024 Nethesis S.r.l.\n// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport {\n callSipURI,\n hangup,\n answerWebRTC,\n muteWebRTC,\n unmuteWebRTC,\n pauseWebRTC,\n unpauseWebRTC,\n} from '../webrtc/messages'\nimport { Dispatch, store } from '../../store'\nimport { isWebRTC } from '../user/default_device'\nimport {\n blindTransfer as blindTransferRequest,\n attendedTransfer as attendedTransferRequest,\n hangupPhysical,\n answerPhysical,\n mutePhysical,\n pausePhysical,\n callPhysical,\n toggleRecord,\n hangupPhysicalRecordingCall,\n startConf,\n joinMyConf,\n endConf,\n muteUserConf,\n unmuteUserConf,\n hangupUserConf,\n forceHangup,\n} from '../../services/astproxy'\nimport dtmfAudios from '../../static/dtmf'\nimport { hangupConversation, parkConversation } from '../../services/astproxy'\nimport { eventDispatch } from '../../utils'\nimport { isEmpty } from '../../utils/genericFunctions/isEmpty'\nimport { getStreamingSourceId } from '../../utils/streaming/getStreamingSourceId'\nimport { unsubscribe } from '../../services/user'\n\n/**\n * Starts a call to a number\n * @param number The number string\n */\nexport function callNumber(number: string, sipHost: string, options: { video?: boolean } = {}) {\n const sipURI = `sip:${number}@${sipHost}`\n\n // Reset any previous operator busy state when starting a new call\n store.dispatch.island.resetOperatorBusy()\n // Save the called number for potential operator busy scenarios\n store.dispatch.island.setOperatorBusyCalledNumber(number)\n\n if (isWebRTC()) {\n callSipURI(sipURI, options)\n } else {\n callPhysical(number)\n }\n\n eventDispatch('phone-island-call-started', {})\n}\n\n/**\n * Answer incoming call\n */\nexport function answerIncomingCall() {\n if (isWebRTC()) {\n answerWebRTC()\n } else {\n answerPhysical()\n }\n // Reset operator busy completely when call is answered successfully\n store.dispatch.island.resetOperatorBusyCompletely()\n}\n\n/**\n * Hangup all the conversations of all the extensions of the current user\n */\nexport function hangupAllExtensions() {\n // Get current user endpoints\n const { conversations } = store.getState().currentUser\n // Hangup all the conversations of all extensions of the current user\n for (const extension in conversations) {\n const conversationsIds = Object.keys(conversations[extension])\n conversationsIds.forEach((id) => {\n hangupConversation({\n convid: id,\n endpointId: extension,\n })\n })\n }\n}\n\nexport function forceHangupConversation() {\n // Get current user endpoints\n const { conversations } = store.getState().currentUser\n // Hangup all the conversations of all extensions of the current user\n for (const extension in conversations) {\n const conversationsIds = Object.keys(conversations[extension])\n conversationsIds.forEach((id) => {\n forceHangup({\n convid: id,\n endpointId: extension,\n endpointType: 'extension',\n })\n })\n }\n}\n\n/**\n * Hangup current call\n */\nexport function hangupCurrentCall() {\n const { outgoing, accepted, streamingSourceNumber } = store.getState().currentCall\n const { isFromStreaming } = store.getState().island\n\n if (outgoing || accepted) {\n if (isWebRTC()) {\n hangup()\n } else {\n hangupPhysical()\n }\n store.dispatch.player.stopAudioPlayer()\n store.dispatch.currentCall.reset()\n store.dispatch.listen.reset()\n\n // If call was from a streaming source, unsubscribe and clear images\n if (isFromStreaming && streamingSourceNumber) {\n const sourceId = getStreamingSourceId(streamingSourceNumber)\n if (sourceId) {\n // Unsubscribe from streaming updates\n unsubscribe({ id: sourceId })\n .then(() => console.debug(`Unsubscribed from streaming source: ${sourceId}`))\n .catch((error) => console.error('Error unsubscribing from streaming source:', error))\n\n // Clear source images to free up memory\n store.dispatch.streaming.clearSourceImages()\n }\n }\n\n // Reset isFromStreaming flag\n store.dispatch.island.setIsFromStreaming(false)\n }\n // Reset operator busy state when call ends\n store.dispatch.island.resetOperatorBusy()\n // Caller close the call before the call is accepted\n eventDispatch('phone-island-call-ended', {})\n}\n\n/**\n * Hangup current physical recording\n */\nexport function hangupCurrentPhysicalRecording() {\n hangupPhysicalRecordingCall()\n store.dispatch.player.stopAudioPlayer()\n store.dispatch.physicalRecorder.reset()\n store.dispatch.physicalRecorder.setRecording(false)\n store.dispatch.island.setIslandView(null)\n store.dispatch.listen.reset()\n // Caller close the call before the call is accepted\n eventDispatch('phone-island-call-ended', {})\n}\n\n/**\n * Mute the current call\n */\nexport function muteCurrentCall() {\n // Check the current user default device\n if (isWebRTC()) {\n const muted = muteWebRTC()\n if (muted) {\n store.dispatch.currentCall.updateCurrentCall({\n muted: true,\n })\n }\n } else {\n mutePhysical(true)\n }\n eventDispatch('phone-island-call-muted', {})\n}\n\n/**\n * Unmute the current call\n */\nexport function unmuteCurrentCall() {\n // Check the current user default device\n if (isWebRTC()) {\n const unmuted = unmuteWebRTC()\n if (unmuted) {\n store.dispatch.currentCall.updateCurrentCall({\n muted: false,\n })\n }\n } else {\n mutePhysical(false)\n }\n eventDispatch('phone-island-call-unmuted', {})\n}\n\n/**\n * Pause the current call\n */\nexport function pauseCurrentCall() {\n // Check the current user default device\n if (isWebRTC()) {\n const paused = pauseWebRTC()\n if (paused) {\n store.dispatch.currentCall.updateCurrentCall({\n paused: true,\n })\n // Pause remote audio\n store.dispatch.player.pauseRemoteAudio()\n }\n } else {\n pausePhysical(true)\n }\n eventDispatch('phone-island-call-held', {})\n}\n\n/**\n * Unpause the current call\n */\nexport function unpauseCurrentCall() {\n // Check the current user default device\n if (isWebRTC()) {\n const unpaused = unpauseWebRTC()\n if (unpaused) {\n store.dispatch.currentCall.updateCurrentCall({\n paused: false,\n })\n // Play remote audio\n store.dispatch.player.playRemoteAudio()\n }\n } else {\n pausePhysical(false)\n }\n eventDispatch('phone-island-call-unheld', {})\n}\n\n/**\n * Transfer the current call through a blind transfer (not in use)\n */\nexport async function blindTransferFunction(number: string, endpointIdInConversation: string) {\n // Retrieve current conversation info\n const { conversationId } = store.getState().currentCall\n // Transfer the call through blind transfer\n if (conversationId && endpointIdInConversation && number) {\n return await blindTransferRequest({\n convid: conversationId,\n to: number,\n endpointId: endpointIdInConversation,\n })\n }\n}\n\n/**\n * Transfer the current call through a attended transfer\n */\nexport async function attendedTransfer(number: string) {\n // Retrieve current conversation info\n const { conversationId } = store.getState().currentCall\n const { default_device } = store.getState().currentUser\n let default_device_details = default_device?.id || default_device?.exten\n // Transfer the call through attended transfer\n if (conversationId && default_device_details && number) {\n return await attendedTransferRequest({\n convid: conversationId,\n to: number,\n endpointId: default_device_details,\n })\n }\n}\n\n/**\n * Play the dtmf audio files\n */\nexport function playDtmfAudio(key: string) {\n if (key === '*') key = 'star'\n if (key === '#') key = 'pound'\n store.dispatch.player.updateStartAudioPlayer({ src: dtmfAudios[`dtmf_${key}`] })\n}\n\n/**\n * Park the current call\n */\nexport function parkCurrentCall() {\n const conversationId = store?.getState()?.currentCall?.conversationId\n const userConversationInformations = store?.getState()?.currentUser?.conversations\n\n let parkingInformation: any = {}\n\n if (conversationId) {\n if (userConversationInformations) {\n for (const key in userConversationInformations) {\n if (userConversationInformations.hasOwnProperty(key)) {\n const conversation = userConversationInformations[key]\n if (Object.keys(conversation).length > 0) {\n parkingInformation = {\n numberParkId: key,\n idConversation: conversationId,\n }\n }\n }\n }\n }\n\n if (Object.keys(parkingInformation).length > 0) {\n if (parkingInformation?.numberParkId) {\n // If park information are not empty park call\n parkConversation({\n applicantId: parkingInformation?.numberParkId,\n convid: conversationId,\n endpointId: parkingInformation?.numberParkId,\n })\n\n store.dispatch.currentCall.setParked(true)\n\n eventDispatch('phone-island-call-parked', {})\n }\n }\n }\n}\n\nconst findFirstExtesnionNotEmpty = (data) => {\n for (const key in data) {\n if (Object.keys(data[key]).length !== 0) {\n const firstEntry: any = Object.values(data[key])[0]\n return {\n id: firstEntry.id,\n recording: firstEntry.recording,\n }\n }\n }\n return null\n}\n\nexport async function recordCurrentCall(recordingValue: boolean) {\n store.dispatch.currentCall.updateRecordingStatus(!recordingValue)\n const userConversationInformations = store?.getState()?.currentUser?.conversations\n\n const firstExtensionNotEmpty = findFirstExtesnionNotEmpty(userConversationInformations)\n\n if (!firstExtensionNotEmpty) {\n return\n } else {\n const numberToSendCall = firstExtensionNotEmpty?.id?.match(/\\/(\\d+)-/)\n const endpointId = numberToSendCall[1]\n\n const listenInformations = {\n convid: firstExtensionNotEmpty?.id?.toString(),\n endpointId: endpointId?.toString(),\n }\n\n let recordingValues = ''\n switch (firstExtensionNotEmpty?.recording) {\n case 'false':\n recordingValues = 'start_record'\n break\n case 'true':\n recordingValues = 'mute_record'\n break\n case 'mute':\n recordingValues = 'unmute_record'\n break\n default:\n recordingValues = ''\n break\n }\n\n if (listenInformations) {\n try {\n await toggleRecord(recordingValues, listenInformations)\n } catch (e) {\n console.error(e)\n return []\n }\n }\n }\n}\n\nexport async function startConference() {\n const {\n accepted,\n chSource,\n chDest,\n incoming,\n outgoing,\n incomingSocket,\n outgoingSocket,\n conversationId,\n }: any = store?.getState()?.currentCall\n const { default_device } = store.getState().currentUser\n const defaultDeviceId = default_device?.id || default_device?.exten\n let addedUserExtension = ''\n if (accepted && (incoming || incomingSocket) && !isEmpty(chSource)) {\n addedUserExtension = chSource?.callerNum\n } else if (accepted && (outgoing || outgoingSocket) && !isEmpty(chDest)) {\n addedUserExtension = chDest?.callerNum\n }\n\n if (defaultDeviceId !== '' && conversationId !== '' && addedUserExtension !== '') {\n const startConferenceInformations = {\n convid: conversationId?.toString(),\n addEndpointId: addedUserExtension?.toString(),\n ownerEndpointId: defaultDeviceId?.toString(),\n }\n\n if (startConferenceInformations) {\n try {\n const result = await startConf(startConferenceInformations)\n if (result) {\n // Set conferencing and disable pause\n store.dispatch.currentCall.updateCurrentCall({\n conferencing: true,\n paused: false,\n })\n\n eventDispatch('phone-island-call-conferenced', {})\n return true\n }\n return false\n } catch (e) {\n console.error(e)\n return false\n }\n }\n }\n return false\n}\n\nexport async function joinConference() {\n const { default_device } = store.getState().currentUser\n const defaultDeviceId = default_device?.id || default_device?.exten\n\n if (defaultDeviceId !== '') {\n const joinConferenceInformation = {\n endpointId: defaultDeviceId?.toString(),\n }\n\n if (joinConferenceInformation) {\n try {\n const result = await joinMyConf(joinConferenceInformation)\n if (result) {\n eventDispatch('phone-island-owner-conference-enter', {})\n return true\n }\n return false\n } catch (e) {\n console.error(e)\n return false\n }\n }\n }\n return false\n}\n\nexport async function endConference() {\n const { conferenceId } = store.getState().conference\n\n if (conferenceId !== '') {\n const endConferenceInformation = {\n confId: conferenceId?.toString(),\n }\n\n if (endConferenceInformation) {\n try {\n const result = await endConf(endConferenceInformation)\n if (result) {\n eventDispatch('phone-island-owner-conference-finished', {})\n return true\n }\n return false\n } catch (e) {\n console.error(e)\n return false\n }\n }\n }\n return false\n}\n\nexport async function muteUserConference(confId, userId, isAlreadyMuted) {\n if (confId === '' || userId === '') {\n return false\n }\n\n const muteUnmuteUserInformation = {\n confId: confId?.toString(),\n userId: userId?.toString(),\n }\n\n try {\n // Check if the user is already muted\n const actionFunction = isAlreadyMuted ? unmuteUserConf : muteUserConf\n const result = await actionFunction(muteUnmuteUserInformation)\n return !!result\n } catch (e) {\n console.error(e)\n return false\n }\n}\n\nexport async function muteAllUsersConference(confId, isAlreadyMuted) {\n if (confId === '') {\n return false\n }\n\n // Get the conference users from the store\n const { usersList } = store.getState().conference\n\n if (!usersList || Object.keys(usersList).length === 0) {\n return false\n }\n\n try {\n // Iterate through all users (except the owner) and mute/unmute them\n const nonOwnerUsers = Object.values(usersList)\n\n // Determine which function to use based on isAlreadyMuted\n const actionFunction = isAlreadyMuted ? unmuteUserConf : muteUserConf\n\n // For each user, call the appropriate function directly\n for (const user of nonOwnerUsers) {\n const muteUnmuteUserInformation = {\n confId: confId?.toString(),\n userId: user.id?.toString(),\n }\n\n const result = await actionFunction(muteUnmuteUserInformation)\n\n if (result) {\n store.dispatch.conference.toggleUserMuted({\n extenId: user.extenId,\n muted: !isAlreadyMuted,\n })\n }\n }\n\n return true\n } catch (e) {\n console.error(e)\n return false\n }\n}\n\nexport async function removeUserConference(conferenceId, extensionId) {\n if (conferenceId !== '' && extensionId !== '') {\n const removeUserInformation = {\n confId: conferenceId?.toString(),\n extenId: extensionId?.toString(),\n }\n\n if (removeUserInformation) {\n try {\n const result = await hangupUserConf(removeUserInformation)\n if (result) {\n // Check if this was the last participant (excluding owner)\n setTimeout(async () => {\n const { usersList } = store.getState().conference\n const remainingParticipants = Object.values(usersList || {}).filter(\n (user) => !user.owner && user.extenId !== extensionId,\n ).length\n\n // If no more participants left, end the conference\n if (remainingParticipants === 0) {\n await endConference()\n }\n }, 500)\n\n return true\n }\n\n return false\n } catch (e) {\n console.error(e)\n return false\n }\n }\n }\n return false\n}\n\nexport const clickTransferOrConference = async (number: string, dispatch: Dispatch) => {\n if (isInsideConferenceList()) {\n const { isActive } = store.getState().conference\n\n // Put current call user inside conference mode (only for first user to add not for the second one)\n // If conference is not active, start it first, otherwise proceed directly\n if (!isActive) {\n const conferenceStarted = await startConference()\n if (!conferenceStarted) {\n return // Early return if conference failed to start\n }\n }\n\n // Proceed to waiting conference view (common path for both cases)\n waitingConferenceView(number, dispatch)\n } else {\n handleAttendedTransfer(number, dispatch)\n }\n}\n\nexport const isInsideConferenceList = () => {\n const { isConferenceList } = store.getState().island\n if (isConferenceList) {\n return true\n }\n return false\n}\n\nexport const waitingConferenceView = (numberToCall, dispatch: Dispatch) => {\n // Get all required state in one call to minimize store access\n const state = store.getState()\n const { username } = state.currentUser\n const { isActive, isOwnerInside, conferenceId } = state.conference\n const { extensions } = state.users\n\n // Show current waiting user in back view (only on first)\n if (!isActive && username) {\n dispatch.conference.setConferenceActive(true)\n dispatch.conference.setConferenceStartedFrom(username)\n }\n\n // Add pending user to track the participant being added (before socket confirms)\n const extension = extensions\n ? Object.values(extensions).find((ext: any) => ext.exten === numberToCall)\n : null\n const extensionName = extension?.name || numberToCall\n\n dispatch.conference.addPendingUser({\n id: `${conferenceId}-${numberToCall}`,\n name: extensionName,\n owner: false,\n muted: false,\n extenId: numberToCall,\n joinTime: Date.now(),\n })\n\n // If owner has already started the conference, hangup before making a new call\n if (isOwnerInside) {\n hangupCurrentCall()\n dispatch.conference.toggleIsOwnerInside(false)\n }\n\n // Start new call with selected user from conference list\n // Use requestAnimationFrame to ensure state updates are complete before dispatching event\n requestAnimationFrame(() => {\n setTimeout(() => {\n eventDispatch('phone-island-call-start', { number: numberToCall })\n }, 1000)\n })\n}\n\nexport async function handleAttendedTransfer(number: string, dispatch: Dispatch) {\n // Send attended transfer message\n unpauseCurrentCall()\n const transferringMessageSent = await attendedTransfer(number)\n if (transferringMessageSent) {\n // Set transferring and disable pause\n dispatch.currentCall.updateCurrentCall({\n transferring: true,\n paused: false,\n })\n\n // Use requestAnimationFrame to ensure state update is complete before audio operations\n requestAnimationFrame(() => {\n dispatch.player.playRemoteAudio()\n eventDispatch('phone-island-call-transfered', {})\n })\n }\n}\n"],"names":["hangupCurrentCall","_a","store","getState","currentCall","outgoing","accepted","streamingSourceNumber","isFromStreaming","island","isWebRTC","hangup","hangupPhysical","dispatch","player","stopAudioPlayer","reset","listen","sourceId_1","getStreamingSourceId","unsubscribe","id","then","console","debug","concat","catch","error","streaming","clearSourceImages","setIsFromStreaming","resetOperatorBusy","eventDispatch","unpauseCurrentCall","unpauseWebRTC","updateCurrentCall","paused","playRemoteAudio","pausePhysical","attendedTransfer","number","conversationId","default_device","currentUser","default_device_details","exten","attendedTransferRequest","convid","to","endpointId","startConference","_b","chSource","chDest","incoming","incomingSocket","outgoingSocket","defaultDeviceId","addedUserExtension","isEmpty","callerNum","startConferenceInformations","toString","addEndpointId","ownerEndpointId","startConf","_c","sent","conferencing","e_2","endConference","conferenceId","conference","endConferenceInformation","confId","endConf","e_4","isInsideConferenceList","isConferenceList","waitingConferenceView","numberToCall","state","username","isActive","isOwnerInside","extensions","users","setConferenceActive","setConferenceStartedFrom","extension","Object","values","find","ext","extensionName","name","addPendingUser","owner","muted","extenId","joinTime","Date","now","toggleIsOwnerInside","requestAnimationFrame","setTimeout","handleAttendedTransfer","transferring","answerWebRTC","answerPhysical","resetOperatorBusyCompletely","endpointIdInConversation","blindTransferRequest","sipHost","options","sipURI","setOperatorBusyCalledNumber","callSipURI","callPhysical","__awaiter","conversations","keys","forEach","forceHangup","endpointType","hangupConversation","hangupPhysicalRecordingCall","physicalRecorder","setRecording","setIslandView","joinConferenceInformation","joinMyConf","e_3","isAlreadyMuted","usersList","length","nonOwnerUsers","actionFunction","unmuteUserConf","muteUserConf","_i","nonOwnerUsers_1","user","muteUnmuteUserInformation","userId","toggleUserMuted","e_6","muteWebRTC","mutePhysical","e_5","userConversationInformations","_d","parkingInformation","key","hasOwnProperty","conversation","numberParkId","idConversation","parkConversation","applicantId","setParked","pauseWebRTC","pauseRemoteAudio","updateStartAudioPlayer","src","dtmfAudios","recordingValue","updateRecordingStatus","firstExtensionNotEmpty","data","firstEntry","recording","findFirstExtesnionNotEmpty","numberToSendCall","match","listenInformations","recordingValues","toggleRecord","_e","e_1","extensionId","removeUserInformation","hangupUserConf","_this","remainingParticipants","filter","e_7","unmuteWebRTC"],"mappings":"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"}
1
+ {"version":3,"file":"call.js","sources":["../../../src/lib/phone/call.ts"],"sourcesContent":["// Copyright (C) 2024 Nethesis S.r.l.\n// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport {\n callSipURI,\n hangup,\n answerWebRTC,\n muteWebRTC,\n unmuteWebRTC,\n pauseWebRTC,\n unpauseWebRTC,\n} from '../webrtc/messages'\nimport { Dispatch, store } from '../../store'\nimport { isWebRTC } from '../user/default_device'\nimport {\n blindTransfer as blindTransferRequest,\n attendedTransfer as attendedTransferRequest,\n hangupPhysical,\n answerPhysical,\n mutePhysical,\n pausePhysical,\n callPhysical,\n toggleRecord,\n hangupPhysicalRecordingCall,\n startConf,\n joinMyConf,\n endConf,\n muteUserConf,\n unmuteUserConf,\n hangupUserConf,\n forceHangup,\n} from '../../services/astproxy'\nimport dtmfAudios from '../../static/dtmf'\nimport { hangupConversation, parkConversation } from '../../services/astproxy'\nimport { eventDispatch } from '../../utils'\nimport { isEmpty } from '../../utils/genericFunctions/isEmpty'\nimport { getStreamingSourceId } from '../../utils/streaming/getStreamingSourceId'\nimport { findVideoSourceByNumber, isRtspVideoSource } from '../../utils/streaming/videoSource'\nimport { stopStreamingVideo } from '../streaming/streamingVideo'\nimport { unsubscribe } from '../../services/user'\n\n/**\n * Starts a call to a number\n * @param number The number string\n */\nexport function callNumber(number: string, sipHost: string, options: { video?: boolean } = {}) {\n const sipURI = `sip:${number}@${sipHost}`\n\n // Reset any previous operator busy state when starting a new call\n store.dispatch.island.resetOperatorBusy()\n // Save the called number for potential operator busy scenarios\n store.dispatch.island.setOperatorBusyCalledNumber(number)\n\n if (isWebRTC()) {\n callSipURI(sipURI, options)\n } else {\n callPhysical(number)\n }\n\n eventDispatch('phone-island-call-started', {})\n}\n\n/**\n * Answer incoming call\n */\nexport function answerIncomingCall() {\n // The call is being answered here: the socket updates of its other ringing legs must not\n // bring the island back to the incoming call view (see Socket.tsx, ringing)\n store.dispatch.currentCall.updateCurrentCall({ answering: true })\n if (isWebRTC()) {\n answerWebRTC()\n } else {\n answerPhysical()\n }\n // Reset operator busy completely when call is answered successfully\n store.dispatch.island.resetOperatorBusyCompletely()\n}\n\n/**\n * Hangup all the conversations of all the extensions of the current user\n */\nexport function hangupAllExtensions() {\n // Get current user endpoints\n const { conversations } = store.getState().currentUser\n // Hangup all the conversations of all extensions of the current user\n for (const extension in conversations) {\n const conversationsIds = Object.keys(conversations[extension])\n conversationsIds.forEach((id) => {\n hangupConversation({\n convid: id,\n endpointId: extension,\n })\n })\n }\n}\n\nexport function forceHangupConversation() {\n // Get current user endpoints\n const { conversations } = store.getState().currentUser\n // Hangup all the conversations of all extensions of the current user\n for (const extension in conversations) {\n const conversationsIds = Object.keys(conversations[extension])\n conversationsIds.forEach((id) => {\n forceHangup({\n convid: id,\n endpointId: extension,\n endpointType: 'extension',\n })\n })\n }\n}\n\n/**\n * Releases the video source of the current streaming call, if any: closes its live video or\n * unsubscribes from its images, then resets the streaming call flag.\n * To be called when the call is over for this client (ended, rejected or answered elsewhere).\n */\nexport function releaseStreamingSource() {\n const { streamingSourceNumber } = store.getState().currentCall\n const { isFromStreaming } = store.getState().island\n\n if (isFromStreaming && streamingSourceNumber) {\n const sourceId = getStreamingSourceId(streamingSourceNumber)\n const source = findVideoSourceByNumber(\n store.getState().streaming.videoSources,\n streamingSourceNumber,\n )\n if (sourceId && isRtspVideoSource(source)) {\n stopStreamingVideo(sourceId)\n } else if (sourceId) {\n // Unsubscribe from streaming updates\n unsubscribe({ id: sourceId })\n .then(() => console.debug(`Unsubscribed from streaming source: ${sourceId}`))\n .catch((error) => console.error('Error unsubscribing from streaming source:', error))\n\n // Clear source images to free up memory\n store.dispatch.streaming.clearSourceImages()\n }\n }\n\n // Reset isFromStreaming flag\n if (isFromStreaming) {\n store.dispatch.island.setIsFromStreaming(false)\n }\n}\n\n/**\n * Hangup current call\n */\nexport function hangupCurrentCall() {\n const { outgoing, accepted } = store.getState().currentCall\n\n if (outgoing || accepted) {\n // If call was from a streaming source, close its live video or unsubscribe and clear images\n releaseStreamingSource()\n\n if (isWebRTC()) {\n hangup()\n } else {\n hangupPhysical()\n }\n store.dispatch.player.stopAudioPlayer()\n store.dispatch.currentCall.reset()\n store.dispatch.listen.reset()\n }\n // Reset operator busy state when call ends\n store.dispatch.island.resetOperatorBusy()\n // Caller close the call before the call is accepted\n eventDispatch('phone-island-call-ended', {})\n}\n\n/**\n * Hangup current physical recording\n */\nexport function hangupCurrentPhysicalRecording() {\n hangupPhysicalRecordingCall()\n store.dispatch.player.stopAudioPlayer()\n store.dispatch.physicalRecorder.reset()\n store.dispatch.physicalRecorder.setRecording(false)\n store.dispatch.island.setIslandView(null)\n store.dispatch.listen.reset()\n // Caller close the call before the call is accepted\n eventDispatch('phone-island-call-ended', {})\n}\n\n/**\n * Mute the current call\n */\nexport function muteCurrentCall() {\n // Check the current user default device\n if (isWebRTC()) {\n const muted = muteWebRTC()\n if (muted) {\n store.dispatch.currentCall.updateCurrentCall({\n muted: true,\n })\n }\n } else {\n mutePhysical(true)\n }\n eventDispatch('phone-island-call-muted', {})\n}\n\n/**\n * Unmute the current call\n */\nexport function unmuteCurrentCall() {\n // Check the current user default device\n if (isWebRTC()) {\n const unmuted = unmuteWebRTC()\n if (unmuted) {\n store.dispatch.currentCall.updateCurrentCall({\n muted: false,\n })\n }\n } else {\n mutePhysical(false)\n }\n eventDispatch('phone-island-call-unmuted', {})\n}\n\n/**\n * Pause the current call\n */\nexport function pauseCurrentCall() {\n // Check the current user default device\n if (isWebRTC()) {\n const paused = pauseWebRTC()\n if (paused) {\n store.dispatch.currentCall.updateCurrentCall({\n paused: true,\n })\n // Pause remote audio\n store.dispatch.player.pauseRemoteAudio()\n }\n } else if (!store.getState().currentCall.paused) {\n pausePhysical(true)\n }\n eventDispatch('phone-island-call-held', {})\n}\n\n/**\n * Unpause the current call\n */\nexport function unpauseCurrentCall() {\n // Check the current user default device\n if (isWebRTC()) {\n const unpaused = unpauseWebRTC()\n if (unpaused) {\n store.dispatch.currentCall.updateCurrentCall({\n paused: false,\n })\n // Play remote audio\n store.dispatch.player.playRemoteAudio()\n }\n } else if (store.getState().currentCall.paused) {\n pausePhysical(false)\n }\n eventDispatch('phone-island-call-unheld', {})\n}\n\n/**\n * Transfer the current call through a blind transfer (not in use)\n */\nexport async function blindTransferFunction(number: string, endpointIdInConversation: string) {\n // Retrieve current conversation info\n const { conversationId } = store.getState().currentCall\n // Transfer the call through blind transfer\n if (conversationId && endpointIdInConversation && number) {\n return await blindTransferRequest({\n convid: conversationId,\n to: number,\n endpointId: endpointIdInConversation,\n })\n }\n}\n\n/**\n * Transfer the current call through a attended transfer\n */\nexport async function attendedTransfer(number: string) {\n // Retrieve current conversation info\n const { conversationId } = store.getState().currentCall\n const { default_device } = store.getState().currentUser\n let default_device_details = default_device?.id || default_device?.exten\n // Transfer the call through attended transfer\n if (conversationId && default_device_details && number) {\n return await attendedTransferRequest({\n convid: conversationId,\n to: number,\n endpointId: default_device_details,\n })\n }\n}\n\n/**\n * Play the dtmf audio files\n */\nexport function playDtmfAudio(key: string) {\n if (key === '*') key = 'star'\n if (key === '#') key = 'pound'\n store.dispatch.player.updateStartAudioPlayer({ src: dtmfAudios[`dtmf_${key}`] })\n}\n\n/**\n * Park the current call\n */\nexport function parkCurrentCall() {\n const conversationId = store?.getState()?.currentCall?.conversationId\n const userConversationInformations = store?.getState()?.currentUser?.conversations\n\n let parkingInformation: any = {}\n\n if (conversationId) {\n if (userConversationInformations) {\n for (const key in userConversationInformations) {\n if (userConversationInformations.hasOwnProperty(key)) {\n const conversation = userConversationInformations[key]\n if (Object.keys(conversation).length > 0) {\n parkingInformation = {\n numberParkId: key,\n idConversation: conversationId,\n }\n }\n }\n }\n }\n\n if (Object.keys(parkingInformation).length > 0) {\n if (parkingInformation?.numberParkId) {\n // If park information are not empty park call\n parkConversation({\n applicantId: parkingInformation?.numberParkId,\n convid: conversationId,\n endpointId: parkingInformation?.numberParkId,\n })\n\n store.dispatch.currentCall.setParked(true)\n\n eventDispatch('phone-island-call-parked', {})\n }\n }\n }\n}\n\nconst findFirstExtesnionNotEmpty = (data) => {\n for (const key in data) {\n if (Object.keys(data[key]).length !== 0) {\n const firstEntry: any = Object.values(data[key])[0]\n return {\n id: firstEntry.id,\n recording: firstEntry.recording,\n }\n }\n }\n return null\n}\n\nexport async function recordCurrentCall(recordingValue: boolean) {\n store.dispatch.currentCall.updateRecordingStatus(!recordingValue)\n const userConversationInformations = store?.getState()?.currentUser?.conversations\n\n const firstExtensionNotEmpty = findFirstExtesnionNotEmpty(userConversationInformations)\n\n if (!firstExtensionNotEmpty) {\n return\n } else {\n const numberToSendCall = firstExtensionNotEmpty?.id?.match(/\\/(\\d+)-/)\n const endpointId = numberToSendCall[1]\n\n const listenInformations = {\n convid: firstExtensionNotEmpty?.id?.toString(),\n endpointId: endpointId?.toString(),\n }\n\n let recordingValues = ''\n switch (firstExtensionNotEmpty?.recording) {\n case 'false':\n recordingValues = 'start_record'\n break\n case 'true':\n recordingValues = 'mute_record'\n break\n case 'mute':\n recordingValues = 'unmute_record'\n break\n default:\n recordingValues = ''\n break\n }\n\n if (listenInformations) {\n try {\n await toggleRecord(recordingValues, listenInformations)\n } catch (e) {\n console.error(e)\n return []\n }\n }\n }\n}\n\nexport async function startConference() {\n const {\n accepted,\n chSource,\n chDest,\n incoming,\n outgoing,\n incomingSocket,\n outgoingSocket,\n conversationId,\n }: any = store?.getState()?.currentCall\n const { default_device } = store.getState().currentUser\n const defaultDeviceId = default_device?.id || default_device?.exten\n let addedUserExtension = ''\n if (accepted && (incoming || incomingSocket) && !isEmpty(chSource)) {\n addedUserExtension = chSource?.callerNum\n } else if (accepted && (outgoing || outgoingSocket) && !isEmpty(chDest)) {\n addedUserExtension = chDest?.callerNum\n }\n\n if (defaultDeviceId !== '' && conversationId !== '' && addedUserExtension !== '') {\n const startConferenceInformations = {\n convid: conversationId?.toString(),\n addEndpointId: addedUserExtension?.toString(),\n ownerEndpointId: defaultDeviceId?.toString(),\n }\n\n if (startConferenceInformations) {\n try {\n const result = await startConf(startConferenceInformations)\n if (result) {\n // Set conferencing and disable pause\n store.dispatch.currentCall.updateCurrentCall({\n conferencing: true,\n paused: false,\n })\n\n eventDispatch('phone-island-call-conferenced', {})\n return true\n }\n return false\n } catch (e) {\n console.error(e)\n return false\n }\n }\n }\n return false\n}\n\nexport async function joinConference() {\n const { default_device } = store.getState().currentUser\n const defaultDeviceId = default_device?.id || default_device?.exten\n\n if (defaultDeviceId !== '') {\n const joinConferenceInformation = {\n endpointId: defaultDeviceId?.toString(),\n }\n\n if (joinConferenceInformation) {\n try {\n const result = await joinMyConf(joinConferenceInformation)\n if (result) {\n eventDispatch('phone-island-owner-conference-enter', {})\n return true\n }\n return false\n } catch (e) {\n console.error(e)\n return false\n }\n }\n }\n return false\n}\n\nexport async function endConference() {\n const { conferenceId } = store.getState().conference\n\n if (conferenceId !== '') {\n const endConferenceInformation = {\n confId: conferenceId?.toString(),\n }\n\n if (endConferenceInformation) {\n try {\n const result = await endConf(endConferenceInformation)\n if (result) {\n eventDispatch('phone-island-owner-conference-finished', {})\n return true\n }\n return false\n } catch (e) {\n console.error(e)\n return false\n }\n }\n }\n return false\n}\n\nexport async function muteUserConference(confId, userId, isAlreadyMuted) {\n if (confId === '' || userId === '') {\n return false\n }\n\n const muteUnmuteUserInformation = {\n confId: confId?.toString(),\n userId: userId?.toString(),\n }\n\n try {\n // Check if the user is already muted\n const actionFunction = isAlreadyMuted ? unmuteUserConf : muteUserConf\n const result = await actionFunction(muteUnmuteUserInformation)\n return !!result\n } catch (e) {\n console.error(e)\n return false\n }\n}\n\nexport async function muteAllUsersConference(confId, isAlreadyMuted) {\n if (confId === '') {\n return false\n }\n\n // Get the conference users from the store\n const { usersList } = store.getState().conference\n\n if (!usersList || Object.keys(usersList).length === 0) {\n return false\n }\n\n try {\n // Iterate through all users (except the owner) and mute/unmute them\n const nonOwnerUsers = Object.values(usersList)\n\n // Determine which function to use based on isAlreadyMuted\n const actionFunction = isAlreadyMuted ? unmuteUserConf : muteUserConf\n\n // For each user, call the appropriate function directly\n for (const user of nonOwnerUsers) {\n const muteUnmuteUserInformation = {\n confId: confId?.toString(),\n userId: user.id?.toString(),\n }\n\n const result = await actionFunction(muteUnmuteUserInformation)\n\n if (result) {\n store.dispatch.conference.toggleUserMuted({\n extenId: user.extenId,\n muted: !isAlreadyMuted,\n })\n }\n }\n\n return true\n } catch (e) {\n console.error(e)\n return false\n }\n}\n\nexport async function removeUserConference(conferenceId, extensionId) {\n if (conferenceId !== '' && extensionId !== '') {\n const removeUserInformation = {\n confId: conferenceId?.toString(),\n extenId: extensionId?.toString(),\n }\n\n if (removeUserInformation) {\n try {\n const result = await hangupUserConf(removeUserInformation)\n if (result) {\n // Check if this was the last participant (excluding owner)\n setTimeout(async () => {\n const { usersList } = store.getState().conference\n const remainingParticipants = Object.values(usersList || {}).filter(\n (user) => !user.owner && user.extenId !== extensionId,\n ).length\n\n // If no more participants left, end the conference\n if (remainingParticipants === 0) {\n await endConference()\n }\n }, 500)\n\n return true\n }\n\n return false\n } catch (e) {\n console.error(e)\n return false\n }\n }\n }\n return false\n}\n\nexport const clickTransferOrConference = async (number: string, dispatch: Dispatch) => {\n if (isInsideConferenceList()) {\n const { isActive } = store.getState().conference\n\n // Put current call user inside conference mode (only for first user to add not for the second one)\n // If conference is not active, start it first, otherwise proceed directly\n if (!isActive) {\n const conferenceStarted = await startConference()\n if (!conferenceStarted) {\n return // Early return if conference failed to start\n }\n }\n\n // Proceed to waiting conference view (common path for both cases)\n waitingConferenceView(number, dispatch)\n } else {\n handleAttendedTransfer(number, dispatch)\n }\n}\n\nexport const isInsideConferenceList = () => {\n const { isConferenceList } = store.getState().island\n if (isConferenceList) {\n return true\n }\n return false\n}\n\nexport const waitingConferenceView = (numberToCall, dispatch: Dispatch) => {\n // Get all required state in one call to minimize store access\n const state = store.getState()\n const { username } = state.currentUser\n const { isActive, isOwnerInside, conferenceId } = state.conference\n const { extensions } = state.users\n\n // Show current waiting user in back view (only on first)\n if (!isActive && username) {\n dispatch.conference.setConferenceActive(true)\n dispatch.conference.setConferenceStartedFrom(username)\n }\n\n // Add pending user to track the participant being added (before socket confirms)\n const extension = extensions\n ? Object.values(extensions).find((ext: any) => ext.exten === numberToCall)\n : null\n const extensionName = extension?.name || numberToCall\n\n dispatch.conference.addPendingUser({\n id: `${conferenceId}-${numberToCall}`,\n name: extensionName,\n owner: false,\n muted: false,\n extenId: numberToCall,\n joinTime: Date.now(),\n })\n\n // If owner has already started the conference, hangup before making a new call\n if (isOwnerInside) {\n hangupCurrentCall()\n dispatch.conference.toggleIsOwnerInside(false)\n }\n\n // Start new call with selected user from conference list\n // Use requestAnimationFrame to ensure state updates are complete before dispatching event\n requestAnimationFrame(() => {\n setTimeout(() => {\n eventDispatch('phone-island-call-start', { number: numberToCall })\n }, 1000)\n })\n}\n\nexport async function handleAttendedTransfer(number: string, dispatch: Dispatch) {\n // Send attended transfer message\n unpauseCurrentCall()\n const transferringMessageSent = await attendedTransfer(number)\n if (transferringMessageSent) {\n // Set transferring and disable pause\n dispatch.currentCall.updateCurrentCall({\n transferring: true,\n paused: false,\n })\n\n // Use requestAnimationFrame to ensure state update is complete before audio operations\n requestAnimationFrame(() => {\n dispatch.player.playRemoteAudio()\n eventDispatch('phone-island-call-transfered', {})\n })\n }\n}\n"],"names":["releaseStreamingSource","streamingSourceNumber","store","getState","currentCall","isFromStreaming","island","sourceId_1","getStreamingSourceId","source","findVideoSourceByNumber","streaming","videoSources","isRtspVideoSource","stopStreamingVideo","unsubscribe","id","then","console","debug","concat","catch","error","dispatch","clearSourceImages","setIsFromStreaming","hangupCurrentCall","_a","outgoing","accepted","isWebRTC","hangup","hangupPhysical","player","stopAudioPlayer","reset","listen","resetOperatorBusy","eventDispatch","unpauseCurrentCall","unpauseWebRTC","updateCurrentCall","paused","playRemoteAudio","pausePhysical","attendedTransfer","number","conversationId","default_device","currentUser","default_device_details","exten","attendedTransferRequest","convid","to","endpointId","startConference","_b","chSource","chDest","incoming","incomingSocket","outgoingSocket","defaultDeviceId","addedUserExtension","isEmpty","callerNum","startConferenceInformations","toString","addEndpointId","ownerEndpointId","startConf","_c","sent","conferencing","e_2","endConference","conferenceId","conference","endConferenceInformation","confId","endConf","e_4","isInsideConferenceList","isConferenceList","waitingConferenceView","numberToCall","state","username","isActive","isOwnerInside","extensions","users","setConferenceActive","setConferenceStartedFrom","extension","Object","values","find","ext","extensionName","name","addPendingUser","owner","muted","extenId","joinTime","Date","now","toggleIsOwnerInside","requestAnimationFrame","setTimeout","handleAttendedTransfer","transferring","answering","answerWebRTC","answerPhysical","resetOperatorBusyCompletely","endpointIdInConversation","blindTransferRequest","sipHost","options","sipURI","setOperatorBusyCalledNumber","callSipURI","callPhysical","__awaiter","conversations","keys","forEach","forceHangup","endpointType","hangupConversation","hangupPhysicalRecordingCall","physicalRecorder","setRecording","setIslandView","joinConferenceInformation","joinMyConf","e_3","isAlreadyMuted","usersList","length","nonOwnerUsers","actionFunction","unmuteUserConf","muteUserConf","_i","nonOwnerUsers_1","user","muteUnmuteUserInformation","userId","toggleUserMuted","e_6","muteWebRTC","mutePhysical","e_5","userConversationInformations","_d","parkingInformation","key","hasOwnProperty","conversation","numberParkId","idConversation","parkConversation","applicantId","setParked","pauseWebRTC","pauseRemoteAudio","updateStartAudioPlayer","src","dtmfAudios","recordingValue","updateRecordingStatus","firstExtensionNotEmpty","data","firstEntry","recording","findFirstExtesnionNotEmpty","numberToSendCall","match","listenInformations","recordingValues","toggleRecord","_e","e_1","extensionId","removeUserInformation","hangupUserConf","_this","remainingParticipants","filter","e_7","unmuteWebRTC"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("../../store/index.js"),t=require("../webrtc/janus.js");require("react");var r=require("../../utils/genericFunctions/eventDispatch.js");require("../../node_modules/tslib/tslib.es6.js"),exports.notifyPeerVideoStart=function(){var t=e.store.getState().websocket.socket,r=e.store.getState().currentCall.username,s=e.store.getState().currentUser.username;t&&r&&s&&t.emit("message",{message:"videoCallStart",destUser:r,callUser:s})},exports.releaseLocalVideo=function(){var s,i,o,a,l=e.store.getState().webrtc,n=l.localVideoStream,d=l.sipcall;n&&t.default.stopAllTracks(n),e.store.dispatch.webrtc.updateLocalVideoStream(null),(null!==(a=null===(o=null===(i=null===(s=null==d?void 0:d.webrtcStuff)||void 0===s?void 0:s.pc)||void 0===i?void 0:i.getSenders)||void 0===o?void 0:o.call(i))&&void 0!==a?a:[]).forEach(function(e){var t;"video"===(null===(t=e.track)||void 0===t?void 0:t.kind)&&(e.track.stop(),e.replaceTrack(null).catch(function(){}))}),e.store.dispatch.currentCall.updateCurrentCall({isLocalVideoEnabled:!1}),"video"===e.store.getState().island.view&&e.store.dispatch.island.setIslandView("call"),r.eventDispatch("phone-island-video-disabled",{})},exports.sdpDeclinesVideo=function(e){return"string"==typeof e&&/^m=video 0 /m.test(e)},exports.sdpHasActiveVideo=function(e){return"string"==typeof e&&/^m=video (?!0 )/m.test(e)};
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("../../store/index.js"),t=require("../webrtc/janus.js");require("react");var r=require("../../utils/genericFunctions/eventDispatch.js");require("../../node_modules/tslib/tslib.es6.js"),require("../../services/user.js"),exports.notifyPeerVideoStart=function(){var t=e.store.getState().websocket.socket,r=e.store.getState().currentCall.username,s=e.store.getState().currentUser.username;t&&r&&s&&t.emit("message",{message:"videoCallStart",destUser:r,callUser:s})},exports.releaseLocalVideo=function(){var s,i,o,a,l=e.store.getState().webrtc,n=l.localVideoStream,d=l.sipcall;n&&t.default.stopAllTracks(n),e.store.dispatch.webrtc.updateLocalVideoStream(null),(null!==(a=null===(o=null===(i=null===(s=null==d?void 0:d.webrtcStuff)||void 0===s?void 0:s.pc)||void 0===i?void 0:i.getSenders)||void 0===o?void 0:o.call(i))&&void 0!==a?a:[]).forEach(function(e){var t;"video"===(null===(t=e.track)||void 0===t?void 0:t.kind)&&(e.track.stop(),e.replaceTrack(null).catch(function(){}))}),e.store.dispatch.currentCall.updateCurrentCall({isLocalVideoEnabled:!1}),"video"===e.store.getState().island.view&&e.store.dispatch.island.setIslandView("call"),r.eventDispatch("phone-island-video-disabled",{})},exports.sdpDeclinesVideo=function(e){return"string"==typeof e&&/^m=video 0 /m.test(e)},exports.sdpHasActiveVideo=function(e){return"string"==typeof e&&/^m=video (?!0 )/m.test(e)};
2
2
  //# sourceMappingURL=video.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"video.js","sources":["../../../src/lib/phone/video.ts"],"sourcesContent":["// Copyright (C) 2026 Nethesis S.r.l.\n// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport { store } from '../../store'\nimport Janus from '../webrtc/janus'\nimport { eventDispatch } from '../../utils'\n\n/**\n * Tells the peer (through the websocket) that a video call started, so that\n * a WebRTC peer opens its video view\n */\nexport function notifyPeerVideoStart() {\n const { socket } = store.getState().websocket\n const { username: destUser } = store.getState().currentCall\n const { username: callUser } = store.getState().currentUser\n\n if (!socket || !destUser || !callUser) {\n return\n }\n\n socket.emit('message', {\n message: 'videoCallStart',\n destUser,\n callUser,\n })\n}\n\n/**\n * True when the SDP answer carries an active video stream\n */\nexport function sdpHasActiveVideo(sdp: string | undefined): boolean {\n if (typeof sdp !== 'string') {\n return false\n }\n return /^m=video (?!0 )/m.test(sdp)\n}\n\n/**\n * True when the SDP declines the video stream (m=video with port 0)\n */\nexport function sdpDeclinesVideo(sdp: string | undefined): boolean {\n return typeof sdp === 'string' && /^m=video 0 /m.test(sdp)\n}\n\n/**\n * Stops the local camera and brings the island back to an audio call: used when the\n * remote party, or Asterisk on its behalf, declines the video stream\n */\nexport function releaseLocalVideo() {\n const { localVideoStream, sipcall }: { localVideoStream: MediaStream | null; sipcall: any } =\n store.getState().webrtc\n if (localVideoStream) {\n // @ts-ignore\n Janus.stopAllTracks(localVideoStream)\n }\n store.dispatch.webrtc.updateLocalVideoStream(null)\n const senders: RTCRtpSender[] = sipcall?.webrtcStuff?.pc?.getSenders?.() ?? []\n senders.forEach((sender) => {\n if (sender.track?.kind === 'video') {\n sender.track.stop()\n sender.replaceTrack(null).catch(() => {})\n }\n })\n store.dispatch.currentCall.updateCurrentCall({ isLocalVideoEnabled: false })\n if (store.getState().island.view === 'video') {\n store.dispatch.island.setIslandView('call')\n }\n eventDispatch('phone-island-video-disabled', {})\n}\n"],"names":["socket","store","getState","websocket","destUser","currentCall","username","callUser","currentUser","emit","message","_e","webrtc","localVideoStream","sipcall","Janus","stopAllTracks","dispatch","updateLocalVideoStream","_d","_c","_a","webrtcStuff","pc","_b","getSenders","call","forEach","sender","track","kind","stop","replaceTrack","catch","updateCurrentCall","isLocalVideoEnabled","island","view","setIslandView","eventDispatch","sdp","test"],"mappings":"mTAYU,IAAAA,EAAWC,EAAKA,MAACC,WAAWC,UAASH,OAC3BI,EAAaH,EAAKA,MAACC,WAAWG,YAAWC,SACzCC,EAAaN,EAAKA,MAACC,WAAWM,YAAWF,SAEtDN,GAAWI,GAAaG,GAI7BP,EAAOS,KAAK,UAAW,CACrBC,QAAS,iBACTN,SAAQA,EACRG,SAAQA,GAEZ,mDAwBQI,EACJV,EAAAA,MAAMC,WAAWU,OADXC,EAAgBF,EAAAE,iBAAEC,YAEtBD,GAEFE,UAAMC,cAAcH,GAEtBZ,EAAAA,MAAMgB,SAASL,OAAOM,uBAAuB,OAC2B,QAAxCC,EAAwC,QAAxCC,EAAwB,kBAAxBC,EAAAP,aAAO,EAAPA,EAASQ,kCAAaC,UAAE,IAAAC,OAAA,EAAAA,EAAEC,kBAAc,IAAAL,OAAA,EAAAA,EAAAM,KAAAF,UAAA,IAAAL,EAAAA,EAAI,IACpEQ,QAAQ,SAACC,SACY,mBAAvBP,EAAAO,EAAOC,4BAAOC,QAChBF,EAAOC,MAAME,OACbH,EAAOI,aAAa,MAAMC,MAAM,WAAQ,GAE5C,GACAhC,EAAKA,MAACgB,SAASZ,YAAY6B,kBAAkB,CAAEC,qBAAqB,IAC/B,UAAjClC,EAAKA,MAACC,WAAWkC,OAAOC,MAC1BpC,EAAAA,MAAMgB,SAASmB,OAAOE,cAAc,QAEtCC,gBAAc,8BAA+B,CAAA,EAC/C,2BA5BM,SAA2BC,GAC/B,MAAsB,iBAARA,GAAoB,eAAeC,KAAKD,EACxD,4BAZM,SAA4BA,GAChC,MAAmB,iBAARA,GAGJ,mBAAmBC,KAAKD,EACjC"}
1
+ {"version":3,"file":"video.js","sources":["../../../src/lib/phone/video.ts"],"sourcesContent":["// Copyright (C) 2026 Nethesis S.r.l.\n// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport { store } from '../../store'\nimport Janus from '../webrtc/janus'\nimport { eventDispatch } from '../../utils'\n\n/**\n * Tells the peer (through the websocket) that a video call started, so that\n * a WebRTC peer opens its video view\n */\nexport function notifyPeerVideoStart() {\n const { socket } = store.getState().websocket\n const { username: destUser } = store.getState().currentCall\n const { username: callUser } = store.getState().currentUser\n\n if (!socket || !destUser || !callUser) {\n return\n }\n\n socket.emit('message', {\n message: 'videoCallStart',\n destUser,\n callUser,\n })\n}\n\n/**\n * True when the SDP answer carries an active video stream\n */\nexport function sdpHasActiveVideo(sdp: string | undefined): boolean {\n if (typeof sdp !== 'string') {\n return false\n }\n return /^m=video (?!0 )/m.test(sdp)\n}\n\n/**\n * True when the SDP declines the video stream (m=video with port 0)\n */\nexport function sdpDeclinesVideo(sdp: string | undefined): boolean {\n return typeof sdp === 'string' && /^m=video 0 /m.test(sdp)\n}\n\n/**\n * Stops the local camera and brings the island back to an audio call: used when the\n * remote party, or Asterisk on its behalf, declines the video stream\n */\nexport function releaseLocalVideo() {\n const { localVideoStream, sipcall }: { localVideoStream: MediaStream | null; sipcall: any } =\n store.getState().webrtc\n if (localVideoStream) {\n // @ts-ignore\n Janus.stopAllTracks(localVideoStream)\n }\n store.dispatch.webrtc.updateLocalVideoStream(null)\n const senders: RTCRtpSender[] = sipcall?.webrtcStuff?.pc?.getSenders?.() ?? []\n senders.forEach((sender) => {\n if (sender.track?.kind === 'video') {\n sender.track.stop()\n sender.replaceTrack(null).catch(() => {})\n }\n })\n store.dispatch.currentCall.updateCurrentCall({ isLocalVideoEnabled: false })\n if (store.getState().island.view === 'video') {\n store.dispatch.island.setIslandView('call')\n }\n eventDispatch('phone-island-video-disabled', {})\n}\n"],"names":["socket","store","getState","websocket","destUser","currentCall","username","callUser","currentUser","emit","message","_e","webrtc","localVideoStream","sipcall","Janus","stopAllTracks","dispatch","updateLocalVideoStream","_d","_c","_a","webrtcStuff","pc","_b","getSenders","call","forEach","sender","track","kind","stop","replaceTrack","catch","updateCurrentCall","isLocalVideoEnabled","island","view","setIslandView","eventDispatch","sdp","test"],"mappings":"qVAYU,IAAAA,EAAWC,EAAKA,MAACC,WAAWC,UAASH,OAC3BI,EAAaH,EAAKA,MAACC,WAAWG,YAAWC,SACzCC,EAAaN,EAAKA,MAACC,WAAWM,YAAWF,SAEtDN,GAAWI,GAAaG,GAI7BP,EAAOS,KAAK,UAAW,CACrBC,QAAS,iBACTN,SAAQA,EACRG,SAAQA,GAEZ,mDAwBQI,EACJV,EAAAA,MAAMC,WAAWU,OADXC,EAAgBF,EAAAE,iBAAEC,YAEtBD,GAEFE,UAAMC,cAAcH,GAEtBZ,EAAAA,MAAMgB,SAASL,OAAOM,uBAAuB,OAC2B,QAAxCC,EAAwC,QAAxCC,EAAwB,kBAAxBC,EAAAP,aAAO,EAAPA,EAASQ,kCAAaC,UAAE,IAAAC,OAAA,EAAAA,EAAEC,kBAAc,IAAAL,OAAA,EAAAA,EAAAM,KAAAF,UAAA,IAAAL,EAAAA,EAAI,IACpEQ,QAAQ,SAACC,SACY,mBAAvBP,EAAAO,EAAOC,4BAAOC,QAChBF,EAAOC,MAAME,OACbH,EAAOI,aAAa,MAAMC,MAAM,WAAQ,GAE5C,GACAhC,EAAKA,MAACgB,SAASZ,YAAY6B,kBAAkB,CAAEC,qBAAqB,IAC/B,UAAjClC,EAAKA,MAACC,WAAWkC,OAAOC,MAC1BpC,EAAAA,MAAMgB,SAASmB,OAAOE,cAAc,QAEtCC,gBAAc,8BAA+B,CAAA,EAC/C,2BA5BM,SAA2BC,GAC/B,MAAsB,iBAARA,GAAoB,eAAeC,KAAKD,EACxD,4BAZM,SAA4BA,GAChC,MAAmB,iBAARA,GAGJ,mBAAmBC,KAAKD,EACjC"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),require("react");var e=require("../../utils/genericFunctions/localStorage.js");require("../../node_modules/tslib/tslib.es6.js"),require("../../store/index.js");exports.loadCache=function(t,r){var i=(e.getJSONItem("caches-".concat(r))||{})[t];if(!(i&&i._expiration&&(new Date).getTime()>i._expiration))return i},exports.saveCache=function(t,r,i,c){if(i){var a=e.getJSONItem("caches-".concat(i))||{},s=r;s._expiration=c,a[t]=s,e.setJSONItem("caches-".concat(i),a)}};
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),require("react");var e=require("../../utils/genericFunctions/localStorage.js");require("../../node_modules/tslib/tslib.es6.js"),require("../../store/index.js"),require("../../services/user.js");exports.loadCache=function(t,r){var i=(e.getJSONItem("caches-".concat(r))||{})[t];if(!(i&&i._expiration&&(new Date).getTime()>i._expiration))return i},exports.saveCache=function(t,r,i,s){if(i){var c=e.getJSONItem("caches-".concat(i))||{},a=r;a._expiration=s,c[t]=a,e.setJSONItem("caches-".concat(i),c)}};
2
2
  //# sourceMappingURL=local_storage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"local_storage.js","sources":["../../../src/lib/storage/local_storage.ts"],"sourcesContent":["// Copyright (C) 2024 Nethesis S.r.l.\n// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport { getJSONItem, setJSONItem } from '../../utils'\n\n/**\n * Used to save data to cache inside a local storage entry \"caches-username\"\n *\n * @param cacheName name of the cache\n * @param cacheValue a JSON object\n * @param currentUsername username currently logged in\n * @param expiration timestamp of expiration of the cache\n */\nexport const saveCache = (\n cacheName: string,\n cacheData: any,\n currentUsername: string,\n expiration: number,\n) => {\n if (!currentUsername) {\n return\n }\n const caches = getJSONItem(`caches-${currentUsername}`) || {}\n let data = cacheData\n data['_expiration'] = expiration\n caches[cacheName] = data\n setJSONItem(`caches-${currentUsername}`, caches)\n}\n\n/**\n * Used to load user caches from the local storage entry \"caches-username\"\n *\n * @param cacheName name of the cache\n * @param currentUsername username currently logged in\n */\nexport const loadCache = (cacheName: string, currentUsername: string) => {\n const caches = getJSONItem(`caches-${currentUsername}`) || {}\n const cache = caches[cacheName]\n\n if (cache && cache['_expiration'] && new Date().getTime() > cache['_expiration']) {\n // cache has expired\n return undefined\n }\n return cache\n}\n"],"names":["cacheName","currentUsername","cache","getJSONItem","concat","Date","getTime","cacheData","expiration","caches","data","setJSONItem"],"mappings":"sPAmCyB,SAACA,EAAmBC,GAC3C,IACMC,GADSC,EAAAA,YAAY,UAAAC,OAAUH,KAAsB,IACtCD,GAErB,KAAIE,GAASA,EAAmB,cAAK,IAAIG,MAAOC,UAAYJ,EAAmB,aAI/E,OAAOA,CACT,oBA/ByB,SACvBF,EACAO,EACAN,EACAO,GAEA,GAAKP,EAAL,CAGA,IAAMQ,EAASN,EAAAA,YAAY,UAAAC,OAAUH,KAAsB,GACvDS,EAAOH,EACXG,EAAkB,YAAIF,EACtBC,EAAOT,GAAaU,EACpBC,EAAAA,YAAY,UAAUP,OAAAH,GAAmBQ,EALxC,CAMH"}
1
+ {"version":3,"file":"local_storage.js","sources":["../../../src/lib/storage/local_storage.ts"],"sourcesContent":["// Copyright (C) 2024 Nethesis S.r.l.\n// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport { getJSONItem, setJSONItem } from '../../utils'\n\n/**\n * Used to save data to cache inside a local storage entry \"caches-username\"\n *\n * @param cacheName name of the cache\n * @param cacheValue a JSON object\n * @param currentUsername username currently logged in\n * @param expiration timestamp of expiration of the cache\n */\nexport const saveCache = (\n cacheName: string,\n cacheData: any,\n currentUsername: string,\n expiration: number,\n) => {\n if (!currentUsername) {\n return\n }\n const caches = getJSONItem(`caches-${currentUsername}`) || {}\n let data = cacheData\n data['_expiration'] = expiration\n caches[cacheName] = data\n setJSONItem(`caches-${currentUsername}`, caches)\n}\n\n/**\n * Used to load user caches from the local storage entry \"caches-username\"\n *\n * @param cacheName name of the cache\n * @param currentUsername username currently logged in\n */\nexport const loadCache = (cacheName: string, currentUsername: string) => {\n const caches = getJSONItem(`caches-${currentUsername}`) || {}\n const cache = caches[cacheName]\n\n if (cache && cache['_expiration'] && new Date().getTime() > cache['_expiration']) {\n // cache has expired\n return undefined\n }\n return cache\n}\n"],"names":["cacheName","currentUsername","cache","getJSONItem","concat","Date","getTime","cacheData","expiration","caches","data","setJSONItem"],"mappings":"wRAmCyB,SAACA,EAAmBC,GAC3C,IACMC,GADSC,EAAAA,YAAY,UAAAC,OAAUH,KAAsB,IACtCD,GAErB,KAAIE,GAASA,EAAmB,cAAK,IAAIG,MAAOC,UAAYJ,EAAmB,aAI/E,OAAOA,CACT,oBA/ByB,SACvBF,EACAO,EACAN,EACAO,GAEA,GAAKP,EAAL,CAGA,IAAMQ,EAASN,EAAAA,YAAY,UAAAC,OAAUH,KAAsB,GACvDS,EAAOH,EACXG,EAAkB,YAAIF,EACtBC,EAAOT,GAAaU,EACpBC,EAAAA,YAAY,UAAUP,OAAAH,GAAmBQ,EALxC,CAMH"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("../../node_modules/tslib/tslib.es6.js"),t=require("../../store/index.js"),n=require("../../services/user.js"),r=require("../../utils/genericFunctions/eventDispatch.js"),s=require("../../utils/streaming/videoSource.js"),i=require("./whepPlayer.js"),o={status:"connecting",failure:null,hasAudio:!1},a={},u={},l=null,c=function(t){return e.__awaiter(void 0,void 0,void 0,function(){var r,s,o;return e.__generator(this,function(e){switch(e.label){case 0:return e.trys.push([0,2,,3]),[4,n.getStreamingToken(t)];case 1:return[2,{token:(r=e.sent()).token,whep:r.whep,expiresIn:r.expires_in}];case 2:if(s=e.sent(),403===(o=s instanceof n.StreamingRequestError?s.status:void 0))throw new i.WhepTokenError("streaming token forbidden",!0,"forbidden");if(400===o||404===o)throw new i.WhepTokenError("streaming token error ".concat(o),!0,"error");throw new i.WhepTokenError("streaming token error ".concat(null!=o?o:""),!1,"unreachable");case 3:return[2]}})})},p=function(e){var n=t.store.getState();if(!n.island.isFromStreaming)return!1;var r=s.findVideoSourceByNumber(n.streaming.videoSources,n.currentCall.streamingSourceNumber);return(null==r?void 0:r.id)===e},h=function(e){e.listeners.slice().forEach(function(t){return t(e.snapshot)})},d=function(e){e.stopTimer&&(clearTimeout(e.stopTimer),e.stopTimer=null)},f=function(e){d(e),a[e.sourceId]===e&&delete a[e.sourceId],!Object.keys(a).length&&l&&(l(),l=null),e.player.stop(),e.listeners.length&&(e.snapshot={state:o,stream:null},h(e))};exports.fetchStreamingToken=c,exports.initialStreamingVideoState=o,exports.stopStreamingVideo=function(e){Object.keys(a).forEach(function(t){void 0!==e&&t!==e||f(a[t])})},exports.watchStreamingVideo=function(s,m,g){if(!p(s))return g({state:o,stream:null}),function(){};var v=a[s];v&&v.whep!==m&&(f(v),v=void 0),v||(v=function(t,s){var l={sourceId:t,whep:s,snapshot:{state:o,stream:null},listeners:[],stopTimer:null,pendingStream:null,player:null};return l.player=new i.WhepPlayer({fetchToken:function(){return e.__awaiter(void 0,void 0,void 0,function(){var n;return e.__generator(this,function(r){switch(r.label){case 0:return[4,c(t)];case 1:return n=r.sent(),[2,e.__assign(e.__assign({},n),{whep:n.whep||s||""})]}})})},resolveUrl:n.getWhepUrl,pending:u[t]=u[t]||new Set,onStateChange:function(e){if(a[t]===l){var n=l.snapshot.stream;"playing"===e.status&&l.pendingStream&&(n=l.pendingStream,l.pendingStream=null),l.snapshot={state:e,stream:n},h(l),r.eventDispatch("phone-island-streaming-video-status",{source:t,status:e.status,failure:e.failure})}},onStream:function(n){a[t]===l&&(n&&l.snapshot.stream&&"playing"!==l.snapshot.state.status?l.pendingStream=n===l.snapshot.stream?null:n:(l.pendingStream=null,l.snapshot.stream!==n&&(l.snapshot=e.__assign(e.__assign({},l.snapshot),{stream:n}),h(l))))}}),l}(s,m),a[s]=v,l||(l=t.store.subscribe(function(){Object.keys(a).forEach(function(e){p(e)||f(a[e])})})),v.player.start()),d(v),v.listeners.push(g),g(v.snapshot);var S=v,w=!1;return function(){w||(w=!0,S.listeners=S.listeners.filter(function(e){return e!==g}),S.listeners.length||a[s]!==S||(p(s)?(d(S),S.stopTimer=setTimeout(function(){S.stopTimer=null,S.listeners.length||f(S)},1500)):f(S)))}};
2
+ //# sourceMappingURL=streamingVideo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streamingVideo.js","sources":["../../../src/lib/streaming/streamingVideo.ts"],"sourcesContent":["// Copyright (C) 2025 Nethesis S.r.l.\n// SPDX-License-Identifier: AGPL-3.0-or-later\n\n/**\n * Live video sessions of the \"rtsp\" video sources (door intercoms).\n *\n * One WHEP session per source is shared by all the views showing it: the incoming call preview\n * and the answered streaming view may be mounted at the same time during the island transitions\n * (and twice in React strict mode), but the gateway sees a single session per call.\n *\n * The device is pulled over the customer uplink only while someone watches: the session is\n * closed when the last view releases it, after a short grace time that bridges the switch\n * between two views of the same call, or at once when the streaming call is over.\n * Sessions are only opened for the source of the current streaming call.\n */\n\nimport { store } from '../../store'\nimport { getStreamingToken, getWhepUrl, StreamingRequestError } from '../../services/user'\nimport { eventDispatch } from '../../utils/genericFunctions/eventDispatch'\nimport { findVideoSourceByNumber } from '../../utils/streaming/videoSource'\nimport { WhepPlayer, WhepPlayerState, WhepToken, WhepTokenError } from './whepPlayer'\n\n// Bridges the island view changes of the same call (incoming preview -> answered view)\nconst RELEASE_GRACE_MS = 1500\n\nexport interface StreamingVideoSnapshot {\n state: WhepPlayerState\n stream: MediaStream | null\n}\n\ntype Listener = (snapshot: StreamingVideoSnapshot) => void\n\ninterface Entry {\n sourceId: string\n whep: string | null\n player: WhepPlayer\n snapshot: StreamingVideoSnapshot\n listeners: Listener[]\n stopTimer: ReturnType<typeof setTimeout> | null\n // stream of a reconnection, shown once it decodes its first frame (meanwhile the views keep\n // the last frame of the previous one instead of turning black)\n pendingStream: MediaStream | null\n}\n\nexport const initialStreamingVideoState: WhepPlayerState = {\n status: 'connecting',\n failure: null,\n hasAudio: false,\n}\n\nconst entries: Record<string, Entry> = {}\n// WHEP requests in flight per source, outliving the entries: the player of a new entry waits\n// for those of the stopped one (e.g. its POST still in flight), one gateway session at a time\nconst pendingRequests: Record<string, Set<Promise<void>>> = {}\nlet unsubscribeStore: (() => void) | null = null\n\n// Token provider of a source, using the CTI REST API\nexport const fetchStreamingToken = async (sourceId: string): Promise<WhepToken> => {\n try {\n const data = await getStreamingToken(sourceId)\n return { token: data.token, whep: data.whep, expiresIn: data.expires_in }\n } catch (error) {\n const status = error instanceof StreamingRequestError ? error.status : undefined\n if (status === 403) {\n throw new WhepTokenError('streaming token forbidden', true, 'forbidden')\n }\n if (status === 400 || status === 404) {\n throw new WhepTokenError(`streaming token error ${status}`, true, 'error')\n }\n // network errors, 5xx: retry\n throw new WhepTokenError(`streaming token error ${status ?? ''}`, false, 'unreachable')\n }\n}\n\n// True while the current call is a streaming call from (or to) the given source\nconst isStreamingCallOf = (sourceId: string) => {\n const state = store.getState()\n if (!state.island.isFromStreaming) return false\n const source = findVideoSourceByNumber(\n state.streaming.videoSources,\n state.currentCall.streamingSourceNumber,\n )\n return source?.id === sourceId\n}\n\nconst notify = (entry: Entry) => {\n entry.listeners.slice().forEach((listener) => listener(entry.snapshot))\n}\n\nconst createEntry = (sourceId: string, whep: string | null): Entry => {\n const entry: Entry = {\n sourceId,\n whep,\n snapshot: { state: initialStreamingVideoState, stream: null },\n listeners: [],\n stopTimer: null,\n pendingStream: null,\n player: null as unknown as WhepPlayer,\n }\n entry.player = new WhepPlayer({\n fetchToken: async () => {\n const token = await fetchStreamingToken(sourceId)\n // the WHEP path returned with the token wins over the one of the sources list\n return { ...token, whep: token.whep || whep || '' }\n },\n resolveUrl: getWhepUrl,\n pending: (pendingRequests[sourceId] = pendingRequests[sourceId] || new Set()),\n onStateChange: (state) => {\n if (entries[sourceId] !== entry) return\n let stream = entry.snapshot.stream\n if (state.status === 'playing' && entry.pendingStream) {\n stream = entry.pendingStream\n entry.pendingStream = null\n }\n entry.snapshot = { state, stream }\n notify(entry)\n eventDispatch('phone-island-streaming-video-status', {\n source: sourceId,\n status: state.status,\n failure: state.failure,\n })\n },\n onStream: (stream) => {\n if (entries[sourceId] !== entry) return\n if (stream && entry.snapshot.stream && entry.snapshot.state.status !== 'playing') {\n // reconnecting: keep the last frame until the new stream plays\n entry.pendingStream = stream === entry.snapshot.stream ? null : stream\n return\n }\n entry.pendingStream = null\n if (entry.snapshot.stream === stream) return\n entry.snapshot = { ...entry.snapshot, stream }\n notify(entry)\n },\n })\n return entry\n}\n\nconst clearStopTimer = (entry: Entry) => {\n if (entry.stopTimer) {\n clearTimeout(entry.stopTimer)\n entry.stopTimer = null\n }\n}\n\n// Closes the sessions as soon as their streaming call is over, whatever ended it\n// (local or remote hangup, call rejected, island reset...)\nconst watchCallEnd = () => {\n if (unsubscribeStore) return\n unsubscribeStore = store.subscribe(() => {\n Object.keys(entries).forEach((id) => {\n if (!isStreamingCallOf(id)) stopEntry(entries[id])\n })\n })\n}\n\nconst stopEntry = (entry: Entry) => {\n clearStopTimer(entry)\n if (entries[entry.sourceId] === entry) {\n delete entries[entry.sourceId]\n }\n if (!Object.keys(entries).length && unsubscribeStore) {\n unsubscribeStore()\n unsubscribeStore = null\n }\n // DELETE of the gateway session, then close of the peer connection\n entry.player.stop()\n if (entry.listeners.length) {\n entry.snapshot = { state: initialStreamingVideoState, stream: null }\n notify(entry)\n }\n}\n\n/**\n * Watches the live video of a source: starts its session (or joins the running one) and calls\n * the listener on every change. Returns the function to stop watching.\n */\nexport const watchStreamingVideo = (\n sourceId: string,\n whep: string | null,\n listener: Listener,\n): (() => void) => {\n if (!isStreamingCallOf(sourceId)) {\n listener({ state: initialStreamingVideoState, stream: null })\n return () => {}\n }\n let entry = entries[sourceId]\n if (entry && entry.whep !== whep) {\n // the source was reconfigured\n stopEntry(entry)\n entry = undefined as unknown as Entry\n }\n if (!entry) {\n entry = createEntry(sourceId, whep)\n entries[sourceId] = entry\n watchCallEnd()\n entry.player.start()\n }\n clearStopTimer(entry)\n entry.listeners.push(listener)\n listener(entry.snapshot)\n\n const current = entry\n let released = false\n return () => {\n if (released) return\n released = true\n current.listeners = current.listeners.filter((l) => l !== listener)\n if (current.listeners.length || entries[sourceId] !== current) return\n if (isStreamingCallOf(sourceId)) {\n // another view of the same call may take it over\n clearStopTimer(current)\n current.stopTimer = setTimeout(() => {\n current.stopTimer = null\n if (!current.listeners.length) stopEntry(current)\n }, RELEASE_GRACE_MS)\n } else {\n stopEntry(current)\n }\n }\n}\n\n/**\n * Closes the live video session of a source, or of all the sources (e.g. when the call ends)\n */\nexport const stopStreamingVideo = (sourceId?: string) => {\n Object.keys(entries).forEach((id) => {\n if (sourceId === undefined || id === sourceId) {\n stopEntry(entries[id])\n }\n })\n}\n\n/**\n * The live video sessions currently open (debug)\n */\nexport const getStreamingVideoSessions = () =>\n Object.keys(entries).map((id) => ({\n source: id,\n status: entries[id].snapshot.state.status,\n viewers: entries[id].listeners.length,\n }))\n"],"names":["initialStreamingVideoState","status","failure","hasAudio","entries","pendingRequests","unsubscribeStore","fetchStreamingToken","sourceId","__awaiter","getStreamingToken","token","data","_a","sent","whep","expiresIn","expires_in","status_1","error_1","StreamingRequestError","undefined","WhepTokenError","concat","isStreamingCallOf","state","store","getState","island","isFromStreaming","source","findVideoSourceByNumber","streaming","videoSources","currentCall","streamingSourceNumber","id","notify","entry","listeners","slice","forEach","listener","snapshot","clearStopTimer","stopTimer","clearTimeout","stopEntry","Object","keys","length","player","stop","stream","pendingStream","WhepPlayer","fetchToken","__assign","resolveUrl","getWhepUrl","pending","Set","onStateChange","eventDispatch","onStream","createEntry","subscribe","start","push","current","released","filter","l","setTimeout"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t=require("../../node_modules/tslib/tslib.es6.js"),e=function(e){function n(t,i,s){void 0===s&&(s="error");var r=e.call(this,t)||this;return r.name="WhepTokenError",r.permanent=i,r.failure=s,Object.setPrototypeOf(r,n.prototype),r}return t.__extends(n,e),n}(Error),n=function(){function n(t){this.state={status:"connecting",failure:null,hasAudio:!1},this.running=!1,this.generation=0,this.session=null,this.token=null,this.retryTimer=null,this.watchdogTimer=null,this.stableTimer=null,this.failures=0,this.consecutiveUnauthorized=0,this.hasPlayed=!1,this.opts=t,this.pending=t.pending||new Set}return n.prototype.start=function(){this.running||(this.running=!0,this.failures=0,this.consecutiveUnauthorized=0,this.hasPlayed=!1,this.setState({status:"connecting",failure:null}),this.connect())},n.prototype.stop=function(){this.running&&(this.running=!1,this.clearRetry(),this.teardown(),this.opts.onStream(null))},n.prototype.getState=function(){return this.state},n.prototype.log=function(){for(var e=[],n=0;n<arguments.length;n++)e[n]=arguments[n];this.opts.debug&&console.debug.apply(console,t.__spreadArray(["[whep]"],e,!1))},n.prototype.setState=function(e){var n=t.__assign(t.__assign({},this.state),e);n.status===this.state.status&&n.failure===this.state.failure&&n.hasAudio===this.state.hasAudio||(this.state=n,this.opts.onStateChange(n))},n.prototype.clearRetry=function(){this.retryTimer&&(clearTimeout(this.retryTimer),this.retryTimer=null)},n.prototype.getToken=function(){return t.__awaiter(this,void 0,void 0,function(){var e,n;return t.__generator(this,function(t){switch(t.label){case 0:return this.token&&this.token.expiresAt>Date.now()?[2,this.token]:[4,this.opts.fetchToken()];case 1:return e=t.sent(),n=Math.max(0,1e3*(e.expiresIn||0)-5e3),this.token={value:e.token,whep:e.whep,expiresAt:Date.now()+n},[2,this.token]}})})},n.prototype.connect=function(){return t.__awaiter(this,void 0,void 0,function(){var n,i,s,r,a,o,u,c,l,h,f,p,d,g,m,y,v=this;return t.__generator(this,function(T){switch(T.label){case 0:this.clearRetry(),this.teardown(),n=++this.generation,i=function(){return v.running&&n===v.generation},T.label=1;case 1:return T.trys.push([1,3,,4]),[4,this.getToken()];case 2:return s=T.sent(),[3,4];case 3:return r=T.sent(),i()?(r instanceof e&&r.permanent?(this.log("token error, giving up",r.message),this.fail(r.failure,!1)):(this.log("token error, retrying",r),this.fail("unreachable",!0)),[2]):[2];case 4:if(!i())return[2];a=new RTCPeerConnection({bundlePolicy:"max-bundle"}),o=new MediaStream,u={pc:a,location:null,token:s.value,stream:o},this.session=u,a.addTransceiver("video",{direction:"recvonly"}),a.addTransceiver("audio",{direction:"recvonly"}),a.ontrack=function(t){i()&&(o.addTrack(t.track),"audio"===t.track.kind&&v.setState({hasAudio:!0}),v.opts.onStream(o))},a.onconnectionstatechange=function(){i()&&(v.log("connection state",a.connectionState),"failed"===a.connectionState&&v.fail("unreachable",!0))},T.label=5;case 5:return T.trys.push([5,15,,16]),l=(c=a).setLocalDescription,[4,a.createOffer()];case 6:return[4,l.apply(c,[T.sent()])];case 7:return T.sent(),[4,this.waitIceGathering(a)];case 8:return T.sent(),[4,this.settle()];case 9:return T.sent(),i()?(h=t.__awaiter(v,void 0,void 0,function(){var e,n,r,o,c,l;return t.__generator(this,function(t){switch(t.label){case 0:e=new AbortController,n=setTimeout(function(){return e.abort()},15e3),t.label=1;case 1:return t.trys.push([1,,3,4]),[4,fetch(this.opts.resolveUrl(s.whep),{method:"POST",headers:{"Content-Type":"application/sdp",Authorization:"Bearer ".concat(s.value)},body:null===(l=a.localDescription)||void 0===l?void 0:l.sdp,signal:e.signal})];case 2:return r=t.sent(),[3,4];case 3:return clearTimeout(n),[7];case 4:return o=r.headers.get("Location"),c=201!==r.status&&200!==r.status||!o?null:new URL(o,r.url).toString(),i()?[3,7]:(this.log("stale WHEP answer, closing its session"),c?[4,this.deleteSession(c,s.value)]:[3,6]);case 5:t.sent(),t.label=6;case 6:return[2,null];case 7:return u.location=c,[2,r]}})}),this.track(h),[4,h]):[2];case 10:return(f=T.sent())&&i()?401===f.status?(this.token=null,this.consecutiveUnauthorized++,this.log("401 from the gateway"),1===this.consecutiveUnauthorized?this.connect():this.fail("unreachable",!0),[2]):(this.consecutiveUnauthorized=0,201===f.status||200===f.status?[3,12]:[4,f.text().catch(function(){return""})]):[2];case 11:if(p=T.sent(),!i())return[2];d=p;try{d=(null===(y=JSON.parse(p))||void 0===y?void 0:y.error)||p}catch(t){}return this.log("gateway error",f.status,d),400===f.status&&/codec/i.test(d)?this.fail("codec",!1):this.fail("unreachable",!0),[2];case 12:return[4,f.text()];case 13:return g=T.sent(),i()?[4,a.setRemoteDescription({type:"answer",sdp:g})]:[2];case 14:return T.sent(),[3,16];case 15:return m=T.sent(),i()?(this.log("connect error",m),this.fail("unreachable",!0),[2]):[2];case 16:return i()?(this.startWatchdog(n,a),[2]):[2]}})})},n.prototype.waitIceGathering=function(t){return new Promise(function(e){if("complete"!==t.iceGatheringState){var n=setTimeout(i,1e3);t.addEventListener("icegatheringstatechange",s)}else e();function i(){clearTimeout(n),t.removeEventListener("icegatheringstatechange",s),e()}function s(){"complete"===t.iceGatheringState&&i()}})},n.prototype.startWatchdog=function(e,n){var i=this,s=Date.now(),r=0,a=s,o=function(){return t.__awaiter(i,void 0,void 0,function(){var i,u;return t.__generator(this,function(t){switch(t.label){case 0:i=r,t.label=1;case 1:return t.trys.push([1,3,,4]),[4,n.getStats()];case 2:return t.sent().forEach(function(t){"inbound-rtp"===t.type&&"video"===t.kind&&(i=t.framesDecoded||0)}),[3,4];case 3:return t.sent(),[3,4];case 4:if(!this.running||e!==this.generation)return[2];if(u=Date.now(),i>r)r=i,a=u,"playing"!==this.state.status&&this.onPlaying();else if(0===r){if(u-s>8e3)return this.log("no first frame"),this.fail("unreachable",!0),[2]}else if(u-a>3e3)return this.log("stream stalled"),this.token=null,this.fail("unreachable",!0),[2];return this.watchdogTimer=setTimeout(o,0===r?200:1e3),[2]}})})};this.watchdogTimer=setTimeout(o,200)},n.prototype.onPlaying=function(){var t=this;this.hasPlayed=!0,this.setState({status:"playing",failure:null}),this.stableTimer&&clearTimeout(this.stableTimer),this.stableTimer=setTimeout(function(){t.stableTimer=null,t.failures=0},1e4)},n.prototype.fail=function(t,e){var n=this;if(this.teardown(),e){this.failures++,this.hasPlayed&&this.failures<=3?this.setState({status:"reconnecting",failure:null}):this.setState({status:"unavailable",failure:t});var i=Math.min(3e4,1e3*Math.pow(2,this.failures-1))*(.8+.4*Math.random());this.log("retry in ".concat(Math.round(i)," ms (failure ").concat(this.failures,")")),this.clearRetry(),this.retryTimer=setTimeout(function(){n.retryTimer=null,n.running&&n.connect()},i)}else this.setState({status:"unavailable",failure:t})},n.prototype.track=function(t){var e=this,n=t.then(function(){e.pending.delete(n)},function(){e.pending.delete(n)});this.pending.add(n)},n.prototype.settle=function(){return t.__awaiter(this,void 0,void 0,function(){return t.__generator(this,function(t){switch(t.label){case 0:return this.pending.size?[4,Promise.all(Array.from(this.pending))]:[3,2];case 1:return t.sent(),[3,0];case 2:return[2]}})})},n.prototype.deleteSession=function(t,e){return new Promise(function(n){var i=setTimeout(n,1e3);fetch(t,{method:"DELETE",headers:{Authorization:"Bearer ".concat(e)},keepalive:!0}).catch(function(){}).finally(function(){clearTimeout(i),n()})})},n.prototype.teardown=function(){this.generation++,this.watchdogTimer&&(clearTimeout(this.watchdogTimer),this.watchdogTimer=null),this.stableTimer&&(clearTimeout(this.stableTimer),this.stableTimer=null);var t=this.session;if(this.session=null,t)if(t.pc.ontrack=null,t.pc.onconnectionstatechange=null,t.location){var e=this.deleteSession(t.location,t.token).then(function(){return t.pc.close()});this.track(e)}else t.pc.close()},n}();exports.WhepPlayer=n,exports.WhepTokenError=e;
2
+ //# sourceMappingURL=whepPlayer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whepPlayer.js","sources":["../../../src/lib/streaming/whepPlayer.ts"],"sourcesContent":["// Copyright (C) 2025 Nethesis S.r.l.\n// SPDX-License-Identifier: AGPL-3.0-or-later\n\n/**\n * Minimal, dependency-free WHEP (WebRTC-HTTP Egress Protocol) player.\n *\n * It receives a one-way (recvonly) video + audio stream from the video gateway and hands the\n * MediaStream to its owner (which attaches it to one or more <video> elements). The gateway\n * gives no signal when the device drops or the session is revoked (frames just stop), so the\n * player watches the decoded frames itself and reconnects with a fresh token and an exponential\n * backoff.\n *\n * Same logic and timings as the player of the NethVoice CTI web client.\n */\n\nexport type WhepPlayerStatus = 'connecting' | 'playing' | 'reconnecting' | 'unavailable'\n\n// unreachable: the gateway could not pull the device (it keeps retrying)\n// codec: the browser cannot decode the stream (no retry)\n// forbidden: the user is not allowed to watch the source (no retry)\n// error: any other permanent error (no retry)\nexport type WhepPlayerFailure = 'unreachable' | 'codec' | 'forbidden' | 'error'\n\nexport interface WhepPlayerState {\n status: WhepPlayerStatus\n failure: WhepPlayerFailure | null\n hasAudio: boolean\n}\n\nexport interface WhepToken {\n token: string\n // WHEP endpoint path (or absolute URL) returned with the token\n whep: string\n // token validity in seconds\n expiresIn: number\n}\n\n// Thrown by the token provider: permanent errors stop the retries\nexport class WhepTokenError extends Error {\n permanent: boolean\n failure: WhepPlayerFailure\n\n constructor(message: string, permanent: boolean, failure: WhepPlayerFailure = 'error') {\n super(message)\n this.name = 'WhepTokenError'\n this.permanent = permanent\n this.failure = failure\n // keep instanceof working with the ES5 build target\n Object.setPrototypeOf(this, WhepTokenError.prototype)\n }\n}\n\nexport interface WhepPlayerOptions {\n fetchToken: () => Promise<WhepToken>\n // turns the WHEP path into an absolute URL\n resolveUrl: (path: string) => string\n onStateChange: (state: WhepPlayerState) => void\n // the stream of the current session, null when stopped. The stream of a reconnection\n // replaces the previous one only when its first track arrives (the last frame stays visible)\n onStream: (stream: MediaStream | null) => void\n // WHEP requests still in flight, shared by the players of the same source so that a new\n // player waits for the ones of the player it replaces (at most one gateway session per source)\n pending?: Set<Promise<void>>\n debug?: boolean\n}\n\n// Max wait for the local ICE gathering before sending the offer (host candidates are enough)\nconst ICE_GATHERING_TIMEOUT_MS = 1000\n// The gateway waits up to 10 s for an unreachable device before answering\nconst WHEP_REQUEST_TIMEOUT_MS = 15000\n// First frame usually arrives 0.6-1.5 s after the answer\nconst FIRST_FRAME_TIMEOUT_MS = 8000\nconst FIRST_FRAME_POLL_MS = 200\n// No new decoded frame for this long means the stream is stalled\nconst STALL_TIMEOUT_MS = 3000\nconst WATCHDOG_INTERVAL_MS = 1000\n// Reconnect backoff: 1 s, 2 s, 4 s, 8 s, 16 s, 30 s, 30 s... with +/-20% jitter\nconst BACKOFF_BASE_MS = 1000\nconst BACKOFF_MAX_MS = 30000\n// Playing this long resets the backoff\nconst STABLE_PLAYING_MS = 10000\n// Consecutive failures shown as \"reconnecting\" before showing \"unavailable\"\nconst MAX_RECONNECTING_FAILURES = 3\n// Max wait for the DELETE of a session before closing its connection anyway\nconst DELETE_CLOSE_TIMEOUT_MS = 1000\n// Renew the token a bit before it expires\nconst TOKEN_EXPIRY_MARGIN_MS = 5000\n\ninterface WhepSession {\n pc: RTCPeerConnection\n location: string | null\n token: string\n stream: MediaStream\n}\n\nexport class WhepPlayer {\n private readonly opts: WhepPlayerOptions\n private state: WhepPlayerState = { status: 'connecting', failure: null, hasAudio: false }\n private running = false\n // incremented on every new attempt or teardown, async steps of older attempts are dropped\n private generation = 0\n private session: WhepSession | null = null\n private token: { value: string; whep: string; expiresAt: number } | null = null\n // WHEP requests that may still create or free a gateway session: a new offer waits for them\n private readonly pending: Set<Promise<void>>\n private retryTimer: ReturnType<typeof setTimeout> | null = null\n private watchdogTimer: ReturnType<typeof setTimeout> | null = null\n private stableTimer: ReturnType<typeof setTimeout> | null = null\n private failures = 0\n private consecutiveUnauthorized = 0\n private hasPlayed = false\n\n constructor(opts: WhepPlayerOptions) {\n this.opts = opts\n this.pending = opts.pending || new Set()\n }\n\n start() {\n if (this.running) return\n this.running = true\n this.failures = 0\n this.consecutiveUnauthorized = 0\n this.hasPlayed = false\n this.setState({ status: 'connecting', failure: null })\n this.connect()\n }\n\n stop() {\n if (!this.running) return\n this.running = false\n this.clearRetry()\n this.teardown()\n this.opts.onStream(null)\n }\n\n getState() {\n return this.state\n }\n\n private log(...args: any[]) {\n if (this.opts.debug) console.debug('[whep]', ...args)\n }\n\n private setState(patch: Partial<WhepPlayerState>) {\n const next = { ...this.state, ...patch }\n if (\n next.status === this.state.status &&\n next.failure === this.state.failure &&\n next.hasAudio === this.state.hasAudio\n ) {\n return\n }\n this.state = next\n this.opts.onStateChange(next)\n }\n\n private clearRetry() {\n if (this.retryTimer) {\n clearTimeout(this.retryTimer)\n this.retryTimer = null\n }\n }\n\n private async getToken(): Promise<{ value: string; whep: string }> {\n if (this.token && this.token.expiresAt > Date.now()) {\n return this.token\n }\n const t = await this.opts.fetchToken()\n const ttlMs = Math.max(0, (t.expiresIn || 0) * 1000 - TOKEN_EXPIRY_MARGIN_MS)\n this.token = { value: t.token, whep: t.whep, expiresAt: Date.now() + ttlMs }\n return this.token\n }\n\n private async connect() {\n this.clearRetry()\n this.teardown()\n const gen = ++this.generation\n const isCurrent = () => this.running && gen === this.generation\n\n let token: { value: string; whep: string }\n try {\n token = await this.getToken()\n } catch (error) {\n if (!isCurrent()) return\n if (error instanceof WhepTokenError && error.permanent) {\n this.log('token error, giving up', error.message)\n this.fail(error.failure, false)\n } else {\n this.log('token error, retrying', error)\n this.fail('unreachable', true)\n }\n return\n }\n if (!isCurrent()) return\n\n const pc = new RTCPeerConnection({ bundlePolicy: 'max-bundle' })\n const stream = new MediaStream()\n const session: WhepSession = { pc, location: null, token: token.value, stream }\n this.session = session\n pc.addTransceiver('video', { direction: 'recvonly' })\n pc.addTransceiver('audio', { direction: 'recvonly' })\n pc.ontrack = (event) => {\n if (!isCurrent()) return\n stream.addTrack(event.track)\n if (event.track.kind === 'audio') {\n this.setState({ hasAudio: true })\n }\n this.opts.onStream(stream)\n }\n pc.onconnectionstatechange = () => {\n if (!isCurrent()) return\n this.log('connection state', pc.connectionState)\n if (pc.connectionState === 'failed') {\n this.fail('unreachable', true)\n }\n }\n\n try {\n await pc.setLocalDescription(await pc.createOffer())\n await this.waitIceGathering(pc)\n // at most one gateway session per player: let the previous requests settle first\n await this.settle()\n if (!isCurrent()) return\n\n // The POST is never aborted by a teardown: the gateway creates the session before\n // answering, and without its Location it could not be deleted. A stale answer frees it.\n const exchange = (async () => {\n const abort = new AbortController()\n const abortTimer = setTimeout(() => abort.abort(), WHEP_REQUEST_TIMEOUT_MS)\n let response: Response\n try {\n response = await fetch(this.opts.resolveUrl(token.whep), {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/sdp',\n Authorization: `Bearer ${token.value}`,\n },\n body: pc.localDescription?.sdp,\n signal: abort.signal,\n })\n } finally {\n clearTimeout(abortTimer)\n }\n const location = response.headers.get('Location')\n const created =\n (response.status === 201 || response.status === 200) && location\n ? new URL(location, response.url).toString()\n : null\n if (!isCurrent()) {\n this.log('stale WHEP answer, closing its session')\n if (created) await this.deleteSession(created, token.value)\n return null\n }\n // from now on the teardown deletes it\n session.location = created\n return response\n })()\n this.track(exchange)\n const response = await exchange\n if (!response || !isCurrent()) return\n\n if (response.status === 401) {\n // token expired or revoked: get a new one, retry at once only the first time\n this.token = null\n this.consecutiveUnauthorized++\n this.log('401 from the gateway')\n if (this.consecutiveUnauthorized === 1) {\n this.connect()\n } else {\n this.fail('unreachable', true)\n }\n return\n }\n this.consecutiveUnauthorized = 0\n\n if (response.status !== 201 && response.status !== 200) {\n const body = await response.text().catch(() => '')\n if (!isCurrent()) return\n let message = body\n try {\n message = JSON.parse(body)?.error || body\n } catch {\n // not JSON\n }\n this.log('gateway error', response.status, message)\n if (response.status === 400 && /codec/i.test(message)) {\n this.fail('codec', false)\n } else {\n this.fail('unreachable', true)\n }\n return\n }\n\n const answer = await response.text()\n if (!isCurrent()) return\n await pc.setRemoteDescription({ type: 'answer', sdp: answer })\n } catch (error) {\n if (!isCurrent()) return\n // network errors, timeouts, an answer the browser cannot accept\n this.log('connect error', error)\n this.fail('unreachable', true)\n return\n }\n if (!isCurrent()) return\n this.startWatchdog(gen, pc)\n }\n\n private waitIceGathering(pc: RTCPeerConnection) {\n return new Promise<void>((resolve) => {\n if (pc.iceGatheringState === 'complete') {\n resolve()\n return\n }\n const timer = setTimeout(done, ICE_GATHERING_TIMEOUT_MS)\n function done() {\n clearTimeout(timer)\n pc.removeEventListener('icegatheringstatechange', onChange)\n resolve()\n }\n function onChange() {\n if (pc.iceGatheringState === 'complete') done()\n }\n pc.addEventListener('icegatheringstatechange', onChange)\n })\n }\n\n // Polls the decoded frames: fast until the first frame (to show it at once), then every second\n private startWatchdog(gen: number, pc: RTCPeerConnection) {\n const startedAt = Date.now()\n let lastFrames = 0\n let lastProgressAt = startedAt\n\n const tick = async () => {\n let frames = lastFrames\n try {\n const stats = await pc.getStats()\n stats.forEach((report: any) => {\n if (report.type === 'inbound-rtp' && report.kind === 'video') {\n frames = report.framesDecoded || 0\n }\n })\n } catch {\n // the connection was closed meanwhile\n }\n if (!this.running || gen !== this.generation) return\n\n const now = Date.now()\n if (frames > lastFrames) {\n lastFrames = frames\n lastProgressAt = now\n if (this.state.status !== 'playing') this.onPlaying()\n } else if (lastFrames === 0) {\n if (now - startedAt > FIRST_FRAME_TIMEOUT_MS) {\n this.log('no first frame')\n this.fail('unreachable', true)\n return\n }\n } else if (now - lastProgressAt > STALL_TIMEOUT_MS) {\n this.log('stream stalled')\n // the session may have been revoked: do not reuse the token\n this.token = null\n this.fail('unreachable', true)\n return\n }\n this.watchdogTimer = setTimeout(\n tick,\n lastFrames === 0 ? FIRST_FRAME_POLL_MS : WATCHDOG_INTERVAL_MS,\n )\n }\n this.watchdogTimer = setTimeout(tick, FIRST_FRAME_POLL_MS)\n }\n\n private onPlaying() {\n this.hasPlayed = true\n this.setState({ status: 'playing', failure: null })\n if (this.stableTimer) clearTimeout(this.stableTimer)\n this.stableTimer = setTimeout(() => {\n this.stableTimer = null\n this.failures = 0\n }, STABLE_PLAYING_MS)\n }\n\n private fail(failure: WhepPlayerFailure, retry: boolean) {\n this.teardown()\n if (!retry) {\n this.setState({ status: 'unavailable', failure })\n return\n }\n this.failures++\n if (this.hasPlayed && this.failures <= MAX_RECONNECTING_FAILURES) {\n this.setState({ status: 'reconnecting', failure: null })\n } else {\n this.setState({ status: 'unavailable', failure })\n }\n const delay =\n Math.min(BACKOFF_MAX_MS, BACKOFF_BASE_MS * 2 ** (this.failures - 1)) *\n (0.8 + Math.random() * 0.4)\n this.log(`retry in ${Math.round(delay)} ms (failure ${this.failures})`)\n this.clearRetry()\n this.retryTimer = setTimeout(() => {\n this.retryTimer = null\n if (this.running) this.connect()\n }, delay)\n }\n\n // Keeps a request in `pending` until it settles\n private track(request: Promise<unknown>) {\n const settled: Promise<void> = request.then(\n () => {\n this.pending.delete(settled)\n },\n () => {\n this.pending.delete(settled)\n },\n )\n this.pending.add(settled)\n }\n\n private async settle() {\n while (this.pending.size) {\n await Promise.all(Array.from(this.pending))\n }\n }\n\n // DELETE of a gateway session (keepalive survives a page unload), settles in at most\n // DELETE_CLOSE_TIMEOUT_MS\n private deleteSession(location: string, token: string) {\n return new Promise<void>((resolve) => {\n const timer = setTimeout(resolve, DELETE_CLOSE_TIMEOUT_MS)\n fetch(location, {\n method: 'DELETE',\n headers: { Authorization: `Bearer ${token}` },\n keepalive: true,\n })\n .catch(() => {})\n .finally(() => {\n clearTimeout(timer)\n resolve()\n })\n })\n }\n\n // Close the current session (if any) and invalidate its pending async steps\n private teardown() {\n this.generation++\n if (this.watchdogTimer) {\n clearTimeout(this.watchdogTimer)\n this.watchdogTimer = null\n }\n if (this.stableTimer) {\n clearTimeout(this.stableTimer)\n this.stableTimer = null\n }\n const session = this.session\n this.session = null\n if (!session) return\n\n session.pc.ontrack = null\n session.pc.onconnectionstatechange = null\n // the views keep showing the last frame while reconnecting\n // no Location yet: an in-flight POST deletes its session when it completes\n if (!session.location) {\n session.pc.close()\n return\n }\n // free the gateway session at once, then close the connection: closing it first makes the\n // gateway drop the session before the DELETE arrives\n const deleted = this.deleteSession(session.location, session.token).then(() =>\n session.pc.close(),\n )\n this.track(deleted)\n }\n}\n"],"names":["WhepTokenError","_super","message","permanent","failure","_this","call","this","name","Object","setPrototypeOf","prototype","__extends","Error","WhepPlayer","opts","state","status","hasAudio","running","generation","session","token","retryTimer","watchdogTimer","stableTimer","failures","consecutiveUnauthorized","hasPlayed","pending","Set","start","setState","connect","stop","clearRetry","teardown","onStream","getState","log","args","_i","arguments","length","debug","console","apply","patch","next","onStateChange","clearTimeout","getToken","expiresAt","Date","now","fetchToken","t","_a","sent","ttlMs","Math","max","expiresIn","value","whep","gen","isCurrent","_d","error_1","fail","pc","RTCPeerConnection","bundlePolicy","stream","MediaStream","location","addTransceiver","direction","ontrack","event","addTrack","track","kind","onconnectionstatechange","connectionState","_b","setLocalDescription","createOffer","waitIceGathering","settle","exchange","__awaiter","abort","AbortController","abortTimer","setTimeout","fetch","resolveUrl","method","headers","Authorization","concat","body","localDescription","sdp","signal","response","get","created","URL","url","toString","deleteSession","text","catch","_c","JSON","parse","error","_e","test","answer","setRemoteDescription","type","error_2","startWatchdog","Promise","resolve","iceGatheringState","timer","done","addEventListener","onChange","removeEventListener","startedAt","lastFrames","lastProgressAt","tick","frames","getStats","forEach","report","framesDecoded","onPlaying","retry","delay","min","random","round","request","settled","then","delete","add","size","all","Array","from","keepalive","finally","deleted","close"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("../node_modules/tslib/tslib.es6.js"),n=require("../node_modules/@rematch/core/dist/core.esm.js"),r=require("../events/CallEvents.js");require("react");var t=require("../utils/genericFunctions/eventDispatch.js");require("../store/index.js"),require("../node_modules/react-redux/es/index.js");var i={displayName:"",username:"",number:"",incomingSocket:!1,incomingWebRTC:!1,incoming:!1,acceptedSocket:!1,acceptedWebRTC:!1,accepted:!1,outgoingSocket:!1,outgoingWebRTC:!1,parked:!1,outgoing:!1,startTime:"",muted:!1,paused:!1,keypadValue:"",conversationId:"",transferring:!1,conferencing:!1,transferringName:"",transferringNumber:"",transferringStartTime:"",transferSwitching:!1,transferCalls:new Array,ownerExtension:"",isRecording:!1,isLocalVideoEnabled:!1,showRemoteVideoPlaceHolder:!0,hasVideoTrackAdded:!1,isStartingVideoCall:!1,streamingSourceNumber:"",chDest:new Array,chSource:new Array,throughQueue:!1,queueId:"",queueName:"",queueNumber:"",queuePosition:"",queueWaitingTime:0,counterpartDeviceType:""},a=n.createModel()({state:i,reducers:{updateCurrentCall:function(n,r){return Number(r.startTime)&&n.startTime&&delete r.startTime,!1===r.throughQueue&&(r.queueId="",r.queueName="",r.queueNumber="",r.queuePosition="",r.queueWaitingTime=0),e.__assign(e.__assign(e.__assign({},n),r),{transferCalls:n.transferCalls})},updateKeypadValue:function(n,r){return e.__assign(e.__assign({},n),{keypadValue:r})},updateTransferring:function(n,r){return e.__assign(e.__assign({},n),{transferring:r})},updateTransferSwitching:function(n,r){return e.__assign(e.__assign({},n),{transferSwitching:r})},addTransferCalls:function(n,r){return n.transferCalls.find(function(e){return e.number===r.number})?n:e.__assign(e.__assign({},n),{transferCalls:e.__spreadArray(e.__spreadArray([],n.transferCalls,!0),[r],!1)})},deleteTransferCalls:function(n){return e.__assign(e.__assign({},n),{transferCalls:n.transferCalls.filter(function(e){return"transferred"!==e.type})})},setParked:function(e,n){return e.parked=n,e},updateRecordingStatus:function(e,n){return e.isRecording=n,e},updateStartTime:function(e,n){return e.startTime=n,e},updateIncoming:function(e,n){return e.incoming=n,e},reset:function(){return i},setLocalVideoEnabled:function(e,n){return e.isLocalVideoEnabled=n,e},setVideoTrackAdded:function(e,n){return e.hasVideoTrackAdded=n,e},updateConferencing:function(n,r){return e.__assign(e.__assign({},n),{conferencing:r})}},effects:function(n){return{checkIncomingUpdatePlay:function(r,t){var i,a,u,s,o,d,l,c;if("webrtc"===(null===(a=null===(i=null==t?void 0:t.currentUser)||void 0===i?void 0:i.default_device)||void 0===a?void 0:a.type)&&(null==r?void 0:r.incomingWebRTC)||"physical"===(null===(s=null===(u=null==t?void 0:t.currentUser)||void 0===u?void 0:u.default_device)||void 0===s?void 0:s.type)&&(null==r?void 0:r.incomingSocket)||"nethlink"===(null===(d=null===(o=null==t?void 0:t.currentUser)||void 0===o?void 0:o.default_device)||void 0===d?void 0:d.type)&&(null==r?void 0:r.incomingWebRTC)){r.incoming=!0;var g=t.ringtones?(null===(l=t.ringtones.availableRingtones.find(function(e){return e.name===t.ringtones.selectedRingtone}))||void 0===l?void 0:l.base64Audio)||(null===(c=t.ringtones.availableRingtones[0])||void 0===c?void 0:c.base64Audio):void 0;g&&n.player.updateStartAudioPlayer({src:g,loop:!0,useRingtoneOutput:!0})}n.currentCall.updateCurrentCall(e.__assign({},r))},checkOutgoingUpdate:function(t,i){var a,u,s;("webrtc"===(null===(a=i.currentUser.default_device)||void 0===a?void 0:a.type)&&t.outgoingWebRTC||"physical"===(null===(u=i.currentUser.default_device)||void 0===u?void 0:u.type)&&t.outgoingSocket||"nethlink"===(null===(s=i.currentUser.default_device)||void 0===s?void 0:s.type)&&t.outgoingWebRTC)&&(t.outgoing=!0,r.dispatchOutgoingCallStarted(t.displayName,t.number)),n.currentCall.updateCurrentCall(e.__assign({},t))},checkAcceptedUpdate:function(r,i){var a,u,s;("webrtc"===(null===(a=i.currentUser.default_device)||void 0===a?void 0:a.type)&&r.acceptedWebRTC||"physical"===(null===(u=i.currentUser.default_device)||void 0===u?void 0:u.type)&&r.acceptedSocket||"nethlink"===(null===(s=i.currentUser.default_device)||void 0===s?void 0:s.type)&&r.acceptedWebRTC)&&(r.accepted=!0,t.eventDispatch("phone-island-call-answered",{})),n.currentCall.updateCurrentCall(e.__assign({},r))}}}});exports.currentCall=a;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("../node_modules/tslib/tslib.es6.js"),n=require("../node_modules/@rematch/core/dist/core.esm.js"),r=require("../events/CallEvents.js");require("react");var t=require("../utils/genericFunctions/eventDispatch.js");require("../store/index.js"),require("../services/user.js"),require("../node_modules/react-redux/es/index.js");var i={displayName:"",username:"",number:"",incomingSocket:!1,incomingWebRTC:!1,incoming:!1,acceptedSocket:!1,acceptedWebRTC:!1,accepted:!1,answering:!1,outgoingSocket:!1,outgoingWebRTC:!1,parked:!1,outgoing:!1,startTime:"",muted:!1,paused:!1,keypadValue:"",conversationId:"",transferring:!1,conferencing:!1,transferringName:"",transferringNumber:"",transferringStartTime:"",transferSwitching:!1,transferCalls:new Array,ownerExtension:"",isRecording:!1,isLocalVideoEnabled:!1,showRemoteVideoPlaceHolder:!0,hasVideoTrackAdded:!1,isStartingVideoCall:!1,streamingSourceNumber:"",chDest:new Array,chSource:new Array,throughQueue:!1,queueId:"",queueName:"",queueNumber:"",queuePosition:"",queueWaitingTime:0,counterpartDeviceType:""},a=n.createModel()({state:i,reducers:{updateCurrentCall:function(n,r){return Number(r.startTime)&&n.startTime&&delete r.startTime,!1===r.throughQueue&&(r.queueId="",r.queueName="",r.queueNumber="",r.queuePosition="",r.queueWaitingTime=0),e.__assign(e.__assign(e.__assign({},n),r),{transferCalls:n.transferCalls})},updateKeypadValue:function(n,r){return e.__assign(e.__assign({},n),{keypadValue:r})},updateTransferring:function(n,r){return e.__assign(e.__assign({},n),{transferring:r})},updateTransferSwitching:function(n,r){return e.__assign(e.__assign({},n),{transferSwitching:r})},addTransferCalls:function(n,r){return n.transferCalls.find(function(e){return e.number===r.number})?n:e.__assign(e.__assign({},n),{transferCalls:e.__spreadArray(e.__spreadArray([],n.transferCalls,!0),[r],!1)})},deleteTransferCalls:function(n){return e.__assign(e.__assign({},n),{transferCalls:n.transferCalls.filter(function(e){return"transferred"!==e.type})})},setParked:function(e,n){return e.parked=n,e},updateRecordingStatus:function(e,n){return e.isRecording=n,e},updateStartTime:function(e,n){return e.startTime=n,e},updateIncoming:function(e,n){return e.incoming=n,e},reset:function(){return i},setLocalVideoEnabled:function(e,n){return e.isLocalVideoEnabled=n,e},setVideoTrackAdded:function(e,n){return e.hasVideoTrackAdded=n,e},updateConferencing:function(n,r){return e.__assign(e.__assign({},n),{conferencing:r})}},effects:function(n){return{checkIncomingUpdatePlay:function(r,t){var i,a,u,s,o,d,l,c;if("webrtc"===(null===(a=null===(i=null==t?void 0:t.currentUser)||void 0===i?void 0:i.default_device)||void 0===a?void 0:a.type)&&(null==r?void 0:r.incomingWebRTC)||"physical"===(null===(s=null===(u=null==t?void 0:t.currentUser)||void 0===u?void 0:u.default_device)||void 0===s?void 0:s.type)&&(null==r?void 0:r.incomingSocket)||"nethlink"===(null===(d=null===(o=null==t?void 0:t.currentUser)||void 0===o?void 0:o.default_device)||void 0===d?void 0:d.type)&&(null==r?void 0:r.incomingWebRTC)){r.incoming=!0;var g=t.ringtones?(null===(l=t.ringtones.availableRingtones.find(function(e){return e.name===t.ringtones.selectedRingtone}))||void 0===l?void 0:l.base64Audio)||(null===(c=t.ringtones.availableRingtones[0])||void 0===c?void 0:c.base64Audio):void 0;g&&n.player.updateStartAudioPlayer({src:g,loop:!0,useRingtoneOutput:!0})}n.currentCall.updateCurrentCall(e.__assign({},r))},checkOutgoingUpdate:function(t,i){var a,u,s;("webrtc"===(null===(a=i.currentUser.default_device)||void 0===a?void 0:a.type)&&t.outgoingWebRTC||"physical"===(null===(u=i.currentUser.default_device)||void 0===u?void 0:u.type)&&t.outgoingSocket||"nethlink"===(null===(s=i.currentUser.default_device)||void 0===s?void 0:s.type)&&t.outgoingWebRTC)&&(t.outgoing=!0,r.dispatchOutgoingCallStarted(t.displayName,t.number)),n.currentCall.updateCurrentCall(e.__assign({},t))},checkAcceptedUpdate:function(r,i){var a,u,s;("webrtc"===(null===(a=i.currentUser.default_device)||void 0===a?void 0:a.type)&&r.acceptedWebRTC||"physical"===(null===(u=i.currentUser.default_device)||void 0===u?void 0:u.type)&&r.acceptedSocket||"nethlink"===(null===(s=i.currentUser.default_device)||void 0===s?void 0:s.type)&&r.acceptedWebRTC)&&(r.accepted=!0,t.eventDispatch("phone-island-call-answered",{})),n.currentCall.updateCurrentCall(e.__assign({},r))}}}});exports.currentCall=a;
2
2
  //# sourceMappingURL=currentCall.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"currentCall.js","sources":["../../src/models/currentCall.ts"],"sourcesContent":["// Copyright (C) 2024 Nethesis S.r.l.\n// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport { createModel } from '@rematch/core'\nimport type { RootModel } from '.'\nimport { dispatchOutgoingCallStarted } from '../events/index'\nimport { eventDispatch } from '../utils'\nimport { PhonebookContact } from '../types/phonebook'\nimport { ExtensionTypeTypes } from '../types/user'\n\nconst defaultState = {\n displayName: '',\n username: '',\n number: '',\n incomingSocket: false,\n incomingWebRTC: false,\n incoming: false,\n acceptedSocket: false,\n acceptedWebRTC: false,\n accepted: false,\n outgoingSocket: false,\n outgoingWebRTC: false,\n parked: false,\n outgoing: false,\n startTime: '',\n muted: false,\n paused: false,\n keypadValue: '',\n conversationId: '',\n transferring: false,\n conferencing: false,\n transferringName: '',\n transferringNumber: '',\n transferringStartTime: '',\n transferSwitching: false,\n transferCalls: new Array(),\n ownerExtension: '',\n isRecording: false,\n isLocalVideoEnabled: false,\n showRemoteVideoPlaceHolder: true,\n hasVideoTrackAdded: false,\n isStartingVideoCall: false,\n streamingSourceNumber: '',\n chDest: new Array(),\n chSource: new Array(),\n throughQueue: false,\n queueId: '',\n queueName: '',\n queueNumber: '',\n queuePosition: '',\n queueWaitingTime: 0,\n counterpartDeviceType: '' as ExtensionTypeTypes | '',\n}\n\nexport const currentCall = createModel<RootModel>()({\n state: defaultState,\n reducers: {\n updateCurrentCall: (state, payload: CurrentCallTypes) => {\n if (Number(payload.startTime) && state.startTime) {\n // avoid updating startTime if it's already set (e.g. while switching to a video call)\n delete payload.startTime\n }\n\n if (payload.throughQueue === false) {\n payload.queueId = ''\n payload.queueName = ''\n payload.queueNumber = ''\n payload.queuePosition = ''\n payload.queueWaitingTime = 0\n }\n\n return {\n ...state,\n ...payload,\n transferCalls: state.transferCalls,\n }\n },\n updateKeypadValue: (state, payload: string) => {\n return {\n ...state,\n keypadValue: payload,\n }\n },\n updateTransferring: (state, payload: boolean) => {\n return {\n ...state,\n transferring: payload,\n }\n },\n updateTransferSwitching: (state, payload: boolean) => {\n return {\n ...state,\n transferSwitching: payload,\n }\n },\n addTransferCalls: (state, payload: TransferCallsTypes) => {\n if (state.transferCalls.find((item) => item.number === payload.number)) {\n return state\n } else {\n return {\n ...state,\n transferCalls: [...state.transferCalls, payload],\n }\n }\n },\n deleteTransferCalls: (state) => {\n return {\n ...state,\n transferCalls: state.transferCalls.filter((item) => item.type !== 'transferred'),\n }\n },\n setParked: (state, payload: boolean) => {\n state.parked = payload\n return state\n },\n updateRecordingStatus: (state, payload: boolean) => {\n state.isRecording = payload\n return state\n },\n updateStartTime: (state, payload: string) => {\n state.startTime = payload\n return state\n },\n updateIncoming: (state, payload: boolean) => {\n state.incoming = payload\n return state\n },\n reset: () => {\n return defaultState\n },\n setLocalVideoEnabled: (state, payload: boolean) => {\n state.isLocalVideoEnabled = payload\n return state\n },\n setVideoTrackAdded: (state, payload: boolean) => {\n state.hasVideoTrackAdded = payload\n return state\n },\n updateConferencing: (state, payload: boolean) => {\n return {\n ...state,\n conferencing: payload,\n }\n },\n },\n effects: (dispatch) => ({\n checkIncomingUpdatePlay: (payload: CurrentCallTypes, rootState) => {\n // Check call type and incoming confirmation source\n if (\n (rootState?.currentUser?.default_device?.type === 'webrtc' && payload?.incomingWebRTC) ||\n (rootState?.currentUser?.default_device?.type === 'physical' && payload?.incomingSocket) ||\n (rootState?.currentUser?.default_device?.type === 'nethlink' && payload?.incomingWebRTC)\n ) {\n payload.incoming = true\n\n // Get selected ringtone from store and play the audio\n const selectedRingtoneAudio = rootState.ringtones\n ? (rootState.ringtones.availableRingtones as any[]).find(\n (r: any) => r.name === rootState.ringtones.selectedRingtone,\n )?.base64Audio || rootState.ringtones.availableRingtones[0]?.base64Audio\n : undefined\n \n if (selectedRingtoneAudio) {\n dispatch.player.updateStartAudioPlayer({ src: selectedRingtoneAudio, loop: true, useRingtoneOutput: true })\n }\n }\n // Update the current call values and set incoming\n dispatch.currentCall.updateCurrentCall({\n ...payload,\n })\n },\n checkOutgoingUpdate: (payload: CurrentCallTypes, rootState) => {\n // Check call type and outgoing confirmation source\n if (\n (rootState.currentUser.default_device?.type === 'webrtc' && payload.outgoingWebRTC) ||\n (rootState.currentUser.default_device?.type === 'physical' && payload.outgoingSocket) ||\n (rootState.currentUser.default_device?.type === 'nethlink' && payload.outgoingWebRTC)\n ) {\n payload.outgoing = true\n // Dispatch an event for outgoing call\n dispatchOutgoingCallStarted(payload.displayName, payload.number)\n }\n // Update the current call values and set outgoing\n dispatch.currentCall.updateCurrentCall({\n ...payload,\n })\n },\n checkAcceptedUpdate: (payload: CurrentCallTypes, rootState) => {\n // Check call type and accepted confirmation source\n if (\n (rootState.currentUser.default_device?.type === 'webrtc' && payload.acceptedWebRTC) ||\n (rootState.currentUser.default_device?.type === 'physical' && payload.acceptedSocket) ||\n (rootState.currentUser.default_device?.type === 'nethlink' && payload.acceptedWebRTC)\n ) {\n payload.accepted = true\n eventDispatch('phone-island-call-answered', {})\n }\n // Update the current call values\n dispatch.currentCall.updateCurrentCall({\n ...payload,\n })\n },\n }),\n})\n\nexport type TransferCallsTypes = {\n type: 'transferred' | 'destination'\n displayName: string\n number: string\n startTime: string\n}\n\nexport type chDestTypes = {\n type: 'dest'\n channel: string\n callerNum: string\n startTime: number\n callerName: string\n bridgedNum: string\n bridgedName: string\n inConference: boolean\n channelStatus: string\n bridgedChannel: string\n}\n\nexport type chSourceTypes = {\n type: 'source'\n channel: string\n callerNum: string\n startTime: number\n callerName: string\n bridgedNum: string\n bridgedName: string\n inConference: boolean\n channelStatus: string\n bridgedChannel: string\n}\n\nexport interface CurrentCallTypes {\n displayName?: string\n username?: string\n number?: string\n incomingSocket?: boolean\n incomingWebRTC?: boolean\n parked?: boolean\n incoming?: boolean\n acceptedSocket?: boolean\n acceptedWebRTC?: boolean\n accepted?: boolean\n outgoingSocket?: boolean\n outgoingWebRTC?: boolean\n outgoing?: boolean\n startTime?: string\n muted?: boolean\n paused?: boolean\n conversationId?: string\n transferring?: boolean\n conferencing?: boolean\n transferringName?: string\n transferringNumber?: string\n transferringStartTime?: string\n transferSwitching?: boolean\n transferCalls?: TransferCallsTypes[]\n ownerExtension?: string\n isRecording?: boolean\n isLocalVideoEnabled?: boolean\n hasVideoTrackAdded?: boolean\n showRemoteVideoPlaceHolder?: boolean\n isStartingVideoCall?: boolean\n streamingSourceNumber?: string\n chDest?: any\n chSource?: any\n throughQueue?: boolean\n queueId?: string\n queueName?: string\n queueNumber?: string\n queuePosition?: string\n queueWaitingTime?: number\n counterpartDeviceType?: ExtensionTypeTypes | ''\n}\n"],"names":["defaultState","displayName","username","number","incomingSocket","incomingWebRTC","incoming","acceptedSocket","acceptedWebRTC","accepted","outgoingSocket","outgoingWebRTC","parked","outgoing","startTime","muted","paused","keypadValue","conversationId","transferring","conferencing","transferringName","transferringNumber","transferringStartTime","transferSwitching","transferCalls","Array","ownerExtension","isRecording","isLocalVideoEnabled","showRemoteVideoPlaceHolder","hasVideoTrackAdded","isStartingVideoCall","streamingSourceNumber","chDest","chSource","throughQueue","queueId","queueName","queueNumber","queuePosition","queueWaitingTime","counterpartDeviceType","currentCall","createModel","state","reducers","updateCurrentCall","payload","Number","__assign","updateKeypadValue","updateTransferring","updateTransferSwitching","addTransferCalls","find","item","__spreadArray","deleteTransferCalls","filter","type","setParked","updateRecordingStatus","updateStartTime","updateIncoming","reset","setLocalVideoEnabled","setVideoTrackAdded","updateConferencing","effects","dispatch","checkIncomingUpdatePlay","rootState","_b","_a","currentUser","default_device","_d","_c","_f","_e","selectedRingtoneAudio","ringtones","_g","availableRingtones","r","name","selectedRingtone","base64Audio","_h","undefined","player","updateStartAudioPlayer","src","loop","useRingtoneOutput","checkOutgoingUpdate","dispatchOutgoingCallStarted","checkAcceptedUpdate","eventDispatch"],"mappings":"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"}
1
+ {"version":3,"file":"currentCall.js","sources":["../../src/models/currentCall.ts"],"sourcesContent":["// Copyright (C) 2024 Nethesis S.r.l.\n// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport { createModel } from '@rematch/core'\nimport type { RootModel } from '.'\nimport { dispatchOutgoingCallStarted } from '../events/index'\nimport { eventDispatch } from '../utils'\nimport { PhonebookContact } from '../types/phonebook'\nimport { ExtensionTypeTypes } from '../types/user'\n\nconst defaultState = {\n displayName: '',\n username: '',\n number: '',\n incomingSocket: false,\n incomingWebRTC: false,\n incoming: false,\n acceptedSocket: false,\n acceptedWebRTC: false,\n accepted: false,\n answering: false,\n outgoingSocket: false,\n outgoingWebRTC: false,\n parked: false,\n outgoing: false,\n startTime: '',\n muted: false,\n paused: false,\n keypadValue: '',\n conversationId: '',\n transferring: false,\n conferencing: false,\n transferringName: '',\n transferringNumber: '',\n transferringStartTime: '',\n transferSwitching: false,\n transferCalls: new Array(),\n ownerExtension: '',\n isRecording: false,\n isLocalVideoEnabled: false,\n showRemoteVideoPlaceHolder: true,\n hasVideoTrackAdded: false,\n isStartingVideoCall: false,\n streamingSourceNumber: '',\n chDest: new Array(),\n chSource: new Array(),\n throughQueue: false,\n queueId: '',\n queueName: '',\n queueNumber: '',\n queuePosition: '',\n queueWaitingTime: 0,\n counterpartDeviceType: '' as ExtensionTypeTypes | '',\n}\n\nexport const currentCall = createModel<RootModel>()({\n state: defaultState,\n reducers: {\n updateCurrentCall: (state, payload: CurrentCallTypes) => {\n if (Number(payload.startTime) && state.startTime) {\n // avoid updating startTime if it's already set (e.g. while switching to a video call)\n delete payload.startTime\n }\n\n if (payload.throughQueue === false) {\n payload.queueId = ''\n payload.queueName = ''\n payload.queueNumber = ''\n payload.queuePosition = ''\n payload.queueWaitingTime = 0\n }\n\n return {\n ...state,\n ...payload,\n transferCalls: state.transferCalls,\n }\n },\n updateKeypadValue: (state, payload: string) => {\n return {\n ...state,\n keypadValue: payload,\n }\n },\n updateTransferring: (state, payload: boolean) => {\n return {\n ...state,\n transferring: payload,\n }\n },\n updateTransferSwitching: (state, payload: boolean) => {\n return {\n ...state,\n transferSwitching: payload,\n }\n },\n addTransferCalls: (state, payload: TransferCallsTypes) => {\n if (state.transferCalls.find((item) => item.number === payload.number)) {\n return state\n } else {\n return {\n ...state,\n transferCalls: [...state.transferCalls, payload],\n }\n }\n },\n deleteTransferCalls: (state) => {\n return {\n ...state,\n transferCalls: state.transferCalls.filter((item) => item.type !== 'transferred'),\n }\n },\n setParked: (state, payload: boolean) => {\n state.parked = payload\n return state\n },\n updateRecordingStatus: (state, payload: boolean) => {\n state.isRecording = payload\n return state\n },\n updateStartTime: (state, payload: string) => {\n state.startTime = payload\n return state\n },\n updateIncoming: (state, payload: boolean) => {\n state.incoming = payload\n return state\n },\n reset: () => {\n return defaultState\n },\n setLocalVideoEnabled: (state, payload: boolean) => {\n state.isLocalVideoEnabled = payload\n return state\n },\n setVideoTrackAdded: (state, payload: boolean) => {\n state.hasVideoTrackAdded = payload\n return state\n },\n updateConferencing: (state, payload: boolean) => {\n return {\n ...state,\n conferencing: payload,\n }\n },\n },\n effects: (dispatch) => ({\n checkIncomingUpdatePlay: (payload: CurrentCallTypes, rootState) => {\n // Check call type and incoming confirmation source\n if (\n (rootState?.currentUser?.default_device?.type === 'webrtc' && payload?.incomingWebRTC) ||\n (rootState?.currentUser?.default_device?.type === 'physical' && payload?.incomingSocket) ||\n (rootState?.currentUser?.default_device?.type === 'nethlink' && payload?.incomingWebRTC)\n ) {\n payload.incoming = true\n\n // Get selected ringtone from store and play the audio\n const selectedRingtoneAudio = rootState.ringtones\n ? (rootState.ringtones.availableRingtones as any[]).find(\n (r: any) => r.name === rootState.ringtones.selectedRingtone,\n )?.base64Audio || rootState.ringtones.availableRingtones[0]?.base64Audio\n : undefined\n \n if (selectedRingtoneAudio) {\n dispatch.player.updateStartAudioPlayer({ src: selectedRingtoneAudio, loop: true, useRingtoneOutput: true })\n }\n }\n // Update the current call values and set incoming\n dispatch.currentCall.updateCurrentCall({\n ...payload,\n })\n },\n checkOutgoingUpdate: (payload: CurrentCallTypes, rootState) => {\n // Check call type and outgoing confirmation source\n if (\n (rootState.currentUser.default_device?.type === 'webrtc' && payload.outgoingWebRTC) ||\n (rootState.currentUser.default_device?.type === 'physical' && payload.outgoingSocket) ||\n (rootState.currentUser.default_device?.type === 'nethlink' && payload.outgoingWebRTC)\n ) {\n payload.outgoing = true\n // Dispatch an event for outgoing call\n dispatchOutgoingCallStarted(payload.displayName, payload.number)\n }\n // Update the current call values and set outgoing\n dispatch.currentCall.updateCurrentCall({\n ...payload,\n })\n },\n checkAcceptedUpdate: (payload: CurrentCallTypes, rootState) => {\n // Check call type and accepted confirmation source\n if (\n (rootState.currentUser.default_device?.type === 'webrtc' && payload.acceptedWebRTC) ||\n (rootState.currentUser.default_device?.type === 'physical' && payload.acceptedSocket) ||\n (rootState.currentUser.default_device?.type === 'nethlink' && payload.acceptedWebRTC)\n ) {\n payload.accepted = true\n eventDispatch('phone-island-call-answered', {})\n }\n // Update the current call values\n dispatch.currentCall.updateCurrentCall({\n ...payload,\n })\n },\n }),\n})\n\nexport type TransferCallsTypes = {\n type: 'transferred' | 'destination'\n displayName: string\n number: string\n startTime: string\n}\n\nexport type chDestTypes = {\n type: 'dest'\n channel: string\n callerNum: string\n startTime: number\n callerName: string\n bridgedNum: string\n bridgedName: string\n inConference: boolean\n channelStatus: string\n bridgedChannel: string\n}\n\nexport type chSourceTypes = {\n type: 'source'\n channel: string\n callerNum: string\n startTime: number\n callerName: string\n bridgedNum: string\n bridgedName: string\n inConference: boolean\n channelStatus: string\n bridgedChannel: string\n}\n\nexport interface CurrentCallTypes {\n displayName?: string\n username?: string\n number?: string\n incomingSocket?: boolean\n incomingWebRTC?: boolean\n parked?: boolean\n incoming?: boolean\n acceptedSocket?: boolean\n acceptedWebRTC?: boolean\n accepted?: boolean\n // the answer of the incoming call was requested on this client (until the call is reset)\n answering?: boolean\n outgoingSocket?: boolean\n outgoingWebRTC?: boolean\n outgoing?: boolean\n startTime?: string\n muted?: boolean\n paused?: boolean\n conversationId?: string\n transferring?: boolean\n conferencing?: boolean\n transferringName?: string\n transferringNumber?: string\n transferringStartTime?: string\n transferSwitching?: boolean\n transferCalls?: TransferCallsTypes[]\n ownerExtension?: string\n isRecording?: boolean\n isLocalVideoEnabled?: boolean\n hasVideoTrackAdded?: boolean\n showRemoteVideoPlaceHolder?: boolean\n isStartingVideoCall?: boolean\n streamingSourceNumber?: string\n chDest?: any\n chSource?: any\n throughQueue?: boolean\n queueId?: string\n queueName?: string\n queueNumber?: string\n queuePosition?: string\n queueWaitingTime?: number\n counterpartDeviceType?: ExtensionTypeTypes | ''\n}\n"],"names":["defaultState","displayName","username","number","incomingSocket","incomingWebRTC","incoming","acceptedSocket","acceptedWebRTC","accepted","answering","outgoingSocket","outgoingWebRTC","parked","outgoing","startTime","muted","paused","keypadValue","conversationId","transferring","conferencing","transferringName","transferringNumber","transferringStartTime","transferSwitching","transferCalls","Array","ownerExtension","isRecording","isLocalVideoEnabled","showRemoteVideoPlaceHolder","hasVideoTrackAdded","isStartingVideoCall","streamingSourceNumber","chDest","chSource","throughQueue","queueId","queueName","queueNumber","queuePosition","queueWaitingTime","counterpartDeviceType","currentCall","createModel","state","reducers","updateCurrentCall","payload","Number","__assign","updateKeypadValue","updateTransferring","updateTransferSwitching","addTransferCalls","find","item","__spreadArray","deleteTransferCalls","filter","type","setParked","updateRecordingStatus","updateStartTime","updateIncoming","reset","setLocalVideoEnabled","setVideoTrackAdded","updateConferencing","effects","dispatch","checkIncomingUpdatePlay","rootState","_b","_a","currentUser","default_device","_d","_c","_f","_e","selectedRingtoneAudio","ringtones","_g","availableRingtones","r","name","selectedRingtone","base64Audio","_h","undefined","player","updateStartAudioPlayer","src","loop","useRingtoneOutput","checkOutgoingUpdate","dispatchOutgoingCallStarted","checkAcceptedUpdate","eventDispatch"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("../node_modules/tslib/tslib.es6.js"),n=require("../node_modules/@rematch/core/dist/core.esm.js");require("react");var i=require("../utils/genericFunctions/eventDispatch.js");require("../store/index.js");var t={view:null,isOpen:!0,actionsExpanded:!1,startPosition:{x:0,y:0},inputOutputOpened:!1,settingsView:"main",contactListView:"main",sideViewIsVisible:!1,transcriptionViewIsVisible:!1,isConferenceList:!1,previousView:null,avoidToShow:!1,isFullScreen:!1,isFromStreaming:!1,isExtraLarge:!1,urlOpened:!1,previewCallFromMobileOrNethlink:!1,forceReload:!1,operatorBusy:{isActive:!1,calledNumber:null,callerNumber:null}},r=n.createModel()({state:t,reducers:{setIslandView:function(n,i){return i===(null==n?void 0:n.view)?n:e.__assign(e.__assign({},n),{view:i,previousView:null==n?void 0:n.view})},toggleIsOpen:function(n,i){return e.__assign(e.__assign({},n),{isOpen:i})},toggleActionsExpanded:function(e,n){return e.actionsExpanded=n,e},toggleInputOutputOpened:function(e,n){return e.inputOutputOpened=n,e},setSettingsView:function(e,n){e.settingsView=n},setContactListView:function(e,n){e.contactListView=n},toggleSideViewVisible:function(e,n){e.sideViewIsVisible=n},toggleTranscriptionViewVisible:function(e,n){e.transcriptionViewIsVisible=n},toggleConferenceList:function(e,n){e.isConferenceList=n},toggleAvoidToShow:function(e,n){e.avoidToShow=n},setUrlOpened:function(e,n){return e.urlOpened=n,e},setPreviewCallFromMobileOrNethlink:function(e,n){return e.previewCallFromMobileOrNethlink=n,e},setForceReload:function(e,n){return e.forceReload=n,e},resetSettingsView:function(e){e.settingsView="main"},setFullScreen:function(n,i){return e.__assign(e.__assign({},n),{isFullScreen:i})},setIsFromStreaming:function(n,i){return e.__assign(e.__assign({},n),{isFromStreaming:i})},setExtraLarge:function(n,i){return e.__assign(e.__assign({},n),{isExtraLarge:i})},resetPlayerClose:function(e){return s(e,!1)},resetIslandStore:function(e){return s(e,!0)},_resetIslandStoreInternal:function(e){return s(e,!0)},_resetPlayerCloseInternal:function(e){return s(e,!1)},setOperatorBusyCalledNumber:function(e,n){return e.operatorBusy.calledNumber=n,e},setOperatorBusyActive:function(e,n){return e.operatorBusy.isActive=!0,e.operatorBusy.callerNumber=n.callerNumber,e},resetOperatorBusy:function(e){return e.operatorBusy.isActive=!1,e.operatorBusy.callerNumber=null,e},resetOperatorBusyCompletely:function(e){return e.operatorBusy.isActive=!1,e.operatorBusy.calledNumber=null,e.operatorBusy.callerNumber=null,e}},effects:function(e){return{handleToggleIsOpen:function(n,t){t.island.isOpen&&t.alerts.status.activeAlertsCount>0&&!t.currentCall.displayName?(i.eventDispatch("phone-island-expanded",{}),e.island.toggleIsOpen(!0)):(i.eventDispatch("phone-island-"+(t.island.isOpen?"compressed":"expanded"),{}),t.island.isOpen&&(i.eventDispatch("phone-island-sideview-close",{}),i.eventDispatch("phone-island-transcription-close",{})),e.island.toggleIsOpen(!t.island.isOpen))},handleResetIslandStore:function(){e.island._resetIslandStoreInternal(),i.eventDispatch("phone-island-transcription-close",{})},handleResetPlayerClose:function(){e.island._resetPlayerCloseInternal(),i.eventDispatch("phone-island-transcription-close",{})}}}});function s(n,i){var r=n.startPosition,s=["waitingConference"];i&&s.push("recorder");var o=s.includes(n.view)?n.view:t.view,l=n.avoidToShow;return e.__assign(e.__assign({},t),{startPosition:r,view:o,avoidToShow:l,isFromStreaming:!1,previewCallFromMobileOrNethlink:!1,forceReload:!1,previousView:"waitingConference"===n.view?n.previousView:t.previousView,operatorBusy:{isActive:!1,calledNumber:n.operatorBusy.calledNumber,callerNumber:null}})}exports.island=r;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("../node_modules/tslib/tslib.es6.js"),n=require("../node_modules/@rematch/core/dist/core.esm.js");require("react");var i=require("../utils/genericFunctions/eventDispatch.js");require("../store/index.js"),require("../services/user.js");var t={view:null,isOpen:!0,actionsExpanded:!1,startPosition:{x:0,y:0},inputOutputOpened:!1,settingsView:"main",contactListView:"main",sideViewIsVisible:!1,transcriptionViewIsVisible:!1,isConferenceList:!1,previousView:null,avoidToShow:!1,isFullScreen:!1,isFromStreaming:!1,isExtraLarge:!1,urlOpened:!1,previewCallFromMobileOrNethlink:!1,forceReload:!1,operatorBusy:{isActive:!1,calledNumber:null,callerNumber:null}},r=n.createModel()({state:t,reducers:{setIslandView:function(n,i){return i===(null==n?void 0:n.view)?n:e.__assign(e.__assign({},n),{view:i,previousView:null==n?void 0:n.view})},toggleIsOpen:function(n,i){return e.__assign(e.__assign({},n),{isOpen:i})},toggleActionsExpanded:function(e,n){return e.actionsExpanded=n,e},toggleInputOutputOpened:function(e,n){return e.inputOutputOpened=n,e},setSettingsView:function(e,n){e.settingsView=n},setContactListView:function(e,n){e.contactListView=n},toggleSideViewVisible:function(e,n){e.sideViewIsVisible=n},toggleTranscriptionViewVisible:function(e,n){e.transcriptionViewIsVisible=n},toggleConferenceList:function(e,n){e.isConferenceList=n},toggleAvoidToShow:function(e,n){e.avoidToShow=n},setUrlOpened:function(e,n){return e.urlOpened=n,e},setPreviewCallFromMobileOrNethlink:function(e,n){return e.previewCallFromMobileOrNethlink=n,e},setForceReload:function(e,n){return e.forceReload=n,e},resetSettingsView:function(e){e.settingsView="main"},setFullScreen:function(n,i){return e.__assign(e.__assign({},n),{isFullScreen:i})},setIsFromStreaming:function(n,i){return e.__assign(e.__assign({},n),{isFromStreaming:i})},setExtraLarge:function(n,i){return e.__assign(e.__assign({},n),{isExtraLarge:i})},resetPlayerClose:function(e){return s(e,!1)},resetIslandStore:function(e){return s(e,!0)},_resetIslandStoreInternal:function(e){return s(e,!0)},_resetPlayerCloseInternal:function(e){return s(e,!1)},setOperatorBusyCalledNumber:function(e,n){return e.operatorBusy.calledNumber=n,e},setOperatorBusyActive:function(e,n){return e.operatorBusy.isActive=!0,e.operatorBusy.callerNumber=n.callerNumber,e},resetOperatorBusy:function(e){return e.operatorBusy.isActive=!1,e.operatorBusy.callerNumber=null,e},resetOperatorBusyCompletely:function(e){return e.operatorBusy.isActive=!1,e.operatorBusy.calledNumber=null,e.operatorBusy.callerNumber=null,e}},effects:function(e){return{handleToggleIsOpen:function(n,t){t.island.isOpen&&t.alerts.status.activeAlertsCount>0&&!t.currentCall.displayName?(i.eventDispatch("phone-island-expanded",{}),e.island.toggleIsOpen(!0)):(i.eventDispatch("phone-island-"+(t.island.isOpen?"compressed":"expanded"),{}),t.island.isOpen&&(i.eventDispatch("phone-island-sideview-close",{}),i.eventDispatch("phone-island-transcription-close",{})),e.island.toggleIsOpen(!t.island.isOpen))},handleResetIslandStore:function(){e.island._resetIslandStoreInternal(),i.eventDispatch("phone-island-transcription-close",{})},handleResetPlayerClose:function(){e.island._resetPlayerCloseInternal(),i.eventDispatch("phone-island-transcription-close",{})}}}});function s(n,i){var r=n.startPosition,s=["waitingConference"];i&&s.push("recorder");var o=s.includes(n.view)?n.view:t.view,l=n.avoidToShow;return e.__assign(e.__assign({},t),{startPosition:r,view:o,avoidToShow:l,isFromStreaming:!1,previewCallFromMobileOrNethlink:!1,forceReload:!1,previousView:"waitingConference"===n.view?n.previousView:t.previousView,operatorBusy:{isActive:!1,calledNumber:n.operatorBusy.calledNumber,callerNumber:null}})}exports.island=r;
2
2
  //# sourceMappingURL=island.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"island.js","sources":["../../src/models/island.ts"],"sourcesContent":["// Copyright (C) 2024 Nethesis S.r.l.\n// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport { createModel } from '@rematch/core'\nimport type { RootModel } from '.'\nimport { eventDispatch } from '../utils'\n\nconst defaultState: IslandTypes = {\n view: null,\n isOpen: true,\n actionsExpanded: false,\n startPosition: {\n x: 0,\n y: 0,\n },\n inputOutputOpened: false,\n settingsView: 'main',\n contactListView: 'main',\n sideViewIsVisible: false,\n transcriptionViewIsVisible: false,\n isConferenceList: false,\n previousView: null,\n avoidToShow: false,\n isFullScreen: false,\n isFromStreaming: false,\n isExtraLarge: false,\n urlOpened: false,\n previewCallFromMobileOrNethlink: false,\n forceReload: false,\n operatorBusy: {\n isActive: false,\n calledNumber: null,\n callerNumber: null,\n },\n}\n\nexport const island = createModel<RootModel>()({\n state: defaultState,\n reducers: {\n setIslandView: (state, newView: IslandViewType | null) => {\n if (newView === state?.view) {\n // Don't change view if it's the same\n return state\n } else {\n return {\n ...state,\n view: newView,\n previousView: state?.view,\n }\n }\n },\n toggleIsOpen: (state, payload: boolean) => {\n return {\n ...state,\n isOpen: payload,\n }\n },\n toggleActionsExpanded: (state, payload: boolean) => {\n state.actionsExpanded = payload\n return state\n },\n toggleInputOutputOpened: (state, payload: boolean) => {\n state.inputOutputOpened = payload\n return state\n },\n setSettingsView: (state, payload: SettingsViewType) => {\n state.settingsView = payload\n },\n setContactListView: (state, payload: ContactListViewType) => {\n state.contactListView = payload\n },\n toggleSideViewVisible: (state, payload: boolean) => {\n state.sideViewIsVisible = payload\n },\n toggleTranscriptionViewVisible: (state, payload: boolean) => {\n state.transcriptionViewIsVisible = payload\n },\n toggleConferenceList: (state, payload: boolean) => {\n state.isConferenceList = payload\n },\n toggleAvoidToShow: (state, payload: boolean) => {\n state.avoidToShow = payload\n },\n setUrlOpened: (state, payload: boolean) => {\n state.urlOpened = payload\n return state\n },\n setPreviewCallFromMobileOrNethlink: (state, payload: boolean) => {\n state.previewCallFromMobileOrNethlink = payload\n return state\n },\n setForceReload: (state, payload: boolean) => {\n state.forceReload = payload\n return state\n },\n resetSettingsView: (state) => {\n state.settingsView = 'main'\n },\n setFullScreen: (state, payload: boolean) => {\n return {\n ...state,\n isFullScreen: payload,\n }\n },\n setIsFromStreaming: (state, payload: boolean) => {\n return {\n ...state,\n isFromStreaming: payload,\n }\n },\n setExtraLarge: (state, payload: boolean) => {\n return {\n ...state,\n isExtraLarge: payload,\n }\n },\n resetPlayerClose: (state) => {\n return getResetState(state, false)\n },\n resetIslandStore: (state) => {\n return getResetState(state, true)\n },\n _resetIslandStoreInternal: (state) => {\n return getResetState(state, true)\n },\n _resetPlayerCloseInternal: (state) => {\n return getResetState(state, false)\n },\n setOperatorBusyCalledNumber: (state, payload: string) => {\n state.operatorBusy.calledNumber = payload\n return state\n },\n setOperatorBusyActive: (state, payload: { callerNumber: string }) => {\n state.operatorBusy.isActive = true\n state.operatorBusy.callerNumber = payload.callerNumber\n return state\n },\n resetOperatorBusy: (state) => {\n state.operatorBusy.isActive = false\n state.operatorBusy.callerNumber = null\n // Keep calledNumber for potential reuse\n return state\n },\n resetOperatorBusyCompletely: (state) => {\n state.operatorBusy.isActive = false\n state.operatorBusy.calledNumber = null\n state.operatorBusy.callerNumber = null\n return state\n },\n },\n effects: (dispatch) => ({\n handleToggleIsOpen: (_: void, rootState) => {\n if (\n rootState.island.isOpen &&\n rootState.alerts.status.activeAlertsCount > 0 &&\n !rootState.currentCall.displayName\n ) {\n eventDispatch('phone-island-expanded', {})\n dispatch.island.toggleIsOpen(true)\n } else {\n eventDispatch('phone-island-' + (rootState.island.isOpen ? 'compressed' : 'expanded'), {})\n if (rootState.island.isOpen) {\n eventDispatch('phone-island-sideview-close', {})\n eventDispatch('phone-island-transcription-close', {})\n }\n dispatch.island.toggleIsOpen(!rootState.island.isOpen)\n }\n },\n handleResetIslandStore: () => {\n dispatch.island._resetIslandStoreInternal()\n eventDispatch('phone-island-transcription-close', {})\n },\n handleResetPlayerClose: () => {\n dispatch.island._resetPlayerCloseInternal()\n eventDispatch('phone-island-transcription-close', {})\n },\n }),\n})\n\nfunction getResetState(state: IslandTypes, includeRecorder: boolean): IslandTypes {\n // Keep beginning position\n const preservedStartPosition = state.startPosition\n // Determine which view to preserve\n const viewsToPreserve = ['waitingConference']\n if (includeRecorder) {\n viewsToPreserve.push('recorder')\n }\n\n const preservedView = viewsToPreserve.includes(state.view as string)\n ? state.view\n : defaultState.view\n const avoidToShow = state.avoidToShow\n\n return {\n ...defaultState,\n startPosition: preservedStartPosition,\n view: preservedView,\n avoidToShow: avoidToShow,\n isFromStreaming: false,\n previewCallFromMobileOrNethlink: false,\n forceReload: false,\n // Keep previousView if waitingConference\n previousView:\n state.view === 'waitingConference' ? state.previousView : defaultState.previousView,\n // Preserve calledNumber for potential operator busy scenarios\n operatorBusy: {\n isActive: false,\n calledNumber: state.operatorBusy.calledNumber,\n callerNumber: null,\n },\n }\n}\n\ntype IslandViewType =\n | 'call'\n | 'keypad'\n | 'player'\n | 'transfer'\n | 'recorder'\n | 'physicalPhoneRecorder'\n | 'settings'\n | 'video'\n | 'conference'\n | 'switchDevice'\n | 'waitingConference'\n | 'streamingAnswer'\n | 'operatorBusy'\ntype SettingsViewType = 'microphone' | 'audioInput' | 'videoInput' | 'theme' | 'main'\ntype ContactListViewType = 'main' | 'selectContactNumber'\n\ninterface IslandTypes {\n view?: IslandViewType | null\n isOpen: boolean\n actionsExpanded: boolean\n startPosition: {\n x: number\n y: number\n }\n inputOutputOpened: boolean\n settingsView: SettingsViewType\n contactListView: ContactListViewType\n sideViewIsVisible: boolean\n transcriptionViewIsVisible: boolean\n isConferenceList: boolean\n previousView?: IslandViewType | null\n avoidToShow?: boolean\n isFullScreen: boolean\n isFromStreaming: boolean\n isExtraLarge: boolean\n urlOpened: boolean\n previewCallFromMobileOrNethlink: boolean\n forceReload: boolean\n operatorBusy: {\n isActive: boolean\n calledNumber: string | null\n callerNumber: string | null\n }\n}\n"],"names":["defaultState","view","isOpen","actionsExpanded","startPosition","x","y","inputOutputOpened","settingsView","contactListView","sideViewIsVisible","transcriptionViewIsVisible","isConferenceList","previousView","avoidToShow","isFullScreen","isFromStreaming","isExtraLarge","urlOpened","previewCallFromMobileOrNethlink","forceReload","operatorBusy","isActive","calledNumber","callerNumber","island","createModel","state","reducers","setIslandView","newView","__assign","toggleIsOpen","payload","toggleActionsExpanded","toggleInputOutputOpened","setSettingsView","setContactListView","toggleSideViewVisible","toggleTranscriptionViewVisible","toggleConferenceList","toggleAvoidToShow","setUrlOpened","setPreviewCallFromMobileOrNethlink","setForceReload","resetSettingsView","setFullScreen","setIsFromStreaming","setExtraLarge","resetPlayerClose","getResetState","resetIslandStore","_resetIslandStoreInternal","_resetPlayerCloseInternal","setOperatorBusyCalledNumber","setOperatorBusyActive","resetOperatorBusy","resetOperatorBusyCompletely","effects","dispatch","handleToggleIsOpen","_","rootState","alerts","status","activeAlertsCount","currentCall","displayName","eventDispatch","handleResetIslandStore","handleResetPlayerClose","includeRecorder","preservedStartPosition","viewsToPreserve","push","preservedView","includes"],"mappings":"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"}
1
+ {"version":3,"file":"island.js","sources":["../../src/models/island.ts"],"sourcesContent":["// Copyright (C) 2024 Nethesis S.r.l.\n// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport { createModel } from '@rematch/core'\nimport type { RootModel } from '.'\nimport { eventDispatch } from '../utils'\n\nconst defaultState: IslandTypes = {\n view: null,\n isOpen: true,\n actionsExpanded: false,\n startPosition: {\n x: 0,\n y: 0,\n },\n inputOutputOpened: false,\n settingsView: 'main',\n contactListView: 'main',\n sideViewIsVisible: false,\n transcriptionViewIsVisible: false,\n isConferenceList: false,\n previousView: null,\n avoidToShow: false,\n isFullScreen: false,\n isFromStreaming: false,\n isExtraLarge: false,\n urlOpened: false,\n previewCallFromMobileOrNethlink: false,\n forceReload: false,\n operatorBusy: {\n isActive: false,\n calledNumber: null,\n callerNumber: null,\n },\n}\n\nexport const island = createModel<RootModel>()({\n state: defaultState,\n reducers: {\n setIslandView: (state, newView: IslandViewType | null) => {\n if (newView === state?.view) {\n // Don't change view if it's the same\n return state\n } else {\n return {\n ...state,\n view: newView,\n previousView: state?.view,\n }\n }\n },\n toggleIsOpen: (state, payload: boolean) => {\n return {\n ...state,\n isOpen: payload,\n }\n },\n toggleActionsExpanded: (state, payload: boolean) => {\n state.actionsExpanded = payload\n return state\n },\n toggleInputOutputOpened: (state, payload: boolean) => {\n state.inputOutputOpened = payload\n return state\n },\n setSettingsView: (state, payload: SettingsViewType) => {\n state.settingsView = payload\n },\n setContactListView: (state, payload: ContactListViewType) => {\n state.contactListView = payload\n },\n toggleSideViewVisible: (state, payload: boolean) => {\n state.sideViewIsVisible = payload\n },\n toggleTranscriptionViewVisible: (state, payload: boolean) => {\n state.transcriptionViewIsVisible = payload\n },\n toggleConferenceList: (state, payload: boolean) => {\n state.isConferenceList = payload\n },\n toggleAvoidToShow: (state, payload: boolean) => {\n state.avoidToShow = payload\n },\n setUrlOpened: (state, payload: boolean) => {\n state.urlOpened = payload\n return state\n },\n setPreviewCallFromMobileOrNethlink: (state, payload: boolean) => {\n state.previewCallFromMobileOrNethlink = payload\n return state\n },\n setForceReload: (state, payload: boolean) => {\n state.forceReload = payload\n return state\n },\n resetSettingsView: (state) => {\n state.settingsView = 'main'\n },\n setFullScreen: (state, payload: boolean) => {\n return {\n ...state,\n isFullScreen: payload,\n }\n },\n setIsFromStreaming: (state, payload: boolean) => {\n return {\n ...state,\n isFromStreaming: payload,\n }\n },\n setExtraLarge: (state, payload: boolean) => {\n return {\n ...state,\n isExtraLarge: payload,\n }\n },\n resetPlayerClose: (state) => {\n return getResetState(state, false)\n },\n resetIslandStore: (state) => {\n return getResetState(state, true)\n },\n _resetIslandStoreInternal: (state) => {\n return getResetState(state, true)\n },\n _resetPlayerCloseInternal: (state) => {\n return getResetState(state, false)\n },\n setOperatorBusyCalledNumber: (state, payload: string) => {\n state.operatorBusy.calledNumber = payload\n return state\n },\n setOperatorBusyActive: (state, payload: { callerNumber: string }) => {\n state.operatorBusy.isActive = true\n state.operatorBusy.callerNumber = payload.callerNumber\n return state\n },\n resetOperatorBusy: (state) => {\n state.operatorBusy.isActive = false\n state.operatorBusy.callerNumber = null\n // Keep calledNumber for potential reuse\n return state\n },\n resetOperatorBusyCompletely: (state) => {\n state.operatorBusy.isActive = false\n state.operatorBusy.calledNumber = null\n state.operatorBusy.callerNumber = null\n return state\n },\n },\n effects: (dispatch) => ({\n handleToggleIsOpen: (_: void, rootState) => {\n if (\n rootState.island.isOpen &&\n rootState.alerts.status.activeAlertsCount > 0 &&\n !rootState.currentCall.displayName\n ) {\n eventDispatch('phone-island-expanded', {})\n dispatch.island.toggleIsOpen(true)\n } else {\n eventDispatch('phone-island-' + (rootState.island.isOpen ? 'compressed' : 'expanded'), {})\n if (rootState.island.isOpen) {\n eventDispatch('phone-island-sideview-close', {})\n eventDispatch('phone-island-transcription-close', {})\n }\n dispatch.island.toggleIsOpen(!rootState.island.isOpen)\n }\n },\n handleResetIslandStore: () => {\n dispatch.island._resetIslandStoreInternal()\n eventDispatch('phone-island-transcription-close', {})\n },\n handleResetPlayerClose: () => {\n dispatch.island._resetPlayerCloseInternal()\n eventDispatch('phone-island-transcription-close', {})\n },\n }),\n})\n\nfunction getResetState(state: IslandTypes, includeRecorder: boolean): IslandTypes {\n // Keep beginning position\n const preservedStartPosition = state.startPosition\n // Determine which view to preserve\n const viewsToPreserve = ['waitingConference']\n if (includeRecorder) {\n viewsToPreserve.push('recorder')\n }\n\n const preservedView = viewsToPreserve.includes(state.view as string)\n ? state.view\n : defaultState.view\n const avoidToShow = state.avoidToShow\n\n return {\n ...defaultState,\n startPosition: preservedStartPosition,\n view: preservedView,\n avoidToShow: avoidToShow,\n isFromStreaming: false,\n previewCallFromMobileOrNethlink: false,\n forceReload: false,\n // Keep previousView if waitingConference\n previousView:\n state.view === 'waitingConference' ? state.previousView : defaultState.previousView,\n // Preserve calledNumber for potential operator busy scenarios\n operatorBusy: {\n isActive: false,\n calledNumber: state.operatorBusy.calledNumber,\n callerNumber: null,\n },\n }\n}\n\ntype IslandViewType =\n | 'call'\n | 'keypad'\n | 'player'\n | 'transfer'\n | 'recorder'\n | 'physicalPhoneRecorder'\n | 'settings'\n | 'video'\n | 'conference'\n | 'switchDevice'\n | 'waitingConference'\n | 'streamingAnswer'\n | 'operatorBusy'\ntype SettingsViewType = 'microphone' | 'audioInput' | 'videoInput' | 'theme' | 'main'\ntype ContactListViewType = 'main' | 'selectContactNumber'\n\ninterface IslandTypes {\n view?: IslandViewType | null\n isOpen: boolean\n actionsExpanded: boolean\n startPosition: {\n x: number\n y: number\n }\n inputOutputOpened: boolean\n settingsView: SettingsViewType\n contactListView: ContactListViewType\n sideViewIsVisible: boolean\n transcriptionViewIsVisible: boolean\n isConferenceList: boolean\n previousView?: IslandViewType | null\n avoidToShow?: boolean\n isFullScreen: boolean\n isFromStreaming: boolean\n isExtraLarge: boolean\n urlOpened: boolean\n previewCallFromMobileOrNethlink: boolean\n forceReload: boolean\n operatorBusy: {\n isActive: boolean\n calledNumber: string | null\n callerNumber: string | null\n }\n}\n"],"names":["defaultState","view","isOpen","actionsExpanded","startPosition","x","y","inputOutputOpened","settingsView","contactListView","sideViewIsVisible","transcriptionViewIsVisible","isConferenceList","previousView","avoidToShow","isFullScreen","isFromStreaming","isExtraLarge","urlOpened","previewCallFromMobileOrNethlink","forceReload","operatorBusy","isActive","calledNumber","callerNumber","island","createModel","state","reducers","setIslandView","newView","__assign","toggleIsOpen","payload","toggleActionsExpanded","toggleInputOutputOpened","setSettingsView","setContactListView","toggleSideViewVisible","toggleTranscriptionViewVisible","toggleConferenceList","toggleAvoidToShow","setUrlOpened","setPreviewCallFromMobileOrNethlink","setForceReload","resetSettingsView","setFullScreen","setIsFromStreaming","setExtraLarge","resetPlayerClose","getResetState","resetIslandStore","_resetIslandStoreInternal","_resetPlayerCloseInternal","setOperatorBusyCalledNumber","setOperatorBusyActive","resetOperatorBusy","resetOperatorBusyCompletely","effects","dispatch","handleToggleIsOpen","_","rootState","alerts","status","activeAlertsCount","currentCall","displayName","eventDispatch","handleResetIslandStore","handleResetPlayerClose","includeRecorder","preservedStartPosition","viewsToPreserve","push","preservedView","includes"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e={width:168,height:40},d={width:348,height:304},i={padding_expanded:24,alert_padding_expanded:2,padding_x_collapsed:8,padding_y_collapsed:16,border_radius_expanded:20,border_radius_collapsed:99,border_radius_collapsed_conference:8,variants:{call:{expanded:{incoming:{width:418,height:96},incomingQueue:{width:418,height:124},incomingStreaming:{width:500,height:278},outgoing:{width:418,height:96},outgoingStreaming:{width:500,height:278},accepted:{width:348,height:236,actionsExpanded:d},listening:{width:348,height:168},transfer:{width:348,height:236,actionsExpanded:d}},collapsed:e},keypad:{expanded:{width:338,height:400},collapsed:e},transfer:{expanded:{width:408,height:410},collapsed:e},player:{expanded:{width:374,height:236},collapsed:e},recorder:{expanded:{width:374,height:272},collapsed:e},physicalPhoneRecorder:{expanded:{width:374,height:256},collapsed:e},alerts:{width:418,height:88},settings:{expanded:d,collapsed:e},video:{expanded:{width:600,height:480,padding:0},collapsed:e},screenShare:{expanded:{width:600,height:480},collapsed:e},conference:{expanded:d,collapsed:e},switchDevice:{expanded:d,collapsed:e},waitingConference:{expanded:{width:348,height:360},collapsed:{width:180,height:74}},streamingAnswer:{expanded:{width:600,height:480,padding:0},extraLarge:{width:936,height:748,padding:0},collapsed:e},operatorBusy:{expanded:{width:400,height:104},collapsed:{width:400,height:104}}}},t=require("../node_modules/@rematch/core/dist/core.esm.js").createModel()({state:i});exports.motions=t;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e={width:168,height:40},d={width:348,height:304},i={padding_expanded:24,alert_padding_expanded:2,padding_x_collapsed:8,padding_y_collapsed:16,border_radius_expanded:20,border_radius_collapsed:99,border_radius_collapsed_conference:8,variants:{call:{expanded:{incoming:{width:418,height:96},incomingQueue:{width:418,height:124},incomingStreaming:{width:500,height:68,previewWidth:500,gatesHeight:52},outgoing:{width:418,height:96},outgoingStreaming:{width:500,height:68,previewWidth:500,gatesHeight:52},accepted:{width:348,height:236,actionsExpanded:d},listening:{width:348,height:168},transfer:{width:348,height:236,actionsExpanded:d}},collapsed:e},keypad:{expanded:{width:338,height:400},collapsed:e},transfer:{expanded:{width:408,height:410},collapsed:e},player:{expanded:{width:374,height:236},collapsed:e},recorder:{expanded:{width:374,height:272},collapsed:e},physicalPhoneRecorder:{expanded:{width:374,height:256},collapsed:e},alerts:{width:418,height:88},settings:{expanded:d,collapsed:e},video:{expanded:{width:600,height:480,padding:0},collapsed:e},screenShare:{expanded:{width:600,height:480},collapsed:e},conference:{expanded:d,collapsed:e},switchDevice:{expanded:d,collapsed:e},waitingConference:{expanded:{width:348,height:360},collapsed:{width:180,height:74}},streamingAnswer:{expanded:{width:600,height:80,previewWidth:600,padding:0},extraLarge:{width:936,height:80,previewWidth:936,padding:0},collapsed:e},operatorBusy:{expanded:{width:400,height:104},collapsed:{width:400,height:104}}}},t=require("../node_modules/@rematch/core/dist/core.esm.js").createModel()({state:i});exports.motions=t;
2
2
  //# sourceMappingURL=motions.js.map