@wazo/sdk 0.43.14 → 0.44.0
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 +84 -57
- package/dist/index.js +10630 -0
- package/dist/index.mjs +10541 -0
- package/dist/types/api-client.d.ts +26 -0
- package/dist/types/api-client.d.ts.map +1 -0
- package/{lib/types/api-client.d.ts → dist/types/base-api-client.d.ts} +3 -24
- package/dist/types/base-api-client.d.ts.map +1 -0
- package/dist/types/constants.d.ts +12 -0
- package/dist/types/constants.d.ts.map +1 -0
- package/{lib → dist}/types/domain/Contact.d.ts +3 -1
- package/dist/types/domain/Contact.d.ts.map +1 -0
- package/{lib → dist}/types/index.d.ts +14 -13
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/service/__tests__/getApiclient.test.d.ts +2 -0
- package/dist/types/service/__tests__/getApiclient.test.d.ts.map +1 -0
- package/{lib → dist}/types/service/getApiClient.d.ts +5 -2
- package/dist/types/service/getApiClient.d.ts.map +1 -0
- package/{esm → dist}/types/simple/index.d.ts +1 -1
- package/{lib → dist}/types/utils/api-requester.d.ts.map +1 -1
- package/dist/wazo-sdk.js +69378 -43
- package/dist/wazo-sdk.js.LICENSE.txt +684 -0
- package/package.json +10 -21
- package/esm/__tests__/api-client.test.js +0 -281
- package/esm/__tests__/web-rtc-client.test.js +0 -192
- package/esm/api/agentd.js +0 -23
- package/esm/api/amid.js +0 -17
- package/esm/api/application.js +0 -63
- package/esm/api/auth.js +0 -198
- package/esm/api/call-logd.js +0 -24
- package/esm/api/calld.js +0 -120
- package/esm/api/chatd.js +0 -50
- package/esm/api/confd.js +0 -77
- package/esm/api/ctid-ng.js +0 -96
- package/esm/api/dird.js +0 -110
- package/esm/api/webhookd.js +0 -7
- package/esm/api-client.js +0 -166
- package/esm/checker/Checker.js +0 -54
- package/esm/checker/checks/aor.js +0 -28
- package/esm/checker/checks/api.js +0 -76
- package/esm/checker/checks/ice-ipv4.js +0 -69
- package/esm/checker/checks/index.js +0 -8
- package/esm/checker/checks/symmetric-nat.js +0 -59
- package/esm/checker/checks/wazo-websocket.js +0 -38
- package/esm/checker/checks/webrtc-transport.js +0 -35
- package/esm/checker/checks/webrtc.js +0 -40
- package/esm/domain/AdHocAPIConference.js +0 -102
- package/esm/domain/Agent.js +0 -30
- package/esm/domain/BadResponse.js +0 -21
- package/esm/domain/Call.js +0 -123
- package/esm/domain/CallLog.js +0 -157
- package/esm/domain/CallSession.js +0 -253
- package/esm/domain/CallerID.js +0 -24
- package/esm/domain/ChatMessage.js +0 -55
- package/esm/domain/ChatRoom.js +0 -30
- package/esm/domain/Contact.js +0 -464
- package/esm/domain/Country.js +0 -19
- package/esm/domain/Device/DebugDevice.js +0 -32
- package/esm/domain/Device/Device.js +0 -1
- package/esm/domain/DirectorySource.js +0 -1
- package/esm/domain/ExternalApp.js +0 -24
- package/esm/domain/Features.js +0 -77
- package/esm/domain/ForwardOption.js +0 -37
- package/esm/domain/Incall.js +0 -28
- package/esm/domain/IndirectTransfer.js +0 -40
- package/esm/domain/Line.js +0 -39
- package/esm/domain/Meeting.js +0 -61
- package/esm/domain/MeetingAuthorization.js +0 -46
- package/esm/domain/MeetingStatus.js +0 -14
- package/esm/domain/NotificationOptions.js +0 -45
- package/esm/domain/Phone/CTIPhone.js +0 -288
- package/esm/domain/Phone/Phone.js +0 -1
- package/esm/domain/Phone/WebRTCPhone.js +0 -1482
- package/esm/domain/Profile.js +0 -128
- package/esm/domain/Recording.js +0 -30
- package/esm/domain/Relocation.js +0 -20
- package/esm/domain/Room.js +0 -97
- package/esm/domain/SFUNotAvailableError.js +0 -6
- package/esm/domain/ServerError.js +0 -9
- package/esm/domain/Session.js +0 -174
- package/esm/domain/SipLine.js +0 -82
- package/esm/domain/Subscription.js +0 -42
- package/esm/domain/SwitchboardCall.js +0 -56
- package/esm/domain/Voicemail.js +0 -76
- package/esm/domain/__tests__/Agent.test.js +0 -37
- package/esm/domain/__tests__/Call.test.js +0 -25
- package/esm/domain/__tests__/CallLog.test.js +0 -181
- package/esm/domain/__tests__/CallSession.test.js +0 -78
- package/esm/domain/__tests__/Contact.test.js +0 -393
- package/esm/domain/__tests__/IndirectTransfer.test.js +0 -67
- package/esm/domain/__tests__/Line.test.js +0 -52
- package/esm/domain/__tests__/Meeting.test.js +0 -77
- package/esm/domain/__tests__/MeetingAuthorization.test.js +0 -49
- package/esm/domain/__tests__/Profile.test.js +0 -169
- package/esm/domain/__tests__/Room.test.js +0 -206
- package/esm/domain/__tests__/Session.test.js +0 -382
- package/esm/domain/__tests__/SipLine.test.js +0 -27
- package/esm/domain/__tests__/Voicemail.test.js +0 -90
- package/esm/domain/types.js +0 -2
- package/esm/index.js +0 -50
- package/esm/lib/WazoSessionDescriptionHandler.js +0 -429
- package/esm/pubkey.js +0 -10
- package/esm/service/CallApi.js +0 -61
- package/esm/service/IssueReporter.js +0 -331
- package/esm/service/__tests__/IssueReporter.test.js +0 -112
- package/esm/service/getApiClient.js +0 -92
- package/esm/simple/Auth.js +0 -384
- package/esm/simple/Configuration.js +0 -13
- package/esm/simple/Directory.js +0 -11
- package/esm/simple/Phone.js +0 -389
- package/esm/simple/Websocket.js +0 -81
- package/esm/simple/__tests__/Auth.test.js +0 -144
- package/esm/simple/index.js +0 -137
- package/esm/simple/room/LocalParticipant.js +0 -4
- package/esm/simple/room/Participant.js +0 -315
- package/esm/simple/room/RemoteParticipant.js +0 -10
- package/esm/simple/room/Room.js +0 -714
- package/esm/simple/room/SipRoom.js +0 -121
- package/esm/simple/room/Stream.js +0 -47
- package/esm/simple/room/__tests__/Participant.test.js +0 -71
- package/esm/simple/room/__tests__/RemoteParticipant.test.js +0 -12
- package/esm/simple/utils.js +0 -10
- package/esm/types/WebSocketMessage.js +0 -1
- package/esm/types/api-client.d.ts +0 -64
- package/esm/types/api-client.d.ts.map +0 -1
- package/esm/types/domain/Contact.d.ts +0 -332
- package/esm/types/domain/Contact.d.ts.map +0 -1
- package/esm/types/index.d.ts +0 -58
- package/esm/types/index.d.ts.map +0 -1
- package/esm/types/service/getApiClient.d.ts +0 -18
- package/esm/types/service/getApiClient.d.ts.map +0 -1
- package/esm/types/utils/api-requester.d.ts.map +0 -1
- package/esm/utils/Emitter.js +0 -19
- package/esm/utils/Heartbeat.js +0 -73
- package/esm/utils/PhoneNumberUtil.js +0 -67
- package/esm/utils/__tests__/Heartbeat.test.js +0 -65
- package/esm/utils/__tests__/PhoneNumberUtil.test.js +0 -70
- package/esm/utils/__tests__/api-requester.test.js +0 -166
- package/esm/utils/__tests__/array.test.js +0 -18
- package/esm/utils/__tests__/compare-version.test.js +0 -10
- package/esm/utils/__tests__/object.test.js +0 -76
- package/esm/utils/__tests__/sdp.test.js +0 -172
- package/esm/utils/__tests__/string.test.js +0 -49
- package/esm/utils/api-requester.js +0 -214
- package/esm/utils/array.js +0 -9
- package/esm/utils/compare-version.js +0 -17
- package/esm/utils/isMobile.js +0 -3
- package/esm/utils/new-from.js +0 -7
- package/esm/utils/object.js +0 -10
- package/esm/utils/once.js +0 -15
- package/esm/utils/sdp.js +0 -104
- package/esm/utils/string.js +0 -12
- package/esm/utils/update-from.js +0 -10
- package/esm/utils/webrtc.js +0 -37
- package/esm/web-rtc-client.js +0 -2200
- package/esm/websocket-client.js +0 -385
- package/index.js +0 -1
- package/lib/__tests__/api-client.test.js +0 -295
- package/lib/__tests__/web-rtc-client.test.js +0 -210
- package/lib/api/agentd.js +0 -28
- package/lib/api/amid.js +0 -28
- package/lib/api/application.js +0 -68
- package/lib/api/auth.js +0 -210
- package/lib/api/call-logd.js +0 -29
- package/lib/api/calld.js +0 -134
- package/lib/api/chatd.js +0 -68
- package/lib/api/confd.js +0 -91
- package/lib/api/ctid-ng.js +0 -101
- package/lib/api/dird.js +0 -124
- package/lib/api/webhookd.js +0 -12
- package/lib/api-client.js +0 -164
- package/lib/checker/Checker.js +0 -68
- package/lib/checker/checks/aor.js +0 -42
- package/lib/checker/checks/api.js +0 -90
- package/lib/checker/checks/ice-ipv4.js +0 -73
- package/lib/checker/checks/index.js +0 -13
- package/lib/checker/checks/symmetric-nat.js +0 -61
- package/lib/checker/checks/wazo-websocket.js +0 -63
- package/lib/checker/checks/webrtc-transport.js +0 -49
- package/lib/checker/checks/webrtc.js +0 -54
- package/lib/domain/AdHocAPIConference.js +0 -101
- package/lib/domain/Agent.js +0 -25
- package/lib/domain/BadResponse.js +0 -19
- package/lib/domain/Call.js +0 -112
- package/lib/domain/CallLog.js +0 -151
- package/lib/domain/CallSession.js +0 -224
- package/lib/domain/CallerID.js +0 -27
- package/lib/domain/ChatMessage.js +0 -53
- package/lib/domain/ChatRoom.js +0 -32
- package/lib/domain/Contact.js +0 -439
- package/lib/domain/Country.js +0 -21
- package/lib/domain/Device/DebugDevice.js +0 -35
- package/lib/domain/Device/Device.js +0 -2
- package/lib/domain/DirectorySource.js +0 -2
- package/lib/domain/ExternalApp.js +0 -27
- package/lib/domain/Features.js +0 -87
- package/lib/domain/ForwardOption.js +0 -41
- package/lib/domain/Incall.js +0 -32
- package/lib/domain/IndirectTransfer.js +0 -42
- package/lib/domain/Line.js +0 -39
- package/lib/domain/Meeting.js +0 -55
- package/lib/domain/MeetingAuthorization.js +0 -45
- package/lib/domain/MeetingStatus.js +0 -15
- package/lib/domain/NotificationOptions.js +0 -49
- package/lib/domain/Phone/CTIPhone.js +0 -324
- package/lib/domain/Phone/Phone.js +0 -2
- package/lib/domain/Phone/WebRTCPhone.js +0 -1492
- package/lib/domain/Profile.js +0 -138
- package/lib/domain/Recording.js +0 -31
- package/lib/domain/Relocation.js +0 -18
- package/lib/domain/Room.js +0 -81
- package/lib/domain/SFUNotAvailableError.js +0 -9
- package/lib/domain/ServerError.js +0 -15
- package/lib/domain/Session.js +0 -166
- package/lib/domain/SipLine.js +0 -76
- package/lib/domain/Subscription.js +0 -34
- package/lib/domain/SwitchboardCall.js +0 -50
- package/lib/domain/Voicemail.js +0 -77
- package/lib/domain/__tests__/Agent.test.js +0 -42
- package/lib/domain/__tests__/Call.test.js +0 -30
- package/lib/domain/__tests__/CallLog.test.js +0 -166
- package/lib/domain/__tests__/CallSession.test.js +0 -83
- package/lib/domain/__tests__/Contact.test.js +0 -371
- package/lib/domain/__tests__/IndirectTransfer.test.js +0 -81
- package/lib/domain/__tests__/Line.test.js +0 -57
- package/lib/domain/__tests__/Meeting.test.js +0 -82
- package/lib/domain/__tests__/MeetingAuthorization.test.js +0 -54
- package/lib/domain/__tests__/Profile.test.js +0 -197
- package/lib/domain/__tests__/Room.test.js +0 -220
- package/lib/domain/__tests__/Session.test.js +0 -378
- package/lib/domain/__tests__/SipLine.test.js +0 -32
- package/lib/domain/__tests__/Voicemail.test.js +0 -95
- package/lib/domain/types.js +0 -38
- package/lib/index.js +0 -125
- package/lib/lib/WazoSessionDescriptionHandler.js +0 -434
- package/lib/pubkey.js +0 -12
- package/lib/service/CallApi.js +0 -112
- package/lib/service/IssueReporter.js +0 -317
- package/lib/service/__tests__/IssueReporter.test.js +0 -117
- package/lib/service/getApiClient.js +0 -112
- package/lib/simple/Auth.js +0 -433
- package/lib/simple/Configuration.js +0 -31
- package/lib/simple/Directory.js +0 -29
- package/lib/simple/Phone.js +0 -418
- package/lib/simple/Websocket.js +0 -116
- package/lib/simple/__tests__/Auth.test.js +0 -181
- package/lib/simple/index.js +0 -165
- package/lib/simple/room/LocalParticipant.js +0 -9
- package/lib/simple/room/Participant.js +0 -302
- package/lib/simple/room/RemoteParticipant.js +0 -15
- package/lib/simple/room/Room.js +0 -711
- package/lib/simple/room/SipRoom.js +0 -141
- package/lib/simple/room/Stream.js +0 -50
- package/lib/simple/room/__tests__/Participant.test.js +0 -85
- package/lib/simple/room/__tests__/RemoteParticipant.test.js +0 -17
- package/lib/simple/utils.js +0 -27
- package/lib/types/WebSocketMessage.js +0 -2
- package/lib/types/__tests__/api-client.test.d.ts +0 -2
- package/lib/types/__tests__/api-client.test.d.ts.map +0 -1
- package/lib/types/__tests__/web-rtc-client.test.d.ts +0 -2
- package/lib/types/__tests__/web-rtc-client.test.d.ts.map +0 -1
- package/lib/types/api/agentd.d.ts +0 -17
- package/lib/types/api/agentd.d.ts.map +0 -1
- package/lib/types/api/amid.d.ts +0 -8
- package/lib/types/api/amid.d.ts.map +0 -1
- package/lib/types/api/application.d.ts +0 -34
- package/lib/types/api/application.d.ts.map +0 -1
- package/lib/types/api/auth.d.ts +0 -69
- package/lib/types/api/auth.d.ts.map +0 -1
- package/lib/types/api/call-logd.d.ts +0 -12
- package/lib/types/api/call-logd.d.ts.map +0 -1
- package/lib/types/api/calld.d.ts +0 -52
- package/lib/types/api/calld.d.ts.map +0 -1
- package/lib/types/api/chatd.d.ts +0 -29
- package/lib/types/api/chatd.d.ts.map +0 -1
- package/lib/types/api/confd.d.ts +0 -46
- package/lib/types/api/confd.d.ts.map +0 -1
- package/lib/types/api/ctid-ng.d.ts +0 -36
- package/lib/types/api/ctid-ng.d.ts.map +0 -1
- package/lib/types/api/dird.d.ts +0 -33
- package/lib/types/api/dird.d.ts.map +0 -1
- package/lib/types/api/webhookd.d.ts +0 -24
- package/lib/types/api/webhookd.d.ts.map +0 -1
- package/lib/types/api-client.d.ts.map +0 -1
- package/lib/types/checker/Checker.d.ts +0 -13
- package/lib/types/checker/Checker.d.ts.map +0 -1
- package/lib/types/checker/checks/aor.d.ts +0 -6
- package/lib/types/checker/checks/aor.d.ts.map +0 -1
- package/lib/types/checker/checks/api.d.ts +0 -6
- package/lib/types/checker/checks/api.d.ts.map +0 -1
- package/lib/types/checker/checks/ice-ipv4.d.ts +0 -6
- package/lib/types/checker/checks/ice-ipv4.d.ts.map +0 -1
- package/lib/types/checker/checks/index.d.ts +0 -9
- package/lib/types/checker/checks/index.d.ts.map +0 -1
- package/lib/types/checker/checks/symmetric-nat.d.ts +0 -6
- package/lib/types/checker/checks/symmetric-nat.d.ts.map +0 -1
- package/lib/types/checker/checks/wazo-websocket.d.ts +0 -6
- package/lib/types/checker/checks/wazo-websocket.d.ts.map +0 -1
- package/lib/types/checker/checks/webrtc-transport.d.ts +0 -7
- package/lib/types/checker/checks/webrtc-transport.d.ts.map +0 -1
- package/lib/types/checker/checks/webrtc.d.ts +0 -6
- package/lib/types/checker/checks/webrtc.d.ts.map +0 -1
- package/lib/types/domain/AdHocAPIConference.d.ts +0 -54
- package/lib/types/domain/AdHocAPIConference.d.ts.map +0 -1
- package/lib/types/domain/Agent.d.ts +0 -31
- package/lib/types/domain/Agent.d.ts.map +0 -1
- package/lib/types/domain/BadResponse.d.ts +0 -11
- package/lib/types/domain/BadResponse.d.ts.map +0 -1
- package/lib/types/domain/Call.d.ts +0 -79
- package/lib/types/domain/Call.d.ts.map +0 -1
- package/lib/types/domain/CallLog.d.ts +0 -88
- package/lib/types/domain/CallLog.d.ts.map +0 -1
- package/lib/types/domain/CallSession.d.ts +0 -119
- package/lib/types/domain/CallSession.d.ts.map +0 -1
- package/lib/types/domain/CallerID.d.ts +0 -22
- package/lib/types/domain/CallerID.d.ts.map +0 -1
- package/lib/types/domain/ChatMessage.d.ts +0 -41
- package/lib/types/domain/ChatMessage.d.ts.map +0 -1
- package/lib/types/domain/ChatRoom.d.ts +0 -22
- package/lib/types/domain/ChatRoom.d.ts.map +0 -1
- package/lib/types/domain/Contact.d.ts.map +0 -1
- package/lib/types/domain/Country.d.ts +0 -21
- package/lib/types/domain/Country.d.ts.map +0 -1
- package/lib/types/domain/Device/DebugDevice.d.ts +0 -14
- package/lib/types/domain/Device/DebugDevice.d.ts.map +0 -1
- package/lib/types/domain/Device/Device.d.ts +0 -13
- package/lib/types/domain/Device/Device.d.ts.map +0 -1
- package/lib/types/domain/DirectorySource.d.ts +0 -13
- package/lib/types/domain/DirectorySource.d.ts.map +0 -1
- package/lib/types/domain/ExternalApp.d.ts +0 -22
- package/lib/types/domain/ExternalApp.d.ts.map +0 -1
- package/lib/types/domain/Features.d.ts +0 -26
- package/lib/types/domain/Features.d.ts.map +0 -1
- package/lib/types/domain/ForwardOption.d.ts +0 -28
- package/lib/types/domain/ForwardOption.d.ts.map +0 -1
- package/lib/types/domain/Incall.d.ts +0 -21
- package/lib/types/domain/Incall.d.ts.map +0 -1
- package/lib/types/domain/IndirectTransfer.d.ts +0 -31
- package/lib/types/domain/IndirectTransfer.d.ts.map +0 -1
- package/lib/types/domain/Line.d.ts +0 -35
- package/lib/types/domain/Line.d.ts.map +0 -1
- package/lib/types/domain/Meeting.d.ts +0 -45
- package/lib/types/domain/Meeting.d.ts.map +0 -1
- package/lib/types/domain/MeetingAuthorization.d.ts +0 -32
- package/lib/types/domain/MeetingAuthorization.d.ts.map +0 -1
- package/lib/types/domain/MeetingStatus.d.ts +0 -10
- package/lib/types/domain/MeetingStatus.d.ts.map +0 -1
- package/lib/types/domain/NotificationOptions.d.ts +0 -22
- package/lib/types/domain/NotificationOptions.d.ts.map +0 -1
- package/lib/types/domain/Phone/CTIPhone.d.ts +0 -79
- package/lib/types/domain/Phone/CTIPhone.d.ts.map +0 -1
- package/lib/types/domain/Phone/Phone.d.ts +0 -83
- package/lib/types/domain/Phone/Phone.d.ts.map +0 -1
- package/lib/types/domain/Phone/WebRTCPhone.d.ts +0 -183
- package/lib/types/domain/Phone/WebRTCPhone.d.ts.map +0 -1
- package/lib/types/domain/Profile.d.ts +0 -155
- package/lib/types/domain/Profile.d.ts.map +0 -1
- package/lib/types/domain/Recording.d.ts +0 -26
- package/lib/types/domain/Recording.d.ts.map +0 -1
- package/lib/types/domain/Relocation.d.ts +0 -23
- package/lib/types/domain/Relocation.d.ts.map +0 -1
- package/lib/types/domain/Room.d.ts +0 -33
- package/lib/types/domain/Room.d.ts.map +0 -1
- package/lib/types/domain/SFUNotAvailableError.d.ts +0 -4
- package/lib/types/domain/SFUNotAvailableError.d.ts.map +0 -1
- package/lib/types/domain/ServerError.d.ts +0 -6
- package/lib/types/domain/ServerError.d.ts.map +0 -1
- package/lib/types/domain/Session.d.ts +0 -100
- package/lib/types/domain/Session.d.ts.map +0 -1
- package/lib/types/domain/SipLine.d.ts +0 -54
- package/lib/types/domain/SipLine.d.ts.map +0 -1
- package/lib/types/domain/Subscription.d.ts +0 -43
- package/lib/types/domain/Subscription.d.ts.map +0 -1
- package/lib/types/domain/SwitchboardCall.d.ts +0 -62
- package/lib/types/domain/SwitchboardCall.d.ts.map +0 -1
- package/lib/types/domain/Voicemail.d.ts +0 -58
- package/lib/types/domain/Voicemail.d.ts.map +0 -1
- package/lib/types/domain/__tests__/Agent.test.d.ts +0 -2
- package/lib/types/domain/__tests__/Agent.test.d.ts.map +0 -1
- package/lib/types/domain/__tests__/Call.test.d.ts +0 -2
- package/lib/types/domain/__tests__/Call.test.d.ts.map +0 -1
- package/lib/types/domain/__tests__/CallLog.test.d.ts +0 -2
- package/lib/types/domain/__tests__/CallLog.test.d.ts.map +0 -1
- package/lib/types/domain/__tests__/CallSession.test.d.ts +0 -2
- package/lib/types/domain/__tests__/CallSession.test.d.ts.map +0 -1
- package/lib/types/domain/__tests__/Contact.test.d.ts +0 -2
- package/lib/types/domain/__tests__/Contact.test.d.ts.map +0 -1
- package/lib/types/domain/__tests__/IndirectTransfer.test.d.ts +0 -2
- package/lib/types/domain/__tests__/IndirectTransfer.test.d.ts.map +0 -1
- package/lib/types/domain/__tests__/Line.test.d.ts +0 -2
- package/lib/types/domain/__tests__/Line.test.d.ts.map +0 -1
- package/lib/types/domain/__tests__/Meeting.test.d.ts +0 -2
- package/lib/types/domain/__tests__/Meeting.test.d.ts.map +0 -1
- package/lib/types/domain/__tests__/MeetingAuthorization.test.d.ts +0 -2
- package/lib/types/domain/__tests__/MeetingAuthorization.test.d.ts.map +0 -1
- package/lib/types/domain/__tests__/Profile.test.d.ts +0 -2
- package/lib/types/domain/__tests__/Profile.test.d.ts.map +0 -1
- package/lib/types/domain/__tests__/Room.test.d.ts +0 -2
- package/lib/types/domain/__tests__/Room.test.d.ts.map +0 -1
- package/lib/types/domain/__tests__/Session.test.d.ts +0 -2
- package/lib/types/domain/__tests__/Session.test.d.ts.map +0 -1
- package/lib/types/domain/__tests__/SipLine.test.d.ts +0 -2
- package/lib/types/domain/__tests__/SipLine.test.d.ts.map +0 -1
- package/lib/types/domain/__tests__/Voicemail.test.d.ts +0 -2
- package/lib/types/domain/__tests__/Voicemail.test.d.ts.map +0 -1
- package/lib/types/domain/types.d.ts +0 -378
- package/lib/types/domain/types.d.ts.map +0 -1
- package/lib/types/index.d.ts.map +0 -1
- package/lib/types/lib/WazoSessionDescriptionHandler.d.ts +0 -31
- package/lib/types/lib/WazoSessionDescriptionHandler.d.ts.map +0 -1
- package/lib/types/pubkey.d.ts +0 -3
- package/lib/types/pubkey.d.ts.map +0 -1
- package/lib/types/service/CallApi.d.ts +0 -28
- package/lib/types/service/CallApi.d.ts.map +0 -1
- package/lib/types/service/IssueReporter.d.ts +0 -42
- package/lib/types/service/IssueReporter.d.ts.map +0 -1
- package/lib/types/service/__tests__/IssueReporter.test.d.ts +0 -2
- package/lib/types/service/__tests__/IssueReporter.test.d.ts.map +0 -1
- package/lib/types/service/getApiClient.d.ts.map +0 -1
- package/lib/types/simple/Auth.d.ts +0 -75
- package/lib/types/simple/Auth.d.ts.map +0 -1
- package/lib/types/simple/Configuration.d.ts +0 -7
- package/lib/types/simple/Configuration.d.ts.map +0 -1
- package/lib/types/simple/Directory.d.ts +0 -7
- package/lib/types/simple/Directory.d.ts.map +0 -1
- package/lib/types/simple/Phone.d.ts +0 -119
- package/lib/types/simple/Phone.d.ts.map +0 -1
- package/lib/types/simple/Websocket.d.ts +0 -21
- package/lib/types/simple/Websocket.d.ts.map +0 -1
- package/lib/types/simple/__tests__/Auth.test.d.ts +0 -2
- package/lib/types/simple/__tests__/Auth.test.d.ts.map +0 -1
- package/lib/types/simple/index.d.ts +0 -153
- package/lib/types/simple/index.d.ts.map +0 -1
- package/lib/types/simple/room/LocalParticipant.d.ts +0 -5
- package/lib/types/simple/room/LocalParticipant.d.ts.map +0 -1
- package/lib/types/simple/room/Participant.d.ts +0 -77
- package/lib/types/simple/room/Participant.d.ts.map +0 -1
- package/lib/types/simple/room/RemoteParticipant.d.ts +0 -7
- package/lib/types/simple/room/RemoteParticipant.d.ts.map +0 -1
- package/lib/types/simple/room/Room.d.ts +0 -127
- package/lib/types/simple/room/Room.d.ts.map +0 -1
- package/lib/types/simple/room/SipRoom.d.ts +0 -14
- package/lib/types/simple/room/SipRoom.d.ts.map +0 -1
- package/lib/types/simple/room/Stream.d.ts +0 -13
- package/lib/types/simple/room/Stream.d.ts.map +0 -1
- package/lib/types/simple/room/__tests__/Participant.test.d.ts +0 -2
- package/lib/types/simple/room/__tests__/Participant.test.d.ts.map +0 -1
- package/lib/types/simple/room/__tests__/RemoteParticipant.test.d.ts +0 -2
- package/lib/types/simple/room/__tests__/RemoteParticipant.test.d.ts.map +0 -1
- package/lib/types/simple/utils.d.ts +0 -3
- package/lib/types/simple/utils.d.ts.map +0 -1
- package/lib/types/types/WebSocketMessage.d.ts +0 -285
- package/lib/types/types/WebSocketMessage.d.ts.map +0 -1
- package/lib/types/utils/Emitter.d.ts +0 -18
- package/lib/types/utils/Emitter.d.ts.map +0 -1
- package/lib/types/utils/Heartbeat.d.ts +0 -22
- package/lib/types/utils/Heartbeat.d.ts.map +0 -1
- package/lib/types/utils/PhoneNumberUtil.d.ts +0 -7
- package/lib/types/utils/PhoneNumberUtil.d.ts.map +0 -1
- package/lib/types/utils/__tests__/Heartbeat.test.d.ts +0 -2
- package/lib/types/utils/__tests__/Heartbeat.test.d.ts.map +0 -1
- package/lib/types/utils/__tests__/PhoneNumberUtil.test.d.ts +0 -2
- package/lib/types/utils/__tests__/PhoneNumberUtil.test.d.ts.map +0 -1
- package/lib/types/utils/__tests__/api-requester.test.d.ts +0 -2
- package/lib/types/utils/__tests__/api-requester.test.d.ts.map +0 -1
- package/lib/types/utils/__tests__/array.test.d.ts +0 -2
- package/lib/types/utils/__tests__/array.test.d.ts.map +0 -1
- package/lib/types/utils/__tests__/compare-version.test.d.ts +0 -2
- package/lib/types/utils/__tests__/compare-version.test.d.ts.map +0 -1
- package/lib/types/utils/__tests__/object.test.d.ts +0 -2
- package/lib/types/utils/__tests__/object.test.d.ts.map +0 -1
- package/lib/types/utils/__tests__/sdp.test.d.ts +0 -2
- package/lib/types/utils/__tests__/sdp.test.d.ts.map +0 -1
- package/lib/types/utils/__tests__/string.test.d.ts +0 -2
- package/lib/types/utils/__tests__/string.test.d.ts.map +0 -1
- package/lib/types/utils/api-requester.d.ts +0 -48
- package/lib/types/utils/array.d.ts +0 -2
- package/lib/types/utils/array.d.ts.map +0 -1
- package/lib/types/utils/compare-version.d.ts +0 -3
- package/lib/types/utils/compare-version.d.ts.map +0 -1
- package/lib/types/utils/isMobile.d.ts +0 -3
- package/lib/types/utils/isMobile.d.ts.map +0 -1
- package/lib/types/utils/new-from.d.ts +0 -3
- package/lib/types/utils/new-from.d.ts.map +0 -1
- package/lib/types/utils/object.d.ts +0 -2
- package/lib/types/utils/object.d.ts.map +0 -1
- package/lib/types/utils/once.d.ts +0 -2
- package/lib/types/utils/once.d.ts.map +0 -1
- package/lib/types/utils/sdp.d.ts +0 -28
- package/lib/types/utils/sdp.d.ts.map +0 -1
- package/lib/types/utils/string.d.ts +0 -3
- package/lib/types/utils/string.d.ts.map +0 -1
- package/lib/types/utils/update-from.d.ts +0 -3
- package/lib/types/utils/update-from.d.ts.map +0 -1
- package/lib/types/utils/webrtc.d.ts +0 -15
- package/lib/types/utils/webrtc.d.ts.map +0 -1
- package/lib/types/web-rtc-client.d.ts +0 -198
- package/lib/types/web-rtc-client.d.ts.map +0 -1
- package/lib/types/websocket-client.d.ts +0 -138
- package/lib/types/websocket-client.d.ts.map +0 -1
- package/lib/utils/Emitter.js +0 -24
- package/lib/utils/Heartbeat.js +0 -66
- package/lib/utils/PhoneNumberUtil.js +0 -73
- package/lib/utils/__tests__/Heartbeat.test.js +0 -79
- package/lib/utils/__tests__/PhoneNumberUtil.test.js +0 -72
- package/lib/utils/__tests__/api-requester.test.js +0 -180
- package/lib/utils/__tests__/array.test.js +0 -20
- package/lib/utils/__tests__/compare-version.test.js +0 -15
- package/lib/utils/__tests__/object.test.js +0 -78
- package/lib/utils/__tests__/sdp.test.js +0 -188
- package/lib/utils/__tests__/string.test.js +0 -51
- package/lib/utils/api-requester.js +0 -201
- package/lib/utils/array.js +0 -13
- package/lib/utils/compare-version.js +0 -19
- package/lib/utils/isMobile.js +0 -5
- package/lib/utils/new-from.js +0 -9
- package/lib/utils/object.js +0 -14
- package/lib/utils/once.js +0 -18
- package/lib/utils/sdp.js +0 -115
- package/lib/utils/string.js +0 -17
- package/lib/utils/update-from.js +0 -12
- package/lib/utils/webrtc.js +0 -41
- package/lib/web-rtc-client.js +0 -2239
- package/lib/websocket-client.js +0 -390
- package/src/__tests__/api-client.test.ts +0 -315
- package/src/__tests__/web-rtc-client.test.ts +0 -198
- package/src/api/agentd.ts +0 -37
- package/src/api/amid.ts +0 -25
- package/src/api/application.ts +0 -96
- package/src/api/auth.ts +0 -305
- package/src/api/call-logd.ts +0 -38
- package/src/api/calld.ts +0 -185
- package/src/api/chatd.ts +0 -87
- package/src/api/confd.ts +0 -119
- package/src/api/ctid-ng.ts +0 -152
- package/src/api/dird.ts +0 -143
- package/src/api/webhookd.ts +0 -30
- package/src/api-client.ts +0 -233
- package/src/checker/Checker.ts +0 -73
- package/src/checker/checks/aor.ts +0 -34
- package/src/checker/checks/api.ts +0 -78
- package/src/checker/checks/ice-ipv4.ts +0 -80
- package/src/checker/checks/index.ts +0 -9
- package/src/checker/checks/symmetric-nat.ts +0 -69
- package/src/checker/checks/wazo-websocket.ts +0 -41
- package/src/checker/checks/webrtc-transport.ts +0 -42
- package/src/checker/checks/webrtc.ts +0 -48
- package/src/domain/AdHocAPIConference.ts +0 -166
- package/src/domain/Agent.ts +0 -68
- package/src/domain/BadResponse.ts +0 -29
- package/src/domain/Call.ts +0 -217
- package/src/domain/CallLog.ts +0 -265
- package/src/domain/CallSession.ts +0 -401
- package/src/domain/CallerID.ts +0 -49
- package/src/domain/ChatMessage.ts +0 -107
- package/src/domain/ChatRoom.ts +0 -55
- package/src/domain/Contact.ts +0 -851
- package/src/domain/Country.ts +0 -19
- package/src/domain/Device/DebugDevice.ts +0 -44
- package/src/domain/Device/Device.ts +0 -12
- package/src/domain/DirectorySource.ts +0 -13
- package/src/domain/ExternalApp.ts +0 -46
- package/src/domain/Features.ts +0 -105
- package/src/domain/ForwardOption.ts +0 -65
- package/src/domain/Incall.ts +0 -50
- package/src/domain/IndirectTransfer.ts +0 -73
- package/src/domain/Line.ts +0 -79
- package/src/domain/Meeting.ts +0 -113
- package/src/domain/MeetingAuthorization.ts +0 -81
- package/src/domain/MeetingStatus.ts +0 -23
- package/src/domain/NotificationOptions.ts +0 -68
- package/src/domain/Phone/CTIPhone.ts +0 -381
- package/src/domain/Phone/Phone.ts +0 -81
- package/src/domain/Phone/WebRTCPhone.ts +0 -1830
- package/src/domain/Profile.ts +0 -289
- package/src/domain/Recording.ts +0 -60
- package/src/domain/Relocation.ts +0 -45
- package/src/domain/Room.ts +0 -141
- package/src/domain/SFUNotAvailableError.ts +0 -7
- package/src/domain/ServerError.ts +0 -12
- package/src/domain/Session.ts +0 -297
- package/src/domain/SipLine.ts +0 -154
- package/src/domain/Subscription.ts +0 -95
- package/src/domain/SwitchboardCall.ts +0 -127
- package/src/domain/Voicemail.ts +0 -138
- package/src/domain/__tests__/Agent.test.ts +0 -38
- package/src/domain/__tests__/Call.test.ts +0 -26
- package/src/domain/__tests__/CallLog.test.ts +0 -203
- package/src/domain/__tests__/CallSession.test.ts +0 -80
- package/src/domain/__tests__/Contact.test.ts +0 -407
- package/src/domain/__tests__/IndirectTransfer.test.ts +0 -68
- package/src/domain/__tests__/Line.test.ts +0 -53
- package/src/domain/__tests__/Meeting.test.ts +0 -93
- package/src/domain/__tests__/MeetingAuthorization.test.ts +0 -50
- package/src/domain/__tests__/Profile.test.ts +0 -170
- package/src/domain/__tests__/Room.test.ts +0 -207
- package/src/domain/__tests__/Session.test.ts +0 -385
- package/src/domain/__tests__/SipLine.test.ts +0 -30
- package/src/domain/__tests__/Voicemail.test.ts +0 -91
- package/src/domain/types.ts +0 -331
- package/src/index.ts +0 -59
- package/src/lib/WazoSessionDescriptionHandler.ts +0 -532
- package/src/pubkey.ts +0 -11
- package/src/service/CallApi.ts +0 -86
- package/src/service/IssueReporter.ts +0 -434
- package/src/service/__tests__/IssueReporter.test.ts +0 -127
- package/src/service/getApiClient.ts +0 -106
- package/src/simple/Auth.ts +0 -496
- package/src/simple/Configuration.ts +0 -18
- package/src/simple/Directory.ts +0 -16
- package/src/simple/Phone.ts +0 -531
- package/src/simple/Websocket.ts +0 -107
- package/src/simple/__tests__/Auth.test.ts +0 -168
- package/src/simple/index.ts +0 -153
- package/src/simple/room/LocalParticipant.ts +0 -5
- package/src/simple/room/Participant.ts +0 -409
- package/src/simple/room/RemoteParticipant.ts +0 -15
- package/src/simple/room/Room.ts +0 -942
- package/src/simple/room/SipRoom.ts +0 -164
- package/src/simple/room/Stream.ts +0 -64
- package/src/simple/room/__tests__/Participant.test.ts +0 -73
- package/src/simple/room/__tests__/RemoteParticipant.test.ts +0 -15
- package/src/simple/utils.ts +0 -12
- package/src/types/WebSocketMessage.ts +0 -335
- package/src/types/global.d.ts +0 -33
- package/src/types/wazo.d.ts +0 -1
- package/src/utils/Emitter.ts +0 -34
- package/src/utils/Heartbeat.ts +0 -102
- package/src/utils/PhoneNumberUtil.ts +0 -81
- package/src/utils/__tests__/Heartbeat.test.ts +0 -66
- package/src/utils/__tests__/PhoneNumberUtil.test.ts +0 -79
- package/src/utils/__tests__/api-requester.test.ts +0 -180
- package/src/utils/__tests__/array.test.ts +0 -19
- package/src/utils/__tests__/compare-version.test.ts +0 -11
- package/src/utils/__tests__/object.test.ts +0 -77
- package/src/utils/__tests__/sdp.test.ts +0 -173
- package/src/utils/__tests__/string.test.ts +0 -55
- package/src/utils/api-requester.ts +0 -295
- package/src/utils/array.ts +0 -11
- package/src/utils/compare-version.ts +0 -21
- package/src/utils/isMobile.ts +0 -4
- package/src/utils/new-from.ts +0 -7
- package/src/utils/object.ts +0 -12
- package/src/utils/once.ts +0 -14
- package/src/utils/sdp.ts +0 -140
- package/src/utils/string.ts +0 -15
- package/src/utils/update-from.ts +0 -11
- package/src/utils/webrtc.ts +0 -56
- package/src/web-rtc-client.ts +0 -2687
- package/src/websocket-client.ts +0 -475
- /package/{esm → dist}/types/__tests__/api-client.test.d.ts +0 -0
- /package/{esm → dist}/types/__tests__/api-client.test.d.ts.map +0 -0
- /package/{esm → dist}/types/__tests__/web-rtc-client.test.d.ts +0 -0
- /package/{esm → dist}/types/__tests__/web-rtc-client.test.d.ts.map +0 -0
- /package/{esm → dist}/types/api/agentd.d.ts +0 -0
- /package/{esm → dist}/types/api/agentd.d.ts.map +0 -0
- /package/{esm → dist}/types/api/amid.d.ts +0 -0
- /package/{esm → dist}/types/api/amid.d.ts.map +0 -0
- /package/{esm → dist}/types/api/application.d.ts +0 -0
- /package/{esm → dist}/types/api/application.d.ts.map +0 -0
- /package/{esm → dist}/types/api/auth.d.ts +0 -0
- /package/{esm → dist}/types/api/auth.d.ts.map +0 -0
- /package/{esm → dist}/types/api/call-logd.d.ts +0 -0
- /package/{esm → dist}/types/api/call-logd.d.ts.map +0 -0
- /package/{esm → dist}/types/api/calld.d.ts +0 -0
- /package/{esm → dist}/types/api/calld.d.ts.map +0 -0
- /package/{esm → dist}/types/api/chatd.d.ts +0 -0
- /package/{esm → dist}/types/api/chatd.d.ts.map +0 -0
- /package/{esm → dist}/types/api/confd.d.ts +0 -0
- /package/{esm → dist}/types/api/confd.d.ts.map +0 -0
- /package/{esm → dist}/types/api/ctid-ng.d.ts +0 -0
- /package/{esm → dist}/types/api/ctid-ng.d.ts.map +0 -0
- /package/{esm → dist}/types/api/dird.d.ts +0 -0
- /package/{esm → dist}/types/api/dird.d.ts.map +0 -0
- /package/{esm → dist}/types/api/webhookd.d.ts +0 -0
- /package/{esm → dist}/types/api/webhookd.d.ts.map +0 -0
- /package/{esm → dist}/types/checker/Checker.d.ts +0 -0
- /package/{esm → dist}/types/checker/Checker.d.ts.map +0 -0
- /package/{esm → dist}/types/checker/checks/aor.d.ts +0 -0
- /package/{esm → dist}/types/checker/checks/aor.d.ts.map +0 -0
- /package/{esm → dist}/types/checker/checks/api.d.ts +0 -0
- /package/{esm → dist}/types/checker/checks/api.d.ts.map +0 -0
- /package/{esm → dist}/types/checker/checks/ice-ipv4.d.ts +0 -0
- /package/{esm → dist}/types/checker/checks/ice-ipv4.d.ts.map +0 -0
- /package/{esm → dist}/types/checker/checks/index.d.ts +0 -0
- /package/{esm → dist}/types/checker/checks/index.d.ts.map +0 -0
- /package/{esm → dist}/types/checker/checks/symmetric-nat.d.ts +0 -0
- /package/{esm → dist}/types/checker/checks/symmetric-nat.d.ts.map +0 -0
- /package/{esm → dist}/types/checker/checks/wazo-websocket.d.ts +0 -0
- /package/{esm → dist}/types/checker/checks/wazo-websocket.d.ts.map +0 -0
- /package/{esm → dist}/types/checker/checks/webrtc-transport.d.ts +0 -0
- /package/{esm → dist}/types/checker/checks/webrtc-transport.d.ts.map +0 -0
- /package/{esm → dist}/types/checker/checks/webrtc.d.ts +0 -0
- /package/{esm → dist}/types/checker/checks/webrtc.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/AdHocAPIConference.d.ts +0 -0
- /package/{esm → dist}/types/domain/AdHocAPIConference.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/Agent.d.ts +0 -0
- /package/{esm → dist}/types/domain/Agent.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/BadResponse.d.ts +0 -0
- /package/{esm → dist}/types/domain/BadResponse.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/Call.d.ts +0 -0
- /package/{esm → dist}/types/domain/Call.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/CallLog.d.ts +0 -0
- /package/{esm → dist}/types/domain/CallLog.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/CallSession.d.ts +0 -0
- /package/{esm → dist}/types/domain/CallSession.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/CallerID.d.ts +0 -0
- /package/{esm → dist}/types/domain/CallerID.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/ChatMessage.d.ts +0 -0
- /package/{esm → dist}/types/domain/ChatMessage.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/ChatRoom.d.ts +0 -0
- /package/{esm → dist}/types/domain/ChatRoom.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/Country.d.ts +0 -0
- /package/{esm → dist}/types/domain/Country.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/Device/DebugDevice.d.ts +0 -0
- /package/{esm → dist}/types/domain/Device/DebugDevice.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/Device/Device.d.ts +0 -0
- /package/{esm → dist}/types/domain/Device/Device.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/DirectorySource.d.ts +0 -0
- /package/{esm → dist}/types/domain/DirectorySource.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/ExternalApp.d.ts +0 -0
- /package/{esm → dist}/types/domain/ExternalApp.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/Features.d.ts +0 -0
- /package/{esm → dist}/types/domain/Features.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/ForwardOption.d.ts +0 -0
- /package/{esm → dist}/types/domain/ForwardOption.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/Incall.d.ts +0 -0
- /package/{esm → dist}/types/domain/Incall.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/IndirectTransfer.d.ts +0 -0
- /package/{esm → dist}/types/domain/IndirectTransfer.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/Line.d.ts +0 -0
- /package/{esm → dist}/types/domain/Line.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/Meeting.d.ts +0 -0
- /package/{esm → dist}/types/domain/Meeting.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/MeetingAuthorization.d.ts +0 -0
- /package/{esm → dist}/types/domain/MeetingAuthorization.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/MeetingStatus.d.ts +0 -0
- /package/{esm → dist}/types/domain/MeetingStatus.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/NotificationOptions.d.ts +0 -0
- /package/{esm → dist}/types/domain/NotificationOptions.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/Phone/CTIPhone.d.ts +0 -0
- /package/{esm → dist}/types/domain/Phone/CTIPhone.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/Phone/Phone.d.ts +0 -0
- /package/{esm → dist}/types/domain/Phone/Phone.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/Phone/WebRTCPhone.d.ts +0 -0
- /package/{esm → dist}/types/domain/Phone/WebRTCPhone.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/Profile.d.ts +0 -0
- /package/{esm → dist}/types/domain/Profile.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/Recording.d.ts +0 -0
- /package/{esm → dist}/types/domain/Recording.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/Relocation.d.ts +0 -0
- /package/{esm → dist}/types/domain/Relocation.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/Room.d.ts +0 -0
- /package/{esm → dist}/types/domain/Room.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/SFUNotAvailableError.d.ts +0 -0
- /package/{esm → dist}/types/domain/SFUNotAvailableError.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/ServerError.d.ts +0 -0
- /package/{esm → dist}/types/domain/ServerError.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/Session.d.ts +0 -0
- /package/{esm → dist}/types/domain/Session.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/SipLine.d.ts +0 -0
- /package/{esm → dist}/types/domain/SipLine.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/Subscription.d.ts +0 -0
- /package/{esm → dist}/types/domain/Subscription.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/SwitchboardCall.d.ts +0 -0
- /package/{esm → dist}/types/domain/SwitchboardCall.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/Voicemail.d.ts +0 -0
- /package/{esm → dist}/types/domain/Voicemail.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/__tests__/Agent.test.d.ts +0 -0
- /package/{esm → dist}/types/domain/__tests__/Agent.test.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/__tests__/Call.test.d.ts +0 -0
- /package/{esm → dist}/types/domain/__tests__/Call.test.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/__tests__/CallLog.test.d.ts +0 -0
- /package/{esm → dist}/types/domain/__tests__/CallLog.test.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/__tests__/CallSession.test.d.ts +0 -0
- /package/{esm → dist}/types/domain/__tests__/CallSession.test.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/__tests__/Contact.test.d.ts +0 -0
- /package/{esm → dist}/types/domain/__tests__/Contact.test.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/__tests__/IndirectTransfer.test.d.ts +0 -0
- /package/{esm → dist}/types/domain/__tests__/IndirectTransfer.test.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/__tests__/Line.test.d.ts +0 -0
- /package/{esm → dist}/types/domain/__tests__/Line.test.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/__tests__/Meeting.test.d.ts +0 -0
- /package/{esm → dist}/types/domain/__tests__/Meeting.test.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/__tests__/MeetingAuthorization.test.d.ts +0 -0
- /package/{esm → dist}/types/domain/__tests__/MeetingAuthorization.test.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/__tests__/Profile.test.d.ts +0 -0
- /package/{esm → dist}/types/domain/__tests__/Profile.test.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/__tests__/Room.test.d.ts +0 -0
- /package/{esm → dist}/types/domain/__tests__/Room.test.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/__tests__/Session.test.d.ts +0 -0
- /package/{esm → dist}/types/domain/__tests__/Session.test.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/__tests__/SipLine.test.d.ts +0 -0
- /package/{esm → dist}/types/domain/__tests__/SipLine.test.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/__tests__/Voicemail.test.d.ts +0 -0
- /package/{esm → dist}/types/domain/__tests__/Voicemail.test.d.ts.map +0 -0
- /package/{esm → dist}/types/domain/types.d.ts +0 -0
- /package/{esm → dist}/types/domain/types.d.ts.map +0 -0
- /package/{esm → dist}/types/lib/WazoSessionDescriptionHandler.d.ts +0 -0
- /package/{esm → dist}/types/lib/WazoSessionDescriptionHandler.d.ts.map +0 -0
- /package/{esm → dist}/types/pubkey.d.ts +0 -0
- /package/{esm → dist}/types/pubkey.d.ts.map +0 -0
- /package/{esm → dist}/types/service/CallApi.d.ts +0 -0
- /package/{esm → dist}/types/service/CallApi.d.ts.map +0 -0
- /package/{esm → dist}/types/service/IssueReporter.d.ts +0 -0
- /package/{esm → dist}/types/service/IssueReporter.d.ts.map +0 -0
- /package/{esm → dist}/types/service/__tests__/IssueReporter.test.d.ts +0 -0
- /package/{esm → dist}/types/service/__tests__/IssueReporter.test.d.ts.map +0 -0
- /package/{esm → dist}/types/simple/Auth.d.ts +0 -0
- /package/{esm → dist}/types/simple/Auth.d.ts.map +0 -0
- /package/{esm → dist}/types/simple/Configuration.d.ts +0 -0
- /package/{esm → dist}/types/simple/Configuration.d.ts.map +0 -0
- /package/{esm → dist}/types/simple/Directory.d.ts +0 -0
- /package/{esm → dist}/types/simple/Directory.d.ts.map +0 -0
- /package/{esm → dist}/types/simple/Phone.d.ts +0 -0
- /package/{esm → dist}/types/simple/Phone.d.ts.map +0 -0
- /package/{esm → dist}/types/simple/Websocket.d.ts +0 -0
- /package/{esm → dist}/types/simple/Websocket.d.ts.map +0 -0
- /package/{esm → dist}/types/simple/__tests__/Auth.test.d.ts +0 -0
- /package/{esm → dist}/types/simple/__tests__/Auth.test.d.ts.map +0 -0
- /package/{esm → dist}/types/simple/index.d.ts.map +0 -0
- /package/{esm → dist}/types/simple/room/LocalParticipant.d.ts +0 -0
- /package/{esm → dist}/types/simple/room/LocalParticipant.d.ts.map +0 -0
- /package/{esm → dist}/types/simple/room/Participant.d.ts +0 -0
- /package/{esm → dist}/types/simple/room/Participant.d.ts.map +0 -0
- /package/{esm → dist}/types/simple/room/RemoteParticipant.d.ts +0 -0
- /package/{esm → dist}/types/simple/room/RemoteParticipant.d.ts.map +0 -0
- /package/{esm → dist}/types/simple/room/Room.d.ts +0 -0
- /package/{esm → dist}/types/simple/room/Room.d.ts.map +0 -0
- /package/{esm → dist}/types/simple/room/SipRoom.d.ts +0 -0
- /package/{esm → dist}/types/simple/room/SipRoom.d.ts.map +0 -0
- /package/{esm → dist}/types/simple/room/Stream.d.ts +0 -0
- /package/{esm → dist}/types/simple/room/Stream.d.ts.map +0 -0
- /package/{esm → dist}/types/simple/room/__tests__/Participant.test.d.ts +0 -0
- /package/{esm → dist}/types/simple/room/__tests__/Participant.test.d.ts.map +0 -0
- /package/{esm → dist}/types/simple/room/__tests__/RemoteParticipant.test.d.ts +0 -0
- /package/{esm → dist}/types/simple/room/__tests__/RemoteParticipant.test.d.ts.map +0 -0
- /package/{esm → dist}/types/simple/utils.d.ts +0 -0
- /package/{esm → dist}/types/simple/utils.d.ts.map +0 -0
- /package/{esm → dist}/types/types/WebSocketMessage.d.ts +0 -0
- /package/{esm → dist}/types/types/WebSocketMessage.d.ts.map +0 -0
- /package/{esm → dist}/types/utils/Emitter.d.ts +0 -0
- /package/{esm → dist}/types/utils/Emitter.d.ts.map +0 -0
- /package/{esm → dist}/types/utils/Heartbeat.d.ts +0 -0
- /package/{esm → dist}/types/utils/Heartbeat.d.ts.map +0 -0
- /package/{esm → dist}/types/utils/PhoneNumberUtil.d.ts +0 -0
- /package/{esm → dist}/types/utils/PhoneNumberUtil.d.ts.map +0 -0
- /package/{esm → dist}/types/utils/__tests__/Heartbeat.test.d.ts +0 -0
- /package/{esm → dist}/types/utils/__tests__/Heartbeat.test.d.ts.map +0 -0
- /package/{esm → dist}/types/utils/__tests__/PhoneNumberUtil.test.d.ts +0 -0
- /package/{esm → dist}/types/utils/__tests__/PhoneNumberUtil.test.d.ts.map +0 -0
- /package/{esm → dist}/types/utils/__tests__/api-requester.test.d.ts +0 -0
- /package/{esm → dist}/types/utils/__tests__/api-requester.test.d.ts.map +0 -0
- /package/{esm → dist}/types/utils/__tests__/array.test.d.ts +0 -0
- /package/{esm → dist}/types/utils/__tests__/array.test.d.ts.map +0 -0
- /package/{esm → dist}/types/utils/__tests__/compare-version.test.d.ts +0 -0
- /package/{esm → dist}/types/utils/__tests__/compare-version.test.d.ts.map +0 -0
- /package/{esm → dist}/types/utils/__tests__/object.test.d.ts +0 -0
- /package/{esm → dist}/types/utils/__tests__/object.test.d.ts.map +0 -0
- /package/{esm → dist}/types/utils/__tests__/sdp.test.d.ts +0 -0
- /package/{esm → dist}/types/utils/__tests__/sdp.test.d.ts.map +0 -0
- /package/{esm → dist}/types/utils/__tests__/string.test.d.ts +0 -0
- /package/{esm → dist}/types/utils/__tests__/string.test.d.ts.map +0 -0
- /package/{esm → dist}/types/utils/api-requester.d.ts +0 -0
- /package/{esm → dist}/types/utils/array.d.ts +0 -0
- /package/{esm → dist}/types/utils/array.d.ts.map +0 -0
- /package/{esm → dist}/types/utils/compare-version.d.ts +0 -0
- /package/{esm → dist}/types/utils/compare-version.d.ts.map +0 -0
- /package/{esm → dist}/types/utils/isMobile.d.ts +0 -0
- /package/{esm → dist}/types/utils/isMobile.d.ts.map +0 -0
- /package/{esm → dist}/types/utils/new-from.d.ts +0 -0
- /package/{esm → dist}/types/utils/new-from.d.ts.map +0 -0
- /package/{esm → dist}/types/utils/object.d.ts +0 -0
- /package/{esm → dist}/types/utils/object.d.ts.map +0 -0
- /package/{esm → dist}/types/utils/once.d.ts +0 -0
- /package/{esm → dist}/types/utils/once.d.ts.map +0 -0
- /package/{esm → dist}/types/utils/sdp.d.ts +0 -0
- /package/{esm → dist}/types/utils/sdp.d.ts.map +0 -0
- /package/{esm → dist}/types/utils/string.d.ts +0 -0
- /package/{esm → dist}/types/utils/string.d.ts.map +0 -0
- /package/{esm → dist}/types/utils/update-from.d.ts +0 -0
- /package/{esm → dist}/types/utils/update-from.d.ts.map +0 -0
- /package/{esm → dist}/types/utils/webrtc.d.ts +0 -0
- /package/{esm → dist}/types/utils/webrtc.d.ts.map +0 -0
- /package/{esm → dist}/types/web-rtc-client.d.ts +0 -0
- /package/{esm → dist}/types/web-rtc-client.d.ts.map +0 -0
- /package/{esm → dist}/types/websocket-client.d.ts +0 -0
- /package/{esm → dist}/types/websocket-client.d.ts.map +0 -0
package/esm/web-rtc-client.js
DELETED
|
@@ -1,2200 +0,0 @@
|
|
|
1
|
-
/* eslint-disable class-methods-use-this, no-param-reassign, max-classes-per-file, no-underscore-dangle */
|
|
2
|
-
/* global window, document, navigator */
|
|
3
|
-
import 'webrtc-adapter';
|
|
4
|
-
import { UserAgentState } from 'sip.js/lib/api/user-agent-state';
|
|
5
|
-
import { Parser } from 'sip.js/lib/core/messages/parser';
|
|
6
|
-
import { C } from 'sip.js/lib/core/messages/methods/constants';
|
|
7
|
-
import { URI } from 'sip.js/lib/grammar/uri';
|
|
8
|
-
import { UserAgent } from 'sip.js/lib/api/user-agent';
|
|
9
|
-
import { holdModifier, stripVideo } from 'sip.js/lib/platform/web/modifiers/modifiers';
|
|
10
|
-
import { SessionDialog } from 'sip.js/lib/core/dialogs/session-dialog';
|
|
11
|
-
import { Messager } from 'sip.js/lib/api/messager';
|
|
12
|
-
import { RegistererState } from 'sip.js/lib/api/registerer-state';
|
|
13
|
-
import { SessionState } from 'sip.js/lib/api/session-state';
|
|
14
|
-
import { TransportState } from 'sip.js/lib/api/transport-state';
|
|
15
|
-
import { defaultPeerConnectionConfiguration } from 'sip.js/lib/platform/web/session-description-handler/peer-connection-configuration-default';
|
|
16
|
-
import getStats from 'getstats';
|
|
17
|
-
import { Inviter, Invitation, Registerer } from 'sip.js/lib/api';
|
|
18
|
-
import WazoSessionDescriptionHandler, { wazoMediaStreamFactory } from './lib/WazoSessionDescriptionHandler';
|
|
19
|
-
import Emitter from './utils/Emitter';
|
|
20
|
-
import ApiClient from './api-client';
|
|
21
|
-
import IssueReporter from './service/IssueReporter';
|
|
22
|
-
import Heartbeat from './utils/Heartbeat';
|
|
23
|
-
import { getVideoDirection, hasAnActiveVideo } from './utils/sdp';
|
|
24
|
-
import { lastIndexOf } from './utils/array';
|
|
25
|
-
// We need to replace 0.0.0.0 to 127.0.0.1 in the sdp to avoid MOH during a createOffer.
|
|
26
|
-
export const replaceLocalIpModifier = (description) => Promise.resolve({
|
|
27
|
-
...JSON.parse(JSON.stringify(description)),
|
|
28
|
-
sdp: description.sdp.replace('c=IN IP4 0.0.0.0', 'c=IN IP4 127.0.0.1'),
|
|
29
|
-
});
|
|
30
|
-
const DEFAULT_ICE_TIMEOUT = 3000;
|
|
31
|
-
const SEND_STATS_DELAY = 5000;
|
|
32
|
-
const states = ['STATUS_NULL', 'STATUS_NEW', 'STATUS_CONNECTING', 'STATUS_CONNECTED', 'STATUS_COMPLETED'];
|
|
33
|
-
const logger = IssueReporter ? IssueReporter.loggerFor('webrtc-client') : console;
|
|
34
|
-
const statsLogger = IssueReporter ? IssueReporter.loggerFor('webrtc-stats') : console;
|
|
35
|
-
// events
|
|
36
|
-
const REGISTERED = 'registered';
|
|
37
|
-
const UNREGISTERED = 'unregistered';
|
|
38
|
-
const REGISTRATION_FAILED = 'registrationFailed';
|
|
39
|
-
const INVITE = 'invite';
|
|
40
|
-
const CONNECTED = 'connected';
|
|
41
|
-
const DISCONNECTED = 'disconnected';
|
|
42
|
-
const TRANSPORT_ERROR = 'transportError';
|
|
43
|
-
const MESSAGE = 'message';
|
|
44
|
-
const ACCEPTED = 'accepted';
|
|
45
|
-
const REJECTED = 'rejected';
|
|
46
|
-
const ON_TRACK = 'onTrack';
|
|
47
|
-
const ON_PROGRESS = 'onProgress';
|
|
48
|
-
const ON_EARLY_MEDIA = 'onEarlyMedia';
|
|
49
|
-
const ON_REINVITE = 'reinvite';
|
|
50
|
-
const ON_ERROR = 'onError';
|
|
51
|
-
const ON_SCREEN_SHARING_REINVITE = 'onScreenSharingReinvite';
|
|
52
|
-
const ON_NETWORK_STATS = 'onNetworkStats';
|
|
53
|
-
const ON_DISCONNECTED = 'onDisconnected';
|
|
54
|
-
export const events = [REGISTERED, UNREGISTERED, REGISTRATION_FAILED, INVITE];
|
|
55
|
-
export const transportEvents = [CONNECTED, DISCONNECTED, TRANSPORT_ERROR, MESSAGE];
|
|
56
|
-
export class CanceledCallError extends Error {
|
|
57
|
-
}
|
|
58
|
-
const MAX_REGISTER_TRIES = 5;
|
|
59
|
-
// setting a 24hr timeout and letting the backend define the actual value
|
|
60
|
-
const NO_ANSWER_TIMEOUT = 60 * 60 * 24; // in seconds
|
|
61
|
-
export default class WebRTCClient extends Emitter {
|
|
62
|
-
clientId;
|
|
63
|
-
config;
|
|
64
|
-
uaConfigOverrides;
|
|
65
|
-
userAgent;
|
|
66
|
-
registerer;
|
|
67
|
-
hasAudio;
|
|
68
|
-
audio;
|
|
69
|
-
audioElements;
|
|
70
|
-
video;
|
|
71
|
-
audioStreams;
|
|
72
|
-
audioOutputDeviceId;
|
|
73
|
-
audioOutputVolume;
|
|
74
|
-
heldSessions;
|
|
75
|
-
connectionPromise;
|
|
76
|
-
_boundOnHeartbeat;
|
|
77
|
-
heartbeat;
|
|
78
|
-
heartbeatTimeoutCb;
|
|
79
|
-
heartbeatCb;
|
|
80
|
-
statsIntervals;
|
|
81
|
-
sipSessions;
|
|
82
|
-
conferences;
|
|
83
|
-
skipRegister;
|
|
84
|
-
networkMonitoringInterval;
|
|
85
|
-
sessionNetworkStats;
|
|
86
|
-
forceClosed;
|
|
87
|
-
// sugar
|
|
88
|
-
ON_USER_AGENT;
|
|
89
|
-
REGISTERED;
|
|
90
|
-
UNREGISTERED;
|
|
91
|
-
REGISTRATION_FAILED;
|
|
92
|
-
INVITE;
|
|
93
|
-
CONNECTED;
|
|
94
|
-
DISCONNECTED;
|
|
95
|
-
TRANSPORT_ERROR;
|
|
96
|
-
MESSAGE;
|
|
97
|
-
ACCEPTED;
|
|
98
|
-
REJECTED;
|
|
99
|
-
ON_TRACK;
|
|
100
|
-
ON_REINVITE;
|
|
101
|
-
ON_ERROR;
|
|
102
|
-
ON_SCREEN_SHARING_REINVITE;
|
|
103
|
-
ON_NETWORK_STATS;
|
|
104
|
-
ON_EARLY_MEDIA;
|
|
105
|
-
ON_PROGRESS;
|
|
106
|
-
ON_DISCONNECTED;
|
|
107
|
-
static isAPrivateIp(ip) {
|
|
108
|
-
const regex = /^(?:10|127|172\.(?:1[6-9]|2[0-9]|3[01])|192\.168)\..*/;
|
|
109
|
-
return regex.exec(ip) == null;
|
|
110
|
-
}
|
|
111
|
-
static getIceServers(ip) {
|
|
112
|
-
if (WebRTCClient.isAPrivateIp(ip)) {
|
|
113
|
-
return [{
|
|
114
|
-
urls: ['stun:stun.l.google.com:19302', 'stun:stun4.l.google.com:19302'],
|
|
115
|
-
}];
|
|
116
|
-
}
|
|
117
|
-
return [];
|
|
118
|
-
}
|
|
119
|
-
constructor(config, session, uaConfigOverrides) {
|
|
120
|
-
super();
|
|
121
|
-
// For debug purpose
|
|
122
|
-
this.clientId = Math.ceil(Math.random() * 1000);
|
|
123
|
-
logger.info('sdk webrtc constructor', { clientId: this.clientId });
|
|
124
|
-
this.uaConfigOverrides = uaConfigOverrides;
|
|
125
|
-
this.config = config;
|
|
126
|
-
this.skipRegister = config.skipRegister;
|
|
127
|
-
this._buildConfig(config, session).then((newConfig) => {
|
|
128
|
-
this.config = newConfig;
|
|
129
|
-
this.userAgent = this.createUserAgent(uaConfigOverrides);
|
|
130
|
-
});
|
|
131
|
-
this.audioOutputDeviceId = config.audioDeviceOutput;
|
|
132
|
-
this.audioOutputVolume = config.audioOutputVolume || 1;
|
|
133
|
-
if (config.media) {
|
|
134
|
-
this.configureMedia(config.media);
|
|
135
|
-
this.setMediaConstraints({
|
|
136
|
-
audio: config.media.audio,
|
|
137
|
-
video: config.media.video,
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
this.heldSessions = {};
|
|
141
|
-
this.statsIntervals = {};
|
|
142
|
-
this.connectionPromise = null;
|
|
143
|
-
this.sipSessions = {};
|
|
144
|
-
this.conferences = {};
|
|
145
|
-
this.networkMonitoringInterval = {};
|
|
146
|
-
this.sessionNetworkStats = {};
|
|
147
|
-
this.forceClosed = false;
|
|
148
|
-
this._boundOnHeartbeat = this._onHeartbeat.bind(this);
|
|
149
|
-
this.heartbeat = new Heartbeat(config.heartbeatDelay, config.heartbeatTimeout, config.maxHeartbeats);
|
|
150
|
-
this.heartbeat.setSendHeartbeat(this.pingServer.bind(this));
|
|
151
|
-
this.heartbeat.setOnHeartbeatTimeout(this._onHeartbeatTimeout.bind(this));
|
|
152
|
-
// sugar
|
|
153
|
-
this.REGISTERED = REGISTERED;
|
|
154
|
-
this.UNREGISTERED = UNREGISTERED;
|
|
155
|
-
this.REGISTRATION_FAILED = REGISTRATION_FAILED;
|
|
156
|
-
this.INVITE = INVITE;
|
|
157
|
-
this.CONNECTED = CONNECTED;
|
|
158
|
-
this.DISCONNECTED = DISCONNECTED;
|
|
159
|
-
this.TRANSPORT_ERROR = TRANSPORT_ERROR;
|
|
160
|
-
this.MESSAGE = MESSAGE;
|
|
161
|
-
this.ACCEPTED = ACCEPTED;
|
|
162
|
-
this.REJECTED = REJECTED;
|
|
163
|
-
this.ON_TRACK = ON_TRACK;
|
|
164
|
-
this.ON_REINVITE = ON_REINVITE;
|
|
165
|
-
this.ON_ERROR = ON_ERROR;
|
|
166
|
-
this.ON_SCREEN_SHARING_REINVITE = ON_SCREEN_SHARING_REINVITE;
|
|
167
|
-
this.ON_NETWORK_STATS = ON_NETWORK_STATS;
|
|
168
|
-
this.ON_DISCONNECTED = ON_DISCONNECTED;
|
|
169
|
-
this.ON_EARLY_MEDIA = ON_EARLY_MEDIA;
|
|
170
|
-
this.ON_PROGRESS = ON_PROGRESS;
|
|
171
|
-
}
|
|
172
|
-
configureMedia(media) {
|
|
173
|
-
this.hasAudio = !!media.audio;
|
|
174
|
-
this.audioStreams = {};
|
|
175
|
-
this.audioElements = {};
|
|
176
|
-
}
|
|
177
|
-
setMediaConstraints(media) {
|
|
178
|
-
this.video = media.video;
|
|
179
|
-
this.audio = media.audio;
|
|
180
|
-
}
|
|
181
|
-
createUserAgent(uaConfigOverrides) {
|
|
182
|
-
const uaOptions = this._createUaOptions(uaConfigOverrides);
|
|
183
|
-
logger.info('sdk webrtc, creating UA', {
|
|
184
|
-
uaOptions: { ...uaOptions, authorizationPassword: `${uaOptions?.authorizationPassword?.slice(0, 5)}xxxx` },
|
|
185
|
-
clientId: this.clientId,
|
|
186
|
-
});
|
|
187
|
-
uaOptions.delegate = {
|
|
188
|
-
onConnect: this.onConnect.bind(this),
|
|
189
|
-
onDisconnect: this.onDisconnect.bind(this),
|
|
190
|
-
onInvite: (invitation) => {
|
|
191
|
-
logger.info('sdk webrtc on invite', {
|
|
192
|
-
method: 'delegate.onInvite',
|
|
193
|
-
clientId: this.clientId,
|
|
194
|
-
id: this.getSipSessionId(invitation),
|
|
195
|
-
remoteURI: invitation.remoteURI,
|
|
196
|
-
});
|
|
197
|
-
this._setupSession(invitation);
|
|
198
|
-
const shouldAutoAnswer = !!invitation.request.getHeader('alert-info');
|
|
199
|
-
this.eventEmitter.emit(INVITE, invitation, this.sessionWantsToDoVideo(invitation), shouldAutoAnswer);
|
|
200
|
-
},
|
|
201
|
-
};
|
|
202
|
-
const ua = new UserAgent(uaOptions);
|
|
203
|
-
ua.start();
|
|
204
|
-
if (ua.transport && ua.transport.connectPromise) {
|
|
205
|
-
ua.transport.connectPromise.catch((e) => {
|
|
206
|
-
logger.warn('Transport connect error', e);
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
ua.transport.onMessage = (rawMessage) => {
|
|
210
|
-
const message = Parser.parseMessage(rawMessage, ua.transport.logger);
|
|
211
|
-
// We have to re-sent the message to the UA ...
|
|
212
|
-
// @ts-ignore: private
|
|
213
|
-
ua.onTransportMessage(rawMessage);
|
|
214
|
-
// And now do what we want with the message
|
|
215
|
-
this.eventEmitter.emit(MESSAGE, message);
|
|
216
|
-
if (message && message.method === C.MESSAGE) {
|
|
217
|
-
// We have to manually reply to MESSAGE with a 200 OK or Asterisk will hangup.
|
|
218
|
-
ua.userAgentCore.replyStateless(message, {
|
|
219
|
-
statusCode: 200,
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
};
|
|
223
|
-
return ua;
|
|
224
|
-
}
|
|
225
|
-
isConnected() {
|
|
226
|
-
return Boolean(this.userAgent?.isConnected());
|
|
227
|
-
}
|
|
228
|
-
isConnecting() {
|
|
229
|
-
return this.userAgent?.transport?.state === TransportState.Connecting;
|
|
230
|
-
}
|
|
231
|
-
isRegistered() {
|
|
232
|
-
return Boolean(this.registerer && this.registerer.state === RegistererState.Registered);
|
|
233
|
-
}
|
|
234
|
-
onConnect() {
|
|
235
|
-
logger.info('sdk webrtc connected', { method: 'delegate.onConnect', clientId: this.clientId });
|
|
236
|
-
this.eventEmitter.emit(CONNECTED);
|
|
237
|
-
// @ts-ignore: private
|
|
238
|
-
if (!this.isRegistered() && this.registerer?.waiting) {
|
|
239
|
-
// @ts-ignore: private
|
|
240
|
-
this.registerer.waitingToggle(false);
|
|
241
|
-
}
|
|
242
|
-
return this.register();
|
|
243
|
-
}
|
|
244
|
-
async onDisconnect(error) {
|
|
245
|
-
logger.info('sdk webrtc disconnected', { method: 'delegate.onConnect', clientId: this.clientId, error });
|
|
246
|
-
this.connectionPromise = null;
|
|
247
|
-
// The UA will attempt to reconnect automatically when an error occurred
|
|
248
|
-
this.eventEmitter.emit(DISCONNECTED, error);
|
|
249
|
-
if (this.isRegistered()) {
|
|
250
|
-
await this.unregister();
|
|
251
|
-
// @ts-ignore: private
|
|
252
|
-
if (this.registerer?.waiting) {
|
|
253
|
-
// @ts-ignore: private
|
|
254
|
-
this.registerer.waitingToggle(false);
|
|
255
|
-
}
|
|
256
|
-
this.eventEmitter.emit(UNREGISTERED);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
async register(tries = 0) {
|
|
260
|
-
const logInfo = {
|
|
261
|
-
clientId: this.clientId,
|
|
262
|
-
userAgent: !!this.userAgent,
|
|
263
|
-
registered: this.isRegistered(),
|
|
264
|
-
connectionPromise: !!this.connectionPromise,
|
|
265
|
-
registerer: !!this.registerer,
|
|
266
|
-
// @ts-ignore: private
|
|
267
|
-
waiting: this.registerer && this.registerer.waiting,
|
|
268
|
-
tries,
|
|
269
|
-
skipRegister: this.skipRegister,
|
|
270
|
-
};
|
|
271
|
-
this.forceClosed = false;
|
|
272
|
-
if (this.skipRegister) {
|
|
273
|
-
logger.info('sdk webrtc skip register...', logInfo);
|
|
274
|
-
return Promise.resolve();
|
|
275
|
-
}
|
|
276
|
-
logger.info('sdk webrtc registering...', logInfo);
|
|
277
|
-
if (!this.userAgent) {
|
|
278
|
-
logger.info('sdk webrtc recreating User Agent');
|
|
279
|
-
this.userAgent = this.createUserAgent(this.uaConfigOverrides);
|
|
280
|
-
}
|
|
281
|
-
if (!this.userAgent || this.isRegistered()) {
|
|
282
|
-
logger.info('sdk webrtc registering aborted, already registered or no UA can be created');
|
|
283
|
-
return Promise.resolve();
|
|
284
|
-
}
|
|
285
|
-
// @ts-ignore: private
|
|
286
|
-
if (this.connectionPromise || this.registerer?.waiting) {
|
|
287
|
-
logger.info('sdk webrtc registering aborted due to a registration in progress.', { clientId: this.clientId });
|
|
288
|
-
return Promise.resolve();
|
|
289
|
-
}
|
|
290
|
-
const registerOptions = this._isWeb() ? {} : {
|
|
291
|
-
extraContactHeaderParams: ['mobility=mobile'],
|
|
292
|
-
};
|
|
293
|
-
const onRegisterFailed = () => {
|
|
294
|
-
logger.info('sdk webrtc registering failed', {
|
|
295
|
-
tries,
|
|
296
|
-
clientId: this.clientId,
|
|
297
|
-
registerer: !!this.registerer,
|
|
298
|
-
forceClosed: this.forceClosed,
|
|
299
|
-
});
|
|
300
|
-
if (this.forceClosed) {
|
|
301
|
-
return;
|
|
302
|
-
}
|
|
303
|
-
this.connectionPromise = null;
|
|
304
|
-
// @ts-ignore: private
|
|
305
|
-
if (this.registerer && this.registerer.waiting) {
|
|
306
|
-
// @ts-ignore: private
|
|
307
|
-
this.registerer.waitingToggle(false);
|
|
308
|
-
}
|
|
309
|
-
if (tries <= MAX_REGISTER_TRIES) {
|
|
310
|
-
logger.info('sdk webrtc registering, retrying...', { clientId: this.clientId, tries });
|
|
311
|
-
setTimeout(() => this.register(tries + 1), 300);
|
|
312
|
-
}
|
|
313
|
-
};
|
|
314
|
-
return this._connectIfNeeded().then(() => {
|
|
315
|
-
// Avoid race condition with the close method called just before register and setting userAgent to null
|
|
316
|
-
// during the resolution of the promise.
|
|
317
|
-
if (!this.userAgent) {
|
|
318
|
-
logger.info('sdk webrtc recreating User Agent after connection');
|
|
319
|
-
this.userAgent = this.createUserAgent(this.uaConfigOverrides);
|
|
320
|
-
}
|
|
321
|
-
logger.info('sdk webrtc registering, transport connected', { registerOptions, ua: !!this.userAgent, clientId: this.clientId });
|
|
322
|
-
this.registerer = new Registerer(this.userAgent, registerOptions);
|
|
323
|
-
this.connectionPromise = null;
|
|
324
|
-
this._monkeyPatchRegisterer(this.registerer);
|
|
325
|
-
// Bind registerer events
|
|
326
|
-
this.registerer.stateChange.addListener(newState => {
|
|
327
|
-
logger.info('sdk webrtc registering, state changed', { newState, clientId: this.clientId });
|
|
328
|
-
if (newState === RegistererState.Registered && this.registerer && this.registerer.state === RegistererState.Registered) {
|
|
329
|
-
this.eventEmitter.emit(REGISTERED);
|
|
330
|
-
}
|
|
331
|
-
else if (newState === RegistererState.Unregistered) {
|
|
332
|
-
this.eventEmitter.emit(UNREGISTERED);
|
|
333
|
-
}
|
|
334
|
-
});
|
|
335
|
-
const options = {
|
|
336
|
-
requestDelegate: {
|
|
337
|
-
onReject: (response) => {
|
|
338
|
-
logger.error('sdk webrtc registering, rejected', { clientId: this.clientId, response });
|
|
339
|
-
onRegisterFailed();
|
|
340
|
-
},
|
|
341
|
-
},
|
|
342
|
-
};
|
|
343
|
-
return this.registerer.register(options).catch(e => {
|
|
344
|
-
logger.error('sdk webrtc registering, error', e);
|
|
345
|
-
this.eventEmitter.emit(REGISTRATION_FAILED);
|
|
346
|
-
return e;
|
|
347
|
-
});
|
|
348
|
-
}).catch(error => {
|
|
349
|
-
logger.error('sdk webrtc registering, transport error', error);
|
|
350
|
-
onRegisterFailed();
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
// Monkey patching sip.js to avoid issues during register.onReject
|
|
354
|
-
_monkeyPatchRegisterer(registerer) {
|
|
355
|
-
if (!registerer) {
|
|
356
|
-
return;
|
|
357
|
-
}
|
|
358
|
-
// @ts-ignore: private
|
|
359
|
-
const oldWaitingToggle = registerer.waitingToggle.bind(registerer);
|
|
360
|
-
// @ts-ignore: private
|
|
361
|
-
const oldUnregistered = registerer.unregistered.bind(registerer);
|
|
362
|
-
// @ts-ignore: private
|
|
363
|
-
registerer.waitingToggle = (waiting) => {
|
|
364
|
-
// @ts-ignore: private
|
|
365
|
-
if (!registerer || registerer.waiting === waiting) {
|
|
366
|
-
return;
|
|
367
|
-
}
|
|
368
|
-
oldWaitingToggle(waiting);
|
|
369
|
-
};
|
|
370
|
-
// @ts-ignore: private
|
|
371
|
-
registerer.unregistered = () => {
|
|
372
|
-
if (!registerer || registerer.state === RegistererState.Terminated) {
|
|
373
|
-
return;
|
|
374
|
-
}
|
|
375
|
-
oldUnregistered();
|
|
376
|
-
};
|
|
377
|
-
}
|
|
378
|
-
async unregister() {
|
|
379
|
-
logger.info('sdk webrtc unregistering..', {
|
|
380
|
-
clientId: this.clientId,
|
|
381
|
-
userAgent: !!this.userAgent,
|
|
382
|
-
registerer: !!this.registerer,
|
|
383
|
-
});
|
|
384
|
-
try {
|
|
385
|
-
return new Promise((resolve, reject) => {
|
|
386
|
-
if (!this.registerer) {
|
|
387
|
-
return resolve();
|
|
388
|
-
}
|
|
389
|
-
const onRegisterStateChange = (state) => {
|
|
390
|
-
if (state === RegistererState.Unregistered) {
|
|
391
|
-
logger.info('sdk webrtc unregistered', { clientId: this.clientId });
|
|
392
|
-
if (this.registerer) {
|
|
393
|
-
this.registerer.stateChange.addListener(onRegisterStateChange);
|
|
394
|
-
}
|
|
395
|
-
this._cleanupRegister();
|
|
396
|
-
resolve();
|
|
397
|
-
}
|
|
398
|
-
};
|
|
399
|
-
this.registerer.stateChange.addListener(onRegisterStateChange);
|
|
400
|
-
this.registerer.unregister().then().catch(e => {
|
|
401
|
-
logger.error('sdk webrtc unregistering, promise error', e);
|
|
402
|
-
this._cleanupRegister();
|
|
403
|
-
reject();
|
|
404
|
-
});
|
|
405
|
-
});
|
|
406
|
-
}
|
|
407
|
-
catch (e) {
|
|
408
|
-
logger.error('sdk webrtc unregistering, error', e);
|
|
409
|
-
// Avoid issue with `undefined is not an object (evaluating 'new.target.prototype')` when triggering a new
|
|
410
|
-
// error when the registerer is in a bad state
|
|
411
|
-
this._cleanupRegister();
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
stop() {
|
|
415
|
-
logger.info('sdk webrtc stop', { clientId: this.clientId, userAgent: !!this.userAgent });
|
|
416
|
-
if (!this.userAgent) {
|
|
417
|
-
return Promise.resolve();
|
|
418
|
-
}
|
|
419
|
-
return this.userAgent.stop().then(() => {
|
|
420
|
-
return this._cleanupRegister();
|
|
421
|
-
}).catch(e => {
|
|
422
|
-
logger.warn('sdk webrtc stop, error', {
|
|
423
|
-
message: e.message,
|
|
424
|
-
stack: e.stack,
|
|
425
|
-
});
|
|
426
|
-
});
|
|
427
|
-
}
|
|
428
|
-
call(number, enableVideo, audioOnly = false, conference = false, options = {}) {
|
|
429
|
-
logger.info('sdk webrtc creating call', {
|
|
430
|
-
clientId: this.clientId,
|
|
431
|
-
number,
|
|
432
|
-
enableVideo,
|
|
433
|
-
audioOnly,
|
|
434
|
-
conference,
|
|
435
|
-
options,
|
|
436
|
-
});
|
|
437
|
-
const inviterOptions = {
|
|
438
|
-
sessionDescriptionHandlerOptionsReInvite: {
|
|
439
|
-
conference,
|
|
440
|
-
audioOnly,
|
|
441
|
-
},
|
|
442
|
-
earlyMedia: true,
|
|
443
|
-
...options,
|
|
444
|
-
};
|
|
445
|
-
if (audioOnly) {
|
|
446
|
-
inviterOptions.sessionDescriptionHandlerModifiersReInvite = [stripVideo];
|
|
447
|
-
}
|
|
448
|
-
const uri = this._makeURI(number);
|
|
449
|
-
let session = null;
|
|
450
|
-
if (uri) {
|
|
451
|
-
session = this.userAgent ? new Inviter(this.userAgent, uri, inviterOptions) : null;
|
|
452
|
-
}
|
|
453
|
-
else {
|
|
454
|
-
logger.error('Null URI');
|
|
455
|
-
}
|
|
456
|
-
if (session) {
|
|
457
|
-
this.storeSipSession(session);
|
|
458
|
-
this._setupSession(session);
|
|
459
|
-
}
|
|
460
|
-
if (conference) {
|
|
461
|
-
this.conferences[this.getSipSessionId(session)] = true;
|
|
462
|
-
}
|
|
463
|
-
const inviteOptions = {
|
|
464
|
-
requestDelegate: {
|
|
465
|
-
onAccept: (response) => {
|
|
466
|
-
if (session?.sessionDescriptionHandler?.peerConnection) {
|
|
467
|
-
(session?.sessionDescriptionHandler).peerConnection.sfu = conference;
|
|
468
|
-
}
|
|
469
|
-
this._onAccepted(session, response.session, true);
|
|
470
|
-
},
|
|
471
|
-
onProgress: (payload) => {
|
|
472
|
-
this._onProgress(payload.session, payload.message.statusCode === 183);
|
|
473
|
-
},
|
|
474
|
-
onReject: (response) => {
|
|
475
|
-
logger.info('on call rejected', {
|
|
476
|
-
id: this.getSipSessionId(session),
|
|
477
|
-
// @ts-ignore: fromTag does not exist
|
|
478
|
-
fromTag: session?.fromTag,
|
|
479
|
-
});
|
|
480
|
-
this._stopSendingStats(session);
|
|
481
|
-
this.stopNetworkMonitoring(session);
|
|
482
|
-
this.eventEmitter.emit(REJECTED, session, response);
|
|
483
|
-
},
|
|
484
|
-
},
|
|
485
|
-
sessionDescriptionHandlerOptions: this.getMediaConfiguration(enableVideo || false, conference),
|
|
486
|
-
};
|
|
487
|
-
if (inviteOptions.sessionDescriptionHandlerOptions) {
|
|
488
|
-
inviteOptions.sessionDescriptionHandlerOptions.audioOnly = audioOnly;
|
|
489
|
-
}
|
|
490
|
-
inviteOptions.sessionDescriptionHandlerModifiers = [replaceLocalIpModifier];
|
|
491
|
-
if (audioOnly) {
|
|
492
|
-
inviteOptions.sessionDescriptionHandlerModifiers.push(stripVideo);
|
|
493
|
-
}
|
|
494
|
-
if (session) {
|
|
495
|
-
// Do not await invite here or we'll miss the Establishing state transition
|
|
496
|
-
// @ts-ignore: Property 'invitePromise' does not exist
|
|
497
|
-
session.invitePromise = session.invite(inviteOptions).catch((e) => {
|
|
498
|
-
logger.warn('sdk webrtc creating call, error', e);
|
|
499
|
-
});
|
|
500
|
-
}
|
|
501
|
-
return session;
|
|
502
|
-
}
|
|
503
|
-
answer(session, enableVideo) {
|
|
504
|
-
logger.info('sdk webrtc answer call', {
|
|
505
|
-
clientId: this.clientId,
|
|
506
|
-
id: this.getSipSessionId(session),
|
|
507
|
-
enableVideo,
|
|
508
|
-
});
|
|
509
|
-
if (!session || !session.accept) {
|
|
510
|
-
const error = 'No session to answer, or not an invitation';
|
|
511
|
-
logger.warn(error);
|
|
512
|
-
return Promise.reject(new Error(error));
|
|
513
|
-
}
|
|
514
|
-
const options = {
|
|
515
|
-
sessionDescriptionHandlerOptions: this.getMediaConfiguration(enableVideo || false),
|
|
516
|
-
};
|
|
517
|
-
return this._accept(session, options).then(() => {
|
|
518
|
-
// @ts-ignore: private
|
|
519
|
-
if (session.isCanceled) {
|
|
520
|
-
const message = 'accepted a canceled session (or was canceled during the accept phase).';
|
|
521
|
-
logger.error(message, {
|
|
522
|
-
id: this.getSipSessionId(session),
|
|
523
|
-
});
|
|
524
|
-
this.onCallEnded(session);
|
|
525
|
-
throw new CanceledCallError(message);
|
|
526
|
-
}
|
|
527
|
-
logger.info('sdk webrtc answer, accepted.');
|
|
528
|
-
this._onAccepted(session);
|
|
529
|
-
}).catch(e => {
|
|
530
|
-
logger.error(`answer call error for ${this.getSipSessionId(session)}`, e);
|
|
531
|
-
throw e;
|
|
532
|
-
});
|
|
533
|
-
}
|
|
534
|
-
async hangup(session) {
|
|
535
|
-
const { state, id } = session;
|
|
536
|
-
logger.info('sdk webrtc hangup call', { clientId: this.clientId, id, state });
|
|
537
|
-
try {
|
|
538
|
-
this._stopSendingStats(session);
|
|
539
|
-
this._cleanupMedia(session);
|
|
540
|
-
delete this.sipSessions[this.getSipSessionId(session)];
|
|
541
|
-
// Check if Invitation or Inviter (Invitation = incoming call)
|
|
542
|
-
const isInviter = session instanceof Inviter;
|
|
543
|
-
// @see github.com/onsip/SIP.js/blob/f11dfd584bc9788ccfc94e03034020672b738975/src/platform/web/simple-user/simple-user.ts#L1004
|
|
544
|
-
const actions = {
|
|
545
|
-
[SessionState.Initial]: isInviter ? this._cancel.bind(this, session) : this._reject.bind(this, session),
|
|
546
|
-
[SessionState.Establishing]: isInviter ? this._cancel.bind(this, session) : this._reject.bind(this, session),
|
|
547
|
-
[SessionState.Established]: this._bye.bind(this, session),
|
|
548
|
-
};
|
|
549
|
-
// Handle different session status
|
|
550
|
-
if (actions[state]) {
|
|
551
|
-
return await actions[state]();
|
|
552
|
-
}
|
|
553
|
-
return await this._bye(session);
|
|
554
|
-
}
|
|
555
|
-
catch (error) {
|
|
556
|
-
logger.warn('sdk webrtc hangup, error', error);
|
|
557
|
-
}
|
|
558
|
-
return Promise.resolve(null);
|
|
559
|
-
}
|
|
560
|
-
async getStats(session) {
|
|
561
|
-
const pc = session.sessionDescriptionHandler?.peerConnection;
|
|
562
|
-
if (!pc) {
|
|
563
|
-
return null;
|
|
564
|
-
}
|
|
565
|
-
return pc.getStats(null);
|
|
566
|
-
}
|
|
567
|
-
// Fetch and emit an event at `interval` with session network stats
|
|
568
|
-
startNetworkMonitoring(session, interval = 1000) {
|
|
569
|
-
const sessionId = this.getSipSessionId(session);
|
|
570
|
-
logger.info('starting network inspection', {
|
|
571
|
-
id: sessionId,
|
|
572
|
-
clientId: this.clientId,
|
|
573
|
-
});
|
|
574
|
-
this.sessionNetworkStats[sessionId] = [];
|
|
575
|
-
this.networkMonitoringInterval[sessionId] = setInterval(() => this._fetchNetworkStats(sessionId), interval);
|
|
576
|
-
}
|
|
577
|
-
stopNetworkMonitoring(session) {
|
|
578
|
-
const sessionId = this.getSipSessionId(session);
|
|
579
|
-
const exists = (sessionId in this.networkMonitoringInterval);
|
|
580
|
-
logger.info('stopping network inspection', {
|
|
581
|
-
clientId: this.clientId,
|
|
582
|
-
id: sessionId,
|
|
583
|
-
exists,
|
|
584
|
-
});
|
|
585
|
-
if (exists) {
|
|
586
|
-
clearInterval(this.networkMonitoringInterval[sessionId]);
|
|
587
|
-
delete this.networkMonitoringInterval[sessionId];
|
|
588
|
-
delete this.sessionNetworkStats[sessionId];
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
async reject(session) {
|
|
592
|
-
logger.info('sdk webrtc reject call', {
|
|
593
|
-
clientId: this.clientId,
|
|
594
|
-
id: this.getSipSessionId(session),
|
|
595
|
-
});
|
|
596
|
-
try {
|
|
597
|
-
if (session instanceof Invitation) {
|
|
598
|
-
return this._reject(session);
|
|
599
|
-
}
|
|
600
|
-
if (session instanceof Inviter) {
|
|
601
|
-
return this._cancel(session);
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
catch (e) {
|
|
605
|
-
logger.warn('Error when rejecting call', e.message, e.stack);
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
async close(force = false) {
|
|
609
|
-
logger.info('sdk webrtc closing client', {
|
|
610
|
-
clientId: this.clientId,
|
|
611
|
-
userAgent: !!this.userAgent,
|
|
612
|
-
force,
|
|
613
|
-
});
|
|
614
|
-
this.forceClosed = force;
|
|
615
|
-
this._cleanupMedia();
|
|
616
|
-
this.connectionPromise = null;
|
|
617
|
-
Object.values(this.audioElements).forEach((audioElement) => {
|
|
618
|
-
// eslint-disable-next-line
|
|
619
|
-
audioElement.srcObject = null;
|
|
620
|
-
audioElement.pause();
|
|
621
|
-
});
|
|
622
|
-
this.audioElements = {};
|
|
623
|
-
if (!this.userAgent) {
|
|
624
|
-
return;
|
|
625
|
-
}
|
|
626
|
-
this.stopHeartbeat();
|
|
627
|
-
if (this.userAgent) {
|
|
628
|
-
this.userAgent.delegate = undefined;
|
|
629
|
-
}
|
|
630
|
-
// @ts-ignore: removeAllListeners does not exist
|
|
631
|
-
this.userAgent.stateChange.removeAllListeners();
|
|
632
|
-
await this._disconnectTransport(force);
|
|
633
|
-
this._cleanupRegister();
|
|
634
|
-
try {
|
|
635
|
-
// Prevent `Connect aborted.` error when disconnecting
|
|
636
|
-
this.userAgent.transport.connectReject = () => { };
|
|
637
|
-
// Don't wait here, It can take ~30s to stop ...
|
|
638
|
-
this.userAgent.stop().catch(console.error);
|
|
639
|
-
}
|
|
640
|
-
catch (_) { // Avoid to raise exception when trying to close with hanged-up sessions remaining
|
|
641
|
-
// eg: "INVITE not rejectable in state Completed"
|
|
642
|
-
}
|
|
643
|
-
this.userAgent = null;
|
|
644
|
-
logger.info('sdk webrtc client closed', { clientId: this.clientId });
|
|
645
|
-
}
|
|
646
|
-
getNumber(session) {
|
|
647
|
-
if (!session) {
|
|
648
|
-
return null;
|
|
649
|
-
}
|
|
650
|
-
// @ts-ignore: private
|
|
651
|
-
return session.remoteIdentity.uri._normal.user;
|
|
652
|
-
}
|
|
653
|
-
mute(session) {
|
|
654
|
-
logger.info('sdk webrtc mute', {
|
|
655
|
-
id: this.getSipSessionId(session),
|
|
656
|
-
});
|
|
657
|
-
this._toggleAudio(session, true);
|
|
658
|
-
}
|
|
659
|
-
unmute(session) {
|
|
660
|
-
logger.info('sdk webrtc unmute', {
|
|
661
|
-
id: this.getSipSessionId(session),
|
|
662
|
-
});
|
|
663
|
-
this._toggleAudio(session, false);
|
|
664
|
-
}
|
|
665
|
-
isAudioMuted(session) {
|
|
666
|
-
if (!session || !session.sessionDescriptionHandler) {
|
|
667
|
-
return false;
|
|
668
|
-
}
|
|
669
|
-
let muted = true;
|
|
670
|
-
const pc = session.sessionDescriptionHandler.peerConnection;
|
|
671
|
-
if (!pc) {
|
|
672
|
-
return false;
|
|
673
|
-
}
|
|
674
|
-
if (pc.getSenders) {
|
|
675
|
-
if (!pc.getSenders().length) {
|
|
676
|
-
return false;
|
|
677
|
-
}
|
|
678
|
-
pc.getSenders().forEach((sender) => {
|
|
679
|
-
if (sender && sender.track && sender.track.kind === 'audio') {
|
|
680
|
-
muted = muted && !sender.track.enabled;
|
|
681
|
-
}
|
|
682
|
-
});
|
|
683
|
-
}
|
|
684
|
-
else {
|
|
685
|
-
if (!pc.getLocalStreams().length) {
|
|
686
|
-
return false;
|
|
687
|
-
}
|
|
688
|
-
pc.getLocalStreams().forEach((stream) => {
|
|
689
|
-
stream.getAudioTracks().forEach(track => {
|
|
690
|
-
muted = muted && !track.enabled;
|
|
691
|
-
});
|
|
692
|
-
});
|
|
693
|
-
}
|
|
694
|
-
return muted;
|
|
695
|
-
}
|
|
696
|
-
toggleCameraOn(session) {
|
|
697
|
-
logger.info('sdk webrtc toggle camera on', {
|
|
698
|
-
id: this.getSipSessionId(session),
|
|
699
|
-
});
|
|
700
|
-
this._toggleVideo(session, false);
|
|
701
|
-
}
|
|
702
|
-
toggleCameraOff(session) {
|
|
703
|
-
logger.info('sdk webrtc toggle camera off', {
|
|
704
|
-
id: this.getSipSessionId(session),
|
|
705
|
-
});
|
|
706
|
-
this._toggleVideo(session, true);
|
|
707
|
-
}
|
|
708
|
-
hold(session, isConference = false, hadVideo = false) {
|
|
709
|
-
const sessionId = this.getSipSessionId(session);
|
|
710
|
-
const hasVideo = hadVideo || this.hasLocalVideo(sessionId);
|
|
711
|
-
logger.info('sdk webrtc hold', {
|
|
712
|
-
sessionId,
|
|
713
|
-
keys: Object.keys(this.heldSessions),
|
|
714
|
-
// @ts-ignore: private
|
|
715
|
-
pendingReinvite: !!session.pendingReinvite,
|
|
716
|
-
isConference,
|
|
717
|
-
hasVideo,
|
|
718
|
-
});
|
|
719
|
-
if (sessionId in this.heldSessions) {
|
|
720
|
-
return Promise.resolve();
|
|
721
|
-
}
|
|
722
|
-
// @ts-ignore: private
|
|
723
|
-
if (session.pendingReinvite) {
|
|
724
|
-
return Promise.resolve();
|
|
725
|
-
}
|
|
726
|
-
this.heldSessions[sessionId] = {
|
|
727
|
-
hasVideo,
|
|
728
|
-
isConference,
|
|
729
|
-
};
|
|
730
|
-
// We should also mute the call, because when holding a call during a voicemail, the audio is still sent with the
|
|
731
|
-
// `sendonly` direction
|
|
732
|
-
this.mute(session);
|
|
733
|
-
session.sessionDescriptionHandlerOptionsReInvite = {
|
|
734
|
-
hold: true,
|
|
735
|
-
conference: isConference,
|
|
736
|
-
};
|
|
737
|
-
const options = this.getMediaConfiguration(false, isConference);
|
|
738
|
-
if (!this._isWeb()) {
|
|
739
|
-
options.sessionDescriptionHandlerModifiers = [holdModifier];
|
|
740
|
-
}
|
|
741
|
-
options.sessionDescriptionHandlerOptions = {
|
|
742
|
-
constraints: options.constraints,
|
|
743
|
-
hold: true,
|
|
744
|
-
conference: isConference,
|
|
745
|
-
};
|
|
746
|
-
// Avoid sdh to create a new stream
|
|
747
|
-
if (session.sessionDescriptionHandler) {
|
|
748
|
-
// @ts-ignore: private
|
|
749
|
-
session.sessionDescriptionHandler.localMediaStreamConstraints = options.constraints;
|
|
750
|
-
}
|
|
751
|
-
// Send re-INVITE
|
|
752
|
-
return session.invite(options).catch((e) => {
|
|
753
|
-
logger.warn('sdk webrtc re-invite during hold, error', e);
|
|
754
|
-
});
|
|
755
|
-
}
|
|
756
|
-
unhold(session, isConference = false) {
|
|
757
|
-
const sessionId = this.getSipSessionId(session);
|
|
758
|
-
const hasVideo = sessionId in this.heldSessions && this.heldSessions[sessionId].hasVideo;
|
|
759
|
-
logger.info('sdk webrtc unhold', {
|
|
760
|
-
sessionId,
|
|
761
|
-
keys: Object.keys(this.heldSessions),
|
|
762
|
-
// @ts-ignore: private
|
|
763
|
-
pendingReinvite: !!session.pendingReinvite,
|
|
764
|
-
isConference,
|
|
765
|
-
hasVideo,
|
|
766
|
-
});
|
|
767
|
-
// @ts-ignore: private
|
|
768
|
-
if (session.pendingReinvite) {
|
|
769
|
-
return Promise.resolve();
|
|
770
|
-
}
|
|
771
|
-
this.unmute(session);
|
|
772
|
-
delete this.heldSessions[this.getSipSessionId(session)];
|
|
773
|
-
session.sessionDescriptionHandlerOptionsReInvite = {
|
|
774
|
-
hold: false,
|
|
775
|
-
conference: isConference,
|
|
776
|
-
};
|
|
777
|
-
const options = this.getMediaConfiguration(false, isConference);
|
|
778
|
-
if (!this._isWeb()) {
|
|
779
|
-
// We should sent an empty `sessionDescriptionHandlerModifiers` or sip.js will take the last sent modifiers
|
|
780
|
-
// (eg: holdModifier)
|
|
781
|
-
options.sessionDescriptionHandlerModifiers = [];
|
|
782
|
-
}
|
|
783
|
-
options.sessionDescriptionHandlerOptions = {
|
|
784
|
-
constraints: options.constraints,
|
|
785
|
-
hold: false,
|
|
786
|
-
conference: isConference,
|
|
787
|
-
};
|
|
788
|
-
// Send re-INVITE
|
|
789
|
-
return session.invite(options).catch((e) => {
|
|
790
|
-
logger.warn('sdk webrtc re-invite during resume, error', e);
|
|
791
|
-
});
|
|
792
|
-
}
|
|
793
|
-
// Returns true if a re-INVITE is required
|
|
794
|
-
async upgradeToVideo(session, constraints, isConference) {
|
|
795
|
-
const pc = session.sessionDescriptionHandler?.peerConnection;
|
|
796
|
-
// Check if a video sender already exists
|
|
797
|
-
let videoSender;
|
|
798
|
-
if (isConference) {
|
|
799
|
-
// We search for the last transceiver without `video-` in the mid (video- means remote transceiver)
|
|
800
|
-
const transceivers = pc?.getTransceivers() || [];
|
|
801
|
-
const transceiverIdx = lastIndexOf(transceivers, transceiver => transceiver.sender.track === null && transceiver.mid && transceiver.mid.indexOf('video') === -1);
|
|
802
|
-
videoSender = transceiverIdx !== -1 ? transceivers[transceiverIdx].sender : null;
|
|
803
|
-
}
|
|
804
|
-
else {
|
|
805
|
-
videoSender = pc && pc.getSenders && pc.getSenders().find((sender) => sender.track === null);
|
|
806
|
-
}
|
|
807
|
-
if (!videoSender) {
|
|
808
|
-
// When no video sender found, it means that we're in the first video upgrade in 1:1
|
|
809
|
-
return;
|
|
810
|
-
}
|
|
811
|
-
// Reuse bidirectional video stream
|
|
812
|
-
const newStream = await this.getStreamFromConstraints(constraints);
|
|
813
|
-
if (!newStream) {
|
|
814
|
-
console.warn(`Can't create media stream with: ${JSON.stringify(constraints || {})}`);
|
|
815
|
-
return;
|
|
816
|
-
}
|
|
817
|
-
// Add previous local audio track
|
|
818
|
-
if (constraints && !constraints.audio) {
|
|
819
|
-
const localVideoStream = session.sessionDescriptionHandler?.localMediaStream;
|
|
820
|
-
const localAudioTrack = localVideoStream.getTracks().find(track => track.kind === 'audio');
|
|
821
|
-
if (localAudioTrack) {
|
|
822
|
-
newStream.addTrack(localAudioTrack);
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
const videoTrack = newStream.getVideoTracks()[0];
|
|
826
|
-
if (videoTrack) {
|
|
827
|
-
videoSender.replaceTrack(videoTrack);
|
|
828
|
-
}
|
|
829
|
-
this.setLocalMediaStream(this.getSipSessionId(session), newStream);
|
|
830
|
-
return newStream;
|
|
831
|
-
}
|
|
832
|
-
downgradeToAudio(session) {
|
|
833
|
-
// Release local video stream when downgrading to audio
|
|
834
|
-
const sessionDescriptionHandler = session.sessionDescriptionHandler;
|
|
835
|
-
const localStream = sessionDescriptionHandler?.localMediaStream;
|
|
836
|
-
const pc = sessionDescriptionHandler?.peerConnection;
|
|
837
|
-
const videoTracks = localStream.getVideoTracks();
|
|
838
|
-
// Remove video senders
|
|
839
|
-
if (pc?.getSenders) {
|
|
840
|
-
pc.getSenders().filter((sender) => sender.track && sender.track.kind === 'video').forEach((videoSender) => {
|
|
841
|
-
videoSender.replaceTrack(null);
|
|
842
|
-
});
|
|
843
|
-
}
|
|
844
|
-
videoTracks.forEach((videoTrack) => {
|
|
845
|
-
videoTrack.enabled = false;
|
|
846
|
-
videoTrack.stop();
|
|
847
|
-
localStream.removeTrack(videoTrack);
|
|
848
|
-
});
|
|
849
|
-
}
|
|
850
|
-
async getStreamFromConstraints(constraints, conference = false) {
|
|
851
|
-
const video = constraints && constraints.video;
|
|
852
|
-
const { constraints: newConstraints, } = this.getMediaConfiguration(video, conference, constraints);
|
|
853
|
-
let newStream = null;
|
|
854
|
-
try {
|
|
855
|
-
newStream = await wazoMediaStreamFactory(newConstraints);
|
|
856
|
-
}
|
|
857
|
-
catch (e) { // Nothing to do when the user cancel the screensharing prompt
|
|
858
|
-
}
|
|
859
|
-
if (!newStream) {
|
|
860
|
-
return null;
|
|
861
|
-
}
|
|
862
|
-
newStream.local = true;
|
|
863
|
-
return newStream;
|
|
864
|
-
}
|
|
865
|
-
getHeldSession(sessionId) {
|
|
866
|
-
return this.heldSessions[sessionId];
|
|
867
|
-
}
|
|
868
|
-
isCallHeld(session) {
|
|
869
|
-
return this.getSipSessionId(session) in this.heldSessions;
|
|
870
|
-
}
|
|
871
|
-
isVideoRemotelyHeld(sessionId) {
|
|
872
|
-
const pc = this.getPeerConnection(sessionId);
|
|
873
|
-
const sdp = pc && pc.remoteDescription ? pc.remoteDescription.sdp : null;
|
|
874
|
-
if (!sdp) {
|
|
875
|
-
return false;
|
|
876
|
-
}
|
|
877
|
-
const videoDirection = getVideoDirection(sdp);
|
|
878
|
-
return videoDirection === 'sendonly';
|
|
879
|
-
}
|
|
880
|
-
sendDTMF(session, tone) {
|
|
881
|
-
if (!session.sessionDescriptionHandler) {
|
|
882
|
-
return false;
|
|
883
|
-
}
|
|
884
|
-
logger.info('Sending DTMF', {
|
|
885
|
-
id: this.getSipSessionId(session),
|
|
886
|
-
tone,
|
|
887
|
-
});
|
|
888
|
-
return session.sessionDescriptionHandler.sendDtmf(tone);
|
|
889
|
-
}
|
|
890
|
-
message(destination, message) {
|
|
891
|
-
const uri = this._makeURI(destination);
|
|
892
|
-
if (!this.userAgent || !uri) {
|
|
893
|
-
logger.warn('Null value on message', { uri, userAgent: this.userAgent });
|
|
894
|
-
return;
|
|
895
|
-
}
|
|
896
|
-
const messager = new Messager(this.userAgent, uri, message);
|
|
897
|
-
messager.message();
|
|
898
|
-
}
|
|
899
|
-
transfer(session, target) {
|
|
900
|
-
this.hold(session);
|
|
901
|
-
logger.info('Transfering a session', {
|
|
902
|
-
id: this.getSipSessionId(session),
|
|
903
|
-
target,
|
|
904
|
-
});
|
|
905
|
-
const options = {
|
|
906
|
-
requestDelegate: {
|
|
907
|
-
onAccept: () => {
|
|
908
|
-
this.hangup(session);
|
|
909
|
-
},
|
|
910
|
-
},
|
|
911
|
-
};
|
|
912
|
-
setTimeout(() => {
|
|
913
|
-
const uri = this._makeURI(target);
|
|
914
|
-
if (!uri) {
|
|
915
|
-
logger.warn('transfer timeout: null URI');
|
|
916
|
-
return;
|
|
917
|
-
}
|
|
918
|
-
session.refer(uri, options);
|
|
919
|
-
}, 50);
|
|
920
|
-
}
|
|
921
|
-
// check https://sipjs.com/api/0.12.0/refer/referClientContext/
|
|
922
|
-
atxfer(session) {
|
|
923
|
-
this.hold(session);
|
|
924
|
-
logger.info('webrtc transfer started', {
|
|
925
|
-
id: this.getSipSessionId(session),
|
|
926
|
-
});
|
|
927
|
-
const result = {
|
|
928
|
-
newSession: null,
|
|
929
|
-
init: async (target) => {
|
|
930
|
-
logger.info('webrtc transfer initialized', {
|
|
931
|
-
id: this.getSipSessionId(session),
|
|
932
|
-
target,
|
|
933
|
-
});
|
|
934
|
-
result.newSession = await this.call(target);
|
|
935
|
-
},
|
|
936
|
-
complete: () => {
|
|
937
|
-
logger.info('webrtc transfer completed', {
|
|
938
|
-
id: this.getSipSessionId(session),
|
|
939
|
-
referId: this.getSipSessionId(result.newSession),
|
|
940
|
-
});
|
|
941
|
-
session.refer(result.newSession);
|
|
942
|
-
},
|
|
943
|
-
cancel: () => {
|
|
944
|
-
this.hangup(result.newSession);
|
|
945
|
-
this.unhold(session);
|
|
946
|
-
},
|
|
947
|
-
};
|
|
948
|
-
return result;
|
|
949
|
-
}
|
|
950
|
-
// eslint-disable-next-line @typescript-eslint/default-param-last
|
|
951
|
-
sendMessage(sipSession = null, body, contentType = 'text/plain') {
|
|
952
|
-
if (!sipSession) {
|
|
953
|
-
return;
|
|
954
|
-
}
|
|
955
|
-
logger.info('send WebRTC message', {
|
|
956
|
-
sipId: this.getSipSessionId(sipSession),
|
|
957
|
-
contentType,
|
|
958
|
-
});
|
|
959
|
-
try {
|
|
960
|
-
sipSession.message({
|
|
961
|
-
requestOptions: {
|
|
962
|
-
body: {
|
|
963
|
-
content: body,
|
|
964
|
-
contentType,
|
|
965
|
-
// @HEADSUP: contentDisposition is a required string, setting it to '' arbitrarily
|
|
966
|
-
contentDisposition: '',
|
|
967
|
-
},
|
|
968
|
-
},
|
|
969
|
-
});
|
|
970
|
-
}
|
|
971
|
-
catch (e) {
|
|
972
|
-
console.warn(e);
|
|
973
|
-
}
|
|
974
|
-
}
|
|
975
|
-
pingServer() {
|
|
976
|
-
if (!this.isConnected()) {
|
|
977
|
-
return;
|
|
978
|
-
}
|
|
979
|
-
const core = this.userAgent?.userAgentCore;
|
|
980
|
-
const fromURI = this._makeURI(this.config.authorizationUser || '');
|
|
981
|
-
const toURI = new URI('sip', '', this.config.host);
|
|
982
|
-
if (fromURI) {
|
|
983
|
-
const message = core?.makeOutgoingRequestMessage('OPTIONS', toURI, fromURI, toURI, {});
|
|
984
|
-
if (message) {
|
|
985
|
-
return core?.request(message);
|
|
986
|
-
}
|
|
987
|
-
logger.warn('pingServer: null message');
|
|
988
|
-
}
|
|
989
|
-
logger.warn('pingServer: null fromURI');
|
|
990
|
-
}
|
|
991
|
-
getState() {
|
|
992
|
-
// @ts-ignore: something fishy here: `states` content doesn't match UserAgentState at all
|
|
993
|
-
return this.userAgent ? states[this.userAgent.state] : UserAgentState.Stopped;
|
|
994
|
-
}
|
|
995
|
-
getContactIdentifier() {
|
|
996
|
-
return this.userAgent ? `${this.userAgent.configuration.contactName}/${this.userAgent.contact.uri}` : null;
|
|
997
|
-
}
|
|
998
|
-
isFirefox() {
|
|
999
|
-
return this._isWeb() && navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
|
|
1000
|
-
}
|
|
1001
|
-
changeAudioOutputVolume(volume) {
|
|
1002
|
-
logger.info('Changing audio output volume', {
|
|
1003
|
-
volume,
|
|
1004
|
-
});
|
|
1005
|
-
Object.values(this.audioElements).forEach(audioElement => {
|
|
1006
|
-
if (audioElement instanceof HTMLAudioElement) {
|
|
1007
|
-
// eslint-disable-next-line no-param-reassign
|
|
1008
|
-
audioElement.volume = volume;
|
|
1009
|
-
}
|
|
1010
|
-
});
|
|
1011
|
-
this.audioOutputVolume = volume;
|
|
1012
|
-
}
|
|
1013
|
-
async changeAudioOutputDevice(id) {
|
|
1014
|
-
logger.info('Changing audio output device', {
|
|
1015
|
-
id,
|
|
1016
|
-
});
|
|
1017
|
-
this.audioOutputDeviceId = id;
|
|
1018
|
-
const promises = [];
|
|
1019
|
-
Object.values(this.audioElements).forEach(audioElement => promises.push(audioElement.setSinkId(id)));
|
|
1020
|
-
await Promise.allSettled(promises);
|
|
1021
|
-
}
|
|
1022
|
-
async changeAudioInputDevice(id, session, force) {
|
|
1023
|
-
const currentId = this.getAudioDeviceId();
|
|
1024
|
-
logger.info('setting audio input device', {
|
|
1025
|
-
id,
|
|
1026
|
-
currentId,
|
|
1027
|
-
session: !!session,
|
|
1028
|
-
});
|
|
1029
|
-
if (!force && id === currentId) {
|
|
1030
|
-
return null;
|
|
1031
|
-
}
|
|
1032
|
-
// in order to handle an audio track change for default devices
|
|
1033
|
-
// we need the actual id of the device (not 'default')
|
|
1034
|
-
let deviceId = id;
|
|
1035
|
-
if (id === 'default' && navigator.mediaDevices) {
|
|
1036
|
-
const devices = await navigator.mediaDevices.enumerateDevices();
|
|
1037
|
-
const defaultDevice = devices.find(device => device.deviceId === 'default');
|
|
1038
|
-
if (defaultDevice) {
|
|
1039
|
-
const deviceLabel = defaultDevice.label.replace('Default - ', '');
|
|
1040
|
-
const targetDevice = devices.find(device => device.label === deviceLabel);
|
|
1041
|
-
if (targetDevice) {
|
|
1042
|
-
deviceId = targetDevice.deviceId;
|
|
1043
|
-
if (!force && deviceId === currentId) {
|
|
1044
|
-
return null;
|
|
1045
|
-
}
|
|
1046
|
-
}
|
|
1047
|
-
}
|
|
1048
|
-
}
|
|
1049
|
-
// let's update the local audio value
|
|
1050
|
-
if (this.audio) {
|
|
1051
|
-
this.audio = {
|
|
1052
|
-
deviceId: {
|
|
1053
|
-
exact: deviceId,
|
|
1054
|
-
},
|
|
1055
|
-
};
|
|
1056
|
-
}
|
|
1057
|
-
if (session && navigator.mediaDevices) {
|
|
1058
|
-
const sdh = session.sessionDescriptionHandler;
|
|
1059
|
-
const pc = sdh?.peerConnection;
|
|
1060
|
-
const constraints = {
|
|
1061
|
-
audio: {
|
|
1062
|
-
deviceId: {
|
|
1063
|
-
exact: deviceId,
|
|
1064
|
-
},
|
|
1065
|
-
},
|
|
1066
|
-
};
|
|
1067
|
-
const stream = await navigator.mediaDevices.getUserMedia(constraints);
|
|
1068
|
-
const audioTrack = stream.getAudioTracks()[0];
|
|
1069
|
-
const sender = pc && pc.getSenders && pc.getSenders().find((s) => audioTrack && s && s.track && s.track.kind === audioTrack.kind);
|
|
1070
|
-
if (sender) {
|
|
1071
|
-
if (sender.track) {
|
|
1072
|
-
audioTrack.enabled = sender.track.enabled;
|
|
1073
|
-
}
|
|
1074
|
-
sender.replaceTrack(audioTrack);
|
|
1075
|
-
}
|
|
1076
|
-
return stream;
|
|
1077
|
-
}
|
|
1078
|
-
return null;
|
|
1079
|
-
}
|
|
1080
|
-
async changeVideoInputDevice(id, session) {
|
|
1081
|
-
this.setVideoInputDevice(id);
|
|
1082
|
-
if (session) {
|
|
1083
|
-
return this.changeSessionVideoInputDevice(id, session);
|
|
1084
|
-
}
|
|
1085
|
-
}
|
|
1086
|
-
setVideoInputDevice(id) {
|
|
1087
|
-
const currentId = this.getVideoDeviceId();
|
|
1088
|
-
logger.info('setting video input device', {
|
|
1089
|
-
id,
|
|
1090
|
-
currentId,
|
|
1091
|
-
});
|
|
1092
|
-
if (id === currentId) {
|
|
1093
|
-
return null;
|
|
1094
|
-
}
|
|
1095
|
-
// let's make sure we don't lose other video constraints settings -- width, height, frameRate...
|
|
1096
|
-
const videoObject = typeof this.video === 'object' ? this.video : {};
|
|
1097
|
-
this.video = { ...videoObject,
|
|
1098
|
-
deviceId: {
|
|
1099
|
-
exact: id,
|
|
1100
|
-
},
|
|
1101
|
-
};
|
|
1102
|
-
}
|
|
1103
|
-
changeSessionVideoInputDevice(id, session) {
|
|
1104
|
-
if (!this.sessionWantsToDoVideo(session)) {
|
|
1105
|
-
return Promise.resolve();
|
|
1106
|
-
}
|
|
1107
|
-
const sdh = session.sessionDescriptionHandler;
|
|
1108
|
-
const pc = sdh.peerConnection;
|
|
1109
|
-
const sessionId = this.getSipSessionId(session);
|
|
1110
|
-
const localStream = this.getLocalStream(sessionId);
|
|
1111
|
-
logger.info('changing video input device', {
|
|
1112
|
-
id,
|
|
1113
|
-
sessionId,
|
|
1114
|
-
});
|
|
1115
|
-
// Release old video stream
|
|
1116
|
-
if (localStream) {
|
|
1117
|
-
localStream.getVideoTracks()
|
|
1118
|
-
.filter((track) => track.enabled)
|
|
1119
|
-
.forEach((track) => track.stop());
|
|
1120
|
-
}
|
|
1121
|
-
const constraints = {
|
|
1122
|
-
video: id ? {
|
|
1123
|
-
deviceId: {
|
|
1124
|
-
exact: id,
|
|
1125
|
-
},
|
|
1126
|
-
} : true,
|
|
1127
|
-
};
|
|
1128
|
-
return navigator.mediaDevices.getUserMedia(constraints).then(async (stream) => {
|
|
1129
|
-
const videoTrack = stream.getVideoTracks()[0];
|
|
1130
|
-
let sender = pc && pc.getSenders && pc.getSenders().find((s) => videoTrack && s && s.track && s.track.kind === videoTrack.kind);
|
|
1131
|
-
let wasTrackEnabled = false;
|
|
1132
|
-
if (!sender) {
|
|
1133
|
-
sender = pc && pc.getSenders && pc.getSenders().find((s) => !s.track);
|
|
1134
|
-
}
|
|
1135
|
-
if (sender) {
|
|
1136
|
-
// No video track means video not enabled
|
|
1137
|
-
wasTrackEnabled = sender.track ? sender.track.enabled : false;
|
|
1138
|
-
videoTrack.enabled = wasTrackEnabled;
|
|
1139
|
-
if (!wasTrackEnabled) {
|
|
1140
|
-
videoTrack.stop();
|
|
1141
|
-
}
|
|
1142
|
-
sender.replaceTrack(wasTrackEnabled ? videoTrack : null);
|
|
1143
|
-
}
|
|
1144
|
-
// let's update the local stream
|
|
1145
|
-
this.eventEmitter.emit('onVideoInputChange', stream);
|
|
1146
|
-
this.setLocalMediaStream(sessionId, stream);
|
|
1147
|
-
return stream;
|
|
1148
|
-
});
|
|
1149
|
-
}
|
|
1150
|
-
getAudioDeviceId() {
|
|
1151
|
-
return this.audio && typeof this.audio === 'object' && 'deviceId' in this.audio ? this.audio.deviceId?.exact : undefined;
|
|
1152
|
-
}
|
|
1153
|
-
getVideoDeviceId() {
|
|
1154
|
-
return this.video && typeof this.video === 'object' && 'deviceId' in this.video ? this.video.deviceId?.exact : undefined;
|
|
1155
|
-
}
|
|
1156
|
-
reinvite(sipSession, newConstraints = null, conference = false, audioOnly = false, iceRestart = false) {
|
|
1157
|
-
if (!sipSession) {
|
|
1158
|
-
return Promise.resolve();
|
|
1159
|
-
}
|
|
1160
|
-
// @ts-ignore: private
|
|
1161
|
-
if (sipSession.pendingReinvite) {
|
|
1162
|
-
return Promise.resolve();
|
|
1163
|
-
}
|
|
1164
|
-
const wasMuted = this.isAudioMuted(sipSession);
|
|
1165
|
-
const shouldDoVideo = newConstraints ? newConstraints.video : this.sessionWantsToDoVideo(sipSession);
|
|
1166
|
-
const shouldDoScreenSharing = newConstraints && newConstraints.screen;
|
|
1167
|
-
const desktop = newConstraints && newConstraints.desktop;
|
|
1168
|
-
logger.info('Sending reinvite', {
|
|
1169
|
-
clientId: this.clientId,
|
|
1170
|
-
id: this.getSipSessionId(sipSession),
|
|
1171
|
-
newConstraints,
|
|
1172
|
-
conference,
|
|
1173
|
-
audioOnly,
|
|
1174
|
-
wasMuted,
|
|
1175
|
-
shouldDoVideo,
|
|
1176
|
-
shouldDoScreenSharing,
|
|
1177
|
-
desktop,
|
|
1178
|
-
});
|
|
1179
|
-
// When upgrading to video, remove the `stripVideo` modifiers
|
|
1180
|
-
if (newConstraints && newConstraints.video) {
|
|
1181
|
-
const modifiers = sipSession.sessionDescriptionHandlerModifiersReInvite;
|
|
1182
|
-
sipSession.sessionDescriptionHandlerModifiersReInvite = modifiers.filter(modifier => modifier !== stripVideo);
|
|
1183
|
-
}
|
|
1184
|
-
sipSession.sessionDescriptionHandlerOptionsReInvite = { ...sipSession.sessionDescriptionHandlerOptionsReInvite,
|
|
1185
|
-
conference,
|
|
1186
|
-
audioOnly,
|
|
1187
|
-
};
|
|
1188
|
-
const { constraints, } = this.getMediaConfiguration(shouldDoVideo, conference, newConstraints);
|
|
1189
|
-
return sipSession.invite({
|
|
1190
|
-
requestDelegate: {
|
|
1191
|
-
onAccept: (response) => {
|
|
1192
|
-
// Update the SDP body to be able to call sessionWantsToDoVideo correctly in `_setup[Local|Remote]Media`.
|
|
1193
|
-
// Can't set directly sipSession.body because it's a getter.
|
|
1194
|
-
// @ts-ignore: private
|
|
1195
|
-
if (sipSession instanceof Inviter && sipSession.outgoingRequestMessage.body) {
|
|
1196
|
-
// @ts-ignore: private
|
|
1197
|
-
sipSession.outgoingRequestMessage.body.body = response.message.body;
|
|
1198
|
-
}
|
|
1199
|
-
else if (sipSession instanceof Invitation) {
|
|
1200
|
-
// @ts-ignore: private
|
|
1201
|
-
sipSession.incomingInviteRequest.message.body = response.message.body;
|
|
1202
|
-
}
|
|
1203
|
-
logger.info('on re-INVITE accepted', {
|
|
1204
|
-
id: this.getSipSessionId(sipSession),
|
|
1205
|
-
wasMuted,
|
|
1206
|
-
shouldDoScreenSharing,
|
|
1207
|
-
});
|
|
1208
|
-
this.updateRemoteStream(this.getSipSessionId(sipSession), false);
|
|
1209
|
-
if (wasMuted) {
|
|
1210
|
-
this.mute(sipSession);
|
|
1211
|
-
}
|
|
1212
|
-
this._onAccepted(sipSession, response.session, false, false);
|
|
1213
|
-
if (shouldDoScreenSharing) {
|
|
1214
|
-
this.eventEmitter.emit(ON_SCREEN_SHARING_REINVITE, sipSession, response, desktop);
|
|
1215
|
-
}
|
|
1216
|
-
return this.eventEmitter.emit(ON_REINVITE, sipSession, response);
|
|
1217
|
-
},
|
|
1218
|
-
},
|
|
1219
|
-
sessionDescriptionHandlerModifiers: [replaceLocalIpModifier],
|
|
1220
|
-
requestOptions: {
|
|
1221
|
-
extraHeaders: [`Subject: ${shouldDoScreenSharing ? 'screenshare' : 'upgrade-video'}`],
|
|
1222
|
-
},
|
|
1223
|
-
sessionDescriptionHandlerOptions: {
|
|
1224
|
-
constraints,
|
|
1225
|
-
conference,
|
|
1226
|
-
audioOnly,
|
|
1227
|
-
offerOptions: {
|
|
1228
|
-
iceRestart,
|
|
1229
|
-
},
|
|
1230
|
-
},
|
|
1231
|
-
});
|
|
1232
|
-
}
|
|
1233
|
-
async getUserMedia(constraints) {
|
|
1234
|
-
const newConstraints = {
|
|
1235
|
-
audio: this._getAudioConstraints(),
|
|
1236
|
-
video: this._getVideoConstraints(constraints.video),
|
|
1237
|
-
};
|
|
1238
|
-
return navigator.mediaDevices.getUserMedia(newConstraints);
|
|
1239
|
-
}
|
|
1240
|
-
getPeerConnection(sessionId) {
|
|
1241
|
-
const sipSession = this.sipSessions[sessionId];
|
|
1242
|
-
if (!sipSession) {
|
|
1243
|
-
return null;
|
|
1244
|
-
}
|
|
1245
|
-
return sipSession.sessionDescriptionHandler ? sipSession.sessionDescriptionHandler.peerConnection : null;
|
|
1246
|
-
}
|
|
1247
|
-
// Local streams
|
|
1248
|
-
getLocalStream(sessionId) {
|
|
1249
|
-
const sipSession = this.sipSessions[sessionId];
|
|
1250
|
-
return sipSession?.sessionDescriptionHandler?.localMediaStream || null;
|
|
1251
|
-
}
|
|
1252
|
-
getLocalTracks(sessionId) {
|
|
1253
|
-
const localStream = this.getLocalStream(sessionId);
|
|
1254
|
-
if (!localStream) {
|
|
1255
|
-
return [];
|
|
1256
|
-
}
|
|
1257
|
-
return localStream.getTracks();
|
|
1258
|
-
}
|
|
1259
|
-
hasLocalVideo(sessionId) {
|
|
1260
|
-
return this.getLocalTracks(sessionId).some(this._isVideoTrack);
|
|
1261
|
-
}
|
|
1262
|
-
// Check if we have at least one video track, even muted or not live
|
|
1263
|
-
hasALocalVideoTrack(sessionId) {
|
|
1264
|
-
return this.getLocalTracks(sessionId).some(track => track.kind === 'video');
|
|
1265
|
-
}
|
|
1266
|
-
getLocalVideoStream(sessionId) {
|
|
1267
|
-
return this.hasLocalVideo(sessionId) ? this.getLocalStream(sessionId) : null;
|
|
1268
|
-
}
|
|
1269
|
-
// Remote streams
|
|
1270
|
-
getRemoteStream(sessionId) {
|
|
1271
|
-
const sipSession = this.sipSessions[sessionId];
|
|
1272
|
-
return sipSession?.sessionDescriptionHandler?.remoteMediaStream || null;
|
|
1273
|
-
}
|
|
1274
|
-
getRemoteTracks(sessionId) {
|
|
1275
|
-
const remoteStream = this.getRemoteStream(sessionId);
|
|
1276
|
-
if (!remoteStream) {
|
|
1277
|
-
return [];
|
|
1278
|
-
}
|
|
1279
|
-
return remoteStream.getTracks();
|
|
1280
|
-
}
|
|
1281
|
-
hasRemoteVideo(sessionId) {
|
|
1282
|
-
return this.getRemoteTracks(sessionId).some(this._isVideoTrack);
|
|
1283
|
-
}
|
|
1284
|
-
// Check if we have at least one video track, even muted or not live
|
|
1285
|
-
hasARemoteVideoTrack(sessionId) {
|
|
1286
|
-
return this.getRemoteTracks(sessionId).some(track => track.kind === 'video');
|
|
1287
|
-
}
|
|
1288
|
-
getRemoteVideoStream(sessionId) {
|
|
1289
|
-
if (this.isVideoRemotelyHeld(sessionId)) {
|
|
1290
|
-
return null;
|
|
1291
|
-
}
|
|
1292
|
-
return this.hasRemoteVideo(sessionId) ? this.getRemoteStream(sessionId) : null;
|
|
1293
|
-
}
|
|
1294
|
-
// Useful in a react-native environment when remoteMediaStream is not updated
|
|
1295
|
-
getRemoteVideoStreamFromPc(sessionId) {
|
|
1296
|
-
const pc = this.getPeerConnection(sessionId);
|
|
1297
|
-
if (!pc) {
|
|
1298
|
-
return null;
|
|
1299
|
-
}
|
|
1300
|
-
return pc.getRemoteStreams().find((stream) => !!stream.getVideoTracks().length);
|
|
1301
|
-
}
|
|
1302
|
-
hasVideo(sessionId) {
|
|
1303
|
-
return this.hasLocalVideo(sessionId) || this.hasRemoteVideo(sessionId);
|
|
1304
|
-
}
|
|
1305
|
-
hasAVideoTrack(sessionId) {
|
|
1306
|
-
return this.hasALocalVideoTrack(sessionId) || this.hasARemoteVideoTrack(sessionId);
|
|
1307
|
-
}
|
|
1308
|
-
getSipSessionId(sipSession) {
|
|
1309
|
-
if (!sipSession) {
|
|
1310
|
-
return '';
|
|
1311
|
-
}
|
|
1312
|
-
// For Inviter
|
|
1313
|
-
// @ts-ignore: private
|
|
1314
|
-
if (sipSession instanceof Inviter && sipSession.outgoingRequestMessage) {
|
|
1315
|
-
// @ts-ignore: private
|
|
1316
|
-
return sipSession.outgoingRequestMessage.callId;
|
|
1317
|
-
}
|
|
1318
|
-
// For Invitation
|
|
1319
|
-
// @ts-ignore: private
|
|
1320
|
-
if (sipSession instanceof Invitation && sipSession.incomingInviteRequest.message) {
|
|
1321
|
-
// @ts-ignore: private
|
|
1322
|
-
return sipSession.incomingInviteRequest.message.callId;
|
|
1323
|
-
}
|
|
1324
|
-
// For EarlyMedia
|
|
1325
|
-
// @ts-ignore: private
|
|
1326
|
-
if (sipSession instanceof SessionDialog) {
|
|
1327
|
-
// @ts-ignore: private
|
|
1328
|
-
return sipSession.dialogState.callId;
|
|
1329
|
-
}
|
|
1330
|
-
return '';
|
|
1331
|
-
}
|
|
1332
|
-
async waitForRegister() {
|
|
1333
|
-
return new Promise(resolve => this.on(REGISTERED, resolve));
|
|
1334
|
-
}
|
|
1335
|
-
// eslint-disable-next-line no-unused-vars
|
|
1336
|
-
sessionWantsToDoVideo(session) {
|
|
1337
|
-
if (!session) {
|
|
1338
|
-
return false;
|
|
1339
|
-
}
|
|
1340
|
-
const { body, } = session.request || session;
|
|
1341
|
-
// Sometimes with InviteClientContext the body is in the body attribute ...
|
|
1342
|
-
const sdp = typeof body === 'object' && body ? body.body : body;
|
|
1343
|
-
return hasAnActiveVideo(sdp);
|
|
1344
|
-
}
|
|
1345
|
-
hasHeartbeat() {
|
|
1346
|
-
return this.heartbeat.hasHeartbeat;
|
|
1347
|
-
}
|
|
1348
|
-
startHeartbeat() {
|
|
1349
|
-
logger.info('sdk webrtc start heartbeat', { userAgent: !!this.userAgent, clientId: this.clientId });
|
|
1350
|
-
if (!this.userAgent) {
|
|
1351
|
-
this.heartbeat.stop();
|
|
1352
|
-
return;
|
|
1353
|
-
}
|
|
1354
|
-
this.eventEmitter.off(MESSAGE, this._boundOnHeartbeat);
|
|
1355
|
-
this.eventEmitter.on(MESSAGE, this._boundOnHeartbeat);
|
|
1356
|
-
this.heartbeat.start();
|
|
1357
|
-
}
|
|
1358
|
-
stopHeartbeat() {
|
|
1359
|
-
logger.info('sdk webrtc stop heartbeat', { clientId: this.clientId });
|
|
1360
|
-
this.heartbeat.stop();
|
|
1361
|
-
}
|
|
1362
|
-
setOnHeartbeatTimeout(cb) {
|
|
1363
|
-
this.heartbeatTimeoutCb = cb;
|
|
1364
|
-
}
|
|
1365
|
-
setOnHeartbeatCallback(cb) {
|
|
1366
|
-
this.heartbeatCb = cb;
|
|
1367
|
-
}
|
|
1368
|
-
onCallEnded(session) {
|
|
1369
|
-
this._cleanupMedia(session);
|
|
1370
|
-
delete this.sipSessions[this.getSipSessionId(session)];
|
|
1371
|
-
this._stopSendingStats(session);
|
|
1372
|
-
this.stopNetworkMonitoring(session);
|
|
1373
|
-
}
|
|
1374
|
-
attemptReconnection() {
|
|
1375
|
-
logger.info('attempt reconnection', { clientId: this.clientId, userAgent: !!this.userAgent });
|
|
1376
|
-
if (!this.userAgent) {
|
|
1377
|
-
return;
|
|
1378
|
-
}
|
|
1379
|
-
// @ts-ignore: private
|
|
1380
|
-
this.userAgent.attemptReconnection();
|
|
1381
|
-
}
|
|
1382
|
-
storeSipSession(session) {
|
|
1383
|
-
const id = this.getSipSessionId(session);
|
|
1384
|
-
logger.info('storing sip session', { id, clientId: this.clientId });
|
|
1385
|
-
this.sipSessions[id] = session;
|
|
1386
|
-
}
|
|
1387
|
-
getSipSession(id) {
|
|
1388
|
-
return id in this.sipSessions ? this.sipSessions[id] : null;
|
|
1389
|
-
}
|
|
1390
|
-
getSipSessionIds() {
|
|
1391
|
-
return Object.keys(this.sipSessions);
|
|
1392
|
-
}
|
|
1393
|
-
setLocalMediaStream(sipSessionId, newStream) {
|
|
1394
|
-
const sipSession = this.sipSessions[sipSessionId];
|
|
1395
|
-
if (!sipSession) {
|
|
1396
|
-
return;
|
|
1397
|
-
}
|
|
1398
|
-
logger.info('setting local media stream', {
|
|
1399
|
-
sipSessionId,
|
|
1400
|
-
tracks: newStream ? newStream.getTracks() : null,
|
|
1401
|
-
});
|
|
1402
|
-
if (sipSession.sessionDescriptionHandler) {
|
|
1403
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
1404
|
-
// @ts-ignore: protected
|
|
1405
|
-
sipSession.sessionDescriptionHandler._localMediaStream = newStream;
|
|
1406
|
-
}
|
|
1407
|
-
}
|
|
1408
|
-
async updateLocalStream(sipSessionId, newStream) {
|
|
1409
|
-
const sipSession = this.sipSessions[sipSessionId];
|
|
1410
|
-
if (!sipSession) {
|
|
1411
|
-
return;
|
|
1412
|
-
}
|
|
1413
|
-
const oldStream = this.getLocalStream(sipSessionId);
|
|
1414
|
-
logger.info('updating local stream', {
|
|
1415
|
-
sipSessionId,
|
|
1416
|
-
oldStream: !!oldStream,
|
|
1417
|
-
tracks: newStream.getTracks(),
|
|
1418
|
-
});
|
|
1419
|
-
if (oldStream) {
|
|
1420
|
-
this._cleanupStream(oldStream);
|
|
1421
|
-
}
|
|
1422
|
-
this.setLocalMediaStream(sipSessionId, newStream);
|
|
1423
|
-
// Update the local video element
|
|
1424
|
-
await this._setupMedias(sipSession, newStream);
|
|
1425
|
-
}
|
|
1426
|
-
updateRemoteStream(sessionId, allTracks = true) {
|
|
1427
|
-
const remoteStream = this.getRemoteStream(sessionId);
|
|
1428
|
-
const pc = this.getPeerConnection(sessionId);
|
|
1429
|
-
logger.info('Updating remote stream', {
|
|
1430
|
-
sessionId,
|
|
1431
|
-
tracks: remoteStream ? remoteStream.getTracks() : null,
|
|
1432
|
-
receiverTracks: pc && pc.getReceivers ? pc.getReceivers().map((receiver) => receiver.track) : null,
|
|
1433
|
-
});
|
|
1434
|
-
if (!pc || !remoteStream) {
|
|
1435
|
-
return;
|
|
1436
|
-
}
|
|
1437
|
-
remoteStream.getTracks().forEach(track => {
|
|
1438
|
-
if (allTracks || track.kind === 'video') {
|
|
1439
|
-
remoteStream.removeTrack(track);
|
|
1440
|
-
}
|
|
1441
|
-
});
|
|
1442
|
-
if (pc.getReceivers) {
|
|
1443
|
-
pc.getReceivers().forEach((receiver) => {
|
|
1444
|
-
if (allTracks || receiver.track.kind === 'video') {
|
|
1445
|
-
remoteStream.addTrack(receiver.track);
|
|
1446
|
-
}
|
|
1447
|
-
});
|
|
1448
|
-
}
|
|
1449
|
-
}
|
|
1450
|
-
getMediaConfiguration(enableVideo, conference = false, constraints = null) {
|
|
1451
|
-
const screenSharing = constraints && 'screen' in constraints ? constraints.screen : false;
|
|
1452
|
-
const isDesktop = constraints && 'desktop' in constraints ? constraints.desktop : false;
|
|
1453
|
-
const withAudio = constraints && 'audio' in constraints ? constraints.audio : true;
|
|
1454
|
-
const mandatoryVideo = constraints && typeof constraints.video === 'object' ? constraints.video.mandatory : {};
|
|
1455
|
-
logger.info('Retrieving media a configuration', {
|
|
1456
|
-
enableVideo,
|
|
1457
|
-
screenSharing,
|
|
1458
|
-
isDesktop,
|
|
1459
|
-
withAudio,
|
|
1460
|
-
constraints,
|
|
1461
|
-
});
|
|
1462
|
-
return {
|
|
1463
|
-
constraints: {
|
|
1464
|
-
// Exact constraint are not supported with `getDisplayMedia` and we must have a video=false in desktop screenshare
|
|
1465
|
-
audio: screenSharing ? !isDesktop : withAudio ? this._getAudioConstraints() : false,
|
|
1466
|
-
video: screenSharing ? isDesktop ? {
|
|
1467
|
-
mandatory: {
|
|
1468
|
-
chromeMediaSource: 'desktop',
|
|
1469
|
-
...(mandatoryVideo || {}),
|
|
1470
|
-
},
|
|
1471
|
-
} : {
|
|
1472
|
-
cursor: 'always',
|
|
1473
|
-
} : this._getVideoConstraints(enableVideo),
|
|
1474
|
-
screen: screenSharing,
|
|
1475
|
-
desktop: isDesktop,
|
|
1476
|
-
conference,
|
|
1477
|
-
},
|
|
1478
|
-
enableVideo,
|
|
1479
|
-
conference,
|
|
1480
|
-
offerOptions: {
|
|
1481
|
-
OfferToReceiveAudio: this._hasAudio(),
|
|
1482
|
-
OfferToReceiveVideo: enableVideo,
|
|
1483
|
-
mandatory: {
|
|
1484
|
-
OfferToReceiveAudio: this._hasAudio(),
|
|
1485
|
-
OfferToReceiveVideo: enableVideo,
|
|
1486
|
-
},
|
|
1487
|
-
},
|
|
1488
|
-
};
|
|
1489
|
-
}
|
|
1490
|
-
isConference(sessionId) {
|
|
1491
|
-
return sessionId in this.conferences;
|
|
1492
|
-
}
|
|
1493
|
-
async createAudioElementFor(sessionId) {
|
|
1494
|
-
const audio = document.createElement('audio');
|
|
1495
|
-
audio.setAttribute('id', `audio-${sessionId}`);
|
|
1496
|
-
logger.info('creating audio element', { sessionId, audioOutputDeviceId: this.audioOutputDeviceId });
|
|
1497
|
-
if (this.audioOutputDeviceId) {
|
|
1498
|
-
await audio.setSinkId(this.audioOutputDeviceId);
|
|
1499
|
-
}
|
|
1500
|
-
if (document.body) {
|
|
1501
|
-
document.body.appendChild(audio);
|
|
1502
|
-
}
|
|
1503
|
-
this.audioElements[sessionId] = audio;
|
|
1504
|
-
audio.volume = this.audioOutputVolume;
|
|
1505
|
-
audio.autoplay = true;
|
|
1506
|
-
return audio;
|
|
1507
|
-
}
|
|
1508
|
-
_onTransportError() {
|
|
1509
|
-
logger.error('on transport error');
|
|
1510
|
-
this.eventEmitter.emit(TRANSPORT_ERROR);
|
|
1511
|
-
this.attemptReconnection();
|
|
1512
|
-
}
|
|
1513
|
-
enableLogger(logConnector) {
|
|
1514
|
-
if (!this.userAgent) {
|
|
1515
|
-
return;
|
|
1516
|
-
}
|
|
1517
|
-
if (this.userAgent?.transport) {
|
|
1518
|
-
this.userAgent.transport.configuration.traceSip = true;
|
|
1519
|
-
}
|
|
1520
|
-
// @ts-ignore: private
|
|
1521
|
-
this.userAgent.loggerFactory.builtinEnabled = true;
|
|
1522
|
-
// @ts-ignore: private
|
|
1523
|
-
this.userAgent.loggerFactory.level = 3; // debug
|
|
1524
|
-
// @ts-ignore: private
|
|
1525
|
-
this.userAgent.loggerFactory.connector = logConnector;
|
|
1526
|
-
}
|
|
1527
|
-
_onHeartbeat(message) {
|
|
1528
|
-
const body = message && typeof message === 'object' ? message.data : message;
|
|
1529
|
-
if (body && body.indexOf('200 OK') !== -1) {
|
|
1530
|
-
if (this.hasHeartbeat()) {
|
|
1531
|
-
logger.info('on heartbeat received from Asterisk', {
|
|
1532
|
-
hasHeartbeat: this.hasHeartbeat(),
|
|
1533
|
-
});
|
|
1534
|
-
this.heartbeat.onHeartbeat();
|
|
1535
|
-
if (this.heartbeatCb) {
|
|
1536
|
-
this.heartbeatCb();
|
|
1537
|
-
}
|
|
1538
|
-
}
|
|
1539
|
-
}
|
|
1540
|
-
}
|
|
1541
|
-
async _onHeartbeatTimeout() {
|
|
1542
|
-
logger.warn('sdk webrtc heartbeat timed out', {
|
|
1543
|
-
userAgent: !!this.userAgent,
|
|
1544
|
-
cb: !!this.heartbeatTimeoutCb,
|
|
1545
|
-
});
|
|
1546
|
-
if (this.heartbeatTimeoutCb) {
|
|
1547
|
-
this.heartbeatTimeoutCb();
|
|
1548
|
-
}
|
|
1549
|
-
if (this.userAgent && this.userAgent.transport) {
|
|
1550
|
-
// Disconnect from WS and triggers events, but do not trigger disconnect if already disconnecting...
|
|
1551
|
-
const transport = this.userAgent.transport;
|
|
1552
|
-
// @HEADS UP
|
|
1553
|
-
if (!transport.transitioningState && !transport.disconnectPromise) {
|
|
1554
|
-
try {
|
|
1555
|
-
await this.userAgent.transport.disconnect();
|
|
1556
|
-
}
|
|
1557
|
-
catch (e) {
|
|
1558
|
-
logger.error('Transport disconnection after heartbeat timeout, error', e);
|
|
1559
|
-
}
|
|
1560
|
-
}
|
|
1561
|
-
// We can invoke disconnect() with an error that can be catcher by `onDisconnect`, so we have to trigger it here.
|
|
1562
|
-
this._onTransportError();
|
|
1563
|
-
}
|
|
1564
|
-
}
|
|
1565
|
-
_isWeb() {
|
|
1566
|
-
return typeof window === 'object' && typeof document === 'object';
|
|
1567
|
-
}
|
|
1568
|
-
_isVideoTrack(track) {
|
|
1569
|
-
return track.kind === 'video' && track.readyState === 'live';
|
|
1570
|
-
}
|
|
1571
|
-
_hasAudio() {
|
|
1572
|
-
return this.hasAudio;
|
|
1573
|
-
}
|
|
1574
|
-
_getAudioConstraints() {
|
|
1575
|
-
// @ts-ignore: media constraints
|
|
1576
|
-
return this.audio?.deviceId?.exact ? this.audio : true;
|
|
1577
|
-
}
|
|
1578
|
-
_getVideoConstraints(video = false) {
|
|
1579
|
-
if (!video) {
|
|
1580
|
-
return false;
|
|
1581
|
-
}
|
|
1582
|
-
// @ts-ignore: media constraints
|
|
1583
|
-
return this.video?.deviceId?.exact ? this.video : true;
|
|
1584
|
-
}
|
|
1585
|
-
_connectIfNeeded() {
|
|
1586
|
-
logger.info('connect if needed, checking', { connected: this.isConnected(), clientId: this.clientId });
|
|
1587
|
-
if (!this.userAgent) {
|
|
1588
|
-
logger.info('need to recreate User Agent');
|
|
1589
|
-
this.userAgent = this.createUserAgent(this.uaConfigOverrides);
|
|
1590
|
-
}
|
|
1591
|
-
if (this.isConnected()) {
|
|
1592
|
-
logger.info('webrtc sdk, already connected');
|
|
1593
|
-
return Promise.resolve();
|
|
1594
|
-
}
|
|
1595
|
-
if (this.isConnecting()) {
|
|
1596
|
-
logger.info('webrtc sdk, already connecting...');
|
|
1597
|
-
this.connectionPromise = this.userAgent.transport.connectPromise;
|
|
1598
|
-
return Promise.resolve(this.connectionPromise);
|
|
1599
|
-
}
|
|
1600
|
-
if (this.connectionPromise) {
|
|
1601
|
-
logger.info('webrtc sdk, connection promise connecting...');
|
|
1602
|
-
return this.connectionPromise;
|
|
1603
|
-
}
|
|
1604
|
-
logger.info('WebRTC UA needs to connect');
|
|
1605
|
-
// Force UA to reconnect
|
|
1606
|
-
if (this.userAgent && this.userAgent.state !== UserAgentState.Stopped) {
|
|
1607
|
-
// @ts-ignore: private
|
|
1608
|
-
this.userAgent.transitionState(UserAgentState.Stopped);
|
|
1609
|
-
}
|
|
1610
|
-
if (this.userAgent.transport && this.userAgent.transport.state !== TransportState.Disconnected) {
|
|
1611
|
-
this.userAgent.transport.transitionState(TransportState.Disconnected);
|
|
1612
|
-
}
|
|
1613
|
-
this.connectionPromise = this.userAgent.start().catch(console.error);
|
|
1614
|
-
return this.connectionPromise;
|
|
1615
|
-
}
|
|
1616
|
-
_buildConfig(config, session) {
|
|
1617
|
-
// If no session provided, return the configuration directly
|
|
1618
|
-
if (!session) {
|
|
1619
|
-
return new Promise(resolve => resolve(config));
|
|
1620
|
-
}
|
|
1621
|
-
const client = new ApiClient({
|
|
1622
|
-
server: `${config.host}:${String(config.port || 443)}`,
|
|
1623
|
-
});
|
|
1624
|
-
client.setToken(session.token);
|
|
1625
|
-
client.setRefreshToken(session.refreshToken);
|
|
1626
|
-
return client.confd.getUserLineSipFromToken(session.uuid).then(sipLine => ({
|
|
1627
|
-
authorizationUser: sipLine.username,
|
|
1628
|
-
password: sipLine.secret,
|
|
1629
|
-
uri: `${sipLine.username}@${config.host}`,
|
|
1630
|
-
...config,
|
|
1631
|
-
}));
|
|
1632
|
-
}
|
|
1633
|
-
_createUaOptions(uaOptionsOverrides = {}) {
|
|
1634
|
-
let { host, } = this.config;
|
|
1635
|
-
let port = this.config.port || 443;
|
|
1636
|
-
if (this.config.websocketSip) {
|
|
1637
|
-
const webSocketSip = this.config.websocketSip.split(':');
|
|
1638
|
-
[host] = webSocketSip;
|
|
1639
|
-
port = Number(webSocketSip[1]);
|
|
1640
|
-
}
|
|
1641
|
-
const { userUuid } = this.config;
|
|
1642
|
-
const uaOptions = {
|
|
1643
|
-
noAnswerTimeout: NO_ANSWER_TIMEOUT,
|
|
1644
|
-
authorizationUsername: this.config.authorizationUser,
|
|
1645
|
-
authorizationPassword: this.config.password,
|
|
1646
|
-
displayName: this.config.displayName,
|
|
1647
|
-
hackIpInContact: true,
|
|
1648
|
-
logBuiltinEnabled: this.config.log ? this.config.log.builtinEnabled : null,
|
|
1649
|
-
logLevel: this.config.log ? this.config.log.logLevel : null,
|
|
1650
|
-
logConnector: this.config.log ? this.config.log.connector : null,
|
|
1651
|
-
uri: this._makeURI(this.config.authorizationUser || ''),
|
|
1652
|
-
userAgentString: this.config.userAgentString || 'wazo-sdk',
|
|
1653
|
-
reconnectionAttempts: 10000,
|
|
1654
|
-
reconnectionDelay: 5,
|
|
1655
|
-
sessionDescriptionHandlerFactory: (session, options = {}) => {
|
|
1656
|
-
const uaLogger = session.userAgent.getLogger('sip.WazoSessionDescriptionHandler');
|
|
1657
|
-
const isWeb = this._isWeb();
|
|
1658
|
-
const iceGatheringTimeout = 'peerConnectionOptions' in options ? options.peerConnectionOptions.iceGatheringTimeout || DEFAULT_ICE_TIMEOUT : DEFAULT_ICE_TIMEOUT;
|
|
1659
|
-
const sdhOptions = { ...options,
|
|
1660
|
-
iceGatheringTimeout,
|
|
1661
|
-
peerConnectionConfiguration: { ...defaultPeerConnectionConfiguration(),
|
|
1662
|
-
...(options.peerConnectionConfiguration || {}),
|
|
1663
|
-
},
|
|
1664
|
-
};
|
|
1665
|
-
return new WazoSessionDescriptionHandler(uaLogger, wazoMediaStreamFactory, sdhOptions, isWeb, session);
|
|
1666
|
-
},
|
|
1667
|
-
transportOptions: {
|
|
1668
|
-
traceSip: uaOptionsOverrides?.traceSip || false,
|
|
1669
|
-
wsServers: `wss://${host}:${port}/api/asterisk/ws${userUuid ? `?userUuid=${userUuid}` : ''}`,
|
|
1670
|
-
},
|
|
1671
|
-
sessionDescriptionHandlerFactoryOptions: {
|
|
1672
|
-
modifiers: [replaceLocalIpModifier],
|
|
1673
|
-
alwaysAcquireMediaFirst: this.isFirefox(),
|
|
1674
|
-
constraints: {
|
|
1675
|
-
audio: this._getAudioConstraints(),
|
|
1676
|
-
video: this._getVideoConstraints(),
|
|
1677
|
-
},
|
|
1678
|
-
peerConnectionOptions: {
|
|
1679
|
-
iceCheckingTimeout: this.config.iceCheckingTimeout || 1000,
|
|
1680
|
-
iceGatheringTimeout: this.config.iceCheckingTimeout || 1000,
|
|
1681
|
-
rtcConfiguration: {
|
|
1682
|
-
rtcpMuxPolicy: 'require',
|
|
1683
|
-
iceServers: WebRTCClient.getIceServers(this.config.host),
|
|
1684
|
-
...this._getRtcOptions(),
|
|
1685
|
-
...(uaOptionsOverrides?.peerConnectionOptions || {}),
|
|
1686
|
-
},
|
|
1687
|
-
},
|
|
1688
|
-
// Configuration used in SDH to create the PeerConnection
|
|
1689
|
-
peerConnectionConfiguration: {
|
|
1690
|
-
rtcpMuxPolicy: 'require',
|
|
1691
|
-
iceServers: WebRTCClient.getIceServers(this.config.host),
|
|
1692
|
-
...(uaOptionsOverrides?.peerConnectionOptions || {}),
|
|
1693
|
-
},
|
|
1694
|
-
},
|
|
1695
|
-
};
|
|
1696
|
-
delete uaOptionsOverrides?.traceSip;
|
|
1697
|
-
return {
|
|
1698
|
-
...uaOptions,
|
|
1699
|
-
...uaOptionsOverrides,
|
|
1700
|
-
};
|
|
1701
|
-
}
|
|
1702
|
-
// eslint-disable-next-line no-unused-vars
|
|
1703
|
-
_getRtcOptions() {
|
|
1704
|
-
return {
|
|
1705
|
-
mandatory: {
|
|
1706
|
-
OfferToReceiveAudio: this._hasAudio(),
|
|
1707
|
-
OfferToReceiveVideo: false,
|
|
1708
|
-
},
|
|
1709
|
-
};
|
|
1710
|
-
}
|
|
1711
|
-
// Invitation and Inviter extends Session
|
|
1712
|
-
_setupSession(session) {
|
|
1713
|
-
const sipSessionId = this.getSipSessionId(session);
|
|
1714
|
-
// When receiving an Invitation, the delegate is not defined.
|
|
1715
|
-
if (!session.delegate) {
|
|
1716
|
-
session.delegate = {};
|
|
1717
|
-
}
|
|
1718
|
-
session.delegate.onSessionDescriptionHandler = (sdh) => {
|
|
1719
|
-
sdh.on('error', (e) => {
|
|
1720
|
-
this.eventEmitter.emit(ON_ERROR, e);
|
|
1721
|
-
});
|
|
1722
|
-
sdh.peerConnectionDelegate = {
|
|
1723
|
-
onicecandidateerror: (error) => {
|
|
1724
|
-
logger.error('on icecandidate error', {
|
|
1725
|
-
address: error.address,
|
|
1726
|
-
port: error.port,
|
|
1727
|
-
errorCode: error.errorCode,
|
|
1728
|
-
errorText: error.errorText,
|
|
1729
|
-
url: error.url,
|
|
1730
|
-
});
|
|
1731
|
-
},
|
|
1732
|
-
};
|
|
1733
|
-
};
|
|
1734
|
-
// @ts-ignore: protected
|
|
1735
|
-
const oldInviteRequest = session.onInviteRequest.bind(session);
|
|
1736
|
-
let hadRemoteVideo = false;
|
|
1737
|
-
// Monkey patch `onInviteRequest` to be able to know if there was a remote video stream before `onInvite` is called
|
|
1738
|
-
// Because when `onInvite` is called we already got the video track
|
|
1739
|
-
// @ts-ignore: protected
|
|
1740
|
-
session.onInviteRequest = request => {
|
|
1741
|
-
hadRemoteVideo = this.hasARemoteVideoTrack(sipSessionId);
|
|
1742
|
-
oldInviteRequest(request);
|
|
1743
|
-
};
|
|
1744
|
-
session.delegate.onInvite = async (request) => {
|
|
1745
|
-
let updatedCalleeName = null;
|
|
1746
|
-
let updatedNumber = null;
|
|
1747
|
-
if (session.assertedIdentity) {
|
|
1748
|
-
// @ts-ignore: private
|
|
1749
|
-
updatedNumber = session.assertedIdentity.uri.normal.user;
|
|
1750
|
-
updatedCalleeName = session.assertedIdentity.displayName || updatedNumber;
|
|
1751
|
-
}
|
|
1752
|
-
logger.info('re-invite received', {
|
|
1753
|
-
updatedCalleeName,
|
|
1754
|
-
updatedNumber,
|
|
1755
|
-
hadRemoteVideo,
|
|
1756
|
-
});
|
|
1757
|
-
// Useful to know if it's a video upgrade or an unhold from a remote peer with a video stream
|
|
1758
|
-
// Update SDP
|
|
1759
|
-
// Remote video is handled by the `track` event. Here we're dealing with video stream removal.
|
|
1760
|
-
if (session instanceof Invitation) {
|
|
1761
|
-
// @ts-ignore: private
|
|
1762
|
-
session.incomingInviteRequest.message.body = request.body;
|
|
1763
|
-
// @ts-ignore: private
|
|
1764
|
-
}
|
|
1765
|
-
else if (session instanceof Inviter && session.outgoingInviteRequest.message.body) {
|
|
1766
|
-
// @ts-ignore: private
|
|
1767
|
-
session.outgoingInviteRequest.message.body.body = request.body;
|
|
1768
|
-
}
|
|
1769
|
-
this.updateRemoteStream(sipSessionId, false);
|
|
1770
|
-
await this._setupMedias(session);
|
|
1771
|
-
return this.eventEmitter.emit(ON_REINVITE, session, request, updatedCalleeName, updatedNumber, hadRemoteVideo);
|
|
1772
|
-
};
|
|
1773
|
-
}
|
|
1774
|
-
async _onProgress(session, early = false) {
|
|
1775
|
-
await this._setupMedias(session);
|
|
1776
|
-
const sessionId = this.getSipSessionId(session);
|
|
1777
|
-
this.updateRemoteStream(sessionId);
|
|
1778
|
-
logger.info('progress received', {
|
|
1779
|
-
sessionId,
|
|
1780
|
-
early,
|
|
1781
|
-
});
|
|
1782
|
-
this.eventEmitter.emit(early ? ON_EARLY_MEDIA : ON_PROGRESS, session);
|
|
1783
|
-
}
|
|
1784
|
-
async _onAccepted(session, sessionDialog, withEvent = true, initAllTracks = true) {
|
|
1785
|
-
logger.info('on call accepted', {
|
|
1786
|
-
id: this.getSipSessionId(session),
|
|
1787
|
-
clientId: this.clientId,
|
|
1788
|
-
remoteTag: session.remoteTag,
|
|
1789
|
-
});
|
|
1790
|
-
this.storeSipSession(session);
|
|
1791
|
-
await this._setupMedias(session);
|
|
1792
|
-
this.updateRemoteStream(this.getSipSessionId(session), initAllTracks);
|
|
1793
|
-
const pc = session.sessionDescriptionHandler?.peerConnection;
|
|
1794
|
-
const onTrack = (event) => {
|
|
1795
|
-
const isAudioOnly = this._isAudioOnly(session);
|
|
1796
|
-
const { kind, label, readyState, id, muted, } = event.track;
|
|
1797
|
-
logger.info('on track event', {
|
|
1798
|
-
isAudioOnly,
|
|
1799
|
-
kind,
|
|
1800
|
-
label,
|
|
1801
|
-
readyState,
|
|
1802
|
-
id,
|
|
1803
|
-
muted,
|
|
1804
|
-
});
|
|
1805
|
-
// Stop video track in audio only mode
|
|
1806
|
-
if (isAudioOnly && kind === 'video') {
|
|
1807
|
-
event.track.stop();
|
|
1808
|
-
}
|
|
1809
|
-
this.eventEmitter.emit(ON_TRACK, session, event);
|
|
1810
|
-
};
|
|
1811
|
-
const sessionDescriptionHandler = session.sessionDescriptionHandler;
|
|
1812
|
-
if (sessionDescriptionHandler?.peerConnection) {
|
|
1813
|
-
sessionDescriptionHandler.peerConnection.addEventListener('track', onTrack);
|
|
1814
|
-
}
|
|
1815
|
-
sessionDescriptionHandler.remoteMediaStream.onaddtrack = onTrack;
|
|
1816
|
-
if (pc) {
|
|
1817
|
-
pc.oniceconnectionstatechange = () => {
|
|
1818
|
-
logger.info('on ice connection state changed', {
|
|
1819
|
-
state: pc.iceConnectionState,
|
|
1820
|
-
});
|
|
1821
|
-
if (pc.iceConnectionState === 'disconnected') {
|
|
1822
|
-
this.eventEmitter.emit(ON_DISCONNECTED);
|
|
1823
|
-
}
|
|
1824
|
-
};
|
|
1825
|
-
}
|
|
1826
|
-
if (withEvent) {
|
|
1827
|
-
this.eventEmitter.emit(ACCEPTED, session, sessionDialog);
|
|
1828
|
-
}
|
|
1829
|
-
this._startSendingStats(session);
|
|
1830
|
-
}
|
|
1831
|
-
_isAudioOnly(session) {
|
|
1832
|
-
return Boolean(session.sessionDescriptionHandlerModifiersReInvite.find(modifier => modifier === stripVideo));
|
|
1833
|
-
}
|
|
1834
|
-
async _setupMedias(session, newStream = null) {
|
|
1835
|
-
if (!this._isWeb()) {
|
|
1836
|
-
logger.info('Setup media on mobile, no need to setup html element, bailing');
|
|
1837
|
-
return;
|
|
1838
|
-
}
|
|
1839
|
-
// Safari hack, because you cannot call .play() from a non user action
|
|
1840
|
-
const sessionId = this.getSipSessionId(session);
|
|
1841
|
-
const isConference = this.isConference(sessionId);
|
|
1842
|
-
if (sessionId in this.audioElements) {
|
|
1843
|
-
logger.info('html element already exists for session', {
|
|
1844
|
-
sessionId,
|
|
1845
|
-
});
|
|
1846
|
-
return;
|
|
1847
|
-
}
|
|
1848
|
-
if (this._hasAudio() && this._isWeb() && !(sessionId in this.audioElements)) {
|
|
1849
|
-
await this.createAudioElementFor(sessionId);
|
|
1850
|
-
}
|
|
1851
|
-
const audioElement = this.audioElements[sessionId];
|
|
1852
|
-
const sipSession = this.sipSessions[session.callId];
|
|
1853
|
-
const removeStream = this.getRemoteStream(sessionId);
|
|
1854
|
-
const sdh = sipSession?.sessionDescriptionHandler;
|
|
1855
|
-
const earlyStream = sdh ? sdh.remoteMediaStream : null;
|
|
1856
|
-
const stream = newStream || removeStream || earlyStream;
|
|
1857
|
-
if (!stream) {
|
|
1858
|
-
logger.info('Setup media no stream to attach, bailing');
|
|
1859
|
-
return;
|
|
1860
|
-
}
|
|
1861
|
-
const shouldPause = audioElement.currentTime > 0 && !audioElement.paused && !audioElement.ended && audioElement.readyState > 2;
|
|
1862
|
-
logger.info('setting up media', {
|
|
1863
|
-
sessionId,
|
|
1864
|
-
streams: {
|
|
1865
|
-
new: !!newStream,
|
|
1866
|
-
remove: !!removeStream,
|
|
1867
|
-
early: !!earlyStream,
|
|
1868
|
-
},
|
|
1869
|
-
hasAudio: this._hasAudio(),
|
|
1870
|
-
isConference,
|
|
1871
|
-
shouldPause,
|
|
1872
|
-
});
|
|
1873
|
-
if (isConference) {
|
|
1874
|
-
// Conference local stream is handled in Room
|
|
1875
|
-
return;
|
|
1876
|
-
}
|
|
1877
|
-
if (shouldPause) {
|
|
1878
|
-
audioElement.pause();
|
|
1879
|
-
}
|
|
1880
|
-
audioElement.srcObject = stream;
|
|
1881
|
-
audioElement.volume = this.audioOutputVolume;
|
|
1882
|
-
audioElement.play().catch(() => { });
|
|
1883
|
-
}
|
|
1884
|
-
_cleanupMedia(session) {
|
|
1885
|
-
const sessionId = this.getSipSessionId(session);
|
|
1886
|
-
const localStream = this.getLocalStream(sessionId);
|
|
1887
|
-
if (localStream) {
|
|
1888
|
-
this._cleanupStream(localStream);
|
|
1889
|
-
}
|
|
1890
|
-
const cleanLocalElement = (id) => {
|
|
1891
|
-
const element = this.audioElements[id];
|
|
1892
|
-
if (!element) {
|
|
1893
|
-
return;
|
|
1894
|
-
}
|
|
1895
|
-
element.pause();
|
|
1896
|
-
if (element.parentNode) {
|
|
1897
|
-
element.parentNode.removeChild(element);
|
|
1898
|
-
}
|
|
1899
|
-
element.srcObject = null;
|
|
1900
|
-
delete this.audioElements[id];
|
|
1901
|
-
};
|
|
1902
|
-
if (this._hasAudio() && this._isWeb()) {
|
|
1903
|
-
if (session) {
|
|
1904
|
-
cleanLocalElement(this.getSipSessionId(session));
|
|
1905
|
-
}
|
|
1906
|
-
else {
|
|
1907
|
-
Object.keys(this.audioElements).forEach(id => cleanLocalElement(id));
|
|
1908
|
-
}
|
|
1909
|
-
}
|
|
1910
|
-
}
|
|
1911
|
-
_cleanupStream(stream) {
|
|
1912
|
-
stream.getTracks().filter(track => track.enabled).forEach(track => track.stop());
|
|
1913
|
-
}
|
|
1914
|
-
_toggleAudio(session, muteAudio) {
|
|
1915
|
-
const sdh = session.sessionDescriptionHandler;
|
|
1916
|
-
const pc = (sdh?.peerConnection || null);
|
|
1917
|
-
if (!pc) {
|
|
1918
|
-
return;
|
|
1919
|
-
}
|
|
1920
|
-
if (pc.getSenders) {
|
|
1921
|
-
pc.getSenders().forEach((sender) => {
|
|
1922
|
-
if (sender && sender.track && sender.track.kind === 'audio') {
|
|
1923
|
-
// eslint-disable-next-line
|
|
1924
|
-
sender.track.enabled = !muteAudio;
|
|
1925
|
-
}
|
|
1926
|
-
});
|
|
1927
|
-
}
|
|
1928
|
-
else {
|
|
1929
|
-
pc.getLocalStreams().forEach((stream) => {
|
|
1930
|
-
stream.getAudioTracks().forEach(track => {
|
|
1931
|
-
// eslint-disable-next-line
|
|
1932
|
-
track.enabled = !muteAudio;
|
|
1933
|
-
});
|
|
1934
|
-
});
|
|
1935
|
-
}
|
|
1936
|
-
}
|
|
1937
|
-
_toggleVideo(session, muteCamera) {
|
|
1938
|
-
const sdh = session.sessionDescriptionHandler;
|
|
1939
|
-
const pc = sdh?.peerConnection;
|
|
1940
|
-
if (pc?.getSenders) {
|
|
1941
|
-
pc.getSenders().forEach((sender) => {
|
|
1942
|
-
if (sender && sender.track && sender.track.kind === 'video') {
|
|
1943
|
-
// eslint-disable-next-line
|
|
1944
|
-
sender.track.enabled = !muteCamera;
|
|
1945
|
-
}
|
|
1946
|
-
});
|
|
1947
|
-
}
|
|
1948
|
-
else {
|
|
1949
|
-
pc.getLocalStreams().forEach((stream) => {
|
|
1950
|
-
stream.getVideoTracks().forEach(track => {
|
|
1951
|
-
// eslint-disable-next-line
|
|
1952
|
-
track.enabled = !muteCamera;
|
|
1953
|
-
});
|
|
1954
|
-
});
|
|
1955
|
-
}
|
|
1956
|
-
}
|
|
1957
|
-
/**
|
|
1958
|
-
* @param pc RTCPeerConnection
|
|
1959
|
-
*/
|
|
1960
|
-
_getRemoteStream(pc) {
|
|
1961
|
-
let remoteStream = null;
|
|
1962
|
-
if (pc && pc.getReceivers) {
|
|
1963
|
-
remoteStream = typeof global !== 'undefined' && global.window && global.window.MediaStream ? new global.window.MediaStream() : new window.MediaStream();
|
|
1964
|
-
pc.getReceivers().forEach((receiver) => {
|
|
1965
|
-
const { track, } = receiver;
|
|
1966
|
-
if (track && remoteStream) {
|
|
1967
|
-
remoteStream.addTrack(track);
|
|
1968
|
-
}
|
|
1969
|
-
});
|
|
1970
|
-
}
|
|
1971
|
-
else if (pc) {
|
|
1972
|
-
[remoteStream] = pc.getRemoteStreams();
|
|
1973
|
-
}
|
|
1974
|
-
return remoteStream;
|
|
1975
|
-
}
|
|
1976
|
-
_cleanupRegister() {
|
|
1977
|
-
if (this.registerer) {
|
|
1978
|
-
// @ts-ignore: removeAllListeners does not exist
|
|
1979
|
-
this.registerer.stateChange.removeAllListeners();
|
|
1980
|
-
this.registerer = null;
|
|
1981
|
-
}
|
|
1982
|
-
}
|
|
1983
|
-
_startSendingStats(session) {
|
|
1984
|
-
const sdh = session.sessionDescriptionHandler;
|
|
1985
|
-
const pc = sdh.peerConnection;
|
|
1986
|
-
if (!pc) {
|
|
1987
|
-
return;
|
|
1988
|
-
}
|
|
1989
|
-
const sessionId = this.getSipSessionId(session);
|
|
1990
|
-
getStats(pc, (result) => {
|
|
1991
|
-
const { results, internal, nomore, ...stats } = result;
|
|
1992
|
-
this.statsIntervals[sessionId] = nomore;
|
|
1993
|
-
statsLogger.trace('stats', {
|
|
1994
|
-
sessionId,
|
|
1995
|
-
...stats,
|
|
1996
|
-
});
|
|
1997
|
-
}, SEND_STATS_DELAY);
|
|
1998
|
-
}
|
|
1999
|
-
_stopSendingStats(session) {
|
|
2000
|
-
const sessionId = this.getSipSessionId(session);
|
|
2001
|
-
logger.trace('Check for stopping stats', {
|
|
2002
|
-
sessionId,
|
|
2003
|
-
ids: Object.keys(this.statsIntervals),
|
|
2004
|
-
});
|
|
2005
|
-
if (sessionId in this.statsIntervals) {
|
|
2006
|
-
logger.trace('Stop sending stats for call', {
|
|
2007
|
-
sessionId,
|
|
2008
|
-
});
|
|
2009
|
-
this.statsIntervals[sessionId]();
|
|
2010
|
-
delete this.statsIntervals[sessionId];
|
|
2011
|
-
}
|
|
2012
|
-
}
|
|
2013
|
-
_makeURI(target) {
|
|
2014
|
-
return UserAgent.makeURI(`sip:${target}@${this.config.host}`);
|
|
2015
|
-
}
|
|
2016
|
-
async _disconnectTransport(force = false) {
|
|
2017
|
-
const transport = this.userAgent?.transport;
|
|
2018
|
-
if (force && transport) {
|
|
2019
|
-
// Bypass sip.js state machine that prevent to close WS with the state `Connecting`
|
|
2020
|
-
transport.disconnectResolve = () => { };
|
|
2021
|
-
if (transport._ws) {
|
|
2022
|
-
transport._ws.close(1000);
|
|
2023
|
-
}
|
|
2024
|
-
return;
|
|
2025
|
-
}
|
|
2026
|
-
// Check if `disconnectPromise` is not present to avoid `Disconnect promise must not be defined` errors.
|
|
2027
|
-
if (transport && !transport.disconnectPromise) {
|
|
2028
|
-
try {
|
|
2029
|
-
await transport.disconnect();
|
|
2030
|
-
}
|
|
2031
|
-
catch (e) {
|
|
2032
|
-
logger.error('WebRTC transport disconnect, error', e);
|
|
2033
|
-
}
|
|
2034
|
-
}
|
|
2035
|
-
}
|
|
2036
|
-
async _fetchNetworkStats(sessionId) {
|
|
2037
|
-
const session = this.getSipSession(sessionId);
|
|
2038
|
-
const stats = session ? await this.getStats(session) : null;
|
|
2039
|
-
if (!stats || !(sessionId in this.sessionNetworkStats)) {
|
|
2040
|
-
return Promise.resolve(null);
|
|
2041
|
-
}
|
|
2042
|
-
const networkStats = {
|
|
2043
|
-
audioBytesSent: 0,
|
|
2044
|
-
videoBytesSent: 0,
|
|
2045
|
-
videoBytesReceived: 0,
|
|
2046
|
-
audioBytesReceived: 0,
|
|
2047
|
-
};
|
|
2048
|
-
const nbStats = this.sessionNetworkStats[sessionId].length;
|
|
2049
|
-
const lastNetworkStats = this.sessionNetworkStats[sessionId][nbStats - 1];
|
|
2050
|
-
const lastAudioSent = lastNetworkStats ? lastNetworkStats.audioBytesSent : 0;
|
|
2051
|
-
const lastAudioContentSent = lastNetworkStats ? lastNetworkStats.audioContentSent : 0;
|
|
2052
|
-
const lastVideoSent = lastNetworkStats ? lastNetworkStats.videoBytesSent : 0;
|
|
2053
|
-
const lastAudioReceived = lastNetworkStats ? lastNetworkStats.audioBytesReceived : 0;
|
|
2054
|
-
const lastAudioContentReceived = lastNetworkStats ? lastNetworkStats.audioContentReceived : 0;
|
|
2055
|
-
const lastVideoReceived = lastNetworkStats ? lastNetworkStats.videoBytesReceived : 0;
|
|
2056
|
-
const lastTransportSent = lastNetworkStats ? lastNetworkStats.transportSent : 0;
|
|
2057
|
-
const lastTransportReceived = lastNetworkStats ? lastNetworkStats.transportReceived : 0;
|
|
2058
|
-
let audioBytesSent = 0; // content + header
|
|
2059
|
-
let audioBytesReceived = 0; // content + header
|
|
2060
|
-
let audioContentSent = 0; // useful to detect blank call
|
|
2061
|
-
let audioContentReceived = 0;
|
|
2062
|
-
let videoBytesSent = 0;
|
|
2063
|
-
let videoBytesReceived = 0;
|
|
2064
|
-
let transportSent = 0;
|
|
2065
|
-
let transportReceived = 0;
|
|
2066
|
-
let packetsLost = 0;
|
|
2067
|
-
stats.forEach(report => {
|
|
2068
|
-
if (report.type === 'outbound-rtp' && report.kind === 'audio') {
|
|
2069
|
-
audioBytesSent += Number(report.bytesSent) + Number(report.headerBytesSent);
|
|
2070
|
-
audioContentSent += Number(report.bytesSent);
|
|
2071
|
-
}
|
|
2072
|
-
if (report.type === 'remote-outbound-rtp' && report.kind === 'audio') {
|
|
2073
|
-
audioBytesSent += Number(report.bytesSent);
|
|
2074
|
-
}
|
|
2075
|
-
if (report.type === 'outbound-rtp' && report.kind === 'video') {
|
|
2076
|
-
videoBytesSent += Number(report.bytesSent) + Number(report.headerBytesSent);
|
|
2077
|
-
}
|
|
2078
|
-
if (report.type === 'inbound-rtp' && report.kind === 'audio') {
|
|
2079
|
-
packetsLost += Number(report.packetsLost);
|
|
2080
|
-
networkStats.packetsReceived = Number(report.packetsReceived);
|
|
2081
|
-
audioBytesReceived += Number(report.bytesReceived) + Number(report.headerBytesReceived);
|
|
2082
|
-
audioContentReceived += Number(report.bytesReceived);
|
|
2083
|
-
}
|
|
2084
|
-
if (report.type === 'inbound-rtp' && report.kind === 'video') {
|
|
2085
|
-
videoBytesReceived += Number(report.bytesReceived) + Number(report.headerBytesReceived);
|
|
2086
|
-
}
|
|
2087
|
-
if (report.type === 'outbound-rtp' && report.kind === 'video') {
|
|
2088
|
-
if ('framesPerSecond' in report) {
|
|
2089
|
-
networkStats.framesPerSecond = Number(report.framesPerSecond);
|
|
2090
|
-
}
|
|
2091
|
-
if ('framerateMean' in report) {
|
|
2092
|
-
// framerateMean is only available in FF
|
|
2093
|
-
networkStats.framesPerSecond = Math.round(report.framerateMean);
|
|
2094
|
-
}
|
|
2095
|
-
}
|
|
2096
|
-
if (report.type === 'remote-inbound-rtp' && report.kind === 'audio') {
|
|
2097
|
-
packetsLost += Number(report.packetsLost);
|
|
2098
|
-
networkStats.roundTripTime = Number(report.roundTripTime);
|
|
2099
|
-
networkStats.jitter = Number(report.jitter);
|
|
2100
|
-
}
|
|
2101
|
-
if (report.type === 'remote-inbound-rtp' && report.kind === 'video') {
|
|
2102
|
-
packetsLost += Number(report.packetsLost);
|
|
2103
|
-
}
|
|
2104
|
-
if (report.type === 'transport') {
|
|
2105
|
-
transportSent += Number(report.bytesSent);
|
|
2106
|
-
transportReceived += Number(report.bytesReceived);
|
|
2107
|
-
}
|
|
2108
|
-
});
|
|
2109
|
-
networkStats.packetsLost = packetsLost;
|
|
2110
|
-
networkStats.totalAudioBytesSent = audioBytesSent;
|
|
2111
|
-
networkStats.audioBytesSent = audioBytesSent - lastAudioSent;
|
|
2112
|
-
networkStats.totalAudioBytesReceived = audioBytesReceived - lastAudioReceived;
|
|
2113
|
-
networkStats.audioBytesReceived = audioBytesReceived;
|
|
2114
|
-
networkStats.totalAudioContentSent = audioContentSent;
|
|
2115
|
-
networkStats.audioContentSent = audioContentSent - lastAudioContentSent;
|
|
2116
|
-
networkStats.totalAudioBytesReceived = audioContentReceived - lastAudioContentReceived;
|
|
2117
|
-
networkStats.audioContentReceived = audioContentReceived;
|
|
2118
|
-
networkStats.totalVideoBytesSent = videoBytesSent;
|
|
2119
|
-
networkStats.videoBytesSent = videoBytesSent - lastVideoSent;
|
|
2120
|
-
networkStats.totalVideoBytesReceived = videoBytesReceived;
|
|
2121
|
-
networkStats.videoBytesReceived = videoBytesReceived - lastVideoReceived;
|
|
2122
|
-
networkStats.totalTransportSent = transportSent - lastTransportSent;
|
|
2123
|
-
networkStats.transportSent = transportSent;
|
|
2124
|
-
networkStats.totalTransportReceived = transportReceived;
|
|
2125
|
-
networkStats.transportReceived = transportReceived - lastTransportReceived;
|
|
2126
|
-
networkStats.bandwidth = networkStats.audioBytesSent + networkStats.audioBytesReceived + networkStats.videoBytesSent + networkStats.videoBytesReceived + networkStats.transportReceived + networkStats.transportSent;
|
|
2127
|
-
if (this.sessionNetworkStats[sessionId]) {
|
|
2128
|
-
this.eventEmitter.emit(ON_NETWORK_STATS, session, networkStats, this.sessionNetworkStats[sessionId]);
|
|
2129
|
-
if (sessionId in this.sessionNetworkStats) {
|
|
2130
|
-
this.sessionNetworkStats[sessionId].push(networkStats);
|
|
2131
|
-
}
|
|
2132
|
-
}
|
|
2133
|
-
}
|
|
2134
|
-
async _accept(session, options = {}) {
|
|
2135
|
-
if (session.state === SessionState.Terminated || session.state === SessionState.Terminating) {
|
|
2136
|
-
const error = 'Trying to accept a terminated sipSession.';
|
|
2137
|
-
logger.warn(error, { state: session.state, sessionId: this.getSipSessionId(session) });
|
|
2138
|
-
throw new Error(error);
|
|
2139
|
-
}
|
|
2140
|
-
if (session.state !== SessionState.Initial) {
|
|
2141
|
-
const error = 'Trying to accept a non Initial sipSession.';
|
|
2142
|
-
logger.warn(error, { state: session.state, sessionId: this.getSipSessionId(session) });
|
|
2143
|
-
throw new Error(error);
|
|
2144
|
-
}
|
|
2145
|
-
// @ts-ignore: private
|
|
2146
|
-
if (!session.incomingInviteRequest.acceptable) {
|
|
2147
|
-
const error = 'Trying to reject a non `acceptable` session';
|
|
2148
|
-
logger.warn(error, { state: session.state, sessionId: this.getSipSessionId(session) });
|
|
2149
|
-
throw new Error(error);
|
|
2150
|
-
}
|
|
2151
|
-
try {
|
|
2152
|
-
return await session.accept(options);
|
|
2153
|
-
}
|
|
2154
|
-
catch (e) {
|
|
2155
|
-
logger.warn('Session accept, error', e);
|
|
2156
|
-
}
|
|
2157
|
-
}
|
|
2158
|
-
async _reject(session, options = {}) {
|
|
2159
|
-
if (session.state !== SessionState.Initial && session.state !== SessionState.Establishing) {
|
|
2160
|
-
logger.warn('Trying to reject a session in a wrong state', { state: session.state, sessionId: this.getSipSessionId(session) });
|
|
2161
|
-
return;
|
|
2162
|
-
}
|
|
2163
|
-
// @ts-ignore: private
|
|
2164
|
-
if (!session.incomingInviteRequest.rejectable) {
|
|
2165
|
-
logger.warn('Trying to reject a non `rejectable` session', { state: session.state, sessionId: this.getSipSessionId(session) });
|
|
2166
|
-
return;
|
|
2167
|
-
}
|
|
2168
|
-
try {
|
|
2169
|
-
return await session.reject(options);
|
|
2170
|
-
}
|
|
2171
|
-
catch (e) {
|
|
2172
|
-
logger.warn('Session reject, error', e);
|
|
2173
|
-
}
|
|
2174
|
-
}
|
|
2175
|
-
async _cancel(session, options = {}) {
|
|
2176
|
-
if (session.state !== SessionState.Initial && session.state !== SessionState.Establishing) {
|
|
2177
|
-
logger.warn('Trying to cancel a session in a wrong state', { state: session.state, sessionId: this.getSipSessionId(session) });
|
|
2178
|
-
return;
|
|
2179
|
-
}
|
|
2180
|
-
try {
|
|
2181
|
-
return await session.cancel(options);
|
|
2182
|
-
}
|
|
2183
|
-
catch (e) {
|
|
2184
|
-
logger.warn('Session cancel, error', e);
|
|
2185
|
-
}
|
|
2186
|
-
}
|
|
2187
|
-
async _bye(session, options = {}) {
|
|
2188
|
-
if (session.state !== SessionState.Established) {
|
|
2189
|
-
logger.warn('Trying to end a session in a wrong state', { state: session.state, sessionId: this.getSipSessionId(session) });
|
|
2190
|
-
return null;
|
|
2191
|
-
}
|
|
2192
|
-
try {
|
|
2193
|
-
return await session.bye(options);
|
|
2194
|
-
}
|
|
2195
|
-
catch (e) {
|
|
2196
|
-
logger.warn('Session bye, error', e);
|
|
2197
|
-
}
|
|
2198
|
-
return null;
|
|
2199
|
-
}
|
|
2200
|
-
}
|