---
title: "Calling Operations Module"
description: "This module provides a set of functions that allow the user to control ongoing calls."
---

## Admin Guide


### Overview


This module provides a set of functions that allow the user to control
ongoing calls. It can be used to trigger a call (either blind or attended)
transfer, or put a call on hold from the proxy side, rather than the
end-device side.
The module binds on top of the [OpenSIPS Dialog
module](../dialog/README.md) to get information about the ongoing calls, as well as
storing information about new calls that will be started.


The module also triggers a set of events over Event Interface, providing
to external applications details about how calls are being transferred, and
how they link between them. These events can be used to track down all the
legs involved in a call transfer.


One of the biggest challenge when doing Call Transfer scenarios is linking
new calls to the old calls being transferred, especially in blind call
transfer scenarios. In order to solve this challenge, the module can be
configured to refer old legs in two different modes, changeable using the
[mode](#mode-stringinteger) parameter:


- Automatically (default mode), by adding a special parameter to the
destination URI that is being sent in the REFER. When the new call
comes back, the parameter will be present in the Request URI of the
new call. The module will find it, link the new call to the old call,
and remove the parameter from the URI.
- Manually, by using custom/external logic (such as a database, or
local storage), to match the old call. In this mode, the user has to
explicitly call the [call blind replace](#call_blind_replacecallid-leg)
function to link the two calls together.


The module can also be used to catch *Notify refer* events
and reply to them from the OpenSIPS level. However, note that in *auto* mode even if the NOTIFY is handled when the dialog is matched,
the request will still continue its execution of the script, unlike when
*manual* mode is used with the
[call transfer notify](#call_transfer_notify) function. In order to avoid sending
the NOTIFY to the end-point, you have to drop it, like below:


```opensips title="Drop automatically handled NOTIFY refer events"
...
if (has_totag() && loose_route() &&
		is_method("NOTIFY") && $hdr(Event) == "refer")
	drop;
...
```


### Dependencies


#### OpenSIPS Modules


The following modules must be loaded before this module:


- *TM* - Transaction module.
- *Dialog* - Dialog module for keeping track of the proxied calls.


#### External Libraries or Applications


The following libraries or applications must be installed before
running OpenSIPS with this module loaded:


- *None*.


### Exported Parameters


#### mode (string/integer)


This parameter can be used to change the mode that the module
uses to match a transferred leg. Supported values are:


- *param* / *0* - when
doing a blind transfer, the destination sent in the
refer message will contain a parameter used to identify
the dialog that is being replaced. this parameter will be
automatically removed when the new call is received.
- *manual* / *1* - the user
will create its own logic to match the new calls, and will
call the [call blind replace](#call_blind_replacecallid-leg) function
to make OpenSIPS aware of the pair. Note that this mode does
not handle automatically the *Notify refer*
either, so you also have to use the
[call transfer notify](#call_transfer_notify) function to handle
them.
- *callid* / *2* - similar
to the *param* value, except that instead
of storing in the Request URI the dialog id of the call to
be transfered, the actual callid is used as identifier.


*Default value is "0 (auto mode using parameters)".*


```opensips title="Set mode parameter"
...
modparam("callops", "mode", "manual") # use your own logic
...
```


#### match_param (string)


The parameter used to match the different calls together. This is
mainly using in the *param* mode, but it is also
used internally to store different values inside the transferred
dialog - make sure it does not overlap with existing dialog values.


*Default value is "osid".*


```opensips title="Set match_param parameter"
...
modparam("callops", "match_param", "call")
...
```


### Exported Functions


#### call_blind_replace(callid[, leg])


When *manual mode* is used, this function is
called to create a mapping between the transferring call and the
transferred call. It should be called when OpenSIPS receives a
new call that is transferring an existing call.


Parameters:


- *callid* (string) - the existing call that
is being transferred.
- *leg* (string, optional) - the leg that is
being transferred. If not specified, and OpenSIPS cannot
determine the leg based on its destination, the
*unknown* tag should be used.


This function can be used only from a request route.


```opensips title="Use call_blind_replace() function to match an existing leg."
...
if (!has_totag() && is_method("INVITE")) {
	if (cache_fetch("local", "callid_$si", $avp(callid))) {
		call_blind_replace($avp(callid));
	}
}
...
	
```


#### call_transfer_notify()


When *manual mode* is used, this function should
be called on in-dialog NOTIFY requests for an *Event: refer*
header, to handle them accordingly.


Note that if the function successfully handles the NOTIFY request,
the script no longer continues its execution.


This function can be used from a request route, failure route and local route.


```opensips title="Use call_transfer_notify() function to handle NOTIFY refer requests."
...
if (has_totag() && is_method("NOTIFY") && loose_route()) {
	call_transfer_notify();
}
...
	
```


#### call_transfer(leg, destination) or


This function triggers a blind call transfer by sending a REFER
message during an ongoing call. The function needs to be run inside
the context of the dialog you are transferring.


Parameters:


- *leg* (string) - the leg that is
being transferred. Must be one of the *caller*
or *callee* values.
- *destination* (string) - SIP URI of the destination
where the leg is being transferred.


This function can be used from any route that has a dialog context.


```opensips title="Use call_transfer() function to do a blind transfer of the caller to a new destination."
...
if (has_totag() && && loose_route()) {
	call_transfer("caller", "sip:announcement@127.0.0.1");
}
...
	
```


#### call_transfer(leg, transfer_callid, transfer_leg[, destination]) or


This function triggers an attended call transfer by sending a REFER
message during an ongoing call. The function needs to be run inside
the context of the dialog you are transferring.


Parameters:


- *leg* (string) - the leg that is
being transferred. Must be one of the *caller*
or *callee* values.
- *transfer_callid* (string) - the callid of the
second dialog that is being transferred.
- *transfer_leg* (string) - the leg within the
second call that will be transferred to *leg*.
Must be one of the *caller* or
*callee* values.
- *destination* (string, optional) - SIP URI of the
destination where the leg is being transferred. If missing, the
From/To URI of the initial call are used.


This function can be used from any route that has a dialog context.


```opensips title="Use call_transfer() function to do an attended transfer of the caller to the callee of a different call."
...
if (has_totag() && && loose_route()) {
	call_transfer("caller", "ba55b1b3-459d-4e84-a6f8-14c40e4f6ace", "callee");
}
...
	
```


### Exported MI Functions


#### callops:transfer


Replaces obsolete MI command: *call_transfer*.


MI command to transfer an ongoing call to a new destination.


Depending on the parameters used, this command can do both
blind and attended transfers scenarios. When the
*transfer_callid* is used, then an attended
transfer is performed, other wise a blind transfer is issued.


Name: *callops:transfer*


Parameters


- *callid* (string) - the callid of the
dialog that is being transferred.
- *leg* (string) - indicates the
leg of the *callid* call that is being
transferred/kept in the new transferring call.
Possible values are "caller",
"callee" or "both".
- *destination* (string, optional) - the URI
where the call is being transferred. This parameter is
mandatory for blind transfers, and optional for attended
transfers. In the case of an attended transfer, if it is
missing, the destination of the call is taken from the
URIs in the transfer dialog.
- *transfer_callid* (string, optional) -
mandatory in case of an attended transfer, to specify the
call of the Bleg in the new call.
- *transfer_leg* (string, optional) -
in case of an attended transfer, it specifies the participant
of the *transfer_callid* call that will be
bridged with the *leg* of the
*callid*. If missing,
*transfer_fromtag* and
*transfer_totag* must be used to identify
the tag.
- *transfer_fromtag* and
*transfer_totag* (string, optional) -
these parameters should always be specified together, and are
used in call attended transfer scenarios where the dialog of the
Bleg that is being transferred is not managed by OpenSIPS.
Note that for these scenarios only the A-leg dialog will
receive events about the call transfer.


MI FIFO Command Format:


```bash
# blind transfer to sip:agent@127.0.0.1
opensips-cli -x mi callops:transfer \
	callid=4b664b48-5639-40bf-bff8-3a866c145c3b \
	leg=caller \
	destination=sip:agent@217.0.0.1
		
```


```bash
# attended transfer between two calls
opensips-cli -x mi callops:transfer \
	callid=e8d024db-78e5-4d18-9794-5b8ba837bed4
	leg=caller \
	transfer_callid=559abf97-9834-4380-bba1-a036eb245450 \
	transfer_leg=calee
		
```


#### callops:hold


Replaces obsolete MI command: *call_hold*.


MI command to put an ongoing call on hold.


Command returns *OK* if any of the legs
of the call have been put on hold. If the call is already
on hold, an error is returned.


Name: *callops:hold*


Parameters


- *callid* (string) - the callid of the
dialog that is being put on hold.
- *leg* (string, optional) - put only a
specific participant on hold. Possible values are
*caller*, *callee*
and *bold* and indicate the leg that
is being put on hold. If not used, both legs are being
put on hold.
- *headers* (string or array, optional) -
extra headers to be added to the outgoing re-INVITE.
If a string is provided, the headers go to both caller
and callee. If a two string elements array is provided,
the first element represents the headers that go to the
caller, the second one headers that go to the callee.
Use empty string for no headers to be passed at caller.


MI FIFO Command Format:


```bash
# put a call on hold
opensips-cli -x mi callops:hold \
	callid=921b00e4-fec0-4a36-9397-a40ab74e1893
		
```


#### callops:unhold


Replaces obsolete MI command: *call_unhold*.


MI command to resume a call from an onhold state put by the
[mi hold](#callopshold) call.


Command returns *OK* if any of the legs
are resumed, or an error if no leg had been previously put
on hold.


Name: *callops:unhold*


Parameters


- *callid* (string) - the callid of the
dialog that is being resumed.
- *leg* (string, optional) - resume only a
specific participant on hold. Possible values are
*caller*, *callee*
and *bold* and indicate the leg that
is being resumed. If not used, both legs are resumed.
- *headers* (string or array, optional) -
extra headers to be added to the outgoing re-INVITE.
If a string is provided, the headers go to both caller
and callee. If a two string elements array is provided,
the first element represents the headers that go to the
caller, the second one headers that go to the callee.
Use empty string for no headers to be passed at caller.


MI FIFO Command Format:


```bash
opensips-cli -x mi callops:unhold \
	callid=921b00e4-fec0-4a36-9397-a40ab74e1893
		
```


### Exported Events


#### E_CALL_TRANSFER


This event is triggered during a call transfer scenario.


For a specific call transfer, multiple events are triggered,
starting when the transfer is initiated, until the transfer
is completed. The *state* parameter indicates
the state of the call transfer.


For a blind transfer scenario, only one set of events are
triggered, whereas for attended transfer, you will get a set
of events for both dialogs involved in the transfer, as long
as both are proxied through OpenSIPS


Parameters:


- *callid* - the callid of the call
that is being transferred.
- *leg* - the leg (*caller* or *callee*) of the call
that is being transferred.
- *transfer_callid* - the callid of the
new call that is transferring the old *callid* call.
- *destination* - the URI destination
where the *leg* is being transferred.
- *state* - the state of the transfer:
	* *start* - triggered when the
		REFER message is being sent out to the transferred participant.
	* *notify* - triggered when
		a NOTIFY refer event is received from the transferred participant.
		The *status* parameter contains extra
		information about the status of the transferring call.
	* *ok* - triggered when
		the transfer is completed - the call is answered by
		the transferred participant.
	* *fail* - triggered when
		a transfer has failed due to various reasons. If we were
		unable to start the call transfer (i.e. send the REFER),
		the *status* parameter is empty,
		otherwise it contains information about the failure.
- *status* - contains extra information about
the success or failure of the call.


#### E_CALL_HOLD


Triggered during the process of putting a call on hold, or resuming
a call from an on hold state.


This event is triggered twice per each leg of the call - first when
the leg starts to be put on hold, and then when the leg accepts or
rejects the state.


Parameters:


- *callid* - the callid of the call
that is being put on hold, or resumed.
- *leg* - the leg (*caller* or *callee*) affected
by the call on hold, or resumed.
- *action* - *hold* or
*unhold* action that is being performed.
- *state* - the state of the action that
is being performed.
  * *start* - triggered when the re-INVITE is being sent out to the participant being put on hold.
  * *ok* - triggered when the on hold/resume action is successfully completed.
  * *fail* - triggered when the action failed.
<!-- CONTRIBUTORS -->

### License

All documentation files (i.e. .md extension) are licensed under the Creative Common License 4.0
