
SIP proxies, by definition, lack the ability to do any media handling, due to the fact that they only stand in the path of call signalling, not call media. Therefore if you want to enhance your SIP proxy with any extra media capabilities, you have to inject a new component in the media path, that is capable of providing media services. This should be ideally done without altering the signalling path of the ongoing call (i.e. without transferring the call to a media server), as the calls should be easily resumed in the initial state.
A set of examples where manipulating media in an ongoing call can be useful, while preserving its signalling path, are:
- inject an audio/video announcement
- playback music on hold files
- fork media for call recording, or for call listening
- inject media for call whispering
- temporary barge in an ongoing call
All these features, and many others can be implemented by simply mixing the participants of multiple calls. This article presents the new OpenSIPS 3.1 Media Exchange module, and describes how it can be used to provide different media capabilities to ongoing, proxied calls, without changing the SIP signalling, but only exchanging SDP bodies between different SIP sessions.
Description
The media_exchange module in OpenSIPS 3.1 provides a set of primitives that are able to originate/answer new calls from a media server (such as FreeSWITCH or Asterisk) in a B2B manner, and bridge the media path between these calls and ongoing proxied calls. In order to implement the B2B behavior, the module relies on the B2B entities module to handle the SIP signalling logic.
The module can work in two modes, described in the following sections:
Full media exchange
In this mode, the module hooks one of the proxied call’s participant to the Media Server call. For a better understanding about how this works, you can find below a set of diagrams. Figure 1. shows a normal, proxied call from A to B, using OpenSIPS. We will refer to this call as SIP1.

Once you decide that an announcement, or a music on hold playback should be inserted, a new call to the Media Server appears. We refer to this call as SIP 2. For this call, the module provides to the Media Server the SDP body of participant A. This state is represented in Figure 2.

Note that participant B is put on hold by the module, since it does not have any endpoints to talk to. If you want to push an announcement to B, you need a new, similar call to the Media Server, that will bridge B. This will be call SIP 3, like the one in Figure 3.

Terminating any of the SIP 2 or 3 calls, by either OpenSIPS or Media Server, will result in closing the corresponding RTP session, and put the remaining participant on hold, similar to the state in Figure 2. When both SIP 2 and 3 calls are terminated, the call will become just a simple, proxied one, like the one in Figure 1.
Media Forking
The second mode that the media_exchange module can work on is the one where the media of an existing call is simply forked to a different SIP UA. This mode can be useful in call recording, or media real-time processing scenarios. It presumes inserting a media relay server (such as RTPProxy) in the media path and duplicating the media to a new destination (similar to the SIPREC module, but using just plain SIP).
Starting from a normal call like the one in Figure 1, forking the media of an existing call, will result in a scheme like the one in Figure 4:

Implementation
In terms of implementation, OpenSIPS provides a set of script function for both modes. Moreover, it is able to both originate calls to a Media Server, as well as handle incoming calls from it. You can find below a description of each function the media_exchange provides, as well as the scenarios they should be used for.
media_exchange_from_uri
This function can be used to originate a call to a Media Server in order to play music on hold to the paused participant. You can engage this function on a re-INVITE that puts one of the call’s participants on hold. The function requires an URI to originate the call to. An example of usage can be found in the following snippet:
if (has_totag() && is_method("INVITE")) {
# catch the on-hold re-invite
if(is_audio_on_hold()) {
if (media_exchange_from_uri("sip:moh@media.server.ip"))
exit;
} else {
# call has resumed - terminate any ongoing media played
media_terminate();
}
}
Notice that if the function exists with success, the INVITE should not be relayed to the other participant, as the module will take care of relaying all the messages.
media_exchange_to_call
This function should be used when a Media Server originates a call towards OpenSIPS (triggered by external means) to make a media announcement. This function requires a callid of the call to push the announcement to, as well as the leg, caller or callee to push it to. A snippet for this scenario can be something like this:
if (!has_totag() && is_method("INVITE")) {
# determine the Call-ID to push the announcement to
# determine the leg to push the announcement to
if (!media_exchange_to_call($var(callid), $var(leg)))
send_reply(406, "Not Acceptable");
exit;
}
Notice the exit triggered after the function is called – this indicates that the INVITE is not proxied further, but “consumed” by the B2B engine. All further handling will be done by the media_exchange module.
media_fork_to_uri
Similar to the media_exchange_from_uri() function, this function can originate a call to a Media Server and fork all the RTP to it. This can be useful when doing call recording on a separate server, similar to SIPREC. To use this function, all you need to do is call it using the URI of the recording extension. Note that you can either fork the media of only one leg of the call, as well as both legs, as long as the Media Server is able to accept two media streams (one according to each participant) and mix them together afterwards.
media_fork_from_call
Using this function you can start listening an ongoing call by simply using a third SIP client. All you have to do is to send a new call to OpenSIPS, indicating the Call-ID of the call you want to listen to. All you have to do is to catch this call in an OpenSIPS route and engage the media forking, similar to the following snippet:
if (!has_totag() && is_method("INVITE") && $rU == "listen") {
# determine the Call-ID of the call to listen
if (!media_fork_from_call($var(callid)))
send_reply(406, "Not Acceptable");
exit;
}
Related script functions
Besides the functions described above, there are several other functions used to aim the interaction with the ongoing exchange or forking sessions:
- media_fork_pause – used to pause an ongoing forking session – using this function does not terminate the forking call to Media Server, but simply puts it on hold, regardless the state of the original call
- media_fork_resume – used to resume a paused forking session
- media_handle_indialog – used to handle indialog requests generated by the proxied call; an example of such handing is when a call is put on hold by a participant that is being played an announcement
- media_terminate – terminate an ongoing session to Media Server, either forking or exchanging
MI commands
The module provides Management Interface commands flavors for originating calls from exterior for both media forking and media exchange mode. These commands are called media_fork_from_call_to_uri, respectively media_exchange_from_call_to_uri. There is also an MI command that can be used to terminate a session, named media_terminate.
Conclusions
As described throughout this article, the new Media Exchange module in OpenSIPS 3.1 provides all the means to enhance proxied calls with complex media capabilities, by simply managing SDP bodies.
We believe this module opens lots of new perspectives in terms of proxied calls and enhanced media services, and we would love to hear any new use cases you see. So feel free to share with us any use case we might have missed during the development of this module.
In the meantime, make sure to stay safe! We are looking forward to seeing you again in the next OpenSIPS Summit, whenever that will be :).
can the call recording part record video as well as audio?
LikeLike
Sure, RTPProxy can fork both streams, audio and video, it is up to the recording server to fetch them and dump them in a file.
LikeLike