@wazo/sdk 0.38.22 → 0.39.0-beta.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.
- package/README.md +0 -293
- package/dist/wazo-sdk.js +9 -25
- package/esm/__tests__/api-client.test.js +183 -5059
- package/esm/__tests__/web-rtc-client.test.js +177 -7930
- package/esm/api/agentd.js +23 -832
- package/esm/api/amid.js +9 -411
- package/esm/api/application.js +60 -829
- package/esm/api/auth.js +164 -1213
- package/esm/api/call-logd.js +24 -733
- package/esm/api/calld.js +114 -1469
- package/esm/api/chatd.js +35 -1312
- package/esm/api/confd.js +67 -1580
- package/esm/api/ctid-ng.js +92 -1343
- package/esm/api/dird.js +100 -1590
- package/esm/api/webhookd.js +7 -513
- package/esm/api-client.js +143 -4881
- package/esm/checker/Checker.js +45 -8727
- package/esm/checker/checks/aor.js +24 -4924
- package/esm/checker/checks/api.js +70 -4968
- package/esm/checker/checks/ice-ipv4.js +63 -117
- package/esm/checker/checks/index.js +8 -8677
- package/esm/checker/checks/symmetric-nat.js +54 -102
- package/esm/checker/checks/wazo-websocket.js +34 -999
- package/esm/checker/checks/webrtc-transport.js +28 -7845
- package/esm/checker/checks/webrtc.js +31 -7852
- package/esm/domain/AdHocAPIConference.js +86 -5115
- package/esm/domain/Agent.js +27 -61
- package/esm/domain/BadResponse.js +20 -43
- package/esm/domain/Call.js +120 -210
- package/esm/domain/CallLog.js +123 -305
- package/esm/domain/CallSession.js +251 -423
- package/esm/domain/ChatMessage.js +52 -105
- package/esm/domain/ChatRoom.js +28 -60
- package/esm/domain/Contact.js +430 -741
- package/esm/domain/Country.js +17 -19
- package/esm/domain/Device/DebugDevice.js +31 -47
- package/esm/domain/Device/Device.js +1 -1
- package/esm/domain/DirectorySource.js +1 -1
- package/esm/domain/ExternalApp.js +23 -56
- package/esm/domain/Features.js +57 -5009
- package/esm/domain/ForwardOption.js +35 -70
- package/esm/domain/IndirectTransfer.js +38 -97
- package/esm/domain/Line.js +37 -88
- package/esm/domain/Meeting.js +58 -113
- package/esm/domain/MeetingAuthorization.js +38 -68
- package/esm/domain/MeetingStatus.js +13 -28
- package/esm/domain/NotificationOptions.js +43 -77
- package/esm/domain/Phone/CTIPhone.js +245 -5743
- package/esm/domain/Phone/Phone.js +1 -2
- package/esm/domain/Phone/WebRTCPhone.js +1446 -2670
- package/esm/domain/Profile.js +120 -405
- package/esm/domain/Recording.js +27 -51
- package/esm/domain/Relocation.js +16 -40
- package/esm/domain/Room.js +90 -133
- package/esm/domain/SFUNotAvailableError.js +5 -8
- package/esm/domain/ServerError.js +8 -61
- package/esm/domain/Session.js +125 -251
- package/esm/domain/SipLine.js +78 -155
- package/esm/domain/Subscription.js +39 -83
- package/esm/domain/SwitchboardCall.js +51 -143
- package/esm/domain/Voicemail.js +57 -122
- package/esm/domain/__tests__/Agent.test.js +31 -101
- package/esm/domain/__tests__/Call.test.js +24 -232
- package/esm/domain/__tests__/CallLog.test.js +60 -386
- package/esm/domain/__tests__/CallSession.test.js +74 -502
- package/esm/domain/__tests__/Contact.test.js +220 -902
- package/esm/domain/__tests__/IndirectTransfer.test.js +63 -546
- package/esm/domain/__tests__/Line.test.js +48 -156
- package/esm/domain/__tests__/Meeting.test.js +73 -226
- package/esm/domain/__tests__/MeetingAuthorization.test.js +45 -105
- package/esm/domain/__tests__/Profile.test.js +135 -496
- package/esm/domain/__tests__/Room.test.js +227 -719
- package/esm/domain/__tests__/Session.test.js +357 -1025
- package/esm/domain/__tests__/SipLine.test.js +24 -179
- package/esm/domain/__tests__/Voicemail.test.js +82 -200
- package/esm/domain/types.js +1 -1
- package/esm/index.js +63 -14985
- package/esm/lib/WazoSessionDescriptionHandler.js +406 -890
- package/esm/pubkey.js +10 -0
- package/esm/service/CallApi.js +42 -5014
- package/esm/service/IssueReporter.js +278 -360
- package/esm/service/__tests__/IssueReporter.test.js +92 -494
- package/esm/service/getApiClient.js +53 -4972
- package/esm/simple/Auth.js +211 -14747
- package/esm/simple/Configuration.js +8 -14796
- package/esm/simple/Directory.js +6 -4964
- package/esm/simple/Phone.js +309 -14727
- package/esm/simple/Websocket.js +68 -1112
- package/esm/simple/index.js +125 -14792
- package/esm/simple/room/LocalParticipant.js +1 -14797
- package/esm/simple/room/Participant.js +274 -14760
- package/esm/simple/room/RemoteParticipant.js +6 -14796
- package/esm/simple/room/Room.js +648 -14736
- package/esm/simple/room/SipRoom.js +111 -14790
- package/esm/simple/room/Stream.js +40 -14792
- package/esm/simple/room/__tests__/Participant.test.js +68 -14872
- package/esm/simple/room/__tests__/RemoteParticipant.test.js +10 -14805
- package/esm/simple/utils.js +9 -14799
- package/esm/types/WebSocketMessage.js +1 -1
- package/esm/types/__tests__/api-client.test.d.ts +2 -0
- package/esm/types/__tests__/api-client.test.d.ts.map +1 -0
- package/esm/types/__tests__/web-rtc-client.test.d.ts +2 -0
- package/esm/types/__tests__/web-rtc-client.test.d.ts.map +1 -0
- package/esm/types/api/agentd.d.ts +17 -0
- package/esm/types/api/agentd.d.ts.map +1 -0
- package/esm/types/api/amid.d.ts +8 -0
- package/esm/types/api/amid.d.ts.map +1 -0
- package/esm/types/api/application.d.ts +34 -0
- package/esm/types/api/application.d.ts.map +1 -0
- package/esm/types/api/auth.d.ts +64 -0
- package/esm/types/api/auth.d.ts.map +1 -0
- package/esm/types/api/call-logd.d.ts +12 -0
- package/esm/types/api/call-logd.d.ts.map +1 -0
- package/esm/types/api/calld.d.ts +51 -0
- package/esm/types/api/calld.d.ts.map +1 -0
- package/esm/types/api/chatd.d.ts +42 -0
- package/esm/types/api/chatd.d.ts.map +1 -0
- package/esm/types/api/confd.d.ts +39 -0
- package/esm/types/api/confd.d.ts.map +1 -0
- package/esm/types/api/ctid-ng.d.ts +36 -0
- package/esm/types/api/ctid-ng.d.ts.map +1 -0
- package/esm/types/api/dird.d.ts +38 -0
- package/esm/types/api/dird.d.ts.map +1 -0
- package/esm/types/api/webhookd.d.ts +24 -0
- package/esm/types/api/webhookd.d.ts.map +1 -0
- package/esm/types/api-client.d.ts +63 -0
- package/esm/types/api-client.d.ts.map +1 -0
- package/esm/types/checker/Checker.d.ts +13 -0
- package/esm/types/checker/Checker.d.ts.map +1 -0
- package/esm/types/checker/checks/aor.d.ts +6 -0
- package/esm/types/checker/checks/aor.d.ts.map +1 -0
- package/esm/types/checker/checks/api.d.ts +6 -0
- package/esm/types/checker/checks/api.d.ts.map +1 -0
- package/esm/types/checker/checks/ice-ipv4.d.ts +6 -0
- package/esm/types/checker/checks/ice-ipv4.d.ts.map +1 -0
- package/esm/types/checker/checks/index.d.ts +9 -0
- package/esm/types/checker/checks/index.d.ts.map +1 -0
- package/esm/types/checker/checks/symmetric-nat.d.ts +6 -0
- package/esm/types/checker/checks/symmetric-nat.d.ts.map +1 -0
- package/esm/types/checker/checks/wazo-websocket.d.ts +6 -0
- package/esm/types/checker/checks/wazo-websocket.d.ts.map +1 -0
- package/esm/types/checker/checks/webrtc-transport.d.ts +7 -0
- package/esm/types/checker/checks/webrtc-transport.d.ts.map +1 -0
- package/esm/types/checker/checks/webrtc.d.ts +6 -0
- package/esm/types/checker/checks/webrtc.d.ts.map +1 -0
- package/esm/types/domain/AdHocAPIConference.d.ts +54 -0
- package/esm/types/domain/AdHocAPIConference.d.ts.map +1 -0
- package/esm/types/domain/Agent.d.ts +31 -0
- package/esm/types/domain/Agent.d.ts.map +1 -0
- package/esm/types/domain/BadResponse.d.ts +11 -0
- package/esm/types/domain/BadResponse.d.ts.map +1 -0
- package/esm/types/domain/Call.d.ts +79 -0
- package/esm/types/domain/Call.d.ts.map +1 -0
- package/esm/types/domain/CallLog.d.ts +91 -0
- package/esm/types/domain/CallLog.d.ts.map +1 -0
- package/esm/types/domain/CallSession.d.ts +120 -0
- package/esm/types/domain/CallSession.d.ts.map +1 -0
- package/esm/types/domain/ChatMessage.d.ts +41 -0
- package/esm/types/domain/ChatMessage.d.ts.map +1 -0
- package/esm/types/domain/ChatRoom.d.ts +22 -0
- package/esm/types/domain/ChatRoom.d.ts.map +1 -0
- package/esm/types/domain/Contact.d.ts +316 -0
- package/esm/types/domain/Contact.d.ts.map +1 -0
- package/esm/types/domain/Country.d.ts +20 -0
- package/esm/types/domain/Country.d.ts.map +1 -0
- package/esm/types/domain/Device/DebugDevice.d.ts +14 -0
- package/esm/types/domain/Device/DebugDevice.d.ts.map +1 -0
- package/esm/types/domain/Device/Device.d.ts +13 -0
- package/esm/types/domain/Device/Device.d.ts.map +1 -0
- package/esm/types/domain/DirectorySource.d.ts +13 -0
- package/esm/types/domain/DirectorySource.d.ts.map +1 -0
- package/esm/types/domain/ExternalApp.d.ts +22 -0
- package/esm/types/domain/ExternalApp.d.ts.map +1 -0
- package/esm/types/domain/Features.d.ts +24 -0
- package/esm/types/domain/Features.d.ts.map +1 -0
- package/esm/types/domain/ForwardOption.d.ts +27 -0
- package/esm/types/domain/ForwardOption.d.ts.map +1 -0
- package/esm/types/domain/IndirectTransfer.d.ts +31 -0
- package/esm/types/domain/IndirectTransfer.d.ts.map +1 -0
- package/esm/types/domain/Line.d.ts +46 -0
- package/esm/types/domain/Line.d.ts.map +1 -0
- package/esm/types/domain/Meeting.d.ts +45 -0
- package/esm/types/domain/Meeting.d.ts.map +1 -0
- package/esm/types/domain/MeetingAuthorization.d.ts +26 -0
- package/esm/types/domain/MeetingAuthorization.d.ts.map +1 -0
- package/esm/types/domain/MeetingStatus.d.ts +10 -0
- package/esm/types/domain/MeetingStatus.d.ts.map +1 -0
- package/esm/types/domain/NotificationOptions.d.ts +22 -0
- package/esm/types/domain/NotificationOptions.d.ts.map +1 -0
- package/esm/types/domain/Phone/CTIPhone.d.ts +76 -0
- package/esm/types/domain/Phone/CTIPhone.d.ts.map +1 -0
- package/esm/types/domain/Phone/Phone.d.ts +71 -0
- package/esm/types/domain/Phone/Phone.d.ts.map +1 -0
- package/esm/types/domain/Phone/WebRTCPhone.d.ts +179 -0
- package/esm/types/domain/Phone/WebRTCPhone.d.ts.map +1 -0
- package/esm/types/domain/Profile.d.ts +151 -0
- package/esm/types/domain/Profile.d.ts.map +1 -0
- package/esm/types/domain/Recording.d.ts +26 -0
- package/esm/types/domain/Recording.d.ts.map +1 -0
- package/esm/types/domain/Relocation.d.ts +23 -0
- package/esm/types/domain/Relocation.d.ts.map +1 -0
- package/esm/types/domain/Room.d.ts +35 -0
- package/esm/types/domain/Room.d.ts.map +1 -0
- package/esm/types/domain/SFUNotAvailableError.d.ts +4 -0
- package/esm/types/domain/SFUNotAvailableError.d.ts.map +1 -0
- package/esm/types/domain/ServerError.d.ts +6 -0
- package/esm/types/domain/ServerError.d.ts.map +1 -0
- package/esm/types/domain/Session.d.ts +90 -0
- package/esm/types/domain/Session.d.ts.map +1 -0
- package/esm/types/domain/SipLine.d.ts +54 -0
- package/esm/types/domain/SipLine.d.ts.map +1 -0
- package/esm/types/domain/Subscription.d.ts +43 -0
- package/esm/types/domain/Subscription.d.ts.map +1 -0
- package/esm/types/domain/SwitchboardCall.d.ts +62 -0
- package/esm/types/domain/SwitchboardCall.d.ts.map +1 -0
- package/esm/types/domain/Voicemail.d.ts +50 -0
- package/esm/types/domain/Voicemail.d.ts.map +1 -0
- package/esm/types/domain/__tests__/Agent.test.d.ts +2 -0
- package/esm/types/domain/__tests__/Agent.test.d.ts.map +1 -0
- package/esm/types/domain/__tests__/Call.test.d.ts +2 -0
- package/esm/types/domain/__tests__/Call.test.d.ts.map +1 -0
- package/esm/types/domain/__tests__/CallLog.test.d.ts +2 -0
- package/esm/types/domain/__tests__/CallLog.test.d.ts.map +1 -0
- package/esm/types/domain/__tests__/CallSession.test.d.ts +2 -0
- package/esm/types/domain/__tests__/CallSession.test.d.ts.map +1 -0
- package/esm/types/domain/__tests__/Contact.test.d.ts +2 -0
- package/esm/types/domain/__tests__/Contact.test.d.ts.map +1 -0
- package/esm/types/domain/__tests__/IndirectTransfer.test.d.ts +2 -0
- package/esm/types/domain/__tests__/IndirectTransfer.test.d.ts.map +1 -0
- package/esm/types/domain/__tests__/Line.test.d.ts +2 -0
- package/esm/types/domain/__tests__/Line.test.d.ts.map +1 -0
- package/esm/types/domain/__tests__/Meeting.test.d.ts +2 -0
- package/esm/types/domain/__tests__/Meeting.test.d.ts.map +1 -0
- package/esm/types/domain/__tests__/MeetingAuthorization.test.d.ts +2 -0
- package/esm/types/domain/__tests__/MeetingAuthorization.test.d.ts.map +1 -0
- package/esm/types/domain/__tests__/Profile.test.d.ts +2 -0
- package/esm/types/domain/__tests__/Profile.test.d.ts.map +1 -0
- package/esm/types/domain/__tests__/Room.test.d.ts +2 -0
- package/esm/types/domain/__tests__/Room.test.d.ts.map +1 -0
- package/esm/types/domain/__tests__/Session.test.d.ts +2 -0
- package/esm/types/domain/__tests__/Session.test.d.ts.map +1 -0
- package/esm/types/domain/__tests__/SipLine.test.d.ts +2 -0
- package/esm/types/domain/__tests__/SipLine.test.d.ts.map +1 -0
- package/esm/types/domain/__tests__/Voicemail.test.d.ts +2 -0
- package/esm/types/domain/__tests__/Voicemail.test.d.ts.map +1 -0
- package/esm/types/domain/types.d.ts +217 -0
- package/esm/types/domain/types.d.ts.map +1 -0
- package/esm/types/index.d.ts +304 -0
- package/esm/types/index.d.ts.map +1 -0
- package/esm/types/lib/WazoSessionDescriptionHandler.d.ts +30 -0
- package/esm/types/lib/WazoSessionDescriptionHandler.d.ts.map +1 -0
- package/esm/types/pubkey.d.ts +3 -0
- package/esm/types/pubkey.d.ts.map +1 -0
- package/esm/types/service/CallApi.d.ts +28 -0
- package/esm/types/service/CallApi.d.ts.map +1 -0
- package/esm/types/service/IssueReporter.d.ts +40 -0
- package/esm/types/service/IssueReporter.d.ts.map +1 -0
- package/esm/types/service/__tests__/IssueReporter.test.d.ts +2 -0
- package/esm/types/service/__tests__/IssueReporter.test.d.ts.map +1 -0
- package/esm/types/service/getApiClient.d.ts +16 -0
- package/esm/types/service/getApiClient.d.ts.map +1 -0
- package/esm/types/simple/Auth.d.ts +51 -0
- package/esm/types/simple/Auth.d.ts.map +1 -0
- package/esm/types/simple/Configuration.d.ts +3 -0
- package/esm/types/simple/Configuration.d.ts.map +1 -0
- package/esm/types/simple/Directory.d.ts +3 -0
- package/esm/types/simple/Directory.d.ts.map +1 -0
- package/esm/types/simple/Phone.d.ts +115 -0
- package/esm/types/simple/Phone.d.ts.map +1 -0
- package/esm/types/simple/Websocket.d.ts +19 -0
- package/esm/types/simple/Websocket.d.ts.map +1 -0
- package/esm/types/simple/index.d.ts +147 -0
- package/esm/types/simple/index.d.ts.map +1 -0
- package/esm/types/simple/room/LocalParticipant.d.ts +5 -0
- package/esm/types/simple/room/LocalParticipant.d.ts.map +1 -0
- package/esm/types/simple/room/Participant.d.ts +76 -0
- package/esm/types/simple/room/Participant.d.ts.map +1 -0
- package/esm/types/simple/room/RemoteParticipant.d.ts +7 -0
- package/esm/types/simple/room/RemoteParticipant.d.ts.map +1 -0
- package/esm/types/simple/room/Room.d.ts +116 -0
- package/esm/types/simple/room/Room.d.ts.map +1 -0
- package/esm/types/simple/room/SipRoom.d.ts +14 -0
- package/esm/types/simple/room/SipRoom.d.ts.map +1 -0
- package/esm/types/simple/room/Stream.d.ts +13 -0
- package/esm/types/simple/room/Stream.d.ts.map +1 -0
- package/esm/types/simple/room/__tests__/Participant.test.d.ts +2 -0
- package/esm/types/simple/room/__tests__/Participant.test.d.ts.map +1 -0
- package/esm/types/simple/room/__tests__/RemoteParticipant.test.d.ts +2 -0
- package/esm/types/simple/room/__tests__/RemoteParticipant.test.d.ts.map +1 -0
- package/esm/types/simple/utils.d.ts +3 -0
- package/esm/types/simple/utils.d.ts.map +1 -0
- package/esm/types/types/WebSocketMessage.d.ts +285 -0
- package/esm/types/types/WebSocketMessage.d.ts.map +1 -0
- package/esm/types/utils/Emitter.d.ts +18 -0
- package/esm/types/utils/Emitter.d.ts.map +1 -0
- package/esm/types/utils/Heartbeat.d.ts +21 -0
- package/esm/types/utils/Heartbeat.d.ts.map +1 -0
- package/esm/types/utils/PhoneNumberUtil.d.ts +8 -0
- package/esm/types/utils/PhoneNumberUtil.d.ts.map +1 -0
- package/esm/types/utils/__tests__/Heartbeat.test.d.ts +2 -0
- package/esm/types/utils/__tests__/Heartbeat.test.d.ts.map +1 -0
- package/esm/types/utils/__tests__/PhoneNumberUtil.test.d.ts +2 -0
- package/esm/types/utils/__tests__/PhoneNumberUtil.test.d.ts.map +1 -0
- package/esm/types/utils/__tests__/api-requester.test.d.ts +2 -0
- package/esm/types/utils/__tests__/api-requester.test.d.ts.map +1 -0
- package/esm/types/utils/__tests__/array.test.d.ts +2 -0
- package/esm/types/utils/__tests__/array.test.d.ts.map +1 -0
- package/esm/types/utils/__tests__/compare-version.test.d.ts +2 -0
- package/esm/types/utils/__tests__/compare-version.test.d.ts.map +1 -0
- package/esm/types/utils/__tests__/object.test.d.ts +2 -0
- package/esm/types/utils/__tests__/object.test.d.ts.map +1 -0
- package/esm/types/utils/__tests__/sdp.test.d.ts +2 -0
- package/esm/types/utils/__tests__/sdp.test.d.ts.map +1 -0
- package/esm/types/utils/__tests__/string.test.d.ts +2 -0
- package/esm/types/utils/__tests__/string.test.d.ts.map +1 -0
- package/esm/types/utils/api-requester.d.ts +45 -0
- package/esm/types/utils/api-requester.d.ts.map +1 -0
- package/esm/types/utils/array.d.ts +2 -0
- package/esm/types/utils/array.d.ts.map +1 -0
- package/esm/types/utils/compare-version.d.ts +3 -0
- package/esm/types/utils/compare-version.d.ts.map +1 -0
- package/esm/types/utils/isMobile.d.ts +3 -0
- package/esm/types/utils/isMobile.d.ts.map +1 -0
- package/esm/types/utils/new-from.d.ts +3 -0
- package/esm/types/utils/new-from.d.ts.map +1 -0
- package/esm/types/utils/object.d.ts +2 -0
- package/esm/types/utils/object.d.ts.map +1 -0
- package/esm/types/utils/once.d.ts +2 -0
- package/esm/types/utils/once.d.ts.map +1 -0
- package/esm/types/utils/sdp.d.ts +13 -0
- package/esm/types/utils/sdp.d.ts.map +1 -0
- package/esm/types/utils/string.d.ts +2 -0
- package/esm/types/utils/string.d.ts.map +1 -0
- package/esm/types/utils/update-from.d.ts +3 -0
- package/esm/types/utils/update-from.d.ts.map +1 -0
- package/esm/types/utils/webrtc.d.ts +15 -0
- package/esm/types/utils/webrtc.d.ts.map +1 -0
- package/esm/types/web-rtc-client.d.ts +211 -0
- package/esm/types/web-rtc-client.d.ts.map +1 -0
- package/esm/types/websocket-client.d.ts +134 -0
- package/esm/types/websocket-client.d.ts.map +1 -0
- package/esm/utils/Emitter.js +17 -27
- package/esm/utils/Heartbeat.js +60 -83
- package/esm/utils/PhoneNumberUtil.js +48 -63
- package/esm/utils/__tests__/Heartbeat.test.js +59 -168
- package/esm/utils/__tests__/PhoneNumberUtil.test.js +55 -125
- package/esm/utils/__tests__/api-requester.test.js +127 -780
- package/esm/utils/__tests__/array.test.js +16 -19
- package/esm/utils/__tests__/compare-version.test.js +8 -26
- package/esm/utils/__tests__/object.test.js +73 -54
- package/esm/utils/__tests__/sdp.test.js +87 -216
- package/esm/utils/__tests__/string.test.js +21 -27
- package/esm/utils/api-requester.js +197 -675
- package/esm/utils/array.js +7 -11
- package/esm/utils/compare-version.js +12 -15
- package/esm/utils/isMobile.js +0 -2
- package/esm/utils/new-from.js +7 -12
- package/esm/utils/object.js +9 -23
- package/esm/utils/once.js +12 -13
- package/esm/utils/sdp.js +87 -131
- package/esm/utils/string.js +5 -9
- package/esm/utils/update-from.js +9 -16
- package/esm/utils/webrtc.js +35 -36
- package/esm/web-rtc-client.js +1973 -7676
- package/esm/websocket-client.js +352 -944
- package/lib/__tests__/api-client.test.js +199 -5067
- package/lib/__tests__/web-rtc-client.test.js +191 -7941
- package/lib/api/agentd.js +27 -837
- package/lib/api/amid.js +18 -415
- package/lib/api/application.js +64 -834
- package/lib/api/auth.js +166 -1222
- package/lib/api/call-logd.js +28 -738
- package/lib/api/calld.js +126 -1473
- package/lib/api/chatd.js +49 -1316
- package/lib/api/confd.js +79 -1584
- package/lib/api/ctid-ng.js +96 -1348
- package/lib/api/dird.js +105 -1596
- package/lib/api/webhookd.js +11 -518
- package/lib/api-client.js +138 -4884
- package/lib/checker/Checker.js +61 -8739
- package/lib/checker/checks/aor.js +37 -4929
- package/lib/checker/checks/api.js +81 -4971
- package/lib/checker/checks/ice-ipv4.js +66 -118
- package/lib/checker/checks/index.js +13 -8687
- package/lib/checker/checks/symmetric-nat.js +56 -104
- package/lib/checker/checks/wazo-websocket.js +58 -1006
- package/lib/checker/checks/webrtc-transport.js +41 -7853
- package/lib/checker/checks/webrtc.js +42 -7858
- package/lib/domain/AdHocAPIConference.js +80 -5116
- package/lib/domain/Agent.js +23 -64
- package/lib/domain/BadResponse.js +17 -44
- package/lib/domain/Call.js +108 -215
- package/lib/domain/CallLog.js +117 -311
- package/lib/domain/CallSession.js +221 -424
- package/lib/domain/ChatMessage.js +49 -110
- package/lib/domain/ChatRoom.js +28 -60
- package/lib/domain/Contact.js +404 -742
- package/lib/domain/Country.js +19 -21
- package/lib/domain/Device/DebugDevice.js +34 -49
- package/lib/domain/Device/Device.js +2 -2
- package/lib/domain/DirectorySource.js +2 -2
- package/lib/domain/ExternalApp.js +24 -56
- package/lib/domain/Features.js +68 -5018
- package/lib/domain/ForwardOption.js +36 -71
- package/lib/domain/IndirectTransfer.js +39 -98
- package/lib/domain/Line.js +35 -88
- package/lib/domain/Meeting.js +51 -118
- package/lib/domain/MeetingAuthorization.js +35 -75
- package/lib/domain/MeetingStatus.js +13 -29
- package/lib/domain/NotificationOptions.js +45 -77
- package/lib/domain/Phone/CTIPhone.js +283 -5755
- package/lib/domain/Phone/Phone.js +2 -5
- package/lib/domain/Phone/WebRTCPhone.js +1446 -2715
- package/lib/domain/Profile.js +127 -406
- package/lib/domain/Recording.js +28 -57
- package/lib/domain/Relocation.js +15 -43
- package/lib/domain/Room.js +73 -134
- package/lib/domain/SFUNotAvailableError.js +7 -9
- package/lib/domain/ServerError.js +14 -63
- package/lib/domain/Session.js +118 -251
- package/lib/domain/SipLine.js +70 -155
- package/lib/domain/Subscription.js +32 -86
- package/lib/domain/SwitchboardCall.js +45 -145
- package/lib/domain/Voicemail.js +56 -127
- package/lib/domain/__tests__/Agent.test.js +36 -103
- package/lib/domain/__tests__/Call.test.js +28 -237
- package/lib/domain/__tests__/CallLog.test.js +65 -392
- package/lib/domain/__tests__/CallSession.test.js +78 -503
- package/lib/domain/__tests__/Contact.test.js +224 -903
- package/lib/domain/__tests__/IndirectTransfer.test.js +75 -546
- package/lib/domain/__tests__/Line.test.js +52 -157
- package/lib/domain/__tests__/Meeting.test.js +78 -232
- package/lib/domain/__tests__/MeetingAuthorization.test.js +50 -107
- package/lib/domain/__tests__/Profile.test.js +161 -496
- package/lib/domain/__tests__/Room.test.js +239 -719
- package/lib/domain/__tests__/Session.test.js +350 -1024
- package/lib/domain/__tests__/SipLine.test.js +28 -180
- package/lib/domain/__tests__/Voicemail.test.js +86 -205
- package/lib/domain/types.js +2 -2
- package/lib/index.js +105 -15010
- package/lib/lib/WazoSessionDescriptionHandler.js +409 -898
- package/lib/pubkey.js +12 -0
- package/lib/service/CallApi.js +88 -5015
- package/lib/service/IssueReporter.js +264 -366
- package/lib/service/__tests__/IssueReporter.test.js +97 -500
- package/lib/service/getApiClient.js +70 -4990
- package/lib/simple/Auth.js +271 -14777
- package/lib/simple/Configuration.js +23 -14805
- package/lib/simple/Directory.js +18 -4966
- package/lib/simple/Phone.js +345 -14746
- package/lib/simple/Websocket.js +98 -1117
- package/lib/simple/index.js +151 -14800
- package/lib/simple/room/LocalParticipant.js +7 -14808
- package/lib/simple/room/Participant.js +269 -14778
- package/lib/simple/room/RemoteParticipant.js +11 -14806
- package/lib/simple/room/Room.js +655 -14761
- package/lib/simple/room/SipRoom.js +136 -14805
- package/lib/simple/room/Stream.js +43 -14802
- package/lib/simple/room/__tests__/Participant.test.js +79 -14879
- package/lib/simple/room/__tests__/RemoteParticipant.test.js +14 -14814
- package/lib/simple/utils.js +22 -14808
- package/lib/types/WebSocketMessage.js +2 -4
- package/lib/types/__tests__/api-client.test.d.ts +2 -0
- package/lib/types/__tests__/api-client.test.d.ts.map +1 -0
- package/lib/types/__tests__/web-rtc-client.test.d.ts +2 -0
- package/lib/types/__tests__/web-rtc-client.test.d.ts.map +1 -0
- package/lib/types/api/agentd.d.ts +17 -0
- package/lib/types/api/agentd.d.ts.map +1 -0
- package/lib/types/api/amid.d.ts +8 -0
- package/lib/types/api/amid.d.ts.map +1 -0
- package/lib/types/api/application.d.ts +34 -0
- package/lib/types/api/application.d.ts.map +1 -0
- package/lib/types/api/auth.d.ts +64 -0
- package/lib/types/api/auth.d.ts.map +1 -0
- package/lib/types/api/call-logd.d.ts +12 -0
- package/lib/types/api/call-logd.d.ts.map +1 -0
- package/lib/types/api/calld.d.ts +51 -0
- package/lib/types/api/calld.d.ts.map +1 -0
- package/lib/types/api/chatd.d.ts +42 -0
- package/lib/types/api/chatd.d.ts.map +1 -0
- package/lib/types/api/confd.d.ts +39 -0
- package/lib/types/api/confd.d.ts.map +1 -0
- package/lib/types/api/ctid-ng.d.ts +36 -0
- package/lib/types/api/ctid-ng.d.ts.map +1 -0
- package/lib/types/api/dird.d.ts +38 -0
- package/lib/types/api/dird.d.ts.map +1 -0
- package/lib/types/api/webhookd.d.ts +24 -0
- package/lib/types/api/webhookd.d.ts.map +1 -0
- package/lib/types/api-client.d.ts +63 -0
- package/lib/types/api-client.d.ts.map +1 -0
- package/lib/types/checker/Checker.d.ts +13 -0
- package/lib/types/checker/Checker.d.ts.map +1 -0
- package/lib/types/checker/checks/aor.d.ts +6 -0
- package/lib/types/checker/checks/aor.d.ts.map +1 -0
- package/lib/types/checker/checks/api.d.ts +6 -0
- package/lib/types/checker/checks/api.d.ts.map +1 -0
- package/lib/types/checker/checks/ice-ipv4.d.ts +6 -0
- package/lib/types/checker/checks/ice-ipv4.d.ts.map +1 -0
- package/lib/types/checker/checks/index.d.ts +9 -0
- package/lib/types/checker/checks/index.d.ts.map +1 -0
- package/lib/types/checker/checks/symmetric-nat.d.ts +6 -0
- package/lib/types/checker/checks/symmetric-nat.d.ts.map +1 -0
- package/lib/types/checker/checks/wazo-websocket.d.ts +6 -0
- package/lib/types/checker/checks/wazo-websocket.d.ts.map +1 -0
- package/lib/types/checker/checks/webrtc-transport.d.ts +7 -0
- package/lib/types/checker/checks/webrtc-transport.d.ts.map +1 -0
- package/lib/types/checker/checks/webrtc.d.ts +6 -0
- package/lib/types/checker/checks/webrtc.d.ts.map +1 -0
- package/lib/types/domain/AdHocAPIConference.d.ts +54 -0
- package/lib/types/domain/AdHocAPIConference.d.ts.map +1 -0
- package/lib/types/domain/Agent.d.ts +31 -0
- package/lib/types/domain/Agent.d.ts.map +1 -0
- package/lib/types/domain/BadResponse.d.ts +11 -0
- package/lib/types/domain/BadResponse.d.ts.map +1 -0
- package/lib/types/domain/Call.d.ts +79 -0
- package/lib/types/domain/Call.d.ts.map +1 -0
- package/lib/types/domain/CallLog.d.ts +91 -0
- package/lib/types/domain/CallLog.d.ts.map +1 -0
- package/lib/types/domain/CallSession.d.ts +120 -0
- package/lib/types/domain/CallSession.d.ts.map +1 -0
- package/lib/types/domain/ChatMessage.d.ts +41 -0
- package/lib/types/domain/ChatMessage.d.ts.map +1 -0
- package/lib/types/domain/ChatRoom.d.ts +22 -0
- package/lib/types/domain/ChatRoom.d.ts.map +1 -0
- package/lib/types/domain/Contact.d.ts +316 -0
- package/lib/types/domain/Contact.d.ts.map +1 -0
- package/lib/types/domain/Country.d.ts +20 -0
- package/lib/types/domain/Country.d.ts.map +1 -0
- package/lib/types/domain/Device/DebugDevice.d.ts +14 -0
- package/lib/types/domain/Device/DebugDevice.d.ts.map +1 -0
- package/lib/types/domain/Device/Device.d.ts +13 -0
- package/lib/types/domain/Device/Device.d.ts.map +1 -0
- package/lib/types/domain/DirectorySource.d.ts +13 -0
- package/lib/types/domain/DirectorySource.d.ts.map +1 -0
- package/lib/types/domain/ExternalApp.d.ts +22 -0
- package/lib/types/domain/ExternalApp.d.ts.map +1 -0
- package/lib/types/domain/Features.d.ts +24 -0
- package/lib/types/domain/Features.d.ts.map +1 -0
- package/lib/types/domain/ForwardOption.d.ts +27 -0
- package/lib/types/domain/ForwardOption.d.ts.map +1 -0
- package/lib/types/domain/IndirectTransfer.d.ts +31 -0
- package/lib/types/domain/IndirectTransfer.d.ts.map +1 -0
- package/lib/types/domain/Line.d.ts +46 -0
- package/lib/types/domain/Line.d.ts.map +1 -0
- package/lib/types/domain/Meeting.d.ts +45 -0
- package/lib/types/domain/Meeting.d.ts.map +1 -0
- package/lib/types/domain/MeetingAuthorization.d.ts +26 -0
- package/lib/types/domain/MeetingAuthorization.d.ts.map +1 -0
- package/lib/types/domain/MeetingStatus.d.ts +10 -0
- package/lib/types/domain/MeetingStatus.d.ts.map +1 -0
- package/lib/types/domain/NotificationOptions.d.ts +22 -0
- package/lib/types/domain/NotificationOptions.d.ts.map +1 -0
- package/lib/types/domain/Phone/CTIPhone.d.ts +76 -0
- package/lib/types/domain/Phone/CTIPhone.d.ts.map +1 -0
- package/lib/types/domain/Phone/Phone.d.ts +71 -0
- package/lib/types/domain/Phone/Phone.d.ts.map +1 -0
- package/lib/types/domain/Phone/WebRTCPhone.d.ts +179 -0
- package/lib/types/domain/Phone/WebRTCPhone.d.ts.map +1 -0
- package/lib/types/domain/Profile.d.ts +151 -0
- package/lib/types/domain/Profile.d.ts.map +1 -0
- package/lib/types/domain/Recording.d.ts +26 -0
- package/lib/types/domain/Recording.d.ts.map +1 -0
- package/lib/types/domain/Relocation.d.ts +23 -0
- package/lib/types/domain/Relocation.d.ts.map +1 -0
- package/lib/types/domain/Room.d.ts +35 -0
- package/lib/types/domain/Room.d.ts.map +1 -0
- package/lib/types/domain/SFUNotAvailableError.d.ts +4 -0
- package/lib/types/domain/SFUNotAvailableError.d.ts.map +1 -0
- package/lib/types/domain/ServerError.d.ts +6 -0
- package/lib/types/domain/ServerError.d.ts.map +1 -0
- package/lib/types/domain/Session.d.ts +90 -0
- package/lib/types/domain/Session.d.ts.map +1 -0
- package/lib/types/domain/SipLine.d.ts +54 -0
- package/lib/types/domain/SipLine.d.ts.map +1 -0
- package/lib/types/domain/Subscription.d.ts +43 -0
- package/lib/types/domain/Subscription.d.ts.map +1 -0
- package/lib/types/domain/SwitchboardCall.d.ts +62 -0
- package/lib/types/domain/SwitchboardCall.d.ts.map +1 -0
- package/lib/types/domain/Voicemail.d.ts +50 -0
- package/lib/types/domain/Voicemail.d.ts.map +1 -0
- package/lib/types/domain/__tests__/Agent.test.d.ts +2 -0
- package/lib/types/domain/__tests__/Agent.test.d.ts.map +1 -0
- package/lib/types/domain/__tests__/Call.test.d.ts +2 -0
- package/lib/types/domain/__tests__/Call.test.d.ts.map +1 -0
- package/lib/types/domain/__tests__/CallLog.test.d.ts +2 -0
- package/lib/types/domain/__tests__/CallLog.test.d.ts.map +1 -0
- package/lib/types/domain/__tests__/CallSession.test.d.ts +2 -0
- package/lib/types/domain/__tests__/CallSession.test.d.ts.map +1 -0
- package/lib/types/domain/__tests__/Contact.test.d.ts +2 -0
- package/lib/types/domain/__tests__/Contact.test.d.ts.map +1 -0
- package/lib/types/domain/__tests__/IndirectTransfer.test.d.ts +2 -0
- package/lib/types/domain/__tests__/IndirectTransfer.test.d.ts.map +1 -0
- package/lib/types/domain/__tests__/Line.test.d.ts +2 -0
- package/lib/types/domain/__tests__/Line.test.d.ts.map +1 -0
- package/lib/types/domain/__tests__/Meeting.test.d.ts +2 -0
- package/lib/types/domain/__tests__/Meeting.test.d.ts.map +1 -0
- package/lib/types/domain/__tests__/MeetingAuthorization.test.d.ts +2 -0
- package/lib/types/domain/__tests__/MeetingAuthorization.test.d.ts.map +1 -0
- package/lib/types/domain/__tests__/Profile.test.d.ts +2 -0
- package/lib/types/domain/__tests__/Profile.test.d.ts.map +1 -0
- package/lib/types/domain/__tests__/Room.test.d.ts +2 -0
- package/lib/types/domain/__tests__/Room.test.d.ts.map +1 -0
- package/lib/types/domain/__tests__/Session.test.d.ts +2 -0
- package/lib/types/domain/__tests__/Session.test.d.ts.map +1 -0
- package/lib/types/domain/__tests__/SipLine.test.d.ts +2 -0
- package/lib/types/domain/__tests__/SipLine.test.d.ts.map +1 -0
- package/lib/types/domain/__tests__/Voicemail.test.d.ts +2 -0
- package/lib/types/domain/__tests__/Voicemail.test.d.ts.map +1 -0
- package/lib/types/domain/types.d.ts +217 -0
- package/lib/types/domain/types.d.ts.map +1 -0
- package/lib/types/index.d.ts +304 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/lib/WazoSessionDescriptionHandler.d.ts +30 -0
- package/lib/types/lib/WazoSessionDescriptionHandler.d.ts.map +1 -0
- package/lib/types/pubkey.d.ts +3 -0
- package/lib/types/pubkey.d.ts.map +1 -0
- package/lib/types/service/CallApi.d.ts +28 -0
- package/lib/types/service/CallApi.d.ts.map +1 -0
- package/lib/types/service/IssueReporter.d.ts +40 -0
- package/lib/types/service/IssueReporter.d.ts.map +1 -0
- package/lib/types/service/__tests__/IssueReporter.test.d.ts +2 -0
- package/lib/types/service/__tests__/IssueReporter.test.d.ts.map +1 -0
- package/lib/types/service/getApiClient.d.ts +16 -0
- package/lib/types/service/getApiClient.d.ts.map +1 -0
- package/lib/types/simple/Auth.d.ts +51 -0
- package/lib/types/simple/Auth.d.ts.map +1 -0
- package/lib/types/simple/Configuration.d.ts +3 -0
- package/lib/types/simple/Configuration.d.ts.map +1 -0
- package/lib/types/simple/Directory.d.ts +3 -0
- package/lib/types/simple/Directory.d.ts.map +1 -0
- package/lib/types/simple/Phone.d.ts +115 -0
- package/lib/types/simple/Phone.d.ts.map +1 -0
- package/lib/types/simple/Websocket.d.ts +19 -0
- package/lib/types/simple/Websocket.d.ts.map +1 -0
- package/lib/types/simple/index.d.ts +147 -0
- package/lib/types/simple/index.d.ts.map +1 -0
- package/lib/types/simple/room/LocalParticipant.d.ts +5 -0
- package/lib/types/simple/room/LocalParticipant.d.ts.map +1 -0
- package/lib/types/simple/room/Participant.d.ts +76 -0
- package/lib/types/simple/room/Participant.d.ts.map +1 -0
- package/lib/types/simple/room/RemoteParticipant.d.ts +7 -0
- package/lib/types/simple/room/RemoteParticipant.d.ts.map +1 -0
- package/lib/types/simple/room/Room.d.ts +116 -0
- package/lib/types/simple/room/Room.d.ts.map +1 -0
- package/lib/types/simple/room/SipRoom.d.ts +14 -0
- package/lib/types/simple/room/SipRoom.d.ts.map +1 -0
- package/lib/types/simple/room/Stream.d.ts +13 -0
- package/lib/types/simple/room/Stream.d.ts.map +1 -0
- package/lib/types/simple/room/__tests__/Participant.test.d.ts +2 -0
- package/lib/types/simple/room/__tests__/Participant.test.d.ts.map +1 -0
- package/lib/types/simple/room/__tests__/RemoteParticipant.test.d.ts +2 -0
- package/lib/types/simple/room/__tests__/RemoteParticipant.test.d.ts.map +1 -0
- package/lib/types/simple/utils.d.ts +3 -0
- package/lib/types/simple/utils.d.ts.map +1 -0
- package/lib/types/types/WebSocketMessage.d.ts +285 -0
- package/lib/types/types/WebSocketMessage.d.ts.map +1 -0
- package/lib/types/utils/Emitter.d.ts +18 -0
- package/lib/types/utils/Emitter.d.ts.map +1 -0
- package/lib/types/utils/Heartbeat.d.ts +21 -0
- package/lib/types/utils/Heartbeat.d.ts.map +1 -0
- package/lib/types/utils/PhoneNumberUtil.d.ts +8 -0
- package/lib/types/utils/PhoneNumberUtil.d.ts.map +1 -0
- package/lib/types/utils/__tests__/Heartbeat.test.d.ts +2 -0
- package/lib/types/utils/__tests__/Heartbeat.test.d.ts.map +1 -0
- package/lib/types/utils/__tests__/PhoneNumberUtil.test.d.ts +2 -0
- package/lib/types/utils/__tests__/PhoneNumberUtil.test.d.ts.map +1 -0
- package/lib/types/utils/__tests__/api-requester.test.d.ts +2 -0
- package/lib/types/utils/__tests__/api-requester.test.d.ts.map +1 -0
- package/lib/types/utils/__tests__/array.test.d.ts +2 -0
- package/lib/types/utils/__tests__/array.test.d.ts.map +1 -0
- package/lib/types/utils/__tests__/compare-version.test.d.ts +2 -0
- package/lib/types/utils/__tests__/compare-version.test.d.ts.map +1 -0
- package/lib/types/utils/__tests__/object.test.d.ts +2 -0
- package/lib/types/utils/__tests__/object.test.d.ts.map +1 -0
- package/lib/types/utils/__tests__/sdp.test.d.ts +2 -0
- package/lib/types/utils/__tests__/sdp.test.d.ts.map +1 -0
- package/lib/types/utils/__tests__/string.test.d.ts +2 -0
- package/lib/types/utils/__tests__/string.test.d.ts.map +1 -0
- package/lib/types/utils/api-requester.d.ts +45 -0
- package/lib/types/utils/api-requester.d.ts.map +1 -0
- package/lib/types/utils/array.d.ts +2 -0
- package/lib/types/utils/array.d.ts.map +1 -0
- package/lib/types/utils/compare-version.d.ts +3 -0
- package/lib/types/utils/compare-version.d.ts.map +1 -0
- package/lib/types/utils/isMobile.d.ts +3 -0
- package/lib/types/utils/isMobile.d.ts.map +1 -0
- package/lib/types/utils/new-from.d.ts +3 -0
- package/lib/types/utils/new-from.d.ts.map +1 -0
- package/lib/types/utils/object.d.ts +2 -0
- package/lib/types/utils/object.d.ts.map +1 -0
- package/lib/types/utils/once.d.ts +2 -0
- package/lib/types/utils/once.d.ts.map +1 -0
- package/lib/types/utils/sdp.d.ts +13 -0
- package/lib/types/utils/sdp.d.ts.map +1 -0
- package/lib/types/utils/string.d.ts +2 -0
- package/lib/types/utils/string.d.ts.map +1 -0
- package/lib/types/utils/update-from.d.ts +3 -0
- package/lib/types/utils/update-from.d.ts.map +1 -0
- package/lib/types/utils/webrtc.d.ts +15 -0
- package/lib/types/utils/webrtc.d.ts.map +1 -0
- package/lib/types/web-rtc-client.d.ts +211 -0
- package/lib/types/web-rtc-client.d.ts.map +1 -0
- package/lib/types/websocket-client.d.ts +134 -0
- package/lib/types/websocket-client.d.ts.map +1 -0
- package/lib/utils/Emitter.js +22 -33
- package/lib/utils/Heartbeat.js +54 -86
- package/lib/utils/PhoneNumberUtil.js +60 -77
- package/lib/utils/__tests__/Heartbeat.test.js +73 -170
- package/lib/utils/__tests__/PhoneNumberUtil.test.js +57 -131
- package/lib/utils/__tests__/api-requester.test.js +139 -784
- package/lib/utils/__tests__/array.test.js +18 -21
- package/lib/utils/__tests__/compare-version.test.js +12 -27
- package/lib/utils/__tests__/object.test.js +75 -56
- package/lib/utils/__tests__/sdp.test.js +99 -220
- package/lib/utils/__tests__/string.test.js +23 -29
- package/lib/utils/api-requester.js +191 -685
- package/lib/utils/array.js +10 -14
- package/lib/utils/compare-version.js +15 -18
- package/lib/utils/isMobile.js +3 -5
- package/lib/utils/new-from.js +9 -14
- package/lib/utils/object.js +12 -26
- package/lib/utils/once.js +15 -15
- package/lib/utils/sdp.js +97 -150
- package/lib/utils/string.js +8 -12
- package/lib/utils/update-from.js +11 -18
- package/lib/utils/webrtc.js +38 -39
- package/lib/web-rtc-client.js +1999 -7696
- package/lib/websocket-client.js +357 -1021
- package/package.json +40 -34
- package/src/__tests__/{api-client.test.js → api-client.test.ts} +71 -29
- package/src/__tests__/{web-rtc-client.test.js → web-rtc-client.test.ts} +95 -35
- package/src/api/agentd.ts +37 -0
- package/src/api/amid.ts +16 -0
- package/src/api/application.ts +96 -0
- package/src/api/auth.ts +259 -0
- package/src/api/call-logd.ts +38 -0
- package/src/api/calld.ts +183 -0
- package/src/api/chatd.ts +83 -0
- package/src/api/confd.ts +110 -0
- package/src/api/ctid-ng.ts +152 -0
- package/src/api/dird.ts +146 -0
- package/src/api/webhookd.ts +30 -0
- package/src/{api-client.js → api-client.ts} +99 -65
- package/src/checker/{Checker.js → Checker.ts} +27 -20
- package/src/checker/checks/{aor.js → aor.ts} +10 -6
- package/src/checker/checks/{api.js → api.ts} +18 -17
- package/src/checker/checks/{ice-ipv4.js → ice-ipv4.ts} +23 -26
- package/src/checker/checks/{index.js → index.ts} +1 -9
- package/src/checker/checks/{symmetric-nat.js → symmetric-nat.ts} +14 -15
- package/src/checker/checks/{wazo-websocket.js → wazo-websocket.ts} +7 -5
- package/src/checker/checks/{webrtc-transport.js → webrtc-transport.ts} +3 -2
- package/src/checker/checks/{webrtc.js → webrtc.ts} +3 -4
- package/src/domain/{AdHocAPIConference.js → AdHocAPIConference.ts} +38 -54
- package/src/domain/{Agent.js → Agent.ts} +11 -7
- package/src/domain/BadResponse.ts +29 -0
- package/src/domain/{Call.js → Call.ts} +62 -46
- package/src/domain/{CallLog.js → CallLog.ts} +61 -63
- package/src/domain/{CallSession.js → CallSession.ts} +55 -52
- package/src/domain/{ChatMessage.js → ChatMessage.ts} +32 -21
- package/src/domain/{ChatRoom.js → ChatRoom.ts} +15 -11
- package/src/domain/{Contact.js → Contact.ts} +373 -261
- package/src/domain/{Country.js → Country.ts} +0 -0
- package/src/domain/Device/{DebugDevice.js → DebugDevice.ts} +3 -5
- package/src/domain/Device/{Device.js → Device.ts} +0 -11
- package/src/domain/DirectorySource.ts +13 -0
- package/src/domain/{ExternalApp.js → ExternalApp.ts} +14 -13
- package/src/domain/{Features.js → Features.ts} +43 -17
- package/src/domain/{ForwardOption.js → ForwardOption.ts} +16 -16
- package/src/domain/{IndirectTransfer.js → IndirectTransfer.ts} +21 -19
- package/src/domain/{Line.js → Line.ts} +39 -26
- package/src/domain/{Meeting.js → Meeting.ts} +36 -29
- package/src/domain/{MeetingAuthorization.js → MeetingAuthorization.ts} +13 -12
- package/src/domain/{MeetingStatus.js → MeetingStatus.ts} +2 -6
- package/src/domain/{NotificationOptions.js → NotificationOptions.ts} +14 -13
- package/src/domain/Phone/{CTIPhone.js → CTIPhone.ts} +90 -60
- package/src/domain/Phone/{Phone.js → Phone.ts} +27 -72
- package/src/domain/Phone/{WebRTCPhone.js → WebRTCPhone.ts} +434 -413
- package/src/domain/{Profile.js → Profile.ts} +117 -100
- package/src/domain/{Recording.js → Recording.ts} +25 -16
- package/src/domain/{Relocation.js → Relocation.ts} +15 -14
- package/src/domain/{Room.js → Room.ts} +58 -27
- package/src/domain/{SFUNotAvailableError.js → SFUNotAvailableError.ts} +2 -2
- package/src/domain/ServerError.ts +12 -0
- package/src/domain/{Session.js → Session.ts} +89 -67
- package/src/domain/{SipLine.js → SipLine.ts} +52 -45
- package/src/domain/{Subscription.js → Subscription.ts} +22 -13
- package/src/domain/{SwitchboardCall.js → SwitchboardCall.ts} +48 -43
- package/src/domain/{Voicemail.js → Voicemail.ts} +38 -34
- package/src/domain/__tests__/{Agent.test.js → Agent.test.ts} +11 -19
- package/src/domain/__tests__/{Call.test.js → Call.test.ts} +12 -9
- package/src/domain/__tests__/CallLog.test.ts +65 -0
- package/src/domain/__tests__/{CallSession.test.js → CallSession.test.ts} +15 -19
- package/src/domain/__tests__/Contact.test.ts +238 -0
- package/src/domain/__tests__/{IndirectTransfer.test.js → IndirectTransfer.test.ts} +38 -31
- package/src/domain/__tests__/Line.test.ts +53 -0
- package/src/domain/__tests__/{Meeting.test.js → Meeting.test.ts} +12 -38
- package/src/domain/__tests__/{MeetingAuthorization.test.js → MeetingAuthorization.test.ts} +13 -21
- package/src/domain/__tests__/Profile.test.ts +139 -0
- package/src/domain/__tests__/{Room.test.js → Room.test.ts} +114 -76
- package/src/domain/__tests__/{Session.test.js → Session.test.ts} +137 -162
- package/src/domain/__tests__/{SipLine.test.js → SipLine.test.ts} +7 -3
- package/src/domain/__tests__/{Voicemail.test.js → Voicemail.test.ts} +26 -20
- package/src/domain/types.ts +227 -0
- package/src/global.d.ts +5 -0
- package/src/{index.js → index.ts} +4 -28
- package/src/lib/WazoSessionDescriptionHandler.ts +534 -0
- package/{config.js → src/pubkey.ts} +3 -3
- package/src/service/{CallApi.js → CallApi.ts} +14 -18
- package/src/service/{IssueReporter.js → IssueReporter.ts} +105 -56
- package/src/service/__tests__/{IssueReporter.test.js → IssueReporter.test.ts} +27 -23
- package/src/service/getApiClient.ts +94 -0
- package/src/simple/{Auth.js → Auth.ts} +127 -100
- package/src/simple/{Configuration.js → Configuration.ts} +2 -3
- package/src/simple/{Directory.js → Directory.ts} +2 -3
- package/src/simple/Phone.ts +623 -0
- package/src/simple/Websocket.ts +119 -0
- package/src/simple/{index.js → index.ts} +51 -21
- package/src/simple/room/{LocalParticipant.js → LocalParticipant.ts} +1 -3
- package/src/simple/room/{Participant.js → Participant.ts} +108 -46
- package/src/simple/room/{RemoteParticipant.js → RemoteParticipant.ts} +5 -4
- package/src/simple/room/{Room.js → Room.ts} +266 -183
- package/src/simple/room/{SipRoom.js → SipRoom.ts} +46 -29
- package/src/simple/room/{Stream.js → Stream.ts} +8 -6
- package/src/simple/room/__tests__/{Participant.test.js → Participant.test.ts} +9 -15
- package/src/simple/room/__tests__/{RemoteParticipant.test.js → RemoteParticipant.test.ts} +5 -1
- package/src/simple/utils.ts +12 -0
- package/src/types/WebSocketMessage.ts +335 -0
- package/src/types/global.d.ts +26 -0
- package/src/utils/Emitter.ts +34 -0
- package/src/utils/{Heartbeat.js → Heartbeat.ts} +17 -11
- package/src/utils/{PhoneNumberUtil.js → PhoneNumberUtil.ts} +12 -18
- package/src/utils/__tests__/{Heartbeat.test.js → Heartbeat.test.ts} +0 -15
- package/src/utils/__tests__/{PhoneNumberUtil.test.js → PhoneNumberUtil.test.ts} +6 -4
- package/src/utils/__tests__/{api-requester.test.js → api-requester.test.ts} +75 -24
- package/src/utils/__tests__/{array.test.js → array.test.ts} +10 -2
- package/src/utils/__tests__/{compare-version.test.js → compare-version.test.ts} +0 -0
- package/src/utils/__tests__/object.test.ts +77 -0
- package/src/utils/__tests__/{sdp.test.js → sdp.test.ts} +15 -37
- package/src/utils/__tests__/{string.test.js → string.test.ts} +4 -2
- package/src/utils/{api-requester.js → api-requester.ts} +104 -83
- package/src/utils/{array.js → array.ts} +2 -2
- package/src/utils/{compare-version.js → compare-version.ts} +3 -2
- package/src/utils/{isMobile.js → isMobile.ts} +1 -1
- package/src/utils/{new-from.js → new-from.ts} +3 -6
- package/src/utils/{object.js → object.ts} +3 -6
- package/src/utils/{once.js → once.ts} +5 -5
- package/src/utils/sdp.ts +119 -0
- package/src/utils/{string.js → string.ts} +2 -3
- package/src/utils/update-from.ts +11 -0
- package/src/utils/{webrtc.js → webrtc.ts} +21 -3
- package/src/{web-rtc-client.js → web-rtc-client.ts} +786 -457
- package/src/{websocket-client.js → websocket-client.ts} +146 -144
- package/esm/simple/Softphone.js +0 -394
- package/lib/simple/Softphone.js +0 -396
- package/src/api/agentd.js +0 -74
- package/src/api/amid.js +0 -13
- package/src/api/application.js +0 -137
- package/src/api/auth.js +0 -279
- package/src/api/call-logd.js +0 -20
- package/src/api/calld.js +0 -214
- package/src/api/chatd.js +0 -80
- package/src/api/confd.js +0 -127
- package/src/api/ctid-ng.js +0 -153
- package/src/api/dird.js +0 -159
- package/src/api/webhookd.js +0 -31
- package/src/domain/BadResponse.js +0 -42
- package/src/domain/DirectorySource.js +0 -16
- package/src/domain/ServerError.js +0 -18
- package/src/domain/__tests__/CallLog.test.js +0 -75
- package/src/domain/__tests__/Contact.test.js +0 -170
- package/src/domain/__tests__/Line.test.js +0 -73
- package/src/domain/__tests__/Profile.test.js +0 -104
- package/src/domain/types.js +0 -248
- package/src/lib/WazoSessionDescriptionHandler.js +0 -467
- package/src/service/getApiClient.js +0 -122
- package/src/simple/Phone.js +0 -425
- package/src/simple/Softphone.js +0 -392
- package/src/simple/Websocket.js +0 -86
- package/src/simple/utils.js +0 -17
- package/src/types/WebSocketMessage.js +0 -232
- package/src/utils/Emitter.js +0 -26
- package/src/utils/__tests__/object.test.js +0 -35
- package/src/utils/sdp.js +0 -140
- package/src/utils/update-from.js +0 -15
|
@@ -1,2680 +1,1456 @@
|
|
|
1
|
-
import { Invitation } from 'sip.js/lib/api/invitation';
|
|
2
1
|
import { SessionState } from 'sip.js/lib/api/session-state';
|
|
3
|
-
import
|
|
4
|
-
import '
|
|
5
|
-
import '
|
|
6
|
-
import '
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
this.dialedExtension = dialedExtension || '';
|
|
199
|
-
this.call = call;
|
|
200
|
-
this.sipStatus = sipStatus;
|
|
201
|
-
this.autoAnswer = autoAnswer || false;
|
|
202
|
-
this.ignored = ignored || false;
|
|
203
|
-
this.screensharing = screensharing || false;
|
|
204
|
-
this.recording = recording || false;
|
|
205
|
-
this.recordingPaused = recordingPaused || false;
|
|
206
|
-
this.videoRemotelyDowngraded = videoRemotelyDowngraded;
|
|
207
|
-
this.sipSession = sipSession;
|
|
208
|
-
this.answerTime = answerTime || this.answerTime;
|
|
209
|
-
this.conference = conference;
|
|
210
|
-
|
|
211
|
-
// Useful to compare instead of instanceof with minified code
|
|
212
|
-
this.type = 'CallSession';
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
resume() {
|
|
216
|
-
this.paused = false;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
hold() {
|
|
220
|
-
this.paused = true;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
mute() {
|
|
224
|
-
this.muted = true;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
unmute() {
|
|
228
|
-
this.muted = false;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
muteVideo() {
|
|
232
|
-
this.videoMuted = true;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
unmuteVideo() {
|
|
236
|
-
this.videoMuted = false;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
answer() {
|
|
240
|
-
this.answerTime = new Date();
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
systemAnswer() {
|
|
244
|
-
this.answeredBySystem = true;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
enableCamera() {
|
|
248
|
-
this.cameraEnabled = true;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
disableCamera() {
|
|
252
|
-
this.cameraEnabled = false;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
ignore() {
|
|
256
|
-
this.ignored = true;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
startScreenSharing() {
|
|
260
|
-
this.screensharing = true;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
stopScreenSharing() {
|
|
264
|
-
this.screensharing = false;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
setIsConference(conference ) {
|
|
268
|
-
this.conference = conference;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
isIncoming() {
|
|
272
|
-
return !this.isCaller && !this.answered;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
isOutgoing() {
|
|
276
|
-
return this.isCaller && !this.answered;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
isActive() {
|
|
280
|
-
return this.answered || this.isOutgoing();
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
isAnswered() {
|
|
284
|
-
return this.answered;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
isAnsweredBySystem() {
|
|
288
|
-
return this.answeredBySystem;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
isRinging() {
|
|
292
|
-
return this.ringing;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
isOnHold() {
|
|
296
|
-
return this.paused;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
isMuted() {
|
|
300
|
-
return this.muted;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
isVideoMuted() {
|
|
304
|
-
return this.videoMuted;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
isCameraEnabled() {
|
|
308
|
-
return this.cameraEnabled;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
isIgnored() {
|
|
312
|
-
return this.ignored;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
isScreenSharing() {
|
|
316
|
-
return this.screensharing;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
isRecording() {
|
|
320
|
-
return this.recording;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
recordingIsPaused() {
|
|
324
|
-
return this.recordingPaused;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
hasAnInitialInterceptionNumber() {
|
|
328
|
-
return this.number.startsWith('*8');
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
isAnInterception() {
|
|
332
|
-
return this.dialedExtension.startsWith('*8');
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
isEstablished() {
|
|
336
|
-
return this.sipStatus === SessionState.Established;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
isTerminating() {
|
|
340
|
-
return this.sipStatus === SessionState.Terminating;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
isTerminated() {
|
|
344
|
-
return this.sipStatus === SessionState.Terminated;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
isConference() {
|
|
348
|
-
return this.conference;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
getElapsedTimeInSeconds() {
|
|
352
|
-
if (!this.startTime) {
|
|
353
|
-
return 0;
|
|
354
|
-
}
|
|
355
|
-
return (Date.now() - this.startTime) / 1000;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
getId() {
|
|
359
|
-
return this.sipCallId || this.callId;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
is(callSession ) {
|
|
363
|
-
if (!callSession) {
|
|
364
|
-
return false;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
return this.isId(callSession.sipCallId) || this.isId(callSession.callId);
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
isId(id ) {
|
|
371
|
-
return (
|
|
372
|
-
this.getId() === id || (this.sipCallId && this.sipCallId === id) || (Boolean(this.callId) && this.callId === id)
|
|
373
|
-
);
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
updateFrom(session ) {
|
|
377
|
-
updateFrom(this, session);
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
separateDisplayName() {
|
|
381
|
-
const names = this.displayName.split(' ');
|
|
382
|
-
const firstName = names[0];
|
|
383
|
-
const lastName = names.slice(1).join(' ');
|
|
384
|
-
|
|
385
|
-
return { firstName, lastName };
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
getTalkingToIds() {
|
|
389
|
-
return this.call ? this.call.talkingToIds : [];
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
setVideoRemotelyDowngraded(value ) {
|
|
393
|
-
this.videoRemotelyDowngraded = value;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
isVideoRemotelyDowngraded() {
|
|
397
|
-
return this.videoRemotelyDowngraded;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
static newFrom(callSession ) {
|
|
401
|
-
return newFrom(callSession, CallSession);
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
// Retro-compatibility: `answered` was a boolean before. We can reproduce the behaviour with a getter/setter
|
|
405
|
-
set answered(value ) {
|
|
406
|
-
this.answerTime = value ? this.answerTime || new Date() : null;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
get answered() {
|
|
410
|
-
return !!this.answerTime;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
toJSON() {
|
|
414
|
-
const jsonObj = { ...this };
|
|
415
|
-
// $FlowFixMe
|
|
416
|
-
jsonObj.answered = this.answered;
|
|
417
|
-
|
|
418
|
-
return jsonObj;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
static parseCall(call ) {
|
|
422
|
-
return new CallSession({
|
|
423
|
-
callId: call.id,
|
|
424
|
-
sipCallId: call.sipCallId,
|
|
425
|
-
displayName: call.calleeName || call.calleeNumber,
|
|
426
|
-
number: call.calleeNumber,
|
|
427
|
-
callerNumber: call.callerNumber,
|
|
428
|
-
startTime: +call.startingTime,
|
|
429
|
-
paused: call.isOnHold(),
|
|
430
|
-
isCaller: call.isCaller,
|
|
431
|
-
muted: call.muted,
|
|
432
|
-
videoMuted: false,
|
|
433
|
-
screensharing: false,
|
|
434
|
-
recording: call.isRecording(),
|
|
435
|
-
recordingPaused: false, // @TODO
|
|
436
|
-
ringing: call.isRinging(),
|
|
437
|
-
answered: call.isUp(),
|
|
438
|
-
answeredBySystem: call.isUp() && call.talkingToIds.length === 0,
|
|
439
|
-
cameraEnabled: call.isVideo,
|
|
440
|
-
dialedExtension: call.dialedExtension,
|
|
441
|
-
call,
|
|
442
|
-
conference: false, // @FIXME?
|
|
443
|
-
});
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
/* */
|
|
448
|
-
/* global navigator */
|
|
449
|
-
const isMobile = () => typeof navigator !== 'undefined' && navigator.product === 'ReactNative';
|
|
450
|
-
|
|
451
|
-
/* */
|
|
452
|
-
|
|
453
|
-
IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
|
|
454
|
-
|
|
455
|
-
// Use a function here to be able to mock it in tests
|
|
456
|
-
const realFetch = () => {
|
|
457
|
-
if (typeof document !== 'undefined' && window.fetch) {
|
|
458
|
-
// Browser
|
|
459
|
-
return window.fetch;
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
if (isMobile()) {
|
|
463
|
-
// React native
|
|
464
|
-
return fetch;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
// nodejs
|
|
468
|
-
// this package is disable for react-native in package.json because it requires nodejs modules
|
|
469
|
-
// Used to trick the optimizer to avoid requiring `node-fetch/lib/index` directly
|
|
470
|
-
// It causes to require it on browsers when delivered by a nodejs engine (cf: vitejs).
|
|
471
|
-
try {
|
|
472
|
-
// $FlowFixMe
|
|
473
|
-
return require(Math.random() >= 0 ? 'node-fetch/lib/index' : '');
|
|
474
|
-
} catch (e) {
|
|
475
|
-
return fetch;
|
|
476
|
-
}
|
|
477
|
-
};
|
|
478
|
-
|
|
479
|
-
/* global window */
|
|
480
|
-
|
|
481
|
-
const TRACE = 'trace';
|
|
482
|
-
const DEBUG = 'debug';
|
|
483
|
-
const INFO = 'info';
|
|
484
|
-
const LOG = 'log';
|
|
485
|
-
const WARN = 'warn';
|
|
486
|
-
const ERROR = 'error';
|
|
487
|
-
const CONSOLE_METHODS = [INFO, LOG, WARN, ERROR];
|
|
488
|
-
const LOG_LEVELS = [TRACE, DEBUG, INFO, LOG, WARN, ERROR];
|
|
489
|
-
const CATEGORY_PREFIX = 'logger-category=';
|
|
490
|
-
|
|
491
|
-
const MAX_REMOTE_RETRY = 100;
|
|
492
|
-
|
|
493
|
-
const addLevelsTo = (instance , withMethods = false) => {
|
|
494
|
-
instance.TRACE = TRACE;
|
|
495
|
-
instance.DEBUG = DEBUG;
|
|
496
|
-
instance.INFO = INFO;
|
|
497
|
-
instance.LOG = LOG;
|
|
498
|
-
instance.WARN = WARN;
|
|
499
|
-
instance.ERROR = ERROR;
|
|
500
|
-
|
|
501
|
-
if (withMethods) {
|
|
502
|
-
instance.trace = (...args) => instance.apply(null, [TRACE, ...args]);
|
|
503
|
-
instance.debug = (...args) => instance.apply(null, [DEBUG, ...args]);
|
|
504
|
-
instance.info = (...args) => instance.apply(null, [INFO, ...args]);
|
|
505
|
-
instance.log = (...args) => instance.apply(null, [LOG, ...args]);
|
|
506
|
-
instance.warn = (...args) => instance.apply(null, [WARN, ...args]);
|
|
507
|
-
instance.error = (...args) => instance.apply(null, [ERROR, ...args]);
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
return instance;
|
|
511
|
-
};
|
|
512
|
-
|
|
513
|
-
const safeStringify = (object ) => {
|
|
514
|
-
const result = '{"message": "Not parsable JSON"}';
|
|
515
|
-
try {
|
|
516
|
-
return JSON.stringify(object);
|
|
517
|
-
} catch (e) {
|
|
518
|
-
// Nothing to do
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
return result;
|
|
522
|
-
};
|
|
523
|
-
|
|
524
|
-
class IssueReporter {
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
constructor() {
|
|
542
|
-
addLevelsTo(this);
|
|
543
|
-
|
|
544
|
-
this.oldConsoleMethods = null;
|
|
545
|
-
this.enabled = false;
|
|
546
|
-
this.remoteClientConfiguration = null;
|
|
547
|
-
this.buffer = [];
|
|
548
|
-
this.bufferTimeout = null;
|
|
549
|
-
this._boundProcessBuffer = this._processBuffer.bind(this);
|
|
550
|
-
this._boundParseLoggerBody = this._parseLoggerBody.bind(this);
|
|
551
|
-
this._callback = null;
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
init() {
|
|
555
|
-
this._catchConsole();
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
setCallback(cb ) {
|
|
559
|
-
this._callback = cb;
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
configureRemoteClient(configuration = { tag: 'wazo-sdk', host: null, port: null, level: null, extra: {} }) {
|
|
563
|
-
this.remoteClientConfiguration = configuration;
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
enable() {
|
|
567
|
-
if (!this.oldConsoleMethods) {
|
|
568
|
-
this.init();
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
this.enabled = true;
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
disable() {
|
|
575
|
-
this.enabled = false;
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
loggerFor(category ) {
|
|
579
|
-
const logger = (level , ...args ) => {
|
|
580
|
-
this.log.apply(this, [level, this._makeCategory(category), ...args]);
|
|
581
|
-
};
|
|
582
|
-
|
|
583
|
-
return addLevelsTo(logger, true);
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
removeSlashes(str ) {
|
|
587
|
-
return str.replace(/"/g, "'").replace(/\\/g, '');
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
log(level , ...args ) {
|
|
591
|
-
if (!this.enabled) {
|
|
592
|
-
return;
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
// Handle category label
|
|
596
|
-
let category = null;
|
|
597
|
-
let skipSendToRemote = false;
|
|
598
|
-
let extra = {};
|
|
599
|
-
if (args[0].indexOf(CATEGORY_PREFIX) === 0) {
|
|
600
|
-
category = args[0].split('=')[1];
|
|
601
|
-
// eslint-disable-next-line no-param-reassign
|
|
602
|
-
args.splice(0, 1);
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
// Handle extra data as object for the last argument
|
|
606
|
-
const lastArg = args[args.length - 1];
|
|
607
|
-
if (lastArg && ((typeof lastArg === 'object' && Object.keys(lastArg).length) || lastArg instanceof Error)) {
|
|
608
|
-
if (lastArg instanceof Error) {
|
|
609
|
-
extra = {
|
|
610
|
-
errorMessage: lastArg.message,
|
|
611
|
-
errorStack: lastArg.stack,
|
|
612
|
-
errorType: lastArg.constructor.name,
|
|
613
|
-
skipSendToRemote: lastArg.skipSendToRemote,
|
|
2
|
+
import { Invitation } from 'sip.js/lib/api';
|
|
3
|
+
import CallSession from '../CallSession';
|
|
4
|
+
import Emitter from '../../utils/Emitter';
|
|
5
|
+
import IssueReporter from '../../service/IssueReporter';
|
|
6
|
+
export const ON_USER_AGENT = 'onUserAgent';
|
|
7
|
+
export const ON_REGISTERED = 'onRegistered';
|
|
8
|
+
export const ON_UNREGISTERED = 'onUnRegistered';
|
|
9
|
+
export const ON_PROGRESS = 'onProgress';
|
|
10
|
+
export const ON_CALL_ACCEPTED = 'onCallAccepted';
|
|
11
|
+
export const ON_CALL_ANSWERED = 'onCallAnswered';
|
|
12
|
+
export const ON_CALL_INCOMING = 'onCallIncoming';
|
|
13
|
+
export const ON_CALL_OUTGOING = 'onCallOutgoing';
|
|
14
|
+
export const ON_CALL_MUTED = 'onCallMuted';
|
|
15
|
+
export const ON_CALL_UNMUTED = 'onCallUnmuted';
|
|
16
|
+
export const ON_CALL_RESUMED = 'onCallResumed';
|
|
17
|
+
export const ON_CALL_HELD = 'onCallHeld';
|
|
18
|
+
export const ON_CALL_UNHELD = 'onCallUnHeld';
|
|
19
|
+
export const ON_CAMERA_DISABLED = 'onCameraDisabled';
|
|
20
|
+
export const ON_CAMERA_RESUMED = 'onCameraResumed';
|
|
21
|
+
export const ON_CALL_CANCELED = 'onCallCanceled';
|
|
22
|
+
export const ON_CALL_FAILED = 'onCallFailed';
|
|
23
|
+
export const ON_CALL_REJECTED = 'onCallRejected';
|
|
24
|
+
export const ON_CALL_ENDED = 'onCallEnded';
|
|
25
|
+
export const ON_CALL_ENDING = 'onCallEnding';
|
|
26
|
+
export const ON_MESSAGE = 'onMessage';
|
|
27
|
+
export const ON_REINVITE = 'reinvite';
|
|
28
|
+
export const ON_TRACK = 'onTrack';
|
|
29
|
+
export const ON_AUDIO_STREAM = 'onAudioStream';
|
|
30
|
+
export const ON_VIDEO_STREAM = 'onVideoStream';
|
|
31
|
+
export const ON_REMOVE_STREAM = 'onRemoveStream';
|
|
32
|
+
export const ON_SHARE_SCREEN_STARTED = 'onScreenShareStarted';
|
|
33
|
+
export const ON_SHARE_SCREEN_ENDING = 'onScreenShareEnding';
|
|
34
|
+
export const ON_SHARE_SCREEN_ENDED = 'onScreenShareEnded';
|
|
35
|
+
export const ON_TERMINATE_SOUND = 'terminateSound';
|
|
36
|
+
export const ON_PLAY_RING_SOUND = 'playRingingSound';
|
|
37
|
+
export const ON_PLAY_INBOUND_CALL_SIGNAL_SOUND = 'playInboundCallSignalSound';
|
|
38
|
+
export const ON_PLAY_HANGUP_SOUND = 'playHangupSound';
|
|
39
|
+
export const ON_PLAY_PROGRESS_SOUND = 'playProgressSound';
|
|
40
|
+
export const ON_VIDEO_INPUT_CHANGE = 'videoInputChange';
|
|
41
|
+
export const ON_CALL_ERROR = 'onCallError';
|
|
42
|
+
export const ON_MESSAGE_TRACK_UPDATED = 'onTrackUpdated';
|
|
43
|
+
export const ON_NETWORK_STATS = 'onNetworkStats';
|
|
44
|
+
export const ON_CHAT = 'phone/ON_CHAT';
|
|
45
|
+
export const ON_SIGNAL = 'phone/ON_SIGNAL';
|
|
46
|
+
export const ON_DISCONNECTED = 'onDisconnected';
|
|
47
|
+
export const ON_EARLY_MEDIA = 'onEarlyMedia';
|
|
48
|
+
export const MESSAGE_TYPE_CHAT = 'message/TYPE_CHAT';
|
|
49
|
+
export const MESSAGE_TYPE_SIGNAL = 'message/TYPE_SIGNAL';
|
|
50
|
+
export const events = [ON_USER_AGENT, ON_REGISTERED, ON_UNREGISTERED, ON_PROGRESS, ON_CALL_ACCEPTED, ON_CALL_ANSWERED, ON_CALL_INCOMING, ON_CALL_OUTGOING, ON_CALL_MUTED, ON_CALL_UNMUTED, ON_CALL_RESUMED, ON_CALL_HELD, ON_CALL_UNHELD, ON_CAMERA_DISABLED, ON_CALL_FAILED, ON_CALL_ENDED, ON_CALL_REJECTED, ON_MESSAGE, ON_REINVITE, ON_TRACK, ON_AUDIO_STREAM, ON_VIDEO_STREAM, ON_REMOVE_STREAM, ON_SHARE_SCREEN_ENDED, ON_TERMINATE_SOUND, ON_PLAY_RING_SOUND, ON_PLAY_INBOUND_CALL_SIGNAL_SOUND, ON_PLAY_HANGUP_SOUND, ON_PLAY_PROGRESS_SOUND, ON_VIDEO_INPUT_CHANGE, ON_SHARE_SCREEN_STARTED, ON_CALL_ERROR, ON_CHAT, ON_SIGNAL, ON_NETWORK_STATS, ON_DISCONNECTED, ON_EARLY_MEDIA];
|
|
51
|
+
const logger = IssueReporter.loggerFor('webrtc-phone');
|
|
52
|
+
export default class WebRTCPhone extends Emitter {
|
|
53
|
+
client;
|
|
54
|
+
allowVideo;
|
|
55
|
+
callSessions;
|
|
56
|
+
incomingSessions;
|
|
57
|
+
currentSipSession;
|
|
58
|
+
currentCallSession;
|
|
59
|
+
audioOutputDeviceId;
|
|
60
|
+
audioRingDeviceId;
|
|
61
|
+
audioOutputVolume;
|
|
62
|
+
audioRingVolume;
|
|
63
|
+
ringingEnabled;
|
|
64
|
+
acceptedSessions;
|
|
65
|
+
rejectedSessions;
|
|
66
|
+
ignoredSessions;
|
|
67
|
+
currentScreenShare;
|
|
68
|
+
lastScreenShare;
|
|
69
|
+
shouldSendReinvite;
|
|
70
|
+
constructor(client, audioOutputDeviceId, allowVideo = false, audioRingDeviceId) {
|
|
71
|
+
super();
|
|
72
|
+
this.client = client;
|
|
73
|
+
this.allowVideo = allowVideo;
|
|
74
|
+
this.callSessions = {};
|
|
75
|
+
this.audioOutputDeviceId = audioOutputDeviceId;
|
|
76
|
+
this.audioRingDeviceId = audioRingDeviceId || audioOutputDeviceId;
|
|
77
|
+
this.audioOutputVolume = 1;
|
|
78
|
+
this.audioRingVolume = 1;
|
|
79
|
+
this.incomingSessions = [];
|
|
80
|
+
this.ringingEnabled = true;
|
|
81
|
+
this.shouldSendReinvite = false;
|
|
82
|
+
this.bindClientEvents();
|
|
83
|
+
this.acceptedSessions = {};
|
|
84
|
+
this.rejectedSessions = {};
|
|
85
|
+
this.ignoredSessions = {};
|
|
86
|
+
}
|
|
87
|
+
register() {
|
|
88
|
+
if (!this.client) {
|
|
89
|
+
return Promise.resolve();
|
|
90
|
+
}
|
|
91
|
+
return this.client.register().then(() => {
|
|
92
|
+
return this.bindClientEvents();
|
|
93
|
+
}).catch(error => {
|
|
94
|
+
// Avoid exception on `t.server.scheme` in sip transport when losing the webrtc socket connection
|
|
95
|
+
console.error('register error', error, error.message, error.stack);
|
|
96
|
+
logger.error('WebRTC register error', {
|
|
97
|
+
message: error.message,
|
|
98
|
+
stack: error.stack,
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
unregister() {
|
|
103
|
+
if (!this.client || !this.client.isRegistered()) {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
return this.client.unregister();
|
|
107
|
+
}
|
|
108
|
+
stop() {
|
|
109
|
+
if (!this.client) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
logger.info('WebRTC phone stop');
|
|
113
|
+
this.client.stop();
|
|
114
|
+
}
|
|
115
|
+
removeIncomingSessions(id) {
|
|
116
|
+
this.incomingSessions = this.incomingSessions.filter(sessionId => sessionId !== id);
|
|
117
|
+
}
|
|
118
|
+
isWebRTC() {
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
async sendReinvite(callSession, constraints = null, conference = false, audioOnly = false, iceRestart = false) {
|
|
122
|
+
const sipSession = this.findSipSession(callSession);
|
|
123
|
+
logger.info('WebRTC phone - send reinvite', {
|
|
124
|
+
sessionId: sipSession ? sipSession.id : null,
|
|
125
|
+
constraints,
|
|
126
|
+
audioOnly,
|
|
127
|
+
conference,
|
|
128
|
+
iceRestart,
|
|
129
|
+
});
|
|
130
|
+
if (!sipSession) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const shouldScreenShare = constraints?.screen;
|
|
134
|
+
const isUpgrade = shouldScreenShare || constraints?.video;
|
|
135
|
+
// Downgrade
|
|
136
|
+
if (constraints && !isUpgrade) {
|
|
137
|
+
// No reinvite needed
|
|
138
|
+
this._downgradeToAudio(callSession);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (isUpgrade) {
|
|
142
|
+
const shouldReinvite = await this._upgradeToVideo(callSession, constraints, conference);
|
|
143
|
+
if (!shouldReinvite) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return this.client.reinvite(sipSession, constraints, conference, audioOnly, iceRestart);
|
|
148
|
+
}
|
|
149
|
+
getUserAgent() {
|
|
150
|
+
return this.client?.config?.userAgentString || 'webrtc-phone';
|
|
151
|
+
}
|
|
152
|
+
startHeartbeat() {
|
|
153
|
+
logger.info('WebRTC phone - start heartbeat', {
|
|
154
|
+
client: !!this.client,
|
|
155
|
+
hasHeartbeat: this.client.hasHeartbeat(),
|
|
156
|
+
});
|
|
157
|
+
if (!this.client || this.client.hasHeartbeat()) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
this.client.startHeartbeat();
|
|
161
|
+
}
|
|
162
|
+
stopHeartbeat() {
|
|
163
|
+
logger.info('WebRTC phone - stopHeartbeat', {
|
|
164
|
+
client: !!this.client,
|
|
165
|
+
});
|
|
166
|
+
if (!this.client) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
this.client.stopHeartbeat();
|
|
170
|
+
}
|
|
171
|
+
setOnHeartbeatTimeout(cb) {
|
|
172
|
+
this.client.setOnHeartbeatTimeout(cb);
|
|
173
|
+
}
|
|
174
|
+
setOnHeartbeatCallback(cb) {
|
|
175
|
+
this.client.setOnHeartbeatCallback(cb);
|
|
176
|
+
}
|
|
177
|
+
reconnect() {
|
|
178
|
+
logger.info('WebRTC phone - reconnect', {
|
|
179
|
+
client: !!this.client,
|
|
180
|
+
});
|
|
181
|
+
if (!this.client) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
this.client.attemptReconnection();
|
|
185
|
+
}
|
|
186
|
+
getOptions() {
|
|
187
|
+
return {
|
|
188
|
+
accept: true,
|
|
189
|
+
decline: true,
|
|
190
|
+
mute: true,
|
|
191
|
+
hold: true,
|
|
192
|
+
transfer: true,
|
|
193
|
+
sendKey: true,
|
|
194
|
+
addParticipant: false,
|
|
195
|
+
record: true,
|
|
196
|
+
merge: true,
|
|
614
197
|
};
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
if
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
console.warn('IssueReporter\'s logs aren\'t stored anymore. Please use fluentd to store them');
|
|
682
|
-
return [];
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
getParsedLogs() {
|
|
686
|
-
console.warn('IssueReporter\'s logs aren\'t stored anymore. Please use fluentd to store them');
|
|
687
|
-
return [];
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
getReport() {
|
|
691
|
-
return this.getParsedLogs().join('\r\n');
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
_catchConsole() {
|
|
695
|
-
this.oldConsoleMethods = {};
|
|
696
|
-
CONSOLE_METHODS.forEach((methodName ) => {
|
|
697
|
-
// eslint-disable-next-line
|
|
698
|
-
this.oldConsoleMethods[methodName] = console[methodName];
|
|
699
|
-
window.console[methodName] = (...args) => {
|
|
700
|
-
// Store message
|
|
701
|
-
try {
|
|
702
|
-
this.log(methodName, args.join(' '));
|
|
703
|
-
// Use old console method to log it normally
|
|
704
|
-
this.oldConsoleMethods[methodName].apply(null, args);
|
|
705
|
-
} catch (e) {
|
|
706
|
-
// Avoid circular structure issues
|
|
707
|
-
}
|
|
708
|
-
};
|
|
709
|
-
});
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
_sendToRemoteLogger(level , payload = {}) {
|
|
713
|
-
if (!this.remoteClientConfiguration) {
|
|
714
|
-
return;
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
const { level: minLevel, bufferSize } = this.remoteClientConfiguration;
|
|
718
|
-
if (!minLevel || this._isLevelAbove(minLevel, level)) {
|
|
719
|
-
return;
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
payload.level = level;
|
|
723
|
-
|
|
724
|
-
if (bufferSize > 0) {
|
|
725
|
-
return this._addToBuffer(payload);
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
this._sendDebugToGrafana(payload);
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
_parseLoggerBody(payload ) {
|
|
732
|
-
const { level } = payload;
|
|
733
|
-
const { maxMessageSize, extra } = this.remoteClientConfiguration || {};
|
|
734
|
-
|
|
735
|
-
delete payload.level;
|
|
736
|
-
|
|
737
|
-
if (maxMessageSize && typeof payload.message === 'string' && payload.message.length > maxMessageSize) {
|
|
738
|
-
payload.message = `${payload.message.substr(0, maxMessageSize)}...`;
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
return safeStringify({
|
|
742
|
-
level,
|
|
743
|
-
...payload,
|
|
744
|
-
...extra,
|
|
745
|
-
});
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
_addToBuffer(payload ) {
|
|
749
|
-
// Reset buffer timer
|
|
750
|
-
if (this.bufferTimeout) {
|
|
751
|
-
clearTimeout(this.bufferTimeout);
|
|
752
|
-
this.bufferTimeout = null;
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
this.buffer.push(payload);
|
|
756
|
-
|
|
757
|
-
// $FlowFixMe
|
|
758
|
-
const { bufferSize, bufferTimeout } = this.remoteClientConfiguration;
|
|
759
|
-
|
|
760
|
-
if (this.buffer.length > bufferSize) {
|
|
761
|
-
return this._processBuffer();
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
if (bufferTimeout > 0) {
|
|
765
|
-
this.bufferTimeout = setTimeout(this._boundProcessBuffer, bufferTimeout);
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
_processBuffer() {
|
|
770
|
-
this._sendDebugToGrafana(this.buffer);
|
|
771
|
-
|
|
772
|
-
this.buffer = [];
|
|
773
|
-
if (this.bufferTimeout) {
|
|
774
|
-
clearTimeout(this.bufferTimeout);
|
|
775
|
-
this.bufferTimeout = null;
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
_sendDebugToGrafana(payload , retry = 0) {
|
|
780
|
-
if (!this.remoteClientConfiguration || retry >= MAX_REMOTE_RETRY) {
|
|
781
|
-
return;
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
const { tag, host, port } = this.remoteClientConfiguration;
|
|
785
|
-
const isArray = Array.isArray(payload);
|
|
786
|
-
const isSecure = +port === 443;
|
|
787
|
-
const url = `http${isSecure ? 's' : ''}://${host}${isSecure ? '' : `:${port}`}/${tag}`;
|
|
788
|
-
const body = isArray ? `[${payload.map(this._boundParseLoggerBody).join(',')}]` : this._parseLoggerBody(payload);
|
|
789
|
-
|
|
790
|
-
realFetch()(url, {
|
|
791
|
-
method: 'POST',
|
|
792
|
-
headers: {
|
|
793
|
-
Accept: 'application/json',
|
|
794
|
-
'Content-Type': 'application/json',
|
|
795
|
-
},
|
|
796
|
-
// $FlowFixMe
|
|
797
|
-
body,
|
|
798
|
-
}).catch((e ) => {
|
|
799
|
-
// $FlowFixMe
|
|
800
|
-
e.skipSendToRemote = true;
|
|
801
|
-
this.log('error', this._makeCategory('grafana'), 'Sending log to grafana, error', e);
|
|
802
|
-
|
|
803
|
-
setTimeout(() => {
|
|
804
|
-
if (isArray) {
|
|
805
|
-
payload = payload.map(message => this._writeRetryCount(message, retry + 1));
|
|
806
|
-
} else if (payload && typeof payload === 'object') {
|
|
807
|
-
payload = this._writeRetryCount(payload, retry + 1);
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
this._sendDebugToGrafana(payload, retry + 1);
|
|
811
|
-
}, 5000 + retry * 1000);
|
|
812
|
-
});
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
_writeRetryCount(message , count ) {
|
|
816
|
-
if (message && typeof message === 'object') {
|
|
817
|
-
// $FlowFixMe
|
|
818
|
-
message._retry = count;
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
return message;
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
_isLevelAbove(level1 , level2 ) {
|
|
825
|
-
const index1 = LOG_LEVELS.indexOf(level1);
|
|
826
|
-
const index2 = LOG_LEVELS.indexOf(level2);
|
|
827
|
-
if (index1 === -1 || index2 === -1) {
|
|
828
|
-
return false;
|
|
829
|
-
}
|
|
830
|
-
|
|
831
|
-
return index1 > index2;
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
_makeCategory(category ) {
|
|
835
|
-
return `${CATEGORY_PREFIX}${category}`;
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
var IssueReporter$1 = new IssueReporter();
|
|
840
|
-
|
|
841
|
-
/* global RTCSessionDescriptionInit, navigator */
|
|
842
|
-
|
|
843
|
-
IssueReporter$1 ? IssueReporter$1.loggerFor('webrtc-sdh') : console;
|
|
844
|
-
|
|
845
|
-
//
|
|
846
|
-
|
|
847
|
-
class Emitter {
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
constructor() {
|
|
851
|
-
this.eventEmitter = new EventEmitter();
|
|
852
|
-
}
|
|
853
|
-
|
|
854
|
-
on(event , callback ) {
|
|
855
|
-
this.eventEmitter.on(event, callback);
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
once(event , callback ) {
|
|
859
|
-
this.eventEmitter.once(event, callback);
|
|
860
|
-
}
|
|
861
|
-
|
|
862
|
-
off(event , callback ) {
|
|
863
|
-
this.eventEmitter.removeListener(event, callback);
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
unbind() {
|
|
867
|
-
this.eventEmitter.removeAllListeners();
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
|
|
871
|
-
//
|
|
872
|
-
|
|
873
|
-
const swarmPublicKey = `-----BEGIN PUBLIC KEY-----
|
|
874
|
-
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmkXOuNfY8u5xoTiIhkb8
|
|
875
|
-
djnbIwG/Wrz3vpo8BZir8L5e1a1nSy740qBjP7ZINBQoALDhFfmdOfJnCyEGiHuz
|
|
876
|
-
ZW6jbG6C3PryE3Bu6GKwqSmD6k3q4Zk27fpwYAnNl+rWhYYM563rJZBda/INyHNN
|
|
877
|
-
pK7M1mixWi7gNdjjXwoEXSSBx+VpYMkY6LiAB2mvHXTY9M1qI14dvgGoQISZQoKi
|
|
878
|
-
NMTRCg5UP2ic0Dd9nSz/XpcOxGfa+0fwIl1F7RC1tJXOqvkGGPTOV4LLfg/Yta3h
|
|
879
|
-
nUPX9EZZDIX6vO/0IBV1LzjSl2A1bYFYAjJfowv3i1CpvONBOClHjSY5t9Y8MH6p
|
|
880
|
-
BwIDAQAB
|
|
881
|
-
-----END PUBLIC KEY-----`;
|
|
882
|
-
|
|
883
|
-
//
|
|
884
|
-
|
|
885
|
-
KEYUTIL.getKey(swarmPublicKey);
|
|
886
|
-
|
|
887
|
-
/* eslint-disable dot-notation */
|
|
888
|
-
|
|
889
|
-
// Can't use node cache mechanism here because when requiring lib/CallApi.js
|
|
890
|
-
// this file will be merge with CallApi.js and the cache will be lost.
|
|
891
|
-
// So we have to store values in global scope.
|
|
892
|
-
global.wazoClients = global.wazoClients || {};
|
|
893
|
-
global.wazoClientId = global.wazoClientId || {};
|
|
894
|
-
global.wazoClientToken = global.wazoClientToken || {};
|
|
895
|
-
global.wazoRefreshToken = global.wazoRefreshToken || {};
|
|
896
|
-
global.wazoRefreshTenantId = global.wazoRefreshTenantId || {};
|
|
897
|
-
global.wazoRefreshDomainName = global.wazoRefreshDomainName || {};
|
|
898
|
-
global.wazoOnRefreshToken = global.wazoOnRefreshToken || {};
|
|
899
|
-
global.wazoOnRefreshTokenError = global.wazoOnRefreshTokenError || {};
|
|
900
|
-
global.wazoRefreshExpiration = global.wazoRefreshExpiration || {};
|
|
901
|
-
global.wazoRefreshBackend = global.wazoRefreshBackend || {};
|
|
902
|
-
global.wazoIsMobile = global.wazoIsMobile || {};
|
|
903
|
-
global.wazoFetchOptions = global.wazoFetchOptions || {};
|
|
904
|
-
|
|
905
|
-
//
|
|
906
|
-
|
|
907
|
-
// const MINIMUM_WAZO_ENGINE_VERSION_FOR_CTI_HOLD = '20.11';
|
|
908
|
-
|
|
909
|
-
IssueReporter$1 ? IssueReporter$1.loggerFor('cti-phone') : console;
|
|
910
|
-
|
|
911
|
-
/* */
|
|
912
|
-
|
|
913
|
-
IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
|
|
914
|
-
|
|
915
|
-
//
|
|
916
|
-
IssueReporter$1 ? IssueReporter$1.loggerFor('webrtc-client') : console;
|
|
917
|
-
IssueReporter$1 ? IssueReporter$1.loggerFor('webrtc-stats') : console;
|
|
918
|
-
|
|
919
|
-
/* eslint-disable no-param-reassign */
|
|
920
|
-
|
|
921
|
-
const ON_USER_AGENT = 'onUserAgent';
|
|
922
|
-
const ON_REGISTERED = 'onRegistered';
|
|
923
|
-
const ON_UNREGISTERED = 'onUnRegistered';
|
|
924
|
-
const ON_PROGRESS = 'onProgress';
|
|
925
|
-
const ON_CALL_ACCEPTED = 'onCallAccepted';
|
|
926
|
-
const ON_CALL_ANSWERED = 'onCallAnswered';
|
|
927
|
-
const ON_CALL_INCOMING = 'onCallIncoming';
|
|
928
|
-
const ON_CALL_OUTGOING = 'onCallOutgoing';
|
|
929
|
-
const ON_CALL_MUTED = 'onCallMuted';
|
|
930
|
-
const ON_CALL_UNMUTED = 'onCallUnmuted';
|
|
931
|
-
const ON_CALL_RESUMED = 'onCallResumed';
|
|
932
|
-
const ON_CALL_HELD = 'onCallHeld';
|
|
933
|
-
const ON_CALL_UNHELD = 'onCallUnHeld';
|
|
934
|
-
const ON_CAMERA_DISABLED = 'onCameraDisabled';
|
|
935
|
-
const ON_CAMERA_RESUMED = 'onCameraResumed';
|
|
936
|
-
const ON_CALL_CANCELED = 'onCallCanceled';
|
|
937
|
-
const ON_CALL_FAILED = 'onCallFailed';
|
|
938
|
-
const ON_CALL_REJECTED = 'onCallRejected';
|
|
939
|
-
const ON_CALL_ENDED = 'onCallEnded';
|
|
940
|
-
const ON_CALL_ENDING = 'onCallEnding';
|
|
941
|
-
const ON_MESSAGE = 'onMessage';
|
|
942
|
-
const ON_REINVITE = 'reinvite';
|
|
943
|
-
const ON_TRACK = 'onTrack';
|
|
944
|
-
const ON_AUDIO_STREAM = 'onAudioStream';
|
|
945
|
-
const ON_VIDEO_STREAM = 'onVideoStream';
|
|
946
|
-
const ON_REMOVE_STREAM = 'onRemoveStream';
|
|
947
|
-
const ON_SHARE_SCREEN_STARTED = 'onScreenShareStarted';
|
|
948
|
-
const ON_SHARE_SCREEN_ENDING = 'onScreenShareEnding';
|
|
949
|
-
const ON_SHARE_SCREEN_ENDED = 'onScreenShareEnded';
|
|
950
|
-
const ON_TERMINATE_SOUND = 'terminateSound';
|
|
951
|
-
const ON_PLAY_RING_SOUND = 'playRingingSound';
|
|
952
|
-
const ON_PLAY_INBOUND_CALL_SIGNAL_SOUND = 'playInboundCallSignalSound';
|
|
953
|
-
const ON_PLAY_HANGUP_SOUND = 'playHangupSound';
|
|
954
|
-
const ON_PLAY_PROGRESS_SOUND = 'playProgressSound';
|
|
955
|
-
const ON_VIDEO_INPUT_CHANGE = 'videoInputChange';
|
|
956
|
-
const ON_CALL_ERROR = 'onCallError';
|
|
957
|
-
const ON_MESSAGE_TRACK_UPDATED = 'onTrackUpdated';
|
|
958
|
-
const ON_NETWORK_STATS = 'onNetworkStats';
|
|
959
|
-
const ON_CHAT = 'phone/ON_CHAT';
|
|
960
|
-
const ON_SIGNAL = 'phone/ON_SIGNAL';
|
|
961
|
-
const ON_DISCONNECTED = 'onDisconnected';
|
|
962
|
-
const ON_EARLY_MEDIA = 'onEarlyMedia';
|
|
963
|
-
|
|
964
|
-
const MESSAGE_TYPE_CHAT = 'message/TYPE_CHAT';
|
|
965
|
-
const MESSAGE_TYPE_SIGNAL = 'message/TYPE_SIGNAL';
|
|
966
|
-
|
|
967
|
-
const events = [
|
|
968
|
-
ON_USER_AGENT,
|
|
969
|
-
ON_REGISTERED,
|
|
970
|
-
ON_UNREGISTERED,
|
|
971
|
-
ON_PROGRESS,
|
|
972
|
-
ON_CALL_ACCEPTED,
|
|
973
|
-
ON_CALL_ANSWERED,
|
|
974
|
-
ON_CALL_INCOMING,
|
|
975
|
-
ON_CALL_OUTGOING,
|
|
976
|
-
ON_CALL_MUTED,
|
|
977
|
-
ON_CALL_UNMUTED,
|
|
978
|
-
ON_CALL_RESUMED,
|
|
979
|
-
ON_CALL_HELD,
|
|
980
|
-
ON_CALL_UNHELD,
|
|
981
|
-
ON_CAMERA_DISABLED,
|
|
982
|
-
ON_CALL_FAILED,
|
|
983
|
-
ON_CALL_ENDED,
|
|
984
|
-
ON_CALL_REJECTED,
|
|
985
|
-
ON_MESSAGE,
|
|
986
|
-
ON_REINVITE,
|
|
987
|
-
ON_TRACK,
|
|
988
|
-
ON_AUDIO_STREAM,
|
|
989
|
-
ON_VIDEO_STREAM,
|
|
990
|
-
ON_REMOVE_STREAM,
|
|
991
|
-
ON_SHARE_SCREEN_ENDED,
|
|
992
|
-
ON_TERMINATE_SOUND,
|
|
993
|
-
ON_PLAY_RING_SOUND,
|
|
994
|
-
ON_PLAY_INBOUND_CALL_SIGNAL_SOUND,
|
|
995
|
-
ON_PLAY_HANGUP_SOUND,
|
|
996
|
-
ON_PLAY_PROGRESS_SOUND,
|
|
997
|
-
ON_VIDEO_INPUT_CHANGE,
|
|
998
|
-
ON_SHARE_SCREEN_STARTED,
|
|
999
|
-
ON_CALL_ERROR,
|
|
1000
|
-
ON_CHAT,
|
|
1001
|
-
ON_SIGNAL,
|
|
1002
|
-
ON_NETWORK_STATS,
|
|
1003
|
-
ON_DISCONNECTED,
|
|
1004
|
-
ON_EARLY_MEDIA,
|
|
1005
|
-
];
|
|
1006
|
-
|
|
1007
|
-
const logger = IssueReporter$1.loggerFor('webrtc-phone');
|
|
1008
|
-
|
|
1009
|
-
class WebRTCPhone extends Emitter {
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
constructor(
|
|
1045
|
-
client ,
|
|
1046
|
-
audioOutputDeviceId ,
|
|
1047
|
-
allowVideo = false,
|
|
1048
|
-
audioRingDeviceId ,
|
|
1049
|
-
) {
|
|
1050
|
-
super();
|
|
1051
|
-
|
|
1052
|
-
this.client = client;
|
|
1053
|
-
this.allowVideo = allowVideo;
|
|
1054
|
-
this.callSessions = {};
|
|
1055
|
-
this.audioOutputDeviceId = audioOutputDeviceId;
|
|
1056
|
-
this.audioRingDeviceId = audioRingDeviceId || audioOutputDeviceId;
|
|
1057
|
-
this.audioOutputVolume = 1;
|
|
1058
|
-
this.audioRingVolume = 1;
|
|
1059
|
-
this.incomingSessions = [];
|
|
1060
|
-
this.ringingEnabled = true;
|
|
1061
|
-
this.shouldSendReinvite = false;
|
|
1062
|
-
|
|
1063
|
-
this.bindClientEvents();
|
|
1064
|
-
|
|
1065
|
-
this.acceptedSessions = {};
|
|
1066
|
-
this.rejectedSessions = {};
|
|
1067
|
-
this.ignoredSessions = {};
|
|
1068
|
-
}
|
|
1069
|
-
|
|
1070
|
-
register() {
|
|
1071
|
-
if (!this.client) {
|
|
1072
|
-
return Promise.resolve();
|
|
1073
|
-
}
|
|
1074
|
-
|
|
1075
|
-
return this.client.register().then(() => {
|
|
1076
|
-
return this.bindClientEvents();
|
|
1077
|
-
}).catch(error => {
|
|
1078
|
-
// Avoid exception on `t.server.scheme` in sip transport when losing the webrtc socket connection
|
|
1079
|
-
console.error('register error', error, error.message, error.stack);
|
|
1080
|
-
logger.error('WebRTC register error', { message: error.message, stack: error.stack });
|
|
1081
|
-
});
|
|
1082
|
-
}
|
|
1083
|
-
|
|
1084
|
-
unregister() {
|
|
1085
|
-
if (!this.client || !this.client.isRegistered()) {
|
|
1086
|
-
return null;
|
|
1087
|
-
}
|
|
1088
|
-
return this.client.unregister();
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
stop() {
|
|
1092
|
-
if (!this.client) {
|
|
1093
|
-
return;
|
|
1094
|
-
}
|
|
1095
|
-
logger.info('WebRTC phone stop');
|
|
1096
|
-
this.client.stop();
|
|
1097
|
-
}
|
|
1098
|
-
|
|
1099
|
-
removeIncomingSessions(id ) {
|
|
1100
|
-
this.incomingSessions = this.incomingSessions.filter(sessionId => sessionId !== id);
|
|
1101
|
-
}
|
|
1102
|
-
|
|
1103
|
-
isWebRTC() {
|
|
1104
|
-
return true;
|
|
1105
|
-
}
|
|
1106
|
-
|
|
1107
|
-
async sendReinvite(callSession , constraints = null, conference = false,
|
|
1108
|
-
audioOnly = false, iceRestart = false) {
|
|
1109
|
-
const sipSession = this.findSipSession(callSession);
|
|
1110
|
-
logger.info('WebRTC phone - send reinvite', {
|
|
1111
|
-
sessionId: sipSession ? sipSession.id : null,
|
|
1112
|
-
constraints,
|
|
1113
|
-
audioOnly,
|
|
1114
|
-
conference,
|
|
1115
|
-
iceRestart,
|
|
1116
|
-
});
|
|
1117
|
-
|
|
1118
|
-
if (!sipSession) {
|
|
1119
|
-
return false;
|
|
1120
|
-
}
|
|
1121
|
-
|
|
1122
|
-
// $FlowFixMe
|
|
1123
|
-
const shouldScreenShare = constraints && constraints.screen;
|
|
1124
|
-
const isUpgrade = shouldScreenShare || (constraints && constraints.video);
|
|
1125
|
-
|
|
1126
|
-
// Downgrade
|
|
1127
|
-
if (constraints && !isUpgrade) {
|
|
1128
|
-
// No reinvite needed
|
|
1129
|
-
this._downgradeToAudio(callSession);
|
|
1130
|
-
return false;
|
|
1131
|
-
}
|
|
1132
|
-
|
|
1133
|
-
if (isUpgrade) {
|
|
1134
|
-
const shouldReinvite = await this._upgradeToVideo(callSession, constraints, conference);
|
|
1135
|
-
if (!shouldReinvite) {
|
|
198
|
+
}
|
|
199
|
+
onConnect() {
|
|
200
|
+
if (!this.client) {
|
|
201
|
+
return Promise.reject(new Error('No webrtc client'));
|
|
202
|
+
}
|
|
203
|
+
return this.client.onConnect();
|
|
204
|
+
}
|
|
205
|
+
onDisconnect() {
|
|
206
|
+
if (!this.client) {
|
|
207
|
+
return Promise.reject(new Error('No webrtc client'));
|
|
208
|
+
}
|
|
209
|
+
return this.client.onDisconnect();
|
|
210
|
+
}
|
|
211
|
+
_downgradeToAudio(callSession, withMessage = true) {
|
|
212
|
+
const sipSession = this.findSipSession(callSession);
|
|
213
|
+
if (!sipSession) {
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
logger.info('Downgrade to video', {
|
|
217
|
+
id: callSession ? callSession.getId() : null,
|
|
218
|
+
withMessage,
|
|
219
|
+
});
|
|
220
|
+
this.client.downgradeToAudio(sipSession);
|
|
221
|
+
if (callSession) {
|
|
222
|
+
callSession.cameraEnabled = false;
|
|
223
|
+
this._updateCallSession(callSession);
|
|
224
|
+
}
|
|
225
|
+
if (withMessage) {
|
|
226
|
+
this._sendReinviteMessage(callSession, false);
|
|
227
|
+
}
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
// Returns true if we need to send a re-INVITE request
|
|
231
|
+
async _upgradeToVideo(callSession, constraints, isConference) {
|
|
232
|
+
const sipSession = this.findSipSession(callSession);
|
|
233
|
+
if (!sipSession) {
|
|
234
|
+
return Promise.resolve(false);
|
|
235
|
+
}
|
|
236
|
+
logger.info('Upgrade to video', {
|
|
237
|
+
id: callSession ? callSession.getId() : null,
|
|
238
|
+
constraints,
|
|
239
|
+
isConference,
|
|
240
|
+
});
|
|
241
|
+
const shouldScreenShare = constraints && !!constraints.screen;
|
|
242
|
+
const desktop = constraints && constraints.desktop;
|
|
243
|
+
const options = sipSession.sessionDescriptionHandlerOptionsReInvite;
|
|
244
|
+
// @ts-ignore
|
|
245
|
+
const wasAudioOnly = options?.audioOnly;
|
|
246
|
+
const newStream = await this.client.upgradeToVideo(sipSession, constraints, isConference);
|
|
247
|
+
if (callSession) {
|
|
248
|
+
callSession.cameraEnabled = true;
|
|
249
|
+
this._updateCallSession(callSession);
|
|
250
|
+
}
|
|
251
|
+
// If no stream is returned, it means we have to reinvite
|
|
252
|
+
if (!newStream) {
|
|
253
|
+
return true;
|
|
254
|
+
}
|
|
255
|
+
this._sendReinviteMessage(callSession, true);
|
|
256
|
+
if (shouldScreenShare) {
|
|
257
|
+
this._onScreenSharing(newStream, sipSession, callSession, false, desktop);
|
|
258
|
+
}
|
|
259
|
+
// We have to reinvite to change the direction on the bundle when upgrading from an audioOnly conference
|
|
260
|
+
if (isConference && wasAudioOnly) {
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
// No reinvite needed here
|
|
1136
264
|
return false;
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
265
|
+
}
|
|
266
|
+
_sendReinviteMessage(callSession, isUpgrade) {
|
|
267
|
+
const sipSession = this.findSipSession(callSession);
|
|
268
|
+
logger.info('Sending reinvite message', {
|
|
269
|
+
id: callSession ? callSession.getId() : null,
|
|
270
|
+
isUpgrade,
|
|
271
|
+
});
|
|
272
|
+
// Have to send the message after a delay due to latency to update the remote peer
|
|
273
|
+
setTimeout(() => {
|
|
274
|
+
this.sendMessage(sipSession, JSON.stringify({
|
|
275
|
+
type: MESSAGE_TYPE_SIGNAL,
|
|
276
|
+
content: {
|
|
277
|
+
type: ON_MESSAGE_TRACK_UPDATED,
|
|
278
|
+
update: isUpgrade ? 'upgrade' : 'downgrade',
|
|
279
|
+
sipCallId: sipSession && this.getSipSessionId(sipSession),
|
|
280
|
+
callId: callSession ? callSession.callId : null,
|
|
281
|
+
number: callSession ? callSession.number : null,
|
|
282
|
+
callerNumber: callSession ? callSession.callerNumber : null,
|
|
283
|
+
},
|
|
284
|
+
}));
|
|
285
|
+
}, 2500);
|
|
286
|
+
}
|
|
287
|
+
_bindEvents(sipSession) {
|
|
288
|
+
if (sipSession instanceof Invitation) {
|
|
289
|
+
// Monkey patch to know when canceled with the CANCEL message
|
|
290
|
+
const onCancel = sipSession._onCancel.bind(sipSession);
|
|
291
|
+
sipSession._onCancel = (message) => {
|
|
292
|
+
logger.trace('on sip session canceled', {
|
|
293
|
+
callId: message.callId,
|
|
294
|
+
});
|
|
295
|
+
onCancel(message);
|
|
296
|
+
const elsewhere = message.data.indexOf('cause=26') !== -1 && message.data.indexOf('completed elsewhere') !== -1;
|
|
297
|
+
const callSession = this._createCallSession(sipSession);
|
|
298
|
+
delete this.callSessions[callSession.getId()];
|
|
299
|
+
this.eventEmitter.emit(ON_CALL_CANCELED, callSession, elsewhere);
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
else if (sipSession instanceof Invitation) {
|
|
303
|
+
console.warn('sipSession._onCancel not found, please update the wazo SDK accordingly');
|
|
304
|
+
}
|
|
305
|
+
sipSession.stateChange.addListener((newState) => {
|
|
306
|
+
switch (newState) {
|
|
307
|
+
case SessionState.Establishing:
|
|
308
|
+
if (sipSession instanceof Invitation) {
|
|
309
|
+
// No need to trigger progress for an invitation (eg: when we answer the call).
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
// When receiving a progress event, we know we are the caller so we have to force incoming to false
|
|
313
|
+
return this.eventEmitter.emit(ON_PROGRESS, this._createCallSession(sipSession, null, {
|
|
314
|
+
incoming: false,
|
|
315
|
+
ringing: true,
|
|
316
|
+
}), this.audioOutputDeviceId, this.audioOutputVolume);
|
|
317
|
+
case SessionState.Terminating:
|
|
318
|
+
logger.info('WebRTC phone - call terminating', {
|
|
319
|
+
sipId: sipSession.id,
|
|
320
|
+
});
|
|
321
|
+
this.eventEmitter.emit(ON_CALL_ENDING, this._createCallSession(sipSession));
|
|
322
|
+
break;
|
|
323
|
+
case SessionState.Terminated:
|
|
324
|
+
{
|
|
325
|
+
logger.info('WebRTC phone - call terminated', {
|
|
326
|
+
sipId: sipSession.id,
|
|
327
|
+
});
|
|
328
|
+
// Should be called before `_onCallTerminated` or the callCount will not decrement...
|
|
329
|
+
const callSession = this._createCallSession(sipSession);
|
|
330
|
+
callSession.endTime = new Date();
|
|
331
|
+
const wasCurrentSession = this._onCallTerminated(sipSession);
|
|
332
|
+
return this.eventEmitter.emit(ON_CALL_ENDED, callSession, wasCurrentSession);
|
|
333
|
+
}
|
|
334
|
+
default:
|
|
335
|
+
break;
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
if (!sipSession.sessionDescriptionHandler) {
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
// Video events
|
|
342
|
+
const {
|
|
343
|
+
// @ts-ignore
|
|
344
|
+
peerConnection, } = sipSession.sessionDescriptionHandler;
|
|
345
|
+
peerConnection.ontrack = (rawEvent) => {
|
|
346
|
+
const event = rawEvent;
|
|
347
|
+
const [stream] = event.streams;
|
|
348
|
+
const kind = event && event.track && event.track.kind;
|
|
349
|
+
logger.info('on track stream called on the peer connection', {
|
|
350
|
+
callId: this.getSipSessionId(sipSession),
|
|
351
|
+
streamId: stream ? stream.id : null,
|
|
352
|
+
tracks: stream ? stream.getTracks() : null,
|
|
353
|
+
kind,
|
|
354
|
+
});
|
|
355
|
+
if (kind === 'audio') {
|
|
356
|
+
return this.eventEmitter.emit(ON_AUDIO_STREAM, stream);
|
|
357
|
+
}
|
|
358
|
+
// not sure this does anything
|
|
359
|
+
if (kind === 'video') {
|
|
360
|
+
event.track.enabled = false;
|
|
361
|
+
}
|
|
362
|
+
return this.eventEmitter.emit(ON_VIDEO_STREAM, stream, event.track.id, event, sipSession);
|
|
363
|
+
};
|
|
364
|
+
peerConnection.onremovestream = (event) => {
|
|
365
|
+
logger.info('on remove stream called on the peer connection', {
|
|
366
|
+
id: event.stream.id,
|
|
367
|
+
tracks: event.stream.getTracks(),
|
|
368
|
+
});
|
|
369
|
+
this.eventEmitter.emit(ON_REMOVE_STREAM, event.stream);
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
async startScreenSharing(constraints, callSession) {
|
|
373
|
+
logger.info('WebRTC - start screen sharing', {
|
|
374
|
+
constraints,
|
|
375
|
+
id: callSession ? callSession.getId() : null,
|
|
376
|
+
});
|
|
377
|
+
const screenShareStream = await this.client.getStreamFromConstraints(constraints);
|
|
378
|
+
if (!screenShareStream) {
|
|
379
|
+
throw new Error(`Can't create media stream for screensharing with: ${JSON.stringify(constraints)}`);
|
|
380
|
+
}
|
|
381
|
+
const screenTrack = screenShareStream.getVideoTracks()[0];
|
|
382
|
+
const sipSession = this.currentSipSession;
|
|
383
|
+
const pc = sipSession && this.client.getPeerConnection(this.getSipSessionId(sipSession));
|
|
384
|
+
const sender = pc && pc.getSenders && pc.getSenders().find((s) => s && s.track && s.track.kind === 'video');
|
|
385
|
+
const localStream = sipSession && this.client.getLocalStream(this.getSipSessionId(sipSession));
|
|
386
|
+
const videoTrack = localStream ? localStream.getTracks().find(track => track.kind === 'video') : null;
|
|
387
|
+
const hadVideo = !!videoTrack;
|
|
388
|
+
// Stop local video tracks
|
|
389
|
+
if (videoTrack && localStream) {
|
|
390
|
+
videoTrack.enabled = false;
|
|
391
|
+
videoTrack.stop();
|
|
392
|
+
localStream.removeTrack(videoTrack);
|
|
393
|
+
}
|
|
394
|
+
if (localStream) {
|
|
395
|
+
localStream.addTrack(screenTrack);
|
|
396
|
+
}
|
|
397
|
+
if (sender) {
|
|
398
|
+
sender.replaceTrack(screenTrack);
|
|
399
|
+
}
|
|
400
|
+
this._onScreenSharing(screenShareStream, sipSession, callSession, hadVideo, constraints.desktop);
|
|
401
|
+
return screenShareStream;
|
|
402
|
+
}
|
|
403
|
+
async stopScreenSharing(restoreLocalStream = true, callSession) {
|
|
404
|
+
if (!this.currentScreenShare) {
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
logger.info('WebRTC phone - stop screen sharing', {
|
|
408
|
+
restoreLocalStream,
|
|
409
|
+
});
|
|
410
|
+
let reinvited;
|
|
411
|
+
try {
|
|
412
|
+
if (this.currentScreenShare.stream) {
|
|
413
|
+
this.currentScreenShare.stream.getTracks().forEach((track) => track.stop());
|
|
414
|
+
}
|
|
415
|
+
if (restoreLocalStream) {
|
|
416
|
+
const targetCallSession = callSession || this.currentCallSession;
|
|
417
|
+
const conference = this.isConference(targetCallSession);
|
|
418
|
+
// When stopping screenshare and we had video before that, we have to re-upgrade
|
|
419
|
+
// When upgrading directly to screenshare (eg: we don't have a videoLocalStream to replace)
|
|
420
|
+
// We have to downgrade to audio.
|
|
421
|
+
const screenshareStopped = this.currentScreenShare.hadVideo;
|
|
422
|
+
const constraints = {
|
|
423
|
+
audio: false,
|
|
424
|
+
video: screenshareStopped,
|
|
425
|
+
};
|
|
426
|
+
// We have to remove the video sender to be able to re-upgrade to video in `sendReinvite` below
|
|
427
|
+
this._downgradeToAudio(targetCallSession, false);
|
|
428
|
+
// Wait for the track to be removed, unless the video sender won't have a null track in `_upgradeToVideo`.
|
|
429
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
430
|
+
reinvited = await this.sendReinvite(targetCallSession, constraints, conference);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
catch (e) {
|
|
434
|
+
console.warn(e);
|
|
435
|
+
}
|
|
436
|
+
const sipSession = this.currentSipSession;
|
|
437
|
+
this.eventEmitter.emit(ON_SHARE_SCREEN_ENDED, callSession && sipSession ? this._createCallSession(sipSession, callSession, {
|
|
438
|
+
screensharing: false,
|
|
439
|
+
}) : null);
|
|
440
|
+
this.currentScreenShare = null;
|
|
441
|
+
return reinvited;
|
|
442
|
+
}
|
|
443
|
+
_onScreenSharing(screenStream, sipSession, callSession, hadVideo, desktop) {
|
|
444
|
+
const screenTrack = screenStream.getVideoTracks()[0];
|
|
445
|
+
const sipSessionId = this.getSipSessionId(sipSession);
|
|
446
|
+
const pc = this.client.getPeerConnection(sipSessionId);
|
|
447
|
+
const sender = pc && pc.getSenders && pc.getSenders().find((s) => s && s.track && s.track.kind === 'video');
|
|
448
|
+
logger.info('WebRTC phone - on screensharing', {
|
|
449
|
+
hadVideo,
|
|
450
|
+
id: this.getSipSessionId(sipSession),
|
|
451
|
+
screenTrack,
|
|
452
|
+
});
|
|
453
|
+
if (screenTrack) {
|
|
454
|
+
screenTrack.onended = () => {
|
|
455
|
+
logger.info('WebRTC phone - on screenshare ended', {
|
|
456
|
+
hadVideo,
|
|
457
|
+
id: this.getSipSessionId(sipSession),
|
|
458
|
+
screenTrack,
|
|
459
|
+
});
|
|
460
|
+
this.eventEmitter.emit(ON_SHARE_SCREEN_ENDING, this._createCallSession(sipSession, callSession));
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
this.currentScreenShare = {
|
|
464
|
+
stream: screenStream,
|
|
465
|
+
hadVideo,
|
|
466
|
+
sender,
|
|
467
|
+
sipSessionId,
|
|
468
|
+
desktop,
|
|
469
|
+
};
|
|
470
|
+
this.client.setLocalMediaStream(this.getSipSessionId(sipSession), screenStream);
|
|
471
|
+
this.eventEmitter.emit(ON_SHARE_SCREEN_STARTED, this._createCallSession(sipSession, callSession, {
|
|
472
|
+
screensharing: true,
|
|
473
|
+
}), screenStream);
|
|
474
|
+
}
|
|
475
|
+
_onCallAccepted(sipSession, cameraEnabled) {
|
|
476
|
+
logger.info('WebRTC phone - on call accepted', {
|
|
477
|
+
sipId: sipSession.id,
|
|
478
|
+
cameraEnabled,
|
|
479
|
+
});
|
|
480
|
+
const callSession = this._createAcceptedCallSession(sipSession, cameraEnabled);
|
|
481
|
+
this.currentSipSession = sipSession;
|
|
482
|
+
this.currentCallSession = callSession;
|
|
483
|
+
this.eventEmitter.emit(ON_TERMINATE_SOUND, callSession, 'call accepted');
|
|
484
|
+
const sipSessionId = this.getSipSessionId(sipSession);
|
|
485
|
+
if (sipSessionId) {
|
|
486
|
+
this.removeIncomingSessions(sipSessionId);
|
|
487
|
+
}
|
|
488
|
+
callSession.answerTime = new Date();
|
|
489
|
+
this._updateCallSession(callSession);
|
|
490
|
+
this.eventEmitter.emit(ON_CALL_ACCEPTED, callSession, cameraEnabled);
|
|
491
|
+
return callSession;
|
|
492
|
+
}
|
|
493
|
+
changeAudioDevice(id) {
|
|
494
|
+
logger.info('WebRTC phone - change audio device', {
|
|
495
|
+
deviceId: id,
|
|
496
|
+
});
|
|
497
|
+
this.audioOutputDeviceId = id;
|
|
498
|
+
this.client.changeAudioOutputDevice(id);
|
|
499
|
+
}
|
|
500
|
+
createAudioElementFor(sessionId) {
|
|
501
|
+
return this.client.createAudioElementFor(sessionId);
|
|
502
|
+
}
|
|
503
|
+
changeRingDevice(id) {
|
|
504
|
+
logger.info('WebRTC phone - changing ring device', {
|
|
505
|
+
id,
|
|
506
|
+
});
|
|
507
|
+
this.audioRingDeviceId = id;
|
|
508
|
+
}
|
|
509
|
+
// volume is a value between 0 and 1
|
|
510
|
+
changeAudioVolume(volume) {
|
|
511
|
+
logger.info('WebRTC phone - changing audio volume', {
|
|
512
|
+
volume,
|
|
513
|
+
});
|
|
514
|
+
this.audioOutputVolume = volume;
|
|
515
|
+
this.client.changeAudioOutputVolume(volume);
|
|
516
|
+
}
|
|
517
|
+
// volume is a value between 0 and 1
|
|
518
|
+
changeRingVolume(volume) {
|
|
519
|
+
logger.info('WebRTC phone - changing ring volume', {
|
|
520
|
+
volume,
|
|
521
|
+
});
|
|
522
|
+
this.audioRingVolume = volume;
|
|
523
|
+
}
|
|
524
|
+
changeAudioInputDevice(id, force) {
|
|
525
|
+
logger.info('WebRTC phone - changeAudio input device', {
|
|
526
|
+
deviceId: id,
|
|
527
|
+
});
|
|
528
|
+
return this.client.changeAudioInputDevice(id, this.currentSipSession, force);
|
|
529
|
+
}
|
|
530
|
+
async changeVideoInputDevice(id) {
|
|
531
|
+
logger.info('WebRTC phone - change video input device', {
|
|
532
|
+
deviceId: id,
|
|
533
|
+
});
|
|
534
|
+
return this.client.changeVideoInputDevice(id, this.currentSipSession);
|
|
535
|
+
}
|
|
536
|
+
changeSessionVideoInputDevice(id) {
|
|
537
|
+
logger.info('WebRTC phone - change session video input device', {
|
|
538
|
+
deviceId: id,
|
|
539
|
+
});
|
|
540
|
+
return this.currentSipSession && this.client.changeSessionVideoInputDevice(id, this.currentSipSession);
|
|
541
|
+
}
|
|
542
|
+
_onCallTerminated(sipSession) {
|
|
543
|
+
logger.info('WebRTC phone - on call terminated', {
|
|
544
|
+
sipId: sipSession.id,
|
|
545
|
+
});
|
|
546
|
+
const sipSessionId = this.getSipSessionId(sipSession);
|
|
1308
547
|
const callSession = this._createCallSession(sipSession);
|
|
548
|
+
const isCurrentSession = this.isCurrentCallSipSession(callSession);
|
|
549
|
+
const isCurrentIncomingCall = callSession.is(this.getIncomingCallSession());
|
|
550
|
+
// If the terminated call was an incoming call, we have to re-trigger if it's was the first incoming call
|
|
551
|
+
// Otherwise, we have to re-trigger an incoming call event if another call is incoming
|
|
552
|
+
const shouldRetrigger = isCurrentSession ? this.incomingSessions.length : isCurrentIncomingCall;
|
|
553
|
+
// Terminate incoming sound only for the ringing call
|
|
554
|
+
// (so another terminated call won't stop the incoming call sound)
|
|
555
|
+
if (isCurrentIncomingCall) {
|
|
556
|
+
setTimeout(() => {
|
|
557
|
+
// Avoid race condition when the other is calling and hanging up immediately
|
|
558
|
+
this.eventEmitter.emit(ON_TERMINATE_SOUND, callSession, 'call terminated');
|
|
559
|
+
}, 5);
|
|
560
|
+
}
|
|
561
|
+
if (sipSessionId) {
|
|
562
|
+
this.removeIncomingSessions(sipSessionId);
|
|
563
|
+
}
|
|
1309
564
|
delete this.callSessions[callSession.getId()];
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
565
|
+
if (isCurrentSession) {
|
|
566
|
+
this.currentSipSession = undefined;
|
|
567
|
+
this.currentCallSession = undefined;
|
|
568
|
+
}
|
|
569
|
+
const hasIncomingCallSession = this.hasIncomingCallSession();
|
|
570
|
+
// Re-trigger incoming call event for remaining incoming calls
|
|
571
|
+
logger.info('WebRTC phone - check to re-trigger incoming call', {
|
|
572
|
+
sipId: sipSession.id,
|
|
573
|
+
shouldRetrigger,
|
|
574
|
+
hasIncomingCallSession,
|
|
575
|
+
});
|
|
576
|
+
this.client.onCallEnded(sipSession);
|
|
577
|
+
if (hasIncomingCallSession && shouldRetrigger) {
|
|
578
|
+
const nextCallSession = this.getIncomingCallSession();
|
|
579
|
+
// Avoid race condition
|
|
580
|
+
setTimeout(() => {
|
|
581
|
+
if (this.ringingEnabled) {
|
|
582
|
+
if (!this.currentCallSession) {
|
|
583
|
+
this.eventEmitter.emit(ON_PLAY_RING_SOUND, this.audioRingDeviceId, this.audioRingVolume, nextCallSession);
|
|
584
|
+
}
|
|
585
|
+
else {
|
|
586
|
+
this.eventEmitter.emit(ON_PLAY_INBOUND_CALL_SIGNAL_SOUND, this.audioOutputDeviceId, this.audioOutputVolume, nextCallSession);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
this.eventEmitter.emit(ON_CALL_INCOMING, nextCallSession, nextCallSession?.cameraEnabled);
|
|
590
|
+
}, 100);
|
|
591
|
+
}
|
|
592
|
+
if (callSession.getId() in this.ignoredSessions) {
|
|
593
|
+
return false;
|
|
594
|
+
}
|
|
595
|
+
// @ts-ignore
|
|
596
|
+
if (!sipSession.isCanceled) {
|
|
597
|
+
setTimeout(() => {
|
|
598
|
+
this.eventEmitter.emit(ON_PLAY_HANGUP_SOUND, this.audioOutputDeviceId, this.audioOutputVolume, callSession);
|
|
599
|
+
}, 10);
|
|
600
|
+
}
|
|
601
|
+
return isCurrentSession;
|
|
602
|
+
}
|
|
603
|
+
setActiveSipSession(callSession) {
|
|
604
|
+
const sipSessionId = this.findSipSession(callSession);
|
|
605
|
+
if (!sipSessionId) {
|
|
1322
606
|
return;
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
return screenShareStream;
|
|
1424
|
-
}
|
|
1425
|
-
|
|
1426
|
-
async stopScreenSharing(restoreLocalStream = true, callSession ) {
|
|
1427
|
-
if (!this.currentScreenShare) {
|
|
1428
|
-
return;
|
|
1429
|
-
}
|
|
1430
|
-
|
|
1431
|
-
logger.info('WebRTC phone - stop screen sharing', {
|
|
1432
|
-
restoreLocalStream,
|
|
1433
|
-
});
|
|
1434
|
-
|
|
1435
|
-
let reinvited = false;
|
|
1436
|
-
|
|
1437
|
-
try {
|
|
1438
|
-
if (this.currentScreenShare.stream) {
|
|
1439
|
-
this.currentScreenShare.stream.getTracks().forEach(track => track.stop());
|
|
1440
|
-
}
|
|
1441
|
-
|
|
1442
|
-
if (restoreLocalStream) {
|
|
1443
|
-
const targetCallSession = callSession || this.currentCallSession;
|
|
1444
|
-
const conference = this.isConference(targetCallSession);
|
|
1445
|
-
|
|
1446
|
-
// When stopping screenshare and we had video before that, we have to re-upgrade
|
|
1447
|
-
// When upgrading directly to screenshare (eg: we don't have a videoLocalStream to replace)
|
|
1448
|
-
// We have to downgrade to audio.
|
|
1449
|
-
const screenshareStopped = this.currentScreenShare.hadVideo;
|
|
1450
|
-
const constraints = { audio: false, video: screenshareStopped };
|
|
1451
|
-
|
|
1452
|
-
// We have to remove the video sender to be able to re-upgrade to video in `sendReinvite` below
|
|
1453
|
-
this._downgradeToAudio(targetCallSession, false);
|
|
1454
|
-
// Wait for the track to be removed, unless the video sender won't have a null track in `_upgradeToVideo`.
|
|
1455
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
1456
|
-
|
|
1457
|
-
reinvited = await this.sendReinvite(targetCallSession, constraints, conference);
|
|
1458
|
-
}
|
|
1459
|
-
} catch (e) {
|
|
1460
|
-
console.warn(e);
|
|
1461
|
-
}
|
|
1462
|
-
|
|
1463
|
-
const sipSession = this.currentSipSession;
|
|
1464
|
-
|
|
1465
|
-
this.eventEmitter.emit(
|
|
1466
|
-
ON_SHARE_SCREEN_ENDED,
|
|
1467
|
-
callSession ? this._createCallSession(sipSession, callSession, { screensharing: false }) : null,
|
|
1468
|
-
);
|
|
1469
|
-
|
|
1470
|
-
this.currentScreenShare = null;
|
|
1471
|
-
|
|
1472
|
-
return reinvited;
|
|
1473
|
-
}
|
|
1474
|
-
|
|
1475
|
-
_onScreenSharing(screenStream ,
|
|
1476
|
-
sipSession ,
|
|
1477
|
-
callSession ,
|
|
1478
|
-
hadVideo ,
|
|
1479
|
-
desktop = false) {
|
|
1480
|
-
const screenTrack = screenStream.getVideoTracks()[0];
|
|
1481
|
-
const sipSessionId = this.getSipSessionId(sipSession);
|
|
1482
|
-
const pc = this.client.getPeerConnection(sipSessionId);
|
|
1483
|
-
const sender = pc && pc.getSenders && pc.getSenders().find(s => s && s.track && s.track.kind === 'video');
|
|
1484
|
-
|
|
1485
|
-
logger.info('WebRTC phone - on screensharing', {
|
|
1486
|
-
hadVideo,
|
|
1487
|
-
id: this.getSipSessionId(sipSession),
|
|
1488
|
-
screenTrack,
|
|
1489
|
-
});
|
|
1490
|
-
|
|
1491
|
-
if (screenTrack) {
|
|
1492
|
-
screenTrack.onended = () => {
|
|
1493
|
-
logger.info('WebRTC phone - on screenshare ended', {
|
|
1494
|
-
hadVideo,
|
|
1495
|
-
id: this.getSipSessionId(sipSession),
|
|
1496
|
-
screenTrack,
|
|
1497
|
-
});
|
|
1498
|
-
|
|
1499
|
-
this.eventEmitter.emit(
|
|
1500
|
-
ON_SHARE_SCREEN_ENDING,
|
|
1501
|
-
this._createCallSession(sipSession, callSession),
|
|
1502
|
-
);
|
|
1503
|
-
};
|
|
1504
|
-
}
|
|
1505
|
-
|
|
1506
|
-
this.currentScreenShare = {
|
|
1507
|
-
stream: screenStream,
|
|
1508
|
-
hadVideo,
|
|
1509
|
-
sender,
|
|
1510
|
-
sipSessionId,
|
|
1511
|
-
desktop,
|
|
1512
|
-
};
|
|
1513
|
-
|
|
1514
|
-
this.client.setLocalMediaStream(this.getSipSessionId(sipSession), screenStream);
|
|
1515
|
-
|
|
1516
|
-
this.eventEmitter.emit(
|
|
1517
|
-
ON_SHARE_SCREEN_STARTED,
|
|
1518
|
-
this._createCallSession(sipSession, callSession, { screensharing: true }),
|
|
1519
|
-
screenStream,
|
|
1520
|
-
);
|
|
1521
|
-
}
|
|
1522
|
-
|
|
1523
|
-
_onCallAccepted(sipSession , cameraEnabled ) {
|
|
1524
|
-
logger.info('WebRTC phone - on call accepted', { sipId: sipSession.id, cameraEnabled });
|
|
1525
|
-
|
|
1526
|
-
const callSession = this._createAcceptedCallSession(sipSession, cameraEnabled);
|
|
1527
|
-
this.currentSipSession = sipSession;
|
|
1528
|
-
this.currentCallSession = callSession;
|
|
1529
|
-
|
|
1530
|
-
this.eventEmitter.emit(ON_TERMINATE_SOUND, callSession, 'call accepted');
|
|
1531
|
-
const sipSessionId = this.getSipSessionId(sipSession);
|
|
1532
|
-
if (sipSessionId) {
|
|
1533
|
-
this.removeIncomingSessions(sipSessionId);
|
|
1534
|
-
}
|
|
1535
|
-
|
|
1536
|
-
callSession.answerTime = new Date();
|
|
1537
|
-
this._updateCallSession(callSession);
|
|
1538
|
-
this.eventEmitter.emit(ON_CALL_ACCEPTED, callSession, cameraEnabled);
|
|
1539
|
-
|
|
1540
|
-
return callSession;
|
|
1541
|
-
}
|
|
1542
|
-
|
|
1543
|
-
changeAudioDevice(id ) {
|
|
1544
|
-
logger.info('WebRTC phone - change audio device', { deviceId: id });
|
|
1545
|
-
this.audioOutputDeviceId = id;
|
|
1546
|
-
this.client.changeAudioOutputDevice(id);
|
|
1547
|
-
}
|
|
1548
|
-
|
|
1549
|
-
createAudioElementFor(sessionId ) {
|
|
1550
|
-
return this.client.createAudioElementFor(sessionId);
|
|
1551
|
-
}
|
|
1552
|
-
|
|
1553
|
-
changeRingDevice(id ) {
|
|
1554
|
-
logger.info('WebRTC phone - changing ring device', { id });
|
|
1555
|
-
|
|
1556
|
-
this.audioRingDeviceId = id;
|
|
1557
|
-
}
|
|
1558
|
-
|
|
1559
|
-
// volume is a value between 0 and 1
|
|
1560
|
-
changeAudioVolume(volume ) {
|
|
1561
|
-
logger.info('WebRTC phone - changing audio volume', { volume });
|
|
1562
|
-
|
|
1563
|
-
this.audioOutputVolume = volume;
|
|
1564
|
-
this.client.changeAudioOutputVolume(volume);
|
|
1565
|
-
}
|
|
1566
|
-
|
|
1567
|
-
// volume is a value between 0 and 1
|
|
1568
|
-
changeRingVolume(volume ) {
|
|
1569
|
-
logger.info('WebRTC phone - changing ring volume', { volume });
|
|
1570
|
-
|
|
1571
|
-
this.audioRingVolume = volume;
|
|
1572
|
-
}
|
|
1573
|
-
|
|
1574
|
-
changeAudioInputDevice(id , force ) {
|
|
1575
|
-
logger.info('WebRTC phone - changeAudio input device', { deviceId: id });
|
|
1576
|
-
|
|
1577
|
-
return this.client.changeAudioInputDevice(id, this.currentSipSession, force);
|
|
1578
|
-
}
|
|
1579
|
-
|
|
1580
|
-
changeVideoInputDevice(id ) {
|
|
1581
|
-
logger.info('WebRTC phone - change video input device', { deviceId: id });
|
|
1582
|
-
|
|
1583
|
-
return this.client.changeVideoInputDevice(id, this.currentSipSession);
|
|
1584
|
-
}
|
|
1585
|
-
|
|
1586
|
-
changeSessionVideoInputDevice(id ) {
|
|
1587
|
-
logger.info('WebRTC phone - change session video input device', { deviceId: id });
|
|
1588
|
-
|
|
1589
|
-
return this.client.changeSessionVideoInputDevice(id, this.currentSipSession);
|
|
1590
|
-
}
|
|
1591
|
-
|
|
1592
|
-
_onCallTerminated(sipSession ) {
|
|
1593
|
-
logger.info('WebRTC phone - on call terminated', { sipId: sipSession.id });
|
|
1594
|
-
|
|
1595
|
-
const sipSessionId = this.getSipSessionId(sipSession);
|
|
1596
|
-
const callSession = this._createCallSession(sipSession);
|
|
1597
|
-
const isCurrentSession = this.isCurrentCallSipSession(callSession);
|
|
1598
|
-
const isCurrentIncomingCall = callSession.is(this.getIncomingCallSession());
|
|
1599
|
-
|
|
1600
|
-
// If the terminated call was an incoming call, we have to re-trigger if it's was the first incoming call
|
|
1601
|
-
// Otherwise, we have to re-trigger an incoming call event if another call is incoming
|
|
1602
|
-
const shouldRetrigger = isCurrentSession ? this.incomingSessions.length : isCurrentIncomingCall;
|
|
1603
|
-
|
|
1604
|
-
// Terminate incoming sound only for the ringing call
|
|
1605
|
-
// (so another terminated call won't stop the incoming call sound)
|
|
1606
|
-
if (isCurrentIncomingCall) {
|
|
1607
|
-
setTimeout(() => {
|
|
1608
|
-
// Avoid race condition when the other is calling and hanging up immediately
|
|
1609
|
-
this.eventEmitter.emit(ON_TERMINATE_SOUND, callSession, 'call terminated');
|
|
1610
|
-
}, 5);
|
|
1611
|
-
}
|
|
1612
|
-
|
|
1613
|
-
if (sipSessionId) {
|
|
1614
|
-
this.removeIncomingSessions(sipSessionId);
|
|
1615
|
-
}
|
|
1616
|
-
|
|
1617
|
-
delete this.callSessions[callSession.getId()];
|
|
1618
|
-
|
|
1619
|
-
if (isCurrentSession) {
|
|
1620
|
-
this.currentSipSession = undefined;
|
|
1621
|
-
this.currentCallSession = undefined;
|
|
1622
|
-
}
|
|
1623
|
-
|
|
1624
|
-
const hasIncomingCallSession = this.hasIncomingCallSession();
|
|
1625
|
-
|
|
1626
|
-
// Re-trigger incoming call event for remaining incoming calls
|
|
1627
|
-
logger.info('WebRTC phone - check to re-trigger incoming call', {
|
|
1628
|
-
sipId: sipSession.id,
|
|
1629
|
-
shouldRetrigger,
|
|
1630
|
-
hasIncomingCallSession,
|
|
1631
|
-
});
|
|
1632
|
-
|
|
1633
|
-
this.client.onCallEnded(sipSession);
|
|
1634
|
-
|
|
1635
|
-
if (hasIncomingCallSession && shouldRetrigger) {
|
|
1636
|
-
const nextCallSession = this.getIncomingCallSession();
|
|
1637
|
-
// Avoid race condition
|
|
1638
|
-
setTimeout(() => {
|
|
1639
|
-
if (this.ringingEnabled) {
|
|
1640
|
-
if (!this.currentCallSession) {
|
|
1641
|
-
this.eventEmitter.emit(ON_PLAY_RING_SOUND, this.audioRingDeviceId, this.audioRingVolume, nextCallSession);
|
|
1642
|
-
} else {
|
|
1643
|
-
this.eventEmitter.emit(ON_PLAY_INBOUND_CALL_SIGNAL_SOUND,
|
|
1644
|
-
this.audioOutputDeviceId,
|
|
1645
|
-
this.audioOutputVolume,
|
|
1646
|
-
nextCallSession);
|
|
1647
|
-
}
|
|
1648
|
-
}
|
|
1649
|
-
|
|
1650
|
-
// $FlowFixMe
|
|
1651
|
-
this.eventEmitter.emit(ON_CALL_INCOMING, nextCallSession, nextCallSession.cameraEnabled);
|
|
1652
|
-
}, 100);
|
|
1653
|
-
}
|
|
1654
|
-
|
|
1655
|
-
if (callSession.getId() in this.ignoredSessions) {
|
|
1656
|
-
return;
|
|
1657
|
-
}
|
|
1658
|
-
|
|
1659
|
-
if (!sipSession.isCanceled) {
|
|
1660
|
-
setTimeout(() => {
|
|
1661
|
-
this.eventEmitter.emit(ON_PLAY_HANGUP_SOUND, this.audioOutputDeviceId, this.audioOutputVolume, callSession);
|
|
1662
|
-
}, 10);
|
|
1663
|
-
}
|
|
1664
|
-
|
|
1665
|
-
return isCurrentSession;
|
|
1666
|
-
}
|
|
1667
|
-
|
|
1668
|
-
setActiveSipSession(callSession ) {
|
|
1669
|
-
const sipSessionId = this.findSipSession(callSession);
|
|
1670
|
-
if (!sipSessionId) {
|
|
1671
|
-
return;
|
|
1672
|
-
}
|
|
1673
|
-
|
|
1674
|
-
this.currentSipSession = sipSessionId;
|
|
1675
|
-
this.currentCallSession = callSession;
|
|
1676
|
-
}
|
|
1677
|
-
|
|
1678
|
-
hasAnActiveCall() {
|
|
1679
|
-
return !!this.currentSipSession;
|
|
1680
|
-
}
|
|
1681
|
-
|
|
1682
|
-
// /!\ In some case with react-native webrtc the session will have only one audio stream set
|
|
1683
|
-
// Maybe due to https://github.com/react-native-webrtc/react-native-webrtc/issues/401
|
|
1684
|
-
hasActiveRemoteVideoStream() {
|
|
1685
|
-
const sipSession = this.currentSipSession;
|
|
1686
|
-
if (!sipSession) {
|
|
1687
|
-
return false;
|
|
1688
|
-
}
|
|
1689
|
-
|
|
1690
|
-
const { peerConnection } = sipSession.sessionDescriptionHandler;
|
|
1691
|
-
const remoteStream = peerConnection.getRemoteStreams().find(stream => !!stream.getVideoTracks().length);
|
|
1692
|
-
|
|
1693
|
-
return remoteStream && remoteStream.getVideoTracks().some(track => !track.muted);
|
|
1694
|
-
}
|
|
1695
|
-
|
|
1696
|
-
callCount() {
|
|
1697
|
-
return Object.keys(this.callSessions).length;
|
|
1698
|
-
}
|
|
1699
|
-
|
|
1700
|
-
isCurrentCallSipSession(callSession ) {
|
|
1701
|
-
if (!this.currentSipSession) {
|
|
1702
|
-
return false;
|
|
1703
|
-
}
|
|
1704
|
-
|
|
1705
|
-
return this.currentSipSession && this.getSipSessionId(this.currentSipSession) === callSession.getId();
|
|
1706
|
-
}
|
|
1707
|
-
|
|
1708
|
-
hasVideo(callSession ) {
|
|
1709
|
-
return this.client.hasVideo(callSession.getId());
|
|
1710
|
-
}
|
|
1711
|
-
|
|
1712
|
-
hasAVideoTrack(callSession ) {
|
|
1713
|
-
return this.client.hasAVideoTrack(callSession.getId());
|
|
1714
|
-
}
|
|
1715
|
-
|
|
1716
|
-
// Deprecated
|
|
1717
|
-
getLocalStreamForCall(callSession ) {
|
|
1718
|
-
logger.warn('WebRTCPhone.getLocalStreamForCall is deprecated, use WebRTCPhone.getLocalStream instead');
|
|
1719
|
-
|
|
1720
|
-
return this.getLocalStream(callSession);
|
|
1721
|
-
}
|
|
1722
|
-
|
|
1723
|
-
// Deprecated
|
|
1724
|
-
getRemoteStreamForCall(callSession ) {
|
|
1725
|
-
logger.warn('WebRTCPhone.getRemoteStreamForCall is deprecated, use WebRTCPhone.getRemoteStream instead');
|
|
1726
|
-
|
|
1727
|
-
return this.getRemoteVideoStream(callSession);
|
|
1728
|
-
}
|
|
1729
|
-
|
|
1730
|
-
getRemoteStreamsForCall(callSession ) {
|
|
1731
|
-
logger.warn('WebRTCPhone.getRemoteStreamsForCall is deprecated, use WebRTCPhone.getRemoteStreams instead');
|
|
1732
|
-
|
|
1733
|
-
return this.getRemoteStream(callSession);
|
|
1734
|
-
}
|
|
1735
|
-
|
|
1736
|
-
accept(callSession , cameraEnabled ) {
|
|
1737
|
-
logger.info('WebRTC phone - accept call', { id: callSession ? callSession.getId() : 'n/a', cameraEnabled });
|
|
1738
|
-
if (this.currentSipSession) {
|
|
1739
|
-
this.holdSipSession(
|
|
1740
|
-
this.currentSipSession,
|
|
1741
|
-
this.currentCallSession,
|
|
1742
|
-
true,
|
|
1743
|
-
);
|
|
1744
|
-
}
|
|
1745
|
-
|
|
1746
|
-
if (!callSession) {
|
|
1747
|
-
logger.warn('no CallSession to accept.');
|
|
1748
|
-
return Promise.resolve(null);
|
|
1749
|
-
}
|
|
1750
|
-
|
|
1751
|
-
const sipSessionId = this.getSipSessionIdFromCallSession(callSession);
|
|
1752
|
-
if (sipSessionId && !(sipSessionId in this.callSessions)) {
|
|
1753
|
-
logger.warn('Call session already ended or not found, can\'t accept it.', { sipSessionId });
|
|
1754
|
-
return Promise.resolve(null);
|
|
1755
|
-
}
|
|
1756
|
-
|
|
1757
|
-
if (callSession.getId() in this.acceptedSessions) {
|
|
1758
|
-
logger.warn('CallSession already accepted.', { id: callSession ? callSession.getId() : 'n/a' });
|
|
1759
|
-
return Promise.resolve(callSession.sipCallId);
|
|
1760
|
-
}
|
|
1761
|
-
|
|
1762
|
-
this.shouldSendReinvite = false;
|
|
1763
|
-
callSession.answerTime = new Date();
|
|
1764
|
-
this._updateCallSession(callSession);
|
|
1765
|
-
this.acceptedSessions[callSession.getId()] = true;
|
|
1766
|
-
|
|
1767
|
-
this.eventEmitter.emit(ON_CALL_ANSWERED, callSession);
|
|
1768
|
-
|
|
1769
|
-
const sipSession = this.client.getSipSession(callSession.getId());
|
|
1770
|
-
if (sipSession) {
|
|
1771
|
-
if (sipSession.state === SessionState.Terminated || sipSession.state === SessionState.Terminating) {
|
|
1772
|
-
logger.warn('Trying to answer a terminated sipSession.');
|
|
1773
|
-
|
|
607
|
+
}
|
|
608
|
+
this.currentSipSession = sipSessionId;
|
|
609
|
+
this.currentCallSession = callSession;
|
|
610
|
+
}
|
|
611
|
+
hasAnActiveCall() {
|
|
612
|
+
return !!this.currentSipSession;
|
|
613
|
+
}
|
|
614
|
+
// /!\ In some case with react-native webrtc the session will have only one audio stream set
|
|
615
|
+
// Maybe due to https://github.com/react-native-webrtc/react-native-webrtc/issues/401
|
|
616
|
+
hasActiveRemoteVideoStream() {
|
|
617
|
+
const sipSession = this.currentSipSession;
|
|
618
|
+
if (!sipSession) {
|
|
619
|
+
return false;
|
|
620
|
+
}
|
|
621
|
+
const {
|
|
622
|
+
// @ts-ignore
|
|
623
|
+
peerConnection, } = sipSession.sessionDescriptionHandler;
|
|
624
|
+
const remoteStream = peerConnection.getRemoteStreams().find((stream) => !!stream.getVideoTracks().length);
|
|
625
|
+
return remoteStream && remoteStream.getVideoTracks().some(track => !track.muted);
|
|
626
|
+
}
|
|
627
|
+
callCount() {
|
|
628
|
+
return Object.keys(this.callSessions).length;
|
|
629
|
+
}
|
|
630
|
+
isCurrentCallSipSession(callSession) {
|
|
631
|
+
if (!this.currentSipSession) {
|
|
632
|
+
return false;
|
|
633
|
+
}
|
|
634
|
+
return this.currentSipSession && this.getSipSessionId(this.currentSipSession) === callSession.getId();
|
|
635
|
+
}
|
|
636
|
+
hasVideo(callSession) {
|
|
637
|
+
return this.client.hasVideo(callSession.getId());
|
|
638
|
+
}
|
|
639
|
+
hasAVideoTrack(callSession) {
|
|
640
|
+
return this.client.hasAVideoTrack(callSession.getId());
|
|
641
|
+
}
|
|
642
|
+
// Deprecated
|
|
643
|
+
getLocalStreamForCall(callSession) {
|
|
644
|
+
logger.warn('WebRTCPhone.getLocalStreamForCall is deprecated, use WebRTCPhone.getLocalStream instead');
|
|
645
|
+
return this.getLocalStream(callSession);
|
|
646
|
+
}
|
|
647
|
+
// Deprecated
|
|
648
|
+
getRemoteStreamForCall(callSession) {
|
|
649
|
+
logger.warn('WebRTCPhone.getRemoteStreamForCall is deprecated, use WebRTCPhone.getRemoteStream instead');
|
|
650
|
+
return this.getRemoteVideoStream(callSession);
|
|
651
|
+
}
|
|
652
|
+
getRemoteStreamsForCall(callSession) {
|
|
653
|
+
logger.warn('WebRTCPhone.getRemoteStreamsForCall is deprecated, use WebRTCPhone.getRemoteStreams instead');
|
|
654
|
+
return this.getRemoteStream(callSession);
|
|
655
|
+
}
|
|
656
|
+
accept(callSession, cameraEnabled) {
|
|
657
|
+
logger.info('WebRTC phone - accept call', {
|
|
658
|
+
id: callSession ? callSession.getId() : 'n/a',
|
|
659
|
+
cameraEnabled,
|
|
660
|
+
});
|
|
661
|
+
if (this.currentSipSession) {
|
|
662
|
+
this.holdSipSession(this.currentSipSession, this.currentCallSession, true);
|
|
663
|
+
}
|
|
664
|
+
if (!callSession) {
|
|
665
|
+
logger.warn('no CallSession to accept.');
|
|
666
|
+
return Promise.resolve(null);
|
|
667
|
+
}
|
|
668
|
+
const sipSessionId = this.getSipSessionIdFromCallSession(callSession);
|
|
669
|
+
if (sipSessionId && !(sipSessionId in this.callSessions)) {
|
|
670
|
+
logger.warn('Call session already ended or not found, can\'t accept it.', {
|
|
671
|
+
sipSessionId,
|
|
672
|
+
});
|
|
673
|
+
return Promise.resolve(null);
|
|
674
|
+
}
|
|
675
|
+
if (callSession.getId() in this.acceptedSessions) {
|
|
676
|
+
logger.warn('CallSession already accepted.', {
|
|
677
|
+
id: callSession ? callSession.getId() : 'n/a',
|
|
678
|
+
});
|
|
679
|
+
return Promise.resolve(callSession.sipCallId);
|
|
680
|
+
}
|
|
681
|
+
this.shouldSendReinvite = false;
|
|
682
|
+
callSession.answerTime = new Date();
|
|
683
|
+
this._updateCallSession(callSession);
|
|
684
|
+
this.acceptedSessions[callSession.getId()] = true;
|
|
685
|
+
this.eventEmitter.emit(ON_CALL_ANSWERED, callSession);
|
|
686
|
+
const sipSession = this.client.getSipSession(callSession.getId());
|
|
687
|
+
if (sipSession) {
|
|
688
|
+
if (sipSession.state === SessionState.Terminated || sipSession.state === SessionState.Terminating) {
|
|
689
|
+
logger.warn('Trying to answer a terminated sipSession.');
|
|
690
|
+
return Promise.resolve(null);
|
|
691
|
+
}
|
|
692
|
+
logger.info('accept call, session found', {
|
|
693
|
+
sipId: sipSession.id,
|
|
694
|
+
});
|
|
695
|
+
return this.client.answer(sipSession, this.allowVideo ? cameraEnabled : false).then(() => {
|
|
696
|
+
return callSession.sipCallId;
|
|
697
|
+
}).catch(e => {
|
|
698
|
+
logger.error(e);
|
|
699
|
+
this.endCurrentCall(callSession);
|
|
700
|
+
throw e;
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
logger.warn('no CallSession found to accept.', {
|
|
704
|
+
id: callSession ? callSession.getId() : 'n/a',
|
|
705
|
+
});
|
|
1774
706
|
return Promise.resolve(null);
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
}
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
callSession
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
}
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
}
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
this.
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
}
|
|
2172
|
-
}
|
|
2173
|
-
|
|
2174
|
-
this.shouldSendReinvite = false;
|
|
2175
|
-
return true;
|
|
2176
|
-
}
|
|
2177
|
-
|
|
2178
|
-
async getStats(callSession ) {
|
|
2179
|
-
const sipSession = this.findSipSession(callSession);
|
|
2180
|
-
|
|
2181
|
-
return sipSession ? this.client.getStats(sipSession) : null;
|
|
2182
|
-
}
|
|
2183
|
-
|
|
2184
|
-
startNetworkMonitoring(callSession , interval = 1000) {
|
|
2185
|
-
const sipSession = this.findSipSession(callSession);
|
|
2186
|
-
|
|
2187
|
-
return sipSession ? this.client.startNetworkMonitoring(sipSession, interval) : null;
|
|
2188
|
-
}
|
|
2189
|
-
|
|
2190
|
-
stopNetworkMonitoring(callSession ) {
|
|
2191
|
-
const sipSession = this.findSipSession(callSession);
|
|
2192
|
-
|
|
2193
|
-
return sipSession ? this.client.stopNetworkMonitoring(sipSession) : null;
|
|
2194
|
-
}
|
|
2195
|
-
|
|
2196
|
-
forceCancel(sipSession ) {
|
|
2197
|
-
if (!sipSession || !sipSession.outgoingInviteRequest) {
|
|
2198
|
-
return;
|
|
2199
|
-
}
|
|
2200
|
-
sipSession.outgoingInviteRequest.cancel();
|
|
2201
|
-
}
|
|
2202
|
-
|
|
2203
|
-
endCurrentCall(callSession ) {
|
|
2204
|
-
const isCurrent = this.isCurrentCallSipSession(callSession);
|
|
2205
|
-
|
|
2206
|
-
logger.info('Ending current call', {
|
|
2207
|
-
id: callSession ? callSession.getId() : null,
|
|
2208
|
-
isCurrent,
|
|
2209
|
-
});
|
|
2210
|
-
|
|
2211
|
-
if (isCurrent) {
|
|
2212
|
-
this.currentSipSession = undefined;
|
|
2213
|
-
this.currentCallSession = null;
|
|
2214
|
-
}
|
|
2215
|
-
|
|
2216
|
-
this.eventEmitter.emit(ON_TERMINATE_SOUND, callSession, 'locally ended');
|
|
2217
|
-
}
|
|
2218
|
-
|
|
2219
|
-
onConnectionMade() {}
|
|
2220
|
-
|
|
2221
|
-
isConference(callSession ) {
|
|
2222
|
-
if (!callSession) {
|
|
2223
|
-
return false;
|
|
2224
|
-
}
|
|
2225
|
-
|
|
2226
|
-
return this.client && this.client.isConference(callSession.sipCallId);
|
|
2227
|
-
}
|
|
2228
|
-
|
|
2229
|
-
async close(force = false) {
|
|
2230
|
-
logger.info('WebRTC close');
|
|
2231
|
-
|
|
2232
|
-
try {
|
|
2233
|
-
await Promise.race([
|
|
2234
|
-
this.unregister(),
|
|
2235
|
-
new Promise((resolve, reject) => setTimeout(() => reject(new Error('Unregister, timed out')), 3000)),
|
|
2236
|
-
]);
|
|
2237
|
-
} catch (e) {
|
|
2238
|
-
logger.error('WebRTC close, unregister error', e);
|
|
2239
|
-
}
|
|
2240
|
-
|
|
2241
|
-
this.client.close(force);
|
|
2242
|
-
this.unbind();
|
|
2243
|
-
|
|
2244
|
-
this.incomingSessions = [];
|
|
2245
|
-
this.currentSipSession = null;
|
|
2246
|
-
this.currentCallSession = null;
|
|
2247
|
-
this.shouldSendReinvite = false;
|
|
2248
|
-
this.rejectedSessions = {};
|
|
2249
|
-
}
|
|
2250
|
-
|
|
2251
|
-
isRegistered() {
|
|
2252
|
-
return this.client && this.client.isRegistered();
|
|
2253
|
-
}
|
|
2254
|
-
|
|
2255
|
-
enableRinging() {
|
|
2256
|
-
logger.info('WebRTC enable ringing');
|
|
2257
|
-
this.ringingEnabled = true;
|
|
2258
|
-
}
|
|
2259
|
-
|
|
2260
|
-
disableRinging() {
|
|
2261
|
-
logger.info('WebRTC disable ringing');
|
|
2262
|
-
this.ringingEnabled = false;
|
|
2263
|
-
}
|
|
2264
|
-
|
|
2265
|
-
getCurrentCallSession() {
|
|
2266
|
-
if (!this.currentSipSession) {
|
|
2267
|
-
return null;
|
|
2268
|
-
}
|
|
2269
|
-
|
|
2270
|
-
return this._createCallSession(this.currentSipSession, this.currentCallSession);
|
|
2271
|
-
}
|
|
2272
|
-
|
|
2273
|
-
hasIncomingCallSession() {
|
|
2274
|
-
return this.incomingSessions.length > 0;
|
|
2275
|
-
}
|
|
2276
|
-
|
|
2277
|
-
getIncomingCallSession() {
|
|
2278
|
-
if (!this.hasIncomingCallSession()) {
|
|
2279
|
-
return null;
|
|
2280
|
-
}
|
|
2281
|
-
|
|
2282
|
-
const sessionId = this.incomingSessions[0];
|
|
2283
|
-
const sipSession = this.client.getSipSession(sessionId);
|
|
2284
|
-
if (!sipSession) {
|
|
2285
|
-
return null;
|
|
2286
|
-
}
|
|
2287
|
-
|
|
2288
|
-
return this._createCallSession(sipSession);
|
|
2289
|
-
}
|
|
2290
|
-
|
|
2291
|
-
sendMessage(sipSession = null, body , contentType = 'text/plain') {
|
|
2292
|
-
return this.client.sendMessage(sipSession, body, contentType);
|
|
2293
|
-
}
|
|
2294
|
-
|
|
2295
|
-
getLocalStream(callSession ) {
|
|
2296
|
-
return callSession ? this.client.getLocalStream(callSession.sipCallId) : null;
|
|
2297
|
-
}
|
|
2298
|
-
|
|
2299
|
-
getLocalVideoStream(callSession ) {
|
|
2300
|
-
return callSession ? this.client.getLocalVideoStream(callSession.sipCallId) : null;
|
|
2301
|
-
}
|
|
2302
|
-
|
|
2303
|
-
// Deprecated
|
|
2304
|
-
getLocalMediaStream(callSession ) {
|
|
2305
|
-
logger.warn('WebRTCPhone.getLocalMediaStream is deprecated, use WebRTCPhone.getLocalStream instead');
|
|
2306
|
-
return this.getLocalStream(callSession);
|
|
2307
|
-
}
|
|
2308
|
-
|
|
2309
|
-
hasLocalVideo(callSession ) {
|
|
2310
|
-
return callSession ? this.client.hasLocalVideo(callSession.sipCallId) : null;
|
|
2311
|
-
}
|
|
2312
|
-
|
|
2313
|
-
hasALocalVideoTrack(callSession ) {
|
|
2314
|
-
return callSession ? this.client.hasALocalVideoTrack(callSession.sipCallId) : null;
|
|
2315
|
-
}
|
|
2316
|
-
|
|
2317
|
-
getRemoteStream(callSession ) {
|
|
2318
|
-
return callSession ? this.client.getRemoteStream(callSession.sipCallId) : null;
|
|
2319
|
-
}
|
|
2320
|
-
|
|
2321
|
-
getRemoteVideoStream(callSession ) {
|
|
2322
|
-
return callSession ? this.client.getRemoteVideoStream(callSession.sipCallId) : null;
|
|
2323
|
-
}
|
|
2324
|
-
|
|
2325
|
-
getRemoteVideoStreamFromPc(callSession ) {
|
|
2326
|
-
return callSession ? this.client.getRemoteVideoStreamFromPc(callSession.sipCallId) : null;
|
|
2327
|
-
}
|
|
2328
|
-
|
|
2329
|
-
hasRemoteVideo(callSession ) {
|
|
2330
|
-
return callSession ? this.client.hasRemoteVideo(callSession.sipCallId) : false;
|
|
2331
|
-
}
|
|
2332
|
-
|
|
2333
|
-
setMediaConstraints(media ) {
|
|
2334
|
-
this.client.setMediaConstraints(media);
|
|
2335
|
-
}
|
|
2336
|
-
|
|
2337
|
-
isVideoRemotelyHeld(callSession ) {
|
|
2338
|
-
return callSession ? this.client.isVideoRemotelyHeld(callSession.sipCallId) : null;
|
|
2339
|
-
}
|
|
2340
|
-
|
|
2341
|
-
bindClientEvents() {
|
|
2342
|
-
this.client.unbind();
|
|
2343
|
-
|
|
2344
|
-
this.client.on(this.client.INVITE, (sipSession , wantsToDoVideo ) => {
|
|
2345
|
-
const autoAnswer = sipSession.request.getHeader('Answer-Mode') === 'Auto';
|
|
2346
|
-
const withVideo = this.allowVideo ? wantsToDoVideo : false;
|
|
2347
|
-
logger.info('WebRTC invite received', { sipId: sipSession.id, withVideo, autoAnswer });
|
|
2348
|
-
|
|
2349
|
-
const callSession = this._createIncomingCallSession(sipSession, withVideo, null, autoAnswer);
|
|
2350
|
-
this.incomingSessions.push(callSession.getId());
|
|
2351
|
-
this._bindEvents(sipSession);
|
|
2352
|
-
|
|
2353
|
-
this.client.storeSipSession(sipSession);
|
|
2354
|
-
|
|
2355
|
-
if (!this.currentSipSession) {
|
|
2356
|
-
if (this.ringingEnabled) {
|
|
2357
|
-
this.eventEmitter.emit(ON_PLAY_RING_SOUND, this.audioRingDeviceId, this.audioRingVolume, callSession);
|
|
2358
|
-
}
|
|
2359
|
-
} else {
|
|
2360
|
-
this.eventEmitter.emit(ON_PLAY_INBOUND_CALL_SIGNAL_SOUND,
|
|
2361
|
-
this.audioOutputDeviceId,
|
|
2362
|
-
this.audioOutputVolume,
|
|
2363
|
-
callSession);
|
|
2364
|
-
}
|
|
2365
|
-
|
|
2366
|
-
callSession.creationTime = new Date();
|
|
2367
|
-
this._updateCallSession(callSession);
|
|
2368
|
-
|
|
2369
|
-
this.eventEmitter.emit(ON_CALL_INCOMING, callSession, wantsToDoVideo);
|
|
2370
|
-
});
|
|
2371
|
-
|
|
2372
|
-
this.client.on(this.client.ON_REINVITE, (...args) => {
|
|
2373
|
-
logger.info('WebRTC on reinvite', {
|
|
2374
|
-
sessionId: args[0].id,
|
|
2375
|
-
inviteId: args[1].id,
|
|
2376
|
-
updatedCalleeName: args[2],
|
|
2377
|
-
updatedNumber: args[3],
|
|
2378
|
-
});
|
|
2379
|
-
|
|
2380
|
-
const sipSession = args[0];
|
|
2381
|
-
|
|
2382
|
-
// Give some time for the stream to be mounted.
|
|
2383
|
-
// if `_createCallSession` is called too soon `hasVideo` will return false because the stream doesn't exists yet
|
|
2384
|
-
setTimeout(() => {
|
|
2385
|
-
// Update callSession
|
|
2386
|
-
this._createCallSession(sipSession, this.callSessions[this.getSipSessionId(sipSession)]);
|
|
2387
|
-
|
|
2388
|
-
this.eventEmitter.emit.apply(this.eventEmitter, [this.client.ON_REINVITE, ...args]);
|
|
2389
|
-
}, 2000);
|
|
2390
|
-
});
|
|
2391
|
-
|
|
2392
|
-
this.client.on(this.client.ACCEPTED, (sipSession ) => {
|
|
2393
|
-
const sessionId = this.getSipSessionId(sipSession);
|
|
2394
|
-
const hasSession = sessionId in this.callSessions;
|
|
2395
|
-
|
|
2396
|
-
logger.info('WebRTC call accepted', { sipId: sessionId, hasSession });
|
|
2397
|
-
|
|
2398
|
-
if (!hasSession) {
|
|
2399
|
-
logger.warn('Call accepted ignored, session is no longer present in the WebRtcPhone', { sessionId });
|
|
2400
|
-
return;
|
|
2401
|
-
}
|
|
2402
|
-
|
|
2403
|
-
this._onCallAccepted(sipSession, this.client.hasVideo(sessionId));
|
|
2404
|
-
|
|
2405
|
-
if (this.audioOutputDeviceId) {
|
|
2406
|
-
this.client.changeAudioOutputDevice(this.audioOutputDeviceId);
|
|
2407
|
-
}
|
|
2408
|
-
});
|
|
2409
|
-
this.client.on('ended', () => {});
|
|
2410
|
-
|
|
2411
|
-
this.client.on(this.client.ON_ERROR, e => {
|
|
2412
|
-
logger.error('WebRTC error', e);
|
|
2413
|
-
this.eventEmitter.emit(ON_CALL_ERROR, e);
|
|
2414
|
-
});
|
|
2415
|
-
|
|
2416
|
-
this.client.on(this.client.REJECTED, session => {
|
|
2417
|
-
logger.info('WebRTC call rejected', session.id);
|
|
2418
|
-
const callSession = this._createCallSession(session);
|
|
2419
|
-
callSession.endTime = new Date();
|
|
2420
|
-
this._updateCallSession(callSession);
|
|
2421
|
-
|
|
2422
|
-
this.eventEmitter.emit(ON_CALL_REJECTED, callSession);
|
|
2423
|
-
});
|
|
2424
|
-
|
|
2425
|
-
this.client.on(this.client.UNREGISTERED, () => {
|
|
2426
|
-
logger.info('WebRTC unregistered');
|
|
2427
|
-
this.eventEmitter.emit(ON_UNREGISTERED);
|
|
2428
|
-
});
|
|
2429
|
-
|
|
2430
|
-
this.client.on(this.client.ON_DISCONNECTED, () => {
|
|
2431
|
-
logger.info('WebRTC disconnected');
|
|
2432
|
-
this.eventEmitter.emit(ON_DISCONNECTED);
|
|
2433
|
-
});
|
|
2434
|
-
this.client.on(this.client.ON_EARLY_MEDIA, session => {
|
|
2435
|
-
logger.info('WebRTC early media');
|
|
2436
|
-
const callSession = this._createCallSession(session);
|
|
2437
|
-
this.eventEmitter.emit(ON_EARLY_MEDIA, callSession);
|
|
2438
|
-
});
|
|
2439
|
-
|
|
2440
|
-
this.client.on(this.client.REGISTERED, () => {
|
|
2441
|
-
logger.info('WebRTC registered', {
|
|
2442
|
-
shouldSendReinvite: this.shouldSendReinvite,
|
|
2443
|
-
state: this.currentSipSession ? this.currentSipSession.state : null,
|
|
2444
|
-
currentSipSession: !!this.currentSipSession,
|
|
2445
|
-
});
|
|
2446
|
-
this.stopHeartbeat();
|
|
2447
|
-
this.eventEmitter.emit(ON_REGISTERED);
|
|
2448
|
-
|
|
2449
|
-
// If the phone registered with a current callSession (eg: when switching network):
|
|
2450
|
-
// send a reinvite to renegociate ICE with new IP
|
|
2451
|
-
if (this.shouldSendReinvite && this.currentSipSession
|
|
2452
|
-
&& this.currentSipSession.state === SessionState.Established) {
|
|
707
|
+
}
|
|
708
|
+
isAccepted(callSession) {
|
|
709
|
+
return callSession && callSession.getId() in this.acceptedSessions;
|
|
710
|
+
}
|
|
711
|
+
async reject(callSession) {
|
|
712
|
+
logger.info('reject WebRTC called', {
|
|
713
|
+
id: callSession.getId(),
|
|
714
|
+
});
|
|
715
|
+
this.eventEmitter.emit(ON_TERMINATE_SOUND, callSession, 'call rejected locally');
|
|
716
|
+
if (!callSession || callSession.getId() in this.rejectedSessions) {
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
this.shouldSendReinvite = false;
|
|
720
|
+
this.rejectedSessions[callSession.getId()] = true;
|
|
721
|
+
const sipSession = this.findSipSession(callSession);
|
|
722
|
+
if (sipSession) {
|
|
723
|
+
logger.info('WebRTC rejecting', {
|
|
724
|
+
sipId: sipSession.id,
|
|
725
|
+
});
|
|
726
|
+
this.client.hangup(sipSession);
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
async ignore(callSession) {
|
|
730
|
+
logger.info('WebRTC ignore', {
|
|
731
|
+
id: callSession.getId(),
|
|
732
|
+
});
|
|
733
|
+
// kill the ring
|
|
734
|
+
this.eventEmitter.emit(ON_TERMINATE_SOUND, callSession, 'ignoring call');
|
|
735
|
+
this.ignoredSessions[callSession.getId()] = true;
|
|
736
|
+
callSession.ignore();
|
|
737
|
+
}
|
|
738
|
+
atxfer(callSession) {
|
|
739
|
+
const sipSession = this.findSipSession(callSession);
|
|
740
|
+
if (sipSession) {
|
|
741
|
+
logger.info('WebRTC atxfer', {
|
|
742
|
+
sipId: sipSession.id,
|
|
743
|
+
});
|
|
744
|
+
return this.client.atxfer(sipSession);
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
hold(callSession, withEvent = true) {
|
|
748
|
+
logger.info('WebRTC hold', {
|
|
749
|
+
id: callSession.getId(),
|
|
750
|
+
});
|
|
751
|
+
const sipSession = this.findSipSession(callSession);
|
|
752
|
+
return sipSession ? this.holdSipSession(sipSession, callSession, withEvent) : null;
|
|
753
|
+
}
|
|
754
|
+
// @Deprecated
|
|
755
|
+
unhold(callSession, withEvent = true) {
|
|
756
|
+
console.warn('Please note that `phone.unhold()` is being deprecated; `phone.resume()` is the preferred method');
|
|
757
|
+
return this.resume(callSession, withEvent);
|
|
758
|
+
}
|
|
759
|
+
resume(callSession, withEvent = true) {
|
|
760
|
+
logger.info('WebRTC resume called', {
|
|
761
|
+
id: callSession ? callSession.getId() : null,
|
|
762
|
+
});
|
|
763
|
+
const sipSession = this.findSipSession(callSession);
|
|
764
|
+
if (!sipSession) {
|
|
765
|
+
return new Promise((resolve, reject) => reject(new Error('No session to resume')));
|
|
766
|
+
}
|
|
767
|
+
logger.info('WebRTC resuming', {
|
|
768
|
+
sipId: sipSession.id,
|
|
769
|
+
});
|
|
770
|
+
// Hold current session if different from the current one (we don't want 2 sessions active at the same time).
|
|
771
|
+
if (this.currentSipSession && this.currentSipSession.id !== sipSession.id) {
|
|
772
|
+
logger.info('WebRTC hold call after resume', {
|
|
773
|
+
id: this.currentSipSession.id,
|
|
774
|
+
});
|
|
775
|
+
this.holdSipSession(this.currentSipSession, this.currentCallSession, withEvent);
|
|
776
|
+
}
|
|
777
|
+
const promise = this.unholdSipSession(sipSession, callSession, withEvent);
|
|
778
|
+
this.currentSipSession = sipSession;
|
|
779
|
+
if (callSession) {
|
|
780
|
+
this.currentCallSession = callSession;
|
|
781
|
+
}
|
|
782
|
+
return promise;
|
|
783
|
+
}
|
|
784
|
+
async holdSipSession(sipSession, callSession, withEvent = true) {
|
|
785
|
+
if (!sipSession) {
|
|
786
|
+
return new Promise((resolve, reject) => reject(new Error('No session to hold')));
|
|
787
|
+
}
|
|
788
|
+
const sessionId = this.getSipSessionId(sipSession);
|
|
789
|
+
const hasVideo = this.client.hasLocalVideo(sessionId);
|
|
790
|
+
logger.info('WebRTC hold sip session', {
|
|
791
|
+
sipId: sipSession.id,
|
|
792
|
+
hasVideo,
|
|
793
|
+
});
|
|
794
|
+
// Stop screenshare if needed
|
|
795
|
+
if (this.currentScreenShare && this.currentScreenShare.sipSessionId === sessionId) {
|
|
796
|
+
this.lastScreenShare = this.currentScreenShare;
|
|
797
|
+
await this.stopScreenSharing(false, callSession);
|
|
798
|
+
}
|
|
799
|
+
// Downgrade to audio if needed
|
|
800
|
+
if (hasVideo) {
|
|
801
|
+
await this.client.downgradeToAudio(sipSession);
|
|
802
|
+
}
|
|
803
|
+
const isConference = !!callSession && callSession.isConference();
|
|
804
|
+
const promise = this.client.hold(sipSession, isConference, hasVideo);
|
|
805
|
+
if (withEvent) {
|
|
806
|
+
this.eventEmitter.emit(ON_CALL_HELD, this._createCallSession(sipSession, callSession));
|
|
807
|
+
}
|
|
808
|
+
return promise;
|
|
809
|
+
}
|
|
810
|
+
async unholdSipSession(sipSession, callSession, withEvent = true) {
|
|
811
|
+
if (!sipSession) {
|
|
812
|
+
return new Promise((resolve, reject) => reject(new Error('No session to unhold')));
|
|
813
|
+
}
|
|
814
|
+
const isConference = !!callSession && callSession.isConference();
|
|
815
|
+
const sessionId = this.getSipSessionId(sipSession);
|
|
816
|
+
logger.info('WebRTC unhold sip session', {
|
|
817
|
+
sessionId,
|
|
818
|
+
isConference,
|
|
819
|
+
});
|
|
820
|
+
const { hasVideo, } = this.client.getHeldSession(sessionId) || {};
|
|
821
|
+
const wasScreensharing = this.lastScreenShare && this.lastScreenShare.sipSessionId === sessionId;
|
|
822
|
+
const wasDesktop = this.lastScreenShare && this.lastScreenShare.desktop;
|
|
823
|
+
const promise = this.client.unhold(sipSession, isConference);
|
|
824
|
+
if (hasVideo) {
|
|
825
|
+
const constraints = {
|
|
826
|
+
audio: false,
|
|
827
|
+
video: true,
|
|
828
|
+
screen: wasScreensharing,
|
|
829
|
+
desktop: wasDesktop,
|
|
830
|
+
};
|
|
831
|
+
await this.client.upgradeToVideo(sipSession, constraints, isConference);
|
|
832
|
+
}
|
|
833
|
+
const onScreenSharing = (stream) => {
|
|
834
|
+
const hadVideo = this.lastScreenShare && this.lastScreenShare.hadVideo;
|
|
835
|
+
if (stream) {
|
|
836
|
+
this._onScreenSharing(stream, sipSession, callSession, hadVideo);
|
|
837
|
+
}
|
|
838
|
+
this.lastScreenShare = null;
|
|
839
|
+
};
|
|
840
|
+
if (withEvent) {
|
|
841
|
+
const updatedCallSession = this._createCallSession(sipSession, callSession);
|
|
842
|
+
// Deprecated event
|
|
843
|
+
this.eventEmitter.emit(ON_CALL_UNHELD, updatedCallSession);
|
|
844
|
+
this.eventEmitter.emit(ON_CALL_RESUMED, updatedCallSession);
|
|
845
|
+
}
|
|
846
|
+
return promise.then(() => {
|
|
847
|
+
const stream = callSession ? this.getLocalVideoStream(callSession) : null;
|
|
848
|
+
if (wasScreensharing) {
|
|
849
|
+
onScreenSharing(stream);
|
|
850
|
+
}
|
|
851
|
+
return stream;
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
mute(callSession, withEvent = true) {
|
|
855
|
+
logger.info('WebRTC mute called', {
|
|
856
|
+
id: callSession ? callSession.getId() : null,
|
|
857
|
+
});
|
|
858
|
+
const sipSession = this.findSipSession(callSession);
|
|
859
|
+
if (!sipSession) {
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
862
|
+
logger.info('WebRTC muting', {
|
|
863
|
+
sipId: sipSession.id,
|
|
864
|
+
});
|
|
865
|
+
this.client.mute(sipSession);
|
|
866
|
+
const newCallSession = this._createCallSession(sipSession, callSession, {
|
|
867
|
+
muted: true,
|
|
868
|
+
});
|
|
869
|
+
if (this.currentCallSession && newCallSession.is(this.currentCallSession)) {
|
|
870
|
+
this.currentCallSession = newCallSession;
|
|
871
|
+
}
|
|
872
|
+
if (withEvent) {
|
|
873
|
+
this.eventEmitter.emit(ON_CALL_MUTED, newCallSession);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
unmute(callSession, withEvent = true) {
|
|
877
|
+
logger.info('WebRTC unmute called', {
|
|
878
|
+
id: callSession ? callSession.getId() : null,
|
|
879
|
+
});
|
|
880
|
+
const sipSession = this.findSipSession(callSession);
|
|
881
|
+
if (!sipSession) {
|
|
882
|
+
return;
|
|
883
|
+
}
|
|
884
|
+
logger.info('WebRTC unmuting', {
|
|
885
|
+
sipId: sipSession.id,
|
|
886
|
+
});
|
|
887
|
+
this.client.unmute(sipSession);
|
|
888
|
+
const newCallSession = this._createCallSession(sipSession, callSession, {
|
|
889
|
+
muted: false,
|
|
890
|
+
});
|
|
891
|
+
if (this.currentCallSession && newCallSession.is(this.currentCallSession)) {
|
|
892
|
+
this.currentCallSession = newCallSession;
|
|
893
|
+
}
|
|
894
|
+
if (withEvent) {
|
|
895
|
+
this.eventEmitter.emit(ON_CALL_UNMUTED, newCallSession);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
isAudioMuted(callSession) {
|
|
899
|
+
const sipSession = this.findSipSession(callSession);
|
|
900
|
+
if (!sipSession) {
|
|
901
|
+
return true;
|
|
902
|
+
}
|
|
903
|
+
return this.client.isAudioMuted(sipSession);
|
|
904
|
+
}
|
|
905
|
+
turnCameraOn(callSession) {
|
|
906
|
+
const sipSession = this.findSipSession(callSession);
|
|
907
|
+
if (!sipSession) {
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
logger.info('WebRTC turn camera on', {
|
|
911
|
+
sipId: sipSession.id,
|
|
912
|
+
});
|
|
913
|
+
this.client.toggleCameraOn(sipSession);
|
|
914
|
+
this.eventEmitter.emit(ON_CAMERA_RESUMED, this._createCameraResumedCallSession(sipSession, callSession));
|
|
915
|
+
}
|
|
916
|
+
turnCameraOff(callSession) {
|
|
917
|
+
const sipSession = this.findSipSession(callSession);
|
|
918
|
+
if (!sipSession) {
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
921
|
+
logger.info('WebRTC turn camera off', {
|
|
922
|
+
sipId: sipSession.id,
|
|
923
|
+
});
|
|
924
|
+
this.client.toggleCameraOff(sipSession);
|
|
925
|
+
this.eventEmitter.emit(ON_CAMERA_DISABLED, this._createCameraDisabledCallSession(sipSession, callSession));
|
|
926
|
+
}
|
|
927
|
+
sendKey(callSession, tone) {
|
|
928
|
+
const sipSession = this.findSipSession(callSession);
|
|
929
|
+
if (!sipSession) {
|
|
930
|
+
return;
|
|
931
|
+
}
|
|
932
|
+
logger.info('WebRTC send key', {
|
|
933
|
+
sipId: sipSession.id,
|
|
934
|
+
tone,
|
|
935
|
+
});
|
|
936
|
+
this.client.sendDTMF(sipSession, tone);
|
|
937
|
+
}
|
|
938
|
+
// Should be async to match CTIPhone definition
|
|
939
|
+
// @TODO: line is not used here
|
|
940
|
+
async makeCall(number, line, cameraEnabled, audioOnly = false, conference = false) {
|
|
941
|
+
logger.info('make WebRTC call', {
|
|
942
|
+
number,
|
|
943
|
+
lineId: line ? line.id : null,
|
|
944
|
+
cameraEnabled,
|
|
945
|
+
audioOnly,
|
|
946
|
+
conference,
|
|
947
|
+
});
|
|
948
|
+
if (!number) {
|
|
949
|
+
return Promise.resolve(null);
|
|
950
|
+
}
|
|
951
|
+
if (!this.client.isRegistered()) {
|
|
952
|
+
await this.client.register();
|
|
953
|
+
}
|
|
954
|
+
if (this.currentSipSession) {
|
|
955
|
+
this.holdSipSession(this.currentSipSession, this.currentCallSession, true).catch(e => {
|
|
956
|
+
logger.warn('Unable to hold current session when making another call', e);
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
let sipSession;
|
|
960
|
+
try {
|
|
961
|
+
sipSession = this.client.call(number, this.allowVideo ? cameraEnabled : false, audioOnly, conference);
|
|
962
|
+
this._bindEvents(sipSession);
|
|
963
|
+
}
|
|
964
|
+
catch (error) {
|
|
965
|
+
console.warn(error);
|
|
966
|
+
logger.warn('make WebRTC call, error', {
|
|
967
|
+
message: error.message,
|
|
968
|
+
stack: error.stack,
|
|
969
|
+
});
|
|
970
|
+
return Promise.resolve(null);
|
|
971
|
+
}
|
|
972
|
+
const callSession = this._createOutgoingCallSession(sipSession, cameraEnabled || false);
|
|
973
|
+
callSession.setIsConference(conference);
|
|
974
|
+
callSession.creationTime = new Date();
|
|
975
|
+
this._updateCallSession(callSession);
|
|
976
|
+
this.eventEmitter.emit(ON_PLAY_PROGRESS_SOUND, this.audioOutputDeviceId, this.audioOutputVolume);
|
|
977
|
+
this.currentSipSession = sipSession;
|
|
978
|
+
this.currentCallSession = callSession;
|
|
979
|
+
this.eventEmitter.emit(ON_CALL_OUTGOING, callSession);
|
|
980
|
+
// If an invite promise exists, catch exceptions on it to trigger error like OverConstraintsError.
|
|
981
|
+
// @ts-ignore
|
|
982
|
+
if (sipSession.invitePromise) {
|
|
983
|
+
// @ts-ignore
|
|
984
|
+
sipSession.invitePromise.catch(error => {
|
|
985
|
+
this.eventEmitter.emit(ON_CALL_ERROR, error, callSession);
|
|
986
|
+
});
|
|
987
|
+
}
|
|
988
|
+
return Promise.resolve(callSession);
|
|
989
|
+
}
|
|
990
|
+
transfer(callSession, target) {
|
|
991
|
+
const sipSession = this.findSipSession(callSession);
|
|
992
|
+
if (!sipSession) {
|
|
993
|
+
return;
|
|
994
|
+
}
|
|
995
|
+
logger.info('WebRTC transfer', {
|
|
996
|
+
sipId: sipSession.id,
|
|
997
|
+
target,
|
|
998
|
+
});
|
|
999
|
+
this.client.transfer(sipSession, target);
|
|
1000
|
+
}
|
|
1001
|
+
async indirectTransfer(source, destination) {
|
|
1002
|
+
const sipSession = this.client.getSipSession(source.sipCallId);
|
|
1003
|
+
const sipSessionTarget = this.client.getSipSession(destination.sipCallId);
|
|
1004
|
+
logger.info('WebRTC indirect transfer', {
|
|
1005
|
+
sipId: sipSession ? sipSession.id : null,
|
|
1006
|
+
target: sipSessionTarget ? sipSessionTarget.id : null,
|
|
1007
|
+
});
|
|
1008
|
+
if (!sipSessionTarget) {
|
|
1009
|
+
return Promise.reject();
|
|
1010
|
+
}
|
|
1011
|
+
return new Promise(resolve => {
|
|
1012
|
+
const options = {
|
|
1013
|
+
requestDelegate: {
|
|
1014
|
+
onAccept: () => {
|
|
1015
|
+
// Wait a little so the REFER will take effect
|
|
1016
|
+
setTimeout(() => {
|
|
1017
|
+
this.hangup(destination).then(resolve);
|
|
1018
|
+
}, 200);
|
|
1019
|
+
},
|
|
1020
|
+
},
|
|
1021
|
+
};
|
|
1022
|
+
return sipSessionTarget.refer(sipSession, options);
|
|
1023
|
+
});
|
|
1024
|
+
}
|
|
1025
|
+
initiateCTIIndirectTransfer() { }
|
|
1026
|
+
cancelCTIIndirectTransfer() { }
|
|
1027
|
+
confirmCTIIndirectTransfer() { }
|
|
1028
|
+
async hangup(callSession) {
|
|
1029
|
+
const sipSession = this.findSipSession(callSession);
|
|
1030
|
+
if (!sipSession) {
|
|
1031
|
+
console.error('Call is unknown to the WebRTC phone', callSession ? callSession.sipCallId : null, callSession ? callSession.callId : null);
|
|
1032
|
+
return false;
|
|
1033
|
+
}
|
|
1034
|
+
logger.info('WebRTC hangup', {
|
|
1035
|
+
sipId: sipSession.id,
|
|
1036
|
+
});
|
|
1037
|
+
const sipSessionId = this.getSipSessionId(sipSession);
|
|
1038
|
+
await this.client.hangup(sipSession);
|
|
1039
|
+
if (callSession) {
|
|
1040
|
+
// Removal of `this.callSessions` will be done in `_onCallTerminated`.
|
|
1041
|
+
this.endCurrentCall(callSession);
|
|
1042
|
+
}
|
|
1043
|
+
else if (sipSessionId) {
|
|
1044
|
+
if (callSession) {
|
|
1045
|
+
delete this.callSessions[sipSessionId];
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
this.shouldSendReinvite = false;
|
|
1049
|
+
return true;
|
|
1050
|
+
}
|
|
1051
|
+
async getStats(callSession) {
|
|
1052
|
+
const sipSession = this.findSipSession(callSession);
|
|
1053
|
+
return sipSession ? this.client.getStats(sipSession) : null;
|
|
1054
|
+
}
|
|
1055
|
+
startNetworkMonitoring(callSession, interval = 1000) {
|
|
1056
|
+
const sipSession = this.findSipSession(callSession);
|
|
1057
|
+
return sipSession ? this.client.startNetworkMonitoring(sipSession, interval) : null;
|
|
1058
|
+
}
|
|
1059
|
+
stopNetworkMonitoring(callSession) {
|
|
1060
|
+
const sipSession = this.findSipSession(callSession);
|
|
1061
|
+
return sipSession ? this.client.stopNetworkMonitoring(sipSession) : null;
|
|
1062
|
+
}
|
|
1063
|
+
forceCancel(sipSession) {
|
|
1064
|
+
// @ts-ignore
|
|
1065
|
+
if (!sipSession || !sipSession.outgoingInviteRequest) {
|
|
1066
|
+
return;
|
|
1067
|
+
}
|
|
1068
|
+
// @ts-ignore
|
|
1069
|
+
sipSession.outgoingInviteRequest.cancel();
|
|
1070
|
+
}
|
|
1071
|
+
endCurrentCall(callSession) {
|
|
1072
|
+
const isCurrent = this.isCurrentCallSipSession(callSession);
|
|
1073
|
+
logger.info('Ending current call', {
|
|
1074
|
+
id: callSession ? callSession.getId() : null,
|
|
1075
|
+
isCurrent,
|
|
1076
|
+
});
|
|
1077
|
+
if (isCurrent) {
|
|
1078
|
+
this.currentSipSession = undefined;
|
|
1079
|
+
this.currentCallSession = null;
|
|
1080
|
+
}
|
|
1081
|
+
this.eventEmitter.emit(ON_TERMINATE_SOUND, callSession, 'locally ended');
|
|
1082
|
+
}
|
|
1083
|
+
onConnectionMade() { }
|
|
1084
|
+
isConference(callSession) {
|
|
1085
|
+
if (!callSession) {
|
|
1086
|
+
return false;
|
|
1087
|
+
}
|
|
1088
|
+
return this.client && this.client.isConference(callSession.sipCallId);
|
|
1089
|
+
}
|
|
1090
|
+
async close(force = false) {
|
|
1091
|
+
logger.info('WebRTC close');
|
|
1092
|
+
try {
|
|
1093
|
+
await Promise.race([this.unregister(), new Promise((resolve, reject) => setTimeout(() => reject(new Error('Unregister, timed out')), 3000))]);
|
|
1094
|
+
}
|
|
1095
|
+
catch (e) {
|
|
1096
|
+
logger.error('WebRTC close, unregister error', e);
|
|
1097
|
+
}
|
|
1098
|
+
this.client.close(force);
|
|
1099
|
+
this.unbind();
|
|
1100
|
+
this.incomingSessions = [];
|
|
1101
|
+
this.currentSipSession = undefined;
|
|
1102
|
+
this.currentCallSession = null;
|
|
2453
1103
|
this.shouldSendReinvite = false;
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
1104
|
+
this.rejectedSessions = {};
|
|
1105
|
+
}
|
|
1106
|
+
isRegistered() {
|
|
1107
|
+
return this.client && this.client.isRegistered();
|
|
1108
|
+
}
|
|
1109
|
+
enableRinging() {
|
|
1110
|
+
logger.info('WebRTC enable ringing');
|
|
1111
|
+
this.ringingEnabled = true;
|
|
1112
|
+
}
|
|
1113
|
+
disableRinging() {
|
|
1114
|
+
logger.info('WebRTC disable ringing');
|
|
1115
|
+
this.ringingEnabled = false;
|
|
1116
|
+
}
|
|
1117
|
+
getCurrentCallSession() {
|
|
1118
|
+
if (!this.currentSipSession) {
|
|
1119
|
+
return null;
|
|
1120
|
+
}
|
|
1121
|
+
return this._createCallSession(this.currentSipSession, this.currentCallSession);
|
|
1122
|
+
}
|
|
1123
|
+
hasIncomingCallSession() {
|
|
1124
|
+
return this.incomingSessions.length > 0;
|
|
1125
|
+
}
|
|
1126
|
+
getIncomingCallSession() {
|
|
1127
|
+
if (!this.hasIncomingCallSession()) {
|
|
1128
|
+
return null;
|
|
1129
|
+
}
|
|
1130
|
+
const sessionId = this.incomingSessions[0];
|
|
1131
|
+
const sipSession = this.client.getSipSession(sessionId);
|
|
1132
|
+
if (!sipSession) {
|
|
1133
|
+
return null;
|
|
1134
|
+
}
|
|
1135
|
+
return this._createCallSession(sipSession);
|
|
1136
|
+
}
|
|
1137
|
+
// eslint-disable-next-line @typescript-eslint/default-param-last
|
|
1138
|
+
sendMessage(sipSession = null, body, contentType = 'text/plain') {
|
|
1139
|
+
return this.client.sendMessage(sipSession, body, contentType);
|
|
1140
|
+
}
|
|
1141
|
+
getLocalStream(callSession) {
|
|
1142
|
+
return callSession ? this.client.getLocalStream(callSession.sipCallId) : null;
|
|
1143
|
+
}
|
|
1144
|
+
getLocalVideoStream(callSession) {
|
|
1145
|
+
return callSession ? this.client.getLocalVideoStream(callSession.sipCallId) : null;
|
|
1146
|
+
}
|
|
1147
|
+
// Deprecated
|
|
1148
|
+
getLocalMediaStream(callSession) {
|
|
1149
|
+
logger.warn('WebRTCPhone.getLocalMediaStream is deprecated, use WebRTCPhone.getLocalStream instead');
|
|
1150
|
+
return this.getLocalStream(callSession);
|
|
1151
|
+
}
|
|
1152
|
+
hasLocalVideo(callSession) {
|
|
1153
|
+
return callSession ? this.client.hasLocalVideo(callSession.sipCallId) : false;
|
|
1154
|
+
}
|
|
1155
|
+
hasALocalVideoTrack(callSession) {
|
|
1156
|
+
return callSession ? this.client.hasALocalVideoTrack(callSession.sipCallId) : false;
|
|
1157
|
+
}
|
|
1158
|
+
getRemoteStream(callSession) {
|
|
1159
|
+
return callSession ? this.client.getRemoteStream(callSession.sipCallId) : null;
|
|
1160
|
+
}
|
|
1161
|
+
getRemoteVideoStream(callSession) {
|
|
1162
|
+
return callSession ? this.client.getRemoteVideoStream(callSession.sipCallId) : null;
|
|
1163
|
+
}
|
|
1164
|
+
getRemoteVideoStreamFromPc(callSession) {
|
|
1165
|
+
return callSession ? this.client.getRemoteVideoStreamFromPc(callSession.sipCallId) : null;
|
|
1166
|
+
}
|
|
1167
|
+
hasRemoteVideo(callSession) {
|
|
1168
|
+
return callSession ? this.client.hasRemoteVideo(callSession.sipCallId) : false;
|
|
1169
|
+
}
|
|
1170
|
+
setMediaConstraints(media) {
|
|
1171
|
+
this.client.setMediaConstraints(media);
|
|
1172
|
+
}
|
|
1173
|
+
isVideoRemotelyHeld(callSession) {
|
|
1174
|
+
return callSession ? this.client.isVideoRemotelyHeld(callSession.sipCallId) : false;
|
|
1175
|
+
}
|
|
1176
|
+
bindClientEvents() {
|
|
1177
|
+
this.client.unbind();
|
|
1178
|
+
this.client.on(this.client.INVITE, (sipSession, wantsToDoVideo) => {
|
|
1179
|
+
const autoAnswer = sipSession.request.getHeader('Answer-Mode') === 'Auto';
|
|
1180
|
+
const withVideo = this.allowVideo ? wantsToDoVideo : false;
|
|
1181
|
+
logger.info('WebRTC invite received', {
|
|
1182
|
+
sipId: sipSession.id,
|
|
1183
|
+
withVideo,
|
|
1184
|
+
autoAnswer,
|
|
1185
|
+
});
|
|
1186
|
+
const callSession = this._createIncomingCallSession(sipSession, withVideo, null, autoAnswer);
|
|
1187
|
+
this.incomingSessions.push(callSession.getId());
|
|
1188
|
+
this._bindEvents(sipSession);
|
|
1189
|
+
this.client.storeSipSession(sipSession);
|
|
1190
|
+
if (!this.currentSipSession) {
|
|
1191
|
+
if (this.ringingEnabled) {
|
|
1192
|
+
this.eventEmitter.emit(ON_PLAY_RING_SOUND, this.audioRingDeviceId, this.audioRingVolume, callSession);
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
else {
|
|
1196
|
+
this.eventEmitter.emit(ON_PLAY_INBOUND_CALL_SIGNAL_SOUND, this.audioOutputDeviceId, this.audioOutputVolume, callSession);
|
|
1197
|
+
}
|
|
1198
|
+
callSession.creationTime = new Date();
|
|
1199
|
+
this._updateCallSession(callSession);
|
|
1200
|
+
this.eventEmitter.emit(ON_CALL_INCOMING, callSession, wantsToDoVideo);
|
|
1201
|
+
});
|
|
1202
|
+
this.client.on(this.client.ON_REINVITE, (...args) => {
|
|
1203
|
+
logger.info('WebRTC on reinvite', {
|
|
1204
|
+
sessionId: args[0].id,
|
|
1205
|
+
inviteId: args[1].id,
|
|
1206
|
+
updatedCalleeName: args[2],
|
|
1207
|
+
updatedNumber: args[3],
|
|
1208
|
+
});
|
|
1209
|
+
const sipSession = args[0];
|
|
1210
|
+
// Give some time for the stream to be mounted.
|
|
1211
|
+
// if `_createCallSession` is called too soon `hasVideo` will return false because the stream doesn't exists yet
|
|
1212
|
+
setTimeout(() => {
|
|
1213
|
+
// Update callSession
|
|
1214
|
+
this._createCallSession(sipSession, this.callSessions[this.getSipSessionId(sipSession)]);
|
|
1215
|
+
this.eventEmitter.emit.apply(this.eventEmitter, [this.client.ON_REINVITE, ...args]);
|
|
1216
|
+
}, 2000);
|
|
1217
|
+
});
|
|
1218
|
+
this.client.on(this.client.ACCEPTED, (sipSession) => {
|
|
1219
|
+
const sessionId = this.getSipSessionId(sipSession);
|
|
1220
|
+
const hasSession = (sessionId in this.callSessions);
|
|
1221
|
+
logger.info('WebRTC call accepted', {
|
|
1222
|
+
sipId: sessionId,
|
|
1223
|
+
hasSession,
|
|
1224
|
+
});
|
|
1225
|
+
if (!hasSession) {
|
|
1226
|
+
logger.warn('Call accepted ignored, session is no longer present in the WebRtcPhone', {
|
|
1227
|
+
sessionId,
|
|
1228
|
+
});
|
|
1229
|
+
return;
|
|
1230
|
+
}
|
|
1231
|
+
this._onCallAccepted(sipSession, this.client.hasVideo(sessionId));
|
|
1232
|
+
if (this.audioOutputDeviceId) {
|
|
1233
|
+
this.client.changeAudioOutputDevice(this.audioOutputDeviceId);
|
|
1234
|
+
}
|
|
1235
|
+
});
|
|
1236
|
+
this.client.on('ended', () => { });
|
|
1237
|
+
this.client.on(this.client.ON_ERROR, e => {
|
|
1238
|
+
logger.error('WebRTC error', e);
|
|
1239
|
+
this.eventEmitter.emit(ON_CALL_ERROR, e);
|
|
1240
|
+
});
|
|
1241
|
+
this.client.on(this.client.REJECTED, session => {
|
|
1242
|
+
logger.info('WebRTC call rejected', session.id);
|
|
1243
|
+
const callSession = this._createCallSession(session);
|
|
1244
|
+
callSession.endTime = new Date();
|
|
1245
|
+
this._updateCallSession(callSession);
|
|
1246
|
+
this.eventEmitter.emit(ON_CALL_REJECTED, callSession);
|
|
1247
|
+
});
|
|
1248
|
+
this.client.on(this.client.UNREGISTERED, () => {
|
|
1249
|
+
logger.info('WebRTC unregistered');
|
|
1250
|
+
this.eventEmitter.emit(ON_UNREGISTERED);
|
|
1251
|
+
});
|
|
1252
|
+
this.client.on(this.client.ON_DISCONNECTED, () => {
|
|
1253
|
+
logger.info('WebRTC disconnected');
|
|
1254
|
+
this.eventEmitter.emit(ON_DISCONNECTED);
|
|
1255
|
+
});
|
|
1256
|
+
this.client.on(this.client.ON_EARLY_MEDIA, session => {
|
|
1257
|
+
logger.info('WebRTC early media');
|
|
1258
|
+
const callSession = this._createCallSession(session);
|
|
1259
|
+
this.eventEmitter.emit(ON_EARLY_MEDIA, callSession);
|
|
1260
|
+
});
|
|
1261
|
+
this.client.on(this.client.REGISTERED, () => {
|
|
1262
|
+
logger.info('WebRTC registered', {
|
|
1263
|
+
shouldSendReinvite: this.shouldSendReinvite,
|
|
1264
|
+
state: this.currentSipSession ? this.currentSipSession.state : null,
|
|
1265
|
+
currentSipSession: !!this.currentSipSession,
|
|
1266
|
+
});
|
|
1267
|
+
this.stopHeartbeat();
|
|
1268
|
+
this.eventEmitter.emit(ON_REGISTERED);
|
|
1269
|
+
// If the phone registered with a current callSession (eg: when switching network):
|
|
1270
|
+
// send a reinvite to renegociate ICE with new IP
|
|
1271
|
+
if (this.shouldSendReinvite && this.currentSipSession && this.currentSipSession.state === SessionState.Established) {
|
|
1272
|
+
this.shouldSendReinvite = false;
|
|
1273
|
+
// @ts-ignore
|
|
1274
|
+
const pc = this.currentSipSession?.sessionDescriptionHandler?.peerConnection;
|
|
1275
|
+
const isConference = pc ? pc.sfu : false;
|
|
1276
|
+
const hasVideo = this.currentCallSession && this.currentCallSession.cameraEnabled;
|
|
1277
|
+
try {
|
|
1278
|
+
// Send reinvite with iceRestart
|
|
1279
|
+
this.sendReinvite(this.currentCallSession, null, isConference, !hasVideo, true);
|
|
1280
|
+
}
|
|
1281
|
+
catch (e) {
|
|
1282
|
+
logger.error('WebRTC reinvite after register, error', {
|
|
1283
|
+
message: e.message,
|
|
1284
|
+
stack: e.stack,
|
|
1285
|
+
});
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
});
|
|
1289
|
+
this.client.on(this.client.CONNECTED, () => {
|
|
1290
|
+
logger.info('WebRTC client connected');
|
|
1291
|
+
this.stopHeartbeat();
|
|
1292
|
+
});
|
|
1293
|
+
this.client.on(this.client.DISCONNECTED, () => {
|
|
1294
|
+
logger.info('WebRTC client disconnected');
|
|
1295
|
+
this.eventEmitter.emit(ON_UNREGISTERED);
|
|
1296
|
+
// Do not trigger heartbeat if already running
|
|
1297
|
+
if (!this.client.hasHeartbeat()) {
|
|
1298
|
+
this.startHeartbeat();
|
|
1299
|
+
}
|
|
1300
|
+
// Tell to send reinvite when reconnecting
|
|
1301
|
+
this.shouldSendReinvite = true;
|
|
1302
|
+
});
|
|
1303
|
+
this.client.on(this.client.ON_TRACK, (session, event) => {
|
|
1304
|
+
this.eventEmitter.emit(ON_TRACK, session, event);
|
|
1305
|
+
});
|
|
1306
|
+
this.client.on('onVideoInputChange', stream => {
|
|
1307
|
+
this.eventEmitter.emit(ON_VIDEO_INPUT_CHANGE, stream);
|
|
1308
|
+
});
|
|
1309
|
+
this.client.on(this.client.MESSAGE, (message) => {
|
|
1310
|
+
this._onMessage(message);
|
|
1311
|
+
this.eventEmitter.emit(ON_MESSAGE, message);
|
|
1312
|
+
});
|
|
1313
|
+
this.client.on(this.client.ON_NETWORK_STATS, (session, stats, previousStats) => {
|
|
1314
|
+
const callSession = this.getCallSession(this.getSipSessionId(session));
|
|
1315
|
+
this.eventEmitter.emit(ON_NETWORK_STATS, callSession, stats, previousStats);
|
|
1316
|
+
});
|
|
1317
|
+
// Used when upgrading directly in screenshare mode
|
|
1318
|
+
this.client.on(this.client.ON_SCREEN_SHARING_REINVITE, (sipSession, response, desktop) => {
|
|
1319
|
+
const sipSessionId = this.getSipSessionId(sipSession);
|
|
1320
|
+
const localStream = this.client.getLocalStream(sipSessionId);
|
|
1321
|
+
const callSession = this.callSessions[sipSessionId];
|
|
1322
|
+
logger.info('Updrading directly in screensharing mode', {
|
|
1323
|
+
sipSessionId,
|
|
1324
|
+
tracks: localStream?.getTracks() || null,
|
|
1325
|
+
});
|
|
1326
|
+
this._onScreenSharing(localStream, sipSession, callSession, false, desktop);
|
|
1327
|
+
});
|
|
1328
|
+
}
|
|
1329
|
+
// Find a corresponding sipSession from a CallSession
|
|
1330
|
+
findSipSession(callSession) {
|
|
1331
|
+
const keys = this.client.getSipSessionIds();
|
|
1332
|
+
const keyIndex = keys.findIndex(sessionId => callSession && callSession.isId(sessionId));
|
|
1333
|
+
if (keyIndex === -1) {
|
|
1334
|
+
const currentSipSessionId = this.currentSipSession ? this.getSipSessionId(this.currentSipSession) : this.client.getSipSessionIds()[0];
|
|
1335
|
+
return currentSipSessionId ? this.client.getSipSession(currentSipSessionId) : null;
|
|
1336
|
+
}
|
|
1337
|
+
return this.client.getSipSession(keys[keyIndex]);
|
|
1338
|
+
}
|
|
1339
|
+
getCallSession(sipSessionId) {
|
|
1340
|
+
return this.callSessions[sipSessionId];
|
|
1341
|
+
}
|
|
1342
|
+
getSipSessionId(sipSession) {
|
|
1343
|
+
return this.client.getSipSessionId(sipSession);
|
|
1344
|
+
}
|
|
1345
|
+
getSipSessionIdFromCallSession(callSession) {
|
|
1346
|
+
const sipSession = this.findSipSession(callSession);
|
|
1347
|
+
return sipSession ? this.getSipSessionId(sipSession) : null;
|
|
1348
|
+
}
|
|
1349
|
+
_updateCallSession(callSession) {
|
|
1350
|
+
const sipSessionId = this.getSipSessionIdFromCallSession(callSession);
|
|
1351
|
+
if (sipSessionId) {
|
|
1352
|
+
this.callSessions[sipSessionId] = callSession;
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
_onMessage(message) {
|
|
1356
|
+
// @ts-ignore
|
|
1357
|
+
if (!message || message.method !== 'MESSAGE') {
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1360
|
+
let body;
|
|
2458
1361
|
try {
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
}
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
}
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
})
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
if (sipSessionId) {
|
|
2554
|
-
this.callSessions[sipSessionId] = callSession;
|
|
2555
|
-
}
|
|
2556
|
-
}
|
|
2557
|
-
|
|
2558
|
-
_onMessage(message ) {
|
|
2559
|
-
if (!message || message.method !== 'MESSAGE') {
|
|
2560
|
-
return;
|
|
2561
|
-
}
|
|
2562
|
-
|
|
2563
|
-
let body;
|
|
2564
|
-
|
|
2565
|
-
try {
|
|
2566
|
-
body = JSON.parse(message.body);
|
|
2567
|
-
} catch (e) {
|
|
2568
|
-
return;
|
|
2569
|
-
}
|
|
2570
|
-
|
|
2571
|
-
const { type, content } = body;
|
|
2572
|
-
|
|
2573
|
-
switch (type) {
|
|
2574
|
-
case MESSAGE_TYPE_CHAT:
|
|
2575
|
-
this.eventEmitter.emit(ON_CHAT, content);
|
|
2576
|
-
break;
|
|
2577
|
-
|
|
2578
|
-
case MESSAGE_TYPE_SIGNAL: {
|
|
2579
|
-
this.eventEmitter.emit(ON_SIGNAL, content);
|
|
2580
|
-
break;
|
|
2581
|
-
}
|
|
2582
|
-
}
|
|
2583
|
-
}
|
|
2584
|
-
|
|
2585
|
-
_createIncomingCallSession(
|
|
2586
|
-
sipSession ,
|
|
2587
|
-
cameraEnabled ,
|
|
2588
|
-
fromSession ,
|
|
2589
|
-
autoAnswer = false,
|
|
2590
|
-
) {
|
|
2591
|
-
return this._createCallSession(sipSession, fromSession, {
|
|
2592
|
-
incoming: true,
|
|
2593
|
-
ringing: true,
|
|
2594
|
-
cameraEnabled,
|
|
2595
|
-
autoAnswer,
|
|
2596
|
-
});
|
|
2597
|
-
}
|
|
2598
|
-
|
|
2599
|
-
_createOutgoingCallSession(
|
|
2600
|
-
sipSession ,
|
|
2601
|
-
cameraEnabled ,
|
|
2602
|
-
fromSession ,
|
|
2603
|
-
) {
|
|
2604
|
-
return this._createCallSession(sipSession, fromSession, { incoming: false, ringing: true, cameraEnabled });
|
|
2605
|
-
}
|
|
2606
|
-
|
|
2607
|
-
_createAcceptedCallSession(
|
|
2608
|
-
sipSession ,
|
|
2609
|
-
cameraEnabled ,
|
|
2610
|
-
fromSession ,
|
|
2611
|
-
) {
|
|
2612
|
-
return this._createCallSession(sipSession, fromSession, {
|
|
2613
|
-
cameraEnabled: cameraEnabled !== undefined ? cameraEnabled : false,
|
|
2614
|
-
});
|
|
2615
|
-
}
|
|
2616
|
-
|
|
2617
|
-
_createMutedCallSession(sipSession , fromSession ) {
|
|
2618
|
-
return this._createCallSession(sipSession, fromSession, {
|
|
2619
|
-
muted: true,
|
|
2620
|
-
});
|
|
2621
|
-
}
|
|
2622
|
-
|
|
2623
|
-
_createUnmutedCallSession(sipSession , fromSession ) {
|
|
2624
|
-
return this._createCallSession(sipSession, fromSession, {
|
|
2625
|
-
muted: false,
|
|
2626
|
-
});
|
|
2627
|
-
}
|
|
2628
|
-
|
|
2629
|
-
_createCameraResumedCallSession(sipSession , fromSession ) {
|
|
2630
|
-
return this._createCallSession(sipSession, fromSession, {
|
|
2631
|
-
videoMuted: false,
|
|
2632
|
-
});
|
|
2633
|
-
}
|
|
2634
|
-
|
|
2635
|
-
_createCameraDisabledCallSession(sipSession , fromSession ) {
|
|
2636
|
-
return this._createCallSession(sipSession, fromSession, {
|
|
2637
|
-
videoMuted: true,
|
|
2638
|
-
});
|
|
2639
|
-
}
|
|
2640
|
-
|
|
2641
|
-
_createCallSession(sipSession , fromSession , extra = {}) {
|
|
2642
|
-
// eslint-disable-next-line
|
|
2643
|
-
const identity = sipSession ? sipSession.remoteIdentity || sipSession.assertedIdentity : null;
|
|
2644
|
-
const number = identity ? identity.uri._normal.user : null;
|
|
2645
|
-
const { state } = sipSession || {};
|
|
2646
|
-
const sessionId = this.getSipSessionId(sipSession);
|
|
2647
|
-
fromSession = fromSession || this.callSessions[sessionId];
|
|
2648
|
-
|
|
2649
|
-
const callSession = new CallSession({
|
|
2650
|
-
callId: fromSession && fromSession.callId,
|
|
2651
|
-
sipCallId: sessionId,
|
|
2652
|
-
sipStatus: state,
|
|
2653
|
-
displayName: identity ? identity.displayName || number : number,
|
|
2654
|
-
startTime: fromSession ? fromSession.startTime : new Date(),
|
|
2655
|
-
creationTime: fromSession ? fromSession.creationTime : null,
|
|
2656
|
-
answerTime: fromSession ? fromSession.answerTime : null,
|
|
2657
|
-
endTime: fromSession ? fromSession.endTime : null,
|
|
2658
|
-
answered: state === SessionState.Established,
|
|
2659
|
-
paused: this.client.isCallHeld(sipSession),
|
|
2660
|
-
isCaller: fromSession ? fromSession.isCaller : ('incoming' in extra ? !extra.incoming : false),
|
|
2661
|
-
cameraEnabled: fromSession ? fromSession.isCameraEnabled() : this.client.hasVideo(sessionId),
|
|
2662
|
-
number,
|
|
2663
|
-
ringing: false,
|
|
2664
|
-
muted: fromSession ? fromSession.isMuted() : this.client.isAudioMuted(sipSession),
|
|
2665
|
-
videoMuted: fromSession ? fromSession.isVideoMuted() : false,
|
|
2666
|
-
recording: fromSession ? fromSession.isRecording() : false,
|
|
2667
|
-
recordingPaused: false, // @TODO
|
|
2668
|
-
sipSession,
|
|
2669
|
-
conference: !!fromSession && fromSession.isConference(),
|
|
2670
|
-
...extra,
|
|
2671
|
-
});
|
|
2672
|
-
|
|
2673
|
-
this.callSessions[callSession.getId()] = callSession;
|
|
2674
|
-
|
|
2675
|
-
return callSession;
|
|
2676
|
-
}
|
|
1362
|
+
// @ts-ignore
|
|
1363
|
+
body = JSON.parse(message.body);
|
|
1364
|
+
}
|
|
1365
|
+
catch (e) {
|
|
1366
|
+
return;
|
|
1367
|
+
}
|
|
1368
|
+
const { type, content, } = body;
|
|
1369
|
+
switch (type) {
|
|
1370
|
+
case MESSAGE_TYPE_CHAT:
|
|
1371
|
+
this.eventEmitter.emit(ON_CHAT, content);
|
|
1372
|
+
break;
|
|
1373
|
+
case MESSAGE_TYPE_SIGNAL:
|
|
1374
|
+
{
|
|
1375
|
+
this.eventEmitter.emit(ON_SIGNAL, content);
|
|
1376
|
+
break;
|
|
1377
|
+
}
|
|
1378
|
+
default:
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
_createIncomingCallSession(sipSession, cameraEnabled, fromSession, autoAnswer = false) {
|
|
1382
|
+
return this._createCallSession(sipSession, fromSession, {
|
|
1383
|
+
incoming: true,
|
|
1384
|
+
ringing: true,
|
|
1385
|
+
cameraEnabled,
|
|
1386
|
+
autoAnswer,
|
|
1387
|
+
});
|
|
1388
|
+
}
|
|
1389
|
+
_createOutgoingCallSession(sipSession, cameraEnabled, fromSession) {
|
|
1390
|
+
return this._createCallSession(sipSession, fromSession, {
|
|
1391
|
+
incoming: false,
|
|
1392
|
+
ringing: true,
|
|
1393
|
+
cameraEnabled,
|
|
1394
|
+
});
|
|
1395
|
+
}
|
|
1396
|
+
_createAcceptedCallSession(sipSession, cameraEnabled, fromSession) {
|
|
1397
|
+
return this._createCallSession(sipSession, fromSession, {
|
|
1398
|
+
cameraEnabled: cameraEnabled !== undefined ? cameraEnabled : false,
|
|
1399
|
+
});
|
|
1400
|
+
}
|
|
1401
|
+
_createMutedCallSession(sipSession, fromSession) {
|
|
1402
|
+
return this._createCallSession(sipSession, fromSession, {
|
|
1403
|
+
muted: true,
|
|
1404
|
+
});
|
|
1405
|
+
}
|
|
1406
|
+
_createUnmutedCallSession(sipSession, fromSession) {
|
|
1407
|
+
return this._createCallSession(sipSession, fromSession, {
|
|
1408
|
+
muted: false,
|
|
1409
|
+
});
|
|
1410
|
+
}
|
|
1411
|
+
_createCameraResumedCallSession(sipSession, fromSession) {
|
|
1412
|
+
return this._createCallSession(sipSession, fromSession, {
|
|
1413
|
+
videoMuted: false,
|
|
1414
|
+
});
|
|
1415
|
+
}
|
|
1416
|
+
_createCameraDisabledCallSession(sipSession, fromSession) {
|
|
1417
|
+
return this._createCallSession(sipSession, fromSession, {
|
|
1418
|
+
videoMuted: true,
|
|
1419
|
+
});
|
|
1420
|
+
}
|
|
1421
|
+
_createCallSession(sipSession, fromSession, extra = {}) {
|
|
1422
|
+
// eslint-disable-next-line
|
|
1423
|
+
const identity = sipSession ? sipSession.remoteIdentity || sipSession.assertedIdentity : null;
|
|
1424
|
+
// @ts-ignore
|
|
1425
|
+
const number = identity ? identity.uri._normal.user : null;
|
|
1426
|
+
const { state, } = sipSession || {};
|
|
1427
|
+
const sessionId = this.getSipSessionId(sipSession);
|
|
1428
|
+
fromSession = fromSession || this.callSessions[sessionId];
|
|
1429
|
+
const callSession = new CallSession({
|
|
1430
|
+
callId: fromSession && fromSession.callId,
|
|
1431
|
+
sipCallId: sessionId,
|
|
1432
|
+
sipStatus: state,
|
|
1433
|
+
displayName: identity ? identity.displayName || number : number,
|
|
1434
|
+
// @ts-ignore: @HEADSUP: startTime should be a number, not a date
|
|
1435
|
+
startTime: fromSession ? fromSession.startTime : new Date(),
|
|
1436
|
+
creationTime: fromSession ? fromSession.creationTime : null,
|
|
1437
|
+
answerTime: fromSession ? fromSession.answerTime : null,
|
|
1438
|
+
endTime: fromSession ? fromSession.endTime : null,
|
|
1439
|
+
answered: state === SessionState.Established,
|
|
1440
|
+
paused: this.client.isCallHeld(sipSession),
|
|
1441
|
+
isCaller: fromSession ? fromSession.isCaller : 'incoming' in extra ? !extra.incoming : false,
|
|
1442
|
+
cameraEnabled: fromSession ? fromSession.isCameraEnabled() : this.client.hasVideo(sessionId),
|
|
1443
|
+
number,
|
|
1444
|
+
ringing: false,
|
|
1445
|
+
muted: fromSession ? fromSession.isMuted() : this.client.isAudioMuted(sipSession),
|
|
1446
|
+
videoMuted: fromSession ? fromSession.isVideoMuted() : false,
|
|
1447
|
+
recording: fromSession ? fromSession.isRecording() : false,
|
|
1448
|
+
recordingPaused: false,
|
|
1449
|
+
sipSession,
|
|
1450
|
+
conference: !!fromSession && fromSession.isConference(),
|
|
1451
|
+
...extra,
|
|
1452
|
+
});
|
|
1453
|
+
this.callSessions[callSession.getId()] = callSession;
|
|
1454
|
+
return callSession;
|
|
1455
|
+
}
|
|
2677
1456
|
}
|
|
2678
|
-
|
|
2679
|
-
export default WebRTCPhone;
|
|
2680
|
-
export { MESSAGE_TYPE_CHAT, MESSAGE_TYPE_SIGNAL, ON_AUDIO_STREAM, ON_CALL_ACCEPTED, ON_CALL_ANSWERED, ON_CALL_CANCELED, ON_CALL_ENDED, ON_CALL_ENDING, ON_CALL_ERROR, ON_CALL_FAILED, ON_CALL_HELD, ON_CALL_INCOMING, ON_CALL_MUTED, ON_CALL_OUTGOING, ON_CALL_REJECTED, ON_CALL_RESUMED, ON_CALL_UNHELD, ON_CALL_UNMUTED, ON_CAMERA_DISABLED, ON_CAMERA_RESUMED, ON_CHAT, ON_DISCONNECTED, ON_EARLY_MEDIA, ON_MESSAGE, ON_MESSAGE_TRACK_UPDATED, ON_NETWORK_STATS, ON_PLAY_HANGUP_SOUND, ON_PLAY_INBOUND_CALL_SIGNAL_SOUND, ON_PLAY_PROGRESS_SOUND, ON_PLAY_RING_SOUND, ON_PROGRESS, ON_REGISTERED, ON_REINVITE, ON_REMOVE_STREAM, ON_SHARE_SCREEN_ENDED, ON_SHARE_SCREEN_ENDING, ON_SHARE_SCREEN_STARTED, ON_SIGNAL, ON_TERMINATE_SOUND, ON_TRACK, ON_UNREGISTERED, ON_USER_AGENT, ON_VIDEO_INPUT_CHANGE, ON_VIDEO_STREAM, events };
|