[Asterisk-Dev] Changing Asterisk's module invocation

Juan Jose Comellas juanjo at comellas.com.ar
Thu Sep 16 10:25:52 MST 2004


I would greatly appreciate if you could send me any basic Java code that uses 
this. I may retrofit our current system into something like this if our 
current strategy fails. We plan to be able to stress test our system next 
week and then we'll know if we're on the right track.

BTW, what JVM are you using on Linux? We have tried several and IBM's 1.4 JVM 
has proved to be much stabler than Sun's. We were having one or two crashes a 
month with Sun's JVM (in another project) and since we've changed to IBM's 
(about two months ago) we've had no crashes at all. We're running Debian 
(testing) with the 2.4 kernel.


On Thursday 16 September 2004 13:26, David Pollak wrote:
> Juan Jose,
>
> Ah hah!  Okay, now I understand where you're going.  It makes a ton of
> sense to re-use your Java code.  It's best for the users if they're
> service doesn't change.  It's best for the developers to have continuity
> in the codebase.
>
> The first thing you may want to look into is a module that reads the
> dial plan from a MySQL database.  You can do the updates in the database
> and they're read out when each extension is accessed.  It gives more
> control for dynamically changing dial plans without the performance hit
> of reloading a 50,000 line dial plan.  On the other hand, you lose the
> existing Java code base.  Plus, the Dial Plan is a really sucky language
> and coding in a saner language is good.
>
> I've been using the code changes I sent in a prior posting to integrate
> AGI and Manager API.  It allows you to control a channel and Asterisk
> through a single socket connection.  I've tested throughput and been
> able to send 300,000 commands per second with proper ACK responses (it
> was the 'ping' command).  I have not seen any problems running many
> channels (hundreds) through this hybrid connection.  The key is that I
> have a high priority Java thread reading from the socket and queuing the
> Manager info to be handled by another thread.  Asterisk will drop
> information if the reader doesn't keep the socket clear.  Reading the
> information in is the most important thing you can do.  That way you can
> run your Java code in an application server and still control Asterisk.
>
> If you need some example Java code, please let me know.
>
> Thanks,
>
> David
>
> Juan Jose Comellas wrote:
> >Thanks for all your recommendations. The immediate objective of the
> > project I'm working on is to use Asterisk to replace another product in a
> > telephony server. The previous version was based on Envox and ran on
> > Windows with a DLL that acted as a bridge between Envox and the Java code
> > that implemented most of the functionality for a lot of services (complex
> > conferencing and voicemail and a lot of additional services not found in
> > Asterisk). We want to reuse all the code we can from the previous
> > version, so I'm trying to provide a similar interface to the other system
> > in an Asterisk module.
> >
> >Initially we planned to use normal dialplans, but we have a highly dynamic
> >system, which has thousands of extensions and is updated constantly, and
> >reloading Asterisk's configuration frequently has some problems. In our
> >tests, reloading the dialplan took about 30 seconds and during that time
> > new connections failed. That is completely unacceptable for the service
> > we provide, so we decided to manage our own dialplan and reuse the
> > functionality of the previous version by writing a module that could act
> > as a bridge between Asterisk and the previous software (in Java). That
> > seemed to be the simplest solution because it allowed us to reuse what we
> > already had developed for the previous version.
> >
> >When we first studied Asterisk we thought about using the Manager
> > Interface, but it did not seem stable enough to be able to make thousands
> > of calls all the time. Has this changed recently?
> >
> >On Wednesday 15 September 2004 20:38, David Pollak wrote:
> >>Juan Jose,
> >>
> >>You should only have 1 JVM instance.  You can put a pointer to your JVM
> >>instance in a static (I forgot the C name for statics... sorry) variable
> >>that can be accessed by any caller into your app.
> >>
> >>You do a lookup for the "cookie" (the void * that you proposed in your
> >>suggested change) based on the unique ID of the channel.
> >>
> >>My strong recommendation for destroying the cookie when you destroy the
> >>channel comes from making sure that there's no memory leak in the JVM
> >>(or more specifically, no reference leak.)  The cookie that you're
> >>storing probably corresponds to a Java Object.  That Object is marked as
> >>referred to by an external JNI program (thus it will not be garbage
> >>collected from the JVM.)  Once the channel in Asterisk is destroyed,
> >>you'll have to let the JVM know that the corresponding Java Object (and
> >>its referenced object) can be garbage collected.
> >>
> >>With all that being said, I'd recommend against running a JVM in the
> >>Asterisk process.  First, the JVM is not as stable as Asterisk. (As a
> >>side-note, I'm a huge fan of Java.  I was the first technologist to use
> >>Java in a production system -- WebLogic ran NetGuide Live [the 11th most
> >>trafficked site on the Internet] back in 1996. I wrote the worlds
> >>fastest spreadsheet in Java.  I think Java and the JVM are the best
> >>combination for doing non-realtime systems.  On the other hand, I'm
> >>realistic about Java's weaknesses as well.)  If the JVM goes down (and
> >>JVMs go down in production once or twice a month), the Asterisk process
> >>goes down.  That's bad.  Second, I don't know if the Sun JVM uses the
> >>same thread primitives as Asterisk.  If it doesn't, there'll be lots of
> >>weird memory corruption, etc.  Third, when the JVM does garbage
> >>collection, it halts the current thread (and any other thread that's
> >>doing a memory allocation -- which is all the time in a JVM.)  Asterisk
> >>mixes the media and logic on the same thread.  You *have* to respond to
> >>the media demands every 20ms.  If the JVM is doing garbage collection
> >>that takes more than 20ms, you're going to have bad sound quality.
> >>
> >>With all that being said, why not use an external Java process that
> >>communicates over AGI and/or the Manager API to control the channel?
> >>What kind of application are you writing?
> >>
> >>Thanks,
> >>
> >>David
> >>
> >>Juan Jose Comellas wrote:
> >>>But if I do what you propose, each Java module would be created and
> >>>destroyed when each channel is created and destroyed. I want to have
> >>> Java modules that last as long as C modules do and that are not tied to
> >>> specific channels.
> >>>
> >>>The problem I'm facing is that I need to map the C callback for each
> >>>application to multiple Java classes in order to have only one instance
> >>> of the JVM for all the Java modules. The configuration file would look
> >>> like this:
> >>>
> >>>--- java.conf
> >>>[commands]
> >>>JavaTransfer = org.asterisk.JavaTransferModule
> >>>JavaConference = org.asterisk.JavaConferenceModule
> >>>JavaDirectory = org.asterisk.JavaDirectoryModule
> >>>
> >>>So, whenever the any of the commands is found in the dialplan and
> >>> Asterisk invokes the C callback for my bridge module I would like to
> >>> invoke a method of the corresponding Java class.
> >>>
> >>>The reason for doing it this way is that I want to be able to
> >>> dynamically set the Java applications without having to write different
> >>> C entry points for the different Java Asterisk applications. Do you
> >>> think this is feasible with the current functionality in Asterisk?
> >>>
> >>>BTW, how can I set up some kind of hook to be notified when Asterisk
> >>>creates and destroys a channel?
> >>>
> >>>Thanks for your help.
> >>>
> >>>On Tuesday 14 September 2004 19:34, David Pollak wrote:
> >>>>Juan Jose,
> >>>>
> >>>>You don't need to change Asterisk.  In your glue layer between SWIG and
> >>>>Asterisk, you can determine the unique identifier of the channel. 
> >>>> Based on this unique ID, you can look up the void * data structure in
> >>>> your own store.  Put another way, you manage your own cookies and use
> >>>> the channel's unique ID as the lookup for the cookie.  The only
> >>>> additional bit of work is that you'll have to monitor to see when a
> >>>> channel is destroyed so you can free the cookie entry for the
> >>>> destroyed channel.
> >>>>
> >>>>Depending on exactly what you're using Java for, you might want to take
> >>>>a look at a patch I made (enclosed) to Asterisk.  This patch merges AGI
> >>>>with the Manager API.  It's useful to have a single socket open between
> >>>>a Java app server and Asterisk and control all the Asterisk channels
> >>>>through that socket.
> >>>>
> >>>>If you've got more questions, please feel free to ping me.
> >>>>
> >>>>Thanks,
> >>>>
> >>>>David
> >>>>
> >>>>Juan Jose Comellas wrote:
> >>>>>I am writing Java bindings for the Asterisk API using SWIG
> >>>>>(http://www.swig.org) so that I can create Asterisk modules written in
> >>>>>Java. The main problem I'm having is that in order to make this
> >>>>> process efficient I need to have more than one application per module
> >>>>> (I load only one instance of the JVM). To be able to build a generic
> >>>>> solution (where I don't have to add one entry point in C per Java
> >>>>> application), I need to make a slight change to the
> >>>>> ast_register_application() function and to the code that invokes each
> >>>>> application's callback function. Currently all application callbacks
> >>>>> follow the following prototype:
> >>>>>
> >>>>>int (*execute)(struct ast_channel *, void *data);
> >>>>>
> >>>>>The problem is that when building Java modules this function acts as a
> >>>>>bridge to the Java invocation and I need extra data to be able to map
> >>>>>the call into a Java class/method. To solve this problem I need to
> >>>>> make the following changes to Asterisk's public interface:
> >>>>>
> >>>>>1) Add one argument to the application callback to be able to pass the
> >>>>>"cookie" that will let me map to the Java class/method:
> >>>>>
> >>>>>int (*execute)(struct ast_channel *, void *data, void *cookie);
> >>>>>
> >>>>>2) Change the ast_app struct to be able to store the "cookie". With my
> >>>>>changes it looks like this:
> >>>>>
> >>>>>struct ast_app {
> >>>>>char name[AST_MAX_APP];   /* Name of the application */
> >>>>>int (*execute)(struct ast_channel *chan, void *data, void *cookie);
> >>>>>char *synopsis;    /* Synopsis text for 'show applications' */
> >>>>>char *description;   /* Description (help text) for 'show application
> >>>>><name>' */
> >>>>>void *cookie;    /* Data used to map the call when using Java modules
> >>>>> */ struct ast_app *next;   /* Next app in list */
> >>>>>};
> >>>>>
> >>>>>3) Change the ast_register_application() function to pass the cookie
> >>>>> to the ast_app struct:
> >>>>>
> >>>>>int ast_register_application(char *app, int (*execute)(struct
> >>>>>ast_channel *, void *data, void *cookie), char *synopsis, char
> >>>>>*description, void *cookie);
> >>>>>
> >>>>>Do these modifications have any chance of being accepted into
> >>>>> Asterisk?

-- 
Juan Jose Comellas
(juanjo at comellas.com.ar)



More information about the asterisk-dev mailing list