Archive for the ‘asterisk’ Category

MFC/R2 branches for Asterisk 1.2 and 1.4

Saturday, July 5th, 2008

I just created 2 branches for MFC/R2 support in chan_zap for Asterisk 1.2 and 1.4, this branches replaced the patches and .tar.gz I previously published, is much easier to keep them up-to-date this way. If you still need the patches you can easily get them using svn diff.

Let’s say you need a patch against Asterisk 1.4.21.1

svn diff  http://svn.digium.com/svn/asterisk/tags/1.4.21.1 \
http://svn.digium.com/svn/asterisk/team/moy/mfcr2-1.4 > asterisk-openr2-1.4.21.1.patch

That will create a patch to transform Asterisk 1.4.21.1 version into an OpenR2-enabled version. However this has other side-effect, changes that may have nothing to do with openr2 can be introduced. I therefore recommend using my branches directly.

OpenR2 back-ported to Asterisk 1.4 and 1.2

Thursday, June 19th, 2008

I just back-ported the support for MFC/R2 signaling using the OpenR2 library to Asterisk 1.4 and 1.2, go and get it while is still hot!

http://www.libopenr2.org/

I also updated the site to use TextMotion, a new web publishing software (aka CMS), works pretty well, kudos to the TextMotion devs.

MFC/R2 branch for Asterisk is available

Wednesday, April 30th, 2008

I just created a branch for Asterisk that has everything required to test the chan_zap MFC/R2 support. Now the installation steps are easier.

1. Install zaptel from 1.4 branch http://svn.digium.com/svn/zaptel/branches/1.4

2. Install openr2 library from the trunk svn://libopenr2.org/openr2/trunk

3. Install Asterisk from the MFC/R2 branch: http://svn.digium.com/svn/asterisk/team/moy/mfcr2

Some people in brazil has now reported success with basic call setup. Configuration info is available at the bugtracker: http://bugs.digium.com/view.php?id=12509

The libopenr2.org site is up, but empty :-( , right now I just have the SVN server, but info will be added soon as well.

Asterisk with MFC/R2 in chan_zap

Friday, April 25th, 2008

I’ve been working lately in a library for the MFC/R2 telephony signalling. I named this library “OpenR2″. My goal is to include support for this signaling in the Asterisk project and eventually in FreeSwitch if possible. I just created a new issue in the bugtracker, that is the first patch I have to give MFC/R2 support in the Asterisk channel driver chan_zap. Hopefully this will eventually be the standard MFC/R2 implementation for Asterisk and finally it will “just work”.

If you are from the many people with R2 issues in Mexico or other country, you should consider to give this thing a try.

The code of the library is LGPL and is available temporarily to download from http://www.moythreads.com/openr2-april21.tar.gz.

I am in the process of getting an SVN account and will post later the link.

Patch for chan_zap: http://www.moythreads.com/chan_zap-mfr2.patch

All you have to do is download Asterisk from this branch: http://svn.digium.com/svn/asterisk/team/markster/mfr2

Then apply the patch. You will also need zaptel from this branch: http://svn.digium.com/svn/zaptel/branches/1.4

After applying the patch, please run ./bootstrap.sh in the Asterisk root directory. Then ./configure –prefix=/usr –with-openr2=/usr

Please report feedback in the bugtracker or contact me via e-mail or IM. My user at gmail it’s quite easy to remember: moises.silva

Zaptel Version

Thursday, April 3rd, 2008

Quick note to myself: to check the version of the loaded zaptel module just cat /sys/module/zaptel/version

Asterisk Asynchronous AGI

Monday, December 24th, 2007

I have been coding some new stuff for Asterisk lately, but the feature I like the most is Asynchronous AGI. I got the idea from MAGI, an old patch written by David Pollak that allowed AGI execution thru the manager interface. For those ignoring what AGI and AMI are, go read:

Asterisk Gateway Interface ( AGI )
Asterisk Manager API ( AMI )

So, my patch, allow users to execute AGI commands using “Action: AGI” and get the response reading “Event: AsyncAGI”. The manager header “CommandID” can be specified to match up the responses. Let’s see an example

In extensions.ael you would put something like this:

context sample-async-agi {
    test => {
        AGI(agi:async);
    };
};

That will put the channel to wait AGI commands. The channel will NOT do anything but wait for Hangup or any AGI command you ask it to execute. AGI commands can arrive from 2 sources. The most important and useful source of commands is the manager, but with my patch you can also execute AGI from the command line. Let’s see how it is done from the manager:

# telnet localhost 5038
Action: Login
Username: test
Secret: test

Action: AGI
Channel: SIP/33-blah
Command: EXEC Playback tt-monkeys
CommandID: MyCommandID

That would cause Asterisk to execute the “Playback” application on channel SIP/33-blah, which MUST be in AGI(agi:async) application. After executing the command you will be able to read an event with the AGI response url-encoded. If the channel is not in Async AGI, the command will not be executed and you will get an error response.

As I said, you can use the command line to execute Async AGI as well, just like this:

tcore*CLI> agi exec SIP/testing-09a5b960 “EXEC startmusiconhold”
tcore*CLI> agi exec SIP/testing-09a5b960 “EXEC stopmusiconhold”
tcore*CLI> agi exec SIP/testing-09a5b960 “EXEC Dial(Agent/23)”

That will start MOH, then stop it, and finally will dial to the Agent 23. This means you can implement a Queue without using native buggy Asterisk queues. You can receive calls and send them to Async AGI to put them on hold, then, when you detect availability of some of your Agents, Dial() to that agent.

If you want to learn more about this feature here is the mantis bug entry: http://bugs.digium.com/view.php?id=11282.

If you want the patch back-ported to 1.4, I have one here: http://www.moythreads.com/asterisk-1.4.15-async-agi.patch

In case you find this patch useful, please try it in trunk as well and provide feedback in mantis. Even when some people has found this patch useful, some of the top developers at asterisk-dev are hesitating in accepting it because similar results can be obtained thru the use of FastAGI, however, me and other people at asterisk-dev are trying to prove the patch also makes easier the implementation of some applications.

This is a hot discussion we got some weeks ago about it: http://lists.digium.com/pipermail/asterisk-dev/2007-December/031046.html

See you!

Asterisk, now with deadlock action!

Tuesday, November 20th, 2007

You gotta belive me, I love Asterisk, I have learned lots of stuff playing with it. However in the last days I have been trying FreeSwitch and reading its code. Yesterday I was hanging out at freeswitch-dev when Anthony posted a link, that I have to admit is so fucking funny!

http://www.sofaswitch.org/eg/pix/mfp_small.jpg

Enjoy,

AppConference Underflow?

Tuesday, October 30th, 2007

Some weeks ago I wrote about a buffer overflow in app_conference Asterisk application when more than 160 samples per frame were received. I showed how the overflow could be fixed using Asterisk smoothers interface. Two days ago I got an e-mail from a guy in Germany ( Tom ), who had a crash in app_conference and found my blog googling about it. I send him the modified version of app_conference with my fix. Even when Asterisk stopped crashing, audio from chan_mISDN channel going to SIP channel was jittering. After adding some debugging messages to app_conference I sent him a new member.c file so he could try it and send me the resulting logs ( I had no access to his server ). The logs showed that chan_mISDN generated frames with multiple amount of samples, is not that odd? The first voice frame on the call had 640 samples encoded with ALAW ( hence 640 bytes ), that first frame was causing Asterisk crash because of the overflow I showed in my other app_conference post. But what was causing the jitter? Well, if more samples than expected can cause an overflow, what does less samples than expected can cause? yes, jitter. app_conference assume 160 samples per frame, because of 20ms RTP packeting being so common and 8000 samples per second being a telephony standard. So, receiving more samples cause overflow, and receiving less of 160 samples cause the mixing of the audio to be incomplete (zeros in the remaining mix buffer), hence, audio with jitter. As I said, chan_misdn generated frames with different amount of samples, however, most of the audio frames (99%) were being received with 120 samples, and a few ones with less than that.

Solution?

I was tempted to make a simple buffering in app_conference to queue an audio frame until enough samples were received to mix the audio, however, a quick non-code fix was achieved by configuring misdn-init.conf to generate 240 samples. That configuration along with the use of Asterisk smoothers worked like a charm :)

I think I will join iax-devel mailing list to discuss this issue with app_conference developers and possibly integrate a final fix for this issues with more/less samples than expected. I saw code in app_conference that was trying to use smoothers, however the last time I checked it was disabled for some reason.

By the way, Tom nicely offered me some German beer for help with that issue.

Thanks Tom!

Asterisk talk at IBM

Saturday, September 29th, 2007

This week took place the Innovation in Software Engineering Latin America Symposium at IBM Guadalajara. I participated with an Asterisk session giving an overview of the Asterisk capabilities with AEL, AGI and AMI. Also I mentioned how it was possible to run Asterisk on an IBM System i Linux LPAR effectively converting the System i in a powerful IP PBX. I plan to give the same talk, but with some adjustments at ENLi the next month.

Rapid VoIP Application Development on Linux

Overflow in AppConference

Sunday, September 2nd, 2007

Some weeks ago I got an offer for a free VoIPSurfer license. Why? just because of a patch I did one year ago for an issue I had, the patch helped the guy who seems to own voipsurfer, so, it is kind of open source Karma. The offering made me remember the interesting issue I had and I thought today it is a good day to write about it. Some background information can be found in this thread where I discussed with some Asterisk developers the issue: http://lists.digium.com/pipermail/asterisk-dev/2006-November/024616.html

Asterisk, as a software PBX, supports conferencing. However, default implementation in 1.2.x versions did not support native audio mixing. Asterisk default conferencing application is “app_meetme” and it works only if you have zaptel hardware available or if zaptel driver zt_dummy.ko is installed, otherwise it cannot work because meetme() use zt_conf functionality. Because of this I started looking for alternatives that did not require zaptel. I found app_conference which at that time was part of the IaxClient project, now it seems to be an independent project.

Anyway, I started doing some testing and kaboom!, Asterisk crashed when one of our IAX2 servers joined the conference. Running valgrind lead me to find code like this:

void mix_slinear_frames( char *dst, const char *src, int samples )
{

        if ( dst == NULL ) return ;

        if ( src == NULL ) return ;

        int i, val ;

        for ( i = 0 ; i < samples ; ++i )
        {

                val = ( (short*)dst )[i] + ( (short*)src )[i] ;

                if ( val > 0x7fff )
                {
                        ( (short*)dst )[i] = 0x7fff - 1 ;
                        continue ;
                }

                else if ( val < -0x7fff )
                {
                        ( (short*)dst )[i] = -0x7fff + 1 ;
                        continue ;
                }

                else
                {
                        ( (short*)dst )[i] = val ;
                        continue ;
                }
        }

        return ;
}

This is a typical function where we’re in buffer overflow danger. It receives 2 buffers as arguments and just 1 len. So better for the caller to be sure that both src and dst have enough data to read/write from/to. I quickly found a call like this:

// allocate a mix buffer which fill large enough memory to
// hold a frame, and reset it’s memory so we don’t get noise
char* cp_listenerBuffer = malloc( AST_CONF_BUFFER_SIZE ) ;

memset( cp_listenerBuffer, 0×0, AST_CONF_BUFFER_SIZE ) ;

// point past the friendly offset right to the data

cp_listenerData = cp_listenerBuffer + AST_FRIENDLY_OFFSET ;

// reset the spoken list pointer
cf_spoken = frames_in ;

// really mix the audio
for ( ; cf_spoken != NULL ; cf_spoken = cf_spoken->next )
{

    //
    // if the members are equal, and they
    // are not null, do not mix them.
    //
    if (
      ( cf_send->member == cf_spoken->member )
       && ( cf_send->member != NULL )
    )
    {

        // don’t mix this frame
    }
    else if ( cf_spoken->fr == NULL )
    {

        ast_log( LOG_WARNING, “unable to mix conf_frame with null ast_framen” ) ;
    }
    else
    {

        // mix the new frame in with the existing buffer
        mix_slinear_frames( cp_listenerData, (char*)( cf_spoken->fr->data ), cf_spoken->fr->samples);
     }
}

So let’s look closely to the call. The first argument passed is cp_listenerData, a pointer to a brand new voice frame where all the mixing of the conference audio sources will be stored. As we can see in the code, the buffer is of a fixed length AST_CONF_BUFFER_SIZE, but since the pointer is advanced AST_FRIENDLY_OFFSET, then the effective length is AST_CONF_BUFFER_SIZE – AST_FRIENDLY_OFFSET. Let’s see some interesting defines:

// 160 samples 16-bit signed linear
#define AST_CONF_BLOCK_SAMPLES 160

// 2 bytes per sample ( i.e. 16-bit )
#define AST_CONF_BYTES_PER_SAMPLE 2

// 320 bytes for each 160 sample frame of 16-bit audio
#define AST_CONF_FRAME_DATA_SIZE 320

// 1000 ms-per-second / 20 ms-per-frame = 50 frames-per-second
#define AST_CONF_FRAMES_PER_SECOND ( 1000 / AST_CONF_FRAME_INTERVAL )

// account for friendly offset when allocating buffer for frame
#define AST_CONF_BUFFER_SIZE ( AST_CONF_FRAME_DATA_SIZE + AST_FRIENDLY_OFFSET )

So AST_CONF_BUFFER_SIZE is 320 + AST_FRIENDLY_OFFSET, since we don’t really care about the asterisk friendly offset since *real* data must start after this offset, we can say our buffer is 320 bytes long. Where this number comes from? Well, some assumptions are made to calculate that number:

1. Telephony most common sampling rate is 8000 samples per second.
2. Audio frames will be 20ms long.
3. Each sample will be encoded using 16 bits ( “slinear” format ).

Given those assumptions we can then calculate: At 8000 samples per second, 20ms audio frame will be made of

( 8000 samples per second * ( 20ms / 1000ms per second) )

that is 160 samples in one 20ms audio frame. Since each of those samples will be encoded with 16 bits, we have a audio frame byte length of:

( 160 samples * 16 bits per sample / 8 bits per byte ), that is 320 bytes, hence #define AST_CONF_FRAME_DATA_SIZE 320

Assumption of 8000 samples per second is an Asterisk requirement, currently Asterisk does not support other sampling rate. 16 bits per sample is assumed because the mixing will be done in slinear format, so this is ok too. However, 20ms audio frames is a *bad* assumption. Some common phones ( Linksys SPA? ) provide an option in their configuration page to change the RTP frame size, and that caused the crash. How many bytes does a 30ms frame has?

( 8000 samples per second * ( 30ms / 1000ms per second) )

that is 240 samples, each one of those samples of 2 bytes ( 16 bits ) give us a frame size of 480 bytes!, far more than the considered 320 bytes, and kaboom! we have a buffer overflow that could lead in the best case to a DoS attack.

Asterisk smoothers to the rescue!

Asterisk smoothers is a way to take variant size frames as input and return frames of single size. So, we can feed the smoother with 480 bytes frames or whichever size we get and the smoother will return us a frame of the size we want ( 320 bytes in this case ).

struct ast_smoother *ast_smoother_new(int size);
int ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap);
struct ast_frame *ast_smoother_read(struct ast_smoother *s);
ast_smoother_free(struct ast_smoother *s);

So, I used this interface to smooth each frame with more samples ( hence size ) than required for the slinear audio mixing. Each time a new frame was read from a conference member I added this verification and partial fix code:

/* create the smoother if were receiving more samples than needed */
if ( AST_CONF_BLOCK_SAMPLES < fr->samples ) {

  if ( member->inSmoother == NULL ) {
    /* calculate bytes per sample */

    ast_log(LOG_DEBUG, “%s frame has %d samples in %d bytesn”, member->channel_name, fr->samples, fr->datalen);

    float bytes_per_sample = ( (float)fr->datalen / (float)fr->samples );

    ast_log(LOG_DEBUG, “%s frame has %f bytes per samplen”, member->channel_name, bytes_per_sample);

    float new_frame_len    = ( AST_CONF_BLOCK_SAMPLES * bytes_per_sample );
    /* WARNING, currently iLBC codec is not fully supported, sound is still choppy */

    if ( fr->subclass == AST_FORMAT_ILBC ) {
      ast_log(LOG_DEBUG, “ILBC format only accepts datalen multiple of 50, so make it happyn”);

      if ( new_frame_len < 50 ) {
        new_frame_len = 50;
      }
    }

    ast_log(LOG_DEBUG, “%s new frame size is %fn”, member->channel_name, new_frame_len);

    member->inSmoother   = ast_smoother_new(new_frame_len);
  }
  ast_smoother_feed(member->inSmoother, fr);

  while ( ( sfr = ast_smoother_read( member->inSmoother ) ) ) {

    conf_frame* cfr = create_conf_frame( member, member->inFrames, sfr ) ;

    if ( cfr == NULL )
    {
      ast_log( LOG_ERROR, “unable to malloc conf_framen” ) ;

      return -1 ;
    }
    add_member_frame(member, cfr);
  }
} else {

  conf_frame* cfr = create_conf_frame( member, member->inFrames, fr ) ;

  add_member_frame(member, cfr);
}

Messy, but hey! it compiled! ship it! ( I don’t remember why in the hell I used float for bytes_per_sample, but im sure I had a good reason?? )

So, what I did was just calculate the proper frame size when more samples than needed were received, so, when converted to slinear, the frame will result in 240 bytes as required by mix_slinear_frame and it will not overflow mixing the audio properly.

Anyway, I still got a problem I did not solve at that time. For some reason iLBC codec only accepted frame sizes multiple of 50, and since slinear mixing required 240 ( not a multiple of 50 ) voice sounded choppy :(

I guess some improvements were made to app_conference since I used it last time, so I will test it with Asterisk 1.4 and let’s see how it goes …

I’ll post results later,