SIPREC Module
     __________________________________________________________

   Table of Contents

   1. Admin Guide

        1.1. Overview
        1.2. How it works
        1.3. Media Handling
        1.4. SRS Failover
        1.5. Limitations
        1.6. Dependencies

              1.6.1. OpenSIPS Modules
              1.6.2. External Libraries or Applications

        1.7. Exported Parameters

              1.7.1. skip_failover_codes (string)

        1.8. Exported Events

              1.8.1. E_SIPREC_START
              1.8.2. E_SIPREC_STOP

        1.9. Exported Functions

              1.9.1. siprec_start_recording(srs[, instance])
              1.9.2. siprec_pause_recording([instance])
              1.9.3. siprec_resume_recording([instance])
              1.9.4. siprec_stop_recording([instance])
              1.9.5. siprec_send_indialog([hdrs[, body]])

        1.10. Exported Pseudo-Variables

              1.10.1. $siprec

   2. Contributors

        2.1. By Commit Statistics
        2.2. By Commit Activity

   3. Documentation

        3.1. Contributors

   List of Tables

   2.1. Top contributors by DevScore^(1), authored commits^(2) and
          lines added/removed^(3)

   2.2. Most recently active contributors^(1) to this module

   List of Examples

   1.1. Set skip_failover_codes parameter
   1.2. Use siprec_start_recording() function with a single SRS
   1.3. Use siprec_start_recording() function with multiple SRS
          servers

   1.4. Use siprec_start_recording() function with custom XML
          values for participants

   1.5. Use siprec_start_recording() function with custom headers
   1.6. Use siprec_start_recording() function with custom group
          and session extensions

   1.7. Use siprec_pause_recording()
   1.8. Use siprec_resume_recording()
   1.9. Use siprec_stop_recording()
   1.10. Use siprec_send_indialog()

Chapter 1. Admin Guide

1.1. Overview

   This module provides the means to do calls recording using an
   external recorder - the entity that records the call is not in
   the media path between the caller and callee, but it is
   completely separate, thus it can not affect by any means the
   quality of the conversation. This is done in a standardized
   manner, using the SIPREC Protocol, thus it can be used by any
   recorder that implements this protocol.

   Since an external server is used to record calls, there are no
   constraints regarding the location of the recorder, thus it can
   be placed arbitrary. This offers huge flexibility to your
   architecture configuration and various means for scaling.

   The work for this module has been sponsored by the OrecX
   Company. This module is fully integrated with the OrecX Call
   Recording products.

1.2. How it works

   The full architecture of a SIP Media Recording platform is
   documented in RFC 7245. According to this architecture, this
   OpenSIPS module implements a SRC (Session Recording Client)
   that instructs a SRS (Session Recording Server) when new calls
   are started, the participants of the calls and their profiles.
   Based on this data, the SRS can decide whether the call should
   be recorded or not.

   From SIP signalling perspective, the module does not change the
   call flow between the caller and callee. The call is
   established just as any other calls that are not recorded. But
   for each call that has SIPREC engaged, a completely separate
   SIP session is started by the SRC (OpenSIPS) towards the SRS,
   using the OpenSIPS Back-2-Back module. The INVITE message sent
   to the SRS contains a multi-part body consisting of two parts:
     * Recording SDP - the SDP of the Media Server that will fork
       the RTP to the recorder.
     * Participants Metadata - an XML-formatted document that
       contains information about the participants. The structure
       of the document is detailed in RFC 7865.

   The SRS can respond with negative reply, indicating that the
   session does not need to be recorded, or with a positive reply
   (200 OK), indicating in the SDP body where the media RTP should
   be sent/forked. When the call ends, the SRC must send a BYE
   message to the SRS, indicating that the recording should be
   completed.

   Full examples of call flows can be found in RFC 8068.

1.3. Media Handling

   Since OpenSIPS is a SIP Proxy, it does not have any Media
   Capabilities by itself. Thus we need to rely on a different
   Media Server to capture the RTP traffic and fork it to the SRS.
   The current implementation supports both the RTPProxy (through
   the RTPProxy module) and RTPEngine (through the RTEngine
   module) Media Servers.

1.4. SRS Failover

   The siprec module supports failover between multiple SRS
   servers - when calling the siprec_start_recording() function,
   one can provision multiple SRS URIs, separated by comma. In
   this case, OpenSIPS will try to use them in the same order
   specified, one by one, until either one of them responds with a
   positive reply (200 OK), or the response code is one of the
   codes matched by the skip_failover_codes regular expression. In
   the latter case the call is not recorded at all.

1.5. Limitations

   This module only implements the SRC specifications of the
   SIPREC RFC. In order to have a full recording solution, you
   will also need a SRS solution such as Oreka - an open-source
   project provided by OrecX.

   Although this module provides all the necessary tools to do
   calls recording, it does not fully implement the entire SIPREC
   SRC specifications. This list contains some of the module's
   limitations:
     * There is no Recording Indicator played to the callee -
       since OpenSIPS continues to act as a proxy, there is no way
       for us to postpone the media between the caller and callee
       to play a Recording Indicator message.
     * Cannot handle Recording Sessions initiated by SRS - we do
       not support the scenario when an SRS suddenly decides to
       record a call in the middle of the dialog.
     * OpenSIPS cannot be “queried” for ongoing recording sessions
       - this is scheduled to be implemented in further releases.

1.6. Dependencies

1.6.1. OpenSIPS Modules

   The following modules must be loaded before this module:
     * TM - Transaction module.
     * Dialog - Dialog module for keeping track of the call.
     * RTP_Relay - RTP Relay module used for controlling the Media
       Servers that will fork the media.
     * B2B_ENTITIES - Back-2-Back module used for communicating
       with the SRS.

1.6.2. External Libraries or Applications

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

1.7. Exported Parameters

1.7.1. skip_failover_codes (string)

   A regular expression used to specify the codes that should
   prevent the module from failing over to a new SRS server.

   By default any negative reply generates a failover.

   Example 1.1. Set skip_failover_codes parameter
...
# do not failover on 408 reply codes
modparam("siprec", "skip_failover_codes", "408")

# do not failover on 408 or 487 reply codes
modparam("siprec", "skip_failover_codes", "408|487")

# do not failover on any 3xx or 4xx reply code
modparam("siprec", "skip_failover_codes", "[34][0-9][0-9]")
...

1.8. Exported Events

1.8.1.  E_SIPREC_START

   This event is raised when a SIPREC call is established and a
   call starts to be recorded.

   Parameters:
     * dlg_id - dialog id (“did”) of the call being recorded;
     * dlg_callid - Call-Id of the call being recorded;
     * callid - Call-Id (B2B id) of the SIPREC call;
     * session_id - SIPREC UUID of the recording call;
     * server - the SIPREC server handing this call;
     * instance - the SIPREC instance this event is triggered for;

1.8.2.  E_SIPREC_STOP

   This event is raised when a SIPREC call is terminated.

   This event exposes the same parameters as the E_SIPREC_START
   event.

1.9. Exported Functions

1.9.1.  siprec_start_recording(srs[, instance])

   Calling this function on an initial INVITE engages call
   recording to SRS(s) for that call. Note that it does not
   necessary mean that the call will be recorded - it just means
   that OpenSIPS will query instruct the SRS that a new call has
   started, but the SRS might decide that the recording is
   disabled for those participants.

   Note that the call recording is not started right away, but
   only when the callee provides an SDP as well (usually in a 200
   OK, or possibly a 183 Ringing).

   Note if you only want to start recording when the call is
   established (200 OK is received), then you should call this
   function in the onreply route processing that 200 OK.

   Parameters:
     * srs (string) - a comma-separated list of SRS URIs. These
       URIs are used in the order specified. See
       siprec_srs_failover for more information.
     * instance (string, optional) - used to start a particular
       SIPREC instance. When missing, the default instance is
       started.

   The function returns false when an internal error is triggered
   and the call recording setup fails. Otherwise, if all the
   internal mechanisms are activated, it returns true.

   This function can be used from REQUEST_ROUTE.

   Example 1.2. Use siprec_start_recording() function with a
   single SRS
        ...
        if (!has_totag() && is_method("INVITE")) {
                $var(srs) = "sip:127.0.0.1";
                xlog("Engage SIPREC call recording to $var(srs) for $ci\
n");
                siprec_start_recording($var(srs));
        }
        ...

   Example 1.3. Use siprec_start_recording() function with
   multiple SRS servers
        ...
        if (!has_totag() && is_method("INVITE")) {
                $var(srs) = "sip:127.0.0.1, sip:127.0.0.1;transport=TCP"
;
                xlog("Engage SIPREC call recording to servers $var(srs)
for $ci in inbound group\n");
                siprec_start_recording($var(srs), "inbound");
        }
        ...

   Example 1.4. Use siprec_start_recording() function with custom
   XML values for participants
        ...
        $xml(caller_xml) = "<nameID></nameID>";
        $xml(caller_xml/nameID.attr/aor) = "sip:6024151234@10.0.0.11:509
0";
        $xml(caller_xml/nameID) = "<name>test</name>";
        $siprec(caller) = $xml(caller_xml/nameID);
        siprec_start_recording($var(srs));
        ...

   Example 1.5. Use siprec_start_recording() function with custom
   headers
        ...
        $siprec(headers) = "X-MY-CUSTOM_HDR: 1\r\n";
        siprec_start_recording($var(srs));
        ...

   Example 1.6. Use siprec_start_recording() function with custom
   group and session extensions
        ...
        $var(temp) = "<callcenterID> 17</callcenterID>";
        $siprec(group_custom_extension) = $var(temp);
        $siprec(session_custom_extension) = "<callcenterCode>dfgh3q45gsd
fty5</callcenterCode>";

        siprec_start_recording($var(srs));
        ...

1.9.2.  siprec_pause_recording([instance])

   Pauses the recording for the ongoing call. Should be called
   after the dialog has matched.

   Parameters:
     * instance (string, optional) - used to pause a particular
       SIPREC instance. When missing, the default instance is
       paused.

   This function can be used from any route.

   Example 1.7. Use siprec_pause_recording()
        ...
        if (has_totag() && is_method("INVITE")) {
                if (is_audio_on_hold())
                        siprec_pause_recording();
        }
        ...

1.9.3.  siprec_resume_recording([instance])

   Resumes the recording for the ongoing call. Should be called
   after the dialog has matched.

   Parameters:
     * instance (string, optional) - used to resume a particular
       SIPREC instance. When missing, the default instance is
       resumed.

   This function can be used from any route.

   Example 1.8. Use siprec_resume_recording()
        ...
        if (has_totag() && is_method("INVITE")) {
                if (!is_audio_on_hold())
                        siprec_resume_recording();
        }
        ...

1.9.4.  siprec_stop_recording([instance])

   Stops the recording for the ongoing call. Should be called for
   SIPREC sessions that have been previously started.

   Parameters:
     * instance (string, optional) - used to stop a particular
       SIPREC instance. When missing, the default instance is
       stopped.

   This function can be used from any route.

   Example 1.9. Use siprec_stop_recording()
        ...
        if (has_totag() && is_method("INVITE")) {
                if (is_audio_on_hold())
                        siprec_stop_recording();
        }
        ...

1.9.5.  siprec_send_indialog([hdrs[, body]])

   Sends an arbitrary in-dialog request to the SRS.

   This function can be used from any route.

   Parameters:
     * headers (string, optional) - a set of headers that will be
       added to the generated request.
     * body (string, optional) - the body that will be added to
       the generated request.
     * instance (string, optional) - used to send a request within
       a particular SIPREC instance. When missing, the request is
       sent in to the default instance.

   Example 1.10. Use siprec_send_indialog()
        ...
        if (has_totag() && is_method("INFO")) {
                siprec_send_indialog("Content-Type: $hdr(Content-Type)\r
\n", $rb);
        }
        ...

1.10. Exported Pseudo-Variables

1.10.1. $siprec

   Used to modify/describe different siprec sessions parameters
   that should be taken into account by the
   siprec_start_recording() function.

   The variable can be indexed with the instance the user wants to
   tune the variable for. If missing, the the default instance is
   being altered.

   The context of this variable is only limited to the current
   message processed - it is not available at the transaction or
   dialog level.

   Any of this setting is optional.

   Settings that can be provisioned:
     * group - an opaque value that will be inserted in the SIPREC
       body and represents the name of the group that can be used
       to classify calls in certain profiles. If missing, no group
       is added.
     * caller - an XML block containing information about the
       caller. If absent, the From header of the initial dialog is
       used to build the value.
     * callee - an XML block containing information about the
       callee. If absent, the To header of the initial dialog is
       used to build the value.
     * media - the IP that RTPProxy will be streaming media from.
       If absent 127.0.0.1 will be used. NOTE:media_ip has been
       dropped.
     * headers - extra headers that are to be added in the initial
       request towards the SRS. NOTE: headers must be separated by
       \r\n and must end with \r\n.
     * socket - listening socket that the outgoing request towards
       SRS should be used.
     * from_uri - the URI to appear in the From header of the
       dialog. Default value is the request URI. Note that this
       does not influence the caller information in the XML block,
       which is taken from the initial dialog.
     * to_uri - the URI to appear in the To header of the dialog.
       Default value is the request URI. Note that this does not
       influence the callee information in the XML block, which is
       taken from the initial dialog.
     * group_custom_extension - an optional XML block containing
       custom information to be added under the group tag. NOTE:
       if the group is absent this value will be ignored and not
       used anywhere.
     * session_custom_extension - an optional XML block containing
       custom information to be added under the session tag.

Chapter 2. Contributors

2.1. By Commit Statistics

   Table 2.1. Top contributors by DevScore^(1), authored
   commits^(2) and lines added/removed^(3)
     Name DevScore Commits Lines ++ Lines --
   1. Razvan Crainea (@razvancrainea) 188 97 6361 2212
   2. Vlad Patrascu (@rvlad-patrascu) 16 11 166 149
   3. Liviu Chircu (@liviuchircu) 9 7 35 53
   4. Maksym Sobolyev (@sobomax) 6 4 12 11
   5. Seyed Mehran Siadati 5 2 124 15
   6. Bogdan-Andrei Iancu (@bogdan-iancu) 4 2 3 2
   7. Norman Brandinger (@NormB) 3 1 4 4

   (1) DevScore = author_commits + author_lines_added /
   (project_lines_added / project_commits) + author_lines_deleted
   / (project_lines_deleted / project_commits)

   (2) including any documentation-related commits, excluding
   merge commits. Regarding imported patches/code, we do our best
   to count the work on behalf of the proper owner, as per the
   "fix_authors" and "mod_renames" arrays in
   opensips/doc/build-contrib.sh. If you identify any
   patches/commits which do not get properly attributed to you,
   please submit a pull request which extends "fix_authors" and/or
   "mod_renames".

   (3) ignoring whitespace edits, renamed files and auto-generated
   files

2.2. By Commit Activity

   Table 2.2. Most recently active contributors^(1) to this module
                     Name                   Commit Activity
   1. Razvan Crainea (@razvancrainea)     Jun 2017 - Jun 2025
   2. Maksym Sobolyev (@sobomax)          Feb 2023 - Nov 2023
   3. Seyed Mehran Siadati                Nov 2023 - Nov 2023
   4. Liviu Chircu (@liviuchircu)         Apr 2018 - Aug 2023
   5. Vlad Patrascu (@rvlad-patrascu)     Feb 2018 - Mar 2023
   6. Norman Brandinger (@NormB)          Aug 2021 - Aug 2021
   7. Bogdan-Andrei Iancu (@bogdan-iancu) Apr 2019 - Apr 2021

   (1) including any documentation-related commits, excluding
   merge commits

Chapter 3. Documentation

3.1. Contributors

   Last edited by: Razvan Crainea (@razvancrainea), Seyed Mehran
   Siadati, Norman Brandinger (@NormB), Vlad Patrascu
   (@rvlad-patrascu), Liviu Chircu (@liviuchircu).

   Documentation Copyrights:

   Copyright © 2017 www.opensips-solutions.com
