ue-softphone-sdk 2.2.2 → 2.2.4
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/dist/api/bye.d.ts +16 -0
- package/dist/api/dtmf.d.ts +15 -0
- package/dist/api/emitter.d.ts +88 -0
- package/dist/api/exceptions/content-type-unsupported.d.ts +8 -0
- package/dist/api/exceptions/index.d.ts +5 -0
- package/dist/api/exceptions/request-pending.d.ts +9 -0
- package/dist/api/exceptions/session-description-handler.d.ts +8 -0
- package/dist/api/exceptions/session-terminated.d.ts +8 -0
- package/dist/api/exceptions/state-transition.d.ts +8 -0
- package/dist/api/index.d.ts +58 -0
- package/dist/api/info.d.ts +16 -0
- package/dist/api/invitation-accept-options.d.ts +19 -0
- package/dist/api/invitation-progress-options.d.ts +38 -0
- package/dist/api/invitation-reject-options.d.ts +25 -0
- package/dist/api/invitation.d.ts +179 -0
- package/dist/api/inviter-cancel-options.d.ts +9 -0
- package/dist/api/inviter-invite-options.d.ts +28 -0
- package/dist/api/inviter-options.d.ts +43 -0
- package/dist/api/inviter.d.ts +236 -0
- package/dist/api/message.d.ts +16 -0
- package/dist/api/messager-message-options.d.ts +11 -0
- package/dist/api/messager-options.d.ts +17 -0
- package/dist/api/messager.d.ts +26 -0
- package/dist/api/notification.d.ts +16 -0
- package/dist/api/notifier.d.ts +8 -0
- package/dist/api/publisher-options.d.ts +33 -0
- package/dist/api/publisher-publish-options.d.ts +6 -0
- package/dist/api/publisher-state.d.ts +21 -0
- package/dist/api/publisher-unpublish-options.d.ts +6 -0
- package/dist/api/publisher.d.ts +65 -0
- package/dist/api/referral.d.ts +38 -0
- package/dist/api/registerer-options.d.ts +46 -0
- package/dist/api/registerer-register-options.d.ts +11 -0
- package/dist/api/registerer-state.d.ts +21 -0
- package/dist/api/registerer-unregister-options.d.ts +16 -0
- package/dist/api/registerer.d.ts +144 -0
- package/dist/api/session-bye-options.d.ts +11 -0
- package/dist/api/session-delegate.d.ts +73 -0
- package/dist/api/session-description-handler-factory.d.ts +15 -0
- package/dist/api/session-description-handler.d.ts +74 -0
- package/dist/api/session-info-options.d.ts +11 -0
- package/dist/api/session-invite-options.d.ts +28 -0
- package/dist/api/session-message-options.d.ts +11 -0
- package/dist/api/session-options.d.ts +8 -0
- package/dist/api/session-refer-options.d.ts +14 -0
- package/dist/api/session-state.d.ts +45 -0
- package/dist/api/session.d.ts +359 -0
- package/dist/api/subscriber-options.d.ts +11 -0
- package/dist/api/subscriber-subscribe-options.d.ts +6 -0
- package/dist/api/subscriber.d.ts +94 -0
- package/dist/api/subscription-delegate.d.ts +12 -0
- package/dist/api/subscription-options.d.ts +8 -0
- package/dist/api/subscription-state.d.ts +19 -0
- package/dist/api/subscription-subscribe-options.d.ts +6 -0
- package/dist/api/subscription-unsubscribe-options.d.ts +6 -0
- package/dist/api/subscription.d.ts +84 -0
- package/dist/api/transport-state.d.ts +37 -0
- package/dist/api/transport.d.ts +159 -0
- package/dist/api/user-agent-delegate.d.ts +84 -0
- package/dist/api/user-agent-options.d.ts +253 -0
- package/dist/api/user-agent-state.d.ts +14 -0
- package/dist/api/user-agent.d.ts +200 -0
- package/dist/core/dialogs/dialog-state.d.ts +34 -0
- package/dist/core/dialogs/dialog.d.ts +161 -0
- package/dist/core/dialogs/index.d.ts +4 -0
- package/dist/core/dialogs/session-dialog.d.ts +196 -0
- package/dist/core/dialogs/subscription-dialog.d.ts +120 -0
- package/dist/core/exceptions/exception.d.ts +8 -0
- package/dist/core/exceptions/index.d.ts +3 -0
- package/dist/core/exceptions/transaction-state-error.d.ts +8 -0
- package/dist/core/exceptions/transport-error.d.ts +8 -0
- package/dist/core/index.d.ts +15 -0
- package/dist/core/log/index.d.ts +3 -0
- package/dist/core/log/levels.d.ts +10 -0
- package/dist/core/log/logger-factory.d.ts +21 -0
- package/dist/core/log/logger.d.ts +19 -0
- package/dist/core/messages/body.d.ts +64 -0
- package/dist/core/messages/digest-authentication.d.ts +51 -0
- package/dist/core/messages/incoming-message.d.ts +79 -0
- package/dist/core/messages/incoming-request-message.d.ts +10 -0
- package/dist/core/messages/incoming-request.d.ts +67 -0
- package/dist/core/messages/incoming-response-message.d.ts +10 -0
- package/dist/core/messages/incoming-response.d.ts +12 -0
- package/dist/core/messages/index.d.ts +13 -0
- package/dist/core/messages/md5.d.ts +32 -0
- package/dist/core/messages/methods/ack.d.ts +18 -0
- package/dist/core/messages/methods/bye.d.ts +21 -0
- package/dist/core/messages/methods/cancel.d.ts +21 -0
- package/dist/core/messages/methods/constants.d.ts +20 -0
- package/dist/core/messages/methods/index.d.ts +13 -0
- package/dist/core/messages/methods/info.d.ts +21 -0
- package/dist/core/messages/methods/invite.d.ts +86 -0
- package/dist/core/messages/methods/message.d.ts +21 -0
- package/dist/core/messages/methods/notify.d.ts +21 -0
- package/dist/core/messages/methods/prack.d.ts +21 -0
- package/dist/core/messages/methods/publish.d.ts +21 -0
- package/dist/core/messages/methods/refer.d.ts +21 -0
- package/dist/core/messages/methods/register.d.ts +21 -0
- package/dist/core/messages/methods/subscribe.d.ts +54 -0
- package/dist/core/messages/outgoing-request-message.d.ts +94 -0
- package/dist/core/messages/outgoing-request.d.ts +67 -0
- package/dist/core/messages/outgoing-response.d.ts +42 -0
- package/dist/core/messages/parser.d.ts +14 -0
- package/dist/core/messages/utils.d.ts +24 -0
- package/dist/core/session/index.d.ts +2 -0
- package/dist/core/session/session-delegate.d.ts +70 -0
- package/dist/core/session/session.d.ts +134 -0
- package/dist/core/subscription/index.d.ts +2 -0
- package/dist/core/subscription/subscription-delegate.d.ts +27 -0
- package/dist/core/subscription/subscription.d.ts +55 -0
- package/dist/core/timers.d.ts +20 -0
- package/dist/core/transactions/client-transaction.d.ts +45 -0
- package/dist/core/transactions/index.d.ts +10 -0
- package/dist/core/transactions/invite-client-transaction.d.ts +116 -0
- package/dist/core/transactions/invite-server-transaction.d.ts +127 -0
- package/dist/core/transactions/non-invite-client-transaction.d.ts +69 -0
- package/dist/core/transactions/non-invite-server-transaction.d.ts +57 -0
- package/dist/core/transactions/server-transaction.d.ts +35 -0
- package/dist/core/transactions/transaction-state.d.ts +13 -0
- package/dist/core/transactions/transaction-user.d.ts +72 -0
- package/dist/core/transactions/transaction.d.ts +79 -0
- package/dist/core/transport.d.ts +31 -0
- package/dist/core/user-agent-core/allowed-methods.d.ts +4 -0
- package/dist/core/user-agent-core/index.d.ts +3 -0
- package/dist/core/user-agent-core/user-agent-core-configuration.d.ts +99 -0
- package/dist/core/user-agent-core/user-agent-core-delegate.d.ts +37 -0
- package/dist/core/user-agent-core/user-agent-core.d.ts +179 -0
- package/dist/core/user-agents/bye-user-agent-client.d.ts +10 -0
- package/dist/core/user-agents/bye-user-agent-server.d.ts +10 -0
- package/dist/core/user-agents/cancel-user-agent-client.d.ts +10 -0
- package/dist/core/user-agents/index.d.ts +26 -0
- package/dist/core/user-agents/info-user-agent-client.d.ts +10 -0
- package/dist/core/user-agents/info-user-agent-server.d.ts +10 -0
- package/dist/core/user-agents/invite-user-agent-client.d.ts +35 -0
- package/dist/core/user-agents/invite-user-agent-server.d.ts +77 -0
- package/dist/core/user-agents/message-user-agent-client.d.ts +10 -0
- package/dist/core/user-agents/message-user-agent-server.d.ts +10 -0
- package/dist/core/user-agents/notify-user-agent-client.d.ts +10 -0
- package/dist/core/user-agents/notify-user-agent-server.d.ts +16 -0
- package/dist/core/user-agents/prack-user-agent-client.d.ts +10 -0
- package/dist/core/user-agents/prack-user-agent-server.d.ts +16 -0
- package/dist/core/user-agents/publish-user-agent-client.d.ts +10 -0
- package/dist/core/user-agents/re-invite-user-agent-client.d.ts +18 -0
- package/dist/core/user-agents/re-invite-user-agent-server.d.ts +41 -0
- package/dist/core/user-agents/re-subscribe-user-agent-client.d.ts +17 -0
- package/dist/core/user-agents/re-subscribe-user-agent-server.d.ts +10 -0
- package/dist/core/user-agents/refer-user-agent-client.d.ts +10 -0
- package/dist/core/user-agents/refer-user-agent-server.d.ts +16 -0
- package/dist/core/user-agents/register-user-agent-client.d.ts +10 -0
- package/dist/core/user-agents/register-user-agent-server.d.ts +11 -0
- package/dist/core/user-agents/subscribe-user-agent-client.d.ts +65 -0
- package/dist/core/user-agents/subscribe-user-agent-server.d.ts +11 -0
- package/dist/core/user-agents/user-agent-client.d.ts +103 -0
- package/dist/core/user-agents/user-agent-server.d.ts +79 -0
- package/dist/grammar/grammar.d.ts +26 -0
- package/dist/grammar/index.d.ts +4 -0
- package/dist/grammar/name-addr-header.d.ts +24 -0
- package/dist/grammar/parameters.d.ts +16 -0
- package/dist/grammar/pegjs/dist/grammar.d.ts +50 -0
- package/dist/grammar/uri.d.ts +62 -0
- package/dist/{types/index.d.ts → index.d.ts} +7 -3
- package/dist/main.d.ts +9 -0
- package/dist/new-index.d.ts +199 -0
- package/dist/platform/web/index.d.ts +4 -0
- package/dist/platform/web/modifiers/index.d.ts +5 -0
- package/dist/platform/web/modifiers/modifiers.d.ts +41 -0
- package/dist/platform/web/session-description-handler/index.d.ts +14 -0
- package/dist/platform/web/session-description-handler/media-stream-factory-default.d.ts +6 -0
- package/dist/platform/web/session-description-handler/media-stream-factory.d.ts +6 -0
- package/dist/platform/web/session-description-handler/peer-connection-configuration-default.d.ts +5 -0
- package/dist/platform/web/session-description-handler/peer-connection-delegate.d.ts +63 -0
- package/dist/platform/web/session-description-handler/session-description-handler-configuration.d.ts +16 -0
- package/dist/platform/web/session-description-handler/session-description-handler-factory-default.d.ts +11 -0
- package/dist/platform/web/session-description-handler/session-description-handler-factory-options.d.ts +9 -0
- package/dist/platform/web/session-description-handler/session-description-handler-factory.d.ts +16 -0
- package/dist/platform/web/session-description-handler/session-description-handler-options.d.ts +47 -0
- package/dist/platform/web/session-description-handler/session-description-handler.d.ts +212 -0
- package/dist/platform/web/simple-user/index.d.ts +7 -0
- package/dist/platform/web/simple-user/simple-user-delegate.d.ts +72 -0
- package/dist/platform/web/simple-user/simple-user-options.d.ts +90 -0
- package/dist/platform/web/simple-user/simple-user.d.ts +226 -0
- package/dist/platform/web/transport/index.d.ts +6 -0
- package/dist/platform/web/transport/transport-options.d.ts +30 -0
- package/dist/platform/web/transport/transport.d.ts +125 -0
- package/dist/ue-softphone-sdk.js +2 -1
- package/dist/ue-softphone-sdk.js.map +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/webPhoneSdk.d.ts +24 -0
- package/dist/webrtc.d.ts +17 -0
- package/{rollup-new.config.mjs → new-rollup.config.mjs} +1 -1
- package/package.json +6 -6
- package/rollup.config.js +15 -14
- package/src/api/api-extractor.json +358 -0
- package/src/api/bye.ts +27 -0
- package/src/api/dtmf.ts +27 -0
- package/src/api/emitter.ts +110 -0
- package/src/api/exceptions/content-type-unsupported.ts +11 -0
- package/src/api/exceptions/index.ts +5 -0
- package/src/api/exceptions/request-pending.ts +12 -0
- package/src/api/exceptions/session-description-handler.ts +11 -0
- package/src/api/exceptions/session-terminated.ts +11 -0
- package/src/api/exceptions/state-transition.ts +11 -0
- package/src/api/index.ts +58 -0
- package/src/api/info.ts +27 -0
- package/src/api/invitation-accept-options.ts +20 -0
- package/src/api/invitation-progress-options.ts +36 -0
- package/src/api/invitation-reject-options.ts +22 -0
- package/src/api/invitation.ts +816 -0
- package/src/api/inviter-cancel-options.ts +9 -0
- package/src/api/inviter-invite-options.ts +29 -0
- package/src/api/inviter-options.ts +44 -0
- package/src/api/inviter.ts +1126 -0
- package/src/api/message.ts +27 -0
- package/src/api/messager-message-options.ts +12 -0
- package/src/api/messager-options.ts +18 -0
- package/src/api/messager.ts +89 -0
- package/src/api/notification.ts +27 -0
- package/src/api/notifier.ts +7 -0
- package/src/api/publisher-options.ts +34 -0
- package/src/api/publisher-publish-options.ts +6 -0
- package/src/api/publisher-state.ts +21 -0
- package/src/api/publisher-unpublish-options.ts +6 -0
- package/src/api/publisher.ts +418 -0
- package/src/api/referral.ts +89 -0
- package/src/api/registerer-options.ts +55 -0
- package/src/api/registerer-register-options.ts +12 -0
- package/src/api/registerer-state.ts +21 -0
- package/src/api/registerer-unregister-options.ts +17 -0
- package/src/api/registerer.ts +814 -0
- package/src/api/session-bye-options.ts +12 -0
- package/src/api/session-delegate.ts +80 -0
- package/src/api/session-description-handler-factory.ts +16 -0
- package/src/api/session-description-handler.ts +89 -0
- package/src/api/session-info-options.ts +12 -0
- package/src/api/session-invite-options.ts +29 -0
- package/src/api/session-message-options.ts +12 -0
- package/src/api/session-options.ts +8 -0
- package/src/api/session-refer-options.ts +15 -0
- package/src/api/session-state.ts +45 -0
- package/src/api/session.ts +1448 -0
- package/src/api/subscriber-options.ts +12 -0
- package/src/api/subscriber-subscribe-options.ts +6 -0
- package/src/api/subscriber.ts +536 -0
- package/src/api/subscription-delegate.ts +13 -0
- package/src/api/subscription-options.ts +8 -0
- package/src/api/subscription-state.ts +19 -0
- package/src/api/subscription-subscribe-options.ts +6 -0
- package/src/api/subscription-unsubscribe-options.ts +6 -0
- package/src/api/subscription.ts +161 -0
- package/src/api/transport-state.ts +37 -0
- package/src/api/transport.ts +169 -0
- package/src/api/user-agent-delegate.ts +95 -0
- package/src/api/user-agent-options.ts +322 -0
- package/src/api/user-agent-state.ts +14 -0
- package/src/api/user-agent.ts +1014 -0
- package/src/core/api-extractor.json +358 -0
- package/src/core/dialogs/dialog-state.ts +35 -0
- package/src/core/dialogs/dialog.ts +605 -0
- package/src/core/dialogs/index.ts +4 -0
- package/src/core/dialogs/session-dialog.ts +996 -0
- package/src/core/dialogs/subscription-dialog.ts +557 -0
- package/src/core/exceptions/exception.ts +11 -0
- package/src/core/exceptions/index.ts +3 -0
- package/src/core/exceptions/transaction-state-error.ts +11 -0
- package/src/core/exceptions/transport-error.ts +11 -0
- package/src/core/index.ts +19 -0
- package/src/core/log/index.ts +3 -0
- package/src/core/log/levels.ts +10 -0
- package/src/core/log/logger-factory.ts +119 -0
- package/src/core/log/logger.ts +42 -0
- package/src/core/messages/body.ts +171 -0
- package/src/core/messages/digest-authentication.ts +190 -0
- package/src/core/messages/incoming-message.ts +152 -0
- package/src/core/messages/incoming-request-message.ts +14 -0
- package/src/core/messages/incoming-request.ts +75 -0
- package/src/core/messages/incoming-response-message.ts +14 -0
- package/src/core/messages/incoming-response.ts +13 -0
- package/src/core/messages/index.ts +18 -0
- package/src/core/messages/md5.ts +437 -0
- package/src/core/messages/methods/ack.ts +22 -0
- package/src/core/messages/methods/bye.ts +22 -0
- package/src/core/messages/methods/cancel.ts +22 -0
- package/src/core/messages/methods/constants.ts +21 -0
- package/src/core/messages/methods/index.ts +13 -0
- package/src/core/messages/methods/info.ts +22 -0
- package/src/core/messages/methods/invite.ts +104 -0
- package/src/core/messages/methods/message.ts +22 -0
- package/src/core/messages/methods/notify.ts +22 -0
- package/src/core/messages/methods/prack.ts +22 -0
- package/src/core/messages/methods/publish.ts +22 -0
- package/src/core/messages/methods/refer.ts +22 -0
- package/src/core/messages/methods/register.ts +22 -0
- package/src/core/messages/methods/subscribe.ts +59 -0
- package/src/core/messages/outgoing-request-message.ts +299 -0
- package/src/core/messages/outgoing-request.ts +77 -0
- package/src/core/messages/outgoing-response.ts +174 -0
- package/src/core/messages/parser.ts +265 -0
- package/src/core/messages/utils.ts +144 -0
- package/src/core/session/index.ts +2 -0
- package/src/core/session/session-delegate.ts +88 -0
- package/src/core/session/session.ts +158 -0
- package/src/core/subscription/index.ts +2 -0
- package/src/core/subscription/subscription-delegate.ts +30 -0
- package/src/core/subscription/subscription.ts +61 -0
- package/src/core/timers.ts +24 -0
- package/src/core/transactions/client-transaction.ts +78 -0
- package/src/core/transactions/index.ts +10 -0
- package/src/core/transactions/invite-client-transaction.ts +504 -0
- package/src/core/transactions/invite-server-transaction.ts +432 -0
- package/src/core/transactions/non-invite-client-transaction.ts +257 -0
- package/src/core/transactions/non-invite-server-transaction.ts +241 -0
- package/src/core/transactions/server-transaction.ts +47 -0
- package/src/core/transactions/transaction-state.ts +13 -0
- package/src/core/transactions/transaction-user.ts +82 -0
- package/src/core/transactions/transaction.ts +149 -0
- package/src/core/transport.ts +32 -0
- package/src/core/user-agent-core/allowed-methods.ts +19 -0
- package/src/core/user-agent-core/index.ts +3 -0
- package/src/core/user-agent-core/user-agent-core-configuration.ts +111 -0
- package/src/core/user-agent-core/user-agent-core-delegate.ts +50 -0
- package/src/core/user-agent-core/user-agent-core.ts +905 -0
- package/src/core/user-agents/bye-user-agent-client.ts +16 -0
- package/src/core/user-agents/bye-user-agent-server.ts +14 -0
- package/src/core/user-agents/cancel-user-agent-client.ts +14 -0
- package/src/core/user-agents/index.ts +26 -0
- package/src/core/user-agents/info-user-agent-client.ts +15 -0
- package/src/core/user-agents/info-user-agent-server.ts +14 -0
- package/src/core/user-agents/invite-user-agent-client.ts +405 -0
- package/src/core/user-agents/invite-user-agent-server.ts +269 -0
- package/src/core/user-agents/message-user-agent-client.ts +14 -0
- package/src/core/user-agents/message-user-agent-server.ts +14 -0
- package/src/core/user-agents/notify-user-agent-client.ts +15 -0
- package/src/core/user-agents/notify-user-agent-server.ts +30 -0
- package/src/core/user-agents/prack-user-agent-client.ts +16 -0
- package/src/core/user-agents/prack-user-agent-server.ts +37 -0
- package/src/core/user-agents/publish-user-agent-client.ts +14 -0
- package/src/core/user-agents/re-invite-user-agent-client.ts +127 -0
- package/src/core/user-agents/re-invite-user-agent-server.ts +109 -0
- package/src/core/user-agents/re-subscribe-user-agent-client.ts +78 -0
- package/src/core/user-agents/re-subscribe-user-agent-server.ts +14 -0
- package/src/core/user-agents/refer-user-agent-client.ts +15 -0
- package/src/core/user-agents/refer-user-agent-server.ts +30 -0
- package/src/core/user-agents/register-user-agent-client.ts +14 -0
- package/src/core/user-agents/register-user-agent-server.ts +14 -0
- package/src/core/user-agents/subscribe-user-agent-client.ts +341 -0
- package/src/core/user-agents/subscribe-user-agent-server.ts +14 -0
- package/src/core/user-agents/user-agent-client.ts +378 -0
- package/src/core/user-agents/user-agent-server.ts +276 -0
- package/src/grammar/grammar.ts +55 -0
- package/src/grammar/index.ts +4 -0
- package/src/grammar/name-addr-header.ts +58 -0
- package/src/grammar/parameters.ts +45 -0
- package/src/grammar/pegjs/README.md +9 -0
- package/src/grammar/pegjs/dist/grammar.ts +1557 -0
- package/src/grammar/pegjs/src/grammar.pegjs +1009 -0
- package/src/grammar/uri.ts +370 -0
- package/src/index.ts +59 -28
- package/src/lib/socket.io.esm.min.js +7 -0
- package/src/main.ts +26 -0
- package/src/new-index.ts +2478 -0
- package/src/platform/react/README.md +1 -0
- package/src/platform/web/index.ts +4 -0
- package/src/platform/web/modifiers/index.ts +5 -0
- package/src/platform/web/modifiers/modifiers.ts +180 -0
- package/src/platform/web/session-description-handler/api-extractor.json +358 -0
- package/src/platform/web/session-description-handler/index.ts +14 -0
- package/src/platform/web/session-description-handler/media-stream-factory-default.ts +22 -0
- package/src/platform/web/session-description-handler/media-stream-factory.ts +10 -0
- package/src/platform/web/session-description-handler/peer-connection-configuration-default.ts +17 -0
- package/src/platform/web/session-description-handler/peer-connection-delegate.ts +72 -0
- package/src/platform/web/session-description-handler/session-description-handler-configuration.ts +17 -0
- package/src/platform/web/session-description-handler/session-description-handler-factory-default.ts +45 -0
- package/src/platform/web/session-description-handler/session-description-handler-factory-options.ts +10 -0
- package/src/platform/web/session-description-handler/session-description-handler-factory.ts +17 -0
- package/src/platform/web/session-description-handler/session-description-handler-options.ts +56 -0
- package/src/platform/web/session-description-handler/session-description-handler.ts +938 -0
- package/src/platform/web/simple-user/api-extractor.json +358 -0
- package/src/platform/web/simple-user/index.ts +7 -0
- package/src/platform/web/simple-user/simple-user-delegate.ts +82 -0
- package/src/platform/web/simple-user/simple-user-options.ts +102 -0
- package/src/platform/web/simple-user/simple-user.ts +1099 -0
- package/src/platform/web/transport/api-extractor.json +358 -0
- package/src/platform/web/transport/index.ts +6 -0
- package/src/platform/web/transport/transport-options.ts +34 -0
- package/src/platform/web/transport/transport.ts +742 -0
- package/src/version.ts +8 -0
- package/src/webPhoneSdk.ts +67 -0
- package/src/webrtc.ts +318 -0
- package/tsconfig.json +26 -10
- /package/dist/{types/config.d.ts → config.d.ts} +0 -0
|
@@ -0,0 +1,1448 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AckableIncomingResponseWithSession,
|
|
3
|
+
Body,
|
|
4
|
+
fromBodyLegacy,
|
|
5
|
+
getBody,
|
|
6
|
+
Grammar,
|
|
7
|
+
IncomingAckRequest,
|
|
8
|
+
IncomingByeRequest,
|
|
9
|
+
IncomingInfoRequest,
|
|
10
|
+
IncomingInviteRequest,
|
|
11
|
+
IncomingMessageRequest,
|
|
12
|
+
IncomingNotifyRequest,
|
|
13
|
+
IncomingPrackRequest,
|
|
14
|
+
IncomingReferRequest,
|
|
15
|
+
Logger,
|
|
16
|
+
NameAddrHeader,
|
|
17
|
+
OutgoingByeRequest,
|
|
18
|
+
OutgoingInfoRequest,
|
|
19
|
+
OutgoingInviteRequest,
|
|
20
|
+
OutgoingInviteRequestDelegate,
|
|
21
|
+
OutgoingMessageRequest,
|
|
22
|
+
OutgoingReferRequest,
|
|
23
|
+
OutgoingRequestDelegate,
|
|
24
|
+
RequestOptions,
|
|
25
|
+
Session as SessionDialog,
|
|
26
|
+
SessionState as SessionDialogState,
|
|
27
|
+
SignalingState,
|
|
28
|
+
URI
|
|
29
|
+
} from "../core";
|
|
30
|
+
import { getReasonPhrase } from "../core/messages/utils";
|
|
31
|
+
import { AllowedMethods } from "../core/user-agent-core/allowed-methods";
|
|
32
|
+
import { Bye } from "./bye";
|
|
33
|
+
import { Emitter, EmitterImpl } from "./emitter";
|
|
34
|
+
import { ContentTypeUnsupportedError, RequestPendingError } from "./exceptions";
|
|
35
|
+
import { Info } from "./info";
|
|
36
|
+
import { Inviter } from "./inviter";
|
|
37
|
+
import { InviterOptions } from "./inviter-options";
|
|
38
|
+
import { Message } from "./message";
|
|
39
|
+
import { Notification } from "./notification";
|
|
40
|
+
import { Referral } from "./referral";
|
|
41
|
+
import { SessionByeOptions } from "./session-bye-options";
|
|
42
|
+
import { SessionDelegate } from "./session-delegate";
|
|
43
|
+
import {
|
|
44
|
+
SessionDescriptionHandler,
|
|
45
|
+
SessionDescriptionHandlerModifier,
|
|
46
|
+
SessionDescriptionHandlerOptions
|
|
47
|
+
} from "./session-description-handler";
|
|
48
|
+
import { SessionDescriptionHandlerFactory } from "./session-description-handler-factory";
|
|
49
|
+
import { SessionInfoOptions } from "./session-info-options";
|
|
50
|
+
import { SessionInviteOptions } from "./session-invite-options";
|
|
51
|
+
import { SessionMessageOptions } from "./session-message-options";
|
|
52
|
+
import { SessionOptions } from "./session-options";
|
|
53
|
+
import { SessionReferOptions } from "./session-refer-options";
|
|
54
|
+
import { SessionState } from "./session-state";
|
|
55
|
+
import { UserAgent } from "./user-agent";
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* A session provides real time communication between one or more participants.
|
|
59
|
+
*
|
|
60
|
+
* @remarks
|
|
61
|
+
* The transport behaves in a deterministic manner according to the
|
|
62
|
+
* the state defined in {@link SessionState}.
|
|
63
|
+
* @public
|
|
64
|
+
*/
|
|
65
|
+
export abstract class Session {
|
|
66
|
+
/**
|
|
67
|
+
* Property reserved for use by instance owner.
|
|
68
|
+
* @defaultValue `undefined`
|
|
69
|
+
*/
|
|
70
|
+
public data: unknown;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The session delegate.
|
|
74
|
+
* @defaultValue `undefined`
|
|
75
|
+
*/
|
|
76
|
+
public delegate: SessionDelegate | undefined;
|
|
77
|
+
|
|
78
|
+
//
|
|
79
|
+
// Public properties for internal use only
|
|
80
|
+
//
|
|
81
|
+
/** @internal */
|
|
82
|
+
public _contact: string | undefined;
|
|
83
|
+
/** @internal */
|
|
84
|
+
public _referral: Inviter | undefined;
|
|
85
|
+
/** @internal */
|
|
86
|
+
public _replacee: Session | undefined;
|
|
87
|
+
|
|
88
|
+
//
|
|
89
|
+
// Protected properties for internal use only
|
|
90
|
+
//
|
|
91
|
+
/** @internal */
|
|
92
|
+
protected _assertedIdentity: NameAddrHeader | undefined;
|
|
93
|
+
/** @internal */
|
|
94
|
+
protected _dialog: SessionDialog | undefined;
|
|
95
|
+
/** @internal */
|
|
96
|
+
protected _referralInviterOptions: InviterOptions | undefined; // FIXME: This is not getting set by Invitation
|
|
97
|
+
/** @internal */
|
|
98
|
+
protected _renderbody: string | undefined;
|
|
99
|
+
/** @internal */
|
|
100
|
+
protected _rendertype: string | undefined;
|
|
101
|
+
|
|
102
|
+
/** If defined, NOTIFYs associated with a REFER subscription are delivered here. */
|
|
103
|
+
private onNotify: ((notification: Notification) => void) | undefined;
|
|
104
|
+
/** True if there is an outgoing re-INVITE request outstanding. */
|
|
105
|
+
private pendingReinvite = false;
|
|
106
|
+
/** True if there is an incoming re-INVITE ACK request outstanding. */
|
|
107
|
+
private pendingReinviteAck = false;
|
|
108
|
+
/** Dialogs session description handler. */
|
|
109
|
+
private _sessionDescriptionHandler: SessionDescriptionHandler | undefined;
|
|
110
|
+
/** SDH modifiers for the initial INVITE transaction. */
|
|
111
|
+
private _sessionDescriptionHandlerModifiers: Array<SessionDescriptionHandlerModifier> | undefined;
|
|
112
|
+
/** SDH options for the initial INVITE transaction. */
|
|
113
|
+
private _sessionDescriptionHandlerOptions: SessionDescriptionHandlerOptions | undefined;
|
|
114
|
+
/** SDH modifiers for re-INVITE transactions. */
|
|
115
|
+
private _sessionDescriptionHandlerModifiersReInvite: Array<SessionDescriptionHandlerModifier> | undefined;
|
|
116
|
+
/** SDH options for re-NVITE transactions.*/
|
|
117
|
+
private _sessionDescriptionHandlerOptionsReInvite: SessionDescriptionHandlerOptions | undefined;
|
|
118
|
+
/** Session state. */
|
|
119
|
+
private _state: SessionState = SessionState.Initial;
|
|
120
|
+
/** Session state emitter. */
|
|
121
|
+
private _stateEventEmitter: EmitterImpl<SessionState>;
|
|
122
|
+
/** User agent. */
|
|
123
|
+
private _userAgent: UserAgent;
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* The identity of the local user.
|
|
127
|
+
*/
|
|
128
|
+
public abstract readonly localIdentity: NameAddrHeader;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* The identity of the remote user.
|
|
132
|
+
*/
|
|
133
|
+
public abstract readonly remoteIdentity: NameAddrHeader;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Logger.
|
|
137
|
+
*/
|
|
138
|
+
protected abstract logger: Logger;
|
|
139
|
+
|
|
140
|
+
/** @internal */
|
|
141
|
+
protected abstract _id: string;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Constructor.
|
|
145
|
+
* @param userAgent - User agent. See {@link UserAgent} for details.
|
|
146
|
+
* @internal
|
|
147
|
+
*/
|
|
148
|
+
protected constructor(userAgent: UserAgent, options: SessionOptions = {}) {
|
|
149
|
+
this.delegate = options.delegate;
|
|
150
|
+
this._stateEventEmitter = new EmitterImpl<SessionState>();
|
|
151
|
+
this._userAgent = userAgent;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Destructor.
|
|
156
|
+
*/
|
|
157
|
+
public dispose(): Promise<void> {
|
|
158
|
+
this.logger.log(`Session ${this.id} in state ${this._state} is being disposed`);
|
|
159
|
+
|
|
160
|
+
// Remove from the user agent's session collection
|
|
161
|
+
delete this.userAgent._sessions[this.id];
|
|
162
|
+
|
|
163
|
+
// Dispose of dialog media
|
|
164
|
+
if (this._sessionDescriptionHandler) {
|
|
165
|
+
this._sessionDescriptionHandler.close();
|
|
166
|
+
|
|
167
|
+
// TODO: The SDH needs to remain defined as it will be called after it is closed in cases
|
|
168
|
+
// where an answer/offer arrives while the session is being torn down. There are a variety
|
|
169
|
+
// of circumstances where this can happen - sending a BYE during a re-INVITE for example.
|
|
170
|
+
// The code is currently written such that it lazily makes a new SDH when it needs one
|
|
171
|
+
// and one is not yet defined. Thus if we undefined it here, it will currently make a
|
|
172
|
+
// new one which is out of sync and then never gets cleaned up.
|
|
173
|
+
//
|
|
174
|
+
// The downside of leaving it defined are that calls this closed SDH will continue to be
|
|
175
|
+
// made (think setDescription) and those should/will fail. These failures are handled, but
|
|
176
|
+
// it would be nice to have it all coded up in a way where having an undefined SDH where
|
|
177
|
+
// one is expected throws an error.
|
|
178
|
+
//
|
|
179
|
+
// this._sessionDescriptionHandler = undefined;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
switch (this.state) {
|
|
183
|
+
case SessionState.Initial:
|
|
184
|
+
break; // the Inviter/Invitation sub class dispose method handles this case
|
|
185
|
+
case SessionState.Establishing:
|
|
186
|
+
break; // the Inviter/Invitation sub class dispose method handles this case
|
|
187
|
+
case SessionState.Established:
|
|
188
|
+
return new Promise((resolve) => {
|
|
189
|
+
this._bye({
|
|
190
|
+
// wait for the response to the BYE before resolving
|
|
191
|
+
onAccept: () => resolve(),
|
|
192
|
+
onRedirect: () => resolve(),
|
|
193
|
+
onReject: () => resolve()
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
case SessionState.Terminating:
|
|
197
|
+
break; // nothing to be done
|
|
198
|
+
case SessionState.Terminated:
|
|
199
|
+
break; // nothing to be done
|
|
200
|
+
default:
|
|
201
|
+
throw new Error("Unknown state.");
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return Promise.resolve();
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* The asserted identity of the remote user.
|
|
209
|
+
*/
|
|
210
|
+
public get assertedIdentity(): NameAddrHeader | undefined {
|
|
211
|
+
return this._assertedIdentity;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* The confirmed session dialog.
|
|
216
|
+
*/
|
|
217
|
+
public get dialog(): SessionDialog | undefined {
|
|
218
|
+
return this._dialog;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* A unique identifier for this session.
|
|
223
|
+
*/
|
|
224
|
+
public get id(): string {
|
|
225
|
+
return this._id;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* The session being replace by this one.
|
|
230
|
+
*/
|
|
231
|
+
public get replacee(): Session | undefined {
|
|
232
|
+
return this._replacee;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Session description handler.
|
|
237
|
+
* @remarks
|
|
238
|
+
* If `this` is an instance of `Invitation`,
|
|
239
|
+
* `sessionDescriptionHandler` will be defined when the session state changes to "established".
|
|
240
|
+
* If `this` is an instance of `Inviter` and an offer was sent in the INVITE,
|
|
241
|
+
* `sessionDescriptionHandler` will be defined when the session state changes to "establishing".
|
|
242
|
+
* If `this` is an instance of `Inviter` and an offer was not sent in the INVITE,
|
|
243
|
+
* `sessionDescriptionHandler` will be defined when the session state changes to "established".
|
|
244
|
+
* Otherwise `undefined`.
|
|
245
|
+
*/
|
|
246
|
+
public get sessionDescriptionHandler(): SessionDescriptionHandler | undefined {
|
|
247
|
+
return this._sessionDescriptionHandler;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Session description handler factory.
|
|
252
|
+
*/
|
|
253
|
+
public get sessionDescriptionHandlerFactory(): SessionDescriptionHandlerFactory {
|
|
254
|
+
return this.userAgent.configuration.sessionDescriptionHandlerFactory;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* SDH modifiers for the initial INVITE transaction.
|
|
259
|
+
* @remarks
|
|
260
|
+
* Used in all cases when handling the initial INVITE transaction as either UAC or UAS.
|
|
261
|
+
* May be set directly at anytime.
|
|
262
|
+
* May optionally be set via constructor option.
|
|
263
|
+
* May optionally be set via options passed to Inviter.invite() or Invitation.accept().
|
|
264
|
+
*/
|
|
265
|
+
public get sessionDescriptionHandlerModifiers(): Array<SessionDescriptionHandlerModifier> {
|
|
266
|
+
return this._sessionDescriptionHandlerModifiers || [];
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
public set sessionDescriptionHandlerModifiers(modifiers: Array<SessionDescriptionHandlerModifier>) {
|
|
270
|
+
this._sessionDescriptionHandlerModifiers = modifiers.slice();
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* SDH options for the initial INVITE transaction.
|
|
275
|
+
* @remarks
|
|
276
|
+
* Used in all cases when handling the initial INVITE transaction as either UAC or UAS.
|
|
277
|
+
* May be set directly at anytime.
|
|
278
|
+
* May optionally be set via constructor option.
|
|
279
|
+
* May optionally be set via options passed to Inviter.invite() or Invitation.accept().
|
|
280
|
+
*/
|
|
281
|
+
public get sessionDescriptionHandlerOptions(): SessionDescriptionHandlerOptions {
|
|
282
|
+
return this._sessionDescriptionHandlerOptions || {};
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
public set sessionDescriptionHandlerOptions(options: SessionDescriptionHandlerOptions) {
|
|
286
|
+
this._sessionDescriptionHandlerOptions = { ...options };
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* SDH modifiers for re-INVITE transactions.
|
|
291
|
+
* @remarks
|
|
292
|
+
* Used in all cases when handling a re-INVITE transaction as either UAC or UAS.
|
|
293
|
+
* May be set directly at anytime.
|
|
294
|
+
* May optionally be set via constructor option.
|
|
295
|
+
* May optionally be set via options passed to Session.invite().
|
|
296
|
+
*/
|
|
297
|
+
public get sessionDescriptionHandlerModifiersReInvite(): Array<SessionDescriptionHandlerModifier> {
|
|
298
|
+
return this._sessionDescriptionHandlerModifiersReInvite || [];
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
public set sessionDescriptionHandlerModifiersReInvite(modifiers: Array<SessionDescriptionHandlerModifier>) {
|
|
302
|
+
this._sessionDescriptionHandlerModifiersReInvite = modifiers.slice();
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* SDH options for re-INVITE transactions.
|
|
307
|
+
* @remarks
|
|
308
|
+
* Used in all cases when handling a re-INVITE transaction as either UAC or UAS.
|
|
309
|
+
* May be set directly at anytime.
|
|
310
|
+
* May optionally be set via constructor option.
|
|
311
|
+
* May optionally be set via options passed to Session.invite().
|
|
312
|
+
*/
|
|
313
|
+
public get sessionDescriptionHandlerOptionsReInvite(): SessionDescriptionHandlerOptions {
|
|
314
|
+
return this._sessionDescriptionHandlerOptionsReInvite || {};
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
public set sessionDescriptionHandlerOptionsReInvite(options: SessionDescriptionHandlerOptions) {
|
|
318
|
+
this._sessionDescriptionHandlerOptionsReInvite = { ...options };
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Session state.
|
|
323
|
+
*/
|
|
324
|
+
public get state(): SessionState {
|
|
325
|
+
return this._state;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Session state change emitter.
|
|
330
|
+
*/
|
|
331
|
+
public get stateChange(): Emitter<SessionState> {
|
|
332
|
+
return this._stateEventEmitter;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* The user agent.
|
|
337
|
+
*/
|
|
338
|
+
public get userAgent(): UserAgent {
|
|
339
|
+
return this._userAgent;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* End the {@link Session}. Sends a BYE.
|
|
344
|
+
* @param options - Options bucket. See {@link SessionByeOptions} for details.
|
|
345
|
+
*/
|
|
346
|
+
public bye(options: SessionByeOptions = {}): Promise<OutgoingByeRequest> {
|
|
347
|
+
let message = "Session.bye() may only be called if established session.";
|
|
348
|
+
|
|
349
|
+
switch (this.state) {
|
|
350
|
+
case SessionState.Initial:
|
|
351
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
352
|
+
if (typeof (this as any).cancel === "function") {
|
|
353
|
+
message += " However Inviter.invite() has not yet been called.";
|
|
354
|
+
message += " Perhaps you should have called Inviter.cancel()?";
|
|
355
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
356
|
+
} else if (typeof (this as any).reject === "function") {
|
|
357
|
+
message += " However Invitation.accept() has not yet been called.";
|
|
358
|
+
message += " Perhaps you should have called Invitation.reject()?";
|
|
359
|
+
}
|
|
360
|
+
break;
|
|
361
|
+
case SessionState.Establishing:
|
|
362
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
363
|
+
if (typeof (this as any).cancel === "function") {
|
|
364
|
+
message += " However a dialog does not yet exist.";
|
|
365
|
+
message += " Perhaps you should have called Inviter.cancel()?";
|
|
366
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
367
|
+
} else if (typeof (this as any).reject === "function") {
|
|
368
|
+
message += " However Invitation.accept() has not yet been called (or not yet resolved).";
|
|
369
|
+
message += " Perhaps you should have called Invitation.reject()?";
|
|
370
|
+
}
|
|
371
|
+
break;
|
|
372
|
+
case SessionState.Established: {
|
|
373
|
+
const requestDelegate = options.requestDelegate;
|
|
374
|
+
const requestOptions = this.copyRequestOptions(options.requestOptions);
|
|
375
|
+
return this._bye(requestDelegate, requestOptions);
|
|
376
|
+
}
|
|
377
|
+
case SessionState.Terminating:
|
|
378
|
+
message += " However this session is already terminating.";
|
|
379
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
380
|
+
if (typeof (this as any).cancel === "function") {
|
|
381
|
+
message += " Perhaps you have already called Inviter.cancel()?";
|
|
382
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
383
|
+
} else if (typeof (this as any).reject === "function") {
|
|
384
|
+
message += " Perhaps you have already called Session.bye()?";
|
|
385
|
+
}
|
|
386
|
+
break;
|
|
387
|
+
case SessionState.Terminated:
|
|
388
|
+
message += " However this session is already terminated.";
|
|
389
|
+
break;
|
|
390
|
+
default:
|
|
391
|
+
throw new Error("Unknown state");
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
this.logger.error(message);
|
|
395
|
+
return Promise.reject(new Error(`Invalid session state ${this.state}`));
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Share {@link Info} with peer. Sends an INFO.
|
|
400
|
+
* @param options - Options bucket. See {@link SessionInfoOptions} for details.
|
|
401
|
+
*/
|
|
402
|
+
public info(options: SessionInfoOptions = {}): Promise<OutgoingInfoRequest> {
|
|
403
|
+
// guard session state
|
|
404
|
+
if (this.state !== SessionState.Established) {
|
|
405
|
+
const message = "Session.info() may only be called if established session.";
|
|
406
|
+
this.logger.error(message);
|
|
407
|
+
return Promise.reject(new Error(`Invalid session state ${this.state}`));
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const requestDelegate = options.requestDelegate;
|
|
411
|
+
const requestOptions = this.copyRequestOptions(options.requestOptions);
|
|
412
|
+
return this._info(requestDelegate, requestOptions);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Renegotiate the session. Sends a re-INVITE.
|
|
417
|
+
* @param options - Options bucket. See {@link SessionInviteOptions} for details.
|
|
418
|
+
*/
|
|
419
|
+
public invite(options: SessionInviteOptions = {}): Promise<OutgoingInviteRequest> {
|
|
420
|
+
this.logger.log("Session.invite");
|
|
421
|
+
if (this.state !== SessionState.Established) {
|
|
422
|
+
return Promise.reject(new Error(`Invalid session state ${this.state}`));
|
|
423
|
+
}
|
|
424
|
+
if (this.pendingReinvite) {
|
|
425
|
+
return Promise.reject(
|
|
426
|
+
new RequestPendingError("Reinvite in progress. Please wait until complete, then try again.")
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
this.pendingReinvite = true;
|
|
430
|
+
|
|
431
|
+
// Modifiers and options for initial INVITE transaction
|
|
432
|
+
if (options.sessionDescriptionHandlerModifiers) {
|
|
433
|
+
this.sessionDescriptionHandlerModifiersReInvite = options.sessionDescriptionHandlerModifiers;
|
|
434
|
+
}
|
|
435
|
+
if (options.sessionDescriptionHandlerOptions) {
|
|
436
|
+
this.sessionDescriptionHandlerOptionsReInvite = options.sessionDescriptionHandlerOptions;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
const delegate: OutgoingInviteRequestDelegate = {
|
|
440
|
+
onAccept: (response): void => {
|
|
441
|
+
// A re-INVITE transaction has an offer/answer [RFC3264] exchange
|
|
442
|
+
// associated with it. The UAC (User Agent Client) generating a given
|
|
443
|
+
// re-INVITE can act as the offerer or as the answerer. A UAC willing
|
|
444
|
+
// to act as the offerer includes an offer in the re-INVITE. The UAS
|
|
445
|
+
// (User Agent Server) then provides an answer in a response to the
|
|
446
|
+
// re-INVITE. A UAC willing to act as answerer does not include an
|
|
447
|
+
// offer in the re-INVITE. The UAS then provides an offer in a response
|
|
448
|
+
// to the re-INVITE becoming, thus, the offerer.
|
|
449
|
+
// https://tools.ietf.org/html/rfc6141#section-1
|
|
450
|
+
const body = getBody(response.message);
|
|
451
|
+
if (!body) {
|
|
452
|
+
// No way to recover, so terminate session and mark as failed.
|
|
453
|
+
this.logger.error("Received 2xx response to re-INVITE without a session description");
|
|
454
|
+
this.ackAndBye(response, 400, "Missing session description");
|
|
455
|
+
this.stateTransition(SessionState.Terminated);
|
|
456
|
+
this.pendingReinvite = false;
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
if (options.withoutSdp) {
|
|
461
|
+
// INVITE without SDP - set remote offer and send an answer in the ACK
|
|
462
|
+
const answerOptions = {
|
|
463
|
+
sessionDescriptionHandlerOptions: this.sessionDescriptionHandlerOptionsReInvite,
|
|
464
|
+
sessionDescriptionHandlerModifiers: this.sessionDescriptionHandlerModifiersReInvite
|
|
465
|
+
};
|
|
466
|
+
this.setOfferAndGetAnswer(body, answerOptions)
|
|
467
|
+
.then((answerBody) => {
|
|
468
|
+
response.ack({ body: answerBody });
|
|
469
|
+
})
|
|
470
|
+
.catch((error: Error) => {
|
|
471
|
+
// No way to recover, so terminate session and mark as failed.
|
|
472
|
+
this.logger.error("Failed to handle offer in 2xx response to re-INVITE");
|
|
473
|
+
this.logger.error(error.message);
|
|
474
|
+
if (this.state === SessionState.Terminated) {
|
|
475
|
+
// A BYE should not be sent if already terminated.
|
|
476
|
+
// For example, a BYE may be sent/received while re-INVITE is outstanding.
|
|
477
|
+
response.ack();
|
|
478
|
+
} else {
|
|
479
|
+
this.ackAndBye(response, 488, "Bad Media Description");
|
|
480
|
+
this.stateTransition(SessionState.Terminated);
|
|
481
|
+
}
|
|
482
|
+
})
|
|
483
|
+
.then(() => {
|
|
484
|
+
this.pendingReinvite = false;
|
|
485
|
+
if (options.requestDelegate && options.requestDelegate.onAccept) {
|
|
486
|
+
options.requestDelegate.onAccept(response);
|
|
487
|
+
}
|
|
488
|
+
});
|
|
489
|
+
} else {
|
|
490
|
+
// INVITE with SDP - set remote answer and send an ACK
|
|
491
|
+
const answerOptions = {
|
|
492
|
+
sessionDescriptionHandlerOptions: this.sessionDescriptionHandlerOptionsReInvite,
|
|
493
|
+
sessionDescriptionHandlerModifiers: this.sessionDescriptionHandlerModifiersReInvite
|
|
494
|
+
};
|
|
495
|
+
this.setAnswer(body, answerOptions)
|
|
496
|
+
.then(() => {
|
|
497
|
+
response.ack();
|
|
498
|
+
})
|
|
499
|
+
.catch((error: Error) => {
|
|
500
|
+
// No way to recover, so terminate session and mark as failed.
|
|
501
|
+
this.logger.error("Failed to handle answer in 2xx response to re-INVITE");
|
|
502
|
+
this.logger.error(error.message);
|
|
503
|
+
// A BYE should only be sent if session is not already terminated.
|
|
504
|
+
// For example, a BYE may be sent/received while re-INVITE is outstanding.
|
|
505
|
+
// The ACK needs to be sent regardless as it was not handled by the transaction.
|
|
506
|
+
if (this.state !== SessionState.Terminated) {
|
|
507
|
+
this.ackAndBye(response, 488, "Bad Media Description");
|
|
508
|
+
this.stateTransition(SessionState.Terminated);
|
|
509
|
+
} else {
|
|
510
|
+
response.ack();
|
|
511
|
+
}
|
|
512
|
+
})
|
|
513
|
+
.then(() => {
|
|
514
|
+
this.pendingReinvite = false;
|
|
515
|
+
if (options.requestDelegate && options.requestDelegate.onAccept) {
|
|
516
|
+
options.requestDelegate.onAccept(response);
|
|
517
|
+
}
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
},
|
|
521
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
522
|
+
onProgress: (response): void => {
|
|
523
|
+
return;
|
|
524
|
+
},
|
|
525
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
526
|
+
onRedirect: (response): void => {
|
|
527
|
+
return;
|
|
528
|
+
},
|
|
529
|
+
onReject: (response): void => {
|
|
530
|
+
this.logger.warn("Received a non-2xx response to re-INVITE");
|
|
531
|
+
this.pendingReinvite = false;
|
|
532
|
+
if (options.withoutSdp) {
|
|
533
|
+
if (options.requestDelegate && options.requestDelegate.onReject) {
|
|
534
|
+
options.requestDelegate.onReject(response);
|
|
535
|
+
}
|
|
536
|
+
} else {
|
|
537
|
+
this.rollbackOffer()
|
|
538
|
+
.catch((error: Error) => {
|
|
539
|
+
// No way to recover, so terminate session and mark as failed.
|
|
540
|
+
this.logger.error("Failed to rollback offer on non-2xx response to re-INVITE");
|
|
541
|
+
this.logger.error(error.message);
|
|
542
|
+
// A BYE should only be sent if session is not already terminated.
|
|
543
|
+
// For example, a BYE may be sent/received while re-INVITE is outstanding.
|
|
544
|
+
// Note that the ACK was already sent by the transaction, so just need to send BYE.
|
|
545
|
+
if (this.state !== SessionState.Terminated) {
|
|
546
|
+
if (!this.dialog) {
|
|
547
|
+
throw new Error("Dialog undefined.");
|
|
548
|
+
}
|
|
549
|
+
const extraHeaders: Array<string> = [];
|
|
550
|
+
extraHeaders.push("Reason: " + this.getReasonHeaderValue(500, "Internal Server Error"));
|
|
551
|
+
this.dialog.bye(undefined, { extraHeaders });
|
|
552
|
+
this.stateTransition(SessionState.Terminated);
|
|
553
|
+
}
|
|
554
|
+
})
|
|
555
|
+
.then(() => {
|
|
556
|
+
if (options.requestDelegate && options.requestDelegate.onReject) {
|
|
557
|
+
options.requestDelegate.onReject(response);
|
|
558
|
+
}
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
},
|
|
562
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
563
|
+
onTrying: (response): void => {
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
const requestOptions = options.requestOptions || {};
|
|
569
|
+
requestOptions.extraHeaders = (requestOptions.extraHeaders || []).slice();
|
|
570
|
+
requestOptions.extraHeaders.push("Allow: " + AllowedMethods.toString());
|
|
571
|
+
requestOptions.extraHeaders.push("Contact: " + this._contact);
|
|
572
|
+
|
|
573
|
+
// Just send an INVITE with no sdp...
|
|
574
|
+
if (options.withoutSdp) {
|
|
575
|
+
if (!this.dialog) {
|
|
576
|
+
this.pendingReinvite = false;
|
|
577
|
+
throw new Error("Dialog undefined.");
|
|
578
|
+
}
|
|
579
|
+
return Promise.resolve(this.dialog.invite(delegate, requestOptions));
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// Get an offer and send it in an INVITE
|
|
583
|
+
const offerOptions = {
|
|
584
|
+
sessionDescriptionHandlerOptions: this.sessionDescriptionHandlerOptionsReInvite,
|
|
585
|
+
sessionDescriptionHandlerModifiers: this.sessionDescriptionHandlerModifiersReInvite
|
|
586
|
+
};
|
|
587
|
+
return this.getOffer(offerOptions)
|
|
588
|
+
.then((offerBody) => {
|
|
589
|
+
if (!this.dialog) {
|
|
590
|
+
this.pendingReinvite = false;
|
|
591
|
+
throw new Error("Dialog undefined.");
|
|
592
|
+
}
|
|
593
|
+
requestOptions.body = offerBody;
|
|
594
|
+
return this.dialog.invite(delegate, requestOptions);
|
|
595
|
+
})
|
|
596
|
+
.catch((error: Error) => {
|
|
597
|
+
this.logger.error(error.message);
|
|
598
|
+
this.logger.error("Failed to send re-INVITE");
|
|
599
|
+
this.pendingReinvite = false;
|
|
600
|
+
throw error;
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Deliver a {@link Message}. Sends a MESSAGE.
|
|
606
|
+
* @param options - Options bucket. See {@link SessionMessageOptions} for details.
|
|
607
|
+
*/
|
|
608
|
+
public message(options: SessionMessageOptions = {}): Promise<OutgoingMessageRequest> {
|
|
609
|
+
// guard session state
|
|
610
|
+
if (this.state !== SessionState.Established) {
|
|
611
|
+
const message = "Session.message() may only be called if established session.";
|
|
612
|
+
this.logger.error(message);
|
|
613
|
+
return Promise.reject(new Error(`Invalid session state ${this.state}`));
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
const requestDelegate = options.requestDelegate;
|
|
617
|
+
const requestOptions = this.copyRequestOptions(options.requestOptions);
|
|
618
|
+
return this._message(requestDelegate, requestOptions);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* Proffer a {@link Referral}. Send a REFER.
|
|
623
|
+
* @param referTo - The referral target. If a `Session`, a REFER w/Replaces is sent.
|
|
624
|
+
* @param options - Options bucket. See {@link SessionReferOptions} for details.
|
|
625
|
+
*/
|
|
626
|
+
public refer(referTo: URI | Session, options: SessionReferOptions = {}): Promise<OutgoingReferRequest> {
|
|
627
|
+
// guard session state
|
|
628
|
+
if (this.state !== SessionState.Established) {
|
|
629
|
+
const message = "Session.refer() may only be called if established session.";
|
|
630
|
+
this.logger.error(message);
|
|
631
|
+
return Promise.reject(new Error(`Invalid session state ${this.state}`));
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
const requestDelegate = options.requestDelegate;
|
|
635
|
+
const requestOptions = this.copyRequestOptions(options.requestOptions);
|
|
636
|
+
requestOptions.extraHeaders = requestOptions.extraHeaders
|
|
637
|
+
? requestOptions.extraHeaders.concat(this.referExtraHeaders(this.referToString(referTo)))
|
|
638
|
+
: this.referExtraHeaders(this.referToString(referTo));
|
|
639
|
+
return this._refer(options.onNotify, requestDelegate, requestOptions);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* Send BYE.
|
|
644
|
+
* @param delegate - Request delegate.
|
|
645
|
+
* @param options - Request options bucket.
|
|
646
|
+
* @internal
|
|
647
|
+
*/
|
|
648
|
+
public _bye(delegate?: OutgoingRequestDelegate, options?: RequestOptions): Promise<OutgoingByeRequest> {
|
|
649
|
+
// Using core session dialog
|
|
650
|
+
if (!this.dialog) {
|
|
651
|
+
return Promise.reject(new Error("Session dialog undefined."));
|
|
652
|
+
}
|
|
653
|
+
const dialog = this.dialog;
|
|
654
|
+
|
|
655
|
+
// The caller's UA MAY send a BYE for either confirmed or early dialogs,
|
|
656
|
+
// and the callee's UA MAY send a BYE on confirmed dialogs, but MUST NOT
|
|
657
|
+
// send a BYE on early dialogs. However, the callee's UA MUST NOT send a
|
|
658
|
+
// BYE on a confirmed dialog until it has received an ACK for its 2xx
|
|
659
|
+
// response or until the server transaction times out.
|
|
660
|
+
// https://tools.ietf.org/html/rfc3261#section-15
|
|
661
|
+
switch (dialog.sessionState) {
|
|
662
|
+
case SessionDialogState.Initial:
|
|
663
|
+
throw new Error(`Invalid dialog state ${dialog.sessionState}`);
|
|
664
|
+
case SessionDialogState.Early: // Implementation choice - not sending BYE for early dialogs.
|
|
665
|
+
throw new Error(`Invalid dialog state ${dialog.sessionState}`);
|
|
666
|
+
case SessionDialogState.AckWait: {
|
|
667
|
+
// This state only occurs if we are the callee.
|
|
668
|
+
this.stateTransition(SessionState.Terminating); // We're terminating
|
|
669
|
+
return new Promise((resolve) => {
|
|
670
|
+
dialog.delegate = {
|
|
671
|
+
// When ACK shows up, say BYE.
|
|
672
|
+
onAck: (): Promise<void> => {
|
|
673
|
+
const request = dialog.bye(delegate, options);
|
|
674
|
+
this.stateTransition(SessionState.Terminated);
|
|
675
|
+
resolve(request);
|
|
676
|
+
return Promise.resolve();
|
|
677
|
+
},
|
|
678
|
+
// Or the server transaction times out before the ACK arrives.
|
|
679
|
+
onAckTimeout: (): void => {
|
|
680
|
+
const request = dialog.bye(delegate, options);
|
|
681
|
+
this.stateTransition(SessionState.Terminated);
|
|
682
|
+
resolve(request);
|
|
683
|
+
}
|
|
684
|
+
};
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
case SessionDialogState.Confirmed: {
|
|
688
|
+
const request = dialog.bye(delegate, options);
|
|
689
|
+
this.stateTransition(SessionState.Terminated);
|
|
690
|
+
return Promise.resolve(request);
|
|
691
|
+
}
|
|
692
|
+
case SessionDialogState.Terminated:
|
|
693
|
+
throw new Error(`Invalid dialog state ${dialog.sessionState}`);
|
|
694
|
+
default:
|
|
695
|
+
throw new Error("Unrecognized state.");
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* Send INFO.
|
|
701
|
+
* @param delegate - Request delegate.
|
|
702
|
+
* @param options - Request options bucket.
|
|
703
|
+
* @internal
|
|
704
|
+
*/
|
|
705
|
+
public _info(delegate?: OutgoingRequestDelegate, options?: RequestOptions): Promise<OutgoingInfoRequest> {
|
|
706
|
+
// Using core session dialog
|
|
707
|
+
if (!this.dialog) {
|
|
708
|
+
return Promise.reject(new Error("Session dialog undefined."));
|
|
709
|
+
}
|
|
710
|
+
return Promise.resolve(this.dialog.info(delegate, options));
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
/**
|
|
714
|
+
* Send MESSAGE.
|
|
715
|
+
* @param delegate - Request delegate.
|
|
716
|
+
* @param options - Request options bucket.
|
|
717
|
+
* @internal
|
|
718
|
+
*/
|
|
719
|
+
public _message(delegate?: OutgoingRequestDelegate, options?: RequestOptions): Promise<OutgoingMessageRequest> {
|
|
720
|
+
// Using core session dialog
|
|
721
|
+
if (!this.dialog) {
|
|
722
|
+
return Promise.reject(new Error("Session dialog undefined."));
|
|
723
|
+
}
|
|
724
|
+
return Promise.resolve(this.dialog.message(delegate, options));
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
/**
|
|
728
|
+
* Send REFER.
|
|
729
|
+
* @param onNotify - Notification callback.
|
|
730
|
+
* @param delegate - Request delegate.
|
|
731
|
+
* @param options - Request options bucket.
|
|
732
|
+
* @internal
|
|
733
|
+
*/
|
|
734
|
+
public _refer(
|
|
735
|
+
onNotify?: (notification: Notification) => void,
|
|
736
|
+
delegate?: OutgoingRequestDelegate,
|
|
737
|
+
options?: RequestOptions
|
|
738
|
+
): Promise<OutgoingByeRequest> {
|
|
739
|
+
// Using core session dialog
|
|
740
|
+
if (!this.dialog) {
|
|
741
|
+
return Promise.reject(new Error("Session dialog undefined."));
|
|
742
|
+
}
|
|
743
|
+
// If set, deliver any in-dialog NOTIFY requests here...
|
|
744
|
+
this.onNotify = onNotify;
|
|
745
|
+
return Promise.resolve(this.dialog.refer(delegate, options));
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* Send ACK and then BYE. There are unrecoverable errors which can occur
|
|
750
|
+
* while handling dialog forming and in-dialog INVITE responses and when
|
|
751
|
+
* they occur we ACK the response and send a BYE.
|
|
752
|
+
* Note that the BYE is sent in the dialog associated with the response
|
|
753
|
+
* which is not necessarily `this.dialog`. And, accordingly, the
|
|
754
|
+
* session state is not transitioned to terminated and session is not closed.
|
|
755
|
+
* @param inviteResponse - The response causing the error.
|
|
756
|
+
* @param statusCode - Status code for he reason phrase.
|
|
757
|
+
* @param reasonPhrase - Reason phrase for the BYE.
|
|
758
|
+
* @internal
|
|
759
|
+
*/
|
|
760
|
+
protected ackAndBye(response: AckableIncomingResponseWithSession, statusCode?: number, reasonPhrase?: string): void {
|
|
761
|
+
response.ack();
|
|
762
|
+
const extraHeaders: Array<string> = [];
|
|
763
|
+
if (statusCode) {
|
|
764
|
+
extraHeaders.push("Reason: " + this.getReasonHeaderValue(statusCode, reasonPhrase));
|
|
765
|
+
}
|
|
766
|
+
// Using the dialog session associate with the response (which might not be this.dialog)
|
|
767
|
+
response.session.bye(undefined, { extraHeaders });
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
/**
|
|
771
|
+
* Handle in dialog ACK request.
|
|
772
|
+
* @internal
|
|
773
|
+
*/
|
|
774
|
+
protected onAckRequest(request: IncomingAckRequest): Promise<void> {
|
|
775
|
+
this.logger.log("Session.onAckRequest");
|
|
776
|
+
if (this.state !== SessionState.Established && this.state !== SessionState.Terminating) {
|
|
777
|
+
this.logger.error(`ACK received while in state ${this.state}, dropping request`);
|
|
778
|
+
return Promise.resolve();
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
const dialog = this.dialog;
|
|
782
|
+
if (!dialog) {
|
|
783
|
+
throw new Error("Dialog undefined.");
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
// if received answer in ACK.
|
|
787
|
+
const answerOptions = {
|
|
788
|
+
sessionDescriptionHandlerOptions: this.pendingReinviteAck
|
|
789
|
+
? this.sessionDescriptionHandlerOptionsReInvite
|
|
790
|
+
: this.sessionDescriptionHandlerOptions,
|
|
791
|
+
sessionDescriptionHandlerModifiers: this.pendingReinviteAck
|
|
792
|
+
? this._sessionDescriptionHandlerModifiersReInvite
|
|
793
|
+
: this._sessionDescriptionHandlerModifiers
|
|
794
|
+
};
|
|
795
|
+
|
|
796
|
+
// reset pending ACK flag
|
|
797
|
+
this.pendingReinviteAck = false;
|
|
798
|
+
|
|
799
|
+
switch (dialog.signalingState) {
|
|
800
|
+
case SignalingState.Initial: {
|
|
801
|
+
// State should never be reached as first reliable response must have answer/offer.
|
|
802
|
+
// So we must have never has sent an offer.
|
|
803
|
+
this.logger.error(`Invalid signaling state ${dialog.signalingState}.`);
|
|
804
|
+
const extraHeaders = ["Reason: " + this.getReasonHeaderValue(488, "Bad Media Description")];
|
|
805
|
+
dialog.bye(undefined, { extraHeaders });
|
|
806
|
+
this.stateTransition(SessionState.Terminated);
|
|
807
|
+
return Promise.resolve();
|
|
808
|
+
}
|
|
809
|
+
case SignalingState.Stable: {
|
|
810
|
+
// State we should be in.
|
|
811
|
+
// Either the ACK has the answer that got us here, or we were in this state prior to the ACK.
|
|
812
|
+
const body = getBody(request.message);
|
|
813
|
+
// If the ACK doesn't have an answer, nothing to be done.
|
|
814
|
+
if (!body) {
|
|
815
|
+
return Promise.resolve();
|
|
816
|
+
}
|
|
817
|
+
if (body.contentDisposition === "render") {
|
|
818
|
+
this._renderbody = body.content;
|
|
819
|
+
this._rendertype = body.contentType;
|
|
820
|
+
return Promise.resolve();
|
|
821
|
+
}
|
|
822
|
+
if (body.contentDisposition !== "session") {
|
|
823
|
+
return Promise.resolve();
|
|
824
|
+
}
|
|
825
|
+
return this.setAnswer(body, answerOptions).catch((error: Error) => {
|
|
826
|
+
this.logger.error(error.message);
|
|
827
|
+
const extraHeaders = ["Reason: " + this.getReasonHeaderValue(488, "Bad Media Description")];
|
|
828
|
+
dialog.bye(undefined, { extraHeaders });
|
|
829
|
+
this.stateTransition(SessionState.Terminated);
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
case SignalingState.HaveLocalOffer: {
|
|
833
|
+
// State should never be reached as local offer would be answered by this ACK.
|
|
834
|
+
// So we must have received an ACK without an answer.
|
|
835
|
+
this.logger.error(`Invalid signaling state ${dialog.signalingState}.`);
|
|
836
|
+
const extraHeaders = ["Reason: " + this.getReasonHeaderValue(488, "Bad Media Description")];
|
|
837
|
+
dialog.bye(undefined, { extraHeaders });
|
|
838
|
+
this.stateTransition(SessionState.Terminated);
|
|
839
|
+
return Promise.resolve();
|
|
840
|
+
}
|
|
841
|
+
case SignalingState.HaveRemoteOffer: {
|
|
842
|
+
// State should never be reached as remote offer would be answered in first reliable response.
|
|
843
|
+
// So we must have never has sent an answer.
|
|
844
|
+
this.logger.error(`Invalid signaling state ${dialog.signalingState}.`);
|
|
845
|
+
const extraHeaders = ["Reason: " + this.getReasonHeaderValue(488, "Bad Media Description")];
|
|
846
|
+
dialog.bye(undefined, { extraHeaders });
|
|
847
|
+
this.stateTransition(SessionState.Terminated);
|
|
848
|
+
return Promise.resolve();
|
|
849
|
+
}
|
|
850
|
+
case SignalingState.Closed:
|
|
851
|
+
throw new Error(`Invalid signaling state ${dialog.signalingState}.`);
|
|
852
|
+
default:
|
|
853
|
+
throw new Error(`Invalid signaling state ${dialog.signalingState}.`);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
/**
|
|
858
|
+
* Handle in dialog BYE request.
|
|
859
|
+
* @internal
|
|
860
|
+
*/
|
|
861
|
+
protected onByeRequest(request: IncomingByeRequest): void {
|
|
862
|
+
this.logger.log("Session.onByeRequest");
|
|
863
|
+
if (this.state !== SessionState.Established) {
|
|
864
|
+
this.logger.error(`BYE received while in state ${this.state}, dropping request`);
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
867
|
+
if (this.delegate && this.delegate.onBye) {
|
|
868
|
+
const bye = new Bye(request);
|
|
869
|
+
this.delegate.onBye(bye);
|
|
870
|
+
} else {
|
|
871
|
+
request.accept();
|
|
872
|
+
}
|
|
873
|
+
this.stateTransition(SessionState.Terminated);
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
/**
|
|
877
|
+
* Handle in dialog INFO request.
|
|
878
|
+
* @internal
|
|
879
|
+
*/
|
|
880
|
+
protected onInfoRequest(request: IncomingInfoRequest): void {
|
|
881
|
+
this.logger.log("Session.onInfoRequest");
|
|
882
|
+
if (this.state !== SessionState.Established) {
|
|
883
|
+
this.logger.error(`INFO received while in state ${this.state}, dropping request`);
|
|
884
|
+
return;
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
if (this.delegate && this.delegate.onInfo) {
|
|
888
|
+
const info = new Info(request);
|
|
889
|
+
this.delegate.onInfo(info);
|
|
890
|
+
} else {
|
|
891
|
+
// FIXME: TODO: We should reject request...
|
|
892
|
+
//
|
|
893
|
+
// If a UA receives an INFO request associated with an Info Package that
|
|
894
|
+
// the UA has not indicated willingness to receive, the UA MUST send a
|
|
895
|
+
// 469 (Bad Info Package) response (see Section 11.6), which contains a
|
|
896
|
+
// Recv-Info header field with Info Packages for which the UA is willing
|
|
897
|
+
// to receive INFO requests.
|
|
898
|
+
// https://tools.ietf.org/html/rfc6086#section-4.2.2
|
|
899
|
+
request.accept();
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
/**
|
|
904
|
+
* Handle in dialog INVITE request.
|
|
905
|
+
* @internal
|
|
906
|
+
*/
|
|
907
|
+
protected onInviteRequest(request: IncomingInviteRequest): void {
|
|
908
|
+
this.logger.log("Session.onInviteRequest");
|
|
909
|
+
if (this.state !== SessionState.Established) {
|
|
910
|
+
this.logger.error(`INVITE received while in state ${this.state}, dropping request`);
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
// set pending ACK flag
|
|
915
|
+
this.pendingReinviteAck = true;
|
|
916
|
+
|
|
917
|
+
// TODO: would be nice to have core track and set the Contact header,
|
|
918
|
+
// but currently the session which is setting it is holding onto it.
|
|
919
|
+
const extraHeaders = ["Contact: " + this._contact];
|
|
920
|
+
|
|
921
|
+
// Handle P-Asserted-Identity
|
|
922
|
+
if (request.message.hasHeader("P-Asserted-Identity")) {
|
|
923
|
+
const header = request.message.getHeader("P-Asserted-Identity");
|
|
924
|
+
if (!header) {
|
|
925
|
+
throw new Error("Header undefined.");
|
|
926
|
+
}
|
|
927
|
+
this._assertedIdentity = Grammar.nameAddrHeaderParse(header);
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
const options = {
|
|
931
|
+
sessionDescriptionHandlerOptions: this.sessionDescriptionHandlerOptionsReInvite,
|
|
932
|
+
sessionDescriptionHandlerModifiers: this.sessionDescriptionHandlerModifiersReInvite
|
|
933
|
+
};
|
|
934
|
+
this.generateResponseOfferAnswerInDialog(options)
|
|
935
|
+
.then((body) => {
|
|
936
|
+
const outgoingResponse = request.accept({ statusCode: 200, extraHeaders, body });
|
|
937
|
+
if (this.delegate && this.delegate.onInvite) {
|
|
938
|
+
this.delegate.onInvite(request.message, outgoingResponse.message, 200);
|
|
939
|
+
}
|
|
940
|
+
})
|
|
941
|
+
.catch((error: Error) => {
|
|
942
|
+
this.logger.error(error.message);
|
|
943
|
+
this.logger.error("Failed to handle to re-INVITE request");
|
|
944
|
+
if (!this.dialog) {
|
|
945
|
+
throw new Error("Dialog undefined.");
|
|
946
|
+
}
|
|
947
|
+
this.logger.error(this.dialog.signalingState);
|
|
948
|
+
// If we don't have a local/remote offer...
|
|
949
|
+
if (this.dialog.signalingState === SignalingState.Stable) {
|
|
950
|
+
const outgoingResponse = request.reject({ statusCode: 488 }); // Not Acceptable Here
|
|
951
|
+
if (this.delegate && this.delegate.onInvite) {
|
|
952
|
+
this.delegate.onInvite(request.message, outgoingResponse.message, 488);
|
|
953
|
+
}
|
|
954
|
+
return;
|
|
955
|
+
}
|
|
956
|
+
// Otherwise rollback
|
|
957
|
+
this.rollbackOffer()
|
|
958
|
+
.then(() => {
|
|
959
|
+
const outgoingResponse = request.reject({ statusCode: 488 }); // Not Acceptable Here
|
|
960
|
+
if (this.delegate && this.delegate.onInvite) {
|
|
961
|
+
this.delegate.onInvite(request.message, outgoingResponse.message, 488);
|
|
962
|
+
}
|
|
963
|
+
})
|
|
964
|
+
.catch((errorRollback: Error) => {
|
|
965
|
+
// No way to recover, so terminate session and mark as failed.
|
|
966
|
+
this.logger.error(errorRollback.message);
|
|
967
|
+
this.logger.error("Failed to rollback offer on re-INVITE request");
|
|
968
|
+
const outgoingResponse = request.reject({ statusCode: 488 }); // Not Acceptable Here
|
|
969
|
+
// A BYE should only be sent if session is not already terminated.
|
|
970
|
+
// For example, a BYE may be sent/received while re-INVITE is outstanding.
|
|
971
|
+
// Note that the ACK was already sent by the transaction, so just need to send BYE.
|
|
972
|
+
if (this.state !== SessionState.Terminated) {
|
|
973
|
+
if (!this.dialog) {
|
|
974
|
+
throw new Error("Dialog undefined.");
|
|
975
|
+
}
|
|
976
|
+
const extraHeadersBye: Array<string> = [];
|
|
977
|
+
extraHeadersBye.push("Reason: " + this.getReasonHeaderValue(500, "Internal Server Error"));
|
|
978
|
+
this.dialog.bye(undefined, { extraHeaders });
|
|
979
|
+
this.stateTransition(SessionState.Terminated);
|
|
980
|
+
}
|
|
981
|
+
if (this.delegate && this.delegate.onInvite) {
|
|
982
|
+
this.delegate.onInvite(request.message, outgoingResponse.message, 488);
|
|
983
|
+
}
|
|
984
|
+
});
|
|
985
|
+
});
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
/**
|
|
989
|
+
* Handle in dialog MESSAGE request.
|
|
990
|
+
* @internal
|
|
991
|
+
*/
|
|
992
|
+
protected onMessageRequest(request: IncomingMessageRequest): void {
|
|
993
|
+
this.logger.log("Session.onMessageRequest");
|
|
994
|
+
if (this.state !== SessionState.Established) {
|
|
995
|
+
this.logger.error(`MESSAGE received while in state ${this.state}, dropping request`);
|
|
996
|
+
return;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
if (this.delegate && this.delegate.onMessage) {
|
|
1000
|
+
const message = new Message(request);
|
|
1001
|
+
this.delegate.onMessage(message);
|
|
1002
|
+
} else {
|
|
1003
|
+
request.accept();
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
/**
|
|
1008
|
+
* Handle in dialog NOTIFY request.
|
|
1009
|
+
* @internal
|
|
1010
|
+
*/
|
|
1011
|
+
protected onNotifyRequest(request: IncomingNotifyRequest): void {
|
|
1012
|
+
this.logger.log("Session.onNotifyRequest");
|
|
1013
|
+
if (this.state !== SessionState.Established) {
|
|
1014
|
+
this.logger.error(`NOTIFY received while in state ${this.state}, dropping request`);
|
|
1015
|
+
return;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
// If this a NOTIFY associated with the progress of a REFER,
|
|
1019
|
+
// look to delegate handling to the associated callback.
|
|
1020
|
+
if (this.onNotify) {
|
|
1021
|
+
const notification = new Notification(request);
|
|
1022
|
+
this.onNotify(notification);
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
// Otherwise accept the NOTIFY.
|
|
1027
|
+
if (this.delegate && this.delegate.onNotify) {
|
|
1028
|
+
const notification = new Notification(request);
|
|
1029
|
+
this.delegate.onNotify(notification);
|
|
1030
|
+
} else {
|
|
1031
|
+
request.accept();
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
/**
|
|
1036
|
+
* Handle in dialog PRACK request.
|
|
1037
|
+
* @internal
|
|
1038
|
+
*/
|
|
1039
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1040
|
+
protected onPrackRequest(request: IncomingPrackRequest): void {
|
|
1041
|
+
this.logger.log("Session.onPrackRequest");
|
|
1042
|
+
if (this.state !== SessionState.Established) {
|
|
1043
|
+
this.logger.error(`PRACK received while in state ${this.state}, dropping request`);
|
|
1044
|
+
return;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
throw new Error("Unimplemented.");
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
/**
|
|
1051
|
+
* Handle in dialog REFER request.
|
|
1052
|
+
* @internal
|
|
1053
|
+
*/
|
|
1054
|
+
protected onReferRequest(request: IncomingReferRequest): void {
|
|
1055
|
+
this.logger.log("Session.onReferRequest");
|
|
1056
|
+
if (this.state !== SessionState.Established) {
|
|
1057
|
+
this.logger.error(`REFER received while in state ${this.state}, dropping request`);
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
// REFER is a SIP request and is constructed as defined in [1]. A REFER
|
|
1062
|
+
// request MUST contain exactly one Refer-To header field value.
|
|
1063
|
+
// https://tools.ietf.org/html/rfc3515#section-2.4.1
|
|
1064
|
+
if (!request.message.hasHeader("refer-to")) {
|
|
1065
|
+
this.logger.warn("Invalid REFER packet. A refer-to header is required. Rejecting.");
|
|
1066
|
+
request.reject();
|
|
1067
|
+
return;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
const referral = new Referral(request, this);
|
|
1071
|
+
|
|
1072
|
+
if (this.delegate && this.delegate.onRefer) {
|
|
1073
|
+
this.delegate.onRefer(referral);
|
|
1074
|
+
} else {
|
|
1075
|
+
this.logger.log("No delegate available to handle REFER, automatically accepting and following.");
|
|
1076
|
+
referral
|
|
1077
|
+
.accept()
|
|
1078
|
+
.then(() => referral.makeInviter(this._referralInviterOptions).invite())
|
|
1079
|
+
.catch((error: Error) => {
|
|
1080
|
+
// FIXME: logging and eating error...
|
|
1081
|
+
this.logger.error(error.message);
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
/**
|
|
1087
|
+
* Generate an offer or answer for a response to an INVITE request.
|
|
1088
|
+
* If a remote offer was provided in the request, set the remote
|
|
1089
|
+
* description and get a local answer. If a remote offer was not
|
|
1090
|
+
* provided, generates a local offer.
|
|
1091
|
+
* @internal
|
|
1092
|
+
*/
|
|
1093
|
+
protected generateResponseOfferAnswer(
|
|
1094
|
+
request: IncomingInviteRequest,
|
|
1095
|
+
options: {
|
|
1096
|
+
sessionDescriptionHandlerOptions?: SessionDescriptionHandlerOptions;
|
|
1097
|
+
sessionDescriptionHandlerModifiers?: Array<SessionDescriptionHandlerModifier>;
|
|
1098
|
+
}
|
|
1099
|
+
): Promise<Body | undefined> {
|
|
1100
|
+
if (this.dialog) {
|
|
1101
|
+
return this.generateResponseOfferAnswerInDialog(options);
|
|
1102
|
+
}
|
|
1103
|
+
const body = getBody(request.message);
|
|
1104
|
+
if (!body || body.contentDisposition !== "session") {
|
|
1105
|
+
return this.getOffer(options);
|
|
1106
|
+
} else {
|
|
1107
|
+
return this.setOfferAndGetAnswer(body, options);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
/**
|
|
1112
|
+
* Generate an offer or answer for a response to an INVITE request
|
|
1113
|
+
* when a dialog (early or otherwise) has already been established.
|
|
1114
|
+
* This method may NOT be called if a dialog has yet to be established.
|
|
1115
|
+
* @internal
|
|
1116
|
+
*/
|
|
1117
|
+
protected generateResponseOfferAnswerInDialog(options: {
|
|
1118
|
+
sessionDescriptionHandlerOptions?: SessionDescriptionHandlerOptions;
|
|
1119
|
+
sessionDescriptionHandlerModifiers?: Array<SessionDescriptionHandlerModifier>;
|
|
1120
|
+
}): Promise<Body | undefined> {
|
|
1121
|
+
if (!this.dialog) {
|
|
1122
|
+
throw new Error("Dialog undefined.");
|
|
1123
|
+
}
|
|
1124
|
+
switch (this.dialog.signalingState) {
|
|
1125
|
+
case SignalingState.Initial:
|
|
1126
|
+
return this.getOffer(options);
|
|
1127
|
+
case SignalingState.HaveLocalOffer:
|
|
1128
|
+
// o Once the UAS has sent or received an answer to the initial
|
|
1129
|
+
// offer, it MUST NOT generate subsequent offers in any responses
|
|
1130
|
+
// to the initial INVITE. This means that a UAS based on this
|
|
1131
|
+
// specification alone can never generate subsequent offers until
|
|
1132
|
+
// completion of the initial transaction.
|
|
1133
|
+
// https://tools.ietf.org/html/rfc3261#section-13.2.1
|
|
1134
|
+
return Promise.resolve(undefined);
|
|
1135
|
+
case SignalingState.HaveRemoteOffer:
|
|
1136
|
+
if (!this.dialog.offer) {
|
|
1137
|
+
throw new Error(`Session offer undefined in signaling state ${this.dialog.signalingState}.`);
|
|
1138
|
+
}
|
|
1139
|
+
return this.setOfferAndGetAnswer(this.dialog.offer, options);
|
|
1140
|
+
case SignalingState.Stable:
|
|
1141
|
+
// o Once the UAS has sent or received an answer to the initial
|
|
1142
|
+
// offer, it MUST NOT generate subsequent offers in any responses
|
|
1143
|
+
// to the initial INVITE. This means that a UAS based on this
|
|
1144
|
+
// specification alone can never generate subsequent offers until
|
|
1145
|
+
// completion of the initial transaction.
|
|
1146
|
+
// https://tools.ietf.org/html/rfc3261#section-13.2.1
|
|
1147
|
+
if (this.state !== SessionState.Established) {
|
|
1148
|
+
return Promise.resolve(undefined);
|
|
1149
|
+
}
|
|
1150
|
+
// In dialog INVITE without offer, get an offer for the response.
|
|
1151
|
+
return this.getOffer(options);
|
|
1152
|
+
case SignalingState.Closed:
|
|
1153
|
+
throw new Error(`Invalid signaling state ${this.dialog.signalingState}.`);
|
|
1154
|
+
default:
|
|
1155
|
+
throw new Error(`Invalid signaling state ${this.dialog.signalingState}.`);
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
/**
|
|
1160
|
+
* Get local offer.
|
|
1161
|
+
* @internal
|
|
1162
|
+
*/
|
|
1163
|
+
protected getOffer(options: {
|
|
1164
|
+
sessionDescriptionHandlerOptions?: SessionDescriptionHandlerOptions;
|
|
1165
|
+
sessionDescriptionHandlerModifiers?: Array<SessionDescriptionHandlerModifier>;
|
|
1166
|
+
}): Promise<Body> {
|
|
1167
|
+
const sdh = this.setupSessionDescriptionHandler();
|
|
1168
|
+
const sdhOptions = options.sessionDescriptionHandlerOptions;
|
|
1169
|
+
const sdhModifiers = options.sessionDescriptionHandlerModifiers;
|
|
1170
|
+
// This is intentionally written very defensively. Don't trust SDH to behave.
|
|
1171
|
+
try {
|
|
1172
|
+
return sdh
|
|
1173
|
+
.getDescription(sdhOptions, sdhModifiers)
|
|
1174
|
+
.then((bodyAndContentType) => fromBodyLegacy(bodyAndContentType))
|
|
1175
|
+
.catch((error: unknown) => {
|
|
1176
|
+
// don't trust SDH to reject with Error
|
|
1177
|
+
this.logger.error("Session.getOffer: SDH getDescription rejected...");
|
|
1178
|
+
const e = error instanceof Error ? error : new Error("Session.getOffer unknown error.");
|
|
1179
|
+
this.logger.error(e.message);
|
|
1180
|
+
throw e;
|
|
1181
|
+
});
|
|
1182
|
+
} catch (error) {
|
|
1183
|
+
// don't trust SDH to throw an Error
|
|
1184
|
+
this.logger.error("Session.getOffer: SDH getDescription threw...");
|
|
1185
|
+
const e = error instanceof Error ? error : new Error(error);
|
|
1186
|
+
this.logger.error(e.message);
|
|
1187
|
+
return Promise.reject(e);
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
/**
|
|
1192
|
+
* Rollback local/remote offer.
|
|
1193
|
+
* @internal
|
|
1194
|
+
*/
|
|
1195
|
+
protected rollbackOffer(): Promise<void> {
|
|
1196
|
+
const sdh = this.setupSessionDescriptionHandler();
|
|
1197
|
+
if (sdh.rollbackDescription === undefined) {
|
|
1198
|
+
return Promise.resolve();
|
|
1199
|
+
}
|
|
1200
|
+
// This is intentionally written very defensively. Don't trust SDH to behave.
|
|
1201
|
+
try {
|
|
1202
|
+
return sdh.rollbackDescription().catch((error: unknown) => {
|
|
1203
|
+
// don't trust SDH to reject with Error
|
|
1204
|
+
this.logger.error("Session.rollbackOffer: SDH rollbackDescription rejected...");
|
|
1205
|
+
const e = error instanceof Error ? error : new Error("Session.rollbackOffer unknown error.");
|
|
1206
|
+
this.logger.error(e.message);
|
|
1207
|
+
throw e;
|
|
1208
|
+
});
|
|
1209
|
+
} catch (error) {
|
|
1210
|
+
// don't trust SDH to throw an Error
|
|
1211
|
+
this.logger.error("Session.rollbackOffer: SDH rollbackDescription threw...");
|
|
1212
|
+
const e = error instanceof Error ? error : new Error(error);
|
|
1213
|
+
this.logger.error(e.message);
|
|
1214
|
+
return Promise.reject(e);
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
/**
|
|
1219
|
+
* Set remote answer.
|
|
1220
|
+
* @internal
|
|
1221
|
+
*/
|
|
1222
|
+
protected setAnswer(
|
|
1223
|
+
answer: Body,
|
|
1224
|
+
options: {
|
|
1225
|
+
sessionDescriptionHandlerOptions?: SessionDescriptionHandlerOptions;
|
|
1226
|
+
sessionDescriptionHandlerModifiers?: Array<SessionDescriptionHandlerModifier>;
|
|
1227
|
+
}
|
|
1228
|
+
): Promise<void> {
|
|
1229
|
+
const sdh = this.setupSessionDescriptionHandler();
|
|
1230
|
+
const sdhOptions = options.sessionDescriptionHandlerOptions;
|
|
1231
|
+
const sdhModifiers = options.sessionDescriptionHandlerModifiers;
|
|
1232
|
+
// This is intentionally written very defensively. Don't trust SDH to behave.
|
|
1233
|
+
try {
|
|
1234
|
+
if (!sdh.hasDescription(answer.contentType)) {
|
|
1235
|
+
return Promise.reject(new ContentTypeUnsupportedError());
|
|
1236
|
+
}
|
|
1237
|
+
} catch (error) {
|
|
1238
|
+
this.logger.error("Session.setAnswer: SDH hasDescription threw...");
|
|
1239
|
+
const e = error instanceof Error ? error : new Error(error);
|
|
1240
|
+
this.logger.error(e.message);
|
|
1241
|
+
return Promise.reject(e);
|
|
1242
|
+
}
|
|
1243
|
+
try {
|
|
1244
|
+
return sdh.setDescription(answer.content, sdhOptions, sdhModifiers).catch((error: unknown) => {
|
|
1245
|
+
// don't trust SDH to reject with Error
|
|
1246
|
+
this.logger.error("Session.setAnswer: SDH setDescription rejected...");
|
|
1247
|
+
const e = error instanceof Error ? error : new Error("Session.setAnswer unknown error.");
|
|
1248
|
+
this.logger.error(e.message);
|
|
1249
|
+
throw e;
|
|
1250
|
+
});
|
|
1251
|
+
} catch (error) {
|
|
1252
|
+
// don't trust SDH to throw an Error
|
|
1253
|
+
this.logger.error("Session.setAnswer: SDH setDescription threw...");
|
|
1254
|
+
const e = error instanceof Error ? error : new Error(error);
|
|
1255
|
+
this.logger.error(e.message);
|
|
1256
|
+
return Promise.reject(e);
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
/**
|
|
1261
|
+
* Set remote offer and get local answer.
|
|
1262
|
+
* @internal
|
|
1263
|
+
*/
|
|
1264
|
+
protected setOfferAndGetAnswer(
|
|
1265
|
+
offer: Body,
|
|
1266
|
+
options: {
|
|
1267
|
+
sessionDescriptionHandlerOptions?: SessionDescriptionHandlerOptions;
|
|
1268
|
+
sessionDescriptionHandlerModifiers?: Array<SessionDescriptionHandlerModifier>;
|
|
1269
|
+
}
|
|
1270
|
+
): Promise<Body> {
|
|
1271
|
+
const sdh = this.setupSessionDescriptionHandler();
|
|
1272
|
+
const sdhOptions = options.sessionDescriptionHandlerOptions;
|
|
1273
|
+
const sdhModifiers = options.sessionDescriptionHandlerModifiers;
|
|
1274
|
+
// This is intentionally written very defensively. Don't trust SDH to behave.
|
|
1275
|
+
try {
|
|
1276
|
+
if (!sdh.hasDescription(offer.contentType)) {
|
|
1277
|
+
return Promise.reject(new ContentTypeUnsupportedError());
|
|
1278
|
+
}
|
|
1279
|
+
} catch (error) {
|
|
1280
|
+
this.logger.error("Session.setOfferAndGetAnswer: SDH hasDescription threw...");
|
|
1281
|
+
const e = error instanceof Error ? error : new Error(error);
|
|
1282
|
+
this.logger.error(e.message);
|
|
1283
|
+
return Promise.reject(e);
|
|
1284
|
+
}
|
|
1285
|
+
try {
|
|
1286
|
+
return sdh
|
|
1287
|
+
.setDescription(offer.content, sdhOptions, sdhModifiers)
|
|
1288
|
+
.then(() => sdh.getDescription(sdhOptions, sdhModifiers))
|
|
1289
|
+
.then((bodyAndContentType) => fromBodyLegacy(bodyAndContentType))
|
|
1290
|
+
.catch((error: unknown) => {
|
|
1291
|
+
// don't trust SDH to reject with Error
|
|
1292
|
+
this.logger.error("Session.setOfferAndGetAnswer: SDH setDescription or getDescription rejected...");
|
|
1293
|
+
const e = error instanceof Error ? error : new Error("Session.setOfferAndGetAnswer unknown error.");
|
|
1294
|
+
this.logger.error(e.message);
|
|
1295
|
+
throw e;
|
|
1296
|
+
});
|
|
1297
|
+
} catch (error) {
|
|
1298
|
+
// don't trust SDH to throw an Error
|
|
1299
|
+
this.logger.error("Session.setOfferAndGetAnswer: SDH setDescription or getDescription threw...");
|
|
1300
|
+
const e = error instanceof Error ? error : new Error(error);
|
|
1301
|
+
this.logger.error(e.message);
|
|
1302
|
+
return Promise.reject(e);
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
/**
|
|
1307
|
+
* SDH for confirmed dialog.
|
|
1308
|
+
* @internal
|
|
1309
|
+
*/
|
|
1310
|
+
protected setSessionDescriptionHandler(sdh: SessionDescriptionHandler): void {
|
|
1311
|
+
if (this._sessionDescriptionHandler) {
|
|
1312
|
+
throw new Error("Session description handler defined.");
|
|
1313
|
+
}
|
|
1314
|
+
this._sessionDescriptionHandler = sdh;
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
/**
|
|
1318
|
+
* SDH for confirmed dialog.
|
|
1319
|
+
* @internal
|
|
1320
|
+
*/
|
|
1321
|
+
protected setupSessionDescriptionHandler(): SessionDescriptionHandler {
|
|
1322
|
+
if (this._sessionDescriptionHandler) {
|
|
1323
|
+
return this._sessionDescriptionHandler;
|
|
1324
|
+
}
|
|
1325
|
+
this._sessionDescriptionHandler = this.sessionDescriptionHandlerFactory(
|
|
1326
|
+
this,
|
|
1327
|
+
this.userAgent.configuration.sessionDescriptionHandlerFactoryOptions
|
|
1328
|
+
);
|
|
1329
|
+
if (this.delegate?.onSessionDescriptionHandler) {
|
|
1330
|
+
this.delegate.onSessionDescriptionHandler(this._sessionDescriptionHandler, false);
|
|
1331
|
+
}
|
|
1332
|
+
return this._sessionDescriptionHandler;
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
/**
|
|
1336
|
+
* Transition session state.
|
|
1337
|
+
* @internal
|
|
1338
|
+
*/
|
|
1339
|
+
protected stateTransition(newState: SessionState): void {
|
|
1340
|
+
const invalidTransition = (): void => {
|
|
1341
|
+
throw new Error(`Invalid state transition from ${this._state} to ${newState}`);
|
|
1342
|
+
};
|
|
1343
|
+
|
|
1344
|
+
// Validate transition
|
|
1345
|
+
switch (this._state) {
|
|
1346
|
+
case SessionState.Initial:
|
|
1347
|
+
if (
|
|
1348
|
+
newState !== SessionState.Establishing &&
|
|
1349
|
+
newState !== SessionState.Established &&
|
|
1350
|
+
newState !== SessionState.Terminating &&
|
|
1351
|
+
newState !== SessionState.Terminated
|
|
1352
|
+
) {
|
|
1353
|
+
invalidTransition();
|
|
1354
|
+
}
|
|
1355
|
+
break;
|
|
1356
|
+
case SessionState.Establishing:
|
|
1357
|
+
if (
|
|
1358
|
+
newState !== SessionState.Established &&
|
|
1359
|
+
newState !== SessionState.Terminating &&
|
|
1360
|
+
newState !== SessionState.Terminated
|
|
1361
|
+
) {
|
|
1362
|
+
invalidTransition();
|
|
1363
|
+
}
|
|
1364
|
+
break;
|
|
1365
|
+
case SessionState.Established:
|
|
1366
|
+
if (newState !== SessionState.Terminating && newState !== SessionState.Terminated) {
|
|
1367
|
+
invalidTransition();
|
|
1368
|
+
}
|
|
1369
|
+
break;
|
|
1370
|
+
case SessionState.Terminating:
|
|
1371
|
+
if (newState !== SessionState.Terminated) {
|
|
1372
|
+
invalidTransition();
|
|
1373
|
+
}
|
|
1374
|
+
break;
|
|
1375
|
+
case SessionState.Terminated:
|
|
1376
|
+
invalidTransition();
|
|
1377
|
+
break;
|
|
1378
|
+
default:
|
|
1379
|
+
throw new Error("Unrecognized state.");
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
// Transition
|
|
1383
|
+
this._state = newState;
|
|
1384
|
+
this.logger.log(`Session ${this.id} transitioned to state ${this._state}`);
|
|
1385
|
+
this._stateEventEmitter.emit(this._state);
|
|
1386
|
+
|
|
1387
|
+
// Dispose
|
|
1388
|
+
if (newState === SessionState.Terminated) {
|
|
1389
|
+
this.dispose();
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
private copyRequestOptions(requestOptions: RequestOptions = {}): RequestOptions {
|
|
1394
|
+
const extraHeaders = requestOptions.extraHeaders ? requestOptions.extraHeaders.slice() : undefined;
|
|
1395
|
+
const body = requestOptions.body
|
|
1396
|
+
? {
|
|
1397
|
+
contentDisposition: requestOptions.body.contentDisposition || "render",
|
|
1398
|
+
contentType: requestOptions.body.contentType || "text/plain",
|
|
1399
|
+
content: requestOptions.body.content || ""
|
|
1400
|
+
}
|
|
1401
|
+
: undefined;
|
|
1402
|
+
return {
|
|
1403
|
+
extraHeaders,
|
|
1404
|
+
body
|
|
1405
|
+
};
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
private getReasonHeaderValue(code: number, reason?: string): string {
|
|
1409
|
+
const cause = code;
|
|
1410
|
+
let text = getReasonPhrase(code);
|
|
1411
|
+
if (!text && reason) {
|
|
1412
|
+
text = reason;
|
|
1413
|
+
}
|
|
1414
|
+
return "SIP;cause=" + cause + ';text="' + text + '"';
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
private referExtraHeaders(referTo: string): Array<string> {
|
|
1418
|
+
const extraHeaders: Array<string> = [];
|
|
1419
|
+
extraHeaders.push("Referred-By: <" + this.userAgent.configuration.uri + ">");
|
|
1420
|
+
extraHeaders.push("Contact: " + this._contact);
|
|
1421
|
+
extraHeaders.push(
|
|
1422
|
+
"Allow: " + ["ACK", "CANCEL", "INVITE", "MESSAGE", "BYE", "OPTIONS", "INFO", "NOTIFY", "REFER"].toString()
|
|
1423
|
+
);
|
|
1424
|
+
extraHeaders.push("Refer-To: " + referTo);
|
|
1425
|
+
return extraHeaders;
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
private referToString(target: URI | Session): string {
|
|
1429
|
+
let referTo: string;
|
|
1430
|
+
if (target instanceof URI) {
|
|
1431
|
+
// REFER without Replaces (Blind Transfer)
|
|
1432
|
+
referTo = target.toString();
|
|
1433
|
+
} else {
|
|
1434
|
+
// REFER with Replaces (Attended Transfer)
|
|
1435
|
+
if (!target.dialog) {
|
|
1436
|
+
throw new Error("Dialog undefined.");
|
|
1437
|
+
}
|
|
1438
|
+
const displayName = target.remoteIdentity.friendlyName;
|
|
1439
|
+
const remoteTarget = target.dialog.remoteTarget.toString();
|
|
1440
|
+
const callId = target.dialog.callId;
|
|
1441
|
+
const remoteTag = target.dialog.remoteTag;
|
|
1442
|
+
const localTag = target.dialog.localTag;
|
|
1443
|
+
const replaces = encodeURIComponent(`${callId};to-tag=${remoteTag};from-tag=${localTag}`);
|
|
1444
|
+
referTo = `"${displayName}" <${remoteTarget}?Replaces=${replaces}>`;
|
|
1445
|
+
}
|
|
1446
|
+
return referTo;
|
|
1447
|
+
}
|
|
1448
|
+
}
|