Login | Register

Documentation

Documentation -> Tutorials -> Voice Transcoding in OpenSIPS using Sangoma D-series Cards

This page has been visited 10863 times.

Voice Transcoding in OpenSIPS using Sangoma D-series Cards

Author: Liviu Chircu <liviu@opensips.org>


1.  Tutorial Overview

This tutorial illustrates the required steps in order to perform audio transcoding with the D-series cards manufactured by Sangoma, using the sngtc_server daemon and the OpenSIPS sngtc module as its client. The latest version of the transcoding library, as of 1 August 2013 is: sng-tc-linux-1.3.4.1


As mentioned in the module documentation, transcoding may only be done if the UAC performs early SDP negotiation and the UAS supports late SDP negotiation.


2.  Installing the transcoding card

The necessary firmware for the D-series transcoding cards can be set up using the sngtc_tool. The cards which require PCI connectivity (D100 and D500) also need additional kernel drivers. Please refer to the Sangoma wiki for installation tutorials.


3.  Setting up the sngtc_server

Installing the sngtc_server is straightforward and also documented in the Sangoma wiki. After doing the configuration, it can be started using the init script:

   $ /etc/init.d/sngtc_server_ctrl start

By default it logs to /var/log/sngtc_server.log


4.  Call flow with the sngtc OpenSIPS module

Due to the limitations of the transcoding library, transcoding sessions can only be created if both codec A and codec B are known. Since this cannot be accomplished with a standard SIP call flow, the module restricts the receiving UA to perform late SDP negotiation. The diagram below explains this better:


5.  Using the sngtc module

The sngtc module exports 3 functions. They are called upon receiving INVITE, 200 OK and ACK messages. A short overview on their purpose would be:

  1. sngtc_offer - called at any INVITE request (re-INVITES too), deletes the INVITE SDP body
  2. sngtc_callee_answer - called at 200 OK responses, intersects codec offers, creates transcoding sessions if necessary
  3. sngtc_caller_answer - called at ACK requests, adds an SDP body to the ACK request

All functions properly handle retransmissions. More details can be found in the module documentation. A basic configuration file is shown below:


####### Global Parameters #########

debug=6
log_stderror=yes
log_facility=LOG_LOCAL0

fork=yes
children=6

memdump=1

auto_aliases=no

listen=udp:eth1:5060

disable_tcp=yes

disable_tls=no

exec_msg_threshold=200000

####### Modules ########

mpath = "modules/"

loadmodule "exec.so"
loadmodule "signaling.so"
loadmodule "sl.so"
loadmodule "tm.so"
loadmodule "rr.so"
loadmodule "maxfwd.so"
loadmodule "sipmsgops.so"
loadmodule "mi_fifo.so"
loadmodule "db_mysql.so"
loadmodule "uri.so"
loadmodule "dialog.so"
loadmodule "usrloc.so"
loadmodule "registrar.so"
loadmodule "sngtc.so"

modparam("tm", "fr_timer", 5)
modparam("tm", "fr_inv_timer", 30)
modparam("tm", "restart_fr_on_each_reply", 0)
modparam("tm", "disable_6xx_block", 1)
modparam("tm", "onreply_avp_mode", 1)

modparam("rr", "append_fromtag", 0)

modparam("mi_fifo", "fifo_name", "/tmp/opensips_fifo")

modparam("uri", "use_uri_table", 0)

modparam("dialog", "db_mode", 0)
modparam("dialog", "default_timeout", 3600)

modparam("usrloc", "db_mode",   1)
modparam("usrloc", "db_url",    "mysql://root:sangoma@localhost/opensips")

####### Routing Logic ########

route {

    if (!mf_process_maxfwd_header("10")) {
        sl_send_reply("483","Too Many Hops");
        exit;
    }

    force_rport();

    if (has_totag()) {
        # sequential request withing a dialog should
        # take the path determined by record-routing

        if (loose_route()) {

            if (is_method("BYE")) {
                setsflag(FAIL_TRANS_FLAG);
            } else if (is_method("INVITE")) {
                sngtc_offer();
            } else if (is_method("ACK")) {
                sngtc_caller_answer();
            }

            # route it out to whatever destination was set by loose_route()
            # in $du (destination URI).
            route(1);
        } else {

            if (is_method("ACK")) {
                if (t_check_trans()) {
                    # non loose-route, but stateful ACK; must be an ACK after 
                    # a 487 or e.g. 404 from upstream server
                    t_relay();
                    exit;
                } else {
                    # ACK without matching transaction ->
                    # ignore and discard
                    exit;
                }
            }
            sl_send_reply("404","Not here");
        }
        exit;
    }

    # CANCEL processing
    if (is_method("CANCEL"))
    {
        if (t_check_trans())
            t_relay();
        exit;
    }

    t_check_trans();

    # preloaded route checking
    if (loose_route()) {
        xlog("L_ERR",
        "Attempt to route with preloaded Route's [$fu/$tu/$ru/$ci]");
        if (!is_method("ACK"))
            sl_send_reply("403","Preload Route denied");
        exit;
    }

    # record routing
    if (!is_method("REGISTER|MESSAGE"))
        record_route();

    # requests for my domain
    if (is_method("PUBLISH|SUBSCRIBE"))
    {
        sl_send_reply("503", "Service Unavailable");
        exit;
    }

    if (is_method("REGISTER"))
    {
        if (!save("location"))
            sl_reply_error();

        exit;
    }

    if ($rU == NULL) {
        sl_send_reply("484","Address Incomplete");
        exit;
    }

    # do lookup with method filtering
    if (!lookup("location","m")) {

        t_newtran();
        t_reply("404", "Not Found");
        exit;
    }

    if (is_method("INVITE"))
        sngtc_offer();

    route(1);
}

route[1] {
    # for INVITEs enable some additional helper routes
    if (is_method("INVITE")) {
        t_on_reply("2");
        t_on_failure("1");
    }

    if (!t_relay()) {
        send_reply("500", "Internal Error");
    }

    exit;
}

onreply_route[2] {

    if ($rs == 200)
        sngtc_callee_answer("11.12.13.14", "11.12.13.14");
}

failure_route[1] {

    if (t_was_cancelled()) {
        exit;
    }

    if (next_branches()) {
        t_on_reply("2");
        t_on_failure("1");
        t_relay();
    }
}

The transcoding sessions on the Sangoma cards are closed in a transparent manner, based on dialog callbacks.


Page last modified on May 10, 2017, at 04:40 PM