Documentation |
Documentation -> Tutorials -> Voice Transcoding in OpenSIPS using Sangoma D-series CardsThis page has been visited 11409 times. Voice Transcoding in OpenSIPS using Sangoma D-series CardsAuthor: Liviu Chircu <liviu@opensips.org> Table of Content (hide) 1. Tutorial OverviewThis 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
2. Installing the transcoding cardThe 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_serverInstalling 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 moduleDue 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 moduleThe sngtc module exports 3 functions. They are called upon receiving INVITE, 200 OK and ACK messages. A short overview on their purpose would be:
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. |