Login | Register

Documentation

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

This page has been visited 1962 times.


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.


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 August 05, 2013, at 04:57 PM