Sangoma Tapping Solution for Asterisk

Sangoma has offered a tapping device for T1/E1 lines for quite some time now. This physical tapping works by installing a PN 633 Tap Connection Adapter, which looks like this:

Sangoma Tapping

As you can see, you will receive the line from the CPE and plug it into the PN 633 and then plug the line from the NET too. At the other side of the adapter you can pull out 2 cables and connect them to your box with Sangoma boards specially configured in high impedance mode, which basically means will be passive and not affect the behavior of your PRI link, passively will be monitoring the E1/T1 link.

As you can tell from the image, there is also 2 cables involved for a single link, this means that you need an A102 card to monitor just 1 E1/T1 link, because one port is used for tx from the CPE and the other for tx from the NET. Until today, it was not possible to use Asterisk because Asterisk assumes each card port is meant to send and receive data for a circuit, Asterisk was meant to be an active component of the circuit, not a passive element.

Now Asterisk can do that. I just submitted 2 patches to Digium’s bug tracker. One for LibPRI, the library that takes care of the Q921 and Q931 signaling and the other for chan_dahdi.c, the Asterisk channel driver used to connect it to PSTN circuits.

LibPRI needed to be modified because it does a lot of state machine checking when receiving a Q921/Q931 frame, for example, if receives a Q931 message “PROCEEDING”, is going to check that a call was already in place and a SETUP message was previously sent, when working as a passive element in the circuit no state checks should be done, we just need to decode the message and return a meaningful telephony event to Asterisk (like a RING event when the SETUP message is seen on the line).

https://issues.asterisk.org/view.php?id=15970

The most important change is this:

pri_event *pri_read_event(struct pri *pri)
{
        char buf[1024];
        int res;
        res = pri->read_func ? pri->read_func(pri, buf, sizeof(buf)) : 0;
        /* this check should be at some routine in q921.c */
        /* at least 4 bytes of Q921 and at check buf[4] for Q931 Network packet */
        if (res < 5 || ((int)buf[4] != 8)) {
                return NULL;
        }
        res = q931_read_event(pri, (q931_h*)(buf + 4), res - 4 - 2 /* remove 4 bytes of Q921 h and 2 of CRC */);
        if (res == -1) {
                return NULL;
        }
        if (res & Q931_RES_HAVEEVENT) {
                return &pri->ev;
        }
        return NULL;
}
 
/* here we trust receiving q931 only (no maintenance or anything else)*/
int q931_read_event(struct pri *ctrl, q931_h *h, int len)
{
        q931_mh *mh;
        q931_call *c;
        int cref;
        int missingmand;
 
        //q931_dump(ctrl, h, len, 0);
 
        mh = (q931_mh *)(h->contents + h->crlen);
 
        cref = q931_cr(h);
 
        c = q931_getcall(ctrl, cref & 0x7FFF);
        if (!c) {
                pri_error(ctrl, "Unable to locate call %d\n", cref);
                return -1;
        }
 
        if (prepare_to_handle_q931_message(ctrl, mh, c)) {
                return 0;
        }
 
        missingmand = 0;
        if (q931_process_ies(ctrl, h, len, mh, c, &missingmand)) {
                return -1;
        }
 
        return post_handle_q931_message(ctrl, mh, c, missingmand, 0);
}

The rest is pretty much just modify post_handle_q931_message to skip state machine checking when invoked with the last parameter as 0, which is only done from q931_read_event, that is the passive q931 processing routine I added.

Asterisk needed to be modified because it needs to correlate that a RING event received, let’s say in span 1 and channel 1, is probably going to be related to a PROGRESS message in span 2 channel 1 (which is the other side of the connection replying to the SETUP Q931 message). Furthermore, once the PROGRESS message is received, Asterisk must launch a regular channel and then create a DAHDI conference (using DAHDI pseudo channels) to mix the audio transmitted by the CPE and NET and return this mixed audio as a single frame to any Asterisk application reading from the channel.

https://issues.asterisk.org/view.php?id=15971

Some interesting code snippet of the changes to Asterisk is where I create the DAHDI conference to do the audio mixing, which is later retrieved by the core via the channel driver interface interface dahdi_read().

This is done during dahdi_new() routine, when creating the new Asterisk channel.

        if (i->tappingpeer) {
                struct dahdi_confinfo dahdic = { 0, };
                /* create the mixing conference
                 * some DAHDI_SETCONF interface rules to keep in mind
                 * confno == -1 means create new conference with the given confmode
                 * confno and confmode == 0 means remove the channel from its conference */
                dahdic.chan = 0; /* means use current channel (the one the fd belongs to)*/
                dahdic.confno = -1; /* -1 means create new conference */
                dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER | DAHDI_CONF_PSEUDO_LISTENER;
                fd = dahdi_open("/dev/dahdi/pseudo");
                if (fd < 0 || ioctl(fd, DAHDI_SETCONF, &dahdic)) {
                        ast_log(LOG_ERROR, "Unable to create dahdi conference for tapping\n");
                        ast_hangup(tmp);
                        i->owner = NULL;
                        return NULL;
                }
                i->tappingconf = dahdic.confno;
                i->tappingfd = fd;
 
                /* add both parties to the conference */
                dahdic.chan = 0;
                dahdic.confno = i->tappingconf;
                dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
                if (ioctl(i->subs[SUB_REAL].dfd, DAHDI_SETCONF, &dahdic)) {
                        ast_log(LOG_ERROR, "Unable to add chan to conference for tapping devices: %s\n", strerror(errno));
                        ast_hangup(tmp);
                        i->owner = NULL;
                        return NULL;
                }
                dahdic.chan = 0;
                dahdic.confno = i->tappingconf;
                dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
                if (ioctl(i->tappingpeer->subs[SUB_REAL].dfd, DAHDI_SETCONF, &dahdic)) {
                        ast_log(LOG_ERROR, "Unable to add peer chan to conference for tapping devices: %s\n", strerror(errno));
                        ast_hangup(tmp);
                        i->owner = NULL;
                        return NULL;
                }
                ast_log(LOG_DEBUG, "Created tapping conference %d with fd %d between dahdi chans %d and %d for ast channel %s\n",
                                i->tappingconf,
                                i->tappingfd,
                                i->channel,
                                i->tappingpeer->channel,
                                tmp->name);
                i->tappingpeer->owner = i->owner;
       }

Later we sent the Asterisk channel to the dial plan.

                /* from now on, reading from the conference has the mix of both tapped channels, we can now launch the pbx thread */
                if (ast_pbx_start(c) != AST_PBX_SUCCESS) {
                        ast_log(LOG_ERROR, "Failed to launch PBX thread for passive channel %s\n", c->name);
                        ast_hangup(c);
                }
                break;

And finally when the Asterisk core requests a frame from chan_dahdi we return the mixed audio.

       /* if we have a tap peer we must read the mixed audio */
        if (p->tappingpeer) {
                /* passive channel reading */
                /* first read from the 2 involved dahdi channels just to consume their frames */
                res = read(p->subs[idx].dfd, readbuf, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
                CHECK_READ_RESULT(res);
                res = read(p->tappingpeer->subs[idx].dfd, readbuf, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
                CHECK_READ_RESULT(res);
                /* now read the mixed audio that will be returned to the core */
                res = read(p->tappingfd, readbuf, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
        } else {
                /* no tapping peer, normal reading */
                res = read(p->subs[idx].dfd, readbuf, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
        }

Finally, you can use regular dial plan Asterisk rules to Record() the conversation, Dial() to someone interested in auditing the call etc. Of course, any audio transmitted to this passive channel will be dropped, therefore using applications like Playback() in this channels just don’t make sense, you can still do it though, but all the audio will be silently dropped. Also remember this is a regular channel (that just happens to ignore any transmitted media or signaling), therefore you can still retrieve the ANI, DNID etc.

[from-pstn]
exten => s,1,Answer()
;exten => s,n,Dial(SIP/moy)
exten => s,n,Record(advanced-recording%d:wav)
exten => s,n,Hangup()
exten => _X.,1,Goto(s,1)

The configuration required is minimal. Sangoma board configuration is described here. It’s not much different than configuring a regular T1/E1 link though. In the Asterisk side, you just have to specify the parameter “tappingpeerpos=next” or “tappingpeerpos=prev” in chan_dahdi.conf to specify which is the peer tapping span for the current span. If you set “tappingpeerpos=no” or any other value for that matter, tapping will be disabled for that span (and then will be a regular active span).

I have the code already in 3 branches. One branch for libpri and 2 branches for Asterisk, one based on trunk and the other in Asterisk 1.6.2, keep in mind that the one from 1.6.2 has a slightly different configuration at this point, the parameter to enable tapping is “passive=yes”, this does not let you specify if the peer tapping device is the next or previous one, therefore assumes your tapping spans always start at an even number (0, 2, 4 etc), I will change that soon, hopefully …

http://svn.digium.com/svn/asterisk/team/moy/dahdi-tap-trunk
http://svn.digium.com/svn/asterisk/team/moy/dahdi-tap-1.6.2
http://svn.digium.com/svn/libpri/team/moy/tap-1.4

Now everytime a new call is detected you will receive a call that you can send wherever you want 🙂

Enjoy!

This entry was posted in asterisk, sangoma. Bookmark the permalink.

40 Responses to Sangoma Tapping Solution for Asterisk

  1. aatif says:

    Nice guide, Can you please let me know an alternative solution of cards other than sangoma, which are best?

  2. prakashkumar says:

    Hi Moises Silva,

    I have configured PRI passive call recording using asterisk 1.6.2 tapping with sangoma A102D card.

    the problem is, whenever hearing some of the asterisk recorded inbound calls audio the called (agent) party voice have silent. However, the Caller (customer) party voice can hear clearly.

    After analysis the asterisk log, I have found the issue in only calls have recorded in Dadhi channel 1 (DADHI/1-1) and remaining channel calls were good. As per sangoma tech team instruction, I have captured audio from DADHI/1-1 channel using “dahdi_monitor 1 -r output_rx.raw -t output_tx.raw” command. As my observation, i can hear the called party (agent) voice in output_rx.wav audio but i can not hear same called party voice in asterisk recorded audio.

    Please give me solution

  3. moy says:

    SS7 tapping is not supported, it would involve some significant work to make it work, but is doable. Drop me a line if you’re interested.

    I have a pure-signaling SS7 solution here: https://github.com/moises-silva/sng_ss7mon

  4. Gogu Melcu says:

    In order to do passive monitoring of ss7 lines is needed a proper patch of chan_dahdi and libss7 in the dahdi tap version 1.6.2?
    Can you tell me some hints regarding a ss7 tapping solution using asterisk?

    Thanks.

  5. Pingback: Sangoma Tapping Solution for FreeSWITCH « Moy Blog

  6. Dersen says:

    Hi Moy, do you know something about my cores ????

    • moy says:

      Not really.

      I am not maintaining anymore this solution on Asterisk. You should try FreeSWITCH, the solution for tapping there is cleaner because it does not require patching, which is easier to maintain for me.

      I will be making a blog post about this later on.

  7. Ansuman says:

    I cant see the call activity ….how could i able to get the call activity gary?…hey moy i am waiting for you kind help…
    Thanx in advence

  8. Gary says:

    Same here Ansuman. I can’t get the dial plan to execute as a result of a call. I can see the call activity via debug though

  9. Ansuman says:

    hey moy! i have installed dahdi complete 2.6 ,tap 1.4,dahdi-tap-1.6.2 .and wanpipe-3.5.28
    and followed your instructions line by line.
    i don’t get log of incoming and outgoing calls…
    kindly help me out
    Thanx in advance.

  10. Moy says:

    I haven’t heard before about core dumps with the latest tapping branch.

    You may want to use pastebin.com to paste a backtrace, see this: https://wiki.asterisk.org/wiki/display/AST/Getting+a+Backtrace

    I may be able to take a look.

  11. Dersen says:

    Hi Moy, I install your tapping solution based on 1.6.2, it runs ok, i can record anything ( more than 1700 calls per day : ), but I have more than 4 asterisk cores per day, and I can’t identify the problem, do you know something about stability problems with big numbers of records?

    Thank you.

  12. Dan Tucker says:

    Thank you. Have it up and recording! Works great.

  13. Moy says:

    Passive monitoring only receives incoming calls, no trunk groups are used.

    Dialplan is simple, just call Answer() and Record() or any application to do recording.

  14. Dan Tucker says:

    Do you have any examples of the trunk group setup and dial plan you could provide?

  15. moy says:

    I’m glad to know you’re using this solution with success.

    Cheers,

  16. Mauro Sollar says:

    I’m using a a102e without echo cancellers and is working perfectly, congratulations Moises, their branches of libpri and asterisk for passive mode was very useful for me, is a very interesting and I intend to use in a call center in the company where I work.

  17. Moises Silva says:

    That is correct, no need for EC.

    A102 without EC is good.

    pinouts can be found at http://wiki.sangoma.com/Cablepinouts

  18. tomcat says:

    Hi,
    I’m going to try this excellent solution. Where could I find pinouts for tapping device. And another question: which type of 102 card is preferable?
    Is it enough to use card without echo cancellation? I suppose EC is not an issue in tapping?

  19. moy says:

    Hello, I offer consultancy services. You can reach me at moises.silva in the email service of the biggest search engine. I am a bit short of time these days, but ping me and may be we can arrange something.

  20. AG says:

    Can I hire you to do my installation?

    I still have the issue with call quality, could we have a talk or exchange email addresses?

  21. Moises Silva says:

    Well, they hired me to do the installations myself so indeed I know exactly which version are they using.

    wanpipe-3.5.10 with latest firmware on each card ( as of now v37 ).

  22. AG says:

    Do you know which version of the Sangoma drivers they are using?

  23. Moises Silva says:

    I have a couple of guys doing recording with excellent quality, so I believe this is a problem specific with your setup but I cannot think of what the problem is with the information you provided. At this point you should probably contact sangoma support.

  24. AG says:

    Yes im using an A102, ive been playing with the gains in chan_dahdi – they reduce the volume of the audio, but do not reduce the distortion.

    I have put a recording online –
    http://www.adrive.com/public/be951b249e51a10b69f5b40578023e5ef2dc76f81944246ead80d0aa4eed7a77.html

    Let me know what you think, thanks

  25. Moises Silva says:

    are you using Sangoma cards at all?

    Have you tried tweaking the gains in chan_dahdi.conf?

    I’d need a sample recording to make any further assessment.

  26. AG says:

    Hi, I am having a problem with static on call recordings on the passive link. Its as if the gain is turned up really high somewhere and is distorting the audio. I tried installing regular asterisk on the same hardware and made test calls over ISDN, the call quality was clear. It is when using this passive setup that the recordings are distorted. DO you have any ideas as to what it could be? Thanks

  27. AG says:

    The change appears to be working. You are a superstar! Thanks for your help

  28. Moises Silva says:

    The problem is I only monitor speech calls ( capability 0x0 ), but some of your calls are capability 3.1Khz audio (0x10). I believe that is mostly used for modem calls?

    In anycase, I committed a change to the 1.6.2 branch that adds capabilities for 3.1Khz and 7khz audio, which may or may not work, I don’t have lines to receive that types of calls to test 🙂

  29. AG says:

    http://pastebin.org/149131

    I have tried with both versions and get the same issue. I am currently using 1.6.2. You can see in the logs “Not monitoring call with unsupported capability 16” – this happens only to the calls not getting recorded.

    I believe the recording issue is due to overuns, I am talking to sangoma about this at the moment. Thanks

  30. Moises Silva says:

    Which version of the code are you using 1.6.2 or trunk branches?

    Pastebin a sample log of the no owner found.

  31. AG says:

    Hi, I have implemented this version of asterisk but am having 2 problems. Firstly, the call recordings get made ok, but they are distorted and unlistenable. Secondly, not 100% of calls are getting recorded, some calls (from mobile/cell phones) are getting a “no owner found” error so do not get recorded. I have logs i could send, any help would be much appreciated. Thanks

  32. Moises Silva says:

    I don’t know. Digium drivers do not support the “high impedance mode”, however they may still work, but in short I don’t know anyone who has tried to use Digium with this solution, all the customers I have with this running have Sangoma boards.

  33. jamm says:

    hello:
    it is a good idea for that. I want to know that does this solution support Digium PRI cards?
    regards!
    jamm

  34. Phani says:

    Hi I configured the same. I have my DialPlan just as above . I dont want to forward any calls. I want to just record them. Is this possible if i just remove the Answer and Hangup in the dialplan ?

    Regards
    Phan

  35. Moises Silva says:

    Hi Flavio,

    The answer is “sort of”. Everything is compatible, but the openr2 stack (or any other R2 stack that I know of for that matter) currently lacks the code to work in “passive mode”. As I explained in the post, I had to modify libpri stack to make it work in passive mode, the modifications were posted to Digium’s bug tracker in order to have them merged soon. For openr2 similar modifications would be required to add “passive mode” option to the stack.

    Evandro from http://www2.ezvoice.com.br/ told me they were interested in having this solution for R2 lines too, however I need some funding to spend time working on this, if you are interested in sponsoring this development for openr2, send me an e-mail, may be you could join with Evandro to split the sponsoring.

  36. Is this solution compatible with OpenR2?

  37. Moises Silva says:

    I sent you an e-mail.

  38. Eddie says:

    i am looking for this solution to be configured remotely.

    please let me know if you can do this

Leave a Reply

Your email address will not be published. Required fields are marked *

*