diff --git a/README.md b/README.md index 9e95237..d45a421 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,8 @@ To make calls, simply use these functions: The value for `destination` argument equals to the target SIP user without the host part (e.g. `+441234567890` or `bob`). The omitted host part is equal to host you’ve defined in `SipProvider` props (e.g. `sip.example.com`). +During a call you can put it on hold using the `call.hold()` and `call.unhold()` functions. You can also get hold status with the `call.isOnHold` property. + --- The values for `sip.status`, `sip.errorType`, `call.status` and `call.direction` can be imported as constants to make typos easier to detect: diff --git a/src/components/SipProvider/index.ts b/src/components/SipProvider/index.ts index 6c99403..0b5f01a 100644 --- a/src/components/SipProvider/index.ts +++ b/src/components/SipProvider/index.ts @@ -55,6 +55,7 @@ export default class SipProvider extends React.Component< callStatus: CallStatus; callDirection: CallDirection | null; callCounterpart: string | null; + callIsOnHold: boolean; rtcSession; } > { @@ -96,7 +97,7 @@ export default class SipProvider extends React.Component< autoAnswer: false, iceRestart: false, sessionTimersExpires: 120, - extraHeaders: { register: [], invite: [] }, + extraHeaders: { register: [], invite: [], hold: [] }, iceServers: [], debug: false, @@ -119,6 +120,7 @@ export default class SipProvider extends React.Component< callStatus: CALL_STATUS_IDLE, callDirection: null, callCounterpart: null, + callIsOnHold: false, }; this.ua = null; @@ -137,6 +139,10 @@ export default class SipProvider extends React.Component< status: this.state.callStatus, direction: this.state.callDirection, counterpart: this.state.callCounterpart, + isOnHold: this.state.callIsOnHold, + hold: this.callHold, + unhold: this.callUnhold, + toggleHold: this.callToggleHold, }, registerSip: this.registerSip, unregisterSip: this.unregisterSip, @@ -436,6 +442,7 @@ export default class SipProvider extends React.Component< callStatus: CALL_STATUS_STARTING, callCounterpart: foundUri.substring(0, delimiterPosition) || foundUri, + callIsOnHold: rtcSession.isOnHold().local, }); } else if (originator === "remote") { const foundUri = rtcRequest.from.toString(); @@ -445,6 +452,7 @@ export default class SipProvider extends React.Component< callStatus: CALL_STATUS_STARTING, callCounterpart: foundUri.substring(0, delimiterPosition) || foundUri, + callIsOnHold: rtcSession.isOnHold().local, }); } @@ -484,6 +492,7 @@ export default class SipProvider extends React.Component< callStatus: CALL_STATUS_IDLE, callDirection: null, callCounterpart: null, + callIsOnHold: false, }); }); @@ -546,4 +555,39 @@ export default class SipProvider extends React.Component< public render() { return this.props.children; } + + private callHold = (useUpdate = false) => { + const holdStatus = this.state.rtcSession.isOnHold(); + if (!holdStatus.local) { + const options = { + useUpdate, + extraHeaders: this.props.extraHeaders.hold, + }; + const done = () => { + this.setState({ callIsOnHold: true }); + }; + this.state.rtcSession.hold(options, done); + } + }; + + private callUnhold = (useUpdate = false) => { + const holdStatus = this.state.rtcSession.isOnHold(); + if (holdStatus.local) { + const options = { + useUpdate, + extraHeaders: this.props.extraHeaders.hold, + }; + const done = () => { + this.setState({ callIsOnHold: false }); + }; + this.state.rtcSession.unhold(options, done); + } + }; + + private callToggleHold = (useUpdate = false) => { + const holdStatus = this.state.rtcSession.isOnHold(); + return holdStatus.local + ? this.callUnhold(useUpdate) + : this.callHold(useUpdate); + }; } diff --git a/src/lib/types.ts b/src/lib/types.ts index 1265303..877c463 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -3,6 +3,7 @@ import * as PropTypes from "prop-types"; export interface ExtraHeaders { register?: string[]; invite?: string[]; + hold?: string[]; } export const extraHeadersPropType = PropTypes.objectOf( PropTypes.arrayOf(PropTypes.string), @@ -62,4 +63,8 @@ export const callPropType = PropTypes.shape({ status: PropTypes.string, direction: PropTypes.string, counterpart: PropTypes.string, + isOnHold: PropTypes.bool, + hold: PropTypes.func, + unhold: PropTypes.func, + toggleHold: PropTypes.func, });