FreeSWITCH Monitoring – ClueCon 2016

Had a good time at ClueCon again.

ClueCon 2016

For anyone interested in systems monitoring in general and how to apply it to FreeSWITCH in particular, here is my presentation:

Posted in sangoma | Leave a comment

FreeSWITCH Internals Notes

At Sangoma we use FreeSWITCH as a communications development platform. I decided to write some notes and guide lines on the FreeSWITCH internal architecture so our developers can use the FreeSWITCH framework effectively. I decided to publish them here as well so they’re useful to others developing modules or core enhancements for FreeSWITCH.

Core

The FreeSWITCH core is contained in the src/*.c files, everything that you see there is considered “core”. The FreeSWITCH core provides common services and protocols that are re-used among many different call control or media protocols. For example, the core provides several useful API abstractions:

  • OS abstraction based on top of the APR project (Apache Portable Runtime). There is a thin layer of abstraction (src/switch_apr.c) that prevents introducing a direct dependency between the rest of the system and the APR library. This means the rest of the system *DOES NOT* use APR directly, they use the API exposed in src/switch_apr.c for operating system abstraction primitives to create sockets, threads, manage memory etc.
  • RTP stack (src/switch_rtp.c) and an API to create rtp streams, read/write to them etc. This provides access to RTP as RTP is used by many other signaling protocols such as SIP, H.323, Megaco etc, so it makes sense to have it in the core.
  • Call switching (src/switch_ivr.c, src/switch_ivr_originate.c) API routines to create a new call (session) towards a destination without explicitly knowing the low-level protocol details. A module can therefore use switch_ivr_originate() API to place a call in SIP, H.323, SS7, PRI etc, using the same consistent API provided by the core.
  • Media playing API (src/switch_ivr_play_say.c, src/switch_ivr_say.c) that allows you to play a file, insert tones etc etc on a given session (regardless of the signaling protocol)
  • Session and channel management (src/switch_core_session.c, src/switch_channel.c) that allows to perform call control operations (answer a channel, hangup a channel) and low-level I/O operations (write a frame of media, read a frame of media) on sessions (regardless of the underlying signaling and media protocols).

fs_architecture
(Image taken from the FreeSWITCH wiki long ago, can’t recall the URL anymore)

Sessions and Channels

The core abstraction for a call leg is the switch_core_session_t opaque structure. This contains all the necessary information for a given call leg. The session contains a channel. The channel is simply a lower-level representation of the call leg that contains information about the underlying protocols and data structures used to interface with that call leg (ie, contains function pointers to functions that allow the call to be answered, hangup, provide media etc) and the state of the session.

Sessions in FreeSWITCH live in their own thread. A typical call involves 2 sessions (the inbound session and then an outbound session, both of them “bridged”). Each session lives in its own thread, looping through a finite state machine (the session channel states go from CS_INIT, last state is CS_DESTROY, there are other states such as CS_ROUTING, CS_EXCHANGE_MEDIA etc etc. These states determine what the session is doing, each of the state handlers to perform the operation (ie, hangup) is executed in the session thread. It is possible however that other threads want to send a message to indicate something, or read/write information about a session in it. In order to do this in a safe way, there are several APIs that can be used to get a locked pointer to a session that allows you to peek into the session data safely without fearing the session thread will terminate and destroy the session while you’re looking at it or doing something with it from another thread, the main core function for this is:

switch_core_session_t *switch_core_session_locate(const char *uuid);

Every session has a UUID (universal identifier) that is unique across computers and across time (at least for practical purposes). You can use that UUID to ask the core to find a session in the system with that UUID. The core will attempt to find the session (in an internal hash table) and if it’s found, it will lock it and return it to you. You can then use the session to retrieve data, set data or perform operations on it or in its underlying switch_channel_t (which is obtained through switch_core_session_get_channel()) without fear of the session thread to destroy the session (for example if someone sets the state to CS_DESTROY). You must remember to unlock the session when done, and you should do that fast enough (not more than a few milliseconds) otherwise you’re blocking other threads from accessing that session if they need to do something with it. Unlock the session with:

switch_core_session_rwunlock();

This function unlocks the session and this releases it so other threads can use it (including destroy it).

Be aware that there are other core functions that return a session locked, such as switch_core_session_get_partner(). It is your responsibility to verify if the function you are using returns a locked session and then use switch_core_session_rwunlock() to unlock it when done.
Modules

FreeSWITCH is highly modular. The FreeSWITCH engine/core source code is contained in the src/ directory. The plugins or modules source code are contained in the src/module/ directory (the only exception is mod_freetdm, which is contained at libs/freetdm/mod_freetdm, there are some legacy reasons why this was done this way, but there is talks in the FreeSWITCH open source community about moving it to the right place in src/mod/endpoints/ folder).

There are different types of modules/plugins (in the future, I’ll refer to them simply as modules). There are endpoints, formats, loggers, event handlers, dialplans, TTS engines etc etc. Pretty much every directory under src/mod/ is a type of module. Each type of module registers an “interface” with the FreeSWITCH core. Great care has been taken to make proper abstractions and do not expose “module-specific” data into the FreeSWITCH core (src/*.c) files. The modules make use of FreeSWITCH core API primitives to request core services, the FreeSWITCH core uses the abstract interface exposed by different type of modules for performing operations. For example, the module mod_sofia is an endpoint module. Therefore mod_sofia code is contained at src/mod/endpoints/mod_sofia/

FreeTDM

The FreeTDM library is a modular API that allows applications to initialize different types of TDM/Analog signaling stacks, place/receive calls and read/write media. It supports signaling modules for SS7, ISDN(PRI/BRI), Analog, MFCR2 etc. It also supports a I/O modules to support multiple different hardware manufacturers. The 2 most prominent I/O modules are src/ftmod/ftdm_wanpipe/ftmod_wanpipe.c (For Sangoma Wanpipe cards) and the src/ftmod/ftmod_zt/ftmod_zt.c (For DAHDI-enabled cards such as Sangoma and Digium).

The FreeTDM project is part of the same source tree as FreeSWITCH, however FreeTDM does not depend on FreeSWITCH. FreeSWITCH also does not depend on FreeTDM, the glue that links them together is mod_freetdm, which is an endpoint module for FreeSWITCH that allows FreeSWITCH to place calls in SS7, PRI, MFC-R2 and Analog telephony networks. Note that the mod_freetdm module is just a plugin/extension to FreeSWITCH and it is a “user” of the freetdm library. As such, you should never expose internal opaque details of freetdm to mod_freetdm or worst, to FreeSWITCH. The freetdm.h header is the main public header that is used by freetdm API users. There are other headers under a private/ folder in freetdm that are not meant to be used by the API users, only for internal use of other freetdm C files/components.

Memory Allocation

When allocating memory within FreeSWITCH you must ask yourself where to allocate from. FreeSWITCH uses APR memory pools (wrapped on the switch_memory_pool_t) data structure. You can request a completely new memory pool for yosuelf, but that may be a waste, instead ask yourself whether the memory you’re allocating will be associated to a particular session (call leg) and whether needs to persist. For example, memory for a data structure to keep track of RTCP statistics of an RTP stream, will always be associated to the RTP stream, which in turn is associated to the session. In such cases it is recommended to use the session memory pool, which is automatically destroyed at the end of the call.

In the other hand, if the memory you are allocating must persist beyond the call life cycle, you will be better off requesting a new memory pool and then allocating from it, but now you’re responsible to destroy the pool when you’re done with your object life cycle. Remember it is not possible to free memory allocated from a pool until you destroy the whole pool completely.

Some functions to remember (from src/include/switch_core.h and src/switch_core_memory.c):

switch_core_session_get_pool() – Returns the memory pool associated with a given session
switch_core_session_alloc() – Allocate x amount of bytes from a given session memory pool
switch_core_session_sprintf() – Allocates a new string with the provided format using the session memory pool
switch_core_session_strdup() – Duplicates a new string using the session memory pool
switch_core_new_memory_pool() – Creates a new pool ready to start allocating objects
switch_core_destroy_memory_pool() – Destroy the given pool, you better be sure no one will be needing any of the objects allocated from that pool
switch_core_alloc() – Allocate memory from a given memory pool
switch_safe_free() – Free memory allocated directly using malloc()/calloc(), testing for NULL pointer
For all the session-related allocation functions, you must be sure the allocated object will NOT outlive the session.

Remember all switch allocation functions already initialize memory, you do not need to call memset() after allocation

There are a few cases where it’s justifiable to use standard memory allocation functions such as strdup()

strdup() is ok when you need a quick duplicate of another string but you have no session pointer or it’s something called often and short-lived, and therefore you do not want to use the session pointer with switch_core_session_strdup() because that would leave the memory allocated until the end of the call

String Manipulation

switch_copy_string() – Safely copy a string, use this instead of strcpy() or strncpy(). It will guarantee the output is null-terminated.
switch_set_tring() – Use this to initialize a string buffer of a fixed length. DO NOT USE THIS with char* pointers as the implementation uses sizeof() and sizeof(char*) is only 4 or 8!!
switch_toupper() – Convert a string to uppercase
switch_strstr() – Find a string in a substr
switch_safe_atoi() – Turn a string into a number, testing for NULL and defaulting to a given value in case of NULL
More gems can be found in src/include/switch_utils.h, please check there before hand-coding your own function or check if you can use one from switch_utils.h instead of using direct libc functions!!

Booleans

switch_true() – Use this to test if a string is true (ie, “true”, “enabled”, “on”, etc, all are considered true), this is useful when parsing configuration files
switch_false() – Use this to test if a string is false (ie “false”, “disabled” etc), this is useful when parsing configuration files
SWITCH_TRUE / SWITCH_FALSE – Use this along with switch_bool_t instead of using integers

Posted in C/C++, freeswitch, voip | Leave a comment

ClueCon 2015

ClueCon 2015

ClueCon 2015

I just got back from attending ClueCon 2015 in Chicago. This year the FreeSWITCH team presented their video conferencing support in version 1.6. Pretty neat stuff!

This year my presentation was about “Scaling FreeSWITCH Performance”. One of the highlights is that using an alternative memory allocator may (or may not) improve drastically the performance of your FreeSWITCH instance.

Posted in freeswitch, sangoma | Leave a comment

Sending email with python without an MTA

I always found puzzling that to send simple notification emails all examples I could find on the web required a valid account on an MTA and hard-coding your credentials in the script or some other dependencies that seemed a bit non-straight forward to me.

This is an alternative method that sends directly an email without intermediaries. First, you’ll need to install the dnspython package:

pip install dnspython

Now, this is the script that takes care of sending email:

#!/usr/bin/env python2.7
 
import sys
import smtplib
import dns.resolver
 
answers = dns.resolver.query('dest-server.com', 'MX')
if len(answers) <= 0:
    sys.stderr.write('No mail servers found for destination\n')
    sys.exit(1)
 
# Just pick the first answer
server = str(answers[0].exchange)
 
# Add the From: and To: headers
fromaddr = 'source-email@whatever.com'
toaddr = 'destination@dest-server.com'
body = 'some email body'
msg = "From: {}\r\nTo: {}\r\n\r\n{}".format(fromaddr, toaddr, body)
 
server = smtplib.SMTP(server)
server.set_debuglevel(1)
server.sendmail(fromaddr, toaddr, msg)
server.quit()

This script resolves the mail server DNS record for the given destination (you could use a parameter instead of hard-coding it if you want to make it more generic). Once it finds out the mail server it directly tries to contact the server and send the email there using the usual basic SMTP commands (ehlo, mail FROM:, rcpt TO: etc). No need for intermediaries for such simple cases 🙂

There are surely a bunch of more complicated scenarios this script does not handle, but, it fits nicely when you need to send emails to your sysadmin account from cron jobs on random servers in your infrastructure.

Posted in python-dev | 3 Comments

GDB strcmp in a core dump

I tried finding an answer on google about how to do a strcmp operation in a core dump and could not find any solution. The answers available focused on using “call” to call the libc strcmp() function on a live process. Most interesting debugging for me happens on core dumps, so I decided to write my own gdb user defined command (sort of like a macro):

define gdb_strcmp
        dont-repeat
        set $result = 1 
        set $_i = 0 
        if ($arg0[0] == 0x0 && $arg1[0] != 0x0)
                set $result = 0 
        end 
        if ($arg0[0] != 0x0 && $arg1[0] == 0x0)
                set $result = 0 
        end 
        while ($result == 1 && $arg0[$_i] != 0x0 && $arg1[$_i] != 0x0)
                if ($arg0[$_i] != $arg1[$_i])
                        set $result = 0 
                end 
                set $_i = $_i + 1 
        end 
end
document gdb_strcmp
Determines if two C strings match
end

Note that gdb user commands are annoying because you don’t really have return values (they are not really functions/macros), so you have to set a global variable (yuck!) to hold the result. This macro sets $result to 0 if the strings are not equal and $1 if they are. I contemplated using the same return value than the C counterpart, but since I was interested in just a ‘yes or no’ answer I sticked to use 1 for equal and 0 for non equal.

You can then go ahead and use this macro in other macros to do useful things, such as scan a linked list and verify if a given member has certain string value.

PD. I know it’d be cleaner to start using Python for these things but I have not really looked yet into that

Posted in C/C++ | 3 Comments

GitHub Rejects Multiple-Authors Commits

UPDATE: GitHub replied to my inquiry (that was fast!). It appears the FreeSWITCH repository has some corrupted commits. The command “git fsck” indicates an error as well with a couple of commits with multiple authors. GitHub seems to be performing (rightly so) verification on push.

I am a fan of GitHub and that made it even more shocking for me when I found out that it seems GitHub has problems accepting git commits with multiple authors in it.

Have a look at this commit from the FreeSWITCH repository:  https://stash.freeswitch.org/projects/FS/repos/freeswitch/commits/487128950df6ee433c131b5feaafe81ee86629f4

The commit looks pretty harmless in itself, but using git cat-file or git show you can see that there are 2 authors:

moy@sigchld test_clone (test_clone) 
$ git cat-file -p 487128950df6ee433c131b5feaafe81ee86629f4
tree 070633dfc3ea352dfb1094822f477111e519a9ca
parent cde20f6fe68523d9416d2fed72435a8ba880a269
author Travis Cross  1395382322 +0000
author Anthony Minessale  1394747953 +0500
committer Travis Cross  1395665690 +0000

Use the system version of APR / APR-util if possible

Autodetect whether the system libapr / libaprutil has our
necessary modifications and use it if it does.

And surprisingly, GitHub barfs when pushing a branch that contains that commit:

moy@sigchld test_clone-2.0.2 (test_branch) 
$ git push moy test_branch
Counting objects: 14905, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (3345/3345), done.
remote: error: object 487128950df6ee433c131b5feaafe81ee86629f4:invalid format - expected 'committer' line
remote: fatal: Error in object
error: pack-objects died of signal 13
error: failed to push some refs to 'git@github.com:moises-silva/freeswitch.git'

Every other git server I’ve tried (gitlab, gitolite, stash) accepts the commit. It would seem GitHub has some sort of hook that is not expecting two author lines one after the other and it’s expecting a “committer” instead right after the first author.

I’ve sent a support note to GitHub, hopefully they’ll fix this one.

Posted in git | 2 Comments

Astricon – WebRTC in Asterisk

astricon10

 

Astricon 10 just finished. It was nice to be back after missing it for the last 2 years.  This time I shared my experiences with the Asterisk WebRTC implementation.

Find the presentation here: https://moythreads.com/congresos/astricon2013/

Also available on SlideShare: https://www.slideshare.net/MoisesSilva6/implementation-lessons-using-webrtc

 

One of the highlights of the presentation is that if you’re trying to use Asterisk for WebRTC using secure WebSockets (TLS) you may notice that the connection is not reliable (may not work, hangs, etc). This is now a known problem and I’ve posted some patches/branches that address that issue, follow the activity in the Asterisk bug tracker: https://issues.asterisk.org/jira/browse/ASTERISK-21930

Starting with Asterisk 12 you also need to install the pjproject stack to use WebRTC at all, otherwise, no errors are printed on calls but simply you may end up without audio (due to lack of ICE support if pjproject libraries are not instlalled/compiled and linked to Asterisk)

I’ve udpated the Asterisk wiki WebRTC instructions to add this very same warning.

https://wiki.asterisk.org/wiki/display/AST/Installing+pjproject

 

Posted in asterisk, sangoma, voip, webrtc | 1 Comment

FreeSWITCH as a Kickass SBC

I had forgotten to post about ClueCon 2012, and here we are in 2013, another ClueCon went by!

As every year, I attended in August 2012  and August 2013 to this telephony developer conference  in Chicago (organized by the FreeSWITCH developers).

 

In 2012 I presented about using FreeSWITCH as an SBC (Session Border Controller)

Find the presentation here: http://www.moythreads.com/congresos/cluecon2012/

You can also view it in SlideShare: http://www.slideshare.net/MoisesSilva6/cluecon-2012kickasssbc

 

In 2013 I presented about SIP Testing

Find the presentation here: http://www.moythreads.com/congresos/cluecon2013/

You can also view it in SlideShare: http://www.slideshare.net/MoisesSilva6/sip-testing-with-freeswi

 

Posted in freeswitch, voip | Leave a comment

Sangoma Tapping Solution for FreeSWITCH

About 4 years ago I wrote a post about Sangoma Tapping with Asterisk. Many people has been interested in that and I’ve done a few implementations with it.

Having said that, still showed some stability issues and it became a burden to maintain because it is a patch to Asterisk.

Something you may find interesting is that a bit later after I wrote the tapping feature for Asterisk, I also did it for FreeSWITCH 🙂

It has been more stable in FreeSWITCH, mostly due to the fact that FreeSWITCH TDM abstraction is modular and it has been much more easy to maintain a tapping module rather than a patch. You can find the module in FreeSWITCH’s tree at libs/freetdm/src/ftmod/ftmod_pritap/ftmod_pritap.c

In addition to the TDM tapping module, I also wrote an RTP tapping module called mod_oreka that can be used for tapping any media stream on FreeSWITCH (SIP, TDM, H.323 etc)

See press release from OrecX

 

Posted in C/C++, freeswitch, sangoma, voip | Leave a comment

Wanpipemon Cookies: Echo Canceller Tricks

When you buy a Sangoma card you can buy it with or without hardware echo canceller. In most cases it is recommended to get the echo canceller as audio quality is something you don’t want to compromise on. Having said that, when developing or troubleshooting audio problems is often desirable to switch on/off the echo canceller to see the effects (perhaps, the echo canceller is being very aggressive and disrupting non-voice signals, such as DTMF).

Now, this post is not strictly speaking only about wanpipemon, in fact, most of the commands shown in this posts are executed using the companion tool “wan_ec_client”. It is important to note that “wan_ec_client” is a lower level tool than wanpipemon in the sense that it is meant to interact “directly” with the echo canceller.

The echo canceller can be set into 3 states:

* Powered Off

* Powered On – Normal Mode

* Powered On – Speech Recognition Mode

Powered Off means the actual hardware EC chip will be set in power off mode and therefore won’t be processing any audio at all.

Powered On is the normal status of the echo canceller if your wanpipe configuration contains the setting “HWEC_OPERATION_MODE   = OCT_NORMAL” (this is the default when using wancfg_dahdi or wancfg_fs to configure your environment).

This is how you can check the status of the echo canceller:

# wan_ec_client wanpipe1 stats

This should display the status of the echo canceller in all channels in span 1 (w1g1).

root@sigchld ~
# wan_ec_client wanpipe1 stats
 
wanpipe1: Running Get stats command to Echo Canceller device...	Done!
 
****** Echo Canceller Chip Get Stats wanpipe1 ******
  wanpipe1: Number of channels currently open			31
  wanpipe1: Number of conference bridges currently open		0
  wanpipe1: Number of playout buffers currently loaded		0
  wanpipe1: Number of framing error on H.100 bus		0
  wanpipe1: Number of errors on H.100 clock CT_C8_A		0
  wanpipe1: Number of errors on H.100 frame CT_FRAME_A		0
  wanpipe1: Number of errors on H.100 clock CT_C8_B		0
  wanpipe1: Number of internal read timeout errors		0
  wanpipe1: Number of SDRAM refresh too late errors		0
  wanpipe1: Number of PLL jitter errors				0
  wanpipe1: Number of HW tone event buffer has overflowed	0
  wanpipe1: Number of SW tone event buffer has overflowed	0
  wanpipe1: Number of SW Playout event buffer has overflowed	0

 

If you want statistics for a particular channel you can execute the ‘stats_full’ version

root@sigchld ~
# wan_ec_client wanpipe1 stats_full 1
 
wanpipe1: Running Get stats command to Echo Canceller device...	Done!
 
  wanpipe1: 1: Echo Channel Operation Mode			: POWER DOWN
  wanpipe1: 1: Enable Tone Disabler					: TRUE
  wanpipe1: 1: Mute Ports					: NONE
  wanpipe1: 1: Enable Extended Tone Detection				: FALSE
  wanpipe1: 1: Current Echo Return Loss				: Invalid
  wanpipe1: 1: Current Echo Return Loss Enhancement		: Invalid
  wanpipe1: 1: Maximum value of the ERL				: Invalid
  wanpipe1: 1: Maximum value of the ERLE			: Invalid
  wanpipe1: 1: Number of Echo Path changes			: 0
  wanpipe1: 1: Current Echo Delay				: Invalid
  wanpipe1: 1: Maximum Echo Delay				: Invalid
  wanpipe1: 1: Tone Disabler Status				: Enabled
  wanpipe1: 1: Voice activity is detected on SIN port		: TRUE
  wanpipe1: 1: Echo canceller has detected and converged	: TRUE
  wanpipe1: 1: Average power of signal level on RIN		: -69 dBm0
  wanpipe1: 1: Average power of signal level on SIN		: -207 dBm0
  wanpipe1: 1: Current gain applied to signal level on RIN	: 0 dB
  wanpipe1: 1: Current gain applied to signal level on SOUT	: 0 dB
  wanpipe1: 1: Average power of the comfort noise injected	: -207 dBm0
  wanpipe1: 1: (TDM) PCM Law type on SIN			: ALAW
  wanpipe1: 1: (TDM) TDM timeslot on SIN port			: 0
  wanpipe1: 1: (TDM) TDM stream on SIN port			: 6
  wanpipe1: 1: (TDM) PCM Law type on RIN			: ALAW
  wanpipe1: 1: (TDM) TDM timeslot on RIN port			: 0
  wanpipe1: 1: (TDM) TDM stream on RIN port			: 4
  wanpipe1: 1: (TDM) PCM Law type on SOUT			: ALAW
  wanpipe1: 1: (TDM) TDM timeslot on SOUT port			: 0
  wanpipe1: 1: (TDM) TDM stream on SOUT port			: 7
  wanpipe1: 1: (TDM) PCM Law type on ROUT			: ALAW
  wanpipe1: 1: (TDM) TDM timeslot on ROUT port			: 0
  wanpipe1: 1: (TDM) TDM stream on ROUT port			: 5
  wanpipe1: 1: (VQE) NLP status					: TRUE
  wanpipe1: 1: (VQE) Enable Tail Displacement			: FALSE
  wanpipe1: 1: (VQE) Offset of the Echo Cancellation window (ms)	: 0
  wanpipe1: 1: (VQE) Maximum tail length			: 128 ms
  wanpipe1: 1: (VQE) Rin Level control mode			: TRUE
  wanpipe1: 1: (VQE) Rin Control Signal gain			: 0 dB
  wanpipe1: 1: (VQE) Sout Level control mode			: TRUE
  wanpipe1: 1: (VQE) Sout Control Signal gain			: 0 dB
  wanpipe1: 1: (VQE) RIN Automatic Level Control		: FALSE
  wanpipe1: 1: (VQE) RIN Target Level Control			: -20 dBm0
  wanpipe1: 1: (VQE) SOUT Automatic Level Control		: FALSE
  wanpipe1: 1: (VQE) SOUT Target Level Control			: -20 dBm0
  wanpipe1: 1: (VQE) Comfort noise mode				: NORMAL
  wanpipe1: 1: (VQE) Remove any DTMF tone detection on SIN port	: FALSE
  wanpipe1: 1: (VQE) Acoustic Echo				: FALSE
  wanpipe1: 1: (VQE) Non Linearity Behavior A			: 1
  wanpipe1: 1: (VQE) Non Linearity Behavior B			: 0
  wanpipe1: 1: (VQE) Double Talk algorithm			: NORMAL
  wanpipe1: 1: (VQE) Default ERL (not converged)		: -6 dB
  wanpipe1: 1: (VQE) Acoustic Echo Cancellation default ERL	: 0 dB
  wanpipe1: 1: (VQE) Maximum Acoustic Echo tail length		: 128 ms
  wanpipe1: 1: (VQE) Attenuation Level applied to the noise signal	: -18 dB
  wanpipe1: 1: (VQE) Silence period before the re-activation of VQE features	: 1836 ms
  wanpipe1: 1: (CODEC) Encoder channel port			: SOUT
  wanpipe1: 1: (CODEC) Encoder rate				: G.711 64 kBps
  wanpipe1: 1: (CODEC) Decoder channel port			: RIN
  wanpipe1: 1: (CODEC) Decoder rate				: G.711 64 kBps

You can completely shut down the EC operation on a given channel (you most likely don’t want to do this unless you know what you’re doing)

wan_ec_client wanpipe1 mpd 1

This puts the channel 1 echo canceller in “power down” mode (mpd as in ‘Mode Power Down’)

As you guessed probably already, the other modes are ‘mn’ for  and ‘msr ‘ for ‘Mode Normal’ and ‘Mode Speech Recognition’ respectively.

wan_ec_client wanpipe1 mn 1
wan_ec_client wanpipe1 msr 1

Instead of disabling the echo canceller you can enable/disable the bypass functionality. Confusingly, “bypass enable” means that audio goes through the echo canceller, whereas “bypass disable” means audio skips the echo canceller path (but the EC is still turned on). This is due to historical reasons and due to giving low-level programmers too much freedom naming commands 🙂

The bypass commands are actually working at the FPGA level. When the bypass is enabled, the FPGA bridges the audio through the echo canceller first before sending it to the driver. When the bypass is disabled the audio is not bridged through the echo canceller. Simple hu?

root@sigchld ~
# wan_ec_client wanpipe1 bd all
wanpipe1: Running Disable bypass command to Echo Canceller device...    Done!

You can verify with wanpipemon that the EC is “disabled” (bypass disabled).

root@sigchld ~
# wanpipemon -i w1g1 -c ehw
Sangoma HW Echo Canceller is disabled for all channels!

Now enable the bypass back.

root@sigchld ~
# wan_ec_client wanpipe1 be all
wanpipe1: Running Enable bypass command to Echo Canceller device...     Done!
root@sigchld ~
# wanpipemon -i w1g1 -c ehw
 
Sangoma HW Echo Canceller is enabled for channel 0
Sangoma HW Echo Canceller is enabled for channel 1
Sangoma HW Echo Canceller is enabled for channel 2
Sangoma HW Echo Canceller is enabled for channel 3
Sangoma HW Echo Canceller is enabled for channel 4
Sangoma HW Echo Canceller is enabled for channel 5
Sangoma HW Echo Canceller is enabled for channel 6
Sangoma HW Echo Canceller is enabled for channel 7
Sangoma HW Echo Canceller is enabled for channel 8
Sangoma HW Echo Canceller is enabled for channel 9
Sangoma HW Echo Canceller is enabled for channel 10
Sangoma HW Echo Canceller is enabled for channel 11
Sangoma HW Echo Canceller is enabled for channel 12
Sangoma HW Echo Canceller is enabled for channel 13
Sangoma HW Echo Canceller is enabled for channel 14
Sangoma HW Echo Canceller is enabled for channel 15
Sangoma HW Echo Canceller is enabled for channel 16
Sangoma HW Echo Canceller is enabled for channel 17
Sangoma HW Echo Canceller is enabled for channel 18
Sangoma HW Echo Canceller is enabled for channel 19
Sangoma HW Echo Canceller is enabled for channel 20
Sangoma HW Echo Canceller is enabled for channel 21
Sangoma HW Echo Canceller is enabled for channel 22
Sangoma HW Echo Canceller is enabled for channel 23
Sangoma HW Echo Canceller is enabled for channel 24
Sangoma HW Echo Canceller is enabled for channel 25
Sangoma HW Echo Canceller is enabled for channel 26
Sangoma HW Echo Canceller is enabled for channel 27
Sangoma HW Echo Canceller is enabled for channel 28
Sangoma HW Echo Canceller is enabled for channel 29
Sangoma HW Echo Canceller is enabled for channel 30
Sangoma HW Echo Canceller is enabled for channel 31

That’s it for today folks, next time you want to debug echo issues, noise on the lines, distortion etc, it’s a good idea to rule out the echo canceller using the commands described in this post.

Posted in sangoma, wanpipemon | Leave a comment